local function Polar( x, y ) local arctan = math.atan2( y, x ) --maybe we don't need this line? --if arctan < 0.0 then arctan = arctan + 2.0 * math.pi end return math.sqrt( x * x + y * y ), arctan end local function tPolar( t ) return Polar( t.x, t.y ) end local function LerpWave( cur, new, alpha, x ) local a = cur:Interpolate( x ) local b = new:Interpolate( x ) return alpha * b + ( 1.0 - alpha ) * a end --Peak of alpha * cur + (1 - alpha) * new on interval [xi, xf] local function GetMinimum( cur, new, alpha, xi, xf ) local ri, rf = LerpWave( cur, new, alpha, xi ), LerpWave( cur, new, alpha, xf ) local xm = 0.5 * ( xi + xf ) local rm = LerpWave( cur, new, alpha, 0.5 * ( xi + xf ) ) return math.min( ri, rf ) end local function GetTimeFromAlpha( alpha, curM, newM ) return alpha * newM.t + ( 1.0 - alpha ) * curM.t end local function DetectCollision( curMarble, newMarble, curWave, newWave ) local t, dt, r, th, normal --Polar coordinates: local iRadius, iTheta = tPolar( curMarble ) local fRadius, fTheta = tPolar( newMarble ) local iWaveRadius = curWave:Interpolate( iTheta ) local fWaveRadius = curWave:Interpolate( fTheta ) local speed = newMarble.dx * newMarble.dx + newMarble.dy * newMarble.dy --Case 1: marble is already outside the curve. if iRadius > iWaveRadius then return { speed = speed, dt = newMarble.t - curMarble.t, t = curMarble.t, r = iWaveRadius, th = iTheta, normal = iTheta - math.atan( curWave:Derivative( iTheta ) ), } end --Case 2: marble is outside the curve by tick end. if fRadius > fWaveRadius then --This isn't right, fix later. return { speed = speed, dt = 0, t = newMarble.t, r = fWaveRadius, th = fTheta, normal = fTheta - math.atan( curWave:Derivative( iTheta ) ) } end --Case 3: check whether marble passed through analog peak. --Case 4: marble must have remained inside curve. return end return DetectCollision