Jak niezawodnie dowiedzieć się, czy przecinają się dwie płaskie krzywe Beziera? Przez „niezawodnie” rozumiem, że test odpowie „tak” tylko wtedy, gdy krzywe się przecinają, i „nie” tylko wtedy, gdy się nie przecinają. Nie muszę wiedzieć, przy jakich parametrach znaleziono skrzyżowanie. W implementacji chciałbym również użyć liczb zmiennoprzecinkowych.
Znalazłem kilka odpowiedzi na StackOverflow, które używają obwiedni krzywych do testu: nie o to mi chodzi, ponieważ taki test może zgłosić przecięcie, nawet jeśli krzywe się nie przecinają.
Jak dotąd znalazłem najbliższy „ klin ograniczający ” Sederberga i Meyersa, ale „tylko” rozróżnia skrzyżowanie co najwyżej jeden i dwa lub więcej, podczas gdy chcę wiedzieć, czy jest co najwyżej zero i jedno lub więcej skrzyżowań.
źródło
Odpowiedzi:
Alternatywnym sposobem sformułowania problemu jest zdefiniowanie funkcji określającej odległość między punktami na dwóch krzywych, w zależności od parametrów krzywych. Następnie spróbuj znaleźć globalne minimum tej funkcji. Jeśli krzywe przecinają się, minimum będzie wynosić zero; w przeciwnym razie minimum będzie dodatnim dystansem.
Mówiąc wprost, biorąc pod uwagę parę krzywych 2D zdefiniowanych przezdo1,do2): [ 0 , 1 ] →R2) , zdefiniuj kwadrat do kwadratu jako
Dla krzywych sześciennych funkcjafa jest wówczas wielomianem szóstego stopnia w dwóch zmiennych. Następnie można zastosować techniki optymalizacji numerycznej, takie jak metoda simpleks lub sprzężone zejście gradientu . Niestety funkcja może mieć kilka lokalnych minimów (nie jest wypukła), więc optymalizacja nie jest łatwa. Mogą istnieć bardziej wyspecjalizowane metody optymalizacji wielomianów, ale nie jest to dla mnie specjalizacja.
źródło
[Oświadczenie: Myślę, że następujące elementy powinny działać, ale sam ich nie kodowałem]
Nie mogłem wymyślić „trywialnej” metody udzielania odpowiedzi tak / nie, ale poniższe podejście byłoby rozsądnym podejściem do praktycznego rozwiązania tego pytania.
Załóżmy, że nasze krzywe to A (s) i B (t) z punktami kontrolnymi odpowiednio { A0, A1..An } i { B0, .. Bm }.
Wydaje mi się, że biorąc pod uwagę parę Beziers 2D, dla których chcemy ustalić, czy przecinają się, czy nie, należy rozważyć sześć przypadków:
Przypadek, w którym możemy „w trywialny sposób” ustalić, że się nie przecinają.
Przypadek, w którym przecinają się one skończoną liczbę razy, a my możemy „łatwo” ustalić, że zdecydowanie przecinają się przynajmniej raz (ale tak naprawdę nie obchodzi nas, gdzie występują te skrzyżowania)
Jeden z Beziersów jest zdegenerowany, tj. Punkt (który wystąpi, jeśli wszystkie punkty kontrolne są identyczne). Możemy założyć, że już załatwiliśmy sprawę, w której oba są punktami.
Jedna lub więcej krzywych jest zamkniętych, np. A0 == An. Aby ułatwić życie, podzielimy takie krzywe i zaczniemy od nowa.
Istnieje nieskończona liczba punktów przecięcia, ponieważ każdy jest podzbiorem „nadrzędnego” Beziera i nakładają się na siebie.
Nie jesteśmy pewni powyższych przypadków i potrzebujemy dalszego dochodzenia
Na razie zignorujemy 3 i 4, ale wrócimy do nich później.
Przypadek 1
Jak sugerujesz w swoim pytaniu, jeśli odpowiednie pola ograniczające punktów kontrolnych A i B ) nie przecinają się, wówczas krzywe nie mogą się przecinać. Oczywiście jest to szybki test odrzucenia, ale jest zbyt konserwatywny. Jak zapewne wiesz, z krzywą Beziera wypukły kadłub punktów kontrolnych tworzy (węższe) wiązanie na krzywej. Możemy zatem użyć techniki osi oddzielającej, aby zdecydować, czy kadłuby A i B nie przecinają się. (np. jak pokazano w Wikipedii :)
Przypadek 2
Jeśli test przypadku 1 nie powiedzie się, możesz sprawdzić „trywialne” istnienie skrzyżowania. Teraz są prawdopodobnie lepsze sposoby, aby to zrobić, ale przyszło mi do głowy następujące stosunkowo tanie podejście:
Rozważ tylko krzywą A:
Wiemy, że krzywa zaczyna się odZA0 kończy się o godz ZAn i będzie leżeć wewnątrz wypukłego kadłuba. Dla uproszczenia obliczmy kierunek odcinka liniiZA0ZAn¯¯¯¯¯¯¯¯¯¯¯¯ i obliczyć granice po obu stronach (tj. wziąć iloczyn iloczynu pozostałych punktów kontrolnych względem prostopadłej do ZA0ZAn¯¯¯¯¯¯¯¯¯¯¯¯ ).
Jeśli zrobimy to samo z krzywą B, otrzymamy następujący (możliwy) przypadek:
Jeśli znajdziemyZA0 i ZAn znajdują się poza przeciwnymi granicami B i tamtob0 i bm znajdują się poza granicami A, a zatem, dzięki ciągłości Beziersa, musi istnieć co najmniej jedno skrzyżowanie.
Przypadek 6
Jeśli nie możemy natychmiast pokazać żadnego z powyższych przypadków, podziel każdy Beziers na dwie „połowy”, tjZA1,ZA2),b1,b2) . Jest to stosunkowo proste (pozostawione jako ćwiczenie dla czytelnika), ale jest szczególnie trywialne dla kwadratowego Beziersa :
Rekurencyjnie porównaj 4 kombinacje:(ZA1,b1) , (ZA2),b1) . . . (ZA2),b2)) . Oczywiście, jeśli wszystkie przypadki przypadku 1 są spełnione, nie ma przecięcia. W przypadku niepowodzenia 1, kontynuuj pozostałe testy z tym zredukowanym podzbiorem.
Przypadek 3 i 5
Tutaj staje się nieco bardziej nużące.
Jeśli „przypadek 3” przejdzie test „przypadek 1”, wydaje mi się, że trzeba rozwiązać rzeczywiste skrzyżowanie. Biorąc pod uwagę, że istnieje prosty proces mapowania N punktów kontrolnych Beziera, A (s), do punktów N-1 Beziera, A (s), reprezentujących wówczas jego 1. pochodną (pod warunkiem zachowania ostrożności stosunkowo rzadkie, tak zwane „zdegenerowane” sytuacje, w których 1. pochodna ma wartość zerową), następnie iteracja Newtona (w jednym wymiarze) może być wykorzystana do znalezienia potencjalnych rozwiązań.
Należy również zauważyć, że ponieważ punkty kontrolne A '(s) są powiązane z wartościami pochodnymi, istnieje możliwość wcześniejszej eliminacji niektórych przypadków.
Przypadek 5 wydaje się stosunkowo mało prawdopodobny, więc być może tylko wtedy, gdy po kilku rekurencjach nie będzie rozstrzygającego dowodu, można wypróbować każdy punkt końcowy A względem krzywej B i odwrotnie. Dałoby to tylko dowód skrzyżowania - a nie dowód braku skrzyżowania.
źródło