Several algorithms for finding the intersection of line segments (JS implementation, full version)

Source: Internet
Author: User
Tags dashed line

The "intersection of segments" is a very basic geometric calculation that will be used in many games.
I now learn to sell the recent learned some of the "line intersection" algorithm said, I hope to help you.
The content of this article is very elementary, mainly for the same as I beginners, so please the algorithm Teijin Pat AH Quack

Reference
The Segment 1 (A, b) and Segment 2 (c,d) are known, where a B c d is the endpoint, and the segment intersection P is obtained. (parallel or collinear as disjoint)

algorithm one: to find the intersection of two line segments, and then determine whether the intersection is on two segments.
We can find the line intersection by the general equation of the straight line ax+by+c=0 (the ABC in the equation is the coefficient, not the endpoint mentioned above, but also the point oblique equation and the oblique-cut equation, here for the time being).
It then determines whether the intersection is on the segment based on the position of the intersection with the end of the segment. Formulas such as:

function Segmentsintr (A, B, C, D) {/** 1 Solving the linear equations, finding the intersection point of the line. **/If the denominator is0Parallel or collinear, disjoint var denominator = (b. Y-A. Y) * (d. x-C. x)-(A. x-B. x) * (c. Y-D. Y); if (denominator==0) {return False; }//The intersection coordinate of the line where the segment is located (x,y) varx= ((b. x-A. x) * (d. x-C. x) * (c. Y-A. Y) + (b. Y-A. Y) * (d. x-C. x) * A. x-(d. Y-C. Y) * (b. x-A. x) * C. x)/Denominator; Vary=-((b. Y-A. Y) * (d. Y-C. Y) * (c. x-A. x) + (b. x-A. x) * (d. Y-C. Y) * A. Y-(d. x-C. x) * (b. Y-A. Y) * C. Y)/Denominator; /** 2 Determine if the intersection is on two segments **/if (//intersection in segment1Onx-A. x) * (x-B. x) <=0&& (y-A. Y) * (y-B. Y) <=0And the intersection is also in the line segment2On && (x-C. x) * (x-D. x) <=0&& (y-C. Y) * (y-D. Y) <=0) {//return intersection P return {x:x,y:y}}//otherwise disjoint return false}

The algorithm is more clear and understandable, but the performance is not high. Because it is not sure whether the intersection is valid (on the line segment), it takes more time to calculate the intersection point first.
If the intersection is found to be invalid, then the previous calculation will be a white toss. And the whole computational process is complicated.
So is there a way of thinking that we can first determine if there is a valid intersection and then calculate it?
Obviously the answer is yes. Then there are some algorithms behind it.

algorithm Two: To determine whether the two endpoints of each segment are on either side of the other segment, the intersection of the lines where the two segments are located, otherwise disjoint.
The first step is to determine whether two points are on either side of a segment, usually using a projection method:

The normal vector of the line segment is obtained, then the point is projected onto the normal, and the relationship between the point and the segment is judged according to the position of the projection. See

The projection of point A and point B on the CD normal of the segment, when we also make a projection of the segment CD on its own normal (select point C or one of point D).
Mainly used for reference.
The midpoint a projection and point B projection on both sides of the point C projection show that the end of the segment AB is on either side of the segment CD.

Likewise, determine if the CD is on either side of the line AB.

Looking for normals, projections, and so on, it sounds complicated, and it's really complicated for me, and I wouldn't have had a few months ago (the geometry of the study was forgotten: ' () '
But fortunately, learning and implementation is not complicated, there are formulas to follow.

To find the normals of line AB:

var nx=b.y - a.y,       ny=a.x - b.x;  var normalLine = {  xy: ny };  

Note: The geometric meaning of normalline.x and normalline.y represents the direction of the normals, not the coordinates.

Find the projection position of C on the normals:

var dist= normalLine.x*c.x + normalLine.y*c.y;  
注意: 这里的"投影位置"是一个标量, 表示的是到法线原点的距离, 而不是投影点的坐标. 通常知道这个距离就足够了. 当我们把图中 点a投影(distA),点b投影(distB),点c投影(distC) 都求出来之后, 就可以很容易的根据各自的大小判断出相对位置. distA==distB==distC 时, 两条线段共线 distA==distB!=distC 时, 两条线段平行 distA 和 distB 在distC 同侧时, 两条线段不相交. distA 和 distB 在distC 异侧时, 两条线段是否相交需要再判断点c点d与线段ab的关系. 前面的那些步骤, 只是实现了"判断线段是否相交", 当结果为true
function Segmentsintr (A, B, C, D) {//Line AB normal N1    varNx1=(b.Y-A.Y), NY1=(A.X-B.x);//Segment CD normal N2    varNx2=(d.Y-C.Y), Ny2=(c.X-D.x);//Two normals do cross-multiply, if the result is 0, the segment AB and segment CD are parallel or collinear, disjoint    varDenominator=Nx1*Ny2-Ny1*NX2;if(Denominator==0) {return false; }//projection on the normal N2    varDistc_n2=Nx2*C.X+Ny2*C.YvarDista_n2=Nx2*A.X+Ny2*A.Y-distc_n2;varDistb_n2=Nx2*B.X+Ny2*B.Y-distc_n2;//Point a projection and point B projection on the same side of the point C projection (in the case of points on the segment, this example is treated as disjoint);     if(dista_n2*Distb_n2>=0) {return false; }//      //Judgment point C point D and Line ab relationship, principle ibid.    //      //projection on the normal N1    varDista_n1=Nx1*A.X+Ny1*A.YvarDistc_n1=Nx1*C.X+Ny1*C.Y-dista_n1;varDistd_n1=Nx1*D.X+Ny1*D.Y-dista_n1;if(distc_n1*Distd_n1>=0) {return false; }//Calculate intersection coordinates    varFraction=Dista_n2/denominator;varDx=Fraction*NY1, DY= -fraction *NX1;return{x:a.X+DX, y:a.Y+DY}; }

The method used to find the coordinates of the intersection point looks a bit strange, with a sense of the mind.
In fact, it and algorithm one inside the algorithm is similar, but the inside of a lot of computing items have been calculated in advance.
In other words, the part of the algorithm two to find the intersection coordinates is actually the linear linear equation group to do.

Now for a simple rough and very unscientific comparison of algorithm one and algorithm two:
1 in the best case, the complexity of the two algorithms is the same
2 worst case, algorithm one and algorithm two calculate the same amount
3 But the algorithm II provides more "premature end conditions", so the average case, the algorithm should be better two.

The actual test, the actual situation is true.

The previous two algorithms are basically more common and can handle most situations. But there's actually a better algorithm.
This is also I recently learned the new (I now learn to sell, we do not mind ah ...)

Algorithm three: To determine whether the two endpoints of each segment are on either side of the other segment, the intersection of the lines where the two segments are located, otherwise disjoint.

How do you feel the same as algorithm two AH? Don't doubt it's the same ... 囧
The so-called algorithm three, in fact, is only a modification of the algorithm two, the improvement of the place is mainly:
Instead of judging the position of points and segments by normal projection, it is judged by the triangular area of points and line segments.

Let's review the Triangle area formula: The triangle is known as three points a (x, y) b (x, Y) c (x, y) with a triangular area of:

var triArea=( (a.x - c.x) * (b.y - c.y) - (a.y - c.y) * (b.x - c.x) ) /2; 

The above formula is not difficult to understand because the two vector forks multiply by = = Two vectors of the parallelogram (with two vectors as the neighboring edge).
And because the vector is a direction, so the area is also a direction, usually we have to counter-clockwise, clockwise is negative.

The key points of the improved algorithm are:
If the Triangle area consisting of line AB and point C is different from the positive and negative sign of the triangle area formed by the segment AB and the Triangle area of Point D,
Then point C and Point D are on both sides of the line AB. As shown in the following:

The triangle shown in the dashed line, the winding direction (the three-side definition order) is different, so the positive and negative signs of the area are different.

Here's a look at the code first:
Since we just have to judge the symbol, we don't need to divide the next 2 by the Triangle area formula.

function Segmentsintr (a, B, C, D) {//Triangle ABC Area2Times Var isA_ABC= (a. x-c.x) * (B.Y-C.Y)-(a. Y-c.y) * (b.x-c.x); Triangular Abd area of2Times Var isA_abd= (a. x-d.x) * (B.Y-D.Y)-(a. Y-d.y) * (b.x-d.x); The same area symbol is two points on the same side of the line segment, disjoint (in the case of points on the segment, this example is treated as disjoint);     if(ISA_ABC*areA_abd>=0) {return false; }//Triangular CDA area2Times Var isA_CDA= (c.x-a. x) * (D.Y-a. Y)-(C.Y-a. Y) * (D.x-a. x); Triangular CDB Area2Times//Note:There is a small optimization here. No more equations are needed to calculate the area, but to add and subtract from a known three area. var isa_cdb= isA_CDA+ isA_ABC-IsA_abd ;     if(ISA_CDA* ISa_cdb>=0) {return false; }//Compute intersection coordinates var t = isA_CDA/(ISA_abd-IsA_ABC); var dx= t* (b.x-a. x), dy= t* (B.Y-a. Y); return {x:a.x + dx, y: a. Y + dy}; }

Finally, the part of intersection coordinates and the algorithm two are the same.

Algorithm three on the basis of the second algorithm, greatly simplifying the calculation steps, the code is also more streamlined. It can be said that there are three kinds of algorithms, the best. The actual test results are also true.

Of course, it's important to be honest, in JavaScript, the time complexity of the three algorithms is almost the same (especially under the V8 engine) for normal computing.
My test case is also a perverted million-level segment intersection test to pull the gap between the three algorithms.

But in terms of excellence and learning attitude, the pursuit of a better algorithm, always has its positive significance.

Several algorithms for finding the intersection of line segments (JS implementation, full version)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.