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