점이 선의 오른쪽인지
포인트가 있습니다. 나는 발송을 2 개의 경우에는 세트로 나누고 싶다. 이를 위해 두 점 ( a 및 b )을 선택하고 그 사이에 가상의 선을 그립니다. 이제 한 줄 에이 줄에서 남은 모든 점과 다른 줄 에이 줄에서 나온 모든 점을 갖고 싶습니다.
주어진 점 z 에 대해 왼쪽 또는 오른쪽 세트인지 어떻게 알 수 있습니까? azb 사이 의 각도를 계산하려고 합니다. 180보다 작은 각도는 거기에 있고 180보다 작은 각도가 있습니다. 그러나 ArcCos의 정의로 인해 계산 된 각도는 항상 180 °보다 작습니다. 180 °보다 큰 각도를 계산하는 공식이 있습니까?
벡터 결정자의 부호를 사용하십시오. (AB,AM)여기서 M(X,Y)쿼리 지점은 다음과 달라집니다.
position = sign((Bx - Ax) * (Y - Ay) - (By - Ay) * (X - Ax))
그것은 0선상에 +1있고, 한쪽 -1에는 다른쪽에 있습니다.
교차 제품을 사용하는이 코드를 사용 합니다.
public bool isLeft(Point a, Point b, Point c){
return ((b.X - a.X)*(c.Y - a.Y) - (b.Y - a.Y)*(c.X - a.X)) > 0;
}
여기서 a = 라인 포인트 1; b = 라인 포인트 2; c = 점검 할 지점.
수식이 0과 같으면 점이 동일 선상에있는 것입니다.
선이 가로이면 점이 선 위에 있으면 사실입니다.
당신은 결정적인 표시를 봅니다.
| x2-x1 x3-x1 |
| y2-y1 y3-y1 |
한쪽의 점은 양수이고 다른 쪽은 음수입니다 (선 자체의 점은 0).
벡터 (y1 - y2, x2 - x1)는 선에 수직이고 항상 오른쪽을 가리는 것 (평면 방향이 광산과 다른 경우 항상 가리켜).
그런 다음 해당 벡터의 내적을 계산하고 점이 (x3 - x1, y3 - y1)수직 벡터와 같은 선의 있는지에 있는지 여부를 확인할 수 있습니다 (내적> 0).
나는 관리 자바로 구현하고 단위 테스트 (아래 소스)를 실행했다. 위의 해결 중 어느 것도 작동하지. 이 코드는 단위 테스트를 통과합니다. 누구도 통과하지 못하는 단위 테스트를 발견하면 알려주십시오.
코드 : 참고 : nearlyEqual(double,double)두 숫자가 매우 가까운 경우 true를 반환합니다.
/*
* @return integer code for which side of the line ab c is on. 1 means
* left turn, -1 means right turn. Returns
* 0 if all three are on a line
*/
public static int findSide(
double ax, double ay,
double bx, double by,
double cx, double cy) {
if (nearlyEqual(bx-ax,0)) { // vertical line
if (cx < bx) {
return by > ay ? 1 : -1;
}
if (cx > bx) {
return by > ay ? -1 : 1;
}
return 0;
}
if (nearlyEqual(by-ay,0)) { // horizontal line
if (cy < by) {
return bx > ax ? -1 : 1;
}
if (cy > by) {
return bx > ax ? 1 : -1;
}
return 0;
}
double slope = (by - ay) / (bx - ax);
double yIntercept = ay - ax * slope;
double cSolution = (slope*cx) + yIntercept;
if (slope != 0) {
if (cy > cSolution) {
return bx > ax ? 1 : -1;
}
if (cy < cSolution) {
return bx > ax ? -1 : 1;
}
return 0;
}
return 0;
}
단위 테스트는 다음과 가변합니다.
@Test public void testFindSide() {
assertTrue("1", 1 == Utility.findSide(1, 0, 0, 0, -1, -1));
assertTrue("1.1", 1 == Utility.findSide(25, 0, 0, 0, -1, -14));
assertTrue("1.2", 1 == Utility.findSide(25, 20, 0, 20, -1, 6));
assertTrue("1.3", 1 == Utility.findSide(24, 20, -1, 20, -2, 6));
assertTrue("-1", -1 == Utility.findSide(1, 0, 0, 0, 1, 1));
assertTrue("-1.1", -1 == Utility.findSide(12, 0, 0, 0, 2, 1));
assertTrue("-1.2", -1 == Utility.findSide(-25, 0, 0, 0, -1, -14));
assertTrue("-1.3", -1 == Utility.findSide(1, 0.5, 0, 0, 1, 1));
assertTrue("2.1", -1 == Utility.findSide(0,5, 1,10, 10,20));
assertTrue("2.2", 1 == Utility.findSide(0,9.1, 1,10, 10,20));
assertTrue("2.3", -1 == Utility.findSide(0,5, 1,10, 20,10));
assertTrue("2.4", -1 == Utility.findSide(0,9.1, 1,10, 20,10));
assertTrue("vertical 1", 1 == Utility.findSide(1,1, 1,10, 0,0));
assertTrue("vertical 2", -1 == Utility.findSide(1,10, 1,1, 0,0));
assertTrue("vertical 3", -1 == Utility.findSide(1,1, 1,10, 5,0));
assertTrue("vertical 3", 1 == Utility.findSide(1,10, 1,1, 5,0));
assertTrue("horizontal 1", 1 == Utility.findSide(1,-1, 10,-1, 0,0));
assertTrue("horizontal 2", -1 == Utility.findSide(10,-1, 1,-1, 0,0));
assertTrue("horizontal 3", -1 == Utility.findSide(1,-1, 10,-1, 0,-9));
assertTrue("horizontal 4", 1 == Utility.findSide(10,-1, 1,-1, 0,-9));
assertTrue("positive slope 1", 1 == Utility.findSide(0,0, 10,10, 1,2));
assertTrue("positive slope 2", -1 == Utility.findSide(10,10, 0,0, 1,2));
assertTrue("positive slope 3", -1 == Utility.findSide(0,0, 10,10, 1,0));
assertTrue("positive slope 4", 1 == Utility.findSide(10,10, 0,0, 1,0));
assertTrue("negative slope 1", -1 == Utility.findSide(0,0, -10,10, 1,2));
assertTrue("negative slope 2", -1 == Utility.findSide(0,0, -10,10, 1,2));
assertTrue("negative slope 3", 1 == Utility.findSide(0,0, -10,10, -1,-2));
assertTrue("negative slope 4", -1 == Utility.findSide(-10,10, 0,0, -1,-2));
assertTrue("0", 0 == Utility.findSide(1, 0, 0, 0, -1, 0));
assertTrue("1", 0 == Utility.findSide(0,0, 0, 0, 0, 0));
assertTrue("2", 0 == Utility.findSide(0,0, 0,1, 0,2));
assertTrue("3", 0 == Utility.findSide(0,0, 2,0, 1,0));
assertTrue("4", 0 == Utility.findSide(1, -2, 0, 0, -1, 2));
}
선 ab 의 방정식을 사용하여 정렬 할 점과 동일한 y 좌표에서 선의 x 좌표를 가져옵니다.
- 점의 x> 선의 x이면 점은 선의 오른쪽에 있습니다.
- 점의 x <선의 x이면 점은 선의 왼쪽에 있습니다.
- 점의 x == 선의 x이면 점이 선에있는 것입니다.
먼저 세로줄이 있는지 확인하십시오.
if (x2-x1) == 0
if x3 < x2
it's on the left
if x3 > x2
it's on the right
else
it's on the line
그런 다음 계획을 계산하십시오. m = (y2-y1)/(x2-x1)
그런 다음 점 경사 형식을 사용하여 선의 방정식을 만듭니다 y - y1 = m*(x-x1) + y1.. 내 설명을 위해 슬로프 절편 형식으로 단순화하십시오 (알고리즘에서 필요하지 않음) y = mx+b.
이제 플러그 (x3, y3)에 x와 y. 다음은 어떤 일이 발생해야하는지 자세히 설명하는 의사 코드입니다.
if m > 0
if y3 > m*x3 + b
it's on the left
else if y3 < m*x3 + b
it's on the right
else
it's on the line
else if m < 0
if y3 < m*x3 + b
it's on the left
if y3 > m*x3+b
it's on the right
else
it's on the line
else
horizontal line; up to you what you do
기본적으로 주어진 다각형에 대해 훨씬 쉽고 간단한 솔루션이 있다고 생각합니다. 네 개의 정점 (p1, p2, p3, p4)으로 구성되어 있고, 다각형에서 두 개의 극히 반대되는 정점을 다른 곳에서 찾습니다. 예를 들어 가장 왼쪽 상단 정점 (p1이라고 함)과 가장 오른쪽 하단에 위치한 반대쪽 정점 (이라고 함)을 찾습니다. 따라서 테스트 포인트 C (x, y)가 주어지면 이제 C와 p1, C와 p4 사이를 다시 확인해야합니다.
if cx> p1x AND cy> p1y ==>는 C가 p1의 오른쪽 아래에 있음을 의미합니다. cx <p2x AND cy <p2y ==>는 C가 p4의 왼쪽에 있음을 의미합니다.
결론적으로 C는 사각형 안에 있습니다.
감사 :)
점이 (Ax, Ay) (Bx, By) 및 (Cx, Cy)라고 가정하면 다음을 계산해야합니다.
(Bx-Ax) * (Cy-Ay)-(By-Ay) * (Cx-Ax)
점 C가 점 A와 B에 의해 형성된 선에 있으면 0과 같고 측면에 따라 다른 부호를 갖습니다. 이것이 어느 쪽인지는 (x, y) 좌표의 방향에 따라 다르지만 A, B 및 C에 대한 테스트 값을이 공식에 연결하여 음수 값이 왼쪽인지 오른쪽인지 확인할 수 있습니다.
루비에서 @AVB의 대답
det = Matrix[
[(x2 - x1), (x3 - x1)],
[(y2 - y1), (y3 - y1)]
].determinant
경우 det그 아래는 위의 경우 부정적 긍정적이다. 0이면 라인에 있습니다.
여기 Clojure로 작성된 교차 곱 로직을 사용하는 버전이 있습니다.
(defn is-left? [line point]
(let [[[x1 y1] [x2 y2]] (sort line)
[x-pt y-pt] point]
(> (* (- x2 x1) (- y-pt y1)) (* (- y2 y1) (- x-pt x1)))))
사용 예 :
(is-left? [[-3 -1] [3 1]] [0 10])
true
즉, 점 (0, 10)은 (-3, -1) 및 (3, 1)에 의해 결정된 선의 왼쪽에 있습니다.
참고 :이 구현은 (지금까지) 다른 어떤 것도 해결하지 못하는 문제를 해결합니다! 라인을 결정하는 포인트를 줄 때 순서가 중요 합니다. 즉, 어떤 의미에서 "지시 된 라인"입니다. 따라서 위의 코드에서이 호출은 다음과 같은 결과도 생성합니다 true.
(is-left? [[3 1] [-3 -1]] [0 10])
true
이는 다음 코드 조각 때문입니다.
(sort line)
마지막으로 다른 외적 기반 솔루션과 마찬가지로이 솔루션은 부울을 반환하고 공선성에 대한 세 번째 결과를 제공하지 않습니다. 그러나 다음과 같이 의미있는 결과를 얻을 수 있습니다.
(is-left? [[1 1] [3 1]] [10 1])
false
물리학에서 영감을받은 솔루션을 제공하고 싶었습니다.
선을 따라 가해지는 힘을 상상해보십시오. 당신은 그 지점에 대한 힘의 토크를 측정하고 있습니다. 토크가 양수 (시계 반대 방향)이면 포인트는 라인의 "왼쪽"에 있지만 토크가 음수이면 포인트는 라인의 "오른쪽"입니다.
따라서 힘 벡터가 선을 정의하는 두 점의 범위와 같으면
fx = x_2 - x_1
fy = y_2 - y_1
다음 테스트 (px,py)의 기호를 기반으로 한 점의 측면을 테스트합니다.
var torque = fx*(py-y_1)-fy*(px-x_1)
if torque>0 then
"point on left side"
else if torque <0 then
"point on right side"
else
"point on line"
end if
netters가 제공하는 솔루션의 느낌을 얻는 또 다른 방법은 약간의 기하학 의미를 이해하는 것입니다.
pqr = [P, Q, R]을 선 [P, R]에 의해 두 변으로 나뉘는 평면을 형성하는 점이라고 합시다 . 우리는 pqr 평면의 두 점 A, B가 같은쪽에 있는지 알아 내야합니다 .
pqr 평면의 모든 점 T 는 다음과 같이 v = PQ 및 u = RQ의 두 벡터로 나타낼 수 있습니다 .
T '= TQ = i * v + j * u
이제 기하학적 의미 :
- i + j = 1 : 홍보 라인의 T
- i + j <1 : T on Sq
- i + j> 1 : Snq의 T
- i + j = 0 : T = Q
- i + j <0 : T on Sq 이상 Q.
i+j: <0 0 <1 =1 >1 ---------Q------[PR]--------- <== this is PQR plane ^ pr line
일반적으로
- I + J는 T 또는 Q는 라인 [P, R] 멀리 얼마나 떨어져 있는지를 측정이며 , 및
- i + j-1 의 부호는 T의 편협함을 의미합니다.
i 와 j 의 다른 기하학적 중요성 (이 솔루션과 관련이 없음)은 다음과 같습니다.
- i , j 는 새 좌표계에서 T에 대한 스칼라입니다. 여기서 v, u 는 새 축이고 Q 는 새 원점입니다.
- 난 , J는 로 알 수있는 흡인력 에 대한 P, R 각각. i가 클수록 T는 R 에서 멀어 집니다 ( P 에서 더 큰 당기기 ).
i, j 의 값은 다음 방정식을 해결하여 얻을 수 있습니다.
i*vx + j*ux = T'x
i*vy + j*uy = T'y
i*vz + j*uz = T'z
그래서 우리는 비행기에서 두 점, A, B가 주어집니다.
A = a1 * v + a2 * u B = b1 * v + b2 * u
A, B가 같은 편에 있으면 다음과 같이됩니다.
sign(a1+a2-1) = sign(b1+b2-1)
이것은 A, B가 평면 [P, Q, R]의 같은면에 있습니까? 라는 질문에도 적용됩니다 .
T = i * P + j * Q + k * R
그리고 난 + J + K = 1 T 비행기 [P, Q, R]과의 부호에 있음을 의미 I + J +는 K-1 의 sideness을 의미한다. 이것으로부터 우리는 :
A = a1 * P + a2 * Q + a3 * R B = b1 * P + b2 * Q + b3 * R
A, B는 평면 [P, Q, R]의 같은면에 있습니다.
sign(a1+a2+a3-1) = sign(b1+b2+b3-1)
'IT' 카테고리의 다른 글
| 사용자가 모든 그룹을 얻는 방법은 무엇입니까? (0) | 2020.07.28 |
|---|---|
| 제목을 8 방향으로 분류 할 때 체인이 if / else if 경우를 피하는 방법은 무엇입니까? (0) | 2020.07.28 |
| (flag == 0) 또는 (0 == flag) 경우 어느 것이 더 빨리 실행합니까? (0) | 2020.07.28 |
| GitHub에 Android Studio 프로젝트를 추가하는 방법 (0) | 2020.07.28 |
| NSArray보다 NSSet을 사용하는 것이 더 좋은 경우는 언제입니까? (0) | 2020.07.28 |