Search code examples
graphicsshapesoverlapangleclip

How to determine if two rectangles overlap (At angle)


I want to determine if two rectangles overlap (Not intersect). I know how to do this for axis aligned rectangles, but in this case I have one rectangle that isn't always axis aligned (aka rotated on its center). This post shows how to calculate two rectangles intersecting, but it won't classify one rectangle inside another as seen in this picture because they are overlapping, not intersecting.

In my case one of the rectangles is axis aligned (The black box) and the other one rotates (red box) so that might make this easier.

I think I'll need multiple cases to determine if they overlap. The first, easy, case would be to check if any of the red vertices are inside the black box. Then I can check if any of the red/black edges intersect. I'm not sure how I can cover the case shown above and if there's a simpler way to do this.

Extra details: This is for my graphics software clipper (Can't use hardware clipping in this case) where the Black box is my window/viewport, the red box is the "sprite" and anything outside the black box is clipped/not-rendered I am using an orthoganal/2D projection. In the end I'll have two functions, one for detecting if a sprite in outside of the window/viewport (What I'm asking in this question) and later I'll make a function to crop the sprite to within the window/viewport using Sutherland–Hodgman algorithm.

EDIT:

This is post does generally describe how to do SAT, however it doesn't go into specifics. How do I generate normals? Are "Corners" the screen coordinates or distance from the center of the shape? I've tried adapting their code for my purposes, but I can't figure out how to perform a SAT test with a list of vertexes (Screen x and y) per shape/rectangle


Solution

  • First I'd like to thank user "prideout" for pointing me in the right direction. His notes, particularly only needed 4 normals, helped me optimise my code. Oddly, the code in the link provided seemed to not work right (Detecting if the "crushed" vertexes of the shapes overlapped). I found this useful example in C++ that pointed me in the right direction and now my code work great.

    Here is my AABB-OBB overlap detector function + the SAT function (Language used is "Processing" which is Java based).

    // True if overlap, False if they don't
    boolean seperating_axis_theorem(float[] x1, float[] y1, float[] x2, float[] y2, float[] normal){
      float[] range = new float[4];  //minAlong1, maxAlong1, minAlong2, maxAlong2
      range[0] = Float.MAX_VALUE;
      range[1] = -Float.MAX_VALUE;
      range[2] = Float.MAX_VALUE;
      range[3] = -Float.MAX_VALUE;
      
      // Dot is projecting the points onto the seperating axis and then we get the max and min
      float dotVal;
      for(int i = 0; i < 4; i++){
        dotVal = dot(x1[i], y1[i], normal[0], normal[1]);
        if(dotVal < range[0]){range[0] = dotVal;}
        if(dotVal > range[1]){range[1] = dotVal;}
        
        dotVal = dot(x2[i], y2[i], normal[0], normal[1]);
        if(dotVal < range[2]){range[2] = dotVal;}
        if(dotVal > range[3]){range[3] = dotVal;}
      }
      
      if(range[1] < range[2] || range[0] > range[3]){
        return false;
      }
      
      return true;
    }
    
    // True if two shapes overlap, False otherwise
    Boolean AABB_OBB_Overlap(float[] OBB_X, float[] OBB_Y, float[] AABB_X, float[] AABB_Y){
      
      // Checking the camera's normals, simplified since we know its axis aligned so no unit vector calculations needed
      float[] range = get_range(OBB_X);  // Returns min and max of array
      if(range[1] < AABB_X[0] || range[0] > AABB_X[1]){
        return false;
      }
      range = get_range(OBB_Y);
      if(range[1] < AABB_Y[0] || range[0] > AABB_Y[2]){
        return false;
      }
      
      // Checking the sprite's normals
      float[] normal1 = unit_vector(OBB_X[1] - OBB_X[0], OBB_Y[1] - OBB_Y[0]);  // Top side
      float[] normal2 = unit_vector(OBB_X[2] - OBB_X[0], OBB_Y[2] - OBB_Y[0]);  // Left side
      
      if(!seperating_axis_theorem(OBB_X, OBB_Y, AABB_X, AABB_Y, normal1)){
        return false;
      }
      
      if(!seperating_axis_theorem(OBB_X, OBB_Y, AABB_X, AABB_Y, normal2)){
        return false;
      }
      
      // They overlap
      return true;
    }