summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMikhail Pozdnyakov <mikhail.pozdnyakov@mapbox.com>2020-04-24 17:02:29 +0300
committerMikhail Pozdnyakov <mikhail.pozdnyakov@mapbox.com>2020-04-28 20:50:18 +0300
commit2bf1610e6cb924d1a893c7f3acf4714c78819961 (patch)
treec661628e6ea7fb1c97527d8d21c999006eebdbd2 /src
parente44598704d82db099f173295839113e3090d8094 (diff)
downloadqtlocation-mapboxgl-2bf1610e6cb924d1a893c7f3acf4714c78819961.tar.gz
[core][tile mode] Fix placement order of the variable labels
Before this change, all variable labels that could potentially intersect tile borders were placed first, breaking the style label placement priority order.
Diffstat (limited to 'src')
-rw-r--r--src/mbgl/text/placement.cpp66
-rw-r--r--src/mbgl/text/placement.hpp4
2 files changed, 41 insertions, 29 deletions
diff --git a/src/mbgl/text/placement.cpp b/src/mbgl/text/placement.cpp
index 7bf360a746..18e1123b32 100644
--- a/src/mbgl/text/placement.cpp
+++ b/src/mbgl/text/placement.cpp
@@ -239,7 +239,9 @@ void Placement::placeSymbolBucket(const BucketPlacementData& params, std::set<ui
collisionGroups.get(params.sourceId),
getAvoidEdges(symbolBucket, renderTile.matrix)};
for (const SymbolInstance& symbol : getSortedSymbols(params, ctx.pixelRatio)) {
- placeSymbol(symbol, ctx, seenCrossTileIDs);
+ if (seenCrossTileIDs.count(symbol.crossTileID) != 0u) continue;
+ placeSymbol(symbol, ctx);
+ seenCrossTileIDs.insert(symbol.crossTileID);
}
// As long as this placement lives, we have to hold onto this bucket's
@@ -250,18 +252,14 @@ void Placement::placeSymbolBucket(const BucketPlacementData& params, std::set<ui
std::forward_as_tuple(symbolBucket.bucketInstanceId, params.featureIndex, ctx.getOverscaledID()));
}
-void Placement::placeSymbol(const SymbolInstance& symbolInstance,
- const PlacementContext& ctx,
- std::set<uint32_t>& seenCrossTileIDs) {
- if (symbolInstance.crossTileID == SymbolInstance::invalidCrossTileID() ||
- seenCrossTileIDs.count(symbolInstance.crossTileID) != 0u)
- return;
+JointPlacement Placement::placeSymbol(const SymbolInstance& symbolInstance, const PlacementContext& ctx) {
+ static const JointPlacement kUnplaced(false, false, false);
+ if (symbolInstance.crossTileID == SymbolInstance::invalidCrossTileID()) return kUnplaced;
if (ctx.getRenderTile().holdForFade()) {
// Mark all symbols from this tile as "not placed", but don't add to seenCrossTileIDs, because we don't
// know yet if we have a duplicate in a parent tile that _should_ be placed.
- placements.emplace(symbolInstance.crossTileID, JointPlacement(false, false, false));
- return;
+ return kUnplaced;
}
const SymbolBucket& bucket = ctx.getBucket();
const mat4& posMatrix = ctx.getRenderTile().matrix;
@@ -603,13 +601,11 @@ void Placement::placeSymbol(const SymbolInstance& symbolInstance,
placements.erase(symbolInstance.crossTileID);
}
- auto pair = placements.emplace(
- symbolInstance.crossTileID,
- JointPlacement(
- placeText || ctx.alwaysShowText, placeIcon || ctx.alwaysShowIcon, offscreen || bucket.justReloaded));
- assert(pair.second);
- newSymbolPlaced(symbolInstance, ctx, pair.first->second, ctx.placementType, textBoxes, iconBoxes);
- seenCrossTileIDs.insert(symbolInstance.crossTileID);
+ JointPlacement result(
+ placeText || ctx.alwaysShowText, placeIcon || ctx.alwaysShowIcon, offscreen || bucket.justReloaded);
+ placements.emplace(symbolInstance.crossTileID, result);
+ newSymbolPlaced(symbolInstance, ctx, result, ctx.placementType, textBoxes, iconBoxes);
+ return result;
}
namespace {
@@ -1274,7 +1270,8 @@ private:
style::SymbolPlacementType,
const std::vector<ProjectedCollisionBox>&,
const std::vector<ProjectedCollisionBox>&) override;
- void populateIntersectingSymbols();
+
+ bool shouldRetryPlacement(const JointPlacement&, const PlacementContext&);
std::unordered_map<uint32_t, bool> locationCache;
optional<CollisionBoundaries> tileBorders;
@@ -1297,7 +1294,7 @@ void TilePlacement::placeLayers(const RenderLayerReferences& layers) {
placeLayer(*it, seenCrossTileIDs);
}
- std::stable_sort(intersections.begin(), intersections.end(), [](const Intersection& a, const Intersection& b) {
+ std::sort(intersections.begin(), intersections.end(), [](const Intersection& a, const Intersection& b) {
if (a.priority != b.priority) return a.priority < b.priority;
uint8_t flagsA = a.status.flags;
uint8_t flagsB = b.status.flags;
@@ -1320,7 +1317,14 @@ void TilePlacement::placeLayers(const RenderLayerReferences& layers) {
});
// Place intersections.
for (const auto& intersection : intersections) {
- placeSymbol(intersection.symbol, intersection.ctx, seenCrossTileIDs);
+ const SymbolInstance& symbol = intersection.symbol;
+ const PlacementContext& ctx = intersection.ctx;
+ if (seenCrossTileIDs.count(symbol.crossTileID) != 0u) continue;
+ JointPlacement placement = placeSymbol(symbol, ctx);
+ if (shouldRetryPlacement(placement, ctx)) {
+ continue;
+ }
+ seenCrossTileIDs.insert(symbol.crossTileID);
}
// Place the rest labels.
populateIntersections = false;
@@ -1473,13 +1477,17 @@ bool TilePlacement::canPlaceAtVariableAnchor(const CollisionBox& box,
const mat4& posMatrix,
float textPixelRatio) {
assert(tileBorders);
+ if (populateIntersections) {
+ // A variable label is only allowed to intersect tile border with the first anchor.
+ if (anchor != anchors.front()) return false;
+ // Check, that the label would intersect the tile borders even without shift, otherwise intersection
+ // is not allowed (preventing cut-offs in case the shift is lager than the buffer size).
+ auto status = collisionIndex.intersectsTileEdges(box, {}, posMatrix, textPixelRatio, *tileBorders);
+ return status.flags != IntersectStatus::None;
+ }
+ // Can be placed, if it does not intersect tile borders.
auto status = collisionIndex.intersectsTileEdges(box, shift, posMatrix, textPixelRatio, *tileBorders);
- if (status.flags == IntersectStatus::None) return true;
-
- if (anchor != anchors.front()) return false;
-
- status = collisionIndex.intersectsTileEdges(box, {}, posMatrix, textPixelRatio, *tileBorders);
- return status.flags != IntersectStatus::None;
+ return (status.flags == IntersectStatus::None);
}
void TilePlacement::newSymbolPlaced(const SymbolInstance& symbol,
@@ -1488,7 +1496,8 @@ void TilePlacement::newSymbolPlaced(const SymbolInstance& symbol,
style::SymbolPlacementType placementType,
const std::vector<ProjectedCollisionBox>& textCollisionBoxes,
const std::vector<ProjectedCollisionBox>& iconCollisionBoxes) {
- if (!collectData || placementType != style::SymbolPlacementType::Point) return;
+ if (!collectData || placementType != style::SymbolPlacementType::Point || shouldRetryPlacement(placement, ctx))
+ return;
optional<mapbox::geometry::box<float>> textCollisionBox;
if (!textCollisionBoxes.empty()) {
@@ -1515,6 +1524,11 @@ void TilePlacement::newSymbolPlaced(const SymbolInstance& symbol,
placedSymbolsData.emplace_back(std::move(symbolData));
}
+bool TilePlacement::shouldRetryPlacement(const JointPlacement& placement, const PlacementContext& ctx) {
+ // We re-try the placement to try out remaining variable anchors.
+ return populateIntersections && !placement.placed() && !ctx.getVariableTextAnchors().empty();
+}
+
// static
Mutable<Placement> Placement::create(std::shared_ptr<const UpdateParameters> updateParameters_,
optional<Immutable<Placement>> prevPlacement) {
diff --git a/src/mbgl/text/placement.hpp b/src/mbgl/text/placement.hpp
index f530b6c5f7..82a62718a4 100644
--- a/src/mbgl/text/placement.hpp
+++ b/src/mbgl/text/placement.hpp
@@ -142,9 +142,7 @@ public:
protected:
friend SymbolBucket;
virtual void placeSymbolBucket(const BucketPlacementData&, std::set<uint32_t>& seenCrossTileIDs);
- void placeSymbol(const SymbolInstance& symbolInstance,
- const PlacementContext&,
- std::set<uint32_t>& seenCrossTileIDs);
+ JointPlacement placeSymbol(const SymbolInstance& symbolInstance, const PlacementContext&);
void placeLayer(const RenderLayer&, std::set<uint32_t>&);
virtual void commit();
virtual void newSymbolPlaced(const SymbolInstance&,