0
# Boolean Operations
1
2
ManimGL provides precise geometric boolean operations for 2D vectorized objects through integration with the Skia-Path Ops library. These operations enable complex shape construction, geometric analysis, and sophisticated mathematical visualizations by combining, subtracting, and analyzing the relationships between shapes.
3
4
## Capabilities
5
6
### Union Operations
7
8
Combine multiple shapes into a single unified shape containing all areas from the input objects.
9
10
```python { .api }
11
class Union(VMobject):
12
def __init__(self, *vmobjects: VMobject, **kwargs):
13
"""
14
Create the union (combined area) of two or more VMobjects.
15
16
Parameters:
17
- vmobjects: Variable number of VMobject instances (minimum 2 required)
18
- kwargs: Additional keyword arguments passed to VMobject constructor
19
20
Raises:
21
- ValueError: If fewer than 2 mobjects are provided
22
"""
23
```
24
25
### Difference Operations
26
27
Subtract one shape from another, creating the remaining area after removal.
28
29
```python { .api }
30
class Difference(VMobject):
31
def __init__(self, subject: VMobject, clip: VMobject, **kwargs):
32
"""
33
Create the difference between two VMobjects (subject minus clip).
34
35
Parameters:
36
- subject: The VMobject to subtract from
37
- clip: The VMobject to subtract
38
- kwargs: Additional keyword arguments passed to VMobject constructor
39
"""
40
```
41
42
### Intersection Operations
43
44
Find the overlapping area where two or more shapes intersect.
45
46
```python { .api }
47
class Intersection(VMobject):
48
def __init__(self, *vmobjects: VMobject, **kwargs):
49
"""
50
Create the intersection (overlapping area) of two or more VMobjects.
51
52
Parameters:
53
- vmobjects: Variable number of VMobject instances (minimum 2 required)
54
- kwargs: Additional keyword arguments passed to VMobject constructor
55
56
Raises:
57
- ValueError: If fewer than 2 mobjects are provided
58
"""
59
```
60
61
### Exclusion Operations
62
63
Create the exclusive or (XOR) of shapes, showing areas that belong to exactly one of the input objects.
64
65
```python { .api }
66
class Exclusion(VMobject):
67
def __init__(self, *vmobjects: VMobject, **kwargs):
68
"""
69
Create the exclusive or (XOR) of two or more VMobjects.
70
71
Parameters:
72
- vmobjects: Variable number of VMobject instances (minimum 2 required)
73
- kwargs: Additional keyword arguments passed to VMobject constructor
74
75
Raises:
76
- ValueError: If fewer than 2 mobjects are provided
77
"""
78
```
79
80
### Internal Path Conversion
81
82
Low-level functions for converting between ManimGL objects and Skia paths for boolean operations.
83
84
```python { .api }
85
def _convert_vmobject_to_skia_path(vmobject: VMobject) -> pathops.Path:
86
"""
87
Convert a ManimGL VMobject to a Skia path for boolean operations.
88
89
Parameters:
90
- vmobject: VMobject to convert
91
92
Returns:
93
pathops.Path object for use in boolean operations
94
"""
95
96
def _convert_skia_path_to_vmobject(path: pathops.Path, vmobject: VMobject) -> VMobject:
97
"""
98
Convert a Skia path back to a ManimGL VMobject.
99
100
Parameters:
101
- path: pathops.Path object from boolean operation
102
- vmobject: Template VMobject for style and properties
103
104
Returns:
105
VMobject with boolean operation result
106
"""
107
```
108
109
## Usage Examples
110
111
### Basic Boolean Operations
112
113
```python
114
from manimlib import *
115
116
class BooleanBasics(Scene):
117
def construct(self):
118
# Create base shapes
119
circle = Circle(radius=1.5, color=BLUE, fill_opacity=0.5)
120
square = Square(side_length=2.5, color=RED, fill_opacity=0.5)
121
122
# Position shapes for demonstration
123
circle.shift(LEFT * 0.5)
124
square.shift(RIGHT * 0.5)
125
126
# Show original shapes
127
self.play(ShowCreation(circle), ShowCreation(square))
128
self.wait()
129
130
# Union - combine both shapes
131
union_result = Union(circle, square)
132
union_result.set_fill(GREEN, opacity=0.7)
133
134
self.play(
135
Transform(VGroup(circle, square), union_result),
136
run_time=2
137
)
138
self.wait()
139
140
# Reset for next operation
141
circle = Circle(radius=1.5, color=BLUE, fill_opacity=0.5).shift(LEFT * 0.5)
142
square = Square(side_length=2.5, color=RED, fill_opacity=0.5).shift(RIGHT * 0.5)
143
144
# Intersection - only overlapping area
145
intersection_result = Intersection(circle, square)
146
intersection_result.set_fill(PURPLE, opacity=0.8)
147
148
self.play(Transform(union_result, VGroup(circle, square)))
149
self.wait()
150
self.play(Transform(VGroup(circle, square), intersection_result))
151
self.wait()
152
```
153
154
### Complex Shape Construction
155
156
```python
157
class ComplexShapes(Scene):
158
def construct(self):
159
# Create gear shape using boolean operations
160
base_circle = Circle(radius=2, fill_opacity=1, color=GREY)
161
inner_circle = Circle(radius=0.8, fill_opacity=1, color=BLACK)
162
163
# Create gear teeth
164
num_teeth = 12
165
teeth = VGroup()
166
for i in range(num_teeth):
167
angle = i * TAU / num_teeth
168
tooth = Rectangle(
169
width=0.4, height=0.6,
170
fill_opacity=1, color=GREY
171
)
172
tooth.move_to(2.3 * np.array([np.cos(angle), np.sin(angle), 0]))
173
tooth.rotate(angle)
174
teeth.add(tooth)
175
176
# Combine all teeth with base circle
177
gear_outline = Union(base_circle, *teeth)
178
179
# Subtract inner circle to create hole
180
gear = Difference(gear_outline, inner_circle)
181
gear.set_fill(YELLOW, opacity=0.8)
182
gear.set_stroke(YELLOW_D, width=2)
183
184
self.play(ShowCreation(gear), run_time=3)
185
186
# Add rotation animation
187
self.play(Rotate(gear, TAU, run_time=4, rate_func=linear))
188
```
189
190
### Mathematical Set Visualization
191
192
```python
193
class SetOperations(Scene):
194
def construct(self):
195
# Create Venn diagram
196
set_a = Circle(radius=1.2, color=BLUE, fill_opacity=0.3)
197
set_b = Circle(radius=1.2, color=RED, fill_opacity=0.3)
198
199
set_a.shift(LEFT * 0.8)
200
set_b.shift(RIGHT * 0.8)
201
202
# Labels
203
label_a = Text("A", font_size=48).move_to(set_a.get_center() + LEFT * 0.5)
204
label_b = Text("B", font_size=48).move_to(set_b.get_center() + RIGHT * 0.5)
205
206
# Show base sets
207
self.add(set_a, set_b, label_a, label_b)
208
self.wait()
209
210
# Demonstrate each operation
211
operations = [
212
("A ∪ B (Union)", Union(set_a, set_b), YELLOW),
213
("A ∩ B (Intersection)", Intersection(set_a, set_b), GREEN),
214
("A - B (Difference)", Difference(set_a, set_b), ORANGE),
215
("A ⊕ B (XOR)", Exclusion(set_a, set_b), PURPLE)
216
]
217
218
for title, operation, color in operations:
219
result = operation.copy()
220
result.set_fill(color, opacity=0.8)
221
result.set_stroke(color, width=3)
222
223
title_text = Text(title, font_size=36).to_edge(UP)
224
225
self.play(
226
Write(title_text),
227
ShowCreation(result),
228
run_time=2
229
)
230
self.wait(2)
231
232
self.play(
233
FadeOut(title_text),
234
FadeOut(result)
235
)
236
```
237
238
### Advanced Shape Analysis
239
240
```python
241
class ShapeAnalysis(Scene):
242
def construct(self):
243
# Create overlapping shapes for analysis
244
triangle = RegularPolygon(3, radius=1.5, color=BLUE, fill_opacity=0.4)
245
hexagon = RegularPolygon(6, radius=1.8, color=RED, fill_opacity=0.4)
246
circle = Circle(radius=1.2, color=GREEN, fill_opacity=0.4)
247
248
triangle.shift(UP * 0.5)
249
hexagon.shift(DOWN * 0.3 + LEFT * 0.4)
250
circle.shift(DOWN * 0.3 + RIGHT * 0.4)
251
252
shapes = VGroup(triangle, hexagon, circle)
253
254
self.play(ShowCreation(shapes), run_time=2)
255
self.wait()
256
257
# Show different combinations
258
combinations = [
259
# All three shapes union
260
("All Combined", Union(triangle, hexagon, circle), YELLOW),
261
# Pairwise intersections
262
("Triangle ∩ Hexagon", Intersection(triangle, hexagon), ORANGE),
263
("Hexagon ∩ Circle", Intersection(hexagon, circle), PURPLE),
264
("Triangle ∩ Circle", Intersection(triangle, circle), PINK),
265
# Triple intersection
266
("All Intersect", Intersection(triangle, hexagon, circle), WHITE)
267
]
268
269
for title, result, color in combinations:
270
analysis = result.copy()
271
analysis.set_fill(color, opacity=0.9)
272
analysis.set_stroke(color, width=4)
273
274
title_text = Text(title, font_size=32).to_edge(UP)
275
276
self.play(Write(title_text))
277
self.play(
278
shapes.animate.set_fill_opacity(0.1),
279
ShowCreation(analysis),
280
run_time=2
281
)
282
self.wait(2)
283
284
self.play(
285
FadeOut(title_text),
286
FadeOut(analysis),
287
shapes.animate.set_fill_opacity(0.4)
288
)
289
290
self.wait()
291
```
292
293
### Dynamic Boolean Operations
294
295
```python
296
class DynamicBoolean(Scene):
297
def construct(self):
298
# Create movable shapes
299
circle = Circle(radius=1, color=BLUE, fill_opacity=0.6)
300
square = Square(side_length=1.8, color=RED, fill_opacity=0.6)
301
302
circle.to_edge(LEFT)
303
square.to_edge(RIGHT)
304
305
# Create result placeholder
306
result_union = Union(circle, square)
307
result_union.set_fill(YELLOW, opacity=0.8)
308
result_union.move_to(ORIGIN)
309
310
self.add(circle, square, result_union)
311
312
# Animate shapes moving and show dynamic boolean result
313
def update_union(mob):
314
new_union = Union(circle, square)
315
new_union.set_fill(YELLOW, opacity=0.8)
316
new_union.move_to(ORIGIN)
317
mob.become(new_union)
318
319
result_union.add_updater(update_union)
320
321
# Move shapes to show dynamic updating
322
self.play(
323
circle.animate.shift(RIGHT * 2),
324
square.animate.shift(LEFT * 2),
325
run_time=4
326
)
327
328
self.play(
329
circle.animate.shift(RIGHT * 1),
330
square.animate.shift(LEFT * 1),
331
run_time=3
332
)
333
334
result_union.clear_updaters()
335
self.wait()
336
```
337
338
## Implementation Details
339
340
### Path Conversion Process
341
342
Boolean operations work by converting ManimGL VMobjects to Skia paths, performing the geometric operations, and converting back:
343
344
1. **VMobject → Skia Path**: Extracts Bezier control points and converts cubic curves to quadratic
345
2. **Boolean Operation**: Uses pathops library functions (union, difference, intersection, xor)
346
3. **Skia Path → VMobject**: Reconstructs path commands into VMobject points
347
348
### Multi-Object Handling
349
350
- **Union**: Single operation combining all paths simultaneously
351
- **Intersection & Exclusion**: Sequential pairwise operations for multiple objects
352
- **Difference**: Single operation between subject and clip objects
353
354
### Integration with ManimGL
355
356
All boolean operation results are fully-featured VMobjects supporting:
357
- Complete styling (stroke, fill, color, opacity)
358
- All transformation methods (rotation, scaling, translation)
359
- Animation compatibility with all ManimGL animations
360
- Point manipulation and curve insertion methods
361
362
### Performance Considerations
363
364
Boolean operations are computationally intensive for complex shapes. For real-time or highly animated scenes, consider:
365
- Pre-computing complex boolean results
366
- Using simpler approximations for preview
367
- Limiting the number of concurrent boolean operations
368
369
The boolean operations module provides powerful tools for geometric construction and mathematical visualization, enabling sophisticated shape analysis and complex geometric demonstrations in ManimGL.