offset method

  1. @override
LatLng offset(
  1. LatLng from,
  2. double distanceInMeter,
  3. double bearing
)
override

Vincenty inverse calculation

More on Wikipedia

Implementation

@override
LatLng offset(
    final LatLng from, final double distanceInMeter, final double bearing) {
  final equatorialRadius = equatorRadius;

  final latitude = from.latitudeInRad;
  final longitude = from.longitudeInRad;

  final alpha1 = degToRadian(bearing);
  final sinAlpha1 = math.sin(alpha1);
  final cosAlpha1 = math.cos(alpha1);

  final tanU1 = (1 - flattening) * math.tan(latitude);
  final cosU1 = 1 / math.sqrt((1 + tanU1 * tanU1));
  final sinU1 = tanU1 * cosU1;

  final sigma1 = math.atan2(tanU1, cosAlpha1);
  final sinAlpha = cosU1 * sinAlpha1;
  final cosSqAlpha = 1 - sinAlpha * sinAlpha;
  final dfUSq = cosSqAlpha *
      (equatorialRadius * equatorialRadius - polarRadius * polarRadius) /
      (polarRadius * polarRadius);
  final a = 1 +
      dfUSq / 16384 * (4096 + dfUSq * (-768 + dfUSq * (320 - 175 * dfUSq)));
  final b = dfUSq / 1024 * (256 + dfUSq * (-128 + dfUSq * (74 - 47 * dfUSq)));

  var sigma = distanceInMeter / (polarRadius * a);
  var sigmaP = 2 * pi;

  var sinSigma = 0.0;
  var cosSigma = 0.0;
  var cos2SigmaM = 0.0;
  double deltaSigma;
  var maxIterations = 200;

  do {
    cos2SigmaM = math.cos(2 * sigma1 + sigma);
    sinSigma = math.sin(sigma);
    cosSigma = math.cos(sigma);
    deltaSigma = b *
        sinSigma *
        (cos2SigmaM +
            b /
                4 *
                (cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM) -
                    b /
                        6 *
                        cos2SigmaM *
                        (-3 + 4 * sinSigma * sinSigma) *
                        (-3 + 4 * cos2SigmaM * cos2SigmaM)));
    sigmaP = sigma;
    sigma = distanceInMeter / (polarRadius * a) + deltaSigma;
  } while ((sigma - sigmaP).abs() > 1e-12 && --maxIterations > 0);

  if (maxIterations == 0) {
    throw StateError('offset calculation faild to converge!');
  }

  final tmp = sinU1 * sinSigma - cosU1 * cosSigma * cosAlpha1;
  final lat2 = math.atan2(sinU1 * cosSigma + cosU1 * sinSigma * cosAlpha1,
      (1 - flattening) * math.sqrt(sinAlpha * sinAlpha + tmp * tmp));

  final lambda = math.atan2(
      sinSigma * sinAlpha1, cosU1 * cosSigma - sinU1 * sinSigma * cosAlpha1);
  final c =
      flattening / 16 * cosSqAlpha * (4 + flattening * (4 - 3 * cosSqAlpha));
  final l = lambda -
      (1 - c) *
          flattening *
          sinAlpha *
          (sigma +
              c *
                  sinSigma *
                  (cos2SigmaM +
                      c * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM)));

  var lon2 = longitude + l;
  // print("LA ${radianToDeg(lat2)}, LO ${radianToDeg(lon2)}");

  if (lon2 > pi) {
    lon2 = lon2 - 2 * pi;
  }
  if (lon2 < -1 * pi) {
    lon2 = lon2 + 2 * pi;
  }

  return LatLng(radianToDeg(lat2), radianToDeg(lon2));
}