Search code examples
c#windows-phone-8compass

How to Get Qibla Direction at Compass Windows Phone 8?


I'm developing an Islamic app which has Qibla feature. I can determine Qibla direction in degrees from my current location using my longitude and latitude. For examle: From Cairo, Qibla direction will be 137 degree. How to make compass sensor in windows phone navigate to this angle?

Edit:

I'm using this method to get sensor heading readings:

public void RunCompass()
{
    try
    {
        if (Compass.IsSupported)
        {
            // If compass sensor is supported create new compass object and attach event handlers
            Compass myCompass = new Compass();
            // This defines how often heading is updated
            myCompass.TimeBetweenUpdates = System.TimeSpan.FromMilliseconds(100); 
            myCompass.Calibrate += new System.EventHandler<CalibrationEventArgs>((s, e) =>
            {
                // This will show the calibration screen
                this.IsCalibrationNeeded = true;
            });
            myCompass.CurrentValueChanged += new System.EventHandler<SensorReadingEventArgs<CompassReading>>((s, e) =>
            {
                // This will update the current heading value. We have to put it in correct direction
                Deployment.Current.Dispatcher.BeginInvoke(() =>
                {
                    CurrentHeading =   e.SensorReading.TrueHeading;
                    if (CurrentHeading >= (RotationAngel - 10) && CurrentHeading <= (RotationAngel + 10))
                    {
                        //Show Kaba
                        KabaVisability = true;
                    }
                    else
                    {
                        KabaVisability = false;
                    }                       
                });
            });
            // Start receiving data from compass sensor
            myCompass.Start();              
        }
    }
    catch (Exception)
    {
    }
}

I'm use CurrentHeading as rotation angel of my pointer. RotaionAgel is angle for Qibla for example 137.

My XAML Code:

<Grid> 
 <Ellipse>
  <Ellipse.Fill>
   <ImageBrush ImageSource="/Assets/qebla_new.png" Stretch="UniformToFill"/>
  </Ellipse.Fill>
  </Ellipse>
  <Border x:Name="head" RenderTransformOrigin="0.5,0.5" Margin="191,0" Padding="0,66,0,162" UseLayoutRounding="False">
   <Border.RenderTransform>
      <RotateTransform Angle="{Binding CurrentHeading,Mode=TwoWay}">     
   </RotateTransform> <!---->
   </Border.RenderTransform>
</Grid>

Thanks in advance,


Solution

  • I did a similar thing one app, showing a compass pointing to a selected landmark (Mecca in your case). I used this code to calculate the bearing:

    public static class DistanceCalculator
    {
        const double kDegreesToRadians = Math.PI / 180.0;
        const double kRadiansToDegrees = 180.0 / Math.PI;
    
    
        public static double Bearing(GeoCoordinate position, GeoCoordinate location)
        {
            double fromLong = position.Longitude * kDegreesToRadians;
            double toLong = location.Longitude * kDegreesToRadians;
            double fromLat = position.Latitude * kDegreesToRadians;
    
            double dlon = toLong - fromLong;
            double y = Math.Sin(dlon) * Math.Cos(toLat);
            double x = Math.Cos(fromLat) * Math.Sin(toLat) - Math.Sin(fromLat) * Math.Cos(toLat) * Math.Cos(dlon);
    
            double direction = Math.Atan2(y, x);
    
            // convert to degrees
            direction = direction * kRadiansToDegrees;
            // normalize
            double fraction = modf(direction + 360.0, direction);
            direction += fraction;
    
            if (direction > 360)
            {
                direction -= 360;
            }
    
            return direction;
        }
    
        private static double modf(double orig, double ipart)
        {
            return orig - (Math.Floor(orig));
        }
    } 
    

    and used it with

    var res = DistanceCalculator.Bearing(Position, SelectedPlace.Position);
    TargetHeading = (360 - res) % 360;
    

    I then get my current real heading from the compass

    CurrentHeading = 360 - e.SensorReading.TrueHeading;
    

    and use the difference

     public double HeadingDifference
     {
        get
        {
            return CurrentHeading - TargetHeading;
        }
     }
    

    to point the arrow in XAML

    <Image Source="/Assets/sn_ico_et_compass_whitepointer.png" x:Name="arrow">
        <Image.RenderTransform>
            <RotateTransform Angle="{Binding HeadingDifference}" CenterX="240" CenterY="240" x:Name="arrowTransform" />
        </Image.RenderTransform>
    </Image>