diff --git a/buildconfig/Setup.Android.SDL2.in b/buildconfig/Setup.Android.SDL2.in index fc556ad024..ad9c7527f9 100644 --- a/buildconfig/Setup.Android.SDL2.in +++ b/buildconfig/Setup.Android.SDL2.in @@ -46,7 +46,6 @@ display src_c/display.c $(SDL) $(DEBUG) event src_c/event.c $(SDL) $(DEBUG) key src_c/key.c $(SDL) $(DEBUG) mouse src_c/mouse.c $(SDL) $(DEBUG) -rect src_c/rect.c src_c/pgcompat_rect.c $(SDL) $(DEBUG) rwobject src_c/rwobject.c $(SDL) $(DEBUG) surface src_c/simd_blitters_sse2.c src_c/simd_blitters_avx2.c src_c/surface.c src_c/alphablit.c src_c/surface_fill.c src_c/simd_surface_fill_avx2.c src_c/simd_surface_fill_sse2.c $(SDL) $(DEBUG) surflock src_c/surflock.c $(SDL) $(DEBUG) diff --git a/buildconfig/Setup.Emscripten.SDL2.in b/buildconfig/Setup.Emscripten.SDL2.in index 23b22f5766..34497162cb 100644 --- a/buildconfig/Setup.Emscripten.SDL2.in +++ b/buildconfig/Setup.Emscripten.SDL2.in @@ -59,7 +59,6 @@ pixelcopy src_c/void.c pixelarray src_c/void.c surface src_c/void.c surflock src_c/void.c -rect src_c/void.c rwobject src_c/void.c system src_c/void.c window src_c/void.c diff --git a/buildconfig/Setup.SDL2.in b/buildconfig/Setup.SDL2.in index 2fd66eeea3..a2a5263857 100644 --- a/buildconfig/Setup.SDL2.in +++ b/buildconfig/Setup.SDL2.in @@ -56,7 +56,6 @@ display src_c/display.c $(SDL) $(DEBUG) event src_c/event.c $(SDL) $(DEBUG) key src_c/key.c $(SDL) $(DEBUG) mouse src_c/mouse.c $(SDL) $(DEBUG) -rect src_c/rect.c src_c/pgcompat_rect.c $(SDL) $(DEBUG) rwobject src_c/rwobject.c $(SDL) $(DEBUG) surface src_c/simd_blitters_sse2.c src_c/simd_blitters_avx2.c src_c/surface.c src_c/alphablit.c src_c/surface_fill.c src_c/simd_surface_fill_avx2.c src_c/simd_surface_fill_sse2.c $(SDL) $(DEBUG) surflock src_c/surflock.c $(SDL) $(DEBUG) diff --git a/buildconfig/stubs/gen_stubs.py b/buildconfig/stubs/gen_stubs.py index 670db2f951..101898e112 100644 --- a/buildconfig/stubs/gen_stubs.py +++ b/buildconfig/stubs/gen_stubs.py @@ -55,7 +55,6 @@ # pygame classes that are autoimported into main namespace are kept in this dict PG_AUTOIMPORT_CLASSES = { - "rect": ["Rect", "FRect"], "surface": ["Surface", "SurfaceType"], "color": ["Color"], "pixelarray": ["PixelArray"], @@ -71,8 +70,8 @@ "joystick": ["Joystick"], "window": ["Window"], "base": ["__version__"], # need an explicit import - # uncomment below line if Circle is added to the base namespace later - # "geometry": ["Circle"], + # Add "Circle" to the list if Circle is added to the base namespace later + "geometry": ["Rect", "FRect"], } # pygame modules from which __init__.py does the equivalent of diff --git a/buildconfig/stubs/pygame/geometry.pyi b/buildconfig/stubs/pygame/geometry.pyi index fb7c8de850..853e559e21 100644 --- a/buildconfig/stubs/pygame/geometry.pyi +++ b/buildconfig/stubs/pygame/geometry.pyi @@ -1,3 +1,4 @@ + from typing import ( overload, Union, @@ -7,11 +8,19 @@ from typing import ( Sequence, ) -from pygame import Rect, FRect from ._common import Coordinate, RectValue -from .rect import Rect, FRect +from .rect import Rect as Rect_, FRect as FRect_ from .math import Vector2 +class Rect(Rect_): + ... + +class FRect(FRect_): + ... + +RectType = Rect +FRectType = FRect + _CanBeCircle = Union[Circle, Tuple[Coordinate, float], Sequence[float]] class _HasCirclettribute(Protocol): diff --git a/buildconfig/stubs/pygame/rect.pyi b/buildconfig/stubs/pygame/rect.pyi index b401f9a930..4b15fd3d40 100644 --- a/buildconfig/stubs/pygame/rect.pyi +++ b/buildconfig/stubs/pygame/rect.pyi @@ -11,6 +11,7 @@ from typing import ( ) from ._common import Coordinate, Literal, RectValue, SupportsIndex, Sequence +from .geometry import _CircleValue if sys.version_info >= (3, 11): from typing import Self @@ -249,6 +250,12 @@ class _GenericRect(Collection[_N]): def colliderect( self, left: float, top: float, width: float, height: float, / ) -> bool: ... + @overload + def collidecircle(self, circle: _CircleValue, /) -> bool: ... + @overload + def collidecircle(self, pos: Coordinate, r: float, /) -> bool: ... + @overload + def collidecircle(self, x: float, y: float, r: float, /) -> bool: ... def collidelist(self, rect_list: Sequence[_RectTypeCompatible_co], /) -> int: ... def collidelistall(self, rect_list: Sequence[_RectTypeCompatible_co], /) -> List[int]: ... def collideobjectsall( diff --git a/docs/reST/ref/rect.rst b/docs/reST/ref/rect.rst index a936683a10..d16aedc8ec 100644 --- a/docs/reST/ref/rect.rst +++ b/docs/reST/ref/rect.rst @@ -391,6 +391,20 @@ .. ## Rect.colliderect ## + .. method:: collidecircle + + | :sl:`checks if a circle intersects the rectangle` + | :sg:`collidecircle(Circle) -> bool` + | :sg:`collidecircle((x, y), r) -> bool` + | :sg:`collidecircle(x, y, r) -> bool` + + Returns `True` if any portion of the `Circle` overlaps with the rectangle, + `False` otherwise. + + .. versionadded:: 2.5.1 + + .. ## Rect.collidecircle ## + .. method:: collidelist | :sl:`test if one rectangle in a list intersects` diff --git a/src_c/_pygame.h b/src_c/_pygame.h index aa13a70bb0..4e8051e932 100644 --- a/src_c/_pygame.h +++ b/src_c/_pygame.h @@ -523,7 +523,6 @@ typedef enum { * Remember to keep these constants up to date. */ -#define PYGAMEAPI_RECT_NUMSLOTS 10 #define PYGAMEAPI_JOYSTICK_NUMSLOTS 3 #define PYGAMEAPI_DISPLAY_NUMSLOTS 2 #define PYGAMEAPI_SURFACE_NUMSLOTS 4 @@ -535,6 +534,6 @@ typedef enum { #define PYGAMEAPI_BASE_NUMSLOTS 29 #define PYGAMEAPI_EVENT_NUMSLOTS 10 #define PYGAMEAPI_WINDOW_NUMSLOTS 1 -#define PYGAMEAPI_GEOMETRY_NUMSLOTS 1 +#define PYGAMEAPI_GEOMETRY_NUMSLOTS 11 #endif /* _PYGAME_INTERNAL_H */ diff --git a/src_c/doc/rect_doc.h b/src_c/doc/rect_doc.h index 934460fef6..463f86f819 100644 --- a/src_c/doc/rect_doc.h +++ b/src_c/doc/rect_doc.h @@ -22,6 +22,7 @@ #define DOC_RECT_CONTAINS "contains(rect, /) -> bool\ntest if one rectangle is inside another" #define DOC_RECT_COLLIDEPOINT "collidepoint(x, y, /) -> bool\ncollidepoint((x, y), /) -> bool\ntest if a point is inside a rectangle" #define DOC_RECT_COLLIDERECT "colliderect(rect, /) -> bool\ntest if two rectangles overlap" +#define DOC_RECT_COLLIDECIRCLE "collidecircle(Circle) -> bool\ncollidecircle((x, y), r) -> bool\ncollidecircle(x, y, r) -> bool\nchecks if a circle intersects the rectangle" #define DOC_RECT_COLLIDELIST "collidelist(list, /) -> index\ntest if one rectangle in a list intersects" #define DOC_RECT_COLLIDELISTALL "collidelistall(list, /) -> indices\ntest if all rectangles in a list intersect" #define DOC_RECT_COLLIDEOBJECTS "collideobjects(rect_list) -> object\ncollideobjects(obj_list, key=func) -> object\ntest if any object in a list intersects" diff --git a/src_c/geometry.c b/src_c/geometry.c index 4ccb0ad22d..f2674129c0 100644 --- a/src_c/geometry.c +++ b/src_c/geometry.c @@ -1,3 +1,5 @@ +#include "pgcompat_rect.c" +#include "rect.c" #include "circle.c" #include "geometry_common.c" @@ -21,12 +23,11 @@ MODINIT_DEFINE(geometry) return NULL; } - import_pygame_rect(); - if (PyErr_Occurred()) { + if (PyType_Ready(&pgCircle_Type) < 0) { return NULL; } - if (PyType_Ready(&pgCircle_Type) < 0) { + if (PyType_Ready(&pgRect_Type) < 0 || PyType_Ready(&pgFRect_Type) < 0) { return NULL; } @@ -35,6 +36,31 @@ MODINIT_DEFINE(geometry) return NULL; } + Py_INCREF(&pgRect_Type); + if (PyModule_AddObject(module, "RectType", (PyObject *)&pgRect_Type)) { + Py_DECREF(&pgRect_Type); + Py_DECREF(module); + return NULL; + } + Py_INCREF(&pgRect_Type); + if (PyModule_AddObject(module, "Rect", (PyObject *)&pgRect_Type)) { + Py_DECREF(&pgRect_Type); + Py_DECREF(module); + return NULL; + } + Py_INCREF(&pgFRect_Type); + if (PyModule_AddObject(module, "FRectType", (PyObject *)&pgFRect_Type)) { + Py_DECREF(&pgFRect_Type); + Py_DECREF(module); + return NULL; + } + Py_INCREF(&pgFRect_Type); + if (PyModule_AddObject(module, "FRect", (PyObject *)&pgFRect_Type)) { + Py_DECREF(&pgFRect_Type); + Py_DECREF(module); + return NULL; + } + Py_INCREF(&pgCircle_Type); if (PyModule_AddObject(module, "Circle", (PyObject *)&pgCircle_Type)) { Py_DECREF(&pgCircle_Type); @@ -42,7 +68,17 @@ MODINIT_DEFINE(geometry) return NULL; } - c_api[0] = &pgCircle_Type; + c_api[0] = &pgRect_Type; + c_api[1] = pgRect_New; + c_api[2] = pgRect_New4; + c_api[3] = pgRect_FromObject; + c_api[4] = pgRect_Normalize; + c_api[5] = &pgFRect_Type; + c_api[6] = pgFRect_New; + c_api[7] = pgFRect_New4; + c_api[8] = pgFRect_FromObject; + c_api[9] = pgFRect_Normalize; + c_api[10] = &pgCircle_Type; apiobj = encapsulate_api(c_api, "geometry"); if (PyModule_AddObject(module, PYGAMEAPI_LOCAL_ENTRY, apiobj)) { Py_XDECREF(apiobj); diff --git a/src_c/include/_pygame.h b/src_c/include/_pygame.h index 1477fe24cc..32827dd2f6 100644 --- a/src_c/include/_pygame.h +++ b/src_c/include/_pygame.h @@ -192,6 +192,12 @@ typedef struct pg_bufferinfo_s { #define import_pygame_base() IMPORT_PYGAME_MODULE(base) #endif /* ~PYGAMEAPI_BASE_INTERNAL */ +#ifndef PYGAMEAPI_GEOMETRY_INTERNAL + +#define import_pygame_geometry() IMPORT_PYGAME_MODULE(geometry) + +#endif /* ~PYGAMEAPI_GEOMETRY_INTERNAL */ + typedef struct { PyObject_HEAD SDL_Rect r; PyObject *weakreflist; @@ -204,35 +210,42 @@ typedef struct { #define pgRect_AsRect(x) (((pgRectObject *)x)->r) #define pgFRect_AsRect(x) (((pgFRectObject *)x)->r) + #ifndef PYGAMEAPI_RECT_INTERNAL -#define pgRect_Type (*(PyTypeObject *)PYGAMEAPI_GET_SLOT(rect, 0)) + +#define pgRect_Type (*(PyTypeObject *)PYGAMEAPI_GET_SLOT(geometry, 0)) #define pgRect_Check(x) ((x)->ob_type == &pgRect_Type) -#define pgRect_New (*(PyObject * (*)(SDL_Rect *)) PYGAMEAPI_GET_SLOT(rect, 1)) +#define pgRect_New \ + (*(PyObject * (*)(SDL_Rect *)) PYGAMEAPI_GET_SLOT(geometry, 1)) #define pgRect_New4 \ - (*(PyObject * (*)(int, int, int, int)) PYGAMEAPI_GET_SLOT(rect, 2)) + (*(PyObject * (*)(int, int, int, int)) PYGAMEAPI_GET_SLOT(geometry, 2)) #define pgRect_FromObject \ - (*(SDL_Rect * (*)(PyObject *, SDL_Rect *)) PYGAMEAPI_GET_SLOT(rect, 3)) + (*(SDL_Rect * (*)(PyObject *, SDL_Rect *)) PYGAMEAPI_GET_SLOT(geometry, 3)) -#define pgRect_Normalize (*(void (*)(SDL_Rect *))PYGAMEAPI_GET_SLOT(rect, 4)) +#define pgRect_Normalize \ + (*(void (*)(SDL_Rect *))PYGAMEAPI_GET_SLOT(geometry, 4)) -#define pgFRect_Type (*(PyTypeObject *)PYGAMEAPI_GET_SLOT(rect, 5)) +#define pgFRect_Type (*(PyTypeObject *)PYGAMEAPI_GET_SLOT(geometry, 5)) #define pgFRect_Check(x) ((x)->ob_type == &pgFRect_Type) #define pgFRect_New \ - (*(PyObject * (*)(SDL_FRect *)) PYGAMEAPI_GET_SLOT(rect, 6)) + (*(PyObject * (*)(SDL_FRect *)) PYGAMEAPI_GET_SLOT(geometry, 6)) -#define pgFRect_New4 \ - (*(PyObject * (*)(float, float, float, float)) PYGAMEAPI_GET_SLOT(rect, 7)) +#define pgFRect_New4 \ + (*(PyObject * (*)(float, float, float, float)) \ + PYGAMEAPI_GET_SLOT(geometry, 7)) -#define pgFRect_FromObject \ - (*(SDL_FRect * (*)(PyObject *, SDL_FRect *)) PYGAMEAPI_GET_SLOT(rect, 8)) +#define pgFRect_FromObject \ + (*(SDL_FRect * (*)(PyObject *, SDL_FRect *)) \ + PYGAMEAPI_GET_SLOT(geometry, 8)) -#define pgFRect_Normalize (*(void (*)(SDL_FRect *))PYGAMEAPI_GET_SLOT(rect, 9)) +#define pgFRect_Normalize \ + (*(void (*)(SDL_FRect *))PYGAMEAPI_GET_SLOT(geometry, 9)) -#define import_pygame_rect() IMPORT_PYGAME_MODULE(rect) +#define import_pygame_rect() IMPORT_PYGAME_MODULE(geometry) #endif /* ~PYGAMEAPI_RECT_INTERNAL */ /* @@ -500,12 +513,6 @@ typedef struct pgColorObject pgColorObject; #define import_pygame_math() IMPORT_PYGAME_MODULE(math) #endif /* PYGAMEAPI_MATH_INTERNAL */ -#ifndef PYGAMEAPI_GEOMETRY_INTERNAL - -#define import_pygame_geometry() IMPORT_PYGAME_MODULE(geometry) - -#endif /* ~PYGAMEAPI_GEOMETRY_INTERNAL */ - /* * Window module */ @@ -531,7 +538,6 @@ typedef struct { */ #ifdef PYGAME_H PYGAMEAPI_DEFINE_SLOTS(base); -PYGAMEAPI_DEFINE_SLOTS(rect); PYGAMEAPI_DEFINE_SLOTS(joystick); PYGAMEAPI_DEFINE_SLOTS(display); PYGAMEAPI_DEFINE_SLOTS(surface); @@ -545,7 +551,6 @@ PYGAMEAPI_DEFINE_SLOTS(window); PYGAMEAPI_DEFINE_SLOTS(geometry); #else /* ~PYGAME_H */ PYGAMEAPI_EXTERN_SLOTS(base); -PYGAMEAPI_EXTERN_SLOTS(rect); PYGAMEAPI_EXTERN_SLOTS(joystick); PYGAMEAPI_EXTERN_SLOTS(display); PYGAMEAPI_EXTERN_SLOTS(surface); diff --git a/src_c/meson.build b/src_c/meson.build index 8e8287c834..3cb09d2211 100644 --- a/src_c/meson.build +++ b/src_c/meson.build @@ -62,15 +62,6 @@ mouse = py.extension_module( subdir: pg, ) -rect = py.extension_module( - 'rect', - ['rect.c', 'pgcompat_rect.c'], - c_args: warnings_error, - dependencies: pg_base_deps, - install: true, - subdir: pg, -) - rwobject = py.extension_module( 'rwobject', 'rwobject.c', diff --git a/src_c/rect.c b/src_c/rect.c index b300c2f97f..bb551ac6ff 100644 --- a/src_c/rect.c +++ b/src_c/rect.c @@ -36,6 +36,8 @@ #include +#include "geometry_common.h" + static PyTypeObject pgRect_Type; static PyTypeObject pgFRect_Type; #define pgRect_Check(x) (PyObject_IsInstance(x, (PyObject *)&pgRect_Type)) @@ -69,6 +71,7 @@ four_floats_from_obj(PyObject *obj, float *val1, float *val2, float *val3, #define RectExport_unionallIp pg_rect_unionall_ip #define RectExport_collidepoint pg_rect_collidepoint #define RectExport_colliderect pg_rect_colliderect +#define RectExport_collidecircle pg_rect_collidecircle #define RectExport_collidelist pg_rect_collidelist #define RectExport_collidelistall pg_rect_collidelistall #define RectExport_RectFromObjectAndKeyFunc pgRect_FromObjectAndKeyFunc @@ -184,6 +187,7 @@ four_floats_from_obj(PyObject *obj, float *val1, float *val2, float *val3, #define RectExport_unionallIp pg_frect_unionall_ip #define RectExport_collidepoint pg_frect_collidepoint #define RectExport_colliderect pg_frect_colliderect +#define RectExport_collidecircle pg_frect_collidecircle #define RectExport_collidelist pg_frect_collidelist #define RectExport_collidelistall pg_frect_collidelistall #define RectExport_RectFromObjectAndKeyFunc pgFRect_FromObjectAndKeyFunc @@ -487,6 +491,8 @@ static struct PyMethodDef pg_rect_methods[] = { DOC_RECT_COLLIDEPOINT}, {"colliderect", (PyCFunction)pg_rect_colliderect, METH_FASTCALL, DOC_RECT_COLLIDERECT}, + {"collidecircle", (PyCFunction)pg_rect_collidecircle, METH_FASTCALL, + DOC_RECT_COLLIDECIRCLE}, {"collidelist", (PyCFunction)pg_rect_collidelist, METH_O, DOC_RECT_COLLIDELIST}, {"collidelistall", (PyCFunction)pg_rect_collidelistall, METH_O, @@ -538,6 +544,8 @@ static struct PyMethodDef pg_frect_methods[] = { DOC_RECT_COLLIDEPOINT}, {"colliderect", (PyCFunction)pg_frect_colliderect, METH_FASTCALL, DOC_RECT_COLLIDERECT}, + {"collidecircle", (PyCFunction)pg_frect_collidecircle, METH_FASTCALL, + DOC_RECT_COLLIDECIRCLE}, {"collidelist", (PyCFunction)pg_frect_collidelist, METH_O, DOC_RECT_COLLIDELIST}, {"collidelistall", (PyCFunction)pg_frect_collidelistall, METH_O, @@ -759,85 +767,3 @@ static PyTypeObject pgFRect_Type = { .tp_iter = (getiterfunc)pg_frect_iterator, .tp_methods = pg_frect_methods, .tp_getset = pg_frect_getsets, .tp_init = (initproc)pg_frect_init, .tp_new = pg_frect_new}; - -static PyMethodDef _pg_module_methods[] = {{NULL, NULL, 0, NULL}}; - -static char _pg_module_doc[] = "Module for the rectangle object\n"; - -MODINIT_DEFINE(rect) -{ - PyObject *module, *apiobj; - static void *c_api[PYGAMEAPI_RECT_NUMSLOTS]; - - static struct PyModuleDef _module = {PyModuleDef_HEAD_INIT, - "rect", - _pg_module_doc, - -1, - _pg_module_methods, - NULL, - NULL, - NULL, - NULL}; - - /* import needed apis; Do this first so if there is an error - the module is not loaded. - */ - import_pygame_base(); - if (PyErr_Occurred()) { - return NULL; - } - - /* Create the module and add the functions */ - if (PyType_Ready(&pgRect_Type) < 0 || PyType_Ready(&pgFRect_Type) < 0) { - return NULL; - } - - module = PyModule_Create(&_module); - if (module == NULL) { - return NULL; - } - - Py_INCREF(&pgRect_Type); - if (PyModule_AddObject(module, "RectType", (PyObject *)&pgRect_Type)) { - Py_DECREF(&pgRect_Type); - Py_DECREF(module); - return NULL; - } - Py_INCREF(&pgRect_Type); - if (PyModule_AddObject(module, "Rect", (PyObject *)&pgRect_Type)) { - Py_DECREF(&pgRect_Type); - Py_DECREF(module); - return NULL; - } - Py_INCREF(&pgFRect_Type); - if (PyModule_AddObject(module, "FRectType", (PyObject *)&pgFRect_Type)) { - Py_DECREF(&pgFRect_Type); - Py_DECREF(module); - return NULL; - } - Py_INCREF(&pgFRect_Type); - if (PyModule_AddObject(module, "FRect", (PyObject *)&pgFRect_Type)) { - Py_DECREF(&pgFRect_Type); - Py_DECREF(module); - return NULL; - } - - /* export the c api */ - c_api[0] = &pgRect_Type; - c_api[1] = pgRect_New; - c_api[2] = pgRect_New4; - c_api[3] = pgRect_FromObject; - c_api[4] = pgRect_Normalize; - c_api[5] = &pgFRect_Type; - c_api[6] = pgFRect_New; - c_api[7] = pgFRect_New4; - c_api[8] = pgFRect_FromObject; - c_api[9] = pgFRect_Normalize; - apiobj = encapsulate_api(c_api, "rect"); - if (PyModule_AddObject(module, PYGAMEAPI_LOCAL_ENTRY, apiobj)) { - Py_XDECREF(apiobj); - Py_DECREF(module); - return NULL; - } - return module; -} diff --git a/src_c/rect_impl.h b/src_c/rect_impl.h index 0187f07768..1f56c15304 100644 --- a/src_c/rect_impl.h +++ b/src_c/rect_impl.h @@ -34,6 +34,8 @@ #include +#include "geometry_common.h" + // #region RectExport #ifndef RectExport_init #error RectExport_init needs to be defined @@ -95,6 +97,9 @@ #ifndef RectExport_colliderect #error RectExport_colliderect needs to be defined #endif +#ifndef RectExport_collidecircle +#error RectExport_collidecircle needs to be defined +#endif #ifndef RectExport_collidelist #error RectExport_collidelist needs to be defined #endif @@ -485,6 +490,9 @@ static PyObject * RectExport_colliderect(RectObject *self, PyObject *const *args, Py_ssize_t nargs); static PyObject * +RectExport_collidecircle(RectObject *self, PyObject *const *args, + Py_ssize_t nargs); +static PyObject * RectExport_collidelist(RectObject *self, PyObject *args); static PyObject * RectExport_collidelistall(RectObject *self, PyObject *args); @@ -1337,6 +1345,22 @@ RectExport_colliderect(RectObject *self, PyObject *const *args, return PyBool_FromLong(_pg_do_rects_intersect(&self->r, argrect)); } +static PyObject * +RectExport_collidecircle(RectObject *self, PyObject *const *args, + Py_ssize_t nargs) +{ + pgCircleBase circle; + InnerRect srect = self->r; + + if (!pgCircle_FromObjectFastcall(args, nargs, &circle)) { + return RAISE(PyExc_TypeError, "A CircleType object was expected"); + } + + return PyBool_FromLong( + pgCollision_RectCircle((double)srect.x, (double)srect.y, + (double)srect.w, (double)srect.h, &circle)); +} + #ifndef OPTIMIZED_COLLIDERECT_SETUP /* This macro is used to optimize the colliderect function. It calculates * the left, top, right and bottom values of the calling rect only once @@ -2858,6 +2882,7 @@ RectExport_iterator(RectObject *self) #undef RectExport_unionallIp #undef RectExport_collidepoint #undef RectExport_colliderect +#undef RectExport_collidecircle #undef RectExport_collidelist #undef RectExport_collidelistall #undef RectExport_collidedict diff --git a/src_c/static.c b/src_c/static.c index b7e8d1ec66..6116428ad0 100644 --- a/src_c/static.c +++ b/src_c/static.c @@ -89,8 +89,6 @@ PyInit_constants(void); PyMODINIT_FUNC PyInit_version(void); PyMODINIT_FUNC -PyInit_rect(void); -PyMODINIT_FUNC PyInit_geometry(void); PyMODINIT_FUNC PyInit_surflock(void); @@ -278,6 +276,7 @@ PyInit_pygame_static() SDL_SetHint("SDL_EMSCRIPTEN_KEYBOARD_ELEMENT", "1"); load_submodule("pygame", PyInit_base(), "base"); + load_submodule("pygame", PyInit_geometry(), "geometry"); load_submodule("pygame", PyInit_constants(), "constants"); load_submodule("pygame", PyInit_surflock(), "surflock"); load_submodule("pygame", PyInit_rwobject(), "rwobject"); @@ -287,8 +286,6 @@ PyInit_pygame_static() load_submodule("pygame", PyInit_system(), "system"); load_submodule("pygame", PyInit_key(), "key"); - load_submodule("pygame", PyInit_rect(), "rect"); - load_submodule("pygame", PyInit_geometry(), "geometry"); load_submodule("pygame", PyInit_gfxdraw(), "gfxdraw"); load_submodule("pygame", PyInit_pg_time(), "time"); load_submodule("pygame", PyInit__freetype(), "_freetype"); @@ -325,8 +322,7 @@ PyInit_pygame_static() #include "base.c" -#include "rect.c" -#include "pgcompat_rect.c" +#include "geometry.c" #undef pgSurface_Lock #undef pgSurface_Unlock @@ -402,7 +398,6 @@ PyInit_pygame_static() #include "time.c" #include "system.c" -#include "geometry.c" #include "_freetype.c" #include "freetype/ft_wrap.c" diff --git a/src_py/meson.build b/src_py/meson.build index 561aebaadb..c37b4c41de 100644 --- a/src_py/meson.build +++ b/src_py/meson.build @@ -19,6 +19,7 @@ python_sources = files( 'surfarray.py', 'sysfont.py', 'version.py', + 'rect.py', ) py.install_sources(python_sources, subdir: pg) diff --git a/src_py/rect.py b/src_py/rect.py new file mode 100644 index 0000000000..2aa2f93181 --- /dev/null +++ b/src_py/rect.py @@ -0,0 +1 @@ +from pygame.geometry import Rect, FRect, RectType, FRectType diff --git a/test/rect_test.py b/test/rect_test.py index 307feb8b29..ff813880c1 100644 --- a/test/rect_test.py +++ b/test/rect_test.py @@ -3,6 +3,7 @@ from collections.abc import Collection, Sequence from pygame import Vector2, FRect, Rect as IRect +from pygame.geometry import Circle from pygame.tests import test_utils Rect = IRect @@ -1683,6 +1684,71 @@ def test_colliderect(self): "r1 collides with Rect(r1.right, r1.bottom, 1, 1)", ) + def test_collidecircle_argtype(self): + """tests if the function correctly handles incorrect types as parameters""" + invalid_types = (None, [], "1", (1,), Vector2(1, 1), 1) + + r = Rect(6, 6, 8, 8) + + for value in invalid_types: + with self.assertRaises(TypeError): + r.collidecircle(value) + + def test_collidecircle_argnum(self): + r = Rect(6, 6, 8, 8) + # no params + with self.assertRaises(TypeError): + r.collidecircle() + + with self.assertRaises(TypeError): + r.collidecircle(Circle(10, 10, 4), Circle(10, 10, 4)) + + def test_collidecircle(self): + r = Rect(-5, -5, 10, 10) + + c1 = Circle(10, 0, 5) + c2 = Circle(100, 100, 5) + c3 = Circle(10, 0, 4.999999999999) + c4 = Circle(0, 0, 2) + c5 = Circle(10, 0, 7) + c6 = Circle(0, 0, 5) + c7 = Circle(0, 0, 20) + + # touching + self.assertTrue( + r.collidecircle(c1), "Expected True, circle should collide here" + ) + + # partly colliding + self.assertTrue( + r.collidecircle(c5), "Expected True, circle should collide here" + ) + + # completely colliding + self.assertTrue( + r.collidecircle(c6), "Expected True, circle should collide here" + ) + + # not touching + self.assertFalse( + r.collidecircle(c2), "Expected False, circle should not collide here" + ) + + # barely not touching + self.assertFalse( + r.collidecircle(c3), "Expected False, circle should not collide here" + ) + + # small circle inside bigger rect + self.assertTrue( + r.collidecircle(c4), "Expected True, circle should collide here" + ) + + # big circle inside smaller rect + self.assertTrue( + r.collidecircle(c7), "Expected True, circle should collide here" + ) + def testEquals(self): """check to see how the rect uses __eq__""" r1 = Rect(1, 2, 3, 4)