-
Notifications
You must be signed in to change notification settings - Fork 1.3k
[core] - avoid animating with infinite zoom out factor for Transform::FlyTo #8302
[core] - avoid animating with infinite zoom out factor for Transform::FlyTo #8302
Conversation
@tobrun, thanks for your PR! By analyzing this pull request, we identified @1ec5, @jfirebaugh and @incanus to be potential reviewers. |
src/mbgl/map/transform.cpp
Outdated
// When u₀ = u₁, the optimal path doesn’t require both ascent and descent. | ||
bool isClose = std::abs(u1) < 0.000001; | ||
// When u₀ = u₁ or zoom out factor = inf, the optimal path doesn’t require both ascent and descent. | ||
bool isClose = std::abs(u1) < 0.000001 || isinf(r(0)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually now thinking that this shouldn't be added as part of bool isClose
but should be added to the if check below..
src/mbgl/map/transform.cpp
Outdated
// Perform a more or less instantaneous transition if the path is too short. | ||
if (isClose && std::abs(w0 - w1) < 0.000001) { | ||
// Perform a more or less instantaneous transition if the path is too short or zoom out factor is inf. | ||
if ((isClose && std::abs(w0 - w1) < 0.000001) || isinf(r(0))) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What causes the ascent factor to be infinite? Do we need to check the descent factor too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pardon me if miss something obvious, but for me (on ubuntu linux), this code doesn't compile (it does if I use explicitely std::isinf, as is done for abs)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch @mrlem – it does compile on most of the platforms/compilers we support (as seen in the CI builds), but we should use std::
explicitly to be safe. 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@1ec5 good call on descent factor, let me try reproducing the reverse interaction.
What causes the ascent factor to be infinite
: a division by 0 in the following code
auto r = [=](double i) {
/// bᵢ
double b = (w1 * w1 - w0 * w0 + (i ? -1 : 1) * rho2 * rho2 * u1 * u1) / (2 * (i ? w1 : w0) * rho2 * u1);
return std::log(std::sqrt(b * b + 1) - b);
};
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wasn't able to reproducing a infinite descent factor but I don't see an issue adding a check for this either. I added this in eeaefae.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a division by 0 in the following code
So that means either w1
or rho2
or u1
is 0, right? Sorry to keep going here; just want to make sure we aren’t running into something more fundamental.
eeaefae
to
2e739e7
Compare
@@ -243,8 +243,8 @@ void Transform::flyTo(const CameraOptions &camera, const AnimationOptions &anima | |||
|
|||
// When u₀ = u₁, the optimal path doesn’t require both ascent and descent. | |||
bool isClose = std::abs(u1) < 0.000001; | |||
// Perform a more or less instantaneous transition if the path is too short. | |||
if (isClose && std::abs(w0 - w1) < 0.000001) { | |||
// Perform a more or less instantaneous transition if the path is too short or zoom in/out factor is infinte |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo
src/mbgl/map/transform.cpp
Outdated
// Perform a more or less instantaneous transition if the path is too short. | ||
if (isClose && std::abs(w0 - w1) < 0.000001) { | ||
// Perform a more or less instantaneous transition if the path is too short or zoom in/out factor is infinte | ||
if ((isClose && std::abs(w0 - w1) < 0.000001) || std::isinf(r(0)) || std::isinf(r(1))) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please explain why this is a correct solution? It feels like putting band-aid on the problem without fixing the underlying problem.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Been looking back and forth between the original paper and our implementation. One difference that I noticed is that we added a check for small changes, as these aren't ideal for the algorithm. Instead we are currently performing an easeTo instead. I don't feel that I'm adding a band-aid to the problem, I'm hardening the existing one.
Above is a normal situation of a flyTo implementation but the use-case described in
#8300 is having a origin and target camera position that is almost the same. This isn't fully captured by current bandaid solution. The algorithm seem to generate -infinite zoom out values as a result of log(o) in following code with i=1:
/** rᵢ: Returns the zoom-out factor at one end of the animation.
@param i 0 for the ascent or 1 for the descent. */
auto r = [=](double i) {
/// bᵢ
double b = (w1 * w1 - w0 * w0 + -1 * rho2 * rho2 * u1 * u1) / (2 * (i ? w1 : w0) * rho2 * u1);
return std::log(std::sqrt(b * b + 1) - b);
};
My proposal is to optimise the bandaid solution as this interaction is not ideal for a flyTo interaction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
src/mbgl/map/transform.cpp
Outdated
// Perform a more or less instantaneous transition if the path is too short. | ||
if (isClose && std::abs(w0 - w1) < 0.000001) { | ||
// Perform a more or less instantaneous transition if the path is too short or zoom in/out factor is infinte | ||
if ((isClose && std::abs(w0 - w1) < 0.000001) || std::isinf(r(0)) || std::isinf(r(1))) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Micro-optimization: Instead of computing r(0)
and r(1)
here, can we split up this conditional return and store the results of r(0)
and r(1)
into a constant; they are recomputed further down.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There’s already an r0
variable just below.
I’m able to reproduce the issue in macosapp using the parameters in #8300 (comment), but I’m noticing that |
@1ec5 the device I was using had a |
… a transformation is close by for flyTo
2e739e7
to
7dec2ac
Compare
My point is that the minZoom depends on the aspect ratio of the map view. For a non-full-screen map view, the aspect ratio could be just about anything. |
Closing as suggested band aid solution didn't capture all use-cases |
This PR fixes the issue if you try to flyTo a camera position that is zoomed out but has the (allmost) the same target LatLng.
closes #8300