Ten problem dotyczy w rzeczywistości przewrotów, po prostu uogólniam poniżej jako takie:
Mam widok 2D i kilka prostokątów w obszarze na ekranie. Jak rozłożyć te pola tak, aby nie zachodziły na siebie, a jedynie dopasować je przy minimalnym ruchu?
Pozycje prostokątów są dynamiczne i zależne od danych wejściowych użytkownika, więc ich pozycje mogą znajdować się w dowolnym miejscu.
Załączone obrazy przedstawiają problem i pożądane rozwiązanie
W rzeczywistości prawdziwy problem dotyczy kumulacji.
Odpowiedzi na pytania w komentarzach
Rozmiar prostokątów nie jest stały i zależy od długości tekstu w najeździe
Jeśli chodzi o rozmiar ekranu, teraz myślę, że lepiej założyć, że rozmiar ekranu jest wystarczający dla prostokątów. Jeśli jest zbyt wiele prostokątów, a algo nie daje rozwiązania, po prostu muszę dostosować zawartość.
Wymóg „minimalnego poruszania się” dotyczy raczej estetyki niż bezwzględnego wymogu inżynieryjnego. Można by oddzielić dwa prostokąty, dodając dużą odległość między nimi, ale nie będzie to dobrze wyglądać jako część GUI. Chodzi o to, aby najazd / prostokąt był tak blisko jego źródła (które następnie połączę ze źródłem za pomocą czarnej linii). Więc albo „przesuwanie tylko jednego o x” albo „przesuwanie obu o pół x” jest w porządku.
Odpowiedzi:
Trochę nad tym pracowałem, bo też potrzebowałem czegoś podobnego, ale opóźniłem rozwój algorytmu. Pomogłeś mi nabrać impulsu: D
Potrzebowałem też kodu źródłowego, więc oto on. Opracowałem to w Mathematica, ale ponieważ nie korzystałem zbytnio z funkcji funkcjonalnych, myślę, że będzie łatwo przetłumaczyć na dowolny język proceduralny.
Perspektywa historyczna
Najpierw postanowiłem opracować algorytm dla okręgów, ponieważ przecięcie jest łatwiejsze do obliczenia. Zależy to tylko od środków i promieni.
Udało mi się skorzystać z narzędzia do rozwiązywania równań Mathematica i działało dobrze.
Spójrz:
To było proste. Właśnie załadowałem solvera z następującym problemem:
Tak proste, a Mathematica wykonała całą pracę.
Powiedziałem: „Ha! To proste, teraz przejdźmy do prostokątów!”. Ale byłem w błędzie ...
Prostokątne bluesy
Główny problem z prostokątami polega na tym, że zapytanie o przecięcie jest nieprzyjemną funkcją. Coś jak:
Tak więc, kiedy próbowałem zasilić Mathematica wieloma z tych warunków do równania, działało tak źle, że zdecydowałem się zrobić coś proceduralnego.
Mój algorytm zakończył się następująco:
Możesz zauważyć, że warunek „najmniejszego ruchu” nie jest w pełni spełniony (tylko w jednym kierunku). Ale odkryłem, że przesuwanie prostokątów w dowolnym kierunku, aby to zaspokoić, czasami kończy się mylącą zmianą mapy dla użytkownika.
Projektując interfejs użytkownika, wybieram przesunięcie prostokąta nieco dalej, ale w bardziej przewidywalny sposób. Możesz zmienić algorytm, aby sprawdzić wszystkie kąty i wszystkie promienie otaczające jego bieżącą pozycję, aż zostanie znalezione puste miejsce, chociaż będzie to znacznie bardziej wymagające.
W każdym razie są to przykłady wyników (przed / po):
Edytuj> Więcej przykładów tutaj
Jak widać, „minimalny ruch” nie jest spełniony, ale wyniki są wystarczająco dobre.
Opublikuję kod tutaj, ponieważ mam problemy z repozytorium SVN. Usunę go, gdy problemy zostaną rozwiązane.
Edytować:
Możesz również użyć R-drzew do znajdowania przecięć prostokątów, ale wydaje się to przesadą do radzenia sobie z niewielką liczbą prostokątów. I nie mam już zaimplementowanych algorytmów. Być może ktoś inny wskaże Ci istniejącą implementację na wybranej platformie.
Ostrzeżenie! Kod to pierwsze podejście… nie jest to jeszcze świetna jakość i na pewno ma kilka błędów.
To Mathematica.
Główny
HTH!
Edycja: wyszukiwanie pod wieloma kątami
Zaimplementowałem zmianę w algorytmie pozwalającą na wyszukiwanie we wszystkich kierunkach, ale dającą pierwszeństwo osi narzuconej przez symetrię geometryczną.
Kosztem większej liczby cykli skutkowało to bardziej zwartymi konfiguracjami końcowymi, jak widać poniżej:
Więcej próbek tutaj .
Pseudokod głównej pętli został zmieniony na:
Nie dołączam kodu źródłowego dla zwięzłości, ale po prostu poproś o to, jeśli uważasz, że możesz go użyć. Myślę, że jeśli pójdziesz tą drogą, lepiej przełączyć się na R-drzewka (potrzeba tutaj dużo testów interwałowych)
źródło
Oto przypuszczenie.
Znajdź środek C obwiedni twoich prostokątów.
Dla każdego prostokąta R, który zachodzi na inny.
To stopniowo przesuwa prostokąty od siebie i od środka wszystkich prostokątów. To zakończy się, ponieważ składnik v z kroku 4 w końcu sam je wystarczająco rozłoży.
źródło
Myślę, że to rozwiązanie jest dość podobne do tego, które daje cape1232, ale jest już zaimplementowane, więc warto sprawdzić :)
Śledź tę dyskusję na reddicie: http://www.reddit.com/r/gamedev/comments/1dlwc4/procedural_dungeon_generation_algorithm_explained/ i sprawdź opis i implementację. Nie ma dostępnego kodu źródłowego, więc oto moje podejście do tego problemu w AS3 (działa dokładnie tak samo, ale utrzymuje prostokąty przyciągane do rozdzielczości siatki):
źródło
velocity
to suma wektorów między jego środkiem a środkiem innych pokoi, jeśli wszystkie pokoje są ułożone w ten sam środek,velocity.length == 0
dla wszystkich pokoi i nic się nie poruszy. W ten sam sposób, jeśli dwa lub więcej pokoi ma ten sam prostokąt z tym samym środkiem, przesuną się razem, ale pozostaną ułożone w stos.Bardzo podoba mi się implementacja b005t3r! Działa w moich przypadkach testowych, jednak mój przedstawiciel jest zbyt niski, aby zostawić komentarz z 2 sugerowanymi poprawkami.
Nie powinieneś tłumaczyć pokoi o pojedyncze przyrosty rozdzielczości, powinieneś tłumaczyć przez prędkość, którą po prostu precyzyjnie obliczyłeś! To sprawia, że separacja jest bardziej organiczna, ponieważ głęboko przecinające się pokoje oddzielają się bardziej w każdej iteracji niż nie tak głęboko przecinające się pokoje.
Nie powinieneś zakładać, że velociity mniejsze niż 0,5 oznaczają oddzielne pokoje, ponieważ możesz utknąć w przypadku, gdy nigdy nie zostaniesz rozdzielony. Wyobraź sobie, że 2 pokoje się przecinają, ale nie są w stanie się poprawić, ponieważ za każdym razem, gdy którykolwiek z nich próbuje skorygować penetrację, obliczają wymaganą prędkość jako <0,5, więc iterują w nieskończoność.
Oto rozwiązanie Java (: Cheers!
źródło
Oto algorytm napisany przy użyciu języka Java do obsługi klastra nieobrotowych plików
Rectangle
s. Pozwala określić pożądane proporcje układu i pozycjonuje klaster za pomocą sparametryzowanegoRectangle
punktu zakotwiczenia, na którym zorientowane są wszystkie wykonane tłumaczenia. Możesz również określić dowolną ilość wypełnienia, według której chcesz rozłożyćRectangle
s.}
Oto przykład użycia
AspectRatio
of1.2
, aFillPercentage
of0.8
i aPadding
of10.0
.Jest to podejście deterministyczne, które pozwala na występowanie odstępów wokół kotwy, pozostawiając niezmienione położenie samej kotwicy. Dzięki temu układ pojawia się wszędzie tam, gdzie znajduje się punkt zainteresowania użytkownika. Logika wyboru pozycji jest dość uproszczona, ale myślę, że otaczająca architektura sortowania elementów na podstawie ich początkowej pozycji, a następnie ich iteracja jest użytecznym podejściem do implementacji stosunkowo przewidywalnej dystrybucji. Poza tym nie polegamy na iteracyjnych testach przecięcia ani na czymś podobnym, po prostu budujemy kilka obwiedni, aby dać nam ogólne wskazówki, gdzie wyrównać rzeczy; potem nakładanie wyściółki przychodzi naturalnie.
źródło
Oto wersja, która przyjmuje odpowiedź cape1232 i jest samodzielnym uruchomionym przykładem dla Javy:
źródło