プロジェクト

全般

プロフィール

発表ネタ - JJUG CCC 2016 Fall向け

企画概要

昨今では、地図を見たいときはGoogle Mapsを代表にいくつかのWebサービスを使って見ることが多いでしょう。このWebサービスで提供される地図は、多くがメルカトル図法で投影したものになっています。このメルカトル図法は16世紀に考案され、当時の羅針盤で航海する用途に適していました。しかし、緯度が高いほど縦横に引き伸ばされる性質があり、市街や県・地方などの狭い範囲を表示する分には問題が目立ちませんが、世界地図を表示するとなると歪みが大きくなります。有名な話では、グリーンランドがオーストラリアより大きく見える、日本から真東に向かうと北米に至るように見えるが実は南米である、などです。世界を正しく把握するには、メルカトル図法で表示した地図だけは不十分です。
そこで、より世界を正しく把握するために、メルカトル図法以外で投影した地図を表示するプログラムをJavaFXで作成します。本セッションでは、世界の海岸線データをもとに、オープンソースの地図投影ライブラリ(Proj4j)を用いていろいろな投影法で投影した地図をJavaFXで表示、任意に拡大・縮小・スクロールするプログラムをステップ・バイ・ステップで紹介します。

構成

アジェンダ

  • 問題提起~メルカトル投影の地図サービス
  • 投影法の基礎
  • JavaFXで地図投影

スライド

発表スライド

調査・検討記録

投影法

面積比(インド、カザフスタン、アラスカ)

ArcGIS 10.4.1 と Esri Data & Maps 2015 の国別ポリゴン(country_gen)を使って、異なる投影法で投影した地図上の国の面積を比較しました。
面積は、計測ツールでフィーチャー計測を選択し、対象ポリゴンをクリックして取得しました。

国・州名 投影法 統計データ
Webメルカトル グードホモロサイン
インド 3,772,217 ㎢ 3,166,802 ㎢ 3,287,263 ㎢
カザフスタン 6,390,214 ㎢ 2,840,355 ㎢ 2,724,900 ㎢
アラスカ 7,875,936 ㎢ 1,422,917 ㎢ 1,718,000 ㎢
Webメルカトル投影 グードホモロサイン投影
worldmap_mercator.png worldmap_goode.png

世界の国の面積順位は、インドが7位、カザフスタンが9位です。アラスカは国ではないですが、ほぼ同等面積のリビアが16位です。

面積比(北海道、九州)

国・州名 投影法 統計データ
Webメルカトル アルベルス正積円錐
北海道 146,982 ㎢ 77,582 ㎢ 83,450 ㎢
九州 52,004 ㎢ 36,756 ㎢ 36,750 ㎢
四国 26,482 ㎢ 18,297 ㎢ 18,800 ㎢
Webメルカトル投影 アルベルス正積円錐投影
japanmap_mercator.png japanmap_albers.png

形状の比較(日本列島)

先のWebメルカトル投影とアルベルス正積円錐投影を同一縮尺(2千万分の1)で重ねてみました。

japancoastline_superimposed_albers_webmercator.png
  • 赤の海岸線はWebメルカトル投影です
  • 青の海岸線はアルベルス正積円錐投影です

Googleマップ

  • 地理座標系(測地系): 半径 6,378,137m、扁平率の逆数 0
  • 投影座標系: メルカトル(南北85度より大きい緯度は切り捨てて、縦横が同じちょうど正方形としている)
    EPSGコード 3857

ただし、地図上の点と緯度経度との変換(API)において緯度経度はWGS84として扱うので、利用者は地理座標系を気にすることはない。

ズームレベル0(最小縮尺)では世界は256pixel四方
ズームレベル1では世界は256pixel正方形が4枚となる
ズームレベル2以降、正方形のタイル画像が4倍ずつ増えていく

参考文献

地図

Googleマップの投影法 インターネット時代におけるメルカトル図法の再評価(佐藤崇徳氏、日本地図センター刊「地図中心」2011年1月号)
Webメルカトル(ウェブメルカトル)」の由来と真相
日本全国に適用できる最適な正積図法は何か?
中央子午線を東経135度に、第1・第2標準緯線を共に北緯40度とした設定
Early world maps - Wikipedia

JavaFX

素材

地図投影法学習のための地図画像素材集(佐藤崇徳氏)

デモプログラム

デモプログラムのリポジトリ

JavaFXプログラム作成環境

  • NetBeans IDE 8.2

NetBeans_Darcula_itaeditor-1.png

  • Scene Builder 8.2

SceneBuilder_Dark-1.png

  • JDK 8u112

NetBeansプロジェクト作成

[ファイル]メニュー > [新規プロジェクト] で、カテゴリ欄から[JavaFX]を選択、右側プロジェクト欄から[JavaFX FXMLアプリケーション]を選択し、[次へ]

NetBeans_NewProject-1.png

  • プロジェクト名に、[TinyMap]
    → トップディレクトリ名、生成されるJARファイル名
  • プロジェクトの場所を適切な場所
    → トップディレクトリが置かれる場所
  • FXML名に、[TinyMapView]
    → FXML名とそのFXMLに紐づけられるコントローラクラス名の基底(TinyMapViewController)
  • アプリケーション・クラスの作成に、[com.torutk.tinymap.TinyMapApp]
    → パッケージ名とアプリケーション派生クラス(mainメソッドを持つクラス)

NetBeans_NewProject-2.png

生成されるファイルは

TinyMap/
├── build.xml
├── manifest.mf
├── nbproject
│   ├── build-impl.xml
│   ├── configs
│   │   ├── _______.properties
│   │   └── WebStart_____.properties
│   ├── genfiles.properties
│   ├── jfx-impl.xml
│   ├── private
│   │   ├── configs
│   │   │   ├── _______.properties
│   │   │   └── WebStart_____.properties
│   │   └── private.properties
│   ├── project.properties
│   └── project.xml
└── src
    └── com
        └── torutk
            └── tinymap
                ├── TinyMapApp.java
                ├── TinyMapView.fxml
                └── TinyMapViewController.java

プロジェクトペインのTinyMapView.fxmlをダブルクリックするとScene Builderが起動します。

SceneBuilder-1.png

プロジェクトを実行すると次の画面が表示されます。

NetBeans_Run-1.png

Gitリポジトリ作成

生成したプロジェクトをGitリポジトリ(ローカル)として初期化

  • プロジェクトペインで[TinyMap]を右クリックし、[バージョン管理] > [Gitリポジトリの初期化]をクリック

NetBeans_GitInit-1.png

  • リポジトリ生成ディレクトリはデフォルト(TinyMapディレクトリ)
  • 初期化後、プロジェクト管理下の対象ファイルはステージング(追加済み)状態となっています

NetBeans_GitInit-2.png

コミット

  • プロジェクトペインで[TinyMap]を右クリックし、[バージョン管理] > [コミット]をクリック

NetBeans_GitInit-3.png

コミット後、プロジェクト管理下の対象ファイルはコミット済み状態となっています

NetBeans_GitInit-4.png

Scene Builderで画面作成

Canvas、Button、Label、ComboBoxの配置

AnchorPane に、地図表示用Canvas、地図データ読み込みButton、縮尺表示Label、投影法選択ComboBoxの4つを貼ります。

SceneBuilder_Layout-1.png

ここでは、ウィンドウの大きさを変えたときに各部品がレイアウトを維持するよう、各部品に必要なアンカー設定もしておきます。

部品 アンカー
Canvas
Label
ComboBox
Button
  • ただし、CanvasはリサイズしてもPrefSizeを維持したままであった。別途処置が必要

NetBeans IDE Tips

ソースファイル先頭の著作権表記の設定

NetBeans ライセンスヘッダーの指定

リポジトリに登録しないディレクトリ

  • nbproject/private ディレクトリ
  • build ディレクトリ
  • dist ディレクトリ

Scene Builder Tips

ウィンドウの大きさ

StageおよびSceneの大きさを指定していない場合(JavaFXアプリケーション雛形で生成されたコードのデフォルト)、トップのコンテナの大きさによりウィンドウの大きさが決まります。
JavaFXアプリケーション雛形で生成されたFXMLファイルでは、AnchorPaneのPref WidthとPref Heightが320, 200となっています。

JavaFXプログラミング

CanvasサイズをAnchorPaneの制約に従って伸び縮みさせたい

Canvasは、レイアウトでAnchorPaneの上下左右にアンカーを貼っても、サイズが変わりませんでした。
ScenicViewを使うと詳しい情報が得られます。

ScenicView_Canvas-1.png

  • isResizableがfalseになっている
    CanvasはNodeを継承していますが、NodeはisResizableがfalseを返す実装となっており、CanvasはisResizableをオーバーライドしていないのでfalseとなります。

ググってみると、Canvasを独自に継承し、isResizable、などをオーバーライドする方法が見つかります。
今回は、サブクラスは作らず(Scene Builderでぽとぺたしたいので)、ルートペイン(anchorPane)のwidthプロパティ・heightプロパティにバインドしてCanvasのサイズを変更するようにしました。

マウスカーソルの位置を中心に拡大縮小したい

起動後1回もスクロール(ドラッグ)をしないときは、左上(0,0)を拡大縮小の原点としています(となっています)。
スクロールをしたあとは、拡大縮小すると表示場所がずれてしまいます。


ほぼ7年前に更新