Being as I can't comment on questions yet because I don't have enough reputation points I'm forced to ask another question. Given this excellent article Distance from Lat/Lng point to Minor Arc segment I have implemented the code in C# and in C. Now I need to know for Case 2.1: The relative bearing is acute, AND p4 falls on our arc, how do I calculate how far along the segment does the point intersect (in metres!). I'm no mathematics genius unfortunately so a code example with real variable names would be advantage for my understanding. The MatLab example is easy to translate to C# and C - I have included the C code below:
// GeoSpatial.h Header file containing....
typedef enum _calculationResultType
{
Undefined,
Obtuse,
BeyondArc,
CrossTrack
} CalculationResultType;
typedef struct _coordinate
{
//int Id;
int FeatureId;
double Latitude;
double Longitude;
int SpeedLimit;
} CoordinateObject, * Coordinate;
double GeoSpatial_Bearing(double latA, double lonA, double latB, double lonB);
double GeoSpatial_Calculate(Coordinate c1, Coordinate c2, Coordinate c3, CalculationResultType * resultType);
double GeoSpatial_Distance(double latA, double lonA, double latB, double lonB);
double GeoSpatial_ToRadians(double degrees);
// C Module....
#include <math.h>
#include "GeoSpatial.h"
const double EarthRadius = 6371000.0L;
const double PI = 3.14159265358979L;
double
GeoSpatial_Bearing(double latA, double lonA, double latB, double lonB)
{
return atan2(sin(lonB - lonA) * cos(latB), cos(latA) * sin(latB) - sin(latA) * cos(latB) * cos(lonB - lonA));
}
double
GeoSpatial_Calculate(Coordinate c1, Coordinate c2, Coordinate c3, CalculationResultType * resultType)
{
double lat1 = GeoSpatial_ToRadians(c1->Latitude);
double lat2 = GeoSpatial_ToRadians(c2->Latitude);
double lat3 = GeoSpatial_ToRadians(c3->Latitude);
double lon1 = GeoSpatial_ToRadians(c1->Longitude);
double lon2 = GeoSpatial_ToRadians(c2->Longitude);
double lon3 = GeoSpatial_ToRadians(c3->Longitude);
// Earth's radius in meters
// Prerequisites for the formulas
double bearingC1C2 = GeoSpatial_Bearing(lat1, lon1, lat2, lon2);
double bearingC1C3 = GeoSpatial_Bearing(lat1, lon1, lat3, lon3);
double distanceC1C3 = GeoSpatial_Distance(lat1, lon1, lat3, lon3);
// Is relative bearing obtuse?
if (fabs(bearingC1C3 - bearingC1C2) > (PI / 2))
{
double distanceC2C3 = GeoSpatial_Distance(lat2, lon2, lat3, lon3);
*resultType = Obtuse;
return distanceC1C3 < distanceC2C3 ? distanceC1C3 : distanceC2C3;
}
// Find the cross-track distance.
double distanceCrossTrack = asin(sin(distanceC1C3 / EarthRadius) * sin(bearingC1C3 - bearingC1C2)) * EarthRadius;
// Is p4 beyond the arc?
double distanceC1C2 = GeoSpatial_Distance(lat1, lon1, lat2, lon2);
double distanceC1C4 = acos(cos(distanceC1C3 / EarthRadius) / cos(distanceCrossTrack / EarthRadius)) * EarthRadius;
if (distanceC1C4 > distanceC1C2)
{
// Distance C2 - C3
*resultType = BeyondArc;
return GeoSpatial_Distance(lat2, lon2, lat3, lon3);
}
*resultType = CrossTrack;
return fabs(distanceCrossTrack);
}
double
GeoSpatial_Distance(double latA, double lonA, double latB, double lonB)
{
return acos(sin(latA) * sin(latB) + cos(latA) * cos(latB) * cos(lonB - lonA)) * EarthRadius;
}
double
GeoSpatial_ToRadians(double degrees)
{
return degrees * (acos(-1) / 180);
}