summaryrefslogtreecommitdiff
path: root/src/mbgl/text
diff options
context:
space:
mode:
authorMikhail Pozdnyakov <mikhail.pozdnyakov@mapbox.com>2020-03-23 21:38:52 +0200
committerMikhail Pozdnyakov <mikhail.pozdnyakov@mapbox.com>2020-03-25 15:11:41 +0200
commit313844b1da56b105cc2798a609b82d85d2286ba5 (patch)
tree7daa3bca9c91310732eddb8e974c7a795d156300 /src/mbgl/text
parentf5430ca33c713a6b709074440961447146a16302 (diff)
downloadqtlocation-mapboxgl-313844b1da56b105cc2798a609b82d85d2286ba5.tar.gz
[core][tile mode] Place tile intersecting labels first, across all layers
Thus, we reduce the amount of label cut-offs in Tile mode. Before, labels were arranged within one symbol layer (one bucket), which was not enough for several symbol layers being placed at the same time.
Diffstat (limited to 'src/mbgl/text')
-rw-r--r--src/mbgl/text/placement.cpp63
-rw-r--r--src/mbgl/text/placement.hpp2
2 files changed, 34 insertions, 31 deletions
diff --git a/src/mbgl/text/placement.cpp b/src/mbgl/text/placement.cpp
index 7ea89fd80d..049a72f63c 100644
--- a/src/mbgl/text/placement.cpp
+++ b/src/mbgl/text/placement.cpp
@@ -557,10 +557,10 @@ void Placement::placeSymbolBucket(const BucketPlacementData& params, std::set<ui
namespace {
SymbolInstanceReferences getBucketSymbols(const SymbolBucket& bucket,
- optional<SortKeyRange> sortKeyRange,
- float bearing) {
+ const optional<SortKeyRange>& sortKeyRange,
+ double bearing) {
if (bucket.layout->get<style::SymbolZOrder>() == style::SymbolZOrderType::ViewportY) {
- auto sortedSymbols = bucket.getSortedSymbols(bearing);
+ auto sortedSymbols = bucket.getSortedSymbols(float(bearing));
// Place in the reverse order than draw i.e., starting from the foreground elements.
std::reverse(std::begin(sortedSymbols), std::end(sortedSymbols));
return sortedSymbols;
@@ -1156,7 +1156,7 @@ const RetainedQueryData& Placement::getQueryData(uint32_t bucketInstanceId) cons
class StaticPlacement : public Placement {
public:
- StaticPlacement(std::shared_ptr<const UpdateParameters> updateParameters_)
+ explicit StaticPlacement(std::shared_ptr<const UpdateParameters> updateParameters_)
: Placement(std::move(updateParameters_), nullopt) {}
private:
@@ -1174,13 +1174,13 @@ void StaticPlacement::commit() {
JointOpacityState(jointPlacement.second.text, jointPlacement.second.icon, jointPlacement.second.skipFade));
}
}
-
class TilePlacement : public StaticPlacement {
public:
- TilePlacement(std::shared_ptr<const UpdateParameters> updateParameters_)
+ explicit TilePlacement(std::shared_ptr<const UpdateParameters> updateParameters_)
: StaticPlacement(std::move(updateParameters_)) {}
private:
+ void placeLayers(const RenderLayerReferences&) override;
optional<CollisionBoundaries> getAvoidEdges(const SymbolBucket&, const mat4&) override;
SymbolInstanceReferences getSortedSymbols(const BucketPlacementData&, float pixelRatio) override;
bool stickToFirstVariableAnchor(const CollisionBox& box,
@@ -1190,8 +1190,19 @@ private:
std::unordered_map<uint32_t, bool> locationCache;
optional<CollisionBoundaries> tileBorders;
+ bool onlyLabelsIntersectingTileBorders;
};
+void TilePlacement::placeLayers(const RenderLayerReferences& layers) {
+ // In order to avoid label cut-offs, at first, place the labels,
+ // which cross tile boundaries.
+ onlyLabelsIntersectingTileBorders = true;
+ StaticPlacement::placeLayers(layers);
+ // Place the rest labels.
+ onlyLabelsIntersectingTileBorders = false;
+ StaticPlacement::placeLayers(layers);
+}
+
optional<CollisionBoundaries> TilePlacement::getAvoidEdges(const SymbolBucket& bucket, const mat4& posMatrix) {
tileBorders = collisionIndex.projectTileBoundaries(posMatrix);
const auto& layout = *bucket.layout;
@@ -1209,7 +1220,8 @@ SymbolInstanceReferences TilePlacement::getSortedSymbols(const BucketPlacementDa
const auto& state = collisionIndex.getTransformState();
if (layout.get<style::SymbolPlacement>() != style::SymbolPlacementType::Point ||
layout.get<style::SymbolAvoidEdges>()) {
- return StaticPlacement::getSortedSymbols(params, pixelRatio);
+ return onlyLabelsIntersectingTileBorders ? SymbolInstanceReferences()
+ : StaticPlacement::getSortedSymbols(params, pixelRatio);
}
const bool rotateTextWithMap = layout.get<style::TextRotationAlignment>() == style::AlignmentType::Map;
const bool pitchTextWithMap = layout.get<style::TextPitchAlignment>() == style::AlignmentType::Map;
@@ -1221,7 +1233,6 @@ SymbolInstanceReferences TilePlacement::getSortedSymbols(const BucketPlacementDa
getBucketSymbols(bucket, params.sortKeyRange, collisionIndex.getTransformState().getBearing());
optional<style::TextVariableAnchorType> variableAnchor;
if (!variableTextAnchors.empty()) variableAnchor = variableTextAnchors.front();
- locationCache.clear();
// Keeps the data necessary to find a feature location according to a tile.
struct NeighborTileData {
@@ -1241,7 +1252,7 @@ SymbolInstanceReferences TilePlacement::getSortedSymbols(const BucketPlacementDa
uint8_t z = renderTile.id.canonical.z;
uint32_t x = renderTile.id.canonical.x;
uint32_t y = renderTile.id.canonical.y;
- const std::array<NeighborTileData, 4> neightbors{{
+ const std::array<NeighborTileData, 4> neighbours{{
{collisionIndex, UnwrappedTileID(z, x, y - 1), {0.0f, util::EXTENT}}, // top
{collisionIndex, UnwrappedTileID(z, x, y + 1), {0.0f, -util::EXTENT}}, // bottom
{collisionIndex, UnwrappedTileID(z, x - 1, y), {util::EXTENT, 0.0f}}, // left
@@ -1252,7 +1263,7 @@ SymbolInstanceReferences TilePlacement::getSortedSymbols(const BucketPlacementDa
bool intersects =
collisionIndex.intersectsTileEdges(collisionBox, shift, renderTile.matrix, pixelRatio, *tileBorders);
// Check if this symbol intersects the neighbor tile borders. If so, it also shall be placed with priority.
- for (const auto& neighbor : neightbors) {
+ for (const auto& neighbor : neighbours) {
if (intersects) break;
intersects = collisionIndex.intersectsTileEdges(
collisionBox, shift + neighbor.shift, neighbor.matrix, pixelRatio, neighbor.borders);
@@ -1261,16 +1272,12 @@ SymbolInstanceReferences TilePlacement::getSortedSymbols(const BucketPlacementDa
};
auto symbolIntersectsTileEdges = [
- this,
&collisionBoxIntersectsTileEdges,
variableAnchor,
pitchTextWithMap,
rotateTextWithMap,
bearing = state.getBearing()
](const SymbolInstance& symbol) noexcept->bool {
- auto it = locationCache.find(symbol.crossTileID);
- if (it != locationCache.end()) return it->second;
-
bool intersects = false;
if (!symbol.textCollisionFeature.boxes.empty()) {
const auto& textCollisionBox = symbol.textCollisionFeature.boxes.front();
@@ -1296,26 +1303,22 @@ SymbolInstanceReferences TilePlacement::getSortedSymbols(const BucketPlacementDa
intersects = collisionBoxIntersectsTileEdges(iconCollisionBox, {});
}
- locationCache.insert(std::make_pair(symbol.crossTileID, intersects));
return intersects;
};
- std::stable_sort(
- symbolInstances.begin(),
- symbolInstances.end(),
- [&symbolIntersectsTileEdges](const SymbolInstance& a, const SymbolInstance& b) noexcept {
- assert(!a.textCollisionFeature.alongLine);
- assert(!b.textCollisionFeature.alongLine);
- auto intersectsA = symbolIntersectsTileEdges(a);
- auto intersectsB = symbolIntersectsTileEdges(b);
- if (intersectsA) {
- if (!intersectsB) return true;
- // Both symbols are inrecepting the tile borders, we need a universal cross-tile rule
- // to define which of them shall be placed first - use anchor `y` point.
- return a.anchor.point.y < b.anchor.point.y;
- }
- return false;
+ if (onlyLabelsIntersectingTileBorders) {
+ SymbolInstanceReferences filtered;
+ filtered.reserve(symbolInstances.size());
+ for (const SymbolInstance& symbol : symbolInstances) {
+ if (symbolIntersectsTileEdges(symbol)) filtered.push_back(symbol);
+ }
+ // Add more stability, sorting tile border labels by their Y position.
+ std::stable_sort(filtered.begin(), filtered.end(), [](const SymbolInstance& a, const SymbolInstance& b) {
+ return a.anchor.point.y < b.anchor.point.y;
});
+ return filtered;
+ }
+
return symbolInstances;
}
diff --git a/src/mbgl/text/placement.hpp b/src/mbgl/text/placement.hpp
index b6354670b1..396aad4425 100644
--- a/src/mbgl/text/placement.hpp
+++ b/src/mbgl/text/placement.hpp
@@ -117,7 +117,7 @@ public:
optional<Immutable<Placement>> prevPlacement = nullopt);
virtual ~Placement();
- void placeLayers(const RenderLayerReferences&);
+ virtual void placeLayers(const RenderLayerReferences&);
void updateLayerBuckets(const RenderLayer&, const TransformState&, bool updateOpacities) const;
virtual float symbolFadeChange(TimePoint now) const;
virtual bool hasTransitions(TimePoint now) const;