Reputation: 6032
I found this code snippet on raywenderlich.com, however the link to the explanation wasn't valid anymore. I "translated" the answer into Swift, I hope you can understand, it's actually quite easy even without knowing the language. Could anyone explain what exactly is going on here? Thanks for any help.
class func linesCross(#line1: Line, line2: Line) -> Bool {
let denominator = (line1.end.y - line1.start.y) * (line2.end.x - line2.start.x) -
(line1.end.x - line1.start.x) * (line2.end.y - line2.start.y)
if denominator == 0 { return false } //lines are parallel
let ua = ((line1.end.x - line1.start.x) * (line2.start.y - line1.start.y) -
(line1.end.y - line1.start.y) * (line2.start.x - line1.start.x)) / denominator
let ub = ((line2.end.x - line2.start.x) * (line2.start.y - line1.start.y) -
(line2.end.y - line2.start.y) * (line2.start.x - line1.start.x)) / denominator
//lines may touch each other - no test for equality here
return ua > 0 && ua < 1 && ub > 0 && ub < 1
}
Upvotes: 2
Views: 469
Reputation: 14843
This is what the code is doing.
Every point P
in the segment AB
can be described as:
P = A + u(B - A)
for some constant 0 <= u <= 1
. In fact, when u=0
you get P=A
, and you getP=B
when u=1.
Intermediate values of u
will give you intermediate values of P
in the segment. For instance, when u = 0.5
you will get the point in the middle. In general, you can think of the parameter u
as the ratio between the lengths of AP
and AB
.
Now, if you have another segment CD
you can describe the points Q
on it in the same way, but with a different u
, which I will call v
:
Q = C + v(D - C)
Again, keep in mind that Q
lies between C
and D
if, and only if, 0 <= v <= 1
(same as above for P
).
To find the intersection between the two segments you have to equate P=Q
. In other words, you need to find u
and v
, both between 0
and 1
such that:
A + u(B - A) = C + v(D - C)
So, you have this equation and you have to see if it is solvable within the given constraints on u
and v
.
Given that A
, B
, C
and D
are points with two coordinates x,y
each, you can open the equation above into two equations:
ax + u(bx - ax) = cx + v(dx - cx)
ay + u(by - ay) = cy + v(dy - cy)
where ax = A.x
, ay = A.y
, etc., are the coordinates of the points.
Now we are left with a 2x2 linear system. In matrix form:
|bx-ax cx-dx| |u| = |cx-ax|
|by-ay cy-dy| |v| |cy-ay|
The determinant of the matrix is
det = (bx-ax)(cy-dy) - (by-ay)(cx-dx)
This quantity corresponds to the denominator
of the code snippet (please check).
Now, multiplying both sides by the cofactor matrix:
|cy-dy dx-cx|
|ay-by bx-ax|
we get
det*u = (cy-dy)(cx-ax) + (dx-cx)(cy-ay)
det*v = (ay-by)(cx-ax) + (bx-ax)(cy-ay)
which correspond to the variables ua
and ub
defined in the code (check this too!)
Finally, once you have u
and v
you can check whether they are both between 0
and 1
and in that case return that there is intersection. Otherwise, there isn't.
Upvotes: 1
Reputation: 4406
You can find a detailed segment-intersection algorithm
in the book Computational Geometry in C, Sec. 7.7.
The SegSegInt
code described there is available here.
I recommend avoiding slope calculations.
There are several "degenerate" cases that require care: collinear segments overlapping or not, one segment endpoint in the interior of the other segments, etc. I wrote the code to return an indication of these special cases.
Upvotes: 2
Reputation: 13700
For a given line the slope is
m=(y_end-y_start)/(x_end-x_start)
if two slopes are equal, the lines are parallel
m1=m1
(y1_end-y_start)/(x1_end-x1_start)=(y2_end-y2_start)/(x2_end-x2_start)
And this is equivalent to checking that the denominator is not zero,
Regarding the rest of the code, find the explanation on wikipedia under "Given two points on each line"
Upvotes: 0