diff options
Diffstat (limited to 'src/mbgl/text')
-rw-r--r-- | src/mbgl/text/collision_index.cpp | 6 | ||||
-rw-r--r-- | src/mbgl/text/collision_index.hpp | 6 | ||||
-rw-r--r-- | src/mbgl/text/cross_tile_symbol_index.cpp | 48 | ||||
-rw-r--r-- | src/mbgl/text/cross_tile_symbol_index.hpp | 6 | ||||
-rw-r--r-- | src/mbgl/text/placement.cpp | 163 | ||||
-rw-r--r-- | src/mbgl/text/placement.hpp | 41 | ||||
-rw-r--r-- | src/mbgl/text/placement_worker.cpp | 128 | ||||
-rw-r--r-- | src/mbgl/text/placement_worker.hpp | 53 |
8 files changed, 299 insertions, 152 deletions
diff --git a/src/mbgl/text/collision_index.cpp b/src/mbgl/text/collision_index.cpp index 05a0450465..08910fa619 100644 --- a/src/mbgl/text/collision_index.cpp +++ b/src/mbgl/text/collision_index.cpp @@ -56,7 +56,7 @@ bool CollisionIndex::placeFeature(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, @@ -87,7 +87,7 @@ bool CollisionIndex::placeLineFeature(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, @@ -201,7 +201,7 @@ bool CollisionIndex::placeLineFeature(CollisionFeature& feature, } -void CollisionIndex::insertFeature(CollisionFeature& feature, bool ignorePlacement) { +void CollisionIndex::insertFeature(const CollisionFeature& feature, bool ignorePlacement) { if (feature.alongLine) { for (auto& circle : feature.boxes) { if (!circle.used) { diff --git a/src/mbgl/text/collision_index.hpp b/src/mbgl/text/collision_index.hpp index 6f78d8aeda..7eab7b5c28 100644 --- a/src/mbgl/text/collision_index.hpp +++ b/src/mbgl/text/collision_index.hpp @@ -21,14 +21,14 @@ public: 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); - void insertFeature(CollisionFeature& feature, bool ignorePlacement); + void insertFeature(const CollisionFeature& feature, bool ignorePlacement); std::vector<IndexedSubfeature> queryRenderedSymbols(const GeometryCoordinates&, const UnwrappedTileID& tileID, const std::string& sourceID) const; @@ -38,7 +38,7 @@ private: const mat4& posMatrix, const mat4& labelPlaneMatrix, const float textPixelRatio, - PlacedSymbol& symbol, + const PlacedSymbol& symbol, const float scale, const float fontSize, const bool allowOverlap, diff --git a/src/mbgl/text/cross_tile_symbol_index.cpp b/src/mbgl/text/cross_tile_symbol_index.cpp index 779bec283c..f701b47694 100644 --- a/src/mbgl/text/cross_tile_symbol_index.cpp +++ b/src/mbgl/text/cross_tile_symbol_index.cpp @@ -7,14 +7,18 @@ namespace mbgl { -TileLayerIndex::TileLayerIndex(OverscaledTileID coord_, std::vector<SymbolInstance>& symbolInstances, uint32_t bucketInstanceId_) +TileLayerIndex::TileLayerIndex(OverscaledTileID coord_, const std::vector<SymbolInstance>& symbolInstances, std::vector<uint32_t>& symbolCrossTileIDs, uint32_t bucketInstanceId_) : coord(coord_), bucketInstanceId(bucketInstanceId_) { - for (SymbolInstance& symbolInstance : symbolInstances) { - indexedSymbolInstances[symbolInstance.key].emplace_back(symbolInstance.crossTileID, getScaledCoordinates(symbolInstance, coord)); + assert(symbolInstances.size() == symbolCrossTileIDs.size()); + auto idIt = symbolCrossTileIDs.begin(); + for (auto it = symbolInstances.begin(); it != symbolInstances.end(); it++, idIt++) { + auto& symbolInstance = *it; + auto crossTileID = *idIt; + indexedSymbolInstances[symbolInstance.key].emplace_back(crossTileID, getScaledCoordinates(symbolInstance, coord)); } } -Point<int64_t> TileLayerIndex::getScaledCoordinates(SymbolInstance& symbolInstance, const OverscaledTileID& childTileCoord) { +Point<int64_t> TileLayerIndex::getScaledCoordinates(const SymbolInstance& symbolInstance, const OverscaledTileID& childTileCoord) const { // Round anchor positions to roughly 4 pixel grid const double roundingFactor = 512.0 / util::EXTENT / 2.0; const double scale = roundingFactor / std::pow(2, childTileCoord.canonical.z - coord.canonical.z); @@ -24,30 +28,34 @@ Point<int64_t> TileLayerIndex::getScaledCoordinates(SymbolInstance& symbolInstan }; } -void TileLayerIndex::findMatches(std::vector<SymbolInstance>& symbolInstances, const OverscaledTileID& newCoord) { +void TileLayerIndex::findMatches(const std::vector<SymbolInstance>& symbolInstances, std::vector<uint32_t>& symbolCrossTileIDs, const OverscaledTileID& newCoord) { float tolerance = coord.canonical.z < newCoord.canonical.z ? 1 : std::pow(2, coord.canonical.z - newCoord.canonical.z); - for (auto& symbolInstance : symbolInstances) { - if (symbolInstance.crossTileID) { + assert(symbolInstances.size() == symbolCrossTileIDs.size()); + auto idIt = symbolCrossTileIDs.begin(); + for (auto it = symbolInstances.begin(); it != symbolInstances.end(); it++, idIt++) { + auto& symbolInstance = *it; + auto& crossTileID = *idIt; + if (crossTileID) { // already has a match, skip continue; } - auto it = indexedSymbolInstances.find(symbolInstance.key); - if (it == indexedSymbolInstances.end()) { + auto indexedSymbolInstance = indexedSymbolInstances.find(symbolInstance.key); + if (indexedSymbolInstance == indexedSymbolInstances.end()) { // No symbol with this key in this bucket continue; } auto scaledSymbolCoord = getScaledCoordinates(symbolInstance, newCoord); - for (IndexedSymbolInstance& thisTileSymbol: it->second) { + for (IndexedSymbolInstance& thisTileSymbol: indexedSymbolInstance->second) { // Return any symbol with the same keys whose coordinates are within 1 // grid unit. (with a 4px grid, this covers a 12px by 12px area) if (std::abs(thisTileSymbol.coord.x - scaledSymbolCoord.x) <= tolerance && std::abs(thisTileSymbol.coord.y - scaledSymbolCoord.y) <= tolerance) { - symbolInstance.crossTileID = thisTileSymbol.crossTileID; + crossTileID = thisTileSymbol.crossTileID; break; } } @@ -63,6 +71,10 @@ void CrossTileSymbolLayerIndex::addBucket(const OverscaledTileID& coord, SymbolB if (bucket.bucketInstanceId) return; bucket.bucketInstanceId = ++maxBucketInstanceId; + auto& symbolInstances = (*bucket.core)->symbolInstances; + + Mutable<std::vector<uint32_t>> symbolCrossTileIDs = makeMutable<std::vector<uint32_t>>(symbolInstances.size(), 0); + uint8_t minZoom = 25; uint8_t maxZoom = 0; for (auto& it : indexes) { @@ -80,7 +92,7 @@ void CrossTileSymbolLayerIndex::addBucket(const OverscaledTileID& coord, SymbolB if (!childIndex.second.coord.isChildOf(coord)) { continue; } - childIndex.second.findMatches(bucket.symbolInstances, coord); + childIndex.second.findMatches(symbolInstances, *symbolCrossTileIDs, coord); } } if (z == 0) { @@ -95,7 +107,7 @@ void CrossTileSymbolLayerIndex::addBucket(const OverscaledTileID& coord, SymbolB if (zoomIndexes != indexes.end()) { auto parentIndex = zoomIndexes->second.find(parentCoord); if (parentIndex != zoomIndexes->second.end()) { - parentIndex->second.findMatches(bucket.symbolInstances, coord); + parentIndex->second.findMatches(symbolInstances, *symbolCrossTileIDs, coord); } } if (z == 0) { @@ -103,14 +115,16 @@ void CrossTileSymbolLayerIndex::addBucket(const OverscaledTileID& coord, SymbolB } } - for (auto& symbolInstance : bucket.symbolInstances) { - if (!symbolInstance.crossTileID) { + for (auto& crossTileID : *symbolCrossTileIDs) { + if (!crossTileID) { // symbol did not match any known symbol, assign a new id - symbolInstance.crossTileID = ++maxCrossTileID; + crossTileID = ++maxCrossTileID; } } - indexes[coord.overscaledZ].emplace(coord, TileLayerIndex(coord, bucket.symbolInstances, bucket.bucketInstanceId)); + indexes[coord.overscaledZ].emplace(coord, TileLayerIndex(coord, symbolInstances, *symbolCrossTileIDs, bucket.bucketInstanceId)); + + bucket.symbolCrossTileIDs = std::make_unique<Immutable<std::vector<uint32_t>>>(std::move(symbolCrossTileIDs)); } bool CrossTileSymbolLayerIndex::removeStaleBuckets(const std::unordered_set<uint32_t>& currentIDs) { diff --git a/src/mbgl/text/cross_tile_symbol_index.hpp b/src/mbgl/text/cross_tile_symbol_index.hpp index 0b8c5c4780..ec0a5677de 100644 --- a/src/mbgl/text/cross_tile_symbol_index.hpp +++ b/src/mbgl/text/cross_tile_symbol_index.hpp @@ -32,10 +32,10 @@ class IndexedSymbolInstance { class TileLayerIndex { public: - TileLayerIndex(OverscaledTileID coord, std::vector<SymbolInstance>&, uint32_t bucketInstanceId); + TileLayerIndex(OverscaledTileID coord, const std::vector<SymbolInstance>&, std::vector<uint32_t>& symbolCrossTileIDs, uint32_t bucketInstanceId); - Point<int64_t> getScaledCoordinates(SymbolInstance&, const OverscaledTileID&); - void findMatches(std::vector<SymbolInstance>&, const OverscaledTileID&); + Point<int64_t> getScaledCoordinates(const SymbolInstance&, const OverscaledTileID&) const; + void findMatches(const std::vector<SymbolInstance>&, std::vector<uint32_t>& symbolCrossTileIDs, const OverscaledTileID&); OverscaledTileID coord; uint32_t bucketInstanceId; diff --git a/src/mbgl/text/placement.cpp b/src/mbgl/text/placement.cpp index 2a24a803a7..546635c51d 100644 --- a/src/mbgl/text/placement.cpp +++ b/src/mbgl/text/placement.cpp @@ -30,16 +30,21 @@ bool JointOpacityState::isHidden() const { return icon.isHidden() && text.isHidden(); } -Placement::Placement(const TransformState& state_, MapMode mapMode_) - : collisionIndex(state_) +Placement::Placement(const TransformState& state_, MapMode mapMode_, const mat4& projMatrix_, const bool showCollisionBoxes_, Scheduler& scheduler) + : result(makeMutable<PlacementResult>(state_)) , state(state_) , mapMode(mapMode_) + , showCollisionBoxes(showCollisionBoxes_) + , projMatrix(projMatrix_) + , worker(scheduler, state_, projMatrix_, showCollisionBoxes_) + , placementBucketLayers(makeMutable<std::vector<std::vector<PlacementBucket>>>()) , recentUntil(TimePoint::min()) {} -void Placement::placeLayer(RenderSymbolLayer& symbolLayer, const mat4& projMatrix, bool showCollisionBoxes) { +void Placement::addLayer(RenderSymbolLayer& symbolLayer) { - std::unordered_set<uint32_t> seenCrossTileIDs; + placementBucketLayers->emplace_back(); + auto& placementBuckets = placementBucketLayers->back(); for (RenderTile& renderTile : symbolLayer.renderTiles) { @@ -51,111 +56,47 @@ void Placement::placeLayer(RenderSymbolLayer& symbolLayer, const mat4& projMatri assert(dynamic_cast<SymbolBucket*>(bucket)); SymbolBucket& symbolBucket = *reinterpret_cast<SymbolBucket*>(bucket); - auto& layout = symbolBucket.layout; - - const float pixelsToTileUnits = renderTile.id.pixelsToTileUnits(1, state.getZoom()); - - const float scale = std::pow(2, state.getZoom() - renderTile.tile.id.overscaledZ); - const float textPixelRatio = util::EXTENT / (util::tileSize * renderTile.tile.id.overscaleFactor()); - - mat4 posMatrix; - state.matrixFor(posMatrix, renderTile.id); - matrix::multiply(posMatrix, projMatrix, posMatrix); - - mat4 textLabelPlaneMatrix = getLabelPlaneMatrix(renderTile.matrix, - layout.get<TextPitchAlignment>() == style::AlignmentType::Map, - layout.get<TextRotationAlignment>() == style::AlignmentType::Map, - state, - pixelsToTileUnits); - - mat4 iconLabelPlaneMatrix = getLabelPlaneMatrix(renderTile.matrix, - layout.get<IconPitchAlignment>() == style::AlignmentType::Map, - layout.get<IconRotationAlignment>() == style::AlignmentType::Map, - state, - pixelsToTileUnits); - - placeLayerBucket(symbolBucket, posMatrix, textLabelPlaneMatrix, iconLabelPlaneMatrix, scale, textPixelRatio, showCollisionBoxes, seenCrossTileIDs); + assert(symbolBucket.core); + placementBuckets.emplace_back(*symbolBucket.core, *symbolBucket.symbolCrossTileIDs, renderTile.id, renderTile.tile.id); } } -void Placement::placeLayerBucket( - SymbolBucket& bucket, - const mat4& posMatrix, - const mat4& textLabelPlaneMatrix, - const mat4& iconLabelPlaneMatrix, - const float scale, - const float textPixelRatio, - const bool showCollisionBoxes, - std::unordered_set<uint32_t>& seenCrossTileIDs) { - - auto partiallyEvaluatedTextSize = bucket.textSizeBinder->evaluateForZoom(state.getZoom()); - auto partiallyEvaluatedIconSize = bucket.iconSizeBinder->evaluateForZoom(state.getZoom()); - - const bool iconWithoutText = !bucket.hasTextData() || bucket.layout.get<TextOptional>(); - const bool textWithoutIcon = !bucket.hasIconData() || bucket.layout.get<IconOptional>(); - - for (auto& symbolInstance : bucket.symbolInstances) { - - if (seenCrossTileIDs.count(symbolInstance.crossTileID) == 0) { - bool placeText = false; - bool placeIcon = false; - - if (symbolInstance.placedTextIndex) { - PlacedSymbol& placedSymbol = bucket.text.placedSymbols.at(*symbolInstance.placedTextIndex); - const float fontSize = evaluateSizeForFeature(partiallyEvaluatedTextSize, placedSymbol); - - placeText = collisionIndex.placeFeature(symbolInstance.textCollisionFeature, - posMatrix, textLabelPlaneMatrix, textPixelRatio, - placedSymbol, scale, fontSize, - bucket.layout.get<TextAllowOverlap>(), - bucket.layout.get<TextPitchAlignment>() == style::AlignmentType::Map, - showCollisionBoxes); - } - - if (symbolInstance.placedIconIndex) { - PlacedSymbol& placedSymbol = bucket.icon.placedSymbols.at(*symbolInstance.placedIconIndex); - const float fontSize = evaluateSizeForFeature(partiallyEvaluatedIconSize, placedSymbol); - - placeIcon = collisionIndex.placeFeature(symbolInstance.iconCollisionFeature, - posMatrix, iconLabelPlaneMatrix, textPixelRatio, - placedSymbol, scale, fontSize, - bucket.layout.get<IconAllowOverlap>(), - bucket.layout.get<IconPitchAlignment>() == style::AlignmentType::Map, - showCollisionBoxes); - } - - // combine placements for icon and text - if (!iconWithoutText && !textWithoutIcon) { - placeText = placeIcon = placeText && placeIcon; - } else if (!textWithoutIcon) { - placeText = placeText && placeIcon; - } else if (!iconWithoutText) { - placeIcon = placeText && placeIcon; - } - - if (placeText) { - collisionIndex.insertFeature(symbolInstance.textCollisionFeature, bucket.layout.get<TextIgnorePlacement>()); - } - - if (placeIcon) { - collisionIndex.insertFeature(symbolInstance.iconCollisionFeature, bucket.layout.get<IconIgnorePlacement>()); - } - - assert(symbolInstance.crossTileID != 0); +void Placement::place() { + if (mapMode == MapMode::Still) { + // synchronous + PlacementWorker placement(state, projMatrix, showCollisionBoxes); + result = placement.place(std::move(placementBucketLayers)); + } else { + // asynchronous + future = worker.ask(&PlacementWorker::place, std::move(placementBucketLayers)); + } +} - placements.emplace(symbolInstance.crossTileID, PlacementPair(placeText, placeIcon)); - seenCrossTileIDs.insert(symbolInstance.crossTileID); - } - } +bool Placement::isReady() { + if (mapMode == MapMode::Still) { + // synchronous + return true; + } else { + // asynchronous + return future.wait_for(Duration(0)) == std::future_status::ready; + } } bool Placement::commit(const Placement& prevPlacement, TimePoint now) { + + if (mapMode != MapMode::Still) { + // asynchronous result + result = future.get(); + } + commitTime = now; bool placementChanged = false; float increment = mapMode == MapMode::Still ? 1.0 : std::chrono::duration<float>(commitTime - prevPlacement.commitTime) / Duration(std::chrono::milliseconds(300)); + auto& placements = result->placements; + if (increment) {} // add the opacities from the current placement, and copy their current values from the previous placement for (auto& placementPair : placements) { @@ -200,17 +141,29 @@ void Placement::updateLayerOpacities(RenderSymbolLayer& symbolLayer) { } void Placement::updateBucketOpacities(SymbolBucket& bucket, std::unordered_set<uint32_t>& seenCrossTileIDs) { - if (bucket.hasTextData()) bucket.text.opacityVertices.clear(); - if (bucket.hasIconData()) bucket.icon.opacityVertices.clear(); + if (bucket.hasTextData()) { + bucket.text.opacityVertices.clear(); + bucket.text.placedSymbolVisibility.clear(); + } + if (bucket.hasIconData()) { + bucket.icon.opacityVertices.clear(); + bucket.icon.placedSymbolVisibility.clear(); + } if (bucket.hasCollisionBoxData()) bucket.collisionBox.dynamicVertices.clear(); if (bucket.hasCollisionCircleData()) bucket.collisionCircle.dynamicVertices.clear(); - for (SymbolInstance& symbolInstance : bucket.symbolInstances) { - auto opacityState = seenCrossTileIDs.count(symbolInstance.crossTileID) == 0 ? - getOpacity(symbolInstance.crossTileID) : + auto& symbolInstances = (*bucket.core)->symbolInstances; + + auto idIt = (*bucket.symbolCrossTileIDs)->begin(); + for (auto it = symbolInstances.begin(); it != symbolInstances.end(); it++, idIt++) { + auto& symbolInstance = *it; + auto crossTileID = *idIt; + + auto opacityState = seenCrossTileIDs.count(crossTileID) == 0 ? + getOpacity(crossTileID) : JointOpacityState(false, false); - seenCrossTileIDs.insert(symbolInstance.crossTileID); + seenCrossTileIDs.insert(crossTileID); if (symbolInstance.hasText) { auto opacityVertex = SymbolOpacityAttributes::vertex(opacityState.text.placed, opacityState.text.opacity); @@ -221,10 +174,10 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, std::unordered_set<u bucket.text.opacityVertices.emplace_back(opacityVertex); } if (symbolInstance.placedTextIndex) { - bucket.text.placedSymbols[*symbolInstance.placedTextIndex].hidden = opacityState.isHidden(); + bucket.text.placedSymbolVisibility.push_back(opacityState.isHidden()); } if (symbolInstance.placedVerticalTextIndex) { - bucket.text.placedSymbols[*symbolInstance.placedVerticalTextIndex].hidden = opacityState.isHidden(); + bucket.text.placedSymbolVisibility.push_back(opacityState.isHidden()); } } if (symbolInstance.hasIcon) { @@ -236,7 +189,7 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, std::unordered_set<u bucket.icon.opacityVertices.emplace_back(opacityVertex); } if (symbolInstance.placedIconIndex) { - bucket.icon.placedSymbols[*symbolInstance.placedIconIndex].hidden = opacityState.isHidden(); + bucket.icon.placedSymbolVisibility.push_back(opacityState.isHidden()); } } diff --git a/src/mbgl/text/placement.hpp b/src/mbgl/text/placement.hpp index fd36ad25e9..ab8f4e1e5a 100644 --- a/src/mbgl/text/placement.hpp +++ b/src/mbgl/text/placement.hpp @@ -2,15 +2,16 @@ #include <string> #include <unordered_map> +#include <mbgl/actor/actor.hpp> #include <mbgl/util/chrono.hpp> -#include <mbgl/text/collision_index.hpp> +#include <mbgl/text/placement_worker.hpp> #include <mbgl/layout/symbol_projection.hpp> +#include <mbgl/renderer/buckets/symbol_bucket.hpp> #include <unordered_set> namespace mbgl { class RenderSymbolLayer; - class SymbolBucket; class OpacityState { public: @@ -30,17 +31,12 @@ namespace mbgl { OpacityState text; }; - class PlacementPair { - public: - PlacementPair(bool text_, bool icon_) : text(text_), icon(icon_) {} - bool text; - bool icon; - }; - class Placement { public: - Placement(const TransformState&, MapMode mapMode); - void placeLayer(RenderSymbolLayer&, const mat4&, bool showCollisionBoxes); + Placement(const TransformState&, MapMode mapMode, const mat4& projMatrix, const bool showCollisionBoxes, Scheduler&); + void addLayer(RenderSymbolLayer&); + void place(); + bool isReady(); bool commit(const Placement& prevPlacement, TimePoint); void updateLayerOpacities(RenderSymbolLayer&); JointOpacityState getOpacity(uint32_t crossTileSymbolID) const; @@ -48,7 +44,7 @@ namespace mbgl { bool hasTransitions(TimePoint now) const; // TODO: public for queryRenderedFeatures - CollisionIndex collisionIndex; + Immutable<PlacementResult> result; bool stillRecent(TimePoint now) const; void setRecent(TimePoint now); @@ -56,22 +52,25 @@ namespace mbgl { private: void placeLayerBucket( - SymbolBucket&, - const mat4& posMatrix, - const mat4& textLabelPlaneMatrix, - const mat4& iconLabelPlaneMatrix, - const float scale, - const float pixelRatio, - const bool showCollisionBoxes, + const SymbolBucket::Core&, + const std::vector<uint32_t>& symbolCrossTileIDs, + const UnwrappedTileID&, + const OverscaledTileID&, std::unordered_set<uint32_t>& seenCrossTileIDs); void updateBucketOpacities(SymbolBucket&, std::unordered_set<uint32_t>&); TransformState state; - MapMode mapMode; + const MapMode mapMode; TimePoint commitTime; + const bool showCollisionBoxes; + const mat4 projMatrix; + + Actor<PlacementWorker> worker; + std::future<Immutable<PlacementResult>> future; + + Mutable<std::vector<std::vector<PlacementBucket>>> placementBucketLayers; - std::unordered_map<uint32_t,PlacementPair> placements; std::unordered_map<uint32_t,JointOpacityState> opacities; TimePoint recentUntil; diff --git a/src/mbgl/text/placement_worker.cpp b/src/mbgl/text/placement_worker.cpp new file mode 100644 index 0000000000..041f48e805 --- /dev/null +++ b/src/mbgl/text/placement_worker.cpp @@ -0,0 +1,128 @@ +#include <mbgl/text/placement_worker.hpp> +#include <mbgl/layout/symbol_projection.hpp> + +namespace mbgl { + +PlacementBucket::PlacementBucket(Immutable<SymbolBucket::Core>& core, Immutable<std::vector<uint32_t>>& ids, const UnwrappedTileID& unwrapped, const OverscaledTileID& overscaled) : + symbolBucketCore(core), symbolCrossTileIDs(ids), unwrappedTileID(unwrapped), overscaledTileID(overscaled) {} + +PlacementWorker::PlacementWorker(const TransformState& state_, const mat4& projMatrix_, const bool showCollisionBoxes_) : + state(state_), + projMatrix(projMatrix_), + showCollisionBoxes(showCollisionBoxes_) + {} + +Immutable<PlacementResult> PlacementWorker::place(Immutable<std::vector<std::vector<PlacementBucket>>> placementBucketLayers) { + Mutable<PlacementResult> result = makeMutable<PlacementResult>(state); + + for (auto& placementBuckets : *placementBucketLayers) { + std::unordered_set<uint32_t> seenCrossTileIDs; + for (auto& placementBucket: placementBuckets) { + placeLayerBucket(result->placements, result->collisionIndex, *placementBucket.symbolBucketCore, *placementBucket.symbolCrossTileIDs, placementBucket.unwrappedTileID, placementBucket.overscaledTileID, seenCrossTileIDs); + } + } + + return std::move(result); +} + +void PlacementWorker::placeLayerBucket( + std::unordered_map<uint32_t,PlacementPair>& placements, + CollisionIndex& collisionIndex, + const SymbolBucket::Core& bucketCore, + const std::vector<uint32_t>& symbolCrossTileIDs, + const UnwrappedTileID& unwrappedTileID, + const OverscaledTileID& overscaledTileID, + std::unordered_set<uint32_t>& seenCrossTileIDs) { + + const float scale = std::pow(2, state.getZoom() - overscaledTileID.overscaledZ); + const float textPixelRatio = util::EXTENT / (util::tileSize * overscaledTileID.overscaleFactor()); + + const float pixelsToTileUnits = unwrappedTileID.pixelsToTileUnits(1, state.getZoom()); + + mat4 posMatrix; + state.matrixFor(posMatrix, unwrappedTileID); + matrix::multiply(posMatrix, projMatrix, posMatrix); + + mat4 textLabelPlaneMatrix = getLabelPlaneMatrix(posMatrix, + bucketCore.layout.get<style::TextPitchAlignment>() == style::AlignmentType::Map, + bucketCore.layout.get<style::TextRotationAlignment>() == style::AlignmentType::Map, + state, + pixelsToTileUnits); + + mat4 iconLabelPlaneMatrix = getLabelPlaneMatrix(posMatrix, + bucketCore.layout.get<style::IconPitchAlignment>() == style::AlignmentType::Map, + bucketCore.layout.get<style::IconRotationAlignment>() == style::AlignmentType::Map, + state, + pixelsToTileUnits); + + auto partiallyEvaluatedTextSize = bucketCore.textSizeBinder->evaluateForZoom(state.getZoom()); + auto partiallyEvaluatedIconSize = bucketCore.iconSizeBinder->evaluateForZoom(state.getZoom()); + + const bool iconWithoutText = !bucketCore.hasTextData || bucketCore.layout.get<style::TextOptional>(); + const bool textWithoutIcon = !bucketCore.hasIconData || bucketCore.layout.get<style::IconOptional>(); + + assert(bucketCore.symbolInstances.size() == symbolCrossTileIDs.size()); + + auto idIt = symbolCrossTileIDs.begin(); + for (auto it = bucketCore.symbolInstances.begin(); it != bucketCore.symbolInstances.end(); it++, idIt++) { + auto& symbolInstance = *it; + const uint32_t crossTileID = *idIt; + + if (seenCrossTileIDs.count(crossTileID) == 0) { + bool placeText = false; + bool placeIcon = false; + + // TODO eliminate this copy + CollisionFeature textCollisionFeature = symbolInstance.textCollisionFeature; + if (symbolInstance.placedTextIndex) { + const PlacedSymbol& placedSymbol = bucketCore.placedTextSymbols.at(*symbolInstance.placedTextIndex); + const float fontSize = evaluateSizeForFeature(partiallyEvaluatedTextSize, placedSymbol); + + placeText = collisionIndex.placeFeature(textCollisionFeature, + posMatrix, textLabelPlaneMatrix, textPixelRatio, + placedSymbol, scale, fontSize, + bucketCore.layout.get<style::TextAllowOverlap>(), + bucketCore.layout.get<style::TextPitchAlignment>() == style::AlignmentType::Map, + showCollisionBoxes); + } + + // TODO eliminate this copy + CollisionFeature iconCollisionFeature = symbolInstance.iconCollisionFeature; + if (symbolInstance.placedIconIndex) { + const PlacedSymbol& placedSymbol = bucketCore.placedIconSymbols.at(*symbolInstance.placedIconIndex); + const float fontSize = evaluateSizeForFeature(partiallyEvaluatedIconSize, placedSymbol); + + placeIcon = collisionIndex.placeFeature(iconCollisionFeature, + posMatrix, iconLabelPlaneMatrix, textPixelRatio, + placedSymbol, scale, fontSize, + bucketCore.layout.get<style::IconAllowOverlap>(), + bucketCore.layout.get<style::IconPitchAlignment>() == style::AlignmentType::Map, + showCollisionBoxes); + } + + // combine placements for icon and text + if (!iconWithoutText && !textWithoutIcon) { + placeText = placeIcon = placeText && placeIcon; + } else if (!textWithoutIcon) { + placeText = placeText && placeIcon; + } else if (!iconWithoutText) { + placeIcon = placeText && placeIcon; + } + + if (placeText) { + collisionIndex.insertFeature(textCollisionFeature, bucketCore.layout.get<style::TextIgnorePlacement>()); + } + + if (placeIcon) { + collisionIndex.insertFeature(iconCollisionFeature, bucketCore.layout.get<style::IconIgnorePlacement>()); + } + + assert(crossTileID != 0); + + placements.emplace(crossTileID, PlacementPair(placeText, placeIcon)); + seenCrossTileIDs.insert(crossTileID); + } + } +} + +} // namespace mbgl diff --git a/src/mbgl/text/placement_worker.hpp b/src/mbgl/text/placement_worker.hpp new file mode 100644 index 0000000000..86bc16088e --- /dev/null +++ b/src/mbgl/text/placement_worker.hpp @@ -0,0 +1,53 @@ +#pragma once + +#include <unordered_map> +#include <mbgl/util/immutable.hpp> +#include <mbgl/renderer/buckets/symbol_bucket.hpp> +#include <mbgl/text/collision_index.hpp> + +namespace mbgl { + +class PlacementBucket { + public: + PlacementBucket(Immutable<SymbolBucket::Core>&, Immutable<std::vector<uint32_t>>& ids, const UnwrappedTileID&, const OverscaledTileID&); + Immutable<SymbolBucket::Core> symbolBucketCore; + Immutable<std::vector<uint32_t>> symbolCrossTileIDs; + UnwrappedTileID unwrappedTileID; + OverscaledTileID overscaledTileID; +}; + +class PlacementPair { + public: + PlacementPair(bool text_, bool icon_) : text(text_), icon(icon_) {} + bool text; + bool icon; +}; + +class PlacementResult { + public: + PlacementResult(const TransformState& state) : collisionIndex(state) {} + CollisionIndex collisionIndex; + std::unordered_map<uint32_t,PlacementPair> placements; +}; + +class PlacementWorker { + public: + PlacementWorker(const TransformState&, const mat4& projMatrix, const bool showCollisionBoxes); + Immutable<PlacementResult> place(Immutable<std::vector<std::vector<PlacementBucket>>> placementBucketLayers); + + private: + TransformState state; + const mat4 projMatrix; + const bool showCollisionBoxes; + + void placeLayerBucket( + std::unordered_map<uint32_t,PlacementPair>& placements, + CollisionIndex& collisionIndex, + const SymbolBucket::Core&, + const std::vector<uint32_t>& symbolCrossTileIDs, + const UnwrappedTileID&, + const OverscaledTileID&, + std::unordered_set<uint32_t>& seenCrossTileIDs); +}; + +} // namespace mbgl |