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 tangDir = { x: efVec.x / efLen, y: efVec.y / efLen };
|
||||
const incRad = this.incAngle * Math.PI / 180;
|
||||
/* incDir = propagation direction (INTO the prism) */
|
||||
const incDir = {
|
||||
x: Math.cos(incRad) * (-efNorm.x) + Math.sin(incRad) * tangDir.x,
|
||||
y: Math.cos(incRad) * (-efNorm.y) + Math.sin(incRad) * tangDir.y,
|
||||
x: Math.cos(incRad) * efNorm.x + Math.sin(incRad) * tangDir.x,
|
||||
y: Math.cos(incRad) * efNorm.y + Math.sin(incRad) * tangDir.y,
|
||||
};
|
||||
const incDLen = Math.hypot(incDir.x, incDir.y);
|
||||
incDir.x /= incDLen; incDir.y /= incDLen;
|
||||
|
||||
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,
|
||||
isWhite ? '#FFFFFF' : wavelengthToRGB(monoNm), 2.5);
|
||||
|
||||
@@ -2639,13 +2641,15 @@ class PrismSim {
|
||||
for (const s of spectral) {
|
||||
const nP = _nAtWavelength(this.n0, 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;
|
||||
if (sinR > 1) continue;
|
||||
const cosR = Math.sqrt(1 - sinR * sinR);
|
||||
const rDir = {
|
||||
x: (1/nP) * incDir.x + ((1/nP) * cosI - cosR) * efNorm.x,
|
||||
y: (1/nP) * incDir.y + ((1/nP) * cosI - cosR) * efNorm.y,
|
||||
x: (1/nP) * incDir.x + (cosR - (1/nP) * cosI) * efNorm.x,
|
||||
y: (1/nP) * incDir.y + (cosR - (1/nP) * cosI) * efNorm.y,
|
||||
};
|
||||
const rDLen = Math.hypot(rDir.x, rDir.y);
|
||||
rDir.x /= rDLen; rDir.y /= rDLen;
|
||||
|
||||
Reference in New Issue
Block a user