|
|
|
@ -1,15 +1,23 @@
|
|
|
|
|
--Render and simulate 1D wave equation.
|
|
|
|
|
local love = love
|
|
|
|
|
local old, cur, new --States add beginning of last tick, current tick, and next tick respectively.
|
|
|
|
|
local N = 15
|
|
|
|
|
local SOUNDSPEED = 0.5
|
|
|
|
|
local IMPULSESIZE = 20
|
|
|
|
|
local DAMPING = 0.01
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
local N = 17
|
|
|
|
|
local SOUNDSPEED = 2.0
|
|
|
|
|
local old, cur, new --States add beginning of last tick, current tick, and next tick respectively.
|
|
|
|
|
|
|
|
|
|
local function Current() return cur end
|
|
|
|
|
local function Next() return new end
|
|
|
|
|
local Integrate
|
|
|
|
|
local Interpolate
|
|
|
|
|
local Derivative
|
|
|
|
|
local SecondDerivative
|
|
|
|
|
local DFT
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
--Calculate discrete fourier transform of radius function.
|
|
|
|
|
local DFT
|
|
|
|
|
do
|
|
|
|
|
local twiddlec = {}
|
|
|
|
|
local twiddles = {}
|
|
|
|
@ -43,7 +51,7 @@ do
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
--Minimal-oscillation interpolant of a real function from its discrete Fourier coefficients.
|
|
|
|
|
local Interpolate = function( wave, x )
|
|
|
|
|
Interpolate = function( wave, x )
|
|
|
|
|
local re, im = wave.dftre, wave.dftim
|
|
|
|
|
local y = re[1]
|
|
|
|
|
|
|
|
|
@ -61,7 +69,7 @@ local Interpolate = function( wave, x )
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
--Derivative of the interpolation.
|
|
|
|
|
local Derivative = function( wave, x )
|
|
|
|
|
Derivative = function( wave, x )
|
|
|
|
|
local re, im = wave.dftre, wave.dftim
|
|
|
|
|
local y = 0
|
|
|
|
|
|
|
|
|
@ -79,7 +87,7 @@ local Derivative = function( wave, x )
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
--Second derivative of the interpolation.
|
|
|
|
|
local SecondDerivative = function( wave, x )
|
|
|
|
|
SecondDerivative = function( wave, x )
|
|
|
|
|
local re, im = wave.dftre, wave.dftim
|
|
|
|
|
local y = 0
|
|
|
|
|
|
|
|
|
@ -103,13 +111,20 @@ local function AliasedSinc( theta, x )
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
--Apply bandlimited impulse to wave.
|
|
|
|
|
local Impulse = function( wave, location, magnitude )
|
|
|
|
|
local speed = wave.vrad
|
|
|
|
|
local function OnImpact( impact )
|
|
|
|
|
|
|
|
|
|
local r = cur.radii
|
|
|
|
|
local theta = impact.th
|
|
|
|
|
local magnitude = IMPULSESIZE * impact.speed
|
|
|
|
|
local dt = math.max( impact.dt, 1 / 120.0 )
|
|
|
|
|
for i = 0, N - 1 do
|
|
|
|
|
speed[ i + 1 ] = speed[ i + 1 ] + magnitude * AliasedSinc( 2.0 * math.pi * i, location )
|
|
|
|
|
end
|
|
|
|
|
r[ i + 1 ] = r[ i + 1 ] + dt * magnitude * AliasedSinc( theta, 2.0 * math.pi * i / N )
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
--We've updated the positions, now we need to take a DFT
|
|
|
|
|
--in order to get the bandlimited second spatial derivative.
|
|
|
|
|
cur:DFT()
|
|
|
|
|
return Integrate( dt )
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local mt = { __index = {
|
|
|
|
@ -134,7 +149,7 @@ local function Wave( )
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for i = 1, N do
|
|
|
|
|
t.radii[i] = 1.0 + 0.05 * math.sin( i * 2.0 * math.pi / N )
|
|
|
|
|
t.radii[i] = 1.0 + 0.05 * ( i/N + math.sin( i * 2.0 * math.pi / N ))
|
|
|
|
|
t.vrad[i] = 0.0
|
|
|
|
|
end
|
|
|
|
|
DFT( t )
|
|
|
|
@ -166,11 +181,11 @@ local function Draw()
|
|
|
|
|
th = ( i - 1 + k ) * 2.0 * math.pi / N
|
|
|
|
|
local r = cur:Interpolate( th )
|
|
|
|
|
local x, y = r * math.cos( th ), r * math.sin( th )
|
|
|
|
|
--love.graphics.circle( "fill", x, y, 0.01 )
|
|
|
|
|
love.graphics.circle( "fill", th / math.pi - 1.0 , r, 0.01)
|
|
|
|
|
love.graphics.circle( "fill", x, y, 0.01 )
|
|
|
|
|
--love.graphics.circle( "fill", th / math.pi - 1.0 , r, 0.01)
|
|
|
|
|
|
|
|
|
|
--First derivative.
|
|
|
|
|
love.graphics.setColor( 0, 1.0, 0, 0.7 )
|
|
|
|
|
--[[love.graphics.setColor( 0, 1.0, 0, 0.7 )
|
|
|
|
|
r = cur:Derivative( th )
|
|
|
|
|
x, y = r * math.cos( th ), r * math.sin( th )
|
|
|
|
|
--love.graphics.circle( "fill", x, y, 0.01 )
|
|
|
|
@ -184,7 +199,7 @@ local function Draw()
|
|
|
|
|
love.graphics.circle( "fill", th / math.pi - 1.0, r, 0.01)
|
|
|
|
|
|
|
|
|
|
love.graphics.setColor( 1.0, 1.0, 1.0, 0.2 )
|
|
|
|
|
love.graphics.circle( "fill", 2.0 * ( i + k ) / N - 1.2, 0, 0.02 )
|
|
|
|
|
love.graphics.circle( "fill", 2.0 * ( i + k ) / N - 1.2, 0, 0.02 )]]
|
|
|
|
|
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
@ -195,9 +210,6 @@ local function Draw()
|
|
|
|
|
love.graphics.circle( "fill", x, y, 0.02 )
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local function OnImpact( impact )
|
|
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local function Update()
|
|
|
|
|
|
|
|
|
@ -216,12 +228,15 @@ local function Update()
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local function Integrate( step )
|
|
|
|
|
Integrate = function( step )
|
|
|
|
|
|
|
|
|
|
for i = 1, N do
|
|
|
|
|
--new.vrad[i] =
|
|
|
|
|
local rxx = cur:SecondDerivative( math.pi * 2.0 * ( i - 1 ) / N )
|
|
|
|
|
new.radii[i] = 2.0 * cur.radii[i] - old.radii[i] + step * step * SOUNDSPEED * rxx
|
|
|
|
|
local r = ( 1.0 - DAMPING ) * ( 2.0 * cur.radii[i] - old.radii[i] + step * step * SOUNDSPEED * rxx ) --Verlet
|
|
|
|
|
+ DAMPING --Damping: oscillate toward 1.
|
|
|
|
|
if r > 1.5 then r = 1.5 end
|
|
|
|
|
if r < 0.5 then r = 0.5 end
|
|
|
|
|
new.radii[i] = r
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
new:DFT( )
|
|
|
|
|