summaryrefslogtreecommitdiff
path: root/src/mbgl
diff options
context:
space:
mode:
Diffstat (limited to 'src/mbgl')
-rw-r--r--src/mbgl/algorithm/update_renderables.hpp6
-rw-r--r--src/mbgl/annotation/render_annotation_source.cpp1
-rw-r--r--src/mbgl/renderer/sources/render_geojson_source.cpp1
-rw-r--r--src/mbgl/renderer/sources/render_raster_source.cpp1
-rw-r--r--src/mbgl/renderer/sources/render_vector_source.cpp1
-rw-r--r--src/mbgl/renderer/tile_pyramid.cpp11
-rw-r--r--src/mbgl/renderer/tile_pyramid.hpp1
-rw-r--r--src/mbgl/style/conversion/tileset.cpp104
-rw-r--r--src/mbgl/util/geo.cpp82
-rw-r--r--src/mbgl/util/tile_range.hpp47
10 files changed, 254 insertions, 1 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 ba80be0da0..0aff64583d 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_geojson_source.cpp b/src/mbgl/renderer/sources/render_geojson_source.cpp
index 504db78ea3..c13cd49f46 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 bcd719365d..5e63e929e2 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 ca3071c6b0..a3da3e7cbd 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 3e2311089d..c9e3b0630a 100644
--- a/src/mbgl/renderer/tile_pyramid.cpp
+++ b/src/mbgl/renderer/tile_pyramid.cpp
@@ -8,6 +8,7 @@
#include <mbgl/text/placement_config.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>
@@ -15,6 +16,7 @@
#include <mapbox/geometry/envelope.hpp>
+#include <cmath>
#include <algorithm>
namespace mbgl {
@@ -62,6 +64,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) {
@@ -134,7 +137,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 73a8d34c1c..e34b050273 100644
--- a/src/mbgl/renderer/tile_pyramid.hpp
+++ b/src/mbgl/renderer/tile_pyramid.hpp
@@ -40,6 +40,7 @@ public:
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
new file mode 100644
index 0000000000..6e559c0cac
--- /dev/null
+++ b/src/mbgl/style/conversion/tileset.cpp
@@ -0,0 +1,104 @@
+#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;
+
+ auto tiles = objectMember(value, "tiles");
+ if (!tiles) {
+ error = { "source must have tiles" };
+ return {};
+ }
+
+ if (!isArray(*tiles)) {
+ error = { "source tiles must be an array" };
+ return {};
+ }
+
+ for (std::size_t i = 0; i < arrayLength(*tiles); i++) {
+ optional<std::string> urlTemplate = toString(arrayMember(*tiles, i));
+ if (!urlTemplate) {
+ error = { "source tiles member must be a string" };
+ return {};
+ }
+ result.tiles.push_back(std::move(*urlTemplate));
+ }
+
+ auto schemeValue = objectMember(value, "scheme");
+ if (schemeValue) {
+ optional<std::string> scheme = toString(*schemeValue);
+ if (scheme && *scheme == "tms") {
+ result.scheme = Tileset::Scheme::TMS;
+ }
+ }
+
+ auto minzoomValue = objectMember(value, "minzoom");
+ if (minzoomValue) {
+ optional<float> minzoom = toNumber(*minzoomValue);
+ if (!minzoom || *minzoom < 0 || *minzoom > std::numeric_limits<uint8_t>::max()) {
+ error = { "invalid minzoom" };
+ return {};
+ }
+ result.zoomRange.min = *minzoom;
+ }
+
+ auto maxzoomValue = objectMember(value, "maxzoom");
+ if (maxzoomValue) {
+ optional<float> maxzoom = toNumber(*maxzoomValue);
+ if (!maxzoom || *maxzoom < 0 || *maxzoom > std::numeric_limits<uint8_t>::max()) {
+ error = { "invalid maxzoom" };
+ return {};
+ }
+ result.zoomRange.max = *maxzoom;
+ }
+
+ auto attributionValue = objectMember(value, "attribution");
+ if (attributionValue) {
+ optional<std::string> attribution = toString(*attributionValue);
+ if (!attribution) {
+ error = { "source attribution must be a string" };
+ return {};
+ }
+ 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;
+}
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl
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