Check for collision between two rotated rectangles

Monkey Forums/Monkey Code/Check for collision between two rotated rectangles

Xaron(Posted 2012) [#1]
Hi all,

here comes a piece of code to perform a collision check between two rotated rectangles:

Strict

Class Vector2D
  Field x:Float
  Field y:Float
End Class

Class RotRect
  Field C:Vector2D
  Field S:Vector2D  
  Field ang:Float
End Class

Function AddVectors2D:Void( v1:Vector2D, v2:Vector2D )
  v1.x += v2.x
  v1.y += v2.y
End Function

Function SubVectors2D:Void( v1:Vector2D, v2:Vector2D )
  v1.x -= v2.x
  v1.y -= v2.y
End Function

Function RotateVector2DClockwise:Void( v:Vector2D, ang:Float )
  Local t:Float
  Local cosa:Float = Cos( ang )
  Local sina:Float = Sin( ang )
  t = v.x
  v.x = t * cosa + v.y * sina
  v.y = -t * sina + v.y * cosa
End Function

' Rotated Rectangles Collision Detection, Oren Becker, 2001
Function RotRectsCollision:Bool( rr1:RotRect, rr2:RotRect )
  Local A:Vector2D
  Local B:Vector2D  ' vertices of the rotated rr2
	Local C:Vector2D  ' center of rr2
	Local BL:Vector2D
  Local TR:Vector2D ' vertices of rr2 (bottom-left, top-right)

  Local ang:Float = rr1.ang - rr2.ang ' orientation of rotated rr1
  Local cosa:Float = Cos( ang ) ' precalculated trigonometic -
  Local sina:Float = Sin( ang ) ' - values for repeated use

  Local t:Float, x:Float, a:Float ' temporary variables for various uses
  Local dx:Float                  ' deltaX for linear equations
  Local ext1:Float, ext2:Float    ' min/max vertical values

  ' move rr2 to make rr1 cannonic
  C = rr2.C
  SubVectors2D( C, rr1.C )

  ' rotate rr2 clockwise by rr2->ang to make rr2 axis-aligned
  RotateVector2DClockwise( C, rr2.ang )

  ' calculate vertices of (moved and axis-aligned := 'ma') rr2
  BL = TR = C
  SubVectors2D( BL, rr2.S )
  AddVectors2D( TR, rr2.S )

  ' calculate vertices of (rotated := 'r') rr1
  A.x = -rr1.S.y * sina
  B.x = A.x
  t = rr1.S.x * cosa
  A.x += t
  B.x -= t
  A.y =  rr1.S.y * cosa
  B.y = A.y
  t = rr1.S.x * sina
  A.y += t
  B.y -= t

  t = sina * cosa;

  ' verify that A is vertical min/max, B is horizontal min/max
  If( t < 0.0 )
    t = A.x
    A.x = B.x
    B.x = t
    t = A.y
    A.y = B.y
    B.y = t
  End If

  ' verify that B is horizontal minimum (leftest-vertex)
  If( sina < 0.0 )
    B.x = -B.x
    B.y = -B.y
  End If

  ' if rr2(ma) isn't in the horizontal range of
  ' colliding with rr1(r), collision is impossible
  If( B.x > TR.x Or B.x > -BL.x ) Then Return False

  ' if rr1(r) is axis-aligned, vertical min/max are easy to get
  If( t = 0 )
    ext1 = A.y
    ext2 = -ext1
  ' else, find vertical min/max in the range [BL.x, TR.x]
  Else
    x = BL.x - A.x
    a = TR.x - A.x
    ext1 = A.y
    ' if the first vertical min/max isn't in (BL.x, TR.x), then
    ' find the vertical min/max on BL.x or on TR.x
    If( a * x > 0.0 )
      dx = A.x
      If( x < 0.0 )
        dx -= B.x
        ext1 -= B.y
        x = a
      Else
        dx += B.x
        ext1 += B.y
      End If
      ext1 *= x
      ext1 /= dx
      ext1 += A.y
    End If
  
    x = BL.x + A.x
    a = TR.x + A.x
    ext2 = -A.y
    ' if the second vertical min/max isn't in (BL.x, TR.x), then
    ' find the local vertical min/max on BL.x or on TR.x
    If( a * x > 0.0 )
      dx = -A.x
      If( x < 0.0 )
        dx -= B.x
        ext2 -= B.y
        x = a
      Else
        dx += B.x
        ext2 += B.y
      End If
      ext2 *= x
      ext2 /= dx
      ext2 -= A.y
    End If
  End If

 ' check whether rr2(ma) is in the vertical range of colliding with rr1(r)
 ' (for the horizontal range of rr2)
 Return Not ( ( ext1 < BL.y And ext2 < BL.y ) Or ( ext1 > TR.y And ext2 > TR.y ) )
End Function



silentshark(Posted 2013) [#2]
Hi Xaron,

Thanks - this is exactly what I'm looking for.. but being stupid, I can't get it to work.

Presumably the way to use it is simply to call the RotRectsCollision function? I'm getting a compilation error "Cannot convert from bool to Vector2D" at the part of the code which reads:

' calculate vertices of (moved and axis-aligned := 'ma') rr2
  BL = TR = C


But I'm probably doing something stupid. Any chance of an example code snippit which calls the RotRectsCollision function?