├── CONTRIBUTING.md ├── Elevation ├── Data.zip ├── Setting up the viewshed geoprocessing service.pdf └── Tools │ ├── ElevationTools.Viewshed.pyt.xml │ ├── ElevationTools.pyt │ ├── ElevationTools.pyt.xml │ └── Utils.tbx ├── ElevationPro ├── Data.zip ├── ElevationTools.Viewshed.pyt.xml ├── ElevationTools.pyt ├── ElevationTools.pyt.xml ├── Setting up the viewshed geoprocessing service (ArcGIS Pro).pdf ├── Utils.tbx └── outputsymbology.lyrx ├── Profile ├── How to set up the profile service (ArcGIS Pro).pdf ├── Profile Tool Pro.Profile.pyt.xml ├── Profile Tool Pro.pyt ├── Profile Tool Pro.pyt.xml ├── Profile Utils Pro.tbx └── ProfileData.zip ├── README.md ├── elevation-gp-python.png └── license.txt /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Esri welcomes contributions from anyone and everyone. Please see our [guidelines for contributing](https://github.com/esri/contributing). -------------------------------------------------------------------------------- /Elevation/Data.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Esri/elevation-gp-python/cd9a8d6892b3690f927450d628262a05539d0ec9/Elevation/Data.zip -------------------------------------------------------------------------------- /Elevation/Setting up the viewshed geoprocessing service.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Esri/elevation-gp-python/cd9a8d6892b3690f927450d628262a05539d0ec9/Elevation/Setting up the viewshed geoprocessing service.pdf -------------------------------------------------------------------------------- /Elevation/Tools/ElevationTools.Viewshed.pyt.xml: -------------------------------------------------------------------------------- 1 | 20130503192640001.0TRUE20150826232537001500000005000ItemDescriptionViewshed<DIV STYLE="text-align:Left;"><DIV><DIV><P STYLE="margin:1 1 1 0;"><SPAN>Returns polygons of visible areas for a given set of input observation points.</SPAN></P></DIV></DIV></DIV>ViewshedVisibilityEarth and AtmosphereObservationSurfaceElevationDEMNEDSRTMArcToolbox Tool<DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>The point features to use as the observer locations.</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>The point features to use as the observer locations.</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>The maximum distance to calculate the viewshed.</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>The maximum distance to calculate the viewshed.</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>The units for the Maximum Distance parameter. </SPAN></P><P><SPAN>The default is meters.</SPAN></P><UL><LI><P><SPAN>Meters — The units are meters. This is the default.</SPAN></P></LI><LI><P><SPAN>Kilometers — The units are kilometers.</SPAN></P></LI><LI><P><SPAN>Feet — The units are feet.</SPAN></P></LI><LI><P><SPAN>Yards — The units are yards.</SPAN></P></LI><LI><P><SPAN>Miles — The units are miles.</SPAN></P></LI></UL><P><SPAN /></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>The units for the Maximum Distance parameter. </SPAN></P><P><SPAN>The default is meters.</SPAN></P><UL><LI><P><SPAN>Meters —The units are meters. This is the default.</SPAN></P></LI><LI><P><SPAN>Kilometers —The units are kilometers.</SPAN></P></LI><LI><P><SPAN>Feet —The units are feet.</SPAN></P></LI><LI><P><SPAN>Yards —The units are yards.</SPAN></P></LI><LI><P><SPAN>Miles —The units are miles.</SPAN></P></LI></UL></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><P><SPAN>The approximate spatial resolution (cell size) of the source elevation data used for the calculation. The default is 90m.</SPAN></P><P><SPAN>The resolution keyword is an approximation of the spatial resolution of the digital elevation model. Many elevation sources are distributed with units of arc seconds, the keyword is an approximation in meters for easier understanding.</SPAN></P><UL><LI><P><SPAN>FINEST — The finest units available for the extent are used.</SPAN></P></LI><LI><P><SPAN>10m — the elevation source resolution is 1/3 arc second, or approximately 10 meters.</SPAN></P></LI><LI><P><SPAN>30m — the elevation source resolution is 1 arc second, or approximately 30 meters.</SPAN></P></LI><LI><P><SPAN>90m — the elevation source resolution is 3 arc second, or approximately 90 meters.</SPAN></P></LI></UL></DIV><DIV STYLE="text-align:Left;"><P><SPAN>The approximate spatial resolution (cell size) of the source elevation data used for the calculation. The default is 90m.</SPAN></P><P><SPAN>The resolution keyword is an approximation of the spatial resolution of the digital elevation model. Many elevation sources are distributed with units of arc seconds, the keyword is an approximation in meters for easier understanding.</SPAN></P><UL><LI><P><SPAN>FINEST — The finest units available for the extent are used.</SPAN></P></LI><LI><P><SPAN>10m — the elevation source resolution is 1/3 arc second, or approximately 10 meters.</SPAN></P></LI><LI><P><SPAN>30m — the elevation source resolution is 1 arc second, or approximately 30 meters.</SPAN></P></LI><LI><P><SPAN>90m — the elevation source resolution is 3 arc second, or approximately 90 meters.</SPAN></P></LI></UL></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>The height above the surface of the observer. The default value of 1.75 meters is an average height of a person. If you are looking from an elevated location such as an observation tower or a tall building, use that height instead.</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>The height above the surface of the observer. The default value of 1.75 meters is an average height of a person. If you are looking from an elevated location such as an observation tower or a tall building, use that height instead.</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>The units for the Observer Height parameter. </SPAN></P><P><SPAN>The default is meters.</SPAN></P><UL><LI><P><SPAN>Meters — The units are meters. This is the default.</SPAN></P></LI><LI><P><SPAN>Kilometers — The units are kilometers.</SPAN></P></LI><LI><P><SPAN>Feet — The units are feet.</SPAN></P></LI><LI><P><SPAN>Yards — The units are yards.</SPAN></P></LI><LI><P><SPAN>Miles — The units are miles.</SPAN></P></LI></UL></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>The units for the Observer Height parameter. </SPAN></P><P><SPAN>The default is meters.</SPAN></P><UL><LI><P><SPAN>Meters — The units are meters. This is the default.</SPAN></P></LI><LI><P><SPAN>Kilometers — The units are kilometers.</SPAN></P></LI><LI><P><SPAN>Feet — The units are feet.</SPAN></P></LI><LI><P><SPAN>Yards — The units are yards.</SPAN></P></LI><LI><P><SPAN>Miles — The units are miles.</SPAN></P></LI></UL></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>The height above the surface of the object you are trying to see. The default value is 0. If you are trying to see buildings or wind turbines use their height here.</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>The height above the surface of the object you are trying to see. The default value is 0. If you are trying to see buildings or wind turbines use their height here.</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>The units for the Surface Offset parameter. </SPAN></P><P><SPAN>The default is meters.</SPAN></P><UL><LI><P><SPAN>Meters — The units are meters. This is the default.</SPAN></P></LI><LI><P><SPAN>Kilometers — The units are kilometers.</SPAN></P></LI><LI><P><SPAN>Feet — The units are feet.</SPAN></P></LI><LI><P><SPAN>Yards —The units are yards.</SPAN></P></LI><LI><P><SPAN>Miles — The units are miles.</SPAN></P></LI></UL></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>The units for the Surface Offset parameter. </SPAN></P><P><SPAN>The default is meters.</SPAN></P><UL><LI><P><SPAN>Meters — The units are meters. This is the default.</SPAN></P></LI><LI><P><SPAN>Kilometers — The units are kilometers.</SPAN></P></LI><LI><P><SPAN>Feet — The units are feet.</SPAN></P></LI><LI><P><SPAN>Yards — The units are yards.</SPAN></P></LI><LI><P><SPAN>Miles — The units are miles.</SPAN></P></LI></UL></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>Determine if the viewshed polygons are to be generalized or not.</SPAN></P><P><SPAN>The viewshed calculation is based upon a raster elevation model which creates a result with stair-stepped edges. To create a more pleasing appearance and improve performance, the default behavior is to generalize the polygons. This generalization will not change the accuracy of the result for any location more than one half of the DEM's resolution.</SPAN></P><UL><LI><P><SPAN>Checked — Generalizes the results. This is the default.</SPAN></P></LI><LI><P><SPAN>Unchecked — No generalization of the output polygons will occur.</SPAN></P></LI></UL></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>Determine if the viewshed polygons are to be generalized or not.</SPAN></P><P><SPAN>The viewshed calculation is based upon a raster elevation model which creates a result with stair-stepped edges. To create a more pleasing appearance and improve performance, the default behavior is to generalize the polygons. This generalization will not change the accuracy of the result for any location more than one half of the DEM's resolution.</SPAN></P><UL><LI><P><SPAN>True — Generalizes the results. This is the default</SPAN></P></LI><LI><P><SPAN>False — No generalization of the output polygons will occur</SPAN></P></LI></UL></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P STYLE="margin:1 1 1 0;"><SPAN>Returns polygons of visible areas for a given set of input observation points.</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><UL><LI><P><SPAN>There are several elevation sources currently available which are at different spatial resolutions and cover different areas. Not all resolutions are available for all areas. The service will return an error message if the specified resolution is not available at any of the input observer locations. </SPAN></P></LI><LI><P><SPAN>If the DEM Resolution parameter is empty or not supplied, then the coarsest resolution (90m) will be used. If FINEST is specified, then the service will use the smallest resolution available at your observer location allowed by the maximum distance parameter. </SPAN></P></LI><LI><P><SPAN>For the MaximumDistance parameter itself, the allowed value for the 10m and 30m DEM resolutions is 15 kilometers or less. For the 90m DEM resolution, the allowed value is 50 kilometers or less. If this parameter is not specified, the task will use a default value based on the DEM resolution parameter. For 10m resolution, the default maximum distance is 5 kilometers. For both the 30m and the 90m DEM resolutions, the default distance is 15 kilometers.</SPAN></P></LI><LI><P><SPAN>The service uses a single resolution elevation source for the input features. The entire input features must fit into a single resolution, or else the service will pick the highest resolution which can cover the input features.</SPAN></P></LI><LI><P><SPAN>Visibility into water is limited, so the tool uses the water surface as the elevation service. Oceans have been assigned a value of zero and major water bodies have been assigned an appropriate flat local elevation.</SPAN></P></LI><LI><P><SPAN>It is possible to control the viewshed analysis using the observer attribute fields. The supported fields are OFFSETA, OFFSETB, AZIMUTH1, AZIMUTH2, VERT1, VERT2, and SPOT. The attribute fields RADIUS1 and RADIUS2 are not supported by the Viewshed service. Fields OFFSETA and OFFSETB are available on the input observer feature set schema template if you are using the service in ArcMap. For additional explanation of using these fields to control your analysis, see </SPAN><A href="http://resources.arcgis.com/en/help/main/10.2/index.html#/Using_Viewshed_and_Observer_Points_for_visibility_analysis/00q90000008n000000/"><SPAN>Using Viewshed and Observer Points for visibility analysis</SPAN></A><SPAN>.</SPAN></P></LI><LI><P><SPAN>The output viewshed is returned as polygon features. The field named "Frequency" is used to record the number of observation points that can see each polygon. The field named "DEMResolution" is used to record the source DEM resolution for the viewshed computation.</SPAN></P></LI><LI><P><SPAN>A lower DEM resolution will result in a faster response from the service. For example, the 90m resolution has the shortest response time from the service. The tradeoff is that a lower DEM resolution has a lower accuracy in the viewshed result compared to that of a higher DEM resolution.</SPAN></P></LI><LI><P><SPAN>The Maximum Distance parameter may also affect the Viewshed service response time. In general, using a smaller distance results in a shorter response time.</SPAN></P></LI><LI><P><SPAN>The maximum number of input points is 1000. If more input points are provided, the service will return an error and will not execute.</SPAN></P></LI></UL></DIV></DIV></DIV>Viewshed service example (stand-alone script)<DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>This example consumes the Viewshed service in python and save the viewshed result as a shapefile locally.</SPAN></P></DIV></DIV></DIV>import time 2 | import arcpy 3 | arcpy.ImportToolbox("http://elevation.arcgis.com/arcgis/services;Tools/Elevation", "elev") 4 | result = arcpy.Viewshed_elev(r"d:\test\testdata.gdb\sumelelvpnt1", "15000", "Meters", "FINEST") 5 | 6 | while result.status < 4: 7 | print result.status 8 | time.sleep(0.2) 9 | print "Execution Finished" 10 | 11 | arcpy.CopyFeatures_management(result.getOutput(0), r'c:\output\viewshd1.shp') 12 | c:\program files (x86)\arcgis\desktop10.2\Help\gp/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsK 13 | CwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQU 14 | FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wAARCAC7AMIDASIA 15 | AhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQA 16 | AAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3 17 | ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWm 18 | p6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEA 19 | AwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSEx 20 | BhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElK 21 | U1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3 22 | uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD4/gmS 23 | /sEibEjbeV/rXPahbtZXSAMQp5U+lPkklsZFKtlWGVI71M+of2p5cTxq8mdqsvBya83W2p5SO/8A 24 | hD4duPGmt7BKYDbxsXmChsL2OMjPJA/GovGd0LfQrgKy7pMKM9817T8EvAMvgHwzNLektfX5EssO 25 | 3bsAyFX1zgkn64wMHPhvir4f+MLyCW8vtJNpp1qN+EnjkKqOrEKxPHXOOBk18tgs5oYjHV6UqsVC 26 | PKo3aV3re3fWy08rbnuYjLKlHDUqig3J3b0ei0tftpd/8MYngO+SO4vLWQKFmj3BmGSNucgfmKx9 27 | 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 295 | -------------------------------------------------------------------------------- /Elevation/Tools/ElevationTools.pyt: -------------------------------------------------------------------------------- 1 | ## Copyright 2015 Esri 2 | ## Licensed under the Apache License, Version 2.0 (the "License"); 3 | ## you may not use this file except in compliance with the License. 4 | ## You may obtain a copy of the License at 5 | ## http://www.apache.org/licenses/LICENSE-2.0 6 | ## Unless required by applicable law or agreed to in writing, software 7 | ## distributed under the License is distributed on an "AS IS" BASIS, 8 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | ## See the License for the specific language governing permissions and 10 | ## limitations under the License. 11 | 12 | import sys 13 | import os 14 | import json 15 | import time 16 | import arcpy 17 | 18 | class Toolbox(object): 19 | def __init__(self): 20 | """Define the toolbox (the name of the toolbox is the name of the 21 | .pyt file).""" 22 | self.label = "ElevationTools" 23 | self.alias = "elev" 24 | 25 | # List of tool classes associated with this toolbox 26 | self.tools = [Viewshed] 27 | #-------------------------------------------- 28 | #Declare data layers for publisher 29 | #-------------------------------------------- 30 | if False: 31 | arcpy.Describe("dem30m") 32 | arcpy.Describe("dem60m") 33 | arcpy.Describe("dem90m") 34 | arcpy.Describe("databoundary_containment") 35 | arcpy.Describe("databoundary_credit") 36 | 37 | class Viewshed(object): 38 | def __init__(self): 39 | """Define the tool (tool name is the name of the class).""" 40 | self.label = "Viewshed" 41 | self.description = ("Calculate viewshed for user specified observer " + 42 | "locations.") 43 | self.canRunInBackground = False 44 | ### service variables 45 | self.visiFieldName = "Frequency" 46 | self.metadataFieldName = "DEMResolution" 47 | self.perimeterFieldName = "PerimeterKm" 48 | self.areaFieldName = "AreaSqKm" 49 | self.defaultObsOffset = 1.75 50 | self.defaultTargetOffset = 1.75 51 | self.useEarthCurvatureCorrection = True 52 | self.listLinearUnits = ["Meters", "Kilometers", "Feet", "Yards", "Miles"] 53 | #-------------------------------------------- 54 | #Input observer point schema 55 | #-------------------------------------------- 56 | self.observerSchema = r"..\Data\MD\Boundary.gdb\obs_schema" 57 | #-------------------------------------------- 58 | #Output symbology 59 | #-------------------------------------------- 60 | self.outputSymbology = r"..\Data\Layers\outputsymbology.lyr" 61 | #-------------------------------------------- 62 | #DEM resolutions 63 | #-------------------------------------------- 64 | self.dictDEMSources = {"30m":"30", "60m":"60", "90m":"90"} 65 | self.defaultDEMResolution = '90' 66 | self.defaultDEMMetadata = ["SRTM", "USGS, NASA, CGIAR", "http://www.cgiar-csi.org/"] 67 | #-------------------------------------------- 68 | #Data source layers 69 | #-------------------------------------------- 70 | self.dictMosaicLayers = {'30':"dem30m", '60':"dem60m", '90':"dem90m"} 71 | #-------------------------------------------- 72 | #default and maximum radiuses 73 | #-------------------------------------------- 74 | self.dictDefaultRadius = {'30':5000, '60':15000, '90':15000} 75 | self.dictMaxRadius = {'30':15000, '60':30000, '90':50000} 76 | self.dictMaxRadiusFinest = {'30':5000, '60':15000, '90':50000} 77 | self.errorMessages = ["One or more input observer points are outside of the area covered by the DEM source. Use a coarser resolution DEM or make sure all the input points are inside the DEM source.", 78 | "Input maximum distance exceeds the maximum value permitted. Reduce the maximum distance value or use a coarser resolution DEM.", 79 | "Input DEM source is not available at observer location. Select a difference DEM source.", 80 | "No input observer points found. The input observer features must contain at least one point.", 81 | "Number of input observer points exceeds the maximum number permitted. The allowed maximum number of input observer points is 25.", 82 | "Input units is not valid. The supported units are meters, kilometers, feet, yards and miles.", 83 | "Input DEM resolution {0} is not available. Select a different DEM source.", 84 | "Input observer feature(s) are not point shape type. Input observer features must be points.", 85 | "Input numeric value {0} is not valid.", 86 | "Input units string {0} is not valid.", 87 | "No DEM source was found at the observer locations. Make sure all the input points are covered by the DEM source, or use a coarser resolution DEM."] 88 | 89 | def getDefaultRadius(self, res): 90 | if not res in self.dictMosaicLayers.keys(): 91 | arcpy.AddError(self.errorMessages[6].format(res)) 92 | raise 93 | return 94 | return self.dictDefaultRadius[res] 95 | 96 | def getMaxRadius(self, res): 97 | if not res in self.dictMosaicLayers.keys(): 98 | arcpy.AddError(self.errorMessages[6].format(res)) 99 | raise 100 | return 101 | return self.dictMaxRadius[res] 102 | 103 | def getMaxRadiusFinest(self, res): 104 | if not res in self.dictMosaicLayers.keys(): 105 | arcpy.AddError(self.errorMessages[6].format(res)) 106 | raise 107 | return 108 | return self.dictMaxRadiusFinest[res] 109 | 110 | def getLayerName(self, res): 111 | if not res in self.dictMosaicLayers.keys(): 112 | arcpy.AddError(self.errorMessages[6].format(res)) 113 | raise 114 | return 115 | return self.dictMosaicLayers[res] 116 | 117 | def getPS(self, res): 118 | if not res in self.dictPS.keys(): 119 | arcpy.AddError(self.errorMessages[6].format(res)) 120 | raise 121 | return 122 | return self.dictPS[res] 123 | 124 | def getUnitConversionFactor(self, u1): # get conversion factor 125 | uFactor = 1 126 | inUnit = u1.strip().lower() 127 | if inUnit in ["meters", "meter"]: 128 | uFactor = 1 129 | if inUnit in ["centimeters", "centimeter"]: 130 | uFactor = 0.01 131 | if inUnit in ["decimaldegrees", "decimaldegree"]: 132 | arcpy.AddError(self.errorMessages[3]) 133 | raise 134 | if inUnit in ["decimeters", "decimeter"]: 135 | uFactor = 0.1 136 | if inUnit in ["feet", "foot"]: 137 | uFactor = 0.3048 138 | if inUnit in ["foot_us", "feet_us"]: 139 | uFactor = 0.3048006096012192 140 | if inUnit in ["inches","inch"]: 141 | uFactor = 0.0254 142 | if inUnit in ["kilometers", "kilometer"]: 143 | uFactor = 1000 144 | if inUnit in ["miles","mile"]: 145 | uFactor = 1609.344 146 | if inUnit in ["millimeters", "millimeter"]: 147 | uFactor = 0.001 148 | if inUnit in ["nauticalmiles", "nauticalmile"]: 149 | uFactor = 1852 150 | if inUnit in ["points", "point"]: 151 | uFactor = 0.000352777778 152 | if inUnit in ["unknown", ""]: 153 | uFactor = 1 154 | if inUnit in ["yards", "yard"]: 155 | uFactor = 0.91440 156 | return uFactor 157 | 158 | def createBuffer(self, in_points, in_dist): 159 | useGCSBuffer = True 160 | if useGCSBuffer: 161 | arcpy.env.outputCoordinateSystem = 4326 # create buffer in GCS_WGS_1984 162 | bufferTemp = os.path.join(r"in_memory","obsbuffertemp01") 163 | arcpy.Buffer_analysis(in_points, bufferTemp, str(in_dist) + " Meters", 164 | "FULL", "ROUND", "NONE", "") 165 | arcpy.env.outputCoordinateSystem = "" 166 | 167 | bufferOutput = bufferTemp 168 | else: 169 | bufferOutput = os.path.join("in_memory","obsbuffertemp02") 170 | arcpy.Buffer_analysis(in_points, bufferOutput, str(in_dist) + " Meters", 171 | "FULL", "ROUND", "NONE", "") 172 | return bufferOutput 173 | 174 | def featureFootprintTest(self, in_features, containment_poly, test_type="contains"): 175 | footPrt = containment_poly 176 | resList = [] 177 | if test_type.lower() == "contains": 178 | arcpy.SelectLayerByLocation_management(footPrt, "COMPLETELY_CONTAINS", 179 | in_features, selection_type="NEW_SELECTION") 180 | elif test_type.lower() == "intersect": 181 | arcpy.SelectLayerByLocation_management(footPrt, "INTERSECT", 182 | in_features, selection_type="NEW_SELECTION") 183 | else: 184 | pass 185 | with arcpy.da.SearchCursor(footPrt, ("res", "prd", "src", "srcurl", "polytype")) as cursor: 186 | for row in cursor: 187 | resList.append(row) 188 | return resList 189 | 190 | def ContainmentCheck(self, in_point_or_buffer): 191 | containment_layer = "databoundary_containment" 192 | foot_candidates = self.featureFootprintTest(in_point_or_buffer, containment_layer) 193 | dict_res = {} 194 | for t in foot_candidates: 195 | k1 = int(t[0]) 196 | v1 = (t[1], t[2], t[3], t[4]) 197 | dict_res[k1] = v1 198 | 199 | if len(dict_res) == 0: 200 | arcpy.AddError(self.errorMessages[2]) 201 | raise 202 | return dict_res 203 | 204 | def CreditCheck(self, in_points, dem_res): 205 | credit_layer = "databoundary_credit" 206 | foot_candidates = self.featureFootprintTest(in_points, credit_layer, test_type="intersect") 207 | list_prd = [] 208 | list_src = [] 209 | list_srcurl = [] 210 | for t in foot_candidates: 211 | k1 = int(t[0]) 212 | if k1 == dem_res: # match resolution 213 | prd = t[1].rsplit(",") 214 | for p in prd: 215 | if not p.strip() in list_prd: 216 | list_prd.append(p.strip()) 217 | src = t[2].rsplit(",") 218 | for s in src: 219 | if not s.strip() in list_src: 220 | list_src.append(s.strip()) 221 | srcurl = t[3].rsplit(",") 222 | for u in srcurl: 223 | if not u.strip() in list_srcurl: 224 | list_srcurl.append(u.strip()) 225 | 226 | prd_string = ", ".join(list_prd) 227 | src_string = ", ".join(list_src) 228 | srcurl_string = ", ".join(list_srcurl) 229 | 230 | credit_list = [prd_string, src_string, srcurl_string] 231 | #if len(list_credit) == 0: 232 | # arcpy.AddError(self.errorMessages[2]) 233 | # raise 234 | return credit_list 235 | 236 | def validateNumerical(self, inVal, paramStr): 237 | if inVal == None: # None is OK 238 | return 239 | elif inVal < 0: 240 | arcpy.AddError(self.errorMessages[8].format(paramStr)) 241 | raise 242 | 243 | def validateDistanceUnits(self, inStr, paramStr): 244 | tempUnitsList = [s.lower() for s in self.listLinearUnits] 245 | tempUnitsList.extend(["#", ""]) 246 | if inStr == None: # None is OK 247 | return 248 | elif not (inStr.strip().lower() in tempUnitsList): 249 | arcpy.AddError(self.errorMessages[9].format(paramStr)) 250 | raise 251 | 252 | def validateInputDEMSource(self, inDEM): 253 | tempDEMList = [s.upper() for s in self.dictDEMSources.keys()] 254 | tempDEMList.extend(["", "FINEST", "#"]) 255 | if inDEM == None: # None is OK 256 | return 257 | elif not (inDEM.strip().upper() in tempDEMList): 258 | arcpy.AddError(self.errorMessages[6].format(inDEM)) 259 | raise 260 | 261 | def formatInputDEMSource(self, inSource): 262 | tempDEMList = self.dictDEMSources.keys() 263 | tempDEMList.extend(["", "FINEST"]) 264 | retVal = inSource 265 | for d in tempDEMList: 266 | if inSource.upper() == d.upper(): 267 | retVal = d 268 | break 269 | return retVal 270 | 271 | def LogUsageMetering(self, taskName, numObjects, cost, startTime, values): 272 | elapsed = time.time() - startTime 273 | valuesMsg = taskName + json.dumps(values) 274 | 275 | arcpy.AddMessage("NumObjects: {} Cost: {}".format(numObjects, cost)) 276 | arcpy.AddMessage(u"{0} Elapsed: {1:.3f}".format(valuesMsg, elapsed)) 277 | #arcpy.gp._arc_object.LogUsageMetering(5555, taskName, numObjects, cost) 278 | arcpy.gp._arc_object.LogUsageMetering(7777, valuesMsg, numObjects, elapsed) 279 | 280 | def GetUnitsIndex(self, in_units): 281 | unitsIndex = 0 282 | listUnits = ["meters", "kilometers", "feet", "yards", "miles"] 283 | if in_units == None or in_units == "": 284 | unitsIndex = 0 # meters 285 | else: 286 | try: 287 | unitsIndex = listUnits.index(in_units.lower()) 288 | except: 289 | unitsIndex = 0 290 | return unitsIndex 291 | 292 | def executeVisibility(self, mosaic_layer, in_points, obs_count, in_buffer, credit_list, maximum_distance, 293 | dem_resolution, obs_offset1, surface_offset1, 294 | generalize_output, out_viewshed_fc): 295 | 296 | try: 297 | 298 | # Buffer input point to get clip extent 299 | if in_buffer is None: 300 | bufferOutput = self.createBuffer(in_points, maximum_distance) 301 | else: 302 | bufferOutput = in_buffer 303 | 304 | #pixel_size = self.getPS(dem_resolution) 305 | arcpy.env.extent = bufferOutput 306 | arcpy.env.mask = bufferOutput 307 | arcpy.env.snapRaster = mosaic_layer 308 | arcpy.env.outputCoordinateSystem = 102100 309 | #arcpy.env.cellSize = pixel_size 310 | 311 | zFactor = 1 312 | ecc = "CURVED_EARTH" 313 | exeString = ("Maximum distance: " + str(maximum_distance) + " meters, DEM resolution: " + str(dem_resolution) + 314 | " meters, Mosaic Layer: " + mosaic_layer + ", Observer offset: " + str(obs_offset1) + 315 | ", Surface offset: " + str(surface_offset1) + ".") 316 | arcpy.AddMessage(exeString) 317 | scratchWS = "in_memory" 318 | outvsd0 = os.path.join(scratchWS, "viewrastmp0") 319 | outvsd = os.path.join(scratchWS, "viewrastmp") 320 | v = arcpy.gp.Visibility_sa(mosaic_layer, in_points, outvsd0, "#", "FREQUENCY", "NODATA", 321 | zFactor, ecc, "#", surface_offset1, "#", obs_offset1, "#") 322 | 323 | arcpy.env.extent = "" 324 | arcpy.env.mask = "" 325 | arcpy.env.snapRaster = "" 326 | arcpy.env.outputCoordinateSystem = "" 327 | arcpy.env.cellSize = "" 328 | 329 | # Raster to Polygon 330 | smoothOutput = "NO_SIMPLIFY" 331 | if generalize_output == True or generalize_output == "GENERALIZE": 332 | smoothOutput = "SIMPLIFY" 333 | #Generalize - remove small areas 334 | arcpy.gp.BoundaryClean_sa(outvsd0, outvsd) 335 | else: 336 | smoothOutput = "NO_SIMPLIFY" 337 | outvsd = outvsd0 338 | 339 | visiPolygon = r"in_memory\visipolytmp" 340 | arcpy.RasterToPolygon_conversion(outvsd, visiPolygon, smoothOutput, "VALUE") 341 | # Dissolve 342 | visiPolygonDisv = out_viewshed_fc ## r"in_memory\visipolytmpdsv" 343 | arcpy.Dissolve_management(visiPolygon, visiPolygonDisv, "gridcode") 344 | # Rename gridcode 345 | arcpy.AddField_management(visiPolygonDisv, self.visiFieldName, "LONG") 346 | arcpy.CalculateField_management(visiPolygonDisv, self.visiFieldName, "!gridcode!", "PYTHON") 347 | arcpy.DeleteField_management(visiPolygonDisv, "gridcode") 348 | arcpy.AddField_management(visiPolygonDisv, self.metadataFieldName, "TEXT", field_length=50, field_alias="DEM Resolution") 349 | arcpy.AddField_management(visiPolygonDisv, "ProductName", "TEXT", field_length=50, field_alias="Product Name") 350 | arcpy.AddField_management(visiPolygonDisv, "Source", "TEXT", field_length=50, field_alias="Source") 351 | arcpy.AddField_management(visiPolygonDisv, "Source_URL", "TEXT", field_length=84, field_alias="Source URL") 352 | # Add metadata info 353 | dem_source = [k for k, v in self.dictDEMSources.iteritems() if v == str(dem_resolution)] 354 | arcpy.CalculateField_management(visiPolygonDisv, self.metadataFieldName, "'" + dem_source[0] + "'", "PYTHON") 355 | product_name = credit_list[0] #self.dictProductName[str(dem_resolution)] 356 | arcpy.CalculateField_management(visiPolygonDisv, "ProductName", "'" + product_name + "'", "PYTHON") 357 | source1 = credit_list[1] #self.dictSource[str(dem_resolution)] 358 | arcpy.CalculateField_management(visiPolygonDisv, "Source", "'" + source1 + "'", "PYTHON") 359 | sourceURL1 = credit_list[2] #self.dictSourceURL[str(dem_resolution)] 360 | arcpy.CalculateField_management(visiPolygonDisv, "Source_URL", "'" + sourceURL1 + "'", "PYTHON") 361 | # Add and calculate length and area field 362 | try: 363 | arcpy.AddField_management(visiPolygonDisv, self.perimeterFieldName, "DOUBLE", field_alias="Perimeter Kilometers") 364 | arcpy.AddField_management(visiPolygonDisv, self.areaFieldName, "DOUBLE", field_alias="Area Square Kilometers") 365 | arcpy.CalculateField_management(visiPolygonDisv, self.perimeterFieldName, "!shape.geodesicLength@meters! / 1000", "PYTHON") 366 | arcpy.CalculateField_management(visiPolygonDisv, self.areaFieldName, "!shape.geodesicArea@meters! / 1000000", "PYTHON") 367 | except: 368 | pass 369 | out_ras = out_viewshed_fc 370 | return out_ras 371 | except: 372 | msgs = arcpy.GetMessages(2) 373 | arcpy.AddError(msgs) 374 | raise 375 | return 0 376 | 377 | def getParameterInfo(self): 378 | """Define parameter definitions""" 379 | param0 = arcpy.Parameter(name="InputPoints", 380 | displayName="Input Point Features", 381 | direction="Input", 382 | parameterType="Required", 383 | datatype="GPFeatureRecordSetLayer") 384 | 385 | param0.value = self.observerSchema 386 | 387 | param1 = arcpy.Parameter(name="MaximumDistance", 388 | displayName="Maximum Distance", 389 | direction="Input", 390 | parameterType="Optional", 391 | datatype="GPDouble") 392 | param1.value = None 393 | 394 | param2 = arcpy.Parameter(name="MaximumDistanceUnits", 395 | displayName="Maximum Distance Units", 396 | direction="Input", 397 | parameterType="Optional", 398 | datatype="GPString") 399 | param2.filter.type = "ValueList" 400 | param2.filter.list = self.listLinearUnits 401 | param2.value = "Meters" 402 | 403 | param3 = arcpy.Parameter(name="DEMResolution", 404 | displayName="DEM Resolution", 405 | direction="Input", 406 | parameterType="Optional", 407 | datatype="GPString") 408 | param3.filter.type = "ValueList" 409 | list_dem = [" ", "FINEST"] 410 | dem_keys = self.dictDEMSources.keys() 411 | dem_keys.sort() 412 | list_dem.extend(dem_keys) 413 | param3.filter.list = list_dem 414 | 415 | param4 = arcpy.Parameter(name="ObserverHeight", 416 | displayName="Observer Height", 417 | direction="Input", 418 | parameterType="Optional", 419 | datatype="GPDouble") 420 | #param4.value = self.defaultObsOffset 421 | 422 | param5 = arcpy.Parameter(name="ObserverHeightUnits", 423 | displayName="Observer Height Units", 424 | direction="Input", 425 | parameterType="Optional", 426 | datatype="GPString") 427 | param5.filter.type = "ValueList" 428 | param5.filter.list = self.listLinearUnits 429 | param5.value = "Meters" 430 | 431 | param6 = arcpy.Parameter(name="SurfaceOffset", 432 | displayName="Surface Offset", 433 | direction="Input", 434 | parameterType="Optional", 435 | datatype="GPDouble") 436 | #param6.value = self.defaultTargetOffset 437 | 438 | param7 = arcpy.Parameter(name="SurfaceOffsetUnits", 439 | displayName="Surface Offset Units", 440 | direction="Input", 441 | parameterType="Optional", 442 | datatype="GPString") 443 | param7.filter.type = "ValueList" 444 | param7.filter.list = self.listLinearUnits 445 | param7.value = "Meters" 446 | 447 | param8 = arcpy.Parameter(name="GeneralizeViewshedPolygons", 448 | displayName="Generalize Viewshed Polygons", 449 | direction="Input", 450 | parameterType="Optional", 451 | datatype="GPBoolean") 452 | param8.value = True 453 | param8.filter.type = "ValueList" 454 | param8.filter.list = ["GENERALIZE", "NO_GENERALIZE"] 455 | 456 | param9 = arcpy.Parameter(name="OutputViewshed", 457 | displayName="Output Viewshed", 458 | direction="Output", 459 | parameterType="Derived", 460 | datatype="DEFeatureClass", 461 | symbology=self.outputSymbology) 462 | #param9.value = os.path.join(os.path.dirname(__file__), "Data", "viewshedout.shp") 463 | 464 | params = [param0, param1, param2, param3, param4, 465 | param5, param6, param7, param8, param9] 466 | return params 467 | 468 | def isLicensed(self): 469 | """Set whether tool is licensed to execute.""" 470 | return True 471 | 472 | def updateParameters(self, parameters): 473 | """Modify the values and properties of parameters before internal 474 | validation is performed. This method is called whenever a parameter 475 | has been changed.""" 476 | return 477 | 478 | def updateMessages(self, parameters): 479 | """Modify the messages created by internal validation for each tool 480 | parameter. This method is called after internal validation.""" 481 | return 482 | 483 | def execute(self, parameters, messages): 484 | """The source code of the tool.""" 485 | try: 486 | startTime = time.time() 487 | 488 | in_points0 = parameters[0].value 489 | maximum_distance_p = parameters[1].value 490 | distance_unit = parameters[2].valueAsText 491 | dem_resolution_p = parameters[3].valueAsText 492 | obs_offset_p = parameters[4].value 493 | obs_offset_unit = parameters[5].valueAsText 494 | surface_offset_p = parameters[6].value 495 | surface_offset_unit = parameters[7].valueAsText 496 | generalize_output = parameters[8].value 497 | 498 | # var for metering 499 | maxDistanceSp = 0 500 | obsOffsetSp = 0 501 | surOffsetSp = 0 502 | demSourceIdx = 0 503 | 504 | scratchWS = "in_memory" 505 | out_viewshed_fc = os.path.join(scratchWS, "viewshedpoly") 506 | 507 | obs_offset_altered = parameters[4].altered 508 | arcpy.env.overwriteOutput = True 509 | 510 | # make a copy of the input 511 | in_points = "in_memory/viewshedinpnts" 512 | arcpy.env.outputCoordinateSystem = 4326 513 | arcpy.CopyFeatures_management(in_points0, in_points) 514 | arcpy.env.outputCoordinateSystem = "" 515 | 516 | # validate # of observer points specified 517 | gCounts = 0 518 | gCounts = arcpy.GetCount_management(in_points) 519 | pntCounts = int(gCounts.getOutput(0)) 520 | if pntCounts < 1: 521 | arcpy.AddError(self.errorMessages[3]) 522 | raise 523 | return 524 | if pntCounts > 1000: # limit of input features 525 | arcpy.AddError(self.errorMessages[4]) 526 | raise 527 | return 528 | 529 | self.validateNumerical(obs_offset_p, "Observer Offset") 530 | self.validateNumerical(surface_offset_p, "Surface Offset") 531 | self.validateInputDEMSource(dem_resolution_p) 532 | 533 | self.validateDistanceUnits(distance_unit, "Maximum Distance Units") 534 | self.validateDistanceUnits(obs_offset_unit, "Observer Offset Units") 535 | self.validateDistanceUnits(surface_offset_unit, "Surface Offset Units") 536 | 537 | demSourceIdx = dem_resolution_p # metering 538 | 539 | if dem_resolution_p is not None and str(dem_resolution_p).upper() <> "FINEST": 540 | if dem_resolution_p.strip() == "": 541 | dem_resolution_p = None 542 | if dem_resolution_p is not None: 543 | dem_resolution_p = self.dictDEMSources[self.formatInputDEMSource(dem_resolution_p)] 544 | 545 | if obs_offset_unit == None: 546 | obs_offset_unit = "meters" 547 | 548 | if surface_offset_unit == None: 549 | surface_offset_unit = "meters" 550 | 551 | if obs_offset_p == None: 552 | obsOffsetSp = 0 553 | obs_offset = "#" 554 | else: 555 | obsOffsetSp = 1 556 | if obs_offset_p == 0 and obs_offset_altered == False: 557 | obs_offset = "#" 558 | else: 559 | obs_offset = obs_offset_p * self.getUnitConversionFactor(obs_offset_unit) 560 | 561 | if surface_offset_p == None: 562 | surOffsetSp = 0 563 | surface_offset = "#" 564 | else: 565 | surOffsetSp = 1 566 | surface_offset = surface_offset_p * self.getUnitConversionFactor(surface_offset_unit) 567 | 568 | mosaic_layer = "" 569 | 570 | res_dict = None 571 | buf_dict = None 572 | # case 1 573 | if maximum_distance_p == None and dem_resolution_p == None: 574 | maxDistanceSp = 0 # metering 575 | dem_resolution = self.defaultDEMResolution #'90' 576 | maximum_distance = self.getDefaultRadius(dem_resolution) 577 | buf1 = None 578 | #buf1 = self.createBuffer(in_points, maximum_distance) 579 | #testRes = self.bufferFootprintTest(buf1) 580 | testRes = [int(self.defaultDEMResolution)] 581 | if int(dem_resolution) in testRes: 582 | pass 583 | else: 584 | arcpy.AddError(self.errorMessages[0]) 585 | raise 586 | 587 | # case 2 588 | if maximum_distance_p is not None and dem_resolution_p == None: 589 | maxDistanceSp = 1 # metering 590 | maximum_distance = maximum_distance_p * self.getUnitConversionFactor(distance_unit) 591 | dem_resolution = self.defaultDEMResolution #'90' 592 | if maximum_distance > self.getMaxRadius(dem_resolution) or maximum_distance <= 0: 593 | arcpy.AddError(self.errorMessages[1]) 594 | raise 595 | else: 596 | buf1 = None 597 | #buf1 = self.createBuffer(in_points, maximum_distance) 598 | #testRes = self.bufferFootprintTest(buf1) 599 | testRes = [int(self.defaultDEMResolution)] 600 | if int(dem_resolution) in testRes: 601 | pass 602 | else: 603 | arcpy.AddError(self.errorMessages[0]) 604 | raise 605 | 606 | # case 3 607 | if maximum_distance_p == None and str(dem_resolution_p).upper() == "FINEST": 608 | maxDistanceSp = 0 # metering 609 | res_dict = self.ContainmentCheck(in_points) 610 | testRes = res_dict.keys() 611 | if len(testRes) == 0: 612 | arcpy.AddError(self.errorMessages[0])## 613 | raise 614 | return 615 | 616 | testRes.sort() 617 | matchFound = False 618 | for r1 in testRes: 619 | dem_resolution = str(r1) 620 | maximum_distance = self.getDefaultRadius(dem_resolution) 621 | buf1 = self.createBuffer(in_points, maximum_distance) 622 | buf_dict = self.ContainmentCheck(buf1) 623 | bufRes = buf_dict.keys() 624 | if r1 in bufRes: 625 | matchFound = True 626 | break 627 | if not matchFound: 628 | arcpy.AddError(self.errorMessages[10]) 629 | raise 630 | 631 | # case 4 632 | if maximum_distance_p is not None and str(dem_resolution_p).upper() == "FINEST": 633 | maxDistanceSp = 1 # metering 634 | maximum_distance = maximum_distance_p * self.getUnitConversionFactor(distance_unit) 635 | if maximum_distance > self.getMaxRadius(self.defaultDEMResolution) or maximum_distance <= 0: 636 | arcpy.AddError(self.errorMessages[1]) 637 | raise 638 | return 639 | # get all resolutions available 640 | res_dict = self.ContainmentCheck(in_points) 641 | testRes = res_dict.keys() 642 | testRes.sort() 643 | # find a finest resolution with the given distance 644 | resl = 0 645 | for r1 in testRes: 646 | d1 = self.getMaxRadiusFinest(str(r1)) 647 | if maximum_distance <= d1: 648 | buf1 = self.createBuffer(in_points, maximum_distance) 649 | buf_dict = self.ContainmentCheck(buf1) 650 | bufRes = buf_dict.keys() 651 | if r1 in bufRes: 652 | resl = r1 653 | break 654 | 655 | if resl == 0: 656 | arcpy.AddError(self.errorMessages[1])## 657 | raise 658 | return 659 | else: 660 | dem_resolution = str(resl) 661 | 662 | # case 5 663 | if maximum_distance_p is None and dem_resolution_p is not None and str(dem_resolution_p).upper() <> "FINEST": 664 | maxDistanceSp = 0 # metering 665 | dem_resolution = dem_resolution_p 666 | maximum_distance = self.getDefaultRadius(dem_resolution) 667 | if str(int(dem_resolution)) != self.defaultDEMResolution: 668 | buf1 = self.createBuffer(in_points, maximum_distance) 669 | buf_dict = self.ContainmentCheck(buf1) 670 | bufRes = buf_dict.keys() 671 | else: # for 90m data, no need to do buffer test 672 | bufRes = [int(self.defaultDEMResolution)] 673 | buf1 = None 674 | if int(dem_resolution) in bufRes: 675 | pass 676 | else: 677 | arcpy.AddError(self.errorMessages[2]) 678 | raise 679 | 680 | # case 6 681 | if maximum_distance_p is not None and dem_resolution_p is not None and str(dem_resolution_p).upper() <> "FINEST": 682 | maxDistanceSp = 1 # metering 683 | dem_resolution = dem_resolution_p 684 | #if dem_resolution == '230': 685 | # dem_resolution = '231' 686 | maximum_distance = maximum_distance_p * self.getUnitConversionFactor(distance_unit) 687 | if maximum_distance > self.getMaxRadius(dem_resolution) or maximum_distance <= 0: 688 | arcpy.AddError(self.errorMessages[1]) 689 | raise 690 | else: 691 | if str(int(dem_resolution)) != self.defaultDEMResolution: 692 | buf1 = self.createBuffer(in_points, maximum_distance) 693 | buf_dict = self.ContainmentCheck(buf1) 694 | bufRes = buf_dict.keys() 695 | else: # for 90m data, no need to do buffer test 696 | bufRes = [int(self.defaultDEMResolution)] 697 | buf1 = None 698 | if int(dem_resolution) in bufRes: 699 | pass 700 | #arcpy.SetParameterAsText(1, outRas) 701 | else: 702 | arcpy.AddError(self.errorMessages[2]) 703 | raise 704 | 705 | # gather credit information 706 | if buf_dict is not None: 707 | res_dict = buf_dict 708 | 709 | if res_dict is None: # 90m 710 | credit_list = self.defaultDEMMetadata 711 | else: 712 | credit_tuple = res_dict[int(dem_resolution)] 713 | credit_list = [] 714 | polytype = credit_tuple[3] 715 | if polytype > 0: # 1 or 2, already contains credit info 716 | prd = credit_tuple[0].strip() 717 | src = credit_tuple[1].strip() 718 | srcurl = credit_tuple[2].strip() 719 | credit_list = [prd, src, srcurl] 720 | else: # 0, containment only polygons, need credit check 721 | credit_list = self.CreditCheck(in_points, int(dem_resolution)) 722 | 723 | mosaic_layer = self.getLayerName(dem_resolution) 724 | outRas = self.executeVisibility(mosaic_layer, in_points, pntCounts, buf1, credit_list, 725 | maximum_distance, dem_resolution, obs_offset, surface_offset, 726 | generalize_output, out_viewshed_fc) 727 | 728 | arcpy.SetParameterAsText(9, out_viewshed_fc) 729 | 730 | # Metering 731 | maxDistUnitsIdx = self.GetUnitsIndex(distance_unit) 732 | obsOffsetUnitsIdx = self.GetUnitsIndex(obs_offset_unit) 733 | surOffsetUnitsIdx = self.GetUnitsIndex(surface_offset_unit) 734 | obsOffsetExectution = obs_offset #1.75 735 | surOffsetExectution = surface_offset #1.75 736 | generalize_out_log = 0 737 | if obsOffsetSp: 738 | obsOffsetExectution = obs_offset 739 | if surOffsetSp: 740 | surOffsetExectution = surface_offset 741 | if generalize_output == True or generalize_output == "GENERALIZE": 742 | generalize_out_log = 1 743 | 744 | taskName = "Viewshed" 745 | cost = pntCounts 746 | # Initiate start time 747 | beginTime = startTime 748 | 749 | values = [ 750 | pntCounts, # input count 751 | maxDistanceSp, 752 | maximum_distance, 753 | maxDistUnitsIdx, 754 | demSourceIdx, 755 | obsOffsetSp, 756 | obsOffsetExectution, 757 | obsOffsetUnitsIdx, 758 | surOffsetSp, 759 | surOffsetExectution, 760 | surOffsetUnitsIdx, 761 | generalize_out_log 762 | ] 763 | 764 | self.LogUsageMetering(taskName, 1, cost, beginTime, values) 765 | 766 | except Exception as err: 767 | import traceback 768 | import sys 769 | msgs = traceback.format_exception(*sys.exc_info())[1:] 770 | for msg in msgs: 771 | arcpy.AddMessage(msg.strip()) 772 | except: 773 | arcpy.AddError("Viewshed failed to execute.") 774 | 775 | -------------------------------------------------------------------------------- /Elevation/Tools/ElevationTools.pyt.xml: -------------------------------------------------------------------------------- 1 | 2 | 20130503192636001.0TRUE201510221206311500000005000ItemDescriptionc:\program files (x86)\arcgis\desktop10.3\Help\gpElevationToolsGeoprocessing services that use the elevation data to compute viewshed polygons for the input observer locations.<DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>The elevation geoprocessing services contains the following tasks:</SPAN></P><UL><LI><P><SPAN>Viewshed – Returns viewshed polygons for the input point features.</SPAN></P></LI></UL></DIV></DIV></DIV>ViewshedSurfaceDEMNEDSRTMArcToolbox Toolbox 3 | -------------------------------------------------------------------------------- /Elevation/Tools/Utils.tbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Esri/elevation-gp-python/cd9a8d6892b3690f927450d628262a05539d0ec9/Elevation/Tools/Utils.tbx -------------------------------------------------------------------------------- /ElevationPro/Data.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Esri/elevation-gp-python/cd9a8d6892b3690f927450d628262a05539d0ec9/ElevationPro/Data.zip -------------------------------------------------------------------------------- /ElevationPro/ElevationTools.Viewshed.pyt.xml: -------------------------------------------------------------------------------- 1 | 20130503192640001.0TRUE20150826232537001500000005000ItemDescriptionViewshed<DIV STYLE="text-align:Left;"><DIV><DIV><P STYLE="margin:1 1 1 0;"><SPAN>Returns polygons of visible areas for a given set of input observation points.</SPAN></P></DIV></DIV></DIV>ViewshedVisibilityEarth and AtmosphereObservationSurfaceElevationDEMNEDSRTMArcToolbox Tool<DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>The point features to use as the observer locations.</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>The point features to use as the observer locations.</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>The maximum distance to calculate the viewshed.</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>The maximum distance to calculate the viewshed.</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>The units for the Maximum Distance parameter. </SPAN></P><P><SPAN>The default is meters.</SPAN></P><UL><LI><P><SPAN>Meters — The units are meters. This is the default.</SPAN></P></LI><LI><P><SPAN>Kilometers — The units are kilometers.</SPAN></P></LI><LI><P><SPAN>Feet — The units are feet.</SPAN></P></LI><LI><P><SPAN>Yards — The units are yards.</SPAN></P></LI><LI><P><SPAN>Miles — The units are miles.</SPAN></P></LI></UL><P><SPAN /></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>The units for the Maximum Distance parameter. </SPAN></P><P><SPAN>The default is meters.</SPAN></P><UL><LI><P><SPAN>Meters —The units are meters. This is the default.</SPAN></P></LI><LI><P><SPAN>Kilometers —The units are kilometers.</SPAN></P></LI><LI><P><SPAN>Feet —The units are feet.</SPAN></P></LI><LI><P><SPAN>Yards —The units are yards.</SPAN></P></LI><LI><P><SPAN>Miles —The units are miles.</SPAN></P></LI></UL></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><P><SPAN>The approximate spatial resolution (cell size) of the source elevation data used for the calculation. The default is 90m.</SPAN></P><P><SPAN>The resolution keyword is an approximation of the spatial resolution of the digital elevation model. Many elevation sources are distributed with units of arc seconds, the keyword is an approximation in meters for easier understanding.</SPAN></P><UL><LI><P><SPAN>FINEST — The finest units available for the extent are used.</SPAN></P></LI><LI><P><SPAN>10m — the elevation source resolution is 1/3 arc second, or approximately 10 meters.</SPAN></P></LI><LI><P><SPAN>30m — the elevation source resolution is 1 arc second, or approximately 30 meters.</SPAN></P></LI><LI><P><SPAN>90m — the elevation source resolution is 3 arc second, or approximately 90 meters.</SPAN></P></LI></UL></DIV><DIV STYLE="text-align:Left;"><P><SPAN>The approximate spatial resolution (cell size) of the source elevation data used for the calculation. The default is 90m.</SPAN></P><P><SPAN>The resolution keyword is an approximation of the spatial resolution of the digital elevation model. Many elevation sources are distributed with units of arc seconds, the keyword is an approximation in meters for easier understanding.</SPAN></P><UL><LI><P><SPAN>FINEST — The finest units available for the extent are used.</SPAN></P></LI><LI><P><SPAN>10m — the elevation source resolution is 1/3 arc second, or approximately 10 meters.</SPAN></P></LI><LI><P><SPAN>30m — the elevation source resolution is 1 arc second, or approximately 30 meters.</SPAN></P></LI><LI><P><SPAN>90m — the elevation source resolution is 3 arc second, or approximately 90 meters.</SPAN></P></LI></UL></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>The height above the surface of the observer. The default value of 1.75 meters is an average height of a person. If you are looking from an elevated location such as an observation tower or a tall building, use that height instead.</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>The height above the surface of the observer. The default value of 1.75 meters is an average height of a person. If you are looking from an elevated location such as an observation tower or a tall building, use that height instead.</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>The units for the Observer Height parameter. </SPAN></P><P><SPAN>The default is meters.</SPAN></P><UL><LI><P><SPAN>Meters — The units are meters. This is the default.</SPAN></P></LI><LI><P><SPAN>Kilometers — The units are kilometers.</SPAN></P></LI><LI><P><SPAN>Feet — The units are feet.</SPAN></P></LI><LI><P><SPAN>Yards — The units are yards.</SPAN></P></LI><LI><P><SPAN>Miles — The units are miles.</SPAN></P></LI></UL></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>The units for the Observer Height parameter. </SPAN></P><P><SPAN>The default is meters.</SPAN></P><UL><LI><P><SPAN>Meters — The units are meters. This is the default.</SPAN></P></LI><LI><P><SPAN>Kilometers — The units are kilometers.</SPAN></P></LI><LI><P><SPAN>Feet — The units are feet.</SPAN></P></LI><LI><P><SPAN>Yards — The units are yards.</SPAN></P></LI><LI><P><SPAN>Miles — The units are miles.</SPAN></P></LI></UL></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>The height above the surface of the object you are trying to see. The default value is 0. If you are trying to see buildings or wind turbines use their height here.</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>The height above the surface of the object you are trying to see. The default value is 0. If you are trying to see buildings or wind turbines use their height here.</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>The units for the Surface Offset parameter. </SPAN></P><P><SPAN>The default is meters.</SPAN></P><UL><LI><P><SPAN>Meters — The units are meters. This is the default.</SPAN></P></LI><LI><P><SPAN>Kilometers — The units are kilometers.</SPAN></P></LI><LI><P><SPAN>Feet — The units are feet.</SPAN></P></LI><LI><P><SPAN>Yards —The units are yards.</SPAN></P></LI><LI><P><SPAN>Miles — The units are miles.</SPAN></P></LI></UL></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>The units for the Surface Offset parameter. </SPAN></P><P><SPAN>The default is meters.</SPAN></P><UL><LI><P><SPAN>Meters — The units are meters. This is the default.</SPAN></P></LI><LI><P><SPAN>Kilometers — The units are kilometers.</SPAN></P></LI><LI><P><SPAN>Feet — The units are feet.</SPAN></P></LI><LI><P><SPAN>Yards — The units are yards.</SPAN></P></LI><LI><P><SPAN>Miles — The units are miles.</SPAN></P></LI></UL></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>Determine if the viewshed polygons are to be generalized or not.</SPAN></P><P><SPAN>The viewshed calculation is based upon a raster elevation model which creates a result with stair-stepped edges. To create a more pleasing appearance and improve performance, the default behavior is to generalize the polygons. This generalization will not change the accuracy of the result for any location more than one half of the DEM's resolution.</SPAN></P><UL><LI><P><SPAN>Checked — Generalizes the results. This is the default.</SPAN></P></LI><LI><P><SPAN>Unchecked — No generalization of the output polygons will occur.</SPAN></P></LI></UL></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>Determine if the viewshed polygons are to be generalized or not.</SPAN></P><P><SPAN>The viewshed calculation is based upon a raster elevation model which creates a result with stair-stepped edges. To create a more pleasing appearance and improve performance, the default behavior is to generalize the polygons. This generalization will not change the accuracy of the result for any location more than one half of the DEM's resolution.</SPAN></P><UL><LI><P><SPAN>True — Generalizes the results. This is the default</SPAN></P></LI><LI><P><SPAN>False — No generalization of the output polygons will occur</SPAN></P></LI></UL></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P STYLE="margin:1 1 1 0;"><SPAN>Returns polygons of visible areas for a given set of input observation points.</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><UL><LI><P><SPAN>There are several elevation sources currently available which are at different spatial resolutions and cover different areas. Not all resolutions are available for all areas. The service will return an error message if the specified resolution is not available at any of the input observer locations. </SPAN></P></LI><LI><P><SPAN>If the DEM Resolution parameter is empty or not supplied, then the coarsest resolution (90m) will be used. If FINEST is specified, then the service will use the smallest resolution available at your observer location allowed by the maximum distance parameter. </SPAN></P></LI><LI><P><SPAN>For the MaximumDistance parameter itself, the allowed value for the 10m and 30m DEM resolutions is 15 kilometers or less. For the 90m DEM resolution, the allowed value is 50 kilometers or less. If this parameter is not specified, the task will use a default value based on the DEM resolution parameter. For 10m resolution, the default maximum distance is 5 kilometers. For both the 30m and the 90m DEM resolutions, the default distance is 15 kilometers.</SPAN></P></LI><LI><P><SPAN>The service uses a single resolution elevation source for the input features. The entire input features must fit into a single resolution, or else the service will pick the highest resolution which can cover the input features.</SPAN></P></LI><LI><P><SPAN>Visibility into water is limited, so the tool uses the water surface as the elevation service. Oceans have been assigned a value of zero and major water bodies have been assigned an appropriate flat local elevation.</SPAN></P></LI><LI><P><SPAN>It is possible to control the viewshed analysis using the observer attribute fields. The supported fields are OFFSETA, OFFSETB, AZIMUTH1, AZIMUTH2, VERT1, VERT2, and SPOT. The attribute fields RADIUS1 and RADIUS2 are not supported by the Viewshed service. Fields OFFSETA and OFFSETB are available on the input observer feature set schema template if you are using the service in ArcMap. For additional explanation of using these fields to control your analysis, see </SPAN><A href="http://resources.arcgis.com/en/help/main/10.2/index.html#/Using_Viewshed_and_Observer_Points_for_visibility_analysis/00q90000008n000000/"><SPAN>Using Viewshed and Observer Points for visibility analysis</SPAN></A><SPAN>.</SPAN></P></LI><LI><P><SPAN>The output viewshed is returned as polygon features. The field named "Frequency" is used to record the number of observation points that can see each polygon. The field named "DEMResolution" is used to record the source DEM resolution for the viewshed computation.</SPAN></P></LI><LI><P><SPAN>A lower DEM resolution will result in a faster response from the service. For example, the 90m resolution has the shortest response time from the service. The tradeoff is that a lower DEM resolution has a lower accuracy in the viewshed result compared to that of a higher DEM resolution.</SPAN></P></LI><LI><P><SPAN>The Maximum Distance parameter may also affect the Viewshed service response time. In general, using a smaller distance results in a shorter response time.</SPAN></P></LI><LI><P><SPAN>The maximum number of input points is 1000. If more input points are provided, the service will return an error and will not execute.</SPAN></P></LI></UL></DIV></DIV></DIV>Viewshed service example (stand-alone script)<DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>This example consumes the Viewshed service in python and save the viewshed result as a shapefile locally.</SPAN></P></DIV></DIV></DIV>import time 2 | import arcpy 3 | arcpy.ImportToolbox("http://elevation.arcgis.com/arcgis/services;Tools/Elevation", "elev") 4 | result = arcpy.Viewshed_elev(r"d:\test\testdata.gdb\sumelelvpnt1", "15000", "Meters", "FINEST") 5 | 6 | while result.status < 4: 7 | print result.status 8 | time.sleep(0.2) 9 | print "Execution Finished" 10 | 11 | arcpy.CopyFeatures_management(result.getOutput(0), r'c:\output\viewshd1.shp') 12 | c:\program files (x86)\arcgis\desktop10.2\Help\gp/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsK 13 | CwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQU 14 | FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wAARCAC7AMIDASIA 15 | AhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQA 16 | AAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3 17 | ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWm 18 | p6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEA 19 | AwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSEx 20 | BhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElK 21 | U1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3 22 | uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD4/gmS 23 | /sEibEjbeV/rXPahbtZXSAMQp5U+lPkklsZFKtlWGVI71M+of2p5cTxq8mdqsvBya83W2p5SO/8A 24 | hD4duPGmt7BKYDbxsXmChsL2OMjPJA/GovGd0LfQrgKy7pMKM9817T8EvAMvgHwzNLektfX5EssO 25 | 3bsAyFX1zgkn64wMHPhvir4f+MLyCW8vtJNpp1qN+EnjkKqOrEKxPHXOOBk18tgs5oYjHV6UqsVC 26 | PKo3aV3re3fWy08rbnuYjLKlHDUqig3J3b0ei0tftpd/8MYngO+SO4vLWQKFmj3BmGSNucgfmKx9 27 | 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 295 | -------------------------------------------------------------------------------- /ElevationPro/ElevationTools.pyt: -------------------------------------------------------------------------------- 1 | ## Copyright 2020 Esri 2 | ## Licensed under the Apache License, Version 2.0 (the "License"); 3 | ## you may not use this file except in compliance with the License. 4 | ## You may obtain a copy of the License at 5 | ## http://www.apache.org/licenses/LICENSE-2.0 6 | ## Unless required by applicable law or agreed to in writing, software 7 | ## distributed under the License is distributed on an "AS IS" BASIS, 8 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 9 | ## See the License for the specific language governing permissions and 10 | ## limitations under the License. 11 | 12 | import sys 13 | import os 14 | import json 15 | import time 16 | import arcpy 17 | 18 | class Toolbox(object): 19 | def __init__(self): 20 | """Define the toolbox (the name of the toolbox is the name of the 21 | .pyt file).""" 22 | self.label = "ElevationTools" 23 | self.alias = "elev" 24 | 25 | # List of tool classes associated with this toolbox 26 | self.tools = [Viewshed] 27 | 28 | class Viewshed(object): 29 | def __init__(self): 30 | """Define the tool (tool name is the name of the class).""" 31 | self.label = "Viewshed" 32 | self.description = ("Calculate viewshed for user specified observer " + 33 | "locations.") 34 | self.canRunInBackground = False 35 | ### service variables 36 | self.visiFieldName = "Frequency" 37 | self.metadataFieldName = "DEMResolution" 38 | self.perimeterFieldName = "PerimeterKm" 39 | self.areaFieldName = "AreaSqKm" 40 | self.defaultObsOffset = 1.75 41 | self.defaultTargetOffset = 0 42 | self.useEarthCurvatureCorrection = True 43 | self.listLinearUnits = ["Meters", "Kilometers", "Feet", "Yards", "Miles"] 44 | #-------------------------------------------- 45 | #Input observer point schema 46 | #-------------------------------------------- 47 | self.observerSchema = r".\Data\Boundary.gdb\obs_schema" 48 | #-------------------------------------------- 49 | #Output symbology 50 | #-------------------------------------------- 51 | #self.outputSymbology = r".\outputsymbology.lyr" 52 | #-------------------------------------------- 53 | #DEM resolutions 54 | #-------------------------------------------- 55 | self.dictDEMSources = {"30m":"30", "60m":"60", "90m":"90"} 56 | self.defaultDEMResolution = '90' 57 | self.defaultDEMMetadata = ["SRTM", "USGS, NASA, CGIAR", "http://www.cgiar-csi.org/"] 58 | #-------------------------------------------- 59 | #Data source layers 60 | #-------------------------------------------- 61 | self.dictMosaicLayers = {'30':r'C:\elevation-gp-python-master\ElevationPro\Data\Elevation.gdb\dem30m', 62 | '60':r'C:\elevation-gp-python-master\ElevationPro\Data\Elevation.gdb\dem60m', 63 | '90':r'C:\elevation-gp-python-master\ElevationPro\Data\Elevation.gdb\dem90m'} 64 | self.resolutionCoverage = r'C:\elevation-gp-python-master\ElevationPro\Data\Boundary.gdb\databoundary' 65 | #-------------------------------------------- 66 | #default and maximum radiuses 67 | #-------------------------------------------- 68 | self.dictDefaultRadius = {'30':5000, '60':15000, '90':15000} 69 | self.dictMaxRadius = {'30':15000, '60':30000, '90':50000} 70 | self.dictMaxRadiusFinest = {'30':5000, '60':15000, '90':50000} 71 | self.errorMessages = ["One or more input observer points are outside of the area covered by the DEM source. Use a coarser resolution DEM or make sure all the input points are inside the DEM source.", 72 | "Input maximum distance exceeds the maximum value permitted. Reduce the maximum distance value or use a coarser resolution DEM.", 73 | "Input DEM source is not available at observer location. Select a difference DEM source.", 74 | "No input observer points found. The input observer features must contain at least one point.", 75 | "Number of input observer points exceeds the maximum number permitted. The allowed maximum number of input observer points is 25.", 76 | "Input units is not valid. The supported units are meters, kilometers, feet, yards and miles.", 77 | "Input DEM resolution {0} is not available. Select a different DEM source.", 78 | "Input observer feature(s) are not point shape type. Input observer features must be points.", 79 | "Input numeric value {0} is not valid.", 80 | "Input units string {0} is not valid.", 81 | "No DEM source was found at the observer locations. Make sure all the input points are covered by the DEM source, or use a coarser resolution DEM."] 82 | 83 | def getDefaultRadius(self, res): 84 | if not res in self.dictMosaicLayers.keys(): 85 | arcpy.AddError(self.errorMessages[6].format(res)) 86 | raise 87 | return 88 | return self.dictDefaultRadius[res] 89 | 90 | def getMaxRadius(self, res): 91 | if not res in self.dictMosaicLayers.keys(): 92 | arcpy.AddError(self.errorMessages[6].format(res)) 93 | raise 94 | return 95 | return self.dictMaxRadius[res] 96 | 97 | def getMaxRadiusFinest(self, res): 98 | if not res in self.dictMosaicLayers.keys(): 99 | arcpy.AddError(self.errorMessages[6].format(res)) 100 | raise 101 | return 102 | return self.dictMaxRadiusFinest[res] 103 | 104 | def getLayerName(self, res): 105 | if not res in self.dictMosaicLayers.keys(): 106 | arcpy.AddError(self.errorMessages[6].format(res)) 107 | raise 108 | return 109 | return self.dictMosaicLayers[res] 110 | 111 | def getPS(self, res): 112 | if not res in self.dictPS.keys(): 113 | arcpy.AddError(self.errorMessages[6].format(res)) 114 | raise 115 | return 116 | return self.dictPS[res] 117 | 118 | def getUnitConversionFactor(self, u1): # get conversion factor 119 | uFactor = 1 120 | inUnit = u1.strip().lower() 121 | if inUnit in ["meters", "meter"]: 122 | uFactor = 1 123 | if inUnit in ["centimeters", "centimeter"]: 124 | uFactor = 0.01 125 | if inUnit in ["decimaldegrees", "decimaldegree"]: 126 | arcpy.AddError(self.errorMessages[3]) 127 | raise 128 | if inUnit in ["decimeters", "decimeter"]: 129 | uFactor = 0.1 130 | if inUnit in ["feet", "foot"]: 131 | uFactor = 0.3048 132 | if inUnit in ["foot_us", "feet_us"]: 133 | uFactor = 0.3048006096012192 134 | if inUnit in ["inches","inch"]: 135 | uFactor = 0.0254 136 | if inUnit in ["kilometers", "kilometer"]: 137 | uFactor = 1000 138 | if inUnit in ["miles","mile"]: 139 | uFactor = 1609.344 140 | if inUnit in ["millimeters", "millimeter"]: 141 | uFactor = 0.001 142 | if inUnit in ["nauticalmiles", "nauticalmile"]: 143 | uFactor = 1852 144 | if inUnit in ["points", "point"]: 145 | uFactor = 0.000352777778 146 | if inUnit in ["unknown", ""]: 147 | uFactor = 1 148 | if inUnit in ["yards", "yard"]: 149 | uFactor = 0.91440 150 | return uFactor 151 | 152 | def createBuffer(self, in_points, in_dist): 153 | useGCSBuffer = True 154 | if useGCSBuffer: 155 | arcpy.env.outputCoordinateSystem = 4326 # create buffer in GCS_WGS_1984 156 | bufferTemp = os.path.join(r"in_memory","obsbuffertemp01") 157 | arcpy.Buffer_analysis(in_points, bufferTemp, str(in_dist) + " Meters", 158 | "FULL", "ROUND", "NONE", "") 159 | arcpy.env.outputCoordinateSystem = "" 160 | 161 | bufferOutput = bufferTemp 162 | else: 163 | bufferOutput = os.path.join("in_memory","obsbuffertemp02") 164 | arcpy.Buffer_analysis(in_points, bufferOutput, str(in_dist) + " Meters", 165 | "FULL", "ROUND", "NONE", "") 166 | return bufferOutput 167 | 168 | def featureFootprintTest(self, in_features, containment_poly, test_type="contains"): 169 | footPrt = containment_poly 170 | resList = [] 171 | if test_type.lower() == "contains": 172 | arcpy.SelectLayerByLocation_management(footPrt, "COMPLETELY_CONTAINS", 173 | in_features, selection_type="NEW_SELECTION") 174 | elif test_type.lower() == "intersect": 175 | arcpy.SelectLayerByLocation_management(footPrt, "INTERSECT", 176 | in_features, selection_type="NEW_SELECTION") 177 | else: 178 | pass 179 | with arcpy.da.SearchCursor(footPrt, ("res", "prd", "src", "srcurl", "polytype")) as cursor: 180 | for row in cursor: 181 | resList.append(row) 182 | return resList 183 | 184 | def ContainmentCheck(self, in_point_or_buffer): 185 | arcpy.management.MakeFeatureLayer(self.resolutionCoverage, 'databoundary_containment', 'polytype = 0 Or polytype = 1') 186 | containment_layer = "databoundary_containment" 187 | foot_candidates = self.featureFootprintTest(in_point_or_buffer, containment_layer) 188 | dict_res = {} 189 | for t in foot_candidates: 190 | k1 = int(t[0]) 191 | v1 = (t[1], t[2], t[3], t[4]) 192 | dict_res[k1] = v1 193 | 194 | if len(dict_res) == 0: 195 | arcpy.AddError(self.errorMessages[2]) 196 | raise 197 | return dict_res 198 | 199 | def CreditCheck(self, in_points, dem_res): 200 | arcpy.management.MakeFeatureLayer(self.resolutionCoverage, 'databoundary_credit', 'polytype = 2') 201 | credit_layer = "databoundary_credit" 202 | foot_candidates = self.featureFootprintTest(in_points, credit_layer, test_type="intersect") 203 | list_prd = [] 204 | list_src = [] 205 | list_srcurl = [] 206 | for t in foot_candidates: 207 | k1 = int(t[0]) 208 | if k1 == dem_res: # match resolution 209 | prd = t[1].rsplit(",") 210 | for p in prd: 211 | if not p.strip() in list_prd: 212 | list_prd.append(p.strip()) 213 | src = t[2].rsplit(",") 214 | for s in src: 215 | if not s.strip() in list_src: 216 | list_src.append(s.strip()) 217 | srcurl = t[3].rsplit(",") 218 | for u in srcurl: 219 | if not u.strip() in list_srcurl: 220 | list_srcurl.append(u.strip()) 221 | 222 | prd_string = ", ".join(list_prd) 223 | src_string = ", ".join(list_src) 224 | srcurl_string = ", ".join(list_srcurl) 225 | 226 | credit_list = [prd_string, src_string, srcurl_string] 227 | #if len(list_credit) == 0: 228 | # arcpy.AddError(self.errorMessages[2]) 229 | # raise 230 | return credit_list 231 | 232 | def validateNumerical(self, inVal, paramStr): 233 | if inVal == None: # None is OK 234 | return 235 | elif inVal < 0: 236 | arcpy.AddError(self.errorMessages[8].format(paramStr)) 237 | raise 238 | 239 | def validateDistanceUnits(self, inStr, paramStr): 240 | tempUnitsList = [s.lower() for s in self.listLinearUnits] 241 | tempUnitsList.extend(["#", ""]) 242 | if inStr == None: # None is OK 243 | return 244 | elif not (inStr.strip().lower() in tempUnitsList): 245 | arcpy.AddError(self.errorMessages[9].format(paramStr)) 246 | raise 247 | 248 | def validateInputDEMSource(self, inDEM): 249 | tempDEMList = [s.upper() for s in self.dictDEMSources.keys()] 250 | tempDEMList.extend(["", "FINEST", "#"]) 251 | if inDEM == None: # None is OK 252 | return 253 | elif not (inDEM.strip().upper() in tempDEMList): 254 | arcpy.AddError(self.errorMessages[6].format(inDEM)) 255 | raise 256 | 257 | def formatInputDEMSource(self, inSource): 258 | tempDEMList = list(self.dictDEMSources.keys()) 259 | tempDEMList.extend(["", "FINEST"]) 260 | retVal = inSource 261 | for d in tempDEMList: 262 | if inSource.upper() == d.upper(): 263 | retVal = d 264 | break 265 | return retVal 266 | 267 | def LogUsageMetering(self, taskName, numObjects, cost, startTime, values): 268 | elapsed = time.time() - startTime 269 | valuesMsg = taskName + json.dumps(values) 270 | 271 | arcpy.AddMessage("NumObjects: {} Cost: {}".format(numObjects, cost)) 272 | arcpy.AddMessage(u"{0} Elapsed: {1:.3f}".format(valuesMsg, elapsed)) 273 | #arcpy.gp._arc_object.LogUsageMetering(5555, taskName, numObjects, cost) 274 | arcpy.gp._arc_object.LogUsageMetering(7777, valuesMsg, numObjects, elapsed) 275 | 276 | def GetUnitsIndex(self, in_units): 277 | unitsIndex = 0 278 | listUnits = ["meters", "kilometers", "feet", "yards", "miles"] 279 | if in_units == None or in_units == "": 280 | unitsIndex = 0 # meters 281 | else: 282 | try: 283 | unitsIndex = listUnits.index(in_units.lower()) 284 | except: 285 | unitsIndex = 0 286 | return unitsIndex 287 | 288 | def executeVisibility(self, mosaic_layer, in_points, obs_count, in_buffer, credit_list, maximum_distance, 289 | dem_resolution, obs_offset1, surface_offset1, 290 | generalize_output, out_viewshed_fc): 291 | 292 | try: 293 | 294 | # Buffer input point to get clip extent 295 | if in_buffer is None: 296 | bufferOutput = self.createBuffer(in_points, maximum_distance) 297 | else: 298 | bufferOutput = in_buffer 299 | 300 | ##pixel_size = self.getPS(dem_resolution) 301 | arcpy.env.extent = bufferOutput 302 | arcpy.env.mask = bufferOutput 303 | arcpy.env.snapRaster = mosaic_layer 304 | arcpy.env.outputCoordinateSystem = 102100 305 | ##arcpy.env.cellSize = pixel_size 306 | 307 | zFactor = 1 308 | ecc = "CURVED_EARTH" 309 | exeString = ("Maximum distance: " + str(maximum_distance) + " meters, DEM resolution: " + str(dem_resolution) + 310 | " meters, Mosaic Layer: " + mosaic_layer + ", Observer offset: " + str(obs_offset1) + 311 | ", Surface offset: " + str(surface_offset1) + ".") 312 | arcpy.AddMessage(exeString) 313 | scratchWS = "in_memory" 314 | outvsd0 = os.path.join(arcpy.env.scratchFolder, "viewrastmp0.tif") 315 | outvsd = os.path.join(arcpy.env.scratchFolder, "viewrastmp") 316 | v = arcpy.gp.Visibility_sa(mosaic_layer, in_points, outvsd0, "#", "FREQUENCY", "NODATA", 317 | zFactor, ecc, "#", surface_offset1, "#", obs_offset1, "#") 318 | 319 | arcpy.env.extent = "" 320 | arcpy.env.mask = "" 321 | arcpy.env.snapRaster = "" 322 | arcpy.env.outputCoordinateSystem = "" 323 | arcpy.env.cellSize = "" 324 | 325 | # Raster to Polygon 326 | smoothOutput = "NO_SIMPLIFY" 327 | if generalize_output == True or generalize_output == "GENERALIZE": 328 | smoothOutput = "SIMPLIFY" 329 | #Generalize - remove small areas 330 | arcpy.gp.BoundaryClean_sa(outvsd0, outvsd) 331 | else: 332 | smoothOutput = "NO_SIMPLIFY" 333 | outvsd = outvsd0 334 | 335 | visiPolygon = r"in_memory\visipolytmp" 336 | arcpy.RasterToPolygon_conversion(outvsd, visiPolygon, smoothOutput, "VALUE") 337 | # Dissolve 338 | visiPolygonDisv = out_viewshed_fc ## r"in_memory\visipolytmpdsv" 339 | arcpy.Dissolve_management(visiPolygon, visiPolygonDisv, "gridcode") 340 | # Rename gridcode 341 | arcpy.AddField_management(visiPolygonDisv, self.visiFieldName, "LONG") 342 | arcpy.CalculateField_management(visiPolygonDisv, self.visiFieldName, "!gridcode!", "PYTHON") 343 | arcpy.DeleteField_management(visiPolygonDisv, "gridcode") 344 | arcpy.AddField_management(visiPolygonDisv, self.metadataFieldName, "TEXT", field_length=50, field_alias="DEM Resolution") 345 | arcpy.AddField_management(visiPolygonDisv, "ProductName", "TEXT", field_length=50, field_alias="Product Name") 346 | arcpy.AddField_management(visiPolygonDisv, "Source", "TEXT", field_length=50, field_alias="Source") 347 | arcpy.AddField_management(visiPolygonDisv, "Source_URL", "TEXT", field_length=84, field_alias="Source URL") 348 | # Add metadata info 349 | dem_source = [k for k, v in self.dictDEMSources.items() if v == str(dem_resolution)] 350 | arcpy.CalculateField_management(visiPolygonDisv, self.metadataFieldName, "'" + dem_source[0] + "'", "PYTHON") 351 | product_name = credit_list[0] #self.dictProductName[str(dem_resolution)] 352 | arcpy.CalculateField_management(visiPolygonDisv, "ProductName", "'" + product_name + "'", "PYTHON") 353 | source1 = credit_list[1] #self.dictSource[str(dem_resolution)] 354 | arcpy.CalculateField_management(visiPolygonDisv, "Source", "'" + source1 + "'", "PYTHON") 355 | sourceURL1 = credit_list[2] #self.dictSourceURL[str(dem_resolution)] 356 | arcpy.CalculateField_management(visiPolygonDisv, "Source_URL", "'" + sourceURL1 + "'", "PYTHON") 357 | # Add and calculate length and area field 358 | try: 359 | arcpy.AddField_management(visiPolygonDisv, self.perimeterFieldName, "DOUBLE", field_alias="Perimeter Kilometers") 360 | arcpy.AddField_management(visiPolygonDisv, self.areaFieldName, "DOUBLE", field_alias="Area Square Kilometers") 361 | arcpy.CalculateField_management(visiPolygonDisv, self.perimeterFieldName, "!shape.geodesicLength@meters! / 1000", "PYTHON") 362 | arcpy.CalculateField_management(visiPolygonDisv, self.areaFieldName, "!shape.geodesicArea@meters! / 1000000", "PYTHON") 363 | except: 364 | pass 365 | out_ras = out_viewshed_fc 366 | return out_ras 367 | except: 368 | msgs = arcpy.GetMessages(2) 369 | arcpy.AddError(msgs) 370 | raise 371 | return 0 372 | 373 | def getParameterInfo(self): 374 | """Define parameter definitions""" 375 | param0 = arcpy.Parameter(name="InputPoints", 376 | displayName="Input Point Features", 377 | direction="Input", 378 | parameterType="Required", 379 | datatype="GPFeatureRecordSetLayer") 380 | 381 | param0.value = self.observerSchema 382 | 383 | param1 = arcpy.Parameter(name="MaximumDistance", 384 | displayName="Maximum Distance", 385 | direction="Input", 386 | parameterType="Optional", 387 | datatype="GPDouble") 388 | param1.value = None 389 | 390 | param2 = arcpy.Parameter(name="MaximumDistanceUnits", 391 | displayName="Maximum Distance Units", 392 | direction="Input", 393 | parameterType="Optional", 394 | datatype="GPString") 395 | param2.filter.type = "ValueList" 396 | param2.filter.list = self.listLinearUnits 397 | param2.value = "Meters" 398 | 399 | param3 = arcpy.Parameter(name="DEMResolution", 400 | displayName="DEM Resolution", 401 | direction="Input", 402 | parameterType="Optional", 403 | datatype="GPString") 404 | param3.filter.type = "ValueList" 405 | list_dem = ["FINEST"] 406 | dem_keys = list(self.dictDEMSources.keys()) 407 | dem_keys.sort() 408 | list_dem.extend(dem_keys) 409 | param3.filter.list = list_dem 410 | 411 | param4 = arcpy.Parameter(name="ObserverHeight", 412 | displayName="Observer Height", 413 | direction="Input", 414 | parameterType="Optional", 415 | datatype="GPDouble") 416 | param4.value = self.defaultObsOffset 417 | 418 | param5 = arcpy.Parameter(name="ObserverHeightUnits", 419 | displayName="Observer Height Units", 420 | direction="Input", 421 | parameterType="Optional", 422 | datatype="GPString") 423 | param5.filter.type = "ValueList" 424 | param5.filter.list = self.listLinearUnits 425 | param5.value = "Meters" 426 | 427 | param6 = arcpy.Parameter(name="SurfaceOffset", 428 | displayName="Surface Offset", 429 | direction="Input", 430 | parameterType="Optional", 431 | datatype="GPDouble") 432 | param6.value = self.defaultTargetOffset 433 | 434 | param7 = arcpy.Parameter(name="SurfaceOffsetUnits", 435 | displayName="Surface Offset Units", 436 | direction="Input", 437 | parameterType="Optional", 438 | datatype="GPString") 439 | param7.filter.type = "ValueList" 440 | param7.filter.list = self.listLinearUnits 441 | param7.value = "Meters" 442 | 443 | param8 = arcpy.Parameter(name="GeneralizeViewshedPolygons", 444 | displayName="Generalize Viewshed Polygons", 445 | direction="Input", 446 | parameterType="Optional", 447 | datatype="GPBoolean") 448 | param8.value = True 449 | param8.filter.type = "ValueList" 450 | param8.filter.list = ["GENERALIZE", "NO_GENERALIZE"] 451 | 452 | param9 = arcpy.Parameter(name="OutputViewshed", 453 | displayName="Output Viewshed", 454 | direction="Output", 455 | parameterType="Derived", 456 | datatype="DEFeatureClass") 457 | #symbology=self.outputSymbology 458 | #param9.value = os.path.join(os.path.dirname(__file__), "Data", "viewshedout.shp") 459 | 460 | params = [param0, param1, param2, param3, param4, 461 | param5, param6, param7, param8, param9] 462 | return params 463 | 464 | def isLicensed(self): 465 | """Set whether tool is licensed to execute.""" 466 | return True 467 | 468 | def updateParameters(self, parameters): 469 | """Modify the values and properties of parameters before internal 470 | validation is performed. This method is called whenever a parameter 471 | has been changed.""" 472 | return 473 | 474 | def updateMessages(self, parameters): 475 | """Modify the messages created by internal validation for each tool 476 | parameter. This method is called after internal validation.""" 477 | return 478 | 479 | def execute(self, parameters, messages): 480 | """The source code of the tool.""" 481 | try: 482 | startTime = time.time() 483 | 484 | in_points0 = parameters[0].value 485 | maximum_distance_p = parameters[1].value 486 | distance_unit = parameters[2].valueAsText 487 | dem_resolution_p = parameters[3].valueAsText 488 | obs_offset_p = parameters[4].value 489 | obs_offset_unit = parameters[5].valueAsText 490 | surface_offset_p = parameters[6].value 491 | surface_offset_unit = parameters[7].valueAsText 492 | generalize_output = parameters[8].value 493 | 494 | # var for metering 495 | maxDistanceSp = 0 496 | obsOffsetSp = 0 497 | surOffsetSp = 0 498 | demSourceIdx = 0 499 | 500 | scratchWS = "in_memory" 501 | out_viewshed_fc = os.path.join(scratchWS, "viewshedpoly") 502 | 503 | obs_offset_altered = parameters[4].altered 504 | arcpy.env.overwriteOutput = True 505 | 506 | # make a copy of the input 507 | in_points = "in_memory/viewshedinpnts" 508 | arcpy.env.outputCoordinateSystem = 4326 509 | arcpy.CopyFeatures_management(in_points0, in_points) 510 | arcpy.env.outputCoordinateSystem = "" 511 | 512 | # validate # of observer points specified 513 | gCounts = 0 514 | gCounts = arcpy.GetCount_management(in_points) 515 | pntCounts = int(gCounts.getOutput(0)) 516 | if pntCounts < 1: 517 | arcpy.AddError(self.errorMessages[3]) 518 | raise 519 | return 520 | if pntCounts > 1000: # limit of input features 521 | arcpy.AddError(self.errorMessages[4]) 522 | raise 523 | return 524 | 525 | self.validateNumerical(obs_offset_p, "Observer Offset") 526 | self.validateNumerical(surface_offset_p, "Surface Offset") 527 | self.validateInputDEMSource(dem_resolution_p) 528 | 529 | self.validateDistanceUnits(distance_unit, "Maximum Distance Units") 530 | self.validateDistanceUnits(obs_offset_unit, "Observer Offset Units") 531 | self.validateDistanceUnits(surface_offset_unit, "Surface Offset Units") 532 | 533 | demSourceIdx = dem_resolution_p # metering 534 | 535 | if dem_resolution_p is not None and str(dem_resolution_p).upper() != "FINEST": 536 | if dem_resolution_p.strip() == "": 537 | dem_resolution_p = None 538 | if dem_resolution_p is not None: 539 | dem_resolution_p = self.dictDEMSources[self.formatInputDEMSource(dem_resolution_p)] 540 | 541 | if obs_offset_unit == None: 542 | obs_offset_unit = "meters" 543 | 544 | if surface_offset_unit == None: 545 | surface_offset_unit = "meters" 546 | 547 | if obs_offset_p == None: 548 | obsOffsetSp = 0 549 | obs_offset = "#" 550 | else: 551 | obsOffsetSp = 1 552 | if obs_offset_p == 0 and obs_offset_altered == False: 553 | obs_offset = "#" 554 | else: 555 | obs_offset = obs_offset_p * self.getUnitConversionFactor(obs_offset_unit) 556 | 557 | if surface_offset_p == None: 558 | surOffsetSp = 0 559 | surface_offset = "#" 560 | else: 561 | surOffsetSp = 1 562 | surface_offset = surface_offset_p * self.getUnitConversionFactor(surface_offset_unit) 563 | 564 | mosaic_layer = "" 565 | 566 | res_dict = None 567 | buf_dict = None 568 | # case 1 569 | if maximum_distance_p == None and dem_resolution_p == None: 570 | maxDistanceSp = 0 # metering 571 | dem_resolution = self.defaultDEMResolution #'90' 572 | maximum_distance = self.getDefaultRadius(dem_resolution) 573 | buf1 = None 574 | #buf1 = self.createBuffer(in_points, maximum_distance) 575 | #testRes = self.bufferFootprintTest(buf1) 576 | testRes = [int(self.defaultDEMResolution)] 577 | if int(dem_resolution) in testRes: 578 | pass 579 | else: 580 | arcpy.AddError(self.errorMessages[0]) 581 | raise 582 | 583 | # case 2 584 | if maximum_distance_p is not None and dem_resolution_p == None: 585 | maxDistanceSp = 1 # metering 586 | maximum_distance = maximum_distance_p * self.getUnitConversionFactor(distance_unit) 587 | dem_resolution = self.defaultDEMResolution #'90' 588 | if maximum_distance > self.getMaxRadius(dem_resolution) or maximum_distance <= 0: 589 | arcpy.AddError(self.errorMessages[1]) 590 | raise 591 | else: 592 | buf1 = None 593 | #buf1 = self.createBuffer(in_points, maximum_distance) 594 | #testRes = self.bufferFootprintTest(buf1) 595 | testRes = [int(self.defaultDEMResolution)] 596 | if int(dem_resolution) in testRes: 597 | pass 598 | else: 599 | arcpy.AddError(self.errorMessages[0]) 600 | raise 601 | 602 | # case 3 603 | if maximum_distance_p == None and str(dem_resolution_p).upper() == "FINEST": 604 | maxDistanceSp = 0 # metering 605 | res_dict = self.ContainmentCheck(in_points) 606 | testRes = list(res_dict.keys()) 607 | if len(testRes) == 0: 608 | arcpy.AddError(self.errorMessages[0])## 609 | raise 610 | return 611 | 612 | testRes.sort() 613 | matchFound = False 614 | for r1 in testRes: 615 | dem_resolution = str(r1) 616 | maximum_distance = self.getDefaultRadius(dem_resolution) 617 | buf1 = self.createBuffer(in_points, maximum_distance) 618 | buf_dict = self.ContainmentCheck(buf1) 619 | bufRes = list(buf_dict.keys()) 620 | if r1 in bufRes: 621 | matchFound = True 622 | break 623 | if not matchFound: 624 | arcpy.AddError(self.errorMessages[10]) 625 | raise 626 | 627 | # case 4 628 | if maximum_distance_p is not None and str(dem_resolution_p).upper() == "FINEST": 629 | maxDistanceSp = 1 # metering 630 | maximum_distance = maximum_distance_p * self.getUnitConversionFactor(distance_unit) 631 | if maximum_distance > self.getMaxRadius(self.defaultDEMResolution) or maximum_distance <= 0: 632 | arcpy.AddError(self.errorMessages[1]) 633 | raise 634 | return 635 | # get all resolutions available 636 | res_dict = self.ContainmentCheck(in_points) 637 | testRes = list(res_dict.keys()) 638 | testRes.sort() 639 | # find a finest resolution with the given distance 640 | resl = 0 641 | for r1 in testRes: 642 | d1 = self.getMaxRadiusFinest(str(r1)) 643 | if maximum_distance <= d1: 644 | buf1 = self.createBuffer(in_points, maximum_distance) 645 | buf_dict = self.ContainmentCheck(buf1) 646 | bufRes = buf_dict.keys() 647 | if r1 in bufRes: 648 | resl = r1 649 | break 650 | 651 | if resl == 0: 652 | arcpy.AddError(self.errorMessages[1])## 653 | raise 654 | return 655 | else: 656 | dem_resolution = str(resl) 657 | 658 | # case 5 659 | if maximum_distance_p is None and dem_resolution_p is not None and str(dem_resolution_p).upper() != "FINEST": 660 | maxDistanceSp = 0 # metering 661 | dem_resolution = dem_resolution_p 662 | maximum_distance = self.getDefaultRadius(dem_resolution) 663 | if str(int(dem_resolution)) != self.defaultDEMResolution: 664 | buf1 = self.createBuffer(in_points, maximum_distance) 665 | buf_dict = self.ContainmentCheck(buf1) 666 | bufRes = list(buf_dict.keys()) 667 | else: # for 90m data, no need to do buffer test 668 | bufRes = [int(self.defaultDEMResolution)] 669 | buf1 = None 670 | if int(dem_resolution) in bufRes: 671 | pass 672 | else: 673 | arcpy.AddError(self.errorMessages[2]) 674 | raise 675 | 676 | # case 6 677 | if maximum_distance_p is not None and dem_resolution_p is not None and str(dem_resolution_p).upper() != "FINEST": 678 | maxDistanceSp = 1 # metering 679 | dem_resolution = dem_resolution_p 680 | #if dem_resolution == '230': 681 | # dem_resolution = '231' 682 | maximum_distance = maximum_distance_p * self.getUnitConversionFactor(distance_unit) 683 | if maximum_distance > self.getMaxRadius(dem_resolution) or maximum_distance <= 0: 684 | arcpy.AddError(self.errorMessages[1]) 685 | raise 686 | else: 687 | if str(int(dem_resolution)) != self.defaultDEMResolution: 688 | buf1 = self.createBuffer(in_points, maximum_distance) 689 | buf_dict = self.ContainmentCheck(buf1) 690 | bufRes = list(buf_dict.keys()) 691 | else: # for 90m data, no need to do buffer test 692 | bufRes = [int(self.defaultDEMResolution)] 693 | buf1 = None 694 | if int(dem_resolution) in bufRes: 695 | pass 696 | #arcpy.SetParameterAsText(1, outRas) 697 | else: 698 | arcpy.AddError(self.errorMessages[2]) 699 | raise 700 | 701 | # gather credit information 702 | if buf_dict is not None: 703 | res_dict = buf_dict 704 | 705 | if res_dict is None: # 90m 706 | credit_list = self.defaultDEMMetadata 707 | else: 708 | credit_tuple = res_dict[int(dem_resolution)] 709 | credit_list = [] 710 | polytype = credit_tuple[3] 711 | if polytype > 0: # 1 or 2, already contains credit info 712 | prd = credit_tuple[0].strip() 713 | src = credit_tuple[1].strip() 714 | srcurl = credit_tuple[2].strip() 715 | credit_list = [prd, src, srcurl] 716 | else: # 0, containment only polygons, need credit check 717 | credit_list = self.CreditCheck(in_points, int(dem_resolution)) 718 | 719 | mosaic_layer = self.getLayerName(dem_resolution) 720 | outRas = self.executeVisibility(mosaic_layer, in_points, pntCounts, buf1, credit_list, 721 | maximum_distance, dem_resolution, obs_offset, surface_offset, 722 | generalize_output, out_viewshed_fc) 723 | 724 | arcpy.SetParameterAsText(9, out_viewshed_fc) 725 | 726 | # Metering 727 | maxDistUnitsIdx = self.GetUnitsIndex(distance_unit) 728 | obsOffsetUnitsIdx = self.GetUnitsIndex(obs_offset_unit) 729 | surOffsetUnitsIdx = self.GetUnitsIndex(surface_offset_unit) 730 | obsOffsetExectution = obs_offset #1.75 731 | surOffsetExectution = surface_offset #1.75 732 | generalize_out_log = 0 733 | if obsOffsetSp: 734 | obsOffsetExectution = obs_offset 735 | if surOffsetSp: 736 | surOffsetExectution = surface_offset 737 | if generalize_output == True or generalize_output == "GENERALIZE": 738 | generalize_out_log = 1 739 | 740 | taskName = "Viewshed" 741 | cost = pntCounts 742 | # Initiate start time 743 | beginTime = startTime 744 | 745 | values = [ 746 | pntCounts, # input count 747 | maxDistanceSp, 748 | maximum_distance, 749 | maxDistUnitsIdx, 750 | demSourceIdx, 751 | obsOffsetSp, 752 | obsOffsetExectution, 753 | obsOffsetUnitsIdx, 754 | surOffsetSp, 755 | surOffsetExectution, 756 | surOffsetUnitsIdx, 757 | generalize_out_log 758 | ] 759 | 760 | self.LogUsageMetering(taskName, 1, cost, beginTime, values) 761 | 762 | except Exception as err: 763 | import traceback 764 | import sys 765 | msgs = traceback.format_exception(*sys.exc_info())[1:] 766 | for msg in msgs: 767 | arcpy.AddMessage(msg.strip()) 768 | except: 769 | arcpy.AddError("Viewshed failed to execute.") 770 | 771 | -------------------------------------------------------------------------------- /ElevationPro/ElevationTools.pyt.xml: -------------------------------------------------------------------------------- 1 | 2 | 20130503192636001.0TRUE202011161537421500000005000ItemDescriptionc:\program files\arcgis\pro\Resources\Help\gpElevationToolsGeoprocessing services that use the elevation data to compute viewshed polygons for the input observer locations.<DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>The elevation geoprocessing services contains the following tasks:</SPAN></P><UL><LI><P><SPAN>Viewshed – Returns viewshed polygons for the input point features.</SPAN></P></LI></UL></DIV></DIV></DIV>ViewshedSurfaceDEMNEDSRTMArcToolbox Toolbox 3 | -------------------------------------------------------------------------------- /ElevationPro/Setting up the viewshed geoprocessing service (ArcGIS Pro).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Esri/elevation-gp-python/cd9a8d6892b3690f927450d628262a05539d0ec9/ElevationPro/Setting up the viewshed geoprocessing service (ArcGIS Pro).pdf -------------------------------------------------------------------------------- /ElevationPro/Utils.tbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Esri/elevation-gp-python/cd9a8d6892b3690f927450d628262a05539d0ec9/ElevationPro/Utils.tbx -------------------------------------------------------------------------------- /ElevationPro/outputsymbology.lyrx: -------------------------------------------------------------------------------- 1 | { 2 | "type" : "CIMLayerDocument", 3 | "version" : "2.7.0", 4 | "build" : 26666, 5 | "layers" : [ 6 | "CIMPATH=map/viewshedpoly.xml" 7 | ], 8 | "layerDefinitions" : [ 9 | { 10 | "type" : "CIMFeatureLayer", 11 | "name" : "Viewshedpoly", 12 | "uRI" : "CIMPATH=map/viewshedpoly.xml", 13 | "sourceModifiedTime" : { 14 | "type" : "TimeInstant" 15 | }, 16 | "metadataURI" : "CIMPATH=Metadata/d5e57275eb71ac994615a26f982fdec6.xml", 17 | "useSourceMetadata" : false, 18 | "layerElevation" : { 19 | "type" : "CIMLayerElevationSurface", 20 | "mapElevationID" : "{27AFD736-C41F-41D6-8C8C-9D9DC6C90E0B}" 21 | }, 22 | "expanded" : true, 23 | "layerType" : "Operational", 24 | "showLegends" : true, 25 | "transparency" : 30, 26 | "visibility" : true, 27 | "displayCacheType" : "Permanent", 28 | "maxDisplayCacheAge" : 5, 29 | "showPopups" : true, 30 | "serviceLayerID" : -1, 31 | "refreshRate" : -1, 32 | "refreshRateUnit" : "esriTimeUnitsSeconds", 33 | "blendingMode" : "Alpha", 34 | "autoGenerateFeatureTemplates" : true, 35 | "featureElevationExpression" : "0", 36 | "featureTable" : { 37 | "type" : "CIMFeatureTable", 38 | "displayField" : "DEM", 39 | "editable" : true, 40 | "timeFields" : { 41 | "type" : "CIMTimeTableDefinition" 42 | }, 43 | "timeDefinition" : { 44 | "type" : "CIMTimeDataDefinition" 45 | }, 46 | "timeDisplayDefinition" : { 47 | "type" : "CIMTimeDisplayDefinition", 48 | "timeInterval" : 0, 49 | "timeIntervalUnits" : "esriTimeUnitsHours", 50 | "timeOffsetUnits" : "esriTimeUnitsYears" 51 | }, 52 | "dataConnection" : { 53 | "type" : "CIMStandardDataConnection", 54 | "workspaceConnectionString" : "DATABASE=C:\\ViewshedUtil\\elevation-gp-python-master\\Users\\xugu4526\\Documents\\ArcGIS\\scratch", 55 | "workspaceFactory" : "Shapefile", 56 | "dataset" : "Viewshedpoly", 57 | "datasetType" : "esriDTFeatureClass" 58 | }, 59 | "studyAreaSpatialRel" : "esriSpatialRelUndefined", 60 | "searchOrder" : "esriSearchOrderSpatial" 61 | }, 62 | "htmlPopupEnabled" : true, 63 | "htmlPopupFormat" : { 64 | "type" : "CIMHtmlPopupFormat", 65 | "htmlUseCodedDomainValues" : true, 66 | "htmlPresentationStyle" : "TwoColumnTable" 67 | }, 68 | "isFlattened" : true, 69 | "selectable" : true, 70 | "selectionSymbol" : { 71 | "type" : "CIMSymbolReference", 72 | "symbol" : { 73 | "type" : "CIMPolygonSymbol", 74 | "symbolLayers" : [ 75 | { 76 | "type" : "CIMSolidStroke", 77 | "enable" : true, 78 | "capStyle" : "Round", 79 | "joinStyle" : "Round", 80 | "lineStyle3D" : "Strip", 81 | "miterLimit" : 10, 82 | "width" : 2, 83 | "color" : { 84 | "type" : "CIMRGBColor", 85 | "values" : [ 86 | 0, 87 | 255, 88 | 255, 89 | 100 90 | ] 91 | } 92 | } 93 | ] 94 | } 95 | }, 96 | "featureCacheType" : "None", 97 | "displayFiltersType" : "ByScale", 98 | "featureBlendingMode" : "Alpha", 99 | "labelClasses" : [ 100 | { 101 | "type" : "CIMLabelClass", 102 | "expression" : "[DEM]", 103 | "expressionEngine" : "VBScript", 104 | "featuresToLabel" : "AllVisibleFeatures", 105 | "maplexLabelPlacementProperties" : { 106 | "type" : "CIMMaplexLabelPlacementProperties", 107 | "featureType" : "Line", 108 | "avoidPolygonHoles" : true, 109 | "canOverrunFeature" : true, 110 | "canPlaceLabelOutsidePolygon" : true, 111 | "canRemoveOverlappingLabel" : true, 112 | "canStackLabel" : true, 113 | "connectionType" : "Unambiguous", 114 | "constrainOffset" : "NoConstraint", 115 | "contourAlignmentType" : "Page", 116 | "contourLadderType" : "Straight", 117 | "contourMaximumAngle" : 90, 118 | "enableConnection" : true, 119 | "featureWeight" : 100, 120 | "fontHeightReductionLimit" : 4, 121 | "fontHeightReductionStep" : 0.5, 122 | "fontWidthReductionLimit" : 90, 123 | "fontWidthReductionStep" : 5, 124 | "graticuleAlignmentType" : "Straight", 125 | "labelBuffer" : 15, 126 | "labelLargestPolygon" : true, 127 | "labelPriority" : -1, 128 | "labelStackingProperties" : { 129 | "type" : "CIMMaplexLabelStackingProperties", 130 | "stackAlignment" : "ChooseBest", 131 | "maximumNumberOfLines" : 3, 132 | "minimumNumberOfCharsPerLine" : 3, 133 | "maximumNumberOfCharsPerLine" : 24 134 | }, 135 | "lineFeatureType" : "General", 136 | "linePlacementMethod" : "OffsetCurvedFromLine", 137 | "maximumLabelOverrun" : 36, 138 | "maximumLabelOverrunUnit" : "Point", 139 | "minimumFeatureSizeUnit" : "Map", 140 | "multiPartOption" : "OneLabelPerPart", 141 | "offsetAlongLineProperties" : { 142 | "type" : "CIMMaplexOffsetAlongLineProperties", 143 | "placementMethod" : "BestPositionAlongLine", 144 | "labelAnchorPoint" : "CenterOfLabel", 145 | "distanceUnit" : "Percentage", 146 | "useLineDirection" : true 147 | }, 148 | "pointExternalZonePriorities" : { 149 | "type" : "CIMMaplexExternalZonePriorities", 150 | "aboveLeft" : 4, 151 | "aboveCenter" : 2, 152 | "aboveRight" : 1, 153 | "centerRight" : 3, 154 | "belowRight" : 5, 155 | "belowCenter" : 7, 156 | "belowLeft" : 8, 157 | "centerLeft" : 6 158 | }, 159 | "pointPlacementMethod" : "AroundPoint", 160 | "polygonAnchorPointType" : "GeometricCenter", 161 | "polygonBoundaryWeight" : 200, 162 | "polygonExternalZones" : { 163 | "type" : "CIMMaplexExternalZonePriorities", 164 | "aboveLeft" : 4, 165 | "aboveCenter" : 2, 166 | "aboveRight" : 1, 167 | "centerRight" : 3, 168 | "belowRight" : 5, 169 | "belowCenter" : 7, 170 | "belowLeft" : 8, 171 | "centerLeft" : 6 172 | }, 173 | "polygonFeatureType" : "General", 174 | "polygonInternalZones" : { 175 | "type" : "CIMMaplexInternalZonePriorities", 176 | "center" : 1 177 | }, 178 | "polygonPlacementMethod" : "CurvedInPolygon", 179 | "primaryOffset" : 1, 180 | "primaryOffsetUnit" : "Point", 181 | "removeExtraWhiteSpace" : true, 182 | "repetitionIntervalUnit" : "Map", 183 | "rotationProperties" : { 184 | "type" : "CIMMaplexRotationProperties", 185 | "rotationType" : "Arithmetic", 186 | "alignmentType" : "Straight" 187 | }, 188 | "secondaryOffset" : 100, 189 | "strategyPriorities" : { 190 | "type" : "CIMMaplexStrategyPriorities", 191 | "stacking" : 1, 192 | "overrun" : 2, 193 | "fontCompression" : 3, 194 | "fontReduction" : 4, 195 | "abbreviation" : 5 196 | }, 197 | "thinningDistanceUnit" : "Map", 198 | "truncationMarkerCharacter" : ".", 199 | "truncationMinimumLength" : 1, 200 | "truncationPreferredCharacters" : "aeiou", 201 | "polygonAnchorPointPerimeterInsetUnit" : "Point" 202 | }, 203 | "name" : "Default", 204 | "priority" : 1, 205 | "standardLabelPlacementProperties" : { 206 | "type" : "CIMStandardLabelPlacementProperties", 207 | "featureType" : "Line", 208 | "featureWeight" : "None", 209 | "labelWeight" : "High", 210 | "numLabelsOption" : "OneLabelPerPart", 211 | "lineLabelPosition" : { 212 | "type" : "CIMStandardLineLabelPosition", 213 | "above" : true, 214 | "inLine" : true, 215 | "parallel" : true 216 | }, 217 | "lineLabelPriorities" : { 218 | "type" : "CIMStandardLineLabelPriorities", 219 | "aboveStart" : 3, 220 | "aboveAlong" : 3, 221 | "aboveEnd" : 3, 222 | "centerStart" : 3, 223 | "centerAlong" : 3, 224 | "centerEnd" : 3, 225 | "belowStart" : 3, 226 | "belowAlong" : 3, 227 | "belowEnd" : 3 228 | }, 229 | "pointPlacementMethod" : "AroundPoint", 230 | "pointPlacementPriorities" : { 231 | "type" : "CIMStandardPointPlacementPriorities", 232 | "aboveLeft" : 2, 233 | "aboveCenter" : 2, 234 | "aboveRight" : 1, 235 | "centerLeft" : 3, 236 | "centerRight" : 2, 237 | "belowLeft" : 3, 238 | "belowCenter" : 3, 239 | "belowRight" : 2 240 | }, 241 | "rotationType" : "Arithmetic", 242 | "polygonPlacementMethod" : "AlwaysHorizontal" 243 | }, 244 | "textSymbol" : { 245 | "type" : "CIMSymbolReference", 246 | "symbol" : { 247 | "type" : "CIMTextSymbol", 248 | "blockProgression" : "TTB", 249 | "compatibilityMode" : true, 250 | "depth3D" : 1, 251 | "drawSoftHyphen" : true, 252 | "extrapolateBaselines" : true, 253 | "flipAngle" : 90, 254 | "fontEffects" : "Normal", 255 | "fontEncoding" : "Unicode", 256 | "fontFamilyName" : "Arial", 257 | "fontStyleName" : "Regular", 258 | "fontType" : "Unspecified", 259 | "haloSize" : 1, 260 | "height" : 8, 261 | "hinting" : "Default", 262 | "horizontalAlignment" : "Center", 263 | "kerning" : true, 264 | "letterWidth" : 100, 265 | "ligatures" : true, 266 | "lineGapType" : "ExtraLeading", 267 | "shadowColor" : { 268 | "type" : "CIMRGBColor", 269 | "values" : [ 270 | 0, 271 | 0, 272 | 0, 273 | 100 274 | ] 275 | }, 276 | "symbol" : { 277 | "type" : "CIMPolygonSymbol", 278 | "symbolLayers" : [ 279 | { 280 | "type" : "CIMSolidFill", 281 | "enable" : true, 282 | "color" : { 283 | "type" : "CIMRGBColor", 284 | "values" : [ 285 | 0, 286 | 0, 287 | 0, 288 | 100 289 | ] 290 | } 291 | } 292 | ] 293 | }, 294 | "textCase" : "Normal", 295 | "textDirection" : "LTR", 296 | "verticalAlignment" : "Bottom", 297 | "verticalGlyphOrientation" : "Right", 298 | "wordSpacing" : 100, 299 | "billboardMode3D" : "FaceNearPlane" 300 | } 301 | }, 302 | "useCodedValue" : true, 303 | "visibility" : true, 304 | "iD" : -1 305 | } 306 | ], 307 | "renderer" : { 308 | "type" : "CIMSimpleRenderer", 309 | "patch" : "Default", 310 | "symbol" : { 311 | "type" : "CIMSymbolReference", 312 | "symbol" : { 313 | "type" : "CIMPolygonSymbol", 314 | "symbolLayers" : [ 315 | { 316 | "type" : "CIMSolidFill", 317 | "enable" : true, 318 | "color" : { 319 | "type" : "CIMRGBColor", 320 | "values" : [ 321 | 230, 322 | 152, 323 | 0, 324 | 100 325 | ] 326 | } 327 | } 328 | ] 329 | } 330 | } 331 | }, 332 | "scaleSymbols" : true, 333 | "snappable" : true 334 | } 335 | ], 336 | "binaryReferences" : [ 337 | { 338 | "type" : "CIMBinaryReference", 339 | "uRI" : "CIMPATH=Metadata/d5e57275eb71ac994615a26f982fdec6.xml", 340 | "data" : "\r\n20201113142937001.0TRUEViewshedpoly\r\n" 341 | } 342 | ], 343 | "elevationSurfaces" : [ 344 | { 345 | "type" : "CIMMapElevationSurface", 346 | "elevationMode" : "BaseGlobeSurface", 347 | "name" : "Ground", 348 | "verticalExaggeration" : 1, 349 | "mapElevationID" : "{27AFD736-C41F-41D6-8C8C-9D9DC6C90E0B}", 350 | "color" : { 351 | "type" : "CIMRGBColor", 352 | "values" : [ 353 | 255, 354 | 255, 355 | 255, 356 | 100 357 | ] 358 | }, 359 | "surfaceTINShadingMode" : "Smooth", 360 | "visibility" : true, 361 | "expanded" : true 362 | } 363 | ], 364 | "rGBColorProfile" : "sRGB IEC61966-2-1 noBPC", 365 | "cMYKColorProfile" : "U.S. Web Coated (SWOP) v2" 366 | } -------------------------------------------------------------------------------- /Profile/How to set up the profile service (ArcGIS Pro).pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Esri/elevation-gp-python/cd9a8d6892b3690f927450d628262a05539d0ec9/Profile/How to set up the profile service (ArcGIS Pro).pdf -------------------------------------------------------------------------------- /Profile/Profile Tool Pro.Profile.pyt.xml: -------------------------------------------------------------------------------- 1 | 2 | 20231026193810001.0TRUE20231028143551001500000005000ItemDescriptionc:\users\xugu4526\appdata\local\programs\arcgis\pro\Resources\Help\gp<DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>Input Line Features</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>Input Line Features</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>Profile ID Field</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><P><SPAN>Profile ID Field</SPAN></P></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>DEM Resolution</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>DEM Resolution</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>Maximum Sample Distance</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>Maximum Sample Distance</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>Maximum Sample Distance Units</SPAN></P></DIV></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><DIV><P><SPAN>Maximum Sample Distance Units</SPAN></P></DIV></DIV><DIV><P><SPAN /></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>Profile script tool</SPAN></P></DIV></DIV><DIV STYLE="text-align:Left;"><DIV><P><SPAN>This Profile script tool can be published to ArcGIS Enterprise as a web tool.</SPAN></P></DIV></DIV>ProfileElevationProfileArcToolbox Tool20231028 3 | -------------------------------------------------------------------------------- /Profile/Profile Tool Pro.pyt: -------------------------------------------------------------------------------- 1 | """ Tool name: Profile 2 | Source name: Profile Tool.pyt 3 | Description: Return an elevation profile for an input polyline. 4 | Author: Environmental Systems Research Institute Inc. 5 | Last updated: Oct. 26, 2023 6 | """ 7 | import os 8 | import time 9 | import arcpy 10 | 11 | class Toolbox(object): 12 | def __init__(self): 13 | """Define the toolbox (the name of the toolbox is the name of the 14 | .pyt file).""" 15 | self.label = "Profile Tool" 16 | self.alias = "" 17 | 18 | # List of tool classes associated with this toolbox 19 | self.tools = [Profile] 20 | 21 | class Profile(object): 22 | def __init__(self): 23 | """Define the tool (tool name is the name of the class).""" 24 | self.label = "Profile" 25 | self.description = "Return an elevation profile for an input polyline." 26 | self.canRunInBackground = False 27 | # custom properties 28 | self.debug = True 29 | self.outputToTable = False # set to True to direct the output to a table. 30 | self.idFieldName = "ID" 31 | self.glen_field1 = "proflen0" 32 | self.glen_field2 = "proflen1" 33 | self.metadataFieldName = "DEMResolution" 34 | self.geodesicLenFieldName = "ProfileLength" 35 | self.listLinearUnits = ["Meters", "Kilometers", "Feet", "Yards", "Miles"] 36 | #--------------------------------------------------- 37 | # Maximum number of vertices 38 | #--------------------------------------------------- 39 | self.maxNumVertices = 2000 40 | #--------------------------------------------------- 41 | # DEM boundary layer 42 | #--------------------------------------------------- 43 | boundaryGdbPath = r'C:\Profile\ProfileData\dembnd.gdb' 44 | boundaryLayer1 = os.path.join(boundaryGdbPath, "demboundary") 45 | if False: 46 | arcpy.Describe(boundaryLayer1) 47 | self.demBoundary = boundaryLayer1 48 | #---------------------------------------------------- 49 | # Profile schema feature class 50 | #---------------------------------------------------- 51 | profileSchm1 = os.path.join(boundaryGdbPath, "profileschema") 52 | self.profileSchema = profileSchm1 53 | #---------------------------------------------------- 54 | # DEM resolution dictionary 55 | #--------------------------------------------------- 56 | self.dictDEMResolutions = {"90m":"90", "30m":"30", "10m":"10"} 57 | self.defaultDEMResolution = '90' 58 | #--------------------------------------------------- 59 | # DEM data layers 60 | #--------------------------------------------------- 61 | mosaicGdbPath = r"C:\Profile\ProfileData\demdata.gdb" 62 | demLayer1 = os.path.join(mosaicGdbPath, "dem90m") 63 | demLayer2 = os.path.join(mosaicGdbPath, "dem30m") 64 | demLayer3 = os.path.join(mosaicGdbPath, "dem10m") 65 | #--------------------------------------------------- 66 | # Wrap each variable in an arcpy.Describe statement 67 | #--------------------------------------------------- 68 | if False: 69 | arcpy.Describe(demLayer1) 70 | arcpy.Describe(demLayer2) 71 | arcpy.Describe(demLayer3) 72 | #--------------------------------------------------- 73 | # Update the DEM layers dictionary 74 | #--------------------------------------------------- 75 | self.dictDEMs = {"90":demLayer1, 76 | "30":demLayer2, 77 | "10":demLayer3} 78 | #---------------------------------------------------- 79 | # DEM coordinate system 80 | demSR = arcpy.Describe(list(self.dictDEMs.values())[0]).spatialReference 81 | self.demCoordinateSystem = demSR 82 | # DEM linear unit 83 | lun = demSR.linearUnitName 84 | if lun == "" or lun == None: 85 | lun = demSR.angularUnitName 86 | if 'degree' in lun.lower(): 87 | lun = 'decimaldegrees' 88 | if 'foot' in lun.lower() or 'feet' in lun.lower(): 89 | lun = 'feet' 90 | self.demLinearUnit = lun 91 | # for adjusting length, change the zf here. eg, if the DEM linear unit is feet, then zf = 0.3048. 92 | # for meter, zf = 1.0; for decimal degrees, use zf = 1.0 93 | self.zFactor = self.getUnitConversionFactor(self.demLinearUnit) 94 | 95 | self.errorMessages = ["No input polyline features specified. The input needs to have at list one line feature.", 96 | "Input resolution is not supported. Select a different DEM source.", 97 | "The input profile line you requested falls outside of the data currently available in this service.", 98 | "Input parameter {0} is not valid.", 99 | "The input polyline contains too many vertices. Reduce the number of vertices.", 100 | "The specified sample distance results in more vertices than allowed. Increase sampling distance.", 101 | "Input feature contains too many vertices or the sample distance is too small. Specify a line with less than 1024 vertices, or increase the sampling distance.", 102 | "Input sample distance cannot be 0 or negative.", 103 | "Input feature id field does not exist. Change to another field or leave it as default.", 104 | "The number of input profile lines exceeds limit. Reduce the number of input profile lines to not more than 10."] 105 | 106 | def getLayerName(self, res): 107 | if not res in self.dictDEMs.keys(): 108 | arcpy.AddError(self.errorMessages[1]) 109 | raise 110 | return 111 | return self.dictDEMs[res] 112 | 113 | def getUnitConversionFactor(self, u1): # get conversion factor 114 | uFactor = 1 115 | inUnit = u1.strip().lower() 116 | if inUnit in ["meters", "meter"]: 117 | uFactor = 1 118 | if inUnit in ["centimeters", "centimeter"]: 119 | uFactor = 0.01 120 | if inUnit in ["decimaldegrees", "decimaldegree"]: 121 | uFactor = 1 122 | if inUnit in ["decimeters", "decimeter"]: 123 | uFactor = 0.1 124 | if inUnit in ["feet", "foot"]: 125 | uFactor = 0.3048 126 | if inUnit in ["foot_us", "feet_us"]: 127 | uFactor = 0.3048006096012192 128 | if inUnit in ["inches","inch"]: 129 | uFactor = 0.0254 130 | if inUnit in ["kilometers", "kilometer"]: 131 | uFactor = 1000 132 | if inUnit in ["miles","mile"]: 133 | uFactor = 1609.344 134 | if inUnit in ["millimeters", "millimeter"]: 135 | uFactor = 0.001 136 | if inUnit in ["nauticalmiles", "nauticalmile"]: 137 | uFactor = 1852 138 | if inUnit in ["points", "point"]: 139 | uFactor = 0.000352777778 140 | if inUnit in ["unknown", ""]: 141 | uFactor = 1 142 | if inUnit in ["yards", "yard"]: 143 | uFactor = 0.91440 144 | return uFactor 145 | 146 | def lineFootprintTest(self, in_line_features): 147 | # Footprint polygon 148 | footPrt = self.demBoundary 149 | resList = [] 150 | footPrtLayer = 'aFootPrtLyr' 151 | arcpy.MakeFeatureLayer_management(footPrt,footPrtLayer) 152 | arcpy.SelectLayerByLocation_management(footPrtLayer, "COMPLETELY_CONTAINS", 153 | in_line_features) 154 | with arcpy.da.SearchCursor(footPrtLayer, "res") as cursor: 155 | for row in cursor: 156 | resList.append(row[0]) 157 | 158 | return resList 159 | 160 | def CountVerticesAndLength(self, in_polylines1): 161 | countL = 0 162 | countV = 0 163 | totalLen = 0 164 | individualLen = [] 165 | 166 | list_oid = [] 167 | list_vert = [] 168 | list_geodesiclen = [] 169 | 170 | with arcpy.da.SearchCursor(in_polylines1, ("Shape@", "Shape@Length", "OID@", self.glen_field2)) as cur: 171 | for row in cur: 172 | countL += 1 173 | countV += row[0].getPart(0).count 174 | totalLen += row[1] 175 | individualLen.append(row[1]) 176 | list_oid.append(row[2]) 177 | list_vert.append(row[0].getPart(0).count) 178 | list_geodesiclen.append(row[3]) 179 | 180 | return (countL, countV, totalLen, individualLen, list_oid, list_vert, list_geodesiclen) 181 | 182 | def CountVerticesNoProjection(self, in_polylines1): 183 | countV = 0 184 | with arcpy.da.SearchCursor(in_polylines1, ("Shape@")) as cur: 185 | for row in cur: 186 | countV += row[0].getPart(0).count 187 | 188 | return countV 189 | 190 | def getResolutionByLength(self, in_len): 191 | dem_res = [] 192 | if in_len < 5000: 193 | dem_res = [10, 30, 90] 194 | if in_len >= 5000 and in_len < 15000: 195 | dem_res = [30, 90] 196 | if in_len >= 15000: 197 | dem_res = [90] 198 | return dem_res 199 | 200 | def getResolutionByLengthFootprint(self, in_polylines, total_len): 201 | len_candidates = self.getResolutionByLength(total_len) 202 | foot_candidates = self.lineFootprintTest(in_polylines) 203 | foot_candidates_int = [int(x) for x in foot_candidates] 204 | res_list = [i for i in len_candidates if i in foot_candidates_int] 205 | res_list.sort() 206 | if len(res_list) == 0: 207 | arcpy.AddError(self.errorMessages[2]) 208 | raise 209 | return res_list 210 | 211 | def getResolutionByFootprint(self, in_polylines): 212 | foot_candidates = self.lineFootprintTest(in_polylines) 213 | foot_candidates_int = [int(x) for x in foot_candidates] 214 | foot_candidates_int.sort() 215 | if len(foot_candidates_int) == 0: 216 | arcpy.AddError(self.errorMessages[2]) 217 | raise 218 | return foot_candidates_int 219 | 220 | def getDefaultNumberVertices(self, in_number_vertices): 221 | out_num = None 222 | if in_number_vertices <= 50: 223 | out_num = 50 224 | if in_number_vertices > 50 and in_number_vertices <= 200: 225 | out_num = 200 226 | if in_number_vertices > 200: 227 | out_num = in_number_vertices 228 | return out_num 229 | 230 | def densifyLine(self, in_line_features, distanceLU): 231 | if distanceLU != "": # only do it when not empty 232 | arcpy.Densify_edit(in_line_features, "DISTANCE", distanceLU) 233 | 234 | def weedLine(self, in_line_features, in_toler): 235 | if in_toler != 0: # only do it when not 0 236 | arcpy.Generalize_edit(in_line_features, in_toler) 237 | 238 | def printCoordinateSystem(self, in_dataset): 239 | des = arcpy.Describe(in_dataset) 240 | arcpy.AddMessage(des.SpatialReference.name) 241 | 242 | def validateNumerical(self, inVal, paramStr): 243 | if inVal == None: # None is OK 244 | return 245 | elif inVal <= 0: 246 | arcpy.AddError(self.errorMessages[7].format(paramStr)) 247 | raise 248 | 249 | def validateDistanceUnits(self, inStr, paramStr): 250 | tempUnitsList = [s.lower() for s in self.listLinearUnits] 251 | tempUnitsList.extend(["#", ""]) 252 | if inStr == None: # None is OK 253 | return 254 | elif not (inStr.lower() in tempUnitsList): 255 | arcpy.AddError(self.errorMessages[3].format(paramStr)) 256 | raise 257 | 258 | def validateInputDEMSource(self, inDEM): 259 | tempDEMList = [s.upper() for s in list(self.dictDEMResolutions.keys())] 260 | tempDEMList.extend(["", "FINEST", "#"]) 261 | if inDEM == None: # None is OK 262 | return 263 | elif not (inDEM.strip().upper() in tempDEMList): 264 | arcpy.AddError(self.errorMessages[1].format(inDEM)) 265 | raise 266 | 267 | def validateFeatureIDField(self, inName, inFeature): 268 | fldList = arcpy.ListFields(inFeature) 269 | fldListLower = [f.name.lower() for f in fldList] 270 | if inName == None: # None is OK 271 | return 272 | elif not (inName.lower() in fldListLower): 273 | arcpy.AddError(self.errorMessages[8]) 274 | raise 275 | 276 | def formatInputDEMSource(self, inSource): 277 | tempDEMList = list(self.dictDEMResolutions.keys()) 278 | tempDEMList.extend(["", "FINEST"]) 279 | retVal = inSource 280 | for d in tempDEMList: 281 | if inSource.upper() == d.upper(): 282 | retVal = d 283 | break 284 | return retVal 285 | 286 | def createProfile(self, in_line_features, inputIsInOcean, line_id_field, idFieldIsTemp, inputSR, 287 | dem_resolution, line_count, list_geodesiclen, out_profile): 288 | try: 289 | line_features_inputCS = os.path.join(r"in_memory", r"linetmpafterprj03") 290 | route_temp = os.path.join(r"in_memory", "outroutetmp") 291 | interp_line_temp = r"in_memory\interpouttmp" 292 | out_vertices_temp = r"in_memory\verticestmp" 293 | arcpy.env.workspace = "in_memory" 294 | 295 | # get Z values from DEM 296 | arcpy.InterpolateShape_3d(in_surface=self.getLayerName(dem_resolution), 297 | in_feature_class=in_line_features, 298 | out_feature_class=interp_line_temp, 299 | vertices_only="VERTICES_ONLY") 300 | 301 | # Calculate M values using Create Routes tool 302 | # By default, M is in meters. To change the M unit, 303 | # change the unit in which glen_field2 is calculated (in the execute method) 304 | arcpy.CreateRoutes_lr(in_line_features=interp_line_temp, route_id_field=line_id_field, 305 | out_feature_class=route_temp, measure_source="TWO_FIELDS", 306 | from_measure_field=self.glen_field1, to_measure_field=self.glen_field2) 307 | 308 | if self.outputToTable: # out to table 309 | # project the line 310 | arcpy.env.outputCoordinateSystem = inputSR # convert to input projection 311 | arcpy.CopyFeatures_management(route_temp, line_features_inputCS) # project 312 | arcpy.env.outputCoordinateSystem = "" 313 | # extract X, Y, Z, M 314 | arcpy.CreateTable_management("in_memory", os.path.basename(out_profile), os.path.join(os.path.dirname(__file__), "profile_schema.dbf")) 315 | with arcpy.da.InsertCursor(out_profile, ("ID", "POINT_X", "POINT_Y", "POINT_M", "POINT_Z")) as icur: 316 | with arcpy.da.SearchCursor(line_features_inputCS, ("Shape@", line_id_field)) as scur: 317 | for row in scur: 318 | geo = row[0] 319 | id_val = row[1] 320 | for l1 in geo.getPart(): 321 | for pnt in l1: 322 | x = pnt.X 323 | y = pnt.Y 324 | m = pnt.M 325 | z = pnt.Z 326 | icur.insertRow((id_val, x, y, m, z)) 327 | else: # out to line 328 | # project the line 329 | arcpy.env.outputCoordinateSystem = inputSR # convert to input projection 330 | arcpy.CopyFeatures_management(route_temp, out_profile) # project 331 | arcpy.env.outputCoordinateSystem = "" 332 | # Add metadata info 333 | if inputIsInOcean: 334 | dem_source = ['1000m'] 335 | else: 336 | dem_source = [k for k, v in self.dictDEMResolutions.items() if v == str(dem_resolution)] 337 | arcpy.AddField_management(out_profile, self.metadataFieldName, "TEXT", field_length=50, field_alias="DEM Resolution") 338 | arcpy.CalculateField_management(out_profile, self.metadataFieldName, "'" + dem_source[0] + "'", "PYTHON") 339 | # Add geodesic length for profile 340 | arcpy.AddField_management(out_profile, self.geodesicLenFieldName, "DOUBLE", field_alias="Length Meters") 341 | i = 0 342 | with arcpy.da.UpdateCursor(out_profile, self.geodesicLenFieldName) as ucur: 343 | for row in ucur: 344 | row[0] = list_geodesiclen[i] 345 | i += 1 346 | ucur.updateRow(row) 347 | # remove tempid field 348 | if idFieldIsTemp: 349 | arcpy.DeleteField_management(out_profile, line_id_field) 350 | 351 | except: 352 | msgs = arcpy.GetMessages(2) 353 | arcpy.AddError(msgs) 354 | raise 355 | 356 | def getParameterInfo(self): 357 | """Define parameter definitions""" 358 | param0 = arcpy.Parameter(name="InputLineFeatures", 359 | displayName="Input Line Features", 360 | direction="Input", 361 | parameterType="Required", 362 | datatype="GPFeatureRecordSetLayer") 363 | # Feautre set schema 364 | param0.value = self.profileSchema 365 | 366 | param1 = arcpy.Parameter(name="ProfileIDField", 367 | displayName="Profile ID Field", 368 | direction="Input", 369 | parameterType="Optional", 370 | datatype="Field") 371 | param1.filter.list = ['OID', 'Short', 'Long'] 372 | 373 | param2 = arcpy.Parameter(name="DEMResolution", 374 | displayName="DEM Resolution", 375 | direction="Input", 376 | parameterType="Optional", 377 | datatype="GPString") 378 | param2.filter.type = "ValueList" 379 | list_dem = ["FINEST"] 380 | dem_keys = list(self.dictDEMResolutions.keys()) 381 | dem_keys.sort() 382 | list_dem.extend(dem_keys) 383 | param2.filter.list = list_dem 384 | 385 | param3 = arcpy.Parameter(name="MaximumSampleDistance", 386 | displayName="Maximum Sample Distance", 387 | direction="Input", 388 | parameterType="Optional", 389 | datatype="GPDouble") 390 | 391 | param4 = arcpy.Parameter(name="MaximumSampleDistanceUnits", 392 | displayName="Maximum Sample Distance Units", 393 | direction="Input", 394 | parameterType="Optional", 395 | datatype="GPString") 396 | 397 | param4.filter.type = "ValueList" 398 | param4.filter.list = self.listLinearUnits 399 | param4.value = "Meters" 400 | 401 | param5 = arcpy.Parameter(name="OutputProfile", 402 | displayName="Output Profile", 403 | direction="Output", 404 | parameterType="Derived", 405 | datatype="DEFeatureClass") 406 | 407 | params = [param0, param1, param2, param3, param4, param5] 408 | return params 409 | 410 | def isLicensed(self): 411 | """Set whether tool is licensed to execute.""" 412 | return True 413 | 414 | def updateParameters(self, parameters): 415 | """Modify the values and properties of parameters before internal 416 | validation is performed. This method is called whenever a parameter 417 | has been changed.""" 418 | return 419 | 420 | def updateMessages(self, parameters): 421 | """Modify the messages created by internal validation for each tool 422 | parameter. This method is called after internal validation.""" 423 | return 424 | 425 | def execute(self, parameters, messages): 426 | """The source code of the tool.""" 427 | startTime = time.time() 428 | self.debug = False 429 | in_polylines = parameters[0].value 430 | profile_id_field = parameters[1].valueAsText 431 | dem_resolution_p = parameters[2].valueAsText 432 | sample_distance_p = parameters[3].value 433 | sample_distance_units = parameters[4].valueAsText 434 | out_profile = os.path.join("in_memory", "profile1") 435 | 436 | arcpy.env.overwriteOutput = True 437 | maxInputLines = 100 # sync is 100, async is 1000 438 | if ("elevation_gpserver" in arcpy.env.scratchWorkspace): 439 | maxInputLines = 1000 440 | 441 | # Get input SR 442 | d0 = arcpy.Describe(in_polylines) 443 | inputSR = d0.spatialReference 444 | oidfld1 = d0.OIDFieldName 445 | 446 | # project first 447 | polylines_after_prj = os.path.join("in_memory", "inputlinetmp02") 448 | # project to raster coordinate system 449 | arcpy.env.outputCoordinateSystem = self.demCoordinateSystem 450 | 451 | arcpy.CopyFeatures_management(in_polylines, polylines_after_prj) # project 452 | arcpy.env.outputCoordinateSystem = "" 453 | 454 | # Add and calcualte geodesic length fields - from field and to field for 455 | # Create Routes tool to calculate the M values 456 | arcpy.AddField_management(polylines_after_prj, self.glen_field1, "DOUBLE") 457 | arcpy.CalculateField_management(polylines_after_prj, self.glen_field1, 458 | "0", "PYTHON_9.3") 459 | 460 | # The unit in which glen_field2 is calculated determines the M unit. 461 | # To change it other units, replace meters below with desired units 462 | arcpy.AddField_management(polylines_after_prj, self.glen_field2, "DOUBLE") 463 | arcpy.CalculateField_management(polylines_after_prj, self.glen_field2, 464 | "!shape.geodesiclength@meters!", "PYTHON_9.3") 465 | 466 | # validate profile id field 467 | time_a = time.time() 468 | self.validateFeatureIDField(profile_id_field, in_polylines) 469 | time_b = time.time() 470 | if self.debug: 471 | arcpy.AddMessage("ValidateFeatureIDField execution time: " + str(time_b - time_a)) 472 | 473 | # make temp id field 474 | idFieldIsTemp = False 475 | temp_id_field = "tmpprflid_" 476 | if profile_id_field == None: 477 | idFieldIsTemp = True # needed for field removal later 478 | fieldSp = 0 479 | fieldIsObjID = 1 480 | profile_id_field = temp_id_field 481 | elif profile_id_field.lower() in ["oid", "fid", "objectid"]: 482 | idFieldIsTemp = True # needed for field removal later 483 | fieldSp = 1 484 | fieldIsObjID = 0 485 | profile_id_field = temp_id_field 486 | 487 | if profile_id_field == temp_id_field: # default 488 | arcpy.AddField_management(polylines_after_prj, profile_id_field, "LONG") 489 | arcpy.CalculateField_management(polylines_after_prj, profile_id_field, "!" + oidfld1 + "!", "PYTHON_9.3") 490 | 491 | # var for metering 492 | fieldSp = 1 493 | fieldIsObjID = 1 494 | samplingDistSp = 0 495 | 496 | # now find the line length and number of vertices 497 | time_a = time.time() 498 | lineFact = self.CountVerticesAndLength(polylines_after_prj) 499 | time_b = time.time() 500 | if self.debug: 501 | arcpy.AddMessage("CountVerticesAndLength execution time: " + str(time_b - time_a)) 502 | 503 | line_counts = lineFact[0] 504 | total_num_vert = lineFact[1] 505 | total_len = lineFact[2] 506 | indiv_len = lineFact[3] 507 | list_oid = lineFact[4] 508 | list_vert = lineFact[5] 509 | list_glen = lineFact[6] 510 | 511 | if line_counts < 1: 512 | arcpy.AddError(self.errorMessages[0]) 513 | raise 514 | elif line_counts > maxInputLines: 515 | arcpy.AddError(self.errorMessages[9]) 516 | raise 517 | 518 | self.validateNumerical(sample_distance_p, "Maximum Sample Distance") 519 | self.validateDistanceUnits(sample_distance_units, "Maximum Sample Distance Units") 520 | self.validateInputDEMSource(dem_resolution_p) 521 | 522 | # trim dem_resolution_p 523 | if dem_resolution_p is not None and str(dem_resolution_p).upper() != "FINEST": 524 | if dem_resolution_p.strip() == "": 525 | dem_resolution_p = None 526 | if dem_resolution_p is not None: 527 | dem_resolution_p = self.dictDEMResolutions[self.formatInputDEMSource(dem_resolution_p)] 528 | 529 | # determine whether input line is in ocean 530 | inputIsInOcean = False 531 | # determine resolution 532 | if str(dem_resolution_p).upper() != "FINEST": 533 | if dem_resolution_p is None: # case 1 blank (default) 534 | dem_resolution = self.defaultDEMResolution 535 | res_list = self.getResolutionByFootprint(polylines_after_prj) 536 | if not int(dem_resolution) in res_list: 537 | arcpy.AddError(self.errorMessages[2]) 538 | raise 539 | return 540 | else: # case 2 specified 541 | dem_resolution = dem_resolution_p 542 | res_list = self.getResolutionByFootprint(polylines_after_prj) 543 | if not int(dem_resolution) in res_list: 544 | arcpy.AddError(self.errorMessages[2]) 545 | raise 546 | return 547 | else: # case 3 - FINEST: 548 | res_list = self.getResolutionByFootprint(polylines_after_prj) 549 | dem_resolution = str(int(res_list[0])) 550 | 551 | if sample_distance_units == None: 552 | sample_distance_units = "meters" 553 | 554 | outfeaturelayer1 = "tempfeaturelayer" 555 | arcpy.MakeFeatureLayer_management(polylines_after_prj, outfeaturelayer1) 556 | 557 | for oid_val in list_oid: 558 | query_exp = oidfld1 + "=" + str(oid_val) 559 | arcpy.SelectLayerByAttribute_management(outfeaturelayer1, "NEW_SELECTION", query_exp) 560 | 561 | in_len = indiv_len[list_oid.index(oid_val)] # individual line length 562 | in_glen = list_glen[list_oid.index(oid_val)] # individual glength 563 | 564 | ratio1 = in_len / (in_glen / self.zFactor) # ratio to convert to Mercator 565 | in_num_vert = list_vert[list_oid.index(oid_val)] # individual line vertex number 566 | 567 | if sample_distance_p == None: # default 568 | samplingDistSp = 0 # metering 569 | out_num_vert = in_num_vert 570 | needDensify = False 571 | needWeed = False 572 | if in_num_vert < 50: 573 | out_num_vert = 50 574 | needDensify = True 575 | elif in_num_vert >= 50 and in_num_vert < 200: 576 | out_num_vert = 200 577 | needDensify = True 578 | elif in_num_vert >= 200 and in_num_vert <= self.maxNumVertices: 579 | out_num_vert = in_num_vert 580 | needDensify = False 581 | elif in_num_vert > self.maxNumVertices: 582 | out_num_vert = self.maxNumVertices 583 | needDensify = False 584 | needWeed = True 585 | 586 | sample_distance_m = in_len / (out_num_vert - 1) # default sample distance 587 | 588 | if needDensify: 589 | # change the unit here to DEM linear unit, eg, feet, meters, decimaldegrees 590 | self.densifyLine(outfeaturelayer1, str(sample_distance_m) + " " + self.demLinearUnit) 591 | if needWeed: 592 | self.weedLine(outfeaturelayer1, str(int(dem_resolution) / 4.0) + " " + self.demLinearUnit) 593 | else: # specified 594 | samplingDistSp = 1 # metering 595 | newSamplingDist = ratio1 * sample_distance_p # convert to GCS distance 596 | sample_distance_m = newSamplingDist * self.getUnitConversionFactor(sample_distance_units) / self.zFactor # convert to Feet 597 | nVert = int((in_len / sample_distance_m) + 1) 598 | if nVert > self.maxNumVertices: 599 | arcpy.AddError(self.errorMessages[5]) 600 | raise 601 | return 602 | else: 603 | self.densifyLine(outfeaturelayer1, str(sample_distance_m) + " " + self.demLinearUnit) 604 | 605 | # final count of no. vertices 606 | nVert1 = self.CountVerticesNoProjection(outfeaturelayer1) 607 | if nVert1 > self.maxNumVertices * 2: 608 | arcpy.AddError(self.errorMessages[6]) 609 | raise 610 | return 611 | 612 | # Execute the tool, line is already densified 613 | arcpy.AddMessage("DEM Resolution: " + dem_resolution + ", Sampling Distance: " 614 | + str(sample_distance_m)) 615 | self.createProfile(polylines_after_prj, inputIsInOcean, profile_id_field, idFieldIsTemp, inputSR, 616 | dem_resolution, line_counts, list_glen, out_profile) 617 | 618 | arcpy.SetParameterAsText(5, out_profile) 619 | -------------------------------------------------------------------------------- /Profile/Profile Tool Pro.pyt.xml: -------------------------------------------------------------------------------- 1 | 2 | 20231026193756001.0TRUE20231028072025c:\users\xugu4526\appdata\local\programs\arcgis\pro\Resources\Help\gpProfile Tool ProArcToolbox Toolbox 3 | -------------------------------------------------------------------------------- /Profile/Profile Utils Pro.tbx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Esri/elevation-gp-python/cd9a8d6892b3690f927450d628262a05539d0ec9/Profile/Profile Utils Pro.tbx -------------------------------------------------------------------------------- /Profile/ProfileData.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Esri/elevation-gp-python/cd9a8d6892b3690f927450d628262a05539d0ec9/Profile/ProfileData.zip -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # elevation-gp-python 2 | ArcGIS elevation analysis tool that allows you to set up an in-house elevation geoprocessing service. 3 | ## Features 4 | 5 | ElevationPro - a Viewshed script tool package that can be published from Pro. 6 | * ElevationTools.pyt - Contains the viewshed tool that can be published from ArcGIS Pro to ArcGIS Enterprise as a geoprocessing service. 7 | * Setting up the viewshed geoprocessing service (ArcGIS Pro).pdf - Detailed instructions on how to configure and set up the service. 8 | 9 | Elevation - a Viewshed script tool package that can be published from ArcMap. 10 | * ElevationTools.pyt - Contains the viewshed tool that can be published from ArcMap to ArcGIS for server as a geoprocessing service. 11 | * Setting up the viewshed geoprocessing service.pdf - Detailed instructions on how to configure and set up the service. 12 | 13 | Profile - a Profile script tool package that can be published from Pro. 14 | * Profile Tool Pro.pyt - Contains the profile tool that can be published from ArcGIS Pro to ArcGIS Enterprise as a geoprocessing service. 15 | * How to set up the profile service (ArcGIS Pro).pdf - Detailed instructions on how to configure and set up the service. 16 | 17 | ## Instructions 18 | 1. Download the files. 19 | 2. Unzip the data.zip file to the same folder (under Elevation, or ElevationPro). 20 | 3. Follow the instructions in the 'Setting up the viewshed geoprocessing service.pdf' or 'Setting up the viewshed geoprocessing service (ArcGIS Pro).pdf' documents. 21 | 22 | ## Requirements 23 | * ArcGIS Desktop or ArcGIS Pro, with Standard or Advanced license. A license for the Spatial Analyst extension is also required. 24 | * ArcGIS Enterprise with Raster Analysis privilege. 25 | 26 | ## Resources 27 | * [Publishing a geoprocessing service](http://server.arcgis.com/en/server/latest/publish-services/linux/publishing-a-geoprocessing-service.htm) 28 | * [ArcGIS Blog](http://blogs.esri.com/esri/arcgis/) 29 | * [twitter@esri](http://twitter.com/esri) 30 | 31 | ## Issues 32 | Find a bug or want to request a new feature? Please let us know by submitting an issue. 33 | 34 | ## Contributing 35 | Esri welcomes contributions from anyone and everyone. Please see our [guidelines for contributing](https://github.com/esri/contributing). 36 | 37 | ## Licensing 38 | Copyright 2016 Esri 39 | Licensed under the Apache License, Version 2.0 (the "License"); 40 | you may not use this file except in compliance with the License. 41 | You may obtain a copy of the License at 42 | 43 | http://www.apache.org/licenses/LICENSE-2.0 44 | 45 | Unless required by applicable law or agreed to in writing, software 46 | distributed under the License is distributed on an "AS IS" BASIS, 47 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 48 | See the License for the specific language governing permissions and 49 | limitations under the License. 50 | 51 | A copy of the license is available in the repository's [license.txt]( https://raw.github.com/Esri/elevation-gp-python/master/license.txt) file. 52 | 53 | [](Esri Tags: ArcGIS Portal Geoprocessing Elevation Viewshed) 54 | [](Esri Language: Python) 55 | -------------------------------------------------------------------------------- /elevation-gp-python.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Esri/elevation-gp-python/cd9a8d6892b3690f927450d628262a05539d0ec9/elevation-gp-python.png -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | Apache License - 2.0 2 | 3 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 4 | 5 | 1. Definitions. 6 | 7 | "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. 8 | 9 | "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. 10 | 11 | "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control 12 | with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management 13 | of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial 14 | ownership of such entity. 15 | 16 | "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. 17 | 18 | "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, 19 | and configuration files. 20 | 21 | "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to 22 | compiled object code, generated documentation, and conversions to other media types. 23 | 24 | "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice 25 | that is included in or attached to the work (an example is provided in the Appendix below). 26 | 27 | "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the 28 | editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes 29 | of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, 30 | the Work and Derivative Works thereof. 31 | 32 | "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work 33 | or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual 34 | or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of 35 | electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on 36 | electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for 37 | the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing 38 | by the copyright owner as "Not a Contribution." 39 | 40 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and 41 | subsequently incorporated within the Work. 42 | 43 | 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, 44 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, 45 | publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 46 | 47 | 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, 48 | non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, 49 | sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are 50 | necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was 51 | submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work 52 | or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You 53 | under this License for that Work shall terminate as of the date such litigation is filed. 54 | 55 | 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, 56 | and in Source or Object form, provided that You meet the following conditions: 57 | 58 | 1. You must give any other recipients of the Work or Derivative Works a copy of this License; and 59 | 60 | 2. You must cause any modified files to carry prominent notices stating that You changed the files; and 61 | 62 | 3. You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices 63 | from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and 64 | 65 | 4. If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a 66 | readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the 67 | Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the 68 | Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever 69 | such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. 70 | You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, 71 | provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to 72 | Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your 73 | modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with 74 | the conditions stated in this License. 75 | 76 | 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You 77 | to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, 78 | nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 79 | 80 | 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except 81 | as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 82 | 83 | 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides 84 | its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, 85 | any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for 86 | determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under 87 | this License. 88 | 89 | 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required 90 | by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, 91 | including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the 92 | use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or 93 | any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 94 | 95 | 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a 96 | fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting 97 | such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree 98 | to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your 99 | accepting any such warranty or additional liability. 100 | 101 | END OF TERMS AND CONDITIONS --------------------------------------------------------------------------------