3

Objective C で記述された iPhone アプリケーションがあり、ユーザーが画面に描画してパスを作成するタッチ ポイントを収集しています。

このデータを薄くできるようにしたい。ポイントの角度が特定のしきい値を超えているかどうかを確認することで、これを行うことを目指している方法の 1 つです。たとえば、a、b、c と呼ばれる線上の任意の 3 つの隣接する点を取得する場合、角度 ABC が 180 度から 5 度以内であれば、線にあまり影響を与えずに点 b を削除できます。

三角形ABCを2つの直角三角形に分割することでこれを達成しようとしています。次に acosf() を使用して、a での角度 (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;

何か案は?

4

3 に答える 3

7

acos(x)andの古典的な問題acosf(x)は、引数が範囲内にあることを保証することです。

さまざまな FP の問題により、計算された値が -1 <= x <= 1 の範囲外になることxがあります。数学x的には範囲内かもしれませんが、丸め/精度は のような値になることがあります1.0000001。その値x(小数点以下8桁まで) では、acosf(x)NaN ですか?

x別の方法は、アレンジの外にあるかどうかをテストし、それを持ち込むことです。

if (x > 1.0) {
  x = 1.0;
}
else if (x < -1.0) {
  x = -1.0;
}
angle = acos(x);

さらに: acosf()180 度 [0 から pi] の範囲のみを提供します。タスクには、 を使用することをお勧めしますatan2f()。それは答えの完全な「輪」を提供します。

于 2013-10-17T21:15:06.970 に答える
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)))
于 2013-10-17T18:45:13.140 に答える
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];
    }
于 2013-10-19T13:48:18.227 に答える