import arcpy, sys, string, os, fpformat mxd = arcpy.mapping.MapDocument("CURRENT") layers = arcpy.mapping.ListLayers(mxd) for layer in layers: if layer.name == "3dLine": layerexists = 1 fields = ["SHAPE@Z","FromLevel","ToLevel"] if layerexists == 1: strLineFC = "3dLine" lineRows = arcpy.da.UpdateCursor(strLineFC, fields) lineRow = lineRows.next() while lineRow: linePointsArray = lineRow.Shape.getPart(0) pt_count = linePointsArray.count pt_begin = linePointsArray.next() # First Vertex on line row[0] = row[1] vertices = 2 while vertices < pt_count: pt_end = linePointsArray.next() vertices = vertices + 1 pt_end = linePointsArray.next() # Last Vertex on line row[0] = row[2]
Solved! Go to Solution.
Hi all,
I have some Z-enabled lines that have no values currently set in the Z property, however I have FromLevel and ToLevel fields as attributes in the feature class. I'd like to have a script that loops through all my lines and populates the Start Vertex with the value in the "FromLevel" field, and the End Vertex with the value in the "ToLevel" field. Is this possible? I started playing around with an UpdateCursor as I thought this would be the quickest/easiest way to get it done, but am unsure how to write to the Z property through the UpdateCursor.
I'm using ArcGIS Desktop 10.2.2import arcpy, sys, string, os, fpformat mxd = arcpy.mapping.MapDocument("CURRENT") layers = arcpy.mapping.ListLayers(mxd) for layer in layers: if layer.name == "3dLine": layerexists = 1 fields = ["SHAPE@Z","FromLevel","ToLevel"] if layerexists == 1: strLineFC = "3dLine" lineRows = arcpy.da.UpdateCursor(strLineFC, fields) lineRow = lineRows.next() while lineRow: linePointsArray = lineRow.Shape.getPart(0) pt_count = linePointsArray.count pt_begin = linePointsArray.next() # First Vertex on line row[0] = row[1] vertices = 2 while vertices < pt_count: pt_end = linePointsArray.next() vertices = vertices + 1 pt_end = linePointsArray.next() # Last Vertex on line row[0] = row[2]
This tells me there is no Shape property to get the vertex info from... (this script was butchered from another similar script, however that script writes to an attribute, not the Z property, and uses arcpy.updatecursor not arcpy.da.updatecursor. Can I write to the Z property through the arcpy.updatecursor?
I'd appreciate any tips/suggestions to allow me to do this.
Cheers,
Mike.
import arcpy infc = arcpy.GetParameterAsText(0) # the input line feature class # Enter for loop for each feature # with arcpy.da.UpdateCursor(infc, ["SHAPE@", "FromLevel", "ToLevel"]) as update_cursor: for row in update_cursor: array = arcpy.Array() partNum = 0 firstpnt = row[0].firstPoint lastpnt = row[0].lastPoint pntnum = 0 for part in row[0]: partArr = arcpy.Array() for pnt in part: if pnt: if partNum == 0 and firstpnt == pnt: # Modify Z value of the first point pnt.Z = row[1] if partNum == lastpart - 1 and lastpnt == pnt: # Z value of the last point pnt.Z = row[2] partArr.add(point) array.add(partArr) partNum += 1 new_line = arcpy.Polyline(array) row[0] = new_line update_cursor.updateRow(row) del update_cursor
Hi all,
I have some Z-enabled lines that have no values currently set in the Z property, however I have FromLevel and ToLevel fields as attributes in the feature class. I'd like to have a script that loops through all my lines and populates the Start Vertex with the value in the "FromLevel" field, and the End Vertex with the value in the "ToLevel" field. Is this possible? I started playing around with an UpdateCursor as I thought this would be the quickest/easiest way to get it done, but am unsure how to write to the Z property through the UpdateCursor.
I'm using ArcGIS Desktop 10.2.2import arcpy, sys, string, os, fpformat mxd = arcpy.mapping.MapDocument("CURRENT") layers = arcpy.mapping.ListLayers(mxd) for layer in layers: if layer.name == "3dLine": layerexists = 1 fields = ["SHAPE@Z","FromLevel","ToLevel"] if layerexists == 1: strLineFC = "3dLine" lineRows = arcpy.da.UpdateCursor(strLineFC, fields) lineRow = lineRows.next() while lineRow: linePointsArray = lineRow.Shape.getPart(0) pt_count = linePointsArray.count pt_begin = linePointsArray.next() # First Vertex on line row[0] = row[1] vertices = 2 while vertices < pt_count: pt_end = linePointsArray.next() vertices = vertices + 1 pt_end = linePointsArray.next() # Last Vertex on line row[0] = row[2]
This tells me there is no Shape property to get the vertex info from... (this script was butchered from another similar script, however that script writes to an attribute, not the Z property, and uses arcpy.updatecursor not arcpy.da.updatecursor. Can I write to the Z property through the arcpy.updatecursor?
I'd appreciate any tips/suggestions to allow me to do this.
Cheers,
Mike.
import arcpy infc = arcpy.GetParameterAsText(0) # the input line feature class # Enter for loop for each feature # with arcpy.da.UpdateCursor(infc, ["SHAPE@", "FromLevel", "ToLevel"]) as update_cursor: for row in update_cursor: array = arcpy.Array() partNum = 0 firstpnt = row[0].firstPoint lastpnt = row[0].lastPoint pntnum = 0 for part in row[0]: partArr = arcpy.Array() for pnt in part: if pnt: if partNum == 0 and firstpnt == pnt: # Modify Z value of the first point pnt.Z = row[1] if partNum == lastpart - 1 and lastpnt == pnt: # Z value of the last point pnt.Z = row[2] partArr.add(point) array.add(partArr) partNum += 1 new_line = arcpy.Polyline(array) row[0] = new_line update_cursor.updateRow(row) del update_cursor
You cannot write to the coordinate properties of a polyline without rewriting the entire polyline geometry. You have to convert the polyline to a point array. You can modify the coordinate properties of the points in the array and write use that array to overwrite the polyline geometry. Frankly there is no good help on how to do this and ESRI should provide a real example of how to modify a geometry other than a point geometry.Hi Richard,
The code below is based on post number 6 of this post from Matthew Coyle and post number 4 of this post by Xander Bakker. The code is untested and I am not sure if my method of attempting to find the first and last points is going to work.
import arcpy, fpformat targetLayer = "MyLayer" shapeFieldName = 'SHAPE' cursor = arcpy.UpdateCursor(targetLayer) for row in cursor: try: geom = row.getValue(shapeFieldName) fromLevel = fpformat.fix(row.FromLevel,2) # Round levels toLevel = fpformat.fix(row.ToLevel,2) # Round levels geomArr = arcpy.Array() for part in geom: partArr = arcpy.Array() pnt_count = part.count # Count Vertices pntNum = 0 for pnt in part: if pnt: if pntNum == 0: # Start Point (first vertex) pntOut = arcpy.Point(pnt.X, pnt.Y, fromLevel) partArr.add(pntOut) pntNum = pntNum + 1 elif pntNum == (pnt_count - 1): # End Point (last vertex) pntOut = arcpy.Point(pnt.X, pnt.Y, toLevel) partArr.add(pntOut) pntNum = pntNum + 1 elif pntNum < (pnt_count - 1): # Any additional vertices pntOut = arcpy.Point(pnt.X, pnt.Y, pnt.Z) partArr.add(pntOut) pntNum = pntNum + 1 geomArr.add(partArr) polyline = arcpy.Polyline(geomArr) row.setValue(shapeFieldName, polyline) cursor.updateRow(row) except: arcpy.AddMessage("Error " + str(row.objectid)) del row del cursor
This code will only work if your polylines have no true curves. True curves would be destroyed by this code.
You should also put in a test to check the assumption that the line only has 2 vertices. For lines with more than 2 vertices, the resultant 3D line with start and end Z values set will look very wonky since any intermediate vertices will have no Z value.Thanks Tim, I've put in a check for extra vertices and at this stage I'm only putting the Z onto the start/end, however if it becomes an issue I may need to interpolate the values in between. That'll be my next problem I guess 😄
Hopefully I don't 🙂 I don't know of any, but since most of my data comes from external sources there may be some. I'll check though, thanks for the tip.
Cheers,
Mike.
Thanks Tim, I've put in a check for extra vertices and at this stage I'm only putting the Z onto the start/end, however if it becomes an issue I may need to interpolate the values in between. That'll be my next problem I guess 😄
Cheers,
Mike.