2 #include <color/spd.hpp>
3 #include <color/specdata.hpp>
4 #include <color/specutils.hpp>
5 #include <color/wave.hpp>
7 #include <math3d/vec3.hpp>
10 using namespace ptracey;
14 const std::vector<WaveLength> &waves,
15 WaveLength waveLStart,
16 WaveLength waveLEnd) {
20 uint end = (uint)waves.size() - 1;
21 if (waveLStart <= waves[0])
23 if (waveLEnd >= waves[end])
25 if ((uint)waves.size() == 1)
29 if (waveLStart < waves[0])
30 psum += powers[0] * (waves[0] - waveLStart);
32 if (waveLEnd > waves[end])
33 psum += powers[end] * (waveLEnd - waves[end]);
36 while (waveLStart > waves[i + 1])
38 auto wsize = (uint)waves.
size();
39 COMP_CHECK((i + 1) < wsize, (i + 1), wsize);
40 auto interpSeg = [waves, powers](
auto w, uint j) {
41 auto t1 = (w - waves[j]) / (waves[j + 1] - waves[j]);
43 auto t3 = powers[j + 1];
44 return mix(t1, t2, t3);
48 j + 1 < (uint)waves.size() && waveLEnd >= waves[j];
50 auto segLambdaStart = std::max(waveLStart, waves[j]);
51 auto segLambdaEnd = std::min(waveLEnd, waves[j + 1]);
52 auto interp_seg_start = interpSeg(segLambdaStart, j);
53 auto interp_seg_end = interpSeg(segLambdaEnd, j);
54 psum += 0.5 * (interp_seg_start + interp_seg_end) *
55 (segLambdaEnd - segLambdaStart);
57 return psum / (waveLEnd - waveLStart);
60 Power averageSpectrum(
const spd &in_spd,
61 WaveLength waveLStart,
62 WaveLength waveLEnd) {
63 auto powers2 = in_spd.powers();
64 auto waves = in_spd.wavelengths();
65 return averageSpectrum(powers2, waves, waveLStart,
69 void resample_wave_power(
71 const std::vector<WaveLength> &in_waves,
72 std::vector<Power> &out_powers,
73 std::vector<WaveLength> &out_waves,
74 const WaveLength &waveLStart,
75 const WaveLength &waveLEnd,
const uint &out_size) {
79 uint wsize = (uint)in_waves.size();
80 COMP_CHECK(wsize > 2, wsize, 2);
81 auto miwave = waveLStart;
82 auto mwave = waveLEnd;
83 auto waves = in_waves;
84 auto pwrs = in_powers;
86 WaveLength delta = (mwave - miwave) / (wsize - 1);
89 auto wlstartClamp = [miwave, mwave, waves, wsize,
90 delta](
int index) -> WaveLength {
92 COMP_CHECK((index >= -1) && (index <= (
int)wsize),
96 COMP_CHECK(miwave - delta < waves[0], miwave - delta,
98 return miwave - delta;
99 }
else if (index == wsize) {
100 COMP_CHECK(mwave + delta > waves[wsize - 1],
101 mwave + delta, waves[wsize - 1]);
102 return mwave + delta;
106 auto pwClamped = [wsize, pwrs](
int index) -> Power {
107 COMP_CHECK(index >= -1 && index <= (
int)wsize, index,
109 return pwrs[dclamp<uint>(index, 0, wsize - 1)];
112 auto samplingfn = [waves, pwrs, delta, wsize, pwClamped,
113 wlstartClamp](WaveLength wl) -> Power {
114 if (wl + delta / 2 <= waves[0])
116 if (wl - delta / 2 >= waves[wsize - 1])
117 return pwrs[wsize - 1];
125 if (wl - delta < waves[0]) {
128 auto intervalfn = [waves, delta, wl](
int i) ->
bool {
129 return waves[i] <= (wl - delta);
131 start = findInterval((
int)wsize, intervalfn);
132 bool sb1 = start >= 0;
133 bool sb2 = start < (int)wsize;
134 COMP_CHECK(sb1 && sb2, start, wsize);
137 if (wl + delta > waves[wsize - 1]) {
140 end = start > 0 ? start : 0;
141 while (end < (
int)wsize && wl + delta > waves[end])
144 bool cond1 = end - start == 2;
145 bool cond2 = (wlstartClamp(start) <= (wl - delta));
146 bool cond3 = waves[start + 1] == wl;
147 bool cond4 = wlstartClamp(end) >= wl + delta;
148 if (cond1 && cond2 && cond3 && cond4) {
149 return pwrs[start + 1];
150 }
else if (end - start == 1) {
153 (wl - wlstartClamp(start)) /
154 (wlstartClamp(end) - wlstartClamp(start));
155 COMP_CHECK(t >= 0 && t <= 1, t, t);
156 return mix(t, pwClamped(start), pwClamped(end));
158 return averageSpectrum(pwrs, waves, wl - delta / 2,
163 for (
int outOffset = 0; outOffset < out_size;
166 auto wave = mix<WaveLength>(WaveLength(outOffset) /
168 waveLStart, waveLEnd);
169 out_waves.push_back(wave);
170 Power pwr = samplingfn(wave);
171 out_powers.push_back(pwr);
175 spd spd::resample_c(
const spd &s)
const {
177 auto waves1 = wavelengths();
178 auto waves2 = s.wavelengths();
179 auto powers1 = powers();
180 auto powers2 = s.powers();
182 auto wsize1 = waves1.size();
183 auto wsize2 = waves2.size();
184 auto wsize = wsize1 > wsize2 ? wsize1 : wsize2;
185 COMP_CHECK(wsize > 2, wsize, 2);
187 auto waves = wsize == wsize1 ? waves1 : waves2;
188 auto pwrs = wsize == wsize1 ? powers1 : powers2;
190 auto mwave1 = max_wave();
191 auto mwave2 = s.max_wave();
192 auto mwave = mwave1 > mwave2 ? mwave1 : mwave2;
194 auto miwave1 = min_wave();
195 auto miwave2 = s.min_wave();
196 auto miwave = miwave1 > miwave2 ? miwave1 : miwave2;
198 std::vector<Power> out_powers;
199 std::vector<WaveLength> out_waves;
200 resample_wave_power(pwrs, waves, out_powers, out_waves,
201 miwave, mwave, wsize);
203 auto sp =
spd(spowers, out_waves);
206 spd spd::resample_c(
const WaveLength &waveLStart,
207 const WaveLength &waveLEnd,
208 const uint &outSize)
const {
210 auto waves = wavelengths();
211 auto spowers = powers();
212 std::vector<Power> out_powers;
213 std::vector<WaveLength> out_waves;
214 resample_wave_power(spowers, waves, out_powers, out_waves,
215 waveLStart, waveLEnd, outSize);
217 auto sp =
spd(sspowers, out_waves);
220 spd spd::resample_c(
const uint &outSize)
const {
221 auto miwave = min_wave();
222 auto mwave = max_wave();
223 auto sp = resample_c(miwave, mwave, outSize);
227 void spd::resample(
const spd &s) { *
this = resample_c(s); }
228 void spd::resample(
const WaveLength &waveLStart,
229 const WaveLength &waveLEnd,
230 const uint &outSize) {
231 *
this = resample_c(waveLStart, waveLEnd, outSize);
236 spd rgb_to_spect(std::vector<Real> rgb_wavelength,
237 std::vector<Real> rgb_spect) {
239 COMP_CHECK(rgb_spect.size() == rgb_wavelength.size(),
240 rgb_spect.size(), rgb_wavelength.size());
241 std::vector<WaveLength> waves =
242 cast_vec<Real, WaveLength>(
243 rgb_wavelength, [](
auto rgbw) {
244 return static_cast<WaveLength
>(rgbw);
246 WaveLength mx_wave = *std::max_element(
247 rgb_wavelength.begin(), rgb_wavelength.end());
248 WaveLength mn_wave = *std::min_element(
249 rgb_wavelength.begin(), rgb_wavelength.end());
251 std::vector<Power> powers =
252 cast_vec<Real, Power>(rgb_spect, [](
auto rgbp) {
253 return static_cast<Power
>(rgbp);
256 std::vector<Power> pwrs;
257 std::vector<WaveLength> wvs;
258 for (uint i = 0; i < SPD_NB_SAMPLE; i++) {
259 WaveLength wl0 = mix<WaveLength>(
260 WaveLength(i) / WaveLength(SPD_NB_SAMPLE),
261 VISIBLE_LAMBDA_START, VISIBLE_LAMBDA_END);
262 WaveLength wl1 = mix<WaveLength>(
263 WaveLength(i + 1) / WaveLength(SPD_NB_SAMPLE),
264 VISIBLE_LAMBDA_START, VISIBLE_LAMBDA_END);
266 averageSpectrum(sampled_powers, waves, wl0, wl1);
268 wvs.push_back((wl0 + wl1) / 2);
272 auto sp =
spd(spower_s, wvs);
276 static spd rgbRefl2SpectWhite =
277 rgb_to_spect(RGB2SpectLambda, RGBRefl2SpectWhite);
279 static spd rgbRefl2SpectCyan =
280 rgb_to_spect(RGB2SpectLambda, RGBRefl2SpectCyan);
282 static spd rgbRefl2SpectMagenta =
283 rgb_to_spect(RGB2SpectLambda, RGBRefl2SpectMagenta);
285 static spd rgbRefl2SpectYellow =
286 rgb_to_spect(RGB2SpectLambda, RGBRefl2SpectYellow);
288 static spd rgbRefl2SpectRed =
289 rgb_to_spect(RGB2SpectLambda, RGBRefl2SpectRed);
291 static spd rgbRefl2SpectGreen =
292 rgb_to_spect(RGB2SpectLambda, RGBRefl2SpectGreen);
294 static spd rgbRefl2SpectBlue =
295 rgb_to_spect(RGB2SpectLambda, RGBRefl2SpectBlue);
297 static spd rgbIllum2SpectWhite =
298 rgb_to_spect(RGB2SpectLambda, RGBIllum2SpectWhite);
300 static spd rgbIllum2SpectCyan =
301 rgb_to_spect(RGB2SpectLambda, RGBIllum2SpectCyan);
303 static spd rgbIllum2SpectBlue =
304 rgb_to_spect(RGB2SpectLambda, RGBIllum2SpectBlue);
306 static spd rgbIllum2SpectGreen =
307 rgb_to_spect(RGB2SpectLambda, RGBIllum2SpectGreen);
309 static spd rgbIllum2SpectRed =
310 rgb_to_spect(RGB2SpectLambda, RGBIllum2SpectRed);
312 static spd rgbIllum2SpectMagenta =
313 rgb_to_spect(RGB2SpectLambda, RGBIllum2SpectMagenta);
315 static spd rgbIllum2SpectYellow =
316 rgb_to_spect(RGB2SpectLambda, RGBIllum2SpectYellow);
318 static spd Xspd = rgb_to_spect(CIE_LAMBDA_REAL, CIE_X);
320 static spd Yspd = rgb_to_spect(CIE_LAMBDA_REAL, CIE_Y);
322 static spd Zspd = rgb_to_spect(CIE_LAMBDA_REAL, CIE_Z);