Compare commits

...
2 Commits
Author SHA1 Message Date
nils 21dcdee1f0 Rename blur labels to diameter
Build & Deploy / build (push) Successful in 2m33s
Build & Deploy / deploy (push) Successful in 41s
2025-10-05 13:39:59 +02:00
nils 39afb5c9e0 Align preview blur metric with plot 2025-10-05 13:33:32 +02:00
2 changed files with 21 additions and 11 deletions
+10 -7
View File
@@ -174,17 +174,20 @@ const PreviewPanel = ({ lensCurves, previewDistanceMeters }) => {
} }
const blurMm = stat?.blurMm ?? 0; const blurMm = stat?.blurMm ?? 0;
const blurPercent = stat?.blurPercentOfDiagonal ??
((curve.sensor?.diagonal ?? 0) > 0 ? (blurMm / curve.sensor.diagonal) * 100 : 0);
return { return {
lens: curve.lens, lens: curve.lens,
blurMm, blurMm,
blurPercent,
sensorDiagonal: curve.sensor?.diagonal ?? 1, sensorDiagonal: curve.sensor?.diagonal ?? 1,
colorIndex: curve.colorIndex, colorIndex: curve.colorIndex,
}; };
}); });
const maxBlurMm = previewItems.reduce((maxValue, item) => Math.max(maxValue, item.blurMm), 0); const maxBlurPercent = previewItems.reduce((maxValue, item) => Math.max(maxValue, item.blurPercent), 0);
const denominator = maxBlurMm > 0 ? maxBlurMm : 1; const denominator = maxBlurPercent > 0 ? maxBlurPercent : 1;
const distanceLabel = Number.isFinite(previewDistanceMeters) const distanceLabel = Number.isFinite(previewDistanceMeters)
? `${formatNumber(previewDistanceMeters, previewDistanceMeters >= 10 ? 0 : 1)} m` ? `${formatNumber(previewDistanceMeters, previewDistanceMeters >= 10 ? 0 : 1)} m`
: '∞'; : '∞';
@@ -200,7 +203,7 @@ const PreviewPanel = ({ lensCurves, previewDistanceMeters }) => {
) : ( ) : (
<div className="flex flex-wrap justify-center gap-4"> <div className="flex flex-wrap justify-center gap-4">
{previewItems.map((item) => { {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 diameter = Math.max(18, 30 + normalized * 70);
const paletteColor = COLOR_PALETTE[item.colorIndex % COLOR_PALETTE.length]; const paletteColor = COLOR_PALETTE[item.colorIndex % COLOR_PALETTE.length];
@@ -221,7 +224,7 @@ const PreviewPanel = ({ lensCurves, previewDistanceMeters }) => {
<div className="text-xs text-slate-200"> <div className="text-xs text-slate-200">
<div className="font-medium text-slate-100">{item.lens.name}</div> <div className="font-medium text-slate-100">{item.lens.name}</div>
<div className="text-[10px] uppercase tracking-wide text-slate-500"> <div className="text-[10px] uppercase tracking-wide text-slate-500">
Blur {formatNumber(item.blurMm, 2)} mm Blur {formatNumber(item.blurPercent, 2)}% diag
</div> </div>
</div> </div>
</div> </div>
@@ -321,7 +324,7 @@ const PlotSection = ({ lensCurves, plotType, setPlotType, previewDistanceMeters
<div className="flex flex-wrap items-center justify-between gap-3"> <div className="flex flex-wrap items-center justify-between gap-3">
<div> <div>
<h2 className="text-lg font-semibold text-slate-100">Blur comparison</h2> <h2 className="text-lg font-semibold text-slate-100">Blur comparison</h2>
<p className="text-xs uppercase tracking-wide text-slate-400">Blur radius as % of sensor diagonal</p> <p className="text-xs uppercase tracking-wide text-slate-400">Blur diameter as % of sensor diagonal</p>
</div> </div>
<div className="flex flex-wrap items-center gap-3"> <div className="flex flex-wrap items-center gap-3">
<select <select
@@ -355,7 +358,7 @@ const PlotSection = ({ lensCurves, plotType, setPlotType, previewDistanceMeters
...(axisConfig.ticksuffix ? { ticksuffix: axisConfig.ticksuffix } : {}), ...(axisConfig.ticksuffix ? { ticksuffix: axisConfig.ticksuffix } : {}),
}, },
yaxis: { yaxis: {
title: 'Blur radius (% of sensor diagonal)', title: 'Blur diameter (% of sensor diagonal)',
type: 'linear', type: 'linear',
gridcolor: 'rgba(148, 163, 184, 0.2)', gridcolor: 'rgba(148, 163, 184, 0.2)',
zerolinecolor: 'rgba(148, 163, 184, 0.4)', zerolinecolor: 'rgba(148, 163, 184, 0.4)',
@@ -976,7 +979,7 @@ const App = () => {
<div> <div>
<h1 className="text-2xl font-semibold text-slate-100">Lens & Sensor Blur Comparison</h1> <h1 className="text-2xl font-semibold text-slate-100">Lens & Sensor Blur Comparison</h1>
<p className="text-sm text-slate-400"> <p className="text-sm text-slate-400">
Explore blur radius as % of sensor diagonal across lens and sensor combinations. Explore blur diameter as % of sensor diagonal across lens and sensor combinations.
</p> </p>
</div> </div>
</div> </div>
+11 -4
View File
@@ -83,13 +83,20 @@ export const calculateBlurCircle = ({ focalLengthMm, aperture, subjectDistanceM,
const safeAperture = coercePositiveNumber(aperture, 1); const safeAperture = coercePositiveNumber(aperture, 1);
const f = focalLengthMm; const f = focalLengthMm;
const u = metersToMillimeters(coercePositiveNumber(subjectDistanceM, 0.5)); 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; 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; return 0;
} }
@@ -197,7 +204,7 @@ export const buildStatsAtCheckpoints = ({
sceneDistanceM: Infinity, sceneDistanceM: Infinity,
}); });
} else { } else {
sceneDistance = safeSubjectDistance + separation; sceneDistance = Math.max(safeSubjectDistance + separation, 0.2);
blurMm = calculateBlurCircle({ blurMm = calculateBlurCircle({
focalLengthMm: lens.focalLength, focalLengthMm: lens.focalLength,
aperture, aperture,