Porównaj commity

...

11 Commity
v819 ... master

Autor SHA1 Wiadomość Data
Taylor Smock cecb9f40be
Fix UI freeze during download of Esri layers
Signed-off-by: Taylor Smock <tsmock@meta.com>
2024-04-15 15:06:52 -06:00
Taylor Smock 7f725f7e4c
Update gradle build dependencies
Signed-off-by: Taylor Smock <tsmock@meta.com>
2024-03-12 08:00:47 -06:00
Taylor Smock f7c1d3d8b0
Fix #23529: JSON downloads may wait on EDT while EDT is waiting on downloads to finish
Signed-off-by: Taylor Smock <tsmock@meta.com>
2024-03-12 06:46:53 -06:00
Taylor Smock fbd3f10541
Use v2 JOSMPluginAction scripts
Signed-off-by: Taylor Smock <tsmock@meta.com>
2024-01-17 06:41:52 -07:00
Taylor Smock faa031e49c
Fix issue where the sources would not be updated
Signed-off-by: Taylor Smock <tsmock@meta.com>
2024-01-17 06:24:08 -07:00
Taylor Smock ca0b8e479f
Fix an issue where a custom source would have "&" for the first query parameter instead of "?"
Signed-off-by: Taylor Smock <tsmock@meta.com>
2024-01-17 06:24:08 -07:00
Taylor Smock ad6ec16acd
Don't download sources multiple times when user asks for refresh multiple times in different locations
Signed-off-by: Taylor Smock <smocktaylor@gmail.com>
2024-01-05 06:37:47 -07:00
Taylor Smock d56513358d
Fix #23390: Progress Monitor needs to send child monitors to avoid being in the finished state
Signed-off-by: Taylor Smock <smocktaylor@gmail.com>
2024-01-05 06:16:54 -07:00
Taylor Smock eff911c300
Extract TileXYZ and add some basic tests
Signed-off-by: Taylor Smock <smocktaylor@gmail.com>
2024-01-03 11:18:39 -07:00
Hermann Schwarting d13d61f13c PMTiles: invert y axis of tile coordinates
The y axis of XYZ tiles is oriented from north to south. When
enumerating tiles for a given bounding box, the y coordinates have to be
enumerated from north/top to south/bottom.
2024-01-03 17:45:24 +01:00
Taylor Smock 68b9ff91c1
Set minimum Java version
Signed-off-by: Taylor Smock <smocktaylor@gmail.com>
2024-01-02 14:44:15 -07:00
13 zmienionych plików z 248 dodań i 174 usunięć

Wyświetl plik

@ -10,8 +10,6 @@ on:
branches:
- master
- $default-branch
schedule:
- cron: "1 5 * * 6"
workflow_dispatch:
jobs:
@ -19,7 +17,7 @@ jobs:
strategy:
matrix:
josm-revision: ["", "r18877"]
uses: JOSM/JOSMPluginAction/.github/workflows/ant.yml@v1
uses: JOSM/JOSMPluginAction/.github/workflows/ant.yml@v2
with:
java-version: 17
josm-revision: ${{ matrix.josm-revision }}

Wyświetl plik

@ -10,4 +10,4 @@ permissions:
jobs:
call-workflow:
uses: JOSM/JOSMPluginAction/.github/workflows/reports.yaml@v1
uses: JOSM/JOSMPluginAction/.github/workflows/reports.yaml@v2

Wyświetl plik

@ -1,9 +1,9 @@
import groovy.xml.XmlParser
plugins {
id "com.diffplug.spotless" version "6.20.0"
id "com.github.ben-manes.versions" version "0.47.0"
id "com.github.spotbugs" version "5.0.14"
id "com.diffplug.spotless" version "6.25.0"
id "com.github.ben-manes.versions" version "0.51.0"
id "com.github.spotbugs" version "6.0.8"
// id "de.aaschmid.cpd" version "3.3"
id "eclipse"
id "jacoco"
@ -12,7 +12,7 @@ plugins {
id "maven-publish"
id "net.ltgt.errorprone" version "3.1.0"
id "org.openstreetmap.josm" version "0.8.2"
id "org.sonarqube" version "4.2.1.3168"
id "org.sonarqube" version "4.4.1.3373"
id "pmd"
}
@ -29,15 +29,15 @@ repositories {
def versions = [
awaitility: "4.2.0",
equalsverifier: "3.15",
errorprone: "2.20.0",
findsecbugs: "1.12.0",
equalsverifier: "3.15.8",
errorprone: "2.26.0",
findsecbugs: "1.13.0",
jacoco: "0.8.10",
jmockit: "1.49.a",
josm: properties.get("plugin.compile.version"),
junit: "5.9.1",
junit: "5.10.2",
pmd: "6.20.0",
spotbugs: "4.7.3",
spotbugs: "4.8.3",
wiremock: "2.35.0",
]

Wyświetl plik

@ -7,6 +7,7 @@
<!-- edit the properties of this plugin in the file `gradle.properties` -->
<property file="${basedir}/gradle.properties"/>
<property name="java.lang.version" value="17"/>
<property name="plugin.minimum.java.version" value="17"/>
<!-- ** include targets that all plugins have in common ** -->
<import file="../build-common.xml"/>

Plik binarny nie jest wyświetlany.

Wyświetl plik

@ -1,7 +1,8 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionSha256Sum=03ec176d388f2aa99defcadc3ac6adf8dd2bce5145a129659537c0874dea5ad1
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip
distributionSha256Sum=9631d53cf3e74bfa726893aee1f8994fee4e060c401335946dba2156f440f24c
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

16
gradlew vendored
Wyświetl plik

@ -85,9 +85,6 @@ done
APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@ -133,10 +130,13 @@ location of your Java installation."
fi
else
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
if ! command -v java >/dev/null 2>&1
then
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
fi
# Increase the maximum file descriptors if we can.
@ -144,7 +144,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
# shellcheck disable=SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
@ -152,7 +152,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
# shellcheck disable=SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
@ -197,6 +197,10 @@ if "$cygwin" || "$msys" ; then
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in

Wyświetl plik

@ -84,10 +84,17 @@ public class AddMapWithAILayerAction extends JosmAction implements AdaptableActi
@Override
public void actionPerformed(ActionEvent e) {
if (!isEnabled()) {
return;
if (isEnabled()) {
MainApplication.worker.execute(() -> realRun(this.info));
}
}
/**
* Run the download tasks. This should be run off of the EDT, see #23529.
*
* @param info The external data to download
*/
private static void realRun(MapWithAIInfo info) {
MapWithAILayer layer = MapWithAIDataUtils.getLayer(false);
final DataSet ds;
final OsmData<?, ?, ?, ?> boundsSource;

Wyświetl plik

@ -23,11 +23,10 @@ import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
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.josm.data.Bounds;
@ -86,114 +85,6 @@ import jakarta.json.stream.JsonParser;
* @author Taylor Smock
*/
public class BoundingBoxMapWithAIDownloader extends BoundingBoxDownloader {
private record TileXYZ(int x, int y, int 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, int 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(int x, int z) {
return (x / Math.pow(2, z)) * 360 - 180;
}
private static double yToLatitude(int y, int 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);
}
/**
* Convert bounds to tiles
*
* @param zoom The zoom level to use
* @param bounds The bounds to convert to tiles
* @return A stream of tiles for the bounds at the given zoom level
*/
private static Stream<TileXYZ> tilesFromBBox(int zoom, Bounds bounds) {
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);
}
/**
* Checks to see if the given bounds are functionally equal to this tile
*
* @param left left lon
* @param bottom bottom lat
* @param right right lon
* @param top top lat
*/
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.toIntExact(Math.round(Math.floor(Math.pow(2, zoom) * (180 + lon) / 360)));
var yCoordinate = Math.toIntExact(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);
}
/**
* 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 boolean crop;
private final int start;
@ -240,14 +131,20 @@ public class BoundingBoxMapWithAIDownloader extends BoundingBoxDownloader {
final var tile = TileXYZ.tileFromBBox(lon1, lat1, lon2, lat2);
return getRequestForTile(tile);
}
return url.replace("{bbox}", Double.toString(lon1) + ',' + lat1 + ',' + lon2 + ',' + lat2)
var current = url.replace("{bbox}", Double.toString(lon1) + ',' + lat1 + ',' + lon2 + ',' + lat2)
.replace("{xmin}", Double.toString(lon1)).replace("{ymin}", Double.toString(lat1))
.replace("{xmax}", Double.toString(lon2)).replace("{ymax}", Double.toString(lat2))
+ (crop ? "&crop_bbox=" + DetectTaskingManagerUtils.getTaskingManagerBounds().toBBox().toStringCSV(",")
: "")
+ (this.info.getSourceType() == MapWithAIType.ESRI_FEATURE_SERVER && !this.info.isConflated()
? "&resultOffset=" + this.start
: "");
.replace("{xmax}", Double.toString(lon2)).replace("{ymax}", Double.toString(lat2));
boolean hasQuery = !Optional.ofNullable(URI.create(current).getRawQuery()).map(String::isEmpty).orElse(true);
if (crop) {
current += (hasQuery ? '&' : '?') + "crop_bbox="
+ DetectTaskingManagerUtils.getTaskingManagerBounds().toBBox().toStringCSV(",");
hasQuery = true;
}
if (this.info.getSourceType() == MapWithAIType.ESRI_FEATURE_SERVER && !this.info.isConflated()) {
current += (hasQuery ? '&' : '?') + "resultOffset=" + this.start;
}
return current;
}
private String getRequestForTile(TileXYZ tile) {
@ -440,19 +337,22 @@ public class BoundingBoxMapWithAIDownloader extends BoundingBoxDownloader {
}
ds = new DataSet();
final var currentBounds = new Bounds(this.downloadArea);
progressMonitor.beginTask(tr("Downloading data"), 2 * tiles.size());
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);
: getInputStream(getRequestForTile(tileXYZ), progressMonitor.createSubTaskMonitor(1, true));
final var dataSet = loadTile(tileSource, tileXYZ, data);
ds.mergeFrom(dataSet, progressMonitor);
ds.mergeFrom(dataSet, progressMonitor.createSubTaskMonitor(1, true));
tileXYZ.expandBounds(currentBounds);
} catch (OsmTransferException | IOException e) {
progressMonitor.finishTask();
throw new IllegalDataException(e);
}
}
progressMonitor.finishTask();
ds.addDataSource(new DataSource(currentBounds, this.url));
return ds;
}

Wyświetl plik

@ -18,6 +18,7 @@ import java.util.Optional;
import java.util.TreeSet;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
import org.openstreetmap.josm.data.Bounds;
@ -213,37 +214,26 @@ public final class MapWithAIDataUtils {
}
}
private static boolean confirmBigDownload(List<Bounds> realBounds) {
final var confirmation = new ConfirmBigDownload(realBounds);
GuiHelper.runInEDTAndWait(confirmation);
return confirmation.confirmed();
}
private static class ConfirmBigDownload implements Runnable {
Boolean bool;
final List<?> realBounds;
public ConfirmBigDownload(List<?> realBounds) {
this.realBounds = realBounds;
}
@Override
public void run() {
bool = ConditionalOptionPaneUtil.showConfirmationDialog(MapWithAIPlugin.NAME.concat(".alwaysdownload"),
null,
/**
* Confirm a large download
*
* @param realBounds The list of bounds that will be downloaded
* @return {@code true} if the user still wants to download data
*/
private static synchronized boolean confirmBigDownload(List<Bounds> realBounds) {
final var confirmation = new AtomicBoolean(false);
// This is not a separate class since we don't want to show multiple
// confirmation dialogs
// which is why this method is synchronized.
GuiHelper.runInEDTAndWait(() -> {
final var confirmed = ConditionalOptionPaneUtil.showConfirmationDialog(
MapWithAIPlugin.NAME.concat(".alwaysdownload"), null,
tr("You are going to make {0} requests to the MapWithAI server. This may take some time. <br /> Continue?",
realBounds.size()),
null, JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE, JOptionPane.YES_OPTION);
}
/**
* Check if the user confirmed the download
*
* @return {@code true} if the user wants to continue
*/
public boolean confirmed() {
return bool;
}
confirmation.set(confirmed);
});
return confirmation.get();
}
/**

Wyświetl plik

@ -0,0 +1,121 @@
// License: GPL. For details, see LICENSE file.
package org.openstreetmap.josm.plugins.mapwithai.backend;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.openstreetmap.josm.data.Bounds;
/**
* Create a tile
*
* @param x The x coordinate of the tile
* @param y The y coordinate of the tile
* @param z The zoom level
*/
record TileXYZ(int x, int y, int 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, int 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(int x, int z) {
return (x / Math.pow(2, z)) * 360 - 180;
}
private static double yToLatitude(int y, int 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);
}
/**
* Convert bounds to tiles
*
* @param zoom The zoom level to use
* @param bounds The bounds to convert to tiles
* @return A stream of tiles for the bounds at the given zoom level
*/
static Stream<TileXYZ> tilesFromBBox(int zoom, Bounds bounds) {
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(tile2.y, tile1.y).mapToObj(y -> new TileXYZ(x, y, zoom)))
.flatMap(stream -> stream);
}
/**
* Checks to see if the given bounds are functionally equal to this tile
*
* @param left left lon
* @param bottom bottom lat
* @param right right lon
* @param top top lat
*/
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);
}
static TileXYZ tileFromLatLonZoom(double lon, double lat, int zoom) {
var xCoordinate = Math.toIntExact(Math.round(Math.floor(Math.pow(2, zoom) * (180 + lon) / 360)));
var yCoordinate = Math.toIntExact(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);
}
/**
* Extends a bounds object to contain this tile
*
* @param currentBounds The bounds to extend
*/
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);
}
}

Wyświetl plik

@ -213,9 +213,13 @@ public class MapWithAILayerInfo {
if (this.finishListenerListenerList == null) {
this.finishListenerListenerList = ListenerList.create();
}
boolean running = this.finishListenerListenerList.hasListeners();
if (listener != null) {
this.finishListenerListenerList.addListener(listener);
}
if (running) {
return;
}
if (worker == null) {
final var pleaseWaitRunnable = new PleaseWaitRunnable(tr("Update default entries")) {
@Override
@ -342,11 +346,12 @@ public class MapWithAILayerInfo {
* @param layers The layers to update
*/
private void updateEsriLayers(@Nonnull final Collection<MapWithAIInfo> layers) {
final var esriInfo = new ArrayList<MapWithAIInfo>(300);
for (var layer : layers) {
if (MapWithAIType.ESRI == layer.getSourceType()) {
for (var future : parseEsri(layer)) {
try {
allDefaultLayers.add(future.get());
esriInfo.add(future.get());
} catch (InterruptedException e) {
Logging.error(e);
Thread.currentThread().interrupt();
@ -355,9 +360,10 @@ public class MapWithAILayerInfo {
}
}
} else {
allDefaultLayers.add(layer);
esriInfo.add(layer);
}
}
layers.addAll(esriInfo);
}
protected void finish() {
@ -365,7 +371,7 @@ public class MapWithAILayerInfo {
synchronized (allDefaultLayers) {
allDefaultLayers.clear();
defaultLayers.addAll(newLayers);
this.updateEsriLayers(newLayers);
allDefaultLayers.addAll(newLayers);
allDefaultLayers.sort(new MapWithAIInfo.MapWithAIInfoCategoryComparator());
allDefaultLayers.sort(Comparator.comparing(TileSourceInfo::getName));
allDefaultLayers.sort(Comparator.comparing(info -> info.getCategory().getDescription()));
@ -501,7 +507,7 @@ public class MapWithAILayerInfo {
}
if (changed) {
save();
MainApplication.worker.execute(this::save);
}
}

Wyświetl plik

@ -0,0 +1,46 @@
// License: GPL. For details, see LICENSE file.
package org.openstreetmap.josm.plugins.mapwithai.backend;
import static org.junit.jupiter.api.Assertions.*;
import java.util.Arrays;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.openstreetmap.josm.data.Bounds;
/**
* Test class for {@link TileXYZ}
*/
class TileXYZTest {
static Stream<Arguments> testTileCalculations() {
return Stream.of(Arguments.of(39.07035, -108.5709286, 52013, 100120, 18),
Arguments.of(39.0643941, -108.5610312, 52020, 100125, 18),
Arguments.of(39.0643941, -108.5709286, 52013, 100125, 18),
Arguments.of(39.07035, -108.5610312, 52020, 100120, 18));
}
@ParameterizedTest
@MethodSource
void testTileCalculations(double lat, double lon, int x, int y, int z) {
final var tile = TileXYZ.tileFromLatLonZoom(lon, lat, z);
assertAll(() -> assertEquals(x, tile.x()), () -> assertEquals(y, tile.y()), () -> assertEquals(z, tile.z()));
}
/**
* Check that the tiles calculated for a bbox are correct
*/
@Test
void testNonRegressionGH44() {
final var tiles = TileXYZ.tilesFromBBox(18, new Bounds(39.0643941, -108.5709286, 39.07035, -108.5610312))
.toArray(TileXYZ[]::new);
assertAll(() -> assertEquals(100125, Arrays.stream(tiles).mapToInt(TileXYZ::y).max().orElse(0)),
() -> assertEquals(100120, Arrays.stream(tiles).mapToInt(TileXYZ::y).min().orElse(0)),
() -> assertEquals(52013, Arrays.stream(tiles).mapToInt(TileXYZ::x).min().orElse(0)),
() -> assertEquals(52020, Arrays.stream(tiles).mapToInt(TileXYZ::x).max().orElse(0)));
assertEquals(48, tiles.length, "Should be 6x8 tiles (rangeClosed)");
}
}