1天学习1个类库 磁场方向 CLHeading 示例

先看效果和图:



代码中引用了github下载的代码.主要引用了其中的

headingInDegrees方法.可以将2点的坐标计算出相对角度

地址:https://github.com/progrmr/SDK_Utilities


UtilitiesGeo.h

/*
 *  UtilitiesGeo.h
 *
 *  Created by Gary Morris on 3/6/11.
 *  Copyright 2011 Gary A. Morris. All rights reserved.
 *
 * This file is part of SDK_Utilities.repo
 *
 * This is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This file is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this file. If not, see <http://www.gnu.org/licenses/>.
 */

// distance conversion factors
#define MILES_TO_METERS_FACTOR (1609.344)	/* exact */
#define MILES_TO_FEET_FACTOR   (5280)		/* exact */

#define METERS_TO_MILES_FACTOR (1/MILES_TO_METERS_FACTOR)
#define METERS_TO_FEET_FACTOR  (3.2808399)

#define NM_TO_METERS_FACTOR    (1852)		/* exact */
#define NM_TO_FEET_FACTOR      (6076.11549)	/* approx */

// earth radius is for a spherical earth model
#define EARTH_RADIUS_METERS    (6372797.6)

#define SPEED_OF_LIGHT_MPS     (299792458)	/* exact */

// degrees/radians conversion macros
#define Deg_to_Rad(X) (X*M_PI/180.0) 
#define Rad_to_Deg(X) (X*180.0/M_PI)


/*-------------------------------------------------------------------------
 * Given two lat/lon points on earth, calculates the heading
 * from lat1/lon1 to lat2/lon2.  
 * 
 * lat/lon params in radians
 * result in radians
 *-------------------------------------------------------------------------*/
double headingInRadians(double lat1, double lon1, double lat2, double lon2);

/*-------------------------------------------------------------------------
 * Given two lat/lon points on earth, calculates the heading
 * from lat1/lon1 to lat2/lon2.  
 * 
 * lat/lon params in degrees
 * result in degrees
 *-------------------------------------------------------------------------*/
double headingInDegrees(double lat1, double lon1, double lat2, double lon2);

/*-------------------------------------------------------------------------
 * Given a starting lat/lon point on earth, distance (in meters)
 * and bearing, calculates destination coordinates lat2/lon2.
 *
 * all params in radians
 *-------------------------------------------------------------------------*/
void destCoordsInRadians(double lat1, double lon1, 
						 double distanceMeters, double bearing,
						 double* lat2, double* lon2);

/*-------------------------------------------------------------------------
 * Given a starting lat/lon point on earth, distance (in meters)
 * and bearing, calculates destination coordinates lat2/lon2.
 *
 * all params in degrees
 *-------------------------------------------------------------------------*/
void destCoordsInDegrees(double lat1, double lon1, 
						 double distanceMeters, double bearing,
						 double* lat2, double* lon2);


// Normalize a heading in degrees to be within -179.999999° to 180.00000°
double normalize180(double heading);
float normalize180f(float heading);

// Normalize a heading in degrees to be within 0° to 359.999999°
double normalize360(double heading);
float normalize360f(float heading);

UtilitiesGeo.c

/*
 *  UtilitiesGeo.h
 *
 *  Created by Gary Morris on 3/6/11.
 *  Copyright 2011 Gary A. Morris. All rights reserved.
 *
 * This file is part of SDK_Utilities.repo
 *
 * This is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This file is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this file. If not, see <http://www.gnu.org/licenses/>.
*/

#include "UtilitiesGeo.h"
#include <math.h>

/*-------------------------------------------------------------------------
 * Given a starting lat/lon point on earth, distance (in meters)
 * and bearing, calculates destination coordinates lat2/lon2.
 *
 * all params in radians
 *-------------------------------------------------------------------------*/
void destCoordsInRadians(double lat1, double lon1, 
						 double distanceMeters, double bearing,
						 double* lat2, double* lon2)
{
	//-------------------------------------------------------------------------
	// Algorithm from http://www.geomidpoint.com/destination/calculation.html
	// Algorithm also at http://www.movable-type.co.uk/scripts/latlong.html
	//
	// Spherical Earth Model
	//   1. Let radiusEarth = 6372.7976 km or radiusEarth=3959.8728 miles
    //   2. Convert distance to the distance in radians.
	//      dist = dist/radiusEarth
	//   3. Calculate the destination coordinates.
	//      lat2 = asin(sin(lat1)*cos(dist) + cos(lat1)*sin(dist)*cos(brg))
	//      lon2 = lon1 + atan2(sin(brg)*sin(dist)*cos(lat1), cos(dist)-sin(lat1)*sin(lat2))
	//-------------------------------------------------------------------------
	const double distRadians = distanceMeters / EARTH_RADIUS_METERS;
		
	*lat2 = asin( sin(lat1) * cos(distRadians) + cos(lat1) * sin(distRadians) * cos(bearing));
	
	*lon2 = lon1 + atan2( sin(bearing) * sin(distRadians) * cos(lat1), 
						  cos(distRadians) - sin(lat1) * sin(*lat2) );	
}

/*-------------------------------------------------------------------------
 * Given a starting lat/lon point on earth, distance (in meters)
 * and bearing, calculates destination coordinates lat2/lon2.
 *
 * all params in degrees
 *-------------------------------------------------------------------------*/
void destCoordsInDegrees(double lat1, double lon1, 
						 double distanceMeters, double bearing,
						 double* lat2, double* lon2)
{
	destCoordsInRadians(Deg_to_Rad(lat1), Deg_to_Rad(lon1),
						distanceMeters, Deg_to_Rad(bearing),
						lat2, lon2);
	
	*lat2 = Rad_to_Deg( *lat2 );
	*lon2 = normalize180( Rad_to_Deg( *lon2 ) );
}


/*-------------------------------------------------------------------------
 * Given two lat/lon points on earth, calculates the heading
 * from lat1/lon1 to lat2/lon2.  
 * 
 * lat/lon params in radians
 * result in radians
 *-------------------------------------------------------------------------*/
double headingInRadians(double lat1, double lon1, double lat2, double lon2)
{
	//-------------------------------------------------------------------------
	// Algorithm found at http://www.movable-type.co.uk/scripts/latlong.html
	//
	// Spherical Law of Cosines
	//
	// Formula: θ = atan2( 	sin(Δlon) * cos(lat2),
	//						cos(lat1) * sin(lat2) − sin(lat1) * cos(lat2) * cos(Δlon) )
	// 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 dLon = lon2 - lon1;
	double y = sin(dLon) * cos(lat2);
	double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon);

	return atan2(y, x);
}

/*-------------------------------------------------------------------------
 * Given two lat/lon points on earth, calculates the heading
 * from lat1/lon1 to lat2/lon2.  
 * 
 * lat/lon params in degrees
 * result in degrees
 *-------------------------------------------------------------------------*/
double headingInDegrees(double lat1, double lon1, double lat2, double lon2)
{
	return Rad_to_Deg( headingInRadians(Deg_to_Rad(lat1), 
										Deg_to_Rad(lon1), 
										Deg_to_Rad(lat2),
										Deg_to_Rad(lon2)) );
}

// Normalize a heading in degrees to be within -179.999999° to 180.00000°
double normalize180(double heading)
{
	while (1) {
		if (heading <= -180) {
			heading += 360;
		} else if (heading > 180) {
			heading -= 360;
		} else {
			return heading;
		}
	}
}

// Normalize a heading in degrees to be within -179.999999° to 180.00000°
float normalize180f(float heading)
{
	while (1) {
		if (heading <= -180) {
			heading += 360;
		} else if (heading > 180) {
			heading -= 360;
		} else {
			return heading;
		}
	}
}

// Normalize a heading in degrees to be within 0° to 359.999999°
double normalize360(double heading)
{
	while (1) {
		if (heading < 0) {
			heading += 360;
		} else if (heading >= 360) {
			heading -= 360;
		} else {
			return heading;
		}
	}
}

// Normalize a heading in degrees to be within 0° to 359.999999°
float normalize360f(float heading)
{
	while (1) {
		if (heading < 0) {
			heading += 360;
		} else if (heading >= 360) {
			heading -= 360;
		} else {
			return heading;
		}
	}
}


main.m

//
//  main.m
//  ControlDemo
//
//  Created by watsy0007 on 12-6-3.
//  Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
//

#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#import "UtilitiesGeo.h"

@interface CWUserLocation : NSObject <MKAnnotation>
@property (nonatomic) CLLocationCoordinate2D coord;
@end

@implementation CWUserLocation
@synthesize coord = _coord;

- (CLLocationCoordinate2D) coordinate {
    return _coord;
}

- (void) setCoordinate:(CLLocationCoordinate2D)newCoordinate {
    _coord = newCoordinate;
}

- (NSString *) title {
    return @"title";
}

- (NSString *) subtitle {
    return @"subtitle";
}

@end

@interface ViewController : UIViewController <MKMapViewDelegate,CLLocationManagerDelegate> {
    CLLocationManager   *_locMgr;
    
    UILabel     *_label;
    MKMapView   *_mapView;
}

@end


@implementation ViewController

- (void) dealloc {
    [_label release];
    [_mapView release];
    
    [super dealloc];
}

//随机生成1些标注位置  
- (NSArray *) randomAnnotation:(NSInteger) nMax {  
    random();  
    
    NSMutableArray *annotationArray = [NSMutableArray array];  
    for (int i = 0; i < nMax; i++) {  
        CWUserLocation *place = [[CWUserLocation alloc] init];  
        double dRandlatitude = (double)(rand() % 10000) / 1000000;  
        double dRandlongitude  = (double)(rand() % 10000) / 1000000;  
        BOOL bAdd = rand() % 2;  
        if (bAdd) {  
            dRandlatitude = -dRandlatitude;  
        }   
        bAdd = rand() % 2;  
        if (bAdd) {  
            dRandlongitude = -dRandlongitude;  
        }   
        
        [place setCoordinate:CLLocationCoordinate2DMake(22.551368 +  dRandlatitude, 113.882654 + dRandlongitude)];  
        [annotationArray addObject:place];  
        [place release];  
    }   
    return annotationArray;  
}  

- (void) updateAngle {
    NSArray *annoArray = [_mapView annotations];  
    CWUserLocation *place = [annoArray objectAtIndex:0];
    
    MKMapPoint pUser = MKMapPointForCoordinate(_mapView.userLocation.location.coordinate);
    MKMapPoint pMapPoint = MKMapPointForCoordinate(place.coordinate);
 
    if (MKMapPointEqualToPoint(pUser,pMapPoint)) {
        place = [annoArray objectAtIndex:1];
     }
    
    //计算出地图上2点的角度.正北为0度
    CGFloat fAngle = headingInDegrees(_mapView.userLocation.coordinate.latitude, _mapView.userLocation.coordinate.longitude,
                                      place.coordinate.latitude, place.coordinate.longitude);
//    NSLog(@"\n%lf|%lf - %lf|%lf\n %.1f \n%.1f %.1f %.1f",_mapView.userLocation.coordinate.latitude, _mapView.userLocation.coordinate.longitude,
//          place.coordinate.latitude, place.coordinate.longitude,fAngle,_locMgr.heading.magneticHeading,_locMgr.heading.trueHeading,_locMgr.heading.headingAccuracy);
    
    //减去磁北偏差角度.得到在地图上的正确角度.
    _label.transform = CGAffineTransformMakeRotation((fAngle - _locMgr.heading.magneticHeading) / 180.0 * M_PI);
}

- (void) randomAnno {
    [_mapView removeAnnotations:_mapView.annotations];
    [_mapView addAnnotations:[self randomAnnotation:1]];
    
    [self updateAngle];
}

- (void) loadView {
    [super loadView];
    
    [[self view] setBackgroundColor:[UIColor whiteColor]];
    
    UIBarButtonItem *barItem = [[UIBarButtonItem alloc] initWithTitle:@"随机" style:UIBarButtonItemStylePlain target:self action:@selector(randomAnno)];
    self.navigationItem.rightBarButtonItem = barItem;
    [barItem release];
    
    _mapView = [[MKMapView alloc] initWithFrame:self.view.bounds];
    [_mapView setShowsUserLocation:YES];
    [_mapView setDelegate:self];
    [self.view addSubview:_mapView];
    [self randomAnno];
    _mapView.userTrackingMode = MKUserTrackingModeFollowWithHeading;
    
    
    _label = [[UILabel alloc] init];
    _label.text = @"^";
    _label.textAlignment = UITextAlignmentCenter;
    _label.frame = self.view.bounds;
    [_label setBackgroundColor:[UIColor clearColor]];
    [self.view addSubview:_label];
    
    _locMgr = [[CLLocationManager alloc] init];
    _locMgr.delegate = self;
    
    if([CLLocationManager headingAvailable]) {
        [_locMgr startUpdatingHeading];
    }
    if ([CLLocationManager locationServicesEnabled]) {
        [_locMgr startUpdatingLocation];
    }

}

- (void) viewWillUnload {
    [_label release];
    
    [super viewWillUnload];
}

- (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation {
    return YES;
}

- (void) viewDidLoad {
    [super viewDidLoad];
}

#pragma mark -
#pragma mark cllocationmanager delegate

- (void) locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading {
    
    NSLog(@"\n地磁北极:%.0f\n真正北极:%.0f\n偏移%.0f\n记录时间:%@\nx:%.1f y:%.1f z:%.1f",
          newHeading.magneticHeading,
          newHeading.trueHeading,
          newHeading.headingAccuracy,
          newHeading.timestamp,
          newHeading.x,newHeading.y,newHeading.z);
}

#pragma mark -
#pragma mark 地图委托
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id <MKAnnotation>)annotation {  
    static NSString *sAnno = @"sAnnoString";  
    
    MKPinAnnotationView *annoView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:sAnno];  
    
    if (annoView == nil) {  
        if (annotation == mapView.userLocation) {  
            annoView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation 
                                                        reuseIdentifier:sAnno] autorelease];  
            
            annoView.pinColor = MKPinAnnotationColorGreen;
        } else {  
            annoView = [[[MKPinAnnotationView alloc] initWithAnnotation:annotation 
                                                        reuseIdentifier:sAnno] autorelease]; 
            
            annoView.pinColor = MKPinAnnotationColorRed;  
            
        }  
    }  
    
    return annoView;  
}  

//更新用户位置  
- (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation  {  
    //        NSLog(@"%@",@"didUpdateUserLocation");  
    [self  updateAngle];
} 

@end


//-----------------------------------------------------------------------------------------------------

#pragma mark -
#pragma mark AppDelegate
@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;
@property (strong, nonatomic) UIViewController *viewController;

@end

@implementation AppDelegate

@synthesize window = _window;
@synthesize viewController = _viewController;

- (void) dealloc {
    [_window release];
    [_viewController release];
    
    [super dealloc];
}

- (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    srand(time(NULL));
    
    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
    
    self.viewController = [[ViewController alloc] init];
    
    UINavigationController *controller = [[UINavigationController alloc] initWithRootViewController:self.viewController]; 
    self.window.rootViewController = controller;
    [controller release];
    
    [self.window makeKeyAndVisible];
    return YES;
}

@end

int main(int argc, char *argv[])
{
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值