@photivra/engine 2.4.1 → 2.6.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 +53 -1
- package/CITATION.cff +1 -1
- package/README.md +6 -6
- package/SECURITY.md +1 -1
- package/THIRD_PARTY.md +1 -0
- package/dist/capture/native-environment-lean.d.ts +1 -1
- package/dist/capture/native-environment-lean.js +17 -3
- package/dist/capture/native-environment-lean.js.map +1 -1
- package/dist/capture/native-environment-raw.d.ts +0 -4
- package/dist/capture/native-environment-raw.js +6 -2
- package/dist/capture/native-environment-raw.js.map +1 -1
- package/dist/color/illuminants.d.ts +15 -0
- package/dist/color/illuminants.js +81 -24
- package/dist/color/illuminants.js.map +1 -1
- package/dist/color/srgb-transfer.d.ts +6 -0
- package/dist/color/srgb-transfer.js +9 -0
- package/dist/color/srgb-transfer.js.map +1 -1
- package/dist/color/white-balance.d.ts +6 -0
- package/dist/color/white-balance.js +15 -2
- package/dist/color/white-balance.js.map +1 -1
- package/dist/core/internal-radiance-evaluator.d.ts +6 -0
- package/dist/core/internal-radiance-evaluator.js +33 -0
- package/dist/core/internal-radiance-evaluator.js.map +1 -0
- package/dist/core/portable-math.d.ts +33 -0
- package/dist/core/portable-math.js +342 -0
- package/dist/core/portable-math.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/facade/chart-scenes.d.ts +9 -0
- package/dist/facade/chart-scenes.js +17 -4
- package/dist/facade/chart-scenes.js.map +1 -1
- package/dist/facade/diffraction-provider.d.ts +10 -0
- package/dist/facade/diffraction-provider.js +38 -17
- package/dist/facade/diffraction-provider.js.map +1 -1
- package/dist/facade/display-view.d.ts +208 -0
- package/dist/facade/display-view.js +1461 -0
- package/dist/facade/display-view.js.map +1 -0
- package/dist/facade/scene-radiance.d.ts +7 -0
- package/dist/facade/scene-radiance.js +18 -5
- package/dist/facade/scene-radiance.js.map +1 -1
- package/dist/facade/simulate-capture.d.ts +229 -5
- package/dist/facade/simulate-capture.js +119 -35
- package/dist/facade/simulate-capture.js.map +1 -1
- package/dist/facade/simulate-display-view.d.ts +21 -0
- package/dist/facade/simulate-display-view.js +168 -0
- package/dist/facade/simulate-display-view.js.map +1 -0
- package/dist/facade/subject-framing.d.ts +78 -0
- package/dist/facade/subject-framing.js +69 -20
- package/dist/facade/subject-framing.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/optics/diffraction-psf-profile.d.ts +59 -3
- package/dist/optics/diffraction-psf-profile.js +147 -5
- package/dist/optics/diffraction-psf-profile.js.map +1 -1
- package/dist/optics/irradiance-convolution.js +1 -1
- package/dist/optics/irradiance-convolution.js.map +1 -1
- package/dist/optics/scene-to-sensor-irradiance.d.ts +7 -0
- package/dist/optics/scene-to-sensor-irradiance.js +10 -5
- package/dist/optics/scene-to-sensor-irradiance.js.map +1 -1
- package/dist/output/print-plan.d.ts +8 -1
- package/dist/output/print-plan.js +8 -1
- package/dist/output/print-plan.js.map +1 -1
- package/dist/schema/scene-radiance.d.ts +16 -0
- package/dist/schema/scene-radiance.js +25 -4
- package/dist/schema/scene-radiance.js.map +1 -1
- package/dist/sensor/raw-readout.d.ts +12 -0
- package/dist/sensor/raw-readout.js +131 -9
- package/dist/sensor/raw-readout.js.map +1 -1
- package/dist/sensor/stochastic-seed.d.ts +13 -0
- package/dist/sensor/stochastic-seed.js +42 -8
- package/dist/sensor/stochastic-seed.js.map +1 -1
- package/docs/AGENT_GUIDE.md +1 -0
- package/docs/API_REFERENCE.md +16 -1
- package/docs/QUICK_START.md +245 -9
- package/docs/USAGE.md +15 -0
- package/docs/api/core-version.md +1 -1
- package/docs/api/exports.json +37 -2
- package/docs/api/facade-simulate-capture.md +70 -2
- package/docs/api/facade-simulate-display-view.md +18 -0
- package/docs/api/facade-subject-framing.md +83 -0
- package/docs/api/optics-diffraction-psf-profile.md +8 -1
- package/docs/api/output-print-plan.md +8 -1
- package/package.json +3 -2
package/docs/api/exports.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"packageVersion": "2.
|
|
3
|
-
"engineApiVersion": "2.
|
|
2
|
+
"packageVersion": "2.6.0",
|
|
3
|
+
"engineApiVersion": "2.6.0",
|
|
4
4
|
"exports": [
|
|
5
5
|
{
|
|
6
6
|
"name": "AbsoluteUncertaintyEstimate",
|
|
@@ -437,6 +437,16 @@
|
|
|
437
437
|
"source": "src/output/crop.ts",
|
|
438
438
|
"kind": "type"
|
|
439
439
|
},
|
|
440
|
+
{
|
|
441
|
+
"name": "calculateChartFraming",
|
|
442
|
+
"source": "src/facade/subject-framing.ts",
|
|
443
|
+
"kind": "runtime"
|
|
444
|
+
},
|
|
445
|
+
{
|
|
446
|
+
"name": "CalculateChartFramingInput",
|
|
447
|
+
"source": "src/facade/subject-framing.ts",
|
|
448
|
+
"kind": "type"
|
|
449
|
+
},
|
|
440
450
|
{
|
|
441
451
|
"name": "calculateChartRadianceBatch",
|
|
442
452
|
"source": "src/facade/chart-radiance-batch.ts",
|
|
@@ -1842,6 +1852,11 @@
|
|
|
1842
1852
|
"source": "src/facade/chart-scenes.ts",
|
|
1843
1853
|
"kind": "type"
|
|
1844
1854
|
},
|
|
1855
|
+
{
|
|
1856
|
+
"name": "ChartFraming",
|
|
1857
|
+
"source": "src/facade/subject-framing.ts",
|
|
1858
|
+
"kind": "type"
|
|
1859
|
+
},
|
|
1845
1860
|
{
|
|
1846
1861
|
"name": "ChartRadianceBatchInput",
|
|
1847
1862
|
"source": "src/facade/chart-radiance-batch.ts",
|
|
@@ -2567,6 +2582,11 @@
|
|
|
2567
2582
|
"source": "src/core/spectral-composition.ts",
|
|
2568
2583
|
"kind": "type"
|
|
2569
2584
|
},
|
|
2585
|
+
{
|
|
2586
|
+
"name": "DisplayViewResult",
|
|
2587
|
+
"source": "src/facade/simulate-capture.ts",
|
|
2588
|
+
"kind": "type"
|
|
2589
|
+
},
|
|
2570
2590
|
{
|
|
2571
2591
|
"name": "DistributeIntegratedQuantityAcrossDiscreteLinesInput",
|
|
2572
2592
|
"source": "src/core/spectral-composition.ts",
|
|
@@ -7892,6 +7912,11 @@
|
|
|
7892
7912
|
"source": "src/facade/simulate-capture.ts",
|
|
7893
7913
|
"kind": "runtime"
|
|
7894
7914
|
},
|
|
7915
|
+
{
|
|
7916
|
+
"name": "SIMULATE_DISPLAY_VIEW_DEFAULT_SAMPLES_PER_AXIS",
|
|
7917
|
+
"source": "src/facade/simulate-capture.ts",
|
|
7918
|
+
"kind": "runtime"
|
|
7919
|
+
},
|
|
7895
7920
|
{
|
|
7896
7921
|
"name": "simulateCapture",
|
|
7897
7922
|
"source": "src/facade/simulate-capture.ts",
|
|
@@ -7987,6 +8012,16 @@
|
|
|
7987
8012
|
"source": "src/capture/simulated-capture.ts",
|
|
7988
8013
|
"kind": "type"
|
|
7989
8014
|
},
|
|
8015
|
+
{
|
|
8016
|
+
"name": "simulateDisplayView",
|
|
8017
|
+
"source": "src/facade/simulate-display-view.ts",
|
|
8018
|
+
"kind": "runtime"
|
|
8019
|
+
},
|
|
8020
|
+
{
|
|
8021
|
+
"name": "SimulateDisplayViewOptions",
|
|
8022
|
+
"source": "src/facade/simulate-capture.ts",
|
|
8023
|
+
"kind": "type"
|
|
8024
|
+
},
|
|
7990
8025
|
{
|
|
7991
8026
|
"name": "simulateEnvironmentSensorRawFrame",
|
|
7992
8027
|
"source": "src/capture/environment-raw-producer.ts",
|
|
@@ -2,6 +2,42 @@
|
|
|
2
2
|
|
|
3
3
|
The package and root API versions are recorded once in [Navigation](../API_REFERENCE.md) · [Developer guide](https://github.com/Photivra/photivra/blob/main/docs/DEVELOPERS.md). Generated signatures retain independent schema/model versions. Only the exports listed here are root-package contracts; module-local helpers are not supported deep imports.
|
|
4
4
|
|
|
5
|
+
## DisplayViewResult
|
|
6
|
+
|
|
7
|
+
Result of {@link simulateDisplayView }: the full-resolution capture resized for display, estimated; not a capture.
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
export interface DisplayViewResult {
|
|
11
|
+
kind: "display-view";
|
|
12
|
+
/** Human-readable label for a user interface. */
|
|
13
|
+
label: string;
|
|
14
|
+
facadeVersion: typeof SIMULATE_CAPTURE_FACADE_VERSION;
|
|
15
|
+
engineApiVersion: string;
|
|
16
|
+
/** The display view (or its region): interleaved sRGB samples, row by row from the top-left. */
|
|
17
|
+
image: { width: number; height: number; format: "srgb-8" | "srgb-16"; samples: Uint8Array | Uint16Array };
|
|
18
|
+
/**
|
|
19
|
+
* The view: display size, the capture frame it shows (output pixels), real pixels per display pixel along each axis,
|
|
20
|
+
* the samples per axis and, with `view.region`, the rendered rectangle.
|
|
21
|
+
*/
|
|
22
|
+
view: { width: number; height: number; frameWidth: number; frameHeight: number; scaleX: number; scaleY: number; samplesPerAxis: number;
|
|
23
|
+
region?: { x: number; y: number; width: number; height: number } };
|
|
24
|
+
/** The resolved exposure of the capture this view shows. */
|
|
25
|
+
exposure: { mode: SimulateCaptureExposureMode; settings: { fNumber: number; shutterSeconds: number; iso: number }; ev100: number };
|
|
26
|
+
scene: SimulateCaptureResult["scene"];
|
|
27
|
+
/**
|
|
28
|
+
* Work done: real pixels sampled, real-site expectations evaluated, scene queries, display pixels sampled in full (detail) or with
|
|
29
|
+
* a quarter of the samples per axis (uniform), display pixels whose value includes the AHD low-signal correction, and wall-clock
|
|
30
|
+
* milliseconds (diagnostic only; never affects the samples).
|
|
31
|
+
*/
|
|
32
|
+
diagnostics: { sampleCount: number; siteEvaluations: number; sceneLookups: number; detailPixelCount: number; uniformPixelCount: number; ahdCorrectedPixelCount: number;
|
|
33
|
+
timingsMs: { view: number; total: number } };
|
|
34
|
+
provenance: { scientificStatus: "approximation"; cameraPresetId: string; cameraPresetVersion: string; evidence: readonly EvidenceProvenance[];
|
|
35
|
+
composedContracts: readonly string[]; limitations: readonly string[] };
|
|
36
|
+
/** The capture request's assumptions, then `view.definition`, `view.estimation`, `view.noise`, `view.demosaic` and `view.source`. */
|
|
37
|
+
assumptions: readonly SimulateCaptureAssumption[];
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
5
41
|
## IdealReferenceResult
|
|
6
42
|
|
|
7
43
|
Result of {@link simulateIdealReference}: an ideal reference image, not a capture (no RAW, plan or request).
|
|
@@ -65,6 +101,14 @@ Version of how the facade builds requests. It changes whenever the same input wo
|
|
|
65
101
|
SIMULATE_CAPTURE_FACADE_VERSION = "1.0.0" as const
|
|
66
102
|
```
|
|
67
103
|
|
|
104
|
+
## SIMULATE_DISPLAY_VIEW_DEFAULT_SAMPLES_PER_AXIS
|
|
105
|
+
|
|
106
|
+
Default stratified samples per axis of a display view (`view.samplesPerAxis`): 16 × 16 sampled real pixels per display pixel with detail, 4 × 4 where it is uniform.
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
SIMULATE_DISPLAY_VIEW_DEFAULT_SAMPLES_PER_AXIS = 16
|
|
110
|
+
```
|
|
111
|
+
|
|
68
112
|
## simulateCapture
|
|
69
113
|
|
|
70
114
|
Simulates one still capture of a planar scene and returns the developed image, the packed RAW, the full
|
|
@@ -285,14 +329,20 @@ export interface SimulateCaptureOptions {
|
|
|
285
329
|
* the whole render: framing, metering, exposure, noise seeds (absolute native site indices), rolling-shutter row
|
|
286
330
|
* timing, diffraction and demosaic all use the whole frame. Use it to tile a large frame across workers or to
|
|
287
331
|
* render a 100 % crop. `result.image` is the region; `result.region` reports it. Not combinable with
|
|
288
|
-
* `whiteBalance: "auto"`, whose statistics would come from the region only.
|
|
332
|
+
* `whiteBalance: "auto"`, whose statistics would come from the region only. From 2.6 the diffraction convolution
|
|
333
|
+
* covers only the region plus the kernel and filter reach, so a small region of a large frame costs about as much
|
|
334
|
+
* as a capture of the region's size.
|
|
289
335
|
*/
|
|
290
336
|
region?: { x: number; y: number; width: number; height: number };
|
|
291
337
|
};
|
|
292
338
|
/** Camera motion and shutter type. Default: still camera, global electronic shutter. */
|
|
293
339
|
motion?: SimulateCaptureMotion;
|
|
294
340
|
sensor?: {
|
|
295
|
-
/**
|
|
341
|
+
/**
|
|
342
|
+
* Pixel pitch in micrometres, 0.5–1000. Default 6. The simulated sensor is output width × pitch wide. 2.5: above 100 µm the
|
|
343
|
+
* capture is a downsized view of a whole frame (for example 36 mm / 48 pixels = 750 µm), recorded in the assumption
|
|
344
|
+
* `sensor.wholeFrameView`: brightness is unchanged and the noise is that of a binned view, not of the real sensor's pixels.
|
|
345
|
+
*/
|
|
296
346
|
pixelPitchMicrometers?: number;
|
|
297
347
|
/** Maximum spectral quadrature subinterval in nm. Default 20. */
|
|
298
348
|
spectralStepNanometers?: number;
|
|
@@ -499,6 +549,24 @@ export type SimulateCaptureWhiteBalance =
|
|
|
499
549
|
| { channelGains: { red: number; green: number; blue: number } };
|
|
500
550
|
```
|
|
501
551
|
|
|
552
|
+
## SimulateDisplayViewOptions
|
|
553
|
+
|
|
554
|
+
The display size and sampling of {@link simulateDisplayView }.
|
|
555
|
+
|
|
556
|
+
```ts
|
|
557
|
+
export interface SimulateDisplayViewOptions {
|
|
558
|
+
/** Display pixels, 1 to the capture's output width and height. */
|
|
559
|
+
width: number;
|
|
560
|
+
height: number;
|
|
561
|
+
/** Stratified Monte Carlo samples per axis for each display pixel's expected value (1–32, default 8: 64 real pixels). */
|
|
562
|
+
samplesPerAxis?: number;
|
|
563
|
+
/** "srgb-8" (default) or "srgb-16". */
|
|
564
|
+
format?: "srgb-8" | "srgb-16";
|
|
565
|
+
/** Render only this rectangle of the display view, in display pixels; byte-identical to the same pixels of the whole view. */
|
|
566
|
+
region?: { x: number; y: number; width: number; height: number };
|
|
567
|
+
}
|
|
568
|
+
```
|
|
569
|
+
|
|
502
570
|
## simulateIdealReference
|
|
503
571
|
|
|
504
572
|
The ideal reference of a capture request (2.3): the same scene, framing, chart size, output size, region and pixel
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# facade/simulate-display-view.ts public contracts
|
|
2
|
+
|
|
3
|
+
The package and root API versions are recorded once in [Navigation](../API_REFERENCE.md) · [Developer guide](https://github.com/Photivra/photivra/blob/main/docs/DEVELOPERS.md). Generated signatures retain independent schema/model versions. Only the exports listed here are root-package contracts; module-local helpers are not supported deep imports.
|
|
4
|
+
|
|
5
|
+
## simulateDisplayView
|
|
6
|
+
|
|
7
|
+
The display view of a capture request: the image the real full-resolution capture (`simulateCapture(options)`) would
|
|
8
|
+
give after it is resized to `view.width` × `view.height` by area averaging in linear light, estimated at a cost that
|
|
9
|
+
follows the display pixels, not the capture's. Optics (lens diffraction, the anti-aliasing filter, the pixel aperture)
|
|
10
|
+
act at the real pixel pitch; the colour mosaic, demosaic and development are those of the real pixels; the noise is
|
|
11
|
+
that of the average of the real pixels, demosaic correlation included; exposure, white balance and tone are the
|
|
12
|
+
capture's. The result is labelled `kind: "display-view"`; it is not a capture.
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
export async function simulateDisplayView(options: SimulateCaptureOptions, view: SimulateDisplayViewOptions): Promise<DisplayViewResult>;
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
This call is asynchronous; byte hashing uses the caller runtime's Web Crypto.
|
|
@@ -2,6 +2,39 @@
|
|
|
2
2
|
|
|
3
3
|
The package and root API versions are recorded once in [Navigation](../API_REFERENCE.md) · [Developer guide](https://github.com/Photivra/photivra/blob/main/docs/DEVELOPERS.md). Generated signatures retain independent schema/model versions. Only the exports listed here are root-package contracts; module-local helpers are not supported deep imports.
|
|
4
4
|
|
|
5
|
+
## calculateChartFraming
|
|
6
|
+
|
|
7
|
+
How much of the frame a chart of a given physical size covers at any subject distance (2.5): magnification, framed plane size,
|
|
8
|
+
coverage fractions (above 1 when cropped), the chart's image size and the minimum-focus check. The same thin-lens framing as
|
|
9
|
+
`simulateCapture` (`scene.framing`, `result.scene.chart`) and `calculateSubjectDistanceForFraming`.
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
export function calculateChartFraming(input: CalculateChartFramingInput): ChartFraming;
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
This call is synchronous; any supplied provider must follow its explicit synchronous contract.
|
|
16
|
+
|
|
17
|
+
## CalculateChartFramingInput
|
|
18
|
+
|
|
19
|
+
The exact contract is declared below; use the domain guide for assumptions and staged integration.
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
export interface CalculateChartFramingInput {
|
|
23
|
+
/** Active sensor (or simulated frame) size, mm: for `simulateCapture`, output width × height × pixel pitch. */
|
|
24
|
+
sensor: { widthMm: number; heightMm: number };
|
|
25
|
+
/** Physical focal length, mm. Give exactly one of this and `equivalentFocalLengthMm`. */
|
|
26
|
+
focalLengthMm?: number;
|
|
27
|
+
/** Full-frame-equivalent focal length (diagonal crop factor); a generic prime's value also reports that lens (as `lens.prime`). */
|
|
28
|
+
equivalentFocalLengthMm?: number;
|
|
29
|
+
/** Chart size as for `simulateCapture` `chartSize`: heightM defaults to widthM × the sensor aspect (height / width). */
|
|
30
|
+
chart: { widthM: number; heightM?: number };
|
|
31
|
+
/** Distance from the lens to the chart plane, metres; more than the focal length. */
|
|
32
|
+
subjectDistanceM: number;
|
|
33
|
+
/** Focus distance, metres (as `lens.focusDistanceM`); default the subject distance. More than the focal length. */
|
|
34
|
+
focusDistanceM?: number;
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
5
38
|
## calculateSubjectDistanceForFraming
|
|
6
39
|
|
|
7
40
|
The subject distance that fits a chart of a given physical size to the frame, with magnification, coverage and the minimum-focus check (2.3).
|
|
@@ -30,6 +63,48 @@ export interface CalculateSubjectDistanceForFramingInput {
|
|
|
30
63
|
}
|
|
31
64
|
```
|
|
32
65
|
|
|
66
|
+
## ChartFraming
|
|
67
|
+
|
|
68
|
+
The exact contract is declared below; use the domain guide for assumptions and staged integration.
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
export interface ChartFraming {
|
|
72
|
+
subjectDistanceM: number;
|
|
73
|
+
focusDistanceM: number;
|
|
74
|
+
/** Thin-lens image distance at the focus distance, f·s/(s − f), mm. */
|
|
75
|
+
imageDistanceMm: number;
|
|
76
|
+
/** Image size ÷ object size on the chart plane, v/d: f/(d − f) when focused on the chart. */
|
|
77
|
+
magnification: number;
|
|
78
|
+
focalLengthMm: number;
|
|
79
|
+
equivalentFocalLengthMm: number;
|
|
80
|
+
cropFactor35Mm: number;
|
|
81
|
+
chart: { widthM: number; heightM: number };
|
|
82
|
+
/** Plane area the frame covers at the subject distance, metres: sensor side ÷ magnification. */
|
|
83
|
+
framedWidthM: number;
|
|
84
|
+
framedHeightM: number;
|
|
85
|
+
/** Fraction of the frame width and height the chart covers; above 1 means the chart is larger than the frame and cropped. */
|
|
86
|
+
coverage: { frameWidthFraction: number; frameHeightFraction: number };
|
|
87
|
+
/** The chart's image on the sensor, mm. */
|
|
88
|
+
chartImageMm: { width: number; height: number };
|
|
89
|
+
/**
|
|
90
|
+
* 2.6: the thin-lens close-up light factor at the focus distance, 1/(1 + m)² with m = v/s: the image-plane irradiance
|
|
91
|
+
* relative to the same lens and f-number focused at infinity (working f-number N·(1 + m)). It is the factor
|
|
92
|
+
* `simulateCapture` applies through the scene-to-sensor irradiance (same function, same value).
|
|
93
|
+
*/
|
|
94
|
+
closeUpTransmission: number;
|
|
95
|
+
/** 2.6: the same factor in stops, 2·log₂(1 + m): how much darker the image is than at infinity focus. */
|
|
96
|
+
closeUpLossStops: number;
|
|
97
|
+
/** The generic prime of this equivalent focal length, when there is one. */
|
|
98
|
+
prime: GenericPrimeLens | null;
|
|
99
|
+
/** The generic prime rule max(0.10 m, f·(1 + 1/0.15)) at this focal length (the prime's own value when there is one). */
|
|
100
|
+
minimumFocusDistanceM: number;
|
|
101
|
+
/** True when the subject or focus distance is closer than the minimum focus distance (`simulateCapture` with `lens.prime` rejects it). */
|
|
102
|
+
belowMinimumFocus: boolean;
|
|
103
|
+
scientificStatus: "approximation";
|
|
104
|
+
assumptions: readonly SimulateCaptureAssumption[];
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
33
108
|
## SubjectFraming
|
|
34
109
|
|
|
35
110
|
The exact contract is declared below; use the domain guide for assumptions and staged integration.
|
|
@@ -52,6 +127,14 @@ export interface SubjectFraming {
|
|
|
52
127
|
framedHeightM: number;
|
|
53
128
|
/** Fraction of the frame width and height the chart covers (1 on the fitted side; above 1 means cropped). */
|
|
54
129
|
coverage: { frameWidthFraction: number; frameHeightFraction: number };
|
|
130
|
+
/**
|
|
131
|
+
* 2.6: the thin-lens close-up light factor at the focus distance, 1/(1 + m)² with m = v/s: the image-plane irradiance
|
|
132
|
+
* relative to the same lens and f-number focused at infinity (working f-number N·(1 + m)). It is the factor
|
|
133
|
+
* `simulateCapture` applies through the scene-to-sensor irradiance (same function, same value).
|
|
134
|
+
*/
|
|
135
|
+
closeUpTransmission: number;
|
|
136
|
+
/** 2.6: the same factor in stops, 2·log₂(1 + m): how much darker the image is than at infinity focus. */
|
|
137
|
+
closeUpLossStops: number;
|
|
55
138
|
/** The generic prime of this equivalent focal length, when there is one. */
|
|
56
139
|
prime: GenericPrimeLens | null;
|
|
57
140
|
/** The generic prime rule max(0.10 m, f·(1 + 1/0.15)) at this focal length (the prime's own value when there is one). */
|
|
@@ -71,7 +71,14 @@ export interface DiffractionLimitedPsfProfile {
|
|
|
71
71
|
wavelengths: readonly DiffractionLimitedPsfWavelength[];
|
|
72
72
|
/** Largest truncated energy over the wavelengths. */
|
|
73
73
|
maximumTruncatedEnergyFraction: number;
|
|
74
|
-
|
|
74
|
+
/**
|
|
75
|
+
* How the cells were integrated. 2.5: wavelengths with β = p·f_c ≥ 192 (cells far larger than the pattern) use the real-space
|
|
76
|
+
* encircled-energy method; `realSpaceWavelengthsNm` lists them, and `method` is `"frequency-domain-and-real-space"` when both ran.
|
|
77
|
+
* `maximumRadialNodes` counts frequency-domain radial nodes (0 when only the real-space method ran); `maximumAngularNodes` the
|
|
78
|
+
* angular nodes of either method (for the real-space method, all θ nodes of one wavelength).
|
|
79
|
+
*/
|
|
80
|
+
quadrature: { method: "polar-frequency-domain-trapezoid-gauss-legendre" | "real-space-encircled-energy-gauss-legendre" | "frequency-domain-and-real-space";
|
|
81
|
+
maximumRadialNodes: number; maximumAngularNodes: number; realSpaceWavelengthsNm?: readonly number[] };
|
|
75
82
|
}
|
|
76
83
|
```
|
|
77
84
|
|
|
@@ -5,7 +5,11 @@ The package and root API versions are recorded once in [Navigation](../API_REFER
|
|
|
5
5
|
## calculatePrintPlan
|
|
6
6
|
|
|
7
7
|
Finds the smallest file, at the exact native aspect ratio, that meets the declared sampling and lab constraints.
|
|
8
|
-
The angular guidance is an approximate rule of thumb; the geometry itself is calculated exactly.
|
|
8
|
+
The angular guidance is an approximate rule of thumb; the geometry itself is calculated exactly. A common criterion,
|
|
9
|
+
one arcminute per pixel, is normal (20/20) visual acuity under optimal conditions: the minimum angle of resolution of an
|
|
10
|
+
ideal eye is about 1 minute of arc, and 20/20 letters are built from elements that each subtend 1 arcmin (Z. Alomar, K. D. Bojikian, "Visual Acuity Testing in Adults", EyeWiki, American Academy of Ophthalmology,
|
|
11
|
+
https://eyewiki.aao.org/Visual_Acuity_Testing_in_Adults, last edited June 16, 2026).
|
|
12
|
+
Some viewers resolve finer detail and many resolve coarser, so it stays a rule of thumb, and the criterion is the caller's.
|
|
9
13
|
It does not assess source detail, perceived quality, file writing or available resources.
|
|
10
14
|
|
|
11
15
|
```ts
|
|
@@ -18,6 +22,9 @@ This call is synchronous; any supplied provider must follow its explicit synchro
|
|
|
18
22
|
|
|
19
23
|
Calculates the largest print size under the stated conditions. Lab constraints need individual plans,
|
|
20
24
|
so this size query reports them as unsupported rather than ignoring them.
|
|
25
|
+
As in `calculatePrintPlan`, an angular criterion is an approximate rule of thumb: one arcminute per pixel is normal
|
|
26
|
+
(20/20) acuity under optimal conditions, which some viewers exceed and many do not (Z. Alomar, K. D. Bojikian, "Visual Acuity Testing in Adults", EyeWiki, American Academy of Ophthalmology,
|
|
27
|
+
https://eyewiki.aao.org/Visual_Acuity_Testing_in_Adults, last edited June 16, 2026).
|
|
21
28
|
|
|
22
29
|
```ts
|
|
23
30
|
export function calculatePrintSizeLimit(value: PrintSizeLimitInput): CalculationResult<PrintSizeLimit>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@photivra/engine",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Scientific TypeScript engine for camera optics, exposure, focus, motion, sensor sampling, diffraction, and digital imaging calculations.",
|
|
6
6
|
"type": "module",
|
|
@@ -108,7 +108,8 @@
|
|
|
108
108
|
"typescript-eslint": "8.70.0",
|
|
109
109
|
"vitest": "5.0.1",
|
|
110
110
|
"@types/node": "24.13.6",
|
|
111
|
-
"@vitest/coverage-v8": "5.0.1"
|
|
111
|
+
"@vitest/coverage-v8": "5.0.1",
|
|
112
|
+
"rolldown": "1.2.9"
|
|
112
113
|
},
|
|
113
114
|
"keywords": [
|
|
114
115
|
"photography",
|