8

I have been working on a project tracing lines in a geometric network. I have had to reverse the line (flow) direction on many lines to make the traces work. Now I am at a point where I have to update the master dataset, and so make those same line reversals in the database.

My thought is that I'd run a small arcpy script to check the to/from XY for every line against the to/from of the matching lines in the master dataset - any that have the to XY matching the master from XY (and vice-versa) would be recorded for flipping.

Although I think this script shouldn't be too difficult to write, I am now wondering whether there is a tool already available that will identify the flipped lines for me? I haven't been able to find one in ArcToolbox yet, but I may be looking for the wrong thing.

Note there are other geometry changes in my dataset that I don't want to find, just identical matching lines (matched on an ID) where the only difference is direction. Lines where XY is different I want to ignore.

For example, the follow lines showing line direction

enter image description here

The lines in the blue area I want to take note of, the only difference is the line direction. The line in the red area I do not want recorded as the line has actually moved.

enter image description here

Is there a tool in ArcGIS Desktop (10.5) that can identify lines that have been flipped, but ignore other geometry changes? If so, which one?

I have just found the "Detect Feature Changes" tool, which I am testing right now (it is very very slow). I am unsure whether this is going to find just flipped lines, or everything. Of course I may have set the parameters incorrectly.

The Detect Feature Changes tool finished processing - took close to 20 minutes to run - but only found 9 features where the line direction had changed. I am expecting at least 10000 flipped features.

  • I am surprised it found any, because it treats flipped lines as identical. – FelixIP Sep 14 '17 at 19:53
  • 1
    @FelixIP Checking for flipped lines is one of the options in the tool, and it identifies them in the output differently – Midavalo Sep 14 '17 at 19:54
  • I see. Anyway you first idea is what I do. Assign from and to nodes to both sets and bring old pair to new. It is possible that flip tool inside fgdb Results in slightly different vertices. Not a case with shapefiles. – FelixIP Sep 14 '17 at 20:03
  • Could you update a field with the line's azimuth and join it to the original and compare differences in that field? – Fezter Sep 14 '17 at 22:05
  • Select identical, then Using a SHAPE@ cusror and the arcpy.geometry object you can get the line.firstPoint. this will reselect the ones you want. – Ben S Nadler Sep 15 '17 at 4:13
3
+50

I would use a dictionary to do that. I'm surprised how fast they are.

import arcpy 

def GetDict(fc,precision):
    fields = ['SHAPE@','OID@']
    # use a dictionary with x1-y1-xn-yn key
    dict = {}
    with arcpy.da.SearchCursor(fc, fields) as cursor:
        for row in cursor:
            fpx = round(row[0].firstPoint.X,precision)
            fpy = round(row[0].firstPoint.Y,precision)
            lpx = round(row[0].lastPoint.X,precision)
            lpy = round(row[0].lastPoint.Y,precision)
            key= u'{0}-{1}-{2}-{3}'.format(fpx,fpy,lpx,lpy)
            if not dict.has_key(key):
                dict[key] = row[0]
    return dict

def GetOIDsOfLinesInNeedofFlipping(fc,dict,precision):
    fields = ['SHAPE@','OID@']
    flipoids = []
    changedoids = [] # polyline has been more than just flipped
    with arcpy.da.SearchCursor(fc, fields) as cursor:
        for row in cursor:
            fpx = round(row[0].firstPoint.X,precision)
            fpy = round(row[0].firstPoint.Y,precision)
            lpx = round(row[0].lastPoint.X,precision)
            lpy = round(row[0].lastPoint.Y,precision)
            ftkey= u'{0}-{1}-{2}-{3}'.format(fpx,fpy,lpx,lpy)
            tfkey= u'{0}-{1}-{2}-{3}'.format(lpx,lpy,fpx,fpy)
            if not dict.has_key(ftkey):
                if dict.has_key(tfkey):
                    flipoids.append(row[1])
                else:
                    changedoids.append(row[1])
    if len(changedoids) > 0:
        print(u'these are not the {0} oids you are looking for'.format(len(changedoids)))
    return flipoids

def FlipPolylines(fc,oids):
    fields = ['SHAPE@','OID@']
    with arcpy.da.UpdateCursor(fc, fields) as cursor:
        for row in cursor:
            if row[1] in oids:
                # https://gis.stackexchange.com/a/67422/59
                if row[0].partCount > 1: 
                    print "Warning: multiple parts! extra parts are automatically trimmed!"
                lp= row[0].getPart(0)
                rPnts=arcpy.Array()
                for i in range(len(lp)): rPnts.append(lp[len(lp)-i-1])
                rPoly=arcpy.Polyline(rPnts)
                row[0] = rPoly
                cursor.updateRow(row)
    return

def main():
    precision = 1
    dict = GetDict(r'H:\filegdbs\sewer.gdb\sewermains',precision) #the "master"
    print(u'keys = {0}'.format(len(dict)))
    oids = GetOIDsOfLinesInNeedofFlipping(r'H:\filegdbs\sewer.gdb\sewermainsflipped',dict,precision)
    print(u'{0} polylines need flipping'.format(len(oids)))
    if len(oids) > 0:
        FlipPolylines(r'H:\filegdbs\sewer.gdb\sewermainsflipped',oids)
    else:
        print("none need flipping")
    return


if __name__ == '__main__':
    main()
  • I actually managed to solve this myself at the time but forgot to update with an answer. I'm going to see if I can find what I produced and compare it to this one :) – Midavalo Nov 29 '17 at 22:26
  • 'these are not the {0} oids you are looking for'! LOL. – Fezter Jul 24 '18 at 2:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.