File size: 5,167 Bytes
e08e802 64b00ed e08e802 adc8d2e e08e802 66b2203 e08e802 adc8d2e e08e802 64b00ed e08e802 64b00ed cc6e945 64b00ed cc6e945 64b00ed e08e802 8c4cb15 cc6e945 e08e802 64b00ed e08e802 cc6e945 e08e802 adc8d2e e08e802 cc6e945 dc9063e e08e802 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 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
import matplotlib.pyplot as plt
import numpy as np
import math as mt
def reflect_vector(v, n):
n = n / np.linalg.norm(n)
return v - 2 * np.dot(v, n) * n
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 plot_reflection_on_circle(ax, angle, center, radius, ray_length=50, color='blue'):
a, b = center
origin = np.array([0, 0])
dx = np.cos(angle)
dy = np.sin(angle)
A = dx**2 + dy**2
B = -2 * (a * dx + b * dy)
C = a**2 + b**2 - radius**2
roots = np.roots([A, B, C])
ts = [t for t in roots if t > 0]
if not ts:
print(f"No intersection at angle {angle}")
return
t_hit = min(ts)
x_hit = t_hit * dx
y_hit = t_hit * dy
hit_point = np.array([x_hit, y_hit])
ax.plot([0, x_hit], [0, y_hit], color='blue', lw=1, zorder=10) # This is the incident ray
normal_vector = hit_point - np.array([a, b]) #Normal at point of reflection
# ax.plot([a, x_hit], [b, y_hit], color='green', lw=1)
# Reflection, this is key
incident_vector = hit_point - origin
reflected_vector = reflect_vector(incident_vector, normal_vector)
reflected_unit = 1000* reflected_vector / np.linalg.norm(reflected_vector)
ax.arrow(x_hit, y_hit,
reflected_unit[0] * ray_length,
reflected_unit[1] * ray_length,
head_width=1.8, head_length=1.5,
fc=color, ec=color, zorder=10)
return incident_vector, reflected_vector
def reflecting_plotter(a = 20, b = 20, r = 15, ray_count = 15, 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='black', fill=False)
ax.add_artist(circle)
ax.plot(a, b, 'ro', markersize=5)
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 reflective 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
def normalize(angle):
return angle % (2 * mt.pi)
lower_angle = normalize(lower_angle)
upper_angle = normalize(upper_angle)
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
# Function to generate a line from origin at a given angle
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]
increment = 2*mt.pi/ray_count
total_hits = 0
for angle in np.arange(0, 2 * np.pi, increment):
# dx = mt.cos(angle)
# dy = mt.sin(angle)
if is_angle_between(angle, lower_angle, upper_angle):
total_hits += 1
plot_reflection_on_circle(ax, angle, center=(a, b), radius=r)
else:
if clutter == "No":
x, y = draw_line(angle)
ax.plot(x, y, color='red', lw=1, zorder=5)
# plot_reflection_on_circle(ax, angle, center=(a, b), radius=r)
ax.set_title(f'Rays with shadow from a perfectly reflective 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 = 100*total_hits / ray_count
return image_array, f"{hit_ratio:.5f}" |