Changeset 11783 in osm for applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/JMapViewer.java
- Timestamp:
- 2008-11-07T15:23:05+01:00 (16 years ago)
- Location:
- applications/viewer/jmapviewer
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
applications/viewer/jmapviewer
- Property svn:ignore
-
old new 1 tiles 1 2 JMapViewer_Demo.jar 2 3 JMapViewer_src.jar
-
- Property svn:ignore
-
applications/viewer/jmapviewer/src/org/openstreetmap/gui/jmapviewer/JMapViewer.java
r11104 r11783 11 11 import java.awt.event.ActionListener; 12 12 import java.awt.geom.Point2D; 13 import java.awt.image.BufferedImage;14 13 import java.util.LinkedList; 15 14 import java.util.List; 16 15 17 import javax.imageio.ImageIO;18 16 import javax.swing.ImageIcon; 19 17 import javax.swing.JButton; … … 40 38 public class JMapViewer extends JPanel implements TileLoaderListener { 41 39 42 private static final long serialVersionUID = 1L; 43 44 /** 45 * Vectors for clock-wise tile painting 46 */ 47 protected static final Point[] move = { new Point(1, 0), new Point(0, 1), 48 new Point(-1, 0), new Point(0, -1) }; 49 50 public static final int MAX_ZOOM = 22; 51 public static final int MIN_ZOOM = 0; 52 53 protected TileLoader tileLoader; 54 protected TileCache tileCache; 55 protected TileSource tileSource; 56 57 protected List<MapMarker> mapMarkerList; 58 protected boolean mapMarkersVisible; 59 protected boolean tileGridVisible; 60 61 /** 62 * x- and y-position of the center of this map-panel on the world map 63 * denoted in screen pixel regarding the current zoom level. 64 */ 65 protected Point center; 66 67 /** 68 * Current zoom level 69 */ 70 protected int zoom; 71 72 protected JSlider zoomSlider; 73 protected JButton zoomInButton; 74 protected JButton zoomOutButton; 75 76 /** 77 * Hourglass image that is displayed until a map tile has been loaded 78 */ 79 protected BufferedImage loadingImage; 80 81 JobDispatcher jobDispatcher; 82 83 /** 84 * Creates a standard {@link JMapViewer} instance that can be controlled via 85 * mouse: hold right mouse button for moving, double click left mouse button 86 * or use mouse wheel for zooming. Loaded tiles are stored the 87 * {@link MemoryTileCache} and the tile loader uses 4 parallel threads for 88 * retrieving the tiles. 89 */ 90 public JMapViewer() { 91 this(new MemoryTileCache(), 4); 92 new DefaultMapController(this); 93 } 94 95 public JMapViewer(TileCache tileCache, int downloadThreadCount) { 96 super(); 97 tileSource = new OsmTileSource.Mapnik(); 98 tileLoader = new OsmTileLoader(this); 99 this.tileCache = tileCache; 100 jobDispatcher = JobDispatcher.getInstance(); 101 mapMarkerList = new LinkedList<MapMarker>(); 102 mapMarkersVisible = true; 103 tileGridVisible = false; 104 setLayout(null); 105 initializeZoomSlider(); 106 setMinimumSize(new Dimension(Tile.SIZE, Tile.SIZE)); 107 setPreferredSize(new Dimension(400, 400)); 108 try { 109 loadingImage = ImageIO.read(JMapViewer.class 110 .getResourceAsStream("images/hourglass.png")); 111 } catch (Exception e1) { 112 loadingImage = null; 113 } 114 setDisplayPositionByLatLon(50, 9, 3); 115 } 116 117 protected void initializeZoomSlider() { 118 zoomSlider = new JSlider(MIN_ZOOM, tileSource.getMaxZoom()); 119 zoomSlider.setOrientation(JSlider.VERTICAL); 120 zoomSlider.setBounds(10, 10, 30, 150); 121 zoomSlider.setOpaque(false); 122 zoomSlider.addChangeListener(new ChangeListener() { 123 public void stateChanged(ChangeEvent e) { 124 setZoom(zoomSlider.getValue()); 125 } 126 }); 127 add(zoomSlider); 128 int size = 18; 129 try { 130 ImageIcon icon = new ImageIcon(getClass().getResource( 131 "images/plus.png")); 132 zoomInButton = new JButton(icon); 133 } catch (Exception e) { 134 zoomInButton = new JButton("+"); 135 zoomInButton.setFont(new Font("sansserif", Font.BOLD, 9)); 136 zoomInButton.setMargin(new Insets(0, 0, 0, 0)); 137 } 138 zoomInButton.setBounds(4, 155, size, size); 139 zoomInButton.addActionListener(new ActionListener() { 140 141 public void actionPerformed(ActionEvent e) { 142 zoomIn(); 143 } 144 }); 145 add(zoomInButton); 146 try { 147 ImageIcon icon = new ImageIcon(getClass().getResource( 148 "images/minus.png")); 149 zoomOutButton = new JButton(icon); 150 } catch (Exception e) { 151 zoomOutButton = new JButton("-"); 152 zoomOutButton.setFont(new Font("sansserif", Font.BOLD, 9)); 153 zoomOutButton.setMargin(new Insets(0, 0, 0, 0)); 154 } 155 zoomOutButton.setBounds(8 + size, 155, size, size); 156 zoomOutButton.addActionListener(new ActionListener() { 157 158 public void actionPerformed(ActionEvent e) { 159 zoomOut(); 160 } 161 }); 162 add(zoomOutButton); 163 } 164 165 /** 166 * Changes the map pane so that it is centered on the specified coordinate 167 * at the given zoom level. 168 * 169 * @param lat 170 * latitude of the specified coordinate 171 * @param lon 172 * longitude of the specified coordinate 173 * @param zoom 174 * {@link #MIN_ZOOM} <= zoom level <= {@link #MAX_ZOOM} 175 */ 176 public void setDisplayPositionByLatLon(double lat, double lon, int zoom) { 177 setDisplayPositionByLatLon(new Point(getWidth() / 2, getHeight() / 2), 178 lat, lon, zoom); 179 } 180 181 /** 182 * Changes the map pane so that the specified coordinate at the given zoom 183 * level is displayed on the map at the screen coordinate 184 * <code>mapPoint</code>. 185 * 186 * @param mapPoint 187 * point on the map denoted in pixels where the coordinate should 188 * be set 189 * @param lat 190 * latitude of the specified coordinate 191 * @param lon 192 * longitude of the specified coordinate 193 * @param zoom 194 * {@link #MIN_ZOOM} <= zoom level <= 195 * {@link TileSource#getMaxZoom()} 196 */ 197 public void setDisplayPositionByLatLon(Point mapPoint, double lat, 198 double lon, int zoom) { 199 int x = OsmMercator.LonToX(lon, zoom); 200 int y = OsmMercator.LatToY(lat, zoom); 201 setDisplayPosition(mapPoint, x, y, zoom); 202 } 203 204 public void setDisplayPosition(int x, int y, int zoom) { 205 setDisplayPosition(new Point(getWidth() / 2, getHeight() / 2), x, y, 206 zoom); 207 } 208 209 public void setDisplayPosition(Point mapPoint, int x, int y, int zoom) { 210 if (zoom > tileSource.getMaxZoom() || zoom < MIN_ZOOM) 211 return; 212 213 // Get the plain tile number 214 Point p = new Point(); 215 p.x = x - mapPoint.x + getWidth() / 2; 216 p.y = y - mapPoint.y + getHeight() / 2; 217 center = p; 218 setIgnoreRepaint(true); 219 try { 220 int oldZoom = this.zoom; 221 this.zoom = zoom; 222 if (oldZoom != zoom) 223 zoomChanged(oldZoom); 224 if (zoomSlider.getValue() != zoom) 225 zoomSlider.setValue(zoom); 226 } finally { 227 setIgnoreRepaint(false); 228 repaint(); 229 } 230 } 231 232 /** 233 * Sets the displayed map pane and zoom level so that all map markers are 234 * visible. 235 */ 236 public void setDisplayToFitMapMarkers() { 237 if (mapMarkerList == null || mapMarkerList.size() == 0) 238 return; 239 int x_min = Integer.MAX_VALUE; 240 int y_min = Integer.MAX_VALUE; 241 int x_max = Integer.MIN_VALUE; 242 int y_max = Integer.MIN_VALUE; 243 int mapZoomMax = tileSource.getMaxZoom(); 244 for (MapMarker marker : mapMarkerList) { 245 int x = OsmMercator.LonToX(marker.getLon(), mapZoomMax); 246 int y = OsmMercator.LatToY(marker.getLat(), mapZoomMax); 247 x_max = Math.max(x_max, x); 248 y_max = Math.max(y_max, y); 249 x_min = Math.min(x_min, x); 250 y_min = Math.min(y_min, y); 251 } 252 int height = Math.max(0, getHeight()); 253 int width = Math.max(0, getWidth()); 254 // System.out.println(x_min + " < x < " + x_max); 255 // System.out.println(y_min + " < y < " + y_max); 256 // System.out.println("tiles: " + width + " " + height); 257 int newZoom = mapZoomMax; 258 int x = x_max - x_min; 259 int y = y_max - y_min; 260 while (x > width || y > height) { 261 // System.out.println("zoom: " + zoom + " -> " + x + " " + y); 262 newZoom--; 263 x >>= 1; 264 y >>= 1; 265 } 266 x = x_min + (x_max - x_min) / 2; 267 y = y_min + (y_max - y_min) / 2; 268 int z = 1 << (mapZoomMax - newZoom); 269 x /= z; 270 y /= z; 271 setDisplayPosition(x, y, newZoom); 272 } 273 274 public Point2D.Double getPosition() { 275 double lon = OsmMercator.XToLon(center.x, zoom); 276 double lat = OsmMercator.YToLat(center.y, zoom); 277 return new Point2D.Double(lat, lon); 278 } 279 280 public Point2D.Double getPosition(Point mapPoint) { 281 int x = center.x + mapPoint.x - getWidth() / 2; 282 int y = center.y + mapPoint.y - getHeight() / 2; 283 double lon = OsmMercator.XToLon(x, zoom); 284 double lat = OsmMercator.YToLat(y, zoom); 285 return new Point2D.Double(lat, lon); 286 } 287 288 /** 289 * Calculates the position on the map of a given coordinate 290 * 291 * @param lat 292 * @param lon 293 * @return point on the map or <code>null</code> if the point is not visible 294 */ 295 public Point getMapPosition(double lat, double lon) { 296 int x = OsmMercator.LonToX(lon, zoom); 297 int y = OsmMercator.LatToY(lat, zoom); 298 x -= center.x - getWidth() / 2; 299 y -= center.y - getHeight() / 2; 300 if (x < 0 || y < 0 || x > getWidth() || y > getHeight()) 301 return null; 302 return new Point(x, y); 303 } 304 305 @Override 306 protected void paintComponent(Graphics g) { 307 super.paintComponent(g); 308 309 int iMove = 0; 310 311 int tilex = center.x / Tile.SIZE; 312 int tiley = center.y / Tile.SIZE; 313 int off_x = (center.x % Tile.SIZE); 314 int off_y = (center.y % Tile.SIZE); 315 316 int w2 = getWidth() / 2; 317 int h2 = getHeight() / 2; 318 int posx = w2 - off_x; 319 int posy = h2 - off_y; 320 321 int diff_left = off_x; 322 int diff_right = Tile.SIZE - off_x; 323 int diff_top = off_y; 324 int diff_bottom = Tile.SIZE - off_y; 325 326 boolean start_left = diff_left < diff_right; 327 boolean start_top = diff_top < diff_bottom; 328 329 if (start_top) { 330 if (start_left) 331 iMove = 2; 332 else 333 iMove = 3; 334 } else { 335 if (start_left) 336 iMove = 1; 337 else 338 iMove = 0; 339 } // calculate the visibility borders 340 int x_min = -Tile.SIZE; 341 int y_min = -Tile.SIZE; 342 int x_max = getWidth(); 343 int y_max = getHeight(); 344 345 // paint the tiles in a spiral, starting from center of the map 346 boolean painted = true; 347 int x = 0; 348 while (painted) { 349 painted = false; 350 for (int i = 0; i < 4; i++) { 351 if (i % 2 == 0) 352 x++; 353 for (int j = 0; j < x; j++) { 354 if (x_min <= posx && posx <= x_max && y_min <= posy 355 && posy <= y_max) { 356 // tile is visible 357 Tile tile = getTile(tilex, tiley, zoom); 358 if (tile != null) { 359 painted = true; 360 tile.paint(g, posx, posy); 361 if (tileGridVisible) 362 g.drawRect(posx, posy, Tile.SIZE, Tile.SIZE); 363 } 364 } 365 Point p = move[iMove]; 366 posx += p.x * Tile.SIZE; 367 posy += p.y * Tile.SIZE; 368 tilex += p.x; 369 tiley += p.y; 370 } 371 iMove = (iMove + 1) % move.length; 372 } 373 } 374 // outer border of the map 375 int mapSize = Tile.SIZE << zoom; 376 g.drawRect(w2 - center.x, h2 - center.y, mapSize, mapSize); 377 378 // g.drawString("Tiles in cache: " + tileCache.getTileCount(), 50, 20); 379 if (!mapMarkersVisible || mapMarkerList == null) 380 return; 381 for (MapMarker marker : mapMarkerList) { 382 Point p = getMapPosition(marker.getLat(), marker.getLon()); 383 // System.out.println(marker + " -> " + p); 384 if (p != null) 385 marker.paint(g, p); 386 } 387 } 388 389 /** 390 * Moves the visible map pane. 391 * 392 * @param x 393 * horizontal movement in pixel. 394 * @param y 395 * vertical movement in pixel 396 */ 397 public void moveMap(int x, int y) { 398 center.x += x; 399 center.y += y; 400 repaint(); 401 } 402 403 /** 404 * @return the current zoom level 405 */ 406 public int getZoom() { 407 return zoom; 408 } 409 410 /** 411 * Increases the current zoom level by one 412 */ 413 public void zoomIn() { 414 setZoom(zoom + 1); 415 } 416 417 /** 418 * Increases the current zoom level by one 419 */ 420 public void zoomIn(Point mapPoint) { 421 setZoom(zoom + 1, mapPoint); 422 } 423 424 /** 425 * Decreases the current zoom level by one 426 */ 427 public void zoomOut() { 428 setZoom(zoom - 1); 429 } 430 431 /** 432 * Decreases the current zoom level by one 433 */ 434 public void zoomOut(Point mapPoint) { 435 setZoom(zoom - 1, mapPoint); 436 } 437 438 public void setZoom(int zoom, Point mapPoint) { 439 if (zoom > tileSource.getMaxZoom() || zoom == this.zoom) 440 return; 441 Point2D.Double zoomPos = getPosition(mapPoint); 442 jobDispatcher.cancelOutstandingJobs(); // Clearing outstanding load 443 // requests 444 setDisplayPositionByLatLon(mapPoint, zoomPos.x, zoomPos.y, zoom); 445 } 446 447 public void setZoom(int zoom) { 448 setZoom(zoom, new Point(getWidth() / 2, getHeight() / 2)); 449 } 450 451 /** 452 * retrieves a tile from the cache. If the tile is not present in the cache 453 * a load job is added to the working queue of {@link JobThread}. 454 * 455 * @param tilex 456 * @param tiley 457 * @param zoom 458 * @return specified tile from the cache or <code>null</code> if the tile 459 * was not found in the cache. 460 */ 461 protected Tile getTile(int tilex, int tiley, int zoom) { 462 int max = (1 << zoom); 463 if (tilex < 0 || tilex >= max || tiley < 0 || tiley >= max) 464 return null; 465 Tile tile = tileCache.getTile(tileSource, tilex, tiley, zoom); 466 if (tile == null) { 467 tile = new Tile(tileSource, tilex, tiley, zoom, loadingImage); 468 tileCache.addTile(tile); 469 tile.loadPlaceholderFromCache(tileCache); 470 } 471 if (!tile.isLoaded()) { 472 jobDispatcher.addJob(tileLoader.createTileLoaderJob(tileSource, 473 tilex, tiley, zoom)); 474 } 475 return tile; 476 } 477 478 /** 479 * Every time the zoom level changes this method is called. Override it in 480 * derived implementations for adapting zoom dependent values. The new zoom 481 * level can be obtained via {@link #getZoom()}. 482 * 483 * @param oldZoom 484 * the previous zoom level 485 */ 486 protected void zoomChanged(int oldZoom) { 487 zoomSlider.setToolTipText("Zoom level " + zoom); 488 zoomInButton.setToolTipText("Zoom to level " + (zoom + 1)); 489 zoomOutButton.setToolTipText("Zoom to level " + (zoom - 1)); 490 zoomOutButton.setEnabled(zoom > 0); 491 zoomInButton.setEnabled(zoom < tileSource.getMaxZoom()); 492 } 493 494 public boolean isTileGridVisible() { 495 return tileGridVisible; 496 } 497 498 public void setTileGridVisible(boolean tileGridVisible) { 499 this.tileGridVisible = tileGridVisible; 500 repaint(); 501 } 502 503 public boolean getMapMarkersVisible() { 504 return mapMarkersVisible; 505 } 506 507 /** 508 * Enables or disables painting of the {@link MapMarker} 509 * 510 * @param mapMarkersVisible 511 * @see #addMapMarker(MapMarker) 512 * @see #getMapMarkerList() 513 */ 514 public void setMapMarkerVisible(boolean mapMarkersVisible) { 515 this.mapMarkersVisible = mapMarkersVisible; 516 repaint(); 517 } 518 519 public void setMapMarkerList(List<MapMarker> mapMarkerList) { 520 this.mapMarkerList = mapMarkerList; 521 repaint(); 522 } 523 524 public List<MapMarker> getMapMarkerList() { 525 return mapMarkerList; 526 } 527 528 public void addMapMarker(MapMarker marker) { 529 mapMarkerList.add(marker); 530 } 531 532 public void setZoomContolsVisible(boolean visible) { 533 zoomSlider.setVisible(visible); 534 zoomInButton.setVisible(visible); 535 zoomOutButton.setVisible(visible); 536 } 537 538 public boolean getZoomContolsVisible() { 539 return zoomSlider.isVisible(); 540 } 541 542 public TileCache getTileCache() { 543 return tileCache; 544 } 545 546 public TileLoader getTileLoader() { 547 return tileLoader; 548 } 549 550 public void setTileLoader(TileLoader tileLoader) { 551 this.tileLoader = tileLoader; 552 } 553 554 public TileSource getTileLayerSource() { 555 return tileSource; 556 } 557 558 public void setTileSource(TileSource tileSource) { 559 if (tileSource.getMaxZoom() > MAX_ZOOM) 560 throw new RuntimeException("Zoom level too high"); 561 this.tileSource = tileSource; 562 zoomSlider.setMaximum(tileSource.getMaxZoom()); 563 jobDispatcher.cancelOutstandingJobs(); 564 if (zoom > tileSource.getMaxZoom()) 565 setZoom(tileSource.getMaxZoom()); 566 repaint(); 567 } 568 569 public void tileLoadingFinished(Tile tile) { 570 repaint(); 571 } 40 private static final long serialVersionUID = 1L; 41 42 /** 43 * Vectors for clock-wise tile painting 44 */ 45 protected static final Point[] move = { new Point(1, 0), new Point(0, 1), new Point(-1, 0), new Point(0, -1) }; 46 47 public static final int MAX_ZOOM = 22; 48 public static final int MIN_ZOOM = 0; 49 50 protected TileLoader tileLoader; 51 protected TileCache tileCache; 52 protected TileSource tileSource; 53 54 protected List<MapMarker> mapMarkerList; 55 protected boolean mapMarkersVisible; 56 protected boolean tileGridVisible; 57 58 /** 59 * x- and y-position of the center of this map-panel on the world map 60 * denoted in screen pixel regarding the current zoom level. 61 */ 62 protected Point center; 63 64 /** 65 * Current zoom level 66 */ 67 protected int zoom; 68 69 protected JSlider zoomSlider; 70 protected JButton zoomInButton; 71 protected JButton zoomOutButton; 72 73 JobDispatcher jobDispatcher; 74 75 /** 76 * Creates a standard {@link JMapViewer} instance that can be controlled via 77 * mouse: hold right mouse button for moving, double click left mouse button 78 * or use mouse wheel for zooming. Loaded tiles are stored the 79 * {@link MemoryTileCache} and the tile loader uses 4 parallel threads for 80 * retrieving the tiles. 81 */ 82 public JMapViewer() { 83 this(new MemoryTileCache(), 4); 84 new DefaultMapController(this); 85 } 86 87 public JMapViewer(TileCache tileCache, int downloadThreadCount) { 88 super(); 89 tileSource = new OsmTileSource.Mapnik(); 90 tileLoader = new OsmTileLoader(this); 91 this.tileCache = tileCache; 92 jobDispatcher = JobDispatcher.getInstance(); 93 mapMarkerList = new LinkedList<MapMarker>(); 94 mapMarkersVisible = true; 95 tileGridVisible = false; 96 setLayout(null); 97 initializeZoomSlider(); 98 setMinimumSize(new Dimension(Tile.SIZE, Tile.SIZE)); 99 setPreferredSize(new Dimension(400, 400)); 100 setDisplayPositionByLatLon(50, 9, 3); 101 } 102 103 protected void initializeZoomSlider() { 104 zoomSlider = new JSlider(MIN_ZOOM, tileSource.getMaxZoom()); 105 zoomSlider.setOrientation(JSlider.VERTICAL); 106 zoomSlider.setBounds(10, 10, 30, 150); 107 zoomSlider.setOpaque(false); 108 zoomSlider.addChangeListener(new ChangeListener() { 109 public void stateChanged(ChangeEvent e) { 110 setZoom(zoomSlider.getValue()); 111 } 112 }); 113 add(zoomSlider); 114 int size = 18; 115 try { 116 ImageIcon icon = new ImageIcon(getClass().getResource("images/plus.png")); 117 zoomInButton = new JButton(icon); 118 } catch (Exception e) { 119 zoomInButton = new JButton("+"); 120 zoomInButton.setFont(new Font("sansserif", Font.BOLD, 9)); 121 zoomInButton.setMargin(new Insets(0, 0, 0, 0)); 122 } 123 zoomInButton.setBounds(4, 155, size, size); 124 zoomInButton.addActionListener(new ActionListener() { 125 126 public void actionPerformed(ActionEvent e) { 127 zoomIn(); 128 } 129 }); 130 add(zoomInButton); 131 try { 132 ImageIcon icon = new ImageIcon(getClass().getResource("images/minus.png")); 133 zoomOutButton = new JButton(icon); 134 } catch (Exception e) { 135 zoomOutButton = new JButton("-"); 136 zoomOutButton.setFont(new Font("sansserif", Font.BOLD, 9)); 137 zoomOutButton.setMargin(new Insets(0, 0, 0, 0)); 138 } 139 zoomOutButton.setBounds(8 + size, 155, size, size); 140 zoomOutButton.addActionListener(new ActionListener() { 141 142 public void actionPerformed(ActionEvent e) { 143 zoomOut(); 144 } 145 }); 146 add(zoomOutButton); 147 } 148 149 /** 150 * Changes the map pane so that it is centered on the specified coordinate 151 * at the given zoom level. 152 * 153 * @param lat 154 * latitude of the specified coordinate 155 * @param lon 156 * longitude of the specified coordinate 157 * @param zoom 158 * {@link #MIN_ZOOM} <= zoom level <= {@link #MAX_ZOOM} 159 */ 160 public void setDisplayPositionByLatLon(double lat, double lon, int zoom) { 161 setDisplayPositionByLatLon(new Point(getWidth() / 2, getHeight() / 2), lat, lon, zoom); 162 } 163 164 /** 165 * Changes the map pane so that the specified coordinate at the given zoom 166 * level is displayed on the map at the screen coordinate 167 * <code>mapPoint</code>. 168 * 169 * @param mapPoint 170 * point on the map denoted in pixels where the coordinate should 171 * be set 172 * @param lat 173 * latitude of the specified coordinate 174 * @param lon 175 * longitude of the specified coordinate 176 * @param zoom 177 * {@link #MIN_ZOOM} <= zoom level <= 178 * {@link TileSource#getMaxZoom()} 179 */ 180 public void setDisplayPositionByLatLon(Point mapPoint, double lat, double lon, int zoom) { 181 int x = OsmMercator.LonToX(lon, zoom); 182 int y = OsmMercator.LatToY(lat, zoom); 183 setDisplayPosition(mapPoint, x, y, zoom); 184 } 185 186 public void setDisplayPosition(int x, int y, int zoom) { 187 setDisplayPosition(new Point(getWidth() / 2, getHeight() / 2), x, y, zoom); 188 } 189 190 public void setDisplayPosition(Point mapPoint, int x, int y, int zoom) { 191 if (zoom > tileSource.getMaxZoom() || zoom < MIN_ZOOM) 192 return; 193 194 // Get the plain tile number 195 Point p = new Point(); 196 p.x = x - mapPoint.x + getWidth() / 2; 197 p.y = y - mapPoint.y + getHeight() / 2; 198 center = p; 199 setIgnoreRepaint(true); 200 try { 201 int oldZoom = this.zoom; 202 this.zoom = zoom; 203 if (oldZoom != zoom) 204 zoomChanged(oldZoom); 205 if (zoomSlider.getValue() != zoom) 206 zoomSlider.setValue(zoom); 207 } finally { 208 setIgnoreRepaint(false); 209 repaint(); 210 } 211 } 212 213 /** 214 * Sets the displayed map pane and zoom level so that all map markers are 215 * visible. 216 */ 217 public void setDisplayToFitMapMarkers() { 218 if (mapMarkerList == null || mapMarkerList.size() == 0) 219 return; 220 int x_min = Integer.MAX_VALUE; 221 int y_min = Integer.MAX_VALUE; 222 int x_max = Integer.MIN_VALUE; 223 int y_max = Integer.MIN_VALUE; 224 int mapZoomMax = tileSource.getMaxZoom(); 225 for (MapMarker marker : mapMarkerList) { 226 int x = OsmMercator.LonToX(marker.getLon(), mapZoomMax); 227 int y = OsmMercator.LatToY(marker.getLat(), mapZoomMax); 228 x_max = Math.max(x_max, x); 229 y_max = Math.max(y_max, y); 230 x_min = Math.min(x_min, x); 231 y_min = Math.min(y_min, y); 232 } 233 int height = Math.max(0, getHeight()); 234 int width = Math.max(0, getWidth()); 235 // System.out.println(x_min + " < x < " + x_max); 236 // System.out.println(y_min + " < y < " + y_max); 237 // System.out.println("tiles: " + width + " " + height); 238 int newZoom = mapZoomMax; 239 int x = x_max - x_min; 240 int y = y_max - y_min; 241 while (x > width || y > height) { 242 // System.out.println("zoom: " + zoom + " -> " + x + " " + y); 243 newZoom--; 244 x >>= 1; 245 y >>= 1; 246 } 247 x = x_min + (x_max - x_min) / 2; 248 y = y_min + (y_max - y_min) / 2; 249 int z = 1 << (mapZoomMax - newZoom); 250 x /= z; 251 y /= z; 252 setDisplayPosition(x, y, newZoom); 253 } 254 255 public Point2D.Double getPosition() { 256 double lon = OsmMercator.XToLon(center.x, zoom); 257 double lat = OsmMercator.YToLat(center.y, zoom); 258 return new Point2D.Double(lat, lon); 259 } 260 261 public Point2D.Double getPosition(Point mapPoint) { 262 int x = center.x + mapPoint.x - getWidth() / 2; 263 int y = center.y + mapPoint.y - getHeight() / 2; 264 double lon = OsmMercator.XToLon(x, zoom); 265 double lat = OsmMercator.YToLat(y, zoom); 266 return new Point2D.Double(lat, lon); 267 } 268 269 /** 270 * Calculates the position on the map of a given coordinate 271 * 272 * @param lat 273 * @param lon 274 * @return point on the map or <code>null</code> if the point is not visible 275 */ 276 public Point getMapPosition(double lat, double lon) { 277 int x = OsmMercator.LonToX(lon, zoom); 278 int y = OsmMercator.LatToY(lat, zoom); 279 x -= center.x - getWidth() / 2; 280 y -= center.y - getHeight() / 2; 281 if (x < 0 || y < 0 || x > getWidth() || y > getHeight()) 282 return null; 283 return new Point(x, y); 284 } 285 286 @Override 287 protected void paintComponent(Graphics g) { 288 super.paintComponent(g); 289 290 int iMove = 0; 291 292 int tilex = center.x / Tile.SIZE; 293 int tiley = center.y / Tile.SIZE; 294 int off_x = (center.x % Tile.SIZE); 295 int off_y = (center.y % Tile.SIZE); 296 297 int w2 = getWidth() / 2; 298 int h2 = getHeight() / 2; 299 int posx = w2 - off_x; 300 int posy = h2 - off_y; 301 302 int diff_left = off_x; 303 int diff_right = Tile.SIZE - off_x; 304 int diff_top = off_y; 305 int diff_bottom = Tile.SIZE - off_y; 306 307 boolean start_left = diff_left < diff_right; 308 boolean start_top = diff_top < diff_bottom; 309 310 if (start_top) { 311 if (start_left) 312 iMove = 2; 313 else 314 iMove = 3; 315 } else { 316 if (start_left) 317 iMove = 1; 318 else 319 iMove = 0; 320 } // calculate the visibility borders 321 int x_min = -Tile.SIZE; 322 int y_min = -Tile.SIZE; 323 int x_max = getWidth(); 324 int y_max = getHeight(); 325 326 // paint the tiles in a spiral, starting from center of the map 327 boolean painted = true; 328 int x = 0; 329 while (painted) { 330 painted = false; 331 for (int i = 0; i < 4; i++) { 332 if (i % 2 == 0) 333 x++; 334 for (int j = 0; j < x; j++) { 335 if (x_min <= posx && posx <= x_max && y_min <= posy && posy <= y_max) { 336 // tile is visible 337 Tile tile = getTile(tilex, tiley, zoom); 338 if (tile != null) { 339 painted = true; 340 tile.paint(g, posx, posy); 341 if (tileGridVisible) 342 g.drawRect(posx, posy, Tile.SIZE, Tile.SIZE); 343 } 344 } 345 Point p = move[iMove]; 346 posx += p.x * Tile.SIZE; 347 posy += p.y * Tile.SIZE; 348 tilex += p.x; 349 tiley += p.y; 350 } 351 iMove = (iMove + 1) % move.length; 352 } 353 } 354 // outer border of the map 355 int mapSize = Tile.SIZE << zoom; 356 g.drawRect(w2 - center.x, h2 - center.y, mapSize, mapSize); 357 358 // g.drawString("Tiles in cache: " + tileCache.getTileCount(), 50, 20); 359 if (!mapMarkersVisible || mapMarkerList == null) 360 return; 361 for (MapMarker marker : mapMarkerList) { 362 Point p = getMapPosition(marker.getLat(), marker.getLon()); 363 // System.out.println(marker + " -> " + p); 364 if (p != null) 365 marker.paint(g, p); 366 } 367 } 368 369 /** 370 * Moves the visible map pane. 371 * 372 * @param x 373 * horizontal movement in pixel. 374 * @param y 375 * vertical movement in pixel 376 */ 377 public void moveMap(int x, int y) { 378 center.x += x; 379 center.y += y; 380 repaint(); 381 } 382 383 /** 384 * @return the current zoom level 385 */ 386 public int getZoom() { 387 return zoom; 388 } 389 390 /** 391 * Increases the current zoom level by one 392 */ 393 public void zoomIn() { 394 setZoom(zoom + 1); 395 } 396 397 /** 398 * Increases the current zoom level by one 399 */ 400 public void zoomIn(Point mapPoint) { 401 setZoom(zoom + 1, mapPoint); 402 } 403 404 /** 405 * Decreases the current zoom level by one 406 */ 407 public void zoomOut() { 408 setZoom(zoom - 1); 409 } 410 411 /** 412 * Decreases the current zoom level by one 413 */ 414 public void zoomOut(Point mapPoint) { 415 setZoom(zoom - 1, mapPoint); 416 } 417 418 public void setZoom(int zoom, Point mapPoint) { 419 if (zoom > tileSource.getMaxZoom() || zoom < tileSource.getMinZoom() || zoom == this.zoom) 420 return; 421 Point2D.Double zoomPos = getPosition(mapPoint); 422 jobDispatcher.cancelOutstandingJobs(); // Clearing outstanding load 423 // requests 424 setDisplayPositionByLatLon(mapPoint, zoomPos.x, zoomPos.y, zoom); 425 } 426 427 public void setZoom(int zoom) { 428 setZoom(zoom, new Point(getWidth() / 2, getHeight() / 2)); 429 } 430 431 /** 432 * retrieves a tile from the cache. If the tile is not present in the cache 433 * a load job is added to the working queue of {@link JobThread}. 434 * 435 * @param tilex 436 * @param tiley 437 * @param zoom 438 * @return specified tile from the cache or <code>null</code> if the tile 439 * was not found in the cache. 440 */ 441 protected Tile getTile(int tilex, int tiley, int zoom) { 442 int max = (1 << zoom); 443 if (tilex < 0 || tilex >= max || tiley < 0 || tiley >= max) 444 return null; 445 Tile tile = tileCache.getTile(tileSource, tilex, tiley, zoom); 446 if (tile == null) { 447 tile = new Tile(tileSource, tilex, tiley, zoom); 448 tileCache.addTile(tile); 449 tile.loadPlaceholderFromCache(tileCache); 450 } 451 if (!tile.isLoaded()) { 452 jobDispatcher.addJob(tileLoader.createTileLoaderJob(tileSource, tilex, tiley, zoom)); 453 } 454 return tile; 455 } 456 457 /** 458 * Every time the zoom level changes this method is called. Override it in 459 * derived implementations for adapting zoom dependent values. The new zoom 460 * level can be obtained via {@link #getZoom()}. 461 * 462 * @param oldZoom 463 * the previous zoom level 464 */ 465 protected void zoomChanged(int oldZoom) { 466 zoomSlider.setToolTipText("Zoom level " + zoom); 467 zoomInButton.setToolTipText("Zoom to level " + (zoom + 1)); 468 zoomOutButton.setToolTipText("Zoom to level " + (zoom - 1)); 469 zoomOutButton.setEnabled(zoom > tileSource.getMinZoom()); 470 zoomInButton.setEnabled(zoom < tileSource.getMaxZoom()); 471 } 472 473 public boolean isTileGridVisible() { 474 return tileGridVisible; 475 } 476 477 public void setTileGridVisible(boolean tileGridVisible) { 478 this.tileGridVisible = tileGridVisible; 479 repaint(); 480 } 481 482 public boolean getMapMarkersVisible() { 483 return mapMarkersVisible; 484 } 485 486 /** 487 * Enables or disables painting of the {@link MapMarker} 488 * 489 * @param mapMarkersVisible 490 * @see #addMapMarker(MapMarker) 491 * @see #getMapMarkerList() 492 */ 493 public void setMapMarkerVisible(boolean mapMarkersVisible) { 494 this.mapMarkersVisible = mapMarkersVisible; 495 repaint(); 496 } 497 498 public void setMapMarkerList(List<MapMarker> mapMarkerList) { 499 this.mapMarkerList = mapMarkerList; 500 repaint(); 501 } 502 503 public List<MapMarker> getMapMarkerList() { 504 return mapMarkerList; 505 } 506 507 public void addMapMarker(MapMarker marker) { 508 mapMarkerList.add(marker); 509 } 510 511 public void setZoomContolsVisible(boolean visible) { 512 zoomSlider.setVisible(visible); 513 zoomInButton.setVisible(visible); 514 zoomOutButton.setVisible(visible); 515 } 516 517 public boolean getZoomContolsVisible() { 518 return zoomSlider.isVisible(); 519 } 520 521 public TileCache getTileCache() { 522 return tileCache; 523 } 524 525 public TileLoader getTileLoader() { 526 return tileLoader; 527 } 528 529 public void setTileLoader(TileLoader tileLoader) { 530 this.tileLoader = tileLoader; 531 } 532 533 public TileSource getTileLayerSource() { 534 return tileSource; 535 } 536 537 public TileSource getTileSource() { 538 return tileSource; 539 } 540 541 public void setTileSource(TileSource tileSource) { 542 if (tileSource.getMaxZoom() > MAX_ZOOM) 543 throw new RuntimeException("Maximum zoom level too high"); 544 if (tileSource.getMinZoom() < MIN_ZOOM) 545 throw new RuntimeException("Minumim zoom level too low"); 546 this.tileSource = tileSource; 547 zoomSlider.setMinimum(tileSource.getMinZoom()); 548 zoomSlider.setMaximum(tileSource.getMaxZoom()); 549 jobDispatcher.cancelOutstandingJobs(); 550 if (zoom > tileSource.getMaxZoom()) 551 setZoom(tileSource.getMaxZoom()); 552 repaint(); 553 } 554 555 public void tileLoadingFinished(Tile tile, boolean success) { 556 repaint(); 557 } 572 558 573 559 }
Note:
See TracChangeset
for help on using the changeset viewer.