Skip to content
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

geometry module, Circle base #2268

Merged
merged 14 commits into from
Oct 8, 2023
1 change: 1 addition & 0 deletions buildconfig/Setup.Android.SDL2.in
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,4 @@ math src_c/math.c $(SDL) $(DEBUG)
pixelcopy src_c/pixelcopy.c $(SDL) $(DEBUG)
newbuffer src_c/newbuffer.c $(SDL) $(DEBUG)
_window src_c/window.c $(SDL) $(DEBUG)
geometry src_c/geometry.c $(SDL) $(DEBUG)
1 change: 1 addition & 0 deletions buildconfig/Setup.Emscripten.SDL2.in
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ rect src_c/void.c
rwobject src_c/void.c
system src_c/void.c
_window src_c/void.c
geometry src_c/void.c

#_sdl2.controller src_c/_sdl2/controller.c $(SDL) $(DEBUG) -Isrc_c
_sdl2.controller_old src_c/void.c
Expand Down
1 change: 1 addition & 0 deletions buildconfig/Setup.SDL2.in
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,5 @@ math src_c/math.c $(SDL) $(DEBUG)
pixelcopy src_c/pixelcopy.c $(SDL) $(DEBUG)
newbuffer src_c/newbuffer.c $(SDL) $(DEBUG)
system src_c/system.c $(SDL) $(DEBUG)
geometry src_c/geometry.c $(SDL) $(DEBUG)
Starbuck5 marked this conversation as resolved.
Show resolved Hide resolved
_window src_c/window.c $(SDL) $(DEBUG)
2 changes: 2 additions & 0 deletions buildconfig/stubs/gen_stubs.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"sysfont",
"_debug",
"system",
"geometry",
]

# pygame classes that are autoimported into main namespace are kept in this dict
Expand All @@ -68,6 +69,7 @@
"mixer": ["Channel"],
"time": ["Clock"],
"joystick": ["Joystick"],
"geometry": ["Circle"],
}

# pygame modules from which __init__.py does the equivalent of
Expand Down
20 changes: 20 additions & 0 deletions buildconfig/stubs/pygame/geometry.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from typing import (
Sequence,
overload,
)

class Circle:
x: float
y: float
r: float

@overload
def __init__(self, x: float, y: float, r: float) -> None: ...
@overload
def __init__(self, pos: Sequence[float], r: float) -> None: ...
@overload
def __init__(self, circle: Circle) -> None: ...
@overload
def __init__(self, obj_with_circle_attr) -> None: ...
def __copy__(self) -> Circle: ...
copy = __copy__
1 change: 1 addition & 0 deletions docs/reST/ext/boilerplate.py
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ def lowercase_name(d):
"music",
"pygame",
"Rect",
"geometry",
"Surface",
"sprite",
"time",
Expand Down
103 changes: 103 additions & 0 deletions docs/reST/ref/geometry.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
.. include:: common.txt

:mod:`pygame.geometry`
======================
itzpr3d4t0r marked this conversation as resolved.
Show resolved Hide resolved

.. module:: pygame.geometry
:synopsis: pygame geometry module

.. warning::
**Experimental Module**

**This module is a work in progress. Refrain from relying on any features provided by
this module, as they are subject to change or removal without prior notice.**

| :sl:`pygame module for the Circle, Line, and Polygon objects`

.. currentmodule:: pygame

.. class:: Circle

| :sl:`pygame object for representing a circle`
| :sg:`Circle((x, y), radius) -> Circle`
| :sg:`Circle(x, y, radius) -> Circle`

The `Circle` class provides many useful methods for collision / transform and intersection.
A `Circle` can be created from a combination of a pair of coordinates that represent
the center of the circle and a radius. Circles can also be created from python objects that
are already a `Circle` or have an attribute named "circle".

Specifically, to construct a circle you can pass the x, y, and radius values as separate
arguments or inside a sequence(list or tuple).

Functions that require a `Circle` argument may also accept these values as Circles:

::

((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.

Here is the list of all the attributes and methods of the Circle class:

**Circle Attributes**

----
Comment on lines +51 to +53
Copy link
Member

Choose a reason for hiding this comment

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

This strategy is unconventional versus the rest of the docs, gave me a pause when looking at the generated copy.


.. attribute:: x

| :sl:`center x coordinate of the circle`
| :sg:`x -> float`

The `x` coordinate of the center of the circle. It can be reassigned to move the circle.
Reassigning the `x` attribute will move the circle to the new `x` coordinate.
The `y` and `r` attributes will not be affected.

.. ## Circle.x ##

.. attribute:: y

| :sl:`center y coordinate of the circle`
| :sg:`y -> float`

The `y` coordinate of the center of the circle. It can be reassigned to move the circle.
Reassigning the `y` attribute will move the circle to the new `y` coordinate.
The `x` and `r` attributes will not be affected.

.. ## Circle.y ##

.. attribute:: r

| :sl:`radius of the circle`
| :sg:`r -> float`

It is not possible to set the radius to a negative value. It can be reassigned.
If reassigned it will only change the radius of the circle.
The circle will not be moved from its original position.

.. ## Circle.r ##

**Circle Methods**

----

.. method:: copy

| :sl:`returns a copy of the circle`
| :sg:`copy() -> Circle`

The `copy` method returns a new `Circle` object having the same position and radius
as the original `Circle` object. The function takes no arguments and returns the
new `Circle` object.

.. ## Circle.copy ##

.. ## pygame.Circle ##
2 changes: 1 addition & 1 deletion docs/reST/themes/classic/elements.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ <h5>pygame-ce documentation</h5>
#}
{%- set basic = ['Color', 'display', 'draw', 'event', 'font', 'image', 'key', 'locals', 'mixer', 'mouse', 'music', 'pygame', 'Rect', 'Surface', 'time'] %}
{%- set advanced = ['BufferProxy', 'freetype', 'gfxdraw', 'midi', 'PixelArray', 'pixelcopy', 'sndarray', 'surfarray', 'cursors', 'joystick', 'mask', 'math', 'sprite', 'transform'] %}
{%- set hidden = ['sdl2_video', 'sdl2_controller'] %}
{%- set hidden = ['sdl2_video', 'sdl2_controller', 'geometry'] %}
{%- if pyg_sections %}
<p class="bottom"><b>Most useful stuff</b>:
{% set sep = joiner(" | \n") %}
Expand Down
3 changes: 2 additions & 1 deletion src_c/_pygame.h
Original file line number Diff line number Diff line change
Expand Up @@ -445,8 +445,9 @@ typedef enum {
#define PYGAMEAPI_PIXELARRAY_NUMSLOTS 2
#define PYGAMEAPI_COLOR_NUMSLOTS 5
#define PYGAMEAPI_MATH_NUMSLOTS 2
#define PYGAMEAPI_BASE_NUMSLOTS 24
#define PYGAMEAPI_BASE_NUMSLOTS 26
#define PYGAMEAPI_EVENT_NUMSLOTS 8
#define PYGAMEAPI_WINDOW_NUMSLOTS 1
#define PYGAMEAPI_GEOMETRY_NUMSLOTS 1

#endif /* _PYGAME_INTERNAL_H */
89 changes: 88 additions & 1 deletion src_c/base.c
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,91 @@ pg_TwoFloatsFromObj(PyObject *obj, float *val1, float *val2)
return 1;
}

static inline int
pg_DoubleFromObj(PyObject *obj, double *val)
{
if (PyFloat_Check(obj)) {
*val = PyFloat_AS_DOUBLE(obj);
return 1;
}

*val = (double)PyLong_AsLong(obj);
if (PyErr_Occurred()) {
PyErr_Clear();
return 0;
}

return 1;
}

/*Assumes obj is a Sequence, internal or conscious use only*/
static inline int
_pg_DoubleFromObjIndex(PyObject *obj, int index, double *val)
{
int result = 0;

PyObject *item = PySequence_ITEM(obj, index);
if (!item) {
PyErr_Clear();
return 0;
}
result = pg_DoubleFromObj(item, val);
Py_DECREF(item);

return result;
}

static inline int
pg_TwoDoublesFromObj(PyObject *obj, double *val1, double *val2)
{
Py_ssize_t length;
/*Faster path for tuples and lists*/
if (pgSequenceFast_Check(obj)) {
length = PySequence_Fast_GET_SIZE(obj);
PyObject **f_arr = PySequence_Fast_ITEMS(obj);
if (length == 2) {
if (!pg_DoubleFromObj(f_arr[0], val1) ||
!pg_DoubleFromObj(f_arr[1], val2)) {
return 0;
}
}
else if (length == 1) {
/* Handle case of ((x, y), ) 'nested sequence' */
return pg_TwoDoublesFromObj(f_arr[0], val1, val2);
}
else {
return 0;
}
}
else if (PySequence_Check(obj)) {
length = PySequence_Length(obj);
if (length == 2) {
if (!_pg_DoubleFromObjIndex(obj, 0, val1)) {
return 0;
}
if (!_pg_DoubleFromObjIndex(obj, 1, val2)) {
return 0;
}
}
else if (length == 1 && !PyUnicode_Check(obj)) {
/* Handle case of ((x, y), ) 'nested sequence' */
PyObject *tmp = PySequence_ITEM(obj, 0);
int ret = pg_TwoDoublesFromObj(tmp, val1, val2);
Py_DECREF(tmp);
return ret;
}
else {
PyErr_Clear();
return 0;
}
}
else {
return 0;
}

return 1;
}

static int
pg_UintFromObj(PyObject *obj, Uint32 *val)
{
Expand Down Expand Up @@ -2171,8 +2256,10 @@ MODINIT_DEFINE(base)
c_api[21] = pg_GetDefaultWindowSurface;
c_api[22] = pg_SetDefaultWindowSurface;
c_api[23] = pg_EnvShouldBlendAlphaSDL2;
c_api[24] = pg_DoubleFromObj;
c_api[25] = pg_TwoDoublesFromObj;

#define FILLED_SLOTS 24
#define FILLED_SLOTS 26

#if PYGAMEAPI_BASE_NUMSLOTS != FILLED_SLOTS
#error export slot count mismatch
Expand Down
Loading
Loading