Пример #1
0
def LCP(outputWeightCodedShp):
    """
	Source dir: costRasters
	Output dir: LCPs
	"""

    weightCode = outputWeightCodedShp.split(".")[0]
    source = paths.join(paths.costRasters, weightCode + ".asc")
    output = paths.join(paths.LCPs, outputWeightCodedShp)
    print "Finding least cost paths for weighting {}".format(weightCode)

    if arcpy.Exists(output) and not redoExistingOutput:
        print "{} already exists, leaving it as is.".format(output)
        return output

    paths.setEnv(env)
    if arcpy.Raster(source).minimum is None:
        print "    Calculating statistics for {}...".format(source)
        arcpy.CalculateStatistics_management(source,
                                             x_skip_factor=30,
                                             y_skip_factor=30)
    print "    Calculating cost distance and backlink..."
    costDist = sa.CostDistance(paths.destination,
                               source,
                               out_backlink_raster="backlink")
    print "    Finding least-cost path..."
    costPath = sa.CostPath(paths.sources, costDist, "backlink", "EACH_ZONE")

    print "    Vectorizing..."
    arcpy.RasterToPolyline_conversion(costPath, output, simplify="SIMPLIFY")

    arcpy.Delete_management("backlink")

    return output
Пример #2
0
row = rows.next()
while row:
    patchIDs.append(row.VALUE)
    row = rows.next()
del row, rows

# Loop through patches and and calculate least cost paths
streamFC = "in_memory/LCPlines"
first = True
for patchID in patchIDs:
    msg("Working on patch %s of %s" % (patchID, len(patchIDs)))
    # Idenfity the cost and back link rasters
    cdRaster = os.path.join(CostDistWS, "CD_%s.img" % patchID)
    blRaster = os.path.join(CostDistWS, "BL_%s.img" % patchID)
    # Calculate least cost paths from all patches to the current patch
    lcpRaster = sa.CostPath(patchFix, cdRaster, blRaster, "EACH_ZONE")
    if first:
        lcpOutput = sa.Con(sa.IsNull(lcpRaster), 0, 1)
        first = False
    else:
        lcpTemp = sa.Con(sa.IsNull(lcpRaster), 0, 1) + lcpOutput
        lcpOutput = sa.Con(lcpTemp, 1, 0, "VALUE > 0")
    '''
    # Convert the backlink to a flow direction raster
    #fdRaster = sa.Int(sa.Exp2(blRaster) / 2)
    # Convert the LCP raster to a vector
    if first:   # If the first patch, save the streamsFC to the output FC file
        sa.StreamToFeature(lcpRaster,fdRaster,lcpFC,"NO_SIMPLIFY")
        first = False
    else:       # Otherwise, create it and append it to the original
        sa.StreamToFeature(lcpRaster,fdRaster,streamFC,"NO_SIMPLIFY")
Пример #3
0
def get_centerline (feature, dem, workspace, power = 5, eu_cell_size = 10):
    """Returns a center line feature of the given polygon feature based on
    cost over an euclidean distance raster and cost path. points are seeded
    using minimum and maximum elevation."""    
    centerline = workspace + '\\centerline.shp'
    center_length = 0
    center_slope = 0
    smoothing = 4
    trim_distance = "100 Meters"

    try: 
        # Setup extents / environments for the current feature
        ARCPY.env.extent = feature.shape.extent
        desc = ARCPY.Describe(feature)
        XMin_new = desc.extent.XMin - 200
        YMin_new = desc.extent.YMin - 200
        XMax_new = desc.extent.XMax + 200
        YMax_new = desc.extent.YMax + 200
        ARCPY.env.extent = ARCPY.Extent(XMin_new, YMin_new, XMax_new, YMax_new)
    
        ARCPY.env.overwriteOutput = True
        ARCPY.env.cellSize = eu_cell_size
        ARCPY.env.snapRaster = dem
        
        
        # Get minimum and maximum points
        resample = ARCPY.Resample_management (dem, 'in_memory\\sample', eu_cell_size)
        masked_dem = spatial.ExtractByMask (resample, feature.shape)
    
    
        # Find the maximum elevation value in the feature, convert them to
        # points and then remove all but one.
        maximum = get_properties (masked_dem, 'MAXIMUM') 
        maximum_raster = spatial.SetNull(masked_dem, masked_dem, 'VALUE <> ' + maximum)
        maximum_point = ARCPY.RasterToPoint_conversion(maximum_raster, 'in_memory\\max_point')
        rows = ARCPY.UpdateCursor (maximum_point)
        for row in rows:
            if row.pointid <> 1:
                rows.deleteRow(row)
        del row, rows
        
        # Find the minimum elevation value in the feature, convert them to
        # points and then remove all but one.
        minimum = get_properties (masked_dem, 'MINIMUM')
        minimum_raster = spatial.SetNull(masked_dem, masked_dem, 'VALUE <> ' + minimum)
        minimum_point = ARCPY.RasterToPoint_conversion(minimum_raster, 'in_memory\\min_point')
        rows = ARCPY.UpdateCursor (minimum_point)
        for row in rows:
            if row.pointid <> 1:
                rows.deleteRow(row)
        del row, rows
        
        # Calculate euclidean Distance to boundary line for input DEM cells.
        polyline = ARCPY.PolygonToLine_management(feature.shape, 'in_memory\\polyline')
        eucdist =spatial.EucDistance(polyline, "", eu_cell_size, '')
         
        masked_eucdist = spatial.ExtractByMask (eucdist, feature.shape)
        
        # Calculate the cost raster by inverting the euclidean distance results,
        # and raising it to the power of x to exaggerate the least expensive route.
        cost_raster = (-1 * masked_eucdist + float(maximum))**power
            
        # Run the cost distance and cost path function to find the path of least
        # resistance between the minimum and maximum values. The results are set
        # so all values equal 1 (different path segments have different values)
        # and convert the raster line to a poly-line.
        backlink = 'in_memory\\backlink'
        cost_distance = spatial.CostDistance(minimum_point, cost_raster, '', backlink) 
        cost_path = spatial.CostPath(maximum_point, cost_distance, backlink, 'EACH_CELL', '')
        cost_path_ones = spatial.Con(cost_path, 1, '', 'VALUE > ' + str(-1)) # Set all resulting pixels to 1
        r_to_p = ARCPY.RasterToPolyline_conversion (cost_path_ones, 'in_memory\\raster_to_polygon')
        
        
        del ARCPY.env.extent # Delete current extents (need here but do not know why)
        
        # Removes small line segments from the centerline shape. These segments are
        # a byproduct of cost analysis.
        lines = str(ARCPY.GetCount_management(r_to_p)) #check whether we have more than one line segment
        if float(lines) > 1: # If there is more then one line
            rows = ARCPY.UpdateCursor(r_to_p)
            for row in rows:
                if row.shape.length == eu_cell_size: # delete all the short 10 m lines
                    rows.deleteRow(row)
            del row, rows
            lines = str(ARCPY.GetCount_management(r_to_p))
            if float(lines) > 1:
                ARCPY.Snap_edit(r_to_p, [[r_to_p, "END", "50 Meters"]]) # make sure that the ends of the lines are connected
                r_to_p = ARCPY.Dissolve_management(r_to_p, 'in_memory\\raster_to_polygon_dissolve')
    
    
        # Smooth the resulting line. Currently smoothing is determined by minimum
        # and maximum distance. The greater change the greater the smoothing.
        smooth_tolerance = (float(maximum) - float(minimum)) / smoothing
        ARCPY.SmoothLine_cartography(r_to_p, centerline, 'PAEK', smooth_tolerance, 'FIXED_CLOSED_ENDPOINT', 'NO_CHECK')
    
        field_names = [] # List of field names in the file that will be deleted.
        fields_list = ARCPY.ListFields(centerline)
        for field in fields_list: # Loop through the field names
            if not field.required: # If they are not required append them to the list of field names.
                field_names.append(field.name)
        # Add new fields to the center line feature
        ARCPY.AddField_management(centerline, 'GLIMSID', 'TEXT', '', '', '25')
        ARCPY.AddField_management(centerline, 'LENGTH', 'FLOAT')
        ARCPY.AddField_management(centerline, 'SLOPE', 'FLOAT')
        ARCPY.DeleteField_management(centerline, field_names) # Remove the old fields.
        
        
        # Calculate the length of the line segment and populate segment data.
        ARCPY.CalculateField_management(centerline, 'LENGTH', 'float(!shape.length@meters!)', 'PYTHON')
        rows = ARCPY.UpdateCursor (centerline)
        for row in rows:
            row.GLIMSID = feature.GLIMSID # Get GLIMS ID and add it to segment
            center_length = row.LENGTH # Get the length of the center line
            # Calculate slope of the line based on change in elevation over length of line
            center_slope = round(math.degrees(math.atan((float(maximum) - float(minimum)) / row.LENGTH)), 2)
            row.SLOPE = center_slope # Write slope to Segment
            rows.updateRow(row) # Update the new entry
        del row, rows #Delete cursors and remove locks    
        
        
        # Flip Line if needed - Turn min point and end point into a line segment if
        # the length of this line is greater then the threshold set, flip the line.
        end_point = ARCPY.FeatureVerticesToPoints_management(centerline, 'in_memory\\end_point', 'END')
        merged_points = ARCPY.Merge_management ([end_point, minimum_point], 'in_memory\\merged_points')
        merged_line = ARCPY.PointsToLine_management (merged_points, 'in_memory\\merged_line')
        
        merged_line_length = 0 # Get the line Length
        rows = ARCPY.SearchCursor (merged_line)
        for row in rows:
            merged_line_length += row.shape.length
        del row, rows
            
        # if the line length is greater then a quarter the entire feature length, flip
        if merged_line_length > (center_length/4):
            ARCPY.FlipLine_edit(centerline)
    
    
        # This function attempts to extend the line and clip it back to the 
        # feature extents in order to create a line that runs from edge to edge
        #trimmed_line = ARCPY.Merge_management([polyline, centerline], 'in_memory\\line_merge')
        trimmed_line = ARCPY.Append_management (polyline, centerline, 'NO_TEST')
        ARCPY.TrimLine_edit (trimmed_line, trim_distance, "DELETE_SHORT")
        ARCPY.ExtendLine_edit(trimmed_line, trim_distance, "EXTENSION")
        
        rows = ARCPY.UpdateCursor (trimmed_line)
        for row in rows:
            if row.LENGTH == 0.0:
                rows.deleteRow(row)
        del row, rows
        # Recalculate length. Must be after 0.0 lengths are deleted or they will
        # not be removed above.
        ARCPY.CalculateField_management(centerline, 'LENGTH', 'float(!shape.length@meters!)', 'PYTHON')
    
    
        ARCPY.env.overwriteOutput = False
        return centerline, center_length, center_slope, False
    except:
        ARCPY.env.overwriteOutput = False
        return centerline, '', '', True
     cdInt.save(os.path.join(saveRasterLocation,"CD_%s.img" %patchID))
 # - Tabulate zonal stats for the other patches on the cost distance
 zStatTable = sa.ZonalStatisticsAsTable(patchRaster,"Value",costDist,"in_memory\zstattbl","DATA","MINIMUM")
 # - Write out edges to an edge list; setting to VALUE > patchID writes only the lower half of the matrix
 recs = arcpy.SearchCursor(zStatTable,"VALUE > %d" %patchID)
 rec = recs.next()
 while rec:
     outFile.write("%d,%d,%s\n" %(patchID, rec.VALUE, rec.MIN))
     # - If asked to write LCPs, here we go
     if computeLCPs == 'true':
         ToPatchID = rec.VALUE
         if rec.MIN > 0:
             # Isolate the to-patch
             ToPatch = sa.SetNull(patchRaster,patchRaster,"VALUE <> %d" %ToPatchID)
             # Calculate the least cost path to the to_patch
             lcpRaster = sa.CostPath(ToPatch,costDist,backLink,"BEST_SINGLE")
             # Convert the raster to a feature
             lcpFeature = "in_memory/LCPfeature"
             result = arcpy.RasterToPolyline_conversion(lcpRaster,lcpFeature)
             # Dissolve the feature
             lcpDissolve = "in_memory/LCPdissolve"
             result = arcpy.Dissolve_management(lcpFeature,lcpDissolve)
             # Copy the features over to the LCP feature class
             cur = arcpy.InsertCursor(lcpFC)
             feat = cur.newRow()
             feat.shape = arcpy.SearchCursor(lcpDissolve).next().shape
             feat.FromID = patchID
             feat.ToID = ToPatchID
             feat.Cost = rec.MIN
             cur.insertRow(feat)
             del feat, cur
Пример #5
0
first = True
for to_patch in patchIDs:
    # Idenfity the cost and back link rasters
    cdRaster = os.path.join(CostDistWS,"CD_%s.img" %to_patch)
    blRaster = os.path.join(CostDistWS,"BL_%s.img" %to_patch)
    # Loop through each from patch (skipping ones already processed...)
    for from_patch in patchIDs:
        if from_patch <= to_patch: continue
        msg("Creating least cost path from %s to %s" %(to_patch, from_patch))
        # Extract the cost
        cost = edgeDict[(to_patch,from_patch)]
        # Isolate the to patch
        fromPatch = sa.SetNull(patchRaster,patchRaster,"VALUE <> %s" %from_patch)
        # Calculate least cost paths from all patches to the current patch
        lcpRaster = sa.CostPath(fromPatch,cdRaster,blRaster,"BEST_SINGLE")
        # Convert the backlink to a flow direction raster
        #fdRaster = sa.Int(sa.Exp2(blRaster) / 2)
        # Convert the LCP raster to a vector
        arcpy.RasterToPolyline_conversion(lcpRaster,streamFC,'ZERO',0,"NO_SIMPLIFY")
        #sa.StreamToFeature(lcpRaster,fdRaster,streamFC,"NO_SIMPLIFY")
        if first:   # If the first patch, dissolve to the output FC file
            arcpy.Dissolve_management(streamFC,lcpFC)
            arcpy.AddField_management(lcpFC,"FromID","LONG",10)
            arcpy.AddField_management(lcpFC,"ToID","LONG",10)
            arcpy.AddField_management(lcpFC,"Cost","DOUBLE",10,2)
            arcpy.CalculateField_management(lcpFC,"FromID",from_patch)
            arcpy.CalculateField_management(lcpFC,"ToID",to_patch)
            arcpy.CalculateField_management(lcpFC,"Cost",cost)
            first = False
        else:       # Otherwise, dissolve it and append it to the original