CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-manimgl

Animation engine for explanatory math videos with programmatic mathematical visualization capabilities

Pending
Overview
Eval results
Files

boolean-operations.mddocs/

Boolean Operations

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.

Capabilities

Union Operations

Combine multiple shapes into a single unified shape containing all areas from the input objects.

class Union(VMobject):
    def __init__(self, *vmobjects: VMobject, **kwargs):
        """
        Create the union (combined area) of two or more VMobjects.
        
        Parameters:
        - vmobjects: Variable number of VMobject instances (minimum 2 required)
        - kwargs: Additional keyword arguments passed to VMobject constructor
        
        Raises:
        - ValueError: If fewer than 2 mobjects are provided
        """

Difference Operations

Subtract one shape from another, creating the remaining area after removal.

class Difference(VMobject):
    def __init__(self, subject: VMobject, clip: VMobject, **kwargs):
        """
        Create the difference between two VMobjects (subject minus clip).
        
        Parameters:
        - subject: The VMobject to subtract from
        - clip: The VMobject to subtract
        - kwargs: Additional keyword arguments passed to VMobject constructor
        """

Intersection Operations

Find the overlapping area where two or more shapes intersect.

class Intersection(VMobject):
    def __init__(self, *vmobjects: VMobject, **kwargs):
        """
        Create the intersection (overlapping area) of two or more VMobjects.
        
        Parameters:
        - vmobjects: Variable number of VMobject instances (minimum 2 required)
        - kwargs: Additional keyword arguments passed to VMobject constructor
        
        Raises:
        - ValueError: If fewer than 2 mobjects are provided
        """

Exclusion Operations

Create the exclusive or (XOR) of shapes, showing areas that belong to exactly one of the input objects.

class Exclusion(VMobject):
    def __init__(self, *vmobjects: VMobject, **kwargs):
        """
        Create the exclusive or (XOR) of two or more VMobjects.
        
        Parameters:
        - vmobjects: Variable number of VMobject instances (minimum 2 required)
        - kwargs: Additional keyword arguments passed to VMobject constructor
        
        Raises:
        - ValueError: If fewer than 2 mobjects are provided
        """

Internal Path Conversion

Low-level functions for converting between ManimGL objects and Skia paths for boolean operations.

def _convert_vmobject_to_skia_path(vmobject: VMobject) -> pathops.Path:
    """
    Convert a ManimGL VMobject to a Skia path for boolean operations.
    
    Parameters:
    - vmobject: VMobject to convert
    
    Returns:
    pathops.Path object for use in boolean operations
    """

def _convert_skia_path_to_vmobject(path: pathops.Path, vmobject: VMobject) -> VMobject:
    """
    Convert a Skia path back to a ManimGL VMobject.
    
    Parameters:
    - path: pathops.Path object from boolean operation
    - vmobject: Template VMobject for style and properties
    
    Returns:
    VMobject with boolean operation result
    """

Usage Examples

Basic Boolean Operations

from manimlib import *

class BooleanBasics(Scene):
    def construct(self):
        # Create base shapes
        circle = Circle(radius=1.5, color=BLUE, fill_opacity=0.5)
        square = Square(side_length=2.5, color=RED, fill_opacity=0.5)
        
        # Position shapes for demonstration
        circle.shift(LEFT * 0.5)
        square.shift(RIGHT * 0.5)
        
        # Show original shapes
        self.play(ShowCreation(circle), ShowCreation(square))
        self.wait()
        
        # Union - combine both shapes
        union_result = Union(circle, square)
        union_result.set_fill(GREEN, opacity=0.7)
        
        self.play(
            Transform(VGroup(circle, square), union_result),
            run_time=2
        )
        self.wait()
        
        # Reset for next operation
        circle = Circle(radius=1.5, color=BLUE, fill_opacity=0.5).shift(LEFT * 0.5)
        square = Square(side_length=2.5, color=RED, fill_opacity=0.5).shift(RIGHT * 0.5)
        
        # Intersection - only overlapping area
        intersection_result = Intersection(circle, square)
        intersection_result.set_fill(PURPLE, opacity=0.8)
        
        self.play(Transform(union_result, VGroup(circle, square)))
        self.wait()
        self.play(Transform(VGroup(circle, square), intersection_result))
        self.wait()

Complex Shape Construction

class ComplexShapes(Scene):
    def construct(self):
        # Create gear shape using boolean operations
        base_circle = Circle(radius=2, fill_opacity=1, color=GREY)
        inner_circle = Circle(radius=0.8, fill_opacity=1, color=BLACK)
        
        # Create gear teeth
        num_teeth = 12
        teeth = VGroup()
        for i in range(num_teeth):
            angle = i * TAU / num_teeth
            tooth = Rectangle(
                width=0.4, height=0.6,
                fill_opacity=1, color=GREY
            )
            tooth.move_to(2.3 * np.array([np.cos(angle), np.sin(angle), 0]))
            tooth.rotate(angle)
            teeth.add(tooth)
        
        # Combine all teeth with base circle
        gear_outline = Union(base_circle, *teeth)
        
        # Subtract inner circle to create hole
        gear = Difference(gear_outline, inner_circle)
        gear.set_fill(YELLOW, opacity=0.8)
        gear.set_stroke(YELLOW_D, width=2)
        
        self.play(ShowCreation(gear), run_time=3)
        
        # Add rotation animation
        self.play(Rotate(gear, TAU, run_time=4, rate_func=linear))

Mathematical Set Visualization

class SetOperations(Scene):
    def construct(self):
        # Create Venn diagram
        set_a = Circle(radius=1.2, color=BLUE, fill_opacity=0.3)
        set_b = Circle(radius=1.2, color=RED, fill_opacity=0.3)
        
        set_a.shift(LEFT * 0.8)
        set_b.shift(RIGHT * 0.8)
        
        # Labels
        label_a = Text("A", font_size=48).move_to(set_a.get_center() + LEFT * 0.5)
        label_b = Text("B", font_size=48).move_to(set_b.get_center() + RIGHT * 0.5)
        
        # Show base sets
        self.add(set_a, set_b, label_a, label_b)
        self.wait()
        
        # Demonstrate each operation
        operations = [
            ("A ∪ B (Union)", Union(set_a, set_b), YELLOW),
            ("A ∩ B (Intersection)", Intersection(set_a, set_b), GREEN),
            ("A - B (Difference)", Difference(set_a, set_b), ORANGE),
            ("A ⊕ B (XOR)", Exclusion(set_a, set_b), PURPLE)
        ]
        
        for title, operation, color in operations:
            result = operation.copy()
            result.set_fill(color, opacity=0.8)
            result.set_stroke(color, width=3)
            
            title_text = Text(title, font_size=36).to_edge(UP)
            
            self.play(
                Write(title_text),
                ShowCreation(result),
                run_time=2
            )
            self.wait(2)
            
            self.play(
                FadeOut(title_text),
                FadeOut(result)
            )

Advanced Shape Analysis

class ShapeAnalysis(Scene):
    def construct(self):
        # Create overlapping shapes for analysis
        triangle = RegularPolygon(3, radius=1.5, color=BLUE, fill_opacity=0.4)
        hexagon = RegularPolygon(6, radius=1.8, color=RED, fill_opacity=0.4)
        circle = Circle(radius=1.2, color=GREEN, fill_opacity=0.4)
        
        triangle.shift(UP * 0.5)
        hexagon.shift(DOWN * 0.3 + LEFT * 0.4)
        circle.shift(DOWN * 0.3 + RIGHT * 0.4)
        
        shapes = VGroup(triangle, hexagon, circle)
        
        self.play(ShowCreation(shapes), run_time=2)
        self.wait()
        
        # Show different combinations
        combinations = [
            # All three shapes union
            ("All Combined", Union(triangle, hexagon, circle), YELLOW),
            # Pairwise intersections
            ("Triangle ∩ Hexagon", Intersection(triangle, hexagon), ORANGE),
            ("Hexagon ∩ Circle", Intersection(hexagon, circle), PURPLE),
            ("Triangle ∩ Circle", Intersection(triangle, circle), PINK),
            # Triple intersection
            ("All Intersect", Intersection(triangle, hexagon, circle), WHITE)
        ]
        
        for title, result, color in combinations:
            analysis = result.copy()
            analysis.set_fill(color, opacity=0.9)
            analysis.set_stroke(color, width=4)
            
            title_text = Text(title, font_size=32).to_edge(UP)
            
            self.play(Write(title_text))
            self.play(
                shapes.animate.set_fill_opacity(0.1),
                ShowCreation(analysis),
                run_time=2
            )
            self.wait(2)
            
            self.play(
                FadeOut(title_text),
                FadeOut(analysis),
                shapes.animate.set_fill_opacity(0.4)
            )
        
        self.wait()

Dynamic Boolean Operations

class DynamicBoolean(Scene):
    def construct(self):
        # Create movable shapes
        circle = Circle(radius=1, color=BLUE, fill_opacity=0.6)
        square = Square(side_length=1.8, color=RED, fill_opacity=0.6)
        
        circle.to_edge(LEFT)
        square.to_edge(RIGHT)
        
        # Create result placeholder
        result_union = Union(circle, square)
        result_union.set_fill(YELLOW, opacity=0.8)
        result_union.move_to(ORIGIN)
        
        self.add(circle, square, result_union)
        
        # Animate shapes moving and show dynamic boolean result
        def update_union(mob):
            new_union = Union(circle, square)
            new_union.set_fill(YELLOW, opacity=0.8)
            new_union.move_to(ORIGIN)
            mob.become(new_union)
        
        result_union.add_updater(update_union)
        
        # Move shapes to show dynamic updating
        self.play(
            circle.animate.shift(RIGHT * 2),
            square.animate.shift(LEFT * 2),
            run_time=4
        )
        
        self.play(
            circle.animate.shift(RIGHT * 1),
            square.animate.shift(LEFT * 1),
            run_time=3
        )
        
        result_union.clear_updaters()
        self.wait()

Implementation Details

Path Conversion Process

Boolean operations work by converting ManimGL VMobjects to Skia paths, performing the geometric operations, and converting back:

  1. VMobject → Skia Path: Extracts Bezier control points and converts cubic curves to quadratic
  2. Boolean Operation: Uses pathops library functions (union, difference, intersection, xor)
  3. Skia Path → VMobject: Reconstructs path commands into VMobject points

Multi-Object Handling

  • Union: Single operation combining all paths simultaneously
  • Intersection & Exclusion: Sequential pairwise operations for multiple objects
  • Difference: Single operation between subject and clip objects

Integration with ManimGL

All boolean operation results are fully-featured VMobjects supporting:

  • Complete styling (stroke, fill, color, opacity)
  • All transformation methods (rotation, scaling, translation)
  • Animation compatibility with all ManimGL animations
  • Point manipulation and curve insertion methods

Performance Considerations

Boolean operations are computationally intensive for complex shapes. For real-time or highly animated scenes, consider:

  • Pre-computing complex boolean results
  • Using simpler approximations for preview
  • Limiting the number of concurrent boolean operations

The boolean operations module provides powerful tools for geometric construction and mathematical visualization, enabling sophisticated shape analysis and complex geometric demonstrations in ManimGL.

Install with Tessl CLI

npx tessl i tessl/pypi-manimgl

docs

3d-objects.md

advanced-animations.md

animation-system.md

boolean-operations.md

coordinate-systems.md

index.md

interactive-controls.md

mathematical-objects.md

matrix-visualization.md

probability-stats.md

scene-framework.md

text-and-latex.md

utilities-and-constants.md

value-tracking.md

vector-fields.md

tile.json