Unfortunately you can't directly assign new values to the existing geometry of a feature - rather, you have to create a new geometry object, and update the shape field of the feature with that new object. Fortunately, the array objects have a replace
method. So rather than trying to directly modify the X coord of the point inside the array, you need to:
- Create a new
arcpy.Point
object with the correct coordinates (looks like you might have done this already)
- Get a copy of the array object stored in the row's Shape field
- Use the
replace
method to set the desired point in your array with your modified point
- Make a new Polyline object with that array
- Use the row object's
setValue
method to update the Shape field with your new, correct Polyline
- Use the cursor object's
updateRow
method to insert the changed row into the dataset.
Concretely:
for r in cur:
ary = r.getValue("SHAPE").getPart(0)
ary.replace(0,correct_point_object) # first arg 0 replaces the first point in the line
newLine = arcpy.Polyline(ary)
r.setValue("SHAPE",newLine)
cur.updateRow(r)
Note the replace
method takes an index and a value. Unfortunately it doesn't accept e.g. -1 as an index to the last point in the array. However you can say my_array[my_array.count]
.
It looks like you're precomputing the X-coordinates somewhere else and retrieving them later. If this is the case, I'd probably go the whole hog and create new Polyline objects with the correct points for each line while you're computing the correct coordinates. This will likely be easier & cleaner. That way your code could be more like
row_num = 0
for r in cur:
r.setValue(shapeField,correct_geometry_list[row_num])
cur.updateRow(r)
row_num += 1
Which, at least for me, is a bit more clear... but that's stylistic!
Edit to add:
I couldn't fit this in a comment. Without seeing your code it's hard to tell where it might be falling over. Here's a complete tested script which works for me. Hopefully it will serve as a reference. Note that here I'm calculating the new geometry directly from the old one, rather than doing two passes; that may or may not be possible depending on how you're doing your snap position calculations. Also this time I'm constructing a brand new array based on the old one rather than using the replace
method, in case that's necessary.
import arcpy
def offsetPoint(old_point,X_distance,Y_distance):
"""Trivial function to offset a point - replace with what you're
actually doing."""
new_point = arcpy.Point(old_point.X+X_distance,
old_point.Y+Y_distance)
return new_point
def offsetFirstPointInLine(line_geom,X_distance,Y_distance):
"""Takes a Polyline geometry object and returns a new Polyline with
the first point of the first part offset by the distance given."""
array = line_geom.getPart(0)
first_point = array[0]
new_point = offsetPoint(first_point,X_distance,Y_distance)
# Build a new array with your new point in the 0th position, and
# the rest of the points from the old array.
new_array = arcpy.Array([new_point]+
[array.getObject(x) for x in range(1,array.count)])
# Then make a new Polyline object with that array.
new_line = arcpy.Polyline(new_array)
return new_line
fc = r"C:\Users\student\Documents\ArcGIS\Default.gdb\SomeStorms"
cur = arcpy.UpdateCursor(fc)
for r in cur:
geom = r.getValue("SHAPE")
r.setValue("SHAPE",offsetFirstPointInLine(geom,-45000,-5000))
cur.updateRow(r)
del r,cur
Hopefully that helps clear it up.
This reads a table (Excel sheet in this case, but could be any table type) that looks like so:
S_X is start X point, E_X end X point, same for Y's. We iterate through the input table, then for each row, set the start/end X/Ys into a point, add that point to an array, then create a polyline from the array of two points. Then insert into the featureclass. Rinse and repeat.
import arcpy
in_rows = arcpy.SearchCursor(r"D:\Temp\Lines.xls\Sheet1$")
point = arcpy.Point()
array = arcpy.Array()
featureList = []
cursor = arcpy.InsertCursor(r"D:\Temp\Lines.shp")
feat = cursor.newRow()
for in_row in in_rows:
# Set X and Y for start and end points
point.X = in_row.S_X
point.Y = in_row.S_Y
array.add(point)
point.X = in_row.E_X
point.Y = in_row.E_Y
array.add(point)
# Create a Polyline object based on the array of points
polyline = arcpy.Polyline(array)
# Clear the array for future use
array.removeAll()
# Append to the list of Polyline objects
featureList.append(polyline)
# Insert the feature
feat.shape = polyline
cursor.insertRow(feat)
del feat
del cursor
And you get your lines:
Best Answer
Your code looks OK, but you use lower case x and y instead of upper case X and Y. Maybe that could help...
Also, I recommend using
arcpy.da.InsertCursor
if you have ArcGIS 10.1 or higher, for example :