def point_to_number(self, point: Sequence[float]) -> float: """Accepts a point with respect to the scene and returns a float along the number line. Parameters ---------- point A sequence of values consisting of ``(x_coord, y_coord, z_coord)``. Returns ------- float A float representing a value along the number line. Examples -------- >>> from manim import NumberLine >>> number_line = NumberLine() >>> number_line.point_to_number((0,0,0)) 0.0 >>> number_line.point_to_number((1,0,0)) 1.0 >>> number_line.point_to_number([[0.5,0,0],[1,0,0],[1.5,0,0]]) array([0.5, 1. , 1.5]) """ point = np.asarray(point) start, end = self.get_start_and_end() unit_vect = normalize(end - start) proportion = np.dot(point - start, unit_vect) / np.dot( end - start, unit_vect) return interpolate(self.x_min, self.x_max, proportion)
def parallel_to( cls, line: Line3D, point: Sequence[float] = ORIGIN, length: float = 5, **kwargs ): """Returns a line parallel to another line going through a given point. Parameters ---------- line The line to be parallel to. point The point to pass through. kwargs Additional parameters to be passed to the class. Examples -------- .. manim:: ParallelLineExample :save_last_frame: class ParallelLineExample(ThreeDScene): def construct(self): self.set_camera_orientation(PI / 3, -PI / 4) ax = ThreeDAxes((-5, 5), (-5, 5), (-5, 5), 10, 10, 10) line1 = Line3D(RIGHT * 2, UP + OUT, color=RED) line2 = Line3D.parallel_to(line1, color=YELLOW) self.add(ax, line1, line2) """ point = np.array(point) vect = normalize(line.vect) return cls( point + vect * length / 2, point - vect * length / 2, **kwargs, )
def _set_start_and_end_attrs(self, start, end): # If either start or end are Mobjects, this # gives their centers rough_start = self._pointify(start) rough_end = self._pointify(end) vect = normalize(rough_end - rough_start) # Now that we know the direction between them, # we can find the appropriate boundary point from # start and end, if they're mobjects self.start = self._pointify(start, vect) self.end = self._pointify(end, -vect)
def get_normal_vector(self) -> np.ndarray: """Returns the normal of a vector. Examples -------- :: >>> np.round(Arrow().get_normal_vector()) + 0. # add 0. to avoid negative 0 in output array([ 0., 0., -1.]) """ p0, p1, p2 = self.tip.get_start_anchors()[:3] return normalize(np.cross(p2 - p1, p1 - p0))
def get_projection(self, point: Sequence[float]) -> Sequence[float]: """Returns the projection of a point onto a line. Parameters ---------- point The point to which the line is projected. """ start = self.get_start() end = self.get_end() unit_vect = normalize(end - start) return start + np.dot(point - start, unit_vect) * unit_vect
def point_to_number(self, point: Sequence[float]) -> float: """Accepts a point with respect to the scene and returns a float along the number line. Parameters ---------- point A sequence of values consisting of ``(x_coord, y_coord, z_coord)``. Returns ------- float A float representing a value along the number line. """ start, end = self.get_start_and_end() unit_vect = normalize(end - start) proportion = np.dot(point - start, unit_vect) / np.dot( end - start, unit_vect) return interpolate(self.x_min, self.x_max, proportion)
def perpendicular_to( cls, line: Line3D, point: Sequence[float] = ORIGIN, length: float = 5, **kwargs ): """Returns a line perpendicular to another line going through a given point. Parameters ---------- line The line to be perpendicular to. point The point to pass through. kwargs Additional parameters to be passed to the class. Examples -------- .. manim:: PerpLineExample :save_last_frame: class PerpLineExample(ThreeDScene): def construct(self): self.set_camera_orientation(PI / 3, -PI / 4) ax = ThreeDAxes((-5, 5), (-5, 5), (-5, 5), 10, 10, 10) line1 = Line3D(RIGHT * 2, UP + OUT, color=RED) line2 = Line3D.perpendicular_to(line1, color=BLUE) self.add(ax, line1, line2) """ point = np.array(point) norm = np.cross(line.vect, point - line.start) if all(np.linalg.norm(norm) == np.zeros(3)): raise ValueError("Could not find the perpendicular.") start, end = perpendicular_bisector([line.start, line.end], norm) vect = normalize(end - start) return cls( point + vect * length / 2, point - vect * length / 2, **kwargs, )
def set_start_and_end_attrs(self, start, end, **kwargs): """Sets the start and end points of the line. If either ``start`` or ``end`` are :class:`Mobjects <.Mobject>`, this gives their centers. """ rough_start = self.pointify(start) rough_end = self.pointify(end) self.vect = rough_end - rough_start self.length = np.linalg.norm(self.vect) self.direction = normalize(self.vect) # Now that we know the direction between them, # we can the appropriate boundary point from # start and end, if they're mobjects self.start = self.pointify(start, self.direction) self.end = self.pointify(end, -self.direction) super().__init__( height=np.linalg.norm(self.vect), radius=self.thickness, direction=self.direction, **kwargs, ) self.shift((self.start + self.end) / 2)
def get_unit_vector(self): return normalize(self.get_vector())
def round_corners(self, radius: float = 0.5): """Rounds off the corners of the :class:`Polygram`. Parameters ---------- radius The curvature of the corners of the :class:`Polygram`. .. seealso:: :class:`.~RoundedRectangle` Examples -------- .. manim:: PolygramRoundCorners :save_last_frame: class PolygramRoundCorners(Scene): def construct(self): star = Star(outer_radius=2) shapes = VGroup(star) shapes.add(star.copy().round_corners(radius=0.1)) shapes.add(star.copy().round_corners(radius=0.25)) shapes.arrange(RIGHT) self.add(shapes) """ if radius == 0: return self new_points = [] for vertices in self.get_vertex_groups(): arcs = [] for v1, v2, v3 in adjacent_n_tuples(vertices, 3): vect1 = v2 - v1 vect2 = v3 - v2 unit_vect1 = normalize(vect1) unit_vect2 = normalize(vect2) angle = angle_between_vectors(vect1, vect2) # Negative radius gives concave curves angle *= np.sign(radius) # Distance between vertex and start of the arc cut_off_length = radius * np.tan(angle / 2) # Determines counterclockwise vs. clockwise sign = np.sign(np.cross(vect1, vect2)[2]) arc = ArcBetweenPoints( v2 - unit_vect1 * cut_off_length, v2 + unit_vect2 * cut_off_length, angle=sign * angle, ) arcs.append(arc) # To ensure that we loop through starting with last arcs = [arcs[-1], *arcs[:-1]] from manim.mobject.geometry.line import Line for arc1, arc2 in adjacent_pairs(arcs): new_points.extend(arc1.points) line = Line(arc1.get_end(), arc2.get_start()) # Make sure anchors are evenly distributed len_ratio = line.get_length() / arc1.get_arc_length() line.insert_n_curves(int(arc1.get_num_curves() * len_ratio)) new_points.extend(line.points) self.set_points(new_points) return self