summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mbgl/renderer/buckets/symbol_bucket.cpp4
-rw-r--r--src/mbgl/renderer/buckets/symbol_bucket.hpp8
-rw-r--r--src/mbgl/text/collision_feature.hpp3
-rw-r--r--src/mbgl/text/collision_index.cpp57
-rw-r--r--src/mbgl/text/collision_index.hpp16
-rw-r--r--src/mbgl/text/placement.cpp60
-rw-r--r--src/mbgl/text/placement.hpp7
7 files changed, 91 insertions, 64 deletions
diff --git a/src/mbgl/renderer/buckets/symbol_bucket.cpp b/src/mbgl/renderer/buckets/symbol_bucket.cpp
index 83efb232c2..2a9f5df9c0 100644
--- a/src/mbgl/renderer/buckets/symbol_bucket.cpp
+++ b/src/mbgl/renderer/buckets/symbol_bucket.cpp
@@ -227,8 +227,8 @@ void SymbolBucket::sortFeatures(const float angle) {
}
}
-std::vector<std::reference_wrapper<SymbolInstance>> SymbolBucket::getSortedSymbols(const float angle) {
- std::vector<std::reference_wrapper<SymbolInstance>> result(symbolInstances.begin(), symbolInstances.end());
+std::vector<std::reference_wrapper<const SymbolInstance>> SymbolBucket::getSortedSymbols(const float angle) const {
+ std::vector<std::reference_wrapper<const SymbolInstance>> result(symbolInstances.begin(), symbolInstances.end());
const float sin = std::sin(angle);
const float cos = std::cos(angle);
diff --git a/src/mbgl/renderer/buckets/symbol_bucket.hpp b/src/mbgl/renderer/buckets/symbol_bucket.hpp
index c22a168a0c..a94073f7d0 100644
--- a/src/mbgl/renderer/buckets/symbol_bucket.hpp
+++ b/src/mbgl/renderer/buckets/symbol_bucket.hpp
@@ -70,7 +70,7 @@ public:
void sortFeatures(const float angle);
// The result contains references to the `symbolInstances` items, sorted by viewport Y.
- std::vector<std::reference_wrapper<SymbolInstance>> getSortedSymbols(const float angle);
+ std::vector<std::reference_wrapper<const SymbolInstance>> getSortedSymbols(const float angle) const;
Immutable<style::SymbolLayoutProperties::PossiblyEvaluated> layout;
const std::string bucketLeaderID;
@@ -84,7 +84,8 @@ public:
bool placementChangesUploaded : 1;
bool dynamicUploaded : 1;
bool sortUploaded : 1;
- bool justReloaded : 1;
+ // Set and used by placement.
+ mutable bool justReloaded : 1;
bool hasVariablePlacement : 1;
std::vector<SymbolInstance> symbolInstances;
@@ -113,8 +114,7 @@ public:
std::unique_ptr<SymbolSizeBinder> iconSizeBinder;
- struct IconBuffer : public Buffer {
- } icon;
+ Buffer icon;
struct CollisionBuffer {
gfx::VertexVector<gfx::Vertex<CollisionBoxLayoutAttributes>> vertices;
diff --git a/src/mbgl/text/collision_feature.hpp b/src/mbgl/text/collision_feature.hpp
index 106fe8402a..4afecd8e73 100644
--- a/src/mbgl/text/collision_feature.hpp
+++ b/src/mbgl/text/collision_feature.hpp
@@ -64,9 +64,6 @@ public:
float y2;
float signedDistanceFromAnchor;
-
- // generated/updated at placement time
- ProjectedCollisionBox projected;
};
class CollisionFeature {
diff --git a/src/mbgl/text/collision_index.cpp b/src/mbgl/text/collision_index.cpp
index 4329b314ea..c83b117b9a 100644
--- a/src/mbgl/text/collision_index.cpp
+++ b/src/mbgl/text/collision_index.cpp
@@ -79,54 +79,58 @@ bool CollisionIndex::isInsideTile(float x1, float y1, float x2, float y2, const
}
-std::pair<bool,bool> CollisionIndex::placeFeature(CollisionFeature& feature,
+std::pair<bool,bool> CollisionIndex::placeFeature(const CollisionFeature& feature,
Point<float> shift,
const mat4& posMatrix,
const mat4& labelPlaneMatrix,
const float textPixelRatio,
- PlacedSymbol& symbol,
+ const PlacedSymbol& symbol,
const float scale,
const float fontSize,
const bool allowOverlap,
const bool pitchWithMap,
const bool collisionDebug,
const optional<CollisionTileBoundaries>& avoidEdges,
- const optional<std::function<bool(const IndexedSubfeature&)>> collisionGroupPredicate) {
+ const optional<std::function<bool(const IndexedSubfeature&)>> collisionGroupPredicate,
+ std::vector<ProjectedCollisionBox>& projectedBoxes) {
+ assert(projectedBoxes.empty());
if (!feature.alongLine) {
- CollisionBox& box = feature.boxes.front();
+ const CollisionBox& box = feature.boxes.front();
const auto projectedPoint = projectAndGetPerspectiveRatio(posMatrix, box.anchor);
const float tileToViewport = textPixelRatio * projectedPoint.second;
float px1 = (box.x1 + shift.x) * tileToViewport + projectedPoint.first.x;
float py1 = (box.y1 + shift.y) * tileToViewport + projectedPoint.first.y;
float px2 = (box.x2 + shift.x) * tileToViewport + projectedPoint.first.x;
float py2 = (box.y2 + shift.y) * tileToViewport + projectedPoint.first.y;
- box.projected = ProjectedCollisionBox{ px1, py1, px2, py2 };
+ projectedBoxes.emplace_back(px1, py1, px2, py2);
if ((avoidEdges && !isInsideTile(px1, py1, px2, py2, *avoidEdges)) ||
!isInsideGrid(px1, py1, px2, py2) ||
- (!allowOverlap && collisionGrid.hitTest(box.projected.box(), collisionGroupPredicate))) {
+ (!allowOverlap && collisionGrid.hitTest(projectedBoxes.back().box(), collisionGroupPredicate))) {
return { false, false };
}
return {true, isOffscreen(px1, py1, px2, py2)};
} else {
- return placeLineFeature(feature, posMatrix, labelPlaneMatrix, textPixelRatio, symbol, scale, fontSize, allowOverlap, pitchWithMap, collisionDebug, avoidEdges, collisionGroupPredicate);
+ return placeLineFeature(feature, posMatrix, labelPlaneMatrix, textPixelRatio, symbol, scale, fontSize, allowOverlap, pitchWithMap, collisionDebug, avoidEdges, collisionGroupPredicate, projectedBoxes);
}
}
-std::pair<bool,bool> CollisionIndex::placeLineFeature(CollisionFeature& feature,
+std::pair<bool,bool> CollisionIndex::placeLineFeature(const CollisionFeature& feature,
const mat4& posMatrix,
const mat4& labelPlaneMatrix,
const float textPixelRatio,
- PlacedSymbol& symbol,
+ const PlacedSymbol& symbol,
const float scale,
const float fontSize,
const bool allowOverlap,
const bool pitchWithMap,
const bool collisionDebug,
const optional<CollisionTileBoundaries>& avoidEdges,
- const optional<std::function<bool(const IndexedSubfeature&)>> collisionGroupPredicate) {
+ const optional<std::function<bool(const IndexedSubfeature&)>> collisionGroupPredicate,
+ std::vector<ProjectedCollisionBox>& projectedBoxes) {
assert(feature.alongLine);
+ assert(projectedBoxes.empty());
const auto tileUnitAnchorPoint = symbol.anchorPoint;
const auto projectedAnchor = projectAnchor(posMatrix, tileUnitAnchorPoint);
@@ -164,8 +168,9 @@ std::pair<bool,bool> CollisionIndex::placeLineFeature(CollisionFeature& feature,
}
bool previousCirclePlaced = false;
+ projectedBoxes.resize(feature.boxes.size());
for (size_t i = 0; i < feature.boxes.size(); i++) {
- CollisionBox& circle = feature.boxes[i];
+ const CollisionBox& circle = feature.boxes[i];
const float boxSignedDistanceFromAnchor = circle.signedDistanceFromAnchor;
if (!firstAndLastGlyph ||
(boxSignedDistanceFromAnchor < -firstTileDistance) ||
@@ -182,9 +187,9 @@ std::pair<bool,bool> CollisionIndex::placeLineFeature(CollisionFeature& feature,
const float radius = tileUnitRadius * tileToViewport;
if (previousCirclePlaced) {
- const CollisionBox& previousCircle = feature.boxes[i - 1];
- assert(previousCircle.projected.isCircle());
- const auto& previousCenter = previousCircle.projected.circle().center;
+ const ProjectedCollisionBox& previousCircle = projectedBoxes[i - 1];
+ assert(previousCircle.isCircle());
+ const auto& previousCenter = previousCircle.circle().center;
const float dx = projectedPoint.x - previousCenter.x;
const float dy = projectedPoint.y - previousCenter.y;
// The circle edges touch when the distance between their centers is 2x the radius
@@ -217,13 +222,13 @@ std::pair<bool,bool> CollisionIndex::placeLineFeature(CollisionFeature& feature,
float py1 = projectedPoint.y - radius;
float py2 = projectedPoint.y + radius;
- circle.projected = ProjectedCollisionBox{projectedPoint.x, projectedPoint.y, radius};
+ projectedBoxes[i] = ProjectedCollisionBox{projectedPoint.x, projectedPoint.y, radius};
entirelyOffscreen &= isOffscreen(px1, py1, px2, py2);
inGrid |= isInsideGrid(px1, py1, px2, py2);
if ((avoidEdges && !isInsideTile(px1, py1, px2, py2, *avoidEdges)) ||
- (!allowOverlap && collisionGrid.hitTest(circle.projected.circle(), collisionGroupPredicate))) {
+ (!allowOverlap && collisionGrid.hitTest(projectedBoxes[i].circle(), collisionGroupPredicate))) {
if (!collisionDebug) {
return {false, false};
} else {
@@ -238,38 +243,38 @@ std::pair<bool,bool> CollisionIndex::placeLineFeature(CollisionFeature& feature,
}
-void CollisionIndex::insertFeature(CollisionFeature& feature, bool ignorePlacement, uint32_t bucketInstanceId, uint16_t collisionGroupId) {
+void CollisionIndex::insertFeature(const CollisionFeature& feature, const std::vector<ProjectedCollisionBox>& projectedBoxes, bool ignorePlacement, uint32_t bucketInstanceId, uint16_t collisionGroupId) {
if (feature.alongLine) {
- for (auto& circle : feature.boxes) {
- if (!circle.projected.isCircle()) {
+ for (auto& circle : projectedBoxes) {
+ if (!circle.isCircle()) {
continue;
}
if (ignorePlacement) {
ignoredGrid.insert(
IndexedSubfeature(feature.indexedFeature, bucketInstanceId, collisionGroupId),
- circle.projected.circle()
+ circle.circle()
);
} else {
collisionGrid.insert(
IndexedSubfeature(feature.indexedFeature, bucketInstanceId, collisionGroupId),
- circle.projected.circle()
+ circle.circle()
);
}
}
} else {
- assert(feature.boxes.size() == 1);
- auto& box = feature.boxes[0];
- assert(box.projected.isBox());
+ assert(projectedBoxes.size() == 1);
+ auto& box = projectedBoxes[0];
+ assert(box.isBox());
if (ignorePlacement) {
ignoredGrid.insert(
IndexedSubfeature(feature.indexedFeature, bucketInstanceId, collisionGroupId),
- box.projected.box()
+ box.box()
);
} else {
collisionGrid.insert(
IndexedSubfeature(feature.indexedFeature, bucketInstanceId, collisionGroupId),
- box.projected.box()
+ box.box()
);
}
}
diff --git a/src/mbgl/text/collision_index.hpp b/src/mbgl/text/collision_index.hpp
index a1b277d06d..4e8a2fdb62 100644
--- a/src/mbgl/text/collision_index.hpp
+++ b/src/mbgl/text/collision_index.hpp
@@ -22,21 +22,22 @@ public:
explicit CollisionIndex(const TransformState&);
- std::pair<bool,bool> placeFeature(CollisionFeature& feature,
+ std::pair<bool,bool> placeFeature(const CollisionFeature& feature,
Point<float> shift,
const mat4& posMatrix,
const mat4& labelPlaneMatrix,
const float textPixelRatio,
- PlacedSymbol& symbol,
+ const PlacedSymbol& symbol,
const float scale,
const float fontSize,
const bool allowOverlap,
const bool pitchWithMap,
const bool collisionDebug,
const optional<CollisionTileBoundaries>& avoidEdges,
- const optional<std::function<bool(const IndexedSubfeature&)>> collisionGroupPredicate);
+ const optional<std::function<bool(const IndexedSubfeature&)>> collisionGroupPredicate,
+ std::vector<ProjectedCollisionBox>& /*out*/);
- void insertFeature(CollisionFeature& feature, bool ignorePlacement, uint32_t bucketInstanceId, uint16_t collisionGroupId);
+ void insertFeature(const CollisionFeature& feature, const std::vector<ProjectedCollisionBox>&, bool ignorePlacement, uint32_t bucketInstanceId, uint16_t collisionGroupId);
std::unordered_map<uint32_t, std::vector<IndexedSubfeature>> queryRenderedSymbols(const ScreenLineString&) const;
@@ -49,18 +50,19 @@ private:
bool isInsideGrid(float x1, float y1, float x2, float y2) const;
bool isInsideTile(float x1, float y1, float x2, float y2, const CollisionTileBoundaries& tileBoundaries) const;
- std::pair<bool,bool> placeLineFeature(CollisionFeature& feature,
+ std::pair<bool,bool> placeLineFeature(const CollisionFeature& feature,
const mat4& posMatrix,
const mat4& labelPlaneMatrix,
const float textPixelRatio,
- PlacedSymbol& symbol,
+ const PlacedSymbol& symbol,
const float scale,
const float fontSize,
const bool allowOverlap,
const bool pitchWithMap,
const bool collisionDebug,
const optional<CollisionTileBoundaries>& avoidEdges,
- const optional<std::function<bool(const IndexedSubfeature&)>> collisionGroupPredicate);
+ const optional<std::function<bool(const IndexedSubfeature&)>> collisionGroupPredicate,
+ std::vector<ProjectedCollisionBox>& /*out*/);
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 4ad911212d..f7d13dcb26 100644
--- a/src/mbgl/text/placement.cpp
+++ b/src/mbgl/text/placement.cpp
@@ -98,7 +98,7 @@ Point<float> calculateVariableLayoutOffset(style::SymbolAnchorType anchor, float
} // namespace
void Placement::placeBucket(
- SymbolBucket& bucket,
+ const SymbolBucket& bucket,
const BucketPlacementParameters& params,
std::set<uint32_t>& seenCrossTileIDs) {
const auto& layout = *bucket.layout;
@@ -157,10 +157,13 @@ void Placement::placeBucket(
std::vector<style::TextVariableAnchorType> variableTextAnchors = layout.get<style::TextVariableAnchor>();
const bool rotateWithMap = layout.get<style::TextRotationAlignment>() == style::AlignmentType::Map;
const bool pitchWithMap = layout.get<style::TextPitchAlignment>() == style::AlignmentType::Map;
+ const bool hasCollisionCircleData = bucket.hasCollisionCircleData();
const bool zOrderByViewportY = layout.get<style::SymbolZOrder>() == style::SymbolZOrderType::ViewportY;
+ std::vector<ProjectedCollisionBox> textBoxes;
+ std::vector<ProjectedCollisionBox> iconBoxes;
- auto placeSymbol = [&] (SymbolInstance& symbolInstance) {
+ auto placeSymbol = [&] (const SymbolInstance& symbolInstance) {
if (seenCrossTileIDs.count(symbolInstance.crossTileID) != 0u) return;
if (renderTile.holdForFade()) {
@@ -169,14 +172,16 @@ void Placement::placeBucket(
placements.emplace(symbolInstance.crossTileID, JointPlacement(false, false, false));
return;
}
+ textBoxes.clear();
+ iconBoxes.clear();
bool placeText = false;
bool placeIcon = false;
bool offscreen = true;
optional<size_t> horizontalTextIndex = symbolInstance.getDefaultHorizontalPlacedTextIndex();
if (horizontalTextIndex) {
- CollisionFeature& textCollisionFeature = symbolInstance.textCollisionFeature;
- PlacedSymbol& placedSymbol = bucket.text.placedSymbols.at(*horizontalTextIndex);
+ const CollisionFeature& textCollisionFeature = symbolInstance.textCollisionFeature;
+ const PlacedSymbol& placedSymbol = bucket.text.placedSymbols.at(*horizontalTextIndex);
const float fontSize = evaluateSizeForFeature(partiallyEvaluatedTextSize, placedSymbol);
if (variableTextAnchors.empty()) {
auto placed = collisionIndex.placeFeature(textCollisionFeature, {},
@@ -184,7 +189,7 @@ void Placement::placeBucket(
placedSymbol, scale, fontSize,
layout.get<style::TextAllowOverlap>(),
pitchWithMap,
- params.showCollisionBoxes, avoidEdges, collisionGroup.second);
+ params.showCollisionBoxes, avoidEdges, collisionGroup.second, textBoxes);
placeText = placed.first;
offscreen &= placed.second;
} else if (!textCollisionFeature.alongLine && !textCollisionFeature.boxes.empty()) {
@@ -227,7 +232,7 @@ void Placement::placeBucket(
placedSymbol, scale, fontSize,
layout.get<style::TextAllowOverlap>(),
pitchWithMap,
- params.showCollisionBoxes, avoidEdges, collisionGroup.second);
+ params.showCollisionBoxes, avoidEdges, collisionGroup.second, textBoxes);
if (placed.first) {
assert(symbolInstance.crossTileID != 0u);
@@ -253,12 +258,12 @@ void Placement::placeBucket(
textBoxScale,
prevAnchor
}));
- markUsedJustification(bucket, anchor, symbolInstance);
placeText = placed.first;
offscreen &= placed.second;
break;
}
+ textBoxes.clear();
}
// If we didn't get placed, we still need to copy our position from the last placement for
@@ -267,14 +272,13 @@ void Placement::placeBucket(
auto prevOffset = prevPlacement->variableOffsets.find(symbolInstance.crossTileID);
if (prevOffset != prevPlacement->variableOffsets.end()) {
variableOffsets[symbolInstance.crossTileID] = prevOffset->second;
- markUsedJustification(bucket, prevOffset->second.anchor, symbolInstance);
}
}
}
}
if (symbolInstance.placedIconIndex) {
- PlacedSymbol& placedSymbol = bucket.icon.placedSymbols.at(*symbolInstance.placedIconIndex);
+ const PlacedSymbol& placedSymbol = bucket.icon.placedSymbols.at(*symbolInstance.placedIconIndex);
const float fontSize = evaluateSizeForFeature(partiallyEvaluatedIconSize, placedSymbol);
auto placed = collisionIndex.placeFeature(symbolInstance.iconCollisionFeature, {},
@@ -282,7 +286,7 @@ void Placement::placeBucket(
placedSymbol, scale, fontSize,
layout.get<style::IconAllowOverlap>(),
pitchWithMap,
- params.showCollisionBoxes, avoidEdges, collisionGroup.second);
+ params.showCollisionBoxes, avoidEdges, collisionGroup.second, iconBoxes);
placeIcon = placed.first;
offscreen &= placed.second;
}
@@ -300,11 +304,20 @@ void Placement::placeBucket(
}
if (placeText) {
- collisionIndex.insertFeature(symbolInstance.textCollisionFeature, layout.get<style::TextIgnorePlacement>(), bucket.bucketInstanceId, collisionGroup.first);
+ collisionIndex.insertFeature(symbolInstance.textCollisionFeature, textBoxes, layout.get<style::TextIgnorePlacement>(), bucket.bucketInstanceId, collisionGroup.first);
}
if (placeIcon) {
- collisionIndex.insertFeature(symbolInstance.iconCollisionFeature, layout.get<style::IconIgnorePlacement>(), bucket.bucketInstanceId, collisionGroup.first);
+ collisionIndex.insertFeature(symbolInstance.iconCollisionFeature, iconBoxes, layout.get<style::IconIgnorePlacement>(), bucket.bucketInstanceId, collisionGroup.first);
+ }
+
+ if (hasCollisionCircleData) {
+ if (symbolInstance.iconCollisionFeature.alongLine && !iconBoxes.empty()) {
+ collisionCircles[&symbolInstance.iconCollisionFeature] = iconBoxes;
+ }
+ if (symbolInstance.textCollisionFeature.alongLine && !textBoxes.empty()) {
+ collisionCircles[&symbolInstance.textCollisionFeature] = textBoxes;
+ }
}
assert(symbolInstance.crossTileID != 0);
@@ -326,7 +339,7 @@ void Placement::placeBucket(
placeSymbol(*it);
}
} else {
- for (SymbolInstance& symbol : bucket.symbolInstances) {
+ for (const SymbolInstance& symbol : bucket.symbolInstances) {
placeSymbol(symbol);
}
}
@@ -407,7 +420,7 @@ Point<float> calculateVariableRenderShift(style::SymbolAnchorType anchor, float
}
} // namespace
-bool Placement::updateBucketDynamicVertices(SymbolBucket& bucket, const TransformState& state, const RenderTile& tile) {
+bool Placement::updateBucketDynamicVertices(SymbolBucket& bucket, const TransformState& state, const RenderTile& tile) const {
using namespace style;
const auto& layout = *bucket.layout;
const bool alongLine = layout.get<SymbolPlacement>() != SymbolPlacementType::Point;
@@ -569,9 +582,9 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, const TransformState
bucket.text.opacityVertices.extend(textOpacityVerticesSize, opacityVertex);
- auto prevOffset = variableOffsets.find(symbolInstance.crossTileID);
- if (prevOffset != variableOffsets.end()) {
- markUsedJustification(bucket, prevOffset->second.anchor, symbolInstance);
+ auto offset = variableOffsets.find(symbolInstance.crossTileID);
+ if (offset != variableOffsets.end()) {
+ markUsedJustification(bucket, offset->second.anchor, symbolInstance);
}
}
if (symbolInstance.hasIcon) {
@@ -627,9 +640,16 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, const TransformState
if (!feature.alongLine) {
return;
}
- for (const CollisionBox& box : feature.boxes) {
- const auto& dynamicVertex = CollisionBoxProgram::dynamicVertex(placed, !box.projected.isCircle(), {});
- bucket.collisionCircle->dynamicVertices.extend(4, dynamicVertex);
+ auto circles = collisionCircles.find(&feature);
+ if (circles != collisionCircles.end()) {
+ for (const auto& circle : circles->second) {
+ const auto& dynamicVertex = CollisionBoxProgram::dynamicVertex(placed, !circle.isCircle(), {});
+ bucket.collisionCircle->dynamicVertices.extend(4, dynamicVertex);
+ }
+ } else {
+ // This feature was not placed, because it was not loaded or from a fading tile. Apply default values.
+ static const auto dynamicVertex = CollisionBoxProgram::dynamicVertex(placed, false /*not used*/, {});
+ bucket.collisionCircle->dynamicVertices.extend(4 * feature.boxes.size(), dynamicVertex);
}
};
diff --git a/src/mbgl/text/placement.hpp b/src/mbgl/text/placement.hpp
index 0f56b0007e..2a6a2e1d6e 100644
--- a/src/mbgl/text/placement.hpp
+++ b/src/mbgl/text/placement.hpp
@@ -116,11 +116,11 @@ public:
private:
friend SymbolBucket;
void placeBucket(
- SymbolBucket&,
+ const SymbolBucket&,
const BucketPlacementParameters&,
std::set<uint32_t>& seenCrossTileIDs);
// Returns `true` if bucket vertices were updated; returns `false` otherwise.
- bool updateBucketDynamicVertices(SymbolBucket&, const TransformState&, const RenderTile& tile);
+ bool updateBucketDynamicVertices(SymbolBucket&, const TransformState&, const RenderTile& tile) const;
void updateBucketOpacities(SymbolBucket&, const TransformState&, std::set<uint32_t>&);
void markUsedJustification(SymbolBucket&, style::TextVariableAnchorType, SymbolInstance&);
@@ -141,6 +141,9 @@ private:
std::unordered_map<uint32_t, RetainedQueryData> retainedQueryData;
CollisionGroups collisionGroups;
std::unique_ptr<Placement> prevPlacement;
+
+ // Used for debug purposes.
+ std::unordered_map<const CollisionFeature*, std::vector<ProjectedCollisionBox>> collisionCircles;
};
} // namespace mbgl