/// <summary> /// 距離演算その5 /// <para>Lambert-Andoyerの式を用いて引数で指定された座標までの距離[m]を返します。</para> /// <para>10 m程度の距離で0.2 mm程度の誤差を生じます。数百km以上の長距離になると誤差は少なめです。</para> /// <para>距離演算その6と比較して、10 m程のごく短距離において、0.01 pm(ピコメートル)の差が生じました。また、通常距離では差は生じませんでした。</para> /// <para>参考文献</para> /// <para>[1] 河合,測地線航海算法,富山高専 航海科学研究室,http://www.toyama-cmt.ac.jp/~mkawai/lecture/sailing/geodetic/geosail.html#note1 ,2012/6.</para> /// </summary> /// <param name="pos">求めたい地点の座標</param> /// <returns>測地線長<para>未知の測地系の場合、非値を返します。</para></returns> public double GetDistance5(Blh pos) { Blh me = this.ToRadian(); Blh he = pos.ToRadian(); GlobalDatum _datum = new GlobalDatum(this.DatumKind); double myParametricLat = Math.Atan(_datum.b / _datum.a * Math.Tan(me.B)); double hisParametricLat = Math.Atan(_datum.b / _datum.a * Math.Tan(he.B)); double sphericalDistance = Math.Acos(Math.Sin(myParametricLat) * Math.Sin(hisParametricLat) + Math.Cos(myParametricLat) * Math.Cos(hisParametricLat) * Math.Cos(me.L - he.L)); double C = Math.Pow(Math.Sin(myParametricLat) + Math.Sin(hisParametricLat), 2.0); double D = Math.Pow(Math.Sin(myParametricLat) - Math.Sin(hisParametricLat), 2.0); double correction = _datum.f / 8.0 * ( (Math.Sin(sphericalDistance) - sphericalDistance) * C / Math.Pow(Math.Cos(sphericalDistance / 2.0), 2.0) - (Math.Sin(sphericalDistance) + sphericalDistance) * D / Math.Pow(Math.Sin(sphericalDistance / 2.0), 2.0) ); double geodeticDistance = double.NaN; geodeticDistance = _datum.a * (sphericalDistance + correction); return geodeticDistance; }
/// <summary> /// 距離演算その6 /// <para>Lambert-Andoyerの式を変形した小野の公式を用い引数で指定された座標までの距離[m]を返します。</para> /// <para>参考文献</para> /// <para>[1] 河合,測地線航海算法,富山高専 航海科学研究室,http://www.toyama-cmt.ac.jp/~mkawai/lecture/sailing/geodetic/geosail.html#note1 ,2012/6.</para> /// <para></para> /// </summary> /// <param name="pos">求めたい地点の座標</param> /// <returns>測地線長<para>未知の測地系の場合、非値を返します。</para></returns> public double GetDistance6(Blh pos) { Blh me = this.ToRadian(); Blh he = pos.ToRadian(); GlobalDatum _datum = new GlobalDatum(this.DatumKind); double myParametricLat = Math.Atan(_datum.b / _datum.a * Math.Tan(me.B)); double hisParametricLat = Math.Atan(_datum.b / _datum.a * Math.Tan(he.B)); double sphericalDistance = Math.Acos(Math.Sin(myParametricLat) * Math.Sin(hisParametricLat) + Math.Cos(myParametricLat) * Math.Cos(hisParametricLat) * Math.Cos(me.L - he.L)); double C = Math.Pow(Math.Sin(myParametricLat) + Math.Sin(hisParametricLat), 2.0); double D = Math.Pow(Math.Sin(myParametricLat) - Math.Sin(hisParametricLat), 2.0); double P = (_datum.a - _datum.b) * (sphericalDistance - Math.Sin(sphericalDistance)) / (4 * (1 + Math.Cos(sphericalDistance))); double Q = (_datum.a - _datum.b) * (sphericalDistance + Math.Sin(sphericalDistance)) / (4 * (1 - Math.Cos(sphericalDistance))); double geodeticDistance = double.NaN; geodeticDistance = _datum.a * sphericalDistance - C * P - D * Q; return geodeticDistance; }
/// <summary> /// 距離演算その2 /// <para> /// <para>引数で指定された座標までの距離[m]を返します。</para> /// 参考:http://homepage3.nifty.com/kubota01/distance.htm /// 距離が50kmを超えるようなら、こちらのメソッドの使用を推奨します。 /// ただし、数百km以上であればその5またはその6の使用を推奨します。 /// <para>なお、高度は無視して楕円体面上での距離を求めています。</para> /// </para> /// </summary> /// <param name="pos">求めたい地点の座標</param> /// <returns>距離</returns> public double GetDistance2(Blh pos) { Ecef me = this.ToXYZ(); Ecef he = pos.ToXYZ(); GlobalDatum _datum = new GlobalDatum(this.DatumKind); double d_straight = Math.Sqrt(Math.Pow(me.x - he.x, 2.0) + Math.Pow(me.y - he.y, 2.0) + Math.Pow(me.z - he.z, 2.0)); // XYZ直交座標系を用いた直線距離(線は地中に潜る) double Nme = _datum.a / Math.Sqrt(1.0d - _datum.e2 * Math.Sin(this.ToRadian().B)); double Nse = _datum.a / Math.Sqrt(1.0d - _datum.e2 * Math.Sin(pos.ToRadian().B)); double N = (Nse + Nme) / 2.0d; // 平均の半径のようなもの double angle = Math.Asin(d_straight / 2.0d / N); // 半射程角(絵を描けば分かる) return 2.0d * angle * N; }