時計回りにポイントの配列を並べ替える


16

2Dポイントの配列を時計回りに並べ替えるアルゴリズムはありますか?
私の場合は特に直角三角形を扱っているので、3ポイントだけです。

しかし、そのようなアルゴリズムが存在するかどうかを知りたいのですが、そうでない場合は、三角形の3点を時計回りに返す簡単な方法は何ですか?

編集:私は、凸であるポリゴンの重心に対して時計回りにポイントを計算しようとしています。

更新: これは、選択した回答に基づいて最終的に使用した実装です。パフォーマンスは重要ではなく、たまにしか発生しないため、うまくいきます。

ArrayList<PVector> pointList = new ArrayList<PVector>();
pointList.add(A);
pointList.add(B);
pointList.add(C);
Collections.sort( pointList, new TriangleVectorComparator(origin) );

return pointList;

// Comparator
package triangleeditor;

import java.util.Comparator;

import processing.core.PVector;

public class TriangleVectorComparator implements Comparator<PVector>  {
    private PVector M; 
    public TriangleVectorComparator(PVector origin) {
        M = origin;
    }

    public int compare(PVector o1, PVector o2) {
        double angle1 = Math.atan2(o1.y - M.y, o1.x - M.x);
        double angle2 = Math.atan2(o2.y - M.y, o2.x - M.x);

        //For counter-clockwise, just reverse the signs of the return values
        if(angle1 < angle2) return 1;
        else if (angle2 < angle1) return -1;
        return 0;
    }

}

1
returnはreturn angle1 <angle2にできますか?1:angle2> angle1?-1:0;
ademar111190 14

2
それは多くの方法で表現することができますが、私は特に例を挙げるときにネストされた三項演算子を避ける傾向があります。
onedayitwillmake

@onedayitwillmake使用したコードを答えに移動できますか?それは本当に問題に属していませんが、将来の読者にとって非常に貴重です。
アンコ

@Ankoあなたは正しいと思いますが、同時にこの方法で見つけるのは人々にとって最も簡単だと思います。また、私が単純に基づいているsamhocevarの答えを取り去らないようにするのにも役立ちます。
onedayitは

回答:


19

あなたの質問は十分に正確ではありません。ポイントの配列は、参照ポイントに対して「時計回り」または「反時計回り」のみです。それ以外の場合、3点の配列は常にCWまたはCCWのいずれかになります。次の図を参照してください。左側では、ポイントは時計回りに並べられています。右側では、まったく同じポイントが反時計回りに並べられています。

時計回りまたは反時計回り

あなたの場合、基準点としてポイントの重心を使用するのが妥当だと思います。

未知の数のポイントに対する適切な方法は次のとおりです。

  • P[0], P[1], ... P[n-1]並べ替えるポイントのリストにしましょう
  • Mをすべての点の重心とする
  • a[0], a[1], ... a[n-1]そのような計算a[i] = atan2(P[i].y - M.y, P[i].x - M.x);
  • たとえば、a値を基準にしてポイントを並べ替えqsortます。

ただし、アドホック方式と比較して、3つの入力値では適切なソートアルゴリズムのパフォーマンスが低下することは確実です。を使用することatan2はまだ有効ですが、使用しないでくださいqsort


これは完全に機能しました:)
onedayitwillmake

1
このメソッドには名前がありますか?
onedayitは、

1
これは単に「極角による並べ替え」と呼ばれるものだと思います。たとえば、Graham Scanのコンポーネントです。
サムホセバー

ここでのパフォーマンスヒットは、にqsort比べてわずかatan2です。

小さな警告:これは潜在的にクラッシュ&ポイントのいずれかが正確であることを起こる場合(使用するプログラミング言語やライブラリに依存する)燃焼する時に重心(または方向の他のどんなポイント使用)。2番目と3番目のステップの間にそのようなポイントを除外することもできます。
マーティンソイカ

3

ここで実際に質問しているのは、三角形の巻き順であり、実際にテストするのは非常に簡単だと思います。

三角形には3つのポイントしかないので、三角形は既に時計回りまたは反時計回りの順序になっています。そのため、必要なのはこれらの2つのうちのどちらかを確認し、ワインディングが逆の場合はインデックスの順序を逆にすることですあなたが望むものではありません。

三角形の3つの頂点がab、およびcであり、単純なベクトル減算演算があると仮定した場合の一般的な考え方は次のとおりです。

Vector2 AToB = b - a;
Vector2 BToC = c - b;
float crossz = AToB.x * BToC.y - AToB.y * BToC.x;
if ( crossz > 0.0f )
{
  // clockwise
}
else
{
  // counter-clockwise.  Need to reverse the order of our vertices.
}

+ y軸の方向(上または下)に応じて、「時計回り」と「反時計回り」のケースは、このサンプルコードのコメントでラベルを付けた場合と逆になる場合があることに注意してください。


ポリゴンを作成するには、これらのポイントをBox2D(java実装)に渡す必要があります。それは私が求めていたものではありませんが、非常に良い洞察:)
onedayitwillmake

2

詳細を教えてください。ポイントのCCW順序が必要ですが、順序の中心となるポイントはどれですか?

平面に三角形(3点)しかない場合、行列から行列式を計算できます。ここで、線は点の座標です(3番目の座標は1)。行列式が0より大きい場合、ポイントはCCW順です。そうでない場合は、例えば最後の2ポイントを急ぐことができ、CCWの注文を受け取ります。

ポイントA、B、Cがある場合、マトリックスは次のようになります。

|xA, yA, 1|
|xB, yB, 1|
|xC, yC, 1|

決定要因は、xA * yB + xB * yC + xC * yA-yB * xC-yC * xA-yA * xBです。次に、それをゼロと比較できます。> 0の場合、ポイントA、B、Cを返し、そうでない場合、A、C、Bを返します。

点のセットを知っていて、それらが凸多角形を作り(すべて凸包の一部である)、それらの順序を取得したい場合、Graham ScanまたはJarvis's Marchを使用できます(これらは多くの点から凸包を見つけるためのアルゴリズムですが、ここでも動作するはずです:))


特定のポイントを中心に時計回りにポイントを並べ替えるだけの場合、zacharmarzが言ったことを完了するには、フロートとポイントのペアから配列を作成し、その特定のポイントからの対応する角度ですべてのポイントを保存し、並べ替えることができますその配列。
Ali1S232
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.