Account for values on both size of 360#25
Conversation
| let finalHeadingNormalized = wrap(finalHeading, min: 0, max: 360) | ||
| let userHeadingNormalized = wrap(location.course, min: 0, max: 360) | ||
| courseMatchesManeuverFinalHeading = abs((finalHeadingNormalized - userHeadingNormalized) - 360) <= RouteControllerMaximumAllowedDegreeOffsetForTurnCompletion | ||
| courseMatchesManeuverFinalHeading = abs((finalHeadingNormalized - userHeadingNormalized)) <= RouteControllerMaximumAllowedDegreeOffsetForTurnCompletion || abs((finalHeadingNormalized - userHeadingNormalized) - 360) <= RouteControllerMaximumAllowedDegreeOffsetForTurnCompletion |
There was a problem hiding this comment.
In the case where the user heading is zero and the final heading is zero, without this ||, this would be false
| let finalHeadingNormalized = wrap(finalHeading, min: 0, max: 360) | ||
| let userHeadingNormalized = wrap(location.course, min: 0, max: 360) | ||
| courseMatchesManeuverFinalHeading = abs(finalHeadingNormalized - userHeadingNormalized) <= RouteControllerMaximumAllowedDegreeOffsetForTurnCompletion | ||
| courseMatchesManeuverFinalHeading = abs((finalHeadingNormalized - userHeadingNormalized)) <= RouteControllerMaximumAllowedDegreeOffsetForTurnCompletion || abs((finalHeadingNormalized - userHeadingNormalized) - 360) <= RouteControllerMaximumAllowedDegreeOffsetForTurnCompletion |
There was a problem hiding this comment.
Conceptually, you want to determine the difference between two angles, then check that difference against a threshold. There are some great solutions in http://stackoverflow.com/questions/1878907/the-smallest-difference-between-2-angles and http://stackoverflow.com/questions/12234574/calculating-if-an-angle-is-between-two-angles that are provably correct. Some use the % operator, while others use trigonometric functions. (If you go the trigonometric route, note that the trigonometric functions in Swift expect arguments in radians, not degrees.)
There was a problem hiding this comment.
If you break this out into a standalone function in Geometry.swift, here’s a test suite you can port to Swift: https://gist.github.com/bradphelan/7fe21ad8ebfcb43696b8.
| */ | ||
| func smallestAngle(alpha: Double, beta: Double) -> Double { | ||
| let phi = abs(beta - alpha).truncatingRemainder(dividingBy: 360); | ||
| return phi > 180 ? 360 - phi : phi; |
| /* | ||
| Returns the smallest angle between two angles | ||
| */ | ||
| func smallestAngle(alpha: Double, beta: Double) -> Double { |
There was a problem hiding this comment.
Name this function differenceBetweenDirections(_:_:). Also, use CLLocationDirection instead of Double, so it’s clear that the function takes degree measurements, not radians.
Source bearing
Ran into a situation today where the maneuver final heading was
358degrees and the user heading never crossed from 0 to35x(the user heading remained around 4 which is an acceptable heading for this example). Thus, the difference between the user heading and the final heading was ~354 degrees.This change normalizes the difference between the user and final heading further.