Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

fix symbol flickering across antimeridian #11938

Merged
merged 2 commits into from
May 22, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 15 additions & 5 deletions include/mbgl/tile/tile_id.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,11 @@ class OverscaledTileID {
uint32_t overscaleFactor() const;
OverscaledTileID scaledTo(uint8_t z) const;
UnwrappedTileID toUnwrapped() const;
OverscaledTileID unwrapTo(int16_t wrap);

const uint8_t overscaledZ;
const int16_t wrap;
const CanonicalTileID canonical;
uint8_t overscaledZ;
int16_t wrap;
CanonicalTileID canonical;
};

::std::ostream& operator<<(::std::ostream& os, const OverscaledTileID& rhs);
Expand All @@ -84,9 +85,10 @@ class UnwrappedTileID {
std::array<UnwrappedTileID, 4> children() const;
OverscaledTileID overscaleTo(uint8_t z) const;
float pixelsToTileUnits(float pixelValue, float zoom) const;
UnwrappedTileID unwrapTo(int16_t wrap);

const int16_t wrap;
const CanonicalTileID canonical;
int16_t wrap;
CanonicalTileID canonical;
};

::std::ostream& operator<<(::std::ostream& os, const UnwrappedTileID& rhs);
Expand Down Expand Up @@ -191,6 +193,10 @@ inline UnwrappedTileID OverscaledTileID::toUnwrapped() const {
return { wrap, canonical };
}

inline OverscaledTileID OverscaledTileID::unwrapTo(int16_t newWrap) {
return { overscaledZ, newWrap, canonical };
}

inline UnwrappedTileID::UnwrappedTileID(uint8_t z_, int64_t x_, int64_t y_)
: wrap((x_ < 0 ? x_ - (1ll << z_) + 1 : x_) / (1ll << z_)),
canonical(
Expand All @@ -215,6 +221,10 @@ inline bool UnwrappedTileID::operator<(const UnwrappedTileID& rhs) const {
return std::tie(wrap, canonical) < std::tie(rhs.wrap, rhs.canonical);
}

inline UnwrappedTileID UnwrappedTileID::unwrapTo(int16_t newWrap) {
return { newWrap, canonical };
}

inline bool UnwrappedTileID::isChildOf(const UnwrappedTileID& parent) const {
return wrap == parent.wrap && canonical.isChildOf(parent.canonical);
}
Expand Down
2 changes: 1 addition & 1 deletion src/mbgl/renderer/render_tile.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class RenderTile final {
RenderTile& operator=(const RenderTile&) = delete;
RenderTile& operator=(RenderTile&&) = default;

const UnwrappedTileID id;
UnwrappedTileID id;
Tile& tile;
ClipID clip;
mat4 matrix;
Expand Down
3 changes: 2 additions & 1 deletion src/mbgl/renderer/renderer_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,8 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) {
}
for (auto it = order.rbegin(); it != order.rend(); ++it) {
if (it->layer.is<RenderSymbolLayer>()) {
if (crossTileSymbolIndex.addLayer(*it->layer.as<RenderSymbolLayer>())) symbolBucketsChanged = true;
const float lng = parameters.state.getLatLng().longitude();
if (crossTileSymbolIndex.addLayer(*it->layer.as<RenderSymbolLayer>(), lng)) symbolBucketsChanged = true;
}
}

Expand Down
40 changes: 40 additions & 0 deletions src/mbgl/renderer/tile_pyramid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ void TilePyramid::update(const std::vector<Immutable<style::Layer::Impl>>& layer
return;
}

handleWrapJump(parameters.transformState.getLatLng().longitude());

// Determine the overzooming/underzooming amounts and required tiles.
int32_t overscaledZoom = util::coveringZoomLevel(parameters.transformState.getZoom(), type, tileSize);
int32_t tileZoom = overscaledZoom;
Expand Down Expand Up @@ -238,6 +240,44 @@ void TilePyramid::update(const std::vector<Immutable<style::Layer::Impl>>& layer
}
}

void TilePyramid::handleWrapJump(float lng) {
// On top of the regular z/x/y values, TileIDs have a `wrap` value that specify
// which cppy of the world the tile belongs to. For example, at `lng: 10` you
// might render z/x/y/0 while at `lng: 370` you would render z/x/y/1.
//
// When lng values get wrapped (going from `lng: 370` to `long: 10`) you expect
// to see the same thing on the screen (370 degrees and 10 degrees is the same
// place in the world) but all the TileIDs will have different wrap values.
//
// In order to make this transition seamless, we calculate the rounded difference of
// "worlds" between the last frame and the current frame. If the map panned by
// a world, then we can assign all the tiles new TileIDs with updated wrap values.
// For example, assign z/x/y/1 a new id: z/x/y/0. It is the same tile, just rendered
// in a different position.
//
// This enables us to reuse the tiles at more ideal locations and prevent flickering.

const float lngDifference = lng - prevLng;
const float worldDifference = lngDifference / 360;
const int wrapDelta = ::round(worldDifference);
prevLng = lng;

if (wrapDelta) {
std::map<OverscaledTileID, std::unique_ptr<Tile>> newTiles;
for (auto& tile : tiles) {
auto newID = tile.second->id.unwrapTo(tile.second->id.wrap + wrapDelta);
tile.second->id = newID;
newTiles.emplace(newID, std::move(tile.second));
}
tiles = std::move(newTiles);

for (auto& renderTile : renderTiles) {
renderTile.id = renderTile.id.unwrapTo(renderTile.id.wrap + wrapDelta);
}
}
}


std::unordered_map<std::string, std::vector<Feature>> TilePyramid::queryRenderedFeatures(const ScreenLineString& geometry,
const TransformState& transformState,
const std::vector<const RenderLayer*>& layers,
Expand Down
4 changes: 4 additions & 0 deletions src/mbgl/renderer/tile_pyramid.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ class TilePyramid {
std::vector<std::reference_wrapper<RenderTile>> getRenderTiles();
Tile* getTile(const OverscaledTileID&);

void handleWrapJump(float lng);

std::unordered_map<std::string, std::vector<Feature>>
queryRenderedFeatures(const ScreenLineString& geometry,
const TransformState& transformState,
Expand All @@ -72,6 +74,8 @@ class TilePyramid {
std::vector<RenderTile> renderTiles;

TileObserver* observer = nullptr;

float prevLng = 0;
};

} // namespace mbgl
30 changes: 29 additions & 1 deletion src/mbgl/text/cross_tile_symbol_index.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,32 @@ void TileLayerIndex::findMatches(std::vector<SymbolInstance>& symbolInstances, c
CrossTileSymbolLayerIndex::CrossTileSymbolLayerIndex() {
}

/*
* Sometimes when a user pans across the antimeridian the longitude value gets wrapped.
* To prevent labels from flashing out and in we adjust the tileID values in the indexes
* so that they match the new wrapped version of the map.
*/
void CrossTileSymbolLayerIndex::handleWrapJump(float newLng) {

const int wrapDelta = ::round((newLng - lng) / 360);
if (wrapDelta != 0) {
std::map<uint8_t, std::map<OverscaledTileID,TileLayerIndex>> newIndexes;
for (auto& zoomIndex : indexes) {
std::map<OverscaledTileID,TileLayerIndex> newZoomIndex;
for (auto& index : zoomIndex.second) {
// change the tileID's wrap and move its index
index.second.coord = index.second.coord.unwrapTo(index.second.coord.wrap + wrapDelta);
newZoomIndex.emplace(index.second.coord, std::move(index.second));
}
newIndexes.emplace(zoomIndex.first, std::move(newZoomIndex));
}

indexes = std::move(newIndexes);
}

lng = newLng;
}

bool CrossTileSymbolLayerIndex::addBucket(const OverscaledTileID& tileID, SymbolBucket& bucket, uint32_t& maxCrossTileID) {
const auto& thisZoomIndexes = indexes[tileID.overscaledZ];
auto previousIndex = thisZoomIndexes.find(tileID);
Expand Down Expand Up @@ -138,13 +164,15 @@ bool CrossTileSymbolLayerIndex::removeStaleBuckets(const std::unordered_set<uint

CrossTileSymbolIndex::CrossTileSymbolIndex() {}

bool CrossTileSymbolIndex::addLayer(RenderSymbolLayer& symbolLayer) {
bool CrossTileSymbolIndex::addLayer(RenderSymbolLayer& symbolLayer, float lng) {

auto& layerIndex = layerIndexes[symbolLayer.getID()];

bool symbolBucketsChanged = false;
std::unordered_set<uint32_t> currentBucketIDs;

layerIndex.handleWrapJump(lng);

for (RenderTile& renderTile : symbolLayer.renderTiles) {
if (!renderTile.tile.isRenderable()) {
continue;
Expand Down
4 changes: 3 additions & 1 deletion src/mbgl/text/cross_tile_symbol_index.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,20 @@ class CrossTileSymbolLayerIndex {
CrossTileSymbolLayerIndex();
bool addBucket(const OverscaledTileID&, SymbolBucket&, uint32_t& maxCrossTileID);
bool removeStaleBuckets(const std::unordered_set<uint32_t>& currentIDs);
void handleWrapJump(float newLng);
private:
void removeBucketCrossTileIDs(uint8_t zoom, const TileLayerIndex& removedBucket);

std::map<uint8_t, std::map<OverscaledTileID,TileLayerIndex>> indexes;
std::map<uint8_t, std::set<uint32_t>> usedCrossTileIDs;
float lng = 0;
};

class CrossTileSymbolIndex {
public:
CrossTileSymbolIndex();

bool addLayer(RenderSymbolLayer&);
bool addLayer(RenderSymbolLayer&, float lng);
void pruneUnusedLayers(const std::set<std::string>&);

void reset();
Expand Down
2 changes: 1 addition & 1 deletion src/mbgl/tile/tile.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ class Tile : private util::noncopyable {

void dumpDebugLogs() const;

const OverscaledTileID id;
OverscaledTileID id;
optional<Timestamp> modified;
optional<Timestamp> expires;

Expand Down