Ignore:
Timestamp:
2024-03-05T21:53:45+01:00 (10 months ago)
Author:
taylor.smock
Message:

PMTiles: Add boundary outline and documentation

Location:
applications/editors/josm/plugins/pmtiles/src/main/java/org/openstreetmap/josm/plugins/pmtiles
Files:
3 added
17 edited

Legend:

Unmodified
Added
Removed
  • applications/editors/josm/plugins/pmtiles/src/main/java/org/openstreetmap/josm/plugins/pmtiles/actions/downloadtasks/DownloadPMTilesTask.java

    r36144 r36219  
    2828 */
    2929public class DownloadPMTilesTask implements DownloadTask {
     30    /** Zoom to the PMTiles bounds after download */
    3031    private boolean zoomAfterDownload;
     32    /** Cancel adding the layer if this is true */
    3133    private boolean cancel;
     34    /** The URL for the tiles */
    3235    private String url;
     36    /** Any recoverable errors from reading the PMTiles */
    3337    private final List<Object> errorObjects = new ArrayList<>();
     38    /** The bounds for the layer */
    3439    private Bounds bounds;
    3540
     41    /**
     42     * Add the appropriate layer to JOSM
     43     */
    3644    private void addLayer() {
    3745        if (this.cancel) {
  • applications/editors/josm/plugins/pmtiles/src/main/java/org/openstreetmap/josm/plugins/pmtiles/data/imagery/PMTilesImageryInfo.java

    r36112 r36219  
    66import java.util.Objects;
    77
    8 import jakarta.json.JsonObject;
    98import org.openstreetmap.josm.data.imagery.ImageryInfo;
    109import org.openstreetmap.josm.plugins.pmtiles.lib.Header;
    1110import org.openstreetmap.josm.plugins.pmtiles.lib.PMTiles;
     11
     12import jakarta.json.JsonObject;
    1213
    1314/**
     
    1516 */
    1617public class PMTilesImageryInfo extends ImageryInfo {
     18    /** The PMTiles header for this info */
    1719    private final Header header;
     20    /** The metadata for this info */
    1821    private final JsonObject meta;
    1922
  • applications/editors/josm/plugins/pmtiles/src/main/java/org/openstreetmap/josm/plugins/pmtiles/gui/layers/PMTileJob.java

    r36145 r36219  
    3030 */
    3131class PMTileJob extends JCSCachedTileLoaderJob<String, CacheEntry> implements TileJob, ICachedLoaderListener {
     32    /** The tile we are fetching */
    3233    private final Tile tile;
     34    /** The tiles information */
    3335    private final Header header;
     36    /** The directory cache */
    3437    private final DirectoryCache directoryCache;
    3538
     39    /**
     40     * Create a new job
     41     * @param cache cache instance that we will work on
     42     * @param options options of the request
     43     * @param downloadJobExecutor that will be executing the jobs
     44     * @param header The header for the tiles
     45     * @param tile The tile to fetch
     46     * @param directoryCache The cache of directories
     47     */
    3648    PMTileJob(ICacheAccess<String, CacheEntry> cache,
    3749              TileJobOptions options,
  • applications/editors/josm/plugins/pmtiles/src/main/java/org/openstreetmap/josm/plugins/pmtiles/gui/layers/PMTilesImageLayer.java

    r36125 r36219  
    22package org.openstreetmap.josm.plugins.pmtiles.gui.layers;
    33
     4import java.awt.Graphics2D;
     5import java.awt.GridBagConstraints;
    46import java.util.Collection;
    57import java.util.Collections;
    68
     9import javax.swing.JLabel;
     10import javax.swing.JPanel;
     11
    712import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader;
     13import org.openstreetmap.josm.data.Bounds;
    814import org.openstreetmap.josm.data.imagery.vectortile.mapbox.MVTFile;
    915import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
     16import org.openstreetmap.josm.gui.MapView;
    1017import org.openstreetmap.josm.gui.layer.AbstractCachedTileSourceLayer;
    1118import org.openstreetmap.josm.plugins.pmtiles.data.imagery.PMTilesImageryInfo;
     19import org.openstreetmap.josm.tools.GBC;
    1220
    1321/**
     
    7280
    7381    @Override
     82    public Object getInfoComponent() {
     83        JPanel panel = (JPanel) super.getInfoComponent();
     84        String[][] content = getInfoContent();
     85        for (String[] entry: content) {
     86            panel.add(new JLabel(entry[0] + ':'), GBC.std());
     87            panel.add(GBC.glue(5, 0), GBC.std());
     88            panel.add(createTextField(entry[1]), GBC.eol().fill(GridBagConstraints.HORIZONTAL));
     89        }
     90        return panel;
     91    }
     92
     93    @Override
     94    public void paint(Graphics2D g, MapView mv, Bounds box) {
     95        super.paint(g, mv, box);
     96        PMTilesLayer.super.paint(g, mv, box);
     97    }
     98
     99    @Override
    74100    public void visitBoundingBox(BoundingXYVisitor v) {
    75101        super.visitBoundingBox(v);
  • applications/editors/josm/plugins/pmtiles/src/main/java/org/openstreetmap/josm/plugins/pmtiles/gui/layers/PMTilesImageSource.java

    r36112 r36219  
    22package org.openstreetmap.josm.plugins.pmtiles.gui.layers;
    33
    4 import jakarta.json.JsonObject;
    54import org.openstreetmap.gui.jmapviewer.OsmMercator;
    65import org.openstreetmap.gui.jmapviewer.tilesources.AbstractTMSTileSource;
     
    87import org.openstreetmap.josm.plugins.pmtiles.lib.Header;
    98
     9import jakarta.json.JsonObject;
     10
    1011/**
    1112 * A source for images in PMTiles
    1213 */
    1314public class PMTilesImageSource extends AbstractTMSTileSource implements PMTilesTileSource {
     15    /** The metadata for this source */
    1416    private final JsonObject metadata;
     17    /** The PMTiles header */
    1518    private final Header header;
     19    /** The {@link OsmMercator} instance for the specified tile size */
    1620    private final OsmMercator osmMercator;
    1721
  • applications/editors/josm/plugins/pmtiles/src/main/java/org/openstreetmap/josm/plugins/pmtiles/gui/layers/PMTilesLayer.java

    r36125 r36219  
    44import static org.openstreetmap.josm.tools.Utils.getSystemProperty;
    55
     6import java.awt.BasicStroke;
     7import java.awt.Color;
     8import java.awt.Graphics2D;
     9import java.awt.Point;
     10
     11import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
     12import org.openstreetmap.josm.data.Bounds;
     13import org.openstreetmap.josm.data.coor.LatLon;
    614import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
     15import org.openstreetmap.josm.gui.MapView;
     16import org.openstreetmap.josm.gui.layer.MapViewPaintable;
    717import org.openstreetmap.josm.plugins.pmtiles.data.imagery.PMTilesImageryInfo;
    818import org.openstreetmap.josm.tools.TextUtils;
     
    1222 * A common interface for layers using PMTiles as a source
    1323 */
    14 interface PMTilesLayer {
     24interface PMTilesLayer extends MapViewPaintable {
    1525
    1626    /**
     
    5262
    5363    /**
     64     * Get info information
     65     * @return The information to add to the info panel
     66     */
     67    default String[][] getInfoContent() {
     68        final var info = getInfo();
     69        final var content = new String[3][];
     70        content[0] = new String[] {"Maximum zoom", String.valueOf(info.getMaxZoom())};
     71        content[1] = new String[] {"Minimum zoom", String.valueOf(info.getMinZoom())};
     72        content[2] = new String[] {"Bounds", info.getBounds().toBBox().toStringCSV(",")};
     73        return content;
     74    }
     75
     76    @Override
     77    default void paint(Graphics2D g, MapView mv, Bounds box) {
     78        final var info = getInfo();
     79        g.setStroke(new BasicStroke());
     80        g.setColor(Color.DARK_GRAY);
     81        if (info.getBounds().getShapes().isEmpty()) {
     82            final var lowerLeft = mv.getPoint(info.getBounds().getMin());
     83            final var upperRight = mv.getPoint(info.getBounds().getMax());
     84            g.drawRect(lowerLeft.x, upperRight.y, upperRight.x - lowerLeft.x, lowerLeft.y - upperRight.y);
     85        } else {
     86            for (var shape : info.getBounds().getShapes()) {
     87                Point last = null;
     88                for (ICoordinate coord : shape.getPoints()) {
     89                    final var point = mv.getPoint(new LatLon(coord.getLat(), coord.getLon()));
     90                    if (last != null) {
     91                        g.drawLine(last.x, last.y, point.x, point.y);
     92                    }
     93                    last = point;
     94                }
     95            }
     96        }
     97    }
     98
     99    /**
    54100     * Visits the content bounds of this layer. The behavior of this method depends on the layer,
    55101     * but each implementation should attempt to cover the relevant content of the layer in this method.
  • applications/editors/josm/plugins/pmtiles/src/main/java/org/openstreetmap/josm/plugins/pmtiles/gui/layers/PMTilesLoader.java

    r36123 r36219  
    2525 */
    2626public class PMTilesLoader implements TileLoader {
     27    /** The executor for fetching the tiles. */
    2728    private static final ThreadPoolExecutor EXECUTOR = TMSCachedTileLoader.getNewThreadPoolExecutor("pmtiles");
     29    /** The current jobs for the loader */
    2830    private final Collection<PMTileJob> jobs = new HashSet<>();
     31    /** The cache for downloaded tiles */
    2932    private final ICacheAccess<String, CacheEntry> cache;
     33    /** The options for the tile loader */
    3034    private final TileJobOptions options;
    31     private final TileLoaderListener listener;
     35    /** The PMTiles header */
    3236    private Header header;
     37    /** The cache of PMTiles directories */
    3338    private DirectoryCache directoryCache;
    3439
    3540    /**
    3641     * Create a new tile loader
    37      * @param listener The listener to notify
     42     * @param ignored The listener to notify
    3843     * @param cache The cache to use
    3944     * @param options The options to use
    4045     */
    41     public PMTilesLoader(TileLoaderListener listener, ICacheAccess<String, CacheEntry> cache,
     46    public PMTilesLoader(TileLoaderListener ignored, ICacheAccess<String, CacheEntry> cache,
    4247                         TileJobOptions options) {
    43         this.listener = listener;
    4448        this.cache = cache;
    4549        this.options = options;
     
    6468    }
    6569
     70    /**
     71     * Set the PMTiles info for this loader
     72     * @param info The info to use
     73     */
    6674    void setInfo(PMTilesImageryInfo info) {
    6775        this.header = info.header();
  • applications/editors/josm/plugins/pmtiles/src/main/java/org/openstreetmap/josm/plugins/pmtiles/gui/layers/PMTilesMVTLayer.java

    r36125 r36219  
    22package org.openstreetmap.josm.plugins.pmtiles.gui.layers;
    33
     4import java.awt.Graphics2D;
     5import java.awt.GridBagConstraints;
    46import java.util.Collection;
    57import java.util.Collections;
    68
     9import javax.swing.JLabel;
     10import javax.swing.JPanel;
     11
    712import org.openstreetmap.gui.jmapviewer.interfaces.TileLoader;
     13import org.openstreetmap.josm.data.Bounds;
    814import org.openstreetmap.josm.data.imagery.vectortile.mapbox.MVTFile;
    915import org.openstreetmap.josm.data.imagery.vectortile.mapbox.MapboxVectorTileSource;
    1016import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
     17import org.openstreetmap.josm.gui.MapView;
    1118import org.openstreetmap.josm.gui.layer.imagery.MVTLayer;
    1219import org.openstreetmap.josm.plugins.pmtiles.data.imagery.PMTilesImageryInfo;
     20import org.openstreetmap.josm.tools.GBC;
    1321
    1422/**
     
    7381
    7482    @Override
     83    public Object getInfoComponent() {
     84        JPanel panel = (JPanel) super.getInfoComponent();
     85        String[][] content = getInfoContent();
     86        for (String[] entry: content) {
     87            panel.add(new JLabel(entry[0] + ':'), GBC.std());
     88            panel.add(GBC.glue(5, 0), GBC.std());
     89            panel.add(createTextField(entry[1]), GBC.eol().fill(GridBagConstraints.HORIZONTAL));
     90        }
     91        return panel;
     92    }
     93
     94    @Override
     95    public void paint(Graphics2D g, MapView mv, Bounds box) {
     96        super.paint(g, mv, box);
     97        PMTilesLayer.super.paint(g, mv, box);
     98    }
     99
     100    @Override
    75101    public void visitBoundingBox(BoundingXYVisitor v) {
    76102        super.visitBoundingBox(v);
  • applications/editors/josm/plugins/pmtiles/src/main/java/org/openstreetmap/josm/plugins/pmtiles/gui/layers/PMTilesMVTTileSource.java

    r36112 r36219  
    11// License: GPL. For details, see LICENSE file.
    22package org.openstreetmap.josm.plugins.pmtiles.gui.layers;
    3 
    4 import jakarta.json.Json;
    5 import jakarta.json.JsonObject;
    6 import jakarta.json.JsonValue;
    73
    84import org.openstreetmap.gui.jmapviewer.OsmMercator;
     
    128import org.openstreetmap.josm.plugins.pmtiles.lib.Header;
    139
     10import jakarta.json.Json;
     11import jakarta.json.JsonObject;
     12import jakarta.json.JsonValue;
     13
    1414/**
    1515 * The tile source for MVT tiles in PMTiles
    1616 */
    1717public class PMTilesMVTTileSource extends MapboxVectorTileSource implements PMTilesTileSource {
     18    /** The metadata for the source */
    1819    private final JsonObject metadata;
     20    /** The PMTiles header information */
    1921    private final Header header;
     22    /** The style source for the vector tiles */
    2023    private final MapboxVectorStyle styleSource;
    2124
  • applications/editors/josm/plugins/pmtiles/src/main/java/org/openstreetmap/josm/plugins/pmtiles/lib/DirectoryCache.java

    r36112 r36219  
    1010 */
    1111public final class DirectoryCache implements Iterable<Directory> {
     12    /** The cached directories; [0] is the root, [1] is the last read directory */
    1213    private final Directory[] directories = new Directory[2];
    1314    /**
  • applications/editors/josm/plugins/pmtiles/src/main/java/org/openstreetmap/josm/plugins/pmtiles/lib/DirectoryEntry.java

    r36112 r36219  
    1212 */
    1313public record DirectoryEntry(long tileId, long offset, long length, long runLength) implements Serializable {
     14    /** Create a new entry with some basic validation */
    1415    public DirectoryEntry {
    1516        if (length <= 0) {
  • applications/editors/josm/plugins/pmtiles/src/main/java/org/openstreetmap/josm/plugins/pmtiles/lib/InternalCompression.java

    r36112 r36219  
    66 */
    77public enum InternalCompression {
     8    /** Unknown compression type */
    89    UNKNOWN,
     10    /** No compression */
    911    NONE,
     12    /** The GNU GZIP compression format */
    1013    GZIP,
     14    /** The Google Brotli compression format */
    1115    BROTLI,
     16    /** The Facebook zstandard compression format */
    1217    ZSTD
    1318}
  • applications/editors/josm/plugins/pmtiles/src/main/java/org/openstreetmap/josm/plugins/pmtiles/lib/PMTiles.java

    r36156 r36219  
    2727 */
    2828public final class PMTiles {
     29    /** An empty byte array for reuse */
    2930    private static final byte[] EMPTY_BYTE = new byte[0];
    3031
     32    /** The constructor for this class. Hidden, so we don't have instances of this class. */
    3133    private PMTiles() {/* hide the constructor */}
    3234
     
    180182        }
    181183        // We need to sum up the previous z levels
    182         var start = 0;
     184        long start = 0L;
    183185        var currentZoom = z;
    184186        // TODO profile this and the integral form (4^x)/(log(4)). Might not be as accurate though due to fp issues.
     
    186188        while (currentZoom > 0) {
    187189            currentZoom--;
    188             start += (1 << currentZoom) * (1 << currentZoom);
     190            start += (1L << currentZoom) * (1L << currentZoom);
    189191        }
    190192        // Now we need to calculate the coordinates inside the specified zoom level
    191193        long d = 0;
    192         var n = 1 << z;
     194        int n = 1 << z;
    193195        final var xy = new int[]{x, y};
    194         for (var s = n / 2; s > 0; s /= 2) {
    195             var rx = (xy[0] & s) > 0 ? 1 : 0;
    196             var ry = (xy[1] & s) > 0 ? 1 : 0;
    197             d += s * s * ((3 * rx) ^ ry);
     196        for (int s = n / 2; s > 0; s /= 2) {
     197            int rx = (xy[0] & s) > 0 ? 1 : 0;
     198            int ry = (xy[1] & s) > 0 ? 1 : 0;
     199            d += ((long) s) * s * ((3 * rx) ^ ry);
    198200            rotate(n, xy, rx, ry);
    199201        }
     
    210212        var start = 0;
    211213        while (true) {
    212             final var zTiles = Math.pow(4, z);
     214            final var zTiles = Math.toIntExact(Math.round(Math.pow(4, z)));
    213215            if (start + zTiles > hilbert) {
    214216                break;
     
    250252    }
    251253
     254    /**
     255     * Decompress a stream
     256     * @param compression The compression the stream uses
     257     * @param inputStream The stream to decompress
     258     * @return The decompressed stream
     259     * @throws IOException if one of the decompressors had an issue
     260     */
    252261    private static InputStream decompressInputStream(InternalCompression compression, InputStream inputStream) throws IOException {
    253262        return switch (compression) {
     
    260269    }
    261270
     271    /**
     272     * Get the stream for a given range and location
     273     * @param location The location of the data
     274     * @param start The start byte
     275     * @param length The end byte (exclusive)
     276     * @return The stream to read for the data
     277     * @throws IOException If there is something that prevents reading the stream from the given location.
     278     */
    262279    private static InputStream getInputStream(URI location, long start, long length) throws IOException {
    263280        if (Utils.isLocalUrl(location.toString())) {
  • applications/editors/josm/plugins/pmtiles/src/main/java/org/openstreetmap/josm/plugins/pmtiles/lib/TileType.java

    r36112 r36219  
    66 */
    77public enum TileType {
     8    /** Unknown tile type */
    89    UNKNOWN,
     10    /** Mapbox Vector Tiles */
    911    MVT,
     12    /** Portable Network Graphics */
    1013    PNG,
     14    /** Joint Photographic Experts Group */
    1115    JPEG,
     16    /** Google's WebP format */
    1217    WEBP,
     18    /** AV1 Image File Format */
    1319    AVIF
    1420}
  • applications/editors/josm/plugins/pmtiles/src/main/java/org/openstreetmap/josm/plugins/pmtiles/lib/internal/DirectoryParser.java

    r36112 r36219  
    1212 */
    1313public final class DirectoryParser {
     14    /** Hide the constructor */
    1415    private DirectoryParser() { /* Hide the constructor */ }
    1516
     17    /**
     18     * Parse a directory
     19     * @param inputStream The stream to read
     20     * @return The parsed directory
     21     * @throws IOException See {@link InputStream#read()}
     22     */
    1623    public static Directory parse(InputStream inputStream) throws IOException {
    1724        int lastByte = inputStream.read();
  • applications/editors/josm/plugins/pmtiles/src/main/java/org/openstreetmap/josm/plugins/pmtiles/lib/internal/HeaderParser.java

    r36112 r36219  
    1414 */
    1515public final class HeaderParser {
     16    /** Hide the constructor */
    1617    private HeaderParser() { /* Hide constructor */ }
    1718
     
    4748    }
    4849
     50    /**
     51     * Read the next degrees from a stream
     52     * @param inputStream The stream to read
     53     * @return The degrees read
     54     * @throws IOException See {@link InputStream#read()}
     55     */
    4956    private static double nextDegrees(InputStream inputStream) throws IOException {
    5057        return Util.nextInt(inputStream, 4) / 10_000_000d;
    5158    }
    5259
     60    /**
     61     * Get the next int
     62     * @param inputStream The stream to read
     63     * @return The next (unsigned) int
     64     * @throws IOException See {@link InputStream#read()}
     65     */
    5366    private static long nextInt(InputStream inputStream) throws IOException {
    5467        return Util.nextInt(inputStream, 8);
    5568    }
    5669
     70    /**
     71     * Get the next compression type
     72     * @param inputStream The stream to read
     73     * @return The compression type
     74     * @throws IOException See {@link InputStream#read()}
     75     */
    5776    private static InternalCompression nextCompressionType(InputStream inputStream) throws IOException {
    5877        final var type = inputStream.read();
     
    6786    }
    6887
     88    /**
     89     * Get the tile type for the next tile
     90     * @param inputStream The stream to read
     91     * @return The tile type
     92     * @throws IOException See {@link InputStream#read()}
     93     */
    6994    private static TileType nextTileType(InputStream inputStream) throws IOException {
    7095        final var type = inputStream.read();
  • applications/editors/josm/plugins/pmtiles/src/main/java/org/openstreetmap/josm/plugins/pmtiles/lib/internal/Util.java

    r36112 r36219  
    1111 */
    1212final class Util {
     13    /** The private constructor to avoid instantiation */
    1314    private Util() {/* Hide constructor */}
    1415
Note: See TracChangeset for help on using the changeset viewer.