Changeset 18354 in osm for applications/editors/josm/plugins/slippymap
- Timestamp:
- 2009-10-28T23:58:42+01:00 (15 years ago)
- Location:
- applications/editors/josm/plugins/slippymap/src/org/openstreetmap/josm/plugins/slippymap
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
applications/editors/josm/plugins/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapLayer.java
r17822 r18354 21 21 import java.util.List; 22 22 import java.util.LinkedList; 23 import java.util. TreeSet;23 import java.util.HashSet; 24 24 25 25 import javax.swing.AbstractAction; 26 26 import javax.swing.Icon; 27 27 import javax.swing.JMenuItem; 28 import javax.swing.JCheckBoxMenuItem; 28 29 import javax.swing.JPopupMenu; 29 30 import javax.swing.JSeparator; … … 41 42 import org.openstreetmap.josm.tools.ImageProvider; 42 43 44 import org.openstreetmap.gui.jmapviewer.*; 45 import org.openstreetmap.gui.jmapviewer.interfaces.*; 46 import org.openstreetmap.gui.jmapviewer.Tile; 47 43 48 /** 44 49 * Class that displays a slippy map layer. … … 49 54 * 50 55 */ 51 public class SlippyMapLayer extends Layer implements ImageObserver, 52 PreferenceChangedListener { 56 public class SlippyMapLayer extends Layer implements PreferenceChangedListener, ImageObserver, 57 TileLoaderListener { 58 boolean debug = false; 59 void out(String s) 60 { 61 Main.debug(s); 62 } 63 64 protected MemoryTileCache tileCache; 65 protected TileSource tileSource = new OsmTileSource.Mapnik(); 66 protected TileLoader tileLoader; 67 JobDispatcher jobDispatcher = JobDispatcher.getInstance(); 68 69 HashSet<Tile> tileRequestsOutstanding = new HashSet<Tile>(); 70 public synchronized void tileLoadingFinished(Tile tile, boolean success) 71 { 72 tile.setLoaded(true); 73 needRedraw = true; 74 Main.map.repaint(100); 75 tileRequestsOutstanding.remove(tile); 76 if (debug) 77 out("tileLoadingFinished() tile: " + tile + " success: " + success); 78 } 79 public TileCache getTileCache() 80 { 81 return tileCache; 82 } 83 void clearTileStorage() 84 { 85 out("clearing tile storage"); 86 tileCache = new MemoryTileCache(); 87 tileCache.setCacheSize(2000); 88 } 89 53 90 /** 54 91 * Actual zoom lvl. Initial zoom lvl is set to 55 92 * {@link SlippyMapPreferences#getMinZoomLvl()}. 56 93 */ 57 public int currentZoomLevel = SlippyMapPreferences.getMinZoomLvl(); 58 private Hashtable<SlippyMapKey, SlippyMapTile> tileStorage = null; 59 60 Point[][] pixelpos = new Point[21][21]; 94 public int currentZoomLevel; 95 61 96 LatLon lastTopLeft; 62 97 LatLon lastBotRight; 63 98 private Image bufferImage; 64 private SlippyMapTile clickedTile;99 private Tile clickedTile; 65 100 private boolean needRedraw; 66 101 private JPopupMenu tileOptionMenu; 67 68 static void debug(String msg) 69 { 70 71 } 102 JCheckBoxMenuItem autoZoomPopup; 103 Tile showMetadataTile; 104 105 void redraw() 106 { 107 needRedraw = true; 108 Main.map.repaint(); 109 } 110 72 111 @SuppressWarnings("serial") 73 112 public SlippyMapLayer() { 74 113 super(tr("Slippy Map")); 114 75 115 setBackgroundLayer(true); 76 116 this.setVisible(true); 117 118 currentZoomLevel = SlippyMapPreferences.getLastZoom(); 119 if (currentZoomLevel <= 0) 120 currentZoomLevel = SlippyMapPreferences.getMinZoomLvl(); 77 121 clearTileStorage(); 122 //tileLoader = new OsmTileLoader(this); 123 tileLoader = new OsmFileCacheTileLoader(this); 78 124 79 125 tileOptionMenu = new JPopupMenu(); 126 127 autoZoomPopup = new JCheckBoxMenuItem(); 128 autoZoomPopup.setAction(new AbstractAction(tr("Auto Zoom")) { 129 public void actionPerformed(ActionEvent ae) { 130 boolean new_state = !SlippyMapPreferences.getAutozoom(); 131 SlippyMapPreferences.setAutozoom(new_state); 132 } 133 }); 134 autoZoomPopup.setSelected(SlippyMapPreferences.getAutozoom()); 135 tileOptionMenu.add(autoZoomPopup); 136 80 137 tileOptionMenu.add(new JMenuItem(new AbstractAction(tr("Load Tile")) { 81 138 public void actionPerformed(ActionEvent ae) { 82 139 if (clickedTile != null) { 83 loadSingleTile(clickedTile); 84 needRedraw = true; 85 Main.map.repaint(); 140 loadTile(clickedTile); 141 redraw(); 86 142 } 87 143 } … … 89 145 90 146 tileOptionMenu.add(new JMenuItem(new AbstractAction( 91 tr("Show Tile Status")) {147 tr("Show Tile Info")) { 92 148 public void actionPerformed(ActionEvent ae) { 149 out("info tile: " + clickedTile); 93 150 if (clickedTile != null) { 94 clickedTile.loadMetadata(); 95 needRedraw = true; 96 Main.map.repaint(); 151 showMetadataTile = clickedTile; 152 redraw(); 97 153 } 98 154 } … … 103 159 public void actionPerformed(ActionEvent ae) { 104 160 if (clickedTile != null) { 105 clickedTile.requestUpdate(); 106 needRedraw = true; 107 Main.map.repaint(); 161 //FIXME//clickedTile.requestUpdate(); 162 redraw(); 108 163 } 109 164 } … … 114 169 public void actionPerformed(ActionEvent ae) { 115 170 loadAllTiles(); 116 needRedraw = true; 117 Main.map.repaint(); 171 redraw(); 118 172 } 119 173 })); … … 124 178 public void actionPerformed(ActionEvent ae) { 125 179 increaseZoomLevel(); 126 needRedraw = true; 127 Main.map.repaint(); 180 redraw(); 128 181 } 129 182 })); … … 141 194 public void actionPerformed(ActionEvent ae) { 142 195 System.out.print("flushing all tiles..."); 143 for (SlippyMapTile t : tileStorage.values()) { 144 t.dropImage(); 145 } 196 clearTileStorage(); 146 197 System.out.println("done"); 147 shrinkTileStorage(0);148 198 } 149 199 })); … … 158 208 return; 159 209 clickedTile = getTileForPixelpos(e.getX(), e.getY()); 160 tileOptionMenu.show(e.getComponent(), e.getX(), e 161 .getY()); 210 tileOptionMenu.show(e.getComponent(), e.getX(), e.getY()); 162 211 } 163 212 }); … … 180 229 } 181 230 231 void zoomChanged() 232 { 233 if (debug) 234 out("zoomChanged(): " + currentZoomLevel); 235 needRedraw = true; 236 jobDispatcher.cancelOutstandingJobs(); 237 tileRequestsOutstanding.clear(); 238 SlippyMapPreferences.setLastZoom(currentZoomLevel); 239 } 182 240 /** 183 241 * Zoom in, go closer to map. … … 188 246 { 189 247 boolean zia = currentZoomLevel < SlippyMapPreferences.getMaxZoomLvl(); 190 this.debug("zoomIncreaseAllowed(): " + zia + " " + currentZoomLevel + " vs. " + SlippyMapPreferences.getMaxZoomLvl() ); 248 if (debug) 249 out("zoomIncreaseAllowed(): " + zia + " " + currentZoomLevel + " vs. " + SlippyMapPreferences.getMaxZoomLvl() ); 191 250 return zia; 192 251 } … … 196 255 if (zoomIncreaseAllowed()) { 197 256 currentZoomLevel++; 198 this.debug("increasing zoom level to: " + currentZoomLevel); 199 needRedraw = true; 257 if (debug) 258 out("increasing zoom level to: " + currentZoomLevel); 259 zoomChanged(); 200 260 } else { 201 261 System.err.println("current zoom lvl ("+currentZoomLevel+") couldnt be increased. "+ … … 219 279 lastImageScale = null; 220 280 if (zoomDecreaseAllowed()) { 221 this.debug("decreasing zoom level to: " + currentZoomLevel); 281 if (debug) 282 out("decreasing zoom level to: " + currentZoomLevel); 222 283 currentZoomLevel--; 223 needRedraw = true;284 zoomChanged(); 224 285 } else { 225 286 System.err.println("current zoom lvl couldnt be decreased. MinZoomLvl("+minZoom+") reached."); … … 229 290 } 230 291 231 public void clearTileStorage() { 232 // when max zoom lvl is begin saved, this method is called and probably 233 // the setting isnt saved yet. 234 int maxZoom = SlippyMapPreferences.getMaxZoomLvl(); 235 tileStorage = new Hashtable<SlippyMapKey, SlippyMapTile>(); 236 checkTileStorage(); 237 } 238 239 class TileTimeComp implements Comparator<SlippyMapTile> { 240 public int compare(SlippyMapTile s1, SlippyMapTile s2) { 241 long t1 = s1.access_time(); 242 long t2 = s2.access_time(); 243 if (s1 == s2) 244 return 0; 245 if (t1 == t2) { 246 t1 = s1.hashCode(); 247 t2 = s2.hashCode(); 248 } 249 if (t1 < t2) 250 return -1; 251 return 1; 252 } 253 } 254 255 /** 256 * <p> 257 * Check if tiles.size() is not more than maxNrTiles. 258 * If yes, oldest tiles by timestamp are flushed from 259 * the cache. 260 * </p> 292 synchronized Tile getOrCreateTile(int x, int y, int zoom) { 293 Tile tile = getTile(x, y, zoom); 294 if (tile == null) { 295 tile = new Tile(tileSource, x, y, zoom); 296 tileCache.addTile(tile); 297 tile.loadPlaceholderFromCache(tileCache); 298 } 299 return tile; 300 } 301 302 /* 303 * This can and will return null for tiles that are not 304 * already in the cache. 261 305 */ 262 public void shrinkTileStorage(int maxNrTiles) 263 { 264 TreeSet<SlippyMapTile> tiles = new TreeSet<SlippyMapTile>(new TileTimeComp()); 265 tiles.addAll(tileStorage.values()); 266 int nr_to_drop = tiles.size() - maxNrTiles; 267 if (nr_to_drop <= 0) { 268 this.debug("total of " + tiles.size() + " loaded tiles, size OK (< " + maxNrTiles + ")"); 269 return; 270 } 271 this.debug("total of " + tiles.size() + " tiles, need to flush " + nr_to_drop + " tiles"); 272 for (SlippyMapTile t : tiles) { 273 if (nr_to_drop <= 0) 274 break; 275 t.dropImage(); 276 nr_to_drop--; 277 //tileStorage.remove(t.getKey()); 278 } 279 } 280 long lastCheck = 0; 281 public void checkTileStorage() { 282 long now = System.currentTimeMillis(); 283 if (now - lastCheck < 1000) 284 return; 285 lastCheck = now; 286 shrinkTileStorage(200); 287 } 288 289 LinkedList<SlippyMapTile> downloadQueue = new LinkedList<SlippyMapTile>(); 290 LinkedList<Image> downloadList = new LinkedList<Image>(); 291 int simultaneousTileDownloads = 5; 292 int maxQueueSize = 50; 293 synchronized void markDone(Image i) 294 { 295 boolean inList = downloadList.remove(i); 296 if (!inList) { 297 Main.debug("ERROR: downloaded image was not queued"); 298 return; 299 } 300 //System.out.print("currently downloading: " + downloadList.size() + 301 // " queue size: " + downloadQueue.size() +" \r"); 302 if (downloadQueue.size() > 0) 303 loadSingleTile(downloadQueue.getLast()); 304 } 305 synchronized void loadSingleTile(SlippyMapTile tile) 306 { 307 // this moves the tile to the front of the line 308 if (downloadQueue.contains(tile)) 309 downloadQueue.remove(tile); 310 downloadQueue.addLast(tile); 311 // We assume that a queue larger than this is 312 // too big and the downloads at the end of it 313 // too old to be relevant. 314 while (downloadQueue.size() > maxQueueSize) 315 downloadQueue.removeFirst(); 316 if (downloadList.size() > simultaneousTileDownloads) 317 return; 318 //System.out.print("currently downloading: " + downloadList.size() + 319 // " queue size: " + downloadQueue.size() + " \r"); 320 while (!downloadQueue.isEmpty()) { 321 // This is a FIFO queue. The reasoning is 322 // that we want to draw the most recently 323 // requested images now. We may have panned 324 // or zoomed away 325 tile = downloadQueue.removeLast(); 326 Image img = tile.loadImage(); 327 if (imageLoaded(img)) 328 continue; 329 Toolkit.getDefaultToolkit().prepareImage(img, -1, -1, this); 330 downloadList.add(img); 331 break; 332 } 333 } 334 335 synchronized SlippyMapTile getTile(int x, int y, int zoom) { 336 SlippyMapKey key = new SlippyMapKey(x, y, zoom); 337 if (!key.valid) { 338 return null; 339 } 340 return tileStorage.get(key); 341 } 342 343 synchronized SlippyMapTile putTile(SlippyMapTile tile, int x, int y, int zoom) { 344 SlippyMapKey key = new SlippyMapKey(x, y, zoom); 345 if (!key.valid) { 346 return null; 347 } 348 return tileStorage.put(key, tile); 349 } 350 351 synchronized SlippyMapTile getOrCreateTile(int x, int y, int zoom) { 352 SlippyMapTile tile = getTile(x, y, zoom); 353 if (tile != null) { 354 return tile; 355 } 356 tile = new SlippyMapTile(x, y, zoom); 357 putTile(tile, x, y, zoom); 306 synchronized Tile getTile(int x, int y, int zoom) { 307 int max = (1 << zoom); 308 if (x < 0 || x >= max || y < 0 || y >= max) 309 return null; 310 Tile tile = tileCache.getTile(tileSource, x, y, zoom); 358 311 return tile; 312 } 313 314 synchronized boolean loadTile(Tile tile) 315 { 316 if (tile == null) 317 return false; 318 if (tile.isLoaded()) 319 return false; 320 if (tile.isLoading()) 321 return false; 322 if (tileRequestsOutstanding.contains(tile)) 323 return false; 324 tileRequestsOutstanding.add(tile); 325 jobDispatcher.addJob(tileLoader.createTileLoaderJob(tileSource, 326 tile.getXtile(), tile.getYtile(), tile.getZoom())); 327 return true; 359 328 } 360 329 … … 372 341 return; 373 342 } 374 375 for (Tile t : ts.allTiles()) { 376 SlippyMapTile tile = getOrCreateTile(t.x, t.y, currentZoomLevel); 377 if (tile.getImage() == null) { 378 this.loadSingleTile(tile); 379 } 380 }//end of for Tile t 343 ts.loadAllTiles(); 381 344 } 382 345 … … 386 349 */ 387 350 Image lastScaledImage = null; 351 public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) { 352 boolean done = ((infoflags & (ERROR | FRAMEBITS | ALLBITS)) != 0); 353 needRedraw = true; 354 Main.map.repaint(done ? 0 : 100); 355 return !done; 356 } 357 boolean imageLoaded(Image i) { 358 if (i == null) 359 return false; 360 int status = Toolkit.getDefaultToolkit().checkImage(i, -1, -1, this); 361 if ((status & ALLBITS) != 0) 362 return true; 363 return false; 364 } 365 Image getLoadedTileImage(Tile tile) 366 { 367 if (!tile.isLoaded()) 368 return null; 369 Image img = tile.getImage(); 370 if (!imageLoaded(img)) 371 return null; 372 return img; 373 } 388 374 389 375 double getImageScaling(Image img, Point p0, Point p1) { … … 425 411 } 426 412 427 boolean imageLoaded(Image i) { 428 if (i == null) 429 return false; 430 431 int status = Toolkit.getDefaultToolkit().checkImage(i, -1, -1, this); 432 if ((status & ALLBITS) != 0) 433 return true; 434 return false; 435 } 436 413 LatLon tileLatLon(Tile t) 414 { 415 int zoom = t.getZoom(); 416 return new LatLon(tileYToLat(t.getYtile(), zoom), 417 tileXToLon(t.getXtile(), zoom)); 418 } 419 420 int paintFromOtherZooms(Graphics g, Tile topLeftTile, Tile botRightTile) 421 { 422 LatLon topLeft = tileLatLon(topLeftTile); 423 LatLon botRight = tileLatLon(botRightTile); 424 425 /* 426 * Go looking for tiles in zoom levels *other* than the current 427 * one. Even if they might look bad, they look better than a 428 * blank tile. 429 * 430 * Make darn sure that the tilesCache can either hold all of 431 * these "fake" tiles or that they don't get inserted in it to 432 * begin with. 433 */ 434 //int otherZooms[] = {-5, -4, -3, 2, -2, 1, -1}; 435 int otherZooms[] = { -1, 1, -2, 2, -3, -4, -5}; 436 int painted = 0;; 437 for (int zoomOff : otherZooms) { 438 int zoom = currentZoomLevel + zoomOff; 439 if ((zoom < SlippyMapPreferences.getMinZoomLvl()) || 440 (zoom > SlippyMapPreferences.getMaxZoomLvl())) { 441 continue; 442 } 443 TileSet ts = new TileSet(topLeft, botRight, zoom); 444 int zoom_painted = this.paintTileImages(g, ts, zoom); 445 if (debug && zoom_painted > 0) 446 out("painted " + zoom_painted + "/"+ ts.size() + 447 " tiles from zoom("+zoomOff+"): " + zoom); 448 painted += zoom_painted; 449 if (zoom_painted >= ts.size()) { 450 if (debug) 451 out("broke after drawing " + zoom_painted + "/"+ ts.size() + " at zoomOff: " + zoomOff); 452 break; 453 } 454 } 455 /* 456 * Save this for last since it will get painted over all the others 457 */ 458 return painted; 459 } 460 // This function is called for several zoom levels, not just 461 // the current one. It should not trigger any tiles to be 462 // downloaded. It should also avoid polluting the tile cache 463 // with any tiles since these tiles are not mandatory. 437 464 Double lastImageScale = null; 438 465 int paintTileImages(Graphics g, TileSet ts, int zoom) { 439 466 int paintedTiles = 0; 440 467 boolean imageScaleRecorded = false; 441 Image img = null; 442 for (Tile t : ts.allTiles()) { 443 SlippyMapTile tile = getTile(t.x, t.y, zoom); 444 if (tile == null) { 445 // Don't trigger tile loading if this isn't 446 // the exact zoom level we're looking for 447 if (zoom != currentZoomLevel) 448 continue; 449 tile = getOrCreateTile(t.x, t.y, zoom); 450 if (SlippyMapPreferences.getAutoloadTiles()) 451 loadSingleTile(tile); 452 } 453 img = tile.getImage(); 454 if (img == null) 455 continue; 456 if ((zoom != currentZoomLevel) && !tile.isDownloaded()) 457 continue; 458 Point p = t.pixelPos(zoom); 468 for (Tile tile : ts.allTiles()) { 459 469 /* 460 470 * We need to get a box in which to draw, so advance by one tile in 461 * each direction to find the other corner of the box 471 * each direction to find the other corner of the box. 472 * Note: this somewhat pollutes the tile cache 462 473 */ 463 Tile t2 = new Tile(t.x + 1, t.y + 1); 464 Point p2 = t2.pixelPos(zoom); 465 if (imageLoaded(img)) { 466 g.drawImage(img, p.x, p.y, p2.x - p.x, p2.y - p.y, this); 467 paintedTiles++; 468 } 469 if (img == null) 474 Tile t2 = getOrCreateTile(tile.getXtile() + 1, tile.getYtile() + 1, zoom); 475 Image img = getLoadedTileImage(tile); 476 Point p = pixelPos(tile); 477 Point p2 = pixelPos(t2); 478 if (currentZoomLevel == zoom && img == null) { 479 int painted = paintFromOtherZooms(g, tile, t2); 480 if (painted > 0 && debug) 481 out("painted a total of " + painted); 470 482 continue; 483 } 484 g.drawImage(img, p.x, p.y, p2.x - p.x, p2.y - p.y, this); 485 paintedTiles++; 471 486 if (!imageScaleRecorded && zoom == currentZoomLevel) { 472 487 lastImageScale = new Double(getImageScaling(img, p, p2)); … … 483 498 } 484 499 485 void paintTileText(TileSet ts, Graphics g, MapView mv, int zoom, Tile t) { 500 void paintTileText(TileSet ts, Tile tile, Graphics g, MapView mv, int zoom, Tile t) { 486 501 int fontHeight = g.getFontMetrics().getHeight(); 487 488 SlippyMapTile tile = getTile(t.x, t.y, zoom); 489 if (tile == null) { 502 if (tile == null) 490 503 return; 491 } 492 if (tile.getImage() == null) { 493 loadSingleTile(tile); 494 } 495 Point p = t.pixelPos(zoom); 504 Point p = pixelPos(t); 496 505 int texty = p.y + 2 + fontHeight; 497 506 498 507 if (SlippyMapPreferences.getDrawDebug()) { 499 g.drawString("x=" + t. x+ " y=" + t.y+ " z=" + zoom + "", p.x + 2, texty);508 g.drawString("x=" + t.getXtile() + " y=" + t.getYtile() + " z=" + zoom + "", p.x + 2, texty); 500 509 texty += 1 + fontHeight; 501 if ((t. x% 32 == 0) && (t.y% 32 == 0)) {502 g.drawString("x=" + t. x/ 32 + " y=" + t.y/ 32 + " z=7", p.x + 2, texty);510 if ((t.getXtile() % 32 == 0) && (t.getYtile() % 32 == 0)) { 511 g.drawString("x=" + t.getXtile() / 32 + " y=" + t.getYtile() / 32 + " z=7", p.x + 2, texty); 503 512 texty += 1 + fontHeight; 504 513 } 505 514 }// end of if draw debug 506 515 507 String md = tile.getMetadata(); 508 if (md != null) { 509 g.drawString(md, p.x + 2, texty); 510 texty += 1 + fontHeight; 516 if (tile == showMetadataTile) { 517 String md = tile.toString(); 518 if (md != null) { 519 g.drawString(md, p.x + 2, texty); 520 texty += 1 + fontHeight; 521 } 511 522 } 512 523 513 524 String tileStatus = tile.getStatus(); 514 Image tileImage = tile.getImage(); 515 if (!imageLoaded(tileImage)) { 525 if (!tile.isLoaded()) { 516 526 g.drawString(tr("image " + tileStatus), p.x + 2, texty); 517 527 texty += 1 + fontHeight; … … 521 531 we don't need to poll like this 522 532 */ 523 if (!imageLoaded(tileImage)) { 524 needRedraw = true; 525 Main.map.repaint(100); 526 } 533 if (!tile.isLoaded()) 534 redraw(); 527 535 528 536 if (SlippyMapPreferences.getDrawDebug()) { 529 537 if (ts.leftTile(t)) { 530 if (t. y% 32 == 31) {538 if (t.getYtile() % 32 == 31) { 531 539 g.fillRect(0, p.y - 1, mv.getWidth(), 3); 532 540 } else { … … 537 545 } 538 546 539 private class Tile { 540 public int x; 541 public int y; 542 543 Tile(int x, int y) { 544 this.x = x; 545 this.y = y; 546 } 547 548 public Point pixelPos(int zoom) { 549 double lon = tileXToLon(this.x, zoom); 550 LatLon tmpLL = new LatLon(tileYToLat(this.y, zoom), lon); 547 public Point pixelPos(Tile t) { 548 double lon = tileXToLon(t.getXtile(), t.getZoom()); 549 LatLon tmpLL = new LatLon(tileYToLat(t.getYtile(), t.getZoom()), lon); 551 550 MapView mv = Main.map.mapView; 552 551 return mv.getPoint(tmpLL); 553 552 } 554 }555 553 private class TileSet { 556 554 int z12x0, z12x1, z12y0, z12y1; … … 581 579 } 582 580 double tilesSpanned() { 583 int x_span = z12x1 - z12x0; 584 int y_span = z12y1 - z12y0; 585 return Math.sqrt(1.0 * x_span * y_span); 581 return Math.sqrt(1.0 * this.size()); 582 } 583 584 int size() { 585 int x_span = z12x1 - z12x0 + 1; 586 int y_span = z12y1 - z12y0 + 1; 587 return x_span * y_span; 586 588 } 587 589 588 590 /* 589 * This is pretty silly. Should probably just be implemented as an590 * iterator to keep from having to instantiate all these tiles.591 * Get all tiles represented by this TileSet that are 592 * already in the tileCache. 591 593 */ 592 594 List<Tile> allTiles() 595 { 596 return this.allTiles(false); 597 } 598 private List<Tile> allTiles(boolean create) 593 599 { 594 600 List<Tile> ret = new ArrayList<Tile>(); 595 601 for (int x = z12x0; x <= z12x1; x++) { 596 602 for (int y = z12y0; y <= z12y1; y++) { 597 Tile t = new Tile(x % tileMax, y % tileMax); 598 ret.add(t); 603 Tile t; 604 if (create) 605 t = getOrCreateTile(x % tileMax, y % tileMax, zoom); 606 else 607 t = getTile(x % tileMax, y % tileMax, zoom); 608 if (t != null) 609 ret.add(t); 599 610 } 600 611 } 601 612 return ret; 602 613 } 603 614 void loadAllTiles() 615 { 616 List<Tile> tiles = this.allTiles(true); 617 int nr_queued = 0; 618 for (Tile t : tiles) { 619 if (loadTile(t)) 620 nr_queued++; 621 } 622 if (debug) 623 if (nr_queued > 0) 624 out("queued to load: " + nr_queued + "/" + tiles.size() + " tiles at zoom: " + zoom); 625 } 604 626 boolean topTile(Tile t) { 605 if (t. y== z12y0 )627 if (t.getYtile() == z12y0 ) 606 628 return true; 607 629 return false; … … 609 631 610 632 boolean leftTile(Tile t) { 611 if (t. x== z12x0 )633 if (t.getXtile() == z12x0 ) 612 634 return true; 613 635 return false; … … 615 637 } 616 638 639 boolean autoZoomEnabled() 640 { 641 return autoZoomPopup.isSelected(); 642 } 617 643 /** 618 644 */ … … 634 660 && !needRedraw) { 635 661 636 this.debug("drawing buffered image"); 662 if (debug) 663 out("drawing buffered image"); 637 664 g.drawImage(bufferImage, 0, 0, null); 638 665 return; … … 645 672 g = bufferImage.getGraphics(); 646 673 647 TileSet ts = new TileSet(topLeft, botRight, currentZoomLevel);648 674 int zoom = currentZoomLevel; 649 650 if (zoomDecreaseAllowed() && (ts.tilesSpanned() > 18)) { 651 this.debug("too many tiles, decreasing zoom from " + currentZoomLevel); 652 if (decreaseZoomLevel()) 653 this.paint(oldg, mv); 675 TileSet ts = new TileSet(topLeft, botRight, zoom); 676 677 if (autoZoomEnabled()) { 678 if (zoomDecreaseAllowed() && (ts.tilesSpanned() > 18)) { 679 if (debug) 680 out("too many tiles, decreasing zoom from " + currentZoomLevel); 681 if (decreaseZoomLevel()) 682 this.paint(oldg, mv); 683 return; 684 } 685 if (zoomIncreaseAllowed() && (ts.tilesSpanned() < 1.0)) { 686 if (debug) 687 out("doesn't even cover one tile (" + ts.tilesSpanned() 688 + "), increasing zoom from " + currentZoomLevel); 689 if (increaseZoomLevel()) 690 this.paint(oldg, mv); 691 return; 692 } 693 } 694 695 // Too many tiles... refuse to draw 696 if (ts.tilesSpanned() > 18) 654 697 return; 655 } 656 if (zoomIncreaseAllowed() && (ts.tilesSpanned() < 1.0)) { 657 this.debug("doesn't even cover one tile (" + ts.tilesSpanned() 658 + "), increasing zoom from " + currentZoomLevel); 659 if (increaseZoomLevel()) 660 this.paint(oldg, mv); 661 return; 662 } 663 664 if (ts.tilesSpanned() <= 0) { 665 System.out.println("doesn't even cover one tile, increasing zoom from " + currentZoomLevel); 666 if (increaseZoomLevel()) { 667 this.paint(oldg, mv); 668 } 669 return; 670 } 698 699 ts.loadAllTiles(); 671 700 672 701 int fontHeight = g.getFontMetrics().getHeight(); … … 674 703 g.setColor(Color.DARK_GRAY); 675 704 676 /*677 * Go looking for tiles in zoom levels *other* than the current678 * one. Even if they might look bad, they look better than a679 * blank tile.680 */681 int otherZooms[] = {-5, -4, -3, 2, -2, 1, -1};682 for (int zoomOff : otherZooms) {683 int zoom2 = currentZoomLevel + zoomOff;684 if ((zoom2 < SlippyMapPreferences.getMinZoomLvl()) ||685 (zoom2 > SlippyMapPreferences.getMaxZoomLvl())) {686 continue;687 }688 TileSet ts2 = new TileSet(topLeft, botRight, zoom2);689 int painted = this.paintTileImages(g, ts2, zoom2);690 //if (painted > 0)691 // System.out.println("painted " + painted + " tiles from zoom: " + zoom2);692 }693 /*694 * Save this for last since it will get painted over all the others695 */696 705 this.paintTileImages(g, ts, currentZoomLevel); 697 706 g.setColor(Color.red); 698 707 708 // The current zoom tileset is guaranteed to have all of 709 // its tiles 699 710 for (Tile t : ts.allTiles()) { 700 711 // This draws the vertical lines for the entire … … 702 713 // the column. 703 714 if (ts.topTile(t)) { 704 Point p = t.pixelPos(currentZoomLevel);715 Point p = pixelPos(t); 705 716 if (SlippyMapPreferences.getDrawDebug()) { 706 if (t. x% 32 == 0) {717 if (t.getXtile() % 32 == 0) { 707 718 // level 7 tile boundary 708 719 g.fillRect(p.x - 1, 0, 3, mv.getHeight()); … … 712 723 } 713 724 } 714 this.paintTileText(ts, g, mv, currentZoomLevel, t); 725 this.paintTileText(ts, t, g, mv, currentZoomLevel, t); 715 726 } 716 727 float fadeBackground = SlippyMapPreferences.getFadeBackground(); … … 721 732 // drawn pixels, zoom in... getting too pixelated 722 733 if (lastImageScale > 3 && zoomIncreaseAllowed()) { 723 if (SlippyMapPreferences.getAutozoom()) { 724 this.debug("autozoom increase: scale: " + lastImageScale); 734 if (autoZoomEnabled()) { 735 if (debug) 736 out("autozoom increase: scale: " + lastImageScale); 725 737 increaseZoomLevel(); 726 738 } … … 729 741 // of a drawn pixels, zoom out. 730 742 } else if ((lastImageScale < 0.45) && (lastImageScale > 0) && zoomDecreaseAllowed()) { 731 if (SlippyMapPreferences.getAutozoom()) { 732 this.debug("autozoom decrease: scale: " + lastImageScale); 743 if (autoZoomEnabled()) { 744 if (debug) 745 out("autozoom decrease: scale: " + lastImageScale); 733 746 decreaseZoomLevel(); 734 747 } … … 744 757 * user right-clicks on the map. 745 758 */ 746 SlippyMapTile getTileForPixelpos(int px, int py) { 759 Tile getTileForPixelpos(int px, int py) { 760 if (debug) 761 out("getTileForPixelpos("+px+", "+py+")"); 747 762 MapView mv = Main.map.mapView; 748 763 Point clicked = new Point(px, py); 749 764 LatLon topLeft = mv.getLatLon(0, 0); 750 765 LatLon botRight = mv.getLatLon(mv.getWidth(), mv.getHeight()); 751 TileSet ts = new TileSet(topLeft, botRight, currentZoomLevel);752 766 int z = currentZoomLevel; 753 767 TileSet ts = new TileSet(topLeft, botRight, z); 768 769 ts.loadAllTiles(); // make sure there are tile objects for all tiles 754 770 Tile clickedTile = null; 755 771 Point p1 = null, p2 = null; 756 772 for (Tile t1 : ts.allTiles()) { 757 Tile t2 = new Tile(t1.x+1, t1.y+1); 758 p1 = t1.pixelPos(z); 759 p2 = t2.pixelPos(z); 760 Rectangle r = new Rectangle(p1,new Dimension(p2.x, p2.y)); 773 Tile t2 = getOrCreateTile(t1.getXtile()+1, t1.getYtile()+1, z); 774 Rectangle r = new Rectangle(pixelPos(t1)); 775 r.add(pixelPos(t2)); 776 if (debug) 777 out("r: " + r + " clicked: " + clicked); 761 778 if (!r.contains(clicked)) 762 779 continue; … … 766 783 if (clickedTile == null) 767 784 return null; 768 System.out.println("clicked on tile: " + clickedTile. x+ " " + clickedTile.y+785 System.out.println("clicked on tile: " + clickedTile.getXtile() + " " + clickedTile.getYtile() + 769 786 " scale: " + lastImageScale + " currentZoomLevel: " + currentZoomLevel); 770 SlippyMapTile tile = getOrCreateTile(clickedTile.x, clickedTile.y, currentZoomLevel); 771 checkTileStorage(); 772 return tile; 787 return clickedTile; 773 788 } 774 789 … … 833 848 } 834 849 835 private SlippyMapTile imgToTile(Image img) {836 // we use the enumeration to avoid ConcurrentUpdateExceptions837 // with other users of the tileStorage838 Enumeration<SlippyMapTile> e = tileStorage.elements();839 while (e.hasMoreElements()) {840 SlippyMapTile t = e.nextElement();841 if (t.getImageNoTimestamp() != img) {842 continue;843 }844 return t;845 }846 return null;847 }848 849 850 private static int nr_loaded = 0; 850 851 private static int at_zoom = -1; 851 852 public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height) {853 boolean error = (infoflags & ERROR) != 0;854 boolean done = ((infoflags & (ERROR | FRAMEBITS | ALLBITS)) != 0);855 boolean success = ((infoflags & (ALLBITS)) != 0);856 SlippyMapTile imageTile = imgToTile(img);857 if (success || error) {858 this.debug("tile done loading: " + imageTile);859 markDone(img);860 }861 if (imageTile == null) {862 System.err.println("no tile for image");863 return false;864 }865 866 if ((infoflags & ERROR) != 0) {867 String url; // = "unknown";868 url = imageTile.getImageURL().toString();869 System.err.println("imageUpdate(" + img + ") error " + url + ")");870 }871 if (((infoflags & ALLBITS) != 0)) {872 int z = imageTile.getZoom();873 if (z == at_zoom) {874 nr_loaded++;875 } else {876 //System.out.println("downloaded " + nr_loaded + " at: " + at_zoom + " now going to " + z +877 // " class: " + img.getClass());878 nr_loaded = 0;879 at_zoom = z;880 }881 }882 if ((infoflags & SOMEBITS) != 0) {883 // if (y%100 == 0)884 //System.out.println("imageUpdate("+img+") SOMEBITS ("+x+","+y+")");885 }886 // Repaint immediately if we are done, otherwise batch up887 // repaint requests every 100 milliseconds888 needRedraw = true;889 Main.map.repaint(done ? 0 : 100);890 return !done;891 }892 852 893 853 /* … … 904 864 // TODO move this code to SlippyMapPreferences class. 905 865 if (!key.equals(SlippyMapPreferences.PREFERENCE_FADE_BACKGROUND)) { 906 clearTileStorage(); 907 } 866 autoZoomPopup.setSelected(SlippyMapPreferences.getAutozoom()); 867 } 868 redraw(); 908 869 } 909 870 } -
applications/editors/josm/plugins/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapPreferences.java
r17433 r18354 19 19 public static final String PREFERENCE_MIN_ZOOM_LVL = PREFERENCE_PREFIX + ".min_zoom_lvl"; 20 20 public static final String PREFERENCE_MAX_ZOOM_LVL = PREFERENCE_PREFIX + ".max_zoom_lvl"; 21 public static final String PREFERENCE_LAST_ZOOM = PREFERENCE_PREFIX + ".last_zoom_lvl"; 21 22 public static final String PREFERENCE_FADE_BACKGROUND = PREFERENCE_PREFIX + ".fade_background"; 22 23 public static final String PREFERENCE_DRAW_DEBUG = PREFERENCE_PREFIX + ".draw_debug"; … … 60 61 } 61 62 63 public static void setLastZoom(int zoom) { 64 Main.pref.put(SlippyMapPreferences.PREFERENCE_LAST_ZOOM, ""+zoom); 65 } 66 public static int getLastZoom() { 67 int ret = -1; 68 String pref = Main.pref.get(SlippyMapPreferences.PREFERENCE_LAST_ZOOM); 69 try { 70 ret = Integer.parseInt(pref); 71 } catch (NumberFormatException e) { 72 } 73 return ret; 74 } 75 62 76 public static boolean getDrawDebug() 63 77 { -
applications/editors/josm/plugins/slippymap/src/org/openstreetmap/josm/plugins/slippymap/SlippyMapTile.java
r16460 r18354 1 package org.openstreetmap.josm.plugins.slippymap;2 3 import static org.openstreetmap.josm.tools.I18n.tr;4 5 import java.awt.Image;6 import java.awt.Toolkit;7 import java.awt.image.ImageObserver;8 import java.io.BufferedReader;9 import java.io.InputStreamReader;10 import java.net.MalformedURLException;11 import java.net.URL;12 import java.net.URLConnection;13 14 /**15 * Class that contains information about one single slippy map tile.16 *17 * @author Frederik Ramm <frederik@remote.org>18 * @author LuVar <lubomir.varga@freemap.sk>19 * @author Dave Hansen <dave@sr71.net>20 *21 */22 public class SlippyMapTile implements ImageObserver23 {24 private Image tileImage;25 private long timestamp;26 27 private int x;28 private int y;29 private int z;30 // Setting this to pending is a bit of a hack31 // as it requires knowledge that SlippyMapLayer32 // will put this tile in a queue before it calls33 // loadImage(). But, this gives the best message34 // to the user.35 private String status = "pending download";36 37 private boolean imageDownloaded = false;38 39 private String metadata;40 41 public SlippyMapTile(int x, int y, int z)42 {43 this.x = x;44 this.y = y;45 this.z = z;46 timestamp = System.currentTimeMillis();47 }48 49 public String getStatus()50 {51 return status;52 }53 public String getMetadata()54 {55 return metadata;56 }57 58 public URL getImageURL()59 {60 try61 {62 return new URL(SlippyMapPreferences.getMapUrl() + "/" + z + "/" + x + "/" + y + ".png");63 }64 catch (MalformedURLException mfu)65 {66 mfu.printStackTrace();67 }68 return null;69 }70 71 public Image loadImage()72 {73 // We do not update the timestamp in this function74 // The download code prioritizes the most recent75 // downloads and will download the oldest tiles last.76 URL imageURL = this.getImageURL();77 tileImage = Toolkit.getDefaultToolkit().createImage(imageURL);78 Toolkit.getDefaultToolkit().prepareImage(tileImage, -1, -1, this);79 Toolkit.getDefaultToolkit().sync();80 status = "being downloaded";81 return tileImage;82 }83 public String toString()84 {85 return "SlippyMapTile{zoom=" + z + " (" + x + "," + y + ") '" + status + "'}";86 }87 synchronized public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height)88 {89 if ((infoflags & ALLBITS) != 0) {90 imageDownloaded = true;91 status = "downloaded";92 if (tileImage == null) {93 System.out.println("completed null'd image: " + this.toString());94 }95 tileImage = img;96 return false;97 }98 return true;99 }100 101 public Image getImageNoTimestamp() {102 return tileImage;103 }104 105 public Image getImage()106 {107 timestamp = System.currentTimeMillis();108 return tileImage;109 }110 111 public int getZoom() {112 return z;113 }114 115 synchronized public void dropImage()116 {117 if(tileImage != null) {118 tileImage.flush();119 status = "dropped";120 }121 tileImage = null;122 // This should work in theory but doesn't seem to actually123 // reduce the X server memory usage124 //tileImage.flush();125 imageDownloaded = false;126 }127 128 public boolean isDownloaded() {129 return imageDownloaded;130 }131 132 public void loadMetadata()133 {134 try135 {136 URL dev = new URL(137 "http://tah.openstreetmap.org/Tiles/info_short.php?x=" + x138 + "&y=" + y + "&z=" + z + "/layer=tile");139 URLConnection devc = dev.openConnection();140 BufferedReader in = new BufferedReader(new InputStreamReader(devc141 .getInputStream()));142 metadata = tr(in.readLine());143 }144 catch (Exception ex)145 {146 metadata = tr("error loading metadata" + ex.toString());147 }148 149 }150 151 public void requestUpdate()152 {153 if (z != 12) {154 metadata = tr("error requesting update: not zoom-level 12");155 }156 try157 {158 URL dev = new URL("http://tah.openstreetmap.org/Request/create/?x=" + x159 + "&y=" + y + "&priority=1&src=slippymap_plugin");160 URLConnection devc = dev.openConnection();161 BufferedReader in = new BufferedReader(new InputStreamReader(devc162 .getInputStream()));163 timestamp = System.currentTimeMillis();164 metadata = tr("requested: {0}", tr(in.readLine()));165 }166 catch (Exception ex)167 {168 metadata = tr("error requesting update");169 }170 }171 172 public long access_time()173 {174 return timestamp;175 }176 177 public boolean equals(Object o)178 {179 if (!(o instanceof SlippyMapTile))180 return false;181 SlippyMapTile other = (SlippyMapTile) o;182 return (this.x == other.x && this.y == other.y && this.z == other.z);183 }184 SlippyMapKey getKey()185 {186 return new SlippyMapKey(x, y, z);187 }188 }
Note:
See TracChangeset
for help on using the changeset viewer.