kopia lustrzana https://github.com/JOSM/MapWithAI
Add basic support for z/x/y data sources
Signed-off-by: Taylor Smock <tsmock@meta.com>pull/37/head
rodzic
6107e3b2c8
commit
193cc730cb
|
@ -59,6 +59,81 @@ import jakarta.json.stream.JsonParser;
|
||||||
* @author Taylor Smock
|
* @author Taylor Smock
|
||||||
*/
|
*/
|
||||||
public class BoundingBoxMapWithAIDownloader extends BoundingBoxDownloader {
|
public class BoundingBoxMapWithAIDownloader extends BoundingBoxDownloader {
|
||||||
|
private record TileXYZ(long x, long y, long z) {
|
||||||
|
/**
|
||||||
|
* Checks to see if the given bounds are functionally equal to this tile
|
||||||
|
*
|
||||||
|
* @param left left
|
||||||
|
* @param bottom bottom
|
||||||
|
* @param right right
|
||||||
|
* @param top top
|
||||||
|
*/
|
||||||
|
boolean checkBounds(double left, double bottom, double right, double top) {
|
||||||
|
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);
|
||||||
|
return equalsEpsilon(thisLeft, left, this.z) && equalsEpsilon(thisRight, right, this.z)
|
||||||
|
&& equalsEpsilon(thisBottom, bottom, this.z) && equalsEpsilon(thisTop, top, this.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean equalsEpsilon(double first, double second, long z) {
|
||||||
|
// 0.1% of tile size is considered to be "equal"
|
||||||
|
final var maxDiff = (360 / Math.pow(2, z)) / 1000;
|
||||||
|
final var diff = Math.abs(first - second);
|
||||||
|
return diff <= maxDiff;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double xToLongitude(long x, long z) {
|
||||||
|
return (x / Math.pow(2, z)) * 360 - 180;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double yToLatitude(long y, long z) {
|
||||||
|
var t = Math.PI - 2 * Math.PI * y / Math.pow(2, z);
|
||||||
|
return 180 / Math.PI * Math.atan((Math.exp(t) - Math.exp(-t)) / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks to see if the given bounds are functionally equal to this tile
|
||||||
|
*
|
||||||
|
* @param left left
|
||||||
|
* @param bottom bottom
|
||||||
|
* @param right right
|
||||||
|
* @param top top
|
||||||
|
*/
|
||||||
|
private static TileXYZ tileFromBBox(double left, double bottom, double right, double top) {
|
||||||
|
var zoom = 18;
|
||||||
|
while (zoom > 0) {
|
||||||
|
final var tile1 = tileFromLatLonZoom(left, bottom, zoom);
|
||||||
|
final var tile2 = tileFromLatLonZoom(right, top, zoom);
|
||||||
|
if (tile1.equals(tile2)) {
|
||||||
|
return tile1;
|
||||||
|
} else if (tile1.checkBounds(left, bottom, right, top)) {
|
||||||
|
return tile1;
|
||||||
|
} else if (tile2.checkBounds(left, bottom, right, top)) {
|
||||||
|
return tile2;
|
||||||
|
// Just in case the coordinates are _barely_ in other tiles and not the "common"
|
||||||
|
// tile
|
||||||
|
} else if (Math.abs(tile1.x() - tile2.x()) <= 2 && Math.abs(tile1.y() - tile2.y()) <= 2) {
|
||||||
|
final var tileT = new TileXYZ((tile1.x() + tile2.x()) / 2, (tile1.y() + tile2.y()) / 2, zoom);
|
||||||
|
if (tileT.checkBounds(left, bottom, right, top)) {
|
||||||
|
return tileT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
zoom--;
|
||||||
|
}
|
||||||
|
return new TileXYZ(0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TileXYZ tileFromLatLonZoom(double lon, double lat, int zoom) {
|
||||||
|
var xCoordinate = Math.round(Math.floor(Math.pow(2, zoom) * (180 + lon) / 360));
|
||||||
|
var yCoordinate = Math.round(Math.floor(Math.pow(2, zoom)
|
||||||
|
* (1 - (Math.log(Math.tan(Math.toRadians(lat)) + 1 / Math.cos(Math.toRadians(lat))) / Math.PI))
|
||||||
|
/ 2));
|
||||||
|
return new TileXYZ(xCoordinate, yCoordinate, zoom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private final String url;
|
private final String url;
|
||||||
private final boolean crop;
|
private final boolean crop;
|
||||||
private final int start;
|
private final int start;
|
||||||
|
@ -101,6 +176,11 @@ public class BoundingBoxMapWithAIDownloader extends BoundingBoxDownloader {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
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}")) {
|
||||||
|
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}",
|
||||||
|
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))
|
||||||
.replace("{xmax}", Double.toString(lon2)).replace("{ymax}", Double.toString(lat2))
|
.replace("{xmax}", Double.toString(lon2)).replace("{ymax}", Double.toString(lat2))
|
||||||
|
|
Ładowanie…
Reference in New Issue