Ticket #22020: 22022.patch

File 22022.patch, 16.6 KB (added by taylor.smock, 2 years ago)

Update Mac shortcuts

  • src/org/openstreetmap/josm/io/GeoJSONReader.java

    diff --git a/src/org/openstreetmap/josm/io/GeoJSONReader.java b/src/org/openstreetmap/josm/io/GeoJSONReader.java
    index 897ab46209..0c1e3deb87 100644
    a b import java.io.InputStreamReader;  
    1111import java.io.StringReader;
    1212import java.nio.charset.StandardCharsets;
    1313import java.util.ArrayList;
    14 import java.util.Arrays;
     14import java.util.Collections;
    1515import java.util.List;
    1616import java.util.Map;
    1717import java.util.Objects;
    public class GeoJSONReader extends AbstractReader {  
    6969    private static final String TYPE = "type";
    7070    /** The record separator is 0x1E per RFC 7464 */
    7171    private static final byte RECORD_SEPARATOR_BYTE = 0x1E;
    72     private Projection projection = Projections.getProjectionByCode("EPSG:4326"); // WGS 84
     72    /**
     73     * WGS 84 is the specified CRS for geojson -- alternate coordinate systems are considered to be deprecated from
     74     * GJ2008.
     75     */
     76    private static final String CRS_GEOJSON = "EPSG:4326";
     77    private Projection projection = Projections.getProjectionByCode(CRS_GEOJSON); // WGS 84
    7378
    7479    GeoJSONReader() {
    7580        // Restricts visibility
    public class GeoJSONReader extends AbstractReader {  
    9297            case "FeatureCollection":
    9398                JsonValue.ValueType valueType = object.get(FEATURES).getValueType();
    9499                CheckParameterUtil.ensureThat(valueType == JsonValue.ValueType.ARRAY, "features must be ARRAY, but is " + valueType);
    95                 parseFeatureCollection(object.getJsonArray(FEATURES));
     100                parseFeatureCollection(object.getJsonArray(FEATURES), false);
    96101                break;
    97102            case "Feature":
    98103                parseFeature(object);
    99104                break;
    100105            case "GeometryCollection":
    101                 parseGeometryCollection(null, object);
     106                parseGeometryCollection(null, object, false);
    102107                break;
    103108            default:
    104109                parseGeometry(null, object);
    public class GeoJSONReader extends AbstractReader {  
    106111    }
    107112
    108113    /**
    109      * Parse CRS as per https://geojson.org/geojson-spec.html#coordinate-reference-system-objects.
     114     * Parse CRS as per <a href="https://geojson.org/geojson-spec.html#coordinate-reference-system-objects">https://geojson.org/geojson-spec.html#coordinate-reference-system-objects</a>.
    110115     * CRS are obsolete in RFC7946 but still allowed for interoperability with older applications.
    111116     * Only named CRS are supported.
    112117     *
    public class GeoJSONReader extends AbstractReader {  
    116121    private void parseCrs(final JsonObject crs) throws IllegalDataException {
    117122        if (crs != null) {
    118123            // Inspired by https://github.com/JOSM/geojson/commit/f13ceed4645244612a63581c96e20da802779c56
    119             JsonObject properties = crs.getJsonObject("properties");
     124            JsonObject properties = crs.getJsonObject(PROPERTIES);
    120125            if (properties != null) {
    121126                switch (crs.getString(TYPE)) {
    122127                    case NAME:
    123128                        String crsName = properties.getString(NAME);
    124129                        if ("urn:ogc:def:crs:OGC:1.3:CRS84".equals(crsName)) {
    125130                            // https://osgeo-org.atlassian.net/browse/GEOT-1710
    126                             crsName = "EPSG:4326";
     131                            crsName = CRS_GEOJSON;
    127132                        } else if (crsName.startsWith("urn:ogc:def:crs:EPSG:")) {
    128133                            crsName = crsName.replace("urn:ogc:def:crs:", "");
    129134                        }
    130135                        projection = Optional.ofNullable(Projections.getProjectionByCode(crsName))
    131                                 .orElse(Projections.getProjectionByCode("EPSG:4326")); // WGS84
     136                                .orElse(Projections.getProjectionByCode(CRS_GEOJSON)); // WGS84
    132137                        break;
    133138                    case LINK: // Not supported (security risk)
    134139                    default:
    public class GeoJSONReader extends AbstractReader {  
    138143        }
    139144    }
    140145
    141     private void parseFeatureCollection(final JsonArray features) {
    142         for (JsonValue feature : features) {
    143             if (feature instanceof JsonObject) {
    144                 parseFeature((JsonObject) feature);
    145             }
     146    private Optional<? extends OsmPrimitive> parseFeatureCollection(final JsonArray features, boolean createRelation) {
     147        List<OsmPrimitive> primitives = features.stream().filter(JsonObject.class::isInstance).map(JsonObject.class::cast)
     148                .map(this::parseFeature).filter(Optional::isPresent).map(Optional::get).collect(Collectors.toList());
     149        if (createRelation && primitives.size() > 1) {
     150            Relation relation = new Relation();
     151            relation.setMembers(primitives.stream().map(osm -> new RelationMember("", osm)).collect(Collectors.toList()));
     152            getDataSet().addPrimitive(relation);
     153            return Optional.of(relation);
     154        } else if (primitives.size() == 1) {
     155            return Optional.of(primitives.get(0));
    146156        }
     157        return Optional.empty();
    147158    }
    148159
    149     private void parseFeature(final JsonObject feature) {
     160    private Optional<? extends OsmPrimitive> parseFeature(final JsonObject feature) {
    150161        JsonValue geometry = feature.get(GEOMETRY);
    151162        if (geometry != null && geometry.getValueType() == JsonValue.ValueType.OBJECT) {
    152             parseGeometry(feature, geometry.asJsonObject());
     163            return parseGeometry(feature, geometry.asJsonObject());
    153164        } else {
    154165            JsonValue properties = feature.get(PROPERTIES);
    155166            if (properties != null && properties.getValueType() == JsonValue.ValueType.OBJECT) {
    156                 parseNonGeometryFeature(feature, properties.asJsonObject());
     167                return parseNonGeometryFeature(feature, properties.asJsonObject());
    157168            } else {
    158169                Logging.warn(tr("Relation/non-geometry feature without properties found: {0}", feature));
    159170            }
    160171        }
     172        return Optional.empty();
    161173    }
    162174
    163     private void parseNonGeometryFeature(final JsonObject feature, final JsonObject properties) {
     175    private Optional<? extends OsmPrimitive> parseNonGeometryFeature(final JsonObject feature, final JsonObject properties) {
    164176        // get relation type
    165177        JsonValue type = properties.get(TYPE);
    166178        if (type == null || properties.getValueType() == JsonValue.ValueType.STRING) {
    167179            Logging.warn(tr("Relation/non-geometry feature without type found: {0}", feature));
    168             return;
     180            if (!feature.containsKey(FEATURES)) {
     181                return Optional.empty();
     182            }
    169183        }
    170184
    171185        // create misc. non-geometry feature
    172         final Relation relation = new Relation();
    173         fillTagsFromFeature(feature, relation);
    174         relation.put(TYPE, type.toString());
    175         getDataSet().addPrimitive(relation);
     186        OsmPrimitive primitive = null;
     187        if (feature.containsKey(FEATURES) && feature.get(FEATURES).getValueType() == JsonValue.ValueType.ARRAY) {
     188            Optional<? extends OsmPrimitive> osm = parseFeatureCollection(feature.getJsonArray(FEATURES), true);
     189            if (osm.isPresent()) {
     190                primitive = osm.get();
     191                fillTagsFromFeature(feature, primitive);
     192            }
     193        }
     194        return Optional.ofNullable(primitive);
    176195    }
    177196
    178     private void parseGeometryCollection(final JsonObject feature, final JsonObject geometry) {
     197    private Optional<Relation> parseGeometryCollection(final JsonObject feature, final JsonObject geometry, boolean createRelation) {
     198        List<RelationMember> relationMembers = new ArrayList<>(geometry.getJsonArray("geometries").size());
    179199        for (JsonValue jsonValue : geometry.getJsonArray("geometries")) {
    180             parseGeometry(feature, jsonValue.asJsonObject());
     200            parseGeometry(feature, jsonValue.asJsonObject()).map(osm -> new RelationMember("", osm)).ifPresent(relationMembers::add);
    181201        }
     202        if (createRelation) {
     203            Relation relation = new Relation();
     204            relation.setMembers(relationMembers);
     205            getDataSet().addPrimitive(relation);
     206            return Optional.of(fillTagsFromFeature(feature, relation));
     207        }
     208        return Optional.empty();
    182209    }
    183210
    184     private void parseGeometry(final JsonObject feature, final JsonObject geometry) {
     211    private Optional<? extends OsmPrimitive> parseGeometry(final JsonObject feature, final JsonObject geometry) {
    185212        if (geometry == null) {
    186213            parseNullGeometry(feature);
    187             return;
     214            return Optional.empty();
    188215        }
    189216
    190217        switch (geometry.getString(TYPE)) {
    191218            case "Point":
    192                 parsePoint(feature, geometry.getJsonArray(COORDINATES));
    193                 break;
     219                return parsePoint(feature, geometry.getJsonArray(COORDINATES));
    194220            case "MultiPoint":
    195                 parseMultiPoint(feature, geometry);
    196                 break;
     221                return parseMultiPoint(feature, geometry);
    197222            case "LineString":
    198                 parseLineString(feature, geometry.getJsonArray(COORDINATES));
    199                 break;
     223                return parseLineString(feature, geometry.getJsonArray(COORDINATES));
    200224            case "MultiLineString":
    201                 parseMultiLineString(feature, geometry);
    202                 break;
     225                return parseMultiLineString(feature, geometry);
    203226            case "Polygon":
    204                 parsePolygon(feature, geometry.getJsonArray(COORDINATES));
    205                 break;
     227                return parsePolygon(feature, geometry.getJsonArray(COORDINATES));
    206228            case "MultiPolygon":
    207                 parseMultiPolygon(feature, geometry);
    208                 break;
     229                return parseMultiPolygon(feature, geometry);
    209230            case "GeometryCollection":
    210                 parseGeometryCollection(feature, geometry);
    211                 break;
     231                return parseGeometryCollection(feature, geometry, true);
    212232            default:
    213233                parseUnknown(geometry);
     234                return Optional.empty();
    214235        }
    215236    }
    216237
    public class GeoJSONReader extends AbstractReader {  
    230251        }
    231252    }
    232253
    233     private void parsePoint(final JsonObject feature, final JsonArray coordinates) {
    234         fillTagsFromFeature(feature, createNode(getLatLon(coordinates)));
     254    private Optional<Node> parsePoint(final JsonObject feature, final JsonArray coordinates) {
     255        return Optional.of(fillTagsFromFeature(feature, createNode(getLatLon(coordinates))));
    235256    }
    236257
    237     private void parseMultiPoint(final JsonObject feature, final JsonObject geometry) {
     258    private Optional<Relation> parseMultiPoint(final JsonObject feature, final JsonObject geometry) {
     259        List<RelationMember> nodes = new ArrayList<>(geometry.getJsonArray(COORDINATES).size());
    238260        for (JsonValue coordinate : geometry.getJsonArray(COORDINATES)) {
    239             parsePoint(feature, coordinate.asJsonArray());
     261            parsePoint(feature, coordinate.asJsonArray()).map(node -> new RelationMember("", node)).ifPresent(nodes::add);
    240262        }
     263        Relation returnRelation = new Relation();
     264        returnRelation.setMembers(nodes);
     265        getDataSet().addPrimitive(returnRelation);
     266        return Optional.of(fillTagsFromFeature(feature, returnRelation));
    241267    }
    242268
    243     private void parseLineString(final JsonObject feature, final JsonArray coordinates) {
     269    private Optional<Way> parseLineString(final JsonObject feature, final JsonArray coordinates) {
    244270        if (!coordinates.isEmpty()) {
    245             createWay(coordinates, false)
    246                 .ifPresent(way -> fillTagsFromFeature(feature, way));
     271            Optional<Way> way = createWay(coordinates, false);
     272            way.ifPresent(tWay -> fillTagsFromFeature(feature, tWay));
     273            return way;
    247274        }
     275        return Optional.empty();
    248276    }
    249277
    250     private void parseMultiLineString(final JsonObject feature, final JsonObject geometry) {
     278    private Optional<Relation> parseMultiLineString(final JsonObject feature, final JsonObject geometry) {
     279        final List<RelationMember> ways = new ArrayList<>(geometry.getJsonArray(COORDINATES).size());
    251280        for (JsonValue coordinate : geometry.getJsonArray(COORDINATES)) {
    252             parseLineString(feature, coordinate.asJsonArray());
     281            parseLineString(feature, coordinate.asJsonArray()).map(way -> new RelationMember("", way)).ifPresent(ways::add);
    253282        }
     283        final Relation relation = new Relation();
     284        relation.setMembers(ways);
     285        getDataSet().addPrimitive(relation);
     286        return Optional.of(fillTagsFromFeature(feature, relation));
    254287    }
    255288
    256     private void parsePolygon(final JsonObject feature, final JsonArray coordinates) {
     289    private Optional<? extends OsmPrimitive> parsePolygon(final JsonObject feature, final JsonArray coordinates) {
    257290        final int size = coordinates.size();
    258291        if (size == 1) {
    259             createWay(coordinates.getJsonArray(0), true)
    260                 .ifPresent(way -> fillTagsFromFeature(feature, way));
     292            Optional<Way> optionalWay = createWay(coordinates.getJsonArray(0), true);
     293            optionalWay.ifPresent(way -> fillTagsFromFeature(feature, way));
     294            return optionalWay;
    261295        } else if (size > 1) {
    262296            // create multipolygon
    263297            final Relation multipolygon = new Relation();
    public class GeoJSONReader extends AbstractReader {  
    272306            fillTagsFromFeature(feature, multipolygon);
    273307            multipolygon.put(TYPE, "multipolygon");
    274308            getDataSet().addPrimitive(multipolygon);
     309            return Optional.of(multipolygon);
    275310        }
     311        return Optional.empty();
    276312    }
    277313
    278     private void parseMultiPolygon(final JsonObject feature, final JsonObject geometry) {
     314    private Optional<Relation> parseMultiPolygon(final JsonObject feature, final JsonObject geometry) {
     315        List<RelationMember> relationMembers = new ArrayList<>(geometry.getJsonArray(COORDINATES).size());
    279316        for (JsonValue coordinate : geometry.getJsonArray(COORDINATES)) {
    280             parsePolygon(feature, coordinate.asJsonArray());
     317            parsePolygon(feature, coordinate.asJsonArray()).map(poly -> new RelationMember("", poly)).ifPresent(relationMembers::add);
    281318        }
     319        Relation relation = new Relation();
     320        relation.setMembers(relationMembers);
     321        return Optional.of(fillTagsFromFeature(feature, relation));
    282322    }
    283323
    284324    private Node createNode(final LatLon latlon) {
    public class GeoJSONReader extends AbstractReader {  
    336376     * Merge existing tags in primitive (if any) with the values given in the GeoJSON feature.
    337377     * @param feature the GeoJSON feature
    338378     * @param primitive the OSM primitive
     379     * @param <O> The primitive type
     380     * @return The primitive passed in as {@code primitive} for easier chaining
    339381     */
    340     private static void fillTagsFromFeature(final JsonObject feature, final OsmPrimitive primitive) {
     382    private static <O extends OsmPrimitive> O fillTagsFromFeature(final JsonObject feature, final O primitive) {
    341383        if (feature != null) {
    342384            TagCollection featureTags = getTags(feature);
    343385            primitive.setKeys(new TagMap(primitive.isTagged() ? mergeAllTagValues(primitive, featureTags) : featureTags));
    344386        }
     387        return primitive;
    345388    }
    346389
    347390    private static TagCollection mergeAllTagValues(final OsmPrimitive primitive, TagCollection featureTags) {
    348391        TagCollection tags = TagCollection.from(primitive).union(featureTags);
    349392        TagConflictResolutionUtil.applyAutomaticTagConflictResolution(tags);
    350         TagConflictResolutionUtil.normalizeTagCollectionBeforeEditing(tags, Arrays.asList(primitive));
     393        TagConflictResolutionUtil.normalizeTagCollectionBeforeEditing(tags, Collections.singletonList(primitive));
    351394        TagConflictResolverModel tagModel = new TagConflictResolverModel();
    352395        tagModel.populate(new TagCollection(tags), tags.getKeysWithMultipleValues());
    353396        tagModel.actOnDecisions((k, d) -> d.keepAll());
    public class GeoJSONReader extends AbstractReader {  
    454497                List<Way> mpWays = new ArrayList<>();
    455498                Way replacement = null;
    456499                for (OsmPrimitive p : e.getPrimitives()) {
    457                     if (p.isTagged() && p.referrers(Relation.class).count() == 0)
     500                    if (p.isTagged() && !p.referrers(Relation.class).findAny().isPresent())
    458501                        replacement = (Way) p;
    459502                    else if (p.referrers(Relation.class).anyMatch(Relation::isMultipolygon))
    460503                        mpWays.add((Way) p);