I am working with C++ and SDL, hoping to create a game later. I am implementing the collision detection between rectangles and segments.
I found this (NateS user's solution) about line-rectangle collision detection on Stack Overflow. I'm working in C++ and not in Java; and though it isn't that hard to reimplement in C++ (I have to check Infinity cases), I decided to work with my own method. It works fine (so far) however I'm not sure if my method is right, because I haven't proved it mathematically (yet).
So, there are three questions:
Is my method correct mathematically?
Is there a better algorithm?
What could I make better in my code?
About my method:
I calculate a determinant of the three points. Lets take the equation of the line which holds the segment: $$\begin{vmatrix} x & y & 1 \\ x_1 & y_1 & 1 \\ x_2 & y_2 & 1 \\ \end{vmatrix} =x*(y_1 - y_2)+y*(x_2 - x_1)+x_1*y_2-x_2*y_1=0$$
So, if the point is above the line, y
will be greater, and so the the determinant value will be greater than 0 (except when the line is vertical). If is under the line, the determinant will be negative. This applies for x
too. We use this for detecting sign differences between determinants, where we use the rectangle points four times respectively for checking the coordinate with the line points. If there is a difference between sign, that means the line is going through the rectangle.
Actually, before this we check if the ends of the segment are on the same side, else we will check the collision with line and not with segment.
As I said it before, I'm not 100% percent sure, if this works perfectly. Here is the actual code (where Vector2 is used for represent points).
Determinant calculation:
//This function return the determinant of a main point with coordinates
//pmainx, pmainy and another two points: p1, p2
template <typename T>
inline double determinant(const T pmainx, const T pmainy,
const Vector2<T>& p1, const Vector2<T>& p2)
{
return pmainx * p1.y + p1.x * p2.y + p2.x * pmainy - p2.x * p1.y -
pmainx * p2.y - p1.x * pmainy;
}
Rectangle-segment collision detection function:
bool Mask::collision(Vector2double& lp1, Vector2double& lp2)
{
if (this->type == TypeRectangle)
{
//rect left side
double rleft = this->position.x - this->origin.x;
//rect right side
double rright = rleft + this->collsize.x;
//rect top side
double rtop = this->position.y - this->origin.y;
//rect bottom side
double rbottom = rtop + this->collsize.y;
//if the points are on the same side of the rectangle
if ((lp1.x < rleft && lp2.x < rleft) ||
(lp1.x > rright && lp2.x > rright) ||
(lp1.y < rtop && lp2.y < rtop) ||
(lp1.y > rbottom && lp2.y > rbottom)
)
{
return false;
}
//get determinant (this is the first determinant)
//with top-left point of rectangle
double maindelta = determinant(rleft, rtop, lp1, lp2);
//get determinant
//with top-right point of rectangle
double checkdelta = determinant(rright, rtop, lp1, lp2);
//check for sign difference
if (!((maindelta >= 0) ^ (checkdelta < 0)))
{
return true;
}
//get determinant
//bottom-right
checkdelta = determinant(rright, rbottom, lp1, lp2);
//check for sign difference
if (!((maindelta >= 0) ^ (checkdelta < 0)))
{
return true;
}
//get determinant
//bottom-left
checkdelta = determinant(rleft, rbottom, lp1, lp2);
//check for sign difference
if (!((maindelta >= 0) ^ (checkdelta < 0)))
{
return true;
}
//else no sign differences
return false;
}
//there are other cases for other meshes, not the part of this problem
}
Here is a test version in JavaScript. (Unfortunately it's not dynamic, I don't have time to develop it further).