【问题标题】:How to rotate a Direction Arrow to particular location如何将方向箭头旋转到特定位置
【发布时间】:2011-11-02 16:30:25
【问题描述】:

在我的应用程序中,我有 1 个固定位置的经纬度。现在使用 iPhone 设备的用户可以在任何地方移动,即使他旋转他的设备,箭头(一些 uiimageview)应该指向那个固定位置,这样用户每次都会得到指向那个位置的方向。我尝试如下。

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

CLLocationCoordinate2D here =  newLocation.coordinate;
[self calculateUserAngle:here];
}


-(void) calculateUserAngle:(CLLocationCoordinate2D)user {
    NSLog(@"my destination is %f ; %f", fixlocLat, fixlocLon);
    degrees =  degrees + atan2(sin(fixlocLon-user.longitude)*cos(fixlocLat),cos(user.latitude)*sin(fixlocLat) - sin(user.latitude)*cos(fixlocLat)*cos(fixlocLon-user.longitude));
//get angle between user location and fix location
}

- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading 
{
    arrow.transform = CGAffineTransformMakeRotation((degrees-newHeading.trueHeading) * M_PI / 180);
}

但上面的代码总是将箭头旋转到大约。每个位置都向北 2-3 度。

我的问题看起来类似于this Stack Overflow question.但是使用此链接中的代码我得到了错误的方向。 请帮帮我。

如果有任何使用加速度计或陀螺仪数据的想法对我有帮助。

提前感谢。

【问题讨论】:

  • 位置有多远?如果很远,可能需要great circle distance 计算。
  • 我们如何在 xcode(objective c) 中使用大圆距离计算,距离可以远至大约。 1000 公里。
  • 距离是可变的,它会随着用户移动而更新,但范围在 0 到 1000 公里左右。
  • 确定这确实是您遇到的问题,大圆只是角度不准确的原因之一。除了这件事,我看到你没有实现设备方向。使用“if ([CLLocationManager headingAvailable]) [locationsManager startUpdatingHeading];”从指南针获取航向(方位角)更新,并实现委托方法 didUpdateHeading,它为您提供设备的最新航向。使用 heading.trueHeading 或 Magnetic 获取设备面向的方向,并在您的 calculateUserAngle 中使用生成的角度。
  • 在这里查看可能的答案:*.com/questions/7298193/…

标签: iphone objective-c xcode cllocationmanager compass-geolocation


【解决方案1】:

这对我有用:将方向箭头旋转到特定位置

-(void)viewDidLoad
{
    [super viewDidLoad]; 

    locationManager = [[CLLocationManager alloc] init];
    locationManager.delegate = self; 
    locationManager.desiredAccuracy = kCLLocationAccuracyBest; 
    locationManager.distanceFilter = kCLDistanceFilterNone;

}

-(void) calculateUserAngle:(CLLocationCoordinate2D)current {
    double x = 0, y = 0 , deg = 0,delLon = 0;

    delLon = fixLon - current.longitude;    
    y = sin(delLon) * cos(fixLat);
    x = cos(current.latitude) * sin(fixLat) - sin(current.latitude) * cos(fixLat) * cos(delLon);    
    deg = RADIANS_TO_DEGREES(atan2(y, x));    

    if(deg<0){      
        deg = -deg;
    } else {
        deg = 360 - deg;
    }    
    degrees = deg;
}


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

     CLLocationCoordinate2D here =  newLocation.coordinate;
     [self calculateUserAngle:here];
}


- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading 
{
    arrow.transform = CGAffineTransformMakeRotation((degrees-newHeading.trueHeading) * M_PI / 180);
}

【讨论】:

  • 我最近实现了这个,但是当箭头直接指向它应该指向的相反方向时偶尔会遇到问题。这就像箭头是镜像的。您对为什么会发生这种情况有任何想法吗?
  • 什么是“fixLon”和“fixLat”?在您的代码中找不到任何定义或声明
  • @chiragshah 这些是您希望箭头指向的固定位置的坐标
【解决方案2】:

这段代码可以帮助你

-(void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading {
    // Use the true heading if it is valid. 
    CLLocationDirection direction = newHeading.magneticHeading;
    CGFloat radians = -direction / 180.0 * M_PI;

    self.strAccuracy = [NSString stringWithFormat:@"%.1fmi",newHeading.headingAccuracy];    
    [lblAccuracy setText:self.strAccuracy];

    //Rotate Bearing View
    [self rotateBearingView:bearingView radians:radians];

    //For Rotate Niddle
    CGFloat angle = RadiansToDegrees(radians);  
    [self setLatLonForDistanceAndAngle];
    [self rotateArrowView:arrowView degrees:(angle + fltAngle)];
}

-(void)rotateArrowView:(UIView *)view degrees:(CGFloat)degrees
{
    CGAffineTransform transform = CGAffineTransformMakeRotation(DegreesToRadians(degrees));
    view.transform = transform;
}

-(void)setLatLonForDistanceAndAngle
{
    dblLat1 = DegreesToRadians(appDelegate.dblLatitude);
    dblLon1 = DegreesToRadians(appDelegate.dblLongitude);

    dblLat2 = DegreesToRadians(objClsProductSearch.dblLatitude);
    dblLon2 = DegreesToRadians(objClsProductSearch.dblLongitude);

    fltLat = dblLat2 - dblLat1;
    fltLon = dblLon2 - dblLon1;
}

-(float)getAngleFromLatLon
{
    //Calculate angle between two points taken from http://www.movable-type.co.uk/scripts    /latlong.html
    double y = sin(fltLon) * cos(dblLat2);
    double x = cos(dblLat1) * sin(dblLat2) - sin(dblLat1) * cos(dblLat2) * cos(dblLon2);
    CGFloat angle = RadiansToDegrees(atan2(y, x));
    return angle;
}

【讨论】:

  • 感谢您的回答和 1 个查询;这个方法怎么样 - [self rotateBearingView:bearingView radians:radians];这个方法是什么?
  • 我刚刚在产品位置方向旋转了一张速度计类型的图像
  • 你在哪里使用 getAngleFromLatLon ??
  • 我有四个不同的位置,它不属于东北条件
  • 这里什么是 fltAngle,dblLat1,dblLon1,dblLat2,dblLon2,fltLat,fltLon 以及如何声明?您还创建了 getAngleFromLatLon 方法,但尚未在代码中调用。
【解决方案3】:
-(void)viewDidLoad
{
  locationManager = [[CLLocationManager alloc] init];
  locationManager.delegate = self;
  locationManager.desiredAccuracy = kCLLocationAccuracyBest;
  locationManager.distanceFilter = kCLDistanceFilterNone;
  [locationManager startUpdatingLocation];
  [locationManager startUpdatingHeading];
}
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
  GeoAngle = [self setLatLonForDistanceAndAngle:newLocation];
}

-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
   CLLocation *location=[locations lastObject];
   GeoAngle = [self setLatLonForDistanceAndAngle:location];
}
-(float)setLatLonForDistanceAndAngle:(CLLocation *)userlocation
{
   float lat1 = DegreesToRadians(userlocation.coordinate.latitude);
   float lon1 = DegreesToRadians(userlocation.coordinate.longitude);

   float lat2 = DegreesToRadians(Destination lattitude);
   float lon2 = DegreesToRadians(Destination Longitude);

   float dLon = lon2 - lon1;

   float y = sin(dLon) * cos(lat2);
   float x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon);
   float radiansBearing = atan2(y, x);
   if(radiansBearing < 0.0)
   {
      radiansBearing += 2*M_PI;
   }
   return radiansBearing;
}

-(void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
{
   float direction = -newHeading.trueHeading;
   arrow.transform=CGAffineTransformMakeRotation((direction* M_PI / 180)+ GeoAngle);
}

【讨论】:

  • 也许添加一个描述它做了什么以及 OP 哪里出错了?
  • 试试这个对你有帮助。
  • 这(对 iOS 8 进行了一些更新)对我来说非常有用!谢谢。
  • ShigaSuresh 你能解释一下这里的 GeoAngle 是什么吗?
【解决方案4】:

试试这个例子。它在 C# Xamarin 中 :) “双标题”是 CLLocationManager.UpdatedHeading 中事件对象的 CLHeading.MagneticHeading。

void UpdateCompass(Location origin, Location target, double heading)
{
    var angle1 = GetAngleBetweenPoints(origin, target);
    var angle2 = GetAngleFromHeading(heading);
    var radian = Math.PI * (angle1 + angle2) / 180.0;
    CompassArrow.Transform = CGAffineTransform.MakeRotation((nfloat)radian);
}

double GetAngleBetweenPoints(Location origin, Location target)
{
    var n = 270 - (Math.Atan2(origin.Latitude - target.Latitude, origin.Longitude - target.Longitude)) * 180 / Math.PI;
    return n % 360;
}

double GetAngleFromHeading(double heading)
{
    var radians = -heading / 180.0 * Math.PI;
    return radians * (180.0 / Math.PI);
}

【讨论】: