IT tutorials
 
Mobile
 

Iphone Application : Implementing Location Services - Understanding the Magnetic Compass (part 2) - Requesting and Using Heading Updates

1/19/2013 4:51:06 PM
- How To Install Windows Server 2012 On VirtualBox
- How To Bypass Torrent Connection Blocking By Your ISP
- How To Install Actual Facebook App On Kindle Fire

Requesting and Using Heading Updates

Before asking for heading updates, we should check with the location manager to see whether heading updates are available via the class method headingAvailable. If heading updates aren’t available, the arrow images will never be shown, and the Cupertino application works just as before. If headingAvailable returns YES, set the heading filter to 10 degrees of precision and start the updates with startUpdatingHeading. Update the viewDidLoad method of the CupertinoViewController.m file, as shown in Listing 2.

Listing 2.
- (void)viewDidLoad {
    [super viewDidLoad];

    locMan = [[CLLocationManager alloc] init];
    locMan.delegate = self;
    locMan.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
    locMan.distanceFilter = 1609; // a mile
    [locMan startUpdatingLocation];
    if ([CLLocationManager headingAvailable]) {
      locMan.headingFilter = 10; // 10 degrees
      [locMan startUpdatingHeading];
    }
}

As previously mentioned, we now need to store the current location whenever we get an updated location from Core Location so that we can use the most recent location in the heading calculations. Add a line to set the recentLocation property we created to the newLocation in the locationManager:didUpdateLocation:fromLocation method and another to stop updating the heading if we are within 3 miles of the destination. The changes to the locationManager:didUpdateLocation:fromLocation method can be seen in Listing 3.

Listing 3.
- (void)locationManager:(CLLocationManager *)manager
    didUpdateToLocation:(CLLocation *)newLocation
           fromLocation:(CLLocation *)oldLocation {

    if (newLocation.horizontalAccuracy >= 0) {

         // Store the location for use during heading updates
        self.recentLocation = newLocation;

        CLLocation *Cupertino = [[[CLLocation alloc]
                                  initWithLatitude:kCupertinoLatitude
                                  longitude:kCupertinoLongitude] autorelease];
        CLLocationDistance delta = [Cupertino distanceFromLocation: newLocation];
        long miles = (delta * 0.000621371) + 0.5; // meters to rounded miles
        if (miles < 3) {
            // Turn off the location manager updates
            [manager stopUpdatingLocation];
            [manager stopUpdatingHeading];

            // Congratulate the user
            distanceLabel.text = @"Enjoy the\nMothership!";
        } else {
            NSNumberFormatter *commaDelimited = [[[NSNumberFormatter alloc]
                                                   init] autorelease];
            [commaDelimited setNumberStyle:NSNumberFormatterDecimalStyle];
            distanceLabel.text = [NSString stringWithFormat:
                                  @"%@ miles to the\nMothership",
                                  [commaDelimited stringFromNumber:
                                  [NSNumber numberWithLong:miles]]];
        }
        waitView.hidden = YES;
        distanceView.hidden = NO;
    }
}

					  

Calculate the Heading to Cupertino

In the previous two sections, we avoided doing calculations with latitude and longitude. This time, it requires just a bit of computation on our part to get a heading to Cupertino, and then to decide whether that heading is straight ahead or requires the user to spin to the right or to the left.

Given two locations such as the user’s current location and the location of Cupertino, it is possible to use some basic geometry of the sphere to calculate the initial heading the user would need to use to reach Cupertino. A search of the Internet quickly finds the formula in JavaScript (copied here in the comment), and from that, we can easily implement the algorithm in Objective-C and provide the heading.

First, add two constants to CupertinoViewController.m, following the latitude and longitude for Cupertino. Multiplying by these constants will allow us to easily convert from radians to degrees and vice versa:

#define deg2rad 0.0174532925
#define rad2deg 57.2957795

Next, add the headingToLocation:current method in the CupertinoViewController.m file as in Listing 4.

Listing 4.
/*
 * According to Movable Type Scripts
 * http://mathforum.org/library/drmath/view/55417.html
 *
 * Javascript:
 *
 * var y = Math.sin(dLon) * Math.cos(lat2);
 * var x = Math.cos(lat1)*Math.sin(lat2) -
 * Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
 * var brng = Math.atan2(y, x).toDeg();
*/
-(double)headingToLocation:(CLLocationCoordinate2D)desired
                  current:(CLLocationCoordinate2D)current {

    // Gather the variables needed by the heading algorithm
    double lat1 = current.latitude*deg2rad;
    double lat2 = desired.latitude*deg2rad;
    double lon1 = current.longitude;
    double lon2 = desired.longitude;
    double dlon = (lon2-lon1)*deg2rad;

    double y = sin(dlon)*cos(lat2);
    double x = cos(lat1)*sin(lat2) - sin(lat1)*cos(lat2)*cos(dlon);

    double heading=atan2(y,x);
    heading=heading*rad2deg;
    heading=heading+360.0;
    heading=fmod(heading,360.0);
    return heading;
}

					  

Handling Heading Updates

The CupertinoViewController class implements the CLLocationManagerDelegate protocol, and as you learned earlier, one of the optional methods of this protocol, locationManager:didUpdateHeading, provides heading updates anytime the heading changes by more degrees than the headingFilter amount.

For each heading update our delegate receives, use the user’s current location to calculate the heading to Cupertino, then compare the desired heading to the user’s current heading, and finally display the correct arrow image: left, right, or straight ahead.

For these heading calculations to be meaningful, we need to have the current location and some confidence in the accuracy of the reading of the user’s current heading. Check these two conditions in an if statement before performing the heading calculations. If this sanity check does not pass, just hide the directionArrow.

Because this heading feature is more of a novelty than a true source of directions (unless you happen to be a bird or in an airplane), there is no need to be overly precise. Use +/–10 degrees from the true heading to Cupertino as close enough to display the straight-ahead arrow. If the difference is greater than 10 degrees, display the left or right arrow based on whichever way would result in a shorter turn to get to the desired heading. Implement the locationManager:didUpdateHeading method in the CupertinoViewController.m file, as shown in Listing 5.

Listing 5.
- (void)locationManager:(CLLocationManager *)manager
       didUpdateHeading:(CLHeading *)newHeading {

    if (self.recentLocation != nil && newHeading.headingAccuracy >= 0) {
        CLLocation *cupertino = [[[CLLocation alloc]
                                   initWithLatitude:kCupertinoLatitude
                                   longitude:kCupertinoLongitude] autorelease];
        double course = [self headingToLocation:cupertino.coordinate
                                        current:recentLocation.coordinate];
        double delta = newHeading.trueHeading - course;
        if (abs(delta) <= 10) {
            directionArrow.image = [UIImage imageNamed:@"up_arrow.png"];
        } else {
            if (delta > 180) directionArrow.image =
                                    [UIImage imageNamed:@"right_arrow.png"];
            else if (delta > 0) directionArrow.image =
                [UIImage imageNamed:@"left_arrow.png"];
            else if (delta > -180) directionArrow.image =
                [UIImage imageNamed:@"right_arrow.png"];
            else directionArrow.image = [UIImage imageNamed:@"left_arrow.png"];
        }
        directionArrow.hidden = NO;
    } else {
        directionArrow.hidden = YES;
    }
}

					  

Build and run the project. If you have a device equipped with an electromagnetic compass, you can now spin around in your office chair and see the arrow images change to show you the heading to Cupertino. If you run the updated Cupertino application in the iPhone Simulator, you will have an arrow pointing to the right as a result of the simulator’s one simulated heading update (see Figure 2).

Figure 2. The completed Cupertino application running in the iPhone Simulator.

 
Others
 
- Iphone Application : Implementing Location Services - Understanding the Magnetic Compass (part 1)
- IPad : Arranging Apps Using iTunes, Finding Good Apps
- Arranging Apps on Your iPad
- Mobile Web Development with WordPress, Joomla!, and Drupal : WEB AND MOBILE WEB EVOLUTION
- Mobile Web Development with WordPress, Joomla!, and Drupal : HOW DEVICES ARE CHANGING
- Windows Phone 8 : XAML Overview - Visual Grammar
- Windows Phone 8 : XAML Overview - Visual Containers
- iPhone SDK 3 : Objective-C and Cocoa - Classes
- iPhone SDK 3 : Creating Interfaces
- IPad : Your Calendar - Manage Your Busy Life on Your iPad
 
25 Inspiring Game of Thrones Quotes
 
Top 10
 
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 2) - Wireframes,Legends
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 1) - Swimlanes
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Formatting and sizing lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Adding shapes to lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Sizing containers
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 3) - The Other Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 2) - The Data Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 1) - The Format Properties of a Control
- Microsoft Access 2010 : Form Properties and Why Should You Use Them - Working with the Properties Window
- Microsoft Visio 2013 : Using the Organization Chart Wizard with new data
programming4us programming4us
 
Popular tags
 
Video Tutorail Microsoft Access Microsoft Excel Microsoft OneNote Microsoft PowerPoint Microsoft Project Microsoft Visio Microsoft Word Active Directory Biztalk Exchange Server Microsoft LynC Server Microsoft Dynamic Sharepoint Sql Server Windows Server 2008 Windows Server 2012 Windows 7 Windows 8 Adobe Indesign Adobe Flash Professional Dreamweaver Adobe Illustrator Adobe After Effects Adobe Photoshop Adobe Fireworks Adobe Flash Catalyst Corel Painter X CorelDRAW X5 CorelDraw 10 QuarkXPress 8 windows Phone 7 windows Phone 8 BlackBerry Android Ipad Iphone iOS