From df20b0cbecb25b8bc6812c4a558fc0f0e6cfb7ed Mon Sep 17 00:00:00 2001 From: Asheem Mamoowala Date: Mon, 2 Oct 2017 13:42:26 -0700 Subject: [core] Add `cameraForLatLngs()` method with modified bearing --- include/mbgl/map/map.hpp | 8 +++++--- include/mbgl/util/geometry.hpp | 6 ++++++ src/mbgl/map/map.cpp | 45 +++++++++++++++++++++++++++++++----------- test/map/map.test.cpp | 26 ++++++++++++++++++++++++ 4 files changed, 71 insertions(+), 14 deletions(-) diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp index 4108725776..c5f90d99e1 100644 --- a/include/mbgl/map/map.hpp +++ b/include/mbgl/map/map.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -66,6 +67,10 @@ public: void jumpTo(const CameraOptions&); void easeTo(const CameraOptions&, const AnimationOptions&); void flyTo(const CameraOptions&, const AnimationOptions&); + CameraOptions cameraForLatLngBounds(const LatLngBounds&, const EdgeInsets&, optional bearing = {}) const; + CameraOptions cameraForLatLngs(const std::vector&, const EdgeInsets&, optional bearing = {}) const; + CameraOptions cameraForGeometry(const Geometry&, const EdgeInsets&, optional bearing = {}) const; + LatLngBounds latLngBoundsForCamera(const CameraOptions&) const; // Position void moveBy(const ScreenCoordinate&, const AnimationOptions& = {}); @@ -82,9 +87,6 @@ public: double getZoom() const; void setLatLngZoom(const LatLng&, double zoom, const AnimationOptions& = {}); void setLatLngZoom(const LatLng&, double zoom, const EdgeInsets&, const AnimationOptions& = {}); - CameraOptions cameraForLatLngBounds(const LatLngBounds&, const EdgeInsets&) const; - CameraOptions cameraForLatLngs(const std::vector&, const EdgeInsets&) const; - LatLngBounds latLngBoundsForCamera(const CameraOptions&) const; void resetZoom(); // Bounds diff --git a/include/mbgl/util/geometry.hpp b/include/mbgl/util/geometry.hpp index 6dc16bc514..a28c59a47d 100644 --- a/include/mbgl/util/geometry.hpp +++ b/include/mbgl/util/geometry.hpp @@ -2,6 +2,7 @@ #include #include +#include namespace mbgl { @@ -58,4 +59,9 @@ struct ToFeatureType { FeatureType operator()(const mapbox::geometry::geometry_collection &) const { return FeatureType::Unknown; } }; +template +auto forEachPoint(const Geometry& g, F f) { + mapbox::geometry::for_each_point(g, f); +} + } // namespace mbgl diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index 7534fe67ad..6eb555ad1e 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -364,27 +364,27 @@ void Map::setLatLngZoom(const LatLng& latLng, double zoom, const EdgeInsets& pad impl->onUpdate(); } -CameraOptions Map::cameraForLatLngBounds(const LatLngBounds& bounds, const EdgeInsets& padding) const { +CameraOptions Map::cameraForLatLngBounds(const LatLngBounds& bounds, const EdgeInsets& padding, optional bearing) const { return cameraForLatLngs({ bounds.northwest(), bounds.southwest(), bounds.southeast(), bounds.northeast(), - }, padding); + }, padding, bearing); } -CameraOptions Map::cameraForLatLngs(const std::vector& latLngs, const EdgeInsets& padding) const { +CameraOptions cameraForLatLngs(const std::vector& latLngs, const Transform& transform, const EdgeInsets& padding) { CameraOptions options; if (latLngs.empty()) { return options; } - + Size size = transform.getState().getSize(); // Calculate the bounds of the possibly rotated shape with respect to the viewport. ScreenCoordinate nePixel = {-INFINITY, -INFINITY}; ScreenCoordinate swPixel = {INFINITY, INFINITY}; - double viewportHeight = getSize().height; + double viewportHeight = size.height; for (LatLng latLng : latLngs) { - ScreenCoordinate pixel = impl->transform.latLngToScreenCoordinate(latLng); + ScreenCoordinate pixel = transform.latLngToScreenCoordinate(latLng); swPixel.x = std::min(swPixel.x, pixel.x); nePixel.x = std::max(nePixel.x, pixel.x); swPixel.y = std::min(swPixel.y, viewportHeight - pixel.y); @@ -396,14 +396,14 @@ CameraOptions Map::cameraForLatLngs(const std::vector& latLngs, const Ed // Calculate the zoom level. double minScale = INFINITY; if (width > 0 || height > 0) { - double scaleX = double(getSize().width) / width; - double scaleY = double(getSize().height) / height; + double scaleX = double(size.width) / width; + double scaleY = double(size.height) / height; scaleX -= (padding.left() + padding.right()) / width; scaleY -= (padding.top() + padding.bottom()) / height; minScale = util::min(scaleX, scaleY); } - double zoom = getZoom() + util::log2(minScale); - zoom = util::clamp(zoom, getMinZoom(), getMaxZoom()); + double zoom = transform.getZoom() + util::log2(minScale); + zoom = util::clamp(zoom, transform.getState().getMinZoom(), transform.getState().getMaxZoom()); // Calculate the center point of a virtual bounds that is extended in all directions by padding. ScreenCoordinate centerPixel = nePixel + swPixel; @@ -421,11 +421,34 @@ CameraOptions Map::cameraForLatLngs(const std::vector& latLngs, const Ed // CameraOptions origin is at the top-left corner. centerPixel.y = viewportHeight - centerPixel.y; - options.center = latLngForPixel(centerPixel); + options.center = transform.screenCoordinateToLatLng(centerPixel); options.zoom = zoom; return options; } +CameraOptions Map::cameraForLatLngs(const std::vector& latLngs, const EdgeInsets& padding, optional bearing) const { + if(bearing) { + double angle = -*bearing * util::DEG2RAD; // Convert to radians + Transform transform(impl->transform.getState()); + transform.setAngle(angle); + CameraOptions options = mbgl::cameraForLatLngs(latLngs, transform, padding); + options.angle = angle; + return options; + } else { + return mbgl::cameraForLatLngs(latLngs, impl->transform, padding); + } +} + +CameraOptions Map::cameraForGeometry(const Geometry& geometry, const EdgeInsets& padding, optional bearing) const { + + std::vector latLngs; + forEachPoint(geometry, [&](const Point& pt) { + latLngs.push_back({ pt.y, pt.x }); + }); + return cameraForLatLngs(latLngs, padding, bearing); + +} + LatLngBounds Map::latLngBoundsForCamera(const CameraOptions& camera) const { Transform shallow { impl->transform.getState() }; Size size = shallow.getState().getSize(); diff --git a/test/map/map.test.cpp b/test/map/map.test.cpp index 50d5e50abb..9358175297 100644 --- a/test/map/map.test.cpp +++ b/test/map/map.test.cpp @@ -109,6 +109,32 @@ TEST(Map, LatLngBoundsToCamera) { CameraOptions virtualCamera = test.map.cameraForLatLngBounds(bounds, {}); ASSERT_TRUE(bounds.contains(*virtualCamera.center)); + EXPECT_NEAR(*virtualCamera.zoom, 1.55467, 1e-5); +} + +TEST(Map, LatLngBoundsToCameraWithAngle) { + MapTest<> test; + + test.map.setLatLngZoom({ 40.712730, -74.005953 }, 16.0); + + LatLngBounds bounds = LatLngBounds::hull({15.68169,73.499857}, {53.560711, 134.77281}); + + CameraOptions virtualCamera = test.map.cameraForLatLngBounds(bounds, {}, 35); + ASSERT_TRUE(bounds.contains(*virtualCamera.center)); + EXPECT_NEAR(*virtualCamera.zoom, 1.21385, 1e-5); + EXPECT_DOUBLE_EQ(virtualCamera.angle.value_or(0), -35 * util::DEG2RAD); +} + +TEST(Map, LatLngsToCamera) { + MapTest<> test; + + std::vector latLngs{{ 40.712730, 74.005953 }, {15.68169,73.499857}, {30.82678, 83.4082}}; + + CameraOptions virtualCamera = test.map.cameraForLatLngs(latLngs, {}, 23); + EXPECT_DOUBLE_EQ(virtualCamera.angle.value_or(0), -23 * util::DEG2RAD); + EXPECT_NEAR(virtualCamera.zoom.value_or(0), 2.75434, 1e-5); + EXPECT_NEAR(virtualCamera.center->latitude(), 28.49288, 1e-5); + EXPECT_NEAR(virtualCamera.center->longitude(), 74.97437, 1e-5); } TEST(Map, CameraToLatLngBounds) { -- cgit v1.2.1