This will return either interior or exterior angles.
I didn't know what you want to do with the list, so this example simply prints the list of interior angles for a featureclass with 6 polygons.
import numpy as np
import arcpy
def _poly_arr_(poly):
"""Return coordinates of nested objects."""
def _split_(part):
yield [(p.X, p.Y) for p in part if p]
arrs =[]
for part in poly:
out = []
w = np.where(np.isin(part, None, invert=False))[0]
bits = np.split(part, w)
for i in bits:
sub = _split_(i)
out.append(np.array(*sub).squeeze())
arrs.append(np.asarray(out).squeeze())
return np.asarray(arrs)
def _angles_(a, inside=True, in_deg=True):
"""Worker for Geo `polygon_angles` and `polyline_angles`.
Parameters
----------
inside : boolean
True, for interior angles.
in_deg : boolean
True for degrees, False for radians.
"""
def _x_(a):
"""Cross product. see npg_helpers as well."""
ba = a - np.concatenate((a[-1, None], a[:-1]), axis=0)
bc = a - np.concatenate((a[1:], a[0, None]), axis=0)
return np.cross(ba, bc), ba, bc
if np.allclose(a[0], a[-1]):
a = a[:-1]
cr, ba, bc = _x_(a)
dt = np.einsum('ij,ij->i', ba, bc)
ang = np.arctan2(cr, dt)
TwoPI = np.pi * 2.
if inside:
angles = np.where(ang < 0, ang + TwoPI, ang)
else:
angles = np.where(ang > 0, TwoPI - ang, ang)
if in_deg:
angles = np.degrees(angles)
return angles
in_fc = r"C:\Folder_to_your\shapefile.shp"
with arcpy.da.SearchCursor(in_fc, "SHAPE@") as cur:
for row in cur:
geom = row[0]
arr = _poly_arr_(geom).squeeze()
ang = _angles_(arr, inside=True, in_deg=True)
print("angles\n{}".format(ang))
Results
angles
[90. 90. 90. 90.]
angles
[ 36.86989765 63.43494882 34.69515353 225. ]
angles
[ 34.69515353 225. 36.86989765 63.43494882]
angles
[63.43494882 53.13010235 63.43494882]
angles
[ 90. 270. 90. 90. 270. 90. 90. 270. 90. 90. 270. 90.]
angles
[ 90. 90. 90. 90. 270. 90.]
The featureclass