Search code examples
c#visual-studio-2012windows-phone-8augmented-reality

Compass error when heading changes from 359-1 or 1-359. C# Windows Phone 8


Landscape mode with compass at top left

I am implementing landscape mode augmented reality app. The little circle to the top left is the compass which shows where north is. Previously I used it in portrait mode. And it absolutely worked fine. but when I shifted to there are two problems. One problem is existing already in portrait mode also.

  1. When the trueheading changes from 1 to 359 or 359 to 1, the compass doesnt know to take the shortest angle directly but it rotates all the full circle and goes to the final heading. Like when the trueheading is 1 degree and I turn the device a little north to make the trueheading 358, it doesnt directly go from 1-0-359-358, it takes a full path from 1-2-5-200-300-358 i.e an almost full circle. This is because I am animating the rotation using storyboard double animation. So how do I fix this ?
  2. And the second problem is, as you can easily understand, the reference axis for trueheading is the device's top part, when the device's top part is headed towards north, the N letter in the circle is always in the green area. I.e 0 degree with respect to the grid in which it is placed. But I want it to take the reference line for measuring the angle by which to turn to be the line joining device's top and bottom part. How do I achieve this ? How can I set the double animation's reference line 90degree to the original ??

There seems to be a bug here because I cannot add the code. But here is the text file which contains the code that I want to show you. Code sample explained above


Solution

  • For your point 1, what you want to do is to detect cases when you're about to rotate of an angle greater than 180°, and then take the shorter path.

    var rotation = newAngle - oldAngle;
    
    if (Math.Abs(rotation) > 180)
    {
        // Rotating of more than 180, which means it exists a shorter path
        newAngle += rotation > 0 ? -360 : 360;
    }
    
    // Start the animation to rotate to newAngle
    

    If the old angle is 1 and the new angle is 359, the rotation will be 358. It's positive, so the code will subtract 360 to 359, and therefore rotate from 1 to -1.

    If the old angle is 359 and the new angle is 1, the rotation will be -358. It's negative, so the code will add 360 to 1, and therefore rotate from 359 to 361.

    Note: in the second case, after the rotation, the angle will be 361. Then you'll have exactly the same problem is you try to rotate to 2° or 3°, and the algorithm will correct the angle to 362, 363, and so on. At some point, if the compass keeps rotating in the same direction, the angle will reach 540 and the algorithm will stop working properly. To prevent this kind of issue, you need to detect when your animation has stopped (there's an event for that), then adjust the angle so it stays in the 0-359 range:

    if (angle > 359)
    {
        angle += (angle / 360) * -360;
    }
    else if (angle < 0)
    {
        angle += ((angle / 360) - 1) * -360;
    }
    

    Since you're changing the angle by multiples of 360, there will be no visual impact to this adjustment.