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

Normalize angle of 360 degrees to 0 degrees #1558

Closed
wants to merge 1 commit into from
Closed

Normalize angle of 360 degrees to 0 degrees #1558

wants to merge 1 commit into from

Conversation

friedbunny
Copy link
Contributor

This fixes the compass not disappearing after it is reset, especially when returning from the background.

When interpolating across 180º, _normalizeAngle will return >180º. Then, trying to reset the bearing to 0º would result in interpolation to 360º. Because [MGLMapView updateCompass] expects bearing to equal 0º when the compass is done resetting, the compass was never disappearing.

Steps to reproduce

  1. Turn on heading-follow location tracking in iOS demo app
  2. Rotate device to a heading less than 180º (due south)
  3. Lock device
  4. While locked, rotate beyond 180º
  5. Unlock device, tap compass to reset heading
  6. Compass will reset, but not disappear because bearing is 360º, not 0º

You can also test this by setting a breakpoint in /src/mbgl/map/transform.cpp _normalizeAngle and doing this:

Start by moving to 171º from 196º:

(lldb) po _normalizeAngle(-2.999457083051174, 3.4266856461794291)
3.2837282241284118 = 189º

When it comes time to reset to 0º from 189º:

(lldb) po _normalizeAngle(0, 3.2837282241284118)
6.2831853071795862 = 360º

Which is the same as 0º, but not what we're looking for.

/cc @1ec5 @incanus

When interpolating across 180º, _normalizeAngle will return >180º. Then trying to reset the bearing to 0º would result in interpolation to 360º when we were expecting 0º.

Result: iOS compass would not disappear when reset because it expects 0º.
@1ec5
Copy link
Contributor

1ec5 commented May 14, 2015

In the course of refactoring the compass for #1496, I discovered another off-by-ε error that may be related.

@jfirebaugh
Copy link
Contributor

Does this preserve the behavior that animated rotations from ø > 180º to 0º take the shortest path around the circle, i.e. to 360º?

@friedbunny
Copy link
Contributor Author

@friedbunny
Copy link
Contributor Author

Found an easier way to trigger the original bug: do the rotation gesture very hard.

@kkaefer
Copy link
Member

kkaefer commented May 26, 2015

Does this only happen for 180 degrees? If so, it looks like the culprit may be in util::wrap, because, the range should be exclusive in one end (preferably the high one), so it should normalize -180 <= x < 180, rather than -180 <= x <= 180.

@friedbunny
Copy link
Contributor Author

Perhaps @mourner could weigh in on our use of util::wrap?

template <typename T>
T wrap(T value, T min, T max) {
    T d = max - min;
    return value == max ? value : std::fmod((std::fmod((value - min), d) + d), d) + min;
}

JS implementation is here.

@friedbunny
Copy link
Contributor Author

This was fixed in #1829 by @1ec5.

@friedbunny friedbunny closed this Jul 6, 2015
@friedbunny friedbunny deleted the normalize-to-zero branch July 6, 2015 19:58
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants