diff options
author | Thiago Marcos P. Santos <tmpsantos@gmail.com> | 2017-08-07 19:19:32 +0300 |
---|---|---|
committer | Thiago Marcos P. Santos <tmpsantos@gmail.com> | 2017-08-09 18:02:46 +0300 |
commit | c53896caefc96a8c18ab746026330ddc4fc0338e (patch) | |
tree | 8f562b0c416d6c99f7b565e58b758701f6081677 /src/mbgl/tile | |
parent | 9ecbe3642fb4a53b558598239b59bf1d0224c25b (diff) | |
download | qtlocation-mapboxgl-c53896caefc96a8c18ab746026330ddc4fc0338e.tar.gz |
Bump Mapbox GL Nativeqt-v1.1.0
mapbox-gl-native @ edd7948893fcd40a24d96b790e21d3dd028cecbe
Diffstat (limited to 'src/mbgl/tile')
-rw-r--r-- | src/mbgl/tile/geojson_tile.cpp | 83 | ||||
-rw-r--r-- | src/mbgl/tile/geojson_tile.hpp | 15 | ||||
-rw-r--r-- | src/mbgl/tile/geometry_tile.cpp | 202 | ||||
-rw-r--r-- | src/mbgl/tile/geometry_tile.hpp | 93 | ||||
-rw-r--r-- | src/mbgl/tile/geometry_tile_data.cpp | 71 | ||||
-rw-r--r-- | src/mbgl/tile/geometry_tile_data.hpp | 16 | ||||
-rw-r--r-- | src/mbgl/tile/geometry_tile_worker.cpp | 189 | ||||
-rw-r--r-- | src/mbgl/tile/geometry_tile_worker.hpp | 33 | ||||
-rw-r--r-- | src/mbgl/tile/raster_tile.cpp | 30 | ||||
-rw-r--r-- | src/mbgl/tile/raster_tile.hpp | 15 | ||||
-rw-r--r-- | src/mbgl/tile/raster_tile_worker.cpp | 4 | ||||
-rw-r--r-- | src/mbgl/tile/tile.cpp | 10 | ||||
-rw-r--r-- | src/mbgl/tile/tile.hpp | 61 | ||||
-rw-r--r-- | src/mbgl/tile/tile_id.hpp | 37 | ||||
-rw-r--r-- | src/mbgl/tile/tile_id_io.cpp | 5 | ||||
-rw-r--r-- | src/mbgl/tile/tile_loader.hpp | 7 | ||||
-rw-r--r-- | src/mbgl/tile/tile_loader_impl.hpp | 4 | ||||
-rw-r--r-- | src/mbgl/tile/vector_tile.cpp | 284 | ||||
-rw-r--r-- | src/mbgl/tile/vector_tile.hpp | 7 | ||||
-rw-r--r-- | src/mbgl/tile/vector_tile_data.cpp | 89 | ||||
-rw-r--r-- | src/mbgl/tile/vector_tile_data.hpp | 54 |
21 files changed, 761 insertions, 548 deletions
diff --git a/src/mbgl/tile/geojson_tile.cpp b/src/mbgl/tile/geojson_tile.cpp index a2f453f03d..5d8339d775 100644 --- a/src/mbgl/tile/geojson_tile.cpp +++ b/src/mbgl/tile/geojson_tile.cpp @@ -1,7 +1,10 @@ #include <mbgl/tile/geojson_tile.hpp> #include <mbgl/tile/geometry_tile_data.hpp> - +#include <mbgl/renderer/query.hpp> +#include <mbgl/renderer/tile_parameters.hpp> +#include <mbgl/style/filter_evaluator.hpp> #include <mbgl/util/string.hpp> + #include <mapbox/geojsonvt.hpp> #include <supercluster.hpp> @@ -26,6 +29,10 @@ public: return feature.properties; } + optional<FeatureIdentifier> getID() const override { + return feature.id; + } + GeometryCollection getGeometries() const override { GeometryCollection geometry = apply_visitor(ToGeometryCollection(), feature.geometry); @@ -46,46 +53,86 @@ public: } }; -class GeoJSONTileData : public GeometryTileData, - public GeometryTileLayer { +class GeoJSONTileLayer : public GeometryTileLayer { public: - mapbox::geometry::feature_collection<int16_t> features; - - GeoJSONTileData(mapbox::geometry::feature_collection<int16_t> features_) + GeoJSONTileLayer(std::shared_ptr<const mapbox::geometry::feature_collection<int16_t>> features_) : features(std::move(features_)) { } - std::unique_ptr<GeometryTileData> clone() const override { - return std::make_unique<GeoJSONTileData>(*this); + std::size_t featureCount() const override { + return features->size(); } - const GeometryTileLayer* getLayer(const std::string&) const override { - return this; + std::unique_ptr<GeometryTileFeature> getFeature(std::size_t i) const override { + return std::make_unique<GeoJSONTileFeature>((*features)[i]); } std::string getName() const override { return ""; } - std::size_t featureCount() const override { - return features.size(); +private: + std::shared_ptr<const mapbox::geometry::feature_collection<int16_t>> features; +}; + +class GeoJSONTileData : public GeometryTileData { +public: + GeoJSONTileData(mapbox::geometry::feature_collection<int16_t> features_) + : features(std::make_shared<mapbox::geometry::feature_collection<int16_t>>( + std::move(features_))) { } - std::unique_ptr<GeometryTileFeature> getFeature(std::size_t i) const override { - return std::make_unique<GeoJSONTileFeature>(features[i]); + GeoJSONTileData(std::shared_ptr<const mapbox::geometry::feature_collection<int16_t>> features_) + : features(std::move(features_)) { } + + std::unique_ptr<GeometryTileData> clone() const override { + return std::make_unique<GeoJSONTileData>(features); + } + + std::unique_ptr<GeometryTileLayer> getLayer(const std::string&) const override { + return std::make_unique<GeoJSONTileLayer>(features); + } + + +private: + std::shared_ptr<const mapbox::geometry::feature_collection<int16_t>> features; }; GeoJSONTile::GeoJSONTile(const OverscaledTileID& overscaledTileID, std::string sourceID_, - const style::UpdateParameters& parameters) + const TileParameters& parameters, + mapbox::geometry::feature_collection<int16_t> features) : GeometryTile(overscaledTileID, sourceID_, parameters) { + updateData(std::move(features)); } - -void GeoJSONTile::updateData(const mapbox::geometry::feature_collection<int16_t>& features) { - setData(std::make_unique<GeoJSONTileData>(features)); + +void GeoJSONTile::updateData(mapbox::geometry::feature_collection<int16_t> features) { + setData(std::make_unique<GeoJSONTileData>(std::move(features))); } void GeoJSONTile::setNecessity(Necessity) {} + +void GeoJSONTile::querySourceFeatures( + std::vector<Feature>& result, + const SourceQueryOptions& options) { + + // Ignore the sourceLayer, there is only one + auto layer = getData()->getLayer({}); + + if (layer) { + auto featureCount = layer->featureCount(); + for (std::size_t i = 0; i < featureCount; i++) { + auto feature = layer->getFeature(i); + + // Apply filter, if any + if (options.filter && !(*options.filter)(*feature)) { + continue; + } + + result.push_back(convertFeature(*feature, id.canonical)); + } + } +} } // namespace mbgl diff --git a/src/mbgl/tile/geojson_tile.hpp b/src/mbgl/tile/geojson_tile.hpp index 2880408736..d8a0a379d7 100644 --- a/src/mbgl/tile/geojson_tile.hpp +++ b/src/mbgl/tile/geojson_tile.hpp @@ -5,19 +5,22 @@ namespace mbgl { -namespace style { -class UpdateParameters; -} // namespace style +class TileParameters; class GeoJSONTile : public GeometryTile { public: GeoJSONTile(const OverscaledTileID&, std::string sourceID, - const style::UpdateParameters&); + const TileParameters&, + mapbox::geometry::feature_collection<int16_t>); + + void updateData(mapbox::geometry::feature_collection<int16_t>); - void updateData(const mapbox::geometry::feature_collection<int16_t>&); - void setNecessity(Necessity) final; + + void querySourceFeatures( + std::vector<Feature>& result, + const SourceQueryOptions&) override; }; } // namespace mbgl diff --git a/src/mbgl/tile/geometry_tile.cpp b/src/mbgl/tile/geometry_tile.cpp index 9aeb35c821..33911df9ed 100644 --- a/src/mbgl/tile/geometry_tile.cpp +++ b/src/mbgl/tile/geometry_tile.cpp @@ -2,17 +2,27 @@ #include <mbgl/tile/geometry_tile_worker.hpp> #include <mbgl/tile/geometry_tile_data.hpp> #include <mbgl/tile/tile_observer.hpp> -#include <mbgl/style/update_parameters.hpp> #include <mbgl/style/layer_impl.hpp> #include <mbgl/style/layers/background_layer.hpp> #include <mbgl/style/layers/custom_layer.hpp> -#include <mbgl/style/layers/symbol_layer.hpp> -#include <mbgl/style/style.hpp> +#include <mbgl/renderer/tile_parameters.hpp> +#include <mbgl/renderer/layers/render_background_layer.hpp> +#include <mbgl/renderer/layers/render_custom_layer.hpp> +#include <mbgl/renderer/layers/render_symbol_layer.hpp> +#include <mbgl/renderer/buckets/symbol_bucket.hpp> +#include <mbgl/renderer/query.hpp> +#include <mbgl/text/glyph_atlas.hpp> +#include <mbgl/renderer/image_atlas.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/util/run_loop.hpp> +#include <mbgl/style/filter_evaluator.hpp> +#include <mbgl/util/chrono.hpp> +#include <mbgl/util/logging.hpp> + +#include <iostream> namespace mbgl { @@ -20,41 +30,49 @@ using namespace style; GeometryTile::GeometryTile(const OverscaledTileID& id_, std::string sourceID_, - const style::UpdateParameters& parameters) + const TileParameters& parameters) : Tile(id_), sourceID(std::move(sourceID_)), - style(parameters.style), mailbox(std::make_shared<Mailbox>(*util::RunLoop::Get())), worker(parameters.workerScheduler, ActorRef<GeometryTile>(*this, mailbox), id_, - *parameters.style.glyphAtlas, obsolete, - parameters.mode) { + parameters.mode, + parameters.pixelRatio), + glyphManager(parameters.glyphManager), + imageManager(parameters.imageManager), + placementThrottler(Milliseconds(300), [this] { invokePlacement(); }), + lastYStretch(1.0f) { } GeometryTile::~GeometryTile() { - cancel(); + glyphManager.removeRequestor(*this); + imageManager.removeRequestor(*this); + markObsolete(); } void GeometryTile::cancel() { + markObsolete(); +} + +void GeometryTile::markObsolete() { obsolete = true; } void GeometryTile::setError(std::exception_ptr err) { + loaded = true; + renderable = false; observer->onTileError(*this, err); } void GeometryTile::setData(std::unique_ptr<const GeometryTileData> data_) { // 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; - } + pending = true; ++correlationID; worker.invoke(&GeometryTileWorker::setData, std::move(data_), correlationID); - redoLayout(); } void GeometryTile::setPlacementConfig(const PlacementConfig& desiredConfig) { @@ -64,71 +82,126 @@ void GeometryTile::setPlacementConfig(const PlacementConfig& desiredConfig) { // 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; - } + pending = true; ++correlationID; requestedConfig = desiredConfig; - worker.invoke(&GeometryTileWorker::setPlacementConfig, desiredConfig, correlationID); + placementThrottler.invoke(); } -void GeometryTile::symbolDependenciesChanged() { - worker.invoke(&GeometryTileWorker::symbolDependenciesChanged); +void GeometryTile::invokePlacement() { + if (requestedConfig) { + worker.invoke(&GeometryTileWorker::setPlacementConfig, *requestedConfig, correlationID); + } } -void GeometryTile::redoLayout() { +void GeometryTile::setLayers(const std::vector<Immutable<Layer::Impl>>& layers) { // 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; - } + pending = true; - std::vector<std::unique_ptr<Layer>> copy; + std::vector<Immutable<Layer::Impl>> impls; - for (const Layer* layer : style.getLayers()) { - // Avoid cloning and including irrelevant layers. - if (layer->is<BackgroundLayer>() || - layer->is<CustomLayer>() || - layer->baseImpl->source != sourceID || - id.overscaledZ < std::floor(layer->baseImpl->minZoom) || - id.overscaledZ >= std::ceil(layer->baseImpl->maxZoom) || - layer->baseImpl->visibility == VisibilityType::None) { + for (const auto& layer : layers) { + // Skip irrelevant layers. + if (layer->type == LayerType::Background || + layer->type == LayerType::Custom || + layer->source != sourceID || + id.overscaledZ < std::floor(layer->minZoom) || + id.overscaledZ >= std::ceil(layer->maxZoom) || + layer->visibility == VisibilityType::None) { continue; } - copy.push_back(layer->baseImpl->clone()); + impls.push_back(layer); } ++correlationID; - worker.invoke(&GeometryTileWorker::setLayers, std::move(copy), correlationID); + worker.invoke(&GeometryTileWorker::setLayers, std::move(impls), correlationID); } void GeometryTile::onLayout(LayoutResult result) { - availableData = DataAvailability::Some; + loaded = true; + renderable = true; nonSymbolBuckets = std::move(result.nonSymbolBuckets); featureIndex = std::move(result.featureIndex); data = std::move(result.tileData); + collisionTile.reset(); observer->onTileChanged(*this); } void GeometryTile::onPlacement(PlacementResult result) { + loaded = true; + renderable = true; if (result.correlationID == correlationID) { - availableData = DataAvailability::All; + pending = false; } symbolBuckets = std::move(result.symbolBuckets); collisionTile = std::move(result.collisionTile); + if (result.glyphAtlasImage) { + glyphAtlasImage = std::move(*result.glyphAtlasImage); + } + if (result.iconAtlasImage) { + iconAtlasImage = std::move(*result.iconAtlasImage); + } + if (collisionTile.get()) { + lastYStretch = collisionTile->yStretch; + } observer->onTileChanged(*this); } void GeometryTile::onError(std::exception_ptr err) { - availableData = DataAvailability::All; + loaded = true; + pending = false; + renderable = false; observer->onTileError(*this, err); } + +void GeometryTile::onGlyphsAvailable(GlyphMap glyphs) { + worker.invoke(&GeometryTileWorker::onGlyphsAvailable, std::move(glyphs)); +} + +void GeometryTile::getGlyphs(GlyphDependencies glyphDependencies) { + glyphManager.getGlyphs(*this, std::move(glyphDependencies)); +} + +void GeometryTile::onImagesAvailable(ImageMap images) { + worker.invoke(&GeometryTileWorker::onImagesAvailable, std::move(images)); +} + +void GeometryTile::getImages(ImageDependencies imageDependencies) { + imageManager.getImages(*this, std::move(imageDependencies)); +} + +void GeometryTile::upload(gl::Context& context) { + auto uploadFn = [&] (Bucket& bucket) { + if (bucket.needsUpload()) { + bucket.upload(context); + } + }; + + for (auto& entry : nonSymbolBuckets) { + uploadFn(*entry.second); + } + + for (auto& entry : symbolBuckets) { + uploadFn(*entry.second); + } + + if (glyphAtlasImage) { + glyphAtlasTexture = context.createTexture(*glyphAtlasImage, 0); + glyphAtlasImage = {}; + } + + if (iconAtlasImage) { + iconAtlasTexture = context.createTexture(*iconAtlasImage, 0); + iconAtlasImage = {}; + } +} -Bucket* GeometryTile::getBucket(const Layer& layer) { - const auto& buckets = layer.is<SymbolLayer>() ? symbolBuckets : nonSymbolBuckets; - const auto it = buckets.find(layer.baseImpl->id); +Bucket* GeometryTile::getBucket(const Layer::Impl& layer) const { + const auto& buckets = layer.type == LayerType::Symbol ? symbolBuckets : nonSymbolBuckets; + const auto it = buckets.find(layer.id); if (it == buckets.end()) { return nullptr; } @@ -141,7 +214,8 @@ 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) { + const RenderStyle& style, + const RenderedQueryOptions& options) { if (!featureIndex || !data) return; @@ -150,11 +224,55 @@ void GeometryTile::queryRenderedFeatures( transformState.getAngle(), util::tileSize * id.overscaleFactor(), std::pow(2, transformState.getZoom() - id.overscaledZ), - layerIDs, + options, *data, id.canonical, style, - collisionTile.get()); + collisionTile.get(), + *this); +} + +void GeometryTile::querySourceFeatures( + std::vector<Feature>& result, + const SourceQueryOptions& options) { + + // Data not yet available + if (!data) { + return; + } + + // No source layers, specified, nothing to do + if (!options.sourceLayers) { + Log::Warning(Event::General, "At least one sourceLayer required"); + return; + } + + for (auto sourceLayer : *options.sourceLayers) { + // Go throught all sourceLayers, if any + // to gather all the features + auto layer = data->getLayer(sourceLayer); + + if (layer) { + auto featureCount = layer->featureCount(); + for (std::size_t i = 0; i < featureCount; i++) { + auto feature = layer->getFeature(i); + + // Apply filter, if any + if (options.filter && !(*options.filter)(*feature)) { + continue; + } + + result.push_back(convertFeature(*feature, id.canonical)); + } + } + } +} + +float GeometryTile::yStretch() const { + // collisionTile gets reset in onLayout but we don't clear the symbolBuckets + // until a new placement result comes along, so keep the yStretch value in + // case we need to render them. + return lastYStretch; } } // namespace mbgl diff --git a/src/mbgl/tile/geometry_tile.hpp b/src/mbgl/tile/geometry_tile.hpp index c61a510311..c45762742b 100644 --- a/src/mbgl/tile/geometry_tile.hpp +++ b/src/mbgl/tile/geometry_tile.hpp @@ -2,9 +2,14 @@ #include <mbgl/tile/tile.hpp> #include <mbgl/tile/geometry_tile_worker.hpp> +#include <mbgl/renderer/image_manager.hpp> +#include <mbgl/text/glyph_manager.hpp> #include <mbgl/text/placement_config.hpp> +#include <mbgl/text/collision_tile.hpp> #include <mbgl/util/feature.hpp> +#include <mbgl/util/throttler.hpp> #include <mbgl/actor/actor.hpp> +#include <mbgl/geometry/feature_index.hpp> #include <atomic> #include <memory> @@ -14,20 +19,18 @@ namespace mbgl { class GeometryTileData; -class FeatureIndex; -class CollisionTile; - -namespace style { -class Style; -class Layer; -class UpdateParameters; -} // namespace style - -class GeometryTile : public Tile { +class RenderStyle; +class RenderLayer; +class SourceQueryOptions; +class TileParameters; +class GlyphAtlas; +class ImageAtlas; + +class GeometryTile : public Tile, public GlyphRequestor, ImageRequestor { public: GeometryTile(const OverscaledTileID&, std::string sourceID, - const style::UpdateParameters&); + const TileParameters&); ~GeometryTile() override; @@ -35,16 +38,30 @@ public: void setData(std::unique_ptr<const GeometryTileData>); void setPlacementConfig(const PlacementConfig&) override; - void symbolDependenciesChanged() override; - void redoLayout() override; + void setLayers(const std::vector<Immutable<style::Layer::Impl>>&) override; + + void onGlyphsAvailable(GlyphMap) override; + void onImagesAvailable(ImageMap) override; + + void getGlyphs(GlyphDependencies); + void getImages(ImageDependencies); + + void upload(gl::Context&) override; + Bucket* getBucket(const style::Layer::Impl&) const override; - Bucket* getBucket(const style::Layer&) override; + Size bindGlyphAtlas(gl::Context&); + Size bindIconAtlas(gl::Context&); void queryRenderedFeatures( std::unordered_map<std::string, std::vector<Feature>>& result, const GeometryCoordinates& queryGeometry, const TransformState&, - const optional<std::vector<std::string>>& layerIDs) override; + const RenderStyle&, + const RenderedQueryOptions& options) override; + + void querySourceFeatures( + std::vector<Feature>& result, + const SourceQueryOptions&) override; void cancel() override; @@ -54,6 +71,15 @@ public: std::unique_ptr<FeatureIndex> featureIndex; std::unique_ptr<GeometryTileData> tileData; uint64_t correlationID; + + LayoutResult(std::unordered_map<std::string, std::shared_ptr<Bucket>> nonSymbolBuckets_, + std::unique_ptr<FeatureIndex> featureIndex_, + std::unique_ptr<GeometryTileData> tileData_, + uint64_t correlationID_) + : nonSymbolBuckets(std::move(nonSymbolBuckets_)), + featureIndex(std::move(featureIndex_)), + tileData(std::move(tileData_)), + correlationID(correlationID_) {} }; void onLayout(LayoutResult); @@ -61,15 +87,37 @@ public: public: std::unordered_map<std::string, std::shared_ptr<Bucket>> symbolBuckets; std::unique_ptr<CollisionTile> collisionTile; + optional<AlphaImage> glyphAtlasImage; + optional<PremultipliedImage> iconAtlasImage; uint64_t correlationID; + + PlacementResult(std::unordered_map<std::string, std::shared_ptr<Bucket>> symbolBuckets_, + std::unique_ptr<CollisionTile> collisionTile_, + optional<AlphaImage> glyphAtlasImage_, + optional<PremultipliedImage> iconAtlasImage_, + uint64_t correlationID_) + : symbolBuckets(std::move(symbolBuckets_)), + collisionTile(std::move(collisionTile_)), + glyphAtlasImage(std::move(glyphAtlasImage_)), + iconAtlasImage(std::move(iconAtlasImage_)), + correlationID(correlationID_) {} }; void onPlacement(PlacementResult); void onError(std::exception_ptr); + + float yStretch() const override; + +protected: + const GeometryTileData* getData() { + return data.get(); + } private: + void markObsolete(); + void invokePlacement(); + const std::string sourceID; - style::Style& style; // Used to signal the worker that it should abandon parsing this tile as soon as possible. std::atomic<bool> obsolete { false }; @@ -77,6 +125,9 @@ private: std::shared_ptr<Mailbox> mailbox; Actor<GeometryTileWorker> worker; + GlyphManager& glyphManager; + ImageManager& imageManager; + uint64_t correlationID = 0; optional<PlacementConfig> requestedConfig; @@ -84,8 +135,18 @@ private: std::unique_ptr<FeatureIndex> featureIndex; std::unique_ptr<const GeometryTileData> data; + optional<AlphaImage> glyphAtlasImage; + optional<PremultipliedImage> iconAtlasImage; + std::unordered_map<std::string, std::shared_ptr<Bucket>> symbolBuckets; std::unique_ptr<CollisionTile> collisionTile; + + util::Throttler placementThrottler; + float lastYStretch; + +public: + optional<gl::Texture> glyphAtlasTexture; + optional<gl::Texture> iconAtlasTexture; }; } // namespace mbgl diff --git a/src/mbgl/tile/geometry_tile_data.cpp b/src/mbgl/tile/geometry_tile_data.cpp index ccc91b027a..680f8d1497 100644 --- a/src/mbgl/tile/geometry_tile_data.cpp +++ b/src/mbgl/tile/geometry_tile_data.cpp @@ -1,7 +1,7 @@ #include <mbgl/tile/geometry_tile_data.hpp> #include <mbgl/tile/tile_id.hpp> -#include <clipper/clipper.hpp> +#include <mapbox/geometry/wagyu/wagyu.hpp> namespace mbgl { @@ -17,8 +17,8 @@ static double signedArea(const GeometryCoordinates& ring) { return sum; } -static ClipperLib::Path toClipperPath(const GeometryCoordinates& ring) { - ClipperLib::Path result; +static LinearRing<int32_t> toWagyuPath(const GeometryCoordinates& ring) { + LinearRing<int32_t> result; result.reserve(ring.size()); for (const auto& p : ring) { result.emplace_back(p.x, p.y); @@ -26,63 +26,29 @@ static ClipperLib::Path toClipperPath(const GeometryCoordinates& ring) { return result; } -static GeometryCoordinates fromClipperPath(const ClipperLib::Path& path) { - GeometryCoordinates result; - result.reserve(path.size() + 1); - - 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)); - } - - // Clipper does not repeat initial point, but our geometry model requires it. - if (!result.empty()) { - result.push_back(result.front()); - } - - 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); - } - - // 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); +static GeometryCollection toGeometryCollection(MultiPolygon<int16_t>&& multipolygon) { + GeometryCollection result; + for (auto& polygon : multipolygon) { + for (auto& ring : polygon) { + result.emplace_back(std::move(ring)); } } + return result; } GeometryCollection fixupPolygons(const GeometryCollection& rings) { - ClipperLib::Clipper clipper; - clipper.StrictlySimple(true); + using namespace mapbox::geometry::wagyu; + + wagyu<int32_t> clipper; for (const auto& ring : rings) { - clipper.AddPath(toClipperPath(ring), ClipperLib::ptSubject, true); + clipper.add_ring(toWagyuPath(ring)); } - ClipperLib::PolyTree polygons; - clipper.Execute(ClipperLib::ctUnion, polygons, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd); - clipper.Clear(); + MultiPolygon<int16_t> multipolygon; + clipper.execute(clip_type_union, multipolygon, fill_type_even_odd, fill_type_even_odd); - GeometryCollection result; - for (auto * polynode : polygons.Childs) { - processPolynodeBranch(polynode, result); - } - return result; + return toGeometryCollection(std::move(multipolygon)); } std::vector<GeometryCollection> classifyRings(const GeometryCollection& rings) { @@ -208,12 +174,7 @@ static Feature::geometry_type convertGeometry(const GeometryTileFeature& geometr } Feature convertFeature(const GeometryTileFeature& geometryTileFeature, const CanonicalTileID& tileID) { -#if !defined(__GNUC__) || __GNUC__ >= 5 Feature feature { convertGeometry(geometryTileFeature, tileID) }; -#else - Feature feature; - feature.geometry = convertGeometry(geometryTileFeature, tileID); -#endif feature.properties = geometryTileFeature.getProperties(); feature.id = geometryTileFeature.getID(); return feature; diff --git a/src/mbgl/tile/geometry_tile_data.hpp b/src/mbgl/tile/geometry_tile_data.hpp index 8a10ec058a..449d8cab28 100644 --- a/src/mbgl/tile/geometry_tile_data.hpp +++ b/src/mbgl/tile/geometry_tile_data.hpp @@ -21,6 +21,13 @@ using GeometryCoordinate = Point<int16_t>; class GeometryCoordinates : public std::vector<GeometryCoordinate> { public: using coordinate_type = int16_t; + + GeometryCoordinates() = default; + GeometryCoordinates(const std::vector<GeometryCoordinate>& v) + : std::vector<GeometryCoordinate>(v) {} + GeometryCoordinates(std::vector<GeometryCoordinate>&& v) + : std::vector<GeometryCoordinate>(std::move(v)) {} + using std::vector<GeometryCoordinate>::vector; }; @@ -44,7 +51,11 @@ class GeometryTileLayer { public: virtual ~GeometryTileLayer() = default; virtual std::size_t featureCount() const = 0; + + // Returns the feature object at the given position within the layer. The returned feature + // object may *not* outlive the layer object. virtual std::unique_ptr<GeometryTileFeature> getFeature(std::size_t) const = 0; + virtual std::string getName() const = 0; }; @@ -52,7 +63,10 @@ class GeometryTileData { public: virtual ~GeometryTileData() = default; virtual std::unique_ptr<GeometryTileData> clone() const = 0; - virtual const GeometryTileLayer* getLayer(const std::string&) const = 0; + + // Returns the layer with the given name. The returned layer object *may* outlive the data + // object. + virtual std::unique_ptr<GeometryTileLayer> getLayer(const std::string&) const = 0; }; // classifies an array of rings into polygons with outer rings and holes diff --git a/src/mbgl/tile/geometry_tile_worker.cpp b/src/mbgl/tile/geometry_tile_worker.cpp index 2a86b7feda..c622d82e31 100644 --- a/src/mbgl/tile/geometry_tile_worker.cpp +++ b/src/mbgl/tile/geometry_tile_worker.cpp @@ -2,13 +2,14 @@ #include <mbgl/tile/geometry_tile_data.hpp> #include <mbgl/tile/geometry_tile.hpp> #include <mbgl/text/collision_tile.hpp> -#include <mbgl/text/glyph_atlas.hpp> #include <mbgl/layout/symbol_layout.hpp> -#include <mbgl/style/bucket_parameters.hpp> -#include <mbgl/style/group_by_layout.hpp> -#include <mbgl/style/layers/symbol_layer.hpp> +#include <mbgl/renderer/bucket_parameters.hpp> +#include <mbgl/renderer/group_by_layout.hpp> +#include <mbgl/style/filter.hpp> +#include <mbgl/style/filter_evaluator.hpp> #include <mbgl/style/layers/symbol_layer_impl.hpp> -#include <mbgl/renderer/symbol_bucket.hpp> +#include <mbgl/renderer/layers/render_symbol_layer.hpp> +#include <mbgl/renderer/buckets/symbol_bucket.hpp> #include <mbgl/util/logging.hpp> #include <mbgl/util/constants.hpp> #include <mbgl/util/string.hpp> @@ -23,20 +24,18 @@ using namespace style; GeometryTileWorker::GeometryTileWorker(ActorRef<GeometryTileWorker> self_, ActorRef<GeometryTile> parent_, OverscaledTileID id_, - GlyphAtlas& glyphAtlas_, const std::atomic<bool>& obsolete_, - const MapMode mode_) + const MapMode mode_, + const float pixelRatio_) : self(std::move(self_)), parent(std::move(parent_)), id(std::move(id_)), - glyphAtlas(glyphAtlas_), obsolete(obsolete_), - mode(mode_) { + mode(mode_), + pixelRatio(pixelRatio_) { } -GeometryTileWorker::~GeometryTileWorker() { - glyphAtlas.removeGlyphs(reinterpret_cast<uintptr_t>(this)); -} +GeometryTileWorker::~GeometryTileWorker() = default; /* GeometryTileWorker is a state machine. This is its transition diagram. @@ -93,7 +92,7 @@ void GeometryTileWorker::setData(std::unique_ptr<const GeometryTileData> data_, } } -void GeometryTileWorker::setLayers(std::vector<std::unique_ptr<Layer>> layers_, uint64_t correlationID_) { +void GeometryTileWorker::setLayers(std::vector<Immutable<Layer::Impl>> layers_, uint64_t correlationID_) { try { layers = std::move(layers_); correlationID = correlationID_; @@ -145,14 +144,14 @@ void GeometryTileWorker::symbolDependenciesChanged() { try { switch (state) { case Idle: - if (hasPendingSymbolDependencies()) { + if (symbolLayoutsNeedPreparation) { attemptPlacement(); coalesce(); } break; case Coalescing: - if (hasPendingSymbolDependencies()) { + if (symbolLayoutsNeedPreparation) { state = NeedPlacement; } break; @@ -197,6 +196,71 @@ void GeometryTileWorker::coalesce() { self.invoke(&GeometryTileWorker::coalesced); } +void GeometryTileWorker::onGlyphsAvailable(GlyphMap newGlyphMap) { + for (auto& newFontGlyphs : newGlyphMap) { + const FontStack& fontStack = newFontGlyphs.first; + Glyphs& newGlyphs = newFontGlyphs.second; + + Glyphs& glyphs = glyphMap[fontStack]; + GlyphIDs& pendingGlyphIDs = pendingGlyphDependencies[fontStack]; + + for (auto& newGlyph : newGlyphs) { + const GlyphID& glyphID = newGlyph.first; + optional<Immutable<Glyph>>& glyph = newGlyph.second; + + if (pendingGlyphIDs.erase(glyphID)) { + glyphs.emplace(glyphID, std::move(glyph)); + } + } + } + symbolDependenciesChanged(); +} + +void GeometryTileWorker::onImagesAvailable(ImageMap newImageMap) { + imageMap = std::move(newImageMap); + pendingImageDependencies.clear(); + symbolDependenciesChanged(); +} + +void GeometryTileWorker::requestNewGlyphs(const GlyphDependencies& glyphDependencies) { + for (auto& fontDependencies : glyphDependencies) { + auto fontGlyphs = glyphMap.find(fontDependencies.first); + for (auto glyphID : fontDependencies.second) { + if (fontGlyphs == glyphMap.end() || fontGlyphs->second.find(glyphID) == fontGlyphs->second.end()) { + pendingGlyphDependencies[fontDependencies.first].insert(glyphID); + } + } + } + if (!pendingGlyphDependencies.empty()) { + parent.invoke(&GeometryTile::getGlyphs, pendingGlyphDependencies); + } +} + +void GeometryTileWorker::requestNewImages(const ImageDependencies& imageDependencies) { + pendingImageDependencies = imageDependencies; + if (!pendingImageDependencies.empty()) { + parent.invoke(&GeometryTile::getImages, pendingImageDependencies); + } +} + +static std::vector<std::unique_ptr<RenderLayer>> toRenderLayers(const std::vector<Immutable<style::Layer::Impl>>& layers, float zoom) { + std::vector<std::unique_ptr<RenderLayer>> renderLayers; + renderLayers.reserve(layers.size()); + for (auto& layer : layers) { + renderLayers.push_back(RenderLayer::create(layer)); + + renderLayers.back()->transition(TransitionParameters { + Clock::time_point::max(), + TransitionOptions() + }); + + renderLayers.back()->evaluate(PropertyEvaluationParameters { + zoom + }); + } + return renderLayers; +} + void GeometryTileWorker::redoLayout() { if (!data || !layers) { return; @@ -204,17 +268,23 @@ void GeometryTileWorker::redoLayout() { std::vector<std::string> symbolOrder; for (auto it = layers->rbegin(); it != layers->rend(); it++) { - if ((*it)->is<SymbolLayer>()) { - symbolOrder.push_back((*it)->getID()); + if ((*it)->type == LayerType::Symbol) { + symbolOrder.push_back((*it)->id); } } std::unordered_map<std::string, std::unique_ptr<SymbolLayout>> symbolLayoutMap; std::unordered_map<std::string, std::shared_ptr<Bucket>> buckets; auto featureIndex = std::make_unique<FeatureIndex>(); - BucketParameters parameters { id, obsolete, *featureIndex, mode }; + BucketParameters parameters { id, mode, pixelRatio }; + + GlyphDependencies glyphDependencies; + ImageDependencies imageDependencies; + + // Create render layers and group by layout + std::vector<std::unique_ptr<RenderLayer>> renderLayers = toRenderLayers(*layers, id.overscaledZ); + std::vector<std::vector<const RenderLayer*>> groups = groupByLayout(renderLayers); - std::vector<std::vector<const Layer*>> groups = groupByLayout(*layers); for (auto& group : groups) { if (obsolete) { return; @@ -224,7 +294,7 @@ void GeometryTileWorker::redoLayout() { continue; // Tile has no data. } - const Layer& leader = *group.at(0); + const RenderLayer& leader = *group.at(0); auto geometryLayer = (*data)->getLayer(leader.baseImpl->sourceLayer); if (!geometryLayer) { @@ -238,14 +308,31 @@ void GeometryTileWorker::redoLayout() { featureIndex->setBucketLayerIDs(leader.getID(), layerIDs); - if (leader.is<SymbolLayer>()) { - symbolLayoutMap.emplace(leader.getID(), - leader.as<SymbolLayer>()->impl->createLayout(parameters, *geometryLayer, layerIDs)); + if (leader.is<RenderSymbolLayer>()) { + auto layout = leader.as<RenderSymbolLayer>()->createLayout( + parameters, group, std::move(geometryLayer), glyphDependencies, imageDependencies); + symbolLayoutMap.emplace(leader.getID(), std::move(layout)); + symbolLayoutsNeedPreparation = true; } else { - std::shared_ptr<Bucket> bucket = leader.baseImpl->createBucket(parameters, *geometryLayer); + const Filter& filter = leader.baseImpl->filter; + const std::string& sourceLayerID = leader.baseImpl->sourceLayer; + std::shared_ptr<Bucket> bucket = leader.createBucket(parameters, group); + + for (std::size_t i = 0; !obsolete && i < geometryLayer->featureCount(); i++) { + std::unique_ptr<GeometryTileFeature> feature = geometryLayer->getFeature(i); + + if (!filter(feature->getType(), feature->getID(), [&] (const auto& key) { return feature->getValue(key); })) + continue; + + GeometryCollection geometries = feature->getGeometries(); + bucket->addFeature(*feature, geometries); + featureIndex->insert(geometries, i, sourceLayerID, leader.getID()); + } + if (!bucket->hasData()) { continue; } + for (const auto& layer : group) { buckets.emplace(layer->getID(), bucket); } @@ -260,6 +347,9 @@ void GeometryTileWorker::redoLayout() { } } + requestNewGlyphs(glyphDependencies); + requestNewImages(imageDependencies); + parent.invoke(&GeometryTile::onLayout, GeometryTile::LayoutResult { std::move(buckets), std::move(featureIndex), @@ -271,43 +361,39 @@ void GeometryTileWorker::redoLayout() { } bool GeometryTileWorker::hasPendingSymbolDependencies() const { - bool result = false; - - for (const auto& symbolLayout : symbolLayouts) { - if (symbolLayout->state == SymbolLayout::Pending) { - result = true; + for (auto& glyphDependency : pendingGlyphDependencies) { + if (!glyphDependency.second.empty()) { + return true; } } - - return result; + return !pendingImageDependencies.empty(); } void GeometryTileWorker::attemptPlacement() { - if (!data || !layers || !placementConfig) { + if (!data || !layers || !placementConfig || hasPendingSymbolDependencies()) { return; } + + optional<AlphaImage> glyphAtlasImage; + optional<PremultipliedImage> iconAtlasImage; - bool canPlace = true; + if (symbolLayoutsNeedPreparation) { + GlyphAtlas glyphAtlas = makeGlyphAtlas(glyphMap); + ImageAtlas imageAtlas = makeImageAtlas(imageMap); - // Prepare as many SymbolLayouts as possible. - for (auto& symbolLayout : symbolLayouts) { - if (obsolete) { - return; - } + glyphAtlasImage = std::move(glyphAtlas.image); + iconAtlasImage = std::move(imageAtlas.image); - if (symbolLayout->state == SymbolLayout::Pending) { - if (symbolLayout->canPrepare(glyphAtlas)) { - symbolLayout->state = SymbolLayout::Prepared; - symbolLayout->prepare(reinterpret_cast<uintptr_t>(this), - glyphAtlas); - } else { - canPlace = false; + for (auto& symbolLayout : symbolLayouts) { + if (obsolete) { + return; } + + symbolLayout->prepare(glyphMap, glyphAtlas.positions, + imageMap, imageAtlas.positions); } - } - if (!canPlace) { - return; // We'll be notified (via `setPlacementConfig`) when it's time to try again. + symbolLayoutsNeedPreparation = false; } auto collisionTile = std::make_unique<CollisionTile>(*placementConfig); @@ -318,20 +404,21 @@ void GeometryTileWorker::attemptPlacement() { return; } - symbolLayout->state = SymbolLayout::Placed; if (!symbolLayout->hasSymbolInstances()) { continue; } std::shared_ptr<Bucket> bucket = symbolLayout->place(*collisionTile); - for (const auto& layerID : symbolLayout->layerIDs) { - buckets.emplace(layerID, bucket); + for (const auto& pair : symbolLayout->layerPaintProperties) { + buckets.emplace(pair.first, bucket); } } parent.invoke(&GeometryTile::onPlacement, GeometryTile::PlacementResult { std::move(buckets), std::move(collisionTile), + std::move(glyphAtlasImage), + std::move(iconAtlasImage), correlationID }); } diff --git a/src/mbgl/tile/geometry_tile_worker.hpp b/src/mbgl/tile/geometry_tile_worker.hpp index 58b5e23cfd..7f80c3b4f7 100644 --- a/src/mbgl/tile/geometry_tile_worker.hpp +++ b/src/mbgl/tile/geometry_tile_worker.hpp @@ -2,19 +2,21 @@ #include <mbgl/map/mode.hpp> #include <mbgl/tile/tile_id.hpp> +#include <mbgl/style/image_impl.hpp> +#include <mbgl/text/glyph.hpp> #include <mbgl/text/placement_config.hpp> #include <mbgl/actor/actor_ref.hpp> #include <mbgl/util/optional.hpp> +#include <mbgl/util/immutable.hpp> +#include <mbgl/style/layer_impl.hpp> #include <atomic> #include <memory> -#include <unordered_map> namespace mbgl { class GeometryTile; class GeometryTileData; -class GlyphAtlas; class SymbolLayout; namespace style { @@ -26,30 +28,38 @@ public: GeometryTileWorker(ActorRef<GeometryTileWorker> self, ActorRef<GeometryTile> parent, OverscaledTileID, - GlyphAtlas&, const std::atomic<bool>&, - const MapMode); + const MapMode, + const float pixelRatio); ~GeometryTileWorker(); - void setLayers(std::vector<std::unique_ptr<style::Layer>>, uint64_t correlationID); + void setLayers(std::vector<Immutable<style::Layer::Impl>>, uint64_t correlationID); void setData(std::unique_ptr<const GeometryTileData>, uint64_t correlationID); void setPlacementConfig(PlacementConfig, uint64_t correlationID); - void symbolDependenciesChanged(); + + void onGlyphsAvailable(GlyphMap glyphs); + void onImagesAvailable(ImageMap images); private: - void coalesce(); void coalesced(); void redoLayout(); void attemptPlacement(); + + void coalesce(); + + void requestNewGlyphs(const GlyphDependencies&); + void requestNewImages(const ImageDependencies&); + + void symbolDependenciesChanged(); bool hasPendingSymbolDependencies() const; ActorRef<GeometryTileWorker> self; ActorRef<GeometryTile> parent; const OverscaledTileID id; - GlyphAtlas& glyphAtlas; const std::atomic<bool>& obsolete; const MapMode mode; + const float pixelRatio; enum State { Idle, @@ -62,11 +72,16 @@ private: uint64_t correlationID = 0; // Outer optional indicates whether we've received it or not. - optional<std::vector<std::unique_ptr<style::Layer>>> layers; + optional<std::vector<Immutable<style::Layer::Impl>>> layers; optional<std::unique_ptr<const GeometryTileData>> data; optional<PlacementConfig> placementConfig; + bool symbolLayoutsNeedPreparation = false; std::vector<std::unique_ptr<SymbolLayout>> symbolLayouts; + GlyphDependencies pendingGlyphDependencies; + ImageDependencies pendingImageDependencies; + GlyphMap glyphMap; + ImageMap imageMap; }; } // namespace mbgl diff --git a/src/mbgl/tile/raster_tile.cpp b/src/mbgl/tile/raster_tile.cpp index c7a051f841..1260fd1edd 100644 --- a/src/mbgl/tile/raster_tile.cpp +++ b/src/mbgl/tile/raster_tile.cpp @@ -3,17 +3,17 @@ #include <mbgl/tile/tile_observer.hpp> #include <mbgl/tile/tile_loader_impl.hpp> #include <mbgl/style/source.hpp> -#include <mbgl/style/update_parameters.hpp> #include <mbgl/storage/resource.hpp> #include <mbgl/storage/response.hpp> #include <mbgl/storage/file_source.hpp> -#include <mbgl/renderer/raster_bucket.hpp> +#include <mbgl/renderer/tile_parameters.hpp> +#include <mbgl/renderer/buckets/raster_bucket.hpp> #include <mbgl/util/run_loop.hpp> namespace mbgl { RasterTile::RasterTile(const OverscaledTileID& id_, - const style::UpdateParameters& parameters, + const TileParameters& parameters, const Tileset& tileset) : Tile(id_), loader(*this, id_, parameters, tileset), @@ -28,6 +28,8 @@ void RasterTile::cancel() { } void RasterTile::setError(std::exception_ptr err) { + loaded = true; + renderable = false; observer->onTileError(*this, err); } @@ -39,22 +41,36 @@ void RasterTile::setData(std::shared_ptr<const std::string> data, worker.invoke(&RasterTileWorker::parse, data); } -void RasterTile::onParsed(std::unique_ptr<Bucket> result) { +void RasterTile::onParsed(std::unique_ptr<RasterBucket> result) { bucket = std::move(result); - availableData = DataAvailability::All; + loaded = true; + renderable = bucket ? true : false; observer->onTileChanged(*this); } void RasterTile::onError(std::exception_ptr err) { bucket.reset(); - availableData = DataAvailability::All; + loaded = true; + renderable = false; observer->onTileError(*this, err); } -Bucket* RasterTile::getBucket(const style::Layer&) { +void RasterTile::upload(gl::Context& context) { + if (bucket) { + bucket->upload(context); + } +} + +Bucket* RasterTile::getBucket(const style::Layer::Impl&) const { return bucket.get(); } +void RasterTile::setMask(TileMask&& mask) { + if (bucket) { + bucket->setMask(std::move(mask)); + } +} + void RasterTile::setNecessity(Necessity necessity) { loader.setNecessity(necessity); } diff --git a/src/mbgl/tile/raster_tile.hpp b/src/mbgl/tile/raster_tile.hpp index 1f6ceef0db..28a27b2b37 100644 --- a/src/mbgl/tile/raster_tile.hpp +++ b/src/mbgl/tile/raster_tile.hpp @@ -8,16 +8,17 @@ namespace mbgl { class Tileset; +class TileParameters; +class RasterBucket; namespace style { class Layer; -class UpdateParameters; } // namespace style class RasterTile : public Tile { public: RasterTile(const OverscaledTileID&, - const style::UpdateParameters&, + const TileParameters&, const Tileset&); ~RasterTile() final; @@ -29,9 +30,13 @@ public: optional<Timestamp> expires_); void cancel() override; - Bucket* getBucket(const style::Layer&) override; - void onParsed(std::unique_ptr<Bucket> result); + void upload(gl::Context&) override; + Bucket* getBucket(const style::Layer::Impl&) const override; + + void setMask(TileMask&&) override; + + void onParsed(std::unique_ptr<RasterBucket> result); void onError(std::exception_ptr); private: @@ -42,7 +47,7 @@ private: // Contains the Bucket object for the tile. Buckets are render // objects and they get added by tile parsing operations. - std::unique_ptr<Bucket> bucket; + std::unique_ptr<RasterBucket> bucket; }; } // namespace mbgl diff --git a/src/mbgl/tile/raster_tile_worker.cpp b/src/mbgl/tile/raster_tile_worker.cpp index 219e9a2e41..3c8af97b40 100644 --- a/src/mbgl/tile/raster_tile_worker.cpp +++ b/src/mbgl/tile/raster_tile_worker.cpp @@ -1,6 +1,6 @@ #include <mbgl/tile/raster_tile_worker.hpp> #include <mbgl/tile/raster_tile.hpp> -#include <mbgl/renderer/raster_bucket.cpp> +#include <mbgl/renderer/buckets/raster_bucket.hpp> #include <mbgl/actor/actor.hpp> #include <mbgl/util/premultiply.hpp> @@ -17,7 +17,7 @@ void RasterTileWorker::parse(std::shared_ptr<const std::string> data) { } try { - auto bucket = std::make_unique<RasterBucket>(util::unpremultiply(decodeImage(*data))); + auto bucket = std::make_unique<RasterBucket>(decodeImage(*data)); parent.invoke(&RasterTile::onParsed, std::move(bucket)); } catch (...) { parent.invoke(&RasterTile::onError, std::current_exception()); diff --git a/src/mbgl/tile/tile.cpp b/src/mbgl/tile/tile.cpp index e84eaaf780..35fc31dae1 100644 --- a/src/mbgl/tile/tile.cpp +++ b/src/mbgl/tile/tile.cpp @@ -1,6 +1,7 @@ #include <mbgl/tile/tile.hpp> #include <mbgl/tile/tile_observer.hpp> -#include <mbgl/renderer/debug_bucket.hpp> +#include <mbgl/renderer/buckets/debug_bucket.hpp> +#include <mbgl/renderer/query.hpp> #include <mbgl/util/string.hpp> #include <mbgl/util/logging.hpp> @@ -32,6 +33,11 @@ void Tile::queryRenderedFeatures( std::unordered_map<std::string, std::vector<Feature>>&, const GeometryCoordinates&, const TransformState&, - const optional<std::vector<std::string>>&) {} + const RenderStyle&, + const RenderedQueryOptions&) {} + +void Tile::querySourceFeatures( + std::vector<Feature>&, + const SourceQueryOptions&) {} } // namespace mbgl diff --git a/src/mbgl/tile/tile.hpp b/src/mbgl/tile/tile.hpp index cebf913f56..a1ab6a84b7 100644 --- a/src/mbgl/tile/tile.hpp +++ b/src/mbgl/tile/tile.hpp @@ -6,9 +6,11 @@ #include <mbgl/util/feature.hpp> #include <mbgl/util/tile_coordinate.hpp> #include <mbgl/tile/tile_id.hpp> +#include <mbgl/renderer/tile_mask.hpp> #include <mbgl/renderer/bucket.hpp> #include <mbgl/tile/geometry_tile_data.hpp> #include <mbgl/storage/resource.hpp> +#include <mbgl/style/layer_impl.hpp> #include <string> #include <memory> @@ -21,10 +23,13 @@ class DebugBucket; class TransformState; class TileObserver; class PlacementConfig; +class RenderStyle; +class RenderedQueryOptions; +class SourceQueryOptions; -namespace style { -class Layer; -} // namespace style +namespace gl { +class Context; +} // namespace gl class Tile : private util::noncopyable { public: @@ -45,17 +50,23 @@ public: // Mark this tile as no longer needed and cancel any pending work. virtual void cancel() = 0; - virtual Bucket* getBucket(const style::Layer&) = 0; + virtual void upload(gl::Context&) = 0; + virtual Bucket* getBucket(const style::Layer::Impl&) const = 0; virtual void setPlacementConfig(const PlacementConfig&) {} - virtual void symbolDependenciesChanged() {}; - virtual void redoLayout() {} + virtual void setLayers(const std::vector<Immutable<style::Layer::Impl>>&) {} + virtual void setMask(TileMask&&) {} virtual void queryRenderedFeatures( std::unordered_map<std::string, std::vector<Feature>>& result, const GeometryCoordinates& queryGeometry, const TransformState&, - const optional<std::vector<std::string>>& layerIDs); + const RenderStyle&, + const RenderedQueryOptions& options); + + virtual void querySourceFeatures( + std::vector<Feature>& result, + const SourceQueryOptions&); void setTriedOptional(); @@ -69,11 +80,23 @@ public: // partial state is still waiting for network resources but can also // be rendered, although layers will be missing. bool isRenderable() const { - return availableData != DataAvailability::None; + return renderable; + } + + // A tile is "Loaded" when we have received a response from a FileSource, and have attempted to + // parse the tile (if applicable). Tile implementations should set this to true when a load + // error occurred, or after the tile was parsed successfully. + bool isLoaded() const { + return loaded; } + // "Completion" of a tile means that we have attempted to load it, and parsed it completely, + // i.e. no parsing or placement operations are pending for that tile. + // Completeness doesn't mean that the tile can be rendered, but merely that we have exhausted + // all options to get this tile to a renderable state. Some tiles may not be renderable, but + // complete, e.g. when a raster tile couldn't be loaded, or parsing failed. bool isComplete() const { - return availableData == DataAvailability::All; + return loaded && !pending; } void dumpDebugLogs() const; @@ -84,24 +107,14 @@ public: // Contains the tile ID string for painting debug information. std::unique_ptr<DebugBucket> debugBucket; + + virtual float yStretch() const { return 1.0f; } protected: bool triedOptional = false; - - enum class DataAvailability : uint8_t { - // Still waiting for data to load or parse. - None, - - // 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, - - // Tile is fully parsed, and all buckets are available if they exist. - All, - }; - - DataAvailability availableData = DataAvailability::None; + bool renderable = false; + bool pending = false; + bool loaded = false; TileObserver* observer = nullptr; }; diff --git a/src/mbgl/tile/tile_id.hpp b/src/mbgl/tile/tile_id.hpp index 6415debfdc..811158e9b9 100644 --- a/src/mbgl/tile/tile_id.hpp +++ b/src/mbgl/tile/tile_id.hpp @@ -46,8 +46,8 @@ std::string toString(const CanonicalTileID&); // z/x/y describe the class OverscaledTileID { public: - OverscaledTileID(uint8_t overscaledZ, CanonicalTileID); - OverscaledTileID(uint8_t overscaledZ, uint8_t z, uint32_t x, uint32_t y); + OverscaledTileID(uint8_t overscaledZ, int16_t wrap, CanonicalTileID); + OverscaledTileID(uint8_t overscaledZ, int16_t wrap, uint8_t z, uint32_t x, uint32_t y); OverscaledTileID(uint8_t z, uint32_t x, uint32_t y); explicit OverscaledTileID(const CanonicalTileID&); explicit OverscaledTileID(CanonicalTileID&&); @@ -57,9 +57,10 @@ public: bool isChildOf(const OverscaledTileID&) const; uint32_t overscaleFactor() const; OverscaledTileID scaledTo(uint8_t z) const; - UnwrappedTileID unwrapTo(int16_t wrap) const; + UnwrappedTileID toUnwrapped() const; const uint8_t overscaledZ; + const int16_t wrap; const CanonicalTileID canonical; }; @@ -137,40 +138,40 @@ inline std::array<CanonicalTileID, 4> CanonicalTileID::children() const { } }; } -inline OverscaledTileID::OverscaledTileID(uint8_t overscaledZ_, CanonicalTileID canonical_) - : overscaledZ(overscaledZ_), canonical(std::move(canonical_)) { +inline OverscaledTileID::OverscaledTileID(uint8_t overscaledZ_, int16_t wrap_, CanonicalTileID canonical_) + : overscaledZ(overscaledZ_), wrap(wrap_), canonical(std::move(canonical_)) { assert(overscaledZ >= canonical.z); } -inline OverscaledTileID::OverscaledTileID(uint8_t overscaledZ_, uint8_t z, uint32_t x, uint32_t y) - : overscaledZ(overscaledZ_), canonical(z, x, y) { +inline OverscaledTileID::OverscaledTileID(uint8_t overscaledZ_, int16_t wrap_, uint8_t z, uint32_t x, uint32_t y) + : overscaledZ(overscaledZ_), wrap(wrap_), canonical(z, x, y) { assert(overscaledZ >= canonical.z); } inline OverscaledTileID::OverscaledTileID(uint8_t z, uint32_t x, uint32_t y) - : overscaledZ(z), canonical(z, x, y) { + : overscaledZ(z), wrap(0), canonical(z, x, y) { } inline OverscaledTileID::OverscaledTileID(const CanonicalTileID& canonical_) - : overscaledZ(canonical_.z), canonical(canonical_) { + : overscaledZ(canonical_.z), wrap(0), canonical(canonical_) { assert(overscaledZ >= canonical.z); } inline OverscaledTileID::OverscaledTileID(CanonicalTileID&& canonical_) - : overscaledZ(canonical_.z), canonical(std::forward<CanonicalTileID>(canonical_)) { + : overscaledZ(canonical_.z), wrap(0), canonical(std::forward<CanonicalTileID>(canonical_)) { assert(overscaledZ >= canonical.z); } inline bool OverscaledTileID::operator==(const OverscaledTileID& rhs) const { - return overscaledZ == rhs.overscaledZ && canonical == rhs.canonical; + return overscaledZ == rhs.overscaledZ && wrap == rhs.wrap &&canonical == rhs.canonical; } inline bool OverscaledTileID::operator!=(const OverscaledTileID& rhs) const { - return overscaledZ != rhs.overscaledZ || canonical != rhs.canonical; + return overscaledZ != rhs.overscaledZ || wrap != rhs.wrap || canonical != rhs.canonical; } inline bool OverscaledTileID::operator<(const OverscaledTileID& rhs) const { - return std::tie(overscaledZ, canonical) < std::tie(rhs.overscaledZ, rhs.canonical); + return std::tie(overscaledZ, wrap, canonical) < std::tie(rhs.overscaledZ, rhs.wrap, rhs.canonical); } inline uint32_t OverscaledTileID::overscaleFactor() const { @@ -183,10 +184,10 @@ inline bool OverscaledTileID::isChildOf(const OverscaledTileID& rhs) const { } inline OverscaledTileID OverscaledTileID::scaledTo(uint8_t z) const { - return { z, z >= canonical.z ? canonical : canonical.scaledTo(z) }; + return { z, wrap, z >= canonical.z ? canonical : canonical.scaledTo(z) }; } -inline UnwrappedTileID OverscaledTileID::unwrapTo(int16_t wrap) const { +inline UnwrappedTileID OverscaledTileID::toUnwrapped() const { return { wrap, canonical }; } @@ -232,7 +233,7 @@ inline std::array<UnwrappedTileID, 4> UnwrappedTileID::children() const { inline OverscaledTileID UnwrappedTileID::overscaleTo(const uint8_t overscaledZ) const { assert(overscaledZ >= canonical.z); - return { overscaledZ, canonical }; + return { overscaledZ, wrap, canonical }; } inline float UnwrappedTileID::pixelsToTileUnits(const float pixelValue, const float zoom) const { @@ -252,7 +253,7 @@ template <> struct hash<mbgl::CanonicalTileID> { return seed; } }; - + template <> struct hash<mbgl::UnwrappedTileID> { size_t operator()(const mbgl::UnwrappedTileID &id) const { std::size_t seed = 0; @@ -261,7 +262,7 @@ template <> struct hash<mbgl::UnwrappedTileID> { return seed; } }; - + template <> struct hash<mbgl::OverscaledTileID> { size_t operator()(const mbgl::OverscaledTileID &id) const { std::size_t seed = 0; diff --git a/src/mbgl/tile/tile_id_io.cpp b/src/mbgl/tile/tile_id_io.cpp index f6adbf183f..d8be6b93d6 100644 --- a/src/mbgl/tile/tile_id_io.cpp +++ b/src/mbgl/tile/tile_id_io.cpp @@ -6,6 +6,8 @@ namespace mbgl { ::std::ostream& operator<<(::std::ostream& os, const CanonicalTileID& rhs) { + // Uncomment this to create code instead of shorthands. + // return os << "CanonicalTileID{ " << uint32_t(rhs.z) << ", " << rhs.x << ", " << rhs.y << " }"; return os << uint32_t(rhs.z) << "/" << rhs.x << "/" << rhs.y; } @@ -26,6 +28,9 @@ std::string toString(const OverscaledTileID& rhs) { } // namespace util ::std::ostream& operator<<(::std::ostream& os, const UnwrappedTileID& rhs) { + // Uncomment this to create code instead of shorthands. + // return os << "UnwrappedTileID{ " << uint32_t(rhs.wrap) << ", { " << uint32_t(rhs.canonical.z) + // << ", " << rhs.canonical.x << ", " << rhs.canonical.y << " } }"; return os << rhs.canonical << (rhs.wrap >= 0 ? "+" : "") << rhs.wrap; } diff --git a/src/mbgl/tile/tile_loader.hpp b/src/mbgl/tile/tile_loader.hpp index 0d64f647d7..bc408ebaf6 100644 --- a/src/mbgl/tile/tile_loader.hpp +++ b/src/mbgl/tile/tile_loader.hpp @@ -10,17 +10,14 @@ class FileSource; class AsyncRequest; class Response; class Tileset; - -namespace style { -class UpdateParameters; -} // namespace style +class TileParameters; template <typename T> class TileLoader : private util::noncopyable { public: TileLoader(T&, const OverscaledTileID&, - const style::UpdateParameters&, + const TileParameters&, const Tileset&); ~TileLoader(); diff --git a/src/mbgl/tile/tile_loader_impl.hpp b/src/mbgl/tile/tile_loader_impl.hpp index 9a5b35a7af..899cbaf9b0 100644 --- a/src/mbgl/tile/tile_loader_impl.hpp +++ b/src/mbgl/tile/tile_loader_impl.hpp @@ -2,7 +2,7 @@ #include <mbgl/tile/tile_loader.hpp> #include <mbgl/storage/file_source.hpp> -#include <mbgl/style/update_parameters.hpp> +#include <mbgl/renderer/tile_parameters.hpp> #include <mbgl/util/tileset.hpp> #include <cassert> @@ -12,7 +12,7 @@ namespace mbgl { template <typename T> TileLoader<T>::TileLoader(T& tile_, const OverscaledTileID& id, - const style::UpdateParameters& parameters, + const TileParameters& parameters, const Tileset& tileset) : tile(tile_), necessity(Necessity::Optional), diff --git a/src/mbgl/tile/vector_tile.cpp b/src/mbgl/tile/vector_tile.cpp index a195885415..e2e700b7b7 100644 --- a/src/mbgl/tile/vector_tile.cpp +++ b/src/mbgl/tile/vector_tile.cpp @@ -1,81 +1,15 @@ #include <mbgl/tile/vector_tile.hpp> +#include <mbgl/tile/vector_tile_data.hpp> #include <mbgl/tile/tile_loader_impl.hpp> -#include <mbgl/tile/geometry_tile_data.hpp> - -#include <protozero/pbf_reader.hpp> - -#include <unordered_map> -#include <unordered_map> -#include <functional> -#include <utility> +#include <mbgl/renderer/tile_parameters.hpp> namespace mbgl { -class VectorTileLayer; - -using packed_iter_type = protozero::iterator_range<protozero::pbf_reader::const_uint32_iterator>; - -class VectorTileFeature : public GeometryTileFeature { -public: - VectorTileFeature(protozero::pbf_reader, const VectorTileLayer&); - - FeatureType getType() const override { return type; } - optional<Value> getValue(const std::string&) const override; - std::unordered_map<std::string,Value> getProperties() const override; - optional<FeatureIdentifier> getID() const override; - GeometryCollection getGeometries() const override; - -private: - const VectorTileLayer& layer; - optional<FeatureIdentifier> id; - FeatureType type = FeatureType::Unknown; - packed_iter_type tags_iter; - packed_iter_type geometry_iter; -}; - -class VectorTileLayer : public GeometryTileLayer { -public: - VectorTileLayer(protozero::pbf_reader); - - std::size_t featureCount() const override { return features.size(); } - std::unique_ptr<GeometryTileFeature> getFeature(std::size_t) const override; - std::string getName() const override; - -private: - friend class VectorTileData; - friend class VectorTileFeature; - - std::string name; - uint32_t version = 1; - uint32_t extent = 4096; - std::unordered_map<std::string, uint32_t> keysMap; - std::vector<std::reference_wrapper<const std::string>> keys; - std::vector<Value> values; - std::vector<protozero::pbf_reader> features; -}; - -class VectorTileData : public GeometryTileData { -public: - VectorTileData(std::shared_ptr<const std::string> data); - - std::unique_ptr<GeometryTileData> clone() const override { - return std::make_unique<VectorTileData>(*this); - } - - const GeometryTileLayer* getLayer(const std::string&) const override; - -private: - std::shared_ptr<const std::string> data; - mutable bool parsed = false; - mutable std::unordered_map<std::string, VectorTileLayer> layers; -}; - VectorTile::VectorTile(const OverscaledTileID& id_, std::string sourceID_, - const style::UpdateParameters& parameters, + const TileParameters& parameters, const Tileset& tileset) - : GeometryTile(id_, sourceID_, parameters), - loader(*this, id_, parameters, tileset) { + : GeometryTile(id_, sourceID_, parameters), loader(*this, id_, parameters, tileset) { } void VectorTile::setNecessity(Necessity necessity) { @@ -91,214 +25,4 @@ void VectorTile::setData(std::shared_ptr<const std::string> data_, GeometryTile::setData(data_ ? std::make_unique<VectorTileData>(data_) : nullptr); } -Value parseValue(protozero::pbf_reader data) { - while (data.next()) - { - switch (data.tag()) { - case 1: // string_value - return data.get_string(); - case 2: // float_value - return static_cast<double>(data.get_float()); - case 3: // double_value - return data.get_double(); - case 4: // int_value - return data.get_int64(); - case 5: // uint_value - return data.get_uint64(); - case 6: // sint_value - return data.get_sint64(); - case 7: // bool_value - return data.get_bool(); - default: - data.skip(); - break; - } - } - return false; -} - -VectorTileFeature::VectorTileFeature(protozero::pbf_reader feature_pbf, const VectorTileLayer& layer_) - : layer(layer_) { - while (feature_pbf.next()) { - switch (feature_pbf.tag()) { - case 1: // id - id = { feature_pbf.get_uint64() }; - break; - case 2: // tags - tags_iter = feature_pbf.get_packed_uint32(); - break; - case 3: // type - type = static_cast<FeatureType>(feature_pbf.get_enum()); - break; - case 4: // geometry - geometry_iter = feature_pbf.get_packed_uint32(); - break; - default: - feature_pbf.skip(); - break; - } - } -} - -optional<Value> VectorTileFeature::getValue(const std::string& key) const { - auto keyIter = layer.keysMap.find(key); - if (keyIter == layer.keysMap.end()) { - return optional<Value>(); - } - - auto start_itr = tags_iter.begin(); - const auto & end_itr = tags_iter.end(); - while (start_itr != end_itr) { - uint32_t tag_key = static_cast<uint32_t>(*start_itr++); - - if (layer.keysMap.size() <= tag_key) { - throw std::runtime_error("feature referenced out of range key"); - } - - if (start_itr == end_itr) { - throw std::runtime_error("uneven number of feature tag ids"); - } - - uint32_t tag_val = static_cast<uint32_t>(*start_itr++);; - if (layer.values.size() <= tag_val) { - throw std::runtime_error("feature referenced out of range value"); - } - - if (tag_key == keyIter->second) { - return layer.values[tag_val]; - } - } - - return optional<Value>(); -} - -std::unordered_map<std::string,Value> VectorTileFeature::getProperties() const { - std::unordered_map<std::string,Value> properties; - auto start_itr = tags_iter.begin(); - const auto & end_itr = tags_iter.end(); - while (start_itr != end_itr) { - uint32_t tag_key = static_cast<uint32_t>(*start_itr++); - if (start_itr == end_itr) { - throw std::runtime_error("uneven number of feature tag ids"); - } - uint32_t tag_val = static_cast<uint32_t>(*start_itr++); - properties[layer.keys.at(tag_key)] = layer.values.at(tag_val); - } - return properties; -} - -optional<FeatureIdentifier> VectorTileFeature::getID() const { - return id; -} - -GeometryCollection VectorTileFeature::getGeometries() const { - uint8_t cmd = 1; - uint32_t length = 0; - int32_t x = 0; - int32_t y = 0; - const float scale = float(util::EXTENT) / layer.extent; - - GeometryCollection lines; - - lines.emplace_back(); - GeometryCoordinates* line = &lines.back(); - - auto g_itr = geometry_iter.begin(); - while (g_itr != geometry_iter.end()) { - if (length == 0) { - uint32_t cmd_length = static_cast<uint32_t>(*g_itr++); - cmd = cmd_length & 0x7; - length = cmd_length >> 3; - } - - --length; - - if (cmd == 1 || cmd == 2) { - x += protozero::decode_zigzag32(static_cast<uint32_t>(*g_itr++)); - y += protozero::decode_zigzag32(static_cast<uint32_t>(*g_itr++)); - - if (cmd == 1 && !line->empty()) { // moveTo - lines.emplace_back(); - line = &lines.back(); - } - - line->emplace_back(::round(x * scale), ::round(y * scale)); - - } else if (cmd == 7) { // closePolygon - if (!line->empty()) { - line->push_back((*line)[0]); - } - - } else { - throw std::runtime_error("unknown command"); - } - } - - if (layer.version >= 2 || type != FeatureType::Polygon) { - return lines; - } - - return fixupPolygons(lines); -} - -VectorTileData::VectorTileData(std::shared_ptr<const std::string> data_) - : data(std::move(data_)) { -} - -const GeometryTileLayer* VectorTileData::getLayer(const std::string& name) const { - if (!parsed) { - parsed = true; - protozero::pbf_reader tile_pbf(*data); - while (tile_pbf.next(3)) { - VectorTileLayer layer(tile_pbf.get_message()); - layers.emplace(layer.name, std::move(layer)); - } - } - - auto it = layers.find(name); - if (it != layers.end()) { - return &it->second; - } - return nullptr; -} - -VectorTileLayer::VectorTileLayer(protozero::pbf_reader layer_pbf) { - while (layer_pbf.next()) { - switch (layer_pbf.tag()) { - case 1: // name - name = layer_pbf.get_string(); - break; - case 2: // feature - features.push_back(layer_pbf.get_message()); - break; - case 3: // keys - { - auto iter = keysMap.emplace(layer_pbf.get_string(), keysMap.size()); - keys.emplace_back(std::reference_wrapper<const std::string>(iter.first->first)); - } - break; - case 4: // values - values.emplace_back(parseValue(layer_pbf.get_message())); - break; - case 5: // extent - extent = layer_pbf.get_uint32(); - break; - case 15: // version - version = layer_pbf.get_uint32(); - break; - default: - layer_pbf.skip(); - break; - } - } -} - -std::unique_ptr<GeometryTileFeature> VectorTileLayer::getFeature(std::size_t i) const { - return std::make_unique<VectorTileFeature>(features.at(i), *this); -} - -std::string VectorTileLayer::getName() const { - return name; -} - } // namespace mbgl diff --git a/src/mbgl/tile/vector_tile.hpp b/src/mbgl/tile/vector_tile.hpp index 2568a277e6..566cde4f37 100644 --- a/src/mbgl/tile/vector_tile.hpp +++ b/src/mbgl/tile/vector_tile.hpp @@ -6,16 +6,13 @@ namespace mbgl { class Tileset; - -namespace style { -class UpdateParameters; -} // namespace style +class TileParameters; class VectorTile : public GeometryTile { public: VectorTile(const OverscaledTileID&, std::string sourceID, - const style::UpdateParameters&, + const TileParameters&, const Tileset&); void setNecessity(Necessity) final; diff --git a/src/mbgl/tile/vector_tile_data.cpp b/src/mbgl/tile/vector_tile_data.cpp new file mode 100644 index 0000000000..2d4a01bda3 --- /dev/null +++ b/src/mbgl/tile/vector_tile_data.cpp @@ -0,0 +1,89 @@ +#include <mbgl/tile/vector_tile_data.hpp> +#include <mbgl/util/constants.hpp> + +namespace mbgl { + +VectorTileFeature::VectorTileFeature(const mapbox::vector_tile::layer& layer, + const protozero::data_view& view) + : feature(view, layer) { +} + +FeatureType VectorTileFeature::getType() const { + switch (feature.getType()) { + case mapbox::vector_tile::GeomType::POINT: + return FeatureType::Point; + case mapbox::vector_tile::GeomType::LINESTRING: + return FeatureType::LineString; + case mapbox::vector_tile::GeomType::POLYGON: + return FeatureType::Polygon; + default: + return FeatureType::Unknown; + } +} + +optional<Value> VectorTileFeature::getValue(const std::string& key) const { + return feature.getValue(key); +} + +std::unordered_map<std::string, Value> VectorTileFeature::getProperties() const { + return feature.getProperties(); +} + +optional<FeatureIdentifier> VectorTileFeature::getID() const { + return feature.getID(); +} + +GeometryCollection VectorTileFeature::getGeometries() const { + const float scale = float(util::EXTENT) / feature.getExtent(); + auto lines = feature.getGeometries<GeometryCollection>(scale); + if (feature.getVersion() >= 2 || feature.getType() != mapbox::vector_tile::GeomType::POLYGON) { + return lines; + } else { + return fixupPolygons(lines); + } +} + +VectorTileLayer::VectorTileLayer(std::shared_ptr<const std::string> data_, + const protozero::data_view& view) + : data(std::move(data_)), layer(view) { +} + +std::size_t VectorTileLayer::featureCount() const { + return layer.featureCount(); +} + +std::unique_ptr<GeometryTileFeature> VectorTileLayer::getFeature(std::size_t i) const { + return std::make_unique<VectorTileFeature>(layer, layer.getFeature(i)); +} + +std::string VectorTileLayer::getName() const { + return layer.getName(); +} + +VectorTileData::VectorTileData(std::shared_ptr<const std::string> data_) : data(std::move(data_)) { +} + +std::unique_ptr<GeometryTileData> VectorTileData::clone() const { + return std::make_unique<VectorTileData>(data); +} + +std::unique_ptr<GeometryTileLayer> VectorTileData::getLayer(const std::string& name) const { + if (!parsed) { + // We're parsing this lazily so that we can construct VectorTileData objects on the main + // thread without incurring the overhead of parsing immediately. + layers = mapbox::vector_tile::buffer(*data).getLayers(); + parsed = true; + } + + auto it = layers.find(name); + if (it != layers.end()) { + return std::make_unique<VectorTileLayer>(data, it->second); + } + return nullptr; +} + +std::vector<std::string> VectorTileData::layerNames() const { + return mapbox::vector_tile::buffer(*data).layerNames(); +} + +} // namespace mbgl diff --git a/src/mbgl/tile/vector_tile_data.hpp b/src/mbgl/tile/vector_tile_data.hpp new file mode 100644 index 0000000000..48beaf9d07 --- /dev/null +++ b/src/mbgl/tile/vector_tile_data.hpp @@ -0,0 +1,54 @@ +#include <mbgl/tile/geometry_tile_data.hpp> + +#include <mapbox/vector_tile.hpp> +#include <protozero/pbf_reader.hpp> + +#include <unordered_map> +#include <functional> +#include <utility> + +namespace mbgl { + +class VectorTileFeature : public GeometryTileFeature { +public: + VectorTileFeature(const mapbox::vector_tile::layer&, const protozero::data_view&); + + FeatureType getType() const override; + optional<Value> getValue(const std::string& key) const override; + std::unordered_map<std::string, Value> getProperties() const override; + optional<FeatureIdentifier> getID() const override; + GeometryCollection getGeometries() const override; + +private: + mapbox::vector_tile::feature feature; +}; + +class VectorTileLayer : public GeometryTileLayer { +public: + VectorTileLayer(std::shared_ptr<const std::string> data, const protozero::data_view&); + + std::size_t featureCount() const override; + std::unique_ptr<GeometryTileFeature> getFeature(std::size_t i) const override; + std::string getName() const override; + +private: + std::shared_ptr<const std::string> data; + mapbox::vector_tile::layer layer; +}; + +class VectorTileData : public GeometryTileData { +public: + VectorTileData(std::shared_ptr<const std::string> data); + + std::unique_ptr<GeometryTileData> clone() const override; + std::unique_ptr<GeometryTileLayer> getLayer(const std::string& name) const override; + + std::vector<std::string> layerNames() const; + +private: + std::shared_ptr<const std::string> data; + mutable bool parsed = false; + mutable std::map<std::string, const protozero::data_view> layers; +}; + +} // namespace mbgl |