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? computeOffsetOrigin(Point to, double distance, double heading) {
distance /= MathUtils.earthRadius;
heading = toRadians(heading);
// http://lists.maptools.org/pipermail/proj/2008-October/003939.html
double n1 = cos(distance);
double n2 = sin(distance) * cos(heading);
double n3 = sin(distance) * sin(heading);
double 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.
double n12 = n1 * n1;
double discriminant = n2 * n2 * n12 + n12 * n12 - n12 * n4 * n4;
// No real solution which would make sense in Point-space.
if (discriminant < 0) {
return null;
}
double b = n2 * n4 + sqrt(discriminant);
b /= n1 * n1 + n2 * n2;
double 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-space.
if (fromLatRadians < -pi / 2 || fromLatRadians > pi / 2) {
return null;
}
double fromLngRadians = toRadians(to.y) -
atan2(n3, n1 * cos(fromLatRadians) - n2 * sin(fromLatRadians));
return Point(toDegrees(fromLatRadians), toDegrees(fromLngRadians));
}