Skip to content

Commit

Permalink
Merge pull request pygame-community#2913 from damusss/circle-zero-radius
Browse files Browse the repository at this point in the history
Allow degenerate circles (radius = 0)
  • Loading branch information
ankith26 authored Jun 26, 2024
2 parents 126c261 + 8940665 commit 717c861
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 21 deletions.
8 changes: 3 additions & 5 deletions docs/reST/ref/geometry.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,6 @@
((x, y), radius)
(x, y, radius)

It is important to note that you cannot create degenerate circles, which are circles with
a radius of 0 or less. If you try to create such a circle, the `Circle` object will not be
created and an error will be raised. This is because a circle with a radius of 0 or
less is not a valid geometric object.

The `Circle` class has both virtual and non-virtual attributes. Non-virtual attributes
are attributes that are stored in the `Circle` object itself. Virtual attributes are the
result of calculations that utilize the Circle's non-virtual attributes.
Expand Down Expand Up @@ -91,6 +86,9 @@

.. versionadded:: 2.4.0

.. versionchanged:: 2.5.1 It is allowed to create degenerate circles with radius
equal to ``0``. This also applies to virtual attributes.

.. ## Circle.r ##
.. attribute:: r_sqr
Expand Down
24 changes: 13 additions & 11 deletions src_c/circle.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ pg_circle_init(pgCircleObject *self, PyObject *args, PyObject *kwds)
PyErr_SetString(
PyExc_TypeError,
"Arguments must be a Circle, a sequence of length 3 or 2, or an "
"object with an attribute called 'circle'");
"object with an attribute called 'circle', all with corresponding "
"nonnegative radius argument");
return -1;
}
return 0;
Expand Down Expand Up @@ -494,8 +495,8 @@ pg_circle_setr(pgCircleObject *self, PyObject *value, void *closure)
return -1;
}

if (radius <= 0) {
PyErr_SetString(PyExc_ValueError, "Radius must be positive");
if (radius < 0) {
PyErr_SetString(PyExc_ValueError, "Radius must be nonnegative");
return -1;
}

Expand Down Expand Up @@ -523,9 +524,9 @@ pg_circle_setr_sqr(pgCircleObject *self, PyObject *value, void *closure)
return -1;
}

if (radius_squared <= 0) {
if (radius_squared < 0) {
PyErr_SetString(PyExc_ValueError,
"Invalid radius squared value, must be > 0");
"Invalid radius squared value, must be nonnegative");
return -1;
}

Expand Down Expand Up @@ -570,8 +571,9 @@ pg_circle_setarea(pgCircleObject *self, PyObject *value, void *closure)
return -1;
}

if (area <= 0) {
PyErr_SetString(PyExc_ValueError, "Invalid area value, must be > 0");
if (area < 0) {
PyErr_SetString(PyExc_ValueError,
"Invalid area value, must be nonnegative");
return -1;
}

Expand Down Expand Up @@ -600,9 +602,9 @@ pg_circle_setcircumference(pgCircleObject *self, PyObject *value,
return -1;
}

if (circumference <= 0) {
if (circumference < 0) {
PyErr_SetString(PyExc_ValueError,
"Invalid circumference value, must be > 0");
"Invalid circumference value, must be nonnegative");
return -1;
}

Expand Down Expand Up @@ -630,9 +632,9 @@ pg_circle_setdiameter(pgCircleObject *self, PyObject *value, void *closure)
return -1;
}

if (diameter <= 0) {
if (diameter < 0) {
PyErr_SetString(PyExc_ValueError,
"Invalid diameter value, must be > 0");
"Invalid diameter value, must be nonnegative");
return -1;
}

Expand Down
2 changes: 1 addition & 1 deletion src_c/geometry_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ int
_pg_circle_set_radius(PyObject *value, pgCircleBase *circle)
{
double radius = 0.0;
if (!pg_DoubleFromObj(value, &radius) || radius <= 0.0) {
if (!pg_DoubleFromObj(value, &radius) || radius < 0.0) {
return 0;
}
circle->r = radius;
Expand Down
15 changes: 11 additions & 4 deletions test/geometry_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@ def testConstructionTUP_XYR_int(self):
self.assertEqual(2.0, c.y)
self.assertEqual(3.0, c.r)

def testConstruction_zero_radius(self):
c = Circle(1, 2, 0)

self.assertEqual(1.0, c.x)
self.assertEqual(2.0, c.y)
self.assertEqual(0, c.r)

def test_x(self):
"""Ensures changing the x attribute moves the circle and does not change
the circle's radius.
Expand Down Expand Up @@ -183,7 +190,7 @@ def test_r__invalid_value(self):
with self.assertRaises(TypeError):
c.radius = value

for value in (-10.3234, -1, 0, 0.0):
for value in (-10.3234, -1):
with self.assertRaises(ValueError):
c.r = value
with self.assertRaises(ValueError):
Expand Down Expand Up @@ -317,7 +324,7 @@ def test_area_invalid_value(self):
with self.assertRaises(TypeError):
c.area = value

for value in (-10.3234, -1, 0, 0.0):
for value in (-10.3234, -1):
with self.assertRaises(ValueError):
c.area = value

Expand Down Expand Up @@ -352,7 +359,7 @@ def test_circumference_invalid_value(self):
with self.assertRaises(TypeError):
c.circumference = value

for value in (-10.3234, -1, 0, 0.0):
for value in (-10.3234, -1):
with self.assertRaises(ValueError):
c.circumference = value

Expand Down Expand Up @@ -390,7 +397,7 @@ def test_diameter_invalid_value(self):
with self.assertRaises(TypeError):
c.diameter = value

for value in (-10.3234, -1, 0, 0.0):
for value in (-10.3234, -1):
with self.assertRaises(ValueError):
c.diameter = value
with self.assertRaises(ValueError):
Expand Down

0 comments on commit 717c861

Please sign in to comment.