-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathFloatTools.hx
128 lines (116 loc) · 3.61 KB
/
FloatTools.hx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package moon.tools;
using StringTools;
/**
* ...
* @author Munir Hussin
*/
class FloatTools
{
/**
* Rounds off a number to `d` decimal places.
*/
public static inline function round(v:Float, d:Int=0):Float
{
var shift = Math.pow(10, d);
return Math.fround(v * shift) / shift;
}
/**
* Truncates a number to `d` decimal places..
*/
public static inline function trunc(v:Float, d:Int=0):Float
{
var shift = Math.pow(10, d);
return Std.int(v * shift) / shift;
}
/**
* Clamps the value `v` to be between `lo` and `hi`
*/
public static inline function clamp<T:Float>(v:T, lo:T, hi:T):T
{
return
if (v <= lo)
lo;
else if (v >= hi)
hi;
else
v;
}
/**
* If truncate is false, round() will be called on the value, otherwise trunc()
* is called instead.
*
* `d` is the number of decimal places to display
*/
public static function format(v:Float, d:Int=0, truncate:Bool=false):String
{
var fnum = Std.string(truncate ? trunc(v, d) : round(v, d));
var fpos = fnum.indexOf(".");
var fdec = "";
if (fpos != -1)
{
fdec = fnum.substr(fpos + 1, d);
fnum = fnum.substr(0, fpos);
}
//return fnum + "." + Text.of(fdec).rpad("0", d);
return fnum + "." + fdec.rpad("0", d);
}
/**
* Linear interpolation between numbers `a` and `b`
* https://en.wikipedia.org/wiki/Linear_interpolation
*
* lerp(a, b, t) == interpolate(t, 0, 1, a, b)
* a.lerp(b, t) == t.interpolate(0, 1, a, b)
*
* Usage:
* var x1 = 5.0;
* var x2 = x1.lerp(8.0, 0.5); // x2 is halfway between 5.0 and 8.0
*/
public static inline function lerp(a:Float, b:Float, t:Float):Float
{
return (1-t) * a + t * b;
}
/**
* Given a number `v`, which is in the range from `aLo` to `aHi`, interpolate `v`
* to be in the range of `bLo` to `bHi`.
*
* Lerp interpolates between any 2 numbers using a parameter that's normalized to
* 0 and 1, where 0 is the first number and 1 is the second number.
*
* This method generalizes that, so instead of 0 and 1, you can specify any
* numbers.
*
* interpolate(t, 0, 1, a, b) == lerp(a, b, t)
*
* Usage:
* var progress = bytesDownloaded;
* var x = progress.interpolate(0, bytesTotal, 50, 100);
* // progress is between 0 and bytesTotal
* // interpolate progress such that x is between 50 and 100
*/
public static function interpolate(v:Float, aLo:Float, aHi:Float, bLo:Float, bHi:Float):Float
{
/*var aRange = aHi - aLo;
var bRange = bHi - bLo;
var ratio = (v - aLo) / aRange;
return bRange * ratio + bLo;*/
return (bHi - bLo) * (v - aLo) / (aHi - aLo) + bLo;
}
/**
* Returns the index of the bin the value `v` belongs to.
* @param v a normalized value between 0 and 1
* @param len the number of bins
* @return
*/
public static inline function bin(v:Float, len:Int, lo:Float=0, hi:Float=1):Int
{
return IntTools.clamp(Math.floor(interpolate(v, lo, hi, 0, len)), 0, len - 1);
}
/**
* Checks if a floating point number is near another floating point number
* by a margin of `epsilon`.
*/
public static inline function isNear(a:Float, b:Float, epsilon:Float):Bool
{
return Math.abs(b - a) <= Math.abs(epsilon);
}
}