Javaで緯度と経度を2Dポイントに変換する

1概要

地図を使うアプリケーションを実装するとき、私たちは通常座標変換の問題に出くわすでしょう。ほとんどの場合、 表示するには 緯度と経度を2Dポイントに変換する必要があります。幸い、この問題を解決するために、メルカトル図法の公式を利用することができます。

このチュートリアルでは、Mercator Projectionを取り上げ、その2つのバリアントの実装方法を学びます。

2メルカトル図法

Mercator投影法 は、1569年にフランドルの地図作成者Gerardus Mercatorによって導入された地図投影法です。 。言い換えれば、 これは地球の表面上の点を平面地図上の点に変換します

メルカトル図法を実装する方法は2つあります。 擬似メルカトル図法は地球を球として扱います。真のメルカトル図法は地球を楕円体 としてモデル化します。両方のバージョンを実装します。

両方のメルカトル図法実装の基本クラスから始めましょう。

abstract class Mercator {
    final static double RADIUS__MAJOR = 6378137.0;
    final static double RADIUS__MINOR = 6356752.3142;

    abstract double yAxisProjection(double input);
    abstract double xAxisProjection(double input);
}

このクラスは、メートル単位で測った地球の長半径と短半径も提供します。地球は正確には球ではないことはよく知られています。

そのため、2つの半径が必要です。まず、 メジャー半径は地球の中心から赤道 までの距離です。次に、 小半径は、地球の中心から南北の極までの距離です

2.1. 球状メルカトル図法

擬似射影モデルは地球を球として扱います。地球がより正確な形で投影される楕円投影とは対照的に。このアプローチにより、より正確だが計算上の重い予測に対して 迅速な推定 が可能になります。その結果として、この投影における距離の直接測定値は概算になります。

さらに、地図上の図形の比率はわずかに変わります。その結果として、国、湖、川などのような地図上のオブジェクトの形状の比率は 正確には保存されない

これはhttps://en.wikipedia.org/wiki/Web Mercator projection[Web Mercator]プロジェクションとも呼ばれ、Googleマップを含むWebアプリケーションで一般的に使用されています。

このアプローチを実行しましょう:

public class SphericalMercator extends Mercator {

    @Override
    double xAxisProjection(double input) {
        return Math.toRadians(input) **  RADIUS__MAJOR;
    }

    @Override
    double yAxisProjection(double input) {
        return Math.log(Math.tan(Math.PI/4 + Math.toRadians(input)/2)) **  RADIUS__MAJOR;
    }
}

このアプローチについて最初に注意することは、このアプローチが実際のように2ではなく 1定数 で地球の 半径 を表すという事実です。次に、 x-axisプロジェクション y-axisプロジェクション に変換するために使用する2つの関数を実装したことがわかります。上記のクラスでは、コードを単純にするために、javaが提供する Math ライブラリを使用しました。

簡単な変換をテストしましょう。

Assert.assertEquals(2449028.7974520186, sphericalMercator.xAxisProjection(22));
Assert.assertEquals(5465442.183322753, sphericalMercator.yAxisProjection(44));

この射影が(-20037508.34、-23810769.32、20037508.34、23810769.32)の境界ボックス(左、下、右、上)に点をマッピングすることは注目に値する。

2 . 2. 楕円メルカトル図法

真の投影は地球を楕円体としてモデル化します。 この射影は、地球上のあらゆる場所の オブジェクトの 正確な比率 を示します。確かに、 地図上のオブジェクトを尊重しますが 100%正確ではありません** 。ただし、このアプローチは計算が複雑であるため、最も頻繁には使用されません。

このアプローチを実行しましょう:

class EllipticalMercator extends Mercator {
    @Override
    double yAxisProjection(double input) {

        input = Math.min(Math.max(input, -89.5), 89.5);
        double earthDimensionalRateNormalized = 1.0 - Math.pow(RADIUS__MINOR/RADIUS__MAJOR, 2);

        double inputOnEarthProj = Math.sqrt(earthDimensionalRateNormalized) **
          Math.sin( Math.toRadians(input));

        inputOnEarthProj = Math.pow(((1.0 - inputOnEarthProj)/(1.0+inputOnEarthProj)),
          0.5 **  Math.sqrt(earthDimensionalRateNormalized));

        double inputOnEarthProjNormalized =
          Math.tan(0.5 **  ((Math.PI **  0.5) - Math.toRadians(input)))/inputOnEarthProj;

        return (-1) **  RADIUS__MAJOR **  Math.log(inputOnEarthProjNormalized);
    }

    @Override
    double xAxisProjection(double input) {
        return RADIUS__MAJOR **  Math.toRadians(input);
    }
}

上で、このアプローチがy軸上の投影に関してどれほど複雑であるかを見ることができます。これは、非円形の地球の形状を考慮に入れる必要があるからです。真のメルカトルアプローチは複雑に見えますが、地球を表すために半径を1つのマイナーと1つのメジャーを表すために使用されるため、球面アプローチよりも正確です。

簡単な変換をテストしましょう。

Assert.assertEquals(2449028.7974520186, ellipticalMercator.xAxisProjection(22));
Assert.assertEquals(5435749.887511954, ellipticalMercator.yAxisProjection(44));

この射影は、(-20037508.34、-34619289.37、20037508.34、34619289.37)の境界ボックスに点をマッピングします。

3 結論

緯度と経度の座標を2Dの面に変換する必要がある場合は、Mercator投影法を使用できます。実装に必要な精度に応じて、球形または楕円形のアプローチを使用できます。

いつものように、私たちはこの記事https://github.com/eugenp/tutorials/tree/master/algorithms-miscellaneous-2[over on GitHub]のコードを見つけることができます。

  • **