9

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

<type 'exceptions.ValueError'>: 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?

PolyGeo
65.5k29 gold badges115 silver badges350 bronze badges
asked Nov 29, 2010 at 0:00

1 Answer 1

14

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
answered Nov 29, 2010 at 17:17
1
  • I just discovered that the script shifts everything perfectly, except for features that have 2 or more interior rings. It will leave lines connected, and distort the polygon. Do you know how to account for this? Commented Dec 12, 2010 at 19:56

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.