rj-action-library/Runtime/Sorting/MinMaxSearch.cs

93 lines
2.3 KiB
C#

using System.Collections;
using System.Collections.Generic;
using System;
using System.Reflection;
using System.Text.RegularExpressions;
using Godot;
namespace Rokojori
{
public class MinMaxSearch<T>
{
Func<T,T,float,T> lerp;
Func<T,float> getValue;
Func<T,T,bool> validateLimits;
public bool cacheValues = true;
public float interpolationAmount = 1f;
Dictionary<T,float> _cachedValues = new Dictionary<T, float>();
public MinMaxSearch( Func<T,T,float,T> lerp, Func<T,float> getValue, Func<T,T,bool> validateLimits = null)
{
this.lerp = lerp;
this.getValue = getValue;
this.validateLimits = validateLimits;
}
public T Find( float searchValue, T low, T high, float treshold )
{
if ( validateLimits != null && ! validateLimits( low, high ) )
{
throw new Exception( "Limit validation failed" );
}
var tweened = GetTweened( searchValue, low, high );
var tweenedValue = GetValue( tweened );
var tweenedDifference = searchValue - tweenedValue;
Safe.While ( () => Mathf.Abs( tweenedDifference ) > treshold ,
()=>
{
if ( searchValue > tweenedValue )
{
low = tweened;
}
else
{
high = tweened;
}
if ( validateLimits != null && ! validateLimits( low, high ) )
{
throw new Exception( "Limit validation failed" );
}
tweened = GetTweened( searchValue, low, high );
tweenedValue = GetValue( tweened );
tweenedDifference = searchValue - tweenedValue;
}
);
return tweened;
}
public T GetTweened( float value, T low, T high )
{
var lowValue = getValue( low );
var highValue = getValue( high );
var position = MathX.Normalize( value, lowValue, highValue );
position = Mathf.Lerp( 0.5f, position, interpolationAmount );
return lerp( low, high, position );
}
float GetValue( T t )
{
if ( ! cacheValues )
{
return getValue( t );
}
if ( _cachedValues.ContainsKey( t ) )
{
return _cachedValues[ t ];
}
_cachedValues[ t ] = getValue( t );
return _cachedValues[ t ];
}
}
}