Exemple #1
0
def workLinesMem(segment_info):
    """
    New version of worklines. It uses memory workspace instead of shapefiles.
    The refactoring is to accelerate the processing speed.
    """

    # input verification
    if segment_info is None or len(segment_info) <= 1:
        print("Input segment is corrupted, ignore")

    # Temporary files
    outWorkspace = flmc.GetWorkspace(workspaceName)

    # read params from text file
    f = open(outWorkspace + "\\params.txt")
    Forest_Line_Feature_Class = f.readline().strip()
    Cost_Raster = f.readline().strip()
    Line_Processing_Radius = float(f.readline().strip())
    f.close()

    lineNo = segment_info[1]  # second element is the line No.
    outWorkspaceMem = r"memory"
    arcpy.env.workspace = r"memory"

    fileSeg = os.path.join(outWorkspaceMem, "FLM_CL_Segment_" + str(lineNo))
    fileOrigin = os.path.join(outWorkspaceMem, "FLM_CL_Origin_" + str(lineNo))
    fileDestination = os.path.join(outWorkspaceMem,
                                   "FLM_CL_Destination_" + str(lineNo))
    fileBuffer = os.path.join(outWorkspaceMem, "FLM_CL_Buffer_" + str(lineNo))
    fileClip = os.path.join(outWorkspaceMem,
                            "FLM_CL_Clip_" + str(lineNo) + ".tif")
    fileCostDist = os.path.join(outWorkspaceMem,
                                "FLM_CL_CostDist_" + str(lineNo) + ".tif")
    fileCostBack = os.path.join(outWorkspaceMem,
                                "FLM_CL_CostBack_" + str(lineNo) + ".tif")
    fileCenterline = os.path.join(outWorkspaceMem,
                                  "FLM_CL_Centerline_" + str(lineNo))

    # Load segment list
    segment_list = []

    for line in segment_info[0]:
        for point in line:  # loops through every point in a line
            # loops through every vertex of every segment
            if point:
                # adds all the vertices to segment_list, which creates an array
                segment_list.append(point)

    # Find origin and destination coordinates
    x1 = segment_list[0].X
    y1 = segment_list[0].Y
    x2 = segment_list[-1].X
    y2 = segment_list[-1].Y

    # Create segment feature class
    try:
        arcpy.CreateFeatureclass_management(outWorkspaceMem,
                                            os.path.basename(fileSeg),
                                            "POLYLINE",
                                            Forest_Line_Feature_Class,
                                            "DISABLED", "DISABLED",
                                            Forest_Line_Feature_Class)
        cursor = arcpy.da.InsertCursor(fileSeg, ["SHAPE@"])
        cursor.insertRow([segment_info[0]])
        del cursor
    except Exception as e:
        print("Create feature class {} failed.".format(fileSeg))
        print(e)
        return

    # Create origin feature class
    # TODO: not in use, delete later
    try:
        arcpy.CreateFeatureclass_management(outWorkspaceMem,
                                            os.path.basename(fileOrigin),
                                            "POINT", Forest_Line_Feature_Class,
                                            "DISABLED", "DISABLED",
                                            Forest_Line_Feature_Class)
        cursor = arcpy.da.InsertCursor(fileOrigin, ["SHAPE@XY"])
        xy = (float(x1), float(y1))
        cursor.insertRow([xy])
        del cursor
    except Exception as e:
        print("Creating origin feature class failed: at X, Y" + str(xy) + ".")
        print(e)
        return

    # Create destination feature class
    # TODO: not in use, delete later
    try:
        arcpy.CreateFeatureclass_management(outWorkspaceMem,
                                            os.path.basename(fileDestination),
                                            "POINT", Forest_Line_Feature_Class,
                                            "DISABLED", "DISABLED",
                                            Forest_Line_Feature_Class)
        cursor = arcpy.da.InsertCursor(fileDestination, ["SHAPE@XY"])
        xy = (float(x2), float(y2))
        cursor.insertRow([xy])
        del cursor
    except Exception as e:
        print("Creating destination feature class failed: at X, Y" + str(xy) +
              ".")
        print(e)
        return

    try:
        # Buffer around line
        arcpy.Buffer_analysis(fileSeg, fileBuffer, Line_Processing_Radius,
                              "FULL", "ROUND", "NONE", "", "PLANAR")

        # Clip cost raster using buffer
        DescBuffer = arcpy.Describe(fileBuffer)
        SearchBox = str(DescBuffer.extent.XMin) + " " + str(DescBuffer.extent.YMin) + " " + \
                    str(DescBuffer.extent.XMax) + " " + str(DescBuffer.extent.YMax)
        arcpy.Clip_management(Cost_Raster, SearchBox, fileClip, fileBuffer, "",
                              "ClippingGeometry", "NO_MAINTAIN_EXTENT")

        # Least cost path
        # arcpy.gp.CostDistance_sa(fileOrigin, fileClip, fileCostDist, "", fileCostBack, "", "", "", "", "TO_SOURCE")
        fileCostDist = CostDistance(arcpy.PointGeometry(arcpy.Point(x1, y1)),
                                    fileClip, "", fileCostBack)
        # print("Cost distance file path: {}".format(fileCostDist))

        # arcpy.gp.CostPathAsPolyline_sa(fileDestination, fileCostDist,
        #                               fileCostBack, fileCenterline, "BEST_SINGLE", "")
        CostPathAsPolyline(arcpy.PointGeometry(arcpy.Point(x2,
                                                           y2)), fileCostDist,
                           fileCostBack, fileCenterline, "BEST_SINGLE", "")

        # get centerline polyline out of feature class file
        centerline = []
        with arcpy.da.SearchCursor(fileCenterline, ["SHAPE@"]) as cursor:
            for row in cursor:
                centerline.append(row[0])

    except Exception as e:
        print("Problem with line starting at X " + str(x1) + ", Y " + str(y1) +
              "; and ending at X " + str(x2) + ", Y " + str(y2) + ".")
        print(e)
        centerline = []
        return centerline

    # Clean temporary files
    arcpy.Delete_management(fileSeg)
    arcpy.Delete_management(fileOrigin)
    arcpy.Delete_management(fileDestination)
    arcpy.Delete_management(fileBuffer)
    arcpy.Delete_management(fileClip)
    arcpy.Delete_management(fileCostDist)
    arcpy.Delete_management(fileCostBack)

    # Return centerline
    print("Processing line {} done".format(fileSeg))
    return centerline, segment_info[2]
Exemple #2
0
def main(argv=None):
    # Setup script path and workspace folder
    global workspaceName
    # workspaceName = "FLM_CL_output"

    global outWorkspace
    outWorkspace = flmc.SetupWorkspace(workspaceName)
    # outWorkspace = flmc.GetWorkspace(workspaceName)
    arcpy.env.workspace = outWorkspace
    arcpy.env.overwriteOutput = True

    # Load arguments from file
    if argv:
        args = argv
    else:
        args = flmc.GetArgs("FLM_CL_params.txt")

    # Tool arguments
    global Forest_Line_Feature_Class
    Forest_Line_Feature_Class = args[0].rstrip()
    global Cost_Raster
    Cost_Raster = args[1].rstrip()
    global Line_Processing_Radius
    Line_Processing_Radius = args[2].rstrip()
    ProcessSegments = args[3].rstrip() == "True"
    Out_Centerline = args[4].rstrip()

    # write params to text file
    f = open(outWorkspace + "\\params.txt", "w")
    f.write(Forest_Line_Feature_Class + "\n")
    f.write(Cost_Raster + "\n")
    f.write(Line_Processing_Radius + "\n")
    f.close()

    # Prepare input lines for multiprocessing
    fields = flmc.GetAllFieldsFromShp(Forest_Line_Feature_Class)
    segment_all = flmc.SplitLines(Forest_Line_Feature_Class, outWorkspace,
                                  "CL", ProcessSegments, fields)

    pool = multiprocessing.Pool(processes=flmc.GetCores())
    flmc.log("Multiprocessing center lines...")
    flmc.log("Using {} CPU cores".format(flmc.GetCores()))
    centerlines = pool.map(workLinesMem, segment_all)
    pool.close()
    pool.join()
    flmc.logStep("Center line multiprocessing done.")

    # No line generated, exit
    if len(centerlines) <= 0:
        print("No lines generated, exit")
        return

    # Create output centerline shapefile
    flmc.log("Create centerline shapefile...")
    try:
        arcpy.CreateFeatureclass_management(os.path.dirname(Out_Centerline),
                                            os.path.basename(Out_Centerline),
                                            "POLYLINE",
                                            Forest_Line_Feature_Class,
                                            "DISABLED", "DISABLED",
                                            Forest_Line_Feature_Class)
    except Exception as e:
        print("Create feature class {} failed.".format(Out_Centerline))
        print(e)
        return

    # Flatten centerlines which is a list of list
    flmc.log("Writing centerlines to shapefile...")

    cl_list = []
    for sublist in centerlines:
        if len(sublist) > 0:
            for item in sublist[0]:
                cl_list.append([item, sublist[1]])

    # arcpy.Merge_management(cl_list, Out_Centerline)
    with arcpy.da.InsertCursor(Out_Centerline, ["SHAPE@"] + fields) as cursor:
        for line in cl_list:
            row = []
            for i in fields:
                row.append(line[1][i])

            cursor.insertRow([line[0]] + row)

    # TODO: inspect CorridorTh
    #       CorridorTh is added to footprint tool as new parameter
    #       This can be removed after testing
    if arcpy.Exists(Out_Centerline):
        arcpy.AddField_management(Out_Centerline, "CorridorTh", "DOUBLE")
        arcpy.CalculateField_management(Out_Centerline, "CorridorTh", "3")
    flmc.log("Centerlines shapefile done")
Exemple #3
0
def workLines(lineNo):
    # read params from text file
    outWorkspace = flmc.GetWorkspace(workspaceName)
    f = open(outWorkspace + "\\params.txt")
    outWorkspace = f.readline().strip()
    Centerline_Feature_Class = f.readline().strip()
    Canopy_Raster = f.readline().strip()
    Cost_Raster = f.readline().strip()
    Corridor_Threshold_Field = f.readline().strip()
    Maximum_distance_from_centerline = float(f.readline().strip())
    Expand_And_Shrink_Cell_Range = f.readline().strip()
    f.close()

    # Temporary files
    fileSeg = outWorkspace + "\\FLM_LFP_Segment_" + str(lineNo) + ".shp"
    fileOrigin = outWorkspace + "\\FLM_LFP_Origin_" + str(lineNo) + ".shp"
    fileDestination = outWorkspace + "\\FLM_LFP_Destination_" + str(
        lineNo) + ".shp"
    fileBuffer = outWorkspace + "\\FLM_LFP_Buffer_" + str(lineNo) + ".shp"
    fileClip = outWorkspace + "\\FLM_LFP_Clip_" + str(lineNo) + ".tif"
    fileCostDa = outWorkspace + "\\FLM_LFP_CostDa_" + str(lineNo) + ".tif"
    fileCostDb = outWorkspace + "\\FLM_LFP_CostDb_" + str(lineNo) + ".tif"
    fileCorridor = outWorkspace + "\\FLM_LFP_Corridor_" + str(lineNo) + ".tif"
    fileCorridorMin = outWorkspace + "\\FLM_LFP_CorridorMin_" + str(
        lineNo) + ".tif"
    fileThreshold = outWorkspace + "\\FLM_LFP_Threshold_" + str(
        lineNo) + ".tif"
    fileExpand = outWorkspace + "\\FLM_LFP_Expand_" + str(lineNo) + ".tif"
    fileShrink = outWorkspace + "\\FLM_LFP_Shrink_" + str(lineNo) + ".tif"
    fileClean = outWorkspace + "\\FLM_LFP_Clean_" + str(lineNo) + ".tif"
    fileNull = outWorkspace + "\\FLM_LFP_Null_" + str(lineNo) + ".tif"
    fileFootprint = outWorkspace + "\\FLM_LFP_Footprint_" + str(
        lineNo) + ".shp"

    # When segment file is missing, just quit and log message
    # This segment will be recorded for later re-processing
    if not arcpy.Exists(fileSeg):
        print("{} doesn't exist, ignore.".format(fileSeg))
        return

    # Load segment list
    segment_list = []
    rows = arcpy.SearchCursor(fileSeg)
    shapeField = arcpy.Describe(fileSeg).ShapeFieldName
    for row in rows:
        feat = row.getValue(shapeField)  # creates a geometry object
        Corridor_Threshold = float(row.getValue(Corridor_Threshold_Field))
        segmentnum = 0
        for segment in feat:  # loops through every segment in a line
            # loops through every vertex of every segment
            for pnt in feat.getPart(
                    segmentnum
            ):  # get.PArt returns an array of points for a particular part in the geometry
                if pnt:  # adds all the vertices to segment_list, which creates an array
                    segment_list.append(arcpy.Point(float(pnt.X),
                                                    float(pnt.Y)))

        segmentnum += 1

    del rows

    # Find origin and destination coordinates
    x1 = segment_list[0].X
    y1 = segment_list[0].Y
    x2 = segment_list[-1].X
    y2 = segment_list[-1].Y

    # Create origin feature class
    try:
        arcpy.CreateFeatureclass_management(outWorkspace, PathFile(fileOrigin),
                                            "POINT", Centerline_Feature_Class,
                                            "DISABLED", "DISABLED",
                                            Centerline_Feature_Class)
        cursor = arcpy.da.InsertCursor(fileOrigin, ["SHAPE@XY"])
        xy = (float(x1), float(y1))
        cursor.insertRow([xy])
        del cursor
    except Exception as e:
        print("Create feature class {} failed.".format(fileOrigin))
        print(e)
        return

    # Create destination feature class
    try:
        arcpy.CreateFeatureclass_management(outWorkspace,
                                            PathFile(fileDestination), "POINT",
                                            Centerline_Feature_Class,
                                            "DISABLED", "DISABLED",
                                            Centerline_Feature_Class)
        cursor = arcpy.da.InsertCursor(fileDestination, ["SHAPE@XY"])
        xy = (float(x2), float(y2))
        cursor.insertRow([xy])
        del cursor
    except Exception as e:
        print("Create feature class {} failed.".format(fileDestination))
        print(e)
        return

    # Buffer around line
    try:
        arcpy.Buffer_analysis(fileSeg, fileBuffer,
                              Maximum_distance_from_centerline, "FULL",
                              "ROUND", "NONE", "", "PLANAR")
    except Exception as e:
        print("Create buffer for {} failed".format(fileSeg))
        print(e)
        return

    # Clip cost raster using buffer
    DescBuffer = arcpy.Describe(fileBuffer)
    SearchBox = str(DescBuffer.extent.XMin) + " " + str(
        DescBuffer.extent.YMin) + " " + str(
            DescBuffer.extent.XMax) + " " + str(DescBuffer.extent.YMax)
    arcpy.Clip_management(Cost_Raster, SearchBox, fileClip, fileBuffer, "",
                          "ClippingGeometry", "NO_MAINTAIN_EXTENT")

    # Process: Cost Distance
    arcpy.gp.CostDistance_sa(fileOrigin, fileClip, fileCostDa, "", "", "", "",
                             "", "", "TO_SOURCE")
    arcpy.gp.CostDistance_sa(fileDestination, fileClip, fileCostDb, "", "", "",
                             "", "", "", "TO_SOURCE")

    # Process: Corridor
    arcpy.gp.Corridor_sa(fileCostDa, fileCostDb, fileCorridor)

    # Calculate minimum value of corridor raster
    RasterCorridor = arcpy.Raster(fileCorridor)
    CorrMin = float(RasterCorridor.minimum)

    # Set minimum as zero and save minimum file
    RasterCorridor = ((RasterCorridor - CorrMin) > Corridor_Threshold)
    RasterCorridor.save(fileCorridorMin)

    # Process: Stamp CC and Max Line Width
    RasterClass = SetNull(IsNull(Raster(fileCorridorMin)),
                          (Raster(fileCorridorMin) +
                           (Raster(Canopy_Raster) >= 1)) > 0)
    RasterClass.save(fileThreshold)
    del RasterCorridor, RasterClass

    if (int(Expand_And_Shrink_Cell_Range) > 0):
        # Process: Expand
        arcpy.gp.Expand_sa(fileThreshold, fileExpand,
                           Expand_And_Shrink_Cell_Range, "1")

        # Process: Shrink
        arcpy.gp.Shrink_sa(fileExpand, fileShrink,
                           Expand_And_Shrink_Cell_Range, "1")
    else:
        fileShrink = fileThreshold

    # Process: Boundary Clean
    arcpy.gp.BoundaryClean_sa(fileShrink, fileClean, "ASCEND", "ONE_WAY")
    # arcpy.gp.BoundaryClean_sa(fileShrink, fileClean, "NO_SORT", "ONE_WAY")  # This is original code

    # Process: Set Null
    arcpy.gp.SetNull_sa(fileClean, "1", fileNull, "VALUE > 0")

    # Process: Raster to Polygon
    arcpy.RasterToPolygon_conversion(fileNull, fileFootprint, "SIMPLIFY",
                                     "VALUE", "SINGLE_OUTER_PART", "")

    flmc.log("Processing line {} done".format(fileSeg))

    # Clean temporary files
    try:
        arcpy.Delete_management(fileSeg)
        arcpy.Delete_management(fileOrigin)
        arcpy.Delete_management(fileDestination)
        arcpy.Delete_management(fileBuffer)
        arcpy.Delete_management(fileClip)
        arcpy.Delete_management(fileCostDa)
        arcpy.Delete_management(fileCostDb)
        arcpy.Delete_management(fileThreshold)
        arcpy.Delete_management(fileCorridor)
        arcpy.Delete_management(fileCorridorMin)
        arcpy.Delete_management(fileExpand)
        arcpy.Delete_management(fileShrink)
        arcpy.Delete_management(fileClean)
        arcpy.Delete_management(fileNull)
    except Exception as e:
        print("Line Footprint: Deleting temporary file failed. Inspect later.")
Exemple #4
0
        try:
            input("\n<Press any key to exit>")
        except Exception as e:
            print("")


if __name__ != '__main__':
    # If script is one of the child processes (multiprocessing) load associated scripts
    # (otherwise parallel processing is avoided)
    import Scripts.FLM_CenterLine
    import Scripts.FLM_LineFootprint
    import Scripts.FLM_Corridor
    import Scripts.FLM_CorridorFootprint
    import Scripts.FLM_ZonalThreshold
    import Scripts.FLM_ForestLineAttributes
else:
    # If script is main process, load and show GUI
    vfile = open(scriptPath + "\\Scripts\\FLM_VERSION", "r")
    args = vfile.readlines()
    vfile.close()
    version = args[0]

    flmc.newLog(version)

    print("-\nFLM  Copyright (C) 2021 Applied Geospatial Research Group")
    print("This program comes with ABSOLUTELY NO WARRANTY;\n"
          "This is free software, and you are welcome to redistribute it under certain conditions;\n"
          "See the license file distributed along with this program for details.")

    main()
Exemple #5
0
def workLinesMemory(segment_info):
    """
    New version of worklines. It uses memory workspace instead of shapefiles.
    The refactoring is to accelerate the processing speed.
    """
    # input verification
    if segment_info is None or len(segment_info) <= 1:
        print("Input segment is corrupted, ignore")

    # read params from text file
    outWorkspace = flmc.GetWorkspace(workspaceName)
    f = open(outWorkspace + "\\params.txt")
    outWorkspace = f.readline().strip()
    Centerline_Feature_Class = f.readline().strip()
    Canopy_Raster = f.readline().strip()
    Cost_Raster = f.readline().strip()
    Corridor_Threshold_Field = f.readline().strip()
    Corridor_Threshold = float(f.readline().strip())
    Maximum_distance_from_centerline = float(f.readline().strip())
    Expand_And_Shrink_Cell_Range = f.readline().strip()
    f.close()

    lineNo = segment_info[1]  # second element is the line No.
    outWorkspaceMem = r"memory"

    # Temporary files
    fileSeg = os.path.join(outWorkspaceMem, "FLM_LFP_Segment_" + str(lineNo))
    fileOrigin = os.path.join(outWorkspaceMem, "FLM_LFP_Origin_" + str(lineNo))
    fileDestination = os.path.join(outWorkspaceMem,
                                   "FLM_LFP_Destination_" + str(lineNo))
    fileBuffer = os.path.join(outWorkspaceMem, "FLM_LFP_Buffer_" + str(lineNo))
    fileClip = os.path.join(outWorkspaceMem,
                            "FLM_LFP_Clip_" + str(lineNo) + ".tif")
    fileCostDa = os.path.join(outWorkspaceMem,
                              "FLM_LFP_CostDa_" + str(lineNo) + ".tif")
    fileCostDb = os.path.join(outWorkspaceMem,
                              "FLM_LFP_CostDb_" + str(lineNo) + ".tif")
    fileCorridor = os.path.join(outWorkspaceMem,
                                "FLM_LFP_Corridor_" + str(lineNo) + ".tif")
    fileCorridorMin = os.path.join(
        outWorkspaceMem, "FLM_LFP_CorridorMin_" + str(lineNo) + ".tif")
    fileThreshold = os.path.join(outWorkspaceMem,
                                 "FLM_LFP_Threshold_" + str(lineNo) + ".tif")
    fileExpand = os.path.join(outWorkspaceMem,
                              "FLM_LFP_Expand_" + str(lineNo) + ".tif")
    fileShrink = os.path.join(outWorkspaceMem,
                              "FLM_LFP_Shrink_" + str(lineNo) + ".tif")
    fileClean = os.path.join(outWorkspaceMem,
                             "FLM_LFP_Clean_" + str(lineNo) + ".tif")
    fileNull = os.path.join(outWorkspaceMem,
                            "FLM_LFP_Null_" + str(lineNo) + ".tif")

    # Load segment list
    segment_list = []

    for line in segment_info[0]:
        for point in line:  # loops through every point in a line
            # loops through every vertex of every segment
            if point:  # adds all the vertices to segment_list, which creates an array
                segment_list.append(point)

    # Find origin and destination coordinates
    x1 = segment_list[0].X
    y1 = segment_list[0].Y
    x2 = segment_list[-1].X
    y2 = segment_list[-1].Y

    # Create segment feature class
    try:
        arcpy.CreateFeatureclass_management(outWorkspaceMem,
                                            os.path.basename(fileSeg),
                                            "POLYLINE",
                                            Centerline_Feature_Class,
                                            "DISABLED", "DISABLED",
                                            Centerline_Feature_Class)
        cursor = arcpy.da.InsertCursor(fileSeg, ["SHAPE@"])
        cursor.insertRow([segment_info[0]])
        del cursor
    except Exception as e:
        print("Create feature class {} failed.".format(fileSeg))
        print(e)
        return

    # Create origin feature class
    try:
        arcpy.CreateFeatureclass_management(outWorkspaceMem,
                                            os.path.basename(fileOrigin),
                                            "POINT", Centerline_Feature_Class,
                                            "DISABLED", "DISABLED",
                                            Centerline_Feature_Class)
        cursor = arcpy.da.InsertCursor(fileOrigin, ["SHAPE@XY"])
        xy = (float(x1), float(y1))
        cursor.insertRow([xy])
        del cursor
    except Exception as e:
        print("Create feature class {} failed.".format(fileOrigin))
        print(e)
        return

    # Create destination feature class
    try:
        arcpy.CreateFeatureclass_management(outWorkspaceMem,
                                            os.path.basename(fileDestination),
                                            "POINT", Centerline_Feature_Class,
                                            "DISABLED", "DISABLED",
                                            Centerline_Feature_Class)
        cursor = arcpy.da.InsertCursor(fileDestination, ["SHAPE@XY"])
        xy = (float(x2), float(y2))
        cursor.insertRow([xy])
        del cursor
    except Exception as e:
        print("Create feature class {} failed.".format(fileDestination))
        print(e)
        return

    # Buffer around line
    try:
        arcpy.Buffer_analysis(fileSeg, fileBuffer,
                              Maximum_distance_from_centerline, "FULL",
                              "ROUND", "NONE", "", "PLANAR")
    except Exception as e:
        print("Create buffer for {} failed".format(fileSeg))
        print(e)
        return

    # Clip cost raster using buffer
    DescBuffer = arcpy.Describe(fileBuffer)
    SearchBox = str(DescBuffer.extent.XMin) + " " + str(
        DescBuffer.extent.YMin) + " " + str(
            DescBuffer.extent.XMax) + " " + str(DescBuffer.extent.YMax)
    arcpy.Clip_management(Cost_Raster, SearchBox, fileClip, fileBuffer, "",
                          "ClippingGeometry", "NO_MAINTAIN_EXTENT")

    try:
        # Process: Cost Distance
        arcpy.gp.CostDistance_sa(fileOrigin, fileClip, fileCostDa, "", "", "",
                                 "", "", "", "TO_SOURCE")
        arcpy.gp.CostDistance_sa(fileDestination, fileClip, fileCostDb, "", "",
                                 "", "", "", "", "TO_SOURCE")

        # Process: Corridor
        arcpy.gp.Corridor_sa(fileCostDa, fileCostDb, fileCorridor)
    except Exception as e:
        print(e)

    footprint = []

    # Calculate minimum value of corridor raster
    try:
        RasterCorridor = arcpy.Raster(fileCorridor)

        if not RasterCorridor.minimum is None:
            CorrMin = float(RasterCorridor.minimum)
        else:
            print("Line segment {} error: RasterCorridor.minimum is None",
                  lineNo)
            CorrMin = 0

        # Set minimum as zero and save minimum file
        RasterCorridor = ((RasterCorridor - CorrMin) > Corridor_Threshold)
        RasterCorridor.save(fileCorridorMin)

        # Process: Stamp CC and Max Line Width
        RasterClass = SetNull(IsNull(Raster(fileCorridorMin)),
                              (Raster(fileCorridorMin) +
                               (Raster(Canopy_Raster) >= 1)) > 0)
        RasterClass.save(fileThreshold)
        del RasterCorridor, RasterClass

        if (int(Expand_And_Shrink_Cell_Range) > 0):
            # Process: Expand
            arcpy.gp.Expand_sa(fileThreshold, fileExpand,
                               Expand_And_Shrink_Cell_Range, "1")

            # Process: Shrink
            arcpy.gp.Shrink_sa(fileExpand, fileShrink,
                               Expand_And_Shrink_Cell_Range, "1")
        else:
            fileShrink = fileThreshold

        # Process: Boundary Clean
        arcpy.gp.BoundaryClean_sa(fileShrink, fileClean, "ASCEND", "ONE_WAY")
        # arcpy.gp.BoundaryClean_sa(fileShrink, fileClean, "NO_SORT", "ONE_WAY")  # This is original code

        # Process: Set Null
        arcpy.gp.SetNull_sa(fileClean, "1", fileNull, "VALUE > 0")

        # Process: Raster to Polygon
        footprint = arcpy.RasterToPolygon_conversion(fileNull,
                                                     arcpy.Geometry(),
                                                     "SIMPLIFY", "VALUE",
                                                     "MULTIPLE_OUTER_PART", "")
    except Exception as e:
        print(e)

    flmc.log("Processing line {} done".format(fileSeg))

    # Clean temporary files
    try:
        arcpy.Delete_management(fileSeg)
        arcpy.Delete_management(fileOrigin)
        arcpy.Delete_management(fileDestination)
        arcpy.Delete_management(fileBuffer)
        arcpy.Delete_management(fileClip)
        arcpy.Delete_management(fileCostDa)
        arcpy.Delete_management(fileCostDb)
        arcpy.Delete_management(fileThreshold)
        arcpy.Delete_management(fileCorridor)
        arcpy.Delete_management(fileCorridorMin)
        arcpy.Delete_management(fileExpand)
        arcpy.Delete_management(fileShrink)
        arcpy.Delete_management(fileClean)
        arcpy.Delete_management(fileNull)
    except Exception as e:
        print("Line Footprint: Deleting temporary file failed. Inspect later.")

    return footprint  # list of polygons
Exemple #6
0
def main(argv=None):
    # Setup script path and workspace folder
    workspaceName = "FLM_LFP_output"
    global outWorkspace
    outWorkspace = flmc.GetWorkspace(workspaceName)
    arcpy.env.workspace = outWorkspace
    arcpy.env.overwriteOutput = True

    # Load arguments from file
    if argv:
        args = argv
    else:
        args = flmc.GetArgs("FLM_LFP_params.txt")

    # Tool arguments
    global Centerline_Feature_Class
    Centerline_Feature_Class = args[0].rstrip()
    global Canopy_Raster
    Canopy_Raster = args[1].rstrip()
    global Cost_Raster
    Cost_Raster = args[2].rstrip()
    global Corridor_Threshold_Field
    Corridor_Threshold_Field = args[3].rstrip()
    global Corridor_Threshold
    Corridor_Threshold = args[4].rstrip()
    global Maximum_distance_from_centerline
    Maximum_distance_from_centerline = float(args[5].rstrip()) / 2.0
    global Expand_And_Shrink_Cell_Range
    Expand_And_Shrink_Cell_Range = args[6].rstrip()
    global ProcessSegments
    ProcessSegments = args[7].rstrip() == "True"
    global Output_Footprint
    Output_Footprint = args[8].rstrip()
    outWorkspace = flmc.SetupWorkspace(workspaceName)

    # write params to text file for use in function workLinesMemory
    f = open(outWorkspace + "\\params.txt", "w")
    f.write(outWorkspace + "\n")
    f.write(Centerline_Feature_Class + "\n")
    f.write(Canopy_Raster + "\n")
    f.write(Cost_Raster + "\n")
    f.write(Corridor_Threshold_Field + "\n")
    f.write(Corridor_Threshold + "\n")
    f.write(str(Maximum_distance_from_centerline) + "\n")
    f.write(Expand_And_Shrink_Cell_Range + "\n")
    f.close()

    # TODO: this code block is not necessary
    if not HasField(Centerline_Feature_Class, Corridor_Threshold_Field):
        flmc.log("ERROR: There is no field named " + Corridor_Threshold_Field +
                 " in the input lines")
        return False

    # Prepare input lines for multiprocessing
    segment_all = flmc.SplitLines(Centerline_Feature_Class, outWorkspace,
                                  "LFP", ProcessSegments,
                                  Corridor_Threshold_Field)

    # TODO: inspect how GetCores works. Make sure it uses all the CPU cores
    pool = multiprocessing.Pool(processes=flmc.GetCores())
    flmc.log("Multiprocessing line corridors...")
    flmc.log("Using {} CPU cores".format(flmc.GetCores()))

    footprints = pool.map(
        workLinesMemory, segment_all)  # new version of memory based processing
    pool.close()
    pool.join()
    flmc.logStep("Corridor multiprocessing")

    flmc.log("Merging footprints...")
    try:
        # Flatten footprints which is a list of list
        ft_list = [item for sublist in footprints for item in sublist]

        fileMerge = outWorkspace + "\\FLM_LFP_Merge.shp"
        arcpy.Merge_management(ft_list, fileMerge)
        arcpy.Dissolve_management(fileMerge, Output_Footprint)
        # arcpy.Delete_management(fileMerge)
    except Exception as e:
        print("e")

    flmc.logStep("Footprints merged.")
Exemple #7
0
def main(argv=None):
    # Setup script path and workspace folder
    workspaceName = "FLM_PT_output"
    global outWorkspace
    outWorkspace = flmc.GetWorkspace(workspaceName)
    arcpy.env.workspace = outWorkspace
    arcpy.env.overwriteOutput = True

    # Load arguments from file
    if argv:
        args = argv
    else:
        args = flmc.GetArgs("FLM_PT_params.txt")

    # Tool arguments
    global Centerline_Feature_Class
    Centerline_Feature_Class = args[0].rstrip()
    global In_CHM
    In_CHM = args[1].rstrip()
    global Canopy_Raster
    Canopy_Raster = args[2].rstrip()
    global Cost_Raster
    Cost_Raster = args[3].rstrip()
    global In_Lidar_Year
    In_Lidar_Year = args[4].rstrip()
    global Maximum_distance_from_centerline
    Maximum_distance_from_centerline = float(args[5].rstrip()) / 2.0
    global Out_Tagged_Line
    Out_Tagged_Line = args[6].rstrip()
    outWorkspace = flmc.SetupWorkspace(workspaceName)

    # write params to text file
    f = open(outWorkspace + "\\params.txt", "w")
    f.write(outWorkspace + "\n")
    f.write(Centerline_Feature_Class + "\n")
    f.write(In_CHM + "\n")
    f.write(Canopy_Raster + "\n")
    f.write(Cost_Raster + "\n")
    f.write(In_Lidar_Year + "\n")
    f.write(str(Maximum_distance_from_centerline) + "\n")
    f.write(Out_Tagged_Line + "\n")
    f.close()

    # Remind if Status field is already in Shapefile
    if HasField(Centerline_Feature_Class, "Status"):
        print("{} has Status field, it will be overwritten.".format(
            Centerline_Feature_Class))

    polygons = retrievePolygons(In_Lidar_Year)

    # Prepare input lines for multiprocessing
    fields = flmc.GetAllFieldsFromShp(Centerline_Feature_Class)
    global ProcessSegments
    segment_all = flmc.SplitLines(Centerline_Feature_Class, outWorkspace,
                                  "LFP", ProcessSegments, fields, polygons)

    # TODO: inspect how GetCores works. Make sure it uses all the CPU cores
    pool = multiprocessing.Pool(processes=flmc.GetCores())
    flmc.log("Multiprocessing line corridors...")
    flmc.log("Using {} CPU cores".format(flmc.GetCores()))

    tagged_lines = pool.map(
        workLinesMem, segment_all)  # new version of memory based processing
    pool.close()
    pool.join()
    flmc.logStep("Tagging lines multiprocessing")

    flmc.log("Write lines with existence and all statistics...")
    try:
        # create tagged line feature class with stats
        (root, ext) = os.path.splitext(Out_Tagged_Line)
        root = root + "_stats"
        out_tagged_line_stats = root + ext
        arcpy.CreateFeatureclass_management(
            os.path.dirname(out_tagged_line_stats),
            os.path.basename(out_tagged_line_stats), "Polyline", "",
            "DISABLED", "DISABLED", Centerline_Feature_Class)
        arcpy.AddField_management(out_tagged_line_stats, "Status", "TEXT")

        arcpy.AddField_management(out_tagged_line_stats, "Mean", "DOUBLE")
        arcpy.AddField_management(out_tagged_line_stats, "Median", "DOUBLE")
        arcpy.AddField_management(out_tagged_line_stats, "Variance", "DOUBLE")
        arcpy.AddField_management(out_tagged_line_stats, "Stdev", "DOUBLE")

        arcpy.AddField_management(out_tagged_line_stats, "Mean_B", "DOUBLE")
        arcpy.AddField_management(out_tagged_line_stats, "Median_B", "DOUBLE")
        arcpy.AddField_management(out_tagged_line_stats, "Variance_B",
                                  "DOUBLE")
        arcpy.AddField_management(out_tagged_line_stats, "Stdev_B", "DOUBLE")

        fields_stats = [
            "SHAPE@", "Status", "Mean", "Median", "Variance", "Stdev",
            "Mean_B", "Median_B", "Variance_B", "Stdev_B"
        ]
        with arcpy.da.InsertCursor(out_tagged_line_stats,
                                   fields_stats) as cursor:
            for line in tagged_lines:
                cursor.insertRow([line[0]] + list(line[1]))

        # arcpy.Delete_management(fileMerge)
    except Exception as e:
        print(e)

    flmc.log("Writing lines with existence and all original attributes.")
    try:
        # create tagged line feature class with existence and all original attributes
        arcpy.CreateFeatureclass_management(os.path.dirname(Out_Tagged_Line),
                                            os.path.basename(Out_Tagged_Line),
                                            "Polyline",
                                            Centerline_Feature_Class,
                                            "DISABLED", "DISABLED",
                                            Centerline_Feature_Class)
        # Add Status field to indicate line existence type: confirmed, unconfirmed and invisible
        status_appended = False
        if not HasField(Centerline_Feature_Class, "Status"):
            arcpy.AddField_management(Out_Tagged_Line, "Status", "TEXT")
            fields.append("Status")
            status_appended = True

        with arcpy.da.InsertCursor(Out_Tagged_Line,
                                   ["Shape@"] + fields) as cursor:
            for line in tagged_lines:
                row = []
                for i in fields:
                    if i != "Status":
                        row.append(line[2][i])

                # Line status
                if status_appended:
                    row.append(line[1][0])
                else:  # overwrite Status value
                    row.insert(fields.index("Status"), line[1][0])

                cursor.insertRow([line[0]] + row)
    except Exception as e:
        print(e)

    flmc.logStep("Tagged lines output done.")
Exemple #8
0
def main(argv=None):
    # Setup script path and output folder
    outWorkspace = flmc.SetupWorkspace("FLM_CC_output")
    arcpy.env.workspace = outWorkspace
    arcpy.env.scratchWorkspace = outWorkspace
    arcpy.env.overwriteOutput = True

    # Load arguments from file
    if argv:
        args = argv
    else:
        args = flmc.GetArgs("FLM_CC_params.txt")

    # Tool arguments
    CHM_Raster = args[0].rstrip()
    Min_Canopy_Height = float(args[1].rstrip())
    Tree_Search_Area = "Circle " + str(float(args[2].rstrip())) + " MAP"
    Max_Line_Distance = float(args[3].rstrip())
    CanopyAvoidance = float(args[4].rstrip())
    Cost_Raster_Exponent = float(args[5].rstrip())
    Output_Canopy_Raster = args[6].rstrip()
    Output_Cost_Raster = args[7].rstrip()

    # Local variables:
    FLM_CC_EucRaster = outWorkspace + "\\FLM_CC_EucRaster.tif"
    FLM_CC_SmoothRaster = outWorkspace + "\\FLM_CC_SmoothRaster.tif"
    FLM_CC_Mean = outWorkspace + "\\FLM_CC_Mean.tif"
    FLM_CC_StDev = outWorkspace + "\\FLM_CC_StDev.tif"
    FLM_CC_CostRaster = outWorkspace + "\\FLM_CC_CostRaster.tif"

    # Process: Turn CHM into a Canopy Closure (CC) map
    flmc.log("Applying height threshold to CHM...")
    arcpy.gp.Con_sa(CHM_Raster, 1, Output_Canopy_Raster, 0,
                    "VALUE > " + str(Min_Canopy_Height))
    flmc.logStep("Height threshold")

    # Process: CC Mean
    flmc.log("Calculating Focal Mean...")
    arcpy.gp.FocalStatistics_sa(Output_Canopy_Raster, FLM_CC_Mean,
                                Tree_Search_Area, "MEAN")
    flmc.logStep("Focal Mean")

    # Process: CC StDev
    flmc.log("Calculating Focal StDev..")
    arcpy.gp.FocalStatistics_sa(Output_Canopy_Raster, FLM_CC_StDev,
                                Tree_Search_Area, "STD")
    flmc.logStep("Focal StDev")

    # Process: Euclidean Distance
    flmc.log("Calculating Euclidean Distance From Canopy...")
    EucAllocation(Con(arcpy.Raster(Output_Canopy_Raster) >= 1, 1, ""), "", "",
                  "", "", FLM_CC_EucRaster, "")
    smoothCost = (float(Max_Line_Distance) - arcpy.Raster(FLM_CC_EucRaster))
    smoothCost = Con(smoothCost > 0, smoothCost, 0) / float(Max_Line_Distance)
    smoothCost.save(FLM_CC_SmoothRaster)
    flmc.logStep("Euclidean Distance")

    # Process: Euclidean Distance
    flmc.log("Calculating Cost Raster...")
    arcpy.env.compression = "NONE"
    Raster_CC = arcpy.Raster(Output_Canopy_Raster)
    Raster_Mean = arcpy.Raster(FLM_CC_Mean)
    Raster_StDev = arcpy.Raster(FLM_CC_StDev)
    Raster_Smooth = arcpy.Raster(FLM_CC_SmoothRaster)
    avoidance = max(min(float(CanopyAvoidance), 1), 0)

    # TODO: shorten following sentence
    outRas = Power(
        Exp(
            Con((Raster_CC == 1), 1,
                Con((Raster_Mean + Raster_StDev <= 0), 0,
                    (1 + (Raster_Mean - Raster_StDev) /
                     (Raster_Mean + Raster_StDev)) / 2) * (1 - avoidance) +
                Raster_Smooth * avoidance)), float(Cost_Raster_Exponent))
    outRas.save(FLM_CC_CostRaster)
    flmc.logStep("Cost Raster")

    flmc.log("Saving Outputs...")
    arcpy.CopyRaster_management(outRas, Output_Cost_Raster, "DEFAULTS")
    arcpy.ClearWorkspaceCache_management()
def main(argv=None):
    # Setup script path and workspace folder
    global outWorkspace
    outWorkspace = flmc.SetupWorkspace(workspaceName)

    arcpy.env.workspace = outWorkspace
    arcpy.env.overwriteOutput = True

    # Load arguments from file
    if argv:
        args = argv
    else:
        args = flmc.GetArgs("FLM_FLA_params.txt")

    # Tool arguments
    Input_Lines = args[0].rstrip()
    Input_Footprint = args[1].rstrip()
    Input_CHM = args[2].rstrip()
    SamplingType = args[3].rstrip()
    Segment_Length = float(args[4].rstrip())
    Tolerance_Radius = float(args[5].rstrip())
    LineSearchRadius = float(args[6].rstrip())
    Attributed_Segments = args[7].rstrip()

    areaAnalysis = arcpy.Exists(Input_Footprint)
    heightAnalysis = arcpy.Exists(Input_CHM)

    # write params to text file
    f = open(outWorkspace + "\\params.txt", "w")
    f.write(outWorkspace + "\n")
    f.write(Input_Lines + "\n")
    f.write(Input_Footprint + "\n")
    f.write(Input_CHM + "\n")
    f.write(SamplingType + "\n")
    f.write(str(Segment_Length) + "\n")
    f.write(str(Tolerance_Radius) + "\n")
    f.write(str(LineSearchRadius) + "\n")
    f.write(Attributed_Segments + "\n")
    f.write(str(areaAnalysis) + "\n")
    f.write(str(heightAnalysis) + "\n")
    f.close()

    # Only process the following SampleingType
    if SamplingType not in [
            "IN-FEATURES", "WHOLE-LINE", "LINE-CROSSINGS", "ARBITRARY"
    ]:
        print("SamplingType is not correct, please verify it.")
        return

    # Temporary layers
    fileBuffer = outWorkspace + "\\FLM_SLA_Buffer.shp"
    fileIdentity = outWorkspace + "\\FLM_SLA_Identity.shp"
    fileFootprints = outWorkspace + "\\FLM_SLA_Footprints.shp"

    footprintField = flmc.FileToField(fileBuffer)

    flmc.log("Preparing line segments...")
    # Segment lines
    flmc.log("FlmLineSplit: Input_Lines = " + Input_Lines)
    # Get all original fields
    keepFields = flmc.GetAllFieldsFromShp(Input_Lines)
    SLA_Segmented_Lines = flma.FlmLineSplit(outWorkspace, Input_Lines,
                                            SamplingType, Segment_Length,
                                            Tolerance_Radius)
    flmc.logStep("Line segmentation")

    # Linear attributes
    flmc.log("Adding attributes...")
    arcpy.AddGeometryAttributes_management(SLA_Segmented_Lines,
                                           "LENGTH;LINE_BEARING", "METERS")
    keepFields += ["LENGTH", "BEARING"]

    if areaAnalysis:
        arcpy.Buffer_analysis(SLA_Segmented_Lines,
                              fileBuffer,
                              LineSearchRadius,
                              line_side="FULL",
                              line_end_type="FLAT",
                              dissolve_option="NONE",
                              dissolve_field="",
                              method="PLANAR")
        arcpy.Identity_analysis(Input_Footprint,
                                fileBuffer,
                                fileIdentity,
                                join_attributes="ONLY_FID",
                                cluster_tolerance="",
                                relationship="NO_RELATIONSHIPS")
        arcpy.Dissolve_management(fileIdentity,
                                  fileFootprints,
                                  dissolve_field=footprintField,
                                  statistics_fields="",
                                  multi_part="MULTI_PART",
                                  unsplit_lines="DISSOLVE_LINES")
        arcpy.JoinField_management(fileFootprints,
                                   footprintField,
                                   fileBuffer,
                                   arcpy.Describe(fileBuffer).OIDFieldName,
                                   fields="ORIG_FID")
        fCursor = arcpy.UpdateCursor(fileFootprints)
        for row in fCursor:
            if float(row.getValue(footprintField)) < 0:
                fCursor.deleteRow(row)
        del fCursor

        arcpy.AddGeometryAttributes_management(
            fileFootprints,
            Geometry_Properties="AREA;PERIMETER_LENGTH",
            Length_Unit="METERS",
            Area_Unit="SQUARE_METERS",
            Coordinate_System="")
        arcpy.JoinField_management(
            SLA_Segmented_Lines,
            arcpy.Describe(SLA_Segmented_Lines).OIDFieldName,
            fileFootprints,
            "ORIG_FID",
            fields="POLY_AREA;PERIMETER")
        keepFields += ["POLY_AREA", "PERIMETER"]
        arcpy.Delete_management(fileBuffer)
        arcpy.Delete_management(fileIdentity)
        arcpy.Delete_management(fileFootprints)

    # Add other fields
    arcpy.AddField_management(SLA_Segmented_Lines, "Direction", "TEXT")
    arcpy.AddField_management(SLA_Segmented_Lines, "Sinuosity", "DOUBLE")
    keepFields += ["Direction", "Sinuosity"]

    if areaAnalysis:
        arcpy.AddField_management(SLA_Segmented_Lines, "AvgWidth", "DOUBLE")
        arcpy.AddField_management(SLA_Segmented_Lines, "Fragment", "DOUBLE")
        keepFields += ["AvgWidth", "Fragment"]
        if heightAnalysis:
            arcpy.AddField_management(SLA_Segmented_Lines, "AvgHeight",
                                      "DOUBLE")
            arcpy.AddField_management(SLA_Segmented_Lines, "Volume", "DOUBLE")
            arcpy.AddField_management(SLA_Segmented_Lines, "Roughness",
                                      "DOUBLE")
            keepFields += ["AvgHeight", "Volume", "Roughness"]

    # Prepare input lines for multiprocessing
    # ["Direction","Sinuosity","Area","AvgWidth","Perimeter","Fragment","SLA_Unity","AvgHeight","Volume","Roughness"])
    segment_all = flmc.SplitLines(SLA_Segmented_Lines, outWorkspace, "SLA",
                                  False, keepFields)

    pool = multiprocessing.Pool(processes=flmc.GetCores())
    flmc.log("Multiprocessing lines...")
    # pool.map(workLinesMem, range(1, numLines + 1))
    line_with_attributes = pool.map(workLinesMem, segment_all)
    pool.close()
    pool.join()

    flmc.logStep("Line attributes multiprocessing")

    # Create output line attribute shapefile
    flmc.log("Create line attribute shapefile...")
    try:
        arcpy.CreateFeatureclass_management(
            os.path.dirname(Attributed_Segments),
            os.path.basename(Attributed_Segments), "POLYLINE",
            SLA_Segmented_Lines, "DISABLED", "DISABLED", SLA_Segmented_Lines)
    except Exception as e:
        print("Create feature class {} failed.".format(Attributed_Segments))
        print(e)
        return

    # Flatten line attribute which is a list of list
    flmc.log("Writing line attributes to shapefile...")
    # TODO: is this necessary? Since we need list of single line next
    # la_list = [item for sublist in line_with_attributes for item in sublist]
    with arcpy.da.InsertCursor(Attributed_Segments,
                               ["SHAPE@"] + keepFields) as cursor:
        for line in line_with_attributes:
            row = []
            for fld in keepFields:
                row.append(line[1][fld])

            cursor.insertRow(line[0] + row)

    flmc.logStep("Line attribute file: {} done".format(Attributed_Segments))
def workLines(lineNo):
    outWorkspace = flmc.GetWorkspace(workspaceName)
    f = open(outWorkspace + "\\params.txt")

    outWorkspace = f.readline().strip()
    Input_Lines = f.readline().strip()
    Input_Footprint = f.readline().strip()
    Input_CHM = f.readline().strip()
    SamplingType = f.readline().strip()
    Segment_Length = float(f.readline().strip())
    Tolerance_Radius = float(f.readline().strip())
    LineSearchRadius = float(f.readline().strip())
    Attributed_Segments = f.readline().strip()
    areaAnalysis = True if f.readline().strip() == "True" else False
    heightAnalysis = True if f.readline().strip() == "True" else False
    f.close()

    # Temporary files
    lineSeg = outWorkspace + "\\FLM_SLA_Segment_" + str(lineNo) + ".shp"
    lineBuffer = outWorkspace + "\\FLM_SLA_Buffer_" + str(lineNo) + ".shp"
    lineClip = outWorkspace + "\\FLM_SLA_Clip_" + str(lineNo) + ".shp"
    lineStats = outWorkspace + "\\FLM_SLA_Stats_" + str(lineNo) + ".dbf"

    if areaAnalysis:
        arcpy.Buffer_analysis(lineSeg,
                              lineBuffer,
                              LineSearchRadius,
                              line_side="FULL",
                              line_end_type="FLAT",
                              dissolve_option="NONE",
                              dissolve_field="",
                              method="PLANAR")
        arcpy.Clip_analysis(Input_Footprint, lineBuffer, lineClip)
        arcpy.Delete_management(lineBuffer)
        if heightAnalysis and arcpy.Exists(lineClip):
            try:
                arcpy.gp.ZonalStatisticsAsTable_sa(
                    lineClip,
                    arcpy.Describe(lineClip).OIDFieldName, Input_CHM,
                    lineStats, "DATA", "ALL")
            except Exception as e:
                lineStats = ""
                print(e)

    rows = arcpy.UpdateCursor(lineSeg)
    shapeField = arcpy.Describe(lineSeg).ShapeFieldName
    row = rows.next()

    feat = row.getValue(shapeField)  # creates a geometry object
    length = float(row.getValue("LENGTH"))  # creates a geometry object

    try:
        bearing = float(row.getValue("BEARING"))  # creates a geometry object
    except Exception as e:
        bearing = 0
        print(e)

    segmentnum = 0
    segment_list = []
    for segment in feat:  # loops through every segment in a line
        # loops through every vertex of every segment
        # get.PArt returns an array of points for a particular part in the geometry
        for pnt in feat.getPart(segmentnum):
            if pnt:  # adds all the vertices to segment_list, which creates an array
                segment_list.append(arcpy.Point(float(pnt.X), float(pnt.Y)))

    # Sinuosity calculation
    eucDistance = arcpy.PointGeometry(feat.firstPoint).distanceTo(
        arcpy.PointGeometry(feat.lastPoint))
    try:
        row.setValue("Sinuosity", length / eucDistance)
    except Exception as e:
        row.setValue("Sinuosity", float("inf"))
        print(e)

    # Direction based on bearing
    ori = "N-S"
    if 22.5 <= bearing < 67.5 or 202.5 <= bearing < 247.5:
        ori = "NE-SW"
    elif 67.5 <= bearing < 112.5 or 247.5 <= bearing < 292.5:
        ori = "E-W"
    elif 112.5 <= bearing < 157.5 or 292.5 <= bearing < 337.5:
        ori = "NW-SE"
    row.setValue("Direction", ori)

    # If footprint polygons are available, get area-based variables
    if areaAnalysis:
        totalArea = float(row.getValue("POLY_AREA"))
        totalPerim = float(row.getValue("PERIMETER"))

        row.setValue("AvgWidth", totalArea / length)

        try:
            row.setValue("Fragment", totalPerim / totalArea)
        except Exception as e:
            row.setValue("Fragment", float("inf"))

        if arcpy.Exists(lineStats):
            # Retrieve useful stats from table which are used to derive CHM attributes
            ChmFootprintCursor = arcpy.SearchCursor(lineStats)
            ChmFoot = ChmFootprintCursor.next()
            chm_count = float(ChmFoot.getValue("COUNT"))
            chm_area = float(ChmFoot.getValue("AREA"))
            chm_mean = float(ChmFoot.getValue("MEAN"))
            chm_std = float(ChmFoot.getValue("STD"))
            chm_sum = float(ChmFoot.getValue("SUM"))
            del ChmFootprintCursor

            # Average vegetation height directly obtained from CHM mean
            row.setValue("AvgHeight", chm_mean)

            # Cell area obtained via dividing the total area by the number of cells
            # (this assumes that the projection is UTM to obtain a measure in square meters)
            cellArea = chm_area / chm_count

            # CHM volume (3D) is obtained via multiplying the sum of height (1D) of all cells
            # of all cells within the footprint by the area of each cell (2D)
            row.setValue("Volume", chm_sum * cellArea)

            # The following math is performed to use available stats (fast) and avoid further
            # raster sampling procedures (slow).
            # RMSH is equal to the square root of the sum of the squared mean and
            # the squared standard deviation (population)
            # STD of population (n) is derived from the STD of sample (n-1).
            # This number is not useful by itself, only to derive RMSH.
            sqStdPop = math.pow(chm_std, 2) * (chm_count - 1) / chm_count

            # Obtain RMSH from mean and STD
            row.setValue("Roughness",
                         math.sqrt(math.pow(chm_mean, 2) + sqStdPop))

    rows.updateRow(row)

    del row, rows
    # Clean temporary files
    if arcpy.Exists(lineClip):
        arcpy.Delete_management(lineClip)
    if arcpy.Exists(lineStats):
        arcpy.Delete_management(lineStats)
def workLinesMem(segment_info):
    """
    New version of worklines. It uses memory workspace instead of shapefiles.
    The refactoring is to accelerate the processing speed.
    """

    # input verification
    if segment_info is None or len(segment_info) <= 1:
        print("Input segment is corrupted, ignore")

    outWorkspace = flmc.GetWorkspace(workspaceName)
    f = open(outWorkspace + "\\params.txt")

    outWorkspace = f.readline().strip()
    Input_Lines = f.readline().strip()
    Input_Footprint = f.readline().strip()
    Input_CHM = f.readline().strip()
    SamplingType = f.readline().strip()
    Segment_Length = float(f.readline().strip())
    Tolerance_Radius = float(f.readline().strip())
    LineSearchRadius = float(f.readline().strip())
    Attributed_Segments = f.readline().strip()
    areaAnalysis = True if f.readline().strip() == "True" else False
    heightAnalysis = True if f.readline().strip() == "True" else False
    f.close()

    line = [segment_info[0]]
    lineNo = segment_info[1]  # second element is the line No.
    attributes = segment_info[2]

    outWorkspaceMem = r"memory"
    arcpy.env.workspace = r"memory"

    # Temporary files
    lineSeg = os.path.join(outWorkspaceMem, "FLM_SLA_Segment_" + str(lineNo))
    lineBuffer = os.path.join(outWorkspaceMem, "FLM_SLA_Buffer_" + str(lineNo))
    lineClip = os.path.join(outWorkspaceMem, "FLM_SLA_Clip_" + str(lineNo))
    lineStats = os.path.join(outWorkspaceMem, "FLM_SLA_Stats_" + str(lineNo))

    # Create segment feature class
    try:
        arcpy.CreateFeatureclass_management(outWorkspaceMem,
                                            os.path.basename(lineSeg),
                                            "POLYLINE", Input_Lines,
                                            "DISABLED", "DISABLED",
                                            Input_Lines)
        cursor = arcpy.da.InsertCursor(lineSeg, ["SHAPE@"])
        cursor.insertRow([segment_info[0]])
        del cursor
    except Exception as e:
        print("Create feature class {} failed.".format(fileSeg))
        print(e)
        return

    if areaAnalysis:
        arcpy.Buffer_analysis(line,
                              lineBuffer,
                              LineSearchRadius,
                              line_side="FULL",
                              line_end_type="FLAT",
                              dissolve_option="NONE",
                              dissolve_field="",
                              method="PLANAR")
        arcpy.Clip_analysis(Input_Footprint, lineBuffer, lineClip)
        arcpy.Delete_management(lineBuffer)
        if heightAnalysis and arcpy.Exists(lineClip):
            try:
                arcpy.gp.ZonalStatisticsAsTable_sa(
                    lineClip,
                    arcpy.Describe(lineClip).OIDFieldName, Input_CHM,
                    lineStats, "DATA", "ALL")
            except Exception as e:
                lineStats = ""
                print(e)

    rows = arcpy.UpdateCursor(lineSeg)
    shapeField = arcpy.Describe(lineSeg).ShapeFieldName
    row = rows.next()

    feat = row.getValue(shapeField)  # creates a geometry object
    length = float(attributes["LENGTH"])  # creates a geometry object

    try:
        bearing = float(attributes["BEARING"])  # creates a geometry object
    except Exception as e:
        bearing = 0
        print(e)

    # TODO: retrieve vertices from line directly and remove lineSeg
    segmentnum = 0
    segment_list = []
    for segment in feat:  # loops through every segment in a line
        # loops through every vertex of every segment
        # get.PArt returns an array of points for a particular part in the geometry
        for pnt in feat.getPart(segmentnum):
            if pnt:  # adds all the vertices to segment_list, which creates an array
                segment_list.append(arcpy.Point(float(pnt.X), float(pnt.Y)))

    # Sinuosity calculation
    eucDistance = arcpy.PointGeometry(feat.firstPoint).distanceTo(
        arcpy.PointGeometry(feat.lastPoint))
    try:
        attributes["Sinuosity"] = length / eucDistance
    except Exception as e:
        attributes["Sinuosity"] = float("inf")
        print(e)

    # Direction based on bearing
    ori = "N-S"
    if 22.5 <= bearing < 67.5 or 202.5 <= bearing < 247.5:
        ori = "NE-SW"
    elif 67.5 <= bearing < 112.5 or 247.5 <= bearing < 292.5:
        ori = "E-W"
    elif 112.5 <= bearing < 157.5 or 292.5 <= bearing < 337.5:
        ori = "NW-SE"
    attributes["Direction"] = ori

    # If footprint polygons are available, get area-based variables
    if areaAnalysis:
        totalArea = float(attributes["POLY_AREA"])
        totalPerim = float(attributes["PERIMETER"])

        attributes["AvgWidth"] = totalArea / length

        try:
            attributes["Fragment"] = totalPerim / totalArea
        except Exception as e:
            attributes["Fragment"] = float("inf")

        if arcpy.Exists(lineStats):
            # Retrieve useful stats from table which are used to derive CHM attributes
            ChmFootprintCursor = arcpy.SearchCursor(lineStats)
            ChmFoot = ChmFootprintCursor.next()
            chm_count = float(ChmFoot.getValue("COUNT"))
            chm_area = float(ChmFoot.getValue("AREA"))
            chm_mean = float(ChmFoot.getValue("MEAN"))
            chm_std = float(ChmFoot.getValue("STD"))
            chm_sum = float(ChmFoot.getValue("SUM"))
            del ChmFootprintCursor

            # Average vegetation height directly obtained from CHM mean
            attributes["AvgHeight"] = chm_mean

            # Cell area obtained via dividing the total area by the number of cells
            # (this assumes that the projection is UTM to obtain a measure in square meters)
            cellArea = chm_area / chm_count

            # CHM volume (3D) is obtained via multiplying the sum of height (1D) of all cells
            # of all cells within the footprint by the area of each cell (2D)
            attributes["Volume"] = chm_sum * cellArea

            # The following math is performed to use available stats (fast) and avoid further
            # raster sampling procedures (slow).
            # RMSH is equal to the square root of the sum of the squared mean and
            # the squared standard deviation (population)
            # STD of population (n) is derived from the STD of sample (n-1).
            # This number is not useful by itself, only to derive RMSH.
            sqStdPop = math.pow(chm_std, 2) * (chm_count - 1) / chm_count

            # Obtain RMSH from mean and STD
            attributes["Roughness"] = math.sqrt(
                math.pow(chm_mean, 2) + sqStdPop)

    # Clean temporary files
    if arcpy.Exists(lineClip):
        arcpy.Delete_management(lineClip)
    if arcpy.Exists(lineStats):
        arcpy.Delete_management(lineStats)

    print("Line {} attributes calculation done.".format(lineNo))
    return [line, attributes]
Exemple #12
0
def main():
    global outWorkspace
    outWorkspace = flmc.SetupWorkspace(workspaceName)

    # Prepare input lines for multiprocessing
    numLines = flmc.SplitLines(Input_Feature_Class, outWorkspace, "ZT", False,
                               ThresholdField)

    pool = multiprocessing.Pool(processes=flmc.GetCores())
    flmc.log("Multiprocessing line zonal thresholds...")
    pool.map(workLines, range(1, numLines + 1))
    pool.close()
    pool.join()

    flmc.logStep("Line multiprocessing")

    flmc.log("Merging layers...")
    tempShapefiles = arcpy.ListFeatureClasses()

    arcpy.Merge_management(tempShapefiles, OutputLines)

    flmc.logStep("Merge")

    for shp in tempShapefiles:
        arcpy.Delete_management(shp)
Exemple #13
0
# Webpage: https://github.com/appliedgrg/flm
#
# Purpose: Assigns corridor thresholds to the input lines based on their
# surrounding canopy density
#
# ---------------------------------------------------------------------------

import multiprocessing
import arcpy
from arcpy.sa import *
arcpy.CheckOutExtension("Spatial")
import FLM_Common as flmc

# Setup script path and workspace folder
workspaceName = "FLM_ZT_output"
outWorkspace = flmc.GetWorkspace(workspaceName)
arcpy.env.workspace = outWorkspace
arcpy.env.overwriteOutput = True

# Load arguments from file
args = flmc.GetArgs("FLM_ZT_params.txt")

# Tool arguments
Input_Feature_Class = args[0].rstrip()
#ID_Field = args[1].rstrip()
ThresholdField = args[1].rstrip()
Canopy_Raster = args[2].rstrip()
Canopy_Search_Radius = float(args[3].rstrip())
MinValue = float(args[4].rstrip())
MaxValue = float(args[5].rstrip())
OutputLines = args[6].rstrip()
Exemple #14
0
def workLines(lineNo):
    # Temporary files
    outWorkspace = flmc.GetWorkspace(workspaceName)

    # read params from text file
    f = open(outWorkspace + "\\params.txt")
    Forest_Line_Feature_Class = f.readline().strip()
    Cost_Raster = f.readline().strip()
    Line_Processing_Radius = f.readline().strip()
    f.close()

    fileSeg = outWorkspace + "\\FLM_CL_Segment_" + str(lineNo) + ".shp"
    fileOrigin = outWorkspace + "\\FLM_CL_Origin_" + str(lineNo) + ".shp"
    fileDestination = outWorkspace + "\\FLM_CL_Destination_" + str(
        lineNo) + ".shp"
    fileBuffer = outWorkspace + "\\FLM_CL_Buffer_" + str(lineNo) + ".shp"
    fileClip = outWorkspace + "\\FLM_CL_Clip_" + str(lineNo) + ".tif"
    fileCostDist = outWorkspace + "\\FLM_CL_CostDist_" + str(lineNo) + ".tif"
    fileCostBack = outWorkspace + "\\FLM_CL_CostBack_" + str(lineNo) + ".tif"
    fileCenterLine = outWorkspace + "\\FLM_CL_CenterLine_" + str(
        lineNo) + ".shp"

    # Find origin and destination coordinates
    x1 = segment_list[0].X
    y1 = segment_list[0].Y
    x2 = segment_list[-1].X
    y2 = segment_list[-1].Y

    # Create origin feature class
    try:
        arcpy.CreateFeatureclass_management(outWorkspace, PathFile(fileOrigin),
                                            "POINT", Forest_Line_Feature_Class,
                                            "DISABLED", "DISABLED",
                                            Forest_Line_Feature_Class)
        cursor = arcpy.da.InsertCursor(fileOrigin, ["SHAPE@XY"])
        xy = (float(x1), float(y1))
        cursor.insertRow([xy])
        del cursor
    except Exception as e:
        print("Creating origin feature class failed: at X, Y" + str(xy) + ".")
        print(e)

    # Create destination feature class
    try:
        arcpy.CreateFeatureclass_management(outWorkspace,
                                            PathFile(fileDestination), "POINT",
                                            Forest_Line_Feature_Class,
                                            "DISABLED", "DISABLED",
                                            Forest_Line_Feature_Class)
        cursor = arcpy.da.InsertCursor(fileDestination, ["SHAPE@XY"])
        xy = (float(x2), float(y2))
        cursor.insertRow([xy])
        del cursor
    except Exception as e:
        print("Creating destination feature class failed: at X, Y" + str(xy) +
              ".")
        print(e)

    try:
        # Buffer around line
        arcpy.Buffer_analysis(fileSeg, fileBuffer, Line_Processing_Radius,
                              "FULL", "ROUND", "NONE", "", "PLANAR")

        # Clip cost raster using buffer
        DescBuffer = arcpy.Describe(fileBuffer)
        SearchBox = str(DescBuffer.extent.XMin) + " " + str(
            DescBuffer.extent.YMin) + " " + str(
                DescBuffer.extent.XMax) + " " + str(DescBuffer.extent.YMax)
        arcpy.Clip_management(Cost_Raster, SearchBox, fileClip, fileBuffer, "",
                              "ClippingGeometry", "NO_MAINTAIN_EXTENT")

        # Least cost path
        arcpy.gp.CostDistance_sa(fileOrigin, fileClip, fileCostDist, "",
                                 fileCostBack, "", "", "", "", "TO_SOURCE")
        arcpy.gp.CostPathAsPolyline_sa(fileDestination, fileCostDist,
                                       fileCostBack, fileCenterLine,
                                       "BEST_SINGLE", "")

    except Exception as e:
        print("Problem with line starting at X " + str(x1) + ", Y " + str(y1) +
              "; and ending at X " + str(x1) + ", Y " + str(y1) + ".")
        print(e)

    # Clean temporary files
    arcpy.Delete_management(fileSeg)
    arcpy.Delete_management(fileOrigin)
    arcpy.Delete_management(fileDestination)
    arcpy.Delete_management(fileBuffer)
    arcpy.Delete_management(fileClip)
    arcpy.Delete_management(fileCostDist)
    arcpy.Delete_management(fileCostBack)
def main():
    # Setup script path and output folder
    outWorkspace = flmc.SetupWorkspace("FLM_RLA_output")
    arcpy.env.workspace = outWorkspace
    arcpy.env.overwriteOutput = True

    # Load arguments from file
    args = flmc.GetArgs("FLM_RLA_params.txt")

    # Tool arguments
    Input_Lines = args[0].rstrip()
    Input_Raster = args[1].rstrip()
    SamplingType = args[2].rstrip()
    Measure_Interval = float(args[3].rstrip())
    Segment_Length = float(args[4].rstrip())
    Tolerance_Radius = float(args[5].rstrip())
    Sampling_Method = args[6].rstrip()
    Attributed_Segments = args[7].rstrip()

    # Local variables:
    FLM_RLA_Measure_Points = outWorkspace + "\\FLM_RLA_Measure_Points.shp"
    FLM_RLA_Attributed_Points = outWorkspace + "\\FLM_RLA_Attributed_Points.shp"

    flmc.log("Generating sample points along lines...")
    arcpy.GeneratePointsAlongLines_management(Input_Lines,
                                              FLM_RLA_Measure_Points,
                                              "DISTANCE", Measure_Interval, "",
                                              "")
    flmc.logStep("Spawning sample points")

    flmc.log("Extracting raster values at sample points...")
    arcpy.gp.ExtractValuesToPoints_sa(FLM_RLA_Measure_Points, Input_Raster,
                                      FLM_RLA_Attributed_Points)
    flmc.logStep("Raster sampling")

    # Find RASTERVALU field and set user defined sampling (merge) method
    fieldmappings = arcpy.FieldMappings()
    fieldmappings.addTable(FLM_RLA_Attributed_Points)
    RastervaluIndex = fieldmappings.findFieldMapIndex("RASTERVALU")
    fieldmap = fieldmappings.getFieldMap(RastervaluIndex)
    fieldmap.mergeRule = Sampling_Method  #Set sampling method (Mean, Minimum, Maximum, Standard Deviation, Etc..)
    fieldmappings = arcpy.FieldMappings()
    fieldmappings.addFieldMap(fieldmap)

    flmc.log("Splitting lines...")
    FLM_RLA_Segmented_Lines = flma.FlmLineSplit(outWorkspace, Input_Lines,
                                                SamplingType, Segment_Length,
                                                Tolerance_Radius)
    flmc.logStep("Line split")

    flmc.log("Generating raster statistics along line segments")
    arcpy.SpatialJoin_analysis(FLM_RLA_Segmented_Lines,
                               FLM_RLA_Attributed_Points, Attributed_Segments,
                               "JOIN_ONE_TO_ONE", "KEEP_COMMON", fieldmappings,
                               "INTERSECT", Tolerance_Radius, "")
Exemple #16
0
def main(version, tools, cols, rows, binSizes, binNames, binTips):
    """Creates tool selection screen and handles GUI loop"""

    master.title("Forest Line Mapper v." + str(version))
    # FLM Header
    lab = tk.Label(toolSelection, text="Forest Line Mapper", font=fontHeader)
    lab.pack(side=tk.TOP, fill=tk.X, padx=5, pady=0)
    lab = tk.Label(
        toolSelection,
        text=
        "A toolset for enhanced delineation and attribution of linear disturbances "
        "in forests. Copyright (C) 2021 Applied Geospatial Research Group.",
        font=fontText,
        wraplength=minWidth,
        justify=tk.LEFT)
    lab.pack(side=tk.TOP, fill=tk.X, padx=5, pady=0)
    AddSpace(toolSelection)

    # Create tool bins inside toolbox
    toolBox = tk.Frame(toolSelection,
                       highlightbackground="gray60",
                       highlightthickness=1)
    bins = []
    for i in range(0, cols):
        binCol = tk.Frame(toolBox)
        binCol.pack(side=tk.LEFT, fill=tk.BOTH, expand=tk.YES, padx=0, pady=0)
        c = []
        for j in range(0, rows):
            bin = tk.Frame(binCol)
            bin.pack(side=tk.TOP, fill=tk.X, padx=0, pady=8)
            binId = i * rows + j
            if binId < 5:
                binName = tk.Label(bin, text=binNames[binId], font=fontBold)
                binName.pack(side=tk.TOP, pady=0)
                ttp.CreateToolTip(binName, binTips[binId], wraplength=minWidth)
                c.append(bin)
        bins.append(c)

    binId = 0
    binLen = 0

    for tool in tools:
        # Figue out the bin where to place the tool
        if binLen >= binSizes[binId]:
            binId += 1
            binLen = 0
        col = int(binId / rows)
        row = binId % rows
        currentBin = bins[col][row]
        binLen += 1

        # Tool object
        currentTool = tool

        # Tool selection button
        row = tk.Frame(currentBin)
        but = tk.Button(row,
                        text=tool.title,
                        command=lambda tool=tool: tool.OpenTool())
        ttp.CreateToolTip(but, tool.description, wraplength=minWidth)
        but.pack(padx=5)
        row.pack(side=tk.TOP, fill=tk.X, padx=5, pady=5)

        # Tool screen and inputs
        toolScreen = tk.Frame(master)
        toolScreens.append(toolScreen)
        tool.SetupTool(toolScreen)

    currentTool = None
    toolBox.pack(side=tk.TOP, fill=tk.BOTH, expand=1, padx=5, pady=0)

    # Multiprocessing cores
    row = tk.Frame(toolSelection)
    lab = tk.Label(row, text="Multiprocessing Cores")
    ttp.CreateToolTip(
        lab,
        "The number of CPU cores to be used in parallel processes. Not all FLM tools use "
        "multiprocessing.\nFor the most part a larger number of cores will decrease processing time. "
        "Small application \nareas (<100 hectares) may work best with a smaller number of cores."
    )
    lab.pack(side=tk.LEFT, padx=5, pady=0)
    global mpc
    maxCores = multiprocessing.cpu_count()
    mpc = tk.Scale(row, from_=1, to=maxCores, orient="horizontal")
    mpc.set(flmc.GetCores())
    mpc.pack(side=tk.TOP, fill=tk.X, padx=5, pady=0)
    row.pack(side=tk.TOP, fill=tk.X, padx=5, pady=10)

    # Footer Buttons
    row = tk.Frame(toolSelection)
    but = tk.Button(row, text='EXIT', command=lambda: Exit())
    but.pack(side=tk.RIGHT, padx=5)
    but = tk.Button(row,
                    text='HELP',
                    command=lambda: webbrowser.open(help_url))
    but.pack(side=tk.RIGHT, padx=5)
    row.pack(side=tk.BOTTOM, fill=tk.X, padx=5, pady=10)
    toolSelection.pack(side=tk.TOP, fill=tk.BOTH, expand=1, padx=5, pady=0)

    master.protocol("WM_DELETE_WINDOW", Exit)
    tk.mainloop()
    return userExit
Exemple #17
0
def main():
    global outWorkspace
    outWorkspace = flmc.SetupWorkspace(workspaceName)

    if(HasField(Centerline_Feature_Class, Corridor_Threshold_Field) == False):
        flmc.log("ERROR: There is no field named "+Corridor_Threshold_Field+" in the input lines")
        return False

    # Prepare input lines for multiprocessing
    numLines = flmc.SplitLines(Centerline_Feature_Class, outWorkspace, "CFP", False, Corridor_Threshold_Field)

    pool = multiprocessing.Pool(processes=flmc.GetCores())
    flmc.log("Multiprocessing line corridors...")
    pool.map(workLines, range(1,numLines+1))
    pool.close()
    pool.join()

    flmc.logStep("Corridor footprint multiprocessing")

    flmc.log("Merging footprint layers...")
    tempShapefiles = arcpy.ListFeatureClasses()
    fileMerge = outWorkspace +"\\FLM_CFP_Merge.shp"
    arcpy.Merge_management(tempShapefiles,fileMerge)
    arcpy.Dissolve_management(fileMerge,Output_Footprint)
    for shp in tempShapefiles:
        arcpy.Delete_management(shp)
    arcpy.Delete_management(fileMerge)

    flmc.logStep("Merging")