@photivra/engine 2.19.0 → 2.21.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.
Files changed (242) hide show
  1. package/CHANGELOG.md +289 -1
  2. package/CITATION.cff +1 -1
  3. package/NODE_SUPPORT.md +7 -5
  4. package/README.md +7 -6
  5. package/SECURITY.md +1 -1
  6. package/THIRD_PARTY.md +21 -10
  7. package/dist/capture/dng-lens-correction-opcodes.d.ts +32 -0
  8. package/dist/capture/dng-lens-correction-opcodes.js +119 -0
  9. package/dist/capture/dng-lens-correction-opcodes.js.map +1 -0
  10. package/dist/capture/exposure-build-up-stage.d.ts +16 -0
  11. package/dist/capture/exposure-build-up-stage.js +4 -0
  12. package/dist/capture/exposure-build-up-stage.js.map +1 -0
  13. package/dist/capture/native-environment-lean.d.ts +2 -1
  14. package/dist/capture/native-environment-lean.js +42 -78
  15. package/dist/capture/native-environment-lean.js.map +1 -1
  16. package/dist/capture/native-environment-tabulated.js +4 -3
  17. package/dist/capture/native-environment-tabulated.js.map +1 -1
  18. package/dist/capture/native-raw-dng.d.ts +6 -0
  19. package/dist/capture/native-raw-dng.js +16 -2
  20. package/dist/capture/native-raw-dng.js.map +1 -1
  21. package/dist/capture/native-raw.d.ts +3 -2
  22. package/dist/capture/native-raw.js +5 -4
  23. package/dist/capture/native-raw.js.map +1 -1
  24. package/dist/capture/sensor-raw-producer.d.ts +4 -1
  25. package/dist/capture/sensor-raw-producer.js +15 -8
  26. package/dist/capture/sensor-raw-producer.js.map +1 -1
  27. package/dist/core/shared-helpers.d.ts +2 -0
  28. package/dist/core/shared-helpers.js +4 -0
  29. package/dist/core/shared-helpers.js.map +1 -1
  30. package/dist/core/version.d.ts +1 -1
  31. package/dist/core/version.js +1 -1
  32. package/dist/core/version.js.map +1 -1
  33. package/dist/equipment/generic-lens-catalogue.d.ts +11 -4
  34. package/dist/equipment/generic-lens-catalogue.js +49 -7
  35. package/dist/equipment/generic-lens-catalogue.js.map +1 -1
  36. package/dist/equipment/generic-tier-assets.d.ts +32 -0
  37. package/dist/equipment/generic-tier-assets.js +18 -14
  38. package/dist/equipment/generic-tier-assets.js.map +1 -1
  39. package/dist/equipment/generic-tier-presets.js +2 -3
  40. package/dist/equipment/generic-tier-presets.js.map +1 -1
  41. package/dist/equipment/sensor-profile-body.d.ts +78 -0
  42. package/dist/equipment/sensor-profile-body.js +77 -0
  43. package/dist/equipment/sensor-profile-body.js.map +1 -0
  44. package/dist/equipment/sensor-profiles.d.ts +8 -0
  45. package/dist/equipment/sensor-profiles.js +82 -0
  46. package/dist/equipment/sensor-profiles.js.map +1 -0
  47. package/dist/facade/catalogue-lens-signal.d.ts +2 -2
  48. package/dist/facade/catalogue-lens-signal.js +58 -71
  49. package/dist/facade/catalogue-lens-signal.js.map +1 -1
  50. package/dist/facade/chart-radiance-batch.js +2 -1
  51. package/dist/facade/chart-radiance-batch.js.map +1 -1
  52. package/dist/facade/defocus-image-space-provider.d.ts +7 -0
  53. package/dist/facade/defocus-image-space-provider.js +64 -76
  54. package/dist/facade/defocus-image-space-provider.js.map +1 -1
  55. package/dist/facade/display-view-gpu-session.js +2 -0
  56. package/dist/facade/display-view-gpu-session.js.map +1 -1
  57. package/dist/facade/display-view-gpu.d.ts +13 -5
  58. package/dist/facade/display-view-gpu.js +4 -4
  59. package/dist/facade/display-view-gpu.js.map +1 -1
  60. package/dist/facade/display-view-lens-signal.d.ts +1 -1
  61. package/dist/facade/display-view-lens-signal.js +30 -26
  62. package/dist/facade/display-view-lens-signal.js.map +1 -1
  63. package/dist/facade/display-view.d.ts +3 -1
  64. package/dist/facade/display-view.js +6 -24
  65. package/dist/facade/display-view.js.map +1 -1
  66. package/dist/facade/expected-signal-setup.d.ts +3 -1
  67. package/dist/facade/expected-signal-setup.js +1 -1
  68. package/dist/facade/expected-signal-setup.js.map +1 -1
  69. package/dist/facade/expected-signal.d.ts +47 -14
  70. package/dist/facade/expected-signal.js +117 -112
  71. package/dist/facade/expected-signal.js.map +1 -1
  72. package/dist/facade/exposure-build-up.d.ts +70 -0
  73. package/dist/facade/exposure-build-up.js +164 -0
  74. package/dist/facade/exposure-build-up.js.map +1 -0
  75. package/dist/facade/fast-methods.d.ts +50 -0
  76. package/dist/facade/fast-methods.js +58 -0
  77. package/dist/facade/fast-methods.js.map +1 -0
  78. package/dist/facade/fast-resolution.d.ts +12 -0
  79. package/dist/facade/fast-resolution.js +18 -0
  80. package/dist/facade/fast-resolution.js.map +1 -0
  81. package/dist/facade/generic-lens-capture.d.ts +5 -4
  82. package/dist/facade/generic-lens-capture.js +5 -4
  83. package/dist/facade/generic-lens-capture.js.map +1 -1
  84. package/dist/facade/image-plane-enable.d.ts +7 -0
  85. package/dist/facade/image-plane-enable.js +17 -0
  86. package/dist/facade/image-plane-enable.js.map +1 -0
  87. package/dist/facade/image-plane-lattice-data.d.ts +6 -0
  88. package/dist/facade/image-plane-lattice-data.js +10 -0
  89. package/dist/facade/image-plane-lattice-data.js.map +1 -0
  90. package/dist/facade/image-plane-support.d.ts +33 -0
  91. package/dist/facade/image-plane-support.js +11 -0
  92. package/dist/facade/image-plane-support.js.map +1 -0
  93. package/dist/facade/image-plane.d.ts +36 -0
  94. package/dist/facade/image-plane.js +353 -0
  95. package/dist/facade/image-plane.js.map +1 -0
  96. package/dist/facade/mixed-illumination.d.ts +108 -0
  97. package/dist/facade/mixed-illumination.js +174 -0
  98. package/dist/facade/mixed-illumination.js.map +1 -0
  99. package/dist/facade/representative-light-sources.d.ts +72 -0
  100. package/dist/facade/representative-light-sources.js +124 -0
  101. package/dist/facade/representative-light-sources.js.map +1 -0
  102. package/dist/facade/scene-radiance.d.ts +129 -4
  103. package/dist/facade/scene-radiance.js +48 -13
  104. package/dist/facade/scene-radiance.js.map +1 -1
  105. package/dist/facade/simulate-capture.d.ts +88 -19
  106. package/dist/facade/simulate-capture.js +374 -145
  107. package/dist/facade/simulate-capture.js.map +1 -1
  108. package/dist/facade/simulate-display-view.d.ts +3 -2
  109. package/dist/facade/simulate-display-view.js +36 -18
  110. package/dist/facade/simulate-display-view.js.map +1 -1
  111. package/dist/gpu/chart-composite-gpu.d.ts +13 -1
  112. package/dist/gpu/chart-composite-gpu.js +48 -9
  113. package/dist/gpu/chart-composite-gpu.js.map +1 -1
  114. package/dist/gpu/chart-radiance-gpu.js +4 -30
  115. package/dist/gpu/chart-radiance-gpu.js.map +1 -1
  116. package/dist/gpu/display-view-composite-material-module.d.ts +10 -4
  117. package/dist/gpu/display-view-composite-material-module.js +39 -13
  118. package/dist/gpu/display-view-composite-material-module.js.map +1 -1
  119. package/dist/gpu/display-view-image-material-module.d.ts +86 -0
  120. package/dist/gpu/display-view-image-material-module.js +339 -0
  121. package/dist/gpu/display-view-image-material-module.js.map +1 -0
  122. package/dist/gpu/display-view-image-quality.d.ts +45 -0
  123. package/dist/gpu/display-view-image-quality.js +380 -0
  124. package/dist/gpu/display-view-image-quality.js.map +1 -0
  125. package/dist/gpu/display-view-quality-gpu.d.ts +67 -1
  126. package/dist/gpu/display-view-quality-gpu.js +136 -205
  127. package/dist/gpu/display-view-quality-gpu.js.map +1 -1
  128. package/dist/gpu/display-view-speed-gpu.d.ts +51 -3
  129. package/dist/gpu/display-view-speed-gpu.js +131 -93
  130. package/dist/gpu/display-view-speed-gpu.js.map +1 -1
  131. package/dist/gpu/wgsl-display-view-quality-kernel.d.ts +29 -15
  132. package/dist/gpu/wgsl-display-view-quality-kernel.js +58 -36
  133. package/dist/gpu/wgsl-display-view-quality-kernel.js.map +1 -1
  134. package/dist/gpu/wgsl-display-view-speed-kernel.d.ts +21 -6
  135. package/dist/gpu/wgsl-display-view-speed-kernel.js +46 -11
  136. package/dist/gpu/wgsl-display-view-speed-kernel.js.map +1 -1
  137. package/dist/gpu/wgsl-exact-sum.d.ts +20 -0
  138. package/dist/gpu/wgsl-exact-sum.js +42 -0
  139. package/dist/gpu/wgsl-exact-sum.js.map +1 -0
  140. package/dist/index.d.ts +18 -3
  141. package/dist/index.js +12 -1
  142. package/dist/index.js.map +1 -1
  143. package/dist/motion/subject-motion.d.ts +66 -0
  144. package/dist/motion/subject-motion.js +52 -0
  145. package/dist/motion/subject-motion.js.map +1 -0
  146. package/dist/optics/aperture-diameter.d.ts +47 -0
  147. package/dist/optics/aperture-diameter.js +50 -0
  148. package/dist/optics/aperture-diameter.js.map +1 -0
  149. package/dist/optics/detail-limit.d.ts +182 -0
  150. package/dist/optics/detail-limit.js +336 -0
  151. package/dist/optics/detail-limit.js.map +1 -0
  152. package/dist/optics/generic-lens-lateral-color.d.ts +83 -0
  153. package/dist/optics/generic-lens-lateral-color.js +77 -0
  154. package/dist/optics/generic-lens-lateral-color.js.map +1 -0
  155. package/dist/optics/generic-lens-psf.d.ts +18 -2
  156. package/dist/optics/generic-lens-psf.js +79 -48
  157. package/dist/optics/generic-lens-psf.js.map +1 -1
  158. package/dist/optics/lens-psf-profile.d.ts +7 -0
  159. package/dist/optics/lens-psf-profile.js +2 -1
  160. package/dist/optics/lens-psf-profile.js.map +1 -1
  161. package/dist/optics/scene-to-sensor-irradiance.d.ts +13 -0
  162. package/dist/optics/scene-to-sensor-irradiance.js +7 -0
  163. package/dist/optics/scene-to-sensor-irradiance.js.map +1 -1
  164. package/dist/output/crop-to-match-focal-length.d.ts +62 -0
  165. package/dist/output/crop-to-match-focal-length.js +63 -0
  166. package/dist/output/crop-to-match-focal-length.js.map +1 -0
  167. package/dist/output/developed-lens-corrections.d.ts +19 -5
  168. package/dist/output/developed-lens-corrections.js +30 -11
  169. package/dist/output/developed-lens-corrections.js.map +1 -1
  170. package/dist/output/generic-lens-corrections.d.ts +41 -3
  171. package/dist/output/generic-lens-corrections.js +57 -9
  172. package/dist/output/generic-lens-corrections.js.map +1 -1
  173. package/dist/output/lens-corrections.d.ts +12 -2
  174. package/dist/output/lens-corrections.js +22 -7
  175. package/dist/output/lens-corrections.js.map +1 -1
  176. package/dist/output/print-contrast-reference.js +1 -1
  177. package/dist/output/print-contrast-reference.js.map +1 -1
  178. package/dist/output/print-plan.d.ts +41 -5
  179. package/dist/output/print-plan.js +59 -14
  180. package/dist/output/print-plan.js.map +1 -1
  181. package/dist/output/print-size-blur-noise.d.ts +110 -0
  182. package/dist/output/print-size-blur-noise.js +138 -0
  183. package/dist/output/print-size-blur-noise.js.map +1 -0
  184. package/dist/sensor/binomial-sample.d.ts +3 -0
  185. package/dist/sensor/binomial-sample.js +86 -0
  186. package/dist/sensor/binomial-sample.js.map +1 -0
  187. package/dist/sensor/eqe-electron-rate.js +1 -7
  188. package/dist/sensor/eqe-electron-rate.js.map +1 -1
  189. package/dist/sensor/exposure-window.d.ts +2 -0
  190. package/dist/sensor/exposure-window.js +2 -2
  191. package/dist/sensor/exposure-window.js.map +1 -1
  192. package/dist/sensor/readout-timing.js +2 -23
  193. package/dist/sensor/readout-timing.js.map +1 -1
  194. package/dist/sensor/response-application-compatibility.js +1 -6
  195. package/dist/sensor/response-application-compatibility.js.map +1 -1
  196. package/dist/sensor/responsivity-photocurrent.js +1 -7
  197. package/dist/sensor/responsivity-photocurrent.js.map +1 -1
  198. package/dist/sensor/sensor-characteristics.d.ts +147 -0
  199. package/dist/sensor/sensor-characteristics.js +126 -0
  200. package/dist/sensor/sensor-characteristics.js.map +1 -0
  201. package/dist/sensor/spatial-sample-reduction.js +1 -5
  202. package/dist/sensor/spatial-sample-reduction.js.map +1 -1
  203. package/dist/sensor/spectral-quadrature.js +1 -6
  204. package/dist/sensor/spectral-quadrature.js.map +1 -1
  205. package/dist/sensor/temporal-photo-signal.d.ts +3 -0
  206. package/dist/sensor/temporal-photo-signal.js +5 -2
  207. package/dist/sensor/temporal-photo-signal.js.map +1 -1
  208. package/dist/stabilization/system.d.ts +9 -0
  209. package/dist/stabilization/system.js +5 -6
  210. package/dist/stabilization/system.js.map +1 -1
  211. package/docs/AGENT_GUIDE.md +5 -0
  212. package/docs/API_REFERENCE.md +173 -2
  213. package/docs/QUICK_START.md +213 -6
  214. package/docs/USAGE.md +157 -3
  215. package/docs/api/capture-native-raw-dng.md +6 -0
  216. package/docs/api/core-version.md +1 -1
  217. package/docs/api/equipment-generic-lens-catalogue.md +17 -7
  218. package/docs/api/equipment-sensor-profile-body.md +64 -0
  219. package/docs/api/equipment-sensor-profiles.md +86 -0
  220. package/docs/api/exports.json +357 -2
  221. package/docs/api/facade-display-view-gpu.md +5 -2
  222. package/docs/api/facade-exposure-build-up.md +105 -0
  223. package/docs/api/facade-fast-methods.md +99 -0
  224. package/docs/api/facade-image-plane-enable.md +16 -0
  225. package/docs/api/facade-mixed-illumination.md +67 -0
  226. package/docs/api/facade-representative-light-sources.md +131 -0
  227. package/docs/api/facade-scene-radiance.md +54 -3
  228. package/docs/api/facade-simulate-capture.md +60 -15
  229. package/docs/api/facade-simulate-display-view.md +3 -2
  230. package/docs/api/motion-subject-motion.md +23 -0
  231. package/docs/api/optics-aperture-diameter.md +51 -0
  232. package/docs/api/optics-detail-limit.md +203 -0
  233. package/docs/api/optics-generic-lens-lateral-color.md +79 -0
  234. package/docs/api/output-crop-to-match-focal-length.md +67 -0
  235. package/docs/api/output-developed-lens-corrections.md +10 -1
  236. package/docs/api/output-generic-lens-corrections.md +40 -2
  237. package/docs/api/output-lens-corrections.md +11 -1
  238. package/docs/api/output-print-plan.md +35 -1
  239. package/docs/api/output-print-size-blur-noise.md +115 -0
  240. package/docs/api/sensor-sensor-characteristics.md +105 -0
  241. package/llms.txt +6 -0
  242. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-plane.js","sourceRoot":"","sources":["../../src/facade/image-plane.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * The image-plane scene (2.21, #581): a photo as a flat matte print on the scene plane. Loaded on demand (a dynamic import by\n * the facade) only when a request's scene is `{ kind: \"image-plane\" }`, so a bundle that never prints a photo does not carry\n * it or its lattice data.\n *\n * **From pixel to reflectance** (docs/IMAGE_PLANE.md):\n *\n * 1. Decode to linear sRGB: `srgb-8` and `srgb-16` through the sRGB transfer function (IEC 61966-2-1, the piecewise EOTF)\n * evaluated with the portable power (`portablePow`, within 1 ulp, the same bits in every JavaScript engine); `linear-srgb`\n * as given, clipped to [0, 1]. A pixel with alpha a is composited over the paper in linear light: c' = a·c + (1 − a).\n * 2. The print reflectance lattice: 5 × 5 × 5 nodes at the sRGB code values 0, 1/4, 1/2, 3/4, 1 per channel (their linear\n * values L₀…L₄). The node spectra on the neutral axis are flat (the node's linear value); the other 120 are Photivra's own\n * LHTSS fits (S. A. Burns, arXiv:1710.05732 v5, \"Least Hyperbolic Tangent Slope Squared (LHTSS) Method\", pp. 24–26), each\n * reproducing its node's sRGB under CIE D65 with the CIE 1931 2° observer (scripts/fit-image-plane-lattice.mjs), stored at\n * 10 nm over 380–780 nm in 16 bits and linearly interpolated between samples. A pixel's spectrum is the trilinear\n * interpolation, in linear sRGB, of the spectra of the eight nodes of its cell: a convex combination of spectra in [0, 1],\n * so it lies in [0, 1], and, XYZ being linear in the spectrum, it reproduces the pixel's sRGB under D65 to the nodes' own\n * residual (measured by the fit: CIEDE2000 at most 6.4·10⁻⁴ over a 17³ grid of sRGB codes).\n * 3. The paper: ρ = ρ_black + (ρ_white − ρ_black)·ρ_lattice, affine and so still bounded; defaults 0.90 and 0.01.\n * 4. Between pixel centers (`bilinear`, the default): the pixels' spectra weighted bilinearly, which under D65 is the bilinear\n * interpolation of the pixels' linear sRGB; `nearest` takes the pixel under the point. The print's edge pixels extend to\n * its edges (clamp to edge).\n *\n * Print-local coordinates are the chart's (cu = ±1 at the left and right edges, cv up, ±aspect at the top and bottom); the\n * pixel coordinates are X = (cu + 1)·W/2 and Y = (aspect − cv)·H/(2·aspect), with pixel centers at half-integers.\n */\n\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport { portablePow } from \"../core/portable-math.js\";\nimport { FULL_RESOLUTION_CEILING_PIXELS, FULL_RESOLUTION_DEFAULT_PIXELS, resolveRaisedLimit } from \"../core/pixel-limits.js\";\nimport { IMAGE_PLANE_LATTICE_CODES } from \"./image-plane-lattice-data.js\";\nimport { CHART_SIZE_DEFAULT_SURROUND_REFLECTANCE, resolveChartSizeOption, type ImagePlaneSignalScene, type ImagePlaneSpectralNodes, type ResolvedImagePlaneScene } from \"./scene-radiance.js\";\n\n/** Version of the print reflectance lattice and its data; a change to any node spectrum changes it. */\nexport const IMAGE_PLANE_LATTICE_VERSION = \"1.0.0\";\n/** Engine defaults of an image-plane scene. */\nexport const IMAGE_PLANE_DEFAULTS = /* @__PURE__ */ Object.freeze({ paperWhiteReflectance: 0.9, paperBlackReflectance: 0.01, interpolation: \"bilinear\" as const });\n\n/** Host bytes of the per-pixel signal rows a signal scene keeps (the direct path's query points revisit nearby pixels). */\nconst SIGNAL_ROW_CACHE_BYTES = 32 << 20;\nconst AXIS = 5, NODES = 125, SAMPLES = 41, MINIMUM_NM = 380, STEP_NM = 10, MAXIMUM_NM = MINIMUM_NM + STEP_NM * (SAMPLES - 1);\n\n/** The sRGB EOTF with the portable power. */\nfunction decodeSrgb(encoded: number): number {\n return encoded <= 0.04045 ? encoded / 12.92 : portablePow((encoded + 0.055) / 1.055, 2.4);\n}\n/** The lattice's node levels in linear sRGB. */\nconst LEVELS = /* @__PURE__ */ Float64Array.from({ length: AXIS }, (_, k) => (k === 0 ? 0 : k === AXIS - 1 ? 1 : decodeSrgb(k / (AXIS - 1))));\n\nlet nodeSpectra: Float64Array | null = null;\n/** The 125 node spectra, 41 samples each (node index r·25 + g·5 + b), decoded once from the data module. */\nfunction spectra(): Float64Array {\n if (nodeSpectra) return nodeSpectra;\n const out = new Float64Array(NODES * SAMPLES), rows = IMAGE_PLANE_LATTICE_CODES.split(\";\");\n if (rows.length !== NODES - AXIS) throw new InvalidConfigurationError(\"The image-plane lattice data is damaged.\");\n let row = 0;\n for (let node = 0; node < NODES; node++) {\n const r = Math.floor(node / 25), g = Math.floor(node / 5) % 5, b = node % 5;\n if (r === g && g === b) { out.fill(LEVELS[r]!, node * SAMPLES, (node + 1) * SAMPLES); continue; }\n const deltas = rows[row++]!.split(\",\");\n if (deltas.length !== SAMPLES) throw new InvalidConfigurationError(\"The image-plane lattice data is damaged.\");\n let code = 0;\n for (let i = 0; i < SAMPLES; i++) {\n code += parseInt(deltas[i]!, 36);\n if (!(code >= 0 && code <= 65535)) throw new InvalidConfigurationError(\"The image-plane lattice data is damaged.\");\n out[node * SAMPLES + i] = code / 65535;\n }\n }\n return (nodeSpectra = out);\n}\n\n/** Internal (for tests and docs): the node spectra as 125 rows of 41 reflectances at 380, 390, …, 780 nm. */\nexport function imagePlaneLatticeSpectra(): { levels: readonly number[]; wavelengthsNm: readonly number[]; spectra: readonly Float64Array[] } {\n const all = spectra();\n return { levels: Array.from(LEVELS), wavelengthsNm: Array.from({ length: SAMPLES }, (_, i) => MINIMUM_NM + STEP_NM * i),\n spectra: Array.from({ length: NODES }, (_, k) => all.slice(k * SAMPLES, (k + 1) * SAMPLES)) };\n}\n\n/** Every node's reflectance at one wavelength (the samples linearly interpolated). */\nfunction nodeReflectancesAt(nm: number): Float64Array {\n if (typeof nm !== \"number\" || !(nm >= MINIMUM_NM && nm <= MAXIMUM_NM)) throw new InvalidConfigurationError(\"An image-plane print is defined on \" + MINIMUM_NM + \"–\" + MAXIMUM_NM + \" nm.\");\n const all = spectra(), p = (nm - MINIMUM_NM) / STEP_NM, i = Math.min(SAMPLES - 2, Math.floor(p)), f = p - i, out = new Float64Array(NODES);\n for (let k = 0; k < NODES; k++) out[k] = all[k * SAMPLES + i]! * (1 - f) + all[k * SAMPLES + i + 1]! * f;\n return out;\n}\n\n/** The image's size, validated (the facade needs the aspect before the print's placement). */\nexport function readImagePlaneSize(value: unknown): { width: number; height: number } {\n if (typeof value !== \"object\" || value === null) throw new InvalidConfigurationError(\"scene must be an object.\");\n const image = (value as { image?: unknown }).image;\n if (typeof image !== \"object\" || image === null) throw new InvalidConfigurationError(\"An image-plane scene needs image { width, height, channels, encoding, data }.\");\n const { width, height } = image as Record<string, unknown>;\n for (const [name, v] of [[\"width\", width], [\"height\", height]] as const)\n if (typeof v !== \"number\" || !Number.isSafeInteger(v) || v < 1 || v > 65_536) throw new InvalidConfigurationError(\"scene.image.\" + name + \" must be an integer from 1 to 65536.\");\n return { width: width as number, height: height as number };\n}\n\n/**\n * Validates an image-plane scene and prepares it on a print of aspect `aspect` (height / width): the digest of its data, the\n * count of clipped `linear-srgb` samples, and the decoders. The data is borrowed (read on every lookup, never written).\n */\nexport async function resolveImagePlaneScene(value: unknown, aspect: number,\n assume?: (id: string, kind: \"default\" | \"model\" | \"derived\", value: unknown, explanation: string) => void): Promise<ResolvedImagePlaneScene> {\n const record = value as Record<string, unknown>;\n for (const key of Object.keys(record)) if (![\"kind\", \"sceneId\", \"image\", \"paper\", \"interpolation\", \"maximumPixels\"].includes(key)) throw new InvalidConfigurationError(\"Unknown scene field: \" + key + \".\");\n if (typeof record.sceneId !== \"string\" || !/^[A-Za-z0-9][A-Za-z0-9._:-]{0,63}$/.test(record.sceneId)) throw new InvalidConfigurationError(\"An image-plane scene needs a public sceneId.\");\n const { width, height } = readImagePlaneSize(record);\n const image = record.image as Record<string, unknown>;\n for (const key of Object.keys(image)) if (![\"width\", \"height\", \"channels\", \"encoding\", \"data\"].includes(key)) throw new InvalidConfigurationError(\"Unknown scene.image field: \" + key + \".\");\n const maximumPixels = resolveRaisedLimit(record.maximumPixels, FULL_RESOLUTION_DEFAULT_PIXELS, FULL_RESOLUTION_CEILING_PIXELS,\n \"scene.maximumPixels must be an integer from 1 to \" + FULL_RESOLUTION_CEILING_PIXELS + \".\");\n if (width * height > maximumPixels) throw new InvalidConfigurationError(\"The image has \" + width * height + \" pixels, above scene.maximumPixels (\" + maximumPixels + \").\");\n const channelsValue = image.channels, encoding = image.encoding, data = image.data;\n if (channelsValue !== 3 && channelsValue !== 4) throw new InvalidConfigurationError(\"scene.image.channels must be 3 (RGB) or 4 (RGBA).\");\n const typeOk = encoding === \"srgb-8\" ? data instanceof Uint8Array || data instanceof Uint8ClampedArray : encoding === \"srgb-16\" ? data instanceof Uint16Array :\n encoding === \"linear-srgb\" ? data instanceof Float32Array : undefined;\n if (typeOk === undefined) throw new InvalidConfigurationError(\"scene.image.encoding must be \\\"srgb-8\\\", \\\"srgb-16\\\" or \\\"linear-srgb\\\".\");\n if (!typeOk) throw new InvalidConfigurationError(\"scene.image.data must be a \" + (encoding === \"srgb-8\" ? \"Uint8Array or Uint8ClampedArray\" : encoding === \"srgb-16\" ? \"Uint16Array\" : \"Float32Array\") + \" for \" + encoding + \".\");\n const channels: 3 | 4 = channelsValue;\n const samples = data as Uint8Array | Uint8ClampedArray | Uint16Array | Float32Array;\n if (samples.length !== width * height * channels) throw new InvalidConfigurationError(\"scene.image.data must hold width × height × channels = \" + width * height * channels + \" samples.\");\n const paperRecord = record.paper;\n if (paperRecord !== undefined && (typeof paperRecord !== \"object\" || paperRecord === null)) throw new InvalidConfigurationError(\"scene.paper must be an object.\");\n const paper = (paperRecord ?? {}) as Record<string, unknown>;\n for (const key of Object.keys(paper)) if (key !== \"whiteReflectance\" && key !== \"blackReflectance\") throw new InvalidConfigurationError(\"Unknown scene.paper field: \" + key + \".\");\n const whiteValue = paper.whiteReflectance ?? IMAGE_PLANE_DEFAULTS.paperWhiteReflectance, blackValue = paper.blackReflectance ?? IMAGE_PLANE_DEFAULTS.paperBlackReflectance;\n if (typeof whiteValue !== \"number\" || typeof blackValue !== \"number\" || !(blackValue >= 0 && blackValue < whiteValue && whiteValue <= 1))\n throw new InvalidConfigurationError(\"scene.paper needs reflectances 0 ≤ blackReflectance < whiteReflectance ≤ 1.\");\n const white: number = whiteValue, black: number = blackValue;\n const interpolation = record.interpolation ?? IMAGE_PLANE_DEFAULTS.interpolation;\n if (interpolation !== \"bilinear\" && interpolation !== \"nearest\") throw new InvalidConfigurationError(\"scene.interpolation must be \\\"bilinear\\\" or \\\"nearest\\\".\");\n if (typeof aspect !== \"number\" || !(aspect > 0) || !Number.isFinite(aspect)) throw new InvalidConfigurationError(\"The print's aspect must be positive.\");\n // Linear input: every sample finite; those outside [0, 1] are clipped and counted.\n let clipped = 0;\n if (encoding === \"linear-srgb\") for (let i = 0; i < samples.length; i++) {\n const v = samples[i]!;\n if (!Number.isFinite(v)) throw new InvalidConfigurationError(\"scene.image.data must be finite (sample \" + i + \").\");\n if (v < 0 || v > 1) clipped++;\n }\n const subtle = globalThis.crypto?.subtle;\n if (!subtle) throw new InvalidConfigurationError(\"An image-plane scene needs crypto.subtle (a secure browser context or Node 22+) to digest the image.\");\n const view = new Uint8Array(samples.buffer, samples.byteOffset, samples.byteLength);\n const digest = new Uint8Array(await subtle.digest(\"SHA-256\", (samples.buffer instanceof ArrayBuffer ? view : view.slice()) as Uint8Array<ArrayBuffer>));\n const dataSha256 = Array.from(digest, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n\n // Decoders: a table per integer encoding (the transfer function once per code), the clip for linear samples.\n const scale = encoding === \"srgb-8\" ? 255 : encoding === \"srgb-16\" ? 65535 : 1;\n const table = encoding === \"linear-srgb\" ? null : Float64Array.from({ length: scale + 1 }, (_, code) => decodeSrgb(code / scale));\n const color = table ? (i: number): number => table[samples[i]!]! : (i: number): number => { const v = samples[i]!; return v <= 0 ? 0 : v >= 1 ? 1 : v; };\n const alpha = channels === 3 ? null : encoding === \"linear-srgb\" ? color : (i: number): number => samples[i]! / scale;\n const rgb = new Float64Array(3), span = white - black;\n const cellOf = (v: number): number => (v > LEVELS[3]! ? 3 : v > LEVELS[2]! ? 2 : v > LEVELS[1]! ? 1 : 0);\n const fractions = new Float64Array(3);\n /** One pixel's lattice cell (its base node, returned) and its fractions in the cell (into `out`). */\n function pixelLattice(index: number, out: Float64Array): number {\n const base = index * channels;\n if (alpha) {\n const a = alpha(base + 3);\n for (let c = 0; c < 3; c++) rgb[c] = a * color(base + c) + (1 - a);\n } else for (let c = 0; c < 3; c++) rgb[c] = color(base + c);\n const kr = cellOf(rgb[0]!), kg = cellOf(rgb[1]!), kb = cellOf(rgb[2]!);\n out[0] = (rgb[0]! - LEVELS[kr]!) / (LEVELS[kr + 1]! - LEVELS[kr]!); out[1] = (rgb[1]! - LEVELS[kg]!) / (LEVELS[kg + 1]! - LEVELS[kg]!); out[2] = (rgb[2]! - LEVELS[kb]!) / (LEVELS[kb + 1]! - LEVELS[kb]!);\n return kr * 25 + kg * 5 + kb;\n }\n /** One pixel in node values: the trilinear weights of its linear sRGB in the lattice cell, then the paper. */\n function pixelValue(index: number, nodeValues: Float64Array, neutral: number): number {\n const n = pixelLattice(index, fractions), fr = fractions[0]!, fg = fractions[1]!, fb = fractions[2]!;\n const lattice = (1 - fr) * ((1 - fg) * ((1 - fb) * nodeValues[n]! + fb * nodeValues[n + 1]!) + fg * ((1 - fb) * nodeValues[n + 5]! + fb * nodeValues[n + 6]!)) +\n fr * ((1 - fg) * ((1 - fb) * nodeValues[n + 25]! + fb * nodeValues[n + 26]!) + fg * ((1 - fb) * nodeValues[n + 30]! + fb * nodeValues[n + 31]!));\n return black * neutral + span * lattice;\n }\n const halfW = width / 2, halfH = height / (2 * aspect);\n /** The print at a print-local point from a per-pixel value: bilinear between pixel centers (clamped to the edge) or the nearest pixel. */\n function interpolate(cu: number, cv: number, at: (index: number) => number): number {\n const X = (cu + 1) * halfW, Y = (aspect - cv) * halfH;\n if (interpolation === \"nearest\") return at(Math.min(height - 1, Math.max(0, Math.floor(Y))) * width + Math.min(width - 1, Math.max(0, Math.floor(X))));\n const sx = X - 0.5, sy = Y - 0.5, i0 = Math.floor(sx), j0 = Math.floor(sy), fx = sx - i0, fy = sy - j0;\n const ia = Math.min(width - 1, Math.max(0, i0)), ib = Math.min(width - 1, Math.max(0, i0 + 1));\n const ja = Math.min(height - 1, Math.max(0, j0)) * width, jb = Math.min(height - 1, Math.max(0, j0 + 1)) * width;\n return (1 - fy) * ((1 - fx) * at(ja + ia) + fx * at(ja + ib)) + fy * ((1 - fx) * at(jb + ia) + fx * at(jb + ib));\n }\n const sampleAt = (cu: number, cv: number, nodeValues: Float64Array, neutral: number): number => interpolate(cu, cv, (index) => pixelValue(index, nodeValues, neutral));\n // Per wavelength the node reflectances (the facade asks for a few spectral nodes many times).\n const atWavelength = new Map<number, Float64Array>();\n function reflectanceAt(cu: number, cv: number, nm: number): number {\n let nodes = atWavelength.get(nm);\n if (!nodes) { nodes = nodeReflectancesAt(nm); if (atWavelength.size < 4096) atWavelength.set(nm, nodes); }\n return sampleAt(cu, cv, nodes, 1);\n }\n /**\n * One pixel's channel signals, integrated from its reconstructed spectrum (owner decision 2026-11-09): per spectral node n its\n * reflectance ρ_n (its cell's eight node spectra at λ_n blended with the trilinear weights, then the paper) times the white\n * radiance W_n, then per channel Σ_n A_c(λ_n)·ρ_n·W_n. Written to out[at..at + 2].\n */\n function pixelSignals(index: number, nodes: ImagePlaneSpectralNodes, out: Float64Array, at: number): void {\n const N = nodes.count, R = nodes.nodeSpectra, W = nodes.whiteRadiance, A0 = nodes.response[0]!, A1 = nodes.response[1]!, A2 = nodes.response[2]!;\n const base = pixelLattice(index, fractions) * N, fr = fractions[0]!, fg = fractions[1]!, fb = fractions[2]!, gb = 1 - fb;\n const a00 = (1 - fr) * (1 - fg), a01 = (1 - fr) * fg, a10 = fr * (1 - fg), a11 = fr * fg;\n const w0 = a00 * gb, w1 = a00 * fb, w5 = a01 * gb, w6 = a01 * fb, w25 = a10 * gb, w26 = a10 * fb, w30 = a11 * gb, w31 = a11 * fb;\n let s0 = 0, s1 = 0, s2 = 0;\n for (let n = 0, k = base; n < N; n++, k++) {\n const lattice = w0 * R[k]! + w1 * R[k + N]! + w5 * R[k + 5 * N]! + w6 * R[k + 6 * N]! + w25 * R[k + 25 * N]! + w26 * R[k + 26 * N]! + w30 * R[k + 30 * N]! + w31 * R[k + 31 * N]!;\n // Each channel's sum in node order (one pass over the spectrum).\n const radiance = (black + span * lattice) * W[n]!;\n s0 += A0[n]! * radiance; s1 += A1[n]! * radiance; s2 += A2[n]! * radiance;\n }\n out[at] = s0; out[at + 1] = s1; out[at + 2] = s2;\n }\n function signalScene(wavelengths: readonly number[], perNode: readonly Float64Array[], whiteRadiance: Float64Array, radianceAt: (u: number, v: number, nm: number) => number,\n scale: number, half: number, surroundReflectance: number): ImagePlaneSignalScene {\n // The lattice's spectra at the nodes (node k's reflectance at λ_n at k·N + n); no channel response is folded in.\n const N = wavelengths.length, spectraAt = wavelengths.map((nm) => nodeReflectancesAt(nm)), nodeSpectra = new Float64Array(NODES * N);\n for (let k = 0; k < NODES; k++) for (let n = 0; n < N; n++) nodeSpectra[k * N + n] = spectraAt[n]![k]!;\n const nodes: ImagePlaneSpectralNodes = { count: N, nodeSpectra, whiteRadiance, response: perNode };\n // The surround's channel signals, integrated from its spectrum ρ·W_n like a pixel's (no white-integral shortcut, 2.21.0).\n const surround = [0, 1, 2].map((c) => { let s = 0; for (let n = 0; n < N; n++) s += perNode[c]![n]! * (surroundReflectance * whiteRadiance[n]!); return s; }) as [number, number, number];\n // The pixels' signals as the query points reach them: rows of three values per pixel (NaN until computed), the latest rows kept.\n const rows = new Map<number, Float64Array>(), keptRows = Math.max(8, Math.floor(SIGNAL_ROW_CACHE_BYTES / (width * 24)));\n let lastJ = -1, lastRow: Float64Array = new Float64Array(0);\n const rowAt = (j: number): Float64Array => {\n if (j === lastJ) return lastRow;\n let row = rows.get(j);\n if (!row) { row = new Float64Array(width * 3).fill(NaN); rows.set(j, row); if (rows.size > keptRows) rows.delete(rows.keys().next().value!); }\n lastJ = j; lastRow = row;\n return row;\n };\n const signalOf = (row: Float64Array, j: number, i: number, c: number): number => {\n if (row[i * 3] !== row[i * 3]) pixelSignals(j * width + i, nodes, row, i * 3);\n return row[i * 3 + c]!;\n };\n return { kind: \"radiance\", radianceAt, signalAt(u: number, v: number, c: number): number {\n const cu = u * scale / half, cv = v * scale / half;\n if (!(Math.abs(cu) <= 1 && Math.abs(cv) <= aspect)) return surround[c]!;\n // As `interpolate`, reading the pixels' signals.\n const X = (cu + 1) * halfW, Y = (aspect - cv) * halfH;\n if (interpolation === \"nearest\") { const j = Math.min(height - 1, Math.max(0, Math.floor(Y))); return signalOf(rowAt(j), j, Math.min(width - 1, Math.max(0, Math.floor(X))), c); }\n const sx = X - 0.5, sy = Y - 0.5, i0 = Math.floor(sx), j0 = Math.floor(sy), fx = sx - i0, fy = sy - j0;\n const ia = Math.min(width - 1, Math.max(0, i0)), ib = Math.min(width - 1, Math.max(0, i0 + 1)), ja = Math.min(height - 1, Math.max(0, j0)), jb = Math.min(height - 1, Math.max(0, j0 + 1));\n const rowA = rowAt(ja), a0 = signalOf(rowA, ja, ia, c), a1 = signalOf(rowA, ja, ib, c), rowB = rowAt(jb);\n return (1 - fy) * ((1 - fx) * a0 + fx * a1) + fy * ((1 - fx) * signalOf(rowB, jb, ia, c) + fx * signalOf(rowB, jb, ib, c));\n }, image: { scene: resolved, nodes, surround, whiteRadiance, surroundReflectance } };\n }\n const resolved: ResolvedImagePlaneScene = Object.freeze({ kind: \"image-plane\" as const, sceneId: record.sceneId, width, height, aspect, channels, encoding: encoding as ResolvedImagePlaneScene[\"encoding\"],\n interpolation, paperWhiteReflectance: white, paperBlackReflectance: black, maximumPixels, clippedSampleCount: clipped, dataSha256,\n reflectanceAt, sampleAt, pixelValue, pixelSignals, pixelLattice, nodeReflectances: nodeReflectancesAt, signalScene, get digestForm() { return imagePlaneDigestForm(resolved); }, parameters: Object.freeze({ width, height, channels, encoding, interpolation, paperWhiteReflectance: white, paperBlackReflectance: black,\n clippedSampleCount: clipped, imageSha256: dataSha256 }) });\n if (assume) for (const [id, kind, v, explanation] of imagePlaneAssumptions(resolved, record)) assume(id, kind, v, explanation);\n return resolved;\n}\n\n/** The scene's form in the facade's source digest: the image's SHA-256 and shape, the paper, the interpolation and the lattice version. */\nexport function imagePlaneDigestForm(scene: ResolvedImagePlaneScene): Record<string, unknown> {\n return { kind: scene.kind, sceneId: scene.sceneId, image: { width: scene.width, height: scene.height, channels: scene.channels, encoding: scene.encoding, sha256: scene.dataSha256 },\n paper: { whiteReflectance: scene.paperWhiteReflectance, blackReflectance: scene.paperBlackReflectance }, interpolation: scene.interpolation, latticeVersion: IMAGE_PLANE_LATTICE_VERSION };\n}\n\n/** The assumptions an image-plane capture records: the model, the defaults taken, and the clipped linear samples. */\nexport function imagePlaneAssumptions(scene: ResolvedImagePlaneScene, record: Record<string, unknown>): [string, \"default\" | \"model\" | \"derived\", unknown, string][] {\n const out: [string, \"default\" | \"model\" | \"derived\", unknown, string][] = [];\n const paper = (record.paper ?? {}) as Record<string, unknown>;\n if (paper.whiteReflectance === undefined) out.push([\"scene.paper.whiteReflectance\", \"default\", scene.paperWhiteReflectance,\n \"Photivra's assumption, not a measurement: the paper reflects 90 % (the white of the engine's Studio Gray 1 patch), so sRGB white prints as a 0.90 flat reflectance.\"]);\n if (paper.blackReflectance === undefined) out.push([\"scene.paper.blackReflectance\", \"default\", scene.paperBlackReflectance,\n \"Photivra's assumption, not a measurement: the deepest ink reflects 1 % (an optical density of 2.0), so sRGB black prints as a 0.01 flat reflectance.\"]);\n if (record.interpolation === undefined) out.push([\"scene.interpolation\", \"default\", scene.interpolation,\n \"Bilinear between pixel centers: the four nearest pixels' reflectance spectra, bilinearly weighted (under CIE D65, the bilinear interpolation of their linear sRGB); the edge pixels extend to the print's edges.\"]);\n out.push([\"scene.imagePlane\", \"model\", { latticeVersion: IMAGE_PLANE_LATTICE_VERSION, nodesPerAxis: AXIS, method: \"lhtss-burns-2020\", wavelengthStepNanometers: STEP_NM,\n width: scene.width, height: scene.height, encoding: scene.encoding, channels: scene.channels },\n \"An approximation: a print of the image, which was already processed, clipped and blurred by the camera that took it. Each pixel is decoded to linear sRGB \" +\n (scene.encoding === \"linear-srgb\" ? \"(given linear, clipped to [0, 1])\" : \"with the sRGB transfer function (IEC 61966-2-1)\") + (scene.channels === 4 ? \", composited over the paper by its alpha,\" : \"\") +\n \" and becomes a reflectance spectrum by trilinear interpolation in a 5 × 5 × 5 lattice of smooth spectra (Burns' LHTSS method, arXiv:1710.05732 v5, fitted by Photivra against CIE D65 and the \" +\n \"CIE 1931 2° observer), which reproduces the pixel's sRGB under D65 within CIEDE2000 6.4e-4 and stays in [0, 1]; then ρ = black + (white − black)·ρ. Under other lights its colors are one plausible \" +\n \"metamer of many (docs/IMAGE_PLANE.md, measured spread). A flat matte Lambertian print: no gloss, paper texture, halftone, curl or fluorescence.\"]);\n out.push([\"scene.digest\", \"model\", \"image-data-hashed\", \"The source digest covers the image's SHA-256, size, channels and encoding, the paper, the interpolation, the lattice version and the framing.\"]);\n if (scene.clippedSampleCount > 0) out.push([\"scene.image.clippedSamples\", \"derived\", scene.clippedSampleCount,\n \"Linear samples outside [0, 1] clipped to the print's range (a print cannot be brighter than its paper or darker than its deepest ink).\"]);\n return out;\n}\n\n/** The GPU display view's image-plane module, loaded on demand by the GPU renderer (its own chunk). */\nexport function loadGpuModule(): Promise<typeof import(\"../gpu/display-view-image-material-module.js\")> {\n return import(\"../gpu/display-view-image-material-module.js\");\n}\n\n/**\n * The print's placement: `chartSize` with its height defaulting to the image's aspect, or, without it, the print fitted inside\n * the frame (centered, filling its width or height) on the default surround; records the defaults it takes.\n */\nexport function imagePlanePrint(scene: unknown, chartSize: unknown, framedWidthM: number, frameAspect: number,\n assume: (id: string, kind: \"default\", value: unknown, explanation: string) => void): ReturnType<typeof resolveChartSizeOption> {\n const size = readImagePlaneSize(scene), imageAspect = size.height / size.width;\n if (chartSize !== undefined) {\n const resolved = resolveChartSizeOption(chartSize, imageAspect);\n if (resolved.defaulted.includes(\"heightM\")) assume(\"chartSize.heightM\", \"default\", resolved.heightM, \"The print has the image's shape: height = width × image height / image width.\");\n return { ...resolved, defaulted: resolved.defaulted.filter((key) => key !== \"heightM\") };\n }\n const widthM = imageAspect > frameAspect ? framedWidthM * frameAspect / imageAspect : framedWidthM;\n const fitted = { widthM, heightM: widthM * imageAspect, surroundReflectance: CHART_SIZE_DEFAULT_SURROUND_REFLECTANCE, defaulted: [] as (\"heightM\" | \"surroundReflectance\")[] };\n assume(\"chartSize\", \"default\", { widthM: fitted.widthM, heightM: fitted.heightM, surroundReflectance: fitted.surroundReflectance },\n \"The print has the image's shape and is fitted inside the frame, centered (it fills the frame's width or height), on an 18 % neutral gray surround.\");\n return fitted;\n}\n"]}
@@ -0,0 +1,108 @@
1
+ import { type CaptureIlluminant, type ResolvedCaptureIlluminant } from "./scene-radiance.js";
2
+ /** Most sources an `illumination` may list. */
3
+ export declare const MIXED_ILLUMINATION_MAX_SOURCES = 8;
4
+ /** Most regions a `regions` blend may list. */
5
+ export declare const MIXED_ILLUMINATION_MAX_REGIONS = 64;
6
+ /** One light source of a mixed illumination: an illuminant (as `simulateCapture` `illuminant` takes it) at an illuminance. */
7
+ export interface MixedIlluminationSource {
8
+ illuminant: CaptureIlluminant;
9
+ /** Illuminance this source alone gives where its weight is 1, lux, (0, 1e7]. */
10
+ illuminanceLux: number;
11
+ }
12
+ /**
13
+ * 2.22 (#550): a point light on the scene plane's front side: an illuminant spectrum, a position in metres (`xM`, `yM` on the plane
14
+ * from the optical axis, +x right and +y up as seen from the camera; `heightM` > 0 in front of the plane, toward the camera) and an
15
+ * intensity, either in candela or as the illuminance it gives at normal incidence at a reference distance (I = E·r²).
16
+ */
17
+ export interface MixedIlluminationPointSource {
18
+ illuminant: CaptureIlluminant;
19
+ position: {
20
+ xM: number;
21
+ yM: number;
22
+ heightM: number;
23
+ };
24
+ intensity: {
25
+ candela: number;
26
+ } | {
27
+ illuminanceLux: number;
28
+ distanceM: number;
29
+ };
30
+ }
31
+ /** A point in chart coordinates (see {@link MixedIllumination}). */
32
+ export interface MixedIlluminationPoint {
33
+ u: number;
34
+ v: number;
35
+ }
36
+ /**
37
+ * How the sources blend across the chart. `linear-gradient` and `radial` map a point to a position t in [0, 1] (its projection
38
+ * onto `from` → `to`, clamped; or its distance from `center` over `radius`, clamped) and crossfade linearly between consecutive
39
+ * sources at their `stops` (one per source, non-decreasing in [0, 1]; default evenly spaced from 0 to 1): source 0 alone up to
40
+ * stops[0], the last source alone from its stop on, and two equal stops a hard edge (the later source from the stop on).
41
+ * `regions` gives each point the source of the first rectangle that contains it (bounds inclusive) and `outsideSource` elsewhere.
42
+ */
43
+ export type MixedIlluminationBlend = {
44
+ kind: "linear-gradient";
45
+ from: MixedIlluminationPoint;
46
+ to: MixedIlluminationPoint;
47
+ stops?: readonly number[];
48
+ } | {
49
+ kind: "radial";
50
+ center?: MixedIlluminationPoint;
51
+ radius: number;
52
+ stops?: readonly number[];
53
+ } | {
54
+ kind: "regions";
55
+ regions: readonly {
56
+ source: number;
57
+ uMin: number;
58
+ uMax: number;
59
+ vMin: number;
60
+ vMax: number;
61
+ }[];
62
+ outsideSource: number;
63
+ };
64
+ /**
65
+ * 2.22 (#550), `simulateCapture` `illumination`: sources blended across the chart and point sources with inverse-square falloff
66
+ * (docs/MIXED_ILLUMINATION.md). It replaces `illuminant` and `illuminanceLux`. `sources` lists 1 to 8 sources (with two or more, a
67
+ * `blend` is required; one lights the whole plane); `points` lists 1 to 8 point sources; a request needs two or more sources or at least one point. Blend
68
+ * coordinates are chart-local with `chartSize` and frame units without it; (0, 0) is the frame center.
69
+ */
70
+ export interface MixedIllumination {
71
+ sources?: readonly MixedIlluminationSource[];
72
+ blend?: MixedIlluminationBlend;
73
+ points?: readonly MixedIlluminationPointSource[];
74
+ }
75
+ /** Internal: a validated mixed illumination with its lights resolved and scaled. */
76
+ export interface ResolvedMixedIllumination {
77
+ /**
78
+ * The lights, the blend's sources first and then the point sources: each with the illuminance it gives at the frame center when
79
+ * it lights it alone (a point source's I·cos θ/d²) and the scale k with k·S(λ) that light's irradiance there; `report` is its
80
+ * public form (the assumption's and the digest's).
81
+ */
82
+ sources: readonly {
83
+ illuminant: ResolvedCaptureIlluminant;
84
+ option: CaptureIlluminant;
85
+ illuminanceLux: number;
86
+ irradianceScale: number;
87
+ report: Readonly<Record<string, unknown>>;
88
+ }[];
89
+ /** The blend with its defaults filled, or null (one source or none). */
90
+ blend: Readonly<Record<string, unknown>> | null;
91
+ /** Spectral irradiance at a plane point, W·m⁻²·nm⁻¹: (u, v) chart coordinates for the blend, (xM, yM) metres for the point sources. */
92
+ irradianceAt(u: number, v: number, xM: number, yM: number, wavelengthNanometers: number): number;
93
+ /**
94
+ * At the frame center: the illuminance, the blend's source weights, each light's illuminance there (w_i·E_i; a point's
95
+ * I·cos θ/d²) and the strongest light (the largest, the first on a tie; an index into `sources`).
96
+ */
97
+ center: {
98
+ illuminanceLux: number;
99
+ weights: number[];
100
+ illuminancesLux: number[];
101
+ strongestSource: number;
102
+ };
103
+ }
104
+ /**
105
+ * Internal: validates `illumination` and resolves its sources with `resolveIlluminant` (the capture's `resolveCaptureIlluminant`, or
106
+ * the display view's portable one).
107
+ */
108
+ export declare function resolveMixedIllumination(value: unknown, resolveIlluminant: (value: CaptureIlluminant) => ResolvedCaptureIlluminant): ResolvedMixedIllumination;
@@ -0,0 +1,174 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ /**
3
+ * 2.22 (#550): spatially varying illumination of the scene plane (mixed lighting), loaded on demand by `simulateCapture` and the
4
+ * display view only when a request has `illumination`, so requests without it neither load nor run it.
5
+ *
6
+ * Model: N sources (1 to {@link MIXED_ILLUMINATION_MAX_SOURCES}; one lights the whole plane), source i an illuminant spectral shape S_i(λ) scaled to
7
+ * `illuminanceLux` E_i exactly as the single illuminant is (`calculateIlluminantIrradianceScale`: k_i with 683 ∫ k_i S_i ȳ dλ = E_i).
8
+ * The plane's spectral irradiance at a point p is the declared blend E(p, λ) = Σ_i w_i(p)·k_i·S_i(λ) with weights w_i(p) ≥ 0 that
9
+ * sum to 1, so the illuminance at p is Σ_i w_i(p)·E_i and, where one weight is 1, the light is exactly that source's. A Lambertian
10
+ * reflector then has radiance ρ(λ)·E(p, λ)/π, as under one illuminant. The blend is a declared crossfade of irradiance, not a
11
+ * model of how light falls off from a lamp or a window (no inverse-square law, no cosine falloff, no shadows); it is exact for
12
+ * what it declares.
13
+ *
14
+ * Point sources (owner decision 2026-11-10, a step toward flash): source j is a point at height h_j in front of the plane above
15
+ * plane point (x_j, y_j) m, with luminous intensity I_j cd (the same in every direction toward the plane) and spectral shape S_j(λ),
16
+ * scaled so that 683 ∫ c_j S_j ȳ dλ = I_j. A point p of the plane at distance d from it receives E_j(p, λ) = c_j·S_j(λ)·cos θ/d²,
17
+ * with cos θ = h_j/d: the inverse-square law with Lambert's cosine law, which follows from the definitions of luminous intensity
18
+ * (flux per solid angle) and illuminance (flux per area) with the solid angle dΩ = dA·cos θ/d² that a plane element subtends (CIE S
19
+ * 017:2020 ILV, International Lighting Vocabulary, entries "luminous intensity" and "illuminance", free at e-ilv.cie.co.at; BIPM SI
20
+ * Brochure, 9th edition 2019, Table 4, the steradian). Exact for an ideal isotropic point; no occlusion (the camera casts no shadow),
21
+ * no source size and no inter-reflection. The point sources add to the blend: E(p, λ) = Σ_i w_i(p)·k_i·S_i(λ) + Σ_j E_j(p, λ).
22
+ *
23
+ * Coordinates are the chart's: a fixed-size chart's chart-local units (±1 at its left and right edges, v up on the same scale,
24
+ * extended linearly over the surround), or, without `chartSize`, frame units (±1 at the frame's left and right edges), which are
25
+ * the chart-local units of a chart that fills the frame. Both put (0, 0) at the frame center.
26
+ */
27
+ import { InvalidConfigurationError } from "../core/configuration-error.js";
28
+ import { requireInputObject } from "../core/record-validation.js";
29
+ import { calculateIlluminantIrradianceScale, tabulatedSpectrum } from "./scene-radiance.js";
30
+ /** Most sources an `illumination` may list. */
31
+ export const MIXED_ILLUMINATION_MAX_SOURCES = 8;
32
+ /** Most regions a `regions` blend may list. */
33
+ export const MIXED_ILLUMINATION_MAX_REGIONS = 64;
34
+ const fail = (message) => { throw new InvalidConfigurationError(message); };
35
+ /** A record with no other fields than these (`name` relative to `illumination`). */
36
+ const fields = (value, name, keys) => {
37
+ requireInputObject(value, "illumination" + name);
38
+ for (const key of Object.keys(value))
39
+ if (!keys.includes(key))
40
+ fail("Unknown illumination" + name + " field: " + key + ".");
41
+ return value;
42
+ };
43
+ const finite = (x, name) => (typeof x === "number" && Number.isFinite(x) && Math.abs(x) <= 1e6 ? x : fail("illumination" + name + " must be a finite number."));
44
+ const positive = (x, name, maximum) => (typeof x === "number" && x > 0 && x <= maximum ? x : fail("illumination" + name + " must be positive, up to " + maximum + "."));
45
+ const list = (value, name, what) => (value === undefined ? [] : Array.isArray(value) && value.length >= 1 && value.length <= MIXED_ILLUMINATION_MAX_SOURCES ? value :
46
+ fail("illumination." + name + " must list 1 to " + MIXED_ILLUMINATION_MAX_SOURCES + " " + what + "."));
47
+ const point = (value, name) => {
48
+ const r = fields(value, ".blend." + name, ["u", "v"]);
49
+ return { u: finite(r.u, ".blend." + name + ".u"), v: finite(r.v, ".blend." + name + ".v") };
50
+ };
51
+ /**
52
+ * Internal: validates `illumination` and resolves its sources with `resolveIlluminant` (the capture's `resolveCaptureIlluminant`, or
53
+ * the display view's portable one).
54
+ */
55
+ export function resolveMixedIllumination(value, resolveIlluminant) {
56
+ const record = fields(value, "", ["sources", "blend", "points"]), given = list(record.sources, "sources", "sources"), pointList = list(record.points, "points", "point sources");
57
+ if (pointList.length === 0 && given.length < 2)
58
+ fail("illumination needs two or more sources, or a point source; one source alone is illuminant and illuminanceLux.");
59
+ const sources = given.map((entry, i) => {
60
+ const s = fields(entry, ".sources[" + i + "]", ["illuminant", "illuminanceLux"]), option = s.illuminant, illuminant = resolveIlluminant(option);
61
+ return Object.freeze({ illuminant, option, illuminanceLux: s.illuminanceLux, irradianceScale: calculateIlluminantIrradianceScale(illuminant.shape, s.illuminanceLux),
62
+ report: Object.freeze({ illuminant: illuminant.id, illuminanceLux: s.illuminanceLux }) });
63
+ });
64
+ // Point sources: c_j with 683 ∫ c_j S_j ȳ dλ = I_j (the irradiance scale of 1 lux, times I_j), and E_j = c_j S_j(λ)·h/d³.
65
+ const points = pointList.map((entry, j) => {
66
+ const at = ".points[" + j + "]", p = fields(entry, at, ["illuminant", "position", "intensity"]), option = p.illuminant, illuminant = resolveIlluminant(option);
67
+ const q = fields(p.position, at + ".position", ["xM", "yM", "heightM"]), i = fields(p.intensity, at + ".intensity", ["candela", "illuminanceLux", "distanceM"]);
68
+ const position = { xM: finite(q.xM, at + ".position.xM"), yM: finite(q.yM, at + ".position.yM"), heightM: positive(q.heightM, at + ".position.heightM", 1e4) };
69
+ const candela = i.candela !== undefined ? (i.illuminanceLux === undefined && i.distanceM === undefined ? positive(i.candela, at + ".intensity.candela", 1e9) :
70
+ fail("illumination" + at + ".intensity takes candela or illuminanceLux and distanceM, not both.")) :
71
+ positive(i.illuminanceLux, at + ".intensity.illuminanceLux", 1e7) * positive(i.distanceM, at + ".intensity.distanceM", 1e4) ** 2;
72
+ return { illuminant, option, position, candela, scale: calculateIlluminantIrradianceScale(illuminant.shape, 1) * candela, shape: tabulatedSpectrum(illuminant.shape) };
73
+ });
74
+ /** cos θ/d² of point source j at plane point (x, y) m. */
75
+ const falloff = (p, x, y) => {
76
+ const dx = x - p.position.xM, dy = y - p.position.yM, h = p.position.heightM, d2 = dx * dx + dy * dy + h * h;
77
+ return h / (d2 * Math.sqrt(d2));
78
+ };
79
+ const n = sources.length, shapes = sources.map((s) => tabulatedSpectrum(s.illuminant.shape));
80
+ if (n < 2 && record.blend !== undefined)
81
+ fail("illumination.blend needs two or more sources.");
82
+ const b = n < 2 ? { kind: "none" } : fields(record.blend, ".blend", ["kind", "from", "to", "center", "radius", "stops", "regions", "outsideSource"]);
83
+ const index = (x, name) => (Number.isInteger(x) && x >= 0 && x < n ? x : fail("illumination.blend." + name + " must be a source index from 0 to " + (n - 1) + "."));
84
+ const unused = (keys) => { for (const key of keys)
85
+ if (b[key] !== undefined)
86
+ fail("illumination.blend." + key + " does not apply to a " + String(b.kind) + " blend."); };
87
+ // A point's position t on a gradient or radial blend, or its source on a regions blend.
88
+ let position, blend = null, stops;
89
+ if (b.kind === "none")
90
+ position = () => 0;
91
+ else if (b.kind === "regions") {
92
+ unused(["from", "to", "center", "radius", "stops"]);
93
+ const rects = b.regions;
94
+ if (!Array.isArray(rects) || rects.length < 1 || rects.length > MIXED_ILLUMINATION_MAX_REGIONS)
95
+ fail("illumination.blend.regions must list 1 to " + MIXED_ILLUMINATION_MAX_REGIONS + " rectangles.");
96
+ const regions = rects.map((entry, i) => {
97
+ const at = ".blend.regions[" + i + "]", r = fields(entry, at, ["source", "uMin", "uMax", "vMin", "vMax"]);
98
+ const region = { source: index(r.source, "regions[" + i + "].source"), uMin: finite(r.uMin, at + ".uMin"), uMax: finite(r.uMax, at + ".uMax"), vMin: finite(r.vMin, at + ".vMin"), vMax: finite(r.vMax, at + ".vMax") };
99
+ if (!(region.uMin <= region.uMax && region.vMin <= region.vMax))
100
+ fail("illumination" + at + " uMin and vMin must not exceed uMax and vMax.");
101
+ return region;
102
+ });
103
+ const outside = index(b.outsideSource, "outsideSource");
104
+ position = (u, v) => regions.find((r) => u >= r.uMin && u <= r.uMax && v >= r.vMin && v <= r.vMax)?.source ?? outside;
105
+ blend = { kind: "regions", regions, outsideSource: outside };
106
+ }
107
+ else {
108
+ if (b.kind === "linear-gradient") {
109
+ unused(["center", "radius", "regions", "outsideSource"]);
110
+ const from = point(b.from, "from"), to = point(b.to, "to"), du = to.u - from.u, dv = to.v - from.v, length2 = du * du + dv * dv;
111
+ if (!(length2 > 0))
112
+ fail("illumination.blend from and to must differ.");
113
+ position = (u, v) => Math.min(1, Math.max(0, ((u - from.u) * du + (v - from.v) * dv) / length2));
114
+ blend = { kind: b.kind, from, to };
115
+ }
116
+ else if (b.kind === "radial") {
117
+ unused(["from", "to", "regions", "outsideSource"]);
118
+ const center = b.center === undefined ? { u: 0, v: 0 } : point(b.center, "center"), radius = finite(b.radius, ".blend.radius");
119
+ if (!(radius > 0))
120
+ fail("illumination.blend.radius must be positive.");
121
+ position = (u, v) => Math.min(1, Math.hypot(u - center.u, v - center.v) / radius);
122
+ blend = { kind: b.kind, center, radius };
123
+ }
124
+ else
125
+ return fail('illumination.blend.kind must be "linear-gradient", "radial" or "regions".');
126
+ const declared = b.stops;
127
+ if (declared !== undefined && (!Array.isArray(declared) || declared.length !== n))
128
+ fail("illumination.blend.stops must list one stop per source.");
129
+ blend.stops = stops = declared ? declared.map((x, i) => {
130
+ const stop = finite(x, ".blend.stops[" + i + "]");
131
+ return stop >= 0 && stop <= 1 && (i === 0 || stop >= declared[i - 1]) ? stop : fail("illumination.blend.stops must be non-decreasing in [0, 1].");
132
+ }) : sources.map((_, i) => i / (n - 1));
133
+ }
134
+ /**
135
+ * The blend at a point: the lower source i and the fraction f of source i + 1 (f = 0: source i alone). On a gradient, the segment
136
+ * [stops[i], stops[i + 1]) that holds t; equal stops are passed over, so the later source takes the stop.
137
+ */
138
+ const at = (u, v) => {
139
+ const t = position(u, v);
140
+ if (!stops)
141
+ return [t, 0];
142
+ let i = 0;
143
+ while (i < n - 1 && t >= stops[i + 1])
144
+ i++;
145
+ return i === n - 1 || t <= stops[i] ? [i, 0] : [i, (t - stops[i]) / (stops[i + 1] - stops[i])];
146
+ };
147
+ const [i0, f0] = at(0, 0), weights = sources.map((_, i) => (i === i0 ? 1 - f0 : i === i0 + 1 ? f0 : 0));
148
+ // Every light at the frame center, the blend's sources first: a point source's irradiance scale there is c_j·cos θ/d².
149
+ const lights = [...sources, ...points.map((p) => {
150
+ const atCenter = falloff(p, 0, 0);
151
+ return Object.freeze({ illuminant: p.illuminant, option: p.option, illuminanceLux: p.candela * atCenter, irradianceScale: p.scale * atCenter,
152
+ report: Object.freeze({ illuminant: p.illuminant.id, position: p.position, intensityCandela: p.candela }) });
153
+ })];
154
+ const illuminancesLux = lights.map((l, i) => (i < n ? weights[i] * l.illuminanceLux : l.illuminanceLux));
155
+ let strongest = 0, illuminanceLux = 0;
156
+ illuminancesLux.forEach((e, i) => { illuminanceLux += e; if (e > illuminancesLux[strongest])
157
+ strongest = i; });
158
+ /** The blend's irradiance (k·S(λ) itself where one source has weight 1). */
159
+ const ambient = (u, v, nm) => {
160
+ if (n === 0)
161
+ return 0;
162
+ const [i, f] = at(u, v), a = sources[i].irradianceScale * shapes[i](nm);
163
+ return f === 0 ? a : (1 - f) * a + f * (sources[i + 1].irradianceScale * shapes[i + 1](nm));
164
+ };
165
+ return Object.freeze({ sources: Object.freeze(lights), blend: blend && Object.freeze(blend),
166
+ irradianceAt: points.length === 0 ? (u, v, _x, _y, nm) => ambient(u, v, nm) : (u, v, x, y, nm) => {
167
+ let e = ambient(u, v, nm);
168
+ for (const p of points)
169
+ e += p.scale * p.shape(nm) * falloff(p, x, y);
170
+ return e;
171
+ },
172
+ center: Object.freeze({ illuminanceLux, weights, illuminancesLux, strongestSource: strongest }) });
173
+ }
174
+ //# sourceMappingURL=mixed-illumination.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mixed-illumination.js","sourceRoot":"","sources":["../../src/facade/mixed-illumination.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * 2.22 (#550): spatially varying illumination of the scene plane (mixed lighting), loaded on demand by `simulateCapture` and the\n * display view only when a request has `illumination`, so requests without it neither load nor run it.\n *\n * Model: N sources (1 to {@link MIXED_ILLUMINATION_MAX_SOURCES}; one lights the whole plane), source i an illuminant spectral shape S_i(λ) scaled to\n * `illuminanceLux` E_i exactly as the single illuminant is (`calculateIlluminantIrradianceScale`: k_i with 683 ∫ k_i S_i ȳ dλ = E_i).\n * The plane's spectral irradiance at a point p is the declared blend E(p, λ) = Σ_i w_i(p)·k_i·S_i(λ) with weights w_i(p) ≥ 0 that\n * sum to 1, so the illuminance at p is Σ_i w_i(p)·E_i and, where one weight is 1, the light is exactly that source's. A Lambertian\n * reflector then has radiance ρ(λ)·E(p, λ)/π, as under one illuminant. The blend is a declared crossfade of irradiance, not a\n * model of how light falls off from a lamp or a window (no inverse-square law, no cosine falloff, no shadows); it is exact for\n * what it declares.\n *\n * Point sources (owner decision 2026-11-10, a step toward flash): source j is a point at height h_j in front of the plane above\n * plane point (x_j, y_j) m, with luminous intensity I_j cd (the same in every direction toward the plane) and spectral shape S_j(λ),\n * scaled so that 683 ∫ c_j S_j ȳ dλ = I_j. A point p of the plane at distance d from it receives E_j(p, λ) = c_j·S_j(λ)·cos θ/d²,\n * with cos θ = h_j/d: the inverse-square law with Lambert's cosine law, which follows from the definitions of luminous intensity\n * (flux per solid angle) and illuminance (flux per area) with the solid angle dΩ = dA·cos θ/d² that a plane element subtends (CIE S\n * 017:2020 ILV, International Lighting Vocabulary, entries \"luminous intensity\" and \"illuminance\", free at e-ilv.cie.co.at; BIPM SI\n * Brochure, 9th edition 2019, Table 4, the steradian). Exact for an ideal isotropic point; no occlusion (the camera casts no shadow),\n * no source size and no inter-reflection. The point sources add to the blend: E(p, λ) = Σ_i w_i(p)·k_i·S_i(λ) + Σ_j E_j(p, λ).\n *\n * Coordinates are the chart's: a fixed-size chart's chart-local units (±1 at its left and right edges, v up on the same scale,\n * extended linearly over the surround), or, without `chartSize`, frame units (±1 at the frame's left and right edges), which are\n * the chart-local units of a chart that fills the frame. Both put (0, 0) at the frame center.\n */\n\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport { requireInputObject } from \"../core/record-validation.js\";\nimport { calculateIlluminantIrradianceScale, tabulatedSpectrum, type CaptureIlluminant, type ResolvedCaptureIlluminant } from \"./scene-radiance.js\";\n\n/** Most sources an `illumination` may list. */\nexport const MIXED_ILLUMINATION_MAX_SOURCES = 8;\n/** Most regions a `regions` blend may list. */\nexport const MIXED_ILLUMINATION_MAX_REGIONS = 64;\n\n/** One light source of a mixed illumination: an illuminant (as `simulateCapture` `illuminant` takes it) at an illuminance. */\nexport interface MixedIlluminationSource {\n illuminant: CaptureIlluminant;\n /** Illuminance this source alone gives where its weight is 1, lux, (0, 1e7]. */\n illuminanceLux: number;\n}\n/**\n * 2.22 (#550): a point light on the scene plane's front side: an illuminant spectrum, a position in metres (`xM`, `yM` on the plane\n * from the optical axis, +x right and +y up as seen from the camera; `heightM` > 0 in front of the plane, toward the camera) and an\n * intensity, either in candela or as the illuminance it gives at normal incidence at a reference distance (I = E·r²).\n */\nexport interface MixedIlluminationPointSource {\n illuminant: CaptureIlluminant;\n position: { xM: number; yM: number; heightM: number };\n intensity: { candela: number } | { illuminanceLux: number; distanceM: number };\n}\n/** A point in chart coordinates (see {@link MixedIllumination}). */\nexport interface MixedIlluminationPoint { u: number; v: number }\n/**\n * How the sources blend across the chart. `linear-gradient` and `radial` map a point to a position t in [0, 1] (its projection\n * onto `from` → `to`, clamped; or its distance from `center` over `radius`, clamped) and crossfade linearly between consecutive\n * sources at their `stops` (one per source, non-decreasing in [0, 1]; default evenly spaced from 0 to 1): source 0 alone up to\n * stops[0], the last source alone from its stop on, and two equal stops a hard edge (the later source from the stop on).\n * `regions` gives each point the source of the first rectangle that contains it (bounds inclusive) and `outsideSource` elsewhere.\n */\nexport type MixedIlluminationBlend =\n | { kind: \"linear-gradient\"; from: MixedIlluminationPoint; to: MixedIlluminationPoint; stops?: readonly number[] }\n | { kind: \"radial\"; center?: MixedIlluminationPoint; radius: number; stops?: readonly number[] }\n | { kind: \"regions\"; regions: readonly { source: number; uMin: number; uMax: number; vMin: number; vMax: number }[]; outsideSource: number };\n/**\n * 2.22 (#550), `simulateCapture` `illumination`: sources blended across the chart and point sources with inverse-square falloff\n * (docs/MIXED_ILLUMINATION.md). It replaces `illuminant` and `illuminanceLux`. `sources` lists 1 to 8 sources (with two or more, a\n * `blend` is required; one lights the whole plane); `points` lists 1 to 8 point sources; a request needs two or more sources or at least one point. Blend\n * coordinates are chart-local with `chartSize` and frame units without it; (0, 0) is the frame center.\n */\nexport interface MixedIllumination {\n sources?: readonly MixedIlluminationSource[];\n blend?: MixedIlluminationBlend;\n points?: readonly MixedIlluminationPointSource[];\n}\n\n/** Internal: a validated mixed illumination with its lights resolved and scaled. */\nexport interface ResolvedMixedIllumination {\n /**\n * The lights, the blend's sources first and then the point sources: each with the illuminance it gives at the frame center when\n * it lights it alone (a point source's I·cos θ/d²) and the scale k with k·S(λ) that light's irradiance there; `report` is its\n * public form (the assumption's and the digest's).\n */\n sources: readonly { illuminant: ResolvedCaptureIlluminant; option: CaptureIlluminant; illuminanceLux: number; irradianceScale: number; report: Readonly<Record<string, unknown>> }[];\n /** The blend with its defaults filled, or null (one source or none). */\n blend: Readonly<Record<string, unknown>> | null;\n /** Spectral irradiance at a plane point, W·m⁻²·nm⁻¹: (u, v) chart coordinates for the blend, (xM, yM) metres for the point sources. */\n irradianceAt(u: number, v: number, xM: number, yM: number, wavelengthNanometers: number): number;\n /**\n * At the frame center: the illuminance, the blend's source weights, each light's illuminance there (w_i·E_i; a point's\n * I·cos θ/d²) and the strongest light (the largest, the first on a tie; an index into `sources`).\n */\n center: { illuminanceLux: number; weights: number[]; illuminancesLux: number[]; strongestSource: number };\n}\n\ntype Fields = Record<string, unknown>;\nconst fail = (message: string): never => { throw new InvalidConfigurationError(message); };\n/** A record with no other fields than these (`name` relative to `illumination`). */\nconst fields = (value: unknown, name: string, keys: string[]): Fields => {\n requireInputObject(value, \"illumination\" + name);\n for (const key of Object.keys(value as object)) if (!keys.includes(key)) fail(\"Unknown illumination\" + name + \" field: \" + key + \".\");\n return value as Fields;\n};\nconst finite = (x: unknown, name: string): number => (typeof x === \"number\" && Number.isFinite(x) && Math.abs(x) <= 1e6 ? x : fail(\"illumination\" + name + \" must be a finite number.\"));\nconst positive = (x: unknown, name: string, maximum: number): number => (typeof x === \"number\" && x > 0 && x <= maximum ? x : fail(\"illumination\" + name + \" must be positive, up to \" + maximum + \".\"));\nconst list = (value: unknown, name: string, what: string): unknown[] => (value === undefined ? [] : Array.isArray(value) && value.length >= 1 && value.length <= MIXED_ILLUMINATION_MAX_SOURCES ? value :\n fail(\"illumination.\" + name + \" must list 1 to \" + MIXED_ILLUMINATION_MAX_SOURCES + \" \" + what + \".\"));\nconst point = (value: unknown, name: string): MixedIlluminationPoint => {\n const r = fields(value, \".blend.\" + name, [\"u\", \"v\"]);\n return { u: finite(r.u, \".blend.\" + name + \".u\"), v: finite(r.v, \".blend.\" + name + \".v\") };\n};\n\n/**\n * Internal: validates `illumination` and resolves its sources with `resolveIlluminant` (the capture's `resolveCaptureIlluminant`, or\n * the display view's portable one).\n */\nexport function resolveMixedIllumination(value: unknown, resolveIlluminant: (value: CaptureIlluminant) => ResolvedCaptureIlluminant): ResolvedMixedIllumination {\n const record = fields(value, \"\", [\"sources\", \"blend\", \"points\"]), given = list(record.sources, \"sources\", \"sources\"), pointList = list(record.points, \"points\", \"point sources\");\n if (pointList.length === 0 && given.length < 2) fail(\"illumination needs two or more sources, or a point source; one source alone is illuminant and illuminanceLux.\");\n const sources = given.map((entry, i) => {\n const s = fields(entry, \".sources[\" + i + \"]\", [\"illuminant\", \"illuminanceLux\"]), option = s.illuminant as CaptureIlluminant, illuminant = resolveIlluminant(option);\n return Object.freeze({ illuminant, option, illuminanceLux: s.illuminanceLux as number, irradianceScale: calculateIlluminantIrradianceScale(illuminant.shape, s.illuminanceLux as number),\n report: Object.freeze({ illuminant: illuminant.id, illuminanceLux: s.illuminanceLux }) });\n });\n // Point sources: c_j with 683 ∫ c_j S_j ȳ dλ = I_j (the irradiance scale of 1 lux, times I_j), and E_j = c_j S_j(λ)·h/d³.\n const points = pointList.map((entry, j) => {\n const at = \".points[\" + j + \"]\", p = fields(entry, at, [\"illuminant\", \"position\", \"intensity\"]), option = p.illuminant as CaptureIlluminant, illuminant = resolveIlluminant(option);\n const q = fields(p.position, at + \".position\", [\"xM\", \"yM\", \"heightM\"]), i = fields(p.intensity, at + \".intensity\", [\"candela\", \"illuminanceLux\", \"distanceM\"]);\n const position = { xM: finite(q.xM, at + \".position.xM\"), yM: finite(q.yM, at + \".position.yM\"), heightM: positive(q.heightM, at + \".position.heightM\", 1e4) };\n const candela = i.candela !== undefined ? (i.illuminanceLux === undefined && i.distanceM === undefined ? positive(i.candela, at + \".intensity.candela\", 1e9) :\n fail(\"illumination\" + at + \".intensity takes candela or illuminanceLux and distanceM, not both.\")) :\n positive(i.illuminanceLux, at + \".intensity.illuminanceLux\", 1e7) * positive(i.distanceM, at + \".intensity.distanceM\", 1e4) ** 2;\n return { illuminant, option, position, candela, scale: calculateIlluminantIrradianceScale(illuminant.shape, 1) * candela, shape: tabulatedSpectrum(illuminant.shape) };\n });\n /** cos θ/d² of point source j at plane point (x, y) m. */\n const falloff = (p: typeof points[number], x: number, y: number): number => {\n const dx = x - p.position.xM, dy = y - p.position.yM, h = p.position.heightM, d2 = dx * dx + dy * dy + h * h;\n return h / (d2 * Math.sqrt(d2));\n };\n const n = sources.length, shapes = sources.map((s) => tabulatedSpectrum(s.illuminant.shape));\n if (n < 2 && record.blend !== undefined) fail(\"illumination.blend needs two or more sources.\");\n const b = n < 2 ? { kind: \"none\" } : fields(record.blend, \".blend\", [\"kind\", \"from\", \"to\", \"center\", \"radius\", \"stops\", \"regions\", \"outsideSource\"]);\n const index = (x: unknown, name: string): number => (Number.isInteger(x) && (x as number) >= 0 && (x as number) < n ? x as number : fail(\"illumination.blend.\" + name + \" must be a source index from 0 to \" + (n - 1) + \".\"));\n const unused = (keys: string[]): void => { for (const key of keys) if (b[key] !== undefined) fail(\"illumination.blend.\" + key + \" does not apply to a \" + String(b.kind) + \" blend.\"); };\n // A point's position t on a gradient or radial blend, or its source on a regions blend.\n let position: (u: number, v: number) => number, blend: Fields | null = null, stops: number[] | undefined;\n if (b.kind === \"none\") position = (): number => 0;\n else if (b.kind === \"regions\") {\n unused([\"from\", \"to\", \"center\", \"radius\", \"stops\"]);\n const rects = b.regions as unknown[];\n if (!Array.isArray(rects) || rects.length < 1 || rects.length > MIXED_ILLUMINATION_MAX_REGIONS) fail(\"illumination.blend.regions must list 1 to \" + MIXED_ILLUMINATION_MAX_REGIONS + \" rectangles.\");\n const regions = rects.map((entry, i) => {\n const at = \".blend.regions[\" + i + \"]\", r = fields(entry, at, [\"source\", \"uMin\", \"uMax\", \"vMin\", \"vMax\"]);\n const region = { source: index(r.source, \"regions[\" + i + \"].source\"), uMin: finite(r.uMin, at + \".uMin\"), uMax: finite(r.uMax, at + \".uMax\"), vMin: finite(r.vMin, at + \".vMin\"), vMax: finite(r.vMax, at + \".vMax\") };\n if (!(region.uMin <= region.uMax && region.vMin <= region.vMax)) fail(\"illumination\" + at + \" uMin and vMin must not exceed uMax and vMax.\");\n return region;\n });\n const outside = index(b.outsideSource, \"outsideSource\");\n position = (u: number, v: number): number => regions.find((r) => u >= r.uMin && u <= r.uMax && v >= r.vMin && v <= r.vMax)?.source ?? outside;\n blend = { kind: \"regions\", regions, outsideSource: outside };\n } else {\n if (b.kind === \"linear-gradient\") {\n unused([\"center\", \"radius\", \"regions\", \"outsideSource\"]);\n const from = point(b.from, \"from\"), to = point(b.to, \"to\"), du = to.u - from.u, dv = to.v - from.v, length2 = du * du + dv * dv;\n if (!(length2 > 0)) fail(\"illumination.blend from and to must differ.\");\n position = (u: number, v: number): number => Math.min(1, Math.max(0, ((u - from.u) * du + (v - from.v) * dv) / length2));\n blend = { kind: b.kind, from, to };\n } else if (b.kind === \"radial\") {\n unused([\"from\", \"to\", \"regions\", \"outsideSource\"]);\n const center = b.center === undefined ? { u: 0, v: 0 } : point(b.center, \"center\"), radius = finite(b.radius, \".blend.radius\");\n if (!(radius > 0)) fail(\"illumination.blend.radius must be positive.\");\n position = (u: number, v: number): number => Math.min(1, Math.hypot(u - center.u, v - center.v) / radius);\n blend = { kind: b.kind, center, radius };\n } else return fail('illumination.blend.kind must be \"linear-gradient\", \"radial\" or \"regions\".');\n const declared = b.stops as unknown[] | undefined;\n if (declared !== undefined && (!Array.isArray(declared) || declared.length !== n)) fail(\"illumination.blend.stops must list one stop per source.\");\n blend!.stops = stops = declared ? declared.map((x, i) => {\n const stop = finite(x, \".blend.stops[\" + i + \"]\");\n return stop >= 0 && stop <= 1 && (i === 0 || stop >= (declared[i - 1] as number)) ? stop : fail(\"illumination.blend.stops must be non-decreasing in [0, 1].\");\n }) : sources.map((_, i) => i / (n - 1));\n }\n /**\n * The blend at a point: the lower source i and the fraction f of source i + 1 (f = 0: source i alone). On a gradient, the segment\n * [stops[i], stops[i + 1]) that holds t; equal stops are passed over, so the later source takes the stop.\n */\n const at = (u: number, v: number): [number, number] => {\n const t = position(u, v);\n if (!stops) return [t, 0];\n let i = 0;\n while (i < n - 1 && t >= stops[i + 1]!) i++;\n return i === n - 1 || t <= stops[i]! ? [i, 0] : [i, (t - stops[i]!) / (stops[i + 1]! - stops[i]!)];\n };\n const [i0, f0] = at(0, 0), weights = sources.map((_, i) => (i === i0 ? 1 - f0 : i === i0 + 1 ? f0 : 0));\n // Every light at the frame center, the blend's sources first: a point source's irradiance scale there is c_j·cos θ/d².\n const lights = [...sources, ...points.map((p) => {\n const atCenter = falloff(p, 0, 0);\n return Object.freeze({ illuminant: p.illuminant, option: p.option, illuminanceLux: p.candela * atCenter, irradianceScale: p.scale * atCenter,\n report: Object.freeze({ illuminant: p.illuminant.id, position: p.position, intensityCandela: p.candela }) });\n })];\n const illuminancesLux = lights.map((l, i) => (i < n ? weights[i]! * l.illuminanceLux : l.illuminanceLux));\n let strongest = 0, illuminanceLux = 0;\n illuminancesLux.forEach((e, i) => { illuminanceLux += e; if (e > illuminancesLux[strongest]!) strongest = i; });\n /** The blend's irradiance (k·S(λ) itself where one source has weight 1). */\n const ambient = (u: number, v: number, nm: number): number => {\n if (n === 0) return 0;\n const [i, f] = at(u, v), a = sources[i]!.irradianceScale * shapes[i]!(nm);\n return f === 0 ? a : (1 - f) * a + f * (sources[i + 1]!.irradianceScale * shapes[i + 1]!(nm));\n };\n return Object.freeze({ sources: Object.freeze(lights), blend: blend && Object.freeze(blend),\n irradianceAt: points.length === 0 ? (u: number, v: number, _x: number, _y: number, nm: number): number => ambient(u, v, nm) : (u: number, v: number, x: number, y: number, nm: number): number => {\n let e = ambient(u, v, nm);\n for (const p of points) e += p.scale * p.shape(nm) * falloff(p, x, y);\n return e;\n },\n center: Object.freeze({ illuminanceLux, weights, illuminancesLux, strongestSource: strongest }) });\n}\n"]}
@@ -0,0 +1,72 @@
1
+ import type { ColorimetricSpectrum } from "../color/color-matching-functions.js";
2
+ import type { CaptureIlluminant } from "./scene-radiance.js";
3
+ /** Identity of the built-in light-source set. */
4
+ export declare const REPRESENTATIVE_LIGHT_SOURCE_SET_ID = "photivra-representative-light-sources";
5
+ /** Version of the set's spectra; a change to any spectrum changes it. */
6
+ export declare const REPRESENTATIVE_LIGHT_SOURCE_SET_VERSION = "1.0.0";
7
+ /** Domain of every spectrum, nm (the CIE 1931 observer's domain; the capture facade uses 380–780 nm of it). */
8
+ export declare const REPRESENTATIVE_LIGHT_SOURCE_WAVELENGTH_RANGE_NANOMETERS: Readonly<{
9
+ minimum: 360;
10
+ maximum: 830;
11
+ }>;
12
+ /** The source ids, in set order. */
13
+ export declare const REPRESENTATIVE_LIGHT_SOURCE_IDS: readonly ["tri-phosphor-fluorescent-4000k", "white-led-low-rendering-4000k", "white-led-high-rendering-4000k", "warm-white-led-2700k"];
14
+ export type RepresentativeLightSourceId = (typeof REPRESENTATIVE_LIGHT_SOURCE_IDS)[number];
15
+ /** One Gaussian band a·exp(−½((λ − μ)/σ)²) of a source spectrum. */
16
+ export interface RepresentativeLightSourceBand {
17
+ kind: "gaussian";
18
+ /** What the band represents, for example "blue pump" or "green phosphor line". */
19
+ role: string;
20
+ amplitude: number;
21
+ centerNanometers: number;
22
+ standardDeviationNanometers: number;
23
+ }
24
+ /** One built-in source: its id, name, design reason and spectrum definition. */
25
+ export interface RepresentativeLightSource {
26
+ sourceId: RepresentativeLightSourceId;
27
+ /** Photivra's descriptive name, for example "White LED, high color rendering, 4000 K". */
28
+ name: string;
29
+ family: "fluorescent" | "led";
30
+ /** The CCT the spectrum was designed for, K (its computed CCT is within 1 K of it, Duv within 0.0001; docs/LIGHT_SOURCES.md). */
31
+ nominalCorrelatedColorTemperatureKelvin: number;
32
+ /** Always "representative, not a named product". */
33
+ label: "representative, not a named product";
34
+ /** One sentence: what the source represents and why it is built this way. */
35
+ reason: string;
36
+ /** The constant b (a low continuum), relative units. */
37
+ base: number;
38
+ bands: readonly RepresentativeLightSourceBand[];
39
+ }
40
+ export interface RepresentativeLightSourceSet {
41
+ setId: typeof REPRESENTATIVE_LIGHT_SOURCE_SET_ID;
42
+ setVersion: typeof REPRESENTATIVE_LIGHT_SOURCE_SET_VERSION;
43
+ wavelengthRangeNanometers: {
44
+ readonly minimum: number;
45
+ readonly maximum: number;
46
+ };
47
+ sources: readonly RepresentativeLightSource[];
48
+ }
49
+ /**
50
+ * The built-in representative light sources: Photivra's own parametric spectra of a tri-phosphor fluorescent tube and
51
+ * three white LEDs (low and high color rendering at 4000 K, warm at 2700 K). A static, deeply frozen engine contract.
52
+ * Each is "representative, not a named product"; docs/LIGHT_SOURCES.md gives every formula and the reasons for it.
53
+ */
54
+ export declare function getRepresentativeLightSourceSet(): RepresentativeLightSourceSet;
55
+ /**
56
+ * A source's relative spectral power distribution S(λ) = b + Σ aₖ·exp(−½((λ − μₖ)/σₖ)²) as a function spectrum on
57
+ * 360–830 nm (relative units; values memoized per wavelength). Pass it to a capture as
58
+ * `illuminant: { kind: "spectrum", spectrum }`; for color work use `sensor.spectralStepNanometers: 5` or finer
59
+ * (docs/LIGHT_SOURCES.md, "Quadrature"). Throws `InvalidScientificInputError` outside 360–830 nm.
60
+ */
61
+ export declare function createRepresentativeLightSourceSpectrum(input: {
62
+ sourceId: RepresentativeLightSourceId;
63
+ }): ColorimetricSpectrum;
64
+ /**
65
+ * A capture illuminant for a source: `{ kind: "spectrum", spectrum, label }` with the spectrum of
66
+ * {@link createRepresentativeLightSourceSpectrum} and the label "<name> (representative, not a named product)".
67
+ */
68
+ export declare function createRepresentativeLightSourceIlluminant(input: {
69
+ sourceId: RepresentativeLightSourceId;
70
+ }): Extract<CaptureIlluminant, {
71
+ kind: "spectrum";
72
+ }>;