Give indications if there may be data available in the region

Update dependencies, slight bump on minimum JOSM version (15229 -> 15233)

Signed-off-by: Taylor Smock <taylor.smock@kaart.com>
pull/1/head
Taylor Smock 2019-10-14 12:55:56 -06:00
rodzic f569da2772
commit d48ef81aae
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 625F6A74A3E4311A
7 zmienionych plików z 322 dodań i 48 usunięć

Wyświetl plik

@ -11,10 +11,10 @@ plugins {
id "jacoco"
id "maven-publish"
id "pmd"
id "com.github.ben-manes.versions" version "0.25.0"
id "com.github.ben-manes.versions" version "0.26.0"
id "com.github.spotbugs" version "2.0.0"
id "org.openstreetmap.josm" version "0.6.1"
id "net.ltgt.errorprone" version "0.8.1"
id "org.openstreetmap.josm" version "0.6.4"
id "net.ltgt.errorprone" version "1.0.0"
//id 'de.aaschmid.cpd' version '2.0'
}
@ -46,7 +46,7 @@ def versions = [
junit: "5.5.2",
pmd: "6.6.0",
spotbugs: "3.1.12",
wiremock: "2.24.1",
wiremock: "2.25.0",
]
repositories {

Wyświetl plik

@ -1,9 +1,9 @@
# The minimum JOSM version this plugin is compatible with (can be any numeric version)
plugin.main.version = 15229
plugin.main.version = 15233
# The JOSM version this plugin is currently compiled against
# Please make sure this version is available at https://josm.openstreetmap.de/download
# The special values "latest" and "tested" are also possible here, but not recommended.
plugin.compile.version = 15229
plugin.compile.version = 15233
plugin.canloadatruntime = true
plugin.author = Taylor Smock <incoming+smocktaylor/rapid@incoming.gitlab.com>
plugin.class = org.openstreetmap.josm.plugins.mapwithai.MapWithAIPlugin

Wyświetl plik

@ -5,11 +5,21 @@ import static org.openstreetmap.josm.tools.I18n.tr;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.stream.Collectors;
import javax.swing.JOptionPane;
import org.openstreetmap.josm.actions.JosmAction;
import org.openstreetmap.josm.data.Bounds;
import org.openstreetmap.josm.gui.Notification;
import org.openstreetmap.josm.plugins.mapwithai.MapWithAIPlugin;
import org.openstreetmap.josm.tools.Shortcut;
public class MapWithAIAction extends JosmAction {
/** UID */
private static final long serialVersionUID = 8886705479253246588L;
@ -23,11 +33,45 @@ public class MapWithAIAction extends JosmAction {
@Override
public void actionPerformed(ActionEvent event) {
MapWithAIDataUtils.getMapWithAIData(MapWithAIDataUtils.getLayer(true));
if (isEnabled()) {
MapWithAIDataUtils.getMapWithAIData(MapWithAIDataUtils.getLayer(true));
createMessageDialog();
}
}
@Override
protected void updateEnabledState() {
setEnabled(getLayerManager().getEditDataSet() != null);
}
public void createMessageDialog() {
final MapWithAILayer layer = MapWithAIDataUtils.getLayer(false);
if (layer != null) {
final Notification notification = new Notification();
final List<Bounds> bounds = layer.getDataSet().getDataSourceBounds();
final StringBuilder message = new StringBuilder();
message.append(MapWithAIPlugin.NAME);
message.append(": ");
MapWithAIAvailability availability = MapWithAIAvailability.getInstance();
Map<String, Boolean> availableTypes = new TreeMap<>();
for (final Bounds bound : bounds) {
availability.getDataTypes(bound.getCenter())
.forEach((type, available) -> availableTypes.merge(type, available, Boolean::logicalOr));
}
List<String> types = availableTypes.entrySet().stream().filter(Entry::getValue)
.map(entry -> MapWithAIAvailability.getPossibleDataTypesAndMessages().get(entry.getKey()))
.collect(Collectors.toList());
if (types.isEmpty()) {
message.append(tr("No data available"));
} else {
message.append("Data available: ");
message.append(String.join(", ", types));
}
notification.setContent(message.toString());
notification.setDuration(Notification.TIME_LONG);
notification.setIcon(JOptionPane.INFORMATION_MESSAGE);
notification.show();
}
}
}

Wyświetl plik

@ -0,0 +1,154 @@
// 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.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.TreeMap;
import java.util.stream.Stream;
import javax.json.Json;
import javax.json.JsonArray;
import javax.json.JsonObject;
import javax.json.JsonValue;
import javax.json.stream.JsonParser;
import org.openstreetmap.josm.data.coor.LatLon;
import org.openstreetmap.josm.data.osm.BBox;
import org.openstreetmap.josm.data.osm.OsmPrimitive;
import org.openstreetmap.josm.io.CachedFile;
import org.openstreetmap.josm.plugins.mapwithai.MapWithAIPlugin;
import org.openstreetmap.josm.tools.Logging;
import org.openstreetmap.josm.tools.Territories;
public class MapWithAIAvailability {
private static final String RAPID_RELEASES = "https://github.com/facebookmicrosites/Open-Mapping-At-Facebook/raw/master/data/rapid_realeases.geojson";
private static MapWithAIAvailability instance = null;
private static final Map<String, Map<String, Boolean>> COUNTRIES = new HashMap<>();
private static final Map<String, String> POSSIBLE_DATA_POINTS = new TreeMap<>();
private static final Map<String, String> COUNTRY_NAME_FIX = new HashMap<>();
static {
COUNTRY_NAME_FIX.put("Egypt", "Egypt, Arab Rep.");
COUNTRY_NAME_FIX.put("Dem. Rep. Congo", "Congo, Dem. Rep.");
POSSIBLE_DATA_POINTS.put("roads", "RapiD roads available");
POSSIBLE_DATA_POINTS.put("buildings", "MS buildings available");
}
private MapWithAIAvailability() {
try (CachedFile rapidReleases = new CachedFile(RAPID_RELEASES);
JsonParser parser = Json.createParser(rapidReleases.getContentReader())) {
if (parser.hasNext()) {
JsonParser.Event event = parser.next();
if (JsonParser.Event.START_OBJECT.equals(event)) {
Stream<Entry<String, JsonValue>> entries = parser.getObjectStream();
Optional<Entry<String, JsonValue>> objects = entries.filter(entry -> "objects".equals(entry.getKey()))
.findFirst();
if (objects.isPresent()) {
JsonObject value = objects.get().getValue().asJsonObject();
JsonObject centroid = value.getJsonObject("rapid_releases_1011_centroid");
JsonArray countries = centroid.getJsonArray("geometries");
parseForCountries(countries);
}
}
}
} catch (IOException e) {
Logging.debug(e);
}
}
/**
* @return the unique instance
*/
public static MapWithAIAvailability getInstance() {
if (instance == null) {
instance = new MapWithAIAvailability();
}
return instance;
}
private static void parseForCountries(JsonArray countries) {
for (int i = 0; i < countries.size(); i++) {
JsonObject country = countries.getJsonObject(i).getJsonObject("properties");
String countryName = cornerCaseNames(country.getString("Country"));
Optional<OsmPrimitive> realCountry = Territories.getDataSet().allPrimitives().parallelStream()
.filter(primitive -> countryName.equalsIgnoreCase(primitive.get("name:en")))
.findFirst();
if (realCountry.isPresent()) {
String key = realCountry.get().get("ISO3166-1:alpha2");
// We need to handle cases like Alaska more elegantly
Map<String, Boolean> data = COUNTRIES.getOrDefault(key, new TreeMap<>());
for (Entry<String, String> entry : POSSIBLE_DATA_POINTS.entrySet()) {
boolean hasData = "yes".equals(country.getString(entry.getValue()));
if (hasData || !data.containsKey(entry.getKey())) {
data.put(entry.getKey(), hasData);
}
}
COUNTRIES.put(key, data);
} else {
Logging.error(tr("{0}: We couldn''t find {1}", MapWithAIPlugin.NAME, countryName));
}
}
}
private static String cornerCaseNames(String name) {
if (COUNTRY_NAME_FIX.containsKey(name)) {
name = COUNTRY_NAME_FIX.get(name);
}
return name;
}
/**
* @param bbox An area that may have data
* @return True if one of the corners of the {@code bbox} is in a country with
* available data.
*/
public boolean hasData(BBox bbox) {
List<LatLon> corners = new ArrayList<>();
corners.add(bbox.getBottomRight());
corners.add(new LatLon(bbox.getBottomRightLat(), bbox.getTopLeftLon()));
corners.add(bbox.getTopLeft());
corners.add(new LatLon(bbox.getTopLeftLat(), bbox.getBottomRightLon()));
return corners.parallelStream().anyMatch(this::hasData);
}
/**
* @param latLon A point that may have data from MapWithAI
* @return true if it is in an ares with data from MapWithAI
*/
public boolean hasData(LatLon latLon) {
boolean returnBoolean = false;
for (Entry<String, Map<String, Boolean>> entry : COUNTRIES.entrySet()) {
if (Territories.isIso3166Code(entry.getKey(), latLon)) {
returnBoolean = entry.getValue().entrySet().parallelStream().anyMatch(Entry::getValue);
break;
}
}
return returnBoolean;
}
/**
* Get data types that may be visible around a point
*
* @param latLon The point of interest
* @return A map that may have available data types (or be empty)
*/
public Map<String, Boolean> getDataTypes(LatLon latLon) {
return COUNTRIES.entrySet().parallelStream().filter(entry -> Territories.isIso3166Code(entry.getKey(), latLon))
.map(Entry::getValue).findFirst().orElse(Collections.emptyMap());
}
/**
* @return A map of possible data types with their messages
*/
public static Map<String, String> getPossibleDataTypesAndMessages() {
return POSSIBLE_DATA_POINTS;
}
}

Wyświetl plik

@ -2,16 +2,12 @@
package org.openstreetmap.josm.plugins.mapwithai.backend;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.openstreetmap.josm.data.Bounds;
import org.openstreetmap.josm.data.DataSource;
import org.openstreetmap.josm.data.osm.DataSet;
import org.openstreetmap.josm.gui.MainApplication;
import org.openstreetmap.josm.gui.layer.Layer;
import org.openstreetmap.josm.gui.layer.OsmDataLayer;
import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAIDataUtils;
import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAILayer;
import org.openstreetmap.josm.testutils.JOSMTestRules;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
@ -21,46 +17,28 @@ public class MapWithAIActionTest {
@SuppressFBWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
public JOSMTestRules test = new JOSMTestRules().preferences().main().projection();
@Test
public void testGetLayer() {
Layer mapWithAILayer = MapWithAIDataUtils.getLayer(false);
Assert.assertNull(mapWithAILayer);
private MapWithAIAction action;
mapWithAILayer = MapWithAIDataUtils.getLayer(true);
Assert.assertEquals(MapWithAILayer.class, mapWithAILayer.getClass());
Layer tMapWithAI = MapWithAIDataUtils.getLayer(false);
Assert.assertSame(mapWithAILayer, tMapWithAI);
tMapWithAI = MapWithAIDataUtils.getLayer(true);
Assert.assertSame(mapWithAILayer, tMapWithAI);
@Before
public void setUp() {
action = new MapWithAIAction();
}
@Test
public void testGetData() {
final MapWithAILayer mapWithAILayer = MapWithAIDataUtils.getLayer(true);
final OsmDataLayer osm = new OsmDataLayer(new DataSet(), "test", null);
MainApplication.getLayerManager().addLayer(osm);
MapWithAIDataUtils.getMapWithAIData(mapWithAILayer, osm);
public void testEnabled() {
Assert.assertFalse(action.isEnabled());
MainApplication.getLayerManager().addLayer(new OsmDataLayer(new DataSet(), "temporary", null));
Assert.assertTrue(action.isEnabled());
}
Assert.assertTrue(mapWithAILayer.getDataSet().getDataSourceBounds().isEmpty());
@Test
public void testDownload() {
Assert.assertTrue(MainApplication.getLayerManager().getLayers().isEmpty());
action.actionPerformed(null);
Assert.assertTrue(MainApplication.getLayerManager().getLayers().isEmpty());
osm.getDataSet().addDataSource(new DataSource(new Bounds(0, 0, 0.001, 0.001), "random test"));
osm.lock();
MapWithAIDataUtils.getMapWithAIData(mapWithAILayer);
Assert.assertTrue(mapWithAILayer.getDataSet().getDataSourceBounds().isEmpty());
osm.unlock();
MapWithAIDataUtils.getMapWithAIData(mapWithAILayer);
Assert.assertFalse(mapWithAILayer.getDataSet().getDataSourceBounds().isEmpty());
Assert.assertEquals(1, mapWithAILayer.getDataSet().getDataSourceBounds().parallelStream().distinct().count());
osm.getDataSet().addDataSource(new DataSource(new Bounds(-0.001, -0.001, 0, 0), "random test"));
MapWithAIDataUtils.getMapWithAIData(mapWithAILayer);
Assert.assertEquals(2, mapWithAILayer.getDataSet().getDataSourceBounds().parallelStream().distinct().count());
MapWithAIDataUtils.getMapWithAIData(mapWithAILayer);
Assert.assertEquals(2, mapWithAILayer.getDataSet().getDataSourceBounds().parallelStream().distinct().count());
MainApplication.getLayerManager().addLayer(new OsmDataLayer(new DataSet(), "temporary", null));
action.actionPerformed(null);
Assert.assertEquals(1, MainApplication.getLayerManager().getLayersOfType(MapWithAILayer.class).size());
}
}

Wyświetl plik

@ -0,0 +1,52 @@
// License: GPL. For details, see LICENSE file.
package org.openstreetmap.josm.plugins.mapwithai.backend;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.openstreetmap.josm.data.coor.LatLon;
import org.openstreetmap.josm.data.osm.BBox;
import org.openstreetmap.josm.testutils.JOSMTestRules;
import org.openstreetmap.josm.tools.Territories;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
public class MapWithAIAvailabilityTest {
private MapWithAIAvailability instance;
@Rule
@SuppressFBWarnings("URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD")
public JOSMTestRules test = new JOSMTestRules().preferences().main().projection();
@Before
public void setUp() {
Territories.initialize();
instance = MapWithAIAvailability.getInstance();
}
@Test
public void testHasDataBBox() {
Assert.assertFalse(instance.hasData(new BBox(0, 0, 0.1, 0.1)));
Assert.assertTrue(instance.hasData(new BBox(-99.9, 39.9, 100.1, 40.1)));
}
@Test
public void testHasDataLatLon() {
Assert.assertFalse(instance.hasData(new LatLon(0, 0)));
Assert.assertTrue(instance.hasData(new LatLon(40, -100)));
Assert.assertTrue(instance.hasData(new LatLon(45.424722, -75.695)));
Assert.assertTrue(instance.hasData(new LatLon(19.433333, -99.133333)));
}
@Test
public void testgetDataLatLon() {
Assert.assertTrue(instance.getDataTypes(new LatLon(0, 0)).isEmpty());
Assert.assertTrue(instance.getDataTypes(new LatLon(40, -100)).get("roads"));
Assert.assertTrue(instance.getDataTypes(new LatLon(40, -100)).get("buildings"));
Assert.assertFalse(instance.getDataTypes(new LatLon(45.424722, -75.695)).get("roads"));
Assert.assertTrue(instance.getDataTypes(new LatLon(45.424722, -75.695)).get("buildings"));
Assert.assertTrue(instance.getDataTypes(new LatLon(19.433333, -99.133333)).get("roads"));
Assert.assertFalse(instance.getDataTypes(new LatLon(19.433333, -99.133333)).get("buildings"));
}
}

Wyświetl plik

@ -14,8 +14,12 @@ import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.openstreetmap.josm.data.Bounds;
import org.openstreetmap.josm.data.DataSource;
import org.openstreetmap.josm.data.osm.DataSet;
import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAILayer;
import org.openstreetmap.josm.gui.MainApplication;
import org.openstreetmap.josm.gui.layer.Layer;
import org.openstreetmap.josm.gui.layer.OsmDataLayer;
import org.openstreetmap.josm.testutils.JOSMTestRules;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
@ -73,6 +77,48 @@ public class MapWithAILayerTest {
Assert.assertEquals(tr("Switch Layers: {0}", false), label.getText());
}
}
}
@Test
public void testGetLayer() {
Layer mapWithAILayer = MapWithAIDataUtils.getLayer(false);
Assert.assertNull(mapWithAILayer);
mapWithAILayer = MapWithAIDataUtils.getLayer(true);
Assert.assertEquals(MapWithAILayer.class, mapWithAILayer.getClass());
Layer tMapWithAI = MapWithAIDataUtils.getLayer(false);
Assert.assertSame(mapWithAILayer, tMapWithAI);
tMapWithAI = MapWithAIDataUtils.getLayer(true);
Assert.assertSame(mapWithAILayer, tMapWithAI);
}
@Test
public void testGetData() {
final MapWithAILayer mapWithAILayer = MapWithAIDataUtils.getLayer(true);
final OsmDataLayer osm = new OsmDataLayer(new DataSet(), "test", null);
MainApplication.getLayerManager().addLayer(osm);
MapWithAIDataUtils.getMapWithAIData(mapWithAILayer, osm);
Assert.assertTrue(mapWithAILayer.getDataSet().getDataSourceBounds().isEmpty());
osm.getDataSet().addDataSource(new DataSource(new Bounds(0, 0, 0.001, 0.001), "random test"));
osm.lock();
MapWithAIDataUtils.getMapWithAIData(mapWithAILayer);
Assert.assertTrue(mapWithAILayer.getDataSet().getDataSourceBounds().isEmpty());
osm.unlock();
MapWithAIDataUtils.getMapWithAIData(mapWithAILayer);
Assert.assertFalse(mapWithAILayer.getDataSet().getDataSourceBounds().isEmpty());
Assert.assertEquals(1, mapWithAILayer.getDataSet().getDataSourceBounds().parallelStream().distinct().count());
osm.getDataSet().addDataSource(new DataSource(new Bounds(-0.001, -0.001, 0, 0), "random test"));
MapWithAIDataUtils.getMapWithAIData(mapWithAILayer);
Assert.assertEquals(2, mapWithAILayer.getDataSet().getDataSourceBounds().parallelStream().distinct().count());
MapWithAIDataUtils.getMapWithAIData(mapWithAILayer);
Assert.assertEquals(2, mapWithAILayer.getDataSet().getDataSourceBounds().parallelStream().distinct().count());
}
}