diff options
author | Chris Loer <chris.loer@gmail.com> | 2018-09-06 14:58:37 -0700 |
---|---|---|
committer | Chris Loer <chris.loer@mapbox.com> | 2018-09-12 14:10:46 -0700 |
commit | d735d89835fb3076e09594fce2a141fe1495e33f (patch) | |
tree | 36fb80484b3952fb730fd34a77439d303d002cdc /src/mbgl/text | |
parent | 079ba0209ed383c15123902f0810e658c2b0abf4 (diff) | |
download | qtlocation-mapboxgl-d735d89835fb3076e09594fce2a141fe1495e33f.tar.gz |
[core] Port "collision group" plumbing to gl-native.
[node] Hook up map-wide "crossSourceCollisions" option, defaulting to true.
[test] Pass "crossSourceCollisions" test option through test harness; enable cross-source-collisions tests on native.
Diffstat (limited to 'src/mbgl/text')
-rw-r--r-- | src/mbgl/text/collision_index.cpp | 34 | ||||
-rw-r--r-- | src/mbgl/text/collision_index.hpp | 8 | ||||
-rw-r--r-- | src/mbgl/text/placement.cpp | 39 | ||||
-rw-r--r-- | src/mbgl/text/placement.hpp | 24 |
4 files changed, 83 insertions, 22 deletions
diff --git a/src/mbgl/text/collision_index.cpp b/src/mbgl/text/collision_index.cpp index dae789a196..90acb2b441 100644 --- a/src/mbgl/text/collision_index.cpp +++ b/src/mbgl/text/collision_index.cpp @@ -89,7 +89,8 @@ std::pair<bool,bool> CollisionIndex::placeFeature(CollisionFeature& feature, const bool allowOverlap, const bool pitchWithMap, const bool collisionDebug, - const optional<CollisionTileBoundaries>& avoidEdges) { + const optional<CollisionTileBoundaries>& avoidEdges, + const optional<std::function<bool(const IndexedSubfeature&)>> collisionGroupPredicate) { if (!feature.alongLine) { CollisionBox& box = feature.boxes.front(); const auto projectedPoint = projectAndGetPerspectiveRatio(posMatrix, box.anchor); @@ -102,13 +103,13 @@ std::pair<bool,bool> CollisionIndex::placeFeature(CollisionFeature& feature, if ((avoidEdges && !isInsideTile(box, *avoidEdges)) || !isInsideGrid(box) || - (!allowOverlap && collisionGrid.hitTest({{ box.px1, box.py1 }, { box.px2, box.py2 }}))) { + (!allowOverlap && collisionGrid.hitTest({{ box.px1, box.py1 }, { box.px2, box.py2 }}, collisionGroupPredicate))) { return { false, false }; } return {true, isOffscreen(box)}; } else { - return placeLineFeature(feature, posMatrix, labelPlaneMatrix, textPixelRatio, symbol, scale, fontSize, allowOverlap, pitchWithMap, collisionDebug, avoidEdges); + return placeLineFeature(feature, posMatrix, labelPlaneMatrix, textPixelRatio, symbol, scale, fontSize, allowOverlap, pitchWithMap, collisionDebug, avoidEdges, collisionGroupPredicate); } } @@ -122,7 +123,8 @@ std::pair<bool,bool> CollisionIndex::placeLineFeature(CollisionFeature& feature, const bool allowOverlap, const bool pitchWithMap, const bool collisionDebug, - const optional<CollisionTileBoundaries>& avoidEdges) { + const optional<CollisionTileBoundaries>& avoidEdges, + const optional<std::function<bool(const IndexedSubfeature&)>> collisionGroupPredicate) { const auto tileUnitAnchorPoint = symbol.anchorPoint; const auto projectedAnchor = projectAnchor(posMatrix, tileUnitAnchorPoint); @@ -222,7 +224,7 @@ std::pair<bool,bool> CollisionIndex::placeLineFeature(CollisionFeature& feature, inGrid |= isInsideGrid(circle); if ((avoidEdges && !isInsideTile(circle, *avoidEdges)) || - (!allowOverlap && collisionGrid.hitTest({{circle.px, circle.py}, circle.radius}))) { + (!allowOverlap && collisionGrid.hitTest({{circle.px, circle.py}, circle.radius}, collisionGroupPredicate))) { if (!collisionDebug) { return {false, false}; } else { @@ -237,7 +239,7 @@ std::pair<bool,bool> CollisionIndex::placeLineFeature(CollisionFeature& feature, } -void CollisionIndex::insertFeature(CollisionFeature& feature, bool ignorePlacement, uint32_t bucketInstanceId) { +void CollisionIndex::insertFeature(CollisionFeature& feature, bool ignorePlacement, uint32_t bucketInstanceId, uint16_t collisionGroupId) { if (feature.alongLine) { for (auto& circle : feature.boxes) { if (!circle.used) { @@ -245,18 +247,30 @@ void CollisionIndex::insertFeature(CollisionFeature& feature, bool ignorePlaceme } if (ignorePlacement) { - ignoredGrid.insert(IndexedSubfeature(feature.indexedFeature, bucketInstanceId), {{ circle.px, circle.py }, circle.radius}); + ignoredGrid.insert( + IndexedSubfeature(feature.indexedFeature, bucketInstanceId, collisionGroupId), + {{ circle.px, circle.py }, circle.radius} + ); } else { - collisionGrid.insert(IndexedSubfeature(feature.indexedFeature, bucketInstanceId), {{ circle.px, circle.py }, circle.radius}); + collisionGrid.insert( + IndexedSubfeature(feature.indexedFeature, bucketInstanceId, collisionGroupId), + {{ circle.px, circle.py }, circle.radius} + ); } } } else { assert(feature.boxes.size() == 1); auto& box = feature.boxes[0]; if (ignorePlacement) { - ignoredGrid.insert(IndexedSubfeature(feature.indexedFeature, bucketInstanceId), {{ box.px1, box.py1 }, { box.px2, box.py2 }}); + ignoredGrid.insert( + IndexedSubfeature(feature.indexedFeature, bucketInstanceId, collisionGroupId), + {{ box.px1, box.py1 }, { box.px2, box.py2 }} + ); } else { - collisionGrid.insert(IndexedSubfeature(feature.indexedFeature, bucketInstanceId), {{ box.px1, box.py1 }, { box.px2, box.py2 }}); + collisionGrid.insert( + IndexedSubfeature(feature.indexedFeature, bucketInstanceId, collisionGroupId), + {{ box.px1, box.py1 }, { box.px2, box.py2 }} + ); } } } diff --git a/src/mbgl/text/collision_index.hpp b/src/mbgl/text/collision_index.hpp index 78782fe61c..dac0aa0bf7 100644 --- a/src/mbgl/text/collision_index.hpp +++ b/src/mbgl/text/collision_index.hpp @@ -32,9 +32,10 @@ public: const bool allowOverlap, const bool pitchWithMap, const bool collisionDebug, - const optional<CollisionTileBoundaries>& avoidEdges); + const optional<CollisionTileBoundaries>& avoidEdges, + const optional<std::function<bool(const IndexedSubfeature&)>> collisionGroupPredicate); - void insertFeature(CollisionFeature& feature, bool ignorePlacement, uint32_t bucketInstanceId); + void insertFeature(CollisionFeature& feature, bool ignorePlacement, uint32_t bucketInstanceId, uint16_t collisionGroupId); std::unordered_map<uint32_t, std::vector<IndexedSubfeature>> queryRenderedSymbols(const ScreenLineString&) const; @@ -55,7 +56,8 @@ private: const bool allowOverlap, const bool pitchWithMap, const bool collisionDebug, - const optional<CollisionTileBoundaries>& avoidEdges); + const optional<CollisionTileBoundaries>& avoidEdges, + const optional<std::function<bool(const IndexedSubfeature&)>> collisionGroupPredicate); 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 48c58a962e..5c6cdcde6c 100644 --- a/src/mbgl/text/placement.cpp +++ b/src/mbgl/text/placement.cpp @@ -33,11 +33,33 @@ JointOpacityState::JointOpacityState(const JointOpacityState& prevOpacityState, bool JointOpacityState::isHidden() const { return icon.isHidden() && text.isHidden(); } + +const CollisionGroups::CollisionGroup& CollisionGroups::get(const std::string& sourceID) { + // The predicate/groupID mechanism allows for arbitrary grouping, + // but the current interface defines one source == one group when + // crossSourceCollisions == true. + if (!crossSourceCollisions) { + if (collisionGroups.find(sourceID) == collisionGroups.end()) { + uint16_t nextGroupID = ++maxGroupID; + collisionGroups.emplace(sourceID, CollisionGroup( + nextGroupID, + optional<Predicate>([nextGroupID](const IndexedSubfeature& feature) -> bool { + return feature.collisionGroupId == nextGroupID; + }) + )); + } + return collisionGroups[sourceID]; + } else { + static CollisionGroup nullGroup{0, nullopt}; + return nullGroup; + } +} -Placement::Placement(const TransformState& state_, MapMode mapMode_) +Placement::Placement(const TransformState& state_, MapMode mapMode_, const bool crossSourceCollisions) : collisionIndex(state_) , state(state_) , mapMode(mapMode_) + , collisionGroups(crossSourceCollisions) {} void Placement::placeLayer(RenderSymbolLayer& symbolLayer, const mat4& projMatrix, bool showCollisionBoxes) { @@ -92,7 +114,9 @@ void Placement::placeLayer(RenderSymbolLayer& symbolLayer, const mat4& projMatri std::forward_as_tuple(symbolBucket.bucketInstanceId), std::forward_as_tuple(symbolBucket.bucketInstanceId, geometryTile.getFeatureIndex(), geometryTile.id)); - placeLayerBucket(symbolBucket, posMatrix, textLabelPlaneMatrix, iconLabelPlaneMatrix, scale, textPixelRatio, showCollisionBoxes, seenCrossTileIDs, renderTile.tile.holdForFade()); + const auto collisionGroup = collisionGroups.get(geometryTile.sourceID); + + placeLayerBucket(symbolBucket, posMatrix, textLabelPlaneMatrix, iconLabelPlaneMatrix, scale, textPixelRatio, showCollisionBoxes, seenCrossTileIDs, renderTile.tile.holdForFade(), collisionGroup); } } @@ -105,7 +129,8 @@ void Placement::placeLayerBucket( const float textPixelRatio, const bool showCollisionBoxes, std::unordered_set<uint32_t>& seenCrossTileIDs, - const bool holdingForFade) { + const bool holdingForFade, + const CollisionGroups::CollisionGroup& collisionGroup) { auto partiallyEvaluatedTextSize = bucket.textSizeBinder->evaluateForZoom(state.getZoom()); auto partiallyEvaluatedIconSize = bucket.iconSizeBinder->evaluateForZoom(state.getZoom()); @@ -159,7 +184,7 @@ void Placement::placeLayerBucket( placedSymbol, scale, fontSize, bucket.layout.get<style::TextAllowOverlap>(), bucket.layout.get<style::TextPitchAlignment>() == style::AlignmentType::Map, - showCollisionBoxes, avoidEdges); + showCollisionBoxes, avoidEdges, collisionGroup.second); placeText = placed.first; offscreen &= placed.second; } @@ -173,7 +198,7 @@ void Placement::placeLayerBucket( placedSymbol, scale, fontSize, bucket.layout.get<style::IconAllowOverlap>(), bucket.layout.get<style::IconPitchAlignment>() == style::AlignmentType::Map, - showCollisionBoxes, avoidEdges); + showCollisionBoxes, avoidEdges, collisionGroup.second); placeIcon = placed.first; offscreen &= placed.second; } @@ -191,11 +216,11 @@ void Placement::placeLayerBucket( } if (placeText) { - collisionIndex.insertFeature(symbolInstance.textCollisionFeature, bucket.layout.get<style::TextIgnorePlacement>(), bucket.bucketInstanceId); + collisionIndex.insertFeature(symbolInstance.textCollisionFeature, bucket.layout.get<style::TextIgnorePlacement>(), bucket.bucketInstanceId, collisionGroup.first); } if (placeIcon) { - collisionIndex.insertFeature(symbolInstance.iconCollisionFeature, bucket.layout.get<style::IconIgnorePlacement>(), bucket.bucketInstanceId); + collisionIndex.insertFeature(symbolInstance.iconCollisionFeature, bucket.layout.get<style::IconIgnorePlacement>(), bucket.bucketInstanceId, collisionGroup.first); } assert(symbolInstance.crossTileID != 0); diff --git a/src/mbgl/text/placement.hpp b/src/mbgl/text/placement.hpp index 24de4c054a..8527d6df57 100644 --- a/src/mbgl/text/placement.hpp +++ b/src/mbgl/text/placement.hpp @@ -59,9 +59,27 @@ struct RetainedQueryData { , tileID(std::move(tileID_)) {} }; +class CollisionGroups { +public: + using Predicate = std::function<bool(const IndexedSubfeature&)>; + using CollisionGroup = std::pair<uint16_t, optional<Predicate>>; + + CollisionGroups(const bool crossSourceCollisions_) + : maxGroupID(0) + , crossSourceCollisions(crossSourceCollisions_) + {} + + const CollisionGroup& get(const std::string& sourceID); + +private: + std::map<std::string, CollisionGroup> collisionGroups; + uint16_t maxGroupID; + bool crossSourceCollisions; +}; + class Placement { public: - Placement(const TransformState&, MapMode mapMode); + Placement(const TransformState&, MapMode mapMode, const bool crossSourceCollisions); void placeLayer(RenderSymbolLayer&, const mat4&, bool showCollisionBoxes); void commit(const Placement& prevPlacement, TimePoint); void updateLayerOpacities(RenderSymbolLayer&); @@ -86,7 +104,8 @@ private: const float pixelRatio, const bool showCollisionBoxes, std::unordered_set<uint32_t>& seenCrossTileIDs, - const bool holdingForFade); + const bool holdingForFade, + const CollisionGroups::CollisionGroup& collisionGroup); void updateBucketOpacities(SymbolBucket&, std::set<uint32_t>&); @@ -103,6 +122,7 @@ private: bool stale = false; std::unordered_map<uint32_t, RetainedQueryData> retainedQueryData; + CollisionGroups collisionGroups; }; } // namespace mbgl |