Geometry 如何检测两条线段相交的位置?

Geometry 如何检测两条线段相交的位置?,geometry,line-intersection,Geometry,Line Intersection,如何确定两条直线是否相交,如果相交,则在x,y点处相交?如果矩形的每一侧是线段,而用户绘制的部分是线段,则只需检查用户绘制的线段是否与四条边线段相交。考虑到每个线段的起点和终点,这应该是一个相当简单的练习。问题归结为这个问题:从a到B和从C到D的两条直线是否相交?然后你可以问它四次(在直线和矩形四边之间) 这是做这件事的矢量数学。我假设从A到B的线是有问题的线,从C到D的线是一条矩形线。我的符号是,Ax是A的x坐标,Cy是C的y坐标,“*”表示点积,例如,A*B=Ax*Bx+Ay*By E =

如何确定两条直线是否相交,如果相交,则在x,y点处相交?

如果矩形的每一侧是线段,而用户绘制的部分是线段,则只需检查用户绘制的线段是否与四条边线段相交。考虑到每个线段的起点和终点,这应该是一个相当简单的练习。

问题归结为这个问题:从a到B和从C到D的两条直线是否相交?然后你可以问它四次(在直线和矩形四边之间)

这是做这件事的矢量数学。我假设从A到B的线是有问题的线,从C到D的线是一条矩形线。我的符号是,
Ax
是A的x坐标,
Cy
是C的y坐标,“
*
”表示点积,例如,
A*B=Ax*Bx+Ay*By

E = B-A = ( Bx-Ax, By-Ay )
F = D-C = ( Dx-Cx, Dy-Cy ) 
P = ( -Ey, Ex )
h = ( (A-C) * P ) / ( F * P )
h
编号是关键。如果
h
介于
0
1
之间,则两条线相交,否则不会相交。如果
F*P
为零,当然不能进行计算,但在这种情况下,直线是平行的,因此仅在明显的情况下相交

确切的交点是
C+F*h

更多乐趣:

如果
h
正好是
0
1
,则线在端点处接触。你可以认为这是一个“十字路口”或不是你认为合适的。< /P> 具体来说,
h
是指为了精确地接触到另一条线,必须乘以该线的长度

因此,如果
h1
矩形线位于给定线的“前面”

派生:

A和C是指向直线起点的向量;E和F是从A和C的末端开始形成直线的向量

对于平面中的任意两条非平行线,必须正好有一对标量
g
h
,这样该方程成立:

A + E*g = C + F*h
为什么??因为两条非平行线必须相交,这意味着您可以将两条线按一定比例缩放,并相互接触

(<强>起初这看起来是一个带有两个未知数的方程)<<强>但不是当你认为这是一个2D向量方程时,这意味着这真的是一个方程在<代码> x<代码>和<代码> y>代码> 我们必须消除其中一个变量。一个简单的方法是将

E
项置零。要做到这一点,用一个向量求方程两边的点积,这个向量将点与E成零。这个向量我在上面称为
P
,我对E进行了明显的变换

你现在有:

A*P = C*P + F*P*h
(A-C)*P = (F*P)*h
( (A-C)*P ) / (F*P) = h

这对我来说很有效。摘自


有一个很好的方法来解决这个问题,使用向量叉积。将二维向量叉积v×w定义为vxwy−vywx

假设两条线段从pp+r和从qq+s。那么第一行上的任何点都可以表示为p+tr(对于标量参数t),第二行上的任何点都可以表示为q+us(对于标量参数u)

如果我们能找到t和u,那么这两条线相交:

p+tr=q+us

s横穿两边,获得

p+tr)×s=(q+us)×s

由于s×s=0,这意味着

t(r×s)=(qp)×s

因此,求解t:

t=(qp)×s/(r×s

同样,我们可以为u求解:

p+tr)×r=(q+us)×r

u(s×r)=(pq)×r

u=(pq)×r/(s×r

为了减少计算步骤的数量,可以方便地重写如下(记住s×r=−r×s):

u=(qp)×r/(r×s

现在有四种情况:

  • 如果r×s=0和(qp)×r=0,则两条线共线

    在这种情况下,根据第一条线段的方程式(p+tr)表示第二条线段(qq+s)的端点:

    t0=(qp)·r/(r·r

    t1=(q+sp)·rr)=t0+sr/(r

    如果t0和t1之间的间隔与间隔[0,1]相交,则线段共线且ov
     // calculates intersection and checks for parallel lines.  
     // also checks that the intersection point is actually on  
     // the line segment p1-p2  
     Point findIntersection(Point p1,Point p2,  
       Point p3,Point p4) {  
       float xD1,yD1,xD2,yD2,xD3,yD3;  
       float dot,deg,len1,len2;  
       float segmentLen1,segmentLen2;  
       float ua,ub,div;  
    
       // calculate differences  
       xD1=p2.x-p1.x;  
       xD2=p4.x-p3.x;  
       yD1=p2.y-p1.y;  
       yD2=p4.y-p3.y;  
       xD3=p1.x-p3.x;  
       yD3=p1.y-p3.y;    
    
       // calculate the lengths of the two lines  
       len1=sqrt(xD1*xD1+yD1*yD1);  
       len2=sqrt(xD2*xD2+yD2*yD2);  
    
       // calculate angle between the two lines.  
       dot=(xD1*xD2+yD1*yD2); // dot product  
       deg=dot/(len1*len2);  
    
       // if abs(angle)==1 then the lines are parallell,  
       // so no intersection is possible  
       if(abs(deg)==1) return null;  
    
       // find intersection Pt between two lines  
       Point pt=new Point(0,0);  
       div=yD2*xD1-xD2*yD1;  
       ua=(xD2*yD3-yD2*xD3)/div;  
       ub=(xD1*yD3-yD1*xD3)/div;  
       pt.x=p1.x+ua*xD1;  
       pt.y=p1.y+ua*yD1;  
    
       // calculate the combined length of the two segments  
       // between Pt-p1 and Pt-p2  
       xD1=pt.x-p1.x;  
       xD2=pt.x-p2.x;  
       yD1=pt.y-p1.y;  
       yD2=pt.y-p2.y;  
       segmentLen1=sqrt(xD1*xD1+yD1*yD1)+sqrt(xD2*xD2+yD2*yD2);  
    
       // calculate the combined length of the two segments  
       // between Pt-p3 and Pt-p4  
       xD1=pt.x-p3.x;  
       xD2=pt.x-p4.x;  
       yD1=pt.y-p3.y;  
       yD2=pt.y-p4.y;  
       segmentLen2=sqrt(xD1*xD1+yD1*yD1)+sqrt(xD2*xD2+yD2*yD2);  
    
       // if the lengths of both sets of segments are the same as  
       // the lenghts of the two lines the point is actually  
       // on the line segment.  
    
       // if the point isn’t on the line, return null  
       if(abs(len1-segmentLen1)>0.01 || abs(len2-segmentLen2)>0.01)  
         return null;  
    
       // return the valid intersection  
       return pt;  
     }  
    
     class Point{  
       float x,y;  
       Point(float x, float y){  
         this.x = x;  
         this.y = y;  
       }  
    
       void set(float x, float y){  
         this.x = x;  
         this.y = y;  
       }  
     }  
    
        Public Function intercetion(ByVal ax As Integer, ByVal ay As Integer, ByVal bx As Integer, ByVal by As Integer, ByVal cx As Integer, ByVal cy As Integer, ByVal dx As Integer, ByVal dy As Integer) As Point
        '//  Determines the intersection point of the line segment defined by points A and B
        '//  with the line segment defined by points C and D.
        '//
        '//  Returns YES if the intersection point was found, and stores that point in X,Y.
        '//  Returns NO if there is no determinable intersection point, in which case X,Y will
        '//  be unmodified.
    
        Dim distAB, theCos, theSin, newX, ABpos As Double
    
        '//  Fail if either line segment is zero-length.
        If ax = bx And ay = by Or cx = dx And cy = dy Then Return New Point(-1, -1)
    
        '//  Fail if the segments share an end-point.
        If ax = cx And ay = cy Or bx = cx And by = cy Or ax = dx And ay = dy Or bx = dx And by = dy Then Return New Point(-1, -1)
    
        '//  (1) Translate the system so that point A is on the origin.
        bx -= ax
        by -= ay
        cx -= ax
        cy -= ay
        dx -= ax
        dy -= ay
    
        '//  Discover the length of segment A-B.
        distAB = Math.Sqrt(bx * bx + by * by)
    
        '//  (2) Rotate the system so that point B is on the positive X axis.
        theCos = bx / distAB
        theSin = by / distAB
        newX = cx * theCos + cy * theSin
        cy = cy * theCos - cx * theSin
        cx = newX
        newX = dx * theCos + dy * theSin
        dy = dy * theCos - dx * theSin
        dx = newX
    
        '//  Fail if segment C-D doesn't cross line A-B.
        If cy < 0 And dy < 0 Or cy >= 0 And dy >= 0 Then Return New Point(-1, -1)
    
        '//  (3) Discover the position of the intersection point along line A-B.
        ABpos = dx + (cx - dx) * dy / (dy - cy)
    
        '//  Fail if segment C-D crosses line A-B outside of segment A-B.
        If ABpos < 0 Or ABpos > distAB Then Return New Point(-1, -1)
    
        '//  (4) Apply the discovered position to line A-B in the original coordinate system.
        '*X=Ax+ABpos*theCos
        '*Y=Ay+ABpos*theSin
    
        '//  Success.
        Return New Point(ax + ABpos * theCos, ay + ABpos * theSin)
    End Function
    
    bool NuGeometry::IsBetween(const double& x0, const double& x, const double& x1){
       return (x >= x0) && (x <= x1);
    }
    
    bool NuGeometry::FindIntersection(const double& x0, const double& y0, 
         const double& x1, const double& y1,
         const double& a0, const double& b0, 
         const double& a1, const double& b1, 
         double& xy, double& ab) {
       // four endpoints are x0, y0 & x1,y1 & a0,b0 & a1,b1
       // returned values xy and ab are the fractional distance along xy and ab
       // and are only defined when the result is true
    
       bool partial = false;
       double denom = (b0 - b1) * (x0 - x1) - (y0 - y1) * (a0 - a1);
       if (denom == 0) {
          xy = -1;
          ab = -1;
       } else {
          xy = (a0 * (y1 - b1) + a1 * (b0 - y1) + x1 * (b1 - b0)) / denom;
          partial = NuGeometry::IsBetween(0, xy, 1);
          if (partial) {
             // no point calculating this unless xy is between 0 & 1
             ab = (y1 * (x0 - a1) + b1 * (x1 - x0) + y0 * (a1 - x1)) / denom; 
          }
       }
       if ( partial && NuGeometry::IsBetween(0, ab, 1)) {
          ab = 1-ab;
          xy = 1-xy;
          return true;
       }  else return false;
    }
    
    int get_line_intersection(float p0_x, float p0_y, float p1_x, float p1_y, 
        float p2_x, float p2_y, float p3_x, float p3_y, float *i_x, float *i_y)
    {
        float s02_x, s02_y, s10_x, s10_y, s32_x, s32_y, s_numer, t_numer, denom, t;
        s10_x = p1_x - p0_x;
        s10_y = p1_y - p0_y;
        s32_x = p3_x - p2_x;
        s32_y = p3_y - p2_y;
    
        denom = s10_x * s32_y - s32_x * s10_y;
        if (denom == 0)
            return 0; // Collinear
        bool denomPositive = denom > 0;
    
        s02_x = p0_x - p2_x;
        s02_y = p0_y - p2_y;
        s_numer = s10_x * s02_y - s10_y * s02_x;
        if ((s_numer < 0) == denomPositive)
            return 0; // No collision
    
        t_numer = s32_x * s02_y - s32_y * s02_x;
        if ((t_numer < 0) == denomPositive)
            return 0; // No collision
    
        if (((s_numer > denom) == denomPositive) || ((t_numer > denom) == denomPositive))
            return 0; // No collision
        // Collision detected
        t = t_numer / denom;
        if (i_x != NULL)
            *i_x = p0_x + (t * s10_x);
        if (i_y != NULL)
            *i_y = p0_y + (t * s10_y);
    
        return 1;
    }
    
    const AGKLine AGKLineZero = (AGKLine){(CGPoint){0.0, 0.0}, (CGPoint){0.0, 0.0}};
    
    AGKLine AGKLineMake(CGPoint start, CGPoint end)
    {
        return (AGKLine){start, end};
    }
    
    double AGKLineLength(AGKLine l)
    {
        return CGPointLengthBetween_AGK(l.start, l.end);
    }
    
    BOOL AGKLineIntersection(AGKLine l1, AGKLine l2, CGPoint *out_pointOfIntersection)
    {
        // http://stackoverflow.com/a/565282/202451
    
        CGPoint p = l1.start;
        CGPoint q = l2.start;
        CGPoint r = CGPointSubtract_AGK(l1.end, l1.start);
        CGPoint s = CGPointSubtract_AGK(l2.end, l2.start);
        
        double s_r_crossProduct = CGPointCrossProductZComponent_AGK(r, s);
        double t = CGPointCrossProductZComponent_AGK(CGPointSubtract_AGK(q, p), s) / s_r_crossProduct;
        double u = CGPointCrossProductZComponent_AGK(CGPointSubtract_AGK(q, p), r) / s_r_crossProduct;
        
        if(t < 0 || t > 1.0 || u < 0 || u > 1.0)
        {
            if(out_pointOfIntersection != NULL)
            {
                *out_pointOfIntersection = CGPointZero;
            }
            return NO;
        }
        else
        {
            if(out_pointOfIntersection != NULL)
            {
                CGPoint i = CGPointAdd_AGK(p, CGPointMultiply_AGK(r, t));
                *out_pointOfIntersection = i;
            }
            return YES;
        }
    }
    
    CGFloat CGPointCrossProductZComponent_AGK(CGPoint v1, CGPoint v2)
    {
        return v1.x * v2.y - v1.y * v2.x;
    }
    
    CGPoint CGPointSubtract_AGK(CGPoint p1, CGPoint p2)
    {
        return (CGPoint){p1.x - p2.x, p1.y - p2.y};
    }
    
    CGPoint CGPointAdd_AGK(CGPoint p1, CGPoint p2)
    {
        return (CGPoint){p1.x + p2.x, p1.y + p2.y};
    }
    
    CGFloat CGPointCrossProductZComponent_AGK(CGPoint v1, CGPoint v2)
    {
        return v1.x * v2.y - v1.y * v2.x;
    }
    
    CGPoint CGPointMultiply_AGK(CGPoint p1, CGFloat factor)
    {
        return (CGPoint){p1.x * factor, p1.y * factor};
    }
    
    function doLinesIntersect(AB, CD) {
        if (x1 == x2) {
            return !(x3 == x4 && x1 != x3);
        } else if (x3 == x4) {
            return true;
        } else {
            // Both lines are not parallel to the y-axis
            m1 = (y1-y2)/(x1-x2);
            m2 = (y3-y4)/(x3-x4);
            return m1 != m2;
        }
    }
    
    bool IsBetween (float x, float b1, float b2)
    {
       return ( ((x >= (b1 - 0.1f)) && 
            (x <= (b2 + 0.1f))) || 
            ((x >= (b2 - 0.1f)) &&
            (x <= (b1 + 0.1f))));
    }
    
    bool IsSegmentsColliding(   POINTFLOAT lineA,
                    POINTFLOAT lineB,
                    POINTFLOAT line2A,
                    POINTFLOAT line2B)
    {
        float deltaX1 = lineB.x - lineA.x;
        float deltaX2 = line2B.x - line2A.x;
        float deltaY1 = lineB.y - lineA.y;
        float deltaY2 = line2B.y - line2A.y;
    
        if (abs(deltaX1) < 0.01f && 
            abs(deltaX2) < 0.01f) // Both are vertical lines
            return false;
        if (abs((deltaY1 / deltaX1) -
            (deltaY2 / deltaX2)) < 0.001f) // Two parallel line
            return false;
    
        float xCol = (  (   (deltaX1 * deltaX2) * 
                            (line2A.y - lineA.y)) - 
                        (line2A.x * deltaY2 * deltaX1) + 
                        (lineA.x * deltaY1 * deltaX2)) / 
                     ((deltaY1 * deltaX2) - (deltaY2 * deltaX1));
        float yCol = 0;
        if (deltaX1 < 0.01f) // L1 is a vertical line
            yCol = ((xCol * deltaY2) + 
                    (line2A.y * deltaX2) - 
                    (line2A.x * deltaY2)) / deltaX2;
        else // L1 is acceptable
            yCol = ((xCol * deltaY1) +
                    (lineA.y * deltaX1) -
                    (lineA.x * deltaY1)) / deltaX1;
    
        bool isCol =    IsBetween(xCol, lineA.x, lineB.x) &&
                IsBetween(yCol, lineA.y, lineB.y) &&
                IsBetween(xCol, line2A.x, line2B.x) &&
                IsBetween(yCol, line2A.y, line2B.y);
        return isCol;
    }
    
    def find_intersection( p0, p1, p2, p3 ) :
    
        s10_x = p1[0] - p0[0]
        s10_y = p1[1] - p0[1]
        s32_x = p3[0] - p2[0]
        s32_y = p3[1] - p2[1]
    
        denom = s10_x * s32_y - s32_x * s10_y
    
        if denom == 0 : return None # collinear
    
        denom_is_positive = denom > 0
    
        s02_x = p0[0] - p2[0]
        s02_y = p0[1] - p2[1]
    
        s_numer = s10_x * s02_y - s10_y * s02_x
    
        if (s_numer < 0) == denom_is_positive : return None # no collision
    
        t_numer = s32_x * s02_y - s32_y * s02_x
    
        if (t_numer < 0) == denom_is_positive : return None # no collision
    
        if (s_numer > denom) == denom_is_positive or (t_numer > denom) == denom_is_positive : return None # no collision
    
    
        # collision detected
    
        t = t_numer / denom
    
        intersection_point = [ p0[0] + (t * s10_x), p0[1] + (t * s10_y) ]
    
    
        return intersection_point
    
    Intersect(a, b, c, d)
     if CCW(a, c, d) == CCW(b, c, d)
        return false;
     else if CCW(a, b, c) == CCW(a, b, d)
        return false;
     else
        return true;
    
    //Required input point must be colinear with the line
    bool on_segment(const V& p, const LineSegment& l)
    {
        //If a point is on the line, the sum of the vectors formed by the point to the line endpoints must be equal
        V va = p - l.pa;
        V vb = p - l.pb;
        R ma = va.magnitude();
        R mb = vb.magnitude();
        R ml = (l.pb - l.pa).magnitude();
        R s = ma + mb;
        bool r = s <= ml + epsilon;
        return r;
    }
    
    //Compute using vector math
    // Returns 0 points if the lines do not intersect or overlap
    // Returns 1 point if the lines intersect
    //  Returns 2 points if the lines overlap, contain the points where overlapping start starts and stop
    std::vector<V> intersect(const LineSegment& la, const LineSegment& lb)
    {
        std::vector<V> r;
    
        //http://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect
        V oa, ob, da, db; //Origin and direction vectors
        R sa, sb; //Scalar values
        oa = la.pa;
        da = la.pb - la.pa;
        ob = lb.pa;
        db = lb.pb - lb.pa;
    
        if (da.cross(db) == 0 && (ob - oa).cross(da) == 0) //If colinear
        {
            if (on_segment(lb.pa, la) && on_segment(lb.pb, la))
            {
                r.push_back(lb.pa);
                r.push_back(lb.pb);
                dprintf("colinear, overlapping\n");
                return r;
            }
    
            if (on_segment(la.pa, lb) && on_segment(la.pb, lb))
            {
                r.push_back(la.pa);
                r.push_back(la.pb);
                dprintf("colinear, overlapping\n");
                return r;
            }
    
            if (on_segment(la.pa, lb))
                r.push_back(la.pa);
    
            if (on_segment(la.pb, lb))
                r.push_back(la.pb);
    
            if (on_segment(lb.pa, la))
                r.push_back(lb.pa);
    
            if (on_segment(lb.pb, la))
                r.push_back(lb.pb);
    
            if (r.size() == 0)
                dprintf("colinear, non-overlapping\n");
            else
                dprintf("colinear, overlapping\n");
    
            return r;
        }
    
        if (da.cross(db) == 0 && (ob - oa).cross(da) != 0)
        {
            dprintf("parallel non-intersecting\n");
            return r;
        }
    
        //Math trick db cross db == 0, which is a single scalar in 2D.
        //Crossing both sides with vector db gives:
        sa = (ob - oa).cross(db) / da.cross(db);
    
        //Crossing both sides with vector da gives
        sb = (oa - ob).cross(da) / db.cross(da);
    
        if (0 <= sa && sa <= 1 && 0 <= sb && sb <= 1)
        {
            dprintf("intersecting\n");
            r.push_back(oa + da * sa);
            return r;
        }
    
        dprintf("non-intersecting, non-parallel, non-colinear, non-overlapping\n");
        return r;
    }
    
    public static float GetLineYIntesept(PointF p, float slope)
        {
            return p.Y - slope * p.X;
        }
    
        public static PointF FindIntersection(PointF line1Start, PointF line1End, PointF line2Start, PointF line2End)
        {
    
            float slope1 = (line1End.Y - line1Start.Y) / (line1End.X - line1Start.X);
            float slope2 = (line2End.Y - line2Start.Y) / (line2End.X - line2Start.X);
    
            float yinter1 = GetLineYIntesept(line1Start, slope1);
            float yinter2 = GetLineYIntesept(line2Start, slope2);
    
            if (slope1 == slope2 && yinter1 != yinter2)
                return PointF.Empty;
    
            float x = (yinter2 - yinter1) / (slope1 - slope2);
    
            float y = slope1 * x + yinter1;
    
            return new PointF(x, y);
        }
    
    Point3D
    
    System.Windows.Media.Media3D
    
    public static Point3D? Intersection(Point3D start1, Point3D end1, Point3D start2, Point3D end2) {
    
            double a1 = end1.Y - start1.Y;
            double b1 = start1.X - end1.X;
            double c1 = a1 * start1.X + b1 * start1.Y;
    
            double a2 = end2.Y - start2.Y;
            double b2 = start2.X - end2.X;
            double c2 = a2 * start2.X + b2 * start2.Y;
    
            double det = a1 * b2 - a2 * b1;
            if (det == 0) { // lines are parallel
                return null;
            }
    
            double x = (b2 * c1 - b1 * c2) / det;
            double y = (a1 * c2 - a2 * c1) / det;
    
            return new Point3D(x, y, 0.0);
        }
    
    public class BoundingBox {
        private Point3D min = new Point3D();
        private Point3D max = new Point3D();
    
        public BoundingBox(Point3D point) {
            min = point;
            max = point;
        }
    
        public Point3D Min {
            get { return min; }
            set { min = value; }
        }
    
        public Point3D Max {
            get { return max; }
            set { max = value; }
        }
    
        public bool Contains(BoundingBox box) {
            bool contains =
                min.X <= box.min.X && max.X >= box.max.X &&
                min.Y <= box.min.Y && max.Y >= box.max.Y &&
                min.Z <= box.min.Z && max.Z >= box.max.Z;
            return contains;
        }
    
        public bool Contains(Point3D point) {
            return Contains(new BoundingBox(point));
        }
    
    }
    
    int intersezione_linee(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, int& p_x, int& p_y)
    {
       //L1: estremi (x1,y1)(x2,y2) L2: estremi (x3,y3)(x3,y3)
       int d;
       d = (x1-x2)*(y3-y4) - (y1-y2)*(x3-x4);
       if(!d)
           return 0;
       p_x = ((x1*y2-y1*x2)*(x3-x4) - (x1-x2)*(x3*y4-y3*x4))/d;
       p_y = ((x1*y2-y1*x2)*(y3-y4) - (y1-y2)*(x3*y4-y3*x4))/d;
       return 1;
    }
    
    int in_bounding_box(int x1, int y1, int x2, int y2, int p_x, int p_y)
    {
        return p_x>=x1 && p_x<=x2 && p_y>=y1 && p_y<=y2;
    
    }
    
    int intersezione_segmenti(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4, int& p_x, int& p_y)
    {
        if (!intersezione_linee(x1,y1,x2,y2,x3,y3,x4,y4,p_x,p_y))
            return 0;
    
        return in_bounding_box(x1,y1,x2,y2,p_x,p_y) && in_bounding_box(x3,y3,x4,y4,p_x,p_y);
    }
    
    #include <iostream>
    using namespace std;
    
    struct Point
    {
        int x;
        int y;
    };
    
    // Given three colinear points p, q, r, the function checks if
    // point q lies on line segment 'pr'
    bool onSegment(Point p, Point q, Point r)
    {
        if (q.x <= max(p.x, r.x) && q.x >= min(p.x, r.x) &&
            q.y <= max(p.y, r.y) && q.y >= min(p.y, r.y))
           return true;
    
        return false;
    }
    
    // To find orientation of ordered triplet (p, q, r).
    // The function returns following values
    // 0 --> p, q and r are colinear
    // 1 --> Clockwise
    // 2 --> Counterclockwise
    int orientation(Point p, Point q, Point r)
    {
        // See 10th slides from following link for derivation of the formula
        // http://www.dcs.gla.ac.uk/~pat/52233/slides/Geometry1x1.pdf
        int val = (q.y - p.y) * (r.x - q.x) -
                  (q.x - p.x) * (r.y - q.y);
    
        if (val == 0) return 0;  // colinear
    
        return (val > 0)? 1: 2; // clock or counterclock wise
    }
    
    // The main function that returns true if line segment 'p1q1'
    // and 'p2q2' intersect.
    bool doIntersect(Point p1, Point q1, Point p2, Point q2)
    {
        // Find the four orientations needed for general and
        // special cases
        int o1 = orientation(p1, q1, p2);
        int o2 = orientation(p1, q1, q2);
        int o3 = orientation(p2, q2, p1);
        int o4 = orientation(p2, q2, q1);
    
        // General case
        if (o1 != o2 && o3 != o4)
            return true;
    
        // Special Cases
        // p1, q1 and p2 are colinear and p2 lies on segment p1q1
        if (o1 == 0 && onSegment(p1, p2, q1)) return true;
    
        // p1, q1 and p2 are colinear and q2 lies on segment p1q1
        if (o2 == 0 && onSegment(p1, q2, q1)) return true;
    
        // p2, q2 and p1 are colinear and p1 lies on segment p2q2
        if (o3 == 0 && onSegment(p2, p1, q2)) return true;
    
         // p2, q2 and q1 are colinear and q1 lies on segment p2q2
        if (o4 == 0 && onSegment(p2, q1, q2)) return true;
    
        return false; // Doesn't fall in any of the above cases
    }
    
    // Driver program to test above functions
    int main()
    {
        struct Point p1 = {1, 1}, q1 = {10, 1};
        struct Point p2 = {1, 2}, q2 = {10, 2};
    
        doIntersect(p1, q1, p2, q2)? cout << "Yes\n": cout << "No\n";
    
        p1 = {10, 0}, q1 = {0, 10};
        p2 = {0, 0}, q2 = {10, 10};
        doIntersect(p1, q1, p2, q2)? cout << "Yes\n": cout << "No\n";
    
        p1 = {-5, -5}, q1 = {0, 0};
        p2 = {1, 1}, q2 = {10, 10};
        doIntersect(p1, q1, p2, q2)? cout << "Yes\n": cout << "No\n";
    
        return 0;
    }
    
    function getLineLineCollision(p0, p1, p2, p3) {
        var s1, s2;
        s1 = {x: p1.x - p0.x, y: p1.y - p0.y};
        s2 = {x: p3.x - p2.x, y: p3.y - p2.y};
    
        var s10_x = p1.x - p0.x;
        var s10_y = p1.y - p0.y;
        var s32_x = p3.x - p2.x;
        var s32_y = p3.y - p2.y;
    
        var denom = s10_x * s32_y - s32_x * s10_y;
    
        if(denom == 0) {
            return false;
        }
    
        var denom_positive = denom > 0;
    
        var s02_x = p0.x - p2.x;
        var s02_y = p0.y - p2.y;
    
        var s_numer = s10_x * s02_y - s10_y * s02_x;
    
        if((s_numer < 0) == denom_positive) {
            return false;
        }
    
        var t_numer = s32_x * s02_y - s32_y * s02_x;
    
        if((t_numer < 0) == denom_positive) {
            return false;
        }
    
        if((s_numer > denom) == denom_positive || (t_numer > denom) == denom_positive) {
            return false;
        }
    
        var t = t_numer / denom;
    
        var p = {x: p0.x + (t * s10_x), y: p0.y + (t * s10_y)};
        return p;
    }
    
    // Some variables for reuse, others may do this differently
    var p0x, p1x, p2x, p3x, ix,
        p0y, p1y, p2y, p3y, iy,
        collisionDetected;
    
    // do stuff, call other functions, set endpoints...
    
    // note: for my purpose I use |t| < |d| as opposed to
    // |t| <= |d| which is equivalent to 0 <= t < 1 rather than
    // 0 <= t <= 1 as in Gavin's answer - results may vary
    
    var lineSegmentIntersection = function(){
        var d, dx1, dx2, dx3, dy1, dy2, dy3, s, t;
    
        dx1 = p1x - p0x;      dy1 = p1y - p0y;
        dx2 = p3x - p2x;      dy2 = p3y - p2y;
        dx3 = p0x - p2x;      dy3 = p0y - p2y;
    
        collisionDetected = 0;
    
        d = dx1 * dy2 - dx2 * dy1;
    
        if(d !== 0){
            s = dx1 * dy3 - dx3 * dy1;
            if((s <= 0 && d < 0 && s >= d) || (s >= 0 && d > 0 && s <= d)){
                t = dx2 * dy3 - dx3 * dy2;
                if((t <= 0 && d < 0 && t > d) || (t >= 0 && d > 0 && t < d)){
                    t = t / d;
                    collisionDetected = 1;
                    ix = p0x + t * dx1;
                    iy = p0y + t * dy1;
                }
            }
        }
    };
    
    import numpy as np
    
    def np_perp( a ) :
        b = np.empty_like(a)
        b[0] = a[1]
        b[1] = -a[0]
        return b
    
    def np_cross_product(a, b):
        return np.dot(a, np_perp(b))
    
    def np_seg_intersect(a, b, considerCollinearOverlapAsIntersect = False):
        # https://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect/565282#565282
        # http://www.codeproject.com/Tips/862988/Find-the-intersection-point-of-two-line-segments
        r = a[1] - a[0]
        s = b[1] - b[0]
        v = b[0] - a[0]
        num = np_cross_product(v, r)
        denom = np_cross_product(r, s)
        # If r x s = 0 and (q - p) x r = 0, then the two lines are collinear.
        if np.isclose(denom, 0) and np.isclose(num, 0):
            # 1. If either  0 <= (q - p) * r <= r * r or 0 <= (p - q) * s <= * s
            # then the two lines are overlapping,
            if(considerCollinearOverlapAsIntersect):
                vDotR = np.dot(v, r)
                aDotS = np.dot(-v, s)
                if (0 <= vDotR  and vDotR <= np.dot(r,r)) or (0 <= aDotS  and aDotS <= np.dot(s,s)):
                    return True
            # 2. If neither 0 <= (q - p) * r = r * r nor 0 <= (p - q) * s <= s * s
            # then the two lines are collinear but disjoint.
            # No need to implement this expression, as it follows from the expression above.
            return None
        if np.isclose(denom, 0) and not np.isclose(num, 0):
            # Parallel and non intersecting
            return None
        u = num / denom
        t = np_cross_product(v, s) / denom
        if u >= 0 and u <= 1 and t >= 0 and t <= 1:
            res = b[0] + (s*u)
            return res
        # Otherwise, the two line segments are not parallel but do not intersect.
        return None
    
    var point_a = {x:0, y:10},
        point_b = {x:12, y:12},
        point_c = {x:10, y:0},
        point_d = {x:0, y:0},
        slope_ab = slope(point_a, point_b),
        slope_bc = slope(point_b, point_c),
        slope_cd = slope(point_c, point_d),
        slope_da = slope(point_d, point_a),
        yint_ab = y_intercept(point_a, slope_ab),
        yint_bc = y_intercept(point_b, slope_bc),
        yint_cd = y_intercept(point_c, slope_cd),
        yint_da = y_intercept(point_d, slope_da),
        xint_ab = x_intercept(point_a, slope_ab, yint_ab),
        xint_bc = x_intercept(point_b, slope_bc, yint_bc),
        xint_cd = x_intercept(point_c, slope_cd, yint_cd),
        xint_da = x_intercept(point_d, slope_da, yint_da),
        point_aa = intersect(slope_da, yint_da, xint_da, slope_ab, yint_ab, xint_ab),
        point_bb = intersect(slope_ab, yint_ab, xint_ab, slope_bc, yint_bc, xint_bc),
        point_cc = intersect(slope_bc, yint_bc, xint_bc, slope_cd, yint_cd, xint_cd),
        point_dd = intersect(slope_cd, yint_cd, xint_cd, slope_da, yint_da, xint_da);
    
    console.log(point_a, point_b, point_c, point_d);
    console.log(slope_ab, slope_bc, slope_cd, slope_da);
    console.log(yint_ab, yint_bc, yint_cd, yint_da);
    console.log(xint_ab, xint_bc, xint_cd, xint_da);
    console.log(point_aa, point_bb, point_cc, point_dd);
    
    function slope(point_a, point_b) {
      var i = (point_b.y - point_a.y) / (point_b.x - point_a.x);
      if (i === -Infinity) return Infinity;
      if (i === -0) return 0;
      return i;
    }
    
    function y_intercept(point, slope) {
        // Horizontal Line
        if (slope == 0) return point.y;
      // Vertical Line
        if (slope == Infinity)
      {
        // THE Y-Axis
        if (point.x == 0) return Infinity;
        // No Intercept
        return null;
      }
      // Angled Line
      return point.y - (slope * point.x);
    }
    
    function x_intercept(point, slope, yint) {
        // Vertical Line
        if (slope == Infinity) return point.x;
      // Horizontal Line
        if (slope == 0)
      {
        // THE X-Axis
        if (point.y == 0) return Infinity;
        // No Intercept
        return null;
      }
      // Angled Line
      return -yint / slope;
    }
    
    // Intersection of two infinite lines
    function intersect(slope_a, yint_a, xint_a, slope_b, yint_b, xint_b) {
      if (slope_a == slope_b)
      {
        // Equal Lines
        if (yint_a == yint_b && xint_a == xint_b) return Infinity;
        // Parallel Lines
        return null;
      }
      // First Line Vertical
        if (slope_a == Infinity)
      {
        return {
            x: xint_a,
          y: (slope_b * xint_a) + yint_b
        };
      }
      // Second Line Vertical
        if (slope_b == Infinity)
      {
        return {
            x: xint_b,
          y: (slope_a * xint_b) + yint_a
        };
      }
      // Not Equal, Not Parallel, Not Vertical
      var i = (yint_b - yint_a) / (slope_a - slope_b);
      return {
        x: i,
        y: (slope_a * i) + yint_a
      };
    }
    
    public struct LineSegment2f
    {
        public Vector2f From { get; }
        public Vector2f To { get; }
    
        public LineSegment2f(Vector2f @from, Vector2f to)
        {
            From = @from;
            To = to;
        }
    
        public Vector2f Delta => new Vector2f(To.X - From.X, To.Y - From.Y);
    
        /// <summary>
        /// Attempt to intersect two line segments.
        /// </summary>
        /// <remarks>
        /// Even if the line segments do not intersect, <paramref name="t"/> and <paramref name="u"/> will be set.
        /// If the lines are parallel, <paramref name="t"/> and <paramref name="u"/> are set to <see cref="float.NaN"/>.
        /// </remarks>
        /// <param name="other">The line to attempt intersection of this line with.</param>
        /// <param name="intersectionPoint">The point of intersection if within the line segments, or empty..</param>
        /// <param name="t">The distance along this line at which intersection would occur, or NaN if lines are collinear/parallel.</param>
        /// <param name="u">The distance along the other line at which intersection would occur, or NaN if lines are collinear/parallel.</param>
        /// <returns><c>true</c> if the line segments intersect, otherwise <c>false</c>.</returns>
        public bool TryIntersect(LineSegment2f other, out Vector2f intersectionPoint, out float t, out float u)
        {
            var p = From;
            var q = other.From;
            var r = Delta;
            var s = other.Delta;
    
            // t = (q − p) × s / (r × s)
            // u = (q − p) × r / (r × s)
    
            var denom = Fake2DCross(r, s);
    
            if (denom == 0)
            {
                // lines are collinear or parallel
                t = float.NaN;
                u = float.NaN;
                intersectionPoint = default(Vector2f);
                return false;
            }
    
            var tNumer = Fake2DCross(q - p, s);
            var uNumer = Fake2DCross(q - p, r);
    
            t = tNumer / denom;
            u = uNumer / denom;
    
            if (t < 0 || t > 1 || u < 0 || u > 1)
            {
                // line segments do not intersect within their ranges
                intersectionPoint = default(Vector2f);
                return false;
            }
    
            intersectionPoint = p + r * t;
            return true;
        }
    
        private static float Fake2DCross(Vector2f a, Vector2f b)
        {
            return a.X * b.Y - a.Y * b.X;
        }
    }