diff options
Diffstat (limited to 'src/mbgl/text')
-rw-r--r-- | src/mbgl/text/collision_index.cpp | 44 | ||||
-rw-r--r-- | src/mbgl/text/collision_index.hpp | 14 | ||||
-rw-r--r-- | src/mbgl/text/placement.cpp | 11 |
3 files changed, 52 insertions, 17 deletions
diff --git a/src/mbgl/text/collision_index.cpp b/src/mbgl/text/collision_index.cpp index 091840a371..dae789a196 100644 --- a/src/mbgl/text/collision_index.cpp +++ b/src/mbgl/text/collision_index.cpp @@ -62,6 +62,21 @@ bool CollisionIndex::isOffscreen(const CollisionBox& box) const { bool CollisionIndex::isInsideGrid(const CollisionBox& box) const { return box.px2 >= 0 && box.px1 < gridRightBoundary && box.py2 >= 0 && box.py1 < gridBottomBoundary; } + +CollisionTileBoundaries CollisionIndex::projectTileBoundaries(const mat4& posMatrix) const { + Point<float> topLeft = projectPoint(posMatrix, { 0, 0 }); + Point<float> bottomRight = projectPoint(posMatrix, { util::EXTENT, util::EXTENT }); + + return {{ topLeft.x, topLeft.y, bottomRight.x, bottomRight.y }}; + +} + +bool CollisionIndex::isInsideTile(const CollisionBox& box, const CollisionTileBoundaries& tileBoundaries) const { + // This check is only well defined when the tile boundaries are axis-aligned + // We are relying on it only being used in MapMode::Tile, where that is always the case + + return box.px1 >= tileBoundaries[0] && box.py1 >= tileBoundaries[1] && box.px2 < tileBoundaries[2] && box.py2 < tileBoundaries[3]; +} std::pair<bool,bool> CollisionIndex::placeFeature(CollisionFeature& feature, @@ -73,7 +88,8 @@ std::pair<bool,bool> CollisionIndex::placeFeature(CollisionFeature& feature, const float fontSize, const bool allowOverlap, const bool pitchWithMap, - const bool collisionDebug) { + const bool collisionDebug, + const optional<CollisionTileBoundaries>& avoidEdges) { if (!feature.alongLine) { CollisionBox& box = feature.boxes.front(); const auto projectedPoint = projectAndGetPerspectiveRatio(posMatrix, box.anchor); @@ -82,15 +98,17 @@ std::pair<bool,bool> CollisionIndex::placeFeature(CollisionFeature& feature, box.py1 = box.y1 * tileToViewport + projectedPoint.first.y; box.px2 = box.x2 * tileToViewport + projectedPoint.first.x; box.py2 = box.y2 * tileToViewport + projectedPoint.first.y; + - if (!isInsideGrid(box) || + if ((avoidEdges && !isInsideTile(box, *avoidEdges)) || + !isInsideGrid(box) || (!allowOverlap && collisionGrid.hitTest({{ box.px1, box.py1 }, { box.px2, box.py2 }}))) { return { false, false }; } return {true, isOffscreen(box)}; } else { - return placeLineFeature(feature, posMatrix, labelPlaneMatrix, textPixelRatio, symbol, scale, fontSize, allowOverlap, pitchWithMap, collisionDebug); + return placeLineFeature(feature, posMatrix, labelPlaneMatrix, textPixelRatio, symbol, scale, fontSize, allowOverlap, pitchWithMap, collisionDebug, avoidEdges); } } @@ -103,7 +121,8 @@ std::pair<bool,bool> CollisionIndex::placeLineFeature(CollisionFeature& feature, const float fontSize, const bool allowOverlap, const bool pitchWithMap, - const bool collisionDebug) { + const bool collisionDebug, + const optional<CollisionTileBoundaries>& avoidEdges) { const auto tileUnitAnchorPoint = symbol.anchorPoint; const auto projectedAnchor = projectAnchor(posMatrix, tileUnitAnchorPoint); @@ -202,15 +221,14 @@ std::pair<bool,bool> CollisionIndex::placeLineFeature(CollisionFeature& feature, entirelyOffscreen &= isOffscreen(circle); inGrid |= isInsideGrid(circle); - if (!allowOverlap) { - if (collisionGrid.hitTest({{circle.px, circle.py}, circle.radius})) { - if (!collisionDebug) { - return {false, false}; - } else { - // Don't early exit if we're showing the debug circles because we still want to calculate - // which circles are in use - collisionDetected = true; - } + if ((avoidEdges && !isInsideTile(circle, *avoidEdges)) || + (!allowOverlap && collisionGrid.hitTest({{circle.px, circle.py}, circle.radius}))) { + if (!collisionDebug) { + return {false, false}; + } else { + // Don't early exit if we're showing the debug circles because we still want to calculate + // which circles are in use + collisionDetected = true; } } } diff --git a/src/mbgl/text/collision_index.hpp b/src/mbgl/text/collision_index.hpp index b2be4c6ade..78782fe61c 100644 --- a/src/mbgl/text/collision_index.hpp +++ b/src/mbgl/text/collision_index.hpp @@ -3,13 +3,18 @@ #include <mbgl/geometry/feature_index.hpp> #include <mbgl/text/collision_feature.hpp> #include <mbgl/util/grid_index.hpp> +#include <mbgl/util/optional.hpp> #include <mbgl/map/transform_state.hpp> +#include <array> + namespace mbgl { class PlacedSymbol; struct TileDistance; + +using CollisionTileBoundaries = std::array<float,4>; class CollisionIndex { public: @@ -26,15 +31,19 @@ public: const float fontSize, const bool allowOverlap, const bool pitchWithMap, - const bool collisionDebug); + const bool collisionDebug, + const optional<CollisionTileBoundaries>& avoidEdges); void insertFeature(CollisionFeature& feature, bool ignorePlacement, uint32_t bucketInstanceId); std::unordered_map<uint32_t, std::vector<IndexedSubfeature>> queryRenderedSymbols(const ScreenLineString&) const; + + CollisionTileBoundaries projectTileBoundaries(const mat4& posMatrix) const; private: bool isOffscreen(const CollisionBox&) const; bool isInsideGrid(const CollisionBox&) const; + bool isInsideTile(const CollisionBox&, const CollisionTileBoundaries& tileBoundaries) const; std::pair<bool,bool> placeLineFeature(CollisionFeature& feature, const mat4& posMatrix, @@ -45,7 +54,8 @@ private: const float fontSize, const bool allowOverlap, const bool pitchWithMap, - const bool collisionDebug); + const bool collisionDebug, + const optional<CollisionTileBoundaries>& avoidEdges); float approximateTileDistance(const TileDistance& tileDistance, const float lastSegmentAngle, const float pixelsToTileUnits, const float cameraToAnchorDistance, const bool pitchWithMap); diff --git a/src/mbgl/text/placement.cpp b/src/mbgl/text/placement.cpp index a050be4648..0747133bd2 100644 --- a/src/mbgl/text/placement.cpp +++ b/src/mbgl/text/placement.cpp @@ -110,6 +110,13 @@ void Placement::placeLayerBucket( auto partiallyEvaluatedTextSize = bucket.textSizeBinder->evaluateForZoom(state.getZoom()); auto partiallyEvaluatedIconSize = bucket.iconSizeBinder->evaluateForZoom(state.getZoom()); + optional<CollisionTileBoundaries> avoidEdges; + if (mapMode == MapMode::Tile && + (bucket.layout.get<style::SymbolAvoidEdges>() || + bucket.layout.get<style::SymbolPlacement>() == style::SymbolPlacementType::Line)) { + avoidEdges = collisionIndex.projectTileBoundaries(posMatrix); + } + for (auto& symbolInstance : bucket.symbolInstances) { if (seenCrossTileIDs.count(symbolInstance.crossTileID) == 0) { @@ -133,7 +140,7 @@ void Placement::placeLayerBucket( placedSymbol, scale, fontSize, bucket.layout.get<style::TextAllowOverlap>(), bucket.layout.get<style::TextPitchAlignment>() == style::AlignmentType::Map, - showCollisionBoxes); + showCollisionBoxes, avoidEdges); placeText = placed.first; offscreen &= placed.second; } @@ -147,7 +154,7 @@ void Placement::placeLayerBucket( placedSymbol, scale, fontSize, bucket.layout.get<style::IconAllowOverlap>(), bucket.layout.get<style::IconPitchAlignment>() == style::AlignmentType::Map, - showCollisionBoxes); + showCollisionBoxes, avoidEdges); placeIcon = placed.first; offscreen &= placed.second; } |