@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
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// This product includes DNG technology under license by Adobe.
|
|
3
|
+
/**
|
|
4
|
+
* @internal #587: a catalogue lens's generic corrections (`createGenericLensCorrectionProfile`, the same arithmetic as `output.lensCorrections`)
|
|
5
|
+
* written as a DNG opcode list, so a RAW editor that applies DNG opcodes corrects the DNG non-destructively; the RAW codes are never
|
|
6
|
+
* changed. Written from the Adobe DNG Specification (opcode lists were added in version 1.3.0.0; the repository's writer follows
|
|
7
|
+
* 1.7.1.0), chapter "Opcode List Processing":
|
|
8
|
+
*
|
|
9
|
+
* - The list goes into OpcodeList3 (tag 51022, UNDEFINED), which a reader applies to the linear, demosaiced stage-3 image: the
|
|
10
|
+
* ActiveArea, which for `simulateCapture` is exactly the output frame. The list is big-endian whatever the file's byte order: a
|
|
11
|
+
* LONG opcode count, then per opcode its LONG id, the four-byte DNG version that introduced it (1.3.0.0), LONG flags and the LONG
|
|
12
|
+
* byte count of its parameters. Every opcode is written with flag bit 0 ("optional") set, so a reader that does not support it may
|
|
13
|
+
* skip it, and bit 1 (preview skip) clear.
|
|
14
|
+
* - FixVignetteRadial (id 3) first, when vignetting is on: parameters k0…k4, cx, cy (DOUBLE); each pixel is multiplied by
|
|
15
|
+
* g = 1 + k0r² + k1r⁴ + k2r⁶ + k3r⁸ + k4r¹⁰, r the distance from the optical centre (cx, cy) normalized to 1 at the image's
|
|
16
|
+
* farthest corner. It runs before the warp, so it acts at the captured (source) position, where the capture applied the falloff.
|
|
17
|
+
* The target gain is the profile's (#584): G(ρ) = det J(ρ_i)/E(ρ), E = (1 − bρ²)² the lens's relative illumination at the
|
|
18
|
+
* capture's f-number and det J = (1 + k1ρ_i²)(1 + 3k1ρ_i²) at the ideal radius ρ_i with ρ_i(1 + k1ρ_i²) = ρ (the lens's own k1,
|
|
19
|
+
* whether or not distortion is corrected). G is not a polynomial in r², so k0…k4 are a near-minimax fit of g/G − 1 (Lawson's
|
|
20
|
+
* iteratively reweighted least squares) on 2 048 radii in [0, 1]; its largest |g/G − 1| there is reported, and a fit worse than
|
|
21
|
+
* 0.1 % is refused (every catalogue lens fits within 0.07 %; GainMap, id 9, would be needed otherwise).
|
|
22
|
+
* - WarpRectilinear (id 1) then, when distortion or lateral colour is on: N = 1 plane (no lateral colour) or 3 planes (red,
|
|
23
|
+
* green, blue; CFAPlaneColor 0 1 2), each kr0…kr3, kt0, kt1, then cx, cy (DOUBLE). For a destination pixel at normalized
|
|
24
|
+
* offset (dx, dy) from the centre, r² = dx² + dy², the source is the centre plus (dx, dy)·(kr0 + kr1r² + kr2r⁴ + kr3r⁶) plus the
|
|
25
|
+
* tangential terms (kt0 = kt1 = 0 here). `output.lensCorrections` reads channel c at s = q(1 + k1|q|²/R²), q = m·a_c·p (R the
|
|
26
|
+
* half-diagonal, a_c the channel's lateral-colour scale, m the zoom-to-fill factor): so kr0 = m·a_c, kr1 = k1·(m·a_c)³·(R_DNG/R)²,
|
|
27
|
+
* kr2 = kr3 = 0 represent it exactly (R_DNG the centre-to-corner distance of the stage-3 image; equal to R for `simulateCapture`).
|
|
28
|
+
* The zoom-to-fill of #570 is folded into kr0, so an editor's result has the corrected JPEG's framing.
|
|
29
|
+
* - The optical centre is the image centre, cx = cy = 0.5 (0 the left or top edge, 1 the right or bottom edge).
|
|
30
|
+
*
|
|
31
|
+
* Limits: the gain is an approximation fitted to the profile (itself a labelled catalogue approximation); a reader's resampling
|
|
32
|
+
* filter, and whether it applies opcodes at all, is the reader's. Some editors apply DNG opcodes automatically with no control in
|
|
33
|
+
* the editor: the switch that is guaranteed is leaving a correction out of the DNG.
|
|
34
|
+
*/
|
|
35
|
+
import { InvalidConfigurationError } from "../core/configuration-error.js";
|
|
36
|
+
import { prepareDevelopedLensCorrection } from "../output/developed-lens-corrections.js";
|
|
37
|
+
/** @internal Largest accepted |g/G − 1| of the FixVignetteRadial fit. */
|
|
38
|
+
export const DNG_VIGNETTE_FIT_TOLERANCE = 1e-3;
|
|
39
|
+
/**
|
|
40
|
+
* @internal The OpcodeList3 bytes and the opcodes for a catalogue lens (`resolveGenericLens` at the capture's f-number, on the
|
|
41
|
+
* W × H ActiveArea of pitch `pitchMm`) and the selected corrections, at least one on (see the module notes).
|
|
42
|
+
*/
|
|
43
|
+
export function createDngLensCorrectionOpcodes(lens, selection, width, height, pitchMm, dispersion) {
|
|
44
|
+
const opcodes = [], params = [];
|
|
45
|
+
// R_DNG / R: the stage-3 image's centre-to-corner distance over the profile's half-diagonal (1 when the frame is the lens's area).
|
|
46
|
+
const scale = Math.hypot(width, height) / 2 / (lens.halfDiagonalMm / pitchMm);
|
|
47
|
+
if (selection.vignetting) {
|
|
48
|
+
const b = 1 - 2 ** (-lens.character.vignetting.cornerStops / 2), k1 = lens.character.distortion.corner;
|
|
49
|
+
const target = (r) => {
|
|
50
|
+
const rho = r * scale, e = 1 - b * rho * rho;
|
|
51
|
+
let ri = rho;
|
|
52
|
+
for (let n = 0; n < 8; n++)
|
|
53
|
+
ri -= (ri * (1 + k1 * ri * ri) - rho) / (1 + 3 * k1 * ri * ri);
|
|
54
|
+
return (1 + k1 * ri * ri) * (1 + 3 * k1 * ri * ri) / (e * e);
|
|
55
|
+
};
|
|
56
|
+
// Near-minimax fit of the relative error g/G − 1 (t = r²: rows t^j/G, j = 1…5, against 1 − 1/G) by Lawson's iteratively
|
|
57
|
+
// reweighted least squares on 2 048 radii in [0, 1] (normal equations, positive definite); of 64 iterations the one with the
|
|
58
|
+
// smallest largest error on those radii is kept.
|
|
59
|
+
const radii = Array.from({ length: 2048 }, (_, i) => { const r = i / 2047; return [r * r, target(r), 1]; });
|
|
60
|
+
let best = [0, 0, 0, 0, 0], worst = Infinity;
|
|
61
|
+
for (let iteration = 0; iteration < 64; iteration++) {
|
|
62
|
+
const a = Array.from({ length: 5 }, () => [0, 0, 0, 0, 0, 0]), k = [0, 0, 0, 0, 0];
|
|
63
|
+
for (const [t, G, w] of radii) {
|
|
64
|
+
const row = [t, t ** 2, t ** 3, t ** 4, t ** 5, G - 1].map((v) => v / G);
|
|
65
|
+
for (let j = 0; j < 5; j++)
|
|
66
|
+
for (let m = 0; m < 6; m++)
|
|
67
|
+
a[j][m] += w * row[j] * row[m];
|
|
68
|
+
}
|
|
69
|
+
for (let j = 0; j < 5; j++)
|
|
70
|
+
for (let i = j + 1; i < 5; i++) {
|
|
71
|
+
const f = a[i][j] / a[j][j];
|
|
72
|
+
for (let m = j; m < 6; m++)
|
|
73
|
+
a[i][m] -= f * a[j][m];
|
|
74
|
+
}
|
|
75
|
+
for (let j = 4; j >= 0; j--)
|
|
76
|
+
k[j] = (a[j][5] - a[j].slice(j + 1, 5).reduce((sum, v, m) => sum + v * k[j + 1 + m], 0)) / a[j][j];
|
|
77
|
+
const errors = radii.map(([t, G]) => Math.abs((1 + t * (k[0] + t * (k[1] + t * (k[2] + t * (k[3] + t * k[4]))))) / G - 1)), max = Math.max(...errors);
|
|
78
|
+
if (max < worst) {
|
|
79
|
+
worst = max;
|
|
80
|
+
best = k;
|
|
81
|
+
}
|
|
82
|
+
radii.forEach((p, i) => { p[2] = p[2] * (errors[i] / max + 1e-9); });
|
|
83
|
+
}
|
|
84
|
+
if (!(worst <= DNG_VIGNETTE_FIT_TOLERANCE))
|
|
85
|
+
throw new InvalidConfigurationError("output.dng.lensCorrectionOpcodes: FixVignetteRadial cannot hold " + lens.name + "'s vignetting gain within 0.1 %.");
|
|
86
|
+
opcodes.push({ opcode: "FixVignetteRadial", coefficients: best, maximumRelativeFitError: worst });
|
|
87
|
+
params.push([...best, 0.5, 0.5]);
|
|
88
|
+
}
|
|
89
|
+
if (selection.distortion || selection.lateralColor) {
|
|
90
|
+
const c = prepareDevelopedLensCorrection(lens, { ...selection, vignetting: false }, width, height, pitchMm, dispersion);
|
|
91
|
+
const planes = (selection.lateralColor ? c.scales : [1]).map((s) => { const a = c.fill * s; return [a, c.k1 * a ** 3 * scale * scale, 0, 0, 0, 0]; });
|
|
92
|
+
opcodes.push({ opcode: "WarpRectilinear", planes, magnification: 1 / c.fill });
|
|
93
|
+
params.push([planes.length, ...planes.flat(), 0.5, 0.5]);
|
|
94
|
+
}
|
|
95
|
+
// Big-endian: the count, then per opcode its id, DNG version 1.3.0.0, flags 1 (optional), parameter bytes and parameters
|
|
96
|
+
// (all DOUBLE but WarpRectilinear's leading LONG plane count).
|
|
97
|
+
const size = (i) => params[i].length * 8 - (opcodes[i].opcode === "WarpRectilinear" ? 4 : 0);
|
|
98
|
+
const bytes = new Uint8Array(4 + params.reduce((sum, _, i) => sum + 16 + size(i), 0)), view = new DataView(bytes.buffer);
|
|
99
|
+
view.setUint32(0, opcodes.length);
|
|
100
|
+
let at = 4;
|
|
101
|
+
params.forEach((values, i) => {
|
|
102
|
+
const warp = opcodes[i].opcode === "WarpRectilinear";
|
|
103
|
+
view.setUint32(at, warp ? 1 : 3);
|
|
104
|
+
view.setUint32(at + 4, 0x01030000);
|
|
105
|
+
view.setUint32(at + 8, 1);
|
|
106
|
+
view.setUint32(at + 12, size(i));
|
|
107
|
+
at += 16;
|
|
108
|
+
values.forEach((v, j) => { if (warp && j === 0) {
|
|
109
|
+
view.setUint32(at, v);
|
|
110
|
+
at += 4;
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
view.setFloat64(at, v);
|
|
114
|
+
at += 8;
|
|
115
|
+
} });
|
|
116
|
+
});
|
|
117
|
+
return { opcodeList3: bytes, opcodes };
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=dng-lens-correction-opcodes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dng-lens-correction-opcodes.js","sourceRoot":"","sources":["../../src/capture/dng-lens-correction-opcodes.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n// This product includes DNG technology under license by Adobe.\n\n/**\n * @internal #587: a catalogue lens's generic corrections (`createGenericLensCorrectionProfile`, the same arithmetic as `output.lensCorrections`)\n * written as a DNG opcode list, so a RAW editor that applies DNG opcodes corrects the DNG non-destructively; the RAW codes are never\n * changed. Written from the Adobe DNG Specification (opcode lists were added in version 1.3.0.0; the repository's writer follows\n * 1.7.1.0), chapter \"Opcode List Processing\":\n *\n * - The list goes into OpcodeList3 (tag 51022, UNDEFINED), which a reader applies to the linear, demosaiced stage-3 image: the\n * ActiveArea, which for `simulateCapture` is exactly the output frame. The list is big-endian whatever the file's byte order: a\n * LONG opcode count, then per opcode its LONG id, the four-byte DNG version that introduced it (1.3.0.0), LONG flags and the LONG\n * byte count of its parameters. Every opcode is written with flag bit 0 (\"optional\") set, so a reader that does not support it may\n * skip it, and bit 1 (preview skip) clear.\n * - FixVignetteRadial (id 3) first, when vignetting is on: parameters k0…k4, cx, cy (DOUBLE); each pixel is multiplied by\n * g = 1 + k0r² + k1r⁴ + k2r⁶ + k3r⁸ + k4r¹⁰, r the distance from the optical centre (cx, cy) normalized to 1 at the image's\n * farthest corner. It runs before the warp, so it acts at the captured (source) position, where the capture applied the falloff.\n * The target gain is the profile's (#584): G(ρ) = det J(ρ_i)/E(ρ), E = (1 − bρ²)² the lens's relative illumination at the\n * capture's f-number and det J = (1 + k1ρ_i²)(1 + 3k1ρ_i²) at the ideal radius ρ_i with ρ_i(1 + k1ρ_i²) = ρ (the lens's own k1,\n * whether or not distortion is corrected). G is not a polynomial in r², so k0…k4 are a near-minimax fit of g/G − 1 (Lawson's\n * iteratively reweighted least squares) on 2 048 radii in [0, 1]; its largest |g/G − 1| there is reported, and a fit worse than\n * 0.1 % is refused (every catalogue lens fits within 0.07 %; GainMap, id 9, would be needed otherwise).\n * - WarpRectilinear (id 1) then, when distortion or lateral colour is on: N = 1 plane (no lateral colour) or 3 planes (red,\n * green, blue; CFAPlaneColor 0 1 2), each kr0…kr3, kt0, kt1, then cx, cy (DOUBLE). For a destination pixel at normalized\n * offset (dx, dy) from the centre, r² = dx² + dy², the source is the centre plus (dx, dy)·(kr0 + kr1r² + kr2r⁴ + kr3r⁶) plus the\n * tangential terms (kt0 = kt1 = 0 here). `output.lensCorrections` reads channel c at s = q(1 + k1|q|²/R²), q = m·a_c·p (R the\n * half-diagonal, a_c the channel's lateral-colour scale, m the zoom-to-fill factor): so kr0 = m·a_c, kr1 = k1·(m·a_c)³·(R_DNG/R)²,\n * kr2 = kr3 = 0 represent it exactly (R_DNG the centre-to-corner distance of the stage-3 image; equal to R for `simulateCapture`).\n * The zoom-to-fill of #570 is folded into kr0, so an editor's result has the corrected JPEG's framing.\n * - The optical centre is the image centre, cx = cy = 0.5 (0 the left or top edge, 1 the right or bottom edge).\n *\n * Limits: the gain is an approximation fitted to the profile (itself a labelled catalogue approximation); a reader's resampling\n * filter, and whether it applies opcodes at all, is the reader's. Some editors apply DNG opcodes automatically with no control in\n * the editor: the switch that is guaranteed is leaving a correction out of the DNG.\n */\n\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport { prepareDevelopedLensCorrection, type DevelopedLensCorrectionSelection } from \"../output/developed-lens-corrections.js\";\n\n/** @internal An opcode as written (application order), for the assumptions. */\nexport type DngLensCorrectionOpcode =\n /** k0…k4 of g = 1 + k0r² + … + k4r¹⁰, and the largest |g/G − 1| on 2 048 radii in [0, 1]. */\n | { opcode: \"FixVignetteRadial\"; coefficients: number[]; maximumRelativeFitError: number }\n /** kr0…kr3, kt0, kt1 of one plane (all channels) or red, green, blue; the zoom-to-fill 1/m folded into kr0. */\n | { opcode: \"WarpRectilinear\"; planes: number[][]; magnification: number };\n\n/** @internal Largest accepted |g/G − 1| of the FixVignetteRadial fit. */\nexport const DNG_VIGNETTE_FIT_TOLERANCE = 1e-3;\n\n/**\n * @internal The OpcodeList3 bytes and the opcodes for a catalogue lens (`resolveGenericLens` at the capture's f-number, on the\n * W × H ActiveArea of pitch `pitchMm`) and the selected corrections, at least one on (see the module notes).\n */\nexport function createDngLensCorrectionOpcodes(lens: Parameters<typeof prepareDevelopedLensCorrection>[0] & { name: string; character: { vignetting: { cornerStops: number } } },\n selection: DevelopedLensCorrectionSelection, width: number, height: number, pitchMm: number, dispersion: (wavelengthNm: number) => number): { opcodeList3: Uint8Array; opcodes: DngLensCorrectionOpcode[] } {\n const opcodes: DngLensCorrectionOpcode[] = [], params: number[][] = [];\n // R_DNG / R: the stage-3 image's centre-to-corner distance over the profile's half-diagonal (1 when the frame is the lens's area).\n const scale = Math.hypot(width, height) / 2 / (lens.halfDiagonalMm / pitchMm);\n if (selection.vignetting) {\n const b = 1 - 2 ** (-lens.character.vignetting.cornerStops / 2), k1 = lens.character.distortion.corner;\n const target = (r: number): number => {\n const rho = r * scale, e = 1 - b * rho * rho;\n let ri = rho;\n for (let n = 0; n < 8; n++) ri -= (ri * (1 + k1 * ri * ri) - rho) / (1 + 3 * k1 * ri * ri);\n return (1 + k1 * ri * ri) * (1 + 3 * k1 * ri * ri) / (e * e);\n };\n // Near-minimax fit of the relative error g/G − 1 (t = r²: rows t^j/G, j = 1…5, against 1 − 1/G) by Lawson's iteratively\n // reweighted least squares on 2 048 radii in [0, 1] (normal equations, positive definite); of 64 iterations the one with the\n // smallest largest error on those radii is kept.\n const radii = Array.from({ length: 2048 }, (_, i) => { const r = i / 2047; return [r * r, target(r), 1]; });\n let best = [0, 0, 0, 0, 0], worst = Infinity;\n for (let iteration = 0; iteration < 64; iteration++) {\n const a = Array.from({ length: 5 }, () => [0, 0, 0, 0, 0, 0]), k = [0, 0, 0, 0, 0];\n for (const [t, G, w] of radii) {\n const row = [t!, t! ** 2, t! ** 3, t! ** 4, t! ** 5, G! - 1].map((v) => v / G!);\n for (let j = 0; j < 5; j++) for (let m = 0; m < 6; m++) a[j]![m]! += w! * row[j]! * row[m]!;\n }\n for (let j = 0; j < 5; j++) for (let i = j + 1; i < 5; i++) { const f = a[i]![j]! / a[j]![j]!; for (let m = j; m < 6; m++) a[i]![m]! -= f * a[j]![m]!; }\n for (let j = 4; j >= 0; j--) k[j] = (a[j]![5]! - a[j]!.slice(j + 1, 5).reduce((sum, v, m) => sum + v * k[j + 1 + m]!, 0)) / a[j]![j]!;\n const errors = radii.map(([t, G]) => Math.abs((1 + t! * (k[0]! + t! * (k[1]! + t! * (k[2]! + t! * (k[3]! + t! * k[4]!))))) / G! - 1)), max = Math.max(...errors);\n if (max < worst) { worst = max; best = k; }\n radii.forEach((p, i) => { p[2] = p[2]! * (errors[i]! / max + 1e-9); });\n }\n if (!(worst <= DNG_VIGNETTE_FIT_TOLERANCE)) throw new InvalidConfigurationError(\"output.dng.lensCorrectionOpcodes: FixVignetteRadial cannot hold \" + lens.name + \"'s vignetting gain within 0.1 %.\");\n opcodes.push({ opcode: \"FixVignetteRadial\", coefficients: best, maximumRelativeFitError: worst });\n params.push([...best, 0.5, 0.5]);\n }\n if (selection.distortion || selection.lateralColor) {\n const c = prepareDevelopedLensCorrection(lens, { ...selection, vignetting: false }, width, height, pitchMm, dispersion);\n const planes = (selection.lateralColor ? c.scales : [1]).map((s) => { const a = c.fill * s; return [a, c.k1 * a ** 3 * scale * scale, 0, 0, 0, 0]; });\n opcodes.push({ opcode: \"WarpRectilinear\", planes, magnification: 1 / c.fill });\n params.push([planes.length, ...planes.flat(), 0.5, 0.5]);\n }\n // Big-endian: the count, then per opcode its id, DNG version 1.3.0.0, flags 1 (optional), parameter bytes and parameters\n // (all DOUBLE but WarpRectilinear's leading LONG plane count).\n const size = (i: number): number => params[i]!.length * 8 - (opcodes[i]!.opcode === \"WarpRectilinear\" ? 4 : 0);\n const bytes = new Uint8Array(4 + params.reduce((sum, _, i) => sum + 16 + size(i), 0)), view = new DataView(bytes.buffer);\n view.setUint32(0, opcodes.length);\n let at = 4;\n params.forEach((values, i) => {\n const warp = opcodes[i]!.opcode === \"WarpRectilinear\";\n view.setUint32(at, warp ? 1 : 3); view.setUint32(at + 4, 0x01030000); view.setUint32(at + 8, 1); view.setUint32(at + 12, size(i)); at += 16;\n values.forEach((v, j) => { if (warp && j === 0) { view.setUint32(at, v); at += 4; } else { view.setFloat64(at, v); at += 8; } });\n });\n return { opcodeList3: bytes, opcodes };\n}\n"]}
|
|
@@ -14,7 +14,8 @@ import { InvalidConfigurationError } from "../core/configuration-error.js";
|
|
|
14
14
|
import { parseEvidenceList } from "../core/evidence-provenance.js";
|
|
15
15
|
import { InvalidScientificInputError } from "../core/validation.js";
|
|
16
16
|
import { parseFocusPlane } from "../optics/focus-state.js";
|
|
17
|
-
import { requireInputObject, requireInputKeys,
|
|
17
|
+
import { requireInputObject, requireInputKeys, requireConfigRecord as requireRecord, requireTrimmedConfigString as requireNonEmptyString, requireTrimmedConfigString as requireScientificNonEmptyString, requireInputNonNegativeFinite as requireScientificNonNegativeFinite, requireInputPositiveFinite as requireScientificPositiveFinite, parseConfigLimitations as parseLimitations } from "../core/record-validation.js";
|
|
18
|
+
import { deepFreeze, cloneJson } from "../core/shared-helpers.js";
|
|
18
19
|
export const FOCUS_CONTROL_PROFILE_SCHEMA_VERSION = "0.1.0";
|
|
19
20
|
export const FOCUS_CONTROL_STATE_VERSION = "0.1.0";
|
|
20
21
|
const FOCUS_MODES = new Set([
|
|
@@ -33,65 +34,6 @@ const TARGET_LOSS_REASONS = new Set([
|
|
|
33
34
|
"identity-lost",
|
|
34
35
|
"outside-focus-area"
|
|
35
36
|
]);
|
|
36
|
-
function requireRecord(value, path, allowedKeys) {
|
|
37
|
-
if (typeof value !== "object" ||
|
|
38
|
-
value === null ||
|
|
39
|
-
Array.isArray(value)) {
|
|
40
|
-
throw new InvalidConfigurationError(path + " must be an object.");
|
|
41
|
-
}
|
|
42
|
-
if (allowedKeys !== null)
|
|
43
|
-
rejectUnknownFields(value, allowedKeys, path);
|
|
44
|
-
return value;
|
|
45
|
-
}
|
|
46
|
-
function requireNonEmptyString(value, path) {
|
|
47
|
-
if (typeof value !== "string" ||
|
|
48
|
-
value.trim().length === 0) {
|
|
49
|
-
throw new InvalidConfigurationError(path +
|
|
50
|
-
" must be a non-empty string.");
|
|
51
|
-
}
|
|
52
|
-
return value.trim();
|
|
53
|
-
}
|
|
54
|
-
function requireScientificNonEmptyString(value, path) {
|
|
55
|
-
if (typeof value !== "string" ||
|
|
56
|
-
value.trim().length === 0) {
|
|
57
|
-
throw new InvalidConfigurationError(path +
|
|
58
|
-
" must be a non-empty string.");
|
|
59
|
-
}
|
|
60
|
-
return value.trim();
|
|
61
|
-
}
|
|
62
|
-
function requireScientificNonNegativeFinite(value, path) {
|
|
63
|
-
if (typeof value !== "number" ||
|
|
64
|
-
!Number.isFinite(value) ||
|
|
65
|
-
value < 0) {
|
|
66
|
-
throw new InvalidScientificInputError(path +
|
|
67
|
-
" must be finite and greater than or equal to zero.");
|
|
68
|
-
}
|
|
69
|
-
return value;
|
|
70
|
-
}
|
|
71
|
-
function requireScientificPositiveFinite(value, path) {
|
|
72
|
-
if (typeof value !== "number" ||
|
|
73
|
-
!Number.isFinite(value) ||
|
|
74
|
-
value <= 0) {
|
|
75
|
-
throw new InvalidScientificInputError(path +
|
|
76
|
-
" must be finite and greater than zero.");
|
|
77
|
-
}
|
|
78
|
-
return value;
|
|
79
|
-
}
|
|
80
|
-
function parseLimitations(value, path) {
|
|
81
|
-
if (!Array.isArray(value)) {
|
|
82
|
-
throw new InvalidConfigurationError(path + " must be an array.");
|
|
83
|
-
}
|
|
84
|
-
const parsed = value.map((entry, index) => requireNonEmptyString(entry, path +
|
|
85
|
-
"[" +
|
|
86
|
-
index +
|
|
87
|
-
"]"));
|
|
88
|
-
if (new Set(parsed).size !==
|
|
89
|
-
parsed.length) {
|
|
90
|
-
throw new InvalidConfigurationError(path +
|
|
91
|
-
" must not contain duplicates.");
|
|
92
|
-
}
|
|
93
|
-
return parsed;
|
|
94
|
-
}
|
|
95
37
|
function parseUniqueEnumList(value, path, allowed) {
|
|
96
38
|
if (!Array.isArray(value) ||
|
|
97
39
|
value.length === 0) {
|
|
@@ -167,21 +109,6 @@ export function parseFocusControlProfile(value) {
|
|
|
167
109
|
limitations: parseLimitations(record.limitations, "focusControlProfile.limitations")
|
|
168
110
|
};
|
|
169
111
|
}
|
|
170
|
-
function cloneJson(value) {
|
|
171
|
-
return JSON.parse(JSON.stringify(value));
|
|
172
|
-
}
|
|
173
|
-
function deepFreeze(value) {
|
|
174
|
-
if (typeof value !== "object" ||
|
|
175
|
-
value === null ||
|
|
176
|
-
Object.isFrozen(value)) {
|
|
177
|
-
return value;
|
|
178
|
-
}
|
|
179
|
-
Object.freeze(value);
|
|
180
|
-
for (const child of Object.values(value)) {
|
|
181
|
-
deepFreeze(child);
|
|
182
|
-
}
|
|
183
|
-
return value;
|
|
184
|
-
}
|
|
185
112
|
function immutableState(state) {
|
|
186
113
|
return deepFreeze(cloneJson(state));
|
|
187
114
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"focus-control.js","sourceRoot":"","sources":["../../src/capture/focus-control.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Focus control: manual focus (MF), single autofocus (AF-S) and continuous autofocus (AF-C), focus\n * lock, and the focus-priority or release-priority check before the shutter fires.\n *\n * Focus is always a distance along the optical axis (a focus plane) or infinity, never a distance\n * on screen. The focus \"actuator\" is ideal: it focuses on the target observations it is given. It\n * does not model a real AF sensor, a focus-ring scale or how long focusing takes. Losing a target,\n * reacquiring it, locking focus and the release-priority decision are separate state changes.\n * @see docs/SIMULATED_CAPTURE.md for equations, coordinate/unit conventions, blockers and support\n * limits.\n */\n\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport {\n parseEvidenceList,\n type EvidenceProvenance\n} from \"../core/evidence-provenance.js\";\nimport { InvalidScientificInputError } from \"../core/validation.js\";\nimport {\n parseFocusPlane,\n type FocusPlane\n} from \"../optics/focus-state.js\";\nimport { requireInputObject, requireInputKeys, rejectUnknownFields } from \"../core/record-validation.js\";\n\ntype UnknownRecord = Record<string, unknown>;\n\nexport const FOCUS_CONTROL_PROFILE_SCHEMA_VERSION =\n \"0.1.0\" as const;\nexport const FOCUS_CONTROL_STATE_VERSION =\n \"0.1.0\" as const;\n\nexport type FocusControlMode =\n | \"manual\"\n | \"single-af\"\n | \"continuous-af\";\n\nexport type FocusAcquisitionState =\n | \"idle\"\n | \"acquiring\"\n | \"acquired\"\n | \"target-lost\"\n | \"locked\";\n\nexport type FocusReleasePriority =\n | \"focus-priority\"\n | \"release-priority\"\n | \"balanced\";\n\nexport type FocusTargetLossReason =\n | \"occluded\"\n | \"out-of-frame\"\n | \"identity-lost\"\n | \"outside-focus-area\";\n\nexport interface FocusControlProfile {\n schemaVersion:\n typeof FOCUS_CONTROL_PROFILE_SCHEMA_VERSION;\n profileId: string;\n profileVersion: string;\n scientificStatus: \"approximation\";\n supportedModes:\n readonly FocusControlMode[];\n actuator: {\n kind: \"ideal-instantaneous\";\n evidence:\n readonly EvidenceProvenance[];\n };\n continuousTargetLossPolicy:\n \"hold-last-focus-require-explicit-reacquisition\";\n supportedReleasePriorities:\n readonly FocusReleasePriority[];\n evidence:\n readonly EvidenceProvenance[];\n limitations: readonly string[];\n}\n\ninterface FocusTargetObservationBase {\n targetId: string;\n focusAreaId?: string;\n observedAtSeconds: number;\n}\n\nexport type FocusTargetObservation =\n | (FocusTargetObservationBase & {\n kind: \"finite-surface\";\n /**\n * Distance along the camera's optical axis (the same convention as\n * FocusPlane), not the renderer's ray length to the point.\n */\n longitudinalDistanceM: number;\n })\n | (FocusTargetObservationBase & {\n kind:\n \"infinity-environment\";\n })\n | (FocusTargetObservationBase & {\n kind: \"unavailable\";\n reason:\n FocusTargetLossReason;\n });\n\n/**\n * Immutable focus-controller state for MF, AF-S or AF-C.\n *\n * The resolved focus is a finite distance along the optical axis in metres, or infinity.\n * Acquisition, loss, reacquisition and lock records explain why a target can be used. The\n * focus-release check is separate from shutter sequencing. The ideal actuator does not model\n * real AF accuracy or the physical time focusing takes.\n */\nexport interface FocusControlState {\n version:\n typeof FOCUS_CONTROL_STATE_VERSION;\n stateId: string;\n sourceProfile: {\n profileId: string;\n profileVersion: string;\n };\n profileLimitations:\n readonly string[];\n mode:\n FocusControlMode;\n acquisitionState:\n FocusAcquisitionState;\n focus:\n FocusPlane;\n activeTargetId?: string;\n activeFocusAreaId?: string;\n lastEventTimeSeconds: number;\n focusResolvedAtSeconds:\n number;\n locked: boolean;\n lock?: {\n lockedAtSeconds: number;\n resumeAcquisitionState:\n Exclude<\n FocusAcquisitionState,\n \"locked\"\n >;\n };\n actuatorModel:\n \"ideal-instantaneous\";\n continuousTargetLossPolicy:\n \"hold-last-focus-require-explicit-reacquisition\";\n exposureModified: false;\n meteringModified: false;\n whiteBalanceModified: false;\n subjectTrackingRecognitionModeled:\n false;\n rendererCoordinatesConsumed:\n false;\n limitations:\n readonly string[];\n}\n\nexport interface CreateFocusControlStateInput {\n stateId: string;\n profile:\n FocusControlProfile;\n mode:\n FocusControlMode;\n initialFocus:\n FocusPlane;\n initialTimeSeconds?: number;\n}\n\nexport interface SetManualFocusStateInput {\n state:\n FocusControlState;\n stateId: string;\n focus:\n FocusPlane;\n eventTimeSeconds: number;\n commandId?: string;\n}\n\nexport type FocusTargetControlEvent =\n | \"acquire\"\n | \"update\";\n\nexport interface ResolveFocusTargetObservationInput {\n state:\n FocusControlState;\n stateId: string;\n event:\n FocusTargetControlEvent;\n observation:\n FocusTargetObservation;\n}\n\nexport interface FocusTargetResolution {\n state:\n FocusControlState;\n targetObservationApplied:\n boolean;\n focusChanged: boolean;\n acquisitionEvent:\n FocusTargetControlEvent;\n actuatorModel:\n \"ideal-instantaneous\";\n silentRetargetingPerformed:\n false;\n}\n\nexport interface SetFocusLockInput {\n state:\n FocusControlState;\n stateId: string;\n locked: boolean;\n eventTimeSeconds: number;\n}\n\nexport interface AssessFocusReleaseGateInput {\n state:\n FocusControlState;\n profile:\n FocusControlProfile;\n priority:\n FocusReleasePriority;\n}\n\nexport interface FocusReleaseGateAssessment {\n priority:\n FocusReleasePriority;\n releaseAuthorized: boolean;\n reason:\n | \"manual-focus-state\"\n | \"focus-acquired\"\n | \"focus-locked\"\n | \"release-priority-bypasses-focus-gate\"\n | \"focus-not-acquired\"\n | \"balanced-policy-not-modeled\";\n requiresProfileSpecificBalancedPolicy:\n boolean;\n opticalFocusModified: false;\n exposureModified: false;\n}\n\nconst FOCUS_MODES =\n new Set<FocusControlMode>([\n \"manual\",\n \"single-af\",\n \"continuous-af\"\n ]);\n\nconst RELEASE_PRIORITIES =\n new Set<FocusReleasePriority>([\n \"focus-priority\",\n \"release-priority\",\n \"balanced\"\n ]);\n\nconst TARGET_LOSS_REASONS =\n new Set<FocusTargetLossReason>([\n \"occluded\",\n \"out-of-frame\",\n \"identity-lost\",\n \"outside-focus-area\"\n ]);\n\nfunction requireRecord(\n value: unknown,\n path: string,\n allowedKeys: readonly string[] | null\n): UnknownRecord {\n if (\n typeof value !== \"object\" ||\n value === null ||\n Array.isArray(value)\n ) {\n throw new InvalidConfigurationError(\n path + \" must be an object.\"\n );\n }\n if (allowedKeys !== null) rejectUnknownFields(value, allowedKeys, path);\n return value as UnknownRecord;\n}\n\nfunction requireNonEmptyString(\n value: unknown,\n path: string\n): string {\n if (\n typeof value !== \"string\" ||\n value.trim().length === 0\n ) {\n throw new InvalidConfigurationError(\n path +\n \" must be a non-empty string.\"\n );\n }\n return value.trim();\n}\n\nfunction requireScientificNonEmptyString(\n value: string,\n path: string\n): string {\n if (\n typeof value !== \"string\" ||\n value.trim().length === 0\n ) {\n throw new InvalidConfigurationError(\n path +\n \" must be a non-empty string.\"\n );\n }\n return value.trim();\n}\n\nfunction requireScientificNonNegativeFinite(\n value: number,\n path: string\n): number {\n if (\n typeof value !== \"number\" ||\n !Number.isFinite(value) ||\n value < 0\n ) {\n throw new InvalidScientificInputError(\n path +\n \" must be finite and greater than or equal to zero.\"\n );\n }\n return value;\n}\n\nfunction requireScientificPositiveFinite(\n value: number,\n path: string\n): number {\n if (\n typeof value !== \"number\" ||\n !Number.isFinite(value) ||\n value <= 0\n ) {\n throw new InvalidScientificInputError(\n path +\n \" must be finite and greater than zero.\"\n );\n }\n return value;\n}\n\nfunction parseLimitations(\n value: unknown,\n path: string\n): readonly string[] {\n if (!Array.isArray(value)) {\n throw new InvalidConfigurationError(\n path + \" must be an array.\"\n );\n }\n const parsed =\n value.map((entry, index) =>\n requireNonEmptyString(\n entry,\n path +\n \"[\" +\n index +\n \"]\"\n )\n );\n if (\n new Set(parsed).size !==\n parsed.length\n ) {\n throw new InvalidConfigurationError(\n path +\n \" must not contain duplicates.\"\n );\n }\n return parsed;\n}\n\nfunction parseUniqueEnumList<T extends string>(\n value: unknown,\n path: string,\n allowed: ReadonlySet<T>\n): readonly T[] {\n if (\n !Array.isArray(value) ||\n value.length === 0\n ) {\n throw new InvalidConfigurationError(\n path +\n \" must be a non-empty array.\"\n );\n }\n const parsed =\n value.map((entry, index) => {\n if (\n typeof entry !==\n \"string\" ||\n !allowed.has(entry as T)\n ) {\n throw new InvalidConfigurationError(\n path +\n \"[\" +\n index +\n \"] is invalid.\"\n );\n }\n return entry as T;\n });\n if (\n new Set(parsed).size !==\n parsed.length\n ) {\n throw new InvalidConfigurationError(\n path +\n \" must not contain duplicates.\"\n );\n }\n return parsed;\n}\n\n/**\n * Validates an untrusted focus-control profile and returns it normalized. Unknown enum values,\n * missing required fields and inconsistent scientific data are rejected.\n *\n * Focus is a distance along the optical axis or infinity, never a distance on screen. The ideal\n * actuator focuses on the target observations it is given. It does not model a real AF sensor, a\n * focus-ring scale or focusing time.\n * @param value - Untrusted data. TypeScript types alone are not validation.\n * @returns The validated profile. Success does not imply calibration.\n *\n * @see docs/API_REFERENCE.md for the package export and its full type definitions.\n */\nexport function parseFocusControlProfile(\n value: unknown\n): FocusControlProfile {\n const record =\n requireRecord(\n value,\n \"focusControlProfile\", [\"schemaVersion\", \"scientificStatus\", \"actuator\", \"continuousTargetLossPolicy\", \"profileId\", \"profileVersion\", \"supportedModes\", \"supportedReleasePriorities\", \"evidence\", \"limitations\"]\n );\n\n if (\n record.schemaVersion !==\n FOCUS_CONTROL_PROFILE_SCHEMA_VERSION\n ) {\n throw new InvalidConfigurationError(\n 'focusControlProfile.schemaVersion must be \"' +\n FOCUS_CONTROL_PROFILE_SCHEMA_VERSION +\n '\".'\n );\n }\n if (\n record.scientificStatus !==\n \"approximation\"\n ) {\n throw new InvalidConfigurationError(\n 'focusControlProfile.scientificStatus must be \"approximation\".'\n );\n }\n\n const actuator =\n requireRecord(\n record.actuator,\n \"focusControlProfile.actuator\", [\"kind\", \"evidence\"]\n );\n if (\n actuator.kind !==\n \"ideal-instantaneous\"\n ) {\n throw new InvalidConfigurationError(\n 'focusControlProfile.actuator.kind must be \"ideal-instantaneous\" in schema 0.1.0.'\n );\n }\n if (\n record\n .continuousTargetLossPolicy !==\n \"hold-last-focus-require-explicit-reacquisition\"\n ) {\n throw new InvalidConfigurationError(\n 'focusControlProfile.continuousTargetLossPolicy must be \"hold-last-focus-require-explicit-reacquisition\".'\n );\n }\n\n return {\n schemaVersion:\n FOCUS_CONTROL_PROFILE_SCHEMA_VERSION,\n profileId:\n requireNonEmptyString(\n record.profileId,\n \"focusControlProfile.profileId\"\n ),\n profileVersion:\n requireNonEmptyString(\n record.profileVersion,\n \"focusControlProfile.profileVersion\"\n ),\n scientificStatus:\n \"approximation\",\n supportedModes:\n parseUniqueEnumList(\n record.supportedModes,\n \"focusControlProfile.supportedModes\",\n FOCUS_MODES\n ),\n actuator: {\n kind:\n \"ideal-instantaneous\",\n evidence:\n parseEvidenceList(\n actuator.evidence,\n \"focusControlProfile.actuator.evidence\"\n )\n },\n continuousTargetLossPolicy:\n \"hold-last-focus-require-explicit-reacquisition\",\n supportedReleasePriorities:\n parseUniqueEnumList(\n record\n .supportedReleasePriorities,\n \"focusControlProfile.supportedReleasePriorities\",\n RELEASE_PRIORITIES\n ),\n evidence:\n parseEvidenceList(\n record.evidence,\n \"focusControlProfile.evidence\"\n ),\n limitations:\n parseLimitations(\n record.limitations,\n \"focusControlProfile.limitations\"\n )\n };\n}\n\nfunction cloneJson<T>(\n value: T\n): T {\n return JSON.parse(\n JSON.stringify(value)\n ) as T;\n}\n\nfunction deepFreeze<T>(\n value: T\n): T {\n if (\n typeof value !== \"object\" ||\n value === null ||\n Object.isFrozen(value)\n ) {\n return value;\n }\n\n Object.freeze(value);\n for (\n const child of\n Object.values(\n value as UnknownRecord\n )\n ) {\n deepFreeze(child);\n }\n return value;\n}\n\nfunction immutableState(\n state:\n FocusControlState\n): FocusControlState {\n return deepFreeze(\n cloneJson(state)\n );\n}\n\nfunction stateBase(\n stateId: string,\n profile:\n FocusControlProfile,\n mode:\n FocusControlMode,\n focus:\n FocusPlane,\n acquisitionState:\n FocusAcquisitionState,\n eventTimeSeconds: number,\n focusResolvedAtSeconds:\n number,\n activeTargetId?:\n string,\n activeFocusAreaId?:\n string,\n lock?:\n FocusControlState[\"lock\"]\n): FocusControlState {\n return immutableState({\n version:\n FOCUS_CONTROL_STATE_VERSION,\n stateId:\n requireScientificNonEmptyString(\n stateId,\n \"stateId\"\n ),\n sourceProfile: {\n profileId:\n profile.profileId,\n profileVersion:\n profile.profileVersion\n },\n profileLimitations: [\n ...profile.limitations\n ],\n mode,\n acquisitionState,\n focus:\n parseFocusPlane(focus),\n ...(activeTargetId ===\n undefined\n ? {}\n : {\n activeTargetId\n }),\n ...(activeFocusAreaId ===\n undefined\n ? {}\n : {\n activeFocusAreaId\n }),\n lastEventTimeSeconds:\n eventTimeSeconds,\n focusResolvedAtSeconds,\n locked:\n acquisitionState ===\n \"locked\",\n ...(lock === undefined\n ? {}\n : {\n lock\n }),\n actuatorModel:\n \"ideal-instantaneous\",\n continuousTargetLossPolicy:\n profile\n .continuousTargetLossPolicy,\n exposureModified: false,\n meteringModified: false,\n whiteBalanceModified:\n false,\n subjectTrackingRecognitionModeled:\n false,\n rendererCoordinatesConsumed:\n false,\n limitations: [\n ...profile.limitations,\n \"Focus target observations use longitudinal camera-space/conjugate distance, not renderer ray length.\",\n \"Ideal instantaneous focus actuation is an approximation and does not represent commercial AF speed, error, hunting, recognition, or low-light behavior.\",\n \"Focus control does not modify exposure, metering, white balance, or scene illumination.\"\n ]\n });\n}\n\nfunction requireSupportedMode(\n profile:\n FocusControlProfile,\n mode:\n FocusControlMode\n): void {\n if (\n !profile.supportedModes\n .includes(mode)\n ) {\n throw new InvalidScientificInputError(\n \"Selected focus-control mode is not supported by the profile.\"\n );\n }\n}\n\nfunction requireMonotonicEventTime(\n current:\n FocusControlState,\n eventTimeSeconds: number\n): number {\n const parsed =\n requireScientificNonNegativeFinite(\n eventTimeSeconds,\n \"eventTimeSeconds\"\n );\n if (\n parsed <\n current.lastEventTimeSeconds\n ) {\n throw new InvalidScientificInputError(\n \"Focus-control event time must not move backward.\"\n );\n }\n return parsed;\n}\n\nfunction verifyStateProfile(\n state:\n FocusControlState,\n profile:\n FocusControlProfile\n): void {\n if (\n state.sourceProfile\n .profileId !==\n profile.profileId ||\n state.sourceProfile\n .profileVersion !==\n profile.profileVersion\n ) {\n throw new InvalidScientificInputError(\n \"Focus-control state/profile identity does not match.\"\n );\n }\n}\n\n/**\n * Creates the initial ideal focus-controller state from a profile, a focus plane and a public\n * state ID.\n * @param input - New state ID, profile, focus mode, initial focus plane and optional start time.\n * @returns The initial state. Success does not imply calibration.\n *\n * @see docs/API_REFERENCE.md for the package export and its full type definitions.\n */\nexport function createFocusControlState(\n input:\n CreateFocusControlStateInput\n): FocusControlState {\n requireInputKeys(input, \"createFocusControlState\", [\"stateId\", \"profile\", \"mode\", \"initialFocus\", \"initialTimeSeconds\"]);\n const profile =\n parseFocusControlProfile(\n input.profile\n );\n requireSupportedMode(\n profile,\n input.mode\n );\n const time =\n input.initialTimeSeconds ===\n undefined\n ? 0\n : requireScientificNonNegativeFinite(\n input.initialTimeSeconds,\n \"initialTimeSeconds\"\n );\n\n return stateBase(\n input.stateId,\n profile,\n input.mode,\n input.initialFocus,\n \"idle\",\n time,\n time\n );\n}\n\nfunction stateProfileView(\n state:\n FocusControlState\n): FocusControlProfile {\n return {\n schemaVersion:\n FOCUS_CONTROL_PROFILE_SCHEMA_VERSION,\n profileId:\n state.sourceProfile\n .profileId,\n profileVersion:\n state.sourceProfile\n .profileVersion,\n scientificStatus:\n \"approximation\",\n supportedModes: [\n state.mode\n ],\n actuator: {\n kind:\n \"ideal-instantaneous\",\n evidence: []\n },\n continuousTargetLossPolicy:\n state\n .continuousTargetLossPolicy,\n supportedReleasePriorities: [\n \"focus-priority\",\n \"release-priority\",\n \"balanced\"\n ],\n evidence: [],\n limitations:\n state.profileLimitations\n };\n}\n\n/**\n * Returns the state after manually focusing on the given finite or infinity plane. No lens\n * actuator or focus-ring conversion is modelled.\n * @param input - Current state, new state ID, new focus plane and event time.\n * @returns The new state. Success does not imply calibration.\n *\n * @see docs/API_REFERENCE.md for the package export and its full type definitions.\n */\nexport function setManualFocusState(\n input:\n SetManualFocusStateInput\n): FocusControlState {\n requireInputKeys(input, \"setManualFocusState\", [\"state\", \"stateId\", \"focus\", \"eventTimeSeconds\", \"commandId\"]);\n requireInputObject(input.state, \"state\");\n if (\n input.state.mode !==\n \"manual\"\n ) {\n throw new InvalidScientificInputError(\n \"setManualFocusState requires manual focus mode.\"\n );\n }\n if (input.state.locked) {\n throw new InvalidScientificInputError(\n \"Manual focus cannot change while focus lock is active.\"\n );\n }\n if (\n input.commandId !==\n undefined\n ) {\n requireScientificNonEmptyString(\n input.commandId,\n \"commandId\"\n );\n }\n const time =\n requireMonotonicEventTime(\n input.state,\n input.eventTimeSeconds\n );\n\n return stateBase(\n input.stateId,\n stateProfileView(\n input.state\n ),\n \"manual\",\n input.focus,\n \"idle\",\n time,\n time\n );\n}\n\nfunction parseObservation(\n observation:\n FocusTargetObservation\n): FocusTargetObservation {\n const targetId =\n requireScientificNonEmptyString(\n observation.targetId,\n \"observation.targetId\"\n );\n const observedAtSeconds =\n requireScientificNonNegativeFinite(\n observation\n .observedAtSeconds,\n \"observation.observedAtSeconds\"\n );\n const focusAreaId =\n observation.focusAreaId ===\n undefined\n ? undefined\n : requireScientificNonEmptyString(\n observation.focusAreaId,\n \"observation.focusAreaId\"\n );\n\n if (\n observation.kind ===\n \"finite-surface\"\n ) {\n return {\n kind: \"finite-surface\",\n targetId,\n ...(focusAreaId ===\n undefined\n ? {}\n : {\n focusAreaId\n }),\n observedAtSeconds,\n longitudinalDistanceM:\n requireScientificPositiveFinite(\n observation\n .longitudinalDistanceM,\n \"observation.longitudinalDistanceM\"\n )\n };\n }\n\n if (\n observation.kind ===\n \"infinity-environment\"\n ) {\n return {\n kind:\n \"infinity-environment\",\n targetId,\n ...(focusAreaId ===\n undefined\n ? {}\n : {\n focusAreaId\n }),\n observedAtSeconds\n };\n }\n\n if (\n observation.kind ===\n \"unavailable\" &&\n TARGET_LOSS_REASONS.has(\n observation.reason\n )\n ) {\n return {\n kind: \"unavailable\",\n targetId,\n ...(focusAreaId ===\n undefined\n ? {}\n : {\n focusAreaId\n }),\n observedAtSeconds,\n reason:\n observation.reason\n };\n }\n\n throw new InvalidConfigurationError(\n \"observation.kind/reason is invalid.\"\n );\n}\n\nfunction focusFromObservation(\n observation:\n Exclude<\n FocusTargetObservation,\n {\n kind: \"unavailable\";\n }\n >\n): FocusPlane {\n if (\n observation.kind ===\n \"infinity-environment\"\n ) {\n return {\n kind: \"infinity\"\n };\n }\n return {\n kind: \"finite\",\n distanceM:\n observation\n .longitudinalDistanceM\n };\n}\n\nfunction focusEquals(\n a: FocusPlane,\n b: FocusPlane\n): boolean {\n if (\n a.kind !== b.kind\n ) {\n return false;\n }\n if (\n a.kind === \"infinity\" ||\n b.kind === \"infinity\"\n ) {\n return true;\n }\n return (\n a.distanceM ===\n b.distanceM\n );\n}\n\nfunction stateFromResolvedTarget(\n input:\n ResolveFocusTargetObservationInput,\n observation:\n Exclude<\n FocusTargetObservation,\n {\n kind: \"unavailable\";\n }\n >\n): FocusTargetResolution {\n const focus =\n focusFromObservation(\n observation\n );\n const state =\n stateBase(\n input.stateId,\n stateProfileView(\n input.state\n ),\n input.state.mode,\n focus,\n \"acquired\",\n observation\n .observedAtSeconds,\n observation\n .observedAtSeconds,\n observation.targetId,\n observation.focusAreaId\n );\n return {\n state,\n targetObservationApplied:\n true,\n focusChanged:\n !focusEquals(\n input.state.focus,\n focus\n ),\n acquisitionEvent:\n input.event,\n actuatorModel:\n \"ideal-instantaneous\",\n silentRetargetingPerformed:\n false\n };\n}\n\nfunction unchangedResolution(\n input:\n ResolveFocusTargetObservationInput\n): FocusTargetResolution {\n return {\n state: input.state,\n targetObservationApplied:\n false,\n focusChanged: false,\n acquisitionEvent:\n input.event,\n actuatorModel:\n \"ideal-instantaneous\",\n silentRetargetingPerformed:\n false\n };\n}\n\n/**\n * Applies one target observation (target available or lost) under the selected AF-S or AF-C\n * policy, and records whether the target was acquired or reacquired.\n *\n * The ideal actuator focuses on the observation as given. Target loss, reacquisition, focus\n * lock and release priority are separate state changes.\n * @param input - Current state, new state ID, control event and target observation.\n * @returns The resolution and new state. Success does not imply calibration.\n *\n * @see docs/API_REFERENCE.md for the package export and its full type definitions.\n */\nexport function resolveFocusTargetObservation(\n input:\n ResolveFocusTargetObservationInput\n): FocusTargetResolution {\n requireInputKeys(input, \"resolveFocusTargetObservation\", [\"state\", \"stateId\", \"event\", \"observation\"]);\n if (\n input.event !== \"acquire\" &&\n input.event !== \"update\"\n ) {\n throw new InvalidConfigurationError(\n 'Focus target event must be \"acquire\" or \"update\".'\n );\n }\n if (\n input.state.mode ===\n \"manual\"\n ) {\n throw new InvalidScientificInputError(\n \"Manual focus does not automatically consume autofocus target observations.\"\n );\n }\n\n const observation =\n parseObservation(\n input.observation\n );\n requireMonotonicEventTime(\n input.state,\n observation\n .observedAtSeconds\n );\n\n if (input.state.locked) {\n return unchangedResolution(\n input\n );\n }\n\n if (\n input.state.mode ===\n \"single-af\"\n ) {\n if (\n input.event ===\n \"update\" &&\n input.state\n .acquisitionState ===\n \"acquired\"\n ) {\n return unchangedResolution(\n input\n );\n }\n if (\n input.event !==\n \"acquire\"\n ) {\n throw new InvalidScientificInputError(\n \"Single AF requires an explicit acquire event before target updates.\"\n );\n }\n if (\n observation.kind ===\n \"unavailable\"\n ) {\n const state =\n stateBase(\n input.stateId,\n stateProfileView(\n input.state\n ),\n \"single-af\",\n input.state.focus,\n \"target-lost\",\n observation\n .observedAtSeconds,\n input.state\n .focusResolvedAtSeconds,\n observation.targetId,\n observation.focusAreaId\n );\n return {\n state,\n targetObservationApplied:\n true,\n focusChanged: false,\n acquisitionEvent:\n input.event,\n actuatorModel:\n \"ideal-instantaneous\",\n silentRetargetingPerformed:\n false\n };\n }\n return stateFromResolvedTarget(\n input,\n observation\n );\n }\n\n if (\n input.event ===\n \"update\"\n ) {\n if (\n input.state\n .activeTargetId ===\n undefined\n ) {\n throw new InvalidScientificInputError(\n \"Continuous AF requires an explicit acquire event before updates.\"\n );\n }\n if (\n observation.targetId !==\n input.state\n .activeTargetId\n ) {\n throw new InvalidScientificInputError(\n \"Continuous AF update targetId must match the active target; silent retargeting is not permitted.\"\n );\n }\n if (\n input.state\n .acquisitionState ===\n \"target-lost\"\n ) {\n throw new InvalidScientificInputError(\n \"Continuous AF target loss requires an explicit acquire event before reacquisition.\"\n );\n }\n }\n\n if (\n observation.kind ===\n \"unavailable\"\n ) {\n const state =\n stateBase(\n input.stateId,\n stateProfileView(\n input.state\n ),\n \"continuous-af\",\n input.state.focus,\n \"target-lost\",\n observation\n .observedAtSeconds,\n input.state\n .focusResolvedAtSeconds,\n observation.targetId,\n observation.focusAreaId\n );\n return {\n state,\n targetObservationApplied:\n true,\n focusChanged: false,\n acquisitionEvent:\n input.event,\n actuatorModel:\n \"ideal-instantaneous\",\n silentRetargetingPerformed:\n false\n };\n }\n\n return stateFromResolvedTarget(\n input,\n observation\n );\n}\n\n/**\n * Locks or unlocks focus. The physical focus plane does not change.\n * @param input - Current state, new state ID, lock setting and event time.\n * @returns The new state. Success does not imply calibration.\n *\n * @see docs/API_REFERENCE.md for the package export and its full type definitions.\n */\nexport function setFocusLock(\n input:\n SetFocusLockInput\n): FocusControlState {\n requireInputKeys(input, \"setFocusLock\", [\"state\", \"stateId\", \"locked\", \"eventTimeSeconds\"]);\n const time =\n requireMonotonicEventTime(\n input.state,\n input.eventTimeSeconds\n );\n\n if (input.locked) {\n if (input.state.locked) {\n return input.state;\n }\n return stateBase(\n input.stateId,\n stateProfileView(\n input.state\n ),\n input.state.mode,\n input.state.focus,\n \"locked\",\n time,\n input.state\n .focusResolvedAtSeconds,\n input.state\n .activeTargetId,\n input.state\n .activeFocusAreaId,\n {\n lockedAtSeconds:\n time,\n resumeAcquisitionState:\n input.state\n .acquisitionState as Exclude<\n FocusAcquisitionState,\n \"locked\"\n >\n }\n );\n }\n\n if (!input.state.locked) {\n return input.state;\n }\n const resume =\n input.state.lock\n ?.resumeAcquisitionState;\n if (resume === undefined) {\n throw new InvalidScientificInputError(\n \"Locked focus state is missing its resume acquisition state.\"\n );\n }\n\n return stateBase(\n input.stateId,\n stateProfileView(\n input.state\n ),\n input.state.mode,\n input.state.focus,\n resume,\n time,\n input.state\n .focusResolvedAtSeconds,\n input.state\n .activeTargetId,\n input.state\n .activeFocusAreaId\n );\n}\n\n/**\n * Reports whether the shutter may be released under the focus-priority or release-priority\n * policy. It does not operate the shutter.\n * @param input - Current state, profile and release priority.\n * @returns The assessment. Read its structured blockers before acting on an authorization.\n *\n * @see docs/API_REFERENCE.md for the package export and its full type definitions.\n */\nexport function assessFocusReleaseGate(\n input:\n AssessFocusReleaseGateInput\n): FocusReleaseGateAssessment {\n requireInputKeys(input, \"assessFocusReleaseGate\", [\"state\", \"profile\", \"priority\"]);\n const profile =\n parseFocusControlProfile(\n input.profile\n );\n verifyStateProfile(\n input.state,\n profile\n );\n\n if (\n !profile\n .supportedReleasePriorities\n .includes(\n input.priority\n )\n ) {\n throw new InvalidScientificInputError(\n \"Selected focus/release priority is not supported by the profile.\"\n );\n }\n\n if (\n input.priority ===\n \"release-priority\"\n ) {\n return {\n priority:\n input.priority,\n releaseAuthorized: true,\n reason:\n \"release-priority-bypasses-focus-gate\",\n requiresProfileSpecificBalancedPolicy:\n false,\n opticalFocusModified:\n false,\n exposureModified:\n false\n };\n }\n\n if (\n input.priority ===\n \"balanced\"\n ) {\n return {\n priority:\n input.priority,\n releaseAuthorized:\n false,\n reason:\n \"balanced-policy-not-modeled\",\n requiresProfileSpecificBalancedPolicy:\n true,\n opticalFocusModified:\n false,\n exposureModified:\n false\n };\n }\n\n if (\n input.state.mode ===\n \"manual\"\n ) {\n return {\n priority:\n input.priority,\n releaseAuthorized: true,\n reason:\n \"manual-focus-state\",\n requiresProfileSpecificBalancedPolicy:\n false,\n opticalFocusModified:\n false,\n exposureModified:\n false\n };\n }\n\n if (\n input.state\n .acquisitionState ===\n \"locked\"\n ) {\n return {\n priority:\n input.priority,\n releaseAuthorized: true,\n reason:\n \"focus-locked\",\n requiresProfileSpecificBalancedPolicy:\n false,\n opticalFocusModified:\n false,\n exposureModified:\n false\n };\n }\n\n if (\n input.state\n .acquisitionState ===\n \"acquired\"\n ) {\n return {\n priority:\n input.priority,\n releaseAuthorized: true,\n reason:\n \"focus-acquired\",\n requiresProfileSpecificBalancedPolicy:\n false,\n opticalFocusModified:\n false,\n exposureModified:\n false\n };\n }\n\n return {\n priority:\n input.priority,\n releaseAuthorized: false,\n reason:\n \"focus-not-acquired\",\n requiresProfileSpecificBalancedPolicy:\n false,\n opticalFocusModified:\n false,\n exposureModified:\n false\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"focus-control.js","sourceRoot":"","sources":["../../src/capture/focus-control.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Focus control: manual focus (MF), single autofocus (AF-S) and continuous autofocus (AF-C), focus\n * lock, and the focus-priority or release-priority check before the shutter fires.\n *\n * Focus is always a distance along the optical axis (a focus plane) or infinity, never a distance\n * on screen. The focus \"actuator\" is ideal: it focuses on the target observations it is given. It\n * does not model a real AF sensor, a focus-ring scale or how long focusing takes. Losing a target,\n * reacquiring it, locking focus and the release-priority decision are separate state changes.\n * @see docs/SIMULATED_CAPTURE.md for equations, coordinate/unit conventions, blockers and support\n * limits.\n */\n\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport {\n parseEvidenceList,\n type EvidenceProvenance\n} from \"../core/evidence-provenance.js\";\nimport { InvalidScientificInputError } from \"../core/validation.js\";\nimport {\n parseFocusPlane,\n type FocusPlane\n} from \"../optics/focus-state.js\";\nimport { requireInputObject, requireInputKeys, requireConfigRecord as requireRecord, requireTrimmedConfigString as requireNonEmptyString, requireTrimmedConfigString as requireScientificNonEmptyString, requireInputNonNegativeFinite as requireScientificNonNegativeFinite, requireInputPositiveFinite as requireScientificPositiveFinite, parseConfigLimitations as parseLimitations } from \"../core/record-validation.js\";\nimport { deepFreeze, cloneJson } from \"../core/shared-helpers.js\";\n\nexport const FOCUS_CONTROL_PROFILE_SCHEMA_VERSION =\n \"0.1.0\" as const;\nexport const FOCUS_CONTROL_STATE_VERSION =\n \"0.1.0\" as const;\n\nexport type FocusControlMode =\n | \"manual\"\n | \"single-af\"\n | \"continuous-af\";\n\nexport type FocusAcquisitionState =\n | \"idle\"\n | \"acquiring\"\n | \"acquired\"\n | \"target-lost\"\n | \"locked\";\n\nexport type FocusReleasePriority =\n | \"focus-priority\"\n | \"release-priority\"\n | \"balanced\";\n\nexport type FocusTargetLossReason =\n | \"occluded\"\n | \"out-of-frame\"\n | \"identity-lost\"\n | \"outside-focus-area\";\n\nexport interface FocusControlProfile {\n schemaVersion:\n typeof FOCUS_CONTROL_PROFILE_SCHEMA_VERSION;\n profileId: string;\n profileVersion: string;\n scientificStatus: \"approximation\";\n supportedModes:\n readonly FocusControlMode[];\n actuator: {\n kind: \"ideal-instantaneous\";\n evidence:\n readonly EvidenceProvenance[];\n };\n continuousTargetLossPolicy:\n \"hold-last-focus-require-explicit-reacquisition\";\n supportedReleasePriorities:\n readonly FocusReleasePriority[];\n evidence:\n readonly EvidenceProvenance[];\n limitations: readonly string[];\n}\n\ninterface FocusTargetObservationBase {\n targetId: string;\n focusAreaId?: string;\n observedAtSeconds: number;\n}\n\nexport type FocusTargetObservation =\n | (FocusTargetObservationBase & {\n kind: \"finite-surface\";\n /**\n * Distance along the camera's optical axis (the same convention as\n * FocusPlane), not the renderer's ray length to the point.\n */\n longitudinalDistanceM: number;\n })\n | (FocusTargetObservationBase & {\n kind:\n \"infinity-environment\";\n })\n | (FocusTargetObservationBase & {\n kind: \"unavailable\";\n reason:\n FocusTargetLossReason;\n });\n\n/**\n * Immutable focus-controller state for MF, AF-S or AF-C.\n *\n * The resolved focus is a finite distance along the optical axis in metres, or infinity.\n * Acquisition, loss, reacquisition and lock records explain why a target can be used. The\n * focus-release check is separate from shutter sequencing. The ideal actuator does not model\n * real AF accuracy or the physical time focusing takes.\n */\nexport interface FocusControlState {\n version:\n typeof FOCUS_CONTROL_STATE_VERSION;\n stateId: string;\n sourceProfile: {\n profileId: string;\n profileVersion: string;\n };\n profileLimitations:\n readonly string[];\n mode:\n FocusControlMode;\n acquisitionState:\n FocusAcquisitionState;\n focus:\n FocusPlane;\n activeTargetId?: string;\n activeFocusAreaId?: string;\n lastEventTimeSeconds: number;\n focusResolvedAtSeconds:\n number;\n locked: boolean;\n lock?: {\n lockedAtSeconds: number;\n resumeAcquisitionState:\n Exclude<\n FocusAcquisitionState,\n \"locked\"\n >;\n };\n actuatorModel:\n \"ideal-instantaneous\";\n continuousTargetLossPolicy:\n \"hold-last-focus-require-explicit-reacquisition\";\n exposureModified: false;\n meteringModified: false;\n whiteBalanceModified: false;\n subjectTrackingRecognitionModeled:\n false;\n rendererCoordinatesConsumed:\n false;\n limitations:\n readonly string[];\n}\n\nexport interface CreateFocusControlStateInput {\n stateId: string;\n profile:\n FocusControlProfile;\n mode:\n FocusControlMode;\n initialFocus:\n FocusPlane;\n initialTimeSeconds?: number;\n}\n\nexport interface SetManualFocusStateInput {\n state:\n FocusControlState;\n stateId: string;\n focus:\n FocusPlane;\n eventTimeSeconds: number;\n commandId?: string;\n}\n\nexport type FocusTargetControlEvent =\n | \"acquire\"\n | \"update\";\n\nexport interface ResolveFocusTargetObservationInput {\n state:\n FocusControlState;\n stateId: string;\n event:\n FocusTargetControlEvent;\n observation:\n FocusTargetObservation;\n}\n\nexport interface FocusTargetResolution {\n state:\n FocusControlState;\n targetObservationApplied:\n boolean;\n focusChanged: boolean;\n acquisitionEvent:\n FocusTargetControlEvent;\n actuatorModel:\n \"ideal-instantaneous\";\n silentRetargetingPerformed:\n false;\n}\n\nexport interface SetFocusLockInput {\n state:\n FocusControlState;\n stateId: string;\n locked: boolean;\n eventTimeSeconds: number;\n}\n\nexport interface AssessFocusReleaseGateInput {\n state:\n FocusControlState;\n profile:\n FocusControlProfile;\n priority:\n FocusReleasePriority;\n}\n\nexport interface FocusReleaseGateAssessment {\n priority:\n FocusReleasePriority;\n releaseAuthorized: boolean;\n reason:\n | \"manual-focus-state\"\n | \"focus-acquired\"\n | \"focus-locked\"\n | \"release-priority-bypasses-focus-gate\"\n | \"focus-not-acquired\"\n | \"balanced-policy-not-modeled\";\n requiresProfileSpecificBalancedPolicy:\n boolean;\n opticalFocusModified: false;\n exposureModified: false;\n}\n\nconst FOCUS_MODES =\n new Set<FocusControlMode>([\n \"manual\",\n \"single-af\",\n \"continuous-af\"\n ]);\n\nconst RELEASE_PRIORITIES =\n new Set<FocusReleasePriority>([\n \"focus-priority\",\n \"release-priority\",\n \"balanced\"\n ]);\n\nconst TARGET_LOSS_REASONS =\n new Set<FocusTargetLossReason>([\n \"occluded\",\n \"out-of-frame\",\n \"identity-lost\",\n \"outside-focus-area\"\n ]);\n\nfunction parseUniqueEnumList<T extends string>(\n value: unknown,\n path: string,\n allowed: ReadonlySet<T>\n): readonly T[] {\n if (\n !Array.isArray(value) ||\n value.length === 0\n ) {\n throw new InvalidConfigurationError(\n path +\n \" must be a non-empty array.\"\n );\n }\n const parsed =\n value.map((entry, index) => {\n if (\n typeof entry !==\n \"string\" ||\n !allowed.has(entry as T)\n ) {\n throw new InvalidConfigurationError(\n path +\n \"[\" +\n index +\n \"] is invalid.\"\n );\n }\n return entry as T;\n });\n if (\n new Set(parsed).size !==\n parsed.length\n ) {\n throw new InvalidConfigurationError(\n path +\n \" must not contain duplicates.\"\n );\n }\n return parsed;\n}\n\n/**\n * Validates an untrusted focus-control profile and returns it normalized. Unknown enum values,\n * missing required fields and inconsistent scientific data are rejected.\n *\n * Focus is a distance along the optical axis or infinity, never a distance on screen. The ideal\n * actuator focuses on the target observations it is given. It does not model a real AF sensor, a\n * focus-ring scale or focusing time.\n * @param value - Untrusted data. TypeScript types alone are not validation.\n * @returns The validated profile. Success does not imply calibration.\n *\n * @see docs/API_REFERENCE.md for the package export and its full type definitions.\n */\nexport function parseFocusControlProfile(\n value: unknown\n): FocusControlProfile {\n const record =\n requireRecord(\n value,\n \"focusControlProfile\", [\"schemaVersion\", \"scientificStatus\", \"actuator\", \"continuousTargetLossPolicy\", \"profileId\", \"profileVersion\", \"supportedModes\", \"supportedReleasePriorities\", \"evidence\", \"limitations\"]\n );\n\n if (\n record.schemaVersion !==\n FOCUS_CONTROL_PROFILE_SCHEMA_VERSION\n ) {\n throw new InvalidConfigurationError(\n 'focusControlProfile.schemaVersion must be \"' +\n FOCUS_CONTROL_PROFILE_SCHEMA_VERSION +\n '\".'\n );\n }\n if (\n record.scientificStatus !==\n \"approximation\"\n ) {\n throw new InvalidConfigurationError(\n 'focusControlProfile.scientificStatus must be \"approximation\".'\n );\n }\n\n const actuator =\n requireRecord(\n record.actuator,\n \"focusControlProfile.actuator\", [\"kind\", \"evidence\"]\n );\n if (\n actuator.kind !==\n \"ideal-instantaneous\"\n ) {\n throw new InvalidConfigurationError(\n 'focusControlProfile.actuator.kind must be \"ideal-instantaneous\" in schema 0.1.0.'\n );\n }\n if (\n record\n .continuousTargetLossPolicy !==\n \"hold-last-focus-require-explicit-reacquisition\"\n ) {\n throw new InvalidConfigurationError(\n 'focusControlProfile.continuousTargetLossPolicy must be \"hold-last-focus-require-explicit-reacquisition\".'\n );\n }\n\n return {\n schemaVersion:\n FOCUS_CONTROL_PROFILE_SCHEMA_VERSION,\n profileId:\n requireNonEmptyString(\n record.profileId,\n \"focusControlProfile.profileId\"\n ),\n profileVersion:\n requireNonEmptyString(\n record.profileVersion,\n \"focusControlProfile.profileVersion\"\n ),\n scientificStatus:\n \"approximation\",\n supportedModes:\n parseUniqueEnumList(\n record.supportedModes,\n \"focusControlProfile.supportedModes\",\n FOCUS_MODES\n ),\n actuator: {\n kind:\n \"ideal-instantaneous\",\n evidence:\n parseEvidenceList(\n actuator.evidence,\n \"focusControlProfile.actuator.evidence\"\n )\n },\n continuousTargetLossPolicy:\n \"hold-last-focus-require-explicit-reacquisition\",\n supportedReleasePriorities:\n parseUniqueEnumList(\n record\n .supportedReleasePriorities,\n \"focusControlProfile.supportedReleasePriorities\",\n RELEASE_PRIORITIES\n ),\n evidence:\n parseEvidenceList(\n record.evidence,\n \"focusControlProfile.evidence\"\n ),\n limitations:\n parseLimitations(\n record.limitations,\n \"focusControlProfile.limitations\"\n )\n };\n}\n\nfunction immutableState(\n state:\n FocusControlState\n): FocusControlState {\n return deepFreeze(\n cloneJson(state)\n );\n}\n\nfunction stateBase(\n stateId: string,\n profile:\n FocusControlProfile,\n mode:\n FocusControlMode,\n focus:\n FocusPlane,\n acquisitionState:\n FocusAcquisitionState,\n eventTimeSeconds: number,\n focusResolvedAtSeconds:\n number,\n activeTargetId?:\n string,\n activeFocusAreaId?:\n string,\n lock?:\n FocusControlState[\"lock\"]\n): FocusControlState {\n return immutableState({\n version:\n FOCUS_CONTROL_STATE_VERSION,\n stateId:\n requireScientificNonEmptyString(\n stateId,\n \"stateId\"\n ),\n sourceProfile: {\n profileId:\n profile.profileId,\n profileVersion:\n profile.profileVersion\n },\n profileLimitations: [\n ...profile.limitations\n ],\n mode,\n acquisitionState,\n focus:\n parseFocusPlane(focus),\n ...(activeTargetId ===\n undefined\n ? {}\n : {\n activeTargetId\n }),\n ...(activeFocusAreaId ===\n undefined\n ? {}\n : {\n activeFocusAreaId\n }),\n lastEventTimeSeconds:\n eventTimeSeconds,\n focusResolvedAtSeconds,\n locked:\n acquisitionState ===\n \"locked\",\n ...(lock === undefined\n ? {}\n : {\n lock\n }),\n actuatorModel:\n \"ideal-instantaneous\",\n continuousTargetLossPolicy:\n profile\n .continuousTargetLossPolicy,\n exposureModified: false,\n meteringModified: false,\n whiteBalanceModified:\n false,\n subjectTrackingRecognitionModeled:\n false,\n rendererCoordinatesConsumed:\n false,\n limitations: [\n ...profile.limitations,\n \"Focus target observations use longitudinal camera-space/conjugate distance, not renderer ray length.\",\n \"Ideal instantaneous focus actuation is an approximation and does not represent commercial AF speed, error, hunting, recognition, or low-light behavior.\",\n \"Focus control does not modify exposure, metering, white balance, or scene illumination.\"\n ]\n });\n}\n\nfunction requireSupportedMode(\n profile:\n FocusControlProfile,\n mode:\n FocusControlMode\n): void {\n if (\n !profile.supportedModes\n .includes(mode)\n ) {\n throw new InvalidScientificInputError(\n \"Selected focus-control mode is not supported by the profile.\"\n );\n }\n}\n\nfunction requireMonotonicEventTime(\n current:\n FocusControlState,\n eventTimeSeconds: number\n): number {\n const parsed =\n requireScientificNonNegativeFinite(\n eventTimeSeconds,\n \"eventTimeSeconds\"\n );\n if (\n parsed <\n current.lastEventTimeSeconds\n ) {\n throw new InvalidScientificInputError(\n \"Focus-control event time must not move backward.\"\n );\n }\n return parsed;\n}\n\nfunction verifyStateProfile(\n state:\n FocusControlState,\n profile:\n FocusControlProfile\n): void {\n if (\n state.sourceProfile\n .profileId !==\n profile.profileId ||\n state.sourceProfile\n .profileVersion !==\n profile.profileVersion\n ) {\n throw new InvalidScientificInputError(\n \"Focus-control state/profile identity does not match.\"\n );\n }\n}\n\n/**\n * Creates the initial ideal focus-controller state from a profile, a focus plane and a public\n * state ID.\n * @param input - New state ID, profile, focus mode, initial focus plane and optional start time.\n * @returns The initial state. Success does not imply calibration.\n *\n * @see docs/API_REFERENCE.md for the package export and its full type definitions.\n */\nexport function createFocusControlState(\n input:\n CreateFocusControlStateInput\n): FocusControlState {\n requireInputKeys(input, \"createFocusControlState\", [\"stateId\", \"profile\", \"mode\", \"initialFocus\", \"initialTimeSeconds\"]);\n const profile =\n parseFocusControlProfile(\n input.profile\n );\n requireSupportedMode(\n profile,\n input.mode\n );\n const time =\n input.initialTimeSeconds ===\n undefined\n ? 0\n : requireScientificNonNegativeFinite(\n input.initialTimeSeconds,\n \"initialTimeSeconds\"\n );\n\n return stateBase(\n input.stateId,\n profile,\n input.mode,\n input.initialFocus,\n \"idle\",\n time,\n time\n );\n}\n\nfunction stateProfileView(\n state:\n FocusControlState\n): FocusControlProfile {\n return {\n schemaVersion:\n FOCUS_CONTROL_PROFILE_SCHEMA_VERSION,\n profileId:\n state.sourceProfile\n .profileId,\n profileVersion:\n state.sourceProfile\n .profileVersion,\n scientificStatus:\n \"approximation\",\n supportedModes: [\n state.mode\n ],\n actuator: {\n kind:\n \"ideal-instantaneous\",\n evidence: []\n },\n continuousTargetLossPolicy:\n state\n .continuousTargetLossPolicy,\n supportedReleasePriorities: [\n \"focus-priority\",\n \"release-priority\",\n \"balanced\"\n ],\n evidence: [],\n limitations:\n state.profileLimitations\n };\n}\n\n/**\n * Returns the state after manually focusing on the given finite or infinity plane. No lens\n * actuator or focus-ring conversion is modelled.\n * @param input - Current state, new state ID, new focus plane and event time.\n * @returns The new state. Success does not imply calibration.\n *\n * @see docs/API_REFERENCE.md for the package export and its full type definitions.\n */\nexport function setManualFocusState(\n input:\n SetManualFocusStateInput\n): FocusControlState {\n requireInputKeys(input, \"setManualFocusState\", [\"state\", \"stateId\", \"focus\", \"eventTimeSeconds\", \"commandId\"]);\n requireInputObject(input.state, \"state\");\n if (\n input.state.mode !==\n \"manual\"\n ) {\n throw new InvalidScientificInputError(\n \"setManualFocusState requires manual focus mode.\"\n );\n }\n if (input.state.locked) {\n throw new InvalidScientificInputError(\n \"Manual focus cannot change while focus lock is active.\"\n );\n }\n if (\n input.commandId !==\n undefined\n ) {\n requireScientificNonEmptyString(\n input.commandId,\n \"commandId\"\n );\n }\n const time =\n requireMonotonicEventTime(\n input.state,\n input.eventTimeSeconds\n );\n\n return stateBase(\n input.stateId,\n stateProfileView(\n input.state\n ),\n \"manual\",\n input.focus,\n \"idle\",\n time,\n time\n );\n}\n\nfunction parseObservation(\n observation:\n FocusTargetObservation\n): FocusTargetObservation {\n const targetId =\n requireScientificNonEmptyString(\n observation.targetId,\n \"observation.targetId\"\n );\n const observedAtSeconds =\n requireScientificNonNegativeFinite(\n observation\n .observedAtSeconds,\n \"observation.observedAtSeconds\"\n );\n const focusAreaId =\n observation.focusAreaId ===\n undefined\n ? undefined\n : requireScientificNonEmptyString(\n observation.focusAreaId,\n \"observation.focusAreaId\"\n );\n\n if (\n observation.kind ===\n \"finite-surface\"\n ) {\n return {\n kind: \"finite-surface\",\n targetId,\n ...(focusAreaId ===\n undefined\n ? {}\n : {\n focusAreaId\n }),\n observedAtSeconds,\n longitudinalDistanceM:\n requireScientificPositiveFinite(\n observation\n .longitudinalDistanceM,\n \"observation.longitudinalDistanceM\"\n )\n };\n }\n\n if (\n observation.kind ===\n \"infinity-environment\"\n ) {\n return {\n kind:\n \"infinity-environment\",\n targetId,\n ...(focusAreaId ===\n undefined\n ? {}\n : {\n focusAreaId\n }),\n observedAtSeconds\n };\n }\n\n if (\n observation.kind ===\n \"unavailable\" &&\n TARGET_LOSS_REASONS.has(\n observation.reason\n )\n ) {\n return {\n kind: \"unavailable\",\n targetId,\n ...(focusAreaId ===\n undefined\n ? {}\n : {\n focusAreaId\n }),\n observedAtSeconds,\n reason:\n observation.reason\n };\n }\n\n throw new InvalidConfigurationError(\n \"observation.kind/reason is invalid.\"\n );\n}\n\nfunction focusFromObservation(\n observation:\n Exclude<\n FocusTargetObservation,\n {\n kind: \"unavailable\";\n }\n >\n): FocusPlane {\n if (\n observation.kind ===\n \"infinity-environment\"\n ) {\n return {\n kind: \"infinity\"\n };\n }\n return {\n kind: \"finite\",\n distanceM:\n observation\n .longitudinalDistanceM\n };\n}\n\nfunction focusEquals(\n a: FocusPlane,\n b: FocusPlane\n): boolean {\n if (\n a.kind !== b.kind\n ) {\n return false;\n }\n if (\n a.kind === \"infinity\" ||\n b.kind === \"infinity\"\n ) {\n return true;\n }\n return (\n a.distanceM ===\n b.distanceM\n );\n}\n\nfunction stateFromResolvedTarget(\n input:\n ResolveFocusTargetObservationInput,\n observation:\n Exclude<\n FocusTargetObservation,\n {\n kind: \"unavailable\";\n }\n >\n): FocusTargetResolution {\n const focus =\n focusFromObservation(\n observation\n );\n const state =\n stateBase(\n input.stateId,\n stateProfileView(\n input.state\n ),\n input.state.mode,\n focus,\n \"acquired\",\n observation\n .observedAtSeconds,\n observation\n .observedAtSeconds,\n observation.targetId,\n observation.focusAreaId\n );\n return {\n state,\n targetObservationApplied:\n true,\n focusChanged:\n !focusEquals(\n input.state.focus,\n focus\n ),\n acquisitionEvent:\n input.event,\n actuatorModel:\n \"ideal-instantaneous\",\n silentRetargetingPerformed:\n false\n };\n}\n\nfunction unchangedResolution(\n input:\n ResolveFocusTargetObservationInput\n): FocusTargetResolution {\n return {\n state: input.state,\n targetObservationApplied:\n false,\n focusChanged: false,\n acquisitionEvent:\n input.event,\n actuatorModel:\n \"ideal-instantaneous\",\n silentRetargetingPerformed:\n false\n };\n}\n\n/**\n * Applies one target observation (target available or lost) under the selected AF-S or AF-C\n * policy, and records whether the target was acquired or reacquired.\n *\n * The ideal actuator focuses on the observation as given. Target loss, reacquisition, focus\n * lock and release priority are separate state changes.\n * @param input - Current state, new state ID, control event and target observation.\n * @returns The resolution and new state. Success does not imply calibration.\n *\n * @see docs/API_REFERENCE.md for the package export and its full type definitions.\n */\nexport function resolveFocusTargetObservation(\n input:\n ResolveFocusTargetObservationInput\n): FocusTargetResolution {\n requireInputKeys(input, \"resolveFocusTargetObservation\", [\"state\", \"stateId\", \"event\", \"observation\"]);\n if (\n input.event !== \"acquire\" &&\n input.event !== \"update\"\n ) {\n throw new InvalidConfigurationError(\n 'Focus target event must be \"acquire\" or \"update\".'\n );\n }\n if (\n input.state.mode ===\n \"manual\"\n ) {\n throw new InvalidScientificInputError(\n \"Manual focus does not automatically consume autofocus target observations.\"\n );\n }\n\n const observation =\n parseObservation(\n input.observation\n );\n requireMonotonicEventTime(\n input.state,\n observation\n .observedAtSeconds\n );\n\n if (input.state.locked) {\n return unchangedResolution(\n input\n );\n }\n\n if (\n input.state.mode ===\n \"single-af\"\n ) {\n if (\n input.event ===\n \"update\" &&\n input.state\n .acquisitionState ===\n \"acquired\"\n ) {\n return unchangedResolution(\n input\n );\n }\n if (\n input.event !==\n \"acquire\"\n ) {\n throw new InvalidScientificInputError(\n \"Single AF requires an explicit acquire event before target updates.\"\n );\n }\n if (\n observation.kind ===\n \"unavailable\"\n ) {\n const state =\n stateBase(\n input.stateId,\n stateProfileView(\n input.state\n ),\n \"single-af\",\n input.state.focus,\n \"target-lost\",\n observation\n .observedAtSeconds,\n input.state\n .focusResolvedAtSeconds,\n observation.targetId,\n observation.focusAreaId\n );\n return {\n state,\n targetObservationApplied:\n true,\n focusChanged: false,\n acquisitionEvent:\n input.event,\n actuatorModel:\n \"ideal-instantaneous\",\n silentRetargetingPerformed:\n false\n };\n }\n return stateFromResolvedTarget(\n input,\n observation\n );\n }\n\n if (\n input.event ===\n \"update\"\n ) {\n if (\n input.state\n .activeTargetId ===\n undefined\n ) {\n throw new InvalidScientificInputError(\n \"Continuous AF requires an explicit acquire event before updates.\"\n );\n }\n if (\n observation.targetId !==\n input.state\n .activeTargetId\n ) {\n throw new InvalidScientificInputError(\n \"Continuous AF update targetId must match the active target; silent retargeting is not permitted.\"\n );\n }\n if (\n input.state\n .acquisitionState ===\n \"target-lost\"\n ) {\n throw new InvalidScientificInputError(\n \"Continuous AF target loss requires an explicit acquire event before reacquisition.\"\n );\n }\n }\n\n if (\n observation.kind ===\n \"unavailable\"\n ) {\n const state =\n stateBase(\n input.stateId,\n stateProfileView(\n input.state\n ),\n \"continuous-af\",\n input.state.focus,\n \"target-lost\",\n observation\n .observedAtSeconds,\n input.state\n .focusResolvedAtSeconds,\n observation.targetId,\n observation.focusAreaId\n );\n return {\n state,\n targetObservationApplied:\n true,\n focusChanged: false,\n acquisitionEvent:\n input.event,\n actuatorModel:\n \"ideal-instantaneous\",\n silentRetargetingPerformed:\n false\n };\n }\n\n return stateFromResolvedTarget(\n input,\n observation\n );\n}\n\n/**\n * Locks or unlocks focus. The physical focus plane does not change.\n * @param input - Current state, new state ID, lock setting and event time.\n * @returns The new state. Success does not imply calibration.\n *\n * @see docs/API_REFERENCE.md for the package export and its full type definitions.\n */\nexport function setFocusLock(\n input:\n SetFocusLockInput\n): FocusControlState {\n requireInputKeys(input, \"setFocusLock\", [\"state\", \"stateId\", \"locked\", \"eventTimeSeconds\"]);\n const time =\n requireMonotonicEventTime(\n input.state,\n input.eventTimeSeconds\n );\n\n if (input.locked) {\n if (input.state.locked) {\n return input.state;\n }\n return stateBase(\n input.stateId,\n stateProfileView(\n input.state\n ),\n input.state.mode,\n input.state.focus,\n \"locked\",\n time,\n input.state\n .focusResolvedAtSeconds,\n input.state\n .activeTargetId,\n input.state\n .activeFocusAreaId,\n {\n lockedAtSeconds:\n time,\n resumeAcquisitionState:\n input.state\n .acquisitionState as Exclude<\n FocusAcquisitionState,\n \"locked\"\n >\n }\n );\n }\n\n if (!input.state.locked) {\n return input.state;\n }\n const resume =\n input.state.lock\n ?.resumeAcquisitionState;\n if (resume === undefined) {\n throw new InvalidScientificInputError(\n \"Locked focus state is missing its resume acquisition state.\"\n );\n }\n\n return stateBase(\n input.stateId,\n stateProfileView(\n input.state\n ),\n input.state.mode,\n input.state.focus,\n resume,\n time,\n input.state\n .focusResolvedAtSeconds,\n input.state\n .activeTargetId,\n input.state\n .activeFocusAreaId\n );\n}\n\n/**\n * Reports whether the shutter may be released under the focus-priority or release-priority\n * policy. It does not operate the shutter.\n * @param input - Current state, profile and release priority.\n * @returns The assessment. Read its structured blockers before acting on an authorization.\n *\n * @see docs/API_REFERENCE.md for the package export and its full type definitions.\n */\nexport function assessFocusReleaseGate(\n input:\n AssessFocusReleaseGateInput\n): FocusReleaseGateAssessment {\n requireInputKeys(input, \"assessFocusReleaseGate\", [\"state\", \"profile\", \"priority\"]);\n const profile =\n parseFocusControlProfile(\n input.profile\n );\n verifyStateProfile(\n input.state,\n profile\n );\n\n if (\n !profile\n .supportedReleasePriorities\n .includes(\n input.priority\n )\n ) {\n throw new InvalidScientificInputError(\n \"Selected focus/release priority is not supported by the profile.\"\n );\n }\n\n if (\n input.priority ===\n \"release-priority\"\n ) {\n return {\n priority:\n input.priority,\n releaseAuthorized: true,\n reason:\n \"release-priority-bypasses-focus-gate\",\n requiresProfileSpecificBalancedPolicy:\n false,\n opticalFocusModified:\n false,\n exposureModified:\n false\n };\n }\n\n if (\n input.priority ===\n \"balanced\"\n ) {\n return {\n priority:\n input.priority,\n releaseAuthorized:\n false,\n reason:\n \"balanced-policy-not-modeled\",\n requiresProfileSpecificBalancedPolicy:\n true,\n opticalFocusModified:\n false,\n exposureModified:\n false\n };\n }\n\n if (\n input.state.mode ===\n \"manual\"\n ) {\n return {\n priority:\n input.priority,\n releaseAuthorized: true,\n reason:\n \"manual-focus-state\",\n requiresProfileSpecificBalancedPolicy:\n false,\n opticalFocusModified:\n false,\n exposureModified:\n false\n };\n }\n\n if (\n input.state\n .acquisitionState ===\n \"locked\"\n ) {\n return {\n priority:\n input.priority,\n releaseAuthorized: true,\n reason:\n \"focus-locked\",\n requiresProfileSpecificBalancedPolicy:\n false,\n opticalFocusModified:\n false,\n exposureModified:\n false\n };\n }\n\n if (\n input.state\n .acquisitionState ===\n \"acquired\"\n ) {\n return {\n priority:\n input.priority,\n releaseAuthorized: true,\n reason:\n \"focus-acquired\",\n requiresProfileSpecificBalancedPolicy:\n false,\n opticalFocusModified:\n false,\n exposureModified:\n false\n };\n }\n\n return {\n priority:\n input.priority,\n releaseAuthorized: false,\n reason:\n \"focus-not-acquired\",\n requiresProfileSpecificBalancedPolicy:\n false,\n opticalFocusModified:\n false,\n exposureModified:\n false\n };\n}\n"]}
|
|
@@ -55,6 +55,7 @@ export declare const nativeEnvironmentLeanStatistics: {
|
|
|
55
55
|
keySites: number;
|
|
56
56
|
};
|
|
57
57
|
export declare function setNativeEnvironmentLeanExecutionEnabled(enabled: boolean): void;
|
|
58
|
+
export declare function isPlainRecord(value: object): boolean;
|
|
58
59
|
interface SpatialNode {
|
|
59
60
|
xPhase: number;
|
|
60
61
|
yPhase: number;
|
|
@@ -24,16 +24,16 @@ import { calculateSiteEffectiveSaturationCode } from "./raw-white-level.js";
|
|
|
24
24
|
import { adcTransfer, resolveSensorReadoutRegime, samplePoisson } from "../sensor/raw-readout.js";
|
|
25
25
|
import { createResettableUniformStream, deriveNativeSiteStreamSeedUint32, sampleDeterministicStandardNormal, NATIVE_SITE_CHARGE_STREAM_ID, NATIVE_SITE_READ_NOISE_STREAM_ID } from "../sensor/stochastic-seed.js";
|
|
26
26
|
import { evaluateParsedFixedPatternSite } from "../sensor/fixed-pattern-noise.js";
|
|
27
|
+
import { approximatelyEqual } from "../core/shared-helpers.js";
|
|
27
28
|
/** Most distinct templates kept for one capture event. Any further distinct sites just run the full path. */
|
|
28
29
|
const MAXIMUM_TEMPLATES = 64;
|
|
29
30
|
const SQUARE_MICROMETERS_TO_SQUARE_METERS = 1e-12;
|
|
30
|
-
const REDUCTION_TOLERANCE = 1e-10;
|
|
31
31
|
/** Disables the lean executor process-wide (internal; tests compare both paths). */
|
|
32
32
|
let leanDisabled = false;
|
|
33
33
|
/** Internal counters of lean work (tests assert the lean path actually runs). Not exported from the package. */
|
|
34
34
|
export const nativeEnvironmentLeanStatistics = { plannedSites: 0, executedSites: 0, sensorSites: 0, psfFallbacks: 0, keySites: 0 };
|
|
35
35
|
export function setNativeEnvironmentLeanExecutionEnabled(enabled) { leanDisabled = !enabled; }
|
|
36
|
-
function isPlainRecord(value) {
|
|
36
|
+
export function isPlainRecord(value) {
|
|
37
37
|
const prototype = Object.getPrototypeOf(value);
|
|
38
38
|
return prototype === Object.prototype || prototype === null;
|
|
39
39
|
}
|
|
@@ -882,10 +882,6 @@ export function createNativeEnvironmentLeanExecutor(frame, access) {
|
|
|
882
882
|
}
|
|
883
883
|
};
|
|
884
884
|
}
|
|
885
|
-
function approximatelyEqual(actual, expected) {
|
|
886
|
-
const scale = Math.max(1, Math.abs(actual), Math.abs(expected));
|
|
887
|
-
return Math.abs(actual - expected) <= REDUCTION_TOLERANCE * scale;
|
|
888
|
-
}
|
|
889
885
|
/** Photo-signal fields that vary per site; every other field is template-level. */
|
|
890
886
|
const PHOTO_SITE_FIELDS = new Set(["temporalIntegrationId", "site", "startOffsetSecondsFromOpeningReference",
|
|
891
887
|
"endOffsetSecondsFromOpeningReference", "localExposureDurationSeconds", "expectedIncidentPhotonCount", "expectedGeneratedElectronCount", "temporalSamples"]);
|