iPhone 指南针 GPS 方向

发布于 2024-09-29 20:59:13 字数 1401 浏览 10 评论 0原文

我正在尝试开发一个使用 iPhone 的 GPS 和指南针的应用程序,以便将某种指针指向特定位置(就像指南针始终指向北方)。位置是固定的,无论用户位于何处,我始终需要指针指向该特定位置。我有这个位置的纬度/经度坐标,但不确定如何使用指南针和 GPS 指向该位置...就像 http://www.youtube.com/watch?v=iC0Xn8hY80w 此链接 1:20'

我写了一些代码,但是,它无法向右旋转。

-(float) angleToRadians:(double) a {
    return ((a/180)*M_PI);
}

-(void)updateArrow {    
    double alon=[longi doubleValue];//source
    double alat=[lati doubleValue];//source
    double blon=[pointlongi doubleValue];//destination
    double blat=[pointlati doubleValue];//destination

    float fLat = [self angleToRadians:alat];
    float fLng = [self angleToRadians:alon];
    float tLat = [self angleToRadians:blat];
    float tLng = [self angleToRadians:blon];

    float temp = atan2(sin(tLng-fLng)*cos(tLat), 
        cos(fLat)*sin(tLat)-sin(fLat)*cos(tLat)*cos(tLng-fLng)); 
    double temp2= previousHeading;

    double temp1=temp-[self angleToRadians:temp2];

    /*I using this,but it can't rotate by :point even i change the coordinate
      in CGPointMake */
    Compass2.layer.anchorPoint=CGPointMake(0, 0.5);

    [Compass2 setTransform:CGAffineTransformMakeRotation(temp1)];
    /* Compass2 is a UIImageView like below picture I want to rotate it around 
     : point in image

        ^
        |
        | 
        |
        :
        |
    */

I'm trying to develop an application that use the GPS and Compass of the iPhone in order to point some sort of pointer to a specific location (like the compass always point to the North). The location is fixed and I always need the pointer to point to that specific location no matter where the user is located. I have the Lat/Long coordinates of this location but not sure how can I point to that location using the Compass and the GPS... just like http://www.youtube.com/watch?v=iC0Xn8hY80w this link 1:20'

I write some code, however, it can't rotate right direction.

-(float) angleToRadians:(double) a {
    return ((a/180)*M_PI);
}

-(void)updateArrow {    
    double alon=[longi doubleValue];//source
    double alat=[lati doubleValue];//source
    double blon=[pointlongi doubleValue];//destination
    double blat=[pointlati doubleValue];//destination

    float fLat = [self angleToRadians:alat];
    float fLng = [self angleToRadians:alon];
    float tLat = [self angleToRadians:blat];
    float tLng = [self angleToRadians:blon];

    float temp = atan2(sin(tLng-fLng)*cos(tLat), 
        cos(fLat)*sin(tLat)-sin(fLat)*cos(tLat)*cos(tLng-fLng)); 
    double temp2= previousHeading;

    double temp1=temp-[self angleToRadians:temp2];

    /*I using this,but it can't rotate by :point even i change the coordinate
      in CGPointMake */
    Compass2.layer.anchorPoint=CGPointMake(0, 0.5);

    [Compass2 setTransform:CGAffineTransformMakeRotation(temp1)];
    /* Compass2 is a UIImageView like below picture I want to rotate it around 
     : point in image

        ^
        |
        | 
        |
        :
        |
    */

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

狂之美人 2024-10-06 20:59:13

您可以使用一个标准的“航向”或“方位角”方程 - 如果您位于 lat1,lon1,并且您感兴趣的点位于 lat2,lon2,则方程为:

heading = atan2( sin(lon2-lon1)*cos(lat2), cos(lat1)*sin(lat2) - sin(lat1)*cos(lat2)*cos(lon2-lon1))

这为您提供了以弧度为单位的方位角,您可以通过乘以 180/π 将其转换为度数。该值介于 -180 和 180 度之间,因此要获得标准罗盘方位,请将 360 添加到任何否定答案。

atan2 是与 arctan 相关的标准函数,它对您的目的地点可能位于的四个可能的象限与您所在的位置进行比较,执行正确的操作。

There is a standard "heading" or "bearing" equation that you can use - if you are at lat1,lon1, and the point you are interested in is at lat2,lon2, then the equation is:

heading = atan2( sin(lon2-lon1)*cos(lat2), cos(lat1)*sin(lat2) - sin(lat1)*cos(lat2)*cos(lon2-lon1))

This gives you a bearing in radians, which you can convert to degrees by multiplying by 180/π. The value is then between -180 and 180 degrees, so to get a standard compass bearing add 360 to any negative answers.

atan2 is a standard function related to arctan, that does the right thing for the four possible quadrants that your destination point could be in compared to where you are.

云巢 2024-10-06 20:59:13

1) 获取您当前的位置(从 GPS)

2) 获取纬度和经度的差异

3) 使用 atan2 方法获取角度,

即(警告:未经测试的代码)

CLLocation *targetLocation = [CLLocation alloc] initWithLatitude:1 longitude:2];
CLLocation *sourceLocation = <get from GPS>

double dx = [targetLocation coordinate].latitude - [sourceLocation coordinate].latitude;
double dy = [targetLocation coordinate].longitude - [sourceLocation coordinate].longitude;

double angle = atan2(dx, dy);

您可能需要对其进行调整才能编译,但想法就在那里!

1) Get your current location (from the GPS)

2) Get the differences in latitude and longitude

3) use the atan2 method to get the angle

i.e. (WARNING: untested code)

CLLocation *targetLocation = [CLLocation alloc] initWithLatitude:1 longitude:2];
CLLocation *sourceLocation = <get from GPS>

double dx = [targetLocation coordinate].latitude - [sourceLocation coordinate].latitude;
double dy = [targetLocation coordinate].longitude - [sourceLocation coordinate].longitude;

double angle = atan2(dx, dy);

You might have to tweak that to get it to compile but the idea is there!

风筝有风,海豚有海 2024-10-06 20:59:13

我前段时间这样做过,这里有两种不同的实现。第一个与您的方法类似,第二个没有三角数学。第一个是我在应用程序中使用的,但第二个似乎也可以工作,尽管看起来不那么干净。您还需要记住根据用户界面中的北向来偏移此方位角。

- (double) toRadian: (double) val
{
    return val * (M_PI / 180);
}

// Convert to degrees from radians
- (double) toDegrees: (double) val
{
    return val * 180 / M_PI;
}

// convert from a radian to a 360 degree format.
- (double) toBearing: (double) val
{
    return ( (int)([self toDegrees: val]) + 360 ) % 360;        // use mod to get the degrees
}

// Calculate the bearing based off of the passed coordinates and destination.  
//
- (double) calcBearingWithLatitude:(CLLocationDegrees)latSource 
                             latitude:(CLLocationDegrees)latDest 
                            longitude:(CLLocationDegrees)lonSrc 
                            longitude:(CLLocationDegrees)lonDest
{
    double lat1 = [self toRadian:latSource];
    double lat2 = [self toRadian:latDest];
    double dLon = [self toRadian:(lonDest - lonSrc)];

    double y = sin(dLon) * cos(lat2);
    double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon);
    return [self toBearing:atan2(y, x)];
}

还有第二个。

// got this code from some forums and modified it, thanks for posting it coullis!  Mostly here for reference on how to do this without sin and cos.
- (CLLocationDegrees) altCalcBearingWithLatitude:(CLLocationDegrees)latSource 
                                        latitude:(CLLocationDegrees)latDest 
                                       longitude:(CLLocationDegrees)lonSrc 
                                       longitude:(CLLocationDegrees)lonDest

{
    CLLocationDegrees result;


// First You calculate Delta distances.
float dx = lonSrc - latSource;
float dy = lonDest - latDest;

// If x part is 0 we could get into division by zero problems, but in that case result can only be 90 or 270:
if (dx==0)
{
    if (dy > 0)
        result = 90;
    else
        result = 270;
}
else
{
    result = [self toDegrees: atan(dy/dx)];
}

// This is only valid for two quadrants (for right side of the coordinate system) so modify result if necessary...
if (dx < 0) 
    result = result + 180;

// looks better if all numbers are positive (0 to 360 range)
if (result < 0)
    result = result + 360;

// return our result.
return result;

}

I did this some time ago, here are two different implementations. The first is similar to your approach, the second is without the trig math. The first is what I used in my app, but the second seemed to work as well, though doesn't appear to be as clean. You will need to also remember to offset this bearing based on north in your UI.

- (double) toRadian: (double) val
{
    return val * (M_PI / 180);
}

// Convert to degrees from radians
- (double) toDegrees: (double) val
{
    return val * 180 / M_PI;
}

// convert from a radian to a 360 degree format.
- (double) toBearing: (double) val
{
    return ( (int)([self toDegrees: val]) + 360 ) % 360;        // use mod to get the degrees
}

// Calculate the bearing based off of the passed coordinates and destination.  
//
- (double) calcBearingWithLatitude:(CLLocationDegrees)latSource 
                             latitude:(CLLocationDegrees)latDest 
                            longitude:(CLLocationDegrees)lonSrc 
                            longitude:(CLLocationDegrees)lonDest
{
    double lat1 = [self toRadian:latSource];
    double lat2 = [self toRadian:latDest];
    double dLon = [self toRadian:(lonDest - lonSrc)];

    double y = sin(dLon) * cos(lat2);
    double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dLon);
    return [self toBearing:atan2(y, x)];
}

And the second.

// got this code from some forums and modified it, thanks for posting it coullis!  Mostly here for reference on how to do this without sin and cos.
- (CLLocationDegrees) altCalcBearingWithLatitude:(CLLocationDegrees)latSource 
                                        latitude:(CLLocationDegrees)latDest 
                                       longitude:(CLLocationDegrees)lonSrc 
                                       longitude:(CLLocationDegrees)lonDest

{
    CLLocationDegrees result;


// First You calculate Delta distances.
float dx = lonSrc - latSource;
float dy = lonDest - latDest;

// If x part is 0 we could get into division by zero problems, but in that case result can only be 90 or 270:
if (dx==0)
{
    if (dy > 0)
        result = 90;
    else
        result = 270;
}
else
{
    result = [self toDegrees: atan(dy/dx)];
}

// This is only valid for two quadrants (for right side of the coordinate system) so modify result if necessary...
if (dx < 0) 
    result = result + 180;

// looks better if all numbers are positive (0 to 360 range)
if (result < 0)
    result = result + 360;

// return our result.
return result;

}

暖风昔人 2024-10-06 20:59:13

用这个。您必须从 getHeadingForDirection 的结果中减去实际的罗盘航向,以确定正确的相对航向。返回值以弧度为单位。

-(float) angleToRadians:(float) a {
    return ((a/180)*M_PI);
}


- (float) getHeadingForDirectionFromCoordinate:(CLLocationCoordinate2D)fromLoc toCoordinate:(CLLocationCoordinate2D)toLoc
{

    float fLat = [self angleToRadians:fromLoc.latitude];
    float fLng = [self angleToRadians:fromLoc.longitude];
    float tLat = [self angleToRadians:toLoc.latitude];
    float tLng = [self angleToRadians:toLoc.longitude];

    return atan2(sin(tLng-fLng)*cos(tLat), cos(fLat)*sin(tLat)-sin(fLat)*cos(tLat)*cos(tLng-fLng));         
}

Use this. You will have to subtract out your actual compass heading from the result of getHeadingForDirection to determine the proper relative heading. Return value is heading in radians.

-(float) angleToRadians:(float) a {
    return ((a/180)*M_PI);
}


- (float) getHeadingForDirectionFromCoordinate:(CLLocationCoordinate2D)fromLoc toCoordinate:(CLLocationCoordinate2D)toLoc
{

    float fLat = [self angleToRadians:fromLoc.latitude];
    float fLng = [self angleToRadians:fromLoc.longitude];
    float tLat = [self angleToRadians:toLoc.latitude];
    float tLng = [self angleToRadians:toLoc.longitude];

    return atan2(sin(tLng-fLng)*cos(tLat), cos(fLat)*sin(tLat)-sin(fLat)*cos(tLat)*cos(tLng-fLng));         
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文