Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
4 changes: 4 additions & 0 deletions buildconfig/stubs/pygame/geometry.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -75,5 +75,9 @@ 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: ...
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()