diff options
-rw-r--r-- | src/mbgl/renderer/buckets/symbol_bucket.cpp | 4 | ||||
-rw-r--r-- | src/mbgl/renderer/buckets/symbol_bucket.hpp | 8 | ||||
-rw-r--r-- | src/mbgl/text/collision_feature.hpp | 3 | ||||
-rw-r--r-- | src/mbgl/text/collision_index.cpp | 57 | ||||
-rw-r--r-- | src/mbgl/text/collision_index.hpp | 16 | ||||
-rw-r--r-- | src/mbgl/text/placement.cpp | 60 | ||||
-rw-r--r-- | src/mbgl/text/placement.hpp | 7 |
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 |