JsonImageDetectionDecoder.java
// License: GPL. For details, see LICENSE file.
package org.openstreetmap.josm.plugins.streetside.utils.api;
import java.awt.Shape;
import java.awt.geom.Path2D;
import javax.json.JsonArray;
import javax.json.JsonNumber;
import javax.json.JsonObject;
import javax.json.JsonValue;
import org.openstreetmap.josm.plugins.streetside.model.ImageDetection;
import org.openstreetmap.josm.plugins.streetside.utils.StreetsideURL.APIv3;
import org.openstreetmap.josm.tools.Logging;
/**
* Decodes the JSON returned by {@link APIv3} into Java objects.
* Takes a {@link JsonObject} and {@link #decodeImageDetection(JsonObject)} tries to convert it to a {@link ImageDetection}.
*/
public final class JsonImageDetectionDecoder {
private JsonImageDetectionDecoder() {
// Private constructor to avoid instantiation
}
// TODO: Image detections? Keep? @rrh
public static ImageDetection decodeImageDetection(final JsonObject json) {
if (json == null || !"Feature".equals(json.getString("type", null))) {
return null;
}
final JsonValue properties = json.get("properties");
if (properties instanceof JsonObject) {
final String key = ((JsonObject) properties).getString("key", null);
final String packag = ((JsonObject) properties).getString("package", null);
final String imageKey = ((JsonObject) properties).getString("image_key", null);
final String value = ((JsonObject) properties).getString("value", null);
final JsonValue scoreVal = ((JsonObject) properties).get("score");
final Double score = scoreVal instanceof JsonNumber ? ((JsonNumber) scoreVal).doubleValue() : null;
final Shape shape = decodeShape(((JsonObject) properties).get("shape"));
if (shape instanceof Path2D && imageKey != null && key != null && score != null && packag != null && value != null) {
return new ImageDetection((Path2D) shape, imageKey, key, score, packag, value);
}
}
return null;
}
private static Shape decodeShape(JsonValue json) {
if (json instanceof JsonObject) {
if (!"Polygon".equals(((JsonObject) json).getString("type", null))) {
Logging.warn(
String.format("Image detections using shapes with type=%s are currently not supported!",
((JsonObject) json).getString("type", "‹no type set›"))
);
} else {
final JsonValue coordinates = ((JsonObject) json).get("coordinates");
if (coordinates instanceof JsonArray && !((JsonArray) coordinates).isEmpty()) {
return decodePolygon((JsonArray) coordinates);
}
}
}
return null;
}
/**
* Decodes a polygon (may be a multipolygon) from JSON
* @param json the json array to decode, must not be <code>null</code>
* @return the decoded polygon as {@link Path2D.Double}
*/
private static Path2D decodePolygon(final JsonArray json) {
final Path2D shape = new Path2D.Double();
json.forEach(val -> {
final Shape part = val instanceof JsonArray ? decodeSimplePolygon((JsonArray) val) : null;
if (part != null) {
shape.append(part, false);
}
});
if (shape.getCurrentPoint() != null) {
return shape;
}
return null;
}
/**
* Decodes a simple polygon (consisting of only one continuous path) from JSON
* @param json the json array to decode, must not be <code>null</code>
* @return the decoded polygon as {@link Path2D.Double}
* @throws NullPointerException if parameter is <code>null</code>
*/
private static Path2D decodeSimplePolygon(final JsonArray json) {
final Path2D shape = new Path2D.Double();
json.forEach(val -> {
double[] coord = JsonDecoder.decodeDoublePair(val instanceof JsonArray ? (JsonArray) val : null);
if (shape.getCurrentPoint() == null && coord != null) {
shape.moveTo(coord[0], coord[1]);
} else if (coord != null) {
shape.lineTo(coord[0], coord[1]);
}
});
if (shape.getCurrentPoint() != null) {
shape.closePath();
return shape;
}
return null;
}
}