从三点获得角度和象限

时间:2011-09-01 16:00:27

标签: objective-c c math trigonometry

鉴于:

  • 指向clickWheelCenter
  • 指向startPoint(第一次触摸)
  • 点(实际触摸)

我想确定这三点之间的角度,我想知道,在哪个象限中找到最后一次触摸。
角度的计算效果很好,而象限总是1或2,从不3或4。

我哪里错了?

CGFloat DistanceBetweenTwoPoints(CGPoint point1,CGPoint point2)
{
    CGFloat dx = point2.x - point1.x;
    CGFloat dy = point2.y - point1.y;
    return sqrt(dx*dx + dy*dy );
};

NSInteger GetQuadrant(double angle)
{
    double sinAngle = sin(angle);
    double cosAngle = cos(angle);
    double tanAngle = tan(angle);
    double cotAngle = 1.0/tanAngle;

    NSLog(@"%f %f %f %f", sinAngle, cosAngle, tanAngle, cosAngle);

    if(sinAngle > 0 && cosAngle > 0 && tanAngle > 0 && cotAngle > 0) return 1;
    if(sinAngle > 0 && cosAngle < 0 && tanAngle < 0 && cotAngle < 0) return 2;
    if(sinAngle < 0 && cosAngle < 0 && tanAngle > 0 && cotAngle > 0) return 3;
    if(sinAngle < 0 && cosAngle > 0 && tanAngle < 0 && cotAngle < 0) return 4;
    return 0;
}

double AngleBetweenThreePoints(CGPoint point1,CGPoint point2, CGPoint point3)
{
    CGPoint point_a = point1;
    CGPoint point_b = point2;
    CGPoint point_c = point3;
    CGFloat a, b, c;

    a = DistanceBetweenTwoPoints(point_b, point_c);
    b = DistanceBetweenTwoPoints(point_a, point_c);
    c = DistanceBetweenTwoPoints(point_a, point_b);
    double result = acos((b*b+c*c-a*a)/(2*b*c));

    NSLog(@"%d", GetQuadrant(result));

    return result/M_PI * 180.0;
}


-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    startPoint = [[touches anyObject] locationInView:self];
}

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    CGPoint point = [[touches anyObject] locationInView:self];
    double angle = AngleBetweenThreePoints(self.clickWheelCenter, startPoint, point);
    NSLog(@"%f", angle);    
}

5 个答案:

答案 0 :(得分:4)

这一切都可以轻松完成。

{x1,y1} =第一个点 - 中心点,{x2,y2} =第三个点 - 中心点,有符号角度( - pi,+ pi)由下式给出:

atan2(x2*y1 - x1*y2,x1*x2 + y1*y2)

根据您对角度符号的定义,您可能想要或不想在前面添加减号。

您可以轻松地从符号和绝对大小派生象限。

  1. size&lt; = pi / 2,sign +
  2. 尺寸&gt; pi / 2,签名+
  3. 尺寸&gt; pi / 2,sign -
  4. 尺寸&lt; = pi / 2,签署 -

答案 1 :(得分:3)

正如其他人所提到的那样,你所做的事情的内角总是小于180度。我假设您想要从一个矢量到另一个矢量的逆时针角度测量的象限。

获得此象限的一种简单方法是使用点积和perp点积并检查每个结果的符号。

这是因为点积等于| A | * | B | * cos(theta)其中||表示幅度,theta是A和B之间的角度。由于幅度总是正的,通过检查结果的符号,您实际上是在检查cos(theta)的符号。

Perp点积实际上是| A | * | B | * sin(theta)所以通过检查perp点的符号,你实际上是在检查sin(theta)的符号。

让我们说我们测量theta为从A到B的逆时针角度。象限也用θ测量。我们可以通过以下

计算点和perpdot

首先,您需要获取向量A和B. A和B将是从clickWheelCenter到startpoint的向量,从clickWheelCenter到您称为'point'的向量

dot = A.x * B.x + A.y * B.y

perpdot = A.x * B.y - A.y * B.x

然后检查标志,注意下表。

quadrant  dot         perpdot
1         positive    positive
2         negative    positive
3         positive    negative
4         negative    negative

同样,通过检查点积的符号,您实际上是在检查cos(theta)的符号,并通过检查perpdot来检查sin(theta)的符号。您只需要一组if语句进行比较,如果这些语句是&gt; 0或&lt; 0

(注意:我上面写的很快,并没有很好地检查一切准确性,但一般的想法是正确的)

BBitmaster

答案 2 :(得分:1)

因为余弦定律只会返回180度或更小的内角。我不太确定你在这里尝试做什么,但这种方法在四分法方面没有意义。此外,您需要错误检查这是否是生产级代码。当你的三角形退化时,余弦定律会爆炸。

答案 3 :(得分:1)

似乎你的函数AngleBetweenThreePoints只返回0和Pi之间的角度,然后传递给它。

你的问题是acos不是一对一的功能。对于任何给定的输入,有多个值,因此没有任何进一步的知识,它将只选择给定范围内的一个。一个简单的例子是270degrees和90degrees都有cos等于0.所以如果你acos(0)那么它显然只能返回两个中的一个。

我有点不清楚你在哪个象限意味着什么。通常你可以通过查看x和y坐标的符号来判断并使用它来计算你的象限。观察两条线之间的角度将为象限(相对于第一条线的象限)提供一个奇怪的值 - 这是你想要的吗?

答案 4 :(得分:1)

您正在计算始终小于180度的内角。 这是计算直角值的快速而正确的方法:

double AngleBetweenThreePoints(CGPoint pointA, CGPoint pointB, CGPoint pointC)
{
    CGFloat a = pointB.x - pointA.x;
    CGFloat b = pointB.y - pointA.y;
    CGFloat c = pointB.x - pointC.x;
    CGFloat d = pointB.y - pointC.y;

    CGFloat atanA = atan2(a, b);
    CGFloat atanB = atan2(c, d);

    return atanB - atanA;
}