From b310ff48901bd8daa4403058d90f4423728b8b94 Mon Sep 17 00:00:00 2001 From: "Hunter, Marc Andrew" <mahunter@usgs.gov> Date: Fri, 14 Apr 2023 19:59:07 +0000 Subject: [PATCH] Upload New File --- PGM_Toolbox_ArcPro3/PGM_Toolbox.pyt | 880 ++++++++++++++++++++++++++++ 1 file changed, 880 insertions(+) create mode 100644 PGM_Toolbox_ArcPro3/PGM_Toolbox.pyt diff --git a/PGM_Toolbox_ArcPro3/PGM_Toolbox.pyt b/PGM_Toolbox_ArcPro3/PGM_Toolbox.pyt new file mode 100644 index 0000000..77593fe --- /dev/null +++ b/PGM_Toolbox_ArcPro3/PGM_Toolbox.pyt @@ -0,0 +1,880 @@ +#/****************************************************************************** +# * $Id$ +# * +# * Project: Support a range of common workflows to support planetary geologic mapping +# * Purpose: Tools include Merge Files, New Template Geodatabase, Build Polygons, +# Topology Check, Longitude Conversion. +# * Author: Marc Hunter, mahunter@usgs.gov +# * +# ****************************************************************************** +# * Public domain licenes (unlicense) +# * +# * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# * DEALINGS IN THE SOFTWARE. +# ****************************************************************************** +# * Disclaimer +# * +# * This software has been approved for release by the U.S. Geological Survey (USGS). +# * Although the software has been subjected to rigorous review, the USGS reserves +# * the right to update the software as needed pursuant to further analysis and review. +# * No warranty, expressed or implied, is made by the USGS or the U.S. Government as +# * to the functionality of the software and related material nor shall the fact of +# * release constitute any such warranty. Furthermore, the software is released on +# * condition that neither the USGS nor the U.S. Government shall be held liable for +# * any damages resulting from its authorized or unauthorized use. +# *****************************************************************************/ + +import arcpy, os, sys +from arcpy import env +from arcpy.sa import * +import numpy +import pandas +#import json + +class Toolbox(object): + def __init__(self): + """Define the toolbox (the name of the toolbox is the name of the + .pyt file).""" + self.label = "PyGM Toolbox" + self.alias = "" + +# List of tool classes associated with this toolbox + self.tools = [ClipNShip, LongitudeConversion, NewGDB, MergeFiles, TopologyCheck, BuildPolygons] + +class ClipNShip(object): + def __init__(self): + """Define the tool (tool name is the name of the class).""" + self.label = "Basemap Clip-N-Ship" + self.canRunInBackground = False + + def getParameterInfo(self): + """Define parameter definitions""" + param0 = arcpy.Parameter( + displayName="Boundary Feature", + name="in_fc", + datatype= ["GPFeatureLayer", "DEFeatureClass"], + parameterType="Required", + direction="Input") + param1 = arcpy.Parameter( + displayName="Mosaic Raster List", + name="mosaic_list", + datatype=["DERasterDataset", "GPRasterLayer"], + parameterType="Required", + direction="Input") + param2 = arcpy.Parameter( + displayName="Output Raster", + name="out_raster", + datatype="DERasterDataset", + parameterType="Required", + direction="Output") + param3 = arcpy.Parameter( + displayName="Workspace", + name="workspace", + datatype="DEWorkspace", + parameterType="Required", + direction="Input") + + param1.multiValue = True + parameters = [param0, param1, param2, param3] + return parameters + + def isLicensed(self): + """Set whether tool is licensed to execute.""" + return True + + def updateParameters(self, parameters): + """Modify the values and properties of parameters before internal + validation is performed. This method is called whenever a parameter + has been changed.""" + return + + def updateMessages(self, parameters): + """Modify the messages created by internal validation for each tool + parameter. This method is called after internal validation.""" + return + + + def execute(self, parameters, messages): +#read in parameters + inFC = parameters[0].value + rasterList = parameters[1].values + outRaster = parameters[2].valueAsText + inWorkspace = parameters[3].valueAsText + + inFCdesc = arcpy.Describe(inFC) + FCsr = inFCdesc.spatialReference + + ws = inWorkspace + "\\clipNship" + tempRaster = ws + "\\tempRaster.tif" + inRasterSR = arcpy.Describe(rasterList[0]).spatialReference + gdbPath = ws + "\\temp.gdb" + if gdbPath: + arcpy.Delete_management(ws) + os.mkdir(inWorkspace + "\\clipNship") + + if len(rasterList) > 1: + arcpy.CreateFileGDB_management(ws, "temp", "CURRENT") + arcpy.CreateMosaicDataset_management(gdbPath, "tempMosaic", inRasterSR) + mosaicPath = gdbPath + "\\tempMosaic" + for ea in rasterList: + arcpy.AddRastersToMosaicDataset_management(mosaicPath, "Raster Dataset", ea) + clippedMosaic = arcpy.sa.ExtractByMask(mosaicPath, inFC) + clippedMosaic.save(tempRaster) + arcpy.ProjectRaster_management(tempRaster, outRaster, FCsr) + arcpy.Delete_management(ws) + + if len(rasterList) == 1: + clippedRaster = arcpy.sa.ExtractByMask(rasterList[0], inFC) + clippedRaster.save(tempRaster) + arcpy.ProjectRaster_management(tempRaster, outRaster, FCsr) + arcpy.AddMessage(ws) + arcpy.Delete_management(tempRaster) + arcpy.Delete_management(ws) + return + +class LongitudeConversion(object): + def __init__(self): + """Define the tool (tool name is the name of the class).""" + self.label = "Longitude Conversion" + self.description = "" + self.canRunInBackground = False + + def getParameterInfo(self): + """Define parameter definitions""" + param0 = arcpy.Parameter( + displayName="Input Feature Class", + name="in_fc", + datatype= ["GPFeatureLayer", "DEFeatureClass"], + parameterType="Required", + direction="Input") + param1 = arcpy.Parameter( + displayName="Output Feature Class", + name="out_fc", + datatype="DEFeatureClass", + parameterType="Required", + direction="Output") + param2 = arcpy.Parameter( + displayName="Conversion Type", + name="conversion_type", + datatype="GPString", + parameterType="Required", + direction="Input") + + param2.filter.type = "ValueList" + param2.filter.list = ["Convert to -180 - 180 longitude", "Convert to 0 - 360 longitude"] + parameters = [param0, param1, param2] + return parameters + + def isLicensed(self): + """Set whether tool is licensed to execute.""" + return True + + def updateParameters(self, parameters): + """Modify the values and properties of parameters before internal + validation is performed. This method is called whenever a parameter + has been changed.""" + return + + def updateMessages(self, parameters): + """Modify the messages created by internal validation for each tool + parameter. This method is called after internal validation.""" + return + + + def execute(self, parameters, messages): +#read in parameters + inFC = parameters[0].value + outFC = parameters[1].valueAsText + conversionType = parameters[2].valueAsText + inFCdesc = arcpy.Describe(inFC) + FCsr = inFCdesc.spatialReference + if FCsr.projectionName: + arcpy.AddMessage("Projected Coordinate Systems are not supported") + return + arcpy.Delete_management("in_memory") + + if conversionType == "Convert to -180 - 180 longitude": + pMeridian = 0.0 + lonChange = -360.0 + oldMeridian = "180.0],UNIT" + newMeridian = "0.0],UNIT" + clipArrayWest = arcpy.Array([arcpy.Point(0.0, 90.0), + arcpy.Point(0.0, -90.0), + arcpy.Point(180.0, -90.0), + arcpy.Point(180.0, 90.0), + arcpy.Point(0.0, 90.0)]) + clipArrayEast = arcpy.Array([arcpy.Point(180.0, 90.0), + arcpy.Point(180.0, -90.0), + arcpy.Point(360.0, -90.0), + arcpy.Point(360.0, 90.0), + arcpy.Point(180.0, 90.0)]) + if conversionType == "Convert to 0 - 360 longitude": + pMeridian = 180.0 + lonChange = 360.0 + oldMeridian = "0.0],UNIT" + newMeridian = "180.0],UNIT" + clipArrayWest = arcpy.Array([arcpy.Point(-180.0, 90.0), + arcpy.Point(-180.0, -90.0), + arcpy.Point(0.0, -90.0), + arcpy.Point(0.0, 90.0), + arcpy.Point(-180.0, 90.0)]) + clipArrayEast = arcpy.Array([arcpy.Point(0.0, 90.0), + arcpy.Point(0.0, -90.0), + arcpy.Point(180.0, -90.0), + arcpy.Point(180.0, 90.0), + arcpy.Point(0.0, 90.0)]) + + outFClayer = "in_memory/outFClayer" + arcpy.CopyFeatures_management(inFC, outFClayer) + clipPolygonLayer = "in_memory/polygonFC" + arcpy.CreateFeatureclass_management("in_memory", "polygonFC", "Polygon") + arcpy.DefineProjection_management(clipPolygonLayer, FCsr) + clipPolygonWest = arcpy.Polygon(clipArrayWest) + clipPolygonEast = arcpy.Polygon(clipArrayEast) + polyCursor = arcpy.da.InsertCursor(clipPolygonLayer, ['SHAPE@']) + polyCursor.insertRow([clipPolygonWest]) + polyCursor.insertRow([clipPolygonEast]) + del polyCursor + + clipFClayer = "in_memory/clipFClayer" + arcpy.AddField_management(outFClayer, "orig_fid", "LONG") + arcpy.CalculateField_management(outFClayer, "orig_fid", '!FID!', "PYTHON") + arcpy.Intersect_analysis([[clipPolygonLayer, 2], [outFClayer, 1]], clipFClayer) + FCsrPRJ = FCsr.exportToString() + outFCsrPRJ = FCsrPRJ.replace(oldMeridian, newMeridian) + outFCsr = arcpy.SpatialReference() + outFCsr.loadFromString(outFCsrPRJ) + arcpy.DefineProjection_management(clipFClayer, outFCsr) + +# Convert X coordinate of each point in each part in each feature + with arcpy.da.UpdateCursor(clipFClayer, ['SHAPE@']) as cursor: + pnt_array = arcpy.Array() + part_array = arcpy.Array() + partnum = 0 + arcpy.AddMessage(arcpy.Describe(clipFClayer).shapeType) +# For points + if arcpy.Describe(clipFClayer).shapeType == "Point": + for row in cursor: + feature = arcpy.PointGeometry.getPart(row[0]) + if feature.X < 0.0 or feature.X > 180.0: + feature.X = feature.X + lonChange + else: + pass + part_array.add(feature) + cursor.updateRow(row) +# For multipoints + elif arcpy.Describe(clipFClayer).shapeType == "Multipoint": + for row in cursor: + geometry = row[0] + for part in geometry: + pts = geometry[0] + if pts.X < 0.0 or pts.X > 180.0: + pts.X = pts.X + lonChange + else: + pass + part_array.add(pts) + cursor.updateRow(row) + part_array.removeAll() + partnum += 1 +# For polylines and polygons + else: + for row in cursor: + geometry = row[0] + for part in geometry: + pts = geometry.getPart(partnum) + for pnt in pts: + if pnt: + if pnt.X < 0.0 or pnt.X > 180.0: + pnt.X = pnt.X + lonChange + else: + pass + pnt_array.add(pnt) + part_array.add(pnt_array) + arcpy.AddMessage(pnt_array) + pnt_array.removeAll() + partnum += 1 + arcpy.AddMessage(part_array) + if arcpy.Describe(clipFClayer).shapeType == "Polygon": + new_feature_geometry = arcpy.Polygon(part_array) + elif arcpy.Describe(clipFClayer).shapeType == "Polyline": + new_feature_geometry = arcpy.Polyline(part_array) + else: + print("Unrecognized geometry") + return + part_array.removeAll() + geometry = new_feature_geometry + cursor.updateRow(row) + + if conversionType == "Convert to -180 - 180 longitude": +#Should snap be applied both ways? + arcpy.Snap_edit(clipFClayer, [[clipFClayer, "VERTEX", "0.001 Degrees"]]) + + dissolveFClayer = "in_memory/dissolveFClayer" + arcpy.Dissolve_management(clipFClayer, dissolveFClayer, 'orig_fid') + joinedFC = arcpy.JoinField_management(dissolveFClayer, 'orig_fid', outFClayer, 'orig_fid') + arcpy.CopyFeatures_management(joinedFC, outFC) + arcpy.DeleteField_management(outFC, ['orig_fid', 'orig_fid_1']) + arcpy.Delete_management("in_memory") + return + +class NewGDB(object): + def __init__(self): + """Define the tool (tool name is the name of the class).""" + self.label = "New Map GDB" + self.description = "" + self.canRunInBackground = False + + def getParameterInfo(self): + """Define parameter definitions""" + param0 = arcpy.Parameter( + displayName="Map Boundary", + name="inBoundary", + datatype=["GPFeatureLayer", "DEShapefile", "DEFeatureClass"], + parameterType="Required", + direction="Input") + param1 = arcpy.Parameter( + displayName="Output Location", + name="outWorkspace", + datatype="DEWorkspace", + parameterType="Required", + direction="Input") + param2 = arcpy.Parameter( + displayName="File Geodatabase Name", + name="outGDB", + datatype="GPString", + parameterType="Required", + direction="Input") + param3 = arcpy.Parameter( + displayName="Geodatabase Version", + name="GDBversion", + datatype="GPString", + parameterType="Required", + direction="input") + param0.Filter = ["Polygon"] + param3.filter.type = "ValueList" + param3.filter.list = ["9.2", "9.3", "10.0", "CURRENT"] + param3.value = "CURRENT" + params = [param0, param1, param2, param3] + return params + + def isLicensed(self): + """Set whether tool is licensed to execute.""" + return True + + def updateParameters(self, parameters): + """Modify the values and properties of parameters before internal + validation is performed. This method is called whenever a parameter + has been changed.""" + return + + def updateMessages(self, parameters): + """Modify the messages created by internal validation for each tool + parameter. This method is called after internal validation.""" + return + + def execute(self, params, messages): + """The source code of the tool.""" + #Read in parameters + inBoundary = params[0].valueAsText + outWorkspace = params[1].valueAsText + GDBname = params[2].valueAsText + gdbVersion = params[3].valueAsText + #Get boundary object + boundaryDesc = arcpy.Describe(inBoundary) + boundaryFullPath = boundaryDesc.catalogPath + boundarySpatialRef = boundaryDesc.spatialReference + + #Create file GDB in workspace + arcpy.CreateFileGDB_management(outWorkspace, GDBname, gdbVersion) + + #Get GDB object + GDBpath = outWorkspace + "/" + GDBname + ".gdb" + GDBdesc = arcpy.Describe(GDBpath) + + #Create domains + arcpy.CreateDomain_management(GDBpath, "contact", "type of geologic contact", "TEXT", "CODED", "DEFAULT", "DEFAULT") + arcpy.CreateDomain_management(GDBpath, "contacts, key beds, and dikes", "contacts, key beds, and dikes", "TEXT", "CODED", "DEFAULT", "DEFAULT") + arcpy.CreateDomain_management(GDBpath, "eolian features", "eolian features", "TEXT", "CODED", "DEFAULT", "DEFAULT") + arcpy.CreateDomain_management(GDBpath, "faults", "faults", "TEXT", "CODED", "DEFAULT", "DEFAULT") + arcpy.CreateDomain_management(GDBpath, "folds", "folds", "TEXT", "CODED", "DEFAULT", "DEFAULT") + arcpy.CreateDomain_management(GDBpath, "landslide and mass-wasting", "landslide and mass-wasting", "TEXT", "CODED", "DEFAULT", "DEFAULT") + arcpy.CreateDomain_management(GDBpath, "lineaments and joints", "lineaments and joints", "TEXT", "CODED", "DEFAULT", "DEFAULT") + arcpy.CreateDomain_management(GDBpath, "linear feature", "type of linear feature", "TEXT", "CODED", "DEFAULT", "DEFAULT") + arcpy.CreateDomain_management(GDBpath, "point feature", "type of point feature", "TEXT", "CODED", "DEFAULT", "DEFAULT") + arcpy.CreateDomain_management(GDBpath, "polygon feature", "type of polygon feature", "TEXT", "CODED", "DEFAULT", "DEFAULT") + arcpy.CreateDomain_management(GDBpath, "zones and blocks", "zones and blocks", "TEXT", "CODED", "DEFAULT", "DEFAULT") + + #Attribute coded domain dictionaries + contactDict = {"certain":"certain", "approximate":"approximate", "inferred":"inferred", "concealed":"concealed", "gradational":"gradational", "boundary":"boundary", "generic contact 1":"generic contact 1", "generic contact 2":"generic contact 2"} + contactsdikesDict = {"contact 1.1.1":"contact - id certain, location accurate", "contact 1.1.2":"contact - id queried, location accurate", "contact 1.1.3":"contact - id certain, location approximate", "contact 1.1.4":"contact - id queried, location approximate", "contact 1.1.5":"contact - id certain, location inferred", "contact 1.1.6":"contact - id queried, location inferred", "contact 1.1.7":"contact - id certain, location concealed", "contact 1.1.8":"contact - id queried, location concealed", "contact 1.1.25":"unconformable contact - id certain, location accurate", "contact 1.1.26":"unconformable contact - id queried, location accurate", "contact 1.1.27":"unconformable contact - id certain, location approximate", "contact 1.1.28":"unconformable contact - id queried, location approximate", "contact 1.1.29":"unconformable contact - id certain, location inferred", "contact 1.1.30":"unconformable contact - id queried, location inferred", "contact 1.1.31":"unconformable contact - id certain, location concealed", "contact 1.1.32":"unconformable contact - id queried, location concealed", "dike 1.3.5":"dike - id certain, location accurate", "dike 1.3.6":"dike - id certain, location approximate"} + eolianDict = {"dune crest":"dune crest", "scarp on dune screst":"scarp on dune screst"} + faultsDict = {"fault 2.1.1":"fault, generic - id certain, location accurate", "fault 2.1.2":"fault, generic - id queried, location accurate", "fault 2.1.3":"fault, generic - id certain, location approximate", "fault 2.1.4":"fault, generic - id queried, location approximate", "fault 2.1.5":"fault, generic - id certain, location inferred", "fault 2.1.6":"fault, generic - id queried, location inferred", "fault 2.1.7":"fault, generic - id certain, location concealed", "fault 2.1.8":"fault, generic - id queried, location concealed", "fault 2.2.1":"fault, normal - id certain, location accurate", "fault 2.2.3":"fault, normal - id certain, location approximate", "fault 2.2.5":"fault, normal - id certain, location inferred", "fault 2.2.7":"fault, normal - id certain, location concealed", "fault 2.8.1":"thrust fault - id certain, location accurate", "fault 2.8.3":"thrust fault - id certain, location approximate", "fault 2.8.5":"thrust fault - id certain, location inferred", "fault 2.8.7":"thrust fault - id certain, location concealed", "fault 2.9.1":"overturned thrust fault - id certain, location accurate", "fault 2.9.3":"overturned thrust fault - id certain, location approximate", "fault 2.9.5":"overturned thrust fault - id certain, location inferred", "fault 2.9.7":"overturned thrust fault - id certain, location concealed", "fault 2.11.10":"fault - vertical or near vertical", "fault 2.14.1":"ductile shear zone"} + foldsDict = {"anticline 5.1.1":"anticline - id certain, location accurate", "anticline 5.1.3":"anticline - id certain, location approximate", "anticline 5.1.5":"anticline - id certain, location inferred", "anticline 5.1.7":"anticline - id certain, location concealed", "antiform 5.2.9":"antiform - id certain, location accurate", "antiform 5.2.11":"antiform - id certain, location approximate", "antiform 5.2.13":"antiform - id certain, location inferred", "antiform 5.2.15":"antiform - id certain, location concealed", "anticline 5.3.17":"anticline, overturned - id certain, location accurate", "anticline 5.3.19":"anticline, overturned - id certain, location approximate", "anticline 5.3.21":"anticline, overturned - id certain, location inferred", "anticline 5.3.23":"anticline, overturned - id certain, location concealed", "syncline 5.5.1":"syncline - id certain, location accurate", "syncline 5.5.3":"syncline - id certain, location approximate", "syncline 5.5.5":"syncline - id certain, location inferred", "syncline 5.5.7":"syncline - id certain, location concealed", "synform 5.6.9":"synform - id certain, location accurate", "synform 5.6.11":"synform - id certain, location approximate", "synform 5.6.13":"synform - id certain, location inferred", "synform 5.6.15":"synform - id certain, location concealed", "syncline 5.7.17":"syncline, overturned - id certain, location accurate", "syncline 5.7.19":"syncline, overturned - id certain, location approximate", "syncline 5.7.21":"syncline, overturned - id certain, location inferred", "syncline 5.7.23":"syncline, overturned - id certain, location concealed", "monocline 5.9.1":"monocline - id certain, location accurate", "monocline 5.9.3":"monocline - id certain, location approximate", "monocline 5.9.5":"monocline - id certain, location inferred", "monocline 5.9.7":"monocline - id certain, location concealed", "anticline 5.10.5":"anticline, plunging", "anticline 5.10.6":"anticline, doubly plunging", "syncline 5.10.7":"syncline, plunging", "syncline 5.10.8":"syncline, doubly plunging"} + landslideDict = {"landslide 17.1":"slip surface outline - id certain, location accurate", "landslide 17.2":"slip surface outline - id queried, location accurate", "landslide 17.3":"slip surface outline - id certain, location approximate", "landslide 17.4":"slip surface outline - id queried, location approximate", "landslide 17.5":"slip surface outline - id certain, location inferred", "landslide 17.6":"slip surface outline - id queried, location inferred", "landslide 17.7":"slip surface outline - id certain, location concealed", "landslide 17.8":"slip surface outline - id queried, location concealed", "landslide 17.12":"main scarp, active", "landslide 17.13":"main scarp, inactive", "landslide 17.16":"minor scarp, active", "landslide 17.17":"minor scarp, inactive", "landslide 17.20":"main toe, active", "landslide 17.21":"main toe, inactive", "landslide 17.22":"minor toe, internal thrust, or pressure ridge, active", "landslide 17.23":"minor toe, internal thrust, or pressure ridge, inactive", "landslide 17.35":"tension crack", "landslide 17.44":"crest line of lateral levee", "landslide 17.10":"direction of downslope motion"} + lineamentDict = {"lineament 4.1.1":"lineament", "joint 4.2.1":"joint, id certain, location accurate", "joint 4.2.2":"joint, id certain, location approximate", "joint 4.2.3":"joint, vertical or subvertical"} + linearDict = {"fault, certain":"fault, certain", "fault, approx.":"fault, approx.", "normal fault, certain":"normal fault, certain", "normal fault, approx.":"normal fault, approx.", "graben trace, certain":"graben trace, certain", "graben trace, approx.":"graben trace, approx.", "reverse fault, certain":"reverse fault, certain", "reverse fault, approx.":"reverse fault, approx.", "ridge crest (type 1), certain":"ridge crest (type 1), certain", "ridge crest (type 1), approx.":"ridge crest (type 1), approx.", "ridge crest (type 2), certain":"ridge crest (type 2), certain", "ridge crest (type 2), approx.":"ridge crest (type 2), approx.", "scarp base":"scarp base", "scarp crest":"scarp crest", "groove":"groove", "depression margin":"depression margin", "dome margin":"dome margin", "lineament":"lineament", "channel (fluvial)":"channel (fluvial)", "channel (volcanic)":"channel (volcanic)", "sinuous channel or groove":"sinuous channel or groove", "crest of crater rim":"crest of crater rim", "crest of buried crater":"crest of buried crater", "small crater rim":"small crater rim", "generic linear 1":"generic linear 1", "generic linear 2":"generic linear 2", "trough (type 1)":"trough (type 1)", "trough (type 2)":"trough (type 2)"} + pointDict = {"pitted cone":"pitted cone", "small crater":"small crater", "shield (certain)":"shield (certain)", "shield (uncertain)":"shield (uncertain)", "generic pt 1":"generic pt 1", "generic pt 2":"generic pt 2"} + polygonDict = {"dark-colored ejecta":"dark-colored ejecta", "secondary crater chain":"dark-colored mantling material", "thumbprint terrain":"thumbprint terrain", "polygonal terrain":"polygonal terrain", "residual ice":"residual ice", "patterned ground (type 1)":"patterned ground (type 1)", "patterend ground (type 2)":"patterend ground (type 2)", "generic overlay 1":"generic overlay 1", "generic overlay 2":"generic overlay 2"} + zonesDict = {"dike 1.3.13":"dike of variable thickness", "shear zone 2.14.2":"shear zone within fault", "breccia zone 2.14.3":"breccia zone within fault", "breccia zone 2.14.4":"breccia zone around fault", "slip surface 17.9":"area of slip surface of landslide", "debris-slide slope 17.65":"debris-slide slope (multiple)"} + + #Add coded values to domains + for code in contactDict: + arcpy.AddCodedValueToDomain_management(GDBpath, "contact", code, contactDict[code]) + for code in contactsdikesDict: + arcpy.AddCodedValueToDomain_management(GDBpath, "contacts, key beds, and dikes", code, contactsdikesDict[code]) + for code in eolianDict: + arcpy.AddCodedValueToDomain_management(GDBpath, "eolian features", code, eolianDict[code]) + for code in faultsDict: + arcpy.AddCodedValueToDomain_management(GDBpath, "faults", code, faultsDict[code]) + for code in foldsDict: + arcpy.AddCodedValueToDomain_management(GDBpath, "folds", code, foldsDict[code]) + for code in landslideDict: + arcpy.AddCodedValueToDomain_management(GDBpath, "landslide and mass-wasting", code, landslideDict[code]) + for code in lineamentDict: + arcpy.AddCodedValueToDomain_management(GDBpath, "lineaments and joints", code, lineamentDict[code]) + for code in linearDict: + arcpy.AddCodedValueToDomain_management(GDBpath, "linear feature", code, linearDict[code]) + for code in pointDict: + arcpy.AddCodedValueToDomain_management(GDBpath, "point feature", code, pointDict[code]) + for code in polygonDict: + arcpy.AddCodedValueToDomain_management(GDBpath, "polygon feature", code, polygonDict[code]) + for code in zonesDict: + arcpy.AddCodedValueToDomain_management(GDBpath, "zones and blocks", code, zonesDict[code]) + + #Create feature dataset and feature classes + arcpy.CreateFeatureDataset_management(GDBpath, "domain_proj_clon", boundarySpatialRef) + FDpath = GDBpath + "/" + "domain_proj_clon" + arcpy.CreateFeatureclass_management(FDpath, "GeoContacts", "POLYLINE") + arcpy.CreateFeatureclass_management(FDpath, "LinearFeatures", "POLYLINE") + arcpy.CreateFeatureclass_management(FDpath, "LocationFeatures", "POINT") + arcpy.CreateFeatureclass_management(FDpath, "MapBoundary", "POLYGON") + arcpy.CreateFeatureclass_management(FDpath, "SurfaceFeatures", "POLYGON") + + #Add fields with coded domains + contactsFC = FDpath + "/" + "GeoContacts" + linearFC = FDpath + "/" + "LinearFeatures" + locationFC = FDpath + "/" + "LocationFeatures" + boundaryFC = FDpath + "/" + "MapBoundary" + surfaceFC = FDpath + "/" + "SurfaceFeatures" + + arcpy.AddField_management(contactsFC, "TYPE", "TEXT", "", "", 50, "TYPE", "NULLABLE", "REQUIRED", "contact") + arcpy.AddField_management(contactsFC, "COMMENT", "TEXT", "", "", 250, "COMMENT", "NULLABLE", "REQUIRED", "") + arcpy.AddField_management(linearFC, "TYPE", "TEXT", "", "", 50, "TYPE", "NULLABLE", "REQUIRED", "linear feature") + arcpy.AddField_management(linearFC, "COMMENT", "TEXT", "", "", 250, "COMMENT", "NULLABLE", "REQUIRED", "") + arcpy.AddField_management(locationFC, "TYPE", "TEXT", "", "", 50, "TYPE", "NULLABLE", "REQUIRED", "point feature") + arcpy.AddField_management(locationFC, "COMMENT", "TEXT", "", "", 250, "COMMENT", "NULLABLE", "REQUIRED", "") + arcpy.AddField_management(surfaceFC, "TYPE", "TEXT", "", "", 50, "TYPE", "NULLABLE", "REQUIRED", "polygon feature") + arcpy.AddField_management(surfaceFC, "COMMENT", "TEXT", "", "", 250, "COMMENT", "NULLABLE", "REQUIRED", "") + arcpy.AddField_management(boundaryFC, "QUAD_NAME", "TEXT", "", "", 250, "QUAD_NAME", "NULLABLE", "REQUIRED", "") + arcpy.AddField_management(boundaryFC, "LAT_MIN", "FLOAT", "", "", "", "", "NULLABLE", "REQUIRED", "") + arcpy.AddField_management(boundaryFC, "LAT_MAX", "FLOAT", "", "", "", "", "NULLABLE", "REQUIRED", "") + arcpy.AddField_management(boundaryFC, "LON_MIN", "FLOAT", "", "", "", "", "NULLABLE", "REQUIRED", "") + arcpy.AddField_management(boundaryFC, "LON_MAX", "FLOAT", "", "", "", "", "NULLABLE", "REQUIRED", "") + arcpy.AddField_management(boundaryFC, "CLON", "FLOAT", "", "", "", "", "NULLABLE", "REQUIRED", "") + arcpy.AddField_management(boundaryFC, "SP_1", "FLOAT", "", "", "", "", "NULLABLE", "REQUIRED", "") + arcpy.AddField_management(boundaryFC, "SP_2", "FLOAT", "", "", "", "", "NULLABLE", "REQUIRED", "") + + #Import map boundary to MapBoundary feature class and GeoContacts + arcpy.Append_management(boundaryFullPath, boundaryFC, "NO_TEST") + boundaryLine = "in_memory/boundaryLine" + arcpy.PolygonToLine_management(boundaryFullPath, boundaryLine) + arcpy.Append_management(boundaryLine, contactsFC, "NO_TEST") + arcpy.CalculateField_management(contactsFC, "TYPE", '"boundary"') + arcpy.Delete_management(boundaryLine) + return + +class MergeFiles(object): + def __init__(self): + """Define the tool (tool name is the name of the class).""" + self.label = "Merge Files" + self.description = "" + self.canRunInBackground = False + + def getParameterInfo(self): + """Define parameter definitions""" + param0 = arcpy.Parameter( + displayName="Workspace", + name="workspace", + datatype=["DEWorkspace", "DEFeatureDataset"], + parameterType="Required", + direction="Input") + param1 = arcpy.Parameter( + displayName="Wildcard", + name="wildcard", + datatype="GPString", + parameterType="Optional", + direction="Input") + param2 = arcpy.Parameter( + displayName="Feature Type", + name="featureType", + datatype="GPString", + parameterType="Required", + direction="Input") + param3 = arcpy.Parameter( + displayName="Recursive", + name="recursive", + datatype="GPBoolean", + parameterType="Optional", + direction="Input") + param4 = arcpy.Parameter( + displayName="Output Feature Class", + name="outFC", + datatype="DEFeatureClass", + parameterType="Required", + direction="Output") + parameters = [param0, param1, param2, param3, param4] + param2.filter.list = ["POLYGON", "POLYLINE", "POINT", "MULTIPOINT"] + return parameters + + def isLicensed(self): + """Set whether tool is licensed to execute.""" + return True + + def updateParameters(self, parameters): + """Modify the values and properties of parameters before internal + validation is performed. This method is called whenever a parameter + has been changed.""" + return + + def updateMessages(self, parameters): + """Modify the messages created by internal validation for each tool + parameter. This method is called after internal validation.""" + return + + def execute(self, parameters, messages): + """The source code of the tool.""" +# Script arguments + + def recursive_list_fcs(workspace, wild_card=None, feature_type=None): + """Returns a list of all feature classes in a tree. Returned + list can be limited by a wildcard, and feature type. + """ + preexisting_wks = arcpy.env.workspace + arcpy.env.workspace = workspace + try: + list_fcs = [] + for root, dirs, files in os.walk(workspace): + arcpy.env.workspace = root + fcs = arcpy.ListFeatureClasses(wild_card, feature_type) + if fcs: + list_fcs += [os.path.join(root, fc) for fc in fcs] + except Exception as err: + raise err + finally: + arcpy.env.workspace = preexisting_wks + return list_fcs + + Workspace = parameters[0].valueAsText + Wildcard = parameters[1].valueAsText + FeatureType = parameters[2].valueAsText + Recursive = parameters[3].valueAsText + outputFC = parameters[4].valueAsText + + if Recursive == '#' or not Recursive: + Recursive = "false" # provide a default value if unspecified + +# Local variables: + FieldName = "Filename" + outputFCpath, outputFCname = os.path.split(outputFC) + +# Process: Iterate Feature Classes + arcpy.env.workspace = Workspace + if Recursive == "true": + WorkspaceList = recursive_list_fcs(Workspace, Wildcard, FeatureType) + elif Recursive == "false": + if Wildcard: + WorkspaceList = arcpy.ListFeatureClasses(Wildcard, FeatureType) + else: + WorkspaceList = arcpy.ListFeatureClasses("", FeatureType, "") + + arcpy.AddMessage(WorkspaceList) + s_list = [] #list of inputs for arcpy.Merge + for s in WorkspaceList: + s_list.append(s) + sDesc = arcpy.Describe(s) + sName = sDesc.name + if sName.endswith('.shp'): + sName = sName[:-4] + arcpy.AddMessage(sName) + arcpy.AddField_management(s, FieldName, "TEXT", "", "", "124", "", "NULLABLE", "NON_REQUIRED", "") + expression = """'{}'""".format(sName) + arcpy.CalculateField_management(s, FieldName, expression, "PYTHON_9.3") + #Can't use append due to fields with spaces. Try merge instead. + #arcpy.Append_management(s, outputFC, "NO_TEST", "", "") + + arcpy.Merge_management(s_list, outputFC, "") + return + +class TopologyCheck(object): + def __init__(self): + """Define the tool (tool name is the name of the class).""" + self.label = "Topology Check" + self.description = "" + self.canRunInBackground = False + + def getParameterInfo(self): + """Define parameter definitions""" + param0 = arcpy.Parameter( + displayName="Input Feature Class", + name="in_fc", + datatype="GPFeatureLayer", + parameterType="Required", + direction="Input") + param1 = arcpy.Parameter( + displayName="Cluster Tolerance", + name="cluster_tolerance", + datatype="GPString", + parameterType="Optional", + direction="Input") + parameters = [param0, param1] + return parameters + + def isLicensed(self): + """Set whether tool is licensed to execute.""" + return True + + def updateParameters(self, parameters): + """Modify the values and properties of parameters before internal + validation is performed. This method is called whenever a parameter + has been changed.""" + return + + def updateMessages(self, parameters): + """Modify the messages created by internal validation for each tool + parameter. This method is called after internal validation.""" + return + + def execute(self, parameters, messages): + inputFC = parameters[0].valueAsText + clusterToleranceIn = parameters[1].valueAsText + clusterTolerance = "" + if clusterToleranceIn: + clusterTolerance = float(clusterToleranceIn) + inputFCdesc = arcpy.Describe(inputFC) + inFCshape = inputFCdesc.shapeType + inputFCpath = inputFCdesc.path + inputFCname = inputFCdesc.name + inputFCfullpath = inputFCdesc.catalogPath + outputTopologyName = inputFCname + "_Topology" + outputTopology = inputFCpath + "\\" + outputTopologyName +#Create topology and add FC + arcpy.CreateTopology_management(inputFCpath, outputTopologyName, clusterTolerance) + arcpy.AddFeatureClassToTopology_management(outputTopology, inputFC, 1, 1) +#Add rules based on geometry type + if inFCshape == "Polygon": + arcpy.AddRuleToTopology_management(outputTopology, "Must Not Have Gaps (Area)", inputFCfullpath) + arcpy.AddRuleToTopology_management(outputTopology, "Must Not Overlap (Area)", inputFCfullpath) + elif inFCshape == "Polyline": + arcpy.AddRuleToTopology_management(outputTopology, "Must Not Have Dangles (Line)", inputFCfullpath) + arcpy.AddRuleToTopology_management(outputTopology, "Must Not Have Pseudo-Nodes (Line)", inputFCfullpath) + arcpy.AddRuleToTopology_management(outputTopology, "Must Not Self-Overlap (Line)", inputFCfullpath) + arcpy.AddRuleToTopology_management(outputTopology, "Must Not Intersect (Line)", inputFCfullpath) + arcpy.AddRuleToTopology_management(outputTopology, "Must Not Overlap (Line)", inputFCfullpath) + arcpy.AddRuleToTopology_management(outputTopology, "Must Not Self-Intersect (Line)", inputFCfullpath) + else: + arcpy.ErrorMessage("This tool only support polygon and polyline geometry types") + return +#Validate topology and export error report + arcpy.ValidateTopology_management(outputTopology) + arcpy.ExportTopologyErrors_management(outputTopology, inputFCpath, inputFCname) +#Collate results and delete intermediate tables + + return + +class BuildPolygons(object): + def __init__(self): + """Define the tool (tool name is the name of the class).""" + self.label = "Build Polygons" + self.description = "" + self.canRunInBackground = False + + def getParameterInfo(self): + """Define parameter definitions""" + param0 = arcpy.Parameter( + displayName="Input Line Feature Class", + name="in_linefc", + datatype="GPFeatureLayer", + parameterType="Required", + direction="Input") + param1 = arcpy.Parameter( + displayName="Input Polygon Feature Class", + name="in_polygonfc", + datatype="GPFeatureLayer", + parameterType="Optional", + direction="Input") + param2 = arcpy.Parameter( + displayName="Output Feature Class", + name="out_fc", + datatype="DEFeatureClass", + parameterType="Required", + direction="Output") + param0.filter.list = ["Polyline"] + parameters = [param0, param1, param2] + return parameters + + def isLicensed(self): + """Set whether tool is licensed to execute.""" + return True + + def updateParameters(self, parameters): + """Modify the values and properties of parameters before internal + validation is performed. This method is called whenever a parameter + has been changed.""" + return + + def updateMessages(self, parameters): + """Modify the messages created by internal validation for each tool + parameter. This method is called after internal validation.""" + return + + def execute(self, parameters, messages): +#Read in parameters + inputLineFCstr = parameters[0].valueAsText + inputPolygonFCstr = parameters[1].valueAsText + outputFC = parameters[2].valueAsText + + inputLineFCdesc = arcpy.Describe(inputLineFCstr) + lineFC = inputLineFCdesc.catalogPath + +#Execute feature to polygon based on optional parameter + if inputPolygonFCstr: + inputPolygonFCdesc = arcpy.Describe(inputPolygonFCstr) + polygonFC= inputPolygonFCdesc.catalogPath + arcpy.Delete_management("in_memory") + tempPoints = "in_memory\\tempPoints" + arcpy.FeatureToPoint_management(polygonFC, tempPoints, "INSIDE") + arcpy.FeatureToPolygon_management(lineFC, outputFC, "", "", tempPoints) + arcpy.Delete_management(tempPoints) + else: + arcpy.FeatureToPolygon_management(lineFC, outputFC) + arcpy.AddField_management(outputFC, "Type", "TEXT") + return + + +class SlopeAspectTest(object): + def __init__(self): + """Define the tool (tool name is the name of the class).""" + self.label = "Slope & Aspect Test" + self.description = "" + self.canRunInBackground = False + + def getParameterInfo(self): + """Define parameter definitions""" + param0 = arcpy.Parameter( + displayName="Input Point Feature Class", + name="in_pointfc", + datatype="GPFeatureLayer", + parameterType="Required", + direction="Input") + param1 = arcpy.Parameter( + displayName="Field Name", + name="in_field", + datatype="Field", + parameterType="Required", + direction="Input") + param2 = arcpy.Parameter( + displayName="Input DEM", + name="in_dem", + datatype="GPRasterLayer", + parameterType="Required", + direction="Input") +## param3 = arcpy.Parameter( +## displayName="Tolerance (Degrees)", +## name="in_tolerance", +## datatype="GPDouble", +## parameterType="Required", +## direction="Input") + param3 = arcpy.Parameter( + displayName="Test Type", + name="in_test", + datatype="GPString", + parameterType="Required", + direction="Input") + param4 = arcpy.Parameter( + displayName="Output Feature Class", + name="out_fc", + datatype="DEFeatureClass", + parameterType="Required", + direction="Output") + param0.filter.list = ["Point"] + param3.filter.type = "ValueList" + param3.filter.list = ["Slope", "Aspect"] + param1.parameterDependencies = [param0.name] + parameters = [param0, param1, param2, param3, param4] + return parameters + + def isLicensed(self): + """Set whether tool is licensed to execute.""" + return True + + def updateParameters(self, parameters): + """Modify the values and properties of parameters before internal + validation is performed. This method is called whenever a parameter + has been changed.""" + return + + def updateMessages(self, parameters): + """Modify the messages created by internal validation for each tool + parameter. This method is called after internal validation.""" + return + + def execute(self, parameters, messages): +#read in parameters + inputPointFCstr = parameters[0].value + fieldName = parameters[1].valueAsText + inputDEMlayer = parameters[2].value +# tolerance = float(parameters[3].valueAsText) + testType = parameters[3].valueAsText + outPoints = parameters[4].valueAsText + +#local variables + DEMdesc = arcpy.Describe(inputDEMlayer) + inDEM = DEMdesc.catalogPath + DEMname = DEMdesc.name + pointDesc = arcpy.Describe(inputPointFCstr) + pointFC = pointDesc.catalogPath + arcpy.env.workspace = DEMdesc.path + +#DEM processing based on test type + if testType == "Aspect": + DEMtemp = Aspect(inDEM) + elif testType == "Slope": + DEMtemp = Slope(inDEM, "DEGREE") + +#Extract values of processed DEM to points + ExtractValuesToPoints(pointFC, DEMtemp, outPoints, "INTERPOLATE", "VALUE_ONLY") + newField = testType + "_PyGM" + arcpy.AlterField_management(outPoints, "RASTERVALU", newField) + +#Create feature layer and select records outside tolerance +## outPointsDesc = arcpy.Describe(outPoints) +## outPointsName = outPointsDesc.name +## outPointsLayer = outPointsName + "_Layer" +## arcpy.MakeFeatureLayer_management(outPoints, outPointsLayer) +## mxd = arcpy.mapping.MapDocument("CURRENT") +## dataFrame = arcpy.mapping.ListDataFrames(mxd, "*")[0] +## addLayer = arcpy.mapping.Layer(outPointsLayer) +## arcpy.mapping.AddLayer(dataFrame, addLayer) +## arcpy.RefreshActiveView() +## pointCursor = arcpy.SearchCursor(outPointsLayer) +## for row in pointCursor: +## pointValue = row.getValue(fieldName) +## DEMvalue = float(row.getValue(newField)) +## delimitedFieldName = arcpy.AddFieldDelimiters(outPointsLayer, fieldName) +## whereClause = delimitedFieldName + " > " + str(DEMvalue + tolerance) + " OR " + delimitedFieldName + " < " + str(DEMvalue - tolerance) +## arcpy.AddMessage(whereClause) +## arcpy.SelectLayerByAttribute_management(outPointsLayer, "ADD_TO_SELECTION", whereClause) + try: + arcpy.RefreshActiveView() + except: + Pass +#Delete slope/aspect raster + if arcpy.Exists(DEMtemp): + arcpy.Delete_management(DEMtemp) + + return -- GitLab