Some algorithms for "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.
Below I now learn to sell the recently learned some of the "line intersection" algorithm summed up, I hope to be helpful to everyone.
The content of this article is very elementary, mainly for the same as I beginners, so please the algorithm Teijin Pat AH Quack

Refer to the known Segment 1 (A, b) and Segment 2 (C,D), where a B c d is the endpoint, the segment intersection p. (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:



The implementation code is as follows:

JavaScript code
  1. function Segmentsintr (A, B, C, D) {
  2. /** 1 solve the linear equations, and find the intersection of line segments. **/
  3. If the denominator is 0 parallel or collinear, does not intersect
  4. var denominator = (b.y-a.y) * (d.x-c.x)-(a.x-b.x) * (C.Y-D.Y);
  5. if (denominator==0) {
  6. return false;
  7. }
  8. Intersection coordinates of the line where the segment is located (x, y)
  9. var x = ((b.x-a.x) * (d.x-c.x) * (C.Y-A.Y)
  10. + (B.Y-A.Y) * (d.x-c.x) * a.x
  11. -(D.Y-C.Y) * (b.x-a.x) * c.x)/denominator;
  12. var y =-((B.Y-A.Y) * (D.Y-C.Y) * (c.x-a.x)
  13. + (b.x-a.x) * (D.Y-C.Y) * A.Y
  14. -(d.x-c.x) * (B.Y-A.Y) * c.y)/denominator;
  15. /** 2 Determine if the intersection is on two segments **/
  16. if (
  17. //intersection on line 1
  18. (x-a.x) * (x-b.x) <= 0 && (Y-A.Y) * (Y-B.Y) <= 0
  19. //And the intersection is also on line 2
  20. && (x-c.x) * (x-d.x) <= 0 && (Y-C.Y) * (Y-D.Y) <= 0
  21. ){
  22. //Return intersection P
  23. return {
  24. X:x,
  25. Y:y
  26. }
  27. }
  28. //Do not intersect otherwise
  29. return false
  30. }



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:

JavaScript code
    1. var nx=b.y-a.y,
    2. ny=a.x-b.x;
    3. var normalline = {x:nx, y: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:

JavaScript code
    1. var dist= normalline.x*c.x + normalline.y*c.y;



Note: the "projection position" here is a scalar that represents the distance to the normal origin, not the coordinates of the projection point.
It is usually enough to know the distance.

When we put a projection (Dista), point B projection (DISTB), point C projection (DISTC), we can easily determine the relative position according to their size.

Two lines collinear when DISTA==DISTB==DISTC
Two line segments parallel when DISTA==DISTB!=DISTC
When the Dista and Distb are on the same side of the DISTC, the two segments do not intersect.
Dista and Distb on the DISTC side, whether the two line segments intersect need to judge the relationship between Point C D and Line AB.

The preceding steps simply implement "judging if the segments intersect", and when the result is true, we also need to seek further intersections.
After the process of finding the intersection, let's look at the complete implementation of the algorithm:

JavaScript code
  1. function Segmentsintr (A, B, C, D) {
  2. //Line AB normal N1
  3. var nx1 = (b.y-a.y), NY1 = (a.x-b.x);
  4. //Segment CD normal N2
  5. var nx2 = (d.y-c.y), Ny2 = (c.x-d.x);
  6. //Two normals do cross-multiply, if the result is 0, the segment AB and segment CD are parallel or collinear, disjoint
  7. var denominator = nx1*ny2-ny1*nx2;
  8. if (denominator==0) {
  9. return false;
  10. }
  11. //projection on the normal N2
  12. var distc_n2=nx2 * c.x + ny2 * C.Y;
  13. var dista_n2=nx2 * a.x + ny2 * A.Y-DISTC_N2;
  14. var distb_n2=nx2 * b.x + ny2 * B.Y-DISTC_N2;
  15. //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);
  16. if (dista_n2*distb_n2>=0) {
  17. return false;
  18. }
  19. //  
  20. //Judgment point C point D and Line ab relationship, principle ibid.
  21. //  
  22. //projection on the normal N1
  23. var dista_n1=nx1 * a.x + NY1 * A.Y;
  24. var distc_n1=nx1 * c.x + NY1 * C.Y-DISTA_N1;
  25. var distd_n1=nx1 * d.x + NY1 * D.Y-DISTA_N1;
  26. if (distc_n1*distd_n1>=0) {
  27. return false;
  28. }
  29. //Calculate intersection coordinates
  30. var fraction= dista_n2/denominator;
  31. var dx= fraction * NY1,
  32. dy=-fraction * NX1;
  33. return {x:a.x + dx, y:a.y + dy};
  34. }



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:

JavaScript code
    1. 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.

JavaScript code
  1. function Segmentsintr (A, B, C, D) {
  2. //twice times the triangle ABC area
  3. var area_abc = (a.x-c.x) * (B.Y-C.Y)-(A.Y-C.Y) * (b.x-c.x);
  4. twice times the area of the Triangle Abd
  5. var area_abd = (a.x-d.x) * (B.Y-D.Y)-(A.Y-D.Y) * (b.x-d.x);
  6. //Area symbol same as two points on the same side of the line, disjoint (in the case of points on the line segment, this example is treated as disjoint);
  7. if (area_abc*area_abd>=0) {
  8. return false;
  9. }
  10. //twice times the area of the triangular CDA
  11. var area_cda = (c.x-a.x) * (D.Y-A.Y)-(C.Y-A.Y) * (d.x-a.x);
  12. twice times the area of the triangular CDB
  13. //Note: There is a small optimization here. It is not necessary to use the formula to calculate the area, but to add and subtract from the known three areas.
  14. var area_cdb = area_cda + area_abc-area_abd;
  15. if (AREA_CDA * area_cdb >= 0) {
  16. return false;
  17. }
  18. //Calculate intersection coordinates
  19. var t = area_cda/(AREA_ABD-AREA_ABC);
  20. var dx= t* (b.x-a.x),
  21. dy= t* (B.Y-A.Y);
  22. return {x:a.x + dx, y:a.y + dy};
  23. }




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.


All right, no more nagging, let's get here.
Now learn to sell things, inevitably have errors, but also please everyone treatise. Thank you first.



Add:
Later on Weibo @miloyip (this is the real Daniel, who will write his own 3D engine) also recommended another better algorithm, but I have not understood thoroughly.
I'll come back and share it with you when I learn.

Some algorithms for "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.