Wednesday 27 June 2018

arcgis 10.0 - Creating script tool that will create copy of feature class and offset it by given distance using ArcPy?


I want to duplicate a polygon feature class and offset all of the polygons by about 10 feet in both the x and y directions. I asked if there was any way to do this last week, and I was informed that I would most likely need to make my own python script using arcpy. I made my own script using arcpy, but it isn't working:


import arcpy
from arcpy import env
import os

env.overwriteOutput = True

# Get arguments:
# Input polygon feature class

# Output polygon feature class
#
inputFeatureClass = arcpy.GetParameterAsText(0)
outputFeatureClass = arcpy.GetParameterAsText(1)
xShift = arcpy.GetParameterAsText(2)
yShift = arcpy.GetParameterAsText(3)

shapeName = arcpy.Describe(inputFeatureClass).shapeFieldName

# Create the output feature class with the same fields and spatial reference as the input feature class

arcpy.CreateFeatureclass_management(os.path.dirname(outputFeatureClass), os.path.basename(outputFeatureClass), "POLYGON", inputFeatureClass, "", "", inputFeatureClass)

# Create a search cursor to iterate through each row of the input feature class
inrows = arcpy.SearchCursor(inputFeatureClass)
# Create an insert cursor to insert rows into the output feature class
outrows = arcpy.InsertCursor(outputFeatureClass)

# Create empty Point and Array objects
pntArray = arcpy.Array()
partArray = arcpy.Array()


# Loop through each row/feature
for row in inrows:
# Create the geometry object
feature = row.getValue(shapeName)

partnum = 0

# Count the total number of points in the current multipart feature
partcount = feature.partCount



while partnum < partcount:
part = feature.getPart(partnum)
pnt = part.next()
pntcount = 0

# Enter while loop for each vertex
#
while pnt:


pnt = part.next()
shiftedPoint = arcpy.Point()
try:
shiftedPoint.ID = pnt.ID
shiftedPoint.X = pnt.X + float(xShift)
shiftedPoint.Y = pnt.Y + float(yShift)
except AttributeError:
continue
#shiftedPoint = arcpy.Point(float(pnt.X) + float(xShift), float(pnt.Y) + float(yShift))

pntArray.add(shiftedPoint)
pntcount += 1

# If pnt is null, either the part is finished or there is an
# interior ring
#
if not pnt:
pnt = part.next()
if pnt:
arcpy.AddMessage("Interior Ring:")

# Create a polygon using the array of points
polygon = arcpy.Polygon(pntArray)

# Empty the array for the next run through the loop
pntArray.removeAll()

# Add the polygons (or 'parts') to an array. This is necessary for multipart features, or those with holes cut in them
partArray.add(polygon)
arcpy.AddMessage("Added a polygon to the partArray!")
partnum += 1


# Create a new row object that will be inserted into the ouput feature class. Set newRow = row so that it has the same attributes
# Set newRow.shape = partArray so that the only thing different about this new feature is that its geometry is different (shifted)
newRow = row
newRow.shape = partArray

outrows.insertRow(newRow)

# Empy the array for the next run through the loop
partArray.removeAll()


del inrows, outrows

I keep getting this error on line 70


: Array: Add input not point nor array object

I can't figure out why it's giving me this error, since I defined the input as an array.


Does anyone know why I'm getting this error?



Answer



Instead of creating and trying to add a polygon to your array, add your array of points to the array of parts. Change this:



polygon = arcpy.Polygon(pntArray)
pntArray.removeAll()
partArray.add(polygon)

To this:


partArray.add(pntArray)
pntArray.removeAll()

Also, there's a problem with your code that tries to insert the row. You need to use your insert cursor to create a new row and insert it. Starting at line 77 in your original code sample:


newRow = outrows.newRow()

newRow.shape = partArray
outrows.insertRow(newRow)

Edit: You should also move the "pnt = part.next()" in your inner while loop to below your try/except block so you don't skip any points and so that the if block that tests for interior rings runs. As is, the code in your post will not pick up interior rings. Here's the whole thing after all the modifications I've described:


import arcpy
from arcpy import env
import os

env.overwriteOutput = True


# Get arguments:
# Input polygon feature class
# Output polygon feature class
#
inputFeatureClass = arcpy.GetParameterAsText(0)
outputFeatureClass = arcpy.GetParameterAsText(1)
xShift = arcpy.GetParameterAsText(2)
yShift = arcpy.GetParameterAsText(3)
print '\nparams: ', inputFeatureClass, outputFeatureClass, xShift, yShift, '\n'


shapeName = arcpy.Describe(inputFeatureClass).shapeFieldName

# Create the output feature class with the same fields and spatial reference as the input feature class
if arcpy.Exists(outputFeatureClass):
arcpy.Delete_management(outputFeatureClass)
arcpy.CreateFeatureclass_management(os.path.dirname(outputFeatureClass), os.path.basename(outputFeatureClass), "POLYGON", inputFeatureClass, "", "", inputFeatureClass)

# Create a search cursor to iterate through each row of the input feature class
inrows = arcpy.SearchCursor(inputFeatureClass)
# Create an insert cursor to insert rows into the output feature class

outrows = arcpy.InsertCursor(outputFeatureClass)

# Create empty Point and Array objects
pntArray = arcpy.Array()
partArray = arcpy.Array()

# Loop through each row/feature
for row in inrows:
# Create the geometry object
feature = row.getValue(shapeName)

partnum = 0
# Count the total number of points in the current multipart feature
partcount = feature.partCount
print 'num parts: ', partcount
while partnum < partcount:
part = feature.getPart(partnum)
pnt = part.next()
print 'outer while'
pntcount = 0
# Enter while loop for each vertex

#
while pnt:
shiftedPoint = arcpy.Point()
try:
shiftedPoint.ID = pnt.ID
shiftedPoint.X = pnt.X + float(xShift)
shiftedPoint.Y = pnt.Y + float(yShift)
except AttributeError:
continue
pntArray.add(shiftedPoint)

pntcount += 1
pnt = part.next()
print 'pntcount: ', pntcount
# If pnt is null, either the part is finished or there is an
# interior ring
if pnt is None:
pnt = part.next()
if pnt:
arcpy.AddMessage("Interior Ring:")
partArray.add(pntArray)

pntArray.removeAll()
arcpy.AddMessage("Added a polygon to the partArray!")
partnum += 1
# Create a new row object that will be inserted into the ouput feature class. Set newRow = row so that it has the same attributes
# Set newRow.shape = partArray so that the only thing different about this new feature is that its geometry is different (shifted)
newRow = outrows.newRow()
newRow.shape = partArray
outrows.insertRow(newRow)
# Empy the array for the next run through the loop
partArray.removeAll()

del inrows, outrows

No comments:

Post a Comment

arcpy - Changing output name when exporting data driven pages to JPG?

Is there a way to save the output JPG, changing the output file name to the page name, instead of page number? I mean changing the script fo...