@photivra/engine 2.18.0 → 2.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +179 -1
- package/CITATION.cff +1 -1
- package/NODE_SUPPORT.md +7 -5
- package/README.md +6 -6
- package/SECURITY.md +1 -1
- package/THIRD_PARTY.md +14 -10
- package/dist/capture/dng-lens-correction-opcodes.d.ts +32 -0
- package/dist/capture/dng-lens-correction-opcodes.js +119 -0
- package/dist/capture/dng-lens-correction-opcodes.js.map +1 -0
- package/dist/capture/focus-control.js +2 -75
- package/dist/capture/focus-control.js.map +1 -1
- package/dist/capture/native-environment-lean.d.ts +1 -0
- package/dist/capture/native-environment-lean.js +2 -6
- package/dist/capture/native-environment-lean.js.map +1 -1
- package/dist/capture/native-environment-optical-stage.d.ts +1 -0
- package/dist/capture/native-environment-optical-stage.js +2 -5
- package/dist/capture/native-environment-optical-stage.js.map +1 -1
- package/dist/capture/native-environment-raw.js +1 -5
- package/dist/capture/native-environment-raw.js.map +1 -1
- package/dist/capture/native-raw-dng.d.ts +6 -0
- package/dist/capture/native-raw-dng.js +16 -2
- package/dist/capture/native-raw-dng.js.map +1 -1
- package/dist/capture/release-sequence.js +2 -47
- package/dist/capture/release-sequence.js.map +1 -1
- package/dist/capture/sensor-raw-producer.js +3 -5
- package/dist/capture/sensor-raw-producer.js.map +1 -1
- package/dist/color/white-balance.d.ts +2 -0
- package/dist/color/white-balance.js +3 -56
- package/dist/color/white-balance.js.map +1 -1
- package/dist/composition/image-formation-plan.d.ts +1 -0
- package/dist/composition/image-formation-plan.js +3 -49
- package/dist/composition/image-formation-plan.js.map +1 -1
- package/dist/core/evidence-provenance.js +1 -16
- package/dist/core/evidence-provenance.js.map +1 -1
- package/dist/core/record-validation.d.ts +54 -0
- package/dist/core/record-validation.js +176 -0
- package/dist/core/record-validation.js.map +1 -1
- package/dist/core/scientific-assurance.js +1 -18
- package/dist/core/scientific-assurance.js.map +1 -1
- package/dist/core/shared-helpers.d.ts +35 -0
- package/dist/core/shared-helpers.js +38 -0
- package/dist/core/shared-helpers.js.map +1 -0
- package/dist/core/spectral-composition.js +1 -36
- package/dist/core/spectral-composition.js.map +1 -1
- package/dist/core/spectral.js +1 -19
- package/dist/core/spectral.js.map +1 -1
- package/dist/core/version.d.ts +1 -1
- package/dist/core/version.js +1 -1
- package/dist/core/version.js.map +1 -1
- package/dist/equipment/exposure-capabilities.d.ts +1 -0
- package/dist/equipment/exposure-capabilities.js +2 -36
- package/dist/equipment/exposure-capabilities.js.map +1 -1
- package/dist/equipment/generic-lens-catalogue.d.ts +8 -2
- package/dist/equipment/generic-lens-catalogue.js +31 -2
- package/dist/equipment/generic-lens-catalogue.js.map +1 -1
- package/dist/equipment/generic-tier-assets.js +2 -3
- package/dist/equipment/generic-tier-assets.js.map +1 -1
- package/dist/equipment/generic-tier-presets.js +2 -3
- package/dist/equipment/generic-tier-presets.js.map +1 -1
- package/dist/equipment/iso-capabilities.js +2 -49
- package/dist/equipment/iso-capabilities.js.map +1 -1
- package/dist/equipment/metering-capabilities.js +1 -26
- package/dist/equipment/metering-capabilities.js.map +1 -1
- package/dist/equipment/release-capabilities.js +1 -53
- package/dist/equipment/release-capabilities.js.map +1 -1
- package/dist/exposure/auto-iso-slowest-shutter.js +1 -7
- package/dist/exposure/auto-iso-slowest-shutter.js.map +1 -1
- package/dist/exposure/exposure-duration-control.js +1 -16
- package/dist/exposure/exposure-duration-control.js.map +1 -1
- package/dist/exposure/exposure-mode-resolver.js +1 -17
- package/dist/exposure/exposure-mode-resolver.js.map +1 -1
- package/dist/exposure/filtered-exposure-time.d.ts +93 -0
- package/dist/exposure/filtered-exposure-time.js +129 -0
- package/dist/exposure/filtered-exposure-time.js.map +1 -0
- package/dist/exposure/flash-ttl.d.ts +1 -0
- package/dist/exposure/flash-ttl.js +1 -1
- package/dist/exposure/flash-ttl.js.map +1 -1
- package/dist/exposure/flash.js +1 -49
- package/dist/exposure/flash.js.map +1 -1
- package/dist/exposure/metering-scene-radiance.js +1 -25
- package/dist/exposure/metering-scene-radiance.js.map +1 -1
- package/dist/exposure/metering-target.js +1 -30
- package/dist/exposure/metering-target.js.map +1 -1
- package/dist/exposure/metering-temporal.js +1 -8
- package/dist/exposure/metering-temporal.js.map +1 -1
- package/dist/exposure/metering.js +1 -72
- package/dist/exposure/metering.js.map +1 -1
- package/dist/exposure/program-line.js +1 -45
- package/dist/exposure/program-line.js.map +1 -1
- package/dist/facade/develop-joined-parts.d.ts +29 -0
- package/dist/facade/develop-joined-parts.js +33 -0
- package/dist/facade/develop-joined-parts.js.map +1 -0
- package/dist/facade/display-view-gpu.d.ts +7 -4
- package/dist/facade/display-view-gpu.js +4 -4
- package/dist/facade/display-view-gpu.js.map +1 -1
- package/dist/facade/display-view-lens-signal.d.ts +1 -1
- package/dist/facade/display-view-lens-signal.js +5 -3
- package/dist/facade/display-view-lens-signal.js.map +1 -1
- package/dist/facade/display-view.d.ts +3 -1
- package/dist/facade/display-view.js +1 -1
- package/dist/facade/display-view.js.map +1 -1
- package/dist/facade/fast-methods.d.ts +50 -0
- package/dist/facade/fast-methods.js +50 -0
- package/dist/facade/fast-methods.js.map +1 -0
- package/dist/facade/fast-resolution.d.ts +12 -0
- package/dist/facade/fast-resolution.js +18 -0
- package/dist/facade/fast-resolution.js.map +1 -0
- package/dist/facade/generic-lens-capture.d.ts +6 -3
- package/dist/facade/generic-lens-capture.js +6 -3
- package/dist/facade/generic-lens-capture.js.map +1 -1
- package/dist/facade/simulate-capture.d.ts +88 -16
- package/dist/facade/simulate-capture.js +279 -153
- package/dist/facade/simulate-capture.js.map +1 -1
- package/dist/facade/simulate-display-view.d.ts +3 -2
- package/dist/facade/simulate-display-view.js +22 -12
- package/dist/facade/simulate-display-view.js.map +1 -1
- package/dist/gpu/chart-composite-gpu.js +1 -3
- package/dist/gpu/chart-composite-gpu.js.map +1 -1
- package/dist/gpu/chart-radiance-gpu.js +1 -5
- package/dist/gpu/chart-radiance-gpu.js.map +1 -1
- package/dist/gpu/display-view-quality-gpu.d.ts +13 -1
- package/dist/gpu/display-view-quality-gpu.js +4 -8
- package/dist/gpu/display-view-quality-gpu.js.map +1 -1
- package/dist/gpu/display-view-speed-gpu.js +3 -25
- package/dist/gpu/display-view-speed-gpu.js.map +1 -1
- package/dist/gpu/sensor-stage-gpu.js +1 -5
- package/dist/gpu/sensor-stage-gpu.js.map +1 -1
- package/dist/gpu/webgpu-runtime.d.ts +2 -0
- package/dist/gpu/webgpu-runtime.js +3 -0
- package/dist/gpu/webgpu-runtime.js.map +1 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/motion/camera-rotation.js +1 -6
- package/dist/motion/camera-rotation.js.map +1 -1
- package/dist/motion/capture-rotation-inverse-mapping.d.ts +12 -0
- package/dist/motion/capture-rotation-inverse-mapping.js +2 -2
- package/dist/motion/capture-rotation-inverse-mapping.js.map +1 -1
- package/dist/motion/capture-rotation-temporal-quadrature.d.ts +1 -0
- package/dist/motion/capture-rotation-temporal-quadrature.js +1 -1
- package/dist/motion/capture-rotation-temporal-quadrature.js.map +1 -1
- package/dist/motion/capture-rotation-trajectory.js +2 -17
- package/dist/motion/capture-rotation-trajectory.js.map +1 -1
- package/dist/motion/capture-translation-parallax-temporal-quadrature.d.ts +1 -0
- package/dist/motion/capture-translation-parallax-temporal-quadrature.js +3 -14
- package/dist/motion/capture-translation-parallax-temporal-quadrature.js.map +1 -1
- package/dist/motion/extended-object-projection.js +5 -40
- package/dist/motion/extended-object-projection.js.map +1 -1
- package/dist/optics/aperture-diameter.d.ts +47 -0
- package/dist/optics/aperture-diameter.js +50 -0
- package/dist/optics/aperture-diameter.js.map +1 -0
- package/dist/optics/atmospheric-haze.js +1 -7
- package/dist/optics/atmospheric-haze.js.map +1 -1
- package/dist/optics/brown-conrady-distortion.js +1 -7
- package/dist/optics/brown-conrady-distortion.js.map +1 -1
- package/dist/optics/complex-pupil-psf.d.ts +1 -0
- package/dist/optics/complex-pupil-psf.js +2 -84
- package/dist/optics/complex-pupil-psf.js.map +1 -1
- package/dist/optics/detail-limit.d.ts +182 -0
- package/dist/optics/detail-limit.js +336 -0
- package/dist/optics/detail-limit.js.map +1 -0
- package/dist/optics/focus-state.js +1 -11
- package/dist/optics/focus-state.js.map +1 -1
- package/dist/optics/front-of-lens-filter.d.ts +5 -0
- package/dist/optics/front-of-lens-filter.js +3 -65
- package/dist/optics/front-of-lens-filter.js.map +1 -1
- package/dist/optics/generic-lens-psf.d.ts +18 -2
- package/dist/optics/generic-lens-psf.js +25 -2
- package/dist/optics/generic-lens-psf.js.map +1 -1
- package/dist/optics/generic-nd-filter-presets.d.ts +12 -0
- package/dist/optics/generic-nd-filter-presets.js +48 -0
- package/dist/optics/generic-nd-filter-presets.js.map +1 -0
- package/dist/optics/illumination-vignetting.js +1 -6
- package/dist/optics/illumination-vignetting.js.map +1 -1
- package/dist/optics/lens-psf-profile.d.ts +4 -1
- package/dist/optics/lens-psf-profile.js +12 -111
- package/dist/optics/lens-psf-profile.js.map +1 -1
- package/dist/optics/longitudinal-chromatic-aberration.js +1 -7
- package/dist/optics/longitudinal-chromatic-aberration.js.map +1 -1
- package/dist/optics/pupil-vignetting.js +1 -7
- package/dist/optics/pupil-vignetting.js.map +1 -1
- package/dist/optics/radial-distortion.js +1 -6
- package/dist/optics/radial-distortion.js.map +1 -1
- package/dist/optics/scene-to-sensor-irradiance.d.ts +13 -0
- package/dist/optics/scene-to-sensor-irradiance.js +11 -96
- package/dist/optics/scene-to-sensor-irradiance.js.map +1 -1
- package/dist/optics/stray-light.d.ts +1 -0
- package/dist/optics/stray-light.js +1 -1
- package/dist/optics/stray-light.js.map +1 -1
- package/dist/optics/zernike-wavefront.js +1 -7
- package/dist/optics/zernike-wavefront.js.map +1 -1
- package/dist/output/capture-geometry.js +1 -8
- package/dist/output/capture-geometry.js.map +1 -1
- package/dist/output/crop-to-match-focal-length.d.ts +62 -0
- package/dist/output/crop-to-match-focal-length.js +63 -0
- package/dist/output/crop-to-match-focal-length.js.map +1 -0
- package/dist/output/developed-lens-corrections.d.ts +62 -0
- package/dist/output/developed-lens-corrections.js +135 -0
- package/dist/output/developed-lens-corrections.js.map +1 -0
- package/dist/output/generic-lens-corrections.d.ts +5 -7
- package/dist/output/generic-lens-corrections.js +11 -10
- package/dist/output/generic-lens-corrections.js.map +1 -1
- package/dist/output/geometric-transforms.js +1 -4
- package/dist/output/geometric-transforms.js.map +1 -1
- package/dist/output/lens-corrections.d.ts +12 -2
- package/dist/output/lens-corrections.js +22 -7
- package/dist/output/lens-corrections.js.map +1 -1
- package/dist/output/native-capture-sdr.d.ts +2 -2
- package/dist/output/native-capture-sdr.js +3 -2
- package/dist/output/native-capture-sdr.js.map +1 -1
- package/dist/output/print-contrast-reference.js +1 -1
- package/dist/output/print-contrast-reference.js.map +1 -1
- package/dist/output/print-size-blur-noise.d.ts +110 -0
- package/dist/output/print-size-blur-noise.js +138 -0
- package/dist/output/print-size-blur-noise.js.map +1 -0
- package/dist/processing/development-detail.d.ts +29 -0
- package/dist/processing/development-detail.js +128 -107
- package/dist/processing/development-detail.js.map +1 -1
- package/dist/schema/illumination-temporal.js +3 -72
- package/dist/schema/illumination-temporal.js.map +1 -1
- package/dist/schema/illumination.d.ts +1 -0
- package/dist/schema/illumination.js +2 -65
- package/dist/schema/illumination.js.map +1 -1
- package/dist/schema/scene-radiance-temporal.js +2 -14
- package/dist/schema/scene-radiance-temporal.js.map +1 -1
- package/dist/schema/scene-radiance.js +2 -60
- package/dist/schema/scene-radiance.js.map +1 -1
- package/dist/schema/validation.d.ts +2 -0
- package/dist/schema/validation.js +2 -17
- package/dist/schema/validation.js.map +1 -1
- package/dist/sensor/accumulated-charge.js +2 -59
- package/dist/sensor/accumulated-charge.js.map +1 -1
- package/dist/sensor/architecture.js +1 -16
- package/dist/sensor/architecture.js.map +1 -1
- package/dist/sensor/camera-saturation-capacity.d.ts +1 -0
- package/dist/sensor/camera-saturation-capacity.js +3 -55
- package/dist/sensor/camera-saturation-capacity.js.map +1 -1
- package/dist/sensor/capture-color-sampling-binding.js +1 -26
- package/dist/sensor/capture-color-sampling-binding.js.map +1 -1
- package/dist/sensor/capture-mode-timing.js +1 -39
- package/dist/sensor/capture-mode-timing.js.map +1 -1
- package/dist/sensor/capture-mode.js +1 -23
- package/dist/sensor/capture-mode.js.map +1 -1
- package/dist/sensor/color-sampling.js +1 -26
- package/dist/sensor/color-sampling.js.map +1 -1
- package/dist/sensor/constant-rate-temporal-integration.js +2 -46
- package/dist/sensor/constant-rate-temporal-integration.js.map +1 -1
- package/dist/sensor/dark-current.js +2 -45
- package/dist/sensor/dark-current.js.map +1 -1
- package/dist/sensor/eqe-electron-rate.js +2 -41
- package/dist/sensor/eqe-electron-rate.js.map +1 -1
- package/dist/sensor/exposure-window.d.ts +7 -0
- package/dist/sensor/exposure-window.js +9 -24
- package/dist/sensor/exposure-window.js.map +1 -1
- package/dist/sensor/iso-gain.js +1 -7
- package/dist/sensor/iso-gain.js.map +1 -1
- package/dist/sensor/iso-signal-chain.js +1 -43
- package/dist/sensor/iso-signal-chain.js.map +1 -1
- package/dist/sensor/optical-stack.js +1 -25
- package/dist/sensor/optical-stack.js.map +1 -1
- package/dist/sensor/photon-energy.js +1 -26
- package/dist/sensor/photon-energy.js.map +1 -1
- package/dist/sensor/physical-charge-capacity.js +3 -77
- package/dist/sensor/physical-charge-capacity.js.map +1 -1
- package/dist/sensor/radiometry-readiness.js +2 -23
- package/dist/sensor/radiometry-readiness.js.map +1 -1
- package/dist/sensor/raw-readout.d.ts +3 -0
- package/dist/sensor/raw-readout.js +4 -66
- package/dist/sensor/raw-readout.js.map +1 -1
- package/dist/sensor/raw-reconstruction.js +2 -64
- package/dist/sensor/raw-reconstruction.js.map +1 -1
- package/dist/sensor/readout-exposure-linkage.js +1 -9
- package/dist/sensor/readout-exposure-linkage.js.map +1 -1
- package/dist/sensor/readout-timing.js +4 -79
- package/dist/sensor/readout-timing.js.map +1 -1
- package/dist/sensor/response-application-compatibility.d.ts +2 -0
- package/dist/sensor/response-application-compatibility.js +4 -35
- package/dist/sensor/response-application-compatibility.js.map +1 -1
- package/dist/sensor/response-operating-range.d.ts +1 -0
- package/dist/sensor/response-operating-range.js +3 -79
- package/dist/sensor/response-operating-range.js.map +1 -1
- package/dist/sensor/responsivity-photocurrent.js +4 -114
- package/dist/sensor/responsivity-photocurrent.js.map +1 -1
- package/dist/sensor/sampling-aperture.js +1 -25
- package/dist/sensor/sampling-aperture.js.map +1 -1
- package/dist/sensor/sensor-characteristics.d.ts +137 -0
- package/dist/sensor/sensor-characteristics.js +115 -0
- package/dist/sensor/sensor-characteristics.js.map +1 -0
- package/dist/sensor/spatial-sample-reduction.js +3 -24
- package/dist/sensor/spatial-sample-reduction.js.map +1 -1
- package/dist/sensor/spatial-sampling-quadrature.js +1 -3
- package/dist/sensor/spatial-sampling-quadrature.js.map +1 -1
- package/dist/sensor/spatio-spectral-reduction.js +1 -18
- package/dist/sensor/spatio-spectral-reduction.js.map +1 -1
- package/dist/sensor/spectral-coverage.d.ts +10 -1
- package/dist/sensor/spectral-coverage.js +1 -1
- package/dist/sensor/spectral-coverage.js.map +1 -1
- package/dist/sensor/spectral-quadrature.js +3 -41
- package/dist/sensor/spectral-quadrature.js.map +1 -1
- package/dist/sensor/spectral-response.js +1 -47
- package/dist/sensor/spectral-response.js.map +1 -1
- package/dist/sensor/temporal-photo-signal.d.ts +3 -0
- package/dist/sensor/temporal-photo-signal.js +5 -2
- package/dist/sensor/temporal-photo-signal.js.map +1 -1
- package/dist/stabilization/camera-shake.js +1 -6
- package/dist/stabilization/camera-shake.js.map +1 -1
- package/dist/stabilization/system.d.ts +9 -0
- package/dist/stabilization/system.js +7 -86
- package/dist/stabilization/system.js.map +1 -1
- package/docs/AGENT_GUIDE.md +5 -0
- package/docs/API_REFERENCE.md +116 -3
- package/docs/QUICK_START.md +178 -14
- package/docs/USAGE.md +111 -3
- package/docs/api/capture-native-raw-dng.md +6 -0
- package/docs/api/core-version.md +1 -1
- package/docs/api/equipment-generic-lens-catalogue.md +7 -2
- package/docs/api/exports.json +203 -3
- package/docs/api/exposure-filtered-exposure-time.md +105 -0
- package/docs/api/facade-develop-joined-parts.md +32 -0
- package/docs/api/facade-display-view-gpu.md +5 -2
- package/docs/api/facade-fast-methods.md +91 -0
- package/docs/api/facade-simulate-capture.md +72 -16
- package/docs/api/facade-simulate-display-view.md +3 -2
- package/docs/api/optics-aperture-diameter.md +51 -0
- package/docs/api/optics-detail-limit.md +203 -0
- package/docs/api/optics-generic-nd-filter-presets.md +34 -0
- package/docs/api/optics-lens-psf-profile.md +3 -1
- package/docs/api/output-crop-to-match-focal-length.md +67 -0
- package/docs/api/output-developed-lens-corrections.md +12 -0
- package/docs/api/output-generic-lens-corrections.md +3 -10
- package/docs/api/output-lens-corrections.md +11 -1
- package/docs/api/output-print-size-blur-noise.md +115 -0
- package/docs/api/sensor-sensor-characteristics.md +105 -0
- package/llms.txt +5 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generic-lens-psf.js","sourceRoot":"","sources":["../../src/optics/generic-lens-psf.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * The PSF of a generic catalogue lens (#549) on a sensor's site lattice, as a field- and wavelength-dependent sampled PSF\n * profile for the environment PSF quadrature (`simulateCapture` `lens.catalogue`).\n *\n * Model (an approximation): scalar Fraunhofer diffraction of a uniform circular pupil of diameter D = f/N carrying the\n * lens's Seidel wavefront (`resolveGenericLens`; the expansion of `createWavefrontPupilGrid`, Hopkins 1950; Wyant & Creath\n * 1992), propagated to the thin-lens image distance z (working f-number z/D; Goodman, Introduction to Fourier Optics, ch. 4-6).\n * U(x) = Σ_pupil exp(i·2π·W(u)/λ)·exp(−i·2π·x·u/(λ·z)) is evaluated with a zero-padded radix-2 FFT (Cooley & Tukey 1965) on\n * an image grid of pitch δ = min(λ·N_w/2, p/4) (p the site pitch), and |U|² is integrated over each site's square cell (exact\n * overlap of each δ-square with the cell). Lateral colour displaces the PSF radially by Δr(λ). The kernel window is (2R + 1)²\n * sites; the energy outside it is reported and put back by unit-sum renormalisation, as for `lens.diffraction`.\n *\n * Nodes: a 5 × 5 regular grid of field points (0, ±half the frame, ±the frame edge plus the kernel reach) × 5 wavelengths\n * (380, 450, 550, 650, 780 nm), each computed at its own field azimuth (no rotation of a radial node), interpolated by the\n * engine's centroid-aligned multilinear scheme. The quadrant x, y ≥ 0 is computed and mirrored (the Seidel PSF of a mirrored\n * field point is the mirrored PSF).\n *\n * Kernel orientation: a kernel's row index increases with image +Y, the orientation the environment PSF quadrature applies\n * (`sensorPsfSourcePoint`), so coma and lateral colour point away from the optical axis in the rendered image.\n */\n\nimport { InvalidScientificInputError } from \"../core/validation.js\";\nimport type { EvidenceProvenance } from \"../core/evidence-provenance.js\";\nimport { genericLensDispersion, type ResolvedGenericLens } from \"../equipment/generic-lens-catalogue.js\";\nimport { markEngineOwnedLensSampledPsfProfile, type LensSampledPsfGridNode, type LensSampledPsfProfile } from \"./lens-psf-profile.js\";\nimport { convolveSiteKernels } from \"./defocus-disc-kernel.js\";\n\n/** Wavelength nodes of a catalogue PSF profile, nm (they span the facade's 380–780 nm quadrature). */\nexport const GENERIC_LENS_PSF_WAVELENGTHS_NM = /* @__PURE__ */ Object.freeze([380, 450, 550, 650, 780] as const);\n/** Largest kernel radius of the aberration PSF in sites (before any defocus disc is convolved in). */\nexport const GENERIC_LENS_PSF_MAXIMUM_KERNEL_RADIUS_SITES = 12;\n/** Largest kernel radius in sites of the catalogue PSF with a defocus disc convolved in (`simulateCapture` refuses more: cost). */\nexport const GENERIC_LENS_PSF_MAXIMUM_COMBINED_RADIUS_SITES = 16;\n/** Energy fraction a node may leave outside the chosen kernel window (it is put back by renormalisation and reported). */\nexport const GENERIC_LENS_PSF_WINDOW_TRUNCATION = 0.03;\n/** Largest FFT size per axis. */\nconst MAXIMUM_TRANSFORM = 2048;\n/** Largest optical-path step between neighbouring pupil samples, in waves (Nyquist is 0.5). */\nconst MAXIMUM_PHASE_STEP_WAVES = 0.35;\nconst DESIGN_WAVELENGTH_UM = 0.55;\n\nexport interface GenericLensPsfInput {\n /** The lens resolved at the capture's f-number and focus distance (`resolveGenericLens`). */\n lens: ResolvedGenericLens;\n /** Finite focus distance, m (the thin-lens image distance sets the propagation distance). */\n focusDistanceM: number;\n sitePitchMicrometers: number;\n /** Half extent of the field the profile must cover, mm (the frame's half width and height plus the PSF and query reach). */\n fieldHalfExtentMm: { x: number; y: number };\n /** The frame's half width and height, mm (the inner field nodes sit at half of them). */\n frameHalfMm: { x: number; y: number };\n /** Optional site kernel (2R_d + 1)² to convolve into every node (the `lens.defocus` disc). */\n extraKernel?: { weights: Float64Array; radius: number };\n evidence: readonly EvidenceProvenance[];\n}\n\nexport interface GenericLensPsf {\n profile: LensSampledPsfProfile;\n /** Radius of the aberration PSF window, sites, and of the applied kernel (with `extraKernel`). */\n aberrationKernelRadiusSites: number;\n kernelRadiusSites: number;\n /** Largest energy fraction outside the aberration window over the nodes (put back by renormalisation). */\n maximumTruncatedEnergyFraction: number;\n /** FFT sizes used (smallest, largest) and the largest pupil phase step, waves. */\n transformSize: { minimum: number; maximum: number };\n maximumPhaseStepWaves: number;\n /** Field node coordinates, mm, and wavelengths, nm. */\n fieldXmm: readonly number[];\n fieldYmm: readonly number[];\n wavelengthsNm: readonly number[];\n}\n\n/** In-place iterative radix-2 FFT, exp(−i·2π·k·m/n). */\nfunction radix2Fft(re: Float64Array, im: Float64Array, n: number, cos: Float64Array, sin: Float64Array): void {\n for (let i = 1, j = 0; i < n; i++) {\n let bit = n >> 1;\n for (; j & bit; bit >>= 1) j ^= bit;\n j ^= bit;\n if (i < j) { let t = re[i]!; re[i] = re[j]!; re[j] = t; t = im[i]!; im[i] = im[j]!; im[j] = t; }\n }\n for (let size = 2; size <= n; size <<= 1) {\n const half = size >> 1, step = n / size;\n for (let start = 0; start < n; start += size) for (let k = 0; k < half; k++) {\n const c = cos[k * step]!, s = sin[k * step]!, a = start + k, b = a + half;\n const tr = re[b]! * c + im[b]! * s, ti = im[b]! * c - re[b]! * s;\n re[b] = re[a]! - tr; im[b] = im[a]! - ti; re[a] = re[a]! + tr; im[a] = im[a]! + ti;\n }\n }\n}\n\n/** One axis's overlap of δ-squares centred at positions (s·δ + shift) with site cells [(i − ½)p, (i + ½)p], i ∈ [−R, R]. */\nfunction overlaps(count: number, delta: number, shift: number, pitch: number, radius: number): { cell: Int32Array; weight: Float64Array; cell2: Int32Array; weight2: Float64Array } {\n const cell = new Int32Array(count).fill(-1), weight = new Float64Array(count), cell2 = new Int32Array(count).fill(-1), weight2 = new Float64Array(count);\n for (let k = 0; k < count; k++) {\n const signed = k < count / 2 ? k : k - count, centre = signed * delta + shift, lo = centre - delta / 2, hi = centre + delta / 2;\n const first = Math.floor(lo / pitch + 0.5), last = Math.floor(hi / pitch + 0.5);\n for (let i = first; i <= last && i <= first + 1; i++) {\n if (i < -radius || i > radius) continue;\n const w = (Math.min(hi, (i + 0.5) * pitch) - Math.max(lo, (i - 0.5) * pitch)) / delta;\n if (w <= 0) continue;\n if (cell[k] === -1) { cell[k] = i + radius; weight[k] = w; } else { cell2[k] = i + radius; weight2[k] = w; }\n }\n }\n return { cell, weight, cell2, weight2 };\n}\n\n/** A node's energy per site cell over the (2R₀ + 1)² window (not normalised) and the whole period's energy. */\ninterface NodeResult { kernel: Float64Array; total: number; transform: number; phaseStep: number }\n\n/** Seidel OPD (µm) at normalised pupil (px, py) for a field point at height H and azimuth φ, at wavelength λ (µm). */\nfunction opdMicrometers(lens: ResolvedGenericLens, H: number, cosPhi: number, sinPhi: number, lambdaUm: number, px: number, py: number): number {\n const a = lens.character.aberrations, r2 = px * px + py * py, along = px * cosPhi + py * sinPhi;\n const defocus = a.balancingDefocusWaves + a.axialColorWaves * genericLensDispersion(lambdaUm * 1000);\n // Positive coma W131 sends the comet's flare away from the axis in the image (H ρ³ cos(θ − φ), with the FFT sign above).\n return DESIGN_WAVELENGTH_UM * (defocus * r2 + a.sphericalWaves * r2 * r2 + a.comaWaves * H * r2 * along + a.astigmatismWaves * H * H * along * along + a.fieldCurvatureWaves * H * H * r2);\n}\n\n/** Largest transverse ray aberration 2·N_w·|∂W/∂ρ| (µm) over the pupil, from a 33 × 33 grid. */\nfunction geometricRadiusMicrometers(lens: ResolvedGenericLens, H: number, lambdaUm: number, workingF: number): number {\n let largest = 0;\n const n = 33, h = 1e-4;\n for (let j = 0; j < n; j++) for (let i = 0; i < n; i++) {\n const px = -1 + 2 * i / (n - 1), py = -1 + 2 * j / (n - 1);\n if (px * px + py * py > 1) continue;\n const gx = (opdMicrometers(lens, H, 1, 0, lambdaUm, px + h, py) - opdMicrometers(lens, H, 1, 0, lambdaUm, px - h, py)) / (2 * h);\n const gy = (opdMicrometers(lens, H, 1, 0, lambdaUm, px, py + h) - opdMicrometers(lens, H, 1, 0, lambdaUm, px, py - h)) / (2 * h);\n largest = Math.max(largest, Math.hypot(gx, gy));\n }\n return 2 * workingF * largest;\n}\n\nfunction nodeKernel(lens: ResolvedGenericLens, xMm: number, yMm: number, lambdaNm: number, workingF: number, pupilDiameterMm: number, zMm: number,\n pitch: number, radius: number): NodeResult {\n const lambdaUm = lambdaNm / 1000, r = Math.hypot(xMm, yMm), H = Math.min(1, r / lens.halfDiagonalMm);\n const cosPhi = r > 0 ? xMm / r : 1, sinPhi = r > 0 ? yMm / r : 0;\n // Lateral colour: radial displacement L·R·H·D(λ), µm.\n const shift = lens.character.lateralColor.fraction * lens.halfDiagonalMm * 1000 * H * genericLensDispersion(lambdaNm);\n const delta = Math.min(lambdaUm * workingF / 2, pitch / 4);\n let size = 64;\n // The FFT period must hold the window, or (when the PSF is much smaller than the window, for large pixels) the PSF itself:\n // the geometric blur plus 16·λ·N_w of Airy rings (the energy beyond, about 1 %, folds back into the period).\n const psfExtentUm = 2 * (geometricRadiusMicrometers(lens, H, lambdaUm, workingF) + 16 * lambdaUm * workingF);\n while (size * delta < Math.min(2.5 * (radius + 0.5) * pitch, psfExtentUm) + 2 * Math.abs(shift)) size *= 2;\n for (;;) {\n if (size > MAXIMUM_TRANSFORM) throw new InvalidScientificInputError(\"The catalogue lens PSF needs an FFT larger than \" + MAXIMUM_TRANSFORM + \" per axis.\");\n // Pupil pitch: δ · p_pupil = λ·z / size (mm).\n const pupilPitchMm = lambdaUm / 1000 * zMm / (size * delta / 1000), half = pupilDiameterMm / 2, reach = Math.floor(half / pupilPitchMm);\n const re = new Float64Array(size * size), im = new Float64Array(size * size), rowUsed = new Uint8Array(size);\n let open = 0, phaseStep = 0;\n const opd = new Float64Array((2 * reach + 1) * (2 * reach + 1)).fill(NaN);\n for (let v = -reach; v <= reach; v++) for (let u = -reach; u <= reach; u++) {\n const px = u * pupilPitchMm / half, py = v * pupilPitchMm / half;\n if (px * px + py * py > 1 + 1e-12) continue;\n const w = opdMicrometers(lens, H, cosPhi, sinPhi, lambdaUm, px, py), phase = 2 * Math.PI * w / lambdaUm;\n opd[(v + reach) * (2 * reach + 1) + u + reach] = w;\n const index = ((v + size) % size) * size + (u + size) % size;\n re[index] = Math.cos(phase); im[index] = Math.sin(phase); rowUsed[(v + size) % size] = 1; open++;\n }\n const width = 2 * reach + 1;\n for (let j = 0; j < width; j++) for (let i = 0; i < width; i++) {\n const w = opd[j * width + i]!;\n if (Number.isNaN(w)) continue;\n if (i + 1 < width && !Number.isNaN(opd[j * width + i + 1]!)) phaseStep = Math.max(phaseStep, Math.abs(opd[j * width + i + 1]! - w) / lambdaUm);\n if (j + 1 < width && !Number.isNaN(opd[(j + 1) * width + i]!)) phaseStep = Math.max(phaseStep, Math.abs(opd[(j + 1) * width + i]! - w) / lambdaUm);\n }\n if (open < 9) throw new InvalidScientificInputError(\"The catalogue lens PSF pupil has fewer than 9 samples.\");\n if (phaseStep > MAXIMUM_PHASE_STEP_WAVES) { size *= 2; continue; }\n const cos = new Float64Array(size / 2), sin = new Float64Array(size / 2);\n for (let k = 0; k < size / 2; k++) { cos[k] = Math.cos(2 * Math.PI * k / size); sin[k] = Math.sin(2 * Math.PI * k / size); }\n const rowRe = new Float64Array(size), rowIm = new Float64Array(size);\n for (let y = 0; y < size; y++) {\n if (!rowUsed[y]) continue;\n rowRe.set(re.subarray(y * size, (y + 1) * size)); rowIm.set(im.subarray(y * size, (y + 1) * size));\n radix2Fft(rowRe, rowIm, size, cos, sin);\n re.set(rowRe, y * size); im.set(rowIm, y * size);\n }\n const colRe = new Float64Array(size), colIm = new Float64Array(size);\n const ox = overlaps(size, delta, shift * cosPhi, pitch, radius), oy = overlaps(size, delta, shift * sinPhi, pitch, radius);\n const w2 = 2 * radius + 1, kernel = new Float64Array(w2 * w2);\n let total = 0, inside = 0;\n for (let x = 0; x < size; x++) {\n for (let y = 0; y < size; y++) { colRe[y] = re[y * size + x]!; colIm[y] = im[y * size + x]!; }\n radix2Fft(colRe, colIm, size, cos, sin);\n const cx = ox.cell[x]!, cx2 = ox.cell2[x]!, wx = ox.weight[x]!, wx2 = ox.weight2[x]!;\n for (let y = 0; y < size; y++) {\n const intensity = colRe[y]! * colRe[y]! + colIm[y]! * colIm[y]!;\n total += intensity;\n if (cx < 0) continue;\n const cy = oy.cell[y]!;\n if (cy < 0) continue;\n const cy2 = oy.cell2[y]!, wy = oy.weight[y]!, wy2 = oy.weight2[y]!;\n // Row index increases with image +Y (the quadrature's orientation).\n kernel[cy * w2 + cx]! += intensity * wx * wy; inside += intensity * wx * wy;\n if (cx2 >= 0) { kernel[cy * w2 + cx2]! += intensity * wx2 * wy; inside += intensity * wx2 * wy; }\n if (cy2 >= 0) {\n kernel[cy2 * w2 + cx]! += intensity * wx * wy2; inside += intensity * wx * wy2;\n if (cx2 >= 0) { kernel[cy2 * w2 + cx2]! += intensity * wx2 * wy2; inside += intensity * wx2 * wy2; }\n }\n }\n }\n if (!(total > 0) || !(inside > 0)) throw new InvalidScientificInputError(\"The catalogue lens PSF has no energy in its window.\");\n return { kernel, total, transform: size, phaseStep };\n }\n}\n\nfunction mirror(kernel: Float64Array, radius: number, flipX: boolean, flipY: boolean): Float64Array {\n const w = 2 * radius + 1, out = new Float64Array(kernel.length);\n for (let j = 0; j < w; j++) for (let i = 0; i < w; i++) out[(flipY ? w - 1 - j : j) * w + (flipX ? w - 1 - i : i)] = kernel[j * w + i]!;\n return out;\n}\n\n/** Thin-lens image distance z (mm), pupil diameter D = f/N (mm) and working f-number z/D at a finite focus. */\nfunction pupilGeometry(lens: ResolvedGenericLens, focusDistanceM: number): { z: number; D: number; workingF: number } {\n const f = lens.focalLengthMm, d = focusDistanceM * 1000;\n if (!(d > f)) throw new InvalidScientificInputError(\"The focus distance must exceed the focal length.\");\n const z = 1 / (1 / f - 1 / d), D = f / lens.character.fNumber;\n return { z, D, workingF: z / D };\n}\n\n/**\n * An upper bound of the aberration PSF's kernel radius in sites (the window is then narrowed to keep at most\n * {@link GENERIC_LENS_PSF_WINDOW_TRUNCATION} of every node's energy outside): the largest transverse ray aberration 2·N_w·|∂W/∂ρ| over the pupil at the frame\n * corner and every wavelength node, plus the lateral-colour shift, plus the Airy third dark ring 3.24·λ·N_w at 780 nm, rounded up\n * to whole sites (at least 1, at most {@link GENERIC_LENS_PSF_MAXIMUM_KERNEL_RADIUS_SITES}).\n */\nexport function genericLensPsfKernelRadius(input: { lens: ResolvedGenericLens; focusDistanceM: number; sitePitchMicrometers: number }): number {\n const { lens, sitePitchMicrometers: pitch } = input, { workingF } = pupilGeometry(lens, input.focusDistanceM);\n const longest = GENERIC_LENS_PSF_WAVELENGTHS_NM[GENERIC_LENS_PSF_WAVELENGTHS_NM.length - 1]! / 1000;\n let reachUm = 0;\n for (const nm of GENERIC_LENS_PSF_WAVELENGTHS_NM) {\n const shift = Math.abs(lens.character.lateralColor.fraction * lens.halfDiagonalMm * 1000 * genericLensDispersion(nm));\n reachUm = Math.max(reachUm, geometricRadiusMicrometers(lens, 1, nm / 1000, workingF) + shift);\n }\n reachUm += 3.24 * longest * workingF;\n return Math.min(GENERIC_LENS_PSF_MAXIMUM_KERNEL_RADIUS_SITES, Math.max(1, Math.ceil(reachUm / pitch - 0.5)));\n}\n\n/**\n * Builds the catalogue lens's sampled PSF profile for the environment PSF quadrature: 5 × 5 field nodes × 5 wavelengths, each\n * kernel on the site lattice. Engine-owned (parsed once). Deterministic: the same input gives the same profile.\n */\nexport function createGenericLensPsfProfile(input: GenericLensPsfInput): GenericLensPsf {\n const { lens, sitePitchMicrometers: pitch } = input;\n const f = lens.focalLengthMm, N = lens.character.fNumber, { z, D, workingF } = pupilGeometry(lens, input.focusDistanceM);\n const ex = input.fieldHalfExtentMm, fh = input.frameHalfMm;\n if (!(ex.x > fh.x / 2 && ex.y > fh.y / 2 && fh.x > 0 && fh.y > 0)) throw new InvalidScientificInputError(\"The PSF field extent must exceed half the frame.\");\n const xs = [0, fh.x / 2, ex.x], ys = [0, fh.y / 2, ex.y];\n const bound = genericLensPsfKernelRadius({ lens, focusDistanceM: input.focusDistanceM, sitePitchMicrometers: pitch });\n const quadrant = new Map<string, NodeResult>();\n let minimumTransform = Infinity, maximumTransform = 0, phaseStep = 0;\n for (const x of xs) for (const y of ys) for (const nm of GENERIC_LENS_PSF_WAVELENGTHS_NM) {\n const node = nodeKernel(lens, x, y, nm, workingF, D, z, pitch, bound);\n minimumTransform = Math.min(minimumTransform, node.transform);\n maximumTransform = Math.max(maximumTransform, node.transform); phaseStep = Math.max(phaseStep, node.phaseStep);\n quadrant.set(x + \":\" + y + \":\" + nm, node);\n }\n // The window: the smallest radius that keeps at most 1 % of every node's energy outside it (at most the bound).\n const outside = (r: number): number => {\n let worst = 0;\n for (const node of quadrant.values()) {\n let inside = 0;\n for (let j = bound - r; j <= bound + r; j++) for (let i = bound - r; i <= bound + r; i++) inside += node.kernel[j * (2 * bound + 1) + i]!;\n worst = Math.max(worst, 1 - inside / node.total);\n }\n return worst;\n };\n let radius = 1;\n while (radius < bound && outside(radius) > GENERIC_LENS_PSF_WINDOW_TRUNCATION) radius++;\n const truncated = Math.max(0, outside(radius));\n const crop = (node: NodeResult): Float64Array => {\n const w0 = 2 * bound + 1, w1 = 2 * radius + 1, out = new Float64Array(w1 * w1);\n let sum = 0;\n for (let j = 0; j < w1; j++) for (let i = 0; i < w1; i++) { const v = node.kernel[(j + bound - radius) * w0 + i + bound - radius]!; out[j * w1 + i] = v; sum += v; }\n for (let k = 0; k < out.length; k++) out[k] = out[k]! / sum;\n return out;\n };\n const extra = input.extraKernel, kernelRadius = radius + (extra ? extra.radius : 0), w = 2 * kernelRadius + 1;\n const fieldX = [-ex.x, -fh.x / 2, 0, fh.x / 2, ex.x], fieldY = [-ex.y, -fh.y / 2, 0, fh.y / 2, ex.y];\n const uncertainty = { kind: \"not-quantified\" as const, limitation: \"Generic catalogue lens PSF: Photivra's own Seidel coefficients, not a measured lens.\" };\n const nodes: LensSampledPsfGridNode[] = [];\n const focusDiopters = 1 / input.focusDistanceM;\n for (const x of fieldX) for (const y of fieldY) for (const nm of GENERIC_LENS_PSF_WAVELENGTHS_NM) {\n const base = quadrant.get(Math.abs(x) + \":\" + Math.abs(y) + \":\" + nm)!;\n let kernel = mirror(crop(base), radius, x < 0, y < 0);\n if (extra) kernel = convolveSiteKernels(kernel, radius, extra.weights, extra.radius);\n nodes.push({ nodeId: \"pv-\" + x.toFixed(6) + \"-\" + y.toFixed(6) + \"-\" + nm,\n coordinate: { focalLengthMm: f, focusDiopters, apertureFNumber: N, fieldXmm: x, fieldYmm: y, wavelengthNm: nm, signedDefocusImagePlaneMicrometers: 0 },\n kernel: { widthSamples: w, heightSamples: w, samplePitchMicrometersX: pitch, samplePitchMicrometersY: pitch, centerSampleX: kernelRadius, centerSampleY: kernelRadius,\n normalizedIntensity: Array.from(kernel) },\n bestFocusImagePlaneOffsetMicrometers: 0, relativePupilThroughputFactor: 1, evidence: input.evidence, uncertainty });\n }\n const profile: LensSampledPsfProfile = { schemaVersion: \"0.1.0\", profileId: \"photivra-\" + lens.lensId + \":psf\", profileVersion: \"1.0.0\", scientificStatus: \"approximation\",\n opticalDomain: \"lens-primary-optical-path-only\", coordinateSystem: \"image-plane-metric\", fieldAxes: \"+X right, +Y up\", kernelEnergyNormalization: \"unit-energy-shape\",\n interpolation: \"bounded-regular-grid-centroid-aligned\", throughputOwnership: \"separate-relative-pupil-throughput-factor\",\n responseIncludes: { diffraction: true, aberration: true, defocus: extra !== undefined, pupilClippingShape: false },\n sensorOpticalStackIncluded: false, sensorSamplingIncluded: false, reconstructionIncluded: false, strayLightIncluded: false,\n axes: { focalLengthMm: [f], focusDiopters: [focusDiopters], apertureFNumber: [N], fieldXmm: fieldX, fieldYmm: fieldY, wavelengthNm: [...GENERIC_LENS_PSF_WAVELENGTHS_NM],\n signedDefocusImagePlaneMicrometers: [0] }, nodes, evidence: input.evidence,\n limitations: [\"Generic catalogue lens (#549): scalar Fraunhofer PSF of Photivra's own Seidel wavefront with lateral colour, integrated over site cells; not a measured lens.\",\n \"Field and wavelength nodes are interpolated with centroid alignment; between nodes the PSF is a blend, not a recomputed PSF.\"] };\n markEngineOwnedLensSampledPsfProfile(profile);\n return { profile, aberrationKernelRadiusSites: radius, kernelRadiusSites: kernelRadius, maximumTruncatedEnergyFraction: truncated,\n transformSize: { minimum: minimumTransform, maximum: maximumTransform }, maximumPhaseStepWaves: phaseStep, fieldXmm: fieldX, fieldYmm: fieldY,\n wavelengthsNm: [...GENERIC_LENS_PSF_WAVELENGTHS_NM] };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"generic-lens-psf.js","sourceRoot":"","sources":["../../src/optics/generic-lens-psf.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * The PSF of a generic catalogue lens (#549) on a sensor's site lattice, as a field- and wavelength-dependent sampled PSF\n * profile for the environment PSF quadrature (`simulateCapture` `lens.catalogue`).\n *\n * Model (an approximation): scalar Fraunhofer diffraction of a uniform circular pupil of diameter D = f/N carrying the\n * lens's Seidel wavefront (`resolveGenericLens`; the expansion of `createWavefrontPupilGrid`, Hopkins 1950; Wyant & Creath\n * 1992), propagated to the thin-lens image distance z (working f-number z/D; Goodman, Introduction to Fourier Optics, ch. 4-6).\n * U(x) = Σ_pupil exp(i·2π·W(u)/λ)·exp(−i·2π·x·u/(λ·z)) is evaluated with a zero-padded radix-2 FFT (Cooley & Tukey 1965) on\n * an image grid of pitch δ = min(λ·N_w/2, p/4) (p the site pitch), and |U|² is integrated over each site's square cell (exact\n * overlap of each δ-square with the cell). Lateral colour displaces the PSF radially by Δr(λ). The kernel window is (2R + 1)²\n * sites; the energy outside it is reported and put back by unit-sum renormalisation, as for `lens.diffraction`.\n *\n * Nodes: a 5 × 5 regular grid of field points (0, ±half the frame, ±the frame edge plus the kernel reach) × 5 wavelengths\n * (380, 450, 550, 650, 780 nm), each computed at its own field azimuth (no rotation of a radial node), interpolated by the\n * engine's centroid-aligned multilinear scheme. The quadrant x, y ≥ 0 is computed and mirrored (the Seidel PSF of a mirrored\n * field point is the mirrored PSF).\n *\n * Kernel orientation: a kernel's row index increases with image +Y, the orientation the environment PSF quadrature applies\n * (`sensorPsfSourcePoint`), so coma and lateral colour point away from the optical axis in the rendered image.\n */\n\nimport { InvalidScientificInputError } from \"../core/validation.js\";\nimport type { EvidenceProvenance } from \"../core/evidence-provenance.js\";\nimport { genericLensDispersion, type ResolvedGenericLens } from \"../equipment/generic-lens-catalogue.js\";\nimport { markEngineOwnedLensSampledPsfProfile, type LensSampledPsfGridNode, type LensSampledPsfProfile } from \"./lens-psf-profile.js\";\nimport { convolveSiteKernels } from \"./defocus-disc-kernel.js\";\nimport { createDefocusBokehSiteKernel, type DefocusBokehSiteKernel, type ResolvedDefocusBokehOptions } from \"./defocus-bokeh-kernel.js\";\n\n/** Wavelength nodes of a catalogue PSF profile, nm (they span the facade's 380–780 nm quadrature). */\nexport const GENERIC_LENS_PSF_WAVELENGTHS_NM = /* @__PURE__ */ Object.freeze([380, 450, 550, 650, 780] as const);\n/** Largest kernel radius of the aberration PSF in sites (before any defocus disc is convolved in). */\nexport const GENERIC_LENS_PSF_MAXIMUM_KERNEL_RADIUS_SITES = 12;\n/** Largest kernel radius in sites of the catalogue PSF with a defocus disc convolved in (`simulateCapture` refuses more: cost). */\nexport const GENERIC_LENS_PSF_MAXIMUM_COMBINED_RADIUS_SITES = 16;\n/** Energy fraction a node may leave outside the chosen kernel window (it is put back by renormalisation and reported). */\nexport const GENERIC_LENS_PSF_WINDOW_TRUNCATION = 0.03;\n/** Largest FFT size per axis. */\nconst MAXIMUM_TRANSFORM = 2048;\n/** Largest optical-path step between neighbouring pupil samples, in waves (Nyquist is 0.5). */\nconst MAXIMUM_PHASE_STEP_WAVES = 0.35;\nconst DESIGN_WAVELENGTH_UM = 0.55;\n\nexport interface GenericLensPsfInput {\n /** The lens resolved at the capture's f-number and focus distance (`resolveGenericLens`). */\n lens: ResolvedGenericLens;\n /** Finite focus distance, m (the thin-lens image distance sets the propagation distance). */\n focusDistanceM: number;\n sitePitchMicrometers: number;\n /** Half extent of the field the profile must cover, mm (the frame's half width and height plus the PSF and query reach). */\n fieldHalfExtentMm: { x: number; y: number };\n /** The frame's half width and height, mm (the inner field nodes sit at half of them). */\n frameHalfMm: { x: number; y: number };\n /** Optional site kernel (2R_d + 1)² to convolve into each node, by its field point (mm, +Y up): the `lens.defocus` bokeh kernel. */\n extraKernel?: { radius: number; clipped?: boolean; at(fieldXmm: number, fieldYmm: number): Float64Array };\n evidence: readonly EvidenceProvenance[];\n}\n\nexport interface GenericLensPsf {\n profile: LensSampledPsfProfile;\n /** Radius of the aberration PSF window, sites, and of the applied kernel (with `extraKernel`). */\n aberrationKernelRadiusSites: number;\n kernelRadiusSites: number;\n /** Largest energy fraction outside the aberration window over the nodes (put back by renormalisation). */\n maximumTruncatedEnergyFraction: number;\n /** FFT sizes used (smallest, largest) and the largest pupil phase step, waves. */\n transformSize: { minimum: number; maximum: number };\n maximumPhaseStepWaves: number;\n /** Field node coordinates, mm, and wavelengths, nm. */\n fieldXmm: readonly number[];\n fieldYmm: readonly number[];\n wavelengthsNm: readonly number[];\n}\n\n/** In-place iterative radix-2 FFT, exp(−i·2π·k·m/n). */\nfunction radix2Fft(re: Float64Array, im: Float64Array, n: number, cos: Float64Array, sin: Float64Array): void {\n for (let i = 1, j = 0; i < n; i++) {\n let bit = n >> 1;\n for (; j & bit; bit >>= 1) j ^= bit;\n j ^= bit;\n if (i < j) { let t = re[i]!; re[i] = re[j]!; re[j] = t; t = im[i]!; im[i] = im[j]!; im[j] = t; }\n }\n for (let size = 2; size <= n; size <<= 1) {\n const half = size >> 1, step = n / size;\n for (let start = 0; start < n; start += size) for (let k = 0; k < half; k++) {\n const c = cos[k * step]!, s = sin[k * step]!, a = start + k, b = a + half;\n const tr = re[b]! * c + im[b]! * s, ti = im[b]! * c - re[b]! * s;\n re[b] = re[a]! - tr; im[b] = im[a]! - ti; re[a] = re[a]! + tr; im[a] = im[a]! + ti;\n }\n }\n}\n\n/** One axis's overlap of δ-squares centred at positions (s·δ + shift) with site cells [(i − ½)p, (i + ½)p], i ∈ [−R, R]. */\nfunction overlaps(count: number, delta: number, shift: number, pitch: number, radius: number): { cell: Int32Array; weight: Float64Array; cell2: Int32Array; weight2: Float64Array } {\n const cell = new Int32Array(count).fill(-1), weight = new Float64Array(count), cell2 = new Int32Array(count).fill(-1), weight2 = new Float64Array(count);\n for (let k = 0; k < count; k++) {\n const signed = k < count / 2 ? k : k - count, centre = signed * delta + shift, lo = centre - delta / 2, hi = centre + delta / 2;\n const first = Math.floor(lo / pitch + 0.5), last = Math.floor(hi / pitch + 0.5);\n for (let i = first; i <= last && i <= first + 1; i++) {\n if (i < -radius || i > radius) continue;\n const w = (Math.min(hi, (i + 0.5) * pitch) - Math.max(lo, (i - 0.5) * pitch)) / delta;\n if (w <= 0) continue;\n if (cell[k] === -1) { cell[k] = i + radius; weight[k] = w; } else { cell2[k] = i + radius; weight2[k] = w; }\n }\n }\n return { cell, weight, cell2, weight2 };\n}\n\n/** A node's energy per site cell over the (2R₀ + 1)² window (not normalised) and the whole period's energy. */\ninterface NodeResult { kernel: Float64Array; total: number; transform: number; phaseStep: number }\n\n/** Seidel OPD (µm) at normalised pupil (px, py) for a field point at height H and azimuth φ, at wavelength λ (µm). */\nfunction opdMicrometers(lens: ResolvedGenericLens, H: number, cosPhi: number, sinPhi: number, lambdaUm: number, px: number, py: number): number {\n const a = lens.character.aberrations, r2 = px * px + py * py, along = px * cosPhi + py * sinPhi;\n const defocus = a.balancingDefocusWaves + a.axialColorWaves * genericLensDispersion(lambdaUm * 1000);\n // Positive coma W131 sends the comet's flare away from the axis in the image (H ρ³ cos(θ − φ), with the FFT sign above).\n return DESIGN_WAVELENGTH_UM * (defocus * r2 + a.sphericalWaves * r2 * r2 + a.comaWaves * H * r2 * along + a.astigmatismWaves * H * H * along * along + a.fieldCurvatureWaves * H * H * r2);\n}\n\n/** Largest transverse ray aberration 2·N_w·|∂W/∂ρ| (µm) over the pupil, from a 33 × 33 grid. */\nfunction geometricRadiusMicrometers(lens: ResolvedGenericLens, H: number, lambdaUm: number, workingF: number): number {\n let largest = 0;\n const n = 33, h = 1e-4;\n for (let j = 0; j < n; j++) for (let i = 0; i < n; i++) {\n const px = -1 + 2 * i / (n - 1), py = -1 + 2 * j / (n - 1);\n if (px * px + py * py > 1) continue;\n const gx = (opdMicrometers(lens, H, 1, 0, lambdaUm, px + h, py) - opdMicrometers(lens, H, 1, 0, lambdaUm, px - h, py)) / (2 * h);\n const gy = (opdMicrometers(lens, H, 1, 0, lambdaUm, px, py + h) - opdMicrometers(lens, H, 1, 0, lambdaUm, px, py - h)) / (2 * h);\n largest = Math.max(largest, Math.hypot(gx, gy));\n }\n return 2 * workingF * largest;\n}\n\nfunction nodeKernel(lens: ResolvedGenericLens, xMm: number, yMm: number, lambdaNm: number, workingF: number, pupilDiameterMm: number, zMm: number,\n pitch: number, radius: number): NodeResult {\n const lambdaUm = lambdaNm / 1000, r = Math.hypot(xMm, yMm), H = Math.min(1, r / lens.halfDiagonalMm);\n const cosPhi = r > 0 ? xMm / r : 1, sinPhi = r > 0 ? yMm / r : 0;\n // Lateral colour: radial displacement L·R·H·D(λ), µm.\n const shift = lens.character.lateralColor.fraction * lens.halfDiagonalMm * 1000 * H * genericLensDispersion(lambdaNm);\n const delta = Math.min(lambdaUm * workingF / 2, pitch / 4);\n let size = 64;\n // The FFT period must hold the window, or (when the PSF is much smaller than the window, for large pixels) the PSF itself:\n // the geometric blur plus 16·λ·N_w of Airy rings (the energy beyond, about 1 %, folds back into the period).\n const psfExtentUm = 2 * (geometricRadiusMicrometers(lens, H, lambdaUm, workingF) + 16 * lambdaUm * workingF);\n while (size * delta < Math.min(2.5 * (radius + 0.5) * pitch, psfExtentUm) + 2 * Math.abs(shift)) size *= 2;\n for (;;) {\n if (size > MAXIMUM_TRANSFORM) throw new InvalidScientificInputError(\"The catalogue lens PSF needs an FFT larger than \" + MAXIMUM_TRANSFORM + \" per axis.\");\n // Pupil pitch: δ · p_pupil = λ·z / size (mm).\n const pupilPitchMm = lambdaUm / 1000 * zMm / (size * delta / 1000), half = pupilDiameterMm / 2, reach = Math.floor(half / pupilPitchMm);\n const re = new Float64Array(size * size), im = new Float64Array(size * size), rowUsed = new Uint8Array(size);\n let open = 0, phaseStep = 0;\n const opd = new Float64Array((2 * reach + 1) * (2 * reach + 1)).fill(NaN);\n for (let v = -reach; v <= reach; v++) for (let u = -reach; u <= reach; u++) {\n const px = u * pupilPitchMm / half, py = v * pupilPitchMm / half;\n if (px * px + py * py > 1 + 1e-12) continue;\n const w = opdMicrometers(lens, H, cosPhi, sinPhi, lambdaUm, px, py), phase = 2 * Math.PI * w / lambdaUm;\n opd[(v + reach) * (2 * reach + 1) + u + reach] = w;\n const index = ((v + size) % size) * size + (u + size) % size;\n re[index] = Math.cos(phase); im[index] = Math.sin(phase); rowUsed[(v + size) % size] = 1; open++;\n }\n const width = 2 * reach + 1;\n for (let j = 0; j < width; j++) for (let i = 0; i < width; i++) {\n const w = opd[j * width + i]!;\n if (Number.isNaN(w)) continue;\n if (i + 1 < width && !Number.isNaN(opd[j * width + i + 1]!)) phaseStep = Math.max(phaseStep, Math.abs(opd[j * width + i + 1]! - w) / lambdaUm);\n if (j + 1 < width && !Number.isNaN(opd[(j + 1) * width + i]!)) phaseStep = Math.max(phaseStep, Math.abs(opd[(j + 1) * width + i]! - w) / lambdaUm);\n }\n if (open < 9) throw new InvalidScientificInputError(\"The catalogue lens PSF pupil has fewer than 9 samples.\");\n if (phaseStep > MAXIMUM_PHASE_STEP_WAVES) { size *= 2; continue; }\n const cos = new Float64Array(size / 2), sin = new Float64Array(size / 2);\n for (let k = 0; k < size / 2; k++) { cos[k] = Math.cos(2 * Math.PI * k / size); sin[k] = Math.sin(2 * Math.PI * k / size); }\n const rowRe = new Float64Array(size), rowIm = new Float64Array(size);\n for (let y = 0; y < size; y++) {\n if (!rowUsed[y]) continue;\n rowRe.set(re.subarray(y * size, (y + 1) * size)); rowIm.set(im.subarray(y * size, (y + 1) * size));\n radix2Fft(rowRe, rowIm, size, cos, sin);\n re.set(rowRe, y * size); im.set(rowIm, y * size);\n }\n const colRe = new Float64Array(size), colIm = new Float64Array(size);\n const ox = overlaps(size, delta, shift * cosPhi, pitch, radius), oy = overlaps(size, delta, shift * sinPhi, pitch, radius);\n const w2 = 2 * radius + 1, kernel = new Float64Array(w2 * w2);\n let total = 0, inside = 0;\n for (let x = 0; x < size; x++) {\n for (let y = 0; y < size; y++) { colRe[y] = re[y * size + x]!; colIm[y] = im[y * size + x]!; }\n radix2Fft(colRe, colIm, size, cos, sin);\n const cx = ox.cell[x]!, cx2 = ox.cell2[x]!, wx = ox.weight[x]!, wx2 = ox.weight2[x]!;\n for (let y = 0; y < size; y++) {\n const intensity = colRe[y]! * colRe[y]! + colIm[y]! * colIm[y]!;\n total += intensity;\n if (cx < 0) continue;\n const cy = oy.cell[y]!;\n if (cy < 0) continue;\n const cy2 = oy.cell2[y]!, wy = oy.weight[y]!, wy2 = oy.weight2[y]!;\n // Row index increases with image +Y (the quadrature's orientation).\n kernel[cy * w2 + cx]! += intensity * wx * wy; inside += intensity * wx * wy;\n if (cx2 >= 0) { kernel[cy * w2 + cx2]! += intensity * wx2 * wy; inside += intensity * wx2 * wy; }\n if (cy2 >= 0) {\n kernel[cy2 * w2 + cx]! += intensity * wx * wy2; inside += intensity * wx * wy2;\n if (cx2 >= 0) { kernel[cy2 * w2 + cx2]! += intensity * wx2 * wy2; inside += intensity * wx2 * wy2; }\n }\n }\n }\n if (!(total > 0) || !(inside > 0)) throw new InvalidScientificInputError(\"The catalogue lens PSF has no energy in its window.\");\n return { kernel, total, transform: size, phaseStep };\n }\n}\n\nfunction mirror(kernel: Float64Array, radius: number, flipX: boolean, flipY: boolean): Float64Array {\n const w = 2 * radius + 1, out = new Float64Array(kernel.length);\n for (let j = 0; j < w; j++) for (let i = 0; i < w; i++) out[(flipY ? w - 1 - j : j) * w + (flipX ? w - 1 - i : i)] = kernel[j * w + i]!;\n return out;\n}\n\n/** Thin-lens image distance z (mm), pupil diameter D = f/N (mm) and working f-number z/D at a finite focus. */\nfunction pupilGeometry(lens: ResolvedGenericLens, focusDistanceM: number): { z: number; D: number; workingF: number } {\n const f = lens.focalLengthMm, d = focusDistanceM * 1000;\n if (!(d > f)) throw new InvalidScientificInputError(\"The focus distance must exceed the focal length.\");\n const z = 1 / (1 / f - 1 / d), D = f / lens.character.fNumber;\n return { z, D, workingF: z / D };\n}\n\n/**\n * An upper bound of the aberration PSF's kernel radius in sites (the window is then narrowed to keep at most\n * {@link GENERIC_LENS_PSF_WINDOW_TRUNCATION} of every node's energy outside): the largest transverse ray aberration 2·N_w·|∂W/∂ρ| over the pupil at the frame\n * corner and every wavelength node, plus the lateral-colour shift, plus the Airy third dark ring 3.24·λ·N_w at 780 nm, rounded up\n * to whole sites (at least 1, at most {@link GENERIC_LENS_PSF_MAXIMUM_KERNEL_RADIUS_SITES}).\n */\nexport function genericLensPsfKernelRadius(input: { lens: ResolvedGenericLens; focusDistanceM: number; sitePitchMicrometers: number }): number {\n const { lens, sitePitchMicrometers: pitch } = input, { workingF } = pupilGeometry(lens, input.focusDistanceM);\n const longest = GENERIC_LENS_PSF_WAVELENGTHS_NM[GENERIC_LENS_PSF_WAVELENGTHS_NM.length - 1]! / 1000;\n let reachUm = 0;\n for (const nm of GENERIC_LENS_PSF_WAVELENGTHS_NM) {\n const shift = Math.abs(lens.character.lateralColor.fraction * lens.halfDiagonalMm * 1000 * genericLensDispersion(nm));\n reachUm = Math.max(reachUm, geometricRadiusMicrometers(lens, 1, nm / 1000, workingF) + shift);\n }\n reachUm += 3.24 * longest * workingF;\n return Math.min(GENERIC_LENS_PSF_MAXIMUM_KERNEL_RADIUS_SITES, Math.max(1, Math.ceil(reachUm / pitch - 0.5)));\n}\n\n/**\n * Builds the catalogue lens's sampled PSF profile for the environment PSF quadrature: 5 × 5 field nodes × 5 wavelengths, each\n * kernel on the site lattice. Engine-owned (parsed once). Deterministic: the same input gives the same profile.\n */\nexport function createGenericLensPsfProfile(input: GenericLensPsfInput): GenericLensPsf {\n const { lens, sitePitchMicrometers: pitch } = input;\n const f = lens.focalLengthMm, N = lens.character.fNumber, { z, D, workingF } = pupilGeometry(lens, input.focusDistanceM);\n const ex = input.fieldHalfExtentMm, fh = input.frameHalfMm;\n if (!(ex.x > fh.x / 2 && ex.y > fh.y / 2 && fh.x > 0 && fh.y > 0)) throw new InvalidScientificInputError(\"The PSF field extent must exceed half the frame.\");\n const xs = [0, fh.x / 2, ex.x], ys = [0, fh.y / 2, ex.y];\n const bound = genericLensPsfKernelRadius({ lens, focusDistanceM: input.focusDistanceM, sitePitchMicrometers: pitch });\n const quadrant = new Map<string, NodeResult>();\n let minimumTransform = Infinity, maximumTransform = 0, phaseStep = 0;\n for (const x of xs) for (const y of ys) for (const nm of GENERIC_LENS_PSF_WAVELENGTHS_NM) {\n const node = nodeKernel(lens, x, y, nm, workingF, D, z, pitch, bound);\n minimumTransform = Math.min(minimumTransform, node.transform);\n maximumTransform = Math.max(maximumTransform, node.transform); phaseStep = Math.max(phaseStep, node.phaseStep);\n quadrant.set(x + \":\" + y + \":\" + nm, node);\n }\n // The window: the smallest radius that keeps at most 1 % of every node's energy outside it (at most the bound).\n const outside = (r: number): number => {\n let worst = 0;\n for (const node of quadrant.values()) {\n let inside = 0;\n for (let j = bound - r; j <= bound + r; j++) for (let i = bound - r; i <= bound + r; i++) inside += node.kernel[j * (2 * bound + 1) + i]!;\n worst = Math.max(worst, 1 - inside / node.total);\n }\n return worst;\n };\n let radius = 1;\n while (radius < bound && outside(radius) > GENERIC_LENS_PSF_WINDOW_TRUNCATION) radius++;\n const truncated = Math.max(0, outside(radius));\n const crop = (node: NodeResult): Float64Array => {\n const w0 = 2 * bound + 1, w1 = 2 * radius + 1, out = new Float64Array(w1 * w1);\n let sum = 0;\n for (let j = 0; j < w1; j++) for (let i = 0; i < w1; i++) { const v = node.kernel[(j + bound - radius) * w0 + i + bound - radius]!; out[j * w1 + i] = v; sum += v; }\n for (let k = 0; k < out.length; k++) out[k] = out[k]! / sum;\n return out;\n };\n const extra = input.extraKernel, kernelRadius = radius + (extra ? extra.radius : 0), w = 2 * kernelRadius + 1;\n const fieldX = [-ex.x, -fh.x / 2, 0, fh.x / 2, ex.x], fieldY = [-ex.y, -fh.y / 2, 0, fh.y / 2, ex.y];\n const uncertainty = { kind: \"not-quantified\" as const, limitation: \"Generic catalogue lens PSF: Photivra's own Seidel coefficients, not a measured lens.\" };\n const nodes: LensSampledPsfGridNode[] = [];\n const focusDiopters = 1 / input.focusDistanceM;\n for (const x of fieldX) for (const y of fieldY) for (const nm of GENERIC_LENS_PSF_WAVELENGTHS_NM) {\n const base = quadrant.get(Math.abs(x) + \":\" + Math.abs(y) + \":\" + nm)!;\n let kernel = mirror(crop(base), radius, x < 0, y < 0);\n if (extra) kernel = convolveSiteKernels(kernel, radius, extra.at(x, y), extra.radius);\n nodes.push({ nodeId: \"pv-\" + x.toFixed(6) + \"-\" + y.toFixed(6) + \"-\" + nm,\n coordinate: { focalLengthMm: f, focusDiopters, apertureFNumber: N, fieldXmm: x, fieldYmm: y, wavelengthNm: nm, signedDefocusImagePlaneMicrometers: 0 },\n kernel: { widthSamples: w, heightSamples: w, samplePitchMicrometersX: pitch, samplePitchMicrometersY: pitch, centerSampleX: kernelRadius, centerSampleY: kernelRadius,\n normalizedIntensity: Array.from(kernel) },\n bestFocusImagePlaneOffsetMicrometers: 0, relativePupilThroughputFactor: 1, evidence: input.evidence, uncertainty });\n }\n const profile: LensSampledPsfProfile = { schemaVersion: \"0.1.0\", profileId: \"photivra-\" + lens.lensId + \":psf\", profileVersion: \"1.0.0\", scientificStatus: \"approximation\",\n opticalDomain: \"lens-primary-optical-path-only\", coordinateSystem: \"image-plane-metric\", fieldAxes: \"+X right, +Y up\", kernelEnergyNormalization: \"unit-energy-shape\",\n interpolation: \"bounded-regular-grid-centroid-aligned\", throughputOwnership: \"separate-relative-pupil-throughput-factor\",\n responseIncludes: { diffraction: true, aberration: true, defocus: extra !== undefined, pupilClippingShape: extra?.clipped === true },\n sensorOpticalStackIncluded: false, sensorSamplingIncluded: false, reconstructionIncluded: false, strayLightIncluded: false,\n axes: { focalLengthMm: [f], focusDiopters: [focusDiopters], apertureFNumber: [N], fieldXmm: fieldX, fieldYmm: fieldY, wavelengthNm: [...GENERIC_LENS_PSF_WAVELENGTHS_NM],\n signedDefocusImagePlaneMicrometers: [0] }, nodes, evidence: input.evidence,\n limitations: [\"Generic catalogue lens (#549): scalar Fraunhofer PSF of Photivra's own Seidel wavefront with lateral colour, integrated over site cells; not a measured lens.\",\n \"Field and wavelength nodes are interpolated with centroid alignment; between nodes the PSF is a blend, not a recomputed PSF.\"] };\n markEngineOwnedLensSampledPsfProfile(profile);\n return { profile, aberrationKernelRadiusSites: radius, kernelRadiusSites: kernelRadius, maximumTruncatedEnergyFraction: truncated,\n transformSize: { minimum: minimumTransform, maximum: maximumTransform }, maximumPhaseStepWaves: phaseStep, fieldXmm: fieldX, fieldYmm: fieldY,\n wavelengthsNm: [...GENERIC_LENS_PSF_WAVELENGTHS_NM] };\n}\n\n/**\n * #567: the catalogue lens's own bokeh kernel for `lens.defocus` (#553's shaped kernel with `lens.character.bokeh`), as the\n * PSF's field-dependent extra kernel. The defocus is referred to the lens's focus, the balanced one of its PSF (W020 = −W040):\n * the ray map (σc/2 + bρ²)·P of the paraxial focus gains −(b/2)·P, so the kernel is #553's for the signed blur σc − b. Rows are\n * flipped from #553's (+Y down) to the profile's (+Y up). With a cat's eye each field point (tangent x/f, y/f: the rectilinear\n * chief ray, distortion neglected) has its own kernel, padded to the axis kernel's radius (clipping only narrows the blur). Each\n * call builds its kernel (the profile calls it once per field and wavelength node: 125 small kernels). `catsEye` false leaves it out.\n */\nexport function genericLensBokehKernel(lens: ResolvedGenericLens, diameterSites: number, side: 1 | -1, pitch: number, catsEye: boolean):\n { axis: DefocusBokehSiteKernel; radius: number; clipped: boolean; at(fieldXmm: number, fieldYmm: number): Float64Array } {\n const b = lens.character.bokeh, options = (catsEye ? b : { blades: b.blades, sphericalAberration: b.sphericalAberration }) as ResolvedDefocusBokehOptions, N = lens.character.fNumber, f = lens.focalLengthMm;\n const s = side * diameterSites - 8 * N * options.sphericalAberration!.w040Micrometers / pitch;\n const build = (x: number, y: number): DefocusBokehSiteKernel => createDefocusBokehSiteKernel({ diameterSites: Math.abs(s), side: s < 0 ? -1 : 1, fNumber: N,\n focalLengthMm: f, pitchMicrometers: pitch, options, field: { x: x / f, y: y / f } });\n const axis = build(0, 0), R = axis.radius, w = 2 * R + 1;\n return { axis, radius: R, clipped: !!options.catsEye, at(x, y): Float64Array {\n const k = options.catsEye ? build(x, y) : axis, r = k.radius, out = new Float64Array(w * w);\n for (let j = -r; j <= r; j++) for (let i = -r; i <= r; i++) out[(R - j) * w + i + R] = k.weights[(j + r) * k.width + i + r]!;\n return out;\n } };\n}\n"]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { FrontOfLensFilterProfile } from "./front-of-lens-filter.js";
|
|
2
|
+
/** Attenuations, in stops, of the generic ND presets. */
|
|
3
|
+
export declare const GENERIC_ND_FILTER_STOPS: readonly [3, 6, 10];
|
|
4
|
+
/** One of the generic ND preset attenuations: 3, 6 or 10 stops. */
|
|
5
|
+
export type GenericNdFilterStops = (typeof GENERIC_ND_FILTER_STOPS)[number];
|
|
6
|
+
/**
|
|
7
|
+
* Frozen generic ND filter profiles keyed by stops: `GENERIC_ND_FILTER_PROFILES[10]` transmits
|
|
8
|
+
* exactly 1/1024. Spectrally flat over 380–780 nm (air), idealized (`scientificStatus:
|
|
9
|
+
* "approximation"`), unbranded. 1/125 s with the 10-stop preset gives 1024/125 ≈ 8.19 s in
|
|
10
|
+
* `calculateFilteredExposureTime`.
|
|
11
|
+
*/
|
|
12
|
+
export declare const GENERIC_ND_FILTER_PROFILES: Readonly<Record<GenericNdFilterStops, FrontOfLensFilterProfile>>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
import { freezeOwnedData } from "../core/owned-data.js";
|
|
3
|
+
/** Attenuations, in stops, of the generic ND presets. */
|
|
4
|
+
export const GENERIC_ND_FILTER_STOPS = /* @__PURE__ */ Object.freeze([3, 6, 10]);
|
|
5
|
+
function idealNdProfile(stops) {
|
|
6
|
+
const evidence = [{
|
|
7
|
+
sourceOrigin: "photivra",
|
|
8
|
+
sourceReference: "photivra:generic-nd-filter-presets:578",
|
|
9
|
+
reuseStatus: "photivra-owned",
|
|
10
|
+
note: `Idealized: transmittance exactly 2^-${stops} by the definition of a ${stops}-stop filter (owner decision 2026-11-09); not measured, not modelled on any product.`
|
|
11
|
+
}];
|
|
12
|
+
return {
|
|
13
|
+
schemaVersion: "0.1.0",
|
|
14
|
+
filterId: `generic-nd-${stops}-stop`,
|
|
15
|
+
profileVersion: "1.0.0",
|
|
16
|
+
identityScope: "photivra-generic-unbranded",
|
|
17
|
+
position: "front-of-lens",
|
|
18
|
+
scientificStatus: "approximation",
|
|
19
|
+
wavelengthBasis: "air",
|
|
20
|
+
wavelengthRangeNanometers: { minimum: 380, maximum: 780 },
|
|
21
|
+
transmission: {
|
|
22
|
+
kind: "neutral-linear-transmission",
|
|
23
|
+
linearTransmissionFactor: { value: 2 ** -stops, evidence }
|
|
24
|
+
},
|
|
25
|
+
uncertainty: {
|
|
26
|
+
kind: "not-quantified",
|
|
27
|
+
limitation: "Idealized nominal filter: real ND filters deviate from their rating and are not perfectly flat across wavelengths."
|
|
28
|
+
},
|
|
29
|
+
polarizationModeled: false,
|
|
30
|
+
wavelengthChangingBehaviorModeled: false,
|
|
31
|
+
evidence,
|
|
32
|
+
limitations: [
|
|
33
|
+
`Idealized spectrally flat ${stops}-stop filter (transmittance exactly 2^-${stops}); not a measured filter.`
|
|
34
|
+
]
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Frozen generic ND filter profiles keyed by stops: `GENERIC_ND_FILTER_PROFILES[10]` transmits
|
|
39
|
+
* exactly 1/1024. Spectrally flat over 380–780 nm (air), idealized (`scientificStatus:
|
|
40
|
+
* "approximation"`), unbranded. 1/125 s with the 10-stop preset gives 1024/125 ≈ 8.19 s in
|
|
41
|
+
* `calculateFilteredExposureTime`.
|
|
42
|
+
*/
|
|
43
|
+
export const GENERIC_ND_FILTER_PROFILES = /* @__PURE__ */ freezeOwnedData({
|
|
44
|
+
3: idealNdProfile(3),
|
|
45
|
+
6: idealNdProfile(6),
|
|
46
|
+
10: idealNdProfile(10)
|
|
47
|
+
});
|
|
48
|
+
//# sourceMappingURL=generic-nd-filter-presets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generic-nd-filter-presets.js","sourceRoot":"","sources":["../../src/optics/generic-nd-filter-presets.ts"],"names":[],"mappings":"AAAA,sCAAsC;AAetC,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAGxD,yDAAyD;AACzD,MAAM,CAAC,MAAM,uBAAuB,GAAG,eAAe,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAU,CAAC,CAAC;AAK1F,SAAS,cAAc,CAAC,KAA2B;IACjD,MAAM,QAAQ,GAAkC,CAAC;YAC/C,YAAY,EAAE,UAAU;YACxB,eAAe,EAAE,wCAAwC;YACzD,WAAW,EAAE,gBAAgB;YAC7B,IAAI,EAAE,uCAAuC,KAAK,2BAA2B,KAAK,sFAAsF;SACzK,CAAC,CAAC;IACH,OAAO;QACL,aAAa,EAAE,OAAO;QACtB,QAAQ,EAAE,cAAc,KAAK,OAAO;QACpC,cAAc,EAAE,OAAO;QACvB,aAAa,EAAE,4BAA4B;QAC3C,QAAQ,EAAE,eAAe;QACzB,gBAAgB,EAAE,eAAe;QACjC,eAAe,EAAE,KAAK;QACtB,yBAAyB,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE;QACzD,YAAY,EAAE;YACZ,IAAI,EAAE,6BAA6B;YACnC,wBAAwB,EAAE,EAAE,KAAK,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE;SAC3D;QACD,WAAW,EAAE;YACX,IAAI,EAAE,gBAAgB;YACtB,UAAU,EAAE,oHAAoH;SACjI;QACD,mBAAmB,EAAE,KAAK;QAC1B,iCAAiC,EAAE,KAAK;QACxC,QAAQ;QACR,WAAW,EAAE;YACX,6BAA6B,KAAK,0CAA0C,KAAK,2BAA2B;SAC7G;KACF,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAqE,eAAe,CAAC,eAAe,CAAC;IAC1I,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC;IACpB,CAAC,EAAE,cAAc,CAAC,CAAC,CAAC;IACpB,EAAE,EAAE,cAAc,CAAC,EAAE,CAAC;CACvB,CAAC,CAAC","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Generic, unbranded neutral-density (ND) filter presets: idealized 3-, 6- and 10-stop filters.\n *\n * \"N-stop\" means a transmittance of exactly 2^-N (owner decision 2026-11-09, #578): 3 stops is\n * 1/8, 6 stops 1/64 and 10 stops 1/1024, each exact in binary floating point. The presets are\n * spectrally flat (`neutral-linear-transmission`) over 380–780 nm. They are idealizations, not\n * measurements: `scientificStatus` is `\"approximation\"` and the uncertainty is not quantified,\n * because real ND filters deviate from their nominal rating and are not perfectly flat. Pass one to\n * `calculateFilteredExposureTime` or to any function that takes a front-of-lens filter profile.\n * @see docs/PHYSICS_FOUNDATION.md \"Exposure time with an ND filter\".\n */\n\nimport type { EvidenceProvenance } from \"../core/evidence-provenance.js\";\nimport { freezeOwnedData } from \"../core/owned-data.js\";\nimport type { FrontOfLensFilterProfile } from \"./front-of-lens-filter.js\";\n\n/** Attenuations, in stops, of the generic ND presets. */\nexport const GENERIC_ND_FILTER_STOPS = /* @__PURE__ */ Object.freeze([3, 6, 10] as const);\n\n/** One of the generic ND preset attenuations: 3, 6 or 10 stops. */\nexport type GenericNdFilterStops = (typeof GENERIC_ND_FILTER_STOPS)[number];\n\nfunction idealNdProfile(stops: GenericNdFilterStops): FrontOfLensFilterProfile {\n const evidence: readonly EvidenceProvenance[] = [{\n sourceOrigin: \"photivra\",\n sourceReference: \"photivra:generic-nd-filter-presets:578\",\n reuseStatus: \"photivra-owned\",\n note: `Idealized: transmittance exactly 2^-${stops} by the definition of a ${stops}-stop filter (owner decision 2026-11-09); not measured, not modelled on any product.`\n }];\n return {\n schemaVersion: \"0.1.0\",\n filterId: `generic-nd-${stops}-stop`,\n profileVersion: \"1.0.0\",\n identityScope: \"photivra-generic-unbranded\",\n position: \"front-of-lens\",\n scientificStatus: \"approximation\",\n wavelengthBasis: \"air\",\n wavelengthRangeNanometers: { minimum: 380, maximum: 780 },\n transmission: {\n kind: \"neutral-linear-transmission\",\n linearTransmissionFactor: { value: 2 ** -stops, evidence }\n },\n uncertainty: {\n kind: \"not-quantified\",\n limitation: \"Idealized nominal filter: real ND filters deviate from their rating and are not perfectly flat across wavelengths.\"\n },\n polarizationModeled: false,\n wavelengthChangingBehaviorModeled: false,\n evidence,\n limitations: [\n `Idealized spectrally flat ${stops}-stop filter (transmittance exactly 2^-${stops}); not a measured filter.`\n ]\n };\n}\n\n/**\n * Frozen generic ND filter profiles keyed by stops: `GENERIC_ND_FILTER_PROFILES[10]` transmits\n * exactly 1/1024. Spectrally flat over 380–780 nm (air), idealized (`scientificStatus:\n * \"approximation\"`), unbranded. 1/125 s with the 10-stop preset gives 1024/125 ≈ 8.19 s in\n * `calculateFilteredExposureTime`.\n */\nexport const GENERIC_ND_FILTER_PROFILES: Readonly<Record<GenericNdFilterStops, FrontOfLensFilterProfile>> = /* @__PURE__ */ freezeOwnedData({\n 3: idealNdProfile(3),\n 6: idealNdProfile(6),\n 10: idealNdProfile(10)\n});\n"]}
|
|
@@ -10,12 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { approximationResult } from "../core/calculation-result.js";
|
|
12
12
|
import { InvalidScientificInputError, requirePositiveFinite } from "../core/validation.js";
|
|
13
|
-
import { requireInputObject, requireInputKeys } from "../core/record-validation.js";
|
|
14
|
-
function requireFinite(name, value) {
|
|
15
|
-
if (!Number.isFinite(value)) {
|
|
16
|
-
throw new InvalidScientificInputError(`${name} must be finite.`);
|
|
17
|
-
}
|
|
18
|
-
}
|
|
13
|
+
import { requireInputObject, requireInputKeys, assertNamedFinite as requireFinite } from "../core/record-validation.js";
|
|
19
14
|
function throughputFromSquaredRadius(squaredRadius, coefficients) {
|
|
20
15
|
return (1 +
|
|
21
16
|
coefficients.r2 * squaredRadius +
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"illumination-vignetting.js","sourceRoot":"","sources":["../../src/optics/illumination-vignetting.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Generic illumination falloff across the image (vignetting), as a factor that multiplies linear\n * light.\n *\n * A profile is accepted only if its relative throughput stays strictly positive and never exceeds 1\n * (the value on the optical axis) anywhere in its declared range.\n * @see docs/PHYSICS_FOUNDATION.md for the equations, units, coordinate conventions, known blockers\n * and support limits.\n */\n\nimport {\n approximationResult,\n type CalculationResult\n} from \"../core/calculation-result.js\";\nimport {\n InvalidScientificInputError,\n requirePositiveFinite\n} from \"../core/validation.js\";\nimport type { LensFieldPointMm } from \"./radial-distortion.js\";\nimport { requireInputObject, requireInputKeys } from \"../core/record-validation.js\";\n\nexport interface IlluminationVignettingCoefficients {\n /** Coefficient on normalized radius squared. */\n r2: number;\n /** Coefficient on normalized radius to the fourth power. */\n r4: number;\n /** Coefficient on normalized radius to the sixth power. */\n r6: number;\n}\n\nexport interface IlluminationVignettingProfile {\n /** Physical image-plane radius used to normalize field position, in mm. */\n normalizationRadiusMm: number;\n /** Maximum normalized image-plane radius over which the profile is valid. */\n maximumNormalizedRadius: number;\n /**\n * Generic radial relative-illumination coefficients.\n *\n * Relative linear throughput is:\n * 1 + r2 * rho^2 + r4 * rho^4 + r6 * rho^6\n *\n * where rho is physical image-plane radius / normalizationRadiusMm.\n */\n coefficients: IlluminationVignettingCoefficients;\n}\n\nexport interface CalculateIlluminationVignettingInput {\n /**\n * Ideal image-plane field position relative to the optical axis, in mm.\n *\n * Throughput is evaluated at this ideal field coordinate. Geometric\n * distortion is neither applied nor inverted.\n */\n imagePointMm: LensFieldPointMm;\n profile: IlluminationVignettingProfile;\n}\n\nexport interface IlluminationVignetting {\n imagePointMm: LensFieldPointMm;\n normalizedRadius: number;\n /**\n * Factor that multiplies scene-linear or channel-linear signal.\n *\n * 1 means no attenuation. Values must stay in (0, 1].\n */\n linearThroughputFactor: number;\n /** Positive exposure loss relative to the optical axis, in stops. */\n attenuationStops: number;\n profileMinimumThroughputFactor: number;\n profileMaximumThroughputFactor: number;\n}\n\ninterface ValidatedIlluminationProfile {\n normalizationRadiusMm: number;\n maximumNormalizedRadius: number;\n coefficients: IlluminationVignettingCoefficients;\n minimumThroughputFactor: number;\n maximumThroughputFactor: number;\n}\n\nfunction requireFinite(name: string, value: number): void {\n if (!Number.isFinite(value)) {\n throw new InvalidScientificInputError(`${name} must be finite.`);\n }\n}\n\nfunction throughputFromSquaredRadius(\n squaredRadius: number,\n coefficients: IlluminationVignettingCoefficients\n): number {\n return (\n 1 +\n coefficients.r2 * squaredRadius +\n coefficients.r4 * squaredRadius * squaredRadius +\n coefficients.r6 *\n squaredRadius *\n squaredRadius *\n squaredRadius\n );\n}\n\n/**\n * Real roots of dT/ds, where s = rho². Every interior maximum or minimum of the throughput lies at\n * one of these roots. The validator checks them along with both ends of the range. So a profile\n * that dips below zero, or rises above one, mid-field is rejected even when both ends are valid.\n *\n * The quadratic is scaled before solving and uses the numerically stable q-form roots. This stops a\n * tiny cubic term from erasing the smaller root through cancellation. The radial-distortion\n * validator uses the same scheme.\n */\nfunction throughputCriticalSquaredRadii(\n coefficients: IlluminationVignettingCoefficients\n): number[] {\n // T(s) = 1 + r2*s + r4*s² + r6*s³\n // dT/ds = r2 + 2*r4*s + 3*r6*s²\n const a = 3 * coefficients.r6;\n const b = 2 * coefficients.r4;\n const c = coefficients.r2;\n const coefficientScale = Math.max(Math.abs(a), Math.abs(b), Math.abs(c));\n if (coefficientScale === 0) {\n return [];\n }\n const scaledA = a / coefficientScale;\n const scaledB = b / coefficientScale;\n const scaledC = c / coefficientScale;\n\n if (scaledA === 0) {\n return scaledB === 0 ? [] : [-scaledC / scaledB];\n }\n\n const discriminant = scaledB * scaledB - 4 * scaledA * scaledC;\n if (discriminant < 0) {\n return [];\n }\n const root = Math.sqrt(discriminant);\n const q = -0.5 * (scaledB + (scaledB >= 0 ? root : -root));\n if (q === 0) {\n // Only when b = c = 0: the double root is s = 0.\n return [0];\n }\n return [q / scaledA, scaledC / q];\n}\n\nfunction validateProfile(\n profile: IlluminationVignettingProfile\n): ValidatedIlluminationProfile {\n requirePositiveFinite(\n \"profile.normalizationRadiusMm\",\n profile.normalizationRadiusMm\n );\n requirePositiveFinite(\n \"profile.maximumNormalizedRadius\",\n profile.maximumNormalizedRadius\n );\n requireFinite(\"profile.coefficients.r2\", profile.coefficients.r2);\n requireFinite(\"profile.coefficients.r4\", profile.coefficients.r4);\n requireFinite(\"profile.coefficients.r6\", profile.coefficients.r6);\n\n const maximumSquaredRadius =\n profile.maximumNormalizedRadius * profile.maximumNormalizedRadius;\n const candidates = [\n 0,\n maximumSquaredRadius,\n ...throughputCriticalSquaredRadii(profile.coefficients).filter(\n (value) => value > 0 && value < maximumSquaredRadius\n )\n ];\n const throughputs = candidates.map((squaredRadius) =>\n throughputFromSquaredRadius(squaredRadius, profile.coefficients)\n );\n const minimumThroughputFactor = Math.min(...throughputs);\n const maximumThroughputFactor = Math.max(...throughputs);\n\n if (\n !Number.isFinite(minimumThroughputFactor) ||\n minimumThroughputFactor <= 0\n ) {\n throw new InvalidScientificInputError(\n \"Illumination vignetting profile must keep relative linear throughput strictly greater than zero over maximumNormalizedRadius.\"\n );\n }\n\n if (\n !Number.isFinite(maximumThroughputFactor) ||\n maximumThroughputFactor > 1\n ) {\n throw new InvalidScientificInputError(\n \"Illumination vignetting profile must not amplify relative linear throughput above the optical-axis value of 1.\"\n );\n }\n\n return {\n normalizationRadiusMm: profile.normalizationRadiusMm,\n maximumNormalizedRadius: profile.maximumNormalizedRadius,\n coefficients: { ...profile.coefficients },\n minimumThroughputFactor,\n maximumThroughputFactor\n };\n}\n\n/** The normalized radius and throughput factor at an image point, for a validated profile (the arithmetic of calculateIlluminationVignetting). */\nfunction throughputAt(profile: ValidatedIlluminationProfile, imagePointMm: LensFieldPointMm): { normalizedRadius: number; linearThroughputFactor: number } {\n const radiusMm = Math.hypot(imagePointMm.x, imagePointMm.y);\n const normalizedRadius = radiusMm / profile.normalizationRadiusMm;\n\n if (normalizedRadius > profile.maximumNormalizedRadius) {\n throw new InvalidScientificInputError(\n \"imagePointMm lies outside the illumination vignetting profile maximumNormalizedRadius.\"\n );\n }\n\n const squaredRadius = normalizedRadius * normalizedRadius;\n return { normalizedRadius, linearThroughputFactor: throughputFromSquaredRadius(squaredRadius, profile.coefficients) };\n}\n\n/**\n * @internal (#563) The `linearThroughputFactor` that {@link calculateIlluminationVignetting} returns, from a profile validated once:\n * the same arithmetic and the same errors, without the result envelope, for callers that evaluate one profile at many points\n * (the image-space field factor of `prepareDefocusImageSpaceGeometry`).\n */\nexport function prepareIlluminationVignettingThroughput(profile: IlluminationVignettingProfile): (imagePointMm: LensFieldPointMm) => number {\n const validated = validateProfile(profile);\n return (imagePointMm) => {\n requireFinite(\"imagePointMm.x\", imagePointMm.x);\n requireFinite(\"imagePointMm.y\", imagePointMm.y);\n return throughputAt(validated, imagePointMm).linearThroughputFactor;\n };\n}\n\nfunction assumptions(): readonly string[] {\n return [\n \"Generic rotationally symmetric illumination-vignetting approximation evaluated from ideal image-plane field radius\",\n \"Relative linear throughput is normalized to 1 on the optical axis\",\n \"The model attenuates scene-linear/channel-linear signal only and must be applied before display/gamma encoding\",\n \"The model changes throughput only; it does not alter field coordinates, pupil shape, PSF shape, bokeh, or focus\",\n \"Mechanical/pupil vignetting and cat's-eye bokeh are separate pupil/PSF effects\",\n \"The profile is a generic caller-supplied radial approximation, not calibrated radiometry or a named-lens measurement\"\n ];\n}\n\n/**\n * Calculates generic illumination falloff across the image (vignetting) as a\n * factor that multiplies linear light.\n *\n * A profile is accepted only if its relative throughput stays strictly\n * positive and never exceeds 1 (the value on the optical axis) anywhere in\n * its declared range.\n */\nexport function calculateIlluminationVignetting(\n input: CalculateIlluminationVignettingInput\n): CalculationResult<IlluminationVignetting> {\n requireInputKeys(input, \"calculateIlluminationVignetting\", [\"imagePointMm\", \"profile\"]);\n requireInputObject(input.imagePointMm, \"imagePointMm\");\n requireFinite(\"imagePointMm.x\", input.imagePointMm.x);\n requireFinite(\"imagePointMm.y\", input.imagePointMm.y);\n\n const profile = validateProfile(input.profile);\n const { normalizedRadius, linearThroughputFactor } = throughputAt(profile, input.imagePointMm);\n\n const attenuationStops =\n linearThroughputFactor === 1\n ? 0\n : -Math.log2(linearThroughputFactor);\n\n return approximationResult(\n {\n imagePointMm: { ...input.imagePointMm },\n normalizedRadius,\n linearThroughputFactor,\n attenuationStops,\n profileMinimumThroughputFactor: profile.minimumThroughputFactor,\n profileMaximumThroughputFactor: profile.maximumThroughputFactor\n },\n \"generic-radial-illumination-vignetting\",\n \"1.0.0\",\n assumptions()\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"illumination-vignetting.js","sourceRoot":"","sources":["../../src/optics/illumination-vignetting.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Generic illumination falloff across the image (vignetting), as a factor that multiplies linear\n * light.\n *\n * A profile is accepted only if its relative throughput stays strictly positive and never exceeds 1\n * (the value on the optical axis) anywhere in its declared range.\n * @see docs/PHYSICS_FOUNDATION.md for the equations, units, coordinate conventions, known blockers\n * and support limits.\n */\n\nimport {\n approximationResult,\n type CalculationResult\n} from \"../core/calculation-result.js\";\nimport {\n InvalidScientificInputError,\n requirePositiveFinite\n} from \"../core/validation.js\";\nimport type { LensFieldPointMm } from \"./radial-distortion.js\";\nimport { requireInputObject, requireInputKeys, assertNamedFinite as requireFinite } from \"../core/record-validation.js\";\n\nexport interface IlluminationVignettingCoefficients {\n /** Coefficient on normalized radius squared. */\n r2: number;\n /** Coefficient on normalized radius to the fourth power. */\n r4: number;\n /** Coefficient on normalized radius to the sixth power. */\n r6: number;\n}\n\nexport interface IlluminationVignettingProfile {\n /** Physical image-plane radius used to normalize field position, in mm. */\n normalizationRadiusMm: number;\n /** Maximum normalized image-plane radius over which the profile is valid. */\n maximumNormalizedRadius: number;\n /**\n * Generic radial relative-illumination coefficients.\n *\n * Relative linear throughput is:\n * 1 + r2 * rho^2 + r4 * rho^4 + r6 * rho^6\n *\n * where rho is physical image-plane radius / normalizationRadiusMm.\n */\n coefficients: IlluminationVignettingCoefficients;\n}\n\nexport interface CalculateIlluminationVignettingInput {\n /**\n * Ideal image-plane field position relative to the optical axis, in mm.\n *\n * Throughput is evaluated at this ideal field coordinate. Geometric\n * distortion is neither applied nor inverted.\n */\n imagePointMm: LensFieldPointMm;\n profile: IlluminationVignettingProfile;\n}\n\nexport interface IlluminationVignetting {\n imagePointMm: LensFieldPointMm;\n normalizedRadius: number;\n /**\n * Factor that multiplies scene-linear or channel-linear signal.\n *\n * 1 means no attenuation. Values must stay in (0, 1].\n */\n linearThroughputFactor: number;\n /** Positive exposure loss relative to the optical axis, in stops. */\n attenuationStops: number;\n profileMinimumThroughputFactor: number;\n profileMaximumThroughputFactor: number;\n}\n\ninterface ValidatedIlluminationProfile {\n normalizationRadiusMm: number;\n maximumNormalizedRadius: number;\n coefficients: IlluminationVignettingCoefficients;\n minimumThroughputFactor: number;\n maximumThroughputFactor: number;\n}\n\nfunction throughputFromSquaredRadius(\n squaredRadius: number,\n coefficients: IlluminationVignettingCoefficients\n): number {\n return (\n 1 +\n coefficients.r2 * squaredRadius +\n coefficients.r4 * squaredRadius * squaredRadius +\n coefficients.r6 *\n squaredRadius *\n squaredRadius *\n squaredRadius\n );\n}\n\n/**\n * Real roots of dT/ds, where s = rho². Every interior maximum or minimum of the throughput lies at\n * one of these roots. The validator checks them along with both ends of the range. So a profile\n * that dips below zero, or rises above one, mid-field is rejected even when both ends are valid.\n *\n * The quadratic is scaled before solving and uses the numerically stable q-form roots. This stops a\n * tiny cubic term from erasing the smaller root through cancellation. The radial-distortion\n * validator uses the same scheme.\n */\nfunction throughputCriticalSquaredRadii(\n coefficients: IlluminationVignettingCoefficients\n): number[] {\n // T(s) = 1 + r2*s + r4*s² + r6*s³\n // dT/ds = r2 + 2*r4*s + 3*r6*s²\n const a = 3 * coefficients.r6;\n const b = 2 * coefficients.r4;\n const c = coefficients.r2;\n const coefficientScale = Math.max(Math.abs(a), Math.abs(b), Math.abs(c));\n if (coefficientScale === 0) {\n return [];\n }\n const scaledA = a / coefficientScale;\n const scaledB = b / coefficientScale;\n const scaledC = c / coefficientScale;\n\n if (scaledA === 0) {\n return scaledB === 0 ? [] : [-scaledC / scaledB];\n }\n\n const discriminant = scaledB * scaledB - 4 * scaledA * scaledC;\n if (discriminant < 0) {\n return [];\n }\n const root = Math.sqrt(discriminant);\n const q = -0.5 * (scaledB + (scaledB >= 0 ? root : -root));\n if (q === 0) {\n // Only when b = c = 0: the double root is s = 0.\n return [0];\n }\n return [q / scaledA, scaledC / q];\n}\n\nfunction validateProfile(\n profile: IlluminationVignettingProfile\n): ValidatedIlluminationProfile {\n requirePositiveFinite(\n \"profile.normalizationRadiusMm\",\n profile.normalizationRadiusMm\n );\n requirePositiveFinite(\n \"profile.maximumNormalizedRadius\",\n profile.maximumNormalizedRadius\n );\n requireFinite(\"profile.coefficients.r2\", profile.coefficients.r2);\n requireFinite(\"profile.coefficients.r4\", profile.coefficients.r4);\n requireFinite(\"profile.coefficients.r6\", profile.coefficients.r6);\n\n const maximumSquaredRadius =\n profile.maximumNormalizedRadius * profile.maximumNormalizedRadius;\n const candidates = [\n 0,\n maximumSquaredRadius,\n ...throughputCriticalSquaredRadii(profile.coefficients).filter(\n (value) => value > 0 && value < maximumSquaredRadius\n )\n ];\n const throughputs = candidates.map((squaredRadius) =>\n throughputFromSquaredRadius(squaredRadius, profile.coefficients)\n );\n const minimumThroughputFactor = Math.min(...throughputs);\n const maximumThroughputFactor = Math.max(...throughputs);\n\n if (\n !Number.isFinite(minimumThroughputFactor) ||\n minimumThroughputFactor <= 0\n ) {\n throw new InvalidScientificInputError(\n \"Illumination vignetting profile must keep relative linear throughput strictly greater than zero over maximumNormalizedRadius.\"\n );\n }\n\n if (\n !Number.isFinite(maximumThroughputFactor) ||\n maximumThroughputFactor > 1\n ) {\n throw new InvalidScientificInputError(\n \"Illumination vignetting profile must not amplify relative linear throughput above the optical-axis value of 1.\"\n );\n }\n\n return {\n normalizationRadiusMm: profile.normalizationRadiusMm,\n maximumNormalizedRadius: profile.maximumNormalizedRadius,\n coefficients: { ...profile.coefficients },\n minimumThroughputFactor,\n maximumThroughputFactor\n };\n}\n\n/** The normalized radius and throughput factor at an image point, for a validated profile (the arithmetic of calculateIlluminationVignetting). */\nfunction throughputAt(profile: ValidatedIlluminationProfile, imagePointMm: LensFieldPointMm): { normalizedRadius: number; linearThroughputFactor: number } {\n const radiusMm = Math.hypot(imagePointMm.x, imagePointMm.y);\n const normalizedRadius = radiusMm / profile.normalizationRadiusMm;\n\n if (normalizedRadius > profile.maximumNormalizedRadius) {\n throw new InvalidScientificInputError(\n \"imagePointMm lies outside the illumination vignetting profile maximumNormalizedRadius.\"\n );\n }\n\n const squaredRadius = normalizedRadius * normalizedRadius;\n return { normalizedRadius, linearThroughputFactor: throughputFromSquaredRadius(squaredRadius, profile.coefficients) };\n}\n\n/**\n * @internal (#563) The `linearThroughputFactor` that {@link calculateIlluminationVignetting} returns, from a profile validated once:\n * the same arithmetic and the same errors, without the result envelope, for callers that evaluate one profile at many points\n * (the image-space field factor of `prepareDefocusImageSpaceGeometry`).\n */\nexport function prepareIlluminationVignettingThroughput(profile: IlluminationVignettingProfile): (imagePointMm: LensFieldPointMm) => number {\n const validated = validateProfile(profile);\n return (imagePointMm) => {\n requireFinite(\"imagePointMm.x\", imagePointMm.x);\n requireFinite(\"imagePointMm.y\", imagePointMm.y);\n return throughputAt(validated, imagePointMm).linearThroughputFactor;\n };\n}\n\nfunction assumptions(): readonly string[] {\n return [\n \"Generic rotationally symmetric illumination-vignetting approximation evaluated from ideal image-plane field radius\",\n \"Relative linear throughput is normalized to 1 on the optical axis\",\n \"The model attenuates scene-linear/channel-linear signal only and must be applied before display/gamma encoding\",\n \"The model changes throughput only; it does not alter field coordinates, pupil shape, PSF shape, bokeh, or focus\",\n \"Mechanical/pupil vignetting and cat's-eye bokeh are separate pupil/PSF effects\",\n \"The profile is a generic caller-supplied radial approximation, not calibrated radiometry or a named-lens measurement\"\n ];\n}\n\n/**\n * Calculates generic illumination falloff across the image (vignetting) as a\n * factor that multiplies linear light.\n *\n * A profile is accepted only if its relative throughput stays strictly\n * positive and never exceeds 1 (the value on the optical axis) anywhere in\n * its declared range.\n */\nexport function calculateIlluminationVignetting(\n input: CalculateIlluminationVignettingInput\n): CalculationResult<IlluminationVignetting> {\n requireInputKeys(input, \"calculateIlluminationVignetting\", [\"imagePointMm\", \"profile\"]);\n requireInputObject(input.imagePointMm, \"imagePointMm\");\n requireFinite(\"imagePointMm.x\", input.imagePointMm.x);\n requireFinite(\"imagePointMm.y\", input.imagePointMm.y);\n\n const profile = validateProfile(input.profile);\n const { normalizedRadius, linearThroughputFactor } = throughputAt(profile, input.imagePointMm);\n\n const attenuationStops =\n linearThroughputFactor === 1\n ? 0\n : -Math.log2(linearThroughputFactor);\n\n return approximationResult(\n {\n imagePointMm: { ...input.imagePointMm },\n normalizedRadius,\n linearThroughputFactor,\n attenuationStops,\n profileMinimumThroughputFactor: profile.minimumThroughputFactor,\n profileMaximumThroughputFactor: profile.maximumThroughputFactor\n },\n \"generic-radial-illumination-vignetting\",\n \"1.0.0\",\n assumptions()\n );\n}\n"]}
|
|
@@ -38,7 +38,9 @@ export type LensPsfUncertainty = {
|
|
|
38
38
|
* - `rotationally-symmetric-radial-field-centroid-aligned`: for a rotationally symmetric lens. Nodes
|
|
39
39
|
* are declared only along the +X field axis (fieldYmm = [0], fieldXmm >= 0). A query at field
|
|
40
40
|
* (x, y) is interpolated, with centroid alignment, at radius hypot(x, y). The kernel is then
|
|
41
|
-
* rotated by atan2(y, x) about its centre
|
|
41
|
+
* rotated by atan2(y, x) about its centre, with the kernel row index increasing with image +Y (the
|
|
42
|
+
* convention the environment PSF quadrature applies), so an asymmetric kernel points the same way
|
|
43
|
+
* as in the 2-D grid modes. The sample pitch must be square.
|
|
42
44
|
* Shifts and rotations use bilinear resampling. This smooths the kernel slightly (by at most about
|
|
43
45
|
* one sample). Samples outside the kernel are zero, and the result is renormalised to unit energy.
|
|
44
46
|
*/
|
|
@@ -175,6 +177,7 @@ export interface MtfOnlyPsfRenderabilityAssessment {
|
|
|
175
177
|
reason: "mtf-magnitude-lacks-phase-and-does-not-uniquely-determine-psf";
|
|
176
178
|
diagnosticUseAuthorized: true;
|
|
177
179
|
}
|
|
180
|
+
export declare function parseUncertainty(value: unknown, path: string): LensPsfUncertainty;
|
|
178
181
|
/**
|
|
179
182
|
* Internal: registers a private profile declaration owned by the engine, so that repeated
|
|
180
183
|
* resolveLensSampledPsf calls reuse one parse. The declaration is a structured clone that caller code
|
|
@@ -21,7 +21,7 @@ import { freezeOwnedData } from "../core/owned-data.js";
|
|
|
21
21
|
import { parseEvidenceList } from "../core/evidence-provenance.js";
|
|
22
22
|
import { InvalidScientificInputError } from "../core/validation.js";
|
|
23
23
|
import { parseFocusPlane } from "./focus-state.js";
|
|
24
|
-
import { requireInputKeys,
|
|
24
|
+
import { requireInputKeys, rejectUnknownVariantFields, UNCERTAINTY_VARIANT_FIELDS, requireConfigRecord as requireRecord, requireTrimmedConfigString as requireNonEmptyString, requireConfigFinite as requireFinite, parseConfigScientificStatus as parseStatus, requireConfigNonNegativeSafeInteger as requireNonNegativeSafeInteger, requireConfigPositiveSafeInteger as requirePositiveSafeInteger, requireInputFinite as requireScientificFinite, parseConfigLimitations as parseLimitations, requireConfigFiniteAboveZero as requirePositiveFinite, requireConfigFiniteAtLeastZero as requireNonNegativeFinite, requireInputFiniteAboveZero as requireScientificPositiveFinite, requireConfigUnitInterval as requireUnitInterval } from "../core/record-validation.js";
|
|
25
25
|
export const LENS_SAMPLED_PSF_PROFILE_SCHEMA_VERSION = "0.1.0";
|
|
26
26
|
export const LENS_MTF_DIAGNOSTIC_PROFILE_SCHEMA_VERSION = "0.1.0";
|
|
27
27
|
const LENS_SAMPLED_PSF_INTERPOLATIONS = [
|
|
@@ -38,82 +38,7 @@ const AXIS_KEYS = [
|
|
|
38
38
|
"wavelengthNm",
|
|
39
39
|
"signedDefocusImagePlaneMicrometers"
|
|
40
40
|
];
|
|
41
|
-
function
|
|
42
|
-
if (typeof value !== "object" ||
|
|
43
|
-
value === null ||
|
|
44
|
-
Array.isArray(value)) {
|
|
45
|
-
throw new InvalidConfigurationError(path + " must be an object.");
|
|
46
|
-
}
|
|
47
|
-
if (allowedKeys !== null)
|
|
48
|
-
rejectUnknownFields(value, allowedKeys, path);
|
|
49
|
-
return value;
|
|
50
|
-
}
|
|
51
|
-
function requireNonEmptyString(value, path) {
|
|
52
|
-
if (typeof value !== "string" ||
|
|
53
|
-
value.trim().length === 0) {
|
|
54
|
-
throw new InvalidConfigurationError(path +
|
|
55
|
-
" must be a non-empty string.");
|
|
56
|
-
}
|
|
57
|
-
return value.trim();
|
|
58
|
-
}
|
|
59
|
-
function requireFinite(value, path) {
|
|
60
|
-
if (typeof value !== "number" ||
|
|
61
|
-
!Number.isFinite(value)) {
|
|
62
|
-
throw new InvalidConfigurationError(path + " must be finite.");
|
|
63
|
-
}
|
|
64
|
-
return value;
|
|
65
|
-
}
|
|
66
|
-
function requirePositiveFinite(value, path) {
|
|
67
|
-
const parsed = requireFinite(value, path);
|
|
68
|
-
if (parsed <= 0) {
|
|
69
|
-
throw new InvalidConfigurationError(path +
|
|
70
|
-
" must be greater than zero.");
|
|
71
|
-
}
|
|
72
|
-
return parsed;
|
|
73
|
-
}
|
|
74
|
-
function requireNonNegativeFinite(value, path) {
|
|
75
|
-
const parsed = requireFinite(value, path);
|
|
76
|
-
if (parsed < 0) {
|
|
77
|
-
throw new InvalidConfigurationError(path +
|
|
78
|
-
" must be greater than or equal to zero.");
|
|
79
|
-
}
|
|
80
|
-
return parsed;
|
|
81
|
-
}
|
|
82
|
-
function requireUnitInterval(value, path) {
|
|
83
|
-
const parsed = requireFinite(value, path);
|
|
84
|
-
if (parsed < 0 ||
|
|
85
|
-
parsed > 1) {
|
|
86
|
-
throw new InvalidConfigurationError(path +
|
|
87
|
-
" must lie from zero through one.");
|
|
88
|
-
}
|
|
89
|
-
return parsed;
|
|
90
|
-
}
|
|
91
|
-
function requirePositiveSafeInteger(value, path) {
|
|
92
|
-
if (typeof value !== "number" ||
|
|
93
|
-
!Number.isSafeInteger(value) ||
|
|
94
|
-
value <= 0) {
|
|
95
|
-
throw new InvalidConfigurationError(path +
|
|
96
|
-
" must be a positive safe integer.");
|
|
97
|
-
}
|
|
98
|
-
return value;
|
|
99
|
-
}
|
|
100
|
-
function requireNonNegativeSafeInteger(value, path) {
|
|
101
|
-
if (typeof value !== "number" ||
|
|
102
|
-
!Number.isSafeInteger(value) ||
|
|
103
|
-
value < 0) {
|
|
104
|
-
throw new InvalidConfigurationError(path +
|
|
105
|
-
" must be a non-negative safe integer.");
|
|
106
|
-
}
|
|
107
|
-
return value;
|
|
108
|
-
}
|
|
109
|
-
function parseStatus(value, path) {
|
|
110
|
-
if (value !== "calibrated" &&
|
|
111
|
-
value !== "approximation") {
|
|
112
|
-
throw new InvalidConfigurationError(path + " is invalid.");
|
|
113
|
-
}
|
|
114
|
-
return value;
|
|
115
|
-
}
|
|
116
|
-
function parseUncertainty(value, path) {
|
|
41
|
+
export function parseUncertainty(value, path) {
|
|
117
42
|
const record = requireRecord(value, path, null);
|
|
118
43
|
rejectUnknownVariantFields(record, "kind", UNCERTAINTY_VARIANT_FIELDS, path);
|
|
119
44
|
if (record.kind === "relative") {
|
|
@@ -133,21 +58,6 @@ function parseUncertainty(value, path) {
|
|
|
133
58
|
}
|
|
134
59
|
throw new InvalidConfigurationError(path + ".kind is invalid.");
|
|
135
60
|
}
|
|
136
|
-
function parseLimitations(value, path) {
|
|
137
|
-
if (!Array.isArray(value)) {
|
|
138
|
-
throw new InvalidConfigurationError(path + " must be an array.");
|
|
139
|
-
}
|
|
140
|
-
const parsed = value.map((entry, index) => requireNonEmptyString(entry, path +
|
|
141
|
-
"[" +
|
|
142
|
-
index +
|
|
143
|
-
"]"));
|
|
144
|
-
if (new Set(parsed).size !==
|
|
145
|
-
parsed.length) {
|
|
146
|
-
throw new InvalidConfigurationError(path +
|
|
147
|
-
" must not contain duplicates.");
|
|
148
|
-
}
|
|
149
|
-
return parsed;
|
|
150
|
-
}
|
|
151
61
|
function parseAxis(value, path, options = {}) {
|
|
152
62
|
if (!Array.isArray(value) ||
|
|
153
63
|
value.length === 0) {
|
|
@@ -518,21 +428,6 @@ function focusDiopters(focus) {
|
|
|
518
428
|
: 1 /
|
|
519
429
|
parsed.distanceM;
|
|
520
430
|
}
|
|
521
|
-
function requireScientificFinite(value, path) {
|
|
522
|
-
if (typeof value !== "number" ||
|
|
523
|
-
!Number.isFinite(value)) {
|
|
524
|
-
throw new InvalidScientificInputError(path + " must be finite.");
|
|
525
|
-
}
|
|
526
|
-
return value;
|
|
527
|
-
}
|
|
528
|
-
function requireScientificPositiveFinite(value, path) {
|
|
529
|
-
const parsed = requireScientificFinite(value, path);
|
|
530
|
-
if (parsed <= 0) {
|
|
531
|
-
throw new InvalidScientificInputError(path +
|
|
532
|
-
" must be greater than zero.");
|
|
533
|
-
}
|
|
534
|
-
return parsed;
|
|
535
|
-
}
|
|
536
431
|
function bracketAxis(values, target, path) {
|
|
537
432
|
const minimum = values[0];
|
|
538
433
|
const maximum = values[values.length - 1];
|
|
@@ -784,20 +679,26 @@ function interpolateKernelCentroidAligned(weighted) {
|
|
|
784
679
|
});
|
|
785
680
|
return normalizedKernel(first, values);
|
|
786
681
|
}
|
|
787
|
-
/**
|
|
682
|
+
/**
|
|
683
|
+
* Rotates a kernel by angleRadians (counter-clockwise from image +X towards image +Y) about its centre sample.
|
|
684
|
+
* The row index increases with image +Y, the convention the environment PSF quadrature applies (`sensorPsfSourcePoint`:
|
|
685
|
+
* tap (kx, ky) lands at image offset (+(kx − cx)·pₓ, +(ky − cy)·p_y), +Y up), so a kernel declared along +X and rotated to
|
|
686
|
+
* field azimuth atan2(y, x) points the same way in the rendered image as a 2-D grid node declared at (x, y). Before 2.19.0
|
|
687
|
+
* this read rows as image −Y, which mirrored asymmetric kernels in y (#566).
|
|
688
|
+
*/
|
|
788
689
|
function rotateKernel(kernel, angleRadians) {
|
|
789
690
|
const cos = Math.cos(angleRadians);
|
|
790
691
|
const sin = Math.sin(angleRadians);
|
|
791
692
|
const values = [];
|
|
792
693
|
for (let row = 0; row < kernel.heightSamples; row += 1) {
|
|
793
|
-
//
|
|
794
|
-
const y = kernel.centerSampleY
|
|
694
|
+
// Row index increases with image +Y (sensorPsfSourcePoint).
|
|
695
|
+
const y = row - kernel.centerSampleY;
|
|
795
696
|
for (let column = 0; column < kernel.widthSamples; column += 1) {
|
|
796
697
|
const x = column - kernel.centerSampleX;
|
|
797
698
|
// Inverse rotation: destination (x, y) samples source R(-angle) (x, y).
|
|
798
699
|
const sourceX = cos * x + sin * y;
|
|
799
700
|
const sourceY = -sin * x + cos * y;
|
|
800
|
-
values.push(bilinearSample(kernel, kernel.centerSampleX + sourceX, kernel.centerSampleY
|
|
701
|
+
values.push(bilinearSample(kernel, kernel.centerSampleX + sourceX, kernel.centerSampleY + sourceY));
|
|
801
702
|
}
|
|
802
703
|
}
|
|
803
704
|
return normalizedKernel(kernel, values);
|