Skip to content

Commit

Permalink
Merge pull request #20 from StarryWisdom/extraMath
Browse files Browse the repository at this point in the history
Make the extraMath package
  • Loading branch information
Xansta authored Jan 25, 2023
2 parents fe9a9f7 + 6983ad3 commit 7e05635
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 57 deletions.
69 changes: 39 additions & 30 deletions sandbox/extraMath.lua
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
function math.lerp (a,b,t)
extraMath = {}

function extraMath.lerp (a,b,t)
-- intended to mirror C++ lerp
-- linear interpolation
assert(type(a)=="number")
assert(type(b)=="number")
assert(type(t)=="number")
return a + t * (b - a)
end
function math.CosineInterpolate(y1,y2,mu)

function extraMath.CosineInterpolate(y1,y2,mu)
-- see http://paulbourke.net/miscellaneous/interpolation/
assert(type(y1)=="number")
assert(type(y2)=="number")
Expand All @@ -15,7 +18,8 @@ function math.CosineInterpolate(y1,y2,mu)
assert(type(mu2)=="number")
return (y1*(1-mu2)+y2*mu2)
end
function math._CosineInterpolateTableInner(tbl,elmt,t)

function extraMath._CosineInterpolateTableInner(tbl,elmt,t)
assert(type(tbl)=="table")
assert(type(t)=="number")
assert(type(elmt)=="number")
Expand All @@ -25,20 +29,21 @@ function math._CosineInterpolateTableInner(tbl,elmt,t)
return tbl[elmt].y
end
local t_scaled=(t-tbl[elmt].x)*(1/x_delta)
return math.CosineInterpolate(tbl[elmt].y,tbl[elmt+1].y,t_scaled)
return extraMath.CosineInterpolate(tbl[elmt].y,tbl[elmt+1].y,t_scaled)
end
function math.CosineInterpolateTable(tbl,t)

function extraMath.CosineInterpolateTable(tbl,t)
assert(type(tbl)=="table")
assert(type(t)=="number")
assert(#tbl>1)
for i=1,#tbl-1 do
if tbl[i+1].x>t then
return math._CosineInterpolateTableInner(tbl,i,t)
return extraMath._CosineInterpolateTableInner(tbl,i,t)
end
end
return math._CosineInterpolateTableInner(tbl,#tbl-1,t)
return extraMath._CosineInterpolateTableInner(tbl,#tbl-1,t)
end
function math.CubicInterpolate(y0,y1,y2,y3,mu)
function extraMath.CubicInterpolate(y0,y1,y2,y3,mu)
-- see http://paulbourke.net/miscellaneous/interpolation/
assert(type(y0)=="number")
assert(type(y1)=="number")
Expand All @@ -52,7 +57,7 @@ function math.CubicInterpolate(y0,y1,y2,y3,mu)
local a3 = y1;
return(a0*mu*mu2+a1*mu2+a2*mu+a3);
end
function math.CubicInterpolate2DTable(tbl,t)
function extraMath.CubicInterpolate2DTable(tbl,t)
-- this takes an array with 2 elements each (x and y)
-- and returns the Cubic interpolation for the (floating point) element t
-- it would be tricky and not very useful allowing a table with 3 elements and t==1
Expand All @@ -65,21 +70,23 @@ function math.CubicInterpolate2DTable(tbl,t)
assert(math.ceil(t)+1<=#tbl,"CubicInterpolate2DTable tbl must have one one more element than the size of t")
local i = math.floor(t)
local mu = t - i
local x = math.CubicInterpolate(tbl[i].x,tbl[i+1].x,tbl[i+2].x,tbl[i+3].x,mu)
local y = math.CubicInterpolate(tbl[i].y,tbl[i+1].y,tbl[i+2].y,tbl[i+3].y,mu)
local x = extraMath.CubicInterpolate(tbl[i].x,tbl[i+1].x,tbl[i+2].x,tbl[i+3].x,mu)
local y = extraMath.CubicInterpolate(tbl[i].y,tbl[i+1].y,tbl[i+2].y,tbl[i+3].y,mu)
return x,y
end
function math.lerpTest()
assert(math.lerp(1,2,0)==1)
assert(math.lerp(1,2,1)==2)
assert(math.lerp(2,1,0)==2)
assert(math.lerp(2,1,1)==1)
assert(math.lerp(2,1,.5)==1.5)

function extraMath:lerpTest()
assert(extraMath.lerp(1,2,0)==1)
assert(extraMath.lerp(1,2,1)==2)
assert(extraMath.lerp(2,1,0)==2)
assert(extraMath.lerp(2,1,1)==1)
assert(extraMath.lerp(2,1,.5)==1.5)
-- extrapolation
assert(math.lerp(1,2,-1)==0)
assert(math.lerp(1,2,2)==3)
assert(extraMath.lerp(1,2,-1)==0)
assert(extraMath.lerp(1,2,2)==3)
end
function math.clamp(value,lo,hi)

function extraMath.clamp(value,lo,hi)
-- intended to mirror C++ clamp
-- clamps value within the range of low and high
assert(type(value)=="number")
Expand All @@ -93,16 +100,18 @@ function math.clamp(value,lo,hi)
end
return value
end
function math.clampTest()
assert(math.clamp(0,1,2)==1)
assert(math.clamp(3,1,2)==2)
assert(math.clamp(1.5,1,2)==1.5)

assert(math.clamp(0,2,3)==2)
assert(math.clamp(4,2,3)==3)
assert(math.clamp(2.5,2,3)==2.5)
function extraMath:clampTest()
assert(extraMath.clamp(0,1,2)==1)
assert(extraMath.clamp(3,1,2)==2)
assert(extraMath.clamp(1.5,1,2)==1.5)

assert(extraMath.clamp(0,2,3)==2)
assert(extraMath.clamp(4,2,3)==3)
assert(extraMath.clamp(2.5,2,3)==2.5)
end
function math.extraTests()
math.lerpTest()
math.clampTest()

function extraMath:runTests()
extraMath:lerpTest()
extraMath:clampTest()
end
28 changes: 14 additions & 14 deletions sandbox/library.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1096,16 +1096,16 @@ function updateSystem:addEnergyDecayCurve(obj, total_time, curve_x, curve_y)
},
update = function (self, obj, delta)
self.elapsed_time = self.elapsed_time + delta
local time_ratio = math.clamp(0,1,self.elapsed_time / self.total_time)
local time_ratio = extraMath.clamp(0,1,self.elapsed_time / self.total_time)
local curve={-- bah this is bad but until the update edit is better its needed
{x = self.curve_x[1], y = self.curve_y[1]},
{x = self.curve_x[2], y = self.curve_y[2]},
{x = self.curve_x[3], y = self.curve_y[3]},
{x = self.curve_x[4], y = self.curve_y[4]}
}
local energy_drain_per_second=math.CosineInterpolateTable(curve,time_ratio)
local energy_drain_per_second=extraMath.CosineInterpolateTable(curve,time_ratio)
local new_energy=obj:getEnergy()+energy_drain_per_second*delta
obj:setEnergy(math.clamp(0,obj:getMaxEnergy(),new_energy))
obj:setEnergy(extraMath.clamp(0,obj:getMaxEnergy(),new_energy))
end
}
self:addUpdate(obj,"energy decay",update_data)
Expand Down Expand Up @@ -1145,14 +1145,14 @@ function updateSystem:addShieldDecayCurve(obj, total_time, curve_x, curve_y)
},
update = function (self, obj, delta)
self.elapsed_time = self.elapsed_time + delta
local time_ratio = math.clamp(0,1,self.elapsed_time / self.total_time)
local time_ratio = extraMath.clamp(0,1,self.elapsed_time / self.total_time)
local curve={-- bah this is bad but until the update edit is better its needed
{x = self.curve_x[1], y = self.curve_y[1]},
{x = self.curve_x[2], y = self.curve_y[2]},
{x = self.curve_x[3], y = self.curve_y[3]},
{x = self.curve_x[4], y = self.curve_y[4]}
}
local maxShieldRatio=math.CosineInterpolateTable(curve,time_ratio)
local maxShieldRatio=extraMath.CosineInterpolateTable(curve,time_ratio)
local shields = {}
for i=0,obj:getShieldCount()-1 do
table.insert(shields,math.min((obj:getShieldMax(i)*maxShieldRatio),obj:getShieldLevel(i)))
Expand Down Expand Up @@ -1194,7 +1194,7 @@ function updateSystem:_addGenericOverclock(obj, overboosted_time, boost_time, ov
assert(type(obj)=="table")
assert(type(delta)=="number")
self.time = self.time - delta
local scale = math.clamp(self.time/self.boost_time,0,1)
local scale = extraMath.clamp(self.time/self.boost_time,0,1)
inner_update(self, obj, scale)
-- if scale == 0 inner_update has already been called with 0, resulting in overclocks being turned off
if scale == 0 then
Expand Down Expand Up @@ -1243,9 +1243,9 @@ function updateSystem:addBeamBoostOverclock(obj, overboosted_time, boost_time, m
-- 16 seems to be the max number of beams (seen via tweak menu)
-- if the engine exports max number of beams it should be used rather than mirror all data
for index=0,16 do
local beam_range = math.lerp(1,self.max_range_boosted,scale)*self.mirrored_data[index+1].range
local beam_range = extraMath.lerp(1,self.max_range_boosted,scale)*self.mirrored_data[index+1].range
compatSetBeamWeaponRange(obj,index,beam_range)
local beam_cycle = math.lerp(1,self.max_cycle_boosted,scale)*self.mirrored_data[index+1].cycle_time
local beam_cycle = extraMath.lerp(1,self.max_cycle_boosted,scale)*self.mirrored_data[index+1].cycle_time
compatSetBeamWeaponCycleTime(obj,index,beam_cycle)
end
end
Expand Down Expand Up @@ -1275,8 +1275,8 @@ function updateSystem:addEngineBoostUpdate(obj, overboosted_time, boost_time, ma
assert(type(self)=="table")
assert(type(obj)=="table")
assert(type(scale)=="number")
obj:setImpulseMaxSpeed(math.lerp(1,self.max_impulse_boosted,scale)*self.mirrored_data.impulse)
obj:setRotationMaxSpeed(math.lerp(1,self.max_turn_boosted,scale)*self.mirrored_data.turn_rate)
obj:setImpulseMaxSpeed(extraMath.lerp(1,self.max_impulse_boosted,scale)*self.mirrored_data.impulse)
obj:setRotationMaxSpeed(extraMath.lerp(1,self.max_turn_boosted,scale)*self.mirrored_data.turn_rate)
end
)
end
Expand Down Expand Up @@ -1309,7 +1309,7 @@ function updateSystem:addOverclockableTractor(obj, spawnFunc)
if orbiting:isValid() then
local orbiting_update=update_self:getUpdateNamed(orbiting,"orbit target")
if orbiting_update ~= nil then
orbiting_update.distance=math.lerp(0,max_dist,scale)
orbiting_update.distance=extraMath.lerp(0,max_dist,scale)
end
else
table.remove(self.orbitingObj,i)
Expand Down Expand Up @@ -1492,9 +1492,9 @@ function updateSystem:addArtifactCyclicalColorUpdate(obj, red_start, red1, red2,
assert(type(self)=="table")
assert(type(obj)=="table")
assert(type(delta)=="number")
local r = math.lerp(self.red1,self.red2,((getScenarioTime()+self.red_start) % self.red_time)/self.red_time)
local g = math.lerp(self.green1,self.green2,((getScenarioTime()+self.green_start) % self.green_time)/self.green_time)
local b = math.lerp(self.blue1,self.blue2,((getScenarioTime()+self.blue_start) % self.blue_time)/self.blue_time)
local r = extraMath.lerp(self.red1,self.red2,((getScenarioTime()+self.red_start) % self.red_time)/self.red_time)
local g = extraMath.lerp(self.green1,self.green2,((getScenarioTime()+self.green_start) % self.green_time)/self.green_time)
local b = extraMath.lerp(self.blue1,self.blue2,((getScenarioTime()+self.blue_start) % self.blue_time)/self.blue_time)
obj:setRadarTraceColor(math.floor(r),math.floor(g),math.floor(b))
end
}
Expand Down
27 changes: 14 additions & 13 deletions sandbox/main.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5995,7 +5995,7 @@ function coloredSubspaceRift (x,y,destination_x,destination_y)
destination_x = destination_x or 0,
destination_y = destination_y or 0,
update = function (self, obj, delta)
self.current_radius = math.clamp(self.current_radius+delta*(self.max_radius/self.max_time),0,self.max_radius)
self.current_radius = extraMath.clamp(self.current_radius+delta*(self.max_radius/self.max_time),0,self.max_radius)
-- ***techincally*** this is probably wrong - the position of the orbit of the objects is based
-- on the previous update, who cares though, but consider this a warning if reusing this code somewhere that matters
for i=#all_objs,1,-1 do
Expand Down Expand Up @@ -6081,7 +6081,7 @@ function gatewayRifts()
max_radius = 3000,
max_time = 120,
update = function (self, obj, delta)
self.current_radius = math.clamp(self.current_radius+delta*(self.max_radius/self.max_time),0,self.max_radius)
self.current_radius = extraMath.clamp(self.current_radius+delta*(self.max_radius/self.max_time),0,self.max_radius)
-- ***techincally*** this is probably wrong - the position of the orbit of the objects is based
-- on the previous update, who cares though, but consider this a warning if reusing this code somewhere that matters
for i=#all_objs,1,-1 do
Expand Down Expand Up @@ -6374,7 +6374,7 @@ function addChristmasArtifact(waypoints)
return
end
local px,py=obj:getPosition()
local x,y=math.CubicInterpolate2DTable(self.waypoints,self.current)
local x,y=extraMath.CubicInterpolate2DTable(self.waypoints,self.current)
if distance(px,py,x,y)>desiredDelta then
obj:setPosition(x,y)
return
Expand Down Expand Up @@ -23504,10 +23504,10 @@ function createPlayerShipKindling()
update = function (self, obj, delta)
-- in a small sign of mercy to players they get their best beams at 90% max heat rather than burning hotel
-- it would be kind of cool to give extra damage or something, but given how long ships last this probably wont be seen
local heat=math.clamp(obj:getSystemHeat("beamweapons"),0,0.90)
local heat=extraMath.clamp(obj:getSystemHeat("beamweapons"),0,0.90)
heat=heat/0.90 -- scale to that 0.90 = 1
obj:setBeamWeapon(0, math.lerp(120,15,heat), math.lerp(-90,5,heat), math.lerp(500,1250,heat), 6, 8)
obj:setBeamWeapon(1, math.lerp(120,15,heat), math.lerp(90,-5,heat), math.lerp(500,1250,heat), 6, 8)
obj:setBeamWeapon(0, extraMath.lerp(120,15,heat), extraMath.lerp(-90,5,heat), extraMath.lerp(500,1250,heat), 6, 8)
obj:setBeamWeapon(1, extraMath.lerp(120,15,heat), extraMath.lerp(90,-5,heat), extraMath.lerp(500,1250,heat), 6, 8)
end
}
update_system:addUpdate(playerKindling,"dynamic kindling beams",update_data)
Expand Down Expand Up @@ -24811,13 +24811,13 @@ function createPlayerShipTorch()
local update_data = {
update = function (self, obj, delta)
local upper_heat = 0.98
local heat = math.clamp(obj:getSystemHeat("beamweapons"),0,upper_heat)
local heat = extraMath.clamp(obj:getSystemHeat("beamweapons"),0,upper_heat)
heat = heat/upper_heat
-- Arc, Dir, Range, Cycle Time, Dmg
obj:setBeamWeapon(0, 90, 0, 1000, math.lerp(6,3,heat), 3)
obj:setBeamWeapon(1, 45, -7.5, 900, math.lerp(6,2,heat), 4)
obj:setBeamWeapon(2, 45, 7.5, 900, math.lerp(6,2,heat), 4)
obj:setBeamWeapon(3, 30, 0, 700, math.lerp(6,1,heat), 5)
obj:setBeamWeapon(0, 90, 0, 1000, extraMath.lerp(6,3,heat), 3)
obj:setBeamWeapon(1, 45, -7.5, 900, extraMath.lerp(6,2,heat), 4)
obj:setBeamWeapon(2, 45, 7.5, 900, extraMath.lerp(6,2,heat), 4)
obj:setBeamWeapon(3, 30, 0, 700, extraMath.lerp(6,1,heat), 5)
end
}
update_system:addUpdate(playerTorch,"dynamic heating cycle beams", update_data)
Expand Down Expand Up @@ -42254,7 +42254,8 @@ function CubicMineObject:updateNow()
local last_y = nil
if #self.markers>=4 then
for t=1,#self.markers-2,delta do
local x,y = math.CubicInterpolate2DTable(pos_tbl,t)
local x,y = extraMath.CubicInterpolate2DTable(pos_tbl,t)
local x,y = extraMath.CubicInterpolate2DTable(pos_tbl,t)
if last_x == nil or distance(last_x,last_y,x,y) > min_mine_dist then
last_x,last_y=x,y
local newArtifact=nil
Expand Down Expand Up @@ -49402,7 +49403,7 @@ end
-------------------------
function runAllTests()
getNumberOfObjectsStringTest()
math.extraTests()
extraMath:runTests()
updateSystem:create():_test()
end
-- Probe functions
Expand Down

0 comments on commit 7e05635

Please sign in to comment.