using UnityEngine; using System; using System.Collections; using System.Collections.Generic; public partial class Spline : MonoBehaviour { /// /// This function calculates the parameter of the closest point on the spline to a given point. /// /// /// The closest parameter of the point to point on the spline. /// /// /// A given point. /// /// /// Defines how accurate the calculation will be. A value of 5 should be high enough for most purposes. /// /// /// A spline parameter from 0 to 1 that specifies the lower bound for the numeric search. (default is 0.0) /// /// /// A spline parameter from 0 to 1 that specifies the upper bound for the numeric search. (default is 1.0) /// /// /// Specifies the step between two sample points on the spline for the 1st iteration. (default is 0.01) /// public float GetClosestPointParam( Vector3 point, int iterations, float start = 0, float end = 1, float step = .01f ) { return GetClosestPointParamIntern( (splinePos) => (point-splinePos).sqrMagnitude, iterations, start, end, step ); } /// /// This function calculates the closest point on the spline to a given ray. /// /// /// The closest spline parameter of the point to the ray on the spline. /// /// /// A given ray. /// /// /// Defines how accurate the calculation will be. A value of 5 should be high enough for most purposes. /// /// /// A spline parameter from 0 to 1 that specifies the lower bound for the numeric search. (default is 0.0) /// /// /// A spline parameter from 0 to 1 that specifies the upper bound for the numeric search. (default is 1.0) /// /// /// Specifies the step between two sample points on the spline for the 1st iteration. (default is 0.01) /// public float GetClosestPointParamToRay( Ray ray, int iterations, float start = 0, float end = 1, float step = .01f ) { return GetClosestPointParamIntern( (splinePos) => Vector3.Cross( ray.direction, splinePos - ray.origin ).sqrMagnitude, iterations, start, end, step ); } /// /// This function calculates the closest point on the spline to a given plane. /// /// /// The closest spline parameter of the point to the plane on the spline. /// /// /// A given plane. /// /// /// Defines how accurate the calculation will be. A value of 5 should be high enough for most purposes. /// /// /// A spline parameter from 0 to 1 that specifies the lower bound for the numeric search. (default is 0.0) /// /// /// A spline parameter from 0 to 1 that specifies the upper bound for the numeric search. (default is 1.0) /// /// /// Specifies the step between two sample points on the spline for the 1st iteration. (default is 0.01) /// public float GetClosestPointParamToPlane( Plane plane, int iterations, float start = 0, float end = 1, float step = .01f ) { return GetClosestPointParamIntern( (splinePos) => Mathf.Abs( plane.GetDistanceToPoint( splinePos ) ), iterations, start, end, step ); } private float GetClosestPointParamIntern( DistanceFunction distFnc, int iterations, float start, float end, float step ) { iterations = Mathf.Clamp( iterations, 0, 5 ); float minParam = GetClosestPointParamOnSegmentIntern( distFnc, start, end, step ); for( int i = 0; i < iterations; i++ ) { float searchOffset = Mathf.Pow( 10f, -(i+2f) ); start = Mathf.Clamp01( minParam-searchOffset ); end = Mathf.Clamp01( minParam+searchOffset ); step = searchOffset * .1f; minParam = GetClosestPointParamOnSegmentIntern( distFnc, start, end, step ); } return minParam; } private float GetClosestPointParamOnSegmentIntern( DistanceFunction distFnc, float start, float end, float step ) { float minDistance = Mathf.Infinity; float minParam = 0f; for( float param = start; param <= end; param += step ) { float distance = distFnc( GetPositionOnSpline( param ) ); if( minDistance > distance ) { minDistance = distance; minParam = param; } } return minParam; } private delegate float DistanceFunction( Vector3 splinePos ); }