File size: 4,239 Bytes
8afc52f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
356f80e
 
 
 
 
 
8949a25
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8afc52f
 
 
 
 
 
8949a25
 
 
 
 
 
 
 
 
 
8afc52f
 
 
 
 
 
 
 
 
62e245c
8afc52f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
654ee06
8afc52f
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import matplotlib.pyplot as plt
import numpy as np
import math as mt

def quad_solver(a, b, c):
    det = b**2 - 4*a*c
    if det < 0:
        raise ValueError("No real roots")
    elif det == 0:
        return -b / (2*a), -b / (2*a)
    else:
        return (-b - mt.sqrt(det)) / (2*a), (-b + mt.sqrt(det)) / (2*a)


def normalize(angle):
    return angle % (2 * mt.pi)

def is_angle_between(angle, start, end):
    angle = normalize(angle)
    start = normalize(start)
    end = normalize(end)
    if start < end:
        return start <= angle <= end
    else:
        return angle >= start or angle <= end


def nonreflecting_plotter(a = 20, b = 20, r = 15, ray_count = 50):
    if a == 0 and b == 0:
        raise ValueError("Circle center cannot be at the origin (0, 0).")

    max_dim = max(abs(a), abs(b), r) * 3
    fig, ax = plt.subplots()
    ax.set_xlim(-max_dim, max_dim)
    ax.set_ylim(-max_dim, max_dim)
    ax.set_aspect('equal', adjustable='box')
    ax.set_xlabel('X-axis')
    ax.set_ylabel('Y-axis')

    ax.axhline(0, color='black', lw=1)
    ax.axvline(0, color='black', lw=1)
    
    circle = plt.Circle((a, b), r, color='blue', fill=False)
    ax.add_artist(circle)

    def draw_line(angle, length=max(max_dim, 500), x_0=0, y_0=0):
        x_1 = length * mt.cos(angle) + x_0
        y_1 = length * mt.sin(angle) + y_0
        return [x_0, x_1], [y_0, y_1]

    def inside_circle_plotter():
        """Function to plot the rays inside the circle"""
        increment = 2 * mt.pi / ray_count

        for angle in np.arange(0, 2 * mt.pi, increment):
            dx = mt.cos(angle)
            dy = mt.sin(angle)

            A = dx**2 + dy**2
            B = -2 * (a * dx + b * dy)
            C = a**2 + b**2 - r**2

            try:
                t1, t2 = quad_solver(A, B, C)

                valid_ts = [t for t in (t1, t2) if t > 0]
                if not valid_ts:
                    continue
                t_hit = min(valid_ts)
                
                x = [0, t_hit * dx]
                y = [0, t_hit * dy]
                ax.plot(x, y, color='orange', lw=1)
            except ValueError:
                continue
    theta_center = mt.atan2(b, a)
    d = mt.hypot(a, b)
    
    try:
        delta = mt.asin(r / d)
    except:
        inside_circle_plotter()
        ax.set_title(f'Rays origin - (0,0). From inside a perfectly absorbing circle\nCenter - ({a},{b}), Radius {r}')
        plt.grid(True)
        plt.show()

        fig.canvas.draw()
        image_array = np.array(fig.canvas.renderer.buffer_rgba())
        plt.close(fig)
        return image_array
        # raise ValueError("Circle radius is too large for the given center coordinates.")
    
    lower_angle = theta_center - delta
    upper_angle = theta_center + delta

    lower_angle = normalize(lower_angle)
    upper_angle = normalize(upper_angle)    

    increment = 2*mt.pi/ray_count

    for angle in np.arange(0, 2 * mt.pi, increment):  # 1° steps
        dx = mt.cos(angle)
        dy = mt.sin(angle)
        if is_angle_between(angle, lower_angle, upper_angle):
            # continue
            A = dx**2 + dy**2
            B = -2 * (a * dx + b * dy)
            C = a**2 + b**2 - r**2
    
            try:
                t1, t2 = quad_solver(A, B, C)
                if abs(t1) < abs(t2):
                    t_hit = t1
                else:
                    t_hit = t2
                # t_hit = min(t1, t2)
                if t_hit < 0:
                    continue  
                x = [0, t_hit * dx]
                y = [0, t_hit * dy]
                ax.plot(x, y, color='orange', lw=1)
            except ValueError:
                continue 
        else:
            x, y = draw_line(angle)
            ax.plot(x, y, color='red', lw=1)

    x1, y1 = draw_line(lower_angle)
    x2, y2 = draw_line(upper_angle)

    ax.plot(x1, y1, color='green', lw=2, linestyle='--')
    ax.plot(x2, y2, color='green', lw=2, linestyle='--')
    
    ax.set_title(f'Rays with shadow from a perfectly absorbing circle\nCenter - ({a},{b}), Radius {r}')
    plt.grid(True)
    plt.show()

    fig.canvas.draw()
    image_array = np.array(fig.canvas.renderer.buffer_rgba())
    plt.close(fig)
    return image_array