From a57e430ead3d68a232f0a84627975e51510961b8 Mon Sep 17 00:00:00 2001 From: Mario-S Date: Mon, 2 Dec 2013 22:39:44 +0100 Subject: [PATCH 1/3] forcing to center the map removed, javadoc added, cleanup --- src/main/java/jfxtras/labs/map/MapPane.java | 1252 ++++++++--------- .../labs/map/render/LicenseRenderer.java | 4 +- .../jfxtras/labs/map/render/TileRenderer.java | 2 + .../map/tile/AbstractTileLoadStrategy.java | 117 +- .../labs/map/tile/CacheLoadStrategy.java | 50 +- .../labs/map/tile/RefreshLoadStrategy.java | 50 +- src/main/java/jfxtras/labs/map/tile/Tile.java | 2 - .../labs/map/tile/bing/BingTileSource.java | 3 +- 8 files changed, 734 insertions(+), 746 deletions(-) diff --git a/src/main/java/jfxtras/labs/map/MapPane.java b/src/main/java/jfxtras/labs/map/MapPane.java index 92ab66fc4..c0833152b 100644 --- a/src/main/java/jfxtras/labs/map/MapPane.java +++ b/src/main/java/jfxtras/labs/map/MapPane.java @@ -1,24 +1,22 @@ /** * MapPane.java * - * Copyright (c) 2011-2013, JFXtras - * All rights reserved. - * + * Copyright (c) 2011-2013, JFXtras All rights reserved. + * * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * modification, are permitted provided that the following conditions are met: * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. * Redistributions in binary + * form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided + * with the distribution. * Neither the name of the nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND @@ -26,7 +24,6 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package jfxtras.labs.map; import jfxtras.labs.map.tile.ZoomBounds; @@ -63,619 +60,618 @@ import static jfxtras.labs.map.CoordinatesConverter.*; /** - * + * * @author smithjel * @author Mario Schroeder */ public final class MapPane extends Pane implements MapTilesourceable { - private static final int INITIAL_ZOOM = 9; - - private static final int SIZE = 600; - - private static final int START = 0; - - private static final String STYLE_LOC = "cursorLocation"; - - private TileProvideable tilesProvider; - - private TileRenderable tileRenderer; - - private MapEdgeChecker mapEdgeChecker; - - private ObservableList mapLayers = observableArrayList(); - - // X&Y position of the center of this map on the world - // in screen pixels for the current zoom level. - private Point center = new Point(); - - // Current zoom level - private SimpleIntegerProperty zoom; - - private SimpleIntegerProperty minZoom = new SimpleIntegerProperty(ZoomBounds.MIN.getValue()); - - private SimpleIntegerProperty maxZoom = new SimpleIntegerProperty(ZoomBounds.MAX.getValue()); - - private boolean ignoreRepaint; - - private Rectangle clipMask = new Rectangle(); - - private Group tilesGroup; - - private Text cursorLocationText; - - private SimpleIntegerProperty mapWidth = new SimpleIntegerProperty(SIZE); - - private SimpleIntegerProperty mapHeight = new SimpleIntegerProperty(SIZE); - - private SimpleBooleanProperty mapMarkersVisible = new SimpleBooleanProperty( - true); - - private boolean cursorLocationVisible = true; - - private SimpleBooleanProperty mapPolygonsVisible = new SimpleBooleanProperty( - true); - - private CoordinateStringFormater formater; - - private boolean tilesPrepared; - - private ZoomCoordinateCache zoomCoordinateCache = new ZoomCoordinateCache(); - - private ZoomChangeListener zoomChangeListener = new ZoomChangeListener(); - - public MapPane(TileSource ts) { - this(ts, SIZE, SIZE, INITIAL_ZOOM); - } - - public MapPane(TileSource tileSource, int width, int height, int zoom) { - this.zoom = new SimpleIntegerProperty(zoom); - formater = new CoordinateStringFormater(); - - tilesGroup = new Group(); - - tilesProvider = new TileRepository(tileSource); - setZoomBounds(tileSource); - tileRenderer = new TileRenderer(tilesProvider); - mapEdgeChecker = new MapEdgeChecker(tileRenderer); - - int tileSize = tileSource.getTileSize(); - setMinSize(tileSize, tileSize); - - DropShadow ds = new DropShadow(); - ds.setOffsetY(3.0f); - ds.setColor(Color.BLACK); - cursorLocationText = new Text(""); - cursorLocationText.setId(STYLE_LOC); - cursorLocationText.setEffect(ds); - cursorLocationText.setFontSmoothingType(FontSmoothingType.LCD); - - clipMask.setFill(Color.WHITE); - tilesGroup.setClip(clipMask); - getChildren().add(tilesGroup); - getChildren().add(cursorLocationText); - - addRenderChangeListener(); - addSizeListeners(); - - setPrefSize(width, height); - - centerMap(); - - setTilesMouseHandler(new TilesMouseHandler()); - - clipMask.setWidth(Double.MAX_VALUE); - clipMask.setHeight(Double.MAX_VALUE); - - this.zoom.addListener(zoomChangeListener); - } - - public final void setTilesMouseHandler(TilesMouseHandler handler) { - handler.setEventPublisher(this); - } - - private void addRenderChangeListener() { - RenderChangeListener listener = new RenderChangeListener(); - mapLayers.addListener(listener); - - mapMarkersVisible.addListener(listener); - mapPolygonsVisible.addListener(listener); - } - - private void addSizeListeners() { - widthProperty().addListener(new ChangeListener() { - @Override - public void changed(ObservableValue observable, - Number oldValue, Number newValue) { - setMapWidth(newValue.doubleValue()); - } - }); - heightProperty().addListener(new ChangeListener() { - @Override - public void changed(ObservableValue observable, - Number oldValue, Number newValue) { - setMapHeight(newValue.doubleValue()); - } - }); - - mapWidth.addListener(new ChangeListener() { - @Override - public void changed(ObservableValue observable, - Number oldValue, Number newValue) { - clipMask.setWidth((Integer)newValue); - adjustCursorLocationText(); - renderControl(); - } - }); - - mapHeight.addListener(new ChangeListener() { - @Override - public void changed(ObservableValue observable, - Number oldValue, Number newValue) { - clipMask.setHeight((Integer)newValue); - adjustCursorLocationText(); - renderControl(); - } - }); - } - - @Override - public void setCursorLocationText(double x, double y) { - if (cursorLocationVisible) { - Coordinate coord = getCoordinate(new Point((int) x, (int) y)); - cursorLocationText.setText(formater.format(coord)); - } - } - - @Override - public void adjustCursorLocationText() { - double strwidth = cursorLocationText.getBoundsInParent().getWidth(); - double x = (double) ((getMapWidth() / 2) - (strwidth / 2)); - int y = getMapHeight() - 28; - - cursorLocationText.setLayoutX(x); - cursorLocationText.setLayoutY(y); - } - - public void setDisplayPositionByLatLon(double lat, double lon) { - setDisplayPositionByLatLon(createMapCenterPoint(), lat, lon, zoom.get()); - } - - private Point createMapCenterPoint() { - return new Point((int) (getMapWidth() / 2), (int) (getMapHeight() / 2)); - } - - private void setDisplayPositionByLatLon(Point mapPoint, double lat, - double lon, int zoom) { - int x = Mercator.lonToX(lon, zoom); - int y = Mercator.latToY(lat, zoom); - setDisplayPosition(mapPoint, x, y, zoom); - } - - private void setDisplayPosition(int x, int y, int zoom) { - setDisplayPosition(createMapCenterPoint(), x, y, zoom); - } - - private void setDisplayPosition(Point mapPoint, int x, int y, int zoom) { - if (isValidZoom(zoom)) { - // Get the plain tile number - moveCenter(mapPoint, x, y); -// this.zoom.set(zoom); - renderControl(); - } - } - - private void moveCenter(Point mapPoint, int x, int y) { - center.x = x - mapPoint.x + (int) (getMapWidth() / 2); - center.y = y - mapPoint.y + (int) (getMapHeight() / 2); - } - - public void setDisplayToFitMapMarkers() { - List markers = getMapMarkers(); - if (!markers.isEmpty()) { - int x_min = Integer.MAX_VALUE; - int y_min = Integer.MAX_VALUE; - int x_max = Integer.MIN_VALUE; - int y_max = Integer.MIN_VALUE; - int mapZoomMax = getTileSource().getMaxZoom(); - - for (MapMarkable marker : markers) { - int x = Mercator.lonToX(marker.getLon(), mapZoomMax); - int y = Mercator.latToY(marker.getLat(), mapZoomMax); - x_max = Math.max(x_max, x); - y_max = Math.max(y_max, y); - x_min = Math.min(x_min, x); - y_min = Math.min(y_min, y); - } - - int height = (int) Math.max(START, getMapHeight()); - int width = (int) Math.max(START, getMapWidth()); - int newZoom = mapZoomMax; - int x = x_max - x_min; - int y = y_max - y_min; - while (x > width || y > height) { - newZoom--; - x >>= 1; - y >>= 1; - } - x = x_min + (x_max - x_min) / 2; - y = y_min + (y_max - y_min) / 2; - int z = 1 << (mapZoomMax - newZoom); - x /= z; - y /= z; - setDisplayPosition(x, y, newZoom); - } - } - - private List getMapMarkers() { - List markers = new ArrayList<>(); - // a bit ugly to filter out by instance of - for (Renderable layer : mapLayers) { - if (layer instanceof MapMarkable) { - markers.add((MapMarkable) layer); - } - } - return markers; - } - - public void setDisplayToFitMapRectangle() { - if (!mapLayers.isEmpty()) { - int x_min = Integer.MAX_VALUE; - int y_min = Integer.MAX_VALUE; - int x_max = Integer.MIN_VALUE; - int y_max = Integer.MIN_VALUE; - int mapZoomMax = getTileSource().getMaxZoom(); - - int height = (int) Math.max(START, getMapHeight()); - int width = (int) Math.max(START, getMapWidth()); - int newZoom = mapZoomMax; - int x = x_max - x_min; - int y = y_max - y_min; - while (x > width || y > height) { - newZoom--; - x >>= 1; - y >>= 1; - } - x = x_min + (x_max - x_min) / 2; - y = y_min + (y_max - y_min) / 2; - int z = 1 << (mapZoomMax - newZoom); - x /= z; - y /= z; - setDisplayPosition(x, y, newZoom); - } - } - - @Override - public void moveMap(int x, int y) { - zoomCoordinateCache.clear(); - - Point previous = new Point(center); - center.x += x; - center.y += y; - - if (prepareTiles() > 0 && !isOnEdge()) { - tilesPrepared = true; - } else { - center = previous; - prepareTiles(); - } - - renderControl(); - } - - private boolean isOnEdge() { - Dimension dim = new Dimension(getMapWidth(), getMapHeight()); - return mapEdgeChecker.isOnEdge(dim); - } - - /** - * centers the map - */ - @Override - public final void centerMap() { - setDisplayPositionByLatLon(START, START); - zoomCoordinateCache.clear(); - } - - @Override - public SimpleIntegerProperty zoomProperty() { - return zoom; - } - - @Override - public void zoomIn(Point mapPoint) { - updateZoom(zoom.get() + 1, mapPoint); - } - - @Override - public void zoomOut(Point mapPoint) { - updateZoom(zoom.get() - 1, mapPoint); - } - - private void setZoom(int nextZoom) { - zoom.set(nextZoom); - } - - private void updateZoom(int nextZoom) { - Point mapPoint = createMapCenterPoint(); - updateZoom(nextZoom, mapPoint, zoomCoordinateCache.getZoomCoordinate()); - } - - private void updateZoom(int nextZoom, Point mapPoint) { - zoomCoordinateCache.clear(); - Coordinate zoomPos = getCoordinate(mapPoint); - updateZoom(nextZoom, mapPoint, zoomPos); - } - - private void updateZoom(int nextZoom, Point mapPoint, Coordinate zoomPos) { - if (isValidZoom(nextZoom)) { - setDisplayPositionByLatLon(mapPoint, zoomPos.getLatitude(), - zoomPos.getLongitude(), nextZoom); - - if (isEdgeVisible()) { -// centerMap(); - } - } - } - - private boolean isValidZoom(int nextZoom) { - return nextZoom <= getMaxZoom() && nextZoom >= getMinZoom(); - } - - private boolean isEdgeVisible() { - Dimension dim = new Dimension(getMapWidth(), getMapHeight()); - return mapEdgeChecker.isAnyVisible(dim); - } - - private Coordinate getCoordinate(Point p) { - return toCoordinate(p, this); - } - - private Coordinate getCoordinate(Point p, int zoom) { - Dimension dim = new Dimension(getMapWidth(), getMapHeight()); - return toCoordinate(p, center, dim, zoom); - } - - public void setMapMarkerVisible(boolean mapMarkersVisible) { - this.mapMarkersVisible.set(mapMarkersVisible); - } - - public void removeMapLayer(Renderable layer) { - mapLayers.remove(layer); - } - - public void addMapLayer(Renderable layer) { - mapLayers.add(layer); - } - - public void setTileSource(TileSource tileSource) { - int minZoom = tileSource.getMinZoom(); - int maxZoom = tileSource.getMaxZoom(); - if (maxZoom > ZoomBounds.MAX.getValue()) { - throw new IllegalArgumentException("Maximum zoom level too high"); - } - if (minZoom < ZoomBounds.MIN.getValue()) { - throw new IllegalArgumentException("Minumim zoom level too low"); - } - tilesProvider.setTileSource(tileSource); - setZoomBounds(tileSource); - //set zoom according to max or min available zoom - if (zoom.get() > maxZoom) { - setZoom(maxZoom); - }else if(zoom.get() < minZoom){ - setZoom(minZoom); - } - zoomCoordinateCache.clear(); - - renderControl(); - } - - protected void renderControl() { - - if (!ignoreRepaint) { - boolean changed = renderMap(); - - if (changed) { - - renderMapLayers(); - renderAttribution(); - } - } - } - - protected boolean renderMap() { - - boolean updated = false; - - if (!tilesPrepared) { - if (prepareTiles() > 0) { - tileRenderer.render(tilesGroup); - updated = true; - } - } else { - tileRenderer.render(tilesGroup); - updated = true; - } - - tilesPrepared = false; - - return updated; - } - - private int prepareTiles() { - return tileRenderer.prepareTiles(this); - } - - protected void renderMapLayers() { - for (Renderable overlay : mapLayers) { - if (isEnabled(overlay)) { - overlay.render(this); - } - } - } - - protected boolean isEnabled(Renderable renderable) { - boolean enabled = true; - if ((renderable instanceof MapPolygonable && !isMapPolygonsVisible())) { - enabled = false; - } else if (renderable instanceof MapMarkable - || renderable instanceof MapLineable) { - enabled = mapMarkersVisible.get(); - } - return enabled; - } - - protected void renderAttribution() { - - if (getTileSource().isAttributionRequired()) { - Renderable renderer = new LicenseRenderer(); - renderer.render(this); - } - } - - public void refereshMap() { - tileRenderer.refresh(this); - renderMapLayers(); - renderAttribution(); - } - - public void setMapWidth(double val) { - mapWidth.set((int) val); - } - - @Override - public int getMapWidth() { - return mapWidth.get(); - } - - public void setMapHeight(double val) { - mapHeight.set((int) val); - } - - @Override - public int getMapHeight() { - return mapHeight.get(); - } - - public void setMapPolygonsVisible(boolean val) { - this.mapPolygonsVisible.set(val); - } - - public boolean isMapPolygonsVisible() { - return this.mapPolygonsVisible.get(); - } - - public void setMonochromeMode(boolean val) { - tileRenderer.setMonoChrome(val); - renderControl(); - } - - public void setTileGridVisible(boolean val) { - tileRenderer.setTileGridVisible(val); - renderControl(); - } - - public void setCursorLocationVisible(boolean val) { - this.cursorLocationVisible = val; - } - - @Override - public TileSource getTileSource() { - return tilesProvider.getTileSource(); - } - - @Override - public Group getTilesGroup() { - return tilesGroup; - } - - @Override - public Point getCenter() { - return center; - } - - @Override - public boolean isMapMoveable() { - Dimension dim = new Dimension(getMapWidth(), getMapHeight()); - return !mapEdgeChecker.isAllVisible(dim); - } - - private int getMinZoom() { - return minZoomProperty().get(); - } - - public SimpleIntegerProperty minZoomProperty() { - return minZoom; - } - - private int getMaxZoom() { - return maxZoomProperty().get(); - } - - public SimpleIntegerProperty maxZoomProperty() { - return maxZoom; - } - - public void setIgnoreRepaint(boolean ignoreRepaint) { - this.ignoreRepaint = ignoreRepaint; - } - - private void setZoomBounds(TileSource tileSource){ - minZoom.set(getTileSource().getMinZoom()); - maxZoom.set(getTileSource().getMaxZoom()); - } - - private class RenderChangeListener implements - ListChangeListener, ChangeListener { - - @Override - public void onChanged(Change change) { - renderControl(); - } - - @Override - public void changed(ObservableValue observable, - Boolean oldVal, Boolean newVal) { - renderControl(); - } - } - - //store the coordinate where the zoom started - private class ZoomCoordinateCache{ - - private Coordinate zoomCoordinate; - - Coordinate getZoomCoordinate(){ - if (zoomCoordinate == null) { - Point p = createMapCenterPoint(); - zoomCoordinate = getCoordinate(p); - } - return zoomCoordinate; - } - - void setZoomCoordinate(Coordinate coordinate){ - this.zoomCoordinate = coordinate; - } - - void clear() { - zoomCoordinate = null; - } - - } - - private class ZoomChangeListener implements ChangeListener{ - - @Override - public void changed(ObservableValue ov, - Number oldVal, Number newVal) { - if(oldVal != null){ - int oldZoomVal = oldVal.intValue(); - Coordinate c = getCoordinate(createMapCenterPoint(), oldZoomVal); - zoomCoordinateCache.setZoomCoordinate(c); - int newZoomVal = newVal.intValue(); - updateZoom(newZoomVal); - } - } - - } + private static final int INITIAL_ZOOM = 9; + private static final int SIZE = 600; + private static final int START = 0; + private static final String STYLE_LOC = "cursorLocation"; + private TileProvideable tilesProvider; + private TileRenderable tileRenderer; + private MapEdgeChecker mapEdgeChecker; + private ObservableList mapLayers = observableArrayList(); + // X&Y position of the center of this map on the world + // in screen pixels for the current zoom level. + private Point center = new Point(); + // Current zoom level + private SimpleIntegerProperty zoom; + private SimpleIntegerProperty minZoom = new SimpleIntegerProperty(ZoomBounds.MIN.getValue()); + private SimpleIntegerProperty maxZoom = new SimpleIntegerProperty(ZoomBounds.MAX.getValue()); + private boolean ignoreRepaint; + private Rectangle clipMask = new Rectangle(); + private Group tilesGroup; + private Text cursorLocationText; + private SimpleIntegerProperty mapWidth = new SimpleIntegerProperty(SIZE); + private SimpleIntegerProperty mapHeight = new SimpleIntegerProperty(SIZE); + private SimpleBooleanProperty mapMarkersVisible = new SimpleBooleanProperty( + true); + private boolean cursorLocationVisible = true; + private SimpleBooleanProperty mapPolygonsVisible = new SimpleBooleanProperty( + true); + private CoordinateStringFormater formater; + /** + * This field is true when tiles when tiles where loaded. + */ + private boolean tilesPrepared; + private ZoomCoordinateCache zoomCoordinateCache = new ZoomCoordinateCache(); + private ZoomChangeListener zoomChangeListener = new ZoomChangeListener(); + + public MapPane(TileSource ts) { + this(ts, SIZE, SIZE, INITIAL_ZOOM); + } + + public MapPane(TileSource tileSource, int width, int height, int zoom) { + this.zoom = new SimpleIntegerProperty(zoom); + formater = new CoordinateStringFormater(); + + tilesGroup = new Group(); + + tilesProvider = new TileRepository(tileSource); + setZoomBounds(); + tileRenderer = new TileRenderer(tilesProvider); + mapEdgeChecker = new MapEdgeChecker(tileRenderer); + + int tileSize = tileSource.getTileSize(); + setMinSize(tileSize, tileSize); + + DropShadow ds = new DropShadow(); + ds.setOffsetY(3.0f); + ds.setColor(Color.BLACK); + cursorLocationText = new Text(""); + cursorLocationText.setId(STYLE_LOC); + cursorLocationText.setEffect(ds); + cursorLocationText.setFontSmoothingType(FontSmoothingType.LCD); + + clipMask.setFill(Color.WHITE); + tilesGroup.setClip(clipMask); + getChildren().add(tilesGroup); + getChildren().add(cursorLocationText); + + addRenderChangeListener(); + addSizeListeners(); + + setPrefSize(width, height); + + centerMap(); + + setTilesMouseHandler(new TilesMouseHandler()); + + clipMask.setWidth(Double.MAX_VALUE); + clipMask.setHeight(Double.MAX_VALUE); + + this.zoom.addListener(zoomChangeListener); + } + + public final void setTilesMouseHandler(TilesMouseHandler handler) { + handler.setEventPublisher(this); + } + + private void addRenderChangeListener() { + RenderChangeListener listener = new RenderChangeListener(); + mapLayers.addListener(listener); + + mapMarkersVisible.addListener(listener); + mapPolygonsVisible.addListener(listener); + } + + private void addSizeListeners() { + widthProperty().addListener(new ChangeListener() { + @Override + public void changed(ObservableValue observable, + Number oldValue, Number newValue) { + setMapWidth(newValue.doubleValue()); + } + }); + heightProperty().addListener(new ChangeListener() { + @Override + public void changed(ObservableValue observable, + Number oldValue, Number newValue) { + setMapHeight(newValue.doubleValue()); + } + }); + + mapWidth.addListener(new ChangeListener() { + @Override + public void changed(ObservableValue observable, + Number oldValue, Number newValue) { + clipMask.setWidth((Integer) newValue); + adjustCursorLocationText(); + renderControl(); + } + }); + + mapHeight.addListener(new ChangeListener() { + @Override + public void changed(ObservableValue observable, + Number oldValue, Number newValue) { + clipMask.setHeight((Integer) newValue); + adjustCursorLocationText(); + renderControl(); + } + }); + } + + @Override + public void setCursorLocationText(double x, double y) { + if (cursorLocationVisible) { + Coordinate coord = getCoordinate(new Point((int) x, (int) y)); + cursorLocationText.setText(formater.format(coord)); + } + } + + @Override + public void adjustCursorLocationText() { + double strwidth = cursorLocationText.getBoundsInParent().getWidth(); + double x = (double) ((getMapWidth() / 2) - (strwidth / 2)); + int y = getMapHeight() - 28; + + cursorLocationText.setLayoutX(x); + cursorLocationText.setLayoutY(y); + } + + public void setDisplayPositionByLatLon(double lat, double lon) { + setDisplayPositionByLatLon(createMapCenterPoint(), lat, lon, zoom.get()); + } + + private Point createMapCenterPoint() { + return new Point((int) (getMapWidth() / 2), (int) (getMapHeight() / 2)); + } + + private void setDisplayPositionByLatLon(Point mapPoint, double lat, + double lon, int zoom) { + int x = Mercator.lonToX(lon, zoom); + int y = Mercator.latToY(lat, zoom); + setDisplayPosition(mapPoint, x, y, zoom); + } + + private void setDisplayPosition(int x, int y, int zoom) { + setDisplayPosition(createMapCenterPoint(), x, y, zoom); + } + + private void setDisplayPosition(Point mapPoint, int x, int y, int zoom) { + if (isValidZoom(zoom)) { + // Get the plain tile number + moveCenter(mapPoint, x, y); + renderControl(); + } + } + + private void moveCenter(Point mapPoint, int x, int y) { + center.x = x - mapPoint.x + (int) (getMapWidth() / 2); + center.y = y - mapPoint.y + (int) (getMapHeight() / 2); + } + + public void setDisplayToFitMapMarkers() { + List markers = getMapMarkers(); + if (!markers.isEmpty()) { + int x_min = Integer.MAX_VALUE; + int y_min = Integer.MAX_VALUE; + int x_max = Integer.MIN_VALUE; + int y_max = Integer.MIN_VALUE; + int mapZoomMax = getTileSource().getMaxZoom(); + + for (MapMarkable marker : markers) { + int x = Mercator.lonToX(marker.getLon(), mapZoomMax); + int y = Mercator.latToY(marker.getLat(), mapZoomMax); + x_max = Math.max(x_max, x); + y_max = Math.max(y_max, y); + x_min = Math.min(x_min, x); + y_min = Math.min(y_min, y); + } + + int height = (int) Math.max(START, getMapHeight()); + int width = (int) Math.max(START, getMapWidth()); + int newZoom = mapZoomMax; + int x = x_max - x_min; + int y = y_max - y_min; + while (x > width || y > height) { + newZoom--; + x >>= 1; + y >>= 1; + } + x = x_min + (x_max - x_min) / 2; + y = y_min + (y_max - y_min) / 2; + int z = 1 << (mapZoomMax - newZoom); + x /= z; + y /= z; + setDisplayPosition(x, y, newZoom); + } + } + + private List getMapMarkers() { + List markers = new ArrayList<>(); + // a bit ugly to filter out by instance of + for (Renderable layer : mapLayers) { + if (layer instanceof MapMarkable) { + markers.add((MapMarkable) layer); + } + } + return markers; + } + + public void setDisplayToFitMapRectangle() { + if (!mapLayers.isEmpty()) { + int x_min = Integer.MAX_VALUE; + int y_min = Integer.MAX_VALUE; + int x_max = Integer.MIN_VALUE; + int y_max = Integer.MIN_VALUE; + int mapZoomMax = getTileSource().getMaxZoom(); + + int height = (int) Math.max(START, getMapHeight()); + int width = (int) Math.max(START, getMapWidth()); + int newZoom = mapZoomMax; + int x = x_max - x_min; + int y = y_max - y_min; + while (x > width || y > height) { + newZoom--; + x >>= 1; + y >>= 1; + } + x = x_min + (x_max - x_min) / 2; + y = y_min + (y_max - y_min) / 2; + int z = 1 << (mapZoomMax - newZoom); + x /= z; + y /= z; + setDisplayPosition(x, y, newZoom); + } + } + + @Override + public void moveMap(int x, int y) { + zoomCoordinateCache.clear(); + + Point previous = new Point(center); + center.x += x; + center.y += y; + + //check if we are not on edge with the new center point + if (prepareTiles() > 0 && !isOnEdge()) { + tilesPrepared = true; + } else { + //we are on the edge of the map, reset the center point to the previous + center = previous; + prepareTiles(); + } + + renderControl(); + } + + /** + * This method checks if the map is close before getting out of the component. + * @return true if the map is on the edge. + */ + private boolean isOnEdge() { + Dimension dim = new Dimension(getMapWidth(), getMapHeight()); + return mapEdgeChecker.isOnEdge(dim); + } + + /** + * Centers the map + */ + @Override + public final void centerMap() { + setDisplayPositionByLatLon(START, START); + zoomCoordinateCache.clear(); + } + + @Override + public SimpleIntegerProperty zoomProperty() { + return zoom; + } + + @Override + public void zoomIn(Point mapPoint) { + updateZoom(zoom.get() + 1, mapPoint); + } + + @Override + public void zoomOut(Point mapPoint) { + updateZoom(zoom.get() - 1, mapPoint); + } + + private void setZoom(int nextZoom) { + zoom.set(nextZoom); + } + + private void updateZoom(int nextZoom) { + Point mapPoint = createMapCenterPoint(); + updateZoom(nextZoom, mapPoint, zoomCoordinateCache.getZoomCoordinate()); + } + + private void updateZoom(int nextZoom, Point mapPoint) { + zoomCoordinateCache.clear(); + Coordinate zoomPos = getCoordinate(mapPoint); + updateZoom(nextZoom, mapPoint, zoomPos); + } + + private void updateZoom(int nextZoom, Point mapPoint, Coordinate zoomPos) { + if (isValidZoom(nextZoom)) { + setDisplayPositionByLatLon(mapPoint, zoomPos.getLatitude(), + zoomPos.getLongitude(), nextZoom); + } + } + + private boolean isValidZoom(int nextZoom) { + return nextZoom <= getMaxZoom() && nextZoom >= getMinZoom(); + } + + private Coordinate getCoordinate(Point p) { + return toCoordinate(p, this); + } + + private Coordinate getCoordinate(Point p, int zoom) { + Dimension dim = new Dimension(getMapWidth(), getMapHeight()); + return toCoordinate(p, center, dim, zoom); + } + + public void setMapMarkerVisible(boolean mapMarkersVisible) { + this.mapMarkersVisible.set(mapMarkersVisible); + } + + public void removeMapLayer(Renderable layer) { + mapLayers.remove(layer); + } + + public void addMapLayer(Renderable layer) { + mapLayers.add(layer); + } + + public void setTileSource(TileSource tileSource) { + int min = tileSource.getMinZoom(); + int max = tileSource.getMaxZoom(); + if (max > ZoomBounds.MAX.getValue()) { + throw new IllegalArgumentException("Maximum zoom level too high"); + } + if (min < ZoomBounds.MIN.getValue()) { + throw new IllegalArgumentException("Minumim zoom level too low"); + } + tilesProvider.setTileSource(tileSource); + setZoomBounds(); + //set zoom according to max or min available zoom + if (zoom.get() > max) { + setZoom(max); + } else if (zoom.get() < min) { + setZoom(min); + } + zoomCoordinateCache.clear(); + + renderControl(); + } + + protected void renderControl() { + + if (!ignoreRepaint) { + boolean changed = renderMap(); + + if (changed) { + renderMapLayers(); + renderAttribution(); + } + } + } + + /** + * This method renders the map. + * @return + */ + protected boolean renderMap() { + + boolean updated = false; + + //tiles where not loaded + if (!tilesPrepared) { + //only call the renderer if some tiles where loaded + if (prepareTiles() > 0) { + tileRenderer.render(tilesGroup); + updated = true; + } + } else { + tileRenderer.render(tilesGroup); + updated = true; + } + + //tiles where loaded + tilesPrepared = false; + + return updated; + } + + /** + * Preload the tiles for the current view. + * @return the number of actual loaded tiles + */ + private int prepareTiles() { + return tileRenderer.prepareTiles(this); + } + + /** + * This method renders all add overlays. + */ + protected void renderMapLayers() { + for (Renderable overlay : mapLayers) { + if (isEnabled(overlay)) { + overlay.render(this); + } + } + } + + protected boolean isEnabled(Renderable renderable) { + boolean enabled = true; + if ((renderable instanceof MapPolygonable && !isMapPolygonsVisible())) { + enabled = false; + } else if (renderable instanceof MapMarkable + || renderable instanceof MapLineable) { + enabled = mapMarkersVisible.get(); + } + return enabled; + } + + protected void renderAttribution() { + + if (getTileSource().isAttributionRequired()) { + Renderable renderer = new LicenseRenderer(); + renderer.render(this); + } + } + + /** + * Reloads the hole map, incded additional layers and attribution. + */ + public void refereshMap() { + tileRenderer.refresh(this); + renderMapLayers(); + renderAttribution(); + } + + public void setMapWidth(double val) { + mapWidth.set((int) val); + } + + @Override + public int getMapWidth() { + return mapWidth.get(); + } + + public void setMapHeight(double val) { + mapHeight.set((int) val); + } + + @Override + public int getMapHeight() { + return mapHeight.get(); + } + + public void setMapPolygonsVisible(boolean val) { + this.mapPolygonsVisible.set(val); + } + + public boolean isMapPolygonsVisible() { + return this.mapPolygonsVisible.get(); + } + + public void setMonochromeMode(boolean val) { + tileRenderer.setMonoChrome(val); + renderControl(); + } + + /** + * Renders a a frame around the tiles which will be display as a grid for all tiles. + * @param val if set to true a grid is added. + */ + public void setTileGridVisible(boolean val) { + tileRenderer.setTileGridVisible(val); + renderControl(); + } + + public void setCursorLocationVisible(boolean val) { + this.cursorLocationVisible = val; + } + + @Override + public TileSource getTileSource() { + return tilesProvider.getTileSource(); + } + + @Override + public Group getTilesGroup() { + return tilesGroup; + } + + @Override + public Point getCenter() { + return center; + } + + @Override + public boolean isMapMoveable() { + Dimension dim = new Dimension(getMapWidth(), getMapHeight()); + return !mapEdgeChecker.isAllVisible(dim); + } + + private int getMinZoom() { + return minZoomProperty().get(); + } + + @Override + public SimpleIntegerProperty minZoomProperty() { + return minZoom; + } + + private int getMaxZoom() { + return maxZoomProperty().get(); + } + + @Override + public SimpleIntegerProperty maxZoomProperty() { + return maxZoom; + } + + /** + * This method can be used to avoid refresh when a bunch of properties is changed. + * @param ignoreRepaint + */ + public void setIgnoreRepaint(boolean ignoreRepaint) { + this.ignoreRepaint = ignoreRepaint; + } + + private void setZoomBounds() { + minZoom.set(getTileSource().getMinZoom()); + maxZoom.set(getTileSource().getMaxZoom()); + } + + private class RenderChangeListener implements + ListChangeListener, ChangeListener { + + @Override + public void onChanged(Change change) { + renderControl(); + } + + @Override + public void changed(ObservableValue observable, + Boolean oldVal, Boolean newVal) { + renderControl(); + } + } + + //store the coordinate where the zoom started + private class ZoomCoordinateCache { + + private Coordinate zoomCoordinate; + + Coordinate getZoomCoordinate() { + if (zoomCoordinate == null) { + Point p = createMapCenterPoint(); + zoomCoordinate = getCoordinate(p); + } + return zoomCoordinate; + } + + void setZoomCoordinate(Coordinate coordinate) { + this.zoomCoordinate = coordinate; + } + + void clear() { + zoomCoordinate = null; + } + } + + private class ZoomChangeListener implements ChangeListener { + + @Override + public void changed(ObservableValue ov, + Number oldVal, Number newVal) { + if (oldVal != null) { + int oldZoomVal = oldVal.intValue(); + Coordinate c = getCoordinate(createMapCenterPoint(), oldZoomVal); + zoomCoordinateCache.setZoomCoordinate(c); + int newZoomVal = newVal.intValue(); + updateZoom(newZoomVal); + } + } + } } \ No newline at end of file diff --git a/src/main/java/jfxtras/labs/map/render/LicenseRenderer.java b/src/main/java/jfxtras/labs/map/render/LicenseRenderer.java index 6dcba5eae..6bfe25212 100644 --- a/src/main/java/jfxtras/labs/map/render/LicenseRenderer.java +++ b/src/main/java/jfxtras/labs/map/render/LicenseRenderer.java @@ -134,7 +134,7 @@ private Text createLicenseText(String attrTxt) { return txt; } - private class MouseClickedAdapter implements EventHandler { + private static class MouseClickedAdapter implements EventHandler { private String url; @@ -153,7 +153,7 @@ public void handle(MouseEvent me) { } } - private class MouseEnteredAdapter implements EventHandler { + private static class MouseEnteredAdapter implements EventHandler { private Text text; diff --git a/src/main/java/jfxtras/labs/map/render/TileRenderer.java b/src/main/java/jfxtras/labs/map/render/TileRenderer.java index af5a04cad..2e897f7ef 100644 --- a/src/main/java/jfxtras/labs/map/render/TileRenderer.java +++ b/src/main/java/jfxtras/labs/map/render/TileRenderer.java @@ -167,10 +167,12 @@ protected Path createBorder(int posx, int posy, int tilesize) { return path; } + @Override public void setMonoChrome(boolean monoChrome) { this.monoChrome = monoChrome; } + @Override public void setTileGridVisible(boolean tileGridVisible) { this.tileGridVisible = tileGridVisible; } diff --git a/src/main/java/jfxtras/labs/map/tile/AbstractTileLoadStrategy.java b/src/main/java/jfxtras/labs/map/tile/AbstractTileLoadStrategy.java index c01e5e9a7..84f167bab 100644 --- a/src/main/java/jfxtras/labs/map/tile/AbstractTileLoadStrategy.java +++ b/src/main/java/jfxtras/labs/map/tile/AbstractTileLoadStrategy.java @@ -1,24 +1,22 @@ /** * AbstractTileLoadStrategy.java * - * Copyright (c) 2011-2013, JFXtras - * All rights reserved. - * + * Copyright (c) 2011-2013, JFXtras All rights reserved. + * * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * modification, are permitted provided that the following conditions are met: * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. * Redistributions in binary + * form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided + * with the distribution. * Neither the name of the nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND @@ -26,7 +24,6 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package jfxtras.labs.map.tile; import java.util.Objects; @@ -37,49 +34,51 @@ /** * Abstract parent class for tile load commands. + * * @author Mario Schroeder * */ -public abstract class AbstractTileLoadStrategy implements TileLoadStrategy{ - protected TileInfoCache cache; - - public void setCache(TileInfoCache cache){ - this.cache = cache; - } - - Tile createTile(String location) { - Tile tile = new Tile(location); - loadImage(tile); - return tile; - } - - private void loadImage(Tile tile) { - ChangeListener listener = new ImageLoadedListener(tile); - tile.imageLoadedProperty().addListener(listener); - tile.loadImage(); - } - - @Override - public String toString() { - return getClass().getSimpleName(); - } - - @Override - public boolean equals(Object obj) { - boolean equal = false; - if(obj != null && getClass() == obj.getClass()){ - equal = Objects.equals(this.toString(), obj.toString()); - } - return equal; - } - - @Override - public int hashCode() { - return toString().hashCode(); - } - - private class ImageLoadedListener implements ChangeListener { - +public abstract class AbstractTileLoadStrategy implements TileLoadStrategy { + + protected TileInfoCache cache; + + public void setCache(TileInfoCache cache) { + this.cache = cache; + } + + Tile createTile(String location) { + Tile tile = new Tile(location); + loadImage(tile); + return tile; + } + + private void loadImage(Tile tile) { + ChangeListener listener = new ImageLoadedListener(tile); + tile.imageLoadedProperty().addListener(listener); + tile.loadImage(); + } + + @Override + public String toString() { + return getClass().getSimpleName(); + } + + @Override + public boolean equals(Object obj) { + boolean equal = false; + if (obj != null && getClass() == obj.getClass()) { + equal = Objects.equals(this.toString(), obj.toString()); + } + return equal; + } + + @Override + public int hashCode() { + return toString().hashCode(); + } + + private class ImageLoadedListener implements ChangeListener { + private Tile tile; public ImageLoadedListener(Tile tile) { @@ -88,7 +87,7 @@ public ImageLoadedListener(Tile tile) { @Override public void changed( - ObservableValue ov, Boolean oldVal, Boolean newVal) { + ObservableValue ov, Boolean oldVal, Boolean newVal) { if (newVal.booleanValue()) { addImage(tile.getLocation(), tile.getImageView().getImage()); } diff --git a/src/main/java/jfxtras/labs/map/tile/CacheLoadStrategy.java b/src/main/java/jfxtras/labs/map/tile/CacheLoadStrategy.java index 06728e560..d028560c0 100644 --- a/src/main/java/jfxtras/labs/map/tile/CacheLoadStrategy.java +++ b/src/main/java/jfxtras/labs/map/tile/CacheLoadStrategy.java @@ -1,24 +1,22 @@ /** * CacheLoadStrategy.java * - * Copyright (c) 2011-2013, JFXtras - * All rights reserved. - * + * Copyright (c) 2011-2013, JFXtras All rights reserved. + * * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * modification, are permitted provided that the following conditions are met: * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. * Redistributions in binary + * form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided + * with the distribution. * Neither the name of the nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND @@ -26,22 +24,21 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package jfxtras.labs.map.tile; /** - * This class checks the {@link TileInfoCache} first if the - * {@link Tile} exists and loads it from there. - * + * This class checks the {@link TileInfoCache} first if the {@link Tile} exists + * and loads it from there. + * * @author Mario Schroeder * */ public class CacheLoadStrategy extends AbstractTileLoadStrategy { - @Override - public Tile execute(String location) { - Tile tile; - TileInfo info = cache.get(location); + @Override + public Tile execute(String location) { + Tile tile; + TileInfo info = cache.get(location); if (info != null) { tile = new Tile(location, info.getImage()); @@ -49,6 +46,5 @@ public Tile execute(String location) { tile = createTile(location); } return tile; - } - + } } diff --git a/src/main/java/jfxtras/labs/map/tile/RefreshLoadStrategy.java b/src/main/java/jfxtras/labs/map/tile/RefreshLoadStrategy.java index 429123aa6..4106abd02 100644 --- a/src/main/java/jfxtras/labs/map/tile/RefreshLoadStrategy.java +++ b/src/main/java/jfxtras/labs/map/tile/RefreshLoadStrategy.java @@ -1,24 +1,22 @@ /** * RefreshLoadStrategy.java * - * Copyright (c) 2011-2013, JFXtras - * All rights reserved. - * + * Copyright (c) 2011-2013, JFXtras All rights reserved. + * * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + * modification, are permitted provided that the following conditions are met: * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. * Redistributions in binary + * form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided + * with the distribution. * Neither the name of the nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND @@ -26,26 +24,24 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package jfxtras.labs.map.tile; /** * This class reloads the {@link Tile} in the {@link TileInfoCache}. - * + * * @author Mario Schroeder * */ public class RefreshLoadStrategy extends AbstractTileLoadStrategy { - @Override - public Tile execute(String location) { - TileInfo info = cache.get(location); + @Override + public Tile execute(String location) { + TileInfo info = cache.get(location); if (info != null) { - cache.remove(location); - } - - return createTile(location); - } + cache.remove(location); + } + return createTile(location); + } } diff --git a/src/main/java/jfxtras/labs/map/tile/Tile.java b/src/main/java/jfxtras/labs/map/tile/Tile.java index ffeac865e..5470b9c46 100644 --- a/src/main/java/jfxtras/labs/map/tile/Tile.java +++ b/src/main/java/jfxtras/labs/map/tile/Tile.java @@ -49,8 +49,6 @@ public class Tile { private static volatile Image delayImage; - private static volatile Image errorImage; - private static final String HTTP = "http:"; private static final double COMPLETE = 1.0; diff --git a/src/main/java/jfxtras/labs/map/tile/bing/BingTileSource.java b/src/main/java/jfxtras/labs/map/tile/bing/BingTileSource.java index a59b754c1..f91260d68 100644 --- a/src/main/java/jfxtras/labs/map/tile/bing/BingTileSource.java +++ b/src/main/java/jfxtras/labs/map/tile/bing/BingTileSource.java @@ -29,6 +29,7 @@ package jfxtras.labs.map.tile.bing; +import java.util.ArrayList; import jfxtras.labs.map.tile.Attribution; import jfxtras.labs.map.tile.AttributtionStringBuilder; import jfxtras.labs.map.tile.DefaultTileSource; @@ -44,7 +45,7 @@ */ public class BingTileSource extends DefaultTileSource { - private List attributions; + private List attributions = new ArrayList<>(); public BingTileSource(String name, String base_url) { super(name, base_url); From 8a7f57d2da45ea521ad3bc86e824c3cb31cee7e8 Mon Sep 17 00:00:00 2001 From: Mario-S Date: Thu, 2 Jan 2014 22:07:06 +0100 Subject: [PATCH 2/3] cleanup & TODO fixed --- .../jfxtras/labs/map/render/TileRenderer.java | 13 +++++---- .../labs/map/tile/local/LocalTileSource.java | 29 ++++++++++++------- .../labs/map/tile/TileRepositoryTest.java | 9 ++++-- 3 files changed, 32 insertions(+), 19 deletions(-) diff --git a/src/main/java/jfxtras/labs/map/render/TileRenderer.java b/src/main/java/jfxtras/labs/map/render/TileRenderer.java index 2e897f7ef..36ef6a2e4 100644 --- a/src/main/java/jfxtras/labs/map/render/TileRenderer.java +++ b/src/main/java/jfxtras/labs/map/render/TileRenderer.java @@ -83,17 +83,20 @@ public TileRenderer(TileProvideable provider) { @Override public int prepareTiles(Moveable mapController) { provider.setStrategy(new CacheLoadStrategy()); - TilesLoadable tileLoader = new TilesLoader(provider); - tileImages = tileLoader.loadTiles(mapController); + loadTiles(mapController); return tileImages.size(); } @Override public void refresh(Moveable mapController) { provider.setStrategy(new RefreshLoadStrategy()); + loadTiles(mapController); + render(mapController.getTilesGroup()); + } + + private void loadTiles(Moveable mapController) { TilesLoadable tileLoader = new TilesLoader(provider); tileImages = tileLoader.loadTiles(mapController); - render(mapController.getTilesGroup()); } @Override @@ -167,12 +170,12 @@ protected Path createBorder(int posx, int posy, int tilesize) { return path; } - @Override + @Override public void setMonoChrome(boolean monoChrome) { this.monoChrome = monoChrome; } - @Override + @Override public void setTileGridVisible(boolean tileGridVisible) { this.tileGridVisible = tileGridVisible; } diff --git a/src/main/java/jfxtras/labs/map/tile/local/LocalTileSource.java b/src/main/java/jfxtras/labs/map/tile/local/LocalTileSource.java index ae7d6a7fc..73f942858 100644 --- a/src/main/java/jfxtras/labs/map/tile/local/LocalTileSource.java +++ b/src/main/java/jfxtras/labs/map/tile/local/LocalTileSource.java @@ -50,7 +50,8 @@ */ public class LocalTileSource extends DefaultTileSource { - private String tilesRootDir; + private static final String DIGIT = "\\d+"; + private String tilesRootDir; public LocalTileSource(String name, String base_url) { super(name, base_url); @@ -77,7 +78,7 @@ public int getMinZoom() { @Override public int getMaxZoom() { - int zoom = super.getMaxZoom(); + int zoom = super.getMinZoom(); LinkedList dirs = listZoomDirs(); if(!dirs.isEmpty()){ zoom = Integer.parseInt(dirs.getLast()); @@ -87,15 +88,21 @@ public int getMaxZoom() { private LinkedList listZoomDirs(){ LinkedList dirs = new LinkedList<>(); - Path root = Paths.get(tilesRootDir); - try (DirectoryStream directoryStream = Files.newDirectoryStream(root)) { - for (Path path : directoryStream) { - //TODO check if the name is a number - dirs.add(path.getFileName().toString()); - } - } catch (IOException ex) { - Logger.getLogger(getClass().getName()).log(Level.WARNING, ex.getMessage(), ex); - } + + if(tilesRootDir != null){ + Path root = Paths.get(tilesRootDir); + try (DirectoryStream directoryStream = Files.newDirectoryStream(root)) { + for (Path path : directoryStream) { + String name = path.getFileName().toString(); + if(name.matches(DIGIT)){ + dirs.add(name); + } + } + } catch (IOException ex) { + Logger.getLogger(getClass().getName()).log(Level.WARNING, ex.getMessage(), ex); + } + } + return dirs; } } diff --git a/src/test/java/jfxtras/labs/map/tile/TileRepositoryTest.java b/src/test/java/jfxtras/labs/map/tile/TileRepositoryTest.java index 1b5c70db7..16efe61fd 100644 --- a/src/test/java/jfxtras/labs/map/tile/TileRepositoryTest.java +++ b/src/test/java/jfxtras/labs/map/tile/TileRepositoryTest.java @@ -79,16 +79,19 @@ public void testBingSource() { public void testLocalSource() { TileSourceFactory factory = new LocalTileSourceFactory(); - TileRepository classUnderTest = new TileRepository(factory.create(null)); + TileSource tileSource = factory.create(null); + TileRepository classUnderTest = new TileRepository(tileSource); Tile tile = classUnderTest.getTile(1, 1, 1); assertNotNull(tile); assertNull(tile.getImageView().getImage()); + assertEquals(1, tileSource.getMinZoom()); + assertEquals(1, tileSource.getMaxZoom()); String path = TilePathLookup.getPath(); - TileSource tileSource = factory.create(path); + tileSource = factory.create(path); classUnderTest = new TileRepository(tileSource); assumeNotNull(classUnderTest.getTile(65, 40, 7)); - assumeTrue(tileSource.getMinZoom() == 7); + assertEquals(7, tileSource.getMinZoom()); assertEquals(8, tileSource.getMaxZoom()); } From a6b2eb773aedbdcfa19f1d1ddeb617764cee7156 Mon Sep 17 00:00:00 2001 From: Mario-S Date: Thu, 2 Jan 2014 22:09:06 +0100 Subject: [PATCH 3/3] added readme for test folder --- src/test/resources/jfxtras/labs/map/tile/tiles/illegal/readme | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 src/test/resources/jfxtras/labs/map/tile/tiles/illegal/readme diff --git a/src/test/resources/jfxtras/labs/map/tile/tiles/illegal/readme b/src/test/resources/jfxtras/labs/map/tile/tiles/illegal/readme new file mode 100644 index 000000000..ec317ae54 --- /dev/null +++ b/src/test/resources/jfxtras/labs/map/tile/tiles/illegal/readme @@ -0,0 +1,2 @@ +This folder is only for test purposes: +to verify if it will be ignored as a valid tile source directory \ No newline at end of file