kopia lustrzana https://github.com/JOSM/MapWithAI
Allow downloading of arbitrary data from the main download panel
Signed-off-by: Taylor Smock <taylor.smock@kaart.com>pull/1/head
rodzic
5768540ff0
commit
38399f73cc
|
@ -17,15 +17,16 @@ import javax.swing.JMenu;
|
|||
import javax.swing.JMenuItem;
|
||||
|
||||
import org.openstreetmap.josm.actions.JosmAction;
|
||||
import org.openstreetmap.josm.data.Version;
|
||||
import org.openstreetmap.josm.gui.MainApplication;
|
||||
import org.openstreetmap.josm.gui.MainMenu;
|
||||
import org.openstreetmap.josm.gui.MapFrame;
|
||||
import org.openstreetmap.josm.gui.download.DownloadDialog;
|
||||
import org.openstreetmap.josm.gui.preferences.PreferenceSetting;
|
||||
import org.openstreetmap.josm.io.remotecontrol.RequestProcessor;
|
||||
import org.openstreetmap.josm.plugins.Plugin;
|
||||
import org.openstreetmap.josm.plugins.PluginInformation;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAIAction;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAIArbitraryAction;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAIDataUtils;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAILayer;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAIMoveAction;
|
||||
|
@ -33,6 +34,7 @@ import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAIObject;
|
|||
import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAIRemoteControl;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAIUploadHook;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.backend.MergeDuplicateWaysAction;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.frontend.MapWithAIDownloadReader;
|
||||
import org.openstreetmap.josm.spi.preferences.Config;
|
||||
import org.openstreetmap.josm.tools.Destroyable;
|
||||
import org.openstreetmap.josm.tools.Logging;
|
||||
|
@ -46,12 +48,13 @@ public final class MapWithAIPlugin extends Plugin implements Destroyable {
|
|||
|
||||
private final PreferenceSetting preferenceSetting;
|
||||
|
||||
private final MapWithAIDownloadReader mapWithAIDownloadReader;
|
||||
|
||||
private final List<Destroyable> destroyables;
|
||||
|
||||
private static final Map<Class<? extends JosmAction>, Boolean> MENU_ENTRIES = new LinkedHashMap<>();
|
||||
static {
|
||||
MENU_ENTRIES.put(MapWithAIAction.class, false);
|
||||
MENU_ENTRIES.put(MapWithAIArbitraryAction.class, true);
|
||||
MENU_ENTRIES.put(MapWithAIMoveAction.class, false);
|
||||
MENU_ENTRIES.put(MergeDuplicateWaysAction.class, true);
|
||||
}
|
||||
|
@ -87,6 +90,8 @@ public final class MapWithAIPlugin extends Plugin implements Destroyable {
|
|||
destroyables = new ArrayList<>();
|
||||
destroyables.add(new MapWithAIUploadHook(info));
|
||||
mapFrameInitialized(null, MainApplication.getMap());
|
||||
mapWithAIDownloadReader = new MapWithAIDownloadReader();
|
||||
DownloadDialog.addDownloadSource(mapWithAIDownloadReader);
|
||||
MainApplication.worker.execute(() -> UpdateProd.doProd(info.mainversion));
|
||||
}
|
||||
|
||||
|
@ -141,12 +146,15 @@ public final class MapWithAIPlugin extends Plugin implements Destroyable {
|
|||
}
|
||||
|
||||
MainApplication.getLayerManager().getLayersOfType(MapWithAILayer.class).stream()
|
||||
.forEach(layer -> MainApplication.getLayerManager().removeLayer(layer));
|
||||
.forEach(layer -> MainApplication.getLayerManager().removeLayer(layer));
|
||||
|
||||
if (!Config.getPref().getBoolean(PAINTSTYLE_PREEXISTS)) {
|
||||
MapWithAIDataUtils.removeMapWithAIPaintStyles();
|
||||
}
|
||||
|
||||
destroyables.forEach(Destroyable::destroy);
|
||||
if (Version.getInstance().getVersion() > 15542) {
|
||||
DownloadDialog.removeDownloadSource(mapWithAIDownloadReader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
// License: GPL. For details, see LICENSE file.
|
||||
package org.openstreetmap.josm.plugins.mapwithai.backend;
|
||||
|
||||
import static org.openstreetmap.josm.tools.I18n.tr;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.openstreetmap.josm.data.Bounds;
|
||||
import org.openstreetmap.josm.data.osm.DataSet;
|
||||
import org.openstreetmap.josm.gui.progress.ProgressMonitor;
|
||||
import org.openstreetmap.josm.io.BoundingBoxDownloader;
|
||||
import org.openstreetmap.josm.io.IllegalDataException;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.MapWithAIPlugin;
|
||||
|
||||
public class BoundingBoxMapWithAIDownloader extends BoundingBoxDownloader {
|
||||
private final String url;
|
||||
private final boolean crop;
|
||||
|
||||
private final Bounds downloadArea;
|
||||
|
||||
public BoundingBoxMapWithAIDownloader(Bounds downloadArea, String url, boolean crop) {
|
||||
super(downloadArea);
|
||||
this.url = url;
|
||||
this.crop = crop;
|
||||
this.downloadArea = downloadArea;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getRequestForBbox(double lon1, double lat1, double lon2, double lat2) {
|
||||
return url.replace("{bbox}", Double.toString(lon1) + ',' + lat1 + ',' + lon2 + ',' + lat2)
|
||||
+ (crop ? "crop_bbox=" + lon1 + ',' + lat1 + ',' + lon2 + ',' + lat2 : "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the download task to be displayed in the
|
||||
* {@link ProgressMonitor}.
|
||||
*
|
||||
* @return task name
|
||||
*/
|
||||
@Override
|
||||
protected String getTaskName() {
|
||||
return tr("Contacting {0} Server...", MapWithAIPlugin.NAME);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
package org.openstreetmap.josm.plugins.mapwithai.backend;
|
||||
|
||||
import static org.openstreetmap.josm.tools.I18n.tr;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask;
|
||||
import org.openstreetmap.josm.actions.downloadtasks.DownloadParams;
|
||||
import org.openstreetmap.josm.data.Bounds;
|
||||
import org.openstreetmap.josm.data.ViewportData;
|
||||
import org.openstreetmap.josm.data.osm.OsmPrimitive;
|
||||
import org.openstreetmap.josm.gui.MainApplication;
|
||||
import org.openstreetmap.josm.gui.MapFrame;
|
||||
import org.openstreetmap.josm.gui.io.UpdatePrimitivesTask;
|
||||
import org.openstreetmap.josm.gui.progress.ProgressMonitor;
|
||||
import org.openstreetmap.josm.io.OsmServerReader;
|
||||
import org.openstreetmap.josm.tools.Utils;
|
||||
|
||||
public class DownloadMapWithAITask extends DownloadOsmTask {
|
||||
@Override
|
||||
public Future<?> download(OsmServerReader reader, DownloadParams settings, Bounds downloadArea,
|
||||
ProgressMonitor progressMonitor) {
|
||||
return download(new MapWithAIDownloadTask(settings, reader, progressMonitor, zoomAfterDownload), downloadArea);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConfirmationMessage(URL url) {
|
||||
if (url != null) {
|
||||
Collection<String> items = new ArrayList<>();
|
||||
items.add(tr("OSM Server URL:") + ' ' + url.getHost());
|
||||
items.add(tr("Command") + ": " + url.getPath());
|
||||
if (url.getQuery() != null) {
|
||||
items.add(tr("Request details: {0}", url.getQuery().replaceAll(",\\s*", ", ")));
|
||||
}
|
||||
return Utils.joinAsHtmlUnorderedList(items);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected class MapWithAIDownloadTask extends DownloadOsmTask.DownloadTask {
|
||||
|
||||
/**
|
||||
* Constructs a new {@code DownloadTask}.
|
||||
*
|
||||
* @param settings download settings
|
||||
* @param reader OSM data reader
|
||||
* @param progressMonitor progress monitor
|
||||
*/
|
||||
public MapWithAIDownloadTask(DownloadParams settings, OsmServerReader reader, ProgressMonitor progressMonitor) {
|
||||
this(settings, reader, progressMonitor, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new {@code DownloadTask}.
|
||||
*
|
||||
* @param settings download settings
|
||||
* @param reader OSM data reader
|
||||
* @param progressMonitor progress monitor
|
||||
* @param zoomAfterDownload If true, the map view will zoom to download area
|
||||
* after download
|
||||
*/
|
||||
public MapWithAIDownloadTask(DownloadParams settings, OsmServerReader reader, ProgressMonitor progressMonitor,
|
||||
boolean zoomAfterDownload) {
|
||||
super(settings, reader, progressMonitor, zoomAfterDownload);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadData(String newLayerName, Bounds bounds) {
|
||||
MapWithAILayer layer = MapWithAIDataUtils.getLayer(true);
|
||||
Collection<OsmPrimitive> primitivesToUpdate = searchPrimitivesToUpdate(bounds, layer.getDataSet());
|
||||
layer.mergeFrom(dataSet);
|
||||
MapFrame map = MainApplication.getMap();
|
||||
if (map != null && (zoomAfterDownload
|
||||
|| MainApplication.getLayerManager().getLayers().parallelStream().allMatch(layer::equals))) {
|
||||
computeBbox(bounds).map(ViewportData::new).ifPresent(map.mapView::zoomTo);
|
||||
}
|
||||
if (!primitivesToUpdate.isEmpty()) {
|
||||
MainApplication.worker.execute(new UpdatePrimitivesTask(layer, primitivesToUpdate));
|
||||
}
|
||||
layer.onPostDownloadFromServer(bounds);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -26,6 +26,7 @@ import javax.net.ssl.SSLException;
|
|||
import org.openstreetmap.josm.actions.MergeNodesAction;
|
||||
import org.openstreetmap.josm.command.Command;
|
||||
import org.openstreetmap.josm.command.DeleteCommand;
|
||||
import org.openstreetmap.josm.data.Bounds;
|
||||
import org.openstreetmap.josm.data.osm.AbstractPrimitive;
|
||||
import org.openstreetmap.josm.data.osm.BBox;
|
||||
import org.openstreetmap.josm.data.osm.DataSet;
|
||||
|
@ -124,8 +125,8 @@ public class GetDataRunnable extends RecursiveTask<DataSet> implements CancelLis
|
|||
}
|
||||
// This can technically be included in the above block, but it is here so that
|
||||
// cancellation is a little faster
|
||||
if (!monitor.isCanceled()) {
|
||||
cleanup(dataSet);
|
||||
if (!monitor.isCanceled() && !bboxes.isEmpty()) {
|
||||
cleanup(dataSet, new Bounds(bboxes.get(0).getBottomRight(), bboxes.get(0).getTopLeft()));
|
||||
}
|
||||
monitor.finishTask();
|
||||
return dataSet;
|
||||
|
@ -135,11 +136,14 @@ public class GetDataRunnable extends RecursiveTask<DataSet> implements CancelLis
|
|||
* Perform cleanups on a dataset (one dataset at a time)
|
||||
*
|
||||
* @param dataSet The dataset to cleanup
|
||||
* @param bounds
|
||||
*/
|
||||
public static void cleanup(DataSet dataSet) {
|
||||
public static void cleanup(DataSet dataSet, Bounds bounds) {
|
||||
synchronized (LOCK) {
|
||||
/* Microsoft buildings don't have a source, so we add one */
|
||||
MapWithAIDataUtils.addSourceTags(dataSet, "building", "microsoft/BuildingFootprints");
|
||||
// MapWithAIDataUtils.addSourceTags(dataSet, "building",
|
||||
// "microsoft/BuildingFootprints");
|
||||
removeRedundantSource(dataSet);
|
||||
replaceTags(dataSet);
|
||||
removeCommonTags(dataSet);
|
||||
mergeNodes(dataSet);
|
||||
|
@ -147,25 +151,48 @@ public class GetDataRunnable extends RecursiveTask<DataSet> implements CancelLis
|
|||
mergeWays(dataSet);
|
||||
removeAlreadyAddedData(dataSet);
|
||||
new MergeDuplicateWays(dataSet).executeCommand();
|
||||
dataSet.getWays().parallelStream().filter(way -> !way.isDeleted())
|
||||
.forEach(GetDataRunnable::cleanupArtifacts);
|
||||
(bounds == null ? dataSet.getWays() : dataSet.searchWays(bounds.toBBox())).parallelStream()
|
||||
.filter(way -> !way.isDeleted())
|
||||
.forEach(GetDataRunnable::cleanupArtifacts);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove redudant sources from objects (if source on way and source on node,
|
||||
* and node doesn't have any other tags, then node doesn't need the source)
|
||||
*
|
||||
* @param dataSet The dataset with potential duplicate source tags
|
||||
*/
|
||||
public static void removeRedundantSource(DataSet dataSet) {
|
||||
dataSet.getNodes().parallelStream().filter(node -> !node.getReferrers().isEmpty())
|
||||
.filter(node -> node.getKeys().entrySet().parallelStream().map(Entry::getKey)
|
||||
.allMatch(key -> key.contains("source"))
|
||||
&& node.getKeys().entrySet().parallelStream()
|
||||
.allMatch(entry -> node.getReferrers().parallelStream()
|
||||
.anyMatch(parent -> parent.hasTag(entry.getKey(), entry.getValue()))))
|
||||
.forEach(node -> node.getKeys().entrySet().parallelStream().map(Entry::getKey)
|
||||
.filter(key -> key.contains("source")).forEach(node::remove));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove ways that have already been added to an OSM layer
|
||||
*
|
||||
* @param dataSet The dataset with potential duplicate ways (it is modified)
|
||||
*/
|
||||
public static void removeAlreadyAddedData(DataSet dataSet) {
|
||||
final List<DataSet> osmData = MainApplication.getLayerManager().getLayersOfType(OsmDataLayer.class)
|
||||
.parallelStream().map(OsmDataLayer::getDataSet).filter(ds -> !ds.equals(dataSet))
|
||||
.collect(Collectors.toList());
|
||||
dataSet.getWays().parallelStream().filter(way -> !way.isDeleted())
|
||||
.filter(way -> osmData.stream().anyMatch(ds -> checkIfPrimitiveDuplicatesPrimitiveInDataSet(way, ds)))
|
||||
.forEach(way -> {
|
||||
final List<Node> nodes = way.getNodes();
|
||||
DeleteCommand.delete(Collections.singleton(way), true, true).executeCommand();
|
||||
nodes.parallelStream()
|
||||
.filter(node -> !node.isDeleted()
|
||||
&& node.getReferrers().parallelStream().allMatch(OsmPrimitive::isDeleted))
|
||||
.forEach(node -> node.setDeleted(true));
|
||||
});
|
||||
.filter(way -> osmData.stream().anyMatch(ds -> checkIfPrimitiveDuplicatesPrimitiveInDataSet(way, ds)))
|
||||
.forEach(way -> {
|
||||
final List<Node> nodes = way.getNodes();
|
||||
DeleteCommand.delete(Collections.singleton(way), true, true).executeCommand();
|
||||
nodes.parallelStream()
|
||||
.filter(node -> !node.isDeleted()
|
||||
&& node.getReferrers().parallelStream().allMatch(OsmPrimitive::isDeleted))
|
||||
.forEach(node -> node.setDeleted(true));
|
||||
});
|
||||
}
|
||||
|
||||
private static boolean checkIfPrimitiveDuplicatesPrimitiveInDataSet(OsmPrimitive primitive, DataSet ds) {
|
||||
|
@ -251,7 +278,7 @@ public class GetDataRunnable extends RecursiveTask<DataSet> implements CancelLis
|
|||
*/
|
||||
public static void removeCommonTags(DataSet dataSet) {
|
||||
dataSet.allPrimitives().parallelStream().filter(prim -> prim.hasKey(MergeDuplicateWays.ORIG_ID))
|
||||
.forEach(prim -> prim.remove(MergeDuplicateWays.ORIG_ID));
|
||||
.forEach(prim -> prim.remove(MergeDuplicateWays.ORIG_ID));
|
||||
dataSet.getNodes().parallelStream().forEach(node -> node.remove(SERVER_ID_KEY));
|
||||
final List<Node> emptyNodes = dataSet.getNodes().parallelStream().distinct().filter(node -> !node.isDeleted())
|
||||
.filter(node -> node.getReferrers().isEmpty() && !node.hasKeys()).collect(Collectors.toList());
|
||||
|
@ -296,7 +323,7 @@ public class GetDataRunnable extends RecursiveTask<DataSet> implements CancelLis
|
|||
.collect(Collectors.toList());
|
||||
way1.getNodePairs(false);
|
||||
nearbyWays.parallelStream().flatMap(way2 -> checkWayDuplications(way1, way2).entrySet().parallelStream())
|
||||
.forEach(GetDataRunnable::addMissingElement);
|
||||
.forEach(GetDataRunnable::addMissingElement);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -399,7 +426,7 @@ public class GetDataRunnable extends RecursiveTask<DataSet> implements CancelLis
|
|||
private static DataSet getDataReal(BBox bbox, ProgressMonitor monitor) {
|
||||
final DataSet dataSet = new DataSet();
|
||||
final List<Map<String, String>> urlMaps = MapWithAIPreferenceHelper.getMapWithAIUrl().stream()
|
||||
.map(map -> new TreeMap<>(map)).collect(Collectors.toList());
|
||||
.map(TreeMap::new).collect(Collectors.toList());
|
||||
if (DetectTaskingManagerUtils.hasTaskingManagerLayer()) {
|
||||
urlMaps.forEach(map -> map.put("url", map.get("url").concat("&crop_bbox={crop_bbox}")));
|
||||
}
|
||||
|
@ -424,6 +451,14 @@ public class GetDataRunnable extends RecursiveTask<DataSet> implements CancelLis
|
|||
return dataSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add information to the user agent and then perform the actual internet call
|
||||
*
|
||||
* @param client The HttpClient
|
||||
* @param dataSet The dataset to add data to
|
||||
* @param source The source of the data (added as a tag to "whole" objects)
|
||||
* @param monitor The monitor (so we know when a cancellation has occurred)
|
||||
*/
|
||||
private static void clientCall(HttpClient client, DataSet dataSet, String source, ProgressMonitor monitor) {
|
||||
final StringBuilder defaultUserAgent = new StringBuilder();
|
||||
client.setReadTimeout(DEFAULT_TIMEOUT);
|
||||
|
@ -434,23 +469,49 @@ public class GetDataRunnable extends RecursiveTask<DataSet> implements CancelLis
|
|||
defaultUserAgent.append(tr("/ {0} {1}", MapWithAIPlugin.NAME, MapWithAIPlugin.getVersionInfo()));
|
||||
client.setHeader("User-Agent", defaultUserAgent.toString());
|
||||
if (!monitor.isCanceled()) {
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
Logging.debug("{0}: Getting {1}", MapWithAIPlugin.NAME, client.getURL().toString());
|
||||
final Response response = client.connect();
|
||||
inputStream = response.getContent();
|
||||
final DataSet mergeData = OsmReaderCustom.parseDataSet(inputStream, null, true);
|
||||
addMapWithAISourceTag(mergeData, source);
|
||||
dataSet.mergeFrom(mergeData);
|
||||
response.disconnect();
|
||||
} catch (final SocketException e) {
|
||||
if (!monitor.isCanceled()) {
|
||||
clientCallInternet(client, dataSet, source, monitor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add perform an internet request to add data to a dataset
|
||||
*
|
||||
* @param client The HttpClient
|
||||
* @param dataSet The dataset to add data to
|
||||
* @param source The source of the data (added as a tag to "whole" objects)
|
||||
* @param monitor The monitor (so we know when a cancellation has occurred)
|
||||
*/
|
||||
private static void clientCallInternet(HttpClient client, DataSet dataSet, String source, ProgressMonitor monitor) {
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
Logging.debug("{0}: Getting {1}", MapWithAIPlugin.NAME, client.getURL().toString());
|
||||
final Response response = client.connect();
|
||||
inputStream = response.getContent();
|
||||
final DataSet mergeData = OsmReaderCustom.parseDataSet(inputStream, null, true);
|
||||
addMapWithAISourceTag(mergeData, source);
|
||||
dataSet.mergeFrom(mergeData);
|
||||
response.disconnect();
|
||||
} catch (final SocketException e) {
|
||||
if (!monitor.isCanceled()) {
|
||||
Logging.debug(e);
|
||||
}
|
||||
} catch (final SSLException e) {
|
||||
Logging.debug(e);
|
||||
new Notification(tr("{0}: Bad SSL Certificate: {1}", MapWithAIPlugin.NAME, client.getURL()))
|
||||
.setDuration(Notification.TIME_DEFAULT).show();
|
||||
} catch (UnsupportedOperationException | IllegalDataException | IOException e) {
|
||||
Logging.debug(e);
|
||||
} finally {
|
||||
if (inputStream != null) {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (final IOException e) {
|
||||
Logging.debug(e);
|
||||
}
|
||||
} catch (final SSLException e) {
|
||||
Logging.debug(e);
|
||||
new Notification(tr("{0}: Bad SSL Certificate: {1}", MapWithAIPlugin.NAME, client.getURL()))
|
||||
.setDuration(Notification.TIME_DEFAULT).show();
|
||||
.setDuration(Notification.TIME_DEFAULT).show();
|
||||
} catch (UnsupportedOperationException | IllegalDataException | IOException e) {
|
||||
Logging.debug(e);
|
||||
} finally {
|
||||
|
@ -470,13 +531,13 @@ public class GetDataRunnable extends RecursiveTask<DataSet> implements CancelLis
|
|||
* @param source The source to associate with the data
|
||||
* @return The dataset for easy chaining
|
||||
*/
|
||||
protected static DataSet addMapWithAISourceTag(DataSet dataSet, String source) {
|
||||
public static DataSet addMapWithAISourceTag(DataSet dataSet, String source) {
|
||||
dataSet.getNodes().parallelStream().filter(node -> !node.isDeleted() && node.getReferrers().isEmpty())
|
||||
.forEach(node -> node.put(MAPWITHAI_SOURCE_TAG_KEY, source));
|
||||
.forEach(node -> node.put(MAPWITHAI_SOURCE_TAG_KEY, source));
|
||||
dataSet.getWays().parallelStream().filter(way -> !way.isDeleted())
|
||||
.forEach(way -> way.put(MAPWITHAI_SOURCE_TAG_KEY, source));
|
||||
.forEach(way -> way.put(MAPWITHAI_SOURCE_TAG_KEY, source));
|
||||
dataSet.getRelations().parallelStream().filter(rel -> !rel.isDeleted())
|
||||
.forEach(rel -> rel.put(MAPWITHAI_SOURCE_TAG_KEY, source));
|
||||
.forEach(rel -> rel.put(MAPWITHAI_SOURCE_TAG_KEY, source));
|
||||
return dataSet;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,148 +0,0 @@
|
|||
// License: GPL. For details, see LICENSE file.
|
||||
package org.openstreetmap.josm.plugins.mapwithai.backend;
|
||||
|
||||
import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
|
||||
import static org.openstreetmap.josm.tools.I18n.tr;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import org.openstreetmap.josm.actions.JosmAction;
|
||||
import org.openstreetmap.josm.data.Bounds;
|
||||
import org.openstreetmap.josm.data.coor.LatLon;
|
||||
import org.openstreetmap.josm.data.osm.BBox;
|
||||
import org.openstreetmap.josm.gui.ExtendedDialog;
|
||||
import org.openstreetmap.josm.gui.MainApplication;
|
||||
import org.openstreetmap.josm.gui.MapView;
|
||||
import org.openstreetmap.josm.gui.datatransfer.ClipboardUtils;
|
||||
import org.openstreetmap.josm.gui.layer.GpxLayer;
|
||||
import org.openstreetmap.josm.gui.widgets.JosmTextField;
|
||||
import org.openstreetmap.josm.gui.widgets.SelectAllOnFocusGainedDecorator;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.MapWithAIPlugin;
|
||||
import org.openstreetmap.josm.spi.preferences.Config;
|
||||
import org.openstreetmap.josm.tools.GBC;
|
||||
import org.openstreetmap.josm.tools.OsmUrlToBounds;
|
||||
import org.openstreetmap.josm.tools.Shortcut;
|
||||
|
||||
/**
|
||||
* @author Taylor Smock
|
||||
*/
|
||||
public class MapWithAIArbitraryAction extends JosmAction {
|
||||
private static final long serialVersionUID = 9048113038651190619L;
|
||||
|
||||
private final transient JosmTextField lowerLat = new JosmTextField();
|
||||
private final transient JosmTextField upperLat = new JosmTextField();
|
||||
private final transient JosmTextField leftLon = new JosmTextField();
|
||||
private final transient JosmTextField rightLon = new JosmTextField();
|
||||
private final transient JCheckBox checkbox = new JCheckBox();
|
||||
|
||||
private static final String ARBITRARY_DATA_STRING = tr("Get arbitrary data from {0}", MapWithAIPlugin.NAME);
|
||||
|
||||
public MapWithAIArbitraryAction() {
|
||||
super(tr("{0}: Download arbitrary data", MapWithAIPlugin.NAME), "mapwithai", tr(ARBITRARY_DATA_STRING),
|
||||
Shortcut.registerShortcut("data:arbitrarymapwithai",
|
||||
tr("Data: Arbitrary {0} Data", tr(ARBITRARY_DATA_STRING)), KeyEvent.VK_R,
|
||||
Shortcut.ALT_CTRL_SHIFT),
|
||||
true);
|
||||
setHelpId(ht("Plugin/MapWithAI#BasicUsage"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
showDownloadDialog();
|
||||
}
|
||||
|
||||
static class MapWithAIArbitraryDialog extends ExtendedDialog {
|
||||
private static final long serialVersionUID = 2795301151521238635L;
|
||||
|
||||
MapWithAIArbitraryDialog(String[] buttons, JPanel panel) {
|
||||
super(MainApplication.getMainFrame(), tr(ARBITRARY_DATA_STRING), buttons);
|
||||
setButtonIcons("ok", "cancel");
|
||||
configureContextsensitiveHelp(ht("Plugin/MapWithAI#BasicUsage"), true);
|
||||
setContent(panel);
|
||||
setCancelButton(2);
|
||||
}
|
||||
}
|
||||
|
||||
public void showDownloadDialog() {
|
||||
final Optional<Bounds> boundsFromClipboard = Optional.ofNullable(ClipboardUtils.getClipboardStringContent())
|
||||
.map(OsmUrlToBounds::parse);
|
||||
if (boundsFromClipboard.isPresent() && Config.getPref().getBoolean("jumpto.use.clipboard", true)) {
|
||||
setBounds(boundsFromClipboard.get());
|
||||
} else if (MainApplication.isDisplayingMapView()) {
|
||||
final MapView mv = MainApplication.getMap().mapView;
|
||||
setBounds(mv.getState().getViewArea().getCornerBounds());
|
||||
}
|
||||
|
||||
final JPanel panel = new JPanel(new BorderLayout());
|
||||
panel.add(new JLabel(
|
||||
"<html>" + tr("Enter Lat/Lon to download {0} data.", MapWithAIPlugin.NAME) + "<br>" + "</html>"),
|
||||
BorderLayout.NORTH);
|
||||
|
||||
SelectAllOnFocusGainedDecorator.decorate(lowerLat);
|
||||
SelectAllOnFocusGainedDecorator.decorate(leftLon);
|
||||
|
||||
final JPanel p = new JPanel(new GridBagLayout());
|
||||
panel.add(p, BorderLayout.NORTH);
|
||||
|
||||
p.add(new JLabel(tr("Lower Latitude")), GBC.eol());
|
||||
p.add(lowerLat, GBC.eol().fill(GridBagConstraints.HORIZONTAL));
|
||||
|
||||
p.add(new JLabel(tr("Left Longitude")), GBC.eol());
|
||||
p.add(leftLon, GBC.eol().fill(GridBagConstraints.HORIZONTAL));
|
||||
p.add(new JLabel(tr("Upper Latitude")), GBC.eol());
|
||||
p.add(upperLat, GBC.eol().fill(GridBagConstraints.HORIZONTAL));
|
||||
p.add(new JLabel(tr("Right Longitude")), GBC.eol());
|
||||
p.add(rightLon, GBC.eol().fill(GridBagConstraints.HORIZONTAL));
|
||||
|
||||
p.add(new JLabel(tr("Crop to download area?")));
|
||||
p.add(checkbox, GBC.eol());
|
||||
|
||||
final String[] buttons = { tr("Download"), tr("Cancel") };
|
||||
BBox bbox = new BBox();
|
||||
while (!bbox.isInWorld()) {
|
||||
final int option = new MapWithAIArbitraryDialog(buttons, panel).showDialog().getValue();
|
||||
if (option != 1) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
bbox = new BBox();
|
||||
bbox.add(new LatLon(Double.parseDouble(lowerLat.getText()), Double.parseDouble(leftLon.getText())));
|
||||
bbox.add(new LatLon(Double.parseDouble(upperLat.getText()), Double.parseDouble(rightLon.getText())));
|
||||
} catch (final NumberFormatException e) {
|
||||
JOptionPane.showMessageDialog(MainApplication.getMainFrame(),
|
||||
tr("Could not parse Latitude or Longitude. Please check."), tr("Unable to parse Lon/Lat"),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
bbox = new BBox();
|
||||
}
|
||||
}
|
||||
|
||||
if (checkbox.isSelected()) {
|
||||
MainApplication.getLayerManager()
|
||||
.addLayer(new GpxLayer(DetectTaskingManagerUtils.createTaskingManagerGpxData(bbox),
|
||||
DetectTaskingManagerUtils.MAPWITHAI_CROP_AREA));
|
||||
}
|
||||
|
||||
MapWithAIDataUtils.getMapWithAIData(MapWithAIDataUtils.getLayer(true), bbox);
|
||||
}
|
||||
|
||||
private void setBounds(Bounds b) {
|
||||
if (b != null) {
|
||||
final LatLon min = b.getMin();
|
||||
final LatLon max = b.getMax();
|
||||
lowerLat.setText(Double.toString(min.lat()));
|
||||
leftLon.setText(Double.toString(min.lon()));
|
||||
rightLon.setText(Double.toString(max.lon()));
|
||||
upperLat.setText(Double.toString(max.lat()));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -45,6 +45,7 @@ import org.openstreetmap.josm.tools.Utils;
|
|||
*
|
||||
*/
|
||||
public final class MapWithAIDataUtils {
|
||||
/** THe maximum dimensions for MapWithAI data (in kilometers) */
|
||||
public static final int MAXIMUM_SIDE_DIMENSIONS = 10_000; // RapiD is about 1km, max is 10km
|
||||
private static final int TOO_MANY_BBOXES = 4;
|
||||
private static ForkJoinPool forkJoinPool;
|
||||
|
@ -69,7 +70,7 @@ public final class MapWithAIDataUtils {
|
|||
"https://gitlab.com/smocktaylor/rapid/raw/master/src/resources/styles/standard/rapid.mapcss",
|
||||
"resource://styles/standard/mapwithai.mapcss");
|
||||
new ArrayList<>(MapPaintStyles.getStyles().getStyleSources()).parallelStream()
|
||||
.filter(style -> oldUrls.contains(style.url)).forEach(MapPaintStyles::removeStyle);
|
||||
.filter(style -> oldUrls.contains(style.url)).forEach(MapPaintStyles::removeStyle);
|
||||
|
||||
if (!checkIfMapWithAIPaintStyleExists()) {
|
||||
final MapCSSStyleSource style = new MapCSSStyleSource(paintStyleResourceUrl, MapWithAIPlugin.NAME,
|
||||
|
@ -172,15 +173,15 @@ public final class MapWithAIDataUtils {
|
|||
} else {
|
||||
final Notification noUrls = MapWithAIPreferenceHelper.getMapWithAIURLs().isEmpty()
|
||||
? new Notification(tr("There are no defined URLs. To get the defaults, restart JOSM"))
|
||||
: new Notification(tr("No URLS are enabled"));
|
||||
noUrls.setDuration(Notification.TIME_DEFAULT);
|
||||
noUrls.setIcon(JOptionPane.INFORMATION_MESSAGE);
|
||||
noUrls.setHelpTopic(ht("Plugin/MapWithAI#Preferences"));
|
||||
if (SwingUtilities.isEventDispatchThread()) {
|
||||
noUrls.show();
|
||||
} else {
|
||||
SwingUtilities.invokeLater(noUrls::show);
|
||||
}
|
||||
: new Notification(tr("No URLS are enabled"));
|
||||
noUrls.setDuration(Notification.TIME_DEFAULT);
|
||||
noUrls.setIcon(JOptionPane.INFORMATION_MESSAGE);
|
||||
noUrls.setHelpTopic(ht("Plugin/MapWithAI#Preferences"));
|
||||
if (SwingUtilities.isEventDispatchThread()) {
|
||||
noUrls.show();
|
||||
} else {
|
||||
SwingUtilities.invokeLater(noUrls::show);
|
||||
}
|
||||
}
|
||||
return dataSet;
|
||||
}
|
||||
|
@ -291,7 +292,7 @@ public final class MapWithAIDataUtils {
|
|||
lock.lock();
|
||||
try {
|
||||
mapWithAISet.mergeFrom(newData);
|
||||
GetDataRunnable.cleanup(mapWithAISet);
|
||||
GetDataRunnable.cleanup(mapWithAISet, null);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import javax.swing.JLabel;
|
|||
import javax.swing.JPanel;
|
||||
import javax.swing.SwingConstants;
|
||||
|
||||
import org.openstreetmap.josm.data.Bounds;
|
||||
import org.openstreetmap.josm.data.osm.DataSet;
|
||||
import org.openstreetmap.josm.data.osm.DownloadPolicy;
|
||||
import org.openstreetmap.josm.data.osm.UploadPolicy;
|
||||
|
@ -176,4 +177,14 @@ public class MapWithAILayer extends OsmDataLayer implements ActiveLayerChangeLis
|
|||
return ImageProvider.getIfAvailable("mapwithai") == null ? super.getIcon()
|
||||
: ImageProvider.get("mapwithai", ImageProvider.ImageSizes.LAYER);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call after download from server
|
||||
*
|
||||
* @param bounds The newly added bounds
|
||||
*/
|
||||
public void onPostDownloadFromServer(Bounds bounds) {
|
||||
super.onPostDownloadFromServer();
|
||||
GetDataRunnable.cleanup(getDataSet(), bounds);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,14 +47,15 @@ public final class MapWithAIPreferenceHelper {
|
|||
/**
|
||||
* Get the current MapWithAI urls
|
||||
*
|
||||
* @return A list of enabled MapWithAI urls
|
||||
* @return A list of enabled MapWithAI urls (maps have source, parameters,
|
||||
* enabled, and the url)
|
||||
*/
|
||||
public static List<Map<String, String>> getMapWithAIUrl() {
|
||||
final MapWithAILayer layer = MapWithAIDataUtils.getLayer(false);
|
||||
return (layer != null) && (layer.getMapWithAIUrl() != null)
|
||||
? getMapWithAIURLs().parallelStream().filter(map -> layer.getMapWithAIUrl().equals(map.get(URL_STRING)))
|
||||
.collect(Collectors.toList())
|
||||
: getMapWithAIURLs().stream()
|
||||
: getMapWithAIURLs().stream()
|
||||
.filter(map -> Boolean.valueOf(map.getOrDefault(ENABLED_STRING, Boolean.FALSE.toString())))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
@ -62,11 +63,12 @@ public final class MapWithAIPreferenceHelper {
|
|||
/**
|
||||
* Get all of the MapWithAI urls (or the default)
|
||||
*
|
||||
* @return The urls for MapWithAI endpoints
|
||||
* @return The urls for MapWithAI endpoints (maps have source, parameters,
|
||||
* enabled, and the url)
|
||||
*/
|
||||
public static List<Map<String, String>> getMapWithAIURLs() {
|
||||
final List<Map<String, String>> returnMap = Config.getPref().getListOfMaps(API_MAP_CONFIG, new ArrayList<>())
|
||||
.stream().map(map -> new TreeMap<>(map)).collect(Collectors.toList());
|
||||
.stream().map(TreeMap::new).collect(Collectors.toList());
|
||||
if (returnMap.isEmpty()) {
|
||||
final List<String> defaultAPIs = Collections.singletonList(DEFAULT_MAPWITHAI_API);
|
||||
final List<String> defaultList = Config.getPref().getList(API_CONFIG).isEmpty() ? defaultAPIs
|
||||
|
|
|
@ -20,6 +20,7 @@ import org.openstreetmap.josm.command.ChangeCommand;
|
|||
import org.openstreetmap.josm.command.Command;
|
||||
import org.openstreetmap.josm.command.DeleteCommand;
|
||||
import org.openstreetmap.josm.command.SequenceCommand;
|
||||
import org.openstreetmap.josm.data.Bounds;
|
||||
import org.openstreetmap.josm.data.osm.DataSet;
|
||||
import org.openstreetmap.josm.data.osm.Node;
|
||||
import org.openstreetmap.josm.data.osm.OsmPrimitive;
|
||||
|
@ -37,6 +38,8 @@ public class MergeDuplicateWays extends Command {
|
|||
private final List<Command> commands;
|
||||
private Command command;
|
||||
|
||||
private Bounds bound;
|
||||
|
||||
public MergeDuplicateWays(DataSet data) {
|
||||
this(data, null, null);
|
||||
}
|
||||
|
@ -64,7 +67,7 @@ public class MergeDuplicateWays extends Command {
|
|||
public boolean executeCommand() {
|
||||
if (commands.isEmpty() || (command == null)) {
|
||||
if ((way1 == null) && (way2 == null)) {
|
||||
filterDataSet(getAffectedDataSet(), commands);
|
||||
filterDataSet(getAffectedDataSet(), commands, bound);
|
||||
} else if ((way1 != null) && (way2 == null)) {
|
||||
checkForDuplicateWays(way1, commands);
|
||||
} else if (way1 == null) {
|
||||
|
@ -98,8 +101,18 @@ public class MergeDuplicateWays extends Command {
|
|||
}
|
||||
}
|
||||
|
||||
public static void filterDataSet(DataSet dataSet, List<Command> commands) {
|
||||
final List<Way> ways = new ArrayList<>(dataSet.getWays().parallelStream()
|
||||
/**
|
||||
* Set the bounds for the command. Must be called before execution.
|
||||
*
|
||||
* @param bound The boundary for the command
|
||||
*/
|
||||
public void setBounds(Bounds bound) {
|
||||
this.bound = bound;
|
||||
}
|
||||
|
||||
public static void filterDataSet(DataSet dataSet, List<Command> commands, Bounds bound) {
|
||||
final List<Way> ways = new ArrayList<>(
|
||||
(bound == null ? dataSet.getWays() : dataSet.searchWays(bound.toBBox())).parallelStream()
|
||||
.filter(prim -> !prim.isIncomplete() && !prim.isDeleted()).collect(Collectors.toList()));
|
||||
for (int i = 0; i < ways.size(); i++) {
|
||||
final Way way1 = ways.get(i);
|
||||
|
|
|
@ -0,0 +1,194 @@
|
|||
// License: GPL. For details, see LICENSE file.
|
||||
package org.openstreetmap.josm.plugins.mapwithai.frontend;
|
||||
|
||||
import static org.openstreetmap.josm.tools.I18n.tr;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.json.JsonObject;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JOptionPane;
|
||||
|
||||
import org.openstreetmap.josm.actions.downloadtasks.DownloadParams;
|
||||
import org.openstreetmap.josm.actions.downloadtasks.PostDownloadHandler;
|
||||
import org.openstreetmap.josm.data.Bounds;
|
||||
import org.openstreetmap.josm.data.coor.LatLon;
|
||||
import org.openstreetmap.josm.gui.MainApplication;
|
||||
import org.openstreetmap.josm.gui.download.AbstractDownloadSourcePanel;
|
||||
import org.openstreetmap.josm.gui.download.DownloadDialog;
|
||||
import org.openstreetmap.josm.gui.download.DownloadSettings;
|
||||
import org.openstreetmap.josm.gui.download.DownloadSource;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.MapWithAIPlugin;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.backend.BoundingBoxMapWithAIDownloader;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.backend.DetectTaskingManagerUtils;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.backend.DownloadMapWithAITask;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAIDataUtils;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAIPreferenceHelper;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.backend.commands.conflation.DataUrl;
|
||||
import org.openstreetmap.josm.tools.GBC;
|
||||
import org.openstreetmap.josm.tools.ImageProvider;
|
||||
|
||||
public class MapWithAIDownloadReader implements DownloadSource<MapWithAIDownloadReader.MapWithAIDownloadData> {
|
||||
|
||||
|
||||
@Override
|
||||
public AbstractDownloadSourcePanel<MapWithAIDownloadData> createPanel(DownloadDialog dialog) {
|
||||
return new MapWithAIDownloadPanel(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doDownload(MapWithAIDownloadData data, DownloadSettings settings) {
|
||||
Bounds area = settings.getDownloadBounds().orElse(new Bounds(0, 0, 0, 0));
|
||||
DownloadMapWithAITask task = new DownloadMapWithAITask();
|
||||
task.setZoomAfterDownload(settings.zoomToData());
|
||||
data.getUrls().forEach(url -> {
|
||||
Future<?> future = task.download(new BoundingBoxMapWithAIDownloader(area, getUrl(url),
|
||||
DetectTaskingManagerUtils.hasTaskingManagerLayer()), new DownloadParams(), area, null);
|
||||
MainApplication.worker.execute(new PostDownloadHandler(task, future, data.getErrorReporter()));
|
||||
});
|
||||
}
|
||||
|
||||
private String getUrl(Map<String, String> urlInformation) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (urlInformation.containsKey("url")) {
|
||||
sb.append(urlInformation.get("url"));
|
||||
if (urlInformation.containsKey("parameters")) {
|
||||
List<String> parameters = DataUrl.readJsonStringArraySimple(urlInformation.get("parameters"))
|
||||
.parallelStream()
|
||||
.filter(JsonObject.class::isInstance).map(JsonObject.class::cast)
|
||||
.filter(map -> map.getBoolean("enabled", false)).filter(map -> map.containsKey("parameter"))
|
||||
.map(map -> map.getString("parameter")).collect(Collectors.toList());
|
||||
if (!parameters.isEmpty()) {
|
||||
sb.append("&").append(String.join("&", parameters));
|
||||
}
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLabel() {
|
||||
return tr("Download from {0} API", MapWithAIPlugin.NAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onlyExpert() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encapsulates data that is required to perform download from MapWithAI API
|
||||
*/
|
||||
static class MapWithAIDownloadData {
|
||||
private final List<Map<String, String>> url;
|
||||
private final Consumer<Collection<Object>> errorReporter;
|
||||
|
||||
MapWithAIDownloadData(List<Map<String, String>> list, Consumer<Collection<Object>> errorReporter) {
|
||||
this.url = list;
|
||||
this.errorReporter = errorReporter;
|
||||
}
|
||||
|
||||
List<Map<String, String>> getUrls() {
|
||||
return url;
|
||||
}
|
||||
|
||||
Consumer<Collection<Object>> getErrorReporter() {
|
||||
return errorReporter;
|
||||
}
|
||||
}
|
||||
|
||||
public static class MapWithAIDownloadPanel extends AbstractDownloadSourcePanel<MapWithAIDownloadData> {
|
||||
private static final long serialVersionUID = -6934457612643307520L;
|
||||
private final JLabel sizeCheck = new JLabel();
|
||||
|
||||
public MapWithAIDownloadPanel(MapWithAIDownloadReader downloadReader) {
|
||||
super(downloadReader);
|
||||
setLayout(new GridBagLayout());
|
||||
|
||||
Font labelFont = sizeCheck.getFont();
|
||||
sizeCheck.setFont(labelFont.deriveFont(Font.PLAIN, labelFont.getSize()));
|
||||
add(sizeCheck, GBC.eol().anchor(GridBagConstraints.EAST).insets(5, 5, 5, 2));
|
||||
setMinimumSize(new Dimension(450, 115));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapWithAIDownloadData getData() {
|
||||
Consumer<Collection<Object>> errorReporter = errors -> {
|
||||
boolean onlyNoDataError = errors.size() == 1 && errors.contains("No data found in this area.");
|
||||
};
|
||||
return new MapWithAIDownloadData(MapWithAIPreferenceHelper.getMapWithAIUrl(), errorReporter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void rememberSettings() {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreSettings() {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkDownload(DownloadSettings settings) {
|
||||
if (!settings.getDownloadBounds().isPresent()) {
|
||||
JOptionPane.showMessageDialog(this.getParent(), tr("Please select a download area first."), tr("Error"),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
return settings.getDownloadBounds().isPresent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSimpleName() {
|
||||
return "mapwithaidownloadpanel";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getIcon() {
|
||||
return new ImageProvider("dialogs", "mapwithai")
|
||||
.setMaxHeight(ImageProvider.ImageSizes.SIDEBUTTON.getVirtualHeight()).get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void boundingBoxChanged(Bounds bbox) {
|
||||
updateSizeCheck(bbox);
|
||||
}
|
||||
|
||||
private void updateSizeCheck(Bounds bbox) {
|
||||
if (bbox == null) {
|
||||
sizeCheck.setText(tr("No area selected yet"));
|
||||
sizeCheck.setForeground(Color.darkGray);
|
||||
return;
|
||||
}
|
||||
|
||||
double width = Math.max(bbox.getMin().greatCircleDistance(new LatLon(bbox.getMinLat(), bbox.getMaxLon())),
|
||||
bbox.getMax().greatCircleDistance(new LatLon(bbox.getMaxLat(), bbox.getMinLon())));
|
||||
double height = Math.max(bbox.getMin().greatCircleDistance(new LatLon(bbox.getMaxLat(), bbox.getMinLon())),
|
||||
bbox.getMax().greatCircleDistance(new LatLon(bbox.getMinLat(), bbox.getMaxLon())));
|
||||
displaySizeCheckResult(height > MapWithAIDataUtils.MAXIMUM_SIDE_DIMENSIONS
|
||||
|| width > MapWithAIDataUtils.MAXIMUM_SIDE_DIMENSIONS);
|
||||
}
|
||||
|
||||
private void displaySizeCheckResult(boolean isAreaTooLarge) {
|
||||
if (isAreaTooLarge) {
|
||||
sizeCheck.setText(tr("Download area too large; will probably be rejected by server"));
|
||||
sizeCheck.setForeground(Color.red);
|
||||
} else {
|
||||
sizeCheck.setText(tr("Download area ok, size probably acceptable to server"));
|
||||
sizeCheck.setForeground(Color.darkGray);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because one or more lines are too long
|
@ -75,11 +75,11 @@ public class MapWithAIPluginTest {
|
|||
*/
|
||||
@Test
|
||||
public void testMapWithAIPlugin() {
|
||||
final int addedMenuItems = 3;
|
||||
final JMenu dataMenu = MainApplication.getMenu().dataMenu;
|
||||
final int dataMenuSize = dataMenu.getMenuComponentCount();
|
||||
plugin = new MapWithAIPlugin(info);
|
||||
Assert.assertEquals(dataMenuSize + 4, dataMenu.getMenuComponentCount());
|
||||
MapPaintStyles.getStyles().getStyleSources().forEach(style -> Logging.error(style.toString()));
|
||||
Assert.assertEquals(dataMenuSize + addedMenuItems, dataMenu.getMenuComponentCount());
|
||||
Assert.assertEquals(1, MapPaintStyles.getStyles().getStyleSources().parallelStream()
|
||||
.filter(source -> source.url != null && source.name.contains("MapWithAI")).count());
|
||||
|
||||
|
@ -89,15 +89,15 @@ public class MapWithAIPluginTest {
|
|||
plugin.destroy();
|
||||
Assert.assertEquals(dataMenuSize, dataMenu.getMenuComponentCount());
|
||||
Awaitility.await().atMost(Durations.FIVE_SECONDS)
|
||||
.until(() -> existed == MapWithAIDataUtils.checkIfMapWithAIPaintStyleExists());
|
||||
.until(() -> existed == MapWithAIDataUtils.checkIfMapWithAIPaintStyleExists());
|
||||
Assert.assertEquals(Config.getPref().getBoolean(MapWithAIPlugin.PAINTSTYLE_PREEXISTS) ? 1 : 0,
|
||||
MapPaintStyles.getStyles().getStyleSources().parallelStream()
|
||||
.filter(source -> source.url != null && source.name.contains("MapWithAI")).count());
|
||||
.filter(source -> source.url != null && source.name.contains("MapWithAI")).count());
|
||||
}
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
plugin = new MapWithAIPlugin(info);
|
||||
Assert.assertEquals(dataMenuSize + 4, dataMenu.getMenuComponentCount());
|
||||
Assert.assertEquals(dataMenuSize + addedMenuItems, dataMenu.getMenuComponentCount());
|
||||
Assert.assertEquals(1, MapPaintStyles.getStyles().getStyleSources().parallelStream()
|
||||
.filter(source -> source.url != null && source.name.contains("MapWithAI")).count());
|
||||
}
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
// License: GPL. For details, see LICENSE file.
|
||||
package org.openstreetmap.josm.plugins.mapwithai.frontend;
|
||||
|
||||
import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.openstreetmap.josm.tools.I18n.tr;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.awaitility.Awaitility;
|
||||
import org.awaitility.Durations;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.openstreetmap.josm.data.Bounds;
|
||||
import org.openstreetmap.josm.gui.download.DownloadSettings;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.MapWithAIPlugin;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAIDataUtils;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAIPreferenceHelper;
|
||||
import org.openstreetmap.josm.testutils.JOSMTestRules;
|
||||
|
||||
import com.github.tomakehurst.wiremock.WireMockServer;
|
||||
|
||||
public class MapWithAIDownloadReaderTest {
|
||||
@Rule
|
||||
public JOSMTestRules rules = new JOSMTestRules().projection();
|
||||
|
||||
WireMockServer wireMock = new WireMockServer(options().usingFilesUnderDirectory("test/resources/wiremock"));
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
wireMock.start();
|
||||
MapWithAIPreferenceHelper.setMapWithAIURLs(MapWithAIPreferenceHelper.getMapWithAIURLs().stream().map(map -> {
|
||||
map.put("url", getDefaultMapWithAIAPIForTest(
|
||||
map.getOrDefault("url", MapWithAIPreferenceHelper.DEFAULT_MAPWITHAI_API)));
|
||||
return map;
|
||||
}).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
wireMock.stop();
|
||||
}
|
||||
|
||||
private String getDefaultMapWithAIAPIForTest(String url) {
|
||||
return getDefaultMapWithAIAPIForTest(url, "https://www.facebook.com");
|
||||
}
|
||||
|
||||
private String getDefaultMapWithAIAPIForTest(String url, String wireMockReplace) {
|
||||
return url.replace(wireMockReplace, wireMock.baseUrl());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetLabel() {
|
||||
assertEquals(tr("Download from {0} API", MapWithAIPlugin.NAME), new MapWithAIDownloadReader().getLabel());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsExpert() {
|
||||
assertFalse(new MapWithAIDownloadReader().onlyExpert());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoDownload() {
|
||||
MapWithAIDownloadReader reader = new MapWithAIDownloadReader();
|
||||
DownloadSettings settings = new DownloadSettings(
|
||||
new Bounds(39.0239848, -108.4522247, 39.1066201, -108.3368683), false, false);
|
||||
MapWithAIDownloadReader.MapWithAIDownloadData data = new MapWithAIDownloadReader.MapWithAIDownloadData(
|
||||
MapWithAIPreferenceHelper.getMapWithAIUrl(), errors -> {
|
||||
});
|
||||
reader.doDownload(data, settings);
|
||||
Awaitility.await().atMost(Durations.TEN_SECONDS).until(() -> MapWithAIDataUtils.getLayer(false) != null);
|
||||
assertNotNull(MapWithAIDataUtils.getLayer(false));
|
||||
Awaitility.await().atMost(Durations.TEN_SECONDS)
|
||||
.until(() -> !MapWithAIDataUtils.getLayer(false).getDataSet().getDataSourceBounds().isEmpty());
|
||||
assertFalse(MapWithAIDataUtils.getLayer(false).getDataSet().getDataSourceBounds().isEmpty());
|
||||
assertTrue(settings.getDownloadBounds().get().toBBox().bboxIsFunctionallyEqual(
|
||||
MapWithAIDataUtils.getLayer(false).getDataSet().getDataSourceBounds().get(0).toBBox(), 0.0001));
|
||||
}
|
||||
}
|
Ładowanie…
Reference in New Issue