Transform needs only a single TransformState
This commit is contained in:
@@ -37,17 +37,17 @@ bool Transform::resize(const uint16_t w, const uint16_t h, const float ratio,
|
||||
const uint16_t fb_w, const uint16_t fb_h) {
|
||||
std::lock_guard<std::recursive_mutex> lock(mtx);
|
||||
|
||||
if (final.width != w || final.height != h || final.pixelRatio != ratio ||
|
||||
final.framebuffer[0] != fb_w || final.framebuffer[1] != fb_h) {
|
||||
if (state.width != w || state.height != h || state.pixelRatio != ratio ||
|
||||
state.framebuffer[0] != fb_w || state.framebuffer[1] != fb_h) {
|
||||
|
||||
view.notifyMapChange(MapChangeRegionWillChange);
|
||||
|
||||
current.width = final.width = w;
|
||||
current.height = final.height = h;
|
||||
current.pixelRatio = final.pixelRatio = ratio;
|
||||
current.framebuffer[0] = final.framebuffer[0] = fb_w;
|
||||
current.framebuffer[1] = final.framebuffer[1] = fb_h;
|
||||
constrain(current.scale, current.y);
|
||||
state.width = w;
|
||||
state.height = h;
|
||||
state.pixelRatio = ratio;
|
||||
state.framebuffer[0] = fb_w;
|
||||
state.framebuffer[1] = fb_h;
|
||||
constrain(state.scale, state.y);
|
||||
|
||||
view.notifyMapChange(MapChangeRegionDidChange);
|
||||
|
||||
@@ -76,27 +76,27 @@ void Transform::_moveBy(const double dx, const double dy, const Duration duratio
|
||||
MapChangeRegionWillChangeAnimated :
|
||||
MapChangeRegionWillChange);
|
||||
|
||||
final.x = current.x + std::cos(current.angle) * dx + std::sin(current.angle) * dy;
|
||||
final.y = current.y + std::cos(current.angle) * dy + std::sin(-current.angle) * dx;
|
||||
double x = state.x + std::cos(state.angle) * dx + std::sin( state.angle) * dy;
|
||||
double y = state.y + std::cos(state.angle) * dy + std::sin(-state.angle) * dx;
|
||||
|
||||
constrain(final.scale, final.y);
|
||||
constrain(state.scale, y);
|
||||
|
||||
if (duration == Duration::zero()) {
|
||||
current.x = final.x;
|
||||
current.y = final.y;
|
||||
state.x = x;
|
||||
state.y = y;
|
||||
} else {
|
||||
const double startX = current.x;
|
||||
const double startY = current.y;
|
||||
current.panning = true;
|
||||
const double startX = state.x;
|
||||
const double startY = state.y;
|
||||
state.panning = true;
|
||||
|
||||
startTransition(
|
||||
[=](double t) {
|
||||
current.x = util::interpolate(startX, final.x, t);
|
||||
current.y = util::interpolate(startY, final.y, t);
|
||||
state.x = util::interpolate(startX, x, t);
|
||||
state.y = util::interpolate(startY, y, t);
|
||||
return Update::Nothing;
|
||||
},
|
||||
[=] {
|
||||
current.panning = false;
|
||||
state.panning = false;
|
||||
}, duration);
|
||||
}
|
||||
|
||||
@@ -116,10 +116,10 @@ void Transform::setLatLng(const LatLng latLng, const Duration duration) {
|
||||
const double m = 1 - 1e-15;
|
||||
const double f = std::fmin(std::fmax(std::sin(util::DEG2RAD * latLng.latitude), -m), m);
|
||||
|
||||
double xn = -latLng.longitude * current.Bc;
|
||||
double yn = 0.5 * current.Cc * std::log((1 + f) / (1 - f));
|
||||
double xn = -latLng.longitude * state.Bc;
|
||||
double yn = 0.5 * state.Cc * std::log((1 + f) / (1 - f));
|
||||
|
||||
_setScaleXY(current.scale, xn, yn, duration);
|
||||
_setScaleXY(state.scale, xn, yn, duration);
|
||||
}
|
||||
|
||||
void Transform::setLatLngZoom(const LatLng latLng, const double zoom, const Duration duration) {
|
||||
@@ -132,14 +132,14 @@ void Transform::setLatLngZoom(const LatLng latLng, const double zoom, const Dura
|
||||
double new_scale = std::pow(2.0, zoom);
|
||||
|
||||
const double s = new_scale * util::tileSize;
|
||||
current.Bc = s / 360;
|
||||
current.Cc = s / util::M2PI;
|
||||
state.Bc = s / 360;
|
||||
state.Cc = s / util::M2PI;
|
||||
|
||||
const double m = 1 - 1e-15;
|
||||
const double f = std::fmin(std::fmax(std::sin(util::DEG2RAD * latLng.latitude), -m), m);
|
||||
|
||||
double xn = -latLng.longitude * current.Bc;
|
||||
double yn = 0.5 * current.Cc * std::log((1 + f) / (1 - f));
|
||||
double xn = -latLng.longitude * state.Bc;
|
||||
double yn = 0.5 * state.Cc * std::log((1 + f) / (1 - f));
|
||||
|
||||
_setScaleXY(new_scale, xn, yn, duration);
|
||||
}
|
||||
@@ -155,7 +155,7 @@ void Transform::scaleBy(const double ds, const double cx, const double cy, const
|
||||
std::lock_guard<std::recursive_mutex> lock(mtx);
|
||||
|
||||
// clamp scale to min/max values
|
||||
double new_scale = current.scale * ds;
|
||||
double new_scale = state.scale * ds;
|
||||
if (new_scale < min_scale) {
|
||||
new_scale = min_scale;
|
||||
} else if (new_scale > max_scale) {
|
||||
@@ -189,18 +189,18 @@ void Transform::setZoom(const double zoom, const Duration duration) {
|
||||
double Transform::getZoom() const {
|
||||
std::lock_guard<std::recursive_mutex> lock(mtx);
|
||||
|
||||
return final.getZoom();
|
||||
return state.getZoom();
|
||||
}
|
||||
|
||||
double Transform::getScale() const {
|
||||
std::lock_guard<std::recursive_mutex> lock(mtx);
|
||||
|
||||
return final.scale;
|
||||
return state.scale;
|
||||
}
|
||||
|
||||
double Transform::getMinZoom() const {
|
||||
double test_scale = current.scale;
|
||||
double test_y = current.y;
|
||||
double test_scale = state.scale;
|
||||
double test_y = state.y;
|
||||
constrain(test_scale, test_y);
|
||||
|
||||
return std::log2(std::fmin(min_scale, test_scale));
|
||||
@@ -222,23 +222,23 @@ void Transform::_setScale(double new_scale, double cx, double cy, const Duration
|
||||
|
||||
// Zoom in on the center if we don't have click or gesture anchor coordinates.
|
||||
if (cx < 0 || cy < 0) {
|
||||
cx = static_cast<double>(current.width) / 2.0;
|
||||
cy = static_cast<double>(current.height) / 2.0;
|
||||
cx = static_cast<double>(state.width) / 2.0;
|
||||
cy = static_cast<double>(state.height) / 2.0;
|
||||
}
|
||||
|
||||
// Account for the x/y offset from the center (= where the user clicked or pinched)
|
||||
const double factor = new_scale / current.scale;
|
||||
const double dx = (cx - static_cast<double>(current.width) / 2.0) * (1.0 - factor);
|
||||
const double dy = (cy - static_cast<double>(current.height) / 2.0) * (1.0 - factor);
|
||||
const double factor = new_scale / state.scale;
|
||||
const double dx = (cx - static_cast<double>(state.width) / 2.0) * (1.0 - factor);
|
||||
const double dy = (cy - static_cast<double>(state.height) / 2.0) * (1.0 - factor);
|
||||
|
||||
// Account for angle
|
||||
const double angle_sin = std::sin(-current.angle);
|
||||
const double angle_cos = std::cos(-current.angle);
|
||||
const double angle_sin = std::sin(-state.angle);
|
||||
const double angle_cos = std::cos(-state.angle);
|
||||
const double ax = angle_cos * dx - angle_sin * dy;
|
||||
const double ay = angle_sin * dx + angle_cos * dy;
|
||||
|
||||
const double xn = current.x * factor + ax;
|
||||
const double yn = current.y * factor + ay;
|
||||
const double xn = state.x * factor + ax;
|
||||
const double yn = state.y * factor + ay;
|
||||
|
||||
_setScaleXY(new_scale, xn, yn, duration);
|
||||
}
|
||||
@@ -251,39 +251,39 @@ void Transform::_setScaleXY(const double new_scale, const double xn, const doubl
|
||||
MapChangeRegionWillChangeAnimated :
|
||||
MapChangeRegionWillChange);
|
||||
|
||||
final.scale = new_scale;
|
||||
final.x = xn;
|
||||
final.y = yn;
|
||||
double scale = new_scale;
|
||||
double x = xn;
|
||||
double y = yn;
|
||||
|
||||
constrain(final.scale, final.y);
|
||||
constrain(scale, y);
|
||||
|
||||
if (duration == Duration::zero()) {
|
||||
current.scale = final.scale;
|
||||
current.x = final.x;
|
||||
current.y = final.y;
|
||||
const double s = current.scale * util::tileSize;
|
||||
current.Bc = s / 360;
|
||||
current.Cc = s / util::M2PI;
|
||||
state.scale = scale;
|
||||
state.x = x;
|
||||
state.y = y;
|
||||
const double s = state.scale * util::tileSize;
|
||||
state.Bc = s / 360;
|
||||
state.Cc = s / util::M2PI;
|
||||
} else {
|
||||
const double startS = current.scale;
|
||||
const double startX = current.x;
|
||||
const double startY = current.y;
|
||||
current.panning = true;
|
||||
current.scaling = true;
|
||||
const double startS = state.scale;
|
||||
const double startX = state.x;
|
||||
const double startY = state.y;
|
||||
state.panning = true;
|
||||
state.scaling = true;
|
||||
|
||||
startTransition(
|
||||
[=](double t) {
|
||||
current.scale = util::interpolate(startS, final.scale, t);
|
||||
current.x = util::interpolate(startX, final.x, t);
|
||||
current.y = util::interpolate(startY, final.y, t);
|
||||
const double s = current.scale * util::tileSize;
|
||||
current.Bc = s / 360;
|
||||
current.Cc = s / util::M2PI;
|
||||
state.scale = util::interpolate(startS, scale, t);
|
||||
state.x = util::interpolate(startX, x, t);
|
||||
state.y = util::interpolate(startY, y, t);
|
||||
const double s = state.scale * util::tileSize;
|
||||
state.Bc = s / 360;
|
||||
state.Cc = s / util::M2PI;
|
||||
return Update::Zoom;
|
||||
},
|
||||
[=] {
|
||||
current.panning = false;
|
||||
current.scaling = false;
|
||||
state.panning = false;
|
||||
state.scaling = false;
|
||||
}, duration);
|
||||
}
|
||||
|
||||
@@ -297,10 +297,10 @@ void Transform::_setScaleXY(const double new_scale, const double xn, const doubl
|
||||
|
||||
void Transform::constrain(double& scale, double& y) const {
|
||||
// Constrain minimum zoom to avoid zooming out far enough to show off-world areas.
|
||||
if (scale < (current.height / util::tileSize)) scale = (current.height / util::tileSize);
|
||||
if (scale < (state.height / util::tileSize)) scale = (state.height / util::tileSize);
|
||||
|
||||
// Constrain min/max vertical pan to avoid showing off-world areas.
|
||||
double max_y = ((scale * util::tileSize) - current.height) / 2;
|
||||
double max_y = ((scale * util::tileSize) - state.height) / 2;
|
||||
|
||||
if (y > max_y) y = max_y;
|
||||
if (y < -max_y) y = -max_y;
|
||||
@@ -316,7 +316,7 @@ void Transform::rotateBy(const double start_x, const double start_y, const doubl
|
||||
|
||||
std::lock_guard<std::recursive_mutex> lock(mtx);
|
||||
|
||||
double center_x = static_cast<double>(current.width) / 2.0, center_y = static_cast<double>(current.height) / 2.0;
|
||||
double center_x = static_cast<double>(state.width) / 2.0, center_y = static_cast<double>(state.height) / 2.0;
|
||||
|
||||
const double begin_center_x = start_x - center_x;
|
||||
const double begin_center_y = start_y - center_y;
|
||||
@@ -338,7 +338,7 @@ void Transform::rotateBy(const double start_x, const double start_y, const doubl
|
||||
const double first_x = start_x - center_x, first_y = start_y - center_y;
|
||||
const double second_x = end_x - center_x, second_y = end_y - center_y;
|
||||
|
||||
const double ang = current.angle + util::angle_between(first_x, first_y, second_x, second_y);
|
||||
const double ang = state.angle + util::angle_between(first_x, first_y, second_x, second_y);
|
||||
|
||||
_setAngle(ang, duration);
|
||||
}
|
||||
@@ -363,8 +363,8 @@ void Transform::setAngle(const double new_angle, const double cx, const double c
|
||||
double dx = 0, dy = 0;
|
||||
|
||||
if (cx >= 0 && cy >= 0) {
|
||||
dx = (static_cast<double>(final.width) / 2.0) - cx;
|
||||
dy = (static_cast<double>(final.height) / 2.0) - cy;
|
||||
dx = (static_cast<double>(state.width) / 2.0) - cx;
|
||||
dy = (static_cast<double>(state.height) / 2.0) - cy;
|
||||
_moveBy(dx, dy, Duration::zero());
|
||||
}
|
||||
|
||||
@@ -382,22 +382,22 @@ void Transform::_setAngle(double new_angle, const Duration duration) {
|
||||
MapChangeRegionWillChangeAnimated :
|
||||
MapChangeRegionWillChange);
|
||||
|
||||
final.angle = _normalizeAngle(new_angle, current.angle);
|
||||
current.angle = _normalizeAngle(current.angle, final.angle);
|
||||
double angle = _normalizeAngle(new_angle, state.angle);
|
||||
state.angle = _normalizeAngle(state.angle, angle);
|
||||
|
||||
if (duration == Duration::zero()) {
|
||||
current.angle = final.angle;
|
||||
state.angle = angle;
|
||||
} else {
|
||||
const double startA = current.angle;
|
||||
current.rotating = true;
|
||||
const double startA = state.angle;
|
||||
state.rotating = true;
|
||||
|
||||
startTransition(
|
||||
[=](double t) {
|
||||
current.angle = util::interpolate(startA, final.angle, t);
|
||||
state.angle = util::interpolate(startA, angle, t);
|
||||
return Update::Nothing;
|
||||
},
|
||||
[=] {
|
||||
current.rotating = false;
|
||||
state.rotating = false;
|
||||
}, duration);
|
||||
}
|
||||
|
||||
@@ -410,7 +410,7 @@ void Transform::_setAngle(double new_angle, const Duration duration) {
|
||||
double Transform::getAngle() const {
|
||||
std::lock_guard<std::recursive_mutex> lock(mtx);
|
||||
|
||||
return final.angle;
|
||||
return state.angle;
|
||||
}
|
||||
|
||||
|
||||
@@ -467,7 +467,7 @@ void Transform::cancelTransitions() {
|
||||
void Transform::setGestureInProgress(bool inProgress) {
|
||||
std::lock_guard<std::recursive_mutex> lock(mtx);
|
||||
|
||||
current.gestureInProgress = inProgress;
|
||||
state.gestureInProgress = inProgress;
|
||||
}
|
||||
|
||||
#pragma mark - Transform state
|
||||
@@ -475,11 +475,5 @@ void Transform::setGestureInProgress(bool inProgress) {
|
||||
const TransformState Transform::currentState() const {
|
||||
std::lock_guard<std::recursive_mutex> lock(mtx);
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
const TransformState Transform::finalState() const {
|
||||
std::lock_guard<std::recursive_mutex> lock(mtx);
|
||||
|
||||
return final;
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ public:
|
||||
void moveBy(double dx, double dy, Duration = Duration::zero());
|
||||
void setLatLng(LatLng latLng, Duration = Duration::zero());
|
||||
void setLatLngZoom(LatLng latLng, double zoom, Duration = Duration::zero());
|
||||
inline const LatLng getLatLng() const { return current.getLatLng(); }
|
||||
inline const LatLng getLatLng() const { return state.getLatLng(); }
|
||||
|
||||
// Zoom
|
||||
void scaleBy(double ds, double cx = -1, double cy = -1, Duration = Duration::zero());
|
||||
@@ -58,7 +58,6 @@ public:
|
||||
|
||||
// Transform state
|
||||
const TransformState currentState() const;
|
||||
const TransformState finalState() const;
|
||||
|
||||
private:
|
||||
// Functions prefixed with underscores will *not* perform any locks. It is the caller's
|
||||
@@ -74,13 +73,7 @@ private:
|
||||
|
||||
mutable std::recursive_mutex mtx;
|
||||
|
||||
// This reflects the current state of the transform, representing the actual position of the
|
||||
// map. After calling a transform function with a timer, this will likely remain the same until
|
||||
// you render a new frame.
|
||||
TransformState current;
|
||||
|
||||
// This reflects the final position of the transform, after all possible transition took place.
|
||||
TransformState final;
|
||||
TransformState state;
|
||||
|
||||
// Limit the amount of zooming possible on the map.
|
||||
const double min_scale = std::pow(2, 0);
|
||||
|
||||
@@ -76,9 +76,8 @@
|
||||
0,
|
||||
@"compass should not be visible when map is unrotated");
|
||||
|
||||
XCTAssertEqualObjects([NSValue valueWithCGAffineTransform:tester.compass.transform],
|
||||
[NSValue valueWithCGAffineTransform:CGAffineTransformIdentity],
|
||||
@"compass rotation should indicate map rotation");
|
||||
XCTAssert(CGAffineTransformEqualToTransform(tester.compass.transform, CGAffineTransformIdentity),
|
||||
@"compass rotation should indicate map rotation");
|
||||
}
|
||||
|
||||
- (void)testDirectionReset {
|
||||
@@ -100,9 +99,8 @@
|
||||
0,
|
||||
@"compass should not be visible when map is unrotated");
|
||||
|
||||
XCTAssertEqualObjects([NSValue valueWithCGAffineTransform:tester.compass.transform],
|
||||
[NSValue valueWithCGAffineTransform:CGAffineTransformIdentity],
|
||||
@"compass rotation should indicate map rotation");
|
||||
XCTAssert(CGAffineTransformEqualToTransform(tester.compass.transform, CGAffineTransformIdentity),
|
||||
@"compass rotation should indicate map rotation");
|
||||
}
|
||||
|
||||
- (void)testZoom {
|
||||
|
||||
Reference in New Issue
Block a user