[core] Added padding option to CameraOptions
Moved EdgeInsets to geo.hpp so CameraOptions and Transform can refer to it. Added a padding option to CameraOptions that alters the frame of reference for the center option. Added optional padding parameters to LatLng getters and setters. Working towards #2600.
This commit is contained in:
committed by
Minh Nguyễn
parent
cb126eafe0
commit
143f8a7817
@@ -17,6 +17,10 @@ struct CameraOptions {
|
||||
/** Coordinate at the center of the map. */
|
||||
mapbox::util::optional<LatLng> center;
|
||||
|
||||
/** Padding around the interior of the view that affects the frame of
|
||||
reference for `center`. */
|
||||
mapbox::util::optional<EdgeInsets> padding;
|
||||
|
||||
/** Point of reference for `zoom` and `angle`, assuming an origin at the
|
||||
top-left corner of the view. */
|
||||
mapbox::util::optional<PrecisionPoint> anchor;
|
||||
|
||||
@@ -34,13 +34,6 @@ namespace util {
|
||||
template <class T> class Thread;
|
||||
} // namespace util
|
||||
|
||||
struct EdgeInsets {
|
||||
double top = 0;
|
||||
double left = 0;
|
||||
double bottom = 0;
|
||||
double right = 0;
|
||||
};
|
||||
|
||||
class Map : private util::noncopyable {
|
||||
friend class View;
|
||||
|
||||
@@ -106,8 +99,9 @@ public:
|
||||
// Position
|
||||
void moveBy(const PrecisionPoint&, const Duration& = Duration::zero());
|
||||
void setLatLng(const LatLng&, const PrecisionPoint&, const Duration& = Duration::zero());
|
||||
void setLatLng(const LatLng&, const EdgeInsets&, const Duration& = Duration::zero());
|
||||
void setLatLng(const LatLng&, const Duration& = Duration::zero());
|
||||
LatLng getLatLng() const;
|
||||
LatLng getLatLng(const EdgeInsets& = {}) const;
|
||||
void resetPosition();
|
||||
|
||||
// Scale
|
||||
|
||||
@@ -108,6 +108,40 @@ enum class NorthOrientation : uint8_t {
|
||||
Leftwards,
|
||||
};
|
||||
|
||||
/// The distance on each side between a rectangle and a rectangle within.
|
||||
struct EdgeInsets {
|
||||
double top = 0; ///< Number of pixels inset from the top edge.
|
||||
double left = 0; ///< Number of pixels inset from the left edge.
|
||||
double bottom = 0; ///< Number of pixels inset from the bottom edge.
|
||||
double right = 0; ///< Number of pixels inset from the right edge.
|
||||
|
||||
inline EdgeInsets() {}
|
||||
|
||||
inline EdgeInsets(const double t, const double l, const double b, const double r)
|
||||
: top(t), left(l), bottom(b), right(r) {}
|
||||
|
||||
inline operator bool() const {
|
||||
return top || left || bottom || right;
|
||||
}
|
||||
|
||||
inline void operator+=(const EdgeInsets& o) {
|
||||
top += o.top;
|
||||
left += o.left;
|
||||
bottom += o.bottom;
|
||||
right += o.right;
|
||||
}
|
||||
|
||||
inline EdgeInsets operator+(const EdgeInsets& o) const {
|
||||
return {
|
||||
top + o.top, left + o.left, bottom + o.bottom, right + o.right,
|
||||
};
|
||||
}
|
||||
|
||||
PrecisionPoint getCenter(uint16_t width, uint16_t height) const;
|
||||
|
||||
void flip();
|
||||
};
|
||||
|
||||
} // namespace mbgl
|
||||
|
||||
#endif
|
||||
|
||||
@@ -172,7 +172,11 @@ void Map::moveBy(const PrecisionPoint& point, const Duration& duration) {
|
||||
}
|
||||
|
||||
void Map::setLatLng(const LatLng& latLng, const Duration& duration) {
|
||||
transform->setLatLng(latLng, duration);
|
||||
setLatLng(latLng, EdgeInsets(), duration);
|
||||
}
|
||||
|
||||
void Map::setLatLng(const LatLng& latLng, const EdgeInsets& padding, const Duration& duration) {
|
||||
transform->setLatLng(latLng, padding, duration);
|
||||
update(Update::Repaint);
|
||||
}
|
||||
|
||||
@@ -181,8 +185,8 @@ void Map::setLatLng(const LatLng& latLng, const PrecisionPoint& point, const Dur
|
||||
update(Update::Repaint);
|
||||
}
|
||||
|
||||
LatLng Map::getLatLng() const {
|
||||
return transform->getLatLng();
|
||||
LatLng Map::getLatLng(const EdgeInsets& padding) const {
|
||||
return transform->getLatLng(padding);
|
||||
}
|
||||
|
||||
void Map::resetPosition() {
|
||||
@@ -259,7 +263,7 @@ CameraOptions Map::cameraForLatLngs(const std::vector<LatLng>& latLngs, const Ed
|
||||
double scaleY = (getHeight() - padding.top - padding.bottom) / height;
|
||||
double minScale = ::fmin(scaleX, scaleY);
|
||||
double zoom = ::log2(getScale() * minScale);
|
||||
zoom = ::fmax(::fmin(zoom, getMaxZoom()), getMinZoom());
|
||||
zoom = util::clamp(zoom, getMinZoom(), getMaxZoom());
|
||||
|
||||
// Calculate the center point of a virtual bounds that is extended in all directions by padding.
|
||||
PrecisionPoint paddedNEPixel = {
|
||||
|
||||
@@ -91,7 +91,12 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim
|
||||
}
|
||||
|
||||
// Determine endpoints.
|
||||
const LatLng startLatLng = getLatLng();
|
||||
EdgeInsets padding;
|
||||
if (camera.padding) {
|
||||
padding = *camera.padding;
|
||||
}
|
||||
const LatLng startLatLng = getLatLng(padding);
|
||||
padding.flip();
|
||||
const PrecisionPoint startPoint = {
|
||||
state.lngX(startLatLng.longitude),
|
||||
state.latY(startLatLng.latitude),
|
||||
@@ -141,6 +146,10 @@ void Transform::easeTo(const CameraOptions& camera, const AnimationOptions& anim
|
||||
if (pitch != startPitch) {
|
||||
state.pitch = util::interpolate(startPitch, pitch, t);
|
||||
}
|
||||
|
||||
if (padding) {
|
||||
state.moveLatLng(frameLatLng, padding.getCenter(state.width, state.height));
|
||||
}
|
||||
return update;
|
||||
}, duration);
|
||||
}
|
||||
@@ -164,7 +173,12 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima
|
||||
}
|
||||
|
||||
// Determine endpoints.
|
||||
const LatLng startLatLng = getLatLng();
|
||||
EdgeInsets padding;
|
||||
if (camera.padding) {
|
||||
padding = *camera.padding;
|
||||
}
|
||||
const LatLng startLatLng = getLatLng(padding);
|
||||
padding.flip();
|
||||
const PrecisionPoint startPoint = {
|
||||
state.lngX(startLatLng.longitude),
|
||||
state.latY(startLatLng.latitude),
|
||||
@@ -189,7 +203,8 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima
|
||||
|
||||
/// w₀: Initial visible span, measured in pixels at the initial scale.
|
||||
/// Known henceforth as a <i>screenful</i>.
|
||||
double w0 = std::max(state.width, state.height);
|
||||
double w0 = std::max(state.width - padding.left - padding.right,
|
||||
state.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);
|
||||
@@ -304,6 +319,10 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima
|
||||
if (pitch != startPitch) {
|
||||
state.pitch = util::interpolate(startPitch, pitch, k);
|
||||
}
|
||||
|
||||
if (padding) {
|
||||
state.moveLatLng(frameLatLng, padding.getCenter(state.width, state.height));
|
||||
}
|
||||
return Update::Zoom;
|
||||
}, duration);
|
||||
}
|
||||
@@ -340,12 +359,19 @@ void Transform::moveBy(const PrecisionPoint& offset, const Duration& duration) {
|
||||
}
|
||||
|
||||
void Transform::setLatLng(const LatLng& latLng, const Duration& duration) {
|
||||
setLatLng(latLng, EdgeInsets(), duration);
|
||||
}
|
||||
|
||||
void Transform::setLatLng(const LatLng& latLng, const EdgeInsets& padding, const Duration& duration) {
|
||||
if (!latLng) {
|
||||
return;
|
||||
}
|
||||
|
||||
CameraOptions camera;
|
||||
camera.center = latLng;
|
||||
if (padding) {
|
||||
camera.padding = padding;
|
||||
}
|
||||
easeTo(camera, duration);
|
||||
}
|
||||
|
||||
@@ -381,6 +407,16 @@ void Transform::setLatLngZoom(const LatLng& latLng, double zoom, const Duration&
|
||||
easeTo(camera, duration);
|
||||
}
|
||||
|
||||
LatLng Transform::getLatLng(const EdgeInsets& padding) const {
|
||||
if (padding) {
|
||||
EdgeInsets flippedPadding = padding;
|
||||
flippedPadding.flip();
|
||||
return state.pointToLatLng(flippedPadding.getCenter(state.width, state.height));
|
||||
} else {
|
||||
return state.getLatLng();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Zoom
|
||||
|
||||
|
||||
@@ -43,9 +43,10 @@ public:
|
||||
top to bottom and from left to right. */
|
||||
void moveBy(const PrecisionPoint& 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 PrecisionPoint&, const Duration& = Duration::zero());
|
||||
void setLatLngZoom(const LatLng&, double zoom, const Duration& = Duration::zero());
|
||||
LatLng getLatLng() const { return state.getLatLng(); }
|
||||
LatLng getLatLng(const EdgeInsets& = {}) const;
|
||||
|
||||
// Zoom
|
||||
|
||||
|
||||
@@ -28,4 +28,16 @@ LatLngBounds::LatLngBounds(const TileID& id)
|
||||
ne(TileID{ id.z, id.x + 1, id.y, id.sourceZ }) {
|
||||
}
|
||||
|
||||
PrecisionPoint EdgeInsets::getCenter(uint16_t width, uint16_t height) const {
|
||||
return {
|
||||
(width - left - right) / 2.0f + left,
|
||||
(height - top - bottom) / 2.0f + top,
|
||||
};
|
||||
}
|
||||
|
||||
void EdgeInsets::flip() {
|
||||
std::swap(top, bottom);
|
||||
std::swap(left, right);
|
||||
}
|
||||
|
||||
} // end namespace mbgl
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "../fixtures/mock_view.hpp"
|
||||
|
||||
#include <mbgl/map/transform.hpp>
|
||||
#include <mbgl/util/geo.hpp>
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
@@ -193,8 +194,7 @@ TEST(Transform, Anchor) {
|
||||
ASSERT_DOUBLE_EQ(10, transform.getZoom());
|
||||
ASSERT_DOUBLE_EQ(0, transform.getAngle());
|
||||
|
||||
const auto size = view.getSize();
|
||||
const PrecisionPoint anchorPoint = { size[0] * 0.8, size[1] * 0.3 };
|
||||
const PrecisionPoint anchorPoint = {0, 0};
|
||||
const LatLng anchorLatLng = transform.getState().pointToLatLng(anchorPoint);
|
||||
transform.setAngle(M_PI_4, anchorPoint);
|
||||
|
||||
@@ -202,3 +202,35 @@ TEST(Transform, Anchor) {
|
||||
ASSERT_NE(anchorLatLng, transform.getLatLng());
|
||||
ASSERT_DOUBLE_EQ(anchorLatLng, transform.getState().pointToLatLng(anchorPoint));
|
||||
}
|
||||
|
||||
TEST(Transform, Padding) {
|
||||
MockView view;
|
||||
Transform transform(view, ConstrainMode::HeightOnly);
|
||||
transform.resize({{ 1000, 1000 }});
|
||||
|
||||
ASSERT_DOUBLE_EQ(0, transform.getLatLng().latitude);
|
||||
ASSERT_DOUBLE_EQ(0, transform.getLatLng().longitude);
|
||||
|
||||
transform.setLatLngZoom({ 10, -100 }, 10);
|
||||
|
||||
const LatLng trueCenter = transform.getLatLng();
|
||||
ASSERT_DOUBLE_EQ(10, trueCenter.latitude);
|
||||
ASSERT_DOUBLE_EQ(-100, trueCenter.longitude);
|
||||
ASSERT_DOUBLE_EQ(10, transform.getZoom());
|
||||
|
||||
const LatLng manualShiftedCenter = transform.getState().pointToLatLng({
|
||||
1000.0 / 2.0,
|
||||
1000.0 / 4.0,
|
||||
});
|
||||
|
||||
EdgeInsets padding;
|
||||
padding.top = 1000.0 / 2.0;
|
||||
ASSERT_GT(padding.top, 0);
|
||||
ASSERT_TRUE(padding);
|
||||
|
||||
const LatLng shiftedCenter = transform.getLatLng(padding);
|
||||
ASSERT_NE(trueCenter.latitude, shiftedCenter.latitude);
|
||||
ASSERT_DOUBLE_EQ(trueCenter.longitude, shiftedCenter.longitude);
|
||||
ASSERT_DOUBLE_EQ(manualShiftedCenter.latitude, shiftedCenter.latitude);
|
||||
ASSERT_DOUBLE_EQ(manualShiftedCenter.longitude, shiftedCenter.longitude);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user