@photivra/engine 0.6.0 → 1.0.1
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/AGENTS.md +674 -0
- package/CHANGELOG.md +191 -0
- package/CITATION.cff +1 -1
- package/CONTRIBUTING.md +76 -0
- package/DCO +33 -0
- package/NODE_SUPPORT.md +37 -0
- package/NOTICE +2 -0
- package/README.md +139 -72
- package/SECURITY.md +55 -0
- package/THIRD_PARTY.md +63 -0
- package/dist/camera/equivalent-focal-length.d.ts +9 -0
- package/dist/camera/equivalent-focal-length.d.ts.map +1 -1
- package/dist/camera/equivalent-focal-length.js +9 -0
- package/dist/camera/equivalent-focal-length.js.map +1 -1
- package/dist/camera/field-of-view.d.ts +13 -0
- package/dist/camera/field-of-view.d.ts.map +1 -1
- package/dist/camera/field-of-view.js +13 -0
- package/dist/camera/field-of-view.js.map +1 -1
- package/dist/camera/projected-object-size.d.ts +8 -0
- package/dist/camera/projected-object-size.d.ts.map +1 -1
- package/dist/camera/projected-object-size.js +8 -0
- package/dist/camera/projected-object-size.js.map +1 -1
- package/dist/capture/capture-export-metadata.d.ts +60 -0
- package/dist/capture/capture-export-metadata.d.ts.map +1 -0
- package/dist/capture/capture-export-metadata.js +62 -0
- package/dist/capture/capture-export-metadata.js.map +1 -0
- package/dist/capture/environment-raw-producer.d.ts +55 -0
- package/dist/capture/environment-raw-producer.d.ts.map +1 -0
- package/dist/capture/environment-raw-producer.js +88 -0
- package/dist/capture/environment-raw-producer.js.map +1 -0
- package/dist/capture/export-jpeg.d.ts +12 -0
- package/dist/capture/export-jpeg.d.ts.map +1 -0
- package/dist/capture/export-jpeg.js +126 -0
- package/dist/capture/export-jpeg.js.map +1 -0
- package/dist/capture/export-tiff.d.ts +45 -0
- package/dist/capture/export-tiff.d.ts.map +1 -0
- package/dist/capture/export-tiff.js +129 -0
- package/dist/capture/export-tiff.js.map +1 -0
- package/dist/capture/focus-control.d.ts +210 -0
- package/dist/capture/focus-control.d.ts.map +1 -0
- package/dist/capture/focus-control.js +664 -0
- package/dist/capture/focus-control.js.map +1 -0
- package/dist/capture/linear-encoding.d.ts +59 -0
- package/dist/capture/linear-encoding.d.ts.map +1 -0
- package/dist/capture/linear-encoding.js +98 -0
- package/dist/capture/linear-encoding.js.map +1 -0
- package/dist/capture/photographic-export.d.ts +135 -0
- package/dist/capture/photographic-export.d.ts.map +1 -0
- package/dist/capture/photographic-export.js +273 -0
- package/dist/capture/photographic-export.js.map +1 -0
- package/dist/capture/raw-frame-limits.d.ts +12 -0
- package/dist/capture/raw-frame-limits.d.ts.map +1 -0
- package/dist/capture/raw-frame-limits.js +13 -0
- package/dist/capture/raw-frame-limits.js.map +1 -0
- package/dist/capture/raw-frame-reconstruction.d.ts +48 -0
- package/dist/capture/raw-frame-reconstruction.d.ts.map +1 -0
- package/dist/capture/raw-frame-reconstruction.js +146 -0
- package/dist/capture/raw-frame-reconstruction.js.map +1 -0
- package/dist/capture/release-sequence.d.ts +120 -0
- package/dist/capture/release-sequence.d.ts.map +1 -0
- package/dist/capture/release-sequence.js +446 -0
- package/dist/capture/release-sequence.js.map +1 -0
- package/dist/capture/sensor-raw-frame.d.ts +34 -0
- package/dist/capture/sensor-raw-frame.d.ts.map +1 -0
- package/dist/capture/sensor-raw-frame.js +106 -0
- package/dist/capture/sensor-raw-frame.js.map +1 -0
- package/dist/capture/sensor-raw-producer.d.ts +51 -0
- package/dist/capture/sensor-raw-producer.d.ts.map +1 -0
- package/dist/capture/sensor-raw-producer.js +235 -0
- package/dist/capture/sensor-raw-producer.js.map +1 -0
- package/dist/capture/simulated-capture.d.ts +125 -0
- package/dist/capture/simulated-capture.d.ts.map +1 -0
- package/dist/capture/simulated-capture.js +248 -0
- package/dist/capture/simulated-capture.js.map +1 -0
- package/dist/color/capture-color.d.ts +73 -0
- package/dist/color/capture-color.d.ts.map +1 -0
- package/dist/color/capture-color.js +145 -0
- package/dist/color/capture-color.js.map +1 -0
- package/dist/color/sensor-color-development.d.ts +23 -0
- package/dist/color/sensor-color-development.d.ts.map +1 -0
- package/dist/color/sensor-color-development.js +56 -0
- package/dist/color/sensor-color-development.js.map +1 -0
- package/dist/color/white-balance.d.ts +175 -0
- package/dist/color/white-balance.d.ts.map +1 -0
- package/dist/color/white-balance.js +606 -0
- package/dist/color/white-balance.js.map +1 -0
- package/dist/composition/image-formation-plan.d.ts +481 -0
- package/dist/composition/image-formation-plan.d.ts.map +1 -0
- package/dist/composition/image-formation-plan.js +2499 -0
- package/dist/composition/image-formation-plan.js.map +1 -0
- package/dist/composition/plan-consumer.d.ts +53 -0
- package/dist/composition/plan-consumer.d.ts.map +1 -0
- package/dist/composition/plan-consumer.js +119 -0
- package/dist/composition/plan-consumer.js.map +1 -0
- package/dist/core/calculation-result.d.ts.map +1 -1
- package/dist/core/calculation-result.js +6 -0
- package/dist/core/calculation-result.js.map +1 -1
- package/dist/core/canonical-json.d.ts +18 -0
- package/dist/core/canonical-json.d.ts.map +1 -0
- package/dist/core/canonical-json.js +44 -0
- package/dist/core/canonical-json.js.map +1 -0
- package/dist/core/configuration-error.d.ts +6 -0
- package/dist/core/configuration-error.d.ts.map +1 -1
- package/dist/core/configuration-error.js +6 -0
- package/dist/core/configuration-error.js.map +1 -1
- package/dist/core/evidence-provenance.d.ts +6 -0
- package/dist/core/evidence-provenance.d.ts.map +1 -1
- package/dist/core/evidence-provenance.js +7 -0
- package/dist/core/evidence-provenance.js.map +1 -1
- package/dist/core/image-formation.d.ts +9 -3
- package/dist/core/image-formation.d.ts.map +1 -1
- package/dist/core/image-formation.js +29 -5
- package/dist/core/image-formation.js.map +1 -1
- package/dist/core/owned-data.d.ts +25 -0
- package/dist/core/owned-data.d.ts.map +1 -0
- package/dist/core/owned-data.js +34 -0
- package/dist/core/owned-data.js.map +1 -0
- package/dist/core/record-validation.d.ts +17 -0
- package/dist/core/record-validation.d.ts.map +1 -0
- package/dist/core/record-validation.js +44 -0
- package/dist/core/record-validation.js.map +1 -0
- package/dist/core/scientific-assurance.d.ts +101 -0
- package/dist/core/scientific-assurance.d.ts.map +1 -0
- package/dist/core/scientific-assurance.js +301 -0
- package/dist/core/scientific-assurance.js.map +1 -0
- package/dist/core/spectral-composition.d.ts +106 -0
- package/dist/core/spectral-composition.d.ts.map +1 -0
- package/dist/core/spectral-composition.js +334 -0
- package/dist/core/spectral-composition.js.map +1 -0
- package/dist/core/spectral.d.ts +34 -0
- package/dist/core/spectral.d.ts.map +1 -0
- package/dist/core/spectral.js +57 -0
- package/dist/core/spectral.js.map +1 -0
- package/dist/core/validation.d.ts +6 -0
- package/dist/core/validation.d.ts.map +1 -1
- package/dist/core/validation.js +6 -0
- package/dist/core/validation.js.map +1 -1
- package/dist/core/version.d.ts +9 -0
- package/dist/core/version.d.ts.map +1 -0
- package/dist/core/version.js +10 -0
- package/dist/core/version.js.map +1 -0
- package/dist/equipment/exposure-capabilities.d.ts +125 -0
- package/dist/equipment/exposure-capabilities.d.ts.map +1 -0
- package/dist/equipment/exposure-capabilities.js +391 -0
- package/dist/equipment/exposure-capabilities.js.map +1 -0
- package/dist/equipment/generic-tier-assets.d.ts +82 -0
- package/dist/equipment/generic-tier-assets.d.ts.map +1 -0
- package/dist/equipment/generic-tier-assets.js +119 -0
- package/dist/equipment/generic-tier-assets.js.map +1 -0
- package/dist/equipment/generic-tier-presets.d.ts +57 -0
- package/dist/equipment/generic-tier-presets.d.ts.map +1 -0
- package/dist/equipment/generic-tier-presets.js +122 -0
- package/dist/equipment/generic-tier-presets.js.map +1 -0
- package/dist/equipment/iso-capabilities.d.ts +143 -0
- package/dist/equipment/iso-capabilities.d.ts.map +1 -0
- package/dist/equipment/iso-capabilities.js +578 -0
- package/dist/equipment/iso-capabilities.js.map +1 -0
- package/dist/equipment/metering-capabilities.d.ts +58 -0
- package/dist/equipment/metering-capabilities.d.ts.map +1 -0
- package/dist/equipment/metering-capabilities.js +151 -0
- package/dist/equipment/metering-capabilities.js.map +1 -0
- package/dist/equipment/release-capabilities.d.ts +33 -0
- package/dist/equipment/release-capabilities.d.ts.map +1 -0
- package/dist/equipment/release-capabilities.js +176 -0
- package/dist/equipment/release-capabilities.js.map +1 -0
- package/dist/exposure/exposure-duration-control.d.ts +72 -0
- package/dist/exposure/exposure-duration-control.d.ts.map +1 -0
- package/dist/exposure/exposure-duration-control.js +161 -0
- package/dist/exposure/exposure-duration-control.js.map +1 -0
- package/dist/exposure/exposure-mode-resolver.d.ts +637 -0
- package/dist/exposure/exposure-mode-resolver.d.ts.map +1 -0
- package/dist/exposure/exposure-mode-resolver.js +1905 -0
- package/dist/exposure/exposure-mode-resolver.js.map +1 -0
- package/dist/exposure/exposure.d.ts +8 -0
- package/dist/exposure/exposure.d.ts.map +1 -1
- package/dist/exposure/exposure.js +8 -0
- package/dist/exposure/exposure.js.map +1 -1
- package/dist/exposure/flash.d.ts +179 -0
- package/dist/exposure/flash.d.ts.map +1 -0
- package/dist/exposure/flash.js +644 -0
- package/dist/exposure/flash.js.map +1 -0
- package/dist/exposure/metering-scene-radiance.d.ts +72 -0
- package/dist/exposure/metering-scene-radiance.d.ts.map +1 -0
- package/dist/exposure/metering-scene-radiance.js +222 -0
- package/dist/exposure/metering-scene-radiance.js.map +1 -0
- package/dist/exposure/metering-target.d.ts +67 -0
- package/dist/exposure/metering-target.d.ts.map +1 -0
- package/dist/exposure/metering-target.js +265 -0
- package/dist/exposure/metering-target.js.map +1 -0
- package/dist/exposure/metering-temporal.d.ts +76 -0
- package/dist/exposure/metering-temporal.d.ts.map +1 -0
- package/dist/exposure/metering-temporal.js +210 -0
- package/dist/exposure/metering-temporal.js.map +1 -0
- package/dist/exposure/metering.d.ts +124 -0
- package/dist/exposure/metering.d.ts.map +1 -0
- package/dist/exposure/metering.js +422 -0
- package/dist/exposure/metering.js.map +1 -0
- package/dist/exposure/program-line.d.ts +29 -0
- package/dist/exposure/program-line.d.ts.map +1 -0
- package/dist/exposure/program-line.js +126 -0
- package/dist/exposure/program-line.js.map +1 -0
- package/dist/index.d.ts +87 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +85 -6
- package/dist/index.js.map +1 -1
- package/dist/motion/camera-rotation.d.ts +16 -0
- package/dist/motion/camera-rotation.d.ts.map +1 -1
- package/dist/motion/camera-rotation.js +16 -0
- package/dist/motion/camera-rotation.js.map +1 -1
- package/dist/motion/capture-rotation-inverse-mapping.d.ts +13 -0
- package/dist/motion/capture-rotation-inverse-mapping.d.ts.map +1 -1
- package/dist/motion/capture-rotation-inverse-mapping.js +13 -0
- package/dist/motion/capture-rotation-inverse-mapping.js.map +1 -1
- package/dist/motion/capture-rotation-temporal-quadrature.d.ts +15 -0
- package/dist/motion/capture-rotation-temporal-quadrature.d.ts.map +1 -1
- package/dist/motion/capture-rotation-temporal-quadrature.js +15 -0
- package/dist/motion/capture-rotation-temporal-quadrature.js.map +1 -1
- package/dist/motion/capture-rotation-trajectory.d.ts +15 -0
- package/dist/motion/capture-rotation-trajectory.d.ts.map +1 -1
- package/dist/motion/capture-rotation-trajectory.js +15 -0
- package/dist/motion/capture-rotation-trajectory.js.map +1 -1
- package/dist/motion/capture-translation-parallax-temporal-quadrature.d.ts +119 -0
- package/dist/motion/capture-translation-parallax-temporal-quadrature.d.ts.map +1 -0
- package/dist/motion/capture-translation-parallax-temporal-quadrature.js +263 -0
- package/dist/motion/capture-translation-parallax-temporal-quadrature.js.map +1 -0
- package/dist/motion/extended-object-projection.d.ts +175 -0
- package/dist/motion/extended-object-projection.d.ts.map +1 -0
- package/dist/motion/extended-object-projection.js +402 -0
- package/dist/motion/extended-object-projection.js.map +1 -0
- package/dist/motion/projected-motion.d.ts +11 -0
- package/dist/motion/projected-motion.d.ts.map +1 -1
- package/dist/motion/projected-motion.js +11 -0
- package/dist/motion/projected-motion.js.map +1 -1
- package/dist/optics/aperture.d.ts +9 -0
- package/dist/optics/aperture.d.ts.map +1 -1
- package/dist/optics/aperture.js +9 -0
- package/dist/optics/aperture.js.map +1 -1
- package/dist/optics/circle-of-confusion.d.ts +8 -0
- package/dist/optics/circle-of-confusion.d.ts.map +1 -1
- package/dist/optics/circle-of-confusion.js +8 -0
- package/dist/optics/circle-of-confusion.js.map +1 -1
- package/dist/optics/complex-pupil-psf.d.ts +128 -0
- package/dist/optics/complex-pupil-psf.d.ts.map +1 -0
- package/dist/optics/complex-pupil-psf.js +462 -0
- package/dist/optics/complex-pupil-psf.js.map +1 -0
- package/dist/optics/depth-of-field.d.ts +18 -0
- package/dist/optics/depth-of-field.d.ts.map +1 -1
- package/dist/optics/depth-of-field.js +29 -4
- package/dist/optics/depth-of-field.js.map +1 -1
- package/dist/optics/diffraction.d.ts +8 -0
- package/dist/optics/diffraction.d.ts.map +1 -1
- package/dist/optics/diffraction.js +8 -0
- package/dist/optics/diffraction.js.map +1 -1
- package/dist/optics/focus-breathing.d.ts +13 -0
- package/dist/optics/focus-breathing.d.ts.map +1 -1
- package/dist/optics/focus-breathing.js +13 -0
- package/dist/optics/focus-breathing.js.map +1 -1
- package/dist/optics/focus-state.d.ts +47 -0
- package/dist/optics/focus-state.d.ts.map +1 -0
- package/dist/optics/focus-state.js +78 -0
- package/dist/optics/focus-state.js.map +1 -0
- package/dist/optics/front-of-lens-filter.d.ts +114 -0
- package/dist/optics/front-of-lens-filter.d.ts.map +1 -0
- package/dist/optics/front-of-lens-filter.js +468 -0
- package/dist/optics/front-of-lens-filter.js.map +1 -0
- package/dist/optics/illumination-vignetting.d.ts +9 -0
- package/dist/optics/illumination-vignetting.d.ts.map +1 -1
- package/dist/optics/illumination-vignetting.js +9 -0
- package/dist/optics/illumination-vignetting.js.map +1 -1
- package/dist/optics/lateral-chromatic-aberration.d.ts +11 -0
- package/dist/optics/lateral-chromatic-aberration.d.ts.map +1 -1
- package/dist/optics/lateral-chromatic-aberration.js +11 -0
- package/dist/optics/lateral-chromatic-aberration.js.map +1 -1
- package/dist/optics/lens-psf-profile.d.ts +217 -0
- package/dist/optics/lens-psf-profile.d.ts.map +1 -0
- package/dist/optics/lens-psf-profile.js +823 -0
- package/dist/optics/lens-psf-profile.js.map +1 -0
- package/dist/optics/polygon-diffraction.d.ts +67 -0
- package/dist/optics/polygon-diffraction.d.ts.map +1 -0
- package/dist/optics/polygon-diffraction.js +145 -0
- package/dist/optics/polygon-diffraction.js.map +1 -0
- package/dist/optics/profile-contract.d.ts +42 -0
- package/dist/optics/profile-contract.d.ts.map +1 -0
- package/dist/optics/profile-contract.js +92 -0
- package/dist/optics/profile-contract.js.map +1 -0
- package/dist/optics/psf-foundation.d.ts +16 -3
- package/dist/optics/psf-foundation.d.ts.map +1 -1
- package/dist/optics/psf-foundation.js +28 -15
- package/dist/optics/psf-foundation.js.map +1 -1
- package/dist/optics/radial-distortion.d.ts +18 -0
- package/dist/optics/radial-distortion.d.ts.map +1 -1
- package/dist/optics/radial-distortion.js +18 -0
- package/dist/optics/radial-distortion.js.map +1 -1
- package/dist/optics/scene-to-sensor-irradiance.d.ts +213 -0
- package/dist/optics/scene-to-sensor-irradiance.d.ts.map +1 -0
- package/dist/optics/scene-to-sensor-irradiance.js +662 -0
- package/dist/optics/scene-to-sensor-irradiance.js.map +1 -0
- package/dist/optics/scene-to-sensor-quadrature.d.ts +63 -0
- package/dist/optics/scene-to-sensor-quadrature.d.ts.map +1 -0
- package/dist/optics/scene-to-sensor-quadrature.js +82 -0
- package/dist/optics/scene-to-sensor-quadrature.js.map +1 -0
- package/dist/optics/sensor-environment-query.d.ts +60 -0
- package/dist/optics/sensor-environment-query.d.ts.map +1 -0
- package/dist/optics/sensor-environment-query.js +50 -0
- package/dist/optics/sensor-environment-query.js.map +1 -0
- package/dist/optics/sensor-psf-quadrature.d.ts +70 -0
- package/dist/optics/sensor-psf-quadrature.d.ts.map +1 -0
- package/dist/optics/sensor-psf-quadrature.js +101 -0
- package/dist/optics/sensor-psf-quadrature.js.map +1 -0
- package/dist/optics/sensor-psf-support.d.ts +20 -0
- package/dist/optics/sensor-psf-support.d.ts.map +1 -0
- package/dist/optics/sensor-psf-support.js +13 -0
- package/dist/optics/sensor-psf-support.js.map +1 -0
- package/dist/optics/stray-light.d.ts +91 -0
- package/dist/optics/stray-light.d.ts.map +1 -0
- package/dist/optics/stray-light.js +110 -0
- package/dist/optics/stray-light.js.map +1 -0
- package/dist/optics/thin-lens.d.ts +8 -0
- package/dist/optics/thin-lens.d.ts.map +1 -1
- package/dist/optics/thin-lens.js +8 -0
- package/dist/optics/thin-lens.js.map +1 -1
- package/dist/output/capture-corrected-sdr.d.ts +49 -0
- package/dist/output/capture-corrected-sdr.d.ts.map +1 -0
- package/dist/output/capture-corrected-sdr.js +149 -0
- package/dist/output/capture-corrected-sdr.js.map +1 -0
- package/dist/output/capture-geometry.d.ts.map +1 -1
- package/dist/output/capture-geometry.js +8 -0
- package/dist/output/capture-geometry.js.map +1 -1
- package/dist/output/capture-sdr.d.ts +49 -0
- package/dist/output/capture-sdr.d.ts.map +1 -0
- package/dist/output/capture-sdr.js +90 -0
- package/dist/output/capture-sdr.js.map +1 -0
- package/dist/output/crop.d.ts +6 -0
- package/dist/output/crop.d.ts.map +1 -1
- package/dist/output/crop.js +6 -0
- package/dist/output/crop.js.map +1 -1
- package/dist/output/geometric-transforms.d.ts +137 -0
- package/dist/output/geometric-transforms.d.ts.map +1 -0
- package/dist/output/geometric-transforms.js +225 -0
- package/dist/output/geometric-transforms.js.map +1 -0
- package/dist/output/lens-corrections.d.ts +121 -0
- package/dist/output/lens-corrections.d.ts.map +1 -0
- package/dist/output/lens-corrections.js +210 -0
- package/dist/output/lens-corrections.js.map +1 -0
- package/dist/output/sdr-rendering.d.ts +81 -0
- package/dist/output/sdr-rendering.d.ts.map +1 -0
- package/dist/output/sdr-rendering.js +106 -0
- package/dist/output/sdr-rendering.js.map +1 -0
- package/dist/output/subject-framing-crop.d.ts +8 -0
- package/dist/output/subject-framing-crop.d.ts.map +1 -1
- package/dist/output/subject-framing-crop.js +8 -0
- package/dist/output/subject-framing-crop.js.map +1 -1
- package/dist/schema/camera.d.ts +6 -0
- package/dist/schema/camera.d.ts.map +1 -1
- package/dist/schema/illumination-spectral.d.ts +51 -0
- package/dist/schema/illumination-spectral.d.ts.map +1 -0
- package/dist/schema/illumination-spectral.js +132 -0
- package/dist/schema/illumination-spectral.js.map +1 -0
- package/dist/schema/illumination-temporal.d.ts +156 -0
- package/dist/schema/illumination-temporal.d.ts.map +1 -0
- package/dist/schema/illumination-temporal.js +554 -0
- package/dist/schema/illumination-temporal.js.map +1 -0
- package/dist/schema/illumination.d.ts +138 -0
- package/dist/schema/illumination.d.ts.map +1 -0
- package/dist/schema/illumination.js +483 -0
- package/dist/schema/illumination.js.map +1 -0
- package/dist/schema/scene-radiance-temporal.d.ts +107 -0
- package/dist/schema/scene-radiance-temporal.d.ts.map +1 -0
- package/dist/schema/scene-radiance-temporal.js +259 -0
- package/dist/schema/scene-radiance-temporal.js.map +1 -0
- package/dist/schema/scene-radiance.d.ts +185 -0
- package/dist/schema/scene-radiance.d.ts.map +1 -0
- package/dist/schema/scene-radiance.js +535 -0
- package/dist/schema/scene-radiance.js.map +1 -0
- package/dist/schema/scene.d.ts +7 -0
- package/dist/schema/scene.d.ts.map +1 -1
- package/dist/schema/validation.d.ts.map +1 -1
- package/dist/schema/validation.js +7 -0
- package/dist/schema/validation.js.map +1 -1
- package/dist/sensor/accumulated-charge.d.ts +199 -0
- package/dist/sensor/accumulated-charge.d.ts.map +1 -0
- package/dist/sensor/accumulated-charge.js +450 -0
- package/dist/sensor/accumulated-charge.js.map +1 -0
- package/dist/sensor/architecture.d.ts +48 -13
- package/dist/sensor/architecture.d.ts.map +1 -1
- package/dist/sensor/architecture.js +58 -16
- package/dist/sensor/architecture.js.map +1 -1
- package/dist/sensor/camera-saturation-capacity.d.ts +138 -0
- package/dist/sensor/camera-saturation-capacity.d.ts.map +1 -0
- package/dist/sensor/camera-saturation-capacity.js +356 -0
- package/dist/sensor/camera-saturation-capacity.js.map +1 -0
- package/dist/sensor/capture-color-sampling-binding.d.ts +1 -0
- package/dist/sensor/capture-color-sampling-binding.d.ts.map +1 -1
- package/dist/sensor/capture-color-sampling-binding.js +14 -0
- package/dist/sensor/capture-color-sampling-binding.js.map +1 -1
- package/dist/sensor/capture-mode-timing.d.ts +63 -0
- package/dist/sensor/capture-mode-timing.d.ts.map +1 -0
- package/dist/sensor/capture-mode-timing.js +270 -0
- package/dist/sensor/capture-mode-timing.js.map +1 -0
- package/dist/sensor/capture-mode.d.ts.map +1 -1
- package/dist/sensor/capture-mode.js +13 -0
- package/dist/sensor/capture-mode.js.map +1 -1
- package/dist/sensor/color-sampling.d.ts.map +1 -1
- package/dist/sensor/color-sampling.js +19 -0
- package/dist/sensor/color-sampling.js.map +1 -1
- package/dist/sensor/constant-rate-temporal-integration.d.ts +126 -0
- package/dist/sensor/constant-rate-temporal-integration.d.ts.map +1 -0
- package/dist/sensor/constant-rate-temporal-integration.js +382 -0
- package/dist/sensor/constant-rate-temporal-integration.js.map +1 -0
- package/dist/sensor/dark-current.d.ts +169 -0
- package/dist/sensor/dark-current.d.ts.map +1 -0
- package/dist/sensor/dark-current.js +427 -0
- package/dist/sensor/dark-current.js.map +1 -0
- package/dist/sensor/environment-photo-signal.d.ts +123 -0
- package/dist/sensor/environment-photo-signal.d.ts.map +1 -0
- package/dist/sensor/environment-photo-signal.js +186 -0
- package/dist/sensor/environment-photo-signal.js.map +1 -0
- package/dist/sensor/eqe-electron-rate.d.ts +107 -0
- package/dist/sensor/eqe-electron-rate.d.ts.map +1 -0
- package/dist/sensor/eqe-electron-rate.js +561 -0
- package/dist/sensor/eqe-electron-rate.js.map +1 -0
- package/dist/sensor/eqe-local-exposure.d.ts +65 -0
- package/dist/sensor/eqe-local-exposure.d.ts.map +1 -0
- package/dist/sensor/eqe-local-exposure.js +84 -0
- package/dist/sensor/eqe-local-exposure.js.map +1 -0
- package/dist/sensor/eqe-temporal-exposure.d.ts +55 -0
- package/dist/sensor/eqe-temporal-exposure.d.ts.map +1 -0
- package/dist/sensor/eqe-temporal-exposure.js +62 -0
- package/dist/sensor/eqe-temporal-exposure.js.map +1 -0
- package/dist/sensor/exposure-window.d.ts +14 -0
- package/dist/sensor/exposure-window.d.ts.map +1 -1
- package/dist/sensor/exposure-window.js +14 -0
- package/dist/sensor/exposure-window.js.map +1 -1
- package/dist/sensor/iso-signal-chain.d.ts +148 -0
- package/dist/sensor/iso-signal-chain.d.ts.map +1 -0
- package/dist/sensor/iso-signal-chain.js +411 -0
- package/dist/sensor/iso-signal-chain.js.map +1 -0
- package/dist/sensor/local-exposure-binding.d.ts +87 -0
- package/dist/sensor/local-exposure-binding.d.ts.map +1 -0
- package/dist/sensor/local-exposure-binding.js +214 -0
- package/dist/sensor/local-exposure-binding.js.map +1 -0
- package/dist/sensor/optical-stack.d.ts.map +1 -1
- package/dist/sensor/optical-stack.js +17 -0
- package/dist/sensor/optical-stack.js.map +1 -1
- package/dist/sensor/photon-energy.d.ts +97 -0
- package/dist/sensor/photon-energy.d.ts.map +1 -0
- package/dist/sensor/photon-energy.js +390 -0
- package/dist/sensor/photon-energy.js.map +1 -0
- package/dist/sensor/physical-charge-capacity.d.ts +130 -0
- package/dist/sensor/physical-charge-capacity.d.ts.map +1 -0
- package/dist/sensor/physical-charge-capacity.js +345 -0
- package/dist/sensor/physical-charge-capacity.js.map +1 -0
- package/dist/sensor/pixel-pitch.d.ts +6 -0
- package/dist/sensor/pixel-pitch.d.ts.map +1 -1
- package/dist/sensor/pixel-pitch.js +6 -0
- package/dist/sensor/pixel-pitch.js.map +1 -1
- package/dist/sensor/radiometry-readiness.d.ts +10 -0
- package/dist/sensor/radiometry-readiness.d.ts.map +1 -1
- package/dist/sensor/radiometry-readiness.js +10 -0
- package/dist/sensor/radiometry-readiness.js.map +1 -1
- package/dist/sensor/raw-readout.d.ts +314 -0
- package/dist/sensor/raw-readout.d.ts.map +1 -0
- package/dist/sensor/raw-readout.js +914 -0
- package/dist/sensor/raw-readout.js.map +1 -0
- package/dist/sensor/raw-reconstruction.d.ts +170 -0
- package/dist/sensor/raw-reconstruction.d.ts.map +1 -0
- package/dist/sensor/raw-reconstruction.js +424 -0
- package/dist/sensor/raw-reconstruction.js.map +1 -0
- package/dist/sensor/readout-exposure-linkage.d.ts +12 -0
- package/dist/sensor/readout-exposure-linkage.d.ts.map +1 -1
- package/dist/sensor/readout-exposure-linkage.js +12 -0
- package/dist/sensor/readout-exposure-linkage.js.map +1 -1
- package/dist/sensor/readout-timing.d.ts +13 -0
- package/dist/sensor/readout-timing.d.ts.map +1 -1
- package/dist/sensor/readout-timing.js +13 -0
- package/dist/sensor/readout-timing.js.map +1 -1
- package/dist/sensor/response-application-compatibility.d.ts +136 -0
- package/dist/sensor/response-application-compatibility.d.ts.map +1 -0
- package/dist/sensor/response-application-compatibility.js +408 -0
- package/dist/sensor/response-application-compatibility.js.map +1 -0
- package/dist/sensor/response-operating-range.d.ts +173 -0
- package/dist/sensor/response-operating-range.d.ts.map +1 -0
- package/dist/sensor/response-operating-range.js +672 -0
- package/dist/sensor/response-operating-range.js.map +1 -0
- package/dist/sensor/responsivity-photocurrent.d.ts +158 -0
- package/dist/sensor/responsivity-photocurrent.d.ts.map +1 -0
- package/dist/sensor/responsivity-photocurrent.js +644 -0
- package/dist/sensor/responsivity-photocurrent.js.map +1 -0
- package/dist/sensor/sampling-aperture.d.ts.map +1 -1
- package/dist/sensor/sampling-aperture.js +14 -0
- package/dist/sensor/sampling-aperture.js.map +1 -1
- package/dist/sensor/scene-eqe-temporal-exposure.d.ts +45 -0
- package/dist/sensor/scene-eqe-temporal-exposure.d.ts.map +1 -0
- package/dist/sensor/scene-eqe-temporal-exposure.js +64 -0
- package/dist/sensor/scene-eqe-temporal-exposure.js.map +1 -0
- package/dist/sensor/sensor-geometry.d.ts +12 -0
- package/dist/sensor/sensor-geometry.d.ts.map +1 -1
- package/dist/sensor/sensor-geometry.js +12 -0
- package/dist/sensor/sensor-geometry.js.map +1 -1
- package/dist/sensor/signal-noise.d.ts +10 -0
- package/dist/sensor/signal-noise.d.ts.map +1 -1
- package/dist/sensor/signal-noise.js +10 -0
- package/dist/sensor/signal-noise.js.map +1 -1
- package/dist/sensor/spatial-sample-reduction.d.ts +44 -1
- package/dist/sensor/spatial-sample-reduction.d.ts.map +1 -1
- package/dist/sensor/spatial-sample-reduction.js +51 -5
- package/dist/sensor/spatial-sample-reduction.js.map +1 -1
- package/dist/sensor/spatial-sampling-quadrature.d.ts +24 -0
- package/dist/sensor/spatial-sampling-quadrature.d.ts.map +1 -1
- package/dist/sensor/spatial-sampling-quadrature.js +27 -0
- package/dist/sensor/spatial-sampling-quadrature.js.map +1 -1
- package/dist/sensor/spatio-spectral-reduction.d.ts +187 -0
- package/dist/sensor/spatio-spectral-reduction.d.ts.map +1 -0
- package/dist/sensor/spatio-spectral-reduction.js +373 -0
- package/dist/sensor/spatio-spectral-reduction.js.map +1 -0
- package/dist/sensor/spectral-coverage.d.ts +24 -0
- package/dist/sensor/spectral-coverage.d.ts.map +1 -0
- package/dist/sensor/spectral-coverage.js +86 -0
- package/dist/sensor/spectral-coverage.js.map +1 -0
- package/dist/sensor/spectral-quadrature.d.ts +169 -0
- package/dist/sensor/spectral-quadrature.d.ts.map +1 -0
- package/dist/sensor/spectral-quadrature.js +542 -0
- package/dist/sensor/spectral-quadrature.js.map +1 -0
- package/dist/sensor/spectral-response.d.ts +192 -0
- package/dist/sensor/spectral-response.d.ts.map +1 -0
- package/dist/sensor/spectral-response.js +664 -0
- package/dist/sensor/spectral-response.js.map +1 -0
- package/dist/sensor/temporal-eqe-sum.d.ts +15 -0
- package/dist/sensor/temporal-eqe-sum.d.ts.map +1 -0
- package/dist/sensor/temporal-eqe-sum.js +30 -0
- package/dist/sensor/temporal-eqe-sum.js.map +1 -0
- package/dist/sensor/temporal-photo-signal.d.ts +38 -0
- package/dist/sensor/temporal-photo-signal.d.ts.map +1 -0
- package/dist/sensor/temporal-photo-signal.js +110 -0
- package/dist/sensor/temporal-photo-signal.js.map +1 -0
- package/dist/sensor/temporal-sample-binding.d.ts +6 -0
- package/dist/sensor/temporal-sample-binding.d.ts.map +1 -0
- package/dist/sensor/temporal-sample-binding.js +32 -0
- package/dist/sensor/temporal-sample-binding.js.map +1 -0
- package/dist/simulation/poc-simulation.d.ts.map +1 -1
- package/dist/simulation/poc-simulation.js +34 -11
- package/dist/simulation/poc-simulation.js.map +1 -1
- package/dist/stabilization/camera-shake.d.ts +11 -0
- package/dist/stabilization/camera-shake.d.ts.map +1 -1
- package/dist/stabilization/camera-shake.js +11 -0
- package/dist/stabilization/camera-shake.js.map +1 -1
- package/dist/stabilization/system.d.ts +218 -0
- package/dist/stabilization/system.d.ts.map +1 -0
- package/dist/stabilization/system.js +695 -0
- package/dist/stabilization/system.js.map +1 -0
- package/docs/API_REFERENCE.md +2017 -0
- package/docs/API_STYLE.md +139 -3
- package/docs/ARCHITECTURE.md +134 -24
- package/docs/AUTOMATION_COORDINATION.md +2 -0
- package/docs/CAPTURE_COLOR.md +25 -0
- package/docs/CAPTURE_CORRECTED_SDR.md +25 -0
- package/docs/CAPTURE_EXPORT_METADATA.md +27 -0
- package/docs/CAPTURE_SDR.md +20 -0
- package/docs/DEVELOPERS.md +60 -0
- package/docs/DIGITAL_OPTICS_FOUNDATION.md +69 -0
- package/docs/ENVIRONMENT_RAW_CAPTURE.md +187 -0
- package/docs/EXPORT_ACCEPTANCE.md +133 -0
- package/docs/GENERIC_TIER_PRESETS.md +269 -0
- package/docs/GEOMETRIC_PREPARATION_REUSE.md +141 -0
- package/docs/IMAGE_FORMATION.md +80 -10
- package/docs/LINEAR_CAPTURE_ENCODING.md +25 -0
- package/docs/MOTION_AND_SIGNAL.md +5 -3
- package/docs/NUMERICAL_CORRECTNESS.md +191 -0
- package/docs/PERFORMANCE_BASELINE.md +56 -0
- package/docs/PHOTOGRAPHIC_EXPORT.md +206 -0
- package/docs/PHYSICS_FOUNDATION.md +152 -5
- package/docs/POC_API.md +2 -0
- package/docs/POC_PROJECTION_REUSE.md +124 -0
- package/docs/PROCESSED_OUTPUT.md +157 -0
- package/docs/PRODUCTION_COMPOSITION.md +373 -0
- package/docs/PRODUCTION_ENVIRONMENT_CAPTURE.md +131 -0
- package/docs/PROVENANCE.md +4 -0
- package/docs/PSF_FOUNDATION.md +110 -88
- package/docs/RAW_FRAME_ENVELOPE.md +56 -0
- package/docs/RAW_FRAME_RECONSTRUCTION.md +30 -0
- package/docs/RELEASE_1_0.md +66 -0
- package/docs/RELEASE_1_0_1.md +61 -0
- package/docs/RELEASE_AUDIT.md +39 -0
- package/docs/SCENE_RADIANCE_AND_ILLUMINATION.md +298 -0
- package/docs/SCENE_SENSOR_QUADRATURE.md +98 -0
- package/docs/SCENE_SENSOR_TEMPORAL_EXPOSURE.md +86 -0
- package/docs/SCIENTIFIC_ASSURANCE.md +280 -0
- package/docs/SCIENTIFIC_CONFORMANCE.md +83 -0
- package/docs/SDR_RENDERING.md +33 -0
- package/docs/SENSOR_ENVIRONMENT_QUERY.md +86 -0
- package/docs/SENSOR_EQE_LOCAL_EXPOSURE.md +104 -0
- package/docs/SENSOR_EQE_TEMPORAL_EXPOSURE.md +74 -0
- package/docs/SENSOR_PSF_QUADRATURE.md +90 -0
- package/docs/SENSOR_RAW_FRAME.md +20 -0
- package/docs/SENSOR_RAW_PRODUCER.md +77 -0
- package/docs/SIGNAL_CONFORMANCE.md +23 -0
- package/docs/SIMULATED_CAPTURE.md +65 -0
- package/docs/STABILIZATION.md +160 -17
- package/docs/TEMPORAL_PHOTO_RAW.md +83 -0
- package/docs/TIER_ACCEPTANCE.md +129 -0
- package/docs/TIER_PRESET_ACCEPTANCE.md +59 -0
- package/docs/USAGE.md +5050 -1047
- package/docs/V1_COMPOSITION_MAP.md +123 -0
- package/docs/V1_HELPER_REUSE_REVIEW.md +60 -0
- package/docs/V1_PERFORMANCE_DISPOSITION.md +88 -0
- package/docs/api/camera-equivalent-focal-length.md +53 -0
- package/docs/api/camera-field-of-view.md +119 -0
- package/docs/api/camera-projected-object-size.md +54 -0
- package/docs/api/capture-capture-export-metadata.md +107 -0
- package/docs/api/capture-environment-raw-producer.md +56 -0
- package/docs/api/capture-focus-control.md +419 -0
- package/docs/api/capture-linear-encoding.md +99 -0
- package/docs/api/capture-photographic-export.md +172 -0
- package/docs/api/capture-raw-frame-reconstruction.md +87 -0
- package/docs/api/capture-release-sequence.md +252 -0
- package/docs/api/capture-sensor-raw-frame.md +66 -0
- package/docs/api/capture-sensor-raw-producer.md +98 -0
- package/docs/api/capture-simulated-capture.md +179 -0
- package/docs/api/color-capture-color.md +122 -0
- package/docs/api/color-white-balance.md +386 -0
- package/docs/api/composition-image-formation-plan.md +825 -0
- package/docs/api/composition-plan-consumer.md +98 -0
- package/docs/api/core-calculation-result.md +220 -0
- package/docs/api/core-configuration-error.md +19 -0
- package/docs/api/core-image-formation.md +204 -0
- package/docs/api/core-scientific-assurance.md +214 -0
- package/docs/api/core-spectral-composition.md +268 -0
- package/docs/api/core-spectral.md +78 -0
- package/docs/api/core-validation.md +34 -0
- package/docs/api/core-version.md +14 -0
- package/docs/api/equipment-exposure-capabilities.md +270 -0
- package/docs/api/equipment-generic-tier-assets.md +82 -0
- package/docs/api/equipment-generic-tier-presets.md +103 -0
- package/docs/api/equipment-iso-capabilities.md +295 -0
- package/docs/api/equipment-metering-capabilities.md +126 -0
- package/docs/api/equipment-release-capabilities.md +91 -0
- package/docs/api/exports.json +5656 -0
- package/docs/api/exposure-exposure-duration-control.md +115 -0
- package/docs/api/exposure-exposure-mode-resolver.md +966 -0
- package/docs/api/exposure-exposure.md +150 -0
- package/docs/api/exposure-flash.md +327 -0
- package/docs/api/exposure-metering-scene-radiance.md +154 -0
- package/docs/api/exposure-metering-target.md +134 -0
- package/docs/api/exposure-metering-temporal.md +77 -0
- package/docs/api/exposure-metering.md +172 -0
- package/docs/api/exposure-program-line.md +64 -0
- package/docs/api/motion-camera-rotation.md +215 -0
- package/docs/api/motion-capture-rotation-inverse-mapping.md +128 -0
- package/docs/api/motion-capture-rotation-temporal-quadrature.md +127 -0
- package/docs/api/motion-capture-rotation-trajectory.md +132 -0
- package/docs/api/motion-capture-translation-parallax-temporal-quadrature.md +171 -0
- package/docs/api/motion-extended-object-projection.md +312 -0
- package/docs/api/motion-projected-motion.md +60 -0
- package/docs/api/optics-aperture.md +69 -0
- package/docs/api/optics-circle-of-confusion.md +46 -0
- package/docs/api/optics-complex-pupil-psf.md +193 -0
- package/docs/api/optics-depth-of-field.md +92 -0
- package/docs/api/optics-diffraction.md +46 -0
- package/docs/api/optics-focus-breathing.md +119 -0
- package/docs/api/optics-focus-state.md +64 -0
- package/docs/api/optics-front-of-lens-filter.md +263 -0
- package/docs/api/optics-illumination-vignetting.md +95 -0
- package/docs/api/optics-lateral-chromatic-aberration.md +225 -0
- package/docs/api/optics-lens-psf-profile.md +380 -0
- package/docs/api/optics-polygon-diffraction.md +68 -0
- package/docs/api/optics-profile-contract.md +47 -0
- package/docs/api/optics-psf-foundation.md +181 -0
- package/docs/api/optics-radial-distortion.md +194 -0
- package/docs/api/optics-scene-to-sensor-irradiance.md +371 -0
- package/docs/api/optics-scene-to-sensor-quadrature.md +78 -0
- package/docs/api/optics-sensor-environment-query.md +58 -0
- package/docs/api/optics-sensor-psf-quadrature.md +81 -0
- package/docs/api/optics-stray-light.md +109 -0
- package/docs/api/optics-thin-lens.md +53 -0
- package/docs/api/output-capture-corrected-sdr.md +71 -0
- package/docs/api/output-capture-geometry.md +500 -0
- package/docs/api/output-capture-sdr.md +69 -0
- package/docs/api/output-crop.md +47 -0
- package/docs/api/output-geometric-transforms.md +199 -0
- package/docs/api/output-lens-corrections.md +162 -0
- package/docs/api/output-sdr-rendering.md +122 -0
- package/docs/api/output-subject-framing-crop.md +59 -0
- package/docs/api/schema-camera.md +84 -0
- package/docs/api/schema-illumination-spectral.md +77 -0
- package/docs/api/schema-illumination-temporal.md +289 -0
- package/docs/api/schema-illumination.md +246 -0
- package/docs/api/schema-scene-radiance-temporal.md +215 -0
- package/docs/api/schema-scene-radiance.md +415 -0
- package/docs/api/schema-scene.md +105 -0
- package/docs/api/schema-validation.md +25 -0
- package/docs/api/sensor-accumulated-charge.md +273 -0
- package/docs/api/sensor-architecture.md +155 -0
- package/docs/api/sensor-camera-saturation-capacity.md +215 -0
- package/docs/api/sensor-capture-color-sampling-binding.md +323 -0
- package/docs/api/sensor-capture-mode-timing.md +123 -0
- package/docs/api/sensor-capture-mode.md +321 -0
- package/docs/api/sensor-color-sampling.md +228 -0
- package/docs/api/sensor-constant-rate-temporal-integration.md +152 -0
- package/docs/api/sensor-dark-current.md +227 -0
- package/docs/api/sensor-environment-photo-signal.md +77 -0
- package/docs/api/sensor-eqe-electron-rate.md +166 -0
- package/docs/api/sensor-eqe-local-exposure.md +68 -0
- package/docs/api/sensor-eqe-temporal-exposure.md +73 -0
- package/docs/api/sensor-exposure-window.md +183 -0
- package/docs/api/sensor-iso-signal-chain.md +264 -0
- package/docs/api/sensor-local-exposure-binding.md +126 -0
- package/docs/api/sensor-optical-stack.md +211 -0
- package/docs/api/sensor-photon-energy.md +149 -0
- package/docs/api/sensor-physical-charge-capacity.md +196 -0
- package/docs/api/sensor-pixel-pitch.md +41 -0
- package/docs/api/sensor-radiometry-readiness.md +240 -0
- package/docs/api/sensor-raw-readout.md +499 -0
- package/docs/api/sensor-raw-reconstruction.md +260 -0
- package/docs/api/sensor-readout-exposure-linkage.md +172 -0
- package/docs/api/sensor-readout-timing.md +209 -0
- package/docs/api/sensor-response-application-compatibility.md +256 -0
- package/docs/api/sensor-response-operating-range.md +293 -0
- package/docs/api/sensor-responsivity-photocurrent.md +245 -0
- package/docs/api/sensor-sampling-aperture.md +221 -0
- package/docs/api/sensor-scene-eqe-temporal-exposure.md +56 -0
- package/docs/api/sensor-sensor-geometry.md +143 -0
- package/docs/api/sensor-signal-noise.md +75 -0
- package/docs/api/sensor-spatial-sample-reduction.md +186 -0
- package/docs/api/sensor-spatial-sampling-quadrature.md +188 -0
- package/docs/api/sensor-spatio-spectral-reduction.md +217 -0
- package/docs/api/sensor-spectral-coverage.md +33 -0
- package/docs/api/sensor-spectral-quadrature.md +183 -0
- package/docs/api/sensor-spectral-response.md +291 -0
- package/docs/api/sensor-temporal-photo-signal.md +62 -0
- package/docs/api/simulation-poc-simulation.md +364 -0
- package/docs/api/stabilization-camera-shake.md +71 -0
- package/docs/api/stabilization-system.md +442 -0
- package/docs/benchmarks/2026-10-01-main-baseline.json +694 -0
- package/docs/benchmarks/2026-10-02-geometric-preparation-reuse.json +2190 -0
- package/docs/benchmarks/2026-10-02-poc-projection-reuse.json +2423 -0
- package/docs/benchmarks/2026-10-02-v1-environment-gc-profile.json +210 -0
- package/docs/benchmarks/2026-10-02-v1-environment-ordinary.json +187 -0
- package/docs/benchmarks/2026-10-02-v1-geometry-gc-profile.json +756 -0
- package/docs/benchmarks/2026-10-02-v1-geometry-ordinary-1.json +711 -0
- package/docs/benchmarks/2026-10-02-v1-geometry-ordinary-2.json +711 -0
- package/docs/benchmarks/2026-10-02-v1-poc-gc-profile.json +885 -0
- package/docs/benchmarks/2026-10-02-v1-poc-ordinary-1.json +868 -0
- package/docs/benchmarks/2026-10-02-v1-poc-ordinary-2.json +868 -0
- package/docs/examples/production-capture.mjs +34 -0
- package/docs/examples/production-request.json +4613 -0
- package/docs/examples/quick-start.mjs +12 -0
- package/docs/validation/documentation-fragments.json +212 -0
- package/docs/validation/release-audit-inventory.json +1306 -0
- package/docs/validation/tier-acceptance-report-v1.json +2538 -0
- package/package.json +15 -3
|
@@ -0,0 +1,823 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
/**
|
|
3
|
+
* Module boundary and integration notes.
|
|
4
|
+
* Validate an untrusted declaration and return the normalized typed contract. Unknown enum values,
|
|
5
|
+
* missing required fields and incompatible scientific data fail at this boundary. Sampled lens PSF
|
|
6
|
+
* shapes bind exact generic optical state, field, wavelength and signed defocus support. Interpolation
|
|
7
|
+
* stays within declared applicability and preserves normalized shape separately from throughput.
|
|
8
|
+
* MTF-only data lacks phase/spatial information and does not authorize rendering a unique PSF.
|
|
9
|
+
* Resolve the bounded sampled PSF for a declared optical state and support point without extrapolation
|
|
10
|
+
* or silently inventing missing dimensions. Sampled lens PSF shapes bind exact generic optical state,
|
|
11
|
+
* field, wavelength and signed defocus support. Interpolation stays within declared applicability and
|
|
12
|
+
* preserves normalized shape separately from throughput. MTF-only data lacks phase/spatial information
|
|
13
|
+
* and does not authorize rendering a unique PSF.
|
|
14
|
+
* @see docs/PSF_FOUNDATION.md for equations, coordinate/unit conventions, blockers and support limits.
|
|
15
|
+
*/
|
|
16
|
+
import { approximationResult } from "../core/calculation-result.js";
|
|
17
|
+
import { InvalidConfigurationError } from "../core/configuration-error.js";
|
|
18
|
+
import { parseEvidenceList } from "../core/evidence-provenance.js";
|
|
19
|
+
import { InvalidScientificInputError } from "../core/validation.js";
|
|
20
|
+
import { parseFocusPlane } from "./focus-state.js";
|
|
21
|
+
export const LENS_SAMPLED_PSF_PROFILE_SCHEMA_VERSION = "0.1.0";
|
|
22
|
+
export const LENS_MTF_DIAGNOSTIC_PROFILE_SCHEMA_VERSION = "0.1.0";
|
|
23
|
+
const AXIS_KEYS = [
|
|
24
|
+
"focalLengthMm",
|
|
25
|
+
"focusDiopters",
|
|
26
|
+
"apertureFNumber",
|
|
27
|
+
"fieldXmm",
|
|
28
|
+
"fieldYmm",
|
|
29
|
+
"wavelengthNm",
|
|
30
|
+
"signedDefocusImagePlaneMicrometers"
|
|
31
|
+
];
|
|
32
|
+
function requireRecord(value, path) {
|
|
33
|
+
if (typeof value !== "object" ||
|
|
34
|
+
value === null ||
|
|
35
|
+
Array.isArray(value)) {
|
|
36
|
+
throw new InvalidConfigurationError(path + " must be an object.");
|
|
37
|
+
}
|
|
38
|
+
return value;
|
|
39
|
+
}
|
|
40
|
+
function requireNonEmptyString(value, path) {
|
|
41
|
+
if (typeof value !== "string" ||
|
|
42
|
+
value.trim().length === 0) {
|
|
43
|
+
throw new InvalidConfigurationError(path +
|
|
44
|
+
" must be a non-empty string.");
|
|
45
|
+
}
|
|
46
|
+
return value.trim();
|
|
47
|
+
}
|
|
48
|
+
function requireFinite(value, path) {
|
|
49
|
+
if (typeof value !== "number" ||
|
|
50
|
+
!Number.isFinite(value)) {
|
|
51
|
+
throw new InvalidConfigurationError(path + " must be finite.");
|
|
52
|
+
}
|
|
53
|
+
return value;
|
|
54
|
+
}
|
|
55
|
+
function requirePositiveFinite(value, path) {
|
|
56
|
+
const parsed = requireFinite(value, path);
|
|
57
|
+
if (parsed <= 0) {
|
|
58
|
+
throw new InvalidConfigurationError(path +
|
|
59
|
+
" must be greater than zero.");
|
|
60
|
+
}
|
|
61
|
+
return parsed;
|
|
62
|
+
}
|
|
63
|
+
function requireNonNegativeFinite(value, path) {
|
|
64
|
+
const parsed = requireFinite(value, path);
|
|
65
|
+
if (parsed < 0) {
|
|
66
|
+
throw new InvalidConfigurationError(path +
|
|
67
|
+
" must be greater than or equal to zero.");
|
|
68
|
+
}
|
|
69
|
+
return parsed;
|
|
70
|
+
}
|
|
71
|
+
function requireUnitInterval(value, path) {
|
|
72
|
+
const parsed = requireFinite(value, path);
|
|
73
|
+
if (parsed < 0 ||
|
|
74
|
+
parsed > 1) {
|
|
75
|
+
throw new InvalidConfigurationError(path +
|
|
76
|
+
" must lie from zero through one.");
|
|
77
|
+
}
|
|
78
|
+
return parsed;
|
|
79
|
+
}
|
|
80
|
+
function requirePositiveSafeInteger(value, path) {
|
|
81
|
+
if (typeof value !== "number" ||
|
|
82
|
+
!Number.isSafeInteger(value) ||
|
|
83
|
+
value <= 0) {
|
|
84
|
+
throw new InvalidConfigurationError(path +
|
|
85
|
+
" must be a positive safe integer.");
|
|
86
|
+
}
|
|
87
|
+
return value;
|
|
88
|
+
}
|
|
89
|
+
function requireNonNegativeSafeInteger(value, path) {
|
|
90
|
+
if (typeof value !== "number" ||
|
|
91
|
+
!Number.isSafeInteger(value) ||
|
|
92
|
+
value < 0) {
|
|
93
|
+
throw new InvalidConfigurationError(path +
|
|
94
|
+
" must be a non-negative safe integer.");
|
|
95
|
+
}
|
|
96
|
+
return value;
|
|
97
|
+
}
|
|
98
|
+
function parseStatus(value, path) {
|
|
99
|
+
if (value !== "calibrated" &&
|
|
100
|
+
value !== "approximation") {
|
|
101
|
+
throw new InvalidConfigurationError(path + " is invalid.");
|
|
102
|
+
}
|
|
103
|
+
return value;
|
|
104
|
+
}
|
|
105
|
+
function parseUncertainty(value, path) {
|
|
106
|
+
const record = requireRecord(value, path);
|
|
107
|
+
if (record.kind === "relative") {
|
|
108
|
+
return {
|
|
109
|
+
kind: "relative",
|
|
110
|
+
fraction: requireNonNegativeFinite(record.fraction, path + ".fraction"),
|
|
111
|
+
basis: requireNonEmptyString(record.basis, path + ".basis")
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
if (record.kind ===
|
|
115
|
+
"not-quantified") {
|
|
116
|
+
return {
|
|
117
|
+
kind: "not-quantified",
|
|
118
|
+
limitation: requireNonEmptyString(record.limitation, path +
|
|
119
|
+
".limitation")
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
throw new InvalidConfigurationError(path + ".kind is invalid.");
|
|
123
|
+
}
|
|
124
|
+
function parseLimitations(value, path) {
|
|
125
|
+
if (!Array.isArray(value)) {
|
|
126
|
+
throw new InvalidConfigurationError(path + " must be an array.");
|
|
127
|
+
}
|
|
128
|
+
const parsed = value.map((entry, index) => requireNonEmptyString(entry, path +
|
|
129
|
+
"[" +
|
|
130
|
+
index +
|
|
131
|
+
"]"));
|
|
132
|
+
if (new Set(parsed).size !==
|
|
133
|
+
parsed.length) {
|
|
134
|
+
throw new InvalidConfigurationError(path +
|
|
135
|
+
" must not contain duplicates.");
|
|
136
|
+
}
|
|
137
|
+
return parsed;
|
|
138
|
+
}
|
|
139
|
+
function parseAxis(value, path, options = {}) {
|
|
140
|
+
if (!Array.isArray(value) ||
|
|
141
|
+
value.length === 0) {
|
|
142
|
+
throw new InvalidConfigurationError(path +
|
|
143
|
+
" must be a non-empty array.");
|
|
144
|
+
}
|
|
145
|
+
const parsed = value.map((entry, index) => {
|
|
146
|
+
const itemPath = path +
|
|
147
|
+
"[" +
|
|
148
|
+
index +
|
|
149
|
+
"]";
|
|
150
|
+
if (options.positive) {
|
|
151
|
+
return requirePositiveFinite(entry, itemPath);
|
|
152
|
+
}
|
|
153
|
+
if (options.nonNegative) {
|
|
154
|
+
return requireNonNegativeFinite(entry, itemPath);
|
|
155
|
+
}
|
|
156
|
+
return requireFinite(entry, itemPath);
|
|
157
|
+
});
|
|
158
|
+
for (let index = 1; index < parsed.length; index += 1) {
|
|
159
|
+
if (parsed[index] <=
|
|
160
|
+
parsed[index - 1]) {
|
|
161
|
+
throw new InvalidConfigurationError(path +
|
|
162
|
+
" must be strictly increasing with unique values.");
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return parsed;
|
|
166
|
+
}
|
|
167
|
+
function parseKernel(value, path) {
|
|
168
|
+
const record = requireRecord(value, path);
|
|
169
|
+
const widthSamples = requirePositiveSafeInteger(record.widthSamples, path + ".widthSamples");
|
|
170
|
+
const heightSamples = requirePositiveSafeInteger(record.heightSamples, path + ".heightSamples");
|
|
171
|
+
const total = widthSamples *
|
|
172
|
+
heightSamples;
|
|
173
|
+
if (!Number.isSafeInteger(total)) {
|
|
174
|
+
throw new InvalidConfigurationError(path +
|
|
175
|
+
" sample count must remain a safe integer.");
|
|
176
|
+
}
|
|
177
|
+
const centerSampleX = requireNonNegativeSafeInteger(record.centerSampleX, path + ".centerSampleX");
|
|
178
|
+
const centerSampleY = requireNonNegativeSafeInteger(record.centerSampleY, path + ".centerSampleY");
|
|
179
|
+
if (centerSampleX >=
|
|
180
|
+
widthSamples ||
|
|
181
|
+
centerSampleY >=
|
|
182
|
+
heightSamples) {
|
|
183
|
+
throw new InvalidConfigurationError(path +
|
|
184
|
+
" center sample must lie within the kernel grid.");
|
|
185
|
+
}
|
|
186
|
+
if (!Array.isArray(record.normalizedIntensity) ||
|
|
187
|
+
record
|
|
188
|
+
.normalizedIntensity
|
|
189
|
+
.length !== total) {
|
|
190
|
+
throw new InvalidConfigurationError(path +
|
|
191
|
+
".normalizedIntensity length must equal widthSamples × heightSamples.");
|
|
192
|
+
}
|
|
193
|
+
const normalizedIntensity = record
|
|
194
|
+
.normalizedIntensity
|
|
195
|
+
.map((entry, index) => requireNonNegativeFinite(entry, path +
|
|
196
|
+
".normalizedIntensity[" +
|
|
197
|
+
index +
|
|
198
|
+
"]"));
|
|
199
|
+
const sum = normalizedIntensity.reduce((acc, entry) => acc + entry, 0);
|
|
200
|
+
if (!Number.isFinite(sum) ||
|
|
201
|
+
Math.abs(sum - 1) >
|
|
202
|
+
1e-10) {
|
|
203
|
+
throw new InvalidConfigurationError(path +
|
|
204
|
+
".normalizedIntensity must sum to one.");
|
|
205
|
+
}
|
|
206
|
+
return {
|
|
207
|
+
widthSamples,
|
|
208
|
+
heightSamples,
|
|
209
|
+
samplePitchMicrometersX: requirePositiveFinite(record
|
|
210
|
+
.samplePitchMicrometersX, path +
|
|
211
|
+
".samplePitchMicrometersX"),
|
|
212
|
+
samplePitchMicrometersY: requirePositiveFinite(record
|
|
213
|
+
.samplePitchMicrometersY, path +
|
|
214
|
+
".samplePitchMicrometersY"),
|
|
215
|
+
centerSampleX,
|
|
216
|
+
centerSampleY,
|
|
217
|
+
normalizedIntensity
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
function parseAxes(value) {
|
|
221
|
+
const record = requireRecord(value, "lensPsfProfile.axes");
|
|
222
|
+
return {
|
|
223
|
+
focalLengthMm: parseAxis(record.focalLengthMm, "lensPsfProfile.axes.focalLengthMm", {
|
|
224
|
+
positive: true
|
|
225
|
+
}),
|
|
226
|
+
focusDiopters: parseAxis(record.focusDiopters, "lensPsfProfile.axes.focusDiopters", {
|
|
227
|
+
nonNegative: true
|
|
228
|
+
}),
|
|
229
|
+
apertureFNumber: parseAxis(record.apertureFNumber, "lensPsfProfile.axes.apertureFNumber", {
|
|
230
|
+
positive: true
|
|
231
|
+
}),
|
|
232
|
+
fieldXmm: parseAxis(record.fieldXmm, "lensPsfProfile.axes.fieldXmm"),
|
|
233
|
+
fieldYmm: parseAxis(record.fieldYmm, "lensPsfProfile.axes.fieldYmm"),
|
|
234
|
+
wavelengthNm: parseAxis(record.wavelengthNm, "lensPsfProfile.axes.wavelengthNm", {
|
|
235
|
+
positive: true
|
|
236
|
+
}),
|
|
237
|
+
signedDefocusImagePlaneMicrometers: parseAxis(record
|
|
238
|
+
.signedDefocusImagePlaneMicrometers, "lensPsfProfile.axes.signedDefocusImagePlaneMicrometers")
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
function parseCoordinate(value, path) {
|
|
242
|
+
const record = requireRecord(value, path);
|
|
243
|
+
return {
|
|
244
|
+
focalLengthMm: requirePositiveFinite(record.focalLengthMm, path + ".focalLengthMm"),
|
|
245
|
+
focusDiopters: requireNonNegativeFinite(record.focusDiopters, path + ".focusDiopters"),
|
|
246
|
+
apertureFNumber: requirePositiveFinite(record.apertureFNumber, path +
|
|
247
|
+
".apertureFNumber"),
|
|
248
|
+
fieldXmm: requireFinite(record.fieldXmm, path + ".fieldXmm"),
|
|
249
|
+
fieldYmm: requireFinite(record.fieldYmm, path + ".fieldYmm"),
|
|
250
|
+
wavelengthNm: requirePositiveFinite(record.wavelengthNm, path + ".wavelengthNm"),
|
|
251
|
+
signedDefocusImagePlaneMicrometers: requireFinite(record
|
|
252
|
+
.signedDefocusImagePlaneMicrometers, path +
|
|
253
|
+
".signedDefocusImagePlaneMicrometers")
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
function coordinateKey(coordinate) {
|
|
257
|
+
return AXIS_KEYS.map((key) => coordinate[key]
|
|
258
|
+
.toString()).join("|");
|
|
259
|
+
}
|
|
260
|
+
function axisContains(values, target) {
|
|
261
|
+
return values.some((value) => value === target);
|
|
262
|
+
}
|
|
263
|
+
function validateNodeCoordinate(axes, coordinate, path) {
|
|
264
|
+
for (const key of AXIS_KEYS) {
|
|
265
|
+
if (!axisContains(axes[key], coordinate[key])) {
|
|
266
|
+
throw new InvalidConfigurationError(path +
|
|
267
|
+
"." +
|
|
268
|
+
key +
|
|
269
|
+
" must exactly match one declared grid-axis value.");
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
function parseNode(value, index, axes, status) {
|
|
274
|
+
const path = "lensPsfProfile.nodes[" +
|
|
275
|
+
index +
|
|
276
|
+
"]";
|
|
277
|
+
const record = requireRecord(value, path);
|
|
278
|
+
const coordinate = parseCoordinate(record.coordinate, path + ".coordinate");
|
|
279
|
+
validateNodeCoordinate(axes, coordinate, path + ".coordinate");
|
|
280
|
+
const uncertainty = parseUncertainty(record.uncertainty, path + ".uncertainty");
|
|
281
|
+
if (status === "calibrated" &&
|
|
282
|
+
uncertainty.kind ===
|
|
283
|
+
"not-quantified") {
|
|
284
|
+
throw new InvalidConfigurationError(path +
|
|
285
|
+
" calibrated PSF data must declare quantified relative uncertainty.");
|
|
286
|
+
}
|
|
287
|
+
return {
|
|
288
|
+
nodeId: requireNonEmptyString(record.nodeId, path + ".nodeId"),
|
|
289
|
+
coordinate,
|
|
290
|
+
kernel: parseKernel(record.kernel, path + ".kernel"),
|
|
291
|
+
bestFocusImagePlaneOffsetMicrometers: requireFinite(record
|
|
292
|
+
.bestFocusImagePlaneOffsetMicrometers, path +
|
|
293
|
+
".bestFocusImagePlaneOffsetMicrometers"),
|
|
294
|
+
relativePupilThroughputFactor: requireUnitInterval(record
|
|
295
|
+
.relativePupilThroughputFactor, path +
|
|
296
|
+
".relativePupilThroughputFactor"),
|
|
297
|
+
evidence: parseEvidenceList(record.evidence, path + ".evidence"),
|
|
298
|
+
uncertainty
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
function expectedNodeCount(axes) {
|
|
302
|
+
let count = 1;
|
|
303
|
+
for (const key of AXIS_KEYS) {
|
|
304
|
+
count *= axes[key].length;
|
|
305
|
+
if (!Number.isSafeInteger(count) ||
|
|
306
|
+
count > 100_000) {
|
|
307
|
+
throw new InvalidConfigurationError("lensPsfProfile regular grid must contain at most 100000 nodes.");
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return count;
|
|
311
|
+
}
|
|
312
|
+
function sameKernelGeometry(first, second) {
|
|
313
|
+
return (first.widthSamples ===
|
|
314
|
+
second.widthSamples &&
|
|
315
|
+
first.heightSamples ===
|
|
316
|
+
second.heightSamples &&
|
|
317
|
+
first
|
|
318
|
+
.samplePitchMicrometersX ===
|
|
319
|
+
second
|
|
320
|
+
.samplePitchMicrometersX &&
|
|
321
|
+
first
|
|
322
|
+
.samplePitchMicrometersY ===
|
|
323
|
+
second
|
|
324
|
+
.samplePitchMicrometersY &&
|
|
325
|
+
first.centerSampleX ===
|
|
326
|
+
second.centerSampleX &&
|
|
327
|
+
first.centerSampleY ===
|
|
328
|
+
second.centerSampleY);
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Validate an untrusted declaration and return the normalized typed contract. Unknown enum values,
|
|
332
|
+
* missing required fields and incompatible scientific data fail at this boundary.
|
|
333
|
+
*
|
|
334
|
+
* Sampled lens PSF shapes bind exact generic optical state, field, wavelength and signed defocus
|
|
335
|
+
* support. Interpolation stays within declared applicability and preserves normalized shape separately
|
|
336
|
+
* from throughput. MTF-only data lacks phase/spatial information and does not authorize rendering a
|
|
337
|
+
* unique PSF.
|
|
338
|
+
* @param value - unknown. Treated as untrusted data; static typing alone is not validation.
|
|
339
|
+
* @returns LensSampledPsfProfile. Return shape and scientific status are explicit; no calibration is inferred from successful execution.
|
|
340
|
+
*
|
|
341
|
+
* @see docs/API_REFERENCE.md for the root export and exact type graph.
|
|
342
|
+
*/
|
|
343
|
+
export function parseLensSampledPsfProfile(value) {
|
|
344
|
+
const record = requireRecord(value, "lensPsfProfile");
|
|
345
|
+
if (record.schemaVersion !==
|
|
346
|
+
LENS_SAMPLED_PSF_PROFILE_SCHEMA_VERSION) {
|
|
347
|
+
throw new InvalidConfigurationError('lensPsfProfile.schemaVersion must be "' +
|
|
348
|
+
LENS_SAMPLED_PSF_PROFILE_SCHEMA_VERSION +
|
|
349
|
+
'".');
|
|
350
|
+
}
|
|
351
|
+
if (record.opticalDomain !==
|
|
352
|
+
"lens-primary-optical-path-only") {
|
|
353
|
+
throw new InvalidConfigurationError('lensPsfProfile.opticalDomain must be "lens-primary-optical-path-only".');
|
|
354
|
+
}
|
|
355
|
+
if (record.coordinateSystem !==
|
|
356
|
+
"image-plane-metric" ||
|
|
357
|
+
record.fieldAxes !==
|
|
358
|
+
"+X right, +Y up") {
|
|
359
|
+
throw new InvalidConfigurationError("lensPsfProfile image-plane coordinate semantics are invalid.");
|
|
360
|
+
}
|
|
361
|
+
if (record.kernelEnergyNormalization !==
|
|
362
|
+
"unit-energy-shape" ||
|
|
363
|
+
record.interpolation !==
|
|
364
|
+
"bounded-regular-grid-multilinear" ||
|
|
365
|
+
record.throughputOwnership !==
|
|
366
|
+
"separate-relative-pupil-throughput-factor") {
|
|
367
|
+
throw new InvalidConfigurationError("lensPsfProfile normalization/interpolation/throughput ownership is invalid.");
|
|
368
|
+
}
|
|
369
|
+
if (record.sensorOpticalStackIncluded !==
|
|
370
|
+
false ||
|
|
371
|
+
record.sensorSamplingIncluded !==
|
|
372
|
+
false ||
|
|
373
|
+
record.reconstructionIncluded !==
|
|
374
|
+
false ||
|
|
375
|
+
record.strayLightIncluded !==
|
|
376
|
+
false) {
|
|
377
|
+
throw new InvalidConfigurationError("V1 lens PSF profiles must remain lens-primary-optical-path-only and exclude sensor/reconstruction/stray-light effects.");
|
|
378
|
+
}
|
|
379
|
+
const status = parseStatus(record.scientificStatus, "lensPsfProfile.scientificStatus");
|
|
380
|
+
const response = requireRecord(record.responseIncludes, "lensPsfProfile.responseIncludes");
|
|
381
|
+
for (const key of [
|
|
382
|
+
"diffraction",
|
|
383
|
+
"aberration",
|
|
384
|
+
"defocus",
|
|
385
|
+
"pupilClippingShape"
|
|
386
|
+
]) {
|
|
387
|
+
if (typeof response[key] !==
|
|
388
|
+
"boolean") {
|
|
389
|
+
throw new InvalidConfigurationError("lensPsfProfile.responseIncludes." +
|
|
390
|
+
key +
|
|
391
|
+
" must be boolean.");
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
const axes = parseAxes(record.axes);
|
|
395
|
+
if (!Array.isArray(record.nodes)) {
|
|
396
|
+
throw new InvalidConfigurationError("lensPsfProfile.nodes must be an array.");
|
|
397
|
+
}
|
|
398
|
+
if (record.nodes.length !==
|
|
399
|
+
expectedNodeCount(axes)) {
|
|
400
|
+
throw new InvalidConfigurationError("lensPsfProfile.nodes must contain exactly one node for every regular-grid coordinate.");
|
|
401
|
+
}
|
|
402
|
+
const nodes = record.nodes.map((node, index) => parseNode(node, index, axes, status));
|
|
403
|
+
const ids = nodes.map((node) => node.nodeId);
|
|
404
|
+
if (new Set(ids).size !==
|
|
405
|
+
ids.length) {
|
|
406
|
+
throw new InvalidConfigurationError("lensPsfProfile.nodes must not contain duplicate nodeId values.");
|
|
407
|
+
}
|
|
408
|
+
const coordinateKeys = nodes.map((node) => coordinateKey(node.coordinate));
|
|
409
|
+
if (new Set(coordinateKeys).size !==
|
|
410
|
+
coordinateKeys.length) {
|
|
411
|
+
throw new InvalidConfigurationError("lensPsfProfile.nodes must not contain duplicate grid coordinates.");
|
|
412
|
+
}
|
|
413
|
+
const firstKernel = nodes[0]?.kernel;
|
|
414
|
+
if (firstKernel === undefined) {
|
|
415
|
+
throw new InvalidConfigurationError("lensPsfProfile.nodes must not be empty.");
|
|
416
|
+
}
|
|
417
|
+
for (const node of nodes) {
|
|
418
|
+
if (!sameKernelGeometry(firstKernel, node.kernel)) {
|
|
419
|
+
throw new InvalidConfigurationError("Every lensPsfProfile node must use identical PSF kernel grid geometry for multilinear interpolation.");
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
return {
|
|
423
|
+
schemaVersion: LENS_SAMPLED_PSF_PROFILE_SCHEMA_VERSION,
|
|
424
|
+
profileId: requireNonEmptyString(record.profileId, "lensPsfProfile.profileId"),
|
|
425
|
+
profileVersion: requireNonEmptyString(record.profileVersion, "lensPsfProfile.profileVersion"),
|
|
426
|
+
scientificStatus: status,
|
|
427
|
+
opticalDomain: "lens-primary-optical-path-only",
|
|
428
|
+
coordinateSystem: "image-plane-metric",
|
|
429
|
+
fieldAxes: "+X right, +Y up",
|
|
430
|
+
kernelEnergyNormalization: "unit-energy-shape",
|
|
431
|
+
interpolation: "bounded-regular-grid-multilinear",
|
|
432
|
+
throughputOwnership: "separate-relative-pupil-throughput-factor",
|
|
433
|
+
responseIncludes: {
|
|
434
|
+
diffraction: response.diffraction,
|
|
435
|
+
aberration: response.aberration,
|
|
436
|
+
defocus: response.defocus,
|
|
437
|
+
pupilClippingShape: response
|
|
438
|
+
.pupilClippingShape
|
|
439
|
+
},
|
|
440
|
+
sensorOpticalStackIncluded: false,
|
|
441
|
+
sensorSamplingIncluded: false,
|
|
442
|
+
reconstructionIncluded: false,
|
|
443
|
+
strayLightIncluded: false,
|
|
444
|
+
axes,
|
|
445
|
+
nodes,
|
|
446
|
+
evidence: parseEvidenceList(record.evidence, "lensPsfProfile.evidence"),
|
|
447
|
+
limitations: parseLimitations(record.limitations, "lensPsfProfile.limitations")
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
function focusDiopters(focus) {
|
|
451
|
+
const parsed = parseFocusPlane(focus);
|
|
452
|
+
return parsed.kind ===
|
|
453
|
+
"infinity"
|
|
454
|
+
? 0
|
|
455
|
+
: 1 /
|
|
456
|
+
parsed.distanceM;
|
|
457
|
+
}
|
|
458
|
+
function requireScientificFinite(value, path) {
|
|
459
|
+
if (typeof value !== "number" ||
|
|
460
|
+
!Number.isFinite(value)) {
|
|
461
|
+
throw new InvalidScientificInputError(path + " must be finite.");
|
|
462
|
+
}
|
|
463
|
+
return value;
|
|
464
|
+
}
|
|
465
|
+
function requireScientificPositiveFinite(value, path) {
|
|
466
|
+
const parsed = requireScientificFinite(value, path);
|
|
467
|
+
if (parsed <= 0) {
|
|
468
|
+
throw new InvalidScientificInputError(path +
|
|
469
|
+
" must be greater than zero.");
|
|
470
|
+
}
|
|
471
|
+
return parsed;
|
|
472
|
+
}
|
|
473
|
+
function bracketAxis(values, target, path) {
|
|
474
|
+
const minimum = values[0];
|
|
475
|
+
const maximum = values[values.length - 1];
|
|
476
|
+
const scale = Math.max(1, Math.abs(target), Math.abs(minimum), Math.abs(maximum));
|
|
477
|
+
const tolerance = Number.EPSILON *
|
|
478
|
+
64 *
|
|
479
|
+
scale;
|
|
480
|
+
if (target <
|
|
481
|
+
minimum - tolerance ||
|
|
482
|
+
target >
|
|
483
|
+
maximum + tolerance) {
|
|
484
|
+
throw new InvalidScientificInputError(path +
|
|
485
|
+
" lies outside the declared PSF profile grid; extrapolation is not permitted.");
|
|
486
|
+
}
|
|
487
|
+
for (const value of values) {
|
|
488
|
+
if (Math.abs(target - value) <= tolerance) {
|
|
489
|
+
return {
|
|
490
|
+
lower: value,
|
|
491
|
+
upper: value,
|
|
492
|
+
fraction: 0,
|
|
493
|
+
exact: true
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
for (let index = 0; index <
|
|
498
|
+
values.length - 1; index += 1) {
|
|
499
|
+
const lower = values[index];
|
|
500
|
+
const upper = values[index + 1];
|
|
501
|
+
if (target > lower &&
|
|
502
|
+
target < upper) {
|
|
503
|
+
return {
|
|
504
|
+
lower,
|
|
505
|
+
upper,
|
|
506
|
+
fraction: (target - lower) /
|
|
507
|
+
(upper - lower),
|
|
508
|
+
exact: false
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
throw new InvalidScientificInputError(path +
|
|
513
|
+
" could not be bracketed inside the declared PSF profile grid.");
|
|
514
|
+
}
|
|
515
|
+
function queryCoordinate(input) {
|
|
516
|
+
const focus = parseFocusPlane(input.focus);
|
|
517
|
+
return {
|
|
518
|
+
coordinate: {
|
|
519
|
+
focalLengthMm: requireScientificPositiveFinite(input.focalLengthMm, "focalLengthMm"),
|
|
520
|
+
focusDiopters: focusDiopters(focus),
|
|
521
|
+
apertureFNumber: requireScientificPositiveFinite(input.apertureFNumber, "apertureFNumber"),
|
|
522
|
+
fieldXmm: requireScientificFinite(input.fieldPointMm.x, "fieldPointMm.x"),
|
|
523
|
+
fieldYmm: requireScientificFinite(input.fieldPointMm.y, "fieldPointMm.y"),
|
|
524
|
+
wavelengthNm: requireScientificPositiveFinite(input.wavelengthNm, "wavelengthNm"),
|
|
525
|
+
signedDefocusImagePlaneMicrometers: requireScientificFinite(input
|
|
526
|
+
.signedDefocusImagePlaneMicrometers, "signedDefocusImagePlaneMicrometers")
|
|
527
|
+
},
|
|
528
|
+
focus
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
function bracketCoordinate(axes, coordinate) {
|
|
532
|
+
return {
|
|
533
|
+
focalLengthMm: bracketAxis(axes.focalLengthMm, coordinate.focalLengthMm, "focalLengthMm"),
|
|
534
|
+
focusDiopters: bracketAxis(axes.focusDiopters, coordinate.focusDiopters, "focus"),
|
|
535
|
+
apertureFNumber: bracketAxis(axes.apertureFNumber, coordinate.apertureFNumber, "apertureFNumber"),
|
|
536
|
+
fieldXmm: bracketAxis(axes.fieldXmm, coordinate.fieldXmm, "fieldPointMm.x"),
|
|
537
|
+
fieldYmm: bracketAxis(axes.fieldYmm, coordinate.fieldYmm, "fieldPointMm.y"),
|
|
538
|
+
wavelengthNm: bracketAxis(axes.wavelengthNm, coordinate.wavelengthNm, "wavelengthNm"),
|
|
539
|
+
signedDefocusImagePlaneMicrometers: bracketAxis(axes
|
|
540
|
+
.signedDefocusImagePlaneMicrometers, coordinate
|
|
541
|
+
.signedDefocusImagePlaneMicrometers, "signedDefocusImagePlaneMicrometers")
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
function cornerCoordinates(brackets) {
|
|
545
|
+
let corners = [{
|
|
546
|
+
partial: {},
|
|
547
|
+
weight: 1
|
|
548
|
+
}];
|
|
549
|
+
for (const key of AXIS_KEYS) {
|
|
550
|
+
const bracket = brackets[key];
|
|
551
|
+
const values = bracket.exact
|
|
552
|
+
? [{
|
|
553
|
+
value: bracket.lower,
|
|
554
|
+
weight: 1
|
|
555
|
+
}]
|
|
556
|
+
: [
|
|
557
|
+
{
|
|
558
|
+
value: bracket.lower,
|
|
559
|
+
weight: 1 -
|
|
560
|
+
bracket.fraction
|
|
561
|
+
},
|
|
562
|
+
{
|
|
563
|
+
value: bracket.upper,
|
|
564
|
+
weight: bracket.fraction
|
|
565
|
+
}
|
|
566
|
+
];
|
|
567
|
+
const next = [];
|
|
568
|
+
for (const corner of corners) {
|
|
569
|
+
for (const option of values) {
|
|
570
|
+
if (option.weight === 0) {
|
|
571
|
+
continue;
|
|
572
|
+
}
|
|
573
|
+
next.push({
|
|
574
|
+
partial: {
|
|
575
|
+
...corner.partial,
|
|
576
|
+
[key]: option.value
|
|
577
|
+
},
|
|
578
|
+
weight: corner.weight *
|
|
579
|
+
option.weight
|
|
580
|
+
});
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
corners = next;
|
|
584
|
+
}
|
|
585
|
+
return corners.map((corner) => ({
|
|
586
|
+
coordinate: corner.partial,
|
|
587
|
+
weight: corner.weight
|
|
588
|
+
}));
|
|
589
|
+
}
|
|
590
|
+
function resolveWeightedNodes(profile, brackets) {
|
|
591
|
+
const byKey = new Map(profile.nodes.map((node) => [
|
|
592
|
+
coordinateKey(node.coordinate),
|
|
593
|
+
node
|
|
594
|
+
]));
|
|
595
|
+
return cornerCoordinates(brackets).map((corner) => {
|
|
596
|
+
const node = byKey.get(coordinateKey(corner.coordinate));
|
|
597
|
+
if (node === undefined) {
|
|
598
|
+
throw new InvalidScientificInputError("PSF profile grid is missing a required interpolation corner.");
|
|
599
|
+
}
|
|
600
|
+
return {
|
|
601
|
+
node,
|
|
602
|
+
weight: corner.weight
|
|
603
|
+
};
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
function interpolateKernel(weighted) {
|
|
607
|
+
const first = weighted[0]?.node.kernel;
|
|
608
|
+
if (first === undefined) {
|
|
609
|
+
throw new InvalidScientificInputError("PSF interpolation requires at least one source node.");
|
|
610
|
+
}
|
|
611
|
+
const values = new Array(first
|
|
612
|
+
.normalizedIntensity
|
|
613
|
+
.length).fill(0);
|
|
614
|
+
for (const entry of weighted) {
|
|
615
|
+
for (let index = 0; index < values.length; index += 1) {
|
|
616
|
+
values[index] +=
|
|
617
|
+
entry.weight *
|
|
618
|
+
entry.node.kernel
|
|
619
|
+
.normalizedIntensity[index];
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
const sum = values.reduce((acc, value) => acc + value, 0);
|
|
623
|
+
if (!Number.isFinite(sum) ||
|
|
624
|
+
sum <= 0) {
|
|
625
|
+
throw new InvalidScientificInputError("Interpolated PSF energy must remain finite and positive.");
|
|
626
|
+
}
|
|
627
|
+
const normalized = values.map((value) => value / sum);
|
|
628
|
+
return {
|
|
629
|
+
widthSamples: first.widthSamples,
|
|
630
|
+
heightSamples: first.heightSamples,
|
|
631
|
+
samplePitchMicrometersX: first
|
|
632
|
+
.samplePitchMicrometersX,
|
|
633
|
+
samplePitchMicrometersY: first
|
|
634
|
+
.samplePitchMicrometersY,
|
|
635
|
+
centerSampleX: first.centerSampleX,
|
|
636
|
+
centerSampleY: first.centerSampleY,
|
|
637
|
+
normalizedIntensity: normalized
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
function weightedScalar(weighted, select) {
|
|
641
|
+
return weighted.reduce((sum, entry) => sum +
|
|
642
|
+
entry.weight *
|
|
643
|
+
select(entry.node), 0);
|
|
644
|
+
}
|
|
645
|
+
/**
|
|
646
|
+
* Resolve the bounded sampled PSF for a declared optical state and support point without extrapolation
|
|
647
|
+
* or silently inventing missing dimensions.
|
|
648
|
+
*
|
|
649
|
+
* Sampled lens PSF shapes bind exact generic optical state, field, wavelength and signed defocus
|
|
650
|
+
* support. Interpolation stays within declared applicability and preserves normalized shape separately
|
|
651
|
+
* from throughput. MTF-only data lacks phase/spatial information and does not authorize rendering a
|
|
652
|
+
* unique PSF.
|
|
653
|
+
* @param input - ResolveLensSampledPsfInput. See the linked contract for coordinate, unit and profile binding semantics.
|
|
654
|
+
* @returns CalculationResult<ResolvedLensSampledPsf>. Return shape and scientific status are explicit; no calibration is inferred from successful execution.
|
|
655
|
+
*
|
|
656
|
+
* @see docs/API_REFERENCE.md for the root export and exact type graph.
|
|
657
|
+
*/
|
|
658
|
+
export function resolveLensSampledPsf(input) {
|
|
659
|
+
const profile = parseLensSampledPsfProfile(input.profile);
|
|
660
|
+
const query = queryCoordinate(input);
|
|
661
|
+
const brackets = bracketCoordinate(profile.axes, query.coordinate);
|
|
662
|
+
const weighted = resolveWeightedNodes(profile, brackets);
|
|
663
|
+
const exact = AXIS_KEYS.every((key) => brackets[key].exact);
|
|
664
|
+
const kernel = interpolateKernel(weighted);
|
|
665
|
+
const bestFocus = weightedScalar(weighted, (node) => node
|
|
666
|
+
.bestFocusImagePlaneOffsetMicrometers);
|
|
667
|
+
const throughput = weightedScalar(weighted, (node) => node
|
|
668
|
+
.relativePupilThroughputFactor);
|
|
669
|
+
if (!Number.isFinite(bestFocus) ||
|
|
670
|
+
!Number.isFinite(throughput) ||
|
|
671
|
+
throughput < 0 ||
|
|
672
|
+
throughput > 1) {
|
|
673
|
+
throw new InvalidScientificInputError("Interpolated PSF metadata must remain finite and physically bounded.");
|
|
674
|
+
}
|
|
675
|
+
return approximationResult({
|
|
676
|
+
profileId: profile.profileId,
|
|
677
|
+
profileVersion: profile.profileVersion,
|
|
678
|
+
scientificStatus: profile.scientificStatus,
|
|
679
|
+
resolutionStatus: exact
|
|
680
|
+
? "exact-grid-sample"
|
|
681
|
+
: "interpolated",
|
|
682
|
+
coordinate: query.coordinate,
|
|
683
|
+
focus: query.focus,
|
|
684
|
+
kernel,
|
|
685
|
+
bestFocusImagePlaneOffsetMicrometers: bestFocus,
|
|
686
|
+
relativePupilThroughputFactor: throughput,
|
|
687
|
+
sourceNodes: weighted.map((entry) => ({
|
|
688
|
+
nodeId: entry.node.nodeId,
|
|
689
|
+
weight: entry.weight,
|
|
690
|
+
evidence: entry.node.evidence,
|
|
691
|
+
uncertainty: entry.node
|
|
692
|
+
.uncertainty
|
|
693
|
+
})),
|
|
694
|
+
responseIncludes: {
|
|
695
|
+
...profile
|
|
696
|
+
.responseIncludes
|
|
697
|
+
},
|
|
698
|
+
throughputOwnership: "separate-relative-pupil-throughput-factor",
|
|
699
|
+
longitudinalChromaticFocusMayVaryWithWavelength: true,
|
|
700
|
+
fieldCurvatureMayVaryWithFieldPosition: true,
|
|
701
|
+
geometricDistortionModified: false,
|
|
702
|
+
lateralChromaticPositionShiftApplied: false,
|
|
703
|
+
sensorOpticalStackIncluded: false,
|
|
704
|
+
sensorSamplingIncluded: false,
|
|
705
|
+
reconstructionIncluded: false,
|
|
706
|
+
strayLightIncluded: false,
|
|
707
|
+
scalarSharpnessScoreProduced: false
|
|
708
|
+
}, "lens-sampled-psf-bounded-interpolation", "1.0.0", [
|
|
709
|
+
"PSF intensity is a unit-energy shape; relative pupil throughput remains a separate factor for the optical-throughput path.",
|
|
710
|
+
"Regular-grid interpolation is bounded and never extrapolates beyond declared focal-length, focus, aperture, field, wavelength or signed-defocus axes.",
|
|
711
|
+
"Full 2D image-plane kernel orientation is preserved in +X right, +Y up coordinates; no radial or sagittal/tangential averaging is forced.",
|
|
712
|
+
"bestFocusImagePlaneOffsetMicrometers may vary with field and wavelength, representing field-curvature and longitudinal-chromatic-focus behavior without changing geometric distortion or lateral chromatic position.",
|
|
713
|
+
"Lens PSF remains upstream of sensor optical stack, sampling and reconstruction, and excludes stray-light/ghosting contributions.",
|
|
714
|
+
"No scalar lens-quality, sharpness or bokeh-quality score is produced."
|
|
715
|
+
]);
|
|
716
|
+
}
|
|
717
|
+
/**
|
|
718
|
+
* Validate an untrusted declaration and return the normalized typed contract. Unknown enum values,
|
|
719
|
+
* missing required fields and incompatible scientific data fail at this boundary.
|
|
720
|
+
*
|
|
721
|
+
* Sampled lens PSF shapes bind exact generic optical state, field, wavelength and signed defocus
|
|
722
|
+
* support. Interpolation stays within declared applicability and preserves normalized shape separately
|
|
723
|
+
* from throughput. MTF-only data lacks phase/spatial information and does not authorize rendering a
|
|
724
|
+
* unique PSF.
|
|
725
|
+
* @param value - unknown. Treated as untrusted data; static typing alone is not validation.
|
|
726
|
+
* @returns LensMtfDiagnosticProfile. Return shape and scientific status are explicit; no calibration is inferred from successful execution.
|
|
727
|
+
*
|
|
728
|
+
* @see docs/API_REFERENCE.md for the root export and exact type graph.
|
|
729
|
+
*/
|
|
730
|
+
export function parseLensMtfDiagnosticProfile(value) {
|
|
731
|
+
const record = requireRecord(value, "lensMtfProfile");
|
|
732
|
+
if (record.schemaVersion !==
|
|
733
|
+
LENS_MTF_DIAGNOSTIC_PROFILE_SCHEMA_VERSION) {
|
|
734
|
+
throw new InvalidConfigurationError('lensMtfProfile.schemaVersion must be "' +
|
|
735
|
+
LENS_MTF_DIAGNOSTIC_PROFILE_SCHEMA_VERSION +
|
|
736
|
+
'".');
|
|
737
|
+
}
|
|
738
|
+
if (record.opticalDomain !==
|
|
739
|
+
"lens-primary-optical-path-only" ||
|
|
740
|
+
record.phaseInformationAvailable !==
|
|
741
|
+
false ||
|
|
742
|
+
record.magnitudeMeaning !==
|
|
743
|
+
"mtf-magnitude-only") {
|
|
744
|
+
throw new InvalidConfigurationError("lensMtfProfile optical/phase semantics are invalid.");
|
|
745
|
+
}
|
|
746
|
+
if (!Array.isArray(record.samples) ||
|
|
747
|
+
record.samples.length ===
|
|
748
|
+
0) {
|
|
749
|
+
throw new InvalidConfigurationError("lensMtfProfile.samples must be a non-empty array.");
|
|
750
|
+
}
|
|
751
|
+
let priorFrequency = -1;
|
|
752
|
+
const samples = record.samples.map((entry, index) => {
|
|
753
|
+
const path = "lensMtfProfile.samples[" +
|
|
754
|
+
index +
|
|
755
|
+
"]";
|
|
756
|
+
const sample = requireRecord(entry, path);
|
|
757
|
+
const frequency = requireNonNegativeFinite(sample
|
|
758
|
+
.spatialFrequencyCyclesPerMm, path +
|
|
759
|
+
".spatialFrequencyCyclesPerMm");
|
|
760
|
+
if (frequency <=
|
|
761
|
+
priorFrequency) {
|
|
762
|
+
throw new InvalidConfigurationError("lensMtfProfile sample frequencies must be strictly increasing.");
|
|
763
|
+
}
|
|
764
|
+
priorFrequency =
|
|
765
|
+
frequency;
|
|
766
|
+
return {
|
|
767
|
+
spatialFrequencyCyclesPerMm: frequency,
|
|
768
|
+
sagittalMagnitude: requireUnitInterval(sample
|
|
769
|
+
.sagittalMagnitude, path +
|
|
770
|
+
".sagittalMagnitude"),
|
|
771
|
+
tangentialMagnitude: requireUnitInterval(sample
|
|
772
|
+
.tangentialMagnitude, path +
|
|
773
|
+
".tangentialMagnitude")
|
|
774
|
+
};
|
|
775
|
+
});
|
|
776
|
+
const field = requireRecord(record.fieldPointMm, "lensMtfProfile.fieldPointMm");
|
|
777
|
+
const wavelength = record.wavelengthNm ===
|
|
778
|
+
null
|
|
779
|
+
? null
|
|
780
|
+
: requirePositiveFinite(record.wavelengthNm, "lensMtfProfile.wavelengthNm");
|
|
781
|
+
return {
|
|
782
|
+
schemaVersion: LENS_MTF_DIAGNOSTIC_PROFILE_SCHEMA_VERSION,
|
|
783
|
+
profileId: requireNonEmptyString(record.profileId, "lensMtfProfile.profileId"),
|
|
784
|
+
profileVersion: requireNonEmptyString(record.profileVersion, "lensMtfProfile.profileVersion"),
|
|
785
|
+
opticalDomain: "lens-primary-optical-path-only",
|
|
786
|
+
phaseInformationAvailable: false,
|
|
787
|
+
magnitudeMeaning: "mtf-magnitude-only",
|
|
788
|
+
fieldPointMm: {
|
|
789
|
+
x: requireFinite(field.x, "lensMtfProfile.fieldPointMm.x"),
|
|
790
|
+
y: requireFinite(field.y, "lensMtfProfile.fieldPointMm.y")
|
|
791
|
+
},
|
|
792
|
+
focalLengthMm: requirePositiveFinite(record.focalLengthMm, "lensMtfProfile.focalLengthMm"),
|
|
793
|
+
focus: parseFocusPlane(record.focus),
|
|
794
|
+
apertureFNumber: requirePositiveFinite(record.apertureFNumber, "lensMtfProfile.apertureFNumber"),
|
|
795
|
+
wavelengthNm: wavelength,
|
|
796
|
+
samples,
|
|
797
|
+
evidence: parseEvidenceList(record.evidence, "lensMtfProfile.evidence"),
|
|
798
|
+
limitations: parseLimitations(record.limitations, "lensMtfProfile.limitations")
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
/**
|
|
802
|
+
* Explain why MTF-only evidence cannot determine a unique renderable PSF; return blockers instead of
|
|
803
|
+
* fabricating phase information.
|
|
804
|
+
*
|
|
805
|
+
* Sampled lens PSF shapes bind exact generic optical state, field, wavelength and signed defocus
|
|
806
|
+
* support. Interpolation stays within declared applicability and preserves normalized shape separately
|
|
807
|
+
* from throughput. MTF-only data lacks phase/spatial information and does not authorize rendering a
|
|
808
|
+
* unique PSF.
|
|
809
|
+
* @param profile - LensMtfDiagnosticProfile. See the linked contract for coordinate, unit and profile binding semantics.
|
|
810
|
+
* @returns MtfOnlyPsfRenderabilityAssessment. Read structured blockers before consuming an authorization.
|
|
811
|
+
*
|
|
812
|
+
* @see docs/API_REFERENCE.md for the root export and exact type graph.
|
|
813
|
+
*/
|
|
814
|
+
export function assessMtfOnlyPsfRenderability(profile) {
|
|
815
|
+
const parsed = parseLensMtfDiagnosticProfile(profile);
|
|
816
|
+
return {
|
|
817
|
+
profileId: parsed.profileId,
|
|
818
|
+
psfReconstructionAuthorized: false,
|
|
819
|
+
reason: "mtf-magnitude-lacks-phase-and-does-not-uniquely-determine-psf",
|
|
820
|
+
diagnosticUseAuthorized: true
|
|
821
|
+
};
|
|
822
|
+
}
|
|
823
|
+
//# sourceMappingURL=lens-psf-profile.js.map
|