This might be a silly question and I will try to keep it short. My code is on a different network so I apologize ahead of time for not providing it, but will try to if more info is needed.
I am using arcpy.PointGeometry.pointFromAngleAndDistance(angle, distance, "GEODESIC") to create boxes centered on a point and rotated at a specified angle. These boxes have hard coded length and width values.
Using a point feature class in WGS84 in noticed that boxes at the same locations but with different lengths, did not look parallel. At first I thought, well yes that is probably right, because in WGS84 the bearing would not be constant across a line. But when measuring with the geodesic measuring tool from the start point to the end point, it does not match with the hard coded distance expected either. Shouldn't the distant values between start and end point match when using the geodesic measuring tool to check the distance. As a side note, when running this on a point feature class in WGS84 World Mercator the distances do match the geodesic measuring tool.
I also tried using the loxodrome method in the function bad had the same issue.
Apologies ahead of time, as I realize you probably want the code used.... the pains of private networks.
Solved! Go to Solution.
After a little bit of debugging I am convinced this is actually not an issue with the pointFromAngleAndDistance( ) function but maybe with the arcpy.Polygon() function. I output all the vertices positions to text prior to feeding them into a polygon array then plotted those on the map. Low and behold, those points were the correct distances apart and not matching with the polygons build from those point objects...I will mark this as accepted and resubmit a separate question.
Following.
Im going to say something, that will likely out me as a fraud but, your doing the work and spitting out GEODESIC and it doesn't measure correctly when displayed in WGS84 (graphic coordinate system) but is correct when using WGS84 WEB MERCATOR (which is a projection).
You are measuring something displayed incorrectly even if measuring it with the correct format.
Also try measuring two features that have the same GEODESIC length (example 500ft) if both the features in WGS84 have the same length it is right but its being messed up my the display.
I should specify that it is the feature class that is in WGS84/WGS84 Mercator that is affecting the output. Not the map project. Switching the map's CRS affects the display of course, but the measuring issue is the same.
After a little bit of debugging I am convinced this is actually not an issue with the pointFromAngleAndDistance( ) function but maybe with the arcpy.Polygon() function. I output all the vertices positions to text prior to feeding them into a polygon array then plotted those on the map. Low and behold, those points were the correct distances apart and not matching with the polygons build from those point objects...I will mark this as accepted and resubmit a separate question.
I've implemented a solution for this in the past:
def build_box_on_point(center: arcpy.PointGeometry, width: float, height: float, bearing: float, *,
start: str="BR", units: str="Feet", method: str="GEODESIC") -> arcpy.Polygon:
"""Builds a box around a point
@param center: The center point
@param width: The width of the box
@param height: The height of the box
@param bearing: The bearing of the box
@param start: The starting corner of the box (default is "BR", options are "BR", "BL", "TR", "TL")
@param units: The units of the width and height (default is "Feet")
@param method: The method to use for the box (default is "GEODESIC"), set to None to use the GCS type of the center
@return: The box
"""
conversion = arcpy.LinearUnitConversionFactor(units, "Meters")
height*=conversion
width*=conversion
if not method:
method = get_coord_type(center)
a = height/2.0
b = width/2.0
c = math.sqrt(math.pow(a, 2) + math.pow(b, 2))
theta = math.degrees(math.asin(a/c))
top_right = center.pointFromAngleAndDistance(bearing+theta, c, method).centroid
bottom_right = center.pointFromAngleAndDistance(bearing-theta, c, method).centroid
bottom_left = center.pointFromAngleAndDistance(bearing+180-theta, c, method).centroid
top_left = center.pointFromAngleAndDistance(bearing+180+theta, c, method).centroid
if start == "TR":
return arcpy.Polygon(arcpy.Array([top_right, bottom_right, top_left, bottom_left]), center.spatialReference)
if start == "BR":
return arcpy.Polygon(arcpy.Array([bottom_left, top_right, bottom_right, top_left]), center.spatialReference)
if start == "BL":
return arcpy.Polygon(arcpy.Array([top_left, bottom_left, top_right, bottom_right]), center.spatialReference)
if start == "TL":
return arcpy.Polygon(arcpy.Array([bottom_right, top_left, bottom_left, top_right]), center.spatialReference)
else:
raise ValueError("Start must be one of BR, BL, TR, TL")
It's not the cleanest and I have the conditions to make sure the directionality of the rings could be controlled, but I haven't had any issues with it.
Here's a simplified version that should still work and doesn't require all the reference logic:
from arcpy import PointGeometry, Polygon, Array
from math import asin, degrees
def build_box_on_point(center: PointGeometry, width: float, height: float, bearing: float) -> Polygon:
"""Builds a box around a point
@param center: The center point
@param width: The width of the box
@param height: The height of the box
@param bearing: The bearing of the box
@return: The box
"""
a = height/2.0
b = width/2.0
c = (a*a + b*a)**0.5
theta = degrees(asin(a/c))
top_right = center.pointFromAngleAndDistance(bearing+theta, c)
bottom_right = center.pointFromAngleAndDistance(bearing-theta, c)
bottom_left = center.pointFromAngleAndDistance(bearing+180-theta, c)
top_left = center.pointFromAngleAndDistance(bearing+180+theta, c)
return Polygon(Array([top_right, bottom_right, top_left, bottom_left]), center.spatialReference)