From 0afd99b0365887d60917b0f3867d3eff1a85345e Mon Sep 17 00:00:00 2001 From: Nathan Date: Sun, 11 Feb 2024 16:22:58 -0800 Subject: [PATCH 01/28] pitch working up to but not including 90 deg --- include/mbgl/util/constants.hpp | 4 ++-- src/mbgl/map/transform.cpp | 17 ++++++++++------- src/mbgl/map/transform.hpp | 1 + src/mbgl/map/transform_state.cpp | 8 +++++--- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/include/mbgl/util/constants.hpp b/include/mbgl/util/constants.hpp index 51900f93ed1..a805e1d5dd9 100644 --- a/include/mbgl/util/constants.hpp +++ b/include/mbgl/util/constants.hpp @@ -31,8 +31,8 @@ constexpr double EARTH_RADIUS_M = 6378137; constexpr double LATITUDE_MAX = 85.051128779806604; constexpr double LONGITUDE_MAX = 180; constexpr double DEGREES_MAX = 360; -constexpr double PITCH_MIN = 0.0; -constexpr double PITCH_MAX = M_PI / 3; +constexpr double PITCH_MIN = 0; +constexpr double PITCH_MAX = M_PI; constexpr double MIN_ZOOM = 0.0; constexpr double MAX_ZOOM = 25.5; constexpr float MIN_ZOOM_F = MIN_ZOOM; diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp index 93ac496cc1c..d2a6b730561 100644 --- a/src/mbgl/map/transform.cpp +++ b/src/mbgl/map/transform.cpp @@ -158,9 +158,8 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim util::interpolate(startEdgeInsets.bottom(), padding.bottom(), t), util::interpolate(startEdgeInsets.right(), padding.right(), t)}); } - double maxPitch = getMaxPitchForEdgeInsets(state.getEdgeInsets()); - if (pitch != startPitch || maxPitch < startPitch) { - state.setPitch(std::min(maxPitch, util::interpolate(startPitch, pitch, t))); + if (pitch != startPitch) { + state.setPitch(util::interpolate(startPitch, pitch, t)); } }, duration); @@ -329,10 +328,9 @@ void Transform::flyTo(const CameraOptions& camera, const AnimationOptions& anima util::interpolate(startEdgeInsets.bottom(), padding.bottom(), k), util::interpolate(startEdgeInsets.right(), padding.right(), k)}); } - double maxPitch = getMaxPitchForEdgeInsets(state.getEdgeInsets()); - if (pitch != startPitch || maxPitch < startPitch) { - state.setPitch(std::min(maxPitch, util::interpolate(startPitch, pitch, k))); + if (pitch != startPitch) { + state.setPitch(util::interpolate(startPitch, pitch, k)); } }, duration); @@ -429,6 +427,10 @@ double Transform::getPitch() const { return state.getPitch(); } +double Transform::getFieldOfView() const { + return state.getFieldOfView(); +} + // MARK: - North Orientation void Transform::setNorthOrientation(NorthOrientation orientation) { @@ -644,7 +646,8 @@ double Transform::getMaxPitchForEdgeInsets(const EdgeInsets& insets) const { // tangentOfFovAboveCenterAngle = (h/2 + centerOffsetY) / (height // * 1.5). 1.03 is a bit extra added to prevent parallel ground to viewport // clipping plane. - const double tangentOfFovAboveCenterAngle = 1.03 * (height / 2.0 + centerOffsetY) / (1.5 * height); + const double tangentOfFovAboveCenterAngle = 1.03 * (0.5 + centerOffsetY / height) * 2.0 * + tan(getFieldOfView() / 2.0); const double fovAboveCenter = std::atan(tangentOfFovAboveCenterAngle); return M_PI * 0.5 - fovAboveCenter; // e.g. Maximum pitch of 60 degrees is when perspective center's offset from diff --git a/src/mbgl/map/transform.hpp b/src/mbgl/map/transform.hpp index eac0e8fb99d..5cec18b97cb 100644 --- a/src/mbgl/map/transform.hpp +++ b/src/mbgl/map/transform.hpp @@ -77,6 +77,7 @@ class Transform : private util::noncopyable { // Pitch double getPitch() const; + double getFieldOfView() const; // North Orientation void setNorthOrientation(NorthOrientation); diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp index 4d33c89dd20..3ff6fe74dd4 100644 --- a/src/mbgl/map/transform_state.cpp +++ b/src/mbgl/map/transform_state.cpp @@ -116,11 +116,13 @@ void TransformState::getProjMatrix(mat4& projMatrix, uint16_t nearZ, bool aligne // (the distance between[width/2, height/2] and [width/2 + 1, height/2]) // See https://github.com/mapbox/mapbox-gl-native/pull/15195 for details. // See TransformState::fov description: fov = 2 * arctan((height / 2) / (height * 1.5)). - const double tanFovAboveCenter = (size.height * 0.5 + offset.y) / (size.height * 1.5); + const double tanFovAboveCenter = (0.5 + offset.y / size.height) * 2.0 * tan(getFieldOfView() / 2.0); const double tanMultiple = tanFovAboveCenter * std::tan(getPitch()); - assert(tanMultiple < 1); // Calculate z distance of the farthest fragment that should be rendered. - const double furthestDistance = cameraToCenterDistance / (1 - tanMultiple); + double furthestDistance = 50000; // TODO: figure out units and set to reasonable value + if (cameraToCenterDistance < furthestDistance * (1 - tanMultiple)) { + furthestDistance = cameraToCenterDistance / (1 - tanMultiple); + } // Add a bit extra to avoid precision problems when a fragment's distance is exactly `furthestDistance` const double farZ = furthestDistance * 1.01; From aa025722efe52d0af50b4a5a7effc01281d5dc06 Mon Sep 17 00:00:00 2001 From: Nathan Date: Sun, 11 Feb 2024 18:15:03 -0800 Subject: [PATCH 02/28] use max furthestDistance if pitched above the horizon --- src/mbgl/map/transform_state.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp index 3ff6fe74dd4..db53133e45c 100644 --- a/src/mbgl/map/transform_state.cpp +++ b/src/mbgl/map/transform_state.cpp @@ -120,7 +120,7 @@ void TransformState::getProjMatrix(mat4& projMatrix, uint16_t nearZ, bool aligne const double tanMultiple = tanFovAboveCenter * std::tan(getPitch()); // Calculate z distance of the farthest fragment that should be rendered. double furthestDistance = 50000; // TODO: figure out units and set to reasonable value - if (cameraToCenterDistance < furthestDistance * (1 - tanMultiple)) { + if (getPitch() < M_PI_2 && cameraToCenterDistance < furthestDistance * (1 - tanMultiple)) { furthestDistance = cameraToCenterDistance / (1 - tanMultiple); } // Add a bit extra to avoid precision problems when a fragment's distance is exactly `furthestDistance` From 0cb061d39fda620c52979fdfbb385906630ab402 Mon Sep 17 00:00:00 2001 From: Nathan Date: Sun, 11 Feb 2024 19:17:59 -0800 Subject: [PATCH 03/28] variable FOV seems to work --- bin/render.cpp | 4 +++- include/mbgl/map/camera.hpp | 8 +++++++- src/mbgl/map/transform.cpp | 2 ++ src/mbgl/map/transform_state.cpp | 13 ++++++++++++- src/mbgl/map/transform_state.hpp | 6 ++++++ 5 files changed, 30 insertions(+), 3 deletions(-) diff --git a/bin/render.cpp b/bin/render.cpp index b6bb55cf6cb..bde36a63c90 100644 --- a/bin/render.cpp +++ b/bin/render.cpp @@ -33,6 +33,7 @@ int main(int argc, char* argv[]) { args::ValueFlag lonValue(argumentParser, "degrees", "Longitude", {'x', "lon"}); args::ValueFlag latValue(argumentParser, "degrees", "Latitude", {'y', "lat"}); + args::ValueFlag fovValue(argumentParser, "degrees", "FOV", {'f', "fov"}); args::ValueFlag bearingValue(argumentParser, "degrees", "Bearing", {'b', "bearing"}); args::ValueFlag pitchValue(argumentParser, "degrees", "Pitch", {'p', "pitch"}); args::ValueFlag widthValue(argumentParser, "pixels", "Image width", {'w', "width"}); @@ -56,6 +57,7 @@ int main(int argc, char* argv[]) { const double lat = latValue ? args::get(latValue) : 0; const double lon = lonValue ? args::get(lonValue) : 0; const double zoom = zoomValue ? args::get(zoomValue) : 0; + const double fov = fovValue ? args::get(fovValue) : 37; const double bearing = bearingValue ? args::get(bearingValue) : 0; const double pitch = pitchValue ? args::get(pitchValue) : 0; const double pixelRatio = pixelRatioValue ? args::get(pixelRatioValue) : 1; @@ -97,7 +99,7 @@ int main(int argc, char* argv[]) { } map.getStyle().loadURL(style); - map.jumpTo(CameraOptions().withCenter(LatLng{lat, lon}).withZoom(zoom).withBearing(bearing).withPitch(pitch)); + map.jumpTo(CameraOptions().withCenter(LatLng{lat, lon}).withZoom(zoom).withBearing(bearing).withPitch(pitch).withFov(fov)); if (debug) { map.setDebug(debug ? mbgl::MapDebugOptions::TileBorders | mbgl::MapDebugOptions::ParseStatus diff --git a/include/mbgl/map/camera.hpp b/include/mbgl/map/camera.hpp index efdd23309c2..7361b1429f8 100644 --- a/include/mbgl/map/camera.hpp +++ b/include/mbgl/map/camera.hpp @@ -41,6 +41,10 @@ struct CameraOptions { pitch = o; return *this; } + CameraOptions& withFov(const std::optional& o) { + fov = o; + return *this; + } /** Coordinate at the center of the map. */ std::optional center; @@ -63,11 +67,13 @@ struct CameraOptions { /** Pitch toward the horizon measured in degrees , with 0 deg resulting in a two-dimensional map. */ std::optional pitch; + + std::optional fov; }; constexpr bool operator==(const CameraOptions& a, const CameraOptions& b) { return a.center == b.center && a.padding == b.padding && a.anchor == b.anchor && a.zoom == b.zoom && - a.bearing == b.bearing && a.pitch == b.pitch; + a.bearing == b.bearing && a.pitch == b.pitch && a.fov == b.fov; } constexpr bool operator!=(const CameraOptions& a, const CameraOptions& b) { diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp index d2a6b730561..1d5821e833d 100644 --- a/src/mbgl/map/transform.cpp +++ b/src/mbgl/map/transform.cpp @@ -97,6 +97,7 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim double zoom = camera.zoom.value_or(getZoom()); double bearing = camera.bearing ? util::deg2rad(-*camera.bearing) : getBearing(); double pitch = camera.pitch ? util::deg2rad(*camera.pitch) : getPitch(); + double fov = camera.fov ? util::deg2rad(*camera.fov) : getFieldOfView(); if (std::isnan(zoom) || std::isnan(bearing) || std::isnan(pitch)) { if (animation.transitionFinishFn) { @@ -161,6 +162,7 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim if (pitch != startPitch) { state.setPitch(util::interpolate(startPitch, pitch, t)); } + state.setFieldOfView(fov); }, duration); } diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp index db53133e45c..c34e8e06938 100644 --- a/src/mbgl/map/transform_state.cpp +++ b/src/mbgl/map/transform_state.cpp @@ -48,6 +48,9 @@ void TransformState::setProperties(const TransformStateProperties& properties) { if (properties.bearing) { setBearing(*properties.bearing); } + if (properties.fov) { + setFieldOfView(*properties.fov); + } if (properties.pitch) { setPitch(*properties.pitch); } @@ -429,7 +432,8 @@ CameraOptions TransformState::getCameraOptions(const std::optional& .withPadding(padding ? padding : edgeInsets) .withZoom(getZoom()) .withBearing(util::rad2deg(-bearing)) - .withPitch(util::rad2deg(pitch)); + .withPitch(util::rad2deg(pitch)) + .withFov(util::rad2deg(fov)); } // MARK: - EdgeInsets @@ -590,6 +594,13 @@ float TransformState::getFieldOfView() const { return static_cast(fov); } +void TransformState::setFieldOfView(double val) { + if (fov != val) { + fov = val; + requestMatricesUpdate = true; + } +} + float TransformState::getCameraToCenterDistance() const { return static_cast(0.5 * size.height / std::tan(fov / 2.0)); } diff --git a/src/mbgl/map/transform_state.hpp b/src/mbgl/map/transform_state.hpp index 28384eb0ba5..25ac3b1781b 100644 --- a/src/mbgl/map/transform_state.hpp +++ b/src/mbgl/map/transform_state.hpp @@ -33,6 +33,10 @@ struct TransformStateProperties { scale = val; return *this; } + TransformStateProperties& withFov(const std::optional& val) { + fov = val; + return *this; + } TransformStateProperties& withBearing(const std::optional& val) { bearing = val; return *this; @@ -88,6 +92,7 @@ struct TransformStateProperties { std::optional x; std::optional y; + std::optional fov; std::optional bearing; std::optional scale; std::optional pitch; @@ -173,6 +178,7 @@ class TransformState { double getBearing() const; void setBearing(double); float getFieldOfView() const; + void setFieldOfView(double); float getCameraToCenterDistance() const; double getPitch() const; void setPitch(double); From ac8fbc2637ce2d8b3a13bff08ecfd5c7ac863d93 Mon Sep 17 00:00:00 2001 From: Nathan Date: Sun, 11 Feb 2024 21:36:33 -0800 Subject: [PATCH 04/28] set camera position, not map center postion. Pitches above 90 work, but label scaling has gone haywire. --- src/mbgl/map/transform_state.cpp | 27 ++++++++++++--------------- src/mbgl/map/transform_state.hpp | 1 + 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp index c34e8e06938..8c003a8fcfc 100644 --- a/src/mbgl/map/transform_state.cpp +++ b/src/mbgl/map/transform_state.cpp @@ -194,7 +194,7 @@ void TransformState::updateCameraState() const { } const double worldSize = Projection::worldSize(scale); - const double cameraToCenterDistance = getCameraToCenterDistance(); + const double cameraAlt = getCameraAlt(); // x & y tracks the center of the map in pixels. However as rendering is // done in pixel coordinates the rendering origo is actually in the middle @@ -207,11 +207,7 @@ void TransformState::updateCameraState() const { // Set camera orientation and move it to a proper distance from the map camera.setOrientation(getPitch(), getBearing()); - const vec3 forward = camera.forward(); - const vec3 orbitPosition = {{-forward[0] * cameraToCenterDistance, - -forward[1] * cameraToCenterDistance, - -forward[2] * cameraToCenterDistance}}; - vec3 cameraPosition = {{dx + orbitPosition[0], dy + orbitPosition[1], orbitPosition[2]}}; + vec3 cameraPosition = {{dx, dy, cameraAlt}}; cameraPosition[0] /= worldSize; cameraPosition[1] /= worldSize; @@ -262,14 +258,7 @@ FreeCameraOptions TransformState::getFreeCameraOptions() const { bool TransformState::setCameraPosition(const vec3& position) { if (std::isnan(position[0]) || std::isnan(position[1]) || std::isnan(position[2])) return false; - const double maxWorldSize = Projection::worldSize(std::pow(2.0, getMaxZoom())); - const double minWorldSize = Projection::worldSize(std::pow(2.0, getMinZoom())); - const double distToCenter = getCameraToCenterDistance(); - - const vec3 updatedPos = vec3{ - {position[0], position[1], util::clamp(position[2], distToCenter / maxWorldSize, distToCenter / minWorldSize)}}; - - camera.setPosition(updatedPos); + camera.setPosition(position); return true; } @@ -602,7 +591,15 @@ void TransformState::setFieldOfView(double val) { } float TransformState::getCameraToCenterDistance() const { - return static_cast(0.5 * size.height / std::tan(fov / 2.0)); + if (pitch < M_PI_2) { + return static_cast(getCameraAlt() / cos(pitch)); + } + return 50000.f; +} + +float TransformState::getCameraAlt() const { + double pixelsPerMeter = 1.0 / Projection::getMetersPerPixelAtLatitude(getLatLng().latitude(), getZoom()); + return static_cast(100000 * pixelsPerMeter); } double TransformState::getPitch() const { diff --git a/src/mbgl/map/transform_state.hpp b/src/mbgl/map/transform_state.hpp index 25ac3b1781b..83639c35d7a 100644 --- a/src/mbgl/map/transform_state.hpp +++ b/src/mbgl/map/transform_state.hpp @@ -180,6 +180,7 @@ class TransformState { float getFieldOfView() const; void setFieldOfView(double); float getCameraToCenterDistance() const; + float getCameraAlt() const; double getPitch() const; void setPitch(double); From c5f18dbaebf8ac5e5cca0332d58faad1f29cc9e5 Mon Sep 17 00:00:00 2001 From: Nathan Date: Tue, 13 Feb 2024 16:40:46 -0800 Subject: [PATCH 05/28] fixes for pitch = 90 --- src/mbgl/map/transform_state.cpp | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp index 8c003a8fcfc..d4722aa6b5b 100644 --- a/src/mbgl/map/transform_state.cpp +++ b/src/mbgl/map/transform_state.cpp @@ -9,6 +9,8 @@ #include #include +constexpr double MAX_PITCH = 1.55; + namespace mbgl { namespace { @@ -109,7 +111,6 @@ void TransformState::getProjMatrix(mat4& projMatrix, uint16_t nearZ, bool aligne return; } - const double cameraToCenterDistance = getCameraToCenterDistance(); const ScreenCoordinate offset = getCenterOffset(); // Find the Z distance from the viewport center point @@ -120,12 +121,11 @@ void TransformState::getProjMatrix(mat4& projMatrix, uint16_t nearZ, bool aligne // See https://github.com/mapbox/mapbox-gl-native/pull/15195 for details. // See TransformState::fov description: fov = 2 * arctan((height / 2) / (height * 1.5)). const double tanFovAboveCenter = (0.5 + offset.y / size.height) * 2.0 * tan(getFieldOfView() / 2.0); - const double tanMultiple = tanFovAboveCenter * std::tan(getPitch()); + const double maxElevationAngle = pitch + atan(tanFovAboveCenter); // Calculate z distance of the farthest fragment that should be rendered. - double furthestDistance = 50000; // TODO: figure out units and set to reasonable value - if (getPitch() < M_PI_2 && cameraToCenterDistance < furthestDistance * (1 - tanMultiple)) { - furthestDistance = cameraToCenterDistance / (1 - tanMultiple); - } + + double furthestDistance = static_cast(getCameraAlt() * tan(std::min(maxElevationAngle, MAX_PITCH))); + // Add a bit extra to avoid precision problems when a fragment's distance is exactly `furthestDistance` const double farZ = furthestDistance * 1.01; @@ -205,7 +205,7 @@ void TransformState::updateCameraState() const { const double dy = 0.5 * worldSize - y; // Set camera orientation and move it to a proper distance from the map - camera.setOrientation(getPitch(), getBearing()); + camera.setOrientation(pitch, getBearing()); vec3 cameraPosition = {{dx, dy, cameraAlt}}; @@ -591,10 +591,7 @@ void TransformState::setFieldOfView(double val) { } float TransformState::getCameraToCenterDistance() const { - if (pitch < M_PI_2) { - return static_cast(getCameraAlt() / cos(pitch)); - } - return 50000.f; + return static_cast(getCameraAlt() / cos(std::min(pitch, MAX_PITCH))); } float TransformState::getCameraAlt() const { @@ -603,7 +600,7 @@ float TransformState::getCameraAlt() const { } double TransformState::getPitch() const { - return pitch; + return std::min(pitch, MAX_PITCH); } void TransformState::setPitch(double val) { @@ -721,7 +718,7 @@ TileCoordinate TransformState::screenCoordinateToTileCoordinate(const ScreenCoor double z0 = coord0[2] / w0; double z1 = coord1[2] / w1; - double t = z0 == z1 ? 0 : (targetZ - z0) / (z1 - z0); + double t = (z1 / z0 > 0.5) ? 0 : (targetZ - z0) / (z1 - z0); Point p = util::interpolate(p0, p1, t) / scale * static_cast(1 << atZoom); return {{p.x, p.y}, static_cast(atZoom)}; From b50ee05fec5f43eb4e8b615b0c9c49885c47c756 Mon Sep 17 00:00:00 2001 From: Nathan Date: Tue, 13 Feb 2024 16:56:20 -0800 Subject: [PATCH 06/28] fix trig issue affecting near nadir --- src/mbgl/map/transform_state.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp index d4722aa6b5b..4df23396892 100644 --- a/src/mbgl/map/transform_state.cpp +++ b/src/mbgl/map/transform_state.cpp @@ -124,7 +124,7 @@ void TransformState::getProjMatrix(mat4& projMatrix, uint16_t nearZ, bool aligne const double maxElevationAngle = pitch + atan(tanFovAboveCenter); // Calculate z distance of the farthest fragment that should be rendered. - double furthestDistance = static_cast(getCameraAlt() * tan(std::min(maxElevationAngle, MAX_PITCH))); + double furthestDistance = static_cast(getCameraAlt() / cos(std::min(maxElevationAngle, MAX_PITCH))); // Add a bit extra to avoid precision problems when a fragment's distance is exactly `furthestDistance` const double farZ = furthestDistance * 1.01; From 414b0e8d7867833562f6121692f85de30937654c Mon Sep 17 00:00:00 2001 From: Nathan Date: Tue, 13 Feb 2024 17:56:58 -0800 Subject: [PATCH 07/28] add settable camera altitude --- bin/render.cpp | 4 +++- include/mbgl/map/camera.hpp | 8 ++++++- src/mbgl/map/transform.cpp | 11 +++++++--- src/mbgl/map/transform_state.cpp | 36 ++++++++++++++++++++++++-------- src/mbgl/map/transform_state.hpp | 12 +++++++++-- 5 files changed, 55 insertions(+), 16 deletions(-) diff --git a/bin/render.cpp b/bin/render.cpp index bde36a63c90..ea2fb98123d 100644 --- a/bin/render.cpp +++ b/bin/render.cpp @@ -33,6 +33,7 @@ int main(int argc, char* argv[]) { args::ValueFlag lonValue(argumentParser, "degrees", "Longitude", {'x', "lon"}); args::ValueFlag latValue(argumentParser, "degrees", "Latitude", {'y', "lat"}); + args::ValueFlag altValue(argumentParser, "degrees", "Altitude", {'y', "alt"}); args::ValueFlag fovValue(argumentParser, "degrees", "FOV", {'f', "fov"}); args::ValueFlag bearingValue(argumentParser, "degrees", "Bearing", {'b', "bearing"}); args::ValueFlag pitchValue(argumentParser, "degrees", "Pitch", {'p', "pitch"}); @@ -56,6 +57,7 @@ int main(int argc, char* argv[]) { const double lat = latValue ? args::get(latValue) : 0; const double lon = lonValue ? args::get(lonValue) : 0; + const double alt = altValue ? args::get(altValue) : 100000; const double zoom = zoomValue ? args::get(zoomValue) : 0; const double fov = fovValue ? args::get(fovValue) : 37; const double bearing = bearingValue ? args::get(bearingValue) : 0; @@ -99,7 +101,7 @@ int main(int argc, char* argv[]) { } map.getStyle().loadURL(style); - map.jumpTo(CameraOptions().withCenter(LatLng{lat, lon}).withZoom(zoom).withBearing(bearing).withPitch(pitch).withFov(fov)); + map.jumpTo(CameraOptions().withCenter(LatLng{lat, lon}).withAlt(alt).withZoom(zoom).withBearing(bearing).withPitch(pitch).withFov(fov)); if (debug) { map.setDebug(debug ? mbgl::MapDebugOptions::TileBorders | mbgl::MapDebugOptions::ParseStatus diff --git a/include/mbgl/map/camera.hpp b/include/mbgl/map/camera.hpp index 7361b1429f8..d9442c1cd6c 100644 --- a/include/mbgl/map/camera.hpp +++ b/include/mbgl/map/camera.hpp @@ -21,6 +21,10 @@ struct CameraOptions { center = o; return *this; } + CameraOptions& withAlt(const std::optional& o) { + altM = o; + return *this; + } CameraOptions& withPadding(const std::optional& p) { padding = p; return *this; @@ -49,6 +53,8 @@ struct CameraOptions { /** Coordinate at the center of the map. */ std::optional center; + std::optional altM; + /** Padding around the interior of the view that affects the frame of reference for `center`. */ std::optional padding; @@ -73,7 +79,7 @@ struct CameraOptions { constexpr bool operator==(const CameraOptions& a, const CameraOptions& b) { return a.center == b.center && a.padding == b.padding && a.anchor == b.anchor && a.zoom == b.zoom && - a.bearing == b.bearing && a.pitch == b.pitch && a.fov == b.fov; + a.bearing == b.bearing && a.pitch == b.pitch && a.fov == b.fov && a.altM == b.altM; } constexpr bool operator!=(const CameraOptions& a, const CameraOptions& b) { diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp index 1d5821e833d..42ed10aaa6d 100644 --- a/src/mbgl/map/transform.cpp +++ b/src/mbgl/map/transform.cpp @@ -58,8 +58,9 @@ void Transform::resize(const Size size) { double scale{state.getScale()}; double x{state.getX()}; double y{state.getY()}; + double z{state.getZ()}; state.constrain(scale, x, y); - state.setProperties(TransformStateProperties().withScale(scale).withX(x).withY(y)); + state.setProperties(TransformStateProperties().withScale(scale).withX(x).withY(y).withZ(z)); observer.onCameraDidChange(MapObserver::CameraChangeMode::Immediate); } @@ -98,6 +99,7 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim double bearing = camera.bearing ? util::deg2rad(-*camera.bearing) : getBearing(); double pitch = camera.pitch ? util::deg2rad(*camera.pitch) : getPitch(); double fov = camera.fov ? util::deg2rad(*camera.fov) : getFieldOfView(); + double alt_m = camera.altM.value_or(100000); if (std::isnan(zoom) || std::isnan(bearing) || std::isnan(pitch)) { if (animation.transitionFinishFn) { @@ -163,6 +165,7 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim state.setPitch(util::interpolate(startPitch, pitch, t)); } state.setFieldOfView(fov); + state.setAltM(alt_m); }, duration); } @@ -440,8 +443,9 @@ void Transform::setNorthOrientation(NorthOrientation orientation) { double scale{state.getScale()}; double x{state.getX()}; double y{state.getY()}; + double z{state.getZ()}; state.constrain(scale, x, y); - state.setProperties(TransformStateProperties().withScale(scale).withX(x).withY(y)); + state.setProperties(TransformStateProperties().withScale(scale).withX(x).withY(y).withZ(z)); } NorthOrientation Transform::getNorthOrientation() const { @@ -455,8 +459,9 @@ void Transform::setConstrainMode(mbgl::ConstrainMode mode) { double scale{state.getScale()}; double x{state.getX()}; double y{state.getY()}; + double z{state.getZ()}; state.constrain(scale, x, y); - state.setProperties(TransformStateProperties().withScale(scale).withX(x).withY(y)); + state.setProperties(TransformStateProperties().withScale(scale).withX(x).withY(y).withZ(z)); } ConstrainMode Transform::getConstrainMode() const { diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp index 4df23396892..63432fd402c 100644 --- a/src/mbgl/map/transform_state.cpp +++ b/src/mbgl/map/transform_state.cpp @@ -44,6 +44,9 @@ void TransformState::setProperties(const TransformStateProperties& properties) { if (properties.y) { setY(*properties.y); } + if (properties.z) { + setZ(*properties.z); + } if (properties.scale) { setScale(*properties.scale); } @@ -124,7 +127,7 @@ void TransformState::getProjMatrix(mat4& projMatrix, uint16_t nearZ, bool aligne const double maxElevationAngle = pitch + atan(tanFovAboveCenter); // Calculate z distance of the farthest fragment that should be rendered. - double furthestDistance = static_cast(getCameraAlt() / cos(std::min(maxElevationAngle, MAX_PITCH))); + double furthestDistance = static_cast(getZ() / cos(std::min(maxElevationAngle, MAX_PITCH))); // Add a bit extra to avoid precision problems when a fragment's distance is exactly `furthestDistance` const double farZ = furthestDistance * 1.01; @@ -194,7 +197,6 @@ void TransformState::updateCameraState() const { } const double worldSize = Projection::worldSize(scale); - const double cameraAlt = getCameraAlt(); // x & y tracks the center of the map in pixels. However as rendering is // done in pixel coordinates the rendering origo is actually in the middle @@ -207,7 +209,7 @@ void TransformState::updateCameraState() const { // Set camera orientation and move it to a proper distance from the map camera.setOrientation(pitch, getBearing()); - vec3 cameraPosition = {{dx, dy, cameraAlt}}; + vec3 cameraPosition = {{dx, dy, z}}; cameraPosition[0] /= worldSize; cameraPosition[1] /= worldSize; @@ -418,6 +420,7 @@ void TransformState::setViewportMode(ViewportMode val) { CameraOptions TransformState::getCameraOptions(const std::optional& padding) const { return CameraOptions() .withCenter(getLatLng()) + .withAlt(getAltM()) .withPadding(padding ? padding : edgeInsets) .withZoom(getZoom()) .withBearing(util::rad2deg(-bearing)) @@ -440,6 +443,10 @@ LatLng TransformState::getLatLng(LatLng::WrapMode wrapMode) const { return {util::rad2deg(2 * std::atan(std::exp(y / Cc)) - 0.5 * M_PI), -x / Bc, wrapMode}; } +double TransformState::getAltM() const { + return z * Projection::getMetersPerPixelAtLatitude(getLatLng().latitude(), getZoom()); +} + double TransformState::pixel_x() const { const double center = (size.width - Projection::worldSize(scale)) / 2; return center + x; @@ -566,6 +573,17 @@ void TransformState::setY(double val) { } } +double TransformState::getZ() const { + return z; +} + +void TransformState::setZ(double val) { + if (z != val) { + z = val; + requestMatricesUpdate = true; + } +} + // MARK: - Rotation double TransformState::getBearing() const { @@ -591,12 +609,7 @@ void TransformState::setFieldOfView(double val) { } float TransformState::getCameraToCenterDistance() const { - return static_cast(getCameraAlt() / cos(std::min(pitch, MAX_PITCH))); -} - -float TransformState::getCameraAlt() const { - double pixelsPerMeter = 1.0 / Projection::getMetersPerPixelAtLatitude(getLatLng().latitude(), getZoom()); - return static_cast(100000 * pixelsPerMeter); + return static_cast(getZ() / cos(std::min(pitch, MAX_PITCH))); } double TransformState::getPitch() const { @@ -801,6 +814,11 @@ void TransformState::setLatLngZoom(const LatLng& latLng, double zoom) { setScalePoint(newScale, point); } +void TransformState::setAltM(double alt_m) { + z = alt_m / Projection::getMetersPerPixelAtLatitude(getLatLng().latitude(), getZoom()); + requestMatricesUpdate = true; +} + void TransformState::setScalePoint(const double newScale, const ScreenCoordinate& point) { double constrainedScale = newScale; ScreenCoordinate constrainedPoint = point; diff --git a/src/mbgl/map/transform_state.hpp b/src/mbgl/map/transform_state.hpp index 83639c35d7a..be5639e1304 100644 --- a/src/mbgl/map/transform_state.hpp +++ b/src/mbgl/map/transform_state.hpp @@ -29,6 +29,10 @@ struct TransformStateProperties { y = val; return *this; } + TransformStateProperties& withZ(const std::optional& val) { + z = val; + return *this; + } TransformStateProperties& withScale(const std::optional& val) { scale = val; return *this; @@ -92,6 +96,7 @@ struct TransformStateProperties { std::optional x; std::optional y; + std::optional z; std::optional fov; std::optional bearing; std::optional scale; @@ -144,6 +149,7 @@ class TransformState { // Position LatLng getLatLng(LatLng::WrapMode = LatLng::Unwrapped) const; + double getAltM() const; double pixel_x() const; double pixel_y() const; @@ -161,6 +167,8 @@ class TransformState { void setX(double); double getY() const; void setY(double); + double getZ() const; + void setZ(double); // Bounds void setLatLngBounds(LatLngBounds); @@ -180,7 +188,6 @@ class TransformState { float getFieldOfView() const; void setFieldOfView(double); float getCameraToCenterDistance() const; - float getCameraAlt() const; double getPitch() const; void setPitch(double); @@ -221,6 +228,7 @@ class TransformState { point on screen. */ void moveLatLng(const LatLng&, const ScreenCoordinate&); void setLatLngZoom(const LatLng& latLng, double zoom); + void setAltM(double alt_m); void constrain(double& scale, double& x, double& y) const; const mat4& getProjectionMatrix() const; @@ -278,7 +286,7 @@ class TransformState { bool gestureInProgress = false; // map position - double x = 0, y = 0; + double x = 0, y = 0, z = 0; double bearing = 0; double scale = 1; // This fov value is somewhat arbitrary. The altitude of the camera used From d17706a8b2d45d6ea1531396d9fc12689b986175 Mon Sep 17 00:00:00 2001 From: Nathan Date: Tue, 13 Feb 2024 18:17:07 -0800 Subject: [PATCH 08/28] twist working, but there's wreckage in camera.cpp --- bin/render.cpp | 4 +++- include/mbgl/map/camera.hpp | 11 ++++++++--- src/mbgl/map/transform.cpp | 6 ++++++ src/mbgl/map/transform.hpp | 1 + src/mbgl/map/transform_state.cpp | 24 +++++++++++++++++++++--- src/mbgl/map/transform_state.hpp | 10 +++++++++- src/mbgl/util/camera.cpp | 31 +++++++++++++++++-------------- src/mbgl/util/camera.hpp | 4 ++-- 8 files changed, 67 insertions(+), 24 deletions(-) diff --git a/bin/render.cpp b/bin/render.cpp index ea2fb98123d..26dcdfa451a 100644 --- a/bin/render.cpp +++ b/bin/render.cpp @@ -37,6 +37,7 @@ int main(int argc, char* argv[]) { args::ValueFlag fovValue(argumentParser, "degrees", "FOV", {'f', "fov"}); args::ValueFlag bearingValue(argumentParser, "degrees", "Bearing", {'b', "bearing"}); args::ValueFlag pitchValue(argumentParser, "degrees", "Pitch", {'p', "pitch"}); + args::ValueFlag twistValue(argumentParser, "degrees", "Twist", {'T', "twist"}); args::ValueFlag widthValue(argumentParser, "pixels", "Image width", {'w', "width"}); args::ValueFlag heightValue(argumentParser, "pixels", "Image height", {'h', "height"}); @@ -62,6 +63,7 @@ int main(int argc, char* argv[]) { const double fov = fovValue ? args::get(fovValue) : 37; const double bearing = bearingValue ? args::get(bearingValue) : 0; const double pitch = pitchValue ? args::get(pitchValue) : 0; + const double twist = twistValue ? args::get(twistValue) : 0; const double pixelRatio = pixelRatioValue ? args::get(pixelRatioValue) : 1; const uint32_t width = widthValue ? args::get(widthValue) : 512; @@ -101,7 +103,7 @@ int main(int argc, char* argv[]) { } map.getStyle().loadURL(style); - map.jumpTo(CameraOptions().withCenter(LatLng{lat, lon}).withAlt(alt).withZoom(zoom).withBearing(bearing).withPitch(pitch).withFov(fov)); + map.jumpTo(CameraOptions().withCenter(LatLng{lat, lon}).withAlt(alt).withZoom(zoom).withBearing(bearing).withPitch(pitch).withTwist(twist).withFov(fov)); if (debug) { map.setDebug(debug ? mbgl::MapDebugOptions::TileBorders | mbgl::MapDebugOptions::ParseStatus diff --git a/include/mbgl/map/camera.hpp b/include/mbgl/map/camera.hpp index d9442c1cd6c..c6be1fa86a3 100644 --- a/include/mbgl/map/camera.hpp +++ b/include/mbgl/map/camera.hpp @@ -45,6 +45,10 @@ struct CameraOptions { pitch = o; return *this; } + CameraOptions& withTwist(const std::optional& o) { + twist = o; + return *this; + } CameraOptions& withFov(const std::optional& o) { fov = o; return *this; @@ -73,13 +77,14 @@ struct CameraOptions { /** Pitch toward the horizon measured in degrees , with 0 deg resulting in a two-dimensional map. */ std::optional pitch; - + + std::optional twist; std::optional fov; }; constexpr bool operator==(const CameraOptions& a, const CameraOptions& b) { return a.center == b.center && a.padding == b.padding && a.anchor == b.anchor && a.zoom == b.zoom && - a.bearing == b.bearing && a.pitch == b.pitch && a.fov == b.fov && a.altM == b.altM; + a.bearing == b.bearing && a.pitch == b.pitch && a.twist == b.twist && a.fov == b.fov && a.altM == b.altM; } constexpr bool operator!=(const CameraOptions& a, const CameraOptions& b) { @@ -165,7 +170,7 @@ struct FreeCameraOptions { /** Helper function for setting the orientation of the camera as a pitch and a bearing. Both values are in degrees */ - void setPitchBearing(double pitch, double bearing); + void setPitchBearing(double pitch, double bearing, double twist); }; } // namespace mbgl diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp index 42ed10aaa6d..78e979c90b3 100644 --- a/src/mbgl/map/transform.cpp +++ b/src/mbgl/map/transform.cpp @@ -100,6 +100,7 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim double pitch = camera.pitch ? util::deg2rad(*camera.pitch) : getPitch(); double fov = camera.fov ? util::deg2rad(*camera.fov) : getFieldOfView(); double alt_m = camera.altM.value_or(100000); + double twist = camera.twist ? util::deg2rad(*camera.twist) : getTwist(); if (std::isnan(zoom) || std::isnan(bearing) || std::isnan(pitch)) { if (animation.transitionFinishFn) { @@ -166,6 +167,7 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim } state.setFieldOfView(fov); state.setAltM(alt_m); + state.setTwist(twist); }, duration); } @@ -432,6 +434,10 @@ double Transform::getPitch() const { return state.getPitch(); } +double Transform::getTwist() const { + return state.getTwist(); +} + double Transform::getFieldOfView() const { return state.getFieldOfView(); } diff --git a/src/mbgl/map/transform.hpp b/src/mbgl/map/transform.hpp index 5cec18b97cb..592b404191b 100644 --- a/src/mbgl/map/transform.hpp +++ b/src/mbgl/map/transform.hpp @@ -77,6 +77,7 @@ class Transform : private util::noncopyable { // Pitch double getPitch() const; + double getTwist() const; double getFieldOfView() const; // North Orientation diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp index 63432fd402c..c7f674d3642 100644 --- a/src/mbgl/map/transform_state.cpp +++ b/src/mbgl/map/transform_state.cpp @@ -59,6 +59,9 @@ void TransformState::setProperties(const TransformStateProperties& properties) { if (properties.pitch) { setPitch(*properties.pitch); } + if (properties.twist) { + setTwist(*properties.twist); + } if (properties.xSkew) { setXSkew(*properties.xSkew); } @@ -123,7 +126,8 @@ void TransformState::getProjMatrix(mat4& projMatrix, uint16_t nearZ, bool aligne // (the distance between[width/2, height/2] and [width/2 + 1, height/2]) // See https://github.com/mapbox/mapbox-gl-native/pull/15195 for details. // See TransformState::fov description: fov = 2 * arctan((height / 2) / (height * 1.5)). - const double tanFovAboveCenter = (0.5 + offset.y / size.height) * 2.0 * tan(getFieldOfView() / 2.0); + const double tanFovAboveCenter = (0.5 + offset.y / size.height) * 2.0 * + tan(getFieldOfView() * hypot(size.height, size.width) / size.height / 2.0); const double maxElevationAngle = pitch + atan(tanFovAboveCenter); // Calculate z distance of the farthest fragment that should be rendered. @@ -207,7 +211,7 @@ void TransformState::updateCameraState() const { const double dy = 0.5 * worldSize - y; // Set camera orientation and move it to a proper distance from the map - camera.setOrientation(pitch, getBearing()); + camera.setOrientation(pitch, getBearing(), getTwist()); vec3 cameraPosition = {{dx, dy, z}}; @@ -230,7 +234,8 @@ void TransformState::updateStateFromCamera() { // Compute bearing and pitch double newBearing; double newPitch; - camera.getOrientation(newPitch, newBearing); + double newTwist; + camera.getOrientation(newPitch, newBearing, newTwist); newPitch = util::clamp(newPitch, minPitch, maxPitch); // Compute zoom level from the camera altitude @@ -245,6 +250,7 @@ void TransformState::updateStateFromCamera() { setLatLngZoom(latLngFromMercator(mercatorPoint), scaleZoom(newScale)); setBearing(newBearing); setPitch(newPitch); + setTwist(newTwist); } FreeCameraOptions TransformState::getFreeCameraOptions() const { @@ -425,6 +431,7 @@ CameraOptions TransformState::getCameraOptions(const std::optional& .withZoom(getZoom()) .withBearing(util::rad2deg(-bearing)) .withPitch(util::rad2deg(pitch)) + .withTwist(util::rad2deg(twist)) .withFov(util::rad2deg(fov)); } @@ -608,6 +615,17 @@ void TransformState::setFieldOfView(double val) { } } +double TransformState::getTwist() const { + return twist; +} + +void TransformState::setTwist(double val) { + if (twist != val) { + twist = val; + requestMatricesUpdate = true; + } +} + float TransformState::getCameraToCenterDistance() const { return static_cast(getZ() / cos(std::min(pitch, MAX_PITCH))); } diff --git a/src/mbgl/map/transform_state.hpp b/src/mbgl/map/transform_state.hpp index be5639e1304..c602a08e09b 100644 --- a/src/mbgl/map/transform_state.hpp +++ b/src/mbgl/map/transform_state.hpp @@ -49,6 +49,10 @@ struct TransformStateProperties { pitch = val; return *this; } + TransformStateProperties& withTwist(const std::optional& val) { + twist = val; + return *this; + } TransformStateProperties& withXSkew(const std::optional& val) { xSkew = val; return *this; @@ -98,9 +102,10 @@ struct TransformStateProperties { std::optional y; std::optional z; std::optional fov; - std::optional bearing; std::optional scale; + std::optional bearing; std::optional pitch; + std::optional twist; std::optional xSkew; std::optional ySkew; std::optional axonometric; @@ -190,6 +195,8 @@ class TransformState { float getCameraToCenterDistance() const; double getPitch() const; void setPitch(double); + double getTwist() const; + void setTwist(double); double getXSkew() const; void setXSkew(double); @@ -295,6 +302,7 @@ class TransformState { // with: `fov = 2 * arctan((height / 2) / (height * 1.5))` double fov = 0.6435011087932844; double pitch = 0.0; + double twist = 0.0; double xSkew = 0.0; double ySkew = 1.0; bool axonometric = false; diff --git a/src/mbgl/util/camera.cpp b/src/mbgl/util/camera.cpp index bc009e6385e..aff76530178 100644 --- a/src/mbgl/util/camera.cpp +++ b/src/mbgl/util/camera.cpp @@ -10,7 +10,7 @@ namespace mbgl { -namespace { +/*namespace { double vec2Len(const vec2& v) { return std::sqrt(v[0] * v[0] + v[1] * v[1]); }; @@ -22,7 +22,7 @@ double vec2Dot(const vec2& a, const vec2& b) { vec2 vec2Scale(const vec2& v, double s) { return vec2{{v[0] * s, v[1] * s}}; }; -} // namespace +} // namespace*/ namespace util { @@ -61,12 +61,13 @@ static vec3 toMercator(const LatLng& location, double altitudeMeters) { altitudeMeters * pixelsPerMeter / worldSize}}; } -static Quaternion orientationFromPitchBearing(double pitch, double bearing) { +static Quaternion orientationFromPitchBearing(double pitch, double bearing, double twist) { // Both angles have to be negated to achieve CW rotation around the axis of rotation Quaternion rotBearing = Quaternion::fromAxisAngle({{0.0, 0.0, 1.0}}, -bearing); Quaternion rotPitch = Quaternion::fromAxisAngle({{1.0, 0.0, 0.0}}, -pitch); + Quaternion rotTwist = Quaternion::fromAxisAngle({{0.0, 0.0, 1.0}}, -twist); - return rotBearing.multiply(rotPitch); + return rotBearing.multiply(rotPitch).multiply(rotTwist); } static void updateTransform(mat4& transform, const Quaternion& orientation) { @@ -163,16 +164,17 @@ vec3 Camera::up() const { return {{-column[0], -column[1], -column[2]}}; } -void Camera::getOrientation(double& pitch, double& bearing) const { +void Camera::getOrientation(double& pitch, double& bearing, double& twist) const { const vec3 f = forward(); const vec3 r = right(); bearing = std::atan2(-r[1], r[0]); pitch = std::atan2(std::sqrt(f[0] * f[0] + f[1] * f[1]), -f[2]); + twist = 0; } -void Camera::setOrientation(double pitch, double bearing) { - orientation = orientationFromPitchBearing(pitch, bearing); +void Camera::setOrientation(double pitch, double bearing, double twist) { + orientation = orientationFromPitchBearing(pitch, bearing, twist); updateTransform(transform, orientation); } @@ -188,19 +190,19 @@ void Camera::setPosition(const vec3& position) { std::optional Camera::orientationFromFrame(const vec3& forward, const vec3& up) { vec3 upVector = up; - vec2 xyForward = {{forward[0], forward[1]}}; - vec2 xyUp = {{up[0], up[1]}}; + //vec2 xyForward = {{forward[0], forward[1]}}; + //vec2 xyUp = {{up[0], up[1]}}; const double epsilon = 1e-15; // Remove roll-component of the resulting orientation by projecting // the up-vector to the forward vector on xy-plane - if (vec2Len(xyForward) >= epsilon) { + /*if (vec2Len(xyForward) >= epsilon) { const vec2 xyDir = vec2Scale(xyForward, 1.0 / vec2Len(xyForward)); xyUp = vec2Scale(xyDir, vec2Dot(xyUp, xyDir)); upVector[0] = xyUp[0]; upVector[1] = xyUp[1]; - } + }*/ const vec3 right = vec3Cross(upVector, forward); @@ -210,8 +212,9 @@ std::optional Camera::orientationFromFrame(const vec3& forward, cons const double bearing = std::atan2(-right[1], right[0]); const double pitch = std::atan2(std::sqrt(forward[0] * forward[0] + forward[1] * forward[1]), -forward[2]); + const double twist = 0; - return util::orientationFromPitchBearing(pitch, bearing); + return util::orientationFromPitchBearing(pitch, bearing, twist); } } // namespace util @@ -257,8 +260,8 @@ void FreeCameraOptions::lookAtPoint(const LatLng& location, const std::optional< } } -void FreeCameraOptions::setPitchBearing(double pitch, double bearing) { - orientation = util::orientationFromPitchBearing(util::deg2rad(pitch), util::deg2rad(bearing)).m; +void FreeCameraOptions::setPitchBearing(double pitch, double bearing, double twist) { + orientation = util::orientationFromPitchBearing(util::deg2rad(pitch), util::deg2rad(bearing), util::deg2rad(twist)).m; } } // namespace mbgl diff --git a/src/mbgl/util/camera.hpp b/src/mbgl/util/camera.hpp index fd74efc973a..54c3f157f72 100644 --- a/src/mbgl/util/camera.hpp +++ b/src/mbgl/util/camera.hpp @@ -25,8 +25,8 @@ class Camera { vec3 up() const; const Quaternion& getOrientation() const { return orientation; } - void getOrientation(double& pitch, double& bearing) const; - void setOrientation(double pitch, double bearing); + void getOrientation(double& pitch, double& bearing, double& twist) const; + void setOrientation(double pitch, double bearing, double twist); void setOrientation(const Quaternion& orientation_); void setPosition(const vec3& position); From 92a4b4d88fe1fce112a3129063e91dc7c6f49700 Mon Sep 17 00:00:00 2001 From: Nathan Date: Tue, 13 Feb 2024 19:54:52 -0800 Subject: [PATCH 09/28] toward full twist support --- src/mbgl/map/transform_state.cpp | 5 ++--- src/mbgl/util/camera.cpp | 36 +++++++------------------------- src/mbgl/util/camera.hpp | 5 ++--- 3 files changed, 11 insertions(+), 35 deletions(-) diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp index c7f674d3642..554aad6cccb 100644 --- a/src/mbgl/map/transform_state.cpp +++ b/src/mbgl/map/transform_state.cpp @@ -290,10 +290,9 @@ bool TransformState::setCameraOrientation(const Quaternion& orientation_) { return false; } - const std::optional updatedOrientation = util::Camera::orientationFromFrame(forward, up); - if (!updatedOrientation) return false; + Quaternion updatedOrientation = util::Camera::orientationFromFrame(forward, up); - camera.setOrientation(updatedOrientation.value()); + camera.setOrientation(updatedOrientation); return true; } diff --git a/src/mbgl/util/camera.cpp b/src/mbgl/util/camera.cpp index aff76530178..eb8ac734f27 100644 --- a/src/mbgl/util/camera.cpp +++ b/src/mbgl/util/camera.cpp @@ -170,7 +170,7 @@ void Camera::getOrientation(double& pitch, double& bearing, double& twist) const bearing = std::atan2(-r[1], r[0]); pitch = std::atan2(std::sqrt(f[0] * f[0] + f[1] * f[1]), -f[2]); - twist = 0; + twist = 0; //TODO } void Camera::setOrientation(double pitch, double bearing, double twist) { @@ -187,32 +187,12 @@ void Camera::setPosition(const vec3& position) { updateTransform(transform, position); } -std::optional Camera::orientationFromFrame(const vec3& forward, const vec3& up) { - vec3 upVector = up; - - //vec2 xyForward = {{forward[0], forward[1]}}; - //vec2 xyUp = {{up[0], up[1]}}; - const double epsilon = 1e-15; - - // Remove roll-component of the resulting orientation by projecting - // the up-vector to the forward vector on xy-plane - /*if (vec2Len(xyForward) >= epsilon) { - const vec2 xyDir = vec2Scale(xyForward, 1.0 / vec2Len(xyForward)); - - xyUp = vec2Scale(xyDir, vec2Dot(xyUp, xyDir)); - upVector[0] = xyUp[0]; - upVector[1] = xyUp[1]; - }*/ - - const vec3 right = vec3Cross(upVector, forward); - - if (vec3Length(right) < epsilon) { - return std::nullopt; - } +Quaternion Camera::orientationFromFrame(const vec3& forward, const vec3& up) { + const vec3 right = vec3Cross(up, forward); const double bearing = std::atan2(-right[1], right[0]); const double pitch = std::atan2(std::sqrt(forward[0] * forward[0] + forward[1] * forward[1]), -forward[2]); - const double twist = 0; + const double twist = 0; //TODO return util::orientationFromPitchBearing(pitch, bearing, twist); } @@ -254,14 +234,12 @@ void FreeCameraOptions::lookAtPoint(const LatLng& location, const std::optional< // Flip z-component of the up vector if it's pointing downwards up[2] = std::abs(up[2]); - const auto newOrientation = util::Camera::orientationFromFrame(forward, up); - if (newOrientation) { - orientation = newOrientation.value().m; - } + orientation = util::Camera::orientationFromFrame(forward, up).m; } void FreeCameraOptions::setPitchBearing(double pitch, double bearing, double twist) { - orientation = util::orientationFromPitchBearing(util::deg2rad(pitch), util::deg2rad(bearing), util::deg2rad(twist)).m; + orientation = + util::orientationFromPitchBearing(util::deg2rad(pitch), util::deg2rad(bearing), util::deg2rad(twist)).m; } } // namespace mbgl diff --git a/src/mbgl/util/camera.hpp b/src/mbgl/util/camera.hpp index 54c3f157f72..182ef7abcee 100644 --- a/src/mbgl/util/camera.hpp +++ b/src/mbgl/util/camera.hpp @@ -31,9 +31,8 @@ class Camera { void setPosition(const vec3& position); // Computes orientation using forward and up vectors of the provided - // coordinate frame. Only bearing and pitch components will be used. Does - // not return a value if input is invalid - static std::optional orientationFromFrame(const vec3& forward, const vec3& up); + // coordinate frame. + static Quaternion orientationFromFrame(const vec3& forward, const vec3& up); private: Quaternion orientation; From f737b2f8af7cf89084c00130766fc2e603fed323 Mon Sep 17 00:00:00 2001 From: Nathan Date: Tue, 12 Nov 2024 12:49:23 -0800 Subject: [PATCH 10/28] compiles --- src/mbgl/map/transform_state.cpp | 10 +++++++--- src/mbgl/util/camera.cpp | 10 +++++----- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp index d6bea67ca21..2eaf0e6f3b4 100644 --- a/src/mbgl/map/transform_state.cpp +++ b/src/mbgl/map/transform_state.cpp @@ -293,10 +293,14 @@ bool TransformState::setCameraOrientation(const Quaternion& orientation_) { return false; } - Quaternion updatedOrientation = util::Camera::orientationFromFrame(forward, up); + std::optional updatedOrientation = util::Camera::orientationFromFrame(forward, up); - camera.setOrientation(updatedOrientation); - return true; + if (updatedOrientation) { + camera.setOrientation(*updatedOrientation); + return true; + } + + return false; } void TransformState::setFreeCameraOptions(const FreeCameraOptions& options) { diff --git a/src/mbgl/util/camera.cpp b/src/mbgl/util/camera.cpp index c27874e38ef..ea808bffdac 100644 --- a/src/mbgl/util/camera.cpp +++ b/src/mbgl/util/camera.cpp @@ -15,7 +15,7 @@ using namespace std::numbers; namespace mbgl { namespace { -double vec2Len(const vec2& v) noexcept { +/*double vec2Len(const vec2& v) noexcept { return std::sqrt(v[0] * v[0] + v[1] * v[1]); }; @@ -25,8 +25,8 @@ double vec2Dot(const vec2& a, const vec2& b) noexcept { vec2 vec2Scale(const vec2& v, double s) noexcept { return vec2{{v[0] * s, v[1] * s}}; -}; -} // namespace*/ +};*/ +} // namespace namespace util { @@ -191,7 +191,7 @@ void Camera::setPosition(const vec3& position) noexcept { updateTransform(transform, position); } -Quaternion Camera::orientationFromFrame(const vec3& forward, const vec3& up) noexcept { +std::optional Camera::orientationFromFrame(const vec3& forward, const vec3& up) noexcept { const vec3 right = vec3Cross(up, forward); const double bearing = std::atan2(-right[1], right[0]); @@ -238,7 +238,7 @@ void FreeCameraOptions::lookAtPoint(const LatLng& location, const std::optional< // Flip z-component of the up vector if it's pointing downwards up[2] = std::abs(up[2]); - orientation = util::Camera::orientationFromFrame(forward, up).m; + orientation = util::Camera::orientationFromFrame(forward, up)->m; } void FreeCameraOptions::setPitchBearing(double pitch, double bearing, double twist) noexcept { From bf5745a3844df22d3d8c20fc47307129469f770e Mon Sep 17 00:00:00 2001 From: Nathan Date: Tue, 12 Nov 2024 12:51:10 -0800 Subject: [PATCH 11/28] rename twist -> roll --- bin/render.cpp | 6 +++--- include/mbgl/map/camera.hpp | 10 +++++----- src/mbgl/map/transform.cpp | 8 ++++---- src/mbgl/map/transform.hpp | 2 +- src/mbgl/map/transform_state.cpp | 24 ++++++++++++------------ src/mbgl/map/transform_state.hpp | 12 ++++++------ src/mbgl/util/camera.cpp | 22 +++++++++++----------- src/mbgl/util/camera.hpp | 4 ++-- 8 files changed, 44 insertions(+), 44 deletions(-) diff --git a/bin/render.cpp b/bin/render.cpp index 47a25af0394..21b1e78882a 100644 --- a/bin/render.cpp +++ b/bin/render.cpp @@ -37,7 +37,7 @@ int main(int argc, char* argv[]) { args::ValueFlag fovValue(argumentParser, "degrees", "FOV", {'f', "fov"}); args::ValueFlag bearingValue(argumentParser, "degrees", "Bearing", {'b', "bearing"}); args::ValueFlag pitchValue(argumentParser, "degrees", "Pitch", {'p', "pitch"}); - args::ValueFlag twistValue(argumentParser, "degrees", "Twist", {'T', "twist"}); + args::ValueFlag rollValue(argumentParser, "degrees", "Roll", {'T', "roll"}); args::ValueFlag widthValue(argumentParser, "pixels", "Image width", {'w', "width"}); args::ValueFlag heightValue(argumentParser, "pixels", "Image height", {'h', "height"}); @@ -63,7 +63,7 @@ int main(int argc, char* argv[]) { const double fov = fovValue ? args::get(fovValue) : 37; const double bearing = bearingValue ? args::get(bearingValue) : 0; const double pitch = pitchValue ? args::get(pitchValue) : 0; - const double twist = twistValue ? args::get(twistValue) : 0; + const double roll = rollValue ? args::get(rollValue) : 0; const double pixelRatio = pixelRatioValue ? args::get(pixelRatioValue) : 1; const uint32_t width = widthValue ? args::get(widthValue) : 512; @@ -103,7 +103,7 @@ int main(int argc, char* argv[]) { } map.getStyle().loadURL(style); - map.jumpTo(CameraOptions().withCenter(LatLng{lat, lon}).withAlt(alt).withZoom(zoom).withBearing(bearing).withPitch(pitch).withTwist(twist).withFov(fov)); + map.jumpTo(CameraOptions().withCenter(LatLng{lat, lon}).withAlt(alt).withZoom(zoom).withBearing(bearing).withPitch(pitch).withRoll(roll).withFov(fov)); if (debug) { map.setDebug(debug ? mbgl::MapDebugOptions::TileBorders | mbgl::MapDebugOptions::ParseStatus diff --git a/include/mbgl/map/camera.hpp b/include/mbgl/map/camera.hpp index 22352197f05..3cdb136a6fa 100644 --- a/include/mbgl/map/camera.hpp +++ b/include/mbgl/map/camera.hpp @@ -45,8 +45,8 @@ struct CameraOptions { pitch = o; return *this; } - CameraOptions& withTwist(const std::optional& o) { - twist = o; + CameraOptions& withRoll(const std::optional& o) { + roll = o; return *this; } CameraOptions& withFov(const std::optional& o) { @@ -78,13 +78,13 @@ struct CameraOptions { two-dimensional map. */ std::optional pitch; - std::optional twist; + std::optional roll; std::optional fov; }; constexpr bool operator==(const CameraOptions& a, const CameraOptions& b) { return a.center == b.center && a.padding == b.padding && a.anchor == b.anchor && a.zoom == b.zoom && - a.bearing == b.bearing && a.pitch == b.pitch && a.twist == b.twist && a.fov == b.fov && a.altM == b.altM; + a.bearing == b.bearing && a.pitch == b.pitch && a.roll == b.roll && a.fov == b.fov && a.altM == b.altM; } constexpr bool operator!=(const CameraOptions& a, const CameraOptions& b) { @@ -170,7 +170,7 @@ struct FreeCameraOptions { /** Helper function for setting the orientation of the camera as a pitch and a bearing. Both values are in degrees */ - void setPitchBearing(double pitch, double bearing, double twist) noexcept; + void setPitchBearing(double pitch, double bearing, double roll) noexcept; }; } // namespace mbgl diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp index 7c2df9bde41..256d06c7e66 100644 --- a/src/mbgl/map/transform.cpp +++ b/src/mbgl/map/transform.cpp @@ -102,7 +102,7 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim double pitch = camera.pitch ? util::deg2rad(*camera.pitch) : getPitch(); double fov = camera.fov ? util::deg2rad(*camera.fov) : getFieldOfView(); double alt_m = camera.altM.value_or(100000); - double twist = camera.twist ? util::deg2rad(*camera.twist) : getTwist(); + double roll = camera.roll ? util::deg2rad(*camera.roll) : getRoll(); if (std::isnan(zoom) || std::isnan(bearing) || std::isnan(pitch)) { if (animation.transitionFinishFn) { @@ -169,7 +169,7 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim } state.setFieldOfView(fov); state.setAltM(alt_m); - state.setTwist(twist); + state.setRoll(roll); }, duration); } @@ -436,8 +436,8 @@ double Transform::getPitch() const { return state.getPitch(); } -double Transform::getTwist() const { - return state.getTwist(); +double Transform::getRoll() const { + return state.getRoll(); } double Transform::getFieldOfView() const { diff --git a/src/mbgl/map/transform.hpp b/src/mbgl/map/transform.hpp index 592b404191b..a8b6acd2835 100644 --- a/src/mbgl/map/transform.hpp +++ b/src/mbgl/map/transform.hpp @@ -77,7 +77,7 @@ class Transform : private util::noncopyable { // Pitch double getPitch() const; - double getTwist() const; + double getRoll() const; double getFieldOfView() const; // North Orientation diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp index 2eaf0e6f3b4..d8d7daf4d75 100644 --- a/src/mbgl/map/transform_state.cpp +++ b/src/mbgl/map/transform_state.cpp @@ -62,8 +62,8 @@ void TransformState::setProperties(const TransformStateProperties& properties) { if (properties.pitch) { setPitch(*properties.pitch); } - if (properties.twist) { - setTwist(*properties.twist); + if (properties.roll) { + setRoll(*properties.roll); } if (properties.xSkew) { setXSkew(*properties.xSkew); @@ -214,7 +214,7 @@ void TransformState::updateCameraState() const { const double dy = 0.5 * worldSize - y; // Set camera orientation and move it to a proper distance from the map - camera.setOrientation(pitch, getBearing(), getTwist()); + camera.setOrientation(pitch, getBearing(), getRoll()); vec3 cameraPosition = {{dx, dy, z}}; @@ -237,8 +237,8 @@ void TransformState::updateStateFromCamera() { // Compute bearing and pitch double newBearing; double newPitch; - double newTwist; - camera.getOrientation(newPitch, newBearing, newTwist); + double newRoll; + camera.getOrientation(newPitch, newBearing, newRoll); newPitch = util::clamp(newPitch, minPitch, maxPitch); // Compute zoom level from the camera altitude @@ -253,7 +253,7 @@ void TransformState::updateStateFromCamera() { setLatLngZoom(latLngFromMercator(mercatorPoint), scaleZoom(newScale)); setBearing(newBearing); setPitch(newPitch); - setTwist(newTwist); + setRoll(newRoll); } FreeCameraOptions TransformState::getFreeCameraOptions() const { @@ -437,7 +437,7 @@ CameraOptions TransformState::getCameraOptions(const std::optional& .withZoom(getZoom()) .withBearing(util::rad2deg(-bearing)) .withPitch(util::rad2deg(pitch)) - .withTwist(util::rad2deg(twist)) + .withRoll(util::rad2deg(roll)) .withFov(util::rad2deg(fov)); } @@ -621,13 +621,13 @@ void TransformState::setFieldOfView(double val) { } } -double TransformState::getTwist() const { - return twist; +double TransformState::getRoll() const { + return roll; } -void TransformState::setTwist(double val) { - if (twist != val) { - twist = val; +void TransformState::setRoll(double val) { + if (roll != val) { + roll = val; requestMatricesUpdate = true; } } diff --git a/src/mbgl/map/transform_state.hpp b/src/mbgl/map/transform_state.hpp index c602a08e09b..4e4ac583379 100644 --- a/src/mbgl/map/transform_state.hpp +++ b/src/mbgl/map/transform_state.hpp @@ -49,8 +49,8 @@ struct TransformStateProperties { pitch = val; return *this; } - TransformStateProperties& withTwist(const std::optional& val) { - twist = val; + TransformStateProperties& withRoll(const std::optional& val) { + roll = val; return *this; } TransformStateProperties& withXSkew(const std::optional& val) { @@ -105,7 +105,7 @@ struct TransformStateProperties { std::optional scale; std::optional bearing; std::optional pitch; - std::optional twist; + std::optional roll; std::optional xSkew; std::optional ySkew; std::optional axonometric; @@ -195,8 +195,8 @@ class TransformState { float getCameraToCenterDistance() const; double getPitch() const; void setPitch(double); - double getTwist() const; - void setTwist(double); + double getRoll() const; + void setRoll(double); double getXSkew() const; void setXSkew(double); @@ -302,7 +302,7 @@ class TransformState { // with: `fov = 2 * arctan((height / 2) / (height * 1.5))` double fov = 0.6435011087932844; double pitch = 0.0; - double twist = 0.0; + double roll = 0.0; double xSkew = 0.0; double ySkew = 1.0; bool axonometric = false; diff --git a/src/mbgl/util/camera.cpp b/src/mbgl/util/camera.cpp index ea808bffdac..90846ff55c5 100644 --- a/src/mbgl/util/camera.cpp +++ b/src/mbgl/util/camera.cpp @@ -65,13 +65,13 @@ static vec3 toMercator(const LatLng& location, double altitudeMeters) noexcept { altitudeMeters * pixelsPerMeter / worldSize}}; } -static Quaternion orientationFromPitchBearing(double pitch, double bearing, double twist) noexcept { +static Quaternion orientationFromPitchBearing(double pitch, double bearing, double roll) noexcept { // Both angles have to be negated to achieve CW rotation around the axis of rotation Quaternion rotBearing = Quaternion::fromAxisAngle({{0.0, 0.0, 1.0}}, -bearing); Quaternion rotPitch = Quaternion::fromAxisAngle({{1.0, 0.0, 0.0}}, -pitch); - Quaternion rotTwist = Quaternion::fromAxisAngle({{0.0, 0.0, 1.0}}, -twist); + Quaternion rotRoll = Quaternion::fromAxisAngle({{0.0, 0.0, 1.0}}, -roll); - return rotBearing.multiply(rotPitch).multiply(rotTwist); + return rotBearing.multiply(rotPitch).multiply(rotRoll); } static void updateTransform(mat4& transform, const Quaternion& orientation) noexcept { @@ -168,17 +168,17 @@ vec3 Camera::up() const noexcept { return {{-column[0], -column[1], -column[2]}}; } -void Camera::getOrientation(double& pitch, double& bearing, double& twist) const noexcept { +void Camera::getOrientation(double& pitch, double& bearing, double& roll) const noexcept { const vec3 f = forward(); const vec3 r = right(); bearing = std::atan2(-r[1], r[0]); pitch = std::atan2(std::sqrt(f[0] * f[0] + f[1] * f[1]), -f[2]); - twist = 0; //TODO + roll = 0; //TODO } -void Camera::setOrientation(double pitch, double bearing, double twist) noexcept { - orientation = orientationFromPitchBearing(pitch, bearing, twist); +void Camera::setOrientation(double pitch, double bearing, double roll) noexcept { + orientation = orientationFromPitchBearing(pitch, bearing, roll); updateTransform(transform, orientation); } @@ -196,9 +196,9 @@ std::optional Camera::orientationFromFrame(const vec3& forward, cons const double bearing = std::atan2(-right[1], right[0]); const double pitch = std::atan2(std::sqrt(forward[0] * forward[0] + forward[1] * forward[1]), -forward[2]); - const double twist = 0; //TODO + const double roll = 0; //TODO - return util::orientationFromPitchBearing(pitch, bearing, twist); + return util::orientationFromPitchBearing(pitch, bearing, roll); } } // namespace util @@ -241,9 +241,9 @@ void FreeCameraOptions::lookAtPoint(const LatLng& location, const std::optional< orientation = util::Camera::orientationFromFrame(forward, up)->m; } -void FreeCameraOptions::setPitchBearing(double pitch, double bearing, double twist) noexcept { +void FreeCameraOptions::setPitchBearing(double pitch, double bearing, double roll) noexcept { orientation = - util::orientationFromPitchBearing(util::deg2rad(pitch), util::deg2rad(bearing), util::deg2rad(twist)).m; + util::orientationFromPitchBearing(util::deg2rad(pitch), util::deg2rad(bearing), util::deg2rad(roll)).m; } } // namespace mbgl diff --git a/src/mbgl/util/camera.hpp b/src/mbgl/util/camera.hpp index ede6dbc9a56..b4b6d3f7617 100644 --- a/src/mbgl/util/camera.hpp +++ b/src/mbgl/util/camera.hpp @@ -25,8 +25,8 @@ class Camera { vec3 up() const noexcept; const Quaternion& getOrientation() const noexcept { return orientation; } - void getOrientation(double& pitch, double& bearing, double& twist) const noexcept; - void setOrientation(double pitch, double bearing, double twist) noexcept; + void getOrientation(double& pitch, double& bearing, double& roll) const noexcept; + void setOrientation(double pitch, double bearing, double roll) noexcept; void setOrientation(const Quaternion& orientation_) noexcept; void setPosition(const vec3& position) noexcept; From a3b7478749cd61221465ac50ed55c4060af8c486 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 12 Nov 2024 20:55:32 +0000 Subject: [PATCH 12/28] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- bin/render.cpp | 9 ++++++++- src/mbgl/util/camera.cpp | 4 ++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/bin/render.cpp b/bin/render.cpp index 21b1e78882a..d8031274202 100644 --- a/bin/render.cpp +++ b/bin/render.cpp @@ -103,7 +103,14 @@ int main(int argc, char* argv[]) { } map.getStyle().loadURL(style); - map.jumpTo(CameraOptions().withCenter(LatLng{lat, lon}).withAlt(alt).withZoom(zoom).withBearing(bearing).withPitch(pitch).withRoll(roll).withFov(fov)); + map.jumpTo(CameraOptions() + .withCenter(LatLng{lat, lon}) + .withAlt(alt) + .withZoom(zoom) + .withBearing(bearing) + .withPitch(pitch) + .withRoll(roll) + .withFov(fov)); if (debug) { map.setDebug(debug ? mbgl::MapDebugOptions::TileBorders | mbgl::MapDebugOptions::ParseStatus diff --git a/src/mbgl/util/camera.cpp b/src/mbgl/util/camera.cpp index 90846ff55c5..2cd13293287 100644 --- a/src/mbgl/util/camera.cpp +++ b/src/mbgl/util/camera.cpp @@ -174,7 +174,7 @@ void Camera::getOrientation(double& pitch, double& bearing, double& roll) const bearing = std::atan2(-r[1], r[0]); pitch = std::atan2(std::sqrt(f[0] * f[0] + f[1] * f[1]), -f[2]); - roll = 0; //TODO + roll = 0; // TODO } void Camera::setOrientation(double pitch, double bearing, double roll) noexcept { @@ -196,7 +196,7 @@ std::optional Camera::orientationFromFrame(const vec3& forward, cons const double bearing = std::atan2(-right[1], right[0]); const double pitch = std::atan2(std::sqrt(forward[0] * forward[0] + forward[1] * forward[1]), -forward[2]); - const double roll = 0; //TODO + const double roll = 0; // TODO return util::orientationFromPitchBearing(pitch, bearing, roll); } From eb06001c8a62ea2e23dbd450375c287e1933920e Mon Sep 17 00:00:00 2001 From: Nathan Date: Tue, 12 Nov 2024 13:01:47 -0800 Subject: [PATCH 13/28] fix command line abbreviations --- bin/render.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/render.cpp b/bin/render.cpp index d8031274202..93a056b1921 100644 --- a/bin/render.cpp +++ b/bin/render.cpp @@ -33,11 +33,11 @@ int main(int argc, char* argv[]) { args::ValueFlag lonValue(argumentParser, "degrees", "Longitude", {'x', "lon"}); args::ValueFlag latValue(argumentParser, "degrees", "Latitude", {'y', "lat"}); - args::ValueFlag altValue(argumentParser, "degrees", "Altitude", {'y', "alt"}); + args::ValueFlag altValue(argumentParser, "degrees", "Altitude", {'A', "alt"}); args::ValueFlag fovValue(argumentParser, "degrees", "FOV", {'f', "fov"}); args::ValueFlag bearingValue(argumentParser, "degrees", "Bearing", {'b', "bearing"}); args::ValueFlag pitchValue(argumentParser, "degrees", "Pitch", {'p', "pitch"}); - args::ValueFlag rollValue(argumentParser, "degrees", "Roll", {'T', "roll"}); + args::ValueFlag rollValue(argumentParser, "degrees", "Roll", {'R', "roll"}); args::ValueFlag widthValue(argumentParser, "pixels", "Image width", {'w', "width"}); args::ValueFlag heightValue(argumentParser, "pixels", "Image height", {'h', "height"}); From d32dc720289f4dda8034b5b57d85eee40c1ae459 Mon Sep 17 00:00:00 2001 From: Nathan Date: Tue, 12 Nov 2024 13:22:02 -0800 Subject: [PATCH 14/28] clarify altitude --- include/mbgl/map/camera.hpp | 8 ++++---- src/mbgl/map/transform.cpp | 4 ++-- src/mbgl/map/transform_state.cpp | 6 +++--- src/mbgl/map/transform_state.hpp | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/mbgl/map/camera.hpp b/include/mbgl/map/camera.hpp index 3cdb136a6fa..036d0f2737d 100644 --- a/include/mbgl/map/camera.hpp +++ b/include/mbgl/map/camera.hpp @@ -21,8 +21,8 @@ struct CameraOptions { center = o; return *this; } - CameraOptions& withAlt(const std::optional& o) { - altM = o; + CameraOptions& withCenterAltitude(const std::optional& o) { + centerAltitude = o; return *this; } CameraOptions& withPadding(const std::optional& p) { @@ -57,7 +57,7 @@ struct CameraOptions { /** Coordinate at the center of the map. */ std::optional center; - std::optional altM; + std::optional centerAltitude; /** Padding around the interior of the view that affects the frame of reference for `center`. */ @@ -84,7 +84,7 @@ struct CameraOptions { constexpr bool operator==(const CameraOptions& a, const CameraOptions& b) { return a.center == b.center && a.padding == b.padding && a.anchor == b.anchor && a.zoom == b.zoom && - a.bearing == b.bearing && a.pitch == b.pitch && a.roll == b.roll && a.fov == b.fov && a.altM == b.altM; + a.bearing == b.bearing && a.pitch == b.pitch && a.roll == b.roll && a.fov == b.fov && a.centerAltitude == b.centerAltitude; } constexpr bool operator!=(const CameraOptions& a, const CameraOptions& b) { diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp index 256d06c7e66..cef2865bd08 100644 --- a/src/mbgl/map/transform.cpp +++ b/src/mbgl/map/transform.cpp @@ -101,7 +101,7 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim double bearing = camera.bearing ? util::deg2rad(-*camera.bearing) : getBearing(); double pitch = camera.pitch ? util::deg2rad(*camera.pitch) : getPitch(); double fov = camera.fov ? util::deg2rad(*camera.fov) : getFieldOfView(); - double alt_m = camera.altM.value_or(100000); + double center_alt = camera.centerAltitude.value_or(0); double roll = camera.roll ? util::deg2rad(*camera.roll) : getRoll(); if (std::isnan(zoom) || std::isnan(bearing) || std::isnan(pitch)) { @@ -168,7 +168,7 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim state.setPitch(util::interpolate(startPitch, pitch, t)); } state.setFieldOfView(fov); - state.setAltM(alt_m); + state.setCenterAltitude(center_alt); state.setRoll(roll); }, duration); diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp index d8d7daf4d75..b0bbc91b092 100644 --- a/src/mbgl/map/transform_state.cpp +++ b/src/mbgl/map/transform_state.cpp @@ -432,7 +432,7 @@ void TransformState::setViewportMode(ViewportMode val) { CameraOptions TransformState::getCameraOptions(const std::optional& padding) const { return CameraOptions() .withCenter(getLatLng()) - .withAlt(getAltM()) + .withCenterAltitude(getCenterAltitude()) .withPadding(padding ? padding : edgeInsets) .withZoom(getZoom()) .withBearing(util::rad2deg(-bearing)) @@ -456,7 +456,7 @@ LatLng TransformState::getLatLng(LatLng::WrapMode wrapMode) const { return {util::rad2deg(2 * std::atan(std::exp(y / Cc)) - 0.5 * pi), -x / Bc, wrapMode}; } -double TransformState::getAltM() const { +double TransformState::getCenterAltitude() const { return z * Projection::getMetersPerPixelAtLatitude(getLatLng().latitude(), getZoom()); } @@ -838,7 +838,7 @@ void TransformState::setLatLngZoom(const LatLng& latLng, double zoom) { setScalePoint(newScale, point); } -void TransformState::setAltM(double alt_m) { +void TransformState::setCenterAltitude(double alt_m) { z = alt_m / Projection::getMetersPerPixelAtLatitude(getLatLng().latitude(), getZoom()); requestMatricesUpdate = true; } diff --git a/src/mbgl/map/transform_state.hpp b/src/mbgl/map/transform_state.hpp index 4e4ac583379..41a05ab9035 100644 --- a/src/mbgl/map/transform_state.hpp +++ b/src/mbgl/map/transform_state.hpp @@ -154,7 +154,7 @@ class TransformState { // Position LatLng getLatLng(LatLng::WrapMode = LatLng::Unwrapped) const; - double getAltM() const; + double getCenterAltitude() const; double pixel_x() const; double pixel_y() const; @@ -235,7 +235,7 @@ class TransformState { point on screen. */ void moveLatLng(const LatLng&, const ScreenCoordinate&); void setLatLngZoom(const LatLng& latLng, double zoom); - void setAltM(double alt_m); + void setCenterAltitude(double alt_m); void constrain(double& scale, double& x, double& y) const; const mat4& getProjectionMatrix() const; From ef274ecefbf6959017fc84be695d9506167c88ff Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 12 Nov 2024 21:22:55 +0000 Subject: [PATCH 15/28] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- include/mbgl/map/camera.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/mbgl/map/camera.hpp b/include/mbgl/map/camera.hpp index 036d0f2737d..ad09cb1856c 100644 --- a/include/mbgl/map/camera.hpp +++ b/include/mbgl/map/camera.hpp @@ -84,7 +84,8 @@ struct CameraOptions { constexpr bool operator==(const CameraOptions& a, const CameraOptions& b) { return a.center == b.center && a.padding == b.padding && a.anchor == b.anchor && a.zoom == b.zoom && - a.bearing == b.bearing && a.pitch == b.pitch && a.roll == b.roll && a.fov == b.fov && a.centerAltitude == b.centerAltitude; + a.bearing == b.bearing && a.pitch == b.pitch && a.roll == b.roll && a.fov == b.fov && + a.centerAltitude == b.centerAltitude; } constexpr bool operator!=(const CameraOptions& a, const CameraOptions& b) { From 1c4a24edb7a3a90900049b66b5aac1a0b5699c8c Mon Sep 17 00:00:00 2001 From: Nathan Date: Tue, 12 Nov 2024 13:35:25 -0800 Subject: [PATCH 16/28] fix compile --- bin/render.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/render.cpp b/bin/render.cpp index 93a056b1921..7d5c4e4051f 100644 --- a/bin/render.cpp +++ b/bin/render.cpp @@ -105,7 +105,7 @@ int main(int argc, char* argv[]) { map.getStyle().loadURL(style); map.jumpTo(CameraOptions() .withCenter(LatLng{lat, lon}) - .withAlt(alt) + .withCenterAltitude(alt) .withZoom(zoom) .withBearing(bearing) .withPitch(pitch) From b98ea0ad24c9ad33fe69bea691627e610994050f Mon Sep 17 00:00:00 2001 From: Nathan Date: Tue, 12 Nov 2024 13:38:33 -0800 Subject: [PATCH 17/28] fix altitude interpretation --- bin/render.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/render.cpp b/bin/render.cpp index 7d5c4e4051f..ab8fb586338 100644 --- a/bin/render.cpp +++ b/bin/render.cpp @@ -58,7 +58,7 @@ int main(int argc, char* argv[]) { const double lat = latValue ? args::get(latValue) : 0; const double lon = lonValue ? args::get(lonValue) : 0; - const double alt = altValue ? args::get(altValue) : 100000; + const double alt = altValue ? args::get(altValue) : 0; const double zoom = zoomValue ? args::get(zoomValue) : 0; const double fov = fovValue ? args::get(fovValue) : 37; const double bearing = bearingValue ? args::get(bearingValue) : 0; From 1c195c813d1f47149618784fefb0f72b96fb0d8f Mon Sep 17 00:00:00 2001 From: Nathan Date: Tue, 12 Nov 2024 13:45:31 -0800 Subject: [PATCH 18/28] Add comments --- include/mbgl/map/camera.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/mbgl/map/camera.hpp b/include/mbgl/map/camera.hpp index ad09cb1856c..b6d02036372 100644 --- a/include/mbgl/map/camera.hpp +++ b/include/mbgl/map/camera.hpp @@ -57,6 +57,7 @@ struct CameraOptions { /** Coordinate at the center of the map. */ std::optional center; + /** Altitude of the center of the map, in meters above sea level. */ std::optional centerAltitude; /** Padding around the interior of the view that affects the frame of @@ -78,7 +79,10 @@ struct CameraOptions { two-dimensional map. */ std::optional pitch; + /** Camera roll, measured in degrees. */ std::optional roll; + + /** Camera vertical field of view, measured in degrees. */ std::optional fov; }; From f64146851d98f8510fbb44cdc76bdc8783100656 Mon Sep 17 00:00:00 2001 From: Nathan Date: Tue, 12 Nov 2024 13:51:05 -0800 Subject: [PATCH 19/28] better naming --- include/mbgl/map/camera.hpp | 6 +++--- src/mbgl/util/camera.cpp | 2 +- test/util/camera.test.cpp | 10 +++++----- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/mbgl/map/camera.hpp b/include/mbgl/map/camera.hpp index b6d02036372..31d8b6fc438 100644 --- a/include/mbgl/map/camera.hpp +++ b/include/mbgl/map/camera.hpp @@ -173,9 +173,9 @@ struct FreeCameraOptions { bearing can't be deduced from the viewing direction */ void lookAtPoint(const LatLng& location, const std::optional& upVector = std::nullopt) noexcept; - /** Helper function for setting the orientation of the camera as a pitch and - a bearing. Both values are in degrees */ - void setPitchBearing(double pitch, double bearing, double roll) noexcept; + /** Helper function for setting the orientation of the camera as a roll, pitch, and + a bearing. All values are in degrees */ + void setRollPitchBearing(double roll, double pitch, double bearing) noexcept; }; } // namespace mbgl diff --git a/src/mbgl/util/camera.cpp b/src/mbgl/util/camera.cpp index 2cd13293287..60fadd3d51f 100644 --- a/src/mbgl/util/camera.cpp +++ b/src/mbgl/util/camera.cpp @@ -241,7 +241,7 @@ void FreeCameraOptions::lookAtPoint(const LatLng& location, const std::optional< orientation = util::Camera::orientationFromFrame(forward, up)->m; } -void FreeCameraOptions::setPitchBearing(double pitch, double bearing, double roll) noexcept { +void FreeCameraOptions::setRollPitchBearing(double roll, double pitch, double bearing) noexcept { orientation = util::orientationFromPitchBearing(util::deg2rad(pitch), util::deg2rad(bearing), util::deg2rad(roll)).m; } diff --git a/test/util/camera.test.cpp b/test/util/camera.test.cpp index de93f297a80..b29f7cf8990 100644 --- a/test/util/camera.test.cpp +++ b/test/util/camera.test.cpp @@ -226,18 +226,18 @@ TEST(FreeCameraOptions, LookAtPointInvalidInput) { ASSERT_FALSE(options.orientation); } -TEST(FreeCameraOptions, SetPitchBearing) { +TEST(FreeCameraOptions, SetRollPitchBearing) { FreeCameraOptions options; vec3 right, up, forward; - options.setPitchBearing(0.0, 0.0); + options.setRollPitchBearing(0.0, 0.0, 0.0); ASSERT_TRUE(options.orientation); std::tie(right, up, forward) = rotatedFrame(options.orientation.value()); ASSERT_THAT(right, Vec3NearEquals1E7(vec3{{1.0, 0.0, 0.0}})); ASSERT_THAT(up, Vec3NearEquals1E7(vec3{{0.0, -1.0, 0.0}})); ASSERT_THAT(forward, Vec3NearEquals1E7(vec3{{0.0, 0.0, -1.0}})); - options.setPitchBearing(0.0, 180.0); + options.setRollPitchBearing(0.0, 0.0, 180.0); ASSERT_TRUE(options.orientation); std::tie(right, up, forward) = rotatedFrame(options.orientation.value()); ASSERT_THAT(right, Vec3NearEquals1E7(vec3{{-1.0, 0.0, 0.0}})); @@ -247,14 +247,14 @@ TEST(FreeCameraOptions, SetPitchBearing) { const double cos60 = std::cos(util::deg2rad(60.0)); const double sin60 = std::sin(util::deg2rad(60.0)); - options.setPitchBearing(60.0, 0.0); + options.setRollPitchBearing(0.0, 60.0, 0.0); ASSERT_TRUE(options.orientation); std::tie(right, up, forward) = rotatedFrame(options.orientation.value()); ASSERT_THAT(right, Vec3NearEquals1E7(vec3{{1.0, 0.0, 0.0}})); ASSERT_THAT(up, Vec3NearEquals1E7(vec3{{0.0, -cos60, sin60}})); ASSERT_THAT(forward, Vec3NearEquals1E7(vec3{{0.0, -sin60, -cos60}})); - options.setPitchBearing(60.0, -450); + options.setRollPitchBearing(0.0, 60.0, -450); ASSERT_TRUE(options.orientation); std::tie(right, up, forward) = rotatedFrame(options.orientation.value()); ASSERT_THAT(right, Vec3NearEquals1E7(vec3{{0.0, 1.0, 0.0}})); From e39788daa449e27158e97edd4f971dd5008bbc97 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 12 Nov 2024 21:54:09 +0000 Subject: [PATCH 20/28] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- include/mbgl/map/camera.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mbgl/map/camera.hpp b/include/mbgl/map/camera.hpp index 31d8b6fc438..5786ed89794 100644 --- a/include/mbgl/map/camera.hpp +++ b/include/mbgl/map/camera.hpp @@ -81,7 +81,7 @@ struct CameraOptions { /** Camera roll, measured in degrees. */ std::optional roll; - + /** Camera vertical field of view, measured in degrees. */ std::optional fov; }; From fd9fa000df8d57aad50923fea097d315aa1a64f6 Mon Sep 17 00:00:00 2001 From: Nathan Date: Tue, 12 Nov 2024 14:19:09 -0800 Subject: [PATCH 21/28] fov handling improvements --- include/mbgl/util/constants.hpp | 2 +- src/mbgl/map/transform_state.cpp | 14 ++++++++------ src/mbgl/util/camera.cpp | 10 +++++----- src/mbgl/util/camera.hpp | 2 +- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/include/mbgl/util/constants.hpp b/include/mbgl/util/constants.hpp index a805e1d5dd9..33f91892956 100644 --- a/include/mbgl/util/constants.hpp +++ b/include/mbgl/util/constants.hpp @@ -31,7 +31,7 @@ constexpr double EARTH_RADIUS_M = 6378137; constexpr double LATITUDE_MAX = 85.051128779806604; constexpr double LONGITUDE_MAX = 180; constexpr double DEGREES_MAX = 360; -constexpr double PITCH_MIN = 0; +constexpr double PITCH_MIN = 0.0; constexpr double PITCH_MAX = M_PI; constexpr double MIN_ZOOM = 0.0; constexpr double MAX_ZOOM = 25.5; diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp index b0bbc91b092..d4cd8baec99 100644 --- a/src/mbgl/map/transform_state.cpp +++ b/src/mbgl/map/transform_state.cpp @@ -8,6 +8,7 @@ #include #include #include + #include using namespace std::numbers; @@ -120,6 +121,7 @@ void TransformState::getProjMatrix(mat4& projMatrix, uint16_t nearZ, bool aligne return; } + const double cameraToCenterDistance = getCameraToCenterDistance(); const ScreenCoordinate offset = getCenterOffset(); // Find the Z distance from the viewport center point @@ -129,12 +131,12 @@ void TransformState::getProjMatrix(mat4& projMatrix, uint16_t nearZ, bool aligne // (the distance between[width/2, height/2] and [width/2 + 1, height/2]) // See https://github.com/mapbox/mapbox-gl-native/pull/15195 for details. // See TransformState::fov description: fov = 2 * arctan((height / 2) / (height * 1.5)). - const double tanFovAboveCenter = (0.5 + offset.y / size.height) * 2.0 * - tan(getFieldOfView() * hypot(size.height, size.width) / size.height / 2.0); - const double maxElevationAngle = pitch + atan(tanFovAboveCenter); + const double tanFovAboveCenter = (0.5 + offset.y / size.height) * 2.0 * std::tan(getFieldOfView() / 2.0) + * (std::abs(std::cos(roll)) + std::abs(std::sin(roll)) * size.width / size.height); + const double tanMultiple = tanFovAboveCenter * std::tan(getPitch()); + assert(tanMultiple < 1); // Calculate z distance of the farthest fragment that should be rendered. - - double furthestDistance = static_cast(getZ() / cos(std::min(maxElevationAngle, MAX_PITCH))); + const double furthestDistance = cameraToCenterDistance / (1 - tanMultiple); // Add a bit extra to avoid precision problems when a fragment's distance is exactly `furthestDistance` const double farZ = furthestDistance * 1.01; @@ -214,7 +216,7 @@ void TransformState::updateCameraState() const { const double dy = 0.5 * worldSize - y; // Set camera orientation and move it to a proper distance from the map - camera.setOrientation(pitch, getBearing(), getRoll()); + camera.setOrientation(getRoll(), pitch, getBearing()); vec3 cameraPosition = {{dx, dy, z}}; diff --git a/src/mbgl/util/camera.cpp b/src/mbgl/util/camera.cpp index 60fadd3d51f..3cde5bb0032 100644 --- a/src/mbgl/util/camera.cpp +++ b/src/mbgl/util/camera.cpp @@ -65,7 +65,7 @@ static vec3 toMercator(const LatLng& location, double altitudeMeters) noexcept { altitudeMeters * pixelsPerMeter / worldSize}}; } -static Quaternion orientationFromPitchBearing(double pitch, double bearing, double roll) noexcept { +static Quaternion orientationFromRollPitchBearing(double roll, double pitch, double bearing) noexcept { // Both angles have to be negated to achieve CW rotation around the axis of rotation Quaternion rotBearing = Quaternion::fromAxisAngle({{0.0, 0.0, 1.0}}, -bearing); Quaternion rotPitch = Quaternion::fromAxisAngle({{1.0, 0.0, 0.0}}, -pitch); @@ -177,8 +177,8 @@ void Camera::getOrientation(double& pitch, double& bearing, double& roll) const roll = 0; // TODO } -void Camera::setOrientation(double pitch, double bearing, double roll) noexcept { - orientation = orientationFromPitchBearing(pitch, bearing, roll); +void Camera::setOrientation(double roll, double pitch, double bearing) noexcept { + orientation = orientationFromRollPitchBearing(roll, pitch, bearing); updateTransform(transform, orientation); } @@ -198,7 +198,7 @@ std::optional Camera::orientationFromFrame(const vec3& forward, cons const double pitch = std::atan2(std::sqrt(forward[0] * forward[0] + forward[1] * forward[1]), -forward[2]); const double roll = 0; // TODO - return util::orientationFromPitchBearing(pitch, bearing, roll); + return util::orientationFromRollPitchBearing(pitch, bearing, roll); } } // namespace util @@ -243,7 +243,7 @@ void FreeCameraOptions::lookAtPoint(const LatLng& location, const std::optional< void FreeCameraOptions::setRollPitchBearing(double roll, double pitch, double bearing) noexcept { orientation = - util::orientationFromPitchBearing(util::deg2rad(pitch), util::deg2rad(bearing), util::deg2rad(roll)).m; + util::orientationFromRollPitchBearing(util::deg2rad(roll), util::deg2rad(pitch), util::deg2rad(bearing)).m; } } // namespace mbgl diff --git a/src/mbgl/util/camera.hpp b/src/mbgl/util/camera.hpp index b4b6d3f7617..e26fd29e1c4 100644 --- a/src/mbgl/util/camera.hpp +++ b/src/mbgl/util/camera.hpp @@ -26,7 +26,7 @@ class Camera { const Quaternion& getOrientation() const noexcept { return orientation; } void getOrientation(double& pitch, double& bearing, double& roll) const noexcept; - void setOrientation(double pitch, double bearing, double roll) noexcept; + void setOrientation(double roll, double pitch, double bearing) noexcept; void setOrientation(const Quaternion& orientation_) noexcept; void setPosition(const vec3& position) noexcept; From 92b6017a488d361d3e3e97a0dbfe1e4e3a2a2fa9 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 12 Nov 2024 22:34:56 +0000 Subject: [PATCH 22/28] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/mbgl/map/transform_state.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp index d4cd8baec99..a1a3bdb4379 100644 --- a/src/mbgl/map/transform_state.cpp +++ b/src/mbgl/map/transform_state.cpp @@ -131,8 +131,8 @@ void TransformState::getProjMatrix(mat4& projMatrix, uint16_t nearZ, bool aligne // (the distance between[width/2, height/2] and [width/2 + 1, height/2]) // See https://github.com/mapbox/mapbox-gl-native/pull/15195 for details. // See TransformState::fov description: fov = 2 * arctan((height / 2) / (height * 1.5)). - const double tanFovAboveCenter = (0.5 + offset.y / size.height) * 2.0 * std::tan(getFieldOfView() / 2.0) - * (std::abs(std::cos(roll)) + std::abs(std::sin(roll)) * size.width / size.height); + const double tanFovAboveCenter = (0.5 + offset.y / size.height) * 2.0 * std::tan(getFieldOfView() / 2.0) * + (std::abs(std::cos(roll)) + std::abs(std::sin(roll)) * size.width / size.height); const double tanMultiple = tanFovAboveCenter * std::tan(getPitch()); assert(tanMultiple < 1); // Calculate z distance of the farthest fragment that should be rendered. From c001e50cc2545c02d4dcf8bec54bd3816aeca6b5 Mon Sep 17 00:00:00 2001 From: Nathan Date: Tue, 12 Nov 2024 15:39:25 -0800 Subject: [PATCH 23/28] formatting --- src/mbgl/map/transform_state.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp index a1a3bdb4379..60f3576e8ba 100644 --- a/src/mbgl/map/transform_state.cpp +++ b/src/mbgl/map/transform_state.cpp @@ -131,13 +131,12 @@ void TransformState::getProjMatrix(mat4& projMatrix, uint16_t nearZ, bool aligne // (the distance between[width/2, height/2] and [width/2 + 1, height/2]) // See https://github.com/mapbox/mapbox-gl-native/pull/15195 for details. // See TransformState::fov description: fov = 2 * arctan((height / 2) / (height * 1.5)). - const double tanFovAboveCenter = (0.5 + offset.y / size.height) * 2.0 * std::tan(getFieldOfView() / 2.0) * + const double tanFovAboveCenter = (0.5 + offset.y / size.height) * 2.0 * std::tan(fov / 2.0) * (std::abs(std::cos(roll)) + std::abs(std::sin(roll)) * size.width / size.height); const double tanMultiple = tanFovAboveCenter * std::tan(getPitch()); assert(tanMultiple < 1); // Calculate z distance of the farthest fragment that should be rendered. const double furthestDistance = cameraToCenterDistance / (1 - tanMultiple); - // Add a bit extra to avoid precision problems when a fragment's distance is exactly `furthestDistance` const double farZ = furthestDistance * 1.01; From ee93d55641b3a47746531a3ba7af2212eca1f74a Mon Sep 17 00:00:00 2001 From: Nathan Date: Tue, 12 Nov 2024 15:49:28 -0800 Subject: [PATCH 24/28] cleanup --- include/mbgl/map/camera.hpp | 1 - src/mbgl/map/transform_state.cpp | 11 ++++++++--- src/mbgl/util/camera.cpp | 2 +- src/mbgl/util/camera.hpp | 2 +- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/include/mbgl/map/camera.hpp b/include/mbgl/map/camera.hpp index 5786ed89794..5357647b3bc 100644 --- a/include/mbgl/map/camera.hpp +++ b/include/mbgl/map/camera.hpp @@ -156,7 +156,6 @@ struct FreeCameraOptions { 0, 0] Orientation can be set freely but certain constraints still apply - - Orientation must be representable with only pitch and bearing. - Pitch has an upper limit */ std::optional orientation = std::nullopt; diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp index 60f3576e8ba..77bfb628d80 100644 --- a/src/mbgl/map/transform_state.cpp +++ b/src/mbgl/map/transform_state.cpp @@ -205,6 +205,7 @@ void TransformState::updateCameraState() const { } const double worldSize = Projection::worldSize(scale); + const double cameraToCenterDistance = getCameraToCenterDistance(); // x & y tracks the center of the map in pixels. However as rendering is // done in pixel coordinates the rendering origo is actually in the middle @@ -215,9 +216,13 @@ void TransformState::updateCameraState() const { const double dy = 0.5 * worldSize - y; // Set camera orientation and move it to a proper distance from the map - camera.setOrientation(getRoll(), pitch, getBearing()); + camera.setOrientation(getRoll(), getPitch(), getBearing()); - vec3 cameraPosition = {{dx, dy, z}}; + const vec3 forward = camera.forward(); + const vec3 orbitPosition = {{-forward[0] * cameraToCenterDistance, + -forward[1] * cameraToCenterDistance, + -forward[2] * cameraToCenterDistance}}; + vec3 cameraPosition = {{dx + orbitPosition[0], dy + orbitPosition[1], z + orbitPosition[2]}}; cameraPosition[0] /= worldSize; cameraPosition[1] /= worldSize; @@ -239,7 +244,7 @@ void TransformState::updateStateFromCamera() { double newBearing; double newPitch; double newRoll; - camera.getOrientation(newPitch, newBearing, newRoll); + camera.getOrientation(newRoll, newPitch, newBearing); newPitch = util::clamp(newPitch, minPitch, maxPitch); // Compute zoom level from the camera altitude diff --git a/src/mbgl/util/camera.cpp b/src/mbgl/util/camera.cpp index 3cde5bb0032..fa3a0edd390 100644 --- a/src/mbgl/util/camera.cpp +++ b/src/mbgl/util/camera.cpp @@ -168,7 +168,7 @@ vec3 Camera::up() const noexcept { return {{-column[0], -column[1], -column[2]}}; } -void Camera::getOrientation(double& pitch, double& bearing, double& roll) const noexcept { +void Camera::getOrientation(double& roll, double& pitch, double& bearing) const noexcept { const vec3 f = forward(); const vec3 r = right(); diff --git a/src/mbgl/util/camera.hpp b/src/mbgl/util/camera.hpp index e26fd29e1c4..d5119dc480b 100644 --- a/src/mbgl/util/camera.hpp +++ b/src/mbgl/util/camera.hpp @@ -25,7 +25,7 @@ class Camera { vec3 up() const noexcept; const Quaternion& getOrientation() const noexcept { return orientation; } - void getOrientation(double& pitch, double& bearing, double& roll) const noexcept; + void getOrientation(double& roll, double& pitch, double& bearing) const noexcept; void setOrientation(double roll, double pitch, double bearing) noexcept; void setOrientation(const Quaternion& orientation_) noexcept; void setPosition(const vec3& position) noexcept; From fb7ffe76f1a39edcfa97785a15ed077e0b1ff5ed Mon Sep 17 00:00:00 2001 From: Nathan Date: Tue, 12 Nov 2024 16:14:20 -0800 Subject: [PATCH 25/28] cleanup --- src/mbgl/map/transform_state.cpp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp index 77bfb628d80..6a671ef33df 100644 --- a/src/mbgl/map/transform_state.cpp +++ b/src/mbgl/map/transform_state.cpp @@ -13,8 +13,6 @@ using namespace std::numbers; -constexpr double MAX_PITCH = 1.55; - namespace mbgl { namespace { @@ -299,14 +297,11 @@ bool TransformState::setCameraOrientation(const Quaternion& orientation_) { return false; } - std::optional updatedOrientation = util::Camera::orientationFromFrame(forward, up); - - if (updatedOrientation) { - camera.setOrientation(*updatedOrientation); - return true; - } + const std::optional updatedOrientation = util::Camera::orientationFromFrame(forward, up); + if (!updatedOrientation) return false; - return false; + camera.setOrientation(updatedOrientation.value()); + return true; } void TransformState::setFreeCameraOptions(const FreeCameraOptions& options) { @@ -639,11 +634,11 @@ void TransformState::setRoll(double val) { } float TransformState::getCameraToCenterDistance() const { - return static_cast(getZ() / cos(std::min(pitch, MAX_PITCH))); + return static_cast(0.5 * size.height / std::tan(fov / 2.0)); } double TransformState::getPitch() const { - return std::min(pitch, MAX_PITCH); + return pitch; } void TransformState::setPitch(double val) { From c150fd656713b4dc91bdaac029d9a38cdd5e9621 Mon Sep 17 00:00:00 2001 From: Nathan Date: Tue, 12 Nov 2024 16:42:40 -0800 Subject: [PATCH 26/28] restore bounds limits, and interpolate center altitude in easeTo() and flyTo() --- src/mbgl/map/transform.cpp | 8 ++++++-- src/mbgl/map/transform_state.cpp | 9 ++++++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp index cef2865bd08..3cbbff923e9 100644 --- a/src/mbgl/map/transform.cpp +++ b/src/mbgl/map/transform.cpp @@ -101,7 +101,7 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim double bearing = camera.bearing ? util::deg2rad(-*camera.bearing) : getBearing(); double pitch = camera.pitch ? util::deg2rad(*camera.pitch) : getPitch(); double fov = camera.fov ? util::deg2rad(*camera.fov) : getFieldOfView(); - double center_alt = camera.centerAltitude.value_or(0); + double centerAlt = camera.centerAltitude.value_or(state.getCenterAltitude()); double roll = camera.roll ? util::deg2rad(*camera.roll) : getRoll(); if (std::isnan(zoom) || std::isnan(bearing) || std::isnan(pitch)) { @@ -139,6 +139,7 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim const double startZoom = state.getZoom(); const double startBearing = state.getBearing(); const double startPitch = state.getPitch(); + const double startCenterAlt = state.getCenterAltitude(); state.setProperties(TransformStateProperties() .withPanningInProgress(unwrappedLatLng != startLatLng) .withScalingInProgress(zoom != startZoom) @@ -153,6 +154,7 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim LatLng frameLatLng = Projection::unproject(framePoint, state.zoomScale(startZoom)); double frameZoom = util::interpolate(startZoom, zoom, t); state.setLatLngZoom(frameLatLng, frameZoom); + state.setCenterAltitude(util::interpolate(startCenterAlt, centerAlt, t)); if (bearing != startBearing) { state.setBearing(util::wrap(util::interpolate(startBearing, bearing, t), -pi, pi)); } @@ -168,7 +170,6 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim state.setPitch(util::interpolate(startPitch, pitch, t)); } state.setFieldOfView(fov); - state.setCenterAltitude(center_alt); state.setRoll(roll); }, duration); @@ -185,6 +186,7 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim void Transform::flyTo(const CameraOptions& camera, const AnimationOptions& animation, bool linearZoomInterpolation) { const EdgeInsets& padding = camera.padding.value_or(state.getEdgeInsets()); const LatLng& latLng = camera.center.value_or(getLatLng(LatLng::Unwrapped)).wrapped(); + const double centerAlt = camera.centerAltitude.value_or(state.getCenterAltitude()); double zoom = camera.zoom.value_or(getZoom()); double bearing = camera.bearing ? util::deg2rad(-*camera.bearing) : getBearing(); double pitch = camera.pitch ? util::deg2rad(*camera.pitch) : getPitch(); @@ -199,6 +201,7 @@ void Transform::flyTo(const CameraOptions& camera, const AnimationOptions& anima // Determine endpoints. LatLng startLatLng = getLatLng(LatLng::Unwrapped).wrapped(); startLatLng.unwrapForShortestPath(latLng); + const double startCenterAlt = state.getCenterAltitude(); const Point startPoint = Projection::project(startLatLng, state.getScale()); const Point endPoint = Projection::project(latLng, state.getScale()); @@ -326,6 +329,7 @@ void Transform::flyTo(const CameraOptions& camera, const AnimationOptions& anima // Convert to geographic coordinates and set the new viewpoint. LatLng frameLatLng = Projection::unproject(framePoint, startScale); state.setLatLngZoom(frameLatLng, frameZoom); + state.setCenterAltitude(util::interpolate(startCenterAlt, centerAlt, us)); if (bearing != startBearing) { state.setBearing(util::wrap(util::interpolate(startBearing, bearing, k), -pi, pi)); } diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp index 6a671ef33df..8ecdf0623db 100644 --- a/src/mbgl/map/transform_state.cpp +++ b/src/mbgl/map/transform_state.cpp @@ -273,7 +273,14 @@ FreeCameraOptions TransformState::getFreeCameraOptions() const { bool TransformState::setCameraPosition(const vec3& position) { if (std::isnan(position[0]) || std::isnan(position[1]) || std::isnan(position[2])) return false; - camera.setPosition(position); + const double maxWorldSize = Projection::worldSize(std::pow(2.0, getMaxZoom())); + const double minWorldSize = Projection::worldSize(std::pow(2.0, getMinZoom())); + const double distToCenter = getCameraToCenterDistance(); + + const vec3 updatedPos = vec3{ + {position[0], position[1], util::clamp(position[2], distToCenter / maxWorldSize, distToCenter / minWorldSize)}}; + + camera.setPosition(updatedPos); return true; } From 8d06c07de804c2a40ecf009eab2957922e8f0952 Mon Sep 17 00:00:00 2001 From: Nathan Date: Tue, 12 Nov 2024 16:53:16 -0800 Subject: [PATCH 27/28] interpolate fov in easeTo and flyTo, and limit FOV --- src/mbgl/map/transform.cpp | 14 ++++++++++++-- src/mbgl/map/transform_state.cpp | 8 ++++++++ src/mbgl/map/transform_state.hpp | 4 ++++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp index 3cbbff923e9..c8e124e11eb 100644 --- a/src/mbgl/map/transform.cpp +++ b/src/mbgl/map/transform.cpp @@ -124,6 +124,7 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim startLatLng.unwrapForShortestPath(latLng); } } + const double startCenterAlt = state.getCenterAltitude(); const Point startPoint = Projection::project(startLatLng, state.getScale()); const Point endPoint = Projection::project(latLng, state.getScale()); @@ -131,6 +132,7 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim // Constrain camera options. zoom = util::clamp(zoom, state.getMinZoom(), state.getMaxZoom()); pitch = util::clamp(pitch, state.getMinPitch(), state.getMaxPitch()); + fov = util::clamp(fov, state.getMinFieldOfView(), state.getMaxFieldOfView()); // Minimize rotation by taking the shorter path around the circle. bearing = _normalizeAngle(bearing, state.getBearing()); @@ -139,7 +141,7 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim const double startZoom = state.getZoom(); const double startBearing = state.getBearing(); const double startPitch = state.getPitch(); - const double startCenterAlt = state.getCenterAltitude(); + const double startFov = state.getFieldOfView(); state.setProperties(TransformStateProperties() .withPanningInProgress(unwrappedLatLng != startLatLng) .withScalingInProgress(zoom != startZoom) @@ -169,7 +171,9 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim if (pitch != startPitch) { state.setPitch(util::interpolate(startPitch, pitch, t)); } - state.setFieldOfView(fov); + if (fov != startFov) { + state.setFieldOfView(util::interpolate(startFov, fov, t)); + } state.setRoll(roll); }, duration); @@ -190,6 +194,7 @@ void Transform::flyTo(const CameraOptions& camera, const AnimationOptions& anima double zoom = camera.zoom.value_or(getZoom()); double bearing = camera.bearing ? util::deg2rad(-*camera.bearing) : getBearing(); double pitch = camera.pitch ? util::deg2rad(*camera.pitch) : getPitch(); + double fov = camera.fov ? util::deg2rad(*camera.fov) : getFieldOfView(); if (std::isnan(zoom) || std::isnan(bearing) || std::isnan(pitch) || state.getSize().isEmpty()) { if (animation.transitionFinishFn) { @@ -209,6 +214,7 @@ void Transform::flyTo(const CameraOptions& camera, const AnimationOptions& anima // Constrain camera options. zoom = util::clamp(zoom, state.getMinZoom(), state.getMaxZoom()); pitch = util::clamp(pitch, state.getMinPitch(), state.getMaxPitch()); + fov = util::clamp(fov, state.getMinFieldOfView(), state.getMaxFieldOfView()); // Minimize rotation by taking the shorter path around the circle. bearing = _normalizeAngle(bearing, state.getBearing()); @@ -216,6 +222,7 @@ void Transform::flyTo(const CameraOptions& camera, const AnimationOptions& anima const double startZoom = state.scaleZoom(state.getScale()); const double startBearing = state.getBearing(); const double startPitch = state.getPitch(); + const double startFov = state.getFieldOfView(); /// w₀: Initial visible span, measured in pixels at the initial scale. /// Known henceforth as a screenful. @@ -345,6 +352,9 @@ void Transform::flyTo(const CameraOptions& camera, const AnimationOptions& anima if (pitch != startPitch) { state.setPitch(util::interpolate(startPitch, pitch, k)); } + if (fov != startFov) { + state.setFieldOfView(util::interpolate(startFov, fov, k)); + } }, duration); } diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp index 8ecdf0623db..a0ad723d5e1 100644 --- a/src/mbgl/map/transform_state.cpp +++ b/src/mbgl/map/transform_state.cpp @@ -558,6 +558,14 @@ double TransformState::getMaxPitch() const { return maxPitch; } +double TransformState::getMinFieldOfView() const { + return minFov; +} + +double TransformState::getMaxFieldOfView() const { + return maxFov; +} + // MARK: - Scale double TransformState::getScale() const { return scale; diff --git a/src/mbgl/map/transform_state.hpp b/src/mbgl/map/transform_state.hpp index 41a05ab9035..be81f13e7ac 100644 --- a/src/mbgl/map/transform_state.hpp +++ b/src/mbgl/map/transform_state.hpp @@ -186,6 +186,8 @@ class TransformState { double getMinPitch() const; void setMaxPitch(double); double getMaxPitch() const; + double getMinFieldOfView() const; + double getMaxFieldOfView() const; // Rotation double getBearing() const; @@ -260,6 +262,8 @@ class TransformState { // Limit the amount of pitch double minPitch = util::PITCH_MIN; double maxPitch = util::PITCH_MAX; + double minFov = util::deg2rad(0.1); + double maxFov = util::deg2rad(150.0); NorthOrientation orientation = NorthOrientation::Upwards; From 8b8b63cba84bf0a27a21b50ea56e068cd0d6be94 Mon Sep 17 00:00:00 2001 From: Nathan Date: Tue, 12 Nov 2024 16:56:04 -0800 Subject: [PATCH 28/28] interpolate roll --- src/mbgl/map/transform.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp index c8e124e11eb..732c18667f1 100644 --- a/src/mbgl/map/transform.cpp +++ b/src/mbgl/map/transform.cpp @@ -141,6 +141,7 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim const double startZoom = state.getZoom(); const double startBearing = state.getBearing(); const double startPitch = state.getPitch(); + const double startRoll = state.getRoll(); const double startFov = state.getFieldOfView(); state.setProperties(TransformStateProperties() .withPanningInProgress(unwrappedLatLng != startLatLng) @@ -171,10 +172,12 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim if (pitch != startPitch) { state.setPitch(util::interpolate(startPitch, pitch, t)); } + if (roll != startRoll) { + state.setPitch(util::interpolate(startRoll, roll, t)); + } if (fov != startFov) { state.setFieldOfView(util::interpolate(startFov, fov, t)); } - state.setRoll(roll); }, duration); } @@ -194,6 +197,7 @@ void Transform::flyTo(const CameraOptions& camera, const AnimationOptions& anima double zoom = camera.zoom.value_or(getZoom()); double bearing = camera.bearing ? util::deg2rad(-*camera.bearing) : getBearing(); double pitch = camera.pitch ? util::deg2rad(*camera.pitch) : getPitch(); + double roll = camera.roll ? util::deg2rad(*camera.roll) : getRoll(); double fov = camera.fov ? util::deg2rad(*camera.fov) : getFieldOfView(); if (std::isnan(zoom) || std::isnan(bearing) || std::isnan(pitch) || state.getSize().isEmpty()) { @@ -222,6 +226,7 @@ void Transform::flyTo(const CameraOptions& camera, const AnimationOptions& anima const double startZoom = state.scaleZoom(state.getScale()); const double startBearing = state.getBearing(); const double startPitch = state.getPitch(); + const double startRoll = state.getRoll(); const double startFov = state.getFieldOfView(); /// w₀: Initial visible span, measured in pixels at the initial scale. @@ -352,6 +357,9 @@ void Transform::flyTo(const CameraOptions& camera, const AnimationOptions& anima if (pitch != startPitch) { state.setPitch(util::interpolate(startPitch, pitch, k)); } + if (roll != startRoll) { + state.setPitch(util::interpolate(startRoll, roll, k)); + } if (fov != startFov) { state.setFieldOfView(util::interpolate(startFov, fov, k)); }