File size: 4,371 Bytes
8afc52f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
adc8d2e
8afc52f
 
 
 
 
 
 
 
 
 
 
 
 
 
66b2203
356f80e
 
 
 
 
 
8949a25
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8afc52f
 
 
 
 
 
8949a25
cc6e945
8949a25
 
 
 
 
 
66b2203
8949a25
8afc52f
 
 
 
 
 
 
 
cc6e945
62e245c
8afc52f
 
adc8d2e
cc6e945
8afc52f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
adc8d2e
 
8afc52f
 
 
 
 
 
 
 
 
cc6e945
8afc52f
 
 
 
 
 
cc6e945
66b2203
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
142
143
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, clutter = "No"):

    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)
    ax.plot(a, b, 'ro', markersize=5)  # Circle center

    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, 100
        # 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
    total_hits = 0
    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):            
            total_hits += 1
            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:
            if clutter == "Yes":
                continue
            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)
    hit_ratio = (total_hits / ray_count) * 100
    return image_array, f"{hit_ratio:.5f}"