Beispiel #1
0
    def insert_n_curves_to_point_list(self, n, points):
        nppc = self.n_points_per_curve
        if len(points) == 1:
            return np.repeat(points, nppc * n, 0)

        bezier_groups = self.get_bezier_tuples_from_points(points)
        norms = np.array(
            [get_norm(bg[nppc - 1] - bg[0]) for bg in bezier_groups])
        total_norm = sum(norms)
        # Calculate insertions per curve (ipc)
        if total_norm < 1e-6:
            ipc = [n] + [0] * (len(bezier_groups) - 1)
        else:
            ipc = np.round(n * norms / sum(norms)).astype(int)

        diff = n - sum(ipc)
        for x in range(diff):
            ipc[np.argmin(ipc)] += 1
        for x in range(-diff):
            ipc[np.argmax(ipc)] -= 1

        new_points = []
        for group, n_inserts in zip(bezier_groups, ipc):
            # What was once a single quadratic curve defined
            # by "group" will now be broken into n_inserts + 1
            # smaller quadratic curves
            alphas = np.linspace(0, 1, n_inserts + 2)
            for a1, a2 in zip(alphas, alphas[1:]):
                new_points += partial_quadratic_bezier_points(group, a1, a2)
        return np.vstack(new_points)
Beispiel #2
0
    def pointwise_become_partial(self, vmobject, a, b):
        assert isinstance(vmobject, VMobject)
        if a <= 0 and b >= 1:
            self.become(vmobject)
            return self
        num_curves = vmobject.get_num_curves()
        nppc = self.n_points_per_curve

        # Partial curve includes three portions:
        # - A middle section, which matches the curve exactly
        # - A start, which is some ending portion of an inner quadratic
        # - An end, which is the starting portion of a later inner quadratic

        lower_index, lower_residue = integer_interpolate(0, num_curves, a)
        upper_index, upper_residue = integer_interpolate(0, num_curves, b)
        i1 = nppc * lower_index
        i2 = nppc * (lower_index + 1)
        i3 = nppc * upper_index
        i4 = nppc * (upper_index + 1)

        vm_points = vmobject.get_points()
        new_points = vm_points.copy()
        if num_curves == 0:
            new_points[:] = 0
            return self
        if lower_index == upper_index:
            tup = partial_quadratic_bezier_points(
                vm_points[i1:i2], lower_residue, upper_residue
            )
            new_points[:i1] = tup[0]
            new_points[i1:i4] = tup
            new_points[i4:] = tup[2]
            new_points[nppc:] = new_points[nppc - 1]
        else:
            low_tup = partial_quadratic_bezier_points(
                vm_points[i1:i2], lower_residue, 1
            )
            high_tup = partial_quadratic_bezier_points(
                vm_points[i3:i4], 0, upper_residue
            )
            new_points[0:i1] = low_tup[0]
            new_points[i1:i2] = low_tup
            # Keep new_points i2:i3 as they are
            new_points[i3:i4] = high_tup
            new_points[i4:] = high_tup[2]
        self.set_points(new_points)
        return self
Beispiel #3
0
 def subdivide_sharp_curves(self, angle_threshold=30 * DEGREES, recurse=True):
     vmobs = [vm for vm in self.get_family(recurse) if vm.has_points()]
     for vmob in vmobs:
         new_points = []
         for tup in vmob.get_bezier_tuples():
             angle = angle_between_vectors(tup[1] - tup[0], tup[2] - tup[1])
             if angle > angle_threshold:
                 n = int(np.ceil(angle / angle_threshold))
                 alphas = np.linspace(0, 1, n + 1)
                 new_points.extend([
                     partial_quadratic_bezier_points(tup, a1, a2)
                     for a1, a2 in zip(alphas, alphas[1:])
                 ])
             else:
                 new_points.append(tup)
         vmob.set_points(np.vstack(new_points))
     return self