[GIS] Rotating polygons by value from attribute table using ArcPy

arcpyerror-000732polygonrotate

I have 60 polygons saved in one shp file.

Is there a way to rotate them by the angle value stored in the attribute table?

I know how to do it manually; I am looking for more automated way (Every polygon has different angle)

I tried to run this script but I got an error

Runtime error Traceback (most recent call last): File "",
line 55, in File "", line 24, in main File
"c:\program files (x86)\arcgis\desktop10.3\arcpy\arcpy\management.py",
line 6520, in MakeFeatureLayer raise e ExecuteError: Failed to
execute. Parameters are not valid. ERROR 000732: Input Features:
Dataset P:\3_Workspaces\DDP_REF.gdb\Original does not exist or is not
supported Failed to execute (MakeFeatureLayer).

# -*- coding: utf-8 -*-
import math
import arcpy
import numpy

def Transform_coords(x, y, angle, polygon_centroid):
    radians =  math.radians(angle)
    (X,Y) = polygon_centroid

    x_trans = x - X
    y_trans = y - Y

    x_transprime = math.cos(radians) * x_trans - math.sin(radians) * y_trans
    y_transprime = math.sin(radians) * x_trans + math.cos(radians) * y_trans

    x_prime = x_transprime + X
    y_prime = y_transprime + Y

    return x_prime, y_prime

def main(shp_file, new_shp_file):
    arcpy.env.overwriteOutput = True

    arcpy.MakeFeatureLayer_management (shp_file, "polygon")
    sr = arcpy.Describe("polygon").spatialReference
    features = []

    with arcpy.da.SearchCursor("polygon", ["SHAPE@", "SHAPE@XY"]) as cursor:
        for row in cursor:

            array = numpy.random.uniform(0, 360, size = 1)
            angle = array.tolist()[0]

            for feature_parts in row[0]:
                feature = []

                polygon_centroid = row[1]

                for coord in feature_parts: 
                    x = coord.X
                    y = coord.Y

                    new_x, new_y = Transform_coords(x, y, angle, polygon_centroid)
                    feature.append([new_x, new_y])

            points = arcpy.Array([arcpy.Point(*coords) for coords in feature])
            polygon_feature = arcpy.Polygon(points,sr)
            features.append(polygon_feature)

    arcpy.CopyFeatures_management(features, new_shp_file)

if __name__ == "__main__":
    main(
        shp_file = r"P:\3_Workspaces\DDP_REF.gdb\Original", 
        new_shp_file = r"P:\3_Workspaces\DDP_REF.gdb\Rotated"
        )

Best Answer

Create a function to rotate points then use the da.UpdateCursor to update the geometry for each polygon. Code below will modify your data so backup before you try it:

import arcpy, math

fc = 'aPoly' #Change to match your data
rotatefield = 'Rotation' #Clockwise rotation in degress. Change name to match your data

#Function to rotate one input Point around a pivot point
def rotatepoint(point, pivotpoint, angle):
    #Source: https://stackoverflow.com/questions/34372480/rotate-point-about-another-point-in-degrees-python
    angle_rad = -math.radians(angle)
    ox, oy = pivotpoint.X, pivotpoint.Y
    px, py = point.X, point.Y
    qx = ox + math.cos(angle_rad) * (px - ox) - math.sin(angle_rad) * (py - oy)
    qy = oy + math.sin(angle_rad) * (px - ox) + math.cos(angle_rad) * (py - oy)    
    return arcpy.Point(qx,qy)

#Rebuild each polygon with rotated vertices
with arcpy.da.UpdateCursor(fc,['SHAPE@',rotatefield]) as cursor:
    for row in cursor:
        polylist = []
        for part in row[0]:
            partlist = []
            for pnt in part:
                if pnt is not None: #Polygons with inner rings will have None pnt(s) which can be skipped
                    partlist.append(rotatepoint(pnt, row[0].centroid, row[1])) #Centroid is pivot point
                    polylist.append(partlist)
        row[0] = arcpy.Polygon(arcpy.Array(polylist))
        cursor.updateRow(row)

enter image description here

Related Question