diff options
Diffstat (limited to 'src/mbgl/map/transform_state.cpp')
-rw-r--r-- | src/mbgl/map/transform_state.cpp | 81 |
1 files changed, 79 insertions, 2 deletions
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; |