Find out if 2 lines intersect [duplicate]

匿名 (未验证) 提交于 2019-12-03 01:05:01

问题:

Possible Duplicate:
How do you detect where two line segments intersect?
Determining if two line segments intersect?

Given are two lines l1=((A0, B0), (A1, B1)) and l2=((A2, B2), (A3, B3)); Ax, Bx are integers and (Ax, Bx) specify the starts and ends of the lines.

Is there a algorithm using only integer arithmetic that determines if l1 and l2 intersect? (Only a Boolean answer is needed.)

My own approach was to compute a point near the intersection point with fixed-point arithmetic. The solution (a, b) was then substituted in the following equations:

I: abs((A0 + a * (A1-A0)) - (A2 + b * (A3-A2))) II: abs((B0 + a * (B1-B0)) - (B2 + b * (B3-B2)))

My method should return true if both I and II evaluate to true.

My C++-Code:
vec.h:

#ifndef __MY_VECTOR__ #define __MY_VECTOR__ #include  template class vec { private:     VType data[dim]; public:     vec(){}     vec(VType v0, ...){             data[0] = v0;             va_list l;             va_start(l, v0);             for(unsigned int i=1; i     vec helpArith1(const vec& A, long delta){             vec r(A);             for(unsigned int i=0; i     vec operator*(const vec& v, long delta) {         return helpArith1(A, delta);     }     template     vec operator*(long delta, const vec& v){         return v * delta;     }     template     vec operator/(const vec& A, long delta) {         return helpArith1(A, delta);     }     template     vec helpArith2(const vec& A, const vec& B){         vec r;         for(unsigned int i=0; i     vec operator+(const vec& A, const vec& B){         return helpArith2(A, B);     }     template     vec operator-(const vec& A, const vec& B){         return helpArith2(A, B);     }     template     bool operator==(const vec& A, const vec& B) {             for(unsigned int i==0; i     bool operator!=(const vec& A, const vec& B) {             return !(A==B);     }     #endif 


line.h:

#ifndef __MY_LINE__ #define __MY_LINE__ #include "vec.h" unsigned long int ggt(unsigned long int A, unsigned long int B) {     if(A==0) {         if(B==0) {             return 1;         }         return B;     }     while(B!=0) {         unsigned long int temp = A % B;         A = B;         B = temp;     }     return A; } #define ABS(n) ( ((n) A, B;     explicit line(long int iA_0, long int iA_1, long int iB_0, long int iB_1) :         A(vec(iA_0(iB_0 slope() const{         vec temp = A-B;         if(temp[0] sl1 = l1.slope(), sl2 = l2.slope();     // l2.A + b*sl2 = l1.A + a*sl1     //  l2.A - l1.A = a*sl1 - b*sl2  // = (I, II)^T     // I': sl2[1] * I; II': sl2[0] * II     vec L = l2.A - l1.A, R = sl1;     L[0] = L[0] * sl2[1];        R[0] = R[0] * sl2[1];     L[1] = L[1] * sl2[0];        R[1] = R[1] * sl2[0];     // I' - II'     long int L_SUB = L[0] - L[1], R_SUB = R[0] - R[1];     if(ABS(R_SUB) == 0) {         return ABS(L_SUB) == 0;     }     long int temp = ggt(ABS(L_SUB), ABS(R_SUB));     L_SUB /= temp; R_SUB /= temp;     // R_SUB * a = L_SUB     long int a = L_SUB/R_SUB, b = ((l1.A[0] - l2.A[0])*R_SUB + L_SUB * sl1[0])/R_SUB;     // if the given lines intersect, then {a, b} must be the solution of     // l2.A - l1.A = a*sl1 - b*sl2     L = l2.A - l1.A;     long x = ABS((L[0]- (a*sl1[0]-b*sl2[0]))), y = ABS((L[1]- (a*sl1[1]-b*sl2[1])));     return x


main.cpp:

#include "line.h" int main(){     line A(0, 0, 6, 0), B(3, 3, 4, -3);     bool temp = intersect(A, B);     return 0; } 

(I am not sure if my intersect function works for all lines, but with the test data I used so far it returned with the correct result.)

回答1:

This is possible. We want to check whether both endpoins of l1 are on different sides of l2, and both endpoints of l2 are on opposite sides of l1.

To check on which side of l1=((A0, B0), (A1, B1)) a point (A, B) lies, we take:

  • an arbitrary normal vector N perpendicular to the line; one such vector is (B1-B0, A1-A0)
  • the vector P from the start of the line to the point (A, B), which is (A-A0, B-B0)

We then compute the dot product:

N ・ P = (A-A0, B-B0) ・ (B1-B0, A1-A0) = (A-A0) * (B1-B0) + (B-B0) * (A1-A0)

We're only interested in the sign: if it's positive, the point is on one side of the line; if it's negative, it's on the other. As you see, no floating point arithmetic required.

We can take advantage of the fact that numbers with opposite signs, when multiplied, always yield negative. So the full expression to determine whether two line segments ((A0, B0), (A1, B1)) and ((A2, B2), (A3, B3)) intersect is:

((A2-A0)*(B1-B0) - (B2-B0)*(A1-A0)) * ((A3-A0)*(B1-B0) - (B3-B0)*(A1-A0)) 

Test Code

Some C++ code to test the above calculation:

#include  #include   struct Point {     int x,y; };  bool isIntersecting(Point& p1, Point& p2, Point& q1, Point& q2) {     return (((q1.x-p1.x)*(p2.y-p1.y) - (q1.y-p1.y)*(p2.x-p1.x))             * ((q2.x-p1.x)*(p2.y-p1.y) - (q2.y-p1.y)*(p2.x-p1.x))   "                    " 

Results:

$ ./intersection_test 0 0 10 10 0 10 10 0 # example from the comments Segments intersect $ ./intersection_test 0 1 2 1 1 2 1 0 Segments intersect $ ./intersection_test 0 0 0 1 1 1 1 0 Segments do not intersect $ ./intersection_test 1 1 5 3 3 4 7 2 # q touches but not intersects at p2 Segments do not intersect                              $ ./intersection_test 1 1 5 3 3 4 6 2 Segments intersect 


回答2:

Two line segments intersect iff their lines intersect and the endpoints of each line segment are on opposite sides of the other segments line. At least in 2d.

Two lines intersect is an easy question in 2d.

Which side of a line a point is on is also easy.

Neither require non integer math.

I would estimate a dozen or three lines for some general geometry code, then a 6 to 10 line solution? Plus language boilerplate. And some zero length corner case checks.

Note I am distinguishing lines from segments.



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!