Próbuję utworzyć szybki punkt 2D wewnątrz algorytmu wielokąta, do użycia w testowaniu trafień (np Polygon.contains(p:Point)
.). Docenione zostaną sugestie dotyczące skutecznych technik.
performance
graphics
collision-detection
polygon
point-in-polygon
Scott Evernden
źródło
źródło
Odpowiedzi:
W przypadku grafiki wolałbym nie preferować liczb całkowitych. Wiele systemów używa liczb całkowitych do malowania w interfejsie użytkownika (w końcu piksele są liczbami całkowitymi), ale na przykład macOS używa float do wszystkiego. macOS zna tylko punkty, a punkt może tłumaczyć się na jeden piksel, ale w zależności od rozdzielczości monitora może on przekładać się na coś innego. Na ekranach siatkówki pół punktu (0,5 / 0,5) to piksel. Mimo to nigdy nie zauważyłem, że interfejsy macOS są znacznie wolniejsze niż inne interfejsy. Po tym, jak wszystkie interfejsy API 3D (OpenGL lub Direct3D) współpracują również z pływakami, a nowoczesne biblioteki graficzne bardzo często korzystają z akceleracji GPU.
Teraz powiedziałeś, że prędkość jest twoim głównym zmartwieniem, dobra, chodźmy na szybkość. Zanim uruchomisz jakiś wyrafinowany algorytm, najpierw wykonaj prosty test. Utwórz obwiednię wyrównaną do osi wokół swojego wielokąta. Jest to bardzo łatwe, szybkie i może już zabezpieczyć wiele obliczeń. Jak to działa? Iteruj po wszystkich punktach wielokąta i znajdź wartości min / maks X i Y.
Np. Masz punkty
(9/1), (4/3), (2/7), (8/2), (3/6)
. Oznacza to, że Xmin to 2, Xmax to 9, Ymin to 1, a Ymax to 7. Punkt poza prostokątem o dwóch krawędziach (2/1) i (9/7) nie może znajdować się w wielokącie.To pierwszy test, który można przeprowadzić w dowolnym momencie. Jak widać, ten test jest bardzo szybki, ale jest również bardzo szorstki. Aby obsłużyć punkty znajdujące się w obrębie prostokąta ograniczającego, potrzebujemy bardziej zaawansowanego algorytmu. Można to obliczyć na kilka sposobów. Która metoda działa, zależy również od tego, czy wielokąt może mieć otwory lub zawsze będzie solidny. Oto przykłady brył (jeden wypukły, jeden wklęsły):
A oto jeden z dziurą:
Zielony ma dziurę w środku!
Najłatwiejszy algorytm, który może obsłużyć wszystkie trzy powyższe przypadki i nadal jest dość szybki, nazywa się rzutowaniem promieniowym . Algorytm jest dość prosty: narysuj wirtualny promień z dowolnego miejsca poza wielokątem i policz, jak często uderza on w bok wielokąta. Jeśli liczba trafień jest parzysta, znajduje się poza wielokątem, a jeśli jest nieparzysty, to jest w środku.
Algorytm numer uzwojenie byłoby alternatywą, jest bardziej dokładna dla punktów będących bardzo blisko do linii wielokąta, ale jest to również znacznie wolniej. Rzutowanie promieniowe może się nie udać w przypadku punktów znajdujących się zbyt blisko boku wielokąta ze względu na ograniczoną precyzję zmiennoprzecinkową i problemy z zaokrąglaniem, ale w rzeczywistości nie stanowi to problemu, tak jakby punkt znajdował się tak blisko boku, często jest to wizualnie niemożliwe widz rozpoznaje, czy jest już w środku, czy na zewnątrz.
Nadal masz powyższą ramkę, pamiętasz? Wystarczy wybrać punkt poza obwiednią i użyć go jako punktu początkowego dla promienia. Np. Punkt
(Xmin - e/p.y)
na pewno znajduje się poza wielokątem.Ale co to jest
e
? Cóż,e
(właściwie epsilon) dodaje obrysowi trochę obicia . Jak powiedziałem, śledzenie promieni nie powiedzie się, jeśli zaczniemy zbyt blisko linii wielokąta. Ponieważ obwiednia może być równa wielobokowi (jeśli wielobok jest prostokątem wyrównanym do osi, obwiednia jest równa samemu wielobokowi!), Potrzebujemy trochę wypełnienia, aby zapewnić bezpieczeństwo, to wszystko. Jak duży powinieneś wybraće
? Nie za duży. To zależy od skali układu współrzędnych używanego do rysowania. Jeśli szerokość kroku w pikselach wynosi 1,0, wybierz po prostu 1,0 (jeszcze 0,1 też by działało)Teraz, gdy mamy promień ze współrzędnymi początkowymi i końcowymi, problem przesuwa się z „ jest punktem wewnątrz wielokąta ” na „ jak często promień przecina stronę wielokąta ”. Dlatego nie możemy tak po prostu pracować z punktami wielokąta, jak teraz, teraz potrzebujemy rzeczywistych boków. Strona jest zawsze definiowana przez dwa punkty.
Musisz przetestować promień ze wszystkich stron. Traktuj promień jako wektor, a każdą stronę jako wektor. Promień musi trafić w każdą stronę dokładnie raz lub wcale. Nie może trafić dwukrotnie po tej samej stronie. Dwie linie w przestrzeni 2D zawsze przecinają się dokładnie raz, chyba że są równoległe, w takim przypadku nigdy się nie przecinają. Jednak ponieważ wektory mają ograniczoną długość, dwa wektory mogą nie być równoległe i nadal nigdy się nie przecinają, ponieważ są zbyt krótkie, aby się ze sobą spotkać.
Jak dotąd dobrze, ale jak sprawdzić, czy dwa wektory się przecinają? Oto kod C (nie testowany), który powinien załatwić sprawę:
Wartości wejściowe to dwa punkty końcowe wektora 1 (
v1x1/v1y1
iv1x2/v1y2
) i wektora 2 (v2x1/v2y1
iv2x2/v2y2
). Masz więc 2 wektory, 4 punkty, 8 współrzędnych.YES
iNO
są jasne.YES
zwiększa skrzyżowania,NO
nic nie robi.Co z COLLINEAR? Oznacza to, że oba wektory leżą na tej samej nieskończonej linii, w zależności od położenia i długości, nie przecinają się wcale lub przecinają się w nieskończonej liczbie punktów. Nie jestem absolutnie pewien, jak poradzić sobie z tą sprawą, nie liczyłbym jej jako skrzyżowania. Cóż, ten przypadek i tak jest raczej rzadki w praktyce z powodu błędów zaokrąglania zmiennoprzecinkowego; Lepszy kod prawdopodobnie nie przetestowałby,
== 0.0f
ale zamiast czegoś takiego< epsilon
, gdzie epsilon jest raczej małą liczbą.Jeśli chcesz przetestować większą liczbę punktów, z pewnością możesz trochę przyspieszyć, utrzymując w pamięci standardowe równania liniowe boków wielokąta, więc nie musisz ich ponownie obliczać za każdym razem. Pozwoli to zaoszczędzić dwa mnożenia zmiennoprzecinkowe i trzy odejmowania zmiennoprzecinkowe na każdym teście w zamian za przechowywanie w pamięci trzech wartości zmiennoprzecinkowych na stronę wielokąta. Jest to typowa kompromis między pamięcią a czasem obliczeniowym.
Na koniec: jeśli możesz użyć sprzętu 3D do rozwiązania problemu, istnieje interesująca alternatywa. Po prostu pozwól GPU wykonać całą pracę za Ciebie. Utwórz malowaną powierzchnię, która jest poza ekranem. Wypełnij go całkowicie kolorem czarnym. Teraz pozwól OpenGL lub Direct3D pomalować twój wielokąt (lub nawet wszystkie twoje wielokąty, jeśli chcesz tylko sprawdzić, czy punkt znajduje się w którymkolwiek z nich, ale nie zależy ci na którym) i wypełnij wielokąt (y) innym kolor, np. biały. Aby sprawdzić, czy punkt znajduje się w wielokącie, uzyskaj kolor tego punktu z powierzchni rysowania. To tylko pobieranie pamięci O (1).
Oczywiście ta metoda jest użyteczna tylko wtedy, gdy twoja powierzchnia do rysowania nie musi być duża. Jeśli nie może zmieścić się w pamięci GPU, ta metoda jest wolniejsza niż w przypadku procesora. Gdyby musiała być ogromna, a Twój procesor graficzny obsługuje nowoczesne moduły cieniujące, nadal możesz używać procesora graficznego, implementując rzutowanie promieni pokazane powyżej jako moduł cieniujący GPU, co jest absolutnie możliwe. W przypadku większej liczby wielokątów lub dużej liczby punktów do przetestowania, opłaci się to, biorąc pod uwagę, że niektóre procesory graficzne będą w stanie przetestować od 64 do 256 punktów równolegle. Należy jednak pamiętać, że przesyłanie danych z procesora do GPU iz powrotem jest zawsze drogie, więc po prostu testowanie kilku punktów na kilku prostych wielokątach, w których albo punkty lub wielokąty są dynamiczne i często się zmieniają, podejście GPU rzadko płaci poza.
źródło
Myślę, że następujący fragment kodu jest najlepszym rozwiązaniem (wzięty stąd ):
Argumenty
Jest zarówno krótki, jak i wydajny i działa zarówno na wypukłe, jak i wklęsłe wielokąty. Jak zasugerowano wcześniej, należy najpierw sprawdzić prostokąt obwiedni i osobno potraktować otwory wielokąta.
Idea tego jest dość prosta. Autor opisuje to w następujący sposób:
Zmienna c zmienia się z 0 na 1 i 1 na 0 za każdym razem, gdy promień poziomy przecina dowolną krawędź. Zasadniczo śledzi więc, czy liczba skrzyżowanych krawędzi jest parzysta czy nieparzysta. 0 oznacza parzystą, a 1 nieparzystą.
źródło
verty[i]
iverty[j]
jest po obu stronachtesty
, więc nigdy nie są równe.Oto wersja C # odpowiedzi udzielonej przez nirg , która pochodzi od tego profesora RPI . Pamiętaj, że użycie kodu z tego źródła RPI wymaga przypisania.
U góry dodano obwiednię. Jednak, jak podkreśla James Brown, główny kod jest prawie tak szybki jak samo sprawdzenie pola granicznego, więc sprawdzenie pola granicznego może faktycznie spowolnić całą operację, w przypadku gdy większość punktów, które sprawdzasz, znajduje się wewnątrz ramki granicznej . Możesz więc pozostawić pole ograniczające wyewidencjonowane, lub alternatywnie byłoby wstępnie obliczyć obwiednie twoich wielokątów, jeśli nie zmieniają one kształtu zbyt często.
źródło
Oto wariant JavaScript odpowiedzi M. Katza oparty na podejściu Nirga:
źródło
Oblicz zorientowaną sumę kątów między punktem p a każdym wierzchołkiem wielokąta. Jeśli całkowity zorientowany kąt wynosi 360 stopni, punkt znajduje się wewnątrz. Jeśli suma wynosi 0, punkt jest na zewnątrz.
Bardziej podoba mi się ta metoda, ponieważ jest bardziej niezawodna i mniej zależna od precyzji numerycznej.
Metody obliczania równości liczby skrzyżowań są ograniczone, ponieważ można „trafić” wierzchołek podczas obliczania liczby skrzyżowań.
EDYCJA: Przy okazji, ta metoda działa z wklęsłymi i wypukłymi wielokątami.
EDYCJA: Niedawno znalazłem cały artykuł w Wikipedii na ten temat.
źródło
To pytanie jest bardzo interesujące. Mam inny praktyczny pomysł, inny niż inne odpowiedzi na ten post. Chodzi o to, aby użyć sumy kątów, aby zdecydować, czy cel jest w środku, czy na zewnątrz. Lepiej znany jako liczba uzwojenia .
Niech x będzie punktem docelowym. Niech tablica [0, 1, .... n] będzie wszystkimi punktami obszaru. Połącz punkt docelowy z każdym punktem granicznym za pomocą linii. Jeśli punkt docelowy znajduje się w tym obszarze. Suma wszystkich kątów wyniesie 360 stopni. Jeśli nie, kąty będą mniejsze niż 360.
Zapoznaj się z tym obrazem, aby uzyskać podstawowe zrozumienie tego pomysłu:
Mój algorytm zakłada, że kierunek zgodny z ruchem wskazówek zegara to kierunek dodatni. Oto potencjalny wkład:
Poniżej znajduje się kod python, który implementuje ten pomysł:
źródło
Artykuł Erica Hainesa cytowany przez bobobobo jest naprawdę doskonały. Szczególnie interesujące są tabele porównujące wydajność algorytmów; metoda sumowania kątów jest naprawdę zła w porównaniu z innymi. Interesujące jest również to, że takie optymalizacje, jak użycie siatki odnośników do dalszego podziału wielokąta na sektory „wejściowy” i „wyjściowy”, mogą sprawić, że test będzie niesamowicie szybki nawet na wielokątach o> 1000 bokach.
W każdym razie, są wczesne dni, ale mój głos dotyczy metody „przejazdów”, co, jak sądzę, jest prawie tym, co opisuje Mecki. Jednak najbardziej trafnie go opisałem i skodyfikowałem przez Davida Bourke . Uwielbiam to, że nie jest wymagana prawdziwa trygonometria i działa ona na wypukłe i wklęsłe i działa dość dobrze, gdy rośnie liczba boków.
Nawiasem mówiąc, oto jedna z tabel wydajności z artykułu Erica Hainesa dla zainteresowania, testowania losowych wielokątów.
źródło
Szybka wersja odpowiedzi nirg :
źródło
Naprawdę podoba się rozwiązanie opublikowane przez Nirga i zredagowane przez bobobobo. Właśnie uczyniłem go javascript przyjaznym i trochę bardziej czytelnym dla mojego zastosowania:
źródło
Pracowałem nad tym, kiedy byłem badaczem pod kierunkiem Michaela Stonebrakera - wiesz, profesor, który wymyślił Ingres , PostgreSQL itp.
Uświadomiliśmy sobie, że najszybszym sposobem było najpierw wykonać obwiednię, ponieważ jest ona superszybka. Jeśli jest poza obwiednią, jest na zewnątrz. W przeciwnym razie wykonasz cięższą pracę ...
Jeśli chcesz świetnego algorytmu, zajrzyj do kodu źródłowego PostgreSQL projektu open source do pracy geo ...
Chcę podkreślić, że nigdy nie mieliśmy wglądu w prawą i lewą rękę (wyrażalną również jako problem „wewnątrz” vs. „na zewnątrz” ...
AKTUALIZACJA
Link BKB dostarczył sporo rozsądnych algorytmów. Pracowałem nad problemami nauk o Ziemi i dlatego potrzebowałem rozwiązania, które działa na szerokości i długości geograficznej, i ma szczególny problem z poręcznością - czy obszar jest wewnątrz mniejszego lub większego obszaru? Odpowiedź jest taka, że „kierunek” wierzchołków ma znaczenie - jest leworęczny lub praworęczny, w ten sposób możesz wskazać dowolny obszar jako „wewnątrz” dowolnego wielokąta. W związku z tym w mojej pracy wykorzystałem rozwiązanie trzy wymienione na tej stronie.
Ponadto w mojej pracy wykorzystałem osobne funkcje do testów „on-line”.
... Ponieważ ktoś zapytał: ustaliliśmy, że testy ramki ograniczającej były najlepsze, gdy liczba pionów przekroczyła pewną liczbę - wykonaj bardzo szybki test przed wykonaniem dłuższego testu, jeśli to konieczne ... Ramkę ograniczającą tworzy się po prostu biorąc największy x, najmniejszy x, największy y i najmniejszy y i zebranie ich razem, aby utworzyć cztery punkty pudełka ...
Kolejna wskazówka dla następnych: wykonaliśmy wszystkie nasze bardziej wyrafinowane i „ściemniające” obliczenia w przestrzeni siatki wszystko w dodatnich punktach na płaszczyźnie, a następnie ponownie rzutowaliśmy na „rzeczywistą” długość / szerokość geograficzną, unikając w ten sposób możliwych błędów owijanie się, gdy jedna linia przekroczy 180 długości geograficznej i podczas obchodzenia się z regionami polarnymi. Działa świetnie!
źródło
Odpowiedź Davida Segonda jest w zasadzie standardową odpowiedzią ogólną, a Richard T jest najczęstszą optymalizacją, choć są też inne. Inne silne optymalizacje oparte są na mniej ogólnych rozwiązaniach. Na przykład, jeśli zamierzasz sprawdzić ten sam wielokąt z dużą ilością punktów, triangulacja wielokąta może znacznie przyspieszyć sprawę, ponieważ istnieje wiele bardzo szybkich algorytmów wyszukiwania TIN. Innym jest, jeśli wielokąt i punkty znajdują się na ograniczonej płaszczyźnie w niskiej rozdzielczości, powiedzmy na ekranie, możesz pomalować wielokąt na buforze wyświetlania odwzorowanym w pamięci w danym kolorze i sprawdzić kolor danego piksela, aby zobaczyć, czy leży w wielokątach.
Podobnie jak wiele optymalizacji, opierają się one na konkretnych, a nie ogólnych przypadkach, i dają korzyści na podstawie zamortyzowanego czasu, a nie pojedynczego użycia.
Pracując w tej dziedzinie, znalazłem Joesepha O'Rourkesa „Geometria obliczeniowa w C” ISBN 0-521-44034-3, która była wielką pomocą.
źródło
Trywialnym rozwiązaniem byłoby podzielenie wielokąta na trójkąty i przetestowanie trójkątów, jak wyjaśniono tutaj
Jeśli twój wielokąt jest CONVEX , może być lepsze podejście. Spójrz na wielokąt jako zbiór nieskończonych linii. Każda linia dzieli przestrzeń na dwie części. dla każdego punktu łatwo jest powiedzieć, czy jest po jednej, czy po drugiej stronie linii. Jeśli punkt znajduje się po tej samej stronie wszystkich linii, to znajduje się wewnątrz wielokąta.
źródło
Zdaję sobie sprawę, że to jest stare, ale tutaj jest algorytm rzucania promieni zaimplementowany w Cocoa, na wypadek, gdyby ktoś był zainteresowany. Nie jestem pewien, czy jest to najskuteczniejszy sposób robienia rzeczy, ale może komuś pomóc.
źródło
Wersja Obj-C odpowiedzi nirga z przykładową metodą testowania punktów. Odpowiedź Nirga działała dla mnie dobrze.
źródło
CGPathContainsPoint()
jest twoim przyjacielem.CGPathContainsPoint()
Nie ma nic piękniejszego niż indukcyjna definicja problemu. Dla kompletności tutaj masz wersję prologu, która może również wyjaśnić kwestie leżące u podstaw rzucania promieni :
Na podstawie symulacji algorytmu prostoty w http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
Niektóre przewidywania pomocnika:
Równanie linii z 2 punktami A i B (Linia (A, B)) jest następujące:
Ważne jest, aby kierunek obrotu linii był ustawiony zgodnie z ruchem wskazówek zegara dla granic i przeciwnie do zegara dla otworów. Sprawdzimy, czy punkt (X, Y), tj. Testowany punkt znajduje się w lewej półpłaszczyźnie naszej linii (jest to kwestia gustu, może to być również prawa strona, ale także kierunek granic) linie muszą zostać zmienione w tym przypadku), ma to na celu rzutowanie promienia z punktu w prawo (lub w lewo) i potwierdzenie przecięcia z linią. Zdecydowaliśmy się wyświetlać promień w kierunku poziomym (znowu jest to kwestia gustu, można to również zrobić w pionie z podobnymi ograniczeniami), więc mamy:
Teraz musimy wiedzieć, czy punkt znajduje się tylko po lewej (lub po prawej) stronie segmentu linii, a nie na całej płaszczyźnie, więc musimy ograniczyć wyszukiwanie tylko do tego segmentu, ale jest to łatwe, ponieważ można znaleźć się w tym segmencie tylko jeden punkt na linii może znajdować się wyżej niż Y w osi pionowej. Ponieważ jest to silniejsze ograniczenie, najpierw musi to sprawdzić, dlatego najpierw bierzemy tylko te linie, które spełniają ten wymóg, a następnie sprawdzamy jego możliwości. Zgodnie z twierdzeniem Curve'a Jordan promień rzutowany na wielokąt musi przecinać się w parzystej liczbie linii. Więc skończymy, rzucimy promień w prawo, a następnie za każdym razem, gdy przecina on linię, przełącza swój stan. Jednak w naszym wdrożeniu sprawdzimy długość pakietu rozwiązań spełniających podane ograniczenia i zdecydujemy o tym. należy to zrobić dla każdej linii w wielokącie.
źródło
Wersja C # odpowiedzi nirg jest tutaj: po prostu podzielę się kodem. Może komuś zaoszczędzić trochę czasu.
źródło
Wersja Java:
źródło
Port .Net:
źródło
WERSJA VBA:
Uwaga: pamiętaj, że jeśli twój wielokąt jest obszarem na mapie, szerokość i długość geograficzna są wartościami Y / X w przeciwieństwie do X / Y (szerokość geograficzna = Y, długość geograficzna = X), ponieważ z tego, co rozumiem, są implikacje historyczne z czasów, gdy Długość geograficzna nie była miarą.
MODUŁ KLASOWY: CPoint
MODUŁ:
źródło
Zrobiłem wdrożenie Pythona z nirg w C ++ kod :
Wejścia
bounding_box_positions: punkty kandydujące do filtrowania. (W mojej implementacji utworzonej z ramki granicznej.
(Wejścia są wykazy krotek w formacie:
[(xcord, ycord), ...]
)Zwroty
Ponownie pomysł zaczerpnięto stąd
źródło
Zaskoczony, że nikt wcześniej tego nie poruszał, ale dla pragmatyków wymagających bazy danych: MongoDB ma doskonałe wsparcie dla zapytań Geo, w tym tego.
To czego szukasz to:
Neighborhoods
to kolekcja przechowująca jeden lub więcej wielokątów w standardowym formacie GeoJson. Jeśli zapytanie zwraca null, nie jest przecinane, inaczej jest.Bardzo dobrze udokumentowane tutaj: https://docs.mongodb.com/manual/tutorial/geospatial-tutorial/
Wydajność dla ponad 6000 punktów sklasyfikowanych w 330 nieregularnych siatkach wielokątów była krótsza niż jedna minuta bez żadnej optymalizacji i obejmowała czas na aktualizację dokumentów za pomocą odpowiedniego wielokąta.
źródło
Oto punkt w teście wielokąta w C, który nie używa rzutowania promieniami. I może działać dla nakładających się obszarów (przecięcia siebie), patrz
use_holes
argument.Uwaga: jest to jedna z mniej optymalnych metod, ponieważ zawiera wiele wywołań
atan2f
, ale może zainteresować programistów czytających ten wątek (w moich testach jest ~ 23 razy wolniejszy niż metoda przecięcia linii).źródło
Aby wykryć trafienie w wielokąt, musimy przetestować dwie rzeczy:
źródło
Aby poradzić sobie z następującymi szczególnymi przypadkami w algorytmie rzutowania promieni :
Sprawdź, czy punkt znajduje się w złożonym wielokącie . Artykuł zapewnia łatwy sposób ich rozwiązania, więc w powyższych przypadkach nie będzie wymagane specjalne leczenie.
źródło
Można to zrobić, sprawdzając, czy obszar utworzony przez połączenie pożądanego punktu z wierzchołkami wielokąta odpowiada obszarowi samego wielokąta.
Lub możesz sprawdzić, czy suma kątów wewnętrznych od twojego punktu do każdej pary dwóch kolejnych wierzchołków wielokąta do sumy punktów kontrolnych do 360, ale mam wrażenie, że pierwsza opcja jest szybsza, ponieważ nie wymaga podziałów ani obliczeń odwrotności funkcji trygonometrycznych.
Nie wiem, co się stanie, jeśli twój wielokąt ma dziurę w środku, ale wydaje mi się, że główny pomysł można dostosować do tej sytuacji
Możesz również opublikować pytanie w społeczności matematyki. Założę się, że mają na to milion sposobów
źródło
Jeśli szukasz biblioteki skryptów Java, istnieje rozszerzenie javascript google maps v3 dla klasy Polygon, aby wykryć, czy w nim znajduje się jakiś punkt.
Rozszerzenie Google Github
źródło
Podczas używania qt(Qt 4.3+), można użyć funkcji QPolygon za containsPoint
źródło
Odpowiedź zależy od tego, czy masz proste, czy złożone wielokąty. Proste wielokąty nie mogą mieć żadnych przecięć segmentów linii. Mogą mieć dziury, ale linie nie mogą się przecinać. Złożone regiony mogą mieć przecięcia linii - mogą więc mieć zachodzące na siebie regiony lub regiony, które stykają się ze sobą tylko jednym punktem.
W przypadku prostych wielokątów najlepszym algorytmem jest algorytm rzutowania promieniowego (liczba przecinająca). W przypadku złożonych wielokątów ten algorytm nie wykrywa punktów znajdujących się w nakładających się regionach. Tak więc w przypadku złożonych wielokątów należy użyć algorytmu liczby uzwojenia.
Oto doskonały artykuł z implementacją C obu algorytmów. Próbowałem ich i działają dobrze.
http://geomalgorithms.com/a03-_inclusion.html
źródło
Wersja rozwiązania Scala firmy nirg (zakłada, że wstępne sprawdzenie prostokąta ograniczającego odbywa się osobno):
źródło
Oto wersja golang odpowiedzi @nirg (zainspirowana kodem C # przez @@ m-katz)
źródło