This is a migrated thread and some comments may be shown as answers.

WP7 Compass

4 Answers 95 Views
Gauge
This is a migrated thread and some comments may be shown as answers.
This question is locked. New answers and comments are not allowed.
Pete
Top achievements
Rank 1
Pete asked on 22 Apr 2011, 04:57 PM
Hi,
anyone any ideas on using the gauges to implement a compass ?

Thanks

4 Answers, 1 is accepted

Sort by
0
Victor
Telerik team
answered on 09 May 2011, 07:58 AM
Hi Pete,

 Thank you for the question.
A compass cannot be implemented, at least to my knowledge, on the current Windows Phone device. The device has an accelerometer and GPS support. The accelerometer only gives you vector data relative to the center of the Earth and the GPS only gives you spherical coordinates and no orientation data relative to the poles of the Earth.

Please write again if you have other questions.

All the best,
Victor
the Telerik team
Let us know about your Windows Phone 7 application built with RadControls and we will help you promote it. Learn more>>
0
ManniAT
Top achievements
Rank 2
answered on 05 Jun 2011, 05:08 PM
Hi,

I already implemented a GPS compass.
The "problem" - it's a GPS related thing.
So what you get is the direction you move to.

If you stop - nothing happens. If you turn the device - nothing happens.

But for the use in a car it works pretty perfect - as long as you are aware what it is - a thing which shows you your driving direction.
I did this compass without the use of RadGauge - just because the main work is the desing.
And than there is an element you rotate.

For this by the way I took the RadGauge compass example and changed the animation code a bit.

BUT - and thats clear - you can also use the compass example from silverlight.
The only thing to mention - GPS gives you the driving direction.
If you want this up (like holding a real compass straight in front of you) you have to subtract the given value from 360 to get a rotation value.
The reason - you get the driving direction - and want the needle to point to north.

And - just to keep you using RadGauge - I also implemented a speedometer.
And for this (of course) I used RadChart.
It gives me current speed, Max Speed, Min Speed and Average Speed - all on one instrument.

Manfred
PS: I attached a screenshot of a test application showing the Compass and the Tacho (RadGauge)
By the way - the orange range is Average speed, the green dot min and the red one max
0
Victor
Telerik team
answered on 06 Jun 2011, 07:20 AM
Hello ManniAT,

 It is great that you figured out how to create a compass. Also thank you for sharing your knowledge. It appears that the Mango update for Windows Phone 7 will have a compass API so implementing a compass should be even easier.

All the best,
Victor
the Telerik team
Let us know about your Windows Phone 7 application built with RadControls and we will help you promote it. Learn more>>
0
ManniAT
Top achievements
Rank 2
answered on 06 Jun 2011, 07:45 AM
Hi Victor,

yes Manog will have a compass - if your device has one :)
And the API should also work on "old devices". I'm not sure how it will work in this case.
But anyhow - I'm sure I can use my existing compass with it.
I made a user control with a "Course" property. So if the new API arrives I'll simply bind it to a value provided by the "compass-api" instead of binding it to the GPS course.

Maybe I've to avoid the -360 thing for this.
By the way - I wrote above that I had to change your (teleriks) code I took from the SL compass sample.
The code is there to provide "short way rotation" or in other words, it takes care about situations when your new position is on the other side. So without that code a change from 340 to 20 would turn the compass counterclockwise - "the long way".
Your code checks this situation and divides the rotation animation in two - one from 340 to 360 followed by a second one from 0 to 20.

The problem with the existing code - it simply divides the animation time by two.
So it looks a bit bad when you have animations where the distance difers a lot.
For an example you go from 200 to 20.
It takes the same time from 200 to 360 as it takes from 0 to 20.
I implemented a simple algorithm wich takes care about this.

Here is the code for it:

public partial class GPSCompass : UserControl {
    private BackEase bE;
    private double m_dSecondFromValue;
    private double m_dSecondToValue;
  
    public GPSCompass() {
        InitializeComponent();
        bE = new BackEase();
        bE.EasingMode = EasingMode.EaseOut;
        bE.Amplitude = 0.6;
    }
  
  
    #region Course handling
    public double Course {
        get { return (double)GetValue(CourseProperty); }
        set { SetValue(CourseProperty, value); }
    }
    public static readonly DependencyProperty CourseProperty =
        DependencyProperty.Register("Course", typeof(double), typeof(GPSCompass),
            new PropertyMetadata(0.0, new PropertyChangedCallback(OnCourseChanged)));
    private static void OnCourseChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) {
        GPSCompass control = (GPSCompass)obj;
        //handle "driving direction always to"
        double dOldValue = 0;
        try {
            dOldValue = 360.0 - (double)args.OldValue;
        }
        catch {
            dOldValue = 0;
        }
        double dNewValue = 0;
        try {
            dNewValue = 360.0 - (double)args.NewValue;
        }
        catch {
            dNewValue = 0;
        }
        control.SetNewValueToIndicator(dNewValue, dOldValue);
        control._TextBoxHeading.Text = ((double)args.NewValue).ToString("F0");
    }
    #endregion
  
  
    private void SetNewValueToIndicator(double newValue, double oldValue) {
        CreateAndRunAnimation(oldValue, newValue);
    }
  
    private Storyboard CreateAnimation(double fromValue, double toValue, Duration duration) {
        // Create DoubleAnimations and set their properties.   
        DoubleAnimation daRotationAnimation = new DoubleAnimation();
        daRotationAnimation.Duration = duration;
  
        Storyboard storyboard = new Storyboard();
        storyboard.Children.Add(daRotationAnimation);
        Storyboard.SetTarget(daRotationAnimation, _HeadingPointer);
        if(duration.TimeSpan.Milliseconds % 10 == 0) {  //ease only on final animation
            daRotationAnimation.EasingFunction = bE;
        }
        Storyboard.SetTargetProperty(daRotationAnimation, new PropertyPath("(UIElement.RenderTransform).(CompositeTransform.Rotation)"));
  
        daRotationAnimation.From = (double.IsNaN(fromValue) ? 0 : fromValue);
        daRotationAnimation.To = toValue;
        return storyboard;
    }
  
    private void CreateAndRunAnimation(double fromValue, double toValue) {
        double dFirstDistance=0;
        double dSecondDistance = 0;
        Duration duration;
        double distance = Math.Abs(toValue - fromValue);
        if(distance > 180) {
            if(toValue > 180) {
                m_dSecondFromValue = 360;
                m_dSecondToValue = toValue;
                toValue = 0;
                dFirstDistance = fromValue;
                dSecondDistance = 360 - m_dSecondToValue;
            }
            else if(fromValue > 180) {
                m_dSecondFromValue = 0;
                m_dSecondToValue = toValue;
                toValue = 360;
                dFirstDistance = 360 - fromValue;
                dSecondDistance = m_dSecondToValue;
            }
        }
        else {
            dFirstDistance = distance;
        }
        duration = new Duration(TimeSpan.FromMilliseconds(CalcDuration(dFirstDistance, dSecondDistance)));
        Storyboard storyboard__1 = CreateAnimation(fromValue, toValue, duration);
        storyboard__1.Completed += onCompleted;
        storyboard__1.Begin();
    }
    private int CalcDuration(double dFirstDistance , double dSecondDistance ) {
        int nRet = 100;
        double dPart1 = 0;
        double dPart2 = 0;
        dPart1 = Math.Round(dFirstDistance / 180, 2);
        if(dSecondDistance != 0) {
            dPart2 = Math.Round(dSecondDistance / 180, 1);
            if(dPart2 < 0.1) {
                dPart2 = 0.1;
            }
            if(dPart1 < 0.1) {
                dPart1 = 0.1;
            }
            if((dPart1 + dPart2) < 0.5) {
                while((dPart1 + dPart2) < 0.5) {
                    dPart1 += 0.1;
                    dPart2 += 0.1;
                }
            }
            else if(dPart2 > 0.8) { //a bit shorter if double animation
                dPart2 = 0.8;
            }
            if(dPart1 > 0.8) {//a bit shorter if double animation
                dPart1 = 0.8;
            }
        }
        else if(dPart1 < 0.5) {
            dPart1 = 0.5;
        }
        else if(dPart1 > 0.9) {
            dPart1 = 0.9;
        }
        nRet = ((int)(dPart1 * 1000.0));
        nRet += ((int)(dPart2 * 10.0));
        return (nRet);
    }
  
    private void onCompleted(object sender, EventArgs e) {
        double dNewTime = 0;
        Storyboard stB = sender as Storyboard;
        if(stB != null) {
            DoubleAnimation dA = stB.Children[0] as DoubleAnimation;
            if(dA != null) {
                int nMilli = dA.Duration.TimeSpan.Milliseconds;
                int nSecondSpan = nMilli % 10;
                if(nSecondSpan > 0) {   //animation has two parts?
                    dNewTime = nSecondSpan;
                    dNewTime /= 10;
                }
            }
        }
        if(dNewTime>0) {    //second part needed?
            Duration duration = new Duration(TimeSpan.FromSeconds(dNewTime));
            Storyboard storyboard = CreateAnimation(m_dSecondFromValue, m_dSecondToValue, duration);
            storyboard.Begin();
        }
    }
}

Maybe this gives you an idea how a compass can be made using RadGauge and WP7 location services.

Manfred
Tags
Gauge
Asked by
Pete
Top achievements
Rank 1
Answers by
Victor
Telerik team
ManniAT
Top achievements
Rank 2
Share this question
or