@photivra/engine 2.12.0 → 2.14.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 +144 -1
- package/CITATION.cff +1 -1
- package/README.md +7 -7
- package/SECURITY.md +1 -1
- package/THIRD_PARTY.md +3 -0
- package/dist/camera/lens-projection.js +2 -1
- package/dist/camera/lens-projection.js.map +1 -1
- package/dist/capture/dng-import.js +1 -1
- package/dist/capture/dng-import.js.map +1 -1
- package/dist/capture/export-jpeg.d.ts +1 -1
- package/dist/capture/export-jpeg.js +6 -4
- package/dist/capture/export-jpeg.js.map +1 -1
- package/dist/capture/host-yield-cadence.js +1 -1
- package/dist/capture/host-yield-cadence.js.map +1 -1
- package/dist/capture/native-environment-optical-stage.js +1 -1
- package/dist/capture/native-environment-optical-stage.js.map +1 -1
- package/dist/capture/native-raw.js +1 -1
- package/dist/capture/native-raw.js.map +1 -1
- package/dist/capture/packed-sensor-raw.js +3 -3
- package/dist/capture/packed-sensor-raw.js.map +1 -1
- package/dist/capture/sensor-raw-producer.js +1 -1
- package/dist/capture/sensor-raw-producer.js.map +1 -1
- package/dist/color/capture-color.js +3 -3
- package/dist/color/capture-color.js.map +1 -1
- package/dist/color/chromatic-adaptation.js +2 -2
- package/dist/color/chromatic-adaptation.js.map +1 -1
- package/dist/color/color-matching-functions.js +1 -1
- package/dist/color/color-matching-functions.js.map +1 -1
- package/dist/color/colorimetry-math.js +2 -2
- package/dist/color/colorimetry-math.js.map +1 -1
- package/dist/color/illuminants.js +3 -3
- package/dist/color/illuminants.js.map +1 -1
- package/dist/color/rgb-color-spaces.js +1 -1
- package/dist/color/rgb-color-spaces.js.map +1 -1
- package/dist/color/sensor-color-development.js +1 -1
- package/dist/color/sensor-color-development.js.map +1 -1
- package/dist/core/record-validation.js +3 -3
- package/dist/core/record-validation.js.map +1 -1
- package/dist/core/version.d.ts +1 -1
- package/dist/core/version.js +1 -1
- package/dist/core/version.js.map +1 -1
- package/dist/equipment/generic-prime-lenses.js +3 -3
- package/dist/equipment/generic-prime-lenses.js.map +1 -1
- package/dist/equipment/generic-tier-assets.d.ts +23 -1
- package/dist/equipment/generic-tier-assets.js +58 -30
- package/dist/equipment/generic-tier-assets.js.map +1 -1
- package/dist/equipment/generic-tier-presets.d.ts +6 -3
- package/dist/equipment/generic-tier-presets.js +26 -13
- package/dist/equipment/generic-tier-presets.js.map +1 -1
- package/dist/exposure/auto-iso-slowest-shutter.d.ts +120 -0
- package/dist/exposure/auto-iso-slowest-shutter.js +217 -0
- package/dist/exposure/auto-iso-slowest-shutter.js.map +1 -0
- package/dist/exposure/exposure-mode-resolver.d.ts +57 -1
- package/dist/exposure/exposure-mode-resolver.js +238 -33
- package/dist/exposure/exposure-mode-resolver.js.map +1 -1
- package/dist/exposure/flash-ttl.js +1 -1
- package/dist/exposure/flash-ttl.js.map +1 -1
- package/dist/exposure/flash.js +1 -1
- package/dist/exposure/flash.js.map +1 -1
- package/dist/facade/chart-material-layers.js +2 -2
- package/dist/facade/chart-material-layers.js.map +1 -1
- package/dist/facade/chart-radiance-batch.js +1 -1
- package/dist/facade/chart-radiance-batch.js.map +1 -1
- package/dist/facade/chart-scenes.d.ts +45 -8
- package/dist/facade/chart-scenes.js +101 -44
- package/dist/facade/chart-scenes.js.map +1 -1
- package/dist/facade/color-patches.d.ts +129 -0
- package/dist/facade/color-patches.js +209 -0
- package/dist/facade/color-patches.js.map +1 -0
- package/dist/facade/diffraction-provider.js +12 -13
- package/dist/facade/diffraction-provider.js.map +1 -1
- package/dist/facade/display-view-gpu.js +1 -1
- package/dist/facade/display-view-gpu.js.map +1 -1
- package/dist/facade/display-view.d.ts +27 -0
- package/dist/facade/display-view.js +234 -65
- package/dist/facade/display-view.js.map +1 -1
- package/dist/facade/scene-radiance.js +2 -2
- package/dist/facade/scene-radiance.js.map +1 -1
- package/dist/facade/simulate-capture.d.ts +139 -12
- package/dist/facade/simulate-capture.js +209 -36
- package/dist/facade/simulate-capture.js.map +1 -1
- package/dist/facade/simulate-display-view.js +2 -2
- package/dist/facade/simulate-display-view.js.map +1 -1
- package/dist/gpu/chart-composite-gpu.js +2 -2
- package/dist/gpu/chart-composite-gpu.js.map +1 -1
- package/dist/gpu/display-view-composite-material-module.js +1 -1
- package/dist/gpu/display-view-composite-material-module.js.map +1 -1
- package/dist/gpu/display-view-quality-gpu.d.ts +2 -1
- package/dist/gpu/display-view-quality-gpu.js +24 -14
- package/dist/gpu/display-view-quality-gpu.js.map +1 -1
- package/dist/gpu/image-kernel-execution.js +2 -2
- package/dist/gpu/image-kernel-execution.js.map +1 -1
- package/dist/gpu/temporal-sum-gpu.js +23 -23
- package/dist/gpu/webgpu-runtime.js +1 -1
- package/dist/gpu/webgpu-runtime.js.map +1 -1
- package/dist/gpu/wgsl-chart-composite-kernel.js +318 -318
- package/dist/gpu/wgsl-chart-composite-kernel.js.map +1 -1
- package/dist/gpu/wgsl-chart-kernel.js +117 -117
- package/dist/gpu/wgsl-chart-kernel.js.map +1 -1
- package/dist/gpu/wgsl-display-view-quality-kernel.d.ts +13 -1
- package/dist/gpu/wgsl-display-view-quality-kernel.js +522 -488
- package/dist/gpu/wgsl-display-view-quality-kernel.js.map +1 -1
- package/dist/gpu/wgsl-display-view-speed-kernel.js +248 -248
- package/dist/gpu/wgsl-display-view-speed-kernel.js.map +1 -1
- package/dist/gpu/wgsl-kernels.js +203 -203
- package/dist/gpu/wgsl-kernels.js.map +1 -1
- package/dist/gpu/wgsl-sensor-kernel.js +302 -302
- package/dist/gpu/wgsl-sensor-kernel.js.map +1 -1
- package/dist/index.d.ts +8 -5
- package/dist/index.js +6 -3
- package/dist/index.js.map +1 -1
- package/dist/motion/temporal-exposure-sum.js +1 -1
- package/dist/motion/temporal-exposure-sum.js.map +1 -1
- package/dist/optics/diffraction-psf-profile.js +4 -4
- package/dist/optics/diffraction-psf-profile.js.map +1 -1
- package/dist/optics/front-of-lens-filter.js +1 -1
- package/dist/optics/front-of-lens-filter.js.map +1 -1
- package/dist/optics/irradiance-convolution.d.ts +10 -0
- package/dist/optics/irradiance-convolution.js +49 -14
- package/dist/optics/irradiance-convolution.js.map +1 -1
- package/dist/output/native-capture-sdr.js +1 -1
- package/dist/output/native-capture-sdr.js.map +1 -1
- package/dist/output/png-encoder.js +2 -2
- package/dist/output/png-encoder.js.map +1 -1
- package/dist/output/print-jpeg.js +13 -10
- package/dist/output/print-jpeg.js.map +1 -1
- package/dist/output/text-metadata.d.ts +22 -2
- package/dist/output/text-metadata.js +58 -9
- package/dist/output/text-metadata.js.map +1 -1
- package/dist/sensor/fixed-pattern-noise.js +1 -1
- package/dist/sensor/fixed-pattern-noise.js.map +1 -1
- package/dist/sensor/readout-exposure-linkage.js +1 -1
- package/dist/sensor/readout-exposure-linkage.js.map +1 -1
- package/docs/API_REFERENCE.md +49 -1
- package/docs/QUICK_START.md +104 -9
- package/docs/USAGE.md +241 -2
- package/docs/api/core-version.md +1 -1
- package/docs/api/equipment-generic-tier-assets.md +41 -1
- package/docs/api/equipment-generic-tier-presets.md +11 -3
- package/docs/api/exports.json +172 -2
- package/docs/api/exposure-auto-iso-slowest-shutter.md +139 -0
- package/docs/api/exposure-exposure-mode-resolver.md +68 -0
- package/docs/api/facade-chart-scenes.md +36 -5
- package/docs/api/facade-color-patches.md +150 -0
- package/docs/api/facade-simulate-capture.md +140 -9
- package/docs/api/output-text-metadata.md +34 -0
- package/llms.txt +1 -0
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"color-matching-functions.js","sourceRoot":"","sources":["../../src/color/color-matching-functions.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * CIE colour-matching functions (CMFs) and spectrum → CIE XYZ integration.\n *\n * Two CMF sources are supported:\n * 1. The engine's own analytic APPROXIMATION of the CIE 1931 2° observer. Each of x̄, ȳ, z̄ is a sum\n * of split Gaussian lobes (a lobe has an amplitude, a centre, and separate widths below and above\n * the centre): three lobes for x̄, two each for ȳ and z̄. The engine fitted the coefficients itself\n * by non-negative least squares to the CIE 1931 2° table (DOI 10.25039/CIE.DS.xvudnb9b) at 1 nm\n * from 360 to 830 nm, with `scripts/fit-cie-1931-cmf.mjs`. The table is used only when the fit is\n * run and is not stored in the repository. Measured fit error (maximum absolute / RMS): x̄ 0.0122 /\n * 0.00426, ȳ 0.00733 / 0.00265, z̄ 0.0221 / 0.00397; see docs/COLORIMETRY.md.\n * 2. Caller-supplied tabulated CMFs, for example the official CIE datasets. The CIE\n * distributes those under CC BY-SA 4.0, so they are NOT bundled with this Apache-2.0\n * package. Tables are linearly interpolated. Outside their declared range they throw\n * (fail closed); there is no extrapolation.\n *\n * Integration uses explicit wavelength quadrature nodes `{wavelengthNanometers,\n * wavelengthMeasureNanometers}`. Nodes from `calculateSensorSpectralQuadrature()` have the\n * same shape and can be passed directly. X = k Σ S(λᵢ) R(λᵢ) x̄(λᵢ) Δλᵢ: a quadrature of the tristimulus\n * integral X = ∫ L(λ) x̄(λ) dλ with stimulus L = S·R (Wyman, Sloan & Shirley 2013, JCGT 2(2), Eq. 1, free;\n * also CIE 15:2018 §7.1). The normalization k and the quadrature nodes are explicit choices.\n * @see docs/COLORIMETRY.md for equations, coordinate/unit conventions and limits.\n */\n\nimport { approximationResult, calculatedResult, type CalculationResult } from \"../core/calculation-result.js\";\nimport type { SpectralWavelengthRangeNanometers, SpectralWavelengthSample } from \"../core/spectral.js\";\nimport { InvalidScientificInputError } from \"../core/validation.js\";\nimport {\n chromaticityOfXyz,\n requireFiniteNumber,\n requireFiniteResult,\n requirePositiveNumber,\n requireRecordValue,\n type CieXyChromaticity,\n type CieXyzTristimulus\n} from \"./colorimetry-math.js\";\nimport { rejectUnknownFields, requireInputKeys } from \"../core/record-validation.js\";\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\n\nexport const COLORIMETRY_MODEL_VERSION = \"2.0.0\" as const;\n/** Upper bound on quadrature nodes per integration call. */\nexport const MAX_COLORIMETRIC_QUADRATURE_NODES = 100_000;\n/** Upper bound on samples in a caller-supplied tabulated spectrum or CMF table. */\nexport const MAX_COLORIMETRIC_TABLE_SAMPLES = 100_000;\n\n/** Wavelength domain over which the analytic CIE 1931 fit is accepted (the domain it was fitted on). */\nexport const ANALYTIC_CIE_1931_CMF_DOMAIN_NANOMETERS: Readonly<SpectralWavelengthRangeNanometers> = Object.freeze({ minimum: 360, maximum: 830 });\n\n/** One wavelength quadrature node; d-lambda is in nanometres. */\nexport interface ColorimetricQuadratureNode {\n wavelengthNanometers: number;\n wavelengthMeasureNanometers: number;\n}\n\n/** One tabulated spectral value at one wavelength. */\nexport interface ColorimetricSpectralSample extends SpectralWavelengthSample {\n value: number;\n}\n\n/**\n * A spectral distribution or spectral factor (reflectance, transmittance, relative SPD,\n * sensitivity).\n * - `tabulated` is the JSON form: strictly increasing wavelengths, linear interpolation, and an\n * error (fail closed) outside the table.\n * - `function` is an in-process evaluator (for example a Planckian SPD). It must be finite over\n * its declared range.\n */\nexport type ColorimetricSpectrum =\n | { kind: \"tabulated\"; samples: readonly ColorimetricSpectralSample[] }\n | { kind: \"function\"; wavelengthRangeNanometers: SpectralWavelengthRangeNanometers; evaluate: (wavelengthNanometers: number) => number };\n\n/** One tabulated colour-matching sample. */\nexport interface TabulatedColorMatchingSample extends SpectralWavelengthSample {\n xBar: number;\n yBar: number;\n zBar: number;\n}\n\nexport type ColorimetricObserver = \"cie-1931-2-degree\" | \"cie-1964-10-degree\" | \"caller-defined\";\n\n/** Selects a colour-matching-function source. */\nexport type ColorMatchingFunctionsSource =\n | { kind: \"analytic-cie-1931-multi-lobe-fit\" }\n | {\n kind: \"tabulated\";\n observer: ColorimetricObserver;\n /** Caller identity for the dataset (for example a DOI); recorded in provenance. */\n datasetId: string;\n samples: readonly TabulatedColorMatchingSample[];\n };\n\n/** Validated, reusable colour-matching functions. */\nexport interface PreparedColorMatchingFunctions {\n observer: ColorimetricObserver;\n sourceKind: ColorMatchingFunctionsSource[\"kind\"];\n datasetId: string;\n scientificStatus: \"approximation\" | \"caller-tabulated\";\n wavelengthRangeNanometers: SpectralWavelengthRangeNanometers;\n /** x̄, ȳ, z̄ at one wavelength in nm; throws outside the declared range. */\n evaluate(wavelengthNanometers: number): CieXyzTristimulus;\n}\n\n// The engine's own fit (scripts/fit-cie-1931-cmf.mjs): per lobe the amplitude, the centre (nm),\n// and the standard deviation (nm) used below and above the centre.\ntype Lobe = readonly [amplitude: number, centreNanometers: number, sigmaBelowNanometers: number, sigmaAboveNanometers: number];\nconst X_LOBES: readonly Lobe[] = [[0.375817, 441.559, 15.3475, 94.5181], [-0.322164, 497.643, 23.3464, 30.5255], [0.968784, 600.86, 33.6528, 29.7704]];\nconst Y_LOBES: readonly Lobe[] = [[0.285798, 530.874, 16.3146, 31.077], [0.820879, 568.79, 46.8848, 40.4965]];\nconst Z_LOBES: readonly Lobe[] = [[1.2165, 436.962, 11.8408, 35.9867], [0.681263, 459.034, 25.9609, 13.7926]];\n\nfunction lobes(wavelength: number, set: readonly Lobe[]): number {\n let sum = 0;\n for (const [amplitude, centre, sigmaBelow, sigmaAbove] of set) {\n const t = (wavelength - centre) / (wavelength < centre ? sigmaBelow : sigmaAbove);\n sum += amplitude * Math.exp(-0.5 * t * t);\n }\n return sum;\n}\n\nfunction requireWavelengthIn(wavelength: number, range: SpectralWavelengthRangeNanometers, what: string): void {\n if (!Number.isFinite(wavelength) || wavelength < range.minimum || wavelength > range.maximum) {\n throw new InvalidScientificInputError(what + \" is outside its declared wavelength range [\" + range.minimum + \", \" + range.maximum + \"] nm.\");\n }\n}\n\n/**\n * Evaluates the engine's multi-lobe analytic approximation of the CIE 1931 2° colour-matching\n * functions at one wavelength (nm, standard-air wavelength as in the CIE tables). Approximation:\n * see the module notes for the measured fit error. The values are non-negative over the domain.\n */\nexport function estimateCie1931ColorMatchingFunctions(wavelengthNanometers: number): CieXyzTristimulus {\n requireWavelengthIn(wavelengthNanometers, ANALYTIC_CIE_1931_CMF_DOMAIN_NANOMETERS, \"Analytic CIE 1931 CMF wavelength\");\n return { x: lobes(wavelengthNanometers, X_LOBES), y: lobes(wavelengthNanometers, Y_LOBES), z: lobes(wavelengthNanometers, Z_LOBES) };\n}\n\nfunction parseIncreasingSamples<T extends SpectralWavelengthSample>(\n samples: unknown,\n path: string,\n sampleKeys: readonly string[],\n parseValue: (sample: Record<string, unknown>, samplePath: string) => T\n): T[] {\n if (!Array.isArray(samples) || samples.length < 2 || samples.length > MAX_COLORIMETRIC_TABLE_SAMPLES) {\n throw new InvalidScientificInputError(path + \" must contain between 2 and \" + MAX_COLORIMETRIC_TABLE_SAMPLES + \" samples.\");\n }\n const parsed: T[] = [];\n let previous = -Infinity;\n samples.forEach((raw: unknown, i) => {\n const samplePath = path + \"[\" + i + \"]\";\n const record = requireRecordValue(raw, samplePath);\n rejectUnknownFields(record, sampleKeys, samplePath);\n const wavelength = requirePositiveNumber(record.wavelengthNanometers, samplePath + \".wavelengthNanometers\");\n if (!(wavelength > previous)) throw new InvalidScientificInputError(path + \" wavelengths must be strictly increasing.\");\n previous = wavelength;\n parsed.push(parseValue(record, samplePath));\n });\n return parsed;\n}\n\n/** Finds the bracketing interval for linear interpolation (binary search). */\nfunction bracket(samples: readonly SpectralWavelengthSample[], wavelength: number): [number, number] {\n let lo = 0;\n let hi = samples.length - 1;\n while (hi - lo > 1) {\n const mid = (lo + hi) >> 1;\n if (samples[mid]!.wavelengthNanometers <= wavelength) lo = mid;\n else hi = mid;\n }\n const a = samples[lo]!.wavelengthNanometers;\n const b = samples[hi]!.wavelengthNanometers;\n return [lo, (wavelength - a) / (b - a)];\n}\n\n/**\n * Validates a colour-matching-function source once for repeated evaluation.\n * Tabulated values may be signed only for `caller-defined` observers; CIE observers\n * require non-negative values.\n */\nexport function prepareColorMatchingFunctions(source: ColorMatchingFunctionsSource): PreparedColorMatchingFunctions {\n const record = requireRecordValue(source, \"colorMatchingFunctions\");\n rejectUnknownFields(record, [\"kind\", \"observer\", \"datasetId\", \"samples\"], \"colorMatchingFunctions\");\n if (record.kind === \"analytic-cie-1931-multi-lobe-fit\") {\n rejectUnknownFields(record, [\"kind\"], \"colorMatchingFunctions\");\n return Object.freeze({\n observer: \"cie-1931-2-degree\" as const,\n sourceKind: \"analytic-cie-1931-multi-lobe-fit\" as const,\n datasetId: \"photivra-cie-1931-multi-lobe-fit-2026-10-17\",\n scientificStatus: \"approximation\" as const,\n wavelengthRangeNanometers: { ...ANALYTIC_CIE_1931_CMF_DOMAIN_NANOMETERS },\n evaluate: estimateCie1931ColorMatchingFunctions\n });\n }\n if (record.kind !== \"tabulated\") throw new InvalidConfigurationError(\"colorMatchingFunctions.kind is not supported.\");\n rejectUnknownFields(record, [\"kind\", \"observer\", \"datasetId\", \"samples\"], \"colorMatchingFunctions\");\n const observer = record.observer;\n if (observer !== \"cie-1931-2-degree\" && observer !== \"cie-1964-10-degree\" && observer !== \"caller-defined\") {\n throw new InvalidConfigurationError(\"colorMatchingFunctions.observer is not supported.\");\n }\n if (typeof record.datasetId !== \"string\" || record.datasetId.trim().length === 0) {\n throw new InvalidConfigurationError(\"colorMatchingFunctions.datasetId must be a non-empty string.\");\n }\n const signed = observer === \"caller-defined\";\n const samples = parseIncreasingSamples<TabulatedColorMatchingSample>(record.samples, \"colorMatchingFunctions.samples\",\n [\"wavelengthNanometers\", \"xBar\", \"yBar\", \"zBar\"], (s, p) => {\n const v = (key: \"xBar\" | \"yBar\" | \"zBar\"): number => {\n const n = requireFiniteNumber(s[key], p + \".\" + key);\n if (!signed && n < 0) throw new InvalidScientificInputError(p + \".\" + key + \" must not be negative for a CIE observer.\");\n return n;\n };\n return { wavelengthNanometers: s.wavelengthNanometers as number, xBar: v(\"xBar\"), yBar: v(\"yBar\"), zBar: v(\"zBar\") };\n });\n const range = { minimum: samples[0]!.wavelengthNanometers, maximum: samples[samples.length - 1]!.wavelengthNanometers };\n return Object.freeze({\n observer,\n sourceKind: \"tabulated\" as const,\n datasetId: record.datasetId.trim(),\n scientificStatus: \"caller-tabulated\" as const,\n wavelengthRangeNanometers: range,\n evaluate(wavelengthNanometers: number): CieXyzTristimulus {\n requireWavelengthIn(wavelengthNanometers, range, \"Tabulated CMF wavelength\");\n const [i, t] = bracket(samples, wavelengthNanometers);\n const a = samples[i]!;\n const b = samples[Math.min(i + 1, samples.length - 1)]!;\n return { x: a.xBar + (b.xBar - a.xBar) * t, y: a.yBar + (b.yBar - a.yBar) * t, z: a.zBar + (b.zBar - a.zBar) * t };\n }\n });\n}\n\n/** A validated spectrum ready for evaluation. */\nexport interface PreparedColorimetricSpectrum {\n wavelengthRangeNanometers: SpectralWavelengthRangeNanometers;\n evaluate(wavelengthNanometers: number): number;\n}\n\n/** Validates a tabulated or functional spectrum (values must be finite; sign is not restricted). */\nexport function prepareColorimetricSpectrum(spectrum: ColorimetricSpectrum, path = \"spectrum\"): PreparedColorimetricSpectrum {\n const record = requireRecordValue(spectrum, path);\n rejectUnknownFields(record, [\"kind\", \"samples\", \"wavelengthRangeNanometers\", \"evaluate\"], path);\n if (record.kind === \"function\") {\n rejectUnknownFields(record, [\"kind\", \"wavelengthRangeNanometers\", \"evaluate\"], path);\n const range = requireRecordValue(record.wavelengthRangeNanometers, path + \".wavelengthRangeNanometers\");\n rejectUnknownFields(range, [\"minimum\", \"maximum\"], path + \".wavelengthRangeNanometers\");\n const minimum = requirePositiveNumber(range.minimum, path + \".wavelengthRangeNanometers.minimum\");\n const maximum = requirePositiveNumber(range.maximum, path + \".wavelengthRangeNanometers.maximum\");\n if (!(minimum < maximum)) throw new InvalidScientificInputError(path + \".wavelengthRangeNanometers.minimum must be less than maximum.\");\n if (typeof record.evaluate !== \"function\") throw new InvalidConfigurationError(path + \".evaluate must be a function.\");\n const evaluate = record.evaluate as (w: number) => number;\n const declared = { minimum, maximum };\n return {\n wavelengthRangeNanometers: declared,\n evaluate(w: number): number {\n requireWavelengthIn(w, declared, path);\n const v = evaluate(w);\n if (typeof v !== \"number\" || !Number.isFinite(v)) throw new InvalidScientificInputError(path + \" evaluated to a non-finite value.\");\n return v;\n }\n };\n }\n if (record.kind !== \"tabulated\") throw new InvalidConfigurationError(path + \".kind is not supported.\");\n rejectUnknownFields(record, [\"kind\", \"samples\"], path);\n const samples = parseIncreasingSamples<ColorimetricSpectralSample>(record.samples, path + \".samples\", [\"wavelengthNanometers\", \"value\"], (s, p) => ({\n wavelengthNanometers: s.wavelengthNanometers as number,\n value: requireFiniteNumber(s.value, p + \".value\")\n }));\n const range = { minimum: samples[0]!.wavelengthNanometers, maximum: samples[samples.length - 1]!.wavelengthNanometers };\n return {\n wavelengthRangeNanometers: range,\n evaluate(w: number): number {\n requireWavelengthIn(w, range, path);\n const [i, t] = bracket(samples, w);\n const a = samples[i]!.value;\n const b = samples[Math.min(i + 1, samples.length - 1)]!.value;\n return a + (b - a) * t;\n }\n };\n}\n\nexport interface CreateColorimetricMidpointQuadratureInput {\n wavelengthRangeNanometers: SpectralWavelengthRangeNanometers;\n /** Hard upper bound on each midpoint subinterval width, nm. */\n maximumSubintervalWidthNanometers: number;\n}\n\n/**\n * Builds deterministic uniform midpoint wavelength nodes covering the range. Every\n * node carries its d-lambda measure in nm; the measures sum to the range width.\n */\nexport function createColorimetricMidpointQuadrature(input: CreateColorimetricMidpointQuadratureInput): ColorimetricQuadratureNode[] {\n requireInputKeys(input, \"createColorimetricMidpointQuadrature\", [\"wavelengthRangeNanometers\", \"maximumSubintervalWidthNanometers\"]);\n const range = requireRecordValue(input.wavelengthRangeNanometers, \"wavelengthRangeNanometers\");\n rejectUnknownFields(range, [\"minimum\", \"maximum\"], \"wavelengthRangeNanometers\");\n const minimum = requirePositiveNumber(range.minimum, \"wavelengthRangeNanometers.minimum\");\n const maximum = requirePositiveNumber(range.maximum, \"wavelengthRangeNanometers.maximum\");\n if (!(minimum < maximum)) throw new InvalidScientificInputError(\"wavelengthRangeNanometers.minimum must be less than maximum.\");\n const width = requirePositiveNumber(input.maximumSubintervalWidthNanometers, \"maximumSubintervalWidthNanometers\");\n const count = Math.ceil((maximum - minimum) / width - 1e-9);\n if (count > MAX_COLORIMETRIC_QUADRATURE_NODES) throw new InvalidScientificInputError(\"Quadrature would exceed \" + MAX_COLORIMETRIC_QUADRATURE_NODES + \" nodes.\");\n const step = (maximum - minimum) / count;\n const nodes: ColorimetricQuadratureNode[] = [];\n for (let i = 0; i < count; i++) nodes.push({ wavelengthNanometers: minimum + (i + 0.5) * step, wavelengthMeasureNanometers: step });\n return nodes;\n}\n\n/** Validates explicit quadrature nodes (positive wavelengths and positive measures). */\nexport function parseColorimetricQuadratureNodes(nodes: unknown): ColorimetricQuadratureNode[] {\n if (!Array.isArray(nodes) || nodes.length === 0 || nodes.length > MAX_COLORIMETRIC_QUADRATURE_NODES) {\n throw new InvalidScientificInputError(\"quadratureNodes must contain between 1 and \" + MAX_COLORIMETRIC_QUADRATURE_NODES + \" nodes.\");\n }\n return nodes.map((raw: unknown, i) => {\n const r = requireRecordValue(raw, \"quadratureNodes[\" + i + \"]\");\n rejectUnknownFields(r, [\"wavelengthNanometers\", \"wavelengthMeasureNanometers\"], \"quadratureNodes[\" + i + \"]\");\n return {\n wavelengthNanometers: requirePositiveNumber(r.wavelengthNanometers, \"quadratureNodes[\" + i + \"].wavelengthNanometers\"),\n wavelengthMeasureNanometers: requirePositiveNumber(r.wavelengthMeasureNanometers, \"quadratureNodes[\" + i + \"].wavelengthMeasureNanometers\")\n };\n });\n}\n\n/**\n * Normalization of integrated tristimulus values.\n * - `white-luminance-one`: k = 1 / Σ S ȳ Δλ, so the perfect reflecting diffuser (or the\n * illuminant itself) has Y = 1 (relative colorimetry with Y scaled to 1; also CIE 15:2018).\n * - `scale`: X = factor · Σ …; for example 683.002 lm/W with spectral radiance in\n * W·m⁻²·sr⁻¹·nm⁻¹ yields luminance in cd/m² (the caller owns the unit semantics).\n */\nexport type TristimulusNormalization = { kind: \"white-luminance-one\" } | { kind: \"scale\"; factor: number };\n\nexport interface IntegrateSpectrumToXyzInput {\n quadratureNodes: readonly ColorimetricQuadratureNode[];\n /** Illuminant SPD or emitted spectral radiance S(λ). */\n spectralDistribution: ColorimetricSpectrum;\n /** Optional spectral reflectance/transmittance factor R(λ); omitted means R = 1. */\n spectralFactor?: ColorimetricSpectrum;\n colorMatchingFunctions: ColorMatchingFunctionsSource;\n normalization: TristimulusNormalization;\n}\n\nexport interface IntegratedSpectrumXyz {\n xyz: CieXyzTristimulus;\n /** Tristimulus values of S(λ) alone under the same normalization (the adopted white). */\n whiteXyz: CieXyzTristimulus;\n chromaticity: CieXyChromaticity | null;\n normalizationFactor: number;\n observer: ColorimetricObserver;\n nodeCount: number;\n}\n\n/** Internal: per-node weights S·Δλ and CMF values; reused by matrix fitting. */\nexport interface SampledColorimetricBasis {\n nodes: readonly ColorimetricQuadratureNode[];\n weights: Float64Array;\n xBar: Float64Array;\n yBar: Float64Array;\n zBar: Float64Array;\n cmf: PreparedColorMatchingFunctions;\n}\n\nexport function sampleColorimetricBasis(\n quadratureNodes: readonly ColorimetricQuadratureNode[],\n spectralDistribution: PreparedColorimetricSpectrum,\n cmf: PreparedColorMatchingFunctions\n): SampledColorimetricBasis {\n const nodes = parseColorimetricQuadratureNodes(quadratureNodes);\n const n = nodes.length;\n const weights = new Float64Array(n), xBar = new Float64Array(n), yBar = new Float64Array(n), zBar = new Float64Array(n);\n for (let i = 0; i < n; i++) {\n const node = nodes[i]!;\n const c = cmf.evaluate(node.wavelengthNanometers);\n weights[i] = spectralDistribution.evaluate(node.wavelengthNanometers) * node.wavelengthMeasureNanometers;\n xBar[i] = c.x; yBar[i] = c.y; zBar[i] = c.z;\n }\n return { nodes, weights, xBar, yBar, zBar, cmf };\n}\n\nexport function sampleFactor(basis: SampledColorimetricBasis, factor: PreparedColorimetricSpectrum | undefined): Float64Array {\n const out = new Float64Array(basis.nodes.length);\n for (let i = 0; i < out.length; i++) out[i] = factor === undefined ? 1 : factor.evaluate(basis.nodes[i]!.wavelengthNanometers);\n return out;\n}\n\nexport function integrateSampledXyz(basis: SampledColorimetricBasis, factor: Float64Array): CieXyzTristimulus {\n let x = 0, y = 0, z = 0;\n for (let i = 0; i < factor.length; i++) {\n const w = basis.weights[i]! * factor[i]!;\n x += w * basis.xBar[i]!; y += w * basis.yBar[i]!; z += w * basis.zBar[i]!;\n }\n return { x, y, z };\n}\n\nexport function resolveNormalizationFactor(normalization: TristimulusNormalization, unnormalizedWhiteY: number): number {\n const r = requireRecordValue(normalization, \"normalization\");\n if (r.kind === \"white-luminance-one\") {\n if (!(unnormalizedWhiteY > 0) || !Number.isFinite(unnormalizedWhiteY)) {\n throw new InvalidScientificInputError(\"White-luminance normalization requires a positive integrated Y of the spectral distribution.\");\n }\n return 1 / unnormalizedWhiteY;\n }\n if (r.kind === \"scale\") return requirePositiveNumber(r.factor, \"normalization.factor\");\n throw new InvalidConfigurationError(\"normalization.kind is not supported.\");\n}\n\nfunction scaleXyz(xyz: CieXyzTristimulus, k: number): CieXyzTristimulus {\n return { x: xyz.x * k, y: xyz.y * k, z: xyz.z * k };\n}\n\n/**\n * Integrates a spectrum (optionally multiplied by a reflectance/transmittance factor)\n * against colour-matching functions with caller-explicit quadrature (the tristimulus integral of\n * Wyman, Sloan & Shirley 2013, Eq. 1; also CIE 15:2018 §7).\n * Provenance is `approximation` for the analytic CMF fit and `calculated` for\n * caller-tabulated CMFs. Either way, the caller chooses the quadrature.\n */\nexport function integrateSpectrumToXyz(input: IntegrateSpectrumToXyzInput): CalculationResult<IntegratedSpectrumXyz> {\n requireInputKeys(input, \"integrateSpectrumToXyz\", [\"quadratureNodes\", \"spectralDistribution\", \"spectralFactor\", \"colorMatchingFunctions\", \"normalization\"]);\n const cmf = prepareColorMatchingFunctions(input.colorMatchingFunctions);\n const distribution = prepareColorimetricSpectrum(input.spectralDistribution, \"spectralDistribution\");\n const factor = input.spectralFactor === undefined ? undefined : prepareColorimetricSpectrum(input.spectralFactor, \"spectralFactor\");\n const basis = sampleColorimetricBasis(input.quadratureNodes, distribution, cmf);\n const rawWhite = integrateSampledXyz(basis, sampleFactor(basis, undefined));\n const rawSample = factor === undefined ? rawWhite : integrateSampledXyz(basis, sampleFactor(basis, factor));\n const k = resolveNormalizationFactor(input.normalization, rawWhite.y);\n const xyz = scaleXyz(rawSample, k);\n const whiteXyz = scaleXyz(rawWhite, k);\n requireFiniteResult([xyz.x, xyz.y, xyz.z, whiteXyz.x, whiteXyz.y, whiteXyz.z], \"Spectral integration\");\n const sum = xyz.x + xyz.y + xyz.z;\n const value: IntegratedSpectrumXyz = {\n xyz, whiteXyz, chromaticity: sum > 0 ? chromaticityOfXyz(xyz) : null, normalizationFactor: k,\n observer: cmf.observer, nodeCount: basis.nodes.length\n };\n const assumptions = [\n \"Tristimulus integral evaluated as Σ S(λ)·R(λ)·CMF(λ)·Δλ over the caller's quadrature nodes\",\n \"Caller owns quadrature convergence and wavelength coverage; tabulated inputs are linearly interpolated and fail closed outside their range\"\n ];\n return cmf.scientificStatus === \"approximation\"\n ? approximationResult(value, \"cie-xyz-spectral-integration-analytic-cmf\", COLORIMETRY_MODEL_VERSION,\n [...assumptions, \"CIE 1931 2° CMFs from the engine's multi-lobe analytic fit (measured max abs CMF error 0.0122/0.00733/0.0221)\"])\n : calculatedResult(value, \"cie-xyz-spectral-integration-tabulated-cmf\", COLORIMETRY_MODEL_VERSION,\n [...assumptions, \"Caller-supplied tabulated CMFs: \" + cmf.datasetId]);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"color-matching-functions.js","sourceRoot":"","sources":["../../src/color/color-matching-functions.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * CIE colour-matching functions (CMFs) and spectrum → CIE XYZ integration.\n *\n * Two CMF sources are supported:\n * 1. The engine's own analytic APPROXIMATION of the CIE 1931 2° observer. Each of x̄, ȳ, z̄ is a sum\n * of split Gaussian lobes (a lobe has an amplitude, a centre, and separate widths below and above\n * the centre): three lobes for x̄, two each for ȳ and z̄. The engine fitted the coefficients itself\n * by non-negative least squares to the CIE 1931 2° table (DOI 10.25039/CIE.DS.xvudnb9b) at 1 nm\n * from 360 to 830 nm, with `scripts/fit-cie-1931-cmf.mjs`. The table is used only when the fit is\n * run and is not stored in the repository. Measured fit error (maximum absolute / RMS): x̄ 0.0122 /\n * 0.00426, ȳ 0.00733 / 0.00265, z̄ 0.0221 / 0.00397; see docs/COLORIMETRY.md.\n * 2. Caller-supplied tabulated CMFs, for example the official CIE datasets. The CIE\n * distributes those under CC BY-SA 4.0, so they are NOT bundled with this Apache-2.0\n * package. Tables are linearly interpolated. Outside their declared range they throw\n * (fail closed); there is no extrapolation.\n *\n * Integration uses explicit wavelength quadrature nodes `{wavelengthNanometers,\n * wavelengthMeasureNanometers}`. Nodes from `calculateSensorSpectralQuadrature()` have the\n * same shape and can be passed directly. X = k Σ S(λᵢ) R(λᵢ) x̄(λᵢ) Δλᵢ: a quadrature of the tristimulus\n * integral X = ∫ L(λ) x̄(λ) dλ with stimulus L = S·R (Wyman, Sloan & Shirley 2013, JCGT 2(2), Eq. 1, free;\n * also CIE 15:2018 §7.1). The normalization k and the quadrature nodes are explicit choices.\n * @see docs/COLORIMETRY.md for equations, coordinate/unit conventions and limits.\n */\n\nimport { approximationResult, calculatedResult, type CalculationResult } from \"../core/calculation-result.js\";\nimport type { SpectralWavelengthRangeNanometers, SpectralWavelengthSample } from \"../core/spectral.js\";\nimport { InvalidScientificInputError } from \"../core/validation.js\";\nimport {\n chromaticityOfXyz,\n requireFiniteNumber,\n requireFiniteResult,\n requirePositiveNumber,\n requireRecordValue,\n type CieXyChromaticity,\n type CieXyzTristimulus\n} from \"./colorimetry-math.js\";\nimport { rejectUnknownFields, requireInputKeys } from \"../core/record-validation.js\";\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\n\nexport const COLORIMETRY_MODEL_VERSION = \"2.0.0\" as const;\n/** Upper bound on quadrature nodes per integration call. */\nexport const MAX_COLORIMETRIC_QUADRATURE_NODES = 100_000;\n/** Upper bound on samples in a caller-supplied tabulated spectrum or CMF table. */\nexport const MAX_COLORIMETRIC_TABLE_SAMPLES = 100_000;\n\n/** Wavelength domain over which the analytic CIE 1931 fit is accepted (the domain it was fitted on). */\nexport const ANALYTIC_CIE_1931_CMF_DOMAIN_NANOMETERS: Readonly<SpectralWavelengthRangeNanometers> = /* @__PURE__ */ Object.freeze({ minimum: 360, maximum: 830 });\n\n/** One wavelength quadrature node; d-lambda is in nanometres. */\nexport interface ColorimetricQuadratureNode {\n wavelengthNanometers: number;\n wavelengthMeasureNanometers: number;\n}\n\n/** One tabulated spectral value at one wavelength. */\nexport interface ColorimetricSpectralSample extends SpectralWavelengthSample {\n value: number;\n}\n\n/**\n * A spectral distribution or spectral factor (reflectance, transmittance, relative SPD,\n * sensitivity).\n * - `tabulated` is the JSON form: strictly increasing wavelengths, linear interpolation, and an\n * error (fail closed) outside the table.\n * - `function` is an in-process evaluator (for example a Planckian SPD). It must be finite over\n * its declared range.\n */\nexport type ColorimetricSpectrum =\n | { kind: \"tabulated\"; samples: readonly ColorimetricSpectralSample[] }\n | { kind: \"function\"; wavelengthRangeNanometers: SpectralWavelengthRangeNanometers; evaluate: (wavelengthNanometers: number) => number };\n\n/** One tabulated colour-matching sample. */\nexport interface TabulatedColorMatchingSample extends SpectralWavelengthSample {\n xBar: number;\n yBar: number;\n zBar: number;\n}\n\nexport type ColorimetricObserver = \"cie-1931-2-degree\" | \"cie-1964-10-degree\" | \"caller-defined\";\n\n/** Selects a colour-matching-function source. */\nexport type ColorMatchingFunctionsSource =\n | { kind: \"analytic-cie-1931-multi-lobe-fit\" }\n | {\n kind: \"tabulated\";\n observer: ColorimetricObserver;\n /** Caller identity for the dataset (for example a DOI); recorded in provenance. */\n datasetId: string;\n samples: readonly TabulatedColorMatchingSample[];\n };\n\n/** Validated, reusable colour-matching functions. */\nexport interface PreparedColorMatchingFunctions {\n observer: ColorimetricObserver;\n sourceKind: ColorMatchingFunctionsSource[\"kind\"];\n datasetId: string;\n scientificStatus: \"approximation\" | \"caller-tabulated\";\n wavelengthRangeNanometers: SpectralWavelengthRangeNanometers;\n /** x̄, ȳ, z̄ at one wavelength in nm; throws outside the declared range. */\n evaluate(wavelengthNanometers: number): CieXyzTristimulus;\n}\n\n// The engine's own fit (scripts/fit-cie-1931-cmf.mjs): per lobe the amplitude, the centre (nm),\n// and the standard deviation (nm) used below and above the centre.\ntype Lobe = readonly [amplitude: number, centreNanometers: number, sigmaBelowNanometers: number, sigmaAboveNanometers: number];\nconst X_LOBES: readonly Lobe[] = [[0.375817, 441.559, 15.3475, 94.5181], [-0.322164, 497.643, 23.3464, 30.5255], [0.968784, 600.86, 33.6528, 29.7704]];\nconst Y_LOBES: readonly Lobe[] = [[0.285798, 530.874, 16.3146, 31.077], [0.820879, 568.79, 46.8848, 40.4965]];\nconst Z_LOBES: readonly Lobe[] = [[1.2165, 436.962, 11.8408, 35.9867], [0.681263, 459.034, 25.9609, 13.7926]];\n\nfunction lobes(wavelength: number, set: readonly Lobe[]): number {\n let sum = 0;\n for (const [amplitude, centre, sigmaBelow, sigmaAbove] of set) {\n const t = (wavelength - centre) / (wavelength < centre ? sigmaBelow : sigmaAbove);\n sum += amplitude * Math.exp(-0.5 * t * t);\n }\n return sum;\n}\n\nfunction requireWavelengthIn(wavelength: number, range: SpectralWavelengthRangeNanometers, what: string): void {\n if (!Number.isFinite(wavelength) || wavelength < range.minimum || wavelength > range.maximum) {\n throw new InvalidScientificInputError(what + \" is outside its declared wavelength range [\" + range.minimum + \", \" + range.maximum + \"] nm.\");\n }\n}\n\n/**\n * Evaluates the engine's multi-lobe analytic approximation of the CIE 1931 2° colour-matching\n * functions at one wavelength (nm, standard-air wavelength as in the CIE tables). Approximation:\n * see the module notes for the measured fit error. The values are non-negative over the domain.\n */\nexport function estimateCie1931ColorMatchingFunctions(wavelengthNanometers: number): CieXyzTristimulus {\n requireWavelengthIn(wavelengthNanometers, ANALYTIC_CIE_1931_CMF_DOMAIN_NANOMETERS, \"Analytic CIE 1931 CMF wavelength\");\n return { x: lobes(wavelengthNanometers, X_LOBES), y: lobes(wavelengthNanometers, Y_LOBES), z: lobes(wavelengthNanometers, Z_LOBES) };\n}\n\nfunction parseIncreasingSamples<T extends SpectralWavelengthSample>(\n samples: unknown,\n path: string,\n sampleKeys: readonly string[],\n parseValue: (sample: Record<string, unknown>, samplePath: string) => T\n): T[] {\n if (!Array.isArray(samples) || samples.length < 2 || samples.length > MAX_COLORIMETRIC_TABLE_SAMPLES) {\n throw new InvalidScientificInputError(path + \" must contain between 2 and \" + MAX_COLORIMETRIC_TABLE_SAMPLES + \" samples.\");\n }\n const parsed: T[] = [];\n let previous = -Infinity;\n samples.forEach((raw: unknown, i) => {\n const samplePath = path + \"[\" + i + \"]\";\n const record = requireRecordValue(raw, samplePath);\n rejectUnknownFields(record, sampleKeys, samplePath);\n const wavelength = requirePositiveNumber(record.wavelengthNanometers, samplePath + \".wavelengthNanometers\");\n if (!(wavelength > previous)) throw new InvalidScientificInputError(path + \" wavelengths must be strictly increasing.\");\n previous = wavelength;\n parsed.push(parseValue(record, samplePath));\n });\n return parsed;\n}\n\n/** Finds the bracketing interval for linear interpolation (binary search). */\nfunction bracket(samples: readonly SpectralWavelengthSample[], wavelength: number): [number, number] {\n let lo = 0;\n let hi = samples.length - 1;\n while (hi - lo > 1) {\n const mid = (lo + hi) >> 1;\n if (samples[mid]!.wavelengthNanometers <= wavelength) lo = mid;\n else hi = mid;\n }\n const a = samples[lo]!.wavelengthNanometers;\n const b = samples[hi]!.wavelengthNanometers;\n return [lo, (wavelength - a) / (b - a)];\n}\n\n/**\n * Validates a colour-matching-function source once for repeated evaluation.\n * Tabulated values may be signed only for `caller-defined` observers; CIE observers\n * require non-negative values.\n */\nexport function prepareColorMatchingFunctions(source: ColorMatchingFunctionsSource): PreparedColorMatchingFunctions {\n const record = requireRecordValue(source, \"colorMatchingFunctions\");\n rejectUnknownFields(record, [\"kind\", \"observer\", \"datasetId\", \"samples\"], \"colorMatchingFunctions\");\n if (record.kind === \"analytic-cie-1931-multi-lobe-fit\") {\n rejectUnknownFields(record, [\"kind\"], \"colorMatchingFunctions\");\n return Object.freeze({\n observer: \"cie-1931-2-degree\" as const,\n sourceKind: \"analytic-cie-1931-multi-lobe-fit\" as const,\n datasetId: \"photivra-cie-1931-multi-lobe-fit-2026-10-17\",\n scientificStatus: \"approximation\" as const,\n wavelengthRangeNanometers: { ...ANALYTIC_CIE_1931_CMF_DOMAIN_NANOMETERS },\n evaluate: estimateCie1931ColorMatchingFunctions\n });\n }\n if (record.kind !== \"tabulated\") throw new InvalidConfigurationError(\"colorMatchingFunctions.kind is not supported.\");\n rejectUnknownFields(record, [\"kind\", \"observer\", \"datasetId\", \"samples\"], \"colorMatchingFunctions\");\n const observer = record.observer;\n if (observer !== \"cie-1931-2-degree\" && observer !== \"cie-1964-10-degree\" && observer !== \"caller-defined\") {\n throw new InvalidConfigurationError(\"colorMatchingFunctions.observer is not supported.\");\n }\n if (typeof record.datasetId !== \"string\" || record.datasetId.trim().length === 0) {\n throw new InvalidConfigurationError(\"colorMatchingFunctions.datasetId must be a non-empty string.\");\n }\n const signed = observer === \"caller-defined\";\n const samples = parseIncreasingSamples<TabulatedColorMatchingSample>(record.samples, \"colorMatchingFunctions.samples\",\n [\"wavelengthNanometers\", \"xBar\", \"yBar\", \"zBar\"], (s, p) => {\n const v = (key: \"xBar\" | \"yBar\" | \"zBar\"): number => {\n const n = requireFiniteNumber(s[key], p + \".\" + key);\n if (!signed && n < 0) throw new InvalidScientificInputError(p + \".\" + key + \" must not be negative for a CIE observer.\");\n return n;\n };\n return { wavelengthNanometers: s.wavelengthNanometers as number, xBar: v(\"xBar\"), yBar: v(\"yBar\"), zBar: v(\"zBar\") };\n });\n const range = { minimum: samples[0]!.wavelengthNanometers, maximum: samples[samples.length - 1]!.wavelengthNanometers };\n return Object.freeze({\n observer,\n sourceKind: \"tabulated\" as const,\n datasetId: record.datasetId.trim(),\n scientificStatus: \"caller-tabulated\" as const,\n wavelengthRangeNanometers: range,\n evaluate(wavelengthNanometers: number): CieXyzTristimulus {\n requireWavelengthIn(wavelengthNanometers, range, \"Tabulated CMF wavelength\");\n const [i, t] = bracket(samples, wavelengthNanometers);\n const a = samples[i]!;\n const b = samples[Math.min(i + 1, samples.length - 1)]!;\n return { x: a.xBar + (b.xBar - a.xBar) * t, y: a.yBar + (b.yBar - a.yBar) * t, z: a.zBar + (b.zBar - a.zBar) * t };\n }\n });\n}\n\n/** A validated spectrum ready for evaluation. */\nexport interface PreparedColorimetricSpectrum {\n wavelengthRangeNanometers: SpectralWavelengthRangeNanometers;\n evaluate(wavelengthNanometers: number): number;\n}\n\n/** Validates a tabulated or functional spectrum (values must be finite; sign is not restricted). */\nexport function prepareColorimetricSpectrum(spectrum: ColorimetricSpectrum, path = \"spectrum\"): PreparedColorimetricSpectrum {\n const record = requireRecordValue(spectrum, path);\n rejectUnknownFields(record, [\"kind\", \"samples\", \"wavelengthRangeNanometers\", \"evaluate\"], path);\n if (record.kind === \"function\") {\n rejectUnknownFields(record, [\"kind\", \"wavelengthRangeNanometers\", \"evaluate\"], path);\n const range = requireRecordValue(record.wavelengthRangeNanometers, path + \".wavelengthRangeNanometers\");\n rejectUnknownFields(range, [\"minimum\", \"maximum\"], path + \".wavelengthRangeNanometers\");\n const minimum = requirePositiveNumber(range.minimum, path + \".wavelengthRangeNanometers.minimum\");\n const maximum = requirePositiveNumber(range.maximum, path + \".wavelengthRangeNanometers.maximum\");\n if (!(minimum < maximum)) throw new InvalidScientificInputError(path + \".wavelengthRangeNanometers.minimum must be less than maximum.\");\n if (typeof record.evaluate !== \"function\") throw new InvalidConfigurationError(path + \".evaluate must be a function.\");\n const evaluate = record.evaluate as (w: number) => number;\n const declared = { minimum, maximum };\n return {\n wavelengthRangeNanometers: declared,\n evaluate(w: number): number {\n requireWavelengthIn(w, declared, path);\n const v = evaluate(w);\n if (typeof v !== \"number\" || !Number.isFinite(v)) throw new InvalidScientificInputError(path + \" evaluated to a non-finite value.\");\n return v;\n }\n };\n }\n if (record.kind !== \"tabulated\") throw new InvalidConfigurationError(path + \".kind is not supported.\");\n rejectUnknownFields(record, [\"kind\", \"samples\"], path);\n const samples = parseIncreasingSamples<ColorimetricSpectralSample>(record.samples, path + \".samples\", [\"wavelengthNanometers\", \"value\"], (s, p) => ({\n wavelengthNanometers: s.wavelengthNanometers as number,\n value: requireFiniteNumber(s.value, p + \".value\")\n }));\n const range = { minimum: samples[0]!.wavelengthNanometers, maximum: samples[samples.length - 1]!.wavelengthNanometers };\n return {\n wavelengthRangeNanometers: range,\n evaluate(w: number): number {\n requireWavelengthIn(w, range, path);\n const [i, t] = bracket(samples, w);\n const a = samples[i]!.value;\n const b = samples[Math.min(i + 1, samples.length - 1)]!.value;\n return a + (b - a) * t;\n }\n };\n}\n\nexport interface CreateColorimetricMidpointQuadratureInput {\n wavelengthRangeNanometers: SpectralWavelengthRangeNanometers;\n /** Hard upper bound on each midpoint subinterval width, nm. */\n maximumSubintervalWidthNanometers: number;\n}\n\n/**\n * Builds deterministic uniform midpoint wavelength nodes covering the range. Every\n * node carries its d-lambda measure in nm; the measures sum to the range width.\n */\nexport function createColorimetricMidpointQuadrature(input: CreateColorimetricMidpointQuadratureInput): ColorimetricQuadratureNode[] {\n requireInputKeys(input, \"createColorimetricMidpointQuadrature\", [\"wavelengthRangeNanometers\", \"maximumSubintervalWidthNanometers\"]);\n const range = requireRecordValue(input.wavelengthRangeNanometers, \"wavelengthRangeNanometers\");\n rejectUnknownFields(range, [\"minimum\", \"maximum\"], \"wavelengthRangeNanometers\");\n const minimum = requirePositiveNumber(range.minimum, \"wavelengthRangeNanometers.minimum\");\n const maximum = requirePositiveNumber(range.maximum, \"wavelengthRangeNanometers.maximum\");\n if (!(minimum < maximum)) throw new InvalidScientificInputError(\"wavelengthRangeNanometers.minimum must be less than maximum.\");\n const width = requirePositiveNumber(input.maximumSubintervalWidthNanometers, \"maximumSubintervalWidthNanometers\");\n const count = Math.ceil((maximum - minimum) / width - 1e-9);\n if (count > MAX_COLORIMETRIC_QUADRATURE_NODES) throw new InvalidScientificInputError(\"Quadrature would exceed \" + MAX_COLORIMETRIC_QUADRATURE_NODES + \" nodes.\");\n const step = (maximum - minimum) / count;\n const nodes: ColorimetricQuadratureNode[] = [];\n for (let i = 0; i < count; i++) nodes.push({ wavelengthNanometers: minimum + (i + 0.5) * step, wavelengthMeasureNanometers: step });\n return nodes;\n}\n\n/** Validates explicit quadrature nodes (positive wavelengths and positive measures). */\nexport function parseColorimetricQuadratureNodes(nodes: unknown): ColorimetricQuadratureNode[] {\n if (!Array.isArray(nodes) || nodes.length === 0 || nodes.length > MAX_COLORIMETRIC_QUADRATURE_NODES) {\n throw new InvalidScientificInputError(\"quadratureNodes must contain between 1 and \" + MAX_COLORIMETRIC_QUADRATURE_NODES + \" nodes.\");\n }\n return nodes.map((raw: unknown, i) => {\n const r = requireRecordValue(raw, \"quadratureNodes[\" + i + \"]\");\n rejectUnknownFields(r, [\"wavelengthNanometers\", \"wavelengthMeasureNanometers\"], \"quadratureNodes[\" + i + \"]\");\n return {\n wavelengthNanometers: requirePositiveNumber(r.wavelengthNanometers, \"quadratureNodes[\" + i + \"].wavelengthNanometers\"),\n wavelengthMeasureNanometers: requirePositiveNumber(r.wavelengthMeasureNanometers, \"quadratureNodes[\" + i + \"].wavelengthMeasureNanometers\")\n };\n });\n}\n\n/**\n * Normalization of integrated tristimulus values.\n * - `white-luminance-one`: k = 1 / Σ S ȳ Δλ, so the perfect reflecting diffuser (or the\n * illuminant itself) has Y = 1 (relative colorimetry with Y scaled to 1; also CIE 15:2018).\n * - `scale`: X = factor · Σ …; for example 683.002 lm/W with spectral radiance in\n * W·m⁻²·sr⁻¹·nm⁻¹ yields luminance in cd/m² (the caller owns the unit semantics).\n */\nexport type TristimulusNormalization = { kind: \"white-luminance-one\" } | { kind: \"scale\"; factor: number };\n\nexport interface IntegrateSpectrumToXyzInput {\n quadratureNodes: readonly ColorimetricQuadratureNode[];\n /** Illuminant SPD or emitted spectral radiance S(λ). */\n spectralDistribution: ColorimetricSpectrum;\n /** Optional spectral reflectance/transmittance factor R(λ); omitted means R = 1. */\n spectralFactor?: ColorimetricSpectrum;\n colorMatchingFunctions: ColorMatchingFunctionsSource;\n normalization: TristimulusNormalization;\n}\n\nexport interface IntegratedSpectrumXyz {\n xyz: CieXyzTristimulus;\n /** Tristimulus values of S(λ) alone under the same normalization (the adopted white). */\n whiteXyz: CieXyzTristimulus;\n chromaticity: CieXyChromaticity | null;\n normalizationFactor: number;\n observer: ColorimetricObserver;\n nodeCount: number;\n}\n\n/** Internal: per-node weights S·Δλ and CMF values; reused by matrix fitting. */\nexport interface SampledColorimetricBasis {\n nodes: readonly ColorimetricQuadratureNode[];\n weights: Float64Array;\n xBar: Float64Array;\n yBar: Float64Array;\n zBar: Float64Array;\n cmf: PreparedColorMatchingFunctions;\n}\n\nexport function sampleColorimetricBasis(\n quadratureNodes: readonly ColorimetricQuadratureNode[],\n spectralDistribution: PreparedColorimetricSpectrum,\n cmf: PreparedColorMatchingFunctions\n): SampledColorimetricBasis {\n const nodes = parseColorimetricQuadratureNodes(quadratureNodes);\n const n = nodes.length;\n const weights = new Float64Array(n), xBar = new Float64Array(n), yBar = new Float64Array(n), zBar = new Float64Array(n);\n for (let i = 0; i < n; i++) {\n const node = nodes[i]!;\n const c = cmf.evaluate(node.wavelengthNanometers);\n weights[i] = spectralDistribution.evaluate(node.wavelengthNanometers) * node.wavelengthMeasureNanometers;\n xBar[i] = c.x; yBar[i] = c.y; zBar[i] = c.z;\n }\n return { nodes, weights, xBar, yBar, zBar, cmf };\n}\n\nexport function sampleFactor(basis: SampledColorimetricBasis, factor: PreparedColorimetricSpectrum | undefined): Float64Array {\n const out = new Float64Array(basis.nodes.length);\n for (let i = 0; i < out.length; i++) out[i] = factor === undefined ? 1 : factor.evaluate(basis.nodes[i]!.wavelengthNanometers);\n return out;\n}\n\nexport function integrateSampledXyz(basis: SampledColorimetricBasis, factor: Float64Array): CieXyzTristimulus {\n let x = 0, y = 0, z = 0;\n for (let i = 0; i < factor.length; i++) {\n const w = basis.weights[i]! * factor[i]!;\n x += w * basis.xBar[i]!; y += w * basis.yBar[i]!; z += w * basis.zBar[i]!;\n }\n return { x, y, z };\n}\n\nexport function resolveNormalizationFactor(normalization: TristimulusNormalization, unnormalizedWhiteY: number): number {\n const r = requireRecordValue(normalization, \"normalization\");\n if (r.kind === \"white-luminance-one\") {\n if (!(unnormalizedWhiteY > 0) || !Number.isFinite(unnormalizedWhiteY)) {\n throw new InvalidScientificInputError(\"White-luminance normalization requires a positive integrated Y of the spectral distribution.\");\n }\n return 1 / unnormalizedWhiteY;\n }\n if (r.kind === \"scale\") return requirePositiveNumber(r.factor, \"normalization.factor\");\n throw new InvalidConfigurationError(\"normalization.kind is not supported.\");\n}\n\nfunction scaleXyz(xyz: CieXyzTristimulus, k: number): CieXyzTristimulus {\n return { x: xyz.x * k, y: xyz.y * k, z: xyz.z * k };\n}\n\n/**\n * Integrates a spectrum (optionally multiplied by a reflectance/transmittance factor)\n * against colour-matching functions with caller-explicit quadrature (the tristimulus integral of\n * Wyman, Sloan & Shirley 2013, Eq. 1; also CIE 15:2018 §7).\n * Provenance is `approximation` for the analytic CMF fit and `calculated` for\n * caller-tabulated CMFs. Either way, the caller chooses the quadrature.\n */\nexport function integrateSpectrumToXyz(input: IntegrateSpectrumToXyzInput): CalculationResult<IntegratedSpectrumXyz> {\n requireInputKeys(input, \"integrateSpectrumToXyz\", [\"quadratureNodes\", \"spectralDistribution\", \"spectralFactor\", \"colorMatchingFunctions\", \"normalization\"]);\n const cmf = prepareColorMatchingFunctions(input.colorMatchingFunctions);\n const distribution = prepareColorimetricSpectrum(input.spectralDistribution, \"spectralDistribution\");\n const factor = input.spectralFactor === undefined ? undefined : prepareColorimetricSpectrum(input.spectralFactor, \"spectralFactor\");\n const basis = sampleColorimetricBasis(input.quadratureNodes, distribution, cmf);\n const rawWhite = integrateSampledXyz(basis, sampleFactor(basis, undefined));\n const rawSample = factor === undefined ? rawWhite : integrateSampledXyz(basis, sampleFactor(basis, factor));\n const k = resolveNormalizationFactor(input.normalization, rawWhite.y);\n const xyz = scaleXyz(rawSample, k);\n const whiteXyz = scaleXyz(rawWhite, k);\n requireFiniteResult([xyz.x, xyz.y, xyz.z, whiteXyz.x, whiteXyz.y, whiteXyz.z], \"Spectral integration\");\n const sum = xyz.x + xyz.y + xyz.z;\n const value: IntegratedSpectrumXyz = {\n xyz, whiteXyz, chromaticity: sum > 0 ? chromaticityOfXyz(xyz) : null, normalizationFactor: k,\n observer: cmf.observer, nodeCount: basis.nodes.length\n };\n const assumptions = [\n \"Tristimulus integral evaluated as Σ S(λ)·R(λ)·CMF(λ)·Δλ over the caller's quadrature nodes\",\n \"Caller owns quadrature convergence and wavelength coverage; tabulated inputs are linearly interpolated and fail closed outside their range\"\n ];\n return cmf.scientificStatus === \"approximation\"\n ? approximationResult(value, \"cie-xyz-spectral-integration-analytic-cmf\", COLORIMETRY_MODEL_VERSION,\n [...assumptions, \"CIE 1931 2° CMFs from the engine's multi-lobe analytic fit (measured max abs CMF error 0.0122/0.00733/0.0221)\"])\n : calculatedResult(value, \"cie-xyz-spectral-integration-tabulated-cmf\", COLORIMETRY_MODEL_VERSION,\n [...assumptions, \"Caller-supplied tabulated CMFs: \" + cmf.datasetId]);\n}\n"]}
|
|
@@ -32,8 +32,8 @@ export function requireRecordValue(value, path) {
|
|
|
32
32
|
}
|
|
33
33
|
return value;
|
|
34
34
|
}
|
|
35
|
-
const XYZ_FIELDS = Object.freeze(["x", "y", "z"]);
|
|
36
|
-
const CHROMATICITY_FIELDS = Object.freeze(["x", "y"]);
|
|
35
|
+
const XYZ_FIELDS = /* @__PURE__ */ Object.freeze(["x", "y", "z"]);
|
|
36
|
+
const CHROMATICITY_FIELDS = /* @__PURE__ */ Object.freeze(["x", "y"]);
|
|
37
37
|
/** Parses an XYZ tristimulus record with exactly the fields x, y and z; any other field is rejected. */
|
|
38
38
|
export function parseXyz(value, path) {
|
|
39
39
|
const r = requireRecordValue(value, path);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"colorimetry-math.js","sourceRoot":"","sources":["../../src/color/colorimetry-math.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Shared colorimetric value types (CIE XYZ tristimulus, xy chromaticity, 3×3\n * row-major matrices) and exact linear-algebra helpers used by the colorimetry\n * modules. Pure mathematics; no colour-science constants live here.\n * @see docs/COLORIMETRY.md for equations, coordinate/unit conventions and limits.\n */\n\nimport { InvalidScientificInputError, InvalidScientificResultError } from \"../core/validation.js\";\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport { rejectUnknownFields } from \"../core/record-validation.js\";\n\n/** Three-component vector (dimensionless unless documented otherwise). */\nexport type ColorVector3 = readonly [number, number, number];\n/** Row-major 3×3 matrix; `m[row][column]`. Applied as `m · v` to column vectors. */\nexport type ColorMatrix3x3 = readonly [ColorVector3, ColorVector3, ColorVector3];\n\n/**\n * Relative CIE XYZ tristimulus values. Units are relative (dimensionless);\n * a normalized white has `y = 1` unless a function documents another scale.\n */\nexport interface CieXyzTristimulus {\n x: number;\n y: number;\n z: number;\n}\n\n/** CIE 1931 (x, y) chromaticity coordinates (dimensionless). */\nexport interface CieXyChromaticity {\n x: number;\n y: number;\n}\n\n/** CIE 1960 UCS (u, v) chromaticity coordinates (dimensionless). */\nexport interface Cie1960UvChromaticity {\n u: number;\n v: number;\n}\n\nexport function requireFiniteNumber(value: unknown, path: string): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) {\n throw new InvalidScientificInputError(path + \" must be a finite number.\");\n }\n return value;\n}\n\nexport function requirePositiveNumber(value: unknown, path: string): number {\n const n = requireFiniteNumber(value, path);\n if (n <= 0) throw new InvalidScientificInputError(path + \" must be greater than zero.\");\n return n;\n}\n\nexport function requireNonNegativeNumber(value: unknown, path: string): number {\n const n = requireFiniteNumber(value, path);\n if (n < 0) throw new InvalidScientificInputError(path + \" must not be negative.\");\n return n;\n}\n\nexport function requireRecordValue(value: unknown, path: string): Record<string, unknown> {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n throw new InvalidConfigurationError(path + \" must be an object.\");\n }\n return value as Record<string, unknown>;\n}\n\nconst XYZ_FIELDS: readonly string[] = Object.freeze([\"x\", \"y\", \"z\"]);\nconst CHROMATICITY_FIELDS: readonly string[] = Object.freeze([\"x\", \"y\"]);\n\n/** Parses an XYZ tristimulus record with exactly the fields x, y and z; any other field is rejected. */\nexport function parseXyz(value: unknown, path: string): CieXyzTristimulus {\n const r = requireRecordValue(value, path);\n rejectUnknownFields(r, XYZ_FIELDS, path);\n return { x: requireFiniteNumber(r.x, path + \".x\"), y: requireFiniteNumber(r.y, path + \".y\"), z: requireFiniteNumber(r.z, path + \".z\") };\n}\n\n/** Parses a white point: finite, non-negative components with Y > 0; fields other than x, y, z are rejected. */\nexport function parseWhiteXyz(value: unknown, path: string): CieXyzTristimulus {\n const r = requireRecordValue(value, path);\n rejectUnknownFields(r, XYZ_FIELDS, path);\n return { x: requireNonNegativeNumber(r.x, path + \".x\"), y: requirePositiveNumber(r.y, path + \".y\"), z: requireNonNegativeNumber(r.z, path + \".z\") };\n}\n\n/** Parses a CIE 1931 xy chromaticity with exactly the fields x and y, inside the spectrum-locus triangle bound. */\nexport function parseChromaticity(value: unknown, path: string): CieXyChromaticity {\n const r = requireRecordValue(value, path);\n rejectUnknownFields(r, CHROMATICITY_FIELDS, path);\n const x = requireFiniteNumber(r.x, path + \".x\");\n const y = requireFiniteNumber(r.y, path + \".y\");\n if (x < 0 || y <= 0 || x + y > 1) {\n throw new InvalidScientificInputError(path + \" must satisfy x >= 0, y > 0 and x + y <= 1.\");\n }\n return { x, y };\n}\n\nexport function parseMatrix3x3(value: unknown, path: string): ColorMatrix3x3 {\n if (!Array.isArray(value) || value.length !== 3) throw new InvalidScientificInputError(path + \" must be a 3×3 row-major matrix.\");\n return value.map((row: unknown, i) => {\n if (!Array.isArray(row) || row.length !== 3) throw new InvalidScientificInputError(path + \" must be a 3×3 row-major matrix.\");\n return row.map((v: unknown, j) => requireFiniteNumber(v, path + \"[\" + i + \"][\" + j + \"]\"));\n }) as unknown as ColorMatrix3x3;\n}\n\nexport function multiplyMatrixVector(m: ColorMatrix3x3, v: ColorVector3): ColorVector3 {\n return [\n m[0][0] * v[0] + m[0][1] * v[1] + m[0][2] * v[2],\n m[1][0] * v[0] + m[1][1] * v[1] + m[1][2] * v[2],\n m[2][0] * v[0] + m[2][1] * v[1] + m[2][2] * v[2]\n ];\n}\n\nexport function multiplyMatrices(a: ColorMatrix3x3, b: ColorMatrix3x3): ColorMatrix3x3 {\n const row = (i: 0 | 1 | 2): ColorVector3 => [\n a[i][0] * b[0][0] + a[i][1] * b[1][0] + a[i][2] * b[2][0],\n a[i][0] * b[0][1] + a[i][1] * b[1][1] + a[i][2] * b[2][1],\n a[i][0] * b[0][2] + a[i][1] * b[1][2] + a[i][2] * b[2][2]\n ];\n return [row(0), row(1), row(2)];\n}\n\nexport function determinant3x3(m: ColorMatrix3x3): number {\n const [[a, b, c], [d, e, f], [g, h, i]] = m;\n return a * (e * i - f * h) - b * (d * i - f * g) + c * (d * h - e * g);\n}\n\n/** Exact cofactor inverse. Throws (fails closed) on a singular or non-finite result. */\nexport function invertMatrix3x3(m: ColorMatrix3x3, path = \"matrix\"): ColorMatrix3x3 {\n const [[a, b, c], [d, e, f], [g, h, i]] = m;\n const det = determinant3x3(m);\n const scale = Math.max(...m.flat().map(Math.abs));\n if (!Number.isFinite(det) || scale === 0 || Math.abs(det) <= 1e-12 * scale ** 3) {\n throw new InvalidScientificInputError(path + \" is singular or numerically ill-conditioned.\");\n }\n const inv: ColorMatrix3x3 = [\n [(e * i - f * h) / det, (c * h - b * i) / det, (b * f - c * e) / det],\n [(f * g - d * i) / det, (a * i - c * g) / det, (c * d - a * f) / det],\n [(d * h - e * g) / det, (b * g - a * h) / det, (a * e - b * d) / det]\n ];\n if (inv.flat().some((v) => !Number.isFinite(v))) throw new InvalidScientificResultError(path + \" inverse is not finite.\");\n return inv;\n}\n\nexport function diagonalMatrix(v: ColorVector3): ColorMatrix3x3 {\n return [[v[0], 0, 0], [0, v[1], 0], [0, 0, v[2]]];\n}\n\nexport function xyzToVector(xyz: CieXyzTristimulus): ColorVector3 {\n return [xyz.x, xyz.y, xyz.z];\n}\n\nexport function vectorToXyz(v: ColorVector3): CieXyzTristimulus {\n return { x: v[0], y: v[1], z: v[2] };\n}\n\nexport function copyMatrix(m: ColorMatrix3x3): ColorMatrix3x3 {\n return [[...m[0]], [...m[1]], [...m[2]]] as unknown as ColorMatrix3x3;\n}\n\nexport function requireFiniteResult(values: readonly number[], what: string): void {\n if (values.some((v) => !Number.isFinite(v))) throw new InvalidScientificResultError(what + \" produced a non-finite value.\");\n}\n\n/** XYZ → xy; requires X + Y + Z > 0. */\nexport function chromaticityOfXyz(xyz: CieXyzTristimulus): CieXyChromaticity {\n const sum = xyz.x + xyz.y + xyz.z;\n if (!(sum > 0) || !Number.isFinite(sum)) throw new InvalidScientificInputError(\"Chromaticity requires X + Y + Z > 0.\");\n return { x: xyz.x / sum, y: xyz.y / sum };\n}\n\n/** xy with luminance Y → XYZ (CIE 15 Eq. 7.3 inverse). */\nexport function xyzOfChromaticity(xy: CieXyChromaticity, luminanceY = 1): CieXyzTristimulus {\n if (!(xy.y > 0)) throw new InvalidScientificInputError(\"Chromaticity y must be greater than zero.\");\n return { x: (xy.x / xy.y) * luminanceY, y: luminanceY, z: ((1 - xy.x - xy.y) / xy.y) * luminanceY };\n}\n\n/** CIE 1931 xy → CIE 1960 UCS uv: u = 4x/(−2x+12y+3), v = 6y/(−2x+12y+3). */\nexport function uvOfChromaticity(xy: CieXyChromaticity): Cie1960UvChromaticity {\n const d = -2 * xy.x + 12 * xy.y + 3;\n return { u: (4 * xy.x) / d, v: (6 * xy.y) / d };\n}\n\n/** CIE 1960 UCS uv → CIE 1931 xy: x = 3u/(2u−8v+4), y = 2v/(2u−8v+4). */\nexport function chromaticityOfUv(uv: Cie1960UvChromaticity): CieXyChromaticity {\n const d = 2 * uv.u - 8 * uv.v + 4;\n return { x: (3 * uv.u) / d, y: (2 * uv.v) / d };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"colorimetry-math.js","sourceRoot":"","sources":["../../src/color/colorimetry-math.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Shared colorimetric value types (CIE XYZ tristimulus, xy chromaticity, 3×3\n * row-major matrices) and exact linear-algebra helpers used by the colorimetry\n * modules. Pure mathematics; no colour-science constants live here.\n * @see docs/COLORIMETRY.md for equations, coordinate/unit conventions and limits.\n */\n\nimport { InvalidScientificInputError, InvalidScientificResultError } from \"../core/validation.js\";\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport { rejectUnknownFields } from \"../core/record-validation.js\";\n\n/** Three-component vector (dimensionless unless documented otherwise). */\nexport type ColorVector3 = readonly [number, number, number];\n/** Row-major 3×3 matrix; `m[row][column]`. Applied as `m · v` to column vectors. */\nexport type ColorMatrix3x3 = readonly [ColorVector3, ColorVector3, ColorVector3];\n\n/**\n * Relative CIE XYZ tristimulus values. Units are relative (dimensionless);\n * a normalized white has `y = 1` unless a function documents another scale.\n */\nexport interface CieXyzTristimulus {\n x: number;\n y: number;\n z: number;\n}\n\n/** CIE 1931 (x, y) chromaticity coordinates (dimensionless). */\nexport interface CieXyChromaticity {\n x: number;\n y: number;\n}\n\n/** CIE 1960 UCS (u, v) chromaticity coordinates (dimensionless). */\nexport interface Cie1960UvChromaticity {\n u: number;\n v: number;\n}\n\nexport function requireFiniteNumber(value: unknown, path: string): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) {\n throw new InvalidScientificInputError(path + \" must be a finite number.\");\n }\n return value;\n}\n\nexport function requirePositiveNumber(value: unknown, path: string): number {\n const n = requireFiniteNumber(value, path);\n if (n <= 0) throw new InvalidScientificInputError(path + \" must be greater than zero.\");\n return n;\n}\n\nexport function requireNonNegativeNumber(value: unknown, path: string): number {\n const n = requireFiniteNumber(value, path);\n if (n < 0) throw new InvalidScientificInputError(path + \" must not be negative.\");\n return n;\n}\n\nexport function requireRecordValue(value: unknown, path: string): Record<string, unknown> {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n throw new InvalidConfigurationError(path + \" must be an object.\");\n }\n return value as Record<string, unknown>;\n}\n\nconst XYZ_FIELDS: readonly string[] = /* @__PURE__ */ Object.freeze([\"x\", \"y\", \"z\"]);\nconst CHROMATICITY_FIELDS: readonly string[] = /* @__PURE__ */ Object.freeze([\"x\", \"y\"]);\n\n/** Parses an XYZ tristimulus record with exactly the fields x, y and z; any other field is rejected. */\nexport function parseXyz(value: unknown, path: string): CieXyzTristimulus {\n const r = requireRecordValue(value, path);\n rejectUnknownFields(r, XYZ_FIELDS, path);\n return { x: requireFiniteNumber(r.x, path + \".x\"), y: requireFiniteNumber(r.y, path + \".y\"), z: requireFiniteNumber(r.z, path + \".z\") };\n}\n\n/** Parses a white point: finite, non-negative components with Y > 0; fields other than x, y, z are rejected. */\nexport function parseWhiteXyz(value: unknown, path: string): CieXyzTristimulus {\n const r = requireRecordValue(value, path);\n rejectUnknownFields(r, XYZ_FIELDS, path);\n return { x: requireNonNegativeNumber(r.x, path + \".x\"), y: requirePositiveNumber(r.y, path + \".y\"), z: requireNonNegativeNumber(r.z, path + \".z\") };\n}\n\n/** Parses a CIE 1931 xy chromaticity with exactly the fields x and y, inside the spectrum-locus triangle bound. */\nexport function parseChromaticity(value: unknown, path: string): CieXyChromaticity {\n const r = requireRecordValue(value, path);\n rejectUnknownFields(r, CHROMATICITY_FIELDS, path);\n const x = requireFiniteNumber(r.x, path + \".x\");\n const y = requireFiniteNumber(r.y, path + \".y\");\n if (x < 0 || y <= 0 || x + y > 1) {\n throw new InvalidScientificInputError(path + \" must satisfy x >= 0, y > 0 and x + y <= 1.\");\n }\n return { x, y };\n}\n\nexport function parseMatrix3x3(value: unknown, path: string): ColorMatrix3x3 {\n if (!Array.isArray(value) || value.length !== 3) throw new InvalidScientificInputError(path + \" must be a 3×3 row-major matrix.\");\n return value.map((row: unknown, i) => {\n if (!Array.isArray(row) || row.length !== 3) throw new InvalidScientificInputError(path + \" must be a 3×3 row-major matrix.\");\n return row.map((v: unknown, j) => requireFiniteNumber(v, path + \"[\" + i + \"][\" + j + \"]\"));\n }) as unknown as ColorMatrix3x3;\n}\n\nexport function multiplyMatrixVector(m: ColorMatrix3x3, v: ColorVector3): ColorVector3 {\n return [\n m[0][0] * v[0] + m[0][1] * v[1] + m[0][2] * v[2],\n m[1][0] * v[0] + m[1][1] * v[1] + m[1][2] * v[2],\n m[2][0] * v[0] + m[2][1] * v[1] + m[2][2] * v[2]\n ];\n}\n\nexport function multiplyMatrices(a: ColorMatrix3x3, b: ColorMatrix3x3): ColorMatrix3x3 {\n const row = (i: 0 | 1 | 2): ColorVector3 => [\n a[i][0] * b[0][0] + a[i][1] * b[1][0] + a[i][2] * b[2][0],\n a[i][0] * b[0][1] + a[i][1] * b[1][1] + a[i][2] * b[2][1],\n a[i][0] * b[0][2] + a[i][1] * b[1][2] + a[i][2] * b[2][2]\n ];\n return [row(0), row(1), row(2)];\n}\n\nexport function determinant3x3(m: ColorMatrix3x3): number {\n const [[a, b, c], [d, e, f], [g, h, i]] = m;\n return a * (e * i - f * h) - b * (d * i - f * g) + c * (d * h - e * g);\n}\n\n/** Exact cofactor inverse. Throws (fails closed) on a singular or non-finite result. */\nexport function invertMatrix3x3(m: ColorMatrix3x3, path = \"matrix\"): ColorMatrix3x3 {\n const [[a, b, c], [d, e, f], [g, h, i]] = m;\n const det = determinant3x3(m);\n const scale = Math.max(...m.flat().map(Math.abs));\n if (!Number.isFinite(det) || scale === 0 || Math.abs(det) <= 1e-12 * scale ** 3) {\n throw new InvalidScientificInputError(path + \" is singular or numerically ill-conditioned.\");\n }\n const inv: ColorMatrix3x3 = [\n [(e * i - f * h) / det, (c * h - b * i) / det, (b * f - c * e) / det],\n [(f * g - d * i) / det, (a * i - c * g) / det, (c * d - a * f) / det],\n [(d * h - e * g) / det, (b * g - a * h) / det, (a * e - b * d) / det]\n ];\n if (inv.flat().some((v) => !Number.isFinite(v))) throw new InvalidScientificResultError(path + \" inverse is not finite.\");\n return inv;\n}\n\nexport function diagonalMatrix(v: ColorVector3): ColorMatrix3x3 {\n return [[v[0], 0, 0], [0, v[1], 0], [0, 0, v[2]]];\n}\n\nexport function xyzToVector(xyz: CieXyzTristimulus): ColorVector3 {\n return [xyz.x, xyz.y, xyz.z];\n}\n\nexport function vectorToXyz(v: ColorVector3): CieXyzTristimulus {\n return { x: v[0], y: v[1], z: v[2] };\n}\n\nexport function copyMatrix(m: ColorMatrix3x3): ColorMatrix3x3 {\n return [[...m[0]], [...m[1]], [...m[2]]] as unknown as ColorMatrix3x3;\n}\n\nexport function requireFiniteResult(values: readonly number[], what: string): void {\n if (values.some((v) => !Number.isFinite(v))) throw new InvalidScientificResultError(what + \" produced a non-finite value.\");\n}\n\n/** XYZ → xy; requires X + Y + Z > 0. */\nexport function chromaticityOfXyz(xyz: CieXyzTristimulus): CieXyChromaticity {\n const sum = xyz.x + xyz.y + xyz.z;\n if (!(sum > 0) || !Number.isFinite(sum)) throw new InvalidScientificInputError(\"Chromaticity requires X + Y + Z > 0.\");\n return { x: xyz.x / sum, y: xyz.y / sum };\n}\n\n/** xy with luminance Y → XYZ (CIE 15 Eq. 7.3 inverse). */\nexport function xyzOfChromaticity(xy: CieXyChromaticity, luminanceY = 1): CieXyzTristimulus {\n if (!(xy.y > 0)) throw new InvalidScientificInputError(\"Chromaticity y must be greater than zero.\");\n return { x: (xy.x / xy.y) * luminanceY, y: luminanceY, z: ((1 - xy.x - xy.y) / xy.y) * luminanceY };\n}\n\n/** CIE 1931 xy → CIE 1960 UCS uv: u = 4x/(−2x+12y+3), v = 6y/(−2x+12y+3). */\nexport function uvOfChromaticity(xy: CieXyChromaticity): Cie1960UvChromaticity {\n const d = -2 * xy.x + 12 * xy.y + 3;\n return { u: (4 * xy.x) / d, v: (6 * xy.y) / d };\n}\n\n/** CIE 1960 UCS uv → CIE 1931 xy: x = 3u/(2u−8v+4), y = 2v/(2u−8v+4). */\nexport function chromaticityOfUv(uv: Cie1960UvChromaticity): CieXyChromaticity {\n const d = 2 * uv.u - 8 * uv.v + 4;\n return { x: (3 * uv.u) / d, y: (2 * uv.v) / d };\n}\n"]}
|
|
@@ -45,9 +45,9 @@ const FIRST_RADIATION_CONSTANT_RADIANCE = 2 * PLANCK_CONSTANT_JOULE_SECONDS * SP
|
|
|
45
45
|
const FIRST_RADIATION_CONSTANT_RADIANCE_PORTABLE = 2 * PLANCK_CONSTANT_JOULE_SECONDS * (SPEED_OF_LIGHT_METERS_PER_SECOND * SPEED_OF_LIGHT_METERS_PER_SECOND);
|
|
46
46
|
const PORTABLE = { pow: portablePow, expm1: portableExpm1, hypot: portableHypot };
|
|
47
47
|
/** Temperature range of the Planckian-locus models, K. */
|
|
48
|
-
export const PLANCKIAN_LOCUS_RANGE_KELVIN = Object.freeze({ minimum: 1000, maximum: 100000 });
|
|
48
|
+
export const PLANCKIAN_LOCUS_RANGE_KELVIN = /* @__PURE__ */ Object.freeze({ minimum: 1000, maximum: 100000 });
|
|
49
49
|
/** CIE daylight-locus validity, K. */
|
|
50
|
-
export const CIE_DAYLIGHT_LOCUS_RANGE_KELVIN = Object.freeze({ minimum: 4000, maximum: 25000 });
|
|
50
|
+
export const CIE_DAYLIGHT_LOCUS_RANGE_KELVIN = /* @__PURE__ */ Object.freeze({ minimum: 4000, maximum: 25000 });
|
|
51
51
|
/**
|
|
52
52
|
* Engine limit: no CCT beyond |Duv| = 0.05, the range over which Smet et al. (2023, free) evaluate CCT
|
|
53
53
|
* methods for nominally white light (CIE 15:2018 §9.5, paid, gives the same limit).
|
|
@@ -99,7 +99,7 @@ function planckianSpectrum(input, portable) {
|
|
|
99
99
|
return spectrum;
|
|
100
100
|
}
|
|
101
101
|
/** CIE illuminant A defining range (nm). */
|
|
102
|
-
export const CIE_ILLUMINANT_A_RANGE_NANOMETERS = Object.freeze({ minimum: 300, maximum: 830 });
|
|
102
|
+
export const CIE_ILLUMINANT_A_RANGE_NANOMETERS = /* @__PURE__ */ Object.freeze({ minimum: 300, maximum: 830 });
|
|
103
103
|
/**
|
|
104
104
|
* CIE standard illuminant A relative SPD from its defining formula (100 at 560 nm),
|
|
105
105
|
* with c₂ = 1.435e-2 m·K and T = 2848 K as in the standard (≈ 2856 K with the
|