Skip to content

Commit d193d59

Browse files
committed
:Merge branch 'pillow'
2 parents 40026fd + 04571da commit d193d59

File tree

7 files changed

+204
-4
lines changed

7 files changed

+204
-4
lines changed

CHANGELOG.rst

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,20 @@
22
Changelog
33
=========
44

5-
.. NEXT
5+
Pymunk 7.2.0 (2025-11-02)
6+
-------------------------
7+
8+
This release provides wheels for Python 3.14. It also contains a new method
9+
that make it possible to get the inverse transform of a Transform.
10+
11+
**Wheels for Python 3.14**
12+
13+
Changes:
14+
15+
- Build wheels for 3.14
616
- Added Tranform.inverted() to get the inverse transform.
717

18+
819
Pymunk 7.1.0 (2025-06-29)
920
-------------------------
1021

27.2 KB
Loading

docs/src/conf.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,6 @@
9393
"pygame.locals",
9494
"pygame.color",
9595
"pyglet",
96+
"pillow",
97+
"PIL"
9698
]

dump/pillow_util.py

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
# ----------------------------------------------------------------------------
2+
# pymunk
3+
# Copyright (c) 2007-2025 Victor Blomqvist
4+
#
5+
# Permission is hereby granted, free of charge, to any person obtaining a copy
6+
# of this software and associated documentation files (the "Software"), to deal
7+
# in the Software without restriction, including without limitation the rights
8+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
# copies of the Software, and to permit persons to whom the Software is
10+
# furnished to do so, subject to the following conditions:
11+
#
12+
# The above copyright notice and this permission notice shall be included in
13+
# all copies or substantial portions of the Software.
14+
#
15+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
# SOFTWARE.
22+
# ----------------------------------------------------------------------------
23+
24+
"""This submodule contains helper functions to help with quick prototyping
25+
using pymunk together with Pillow/PIL.
26+
27+
For now this is experimental.
28+
29+
Intended to help with debugging and prototyping, not for actual production use
30+
in a full application. The methods contained in this module is opinionated
31+
about your coordinate system and not in any way optimized.
32+
"""
33+
34+
__docformat__ = "reStructuredText"
35+
36+
__all__ = [
37+
"DrawOptions",
38+
]
39+
40+
from typing import Sequence
41+
42+
from PIL import ImageDraw, Image
43+
44+
import pymunk
45+
from pymunk.space_debug_draw_options import SpaceDebugColor
46+
from pymunk.vec2d import Vec2d
47+
48+
49+
class DrawOptions(pymunk.SpaceDebugDrawOptions):
50+
def __init__(self, im: Image.Image) -> None:
51+
"""Draw a pymunk.Space on a pillow Image object.
52+
53+
Typical usage::
54+
55+
>>> import pymunk
56+
>>> from PIL import Image
57+
>>> image = Image.new("RGB", (1000, 700), "white")
58+
>>> space = pymunk.Space()
59+
>>> options = pymunk.pillow_util.DrawOptions(image)
60+
>>> space.debug_draw(options)
61+
62+
You can control the color of a shape by setting shape.color to the color
63+
you want it drawn in::
64+
65+
>>> c = pymunk.Circle(None, 10)
66+
>>> c.color = (255,0,0,255)
67+
68+
See pillow_util.demo.py for a full example
69+
70+
:Parameters:
71+
im : Image.Image
72+
Image that the objects will be drawn on
73+
"""
74+
self.image = im
75+
self.draw = ImageDraw.Draw(im)
76+
super(DrawOptions, self).__init__()
77+
78+
def draw_circle(
79+
self,
80+
pos: Vec2d,
81+
angle: float,
82+
radius: float,
83+
outline_color: SpaceDebugColor,
84+
fill_color: SpaceDebugColor,
85+
) -> None:
86+
self.draw.circle(pos, radius, fill_color.as_int(), outline_color.as_int(), 1)
87+
88+
circle_edge = pos + Vec2d.from_polar(radius, angle)
89+
p2 = circle_edge
90+
line_r = 2 if radius > 20 else 1
91+
self.draw.line([pos, p2], outline_color.as_int(), line_r)
92+
93+
94+
def draw_segment(self, a: Vec2d, b: Vec2d, color: SpaceDebugColor) -> None:
95+
self.draw.line([a,b], color.as_int())
96+
97+
def draw_fat_segment(
98+
self,
99+
a: tuple[float, float],
100+
b: tuple[float, float],
101+
radius: float,
102+
outline_color: SpaceDebugColor,
103+
fill_color: SpaceDebugColor,
104+
) -> None:
105+
p1 = a
106+
p2 = b
107+
108+
r = round(max(1, radius * 2))
109+
self.draw.line([a,b], fill_color.as_int(), r)
110+
111+
if r > 2:
112+
orthog = [abs(p2[1] - p1[1]), abs(p2[0] - p1[0])]
113+
if orthog[0] == 0 and orthog[1] == 0:
114+
return
115+
scale = radius / (orthog[0] * orthog[0] + orthog[1] * orthog[1]) ** 0.5
116+
orthog[0] = round(orthog[0] * scale)
117+
orthog[1] = round(orthog[1] * scale)
118+
points = [
119+
(p1[0] - orthog[0], p1[1] - orthog[1]),
120+
(p1[0] + orthog[0], p1[1] + orthog[1]),
121+
(p2[0] + orthog[0], p2[1] + orthog[1]),
122+
(p2[0] - orthog[0], p2[1] - orthog[1]),
123+
]
124+
self.draw.polygon(points, fill_color.as_int())
125+
self.draw.circle((round(p1[0]), round(p1[1])), radius-1, fill_color.as_int())
126+
self.draw.circle((round(p2[0]), round(p2[1])), radius-1, fill_color.as_int())
127+
128+
def draw_polygon(
129+
self,
130+
verts: Sequence[tuple[float, float]],
131+
radius: float,
132+
outline_color: SpaceDebugColor,
133+
fill_color: SpaceDebugColor,
134+
) -> None:
135+
ps = [v for v in verts]
136+
ps += [ps[0]]
137+
138+
self.draw.polygon(ps, fill_color.as_int())
139+
140+
if radius > 0:
141+
for i in range(len(verts)):
142+
a = verts[i]
143+
b = verts[(i + 1) % len(verts)]
144+
self.draw_fat_segment(a, b, radius, outline_color, outline_color)
145+
146+
def draw_dot(
147+
self, size: float, pos: tuple[float, float], color: SpaceDebugColor
148+
) -> None:
149+
self.draw.circle(pos, size, color.as_int(), width=0)
150+
151+

dump/pillow_util_demo.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
"""Showcase what the output of pymunk.pyglet_util draw methods will look like.
2+
3+
See pygame_util_demo.py for a comparison to pygame.
4+
"""
5+
6+
__docformat__ = "reStructuredText"
7+
8+
from PIL import Image, ImageDraw, ImageColor, ImageShow
9+
10+
import pymunk
11+
import pymunk.pillow_util
12+
13+
from .shapes_for_draw_demos import fill_space
14+
15+
img = Image.new("RGB", (1000, 700), "white")
16+
draw = ImageDraw.Draw(img)
17+
18+
space = pymunk.Space()
19+
draw_options = pymunk.pillow_util.DrawOptions(img)
20+
captions = fill_space(space)
21+
22+
23+
24+
labels = []
25+
26+
draw.text((5,5),"Demo example of shapes drawn by pillow_util.draw()", fill=(100,100,100))
27+
28+
for caption in captions:
29+
x, y = caption[0]
30+
y = y - 10
31+
draw.text((x,y),caption[1], fill=(50,50,50))
32+
33+
space.debug_draw(draw_options)
34+
35+
img.save("pillow_util_demo.png")
36+
ImageShow.show(img)

pymunk/tests/doctests.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import pymunk
77

88
ignores = ["pymunk_extension_build"]
9-
all_dependencies = ["pygame", "pyglet", "matplotlib", "_pyglet"]
9+
all_dependencies = ["pygame", "pyglet", "matplotlib", "_pyglet", "pillow", "PIL"]
1010

1111

1212
def load_tests(

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ build-backend = "setuptools.build_meta"
1010
[project]
1111
name = "pymunk"
1212
version = "7.1.0" # remember to change me for new versions!
13-
# Require cffi >1.14.0 since that (and older) has problem with returing structs from functions.
13+
# Require cffi >1.14.0 since that (and older) has problem with returning structs from functions.
1414
# Require cffi >= 1.17.1 since older cant work with latest setuptools version
1515
dependencies = [
1616
"cffi >= 1.17.1; platform_system != 'Emscripten'",
@@ -36,7 +36,7 @@ classifiers = [
3636
requires-python = ">=3.9"
3737

3838
[project.optional-dependencies]
39-
dev = ["pyglet", "pygame", "sphinx", "aafigure", "wheel", "matplotlib", "numpy"]
39+
dev = ["pyglet", "pygame", "pillow", "sphinx", "aafigure", "wheel", "matplotlib", "numpy"]
4040
[project.urls]
4141
Homepage = "https://www.pymunk.org"
4242
Documentation = "https://www.pymunk.org"

0 commit comments

Comments
 (0)