local function p(p,r)local E=r-p if type(E)=="\110\117\109\098\101\114"then return math.abs(E)end return E.Magnitude end local r={}r.__index=r r.__type="\083\112\114\105\110\103"function r.__tostring(p)return r.__type end function r.new(p,E,u,Y)local x=setmetatable({},r)x.instant=false x.marginOfError=1e-06 u=u or 1 local q=(E*E)/(((4*p)*u)*u)x.k=p/q x.d=-E/q x.x=Y x.t=Y x.v=Y*0 return x end function r.Update(E,r)if not E.instant then local u,Y,x,q,g=E.t,E.k,E.d,E.x,E.v local A=Y*(u-q)+g*x local P=g+A*(r/2)local I=Y*(u-(q+g*(r/2)))+P*x local h=g+I*(r/2)local D=Y*(u-(q+P*(r/2)))+h*x local j=g+D*r local k=q+((g+2*(P+h))+j)*(r/6)E.x,E.v=k,g+(((A+2*(I+D))+Y*(u-(q+h*r)))+j*x)*(r/6)if p(k,E.t)>E.marginOfError then return k end end E.x,E.v=E.t,E.v*0 return E.x end return r
-- CONSTANTS

-- Private Functions

local function getAbsDist(a, b)
	local d = b - a
	if (type(d) == "number") then
		return math.abs(d)
	end
	return d.Magnitude
end

-- Class

local SpringClass = {}
SpringClass.__index = SpringClass
SpringClass.__type = "Spring"

function SpringClass:__tostring()
	return SpringClass.__type
end

-- Public Constructors

function SpringClass.new(stiffness, dampingCoeff, dampingRatio, initialPos)
	local self = setmetatable({}, SpringClass)
	
	self.instant = false
	self.marginOfError = 1E-6

	dampingRatio = dampingRatio or 1
	local m = dampingCoeff*dampingCoeff/(4*stiffness*dampingRatio*dampingRatio)
	self.k = stiffness/m
	self.d = -dampingCoeff/m
	self.x = initialPos
	self.t = initialPos
	self.v = initialPos*0

	return self
end

-- Public Methods

function SpringClass:Update(dt)
	if (not self.instant) then
		local t, k, d, x0, v0 = self.t, self.k, self.d, self.x, self.v
		local a0 = k*(t - x0) + v0*d
		local v1 = v0 + a0*(dt/2)
		local a1 = k*(t - (x0 + v0*(dt/2))) + v1*d
		local v2 = v0 + a1*(dt/2)
		local a2 = k*(t - (x0 + v1*(dt/2))) + v2*d
		local v3 = v0 + a2*dt
		local x4 = x0 + (v0 + 2*(v1 + v2) + v3)*(dt/6)
		self.x, self.v = x4, v0 + (a0 + 2*(a1 + a2) + k*(t - (x0 + v2*dt)) + v3*d)*(dt/6)
		
		if (getAbsDist(x4, self.t) > self.marginOfError) then
			return x4
		end
	end
	
	self.x, self.v = self.t, self.v*0
	return self.x
end

--

return SpringClass