diff --git a/src/App.jsx b/src/App.jsx index 59e571e..8262826 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -174,17 +174,20 @@ const PreviewPanel = ({ lensCurves, previewDistanceMeters }) => { } const blurMm = stat?.blurMm ?? 0; + const blurPercent = stat?.blurPercentOfDiagonal ?? + ((curve.sensor?.diagonal ?? 0) > 0 ? (blurMm / curve.sensor.diagonal) * 100 : 0); return { lens: curve.lens, blurMm, + blurPercent, sensorDiagonal: curve.sensor?.diagonal ?? 1, colorIndex: curve.colorIndex, }; }); - const maxBlurMm = previewItems.reduce((maxValue, item) => Math.max(maxValue, item.blurMm), 0); - const denominator = maxBlurMm > 0 ? maxBlurMm : 1; + const maxBlurPercent = previewItems.reduce((maxValue, item) => Math.max(maxValue, item.blurPercent), 0); + const denominator = maxBlurPercent > 0 ? maxBlurPercent : 1; const distanceLabel = Number.isFinite(previewDistanceMeters) ? `${formatNumber(previewDistanceMeters, previewDistanceMeters >= 10 ? 0 : 1)} m` : '∞'; @@ -200,7 +203,7 @@ const PreviewPanel = ({ lensCurves, previewDistanceMeters }) => { ) : (
{previewItems.map((item) => { - const normalized = Math.min(item.blurMm / denominator, 1); + const normalized = Math.min(item.blurPercent / denominator, 1); const diameter = Math.max(18, 30 + normalized * 70); const paletteColor = COLOR_PALETTE[item.colorIndex % COLOR_PALETTE.length]; @@ -221,7 +224,7 @@ const PreviewPanel = ({ lensCurves, previewDistanceMeters }) => {
{item.lens.name}
- Blur {formatNumber(item.blurMm, 2)} mm + Blur {formatNumber(item.blurPercent, 2)}% diag
diff --git a/src/utils/optics.js b/src/utils/optics.js index daa087a..77667cd 100644 --- a/src/utils/optics.js +++ b/src/utils/optics.js @@ -83,13 +83,20 @@ export const calculateBlurCircle = ({ focalLengthMm, aperture, subjectDistanceM, const safeAperture = coercePositiveNumber(aperture, 1); const f = focalLengthMm; const u = metersToMillimeters(coercePositiveNumber(subjectDistanceM, 0.5)); - const s = metersToMillimeters(coercePositiveNumber(sceneDistanceM, 0.51)); - if (Math.abs(s - u) < 1e-6) { + if (Math.abs(u - f) < 1e-6) { return 0; } - if (Math.abs(u - f) < 1e-6) { + if (!Number.isFinite(sceneDistanceM)) { + const denominator = safeAperture * (u - f); + return Math.abs((f ** 2) / denominator); + } + + const sceneMeters = Math.max(sceneDistanceM, 0.2); + const s = metersToMillimeters(sceneMeters); + + if (Math.abs(s - u) < 1e-6) { return 0; } @@ -197,7 +204,7 @@ export const buildStatsAtCheckpoints = ({ sceneDistanceM: Infinity, }); } else { - sceneDistance = safeSubjectDistance + separation; + sceneDistance = Math.max(safeSubjectDistance + separation, 0.2); blurMm = calculateBlurCircle({ focalLengthMm: lens.focalLength, aperture,