OK!
Say you have two lines AB (with endpoints A and B) and CD (with points C and D)
Any point on line AB can be represented in the following form:
P = (B - A) * k + A
Where 'P' is the point, and 'k' is a value between [0..1]. Basically k acts as a "scale" to find the point according to it's distance from A. So if P is exactly halfway between A and B, k would be 0.5
The same can be said of line CD. Any point can be represented in the following form:
Q = (D - C) * m + C
To shorten/simplify future equations, I'm going to use some shorthand and say vBA = (B-A) and vDC = (D-C)
Now, assuming AB and CD extend to infinity, that means P=Q at the intersection point.
Which further means that:
P = vBA * k + A
Q = vDC * m + C
P = Q
vBA * k + A = vDC * m + C
Now if we solve this equation for k and m, we have found the intersection point. Assuming you know standard algebra, you should be able to solve it yourself so I'll skip the steps. Basically you're left with this:
k = (vDC * m + vCA) / vBA
m = (vBA * k - vCA) / vDC
Now keep in mind that each of these equations are actually 2 equations in one, because the vectors all consist of both an x component and a y component. So, actually, we have 2 ways to find k:
k = (vDC.x * m + vCA.x) / vBA.x
and
k = (vDC.y * m + vCA.y) / vBA.y
Likewise, we have 2 ways to find m.
Using this, we can substitute 'm' in one of the 'k' equations to eliminate it as a variable:
k = (vDC.x * m + vCA.x) / vBA.x
m = (vBA.y * k - vCA.y) / vDC.y
so
k = (vDC.x * ( m ) + vCA.x) / vBA.x
k = (vDC.x * ((vBA.y * k - vCA.y) / vDC.y) + vCA.x) / vBA.x
Now we can solve for 'k' and have the result using only the given points A,B,C, and D. We can also do the same thing to get 'm'.
So after all that solving you finally get this:
k = (vDC.y*vCA.x - vDC.x*vCA.y) / (vDC.y*vBA.x - vDC.x*vBA.y)
m = (vBA.y*vCA.x - vBA.x*vCA.y) / (vDC.y*vBA.x - vDC.x*vBA.y)
But wait a moment.... don't those expressions look a little familiar?
inline double PerpDot(const Point& a,const Point& b) { return (a.y*b.x) - (a.x*b.y); }
That's right! It's good old PerpDot! That magical linear algebra function!
This means we can further simplify:
k = PerpDot(vDC,vCA) / PerpDot(vDC,vBA)
m = PerpDot(vBA,vCA) / PerpDot(vDC,vBA)
Note the bottom part for each is the same.
Knowing that we're working with finite lines -- this means k and m must both be within the range [0..1] or else there is no intersection.
Also note the divide by 0 situation. If PerpDot(vDC,vBA) is zero, there is no intersection. Remember that PerpDot gives you sin(theta) and if sin(theta) is zero, it means the lines are parallel, so they cannot intersect. Hence why the above equation wouldn't work in that case.
So all that roundabout math aside, we're left with a very, very simple function:
bool LineCollision( const Point& A, const Point& B, // line AB
const Point& C, const Point& D, // line CD
Point* out ) // filled with intersection point
{
Point vBA(B - A);
Point vDC(D - C);
double f = PerpDot(vDC,vBA);
if(!f) // lines are parallel
return false;
Point vCA(C - A);
double k = PerpDot(vDC,vCA) / f;
if(k < 0) return false;
if(k > 1) return false;
double m = PerpDot(vBA,vCA) / f;
if(m < 0) return false;
if(m > 1) return false;
if(out)
*out = (vDC * m) + C; // or (vBA * k) + A if you prefer -- same thing
return true;
}