LB Booster
General >> General Board >> OBB 2D + OBB 2D colision
http://lbb.conforums.com/index.cgi?board=general&action=display&num=1446812338

OBB 2D + OBB 2D colision
Post by bluatigro on Nov 6th, 2015, 11:18am

this is a try at oriented bonding boxes
error :
- no rect shape
- obb.hit1way() error

i think i made a typo somwere

Code:
dim obb( 37 , 12 )
global corner , axes , org , x , y , pi
global true , false
false = 0
true = not( false )
corner = 0
axes = 8
org = 10
x = 0
y = 1
pi = atn( 1 ) * 4
WindowWidth = DisplayWidth
WimdowHeight = DisplayHeight
global winx , winy
winx = WindowWidth
winy = WindowHeight
nomainwin
open "obb 2d" for graphics as #m
  #m "trapclose [quit]"
  #m "size 5"
  for i = 0 to 36
    call obb.fill i , winx / 6 , winy / 2 _
    , 50 , 100 , i * 10
  next i
  call obb.fill 37 , winx - 100 , winy / 2 _
  , 50 , 100 , 30
  timer 100 , [timer]
wait
[timer]
  #m "cls"
  for i = 0 to 36
    if not( obb.hit( i , 37 ) ) then
      call obb.move i , 5 , 0
    end if
    call obb.show i
  next i
  call obb.show 37
wait
[quit]
  close #m
end

end
function dot( a,b , c,d )
  dot = a * c + b * d
end function
sub obb.show no
  cx0 = obb( no , corner + x )
  cy0 = obb( no , corner + y )
  cx1 = obb( no , corner + 2 + x )
  cy1 = obb( no , corner + 2 + y )
  cx2 = obb( no , corner + 4 + x )
  cy2 = obb( no , corner + 4 + y )
  cx3 = obb( no , corner + 6 + x )
  cy3 = obb( no , corner + 6 + y )
  #m "down"
  #m "line ";cx0;" ";cy0;" ";cx1;" ";cy1
  #m "line ";cx1;" ";cy1;" ";cx2;" ";cy2
  #m "line ";cx2;" ";cy2;" ";cx3;" ";cy3
  #m "line ";cx3;" ";cy3;" ";cx0;" ";cy0
  #m "up"
end sub
function obb.hit1way( this , other )
  uit = true
  for a = 0 to 1
    ax = obb( this , axes + a * 2 + x )
    ay = obb( this , axes + a * 2 + y )
    cx = obb( other , corner + x )
    cy = obb( other , corner + y )
    t = dot( ax , ay , cx , cy )
    tmin = t
    tmax = t
    for c = 0 to 3
      ax = obb( this , axes + a * 2 + x )
      ay = obb( this , axes + a * 2 + y )
      cx = obb( other , corner + c * 2 + x )
      cy = obb( other , corner + c * 2 + y )
      if t < tmin then
        tmin = t
      else
        if t > tmax then
          tmax = t
        end if
      end if
    next c
    o = obb( this , org + a )
    if tmin > 1 + o or tmax < o then
      uit = false
    end if
  next a
  obb.hit1way = uit
end function
function obb.hit( a , b )
  obb.hit = obb.hit1way( a , b ) _
  and obb.hit1way( b , a )
end function
sub obb.move no , dx , dy
  for i = 0 to 3
    a = obb( no , corner + i * 2 + x )
    b = obb( no , corner + i * 2 + y )
    a = a + dx
    b = b + dy
    obb( no , corner + i * 2 + x ) = a
    obb( no , corner + i * 2 + y ) = b
  next i
  call calcAxes no
end sub
sub calcAxes no
  cx0 = obb( no , corner + x )
  cy0 = obb( no , corner + y )
  cx1 = obb( no , corner + 2 + x )
  cy1 = obb( no , corner + 2 + y )
  cx3 = obb( no , corner + 6 + x )
  cy3 = obb( no , corner + 6 + y )
  ax0 = cx1 - cx0
  ay0 = cy1 - cy0
  ax1 = cx3 - cx0
  ay1 = cy3 - cy0
  l = dot( ax0 , ay0 , ax0 , ay0 ) + 1e-5
  ax0 = ax0 / l
  ay0 = ay0 / l
  o0 = dot( ax0 , ay0 , cx0 , cy0 )
  l = dot( ax1 , ay1 , ax1 , ay1 ) + 1e-5
  ax1 = ax1 / l
  ay1 = ay1 / l
  o1 = dot( ax1 , ay1 , cx0 , cy0 )
  obb( no , axes + x ) = ax0
  obb( no , axes + y ) = ax0
  obb( no , axes + 2 + x ) = ax1
  obb( no , axes + 2 + y ) = ax1
  obb( no , org ) = o0
  obb( no , org + 1 ) = o1
end sub
sub obb.fill no , cx , cy , w , h , deg
  ax = cos( rad( deg ) )
  ay = sin( rad( deg ) )
  bx = cos( rad( deg ) )
  by = 0-sin( rad( deg ) )
  ax = ax * w / 2
  ay = ay * w / 2
  bx = bx * h / 2
  by = by * h / 2
  obb( no , corner + x ) = cx - ax - bx
  obb( no , corner + y ) = cy - ay - by
  obb( no , corner + 2 + x ) = cx + ax - bx
  obb( no , corner + 2 + y ) = cy + ay - by
  obb( no , corner + 4 + x ) = cx + ax + bx
  obb( no , corner + 4 + y ) = cy + ay + by
  obb( no , corner + 6 + x ) = cx - ax + bx
  obb( no , corner + 6 + y ) = cy - ay + by
  call calcAxes no
end sub
function rad( deg )
  rad = deg * pi / 180
end function
 

Re: OBB 2D + OBB 2D colision
Post by bluatigro on Nov 11th, 2015, 09:55am


update :
- shape error fixed

error :
- no colision detected
Code:
dim obb( 37 , 12 )
global corner , axes , org , x , y , pi
global true , false
false = 0
true = not( false )
corner = 0
axes = 8
org = 10
x = 0
y = 1
pi = atn( 1 ) * 4
WindowWidth = DisplayWidth
WindowHeight = DisplayHeight
global winx , winy
winx = WindowWidth
winy = WindowHeight
nomainwin
open "obb 2d" for graphics as #m
  #m "trapclose [quit]"
  #m "size 5"
  for i = 0 to 36
    call obb.fill i , winx / 6 , winy / 2 _
    , 50 , 100 , i * 10
  next i
  call obb.fill 37 , winx * 5 / 6 , winy / 2 _
  , 50 , 100 , 15
  timer 100 , [timer]
wait
[timer]
  #m "cls"
  for i = 0 to 36
    if not( obb.hit( i , 37 ) ) then
      call obb.move i , 5 , 0
    end if
    call obb.show i
  next i
  call obb.show 37
wait
[quit]
  close #m
end

end
function dot( a,b , c,d )
  dot = a * c + b * d
end function
sub obb.show no
  cx0 = obb( no , corner + x )
  cy0 = obb( no , corner + y )
  cx1 = obb( no , corner + 2 + x )
  cy1 = obb( no , corner + 2 + y )
  cx2 = obb( no , corner + 4 + x )
  cy2 = obb( no , corner + 4 + y )
  cx3 = obb( no , corner + 6 + x )
  cy3 = obb( no , corner + 6 + y )
  #m "down"
  #m "line ";cx0;" ";cy0;" ";cx1;" ";cy1
  #m "line ";cx1;" ";cy1;" ";cx2;" ";cy2
  #m "line ";cx2;" ";cy2;" ";cx3;" ";cy3
  #m "line ";cx3;" ";cy3;" ";cx0;" ";cy0
  #m "up"
end sub
function obb.hit1way( this , other )
  uit = true
  for a = 0 to 1
    ax = obb( this , axes + a * 2 + x )
    ay = obb( this , axes + a * 2 + y )
    cx = obb( other , corner + x )
    cy = obb( other , corner + y )
    t = dot( ax , ay , cx , cy )
    tmin = t
    tmax = t
    for c = 0 to 3
      ax = obb( this , axes + a * 2 + x )
      ay = obb( this , axes + a * 2 + y )
      cx = obb( other , corner + c * 2 + x )
      cy = obb( other , corner + c * 2 + y )
      if t < tmin then
        tmin = t
      else
        if t > tmax then
          tmax = t
        end if
      end if
    next c
    o = obb( this , org + a )
    if tmin > 1 + o or tmax < o then
      uit = false
    end if
  next a
  obb.hit1way = uit
end function
function obb.hit( a , b )
  obb.hit = obb.hit1way( a , b ) _
  and obb.hit1way( b , a )
end function
sub obb.move no , dx , dy
  for i = 0 to 3
    a = obb( no , corner + i * 2 + x )
    b = obb( no , corner + i * 2 + y )
    a = a + dx
    b = b + dy
    obb( no , corner + i * 2 + x ) = a
    obb( no , corner + i * 2 + y ) = b
  next i
  call calcAxes no
end sub
sub calcAxes no
  cx0 = obb( no , corner + x )
  cy0 = obb( no , corner + y )
  cx1 = obb( no , corner + 2 + x )
  cy1 = obb( no , corner + 2 + y )
  cx3 = obb( no , corner + 6 + x )
  cy3 = obb( no , corner + 6 + y )
  ax0 = cx1 - cx0
  ay0 = cy1 - cy0
  ax1 = cx3 - cx0
  ay1 = cy3 - cy0
  l = dot( ax0 , ay0 , ax0 , ay0 ) + 1e-5
  ax0 = ax0 / l
  ay0 = ay0 / l
  o0 = dot( ax0 , ay0 , cx0 , cy0 )
  l = dot( ax1 , ay1 , ax1 , ay1 ) + 1e-5
  ax1 = ax1 / l
  ay1 = ay1 / l
  o1 = dot( ax1 , ay1 , cx0 , cy0 )
  obb( no , axes + x ) = ax0
  obb( no , axes + y ) = ax0
  obb( no , axes + 2 + x ) = ax1
  obb( no , axes + 2 + y ) = ax1
  obb( no , org ) = o0
  obb( no , org + 1 ) = o1
end sub
sub obb.fill no , cx , cy , w , h , angle
  x1 = w / 2
  y1 = h / 2
  x2 = 0 - w / 2
  y2 = h / 2
  x3 = 0 - w / 2
  y3 = 0 - h / 2
  x4 = w / 2
  y4 = 0 - h / 2
  call rotate x1 , y1 , angle
  call rotate x2 , y2 , angle
  call rotate x3 , y3 , angle
  call rotate x4 , y4 , angle
  obb( no , corner + x ) = cx + x1
  obb( no , corner + y ) = cy + y1
  obb( no , corner + 2 + x ) = cx + x2
  obb( no , corner + 2 + y ) = cy + y2
  obb( no , corner + 4 + x ) = cx + x3
  obb( no , corner + 4 + y ) = cy + y3
  obb( no , corner + 6 + x ) = cx + x4
  obb( no , corner + 6 + y ) = cy + y4
  call calcAxes no
end sub
function rad( deg )
  rad = deg * pi / 180
end function
sub rotate byref k , byref l , deg
  s = sin( rad( deg ) )
  c = cos( rad( deg ) )
  hk = k * c - l * s
  hl = k * s + l * c
  k = hk
  l = hl
end sub
 

translated from freebasic
Code:
screen 20 , 32 , 2
type t2d
public :
  dim as double x , y
  declare constructor ( nx as double = 0 , ny as double = 0 )
  declare sub fill( nx as double , ny as double )
  declare function dot( r as t2d ) as double
  declare function squaredLenght() as double
end type

constructor t2d( nx as double , ny as double )
  x = nx
  y = ny
end constructor 

sub t2d.fill( nx as double , ny as double )
  x = nx
  y = ny
end sub

function t2d.dot( r as t2d ) as double
  return  x * r.x + y * r.y 
end function 

function t2d.squaredLenght() as double
  return x ^ 2 + y ^ 2 
end function

operator + ( a as t2d , b as t2d ) as t2d
  return type( a.x + b.x , a.y + b.y )
end operator 

operator - ( a as t2d , b as t2d ) as t2d
  return type( a.x - b.x , a.y - b.y )
end operator 

operator * ( v as t2d , f as double ) as t2d
  return type( v.x * f , v.y * f )
end operator

operator / ( v as t2d , f as double ) as t2d
  return type( v.x / f , v.y / f )
end operator

const as integer false = 0
const as integer true = not false
const as double pi = atn( 1 ) * 4

function rad( gr as double ) as double
  return gr * pi / 180 
end function


type obb2d
private :
  dim as t2d corner( 4 ) , axis( 2 )
  dim as double origin( 2 )
  declare function hit1way( other as obb2d ) as integer 
  declare sub computeAxis()
public :
  declare constructor 
  declare sub fill( cx as double , cy as double _
  , w as double , h as double , angle as double )
  declare function hit( other as obb2d ) as integer 
  declare sub move( dx as double , dy as double ) 
  declare sub drawit( kl as integer )
end type 

constructor obb2d
end constructor

sub obb2d.fill( cx as double , cy as double  _
, w as double , h as double , angle as double )
  dim a as t2d , center as t2d
  a.fill cos( angle ) , sin( angle )
  dim b as t2d
  b.fill -sin( angle ) , cos( angle ) 
  center.fill cx , cy
  a *= w / 2
  b *= h / 2
  corner( 0 ) = center - a - b
  corner( 1 ) = center + a - b
  corner( 2 ) = center + a + b
  corner( 3 ) = center - a + b
  computeAxis
end sub

function obb2d.hit1way( other as obb2d ) as integer
  dim as integer a , c
  dim as double t , tMin , tMax
  for a = 0 to 1
    t = other.corner( 0 ).dot( axis( a ) )
    tMin = t
    tMax = t
    for c = 0 to 3
      t = other.corner( c ).dot( axis( a ) )
      if t < tMin then
        tMin = t
      else
        if t > tMax then
          tMax = t
        end if
      end if
    next c
    if ( tMin > 1 + origin( a ) ) or ( tMax < origin( a ) ) then
      return false
    end if
  next a
  return true
end function

sub obb2d.computeAxis()
  axis( 0 ) = corner( 1 ) - corner( 0 )
  axis( 1 ) = corner( 3 ) - corner( 0 )
  dim i as integer
  for i = 0 to 1
    axis( i ) /= axis( i ).squaredLenght()
    origin( i ) = corner( 0 ).dot( axis( i ) )
  next i
end sub

function obb2d.hit( other as obb2d ) as integer
  return hit1way( other ) and other.hit1way( this )
end function

sub obb2d.move( dx as double , dy as double )
  dim i as integer , m as t2d
  m.fill dx , dy
  for i = 0 to 3
    corner( i ) += m
  next i
  computeAxis
end sub

sub obb2d.drawit( kl as integer )
  line ( corner( 0 ).x , corner( 0 ).y ) _
       -( corner( 1 ).x , corner( 1 ).y ) , kl
  line ( corner( 1 ).x , corner( 1 ).y ) _
       -( corner( 2 ).x , corner( 2 ).y ) , kl
  line ( corner( 2 ).x , corner( 2 ).y ) _
       -( corner( 3 ).x , corner( 3 ).y ) , kl
  line ( corner( 3 ).x , corner( 3 ).y ) _
       -( corner( 0 ).x , corner( 0 ).y ) , kl
end sub


function rainbow( x as double ) as integer
  return rgb( sin( x ) * 127 + 128 _
            , sin( x + pi * 2 / 3 ) * 127 + 128 _
            , sin( x - pi * 2 / 3 ) * 127 + 128 )
end function


dim i as integer
dim a( 20 ) as obb2d
for i = 0 to 20
  a( i ).fill 200 , 350 , 100 , 200 , pi/20*i
next i
dim b as obb2d
b.fill 800 , 350 , 100 , 200 , -1 
dim in as string
screenset 1 , 0
do 
  cls
  for i = 0 to 20
    if not a( i ).hit( b ) then
      a( i ).move 1 , 0
    end if
  next i
  for i = 0 to 20
    a( i ).drawit rainbow( i * pi / 10 )
  next i
  b.drawit rgb( 255 , 255 , 255 )
  sleep 40
  flip
  in = inkey
loop while in = ""