Skip to content

Commit

Permalink
Merge pull request #2562 from itzpr3d4t0r/circle-update
Browse files Browse the repository at this point in the history
Add Circle `update()`
  • Loading branch information
ankith26 authored Dec 11, 2023
2 parents 8a446a2 + 355a1d0 commit a42137e
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 0 deletions.
6 changes: 6 additions & 0 deletions buildconfig/stubs/pygame/geometry.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -75,5 +75,11 @@ class Circle:
def collidecircle(self, x: float, y: float, r: float) -> bool: ...
@overload
def collidecircle(self, center: Coordinate, r: float) -> bool: ...
@overload
def update(self, circle: _CircleValue) -> None: ...
@overload
def update(self, x: float, y: float, r: float) -> None: ...
@overload
def update(self, center: Coordinate, r: float) -> None: ...
def __copy__(self) -> Circle: ...
copy = __copy__
19 changes: 19 additions & 0 deletions docs/reST/ref/geometry.rst
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,25 @@

.. ## Circle.collidecircle ##
.. method:: update

| :sl:`updates the circle position and radius`
| :sg:`update((x, y), radius) -> None`
| :sg:`update(x, y, radius) -> None`
The `update` method allows you to set the position and radius of a `Circle` object in
place. This method takes either a tuple of (x, y) coordinates, two separate x and
y coordinates, and a radius as its arguments, and it always returns `None`.

.. note::
This method is equivalent(behaviour wise) to the following code:
::
circle.x = x
circle.y = y
circle.r = radius

.. ## Circle.update ##
.. method:: copy

| :sl:`returns a copy of the circle`
Expand Down
14 changes: 14 additions & 0 deletions src_c/circle.c
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,18 @@ pg_circle_str(pgCircleObject *self)
return pg_circle_repr(self);
}

static PyObject *
pg_circle_update(pgCircleObject *self, PyObject *const *args, Py_ssize_t nargs)
{
if (!pgCircle_FromObjectFastcall(args, nargs, &self->circle)) {
PyErr_SetString(
PyExc_TypeError,
"Circle.update requires a circle or CircleLike object");
return NULL;
}
Py_RETURN_NONE;
}

static PyObject *
pg_circle_collidepoint(pgCircleObject *self, PyObject *const *args,
Py_ssize_t nargs)
Expand Down Expand Up @@ -295,6 +307,8 @@ static struct PyMethodDef pg_circle_methods[] = {
DOC_CIRCLE_COLLIDEPOINT},
{"collidecircle", (PyCFunction)pg_circle_collidecircle, METH_FASTCALL,
DOC_CIRCLE_COLLIDECIRCLE},
{"update", (PyCFunction)pg_circle_update, METH_FASTCALL,
DOC_CIRCLE_UPDATE},
{"__copy__", (PyCFunction)pg_circle_copy, METH_NOARGS, DOC_CIRCLE_COPY},
{"copy", (PyCFunction)pg_circle_copy, METH_NOARGS, DOC_CIRCLE_COPY},
{NULL, NULL, 0, NULL}};
Expand Down
1 change: 1 addition & 0 deletions src_c/doc/geometry_doc.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@
#define DOC_CIRCLE_CIRCUMFERENCE "circumference -> float\ncircumference of the circle"
#define DOC_CIRCLE_COLLIDEPOINT "collidepoint((x, y)) -> bool\ncollidepoint(x, y) -> bool\ncollidepoint(Vector2) -> bool\ntest if a point is inside the circle"
#define DOC_CIRCLE_COLLIDECIRCLE "collidecircle(Circle) -> bool\ncollidecircle(x, y, radius) -> bool\ncollidecircle((x, y), radius) -> bool\ntest if two circles collide"
#define DOC_CIRCLE_UPDATE "update((x, y), radius) -> None\nupdate(x, y, radius) -> None\nupdates the circle position and radius"
#define DOC_CIRCLE_COPY "copy() -> Circle\nreturns a copy of the circle"
80 changes: 80 additions & 0 deletions test/geometry_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,86 @@ def test_collidecircle(self):
c5.collidecircle(c), "Expected False, circles should collide here"
)

def test_update(self):
"""Ensures that updating the circle position
and dimension correctly updates position and dimension"""
c = Circle(0, 0, 10)

c.update(5, 5, 3)

self.assertEqual(c.x, 5.0)
self.assertEqual(c.y, 5.0)
self.assertEqual(c.r, 3.0)
self.assertEqual(c.r_sqr, 9.0)

def test_update_argtype(self):
"""tests if the function correctly handles incorrect types as parameters"""
invalid_types = (None, [], "1", (1,), Vector2(1, 1), 1, 0.2324)

c = Circle(10, 10, 4)

for value in invalid_types:
with self.assertRaises(TypeError):
c.update(value)

def test_update_argnum(self):
c = Circle(10, 10, 4)

# no params
with self.assertRaises(TypeError):
c.update()

# too many params
with self.assertRaises(TypeError):
c.update(1, 1, 1, 1)

def test_update_twice(self):
"""Ensures that updating the circle position
and dimension correctly updates position and dimension"""
c = Circle(0, 0, 10)

c.update(5, 5, 3)
c.update(0, 0, 10)

self.assertEqual(c.x, 0.0)
self.assertEqual(c.y, 0.0)
self.assertEqual(c.r, 10)
self.assertEqual(c.r_sqr, 100)

def test_update_inplace(self):
"""Ensures that updating the circle to its position doesn't
move the circle to another position"""
c = Circle(0, 0, 10)
centerx = c.x
centery = c.y
c_r = c.r
c_r_sqr = c.r_sqr

c.update(0, 0, 10)

self.assertEqual(c.x, centerx)
self.assertEqual(c.y, centery)
self.assertEqual(c.r, c_r)
self.assertEqual(c.r_sqr, c_r_sqr)

c.update(c)

def test_selfupdate(self):
"""Ensures that updating the circle to its position doesn't
move the circle to another position"""
c = Circle(0, 0, 10)
centerx = c.x
centery = c.y
c_r = c.r
c_r_sqr = c.r_sqr

c.update(c)

self.assertEqual(c.x, centerx)
self.assertEqual(c.y, centery)
self.assertEqual(c.r, c_r)
self.assertEqual(c.r_sqr, c_r_sqr)


if __name__ == "__main__":
unittest.main()

0 comments on commit a42137e

Please sign in to comment.