353 lines
7.2 KiB
C#
353 lines
7.2 KiB
C#
using Godot;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
|
|
|
|
namespace Rokojori
|
|
{
|
|
|
|
public class Triangle3
|
|
{
|
|
public Vector3 a;
|
|
public Vector3 b;
|
|
public Vector3 c;
|
|
|
|
public Triangle3( Vector3 a, Vector3 b, Vector3 c )
|
|
{
|
|
this.a = a;
|
|
this.b = b;
|
|
this.c = c;
|
|
|
|
_needsUpdate = true;
|
|
}
|
|
|
|
public float perimeter
|
|
{
|
|
get
|
|
{
|
|
var sideA = ( b - a ).Length();
|
|
var sideB = ( c - b ).Length();
|
|
var sideC = ( a - c ).Length();
|
|
|
|
return sideA + sideB + sideC;
|
|
}
|
|
}
|
|
|
|
public float semiperimeter => perimeter * 0.5f;
|
|
|
|
Vector3 _center;
|
|
Sphere _boundingSphere;
|
|
Plane3 _plane;
|
|
|
|
bool _needsUpdate = false;
|
|
|
|
public void NeedsUpdate()
|
|
{
|
|
_needsUpdate = true;
|
|
}
|
|
|
|
public Sphere boundingSphere
|
|
{
|
|
get
|
|
{
|
|
Update();
|
|
return _boundingSphere;
|
|
}
|
|
}
|
|
|
|
void Update()
|
|
{
|
|
if ( ! _needsUpdate )
|
|
{
|
|
return;
|
|
}
|
|
|
|
var m = Math3D.Center( a, b, c );
|
|
var radius = Mathf.Sqrt( MathX.Min( ( m - a ).LengthSquared(), ( m - b ).LengthSquared(), ( m -c ).LengthSquared() ) );
|
|
_boundingSphere = new Sphere( m, radius );
|
|
|
|
_plane = new Plane3();
|
|
_plane.SetFromCoplanarPoints( a, b, c );
|
|
|
|
_needsUpdate = false;
|
|
}
|
|
|
|
public static float ComputeTriangleArea( Vector3 a, Vector3 b, Vector3 c )
|
|
{
|
|
var sideA = ( b - a ).Length();
|
|
var sideB = ( c - b ).Length();
|
|
var sideC = ( a - c ).Length();
|
|
|
|
|
|
var perimeter = sideA + sideB + sideC;
|
|
var semiperimeter = 0.5f * perimeter;
|
|
var areaValue = Mathf.Sqrt( semiperimeter * ( semiperimeter - sideA )
|
|
* ( semiperimeter - sideB )
|
|
* ( semiperimeter - sideC )) ;
|
|
|
|
return areaValue;
|
|
}
|
|
|
|
public float area => ComputeTriangleArea( a, b, c );
|
|
|
|
public bool Intersects( Line3 line )
|
|
{
|
|
var planePoint = _plane.IntersectLine( line );
|
|
|
|
if ( planePoint == null )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return InsideTriangle( (Vector3) planePoint, a, b, c );
|
|
}
|
|
|
|
public Vector3? GetIntersection( Line3 line )
|
|
{
|
|
Update();
|
|
|
|
var planePoint = _plane.IntersectLine( line );
|
|
|
|
if ( planePoint == null )
|
|
{
|
|
return null;
|
|
}
|
|
|
|
if ( ! InsideTriangle( (Vector3) planePoint, a, b, c ) )
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return planePoint;
|
|
}
|
|
|
|
public bool PointInside( Vector3 p )
|
|
{
|
|
return InsideTriangle( p, a, b, c );
|
|
}
|
|
|
|
public Vector3 ClosestPoint( Vector3 p )
|
|
{
|
|
Update();
|
|
|
|
var planePoint = _plane.ClosestPointTo( p );
|
|
|
|
if ( PointInside( planePoint ) )
|
|
{
|
|
return planePoint;
|
|
}
|
|
|
|
return ClosestPointToEdges( p );
|
|
|
|
}
|
|
|
|
public Vector3? GetPointOnPlaneInsideTriangle( Vector3 p )
|
|
{
|
|
Update();
|
|
|
|
var planePoint = _plane.ClosestPointTo( p );
|
|
|
|
if ( PointInside( planePoint ) )
|
|
{
|
|
return planePoint;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
Vector3[] closestPoints = new Vector3[3];
|
|
|
|
public Vector3 ClosestPointToEdges( Vector3 p )
|
|
{
|
|
closestPoints[ 0 ] = Line3.ClosestPointOf( p, a, b );
|
|
closestPoints[ 1 ] = Line3.ClosestPointOf( p, b, c );
|
|
closestPoints[ 2 ] = Line3.ClosestPointOf( p, c, a );
|
|
|
|
return Math3D.GetClosest( p, closestPoints );
|
|
}
|
|
|
|
public Vector3 ClosestPoint( Line3 line )
|
|
{
|
|
var intersection = GetIntersection( line );
|
|
|
|
if ( intersection != null )
|
|
{
|
|
return (Vector3) intersection;
|
|
}
|
|
|
|
var ab = new Line3( a, b ).ClosestPointTo( line );
|
|
var bc = new Line3( b, c ).ClosestPointTo( line );
|
|
var ca = new Line3( c, a ).ClosestPointTo( line );
|
|
|
|
return line.ClosestPointTo( ab, bc, ca );
|
|
}
|
|
|
|
public Vector3 GetPoint( int i )
|
|
{
|
|
if ( i == 0 )
|
|
{
|
|
return a;
|
|
}
|
|
else if ( i == 1 )
|
|
{
|
|
return b;
|
|
}
|
|
else if ( i == 2 )
|
|
{
|
|
return c;
|
|
}
|
|
|
|
return a;
|
|
}
|
|
|
|
void SetPointsToLine( Line3 line, int index )
|
|
{
|
|
line.Set( GetPoint( index ), GetPoint( ( index + 1 ) % 3 ) );
|
|
}
|
|
|
|
public Line3 GetIntersectionLine( Triangle3 other )
|
|
{
|
|
var ownSphere = boundingSphere;
|
|
var otherSphere = other.boundingSphere;
|
|
|
|
if ( ! ownSphere.IntersectsSphere( otherSphere ) )
|
|
{
|
|
return null;
|
|
}
|
|
|
|
var line = new Line3();
|
|
|
|
var intersections = new List<Vector3>();
|
|
|
|
for ( int i = 0; i < 3; i++ )
|
|
{
|
|
SetPointsToLine( line, i );
|
|
var intersection = other.GetIntersection( line );
|
|
|
|
if ( intersection != null )
|
|
{
|
|
intersections.Add( (Vector3) intersection );
|
|
}
|
|
}
|
|
|
|
if ( intersections.Count == 2 )
|
|
{
|
|
line.Set( intersections[ 0 ], intersections[ 1 ] );
|
|
return line;
|
|
}
|
|
|
|
for ( int i = 0; i < 3; i++ )
|
|
{
|
|
other.SetPointsToLine( line, i );
|
|
var intersection = GetIntersection( line );
|
|
|
|
if ( intersection != null )
|
|
{
|
|
intersections.Add( (Vector3) intersection );
|
|
}
|
|
}
|
|
|
|
if ( intersections.Count == 2 )
|
|
{
|
|
line.Set( intersections[ 0 ], intersections[ 1 ] );
|
|
return line;
|
|
}
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
public bool Intersects( Triangle3 other )
|
|
{
|
|
var ownSphere = boundingSphere;
|
|
var otherSphere = other.boundingSphere;
|
|
|
|
if ( ! ownSphere.IntersectsSphere( otherSphere ) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var line = new Line3();
|
|
|
|
for ( int i = 0; i < 3; i++ )
|
|
{
|
|
if ( PointInside( other.GetPoint( i ) ) )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if ( other.PointInside( GetPoint( i ) ) )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
SetPointsToLine( line, i );
|
|
|
|
if ( other.Intersects( line ) )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
other.SetPointsToLine( line, i );
|
|
|
|
if ( Intersects( line ) )
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
public static bool InsideTriangle( Vector3 point, Vector3 a, Vector3 b, Vector3 c )
|
|
{
|
|
var bary = GetBaryCentricCoordinate( point, a, b, c );
|
|
|
|
if ( bary == null )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var values = (Vector3) bary;
|
|
|
|
var insideV = Range.Contains( values.Y, 0, 1 );
|
|
var insideU = Range.Contains( values.Z, 0, 1 );
|
|
var insideX = Range.Contains( values.X, 0, 1 );
|
|
|
|
var result = insideX && insideV && insideU;
|
|
return result;
|
|
|
|
}
|
|
|
|
public static Vector3? GetBaryCentricCoordinate( Vector3 point, Vector3 a, Vector3 b, Vector3 c )
|
|
{
|
|
var _v0 = c - a;
|
|
var _v1 = b - a;
|
|
var _v2 = point - a;
|
|
|
|
var dot00 = Math3D.Dot( _v0, _v0 );
|
|
var dot01 = Math3D.Dot( _v0, _v1 );
|
|
var dot02 = Math3D.Dot( _v0, _v2 );
|
|
var dot11 = Math3D.Dot( _v1, _v1 );
|
|
var dot12 = Math3D.Dot( _v1, _v2 );
|
|
|
|
var denom = ( dot00 * dot11 - dot01 * dot01 );
|
|
|
|
if ( denom == 0 )
|
|
{
|
|
return null;
|
|
}
|
|
|
|
var invDenom = 1f / denom;
|
|
|
|
var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
|
|
var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
|
|
|
|
return new Vector3( 1f - u - v, v, u );
|
|
}
|
|
|
|
}
|
|
|
|
} |