Сортування масиву точок у порядку годинникової стрілки


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
повернення може бути кутом повернення1 <угол2? 1: кут2> кут1? -1: 0;
ademar111190

2
Це можна висловити багатьма способами, але я, як правило, уникаю вкладених потрійних операторів, особливо при наданні прикладів.
onedayitwillmake

@onedayitwillmake Чи можете ви перемістити код, який ви закінчили, використовуючи у відповідь? Це насправді не належить до питання, але це дуже цінно для майбутніх читачів.
Анко

@Anko Я думаю, ти маєш рацію, але в той же час я думаю, що людям буде найпростіше знайти це таким чином. Це також допомагає переконатися, що я не відволікаюсь від відповіді samhocevar, на якій просто заснована моя.
onedayitwillmake

Відповіді:


19

Ваше питання недостатньо точне. Масив точок є лише «за годинниковою стрілкою» або «проти годинникової стрілки» щодо опорної точки. В іншому випадку будь-який масив з трьох точок завжди може бути або 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наприклад.

Однак ви можете бути впевнені, що хороший алгоритм сортування буде погано працювати з трьома вхідними значеннями порівняно з тимчасовим методом. Використання atan2все ще дійсне, але просто не використовуйте qsort.


Це спрацювало чудово :)
onedayitwillmake

1
Чи має цей метод назву?
onedayitwillmake

1
Я вважаю, що це просто називається «сортування за полярним кутом». Наприклад, це компонент сканування Грема .
sam hocevar

Вистава хіт qsortтут невеликий порівняно з atan2.

Невелике попередження: Це потенційно може вийти з ладу та згоріти (залежно від мови програмування та використовуваних бібліотек), якщо будь-яка з точок виявиться точно в барицентрі (або будь-якій іншій орієнтації, яку ви використовуєте). Ви можете виключити такі точки між другим та третім кроком.
Мартін Сойка

3

Я вважаю, що ви насправді запитуєте тут про намотування трикутника, яке насправді досить просто перевірити.

Оскільки у вашому трикутнику є лише три точки, ваш трикутник вже розташований або за годинниковою стрілкою, або проти годинникової стрілки, і тому все, що вам потрібно зробити, це перевірити, який з цих двох це, і змінити порядок показників, якщо обмотка не той, кого ти хочеш.

Ось загальна ідея, припускаючи, що три вершини трикутника є a , b і 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), щоб створити багатокутник. хоча це не те, про що я просив, дуже добре
розумію

2

Чи можете ви дати більше інформації? Ви хочете порядку балів CCW, але який пункт повинен бути центром упорядкування?

Якщо у вас в площині просто трикутник (3 точки), ви можете обчислити визначник з матриці, де рядки є координатами точок (3-а координата - 1). Якщо визначник> 0, точки в порядку CCW. Якщо ні, ви можете покласти на приклад останні два пункти, і ви отримаєте замовлення 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.

Якщо у вас є набір точок і ви знаєте, вони складають опуклий багатокутник (усі вони є частиною опуклого корпусу), і хочете отримати їх порядок, ви можете скористатися Грехом Сканом або Маршем Джарвіса (це алгоритми пошуку випуклого корпусу з багатьох точок, але він також повинен працювати тут :))


щоб виконати те, що сказав zacharmarz, якщо ви просто хочете сортувати свої точки за годинниковою стрілкою навколо певної точки, ви можете створити масив з пар поплавця та точки, в якій ви зберігаєте всі точки з відповідним кутом від цієї конкретної точки, а потім сортуйте цей масив.
Ali1S232
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.