Changeset 18578 in josm for trunk/src/org


Ignore:
Timestamp:
2022-10-18T00:43:38+02:00 (2 years ago)
Author:
taylor.smock
Message:

Fix #22404: MVT background layer: Polygons not drawn

This was a two-part problem:

  1. Converting shapes to areas does not always keep the same winding.
  2. MVT styles are minZoom <= showable zooms < maxZoom. We were doing minZoom <= showable zooms <= maxZoom.

This also fixes some sonarlint issues in the modified files.

Location:
trunk/src/org/openstreetmap/josm/data
Files:
2 added
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/data/imagery/vectortile/mapbox/style/Layers.java

    r18211 r18578  
    7676
    7777    /** Default paint properties for this layer */
    78     private final String paint;
     78    private final String paintProperties;
    7979
    8080    /** A source description to be used with this layer. Required for everything <i>but</i> {@link Type#BACKGROUND} */
     
    106106            this.filter = Expression.EMPTY_EXPRESSION;
    107107        }
    108         this.maxZoom = layerInfo.getInt("maxzoom", Integer.MAX_VALUE);
     108        // minZoom <= showable zooms < maxZoom. This should be fractional, but our mapcss implementations expects ints.
    109109        this.minZoom = layerInfo.getInt("minzoom", Integer.MIN_VALUE);
     110        int tMaxZoom = layerInfo.getInt("maxzoom", Integer.MAX_VALUE);
     111        if (tMaxZoom == Integer.MAX_VALUE) {
     112            this.maxZoom = Integer.MAX_VALUE;
     113        } else {
     114            this.maxZoom = Math.max(this.minZoom, Math.max(0, tMaxZoom - 1));
     115        }
    110116        // There is a metadata field (I don't *think* I need it?)
    111117        // source is only optional with {@link Type#BACKGROUND}.
     
    123129                case FILL:
    124130                    // area
    125                     this.paint = parsePaintFill(paintObject);
     131                    this.paintProperties = parsePaintFill(paintObject);
    126132                    break;
    127133                case LINE:
    128134                    // way
    129                     this.paint = parsePaintLine(layoutObject, paintObject);
     135                    this.paintProperties = parsePaintLine(layoutObject, paintObject);
    130136                    break;
    131137                case CIRCLE:
    132138                    // point
    133                     this.paint = parsePaintCircle(paintObject);
     139                    this.paintProperties = parsePaintCircle(paintObject);
    134140                    break;
    135141                case SYMBOL:
    136142                    // point
    137                     this.paint = parsePaintSymbol(layoutObject, paintObject);
     143                    this.paintProperties = parsePaintSymbol(layoutObject, paintObject);
    138144                    break;
    139145                case BACKGROUND:
    140146                    // canvas only
    141                     this.paint = parsePaintBackground(paintObject);
     147                    this.paintProperties = parsePaintBackground(paintObject);
    142148                    break;
    143149                default:
    144                     this.paint = EMPTY_STRING;
     150                    this.paintProperties = EMPTY_STRING;
    145151                }
    146152            } else {
    147                 this.paint = EMPTY_STRING;
     153                this.paintProperties = EMPTY_STRING;
    148154            }
    149155        } else {
    150             this.paint = EMPTY_STRING;
     156            this.paintProperties = EMPTY_STRING;
    151157        }
    152158        this.sourceLayer = layerInfo.getString("source-layer", null);
     
    454460    @Override
    455461    public String toString() {
    456         if (this.filter.toString().isEmpty() && this.paint.isEmpty()) {
     462        if (this.filter.toString().isEmpty() && this.paintProperties.isEmpty()) {
    457463            return EMPTY_STRING;
    458464        } else if (this.type == Type.BACKGROUND) {
    459465            // AFAIK, paint has no zoom levels, and doesn't accept a layer
    460             return "canvas{" + this.paint + "}";
     466            return "canvas{" + this.paintProperties + "}";
    461467        }
    462468
     
    473479            zoomSelector = EMPTY_STRING;
    474480        }
    475         final String commonData = zoomSelector + this.filter.toString() + "::" + this.id + "{" + this.paint + "}";
     481        final String commonData = zoomSelector + this.filter.toString() + "::" + this.id + "{" + this.paintProperties + "}";
    476482
    477483        if (this.type == Type.CIRCLE || this.type == Type.SYMBOL) {
     
    513519              && Objects.equals(this.source, o.source)
    514520              && Objects.equals(this.filter, o.filter)
    515               && Objects.equals(this.paint, o.paint);
     521              && Objects.equals(this.paintProperties, o.paintProperties);
    516522        }
    517523        return false;
     
    521527    public int hashCode() {
    522528        return Objects.hash(this.type, this.minZoom, this.maxZoom, this.id, this.styleId, this.sourceLayer, this.source,
    523           this.filter, this.paint);
     529          this.filter, this.paintProperties);
    524530    }
    525531}
  • trunk/src/org/openstreetmap/josm/data/osm/PrimitiveId.java

    r13924 r18578  
    1717
    1818    /**
    19      * Gets the type of object represented by this object.
     19     * Gets the type of object represented by this object. Note that this should
     20     * return the base primitive type ({@link OsmPrimitiveType#NODE},
     21     * {@link OsmPrimitiveType#WAY}, and {@link OsmPrimitiveType#RELATION}).
    2022     *
    2123     * @return the object type
  • trunk/src/org/openstreetmap/josm/data/vector/VectorDataStore.java

    r18478 r18578  
    7878            if (mergedRelation.getMemberPrimitivesList().stream().allMatch(IWay.class::isInstance)) {
    7979                // This pretty much does the "right" thing
    80                 this.mergeWays(mergedRelation);
     80                mergeWays(mergedRelation);
    8181            } else if (!(primitive instanceof IWay)) {
    8282                // Can't merge, ever (one of the childs is a node/relation)
    8383                mergedRelation.remove(JOSM_MERGE_TYPE_KEY);
    8484            }
    85         } else if (mergedRelation != null && primitive instanceof IRelation) {
     85        } else if (mergedRelation != null && primitive instanceof VectorRelation) {
    8686            // Just add to the relation
    8787            ((VectorRelation) primitive).getMembers().forEach(mergedRelation::addRelationMember);
     
    9999    }
    100100
    101     private VectorPrimitive mergeWays(VectorRelation relation) {
     101    private static VectorPrimitive mergeWays(VectorRelation relation) {
    102102        List<VectorRelationMember> members = RelationSorter.sortMembersByConnectivity(relation.getMembers());
    103103        Collection<VectorWay> relationWayList = members.stream().map(VectorRelationMember::getMember)
     
    268268      Collection<VectorPrimitive> featureObjects, Area area) {
    269269        VectorRelation vectorRelation = new VectorRelation(layer.getName());
    270         for (VectorPrimitive member : pathIteratorToObjects(tile, layer, featureObjects, area.getPathIterator(null))) {
     270        PathIterator pathIterator = area.getPathIterator(null);
     271        int windingRule = pathIterator.getWindingRule();
     272        for (VectorPrimitive member : pathIteratorToObjects(tile, layer, featureObjects, pathIterator)) {
    271273            final String role;
    272274            if (member instanceof VectorWay && ((VectorWay) member).isClosed()) {
     275                // Area messes up the winding. See #22404.
     276                if (windingRule == PathIterator.WIND_NON_ZERO) {
     277                    VectorWay vectorWay = (VectorWay) member;
     278                    List<VectorNode> nodes = new ArrayList<>(vectorWay.getNodes());
     279                    Collections.reverse(nodes);
     280                    vectorWay.setNodes(nodes);
     281                }
    273282                role = Geometry.isClockwise(((VectorWay) member).getNodes()) ? "outer" : "inner";
    274283            } else {
     
    375384            primitive = pathToWay(tile, layer, featureObjects, (Path2D) shape).stream().findFirst().orElse(null);
    376385        } else if (shape instanceof Area) {
    377             primitive = areaToRelation(tile, layer, featureObjects, (Area) shape);
    378             primitive.put(RELATION_TYPE, MULTIPOLYGON_TYPE);
     386            VectorRelation vectorRelation = areaToRelation(tile, layer, featureObjects, (Area) shape);
     387            if (vectorRelation.getMembersCount() != 1) {
     388                primitive = vectorRelation;
     389                primitive.put(RELATION_TYPE, MULTIPOLYGON_TYPE);
     390            } else {
     391                primitive = vectorRelation.getMember(0).getMember();
     392            }
    379393        } else {
    380394            // We shouldn't hit this, but just in case
  • trunk/src/org/openstreetmap/josm/data/vector/VectorWay.java

    r18214 r18578  
    131131    @Override
    132132    public OsmPrimitiveType getType() {
     133        return OsmPrimitiveType.WAY;
     134    }
     135
     136    @Override
     137    public OsmPrimitiveType getDisplayType() {
    133138        return this.isClosed() ? OsmPrimitiveType.CLOSEDWAY : OsmPrimitiveType.WAY;
    134139    }
Note: See TracChangeset for help on using the changeset viewer.