Refraction of Light
Physics
Code
= {
chart const margin = { top: 20, right: 10, bottom: 20, left: 10 };
const width = fullWidth - margin.left - margin.right,
= fullHeight - margin.top - margin.bottom;
height
const window = d3.create("svg")
.attr("width", "100%")
.attr("height", "100%")
.attr("viewBox", `0 0 ${fullWidth} ${fullHeight}`)
.attr("preserveAspectRatio", "xMidYMid meet");
const svg = window.append("g")
.attr("class", "refrac")
.attr("transform", `translate(${margin.left},${margin.top})`);
const line = d3.line();
let state = {
_n: defaults.n,
_a: defaults.a,
_pol: defaults.pol,
get n() {
return this._n;
,
}set n(x) {
this._n = x;
this.update();
,
}get a() {
return this._a;
,
}set a(x) {
this._a = x;
this.update();
,
}get pol() {
return this._pol;
,
}set pol(x) {
this._pol = x;
this.update();
,
}get aT() {
return Math.asin(this.n);
,
}get aB() {
return Math.atan(this.n);
,
}update: function() {
this.b = Math.asin(Math.sin(this.a) / this.n);
// Snell's Law
this.deflection = {
t: this.a - this.b,
r: Math.PI + 2 * this.a
;
}
// Fresnel's Equations
this.intensity = {
s: {
t: Math.pow(2 * Math.cos(this.a)
/ (Math.cos(this.a) + this.n * Math.cos(this.b)), 2),
r: Math.pow((Math.cos(this.a) - this.n * Math.cos(this.b))
/ (Math.cos(this.a) + this.n * Math.cos(this.b)), 2),
,
}p: {
t: Math.pow(2 * Math.cos(this.a)
/ (Math.cos(this.b) + this.n * Math.cos(this.a)), 2),
r: Math.pow((this.n * Math.cos(this.a) - Math.cos(this.b))
/ (Math.cos(this.b) + this.n * Math.cos(this.a)), 2),
};
}
};
}
// set up defaults
.update();
state
const radius = width / 2,
= [0, height / 2],
origin = [origin[0] + radius, origin[1]];
pivot
.selectAll(".ray")
svg.data([[origin], [pivot], [pivot]])
.join("path")
.attr("class", (d, i) => `ray ray${i}`);
.append("path")
svg.attr("class", "surface");
function updateData() {
// input ray
.select(".ray0").datum([origin, pivot]);
svg
// transmitted ray
if (state.n < 1 && Math.abs(state.a) >= state.aT) {
.intensity[state.pol].r = 1; // could be Nan
state.select(".ray1").datum([pivot]);
svgelse {
} .select(".ray1").datum([pivot, [
svg0] + radius * Math.cos(state.deflection.t),
pivot[1] + radius * Math.sin(state.deflection.t),
pivot[;
]])
}
// reflected ray
.select(".ray2").datum([pivot, [
svg0] + radius * Math.cos(state.deflection.r),
pivot[1] + radius * Math.sin(state.deflection.r),
pivot[;
]])
}
function updateChart() {
.select(".surface")
svg.attr("d", line([
[* Math.sin(state.a) + pivot[0],
radius -radius * Math.cos(state.a) + pivot[1],
, [
]-radius * Math.sin(state.a) + pivot[0],
* Math.cos(state.a) + pivot[1],
radius ,
];
]))
// input ray
.select(".ray0")
svg.attr("d", line)
.attr("opacity", 1);
// transmitted ray
.select(".ray1")
svg.attr("d", line)
.attr("opacity", state.intensity[state.pol].t);
// reflected ray
.select(".ray2")
svg.attr("d", line)
.attr("opacity", state.intensity[state.pol].r);
setInputDisabled(viewof _onTotal, state.n >= 1);
setInputDisabled(viewof _onZero, state.pol == "s");
}
function updateAll() {
updateData();
updateChart();
}
.then(() => {
invalidation.selectAll("*").interrupt();
svg;
})
function rotationTween(a) {
return function() {
const interpolate = d3.interpolateNumber(state.a, a);
return function(t) {
.a = interpolate(t);
stateupdateAll();
setInputValue(viewof _a, state.a);
;
}
}
}
return Object.assign(window.node(), {
update(values) {
.a = values.a;
state.n = values.n;
state.pol = values.pol;
stateupdateAll();
,
}setTotal(value) {
if (value > 0) {
.transition()
svg.duration(500)
.tween("rotate", rotationTween(state.aT));
},
}setZero(value) {
if (value > 0) {
.transition()
svg.duration(500)
.tween("rotate", rotationTween(state.aB));
},
};
}) }
This interactive visualization demonstrates the reflection and refraction of a light beam at the interface of a medium, as described by Snell’s law and Fresnel’s equations. Depending on the value of the refractive index and the polarization, the incoming beam can be fully reflected or fully refracted.