Beispiel #1
0
    def viewing_rays(self, screen):

        lower_angle, upper_angle = self.viewing_angles(screen)
        projected_RIGHT = self.project(
            RIGHT) / get_norm(self.project(RIGHT))
        lower_ray = rotate_vector(
            projected_RIGHT, lower_angle, axis=self.projection_direction())
        upper_ray = rotate_vector(
            projected_RIGHT, upper_angle, axis=self.projection_direction())

        return lower_ray, upper_ray
Beispiel #2
0
    def viewing_rays(self, screen):

        lower_angle, upper_angle = self.viewing_angles(screen)
        projected_RIGHT = self.project(
            RIGHT) / get_norm(self.project(RIGHT))
        lower_ray = rotate_vector(
            projected_RIGHT, lower_angle, axis=self.projection_direction())
        upper_ray = rotate_vector(
            projected_RIGHT, upper_angle, axis=self.projection_direction())

        return lower_ray, upper_ray
Beispiel #3
0
def calc_centers_by_radii(r1, r2, r3, init_angle=0):
    if init_angle is None:
        init_angle = TAU * np.random.random_sample()
    r12 = r1 + r2
    r23 = r2 + r3
    r13 = r1 + r3
    cos_theta = (r12**2 + r13**2 - r23**2) / (2 * r12 * r13)
    theta = math.acos(cos_theta)
    p1 = ORIGIN
    p2 = p1 + rotate_vector(RIGHT, init_angle) * r12
    p3 = p1 + rotate_vector(RIGHT * r13, init_angle + theta)
    return p1, p2, p3
Beispiel #4
0
 def get_arc_center(self):
     """
     Looks at the normals to the first two
     anchors, and finds their intersection points
     """
     # First two anchors and handles
     a1, h, a2 = self.get_points()[:3]
     # Tangent vectors
     t1 = h - a1
     t2 = h - a2
     # Normals
     n1 = rotate_vector(t1, TAU / 4)
     n2 = rotate_vector(t2, TAU / 4)
     return find_intersection(a1, n1, a2, n2)
Beispiel #5
0
    def generate_points(self):
        start_angle = np.pi / 2 + self.arc_angle / 2
        end_angle = np.pi / 2 - self.arc_angle / 2
        self.add(Arc(
            start_angle=start_angle,
            angle=-self.arc_angle
        ))
        tick_angle_range = np.linspace(start_angle, end_angle, self.num_ticks)
        for index, angle in enumerate(tick_angle_range):
            vect = rotate_vector(RIGHT, angle)
            tick = Line((1 - self.tick_length) * vect, vect)
            label = TexMobject(str(10 * index))
            label.set_height(self.tick_length)
            label.shift((1 + self.tick_length) * vect)
            self.add(tick, label)

        needle = Polygon(
            LEFT, UP, RIGHT,
            stroke_width=0,
            fill_opacity=1,
            fill_color=self.needle_color
        )
        needle.stretch_to_fit_width(self.needle_width)
        needle.stretch_to_fit_height(self.needle_height)
        needle.rotate(start_angle - np.pi / 2, about_point=ORIGIN)
        self.add(needle)
        self.needle = needle

        self.center_offset = self.get_center()
Beispiel #6
0
    def set_points_by_ends(self, start, end, buff=0, path_arc=0):
        vect = end - start
        dist = get_norm(vect)
        if np.isclose(dist, 0):
            self.set_points_as_corners([start, end])
            return self
        if path_arc:
            neg = path_arc < 0
            if neg:
                path_arc = -path_arc
                start, end = end, start
            radius = (dist / 2) / math.sin(path_arc / 2)
            alpha = (PI - path_arc) / 2
            center = start + radius * normalize(
                rotate_vector(end - start, alpha))

            raw_arc_points = Arc.create_quadratic_bezier_points(
                angle=path_arc - 2 * buff / radius,
                start_angle=angle_of_vector(start - center) + buff / radius,
            )
            if neg:
                raw_arc_points = raw_arc_points[::-1]
            self.set_points(center + radius * raw_arc_points)
        else:
            if buff > 0 and dist > 0:
                start = start + vect * (buff / dist)
                end = end - vect * (buff / dist)
            self.set_points_as_corners([start, end])
        return self
    def add_smooth_curve_to(self, *points):
        """
        If two points are passed in, the first is intepretted
        as a handle, the second as an anchor
        """
        if len(points) == 1:
            handle2 = None
            new_anchor = points[0]
        elif len(points) == 2:
            handle2, new_anchor = points
        else:
            name = sys._getframe(0).f_code.co_name
            raise Exception("Only call {} with 1 or 2 points".format(name))

        if self.has_new_path_started():
            self.add_line_to(new_anchor)
        else:
            self.throw_error_if_no_points()
            last_h2, last_a2 = self.points[-2:]
            last_tangent = (last_a2 - last_h2)
            handle1 = last_a2 + last_tangent
            if handle2 is None:
                to_anchor_vect = new_anchor - last_a2
                new_tangent = rotate_vector(last_tangent,
                                            PI,
                                            axis=to_anchor_vect)
                handle2 = new_anchor - new_tangent
            self.append_points([last_a2, handle1, handle2, new_anchor])
        return self
    def init_points(self):
        start_angle = np.pi / 2 + self.arc_angle / 2
        end_angle = np.pi / 2 - self.arc_angle / 2
        self.add(Arc(start_angle=start_angle, angle=-self.arc_angle))
        tick_angle_range = np.linspace(start_angle, end_angle, self.num_ticks)
        for index, angle in enumerate(tick_angle_range):
            vect = rotate_vector(RIGHT, angle)
            tick = Line((1 - self.tick_length) * vect, vect)
            label = TexMobject(str(10 * index))
            label.set_height(self.tick_length)
            label.shift((1 + self.tick_length) * vect)
            self.add(tick, label)

        needle = Polygon(LEFT,
                         UP,
                         RIGHT,
                         stroke_width=0,
                         fill_opacity=1,
                         fill_color=self.needle_color)
        needle.stretch_to_fit_width(self.needle_width)
        needle.stretch_to_fit_height(self.needle_height)
        needle.rotate(start_angle - np.pi / 2, about_point=ORIGIN)
        self.add(needle)
        self.needle = needle

        self.center_offset = self.get_center()
Beispiel #9
0
    def add_smooth_curve_to(self, *points):
        """
        If two points are passed in, the first is intepretted
        as a handle, the second as an anchor
        """
        if len(points) == 1:
            handle2 = None
            new_anchor = points[0]
        elif len(points) == 2:
            handle2, new_anchor = points
        else:
            name = sys._getframe(0).f_code.co_name
            raise Exception("Only call {} with 1 or 2 points".format(name))

        if self.has_new_path_started():
            self.add_line_to(new_anchor)
        else:
            self.throw_error_if_no_points()
            last_h2, last_a2 = self.points[-2:]
            last_tangent = (last_a2 - last_h2)
            handle1 = last_a2 + last_tangent
            if handle2 is None:
                to_anchor_vect = new_anchor - last_a2
                new_tangent = rotate_vector(
                    last_tangent, PI, axis=to_anchor_vect
                )
                handle2 = new_anchor - new_tangent
            self.append_points([
                last_a2, handle1, handle2, new_anchor
            ])
        return self
    def get_graph_label(self,
                        graph,
                        label="f(x)",
                        x=None,
                        direction=RIGHT,
                        buff=MED_SMALL_BUFF,
                        color=None):
        if isinstance(label, str):
            label = Tex(label)
        if color is None:
            label.match_color(graph)
        if x is None:
            # Searching from the right, find a point
            # whose y value is in bounds
            max_y = FRAME_Y_RADIUS - label.get_height()
            max_x = FRAME_X_RADIUS - label.get_width()
            for x0 in np.arange(*self.x_range)[::-1]:
                pt = self.i2gp(x0, graph)
                if abs(pt[0]) < max_x and abs(pt[1]) < max_y:
                    x = x0
                    break
            if x is None:
                x = self.x_range[1]

        point = self.input_to_graph_point(x, graph)
        angle = self.angle_of_tangent(x, graph)
        normal = rotate_vector(RIGHT, angle + 90 * DEGREES)
        if normal[1] < 0:
            normal *= -1
        label.next_to(point, normal, buff=buff)
        label.shift_onto_screen()
        return label
Beispiel #11
0
 def __init__(self, n=6, **kwargs):
     digest_config(self, kwargs, locals())
     if self.start_angle is None:
         # 0 for odd, 90 for even
         self.start_angle = (n % 2) * 90 * DEGREES
     start_vect = rotate_vector(RIGHT, self.start_angle)
     vertices = compass_directions(n, start_vect)
     super().__init__(*vertices, **kwargs)
Beispiel #12
0
 def __init__(self, n=6, **kwargs):
     digest_config(self, kwargs, locals())
     if self.start_angle is None:
         if n % 2 == 0:
             self.start_angle = 0
         else:
             self.start_angle = 90 * DEGREES
     start_vect = rotate_vector(RIGHT, self.start_angle)
     vertices = compass_directions(n, start_vect)
     Polygon.__init__(self, *vertices, **kwargs)
Beispiel #13
0
 def __init__(self, n=6, **kwargs):
     digest_config(self, kwargs, locals())
     if self.start_angle is None:
         if n % 2 == 0:
             self.start_angle = 0
         else:
             self.start_angle = 90 * DEGREES
     start_vect = rotate_vector(RIGHT, self.start_angle)
     vertices = compass_directions(n, start_vect)
     Polygon.__init__(self, *vertices, **kwargs)
Beispiel #14
0
 def get_arc_center(self):
     """
     Looks at the normals to the first two
     anchors, and finds their intersection points
     """
     # First two anchors and handles
     a1, h1, h2, a2 = self.points[:4]
     # Tangent vectors
     t1 = h1 - a1
     t2 = h2 - a2
     # Normals
     n1 = rotate_vector(t1, TAU / 4)
     n2 = rotate_vector(t2, TAU / 4)
     try:
         return line_intersection(
             line1=(a1, a1 + n1),
             line2=(a2, a2 + n2),
         )
     except Exception:
         warnings.warn("Can't find Arc center, using ORIGIN instead")
         return np.array(ORIGIN)
Beispiel #15
0
 def get_arc_center(self):
     """
     Looks at the normals to the first two
     anchors, and finds their intersection points
     """
     # First two anchors and handles
     a1, h1, h2, a2 = self.points[:4]
     # Tangent vectors
     t1 = h1 - a1
     t2 = h2 - a2
     # Normals
     n1 = rotate_vector(t1, TAU / 4)
     n2 = rotate_vector(t2, TAU / 4)
     try:
         return line_intersection(
             line1=(a1, a1 + n1),
             line2=(a2, a2 + n2),
         )
     except Exception:
         warnings.warn("Can't find Arc center, using ORIGIN instead")
         return np.array(ORIGIN)
Beispiel #16
0
    def __init__(self, n=6, *args, **kwargs):
        self.args_name = \
            ["mobject_or_point", "radius", "start_angle", "element", "normal_vector"]
        self.args = \
            [ORIGIN, 1, None, "point", "OUT"]
        self.mobject_or_point, self.radius, self.start_angle, self.element, self.normal_vector = \
            generate_args(self, args, self.args)
        kwargs = merge_config_kwargs(self, kwargs, self.args_name)

        self.mobject_or_point = Location(self.mobject_or_point)
        if self.element == "point":
            if self.start_angle is None:
                if n % 2 == 0:
                    self.start_angle = 0
                else:
                    self.start_angle = 90 * DEGREES
            start_vect = rotate_vector(self.radius*RIGHT, self.start_angle)
        vertices = np.add(compass_directions(n, start_vect),
                          np.repeat([self.mobject_or_point], n, axis=0))
        GeomPolygon.__init__(self, *vertices, **kwargs)
Beispiel #17
0
 def __init__(self, n=6, **kwargs):
     #### EULERTOUR_INIT_START ####
     if not hasattr(self, "args"):
         self.args = serialize_args([])
     if not hasattr(self, "config"):
         self.config = serialize_config({
             'n': n,
             **kwargs,
         })
     #### EULERTOUR_INIT_START ####
     digest_config(self, kwargs, locals())
     if self.start_angle is None:
         if n % 2 == 0:
             self.start_angle = 0
         else:
             self.start_angle = 90 * DEGREES
     start_vect = rotate_vector(RIGHT, self.start_angle)
     vertices = compass_directions(n, start_vect)
     Polygon.__init__(self, *vertices, **kwargs)
     #### EULERTOUR_INIT_END ####
     register_mobject(self)
Beispiel #18
0
def fractalification_iteration(vmobject,
                               dimension=1.05,
                               num_inserted_anchors_range=list(range(1, 4))):
    num_points = vmobject.get_num_points()
    if num_points > 0:
        # original_anchors = vmobject.get_anchors()
        original_anchors = [
            vmobject.point_from_proportion(x)
            for x in np.linspace(0, 1 - 1. / num_points, num_points)
        ]
        new_anchors = []
        for p1, p2, in zip(original_anchors, original_anchors[1:]):
            num_inserts = random.choice(num_inserted_anchors_range)
            inserted_points = [
                interpolate(p1, p2, alpha)
                for alpha in np.linspace(0, 1, num_inserts + 2)[1:-1]
            ]
            mass_scaling_factor = 1. / (num_inserts + 1)
            length_scaling_factor = mass_scaling_factor**(1. / dimension)
            target_length = get_norm(p1 - p2) * length_scaling_factor
            curr_length = get_norm(p1 - p2) * mass_scaling_factor
            # offset^2 + curr_length^2 = target_length^2
            offset_len = np.sqrt(target_length**2 - curr_length**2)
            unit_vect = (p1 - p2) / get_norm(p1 - p2)
            offset_unit_vect = rotate_vector(unit_vect, np.pi / 2)
            inserted_points = [
                point + u * offset_len * offset_unit_vect
                for u, point in zip(it.cycle([-1, 1]), inserted_points)
            ]
            new_anchors += [p1] + inserted_points
        new_anchors.append(original_anchors[-1])
        vmobject.set_points_as_corners(new_anchors)
    vmobject.set_submobjects([
        fractalification_iteration(submob, dimension,
                                   num_inserted_anchors_range)
        for submob in vmobject.submobjects
    ])
    return vmobject
Beispiel #19
0
def fractalification_iteration(vmobject, dimension=1.05, num_inserted_anchors_range=list(range(1, 4))):
    num_points = vmobject.get_num_points()
    if num_points > 0:
        # original_anchors = vmobject.get_anchors()
        original_anchors = [
            vmobject.point_from_proportion(x)
            for x in np.linspace(0, 1 - 1. / num_points, num_points)
        ]
        new_anchors = []
        for p1, p2, in zip(original_anchors, original_anchors[1:]):
            num_inserts = random.choice(num_inserted_anchors_range)
            inserted_points = [
                interpolate(p1, p2, alpha)
                for alpha in np.linspace(0, 1, num_inserts + 2)[1:-1]
            ]
            mass_scaling_factor = 1. / (num_inserts + 1)
            length_scaling_factor = mass_scaling_factor**(1. / dimension)
            target_length = get_norm(p1 - p2) * length_scaling_factor
            curr_length = get_norm(p1 - p2) * mass_scaling_factor
            # offset^2 + curr_length^2 = target_length^2
            offset_len = np.sqrt(target_length**2 - curr_length**2)
            unit_vect = (p1 - p2) / get_norm(p1 - p2)
            offset_unit_vect = rotate_vector(unit_vect, np.pi / 2)
            inserted_points = [
                point + u * offset_len * offset_unit_vect
                for u, point in zip(it.cycle([-1, 1]), inserted_points)
            ]
            new_anchors += [p1] + inserted_points
        new_anchors.append(original_anchors[-1])
        vmobject.set_points_as_corners(new_anchors)
    vmobject.submobjects = [
        fractalification_iteration(
            submob, dimension, num_inserted_anchors_range)
        for submob in vmobject.submobjects
    ]
    return vmobject
Beispiel #20
0
 def __init__(self, n=3, **kwargs):
     digest_config(self, kwargs, locals())
     start_vect = rotate_vector(RIGHT, self.start_angle)
     vertices = compass_directions(n, start_vect)
     Polygon.__init__(self, *vertices, **kwargs)
 def move_to(self, point_or_mobject):
     vect = rotate_vector(UP + LEFT, self.orientation_line.get_angle())
     self.next_to(point_or_mobject, vect, buff=0)
     return self
Beispiel #22
0
 def move_to(self, point_or_mobject):
     vect = rotate_vector(
         UP + LEFT, self.orientation_line.get_angle()
     )
     self.next_to(point_or_mobject, vect, buff=0)
     return self
Beispiel #23
0
    def set_points_by_ends(self, start, end, buff=0, path_arc=0):
        # Find the right tip length and thickness
        vect = end - start
        length = max(get_norm(vect), 1e-8)
        thickness = self.thickness
        w_ratio = fdiv(self.max_width_to_length_ratio, fdiv(thickness, length))
        if w_ratio < 1:
            thickness *= w_ratio

        tip_width = self.tip_width_ratio * thickness
        tip_length = tip_width / (2 * np.tan(self.tip_angle / 2))
        t_ratio = fdiv(self.max_tip_length_to_length_ratio,
                       fdiv(tip_length, length))
        if t_ratio < 1:
            tip_length *= t_ratio
            tip_width *= t_ratio

        # Find points for the stem
        if path_arc == 0:
            points1 = (length - tip_length) * np.array(
                [RIGHT, 0.5 * RIGHT, ORIGIN])
            points1 += thickness * UP / 2
            points2 = points1[::-1] + thickness * DOWN
        else:
            # Solve for radius so that the tip-to-tail length matches |end - start|
            a = 2 * (1 - np.cos(path_arc))
            b = -2 * tip_length * np.sin(path_arc)
            c = tip_length**2 - length**2
            R = (-b + np.sqrt(b**2 - 4 * a * c)) / (2 * a)

            # Find arc points
            points1 = Arc.create_quadratic_bezier_points(path_arc)
            points2 = np.array(points1[::-1])
            points1 *= (R + thickness / 2)
            points2 *= (R - thickness / 2)
            if path_arc < 0:
                tip_length *= -1
            rot_T = rotation_matrix_transpose(PI / 2 - path_arc, OUT)
            for points in points1, points2:
                points[:] = np.dot(points, rot_T)
                points += R * DOWN

        self.set_points(points1)
        # Tip
        self.add_line_to(tip_width * UP / 2)
        self.add_line_to(tip_length * LEFT)
        self.tip_index = len(self.get_points()) - 1
        self.add_line_to(tip_width * DOWN / 2)
        self.add_line_to(points2[0])
        # Close it out
        self.append_points(points2)
        self.add_line_to(points1[0])

        if length > 0:
            # Final correction
            super().scale(length / self.get_length())

        self.rotate(angle_of_vector(vect) - self.get_angle())
        self.rotate(
            PI / 2 - np.arccos(normalize(vect)[2]),
            axis=rotate_vector(self.get_unit_vector(), -PI / 2),
        )
        self.shift(start - self.get_start())
        self.refresh_triangulation()