Skip to content

Package: MapViewExampleController$1PointsAndArea

MapViewExampleController$1PointsAndArea

nameinstructionbranchcomplexitylinemethod
{...}
M: 0 C: 9
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%

Coverage

1: /*
2: * *************************************************************************************************************************************************************
3: *
4: * MapView: a JavaFX map renderer for tile-based servers
5: * http://tidalwave.it/projects/mapview
6: *
7: * Copyright (C) 2024 - 2025 by Tidalwave s.a.s. (http://tidalwave.it)
8: *
9: * *************************************************************************************************************************************************************
10: *
11: * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
12: * You may obtain a copy of the License at
13: *
14: * http://www.apache.org/licenses/LICENSE-2.0
15: *
16: * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
17: * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
18: *
19: * *************************************************************************************************************************************************************
20: *
21: * git clone https://bitbucket.org/tidalwave/mapview-src
22: * git clone https://github.com/tidalwave-it/mapview-src
23: *
24: * *************************************************************************************************************************************************************
25: */
26: package it.tidalwave.mapview.javafx.example;
27:
28: import jakarta.annotation.Nonnull;
29: import java.util.Collection;
30: import java.util.List;
31: import java.util.concurrent.ExecutionException;
32: import java.util.concurrent.ExecutorService;
33: import java.util.concurrent.Executors;
34: import java.io.IOException;
35: import java.io.UncheckedIOException;
36: import java.nio.file.Path;
37: import javafx.concurrent.Task;
38: import javafx.fxml.FXML;
39: import javafx.scene.Node;
40: import javafx.scene.control.Button;
41: import javafx.scene.control.Label;
42: import javafx.scene.control.Slider;
43: import javafx.scene.layout.AnchorPane;
44: import javafx.scene.paint.Color;
45: import javafx.scene.shape.Circle;
46: import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
47: import io.jenetics.jpx.GPX;
48: import io.jenetics.jpx.Track;
49: import io.jenetics.jpx.TrackSegment;
50: import io.jenetics.jpx.WayPoint;
51: import it.tidalwave.mapviewer.MapArea;
52: import it.tidalwave.mapviewer.MapCoordinates;
53: import it.tidalwave.mapviewer.OpenStreetMapTileSource;
54: import it.tidalwave.mapviewer.OpenTopoMapTileSource;
55: import it.tidalwave.mapviewer.TileSource;
56: import it.tidalwave.mapviewer.javafx.MapView;
57: import lombok.Getter;
58: import lombok.extern.slf4j.Slf4j;
59: import static lombok.AccessLevel.PROTECTED;
60:
61: /***************************************************************************************************************************************************************
62: *
63: * @author Fabrizio Giudici
64: *
65: **************************************************************************************************************************************************************/
66: @Getter(PROTECTED) @Slf4j
67: public class MapViewExampleController
68: {
69: private static final Path CACHE_FOLDER = Path.of("target/tile-cache");
70:
71: private static final String TRACK_OVERLAY_NAME = "track";
72: private static final MapCoordinates START = MapCoordinates.of(44.4072, 8.9340);
73: private static final double START_ZOOM = 8;
74: private static final MapArea ITALY = MapArea.of(47.115, 18.480, 36.6199, 6.749);
75: private static final MapArea FRANCE = MapArea.of(51.148, 9.560, 2.053, -54.524);
76: private static final MapArea SWITZERLAND = MapArea.of(47.830, 10.442, 45.776, 6.022);
77: private static final MapArea ALEUTIAN = MapArea.of(62.67, -147.38, 46.32, 161.64 );
78: private static final TileSource osm = new OpenStreetMapTileSource();
79: private static final TileSource otm = new OpenTopoMapTileSource();
80:
81: @FXML
82: private AnchorPane apAnchorPane;
83:
84: @FXML
85: private Slider slZoom;
86:
87: @FXML
88: private Button btZoomIn;
89:
90: @FXML
91: private Button btZoomOut;
92:
93: @FXML
94: private Button btReset;
95:
96: @FXML
97: private Button btShowItaly;
98:
99: @FXML
100: private Button btShowFrance;
101:
102: @FXML
103: private Button btShowSwitzerland;
104:
105: @FXML
106: private Button btShowAleutian;
107:
108: @FXML
109: private Button btZeroZero;
110:
111: @FXML
112: private Button btTrack;
113:
114: @FXML
115: private Button btOSM;
116:
117: @FXML
118: private Button btOTM;
119:
120: @FXML
121: private Label lbCoordinates;
122:
123: @FXML
124: private Label lbArea;
125:
126: @FXML
127: private Label lbCenterCoordinates;
128:
129: @FXML
130: private Label lbZoom;
131:
132: private MapView mapView;
133:
134: @Nonnull
135: private final ExecutorService executorService = Executors.newFixedThreadPool(1);
136:
137: /***********************************************************************************************************************************************************
138: *
139: **********************************************************************************************************************************************************/
140: public void initialize()
141: {
142: mapView = new MapView(MapView.options().withCacheFolder(CACHE_FOLDER));
143: mapView.setZoom(START_ZOOM);
144: mapView.setCenter(START);
145: mapView.setRecenterOnDoubleClick(true);
146: AnchorPane.setLeftAnchor(mapView, 0.0);
147: AnchorPane.setRightAnchor(mapView, 0.0);
148: AnchorPane.setTopAnchor(mapView, 0.0);
149: AnchorPane.setBottomAnchor(mapView, 0.0);
150: apAnchorPane.getChildren().add(mapView);
151: mapView.setRecenterOnDoubleClick(true);
152: slZoom.minProperty().bind(mapView.minZoomProperty());
153: slZoom.maxProperty().bind(mapView.maxZoomProperty());
154: slZoom.valueProperty().bindBidirectional(mapView.zoomProperty());
155: mapView.centerProperty().addListener((_1, _2, coordinates) -> lbCenterCoordinates.setText(coordinates.toString()));
156: mapView.zoomProperty().addListener((_1, _2, zoom) -> lbZoom.setText(Integer.toString(zoom.intValue())));
157: mapView.areaProperty().addListener((_1, _2, area) -> lbArea.setText(area.toString()));
158: mapView.mouseCoordinatesProperty().addListener((_1, _2, coordinates) -> lbCoordinates.setText(coordinates.toString()));
159: btZoomIn.setOnAction(event -> mapView.setZoom(mapView.getZoom() + 1));
160: btZoomOut.setOnAction(event -> mapView.setZoom(mapView.getZoom() - 1));
161: btReset.setOnAction(event -> { mapView.setCenter(START); mapView.setZoom(START_ZOOM); });
162: btShowItaly.setOnAction(event -> mapView.fitArea(ITALY));
163: btShowFrance.setOnAction(event -> mapView.fitArea(FRANCE));
164: btShowSwitzerland.setOnAction(event -> mapView.fitArea(SWITZERLAND));
165: btShowAleutian.setOnAction(event -> mapView.fitArea(ALEUTIAN));
166: btZeroZero.setOnAction(event -> mapView.setCenter(MapCoordinates.of(0, 0)));
167: btOSM.setOnAction(event -> mapView.setTileSource(osm));
168: btOTM.setOnAction(event -> mapView.setTileSource(otm));
169: btTrack.setOnAction(event -> renderTrack());
170: }
171:
172: /***********************************************************************************************************************************************************
173: *
174: **********************************************************************************************************************************************************/
175: @SuppressFBWarnings("RV_RETURN_VALUE_IGNORED_BAD_PRACTICE")
176: public void renderTrack()
177: {
178: record PointsAndArea(List<WayPoint> points, MapArea area) {}
179:
180: final var task = new Task<PointsAndArea>()
181: {
182: @Override @Nonnull
183: protected PointsAndArea call()
184: {
185: final var track = loadTrack();
186: final var points = track.segments().flatMap(TrackSegment::points).toList();
187: final var area = computeFitArea(points);
188: log.info("track with {} points, fit area: {}", points.size(), area);
189: return new PointsAndArea(points, area);
190: }
191: };
192:
193: task.setOnSucceeded(event ->
194: {
195: try
196: {
197: final var pointsAndArea = task.get();
198: mapView.removeOverlay(TRACK_OVERLAY_NAME);
199: mapView.addOverlay(TRACK_OVERLAY_NAME, helper ->
200: helper.addAll(pointsAndArea.points.stream().map(wp -> createPoint(helper, wp)).toList()));
201: mapView.fitArea(pointsAndArea.area);
202: }
203: catch (InterruptedException e)
204: {
205: log.error("", e);
206: Thread.currentThread().interrupt();
207: }
208: catch (ExecutionException e)
209: {
210: log.error("", e);
211: }
212: });
213:
214: executorService.submit(task);
215: }
216:
217: /***********************************************************************************************************************************************************
218: *
219: **********************************************************************************************************************************************************/
220: @Nonnull
221: private static Node createPoint (@Nonnull final MapView.OverlayHelper helper, @Nonnull final WayPoint wp)
222: {
223: final var mapPoint = helper.toMapViewPoint(MapCoordinates.of(wp.getLatitude().doubleValue(), wp.getLongitude().doubleValue()));
224: final var node = new Circle(2.5, Color.RED);
225: node.setVisible(true);
226: node.setTranslateX(mapPoint.x());
227: node.setTranslateY(mapPoint.y());
228: return node;
229: }
230:
231: /***********************************************************************************************************************************************************
232: *
233: **********************************************************************************************************************************************************/
234: @Nonnull
235: private static MapArea computeFitArea (@Nonnull final Collection<WayPoint> points)
236: {
237: // quick and dirty, just for this example
238: var north = -999d;
239: var south = 999d;
240: var east = -999d;
241: var west = 999d;
242:
243: for (final var point : points)
244: {
245: north = Math.max(north, point.getLatitude().doubleValue());
246: south = Math.min(south, point.getLatitude().doubleValue());
247: east = Math.max(east, point.getLongitude().doubleValue());
248: west = Math.min(west, point.getLongitude().doubleValue());
249: }
250:
251: return MapArea.of(north, east, south, west);
252: }
253:
254: /***********************************************************************************************************************************************************
255: *
256: **********************************************************************************************************************************************************/
257: @Nonnull
258: private Track loadTrack()
259: {
260: try (final var is = MapViewExampleController.class.getResourceAsStream("/2014-04-10 1800__20140410_1800.gpx"))
261: {
262: return GPX.Reader.of(GPX.Reader.Mode.LENIENT).read(is).getTracks().getFirst();
263: }
264: catch (IOException e)
265: {
266: log.error(e.toString());
267: throw new UncheckedIOException(e);
268: }
269: }
270: }