Nokta dizisini saat yönünde sıralama


16

2D nokta dizisini saat yönünde sıralamak için böyle bir algoritma var mı?
Özellikle üçgene doğru üçgeni ele alıyorum.

Ancak böyle bir algoritmanın var olup olmadığını bilmekle ilgileniyorum, eğer değilse üçgemin 3 noktasını saat yönünde döndürmenin basit bir yolu nedir?

Düzenleme: Ben dışbükey olan çokgen centroid göre saat yönünde noktaları hesaplamak için çalışıyorum.

Güncelleme: Bu, seçilen cevaba dayanarak kullandığım uygulama, performans açısından kritik değil ve sadece arada bir gerçekleşiyor, bu yüzden işe yarıyor.

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
dönüş dönüş açısı1 <açı2? 1: angle2> angle1? -1: 0;
ademar111190

2
Birçok şekilde ifade edilebilir, ancak özellikle örnekler verirken iç içe üçlü operatörlerden kaçınma eğilimindeyim.
onedayitwillmake

@onedayitwillmake Sonlandırdığınız kodu bir cevaba taşıyabilir misiniz? Soruna gerçekten ait değil, ancak gelecekteki okuyucular için çok değerli.
Anko

@Anko haklı olduğunu düşünüyorum, ama aynı zamanda insanların bu şekilde bulmasının en kolay yol olacağını düşünüyorum. Ayrıca samhocevar'ın benimkinin dayandığı cevabından uzak durmamaya yardımcı olur.
onedayitwillmake

Yanıtlar:


19

Sorunuz yeterince kesin değil. Bir nokta dizisi bir referans noktasına göre yalnızca «saat yönünde» veya «saat yönünün tersine» dir. Aksi takdirde, üç noktadan oluşan herhangi bir dizi her zaman CW veya CCW olabilir. Aşağıdaki resme bakın: solda, noktalar saat yönünde sıralanır; sağda, aynı noktalar saat yönünün tersine sıralanır.

saat yönünde veya saat yönünün tersine

Sizin durumunuzda, noktaların merkez merkezini referans noktası olarak kullanmanın makul olduğuna inanıyorum.

Bilinmeyen sayıda nokta için iyi bir yöntem aşağıdaki olabilir:

  • P[0], P[1], ... P[n-1]sıralamak için puan listesi olsun
  • M tüm noktaların barmenliği olsun
  • hesaplamak a[0], a[1], ... a[n-1]şekildedira[i] = atan2(P[i].y - M.y, P[i].x - M.x);
  • noktaları akullanarak qsortörneğin değerlerine göre sıralar.

Ancak, iyi bir sıralama algoritmasının geçici bir yönteme kıyasla üç giriş değeri ile kötü performans göstereceğinden emin olabilirsiniz. Kullanmak atan2hala geçerlidir, ancak kullanmayın qsort.


Bu mükemmel çalıştı :)
onedayitwillmake

1
Bu yöntemin bir adı var mı?
onedayitwillmake

1
Buna “kutup açısına göre sıralama” denildiğine inanıyorum. Örneğin , Graham Tarama'nın bir bileşenidir .
sam hocevar

Buradaki performans isabetiyle qsortkarşılaştırıldığında küçük atan2.

Küçük uyarı: Bu, potansiyel olarak çökmesine ve noktalardan herhangi aynen olmak olur (kullanılan programlama dili ve kütüphaneleri bağlı olarak) yanacak de ağırlık merkezinin (veya yönelim diğer türlü nokta kullanın). İkinci ve üçüncü adım arasındaki bu tür noktaları hariç tutmak isteyebilirsiniz.
Martin Sojka

3

Burada gerçekten sorduğunuz şeyin, üçgenin sınama sırası olduğuna inanıyorum, ki bu aslında test edilmesi oldukça basit.

Üçgeninizde sadece üç nokta olduğundan, üçgeniniz zaten saat yönünde veya saat yönünün tersine sıradadır ve bu nedenle yapmanız gereken tek şey bu ikisinden hangisinin olduğunu kontrol etmek ve sargı varsa endekslerin sırasını tersine çevirmektir. istediğin kişi değil.

Üçgenin üç köşesinin a , b ve c olduğunu ve basit bir vektör çıkarma işlemine sahip olduğunuzu varsayarak genel fikir şu şekildedir :

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 ekseninizi (yukarı veya aşağı) hangi yöne yönlendirdiğinize bağlı olarak, "saat yönünde" ve "saat yönünün tersine" durumların bunları bu örnek koddaki yorumlarda nasıl etiketlediğimden geri alınabileceğini unutmayın.


Bir çokgen oluşturmak için bu noktaları Box2D (java uygulama) geçmek gerekir. istediğim şey olmasa da, çok iyi bir fikir :)
onedayitwillmake

2

Daha fazla bilgi verebilir misiniz? CCW puan sırası istersiniz, ancak hangi nokta sipariş merkezi olmalıdır?

Düzlemde sadece üçgen (3 puan) varsa, çizgilerin noktaların koordinatları olduğu (3. koordinat 1'dir) matristen determinant hesaplayabilirsiniz. Determinant> 0 ise, noktalar CCW düzenindedir. Değilse, örneğin son iki noktayı değiştirebilir ve CCW siparişi alırsınız.

A, B, C puanlarınız varsa, matrisiniz şöyle görünür:

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

Determinant: xA * yB + xB * yC + xC * yA - yB * xC - yC * xA - yA * xB. Sonra sıfır ile karşılaştırabilirsiniz. > 0 ise, A, B, C noktalarını döndürün, değilse A, C, B'ye dönün.

Eğer puan kümeniz varsa ve biliyorsanız, dışbükey çokgen yaparlar (hepsi dışbükey gövdenin bir parçasıdır) ve siparişlerini almak isterler, Graham Scan veya Jarvis'in Mart'ını kullanabilirsiniz (bunlar birçok noktadan dışbükey gövdeyi bulmak için algoritmalardır, ancak burada da çalışmalı :))


noktalarınızı belirli bir nokta etrafında saat yönünde sıralamak istiyorsanız zacharmarz'ın söylediklerini tamamlamak için, kayan nokta çiftlerinden bir dizi oluşturabilir ve tüm noktaları bu noktadan karşılık gelen açısı ile sakladığınız noktadan sonra sıralayabilirsiniz. o dizi.
Ali1S232
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.