def plot_junction_points(line_lyr, network_type): """ Dissolves a network polyline feature class into single part features, intersects the dissolved network with itself, and returns a junction point (i.e. tributary confluence) feature class. :param fc: network polyline feature class :return: point feature class """ line_dslv = "in_memory\\line_dslv" gis_tools.newGISDataset("in_memory", line_dslv) arcpy.Dissolve_management(line_lyr, line_dslv, "#", "#", "SINGLE_PART") pnt_junctions = "in_memory\\{0}_pnt_junctions".format(network_type) gis_tools.newGISDataset("in_memory", pnt_junctions) arcpy.Intersect_analysis(line_dslv, pnt_junctions, output_type="POINT") arcpy.AddXY_management(pnt_junctions) return pnt_junctions
def getNetworkNodes(inStreamNetwork, scratchWorkspace="in_memory"): # Preprocess network fcNetworkDissolved = gis_tools.newGISDataset(scratchWorkspace, "GNAT_SO_NetworkDissolved") arcpy.Dissolve_management(inStreamNetwork, fcNetworkDissolved, multi_part="SINGLE_PART", unsplit_lines="DISSOLVE_LINES") fcNetworkIntersectPoints = gis_tools.newGISDataset( scratchWorkspace, "GNAT_SO_NetworkIntersectPoints") arcpy.Intersect_analysis(fcNetworkDissolved, fcNetworkIntersectPoints, "ALL", output_type="POINT") arcpy.AddXY_management(fcNetworkIntersectPoints) fcNetworkNodes = gis_tools.newGISDataset(scratchWorkspace, "GNAT_SO_NetworkNodes") arcpy.Dissolve_management(fcNetworkIntersectPoints, fcNetworkNodes, ["POINT_X", "POINT_Y"], "#", "SINGLE_PART") del fcNetworkDissolved del fcNetworkIntersectPoints return fcNetworkNodes
def join_node_summary(lyrInputSegments, node_type, lyrNodesToSegments, LineOID, tempWorkspace): NODES = "NODES_{0}".format(node_type) tblNodeSummary = gis_tools.newGISDataset(tempWorkspace, "tblNode{0}Summary".format(node_type)) viewNodeSummary = "viewNode{0}Summary".format(node_type) arcpy.SelectLayerByAttribute_management(lyrNodesToSegments, "NEW_SELECTION", """"NODE_TYPE" = '{0}'""".format(node_type)) arcpy.Statistics_analysis(lyrNodesToSegments, tblNodeSummary, [["NODE_TYPE", "COUNT"]], LineOID) arcpy.SelectLayerByAttribute_management(lyrNodesToSegments, "CLEAR_SELECTION") arcpy.AddField_management(lyrInputSegments, NODES, "TEXT") arcpy.MakeTableView_management(tblNodeSummary, viewNodeSummary) arcpy.AddJoin_management(lyrInputSegments, LineOID, viewNodeSummary, LineOID, "KEEP_COMMON") arcpy.CalculateField_management(lyrInputSegments, NODES, '"!COUNT_NODE_TYPE!"', "PYTHON_9.3") arcpy.RemoveJoin_management(lyrInputSegments) return
def main(inputFCStreamNetwork, inputDistance, strmIndex, segMethod, boolNode, boolMerge, outputFCSegments): """Segment a stream network into user-defined length intervals.""" # Get output workspace from output feature class out_wspace = os.path.dirname(outputFCSegments) # process terminates if input requirements not met gis_tools.checkReq(inputFCStreamNetwork) lyrStreamNetwork = gis_tools.newGISDataset("LAYER", "GNAT_SEGMENT_StreamNetwork") arcpy.MakeFeatureLayer_management(inputFCStreamNetwork, lyrStreamNetwork) strm_nodes = getNetworkNodes(lyrStreamNetwork) strm_dslv = r"in_memory\strm_dslv" arcpy.Dissolve_management(lyrStreamNetwork, strm_dslv, "BranchID", "", "SINGLE_PART", "DISSOLVE_LINES") # Split dissolved network at intersection nodes before segmentation, if option is chosen by user if boolNode == "true": strm_split_node = r"in_memory\strm_split_node" arcpy.SplitLineAtPoint_management(strm_dslv, strm_nodes, strm_split_node, "0.0001 Meters") else: strm_split_node = strm_dslv # Segment using method with remainder at inflow of each stream reach (i.e. Jesse's method) if segMethod == "Remaining segment at inflow (top) of stream branch": strm_seg = segOptionA(strm_split_node, inputDistance, out_wspace) # Segment using method with remainder at outflow, or divided remainder (i.e. Kelly's method) else: strm_seg = segOptionBC(strm_split_node, inputDistance, segMethod) if boolMerge == 'true': arcpy.AddMessage("Merging attributes and geometry from " + inputFCStreamNetwork + " with segmented stream network...") arcpy.Intersect_analysis([inputFCStreamNetwork, strm_seg], outputFCSegments) else: arcpy.CopyFeatures_management(strm_seg, outputFCSegments) # Finalize the process ClearInMemory.main() arcpy.AddMessage("GNAT: Segmentation process complete!") return
def snap_junction_points(from_line_lyr, to_line_lyr, search_distance): """ Shifts junction points (i.e. tributary confluences) in the 'From' network to same coordinates of junction points in the 'To' network, found within a user-specified search distance. :param from_line_lyr: polyline layer representing 'From' stream network :param to_line_lyr: polyline layer representing 'To' stream network :param search_distance: buffer distance around each 'To' junction point, in meters :return: line feature class """ tempWorkspace = "in_memory" arcpy.AddMessage("GNAT TLA: snapping junction points in 'From' network to 'To' network") snapped_from_line = gis_tools.newGISDataset(tempWorkspace, "snapped_from_line") arcpy.CopyFeatures_management(from_line_lyr, snapped_from_line) snap_line_lyr = gis_tools.newGISDataset("Layer", "snap_line_lyr") arcpy.MakeFeatureLayer_management(snapped_from_line, snap_line_lyr) list_field_objects = arcpy.ListFields(snap_line_lyr) list_from_fields = [f.name for f in list_field_objects if f.type != "OID" and f.type != "Geometry"] # Plot junction points for 'From' and 'To' stream networks from_junction_pnts = plot_junction_points(snap_line_lyr, "from") to_junction_pnts = plot_junction_points(to_line_lyr, "to") lyr_from_junc_pnts = gis_tools.newGISDataset("Layer", "lyr_from_junc_pnts") arcpy.MakeFeatureLayer_management(from_junction_pnts, lyr_from_junc_pnts) from_line_oidfield = arcpy.Describe(snap_line_lyr).OIDFieldName from_vrtx = gis_tools.newGISDataset(tempWorkspace, "from_vrtx") arcpy.FeatureVerticesToPoints_management(snap_line_lyr, from_vrtx, point_location="ALL") arcpy.AddXY_management(from_vrtx) from_vrtx_lyr = gis_tools.newGISDataset("Layer", "from_vrtx_lyr") arcpy.MakeFeatureLayer_management(from_vrtx, from_vrtx_lyr) arcpy.Near_analysis(from_vrtx_lyr, to_junction_pnts, search_distance, "LOCATION") arcpy.SelectLayerByLocation_management(from_vrtx_lyr, "INTERSECT", lyr_from_junc_pnts, "#", "NEW_SELECTION") update_xy_coord(from_vrtx_lyr) arcpy.MakeXYEventLayer_management(from_vrtx_lyr, "POINT_X", "POINT_Y", "xy_events", from_vrtx_lyr) xy_events_pnt = gis_tools.newGISDataset(tempWorkspace, "xy_events_pnt") arcpy.CopyFeatures_management("xy_events", xy_events_pnt) arcpy.MakeFeatureLayer_management(xy_events_pnt, "xy_events_lyr") xy_line = gis_tools.newGISDataset(tempWorkspace, "xy_line") arcpy.PointsToLine_management("xy_events_lyr", xy_line, "ORIG_FID") arcpy.JoinField_management(xy_line, "ORIG_FID", snap_line_lyr, from_line_oidfield, list_from_fields) arcpy.DeleteFeatures_management(snap_line_lyr) arcpy.Append_management(xy_line, snap_line_lyr, "NO_TEST") return snap_line_lyr
def segOptionBC(fcDissolvedStreamBranch, inputDistance, segMethod, fcTempStreamNetwork=r"in_memory\temp_network", outSegmentIDField="SegmentID", scratchWorkspace=r"in_memory"): """Segment the input stream network feature class using one of two methods: 1. Remainder at the outflow of each stream reach 2. Remainder is divided amongst each stream segment """ gis_tools.resetData(fcTempStreamNetwork) listPoints = [] if segMethod == "Remaining segment at outflow (bottom) of stream branch": arcpy.AddMessage( "Segmenting using the remainder at stream branch outflow method..." ) else: arcpy.AddMessage( "Segmenting using the segment remainder division method...") with arcpy.da.SearchCursor(fcDissolvedStreamBranch, ["SHAPE@", "SHAPE@LENGTH"]) as scBranches: for row in scBranches: gLine = row[0] dblPointPosition = 0 if segMethod == "Remaining segment at outflow (bottom) of stream branch": while dblPointPosition < row[1]: listPoints.append( gLine.positionAlongLine(dblPointPosition)) dblPointPosition += Decimal(inputDistance) else: intNumberOfPositions = int( Decimal(row[1]) / Decimal(inputDistance)) for intPosition in range(intNumberOfPositions): dblProportionalPosition = float( intPosition) / intNumberOfPositions listPoints.append( gLine.positionAlongLine(dblProportionalPosition, True)) fcSplitPoints = gis_tools.newGISDataset(scratchWorkspace, "GNAT_SEG_SplitPoints") arcpy.CreateFeatureclass_management( scratchWorkspace, "GNAT_SEG_SplitPoints", "POINT", spatial_reference=fcDissolvedStreamBranch) with arcpy.da.InsertCursor(fcSplitPoints, ["SHAPE@"]) as icSplitPoints: for point in listPoints: icSplitPoints.insertRow([point]) arcpy.SplitLineAtPoint_management(fcDissolvedStreamBranch, fcSplitPoints, fcTempStreamNetwork, "1 Meters") gis_tools.addUniqueIDField(fcTempStreamNetwork, outSegmentIDField) # Remove unnecessary fields fieldObjects = arcpy.ListFields(fcTempStreamNetwork) oidField = arcpy.Describe(fcTempStreamNetwork).OIDFieldName shapeField = arcpy.Describe(fcTempStreamNetwork).shapeFieldName lengthField = arcpy.Describe(fcTempStreamNetwork).lengthFieldName keepFields = [oidField, shapeField, lengthField, outSegmentIDField] for field in fieldObjects: if field.name not in keepFields: arcpy.DeleteField_management(fcTempStreamNetwork, [field.name]) # Clean up del fcSplitPoints return fcTempStreamNetwork
def main(fcFromLine, fcToLine, fcOutputLineNetwork, searchDistance, tempWorkspace): reload(DividePolygonBySegment) # Environment settings arcpy.env.overwriteOutput = True arcpy.env.outputMFlag = "Disabled" arcpy.env.outputZFlag = "Disabled" arcpy.env.scratchWorkspace = tempWorkspace arcpy.AddMessage("GNAT TLA: starting transfer process...") gis_tools.resetData(fcOutputLineNetwork) fcFromLineTemp = gis_tools.newGISDataset(tempWorkspace, "GNAT_TLA_FromLineTemp") fcToLineTemp = gis_tools.newGISDataset(tempWorkspace, "GNAT_TLA_ToLineTemp") arcpy.MakeFeatureLayer_management(fcFromLine, "lyrFromLine") arcpy.MakeFeatureLayer_management(fcToLine, "lyrToLine") arcpy.CopyFeatures_management("lyrFromLine", fcFromLineTemp) arcpy.CopyFeatures_management("lyrToLine", fcToLineTemp) # Add a unique ID for the "From" line feature class from_oid = arcpy.Describe(fcFromLineTemp).OIDFieldName arcpy.AddField_management(fcFromLineTemp, "FromID", "LONG") arcpy.CalculateField_management(fcFromLineTemp, "FromID", "!{0}!".format(from_oid), "PYTHON_9.3") # Snap "From" line network to "To" line network lyrFromLineTemp = gis_tools.newGISDataset("Layer", "lyrFromLineTemp") lyrToLineTemp = gis_tools.newGISDataset("Layer", "lyrToLineTemp") arcpy.MakeFeatureLayer_management(fcFromLineTemp, lyrFromLineTemp) arcpy.MakeFeatureLayer_management(fcToLineTemp, lyrToLineTemp) lyrSnapFromLine = snap_junction_points(lyrFromLineTemp, lyrToLineTemp, searchDistance) # Make bounding polygon for "From" line feature class # arcpy.AddMessage("GNAT TLA: Create buffer polygon around 'From' network") # fcFromLineBuffer = gis_tools.newGISDataset(tempWorkspace, "GNAT_TLA_FromLineBuffer") # arcpy.Buffer_analysis(lyrSnapFromLine, fcFromLineBuffer, "{0} Meters".format(searchDistance * 3), "FULL", "ROUND", "ALL") # fcFromLineBufDslv = gis_tools.newGISDataset(tempWorkspace, "GNAT_TLA_FromLineBUfDslv") # arcpy.AddMessage("GNAT TLA: Dissolve buffer") # arcpy.Dissolve_management(fcFromLineBuffer, fcFromLineBufDslv) merge_lines = gis_tools.newGISDataset(tempWorkspace, "GNAT_TLA_merged_lines") arcpy.Merge_management([lyrSnapFromLine, lyrToLineTemp], merge_lines) fcFromLineBuffer = gis_tools.newGISDataset(tempWorkspace, "GNAT_TLA_FromLineBUfDslv") external_edge_buffer(merge_lines, 10, fcFromLineBuffer) # Select features from "To" line feature class that are inside "From" line buffer arcpy.AddMessage("GNAT TLA: Select 'To' line features inside 'From' buffer") lyrFromLineBuffer = gis_tools.newGISDataset("Layer", "lyrFromLineBuffer") arcpy.MakeFeatureLayer_management(fcFromLineBuffer, lyrFromLineBuffer) lyrToLine = gis_tools.newGISDataset("Layer", "lyrToLine") arcpy.MakeFeatureLayer_management(fcToLine, lyrToLine) arcpy.SelectLayerByLocation_management(lyrToLine, "WITHIN", lyrFromLineBuffer, "#", "NEW_SELECTION") fcToLineWithinFromBuffer = arcpy.FeatureClassToFeatureClass_conversion(lyrToLine, tempWorkspace, "GNAT_TLA_ToLineWithinFromBuffer") # Select features from "To" line feature class that are outside "From" line buffer arcpy.SelectLayerByAttribute_management(lyrToLine, "SWITCH_SELECTION") fcToLineOutsideFromBuffer = arcpy.FeatureClassToFeatureClass_conversion(lyrToLine, tempWorkspace, "GNAT_TLA_ToLineOutsideFromBuffer") # Segment "From" line buffer polygon arcpy.AddMessage("GNAT TLA: Segmenting 'From' line buffer polygon") fcSegmentedBoundingPolygons = gis_tools.newGISDataset(tempWorkspace, "GNAT_TLA_SegmentedBoundingPolygons") DividePolygonBySegment.main(lyrSnapFromLine, fcFromLineBuffer, fcSegmentedBoundingPolygons, 10.0, 150.0, tempWorkspace) # Split points of "To" line at intersection of polygon segments arcpy.AddMessage("GNAT TLA: Split 'To' line features") fcIntersectSplitPoints = gis_tools.newGISDataset(tempWorkspace, "GNAT_TLA_IntersectSplitPoints") arcpy.Intersect_analysis([fcToLineWithinFromBuffer, fcSegmentedBoundingPolygons], fcIntersectSplitPoints, output_type="POINT") fcSplitLines = gis_tools.newGISDataset(tempWorkspace, "GNAT_TLA_SplitLines") arcpy.SplitLineAtPoint_management(fcToLineWithinFromBuffer, fcIntersectSplitPoints, fcSplitLines, "0.1 METERS") # Spatial join lines based on a common field, as transferred by segmented polygon arcpy.AddMessage("GNAT TLA: Joining polygon segments") arcpy.SpatialJoin_analysis(fcSplitLines, fcSegmentedBoundingPolygons, fcOutputLineNetwork, "JOIN_ONE_TO_ONE", "KEEP_ALL", match_option="WITHIN") arcpy.JoinField_management(fcOutputLineNetwork, "FromID", fcFromLineTemp, "FromID") # Append the "To" lines that were outside of the "From" line buffer, which will have NULL or zero values arcpy.env.extent = fcToLine # changed earlier in the workflow in DividePolygonBySegment module arcpy.Append_management([fcToLineOutsideFromBuffer], fcOutputLineNetwork, "NO_TEST") # Change values of "From" features to -99999 if no "To" features to transfer to. arcpy.MakeFeatureLayer_management(fcOutputLineNetwork, "lyrOutputLineNetwork") arcpy.SelectLayerByLocation_management("lyrOutputLineNetwork", "ARE_IDENTICAL_TO", fcToLineOutsideFromBuffer, "#", "NEW_SELECTION") to_fields = [f.name for f in arcpy.ListFields(fcToLine)] empty_attributes("lyrOutputLineNetwork", to_fields) arcpy.SelectLayerByAttribute_management("lyrOutputLineNetwork", "CLEAR_SELECTION") arcpy.AddMessage("GNAT TLA: Tool complete") return
def main(fcInputCenterline, fcInputPolygon, fcSegmentedPolygons, dblPointDensity=10.0, dblJunctionBuffer=100.00, workspaceTemp="in_memory"): # Manage Environments env_extent = arcpy.env.extent env_outputmflag = arcpy.env.outputMFlag env_outputzflag = arcpy.env.outputZFlag arcpy.env.outputMFlag = "Disabled" arcpy.env.outputZFlag = "Disabled" arcpy.env.extent = fcInputPolygon ## Set full extent to build Thiessan polygons over entire line network. # Copy centerline to temporary workspace fcCenterline = gis_tools.newGISDataset(workspaceTemp, "GNAT_DPS_Centerline") arcpy.CopyFeatures_management(fcInputCenterline, fcCenterline) if "FromID" not in [ field.name for field in arcpy.ListFields(fcCenterline) ]: arcpy.AddField_management(fcCenterline, "FromID", "LONG") arcpy.CalculateField_management( fcCenterline, "FromID", "!{}!".format(arcpy.Describe(fcCenterline).OIDFieldName), "PYTHON_9.3") # Build Thiessan polygons arcpy.AddMessage("GNAT DPS: Building Thiessan polygons") arcpy.Densify_edit(fcCenterline, "DISTANCE", "{} METERS".format(dblPointDensity)) fcTribJunctionPoints = gis_tools.newGISDataset( workspaceTemp, "GNAT_DPS_TribJunctionPoints") arcpy.Intersect_analysis([fcCenterline], fcTribJunctionPoints, output_type="POINT") fcThiessanPoints = gis_tools.newGISDataset(workspaceTemp, "GNAT_DPS_ThiessanPoints") arcpy.FeatureVerticesToPoints_management(fcCenterline, fcThiessanPoints, "ALL") lyrThiessanPoints = gis_tools.newGISDataset("Layer", "lyrThiessanPoints") arcpy.MakeFeatureLayer_management(fcThiessanPoints, lyrThiessanPoints) arcpy.SelectLayerByLocation_management( lyrThiessanPoints, "INTERSECT", fcTribJunctionPoints, "{} METERS".format(dblJunctionBuffer)) fcThiessanPoly = gis_tools.newGISDataset(workspaceTemp, "GNAT_DPS_ThiessanPoly") # arcpy.CreateThiessenPolygons_analysis(lyrThiessanPoints,fcThiessanPoly,"ONLY_FID") arcpy.CreateThiessenPolygons_analysis(lyrThiessanPoints, fcThiessanPoly, "ALL") # Clean polygons # lyrInputPolygon = gis_tools.newGISDataset("Layer", "lyrInputPolygon") # arcpy.MakeFeatureLayer_management(fcInputPolygon, lyrInputPolygon) arcpy.RepairGeometry_management(fcInputPolygon, "KEEP_NULL") fcThiessanPolyClip = gis_tools.newGISDataset(workspaceTemp, "GNAT_DPS_TheissanPolyClip") arcpy.Clip_analysis(fcThiessanPoly, fcInputPolygon, fcThiessanPolyClip) # Split the junction Thiessan polygons arcpy.AddMessage("GNAT DPS: Split junction Thiessan polygons") lyrTribThiessanPolys = gis_tools.newGISDataset("Layer", "lyrTribThiessanPolys") arcpy.MakeFeatureLayer_management(fcThiessanPolyClip, lyrTribThiessanPolys) arcpy.SelectLayerByLocation_management(lyrTribThiessanPolys, "INTERSECT", fcTribJunctionPoints) fcSplitPoints = gis_tools.newGISDataset(workspaceTemp, "GNAT_DPS_SplitPoints") arcpy.Intersect_analysis([lyrTribThiessanPolys, fcCenterline], fcSplitPoints, output_type="POINT") arcpy.AddMessage("GNAT DPS: Moving starting vertices of junction polygons") geometry_functions.changeStartingVertex(fcTribJunctionPoints, lyrTribThiessanPolys) arcpy.AddMessage("GNAT DPS: Vertices moved") fcThiessanTribPolyEdges = gis_tools.newGISDataset( workspaceTemp, "GNAT_DPS_ThiessanTribPolyEdges") arcpy.FeatureToLine_management(lyrTribThiessanPolys, fcThiessanTribPolyEdges) fcSplitLines = gis_tools.newGISDataset(workspaceTemp, "GNAT_DPS_SplitLines") arcpy.SplitLineAtPoint_management(fcThiessanTribPolyEdges, fcSplitPoints, fcSplitLines, "0.1 METERS") fcMidPoints = gis_tools.newGISDataset(workspaceTemp, "GNAT_DPS_MidPoints") arcpy.FeatureVerticesToPoints_management(fcSplitLines, fcMidPoints, "MID") arcpy.Near_analysis(fcMidPoints, fcTribJunctionPoints, location="LOCATION") arcpy.AddXY_management(fcMidPoints) fcTribToMidLines = gis_tools.newGISDataset(workspaceTemp, "GNAT_DPS_TribToMidLines") arcpy.XYToLine_management(fcMidPoints, fcTribToMidLines, "POINT_X", "POINT_Y", "NEAR_X", "NEAR_Y") ### Select polygons by centerline ### arcpy.AddMessage("GNAT DPS: Select polygons by centerline") fcThiessanEdges = gis_tools.newGISDataset(workspaceTemp, "GNAT_DPS_ThiessanEdges") arcpy.FeatureToLine_management(fcThiessanPolyClip, fcThiessanEdges) fcAllEdges = gis_tools.newGISDataset(workspaceTemp, "GNAT_DPS_AllEdges") arcpy.Merge_management([fcTribToMidLines, fcThiessanEdges, fcCenterline], fcAllEdges) # include fcCenterline if needed fcAllEdgesPolygons = gis_tools.newGISDataset(workspaceTemp, "GNAT_DPS_AllEdgesPolygons") arcpy.FeatureToPolygon_management(fcAllEdges, fcAllEdgesPolygons) fcAllEdgesPolygonsClip = gis_tools.newGISDataset( workspaceTemp, "GNAT_DPS_AllEdgesPolygonsClip") arcpy.Clip_analysis(fcAllEdgesPolygons, fcInputPolygon, fcAllEdgesPolygonsClip) fcPolygonsJoinCenterline = gis_tools.newGISDataset( workspaceTemp, "GNAT_DPS_PolygonsJoinCenterline") arcpy.SpatialJoin_analysis(fcAllEdgesPolygonsClip, fcCenterline, fcPolygonsJoinCenterline, "JOIN_ONE_TO_MANY", "KEEP_ALL", match_option="SHARE_A_LINE_SEGMENT_WITH") fcPolygonsDissolved = gis_tools.newGISDataset( workspaceTemp, "GNAT_DPS_PolygonsDissolved") arcpy.Dissolve_management(fcPolygonsJoinCenterline, fcPolygonsDissolved, "FromID", multi_part="SINGLE_PART") lyrPolygonsDissolved = gis_tools.newGISDataset("Layer", "lyrPolygonsDissolved") arcpy.MakeFeatureLayer_management(fcPolygonsDissolved, lyrPolygonsDissolved) arcpy.SelectLayerByAttribute_management(lyrPolygonsDissolved, "NEW_SELECTION", """ "FromID" IS NULL """) arcpy.Eliminate_management(lyrPolygonsDissolved, fcSegmentedPolygons, "LENGTH") arcpy.AddMessage("GNAT DPS: Tool complete") # Reset env arcpy.env.extent = env_extent arcpy.env.outputMFlag = env_outputmflag arcpy.env.outputZFlag = env_outputzflag return
def main(inputFCPolylineNetwork, inputDownstreamID, outputFCPolylineStreamOrder, outputFCIntersectPoints, scratchWorkspace= "in_memory"): # Set processing environments arcpy.env.outputMflag = "Disabled" arcpy.env.outputZflag = "Disabled" # Initialize stream order intCurrentOrder = 1 if arcpy.Exists(outputFCPolylineStreamOrder): arcpy.Delete_management(outputFCPolylineStreamOrder) if arcpy.Exists(outputFCIntersectPoints): arcpy.Delete_management(outputFCIntersectPoints) # Preprocess network fcNetworkDissolved = gis_tools.newGISDataset(scratchWorkspace, "GNAT_SO_NetworkDissolved") arcpy.Dissolve_management(inputFCPolylineNetwork, fcNetworkDissolved, multi_part="SINGLE_PART", unsplit_lines="DISSOLVE_LINES") fcNetworkIntersectPoints = gis_tools.newGISDataset(scratchWorkspace, "GNAT_SO_NetworkIntersectPoints") arcpy.Intersect_analysis(fcNetworkDissolved, fcNetworkIntersectPoints, "ALL", output_type="POINT") arcpy.AddXY_management(fcNetworkIntersectPoints) fcNetworkNodes = gis_tools.newGISDataset(scratchWorkspace, "GNAT_SO_NetworkNodes") arcpy.Dissolve_management(fcNetworkIntersectPoints,fcNetworkNodes, ["POINT_X", "POINT_Y"], "#", "SINGLE_PART") listFields = arcpy.ListFields(fcNetworkDissolved,"strm_order") if len(listFields) == 0: arcpy.AddField_management(fcNetworkDissolved,"strm_order","LONG") arcpy.CalculateField_management(fcNetworkDissolved,"strm_order",0,"PYTHON") lyrA = gis_tools.newGISDataset("LAYER", "lyrA") lyrB = gis_tools.newGISDataset("LAYER", "lyrB") lyrCalculate = gis_tools.newGISDataset("LAYER", "lyrCalculate") arcpy.MakeFeatureLayer_management(fcNetworkDissolved,lyrA) arcpy.MakeFeatureLayer_management(fcNetworkDissolved,lyrB) arcpy.MakeFeatureLayer_management(fcNetworkDissolved,lyrCalculate) # Determine order 1 streams as initial condition fcDangles = gis_tools.newGISDataset(scratchWorkspace, "GNAT_SO_Dangles") arcpy.FeatureVerticesToPoints_management(inputFCPolylineNetwork,fcDangles,"DANGLE") lyrDangles = gis_tools.newGISDataset("LAYER", "lyrDangles") where = '"ORIG_FID" <> ' + str(inputDownstreamID) arcpy.MakeFeatureLayer_management(fcDangles,lyrDangles,where) arcpy.SelectLayerByLocation_management(lyrA,"INTERSECT",lyrDangles,selection_type="NEW_SELECTION") arcpy.CalculateField_management(lyrA,"strm_order",intCurrentOrder,"PYTHON") fcStreamOrderTransistionPoints = gis_tools.newGISDataset(scratchWorkspace, "GNAT_SO_StreamOrderTransistionPoints") # Iterate through stream orders arcpy.AddMessage("Evaluating Stream Order: " + str(intCurrentOrder)) arcpy.SelectLayerByAttribute_management(lyrCalculate,"NEW_SELECTION",'"strm_order" = 0') intFeaturesRemaining = int(arcpy.GetCount_management(lyrCalculate).getOutput(0)) intIteration = 1 listPairsRetired = [] while intFeaturesRemaining <> 0: arcpy.AddMessage(" Iteration: " + str(intIteration) + " |Features Remaining: " + str(intFeaturesRemaining)) listPairs = newListPairs(intCurrentOrder) for pair in listPairs: if pair not in listPairsRetired: fcIntersectPoints = gis_tools.newGISDataset(scratchWorkspace, "GNAT_SO_IntersectPoints_" + str(intIteration) + "_Pair_" + str(pair[0]) + "_" + str(pair[1]) + "_Order_" + str(intCurrentOrder)) lyrIntersectPoints = gis_tools.newGISDataset("LAYER", "lyrIntersectPoints" + str(intIteration) + str(pair[0]) + str(pair[1])) if pair[0] == pair[1]: arcpy.SelectLayerByAttribute_management(lyrA,"NEW_SELECTION",'"strm_order" = ' + str(pair[0])) arcpy.Intersect_analysis(lyrA,fcIntersectPoints,output_type="POINT") arcpy.MakeFeatureLayer_management(fcIntersectPoints,lyrIntersectPoints) arcpy.SelectLayerByAttribute_management(lyrCalculate,"NEW_SELECTION",'"strm_order" = 0') arcpy.SelectLayerByLocation_management(lyrIntersectPoints,"INTERSECT",lyrCalculate,selection_type="NEW_SELECTION") if arcpy.Exists(fcStreamOrderTransistionPoints): arcpy.Append_management(lyrIntersectPoints,fcStreamOrderTransistionPoints) else: arcpy.CopyFeatures_management(lyrIntersectPoints,fcStreamOrderTransistionPoints) arcpy.SelectLayerByLocation_management(lyrCalculate,"INTERSECT",fcIntersectPoints,selection_type="SUBSET_SELECTION") if int(arcpy.GetCount_management(lyrCalculate).getOutput(0)) > 0 and pair[0] == intCurrentOrder: intCurrentOrder = intCurrentOrder + 1 arcpy.AddMessage("New Stream Order: " + str(intCurrentOrder)) arcpy.CalculateField_management(lyrCalculate,"strm_order",int(intCurrentOrder),"PYTHON") else: arcpy.SelectLayerByAttribute_management(lyrA,"NEW_SELECTION",'"strm_order" = ' + str(pair[0])) arcpy.SelectLayerByAttribute_management(lyrB,"NEW_SELECTION",'"strm_order" = ' + str(pair[1])) arcpy.Intersect_analysis([lyrA,lyrB],fcIntersectPoints,output_type="POINT") arcpy.SelectLayerByAttribute_management(lyrCalculate,"NEW_SELECTION",'"strm_order" = 0') arcpy.SelectLayerByLocation_management(lyrCalculate,"INTERSECT",fcIntersectPoints,selection_type="SUBSET_SELECTION") arcpy.CalculateField_management(lyrCalculate,"strm_order",int(max(pair)),"PYTHON") # Set up next round arcpy.SelectLayerByAttribute_management(lyrCalculate,"NEW_SELECTION",'"strm_order" = 0') intFeaturesCurrent = int(arcpy.GetCount_management(lyrCalculate).getOutput(0)) if intFeaturesRemaining == intFeaturesCurrent: arcpy.AddError("The number of features remaining (" + str(intFeaturesCurrent) + " is the same as the last iteration.") break else: intFeaturesRemaining = intFeaturesCurrent intIteration = intIteration + 1 # Outputs arcpy.Intersect_analysis([fcNetworkDissolved,inputFCPolylineNetwork],outputFCPolylineStreamOrder) arcpy.DeleteIdentical_management(fcStreamOrderTransistionPoints, "Shape") arcpy.CopyFeatures_management(fcNetworkNodes, outputFCIntersectPoints) # arcpy.CopyFeatures_management(fcNetworkIntersectPoints, outputFCIntersectPoints) ClearInMemory.main() return outputFCPolylineStreamOrder, outputFCIntersectPoints
def main(fcInput, fieldName="Sin", workspaceTmp="in_memory"): # Get list of fields from input feature class keepFields = [keepField.name for keepField in arcpy.ListFields(fcInput)] keepFields.append(fieldName) keepFields.append("InputID") # Prepare inputs fieldInputID = gis_tools.resetField(fcInput, "InputID", "DOUBLE") arcpy.CalculateField_management( fcInput, fieldInputID, "!" + arcpy.Describe(fcInput).OIDFieldName + "!", "PYTHON_9.3") fcInputTmp = gis_tools.newGISDataset(workspaceTmp, "fcIn") arcpy.CopyFeatures_management(fcInput, fcInputTmp) fieldSinuosity = gis_tools.resetField(fcInputTmp, fieldName, "DOUBLE") fieldSegmentLength = gis_tools.resetField(fcInputTmp, "SgLen", "DOUBLE") # Find length of segment arcpy.CalculateField_management(fcInputTmp, fieldSegmentLength, "!shape.length!", "PYTHON_9.3") # Find straight line distance fcSegmentEnds = gis_tools.newGISDataset(workspaceTmp, "SgEnd") arcpy.FeatureVerticesToPoints_management(fcInputTmp, fcSegmentEnds, "BOTH_ENDS") fcSegmentDistances = gis_tools.newGISDataset(workspaceTmp, "SgDst") arcpy.PointsToLine_management(fcSegmentEnds, fcSegmentDistances, fieldInputID) fieldDistance = gis_tools.resetField(fcSegmentDistances, "SgDst", "DOUBLE") arcpy.CalculateField_management(fcSegmentDistances, fieldDistance, "!shape.length!", "PYTHON_9.3") # Join straight line distance feature class lyrInputTmp = gis_tools.newGISDataset("Layer", "lyrInputTmp") arcpy.MakeFeatureLayer_management(fcInputTmp, lyrInputTmp) fieldTmpID = gis_tools.resetField(fcSegmentDistances, "TmpID", "DOUBLE") arcpy.CalculateField_management(fcSegmentDistances, fieldTmpID, "!InputID!", "PYTHON_9.3") arcpy.AddJoin_management(lyrInputTmp, fieldInputID, fcSegmentDistances, fieldTmpID) # Calculate sinuosity codeblock = """def calculateSinuosity(length,distance): if distance == 0: return -9999 else: return length/distance """ arcpy.CalculateField_management( lyrInputTmp, fieldSinuosity, "calculateSinuosity(!{}!, !{}!".format(fieldSegmentLength, fieldDistance), "PYTHON_9.3", codeblock) # Write Temporary polyline feature class to disk fcOutput = gis_tools.newGISDataset(workspaceTmp, "outputFCSinuosityChannel") arcpy.CopyFeatures_management(lyrInputTmp, fcOutput) dropFields = [dropField.name for dropField in arcpy.ListFields(fcOutput)] arcpy.MakeTableView_management(fcOutput, "fcOutputView") for dropField in dropFields: if dropField not in keepFields: arcpy.DeleteField_management("fcOutputView", dropField) # join final sinuosity output back to input stream network arcpy.MakeFeatureLayer_management(fcInput, "lyrInput") fcInputOID = arcpy.Describe("lyrInput").OIDFieldName arcpy.JoinField_management("lyrInput", fcInputOID, "fcOutputView", "InputID", fieldName) return
def main(fcLineNetwork, fieldStreamRouteID, seed_distance, window_sizes, stat_fields, fcOutputWindows, fcOutputSeedPoints, tempWorkspace=arcpy.env.scratchWorkspace): """Perform a Moving Window Analysis on a Line Network.""" # Prepare Inputs arcpy.AddMessage("Preparing Moving Window Analysis") fc_line_dissolve = gis_tools.newGISDataset(tempWorkspace, "GNAT_MWA_LineNetworkDissolved") arcpy.Dissolve_management(fcLineNetwork, fc_line_dissolve, fieldStreamRouteID, multi_part=False, unsplit_lines=True) arcpy.FlipLine_edit(fc_line_dissolve) listSeeds = [] listgWindows = [] intSeedID = 0 # Moving Window Generation arcpy.AddMessage("Starting Window Generation") iRoutes = int(arcpy.GetCount_management(fc_line_dissolve).getOutput(0)) arcpy.SetProgressor("step", "Processing Each Route", 0, iRoutes, 1) iRoute = 0 with arcpy.da.SearchCursor(fc_line_dissolve, ["SHAPE@", fieldStreamRouteID, "SHAPE@LENGTH"]) as scLines: for fLine in scLines: # Loop Through Routes arcpy.SetProgressorLabel("Route: {} Seed Point: {}".format(iRoute, intSeedID)) arcpy.SetProgressorPosition(iRoute) dblSeedPointPosition = float(max(window_sizes)) / 2 # Start Seeds at position of largest window while dblSeedPointPosition + float(max(window_sizes)) / 2 < fLine[2]: arcpy.SetProgressorLabel("Route: {} Seed Point: {}".format(iRoute, intSeedID)) gSeedPointPosition = fLine[0].positionAlongLine(dblSeedPointPosition) listSeeds.append([scLines[1], intSeedID, gSeedPointPosition, dblSeedPointPosition]) for window_size in window_sizes: dblWindowSize = float(window_size) dblLengthStart = dblSeedPointPosition - dblWindowSize / 2 dblLengthEnd = dblSeedPointPosition + dblWindowSize / 2 listgWindows.append([scLines[1], intSeedID, dblWindowSize, fLine[0].segmentAlongLine(dblLengthStart, dblLengthEnd)]) dblSeedPointPosition = dblSeedPointPosition + float(seed_distance) intSeedID = intSeedID + 1 iRoute = iRoute + 1 arcpy.AddMessage("Compiling Moving Windows") fcSeedPoints = gis_tools.newGISDataset(tempWorkspace, "GNAT_MWA_SeedPoints") fcWindowLines = gis_tools.newGISDataset(tempWorkspace, "GNAT_MWA_WindowLines") arcpy.CreateFeatureclass_management(tempWorkspace, "GNAT_MWA_SeedPoints", "POINT", spatial_reference=fcLineNetwork) arcpy.CreateFeatureclass_management(tempWorkspace, "GNAT_MWA_WindowLines", "POLYLINE", spatial_reference=fcLineNetwork) gis_tools.resetField(fcSeedPoints, "RouteID", "TEXT") gis_tools.resetField(fcSeedPoints, "SeedID", "LONG") gis_tools.resetField(fcSeedPoints, "SeedDist", "DOUBLE") gis_tools.resetField(fcWindowLines, "RouteID", "TEXT") gis_tools.resetField(fcWindowLines, "SeedID", "LONG") gis_tools.resetField(fcWindowLines, "Seg", "DOUBLE") with arcpy.da.InsertCursor(fcSeedPoints, ["RouteID", "SeedID", "SHAPE@XY", "SeedDist"]) as icSeedPoints: for row in listSeeds: icSeedPoints.insertRow(row) with arcpy.da.InsertCursor(fcWindowLines, ["RouteID", "SeedID", "Seg", "SHAPE@"]) as icWindowLines: for row in listgWindows: icWindowLines.insertRow(row) # Intersecting Network Attributes with Moving Windows arcpy.AddMessage("Intersecting Network Attributes with Moving Windows") fcIntersected = gis_tools.newGISDataset(tempWorkspace, "GNAT_MWA_IntersectWindowAttributes") arcpy.Intersect_analysis([fcWindowLines, fcLineNetwork], fcIntersected, "ALL", output_type="LINE") # Use Python Dictionaries for Summary Stats # Reference: https://community.esri.com/blogs/richard_fairhurst/2014/11/08/turbo-charging-data-manipulation-with-python-cursors-and-dictionaries arcpy.AddMessage("Loading Moving Window Attributes") valueDict = {} with arcpy.da.SearchCursor(fcIntersected, ["SeedID", "Seg", "SHAPE@LENGTH"] + stat_fields) as searchRows: for searchRow in searchRows: keyValue = str(searchRow[0]) segValue = str(searchRow[1]) if not keyValue in valueDict: valueDict[keyValue] = {segValue: [(searchRow[2:])]} else: if segValue not in valueDict[keyValue]: valueDict[keyValue][segValue] = [(searchRow[2:])] else: valueDict[keyValue][segValue].append((searchRow[2:])) addfields = ["w{}{}{}".format(str(ws)[:4].rstrip("."), stat, field)[:10] for ws in window_sizes for field in stat_fields for stat in ["N", "Av", "Sm", "Rn", "Mn", "Mx", "Sd", "WA"]] for field in addfields: gis_tools.resetField(fcSeedPoints, field, "DOUBLE") arcpy.AddMessage("Calculating Attribute Statistics") with arcpy.da.UpdateCursor(fcSeedPoints, ["SeedID"] + addfields) as ucSeedPoints: for row in ucSeedPoints: new_row = [row[0]] for ws in window_sizes: seglen = [segment[0] for segment in valueDict[str(row[0])][str(ws)]] for i in range(1, len(stat_fields) + 1): vals = [float(segment[i]) for segment in valueDict[str(row[0])][str(ws)]] count_vals = float(len(vals)) sum_vals = sum(vals) ave_vals = sum_vals / float(count_vals) max_vals = max(vals) min_vals = min(vals) range_vals = max_vals - min_vals sd_vals = sqrt(sum([abs(float(x) - float(ave_vals))**2 for x in vals]) / float(count_vals)) wave_vals = sum([val / slen for val, slen in zip(vals, seglen)])/ float(count_vals) new_row.extend([count_vals, ave_vals, sum_vals, range_vals, min_vals, max_vals, sd_vals, wave_vals]) ucSeedPoints.updateRow(new_row) # Manage Outputs arcpy.AddMessage("Saving Outputs") gis_tools.resetData(fcOutputSeedPoints) arcpy.CopyFeatures_management(fcSeedPoints, fcOutputSeedPoints) gis_tools.resetData(fcOutputWindows) arcpy.CopyFeatures_management(fcWindowLines, fcOutputWindows) return 0
def main(source_segments, vb_centerline, temp_workspace, xy_dist=150, filterfield="_vb_", field_segid="SegmentID", out_shapefile=None): """ Calculate channel, planform and valley bottom sinuosity""" if out_shapefile: arcpy.CopyFeatures_management(source_segments, out_shapefile) source_segments = out_shapefile out_segments = gis_tools.newGISDataset("LAYER", "OutputSegments") where = '"{}" = 1'.format(filterfield) if filterfield in arcpy.ListFields( source_segments) else None # TODO Test arcpy.MakeFeatureLayer_management(source_segments, out_segments, where_clause=where) # Generate Split Points arcpy.AddMessage("Generating Near Points for Split") endpoints = gis_tools.newGISDataset(temp_workspace, "Endpoints") arcpy.FeatureVerticesToPoints_management(out_segments, endpoints, "BOTH_ENDS") arcpy.AddXY_management(endpoints) arcpy.Near_analysis(endpoints, vb_centerline, location=True, angle=True, method="PLANAR", search_radius=xy_dist) sr = arcpy.Describe(endpoints).spatialReference ddict_vb_points = defaultdict(list) with arcpy.da.SearchCursor(endpoints, ["NEAR_X", "NEAR_Y", field_segid]) as sc: splitpoints = [ arcpy.PointGeometry(arcpy.Point(row[0], row[1]), sr) for row in sc if not row[0] == -1 ] sc.reset() for row in sc: if row[0] != -1: ddict_vb_points[row[2]].append(arcpy.Point(row[0], row[1])) # Generate Valley Bottom distances arcpy.AddMessage("Generating VB Centerline Segment Distances") dict_vb_lines = {} for segid, lpts in ddict_vb_points.iteritems(): line = arcpy.Polyline(arcpy.Array(lpts)) dict_vb_lines[segid] = line vb_lines = gis_tools.newGISDataset("in_memory", "VBDIST") arcpy.CopyFeatures_management( [line for line in dict_vb_lines.itervalues()], vb_lines) split_lines = gis_tools.newGISDataset(temp_workspace, "SplitVB_Centerline") arcpy.SplitLineAtPoint_management(vb_centerline, splitpoints, split_lines, search_radius=0.1) # Selection Polygons from VB_Dist arcpy.AddMessage("Generating VB Selection Polygons") vb_polys = gis_tools.newGISDataset(temp_workspace, "VB_Polygons") arcpy.FeatureToPolygon_management( [vb_centerline, vb_lines], vb_polys) # TODO test use vb_centerlines for faster procesing? dict_vb_dist = {} lyr_selection_polygons = gis_tools.newGISDataset("LAYER", "SelectionPolygons") arcpy.MakeFeatureLayer_management(vb_polys, lyr_selection_polygons) lyr_splitlines = gis_tools.newGISDataset("LAYER", "SplitLines") arcpy.MakeFeatureLayer_management(split_lines, lyr_splitlines) for segid, vbline in dict_vb_lines.iteritems(): arcpy.SelectLayerByLocation_management(lyr_selection_polygons, "SHARE_A_LINE_SEGMENT_WITH", vbline) arcpy.SelectLayerByLocation_management(lyr_splitlines, "SHARE_A_LINE_SEGMENT_WITH", lyr_selection_polygons) with arcpy.da.SearchCursor(lyr_splitlines, ["SHAPE@LENGTH"]) as scSplitLines: dict_vb_dist[segid] = sum([line[0] for line in scSplitLines]) # Find Lengths and Distances for Segments arcpy.AddMessage("Adding Channel Lengths To Segments") field_chanlength = gis_tools.resetField(out_segments, "Chan_Len", "DOUBLE") arcpy.CalculateField_management(out_segments, field_chanlength, "!shape.length!", "PYTHON_9.3") # Channel Segment Distances arcpy.AddMessage( "Adding Channel Distances and VB Lengths and Distances to Segments") field_vblength = gis_tools.resetField(out_segments, "VB_Len", "DOUBLE") field_chandist = gis_tools.resetField(out_segments, "Chan_Dist", "DOUBLE") field_vbdist = gis_tools.resetField(out_segments, "VB_Dist", "DOUBLE") total_segments = int(arcpy.GetCount_management(out_segments).getOutput(0)) percents = [(total_segments / 10) * value for value in range(1, 10, 1)] arcpy.AddMessage( "Starting iteration of {} segments".format(total_segments)) with arcpy.da.UpdateCursor( out_segments, ["SHAPE@", field_vblength, field_chandist, field_vbdist, field_segid ]) as ucSegments: i = 1 percent = 0 for segment in ucSegments: segment_endpoints = [ arcpy.PointGeometry(segment[0].firstPoint), arcpy.PointGeometry(segment[0].lastPoint) ] segment[2] = segment_endpoints[0].distanceTo(segment_endpoints[1]) segment[3] = dict_vb_lines[ segment[4]].length if dict_vb_lines.has_key( segment[4]) else 0.0 segment[1] = dict_vb_dist[segment[4]] if dict_vb_dist.has_key( segment[4]) else 0.0 ucSegments.updateRow(segment) if i in percents: percent = percent + 10 arcpy.AddMessage( " {}% Complete: Segment {} out of {}".format( percent, i, total_segments)) i = i + 1 arcpy.AddMessage(" 100% Complete: Segment {} out of {}".format( total_segments, total_segments)) # Calculate Sinuosty Metrics arcpy.AddMessage("Calculating Sinuosity Values") fieldPlanformSinuosity = gis_tools.resetField(out_segments, "Sin_Plan", "DOUBLE") field_vbsin = gis_tools.resetField(out_segments, "Sin_VB", "DOUBLE") field_chansin = gis_tools.resetField(out_segments, "Sin_Chan", "DOUBLE") codeblock = """def calculate_sinuosity(seg_length, seg_distance): if seg_distance == 0 or seg_distance == -9999: return -9999 else: return seg_length / seg_distance """ arcpy.CalculateField_management( out_segments, fieldPlanformSinuosity, "calculate_sinuosity(!{}!, !{}!)".format(field_chanlength, field_chandist), "PYTHON_9.3", codeblock) arcpy.CalculateField_management( out_segments, field_chansin, "calculate_sinuosity(!{}!, !{}!)".format(field_chanlength, field_vblength), "PYTHON_9.3", codeblock) arcpy.CalculateField_management( out_segments, field_vbsin, "calculate_sinuosity(!{}!, !{}!)".format(field_vblength, field_vbdist), "PYTHON_9.3", codeblock) return out_segments
def main(fcLineNetwork, fcNetworkNodes, fieldStreamName, fieldStreamOrder, fcOutputStreamNetwork, boolDissolve, tempWorkspace): reload(gis_tools) # Preprocessing gis_tools.resetData(fcOutputStreamNetwork) listfcMerge = [] # Check for required attribute fields test_field(fcLineNetwork, "GNIS_Name") test_field(fcLineNetwork, "_strmordr_") # Make Feature Layer for lyrStreamSelection = gis_tools.newGISDataset("LAYER", "GNAT_BRANCHES_SelectByName") arcpy.MakeFeatureLayer_management(fcLineNetwork, lyrStreamSelection) # Dissolve by Stream (GNIS) Name where = arcpy.AddFieldDelimiters(fcLineNetwork, fieldStreamName) + " <> '' " arcpy.SelectLayerByAttribute_management(lyrStreamSelection, "NEW_SELECTION", where) fcDissolveByName = gis_tools.newGISDataset(tempWorkspace, "GNAT_BRANCHES_DissolveByName") arcpy.Dissolve_management(lyrStreamSelection, fcDissolveByName, fieldStreamName, multi_part="SINGLE_PART", unsplit_lines="DISSOLVE_LINES") listfcMerge.append(fcDissolveByName) # Select tributary conflences from network nodes lyrNetworkNodes = gis_tools.newGISDataset("LAYER", "GNAT_BRANCHES_NetworkNodes") arcpy.MakeFeatureLayer_management(fcNetworkNodes, lyrNetworkNodes) fcNodesTC = get_trib_confluences(lyrNetworkNodes) # Dissolve by Stream Order arcpy.SelectLayerByAttribute_management(lyrStreamSelection, "SWITCH_SELECTION") if fieldStreamOrder: if len(arcpy.ListFields(fcLineNetwork, fieldStreamOrder)) == 1: fcDissolveByStreamOrder = gis_tools.newGISDataset( tempWorkspace, "GNAT_BRANCHES_DissolveByStreamOrder") arcpy.Dissolve_management(lyrStreamSelection, fcDissolveByStreamOrder, fieldStreamOrder, multi_part="SINGLE_PART", unsplit_lines="DISSOLVE_LINES") # Split Stream Order Junctions if arcpy.Exists(fcNodesTC): fcDissolveByStreamOrderSplit = gis_tools.newGISDataset( tempWorkspace, "GNAT_BRANCHES_DissolveByStreamOrderSplit") arcpy.SplitLineAtPoint_management(fcDissolveByStreamOrder, fcNodesTC, fcDissolveByStreamOrderSplit, "1 METER") listfcMerge.append(fcDissolveByStreamOrderSplit) else: listfcMerge.append(fcDissolveByStreamOrder) else: fcNoStreamOrder = gis_tools.newGISDataset( tempWorkspace, "GNAT_BRANCHES_NoStreamOrderOrStreamName") arcpy.Dissolve_management(lyrStreamSelection, fcNoStreamOrder, multi_part="SINGLE_PART") listfcMerge.append(fcNoStreamOrder) # Merge Dissolved Networks fcMerged = gis_tools.newGISDataset( tempWorkspace, "GNAT_BRANCHES_MergedDissolvedNetworks") arcpy.Merge_management(listfcMerge, fcMerged) # Add Branch ID arcpy.AddField_management(fcMerged, "BranchID", "LONG") gis_tools.addUniqueIDField(fcMerged, "BranchID") # Final Output if boolDissolve == "true": arcpy.AddMessage("Dissolving " + str(boolDissolve)) arcpy.CopyFeatures_management(fcMerged, fcOutputStreamNetwork) else: ## Delete remaining fields from fcMerged not BranchID, or required fields fieldStreamName,fieldStreamOrder, descFCMerged = arcpy.Describe(fcMerged) for field in descFCMerged.fields: if field.name not in [ "BranchID", descFCMerged.OIDFieldName, descFCMerged.shapeFieldName, "Shape_Length" ]: arcpy.DeleteField_management(fcMerged, field.name) arcpy.AddMessage("NOT Dissolving " + str(boolDissolve)) arcpy.Intersect_analysis([fcMerged, fcLineNetwork], fcOutputStreamNetwork, "ALL") return fcOutputStreamNetwork
def main(fcInputSegments, fcInputAttrbNetwork, tempWorkspace): arcpy.env.overwriteOutput = True # Turn off Z and M geometry arcpy.env.outputMFlag = "Disabled" arcpy.env.outputZFlag = "Disabled" # Prep temporary files and layers arcpy.MakeFeatureLayer_management(fcInputSegments, "lyrInputSegments") arcpy.MakeFeatureLayer_management(fcInputAttrbNetwork, "lyrInputAttrbNetwork") fcInputAttrbNetworkTemp = gis_tools.newGISDataset(tempWorkspace, "fcInputAttrbNetworkTemp") arcpy.CopyFeatures_management("lyrInputAttrbNetwork", fcInputAttrbNetworkTemp) fcBraidDslv = gis_tools.newGISDataset(tempWorkspace, "fcBraidDslv") fcSegmentDslv = gis_tools.newGISDataset(tempWorkspace, "fcSegmentDslv") fcNodeBraidToBraid = gis_tools.newGISDataset(tempWorkspace, "fcNodeBraidToBraid") fcNodeBraidToBraidSingle = gis_tools.newGISDataset(tempWorkspace, "fcNodeBraidToBraidSingle") fcNodeBraidToBraidDslv = gis_tools.newGISDataset(tempWorkspace, "fcNodeBraidToBraidDslv") fcNodeBraidToMainstem = gis_tools.newGISDataset(tempWorkspace, "fcNodeBraidToMainstem") fcNodeBraidToMainstemSingle = gis_tools.newGISDataset(tempWorkspace, "fcNodeBraidToMainstemSingle") fcNodeBraidToMainstemDslv = gis_tools.newGISDataset(tempWorkspace, "fcNodeBraidToMainstemDslv") fcNodeTribConfluence = gis_tools.newGISDataset(tempWorkspace, "fcNodeTribConfluence") fcNodeTribConfluenceSingle = gis_tools.newGISDataset(tempWorkspace, "fcNodeTribConfuenceSingle") fcNodeTribConfluenceDslv = gis_tools.newGISDataset(tempWorkspace, "fcNodeTribConfluenceDslv") fcNodesAll = gis_tools.newGISDataset(tempWorkspace, "fcNodesAll") fcNodesToSegments = gis_tools.newGISDataset(tempWorkspace, "fcNodesToSegments") # Check if the segmented stream network has a field named LineOID if findField(fcInputSegments, "SegmentID"): LineOID = "SegmentID" pass else: arcpy.AddMessage("SegmentID attribute field not found in input stream feature class. Using ObjectID field...") LineOID = arcpy.Describe(fcInputSegments).OIDFieldName # Check if the attributed network as been run through the Generate Network Attributes tool. if findField(fcInputAttrbNetworkTemp, "_edgetype_"): pass else: arcpy.AddError("The attributed network input is missing the '_edgetype_' field. Please run the " "network through the Generate Network Attributes tool before running this tool.") # Braid-to-braid nodes arcpy.AddMessage("GNAT CTT: Generating braid-to-braid nodes...") arcpy.MakeFeatureLayer_management(fcInputAttrbNetworkTemp, "lyrInputAttrbNetworkTemp") arcpy.SelectLayerByAttribute_management("lyrInputAttrbNetworkTemp","NEW_SELECTION", """ "_edgetype_" = 'braid' """) arcpy.Dissolve_management("lyrInputAttrbNetworkTemp", fcBraidDslv, "#", "#", "SINGLE_PART") arcpy.Intersect_analysis([fcBraidDslv], fcNodeBraidToBraid, "ONLY_FID", "#", "POINT") arcpy.MakeFeatureLayer_management(fcNodeBraidToBraid, "lyrNodeBraidToBraid") arcpy.MultipartToSinglepart_management("lyrNodeBraidToBraid", fcNodeBraidToBraidSingle) arcpy.MakeFeatureLayer_management(fcNodeBraidToBraidSingle, "lyrNodeBraidToBraidSingle") arcpy.Dissolve_management("lyrNodeBraidToBraidSingle", fcNodeBraidToBraidDslv, "#", "#", "SINGLE_PART") arcpy.MakeFeatureLayer_management(fcNodeBraidToBraidDslv, "lyrNodeBraidToBraidDslv") arcpy.AddField_management("lyrNodeBraidToBraidDslv", "NODE_TYPE", "TEXT") arcpy.CalculateField_management("lyrNodeBraidToBraidDslv", "NODE_TYPE", '"BB"', "PYTHON_9.3") # Braid-to-mainstem nodes arcpy.AddMessage("GNAT CTT: Generating braid-to-mainstem nodes...") arcpy.Intersect_analysis([fcBraidDslv,fcInputSegments],fcNodeBraidToMainstem, "#", "#", "POINT") arcpy.MakeFeatureLayer_management(fcNodeBraidToMainstem, "lyrNodeBraidToMainstem") arcpy.MultipartToSinglepart_management("lyrNodeBraidToMainstem", fcNodeBraidToMainstemSingle) arcpy.MakeFeatureLayer_management(fcNodeBraidToMainstemSingle, "lyrNodeBraidToMainstemSingle") arcpy.Dissolve_management("lyrNodeBraidToMainstemSingle", fcNodeBraidToMainstemDslv, "#", "#", "SINGLE_PART") arcpy.MakeFeatureLayer_management(fcNodeBraidToMainstemDslv, "lyrNodeBraidToMainstemDslv") arcpy.AddField_management("lyrNodeBraidToMainstemDslv", "NODE_TYPE", "TEXT") arcpy.CalculateField_management("lyrNodeBraidToMainstemDslv", "NODE_TYPE", '"BM"', "PYTHON_9.3") # Tributary confluence nodes arcpy.AddMessage("GNAT CTT: Generating tributary nodes...") arcpy.Dissolve_management("lyrInputSegments", fcSegmentDslv, "#", "#", "SINGLE_PART") arcpy.Intersect_analysis([fcSegmentDslv], fcNodeTribConfluence, "ONLY_FID", "#", "POINT") arcpy.MakeFeatureLayer_management(fcNodeTribConfluence, "lyrNodeTribConfluence") arcpy.MultipartToSinglepart_management("lyrNodeTribConfluence", fcNodeTribConfluenceSingle) arcpy.MakeFeatureLayer_management(fcNodeTribConfluenceSingle, "lyrNodeTribConfluenceSingle") arcpy.Dissolve_management("lyrNodeTribConfluenceSingle", fcNodeTribConfluenceDslv, "#", "#", "SINGLE_PART") arcpy.MakeFeatureLayer_management(fcNodeTribConfluenceDslv, "lyrNodeTribConfluenceDslv") arcpy.AddField_management("lyrNodeTribConfluenceDslv", "NODE_TYPE", "TEXT") arcpy.CalculateField_management("lyrNodeTribConfluenceDslv", "NODE_TYPE", '"TC"', "PYTHON_9.3") # Merge nodes feature classes together arcpy.AddMessage("GNAT CTT: Merge and save node feature class...") node_list = ["lyrNodeBraidToBraidDslv", "lyrNodeBraidToMainstemDslv", "lyrNodeTribConfluenceDslv"] fieldMapping = nodeFieldMap(node_list) arcpy.Merge_management(node_list, fcNodesAll, fieldMapping) arcpy.MakeFeatureLayer_management(fcNodesAll, "lyrNodesAll") # Spatial join nodes to segmented stream network arcpy.SpatialJoin_analysis("lyrInputSegments", "lyrNodesAll", fcNodesToSegments, "JOIN_ONE_TO_MANY", "KEEP_COMMON", "#", "INTERSECT") # Summarize each node type by attribute field LineOID arcpy.AddMessage("GNAT CTT: Summarize nodes per stream segments...") arcpy.MakeFeatureLayer_management(fcNodesToSegments, "lyrNodesToSegments") # Spatial join each summary table as a new attribute field to final segment network node_types = ["BB", "BM", "TC"] for n in node_types: join_node_summary("lyrInputSegments", n, "lyrNodesToSegments", LineOID, tempWorkspace) arcpy.AddMessage("GNAT CTT: Processing complete.")