Source code for manim_pymunk.constraints.VGrooveJoint

from typing import Optional
from pymunk.constraints import GrooveJoint

from manim import *
from manim_pymunk.constraints import VConstraint
from pymunk import Space


[docs] class VGrooveJoint(VConstraint): """Initializes a Groove Joint constraint between two Mobjects. A Groove Joint constrains a point on the second body to a line segment (the "groove") on the first body. The groove is defined by two points relative to the first body's center, and the anchor point is relative to the second body's center. Parameters ---------- a_mob The Mobject that contains the groove (the rail/track). b_mob The Mobject that contains the sliding anchor (the slider). groove_a_local The start point of the groove, in `a_mob`'s local coordinates. groove_b_local The end point of the groove, in `a_mob`'s local coordinates. anchor_b_local The anchor point on `b_mob` that slides within the groove, in local coordinates. groove_a_appearance Visual Mobject representing the start of the groove. groove_b_appearance Visual Mobject representing the end of the groove. anchor_b_appearance Visual Mobject representing the sliding anchor on the second body. groove_line_class The Manim class used to draw the groove line (e.g., Line or DashedLine). groove_line_config Configuration dictionary for the styling of the groove line. Examples -------- .. manim:: VGrooveJointExample from manim_pymunk import * class VGrooveJointExample(SpaceScene): def construct(self): static_dot = Dot() square_1 = Square().move_to(static_dot) square_2 = Square().move_to(static_dot.get_center() + RIGHT * 4).scale(0.3) constraints = [ VGrooveJoint( square_1, square_2, groove_a_local=RIGHT * 2, groove_b_local=RIGHT * 4, ), VPinJoint(static_dot, square_1), ] self.add_static_body(static_dot) self.add_dynamic_body(square_1, angular_velocity=PI * 2) self.add_dynamic_body(square_2) self.add_shapes_filter(static_dot, square_1, square_2, group=2) self.add_constraints(*constraints) self.wait(6) """ def __init__( self, a_mob: Mobject, b_mob: Mobject, groove_a_local: list[float, float, float] = RIGHT, groove_b_local: list[float, float, float] = RIGHT * 2, anchor_b_local: list[float, float, float] = ORIGIN, groove_a_appearance: Mobject = Dot(color=RED), groove_b_appearance: Mobject = Dot(color=RED), anchor_b_appearance: Mobject = Dot(color=GREEN), groove_line_class: Optional[Line] = Line, groove_line_config: dict = { "color": YELLOW, "stroke_width": 2, }, **kwargs, ): super().__init__(**kwargs) self.a_mob = a_mob self.b_mob = b_mob self.groove_a_local = groove_a_local self.groove_b_local = groove_b_local self.anchor_b_local = anchor_b_local self.groove_a_appearance = groove_a_appearance self.groove_b_appearance = groove_b_appearance self.anchor_b_appearance = anchor_b_appearance self.groove_line_class = groove_line_class self.groove_line_config = groove_line_config self.groove_line = None self.constraint: Optional[GrooveJoint] = None
[docs] def install(self, space: Space): """Verify the validity of constraint parameters.""" a_body = getattr(self.a_mob, "body", None) b_body = getattr(self.b_mob, "body", None) if not a_body or not b_body: raise ValueError("VGrooveJoint connected objects must have Pymunk bodies.") self.constraint = GrooveJoint( a_body, b_body, tuple(self.groove_a_local[:2]), tuple(self.groove_b_local[:2]), tuple(self.anchor_b_local[:2]), ) groove_a_world = a_body.local_to_world(tuple(self.groove_a_local[:2])) groove_b_world = a_body.local_to_world(tuple(self.groove_b_local[:2])) anchor_b_world = b_body.local_to_world(tuple(self.anchor_b_local[:2])) ga = [groove_a_world.x, groove_a_world.y, 0] gb = [groove_b_world.x, groove_b_world.y, 0] ab = [anchor_b_world.x, anchor_b_world.y, 0] if self.groove_line_class: self.groove_line = self.groove_line_class(ga, gb, **self.groove_line_config) self.add(self.groove_line) self.groove_a_appearance.move_to(ga) self.groove_b_appearance.move_to(gb) self.anchor_b_appearance.move_to(ab) self.add( self.groove_a_appearance, self.groove_b_appearance, self.anchor_b_appearance ) space.add(self.constraint) self.add_updater(self.mob_updater)
[docs] def mob_updater(self, mob, dt): """Visual control updater""" if not self.constraint: return a_body = self.constraint.a b_body = self.constraint.b # 2. Sync initial visual position groove_a_world = a_body.local_to_world(tuple(self.groove_a_local[:2])) groove_b_world = a_body.local_to_world(tuple(self.groove_b_local[:2])) anchor_b_world = b_body.local_to_world(tuple(self.anchor_b_local[:2])) ga = [groove_a_world.x, groove_a_world.y, 0] gb = [groove_b_world.x, groove_b_world.y, 0] ab = [anchor_b_world.x, anchor_b_world.y, 0] self.groove_a_appearance.move_to(ga) self.groove_b_appearance.move_to(gb) self.anchor_b_appearance.move_to(ab) if isinstance(self.groove_line, Line): self.groove_line.put_start_and_end_on(ga, gb)