🌏

多角形ポリゴンの面積を計算する方法

2022/10/18に公開

目的

多角形ポリゴンの面積計算をGoogle Maps JavaScript APIを使わないで実装したい

Google MapをWebアプリに組み込みたいとき、通常はフロントエンドでGoogle Maps JavaScript APIを使うと思います。地図上の任意の多角形ポリゴンの面積を求る場合はこのAPIcomputeArea(path))を利用して面積を求めます。

今回の目的は、「任意の多角形ポリゴンの面積計算をこのAPIを使わないで実装する」ことになります。

今回使用する言語はJavaにしました。

調査

Google Map JavaScript APIの仕様の調査

公式ドキュメントの球面ジオメトリのコンセプトによると、地球を「球面」として扱っています。

球面上(またはその投影上)においては、球面幾何学の関数を使用して、距離や方向、面積などの構成要素を計算する必要があります。Maps API の google.maps.geometry.spherical 名前空間には、これらの球面幾何学の構成要素を計算するユーティリティ、および球面座標(緯度と経度)からスカラー値を計算する静的メソッドが含まれています。

補足: 地球を球面とするか回転楕円体とするかで面積が変わる

地球の形は最も近い回転楕円体で定義されています。世界測地系移行の概要 1.概要 - 国土地理院
国土地理院が提供しているWebアプリ「地理院地図」では回転楕円体として面積を計算しています。地理院地図で得られる値等について

しかしGEO系のライブラリのいくつかでは地球を球体として扱っているケースがあります。この時の計算手法が異なるので欲しい結果がどのような値なのか注意が必要です。

地球を球体として扱う際の面積計算方法

地球の面積を求める方法は論文Some algorithms for polygons on a sphereを利用した実装をしているケースがありました。

ライブラリのコード

実装

Javaで論文のように書き下してみる

  • Google Maps JavaScript APIでは地球の半径を6,378,137 mとしています。
import java.math.BigDecimal;
import java.util.ArrayList;

public class AreaOfaPolygonOnaSphere { 
    public static final Double RADIUS = Double.valueOf(6378137);
    
    public static BigDecimal getAreaInternal() { 
        Double acreage = Double.valueOf(0); 
        
        ArrayList<Double[]> coordinates = new ArrayList<>(); 
        Double[][] point1 = {{35.656479794530156, 139.7582095207256}}; 
        Double[][] point2 = {{35.65613109521005, 139.7597973884624}}; 
        Double[][] point3 = {{35.657403840365355, 139.75994759216724}}; 
        Double[][] point4 = {{35.65765664349531, 139.7585206569713}}; 
        
        coordinates.add(point1[0]); 
        coordinates.add(point2[0]); 
        coordinates.add(point3[0]); 
        coordinates.add(point4[0]); 
        
        Integer len = coordinates.size(); 
        
        Double y1 = coordinates.get(len - 1)[0]; 
        Double x1 = coordinates.get(len - 1)[1]; 
        
        for (int i = 0; i < len; i++) { 
            Double y2 = coordinates.get(i)[0]; 
            Double x2 = coordinates.get(i)[1]; 
            
            acreage += Math.toRadians(x2 - x1) * (2 + Math.sin(Math.toRadians(y1)) + Math.sin(Math.toRadians(y2))); 
            x1 = x2; y1 = y2; 
        } 
        // 座標がリストが右回りか左回りかで正負が反転するため絶対値を取る
        return BigDecimal.valueOf(Math.abs((acreage * RADIUS * RADIUS) / 2.0)); 
    } 
        
    public static void main(String[] args) { 
        System.out.println(getAreaInternal()); 
    }
}

調査結果

  • Google Maps JavaScript APIを用いた結果と同じ値が得られることがわかった。
  • このような実装をすることでGoogle Maps JavaScriptやその他ライブラリを用いなくても実装できることがわかった。

参考

GitHubで編集を提案

Discussion