使用3个CGPoint找出角度

3
在我的应用程序中,用户轻触三次,就会由被轻触的三个点创建一个角度。它可以完美地绘制出这个角度。我试图计算第二次轻触时的角度,但我认为我做错了(可能是数学错误)。我还没有在我的微积分课上涵盖到这个问题,所以我正在根据维基百科上的公式进行计算。

http://en.wikipedia.org/wiki/Law_of_cosines

我正在尝试的是:

注意:First、Second和Third是由用户点击创建的CGPoints

        CGFloat xDistA = (second.x - third.x);
        CGFloat yDistA = (second.y - third.y);
        CGFloat a = sqrt((xDistA * xDistA) + (yDistA * yDistA));

        CGFloat xDistB = (first.x - third.x);
        CGFloat yDistB = (first.y - third.y);
        CGFloat b = sqrt((xDistB * xDistB) + (yDistB * yDistB));

        CGFloat xDistC = (second.x - first.x);
        CGFloat yDistC = (second.y - first.y);
        CGFloat c = sqrt((xDistC * xDistC) + (yDistC * yDistC));

        CGFloat angle = acos(((a*a)+(b*b)-(c*c))/((2*(a)*(b))));

        NSLog(@"FULL ANGLE IS: %f, ANGLE IS: %.2f",angle, angle);

有时,它会给出角度为1,这对我来说没有意义。有人可以解释一下为什么会这样,或者如何修复它吗?

1
你的公式给出了第三个点的角度。 - Martin R
@MartinR:我需要修改什么才能让它成为第二个点? - Josue Espinosa
CGFloat angle = acos(((a*a)+(c*c)-(b*b))/((2*(a)*(c)))); - Tyler
5个回答

14

不确定这是否是主要问题,但这是一个问题。

你的答案给出的角度是错误的:

enter image description here

要获得绿色角度(根据你的变量名“first”,“second”和“third”),请使用:

CGFloat angle = acos(((a*a)+(c*c)-(b*b))/((2*(a)*(c))));


1
谢谢!非常有用的图表!不知道世界将如何没有懂数学的人。 - Josue Espinosa
我添加了这段代码以避免零除:CGFloat angle = 0.0; CGFloat numerator = ((a*a)+(c*c)-(b*b)) ; if (numerator != 0 ) { angle = acos( numerator / ((2*(a)*(c))) ); } - Pedro Trujillo

5

以下是一种规避余弦定理的方法,它计算两个向量的角度。两个角度之间的差值即为所求的值:

CGVector vec1 = { first.x - second.x, first.y - second.y };
CGVector vec2 = { third.x - second.x, third.y - second.y };

CGFloat theta1 = atan2f(vec1.dy, vec1.dx);
CGFloat theta2 = atan2f(vec2.dy, vec2.dx);

CGFloat angle = theta1 - theta2;
NSLog(@"angle: %.1f°, ", angle / M_PI * 180);

请注意atan2函数,它将x和y分量作为单独的参数接受,从而避免了0/90/180/270°的歧义。

@MartinR 使用CGSize来表示距离是Cocoa的一个长期惯例。不过,我可能需要一些时间才能找到参考资料。我确信在苹果的代码中见过它。 - Nikolai Ruhe
谢谢Nikolai,这个答案非常有帮助!它确实有效,但每次都会返回一个负数,并且会变得大于180(超过180后需要变小),所以我会坚持选择我选的答案,但稍微调整一下也可以奏效! - Josue Espinosa
@Josue,你可以使用 if(angle < 0) angle += 360 来进行归一化。 - ilya n.
直到现在我才意识到CGVector,但它确实在CGGeometry.h中定义。 - Martin R
2
@NikolaiRuhe;确实,这仅适用于iOS 7:https://developer.apple.com/library/ios/documentation/graphicsimaging/reference/CGGeometry/Reference/reference.html - ilya n.
显示剩余5条评论

1
我所做的方式是分别使用atan2(y,x)计算两个角度,然后使用此函数。
static inline double
AngleDiff(const double Angle1, const double Angle2)
{
    double diff = 0;
    diff = fabs(Angle1 - Angle2);
    if (diff > <Pi>) {
        diff = (<2Pi>) - diff;
    }
    return diff;
}

该函数使用弧度制计算,但你可以将<Pi>替换为180,将<2Pi>替换为360。

1
余弦公式的实现看起来正确;您是否考虑到acos()返回的角度是弧度制而不是角度制?为了转换为角度,需要将角度乘以180并除以Pi(3.14159...)。

当我画一个90度的角度时,它返回45度?((angle*180)/3.14); - Josue Espinosa
看起来是错误的点。您现在正在计算第三个点的角度(因为c是第二个-第一个); 您想要哪一个? - Seva Alekseyev

0

使用此答案来计算向量的角度:

CGFloat angleForVector(CGFloat dx, CGFloat dy) {
    return atan2(dx, -dy) * 180.0/M_PI;
}

// Compute angle at point Corner, that is between AC and BC:

CGFloat angle = angleForVector(A.x - Corner.x, A.y - Corner.y)
              - angleForVector(B.x - Corner.x, B.y - Corner.y);

NSLog(@"FULL ANGLE IS: %f, ANGLE IS: %.2f",angle, angle);

这或多或少是 Nikolai 在他的回答中建议的。 - Martin R
嗯,是的,我写了十多分钟 :) - ilya n.
注意 @ilyan,atan2函数的参数顺序是y先,然后是x(即 atan2(y, x))。但在这种情况下,由于我们只关心两个角度之间的差异,因此顺序无关紧要。 - Nikolai Ruhe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接