1

I have a line layer and point layer on my ArcGIS project. The points are on the lines. I want to create vertex on lines at this point coordinates.

import arcpy

point_rows = arcpy.da.SearchCursor("D:\Test.gdb\MyPoints", ['OID@', 'SHAPE'])

rows = arcpy.UpdateCursor("D:\Test.gdb\MyLines")

for row in rows:
    geom = row.SHAPE
    for part in geom.getPart():
        for pnt in point_rows:
                row.X = pnt.X
                row.Y = pnt.Y
                rows.updateRow(row)

I could not add vertex on points, if point is on the line. How can I do this using arcpy?

4
  • Related 1: gis.stackexchange.com/questions/250263/… Aug 2, 2018 at 9:24
  • Related 2: gis.stackexchange.com/questions/81777/… Aug 2, 2018 at 9:25
  • Can you clarify the what your data really consists of? You say The points are on the lines. Are you saying you have multiple points on a single line or each line has a corresponding single point? If they are single points, do their row order correspond to the row order of the polyline? Do these points ever occur at the ends? Are these polylines joined at their ends such as in a road network? Do they overlap? Looking at the suggested code below people are making assumptions (not unreasonable) about the row order relationship. You need to describe your data if you want a robust solution.
    – Hornbydd
    Aug 3, 2018 at 14:30

4 Answers 4

1

Below is some python code that will take an un-ordered set of polylines with zero or more intersecting points and insert a vertex into the polyline at the point position.

Sample data

Sample data

This code is designed to be dropped into the Python console in ArcMap, simply change lineLayer and pointLayer.

import arcpy

# Layers in MXD
lineLayer = "fcLine"
pointLayer = "fcPoint"

with arcpy.da.UpdateCursor(lineLayer,['SHAPE@']) as lineCursor:
    for row in lineCursor:
        geom = row[0]

        # Get selected points along line, this could be zero, 1 or more
        arcpy.SelectLayerByLocation_management(pointLayer,"INTERSECT",geom,"#","NEW_SELECTION")
        res = arcpy.GetCount_management(pointLayer)
        n = int(res.getOutput(0))
        if n > 0:
            # We have at least 1 point intersecting line
            # Store selected point(s) in list for further processing
            pointList = []
            with arcpy.da.SearchCursor(pointLayer,['SHAPE@']) as pointCursor:
                for pointRow in pointCursor:
                    pointList.append(pointRow[0])
            print(str(len(pointList)) + " intersect current line.")

            # Convert polyline to points
            # Assumes line is simple geometry, i,e a single part
            lineArr = geom.getPart(0) # Returns an array
            for p in lineArr:
                pointList.append(arcpy.PointGeometry(p))

            # PointList is a list of PointGeometries composed of points on the line and points from the line itself
            # Now need to work out position of points along the line
            posDict = {}
            for p in pointList:
                pos = geom.measureOnLine(p,True)
                posDict[pos] = p

            # Reconstruct polyline by using sorted keys in posDict
            newArray = arcpy.Array()
            for key in sorted(posDict.iterkeys()):
                newArray.add(posDict[key].centroid) # Array takes points not PointGeometry, hence using centroid property
            newLine = arcpy.Polyline(newArray)

            # Insert updated geometry line back into dataset
            row[0] = newLine
            lineCursor.updateRow(row)
7
  • 1
    Thanks, your script worked as expected. Is there anyway to improve performance? It took about 5 minutes to add a point to 1100 lines.
    – GreyHippo
    Nov 29, 2018 at 16:43
  • @GreyHippo Don't think so, it's already using the faster cursor type and the logic excludes lines that do not have any intersecting points. You could try moving the layers into an IN_MEMORY workspace to see if performance is improved or if your source datasets are shapefiles make sure they have a spatial index.
    – Hornbydd
    Nov 29, 2018 at 16:57
  • Also after I run the command it takes a long time to save the MXD. Would your script cause something like that
    – GreyHippo
    Nov 29, 2018 at 18:11
  • If you perform this script on a 10 lines the MXD saves normally but if I perform the script on 200 lines then it takes a few minutes to save the MXD.
    – GreyHippo
    Nov 29, 2018 at 18:35
  • I just checked the MXD filesize and it is 64 mb after doing the script on 200 lines
    – GreyHippo
    Nov 29, 2018 at 18:36
0

I think I have a solution! I ve checked the following code and it works.

1) This example creates a Point Feature of the Vertices of your line with the help of Numpy Arrays (Numpy Needs to be installed)

2) Then it merges These Vertices as Points together with your 'points' on the line -> Theres one drawback: On the Output Pointfile of this merge you Need to create a new field and sort the Points in the right order (1-9 in this example) Otherwise the final line would look like a 'grinding by numbers' (but Ive found also examples to automate this too..

3) Finally a new line is created including the original line and the Points on the line

Feel free to ask me, in case you've got questions or some parts of the code dont work on your system

import arcpy, numpy, os

sr = arcpy.SpatialReference(25832)


### The Input: Your Points on the line (PointsLTW) // The line feature itself (InFcLine)

PointsLTW = r"C:\lineVerts\PointsLTW.shp"
InFcLine  = r"C:\\lineVerts\LineLTW.shp" # input feature class

OutFcLine = r"C:\lineVerts\LineLTW_out2.shp" # output feature class


print "Inputs accepted.."

# Creates a Point Array of your Line

arrayLine = arcpy.da.FeatureClassToNumPyArray(InFcLine,["SHAPE@XY"], "", sr, explode_to_points=True)

print "Numpy Array created.."

# ..in case no Array was created

if arrayLine.size == 0:
    arcpy.AddError(InFcLine + " contains no features!")

# From Array to Point Feature of your Input Line
else:
    arcpy.da.NumPyArrayToFeatureClass(arrayLine, OutFcLine, ['SHAPE@XY'], sr)
    print "New Multipoint Feature (LineToVertPoints) from Numpy Array.."

# Now you just merge your original PointsLTW with your original Line, now written as a Point Feature out of the lines Vertices

arcpy.Merge_management(inputs="PointsLTW;LineLTW_out2",output="C:/lineVerts/FinalPointsxx.shp",field_mappings="""Id "Id" true true false 6 Long 0 6 ,First,#,PointsLTW,Id,-1,-1,LineLTW_out2,Id,-1,-1""")

# Finally you create a line out of the merged points, the only drawback is that you need the Points to be sorted after the line Direction (From East to West or VV), I did this with a new field sorting the points by hand

arcpy.PointsToLine_management(r"C:/lineVerts/FinalPointsxx.shp" , r"D:\FinalLinexx.shp", "","sortedLTW")

enter image description here

-1

As the easiest way (not too much coding, but questionable performance) you might try to do this (ArcGIS Desktop Advanced license required):

  1. Use Split Line at Point tool to split the lines.
  2. Use Unsplit Line tool to merge the lines back.

As described in the description of the tool:

If Search Radius (search_radius in Python) is unspecified, the nearest point will be used to split the line feature. If a Search Radius is specified, all points within the search radius are used to split the line.

So by default Split Line at Point only works for ONE point per line. Other points on the line are ignored. But if you set huge Search Radius all points will split the line.

________Before_____________________ Splitted_____________________ UNsplitted

before_________ splitted_________ UNsplitted

This code should do the job (not tested):

import arcpy

points = r"D:\Test.gdb\MyPoints"
lines = r"D:\Test.gdb\MyLines"
splitted = r"D:\Test.gdb\MySplittedLines"
unsplitted = r"D:\Test.gdb\MyUnSplittedLines"
searchRadius = "9999999999999999999 Meters"

arcpy.SplitLineAtPoint_management(lines, points, splitted, searchRadius)
arcpy.UnsplitLine_management(splitted, unsplitted)
4
  • But Split and Unsplit does not create verticies on line.
    – barteloma
    Aug 2, 2018 at 10:58
  • aplit and unsplid operations recreates objects and changes the objectid's
    – barteloma
    Aug 2, 2018 at 14:16
  • @barteloma You can copy ID's to a new field before the operation. Aug 3, 2018 at 4:09
  • I have an error: 'The tool is not licensed. Failed to execute' So I need using update.
    – barteloma
    Aug 3, 2018 at 5:41
-2

I think you had your geometry token for your points wrong. It should have come as "Shape@".

The code can be written as :

    Import arcpy 
    # Setting path 
    arcpy.env.workspace = "path" 
    # This line of code returns x, and y as tuple. 
    with arcpy.da.searchCursor("Feature/Table",['OID@','Shape@']) as /
    point_cursor
    for row in point_cursor: 
       pnt.X,pnt.Y = row[1]
       print('{},{}'.format(pnt.X,pnt.Y)) 
       ## The first code reads the x,y of the point layer 
       ### The next code is to write the point x,y on the line 
       with arcpy.InsertCursor('Feature/Table',"Shape@") as line_cursor 
         array = arcpy.array([pnt.X,pnt.Y]) 
         Line_ = arcpy.polyline(array) 
         line_cursor.insertRow([Line_])
2
  • 1
    This code appears not to insert the point into the line, in fact as I read it, it INSERTS not UPDATES a polyline and actually fails by inserting a line consisting of 1 vertex which makes no sense.
    – Hornbydd
    Aug 3, 2018 at 15:55
  • You answer has multiple syntax errors
    – BERA
    Nov 8 at 13:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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