0

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);
}
John Bollinger
  • 160,171
  • 8
  • 81
  • 157
Tim
  • 21
  • 1
  • 5
  • Please note this example does NOT include the fix in the article for "Mirror like cases". This is included in a later release of this code but we have strict release policies so I have posted the version that is currently in production :) – Tim Sep 09 '20 at 18:00
  • So you can successfully find point p4, and now you want the distance from p1 to p4 (or p2 to p4) along the arc? – John Bollinger Sep 09 '20 at 18:28
  • You already have a function `GeoSpatial_Distance()`. I have not checked the formula, but it sounds like it would be applicable to the problem, and it has the right general appearance. Isn't it what you want? – John Bollinger Sep 09 '20 at 18:45
  • Aside: `L` in `const double PI = 3.14159265358979L;` serves no point. Initialize with a precise value. `double PI = 3.1415926535897932384626433832795;` Compiler will use what it can, no need to crop it. – chux - Reinstate Monica Sep 09 '20 at 20:43
  • `acos(x)` is prone errors when `|x|` is just above 1.0 due to computational issues. Recommend to test `fabs(x) <= 1.0` first and take evasive action when just a bit too large. – chux - Reinstate Monica Sep 09 '20 at 20:45
  • @chux-ReinstateMonica What's wrong with `M_PI` from `math.h`? – user58697 Sep 09 '20 at 20:50
  • @user58697 A conforming [does not have `M_PI`](https://stackoverflow.com/questions/5007925/using-m-pi-with-c89-standard), although many implementations do allow some extensions to a machine pi constant. – chux - Reinstate Monica Sep 09 '20 at 23:38
  • So what do I actually need to do to calculate the distance along the arc where the point intersects at right angles? – Tim Sep 14 '20 at 02:39
  • Does anyone have any constructive comments on this? – Tim Oct 17 '20 at 15:36

0 Answers0