From dad57df38ef86363da9bff2e62f3fddc5688f0cf Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Wed, 14 Dec 2016 14:58:06 -0800 Subject: [core] Fix symbol rendering for multipoints Ports https://github.com/mapbox/mapbox-gl-js/pull/3763 and https://github.com/mapbox/mapbox-gl-js/pull/3806. --- src/mbgl/layout/symbol_feature.hpp | 1 + src/mbgl/layout/symbol_layout.cpp | 132 ++++++++++++++++++++----------------- src/mbgl/layout/symbol_layout.hpp | 5 +- 3 files changed, 75 insertions(+), 63 deletions(-) (limited to 'src/mbgl/layout') diff --git a/src/mbgl/layout/symbol_feature.hpp b/src/mbgl/layout/symbol_feature.hpp index 9e0eacaac5..5dd61d9156 100644 --- a/src/mbgl/layout/symbol_feature.hpp +++ b/src/mbgl/layout/symbol_feature.hpp @@ -9,6 +9,7 @@ namespace mbgl { class SymbolFeature { public: + FeatureType type; GeometryCollection geometry; optional text; optional icon; diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index 2b7b41b8c9..7be2c13ada 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -103,16 +103,8 @@ SymbolLayout::SymbolLayout(std::string bucketName_, } if (ft.text || ft.icon) { - auto &multiline = ft.geometry; - - GeometryCollection geometryCollection = feature->getGeometries(); - for (auto& line : geometryCollection) { - multiline.emplace_back(); - for (auto& point : line) { - multiline.back().emplace_back(point.x, point.y); - } - } - + ft.type = feature->getType(); + ft.geometry = feature->getGeometries(); features.push_back(std::move(ft)); } } @@ -229,17 +221,17 @@ void SymbolLayout::prepare(uintptr_t tileUID, // if either shapedText or icon position is present, add the feature if (shapedText || shapedIcon) { - addFeature(feature.geometry, shapedText, shapedIcon, face, feature.index); + addFeature(feature, shapedText, shapedIcon, face); } } features.clear(); } - -void SymbolLayout::addFeature(const GeometryCollection &lines, - const Shaping &shapedText, const PositionedIcon &shapedIcon, const GlyphPositions &face, const size_t index) { - +void SymbolLayout::addFeature(const SymbolFeature& feature, + const Shaping& shapedText, + const PositionedIcon& shapedIcon, + const GlyphPositions& face) { const float minScale = 0.5f; const float glyphSize = 24.0f; @@ -258,55 +250,75 @@ void SymbolLayout::addFeature(const GeometryCollection &lines, const SymbolPlacementType iconPlacement = layout.get() != AlignmentType::Map ? SymbolPlacementType::Point : layout.get(); - const bool isLine = layout.get() == SymbolPlacementType::Line; const float textRepeatDistance = symbolSpacing / 2; + IndexedSubfeature indexedFeature = {feature.index, sourceLayerName, bucketName, symbolInstances.size()}; + + auto addSymbolInstance = [&] (const GeometryCoordinates& line, Anchor& anchor) { + // https://github.com/mapbox/vector-tile-spec/tree/master/2.1#41-layers + // +-------------------+ Symbols with anchors located on tile edges + // |(0,0) || are duplicated on neighbor tiles. + // | || + // | || In continuous mode, to avoid overdraw we + // | || skip symbols located on the extent edges. + // | Tile || In still mode, we include the features in + // | || the buffers for both tiles and clip them + // | || at draw time. + // | || + // +-------------------| In this scenario, the inner bounding box + // +-------------------+ is called 'withinPlus0', and the outer + // (extent,extent) is called 'inside'. + const bool withinPlus0 = anchor.point.x >= 0 && anchor.point.x < util::EXTENT && anchor.point.y >= 0 && anchor.point.y < util::EXTENT; + const bool inside = withinPlus0 || anchor.point.x == util::EXTENT || anchor.point.y == util::EXTENT; + + if (avoidEdges && !inside) return; + + const bool addToBuffers = mode == MapMode::Still || withinPlus0; + + symbolInstances.emplace_back(anchor, line, shapedText, shapedIcon, layout, addToBuffers, symbolInstances.size(), + textBoxScale, textPadding, textPlacement, + iconBoxScale, iconPadding, iconPlacement, + face, indexedFeature); + }; - auto& clippedLines = isLine ? - util::clipLines(lines, 0, 0, util::EXTENT, util::EXTENT) : - lines; - - IndexedSubfeature indexedFeature = {index, sourceLayerName, bucketName, symbolInstances.size()}; - - for (const auto& line : clippedLines) { - if (line.empty()) continue; - - // Calculate the anchor points around which you want to place labels - Anchors anchors = isLine ? - getAnchors(line, symbolSpacing, textMaxAngle, shapedText.left, shapedText.right, shapedIcon.left, shapedIcon.right, glyphSize, textMaxBoxScale, overscaling) : - Anchors({ Anchor(float(line[0].x), float(line[0].y), 0, minScale) }); - - // For each potential label, create the placement features used to check for collisions, and the quads use for rendering. - for (Anchor &anchor : anchors) { - if (shapedText && isLine) { - if (anchorIsTooClose(shapedText.text, textRepeatDistance, anchor)) { - continue; + if (layout.get() == SymbolPlacementType::Line) { + auto clippedLines = util::clipLines(feature.geometry, 0, 0, util::EXTENT, util::EXTENT); + for (const auto& line : clippedLines) { + Anchors anchors = getAnchors(line, + symbolSpacing, + textMaxAngle, + shapedText.left, + shapedText.right, + shapedIcon.left, + shapedIcon.right, + glyphSize, + textMaxBoxScale, + overscaling); + + for (auto& anchor : anchors) { + if (!shapedText || !anchorIsTooClose(shapedText.text, textRepeatDistance, anchor)) { + addSymbolInstance(line, anchor); } } - - // https://github.com/mapbox/vector-tile-spec/tree/master/2.1#41-layers - // +-------------------+ Symbols with anchors located on tile edges - // |(0,0) || are duplicated on neighbor tiles. - // | || - // | || In continuous mode, to avoid overdraw we - // | || skip symbols located on the extent edges. - // | Tile || In still mode, we include the features in - // | || the buffers for both tiles and clip them - // | || at draw time. - // | || - // +-------------------| In this scenario, the inner bounding box - // +-------------------+ is called 'withinPlus0', and the outer - // (extent,extent) is called 'inside'. - const bool withinPlus0 = anchor.point.x >= 0 && anchor.point.x < util::EXTENT && anchor.point.y >= 0 && anchor.point.y < util::EXTENT; - const bool inside = withinPlus0 || anchor.point.x == util::EXTENT || anchor.point.y == util::EXTENT; - - if (avoidEdges && !inside) continue; - - const bool addToBuffers = mode == MapMode::Still || withinPlus0; - - symbolInstances.emplace_back(anchor, line, shapedText, shapedIcon, layout, addToBuffers, symbolInstances.size(), - textBoxScale, textPadding, textPlacement, - iconBoxScale, iconPadding, iconPlacement, - face, indexedFeature); + } + } else if (feature.type == FeatureType::Polygon) { + // TODO: pole of inaccessibility + for (const auto& ring : feature.geometry) { + for (const auto& point : ring) { + Anchor anchor(point.x, point.y, 0, minScale); + addSymbolInstance(ring, anchor); + } + } + } else if (feature.type == FeatureType::LineString) { + for (const auto& line : feature.geometry) { + Anchor anchor(line[0].x, line[0].y, 0, minScale); + addSymbolInstance(line, anchor); + } + } else if (feature.type == FeatureType::Point) { + for (const auto& points : feature.geometry) { + for (const auto& point : points) { + Anchor anchor(point.x, point.y, 0, minScale); + addSymbolInstance({point}, anchor); + } } } } diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp index faed2de2a0..18fb9ff4bc 100644 --- a/src/mbgl/layout/symbol_layout.hpp +++ b/src/mbgl/layout/symbol_layout.hpp @@ -59,11 +59,10 @@ public: const std::string sourceLayerName; private: - void addFeature(const GeometryCollection&, + void addFeature(const SymbolFeature&, const Shaping& shapedText, const PositionedIcon& shapedIcon, - const GlyphPositions& face, - const size_t index); + const GlyphPositions& face); bool anchorIsTooClose(const std::u16string& text, const float repeatDistance, const Anchor&); std::map> compareText; -- cgit v1.2.1