// License: GPL. For details, see LICENSE file. package org.openstreetmap.josm.plugins.elevation.grid; import static org.openstreetmap.josm.tools.I18n.tr; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import javax.swing.Action; import javax.swing.Icon; import org.openstreetmap.gui.jmapviewer.MemoryTileCache; import org.openstreetmap.gui.jmapviewer.Tile; import org.openstreetmap.gui.jmapviewer.TileController; import org.openstreetmap.gui.jmapviewer.TileXY; import org.openstreetmap.gui.jmapviewer.interfaces.TileLoaderListener; import org.openstreetmap.gui.jmapviewer.interfaces.TileSource; import org.openstreetmap.josm.Main; import org.openstreetmap.josm.data.Bounds; import org.openstreetmap.josm.data.coor.LatLon; import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor; import org.openstreetmap.josm.gui.MapView; import org.openstreetmap.josm.gui.layer.Layer; import org.openstreetmap.josm.plugins.elevation.IVertexRenderer; import org.openstreetmap.josm.tools.ImageProvider; /** * @author Oliver Wieland <oliver.wieland@online.de> * */ public class ElevationGridLayer extends Layer implements TileLoaderListener { private static final int ELE_ZOOM_LEVEL = 13; private final IVertexRenderer vertexRenderer; private final MemoryTileCache tileCache; protected TileSource tileSource; protected ElevationGridTileLoader tileLoader; protected TileController tileController; private Bounds lastBounds; private TileSet tileSet; public ElevationGridLayer(String name) { super(name); setOpacity(0.8); setBackgroundLayer(true); vertexRenderer = new SimpleVertexRenderer(); tileCache = new MemoryTileCache(); tileCache.setCacheSize(500); tileSource = new ElevationGridTileSource(name); tileLoader = new ElevationGridTileLoader(this); tileController = new ElevationGridTileController(tileSource, tileCache, this, tileLoader); } @Override public void paint(Graphics2D g, MapView mv, Bounds box) { boolean needsNewTileSet = tileSet == null || (lastBounds == null || !lastBounds.equals(box)); if (needsNewTileSet) { tileSet = new TileSet(box.getMin(), box.getMax(), ELE_ZOOM_LEVEL); // we use a vector format with constant zoom level lastBounds = box; System.out.println("paint " + tileSet); } if (tileSet.insane()) { myDrawString(g, tr("zoom in to load any tiles"), 120, 120); return; } else if (tileSet.tooLarge()) { myDrawString(g, tr("zoom in to load more tiles"), 120, 120); return; } else if (tileSet.tooSmall()) { myDrawString(g, tr("increase zoom level to see more detail"), 120, 120); return; } for (int x = tileSet.x0; x <= tileSet.x1; x++) { for (int y = tileSet.y0; y <= tileSet.y1; y++) { Tile t = tileController.getTile(x, y, ELE_ZOOM_LEVEL); if (t != null && t.isLoaded() && t instanceof ElevationGridTile) { ((ElevationGridTile) t).paintTile(g, mv, vertexRenderer); } else { // give some consolation... Point topLeft = mv.getPoint(new LatLon(tileSource.tileXYToLatLon(x, y, ELE_ZOOM_LEVEL))); t.paint(g, topLeft.x, topLeft.y); } } } } @Override public String getToolTipText() { // TODO Auto-generated method stub return null; } @Override public void visitBoundingBox(BoundingXYVisitor v) { // TODO Auto-generated method stub } @Override public Action[] getMenuEntries() { // TODO Auto-generated method stub return null; } @Override public void tileLoadingFinished(Tile tile, boolean success) { try { if (Main.map != null) { Main.map.repaint(100); } } catch (Exception ex) { System.err.println(ex); ex.printStackTrace(System.err); } } @Override public Icon getIcon() { return ImageProvider.get("layer", "elevation"); } @Override public void mergeFrom(Layer from) { // TODO Auto-generated method stub } @Override public boolean isMergable(Layer other) { // TODO Auto-generated method stub return false; } @Override public Object getInfoComponent() { // TODO Auto-generated method stub return null; } // Stolen from TMSLayer... void myDrawString(Graphics g, String text, int x, int y) { Color oldColor = g.getColor(); g.setColor(Color.black); g.drawString(text, x+1, y+1); g.setColor(oldColor); g.drawString(text, x, y); } private class TileSet { int x0, x1, y0, y1; int tileMax = -1; /** * Create a TileSet by known LatLon bbox without layer shift correction */ TileSet(LatLon topLeft, LatLon botRight, int zoom) { if (zoom == 0) return; TileXY p0 = tileSource.latLonToTileXY(topLeft.lat(), topLeft.lon(), zoom); TileXY p1 = tileSource.latLonToTileXY(botRight.lat(), botRight.lon(), zoom); x0 = p0.getXIndex(); y0 = p0.getYIndex(); x1 = p1.getXIndex(); y1 = p1.getYIndex(); if (x0 > x1) { int tmp = x0; x0 = x1; x1 = tmp; } if (y0 > y1) { int tmp = y0; y0 = y1; y1 = tmp; } tileMax = (int) Math.pow(2.0, zoom); if (x0 < 0) { x0 = 0; } if (y0 < 0) { y0 = 0; } if (x1 > tileMax) { x1 = tileMax; } if (y1 > tileMax) { y1 = tileMax; } } int size() { int x_span = x1 - x0 + 1; int y_span = y1 - y0 + 1; return x_span * y_span; } @Override public String toString() { return "TileSet [x0=" + x0 + ", x1=" + x1 + ", y0=" + y0 + ", y1=" + y1 + ", size()=" + size() + ", tilesSpanned()=" + tilesSpanned() + "]"; } double tilesSpanned() { return Math.sqrt(1.0 * this.size()); } boolean tooSmall() { return this.tilesSpanned() < 1; } boolean tooLarge() { return this.tilesSpanned() > 50; } boolean insane() { return this.tilesSpanned() > 200; } } }