[core] always reparse with the freshest possible placement config
Fixes an issue where updates to stale tiles would remove labels altogether until the map was rotated.
This commit is contained in:
@@ -213,7 +213,7 @@ void GLFWView::addRandomPointAnnotations(int count) {
|
||||
std::vector<mbgl::PointAnnotation> points;
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
points.emplace_back(makeRandomPoint(), "default_marker");
|
||||
points.emplace_back(makeRandomPoint(), "marker-15");
|
||||
}
|
||||
|
||||
auto newIDs = map->addPointAnnotations(points);
|
||||
|
||||
@@ -14,17 +14,12 @@ using namespace mbgl;
|
||||
|
||||
LiveTileData::LiveTileData(const TileID& id_,
|
||||
std::unique_ptr<AnnotationTile> tile_,
|
||||
Style& style_,
|
||||
const SourceInfo& source_,
|
||||
Style& style,
|
||||
const SourceInfo& source,
|
||||
std::function<void()> callback)
|
||||
: TileData(id_),
|
||||
worker(style_.workers),
|
||||
tileWorker(id_,
|
||||
source_.source_id,
|
||||
style_,
|
||||
style_.layers,
|
||||
state,
|
||||
std::make_unique<CollisionTile>(0, 0, false)),
|
||||
worker(style.workers),
|
||||
tileWorker(id, source.source_id, style, style.layers, state),
|
||||
tile(std::move(tile_)) {
|
||||
state = State::loaded;
|
||||
|
||||
@@ -41,25 +36,41 @@ bool LiveTileData::parsePending(std::function<void()> callback) {
|
||||
return false;
|
||||
}
|
||||
|
||||
workRequest = worker.parseLiveTile(tileWorker, *tile, [this, callback] (TileParseResult result) {
|
||||
workRequest.reset();
|
||||
workRequest = worker.parseLiveTile(tileWorker, *tile, targetConfig, [this, callback, config = targetConfig] (TileParseResult result) {
|
||||
workRequest.reset();
|
||||
|
||||
if (result.is<TileParseResultBuckets>()) {
|
||||
auto& resultBuckets = result.get<TileParseResultBuckets>();
|
||||
state = resultBuckets.state;
|
||||
|
||||
// Persist the configuration we just placed so that we can later check whether we need
|
||||
// to place again in case the configuration has changed.
|
||||
placedConfig = config;
|
||||
|
||||
// Move over all buckets we received in this parse request, potentially overwriting
|
||||
// existing buckets in case we got a refresh parse.
|
||||
for (auto& bucket : resultBuckets.buckets) {
|
||||
buckets[bucket.first] = std::move(bucket.second);
|
||||
}
|
||||
|
||||
// The target configuration could have changed since we started placement. In this case,
|
||||
// we're starting another placement run.
|
||||
if (placedConfig != targetConfig) {
|
||||
redoPlacement();
|
||||
}
|
||||
} else {
|
||||
error = result.get<std::string>();
|
||||
state = State::obsolete;
|
||||
}
|
||||
|
||||
callback();
|
||||
|
||||
// The target configuration could have changed since we started placement. In this case,
|
||||
// we're starting another placement run.
|
||||
if (!workRequest && placedConfig != targetConfig) {
|
||||
redoPlacement();
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
@@ -87,3 +98,36 @@ void LiveTileData::cancel() {
|
||||
state = State::obsolete;
|
||||
workRequest.reset();
|
||||
}
|
||||
|
||||
void LiveTileData::redoPlacement(const PlacementConfig newConfig) {
|
||||
if (newConfig != placedConfig) {
|
||||
targetConfig = newConfig;
|
||||
|
||||
if (!workRequest) {
|
||||
// Don't start a new placement request when the current one hasn't completed yet, or
|
||||
// when we are parsing buckets.
|
||||
redoPlacement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LiveTileData::redoPlacement() {
|
||||
workRequest.reset();
|
||||
workRequest = worker.redoPlacement(tileWorker, buckets, targetConfig, [this, config = targetConfig] {
|
||||
workRequest.reset();
|
||||
|
||||
// Persist the configuration we just placed so that we can later check whether we need to
|
||||
// place again in case the configuration has changed.
|
||||
placedConfig = config;
|
||||
|
||||
for (auto& bucket : buckets) {
|
||||
bucket.second->swapRenderData();
|
||||
}
|
||||
|
||||
// The target configuration could have changed since we started placement. In this case,
|
||||
// we're starting another placement run.
|
||||
if (placedConfig != targetConfig) {
|
||||
redoPlacement();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -22,6 +22,9 @@ public:
|
||||
|
||||
bool parsePending(std::function<void ()> callback) override;
|
||||
|
||||
void redoPlacement(PlacementConfig config) override;
|
||||
void redoPlacement();
|
||||
|
||||
void cancel() override;
|
||||
Bucket* getBucket(const StyleLayer&) override;
|
||||
|
||||
@@ -34,6 +37,13 @@ private:
|
||||
// Contains all the Bucket objects for the tile. Buckets are render
|
||||
// objects and they get added by tile parsing operations.
|
||||
std::unordered_map<std::string, std::unique_ptr<Bucket>> buckets;
|
||||
|
||||
// Stores the placement configuration of the text that is currently placed on the screen.
|
||||
PlacementConfig placedConfig;
|
||||
|
||||
// Stores the placement configuration of how the text should be placed. This isn't necessarily
|
||||
// the one that is being displayed.
|
||||
PlacementConfig targetConfig;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -286,8 +286,7 @@ TileData::State Source::addTile(MapData& data,
|
||||
|
||||
// If we don't find working tile data, we're just going to load it.
|
||||
if (info.type == SourceType::Vector) {
|
||||
auto tileData = std::make_shared<VectorTileData>(normalized_id, style, info,
|
||||
transformState.getAngle(), transformState.getPitch(), data.getCollisionDebug());
|
||||
auto tileData = std::make_shared<VectorTileData>(normalized_id, style, info);
|
||||
tileData->request(data.pixelRatio, callback);
|
||||
new_tile.data = tileData;
|
||||
} else if (info.type == SourceType::Raster) {
|
||||
@@ -296,7 +295,7 @@ TileData::State Source::addTile(MapData& data,
|
||||
new_tile.data = tileData;
|
||||
} else if (info.type == SourceType::Annotations) {
|
||||
new_tile.data = std::make_shared<LiveTileData>(normalized_id,
|
||||
data.getAnnotationManager()->getTile(normalized_id), style, info, callback);
|
||||
data.getAnnotationManager()->getTile(normalized_id), style, info, callback);
|
||||
} else {
|
||||
throw std::runtime_error("source type not implemented");
|
||||
}
|
||||
@@ -510,7 +509,8 @@ bool Source::update(MapData& data,
|
||||
updateTilePtrs();
|
||||
|
||||
for (auto& tilePtr : tilePtrs) {
|
||||
tilePtr->data->redoPlacement(transformState.getAngle(), transformState.getPitch(), data.getCollisionDebug());
|
||||
tilePtr->data->redoPlacement(
|
||||
{ transformState.getAngle(), transformState.getPitch(), data.getCollisionDebug() });
|
||||
}
|
||||
|
||||
updated = data.getAnimationTime();
|
||||
@@ -560,7 +560,7 @@ void Source::tileLoadingCompleteCallback(const TileID& normalized_id, const Tran
|
||||
return;
|
||||
}
|
||||
|
||||
data->redoPlacement(transformState.getAngle(), transformState.getPitch(), collisionDebug);
|
||||
data->redoPlacement({ transformState.getAngle(), transformState.getPitch(), collisionDebug });
|
||||
emitTileLoaded(true);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <mbgl/util/noncopyable.hpp>
|
||||
#include <mbgl/map/tile_id.hpp>
|
||||
#include <mbgl/renderer/bucket.hpp>
|
||||
#include <mbgl/text/placement_config.hpp>
|
||||
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
@@ -76,7 +77,7 @@ public:
|
||||
virtual Bucket* getBucket(const StyleLayer&) = 0;
|
||||
|
||||
virtual bool parsePending(std::function<void ()>) { return true; }
|
||||
virtual void redoPlacement(float, float, bool) {}
|
||||
virtual void redoPlacement(PlacementConfig) {}
|
||||
|
||||
bool isReady() const {
|
||||
return isReadyState(state);
|
||||
|
||||
@@ -19,15 +19,13 @@ TileWorker::TileWorker(TileID id_,
|
||||
std::string sourceID_,
|
||||
Style& style_,
|
||||
std::vector<util::ptr<StyleLayer>> layers_,
|
||||
const std::atomic<TileData::State>& state_,
|
||||
std::unique_ptr<CollisionTile> collision_)
|
||||
const std::atomic<TileData::State>& state_)
|
||||
: layers(std::move(layers_)),
|
||||
id(id_),
|
||||
sourceID(sourceID_),
|
||||
parameters(id.z),
|
||||
style(style_),
|
||||
state(state_),
|
||||
collisionTile(std::move(collision_)) {
|
||||
state(state_) {
|
||||
assert(style.sprite);
|
||||
}
|
||||
|
||||
@@ -35,10 +33,14 @@ TileWorker::~TileWorker() {
|
||||
style.glyphAtlas->removeGlyphs(reinterpret_cast<uintptr_t>(this));
|
||||
}
|
||||
|
||||
TileParseResult TileWorker::parseAllLayers(const GeometryTile& geometryTile) {
|
||||
TileParseResult TileWorker::parseAllLayers(const GeometryTile& geometryTile,
|
||||
PlacementConfig config) {
|
||||
// We're doing a fresh parse of the tile, because the underlying data has changed.
|
||||
pending.clear();
|
||||
|
||||
// Reset the collision tile so we have a clean slate; we're placing all features anyway.
|
||||
collisionTile = std::make_unique<CollisionTile>(config);
|
||||
|
||||
// We're storing a list of buckets we've parsed to avoid parsing a bucket twice that is
|
||||
// referenced from more than one layer
|
||||
std::set<StyleBucket*> parsed;
|
||||
@@ -84,12 +86,10 @@ TileParseResult TileWorker::parsePendingLayers() {
|
||||
|
||||
void TileWorker::redoPlacement(
|
||||
const std::unordered_map<std::string, std::unique_ptr<Bucket>>* buckets,
|
||||
float angle,
|
||||
float pitch,
|
||||
bool collisionDebug) {
|
||||
PlacementConfig config) {
|
||||
|
||||
// Reset the collision tile so we have a clean slate; we're placing all features anyway.
|
||||
collisionTile = std::make_unique<CollisionTile>(angle, pitch, collisionDebug);
|
||||
collisionTile = std::make_unique<CollisionTile>(config);
|
||||
|
||||
for (auto i = layers.rbegin(); i != layers.rend(); i++) {
|
||||
const auto it = buckets->find((*i)->id);
|
||||
@@ -268,11 +268,17 @@ void TileWorker::createSymbolBucket(const GeometryTileLayer& layer,
|
||||
|
||||
bucket->parseFeatures(layer, styleBucket.filter);
|
||||
|
||||
assert(style.glyphStore);
|
||||
assert(style.sprite);
|
||||
const bool needsDependencies = bucket->needsDependencies(*style.glyphStore, *style.sprite);
|
||||
if (needsDependencies) {
|
||||
// We cannot parse this bucket yet. Instead, we're saving it for later.
|
||||
pending.emplace_back(styleBucket, std::move(bucket));
|
||||
} else {
|
||||
assert(style.spriteAtlas);
|
||||
assert(style.glyphAtlas);
|
||||
assert(style.glyphStore);
|
||||
assert(collisionTile);
|
||||
bucket->addFeatures(reinterpret_cast<uintptr_t>(this), *style.spriteAtlas,
|
||||
*style.glyphAtlas, *style.glyphStore, *collisionTile);
|
||||
insertBucket(styleBucket.name, std::move(bucket));
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <mbgl/util/ptr.hpp>
|
||||
#include <mbgl/style/filter_expression.hpp>
|
||||
#include <mbgl/style/style_calculation_parameters.hpp>
|
||||
#include <mbgl/text/placement_config.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
@@ -42,16 +43,13 @@ public:
|
||||
std::string sourceID,
|
||||
Style&,
|
||||
std::vector<util::ptr<StyleLayer>>,
|
||||
const std::atomic<TileData::State>&,
|
||||
std::unique_ptr<CollisionTile>);
|
||||
const std::atomic<TileData::State>&);
|
||||
~TileWorker();
|
||||
|
||||
TileParseResult parseAllLayers(const GeometryTile&);
|
||||
TileParseResult parseAllLayers(const GeometryTile&, PlacementConfig);
|
||||
TileParseResult parsePendingLayers();
|
||||
void redoPlacement(const std::unordered_map<std::string, std::unique_ptr<Bucket>>*,
|
||||
float angle,
|
||||
float pitch,
|
||||
bool collisionDebug);
|
||||
PlacementConfig);
|
||||
|
||||
std::vector<util::ptr<StyleLayer>> layers;
|
||||
|
||||
|
||||
@@ -14,23 +14,15 @@ using namespace mbgl;
|
||||
|
||||
VectorTileData::VectorTileData(const TileID& id_,
|
||||
Style& style_,
|
||||
const SourceInfo& source_,
|
||||
float angle,
|
||||
float pitch,
|
||||
bool collisionDebug)
|
||||
const SourceInfo& source_)
|
||||
: TileData(id_),
|
||||
worker(style_.workers),
|
||||
tileWorker(id_,
|
||||
source_.source_id,
|
||||
style_,
|
||||
style_.layers,
|
||||
state,
|
||||
std::make_unique<CollisionTile>(angle, pitch, collisionDebug)),
|
||||
source(source_),
|
||||
lastAngle(angle),
|
||||
currentAngle(angle),
|
||||
currentPitch(pitch),
|
||||
currentCollisionDebug(collisionDebug) {
|
||||
state),
|
||||
source(source_) {
|
||||
}
|
||||
|
||||
VectorTileData::~VectorTileData() {
|
||||
@@ -81,7 +73,7 @@ void VectorTileData::parse(std::function<void ()> callback) {
|
||||
// when tile data changed. Replacing the workdRequest will cancel a pending work
|
||||
// request in case there is one.
|
||||
workRequest.reset();
|
||||
workRequest = worker.parseVectorTile(tileWorker, data, [this, callback] (TileParseResult result) {
|
||||
workRequest = worker.parseVectorTile(tileWorker, data, targetConfig, [this, callback, config = targetConfig] (TileParseResult result) {
|
||||
workRequest.reset();
|
||||
if (state == State::obsolete) {
|
||||
return;
|
||||
@@ -91,11 +83,21 @@ void VectorTileData::parse(std::function<void ()> callback) {
|
||||
auto& resultBuckets = result.get<TileParseResultBuckets>();
|
||||
state = resultBuckets.state;
|
||||
|
||||
// Persist the configuration we just placed so that we can later check whether we need to
|
||||
// place again in case the configuration has changed.
|
||||
placedConfig = config;
|
||||
|
||||
// Move over all buckets we received in this parse request, potentially overwriting
|
||||
// existing buckets in case we got a refresh parse.
|
||||
for (auto& bucket : resultBuckets.buckets) {
|
||||
buckets[bucket.first] = std::move(bucket.second);
|
||||
}
|
||||
|
||||
// The target configuration could have changed since we started placement. In this case,
|
||||
// we're starting another placement run.
|
||||
if (placedConfig != targetConfig) {
|
||||
redoPlacement();
|
||||
}
|
||||
} else {
|
||||
std::stringstream message;
|
||||
message << "Failed to parse [" << std::string(id) << "]: " << result.get<std::string>();
|
||||
@@ -129,6 +131,12 @@ bool VectorTileData::parsePending(std::function<void()> callback) {
|
||||
for (auto& bucket : resultBuckets.buckets) {
|
||||
buckets[bucket.first] = std::move(bucket.second);
|
||||
}
|
||||
|
||||
// The target configuration could have changed since we started placement. In this case,
|
||||
// we're starting another placement run.
|
||||
if (placedConfig != targetConfig) {
|
||||
redoPlacement();
|
||||
}
|
||||
} else {
|
||||
std::stringstream message;
|
||||
message << "Failed to parse [" << std::string(id) << "]: " << result.get<std::string>();
|
||||
@@ -156,34 +164,36 @@ Bucket* VectorTileData::getBucket(const StyleLayer& layer) {
|
||||
return it->second.get();
|
||||
}
|
||||
|
||||
void VectorTileData::redoPlacement(float angle, float pitch, bool collisionDebug) {
|
||||
if (angle == currentAngle && pitch == currentPitch && collisionDebug == currentCollisionDebug)
|
||||
return;
|
||||
void VectorTileData::redoPlacement(const PlacementConfig newConfig) {
|
||||
if (newConfig != placedConfig) {
|
||||
targetConfig = newConfig;
|
||||
|
||||
lastAngle = angle;
|
||||
lastPitch = pitch;
|
||||
lastCollisionDebug = collisionDebug;
|
||||
|
||||
if (workRequest) {
|
||||
// Don't start a new placement request when the current one hasn't completed yet, or when
|
||||
// we are parsing buckets.
|
||||
return;
|
||||
}
|
||||
|
||||
currentAngle = angle;
|
||||
currentPitch = pitch;
|
||||
currentCollisionDebug = collisionDebug;
|
||||
|
||||
workRequest.reset();
|
||||
workRequest = worker.redoPlacement(tileWorker, buckets, angle, pitch, collisionDebug, [this] {
|
||||
workRequest.reset();
|
||||
for (const auto& layer : tileWorker.layers) {
|
||||
auto bucket = getBucket(*layer);
|
||||
if (bucket) {
|
||||
bucket->swapRenderData();
|
||||
}
|
||||
if (!workRequest) {
|
||||
// Don't start a new placement request when the current one hasn't completed yet, or when
|
||||
// we are parsing buckets.
|
||||
redoPlacement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VectorTileData::redoPlacement() {
|
||||
workRequest.reset();
|
||||
workRequest = worker.redoPlacement(tileWorker, buckets, targetConfig, [this, config = targetConfig] {
|
||||
workRequest.reset();
|
||||
|
||||
// Persist the configuration we just placed so that we can later check whether we need to
|
||||
// place again in case the configuration has changed.
|
||||
placedConfig = config;
|
||||
|
||||
for (auto& bucket : buckets) {
|
||||
bucket.second->swapRenderData();
|
||||
}
|
||||
|
||||
// The target configuration could have changed since we started placement. In this case,
|
||||
// we're starting another placement run.
|
||||
if (placedConfig != targetConfig) {
|
||||
redoPlacement();
|
||||
}
|
||||
redoPlacement(lastAngle, lastPitch, lastCollisionDebug);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <mbgl/map/tile_data.hpp>
|
||||
#include <mbgl/map/tile_worker.hpp>
|
||||
#include <mbgl/storage/request_holder.hpp>
|
||||
#include <mbgl/text/placement_config.hpp>
|
||||
|
||||
#include <atomic>
|
||||
|
||||
@@ -17,7 +18,7 @@ class Request;
|
||||
class VectorTileData : public TileData {
|
||||
public:
|
||||
VectorTileData(
|
||||
const TileID&, Style&, const SourceInfo&, float angle_, float pitch_, bool collisionDebug_);
|
||||
const TileID&, Style&, const SourceInfo&);
|
||||
~VectorTileData();
|
||||
|
||||
Bucket* getBucket(const StyleLayer&) override;
|
||||
@@ -27,7 +28,8 @@ public:
|
||||
void parse(std::function<void()> callback);
|
||||
bool parsePending(std::function<void()> callback) override;
|
||||
|
||||
void redoPlacement(float angle, float pitch, bool collisionDebug) override;
|
||||
void redoPlacement(PlacementConfig config) override;
|
||||
void redoPlacement();
|
||||
|
||||
void cancel() override;
|
||||
|
||||
@@ -43,12 +45,13 @@ private:
|
||||
const SourceInfo& source;
|
||||
RequestHolder req;
|
||||
std::shared_ptr<const std::string> data;
|
||||
float lastAngle = 0;
|
||||
float currentAngle;
|
||||
float lastPitch = 0;
|
||||
float currentPitch;
|
||||
bool lastCollisionDebug = 0;
|
||||
bool currentCollisionDebug = 0;
|
||||
|
||||
// Stores the placement configuration of the text that is currently placed on the screen.
|
||||
PlacementConfig placedConfig;
|
||||
|
||||
// Stores the placement configuration of how the text should be placed. This isn't necessarily
|
||||
// the one that is being displayed.
|
||||
PlacementConfig targetConfig;
|
||||
};
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
@@ -382,8 +382,8 @@ void SymbolBucket::placeFeatures(CollisionTile& collisionTile, bool swapImmediat
|
||||
// Don't sort symbols that won't overlap because it isn't necessary and
|
||||
// because it causes more labels to pop in and out when rotating.
|
||||
if (mayOverlap) {
|
||||
float sin = std::sin(collisionTile.angle);
|
||||
float cos = std::cos(collisionTile.angle);
|
||||
const float sin = std::sin(collisionTile.config.angle);
|
||||
const float cos = std::cos(collisionTile.config.angle);
|
||||
|
||||
std::sort(symbolInstances.begin(), symbolInstances.end(), [sin, cos](SymbolInstance &a, SymbolInstance &b) {
|
||||
const float aRotated = sin * a.x + cos * a.y;
|
||||
@@ -426,8 +426,9 @@ void SymbolBucket::placeFeatures(CollisionTile& collisionTile, bool swapImmediat
|
||||
collisionTile.insertFeature(symbolInstance.textCollisionFeature, glyphScale);
|
||||
}
|
||||
if (glyphScale < collisionTile.maxScale) {
|
||||
addSymbols<SymbolRenderData::TextBuffer, TextElementGroup>(renderDataInProgress->text,
|
||||
symbolInstance.glyphQuads, glyphScale, layout.text.keep_upright, textAlongLine, collisionTile.angle);
|
||||
addSymbols<SymbolRenderData::TextBuffer, TextElementGroup>(
|
||||
renderDataInProgress->text, symbolInstance.glyphQuads, glyphScale,
|
||||
layout.text.keep_upright, textAlongLine, collisionTile.config.angle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -436,13 +437,16 @@ void SymbolBucket::placeFeatures(CollisionTile& collisionTile, bool swapImmediat
|
||||
collisionTile.insertFeature(symbolInstance.iconCollisionFeature, iconScale);
|
||||
}
|
||||
if (iconScale < collisionTile.maxScale) {
|
||||
addSymbols<SymbolRenderData::IconBuffer, IconElementGroup>(renderDataInProgress->icon,
|
||||
symbolInstance.iconQuads, iconScale, layout.icon.keep_upright, iconAlongLine, collisionTile.angle);
|
||||
addSymbols<SymbolRenderData::IconBuffer, IconElementGroup>(
|
||||
renderDataInProgress->icon, symbolInstance.iconQuads, iconScale,
|
||||
layout.icon.keep_upright, iconAlongLine, collisionTile.config.angle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (collisionTile.getDebug()) addToDebugBuffers(collisionTile);
|
||||
if (collisionTile.config.debug) {
|
||||
addToDebugBuffers(collisionTile);
|
||||
}
|
||||
|
||||
if (swapImmediately) swapRenderData();
|
||||
}
|
||||
@@ -513,7 +517,7 @@ void SymbolBucket::addSymbols(Buffer &buffer, const SymbolQuads &symbols, float
|
||||
void SymbolBucket::addToDebugBuffers(CollisionTile &collisionTile) {
|
||||
|
||||
const float yStretch = collisionTile.yStretch;
|
||||
const float angle = collisionTile.angle;
|
||||
const float angle = collisionTile.config.angle;
|
||||
float angle_sin = std::sin(-angle);
|
||||
float angle_cos = std::cos(-angle);
|
||||
std::array<float, 4> matrix = {{angle_cos, -angle_sin, angle_sin, angle_cos}};
|
||||
@@ -562,7 +566,9 @@ void SymbolBucket::addToDebugBuffers(CollisionTile &collisionTile) {
|
||||
}
|
||||
|
||||
void SymbolBucket::swapRenderData() {
|
||||
renderData = std::move(renderDataInProgress);
|
||||
if (renderDataInProgress) {
|
||||
renderData = std::move(renderDataInProgress);
|
||||
}
|
||||
}
|
||||
|
||||
void SymbolBucket::drawGlyphs(SDFShader &shader) {
|
||||
|
||||
@@ -3,17 +3,16 @@
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
CollisionTile::CollisionTile(const float angle_, const float pitch, bool debug_) :
|
||||
angle(angle_), debug(debug_) {
|
||||
CollisionTile::CollisionTile(PlacementConfig config_) : config(config_) {
|
||||
tree.clear();
|
||||
|
||||
// Compute the transformation matrix.
|
||||
float angle_sin = std::sin(angle);
|
||||
float angle_cos = std::cos(angle);
|
||||
rotationMatrix = {{angle_cos, -angle_sin, angle_sin, angle_cos}};
|
||||
// Compute the transformation matrix.
|
||||
const float angle_sin = std::sin(config.angle);
|
||||
const float angle_cos = std::cos(config.angle);
|
||||
rotationMatrix = { { angle_cos, -angle_sin, angle_sin, angle_cos } };
|
||||
|
||||
// Stretch boxes in y direction to account for the map tilt.
|
||||
const float _yStretch = 1.0f / std::cos(pitch);
|
||||
const float _yStretch = 1.0f / std::cos(config.pitch);
|
||||
|
||||
// The amount the map is squished depends on the y position.
|
||||
// Sort of account for this by making all boxes a bit bigger.
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define MBGL_TEXT_COLLISION_TILE
|
||||
|
||||
#include <mbgl/text/collision_feature.hpp>
|
||||
#include <mbgl/text/placement_config.hpp>
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||
@@ -24,39 +25,34 @@
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
namespace bg = boost::geometry;
|
||||
namespace bgm = bg::model;
|
||||
namespace bgi = bg::index;
|
||||
typedef bgm::point<float, 2, bg::cs::cartesian> CollisionPoint;
|
||||
typedef bgm::box<CollisionPoint> Box;
|
||||
typedef std::pair<Box, CollisionBox> CollisionTreeBox;
|
||||
typedef bgi::rtree<CollisionTreeBox, bgi::linear<16,4>> Tree;
|
||||
namespace bg = boost::geometry;
|
||||
namespace bgm = bg::model;
|
||||
namespace bgi = bg::index;
|
||||
typedef bgm::point<float, 2, bg::cs::cartesian> CollisionPoint;
|
||||
typedef bgm::box<CollisionPoint> Box;
|
||||
typedef std::pair<Box, CollisionBox> CollisionTreeBox;
|
||||
typedef bgi::rtree<CollisionTreeBox, bgi::linear<16, 4>> Tree;
|
||||
|
||||
class CollisionTile {
|
||||
public:
|
||||
explicit CollisionTile(PlacementConfig);
|
||||
|
||||
public:
|
||||
explicit CollisionTile(float angle_, float pitch_, bool debug_);
|
||||
float placeFeature(const CollisionFeature& feature);
|
||||
void insertFeature(CollisionFeature& feature, const float minPlacementScale);
|
||||
|
||||
float placeFeature(const CollisionFeature &feature);
|
||||
void insertFeature(CollisionFeature &feature, const float minPlacementScale);
|
||||
|
||||
bool getDebug() { return debug; }
|
||||
|
||||
const float angle = 0;
|
||||
const PlacementConfig config;
|
||||
|
||||
const float minScale = 0.5f;
|
||||
const float maxScale = 2.0f;
|
||||
float yStretch;
|
||||
|
||||
private:
|
||||
|
||||
Box getTreeBox(const vec2<float> &anchor, const CollisionBox &box);
|
||||
private:
|
||||
Box getTreeBox(const vec2<float>& anchor, const CollisionBox& box);
|
||||
|
||||
Tree tree;
|
||||
std::array<float, 4> rotationMatrix;
|
||||
bool debug;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
#endif
|
||||
|
||||
28
src/mbgl/text/placement_config.hpp
Normal file
28
src/mbgl/text/placement_config.hpp
Normal file
@@ -0,0 +1,28 @@
|
||||
#ifndef MBGL_TEXT_PLACEMENT_CONFIG
|
||||
#define MBGL_TEXT_PLACEMENT_CONFIG
|
||||
|
||||
namespace mbgl {
|
||||
|
||||
class PlacementConfig {
|
||||
public:
|
||||
inline PlacementConfig(float angle_ = 0, float pitch_ = 0, bool debug_ = false)
|
||||
: angle(angle_), pitch(pitch_), debug(debug_) {
|
||||
}
|
||||
|
||||
inline bool operator==(const PlacementConfig& rhs) const {
|
||||
return angle == rhs.angle && pitch == rhs.pitch && debug == rhs.debug;
|
||||
}
|
||||
|
||||
inline bool operator!=(const PlacementConfig& rhs) const {
|
||||
return !operator==(rhs);
|
||||
}
|
||||
|
||||
public:
|
||||
float angle;
|
||||
float pitch;
|
||||
bool debug;
|
||||
};
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
#endif
|
||||
@@ -37,10 +37,11 @@ public:
|
||||
|
||||
void parseVectorTile(TileWorker* worker,
|
||||
const std::shared_ptr<const std::string> data,
|
||||
PlacementConfig config,
|
||||
std::function<void(TileParseResult)> callback) {
|
||||
try {
|
||||
pbf tilePBF(reinterpret_cast<const unsigned char*>(data->data()), data->size());
|
||||
callback(worker->parseAllLayers(VectorTile(tilePBF)));
|
||||
callback(worker->parseAllLayers(VectorTile(tilePBF), config));
|
||||
} catch (const std::exception& ex) {
|
||||
callback(TileParseResult(ex.what()));
|
||||
}
|
||||
@@ -57,9 +58,10 @@ public:
|
||||
|
||||
void parseLiveTile(TileWorker* worker,
|
||||
const AnnotationTile* tile,
|
||||
PlacementConfig config,
|
||||
std::function<void(TileParseResult)> callback) {
|
||||
try {
|
||||
callback(worker->parseAllLayers(*tile));
|
||||
callback(worker->parseAllLayers(*tile, config));
|
||||
} catch (const std::exception& ex) {
|
||||
callback(TileParseResult(ex.what()));
|
||||
}
|
||||
@@ -67,11 +69,9 @@ public:
|
||||
|
||||
void redoPlacement(TileWorker* worker,
|
||||
const std::unordered_map<std::string, std::unique_ptr<Bucket>>* buckets,
|
||||
float angle,
|
||||
float pitch,
|
||||
bool collisionDebug,
|
||||
PlacementConfig config,
|
||||
std::function<void()> callback) {
|
||||
worker->redoPlacement(buckets, angle, pitch, collisionDebug);
|
||||
worker->redoPlacement(buckets, config);
|
||||
callback();
|
||||
}
|
||||
};
|
||||
@@ -97,10 +97,11 @@ Worker::parseRasterTile(std::unique_ptr<RasterBucket> bucket,
|
||||
std::unique_ptr<WorkRequest>
|
||||
Worker::parseVectorTile(TileWorker& worker,
|
||||
const std::shared_ptr<const std::string> data,
|
||||
PlacementConfig config,
|
||||
std::function<void(TileParseResult)> callback) {
|
||||
current = (current + 1) % threads.size();
|
||||
return threads[current]->invokeWithCallback(&Worker::Impl::parseVectorTile, callback, &worker,
|
||||
data);
|
||||
data, config);
|
||||
}
|
||||
|
||||
std::unique_ptr<WorkRequest>
|
||||
@@ -113,22 +114,21 @@ Worker::parsePendingVectorTileLayers(TileWorker& worker,
|
||||
|
||||
std::unique_ptr<WorkRequest> Worker::parseLiveTile(TileWorker& worker,
|
||||
const AnnotationTile& tile,
|
||||
PlacementConfig config,
|
||||
std::function<void(TileParseResult)> callback) {
|
||||
current = (current + 1) % threads.size();
|
||||
return threads[current]->invokeWithCallback(&Worker::Impl::parseLiveTile, callback, &worker,
|
||||
&tile);
|
||||
&tile, config);
|
||||
}
|
||||
|
||||
std::unique_ptr<WorkRequest>
|
||||
Worker::redoPlacement(TileWorker& worker,
|
||||
const std::unordered_map<std::string, std::unique_ptr<Bucket>>& buckets,
|
||||
float angle,
|
||||
float pitch,
|
||||
bool collisionDebug,
|
||||
PlacementConfig config,
|
||||
std::function<void()> callback) {
|
||||
current = (current + 1) % threads.size();
|
||||
return threads[current]->invokeWithCallback(&Worker::Impl::redoPlacement, callback, &worker,
|
||||
&buckets, angle, pitch, collisionDebug);
|
||||
&buckets, config);
|
||||
}
|
||||
|
||||
} // end namespace mbgl
|
||||
|
||||
@@ -37,6 +37,7 @@ public:
|
||||
|
||||
Request parseVectorTile(TileWorker&,
|
||||
std::shared_ptr<const std::string> data,
|
||||
PlacementConfig config,
|
||||
std::function<void(TileParseResult)> callback);
|
||||
|
||||
Request parsePendingVectorTileLayers(TileWorker&,
|
||||
@@ -44,13 +45,12 @@ public:
|
||||
|
||||
Request parseLiveTile(TileWorker&,
|
||||
const AnnotationTile&,
|
||||
PlacementConfig config,
|
||||
std::function<void(TileParseResult)> callback);
|
||||
|
||||
Request redoPlacement(TileWorker&,
|
||||
const std::unordered_map<std::string, std::unique_ptr<Bucket>>&,
|
||||
float angle,
|
||||
float pitch,
|
||||
bool collisionDebug,
|
||||
PlacementConfig config,
|
||||
std::function<void()> callback);
|
||||
|
||||
private:
|
||||
|
||||
Reference in New Issue
Block a user