Skip to content

Commit c7a1714

Browse files
committed
feat: add Snell's Law refraction angle calculation
1 parent 791deb4 commit c7a1714

1 file changed

Lines changed: 66 additions & 0 deletions

File tree

physics/snells_law.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import math
2+
3+
4+
def calculate_refraction_angle(
5+
index_of_refraction_1: float,
6+
index_of_refraction_2: float,
7+
incident_angle_degrees: float,
8+
) -> float:
9+
"""
10+
Calculates the refraction angle of light passing from one medium to another.
11+
The law states that, for a given pair of media, the ratio of the sines
12+
of angle of incidence and angle of refraction s equal to the refractive
13+
index of the second medium with regard to the first which is equal to the
14+
ratio of the refractive indices of the two media, or equivalently, to the
15+
ratio of the phase velocities in the two media.
16+
17+
18+
Formula: n1 * sin(theta1) = n2 * sin(theta2)
19+
or : (sin(theta1) / sin(theta2)) = (n2 / n1)
20+
Where:
21+
n1 = refractive index of the first medium
22+
n2 = refractive index of the second medium
23+
theta1 = angle of incidence
24+
theta2 = angle of refraction
25+
26+
Note: Total Internal Reflection (TIR) occurs when light travels from a
27+
denser medium to a rarer medium and the incident angle exceeds the
28+
critical angle, making refraction impossible.
29+
30+
Sources:
31+
- https://en.wikipedia.org/wiki/Snell%27s_law
32+
33+
-----------------------------------------------------------------------------
34+
35+
>>> calculate_refraction_angle(1.0, 1.33, 60.0)
36+
40.63
37+
>>> calculate_refraction_angle(2.0, 1.0, 30.0)
38+
90.0
39+
>>> calculate_refraction_angle(1.33, 1.0, 60.0)
40+
Traceback (most recent call last):
41+
...
42+
ValueError: Total Internal Reflection occurred.
43+
>>> calculate_refraction_angle(-1.33, 1.0, 60.0)
44+
Traceback (most recent call last):
45+
...
46+
ValueError: Invalid physical inputs: ratio cannot be less than -1.
47+
48+
"""
49+
50+
incident_angle_radians = math.radians(incident_angle_degrees)
51+
refraction_sine = (index_of_refraction_1 / index_of_refraction_2) * math.sin(
52+
incident_angle_radians
53+
)
54+
55+
if refraction_sine > 1:
56+
raise ValueError("Total Internal Reflection occurred.")
57+
if refraction_sine < -1:
58+
raise ValueError("Invalid physical inputs: ratio cannot be less than -1.")
59+
60+
# If the sine value is approximately 1.0, it's at the critical angle
61+
# We use math.isclose to account for floating-point precision errors
62+
if math.isclose(refraction_sine, 1.0):
63+
return 90.0
64+
65+
refraction_angle = round(math.degrees(math.asin(refraction_sine)), 2)
66+
return refraction_angle

0 commit comments

Comments
 (0)