diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 17e4610..1205868 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -21,8 +21,7 @@ * [ ] map API * [ ] math API * [x] Cos, Sin, Atan2 - * [x] Mid for integers - * [x] Mid for float64 + * [x] Generic Mid for float64 and integers * [x] Game controller support: gamepad and keyboard * [x] Mouse support * [ ] Add mouse wheel support diff --git a/math.go b/math.go index 965edce..a46ac28 100644 --- a/math.go +++ b/math.go @@ -3,7 +3,10 @@ package pi -import "math" +import ( + "cmp" + "math" +) // Sin returns the sine of angle which is in the range of 0.0-1.0 measured clockwise. // @@ -36,42 +39,15 @@ func Atan2(dx, dy float64) float64 { return math.Mod(0.75+v/(math.Pi*2), 1) } -// Int is a generic type for all integer types type Int interface { ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr } -// MidInt returns the middle of three integer numbers. Very useful for clamping. -func MidInt[T Int](x, y, z T) T { - if x > y { - x, y = y, x - } - - if y > z { - y = z - } - - if x > y { - y = x - } - - return y -} - -// Mid returns the middle of three float64 numbers. Very useful for clamping. -// NaNs are always put at the beginning (are the smallest ones). -func Mid(x, y, z float64) float64 { - if x > y || math.IsNaN(y) { - x, y = y, x - } - - if y > z || math.IsNaN(z) { - y = z - } - - if x > y || math.IsNaN(y) { - y = x - } +// Mid returns the middle of three numbers. Very useful for clamping. +func Mid[T cmp.Ordered](x, y, z T) T { + x, y = min(x, y), max(x, y) + y = min(y, z) + y = max(x, y) return y } diff --git a/math_test.go b/math_test.go index 942b725..50f40fe 100644 --- a/math_test.go +++ b/math_test.go @@ -114,33 +114,31 @@ func TestAtan2(t *testing.T) { } } -func TestMidInt(t *testing.T) { - assert.Equal(t, 0, pi.MidInt(0, 0, 0)) - assert.Equal(t, 1, pi.MidInt(0, 1, 2)) - assert.Equal(t, 1, pi.MidInt(2, 1, 0)) - assert.Equal(t, 1, pi.MidInt(1, 0, 2)) - assert.Equal(t, 1, pi.MidInt(1, 2, 0)) - assert.Equal(t, 1, pi.MidInt(2, 0, 1)) - assert.Equal(t, 1, pi.MidInt(0, 2, 1)) - assert.Equal(t, -1, pi.MidInt(0, -1, -2)) -} - func TestMid(t *testing.T) { - assert.Equal(t, 0.0, pi.Mid(0, 0, 0)) - assert.Equal(t, 1.0, pi.Mid(0, 1, 2)) - assert.Equal(t, 1.0, pi.Mid(2, 1, 0)) - assert.Equal(t, 1.0, pi.Mid(1, 0, 2)) - assert.Equal(t, 1.0, pi.Mid(1, 2, 0)) - assert.Equal(t, 1.0, pi.Mid(2, 0, 1)) - assert.Equal(t, 1.0, pi.Mid(0, 2, 1)) - assert.Equal(t, -1.0, pi.Mid(0, -1, -2)) + assert.Equal(t, 0, pi.Mid(0, 0, 0)) + assert.Equal(t, 1, pi.Mid(0, 1, 2)) + assert.Equal(t, 1, pi.Mid(2, 1, 0)) + assert.Equal(t, 1, pi.Mid(1, 0, 2)) + assert.Equal(t, 1, pi.Mid(1, 2, 0)) + assert.Equal(t, 1, pi.Mid(2, 0, 1)) + assert.Equal(t, 1, pi.Mid(0, 2, 1)) + assert.Equal(t, -1, pi.Mid(0, -1, -2)) + + assert.Equal(t, 0.0, pi.Mid(0.0, 0.0, 0.0)) + assert.Equal(t, 1.0, pi.Mid(0.0, 1.0, 2.0)) + assert.Equal(t, 1.0, pi.Mid(2.0, 1.0, 0.0)) + assert.Equal(t, 1.0, pi.Mid(1.0, 0.0, 2.0)) + assert.Equal(t, 1.0, pi.Mid(1.0, 2.0, 0.0)) + assert.Equal(t, 1.0, pi.Mid(2.0, 0.0, 1.0)) + assert.Equal(t, 1.0, pi.Mid(0.0, 2.0, 1.0)) + assert.Equal(t, -1.0, pi.Mid(0.0, -1.0, -2.0)) assertNaN(t, pi.Mid(math.NaN(), math.NaN(), math.NaN())) assertInf(t, pi.Mid(math.Inf(1), math.Inf(1), math.Inf(1)), 1) - assert.Equal(t, 1.0, pi.Mid(1.0, math.NaN(), 2.0)) // NaNs always go to the beginning + assertNaN(t, pi.Mid(1.0, math.NaN(), 2.0)) assertNaN(t, pi.Mid(math.NaN(), math.NaN(), 1.0)) assertNaN(t, pi.Mid(1.0, math.NaN(), math.NaN())) - assert.Equal(t, 1.0, pi.Mid(1.0, 2.0, math.NaN())) + assertNaN(t, pi.Mid(1.0, 2.0, math.NaN())) assert.Equal(t, 1.0, pi.Mid(math.Inf(1), math.Inf(-1), 1.0)) }