Ignore:
Timestamp:
2016-08-16T09:12:51+02:00 (8 years ago)
Author:
Don-vip
Message:

fix #13222 - Use visitor pattern for painting tiles (patch by michael2402) - gsoc-core

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java

    r10809 r10820  
    3535import java.util.Map;
    3636import java.util.Map.Entry;
     37import java.util.Objects;
    3738import java.util.Set;
    3839import java.util.concurrent.ConcurrentSkipListSet;
    3940import java.util.concurrent.atomic.AtomicInteger;
     41import java.util.function.Consumer;
     42import java.util.function.Function;
     43import java.util.stream.Collectors;
     44import java.util.stream.IntStream;
    4045import java.util.stream.Stream;
    4146
     
    958963    }
    959964
     965    private Tile getOrCreateTile(TilePosition tilePosition) {
     966        return getOrCreateTile(tilePosition.getX(), tilePosition.getY(), tilePosition.getZoom());
     967    }
     968
    960969    private Tile getOrCreateTile(int x, int y, int zoom) {
    961970        Tile tile = getTile(x, y, zoom);
     
    969978        }
    970979        return tile;
     980    }
     981
     982    private Tile getTile(TilePosition tilePosition) {
     983        return getTile(tilePosition.getX(), tilePosition.getY(), tilePosition.getZoom());
    971984    }
    972985
     
    11251138            ((Graphics2D) g).fill(target);
    11261139        }
     1140    }
     1141
     1142    private List<Tile> paintTileImages(Graphics g, TileSet ts) {
     1143        Object paintMutex = new Object();
     1144        List<TilePosition> missed = Collections.synchronizedList(new ArrayList<>());
     1145        ts.visitTiles(tile -> {
     1146            Image img = getLoadedTileImage(tile);
     1147            if (img == null) {
     1148                missed.add(new TilePosition(tile));
     1149            }
     1150            img = applyImageProcessors((BufferedImage) img);
     1151            Rectangle2D sourceRect = coordinateConverter.getRectangleForTile(tile);
     1152            synchronized (paintMutex) {
     1153                //cannot paint in parallel
     1154                drawImageInside(g, img, sourceRect, null);
     1155            }
     1156        }, missed::add);
     1157
     1158        return missed.stream().map(this::getOrCreateTile).collect(Collectors.toList());
    11271159    }
    11281160
     
    11381170    private List<Tile> paintTileImages(Graphics g, TileSet ts, int zoom, Tile border) {
    11391171        if (zoom <= 0) return Collections.emptyList();
    1140         Rectangle2D borderRect = null;
    1141         if (border != null) {
    1142             borderRect = coordinateConverter.getRectangleForTile(border);
    1143         }
     1172        Rectangle2D borderRect = coordinateConverter.getRectangleForTile(border);
    11441173        List<Tile> missedTiles = new LinkedList<>();
    11451174        // The callers of this code *require* that we return any tiles
     
    12951324            return xSpan * ySpan;
    12961325        }
     1326
     1327        /**
     1328         * Gets a stream of all tile positions in this set
     1329         * @return A stream of all positions
     1330         */
     1331        public Stream<TilePosition> tilePositions() {
     1332            if (zoom == 0) {
     1333                return Stream.empty();
     1334            } else {
     1335                return IntStream.rangeClosed(minX, maxX).mapToObj(
     1336                        x -> IntStream.rangeClosed(minY, maxY).mapToObj(y -> new TilePosition(x, y, zoom))
     1337                        ).flatMap(Function.identity());
     1338            }
     1339        }
     1340    }
     1341
     1342    /**
     1343     * The position of a single tile.
     1344     * @author Michael Zangl
     1345     * @since xxx
     1346     */
     1347    private static class TilePosition {
     1348        private final int x;
     1349        private final int y;
     1350        private final int zoom;
     1351        TilePosition(int x, int y, int zoom) {
     1352            super();
     1353            this.x = x;
     1354            this.y = y;
     1355            this.zoom = zoom;
     1356        }
     1357
     1358        TilePosition(Tile tile) {
     1359            this(tile.getXtile(), tile.getYtile(), tile.getZoom());
     1360        }
     1361
     1362        /**
     1363         * @return the x position
     1364         */
     1365        public int getX() {
     1366            return x;
     1367        }
     1368
     1369        /**
     1370         * @return the y position
     1371         */
     1372        public int getY() {
     1373            return y;
     1374        }
     1375
     1376        /**
     1377         * @return the zoom
     1378         */
     1379        public int getZoom() {
     1380            return zoom;
     1381        }
     1382
     1383        @Override
     1384        public String toString() {
     1385            return "TilePosition [x=" + x + ", y=" + y + ", zoom=" + zoom + "]";
     1386        }
    12971387    }
    12981388
     
    13081398         */
    13091399        private TileSet() {
    1310             return;
     1400            // default
    13111401        }
    13121402
     
    13381428        }
    13391429
    1340         /*
    1341          * Get all tiles represented by this TileSet that are
    1342          * already in the tileCache.
     1430        /**
     1431         * Get all tiles represented by this TileSet that are already in the tileCache.
    13431432         */
    13441433        private List<Tile> allExistingTiles() {
    1345             return this.findAllTiles(false);
     1434            return allTiles(p -> getTile(p));
    13461435        }
    13471436
    13481437        private List<Tile> allTilesCreate() {
    1349             return this.findAllTiles(true);
    1350         }
    1351 
    1352         private List<Tile> findAllTiles(boolean create) {
    1353             // Tileset is either empty or too large
    1354             if (zoom == 0 || this.insane())
    1355                 return Collections.emptyList();
    1356             List<Tile> ret = new ArrayList<>();
    1357             for (int x = minX; x <= maxX; x++) {
    1358                 for (int y = minY; y <= maxY; y++) {
    1359                     Tile t;
    1360                     if (create) {
    1361                         t = getOrCreateTile(x, y, zoom);
    1362                     } else {
    1363                         t = getTile(x, y, zoom);
    1364                     }
    1365                     if (t != null) {
    1366                         ret.add(t);
    1367                     }
    1368                 }
    1369             }
    1370             return ret;
     1438            return allTiles(p -> getOrCreateTile(p));
     1439        }
     1440
     1441        private List<Tile> allTiles(Function<TilePosition, Tile> mapper) {
     1442            return tilePositions().map(mapper).filter(Objects::nonNull).collect(Collectors.toList());
     1443        }
     1444
     1445        @Override
     1446        public Stream<TilePosition> tilePositions() {
     1447            if (this.insane()) {
     1448                // Tileset is either empty or too large
     1449                return Stream.empty();
     1450            } else {
     1451                return super.tilePositions();
     1452            }
    13711453        }
    13721454
    13731455        private List<Tile> allLoadedTiles() {
    1374             List<Tile> ret = new ArrayList<>();
    1375             for (Tile t : this.allExistingTiles()) {
    1376                 if (t.isLoaded())
    1377                     ret.add(t);
    1378             }
    1379             return ret;
     1456            return allExistingTiles().stream().filter(Tile::isLoaded).collect(Collectors.toList());
    13801457        }
    13811458
     
    13861463            final int centerX = (int) Math.ceil((minX + maxX) / 2d);
    13871464            final int centerY = (int) Math.ceil((minY + maxY) / 2d);
    1388             return new Comparator<Tile>() {
    1389                 private int getDistance(Tile t) {
    1390                     return Math.abs(t.getXtile() - centerX) + Math.abs(t.getYtile() - centerY);
    1391                 }
    1392 
    1393                 @Override
    1394                 public int compare(Tile o1, Tile o2) {
    1395                     int distance1 = getDistance(o1);
    1396                     int distance2 = getDistance(o2);
    1397                     return Integer.compare(distance1, distance2);
    1398                 }
    1399             };
     1465            return Comparator.comparingInt(t -> Math.abs(t.getXtile() - centerX) + Math.abs(t.getYtile() - centerY));
    14001466        }
    14011467
     
    14171483                    tileLoader.createTileLoaderJob(t).submit(force);
    14181484                }
     1485            }
     1486        }
     1487
     1488        /**
     1489         * Call the given paint method for all tiles in this tile set.
     1490         * <p>
     1491         * Uses a parallel stream.
     1492         * @param visitor A visitor to call for each tile.
     1493         * @param missed a consumer to call for each missed tile.
     1494         */
     1495        public void visitTiles(Consumer<Tile> visitor, Consumer<TilePosition> missed) {
     1496            tilePositions().parallel().forEach(tp -> visitTilePosition(visitor, tp, missed));
     1497        }
     1498
     1499        private void visitTilePosition(Consumer<Tile> visitor, TilePosition tp, Consumer<TilePosition> missed) {
     1500            Tile tile = getTile(tp);
     1501            if (tile == null) {
     1502                missed.accept(tp);
     1503            } else {
     1504                visitor.accept(tile);
    14191505            }
    14201506        }
     
    15921678        g.setColor(Color.DARK_GRAY);
    15931679
    1594         List<Tile> missedTiles = this.paintTileImages(g, ts, displayZoomLevel, null);
     1680        List<Tile> missedTiles = this.paintTileImages(g, ts);
    15951681        int[] otherZooms = {-1, 1, -2, 2, -3, -4, -5};
    15961682        for (int zoomOffset : otherZooms) {
Note: See TracChangeset for help on using the changeset viewer.