What is the most reliable method to calculate angle of a line from north, defined by it’s from and to points? I used to use IMeasurementTool interface found in defense solutions namespace found in Military Analyst for this purpose when we were using ArcGIS 10.0.
Since Military Analyst is no longer available for version later that 10.1, I need to find a method to replace its functionality. I have tested several methods for this purpose. Example code that uses same methods in a similar fashion can be found bellow ;
By constructing a line and using its angle;
IPoint from_point;
IPoint to_point;
To and from points are available with two point coordinate chosen by the user.
ILine2 measurement_line = new LineClass();
measurement_line.SpatialReference = from_point.SpatialReference;
measurement_line.FromPoint = from_point;
measurement_line.ToPoint = to_point;
Double angle_from_horizontal = (180.0 * measurement_line.Angle) / Math.PI;
Double angle_from_north = 90.0 - angle_from_horizontal;
By using IConstructAngle interface and GeometryEnvironmentClass object.
IConstructAngle angle_measurement = new GeometryEnvironmentClass();
IPoint north_point = new PointClass();
north_point.SpatialReference = from_point.SpatialReference;
north_point.X = from_point.X;
north_point.Y = 90.0;
FLOAT64 angle_radian = aci_olcer.ConstructThreePoint(north_point, from_point, to_point);
Double angle_from_horizontal = (180.0 * angle_radian) / Math.PI;
Double angle_from_north = angle_from_horizontal;
By constructing a geodetic line and QueryTangent method of ICurve interface in order to find the tangent line at the start point.
PolylineClass geodeticline = new PolylineClass();
geodeticline.SpatialReference = from_point.SpatialReference;
IConstructGeodetic geodetic_calculations = (IConstructGeodetic)geodeticline;
geodetic_calculations.ConstructGeodeticLineFromPoints(esriGeodeticType.esriGeodeticTypeGeodesic, from_point, to_point, linearUnitMeter, esriCurveDensifyMethod.esriCurveDensifyByDeviation, 0.01);
ICurve tangent_finder = (ICurve)geodeticline;
ILine tanjant_line = new LineClass();
tangent_finder.QueryTangent(esriSegmentExtension.esriNoExtension, 0, true, 0.0000001, tanjant_line);
Double angle_from_horizontal = (180.0 * tanjant_line.Angle) / Math.PI;
Double angle_from_north = 90 - angle_from_horizontal;
By using new MensurationClass.
IDistanceMeasurement distanceResult = new DistanceMeasurementClass();
IAngularMeasurement angularResult = new AngularMeasurementClass();
double result;
double uncertainty;
double result_angluar = 0;
double uncertainty_angular;
if (measure.CanMeasure == true)
{
measure.GetDistance(test_1_pnt, test_2_pnt, out distanceResult);
result = distanceResult.DistanceMeasurement;
uncertainty = distanceResult.DistanceUncertainty;
measure.GetAzimuthAngle(test_1_pnt, test_2_pnt, out angularResult);
result_angluar = angularResult.AngleMeasurement;
uncertainty_angular = angularResult.AngleUncertainty;
}
I compared the results of the methods I enlisted with the result of IMeasurementTool method and none of the produced the results produced by the MeasurementTool. Moreover this angle is actually used for later calculations where several points constructing corners of a rectangle are found by using distance, angle and starting point as arguments. If the angle measurements are not reliable, results deviate from original points. For example, I found out the by using other methods, resultant rectangle is deviated at an angle of 4 to 5 degrees from the original line for lines having a length of 200 000 meters located at whereabouts of Scandinavia. I also tested this for a wide range of locations throughout the World Map and found that resultant deviation is depended on the latitude, as results on the equator has near zero deviation where deviations near the poles are huge, and also depended on the length of the original line.
This is somewhat understandable because I found out that, as far as I understand, all of the methods I enlisted apart from the geodesic line construction returns angles calculated by using latitude and longitude values as Cartesian coordinates. Geodesic line construction on the other hand uses QueryTangent method to calculate angle at from_point. Results of the geodetic line are closer to the results on of the MeasurementTool but not same again. I assume that this may be due to the QueryTangent method used to calculate the angle at from point if it uses Cartesian latitude and longitude rations for arctangent. Also since I couldn’t find any sources on the implementation details, these are all my guesses.
Since when we approach the poles, actual distance between observed distances on the map changes, it is understandable to have an increased amount of error near the poles. So I used another method where I calculate geodetic distances of the two sides of a triangle formed by to and from points and a point representing the corner of a right triangle. Later on I used geodesic distance values to calculate an arctangent.
IGeometryServer2 geometry_server = new GeometryServerImplClass();
Double lat_y_dist_f64;
Double long_x_dist_f64;
IPoint corner_point = new PointClass();
corner_point.SpatialReference = spatialReference;
corner_point.X = to_point.X;
corner_point.Y = from_point.Y;
lat_y_dist_f64 = geometry_server.GetDistanceGeodesic(spatialReference, corner_point, to_point, linearUnitMeter);
long_x_dist_f64 = geometry_server.GetDistanceGeodesic(spatialReference, from_point, corner_point, linearUnitMeter);
Double angle_radian = Math.Atan2(long_x_dist_f64, lat_y_dist_f64);
Double angle_from_north = (180.0 * angle_radian) / Math.PI;
Results were much closer to their results of the MeasurementTool where originally 5 degrees of deviation observed at whereabouts of 40 degree latitude reduced to 0.003 degree for 2000 meter lines. While results were almost identical o the results of the MeasurementTool, they were not exactly same and deviation again increased near the poles and for longer lines.
So my question is what am I missing here? What is the most reliable and accurate method for calculating angles from north for geometries defined by two points? I believe that since this question is a very basic and fundamental question, ArcGIS should have a far easier solution to this problem which I am simply overlooking.
Best Answer
I've used Richie Carmichael's code from his blog post. In a later post he said he fixed some memory leaks and uploaded to arcscripts, however that link is broken. I'll look for the code - I think I downloaded it years ago. Anyway, here is the code from his first post. Take a look at the azimuth outputs.
The code uses the "projection engine" dll. I've read this dll is used throughout numerous Esri toolsets.