Add lens presets and contact footer
Build & Deploy / build (push) Successful in 2m41s
Build & Deploy / deploy (push) Successful in 19s

This commit is contained in:
2025-10-05 12:52:09 +02:00
parent 7847406b10
commit 43d028a41f
2 changed files with 258 additions and 48 deletions
+138
View File
@@ -0,0 +1,138 @@
export const NORMAL_RATIO_RANGE = {
min: 0.7,
max: 1.5,
};
export const scoreLensForNormalView = (lens, sensor, ratioRange = NORMAL_RATIO_RANGE) => {
const aperture = Number.isFinite(lens?.maxAperture) ? lens.maxAperture : Infinity;
const sensorDiagonal = Number.isFinite(sensor?.diagonal) ? sensor.diagonal : Infinity;
const cropFactor = Number.isFinite(sensor?.cropFactor) ? sensor.cropFactor : 1;
const delta = Number.isFinite(sensorDiagonal) ? Math.abs(lens.focalLength - sensorDiagonal) : Infinity;
const ratio = sensorDiagonal > 0 ? lens.focalLength / sensorDiagonal : Infinity;
const withinNormalBand = ratio >= ratioRange.min && ratio <= ratioRange.max;
const effectiveFocalLength = lens.focalLength * cropFactor;
return {
lens,
aperture,
delta,
ratio,
withinNormalBand,
cropFactor,
effectiveFocalLength,
};
};
const groupLensesBySensor = (lenses) =>
lenses.reduce((acc, lens) => {
if (!acc[lens.sensorId]) {
acc[lens.sensorId] = [];
}
acc[lens.sensorId].push(lens);
return acc;
}, {});
export const selectNormalLensForSensor = (lenses, sensor, ratioRange = NORMAL_RATIO_RANGE) => {
if (!Array.isArray(lenses) || lenses.length === 0 || !sensor) {
return null;
}
const scored = lenses.map((lens) => scoreLensForNormalView(lens, sensor, ratioRange));
const normalCandidates = scored.filter((entry) => entry.withinNormalBand);
const candidates = normalCandidates.length > 0 ? normalCandidates : scored;
candidates.sort((a, b) => {
if (a.aperture !== b.aperture) {
return a.aperture - b.aperture;
}
if (a.delta !== b.delta) {
return a.delta - b.delta;
}
return a.lens.focalLength - b.lens.focalLength;
});
return candidates[0]?.lens ?? null;
};
export const selectWideLensForSensor = (lenses, sensor, ratioRange = NORMAL_RATIO_RANGE) => {
if (!Array.isArray(lenses) || lenses.length === 0 || !sensor) {
return null;
}
const scored = lenses.map((lens) => scoreLensForNormalView(lens, sensor, ratioRange));
const wideCandidates = scored.filter((entry) => entry.ratio < ratioRange.min);
const candidates = wideCandidates.length > 0 ? wideCandidates : scored;
candidates.sort((a, b) => {
if (a.ratio !== b.ratio) {
return a.ratio - b.ratio;
}
if (a.aperture !== b.aperture) {
return a.aperture - b.aperture;
}
return a.lens.focalLength - b.lens.focalLength;
});
return candidates[0]?.lens ?? null;
};
export const selectPortraitLensForSensor = (lenses, sensor, ratioRange = NORMAL_RATIO_RANGE) => {
if (!Array.isArray(lenses) || lenses.length === 0 || !sensor) {
return null;
}
const PORTRAIT_TARGET_EQUIV_MM = 85;
const PORTRAIT_MIN_EQUIV_MM = 70;
const scored = lenses.map((lens) => scoreLensForNormalView(lens, sensor, ratioRange));
const portraitCandidates = scored.filter((entry) => entry.effectiveFocalLength >= PORTRAIT_MIN_EQUIV_MM);
const candidates = portraitCandidates.length > 0 ? portraitCandidates : scored;
candidates.sort((a, b) => {
const deltaA = Math.abs(a.effectiveFocalLength - PORTRAIT_TARGET_EQUIV_MM);
const deltaB = Math.abs(b.effectiveFocalLength - PORTRAIT_TARGET_EQUIV_MM);
if (deltaA !== deltaB) {
return deltaA - deltaB;
}
if (a.aperture !== b.aperture) {
return a.aperture - b.aperture;
}
if (a.effectiveFocalLength !== b.effectiveFocalLength) {
return b.effectiveFocalLength - a.effectiveFocalLength;
}
return b.lens.focalLength - a.lens.focalLength;
});
return candidates[0]?.lens ?? null;
};
const selectLensIdsForSensorsBySelector = (sensors, lenses, selector, ratioRange = NORMAL_RATIO_RANGE) => {
if (!Array.isArray(sensors) || sensors.length === 0) {
return [];
}
const lensMap = groupLensesBySensor(lenses);
const selectedIds = sensors
.map((sensor) => {
const sensorLenses = lensMap[sensor.id];
if (!sensorLenses || sensorLenses.length === 0) {
return null;
}
const match = selector(sensorLenses, sensor, ratioRange);
return match?.id ?? null;
})
.filter(Boolean);
return selectedIds.length > 0 ? Array.from(new Set(selectedIds)) : [];
};
export const selectNormalLensIdsForSensors = (sensors, lenses, ratioRange = NORMAL_RATIO_RANGE) =>
selectLensIdsForSensorsBySelector(sensors, lenses, selectNormalLensForSensor, ratioRange);
export const selectWideLensIdsForSensors = (sensors, lenses, ratioRange = NORMAL_RATIO_RANGE) =>
selectLensIdsForSensorsBySelector(sensors, lenses, selectWideLensForSensor, ratioRange);
export const selectPortraitLensIdsForSensors = (sensors, lenses, ratioRange = NORMAL_RATIO_RANGE) =>
selectLensIdsForSensorsBySelector(sensors, lenses, selectPortraitLensForSensor, ratioRange);