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