0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Bowring for short lines(精度良好な地理的距離の短距離近似法)をさらに精度改善(中間緯度を利用)

Last updated at Posted at 2025-01-04

こんにちは。
精度良好な地理的距離の短距離近似法である Bowring's method for short lines (Wikipedia)1 を、さらに精度改善しました。

用いた計算方法は、中間緯度を用い、"Bowring for short lines"(Karney; geographiclib) をそっくり踏襲しました。

精度評価2を行うと、

  • 「更成緯度+中間緯度」を用いた計算は、短距離近似法としては確かに最も精度良好のようで(下記のプロット内のbowring_short_beta_;100kmでは10ppb)、

  • 「地理緯度+中間緯度」を用いる計算はこれに次ぐようです(bowring_short_)。

精度評価

mini1736353739.jpg

source code

bowring_short.js
// Bowring, B. R. (1981). "The direct and inverse problems for short geodesic lines on the ellipsoid". Surveying and Mapping. 41 (2): 135–141.
function bowring_short(lat1, lon1, lat2, lon2){  // in degrees
  "use strict";
  const a = 6378137.0;  // GRS80
  const f = 1 / 298.257223563;  // WGS84
  const e2 = f * (2 - f);  // first eccentricity squared
  const ep2 = e2 / (1 - f) ** 2;  // second eccentricity squared; epsilon

  const degree = Math.PI / 180.0;
  const sin = Math.sin;
  const cos = Math.cos;
  const sqrt = Math.sqrt;
  const hypot = Math.hypot;
  const asin2 = x => x < 1 ? 2 * Math.asin(x) : Math.PI;

  const londiffhalf = (lon2 - lon1) / 2 * degree;
  lat1 = lat1 * degree;
  lat2 = lat2 * degree;
  const latdiffhalf = (lat2 - lat1) / 2;
  
  const lat0 = lat1;  // Bowring
  const cos_lat0 = cos(lat0);
  const cos_lat0_squared = cos_lat0 ** 2;

  const C = sqrt(1 + ep2);
  const B2 = 1 + ep2 * cos_lat0_squared;
  const B = sqrt(B2);
  const A = sqrt(1 + ep2 * cos_lat0_squared ** 2);

// radius, longitude, and latitude on the conformal sphere
  const Rp = C / B2;
  const lonpdiffhalf = A * londiffhalf;
  const latpdiffhalf = latdiffhalf / B * (1 + (3 / 2 * ep2 / B2) * latdiffhalf * sin(2 * lat0 + 4 / 3 * latdiffhalf));  // D
  const cos_latp0 = (B * cos_lat0 * cos(latpdiffhalf) - sin(lat0) * sin(latpdiffhalf)) / A;

// great circle formula
  const E = cos(lonpdiffhalf) * sin(latpdiffhalf);
  const F = sin(lonpdiffhalf) * cos_latp0;
  return a * Rp * asin2(hypot(E, F));  // geodesic distance
}

// by Karney
// https://geographiclib.sourceforge.io/C++/doc/geodesic.html#bowring
function bowring_short_(lat1, lon1, lat2, lon2){  // in degrees
  "use strict";
  const a = 6378137.0;  // GRS80
  const f = 1 / 298.257223563;  // WGS84
  const e2 = f * (2 - f);  // first eccentricity squared
  const ep2 = e2 / (1 - f) ** 2;  // second eccentricity squared; epsilon

  const degree = Math.PI / 180.0;
  const sin = Math.sin;
  const cos = Math.cos;
  const tan = Math.tan;
  const atan = Math.atan;
  const sqrt = Math.sqrt;
  const hypot = Math.hypot;
  const asin2 = x => x < 1 ? 2 * Math.asin(x) : Math.PI;

  const londiffhalf = (lon2 - lon1) / 2 * degree;
  lat1 = lat1 * degree, lat2 = lat2 * degree;
  const lat = (lat1 + lat2) / 2;  // mid-latitude by Karney
  const cos_lat = cos(lat);
  const cos_lat_squared = cos_lat ** 2;

  const C = sqrt(1 + ep2);
  const B2 = 1 + ep2 * cos_lat_squared;
  const B = sqrt(B2);
  const A = sqrt(1 + ep2 * cos_lat_squared ** 2);

// radius, longitude, and latitude on the conformal sphere
  const Rp = C / B2;
  const lonpdiffhalf = A * londiffhalf;
  
  const dlat1 = lat1 - lat;  // = -(lat2 - lat)
  const phipm = atan(tan(lat)/B) + dlat1*dlat1 * 3*ep2/(4*B*B2) * sin(2*lat) * cos(2/3*dlat1);
  const phipdiffhalf = dlat1/B * (1 + (3*ep2*dlat1)/(4*B2) * cos(2*lat) * sin(2/3*dlat1));

// great circle formula
  const E = cos(lonpdiffhalf) * sin(phipdiffhalf);
  const F = sin(lonpdiffhalf) * cos(phipm);
  return a * Rp * asin2(hypot(E, F));  // geodesic distance
}

// by Karney
// https://geographiclib.sourceforge.io/C++/doc/geodesic.html#bowring
function bowring_short_beta_(lat1, lon1, lat2, lon2){  // in degrees
  "use strict";
  const a = 6378137.0;  // GRS80
  const f = 1 / 298.257223563;  // WGS84
  const f1 = 1 - f;
  const e2 = f * (2 - f);  // first eccentricity squared
  const ep2 = e2 / f1 ** 2;  // second eccentricity squared; epsilon

  const degree = Math.PI / 180.0;
  const sin = Math.sin;
  const cos = Math.cos;
  const tan = Math.tan;
  const atan = Math.atan;
  const sqrt = Math.sqrt;
  const hypot = Math.hypot;
  const asin2 = x => x < 1 ? 2 * Math.asin(x) : Math.PI;

  const londiffhalf = (lon2 - lon1) / 2 * degree;
  const bet1 = atan(tan(lat1 * degree) * f1);
  const bet2 = atan(tan(lat2 * degree) * f1);
  const betm = (bet1 + bet2)/2;  // mid-latitude by Karney
  const sbetm = sin(betm);
  const cbetm = cos(betm);
  const phim = atan(tan(betm) / f1);
  const cosm = cos(phim);
  const cosm_squared = cosm ** 2;
  const C = sqrt(1 + ep2);
  const B2 = 1 + ep2 * cosm_squared;
  const B = sqrt(B2);
  const A = sqrt(1 + ep2 * cosm_squared ** 2);

// radius, longitude, and latitude on the conformal sphere
  const Rp = C / B2;
  const lonpdiffhalf = A * londiffhalf;
  const dnm2 = 1+ep2*sbetm*sbetm;
  const dnm = sqrt(dnm2);
  const dbet1 = (bet1-betm)/dnm;  // = -(bet2-betm)/dnm
  const phipm = atan(tan(phim)/B) + dbet1 * dbet1 * ep2/2 * cbetm*sbetm/dnm;
  const phipdiffhalf = dbet1 * (1 + dbet1 * dbet1 * ep2/6 * (cbetm*cbetm/dnm2 - sbetm*sbetm) );

// great circle formula
  const E = cos(lonpdiffhalf) * sin(phipdiffhalf);
  const F = sin(lonpdiffhalf) * cos(phipm);
  return a * Rp * asin2(hypot(E, F));  // geodesic distance
}
  1. Bowring, B. R., "The direct and inverse problems for short geodesic lines on the ellipsoid". Surveying and Mapping (1981), p.135.

  2. 参考: 二点間測地線距離(地球上):各計算方法の誤差評価#精度評価用入力データ生成

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?