Improve calculations for areas that have already been downloaded

Signed-off-by: Taylor Smock <tsmock@fb.com>
pull/1/head
Taylor Smock 2020-09-21 16:42:35 -06:00
rodzic 0441c11d4a
commit 1ffa7fcad3
15 zmienionych plików z 213 dodań i 256 usunięć

Wyświetl plik

@ -3,8 +3,10 @@ package org.openstreetmap.josm.plugins.mapwithai.backend;
import static org.openstreetmap.josm.tools.I18n.tr; import static org.openstreetmap.josm.tools.I18n.tr;
import java.awt.geom.Area;
import java.io.InputStream; import java.io.InputStream;
import java.net.SocketTimeoutException; import java.net.SocketTimeoutException;
import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
@ -72,7 +74,8 @@ public class BoundingBoxMapWithAIDownloader extends BoundingBoxDownloader {
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))
+ (crop ? "&crop_bbox=" + DetectTaskingManagerUtils.getTaskingManagerBBox().toStringCSV(",") : ""); + (crop ? "&crop_bbox=" + DetectTaskingManagerUtils.getTaskingManagerBounds().toBBox().toStringCSV(",")
: "");
} }
@Override @Override
@ -119,7 +122,7 @@ public class BoundingBoxMapWithAIDownloader extends BoundingBoxDownloader {
} }
// Just in case something happens, try again... // Just in case something happens, try again...
DataSet ds = new DataSet(); DataSet ds = new DataSet();
GetDataRunnable runnable = new GetDataRunnable(downloadArea.toBBox(), ds, NullProgressMonitor.INSTANCE); GetDataRunnable runnable = new GetDataRunnable(downloadArea, ds, NullProgressMonitor.INSTANCE);
runnable.setMapWithAIInfo(info); runnable.setMapWithAIInfo(info);
MainApplication.worker.execute(() -> { MainApplication.worker.execute(() -> {
try { try {
@ -143,9 +146,9 @@ public class BoundingBoxMapWithAIDownloader extends BoundingBoxDownloader {
* @return The dataset to send to the server * @return The dataset to send to the server
*/ */
private static DataSet getConflationData(Bounds bound) { private static DataSet getConflationData(Bounds bound) {
List<OsmDataLayer> layers = MainApplication Area area = DataSource.getDataSourceArea(Collections.singleton(new DataSource(bound, "")));
.getLayerManager().getLayersOfType(OsmDataLayer.class).stream().filter(l -> l.getDataSet() List<OsmDataLayer> layers = MainApplication.getLayerManager().getLayersOfType(OsmDataLayer.class).stream()
.getDataSourceBounds().stream().anyMatch(b -> b.toBBox().bounds(bound.toBBox()))) .filter(l -> l.getDataSet().getDataSourceBounds().stream().anyMatch(b -> area.contains(bound.asRect())))
.collect(Collectors.toList()); .collect(Collectors.toList());
return layers.stream().max(Comparator.comparingInt(l -> l.getDataSet().allPrimitives().size())) return layers.stream().max(Comparator.comparingInt(l -> l.getDataSet().allPrimitives().size()))
.map(OsmDataLayer::getDataSet).orElse(null); .map(OsmDataLayer::getDataSet).orElse(null);

Wyświetl plik

@ -19,8 +19,8 @@ import javax.json.JsonObject;
import javax.json.JsonValue; import javax.json.JsonValue;
import javax.json.stream.JsonParser; import javax.json.stream.JsonParser;
import org.openstreetmap.josm.data.Bounds;
import org.openstreetmap.josm.data.coor.LatLon; import org.openstreetmap.josm.data.coor.LatLon;
import org.openstreetmap.josm.data.osm.BBox;
import org.openstreetmap.josm.io.CachedFile; import org.openstreetmap.josm.io.CachedFile;
import org.openstreetmap.josm.plugins.mapwithai.data.mapwithai.MapWithAIInfo; import org.openstreetmap.josm.plugins.mapwithai.data.mapwithai.MapWithAIInfo;
import org.openstreetmap.josm.plugins.mapwithai.data.mapwithai.MapWithAILayerInfo; import org.openstreetmap.josm.plugins.mapwithai.data.mapwithai.MapWithAILayerInfo;
@ -151,7 +151,7 @@ public class DataAvailability {
* @return A string that doesn't have quotes at the beginning or end * @return A string that doesn't have quotes at the beginning or end
*/ */
public static String stripQuotes(String string) { public static String stripQuotes(String string) {
return string.replaceAll("(^\"|\"$)", EMPTY_STRING); return string.replaceAll("((^\")|(\"$))", EMPTY_STRING);
} }
/** /**
@ -168,19 +168,19 @@ public class DataAvailability {
} }
/** /**
* Check if a bbox may have data * Check if a bounds may have data
* *
* @param bbox An area that may have data * @param bounds An area that may have data
* @return True if one of the corners of the {@code bbox} is in a country with * @return True if one of the corners of the {@code bounds} is in a country with
* available data. * available data.
*/ */
public boolean hasData(BBox bbox) { public boolean hasData(Bounds bounds) {
final List<LatLon> corners = new ArrayList<>(); final List<LatLon> corners = new ArrayList<>();
corners.add(bbox.getBottomRight()); corners.add(bounds.getMin());
corners.add(new LatLon(bbox.getBottomRightLat(), bbox.getTopLeftLon())); corners.add(new LatLon(bounds.getMinLat(), bounds.getMaxLon()));
corners.add(bbox.getTopLeft()); corners.add(bounds.getMax());
corners.add(new LatLon(bbox.getTopLeftLat(), bbox.getBottomRightLon())); corners.add(new LatLon(bounds.getMaxLat(), bounds.getMinLon()));
corners.add(bbox.getCenter()); corners.add(bounds.getCenter());
return corners.parallelStream().anyMatch(this::hasData); return corners.parallelStream().anyMatch(this::hasData);
} }

Wyświetl plik

@ -12,7 +12,6 @@ import org.openstreetmap.josm.data.coor.LatLon;
import org.openstreetmap.josm.data.gpx.GpxData; import org.openstreetmap.josm.data.gpx.GpxData;
import org.openstreetmap.josm.data.gpx.GpxRoute; import org.openstreetmap.josm.data.gpx.GpxRoute;
import org.openstreetmap.josm.data.gpx.WayPoint; import org.openstreetmap.josm.data.gpx.WayPoint;
import org.openstreetmap.josm.data.osm.BBox;
import org.openstreetmap.josm.gui.MainApplication; import org.openstreetmap.josm.gui.MainApplication;
import org.openstreetmap.josm.gui.layer.GpxLayer; import org.openstreetmap.josm.gui.layer.GpxLayer;
import org.openstreetmap.josm.gui.layer.Layer; import org.openstreetmap.josm.gui.layer.Layer;
@ -58,35 +57,39 @@ final class DetectTaskingManagerUtils {
} }
/** /**
* Get the bbox from the tasking manager layer * Get the bounds from the tasking manager layer
* *
* @return A {@link BBox} made from a tasking manager layer, or one that is not * @return A {@link Bounds} made from a tasking manager layer, or one that is
* valid. * not valid.
*/ */
public static BBox getTaskingManagerBBox() { public static Bounds getTaskingManagerBounds() {
final BBox returnBBox = new BBox(); Bounds returnBounds = new Bounds(0, 0, 0, 0);
final Layer layer = getTaskingManagerLayer(); final Layer layer = getTaskingManagerLayer();
if (layer instanceof GpxLayer) { if (layer instanceof GpxLayer) {
final GpxLayer gpxLayer = (GpxLayer) layer; final GpxLayer gpxLayer = (GpxLayer) layer;
final Bounds realBounds = gpxLayer.data.recalculateBounds(); final Bounds realBounds = gpxLayer.data.recalculateBounds();
returnBBox.add(realBounds.toBBox()); if (returnBounds.isCollapsed()) {
returnBounds = realBounds;
} else {
returnBounds.extend(realBounds);
} }
return returnBBox; }
return returnBounds;
} }
/** /**
* Create a GpxData that can be used to define a crop area * Create a GpxData that can be used to define a crop area
* *
* @param bbox A bbox to crop data to * @param bounds A bounds to crop data to
* @return A gpx layer that can be used to crop data from MapWithAI * @return A gpx layer that can be used to crop data from MapWithAI
*/ */
public static GpxData createTaskingManagerGpxData(BBox bbox) { public static GpxData createTaskingManagerGpxData(Bounds bounds) {
final GpxData data = new GpxData(); final GpxData data = new GpxData();
final GpxRoute route = new GpxRoute(); final GpxRoute route = new GpxRoute();
route.routePoints.add(new WayPoint(bbox.getBottomRight())); route.routePoints.add(new WayPoint(bounds.getMin()));
route.routePoints.add(new WayPoint(new LatLon(bbox.getBottomRightLat(), bbox.getTopLeftLon()))); route.routePoints.add(new WayPoint(new LatLon(bounds.getMaxLat(), bounds.getMinLon())));
route.routePoints.add(new WayPoint(bbox.getTopLeft())); route.routePoints.add(new WayPoint(bounds.getMax()));
route.routePoints.add(new WayPoint(new LatLon(bbox.getTopLeftLat(), bbox.getBottomRightLon()))); route.routePoints.add(new WayPoint(new LatLon(bounds.getMinLat(), bounds.getMaxLon())));
route.routePoints.add(route.routePoints.iterator().next()); route.routePoints.add(route.routePoints.iterator().next());
route.routePoints.forEach(waypoint -> waypoint.setTime(0)); route.routePoints.forEach(waypoint -> waypoint.setTime(0));
data.addRoute(route); data.addRoute(route);

Wyświetl plik

@ -6,7 +6,6 @@ import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.stream.Collectors;
import org.openstreetmap.josm.data.Bounds; import org.openstreetmap.josm.data.Bounds;
import org.openstreetmap.josm.data.DataSource; import org.openstreetmap.josm.data.DataSource;
@ -44,11 +43,11 @@ public final class DownloadListener implements DataSourceListener, Destroyable {
return; return;
} }
if (layer.downloadContinuous()) { if (layer.downloadContinuous()) {
MapWithAIDataUtils.getMapWithAIData(layer, event.getAdded().stream().map(ev -> ev.bounds)
.map(Bounds::toBBox).collect(Collectors.toList()));
List<Bounds> bounds = DataSource.getDataSourceBounds(event.getSource().getDataSources()); List<Bounds> bounds = DataSource.getDataSourceBounds(event.getSource().getDataSources());
bounds.removeIf(a -> layer.getDataSet().getDataSourceBounds().stream().map(Bounds::toBBox) bounds.removeIf(a -> layer.getDataSet().getDataSourceBounds().stream().map(Bounds::toBBox)
.anyMatch(b -> b.bboxIsFunctionallyEqual(a.toBBox(), BBOX_SIMILARITY_DEGREES))); .anyMatch(b -> b.bboxIsFunctionallyEqual(a.toBBox(), BBOX_SIMILARITY_DEGREES)));
MapWithAIDataUtils.getMapWithAIData(layer, bounds);
} }
} }
} }

Wyświetl plik

@ -53,7 +53,7 @@ import org.openstreetmap.josm.tools.Pair;
*/ */
public class GetDataRunnable extends RecursiveTask<DataSet> { public class GetDataRunnable extends RecursiveTask<DataSet> {
private static final long serialVersionUID = 258423685658089715L; private static final long serialVersionUID = 258423685658089715L;
private final transient List<BBox> bbox; private final transient List<Bounds> runnableBounds;
private final transient DataSet dataSet; private final transient DataSet dataSet;
private final transient ProgressMonitor monitor; private final transient ProgressMonitor monitor;
private static final float DEGREE_BUFFER = 0.001f; private static final float DEGREE_BUFFER = 0.001f;
@ -88,7 +88,7 @@ public class GetDataRunnable extends RecursiveTask<DataSet> {
* @param dataSet The dataset to add the data to * @param dataSet The dataset to add the data to
* @param monitor A monitor to keep track of progress * @param monitor A monitor to keep track of progress
*/ */
public GetDataRunnable(BBox bbox, DataSet dataSet, ProgressMonitor monitor) { public GetDataRunnable(Bounds bbox, DataSet dataSet, ProgressMonitor monitor) {
this(Arrays.asList(bbox), dataSet, monitor); this(Arrays.asList(bbox), dataSet, monitor);
} }
@ -98,9 +98,9 @@ public class GetDataRunnable extends RecursiveTask<DataSet> {
* @param dataSet The dataset to add the data to * @param dataSet The dataset to add the data to
* @param monitor A monitor to keep track of progress * @param monitor A monitor to keep track of progress
*/ */
public GetDataRunnable(List<BBox> bbox, DataSet dataSet, ProgressMonitor monitor) { public GetDataRunnable(List<Bounds> bbox, DataSet dataSet, ProgressMonitor monitor) {
super(); super();
this.bbox = bbox.stream().distinct().collect(Collectors.toList()); this.runnableBounds = bbox.stream().distinct().collect(Collectors.toList());
this.dataSet = dataSet; this.dataSet = dataSet;
this.monitor = Optional.ofNullable(monitor).orElse(NullProgressMonitor.INSTANCE); this.monitor = Optional.ofNullable(monitor).orElse(NullProgressMonitor.INSTANCE);
} }
@ -116,19 +116,19 @@ public class GetDataRunnable extends RecursiveTask<DataSet> {
@Override @Override
public DataSet compute() { public DataSet compute() {
final List<BBox> bboxes = maximumDimensions == null ? MapWithAIDataUtils.reduceBBoxSize(bbox) final List<Bounds> bounds = maximumDimensions == null ? MapWithAIDataUtils.reduceBoundSize(runnableBounds)
: MapWithAIDataUtils.reduceBBoxSize(bbox, maximumDimensions); : MapWithAIDataUtils.reduceBoundSize(runnableBounds, maximumDimensions);
monitor.beginTask(tr("Downloading {0} data ({1} total downloads)", MapWithAIPlugin.NAME, bboxes.size()), monitor.beginTask(tr("Downloading {0} data ({1} total downloads)", MapWithAIPlugin.NAME, bounds.size()),
bboxes.size() - 1); bounds.size() - 1);
if (!monitor.isCanceled()) { if (!monitor.isCanceled()) {
if (bboxes.size() == MAX_NUMBER_OF_BBOXES_TO_PROCESS) { if (bounds.size() == MAX_NUMBER_OF_BBOXES_TO_PROCESS) {
final DataSet temporaryDataSet = getDataReal(bboxes.get(0), monitor); final DataSet temporaryDataSet = getDataReal(bounds.get(0), monitor);
synchronized (GetDataRunnable.class) { synchronized (GetDataRunnable.class) {
dataSet.mergeFrom(temporaryDataSet); dataSet.mergeFrom(temporaryDataSet);
} }
} else { } else {
final Collection<GetDataRunnable> tasks = bboxes.parallelStream() final Collection<GetDataRunnable> tasks = bounds.parallelStream()
.map(tBbox -> new GetDataRunnable(tBbox, dataSet, monitor.createSubTaskMonitor(0, true))) .map(bound -> new GetDataRunnable(bound, dataSet, monitor.createSubTaskMonitor(0, true)))
.collect(Collectors.toList()); .collect(Collectors.toList());
tasks.forEach(GetDataRunnable::fork); tasks.forEach(GetDataRunnable::fork);
tasks.parallelStream().forEach(runnable -> { tasks.parallelStream().forEach(runnable -> {
@ -139,8 +139,8 @@ public class GetDataRunnable extends RecursiveTask<DataSet> {
} }
// This can technically be included in the above block, but it is here so that // This can technically be included in the above block, but it is here so that
// cancellation is a little faster // cancellation is a little faster
if (!monitor.isCanceled() && !bboxes.isEmpty()) { if (!monitor.isCanceled() && !bounds.isEmpty()) {
cleanup(dataSet, new Bounds(bboxes.get(0).getBottomRight(), bboxes.get(0).getTopLeft()), info); cleanup(dataSet, bounds.get(0), info);
} }
monitor.finishTask(); monitor.finishTask();
return dataSet; return dataSet;
@ -391,8 +391,7 @@ public class GetDataRunnable extends RecursiveTask<DataSet> {
} }
private static boolean distanceCheck(Node nearNode, Node node, Double distance) { private static boolean distanceCheck(Node nearNode, Node node, Double distance) {
return nearNode == null || node == null ? false return !(nearNode == null || node == null) && nearNode.getCoor().greatCircleDistance(node.getCoor()) < distance;
: nearNode.getCoor().greatCircleDistance(node.getCoor()) < distance;
} }
private static boolean keyCheck(Node nearNode, Node node) { private static boolean keyCheck(Node nearNode, Node node) {
@ -516,19 +515,17 @@ public class GetDataRunnable extends RecursiveTask<DataSet> {
/** /**
* Actually get the data * Actually get the data
* *
* @param bbox The bbox to get the data from * @param bounds The bounds to get the data from
* @param monitor Use to determine if the operation has been cancelled * @param monitor Use to determine if the operation has been cancelled
* @return A dataset with the data from the bbox * @return A dataset with the data from the bounds
*/ */
private static DataSet getDataReal(BBox bbox, ProgressMonitor monitor) { private static DataSet getDataReal(Bounds bounds, ProgressMonitor monitor) {
final DataSet dataSet = new DataSet(); final DataSet dataSet = new DataSet();
dataSet.setUploadPolicy(UploadPolicy.DISCOURAGED); dataSet.setUploadPolicy(UploadPolicy.DISCOURAGED);
new ArrayList<>(MapWithAILayerInfo.getInstance().getLayers()).parallelStream().forEach(map -> { new ArrayList<>(MapWithAILayerInfo.getInstance().getLayers()).parallelStream().forEach(map -> {
try { try {
Bounds bound = new Bounds(bbox.getBottomRight()); BoundingBoxMapWithAIDownloader downloader = new BoundingBoxMapWithAIDownloader(bounds, map,
bound.extend(bbox.getTopLeft());
BoundingBoxMapWithAIDownloader downloader = new BoundingBoxMapWithAIDownloader(bound, map,
DetectTaskingManagerUtils.hasTaskingManagerLayer()); DetectTaskingManagerUtils.hasTaskingManagerLayer());
dataSet.mergeFrom(downloader.parseOsm(monitor)); dataSet.mergeFrom(downloader.parseOsm(monitor));
} catch (OsmTransferException e1) { } catch (OsmTransferException e1) {

Wyświetl plik

@ -4,6 +4,7 @@ package org.openstreetmap.josm.plugins.mapwithai.backend;
import static org.openstreetmap.josm.gui.help.HelpUtil.ht; import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
import static org.openstreetmap.josm.tools.I18n.tr; import static org.openstreetmap.josm.tools.I18n.tr;
import java.awt.geom.Area;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
@ -19,7 +20,6 @@ import javax.swing.JOptionPane;
import org.openstreetmap.josm.data.Bounds; import org.openstreetmap.josm.data.Bounds;
import org.openstreetmap.josm.data.UndoRedoHandler; import org.openstreetmap.josm.data.UndoRedoHandler;
import org.openstreetmap.josm.data.coor.LatLon; import org.openstreetmap.josm.data.coor.LatLon;
import org.openstreetmap.josm.data.osm.BBox;
import org.openstreetmap.josm.data.osm.DataSet; import org.openstreetmap.josm.data.osm.DataSet;
import org.openstreetmap.josm.data.osm.Node; import org.openstreetmap.josm.data.osm.Node;
import org.openstreetmap.josm.data.osm.OsmPrimitive; import org.openstreetmap.josm.data.osm.OsmPrimitive;
@ -92,54 +92,53 @@ public final class MapWithAIDataUtils {
} }
/** /**
* Get a dataset from the API servers using a bbox * Get a dataset from the API servers using a bounds
* *
* @param bbox The bbox from which to get data * @param bounds The bounds from which to get data
* @return A DataSet with data inside the bbox * @return A DataSet with data inside the bounds
*/ */
public static DataSet getData(BBox bbox) { public static DataSet getData(Bounds bounds) {
return getData(Arrays.asList(bbox), MAXIMUM_SIDE_DIMENSIONS); return getData(Arrays.asList(bounds), MAXIMUM_SIDE_DIMENSIONS);
} }
/** /**
* Get a dataset from the API servers using a bbox * Get a dataset from the API servers using a bounds
* *
* @param bbox The bbox from which to get data * @param bounds The bounds from which to get data
* @param maximumDimensions The maximum dimensions to try to download at any one * @param maximumDimensions The maximum dimensions to try to download at any one
* time * time
* @return A DataSet with data inside the bbox * @return A DataSet with data inside the bounds
*/ */
public static DataSet getData(BBox bbox, int maximumDimensions) { public static DataSet getData(Bounds bounds, int maximumDimensions) {
return getData(Arrays.asList(bbox), maximumDimensions); return getData(Arrays.asList(bounds), maximumDimensions);
} }
/** /**
* *
* Get a dataset from the API servers using a list bboxes * Get a dataset from the API servers using a list of bounds
* *
* @param bbox The bboxes from which to get data * @param bounds The bounds from which to get data
* @return A DataSet with data inside the bboxes * @return A DataSet with data inside the bounds
*/ */
public static DataSet getData(List<BBox> bbox) { public static DataSet getData(List<Bounds> bounds) {
return getData(bbox, MAXIMUM_SIDE_DIMENSIONS); return getData(bounds, MAXIMUM_SIDE_DIMENSIONS);
} }
/** /**
* Get a dataset from the API servers using a list bboxes * Get a dataset from the API servers using a list bounds
* *
* @param bbox The bboxes from which to get data * @param bounds The bounds from which to get data
* @param maximumDimensions The maximum dimensions to try to download at any one * @param maximumDimensions The maximum dimensions to try to download at any one
* time * time
* @return A DataSet with data inside the bboxes * @return A DataSet with data inside the bounds
*/ */
public static DataSet getData(List<BBox> bbox, int maximumDimensions) { public static DataSet getData(List<Bounds> bounds, int maximumDimensions) {
final DataSet dataSet = new DataSet(); final DataSet dataSet = new DataSet();
final List<BBox> realBBoxes = bbox.stream().filter(BBox::isValid).distinct().collect(Collectors.toList()); final List<Bounds> realBounds = bounds.stream().filter(b -> !b.isOutOfTheWorld()).distinct()
final List<Bounds> realBounds = realBBoxes.stream() .flatMap(bound -> MapWithAIDataUtils.reduceBoundSize(bound, maximumDimensions).stream())
.flatMap(tBBox -> MapWithAIDataUtils.reduceBBoxSize(tBBox, maximumDimensions).stream()) .collect(Collectors.toList());
.map(MapWithAIDataUtils::bboxToBounds).collect(Collectors.toList());
if (!MapWithAIPreferenceHelper.getMapWithAIUrl().isEmpty()) { if (!MapWithAIPreferenceHelper.getMapWithAIUrl().isEmpty()) {
if ((realBBoxes.size() < TOO_MANY_BBOXES) || confirmBigDownload(realBBoxes)) { if ((bounds.size() < TOO_MANY_BBOXES) || confirmBigDownload(realBounds)) {
final PleaseWaitProgressMonitor monitor = new PleaseWaitProgressMonitor(); final PleaseWaitProgressMonitor monitor = new PleaseWaitProgressMonitor();
monitor.beginTask(tr("Downloading {0} Data", MapWithAIPlugin.NAME), realBounds.size()); monitor.beginTask(tr("Downloading {0} Data", MapWithAIPlugin.NAME), realBounds.size());
realBounds.parallelStream() realBounds.parallelStream()
@ -155,7 +154,7 @@ public final class MapWithAIDataUtils {
} catch (OsmTransferException e) { } catch (OsmTransferException e) {
Logging.error(e); Logging.error(e);
if (maximumDimensions > MAXIMUM_SIDE_DIMENSIONS / 10) { if (maximumDimensions > MAXIMUM_SIDE_DIMENSIONS / 10) {
dataSet.mergeFrom(getData(bound.toBBox(), maximumDimensions / 2)); dataSet.mergeFrom(getData(bound, maximumDimensions / 2));
} }
} }
})); }));
@ -180,18 +179,18 @@ public final class MapWithAIDataUtils {
return dataSet; return dataSet;
} }
private static boolean confirmBigDownload(List<BBox> realBBoxes) { private static boolean confirmBigDownload(List<Bounds> realBounds) {
ConfirmBigDownload confirmation = new ConfirmBigDownload(realBBoxes); ConfirmBigDownload confirmation = new ConfirmBigDownload(realBounds);
GuiHelper.runInEDTAndWait(confirmation); GuiHelper.runInEDTAndWait(confirmation);
return confirmation.confirmed(); return confirmation.confirmed();
} }
private static class ConfirmBigDownload implements Runnable { private static class ConfirmBigDownload implements Runnable {
Boolean bool; Boolean bool;
List<BBox> realBBoxes; List<?> realBounds;
public ConfirmBigDownload(List<BBox> realBBoxes) { public ConfirmBigDownload(List<?> realBounds) {
this.realBBoxes = realBBoxes; this.realBounds = realBounds;
} }
@Override @Override
@ -199,7 +198,7 @@ public final class MapWithAIDataUtils {
bool = ConditionalOptionPaneUtil.showConfirmationDialog(MapWithAIPlugin.NAME.concat(".alwaysdownload"), bool = ConditionalOptionPaneUtil.showConfirmationDialog(MapWithAIPlugin.NAME.concat(".alwaysdownload"),
null, null,
tr("You are going to make {0} requests to the MapWithAI server. This may take some time. <br /> Continue?", tr("You are going to make {0} requests to the MapWithAI server. This may take some time. <br /> Continue?",
realBBoxes.size()), realBounds.size()),
null, JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE, JOptionPane.YES_OPTION); null, JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE, JOptionPane.YES_OPTION);
} }
@ -208,12 +207,6 @@ public final class MapWithAIDataUtils {
} }
} }
private static Bounds bboxToBounds(BBox bbox) {
Bounds bound = new Bounds(bbox.getBottomRight());
bound.extend(bbox.getTopLeft());
return bound;
}
/** /**
* Get a ForkJoinPool that is safe for use in Webstart * Get a ForkJoinPool that is safe for use in Webstart
* *
@ -228,18 +221,18 @@ public final class MapWithAIDataUtils {
} }
/** /**
* Get the height of a bbox * Get the height of a bounds
* *
* @param bbox The bbox with lat/lon information * @param bounds The bounds with lat/lon information
* @return The height in meters (see {@link LatLon#greatCircleDistance}) * @return The height in meters (see {@link LatLon#greatCircleDistance})
*/ */
public static double getHeight(BBox bbox) { public static double getHeight(Bounds bounds) {
final LatLon bottomRight = bbox.getBottomRight(); final LatLon topRight = bounds.getMax();
final LatLon topLeft = bbox.getTopLeft(); final LatLon bottomLeft = bounds.getMin();
final double minx = topLeft.getX(); final double minx = bottomLeft.getX();
final double miny = bottomRight.getY(); final double maxY = topRight.getY();
final LatLon bottomLeft = new LatLon(miny, minx); final LatLon topLeft = new LatLon(maxY, minx);
return topLeft.greatCircleDistance(bottomLeft); return bottomLeft.greatCircleDistance(topLeft);
} }
/** /**
@ -295,36 +288,33 @@ public final class MapWithAIDataUtils {
* @return true if data was downloaded * @return true if data was downloaded
*/ */
public static boolean getMapWithAIData(MapWithAILayer layer, OsmDataLayer osmLayer) { public static boolean getMapWithAIData(MapWithAILayer layer, OsmDataLayer osmLayer) {
return getMapWithAIData(layer, return getMapWithAIData(layer, osmLayer.getDataSet().getDataSourceBounds());
osmLayer.getDataSet().getDataSourceBounds().stream().map(Bounds::toBBox).collect(Collectors.toList()));
} }
/** /**
* Get the data for MapWithAI * Get the data for MapWithAI
* *
* @param layer A pre-existing {@link MapWithAILayer} * @param layer A pre-existing {@link MapWithAILayer}
* @param bboxes The bboxes to get the data in * @param bounds The bounds to get the data in
* @return true if data was downloaded * @return true if data was downloaded
*/ */
public static boolean getMapWithAIData(MapWithAILayer layer, BBox... bboxes) { public static boolean getMapWithAIData(MapWithAILayer layer, Bounds... bounds) {
return getMapWithAIData(layer, Arrays.asList(bboxes)); return getMapWithAIData(layer, Arrays.asList(bounds));
} }
/** /**
* Get the data for MapWithAI * Get the data for MapWithAI
* *
* @param layer A pre-existing {@link MapWithAILayer} * @param layer A pre-existing {@link MapWithAILayer}
* @param bboxes The bboxes to get the data in * @param bounds The bounds to get the data in
* @return true if data was downloaded * @return true if data was downloaded
*/ */
public static boolean getMapWithAIData(MapWithAILayer layer, Collection<BBox> bboxes) { public static boolean getMapWithAIData(MapWithAILayer layer, Collection<Bounds> bounds) {
final DataSet mapWithAISet = layer.getDataSet(); final DataSet mapWithAISet = layer.getDataSet();
final List<BBox> mapWithAIBounds = mapWithAISet.getDataSourceBounds().stream().map(Bounds::toBBox) Area area = mapWithAISet.getDataSourceArea();
final List<Bounds> toDownload = area == null ? new ArrayList<>(bounds)
: bounds.stream().filter(Objects::nonNull).filter(tBounds -> !area.contains(tBounds.asRect()))
.collect(Collectors.toList()); .collect(Collectors.toList());
final List<BBox> editSetBBoxes = bboxes.stream()
.filter(bbox -> mapWithAIBounds.stream().noneMatch(tBBox -> tBBox.bounds(bbox)))
.collect(Collectors.toList());
final List<BBox> toDownload = reduceBBox(mapWithAIBounds, editSetBBoxes);
if (!toDownload.isEmpty()) { if (!toDownload.isEmpty()) {
getForkJoinPool().execute(() -> { getForkJoinPool().execute(() -> {
final DataSet newData = getData(toDownload); final DataSet newData = getData(toDownload);
@ -336,134 +326,87 @@ public final class MapWithAIDataUtils {
} finally { } finally {
lock.unlock(); lock.unlock();
} }
toDownload.stream().map(MapWithAIDataUtils::bboxToBounds).forEach(layer::onPostDownloadFromServer); toDownload.stream().forEach(layer::onPostDownloadFromServer);
}); });
} }
return !toDownload.isEmpty(); return !toDownload.isEmpty();
} }
private static List<BBox> reduceBBox(List<BBox> alreadyDownloaded, List<BBox> wantToDownload) {
final List<BBox> alreadyDownloadedReduced = new ArrayList<>(alreadyDownloaded);
int aDRSize = -1;
do {
aDRSize = alreadyDownloadedReduced.size();
for (int i = 0; i < alreadyDownloadedReduced.size(); i++) {
final BBox bbox1 = alreadyDownloadedReduced.get(i);
for (int j = 0; j < alreadyDownloadedReduced.size(); j++) {
final BBox bbox2 = alreadyDownloadedReduced.get(j);
if (!bbox1.bboxIsFunctionallyEqual(bbox2, null) && bboxesShareSide(bbox1, bbox2)) {
bbox1.add(bbox2);
alreadyDownloadedReduced.remove(bbox2);
}
}
}
} while (aDRSize != alreadyDownloadedReduced.size());
return removeDuplicateBBoxes(wantToDownload, alreadyDownloadedReduced);
}
private static List<BBox> removeDuplicateBBoxes(List<BBox> wantToDownload, List<BBox> alreadyDownloaded) {
for (final BBox bbox : wantToDownload) {
for (final BBox downloaded : alreadyDownloaded) {
if (downloaded.bboxIsFunctionallyEqual(downloaded, null)) {
Logging.debug("{0}: It looks like we already downloaded {1}", MapWithAIPlugin.NAME,
bbox.toStringCSV(","));
}
}
}
return wantToDownload.parallelStream()
.filter(bbox1 -> alreadyDownloaded.parallelStream()
.noneMatch(bbox2 -> bbox2.bboxIsFunctionallyEqual(bbox1, 0.000_02)))
.collect(Collectors.toList());
}
private static boolean bboxesShareSide(BBox bbox1, BBox bbox2) {
final List<Double> bbox1Lons = Arrays.asList(bbox1.getTopLeftLon(), bbox1.getBottomRightLon());
final List<Double> bbox1Lats = Arrays.asList(bbox1.getTopLeftLat(), bbox1.getBottomRightLat());
final List<Double> bbox2Lons = Arrays.asList(bbox2.getTopLeftLon(), bbox2.getBottomRightLon());
final List<Double> bbox2Lats = Arrays.asList(bbox2.getTopLeftLat(), bbox2.getBottomRightLat());
final Long lonDupeCount = bbox1Lons.parallelStream()
.filter(lon -> bbox2Lons.parallelStream().anyMatch(lon2 -> Double.compare(lon, lon2) == 0)).count();
final Long latDupeCount = bbox1Lats.parallelStream()
.filter(lat -> bbox2Lats.parallelStream().anyMatch(lat2 -> Double.compare(lat, lat2) == 0)).count();
return (lonDupeCount + latDupeCount) > 1;
}
/** /**
* Get the width of a bbox * Get the width of a bounds
* *
* @param bbox The bbox to get the width of * @param bounds The bounds to get the width of
* @return See {@link LatLon#greatCircleDistance} * @return See {@link LatLon#greatCircleDistance}
*/ */
public static double getWidth(BBox bbox) { public static double getWidth(Bounds bounds) {
// Lat is y, Lon is x // Lat is y, Lon is x
final LatLon bottomRight = bbox.getBottomRight(); final LatLon bottomLeft = bounds.getMin();
final LatLon topLeft = bbox.getTopLeft(); final LatLon topRight = bounds.getMax();
final double maxx = bottomRight.getX(); final double minx = bottomLeft.getX();
final double minx = topLeft.getX(); final double maxx = topRight.getX();
final double miny = bottomRight.getY(); final double miny = bottomLeft.getY();
final double maxy = topLeft.getY(); final double maxy = topRight.getY();
final LatLon bottomLeft = new LatLon(miny, minx); final LatLon bottomRight = new LatLon(miny, maxx);
final LatLon topRight = new LatLon(maxy, maxx); final LatLon topLeft = new LatLon(maxy, minx);
return Math.max(bottomRight.greatCircleDistance(bottomLeft), topRight.greatCircleDistance(topLeft)); return Math.max(bottomLeft.greatCircleDistance(bottomRight), topLeft.greatCircleDistance(topRight));
} }
/** /**
* Reduce a bbox to the specified dimensions, returning a list of bboxes. * Reduce a bound to the specified dimensions, returning a list of bounds.
* *
* @param bbox The bbox to reduce to a set maximum dimension * @param bound The bound to reduce to a set maximum dimension
* @param maximumDimensions The maximum side dimensions of the bbox * @param maximumDimensions The maximum side dimensions of the bound
* @return A list of BBoxes that have a dimension no more than * @return A list of Bounds that have a dimension no more than
* {@code maximumDimensions} * {@code maximumDimensions}
*/ */
public static List<BBox> reduceBBoxSize(BBox bbox, int maximumDimensions) { public static List<Bounds> reduceBoundSize(Bounds bound, int maximumDimensions) {
final List<BBox> returnBounds = new ArrayList<>(); final List<Bounds> returnBounds = new ArrayList<>();
final double width = getWidth(bbox); final double width = getWidth(bound);
final double height = getHeight(bbox); final double height = getHeight(bound);
final Double widthDivisions = width / maximumDimensions; final Double widthDivisions = width / maximumDimensions;
final Double heightDivisions = height / maximumDimensions; final Double heightDivisions = height / maximumDimensions;
final int widthSplits = widthDivisions.intValue() + ((widthDivisions - widthDivisions.intValue()) > 0 ? 1 : 0); final int widthSplits = widthDivisions.intValue() + ((widthDivisions - widthDivisions.intValue()) > 0 ? 1 : 0);
final int heightSplits = heightDivisions.intValue() final int heightSplits = heightDivisions.intValue()
+ ((heightDivisions - heightDivisions.intValue()) > 0 ? 1 : 0); + ((heightDivisions - heightDivisions.intValue()) > 0 ? 1 : 0);
final double newMinWidths = Math.abs(bbox.getTopLeftLon() - bbox.getBottomRightLon()) / widthSplits; final double newMinWidths = Math.abs(bound.getMaxLon() - bound.getMinLon()) / widthSplits;
final double newMinHeights = Math.abs(bbox.getBottomRightLat() - bbox.getTopLeftLat()) / heightSplits; final double newMinHeights = Math.abs(bound.getMaxLat() - bound.getMinLat()) / heightSplits;
final double minx = bbox.getTopLeftLon(); final double minx = bound.getMinLon();
final double miny = bbox.getBottomRightLat(); final double miny = bound.getMinLat();
for (int x = 1; x <= widthSplits; x++) { for (int x = 1; x <= widthSplits; x++) {
for (int y = 1; y <= heightSplits; y++) { for (int y = 1; y <= heightSplits; y++) {
final LatLon lowerLeft = new LatLon(miny + (newMinHeights * (y - 1)), minx + (newMinWidths * (x - 1))); final LatLon lowerLeft = new LatLon(miny + (newMinHeights * (y - 1)), minx + (newMinWidths * (x - 1)));
final LatLon upperRight = new LatLon(miny + (newMinHeights * y), minx + (newMinWidths * x)); final LatLon upperRight = new LatLon(miny + (newMinHeights * y), minx + (newMinWidths * x));
returnBounds.add(new BBox(lowerLeft, upperRight)); returnBounds.add(new Bounds(lowerLeft, upperRight));
} }
} }
return returnBounds.stream().distinct().collect(Collectors.toList()); return returnBounds.stream().distinct().collect(Collectors.toList());
} }
/** /**
* Reduce a list of bboxes to {@link MapWithAIDataUtils#MAXIMUM_SIDE_DIMENSIONS} * Reduce a list of bounds to {@link MapWithAIDataUtils#MAXIMUM_SIDE_DIMENSIONS}
* *
* @param bboxes The bboxes to reduce to a set maximum dimension * @param bounds The bounds to reduce to a set maximum dimension
* @return A list of BBoxes that have a dimension no more than * @return A list of Bounds that have a dimension no more than
* {@link MapWithAIDataUtils#MAXIMUM_SIDE_DIMENSIONS} * {@link MapWithAIDataUtils#MAXIMUM_SIDE_DIMENSIONS}
*/ */
public static List<BBox> reduceBBoxSize(List<BBox> bboxes) { public static List<Bounds> reduceBoundSize(List<Bounds> bounds) {
return reduceBBoxSize(bboxes, MAXIMUM_SIDE_DIMENSIONS); return reduceBoundSize(bounds, MAXIMUM_SIDE_DIMENSIONS);
} }
/** /**
* Reduce a list of bboxes to a specified size * Reduce a list of bounds to a specified size
* *
* @param bboxes The bboxes to reduce to a set maximum dimension * @param bounds The bounds to reduce to a set maximum dimension
* @param maximumDimensions The maximum width/height dimensions * @param maximumDimensions The maximum width/height dimensions
* @return A list of BBoxes that have a dimension no more than the * @return A list of Bounds that have a dimension no more than the
* {@code maximumDimensions} * {@code maximumDimensions}
*/ */
public static List<BBox> reduceBBoxSize(List<BBox> bboxes, int maximumDimensions) { public static List<Bounds> reduceBoundSize(List<Bounds> bounds, int maximumDimensions) {
final List<BBox> returnBBoxes = new ArrayList<>(); final List<Bounds> returnBounds = new ArrayList<>();
bboxes.forEach(bbox -> returnBBoxes.addAll(reduceBBoxSize(bbox, maximumDimensions))); bounds.forEach(bound -> returnBounds.addAll(reduceBoundSize(bound, maximumDimensions)));
return returnBBoxes.stream().distinct().collect(Collectors.toList()); return returnBounds.stream().distinct().collect(Collectors.toList());
} }
/** /**

Wyświetl plik

@ -5,8 +5,9 @@ import static org.openstreetmap.josm.tools.I18n.tr;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.util.stream.Stream;
import org.openstreetmap.josm.data.osm.BBox; import org.openstreetmap.josm.data.Bounds;
import org.openstreetmap.josm.gui.MainApplication; import org.openstreetmap.josm.gui.MainApplication;
import org.openstreetmap.josm.gui.layer.GpxLayer; import org.openstreetmap.josm.gui.layer.GpxLayer;
import org.openstreetmap.josm.gui.layer.OsmDataLayer; import org.openstreetmap.josm.gui.layer.OsmDataLayer;
@ -20,8 +21,8 @@ public class MapWithAIRemoteControl extends RequestHandler.RawURLParseRequestHan
private static final PermissionPrefWithDefault PERMISSION_PREF_WITH_DEFAULT = new PermissionPrefWithDefault( private static final PermissionPrefWithDefault PERMISSION_PREF_WITH_DEFAULT = new PermissionPrefWithDefault(
MapWithAIPlugin.NAME.concat(".remote_control"), true, tr("MapWithAI")); MapWithAIPlugin.NAME.concat(".remote_control"), true, tr("MapWithAI"));
private BBox download; private Bounds download;
private BBox crop; private Bounds crop;
private Integer maxObj; private Integer maxObj;
private Boolean switchLayer; private Boolean switchLayer;
private String url; private String url;
@ -43,10 +44,10 @@ public class MapWithAIRemoteControl extends RequestHandler.RawURLParseRequestHan
if (args != null) { if (args != null) {
try { try {
if (args.containsKey(BBOX)) { if (args.containsKey(BBOX)) {
download = parseBBox(args.get(BBOX)); download = parseBounds(args.get(BBOX));
} }
if (args.containsKey(CROP_BBOX)) { if (args.containsKey(CROP_BBOX)) {
crop = parseBBox(args.get(CROP_BBOX)); crop = parseBounds(args.get(CROP_BBOX));
} }
if (args.containsKey(MAX_OBJ)) { if (args.containsKey(MAX_OBJ)) {
maxObj = Integer.parseInt(args.get(MAX_OBJ)); maxObj = Integer.parseInt(args.get(MAX_OBJ));
@ -70,24 +71,32 @@ public class MapWithAIRemoteControl extends RequestHandler.RawURLParseRequestHan
} }
} }
private static BBox parseBBox(String coordinates) throws RequestHandlerBadRequestException { /**
final String[] coords = coordinates.split(",", -1); * Parse a string of coordinates into bounds
final BBox tBBox = new BBox(); *
if (coords.length >= 4 && coords.length % 2 == 0) { * @param coordinates The coordinates to parse
for (int i = 0; i < coords.length / 2; i++) { * @return The new Bounds
tBBox.add(Double.parseDouble(coords[2 * i]), Double.parseDouble(coords[2 * i + 1])); * @throws RequestHandlerBadRequestException If there was something wrong with
} * the coordinates
} */
if (!tBBox.isInWorld()) { private static Bounds parseBounds(String coordinates) throws RequestHandlerBadRequestException {
final Double[] coords = Stream.of(coordinates.split(",", -1)).map(Double::parseDouble).toArray(Double[]::new);
// min lat, min lon, max lat, max lon
final double minLat = Math.min(coords[1], coords[3]);
final double maxLat = Math.max(coords[1], coords[3]);
final double maxLon = Math.max(coords[0], coords[2]);
final double minLon = Math.min(coords[0], coords[2]);
final Bounds tBounds = new Bounds(minLat, minLon, maxLat, maxLon);
if (tBounds.isOutOfTheWorld() || tBounds.isCollapsed()) {
throw new RequestHandlerBadRequestException( throw new RequestHandlerBadRequestException(
tr("Bad bbox: {0} (converted to {1})", coordinates, tBBox.toString())); tr("Bad bbox: {0} (converted to {1})", coordinates, tBounds.toString()));
} }
return tBBox; return tBounds;
} }
@Override @Override
protected void handleRequest() throws RequestHandlerErrorException, RequestHandlerBadRequestException { protected void handleRequest() throws RequestHandlerErrorException, RequestHandlerBadRequestException {
if (crop != null && crop.isInWorld()) { if (crop != null && crop.toBBox().isInWorld()) {
MainApplication.getLayerManager() MainApplication.getLayerManager()
.addLayer(new GpxLayer(DetectTaskingManagerUtils.createTaskingManagerGpxData(crop), .addLayer(new GpxLayer(DetectTaskingManagerUtils.createTaskingManagerGpxData(crop),
DetectTaskingManagerUtils.MAPWITHAI_CROP_AREA)); DetectTaskingManagerUtils.MAPWITHAI_CROP_AREA));
@ -108,12 +117,12 @@ public class MapWithAIRemoteControl extends RequestHandler.RawURLParseRequestHan
layer.setSwitchLayers(switchLayer); layer.setSwitchLayers(switchLayer);
} }
if (download != null && download.isInWorld()) { if (download != null && download.toBBox().isInWorld()) {
MapWithAIDataUtils.getMapWithAIData(layer, download); MapWithAIDataUtils.getMapWithAIData(layer, download);
} else if (MainApplication.getLayerManager().getLayersOfType(OsmDataLayer.class).stream() } else if (MainApplication.getLayerManager().getLayersOfType(OsmDataLayer.class).stream()
.anyMatch(tLayer -> !(tLayer instanceof MapWithAILayer))) { .anyMatch(tLayer -> !(tLayer instanceof MapWithAILayer))) {
MapWithAIDataUtils.getMapWithAIData(layer); MapWithAIDataUtils.getMapWithAIData(layer);
} else if (crop != null && crop.isInWorld()) { } else if (crop != null && crop.toBBox().isInWorld()) {
MapWithAIDataUtils.getMapWithAIData(layer, crop); MapWithAIDataUtils.getMapWithAIData(layer, crop);
} }
} }
@ -129,10 +138,10 @@ public class MapWithAIRemoteControl extends RequestHandler.RawURLParseRequestHan
} }
sb.append(tr("automatically switch layers.")).append(br); sb.append(tr("automatically switch layers.")).append(br);
if (download != null) { if (download != null) {
sb.append(tr("We will download data in ")).append(download.toStringCSV(",")).append(br); sb.append(tr("We will download data in ")).append(download.toBBox().toStringCSV(",")).append(br);
} }
if (crop != null) { if (crop != null) {
sb.append(tr("We will crop the data to ")).append(crop.toStringCSV(",")).append(br); sb.append(tr("We will crop the data to ")).append(crop.toBBox().toStringCSV(",")).append(br);
} }
sb.append(tr("There is a maximum addition of {0} objects at one time", maxObj)); sb.append(tr("There is a maximum addition of {0} objects at one time", maxObj));
return sb.toString(); return sb.toString();

Wyświetl plik

@ -35,7 +35,8 @@ public class MapWithAIUploadHook implements UploadHook, Destroyable {
sb.append(";maxadd=").append(MapWithAIPreferenceHelper.getMaximumAddition()); sb.append(";maxadd=").append(MapWithAIPreferenceHelper.getMaximumAddition());
} }
if (DetectTaskingManagerUtils.hasTaskingManagerLayer()) { if (DetectTaskingManagerUtils.hasTaskingManagerLayer()) {
sb.append(";task=").append(DetectTaskingManagerUtils.getTaskingManagerBBox().toStringCSV(",")); sb.append(";task=")
.append(DetectTaskingManagerUtils.getTaskingManagerBounds().toBBox().toStringCSV(","));
} }
if (!MapWithAIPreferenceHelper.getMapWithAIUrl().isEmpty()) { if (!MapWithAIPreferenceHelper.getMapWithAIUrl().isEmpty()) {
sb.append(";url_ids=") sb.append(";url_ids=")

Wyświetl plik

@ -9,6 +9,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.openstreetmap.josm.data.Bounds;
import org.openstreetmap.josm.data.coor.LatLon; import org.openstreetmap.josm.data.coor.LatLon;
import org.openstreetmap.josm.data.gpx.GpxData; import org.openstreetmap.josm.data.gpx.GpxData;
import org.openstreetmap.josm.data.gpx.WayPoint; import org.openstreetmap.josm.data.gpx.WayPoint;
@ -49,18 +50,18 @@ public class DetectTaskingManagerUtilsTest {
@Test @Test
public void testGetTaskingManagerBounds() { public void testGetTaskingManagerBounds() {
assertFalse(DetectTaskingManagerUtils.getTaskingManagerBBox().isInWorld(), "No TM layer exists yet"); assertTrue(DetectTaskingManagerUtils.getTaskingManagerBounds().isCollapsed(), "No TM layer exists yet");
final GpxLayer layer = new GpxLayer(new GpxData(), LAYER_NAME); final GpxLayer layer = new GpxLayer(new GpxData(), LAYER_NAME);
layer.data.addWaypoint(new WayPoint(new LatLon(0, 0))); layer.data.addWaypoint(new WayPoint(new LatLon(0, 0)));
MainApplication.getLayerManager().addLayer(layer); MainApplication.getLayerManager().addLayer(layer);
assertEquals(0, DetectTaskingManagerUtils.getTaskingManagerBBox().height(), 0.000001, assertEquals(0, DetectTaskingManagerUtils.getTaskingManagerBounds().toBBox().height(), 0.000001,
"The TM layer only has one point"); "The TM layer only has one point");
assertEquals(0, DetectTaskingManagerUtils.getTaskingManagerBBox().width(), 0.000001, assertEquals(0, DetectTaskingManagerUtils.getTaskingManagerBounds().toBBox().width(), 0.000001,
"The TM layer only has one point"); "The TM layer only has one point");
layer.data.addWaypoint(new WayPoint(new LatLon(1, 1))); layer.data.addWaypoint(new WayPoint(new LatLon(1, 1)));
final BBox bbox = DetectTaskingManagerUtils.getTaskingManagerBBox(); final BBox bbox = DetectTaskingManagerUtils.getTaskingManagerBounds().toBBox();
assertTrue(bbox.isInWorld(), "A TM layer exists"); assertTrue(bbox.isInWorld(), "A TM layer exists");
assertTrue(bbox.getBottomRight().equalsEpsilon(new LatLon(0, 1)), "The bottom right should be at (0, 1)"); assertTrue(bbox.getBottomRight().equalsEpsilon(new LatLon(0, 1)), "The bottom right should be at (0, 1)");
assertTrue(bbox.getTopLeft().equalsEpsilon(new LatLon(1, 0)), "The top left should be at (1, 0)"); assertTrue(bbox.getTopLeft().equalsEpsilon(new LatLon(1, 0)), "The top left should be at (1, 0)");
@ -70,12 +71,13 @@ public class DetectTaskingManagerUtilsTest {
public void testCreateTaskingManagerGpxBounds() { public void testCreateTaskingManagerGpxBounds() {
assertFalse(DetectTaskingManagerUtils.hasTaskingManagerLayer(), "No TM layer exists yet"); assertFalse(DetectTaskingManagerUtils.hasTaskingManagerLayer(), "No TM layer exists yet");
final BBox bbox = new BBox(0, 0, 1, 1); final Bounds bounds = new Bounds(0, 0, 1, 1);
MainApplication.getLayerManager() MainApplication.getLayerManager()
.addLayer(new GpxLayer(DetectTaskingManagerUtils.createTaskingManagerGpxData(bbox), .addLayer(new GpxLayer(DetectTaskingManagerUtils.createTaskingManagerGpxData(bounds),
DetectTaskingManagerUtils.MAPWITHAI_CROP_AREA)); DetectTaskingManagerUtils.MAPWITHAI_CROP_AREA));
assertTrue(DetectTaskingManagerUtils.hasTaskingManagerLayer(), "A TM layer exists"); assertTrue(DetectTaskingManagerUtils.hasTaskingManagerLayer(), "A TM layer exists");
assertTrue(DetectTaskingManagerUtils.getTaskingManagerBBox().bounds(bbox), "The TM layer should bound itself"); assertTrue(DetectTaskingManagerUtils.getTaskingManagerBounds().toBBox().bounds(bounds.toBBox()),
"The TM layer should bound itself");
} }
} }

Wyświetl plik

@ -18,8 +18,8 @@ import java.util.Map;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.openstreetmap.josm.TestUtils; import org.openstreetmap.josm.TestUtils;
import org.openstreetmap.josm.data.Bounds;
import org.openstreetmap.josm.data.coor.LatLon; import org.openstreetmap.josm.data.coor.LatLon;
import org.openstreetmap.josm.data.osm.BBox;
import org.openstreetmap.josm.data.osm.DataSet; import org.openstreetmap.josm.data.osm.DataSet;
import org.openstreetmap.josm.data.osm.Node; import org.openstreetmap.josm.data.osm.Node;
import org.openstreetmap.josm.data.osm.Way; import org.openstreetmap.josm.data.osm.Way;
@ -103,7 +103,7 @@ public class GetDataRunnableTest {
public void testRegressionTicket46() { public void testRegressionTicket46() {
DataSet ds = new DataSet(); DataSet ds = new DataSet();
GetDataRunnable getData = new GetDataRunnable( GetDataRunnable getData = new GetDataRunnable(
Arrays.asList(new BBox(-5.7400005, 34.4524384, -5.6686014, 34.5513153)), ds, null); Arrays.asList(new Bounds(34.4524384, -5.7400005, 34.5513153, -5.6686014)), ds, null);
getData.setMaximumDimensions(5_000); getData.setMaximumDimensions(5_000);
getData.fork().join(); getData.fork().join();
assertNotNull(ds); assertNotNull(ds);

Wyświetl plik

@ -13,8 +13,8 @@ import org.awaitility.Durations;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.openstreetmap.josm.data.Bounds;
import org.openstreetmap.josm.data.coor.LatLon; import org.openstreetmap.josm.data.coor.LatLon;
import org.openstreetmap.josm.data.osm.BBox;
import org.openstreetmap.josm.plugins.mapwithai.data.mapwithai.MapWithAILayerInfo; import org.openstreetmap.josm.plugins.mapwithai.data.mapwithai.MapWithAILayerInfo;
import org.openstreetmap.josm.plugins.mapwithai.testutils.MapWithAITestRules; import org.openstreetmap.josm.plugins.mapwithai.testutils.MapWithAITestRules;
import org.openstreetmap.josm.testutils.JOSMTestRules; import org.openstreetmap.josm.testutils.JOSMTestRules;
@ -38,8 +38,8 @@ public class MapWithAIAvailabilityTest {
@Test @Test
public void testHasDataBBox() { public void testHasDataBBox() {
assertFalse(instance.hasData(new BBox(0, 0, 0.1, 0.1)), "There shouldn't be data in the ocean"); assertFalse(instance.hasData(new Bounds(0, 0, 0.1, 0.1)), "There shouldn't be data in the ocean");
assertTrue(instance.hasData(new BBox(-99.9, 39.9, 100.1, 40.1)), "There should be data in the US"); assertTrue(instance.hasData(new Bounds(39.9, -99.9, 40.1, 100.1)), "There should be data in the US");
} }
@Test @Test

Wyświetl plik

@ -50,7 +50,7 @@ public class MapWithAIDataUtilsTest {
*/ */
@Test @Test
public void testGetData() { public void testGetData() {
final BBox testBBox = getTestBBox(); final Bounds testBBox = getTestBounds();
final DataSet ds = new DataSet(MapWithAIDataUtils.getData(testBBox)); final DataSet ds = new DataSet(MapWithAIDataUtils.getData(testBBox));
assertEquals(1, ds.getWays().size(), "There should only be one way in the testBBox"); assertEquals(1, ds.getWays().size(), "There should only be one way in the testBBox");
} }
@ -60,9 +60,9 @@ public class MapWithAIDataUtilsTest {
*/ */
@Test @Test
public void testGetDataMultiple() { public void testGetDataMultiple() {
final BBox testBBox = getTestBBox(); final Bounds testBounds1 = getTestBounds();
final BBox testBBox2 = new BBox(-108.4495519, 39.095376, -108.4422314, 39.0987811); final Bounds testBounds2 = new Bounds(39.095376, -108.4495519, 39.0987811, -108.4422314);
final DataSet ds = new DataSet(MapWithAIDataUtils.getData(Arrays.asList(testBBox, testBBox2))); final DataSet ds = new DataSet(MapWithAIDataUtils.getData(Arrays.asList(testBounds1, testBounds2)));
int expectedBounds = 2; int expectedBounds = 2;
assertEquals(expectedBounds, ds.getDataSourceBounds().size(), "There should be two data sources"); assertEquals(expectedBounds, ds.getDataSourceBounds().size(), "There should be two data sources");
} }
@ -73,14 +73,14 @@ public class MapWithAIDataUtilsTest {
*/ */
@Test @Test
public void testGetDataCropped() { public void testGetDataCropped() {
final BBox testBBox = getTestBBox(); final Bounds testBounds = getTestBounds();
final GpxData gpxData = new GpxData(); final GpxData gpxData = new GpxData();
gpxData.addWaypoint(new WayPoint(new LatLon(39.0735205, -108.5711561))); gpxData.addWaypoint(new WayPoint(new LatLon(39.0735205, -108.5711561)));
gpxData.addWaypoint(new WayPoint(new LatLon(39.0736682, -108.5708568))); gpxData.addWaypoint(new WayPoint(new LatLon(39.0736682, -108.5708568)));
final GpxLayer gpx = new GpxLayer(gpxData, DetectTaskingManagerUtils.MAPWITHAI_CROP_AREA); final GpxLayer gpx = new GpxLayer(gpxData, DetectTaskingManagerUtils.MAPWITHAI_CROP_AREA);
final DataSet originalData = MapWithAIDataUtils.getData(testBBox); final DataSet originalData = MapWithAIDataUtils.getData(testBounds);
MainApplication.getLayerManager().addLayer(gpx); MainApplication.getLayerManager().addLayer(gpx);
final DataSet ds = MapWithAIDataUtils.getData(testBBox); final DataSet ds = MapWithAIDataUtils.getData(testBounds);
assertEquals(1, ds.getWays().size(), "There should only be one way in the cropped testBBox"); assertEquals(1, ds.getWays().size(), "There should only be one way in the cropped testBBox");
assertEquals(3, ds.getNodes().size(), "There should be three nodes in the cropped testBBox"); assertEquals(3, ds.getNodes().size(), "There should be three nodes in the cropped testBBox");
assertEquals(1, originalData.getWays().size(), "There should be one way in the testBBox"); assertEquals(1, originalData.getWays().size(), "There should be one way in the testBBox");
@ -153,14 +153,15 @@ public class MapWithAIDataUtilsTest {
@Test @Test
public void testSplitBounds() { public void testSplitBounds() {
final BBox bbox = new BBox(0, 0, 0.0001, 0.0001); final Bounds bounds = new Bounds(0, 0, 0.0001, 0.0001);
for (Double i : Arrays.asList(0.0001, 0.001, 0.01, 0.1)) { for (Double i : Arrays.asList(0.0001, 0.001, 0.01, 0.1)) {
bbox.add(i, i); bounds.extend(i, i);
List<BBox> bboxes = MapWithAIDataUtils.reduceBBoxSize(bbox, 5_000); List<BBox> bboxes = MapWithAIDataUtils.reduceBoundSize(bounds, 5_000).stream().map(Bounds::toBBox)
assertEquals(getExpectedNumberOfBBoxes(bbox, 5_000), bboxes.size(), .collect(Collectors.toList());
assertEquals(getExpectedNumberOfBBoxes(bounds, 5_000), bboxes.size(),
"The bbox should be appropriately reduced"); "The bbox should be appropriately reduced");
checkInBBox(bbox, bboxes); checkInBBox(bounds.toBBox(), bboxes);
checkBBoxesConnect(bbox, bboxes); checkBBoxesConnect(bounds.toBBox(), bboxes);
} }
} }
@ -176,7 +177,7 @@ public class MapWithAIDataUtilsTest {
.collect(Collectors.toList()).isEmpty()); .collect(Collectors.toList()).isEmpty());
} }
private static int getExpectedNumberOfBBoxes(BBox bbox, int maximumDimensions) { private static int getExpectedNumberOfBBoxes(Bounds bbox, int maximumDimensions) {
double width = MapWithAIDataUtils.getWidth(bbox); double width = MapWithAIDataUtils.getWidth(bbox);
double height = MapWithAIDataUtils.getHeight(bbox); double height = MapWithAIDataUtils.getHeight(bbox);
int widthDivisions = (int) Math.ceil(width / maximumDimensions); int widthDivisions = (int) Math.ceil(width / maximumDimensions);

Wyświetl plik

@ -30,7 +30,6 @@ import org.openstreetmap.josm.data.Bounds;
import org.openstreetmap.josm.data.DataSource; import org.openstreetmap.josm.data.DataSource;
import org.openstreetmap.josm.data.UndoRedoHandler; import org.openstreetmap.josm.data.UndoRedoHandler;
import org.openstreetmap.josm.data.coor.LatLon; import org.openstreetmap.josm.data.coor.LatLon;
import org.openstreetmap.josm.data.osm.BBox;
import org.openstreetmap.josm.data.osm.DataSet; import org.openstreetmap.josm.data.osm.DataSet;
import org.openstreetmap.josm.data.osm.Node; import org.openstreetmap.josm.data.osm.Node;
import org.openstreetmap.josm.data.osm.OsmPrimitive; import org.openstreetmap.josm.data.osm.OsmPrimitive;
@ -143,7 +142,7 @@ public class MapWithAILayerTest {
MapWithAILayer mapWithAILayer = MapWithAIDataUtils.getLayer(true); MapWithAILayer mapWithAILayer = MapWithAIDataUtils.getLayer(true);
DataSet ds = mapWithAILayer.getDataSet(); DataSet ds = mapWithAILayer.getDataSet();
GetDataRunnable getData = new GetDataRunnable( GetDataRunnable getData = new GetDataRunnable(
Arrays.asList(new BBox(-5.7400005, 34.4524384, -5.6686014, 34.5513153)), ds, null); Arrays.asList(new Bounds(34.4524384, -5.7400005, 34.5513153, -5.6686014)), ds, null);
getData.setMaximumDimensions(5_000); getData.setMaximumDimensions(5_000);
getData.fork().join(); getData.fork().join();
assertTrue(ds.getSelected().isEmpty()); assertTrue(ds.getSelected().isEmpty());

Wyświetl plik

@ -139,7 +139,7 @@ public class MapWithAIRemoteControlTest {
"http://127.0.0.1:8111/mapwithai?bbox={bbox}".replace("{bbox}", temp2.toStringCSV(","))) "http://127.0.0.1:8111/mapwithai?bbox={bbox}".replace("{bbox}", temp2.toStringCSV(",")))
.handle()); .handle());
assertEquals( assertEquals(
"Bad bbox: 39.0621223,-108.4625421,39.0633059,-108.4594728 (converted to [ x: 39.0621223 -> 39.0633059, y: -108.4625421 -> -108.4594728 ])", "Bad bbox: 39.0621223,-108.4625421,39.0633059,-108.4594728 (converted to Bounds[-108.4625421,39.0621223,-108.4594728,39.0633059])",
exception.getMessage()); exception.getMessage());
} }

Wyświetl plik

@ -18,8 +18,8 @@ import org.junit.Before;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.openstreetmap.josm.TestUtils; import org.openstreetmap.josm.TestUtils;
import org.openstreetmap.josm.data.Bounds;
import org.openstreetmap.josm.data.coor.LatLon; import org.openstreetmap.josm.data.coor.LatLon;
import org.openstreetmap.josm.data.osm.BBox;
import org.openstreetmap.josm.data.osm.DataSet; import org.openstreetmap.josm.data.osm.DataSet;
import org.openstreetmap.josm.data.osm.Node; import org.openstreetmap.josm.data.osm.Node;
import org.openstreetmap.josm.data.osm.Way; import org.openstreetmap.josm.data.osm.Way;
@ -119,9 +119,9 @@ public class MapWithAIUploadHookTest {
assertTrue(split.contains("url_ids=false-url"), "The false-url should be shown in the changeset tag"); assertTrue(split.contains("url_ids=false-url"), "The false-url should be shown in the changeset tag");
assertTrue(split.contains("maxadd=20"), "The maxadd should be 20"); assertTrue(split.contains("maxadd=20"), "The maxadd should be 20");
BBox tBBox = new BBox(1, 0, 0, 1); Bounds tBounds = new Bounds(0, 1, 1, 0);
MainApplication.getLayerManager() MainApplication.getLayerManager()
.addLayer(new GpxLayer(DetectTaskingManagerUtils.createTaskingManagerGpxData(tBBox), .addLayer(new GpxLayer(DetectTaskingManagerUtils.createTaskingManagerGpxData(tBounds),
DetectTaskingManagerUtils.MAPWITHAI_CROP_AREA)); DetectTaskingManagerUtils.MAPWITHAI_CROP_AREA));
tags.clear(); tags.clear();
@ -131,7 +131,7 @@ public class MapWithAIUploadHookTest {
assertTrue(split.contains("version=".concat(info.localversion)), "The version should match the local version"); assertTrue(split.contains("version=".concat(info.localversion)), "The version should match the local version");
assertTrue(split.contains("url_ids=false-url"), "The false-url should be shown in the changeset tag"); assertTrue(split.contains("url_ids=false-url"), "The false-url should be shown in the changeset tag");
assertTrue(split.contains("maxadd=20"), "The maxadd should be 20"); assertTrue(split.contains("maxadd=20"), "The maxadd should be 20");
assertTrue(split.contains("task=".concat(tBBox.toStringCSV(","))), assertTrue(split.contains("task=".concat(tBounds.toBBox().toStringCSV(","))),
"There should be a task in the mapwithai:options"); "There should be a task in the mapwithai:options");
} }