from manim import *
import numpy as np

class CircleCenterConstruction(Scene):
    def construct(self):
        # Set up constants for the radii
        r = 2  # Radius of circle \mathcal{C}
        R = 3.3  # Radius of circle \mathcal{C}_1 (must be between r/2 and 2r)

        # Define points and circles
        O = ORIGIN  # Center of circle \mathcal{C}
        A = O + DOWN * r  # Point A on circle \mathcal{C}

        circle_C = Circle(radius=r, color=WHITE)  # Circle \mathcal{C}
        circle_C1 = Circle(radius=R, color=RED).move_to(A)  # Circle \mathcal{C}_1

        # Function to calculate intersection points of two circles
        def circle_intersections(center1, radius1, center2, radius2):
            d = np.linalg.norm(np.array(center2) - np.array(center1))
            if d > radius1 + radius2 or d < abs(radius1 - radius2) or d == 0:
                return None  # No intersection

            a = (radius1**2 - radius2**2 + d**2) / (2 * d)
            h = np.sqrt(radius1**2 - a**2)
            P2 = np.array(center1) + a * (np.array(center2) - np.array(center1)) / d

            x3 = P2[0] + h * (center2[1] - center1[1]) / d
            y3 = P2[1] - h * (center2[0] - center1[0]) / d
            x4 = P2[0] - h * (center2[1] - center1[1]) / d
            y4 = P2[1] + h * (center2[0] - center1[0]) / d

            return [np.array([x3, y3, 0]), np.array([x4, y4, 0])]

        # Calculate intersections of \mathcal{C} and \mathcal{C}_1
        intersections = circle_intersections(O, r, A, R)
        if intersections:
            B, Bp = intersections

            # Draw circle \mathcal{C}
            self.play(Create(circle_C), run_time=2)

            # Show O briefly
            self.play(FadeIn(Dot(O, color=WHITE)), Write(MathTex("O").next_to(O, UP)))
            self.wait(1)
            self.play(FadeOut(Dot(O)), FadeOut(MathTex("O").next_to(O, UP)))

            self.play(FadeIn(Dot(A, color=WHITE)), Write(MathTex("A").next_to(A, DOWN)))

            # Draw circle \mathcal{C}_1
            self.play(Create(circle_C1), run_time=2)

            # Highlight B and B'
            self.play(FadeIn(Dot(B, color=RED)), Write(MathTex("B").next_to(B, RIGHT)))
            self.play(FadeIn(Dot(Bp, color=RED)), Write(MathTex("B'").next_to(Bp, LEFT)))

            # Draw circles \mathcal{C}_2 centered at B and B'
            circle_C2_B = Circle(radius=np.linalg.norm(B - A), color=GREEN).move_to(B)
            circle_C2_Bp = Circle(radius=np.linalg.norm(Bp - A), color=GREEN).move_to(Bp)
            self.play(Create(circle_C2_B), Create(circle_C2_Bp), run_time=2)

            # Calculate intersections of \mathcal{C}_2
            C_points = circle_intersections(B, np.linalg.norm(B - A), Bp, np.linalg.norm(Bp - A))
            if C_points:
                C = C_points[1]  # Select the other intersection for C

                # Highlight point C
                self.play(FadeIn(Dot(C, color=GREEN)), Write(MathTex("C").next_to(C, UP)))

                # Draw circle \mathcal{C}_3 centered at C
                circle_C3 = Circle(radius=np.linalg.norm(C - A), color=PURPLE).move_to(C)
                self.play(Create(circle_C3), run_time=2)

                # Calculate intersections of \mathcal{C}_3 and \mathcal{C}_1
                D_points = circle_intersections(C, np.linalg.norm(C - A), A, R)
                if D_points:
                    D, Dp = D_points

                    # Highlight D and D'
                    self.play(FadeIn(Dot(D, color=PURPLE)), Write(MathTex("D").next_to(D, RIGHT)))
                    self.play(FadeIn(Dot(Dp, color=PURPLE)), Write(MathTex("D'").next_to(Dp, LEFT)))

                    # Draw circles \mathcal{C}_4 centered at D and D'
                    circle_C4_D = Circle(radius=np.linalg.norm(D - A), color=BLUE).move_to(D)
                    circle_C4_Dp = Circle(radius=np.linalg.norm(Dp - A), color=BLUE).move_to(Dp)
                    self.play(Create(circle_C4_D), Create(circle_C4_Dp), run_time=2)

                    # Calculate intersections of \mathcal{C}_4
                    X_points = circle_intersections(D, np.linalg.norm(D - A), Dp, np.linalg.norm(Dp - A))
                    if X_points:
                        X = X_points[1]

                        # Highlight point X
                        self.play(FadeIn(Dot(X, color=BLUE)), Write(MathTex("X").next_to(X, UP)))

                        # Indicate that X coincides with O
                        self.play(Indicate(Dot(O, color=YELLOW)), Indicate(Dot(X, color=YELLOW)))

        else:
            self.play(Write(Text("No intersections found").move_to(ORIGIN)))
