2009-03-04 19 views
16

Poszukuję dobrego algorytmu, aby znaleźć prostokąt wyrównany względem osi w (niekoniecznie wypukłym) wielokącie. Maksymalny prostokąt byłby miły, ale nie jest konieczny - jakikolwiek algorytm, który znajdzie "dość dobry" prostokąt, będzie w porządku.Znajdowanie prostokąta wyrównanego do osi wewnątrz wielokąta

Wielokąt może mieć również dziury, ale pomocne będą również dowolne wskazówki dotyczące algorytmów działających tylko w przypadku wypukłych lub prostych wielokątów.

W mojej implementacji testowanie skrzyżowań dla stron jest dość tanie, ale testy "point in polygon" są drogie, więc najlepiej należy je zminimalizować.

+0

Czy uważasz, że test "punkt w wielokąt" jest ciężki? Przez większość czasu jest to tylko "większy niż" i/lub "mniej niż" test wszystkich punktów, z których składa się wielokąt, a tylko w niektórych przypadkach test przecięcia linii. Lub...? –

+0

Nie jestem pewien, co masz na myśli ... Używam testu "parzysty-nieparzysty" dla połowy linii (po sprawdzeniu prostokąta ograniczającego oczywiście). To kończy się testowaniem wielu stron, a jeśli wielokąt ma wiele stron, jest dość wolny. –

+0

Coud link do niektórych zestawów danych, brzmi to jak coś, co może być zabawne, aby spróbować. –

Odpowiedz

2

Dla porównania, jak dotąd wszystko, co mam, to brutalna siła: utworzyć siatkę, a dla punktów na siatce, jeśli znajdują się wewnątrz wielokąta, zrobić serię prostokątów, rozszerzając każdy róg lub bok po kolei, aż do momentu, w którym uderza w bok. Następnie wybierz największy.

Najprostszą (i bardzo skuteczną) optymalizacją jest jedynie sprawdzenie, czy punkt siatki znajduje się w wielokącie po sprawdzeniu, czy nie jest on zawarty w jednym z już zbudowanych prostokątów, ponieważ sprawdzanie "punktu w prostokącie" jest płonące szybki.

Z oczywistych względów, jest to dość powolne i niedokładne, nie wspominając nieeleganckie :)

+0

Po prostu z góry mojej głowy skonstruuj poziomy i pionowe linie przez każdy wierzchołek zamiast jednolitej siatki. –

+0

... zakładając, że poli nie ma wielu małych boków zbliżających się do krzywych. –

+0

Użyłem odmiany tego do dobrego efektu. Zasadniczo przecinam wielokąt w 16 punktach testowych (4 szerokości i 4 wysokości w oparciu o wymiary prostokąta ograniczającego). Z bardzo ograniczoną listą próbek musiałem tylko powiększyć mój prostokąt, sprawdzając, czy nowy punkt wytworzył prostokąt całkowicie wewnątrz geometrii. To zadziałało bardzo dobrze dla moich celów. –

3

Jednym z rozwiązań jest podzielenie wklęsłego wielokąta na wypukłe segmenty, a następnie użycie linku cobbal.

Ponieważ naprawdę masz dwa różne podstawowe problemy, czy rozważałeś inne alternatywy dla problemu testu trafienia, na przykład używając drzewa BSP? Możesz przyspieszyć to jeszcze bardziej, układając siatkę ponad polem i budując drzewo BSP dla każdego kwadratu siatki. Lub drzewo kd z najwyżej jedną krawędzią w każdym liściu?

Edit: będę ellaborate na kd-drzewa (z nudów, nawet jeśli może to być dowolnego użytku dla nikogo):

kd-drzewa mają następujące właściwości:

  1. Są one binarne
  2. Każdy nie-liść węzłowy dzieli przestrzeń wzdłuż płaszczyzny prostopadłej do osi, z jednej strony na dziecko. Na przykład. root dzieli przestrzeń na x < x0 i x> = x0
  3. Poziomy drzew z kolei dzielą się na różne osie, np. poziom 0 (root) dzieli prostopadle X, Poziom 1 -> Y, itd

Aby użyć tego wielokąta uderza detekcję skonstruować drzewo w następujący sposób:

  1. Odbiór wierzchołek podzielić wzdłuż. (Leprably gdzieś blisko środka dla zrównoważonego drzewa).
  2. Podziel pozostałe wierzchołki na dwa zestawy, po jednym dla każdej strony podziału. Powyższy wierzchołek nie przechodzi do żadnego z zestawów.
  3. Umieść krawędzie w zestawach. Każda krawędź, która przecina linię podziału, przechodzi do obu zbiorów.
  4. Skonstruuj dzieci rekurencyjnie z powyższych grup.

Jeśli podzielony wierzchołek zostanie wybrany odpowiednio, drzewo powinno mieć głębokość zbliżoną do log (N), gdzie N jest liczbą wierzchołków. Każdy węzeł liści będzie miał co najwyżej jedną krawędź przechodzącą przez niego. Aby wykryć trafienie:

  1. Znajdź liść, w którym znajduje się punkt.
  2. Jeśli w liściu jest krawędź, porównaj z nią punkt. Jeśli nie, powinno być oczywiste, czy punkt jest wewnątrz czy na zewnątrz (przechowuj tę informację w takich liściach podczas konstruowania drzewa).
+0

Próbowałem tego uniknąć ... czy znasz dobre wprowadzenie? Dzięki :) –

+0

Nie mogę podać żadnego, ale możesz łatwo załadować wiele rzeczy, a to, co właśnie napisałem, powinno dać ogólny pogląd. – TrayMan

0

A co z wykorzystaniem obcinania uszu? W każdym trójkącie można znaleźć prostokąt wyrównany do osi. Wtedy możesz spróbować dołączyć do trójkątów i przeliczyć swoje prostokąty.