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

265 lines
5.6 KiB
C#

using Godot;
using System.Collections;
using System.Collections.Generic;
namespace Rokojori
{
public class Line3:Curve3
{
public Vector3 start = Vector3.Zero;
public Vector3 end = Vector3.Zero;
public Line3( Vector3 start, Vector3 end )
{
this.start = start;
this.end = end;
}
public Line3(){}
public static Line3 Create( Vector3 start, Vector3 end )
{
return new Line3( start, end );
}
public void Set( Vector3 start, Vector3 end )
{
this.start = start;
this.end = end;
}
public override Vector3 PositionAt( float t )
{
return start.Lerp( end, t );
}
public Line3 Copy( )
{
return new Line3( start, end );
}
public Vector3 direction { get { return end - start; } }
public float length { get { return direction.Length(); } }
public Vector3 GetPointAtParameter( float t )
{
return start + direction * t;
}
public Vector3 center{ get { return ( start + end ) * 0.5f; } }
public Line3 ScaleFromCenter( float scale )
{
var lineCenter = center;
var halfDirection = direction * ( 0.5f * scale );
var scaledStart = lineCenter - halfDirection;
var scaledEnd = lineCenter + halfDirection;
return new Line3( scaledStart, scaledEnd );
}
public Line3 ChangeLengthFromCenter( float lengthChange )
{
var lineCenter = center;
var halfDirection = direction * 0.5f;
var length = halfDirection.Length();
length += lengthChange * 0.5f;
halfDirection = halfDirection.Normalized() * length;
var scaledStart = lineCenter - halfDirection;
var scaledEnd = lineCenter + halfDirection;
return new Line3( scaledStart, scaledEnd );
}
public Line3 SetLengthFromCenter( float length )
{
var lineCenter = center;
var halfDirection = direction.Normalized() * ( length * 0.5f );
var scaledStart = lineCenter - halfDirection;
var scaledEnd = lineCenter + halfDirection;
return new Line3( scaledStart, scaledEnd );
}
public Vector3 ClosestPointToPoint( Vector3 point )
{
var parameter = MathX.Clamp01( ClostestParameterToPoint( point ) );
return GetPointAtParameter( parameter );
}
public static Vector3 ClosestPointOf( Vector3 p, Vector3 lineStart, Vector3 lineEnd )
{
var line = new Line3();
line.Set( lineStart, lineEnd );
return line.ClosestPointToPoint( p );
}
public float ClostestParameterToPoint( Vector3 point )
{
var startP = point - start;
var startEnd = end - start;
var startEnd2 = startEnd.Dot( startEnd );
var startEnd_startP = startEnd.Dot( startP );
if ( startEnd2 == 0 )
{
return 0;
}
var t = startEnd_startP / startEnd2;
return t;
}
public float DistanceToPoint( Vector3 point )
{
return ( point - ClosestPointToPoint( point ) ).Length();
}
public float DistanceToLine( Line3 s )
{
var points = ClosestPointsToLine( s );
return ( points[ 1 ] - points[ 0 ] ).Length();
}
public Vector3[] ClosestPointsToLine( Line3 s )
{
var parameters = ClosestParametersToLine( s );
var x = this.GetPointAtParameter( parameters.X );
var y = s.GetPointAtParameter( parameters.Y );
return new Vector3[]{ x, y };
}
public Vector3 ClosestPointTo( Line3 other )
{
var parameters = ClosestParametersToLine( other );
return PositionAt( parameters.X );
}
public Vector3 ClosestPointTo( params Vector3[] points )
{
var d = float.MaxValue;
var id = -1;
for ( int i = 0; i < points.Length; i++ )
{
var pd = DistanceToPoint( points[ i ] );
if ( pd < d )
{
id = i;
d = pd;
}
}
return points[ id ];
}
public Vector3 ClosestPointTo( List<Vector3> points )
{
var d = float.MaxValue;
var id = -1;
for ( int i = 0; i < points.Count; i++ )
{
var pd = DistanceToPoint( points[ i ] );
if ( pd < d )
{
id = i;
d = pd;
}
}
return points[ id ];
}
public Vector2 ClosestParametersToLine( Line3 s )
{
float epsilon = 0.00000001f;
var u = this.direction;
var v = s.direction;
var w = start - s.start;
var a = u.Dot( u );
var b = u.Dot( v );
var c = v.Dot( v );
var d = u.Dot( w );
var e = v.Dot( w );
var DD = a * c - b * b;
var sc = 0f;
var sN = 0f;
var sD = 0f;
var tc = 0f;
var tN = 0f;
var tD = 0f;
sD = DD;
tD = DD;
if ( DD < epsilon )
{
sN = 0.0f;
sD = 1.0f;
tN = e;
tD = c;
}
else
{
sN = b * e - c * d ;
tN = a * e - b * d ;
if ( sN < 0.0f )
{
sN = 0.0f;
tN = e;
tD = c;
}
else if ( sN > sD )
{
sN = sD;
tN = e + b;
tD = c;
}
}
if ( tN < 0f || tN > tD )
{
var tN_bigger_tD = tN >= 0f && tN > tD;
tN = tN_bigger_tD ? tD : 0f;
var inbetween = tN_bigger_tD ? ( -d + b ) : ( -d );
var isSmaller = inbetween < 0;
var isBigger = inbetween > a;
sN = isSmaller ? 0f : isBigger ? sD : inbetween;
sD = ! isSmaller && ! isBigger ? a : sD;
}
sc = Mathf.Abs( sN ) < epsilon ? 0f : sN / sD;
tc = Mathf.Abs( tN ) < epsilon ? 0f : tN / tD;
return new Vector2( sc, tc );
}
}
}