我有一个用Objective C编写的iPhone应用程序,我收集用户在屏幕上绘制的触摸点以创建路径。
我希望能够细化这些数据。我通过检查点的角度是否超过某个阈值来实现此目的的方法之一。例如,如果我在a,b,c这一行上取任意三个相邻点,如果角度ABC在180度的5度范围内,那么我可以移除点b而不会过多地影响线。
我试图通过将三角形ABC分成两个直角三角形来实现这一目标。然后我使用acosf()来找到(BAC)处的角度和c处的角度(BCA)。然后,我可以从180减去这两个角度,找到ABC的角度。
我的问题是acosf()经常返回NaN。当它返回一个数字时,我在计算器上检查它并且值是正确的。我已经尝试过返回NaN的价值观,他们也不会在计算器上工作。我知道这是因为它们超出了acosf()的范围。我怎么能避免这个?
以下是我使用的代码:
float prevToNextDist = ccpDistance(prevPoint.location, nextPoint.location);
//work out the next point angle
float pointToNextDistance = ccpDistance(point.location, nextPoint.location);
float nextPointAngle = acosf((prevToNextDist/2)/pointToNextDistance);
nextPointAngle = CC_RADIANS_TO_DEGREES(nextPointAngle);
//work out the previous point angle
float prevToPointDistance = ccpDistance(prevPoint.location, point.location);
float prevPointAngle = acosf((prevToNextDist/2)/prevToPointDistance);
prevPointAngle = CC_RADIANS_TO_DEGREES(prevPointAngle);
//work out the point angle
float pointAngle = 180 - nextPointAngle - prevPointAngle;
有什么想法吗?
答案 0 :(得分:5)
acos(x)
和acosf(x)
的典型问题是确保参数在范围内。
由于各种FP问题,有时计算出的x
仅超出范围-1< = x< = 1。数学x
可能在范围内,但舍入/精度有时会出现1.0000001
之类的值。当x
是NaN时,acosf(x)
(到 8 小数步幅)的价值是多少?
if (x > 1.0) {
x = 1.0;
}
else if (x < -1.0) {
x = -1.0;
}
angle = acos(x);
此外:acosf()
仅提供180度[0到pi]的范围。对于您的任务,您可能希望使用atan2f()
。它提供了一个完整的“圈子”答案。
答案 1 :(得分:1)
1 / float不是默认的浮点类型,它是double。 float可能足以存储,即使这样你也应该用double进行计算。
2 /没有cppDistance的代码,很难确定,但我不认为它会像你想象的那样计算三角形的一面(我认为没有3点就不可能作为参数)。
3 /如果您的点是(xa,ya),(0,0)和(xb,yb)并且您正在寻找(0,0)处的角度(如果不是这样,只需更改坐标是这样的,你正在寻找的角度是
acos((xa*xb+ya*yb)/sqrt((xa*xa+ya*ya)*(xb*xb+yb*yb)))
答案 2 :(得分:0)
好的,我已经解决了这个问题,因此我发布的解决方案适用于任何可能偶然发现并发现它有用的人。虽然,我正在使用我自己的解决方案,chux和AProgrammers的建议都是合理的,并帮助我提出了解决方案,所以我对它们进行了投票。
正如chux所说,atan2()是更好的功能,而不是acosf()。这是基于角度精简点数据的代码:
#define kAngleTolerance 3
double prevPointAngle = atan2(point.location.y - prevPoint.location.y, point.location.x - prevPoint.location.x) * 180.0f / M_PI;
prevPointAngle = fabs(prevPointAngle);
double nextPointAngle = atan2(nextPoint.location.y - point.location.y, nextPoint.location.x - point.location.x) * 180.0f / M_PI;
nextPointAngle = fabs(nextPointAngle);
double pointAngle = 180 - fabs(nextPointAngle - prevPointAngle);
if (pointAngle < 180 + kAngleTolerance && pointAngle > 180 - kAngleTolerance ) {
point.remove = YES;
[pointsToRemove addObject:point];
}