From 1975b07efa9812915fd3c485b1f4e931673c3871 Mon Sep 17 00:00:00 2001 From: bilhox Date: Thu, 4 Jan 2024 11:11:12 +0100 Subject: [PATCH 01/31] invlerp & remap impl --- a.py | 15 +++++ buildconfig/stubs/pygame/math.pyi | 1 + src_c/doc/math_doc.h | 2 + src_c/math.c | 101 ++++++++++++++++++++++++++++-- 4 files changed, 113 insertions(+), 6 deletions(-) create mode 100644 a.py diff --git a/a.py b/a.py new file mode 100644 index 0000000000..9102725738 --- /dev/null +++ b/a.py @@ -0,0 +1,15 @@ +import numpy +import pygame +import random + +from statistics import median +from timeit import timeit + +def foo(): + + c = pygame.math.invlerp(238782374, 34729374275, 0.3478098) + +t = [timeit(foo, number=500_000) for _ in range(50)] +print(median(t)) + +print(pygame.math.remap(0, 100, 0, 200, 50)) \ No newline at end of file diff --git a/buildconfig/stubs/pygame/math.pyi b/buildconfig/stubs/pygame/math.pyi index ebb99fb232..230a3a7b97 100644 --- a/buildconfig/stubs/pygame/math.pyi +++ b/buildconfig/stubs/pygame/math.pyi @@ -334,6 +334,7 @@ class Vector3(_GenericVector): def lerp(a: float, b: float, weight: float, do_clamp: bool = True, /) -> float: ... +def invlerp(a: float, b: float, weight: float /) -> float: ... def smoothstep(a: float, b: float, weight: float, /) -> float: ... diff --git a/src_c/doc/math_doc.h b/src_c/doc/math_doc.h index 0c38edbaa2..75d906d95b 100644 --- a/src_c/doc/math_doc.h +++ b/src_c/doc/math_doc.h @@ -2,6 +2,8 @@ #define DOC_MATH "pygame module for vector classes" #define DOC_MATH_CLAMP "clamp(value, min, max, /) -> float\nreturns value clamped to min and max." #define DOC_MATH_LERP "lerp(a, b, value, do_clamp=True, /) -> float\nreturns value linearly interpolated between a and b" +#define DOC_MATH_REMAP "remap(i_min, i_max, o_min, o_max, value, /) -> float\nremaps value from i_range to o_range" +#define DOC_MATH_INVLERP "invlerp(a, b, value, /) -> float\nreturns value inverse interpolated between a and b" #define DOC_MATH_SMOOTHSTEP "smoothstep(a, b, value, /) -> float\nreturns value smoothly interpolated between a and b." #define DOC_MATH_VECTOR2 "Vector2() -> Vector2(0, 0)\nVector2(int) -> Vector2\nVector2(float) -> Vector2\nVector2(Vector2) -> Vector2\nVector2(x, y) -> Vector2\nVector2((x, y)) -> Vector2\na 2-Dimensional Vector" #define DOC_MATH_VECTOR2_DOT "dot(Vector2, /) -> float\ncalculates the dot- or scalar-product with the other vector" diff --git a/src_c/math.c b/src_c/math.c index 49aa3acf63..97e848e16f 100644 --- a/src_c/math.c +++ b/src_c/math.c @@ -4192,6 +4192,18 @@ vector_elementwise(pgVector *vec, PyObject *_null) return (PyObject *)proxy; } +double +lerp(double a, double b, double v) +{ + return a + (b - a) * v; +} + +double +invlerp(double a, double b, double v) +{ + return (v - a)/(b - a); +} + static PyObject * math_clamp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { @@ -4233,6 +4245,81 @@ math_clamp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) return value; } +static PyObject * +math_invlerp(PyObject *self, PyObject *const *args, Py_ssize_t nargs){ + if (nargs != 3) + return RAISE(PyExc_TypeError, "invlerp requires 3 arguments"); + + PyObject *min = args[0]; + PyObject *max = args[1]; + PyObject *value = args[2]; + + if(PyNumber_Check(args[2]) != 1) + return RAISE(PyExc_TypeError, + "invlerp requires the interpolation amount to be number"); + + double t = PyFloat_AsDouble(value); + + if (t < 0) + t = 0.0; + else if (t > 1) + t = 1.0; + + + if (PyNumber_Check(min) && PyNumber_Check(max)) { + double a = PyFloat_AsDouble(min); + double b = PyFloat_AsDouble(max); + + if (b - a == 0) + return RAISE(PyExc_ZeroDivisionError, + "the result of b - a needs to be different from zero"); + + return PyFloat_FromDouble(invlerp(a, b, t)); + } + else { + return RAISE( + PyExc_TypeError, + "math.invlerp requires all the arguments to be numbers."); + } +} + +static PyObject * +math_remap(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + if (nargs != 5) + return RAISE(PyExc_TypeError, "remap requires 5 arguments"); + + PyObject *i_min = args[0]; + PyObject *i_max = args[1]; + PyObject *o_min = args[2]; + PyObject *o_max = args[3]; + PyObject *value = args[4]; + + if(PyNumber_Check(args[4]) != 1) + return RAISE(PyExc_TypeError, + "remap requires the value to be a number"); + + double v = PyFloat_AsDouble(value); + + if (PyNumber_Check(i_min) && PyNumber_Check(i_max) && PyNumber_Check(o_min) && PyNumber_Check(o_max)) { + double a = PyFloat_AsDouble(i_min); + double b = PyFloat_AsDouble(i_max); + double c = PyFloat_AsDouble(o_min); + double d = PyFloat_AsDouble(o_max); + + if (b - a == 0) + return RAISE(PyExc_ZeroDivisionError, + "the result of i_max - i_min needs to be different from zero"); + + return PyFloat_FromDouble(lerp(c, d, invlerp(a, b, v))); + } + else { + return RAISE( + PyExc_TypeError, + "math.remap requires all the arguments to be numbers."); + } +} + static PyObject * math_lerp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { @@ -4250,10 +4337,8 @@ math_lerp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) double t = PyFloat_AsDouble(value); - if (nargs == 4 && !PyObject_IsTrue(args[3])) { - ; // pass if do_clamp is false - } - else { + if (nargs != 4 || PyObject_IsTrue(args[3])) + { if (t < 0) t = 0.0; else if (t > 1) @@ -4261,8 +4346,10 @@ math_lerp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) } if (PyNumber_Check(min) && PyNumber_Check(max)) { - return PyFloat_FromDouble(PyFloat_AsDouble(min) * (1 - t) + - PyFloat_AsDouble(max) * t); + double a = PyFloat_AsDouble(min); + double b = PyFloat_AsDouble(max); + + return PyFloat_FromDouble(lerp(a, b, t)); } else { return RAISE( @@ -4343,6 +4430,8 @@ math_disable_swizzling(pgVector *self, PyObject *_null) static PyMethodDef _math_methods[] = { {"clamp", (PyCFunction)math_clamp, METH_FASTCALL, DOC_MATH_CLAMP}, {"lerp", (PyCFunction)math_lerp, METH_FASTCALL, DOC_MATH_LERP}, + {"invlerp", (PyCFunction)math_invlerp, METH_FASTCALL, DOC_MATH_INVLERP}, + {"remap", (PyCFunction)math_remap, METH_FASTCALL, DOC_MATH_REMAP}, {"smoothstep", (PyCFunction)math_smoothstep, METH_FASTCALL, DOC_MATH_SMOOTHSTEP}, {"enable_swizzling", (PyCFunction)math_enable_swizzling, METH_NOARGS, From 3e6fe92facc32e20b085e4bcde6807472b3df8a5 Mon Sep 17 00:00:00 2001 From: bilhox Date: Thu, 4 Jan 2024 11:16:15 +0100 Subject: [PATCH 02/31] remove test code --- a.py | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 a.py diff --git a/a.py b/a.py deleted file mode 100644 index 9102725738..0000000000 --- a/a.py +++ /dev/null @@ -1,15 +0,0 @@ -import numpy -import pygame -import random - -from statistics import median -from timeit import timeit - -def foo(): - - c = pygame.math.invlerp(238782374, 34729374275, 0.3478098) - -t = [timeit(foo, number=500_000) for _ in range(50)] -print(median(t)) - -print(pygame.math.remap(0, 100, 0, 200, 50)) \ No newline at end of file From 4f9ca04afdd0aaa2e6b73bca082fe9f5ecad012d Mon Sep 17 00:00:00 2001 From: bilhox Date: Thu, 4 Jan 2024 14:02:02 +0100 Subject: [PATCH 03/31] potential fix --- src_c/doc/math_doc.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src_c/doc/math_doc.h b/src_c/doc/math_doc.h index 75d906d95b..0c38edbaa2 100644 --- a/src_c/doc/math_doc.h +++ b/src_c/doc/math_doc.h @@ -2,8 +2,6 @@ #define DOC_MATH "pygame module for vector classes" #define DOC_MATH_CLAMP "clamp(value, min, max, /) -> float\nreturns value clamped to min and max." #define DOC_MATH_LERP "lerp(a, b, value, do_clamp=True, /) -> float\nreturns value linearly interpolated between a and b" -#define DOC_MATH_REMAP "remap(i_min, i_max, o_min, o_max, value, /) -> float\nremaps value from i_range to o_range" -#define DOC_MATH_INVLERP "invlerp(a, b, value, /) -> float\nreturns value inverse interpolated between a and b" #define DOC_MATH_SMOOTHSTEP "smoothstep(a, b, value, /) -> float\nreturns value smoothly interpolated between a and b." #define DOC_MATH_VECTOR2 "Vector2() -> Vector2(0, 0)\nVector2(int) -> Vector2\nVector2(float) -> Vector2\nVector2(Vector2) -> Vector2\nVector2(x, y) -> Vector2\nVector2((x, y)) -> Vector2\na 2-Dimensional Vector" #define DOC_MATH_VECTOR2_DOT "dot(Vector2, /) -> float\ncalculates the dot- or scalar-product with the other vector" From 1b196b85047e4b59cab3166af3b4d22ab70da2ef Mon Sep 17 00:00:00 2001 From: bilhox Date: Thu, 4 Jan 2024 14:05:01 +0100 Subject: [PATCH 04/31] clang fix --- src_c/math.c | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src_c/math.c b/src_c/math.c index 97e848e16f..4f7ef36b04 100644 --- a/src_c/math.c +++ b/src_c/math.c @@ -4192,7 +4192,7 @@ vector_elementwise(pgVector *vec, PyObject *_null) return (PyObject *)proxy; } -double +double lerp(double a, double b, double v) { return a + (b - a) * v; @@ -4201,7 +4201,7 @@ lerp(double a, double b, double v) double invlerp(double a, double b, double v) { - return (v - a)/(b - a); + return (v - a) / (b - a); } static PyObject * @@ -4246,7 +4246,8 @@ math_clamp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) } static PyObject * -math_invlerp(PyObject *self, PyObject *const *args, Py_ssize_t nargs){ +math_invlerp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ if (nargs != 3) return RAISE(PyExc_TypeError, "invlerp requires 3 arguments"); @@ -4254,32 +4255,31 @@ math_invlerp(PyObject *self, PyObject *const *args, Py_ssize_t nargs){ PyObject *max = args[1]; PyObject *value = args[2]; - if(PyNumber_Check(args[2]) != 1) + if (PyNumber_Check(args[2]) != 1) return RAISE(PyExc_TypeError, "invlerp requires the interpolation amount to be number"); - + double t = PyFloat_AsDouble(value); if (t < 0) t = 0.0; else if (t > 1) t = 1.0; - if (PyNumber_Check(min) && PyNumber_Check(max)) { double a = PyFloat_AsDouble(min); double b = PyFloat_AsDouble(max); if (b - a == 0) - return RAISE(PyExc_ZeroDivisionError, - "the result of b - a needs to be different from zero"); + return RAISE( + PyExc_ZeroDivisionError, + "the result of b - a needs to be different from zero"); return PyFloat_FromDouble(invlerp(a, b, t)); } else { - return RAISE( - PyExc_TypeError, - "math.invlerp requires all the arguments to be numbers."); + return RAISE(PyExc_TypeError, + "math.invlerp requires all the arguments to be numbers."); } } @@ -4288,35 +4288,36 @@ math_remap(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { if (nargs != 5) return RAISE(PyExc_TypeError, "remap requires 5 arguments"); - + PyObject *i_min = args[0]; PyObject *i_max = args[1]; PyObject *o_min = args[2]; PyObject *o_max = args[3]; PyObject *value = args[4]; - if(PyNumber_Check(args[4]) != 1) + if (PyNumber_Check(args[4]) != 1) return RAISE(PyExc_TypeError, "remap requires the value to be a number"); - + double v = PyFloat_AsDouble(value); - - if (PyNumber_Check(i_min) && PyNumber_Check(i_max) && PyNumber_Check(o_min) && PyNumber_Check(o_max)) { + + if (PyNumber_Check(i_min) && PyNumber_Check(i_max) && + PyNumber_Check(o_min) && PyNumber_Check(o_max)) { double a = PyFloat_AsDouble(i_min); double b = PyFloat_AsDouble(i_max); double c = PyFloat_AsDouble(o_min); double d = PyFloat_AsDouble(o_max); if (b - a == 0) - return RAISE(PyExc_ZeroDivisionError, - "the result of i_max - i_min needs to be different from zero"); + return RAISE( + PyExc_ZeroDivisionError, + "the result of i_max - i_min needs to be different from zero"); return PyFloat_FromDouble(lerp(c, d, invlerp(a, b, v))); } else { - return RAISE( - PyExc_TypeError, - "math.remap requires all the arguments to be numbers."); + return RAISE(PyExc_TypeError, + "math.remap requires all the arguments to be numbers."); } } @@ -4337,8 +4338,7 @@ math_lerp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) double t = PyFloat_AsDouble(value); - if (nargs != 4 || PyObject_IsTrue(args[3])) - { + if (nargs != 4 || PyObject_IsTrue(args[3])) { if (t < 0) t = 0.0; else if (t > 1) From 7e20fb8011889d0e71fb085b01838e9c2f15e3eb Mon Sep 17 00:00:00 2001 From: bilhox Date: Thu, 4 Jan 2024 14:20:13 +0100 Subject: [PATCH 05/31] docs --- src_c/doc/math_doc.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src_c/doc/math_doc.h b/src_c/doc/math_doc.h index 0c38edbaa2..75d906d95b 100644 --- a/src_c/doc/math_doc.h +++ b/src_c/doc/math_doc.h @@ -2,6 +2,8 @@ #define DOC_MATH "pygame module for vector classes" #define DOC_MATH_CLAMP "clamp(value, min, max, /) -> float\nreturns value clamped to min and max." #define DOC_MATH_LERP "lerp(a, b, value, do_clamp=True, /) -> float\nreturns value linearly interpolated between a and b" +#define DOC_MATH_REMAP "remap(i_min, i_max, o_min, o_max, value, /) -> float\nremaps value from i_range to o_range" +#define DOC_MATH_INVLERP "invlerp(a, b, value, /) -> float\nreturns value inverse interpolated between a and b" #define DOC_MATH_SMOOTHSTEP "smoothstep(a, b, value, /) -> float\nreturns value smoothly interpolated between a and b." #define DOC_MATH_VECTOR2 "Vector2() -> Vector2(0, 0)\nVector2(int) -> Vector2\nVector2(float) -> Vector2\nVector2(Vector2) -> Vector2\nVector2(x, y) -> Vector2\nVector2((x, y)) -> Vector2\na 2-Dimensional Vector" #define DOC_MATH_VECTOR2_DOT "dot(Vector2, /) -> float\ncalculates the dot- or scalar-product with the other vector" From 66c817f507baf687923d6b84a30ab5ac1778a1c1 Mon Sep 17 00:00:00 2001 From: bilhox Date: Thu, 4 Jan 2024 14:37:02 +0100 Subject: [PATCH 06/31] docs fix --- docs/reST/ref/math.rst | 39 ++++++++++++++++++++++++++++++++++++++- src_c/doc/math_doc.h | 2 +- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/docs/reST/ref/math.rst b/docs/reST/ref/math.rst index 9ab1d6cd9d..edf0f7a69f 100644 --- a/docs/reST/ref/math.rst +++ b/docs/reST/ref/math.rst @@ -73,12 +73,30 @@ Multiple coordinates can be set using slices or swizzling The formula is: - ``a * value + (1 - value) * b``. + ``a + (b - a) * value``. .. versionadded:: 2.4.0 .. ## math.lerp ## +.. function:: invlerp + + | :sl:`returns value inverse interpolated between a and b` + | :sg:`invlerp(a, b, value, /) -> float` + + Returns a number which is a inverse interpolation between ``a`` + and ``b``. The third parameter determines how far between ``a`` and + ``b`` the result is going to be. + If ``b - a`` is equal to 0, it raises a ``ZeroDivisionError``. + + The formula is: + + ``(v - a)/(b - a)``. + + .. versionadded:: 2.5.0 + + .. ## math.invlerp ## + .. function:: smoothstep | :sl:`returns value smoothly interpolated between a and b.` @@ -102,6 +120,25 @@ Multiple coordinates can be set using slices or swizzling .. ## math.smoothstep ## +.. function:: remap + + | :sl:`remaps value from i_range to o_range` + | :sg:`remap(i_min, i_max, o_min, o_max, value, /) -> float` + + Returns a number which is the value remapped from ``i_range`` to + ``o_range``. + If ``i_max - i_min`` is equal to 0, it raises a ``ZeroDivisionError``. + + Example: + + :: + > pygame.math.remap(0, 100, 0, 200, 50) + > 100.0 + + .. versionadded:: 2.5.0 + + .. ## math.lerp ## + .. class:: Vector2 | :sl:`a 2-Dimensional Vector` diff --git a/src_c/doc/math_doc.h b/src_c/doc/math_doc.h index 75d906d95b..f5ceebb0bc 100644 --- a/src_c/doc/math_doc.h +++ b/src_c/doc/math_doc.h @@ -2,9 +2,9 @@ #define DOC_MATH "pygame module for vector classes" #define DOC_MATH_CLAMP "clamp(value, min, max, /) -> float\nreturns value clamped to min and max." #define DOC_MATH_LERP "lerp(a, b, value, do_clamp=True, /) -> float\nreturns value linearly interpolated between a and b" -#define DOC_MATH_REMAP "remap(i_min, i_max, o_min, o_max, value, /) -> float\nremaps value from i_range to o_range" #define DOC_MATH_INVLERP "invlerp(a, b, value, /) -> float\nreturns value inverse interpolated between a and b" #define DOC_MATH_SMOOTHSTEP "smoothstep(a, b, value, /) -> float\nreturns value smoothly interpolated between a and b." +#define DOC_MATH_REMAP "remap(i_min, i_max, o_min, o_max, value, /) -> float\nremaps value from i_range to o_range" #define DOC_MATH_VECTOR2 "Vector2() -> Vector2(0, 0)\nVector2(int) -> Vector2\nVector2(float) -> Vector2\nVector2(Vector2) -> Vector2\nVector2(x, y) -> Vector2\nVector2((x, y)) -> Vector2\na 2-Dimensional Vector" #define DOC_MATH_VECTOR2_DOT "dot(Vector2, /) -> float\ncalculates the dot- or scalar-product with the other vector" #define DOC_MATH_VECTOR2_CROSS "cross(Vector2, /) -> float\ncalculates the cross- or vector-product" From cf51bf6e77de34bfd95c2097c5f02d4b8d75d68c Mon Sep 17 00:00:00 2001 From: bilhox Date: Thu, 4 Jan 2024 14:48:52 +0100 Subject: [PATCH 07/31] docs fix 2 --- docs/reST/ref/math.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/reST/ref/math.rst b/docs/reST/ref/math.rst index edf0f7a69f..53833de29a 100644 --- a/docs/reST/ref/math.rst +++ b/docs/reST/ref/math.rst @@ -132,8 +132,8 @@ Multiple coordinates can be set using slices or swizzling Example: :: - > pygame.math.remap(0, 100, 0, 200, 50) - > 100.0 + pygame.math.remap(0, 100, 0, 200, 50) + 100.0 .. versionadded:: 2.5.0 From a291038fe416b3ef9e43ae22382dcc10a6d5e489 Mon Sep 17 00:00:00 2001 From: bilhox Date: Thu, 4 Jan 2024 14:57:51 +0100 Subject: [PATCH 08/31] stub fix --- docs/reST/ref/math.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reST/ref/math.rst b/docs/reST/ref/math.rst index 53833de29a..a815b16e71 100644 --- a/docs/reST/ref/math.rst +++ b/docs/reST/ref/math.rst @@ -134,7 +134,7 @@ Multiple coordinates can be set using slices or swizzling :: pygame.math.remap(0, 100, 0, 200, 50) 100.0 - + .. versionadded:: 2.5.0 .. ## math.lerp ## From f5524ef602abd289da8ba12fcf2ce2e975039a2f Mon Sep 17 00:00:00 2001 From: bilhox Date: Thu, 4 Jan 2024 14:58:35 +0100 Subject: [PATCH 09/31] stub fix 2 --- docs/reST/ref/math.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/reST/ref/math.rst b/docs/reST/ref/math.rst index a815b16e71..5dd410070a 100644 --- a/docs/reST/ref/math.rst +++ b/docs/reST/ref/math.rst @@ -134,10 +134,10 @@ Multiple coordinates can be set using slices or swizzling :: pygame.math.remap(0, 100, 0, 200, 50) 100.0 - + .. versionadded:: 2.5.0 - .. ## math.lerp ## + .. ## math.remap ## .. class:: Vector2 From f5579839083fb88559030a757753c99219d513a1 Mon Sep 17 00:00:00 2001 From: bilhox Date: Thu, 4 Jan 2024 20:30:48 +0100 Subject: [PATCH 10/31] revert lerp & overflow prevention --- buildconfig/stubs/pygame/math.pyi | 3 +- docs/reST/ref/math.rst | 13 ++++-- src_c/math.c | 78 +++++++++++++++---------------- 3 files changed, 48 insertions(+), 46 deletions(-) diff --git a/buildconfig/stubs/pygame/math.pyi b/buildconfig/stubs/pygame/math.pyi index 230a3a7b97..50cdbec95d 100644 --- a/buildconfig/stubs/pygame/math.pyi +++ b/buildconfig/stubs/pygame/math.pyi @@ -334,7 +334,8 @@ class Vector3(_GenericVector): def lerp(a: float, b: float, weight: float, do_clamp: bool = True, /) -> float: ... -def invlerp(a: float, b: float, weight: float /) -> float: ... +def invlerp(a: float, b: float, weight: float, /) -> float: ... +def remap(i_min : float, i_max : float, o_min : float, o_max : float, value : float , /) -> float: ... def smoothstep(a: float, b: float, weight: float, /) -> float: ... diff --git a/docs/reST/ref/math.rst b/docs/reST/ref/math.rst index 5dd410070a..31049d3e73 100644 --- a/docs/reST/ref/math.rst +++ b/docs/reST/ref/math.rst @@ -73,7 +73,7 @@ Multiple coordinates can be set using slices or swizzling The formula is: - ``a + (b - a) * value``. + ``a * value + (1 - value) * b``. .. versionadded:: 2.4.0 @@ -84,7 +84,7 @@ Multiple coordinates can be set using slices or swizzling | :sl:`returns value inverse interpolated between a and b` | :sg:`invlerp(a, b, value, /) -> float` - Returns a number which is a inverse interpolation between ``a`` + Returns a number which is an inverse interpolation between ``a`` and ``b``. The third parameter determines how far between ``a`` and ``b`` the result is going to be. If ``b - a`` is equal to 0, it raises a ``ZeroDivisionError``. @@ -131,9 +131,12 @@ Multiple coordinates can be set using slices or swizzling Example: - :: - pygame.math.remap(0, 100, 0, 200, 50) - 100.0 + .. code-block:: python + + > value = 50 + > pygame.math.remap(0, 100, 0, 200, value) + > 100.0 + .. versionadded:: 2.5.0 diff --git a/src_c/math.c b/src_c/math.c index 4f7ef36b04..258961562f 100644 --- a/src_c/math.c +++ b/src_c/math.c @@ -4249,15 +4249,16 @@ static PyObject * math_invlerp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { if (nargs != 3) - return RAISE(PyExc_TypeError, "invlerp requires 3 arguments"); + return RAISE(PyExc_TypeError, + "invlerp requires exactly 3 numeric arguments"); PyObject *min = args[0]; PyObject *max = args[1]; PyObject *value = args[2]; - if (PyNumber_Check(args[2]) != 1) + if (!PyNumber_Check(min) || !PyNumber_Check(max) || !PyNumber_Check(value)) return RAISE(PyExc_TypeError, - "invlerp requires the interpolation amount to be number"); + "invlerp requires all the arguments to be numbers."); double t = PyFloat_AsDouble(value); @@ -4266,28 +4267,26 @@ math_invlerp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) else if (t > 1) t = 1.0; - if (PyNumber_Check(min) && PyNumber_Check(max)) { - double a = PyFloat_AsDouble(min); - double b = PyFloat_AsDouble(max); + double a = PyFloat_AsDouble(min); + double b = PyFloat_AsDouble(max); - if (b - a == 0) - return RAISE( - PyExc_ZeroDivisionError, - "the result of b - a needs to be different from zero"); + if (PyErr_Occurred()) + return RAISE(PyExc_ValueError, + "Invalid argument values passed to invlerp."); - return PyFloat_FromDouble(invlerp(a, b, t)); - } - else { - return RAISE(PyExc_TypeError, - "math.invlerp requires all the arguments to be numbers."); - } + if (b - a == 0) + return RAISE(PyExc_ZeroDivisionError, + "the result of b - a needs to be different from zero"); + + return PyFloat_FromDouble(invlerp(a, b, t)); } static PyObject * math_remap(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { if (nargs != 5) - return RAISE(PyExc_TypeError, "remap requires 5 arguments"); + return RAISE(PyExc_TypeError, + "remap requires exactly 5 numeric arguments"); PyObject *i_min = args[0]; PyObject *i_max = args[1]; @@ -4295,30 +4294,28 @@ math_remap(PyObject *self, PyObject *const *args, Py_ssize_t nargs) PyObject *o_max = args[3]; PyObject *value = args[4]; - if (PyNumber_Check(args[4]) != 1) + if (!PyNumber_Check(value) || !PyNumber_Check(i_min) || + !PyNumber_Check(i_max) || !PyNumber_Check(o_min) || + !PyNumber_Check(o_max)) return RAISE(PyExc_TypeError, - "remap requires the value to be a number"); + "remap requires all the arguments to be numbers."); double v = PyFloat_AsDouble(value); + double a = PyFloat_AsDouble(i_min); + double b = PyFloat_AsDouble(i_max); + double c = PyFloat_AsDouble(o_min); + double d = PyFloat_AsDouble(o_max); - if (PyNumber_Check(i_min) && PyNumber_Check(i_max) && - PyNumber_Check(o_min) && PyNumber_Check(o_max)) { - double a = PyFloat_AsDouble(i_min); - double b = PyFloat_AsDouble(i_max); - double c = PyFloat_AsDouble(o_min); - double d = PyFloat_AsDouble(o_max); + if (PyErr_Occurred()) + return RAISE(PyExc_ValueError, + "Invalid argument values passed to remap."); - if (b - a == 0) - return RAISE( - PyExc_ZeroDivisionError, - "the result of i_max - i_min needs to be different from zero"); + if (b - a == 0) + return RAISE( + PyExc_ZeroDivisionError, + "the result of i_max - i_min needs to be different from zero"); - return PyFloat_FromDouble(lerp(c, d, invlerp(a, b, v))); - } - else { - return RAISE(PyExc_TypeError, - "math.remap requires all the arguments to be numbers."); - } + return PyFloat_FromDouble(lerp(c, d, invlerp(a, b, v))); } static PyObject * @@ -4338,7 +4335,10 @@ math_lerp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) double t = PyFloat_AsDouble(value); - if (nargs != 4 || PyObject_IsTrue(args[3])) { + if (nargs == 4 && !PyObject_IsTrue(args[3])) { + ; // pass if do_clamp is false + } + else { if (t < 0) t = 0.0; else if (t > 1) @@ -4346,10 +4346,8 @@ math_lerp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) } if (PyNumber_Check(min) && PyNumber_Check(max)) { - double a = PyFloat_AsDouble(min); - double b = PyFloat_AsDouble(max); - - return PyFloat_FromDouble(lerp(a, b, t)); + return PyFloat_FromDouble(PyFloat_AsDouble(min) * (1 - t) + + PyFloat_AsDouble(max) * t); } else { return RAISE( From 5f41e95a38598bcbff1c2c65e899f63c75b46059 Mon Sep 17 00:00:00 2001 From: bilhox Date: Sat, 6 Jan 2024 15:05:29 +0100 Subject: [PATCH 11/31] unittest & stub fix & error message --- a.py | 3 + buildconfig/stubs/pygame/math.pyi | 2 +- src_c/math.c | 8 +-- test/math_test.py | 102 ++++++++++++++++++++++++++++++ 4 files changed, 110 insertions(+), 5 deletions(-) create mode 100644 a.py diff --git a/a.py b/a.py new file mode 100644 index 0000000000..179f18a264 --- /dev/null +++ b/a.py @@ -0,0 +1,3 @@ +import pygame + +print(pygame.math.remap(0, 10, 0, 100, -1)) \ No newline at end of file diff --git a/buildconfig/stubs/pygame/math.pyi b/buildconfig/stubs/pygame/math.pyi index 50cdbec95d..09cb1cc170 100644 --- a/buildconfig/stubs/pygame/math.pyi +++ b/buildconfig/stubs/pygame/math.pyi @@ -335,7 +335,7 @@ class Vector3(_GenericVector): def lerp(a: float, b: float, weight: float, do_clamp: bool = True, /) -> float: ... def invlerp(a: float, b: float, weight: float, /) -> float: ... -def remap(i_min : float, i_max : float, o_min : float, o_max : float, value : float , /) -> float: ... +def remap(i_min: float, i_max: float, o_min: float, o_max: float, value: float , /) -> float: ... def smoothstep(a: float, b: float, weight: float, /) -> float: ... diff --git a/src_c/math.c b/src_c/math.c index 258961562f..f42a43696b 100644 --- a/src_c/math.c +++ b/src_c/math.c @@ -4192,13 +4192,13 @@ vector_elementwise(pgVector *vec, PyObject *_null) return (PyObject *)proxy; } -double +inline double lerp(double a, double b, double v) { return a + (b - a) * v; } -double +inline double invlerp(double a, double b, double v) { return (v - a) / (b - a); @@ -4272,7 +4272,7 @@ math_invlerp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) if (PyErr_Occurred()) return RAISE(PyExc_ValueError, - "Invalid argument values passed to invlerp."); + "invalid argument values passed to invlerp, numbers might be too small or too big."); if (b - a == 0) return RAISE(PyExc_ZeroDivisionError, @@ -4308,7 +4308,7 @@ math_remap(PyObject *self, PyObject *const *args, Py_ssize_t nargs) if (PyErr_Occurred()) return RAISE(PyExc_ValueError, - "Invalid argument values passed to remap."); + "invalid argument values passed to remap, numbers might be too small or too big."); if (b - a == 0) return RAISE( diff --git a/test/math_test.py b/test/math_test.py index 1d8408fbb4..46dc99e0e3 100644 --- a/test/math_test.py +++ b/test/math_test.py @@ -85,6 +85,108 @@ def test_lerp(self): a = 1 b = 2 pygame.math.lerp(a, b, Vector2(0, 0)) + + def test_invlerp(self): + a = 0.0 + b = 10.0 + self.assertEqual(pygame.math.invlerp(a, b, 0.5), 0.05) + + a = 0.0 + b = 10.0 + self.assertEqual(pygame.math.invlerp(a, b, 0.1), 0.01) + + a = -10.0 + b = 10.0 + self.assertEqual(pygame.math.invlerp(a, b, 0.5), 0.525) + + a = -10.0 + b = 10.0 + self.assertEqual(pygame.math.invlerp(a, b, 1.5), 0.55) + + a = 0.0 + b = 100.0 + self.assertEqual(pygame.math.invlerp(a, b, 0.25), 0.0025) + + with self.assertRaises(TypeError): + a = Vector2(0, 0) + b = Vector2(10.0, 10.0) + pygame.math.invlerp(a, b, 0.5) + + with self.assertRaises(TypeError): + a = 1 + b = 2 + pygame.math.invlerp(a, b, Vector2(0, 0)) + + with self.assertRaises(ZeroDivisionError): + a = 5 + b = 5 + pygame.math.invlerp(a, b, 5) + + with self.assertRaises(ValueError): + a = 12**300 + b = 11**30 + pygame.math.invlerp(a, b, 1) + + def test_remap(self): + a = 0.0 + b = 10.0 + c = 0.0 + d = 100.0 + self.assertEqual(pygame.math.remap(a, b, c, d, 1.0), 10.0) + + a = 0.0 + b = 10.0 + c = 0.0 + d = 100.0 + self.assertEqual(pygame.math.remap(a, b, c, d, -1.0), -10.0) + + a = -10.0 + b = 10.0 + c = -20.0 + d = 20.0 + self.assertEqual(pygame.math.remap(a, b, c, d, 0.0), 0.0) + + a = -10.0 + b = 10.0 + c = 10.0 + d = 110.0 + self.assertEqual(pygame.math.remap(a, b, c, d, -8.0), 20.0) + + with self.assertRaises(TypeError): + a = Vector2(0, 0) + b = "fish" + c = "durk" + d = Vector2(100, 100) + pygame.math.remap(a, b, c, d, 10) + + with self.assertRaises(TypeError): + a = 1 + b = 2 + c = 10 + d = 20 + pygame.math.remap(a, b, c, d, Vector2(0, 0)) + + with self.assertRaises(ZeroDivisionError): + a = 5 + b = 5 + c = 0 + d = 100 + pygame.math.remap(a, b, c, d, 10) + + with self.assertRaises(ValueError): + a = 12**300 + b = 11**30 + c = 20 + d = 30 + pygame.math.remap(a, b, c, d, 100*50) + + with self.assertRaises(ValueError): + a = 12j + b = 11j + c = 10j + d = 9j + pygame.math.remap(a, b, c, d, 50j) + def test_smoothstep(self): a = 0.0 From 0f552cdec6105bf31393c27ab3b02183aaea42cd Mon Sep 17 00:00:00 2001 From: bilhox Date: Sat, 6 Jan 2024 15:05:54 +0100 Subject: [PATCH 12/31] test removal --- a.py | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 a.py diff --git a/a.py b/a.py deleted file mode 100644 index 179f18a264..0000000000 --- a/a.py +++ /dev/null @@ -1,3 +0,0 @@ -import pygame - -print(pygame.math.remap(0, 10, 0, 100, -1)) \ No newline at end of file From 3f83b7fd05be83594dc05aa05ec0caf90f31f909 Mon Sep 17 00:00:00 2001 From: bilhox Date: Sat, 6 Jan 2024 15:07:26 +0100 Subject: [PATCH 13/31] format fix --- src_c/math.c | 6 ++++-- test/math_test.py | 17 ++++++++--------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src_c/math.c b/src_c/math.c index f42a43696b..0b29509b54 100644 --- a/src_c/math.c +++ b/src_c/math.c @@ -4272,7 +4272,8 @@ math_invlerp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) if (PyErr_Occurred()) return RAISE(PyExc_ValueError, - "invalid argument values passed to invlerp, numbers might be too small or too big."); + "invalid argument values passed to invlerp, numbers " + "might be too small or too big."); if (b - a == 0) return RAISE(PyExc_ZeroDivisionError, @@ -4308,7 +4309,8 @@ math_remap(PyObject *self, PyObject *const *args, Py_ssize_t nargs) if (PyErr_Occurred()) return RAISE(PyExc_ValueError, - "invalid argument values passed to remap, numbers might be too small or too big."); + "invalid argument values passed to remap, numbers might " + "be too small or too big."); if (b - a == 0) return RAISE( diff --git a/test/math_test.py b/test/math_test.py index 46dc99e0e3..9dc89d704b 100644 --- a/test/math_test.py +++ b/test/math_test.py @@ -85,7 +85,7 @@ def test_lerp(self): a = 1 b = 2 pygame.math.lerp(a, b, Vector2(0, 0)) - + def test_invlerp(self): a = 0.0 b = 10.0 @@ -116,17 +116,17 @@ def test_invlerp(self): a = 1 b = 2 pygame.math.invlerp(a, b, Vector2(0, 0)) - + with self.assertRaises(ZeroDivisionError): a = 5 b = 5 pygame.math.invlerp(a, b, 5) - + with self.assertRaises(ValueError): a = 12**300 b = 11**30 pygame.math.invlerp(a, b, 1) - + def test_remap(self): a = 0.0 b = 10.0 @@ -165,21 +165,21 @@ def test_remap(self): c = 10 d = 20 pygame.math.remap(a, b, c, d, Vector2(0, 0)) - + with self.assertRaises(ZeroDivisionError): a = 5 b = 5 c = 0 d = 100 pygame.math.remap(a, b, c, d, 10) - + with self.assertRaises(ValueError): a = 12**300 b = 11**30 c = 20 d = 30 - pygame.math.remap(a, b, c, d, 100*50) - + pygame.math.remap(a, b, c, d, 100 * 50) + with self.assertRaises(ValueError): a = 12j b = 11j @@ -187,7 +187,6 @@ def test_remap(self): d = 9j pygame.math.remap(a, b, c, d, 50j) - def test_smoothstep(self): a = 0.0 b = 10.0 From d2b053b218ad97111b13721bf82aaf8ee0dd17bb Mon Sep 17 00:00:00 2001 From: bilhox Date: Sat, 6 Jan 2024 15:09:12 +0100 Subject: [PATCH 14/31] period --- src_c/math.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src_c/math.c b/src_c/math.c index 0b29509b54..8ade12df33 100644 --- a/src_c/math.c +++ b/src_c/math.c @@ -4250,7 +4250,7 @@ math_invlerp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { if (nargs != 3) return RAISE(PyExc_TypeError, - "invlerp requires exactly 3 numeric arguments"); + "invlerp requires exactly 3 numeric arguments."); PyObject *min = args[0]; PyObject *max = args[1]; @@ -4277,7 +4277,7 @@ math_invlerp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) if (b - a == 0) return RAISE(PyExc_ZeroDivisionError, - "the result of b - a needs to be different from zero"); + "the result of b - a needs to be different from zero."); return PyFloat_FromDouble(invlerp(a, b, t)); } @@ -4287,7 +4287,7 @@ math_remap(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { if (nargs != 5) return RAISE(PyExc_TypeError, - "remap requires exactly 5 numeric arguments"); + "remap requires exactly 5 numeric arguments."); PyObject *i_min = args[0]; PyObject *i_max = args[1]; @@ -4315,7 +4315,7 @@ math_remap(PyObject *self, PyObject *const *args, Py_ssize_t nargs) if (b - a == 0) return RAISE( PyExc_ZeroDivisionError, - "the result of i_max - i_min needs to be different from zero"); + "the result of i_max - i_min needs to be different from zero."); return PyFloat_FromDouble(lerp(c, d, invlerp(a, b, v))); } From 969b2b04239525c6ec3421ee434b43daea4d22ad Mon Sep 17 00:00:00 2001 From: bilhox Date: Sat, 6 Jan 2024 15:12:08 +0100 Subject: [PATCH 15/31] period --- src_c/math.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src_c/math.c b/src_c/math.c index 8ade12df33..92f6e83bee 100644 --- a/src_c/math.c +++ b/src_c/math.c @@ -4250,7 +4250,7 @@ math_invlerp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { if (nargs != 3) return RAISE(PyExc_TypeError, - "invlerp requires exactly 3 numeric arguments."); + "invlerp requires exactly 3 numeric arguments"); PyObject *min = args[0]; PyObject *max = args[1]; @@ -4258,7 +4258,7 @@ math_invlerp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) if (!PyNumber_Check(min) || !PyNumber_Check(max) || !PyNumber_Check(value)) return RAISE(PyExc_TypeError, - "invlerp requires all the arguments to be numbers."); + "invlerp requires all the arguments to be numbers"); double t = PyFloat_AsDouble(value); @@ -4273,11 +4273,11 @@ math_invlerp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) if (PyErr_Occurred()) return RAISE(PyExc_ValueError, "invalid argument values passed to invlerp, numbers " - "might be too small or too big."); + "might be too small or too big"); if (b - a == 0) return RAISE(PyExc_ZeroDivisionError, - "the result of b - a needs to be different from zero."); + "the result of b - a needs to be different from zero"); return PyFloat_FromDouble(invlerp(a, b, t)); } @@ -4287,7 +4287,7 @@ math_remap(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { if (nargs != 5) return RAISE(PyExc_TypeError, - "remap requires exactly 5 numeric arguments."); + "remap requires exactly 5 numeric arguments"); PyObject *i_min = args[0]; PyObject *i_max = args[1]; @@ -4299,7 +4299,7 @@ math_remap(PyObject *self, PyObject *const *args, Py_ssize_t nargs) !PyNumber_Check(i_max) || !PyNumber_Check(o_min) || !PyNumber_Check(o_max)) return RAISE(PyExc_TypeError, - "remap requires all the arguments to be numbers."); + "remap requires all the arguments to be numbers"); double v = PyFloat_AsDouble(value); double a = PyFloat_AsDouble(i_min); @@ -4310,12 +4310,12 @@ math_remap(PyObject *self, PyObject *const *args, Py_ssize_t nargs) if (PyErr_Occurred()) return RAISE(PyExc_ValueError, "invalid argument values passed to remap, numbers might " - "be too small or too big."); + "be too small or too big"); if (b - a == 0) return RAISE( PyExc_ZeroDivisionError, - "the result of i_max - i_min needs to be different from zero."); + "the result of i_max - i_min needs to be different from zero"); return PyFloat_FromDouble(lerp(c, d, invlerp(a, b, v))); } From 3868b04ca2658707bcd9e7d99241d6f7219993a1 Mon Sep 17 00:00:00 2001 From: bilhox Date: Sat, 6 Jan 2024 15:58:57 +0100 Subject: [PATCH 16/31] space moments --- buildconfig/stubs/pygame/math.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildconfig/stubs/pygame/math.pyi b/buildconfig/stubs/pygame/math.pyi index 09cb1cc170..82ec91c7a0 100644 --- a/buildconfig/stubs/pygame/math.pyi +++ b/buildconfig/stubs/pygame/math.pyi @@ -335,7 +335,7 @@ class Vector3(_GenericVector): def lerp(a: float, b: float, weight: float, do_clamp: bool = True, /) -> float: ... def invlerp(a: float, b: float, weight: float, /) -> float: ... -def remap(i_min: float, i_max: float, o_min: float, o_max: float, value: float , /) -> float: ... +def remap(i_min: float, i_max: float, o_min: float, o_max: float, value: float, /) -> float: ... def smoothstep(a: float, b: float, weight: float, /) -> float: ... From 99d0682376fe68622e78de333c344d41d3b8d89d Mon Sep 17 00:00:00 2001 From: Dan Lawrence Date: Sun, 11 Feb 2024 12:25:59 +0000 Subject: [PATCH 17/31] Improve inverse lerp tests --- test/math_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/math_test.py b/test/math_test.py index 9dc89d704b..795a5b9d8f 100644 --- a/test/math_test.py +++ b/test/math_test.py @@ -89,7 +89,7 @@ def test_lerp(self): def test_invlerp(self): a = 0.0 b = 10.0 - self.assertEqual(pygame.math.invlerp(a, b, 0.5), 0.05) + self.assertEqual(pygame.math.invlerp(a, b, 5.0), 0.5) a = 0.0 b = 10.0 From 93aa1a91692443d01c67ff394fd56d137f28097c Mon Sep 17 00:00:00 2001 From: Dan Lawrence Date: Sun, 11 Feb 2024 12:28:29 +0000 Subject: [PATCH 18/31] Correcting test --- test/math_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/math_test.py b/test/math_test.py index 795a5b9d8f..a0d426ae2e 100644 --- a/test/math_test.py +++ b/test/math_test.py @@ -101,7 +101,7 @@ def test_invlerp(self): a = -10.0 b = 10.0 - self.assertEqual(pygame.math.invlerp(a, b, 1.5), 0.55) + self.assertEqual(pygame.math.invlerp(a, b, 1.0), 0.55) a = 0.0 b = 100.0 From 43dc68f8190affbf2fb58383892764bff4dd8fcc Mon Sep 17 00:00:00 2001 From: Dan Lawrence Date: Sun, 11 Feb 2024 12:30:22 +0000 Subject: [PATCH 19/31] Improve test. --- test/math_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/math_test.py b/test/math_test.py index a0d426ae2e..f384c4f4f8 100644 --- a/test/math_test.py +++ b/test/math_test.py @@ -101,7 +101,7 @@ def test_invlerp(self): a = -10.0 b = 10.0 - self.assertEqual(pygame.math.invlerp(a, b, 1.0), 0.55) + self.assertEqual(pygame.math.invlerp(a, b, 1.5), 0.575) a = 0.0 b = 100.0 From 8960d023d591f5fb94bc655cbf871cc1d37d031b Mon Sep 17 00:00:00 2001 From: bilhox Date: Sun, 11 Feb 2024 13:39:52 +0100 Subject: [PATCH 20/31] uncap invlerp value --- src_c/math.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src_c/math.c b/src_c/math.c index 92f6e83bee..0ddeead800 100644 --- a/src_c/math.c +++ b/src_c/math.c @@ -4261,12 +4261,6 @@ math_invlerp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) "invlerp requires all the arguments to be numbers"); double t = PyFloat_AsDouble(value); - - if (t < 0) - t = 0.0; - else if (t > 1) - t = 1.0; - double a = PyFloat_AsDouble(min); double b = PyFloat_AsDouble(max); @@ -4276,7 +4270,7 @@ math_invlerp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) "might be too small or too big"); if (b - a == 0) - return RAISE(PyExc_ZeroDivisionError, + return RAISE(PyExc_ValueError, "the result of b - a needs to be different from zero"); return PyFloat_FromDouble(invlerp(a, b, t)); @@ -4314,7 +4308,7 @@ math_remap(PyObject *self, PyObject *const *args, Py_ssize_t nargs) if (b - a == 0) return RAISE( - PyExc_ZeroDivisionError, + PyExc_ValueError, "the result of i_max - i_min needs to be different from zero"); return PyFloat_FromDouble(lerp(c, d, invlerp(a, b, v))); From a542c8f625709a08154efeeeeb6cf6ea04cde884 Mon Sep 17 00:00:00 2001 From: bilhox Date: Sun, 11 Feb 2024 13:48:40 +0100 Subject: [PATCH 21/31] update test --- test/math_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/math_test.py b/test/math_test.py index 62f7dfddac..4ce8690f6d 100644 --- a/test/math_test.py +++ b/test/math_test.py @@ -117,7 +117,7 @@ def test_invlerp(self): b = 2 pygame.math.invlerp(a, b, Vector2(0, 0)) - with self.assertRaises(ZeroDivisionError): + with self.assertRaises(ValueError): a = 5 b = 5 pygame.math.invlerp(a, b, 5) @@ -166,7 +166,7 @@ def test_remap(self): d = 20 pygame.math.remap(a, b, c, d, Vector2(0, 0)) - with self.assertRaises(ZeroDivisionError): + with self.assertRaises(ValueError): a = 5 b = 5 c = 0 From 5bcdf3548242a9f583f18778bedd561d9056698a Mon Sep 17 00:00:00 2001 From: bilhox Date: Sat, 25 May 2024 23:08:07 +0200 Subject: [PATCH 22/31] temp changes --- src_c/math.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src_c/math.c b/src_c/math.c index 0ddeead800..b4bf56b58b 100644 --- a/src_c/math.c +++ b/src_c/math.c @@ -4245,6 +4245,8 @@ math_clamp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) return value; } +#define RAISE_ARG_TYPE_ERROR(py_num_obj, var) (!PyNumber_Check(py_num_obj))?RAISE(PyExc_TypeError, "The argument '"var"' must be a real number"):{} + static PyObject * math_invlerp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { @@ -4253,12 +4255,15 @@ math_invlerp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) "invlerp requires exactly 3 numeric arguments"); PyObject *min = args[0]; + RAISE_ARG_TYPE_ERROR(min, "min") PyObject *max = args[1]; + RAISE_ARG_TYPE_ERROR(max, "max") PyObject *value = args[2]; + RAISE_ARG_TYPE_ERROR(value, "value") - if (!PyNumber_Check(min) || !PyNumber_Check(max) || !PyNumber_Check(value)) - return RAISE(PyExc_TypeError, - "invlerp requires all the arguments to be numbers"); + // if (!PyNumber_Check(min) || !PyNumber_Check(max) || !PyNumber_Check(value)) + // return RAISE(PyExc_TypeError, + // "invlerp requires all the arguments to be numbers"); double t = PyFloat_AsDouble(value); double a = PyFloat_AsDouble(min); @@ -4276,6 +4281,8 @@ math_invlerp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) return PyFloat_FromDouble(invlerp(a, b, t)); } +# + static PyObject * math_remap(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { From cbf66efd29fde69e510e414a73080990f2137aaf Mon Sep 17 00:00:00 2001 From: bilhox Date: Sun, 26 May 2024 14:51:15 +0200 Subject: [PATCH 23/31] separate arg error part 1 --- src_c/math.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src_c/math.c b/src_c/math.c index 1120506888..4a6395b5ca 100644 --- a/src_c/math.c +++ b/src_c/math.c @@ -4245,7 +4245,7 @@ math_clamp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) return value; } -#define RAISE_ARG_TYPE_ERROR(py_num_obj, var) (!PyNumber_Check(py_num_obj))?RAISE(PyExc_TypeError, "The argument '"var"' must be a real number"):{} +#define RAISE_ARG_TYPE_ERROR(var) RAISE(PyExc_TypeError, "The argument '"var"' must be a real number") static PyObject * math_invlerp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) @@ -4255,11 +4255,11 @@ math_invlerp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) "invlerp requires exactly 3 numeric arguments"); PyObject *min = args[0]; - RAISE_ARG_TYPE_ERROR(min, "min") + if (!PyNumber_Check(min)) {return RAISE_ARG_TYPE_ERROR("min");} PyObject *max = args[1]; - RAISE_ARG_TYPE_ERROR(max, "max") + if (!PyNumber_Check(max)) {return RAISE_ARG_TYPE_ERROR("max");} PyObject *value = args[2]; - RAISE_ARG_TYPE_ERROR(value, "value") + if (!PyNumber_Check(value)) {return RAISE_ARG_TYPE_ERROR("value");} // if (!PyNumber_Check(min) || !PyNumber_Check(max) || !PyNumber_Check(value)) // return RAISE(PyExc_TypeError, @@ -4291,16 +4291,21 @@ math_remap(PyObject *self, PyObject *const *args, Py_ssize_t nargs) "remap requires exactly 5 numeric arguments"); PyObject *i_min = args[0]; + if (!PyNumber_Check(i_min)) {return RAISE_ARG_TYPE_ERROR("i_min");} PyObject *i_max = args[1]; + if (!PyNumber_Check(i_max)) {return RAISE_ARG_TYPE_ERROR("i_max");} PyObject *o_min = args[2]; + if (!PyNumber_Check(o_min)) {return RAISE_ARG_TYPE_ERROR("o_min");} PyObject *o_max = args[3]; + if (!PyNumber_Check(o_max)) {return RAISE_ARG_TYPE_ERROR("o_max");} PyObject *value = args[4]; + if (!PyNumber_Check(value)) {return RAISE_ARG_TYPE_ERROR("value");} - if (!PyNumber_Check(value) || !PyNumber_Check(i_min) || - !PyNumber_Check(i_max) || !PyNumber_Check(o_min) || - !PyNumber_Check(o_max)) - return RAISE(PyExc_TypeError, - "remap requires all the arguments to be numbers"); + // if (!PyNumber_Check(value) || !PyNumber_Check(i_min) || + // !PyNumber_Check(i_max) || !PyNumber_Check(o_min) || + // !PyNumber_Check(o_max)) + // return RAISE(PyExc_TypeError, + // "remap requires all the arguments to be numbers"); double v = PyFloat_AsDouble(value); double a = PyFloat_AsDouble(i_min); From bbcdeefd1a750d03daf66a3b2b86ab62b0a30f8a Mon Sep 17 00:00:00 2001 From: Dan Lawrence Date: Thu, 30 May 2024 17:08:42 +0100 Subject: [PATCH 24/31] fix numcheck macro --- src_c/math.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src_c/math.c b/src_c/math.c index 1120506888..a2229aa3a0 100644 --- a/src_c/math.c +++ b/src_c/math.c @@ -4245,7 +4245,11 @@ math_clamp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) return value; } -#define RAISE_ARG_TYPE_ERROR(py_num_obj, var) (!PyNumber_Check(py_num_obj))?RAISE(PyExc_TypeError, "The argument '"var"' must be a real number"):{} +#define RAISE_ARG_TYPE_ERROR(py_num_obj, var) \ + if (!PyNumber_Check(py_num_obj)) { \ + return RAISE(PyExc_TypeError, \ + "The argument '" var "' must be a real number"); \ + } static PyObject * math_invlerp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) @@ -4261,7 +4265,8 @@ math_invlerp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) PyObject *value = args[2]; RAISE_ARG_TYPE_ERROR(value, "value") - // if (!PyNumber_Check(min) || !PyNumber_Check(max) || !PyNumber_Check(value)) + // if (!PyNumber_Check(min) || !PyNumber_Check(max) || + // !PyNumber_Check(value)) // return RAISE(PyExc_TypeError, // "invlerp requires all the arguments to be numbers"); From 64461ed5e01b6cb1ecfa1ac4169676c5a6c18a35 Mon Sep 17 00:00:00 2001 From: Dan Lawrence Date: Thu, 30 May 2024 19:44:56 +0100 Subject: [PATCH 25/31] Apply suggestions from code review Co-authored-by: Ankith --- src_c/math.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/src_c/math.c b/src_c/math.c index a2229aa3a0..512c5c7c4e 100644 --- a/src_c/math.c +++ b/src_c/math.c @@ -4245,8 +4245,8 @@ math_clamp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) return value; } -#define RAISE_ARG_TYPE_ERROR(py_num_obj, var) \ - if (!PyNumber_Check(py_num_obj)) { \ +#define RAISE_ARG_TYPE_ERROR(var) \ + if (PyErr_Occurred()) { \ return RAISE(PyExc_TypeError, \ "The argument '" var "' must be a real number"); \ } @@ -4258,21 +4258,12 @@ math_invlerp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) return RAISE(PyExc_TypeError, "invlerp requires exactly 3 numeric arguments"); - PyObject *min = args[0]; - RAISE_ARG_TYPE_ERROR(min, "min") - PyObject *max = args[1]; - RAISE_ARG_TYPE_ERROR(max, "max") - PyObject *value = args[2]; - RAISE_ARG_TYPE_ERROR(value, "value") - - // if (!PyNumber_Check(min) || !PyNumber_Check(max) || - // !PyNumber_Check(value)) - // return RAISE(PyExc_TypeError, - // "invlerp requires all the arguments to be numbers"); - - double t = PyFloat_AsDouble(value); - double a = PyFloat_AsDouble(min); - double b = PyFloat_AsDouble(max); + double a = PyFloat_AsDouble(args[0]); + RAISE_ARG_TYPE_ERROR("min") + double b = PyFloat_AsDouble(args[1]) + RAISE_ARG_TYPE_ERROR("max") + double t = PyFloat_AsDouble(args[2]); + RAISE_ARG_TYPE_ERROR("value") if (PyErr_Occurred()) return RAISE(PyExc_ValueError, From a87b274f706a03cef3a47772874a4afc30167f39 Mon Sep 17 00:00:00 2001 From: Dan Lawrence Date: Thu, 30 May 2024 19:47:21 +0100 Subject: [PATCH 26/31] formatting --- src_c/math.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src_c/math.c b/src_c/math.c index 512c5c7c4e..c72ee6368f 100644 --- a/src_c/math.c +++ b/src_c/math.c @@ -4260,9 +4260,8 @@ math_invlerp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) double a = PyFloat_AsDouble(args[0]); RAISE_ARG_TYPE_ERROR("min") - double b = PyFloat_AsDouble(args[1]) - RAISE_ARG_TYPE_ERROR("max") - double t = PyFloat_AsDouble(args[2]); + double b = PyFloat_AsDouble(args[1]) RAISE_ARG_TYPE_ERROR("max") double t = + PyFloat_AsDouble(args[2]); RAISE_ARG_TYPE_ERROR("value") if (PyErr_Occurred()) From a27e44d77ef3f706832e996c3c5973f16e2b676d Mon Sep 17 00:00:00 2001 From: Dan Lawrence Date: Thu, 30 May 2024 20:19:34 +0100 Subject: [PATCH 27/31] fix missing semi-colon and test assert type --- src_c/math.c | 5 +++-- test/math_test.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src_c/math.c b/src_c/math.c index c72ee6368f..f08e82ff29 100644 --- a/src_c/math.c +++ b/src_c/math.c @@ -4260,8 +4260,9 @@ math_invlerp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) double a = PyFloat_AsDouble(args[0]); RAISE_ARG_TYPE_ERROR("min") - double b = PyFloat_AsDouble(args[1]) RAISE_ARG_TYPE_ERROR("max") double t = - PyFloat_AsDouble(args[2]); + double b = PyFloat_AsDouble(args[1]); + RAISE_ARG_TYPE_ERROR("max") + double t = PyFloat_AsDouble(args[2]); RAISE_ARG_TYPE_ERROR("value") if (PyErr_Occurred()) diff --git a/test/math_test.py b/test/math_test.py index 4ce8690f6d..208172ef02 100644 --- a/test/math_test.py +++ b/test/math_test.py @@ -122,7 +122,7 @@ def test_invlerp(self): b = 5 pygame.math.invlerp(a, b, 5) - with self.assertRaises(ValueError): + with self.assertRaises(TypeError): a = 12**300 b = 11**30 pygame.math.invlerp(a, b, 1) From fce1693e08fe3e5c7a222962228a3373a6297ea0 Mon Sep 17 00:00:00 2001 From: bilhox Date: Sat, 1 Jun 2024 20:41:50 +0200 Subject: [PATCH 28/31] small fix --- src_c/math.c | 26 +++++++++++--------------- test/math_test.py | 2 +- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/src_c/math.c b/src_c/math.c index 4a6395b5ca..7af0bdd7b6 100644 --- a/src_c/math.c +++ b/src_c/math.c @@ -4245,7 +4245,11 @@ math_clamp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) return value; } -#define RAISE_ARG_TYPE_ERROR(var) RAISE(PyExc_TypeError, "The argument '"var"' must be a real number") +#define RAISE_ARG_TYPE_ERROR(var) \ + if (PyErr_Occurred()) { \ + return RAISE(PyExc_TypeError, \ + "The argument '" var "' must be a real number"); \ + } static PyObject * math_invlerp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) @@ -4254,20 +4258,12 @@ math_invlerp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) return RAISE(PyExc_TypeError, "invlerp requires exactly 3 numeric arguments"); - PyObject *min = args[0]; - if (!PyNumber_Check(min)) {return RAISE_ARG_TYPE_ERROR("min");} - PyObject *max = args[1]; - if (!PyNumber_Check(max)) {return RAISE_ARG_TYPE_ERROR("max");} - PyObject *value = args[2]; - if (!PyNumber_Check(value)) {return RAISE_ARG_TYPE_ERROR("value");} - - // if (!PyNumber_Check(min) || !PyNumber_Check(max) || !PyNumber_Check(value)) - // return RAISE(PyExc_TypeError, - // "invlerp requires all the arguments to be numbers"); - - double t = PyFloat_AsDouble(value); - double a = PyFloat_AsDouble(min); - double b = PyFloat_AsDouble(max); + double a = PyFloat_AsDouble(args[0]); + RAISE_ARG_TYPE_ERROR("min") + double b = PyFloat_AsDouble(args[1]); + RAISE_ARG_TYPE_ERROR("max") + double t = PyFloat_AsDouble(args[2]); + RAISE_ARG_TYPE_ERROR("value") if (PyErr_Occurred()) return RAISE(PyExc_ValueError, diff --git a/test/math_test.py b/test/math_test.py index 4ce8690f6d..208172ef02 100644 --- a/test/math_test.py +++ b/test/math_test.py @@ -122,7 +122,7 @@ def test_invlerp(self): b = 5 pygame.math.invlerp(a, b, 5) - with self.assertRaises(ValueError): + with self.assertRaises(TypeError): a = 12**300 b = 11**30 pygame.math.invlerp(a, b, 1) From 85e64e34efd2a4082db60cf532cea583c885a552 Mon Sep 17 00:00:00 2001 From: bilhox Date: Sat, 1 Jun 2024 21:08:42 +0200 Subject: [PATCH 29/31] last fixes --- docs/reST/ref/math.rst | 17 +++++++++++++++-- src_c/math.c | 16 +++++----------- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/docs/reST/ref/math.rst b/docs/reST/ref/math.rst index 31049d3e73..93cb998bbc 100644 --- a/docs/reST/ref/math.rst +++ b/docs/reST/ref/math.rst @@ -85,14 +85,27 @@ Multiple coordinates can be set using slices or swizzling | :sg:`invlerp(a, b, value, /) -> float` Returns a number which is an inverse interpolation between ``a`` - and ``b``. The third parameter determines how far between ``a`` and - ``b`` the result is going to be. + and ``b``. The third parameter ``value`` is the result of the linear interpolation + between a and b with a certain coefficient. In other words, this coefficient + will be the result of this function. If ``b - a`` is equal to 0, it raises a ``ZeroDivisionError``. The formula is: ``(v - a)/(b - a)``. + This is an example explaining what is above : + + .. code-block:: python + + > a = 10 + > b = 20 + > pygame.math.invlerp(10, 20, 11.5) + > 0.15 + > pygame.math.lerp(10, 20, 0.15) + > 11.5 + + .. versionadded:: 2.5.0 .. ## math.invlerp ## diff --git a/src_c/math.c b/src_c/math.c index 7af0bdd7b6..967f2bba1d 100644 --- a/src_c/math.c +++ b/src_c/math.c @@ -4287,27 +4287,21 @@ math_remap(PyObject *self, PyObject *const *args, Py_ssize_t nargs) "remap requires exactly 5 numeric arguments"); PyObject *i_min = args[0]; - if (!PyNumber_Check(i_min)) {return RAISE_ARG_TYPE_ERROR("i_min");} PyObject *i_max = args[1]; - if (!PyNumber_Check(i_max)) {return RAISE_ARG_TYPE_ERROR("i_max");} PyObject *o_min = args[2]; - if (!PyNumber_Check(o_min)) {return RAISE_ARG_TYPE_ERROR("o_min");} PyObject *o_max = args[3]; - if (!PyNumber_Check(o_max)) {return RAISE_ARG_TYPE_ERROR("o_max");} PyObject *value = args[4]; - if (!PyNumber_Check(value)) {return RAISE_ARG_TYPE_ERROR("value");} - - // if (!PyNumber_Check(value) || !PyNumber_Check(i_min) || - // !PyNumber_Check(i_max) || !PyNumber_Check(o_min) || - // !PyNumber_Check(o_max)) - // return RAISE(PyExc_TypeError, - // "remap requires all the arguments to be numbers"); double v = PyFloat_AsDouble(value); + RAISE_ARG_TYPE_ERROR("value") double a = PyFloat_AsDouble(i_min); + RAISE_ARG_TYPE_ERROR("i_min") double b = PyFloat_AsDouble(i_max); + RAISE_ARG_TYPE_ERROR("i_max") double c = PyFloat_AsDouble(o_min); + RAISE_ARG_TYPE_ERROR("o_min") double d = PyFloat_AsDouble(o_max); + RAISE_ARG_TYPE_ERROR("o_max") if (PyErr_Occurred()) return RAISE(PyExc_ValueError, From 964fdbdcca5ec7b91a160428ccab485b769351f4 Mon Sep 17 00:00:00 2001 From: bilhox Date: Sat, 1 Jun 2024 21:15:54 +0200 Subject: [PATCH 30/31] test fix + removed useless code --- src_c/math.c | 5 ----- test/math_test.py | 4 ++-- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src_c/math.c b/src_c/math.c index 967f2bba1d..de763789ac 100644 --- a/src_c/math.c +++ b/src_c/math.c @@ -4303,11 +4303,6 @@ math_remap(PyObject *self, PyObject *const *args, Py_ssize_t nargs) double d = PyFloat_AsDouble(o_max); RAISE_ARG_TYPE_ERROR("o_max") - if (PyErr_Occurred()) - return RAISE(PyExc_ValueError, - "invalid argument values passed to remap, numbers might " - "be too small or too big"); - if (b - a == 0) return RAISE( PyExc_ValueError, diff --git a/test/math_test.py b/test/math_test.py index 208172ef02..bcc2c73830 100644 --- a/test/math_test.py +++ b/test/math_test.py @@ -173,14 +173,14 @@ def test_remap(self): d = 100 pygame.math.remap(a, b, c, d, 10) - with self.assertRaises(ValueError): + with self.assertRaises(TypeError): a = 12**300 b = 11**30 c = 20 d = 30 pygame.math.remap(a, b, c, d, 100 * 50) - with self.assertRaises(ValueError): + with self.assertRaises(TypeError): a = 12j b = 11j c = 10j From 9d483eaa0a5efa2f1e38bc5e92e489e9b865dc3b Mon Sep 17 00:00:00 2001 From: Dan Lawrence Date: Sun, 2 Jun 2024 08:36:12 +0100 Subject: [PATCH 31/31] match errors to var names in signature (docs and type hints) --- src_c/math.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src_c/math.c b/src_c/math.c index de763789ac..8ed8ccae5e 100644 --- a/src_c/math.c +++ b/src_c/math.c @@ -4259,9 +4259,9 @@ math_invlerp(PyObject *self, PyObject *const *args, Py_ssize_t nargs) "invlerp requires exactly 3 numeric arguments"); double a = PyFloat_AsDouble(args[0]); - RAISE_ARG_TYPE_ERROR("min") + RAISE_ARG_TYPE_ERROR("a") double b = PyFloat_AsDouble(args[1]); - RAISE_ARG_TYPE_ERROR("max") + RAISE_ARG_TYPE_ERROR("b") double t = PyFloat_AsDouble(args[2]); RAISE_ARG_TYPE_ERROR("value")