Mam zestaw punktów. Chcę podzielić je na 2 różne zestawy. Aby to zrobić, wybieram dwa punkty ( a i b ) i rysuję między nimi wyimaginowaną linię. Teraz chcę mieć wszystkie punkty, które pozostały z tej linii w jednym zestawie, a te, które są na prawo od tej linii w drugim zestawie.
Jak mogę stwierdzić dla dowolnego punktu z, czy znajduje się on w lewym czy prawym zbiorze? Próbowałem obliczyć kąt między azb - kąty mniejsze niż 180 są po prawej stronie, większe niż 180 po lewej - ale ze względu na definicję ArcCos obliczone kąty są zawsze mniejsze niż 180 °. Czy istnieje wzór do obliczania kątów większych niż 180 ° (lub jakikolwiek inny wzór do wyboru prawej lub lewej strony)?
c#
math
geometry
convex-hull
Aaginor
źródło
źródło
Odpowiedzi:
Użyj znaku wyznacznika wektorów
(AB,AM)
, gdzieM(X,Y)
jest punktem zapytania:Jest
0
na linii i+1
po jednej stronie-1
po drugiej stronie.źródło
positions
?Wypróbuj ten kod, który wykorzystuje iloczyn iloczynowy :
Gdzie a = punkt linii 1; b = punkt 2 linii; c = punkt do sprawdzenia.
Jeśli formuła jest równa 0, punkty są współliniowe.
Jeśli linia jest pozioma, zwraca prawdę, jeśli punkt znajduje się powyżej linii.
źródło
return (b.x - a.x)*(c.y - a.y) > (b.y - a.y)*(c.x - a.x);
, ale kompilator prawdopodobnie i tak to optymalizuje.Patrzysz na znak wyznacznika
Będzie dodatnia dla punktów z jednej strony i ujemna dla drugiej (i zero dla punktów na samej linii).
źródło
Wektor
(y1 - y2, x2 - x1)
jest prostopadły do linii i zawsze wskazuje w prawo (lub zawsze wskazuje w lewo, jeśli orientacja płaszczyzny jest inna niż moja).Następnie możesz obliczyć iloczyn skalarny tego wektora i
(x3 - x1, y3 - y1)
określić, czy punkt leży po tej samej stronie linii co wektor prostopadły (iloczyn skalarny>0
), czy nie.źródło
Korzystając z równania linii ab , pobierz współrzędną x na linii o tej samej współrzędnej y, co sortowany punkt.
źródło
Najpierw sprawdź, czy masz pionową linię:
Następnie oblicz nachylenie:
m = (y2-y1)/(x2-x1)
Następnie należy utworzyć równanie linii z wykorzystaniem punktu postać nachylenia:
y - y1 = m*(x-x1) + y1
. Ze względu na moje wyjaśnienie, uprość to do postaci przecięcia z nachyleniem (niekonieczne w twoim algorytmie):y = mx+b
.Teraz podłącz
(x3, y3)
dox
ay
. Oto pseudokod opisujący szczegółowo, co powinno się stać:źródło
Zaimplementowałem to w Javie i przeprowadziłem test jednostkowy (źródło poniżej). Żadne z powyższych rozwiązań nie działa. Ten kod przechodzi test jednostkowy. Jeśli ktoś znajdzie test jednostkowy, który nie przejdzie, daj mi znać.
Kod: UWAGA:
nearlyEqual(double,double)
zwraca prawdę, jeśli te dwie liczby są bardzo zbliżone.Oto test jednostkowy:
źródło
Zakładając, że punkty to (Ax, Ay) (Bx, By) i (Cx, Cy), musisz obliczyć:
(Bx - Ax) * (Cy - Ay) - (By - Ay) * (Cx - Axe)
Będzie to równe zero, jeśli punkt C znajduje się na linii utworzonej przez punkty A i B i będzie miał inny znak w zależności od strony. To, która strona to jest, zależy od orientacji twoich współrzędnych (x, y), ale możesz podłączyć wartości testowe dla A, B i C do tego wzoru, aby określić, czy wartości ujemne są po lewej czy po prawej stronie.
źródło
Chciałem dostarczyć rozwiązanie inspirowane fizyką.
Wyobraź sobie siłę przyłożoną wzdłuż linii i mierzysz moment siły działającej na punkt. Jeśli moment obrotowy jest dodatni (przeciwnie do ruchu wskazówek zegara), to punkt znajduje się „po lewej” linii, ale jeśli moment jest ujemny, punkt jest „po prawej” linii.
Więc jeśli wektor siły jest równy rozpiętości dwóch punktów definiujących linię
sprawdzasz stronę punktu
(px,py)
na podstawie znaku następującego testuźródło
w zasadzie myślę, że istnieje rozwiązanie, które jest dużo łatwiejsze i prostsze do przodu, dla dowolnego danego wielokąta, powiedzmy składającego się z czterech wierzchołków (p1, p2, p3, p4), znajdź dwa skrajnie przeciwne wierzchołki w wielokącie, w innym słów, znajdź na przykład najwyższy lewy wierzchołek (powiedzmy p1) i przeciwległy wierzchołek, który znajduje się najbardziej na dole po prawej (powiedzmy). Stąd, biorąc pod uwagę twój punkt testowy C (x, y), teraz musisz dwukrotnie sprawdzić między C i p1 oraz C i p4:
if cx> p1x AND cy> p1y ==> oznacza, że C jest niżej i na prawo od p1, a następnie jeśli cx <p2x AND cy <p2y ==> oznacza, że C jest na górze i na lewo od p4
Podsumowując, C znajduje się wewnątrz prostokąta.
Dzięki :)
źródło
@ Odpowiedź AVB w rubinie
Jeśli
det
jest dodatnie, to powyżej, jeśli ujemne, to poniżej. Jeśli 0, to jest na linii.źródło
Oto wersja, ponownie wykorzystująca logikę obejmującą wiele produktów, napisana w Clojure.
Przykładowe użycie:
To znaczy, że punkt (0, 10) znajduje się na lewo od prostej określonej przez (-3, -1) i (3, 1).
UWAGA: Ta implementacja rozwiązuje problem, którego żadna z pozostałych (jak dotąd) nie rozwiązuje! Porządek ma znaczenie przy przyznawaniu punktów, które wyznaczają linię. To znaczy, w pewnym sensie jest to „linia skierowana”. Więc w powyższym kodzie wywołanie to również daje wynik
true
:To z powodu tego fragmentu kodu:
Wreszcie, podobnie jak w przypadku innych rozwiązań opartych na iloczynach krzyżowych, rozwiązanie to zwraca wartość logiczną i nie daje trzeciego wyniku dla kolinearności. Ale da wynik, który ma sens, np:
źródło
Alternatywnym sposobem zapoznania się z rozwiązaniami oferowanymi przez netters jest zrozumienie implikacji geometrii.
Niech pqr = [P, Q, R] są punktami tworzącymi płaszczyznę podzieloną na 2 boki linią [P, R] . Mamy sprawdzić, czy dwa punkty na płaszczyźnie pqr , A, B, leżą po tej samej stronie.
Dowolny punkt T na płaszczyźnie pqr można przedstawić za pomocą 2 wektorów: v = PQ iu = RQ, jako:
T '= TQ = i * v + j * u
Teraz implikacje geometrii:
i+j: <0 0 <1 =1 >1 ---------Q------[PR]--------- <== this is PQR plane ^ pr line
Ogólnie,
Inne znaczenia geometryczne i i j (niezwiązane z tym rozwiązaniem) to:
Wartość i, j można uzyskać rozwiązując równania:
Mamy więc na płaszczyźnie 2 punkty, A, B:
A = a1 * v + a2 * u B = b1 * v + b2 * u
Jeśli A, B są po tej samej stronie, będzie to prawdą:
sign(a1+a2-1) = sign(b1+b2-1)
Zauważ, że dotyczy to również pytania: Czy A, B są po tej samej stronie płaszczyzny [P, Q, R] , w której:
T = i * P + j * Q + k * R
a i + j + k = 1 oznacza, że T jest na płaszczyźnie [P, Q, R], a znak i + j + k-1 implikuje jego boczność. Z tego mamy:
A = a1 * P + a2 * Q + a3 * R B = b1 * P + b2 * Q + b3 * R
i A, B są po tej samej stronie płaszczyzny [P, Q, R] jeśli
sign(a1+a2+a3-1) = sign(b1+b2+b3-1)
źródło