summaryrefslogtreecommitdiff
path: root/src/mbgl/map
diff options
context:
space:
mode:
authorBruno de Oliveira Abinader <bruno@mapbox.com>2016-03-12 00:50:00 +0200
committerBruno de Oliveira Abinader <bruno@mapbox.com>2016-03-13 21:38:20 +0200
commit8e30a4a0806e970e727c3563b8ed57dbaf9a0fa0 (patch)
tree792abd2a0b6d19aac7e60d83cfa4c2d88893b936 /src/mbgl/map
parenta396c6a7f082749476f332c976912f37cbd93c92 (diff)
downloadqtlocation-mapboxgl-8e30a4a0806e970e727c3563b8ed57dbaf9a0fa0.tar.gz
[core] Harden Transform anchor & padding usage
Use optional values for anchor & padding in Map and Transform functions instead of NaNs. Added unit tests to stress some edge cases.
Diffstat (limited to 'src/mbgl/map')
-rw-r--r--src/mbgl/map/map.cpp77
-rw-r--r--src/mbgl/map/transform.cpp124
-rw-r--r--src/mbgl/map/transform.hpp36
3 files changed, 121 insertions, 116 deletions
diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp
index 374e3fe615..d2ec76f8f9 100644
--- a/src/mbgl/map/map.cpp
+++ b/src/mbgl/map/map.cpp
@@ -172,31 +172,29 @@ void Map::moveBy(const ScreenCoordinate& point, const Duration& duration) {
}
void Map::setLatLng(const LatLng& latLng, const Duration& duration) {
- setLatLng(latLng, EdgeInsets(), duration);
+ setLatLng(latLng, ScreenCoordinate {}, duration);
}
-void Map::setLatLng(const LatLng& latLng, const EdgeInsets& padding, const Duration& duration) {
+void Map::setLatLng(const LatLng& latLng, optional<EdgeInsets> padding, const Duration& duration) {
transform->setLatLng(latLng, padding, duration);
update(Update::Repaint);
}
-void Map::setLatLng(const LatLng& latLng, const ScreenCoordinate& point, const Duration& duration) {
- transform->setLatLng(latLng, point, duration);
+void Map::setLatLng(const LatLng& latLng, optional<ScreenCoordinate> anchor, const Duration& duration) {
+ transform->setLatLng(latLng, anchor, duration);
update(Update::Repaint);
}
-LatLng Map::getLatLng(const EdgeInsets& padding) const {
+LatLng Map::getLatLng(optional<EdgeInsets> padding) const {
return transform->getLatLng(padding);
}
-void Map::resetPosition(const EdgeInsets& padding) {
+void Map::resetPosition(optional<EdgeInsets> padding) {
CameraOptions camera;
camera.angle = 0;
camera.pitch = 0;
camera.center = LatLng(0, 0);
- if (padding) {
- camera.padding = padding;
- }
+ camera.padding = padding;
camera.zoom = 0;
transform->jumpTo(camera);
update(Update::Zoom);
@@ -205,13 +203,13 @@ void Map::resetPosition(const EdgeInsets& padding) {
#pragma mark - Scale
-void Map::scaleBy(double ds, const ScreenCoordinate& point, const Duration& duration) {
- transform->scaleBy(ds, point, duration);
+void Map::scaleBy(double ds, optional<ScreenCoordinate> anchor, const Duration& duration) {
+ transform->scaleBy(ds, anchor, duration);
update(Update::Zoom);
}
-void Map::setScale(double scale, const ScreenCoordinate& point, const Duration& duration) {
- transform->setScale(scale, point, duration);
+void Map::setScale(double scale, optional<ScreenCoordinate> anchor, const Duration& duration) {
+ transform->setScale(scale, anchor, duration);
update(Update::Zoom);
}
@@ -223,7 +221,7 @@ void Map::setZoom(double zoom, const Duration& duration) {
setZoom(zoom, {}, duration);
}
-void Map::setZoom(double zoom, const EdgeInsets& padding, const Duration& duration) {
+void Map::setZoom(double zoom, optional<EdgeInsets> padding, const Duration& duration) {
transform->setZoom(zoom, padding, duration);
update(Update::Zoom);
}
@@ -236,12 +234,12 @@ void Map::setLatLngZoom(const LatLng& latLng, double zoom, const Duration& durat
setLatLngZoom(latLng, zoom, {}, duration);
}
-void Map::setLatLngZoom(const LatLng& latLng, double zoom, const EdgeInsets& padding, const Duration& duration) {
+void Map::setLatLngZoom(const LatLng& latLng, double zoom, optional<EdgeInsets> padding, const Duration& duration) {
transform->setLatLngZoom(latLng, zoom, padding, duration);
update(Update::Zoom);
}
-CameraOptions Map::cameraForLatLngBounds(const LatLngBounds& bounds, const EdgeInsets& padding) {
+CameraOptions Map::cameraForLatLngBounds(const LatLngBounds& bounds, optional<EdgeInsets> padding) {
AnnotationSegment segment = {
bounds.northwest(),
bounds.southwest(),
@@ -251,7 +249,7 @@ CameraOptions Map::cameraForLatLngBounds(const LatLngBounds& bounds, const EdgeI
return cameraForLatLngs(segment, padding);
}
-CameraOptions Map::cameraForLatLngs(const std::vector<LatLng>& latLngs, const EdgeInsets& padding) {
+CameraOptions Map::cameraForLatLngs(const std::vector<LatLng>& latLngs, optional<EdgeInsets> padding) {
CameraOptions options;
if (latLngs.empty()) {
return options;
@@ -272,26 +270,31 @@ CameraOptions Map::cameraForLatLngs(const std::vector<LatLng>& latLngs, const Ed
double height = nePixel.y - swPixel.y;
// Calculate the zoom level.
- double scaleX = (getWidth() - padding.left - padding.right) / width;
- double scaleY = (getHeight() - padding.top - padding.bottom) / height;
+ double scaleX = getWidth() / width;
+ double scaleY = getHeight() / height;
+ if (padding && *padding) {
+ scaleX -= (padding->left + padding->right) / width;
+ scaleY -= (padding->top + padding->bottom) / height;
+ }
double minScale = ::fmin(scaleX, scaleY);
double zoom = ::log2(getScale() * minScale);
zoom = util::clamp(zoom, getMinZoom(), getMaxZoom());
// Calculate the center point of a virtual bounds that is extended in all directions by padding.
- ScreenCoordinate paddedNEPixel = {
- nePixel.x + padding.right / minScale,
- nePixel.y + padding.top / minScale,
- };
- ScreenCoordinate paddedSWPixel = {
- swPixel.x - padding.left / minScale,
- swPixel.y - padding.bottom / minScale,
- };
- ScreenCoordinate centerPixel = {
- (paddedNEPixel.x + paddedSWPixel.x) / 2,
- (paddedNEPixel.y + paddedSWPixel.y) / 2,
- };
-
+ ScreenCoordinate centerPixel = nePixel + swPixel;
+ if (padding && *padding) {
+ ScreenCoordinate paddedNEPixel = {
+ padding->right / minScale,
+ padding->top / minScale,
+ };
+ ScreenCoordinate paddedSWPixel = {
+ padding->left / minScale,
+ padding->bottom / minScale,
+ };
+ centerPixel = centerPixel - paddedNEPixel - paddedSWPixel;
+ }
+ centerPixel /= 2;
+
// CameraOptions origin is at the top-left corner.
centerPixel.y = viewportHeight - centerPixel.y;
@@ -349,12 +352,12 @@ void Map::setBearing(double degrees, const Duration& duration) {
setBearing(degrees, EdgeInsets(), duration);
}
-void Map::setBearing(double degrees, const ScreenCoordinate& center, const Duration& duration) {
- transform->setAngle(-degrees * util::DEG2RAD, center, duration);
+void Map::setBearing(double degrees, optional<ScreenCoordinate> anchor, const Duration& duration) {
+ transform->setAngle(-degrees * util::DEG2RAD, anchor, duration);
update(Update::Repaint);
}
-void Map::setBearing(double degrees, const EdgeInsets& padding, const Duration& duration) {
+void Map::setBearing(double degrees, optional<EdgeInsets> padding, const Duration& duration) {
transform->setAngle(-degrees * util::DEG2RAD, padding, duration);
update(Update::Repaint);
}
@@ -372,10 +375,10 @@ void Map::resetNorth(const Duration& duration) {
#pragma mark - Pitch
void Map::setPitch(double pitch, const Duration& duration) {
- setPitch(pitch, {NAN, NAN}, duration);
+ setPitch(pitch, {}, duration);
}
-void Map::setPitch(double pitch, const ScreenCoordinate& anchor, const Duration& duration) {
+void Map::setPitch(double pitch, optional<ScreenCoordinate> anchor, const Duration& duration) {
transform->setPitch(pitch * util::DEG2RAD, anchor, duration);
update(Update::Repaint);
}
diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp
index ac1f4142a5..9868d96485 100644
--- a/src/mbgl/map/transform.cpp
+++ b/src/mbgl/map/transform.cpp
@@ -352,68 +352,57 @@ void Transform::moveBy(const ScreenCoordinate& offset, const Duration& duration)
}
void Transform::setLatLng(const LatLng& latLng, const Duration& duration) {
- setLatLng(latLng, EdgeInsets(), duration);
+ setLatLng(latLng, optional<ScreenCoordinate> {}, duration);
}
-void Transform::setLatLng(const LatLng& latLng, const EdgeInsets& padding, const Duration& duration) {
- if (!latLng) {
- return;
- }
-
+void Transform::setLatLng(const LatLng& latLng, optional<EdgeInsets> padding, const Duration& duration) {
+ if (!latLng) return;
CameraOptions camera;
camera.center = latLng;
- if (padding) {
- camera.padding = padding;
- }
+ camera.padding = padding;
easeTo(camera, duration);
}
-void Transform::setLatLng(const LatLng& latLng, const ScreenCoordinate& point, const Duration& duration) {
- if (!latLng || !point) {
- return;
- }
-
- // Pretend the viewport is 0×0 around the passed-in point.
+void Transform::setLatLng(const LatLng& latLng, optional<ScreenCoordinate> anchor, const Duration& duration) {
+ if (!latLng) return;
CameraOptions camera;
camera.center = latLng;
- EdgeInsets padding;
- padding.top = point.y;
- padding.left = point.x;
- padding.bottom = state.height - point.y;
- padding.right = state.width - point.x;
- if (padding) camera.padding = padding;
+ if (anchor) {
+ EdgeInsets padding;
+ padding.top = anchor->y;
+ padding.left = anchor->x;
+ padding.bottom = state.height - anchor->y;
+ padding.right = state.width - anchor->x;
+ if (padding) camera.padding = padding;
+ }
easeTo(camera, duration);
}
void Transform::setLatLngZoom(const LatLng& latLng, double zoom, const Duration& duration) {
- setLatLngZoom(latLng, zoom, {}, duration);
+ setLatLngZoom(latLng, zoom, EdgeInsets {}, duration);
}
-void Transform::setLatLngZoom(const LatLng& latLng, double zoom, const EdgeInsets& padding, const Duration& duration) {
- if (!latLng || std::isnan(zoom)) {
- return;
- }
+void Transform::setLatLngZoom(const LatLng& latLng, double zoom, optional<EdgeInsets> padding, const Duration& duration) {
+ if (!latLng || std::isnan(zoom)) return;
CameraOptions camera;
camera.center = latLng;
- if (padding) {
- camera.padding = padding;
- }
+ camera.padding = padding;
camera.zoom = zoom;
easeTo(camera, duration);
}
-LatLng Transform::getLatLng(const EdgeInsets& padding) const {
- if (padding) {
- return screenCoordinateToLatLng(padding.getCenter(state.width, state.height));
+LatLng Transform::getLatLng(optional<EdgeInsets> padding) const {
+ if (padding && *padding) {
+ return screenCoordinateToLatLng(padding->getCenter(state.width, state.height));
} else {
return state.getLatLng();
}
}
-ScreenCoordinate Transform::getScreenCoordinate(const EdgeInsets& padding) const {
- if (padding) {
- return padding.getCenter(state.width, state.height);
+ScreenCoordinate Transform::getScreenCoordinate(optional<EdgeInsets> padding) const {
+ if (padding && *padding) {
+ return padding->getCenter(state.width, state.height);
} else {
return { state.width / 2., state.height / 2. };
}
@@ -422,20 +411,24 @@ ScreenCoordinate Transform::getScreenCoordinate(const EdgeInsets& padding) const
#pragma mark - Zoom
-void Transform::scaleBy(double ds, const ScreenCoordinate& center, const Duration& duration) {
- if (std::isnan(ds) || !center) {
- return;
- }
+void Transform::scaleBy(double ds, const Duration& duration) {
+ scaleBy(ds, optional<ScreenCoordinate> {}, duration);
+}
+void Transform::scaleBy(double ds, optional<ScreenCoordinate> anchor, const Duration& duration) {
double scale = util::clamp(state.scale * ds, state.min_scale, state.max_scale);
- setScale(scale, center, duration);
+ setScale(scale, anchor, duration);
+}
+
+void Transform::setZoom(double zoom, const Duration& duration) {
+ setZoom(zoom, optional<ScreenCoordinate> {}, duration);
}
-void Transform::setZoom(double zoom, const ScreenCoordinate& anchor, const Duration& duration) {
+void Transform::setZoom(double zoom, optional<ScreenCoordinate> anchor, const Duration& duration) {
setScale(state.zoomScale(zoom), anchor, duration);
}
-void Transform::setZoom(double zoom, const EdgeInsets& padding, const Duration& duration) {
+void Transform::setZoom(double zoom, optional<EdgeInsets> padding, const Duration& duration) {
setScale(state.zoomScale(zoom), padding, duration);
}
@@ -447,19 +440,22 @@ double Transform::getScale() const {
return state.scale;
}
-void Transform::setScale(double scale, const ScreenCoordinate& anchor, const Duration& duration) {
- if (std::isnan(scale)) {
- return;
- }
-
+void Transform::setScale(double scale, const Duration& duration) {
+ setScale(scale, optional<ScreenCoordinate> {}, duration);
+}
+
+void Transform::setScale(double scale, optional<ScreenCoordinate> anchor, const Duration& duration) {
+ if (std::isnan(scale)) return;
CameraOptions camera;
camera.zoom = state.scaleZoom(scale);
- if (anchor) camera.anchor = anchor;
+ camera.anchor = anchor;
easeTo(camera, duration);
}
-void Transform::setScale(double scale, const EdgeInsets& padding, const Duration& duration) {
- setScale(scale, getScreenCoordinate(padding), duration);
+void Transform::setScale(double scale, optional<EdgeInsets> padding, const Duration& duration) {
+ optional<ScreenCoordinate> anchor;
+ if (padding) anchor = getScreenCoordinate(padding);
+ setScale(scale, anchor, duration);
}
void Transform::setMinZoom(const double minZoom) {
@@ -502,22 +498,21 @@ void Transform::rotateBy(const ScreenCoordinate& first, const ScreenCoordinate&
}
void Transform::setAngle(double angle, const Duration& duration) {
- setAngle(angle, ScreenCoordinate { NAN, NAN }, duration);
+ setAngle(angle, optional<ScreenCoordinate> {}, duration);
}
-void Transform::setAngle(double angle, const ScreenCoordinate& anchor, const Duration& duration) {
- if (std::isnan(angle)) {
- return;
- }
-
+void Transform::setAngle(double angle, optional<ScreenCoordinate> anchor, const Duration& duration) {
+ if (std::isnan(angle)) return;
CameraOptions camera;
camera.angle = angle;
- if (anchor) camera.anchor = anchor;
+ camera.anchor = anchor;
easeTo(camera, duration);
}
-void Transform::setAngle(double angle, const EdgeInsets& padding, const Duration& duration) {
- setAngle(angle, getScreenCoordinate(padding), duration);
+void Transform::setAngle(double angle, optional<EdgeInsets> padding, const Duration& duration) {
+ optional<ScreenCoordinate> anchor;
+ if (padding && *padding) anchor = getScreenCoordinate(padding);
+ setAngle(angle, anchor, duration);
}
double Transform::getAngle() const {
@@ -527,17 +522,14 @@ double Transform::getAngle() const {
#pragma mark - Pitch
void Transform::setPitch(double pitch, const Duration& duration) {
- setPitch(pitch, ScreenCoordinate {}, duration);
+ setPitch(pitch, optional<ScreenCoordinate> {}, duration);
}
-void Transform::setPitch(double pitch, const ScreenCoordinate& anchor, const Duration& duration) {
- if (std::isnan(pitch)) {
- return;
- }
-
+void Transform::setPitch(double pitch, optional<ScreenCoordinate> anchor, const Duration& duration) {
+ if (std::isnan(pitch)) return;
CameraOptions camera;
camera.pitch = pitch;
- if (anchor) camera.anchor = anchor;
+ camera.anchor = anchor;
easeTo(camera, duration);
}
diff --git a/src/mbgl/map/transform.hpp b/src/mbgl/map/transform.hpp
index e904b3956a..1e84b013c9 100644
--- a/src/mbgl/map/transform.hpp
+++ b/src/mbgl/map/transform.hpp
@@ -8,6 +8,7 @@
#include <mbgl/util/chrono.hpp>
#include <mbgl/util/geo.hpp>
#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/optional.hpp>
#include <cstdint>
#include <cmath>
@@ -43,38 +44,47 @@ public:
top to bottom and from left to right. */
void moveBy(const ScreenCoordinate& offset, const Duration& = Duration::zero());
void setLatLng(const LatLng&, const Duration& = Duration::zero());
- void setLatLng(const LatLng&, const EdgeInsets&, const Duration& = Duration::zero());
- void setLatLng(const LatLng&, const ScreenCoordinate&, const Duration& = Duration::zero());
+ void setLatLng(const LatLng&, optional<EdgeInsets>, const Duration& = Duration::zero());
+ void setLatLng(const LatLng&, optional<ScreenCoordinate>, const Duration& = Duration::zero());
void setLatLngZoom(const LatLng&, double zoom, const Duration& = Duration::zero());
- void setLatLngZoom(const LatLng&, double zoom, const EdgeInsets&, const Duration& = Duration::zero());
- LatLng getLatLng(const EdgeInsets& = {}) const;
- ScreenCoordinate getScreenCoordinate(const EdgeInsets& = {}) const;
+ void setLatLngZoom(const LatLng&, double zoom, optional<EdgeInsets>, const Duration& = Duration::zero());
+ LatLng getLatLng(optional<EdgeInsets> = {}) const;
+ ScreenCoordinate getScreenCoordinate(optional<EdgeInsets> = {}) const;
// Zoom
/** Scales the map, keeping the given point fixed within the view.
+ @param ds The difference in scale factors to scale the map by. */
+ void scaleBy(double ds, const Duration& = Duration::zero());
+ /** Scales the map, keeping the given point fixed within the view.
@param ds The difference in scale factors to scale the map by.
@param anchor A point relative to the top-left corner of the view.
If unspecified, the center point is fixed within the view. */
- void scaleBy(double ds, const ScreenCoordinate& anchor = {}, const Duration& = Duration::zero());
+ void scaleBy(double ds, optional<ScreenCoordinate> anchor, const Duration& = Duration::zero());
+ /** Sets the scale factor, keeping the given point fixed within the view.
+ @param scale The new scale factor. */
+ void setScale(double scale, const Duration& = Duration::zero());
/** Sets the scale factor, keeping the given point fixed within the view.
@param scale The new scale factor.
@param anchor A point relative to the top-left corner of the view.
If unspecified, the center point is fixed within the view. */
- void setScale(double scale, const ScreenCoordinate& anchor = {}, const Duration& = Duration::zero());
+ void setScale(double scale, optional<ScreenCoordinate> anchor, const Duration& = Duration::zero());
/** Sets the scale factor, keeping the center point fixed within the inset view.
@param scale The new scale factor.
@param padding The viewport padding that affects the fixed center point. */
- void setScale(double scale, const EdgeInsets& padding, const Duration& = Duration::zero());
+ void setScale(double scale, optional<EdgeInsets> padding, const Duration& = Duration::zero());
+ /** Sets the zoom level, keeping the given point fixed within the view.
+ @param zoom The new zoom level. */
+ void setZoom(double zoom, const Duration& = Duration::zero());
/** Sets the zoom level, keeping the given point fixed within the view.
@param zoom The new zoom level.
@param anchor A point relative to the top-left corner of the view.
If unspecified, the center point is fixed within the view. */
- void setZoom(double zoom, const ScreenCoordinate& anchor = {}, const Duration& = Duration::zero());
+ void setZoom(double zoom, optional<ScreenCoordinate> anchor, const Duration& = Duration::zero());
/** Sets the zoom level, keeping the center point fixed within the inset view.
@param zoom The new zoom level.
@param padding The viewport padding that affects the fixed center point. */
- void setZoom(double zoom, const EdgeInsets& padding, const Duration& = Duration::zero());
+ void setZoom(double zoom, optional<EdgeInsets> padding, const Duration& = Duration::zero());
/** Returns the zoom level. */
double getZoom() const;
/** Returns the scale factor. */
@@ -94,12 +104,12 @@ public:
@param angle The new angle of rotation, measured in radians
counterclockwise from true north.
@param anchor A point relative to the top-left corner of the view. */
- void setAngle(double angle, const ScreenCoordinate& anchor, const Duration& = Duration::zero());
+ void setAngle(double angle, optional<ScreenCoordinate> anchor, const Duration& = Duration::zero());
/** Sets the angle of rotation, keeping the center point fixed within the inset view.
@param angle The new angle of rotation, measured in radians
counterclockwise from true north.
@param padding The viewport padding that affects the fixed center point. */
- void setAngle(double angle, const EdgeInsets& padding, const Duration& = Duration::zero());
+ void setAngle(double angle, optional<EdgeInsets> padding, const Duration& = Duration::zero());
/** Returns the angle of rotation.
@return The angle of rotation, measured in radians counterclockwise from
true north. */
@@ -114,7 +124,7 @@ public:
@param angle The new pitch angle, measured in radians toward the
horizon.
@param anchor A point relative to the top-left corner of the view. */
- void setPitch(double pitch, const ScreenCoordinate& anchor, const Duration& = Duration::zero());
+ void setPitch(double pitch, optional<ScreenCoordinate> anchor, const Duration& = Duration::zero());
double getPitch() const;
// North Orientation