summaryrefslogtreecommitdiff
path: root/src/mbgl/map
diff options
context:
space:
mode:
authorzmiao <miao.zhao@mapbox.com>2019-12-05 18:58:48 +0200
committerGitHub <noreply@github.com>2019-12-05 18:58:48 +0200
commit9f3a384296f019b1b3719b39389ae5be995a4d37 (patch)
treed34f24778c3f4541295ea6ae7f7516bd2b656ff2 /src/mbgl/map
parente619552a5df5fdfa3c95efa0959ff2da20eac452 (diff)
downloadqtlocation-mapboxgl-9f3a384296f019b1b3719b39389ae5be995a4d37.tar.gz
[core] Refactoring transform state (#15956)
* [core] Refactoring transform state class * [core] update matrix in transform, Fix precision * [core] Make matrix mutable so that we only update them when needed * [core] Add getters for matrices
Diffstat (limited to 'src/mbgl/map')
-rw-r--r--src/mbgl/map/transform.cpp274
-rw-r--r--src/mbgl/map/transform.hpp5
-rw-r--r--src/mbgl/map/transform_state.cpp276
-rw-r--r--src/mbgl/map/transform_state.hpp152
4 files changed, 518 insertions, 189 deletions
diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp
index 6b44e633d9..9245d7c5bc 100644
--- a/src/mbgl/map/transform.cpp
+++ b/src/mbgl/map/transform.cpp
@@ -49,14 +49,17 @@ void Transform::resize(const Size size) {
throw std::runtime_error("failed to resize: size is empty");
}
- if (state.size == size) {
+ if (state.getSize() == size) {
return;
}
observer.onCameraWillChange(MapObserver::CameraChangeMode::Immediate);
-
- state.size = size;
- state.constrain(state.scale, state.x, state.y);
+ state.setSize(size);
+ double scale{state.getScale()};
+ double x{state.getX()};
+ double y{state.getY()};
+ state.constrain(scale, x, y);
+ state.setProperties(TransformStateProperties().withScale(scale).withX(x).withY(y));
observer.onCameraDidChange(MapObserver::CameraChangeMode::Immediate);
}
@@ -83,14 +86,14 @@ void Transform::jumpTo(const CameraOptions& camera) {
*/
void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& animation) {
Duration duration = animation.duration.value_or(Duration::zero());
- if (state.bounds == LatLngBounds() && !isGestureInProgress() && duration != Duration::zero()) {
+ if (state.getLatLngBounds() == LatLngBounds() && !isGestureInProgress() && duration != Duration::zero()) {
// reuse flyTo, without exaggerated animation, to achieve constant ground speed.
return flyTo(camera, animation, true);
}
- const EdgeInsets& padding = camera.padding.value_or(state.edgeInsets);
+ const EdgeInsets& padding = camera.padding.value_or(state.getEdgeInsets());
LatLng startLatLng = getLatLng(LatLng::Unwrapped);
const LatLng& unwrappedLatLng = camera.center.value_or(startLatLng);
- const LatLng& latLng = state.bounds != LatLngBounds() ? unwrappedLatLng : unwrappedLatLng.wrapped();
+ const LatLng& latLng = state.getLatLngBounds() != LatLngBounds() ? unwrappedLatLng : unwrappedLatLng.wrapped();
double zoom = camera.zoom.value_or(getZoom());
double bearing = camera.bearing ? -*camera.bearing * util::DEG2RAD : getBearing();
double pitch = camera.pitch ? *camera.pitch * util::DEG2RAD : getPitch();
@@ -102,7 +105,7 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim
return;
}
- if (state.bounds == LatLngBounds()) {
+ if (state.getLatLngBounds() == LatLngBounds()) {
if (isGestureInProgress()) {
// If gesture in progress, we transfer the wrap rounds from the end longitude into
// start, so the "scroll effect" of rounding the world is the same while assuring the
@@ -115,48 +118,51 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim
}
}
- const Point<double> startPoint = Projection::project(startLatLng, state.scale);
- const Point<double> endPoint = Projection::project(latLng, state.scale);
+ const Point<double> startPoint = Projection::project(startLatLng, state.getScale());
+ const Point<double> endPoint = Projection::project(latLng, state.getScale());
// Constrain camera options.
zoom = util::clamp(zoom, state.getMinZoom(), state.getMaxZoom());
pitch = util::clamp(pitch, util::PITCH_MIN, util::PITCH_MAX);
// Minimize rotation by taking the shorter path around the circle.
- bearing = _normalizeAngle(bearing, state.bearing);
- state.bearing = _normalizeAngle(state.bearing, bearing);
+ bearing = _normalizeAngle(bearing, state.getBearing());
+ state.setBearing(_normalizeAngle(state.getBearing(), bearing));
const double startZoom = state.getZoom();
- const double startBearing = state.bearing;
- const double startPitch = state.pitch;
- state.panning = unwrappedLatLng != startLatLng;
- state.scaling = zoom != startZoom;
- state.rotating = bearing != startBearing;
- const EdgeInsets startEdgeInsets = state.edgeInsets;
-
- startTransition(camera, animation, [=](double t) {
- Point<double> framePoint = util::interpolate(startPoint, endPoint, t);
- LatLng frameLatLng = Projection::unproject(framePoint, state.zoomScale(startZoom));
- double frameZoom = util::interpolate(startZoom, zoom, t);
- state.setLatLngZoom(frameLatLng, frameZoom);
-
- if (bearing != startBearing) {
- state.bearing = util::wrap(util::interpolate(startBearing, bearing, t), -M_PI, M_PI);
- }
- if (padding != startEdgeInsets) {
- // Interpolate edge insets
- state.edgeInsets = {
- util::interpolate(startEdgeInsets.top(), padding.top(), t),
- util::interpolate(startEdgeInsets.left(), padding.left(), t),
- util::interpolate(startEdgeInsets.bottom(), padding.bottom(), t),
- util::interpolate(startEdgeInsets.right(), padding.right(), t)
- };
- }
- auto maxPitch = getMaxPitchForEdgeInsets(state.edgeInsets);
- if (pitch != startPitch || maxPitch < startPitch) {
- state.pitch = std::min(maxPitch, util::interpolate(startPitch, pitch, t));
- }
- }, duration);
+ const double startBearing = state.getBearing();
+ const double startPitch = state.getPitch();
+ state.setProperties(TransformStateProperties()
+ .withPanningInProgress(unwrappedLatLng != startLatLng)
+ .withScalingInProgress(zoom != startZoom)
+ .withRotatingInProgress(bearing != startBearing));
+ const EdgeInsets startEdgeInsets = state.getEdgeInsets();
+
+ startTransition(
+ camera,
+ animation,
+ [=](double t) {
+ Point<double> framePoint = util::interpolate(startPoint, endPoint, t);
+ LatLng frameLatLng = Projection::unproject(framePoint, state.zoomScale(startZoom));
+ double frameZoom = util::interpolate(startZoom, zoom, t);
+ state.setLatLngZoom(frameLatLng, frameZoom);
+ if (bearing != startBearing) {
+ state.setBearing(util::wrap(util::interpolate(startBearing, bearing, t), -M_PI, M_PI));
+ }
+ if (padding != startEdgeInsets) {
+ // Interpolate edge insets
+ EdgeInsets edgeInsets;
+ state.setEdgeInsets({util::interpolate(startEdgeInsets.top(), padding.top(), t),
+ util::interpolate(startEdgeInsets.left(), padding.left(), t),
+ 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)));
+ }
+ },
+ duration);
}
/** This method implements an “optimal path” animation, as detailed in:
@@ -167,14 +173,14 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim
Where applicable, local variable documentation begins with the associated
variable or function in van Wijk (2003). */
-void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &animation, bool linearZoomInterpolation) {
- const EdgeInsets& padding = camera.padding.value_or(state.edgeInsets);
+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();
double zoom = camera.zoom.value_or(getZoom());
double bearing = camera.bearing ? -*camera.bearing * util::DEG2RAD : getBearing();
double pitch = camera.pitch ? *camera.pitch * util::DEG2RAD : getPitch();
- if (std::isnan(zoom) || std::isnan(bearing) || std::isnan(pitch) || state.size.isEmpty()) {
+ if (std::isnan(zoom) || std::isnan(bearing) || std::isnan(pitch) || state.getSize().isEmpty()) {
if (animation.transitionFinishFn) {
animation.transitionFinishFn();
}
@@ -185,25 +191,25 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima
LatLng startLatLng = getLatLng(LatLng::Unwrapped).wrapped();
startLatLng.unwrapForShortestPath(latLng);
- const Point<double> startPoint = Projection::project(startLatLng, state.scale);
- const Point<double> endPoint = Projection::project(latLng, state.scale);
+ const Point<double> startPoint = Projection::project(startLatLng, state.getScale());
+ const Point<double> endPoint = Projection::project(latLng, state.getScale());
// Constrain camera options.
zoom = util::clamp(zoom, state.getMinZoom(), state.getMaxZoom());
pitch = util::clamp(pitch, util::PITCH_MIN, util::PITCH_MAX);
// Minimize rotation by taking the shorter path around the circle.
- bearing = _normalizeAngle(bearing, state.bearing);
- state.bearing = _normalizeAngle(state.bearing, bearing);
-
- const double startZoom = state.scaleZoom(state.scale);
- const double startBearing = state.bearing;
- const double startPitch = state.pitch;
+ bearing = _normalizeAngle(bearing, state.getBearing());
+ state.setBearing(_normalizeAngle(state.getBearing(), bearing));
+ const double startZoom = state.scaleZoom(state.getScale());
+ const double startBearing = state.getBearing();
+ const double startPitch = state.getPitch();
/// w₀: Initial visible span, measured in pixels at the initial scale.
/// Known henceforth as a <i>screenful</i>.
- double w0 = std::max(state.size.width - padding.left() - padding.right(),
- state.size.height - padding.top() - padding.bottom());
+
+ double w0 = std::max(state.getSize().width - padding.left() - padding.right(),
+ state.getSize().height - padding.top() - padding.bottom());
/// w₁: Final visible span, measured in pixels with respect to the initial
/// scale.
double w1 = w0 / state.zoomScale(zoom - startZoom);
@@ -286,56 +292,60 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima
return;
}
- const double startScale = state.scale;
- state.panning = true;
- state.scaling = true;
- state.rotating = bearing != startBearing;
- const EdgeInsets startEdgeInsets = state.edgeInsets;
-
- startTransition(camera, animation, [=](double k) {
- /// s: The distance traveled along the flight path, measured in
- /// ρ-screenfuls.
- double s = k * S;
- double us = k == 1.0 ? 1.0 : u(s);
-
- // Calculate the current point and zoom level along the flight path.
- Point<double> framePoint = util::interpolate(startPoint, endPoint, us);
- double frameZoom = linearZoomInterpolation ? util::interpolate(startZoom, zoom, k)
- : startZoom + state.scaleZoom(1 / w(s));
-
- // Zoom can be NaN if size is empty.
- if (std::isnan(frameZoom)) {
- frameZoom = zoom;
- }
+ const double startScale = state.getScale();
+ state.setProperties(
+ TransformStateProperties().withPanningInProgress(true).withScalingInProgress(true).withRotatingInProgress(
+ bearing != startBearing));
+ const EdgeInsets startEdgeInsets = state.getEdgeInsets();
+
+ startTransition(
+ camera,
+ animation,
+ [=](double k) {
+ /// s: The distance traveled along the flight path, measured in
+ /// ρ-screenfuls.
+ double s = k * S;
+ double us = k == 1.0 ? 1.0 : u(s);
+
+ // Calculate the current point and zoom level along the flight path.
+ Point<double> framePoint = util::interpolate(startPoint, endPoint, us);
+ double frameZoom =
+ linearZoomInterpolation ? util::interpolate(startZoom, zoom, k) : startZoom + state.scaleZoom(1 / w(s));
+
+ // Zoom can be NaN if size is empty.
+ if (std::isnan(frameZoom)) {
+ frameZoom = zoom;
+ }
- // Convert to geographic coordinates and set the new viewpoint.
- LatLng frameLatLng = Projection::unproject(framePoint, startScale);
- state.setLatLngZoom(frameLatLng, frameZoom);
+ // Convert to geographic coordinates and set the new viewpoint.
+ LatLng frameLatLng = Projection::unproject(framePoint, startScale);
+ state.setLatLngZoom(frameLatLng, frameZoom);
+ if (bearing != startBearing) {
+ state.setBearing(util::wrap(util::interpolate(startBearing, bearing, k), -M_PI, M_PI));
+ }
- if (bearing != startBearing) {
- state.bearing = util::wrap(util::interpolate(startBearing, bearing, k), -M_PI, M_PI);
- }
- if (padding != startEdgeInsets) {
- // Interpolate edge insets
- state.edgeInsets = {
- util::interpolate(startEdgeInsets.top(), padding.top(), k),
- util::interpolate(startEdgeInsets.left(), padding.left(), k),
- util::interpolate(startEdgeInsets.bottom(), padding.bottom(), k),
- util::interpolate(startEdgeInsets.right(), padding.right(), k)
- };
- }
- auto maxPitch = getMaxPitchForEdgeInsets(state.edgeInsets);
- if (pitch != startPitch || maxPitch < startPitch) {
- state.pitch = std::min(maxPitch, util::interpolate(startPitch, pitch, k));
- }
- }, duration);
+ if (padding != startEdgeInsets) {
+ // Interpolate edge insets
+ state.setEdgeInsets({util::interpolate(startEdgeInsets.top(), padding.top(), k),
+ util::interpolate(startEdgeInsets.left(), padding.left(), k),
+ 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)));
+ }
+ },
+ duration);
}
#pragma mark - Position
void Transform::moveBy(const ScreenCoordinate& offset, const AnimationOptions& animation) {
- ScreenCoordinate centerOffset = { offset.x, offset.y };
- ScreenCoordinate pointOnScreen = state.edgeInsets.getCenter(state.size.width, state.size.height) - centerOffset;
+ ScreenCoordinate centerOffset = {offset.x, offset.y};
+ ScreenCoordinate pointOnScreen =
+ state.getEdgeInsets().getCenter(state.getSize().width, state.getSize().height) - centerOffset;
// Use unwrapped LatLng to carry information about moveBy direction.
easeTo(CameraOptions().withCenter(screenCoordinateToLatLng(pointOnScreen, LatLng::Unwrapped)), animation);
}
@@ -371,8 +381,10 @@ void Transform::setMaxZoom(const double maxZoom) {
#pragma mark - Bearing
-void Transform::rotateBy(const ScreenCoordinate& first, const ScreenCoordinate& second, const AnimationOptions& animation) {
- ScreenCoordinate center = state.edgeInsets.getCenter(state.size.width, state.size.height);
+void Transform::rotateBy(const ScreenCoordinate& first,
+ const ScreenCoordinate& second,
+ const AnimationOptions& animation) {
+ ScreenCoordinate center = state.getEdgeInsets().getCenter(state.getSize().width, state.getSize().height);
const ScreenCoordinate offset = first - center;
const double distance = std::sqrt(std::pow(2, offset.x) + std::pow(2, offset.y));
@@ -385,25 +397,29 @@ void Transform::rotateBy(const ScreenCoordinate& first, const ScreenCoordinate&
center.y = first.y + std::sin(rotateBearing) * heightOffset;
}
- const double bearing = -(state.bearing + util::angle_between(first - center, second - center)) * util::RAD2DEG;
+ const double bearing = -(state.getBearing() + util::angle_between(first - center, second - center)) * util::RAD2DEG;
easeTo(CameraOptions().withBearing(bearing), animation);
}
double Transform::getBearing() const {
- return state.bearing;
+ return state.getBearing();
}
#pragma mark - Pitch
double Transform::getPitch() const {
- return state.pitch;
+ return state.getPitch();
}
#pragma mark - North Orientation
void Transform::setNorthOrientation(NorthOrientation orientation) {
- state.orientation = orientation;
- state.constrain(state.scale, state.x, state.y);
+ state.setNorthOrientation(orientation);
+ double scale{state.getScale()};
+ double x{state.getX()};
+ double y{state.getY()};
+ state.constrain(scale, x, y);
+ state.setProperties(TransformStateProperties().withScale(scale).withX(x).withY(y));
}
NorthOrientation Transform::getNorthOrientation() const {
@@ -413,8 +429,12 @@ NorthOrientation Transform::getNorthOrientation() const {
#pragma mark - Constrain mode
void Transform::setConstrainMode(mbgl::ConstrainMode mode) {
- state.constrainMode = mode;
- state.constrain(state.scale, state.x, state.y);
+ state.setConstrainMode(mode);
+ double scale{state.getScale()};
+ double x{state.getX()};
+ double y{state.getY()};
+ state.constrain(scale, x, y);
+ state.setProperties(TransformStateProperties().withScale(scale).withX(x).withY(y));
}
ConstrainMode Transform::getConstrainMode() const {
@@ -424,7 +444,7 @@ ConstrainMode Transform::getConstrainMode() const {
#pragma mark - Viewport mode
void Transform::setViewportMode(mbgl::ViewportMode mode) {
- state.viewportMode = mode;
+ state.setViewportMode(mode);
}
ViewportMode Transform::getViewportMode() const {
@@ -434,16 +454,17 @@ ViewportMode Transform::getViewportMode() const {
#pragma mark - Projection mode
void Transform::setProjectionMode(const ProjectionMode& options) {
- state.axonometric = options.axonometric.value_or(state.axonometric);
- state.xSkew = options.xSkew.value_or(state.xSkew);
- state.ySkew = options.ySkew.value_or(state.ySkew);
+ state.setProperties(TransformStateProperties()
+ .withAxonometric(options.axonometric.value_or(state.getAxonometric()))
+ .withXSkew(options.xSkew.value_or(state.getXSkew()))
+ .withYSkew(options.ySkew.value_or(state.getYSkew())));
}
ProjectionMode Transform::getProjectionMode() const {
return ProjectionMode()
- .withAxonometric(state.axonometric)
- .withXSkew(state.xSkew)
- .withYSkew(state.ySkew);
+ .withAxonometric(state.getAxonometric())
+ .withXSkew(state.getXSkew())
+ .withYSkew(state.getYSkew());
}
#pragma mark - Transition
@@ -457,7 +478,8 @@ void Transform::startTransition(const CameraOptions& camera,
}
bool isAnimated = duration != Duration::zero();
- observer.onCameraWillChange(isAnimated ? MapObserver::CameraChangeMode::Animated : MapObserver::CameraChangeMode::Immediate);
+ observer.onCameraWillChange(isAnimated ? MapObserver::CameraChangeMode::Animated
+ : MapObserver::CameraChangeMode::Immediate);
// Associate the anchor, if given, with a coordinate.
// Anchor and center points are mutually exclusive, with preference for the
@@ -465,7 +487,7 @@ void Transform::startTransition(const CameraOptions& camera,
optional<ScreenCoordinate> anchor = camera.center ? nullopt : camera.anchor;
LatLng anchorLatLng;
if (anchor) {
- anchor->y = state.size.height - anchor->y;
+ anchor->y = state.getSize().height - anchor->y;
anchorLatLng = state.screenCoordinateToLatLng(*anchor);
}
@@ -497,13 +519,14 @@ void Transform::startTransition(const CameraOptions& camera,
};
transitionFinishFn = [isAnimated, animation, this] {
- state.panning = false;
- state.scaling = false;
- state.rotating = false;
+ state.setProperties(
+ TransformStateProperties().withPanningInProgress(false).withScalingInProgress(false).withRotatingInProgress(
+ false));
if (animation.transitionFinishFn) {
animation.transitionFinishFn();
}
- observer.onCameraDidChange(isAnimated ? MapObserver::CameraChangeMode::Animated : MapObserver::CameraChangeMode::Immediate);
+ observer.onCameraDidChange(isAnimated ? MapObserver::CameraChangeMode::Animated
+ : MapObserver::CameraChangeMode::Immediate);
};
if (!isAnimated) {
@@ -573,28 +596,27 @@ void Transform::cancelTransitions() {
}
void Transform::setGestureInProgress(bool inProgress) {
- state.gestureInProgress = inProgress;
+ state.setGestureInProgress(inProgress);
}
#pragma mark Conversion and projection
ScreenCoordinate Transform::latLngToScreenCoordinate(const LatLng& latLng) const {
ScreenCoordinate point = state.latLngToScreenCoordinate(latLng);
- point.y = state.size.height - point.y;
+ point.y = state.getSize().height - point.y;
return point;
}
LatLng Transform::screenCoordinateToLatLng(const ScreenCoordinate& point, LatLng::WrapMode wrapMode) const {
ScreenCoordinate flippedPoint = point;
- flippedPoint.y = state.size.height - flippedPoint.y;
+ flippedPoint.y = state.getSize().height - flippedPoint.y;
return state.screenCoordinateToLatLng(flippedPoint, wrapMode);
}
-double Transform::getMaxPitchForEdgeInsets(const EdgeInsets &insets) const
-{
+double Transform::getMaxPitchForEdgeInsets(const EdgeInsets& insets) const {
double centerOffsetY = 0.5 * (insets.top() - insets.bottom()); // See TransformState::getCenterOffset.
- const auto height = state.size.height;
+ const auto height = state.getSize().height;
assert(height);
// For details, see description at https://github.com/mapbox/mapbox-gl-native/pull/15195
// The definition of half of TransformState::fov with no inset, is: fov = arctan((height / 2) / (height * 1.5)).
diff --git a/src/mbgl/map/transform.hpp b/src/mbgl/map/transform.hpp
index 30ce8a37a4..3dd1a3ffc5 100644
--- a/src/mbgl/map/transform.hpp
+++ b/src/mbgl/map/transform.hpp
@@ -114,10 +114,7 @@ private:
MapObserver& observer;
TransformState state;
- void startTransition(const CameraOptions&,
- const AnimationOptions&,
- std::function<void(double)>,
- const Duration&);
+ void startTransition(const CameraOptions&, const AnimationOptions&, std::function<void(double)>, const Duration&);
// We don't want to show horizon: limit max pitch based on edge insets.
double getMaxPitchForEdgeInsets(const EdgeInsets &insets) const;
diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp
index f3cd8c3886..c8f1c7f594 100644
--- a/src/mbgl/map/transform_state.cpp
+++ b/src/mbgl/map/transform_state.cpp
@@ -8,10 +8,60 @@
#include <mbgl/math/clamp.hpp>
namespace mbgl {
-
TransformState::TransformState(ConstrainMode constrainMode_, ViewportMode viewportMode_)
: bounds(LatLngBounds()), constrainMode(constrainMode_), viewportMode(viewportMode_) {}
+void TransformState::setProperties(const TransformStateProperties& properties) {
+ if (properties.x) {
+ setX(*properties.x);
+ }
+ if (properties.y) {
+ setY(*properties.y);
+ }
+ if (properties.scale) {
+ setScale(*properties.scale);
+ }
+ if (properties.bearing) {
+ setBearing(*properties.bearing);
+ }
+ if (properties.pitch) {
+ setPitch(*properties.pitch);
+ }
+ if (properties.xSkew) {
+ setXSkew(*properties.xSkew);
+ }
+ if (properties.ySkew) {
+ setYSkew(*properties.ySkew);
+ }
+ if (properties.axonometric) {
+ setAxonometric(*properties.axonometric);
+ }
+ if (properties.panning) {
+ setPanningInProgress(*properties.panning);
+ }
+ if (properties.scaling) {
+ setScalingInProgress(*properties.scaling);
+ }
+ if (properties.rotating) {
+ setRotatingInProgress(*properties.rotating);
+ }
+ if (properties.edgeInsets) {
+ setEdgeInsets(*properties.edgeInsets);
+ }
+ if (properties.size) {
+ setSize(*properties.size);
+ }
+ if (properties.constrain) {
+ setConstrainMode(*properties.constrain);
+ }
+ if (properties.northOrientation) {
+ setNorthOrientation(*properties.northOrientation);
+ }
+ if (properties.viewPortMode) {
+ setViewportMode(*properties.viewPortMode);
+ }
+}
+
#pragma mark - Matrix
void TransformState::matrixFor(mat4& matrix, const UnwrappedTileID& tileID) const {
@@ -19,9 +69,8 @@ void TransformState::matrixFor(mat4& matrix, const UnwrappedTileID& tileID) cons
const double s = Projection::worldSize(scale) / tileScale;
matrix::identity(matrix);
- matrix::translate(matrix, matrix,
- int64_t(tileID.canonical.x + tileID.wrap * tileScale) * s,
- int64_t(tileID.canonical.y) * s, 0);
+ matrix::translate(
+ matrix, matrix, int64_t(tileID.canonical.x + tileID.wrap * tileScale) * s, int64_t(tileID.canonical.y) * s, 0);
matrix::scale(matrix, matrix, s / util::EXTENT, s / util::EXTENT, 1);
}
@@ -65,10 +114,18 @@ void TransformState::getProjMatrix(mat4& projMatrix, uint16_t nearZ, bool aligne
using NO = NorthOrientation;
switch (getNorthOrientation()) {
- case NO::Rightwards: matrix::rotate_y(projMatrix, projMatrix, getPitch()); break;
- case NO::Downwards: matrix::rotate_x(projMatrix, projMatrix, -getPitch()); break;
- case NO::Leftwards: matrix::rotate_y(projMatrix, projMatrix, -getPitch()); break;
- default: matrix::rotate_x(projMatrix, projMatrix, getPitch()); break;
+ case NO::Rightwards:
+ matrix::rotate_y(projMatrix, projMatrix, getPitch());
+ break;
+ case NO::Downwards:
+ matrix::rotate_x(projMatrix, projMatrix, -getPitch());
+ break;
+ case NO::Leftwards:
+ matrix::rotate_y(projMatrix, projMatrix, -getPitch());
+ break;
+ default:
+ matrix::rotate_x(projMatrix, projMatrix, getPitch());
+ break;
}
matrix::rotate_z(projMatrix, projMatrix, getBearing() + getNorthOrientationAngle());
@@ -104,18 +161,59 @@ void TransformState::getProjMatrix(mat4& projMatrix, uint16_t nearZ, bool aligne
}
}
+void TransformState::updateMatricesIfNeeded() const {
+ if (!needsMatricesUpdate() || size.isEmpty()) return;
+
+ getProjMatrix(projectionMatrix);
+ coordMatrix = coordinatePointMatrix(projectionMatrix);
+
+ bool err = matrix::invert(invertedMatrix, coordMatrix);
+
+ if (err) throw std::runtime_error("failed to invert coordinatePointMatrix");
+ requestMatricesUpdate = false;
+}
+
+const mat4& TransformState::getProjectionMatrix() const {
+ updateMatricesIfNeeded();
+ return projectionMatrix;
+}
+
+const mat4& TransformState::getCoordMatrix() const {
+ updateMatricesIfNeeded();
+ return coordMatrix;
+}
+
+const mat4& TransformState::getInvertedMatrix() const {
+ updateMatricesIfNeeded();
+ return invertedMatrix;
+}
+
#pragma mark - Dimensions
Size TransformState::getSize() const {
return size;
}
+void TransformState::setSize(const Size& size_) {
+ if (size != size_) {
+ size = size_;
+ requestMatricesUpdate = true;
+ }
+}
+
#pragma mark - North Orientation
NorthOrientation TransformState::getNorthOrientation() const {
return orientation;
}
+void TransformState::setNorthOrientation(const NorthOrientation val) {
+ if (orientation != val) {
+ orientation = val;
+ requestMatricesUpdate = true;
+ }
+}
+
double TransformState::getNorthOrientationAngle() const {
double angleOrientation = 0;
if (orientation == NorthOrientation::Rightwards) {
@@ -134,12 +232,26 @@ ConstrainMode TransformState::getConstrainMode() const {
return constrainMode;
}
+void TransformState::setConstrainMode(const ConstrainMode val) {
+ if (constrainMode != val) {
+ constrainMode = val;
+ requestMatricesUpdate = true;
+ }
+}
+
#pragma mark - ViewportMode
ViewportMode TransformState::getViewportMode() const {
return viewportMode;
}
+void TransformState::setViewportMode(ViewportMode val) {
+ if (viewportMode != val) {
+ viewportMode = val;
+ requestMatricesUpdate = true;
+ }
+}
+
#pragma mark - Camera options
CameraOptions TransformState::getCameraOptions(optional<EdgeInsets> padding) const {
@@ -151,14 +263,19 @@ CameraOptions TransformState::getCameraOptions(optional<EdgeInsets> padding) con
.withPitch(pitch * util::RAD2DEG);
}
+#pragma mark - EdgeInsets
+
+void TransformState::setEdgeInsets(const EdgeInsets& val) {
+ if (edgeInsets != val) {
+ edgeInsets = val;
+ requestMatricesUpdate = true;
+ }
+}
+
#pragma mark - Position
LatLng TransformState::getLatLng(LatLng::WrapMode wrapMode) const {
- return {
- util::RAD2DEG * (2 * std::atan(std::exp(y / Cc)) - 0.5 * M_PI),
- -x / Bc,
- wrapMode
- };
+ return {util::RAD2DEG * (2 * std::atan(std::exp(y / Cc)) - 0.5 * M_PI), -x / Bc, wrapMode};
}
double TransformState::pixel_x() const {
@@ -223,12 +340,55 @@ double TransformState::getMaxZoom() const {
return scaleZoom(max_scale);
}
+#pragma mark - Scale
+double TransformState::getScale() const {
+ return scale;
+}
+
+void TransformState::setScale(double val) {
+ if (scale != val) {
+ scale = val;
+ requestMatricesUpdate = true;
+ }
+}
+
+#pragma mark - Positions
+
+double TransformState::getX() const {
+ return x;
+}
+
+void TransformState::setX(double val) {
+ if (x != val) {
+ x = val;
+ requestMatricesUpdate = true;
+ }
+}
+
+double TransformState::getY() const {
+ return y;
+}
+
+void TransformState::setY(double val) {
+ if (y != val) {
+ y = val;
+ requestMatricesUpdate = true;
+ }
+}
+
#pragma mark - Rotation
-float TransformState::getBearing() const {
+double TransformState::getBearing() const {
return bearing;
}
+void TransformState::setBearing(double val) {
+ if (bearing != val) {
+ bearing = val;
+ requestMatricesUpdate = true;
+ }
+}
+
float TransformState::getFieldOfView() const {
return fov;
}
@@ -237,10 +397,49 @@ float TransformState::getCameraToCenterDistance() const {
return 0.5 * size.height / std::tan(fov / 2.0);
}
-float TransformState::getPitch() const {
+double TransformState::getPitch() const {
return pitch;
}
+void TransformState::setPitch(double val) {
+ if (pitch != val) {
+ pitch = val;
+ requestMatricesUpdate = true;
+ }
+}
+
+double TransformState::getXSkew() const {
+ return xSkew;
+}
+
+void TransformState::setXSkew(double val) {
+ if (xSkew != val) {
+ xSkew = val;
+ requestMatricesUpdate = true;
+ }
+}
+double TransformState::getYSkew() const {
+ return ySkew;
+}
+
+void TransformState::setYSkew(double val) {
+ if (ySkew != val) {
+ ySkew = val;
+ requestMatricesUpdate = true;
+ }
+}
+
+bool TransformState::getAxonometric() const {
+ return axonometric;
+}
+
+void TransformState::setAxonometric(bool val) {
+ if (axonometric != val) {
+ axonometric = val;
+ requestMatricesUpdate = true;
+ }
+}
+
#pragma mark - State
bool TransformState::isChanging() const {
@@ -278,26 +477,19 @@ ScreenCoordinate TransformState::latLngToScreenCoordinate(const LatLng& latLng)
return {};
}
- mat4 mat = coordinatePointMatrix();
vec4 p;
Point<double> pt = Projection::project(latLng, scale) / util::tileSize;
- vec4 c = {{ pt.x, pt.y, 0, 1 }};
- matrix::transformMat4(p, c, mat);
- return { p[0] / p[3], size.height - p[1] / p[3] };
+ vec4 c = {{pt.x, pt.y, 0, 1}};
+ matrix::transformMat4(p, c, getCoordMatrix());
+ return {p[0] / p[3], size.height - p[1] / p[3]};
}
TileCoordinate TransformState::screenCoordinateToTileCoordinate(const ScreenCoordinate& point, uint8_t atZoom) const {
if (size.isEmpty()) {
- return { {}, 0 };
+ return {{}, 0};
}
float targetZ = 0;
- mat4 mat = coordinatePointMatrix();
-
- mat4 inverted;
- bool err = matrix::invert(inverted, mat);
-
- if (err) throw std::runtime_error("failed to invert coordinatePointMatrix");
double flippedY = size.height - point.y;
@@ -307,10 +499,10 @@ TileCoordinate TransformState::screenCoordinateToTileCoordinate(const ScreenCoor
vec4 coord0;
vec4 coord1;
- vec4 point0 = {{ point.x, flippedY, 0, 1 }};
- vec4 point1 = {{ point.x, flippedY, 1, 1 }};
- matrix::transformMat4(coord0, point0, inverted);
- matrix::transformMat4(coord1, point1, inverted);
+ vec4 point0 = {{point.x, flippedY, 0, 1}};
+ vec4 point1 = {{point.x, flippedY, 1, 1}};
+ matrix::transformMat4(coord0, point0, getInvertedMatrix());
+ matrix::transformMat4(coord1, point1, getInvertedMatrix());
double w0 = coord0[3];
double w1 = coord1[3];
@@ -323,7 +515,7 @@ TileCoordinate TransformState::screenCoordinateToTileCoordinate(const ScreenCoor
double t = z0 == z1 ? 0 : (targetZ - z0) / (z1 - z0);
Point<double> p = util::interpolate(p0, p1, t) / scale * static_cast<double>(1 << atZoom);
- return { { p.x, p.y }, static_cast<double>(atZoom) };
+ return {{p.x, p.y}, static_cast<double>(atZoom)};
}
LatLng TransformState::screenCoordinateToLatLng(const ScreenCoordinate& point, LatLng::WrapMode wrapMode) const {
@@ -331,9 +523,8 @@ LatLng TransformState::screenCoordinateToLatLng(const ScreenCoordinate& point, L
return Projection::unproject(coord.p, 1 / util::tileSize, wrapMode);
}
-mat4 TransformState::coordinatePointMatrix() const {
- mat4 proj;
- getProjMatrix(proj);
+mat4 TransformState::coordinatePointMatrix(const mat4& projMatrix) const {
+ mat4 proj = projMatrix;
matrix::scale(proj, proj, util::tileSize, util::tileSize, 1);
matrix::multiply(proj, getPixelMatrix(), proj);
return proj;
@@ -342,13 +533,11 @@ mat4 TransformState::coordinatePointMatrix() const {
mat4 TransformState::getPixelMatrix() const {
mat4 m;
matrix::identity(m);
- matrix::scale(m, m,
- static_cast<double>(size.width) / 2, -static_cast<double>(size.height) / 2, 1);
+ matrix::scale(m, m, static_cast<double>(size.width) / 2, -static_cast<double>(size.height) / 2, 1);
matrix::translate(m, m, 1, -1, 0);
return m;
}
-
#pragma mark - (private helper functions)
bool TransformState::rotatedNorth() const {
@@ -377,7 +566,7 @@ void TransformState::constrain(double& scale_, double& x_, double& y_) const {
}
ScreenCoordinate TransformState::getCenterOffset() const {
- return { 0.5 * (edgeInsets.left() - edgeInsets.right()), 0.5 * (edgeInsets.top() - edgeInsets.bottom()) };
+ return {0.5 * (edgeInsets.left() - edgeInsets.right()), 0.5 * (edgeInsets.top() - edgeInsets.bottom())};
}
void TransformState::moveLatLng(const LatLng& latLng, const ScreenCoordinate& anchor) {
@@ -406,7 +595,7 @@ void TransformState::setLatLngZoom(const LatLng& latLng, double zoom) {
setScalePoint(newScale, point);
}
-void TransformState::setScalePoint(const double newScale, const ScreenCoordinate &point) {
+void TransformState::setScalePoint(const double newScale, const ScreenCoordinate& point) {
double constrainedScale = newScale;
ScreenCoordinate constrainedPoint = point;
constrain(constrainedScale, constrainedPoint.x, constrainedPoint.y);
@@ -416,14 +605,13 @@ void TransformState::setScalePoint(const double newScale, const ScreenCoordinate
y = constrainedPoint.y;
Bc = Projection::worldSize(scale) / util::DEGREES_MAX;
Cc = Projection::worldSize(scale) / util::M2PI;
+ requestMatricesUpdate = true;
}
float TransformState::getCameraToTileDistance(const UnwrappedTileID& tileID) const {
- mat4 projectionMatrix;
- getProjMatrix(projectionMatrix);
mat4 tileProjectionMatrix;
matrixFor(tileProjectionMatrix, tileID);
- matrix::multiply(tileProjectionMatrix, projectionMatrix, tileProjectionMatrix);
+ matrix::multiply(tileProjectionMatrix, getProjectionMatrix(), tileProjectionMatrix);
vec4 tileCenter = {{util::tileSize / 2, util::tileSize / 2, 0, 1}};
vec4 projectedCenter;
matrix::transformMat4(projectedCenter, tileCenter, tileProjectionMatrix);
@@ -435,11 +623,11 @@ float TransformState::maxPitchScaleFactor() const {
return {};
}
auto latLng = screenCoordinateToLatLng({ 0, static_cast<float>(getSize().height) });
- mat4 mat = coordinatePointMatrix();
+
Point<double> pt = Projection::project(latLng, scale) / util::tileSize;
vec4 p = {{ pt.x, pt.y, 0, 1 }};
vec4 topPoint;
- matrix::transformMat4(topPoint, p, mat);
+ matrix::transformMat4(topPoint, p, getCoordMatrix());
return topPoint[3] / getCameraToCenterDistance();
}
diff --git a/src/mbgl/map/transform_state.hpp b/src/mbgl/map/transform_state.hpp
index 10a92187d5..edc7f3b9cf 100644
--- a/src/mbgl/map/transform_state.hpp
+++ b/src/mbgl/map/transform_state.hpp
@@ -19,32 +19,123 @@ namespace mbgl {
class UnwrappedTileID;
class TileCoordinate;
-class TransformState {
- friend class Transform;
- friend class RendererState;
+struct TransformStateProperties {
+ TransformStateProperties& withX(const optional<double>& val) {
+ x = val;
+ return *this;
+ }
+ TransformStateProperties& withY(const optional<double>& val) {
+ y = val;
+ return *this;
+ }
+ TransformStateProperties& withScale(const optional<double>& val) {
+ scale = val;
+ return *this;
+ }
+ TransformStateProperties& withBearing(const optional<double>& val) {
+ bearing = val;
+ return *this;
+ }
+ TransformStateProperties& withPitch(const optional<double>& val) {
+ pitch = val;
+ return *this;
+ }
+ TransformStateProperties& withXSkew(const optional<double>& val) {
+ xSkew = val;
+ return *this;
+ }
+ TransformStateProperties& withYSkew(const optional<double>& val) {
+ ySkew = val;
+ return *this;
+ }
+ TransformStateProperties& withAxonometric(const optional<bool>& val) {
+ axonometric = val;
+ return *this;
+ }
+ TransformStateProperties& withPanningInProgress(const optional<bool>& val) {
+ panning = val;
+ return *this;
+ }
+ TransformStateProperties& withScalingInProgress(const optional<bool>& val) {
+ scaling = val;
+ return *this;
+ }
+ TransformStateProperties& withRotatingInProgress(const optional<bool>& val) {
+ rotating = val;
+ return *this;
+ }
+ TransformStateProperties& withEdgeInsets(const optional<EdgeInsets>& val) {
+ edgeInsets = val;
+ return *this;
+ }
+ TransformStateProperties& withSize(const optional<Size>& val) {
+ size = val;
+ return *this;
+ }
+ TransformStateProperties& withConstrainMode(const optional<ConstrainMode>& val) {
+ constrain = val;
+ return *this;
+ }
+ TransformStateProperties& withNorthOrientation(const optional<NorthOrientation>& val) {
+ northOrientation = val;
+ return *this;
+ }
+ TransformStateProperties& withViewportMode(const optional<ViewportMode>& val) {
+ viewPortMode = val;
+ return *this;
+ }
+
+ optional<double> x;
+ optional<double> y;
+ optional<double> bearing;
+ optional<double> scale;
+ optional<double> pitch;
+ optional<double> xSkew;
+ optional<double> ySkew;
+ optional<bool> axonometric;
+ optional<bool> panning;
+ optional<bool> scaling;
+ optional<bool> rotating;
+ optional<EdgeInsets> edgeInsets;
+ optional<Size> size;
+ optional<ConstrainMode> constrain;
+ optional<NorthOrientation> northOrientation;
+ optional<ViewportMode> viewPortMode;
+};
+class TransformState {
public:
TransformState(ConstrainMode = ConstrainMode::HeightOnly, ViewportMode = ViewportMode::Default);
+ void setProperties(const TransformStateProperties& properties);
+
// Matrix
void matrixFor(mat4&, const UnwrappedTileID&) const;
void getProjMatrix(mat4& matrix, uint16_t nearZ = 1, bool aligned = false) const;
// Dimensions
Size getSize() const;
+ void setSize(const Size& size_);
// North Orientation
NorthOrientation getNorthOrientation() const;
double getNorthOrientationAngle() const;
+ void setNorthOrientation(const NorthOrientation);
// Constrain mode
ConstrainMode getConstrainMode() const;
+ void setConstrainMode(const ConstrainMode);
// Viewport mode
ViewportMode getViewportMode() const;
+ void setViewportMode(ViewportMode val);
CameraOptions getCameraOptions(optional<EdgeInsets>) const;
+ // EdgeInsects
+ EdgeInsets getEdgeInsets() const { return edgeInsets; }
+ void setEdgeInsets(const EdgeInsets&);
+
// Position
LatLng getLatLng(LatLng::WrapMode = LatLng::Unwrapped) const;
double pixel_x() const;
@@ -56,7 +147,14 @@ public:
double getZoomFraction() const;
// Scale
- double getScale() const { return scale; }
+ double getScale() const;
+ void setScale(double);
+
+ // Positions
+ double getX() const;
+ void setX(double);
+ double getY() const;
+ void setY(double);
// Bounds
void setLatLngBounds(LatLngBounds);
@@ -67,17 +165,30 @@ public:
double getMaxZoom() const;
// Rotation
- float getBearing() const;
+ double getBearing() const;
+ void setBearing(double);
float getFieldOfView() const;
float getCameraToCenterDistance() const;
- float getPitch() const;
+ double getPitch() const;
+ void setPitch(double);
+
+ double getXSkew() const;
+ void setXSkew(double);
+ double getYSkew() const;
+ void setYSkew(double);
+ bool getAxonometric() const;
+ void setAxonometric(bool);
// State
bool isChanging() const;
bool isRotating() const;
+ void setRotatingInProgress(bool val) { rotating = val; }
bool isScaling() const;
+ void setScalingInProgress(bool val) { scaling = val; }
bool isPanning() const;
+ void setPanningInProgress(bool val) { panning = val; }
bool isGestureInProgress() const;
+ void setGestureInProgress(bool val) { gestureInProgress = val; }
// Conversion
ScreenCoordinate latLngToScreenCoordinate(const LatLng&) const;
@@ -88,16 +199,20 @@ public:
double zoomScale(double zoom) const;
double scaleZoom(double scale) const;
- bool valid() const {
- return !size.isEmpty() && (scale >= min_scale && scale <= max_scale);
- }
+ bool valid() const { return !size.isEmpty() && (scale >= min_scale && scale <= max_scale); }
float getCameraToTileDistance(const UnwrappedTileID&) const;
float maxPitchScaleFactor() const;
+ /** Recenter the map so that the given coordinate is located at the given
+ point on screen. */
+ void moveLatLng(const LatLng&, const ScreenCoordinate&);
+ void setLatLngZoom(const LatLng& latLng, double zoom);
+
+ void constrain(double& scale, double& x, double& y) const;
+
private:
bool rotatedNorth() const;
- void constrain(double& scale, double& x, double& y) const;
// Viewport center offset, from [size.width / 2, size.height / 2], defined
// by |edgeInsets| in screen coordinates, with top left origin.
@@ -114,15 +229,17 @@ private:
// logical dimensions
Size size;
- mat4 coordinatePointMatrix() const;
+ mat4 coordinatePointMatrix(const mat4& projMatrix) const;
mat4 getPixelMatrix() const;
- /** Recenter the map so that the given coordinate is located at the given
- point on screen. */
- void moveLatLng(const LatLng&, const ScreenCoordinate&);
- void setLatLngZoom(const LatLng &latLng, double zoom);
void setScalePoint(const double scale, const ScreenCoordinate& point);
+ void updateMatricesIfNeeded() const;
+ bool needsMatricesUpdate() const { return requestMatricesUpdate; }
+ const mat4& getProjectionMatrix() const;
+ const mat4& getCoordMatrix() const;
+ const mat4& getInvertedMatrix() const;
+
private:
ConstrainMode constrainMode;
ViewportMode viewportMode;
@@ -152,6 +269,11 @@ private:
// cache values for spherical mercator math
double Bc = Projection::worldSize(scale) / util::DEGREES_MAX;
double Cc = Projection::worldSize(scale) / util::M2PI;
+
+ mutable bool requestMatricesUpdate{true};
+ mutable mat4 projectionMatrix;
+ mutable mat4 coordMatrix;
+ mutable mat4 invertedMatrix;
};
} // namespace mbgl