1. 概要

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

このチュートリアルでは、メルカトル図法について説明し、その2つのバリアントを実装する方法を学習します。

2. メルカトル図法

メルカトル図法は、1569年にフランドルの地図製作者ゲラルドゥスメルカトルによって導入された地図投影法です。 地図投影法は、地球上の緯度と経度の座標を平面上の点に変換します。 つまり、は、地表上のポイントをフラットマップ上のポイントに変換します。

メルカトル図法を実装する方法は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. 球面メルカトル図法

疑似投影モデルは、地球を球として扱います。 地球がより正確な形状で投影される楕円形の投影とは対照的です。 このアプローチにより、迅速な推定がより正確になりますが、計算量が多くなります楕円形投影になります。 その結果、この投影法での距離の直接測定値は概算になります。

さらに、マップ上の形状の比率はわずかに変化します。 その緯度と、国、湖、川などのマップ上のオブジェクトの形状の比率の結果として。 正確に保存されていません

これは、 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;
    }
}

このアプローチで最初に注意することは、このアプローチが地球の半径 1つの定数で表し、実際の2つではないという事実です。  次に、x軸投影y軸投影への変換に使用する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サーフェスに変換する必要がある場合は、メルカトル図法を使用できます。 実装に必要な精度に応じて、球形または楕円形のアプローチを使用できます。

いつものように、この記事のコードはGitHubにあります。