diff options
Diffstat (limited to 'src/mbgl')
-rw-r--r-- | src/mbgl/algorithm/update_renderables.hpp | 6 | ||||
-rw-r--r-- | src/mbgl/annotation/render_annotation_source.cpp | 1 | ||||
-rw-r--r-- | src/mbgl/renderer/sources/render_custom_geometry_source.cpp | 1 | ||||
-rw-r--r-- | src/mbgl/renderer/sources/render_geojson_source.cpp | 1 | ||||
-rw-r--r-- | src/mbgl/renderer/sources/render_raster_source.cpp | 1 | ||||
-rw-r--r-- | src/mbgl/renderer/sources/render_vector_source.cpp | 1 | ||||
-rw-r--r-- | src/mbgl/renderer/tile_pyramid.cpp | 11 | ||||
-rw-r--r-- | src/mbgl/renderer/tile_pyramid.hpp | 1 | ||||
-rw-r--r-- | src/mbgl/style/conversion/tileset.cpp | 31 | ||||
-rw-r--r-- | src/mbgl/style/custom_tile_loader.cpp | 11 | ||||
-rw-r--r-- | src/mbgl/util/geo.cpp | 82 | ||||
-rw-r--r-- | src/mbgl/util/tile_range.hpp | 47 |
12 files changed, 191 insertions, 3 deletions
diff --git a/src/mbgl/algorithm/update_renderables.hpp b/src/mbgl/algorithm/update_renderables.hpp index c583b6b2b6..5fbe0d943f 100644 --- a/src/mbgl/algorithm/update_renderables.hpp +++ b/src/mbgl/algorithm/update_renderables.hpp @@ -35,7 +35,11 @@ void updateRenderables(GetTileFn getTile, auto tile = getTile(idealDataTileID); if (!tile) { tile = createTile(idealDataTileID); - assert(tile); + // For source types where TileJSON.bounds is set, tiles outside the + // bounds are not created + if(tile == nullptr) { + continue; + } } // if (source has the tile and bucket is loaded) { diff --git a/src/mbgl/annotation/render_annotation_source.cpp b/src/mbgl/annotation/render_annotation_source.cpp index a0b69af8d5..38ca5ccd0b 100644 --- a/src/mbgl/annotation/render_annotation_source.cpp +++ b/src/mbgl/annotation/render_annotation_source.cpp @@ -41,6 +41,7 @@ void RenderAnnotationSource::update(Immutable<style::Source::Impl> baseImpl_, // Zoom level 16 is typically sufficient for annotations. // See https://github.com/mapbox/mapbox-gl-native/issues/10197 { 0, 16 }, + optional<LatLngBounds> {}, [&] (const OverscaledTileID& tileID) { return std::make_unique<AnnotationTile>(tileID, parameters); }); diff --git a/src/mbgl/renderer/sources/render_custom_geometry_source.cpp b/src/mbgl/renderer/sources/render_custom_geometry_source.cpp index 111f0234ed..df615a7e20 100644 --- a/src/mbgl/renderer/sources/render_custom_geometry_source.cpp +++ b/src/mbgl/renderer/sources/render_custom_geometry_source.cpp @@ -44,6 +44,7 @@ void RenderCustomGeometrySource::update(Immutable<style::Source::Impl> baseImpl_ SourceType::CustomVector, util::tileSize, impl().getZoomRange(), + {}, [&] (const OverscaledTileID& tileID) { return std::make_unique<CustomGeometryTile>(tileID, impl().id, parameters, impl().getTileOptions(), *tileLoader); }); diff --git a/src/mbgl/renderer/sources/render_geojson_source.cpp b/src/mbgl/renderer/sources/render_geojson_source.cpp index d07cfcdc41..8ea80cd813 100644 --- a/src/mbgl/renderer/sources/render_geojson_source.cpp +++ b/src/mbgl/renderer/sources/render_geojson_source.cpp @@ -62,6 +62,7 @@ void RenderGeoJSONSource::update(Immutable<style::Source::Impl> baseImpl_, SourceType::GeoJSON, util::tileSize, impl().getZoomRange(), + optional<LatLngBounds>{}, [&] (const OverscaledTileID& tileID) { return std::make_unique<GeoJSONTile>(tileID, impl().id, parameters, data->getTile(tileID.canonical)); }); diff --git a/src/mbgl/renderer/sources/render_raster_source.cpp b/src/mbgl/renderer/sources/render_raster_source.cpp index f11f9b7aed..e99cd040e9 100644 --- a/src/mbgl/renderer/sources/render_raster_source.cpp +++ b/src/mbgl/renderer/sources/render_raster_source.cpp @@ -52,6 +52,7 @@ void RenderRasterSource::update(Immutable<style::Source::Impl> baseImpl_, SourceType::Raster, impl().getTileSize(), tileset->zoomRange, + tileset->bounds, [&] (const OverscaledTileID& tileID) { return std::make_unique<RasterTile>(tileID, parameters, *tileset); }); diff --git a/src/mbgl/renderer/sources/render_vector_source.cpp b/src/mbgl/renderer/sources/render_vector_source.cpp index 49f8fdff2c..d53023e4d0 100644 --- a/src/mbgl/renderer/sources/render_vector_source.cpp +++ b/src/mbgl/renderer/sources/render_vector_source.cpp @@ -55,6 +55,7 @@ void RenderVectorSource::update(Immutable<style::Source::Impl> baseImpl_, SourceType::Vector, util::tileSize, tileset->zoomRange, + tileset->bounds, [&] (const OverscaledTileID& tileID) { return std::make_unique<VectorTile>(tileID, impl().id, parameters, *tileset); }); diff --git a/src/mbgl/renderer/tile_pyramid.cpp b/src/mbgl/renderer/tile_pyramid.cpp index 6a711fb6d5..e474737f8d 100644 --- a/src/mbgl/renderer/tile_pyramid.cpp +++ b/src/mbgl/renderer/tile_pyramid.cpp @@ -7,6 +7,7 @@ #include <mbgl/map/transform.hpp> #include <mbgl/math/clamp.hpp> #include <mbgl/util/tile_cover.hpp> +#include <mbgl/util/tile_range.hpp> #include <mbgl/util/enum.hpp> #include <mbgl/util/logging.hpp> @@ -14,6 +15,7 @@ #include <mapbox/geometry/envelope.hpp> +#include <cmath> #include <algorithm> namespace mbgl { @@ -61,6 +63,7 @@ void TilePyramid::update(const std::vector<Immutable<style::Layer::Impl>>& layer const SourceType type, const uint16_t tileSize, const Range<uint8_t> zoomRange, + optional<LatLngBounds> bounds, std::function<std::unique_ptr<Tile> (const OverscaledTileID&)> createTile) { // If we need a relayout, abandon any cached tiles; they're now stale. if (needsRelayout) { @@ -135,7 +138,15 @@ void TilePyramid::update(const std::vector<Immutable<style::Layer::Impl>>& layer auto it = tiles.find(tileID); return it == tiles.end() ? nullptr : it->second.get(); }; + + optional<util::TileRange> tileRange = {}; + if (bounds) { + tileRange = util::TileRange::fromLatLngBounds(*bounds, std::min(tileZoom, (int32_t)zoomRange.max)); + } auto createTileFn = [&](const OverscaledTileID& tileID) -> Tile* { + if (tileRange && !tileRange->contains(tileID.canonical)) { + return nullptr; + } std::unique_ptr<Tile> tile = cache.get(tileID); if (!tile) { tile = createTile(tileID); diff --git a/src/mbgl/renderer/tile_pyramid.hpp b/src/mbgl/renderer/tile_pyramid.hpp index feab8a838c..3755cee06d 100644 --- a/src/mbgl/renderer/tile_pyramid.hpp +++ b/src/mbgl/renderer/tile_pyramid.hpp @@ -40,6 +40,7 @@ public: style::SourceType type, uint16_t tileSize, Range<uint8_t> zoomRange, + optional<LatLngBounds> bounds, std::function<std::unique_ptr<Tile> (const OverscaledTileID&)> createTile); void startRender(PaintParameters&); diff --git a/src/mbgl/style/conversion/tileset.cpp b/src/mbgl/style/conversion/tileset.cpp index b9383c41b8..6e559c0cac 100644 --- a/src/mbgl/style/conversion/tileset.cpp +++ b/src/mbgl/style/conversion/tileset.cpp @@ -1,9 +1,14 @@ #include <mbgl/style/conversion/tileset.hpp> +#include <mbgl/util/geo.hpp> namespace mbgl { namespace style { namespace conversion { +bool validateLatitude(const double lat) { + return lat < 90 && lat > -90; +} + optional<Tileset> Converter<Tileset>::operator()(const Convertible& value, Error& error) const { Tileset result; @@ -65,6 +70,32 @@ optional<Tileset> Converter<Tileset>::operator()(const Convertible& value, Error result.attribution = std::move(*attribution); } + auto boundsValue = objectMember(value, "bounds"); + if (boundsValue) { + if (!isArray(*boundsValue) || arrayLength(*boundsValue) != 4) { + error = { "bounds must be an array with left, bottom, top, and right values" }; + return {}; + } + optional<double> left = toDouble(arrayMember(*boundsValue, 0)); + optional<double> bottom = toDouble(arrayMember(*boundsValue, 1)); + optional<double> right = toDouble(arrayMember(*boundsValue, 2)); + optional<double> top = toDouble(arrayMember(*boundsValue, 3)); + + if (!left || !right || !bottom || !top) { + error = { "bounds array must contain numeric longitude and latitude values" }; + return {}; + } + if (!validateLatitude(*bottom) || !validateLatitude(*top) || top <= bottom){ + error = { "bounds latitude values must be between -90 and 90 with bottom less than top" }; + return {}; + } + if(*left >= *right) { + error = { "bounds left longitude should be less than right longitude" }; + return {}; + } + result.bounds = LatLngBounds::hull({ *bottom, *left }, { *top, *right }); + } + return result; } diff --git a/src/mbgl/style/custom_tile_loader.cpp b/src/mbgl/style/custom_tile_loader.cpp index 76248b84bd..1c587302b8 100644 --- a/src/mbgl/style/custom_tile_loader.cpp +++ b/src/mbgl/style/custom_tile_loader.cpp @@ -1,5 +1,6 @@ #include <mbgl/style/custom_tile_loader.hpp> #include <mbgl/tile/custom_geometry_tile.hpp> +#include <mbgl/util/tile_range.hpp> namespace mbgl { namespace style { @@ -79,9 +80,15 @@ void CustomTileLoader::invalidateTile(const CanonicalTileID& tileID) { } void CustomTileLoader::invalidateRegion(const LatLngBounds& bounds, Range<uint8_t> ) { + std::map<uint8_t, util::TileRange> tileRanges; + for (auto idtuple= tileCallbackMap.begin(); idtuple != tileCallbackMap.end(); idtuple++) { - const LatLngBounds tileBounds(idtuple->first); - if (tileBounds.intersects(bounds, LatLng::Wrapped) || bounds.contains(tileBounds, LatLng::Wrapped) || tileBounds.contains(bounds, LatLng::Wrapped)) { + auto zoom = idtuple->first.z; + auto tileRange = tileRanges.find(zoom); + if(tileRange == tileRanges.end()) { + tileRange = tileRanges.emplace(std::make_pair(zoom, util::TileRange::fromLatLngBounds(bounds, zoom))).first; + } + if (tileRange->second.contains(idtuple->first)) { for (auto iter = idtuple->second.begin(); iter != idtuple->second.end(); iter++) { auto actor = std::get<2>(*iter); actor.invoke(&CustomGeometryTile::invalidateTileData); diff --git a/src/mbgl/util/geo.cpp b/src/mbgl/util/geo.cpp index f38aba20c4..a04e2c5355 100644 --- a/src/mbgl/util/geo.cpp +++ b/src/mbgl/util/geo.cpp @@ -1,6 +1,8 @@ #include <mbgl/util/geo.hpp> #include <mbgl/util/constants.hpp> #include <mbgl/tile/tile_id.hpp> +#include <mbgl/math/clamp.hpp> +#include <mbgl/util/tile_range.hpp> #include <cmath> @@ -32,6 +34,86 @@ LatLngBounds::LatLngBounds(const CanonicalTileID& id) ne({ lat_(id.z, id.y), lon_(id.z, id.x + 1) }) { } +bool LatLngBounds::contains(const CanonicalTileID& tileID) const { + return util::TileRange::fromLatLngBounds(*this, tileID.z).contains(tileID); +} + +bool LatLngBounds::contains(const LatLng& point, LatLng::WrapMode wrap /*= LatLng::Unwrapped*/) const { + bool containsLatitude = point.latitude() >= sw.latitude() && + point.latitude() <= ne.latitude(); + if (!containsLatitude) { + return false; + } + + bool containsUnwrappedLongitude = point.longitude() >= sw.longitude() && + point.longitude() <= ne.longitude(); + if (containsUnwrappedLongitude) { + return true; + } else if (wrap == LatLng::Wrapped) { + LatLngBounds wrapped(sw.wrapped(), ne.wrapped()); + auto ptLon = point.wrapped().longitude(); + if (crossesAntimeridian()) { + return (ptLon >= wrapped.sw.longitude() && + ptLon <= util::LONGITUDE_MAX) || + (ptLon <= wrapped.ne.longitude() && + ptLon >= -util::LONGITUDE_MAX); + } else { + return (ptLon >= wrapped.sw.longitude() && + ptLon <= wrapped.ne.longitude()); + } + } + return false; +} + +bool LatLngBounds::contains(const LatLngBounds& area, LatLng::WrapMode wrap /*= LatLng::Unwrapped*/) const { + bool containsLatitude = area.north() <= north() && area.south() >= south(); + if (!containsLatitude) { + return false; + } + + bool containsUnwrapped = area.east() <= east() && area.west() >= west(); + if(containsUnwrapped) { + return true; + } else if (wrap == LatLng::Wrapped) { + LatLngBounds wrapped(sw.wrapped(), ne.wrapped()); + LatLngBounds other(area.sw.wrapped(), area.ne.wrapped()); + if (crossesAntimeridian() & !area.crossesAntimeridian()) { + return (other.east() <= util::LONGITUDE_MAX && other.west() >= wrapped.west()) || + (other.east() <= wrapped.east() && other.west() >= -util::LONGITUDE_MAX); + } else { + return other.east() <= wrapped.east() && other.west() >= wrapped.west(); + } + } + return false; +} + +bool LatLngBounds::intersects(const LatLngBounds area, LatLng::WrapMode wrap /*= LatLng::Unwrapped*/) const { + bool latitudeIntersects = area.north() > south() && area.south() < north(); + if (!latitudeIntersects) { + return false; + } + + bool longitudeIntersects = area.east() > west() && area.west() < east(); + if (longitudeIntersects) { + return true; + } else if (wrap == LatLng::Wrapped) { + LatLngBounds wrapped(sw.wrapped(), ne.wrapped()); + LatLngBounds other(area.sw.wrapped(), area.ne.wrapped()); + if (crossesAntimeridian()) { + return area.crossesAntimeridian() || + other.east() > wrapped.west() || + other.west() < wrapped.east(); + } else if (other.crossesAntimeridian()){ + return other.east() > wrapped.west() || + other.west() < wrapped.east(); + } else { + return other.east() > wrapped.west() && + other.west() < wrapped.east(); + } + } + return false; +} + ScreenCoordinate EdgeInsets::getCenter(uint16_t width, uint16_t height) const { return { (width - left() - right()) / 2.0 + left(), diff --git a/src/mbgl/util/tile_range.hpp b/src/mbgl/util/tile_range.hpp new file mode 100644 index 0000000000..f630a49078 --- /dev/null +++ b/src/mbgl/util/tile_range.hpp @@ -0,0 +1,47 @@ +#pragma once + +#include <mbgl/tile/tile_id.hpp> +#include <mbgl/util/range.hpp> +#include <mbgl/util/geo.hpp> +#include <mbgl/util/projection.hpp> + +namespace mbgl { + +namespace util { + +class TileRange { +public: + Range<Point<double>> range; + uint8_t z; + + // Compute the range of tiles covered by the bounds. + static TileRange fromLatLngBounds(const LatLngBounds& bounds, uint8_t z) { + auto swProj = Projection::project(bounds.southwest().wrapped(), z); + auto ne = bounds.northeast(); + auto neProj = Projection::project(ne.longitude() > util::LONGITUDE_MAX ? ne.wrapped() : ne , z); + const auto minX = std::floor(swProj.x); + const auto maxX = std::ceil(neProj.x); + const auto minY = std::floor(neProj.y); + const auto maxY = std::ceil(swProj.y); + return TileRange({ {minX, minY}, {maxX, maxY} }, z); + } + + bool contains(const CanonicalTileID& tileID) { + return z == tileID.z && + (range.min.x >= range.max.x ? //For wrapped bounds + tileID.x >= range.min.x || tileID.x < range.max.x : + tileID.x < range.max.x && tileID.x >= range.min.x) && + tileID.y < range.max.y && + tileID.y >= range.min.y; + } + +private: + TileRange(Range<Point<double>> range_, uint8_t z_) + : range(range_), + z(z_) { + } + +}; + +} // namespace util +} // namespace mbgl |