Skip to content

Commit

Permalink
Fix overlapping points erroring
Browse files Browse the repository at this point in the history
  • Loading branch information
ecurtiss committed Oct 31, 2021
1 parent 4c17ab2 commit d29ef27
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 43 deletions.
38 changes: 7 additions & 31 deletions src/Chain.lua
Original file line number Diff line number Diff line change
@@ -1,42 +1,14 @@
local FuzzyEq = require(script.Parent.FuzzyEq)
local Spline = require(script.Parent.Spline)
local Types = require(script.Parent.Types)

local Chain = {}
Chain.__index = Chain

local EPSILON = 1e-4

-- Type checking
local tUnitInterval = Types.tUnitInterval
local tOptionalUnitInterval = Types.tOptionalUnitInterval

local function FuzzyEq(a, b)
local aType = typeof(a)

if aType == "number" then
return a == b or math.abs(a - b) <= (math.abs(a) + 1) * EPSILON
elseif aType == "Vector3" then
return a:FuzzyEq(b, EPSILON)
elseif aType == "Vector2" then
local aX, bX = a.X, b.X
if aX == bX or math.abs(aX - bX) <= (math.abs(aX) + 1) * EPSILON then
local aY, bY = a.Y, b.Y
if aY == bY or math.abs(aY - bY) <= (math.abs(aY) + 1) * EPSILON then
return true
end
end
elseif aType == "CFrame" then
if a.Position:FuzzyEq(b.Position, EPSILON)
and a.RightVector:FuzzyEq(b.RightVector, EPSILON)
and a.UpVector:FuzzyEq(b.UpVector, EPSILON)
and a.LookVector:FuzzyEq(b.LookVector, EPSILON) then
return true
end
end

return false
end

-- Constructor
function Chain.new(points: {Types.Knot}, alpha: number?, tension: number?)
assert(#points >= 2, "2 or more points are required to create a chain.")
Expand Down Expand Up @@ -99,10 +71,14 @@ local function AlphaToSpline(self, alpha: number)
end

-- Special cases for when alpha is outside of the unti interval.
if alpha <= 0 then
if alpha < 0 then
-- (alpha - 0) / (intervals[2] - 0)
return splines[1], alpha / intervals[2]
elseif alpha >= 1 then
elseif alpha == 0 then
return splines[1], 0
elseif alpha == 1 then
return splines[#splines], 1
elseif alpha > 1 then
local n = #splines
return splines[n], (alpha - intervals[n]) / (1 - intervals[n])
end
Expand Down
30 changes: 30 additions & 0 deletions src/FuzzyEq.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
local EPSILON = 1e-4

local function FuzzyEq(a, b)
local aType = typeof(a)

if aType == "number" then
return a == b or math.abs(a - b) <= (math.abs(a) + 1) * EPSILON
elseif aType == "Vector3" then
return a:FuzzyEq(b, EPSILON)
elseif aType == "Vector2" then
local aX, bX = a.X, b.X
if aX == bX or math.abs(aX - bX) <= (math.abs(aX) + 1) * EPSILON then
local aY, bY = a.Y, b.Y
if aY == bY or math.abs(aY - bY) <= (math.abs(aY) + 1) * EPSILON then
return true
end
end
elseif aType == "CFrame" then
if a.Position:FuzzyEq(b.Position, EPSILON)
and a.RightVector:FuzzyEq(b.RightVector, EPSILON)
and a.UpVector:FuzzyEq(b.UpVector, EPSILON)
and a.LookVector:FuzzyEq(b.LookVector, EPSILON) then
return true
end
end

return false
end

return FuzzyEq
36 changes: 24 additions & 12 deletions src/Spline.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
local FuzzyEq = require(script.Parent.FuzzyEq)
local Squad = require(script.Parent.Squad)
local Types = require(script.Parent.Types)

Expand Down Expand Up @@ -31,17 +32,28 @@ function Spline.new(k0: Types.Knot, k1: Types.Knot, k2: Types.Knot, k3: Types.Kn
className = "CFrameSpline"
end

-- https://qroph.github.io/2018/07/30/smooth-paths-using-catmull-rom-splines.html
local t0 = 0
local t1 = (p1 - p0).Magnitude ^ alpha + t0
local t2 = (p2 - p1).Magnitude ^ alpha + t1
local t3 = (p3 - p2).Magnitude ^ alpha + t2
local m1 = (1 - tension) * (t2 - t1) * ((p1 - p0)/(t1 - t0) - (p2 - p0)/(t2 - t0) + (p2 - p1)/(t2 - t1))
local m2 = (1 - tension) * (t2 - t1) * ((p2 - p1)/(t2 - t1) - (p3 - p1)/(t3 - t1) + (p3 - p2)/(t3 - t2))
local a: Vector3 = 2 * (p1 - p2) + m1 + m2
local b: Vector3 = 3 * (p2 - p1) - 2 * m1 - m2
local c: Vector3 = m1
local d: Vector3 = p1
local a, b, c
if FuzzyEq(p1, p2) then
a = p1 * 0
b = a
c = a
elseif FuzzyEq(p0, p1) or FuzzyEq(p2, p3) then
a = p1 * 0
b = a
c = p2 - p1
else
-- https://qroph.github.io/2018/07/30/smooth-paths-using-catmull-rom-splines.html
local t0 = 0
local t1 = (p1 - p0).Magnitude ^ alpha + t0
local t2 = (p2 - p1).Magnitude ^ alpha + t1
local t3 = (p3 - p2).Magnitude ^ alpha + t2
local m1 = (1 - tension) * (t2 - t1) * ((p1 - p0)/(t1 - t0) - (p2 - p0)/(t2 - t0) + (p2 - p1)/(t2 - t1))
local m2 = (1 - tension) * (t2 - t1) * ((p2 - p1)/(t2 - t1) - (p3 - p1)/(t3 - t1) + (p3 - p2)/(t3 - t2))
a = 2 * (p1 - p2) + m1 + m2
b = 3 * (p2 - p1) - 2 * m1 - m2
c = m1
end


local self = setmetatable({
ClassName = className,
Expand All @@ -58,7 +70,7 @@ function Spline.new(k0: Types.Knot, k1: Types.Knot, k2: Types.Knot, k3: Types.Kn
a = a,
b = b,
c = c,
d = d
d = p1
}, Spline)
self.Length = self:SolveLength()

Expand Down

0 comments on commit d29ef27

Please sign in to comment.