diff options
author | John Firebaugh <john.firebaugh@gmail.com> | 2016-06-13 10:59:33 -0700 |
---|---|---|
committer | John Firebaugh <john.firebaugh@gmail.com> | 2016-06-13 10:59:33 -0700 |
commit | 5c7dfd948ffd52f2b60dcfe052176da788f17893 (patch) | |
tree | 596d02b0e28d6e7649f9527af2834c90c3c3b056 /src/mbgl/tile | |
parent | 3ab7c1cca3aa4658b40af1d7d591850e005d011e (diff) | |
download | qtlocation-mapboxgl-5c7dfd948ffd52f2b60dcfe052176da788f17893.tar.gz |
[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.
Diffstat (limited to 'src/mbgl/tile')
21 files changed, 604 insertions, 610 deletions
diff --git a/src/mbgl/tile/geojson_tile.cpp b/src/mbgl/tile/geojson_tile.cpp index 4bea00bb45..b702400d47 100644 --- a/src/mbgl/tile/geojson_tile.cpp +++ b/src/mbgl/tile/geojson_tile.cpp @@ -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; } diff --git a/src/mbgl/tile/geojson_tile.hpp b/src/mbgl/tile/geojson_tile.hpp index 613ef2d962..9cdc705d32 100644 --- a/src/mbgl/tile/geojson_tile.hpp +++ b/src/mbgl/tile/geojson_tile.hpp @@ -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; }; diff --git a/src/mbgl/tile/geometry_tile.cpp b/src/mbgl/tile/geometry_tile.cpp index f4589b4052..cded448656 100644 --- a/src/mbgl/tile/geometry_tile.cpp +++ b/src/mbgl/tile/geometry_tile.cpp @@ -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)); +void GeometryTile::setData(std::unique_ptr<GeometryTileData> data_, + optional<Timestamp> modified_, + optional<Timestamp> expires_) { + modified = modified_; + expires = expires_; + + 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; } - 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); + // 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; } - // 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); - } - } -} + // 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(); -GeometryCollection fixupPolygons(const GeometryCollection& rings) { - ClipperLib::Clipper clipper; - clipper.StrictlySimple(true); + if (result.is<TileParseResultData>()) { + auto& resultBuckets = result.get<TileParseResultData>(); + availableData = resultBuckets.complete ? DataAvailability::All : DataAvailability::Some; - for (const auto& ring : rings) { - clipper.AddPath(toClipperPath(ring), ClipperLib::ptSubject, 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; - ClipperLib::PolyTree polygons; - clipper.Execute(ClipperLib::ctUnion, polygons, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd); - clipper.Clear(); + // 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); - GeometryCollection result; - for (auto * polynode : polygons.Childs) { - processPolynodeBranch(polynode, result); - } - return result; -} + if (isComplete()) { + featureIndex = std::move(resultBuckets.featureIndex); + data = std::move(resultBuckets.tileData); + } -std::vector<GeometryCollection> classifyRings(const GeometryCollection& rings) { - std::vector<GeometryCollection> polygons; + redoPlacement(); + observer->onTileLoaded(*this, true); + } else { + availableData = DataAvailability::All; + observer->onTileError(*this, result.get<std::exception_ptr>()); + } + }); +} - std::size_t len = rings.size(); +GeometryTile::~GeometryTile() { + cancel(); +} - 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); + } + + // 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 == 0) - ccw = (area < 0 ? -1 : 1); + if (isComplete()) { + featureIndex = std::move(resultBuckets.featureIndex); + data = std::move(resultBuckets.tileData); + } - if (ccw == (area < 0 ? -1 : 1) && !polygon.empty()) { - polygons.push_back(polygon); - polygon.clear(); + redoPlacement(); + observer->onTileLoaded(*this, false); + } else { + availableData = DataAvailability::All; + observer->onTileError(*this, result.get<std::exception_ptr>()); } + }); + + return true; +} - polygon.push_back(rings[i]); +Bucket* GeometryTile::getBucket(const style::Layer& layer) { + const auto it = buckets.find(layer.baseImpl->bucketName()); + if (it == buckets.end()) { + return nullptr; } - if (!polygon.empty()) - polygons.push_back(polygon); + assert(it->second); + return it->second.get(); +} - return polygons; +void GeometryTile::redoPlacement(const PlacementConfig newConfig) { + targetConfig = newConfig; + redoPlacement(); } -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::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; } -} -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); - } + workRequest = worker.redoPlacement(tileWorker, buckets, targetConfig, [this, config = targetConfig](std::unique_ptr<CollisionTile> collisionTile) { + workRequest.reset(); - 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; - } + // 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(); } - 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; - } + if (featureIndex) { + featureIndex->setCollisionTile(std::move(collisionTile)); } - 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; - } + // 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(); } - } + }); +} - // Unreachable, but placate GCC. - return Point<double>(); +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); } -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 diff --git a/src/mbgl/tile/geometry_tile.hpp b/src/mbgl/tile/geometry_tile.hpp index 80d6d6031d..4c5d08ee46 100644 --- a/src/mbgl/tile/geometry_tile.hpp +++ b/src/mbgl/tile/geometry_tile.hpp @@ -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 CanonicalTileID; +class AsyncRequest; +class GeometryTileData; +class FeatureIndex; -// 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>; +namespace style { +class Style; +} -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); -class GeometryCollection : public std::vector<GeometryCoordinates> { -public: - using coordinate_type = int16_t; - using std::vector<GeometryCoordinates>::vector; -}; + ~GeometryTile(); -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; -}; + void setError(std::exception_ptr err); -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; -}; + void setData(std::unique_ptr<GeometryTileData>, + optional<Timestamp> modified_, + optional<Timestamp> expires_); -class GeometryTile : private util::noncopyable { -public: - virtual ~GeometryTile() = default; - virtual util::ptr<GeometryTileLayer> getLayer(const std::string&) const = 0; -}; + 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; -// classifies an array of rings into polygons with outer rings and holes -std::vector<GeometryCollection> classifyRings(const GeometryCollection&); +private: + void redoPlacement(); -// Truncate polygon to the largest `maxHoles` inner rings by area. -void limitHoles(GeometryCollection&, uint32_t maxHoles); + style::Style& style; + Worker& worker; + TileWorker tileWorker; -// convert from GeometryTileFeature to Feature (eventually we should eliminate GeometryTileFeature) -Feature convertFeature(const GeometryTileFeature&, const CanonicalTileID&); + std::unique_ptr<AsyncRequest> workRequest; -// 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&); + // 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 }; +}; } // namespace mbgl diff --git a/src/mbgl/tile/geometry_tile_data.cpp b/src/mbgl/tile/geometry_tile_data.cpp index 39a379a8ed..6e700aa633 100644 --- a/src/mbgl/tile/geometry_tile_data.cpp +++ b/src/mbgl/tile/geometry_tile_data.cpp @@ -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); + 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; } -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; +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; +} - // 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; +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; +} - // 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(); +static void processPolynodeBranch(ClipperLib::PolyNode* polynode, GeometryCollection& rings) { + // Exterior ring. + rings.push_back(fromClipperPath(polynode->Contour)); + assert(signedArea(rings.back()) > 0); - if (result.is<TileParseResultData>()) { - auto& resultBuckets = result.get<TileParseResultData>(); - availableData = resultBuckets.complete ? DataAvailability::All : DataAvailability::Some; + // Interior rings. + for (auto * ring : polynode->Childs) { + rings.push_back(fromClipperPath(ring->Contour)); + assert(signedArea(rings.back()) < 0); + } - // 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; + // 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); + } + } +} - // 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); +GeometryCollection fixupPolygons(const GeometryCollection& rings) { + ClipperLib::Clipper clipper; + clipper.StrictlySimple(true); - if (isComplete()) { - featureIndex = std::move(resultBuckets.featureIndex); - geometryTile = std::move(resultBuckets.geometryTile); - } + for (const auto& ring : rings) { + clipper.AddPath(toClipperPath(ring), ClipperLib::ptSubject, true); + } - redoPlacement(); - observer->onTileLoaded(*this, true); - } else { - availableData = DataAvailability::All; - observer->onTileError(*this, result.get<std::exception_ptr>()); - } - }); -} + ClipperLib::PolyTree polygons; + clipper.Execute(ClipperLib::ctUnion, polygons, ClipperLib::pftEvenOdd, ClipperLib::pftEvenOdd); + clipper.Clear(); -GeometryTileData::~GeometryTileData() { - cancel(); + GeometryCollection result; + for (auto * polynode : polygons.Childs) { + processPolynodeBranch(polynode, result); + } + return result; } -bool GeometryTileData::parsePending() { - if (workRequest) { - // There's already parsing or placement going on. - return false; - } +std::vector<GeometryCollection> classifyRings(const GeometryCollection& rings) { + std::vector<GeometryCollection> polygons; + + std::size_t len = rings.size(); - workRequest.reset(); - workRequest = worker.parsePendingGeometryTileLayers(tileWorker, targetConfig, [this, config = targetConfig] (TileParseResult result) { - workRequest.reset(); + if (len <= 1) { + polygons.push_back(rings); + return polygons; + } - if (result.is<TileParseResultData>()) { - auto& resultBuckets = result.get<TileParseResultData>(); - availableData = resultBuckets.complete ? DataAvailability::All : DataAvailability::Some; + GeometryCollection polygon; + int8_t ccw = 0; - // 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); - } + for (std::size_t i = 0; i < len; i++) { + double area = signedArea(rings[i]); - // 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 (area == 0) + continue; - if (isComplete()) { - featureIndex = std::move(resultBuckets.featureIndex); - geometryTile = std::move(resultBuckets.geometryTile); - } + if (ccw == 0) + ccw = (area < 0 ? -1 : 1); - redoPlacement(); - observer->onTileLoaded(*this, false); - } else { - availableData = DataAvailability::All; - observer->onTileError(*this, result.get<std::exception_ptr>()); + if (ccw == (area < 0 ? -1 : 1) && !polygon.empty()) { + polygons.push_back(polygon); + polygon.clear(); } - }); - - return true; -} -Bucket* GeometryTileData::getBucket(const style::Layer& layer) { - const auto it = buckets.find(layer.baseImpl->bucketName()); - if (it == buckets.end()) { - return nullptr; + polygon.push_back(rings[i]); } - assert(it->second); - return it->second.get(); -} + if (!polygon.empty()) + polygons.push_back(polygon); -void GeometryTileData::redoPlacement(const PlacementConfig newConfig) { - targetConfig = newConfig; - redoPlacement(); + return polygons; } -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; +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); } +} - 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; +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); + } - for (auto& bucket : buckets) { - bucket.second->swapRenderData(); + 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; + } } - if (featureIndex) { - featureIndex->setCollisionTile(std::move(collisionTile)); + 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; + } } - // 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(); + 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; + } } - }); -} + } -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); + // Unreachable, but placate GCC. + return Point<double>(); } -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 diff --git a/src/mbgl/tile/geometry_tile_data.hpp b/src/mbgl/tile/geometry_tile_data.hpp index 6c7ff2f3d9..753ba6b8a2 100644 --- a/src/mbgl/tile/geometry_tile_data.hpp +++ b/src/mbgl/tile/geometry_tile_data.hpp @@ -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 <memory> +#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 <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; +enum class FeatureType : uint8_t { + Unknown = 0, + Point = 1, + LineString = 2, + Polygon = 3 +}; - void redoPlacement(PlacementConfig) override; +class CanonicalTileID; - void queryRenderedFeatures( - std::unordered_map<std::string, std::vector<Feature>>& result, - const GeometryCoordinates& queryGeometry, - const TransformState&, - const optional<std::vector<std::string>>& layerIDs) override; +// 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>; - void cancel() override; +class GeometryCoordinates : public std::vector<GeometryCoordinate> { +public: + using coordinate_type = int16_t; + using std::vector<GeometryCoordinate>::vector; +}; -private: - void redoPlacement(); +class GeometryCollection : public std::vector<GeometryCoordinates> { +public: + using coordinate_type = int16_t; + using std::vector<GeometryCoordinates>::vector; +}; - style::Style& style; - Worker& worker; - TileWorker tileWorker; +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; +}; - std::unique_ptr<AsyncRequest> workRequest; +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; +}; - // 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; +class GeometryTileData : private util::noncopyable { +public: + virtual ~GeometryTileData() = default; + virtual util::ptr<GeometryTileLayer> getLayer(const std::string&) const = 0; +}; - std::unique_ptr<FeatureIndex> featureIndex; - std::unique_ptr<const GeometryTile> geometryTile; +// classifies an array of rings into polygons with outer rings and holes +std::vector<GeometryCollection> classifyRings(const GeometryCollection&); - // Stores the placement configuration of the text that is currently placed on the screen. - PlacementConfig placedConfig; +// Truncate polygon to the largest `maxHoles` inner rings by area. +void limitHoles(GeometryCollection&, uint32_t maxHoles); - // Stores the placement configuration of how the text should be placed. This isn't necessarily - // the one that is being displayed. - PlacementConfig targetConfig; +// convert from GeometryTileFeature to Feature (eventually we should eliminate GeometryTileFeature) +Feature convertFeature(const GeometryTileFeature&, const CanonicalTileID&); - // Used to signal the worker that it should abandon parsing this tile as soon as possible. - util::Atomic<bool> obsolete { false }; -}; +// 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 diff --git a/src/mbgl/tile/raster_tile_data.cpp b/src/mbgl/tile/raster_tile.cpp index 7737f1fb7d..c3838bc59b 100644 --- a/src/mbgl/tile/raster_tile_data.cpp +++ b/src/mbgl/tile/raster_tile.cpp @@ -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(); } diff --git a/src/mbgl/tile/raster_tile_data.hpp b/src/mbgl/tile/raster_tile.hpp index 7c224ad812..eebfbe6b9c 100644 --- a/src/mbgl/tile/raster_tile_data.hpp +++ b/src/mbgl/tile/raster_tile.hpp @@ -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 diff --git a/src/mbgl/tile/tile.cpp b/src/mbgl/tile/tile.cpp new file mode 100644 index 0000000000..846cda26cf --- /dev/null +++ b/src/mbgl/tile/tile.cpp @@ -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 diff --git a/src/mbgl/tile/tile_data.hpp b/src/mbgl/tile/tile.hpp index 4eee82ef4c..058e41a024 100644 --- a/src/mbgl/tile/tile_data.hpp +++ b/src/mbgl/tile/tile.hpp @@ -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 diff --git a/src/mbgl/tile/tile_cache.cpp b/src/mbgl/tile/tile_cache.cpp index 619d813fd2..3fafb1259c 100644 --- a/src/mbgl/tile/tile_cache.cpp +++ b/src/mbgl/tile/tile_cache.cpp @@ -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) { diff --git a/src/mbgl/tile/tile_cache.hpp b/src/mbgl/tile/tile_cache.hpp index edaa6bd680..80fe98a20c 100644 --- a/src/mbgl/tile/tile_cache.hpp +++ b/src/mbgl/tile/tile_cache.hpp @@ -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; diff --git a/src/mbgl/tile/tile_data.cpp b/src/mbgl/tile/tile_data.cpp deleted file mode 100644 index 7046d2e7db..0000000000 --- a/src/mbgl/tile/tile_data.cpp +++ /dev/null @@ -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 diff --git a/src/mbgl/tile/tile_data_observer.hpp b/src/mbgl/tile/tile_data_observer.hpp deleted file mode 100644 index b950fc0b72..0000000000 --- a/src/mbgl/tile/tile_data_observer.hpp +++ /dev/null @@ -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 diff --git a/src/mbgl/tile/tile_observer.hpp b/src/mbgl/tile/tile_observer.hpp new file mode 100644 index 0000000000..96ded11fbb --- /dev/null +++ b/src/mbgl/tile/tile_observer.hpp @@ -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 diff --git a/src/mbgl/tile/tile_source.hpp b/src/mbgl/tile/tile_source.hpp index f1a0a1c922..b4aff4492f 100644 --- a/src/mbgl/tile/tile_source.hpp +++ b/src/mbgl/tile/tile_source.hpp @@ -58,7 +58,7 @@ private: void loadedData(const Response&); void loadRequired(); - T& tileData; + T& tile; Necessity necessity; Resource resource; FileSource& fileSource; diff --git a/src/mbgl/tile/tile_source_impl.hpp b/src/mbgl/tile/tile_source_impl.hpp index 625a0e2020..51591aa534 100644 --- a/src/mbgl/tile/tile_source_impl.hpp +++ b/src/mbgl/tile/tile_source_impl.hpp @@ -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); } } diff --git a/src/mbgl/tile/tile_worker.cpp b/src/mbgl/tile/tile_worker.cpp index 1890aa7c47..358cfd3ca9 100644 --- a/src/mbgl/tile/tile_worker.cpp +++ b/src/mbgl/tile/tile_worker.cpp @@ -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) { diff --git a/src/mbgl/tile/tile_worker.hpp b/src/mbgl/tile/tile_worker.hpp index 631a8c929f..b325459682 100644 --- a/src/mbgl/tile/tile_worker.hpp +++ b/src/mbgl/tile/tile_worker.hpp @@ -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. diff --git a/src/mbgl/tile/vector_tile.cpp b/src/mbgl/tile/vector_tile.cpp index dc4ed04d7f..cd61b52c8e 100644 --- a/src/mbgl/tile/vector_tile.cpp +++ b/src/mbgl/tile/vector_tile.cpp @@ -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); diff --git a/src/mbgl/tile/vector_tile.hpp b/src/mbgl/tile/vector_tile.hpp index 4815f9276e..a7e808af4e 100644 --- a/src/mbgl/tile/vector_tile.hpp +++ b/src/mbgl/tile/vector_tile.hpp @@ -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 |