Simple Spline Module
Posted: Tue Jun 25, 2024 10:52 am
Here is a Spline Module without the need to use InitEngine3D().
It is ported from Ogres SimpleSpline Class, so it "should" produce the same output as the PureBasic functions.
It is ported from Ogres SimpleSpline Class, so it "should" produce the same output as the PureBasic functions.
Code: Select all
DeclareModule Spline
Structure Vec3
x.f
y.f
z.f
EndStructure
Macro _Spline_SetVec3_(v_, x_, y_, z_)
v_\x = x_
v_\y = y_
v_\z = z_
EndMacro
Declare Create()
Declare AddPoint(*spline, x.f, y.f, z.f)
Declare Close(*spline)
Declare.f PointX(*spline, index.i)
Declare.f PointY(*spline, index.i)
Declare.f PointZ(*spline, index.i)
Declare.f ComputeX(*spline)
Declare.f ComputeY(*spline)
Declare.f ComputeZ(*spline)
Declare Count(*spline)
Declare Update(*spline, index.i, x.f, y.f, z.f)
Declare Compute(*spline, t.f)
Declare Clear(*spline)
Declare Free(*spline)
EndDeclareModule
Module Spline
EnableExplicit
Structure SPLINE
nrPoints.l
Array points.Vec3(0)
Array tangents.Vec3(0)
splinePos.Vec3
EndStructure
Procedure UpdateTangents(*spline.SPLINE)
If *spline And *spline\nrPoints > 1
Protected i
Protected nrPoints = *spline\nrPoints
If (*spline\points(0)\x = *spline\points(nrPoints - 1)\x) And
(*spline\points(0)\y = *spline\points(nrPoints - 1)\y) And
(*spline\points(0)\z = *spline\points(nrPoints - 1)\z)
; spline is closed
_Spline_SetVec3_(*spline\tangents(0),
0.5 * (*spline\points(1)\x - *spline\points(nrPoints - 2)\x),
0.5 * (*spline\points(1)\y - *spline\points(nrPoints - 2)\y),
0.5 * (*spline\points(1)\z - *spline\points(nrPoints - 2)\z))
_Spline_SetVec3_(*spline\tangents(nrPoints - 1),
*spline\tangents(0)\x, *spline\tangents(0)\y, *spline\tangents(0)\z)
For i = 1 To nrPoints - 2
_Spline_SetVec3_(*spline\tangents(i),
0.5 * (*spline\points(i + 1)\x - *spline\points(i - 1)\x),
0.5 * (*spline\points(i + 1)\y - *spline\points(i - 1)\y),
0.5 * (*spline\points(i + 1)\z - *spline\points(i - 1)\z))
Next
Else
; spline is not closed
_Spline_SetVec3_(*spline\tangents(0),
0.5 * (*spline\points(1)\x - *spline\points(0)\x),
0.5 * (*spline\points(1)\y - *spline\points(0)\y),
0.5 * (*spline\points(1)\z - *spline\points(0)\z))
_Spline_SetVec3_(*spline\tangents(nrPoints - 1),
0.5 * (*spline\points(nrPoints - 1)\x - *spline\points(nrPoints - 2)\x),
0.5 * (*spline\points(nrPoints - 1)\y - *spline\points(nrPoints - 2)\y),
0.5 * (*spline\points(nrPoints - 1)\z - *spline\points(nrPoints - 2)\z))
For i = 1 To nrPoints - 2
_Spline_SetVec3_(*spline\tangents(i),
0.5 * (*spline\points(i+1)\x - *spline\points(i - 1)\x),
0.5 * (*spline\points(i+1)\y - *spline\points(i - 1)\y),
0.5 * (*spline\points(i+1)\z - *spline\points(i - 1)\z))
Next
EndIf
EndIf
EndProcedure
Procedure Interpolate(*spline.SPLINE, index.i, t.f)
If index < *spline\nrPoints
Protected *point1.Vec3 = @*spline\points(index)
Protected *point2.Vec3 = @*spline\points(index + 1)
If (index + 1) = *spline\nrPoints
_Spline_SetVec3_(*spline\splinePos, *point1\x, *point1\y, *point1\z)
ElseIf t = 0
_Spline_SetVec3_(*spline\splinePos, *point1\x, *point1\y, *point1\z)
ElseIf t = 1
_Spline_SetVec3_(*spline\splinePos, *point2\x, *point2\y, *point2\z)
Else
Protected.f t2 = t * t
Protected.f t3 = t2 * t
Protected *tan1.Vec3 = @*spline\tangents(index)
Protected *tan2.Vec3 = @*spline\tangents(index + 1)
_Spline_SetVec3_(*spline\splinePos,
t3 * (2 * *point1\x - 2 * *point2\x + *tan1\x + *tan2\x) +
t2 * (-3 * *point1\x + 3 * *point2\x - 2 * *tan1\x - *tan2\x) +
t * *tan1\x + *point1\x,
t3 * (2 * *point1\y - 2 * *point2\y + *tan1\y + *tan2\y) +
t2 * (-3 * *point1\y + 3 * *point2\y - 2 * *tan1\y - *tan2\y) +
t * *tan1\y + *point1\y,
t3 * (2 * *point1\z - 2 * *point2\z + *tan1\z + *tan2\z) +
t2 * (-3 * *point1\z + 3 * *point2\z - 2 * *tan1\z - *tan2\z) +
t * *tan1\z + *point1\z)
EndIf
EndIf
EndProcedure
Procedure Create()
Protected *spline.SPLINE = AllocateStructure(SPLINE)
ProcedureReturn *spline
EndProcedure
Procedure AddPoint(*spline.SPLINE, x.f, y.f, z.f)
If *spline
If *spline\nrPoints >= ArraySize(*spline\points())
ReDim *spline\points(*spline\nrPoints + 4)
ReDim *spline\tangents(*spline\nrPoints + 4)
EndIf
_Spline_SetVec3_(*spline\points(*spline\nrPoints), x, y, z)
*spline\nrPoints + 1
UpdateTangents(*spline)
EndIf
EndProcedure
Procedure Close(*spline.SPLINE)
If *spline And *spline\nrPoints > 0
If *spline\points(0)\x <> *spline\points(*spline\nrPoints - 1)\x Or
*spline\points(0)\y <> *spline\points(*spline\nrPoints - 1)\y Or
*spline\points(0)\z <> *spline\points(*spline\nrPoints - 1)\z
Spline::AddPoint(*spline, *spline\points(0)\x, *spline\points(0)\y, *spline\points(0)\z)
EndIf
EndIf
EndProcedure
Procedure.f PointX(*spline.SPLINE, index.i)
If *spline And index < *spline\nrPoints
ProcedureReturn *spline\points(index)\x
EndIf
EndProcedure
Procedure.f PointY(*spline.SPLINE, index.i)
If *spline And index < *spline\nrPoints
ProcedureReturn *spline\points(index)\y
EndIf
EndProcedure
Procedure.f PointZ(*spline.SPLINE, index.i)
If *spline And index < *spline\nrPoints
ProcedureReturn *spline\points(index)\z
EndIf
EndProcedure
Procedure.f ComputeX(*spline.SPLINE)
If *spline
ProcedureReturn *spline\splinePos\x
EndIf
EndProcedure
Procedure.f ComputeY(*spline.SPLINE)
If *spline
ProcedureReturn *spline\splinePos\y
EndIf
EndProcedure
Procedure.f ComputeZ(*spline.SPLINE)
If *spline
ProcedureReturn *spline\splinePos\z
EndIf
EndProcedure
Procedure Count(*spline.SPLINE)
If *spline
ProcedureReturn *spline\nrPoints
EndIf
EndProcedure
Procedure Clear(*spline.SPLINE)
If *spline
*spline\nrPoints = 0
Dim *spline\points(0)
Dim *spline\tangents(0)
EndIf
EndProcedure
Procedure Free(*spline.SPLINE)
If *spline
FreeStructure(*spline)
EndIf
EndProcedure
Procedure Update(*spline.SPLINE, index.i, x.f, y.f, z.f)
If *spline And index < *spline\nrPoints
_Spline_SetVec3_(*spline\points(index), x, y, z)
UpdateTangents(*spline)
EndIf
EndProcedure
Procedure Compute(*spline.SPLINE, t.f)
If *spline
Protected fSeg.f = t * (*spline\nrPoints - 1);
Protected segIdx = Int(fSeg)
Interpolate(*spline, segIdx, fSeg - segIdx)
EndIf
EndProcedure
DisableExplicit
EndModule
CompilerIf #PB_Compiler_IsMainFile
OpenWindow(0,0,0,600,600,"SimpleSpline")
CanvasGadget(0,0,0,600,600)
spline = Spline::Create()
For r = 0 To 359 Step 18
rad = 150 + Sin(Radian(r * 5)) * 100
Spline::AddPoint(spline, 300 + Sin(Radian(r)) * rad, 300 + Cos(Radian(r)) * rad, 0)
Next
Spline::Close(spline)
If StartVectorDrawing(CanvasVectorOutput(0))
Spline::Compute(spline, 0)
MovePathCursor(Spline::ComputeX(spline), Spline::ComputeY(spline))
t.f = 0.005 : Repeat
Spline::Compute(spline, t)
AddPathLine(Spline::ComputeX(spline), Spline::ComputeY(spline))
t + 0.005
Until t > 1
AddPathCircle(300, 300, 30)
VectorSourceColor(RGBA(225,225,255,255))
FillPath(#PB_Path_Winding | #PB_Path_Preserve)
VectorSourceColor(RGBA(0,0,0,255))
StrokePath(5)
StopVectorDrawing()
EndIf
Repeat
Until WaitWindowEvent(50) = #PB_Event_CloseWindow
Spline::Free(spline)
CompilerEndIf