rj-action-library/Runtime/Math/Geometry/SplineCurveCreator.cs

137 lines
3.7 KiB
C#
Raw Normal View History

2024-09-14 06:41:52 +00:00
using Godot;
using System.Collections.Generic;
using System;
namespace Rokojori
{
public class SplineCurveCreator
{
bool closed;
public SplineCurve Create( List<SplinePoint> splinePoints, bool close )
{
closed = close;
var points = new List<SplineCurvePoint>();
for ( int i = 0; i < splinePoints.Count; i++ )
{
points.Add( CreatePoint( splinePoints, i ) );
}
if ( closed )
{
points.Add( CreatePoint( splinePoints, 0 ) );
}
return SplineCurve.From( points );
}
SplineCurvePoint CreatePoint( List<SplinePoint> splinePoints, int index )
{
var splineCurvePoint = new SplineCurvePoint();
var splinePoint = splinePoints[ index ];
splineCurvePoint.position = splinePoint.GlobalPosition;
splineCurvePoint.weight = 1f;
splineCurvePoint.tangentBefore.position = GetTangentPosition( splinePoints, index, true );
splineCurvePoint.tangentNext.position = GetTangentPosition( splinePoints, index, false );
splineCurvePoint.tangentBefore.weight = splinePoint.tangentBeforeWeight;
splineCurvePoint.tangentNext.weight = splinePoint.tangentNextWeight;
return splineCurvePoint;
}
public Vector3 GetTangentPosition( List<SplinePoint> splinePoints, int index, bool before )
{
var splinePoint = splinePoints[ index ];
if ( splinePoint.tangentMode == SplinePointTangentMode.Custom )
{
return before ? splinePoint.tangentBefore.GlobalPosition :
splinePoint.tangentNext.GlobalPosition;
}
var previousIndex = index - 1;
if ( previousIndex == -1 )
{
previousIndex = closed ? splinePoints.Count -1 : 0;
}
var nextIndex = index + 1;
if ( nextIndex == splinePoints.Count )
{
nextIndex = closed ? 0 : splinePoints.Count - 1;
}
var previous = splinePoints[ previousIndex ];
var next = splinePoints[ nextIndex ];
var previousPosition = previous.GlobalPosition;
var nextPosition = next.GlobalPosition;
var point = splinePoint.GlobalPosition;
var overshootPrevention = splinePoint.overshootPrevention;
var tangentScale = splinePoint.tangentScale;
var symmetricTangentLength = splinePoint.symmetricTangentLength;
if ( overshootPrevention > 0 )
{
var previousDirection = ( previousPosition - point ) ;
var nextDirection = ( nextPosition - point );
var previousLength = previousDirection.Length();
var nextLength = nextDirection.Length();
if ( previousLength > nextLength )
{
previousPosition = Math3D.Lerp(
previousPosition, point + previousDirection.Normalized() * nextLength,
overshootPrevention
);
}
else
{
nextPosition = Math3D.Lerp(
nextPosition, point + nextDirection.Normalized() * previousLength,
overshootPrevention
);
}
}
var direction = nextPosition - previousPosition;
var length = 0f;
var lengthBefore = ( point - previousPosition ).Length();
var lengthNext = ( point - nextPosition ).Length();
var lengthAverage = ( lengthBefore + lengthNext ) * 0.5f;
if ( symmetricTangentLength > 0 )
{
lengthBefore = Mathf.Lerp( lengthBefore, lengthAverage, symmetricTangentLength );
lengthNext = Mathf.Lerp( lengthNext, lengthAverage, symmetricTangentLength );
}
if ( before )
{
length = -lengthBefore;
}
else
{
length = lengthNext;
}
return point + direction.Normalized() * length * 0.33333f * tangentScale;
}
}
}