Jump to content

  • Log In with Google      Sign In   
  • Create Account


#Actuall0k0

Posted 10 January 2013 - 12:40 AM

It would be quite the feat if you could do this without vectors so not sure what you mean by "not vector based" smile.png

 

To keep this simple, albeit not the most efficient, I'd first make a system of equations between the line segment and the line in normal form (for each edge of the rectangle).  Ensure the t value is within 0 to 1 for the segment.  Then, find the scalar projection onto the edge of the rectangle.  It is possible that the segment resides completely in the rectangle, which means we need a point inside rectangle test.  If either point is inside the rectangle it is a positive intersection. It would look something like this:

 

 

 

const Vector2 RightPerp(const Vector2& v) {
    return Vector2(y, -x);
}

bool32 TestLineSegmentLineSegment(const Vector2& a0, const Vector2& a1, const Vector2& b0, const Vector2& b1) {
    const Vector2 a = a1 - a0;
    const Vector2 b = b1 - b0;
    const Vector2 bPerp = RightPerp(b);
    const Vector2 bPerpN = Normalize(bPerp);
    const float bPerpNDist = -Dot(bPerpN, b0);
    // dot(pn, x) = -pd
    // pt = a0 + a * t
    // dot(pn, a0 + a * t) = -pd
    // t = (-pd - dot(pn, a0)) / dot(pn, a)
    // intersects a if t is in zero to one range
    const float t = (-bPerpNDist - Dot(bPerpN, a0)) / (Dot(bPerpN, a));
    if (0.0f <= t && t <= 1.0f) {
        // this means the segment a is being intersected between a0 and a1
        const Vector2 ptOnA = a0 + a * t; // this is the point on a of the intersection
        // find the scalar projection of the point onto b and if it is in range they intersect
        const float bt = Dot(ptOnA - b0, b) / (Dot(b, b));
        if (0.0f <= bt && bt <= 1.0f) {
            return 1;
        }
    }
    return 0;
}


bool32 TestRectanglePoint(const Vector2& min, const Vector2& max, const Vector2& pt) {
    return (pt.x >= min.x && pt.y >= min.y && pt.x <= max.x && pt.y <= max.y);
}

bool32 TestRectangleLineSegment(const Vector2& min, const Vector2& max, const Vector2& a, const Vector2& b) {

    if (TestRectanglePoint(min, max, a) || TestRectanglePoint(min, max, b)) return 1;
    const Vector2 maxXMinY = Vector2(max.x, min.y);
    const Vector2 minXMaxY = Vector2(min.x, max.y);
    return (TestLineSegmentLineSegment(min, maxXMinY, a, b) || TestLineSegmentLineSegment(maxXMinY, max, a, b) || TestLineSegmentLineSegment(max, minXMaxY, a, b) || TestLineSegmentLineSegment(minXMaxY, min, a, b));
} 

 

Give this a try and let me know if you have any issues.


#2l0k0

Posted 09 January 2013 - 12:57 AM

It would be quite the feat if you could do this without vectors so not sure what you mean by "not vector based" smile.png

 

To keep this simple, albeit not the most efficient, I'd first make a system of equations between the line segment and the line in normal form (for each edge of the rectangle).  Ensure the t value is within 0 to 1 for the segment.  Then, find the scalar projection onto the edge of the rectangle.  It is possible that the segment resides completely in the rectangle, which means we need a point inside rectangle test.  If either point is inside the rectangle it is a positive intersection. It would look something like this:

 

 

 

const Vector2 RightPerp(const Vector2& v) {
    return Vector2(y, -x);
}

bool32 TestLineSegmentLineSegment(const Vector2& a0, const Vector2& a1, const Vector2& b0, const Vector2& b1) {
    const Vector2 a = a1 - a0;
    const Vector2 b = b1 - b0;
    const Vector2 bPerp = RightPerp(b);
    const Vector2 bPerpN = Normalize(bPerp);
    const float bPerpNDist = -Dot(bPerpN, b0);
    // dot(pn, x) = -pd
    // pt = a0 + a * t
    // dot(pn, a0 + a * t) = -pd
    // t = (-pd - dot(pn, a0)) / dot(pn, a)
    // intersects a if t is in zero to one range
    const float t = (-bPerpNDist - Dot(bPerpN, a0)) / (Dot(bPerpN, a));
    if (0.0f <= t && t <= 1.0f) {
        // this means the segment a is being intersected between a0 and a1
        const Vector2 ptOnA = a0 + a * t; // this is the point on a of the intersection
        // find the scalar projection of the point onto b and if it is in range they intersect
        const float bt = Dot(ptOnA - b0) / (Dot(b, b));
        if (0.0f <= bt && bt <= 1.0f) {
            return 1;
        }
    }
    return 0;
}


bool32 TestRectanglePoint(const Vector2& min, const Vector2& max, const Vector2& pt) {
    return (pt.x >= min.x && pt.y >= min.y && pt.x <= max.x && pt.y <= max.y);
}

bool32 TestRectangleLineSegment(const Vector2& min, const Vector2& max, const Vector2& a, const Vector2& b) {

    if (TestRectanglePoint(min, max, a) || TestRectanglePoint(min, max, b)) return 1;
    const Vector2 maxXMinY = Vector2(max.x, min.y);
    const Vector2 minXMaxY = Vector2(min.x, max.y);
    return (TestLineSegmentLineSegment(min, maxXMinY, a, b) || TestLineSegmentLineSegment(maxXMinY, max, a, b) || TestLineSegmentLineSegment(max, minXMaxY, a, b) || TestLineSegmentLineSegment(minXMaxY, min, a, b));
} 

 

Give this a try and let me know if you have any issues.


#1l0k0

Posted 09 January 2013 - 12:52 AM

It would be quite the feat if you could do this without vectors so not sure what you mean by "not vector based" :)

 

To keep this simple, albeit not the most efficient, I'd first make a system of equations between the line segment and the line in normal form (for each edge of the rectangle).  Ensure the t value is within 0 to 1 for the segment.  Then, find the scalar projection onto the edge of the rectangle.  It is possible that the segment resides completely in the rectangle, which means we need a point inside rectangle test.  If either point is inside the rectangle it is a positive intersection. It would look something like this:

 

 

 

const Vector2 RightPerp(const Vector2& v) {
    return Vector2(y, -x);
}

bool32 TestLineSegmentLineSegment(const Vector2& a0, const Vector2& a1, const Vector2& b0, const Vector2& b1) {
    const Vector2 a = a1 - a0;
    const Vector2 b = b1 - b0;
    const Vector2 bPerp = RightPerp(b);
    const Vector2 bPerpN = Normalize(bPerp);
    const float bPerpNDist = -Dot(bPerpN, b0);
    // dot(pn, x) = -pd
    // pt = a0 + a * t
    // dot(pn, a0 + a * t) = -pd
    // t = (-pd - dot(pn, a0)) / dot(pn, a)
    // intersects a if t is in zero to one range
    const float t = (-bPerpNDist - Dot(bPerpN, a0)) / (Dot(bPerpN, a));
    return (0.0f <= t && t <= 1.0f);
}


bool32 TestRectanglePoint(const Vector2& min, const Vector2& max, const Vector2& pt) {
    return (pt.x >= min.x && pt.y >= min.y && pt.x <= max.x && pt.y <= max.y);
}

bool32 TestRectangleLineSegment(const Vector2& min, const Vector2& max, const Vector2& a, const Vector2& b) {

    if (TestRectanglePoint(min, max, a) || TestRectanglePoint(min, max, b)) return 1;
    const Vector2 maxXMinY = Vector2(max.x, min.y);
    const Vector2 minXMaxY = Vector2(min.x, max.y);
    return (TestLineSegmentLineSegment(min, maxXMinY, a, b) || TestLineSegmentLineSegment(maxXMinY, max, a, b) || TestLineSegmentLineSegment(max, minXMaxY, a, b) || TestLineSegmentLineSegment(minXMaxY, min, a, b));
} 

 

Give this a try and let me know if you have any issues.


PARTNERS