I'm very new to manim! As such I hope my question is not inappropriate. I have a line mobject and I would like to create a shape of specific size around, a so called 'buffer'. In the image you see a blue line, and the shape around it is what I like to create. Is there some method which creates this sort of shape for line objects?
I really did try to find something by myself, but maybe I just don't use the correct wording in my search.
Is there some method in the library which does this?
I'm very sorry if my question is too broad or just in other ways not appropriate. I just started to learn manim!
UPDATE I tried to accomplish this task by setting the stroke_width to a very high level. However, the ends are not round but sharp.
This is the code for it:
class CreateLineWithBuffer(Scene):
def construct(self):
street=Line(color=PINK).rotate(angle=45)
street.scale(8)
line = Line(stroke_width=50, stroke_opacity=0.5).rotate(angle=45)
line.scale(8)
self.play(Create(street), run_time=3)
self.play(Create(line), run_time=3)
self.wait()
Here is a possible solution. Note that the code can definitely be optimized/refactored, and I didn't test it that much (so bugs are included ;) ). But you can use that as a starting point.
from manim import *
import math
import numpy as np
from manim.typing import Point3D
def interpolate(
start: int | float | Point3D, end: int | float | Point3D, alpha: float | Point3D
) -> float | Point3D:
return (1 - alpha) * start + alpha * end
class BigLine(VMobject):
def __init__(
self,
start: Point3D = LEFT,
end: Point3D = RIGHT,
buff: float = 0.2,
**kwargs,
) -> None:
self.start = start
self.end = end
self.buff = buff
super().__init__(**kwargs)
def generate_points(self) -> None:
points = []
start_point_pos_normal = self.start + self.buff * self.calc_normal(
self.start, self.end
)
start_point_neg_normal = self.start - self.buff * self.calc_normal(
self.start, self.end
)
end_point_pos_normal = self.end + self.buff * self.calc_normal(
self.start, self.end
)
end_point_neg_normal = self.end - self.buff * self.calc_normal(
self.start, self.end
)
first_arc = ArcBetweenPoints(
end_point_pos_normal, end_point_neg_normal, angle=-TAU / 2
)
second_arc = ArcBetweenPoints(
start_point_neg_normal, start_point_pos_normal, angle=-TAU / 2
)
nppcc = self.n_points_per_cubic_curve
points.extend(
interpolate(start_point_pos_normal, end_point_pos_normal, a)
for a in np.linspace(0, 1, nppcc)
)
points.extend(first_arc.points)
points.extend(
interpolate(end_point_neg_normal, start_point_neg_normal, a)
for a in np.linspace(0, 1, nppcc)
)
points.extend(second_arc.points)
points.append(start_point_pos_normal)
self.set_points(points)
def calc_normal(self, first, second) -> Point3D:
dx = second[0] - first[0]
dy = second[1] - first[1]
normal_vec = np.array([-dy, dx, 0])
return normal_vec/np.linalg.norm(normal_vec)
class LineWidth(Scene):
def construct(self):
line = Line(2 * UL, 2 * DR, stroke_width=3)
big_line = BigLine(2 * UL, 2 * DR, buff=1, fill_color=RED, fill_opacity=0.3)
self.add(line, big_line)
self.wait(3)