WP7 Compass

5 posts, 0 answers
  1. Pete
    Pete avatar
    11 posts
    Member since:
    Feb 2011

    Posted 22 Apr 2011 Link to this post

    Hi,
    anyone any ideas on using the gauges to implement a compass ?

    Thanks
  2. Victor
    Admin
    Victor avatar
    1351 posts

    Posted 09 May 2011 Link to this post

    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>>
  3. DevCraft banner
  4. ManniAT
    ManniAT avatar
    877 posts
    Member since:
    Nov 2003

    Posted 05 Jun 2011 Link to this post

    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
  5. Victor
    Admin
    Victor avatar
    1351 posts

    Posted 06 Jun 2011 Link to this post

    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>>
  6. ManniAT
    ManniAT avatar
    877 posts
    Member since:
    Nov 2003

    Posted 06 Jun 2011 Link to this post

    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
Back to Top
DevCraft banner