jjugccc2016fall-javafx/src/com/torutk/tinymap/TinyMapViewController.java @ 844c5579
| b918a80d | TAKAHASHI,Toru | /*
|
||
* © 2016 Toru Takahashi
|
||||
*/
|
||||
package com.torutk.tinymap;
|
||||
| 844c5579 | TAKAHASHI,Toru | import static java.lang.String.format;
|
||
| b918a80d | TAKAHASHI,Toru | import java.net.URL;
|
||
import java.util.ResourceBundle;
|
||||
| 844c5579 | TAKAHASHI,Toru | import java.util.logging.Level;
|
||
import java.util.logging.Logger;
|
||||
| d6bce004 | TAKAHASHI,Toru | import javafx.beans.property.DoubleProperty;
|
||
import javafx.beans.property.SimpleDoubleProperty;
|
||||
| b918a80d | TAKAHASHI,Toru | import javafx.event.ActionEvent;
|
||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.Initializable;
|
||||
| d6bce004 | TAKAHASHI,Toru | import javafx.geometry.Point2D;
|
||
| 89092ba0 | TAKAHASHI,Toru | import javafx.scene.canvas.Canvas;
|
||
import javafx.scene.canvas.GraphicsContext;
|
||||
import javafx.scene.control.ComboBox;
|
||||
| b918a80d | TAKAHASHI,Toru | import javafx.scene.control.Label;
|
||
| 89092ba0 | TAKAHASHI,Toru | import javafx.scene.layout.Pane;
|
||
import javafx.scene.paint.Color;
|
||||
| d6bce004 | TAKAHASHI,Toru | import javafx.scene.transform.Affine;
|
||
| 844c5579 | TAKAHASHI,Toru | import javafx.scene.transform.NonInvertibleTransformException;
|
||
| d6bce004 | TAKAHASHI,Toru | import javafx.stage.Screen;
|
||
| b918a80d | TAKAHASHI,Toru | |||
/**
|
||||
*
|
||||
* @author Toru Takahashi
|
||||
*/
|
||||
public class TinyMapViewController implements Initializable {
|
||||
| 844c5579 | TAKAHASHI,Toru | |||
private static final Logger logger = Logger.getLogger(TinyMapViewController.class.getName());
|
||||
| d6bce004 | TAKAHASHI,Toru | private static final Affine IDENTITY_TRANSFORM = new Affine(); // 恒等変換(表示消去で使用)
|
||
private static final double METER_PER_INCH = 0.0254; // インチからメートルへの換算値
|
||||
| 844c5579 | TAKAHASHI,Toru | private static final double SCALE_RATE = 2; // 1段階の拡大縮小比
|
||
| b918a80d | TAKAHASHI,Toru | |||
@FXML
|
||||
| d6bce004 | TAKAHASHI,Toru | private Label scaleLabel; // 縮尺表示用ラベル
|
||
| 89092ba0 | TAKAHASHI,Toru | @FXML
|
||
| d6bce004 | TAKAHASHI,Toru | private ComboBox projectionComboBox; // 投影法選択コンボボックス
|
||
| 89092ba0 | TAKAHASHI,Toru | @FXML
|
||
| d6bce004 | TAKAHASHI,Toru | private Canvas mapCanvas; // 地図描画領域
|
||
| b918a80d | TAKAHASHI,Toru | @FXML
|
||
| 89092ba0 | TAKAHASHI,Toru | private Pane rootPane;
|
||
| 04f0d3d7 | TAKAHASHI,Toru | |||
| d6bce004 | TAKAHASHI,Toru | private Affine mapTransform = new Affine(); // 地図の拡大縮小スクロールの座標変換
|
||
private DoubleProperty scaleProperty = new SimpleDoubleProperty(1); // 地図の拡大率
|
||||
private double dotPitchInMeter; // 実行環境でのドットピッチを保持
|
||||
| 844c5579 | TAKAHASHI,Toru | private Point2D prevDragPoint; // 平行移動の開始点
|
||
| 04f0d3d7 | TAKAHASHI,Toru | private TinyMapModel mapModel;
|
||
| d6bce004 | TAKAHASHI,Toru | /**
|
||
* 地図データを読み込む。
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
| 89092ba0 | TAKAHASHI,Toru | @FXML
|
||
private void loadShapefile(ActionEvent event) {
|
||||
| b918a80d | TAKAHASHI,Toru | System.out.println("You clicked me!");
|
||
| 04f0d3d7 | TAKAHASHI,Toru | mapModel = new TinyMapModel();
|
||
mapModel.loadLines();
|
||||
drawMapCanvas();
|
||||
| b918a80d | TAKAHASHI,Toru | }
|
||
| 89092ba0 | TAKAHASHI,Toru | |||
/**
|
||||
* 地図表示領域を背景色(海)で塗りつぶす。
|
||||
*/
|
||||
private void clearMapCanvas() {
|
||||
GraphicsContext gc = mapCanvas.getGraphicsContext2D();
|
||||
| d6bce004 | TAKAHASHI,Toru | gc.setTransform(IDENTITY_TRANSFORM);
|
||
| 89092ba0 | TAKAHASHI,Toru | gc.setFill(Color.MIDNIGHTBLUE);
|
||
gc.fillRect(0, 0, mapCanvas.getWidth(), mapCanvas.getHeight());
|
||||
}
|
||||
| 04f0d3d7 | TAKAHASHI,Toru | |||
| d6bce004 | TAKAHASHI,Toru | /**
|
||
* 地図の描画
|
||||
*/
|
||||
| 04f0d3d7 | TAKAHASHI,Toru | private void drawMapCanvas() {
|
||
| 844c5579 | TAKAHASHI,Toru | logger.info(mapTransform.toString());
|
||
| d6bce004 | TAKAHASHI,Toru | clearMapCanvas();
|
||
| 844c5579 | TAKAHASHI,Toru | if (mapModel == null) {
|
||
return;
|
||||
}
|
||||
| d6bce004 | TAKAHASHI,Toru | GraphicsContext gc = mapCanvas.getGraphicsContext2D();
|
||
gc.setTransform(mapTransform);
|
||||
gc.setStroke(Color.LIGHTGREEN);
|
||||
gc.setLineWidth(1d / scaleProperty.get());
|
||||
| 04f0d3d7 | TAKAHASHI,Toru | mapModel.stream().forEach(polyline -> {
|
||
gc.strokePolyline(polyline.getXArray(), polyline.getYArray(), polyline.size());
|
||||
});
|
||||
}
|
||||
| b918a80d | TAKAHASHI,Toru | |||
@Override
|
||||
public void initialize(URL url, ResourceBundle rb) {
|
||||
| d6bce004 | TAKAHASHI,Toru | // 実行環境でのドットピッチを計算
|
||
dotPitchInMeter = 1 / Screen.getPrimary().getDpi() * METER_PER_INCH;
|
||||
// 拡大率の変更に縮尺ラベルの表示を連動
|
||||
scaleProperty.addListener((target, oldValue, newValue) -> {
|
||||
scaleLabel.setText(String.format("1/%,d", (int) (1 / (newValue.doubleValue() * dotPitchInMeter))));
|
||||
});
|
||||
// 初期縮尺の設定
|
||||
scaleProperty.set(1 / mapToScale(5_000));
|
||||
// ウィンドウサイズの変更に合わせて地図表示用Canvasの大きさを連動
|
||||
| 89092ba0 | TAKAHASHI,Toru | mapCanvas.widthProperty().bind(rootPane.widthProperty().subtract(120));
|
||
mapCanvas.heightProperty().bind(rootPane.heightProperty());
|
||||
| d6bce004 | TAKAHASHI,Toru | mapCanvas.widthProperty().addListener(event -> drawMapCanvas());
|
||
mapCanvas.heightProperty().addListener(event -> drawMapCanvas());
|
||||
// 地図の拡大縮小平行移動の座標変換初期値
|
||||
mapTransform = new Affine(scaleProperty.get(), 0, 0, 0, -scaleProperty.get(), 0);
|
||||
// マウスホイールで拡大縮小
|
||||
| 844c5579 | TAKAHASHI,Toru | mapCanvas.setOnScroll(event ->
|
||
zoom(event.getDeltaY() >= 0 ? scaleProperty.get() * SCALE_RATE : scaleProperty.get() / SCALE_RATE)
|
||||
);
|
||||
| d6bce004 | TAKAHASHI,Toru | // ドラッグで平行移動するための開始場所保持
|
||
mapCanvas.setOnMousePressed(event -> {
|
||||
| 844c5579 | TAKAHASHI,Toru | prevDragPoint = new Point2D(event.getSceneX(), event.getSceneY());
|
||
| d6bce004 | TAKAHASHI,Toru | });
|
||
// ドラッグで平行移動
|
||||
mapCanvas.setOnMouseDragged(event -> {
|
||||
Point2D dragPoint = new Point2D(event.getSceneX(), event.getSceneY());
|
||||
| 844c5579 | TAKAHASHI,Toru | Point2D translate = dragPoint.subtract(prevDragPoint);
|
||
prevDragPoint = dragPoint;
|
||||
mapTransform.setTx(mapTransform.getTx() + translate.getX());
|
||||
mapTransform.setTy(mapTransform.getTy() + translate.getY());
|
||||
| d6bce004 | TAKAHASHI,Toru | drawMapCanvas();
|
||
});
|
||||
| b918a80d | TAKAHASHI,Toru | }
|
||
| d6bce004 | TAKAHASHI,Toru | |||
/**
|
||||
* 地図縮尺(例: 1 / 10,000)をAffineのscaleに変換する.
|
||||
*
|
||||
* @param reduce 縮尺の母数(例: 10,000)
|
||||
* @return
|
||||
*/
|
||||
double mapToScale(double reduce) {
|
||||
return reduce * dotPitchInMeter;
|
||||
}
|
||||
| 844c5579 | TAKAHASHI,Toru | |||
/**
|
||||
* mapCanvasの画面中心位置の地図座標を計算
|
||||
*/
|
||||
private Point2D getCenterOfDisplayInMap() throws NonInvertibleTransformException {
|
||||
return mapTransform.inverseTransform(getCenterOfDisplay());
|
||||
}
|
||||
/**
|
||||
* mapCanvasの中心画面座標を返却する。
|
||||
*
|
||||
* @return mapCanvasの中心画面座標
|
||||
*/
|
||||
private Point2D getCenterOfDisplay() {
|
||||
return new Point2D(mapCanvas.getWidth() / 2, mapCanvas.getHeight() / 2);
|
||||
}
|
||||
/**
|
||||
* 地図表示の拡大・縮小処理。
|
||||
* <p>
|
||||
* 画面の真ん中を中心に拡大・縮小表示する。
|
||||
* <p>
|
||||
* 次の座標変換を行う。
|
||||
* <ul>
|
||||
* <li> Y軸の正負変換
|
||||
* <li> スケール変換
|
||||
* <li> 並行移動
|
||||
* </ul>
|
||||
* これらを合成すると次のAffine行列となる。
|
||||
* <pre>
|
||||
* | scale 0 画面の中心画素(x) - (画面の中心に位置する地図座標(x) * scale) |
|
||||
* | 0 scale 画面の中心画素(y) + (画面の中心に位置する地図座標(y) * scale) |
|
||||
* </pre>
|
||||
*
|
||||
* @param scale 拡大率
|
||||
*/
|
||||
private void zoom(double scale) {
|
||||
try {
|
||||
scaleProperty.set(scale);
|
||||
Point2D centerOfDisplayInMap = getCenterOfDisplayInMap();
|
||||
Point2D centerOfDisplay = getCenterOfDisplay();
|
||||
double tx = centerOfDisplay.getX() - centerOfDisplayInMap.getX() * scale;
|
||||
double ty = centerOfDisplay.getY() + centerOfDisplayInMap.getY() * scale;
|
||||
mapTransform.setToTransform(
|
||||
scaleProperty.get(), 0, tx,
|
||||
0, -scaleProperty.get(), ty
|
||||
);
|
||||
drawMapCanvas();
|
||||
} catch (NonInvertibleTransformException ex) {
|
||||
Logger.getLogger(TinyMapViewController.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
| b918a80d | TAKAHASHI,Toru | }
|