Skip to content

Instantly share code, notes, and snippets.

@uwezi
Last active October 15, 2025 18:22
Show Gist options
  • Save uwezi/dfe01e7e06b1e93af8fd4d5563e1639f to your computer and use it in GitHub Desktop.
Save uwezi/dfe01e7e06b1e93af8fd4d5563e1639f to your computer and use it in GitHub Desktop.
[Line from points] Creating a line from a list of vertices. #manim #line #radius #rounded #tip
from manim import *
import manim.mobject.geometry.tips as tips
class LineFromPoints(Line):
def __init__(self, pointsdirections, radius=0, **kwargs):
super().__init__(**kwargs)
pointsradii = [(pointsdirections[0][0],0)]
for p0,p2 in zip(pointsdirections, pointsdirections[1:]):
if len(p0)==3:
r = p0[2]
else:
r = radius
if len(p0)>1:
if p0[1] == "-|":
p1 = p0[0]*UP + p2[0]*RIGHT
pointsradii.append((p1,r))
elif p0[1] == "|-":
p1 = p0[0]*RIGHT + p2[0]*UP
pointsradii.append((p1,r))
pointsradii.append((p2[0],r))
self.set_points([pointsradii[0][0]])
for p0,p1,p2 in zip(pointsradii,pointsradii[1:],pointsradii[2:]):
hl1 = Line(p0[0],p1[0])
hl2 = Line(p1[0],p2[0])
hl1.scale((hl1.get_length()-p1[1])/hl1.get_length(),about_point=hl1.get_start())
hl2.scale((hl2.get_length()-p1[1])/hl2.get_length(),about_point=hl2.get_end())
self.add_line_to(hl1.get_end())
if r>0:
self.add_cubic_bezier_curve(
hl1.get_end(),
p1[0],
p1[0],
hl2.get_start()
)
self.add_line_to(pointsradii[-1][0])
def add_tip(
line,
shorten=True,
tip_shape: type[tips.ArrowTip] | None = None,
tip_length: float | None = None,
tip_width: float | None = None,
):
tip = line.get_unpositioned_tip(
tip_length=tip_length,
tip_shape = tip_shape,
tip_width = tip_width,
)
tipangle = Line(tip.base, tip.tip_point).get_angle()
angle = Line(line.point_from_proportion(0.999),line.point_from_proportion(1.0)).get_angle()
tip.rotate(angle-tipangle,about_point=tip.base)
tip.shift(line.get_end()-tip.tip_point)
if shorten==True:
points = line.get_all_points()
points[-1]=tip.base
line.set_points(points)
line.add(tip)
return line
class testLineThroughPoints(Scene):
def construct(self):
p1 = Dot([-4,2,0],color=RED)
p2 = Dot([4,-1,0],color=BLUE)
p3 = Dot([6,+3,0],color=YELLOW)
line1 = LineFromPoints(
[
(p1.get_center(),"|-"),
(p2.get_center(),"|-",1.5),
(p3.get_center(),""),
],
radius=0.5
)
line2 = LineFromPoints(
[
(p1.get_center(),"-|"),
(p2.get_center(),"-|"),
(p3.get_center(),""),
],
radius=0.5,
color=GREEN
).add_tip()
line3 = LineFromPoints(
[
(p1.get_center(),""),
(p2.get_center(),""),
(p3.get_center(),""),
],
radius=1,
color=ORANGE
)
self.add(p1,p2,p3)
self.add(line1,line2,line3)

Similar to my other gist LineThroughPoints but now the line is also rounded at the given control points. This behavior is now similar to line drawing and edges in Tikz.

image

The syntax should be rather self-explanatory together with the example.

LineThroughPoints([(p1,""),(p2,""),(p3,"")])

creates a line which goes straight from p1 to p2 to p3, optinally with an arrow tip at the end.

LineThroughPoints([(p1,"-|"),(p2,"")])

creates a line which leaves p1 horizontally until it is right above p2, then it drops vertically to p2.

LineThroughPoints([(p1,"|-"),(p2,"")])

creates a line which leaves p1 vertically until it is on the same height as p2, then it goes horizontally to p2.

The directional argument of the last point doesn't matter.

Additional a global radius= can be defined to round the midway corners between the control points, and/or individual radii can be given to each rectangular midway-corner.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment