Centroidal Longest Flowpath (Not GeoHMS)

5235
5
Jump to solution
07-11-2015 02:34 PM
PeterWilson
Occasional Contributor III

I've re-written my ArcHydro models (Model Builder) into Python and the only part of my model that I've note been able to convert is the Centroidal Longest Flowpath within the Basin Characteristics Toolbox. The explanation under the HEC-GeoHMS user manual (HEC-GeoHMS Manual😞

"This operation computes the centroidal longest flowpath by projecting the centroid onto the longest flowpath. The centroidal longest flowpath is measured from the projected point onto the longest flowpath to the subbasin outlet as shown in Figure 9-13"

CentroidalLongestFlowPath.JPG

I've searched the internet and have not been able to find an alternative solution to replace the following tool found within the HEC-GeoHMS : Basin Characteristics Toolbox. I'm hoping that someone within the ESRI community have found an alternative script or has written a script to achieve the same functionality as the HEC-GeoHMS: Centroidal Longest Flowpath.

Any advice in how to write a python function to replace the following HEC-GeoHMS: Centroidal Longest Flowpath would really be appreciated.

Regards

Peter Wilson

Tags (1)
1 Solution

Accepted Solutions
XanderBakker
Esri Esteemed Contributor

OK, so if you use a snippet like this one:

def main():
    import arcpy

    fc_pnt = r"C:\Forum\LongestFlowPath\data.gdb\centroid"
    fc_lin = r"C:\Forum\LongestFlowPath\data.gdb\flowpath"

    # get the first point and first polyline
    point = [r[0] for r in arcpy.da.SearchCursor(fc_pnt, ("SHAPE@"))][0]
    polyline = [r[0] for r in arcpy.da.SearchCursor(fc_lin, ("SHAPE@"))][0]

    # get the tuple
    tpl = polyline.queryPointAndDistance(point, False)
    print tpl

if __name__ == '__main__':
    main()

It will return:

(<PointGeometry object at 0x2233e70[0x2233480]>, 590.9600881822321, 190.0152317659558, True)

Which means: (point on line, distance from start, distance to line, bool right side of line), which makes sense, since it is the same as ArcObjects does.

To expand the code to extract the longest flow path you can do this:

def main():
    import arcpy

    fc_pnt = r"C:\Forum\LongestFlowPath\data.gdb\centroid"
    fc_lin = r"C:\Forum\LongestFlowPath\data.gdb\flowpath"

    # get the first point and first polyline
    point = [r[0] for r in arcpy.da.SearchCursor(fc_pnt, ("SHAPE@"))][0]
    polyline = [r[0] for r in arcpy.da.SearchCursor(fc_lin, ("SHAPE@"))][0]

    # get the tuple
    tpl = polyline.queryPointAndDistance(point, False)

    # to extract the part from the point on the line to the end:
    lfp = polyline.segmentAlongLine(tpl[1], polyline.length, False)
    arcpy.CopyFeatures_management([lfp], r"C:\Forum\LongestFlowPath\data.gdb\lfp")

    # point on line
    arcpy.CopyFeatures_management([tpl[0]], r"C:\Forum\LongestFlowPath\data.gdb\projected_pnt")

if __name__ == '__main__':
    main()

This is what it looks like:

View solution in original post

5 Replies
XanderBakker
Esri Esteemed Contributor

Let me see if I understand this correctly, you have:

  • Input Subbasin
  • Input Centroid
  • Input Longest Flow Path

... and the tools creates:

  • Output Centroidal Longest Flow Path

I guess the Centroid is used to select the Subbasin which on it's turn is used to select the longest flow path(s) that correspond to that subbasin. You will probably want to select the nearest flow path (?) and project the point onto this line.

To project the point on the line the :

arcpy.Polyline().queryPointAndDistance (in_point, {as_percentage})

... offers the functionality for this. It will find the point on the polyline nearest to the centroid and return a tuple with among others "the distance along the line where the nearest point occurs". This in combination with the length of the line can be used to determine the Longest Flow Path.

0 Kudos
PeterWilson
Occasional Contributor III

Hi Xander

Thanks for getting back to me. Would it be possible  to generate a new feature based on the projection of the point onto the longest flow path. I'm struggling to figure out how I would either split the existing line and keep the segment below the points position or generate a new polyline up to the points position. Any suggestions would be appreciated.

0 Kudos
XanderBakker
Esri Esteemed Contributor

Hi Peter Wilson ,

The Polyline::queryPointAndDistance (in_point, {as_percentage}) returns a tuple with the projected point on the line. and the percentage or length (depending the as_percentage parameter) of that point on the line. The documentation is not clear on how the tuple is constructed and in which order the results are listed, but I'll do a small test and get back to you on that.

If you have the length or percentage the Polyline::segmentAlongLine (start_measure, end_measure, {use_percentage}) can be used to extract the polyline corresponding to the Longest Flow Path.

Kind regards, Xander

0 Kudos
XanderBakker
Esri Esteemed Contributor

OK, so if you use a snippet like this one:

def main():
    import arcpy

    fc_pnt = r"C:\Forum\LongestFlowPath\data.gdb\centroid"
    fc_lin = r"C:\Forum\LongestFlowPath\data.gdb\flowpath"

    # get the first point and first polyline
    point = [r[0] for r in arcpy.da.SearchCursor(fc_pnt, ("SHAPE@"))][0]
    polyline = [r[0] for r in arcpy.da.SearchCursor(fc_lin, ("SHAPE@"))][0]

    # get the tuple
    tpl = polyline.queryPointAndDistance(point, False)
    print tpl

if __name__ == '__main__':
    main()

It will return:

(<PointGeometry object at 0x2233e70[0x2233480]>, 590.9600881822321, 190.0152317659558, True)

Which means: (point on line, distance from start, distance to line, bool right side of line), which makes sense, since it is the same as ArcObjects does.

To expand the code to extract the longest flow path you can do this:

def main():
    import arcpy

    fc_pnt = r"C:\Forum\LongestFlowPath\data.gdb\centroid"
    fc_lin = r"C:\Forum\LongestFlowPath\data.gdb\flowpath"

    # get the first point and first polyline
    point = [r[0] for r in arcpy.da.SearchCursor(fc_pnt, ("SHAPE@"))][0]
    polyline = [r[0] for r in arcpy.da.SearchCursor(fc_lin, ("SHAPE@"))][0]

    # get the tuple
    tpl = polyline.queryPointAndDistance(point, False)

    # to extract the part from the point on the line to the end:
    lfp = polyline.segmentAlongLine(tpl[1], polyline.length, False)
    arcpy.CopyFeatures_management([lfp], r"C:\Forum\LongestFlowPath\data.gdb\lfp")

    # point on line
    arcpy.CopyFeatures_management([tpl[0]], r"C:\Forum\LongestFlowPath\data.gdb\projected_pnt")

if __name__ == '__main__':
    main()

This is what it looks like:

DuncanHornby
MVP Notable Contributor

It's worth emphasising that the method segmentAlongLine returns the polyline segment between start and end measure on a single polyline. If the river is composed of polylines joining at nodes which is typical of say a geometric network it could not return a segment that followed the river downstream beyond it's To-end. If Peter wanted a line that went beyond the end of a polyline he either has to prepare the main stem by dissolving the polylines into a single route  and use your code or traverse a network.