[core] *Tile ↔ *TileData

Tile is now the main base class; RasterTile, VectorTile, etc are its subclasses. GeometryTileData and its subclasses form the piece that's passed to the worker.
This commit is contained in:
John Firebaugh
2016-06-13 10:59:33 -07:00
parent 3ab7c1cca3
commit 5c7dfd948f
58 changed files with 814 additions and 820 deletions

View File

@@ -3,7 +3,7 @@
#include <mbgl/style/filter.hpp>
#include <mbgl/style/filter_evaluator.hpp>
#include <mbgl/style/parser.hpp>
#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <rapidjson/document.h>

View File

@@ -7,15 +7,15 @@
namespace mbgl {
namespace algorithm {
template <typename GetTileDataFn,
typename CreateTileDataFn,
typename RetainTileDataFn,
template <typename GetTileFn,
typename CreateTileFn,
typename RetainTileFn,
typename RenderTileFn,
typename IdealTileIDs,
typename SourceInfo>
void updateRenderables(GetTileDataFn getTileData,
CreateTileDataFn createTileData,
RetainTileDataFn retainTileData,
void updateRenderables(GetTileFn getTile,
CreateTileFn createTile,
RetainTileFn retainTile,
RenderTileFn renderTile,
const IdealTileIDs& idealTileIDs,
const SourceInfo& info,
@@ -31,29 +31,29 @@ void updateRenderables(GetTileDataFn getTileData,
assert(dataTileZoom >= idealRenderTileID.canonical.z);
const OverscaledTileID idealDataTileID(dataTileZoom, idealRenderTileID.canonical);
auto data = getTileData(idealDataTileID);
auto data = getTile(idealDataTileID);
if (!data) {
data = createTileData(idealDataTileID);
data = createTile(idealDataTileID);
assert(data);
}
// if (source has the tile and bucket is loaded) {
if (data->isRenderable()) {
retainTileData(*data, true);
retainTile(*data, true);
renderTile(idealRenderTileID, *data);
} else {
bool triedPrevious = data->hasTriedOptional();
// The tile isn't loaded yet, but retain it anyway because it's an ideal tile.
retainTileData(*data, true);
retainTile(*data, true);
covered = true;
overscaledZ = dataTileZoom + 1;
if (overscaledZ > info.maxZoom) {
// We're looking for an overzoomed child tile.
const auto childDataTileID = idealDataTileID.scaledTo(overscaledZ);
data = getTileData(childDataTileID);
data = getTile(childDataTileID);
if (data && data->isRenderable()) {
retainTileData(*data, false);
retainTile(*data, false);
renderTile(idealRenderTileID, *data);
} else {
covered = false;
@@ -62,9 +62,9 @@ void updateRenderables(GetTileDataFn getTileData,
// Check all four actual child tiles.
for (const auto& childTileID : idealDataTileID.canonical.children()) {
const OverscaledTileID childDataTileID(overscaledZ, childTileID);
data = getTileData(childDataTileID);
data = getTile(childDataTileID);
if (data && data->isRenderable()) {
retainTileData(*data, false);
retainTile(*data, false);
renderTile(childDataTileID.unwrapTo(idealRenderTileID.wrap), *data);
} else {
// At least one child tile doesn't exist, so we are going to look for
@@ -89,14 +89,14 @@ void updateRenderables(GetTileDataFn getTileData,
checked.emplace(parentRenderTileID);
}
data = getTileData(parentDataTileID);
data = getTile(parentDataTileID);
if (!data && triedPrevious) {
data = createTileData(parentDataTileID);
data = createTile(parentDataTileID);
}
if (data) {
triedPrevious = data->hasTriedOptional();
retainTileData(*data, false);
retainTile(*data, false);
if (data->isRenderable()) {
renderTile(parentRenderTileID, *data);

View File

@@ -80,13 +80,13 @@ AnnotationIDs AnnotationManager::getPointAnnotationsInBounds(const LatLngBounds&
return result;
}
std::unique_ptr<AnnotationTile> AnnotationManager::getTile(const CanonicalTileID& tileID) {
std::unique_ptr<AnnotationTileData> AnnotationManager::getTileData(const CanonicalTileID& tileID) {
if (symbolAnnotations.empty() && shapeAnnotations.empty())
return nullptr;
auto tile = std::make_unique<AnnotationTile>();
auto tileData = std::make_unique<AnnotationTileData>();
AnnotationTileLayer& pointLayer = *tile->layers.emplace(
AnnotationTileLayer& pointLayer = *tileData->layers.emplace(
PointLayerID,
std::make_unique<AnnotationTileLayer>(PointLayerID)).first->second;
@@ -98,10 +98,10 @@ std::unique_ptr<AnnotationTile> AnnotationManager::getTile(const CanonicalTileID
}));
for (const auto& shape : shapeAnnotations) {
shape.second->updateTile(tileID, *tile);
shape.second->updateTileData(tileID, *tileData);
}
return tile;
return tileData;
}
void AnnotationManager::updateStyle(Style& style) {
@@ -134,18 +134,18 @@ void AnnotationManager::updateStyle(Style& style) {
obsoleteShapeAnnotationLayers.clear();
for (auto& data : monitors) {
data->setData(getTile(data->id.canonical), {}, {});
for (auto& tile : tiles) {
tile->setData(getTileData(tile->id.canonical), {}, {});
}
}
void AnnotationManager::addTileData(AnnotationTileData& data) {
monitors.insert(&data);
data.setData(getTile(data.id.canonical), {}, {});
void AnnotationManager::addTile(AnnotationTile& tile) {
tiles.insert(&tile);
tile.setData(getTileData(tile.id.canonical), {}, {});
}
void AnnotationManager::removeTileData(AnnotationTileData& data) {
monitors.erase(&data);
void AnnotationManager::removeTile(AnnotationTile& tile) {
tiles.erase(&tile);
}
void AnnotationManager::addIcon(const std::string& name, std::shared_ptr<const SpriteImage> sprite) {

View File

@@ -41,8 +41,8 @@ public:
void updateStyle(style::Style&);
void addTileData(AnnotationTileData&);
void removeTileData(AnnotationTileData&);
void addTile(AnnotationTile&);
void removeTile(AnnotationTile&);
static const std::string SourceID;
static const std::string PointLayerID;
@@ -53,7 +53,7 @@ private:
void add(const AnnotationID&, const FillAnnotation&, const uint8_t);
void add(const AnnotationID&, const StyleSourcedAnnotation&, const uint8_t);
std::unique_ptr<AnnotationTile> getTile(const CanonicalTileID&);
std::unique_ptr<AnnotationTileData> getTileData(const CanonicalTileID&);
AnnotationID nextID = 0;
@@ -65,7 +65,7 @@ private:
SymbolAnnotationMap symbolAnnotations;
ShapeAnnotationMap shapeAnnotations;
std::vector<std::string> obsoleteShapeAnnotationLayers;
std::set<AnnotationTileData*> monitors;
std::set<AnnotationTile*> tiles;
SpriteStore spriteStore;
SpriteAtlas spriteAtlas;

View File

@@ -8,19 +8,19 @@
namespace mbgl {
AnnotationTileData::AnnotationTileData(const OverscaledTileID& overscaledTileID,
std::string sourceID,
const style::UpdateParameters& parameters)
: GeometryTileData(overscaledTileID, sourceID, parameters.style, parameters.mode),
AnnotationTile::AnnotationTile(const OverscaledTileID& overscaledTileID,
std::string sourceID,
const style::UpdateParameters& parameters)
: GeometryTile(overscaledTileID, sourceID, parameters.style, parameters.mode),
annotationManager(parameters.annotationManager) {
annotationManager.addTileData(*this);
annotationManager.addTile(*this);
}
AnnotationTileData::~AnnotationTileData() {
annotationManager.removeTileData(*this);
AnnotationTile::~AnnotationTile() {
annotationManager.removeTile(*this);
}
void AnnotationTileData::setNecessity(Necessity) {}
void AnnotationTile::setNecessity(Necessity) {}
AnnotationTileFeature::AnnotationTileFeature(FeatureType type_, GeometryCollection geometries_,
std::unordered_map<std::string, std::string> properties_)
@@ -39,7 +39,7 @@ optional<Value> AnnotationTileFeature::getValue(const std::string& key) const {
AnnotationTileLayer::AnnotationTileLayer(const std::string &name_)
: name(name_) {}
util::ptr<GeometryTileLayer> AnnotationTile::getLayer(const std::string& name) const {
util::ptr<GeometryTileLayer> AnnotationTileData::getLayer(const std::string& name) const {
auto it = layers.find(name);
if (it != layers.end()) {
return it->second;

View File

@@ -11,12 +11,12 @@ namespace style {
class UpdateParameters;
}
class AnnotationTileData : public GeometryTileData {
class AnnotationTile : public GeometryTile {
public:
AnnotationTileData(const OverscaledTileID&,
AnnotationTile(const OverscaledTileID&,
std::string sourceID,
const style::UpdateParameters&);
~AnnotationTileData();
~AnnotationTile();
void setNecessity(Necessity) final;
@@ -52,7 +52,7 @@ private:
std::string name;
};
class AnnotationTile : public GeometryTile {
class AnnotationTileData : public GeometryTileData {
public:
util::ptr<GeometryTileLayer> getLayer(const std::string&) const override;

View File

@@ -85,7 +85,7 @@ private:
}
};
void ShapeAnnotationImpl::updateTile(const CanonicalTileID& tileID, AnnotationTile& tile) {
void ShapeAnnotationImpl::updateTileData(const CanonicalTileID& tileID, AnnotationTileData& data) {
static const double baseTolerance = 4;
if (!shapeTiler) {
@@ -108,7 +108,7 @@ void ShapeAnnotationImpl::updateTile(const CanonicalTileID& tileID, AnnotationTi
if (!shapeTile)
return;
AnnotationTileLayer& layer = *tile.layers.emplace(layerID,
AnnotationTileLayer& layer = *data.layers.emplace(layerID,
std::make_unique<AnnotationTileLayer>(layerID)).first->second;
for (auto& shapeFeature : shapeTile.features) {

View File

@@ -9,7 +9,7 @@
namespace mbgl {
class AnnotationTile;
class AnnotationTileData;
class CanonicalTileID;
namespace style {
@@ -24,7 +24,7 @@ public:
virtual void updateStyle(style::Style&) const = 0;
virtual const ShapeAnnotationGeometry& geometry() const = 0;
void updateTile(const CanonicalTileID&, AnnotationTile&);
void updateTileData(const CanonicalTileID&, AnnotationTileData&);
const AnnotationID id;
const uint8_t maxZoom;

View File

@@ -57,7 +57,7 @@ void FeatureIndex::query(
const double tileSize,
const double scale,
const optional<std::vector<std::string>>& filterLayerIDs,
const GeometryTile& geometryTile,
const GeometryTileData& geometryTileData,
const CanonicalTileID& tileID,
const style::Style& style) const {
@@ -75,7 +75,7 @@ void FeatureIndex::query(
if (indexedFeature.sortIndex == previousSortIndex) continue;
previousSortIndex = indexedFeature.sortIndex;
addFeature(result, indexedFeature, queryGeometry, filterLayerIDs, geometryTile, tileID, style, bearing, pixelsToTileUnits);
addFeature(result, indexedFeature, queryGeometry, filterLayerIDs, geometryTileData, tileID, style, bearing, pixelsToTileUnits);
}
// query symbol features
@@ -83,7 +83,7 @@ void FeatureIndex::query(
std::vector<IndexedSubfeature> symbolFeatures = collisionTile->queryRenderedSymbols(box, scale);
std::sort(symbolFeatures.begin(), symbolFeatures.end(), topDownSymbols);
for (const auto& symbolFeature : symbolFeatures) {
addFeature(result, symbolFeature, queryGeometry, filterLayerIDs, geometryTile, tileID, style, bearing, pixelsToTileUnits);
addFeature(result, symbolFeature, queryGeometry, filterLayerIDs, geometryTileData, tileID, style, bearing, pixelsToTileUnits);
}
}
@@ -92,7 +92,7 @@ void FeatureIndex::addFeature(
const IndexedSubfeature& indexedFeature,
const GeometryCollection& queryGeometry,
const optional<std::vector<std::string>>& filterLayerIDs,
const GeometryTile& geometryTile,
const GeometryTileData& geometryTileData,
const CanonicalTileID& tileID,
const style::Style& style,
const float bearing,
@@ -103,7 +103,7 @@ void FeatureIndex::addFeature(
return;
}
auto sourceLayer = geometryTile.getLayer(indexedFeature.sourceLayerName);
auto sourceLayer = geometryTileData.getLayer(indexedFeature.sourceLayerName);
assert(sourceLayer);
auto geometryTileFeature = sourceLayer->getFeature(indexedFeature.index);

View File

@@ -1,7 +1,7 @@
#pragma once
#include <mbgl/style/types.hpp>
#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/util/grid_index.hpp>
#include <mbgl/util/feature.hpp>
@@ -40,7 +40,7 @@ public:
const double tileSize,
const double scale,
const optional<std::vector<std::string>>& layerIDs,
const GeometryTile&,
const GeometryTileData&,
const CanonicalTileID&,
const style::Style&) const;
@@ -61,7 +61,7 @@ private:
const IndexedSubfeature&,
const GeometryCollection& queryGeometry,
const optional<std::vector<std::string>>& filterLayerIDs,
const GeometryTile&,
const GeometryTileData&,
const CanonicalTileID&,
const style::Style&,
const float bearing,

View File

@@ -2,7 +2,7 @@
#include <mbgl/renderer/bucket.hpp>
#include <mbgl/map/mode.hpp>
#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/geometry/elements_buffer.hpp>
#include <mbgl/geometry/circle_buffer.hpp>

View File

@@ -1,6 +1,5 @@
#pragma once
#include <mbgl/tile/tile_data.hpp>
#include <mbgl/map/mode.hpp>
#include <mbgl/geometry/debug_font_buffer.hpp>
#include <mbgl/geometry/vao.hpp>
@@ -8,6 +7,7 @@
namespace mbgl {
class OverscaledTileID;
class PlainShader;
namespace gl {

View File

@@ -1,7 +1,7 @@
#pragma once
#include <mbgl/renderer/bucket.hpp>
#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/geometry/elements_buffer.hpp>
#include <mbgl/geometry/fill_buffer.hpp>

View File

@@ -1,7 +1,7 @@
#pragma once
#include <mbgl/renderer/bucket.hpp>
#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/geometry/vao.hpp>
#include <mbgl/geometry/elements_buffer.hpp>
#include <mbgl/geometry/line_buffer.hpp>

View File

@@ -32,7 +32,7 @@ class SpriteAtlas;
class GlyphAtlas;
class LineAtlas;
struct FrameData;
class TileData;
class Tile;
class DebugBucket;
class FillBucket;
@@ -100,7 +100,7 @@ public:
void renderClipMasks();
void renderDebugText(TileData&, const mat4&);
void renderDebugText(Tile&, const mat4&);
void renderFill(FillBucket&, const style::FillLayer&, const UnwrappedTileID&, const mat4&);
void renderLine(LineBucket&, const style::LineLayer&, const UnwrappedTileID&, const mat4&);
void renderCircle(CircleBucket&, const style::CircleLayer&, const UnwrappedTileID&, const mat4&);

View File

@@ -1,7 +1,7 @@
#include <mbgl/renderer/painter.hpp>
#include <mbgl/renderer/debug_bucket.hpp>
#include <mbgl/renderer/render_tile.hpp>
#include <mbgl/tile/tile_data.hpp>
#include <mbgl/tile/tile.hpp>
#include <mbgl/shader/plain_shader.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/gl/debugging.hpp>
@@ -16,7 +16,7 @@ void Painter::renderTileDebug(const RenderTile& tile) {
if (frame.debugOptions != MapDebugOptions::NoDebug) {
setClipping(tile.clip);
if (frame.debugOptions & (MapDebugOptions::Timestamps | MapDebugOptions::ParseStatus)) {
renderDebugText(tile.data, tile.matrix);
renderDebugText(tile.tile, tile.matrix);
}
if (frame.debugOptions & MapDebugOptions::TileBorders) {
renderDebugFrame(tile.matrix);
@@ -24,19 +24,19 @@ void Painter::renderTileDebug(const RenderTile& tile) {
}
}
void Painter::renderDebugText(TileData& tileData, const mat4 &matrix) {
void Painter::renderDebugText(Tile& tile, const mat4 &matrix) {
MBGL_DEBUG_GROUP("debug text");
config.depthTest = GL_FALSE;
if (!tileData.debugBucket || tileData.debugBucket->renderable != tileData.isRenderable() ||
tileData.debugBucket->complete != tileData.isComplete() ||
!(tileData.debugBucket->modified == tileData.modified) ||
!(tileData.debugBucket->expires == tileData.expires) ||
tileData.debugBucket->debugMode != frame.debugOptions) {
tileData.debugBucket = std::make_unique<DebugBucket>(
tileData.id, tileData.isRenderable(), tileData.isComplete(), tileData.modified,
tileData.expires, frame.debugOptions);
if (!tile.debugBucket || tile.debugBucket->renderable != tile.isRenderable() ||
tile.debugBucket->complete != tile.isComplete() ||
!(tile.debugBucket->modified == tile.modified) ||
!(tile.debugBucket->expires == tile.expires) ||
tile.debugBucket->debugMode != frame.debugOptions) {
tile.debugBucket = std::make_unique<DebugBucket>(
tile.id, tile.isRenderable(), tile.isComplete(), tile.modified,
tile.expires, frame.debugOptions);
}
config.program = plainShader->getID();
@@ -45,18 +45,18 @@ void Painter::renderDebugText(TileData& tileData, const mat4 &matrix) {
// Draw white outline
plainShader->u_color = {{ 1.0f, 1.0f, 1.0f, 1.0f }};
config.lineWidth = 4.0f * frame.pixelRatio;
tileData.debugBucket->drawLines(*plainShader, store);
tile.debugBucket->drawLines(*plainShader, store);
#ifndef GL_ES_VERSION_2_0
// Draw line "end caps"
MBGL_CHECK_ERROR(glPointSize(2));
tileData.debugBucket->drawPoints(*plainShader, store);
tile.debugBucket->drawPoints(*plainShader, store);
#endif
// Draw black text.
plainShader->u_color = {{ 0.0f, 0.0f, 0.0f, 1.0f }};
config.lineWidth = 2.0f * frame.pixelRatio;
tileData.debugBucket->drawLines(*plainShader, store);
tile.debugBucket->drawLines(*plainShader, store);
config.depthFunc.reset();
config.depthTest = GL_TRUE;

View File

@@ -7,11 +7,11 @@
namespace mbgl {
class TileData;
class Tile;
class RenderTile {
public:
RenderTile(const UnwrappedTileID& id_, TileData& data_) : id(id_), data(data_) {
RenderTile(const UnwrappedTileID& id_, Tile& tile_) : id(id_), tile(tile_) {
}
RenderTile(const RenderTile&) = delete;
@@ -20,7 +20,7 @@ public:
RenderTile& operator=(RenderTile&&) = default;
const UnwrappedTileID id;
TileData& data;
Tile& tile;
ClipID clip;
mat4 matrix;
};

View File

@@ -1,7 +1,7 @@
#include <mbgl/renderer/symbol_bucket.hpp>
#include <mbgl/style/filter_evaluator.hpp>
#include <mbgl/style/layers/symbol_layer.hpp>
#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/sprite/sprite_image.hpp>
#include <mbgl/sprite/sprite_store.hpp>
#include <mbgl/sprite/sprite_atlas.hpp>

View File

@@ -1,7 +1,7 @@
#pragma once
#include <mbgl/renderer/bucket.hpp>
#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/map/mode.hpp>
#include <mbgl/geometry/vao.hpp>
#include <mbgl/geometry/elements_buffer.hpp>

View File

@@ -1,6 +1,6 @@
#include <mbgl/style/bucket_parameters.hpp>
#include <mbgl/style/filter_evaluator.hpp>
#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
namespace mbgl {
namespace style {

View File

@@ -1,7 +1,7 @@
#pragma once
#include <mbgl/style/filter.hpp>
#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <type_traits>

View File

@@ -6,7 +6,7 @@
#include <mbgl/renderer/render_pass.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/rapidjson.hpp>
#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <memory>
#include <string>

View File

@@ -12,7 +12,7 @@
#include <mapbox/geojsonvt.hpp>
#include <mapbox/geojsonvt/convert.hpp>
#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/util/mapbox.hpp>
#include <rapidjson/document.h>

View File

@@ -19,7 +19,7 @@
#include <mbgl/util/string.hpp>
#include <mbgl/util/tile_cover.hpp>
#include <mbgl/tile/raster_tile_data.hpp>
#include <mbgl/tile/raster_tile.hpp>
#include <mbgl/tile/geojson_tile.hpp>
#include <mbgl/tile/vector_tile.hpp>
#include <mbgl/annotation/annotation_tile.hpp>
@@ -62,7 +62,7 @@ Source::~Source() = default;
bool Source::isLoaded() const {
if (!loaded) return false;
for (const auto& pair : tileDataMap) {
for (const auto& pair : tiles) {
if (!pair.second->isComplete()) {
return false;
}
@@ -155,7 +155,7 @@ void Source::load(FileSource& fileSource) {
if (reloadTiles) {
// Tile information changed because we got new GeoJSON data, or a new tile URL.
tileDataMap.clear();
tiles.clear();
renderTiles.clear();
cache.clear();
}
@@ -185,17 +185,17 @@ const std::map<UnwrappedTileID, RenderTile>& Source::getRenderTiles() const {
return renderTiles;
}
std::unique_ptr<TileData> Source::createTile(const OverscaledTileID& overscaledTileID,
std::unique_ptr<Tile> Source::createTile(const OverscaledTileID& overscaledTileID,
const UpdateParameters& parameters) {
// If we don't find working tile data, we're just going to load it.
if (type == SourceType::Raster) {
return std::make_unique<RasterTileData>(overscaledTileID, parameters, *tileset);
return std::make_unique<RasterTile>(overscaledTileID, parameters, *tileset);
} else if (type == SourceType::Vector) {
return std::make_unique<VectorTileData>(overscaledTileID, id, parameters, *tileset);
return std::make_unique<VectorTile>(overscaledTileID, id, parameters, *tileset);
} else if (type == SourceType::Annotations) {
return std::make_unique<AnnotationTileData>(overscaledTileID, id, parameters);
return std::make_unique<AnnotationTile>(overscaledTileID, id, parameters);
} else if (type == SourceType::GeoJSON) {
return std::make_unique<GeoJSONTileData>(overscaledTileID, id, parameters, geojsonvt.get());
return std::make_unique<GeoJSONTile>(overscaledTileID, id, parameters, geojsonvt.get());
} else {
Log::Warning(Event::Style, "Source type '%s' is not implemented",
SourceTypeClass(type).c_str());
@@ -203,9 +203,9 @@ std::unique_ptr<TileData> Source::createTile(const OverscaledTileID& overscaledT
}
}
TileData* Source::getTileData(const OverscaledTileID& overscaledTileID) const {
auto it = tileDataMap.find(overscaledTileID);
if (it != tileDataMap.end()) {
Tile* Source::getTile(const OverscaledTileID& overscaledTileID) const {
auto it = tiles.find(overscaledTileID);
if (it != tiles.end()) {
return it->second.get();
} else {
return nullptr;
@@ -241,16 +241,16 @@ bool Source::update(const UpdateParameters& parameters) {
// we're actively using, e.g. as a replacement for tile that aren't loaded yet.
std::set<OverscaledTileID> retain;
auto retainTileDataFn = [&retain](TileData& tileData, bool required) -> void {
retain.emplace(tileData.id);
tileData.setNecessity(required ? TileData::Necessity::Required
: TileData::Necessity::Optional);
auto retainTileFn = [&retain](Tile& tile, bool required) -> void {
retain.emplace(tile.id);
tile.setNecessity(required ? Tile::Necessity::Required
: Tile::Necessity::Optional);
};
auto getTileDataFn = [this](const OverscaledTileID& dataTileID) -> TileData* {
return getTileData(dataTileID);
auto getTileFn = [this](const OverscaledTileID& dataTileID) -> Tile* {
return getTile(dataTileID);
};
auto createTileDataFn = [this, &parameters](const OverscaledTileID& dataTileID) -> TileData* {
std::unique_ptr<TileData> data = cache.get(dataTileID);
auto createTileFn = [this, &parameters](const OverscaledTileID& dataTileID) -> Tile* {
std::unique_ptr<Tile> data = cache.get(dataTileID);
if (!data) {
data = createTile(dataTileID, parameters);
if (data) {
@@ -258,17 +258,17 @@ bool Source::update(const UpdateParameters& parameters) {
}
}
if (data) {
return tileDataMap.emplace(dataTileID, std::move(data)).first->second.get();
return tiles.emplace(dataTileID, std::move(data)).first->second.get();
} else {
return nullptr;
}
};
auto renderTileFn = [this](const UnwrappedTileID& renderTileID, TileData& tileData) {
renderTiles.emplace(renderTileID, RenderTile{ renderTileID, tileData });
auto renderTileFn = [this](const UnwrappedTileID& renderTileID, Tile& tile) {
renderTiles.emplace(renderTileID, RenderTile{ renderTileID, tile });
};
renderTiles.clear();
algorithm::updateRenderables(getTileDataFn, createTileDataFn, retainTileDataFn, renderTileFn,
algorithm::updateRenderables(getTileFn, createTileFn, retainTileFn, renderTileFn,
idealTiles, *tileset, dataTileZoom);
if (type != SourceType::Raster && type != SourceType::Annotations && cache.getSize() == 0) {
@@ -281,15 +281,15 @@ bool Source::update(const UpdateParameters& parameters) {
}
// Remove stale data tiles from the active set of tiles.
// This goes through the (sorted!) tileDataMap and retain set in lockstep and removes items from
// tileDataMap that don't have the corresponding key in the retain set.
auto dataIt = tileDataMap.begin();
// This goes through the (sorted!) tiles and retain set in lockstep and removes items from
// tiles that don't have the corresponding key in the retain set.
auto dataIt = tiles.begin();
auto retainIt = retain.begin();
while (dataIt != tileDataMap.end()) {
while (dataIt != tiles.end()) {
if (retainIt == retain.end() || dataIt->first < *retainIt) {
dataIt->second->setNecessity(TileData::Necessity::Optional);
dataIt->second->setNecessity(Tile::Necessity::Optional);
cache.add(dataIt->first, std::move(dataIt->second));
tileDataMap.erase(dataIt++);
tiles.erase(dataIt++);
} else {
if (!(*retainIt < dataIt->first)) {
++dataIt;
@@ -301,14 +301,14 @@ bool Source::update(const UpdateParameters& parameters) {
const PlacementConfig newConfig{ parameters.transformState.getAngle(),
parameters.transformState.getPitch(),
parameters.debugOptions & MapDebugOptions::Collision };
for (auto& pair : tileDataMap) {
auto tileData = pair.second.get();
if (parameters.shouldReparsePartialTiles && tileData->isIncomplete()) {
if (!tileData->parsePending()) {
for (auto& pair : tiles) {
auto tile = pair.second.get();
if (parameters.shouldReparsePartialTiles && tile->isIncomplete()) {
if (!tile->parsePending()) {
allTilesUpdated = false;
}
} else {
tileData->redoPlacement(newConfig);
tile->redoPlacement(newConfig);
}
}
@@ -356,7 +356,7 @@ std::unordered_map<std::string, std::vector<Feature>> Source::queryRenderedFeatu
tileSpaceQueryGeometry.push_back(coordinateToTilePoint(tile.id, c));
}
tile.data.queryRenderedFeatures(result,
tile.tile.queryRenderedFeatures(result,
tileSpaceQueryGeometry,
parameters.transformState,
parameters.layerIDs);
@@ -377,12 +377,12 @@ void Source::setObserver(SourceObserver* observer_) {
observer = observer_;
}
void Source::onTileLoaded(TileData& tileData, bool isNewTile) {
observer->onTileLoaded(*this, tileData.id, isNewTile);
void Source::onTileLoaded(Tile& tile, bool isNewTile) {
observer->onTileLoaded(*this, tile.id, isNewTile);
}
void Source::onTileError(TileData& tileData, std::exception_ptr error) {
observer->onTileError(*this, tileData.id, error);
void Source::onTileError(Tile& tile, std::exception_ptr error) {
observer->onTileError(*this, tile.id, error);
}
void Source::onNeedsRepaint() {
@@ -393,9 +393,9 @@ void Source::dumpDebugLogs() const {
Log::Info(Event::General, "Source::id: %s", id.c_str());
Log::Info(Event::General, "Source::loaded: %d", loaded);
for (const auto& pair : tileDataMap) {
auto& tileData = pair.second;
tileData->dumpDebugLogs();
for (const auto& pair : tiles) {
auto& tile = pair.second;
tile->dumpDebugLogs();
}
}

View File

@@ -1,8 +1,8 @@
#pragma once
#include <mbgl/tile/tile_id.hpp>
#include <mbgl/tile/tile_data_observer.hpp>
#include <mbgl/tile/tile_data.hpp>
#include <mbgl/tile/tile_observer.hpp>
#include <mbgl/tile/tile.hpp>
#include <mbgl/tile/tile_cache.hpp>
#include <mbgl/style/types.hpp>
@@ -38,7 +38,7 @@ class UpdateParameters;
class QueryParameters;
class SourceObserver;
class Source : public TileDataObserver, private util::noncopyable {
class Source : public TileObserver, private util::noncopyable {
public:
Source(SourceType,
const std::string& id,
@@ -71,7 +71,7 @@ public:
const std::map<UnwrappedTileID, RenderTile>& getRenderTiles() const;
TileData* getTileData(const OverscaledTileID&) const;
Tile* getTile(const OverscaledTileID&) const;
std::unordered_map<std::string, std::vector<Feature>>
queryRenderedFeatures(const QueryParameters&) const;
@@ -89,12 +89,12 @@ public:
bool enabled = false;
private:
// TileDataObserver implementation.
void onTileLoaded(TileData&, bool isNewTile) override;
void onTileError(TileData&, std::exception_ptr) override;
// TileObserver implementation.
void onTileLoaded(Tile&, bool isNewTile) override;
void onTileError(Tile&, std::exception_ptr) override;
void onNeedsRepaint() override;
std::unique_ptr<TileData> createTile(const OverscaledTileID&, const UpdateParameters&);
std::unique_ptr<Tile> createTile(const OverscaledTileID&, const UpdateParameters&);
private:
std::unique_ptr<const Tileset> tileset;
@@ -104,8 +104,8 @@ private:
// Stores the time when this source was most recently updated.
TimePoint updated = TimePoint::min();
std::map<OverscaledTileID, std::unique_ptr<Tile>> tiles;
std::map<UnwrappedTileID, RenderTile> renderTiles;
std::map<OverscaledTileID, std::unique_ptr<TileData>> tileDataMap;
TileCache cache;
std::unique_ptr<AsyncRequest> req;

View File

@@ -291,7 +291,7 @@ RenderData Style::getRenderData() const {
for (auto& pair : source->getRenderTiles()) {
auto& tile = pair.second;
if (!tile.data.isRenderable()) {
if (!tile.tile.isRenderable()) {
continue;
}
@@ -304,7 +304,7 @@ RenderData Style::getRenderData() const {
// already a bucket from this layer that is a parent of this tile. Tiles are ordered
// by zoom level when we obtain them from getTiles().
for (auto it = result.order.rbegin(); it != result.order.rend() && (&it->layer == layer.get()); ++it) {
if (tile.data.id.isChildOf(it->tile->data.id)) {
if (tile.tile.id.isChildOf(it->tile->tile.id)) {
skip = true;
break;
}
@@ -314,7 +314,7 @@ RenderData Style::getRenderData() const {
}
}
auto bucket = tile.data.getBucket(*layer);
auto bucket = tile.tile.getBucket(*layer);
if (bucket) {
result.order.emplace_back(*layer, &tile, bucket);
}

View File

@@ -1,6 +1,6 @@
#pragma once
#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
namespace mbgl {

View File

@@ -2,7 +2,7 @@
#include <mbgl/geometry/anchor.hpp>
#include <mbgl/text/shaping.hpp>
#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/geometry/feature_index.hpp>
#include <vector>

View File

@@ -1,7 +1,7 @@
#pragma once
#include <mbgl/geometry/anchor.hpp>
#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/util/math.hpp>
namespace mbgl {

View File

@@ -1,6 +1,6 @@
#include <mbgl/text/quads.hpp>
#include <mbgl/text/shaping.hpp>
#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/geometry/anchor.hpp>
#include <mbgl/style/layers/symbol_layer_properties.hpp>
#include <mbgl/util/math.hpp>

View File

@@ -1,7 +1,7 @@
#pragma once
#include <mbgl/text/glyph.hpp>
#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <vector>

View File

@@ -1,5 +1,5 @@
#include <mbgl/tile/geojson_tile.hpp>
#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/style/update_parameters.hpp>
#include <mapbox/geojsonvt.hpp>
@@ -36,9 +36,9 @@ private:
const Features features;
};
class GeoJSONTile : public GeometryTile {
class GeoJSONTileData : public GeometryTileData {
public:
GeoJSONTile(std::shared_ptr<GeoJSONTileLayer>);
GeoJSONTileData(std::shared_ptr<GeoJSONTileLayer>);
util::ptr<GeometryTileLayer> getLayer(const std::string&) const override;
private:
@@ -46,7 +46,7 @@ private:
};
// Converts the geojsonvt::Tile to a a GeoJSONTile. They have a differing internal structure.
std::unique_ptr<GeoJSONTile> convertTile(const mapbox::geojsonvt::Tile& tile) {
std::unique_ptr<GeoJSONTileData> convertTile(const mapbox::geojsonvt::Tile& tile) {
std::shared_ptr<GeoJSONTileLayer> layer;
if (tile) {
@@ -103,24 +103,20 @@ std::unique_ptr<GeoJSONTile> convertTile(const mapbox::geojsonvt::Tile& tile) {
layer = std::make_unique<GeoJSONTileLayer>(std::move(features));
}
return std::make_unique<GeoJSONTile>(layer);
return std::make_unique<GeoJSONTileData>(layer);
}
GeoJSONTileData::GeoJSONTileData(const OverscaledTileID& overscaledTileID,
std::string sourceID,
const style::UpdateParameters& parameters,
mapbox::geojsonvt::GeoJSONVT* geojsonvt)
: GeometryTileData(overscaledTileID, sourceID, parameters.style, parameters.mode) {
GeoJSONTile::GeoJSONTile(const OverscaledTileID& overscaledTileID,
std::string sourceID,
const style::UpdateParameters& parameters,
mapbox::geojsonvt::GeoJSONVT* geojsonvt)
: GeometryTile(overscaledTileID, sourceID, parameters.style, parameters.mode) {
if (geojsonvt) {
auto tile = convertTile(
geojsonvt->getTile(id.canonical.z, id.canonical.x, id.canonical.y));
setData(std::move(tile), {}, {});
setData(convertTile(geojsonvt->getTile(id.canonical.z, id.canonical.x, id.canonical.y)), {}, {});
}
}
GeoJSONTileData::~GeoJSONTileData() = default;
void GeoJSONTileData::setNecessity(Necessity) {}
void GeoJSONTile::setNecessity(Necessity) {}
GeoJSONTileFeature::GeoJSONTileFeature(FeatureType type_,
GeometryCollection&& geometries_,
@@ -155,10 +151,10 @@ util::ptr<const GeometryTileFeature> GeoJSONTileLayer::getFeature(std::size_t i)
return features[i];
}
GeoJSONTile::GeoJSONTile(std::shared_ptr<GeoJSONTileLayer> layer_) : layer(std::move(layer_)) {
GeoJSONTileData::GeoJSONTileData(std::shared_ptr<GeoJSONTileLayer> layer_) : layer(std::move(layer_)) {
}
util::ptr<GeometryTileLayer> GeoJSONTile::getLayer(const std::string&) const {
util::ptr<GeometryTileLayer> GeoJSONTileData::getLayer(const std::string&) const {
// We're ignoring the layer name because GeoJSON tiles only have one layer.
return layer;
}

View File

@@ -1,6 +1,6 @@
#pragma once
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/tile/geometry_tile.hpp>
namespace mapbox {
namespace geojsonvt {
@@ -14,13 +14,12 @@ namespace style {
class UpdateParameters;
}
class GeoJSONTileData : public GeometryTileData {
class GeoJSONTile : public GeometryTile {
public:
GeoJSONTileData(const OverscaledTileID&,
std::string sourceID,
const style::UpdateParameters&,
mapbox::geojsonvt::GeoJSONVT*);
~GeoJSONTileData();
GeoJSONTile(const OverscaledTileID&,
std::string sourceID,
const style::UpdateParameters&,
mapbox::geojsonvt::GeoJSONVT*);
void setNecessity(Necessity) final;
};

View File

@@ -1,210 +1,206 @@
#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/tile/tile_id.hpp>
#include <clipper/clipper.hpp>
#include <mbgl/tile/tile_observer.hpp>
#include <mbgl/tile/tile_source.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/style/layer_impl.hpp>
#include <mbgl/util/worker.hpp>
#include <mbgl/util/work_request.hpp>
#include <mbgl/style/style.hpp>
#include <mbgl/storage/file_source.hpp>
#include <mbgl/geometry/feature_index.hpp>
#include <mbgl/text/collision_tile.hpp>
#include <mbgl/map/transform_state.hpp>
namespace mbgl {
static double signedArea(const GeometryCoordinates& ring) {
double sum = 0;
for (std::size_t i = 0, len = ring.size(), j = len - 1; i < len; j = i++) {
const GeometryCoordinate& p1 = ring[i];
const GeometryCoordinate& p2 = ring[j];
sum += (p2.x - p1.x) * (p1.y + p2.y);
}
return sum;
GeometryTile::GeometryTile(const OverscaledTileID& id_,
std::string sourceID,
style::Style& style_,
const MapMode mode_)
: Tile(id_),
style(style_),
worker(style_.workers),
tileWorker(id_,
sourceID,
*style_.spriteStore,
*style_.glyphAtlas,
*style_.glyphStore,
obsolete,
mode_) {
}
static ClipperLib::Path toClipperPath(const GeometryCoordinates& ring) {
ClipperLib::Path result;
result.reserve(ring.size());
for (const auto& p : ring) {
result.emplace_back(p.x, p.y);
}
return result;
void GeometryTile::setError(std::exception_ptr err) {
observer->onTileError(*this, err);
}
static GeometryCoordinates fromClipperPath(const ClipperLib::Path& path) {
GeometryCoordinates result;
result.reserve(path.size());
for (const auto& p : path) {
using Coordinate = GeometryCoordinates::coordinate_type;
assert(p.x >= std::numeric_limits<Coordinate>::min());
assert(p.x <= std::numeric_limits<Coordinate>::max());
assert(p.y >= std::numeric_limits<Coordinate>::min());
assert(p.y <= std::numeric_limits<Coordinate>::max());
result.emplace_back(Coordinate(p.x), Coordinate(p.y));
}
return result;
}
void GeometryTile::setData(std::unique_ptr<GeometryTileData> data_,
optional<Timestamp> modified_,
optional<Timestamp> expires_) {
modified = modified_;
expires = expires_;
static void processPolynodeBranch(ClipperLib::PolyNode* polynode, GeometryCollection& rings) {
// Exterior ring.
rings.push_back(fromClipperPath(polynode->Contour));
assert(signedArea(rings.back()) > 0);
// Interior rings.
for (auto * ring : polynode->Childs) {
rings.push_back(fromClipperPath(ring->Contour));
assert(signedArea(rings.back()) < 0);
if (!data_) {
// This is a 404 response. We're treating these as empty tiles.
workRequest.reset();
availableData = DataAvailability::All;
buckets.clear();
redoPlacement();
observer->onTileLoaded(*this, true);
return;
}
// PolyNodes may be nested in the case of a polygon inside a hole.
for (auto * ring : polynode->Childs) {
for (auto * subRing : ring->Childs) {
processPolynodeBranch(subRing, rings);
// Mark the tile as pending again if it was complete before to prevent signaling a complete
// state despite pending parse operations.
if (availableData == DataAvailability::All) {
availableData = DataAvailability::Some;
}
// Kick off a fresh parse of this tile. This happens when the tile is new, or
// when tile data changed. Replacing the workdRequest will cancel a pending work
// request in case there is one.
workRequest.reset();
workRequest = worker.parseGeometryTile(tileWorker, style.getLayers(), std::move(data_), targetConfig, [this, config = targetConfig] (TileParseResult result) {
workRequest.reset();
if (result.is<TileParseResultData>()) {
auto& resultBuckets = result.get<TileParseResultData>();
availableData = resultBuckets.complete ? DataAvailability::All : DataAvailability::Some;
// 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.
buckets = std::move(resultBuckets.buckets);
if (isComplete()) {
featureIndex = std::move(resultBuckets.featureIndex);
data = std::move(resultBuckets.tileData);
}
redoPlacement();
observer->onTileLoaded(*this, true);
} else {
availableData = DataAvailability::All;
observer->onTileError(*this, result.get<std::exception_ptr>());
}
}
});
}
GeometryCollection fixupPolygons(const GeometryCollection& rings) {
ClipperLib::Clipper clipper;
clipper.StrictlySimple(true);
for (const auto& ring : rings) {
clipper.AddPath(toClipperPath(ring), ClipperLib::ptSubject, true);
}
ClipperLib::PolyTree polygons;
clipper.Execute(ClipperLib::ctUnion, polygons, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd);
clipper.Clear();
GeometryCollection result;
for (auto * polynode : polygons.Childs) {
processPolynodeBranch(polynode, result);
}
return result;
GeometryTile::~GeometryTile() {
cancel();
}
std::vector<GeometryCollection> classifyRings(const GeometryCollection& rings) {
std::vector<GeometryCollection> polygons;
std::size_t len = rings.size();
if (len <= 1) {
polygons.push_back(rings);
return polygons;
bool GeometryTile::parsePending() {
if (workRequest) {
// There's already parsing or placement going on.
return false;
}
GeometryCollection polygon;
int8_t ccw = 0;
workRequest.reset();
workRequest = worker.parsePendingGeometryTileLayers(tileWorker, targetConfig, [this, config = targetConfig] (TileParseResult result) {
workRequest.reset();
for (std::size_t i = 0; i < len; i++) {
double area = signedArea(rings[i]);
if (result.is<TileParseResultData>()) {
auto& resultBuckets = result.get<TileParseResultData>();
availableData = resultBuckets.complete ? DataAvailability::All : DataAvailability::Some;
if (area == 0)
continue;
// 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);
}
if (ccw == 0)
ccw = (area < 0 ? -1 : 1);
// 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;
if (ccw == (area < 0 ? -1 : 1) && !polygon.empty()) {
polygons.push_back(polygon);
polygon.clear();
if (isComplete()) {
featureIndex = std::move(resultBuckets.featureIndex);
data = std::move(resultBuckets.tileData);
}
redoPlacement();
observer->onTileLoaded(*this, false);
} else {
availableData = DataAvailability::All;
observer->onTileError(*this, result.get<std::exception_ptr>());
}
});
return true;
}
Bucket* GeometryTile::getBucket(const style::Layer& layer) {
const auto it = buckets.find(layer.baseImpl->bucketName());
if (it == buckets.end()) {
return nullptr;
}
assert(it->second);
return it->second.get();
}
void GeometryTile::redoPlacement(const PlacementConfig newConfig) {
targetConfig = newConfig;
redoPlacement();
}
void GeometryTile::redoPlacement() {
// Don't start a new placement request when the current one hasn't completed yet, or when
// we are parsing buckets.
if (workRequest || targetConfig == placedConfig) {
return;
}
workRequest = worker.redoPlacement(tileWorker, buckets, targetConfig, [this, config = targetConfig](std::unique_ptr<CollisionTile> collisionTile) {
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();
}
polygon.push_back(rings[i]);
}
if (featureIndex) {
featureIndex->setCollisionTile(std::move(collisionTile));
}
if (!polygon.empty())
polygons.push_back(polygon);
return polygons;
// The target configuration could have changed since we started placement. In this case,
// we're starting another placement run.
if (placedConfig != targetConfig) {
redoPlacement();
} else {
observer->onNeedsRepaint();
}
});
}
void limitHoles(GeometryCollection& polygon, uint32_t maxHoles) {
if (polygon.size() > 1 + maxHoles) {
std::nth_element(polygon.begin() + 1,
polygon.begin() + 1 + maxHoles,
polygon.end(),
[] (const auto& a, const auto& b) {
return signedArea(a) > signedArea(b);
});
polygon.resize(1 + maxHoles);
}
void GeometryTile::queryRenderedFeatures(
std::unordered_map<std::string, std::vector<Feature>>& result,
const GeometryCoordinates& queryGeometry,
const TransformState& transformState,
const optional<std::vector<std::string>>& layerIDs) {
if (!featureIndex || !data) return;
featureIndex->query(result,
{ queryGeometry },
transformState.getAngle(),
util::tileSize * id.overscaleFactor(),
std::pow(2, transformState.getZoom() - id.overscaledZ),
layerIDs,
*data,
id.canonical,
style);
}
static Feature::geometry_type convertGeometry(const GeometryTileFeature& geometryTileFeature, const CanonicalTileID& tileID) {
const double size = util::EXTENT * std::pow(2, tileID.z);
const double x0 = util::EXTENT * tileID.x;
const double y0 = util::EXTENT * tileID.y;
auto tileCoordinatesToLatLng = [&] (const Point<int16_t>& p) {
double y2 = 180 - (p.y + y0) * 360 / size;
return Point<double>(
(p.x + x0) * 360 / size - 180,
360.0 / M_PI * std::atan(std::exp(y2 * M_PI / 180)) - 90.0
);
};
GeometryCollection geometries = geometryTileFeature.getGeometries();
switch (geometryTileFeature.getType()) {
case FeatureType::Unknown: {
assert(false);
return Point<double>(NAN, NAN);
}
case FeatureType::Point: {
MultiPoint<double> multiPoint;
for (const auto& p : geometries.at(0)) {
multiPoint.push_back(tileCoordinatesToLatLng(p));
}
if (multiPoint.size() == 1) {
return multiPoint[0];
} else {
return multiPoint;
}
}
case FeatureType::LineString: {
MultiLineString<double> multiLineString;
for (const auto& g : geometries) {
LineString<double> lineString;
for (const auto& p : g) {
lineString.push_back(tileCoordinatesToLatLng(p));
}
multiLineString.push_back(std::move(lineString));
}
if (multiLineString.size() == 1) {
return multiLineString[0];
} else {
return multiLineString;
}
}
case FeatureType::Polygon: {
MultiPolygon<double> multiPolygon;
for (const auto& pg : classifyRings(geometries)) {
Polygon<double> polygon;
for (const auto& r : pg) {
LinearRing<double> linearRing;
for (const auto& p : r) {
linearRing.push_back(tileCoordinatesToLatLng(p));
}
polygon.push_back(std::move(linearRing));
}
multiPolygon.push_back(std::move(polygon));
}
if (multiPolygon.size() == 1) {
return multiPolygon[0];
} else {
return multiPolygon;
}
}
}
// Unreachable, but placate GCC.
return Point<double>();
}
Feature convertFeature(const GeometryTileFeature& geometryTileFeature, const CanonicalTileID& tileID) {
Feature feature { convertGeometry(geometryTileFeature, tileID) };
feature.properties = geometryTileFeature.getProperties();
feature.id = geometryTileFeature.getID();
return feature;
void GeometryTile::cancel() {
obsolete = true;
workRequest.reset();
}
} // namespace mbgl

View File

@@ -1,83 +1,78 @@
#pragma once
#include <mbgl/util/geometry.hpp>
#include <mbgl/tile/tile.hpp>
#include <mbgl/tile/tile_worker.hpp>
#include <mbgl/text/placement_config.hpp>
#include <mbgl/util/atomic.hpp>
#include <mbgl/util/feature.hpp>
#include <mbgl/util/chrono.hpp>
#include <mbgl/util/ptr.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/optional.hpp>
#include <mbgl/util/variant.hpp>
#include <mbgl/util/constants.hpp>
#include <cstdint>
#include <string>
#include <vector>
#include <memory>
#include <unordered_map>
#include <functional>
namespace mbgl {
enum class FeatureType : uint8_t {
Unknown = 0,
Point = 1,
LineString = 2,
Polygon = 3
};
class AsyncRequest;
class GeometryTileData;
class FeatureIndex;
class CanonicalTileID;
namespace style {
class Style;
}
// Normalized vector tile coordinates.
// Each geometry coordinate represents a point in a bidimensional space,
// varying from -V...0...+V, where V is the maximum extent applicable.
using GeometryCoordinate = Point<int16_t>;
class GeometryCoordinates : public std::vector<GeometryCoordinate> {
class GeometryTile : public Tile {
public:
using coordinate_type = int16_t;
using std::vector<GeometryCoordinate>::vector;
GeometryTile(const OverscaledTileID&,
std::string sourceID,
style::Style&,
const MapMode);
~GeometryTile();
void setError(std::exception_ptr err);
void setData(std::unique_ptr<GeometryTileData>,
optional<Timestamp> modified_,
optional<Timestamp> expires_);
Bucket* getBucket(const style::Layer&) override;
bool parsePending() override;
void redoPlacement(PlacementConfig) override;
void queryRenderedFeatures(
std::unordered_map<std::string, std::vector<Feature>>& result,
const GeometryCoordinates& queryGeometry,
const TransformState&,
const optional<std::vector<std::string>>& layerIDs) override;
void cancel() override;
private:
void redoPlacement();
style::Style& style;
Worker& worker;
TileWorker tileWorker;
std::unique_ptr<AsyncRequest> workRequest;
// 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;
std::unique_ptr<FeatureIndex> featureIndex;
std::unique_ptr<const GeometryTileData> data;
// 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;
// Used to signal the worker that it should abandon parsing this tile as soon as possible.
util::Atomic<bool> obsolete { false };
};
class GeometryCollection : public std::vector<GeometryCoordinates> {
public:
using coordinate_type = int16_t;
using std::vector<GeometryCoordinates>::vector;
};
class GeometryTileFeature : private util::noncopyable {
public:
virtual ~GeometryTileFeature() = default;
virtual FeatureType getType() const = 0;
virtual optional<Value> getValue(const std::string& key) const = 0;
virtual Feature::property_map getProperties() const { return Feature::property_map(); }
virtual optional<uint64_t> getID() const { return {}; }
virtual GeometryCollection getGeometries() const = 0;
};
class GeometryTileLayer : private util::noncopyable {
public:
virtual ~GeometryTileLayer() = default;
virtual std::size_t featureCount() const = 0;
virtual util::ptr<const GeometryTileFeature> getFeature(std::size_t) const = 0;
virtual std::string getName() const = 0;
};
class GeometryTile : private util::noncopyable {
public:
virtual ~GeometryTile() = default;
virtual util::ptr<GeometryTileLayer> getLayer(const std::string&) const = 0;
};
// classifies an array of rings into polygons with outer rings and holes
std::vector<GeometryCollection> classifyRings(const GeometryCollection&);
// Truncate polygon to the largest `maxHoles` inner rings by area.
void limitHoles(GeometryCollection&, uint32_t maxHoles);
// convert from GeometryTileFeature to Feature (eventually we should eliminate GeometryTileFeature)
Feature convertFeature(const GeometryTileFeature&, const CanonicalTileID&);
// Fix up possibly-non-V2-compliant polygon geometry using angus clipper.
// The result is guaranteed to have correctly wound, strictly simple rings.
GeometryCollection fixupPolygons(const GeometryCollection&);
} // namespace mbgl

View File

@@ -1,206 +1,210 @@
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/tile/tile_data_observer.hpp>
#include <mbgl/tile/tile_source.hpp>
#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/style/layer_impl.hpp>
#include <mbgl/util/worker.hpp>
#include <mbgl/util/work_request.hpp>
#include <mbgl/style/style.hpp>
#include <mbgl/storage/file_source.hpp>
#include <mbgl/geometry/feature_index.hpp>
#include <mbgl/text/collision_tile.hpp>
#include <mbgl/map/transform_state.hpp>
#include <mbgl/tile/tile_id.hpp>
#include <clipper/clipper.hpp>
namespace mbgl {
GeometryTileData::GeometryTileData(const OverscaledTileID& id_,
std::string sourceID,
style::Style& style_,
const MapMode mode_)
: TileData(id_),
style(style_),
worker(style_.workers),
tileWorker(id_,
sourceID,
*style_.spriteStore,
*style_.glyphAtlas,
*style_.glyphStore,
obsolete,
mode_) {
}
static double signedArea(const GeometryCoordinates& ring) {
double sum = 0;
void GeometryTileData::setError(std::exception_ptr err) {
observer->onTileError(*this, err);
}
void GeometryTileData::setData(std::unique_ptr<GeometryTile> tile,
optional<Timestamp> modified_,
optional<Timestamp> expires_) {
modified = modified_;
expires = expires_;
if (!tile) {
// This is a 404 response. We're treating these as empty tiles.
workRequest.reset();
availableData = DataAvailability::All;
buckets.clear();
redoPlacement();
observer->onTileLoaded(*this, true);
return;
for (std::size_t i = 0, len = ring.size(), j = len - 1; i < len; j = i++) {
const GeometryCoordinate& p1 = ring[i];
const GeometryCoordinate& p2 = ring[j];
sum += (p2.x - p1.x) * (p1.y + p2.y);
}
// Mark the tile as pending again if it was complete before to prevent signaling a complete
// state despite pending parse operations.
if (availableData == DataAvailability::All) {
availableData = DataAvailability::Some;
return sum;
}
static ClipperLib::Path toClipperPath(const GeometryCoordinates& ring) {
ClipperLib::Path result;
result.reserve(ring.size());
for (const auto& p : ring) {
result.emplace_back(p.x, p.y);
}
return result;
}
static GeometryCoordinates fromClipperPath(const ClipperLib::Path& path) {
GeometryCoordinates result;
result.reserve(path.size());
for (const auto& p : path) {
using Coordinate = GeometryCoordinates::coordinate_type;
assert(p.x >= std::numeric_limits<Coordinate>::min());
assert(p.x <= std::numeric_limits<Coordinate>::max());
assert(p.y >= std::numeric_limits<Coordinate>::min());
assert(p.y <= std::numeric_limits<Coordinate>::max());
result.emplace_back(Coordinate(p.x), Coordinate(p.y));
}
return result;
}
static void processPolynodeBranch(ClipperLib::PolyNode* polynode, GeometryCollection& rings) {
// Exterior ring.
rings.push_back(fromClipperPath(polynode->Contour));
assert(signedArea(rings.back()) > 0);
// Interior rings.
for (auto * ring : polynode->Childs) {
rings.push_back(fromClipperPath(ring->Contour));
assert(signedArea(rings.back()) < 0);
}
// Kick off a fresh parse of this tile. This happens when the tile is new, or
// when tile data changed. Replacing the workdRequest will cancel a pending work
// request in case there is one.
workRequest.reset();
workRequest = worker.parseGeometryTile(tileWorker, style.getLayers(), std::move(tile), targetConfig, [this, config = targetConfig] (TileParseResult result) {
workRequest.reset();
// PolyNodes may be nested in the case of a polygon inside a hole.
for (auto * ring : polynode->Childs) {
for (auto * subRing : ring->Childs) {
processPolynodeBranch(subRing, rings);
}
}
}
if (result.is<TileParseResultData>()) {
auto& resultBuckets = result.get<TileParseResultData>();
availableData = resultBuckets.complete ? DataAvailability::All : DataAvailability::Some;
GeometryCollection fixupPolygons(const GeometryCollection& rings) {
ClipperLib::Clipper clipper;
clipper.StrictlySimple(true);
// 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 (const auto& ring : rings) {
clipper.AddPath(toClipperPath(ring), ClipperLib::ptSubject, true);
}
// Move over all buckets we received in this parse request, potentially overwriting
// existing buckets in case we got a refresh parse.
buckets = std::move(resultBuckets.buckets);
ClipperLib::PolyTree polygons;
clipper.Execute(ClipperLib::ctUnion, polygons, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd);
clipper.Clear();
if (isComplete()) {
featureIndex = std::move(resultBuckets.featureIndex);
geometryTile = std::move(resultBuckets.geometryTile);
GeometryCollection result;
for (auto * polynode : polygons.Childs) {
processPolynodeBranch(polynode, result);
}
return result;
}
std::vector<GeometryCollection> classifyRings(const GeometryCollection& rings) {
std::vector<GeometryCollection> polygons;
std::size_t len = rings.size();
if (len <= 1) {
polygons.push_back(rings);
return polygons;
}
GeometryCollection polygon;
int8_t ccw = 0;
for (std::size_t i = 0; i < len; i++) {
double area = signedArea(rings[i]);
if (area == 0)
continue;
if (ccw == 0)
ccw = (area < 0 ? -1 : 1);
if (ccw == (area < 0 ? -1 : 1) && !polygon.empty()) {
polygons.push_back(polygon);
polygon.clear();
}
polygon.push_back(rings[i]);
}
if (!polygon.empty())
polygons.push_back(polygon);
return polygons;
}
void limitHoles(GeometryCollection& polygon, uint32_t maxHoles) {
if (polygon.size() > 1 + maxHoles) {
std::nth_element(polygon.begin() + 1,
polygon.begin() + 1 + maxHoles,
polygon.end(),
[] (const auto& a, const auto& b) {
return signedArea(a) > signedArea(b);
});
polygon.resize(1 + maxHoles);
}
}
static Feature::geometry_type convertGeometry(const GeometryTileFeature& geometryTileFeature, const CanonicalTileID& tileID) {
const double size = util::EXTENT * std::pow(2, tileID.z);
const double x0 = util::EXTENT * tileID.x;
const double y0 = util::EXTENT * tileID.y;
auto tileCoordinatesToLatLng = [&] (const Point<int16_t>& p) {
double y2 = 180 - (p.y + y0) * 360 / size;
return Point<double>(
(p.x + x0) * 360 / size - 180,
360.0 / M_PI * std::atan(std::exp(y2 * M_PI / 180)) - 90.0
);
};
GeometryCollection geometries = geometryTileFeature.getGeometries();
switch (geometryTileFeature.getType()) {
case FeatureType::Unknown: {
assert(false);
return Point<double>(NAN, NAN);
}
case FeatureType::Point: {
MultiPoint<double> multiPoint;
for (const auto& p : geometries.at(0)) {
multiPoint.push_back(tileCoordinatesToLatLng(p));
}
redoPlacement();
observer->onTileLoaded(*this, true);
} else {
availableData = DataAvailability::All;
observer->onTileError(*this, result.get<std::exception_ptr>());
}
});
}
GeometryTileData::~GeometryTileData() {
cancel();
}
bool GeometryTileData::parsePending() {
if (workRequest) {
// There's already parsing or placement going on.
return false;
}
workRequest.reset();
workRequest = worker.parsePendingGeometryTileLayers(tileWorker, targetConfig, [this, config = targetConfig] (TileParseResult result) {
workRequest.reset();
if (result.is<TileParseResultData>()) {
auto& resultBuckets = result.get<TileParseResultData>();
availableData = resultBuckets.complete ? DataAvailability::All : DataAvailability::Some;
// 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);
if (multiPoint.size() == 1) {
return multiPoint[0];
} else {
return multiPoint;
}
}
// 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;
if (isComplete()) {
featureIndex = std::move(resultBuckets.featureIndex);
geometryTile = std::move(resultBuckets.geometryTile);
case FeatureType::LineString: {
MultiLineString<double> multiLineString;
for (const auto& g : geometries) {
LineString<double> lineString;
for (const auto& p : g) {
lineString.push_back(tileCoordinatesToLatLng(p));
}
multiLineString.push_back(std::move(lineString));
}
if (multiLineString.size() == 1) {
return multiLineString[0];
} else {
return multiLineString;
}
redoPlacement();
observer->onTileLoaded(*this, false);
} else {
availableData = DataAvailability::All;
observer->onTileError(*this, result.get<std::exception_ptr>());
}
});
return true;
}
Bucket* GeometryTileData::getBucket(const style::Layer& layer) {
const auto it = buckets.find(layer.baseImpl->bucketName());
if (it == buckets.end()) {
return nullptr;
case FeatureType::Polygon: {
MultiPolygon<double> multiPolygon;
for (const auto& pg : classifyRings(geometries)) {
Polygon<double> polygon;
for (const auto& r : pg) {
LinearRing<double> linearRing;
for (const auto& p : r) {
linearRing.push_back(tileCoordinatesToLatLng(p));
}
polygon.push_back(std::move(linearRing));
}
multiPolygon.push_back(std::move(polygon));
}
if (multiPolygon.size() == 1) {
return multiPolygon[0];
} else {
return multiPolygon;
}
}
}
assert(it->second);
return it->second.get();
// Unreachable, but placate GCC.
return Point<double>();
}
void GeometryTileData::redoPlacement(const PlacementConfig newConfig) {
targetConfig = newConfig;
redoPlacement();
}
void GeometryTileData::redoPlacement() {
// Don't start a new placement request when the current one hasn't completed yet, or when
// we are parsing buckets.
if (workRequest || targetConfig == placedConfig) {
return;
}
workRequest = worker.redoPlacement(tileWorker, buckets, targetConfig, [this, config = targetConfig](std::unique_ptr<CollisionTile> collisionTile) {
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();
}
if (featureIndex) {
featureIndex->setCollisionTile(std::move(collisionTile));
}
// The target configuration could have changed since we started placement. In this case,
// we're starting another placement run.
if (placedConfig != targetConfig) {
redoPlacement();
} else {
observer->onNeedsRepaint();
}
});
}
void GeometryTileData::queryRenderedFeatures(
std::unordered_map<std::string, std::vector<Feature>>& result,
const GeometryCoordinates& queryGeometry,
const TransformState& transformState,
const optional<std::vector<std::string>>& layerIDs) {
if (!featureIndex || !geometryTile) return;
featureIndex->query(result,
{ queryGeometry },
transformState.getAngle(),
util::tileSize * id.overscaleFactor(),
std::pow(2, transformState.getZoom() - id.overscaledZ),
layerIDs,
*geometryTile,
id.canonical,
style);
}
void GeometryTileData::cancel() {
obsolete = true;
workRequest.reset();
Feature convertFeature(const GeometryTileFeature& geometryTileFeature, const CanonicalTileID& tileID) {
Feature feature { convertGeometry(geometryTileFeature, tileID) };
feature.properties = geometryTileFeature.getProperties();
feature.id = geometryTileFeature.getID();
return feature;
}
} // namespace mbgl

View File

@@ -1,79 +1,83 @@
#pragma once
#include <mbgl/tile/tile_data.hpp>
#include <mbgl/tile/tile_worker.hpp>
#include <mbgl/text/placement_config.hpp>
#include <mbgl/util/atomic.hpp>
#include <mbgl/util/geometry.hpp>
#include <mbgl/util/feature.hpp>
#include <mbgl/util/chrono.hpp>
#include <mbgl/util/ptr.hpp>
#include <mbgl/util/noncopyable.hpp>
#include <mbgl/util/optional.hpp>
#include <mbgl/util/variant.hpp>
#include <mbgl/util/constants.hpp>
#include <memory>
#include <cstdint>
#include <string>
#include <vector>
#include <unordered_map>
#include <functional>
namespace mbgl {
class AsyncRequest;
class GeometryTile;
class GeometryTileSource;
class FeatureIndex;
namespace style {
class Style;
}
class GeometryTileData : public TileData {
public:
GeometryTileData(const OverscaledTileID&,
std::string sourceID,
style::Style&,
const MapMode);
~GeometryTileData();
void setError(std::exception_ptr err);
void setData(std::unique_ptr<GeometryTile> tile,
optional<Timestamp> modified_,
optional<Timestamp> expires_);
Bucket* getBucket(const style::Layer&) override;
bool parsePending() override;
void redoPlacement(PlacementConfig) override;
void queryRenderedFeatures(
std::unordered_map<std::string, std::vector<Feature>>& result,
const GeometryCoordinates& queryGeometry,
const TransformState&,
const optional<std::vector<std::string>>& layerIDs) override;
void cancel() override;
private:
void redoPlacement();
style::Style& style;
Worker& worker;
TileWorker tileWorker;
std::unique_ptr<AsyncRequest> workRequest;
// 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;
std::unique_ptr<FeatureIndex> featureIndex;
std::unique_ptr<const GeometryTile> geometryTile;
// 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;
// Used to signal the worker that it should abandon parsing this tile as soon as possible.
util::Atomic<bool> obsolete { false };
enum class FeatureType : uint8_t {
Unknown = 0,
Point = 1,
LineString = 2,
Polygon = 3
};
class CanonicalTileID;
// Normalized vector tile coordinates.
// Each geometry coordinate represents a point in a bidimensional space,
// varying from -V...0...+V, where V is the maximum extent applicable.
using GeometryCoordinate = Point<int16_t>;
class GeometryCoordinates : public std::vector<GeometryCoordinate> {
public:
using coordinate_type = int16_t;
using std::vector<GeometryCoordinate>::vector;
};
class GeometryCollection : public std::vector<GeometryCoordinates> {
public:
using coordinate_type = int16_t;
using std::vector<GeometryCoordinates>::vector;
};
class GeometryTileFeature : private util::noncopyable {
public:
virtual ~GeometryTileFeature() = default;
virtual FeatureType getType() const = 0;
virtual optional<Value> getValue(const std::string& key) const = 0;
virtual Feature::property_map getProperties() const { return Feature::property_map(); }
virtual optional<uint64_t> getID() const { return {}; }
virtual GeometryCollection getGeometries() const = 0;
};
class GeometryTileLayer : private util::noncopyable {
public:
virtual ~GeometryTileLayer() = default;
virtual std::size_t featureCount() const = 0;
virtual util::ptr<const GeometryTileFeature> getFeature(std::size_t) const = 0;
virtual std::string getName() const = 0;
};
class GeometryTileData : private util::noncopyable {
public:
virtual ~GeometryTileData() = default;
virtual util::ptr<GeometryTileLayer> getLayer(const std::string&) const = 0;
};
// classifies an array of rings into polygons with outer rings and holes
std::vector<GeometryCollection> classifyRings(const GeometryCollection&);
// Truncate polygon to the largest `maxHoles` inner rings by area.
void limitHoles(GeometryCollection&, uint32_t maxHoles);
// convert from GeometryTileFeature to Feature (eventually we should eliminate GeometryTileFeature)
Feature convertFeature(const GeometryTileFeature&, const CanonicalTileID&);
// Fix up possibly-non-V2-compliant polygon geometry using angus clipper.
// The result is guaranteed to have correctly wound, strictly simple rings.
GeometryCollection fixupPolygons(const GeometryCollection&);
} // namespace mbgl

View File

@@ -1,8 +1,8 @@
#include <mbgl/tile/raster_tile_data.hpp>
#include <mbgl/tile/raster_tile.hpp>
#include <mbgl/tile/tile_observer.hpp>
#include <mbgl/tile/tile_source_impl.hpp>
#include <mbgl/style/source.hpp>
#include <mbgl/style/update_parameters.hpp>
#include <mbgl/tile/tile_data_observer.hpp>
#include <mbgl/tile/tile_source_impl.hpp>
#include <mbgl/storage/resource.hpp>
#include <mbgl/storage/response.hpp>
#include <mbgl/storage/file_source.hpp>
@@ -11,20 +11,20 @@
using namespace mbgl;
RasterTileData::RasterTileData(const OverscaledTileID& id_,
const style::UpdateParameters& parameters,
const Tileset& tileset)
: TileData(id_),
RasterTile::RasterTile(const OverscaledTileID& id_,
const style::UpdateParameters& parameters,
const Tileset& tileset)
: Tile(id_),
texturePool(parameters.texturePool),
worker(parameters.worker),
tileSource(*this, id_, parameters, tileset) {
}
void RasterTileData::setError(std::exception_ptr err) {
void RasterTile::setError(std::exception_ptr err) {
observer->onTileError(*this, err);
}
void RasterTileData::setData(std::shared_ptr<const std::string> data,
void RasterTile::setData(std::shared_ptr<const std::string> data,
optional<Timestamp> modified_,
optional<Timestamp> expires_) {
modified = modified_;
@@ -55,14 +55,14 @@ void RasterTileData::setData(std::shared_ptr<const std::string> data,
});
}
Bucket* RasterTileData::getBucket(const style::Layer&) {
Bucket* RasterTile::getBucket(const style::Layer&) {
return bucket.get();
}
void RasterTileData::setNecessity(Necessity necessity) {
tileSource.setNecessity(static_cast<TileSource<RasterTileData>::Necessity>(necessity));
void RasterTile::setNecessity(Necessity necessity) {
tileSource.setNecessity(static_cast<TileSource<RasterTile>::Necessity>(necessity));
}
void RasterTileData::cancel() {
void RasterTile::cancel() {
workRequest.reset();
}

View File

@@ -1,8 +1,8 @@
#pragma once
#include <mbgl/tile/tile_data.hpp>
#include <mbgl/renderer/raster_bucket.hpp>
#include <mbgl/tile/tile.hpp>
#include <mbgl/tile/tile_source.hpp>
#include <mbgl/renderer/raster_bucket.hpp>
namespace mbgl {
@@ -16,9 +16,9 @@ class Layer;
class UpdateParameters;
}
class RasterTileData : public TileData {
class RasterTile : public Tile {
public:
RasterTileData(const OverscaledTileID&,
RasterTile(const OverscaledTileID&,
const style::UpdateParameters&,
const Tileset&);
@@ -37,7 +37,7 @@ private:
gl::TexturePool& texturePool;
Worker& worker;
TileSource<RasterTileData> tileSource;
TileSource<RasterTile> tileSource;
std::unique_ptr<AsyncRequest> workRequest;
// Contains the Bucket object for the tile. Buckets are render

37
src/mbgl/tile/tile.cpp Normal file
View File

@@ -0,0 +1,37 @@
#include <mbgl/tile/tile.hpp>
#include <mbgl/tile/tile_observer.hpp>
#include <mbgl/renderer/debug_bucket.hpp>
#include <mbgl/util/string.hpp>
namespace mbgl {
static TileObserver nullObserver;
Tile::Tile(const OverscaledTileID& id_)
: id(id_), observer(&nullObserver) {
}
Tile::~Tile() = default;
void Tile::setObserver(TileObserver* observer_) {
observer = observer_;
}
void Tile::setTriedOptional() {
triedOptional = true;
observer->onNeedsRepaint();
}
void Tile::dumpDebugLogs() const {
Log::Info(Event::General, "Tile::id: %s", util::toString(id).c_str());
Log::Info(Event::General, "Tile::renderable: %s", isRenderable() ? "yes" : "no");
Log::Info(Event::General, "Tile::complete: %s", isComplete() ? "yes" : "no");
}
void Tile::queryRenderedFeatures(
std::unordered_map<std::string, std::vector<Feature>>&,
const GeometryCoordinates&,
const TransformState&,
const optional<std::vector<std::string>>&) {}
} // namespace mbgl

View File

@@ -7,7 +7,7 @@
#include <mbgl/tile/tile_id.hpp>
#include <mbgl/renderer/bucket.hpp>
#include <mbgl/text/placement_config.hpp>
#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <string>
#include <memory>
@@ -19,18 +19,18 @@ namespace mbgl {
class Worker;
class DebugBucket;
class TransformState;
class TileDataObserver;
class TileObserver;
namespace style {
class Layer;
}
class TileData : private util::noncopyable {
class Tile : private util::noncopyable {
public:
TileData(const OverscaledTileID&);
virtual ~TileData();
Tile(const OverscaledTileID&);
virtual ~Tile();
void setObserver(TileDataObserver* observer);
void setObserver(TileObserver* observer);
enum class Necessity : bool {
Optional = false,
@@ -91,18 +91,18 @@ protected:
// Still waiting for data to load or parse.
None,
// TileData is partially parsed, some buckets are still waiting for dependencies
// Tile is partially parsed, some buckets are still waiting for dependencies
// to arrive, but it is good for rendering. Partial tiles can also be re-parsed,
// but might remain in the same state if dependencies are still missing.
Some,
// TileData is fully parsed, and all buckets are available if they exist.
// Tile is fully parsed, and all buckets are available if they exist.
All,
};
DataAvailability availableData = DataAvailability::None;
TileDataObserver* observer = nullptr;
TileObserver* observer = nullptr;
};
} // namespace mbgl

View File

@@ -1,5 +1,5 @@
#include <mbgl/tile/tile_cache.hpp>
#include <mbgl/tile/tile_data.hpp>
#include <mbgl/tile/tile.hpp>
#include <cassert>
@@ -17,21 +17,21 @@ void TileCache::setSize(size_t size_) {
assert(orderedKeys.size() <= size);
}
void TileCache::add(const OverscaledTileID& key, std::unique_ptr<TileData> data) {
if (!data->isRenderable() || !size) {
void TileCache::add(const OverscaledTileID& key, std::unique_ptr<Tile> tile) {
if (!tile->isRenderable() || !size) {
return;
}
// insert new or query existing data
if (tiles.emplace(key, std::move(data)).second) {
// remove existing data key
// insert new or query existing tile
if (tiles.emplace(key, std::move(tile)).second) {
// remove existing tile key
orderedKeys.remove(key);
}
// (re-)insert data key as newest
// (re-)insert tile key as newest
orderedKeys.push_back(key);
// purge oldest key/data if necessary
// purge oldest key/tile if necessary
if (orderedKeys.size() > size) {
get(orderedKeys.front());
}
@@ -39,19 +39,19 @@ void TileCache::add(const OverscaledTileID& key, std::unique_ptr<TileData> data)
assert(orderedKeys.size() <= size);
}
std::unique_ptr<TileData> TileCache::get(const OverscaledTileID& key) {
std::unique_ptr<Tile> TileCache::get(const OverscaledTileID& key) {
std::unique_ptr<TileData> data;
std::unique_ptr<Tile> tile;
auto it = tiles.find(key);
if (it != tiles.end()) {
data = std::move(it->second);
tile = std::move(it->second);
tiles.erase(it);
orderedKeys.remove(key);
assert(data->isRenderable());
assert(tile->isRenderable());
}
return data;
return tile;
}
bool TileCache::has(const OverscaledTileID& key) {

View File

@@ -8,7 +8,7 @@
namespace mbgl {
class TileData;
class Tile;
class TileCache {
public:
@@ -16,13 +16,13 @@ public:
void setSize(size_t);
size_t getSize() const { return size; };
void add(const OverscaledTileID& key, std::unique_ptr<TileData> data);
std::unique_ptr<TileData> get(const OverscaledTileID& key);
void add(const OverscaledTileID& key, std::unique_ptr<Tile> data);
std::unique_ptr<Tile> get(const OverscaledTileID& key);
bool has(const OverscaledTileID& key);
void clear();
private:
std::map<OverscaledTileID, std::unique_ptr<TileData>> tiles;
std::map<OverscaledTileID, std::unique_ptr<Tile>> tiles;
std::list<OverscaledTileID> orderedKeys;
size_t size;

View File

@@ -1,37 +0,0 @@
#include <mbgl/tile/tile_data.hpp>
#include <mbgl/tile/tile_data_observer.hpp>
#include <mbgl/renderer/debug_bucket.hpp>
#include <mbgl/util/string.hpp>
namespace mbgl {
static TileDataObserver nullObserver;
TileData::TileData(const OverscaledTileID& id_)
: id(id_), observer(&nullObserver) {
}
TileData::~TileData() = default;
void TileData::setObserver(TileDataObserver* observer_) {
observer = observer_;
}
void TileData::setTriedOptional() {
triedOptional = true;
observer->onNeedsRepaint();
}
void TileData::dumpDebugLogs() const {
Log::Info(Event::General, "TileData::id: %s", util::toString(id).c_str());
Log::Info(Event::General, "TileData::renderable: %s", isRenderable() ? "yes" : "no");
Log::Info(Event::General, "TileData::complete: %s", isComplete() ? "yes" : "no");
}
void TileData::queryRenderedFeatures(
std::unordered_map<std::string, std::vector<Feature>>&,
const GeometryCoordinates&,
const TransformState&,
const optional<std::vector<std::string>>&) {}
} // namespace mbgl

View File

@@ -1,18 +0,0 @@
#pragma once
#include <exception>
namespace mbgl {
class TileData;
class TileDataObserver {
public:
virtual ~TileDataObserver() = default;
virtual void onTileLoaded(TileData&, bool /*isNewTile*/) {}
virtual void onTileError(TileData&, std::exception_ptr) {}
virtual void onNeedsRepaint() {}
};
} // namespace mbgl

View File

@@ -0,0 +1,18 @@
#pragma once
#include <exception>
namespace mbgl {
class Tile;
class TileObserver {
public:
virtual ~TileObserver() = default;
virtual void onTileLoaded(Tile&, bool /*isNewTile*/) {}
virtual void onTileError(Tile&, std::exception_ptr) {}
virtual void onNeedsRepaint() {}
};
} // namespace mbgl

View File

@@ -58,7 +58,7 @@ private:
void loadedData(const Response&);
void loadRequired();
T& tileData;
T& tile;
Necessity necessity;
Resource resource;
FileSource& fileSource;

View File

@@ -10,11 +10,11 @@
namespace mbgl {
template <typename T>
TileSource<T>::TileSource(T& tileData_,
TileSource<T>::TileSource(T& tile_,
const OverscaledTileID& id,
const style::UpdateParameters& parameters,
const Tileset& tileset)
: tileData(tileData_),
: tile(tile_),
necessity(Necessity::Optional),
resource(Resource::tile(
tileset.tiles.at(0),
@@ -51,7 +51,7 @@ void TileSource<T>::loadOptional() {
request = fileSource.request(resource, [this](Response res) {
request.reset();
tileData.setTriedOptional();
tile.setTriedOptional();
if (res.error && res.error->reason == Response::Error::Reason::NotFound) {
// When the optional request could not be satisfied, don't treat it as an error.
@@ -86,16 +86,16 @@ void TileSource<T>::makeOptional() {
template <typename T>
void TileSource<T>::loadedData(const Response& res) {
if (res.error && res.error->reason != Response::Error::Reason::NotFound) {
tileData.setError(std::make_exception_ptr(std::runtime_error(res.error->message)));
tile.setError(std::make_exception_ptr(std::runtime_error(res.error->message)));
} else if (res.notModified) {
resource.priorExpires = res.expires;
// Do not notify the TileData object; when we get this message, it already has the current
// Do not notify the tile; when we get this message, it already has the current
// version of the data.
} else {
resource.priorModified = res.modified;
resource.priorExpires = res.expires;
resource.priorEtag = res.etag;
tileData.setData(res.noContent ? nullptr : res.data, res.modified, res.expires);
tile.setData(res.noContent ? nullptr : res.data, res.modified, res.expires);
}
}

View File

@@ -1,6 +1,6 @@
#include <mbgl/text/collision_tile.hpp>
#include <mbgl/tile/tile_worker.hpp>
#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/style/bucket_parameters.hpp>
#include <mbgl/style/layers/background_layer.hpp>
#include <mbgl/style/layers/custom_layer.hpp>
@@ -40,14 +40,14 @@ TileWorker::~TileWorker() {
}
TileParseResult TileWorker::parseAllLayers(std::vector<std::unique_ptr<Layer>> layers_,
std::unique_ptr<const GeometryTile> geometryTile_,
std::unique_ptr<const GeometryTileData> tileData_,
PlacementConfig config) {
// We're doing a fresh parse of the tile, because the underlying data has changed.
pending.clear();
placementPending.clear();
partialParse = false;
featureIndex = std::make_unique<FeatureIndex>();
geometryTile = std::move(geometryTile_);
tileData = std::move(tileData_);
// Store the layers for use in redoPlacement.
layers = std::move(layers_);
@@ -98,7 +98,7 @@ TileParseResult TileWorker::prepareResult(const PlacementConfig& config) {
if (result.complete) {
featureIndex->setCollisionTile(placeLayers(config));
result.featureIndex = std::move(featureIndex);
result.geometryTile = std::move(geometryTile);
result.tileData = std::move(tileData);
}
return std::move(result);
@@ -147,7 +147,7 @@ void TileWorker::parseLayer(const Layer* layer) {
return;
}
auto geometryLayer = geometryTile->getLayer(layer->baseImpl->sourceLayer);
auto geometryLayer = tileData->getLayer(layer->baseImpl->sourceLayer);
if (!geometryLayer) {
// The layer specified in the bucket does not exist. Do nothing.
if (debug::tileParseWarnings) {

View File

@@ -18,7 +18,7 @@
namespace mbgl {
class CollisionTile;
class GeometryTile;
class GeometryTileData;
class SpriteStore;
class GlyphAtlas;
class GlyphStore;
@@ -36,7 +36,7 @@ public:
bool complete = false;
std::unordered_map<std::string, std::unique_ptr<Bucket>> buckets;
std::unique_ptr<FeatureIndex> featureIndex;
std::unique_ptr<const GeometryTile> geometryTile;
std::unique_ptr<const GeometryTileData> tileData;
};
using TileParseResult = variant<
@@ -55,7 +55,7 @@ public:
~TileWorker();
TileParseResult parseAllLayers(std::vector<std::unique_ptr<style::Layer>>,
std::unique_ptr<const GeometryTile> geometryTile,
std::unique_ptr<const GeometryTileData> tileData,
PlacementConfig);
TileParseResult parsePendingLayers(PlacementConfig);
@@ -83,7 +83,7 @@ private:
std::vector<std::unique_ptr<style::Layer>> layers;
std::unique_ptr<FeatureIndex> featureIndex;
std::unique_ptr<const GeometryTile> geometryTile;
std::unique_ptr<const GeometryTileData> tileData;
// Contains buckets that we couldn't parse so far due to missing resources.
// They will be attempted on subsequent parses.

View File

@@ -1,6 +1,6 @@
#include <mbgl/tile/vector_tile.hpp>
#include <mbgl/tile/tile_source_impl.hpp>
#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/style/update_parameters.hpp>
#include <protozero/pbf_reader.hpp>
@@ -44,7 +44,7 @@ public:
std::string getName() const override;
private:
friend class VectorTile;
friend class VectorTileData;
friend class VectorTileFeature;
std::string name;
@@ -56,9 +56,9 @@ private:
std::vector<protozero::pbf_reader> features;
};
class VectorTile : public GeometryTile {
class VectorTileData : public GeometryTileData {
public:
VectorTile(std::shared_ptr<const std::string> data);
VectorTileData(std::shared_ptr<const std::string> data);
util::ptr<GeometryTileLayer> getLayer(const std::string&) const override;
@@ -68,22 +68,22 @@ private:
mutable std::map<std::string, util::ptr<GeometryTileLayer>> layers;
};
VectorTileData::VectorTileData(const OverscaledTileID& id_,
std::string sourceID,
const style::UpdateParameters& parameters,
const Tileset& tileset)
: GeometryTileData(id_, sourceID, parameters.style, parameters.mode),
VectorTile::VectorTile(const OverscaledTileID& id_,
std::string sourceID,
const style::UpdateParameters& parameters,
const Tileset& tileset)
: GeometryTile(id_, sourceID, parameters.style, parameters.mode),
tileSource(*this, id_, parameters, tileset) {
}
void VectorTileData::setNecessity(Necessity necessity) {
tileSource.setNecessity(static_cast<TileSource<VectorTileData>::Necessity>(necessity));
void VectorTile::setNecessity(Necessity necessity) {
tileSource.setNecessity(static_cast<TileSource<VectorTile>::Necessity>(necessity));
}
void VectorTileData::setData(std::shared_ptr<const std::string> data,
optional<Timestamp> modified,
optional<Timestamp> expires) {
GeometryTileData::setData(data ? std::make_unique<VectorTile>(data) : nullptr, modified, expires);
void VectorTile::setData(std::shared_ptr<const std::string> data_,
optional<Timestamp> modified_,
optional<Timestamp> expires_) {
GeometryTile::setData(data_ ? std::make_unique<VectorTileData>(data_) : nullptr, modified_, expires_);
}
Value parseValue(protozero::pbf_reader data) {
@@ -236,11 +236,11 @@ GeometryCollection VectorTileFeature::getGeometries() const {
return fixupPolygons(lines);
}
VectorTile::VectorTile(std::shared_ptr<const std::string> data_)
VectorTileData::VectorTileData(std::shared_ptr<const std::string> data_)
: data(std::move(data_)) {
}
util::ptr<GeometryTileLayer> VectorTile::getLayer(const std::string& name) const {
util::ptr<GeometryTileLayer> VectorTileData::getLayer(const std::string& name) const {
if (!parsed) {
parsed = true;
protozero::pbf_reader tile_pbf(*data);

View File

@@ -1,6 +1,6 @@
#pragma once
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/tile/tile_source.hpp>
namespace mbgl {
@@ -11,12 +11,12 @@ namespace style {
class UpdateParameters;
}
class VectorTileData : public GeometryTileData {
class VectorTile : public GeometryTile {
public:
VectorTileData(const OverscaledTileID&,
std::string sourceID,
const style::UpdateParameters&,
const Tileset&);
VectorTile(const OverscaledTileID&,
std::string sourceID,
const style::UpdateParameters&,
const Tileset&);
void setNecessity(Necessity) final;
void setData(std::shared_ptr<const std::string> data,
@@ -24,7 +24,7 @@ public:
optional<Timestamp> expires);
private:
TileSource<VectorTileData> tileSource;
TileSource<VectorTile> tileSource;
};
} // namespace mbgl

View File

@@ -1,6 +1,6 @@
#pragma once
#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
namespace mbgl {
namespace util {

View File

@@ -3,7 +3,7 @@
#include <mbgl/util/work_request.hpp>
#include <mbgl/platform/platform.hpp>
#include <mbgl/renderer/raster_bucket.hpp>
#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/style/layer.hpp>
#include <mbgl/text/collision_tile.hpp>
@@ -31,11 +31,11 @@ public:
void parseGeometryTile(TileWorker* worker,
std::vector<std::unique_ptr<style::Layer>> layers,
std::unique_ptr<GeometryTile> tile,
std::unique_ptr<GeometryTileData> tileData,
PlacementConfig config,
std::function<void(TileParseResult)> callback) {
try {
callback(worker->parseAllLayers(std::move(layers), std::move(tile), config));
callback(worker->parseAllLayers(std::move(layers), std::move(tileData), config));
} catch (...) {
callback(std::current_exception());
}
@@ -80,12 +80,12 @@ Worker::parseRasterTile(std::unique_ptr<RasterBucket> bucket,
std::unique_ptr<AsyncRequest>
Worker::parseGeometryTile(TileWorker& worker,
std::vector<std::unique_ptr<style::Layer>> layers,
std::unique_ptr<GeometryTile> tile,
std::unique_ptr<GeometryTileData> tileData,
PlacementConfig config,
std::function<void(TileParseResult)> callback) {
current = (current + 1) % threads.size();
return threads[current]->invokeWithCallback(&Worker::Impl::parseGeometryTile, callback, &worker,
std::move(layers), std::move(tile), config);
std::move(layers), std::move(tileData), config);
}
std::unique_ptr<AsyncRequest>

View File

@@ -41,7 +41,7 @@ public:
Request parseGeometryTile(TileWorker&,
std::vector<std::unique_ptr<style::Layer>>,
std::unique_ptr<GeometryTile>,
std::unique_ptr<GeometryTileData>,
PlacementConfig,
std::function<void(TileParseResult)> callback);

View File

@@ -3,7 +3,7 @@
#include <mbgl/style/filter.hpp>
#include <mbgl/style/filter_evaluator.hpp>
#include <mbgl/style/parser.hpp>
#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <rapidjson/document.h>

View File

@@ -56,7 +56,7 @@
'math/minmax.cpp',
'math/clamp.cpp',
'tile/geometry_tile.cpp',
'tile/geometry_tile_data.cpp',
'tile/tile_id.cpp',
'storage/offline.cpp',

View File

@@ -1,9 +1,9 @@
#include <mbgl/test/util.hpp>
#include <mbgl/tile/geometry_tile.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
using namespace mbgl;
TEST(GeometryTile, classifyRings1) {
TEST(GeometryTileData, classifyRings1) {
std::vector<GeometryCollection> polygons = classifyRings({
{ {0, 0}, {0, 40}, {40, 40}, {40, 0}, {0, 0} }
});
@@ -14,7 +14,7 @@ TEST(GeometryTile, classifyRings1) {
ASSERT_EQ(polygons[0].size(), 1u);
}
TEST(GeometryTile, classifyRings2) {
TEST(GeometryTileData, classifyRings2) {
std::vector<GeometryCollection> polygons = classifyRings({
{ {0, 0}, {0, 40}, {40, 40}, {40, 0}, {0, 0} },
{ {10, 10}, {20, 10}, {20, 20}, {10, 10} }
@@ -26,7 +26,7 @@ TEST(GeometryTile, classifyRings2) {
ASSERT_EQ(polygons[0].size(), 2u);
}
TEST(GeometryTile, limitHoles1) {
TEST(GeometryTileData, limitHoles1) {
GeometryCollection polygon = {
{ {0, 0}, {0, 40}, {40, 40}, {40, 0}, {0, 0} },
{ {30, 30}, {32, 30}, {32, 32}, {30, 30} },
@@ -43,7 +43,7 @@ TEST(GeometryTile, limitHoles1) {
ASSERT_EQ(polygon[1][0].x, 10);
}
TEST(GeometryTile, limitHoles2) {
TEST(GeometryTileData, limitHoles2) {
GeometryCollection polygon = {
{ {0, 0}, {0, 40}, {40, 40}, {40, 0}, {0, 0} },
{ {10, 10}, {20, 10}, {20, 20}, {10, 10} },