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}" |