2

Point が、点 p0、p1、および p2 で定義される 2 次ベジエ曲線の一部であるかどうかを確認したい..

これは、特定の t を持つ曲線内のポイントを取得するための私の関数です。

public static final Point quadratic (Point p0, Point p1, Point p2, double t) {
    double x = Math.pow(1-t, 2) * p0.x + 2 * (1-t) * t * p1.x + Math.pow(t, 2) * p2.x;
    double y = Math.pow(1-t, 2) * p0.y + 2 * (1-t) * t * p1.y + Math.pow(t, 2) * p2.y;

    return new Point((int)x, (int)y);
}

二次曲線の点 B(t) が次のように得られるとします。

B(t) = (1 - t)^2 * p0 + 2 * t * (1 - t) * p1 + t^2 * p2

その点の t 値を取得し、その t パラメータを使用して取得した Point と比較することにより、点 P が曲線に属しているかどうかを確認する必要がありますが、Java では変数の精度に問題があります。

ポイントを確認するための私の機能は次のとおりです。

public static final boolean belongsQuadratic (Point p, Point p0, Point p1, Point p2) {
    double[] tx = obtainTs(p.x, p0, p1, p2);
    double[] ty = obtainTs(p.y, p0, p1, p2);

    if (tx[0] >= 0) {
        if ((tx[0] >= ty[0] - ERROR && tx[0] <= ty[0] + ERROR) || (tx[0] >= ty[1] - ERROR && tx[0] <= ty[1] + ERROR)) {
            return true;
        }
    }

    if (tx[1] >= 0) {
        if ((tx[1] >= ty[0] - ERROR && tx[1] <= ty[0] + ERROR) || (tx[1] >= ty[1] - ERROR && tx[1] <= ty[1] + ERROR)) {
            return true;
        }
}


    return false;
}

public static double[] obtainTs (int comp, Point p0, Point p1, Point p2) {
    double a = p0.x - 2*p1.x + p2.x;
    double b = 2*p1.x - 2*p0.x ;
    double c = p0.x - comp;

    double t1 = (-b + Math.sqrt(b*b - 4*a*c)) / (2*a);
    double t2 = (-b - Math.sqrt(b*b - 4*a*c)) / (2*a);

    return new double[] {t1, t2};
}

したがって、この値でコードを実行すると:

Point p0 = new Point(320, 480);
Point p1 = new Point(320, 240);
Point p2 = new Point(0, 240);
double t = 0.10f;
Point p = Bezier.quadratic(p0, p1, p2, t);
double[] ts = Bezier.obtainTs(p.x, p0, p1, p2);

次の出力が得られます。

For t=0.10000000149011612, java.awt.Point[x=316,y=434]
For t1: -0.1118033988749895, java.awt.Point[x=316,y=536]
For t2: 0.1118033988749895, java.awt.Point[x=316,y=429]
java.awt.Point[x=316,y=434] belongs?: false

BigDecimal操作を実行するために使用する必要がありますか? これを確認する別の方法はありますか?ありがとう

4

2 に答える 2

1

ここにエラーがあります:

double[] ty = obtainTs(p.y, p0, p1, p2);

p0、p1、p2 の x 座標を使用して、p の y 座標の t パラメータを見つけるobtainTs()ためです

メソッドのパラメーターをint(ポイントの x 座標または y 座標にすることができます) に変更すると、次のようになります。

public static double[] obtainTs (int comp, int p0, int p1, int p2) {
    double a = p0 - 2*p1 + p2;
    double b = 2*p1 - 2*p0 ;
    double c = p0 - comp;

    double t1 = (-b + Math.sqrt(b*b - 4*a*c)) / (2*a);
    double t2 = (-b - Math.sqrt(b*b - 4*a*c)) / (2*a);

    return new double[] {t1, t2};
}

そしてそれを呼び出します

double[] tx = obtainTs(p.x, p0.x, p1.x, p2.x);
double[] ty = obtainTs(p.y, p0.y, p1.y, p2.y);

その後、テスト コードは「true」を返します (ERROR = 0.02 でテスト)。


方程式を書き留める場合、

B(t) = (1 - t)^2 * p0 + 2 * t * (1 - t) * p1 + t^2 * p2

x 座標と y 座標の両方について、t^2 項を削除して、t の単一の線形方程式を得ることができます。これにより、次の方法が得られます。これは、少し単純で、平方根を使用しない場合があります。

public static final boolean belongsQuadratic2 (Point p, Point p0, Point p1, Point p2) {
    double ax = p0.x - 2*p1.x + p2.x;
    double bx = 2*p1.x - 2*p0.x ;
    double cx = p0.x - p.x;

    double ay = p0.y - 2*p1.y + p2.y;
    double by = 2*p1.y - 2*p0.y ;
    double cy = p0.y - p.y;

    // "Candidate" for t:
    double t = -(cx*ay - cy*ax)/(bx*ay - by*ax);
    if (t < 0 || t > 1)
        return false;
    // Compute the point corresponding to this candidate value ...
    Point q = Bezier.quadratic(p0, p1, p2, t);
    // ... and check if it is near the given point p:
    return Math.abs(q.x - p.x) <= 1 && Math.abs(q.y - p.y) <= 1;
}

もちろん、 などの特殊なケースをチェックする必要がありbx*ay - by*ax == 0ます。

ポイント座標は整数に丸められるため、ポイントが曲線上にあるかどうかを正確に判断するのは難しいことにも注意してください。

于 2013-06-15T16:04:32.423 に答える