def from_three_points( p1: Sequence[float], p2: Sequence[float], p3: Sequence[float], **kwargs ): """Returns a circle passing through the specified three points. Example ------- .. manim:: CircleFromPointsExample :save_last_frame: class CircleFromPointsExample(Scene): def construct(self): circle = Circle.from_three_points(LEFT, LEFT + UP, UP * 2, color=RED) dots = VGroup( Dot(LEFT), Dot(LEFT + UP), Dot(UP * 2), ) self.add(NumberPlane(), circle, dots) """ center = line_intersection( perpendicular_bisector([p1, p2]), perpendicular_bisector([p2, p3]), ) radius = np.linalg.norm(p1 - center) return Circle(radius=radius, **kwargs).shift(center)
def get_arc_center(self, warning=True): """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] if np.all(a1 == a2): # For a1 and a2 to lie at the same point arc radius # must be zero. Thus arc_center will also lie at # that point. return a1 # 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: if warning: warnings.warn("Can't find Arc center, using ORIGIN instead") self._failed_to_get_center = True return np.array(ORIGIN)
def __init__( self, line1: Line, line2: Line, radius: float = None, quadrant=(1, 1), other_angle: bool = False, dot=False, dot_radius=None, dot_distance=0.55, dot_color=WHITE, elbow=False, **kwargs, ): super().__init__(**kwargs) self.lines = (line1, line2) self.quadrant = quadrant self.dot_distance = dot_distance self.elbow = elbow inter = line_intersection( [line1.get_start(), line1.get_end()], [line2.get_start(), line2.get_end()], ) if radius is None: if quadrant[0] == 1: dist_1 = np.linalg.norm(line1.get_end() - inter) else: dist_1 = np.linalg.norm(line1.get_start() - inter) if quadrant[1] == 1: dist_2 = np.linalg.norm(line2.get_end() - inter) else: dist_2 = np.linalg.norm(line2.get_start() - inter) if np.minimum(dist_1, dist_2) < 0.6: radius = (2 / 3) * np.minimum(dist_1, dist_2) else: radius = 0.4 else: self.radius = radius anchor_angle_1 = inter + quadrant[0] * radius * line1.get_unit_vector() anchor_angle_2 = inter + quadrant[1] * radius * line2.get_unit_vector() if elbow: anchor_middle = (inter + quadrant[0] * radius * line1.get_unit_vector() + quadrant[1] * radius * line2.get_unit_vector()) angle_mobject = Elbow(**kwargs) angle_mobject.set_points_as_corners( [anchor_angle_1, anchor_middle, anchor_angle_2], ) else: angle_1 = angle_of_vector(anchor_angle_1 - inter) angle_2 = angle_of_vector(anchor_angle_2 - inter) if not other_angle: start_angle = angle_1 if angle_2 > angle_1: angle_fin = angle_2 - angle_1 else: angle_fin = 2 * np.pi - (angle_1 - angle_2) else: start_angle = angle_1 if angle_2 < angle_1: angle_fin = -angle_1 + angle_2 else: angle_fin = -2 * np.pi + (angle_2 - angle_1) self.angle_value = angle_fin angle_mobject = Arc( radius=radius, angle=self.angle_value, start_angle=start_angle, arc_center=inter, **kwargs, ) if dot: if dot_radius is None: dot_radius = radius / 10 else: self.dot_radius = dot_radius right_dot = Dot(ORIGIN, radius=dot_radius, color=dot_color) dot_anchor = ( inter + (angle_mobject.get_center() - inter) / np.linalg.norm(angle_mobject.get_center() - inter) * radius * dot_distance) right_dot.move_to(dot_anchor) self.add(right_dot) self.set_points(angle_mobject.points)