@Prince,
post #1
Troszkę późno wprawdzie, ale co tam...
Kłania się geometria analityczna :/
Ja bym ten algorytm (w telegraficznym skrócie) widział tak:
1. Wybrać wielokąt, który potraktujemy jako bazę (A), zostanie on jako pierwszy umieszczony na powierzchni, a właściwie to bryła zostanie obrócona tak, że wybrany wielokąt znajdzie się na płaszczyźnie. Myślę, że dobrym kryterium było by wybranie największego wielokąta, no i oczywiście opcjonalnie wybór przez użytkownika.
2. szukamy wielokąta stykającego się krawędzią z wielokątem bazowym (B)
3. "odcinamy" wielokąt, zapamiętując krawedź (b) tego wielokąta leżącą po przeciwnej stronie niż krawędź (a) którą łączy się on z wielokątem bazowym (A). Oczywiście, jeżeli ta krawedź jest krawędzią wilelokąta bazowego, to jej nie zapamiętujemy. kraweź (b) powinna być jak najbardziej równoległa do krawędzi (a), czyli porównujemy krawedź (a) z kolejnymi krawędziami wielokąta (B) pod kątem równoległości. nie wiem, czy iloczyn wektorowy będzie działął tak samo w 3D, jak działa w 2D, ale właśnie w 2D iloczyn wektorowy jest takim kryterium.
4. odcięty wielokąt (B) obracamy względem krawędzi (a) która łączy go z bazą do poziomu. A jak? Ano tak: wiemy już, że wielokąt bazowy znajduje się na płaszczyżnie i jego nie ruszamy, na obróconym wielokącie (B) szukamy natomiast punktu jak najbardziej oddalonego od krawędzi (a). Rzutujemy ten punkt na krawędź (a) i już możemy wyznaczyć sobie kąt, o jaki należy obrócić wielokąt (kąt: płaszczyzna - zrzutowany punkt - wybrany punkt). Obracamy wielokąt względem krawędzi (a).
5. Bardzo ważna część, a zarazem dość banalna. Trzeba sprawdzić, czy naszą wycinankę można zrealizować w rzeczywistości, czyli żadne wielokąty na płaszczyźnie się nie pokrywają. Test jest prosty - sprawdzamy czy krawędzie obróconego wielokąta nie przecinają się z krawędziami innych wielokątów znajdujących się już na płaszczyźnie. Jeżeli się przecinają, to "przyklejamy" wielokąt z powrotem do bryły.
6. Odcinamy wielokąt (C) który łączył się zapamiętaną w punkcie 3 krawędzią (b) z wielokątem (B) obróconym w punkcie 4. Przyklejamy go z powrotem do obróconego wielokąta (B), oczywiście odpowiednio obracając. taki myk tak właściwie: W punkcie 4 zapamiętujemy wykonany obrót, i tak samo obracamy wielokąt (C), tzn. względem krawędzi (a). Po takiej operacji uzyskujemy płaską konstrukcję bazy i wielokąta (B), z "przyklejonym" do krawędzi (b) wielokątem (C) nieleżącym (ale uwaga, niekoniecznie!) na płaszczyźnie. wielokąt (C) obracamy tak samo względem krawędzi (b) jak obróciliśmy wielokąt (B) względem krawędzi (a).
7. No i znowu test na pokrywanie się wielokątów
I kilka uwag.
- Algorytm jest rekurencyjny, czego powyżej nie widać za bardzo.
- Algorytm stara się wyciąć jak najdłuższy pasek z wielokątów (stąd to poszukiwanie krawędzi (b) w punkcie 3.
- Algorytm zakłąda, że wszystkie wielokąty są płaskie (wszystkie punkty każdego z wielokątów leżą na płaszczyźnie. Można to zagwarantować jedynie przez wstępną triangulację, jednak w wypadku trójkątów wyszukiwanie paska staje się bardziej skomplikowane, ale nie do rozwiązania. trzeba wtedy stosować propagację błędów. Jeżeli obcinając pierwszy wielokąt skręcimy w lewo, to fakt ten zapamiętujemy i następny wielokąt do paska wybieramy tak, żeby skręcić w prawo i w efekcie rozwinięty na powierzchni pasek biegł jak najbardziej prosto.
- Przy okazji odcinania wielokątów nie możemy zapominać o wielokątach które były z nim połączone, bo gdy skończymy wycinać pasek (szukając kolejnych wielokątów natrafimy na wielokąt bazowy (punkt 3), to cofamy się i zaczynamy obcinać wielokąty stykające się z pozostałymi innymi krawędziami niż te najbardziej równoległe.
- Jeżeli do danego paska nie będziemy mogli dokleić więcej wielokątów (bo będą sie przecinały krawędzie), to wykonujemy cały algorytm od początku wybierając inny wielokąt połączony z wielokątem bazowym.
- Bryłę wyjściową przechowujemy jako zestaw punktów i krawędzi, obiekt krawędź jest wspólny dla dwóch wielokątów.
- W momencie odcinania obiekt krawedź zostaje przy bryle, a w odciętym wielokącie tworzymy nową.
- Jeżeli okaże się, że krawędzie "spłaszczonego" właśnie wielokąta się przecinają, to przy przyklejaniu go z powrotem stworzoną krawedź niszczymy, a punktom przypisujemy krewedź pozostałą przy bryle.
Jeszcze raz przypomnę o rekurencji, jest ona tu dość ważna i pozwala zrealizować ten algorytm w dość prosty sposób.
Całość można zrealizować jako funkcję obróć_wielokąt(wielokąt_bazowy, krawedź), która będzie obracać wielokąt (w przykłądzie powyżej (B) przylegający do wielokąta wielokąt_bazowy krawędzią krawędź (w przykłądzie (a) względem tejże krawędzi, a następnie wyszukiwać krawedź (b) z przeciwległego "końca" wielokąta równoległą do krawędzi (a) przekazanej jako argument i wywoływać samą siebie jako parametry podając tą znalezioną krawedź i łączący się z nią wielokąt. Warunkiem zakończenia jest znalezienie krawędzi należącej do wielokąta bazowego, lub niemożność "spłaszczenia" wielokąta (przecinanie się krawędzi), lub brak możliwości znalezienia kolejnej krawędzi należącej do "niespłaszczonego" już wielokąta.
Jeżeli nastąpi powrót z wywołania rekurencyjnego, to nie wywołująca funkcja nie kończy się, tylko szuka kolejnej krawędzi, mniej równoległej do krawędzi, która zostałą jej przekazana jako argument. Wyjscie z funkcji (poziom wyzej) nastepuje gdy nie mozna znaleźć więcej wielokątów / krawędzi.
Pierwsze wywołanie funkcij może nastąpić na przykłąd z parametrami (wielokąt bazowy, 0), co będzie oznaczało, że funkcja ma wylosować pierwszą krawedź.
Oczywiście należy stosować jakiś system znaczników w celu zapamiętywania, które wielokąty zostały już spłaszczone, oraz które krawędzie należą tylko do jednego wielokąta, przespieszy to drastycznie wykonywanie programu, a i całą funkcjie uprości.
Jeżeli odcinany z bryły wielokąt nie ma krawędzi wspólnej z innym wielokątem (krawędź wisi w powietrzu), to nie tworzysz nowej, tolko ją zostawiasz (do klejenia), posłuży to do wykonania 'listków' do sklejania (po jednym listku na krawedź z bryły wyjściowej).
Jeżeli do już spłaszczonego wielokąta doklejasz nowy to jeden z łączących je obiektów krawędź niszczysz, ale jak niszczysz, to musi być to krawędź, która wcześniej należała do bryły, a nie ta, która została przez Ciebie utworzona w momencie odklejania. Zostaje tylko jeden (utworzony przez Ciebie), który od tej pory jest wspólny.
Zastpspwanie powyższej metody pozwala na stworzenie listków w dość prosty sposób, bo trzeba zrobić tylko pętelkę po wszystkich krawędziach z bryły wyjściowej (część z nich zostałą usunięta i tam listków nie robimy, bo wielokąty są już połączone w tym miejscu ze sobą)
W ten sposób skonstruowana funkcja będzie sobie dobrze radziła z bryłami wypukłymi i niektórymi (chyba nawet z większością) niewypukłymi.
Wzorów nie podam, bo nie znam / nie pamiętam. Do znalezienia masz:
Test równoległości prostych / odcinków w 3D, musi zwracać jakąś wartość określająca "jak bardzo równoległe" są linie, czyli np. 0 gdy są równoległe, a 1 gdy rpostopadłe (trochę przekombinowane, bo w 3D jest jeszcze kilka innych warunków, ale chodzi tylko o sam "współczynnik równoległości"
Obroty punktów w 3D względem prostej (a prostą sobie wyliczysz z punktów końcowych krawędzi), większość tego co w sieci to obroty w 3D względem punktu, to też się nadaje, ale za każdym razem trzeba będzie te punkty wyliczać. Są to punkty leżące na prostej, której odcinkiem jest krawędź, a wylicza się je przez zrzutowanie punktu, który chcesz obracać na tą prostą. Ale lepiej znajdź gotowca obracającego wokół linii, jest dużo prostszy (i w obliczeniach i w stosowaniu).
Test przecinania się odcinków, to akurat do znalezienia dość łatwe.
Uffff, chyba tyle :P