Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

[core] - avoid animating with infinite zoom out factor for Transform::FlyTo #8302

Closed

Conversation

tobrun
Copy link
Member

@tobrun tobrun commented Mar 7, 2017

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

@tobrun tobrun added the Core The cross-platform C++ core, aka mbgl label Mar 7, 2017
@tobrun tobrun added this to the android-v5.0.0 milestone Mar 7, 2017
@tobrun tobrun self-assigned this Mar 7, 2017
@tobrun tobrun requested a review from 1ec5 March 7, 2017 19:19
@mention-bot
Copy link

@tobrun, thanks for your PR! By analyzing this pull request, we identified @1ec5, @jfirebaugh and @incanus to be potential reviewers.

// 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));
Copy link
Member Author

@tobrun tobrun Mar 7, 2017

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..

// 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))) {
Copy link
Contributor

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?

Copy link

@mrlem mrlem Mar 8, 2017

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)

Copy link
Contributor

@1ec5 1ec5 Mar 8, 2017

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. 👍

Copy link
Member Author

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);
    };

Copy link
Member Author

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.

Copy link
Contributor

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.

@tobrun tobrun force-pushed the tvn-blank-map-with-zoom-out branch from eeaefae to 2e739e7 Compare March 8, 2017 17:38
@zugaldia zugaldia requested a review from kkaefer March 9, 2017 18:12
@@ -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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo

// 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))) {
Copy link
Contributor

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.

Copy link
Member Author

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.

screen shot 2017-03-13 at 14 31 36

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.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

// 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))) {
Copy link
Contributor

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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Copy link
Contributor

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.

@1ec5
Copy link
Contributor

1ec5 commented Mar 16, 2017

I’m able to reproduce the issue in macosapp using the parameters in #8300 (comment), but I’m noticing that r(0) is -12.395270530594363 and r(1) is 120828.22925742983, not infinity (and the transition isn’t “close” either). It may be relevant that a map view frame 683 points wide by 722 points high results in an mbgl::TransformState::minZoom of 0.49585502688717098 rather than 0, due to constraining the map at the world bounds.

@tobrun
Copy link
Member Author

tobrun commented Mar 17, 2017

@1ec5 the device I was using had a mgbl::TransfrormState::minZooom = 0.2360141919000848.

@tobrun tobrun force-pushed the tvn-blank-map-with-zoom-out branch from 2e739e7 to 7dec2ac Compare March 17, 2017 14:12
@tobrun tobrun mentioned this pull request Mar 17, 2017
10 tasks
@1ec5
Copy link
Contributor

1ec5 commented Mar 17, 2017

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.

@tobrun tobrun removed this from the android-v5.0.0 milestone Mar 17, 2017
@tobrun
Copy link
Member Author

tobrun commented Mar 24, 2017

Closing as suggested band aid solution didn't capture all use-cases

@tobrun tobrun closed this Mar 24, 2017
@tobrun tobrun deleted the tvn-blank-map-with-zoom-out branch April 21, 2017 09:08
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Core The cross-platform C++ core, aka mbgl
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants