Qibla Compass for Windows Phone

This article explains how to find the Qibla Direction using Windows Phone Compass APIs.

Code ExampleTested with
Devices(s): Nokia Lumia 820
CompatibilityPlatform Security
Capabilities: Sensors, Location
Article
Created: arafattehsin (14 Apr 2013)
Last edited: arafattehsin (27 Nov 2013)

Introduction

Qibla compass is one of the mostly used community applications/utility among Muslims. It allows users to determine the correct location / direction of Ka’aba (Makkah tul Mukarramah, Saudi Arabia).

This utility requires some location parameters and trigonometric calculations to determine the angle of Ka’aba and upon modelling that, we can set up or rotate our compass relative to the true North (instead of magnetic North).

Before you dive into the development stage, it is required to understand the basics of finding out the correct angle, setting up the compass and the issues which have been reported on the Internet regarding correct direction of finding Qibla.

Qibla Compass for Windows Phone.

Mathematics

The calculation depends upon number of factors, parameters and considerations. Before we dig into the actual formula to find out Qibla’s angle, you should be aware of fundamental geometry and cardinal directions.

Formula

Formula to find out the angle for Qibla.

Implementation

The angle of Ka’abah is calculated by providing few parameters as stated above in a formula section. Coordinates for Ka’abah (Lat: 27.282821, Lon: 58341148) will always be hardcoded as that’s the location where our compass will always be pointing to. However, your location can be varied depending upon what threshold have you defined in meters.

Note: I would recommend you to save your location in settings and then try to use it in Qibla Compass - otherwise, there will be significant performance issues (as GPS and Sensors would both be active at the same time)

In this code example, we use stored geo coordinates (latitude, longitude) in Application Settings to avoid the performance issues and to imitate best practice.

The code model

We have got one class as a Model for Qibla that contains properties that are needed to compute the angle of Ka’abah.

ViewModel has the method that actually gets the values from Model’s properties (KaabaLocation, MyLocation) and determine the angle using the formula stated above.

View has got a page and a user control and this is the core of our article which will be discussed in more detail.

Class Diagram for Qibla Compass.

Note: The angle is calculated in radians and we need to convert it to degrees to point it to the correct direction.

Anatomy of a Compass in Windows Phone 8

The compass, or magnetometer, sensor can be used to determine the angle by which the device is rotated relative to the Earth’s magnetic north pole. Your app should always check to see whether the sensor is allowed from the capability sections or fail gracefully if it is not.

The compass sensor in a device can become inaccurate over time, especially if it is exposed to magnetic fields. So all you have to do is just a simple action (sweeping the device in a figure 8 pattern) to calibrate it. The calibrate event is fired whenever system detects the heading accuracy is greater than +/- 20 degrees.

Below is the snippet of helper function QiblaDirection (View and a main page for this app) that registers the calibration event along with other events which are discussed below:

`private void GetQibla(){             compass = new Compass();            compass.Calibrate += compass_Calibrate;            compass.CurrentValueChanged += compass_CurrentValueChanged;            compass.TimeBetweenUpdates = TimeSpan.FromMilliseconds(20);            compass.Start();}`

We have got the StackPanel on the main page (QiblaDirection.xaml) that would only be visible if compass needs to be calibrated - at which point a user can follow the instructions on the control to accomplish it.

`<!--Calibration UI-->        <StackPanel Visibility="Collapsed" Name="calibrationStackPanel" Grid.Row="1" Background="{x:Null}" Opacity="1">            <Image Source="/Assets/Images/calibrate_compass.png" Opacity=".95" HorizontalAlignment="Center"/>            <TextBlock TextWrapping="Wrap" TextAlignment="Center">The compass on your device needs to be calibrated.  Hold the device in front of you and sweep it through a figure 8 pattern as shown  until the calibration is complete.</TextBlock>            <StackPanel Orientation="Horizontal" Margin="0,10" HorizontalAlignment="Center">                <TextBlock>heading accuracy:</TextBlock>                <TextBlock Name="calibrationTextBlock">0.0°</TextBlock>            </StackPanel>            <Button Name="calibrationButton" Content="Done" Click="calibrationDone_Click"></Button>        </StackPanel>        <!--End Calibration UI-->`

Once the calibration is done, compass_CurrentValueChanged (discussed below) is fired depending upon the reporting frequency (compass.TimeBetweenUpdates).

Calibration Popup for Qibla Compass.

Along with calibration StackPanel, we have got two important controls that are requisites for showing you the correct direction:

• Compass Rose (Image control that contains the image of compass with cardinal directions)
`<Image VerticalAlignment="Top" HorizontalAlignment="Center" Width="Auto" Height="400"  Name="CompassFace" Grid.Row="1" Source="/Assets/Images/compassrose-mp.png" Stretch="Uniform" />`
• QiblaControl (UserControl with an ellipse and needle like image Control that points to the Qibla Direction with respect to the location and formula discussed above)
`<QC:QiblaControl x:Name="QiblaControl" Grid.Row="1"  HorizontalAlignment="Center" RenderTransformOrigin="0.5,0.5" VerticalAlignment="Top">                <QC:QiblaControl.RenderTransform>                    <RotateTransform Angle="0"/>                </QC:QiblaControl.RenderTransform>            </QC:QiblaControl>`
• UserControl's (QiblaControl) implementation
`<UserControl x:Class="QiblaCompass.View.QiblaControl"    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"    mc:Ignorable="d"    FontFamily="{StaticResource PhoneFontFamilyNormal}"    FontSize="{StaticResource PhoneFontSizeNormal}"    Foreground="{StaticResource PhoneForegroundBrush}"   Height="395.146"             Width="395.146">     <Grid x:Name="LayoutRoot">        <Ellipse HorizontalAlignment="Left"                 Height="392"                 Stroke="White"                 StrokeThickness="1"                 VerticalAlignment="Top"                 Width="392" />        <Image Margin="0,3,0,184" Source="/Assets/Images/kaaba-mp.png" />     </Grid></UserControl>`

Let’s have a look at compass_CurrentValueChange method which contains the main logic to rotate and display the correct direction of Qibla.

`void compass_CurrentValueChanged(object sender, SensorReadingEventArgs<CompassReading> e){      try      {                if (compass.IsDataValid)                {                    Dispatcher.BeginInvoke(() =>                         {                            // To check the calibration's reading.                            double headingAccuracy = e.SensorReading.HeadingAccuracy;                             if (!calibratingFlag)                            {                                double trueHeading = e.SensorReading.TrueHeading;                                double qiblaDegrees = _viewModel.GetQiblaAngleInDegrees();                                RotateTransform roseTransform = new RotateTransform() { Angle = 360 - trueHeading };                                RotateTransform qiblaTransform = new RotateTransform() { Angle = roseTransform.Angle + qiblaDegrees };                                 // Assigning the respective values to rose and qibla transform controls.                                CompassFace.RenderTransformOrigin = new Point(0.5, 0.5);                                QiblaControl.RenderTransformOrigin = new Point(0.5, 0.5);                                CompassFace.RenderTransform = roseTransform;                                QiblaControl.RenderTransform = qiblaTransform;                              }                            else                            {                                // For Calibration StackPanel.                                if (headingAccuracy <= 10)                                {                                    calibrationTextBlock.Foreground = new SolidColorBrush(Colors.Green);                                    calibrationTextBlock.Text = "Complete!";                                }                                else                                {                                    calibrationTextBlock.Foreground = new SolidColorBrush(Colors.Red);                                    calibrationTextBlock.Text = headingAccuracy.ToString("0.0");                                }                            }                        });                }          }          catch (Exception ex)          {                MessageBox.Show(ex.Message, "Error!", MessageBoxButton.OK);          }}`

Every time the current value of a compass gets changed, this function gets fired and reads the heading accuracy of a compass. If the accuracy is less than 10 then it doesn't do anything and let the code flow otherwise the calibrate event gets fired which set the value of calibrationFlag with respect to the heading accuracy.

If the calibrationFlag is false, it gets the trueHeading and the angle using the same formula I discussed above (in case of dynamic location, you can pass your geo coordinates here and modify the ViewModel’s function).

In the next few lines of above discussed code, we are calculating the angle for compass rose and QiblaControl and setting up the QiblaControl’s origin (using new Point(0.5,0.5) to the center of compass rose so the results can be displayed accurately). Now, you may deploy the app and locate Qibla on your phone.

So that’s about it. You can see how easy is to develop the Qibla Control which can be useful for your prayer times and other relevant applications.

Special Thanks

I would like to thank Nokia UAE team for their splendid efforts, support and care towards their developers in this region, without them I wouldn't have learnt anything I wrote above. Nokia truly deserves a big applause!