fix(opticsbench): починка физики призмы — луч теперь правильно входит и преломляется
PrismSim был сломан в 3 местах: 1. incDir строился с -efNorm (наружу), а не efNorm (внутрь) → падающий луч рисовался не с той стороны 2. cosI = -(incDir·efNorm) с уже-перевёрнутым incDir давал противоречивые знаки 3. Формула Снелла rDir имела + вместо - на коэффициенте efNorm Итог: при incAngle≈0 преломлённый луч уходил в обратную сторону, точка пересечения с выходной гранью не находилась (tRay<0), и наружный луч с дисперсией не отрисовывался → визуально 'призма не работает'. Теперь incDir — направление распространения (внутрь призмы), cosI = +(incDir·efNorm), формула: r = (1/n)·l + (cosR − cosI/n)·n
This commit is contained in:
@@ -2616,14 +2616,16 @@ class PrismSim {
|
|||||||
const eX = (v[0].x + v[2].x) / 2, eY = (v[0].y + v[2].y) / 2;
|
const eX = (v[0].x + v[2].x) / 2, eY = (v[0].y + v[2].y) / 2;
|
||||||
const tangDir = { x: efVec.x / efLen, y: efVec.y / efLen };
|
const tangDir = { x: efVec.x / efLen, y: efVec.y / efLen };
|
||||||
const incRad = this.incAngle * Math.PI / 180;
|
const incRad = this.incAngle * Math.PI / 180;
|
||||||
|
/* incDir = propagation direction (INTO the prism) */
|
||||||
const incDir = {
|
const incDir = {
|
||||||
x: Math.cos(incRad) * (-efNorm.x) + Math.sin(incRad) * tangDir.x,
|
x: Math.cos(incRad) * efNorm.x + Math.sin(incRad) * tangDir.x,
|
||||||
y: Math.cos(incRad) * (-efNorm.y) + Math.sin(incRad) * tangDir.y,
|
y: Math.cos(incRad) * efNorm.y + Math.sin(incRad) * tangDir.y,
|
||||||
};
|
};
|
||||||
const incDLen = Math.hypot(incDir.x, incDir.y);
|
const incDLen = Math.hypot(incDir.x, incDir.y);
|
||||||
incDir.x /= incDLen; incDir.y /= incDLen;
|
incDir.x /= incDLen; incDir.y /= incDLen;
|
||||||
|
|
||||||
const rayLen = W * 0.45;
|
const rayLen = W * 0.45;
|
||||||
|
/* draw incoming ray from outside (source side) to entry midpoint */
|
||||||
this._drawRayLine(ctx, eX - incDir.x * rayLen, eY - incDir.y * rayLen, eX, eY,
|
this._drawRayLine(ctx, eX - incDir.x * rayLen, eY - incDir.y * rayLen, eX, eY,
|
||||||
isWhite ? '#FFFFFF' : wavelengthToRGB(monoNm), 2.5);
|
isWhite ? '#FFFFFF' : wavelengthToRGB(monoNm), 2.5);
|
||||||
|
|
||||||
@@ -2639,13 +2641,15 @@ class PrismSim {
|
|||||||
for (const s of spectral) {
|
for (const s of spectral) {
|
||||||
const nP = _nAtWavelength(this.n0, s.nm);
|
const nP = _nAtWavelength(this.n0, s.nm);
|
||||||
const col = wavelengthToRGB(s.nm);
|
const col = wavelengthToRGB(s.nm);
|
||||||
const cosI = -(incDir.x * efNorm.x + incDir.y * efNorm.y);
|
/* Snell vector form: l = incDir (propagation), n = -efNorm (toward incident medium)
|
||||||
|
cosθ_i = -n·l = efNorm·l; r = μl + (μcosθ_i - cosθ_t)·n */
|
||||||
|
const cosI = (incDir.x * efNorm.x + incDir.y * efNorm.y);
|
||||||
const sinR = Math.sqrt(Math.max(0, 1 - cosI * cosI)) / nP;
|
const sinR = Math.sqrt(Math.max(0, 1 - cosI * cosI)) / nP;
|
||||||
if (sinR > 1) continue;
|
if (sinR > 1) continue;
|
||||||
const cosR = Math.sqrt(1 - sinR * sinR);
|
const cosR = Math.sqrt(1 - sinR * sinR);
|
||||||
const rDir = {
|
const rDir = {
|
||||||
x: (1/nP) * incDir.x + ((1/nP) * cosI - cosR) * efNorm.x,
|
x: (1/nP) * incDir.x + (cosR - (1/nP) * cosI) * efNorm.x,
|
||||||
y: (1/nP) * incDir.y + ((1/nP) * cosI - cosR) * efNorm.y,
|
y: (1/nP) * incDir.y + (cosR - (1/nP) * cosI) * efNorm.y,
|
||||||
};
|
};
|
||||||
const rDLen = Math.hypot(rDir.x, rDir.y);
|
const rDLen = Math.hypot(rDir.x, rDir.y);
|
||||||
rDir.x /= rDLen; rDir.y /= rDLen;
|
rDir.x /= rDLen; rDir.y /= rDLen;
|
||||||
|
|||||||
Reference in New Issue
Block a user