File size: 3,514 Bytes
e08e802 c5ce868 e08e802 8c4cb15 e08e802 654ee06 dc9063e e08e802 |
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 |
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 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):
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')
circle = plt.Circle((a, b), r, color='black', fill=False)
ax.add_artist(circle)
theta_center = mt.atan2(b, a)
d = mt.hypot(a, b)
try:
delta = mt.asin(r / d)
except:
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
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):
plot_reflection_on_circle(ax, angle, center=(a, b), radius=r)
else:
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)
return image_array |