summaryrefslogtreecommitdiff
path: root/src/mbgl/text
diff options
context:
space:
mode:
Diffstat (limited to 'src/mbgl/text')
-rw-r--r--src/mbgl/text/collision_index.cpp34
-rw-r--r--src/mbgl/text/collision_index.hpp8
-rw-r--r--src/mbgl/text/placement.cpp39
-rw-r--r--src/mbgl/text/placement.hpp24
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