computeOffsetOrigin static method
Returns the location of origin when provided with a Point destination, meters travelled and original heading. Headings are expressed in degrees clockwise from North. This function returns null when no solution is available.
to The destination Point.
distance The distance travelled, in meters.
heading The heading in degrees clockwise from north.
Implementation
static Point<double>? computeOffsetOrigin(
Point<double> to, double distance, double heading) {
distance /= MathUtils.earthRadius;
heading = toRadians(heading);
// http://lists.maptools.org/pipermail/proj/2008-October/003939.html
final n1 = cos(distance);
final n2 = sin(distance) * cos(heading);
final n3 = sin(distance) * sin(heading);
final n4 = sin(toRadians(to.x));
// There are two solutions for b. b = n2 * n4 +/- sqrt(), one solution results
// in the x outside the [-90, 90] range. We first try one solution and
// back off to the other if we are outside that range.
final n12 = n1 * n1;
final discriminant = n2 * n2 * n12 + n12 * n12 - n12 * n4 * n4;
// No real solution which would make sense in Point<double>-space.
if (discriminant < 0) {
return null;
}
double b = n2 * n4 + sqrt(discriminant);
b /= n1 * n1 + n2 * n2;
final a = (n4 - n2 * b) / n1;
double fromLatRadians = atan2(a, b);
if (fromLatRadians < -pi / 2 || fromLatRadians > pi / 2) {
b = n2 * n4 - sqrt(discriminant);
b /= n1 * n1 + n2 * n2;
fromLatRadians = atan2(a, b);
}
// No solution which would make sense in Point<double>-space.
if (fromLatRadians < -pi / 2 || fromLatRadians > pi / 2) {
return null;
}
final fromLngRadians = toRadians(to.y) -
atan2(n3, n1 * cos(fromLatRadians) - n2 * sin(fromLatRadians));
return Point(toDegrees(fromLatRadians), toDegrees(fromLngRadians));
}