Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion buildconfig/stubs/pygame/math.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,11 @@ class _GenericVector(Collection[float]):
self: _TVec, other: Union[SequenceLike[float], _TVec], /
) -> float: ...
def lerp(
self: _TVec, other: Union[SequenceLike[float], _TVec], value: float, /
self: _TVec,
other: Union[SequenceLike[float], _TVec],
value: float,
do_clamp: bool = True,
/,
) -> _TVec: ...
def slerp(
self: _TVec, other: Union[SequenceLike[float], _TVec], value: float, /
Expand Down
26 changes: 20 additions & 6 deletions docs/reST/ref/math.rst
Original file line number Diff line number Diff line change
Expand Up @@ -385,12 +385,19 @@ Conversion can be combined with swizzling or slicing to create a new order
.. method:: lerp

| :sl:`returns a linear interpolation to the given vector.`
| :sg:`lerp(Vector2, float, /) -> Vector2`
| :sg:`lerp(Vector2, float, do_clamp=True, /) -> Vector2`

Returns a Vector which is a linear interpolation between self and the
given Vector. The second parameter determines how far between self and
other the result is going to be. It must be a value between ``0`` and ``1``
where ``0`` means self and ``1`` means other will be returned.
when ``do_clamp`` is ``True`` where ``0`` means self and ``1`` means other
will be returned. When ``do_clamp`` is ``False``, the lerp will extend out
linearly when the second parameter is outside of the nominal range.
Comment on lines 391 to +395
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Align lerp docs with clamping behavior.

These paragraphs still claim the factor “must be” in [0, 1], which contradicts the actual behavior (the value is clamped when do_clamp is True and allowed to extrapolate when False). Update the prose to describe the clamping instead.

-      other the result is going to be. It must be a value between ``0`` and ``1``
-      when ``do_clamp`` is ``True`` where ``0`` means self and ``1`` means other
-      will be returned. When ``do_clamp`` is ``False``, the lerp will extend out
-      linearly when the second parameter is outside of the nominal range.
+      other the result is going to be. When ``do_clamp`` is ``True``, the second
+      parameter is clamped to the closed interval ``[0, 1]`` so that ``0``
+      returns self and ``1`` returns other. When ``do_clamp`` is ``False``, the
+      lerp will extrapolate linearly when the second parameter is outside of that
+      nominal range.

Also applies to: 887-891


.. versionchanged:: 2.5.7 The ``do_clamp`` parameter is added with a default
value of ``True``. When it's ``True``, the second parameter is limited
to the closed interval ``[0, 1]``. When it's ``False``, the second parameter
is not limited and the lerp will extend beyond the original two vectors.

.. ## Vector2.lerp ##

Expand Down Expand Up @@ -874,12 +881,19 @@ Conversion can be combined with swizzling or slicing to create a new order
.. method:: lerp

| :sl:`returns a linear interpolation to the given vector.`
| :sg:`lerp(Vector3, float, /) -> Vector3`
| :sg:`lerp(Vector3, float, do_clamp=True, /) -> Vector3`

Returns a Vector which is a linear interpolation between self and the
given Vector. The second parameter determines how far between self an
other the result is going to be. It must be a value between ``0`` and
``1``, where ``0`` means self and ``1`` means other will be returned.
given Vector. The second parameter determines how far between self and
other the result is going to be. It must be a value between ``0`` and ``1``
when ``do_clamp`` is ``True`` where ``0`` means self and ``1`` means other
will be returned. When ``do_clamp`` is ``False``, the lerp will extend out
linearly when the second parameter is outside of the nominal range.

.. versionchanged:: 2.5.7 The ``do_clamp`` parameter is added with a default
value of ``True``. When it's ``True``, the second parameter is limited
to the closed interval ``[0, 1]``. When it's ``False``, the second parameter
is not limited and the lerp will extend beyond the original two vectors.

.. ## Vector3.lerp ##

Expand Down
4 changes: 2 additions & 2 deletions src_c/doc/math_doc.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#define DOC_MATH_VECTOR2_DISTANCESQUAREDTO "distance_squared_to(Vector2, /) -> float\ncalculates the squared Euclidean distance to a given vector."
#define DOC_MATH_VECTOR2_MOVETOWARDS "move_towards(Vector2, float, /) -> Vector2\nreturns a vector moved toward the target by a given distance."
#define DOC_MATH_VECTOR2_MOVETOWARDSIP "move_towards_ip(Vector2, float, /) -> None\nmoves the vector toward its target at a given distance."
#define DOC_MATH_VECTOR2_LERP "lerp(Vector2, float, /) -> Vector2\nreturns a linear interpolation to the given vector."
#define DOC_MATH_VECTOR2_LERP "lerp(Vector2, float, do_clamp=True, /) -> Vector2\nreturns a linear interpolation to the given vector."
#define DOC_MATH_VECTOR2_SLERP "slerp(Vector2, float, /) -> Vector2\nreturns a spherical interpolation to the given vector."
#define DOC_MATH_VECTOR2_SMOOTHSTEP "smoothstep(Vector2, float, /) -> Vector2\nreturns a smooth interpolation to the given vector."
#define DOC_MATH_VECTOR2_ELEMENTWISE "elementwise() -> VectorElementwiseProxy\nThe next operation will be performed elementwise."
Expand Down Expand Up @@ -59,7 +59,7 @@
#define DOC_MATH_VECTOR3_DISTANCESQUAREDTO "distance_squared_to(Vector3, /) -> float\ncalculates the squared Euclidean distance to a given vector."
#define DOC_MATH_VECTOR3_MOVETOWARDS "move_towards(Vector3, float, /) -> Vector3\nreturns a vector moved toward the target by a given distance."
#define DOC_MATH_VECTOR3_MOVETOWARDSIP "move_towards_ip(Vector3, float, /) -> None\nmoves the vector toward its target at a given distance."
#define DOC_MATH_VECTOR3_LERP "lerp(Vector3, float, /) -> Vector3\nreturns a linear interpolation to the given vector."
#define DOC_MATH_VECTOR3_LERP "lerp(Vector3, float, do_clamp=True, /) -> Vector3\nreturns a linear interpolation to the given vector."
#define DOC_MATH_VECTOR3_SLERP "slerp(Vector3, float, /) -> Vector3\nreturns a spherical interpolation to the given vector."
#define DOC_MATH_VECTOR3_SMOOTHSTEP "smoothstep(Vector3, float, /) -> Vector3\nreturns a smooth interpolation to the given vector."
#define DOC_MATH_VECTOR3_ELEMENTWISE "elementwise() -> VectorElementwiseProxy\nThe next operation will be performed elementwise."
Expand Down
9 changes: 6 additions & 3 deletions src_c/math.c
Original file line number Diff line number Diff line change
Expand Up @@ -1708,16 +1708,19 @@ vector_lerp(pgVector *self, PyObject *args)
pgVector *ret;
double t;
double other_coords[VECTOR_MAX_SIZE];
int do_clamp = 1;

if (!PyArg_ParseTuple(args, "Od:Vector.lerp", &other, &t)) {
if (!PyArg_ParseTuple(args, "Od|p:Vector.lerp", &other, &t, &do_clamp)) {
return NULL;
}
if (!pg_VectorCoordsFromObjOldDontUseInNewCode(other, other_coords,
self->dim)) {
return RAISE(PyExc_TypeError, "Expected Vector as argument 1");
}
if (t < 0 || t > 1) {
return RAISE(PyExc_ValueError, "Argument 2 must be in range [0, 1]");
if ((t < 0 || t > 1) && do_clamp > 0) {
return RAISE(PyExc_ValueError,
"Argument 2 must be in range [0, 1] when do_clamp is set "
"to True (the default value)");
}

ret = _vector_subtype_new(self);
Expand Down
8 changes: 8 additions & 0 deletions test/math_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1139,14 +1139,18 @@ def test_lerp(self):
v2 = Vector2(10, 10)
self.assertEqual(v1.lerp(v2, 0.5), (5, 5))
self.assertRaises(ValueError, lambda: v1.lerp(v2, 2.5))
self.assertEqual(v1.lerp(v2, 2.5, False), (25, 25))
self.assertEqual(v1.lerp(v2, -1, False), (-10, -10))

v1 = Vector2(0, 0)
v2 = Vector2(10, 10)
self.assertEqual(v1.lerp(v2, 0.1), (1, 1))
self.assertEqual(v1.lerp(v2, 10, False), (100, 100))

v1 = Vector2(-10, -5)
v2 = Vector2(10, 10)
self.assertEqual(v1.lerp(v2, 0.5), (0, 2.5))
self.assertEqual(v1.lerp(v2, -10, False), (-210, -155))

def test_smoothstep(self):
v1 = Vector2(0, 0)
Expand Down Expand Up @@ -2892,14 +2896,18 @@ def test_lerp(self):
v2 = Vector3(10, 10, 10)
self.assertEqual(v1.lerp(v2, 0.5), (5, 5, 5))
self.assertRaises(ValueError, lambda: v1.lerp(v2, 2.5))
self.assertEqual(v1.lerp(v2, 2.5, False), (25, 25, 25))
self.assertEqual(v1.lerp(v2, -1, False), (-10, -10, -10))

v1 = Vector3(0, 0, 0)
v2 = Vector3(10, 10, 10)
self.assertEqual(v1.lerp(v2, 0.1), (1, 1, 1))
self.assertEqual(v1.lerp(v2, 10, False), (100, 100, 100))

v1 = Vector3(-10, -5, -20)
v2 = Vector3(10, 10, -20)
self.assertEqual(v1.lerp(v2, 0.5), (0, 2.5, -20))
self.assertEqual(v1.lerp(v2, -10, False), (-210, -155, -20))

def test_smoothstep(self):
v1 = Vector3(0, 0, 0)
Expand Down
Loading