kopia lustrzana https://github.com/JOSM/MapWithAI
Use max zoom from pmtiles and guess zoom for new MVT layers
Signed-off-by: Taylor Smock <tsmock@meta.com>pull/42/head v816
rodzic
9c3e9c0879
commit
4af7ac225f
|
@ -13,16 +13,21 @@ import java.net.MalformedURLException;
|
||||||
import java.net.SocketTimeoutException;
|
import java.net.SocketTimeoutException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.net.http.HttpRequest;
|
||||||
|
import java.net.http.HttpResponse;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
|
import org.openstreetmap.gui.jmapviewer.interfaces.TileSource;
|
||||||
import org.openstreetmap.josm.data.Bounds;
|
import org.openstreetmap.josm.data.Bounds;
|
||||||
|
@ -64,6 +69,7 @@ import org.openstreetmap.josm.plugins.mapwithai.tools.MapPaintUtils;
|
||||||
import org.openstreetmap.josm.plugins.pmtiles.data.imagery.PMTilesImageryInfo;
|
import org.openstreetmap.josm.plugins.pmtiles.data.imagery.PMTilesImageryInfo;
|
||||||
import org.openstreetmap.josm.plugins.pmtiles.gui.layers.PMTilesImageSource;
|
import org.openstreetmap.josm.plugins.pmtiles.gui.layers.PMTilesImageSource;
|
||||||
import org.openstreetmap.josm.plugins.pmtiles.lib.DirectoryCache;
|
import org.openstreetmap.josm.plugins.pmtiles.lib.DirectoryCache;
|
||||||
|
import org.openstreetmap.josm.plugins.pmtiles.lib.Header;
|
||||||
import org.openstreetmap.josm.plugins.pmtiles.lib.PMTiles;
|
import org.openstreetmap.josm.plugins.pmtiles.lib.PMTiles;
|
||||||
import org.openstreetmap.josm.spi.preferences.Config;
|
import org.openstreetmap.josm.spi.preferences.Config;
|
||||||
import org.openstreetmap.josm.tools.HttpClient;
|
import org.openstreetmap.josm.tools.HttpClient;
|
||||||
|
@ -115,13 +121,22 @@ public class BoundingBoxMapWithAIDownloader extends BoundingBoxDownloader {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a bbox to a tile
|
* Convert bounds to tiles
|
||||||
*
|
*
|
||||||
* @param bounds The bounds to convert
|
* @param zoom The zoom level to use
|
||||||
* @return The tile
|
* @param bounds The bounds to convert to tiles
|
||||||
|
* @return A stream of tiles for the bounds at the given zoom level
|
||||||
*/
|
*/
|
||||||
private static TileXYZ tileFromBBox(Bounds bounds) {
|
private static Stream<TileXYZ> tilesFromBBox(int zoom, Bounds bounds) {
|
||||||
return tileFromBBox(bounds.getMinLon(), bounds.getMinLat(), bounds.getMaxLon(), bounds.getMaxLat());
|
final var left = bounds.getMinLon();
|
||||||
|
final var bottom = bounds.getMinLat();
|
||||||
|
final var right = bounds.getMaxLon();
|
||||||
|
final var top = bounds.getMaxLat();
|
||||||
|
final var tile1 = tileFromLatLonZoom(left, bottom, zoom);
|
||||||
|
final var tile2 = tileFromLatLonZoom(right, top, zoom);
|
||||||
|
return IntStream.rangeClosed(tile1.x, tile2.x)
|
||||||
|
.mapToObj(x -> IntStream.rangeClosed(tile1.y, tile2.y).mapToObj(y -> new TileXYZ(x, y, zoom)))
|
||||||
|
.flatMap(stream -> stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -163,6 +178,20 @@ public class BoundingBoxMapWithAIDownloader extends BoundingBoxDownloader {
|
||||||
/ 2)));
|
/ 2)));
|
||||||
return new TileXYZ(xCoordinate, yCoordinate, zoom);
|
return new TileXYZ(xCoordinate, yCoordinate, zoom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extends a bounds object to contain this tile
|
||||||
|
*
|
||||||
|
* @param currentBounds The bounds to extend
|
||||||
|
*/
|
||||||
|
private void expandBounds(Bounds currentBounds) {
|
||||||
|
final var thisLeft = xToLongitude(this.x, this.z);
|
||||||
|
final var thisRight = xToLongitude(this.x + 1, this.z);
|
||||||
|
final var thisBottom = yToLatitude(this.y + 1, this.z);
|
||||||
|
final var thisTop = yToLatitude(this.y, this.z);
|
||||||
|
currentBounds.extend(thisBottom, thisLeft);
|
||||||
|
currentBounds.extend(thisTop, thisRight);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final String url;
|
private final String url;
|
||||||
|
@ -209,8 +238,7 @@ public class BoundingBoxMapWithAIDownloader extends BoundingBoxDownloader {
|
||||||
protected String getRequestForBbox(double lon1, double lat1, double lon2, double lat2) {
|
protected String getRequestForBbox(double lon1, double lat1, double lon2, double lat2) {
|
||||||
if (url.contains("{x}") && url.contains("{y}") && url.contains("{z}")) {
|
if (url.contains("{x}") && url.contains("{y}") && url.contains("{z}")) {
|
||||||
final var tile = TileXYZ.tileFromBBox(lon1, lat1, lon2, lat2);
|
final var tile = TileXYZ.tileFromBBox(lon1, lat1, lon2, lat2);
|
||||||
return url.replace("{x}", Long.toString(tile.x())).replace("{y}", Long.toString(tile.y())).replace("{z}",
|
return getRequestForTile(tile);
|
||||||
Long.toString(tile.z()));
|
|
||||||
}
|
}
|
||||||
return url.replace("{bbox}", Double.toString(lon1) + ',' + lat1 + ',' + lon2 + ',' + lat2)
|
return url.replace("{bbox}", Double.toString(lon1) + ',' + lat1 + ',' + lon2 + ',' + lat2)
|
||||||
.replace("{xmin}", Double.toString(lon1)).replace("{ymin}", Double.toString(lat1))
|
.replace("{xmin}", Double.toString(lon1)).replace("{ymin}", Double.toString(lat1))
|
||||||
|
@ -222,6 +250,11 @@ public class BoundingBoxMapWithAIDownloader extends BoundingBoxDownloader {
|
||||||
: "");
|
: "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getRequestForTile(TileXYZ tile) {
|
||||||
|
return url.replace("{x}", Long.toString(tile.x())).replace("{y}", Long.toString(tile.y())).replace("{z}",
|
||||||
|
Long.toString(tile.z()));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DataSet parseOsm(ProgressMonitor progressMonitor) throws OsmTransferException {
|
public DataSet parseOsm(ProgressMonitor progressMonitor) throws OsmTransferException {
|
||||||
long startTime = System.nanoTime();
|
long startTime = System.nanoTime();
|
||||||
|
@ -355,25 +388,77 @@ public class BoundingBoxMapWithAIDownloader extends BoundingBoxDownloader {
|
||||||
|
|
||||||
private DataSet readMvt(InputStream source, ProgressMonitor progressMonitor) throws IllegalDataException {
|
private DataSet readMvt(InputStream source, ProgressMonitor progressMonitor) throws IllegalDataException {
|
||||||
final DataSet ds;
|
final DataSet ds;
|
||||||
final var tileXYZ = TileXYZ.tileFromBBox(this.downloadArea);
|
|
||||||
final TileSource tileSource;
|
final TileSource tileSource;
|
||||||
final InputStream actualSource;
|
final List<TileXYZ> tiles;
|
||||||
|
final Header header;
|
||||||
|
final DirectoryCache cachedDirectories;
|
||||||
if (this.info.getSourceType() == MapWithAIType.PMTILES) {
|
if (this.info.getSourceType() == MapWithAIType.PMTILES) {
|
||||||
final var hilbert = PMTiles.convertToHilbert(tileXYZ.z(), tileXYZ.x(), tileXYZ.y());
|
|
||||||
try {
|
try {
|
||||||
final var header = PMTiles.readHeader(URI.create(this.url));
|
header = PMTiles.readHeader(URI.create(this.url));
|
||||||
final var root = PMTiles.readRootDirectory(header);
|
final var root = PMTiles.readRootDirectory(header);
|
||||||
final var cachedDirectories = new DirectoryCache(root);
|
tiles = TileXYZ.tilesFromBBox(header.maxZoom(), this.downloadArea).toList();
|
||||||
final var data = PMTiles.readData(header, hilbert, cachedDirectories);
|
cachedDirectories = new DirectoryCache(root);
|
||||||
tileSource = new PMTilesImageSource(new PMTilesImageryInfo(header));
|
tileSource = new PMTilesImageSource(new PMTilesImageryInfo(header));
|
||||||
actualSource = new ByteArrayInputStream(data);
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new IllegalDataException(e);
|
throw new IllegalDataException(e);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
actualSource = source;
|
header = null;
|
||||||
|
cachedDirectories = null;
|
||||||
|
// Assume the source is added by the user
|
||||||
|
final int zoom;
|
||||||
|
if (this.info.getMaxZoom() == 0) {
|
||||||
|
var z = 18;
|
||||||
|
for (; z > 0; z--) {
|
||||||
|
final var tileOptional = TileXYZ.tilesFromBBox(z, this.downloadArea).findFirst();
|
||||||
|
if (tileOptional.isPresent()) {
|
||||||
|
final var tile = tileOptional.get();
|
||||||
|
try {
|
||||||
|
final var responseHeader = java.net.http.HttpClient.newBuilder()
|
||||||
|
.followRedirects(java.net.http.HttpClient.Redirect.NORMAL).build()
|
||||||
|
.send(HttpRequest.newBuilder().uri(URI.create(this.getRequestForTile(tile)))
|
||||||
|
.method("HEAD", HttpRequest.BodyPublishers.noBody()).build(),
|
||||||
|
HttpResponse.BodyHandlers.discarding());
|
||||||
|
if (responseHeader.statusCode() >= 200 && responseHeader.statusCode() < 300) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
Logging.trace(e);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Logging.trace(e);
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
zoom = z;
|
||||||
|
} else {
|
||||||
|
zoom = this.info.getMaxZoom();
|
||||||
|
}
|
||||||
|
tiles = TileXYZ.tilesFromBBox(zoom, this.downloadArea).toList();
|
||||||
tileSource = new MapboxVectorTileSource(new ImageryInfo(this.url, this.url));
|
tileSource = new MapboxVectorTileSource(new ImageryInfo(this.url, this.url));
|
||||||
}
|
}
|
||||||
|
ds = new DataSet();
|
||||||
|
final var currentBounds = new Bounds(this.downloadArea);
|
||||||
|
for (TileXYZ tileXYZ : tiles) {
|
||||||
|
try {
|
||||||
|
final var hilbert = PMTiles.convertToHilbert(tileXYZ.z(), tileXYZ.x(), tileXYZ.y());
|
||||||
|
final var data = this.info.getSourceType() == MapWithAIType.PMTILES
|
||||||
|
? new ByteArrayInputStream(PMTiles.readData(header, hilbert, cachedDirectories))
|
||||||
|
: getInputStream(getRequestForTile(tileXYZ), progressMonitor);
|
||||||
|
final var dataSet = loadTile(tileSource, tileXYZ, data);
|
||||||
|
ds.mergeFrom(dataSet, progressMonitor);
|
||||||
|
tileXYZ.expandBounds(currentBounds);
|
||||||
|
} catch (OsmTransferException | IOException e) {
|
||||||
|
throw new IllegalDataException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ds.addDataSource(new DataSource(currentBounds, this.url));
|
||||||
|
return ds;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DataSet loadTile(TileSource tileSource, TileXYZ tileXYZ, InputStream actualSource)
|
||||||
|
throws IllegalDataException {
|
||||||
|
|
||||||
final var tile = new MVTTile(tileSource, tileXYZ.x(), tileXYZ.y(), tileXYZ.z());
|
final var tile = new MVTTile(tileSource, tileXYZ.x(), tileXYZ.y(), tileXYZ.z());
|
||||||
try {
|
try {
|
||||||
|
@ -381,8 +466,7 @@ public class BoundingBoxMapWithAIDownloader extends BoundingBoxDownloader {
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new IllegalDataException(e);
|
throw new IllegalDataException(e);
|
||||||
}
|
}
|
||||||
ds = new DataSet();
|
final var ds = new DataSet();
|
||||||
ds.addDataSource(new DataSource(this.downloadArea, this.url));
|
|
||||||
final var primitiveMap = new HashMap<PrimitiveId, OsmPrimitive>(tile.getData().getAllPrimitives().size());
|
final var primitiveMap = new HashMap<PrimitiveId, OsmPrimitive>(tile.getData().getAllPrimitives().size());
|
||||||
for (VectorPrimitive p : tile.getData().getAllPrimitives()) {
|
for (VectorPrimitive p : tile.getData().getAllPrimitives()) {
|
||||||
final OsmPrimitive osmPrimitive;
|
final OsmPrimitive osmPrimitive;
|
||||||
|
|
Ładowanie…
Reference in New Issue