kopia lustrzana https://github.com/JOSM/MapWithAI
Add preference for merging building/addresses (does nothing right now)
Signed-off-by: Taylor Smock <taylor.smock@kaart.com>pull/1/head
rodzic
4d52d4bdd8
commit
0292641b3f
|
@ -18,19 +18,20 @@ import javax.swing.SpinnerNumberModel;
|
|||
import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
|
||||
import org.openstreetmap.josm.gui.preferences.SubPreferenceSetting;
|
||||
import org.openstreetmap.josm.gui.preferences.TabPreferenceSetting;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAIDataUtils;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAIPreferenceHelper;
|
||||
|
||||
public class MapWithAIPreferences implements SubPreferenceSetting {
|
||||
private final JComboBox<String> possibleMapWithAIApiUrl;
|
||||
|
||||
private final JCheckBox switchLayerCheckBox;
|
||||
|
||||
private final JCheckBox mergeBuildingAddressCheckBox;
|
||||
private final JSpinner maximumAdditionSpinner;
|
||||
|
||||
public MapWithAIPreferences() {
|
||||
possibleMapWithAIApiUrl = new JComboBox<>();
|
||||
switchLayerCheckBox = new JCheckBox();
|
||||
maximumAdditionSpinner = new JSpinner(new SpinnerNumberModel(MapWithAIDataUtils.getMaximumAddition(), 0, 100, 1));
|
||||
maximumAdditionSpinner = new JSpinner(
|
||||
new SpinnerNumberModel(MapWithAIPreferenceHelper.getMaximumAddition(), 0, 100, 1));
|
||||
mergeBuildingAddressCheckBox = new JCheckBox();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -38,6 +39,7 @@ public class MapWithAIPreferences implements SubPreferenceSetting {
|
|||
final JLabel mapWithAIApiUrl = new JLabel(tr("{0} API URL", MapWithAIPlugin.NAME));
|
||||
final JLabel switchLayer = new JLabel(tr("Automatically switch layers"));
|
||||
final JLabel maximumAddition = new JLabel(tr("Maximum features (add)"));
|
||||
final JLabel mergeBuildingWithAddress = new JLabel(tr("Merge existing address nodes onto added buildings?"));
|
||||
final JPanel container = new JPanel(new GridBagLayout());
|
||||
container.setAlignmentY(Component.TOP_ALIGNMENT);
|
||||
final GridBagConstraints constraints = new GridBagConstraints();
|
||||
|
@ -48,12 +50,13 @@ public class MapWithAIPreferences implements SubPreferenceSetting {
|
|||
if (textField instanceof JTextField) {
|
||||
((JTextField) textField).setColumns(36);
|
||||
}
|
||||
for (final String url : MapWithAIDataUtils.getMapWithAIURLs()) {
|
||||
for (final String url : MapWithAIPreferenceHelper.getMapWithAIURLs()) {
|
||||
possibleMapWithAIApiUrl.addItem(url);
|
||||
}
|
||||
possibleMapWithAIApiUrl.setSelectedItem(MapWithAIDataUtils.getMapWithAIUrl());
|
||||
possibleMapWithAIApiUrl.setSelectedItem(MapWithAIPreferenceHelper.getMapWithAIUrl());
|
||||
|
||||
switchLayerCheckBox.setSelected(MapWithAIDataUtils.isSwitchLayers());
|
||||
switchLayerCheckBox.setSelected(MapWithAIPreferenceHelper.isSwitchLayers());
|
||||
mergeBuildingAddressCheckBox.setSelected(MapWithAIPreferenceHelper.isMergeBuildingAddress());
|
||||
|
||||
constraints.gridx = 0;
|
||||
constraints.gridy = 0;
|
||||
|
@ -80,16 +83,22 @@ public class MapWithAIPreferences implements SubPreferenceSetting {
|
|||
constraints.gridx++;
|
||||
container.add(maximumAdditionSpinner, constraints);
|
||||
|
||||
constraints.gridx--;
|
||||
constraints.gridy++;
|
||||
container.add(mergeBuildingWithAddress, constraints);
|
||||
constraints.gridx++;
|
||||
container.add(mergeBuildingAddressCheckBox, constraints);
|
||||
|
||||
getTabPreferenceSetting(gui).addSubTab(this, MapWithAIPlugin.NAME, container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean ok() {
|
||||
MapWithAIDataUtils.setMapWithAIUrl((String) possibleMapWithAIApiUrl.getSelectedItem(), true);
|
||||
MapWithAIDataUtils.setSwitchLayers(switchLayerCheckBox.isSelected(), true);
|
||||
MapWithAIPreferenceHelper.setMapWithAIUrl((String) possibleMapWithAIApiUrl.getSelectedItem(), true);
|
||||
MapWithAIPreferenceHelper.setSwitchLayers(switchLayerCheckBox.isSelected(), true);
|
||||
final Object value = maximumAdditionSpinner.getValue();
|
||||
if (value instanceof Number) {
|
||||
MapWithAIDataUtils.setMaximumAddition(((Number) value).intValue(), true);
|
||||
MapWithAIPreferenceHelper.setMaximumAddition(((Number) value).intValue(), true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -118,6 +127,10 @@ public class MapWithAIPreferences implements SubPreferenceSetting {
|
|||
return switchLayerCheckBox;
|
||||
}
|
||||
|
||||
public JCheckBox getMergeBuildingAddressCheckBox() {
|
||||
return mergeBuildingAddressCheckBox;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code JSpinner} for the maximum additions
|
||||
*/
|
||||
|
|
|
@ -38,7 +38,6 @@ import org.openstreetmap.josm.gui.progress.swing.PleaseWaitProgressMonitor;
|
|||
import org.openstreetmap.josm.io.IllegalDataException;
|
||||
import org.openstreetmap.josm.io.OsmReader;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.MapWithAIPlugin;
|
||||
import org.openstreetmap.josm.spi.preferences.Config;
|
||||
import org.openstreetmap.josm.tools.HttpClient;
|
||||
import org.openstreetmap.josm.tools.HttpClient.Response;
|
||||
import org.openstreetmap.josm.tools.Logging;
|
||||
|
@ -49,9 +48,90 @@ import org.openstreetmap.josm.tools.Utils;
|
|||
*
|
||||
*/
|
||||
public final class MapWithAIDataUtils {
|
||||
public static final String DEFAULT_MAPWITHAI_API = "https://www.facebook.com/maps/ml_roads?conflate_with_osm=true&theme=ml_road_vector&collaborator=josm&token=ASb3N5o9HbX8QWn8G_NtHIRQaYv3nuG2r7_f3vnGld3KhZNCxg57IsaQyssIaEw5rfRNsPpMwg4TsnrSJtIJms5m&hash=ASawRla3rBcwEjY4HIY&result_type=road_building_vector_xml&bbox={bbox}";
|
||||
private static class GetDataRunnable extends RecursiveTask<DataSet> {
|
||||
private static final long serialVersionUID = 258423685658089715L;
|
||||
private static DataSet getDataReal(BBox bbox) {
|
||||
InputStream inputStream = null;
|
||||
final DataSet dataSet = new DataSet();
|
||||
String urlString = MapWithAIPreferenceHelper.getMapWithAIUrl();
|
||||
if (DetectTaskingManagerUtils.hasTaskingManagerLayer()) {
|
||||
urlString += "&crop_bbox={crop_bbox}";
|
||||
}
|
||||
|
||||
dataSet.setUploadPolicy(UploadPolicy.DISCOURAGED);
|
||||
|
||||
try {
|
||||
final URL url = new URL(urlString.replace("{bbox}", bbox.toStringCSV(",")).replace("{crop_bbox}",
|
||||
DetectTaskingManagerUtils.getTaskingManagerBBox().toStringCSV(",")));
|
||||
final HttpClient client = HttpClient.create(url);
|
||||
final StringBuilder defaultUserAgent = new StringBuilder();
|
||||
defaultUserAgent.append(client.getHeaders().get("User-Agent"));
|
||||
if (defaultUserAgent.toString().trim().length() == 0) {
|
||||
defaultUserAgent.append("JOSM");
|
||||
}
|
||||
defaultUserAgent.append(tr("/ {0} {1}", MapWithAIPlugin.NAME, MapWithAIPlugin.getVersionInfo()));
|
||||
client.setHeader("User-Agent", defaultUserAgent.toString());
|
||||
Logging.debug("{0}: Getting {1}", MapWithAIPlugin.NAME, client.getURL().toString());
|
||||
final Response response = client.connect();
|
||||
inputStream = response.getContent();
|
||||
final DataSet mergeData = OsmReader.parseDataSet(inputStream, null);
|
||||
dataSet.mergeFrom(mergeData);
|
||||
response.disconnect();
|
||||
} catch (UnsupportedOperationException | IllegalDataException | IOException e) {
|
||||
Logging.debug(e);
|
||||
} finally {
|
||||
if (inputStream != null) {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (final IOException e) {
|
||||
Logging.debug(e);
|
||||
}
|
||||
}
|
||||
dataSet.setUploadPolicy(UploadPolicy.BLOCKED);
|
||||
}
|
||||
return dataSet;
|
||||
}
|
||||
private final transient List<BBox> bbox;
|
||||
private final transient DataSet dataSet;
|
||||
|
||||
private final transient PleaseWaitProgressMonitor monitor;
|
||||
|
||||
public GetDataRunnable(BBox bbox, DataSet dataSet, PleaseWaitProgressMonitor monitor) {
|
||||
this(Arrays.asList(bbox), dataSet, monitor);
|
||||
}
|
||||
|
||||
public GetDataRunnable(List<BBox> bbox, DataSet dataSet, PleaseWaitProgressMonitor monitor) {
|
||||
this.bbox = bbox;
|
||||
this.dataSet = dataSet;
|
||||
this.monitor = monitor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataSet compute() {
|
||||
List<BBox> bboxes = reduceBBoxSize(bbox);
|
||||
if (bboxes.size() == 1) {
|
||||
final DataSet temporaryDataSet = getDataReal(bboxes.get(0));
|
||||
synchronized (MapWithAIDataUtils.GetDataRunnable.class) {
|
||||
dataSet.mergeFrom(temporaryDataSet);
|
||||
}
|
||||
} else {
|
||||
Collection<GetDataRunnable> tasks = bboxes.parallelStream()
|
||||
.map(tBbox -> new GetDataRunnable(tBbox, dataSet, null)).collect(Collectors.toList());
|
||||
tasks.forEach(GetDataRunnable::fork);
|
||||
tasks.forEach(GetDataRunnable::join);
|
||||
}
|
||||
if (Objects.nonNull(monitor)) {
|
||||
monitor.finishTask();
|
||||
monitor.close();
|
||||
}
|
||||
|
||||
/* Microsoft buildings don't have a source, so we add one */
|
||||
MapWithAIDataUtils.addSourceTags(dataSet, "building", "Microsoft");
|
||||
return dataSet;
|
||||
}
|
||||
}
|
||||
|
||||
public static final int MAXIMUM_SIDE_DIMENSIONS = 1000; // 1 km
|
||||
private static final int DEFAULT_MAXIMUM_ADDITION = 5;
|
||||
|
||||
private static ForkJoinPool forkJoinPool;
|
||||
|
||||
|
@ -62,26 +142,56 @@ public final class MapWithAIDataUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the first {@link MapWithAILayer} that we can find.
|
||||
*
|
||||
* @param create true if we want to create a new layer
|
||||
* @return A MapWithAILayer, or a new MapWithAILayer if none exist. May return
|
||||
* {@code null} if {@code create} is {@code false}.
|
||||
* Add a paintstyle from the jar (TODO)
|
||||
*/
|
||||
public static MapWithAILayer getLayer(boolean create) {
|
||||
final List<MapWithAILayer> mapWithAILayers = MainApplication.getLayerManager().getLayersOfType(MapWithAILayer.class);
|
||||
MapWithAILayer layer = null;
|
||||
synchronized (LAYER_LOCK) {
|
||||
if (mapWithAILayers.isEmpty() && create) {
|
||||
layer = new MapWithAILayer(new DataSet(), MapWithAIPlugin.NAME, null);
|
||||
MainApplication.getLayerManager().addLayer(layer);
|
||||
} else if (!mapWithAILayers.isEmpty()) {
|
||||
layer = mapWithAILayers.get(0);
|
||||
public static void addMapWithAIPaintStyles() {
|
||||
// TODO figure out how to use the one in the jar file
|
||||
final ExtendedSourceEntry mapWithAI = new ExtendedSourceEntry(SourceType.MAP_PAINT_STYLE, "mapwithai.mapcss",
|
||||
"https://gitlab.com/gokaart/JOSM_MapWithAI/raw/master/src/resources/styles/standard/mapwithai.mapcss");
|
||||
final List<SourceEntry> paintStyles = MapPaintPrefHelper.INSTANCE.get();
|
||||
for (final SourceEntry paintStyle : paintStyles) {
|
||||
if (mapWithAI.url.equals(paintStyle.url)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
return layer;
|
||||
paintStyles.add(mapWithAI);
|
||||
MapPaintPrefHelper.INSTANCE.put(paintStyles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add primitives and their children to a collection
|
||||
*
|
||||
* @param collection A collection to add the primitives to
|
||||
* @param primitives The primitives to add to the collection
|
||||
*/
|
||||
public static void addPrimitivesToCollection(Collection<OsmPrimitive> collection,
|
||||
Collection<OsmPrimitive> primitives) {
|
||||
final Collection<OsmPrimitive> temporaryCollection = new TreeSet<>();
|
||||
for (final OsmPrimitive primitive : primitives) {
|
||||
if (primitive instanceof Way) {
|
||||
temporaryCollection.addAll(((Way) primitive).getNodes());
|
||||
} else if (primitive instanceof Relation) {
|
||||
addPrimitivesToCollection(temporaryCollection, ((Relation) primitive).getMemberPrimitives());
|
||||
}
|
||||
temporaryCollection.add(primitive);
|
||||
}
|
||||
collection.addAll(temporaryCollection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add specified source tags to objects without a source tag that also have a
|
||||
* specific key
|
||||
*
|
||||
* @param dataSet The {#link DataSet} to look through
|
||||
* @param primaryKey The primary key that must be in the {@link OsmPrimitive}
|
||||
* @param source The specified source value (not tag)
|
||||
*/
|
||||
public static void addSourceTags(DataSet dataSet, String primaryKey, String source) {
|
||||
dataSet.allPrimitives().stream().filter(p -> p.hasKey(primaryKey) && !p.hasKey("source")).forEach(p -> {
|
||||
p.put("source", source);
|
||||
p.save();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a dataset from the API servers using a bbox
|
||||
|
@ -120,306 +230,129 @@ public final class MapWithAIDataUtils {
|
|||
return dataSet;
|
||||
}
|
||||
|
||||
private static class GetDataRunnable extends RecursiveTask<DataSet> {
|
||||
private static final long serialVersionUID = 258423685658089715L;
|
||||
private final transient List<BBox> bbox;
|
||||
private final transient DataSet dataSet;
|
||||
private final transient PleaseWaitProgressMonitor monitor;
|
||||
|
||||
public GetDataRunnable(BBox bbox, DataSet dataSet, PleaseWaitProgressMonitor monitor) {
|
||||
this(Arrays.asList(bbox), dataSet, monitor);
|
||||
/**
|
||||
* @return The {@link ForkJoinPool} for MapWithAI use.
|
||||
*/
|
||||
public static ForkJoinPool getForkJoinPool() {
|
||||
if (Objects.isNull(forkJoinPool) || forkJoinPool.isShutdown()) {
|
||||
forkJoinPool = Utils.newForkJoinPool(MapWithAIPlugin.NAME.concat(".forkjoinpoolthreads"),
|
||||
MapWithAIPlugin.NAME, Thread.NORM_PRIORITY);
|
||||
}
|
||||
return forkJoinPool;
|
||||
}
|
||||
|
||||
public GetDataRunnable(List<BBox> bbox, DataSet dataSet, PleaseWaitProgressMonitor monitor) {
|
||||
this.bbox = bbox;
|
||||
this.dataSet = dataSet;
|
||||
this.monitor = monitor;
|
||||
public static double getHeight(BBox bbox) {
|
||||
final LatLon bottomRight = bbox.getBottomRight();
|
||||
final LatLon topLeft = bbox.getTopLeft();
|
||||
final double minx = topLeft.getX();
|
||||
final double miny = bottomRight.getY();
|
||||
final LatLon bottomLeft = new LatLon(miny, minx);
|
||||
// TODO handle poles
|
||||
return topLeft.greatCircleDistance(bottomLeft);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first {@link MapWithAILayer} that we can find.
|
||||
*
|
||||
* @param create true if we want to create a new layer
|
||||
* @return A MapWithAILayer, or a new MapWithAILayer if none exist. May return
|
||||
* {@code null} if {@code create} is {@code false}.
|
||||
*/
|
||||
public static MapWithAILayer getLayer(boolean create) {
|
||||
final List<MapWithAILayer> mapWithAILayers = MainApplication.getLayerManager()
|
||||
.getLayersOfType(MapWithAILayer.class);
|
||||
MapWithAILayer layer = null;
|
||||
synchronized (LAYER_LOCK) {
|
||||
if (mapWithAILayers.isEmpty() && create) {
|
||||
layer = new MapWithAILayer(new DataSet(), MapWithAIPlugin.NAME, null);
|
||||
MainApplication.getLayerManager().addLayer(layer);
|
||||
} else if (!mapWithAILayers.isEmpty()) {
|
||||
layer = mapWithAILayers.get(0);
|
||||
}
|
||||
}
|
||||
return layer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataSet compute() {
|
||||
List<BBox> bboxes = reduceBBoxSize(bbox);
|
||||
if (bboxes.size() == 1) {
|
||||
final DataSet temporaryDataSet = getDataReal(bboxes.get(0));
|
||||
synchronized (MapWithAIDataUtils.GetDataRunnable.class) {
|
||||
dataSet.mergeFrom(temporaryDataSet);
|
||||
}
|
||||
} else {
|
||||
Collection<GetDataRunnable> tasks = bboxes.parallelStream()
|
||||
.map(tBbox -> new GetDataRunnable(tBbox, dataSet, null)).collect(Collectors.toList());
|
||||
tasks.forEach(GetDataRunnable::fork);
|
||||
tasks.forEach(GetDataRunnable::join);
|
||||
/**
|
||||
* Get data for a {@link MapWithAILayer}
|
||||
*
|
||||
* @param layer The {@link MapWithAILayer} to add data to
|
||||
*/
|
||||
public static void getMapWithAIData(MapWithAILayer layer) {
|
||||
final List<OsmDataLayer> osmLayers = MainApplication.getLayerManager().getLayersOfType(OsmDataLayer.class);
|
||||
for (final OsmDataLayer osmLayer : osmLayers) {
|
||||
if (!osmLayer.isLocked()) {
|
||||
getMapWithAIData(layer, osmLayer);
|
||||
}
|
||||
if (Objects.nonNull(monitor)) {
|
||||
monitor.finishTask();
|
||||
monitor.close();
|
||||
}
|
||||
|
||||
/* Microsoft buildings don't have a source, so we add one */
|
||||
MapWithAIDataUtils.addSourceTags(dataSet, "building", "Microsoft");
|
||||
return dataSet;
|
||||
}
|
||||
|
||||
private static DataSet getDataReal(BBox bbox) {
|
||||
InputStream inputStream = null;
|
||||
final DataSet dataSet = new DataSet();
|
||||
String urlString = getMapWithAIUrl();
|
||||
if (DetectTaskingManagerUtils.hasTaskingManagerLayer()) {
|
||||
urlString += "&crop_bbox={crop_bbox}";
|
||||
}
|
||||
|
||||
dataSet.setUploadPolicy(UploadPolicy.DISCOURAGED);
|
||||
|
||||
try {
|
||||
final URL url = new URL(urlString.replace("{bbox}", bbox.toStringCSV(",")).replace("{crop_bbox}",
|
||||
DetectTaskingManagerUtils.getTaskingManagerBBox().toStringCSV(",")));
|
||||
final HttpClient client = HttpClient.create(url);
|
||||
final StringBuilder defaultUserAgent = new StringBuilder();
|
||||
defaultUserAgent.append(client.getHeaders().get("User-Agent"));
|
||||
if (defaultUserAgent.toString().trim().length() == 0) {
|
||||
defaultUserAgent.append("JOSM");
|
||||
}
|
||||
defaultUserAgent.append(tr("/ {0} {1}", MapWithAIPlugin.NAME, MapWithAIPlugin.getVersionInfo()));
|
||||
client.setHeader("User-Agent", defaultUserAgent.toString());
|
||||
Logging.debug("{0}: Getting {1}", MapWithAIPlugin.NAME, client.getURL().toString());
|
||||
final Response response = client.connect();
|
||||
inputStream = response.getContent();
|
||||
final DataSet mergeData = OsmReader.parseDataSet(inputStream, null);
|
||||
dataSet.mergeFrom(mergeData);
|
||||
response.disconnect();
|
||||
} catch (UnsupportedOperationException | IllegalDataException | IOException e) {
|
||||
Logging.debug(e);
|
||||
} finally {
|
||||
if (inputStream != null) {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (final IOException e) {
|
||||
Logging.debug(e);
|
||||
}
|
||||
}
|
||||
dataSet.setUploadPolicy(UploadPolicy.BLOCKED);
|
||||
}
|
||||
return dataSet;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add specified source tags to objects without a source tag that also have a
|
||||
* specific key
|
||||
* Get the data for MapWithAI
|
||||
*
|
||||
* @param dataSet The {#link DataSet} to look through
|
||||
* @param primaryKey The primary key that must be in the {@link OsmPrimitive}
|
||||
* @param source The specified source value (not tag)
|
||||
* @param layer A pre-existing {@link MapWithAILayer}
|
||||
* @param bboxes The bboxes to get the data in
|
||||
*/
|
||||
public static void addSourceTags(DataSet dataSet, String primaryKey, String source) {
|
||||
dataSet.allPrimitives().stream().filter(p -> p.hasKey(primaryKey) && !p.hasKey("source")).forEach(p -> {
|
||||
p.put("source", source);
|
||||
p.save();
|
||||
public static void getMapWithAIData(MapWithAILayer layer, BBox... bboxes) {
|
||||
getMapWithAIData(layer, Arrays.asList(bboxes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data for MapWithAI
|
||||
*
|
||||
* @param layer A pre-existing {@link MapWithAILayer}
|
||||
* @param bboxes The bboxes to get the data in
|
||||
*/
|
||||
public static void getMapWithAIData(MapWithAILayer layer, Collection<BBox> bboxes) {
|
||||
final DataSet mapWithAISet = layer.getDataSet();
|
||||
final List<BBox> mapWithAIBounds = mapWithAISet.getDataSourceBounds().stream().map(Bounds::toBBox)
|
||||
.collect(Collectors.toList());
|
||||
final List<BBox> editSetBBoxes = bboxes.stream()
|
||||
.filter(bbox -> mapWithAIBounds.stream().noneMatch(tBBox -> tBBox.bounds(bbox)))
|
||||
.collect(Collectors.toList());
|
||||
getForkJoinPool().execute(() -> {
|
||||
layer.getDataSet().clear();
|
||||
final DataSet newData = getData(editSetBBoxes);
|
||||
Lock lock = layer.getLock();
|
||||
lock.lock();
|
||||
try {
|
||||
layer.mergeFrom(newData);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove primitives and their children from a dataset.
|
||||
* Get the data for MapWithAI
|
||||
*
|
||||
* @param primitives The primitives to remove
|
||||
* @param layer A pre-existing {@link MapWithAILayer}
|
||||
* @param osmLayer The osm datalayer with a set of bounds
|
||||
*/
|
||||
public static void removePrimitivesFromDataSet(Collection<OsmPrimitive> primitives) {
|
||||
for (final OsmPrimitive primitive : primitives) {
|
||||
if (primitive instanceof Relation) {
|
||||
removePrimitivesFromDataSet(((Relation) primitive).getMemberPrimitives());
|
||||
} else if (primitive instanceof Way) {
|
||||
for (final Node node : ((Way) primitive).getNodes()) {
|
||||
final DataSet ds = node.getDataSet();
|
||||
if (ds != null) {
|
||||
ds.removePrimitive(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
final DataSet ds = primitive.getDataSet();
|
||||
if (ds != null) {
|
||||
ds.removePrimitive(primitive);
|
||||
}
|
||||
}
|
||||
public static void getMapWithAIData(MapWithAILayer layer, OsmDataLayer osmLayer) {
|
||||
getMapWithAIData(layer,
|
||||
osmLayer.getDataSet().getDataSourceBounds().stream().map(Bounds::toBBox).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
public static double getWidth(BBox bbox) {
|
||||
// Lat is y, Lon is x
|
||||
final LatLon bottomRight = bbox.getBottomRight();
|
||||
final LatLon topLeft = bbox.getTopLeft();
|
||||
final double maxx = bottomRight.getX();
|
||||
final double minx = topLeft.getX();
|
||||
final double miny = bottomRight.getY();
|
||||
final double maxy = topLeft.getY();
|
||||
final LatLon bottomLeft = new LatLon(miny, minx);
|
||||
final LatLon topRight = new LatLon(maxy, maxx);
|
||||
// TODO handle meridian
|
||||
return Math.max(bottomRight.greatCircleDistance(bottomLeft), topRight.greatCircleDistance(topLeft));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add primitives and their children to a collection
|
||||
*
|
||||
* @param collection A collection to add the primitives to
|
||||
* @param primitives The primitives to add to the collection
|
||||
* @param bbox The bbox to reduce to a set maximum dimension
|
||||
* @return A list of BBoxes that have a dimension no more than
|
||||
* {@link MAXIMUM_SIDE_DIMENSIONS}
|
||||
*/
|
||||
public static void addPrimitivesToCollection(Collection<OsmPrimitive> collection,
|
||||
Collection<OsmPrimitive> primitives) {
|
||||
final Collection<OsmPrimitive> temporaryCollection = new TreeSet<>();
|
||||
for (final OsmPrimitive primitive : primitives) {
|
||||
if (primitive instanceof Way) {
|
||||
temporaryCollection.addAll(((Way) primitive).getNodes());
|
||||
} else if (primitive instanceof Relation) {
|
||||
addPrimitivesToCollection(temporaryCollection, ((Relation) primitive).getMemberPrimitives());
|
||||
}
|
||||
temporaryCollection.add(primitive);
|
||||
}
|
||||
collection.addAll(temporaryCollection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current MapWithAI url
|
||||
*
|
||||
* @return A MapWithAI url
|
||||
*/
|
||||
public static String getMapWithAIUrl() {
|
||||
final MapWithAILayer layer = getLayer(false);
|
||||
String url = Config.getPref().get(MapWithAIPlugin.NAME.concat(".current_api"), DEFAULT_MAPWITHAI_API);
|
||||
if (layer != null && layer.getMapWithAIUrl() != null) {
|
||||
url = layer.getMapWithAIUrl();
|
||||
} else {
|
||||
final List<String> urls = getMapWithAIURLs();
|
||||
if (!urls.contains(url)) {
|
||||
url = DEFAULT_MAPWITHAI_API;
|
||||
setMapWithAIUrl(DEFAULT_MAPWITHAI_API, true);
|
||||
}
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the MapWithAI url
|
||||
*
|
||||
* @param url The url to set as the default
|
||||
* @param permanent {@code true} if we want the setting to persist between
|
||||
* sessions
|
||||
*/
|
||||
public static void setMapWithAIUrl(String url, boolean permanent) {
|
||||
final MapWithAILayer layer = getLayer(false);
|
||||
if (permanent) {
|
||||
final List<String> urls = new ArrayList<>(getMapWithAIURLs());
|
||||
if (!urls.contains(url)) {
|
||||
urls.add(url);
|
||||
setMapWithAIURLs(urls);
|
||||
}
|
||||
if (DEFAULT_MAPWITHAI_API.equals(url)) {
|
||||
url = "";
|
||||
}
|
||||
Config.getPref().put(MapWithAIPlugin.NAME.concat(".current_api"), url);
|
||||
} else if (layer != null) {
|
||||
layer.setMapWithAIUrl(url);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the MapWithAI urls
|
||||
*
|
||||
* @param urls A list of URLs
|
||||
*/
|
||||
public static void setMapWithAIURLs(List<String> urls) {
|
||||
Config.getPref().putList(MapWithAIPlugin.NAME.concat(".apis"), urls);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the MapWithAI urls (or the default)
|
||||
*
|
||||
* @return The urls for MapWithAI endpoints
|
||||
*/
|
||||
public static List<String> getMapWithAIURLs() {
|
||||
return Config.getPref().getList(MapWithAIPlugin.NAME.concat(".apis"),
|
||||
new ArrayList<>(Arrays.asList(DEFAULT_MAPWITHAI_API)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a paintstyle from the jar (TODO)
|
||||
*/
|
||||
public static void addMapWithAIPaintStyles() {
|
||||
// TODO figure out how to use the one in the jar file
|
||||
final ExtendedSourceEntry mapWithAI = new ExtendedSourceEntry(SourceType.MAP_PAINT_STYLE, "mapwithai.mapcss",
|
||||
"https://gitlab.com/gokaart/JOSM_MapWithAI/raw/master/src/resources/styles/standard/mapwithai.mapcss");
|
||||
final List<SourceEntry> paintStyles = MapPaintPrefHelper.INSTANCE.get();
|
||||
for (final SourceEntry paintStyle : paintStyles) {
|
||||
if (mapWithAI.url.equals(paintStyle.url)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
paintStyles.add(mapWithAI);
|
||||
MapPaintPrefHelper.INSTANCE.put(paintStyles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not a we switch from the MapWithAI layer to an OSM data layer
|
||||
*
|
||||
* @param selected true if we are going to switch layers
|
||||
* @param permanent {@code true} if we want the setting to persist between
|
||||
* sessions
|
||||
*/
|
||||
public static void setSwitchLayers(boolean selected, boolean permanent) {
|
||||
final MapWithAILayer layer = getLayer(false);
|
||||
if (permanent) {
|
||||
if (!selected) {
|
||||
Config.getPref().putBoolean(MapWithAIPlugin.NAME.concat(".autoswitchlayers"), selected);
|
||||
} else {
|
||||
Config.getPref().put(MapWithAIPlugin.NAME.concat(".autoswitchlayers"), null);
|
||||
}
|
||||
} else if (layer != null) {
|
||||
layer.setSwitchLayers(selected);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if we want to automatically switch layers
|
||||
*/
|
||||
public static boolean isSwitchLayers() {
|
||||
final MapWithAILayer layer = getLayer(false);
|
||||
boolean returnBoolean = Config.getPref().getBoolean(MapWithAIPlugin.NAME.concat(".autoswitchlayers"), true);
|
||||
if (layer != null && layer.isSwitchLayers() != null) {
|
||||
returnBoolean = layer.isSwitchLayers();
|
||||
}
|
||||
return returnBoolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum number of objects that can be added at one time
|
||||
*
|
||||
* @return The maximum selection. If 0, allow any number.
|
||||
*/
|
||||
public static int getMaximumAddition() {
|
||||
final MapWithAILayer mapWithAILayer = MapWithAIDataUtils.getLayer(false);
|
||||
Integer defaultReturn = Config.getPref().getInt(MapWithAIPlugin.NAME.concat(".maximumselection"),
|
||||
getDefaultMaximumAddition());
|
||||
if (mapWithAILayer != null && mapWithAILayer.getMaximumAddition() != null) {
|
||||
defaultReturn = mapWithAILayer.getMaximumAddition();
|
||||
}
|
||||
return defaultReturn;
|
||||
}
|
||||
|
||||
public static int getDefaultMaximumAddition() {
|
||||
return DEFAULT_MAXIMUM_ADDITION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum number of objects that can be added at one time.
|
||||
*
|
||||
* @param max The maximum number of objects to select (0 allows any number
|
||||
* to be selected).
|
||||
* @param permanent {@code true} if we want the setting to persist between
|
||||
* sessions
|
||||
*/
|
||||
public static void setMaximumAddition(int max, boolean permanent) {
|
||||
final MapWithAILayer mapWithAILayer = getLayer(false);
|
||||
if (permanent) {
|
||||
if (getDefaultMaximumAddition() != max) {
|
||||
Config.getPref().putInt(MapWithAIPlugin.NAME.concat(".maximumselection"), max);
|
||||
} else {
|
||||
Config.getPref().put(MapWithAIPlugin.NAME.concat(".maximumselection"), null);
|
||||
}
|
||||
} else if (mapWithAILayer != null) {
|
||||
mapWithAILayer.setMaximumAddition(max);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<BBox> reduceBBoxSize(List<BBox> bboxes) {
|
||||
List<BBox> returnBBoxes = new ArrayList<>();
|
||||
bboxes.forEach(bbox -> returnBBoxes.addAll(reduceBBoxSize(bbox)));
|
||||
return returnBBoxes;
|
||||
}
|
||||
|
||||
public static List<BBox> reduceBBoxSize(BBox bbox) {
|
||||
final List<BBox> returnBounds = new ArrayList<>();
|
||||
final double width = getWidth(bbox);
|
||||
|
@ -445,98 +378,38 @@ public final class MapWithAIDataUtils {
|
|||
return returnBounds;
|
||||
}
|
||||
|
||||
public static double getWidth(BBox bbox) {
|
||||
// Lat is y, Lon is x
|
||||
final LatLon bottomRight = bbox.getBottomRight();
|
||||
final LatLon topLeft = bbox.getTopLeft();
|
||||
final double maxx = bottomRight.getX();
|
||||
final double minx = topLeft.getX();
|
||||
final double miny = bottomRight.getY();
|
||||
final double maxy = topLeft.getY();
|
||||
final LatLon bottomLeft = new LatLon(miny, minx);
|
||||
final LatLon topRight = new LatLon(maxy, maxx);
|
||||
// TODO handle meridian
|
||||
return Math.max(bottomRight.greatCircleDistance(bottomLeft), topRight.greatCircleDistance(topLeft));
|
||||
}
|
||||
|
||||
public static double getHeight(BBox bbox) {
|
||||
final LatLon bottomRight = bbox.getBottomRight();
|
||||
final LatLon topLeft = bbox.getTopLeft();
|
||||
final double minx = topLeft.getX();
|
||||
final double miny = bottomRight.getY();
|
||||
final LatLon bottomLeft = new LatLon(miny, minx);
|
||||
// TODO handle poles
|
||||
return topLeft.greatCircleDistance(bottomLeft);
|
||||
/**
|
||||
* @param bboxes The bboxes to reduce to a set maximum dimension
|
||||
* @return A list of BBoxes that have a dimension no more than
|
||||
* {@link MAXIMUM_SIDE_DIMENSIONS}
|
||||
*/
|
||||
public static List<BBox> reduceBBoxSize(List<BBox> bboxes) {
|
||||
List<BBox> returnBBoxes = new ArrayList<>();
|
||||
bboxes.forEach(bbox -> returnBBoxes.addAll(reduceBBoxSize(bbox)));
|
||||
return returnBBoxes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data for MapWithAI
|
||||
* Remove primitives and their children from a dataset.
|
||||
*
|
||||
* @param layer A pre-existing {@link MapWithAILayer}
|
||||
* @param bboxes The bboxes to get the data in
|
||||
* @param primitives The primitives to remove
|
||||
*/
|
||||
public static void getMapWithAIData(MapWithAILayer layer, Collection<BBox> bboxes) {
|
||||
final DataSet mapWithAISet = layer.getDataSet();
|
||||
final List<BBox> mapWithAIBounds = mapWithAISet.getDataSourceBounds().stream().map(Bounds::toBBox).collect(Collectors.toList());
|
||||
final List<BBox> editSetBBoxes = bboxes.stream()
|
||||
.filter(bbox -> mapWithAIBounds.stream().noneMatch(tBBox -> tBBox.bounds(bbox)))
|
||||
.collect(Collectors.toList());
|
||||
getForkJoinPool().execute(() -> {
|
||||
layer.getDataSet().clear();
|
||||
final DataSet newData = getData(editSetBBoxes);
|
||||
Lock lock = layer.getLock();
|
||||
lock.lock();
|
||||
try {
|
||||
layer.mergeFrom(newData);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
public static void removePrimitivesFromDataSet(Collection<OsmPrimitive> primitives) {
|
||||
for (final OsmPrimitive primitive : primitives) {
|
||||
if (primitive instanceof Relation) {
|
||||
removePrimitivesFromDataSet(((Relation) primitive).getMemberPrimitives());
|
||||
} else if (primitive instanceof Way) {
|
||||
for (final Node node : ((Way) primitive).getNodes()) {
|
||||
final DataSet ds = node.getDataSet();
|
||||
if (ds != null) {
|
||||
ds.removePrimitive(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data for MapWithAI
|
||||
*
|
||||
* @param layer A pre-existing {@link MapWithAILayer}
|
||||
* @param bboxes The bboxes to get the data in
|
||||
*/
|
||||
public static void getMapWithAIData(MapWithAILayer layer, BBox... bboxes) {
|
||||
getMapWithAIData(layer, Arrays.asList(bboxes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data for MapWithAI
|
||||
*
|
||||
* @param layer A pre-existing {@link MapWithAILayer}
|
||||
* @param osmLayer The osm datalayer with a set of bounds
|
||||
*/
|
||||
public static void getMapWithAIData(MapWithAILayer layer, OsmDataLayer osmLayer) {
|
||||
getMapWithAIData(layer,
|
||||
osmLayer.getDataSet().getDataSourceBounds().stream().map(Bounds::toBBox).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get data for a {@link MapWithAILayer}
|
||||
*
|
||||
* @param layer The {@link MapWithAILayer} to add data to
|
||||
*/
|
||||
public static void getMapWithAIData(MapWithAILayer layer) {
|
||||
final List<OsmDataLayer> osmLayers = MainApplication.getLayerManager().getLayersOfType(OsmDataLayer.class);
|
||||
for (final OsmDataLayer osmLayer : osmLayers) {
|
||||
if (!osmLayer.isLocked()) {
|
||||
getMapWithAIData(layer, osmLayer);
|
||||
final DataSet ds = primitive.getDataSet();
|
||||
if (ds != null) {
|
||||
ds.removePrimitive(primitive);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The {@link ForkJoinPool} for MapWithAI use.
|
||||
*/
|
||||
public static ForkJoinPool getForkJoinPool() {
|
||||
if (Objects.isNull(forkJoinPool) || forkJoinPool.isShutdown()) {
|
||||
forkJoinPool = Utils.newForkJoinPool(MapWithAIPlugin.NAME.concat(".forkjoinpoolthreads"),
|
||||
MapWithAIPlugin.NAME, Thread.NORM_PRIORITY);
|
||||
}
|
||||
return forkJoinPool;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ public class MapWithAIMoveAction extends JosmAction {
|
|||
DataSet ds = mapWithAI.getDataSet();
|
||||
final List<OsmDataLayer> osmLayers = MainApplication.getLayerManager().getLayersOfType(OsmDataLayer.class);
|
||||
OsmDataLayer editLayer = null;
|
||||
final int maxAddition = MapWithAIDataUtils.getMaximumAddition();
|
||||
final int maxAddition = MapWithAIPreferenceHelper.getMaximumAddition();
|
||||
Collection<OsmPrimitive> selected;
|
||||
List<Node> nodes = ds.getSelectedNodes().stream().filter(node -> !node.getReferrers().isEmpty())
|
||||
.collect(Collectors.toList());
|
||||
|
@ -60,7 +60,7 @@ public class MapWithAIMoveAction extends JosmAction {
|
|||
if (editLayer != null) {
|
||||
final MapWithAIAddCommand command = new MapWithAIAddCommand(mapWithAI, editLayer, selected);
|
||||
UndoRedoHandler.getInstance().add(command);
|
||||
if (MapWithAIDataUtils.isSwitchLayers()) {
|
||||
if (MapWithAIPreferenceHelper.isSwitchLayers()) {
|
||||
MainApplication.getLayerManager().setActiveLayer(editLayer);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,184 @@
|
|||
// License: GPL. For details, see LICENSE file.
|
||||
package org.openstreetmap.josm.plugins.mapwithai.backend;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.openstreetmap.josm.plugins.mapwithai.MapWithAIPlugin;
|
||||
import org.openstreetmap.josm.spi.preferences.Config;
|
||||
|
||||
public class MapWithAIPreferenceHelper {
|
||||
public static final String DEFAULT_MAPWITHAI_API = "https://www.facebook.com/maps/ml_roads?conflate_with_osm=true&theme=ml_road_vector&collaborator=josm&token=ASb3N5o9HbX8QWn8G_NtHIRQaYv3nuG2r7_f3vnGld3KhZNCxg57IsaQyssIaEw5rfRNsPpMwg4TsnrSJtIJms5m&hash=ASawRla3rBcwEjY4HIY&result_type=road_building_vector_xml&bbox={bbox}";
|
||||
private static final int DEFAULT_MAXIMUM_ADDITION = 5;
|
||||
private static final String AUTOSWITCHLAYERS = MapWithAIPlugin.NAME.concat(".autoswitchlayers");
|
||||
private static final String MERGEBUILDINGADDRESSES = MapWithAIPlugin.NAME.concat(".mergebuildingaddresses");
|
||||
private static final String MAXIMUMSELECTION = MapWithAIPlugin.NAME.concat(".maximumselection");
|
||||
|
||||
private MapWithAIPreferenceHelper() {
|
||||
// Hide the constructor
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The default maximum number of objects to add.
|
||||
*/
|
||||
public static int getDefaultMaximumAddition() {
|
||||
return DEFAULT_MAXIMUM_ADDITION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current MapWithAI url
|
||||
*
|
||||
* @return A MapWithAI url
|
||||
*/
|
||||
public static String getMapWithAIUrl() {
|
||||
final MapWithAILayer layer = MapWithAIDataUtils.getLayer(false);
|
||||
String url = Config.getPref().get(MapWithAIPlugin.NAME.concat(".current_api"), DEFAULT_MAPWITHAI_API);
|
||||
if (layer != null && layer.getMapWithAIUrl() != null) {
|
||||
url = layer.getMapWithAIUrl();
|
||||
} else {
|
||||
final List<String> urls = getMapWithAIURLs();
|
||||
if (!urls.contains(url)) {
|
||||
url = DEFAULT_MAPWITHAI_API;
|
||||
setMapWithAIUrl(DEFAULT_MAPWITHAI_API, true);
|
||||
}
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the MapWithAI urls (or the default)
|
||||
*
|
||||
* @return The urls for MapWithAI endpoints
|
||||
*/
|
||||
public static List<String> getMapWithAIURLs() {
|
||||
return Config.getPref().getList(MapWithAIPlugin.NAME.concat(".apis"),
|
||||
new ArrayList<>(Arrays.asList(DEFAULT_MAPWITHAI_API)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the maximum number of objects that can be added at one time
|
||||
*
|
||||
* @return The maximum selection. If 0, allow any number.
|
||||
*/
|
||||
public static int getMaximumAddition() {
|
||||
final MapWithAILayer mapWithAILayer = MapWithAIDataUtils.getLayer(false);
|
||||
Integer defaultReturn = Config.getPref().getInt(MAXIMUMSELECTION,
|
||||
getDefaultMaximumAddition());
|
||||
if (mapWithAILayer != null && mapWithAILayer.getMaximumAddition() != null) {
|
||||
defaultReturn = mapWithAILayer.getMaximumAddition();
|
||||
}
|
||||
return defaultReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if we want to automatically merge buildings with
|
||||
* pre-existing addresses
|
||||
*/
|
||||
public static boolean isMergeBuildingAddress() {
|
||||
return Config.getPref().getBoolean(MERGEBUILDINGADDRESSES, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if we want to automatically switch layers
|
||||
*/
|
||||
public static boolean isSwitchLayers() {
|
||||
final MapWithAILayer layer = MapWithAIDataUtils.getLayer(false);
|
||||
boolean returnBoolean = Config.getPref().getBoolean(AUTOSWITCHLAYERS, true);
|
||||
if (layer != null && layer.isSwitchLayers() != null) {
|
||||
returnBoolean = layer.isSwitchLayers();
|
||||
}
|
||||
return returnBoolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the MapWithAI url
|
||||
*
|
||||
* @param url The url to set as the default
|
||||
* @param permanent {@code true} if we want the setting to persist between
|
||||
* sessions
|
||||
*/
|
||||
public static void setMapWithAIUrl(String url, boolean permanent) {
|
||||
final MapWithAILayer layer = MapWithAIDataUtils.getLayer(false);
|
||||
if (permanent) {
|
||||
final List<String> urls = new ArrayList<>(getMapWithAIURLs());
|
||||
if (!urls.contains(url)) {
|
||||
urls.add(url);
|
||||
setMapWithAIURLs(urls);
|
||||
}
|
||||
if (DEFAULT_MAPWITHAI_API.equals(url)) {
|
||||
url = "";
|
||||
}
|
||||
Config.getPref().put(MapWithAIPlugin.NAME.concat(".current_api"), url);
|
||||
} else if (layer != null) {
|
||||
layer.setMapWithAIUrl(url);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the MapWithAI urls
|
||||
*
|
||||
* @param urls A list of URLs
|
||||
*/
|
||||
public static void setMapWithAIURLs(List<String> urls) {
|
||||
Config.getPref().putList(MapWithAIPlugin.NAME.concat(".apis"), urls);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum number of objects that can be added at one time.
|
||||
*
|
||||
* @param max The maximum number of objects to select (0 allows any number
|
||||
* to be selected).
|
||||
* @param permanent {@code true} if we want the setting to persist between
|
||||
* sessions
|
||||
*/
|
||||
public static void setMaximumAddition(int max, boolean permanent) {
|
||||
final MapWithAILayer mapWithAILayer = MapWithAIDataUtils.getLayer(false);
|
||||
if (permanent) {
|
||||
if (getDefaultMaximumAddition() != max) {
|
||||
Config.getPref().putInt(MAXIMUMSELECTION, max);
|
||||
} else {
|
||||
Config.getPref().put(MAXIMUMSELECTION, null);
|
||||
}
|
||||
} else if (mapWithAILayer != null) {
|
||||
mapWithAILayer.setMaximumAddition(max);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not a we switch from the MapWithAI layer to an OSM data layer
|
||||
*
|
||||
* @param selected true if we are going to switch layers
|
||||
* @param permanent {@code true} if we want the setting to persist between
|
||||
* sessions
|
||||
*/
|
||||
public static void setMergeBuildingAddress(boolean selected, boolean permanent) {
|
||||
if (permanent) {
|
||||
if (!selected) {
|
||||
Config.getPref().putBoolean(MERGEBUILDINGADDRESSES, selected);
|
||||
} else {
|
||||
Config.getPref().put(MERGEBUILDINGADDRESSES, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not a we switch from the MapWithAI layer to an OSM data layer
|
||||
*
|
||||
* @param selected true if we are going to switch layers
|
||||
* @param permanent {@code true} if we want the setting to persist between
|
||||
* sessions
|
||||
*/
|
||||
public static void setSwitchLayers(boolean selected, boolean permanent) {
|
||||
final MapWithAILayer layer = MapWithAIDataUtils.getLayer(false);
|
||||
if (permanent) {
|
||||
if (!selected) {
|
||||
Config.getPref().putBoolean(AUTOSWITCHLAYERS, selected);
|
||||
} else {
|
||||
Config.getPref().put(AUTOSWITCHLAYERS, null);
|
||||
}
|
||||
} else if (layer != null) {
|
||||
layer.setSwitchLayers(selected);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -79,13 +79,13 @@ public class MapWithAIRemoteControl extends RequestHandler.RawURLParseRequestHan
|
|||
final MapWithAILayer layer = MapWithAIDataUtils.getLayer(true);
|
||||
|
||||
if (maxObj != null) {
|
||||
MapWithAIDataUtils.setMaximumAddition(maxObj, false);
|
||||
MapWithAIPreferenceHelper.setMaximumAddition(maxObj, false);
|
||||
}
|
||||
if (url != null) {
|
||||
MapWithAIDataUtils.setMapWithAIUrl(url, false);
|
||||
MapWithAIPreferenceHelper.setMapWithAIUrl(url, false);
|
||||
}
|
||||
if (switchLayer != null) {
|
||||
MapWithAIDataUtils.setSwitchLayers(switchLayer, false);
|
||||
MapWithAIPreferenceHelper.setSwitchLayers(switchLayer, false);
|
||||
}
|
||||
|
||||
if (download != null && download.isInWorld()) {
|
||||
|
@ -154,6 +154,6 @@ public class MapWithAIRemoteControl extends RequestHandler.RawURLParseRequestHan
|
|||
"/mapwithai?url=https://www.facebook.com/maps/ml_roads?conflate_with_osm=true&theme=ml_road_vector&collaborator=josm&token=ASb3N5o9HbX8QWn8G_NtHIRQaYv3nuG2r7_f3vnGld3KhZNCxg57IsaQyssIaEw5rfRNsPpMwg4TsnrSJtIJms5m&hash=ASawRla3rBcwEjY4HIY&bbox={bbox}",
|
||||
"/mapwithai?bbox=-108.4625421,39.0621223,-108.4594728,39.0633059&max_obj=1",
|
||||
"/mapwithai?bbox=-108.4625421,39.0621223,-108.4594728,39.0633059&switch_layer=false",
|
||||
"/mapwithai?crop_bbox=-108.4625421,39.0621223,-108.4594728,39.0633059" };
|
||||
"/mapwithai?crop_bbox=-108.4625421,39.0621223,-108.4594728,39.0633059" };
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,12 +26,14 @@ public class MapWithAIUploadHook implements UploadHook {
|
|||
tags.put("mapwithai", addedObjects.toString());
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("version=").append(version);
|
||||
if (MapWithAIDataUtils.getMaximumAddition() != MapWithAIDataUtils.getDefaultMaximumAddition()) {
|
||||
sb.append(";maxadd=").append(MapWithAIDataUtils.getMaximumAddition());
|
||||
}
|
||||
if (!MapWithAIDataUtils.getMapWithAIUrl().equalsIgnoreCase(MapWithAIDataUtils.DEFAULT_MAPWITHAI_API)) {
|
||||
sb.append(";url=").append(MapWithAIDataUtils.getMapWithAIUrl());
|
||||
}
|
||||
if (MapWithAIPreferenceHelper.getMaximumAddition() != MapWithAIPreferenceHelper
|
||||
.getDefaultMaximumAddition()) {
|
||||
sb.append(";maxadd=").append(MapWithAIPreferenceHelper.getMaximumAddition());
|
||||
}
|
||||
if (!MapWithAIPreferenceHelper.getMapWithAIUrl()
|
||||
.equalsIgnoreCase(MapWithAIPreferenceHelper.DEFAULT_MAPWITHAI_API)) {
|
||||
sb.append(";url=").append(MapWithAIPreferenceHelper.getMapWithAIUrl());
|
||||
}
|
||||
if (DetectTaskingManagerUtils.hasTaskingManagerLayer()) {
|
||||
sb.append(";task=").append(DetectTaskingManagerUtils.getTaskingManagerBBox().toStringCSV(","));
|
||||
}
|
||||
|
|
|
@ -8,8 +8,7 @@ import org.junit.Before;
|
|||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.MapWithAIPreferences;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAIDataUtils;
|
||||
import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAIPreferenceHelper;
|
||||
import org.openstreetmap.josm.testutils.JOSMTestRules;
|
||||
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
|
@ -47,16 +46,16 @@ public class MapWithAIPreferencesTest {
|
|||
Assert.assertEquals(tabs + 1, pane.getPluginPreference().getTabPane().getTabCount());
|
||||
Assert.assertEquals(pane.getPluginPreference(), preferences.getTabPreferenceSetting(pane));
|
||||
|
||||
final boolean switchLayers = MapWithAIDataUtils.isSwitchLayers();
|
||||
final boolean switchLayers = MapWithAIPreferenceHelper.isSwitchLayers();
|
||||
|
||||
Assert.assertEquals(switchLayers, preferences.getSwitchLayerCheckBox().isSelected());
|
||||
preferences.ok();
|
||||
Assert.assertEquals(switchLayers, MapWithAIDataUtils.isSwitchLayers());
|
||||
Assert.assertEquals(switchLayers, MapWithAIPreferenceHelper.isSwitchLayers());
|
||||
|
||||
preferences.getSwitchLayerCheckBox().setSelected(!switchLayers);
|
||||
Assert.assertNotEquals(!switchLayers, MapWithAIDataUtils.isSwitchLayers());
|
||||
Assert.assertNotEquals(!switchLayers, MapWithAIPreferenceHelper.isSwitchLayers());
|
||||
preferences.ok();
|
||||
Assert.assertEquals(!switchLayers, MapWithAIDataUtils.isSwitchLayers());
|
||||
Assert.assertEquals(!switchLayers, MapWithAIPreferenceHelper.isSwitchLayers());
|
||||
|
||||
final Object tmp = preferences.getMaximumAdditionSpinner().getModel();
|
||||
SpinnerNumberModel spinnerModel = null;
|
||||
|
@ -64,12 +63,12 @@ public class MapWithAIPreferencesTest {
|
|||
spinnerModel = (SpinnerNumberModel) tmp;
|
||||
}
|
||||
Assert.assertNotNull(spinnerModel);
|
||||
final Number currentNumber = MapWithAIDataUtils.getMaximumAddition();
|
||||
final Number currentNumber = MapWithAIPreferenceHelper.getMaximumAddition();
|
||||
Assert.assertEquals(currentNumber.intValue(), spinnerModel.getNumber().intValue());
|
||||
spinnerModel.setValue(currentNumber.intValue() + 3);
|
||||
Assert.assertNotEquals(spinnerModel.getNumber().intValue(), MapWithAIDataUtils.getMaximumAddition());
|
||||
Assert.assertNotEquals(spinnerModel.getNumber().intValue(), MapWithAIPreferenceHelper.getMaximumAddition());
|
||||
preferences.ok();
|
||||
Assert.assertEquals(spinnerModel.getNumber().intValue(), MapWithAIDataUtils.getMaximumAddition());
|
||||
Assert.assertEquals(spinnerModel.getNumber().intValue(), MapWithAIPreferenceHelper.getMaximumAddition());
|
||||
|
||||
Assert.assertNotNull(preferences.getPossibleMapWithAIApiUrl().getSelectedItem());
|
||||
}
|
||||
|
|
|
@ -42,9 +42,9 @@ public class MapWithAIDataUtilsTest {
|
|||
|
||||
@Before
|
||||
public void setUp() {
|
||||
String URL = MapWithAIDataUtils.getMapWithAIUrl().replace("https://www.facebook.com/maps",
|
||||
String URL = MapWithAIPreferenceHelper.getMapWithAIUrl().replace("https://www.facebook.com/maps",
|
||||
wireMockRule.baseUrl());
|
||||
MapWithAIDataUtils.setMapWithAIUrl(URL, true);
|
||||
MapWithAIPreferenceHelper.setMapWithAIUrl(URL, true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -139,18 +139,20 @@ public class MapWithAIDataUtilsTest {
|
|||
@Test
|
||||
public void testMapWithAIURLPreferences() {
|
||||
final String fakeUrl = "https://fake.url";
|
||||
Assert.assertNotEquals(fakeUrl, MapWithAIDataUtils.getMapWithAIUrl());
|
||||
MapWithAIDataUtils.setMapWithAIUrl(fakeUrl, true);
|
||||
Assert.assertEquals(fakeUrl, MapWithAIDataUtils.getMapWithAIUrl());
|
||||
final List<String> urls = new ArrayList<>(MapWithAIDataUtils.getMapWithAIURLs());
|
||||
Assert.assertNotEquals(fakeUrl, MapWithAIPreferenceHelper.getMapWithAIUrl());
|
||||
MapWithAIPreferenceHelper.setMapWithAIUrl(fakeUrl, true);
|
||||
Assert.assertEquals(fakeUrl, MapWithAIPreferenceHelper.getMapWithAIUrl());
|
||||
final List<String> urls = new ArrayList<>(MapWithAIPreferenceHelper.getMapWithAIURLs());
|
||||
Assert.assertEquals(3, urls.size());
|
||||
MapWithAIDataUtils.setMapWithAIUrl(MapWithAIDataUtils.DEFAULT_MAPWITHAI_API, true);
|
||||
Assert.assertEquals(MapWithAIDataUtils.DEFAULT_MAPWITHAI_API, MapWithAIDataUtils.getMapWithAIUrl());
|
||||
MapWithAIDataUtils.setMapWithAIUrl(fakeUrl, true);
|
||||
Assert.assertEquals(fakeUrl, MapWithAIDataUtils.getMapWithAIUrl());
|
||||
MapWithAIPreferenceHelper.setMapWithAIUrl(MapWithAIPreferenceHelper.DEFAULT_MAPWITHAI_API, true);
|
||||
Assert.assertEquals(MapWithAIPreferenceHelper.DEFAULT_MAPWITHAI_API,
|
||||
MapWithAIPreferenceHelper.getMapWithAIUrl());
|
||||
MapWithAIPreferenceHelper.setMapWithAIUrl(fakeUrl, true);
|
||||
Assert.assertEquals(fakeUrl, MapWithAIPreferenceHelper.getMapWithAIUrl());
|
||||
urls.remove(fakeUrl);
|
||||
MapWithAIDataUtils.setMapWithAIURLs(urls);
|
||||
Assert.assertEquals(MapWithAIDataUtils.DEFAULT_MAPWITHAI_API, MapWithAIDataUtils.getMapWithAIUrl());
|
||||
MapWithAIPreferenceHelper.setMapWithAIURLs(urls);
|
||||
Assert.assertEquals(MapWithAIPreferenceHelper.DEFAULT_MAPWITHAI_API,
|
||||
MapWithAIPreferenceHelper.getMapWithAIUrl());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -46,9 +46,9 @@ public class MapWithAILayerTest {
|
|||
|
||||
@Before
|
||||
public void setUp() {
|
||||
String URL = MapWithAIDataUtils.getMapWithAIUrl().replace("https://www.facebook.com/maps",
|
||||
String URL = MapWithAIPreferenceHelper.getMapWithAIUrl().replace("https://www.facebook.com/maps",
|
||||
wireMockRule.baseUrl());
|
||||
MapWithAIDataUtils.setMapWithAIUrl(URL, true);
|
||||
MapWithAIPreferenceHelper.setMapWithAIUrl(URL, true);
|
||||
layer = new MapWithAILayer(new DataSet(), "test", null);
|
||||
}
|
||||
|
||||
|
|
|
@ -45,9 +45,9 @@ public class MapWithAIRemoteControlTest {
|
|||
|
||||
@Before
|
||||
public void setUp() {
|
||||
String URL = MapWithAIDataUtils.getMapWithAIUrl().replace("https://www.facebook.com/maps",
|
||||
String URL = MapWithAIPreferenceHelper.getMapWithAIUrl().replace("https://www.facebook.com/maps",
|
||||
wireMockRule.baseUrl());
|
||||
MapWithAIDataUtils.setMapWithAIUrl(URL, true);
|
||||
MapWithAIPreferenceHelper.setMapWithAIUrl(URL, true);
|
||||
}
|
||||
|
||||
private static MapWithAIRemoteControl newHandler(String url) throws RequestHandlerBadRequestException {
|
||||
|
@ -80,7 +80,7 @@ public class MapWithAIRemoteControlTest {
|
|||
*/
|
||||
@Test
|
||||
public void testNominalRequest() throws Exception {
|
||||
newHandler("https://localhost?url=" + Utils.encodeUrl(MapWithAIDataUtils.getMapWithAIUrl())).handle();
|
||||
newHandler("https://localhost?url=" + Utils.encodeUrl(MapWithAIPreferenceHelper.getMapWithAIUrl())).handle();
|
||||
Assert.assertFalse(MainApplication.getLayerManager().getLayersOfType(MapWithAILayer.class).isEmpty());
|
||||
|
||||
Assert.assertTrue(MapWithAIDataUtils.getLayer(false).getDataSet().getDataSourceBounds().isEmpty());
|
||||
|
@ -92,9 +92,9 @@ public class MapWithAIRemoteControlTest {
|
|||
newHandler("https://localhost?url=" + Utils.encodeUrl(badUrl)).handle();
|
||||
Assert.assertFalse(MainApplication.getLayerManager().getLayersOfType(MapWithAILayer.class).isEmpty());
|
||||
|
||||
Assert.assertEquals(badUrl, MapWithAIDataUtils.getMapWithAIUrl());
|
||||
Assert.assertEquals(badUrl, MapWithAIPreferenceHelper.getMapWithAIUrl());
|
||||
MainApplication.getLayerManager().removeLayer(MapWithAIDataUtils.getLayer(false));
|
||||
Assert.assertNotEquals(badUrl, MapWithAIDataUtils.getMapWithAIUrl());
|
||||
Assert.assertNotEquals(badUrl, MapWithAIPreferenceHelper.getMapWithAIUrl());
|
||||
|
||||
badUrl = "NothingToSeeHere";
|
||||
thrown.expect(RequestHandlerBadRequestException.class);
|
||||
|
@ -110,9 +110,9 @@ public class MapWithAIRemoteControlTest {
|
|||
+ maxObj.toString()).handle();
|
||||
Assert.assertFalse(MainApplication.getLayerManager().getLayersOfType(MapWithAILayer.class).isEmpty());
|
||||
|
||||
Assert.assertEquals(maxObj.intValue(), MapWithAIDataUtils.getMaximumAddition());
|
||||
Assert.assertEquals(maxObj.intValue(), MapWithAIPreferenceHelper.getMaximumAddition());
|
||||
MainApplication.getLayerManager().removeLayer(MapWithAIDataUtils.getLayer(false));
|
||||
Assert.assertNotEquals(maxObj.intValue(), MapWithAIDataUtils.getMaximumAddition());
|
||||
Assert.assertNotEquals(maxObj.intValue(), MapWithAIPreferenceHelper.getMaximumAddition());
|
||||
|
||||
thrown.expect(RequestHandlerBadRequestException.class);
|
||||
thrown.expectMessage("NumberFormatException (For input string: \"BAD_VALUE\")");
|
||||
|
@ -128,7 +128,7 @@ public class MapWithAIRemoteControlTest {
|
|||
Assert.assertFalse(MainApplication.getLayerManager().getLayersOfType(MapWithAILayer.class).isEmpty());
|
||||
|
||||
await().atMost(10, TimeUnit.SECONDS)
|
||||
.until(() -> !MapWithAIDataUtils.getLayer(false).getDataSet().getDataSourceBounds().isEmpty());
|
||||
.until(() -> !MapWithAIDataUtils.getLayer(false).getDataSet().getDataSourceBounds().isEmpty());
|
||||
|
||||
final BBox added = MapWithAIDataUtils.getLayer(false).getDataSet().getDataSourceBounds().iterator().next().toBBox();
|
||||
Assert.assertTrue(temp.bounds(added));
|
||||
|
|
|
@ -78,7 +78,7 @@ public class MapWithAIUploadHookTest {
|
|||
Assert.assertTrue(
|
||||
Arrays.asList(tags.get("mapwithai:options").split(";")).contains("version=".concat(info.localversion)));
|
||||
|
||||
MapWithAIDataUtils.setMapWithAIUrl("false-url", false);
|
||||
MapWithAIPreferenceHelper.setMapWithAIUrl("false-url", false);
|
||||
|
||||
tags.clear();
|
||||
|
||||
|
@ -93,7 +93,7 @@ public class MapWithAIUploadHookTest {
|
|||
Assert.assertTrue(split.contains("version=".concat(info.localversion)));
|
||||
Assert.assertTrue(split.contains("url=false-url"));
|
||||
|
||||
MapWithAIDataUtils.setMaximumAddition(20, false);
|
||||
MapWithAIPreferenceHelper.setMaximumAddition(20, false);
|
||||
tags.clear();
|
||||
hook.modifyChangesetTags(tags);
|
||||
split = Arrays.asList(tags.get("mapwithai:options").split(";"));
|
||||
|
|
Ładowanie…
Reference in New Issue