diff options
author | Mikko Pulkki <mikko.pulkki@mapbox.com> | 2020-04-27 13:28:46 +0300 |
---|---|---|
committer | Mikko Pulkki <55925868+mpulkki-mapbox@users.noreply.github.com> | 2020-05-02 17:07:02 +0300 |
commit | 83c06c1f99bf82fb1bc695b8b38fe1ea1dd91dde (patch) | |
tree | dbe6a4d917458b67787ad0b2d35e1bf23db062fb /src/mbgl | |
parent | 57b4b2829e8033d6cf3f7bd48c1fe511e00b830c (diff) | |
download | qtlocation-mapboxgl-83c06c1f99bf82fb1bc695b8b38fe1ea1dd91dde.tar.gz |
Add FreeCameraOptions to the Map class
Diffstat (limited to 'src/mbgl')
-rw-r--r-- | src/mbgl/map/map.cpp | 10 | ||||
-rw-r--r-- | src/mbgl/map/transform.cpp | 9 | ||||
-rw-r--r-- | src/mbgl/map/transform.hpp | 3 | ||||
-rw-r--r-- | src/mbgl/map/transform_state.cpp | 81 | ||||
-rw-r--r-- | src/mbgl/map/transform_state.hpp | 5 | ||||
-rw-r--r-- | src/mbgl/util/camera.cpp | 47 |
6 files changed, 153 insertions, 2 deletions
diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index 91a657294c..afaa1223ce 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -500,4 +500,14 @@ void Map::dumpDebugLogs() const { Log::Info(Event::General, "--------------------------------------------------------------------------------"); } +void Map::setFreeCameraOptions(const FreeCameraOptions& camera) { + impl->transform.setFreeCameraOptions(camera); + impl->cameraMutated = true; + impl->onUpdate(); +} + +FreeCameraOptions Map::getFreeCameraOptions() const { + return impl->transform.getFreeCameraOptions(); +} + } // namespace mbgl diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp index 3e3584e5ba..b20f9b59fd 100644 --- a/src/mbgl/map/transform.cpp +++ b/src/mbgl/map/transform.cpp @@ -650,4 +650,13 @@ double Transform::getMaxPitchForEdgeInsets(const EdgeInsets& insets) const { // e.g. Maximum pitch of 60 degrees is when perspective center's offset from the top is 84% of screen height. } +FreeCameraOptions Transform::getFreeCameraOptions() const { + return state.getFreeCameraOptions(); +} + +void Transform::setFreeCameraOptions(const FreeCameraOptions& options) { + cancelTransitions(); + state.setFreeCameraOptions(options); +} + } // namespace mbgl diff --git a/src/mbgl/map/transform.hpp b/src/mbgl/map/transform.hpp index 38fb302b7b..90be7a9ef7 100644 --- a/src/mbgl/map/transform.hpp +++ b/src/mbgl/map/transform.hpp @@ -113,6 +113,9 @@ public: ScreenCoordinate latLngToScreenCoordinate(const LatLng&) const; LatLng screenCoordinateToLatLng(const ScreenCoordinate&, LatLng::WrapMode = LatLng::Wrapped) const; + FreeCameraOptions getFreeCameraOptions() const; + void setFreeCameraOptions(const FreeCameraOptions& options); + private: MapObserver& observer; TransformState state; diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp index a61d02963a..d9acecf888 100644 --- a/src/mbgl/map/transform_state.cpp +++ b/src/mbgl/map/transform_state.cpp @@ -177,8 +177,8 @@ void TransformState::updateCameraState() const { // 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 of the map (0.5 * worldSize). x&y positions have to be negated because it defines - // position of the map, not the camera. Moving map 10 units left has the same effect as moving camera 10 units to the - // right. + // position of the map, not the camera. Moving map 10 units left has the same effect as moving camera 10 units to + // the right. const double dx = 0.5 * worldSize - x; const double dy = 0.5 * worldSize - y; @@ -226,6 +226,83 @@ void TransformState::updateStateFromCamera() { setBearing(newBearing); setPitch(newPitch); } + +FreeCameraOptions TransformState::getFreeCameraOptions() const { + updateCameraState(); + + FreeCameraOptions options; + options.position = camera.getPosition(); + options.orientation = camera.getOrientation().m; + + return options; +} + +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); + return true; +} + +bool TransformState::setCameraOrientation(const Quaternion& orientation_) { + const vec4& c = orientation_.m; + if (std::isnan(c[0]) || std::isnan(c[1]) || std::isnan(c[2]) || std::isnan(c[3])) { + return false; + } + + // Zero-length quaternions are not valid + if (orientation_.length() == 0.0) { + return false; + } + + Quaternion unitQuat = orientation_.normalized(); + const vec3 forward = unitQuat.transform({{0.0, 0.0, -1.0}}); + const vec3 up = unitQuat.transform({{0.0, -1.0, 0.0}}); + + if (up[2] < 0.0) { + // Camera is upside down and not recoverable + return false; + } + + const optional<Quaternion> updatedOrientation = util::Camera::orientationFromFrame(forward, up); + if (!updatedOrientation) return false; + + camera.setOrientation(updatedOrientation.value()); + return true; +} + +void TransformState::setFreeCameraOptions(const FreeCameraOptions& options) { + if (!valid()) { + return; + } + + if (!options.position && !options.orientation) return; + + // Check if the state is dirty and camera needs to be synchronized + updateMatricesIfNeeded(); + + bool changed = false; + if (options.orientation && options.orientation.value() != camera.getOrientation().m) { + changed |= setCameraOrientation(options.orientation.value()); + } + + if (options.position && options.position.value() != camera.getPosition()) { + changed |= setCameraPosition(options.position.value()); + } + + if (changed) { + updateStateFromCamera(); + requestMatricesUpdate = true; + } +} + void TransformState::updateMatricesIfNeeded() const { if (!needsMatricesUpdate() || size.isEmpty()) return; diff --git a/src/mbgl/map/transform_state.hpp b/src/mbgl/map/transform_state.hpp index aade9be098..aa27067172 100644 --- a/src/mbgl/map/transform_state.hpp +++ b/src/mbgl/map/transform_state.hpp @@ -219,6 +219,9 @@ public: const mat4& getProjectionMatrix() const; const mat4& getInvProjectionMatrix() const; + FreeCameraOptions getFreeCameraOptions() const; + void setFreeCameraOptions(const FreeCameraOptions& options); + private: bool rotatedNorth() const; @@ -249,6 +252,8 @@ private: void updateMatricesIfNeeded() const; bool needsMatricesUpdate() const { return requestMatricesUpdate; } + bool setCameraPosition(const vec3& position); + bool setCameraOrientation(const Quaternion& orientation); void updateCameraState() const; void updateStateFromCamera(); diff --git a/src/mbgl/util/camera.cpp b/src/mbgl/util/camera.cpp index f64e24ab2d..34d27620ac 100644 --- a/src/mbgl/util/camera.cpp +++ b/src/mbgl/util/camera.cpp @@ -212,4 +212,51 @@ optional<Quaternion> Camera::orientationFromFrame(const vec3& forward, const vec return util::orientationFromPitchBearing(pitch, bearing); } } // namespace util + +void FreeCameraOptions::setLocation(const LatLngAltitude& location) { + position = util::toMercator(location.location, location.altitude); +} + +optional<LatLngAltitude> FreeCameraOptions::getLocation() const { + if (!position) { + return nullopt; + } + + const vec3 positionValue = position.value(); + if (positionValue[1] < 0.0 || positionValue[1] > 1.0) { + return nullopt; + } + + const LatLng location = {util::latFromMercatorY(positionValue[1]), util::lngFromMercatorX(positionValue[0])}; + + const double metersPerPixel = Projection::getMetersPerPixelAtLatitude(location.latitude(), 0.0); + const double worldSize = Projection::worldSize(std::pow(2.0, 0.0)); + const double altitude = positionValue[2] * worldSize * metersPerPixel; + + return LatLngAltitude{location, altitude}; +} + +void FreeCameraOptions::lookAtPoint(const LatLng& location, const optional<vec3>& upVector) { + orientation = nullopt; + if (!position) { + return; + } + + const vec3 target = util::toMercator(location, 0.0); + const vec3 forward = vec3Sub(target, position.value()); + vec3 up = upVector ? upVector.value() : vec3{{0.0, 0.0, 1.0}}; + + // 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; + } +} + +void FreeCameraOptions::setPitchBearing(double pitch, double bearing) { + orientation = util::orientationFromPitchBearing(pitch * util::DEG2RAD, bearing * util::DEG2RAD).m; +} + } // namespace mbgl
\ No newline at end of file |