├── 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
--------------------------------------------------------------------------------