简体   繁体   中英

Draw Higher-Order Bezier Curve in Manim

I want to draw a higher-order bezier curve in Manim. A higher-order bezier curve is a bezier curve which has more than 4 control points. I didn't find any way of achieving this...

In Manim there is a CubicBezier class. Unfortunately it only accepts 4 control points. There is also a bezier function. Unfortunately I didn't manage to use that function to help solve this problem.

Solution:

from manim import *
from itertools import cycle

ALL_COLORS = [RED, BLUE, GREEN, TEAL, YELLOW, PURPLE, MAROON, PINK, GOLD]

class Bezier(ParametricFunction):
    def __init__(self, points, **kwargs):
        super().__init__(bezier(points),**kwargs)

class MainScene(Scene):
    def construct(self):
        points = [
            np.array([x, y, 0])
            for x,y in [
                (-5,2),  (-2,2), (-5,-3), (2,3),
                (4,3.2), (6,0), (6,-3),  (0,-1),
            ]
        ]
        bezier_plot = Bezier(points)
        self.c_colors = cycle(ALL_COLORS[:len(points)-2])
        lines, dots = self.get_lines_and_dots_from_points(points)
        init_grp = VGroup(VGroup(lines, dots))
        all_grp = self.get_all_lines(init_grp.copy(), 0)

        self.add(all_grp)
        self.wait()
        self.play(
            UpdateFromAlphaFunc(all_grp,
                lambda mob, alpha: mob.become(
                    self.get_all_lines(init_grp.copy(), alpha)
                )
            ),
            Create(bezier_plot),
            run_time=10, rate_func=linear
        )
        self.wait()

    def get_lines_and_dots_from_points(self, points):
        lines = VGroup(*[
            Line(points[i],points[i+1])
            for i in range(len(points)-1)
        ])
        dots = VGroup(*list(map(Dot,points)))
        return lines, dots

    def get_sub_lines(self, lines, alpha):
        points = [
            l.point_from_proportion(alpha)
            for l in lines
        ]
        new_lines, dots =  self.get_lines_and_dots_from_points(points)
        return VGroup(new_lines, dots).set_color(next(self.c_colors))

    def get_all_lines(self, main_grp, alpha, index=0):
        last_grp = main_grp[-1]
        new_lines = last_grp[0]
        if len(new_lines) >= 2:
            main_grp.add( self.get_sub_lines(new_lines, alpha) )
            return self.get_all_lines(main_grp, alpha, index+1)
        else:
            main_grp.add( Dot(new_lines[0].point_from_proportion(alpha)) )
            return main_grp

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM