Ordinamento di array di punti in senso orario


16

Esiste un tale algoritmo per ordinare una matrice di punti 2D in ordine orario?
Ho a che fare con il triangolo destro nel mio caso, quindi solo 3 punti.

Tuttavia sono interessato a sapere se esiste un tale algoritmo, se non quale è un modo semplice per restituire i 3 punti del mio triangolo in senso orario?

Modifica: sto provando a calcolare i punti in senso orario rispetto al centroide del poligono, che è convesso.

Aggiornamento: questa è l'implementazione che ho finito usando sulla base della risposta scelta, non è critica per le prestazioni e succede solo una volta ogni tanto, quindi funziona.

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
il ritorno può essere angolo di ritorno1 <angolo2? 1: angolo2> angolo1? -1: 0;
ademar111190,

2
Può essere espresso in molti modi, ma tendo ad evitare operatori ternari nidificati, specialmente quando si danno esempi.
onedayitwillmake,

@onedayitwillmake Potresti spostare il codice che hai utilizzato in una risposta? Non appartiene davvero alla domanda, ma è molto prezioso per i futuri lettori.
Anko,

@Anko Penso che tu abbia ragione, ma allo stesso tempo penso che sarà più facile per le persone trovarlo in questo modo. Aiuta anche ad assicurarmi di non togliermi dalla risposta di Samhocevar su cui si basa semplicemente la mia.
onedayitwillmake

Risposte:


19

La tua domanda non è abbastanza precisa. Una matrice di punti è solo «in senso orario» o «in senso antiorario» rispetto a un punto di riferimento. Altrimenti, qualsiasi array di tre punti può sempre essere CW o CCW. Vedere la seguente immagine: a sinistra, i punti sono ordinati in senso orario; a destra, gli stessi punti esatti sono ordinati in senso antiorario.

in senso orario o antiorario

Nel tuo caso, credo che usare il baricentro dei punti come punto di riferimento sia ragionevole.

Un buon metodo per un numero sconosciuto di punti potrebbe essere il seguente:

  • lascia che P[0], P[1], ... P[n-1]sia l'elenco dei punti da ordinare
  • lascia che M sia il baricentro di tutti i punti
  • calcolare a[0], a[1], ... a[n-1]tale chea[i] = atan2(P[i].y - M.y, P[i].x - M.x);
  • ordina i punti in relazione al loro avalore, usando qsortad esempio.

Tuttavia, puoi essere sicuro che un buon algoritmo di ordinamento funzionerà male con tre valori di input rispetto a un metodo ad hoc. L'uso atan2è ancora valido, ma semplicemente non lo usa qsort.



1
Questo metodo ha un nome?
onedayitwillmake il

1
Credo che questo sia semplicemente chiamato «ordinamento per angolo polare». È un componente di Graham Scan , ad esempio.
sam hocevar,

Il successo prestazionale di qsortqui è minuscolo rispetto a atan2.

Piccolo avvertimento: questo potrebbe potenzialmente arrestarsi e bruciarsi (a seconda del linguaggio di programmazione e delle librerie utilizzate) se uno dei punti si trova esattamente nel baricentro (o qualunque altro punto di orientamento che usi). Potresti voler escludere tali punti tra il secondo e il terzo passaggio.
Martin Sojka,

3

Credo che ciò di cui stai effettivamente chiedendo qui sia l'ordine di avvolgimento del triangolo, che in realtà è piuttosto semplice da testare.

Dato che ci sono solo tre punti nel tuo triangolo, il tuo triangolo è già in un ordine in senso orario o antiorario, e quindi tutto ciò che devi fare è controllare quale di quei due è e invertire l'ordine degli indici se l'avvolgimento non è quello che vuoi.

Ecco l'idea generale, supponendo che i tre vertici di un triangolo siano a , b e c e che si abbia una semplice operazione di sottrazione vettoriale:

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.
}

Nota che a seconda del modo in cui hai orientato il tuo asse + y (su o giù), i casi "in senso orario" e "in senso antiorario" possono essere invertiti rispetto a come li ho etichettati nei commenti in questo codice di esempio.


Devo passare questi punti a Box2D (implementazione Java) per creare un poligono. anche se non è quello che stavo chiedendo, ottima intuizione :)
onedayitwillmake il

2

Puoi dare maggiori informazioni? Volete l'ordine dei punti CCW, ma quale punto dovrebbe essere al centro dell'ordine?

Se hai solo un triangolo (3 punti) nel piano, puoi calcolare il determinante dalla matrice, dove le linee sono coordinate di punti (la terza coordinata è 1). Se il determinante è> 0, i punti sono nell'ordine CCW. In caso contrario, puoi ad esempio scambiare gli ultimi due punti e otterrai l'ordine CCW.

Se hai i punti A, B, C, la tua matrice sarà simile a:

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

Il determinante è: xA * yB + xB * yC + xC * yA - yB * xC - yC * xA - yA * xB. Quindi puoi confrontarlo con zero. Se è> 0, restituisce i punti A, B, C, in caso contrario, restituisce A, C, B.

Se hai una serie di punti e sai, formano un poligono convesso (tutti fanno parte dello scafo convesso) e vogliono ottenere il loro ordine, puoi usare Graham Scan o March di Jarvis (questi sono algoritmi per trovare lo scafo convesso da molti punti, ma dovrebbe funzionare anche qui :))


per completare ciò che ha detto zacharmarz se vuoi solo ordinare i tuoi punti in senso orario attorno a un punto specifico puoi creare un array da coppie di float e punto in cui memorizzi tutti i punti con il loro angolo corrispondente da quel punto specifico, e quindi ordina quella matrice.
Ali1S232,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.