Skip to content

Add Circle update() #2562

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 11, 2023
Merged
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: 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()