@Test public void testComputeOffsetOrigin() { expectLatLngApproxEquals(front, SphericalUtil.computeOffsetOrigin(front, 0, 0)); expectLatLngApproxEquals( front, SphericalUtil.computeOffsetOrigin( new LatLng(0, 45), Math.PI * EARTH_RADIUS / 4, 90)); expectLatLngApproxEquals( front, SphericalUtil.computeOffsetOrigin( new LatLng(0, -45), Math.PI * EARTH_RADIUS / 4, -90)); expectLatLngApproxEquals( front, SphericalUtil.computeOffsetOrigin( new LatLng(45, 0), Math.PI * EARTH_RADIUS / 4, 0)); expectLatLngApproxEquals( front, SphericalUtil.computeOffsetOrigin( new LatLng(-45, 0), Math.PI * EARTH_RADIUS / 4, 180)); assertNull( SphericalUtil.computeOffsetOrigin( new LatLng(80, 0), Math.PI * EARTH_RADIUS / 4, 180)); assertNull( SphericalUtil.computeOffsetOrigin( new LatLng(80, 0), Math.PI * EARTH_RADIUS / 4, 90)); }
public static LatLng computeOffsetOrigin(LatLng to, double distance, double heading) { heading = toRadians(heading); distance /= EARTH_RADIUS; double n1 = cos(distance); double n2 = sin(distance) * cos(heading); double n3 = sin(distance) * sin(heading); double n4 = sin(toRadians(to.latitude)); double n12 = n1 * n1; double discriminant = n2 * n2 * n12 + n12 * n12 - n12 * n4 * n4; 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); } if (fromLatRadians < -PI / 2 || fromLatRadians > PI / 2) { return null; } double fromLngRadians = toRadians(to.longitude) - atan2(n3, n1 * cos(fromLatRadians) - n2 * sin(fromLatRadians)); return new LatLng(toDegrees(fromLatRadians), toDegrees(fromLngRadians)); }
SphericalUtil { public static LatLng computeOffsetOrigin(LatLng to, double distance, double heading) { heading = toRadians(heading); distance /= EARTH_RADIUS; double n1 = cos(distance); double n2 = sin(distance) * cos(heading); double n3 = sin(distance) * sin(heading); double n4 = sin(toRadians(to.latitude)); double n12 = n1 * n1; double discriminant = n2 * n2 * n12 + n12 * n12 - n12 * n4 * n4; 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); } if (fromLatRadians < -PI / 2 || fromLatRadians > PI / 2) { return null; } double fromLngRadians = toRadians(to.longitude) - atan2(n3, n1 * cos(fromLatRadians) - n2 * sin(fromLatRadians)); return new LatLng(toDegrees(fromLatRadians), toDegrees(fromLngRadians)); } }
SphericalUtil { public static LatLng computeOffsetOrigin(LatLng to, double distance, double heading) { heading = toRadians(heading); distance /= EARTH_RADIUS; double n1 = cos(distance); double n2 = sin(distance) * cos(heading); double n3 = sin(distance) * sin(heading); double n4 = sin(toRadians(to.latitude)); double n12 = n1 * n1; double discriminant = n2 * n2 * n12 + n12 * n12 - n12 * n4 * n4; 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); } if (fromLatRadians < -PI / 2 || fromLatRadians > PI / 2) { return null; } double fromLngRadians = toRadians(to.longitude) - atan2(n3, n1 * cos(fromLatRadians) - n2 * sin(fromLatRadians)); return new LatLng(toDegrees(fromLatRadians), toDegrees(fromLngRadians)); } private  SphericalUtil(); }
SphericalUtil { public static LatLng computeOffsetOrigin(LatLng to, double distance, double heading) { heading = toRadians(heading); distance /= EARTH_RADIUS; double n1 = cos(distance); double n2 = sin(distance) * cos(heading); double n3 = sin(distance) * sin(heading); double n4 = sin(toRadians(to.latitude)); double n12 = n1 * n1; double discriminant = n2 * n2 * n12 + n12 * n12 - n12 * n4 * n4; 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); } if (fromLatRadians < -PI / 2 || fromLatRadians > PI / 2) { return null; } double fromLngRadians = toRadians(to.longitude) - atan2(n3, n1 * cos(fromLatRadians) - n2 * sin(fromLatRadians)); return new LatLng(toDegrees(fromLatRadians), toDegrees(fromLngRadians)); } private  SphericalUtil(); static double computeHeading(LatLng from, LatLng to); static LatLng computeOffset(LatLng from, double distance, double heading); static LatLng computeOffsetOrigin(LatLng to, double distance, double heading); static LatLng interpolate(LatLng from, LatLng to, double fraction); static double computeDistanceBetween(LatLng from, LatLng to); static double computeLength(List<LatLng> path); static double computeArea(List<LatLng> path); static double computeSignedArea(List<LatLng> path); }
SphericalUtil { public static LatLng computeOffsetOrigin(LatLng to, double distance, double heading) { heading = toRadians(heading); distance /= EARTH_RADIUS; double n1 = cos(distance); double n2 = sin(distance) * cos(heading); double n3 = sin(distance) * sin(heading); double n4 = sin(toRadians(to.latitude)); double n12 = n1 * n1; double discriminant = n2 * n2 * n12 + n12 * n12 - n12 * n4 * n4; 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); } if (fromLatRadians < -PI / 2 || fromLatRadians > PI / 2) { return null; } double fromLngRadians = toRadians(to.longitude) - atan2(n3, n1 * cos(fromLatRadians) - n2 * sin(fromLatRadians)); return new LatLng(toDegrees(fromLatRadians), toDegrees(fromLngRadians)); } private  SphericalUtil(); static double computeHeading(LatLng from, LatLng to); static LatLng computeOffset(LatLng from, double distance, double heading); static LatLng computeOffsetOrigin(LatLng to, double distance, double heading); static LatLng interpolate(LatLng from, LatLng to, double fraction); static double computeDistanceBetween(LatLng from, LatLng to); static double computeLength(List<LatLng> path); static double computeArea(List<LatLng> path); static double computeSignedArea(List<LatLng> path);  }