Ticket #11487: 11487.patch
File 11487.patch, 7.2 KB (added by , 19 months ago) |
---|
-
src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java
Subject: [PATCH] #11487: Try to improve render performance --- IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 diff --git a/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java b/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java
a b 11 11 import java.awt.Composite; 12 12 import java.awt.Graphics2D; 13 13 import java.awt.GridBagLayout; 14 import java.awt.Point; 14 15 import java.awt.Rectangle; 15 16 import java.awt.TexturePaint; 16 17 import java.awt.datatransfer.Transferable; 17 18 import java.awt.datatransfer.UnsupportedFlavorException; 18 19 import java.awt.event.ActionEvent; 20 import java.awt.geom.AffineTransform; 19 21 import java.awt.geom.Area; 20 22 import java.awt.geom.Path2D; 21 23 import java.awt.geom.Rectangle2D; … … 49 51 import javax.swing.JPanel; 50 52 import javax.swing.JScrollPane; 51 53 54 import org.apache.commons.jcs3.access.CacheAccess; 55 import org.openstreetmap.gui.jmapviewer.OsmMercator; 56 import org.openstreetmap.gui.jmapviewer.TileXY; 52 57 import org.openstreetmap.josm.actions.AutoScaleAction; 53 58 import org.openstreetmap.josm.actions.ExpertToggleAction; 54 59 import org.openstreetmap.josm.actions.RenameLayerAction; … … 58 63 import org.openstreetmap.josm.data.Data; 59 64 import org.openstreetmap.josm.data.ProjectionBounds; 60 65 import org.openstreetmap.josm.data.UndoRedoHandler; 66 import org.openstreetmap.josm.data.cache.JCSCacheManager; 61 67 import org.openstreetmap.josm.data.conflict.Conflict; 62 68 import org.openstreetmap.josm.data.conflict.ConflictCollection; 63 69 import org.openstreetmap.josm.data.coor.EastNorth; … … 155 161 private boolean requiresUploadToServer; 156 162 /** Flag used to know if the layer is being uploaded */ 157 163 private final AtomicBoolean isUploadInProgress = new AtomicBoolean(false); 164 /** A cache used for painting */ 165 private final CacheAccess<String, BufferedImage> cache = JCSCacheManager.getCache("osmDataLayer:" + this); 166 /** The last zoom that was painted (used to invalidate {@link #cache}) */ 167 private int lastZoom; 168 /** The map paint index that was painted (used to invalidate {@link #cache}) */ 169 private int lastDataIdx; 158 170 159 171 /** 160 172 * List of validation errors in this layer. … … 540 552 AbstractMapRenderer painter = MapRendererFactory.getInstance().createActiveRenderer(g, mv, inactive); 541 553 painter.enableSlowOperations(mv.getMapMover() == null || !mv.getMapMover().movementInProgress() 542 554 || !PROPERTY_HIDE_LABELS_WHILE_DRAGGING.get()); 543 painter.render(data, virtual, box); 555 final double scale = mv.getScale(); 556 final int tileSize = 256; 557 // We might have to fall back to the old method if user is reprojecting 558 final double topResolution = 2 * Math.PI * OsmMercator.EARTH_RADIUS / tileSize; 559 // Use to invalidate cache in the future 560 int zoom; 561 for (zoom = 0; zoom < 30; zoom++) {// Use something like imagery.{generic|tms}.max_zoom_lvl (20 is a bit too low for our needs) 562 if (scale > topResolution / (Math.pow(2, zoom))) { 563 zoom = zoom > 0 ? zoom - 1 : zoom; 564 break; 565 } 566 } 567 if (zoom != lastZoom || data.getMappaintCacheIndex() != lastDataIdx 568 || !data.selectionEmpty() 569 || !data.getHighlightedVirtualNodes().isEmpty() 570 || !data.getHighlightedWaySegments().isEmpty()) { 571 cache.clear(); 572 lastZoom = zoom; 573 lastDataIdx = data.getMappaintCacheIndex(); 574 Logging.trace("OsmDataLayer {0} paint cache cleared", this.getName()); 575 } 576 final List<TileXY> toRender = new ArrayList<>(); 577 final TileXY upperRight = latLonToTile(box.getMaxLat(), box.getMaxLon(), zoom); 578 final TileXY lowerLeft = latLonToTile(box.getMinLat(), box.getMinLon(), zoom); 579 for (int x = lowerLeft.getXIndex(); x <= upperRight.getXIndex(); x++) { 580 for (int y = upperRight.getYIndex(); y <= lowerLeft.getYIndex(); y++) { 581 toRender.add(new TileXY(x, y)); 582 } 583 } 584 585 for (TileXY tile : toRender) { 586 final int actualZoom = zoom; 587 final double lat = yToLat(tile.getYIndex(), zoom); 588 final double lon = xToLon(tile.getXIndex(), zoom); 589 final Point point = mv.getPoint(new LatLon(lat, lon)); 590 BufferedImage tileImage = cache.get(tile.toString(), 591 () -> generateTile(data, mv, point, inactive, virtual, tile, tileSize, actualZoom)); 592 g.drawImage(tileImage, point.x, point.y, tileSize, tileSize, null, null); 593 } 594 //painter.render(data, virtual, box); 544 595 MainApplication.getMap().conflictDialog.paintConflicts(g, mv); 545 596 } 546 597 598 private static BufferedImage generateTile(DataSet data, MapView mv, Point point, boolean inactive, boolean virtual, TileXY tile, 599 int tileSize, int zoom) { 600 BufferedImage bufferedImage = new BufferedImage(tileSize, tileSize, BufferedImage.TYPE_4BYTE_ABGR); 601 Graphics2D g2d = bufferedImage.createGraphics(); 602 g2d.setTransform(AffineTransform.getTranslateInstance(-point.x, -point.y)); 603 try { 604 AbstractMapRenderer tilePainter = MapRendererFactory.getInstance().createActiveRenderer(g2d, mv, inactive); 605 tilePainter.render(data, virtual, tileToBounds(tile, zoom)); 606 } finally { 607 g2d.dispose(); 608 } 609 return bufferedImage; 610 } 611 612 private static Bounds tileToBounds(TileXY tile, int zoom) { 613 return new Bounds(yToLat(tile.getYIndex() + 1, zoom), xToLon(tile.getXIndex(), zoom), 614 yToLat(tile.getYIndex(), zoom), xToLon(tile.getXIndex() + 1, zoom)); 615 } 616 617 private static double xToLon(int x, int zoom) { 618 return (x / Math.pow(2, zoom)) * 360 - 180; 619 } 620 621 private static double yToLat(int y, int zoom) { 622 double t = Math.PI - (2 * Math.PI * y) / (Math.pow(2, zoom)); 623 return 180 / Math.PI * Math.atan((Math.exp(t) - Math.exp(-t)) / 2); 624 } 625 626 private static TileXY latLonToTile(double lat, double lon, int zoom) { 627 int xCoord = (int) Math.floor(Math.pow(2, zoom) * (180 + lon) / 360); 628 int yCoord = (int) Math.floor(Math.pow(2, zoom) * (1 - Math.log(Math.tan(Math.toRadians(lat)) + 1 / Math.cos(Math.toRadians(lat))) / Math.PI) / 2); 629 return new TileXY(xCoord, yCoord); 630 } 631 547 632 @Override public String getToolTipText() { 548 633 DataCountVisitor counter = new DataCountVisitor(); 549 634 for (final OsmPrimitive osm : data.allPrimitives()) { … … 1165 1250 1166 1251 @Override 1167 1252 public void processDatasetEvent(AbstractDatasetChangedEvent event) { 1253 cache.clear(); 1168 1254 invalidate(); 1169 1255 setRequiresSaveToFile(true); 1170 1256 setRequiresUploadToServer(event.getDataset().requiresUploadToServer()); … … 1172 1258 1173 1259 @Override 1174 1260 public void selectionChanged(SelectionChangeEvent event) { 1261 cache.clear(); 1175 1262 invalidate(); 1176 1263 } 1177 1264