3 #include <color/specdata.hpp>
4 #include <color/specutils.hpp>
5 #include <color/wave.hpp>
7 #include <math3d/vec3.hpp>
10 using namespace ptracey;
15 WaveLength wave_start;
17 std::map<WaveLength, Power> wavelength_power;
21 static spd random() {
return spd(); }
22 static spd random(Real mn, Real mx) {
24 auto pw = ss.powers();
25 std::vector<Real> pws;
26 for (uint i = 0; i < (uint)pw.size(); i++) {
27 pws.push_back(random_real(mn, mx));
30 auto wlength = ss.wavelengths();
31 ss =
spd(power_spd, wlength);
35 static spd zeros_like(
const spd &s) {
36 auto waves = s.wavelengths();
37 std::vector<Power> pws(waves.size(), 0.0);
39 auto sp =
spd(powers, waves);
45 spd(uint size = 471 / SPD_STRIDE) {
46 wavelength_power.clear();
47 std::vector<Power> powers;
48 for (uint i = 0; i < size; i++) {
49 powers.push_back(0.0);
52 auto ws = linspace<WaveLength>(VISIBLE_LAMBDA_START,
55 for (uint i = 0; i < powers.size(); i++) {
56 auto pw = make_pair(ws[i], powers[i]);
57 wavelength_power.insert(pw);
62 : wave_start(wstart) {
63 wavelength_power.clear();
64 for (uint i = 0; i < sampled_powers.
size(); i++) {
65 Power power = sampled_powers[i];
66 WaveLength wavelength =
67 i +
static_cast<WaveLength
>(wstart);
68 auto pw = make_pair(wavelength, power);
69 wavelength_power.insert(pw);
71 wave_end = wave_start +
static_cast<WaveLength
>(
72 sampled_powers.
size() - 1);
75 const std::vector<WaveLength> &wlengths) {
76 wavelength_power.clear();
78 sampled_powers.
size() == (uint)wlengths.size(),
79 sampled_powers.
size(), (uint)wlengths.size());
80 for (
auto wl : wlengths) {
82 throw std::runtime_error(
83 "wavelength can not be less than 0");
86 std::map<WaveLength, Power> temp;
87 for (uint i = 0; i < (uint)wlengths.size(); i++) {
89 make_pair(wlengths[i], sampled_powers[i]));
91 std::vector<WaveLength> nwlengths(wlengths.size());
93 std::copy(wlengths.begin(), wlengths.end(),
96 std::sort(nwlengths.begin(), nwlengths.end(),
97 [](
auto i,
auto j) { return i < j; });
99 wave_start = nwlengths[0];
100 wave_end = nwlengths[wlengths.size() - 1];
101 for (uint i = 0; i < nwlengths.size(); i++) {
103 make_pair(nwlengths[i], temp.at(nwlengths[i]));
104 wavelength_power.insert(pw);
125 spd(uint wave_range,
const std::function<WaveLength(uint)>
126 &wavelength_generator,
127 const std::function<Power(WaveLength)>
129 wave_start = wavelength_generator(0);
130 wave_end = wavelength_generator(wave_range - 1);
131 wavelength_power.clear();
132 for (uint i = 1; i < wave_range; i++) {
133 WaveLength wave = wavelength_generator(i);
134 Power power_value = power_generator(wave);
135 wavelength_power.insert(make_pair(wave, power_value));
138 template <
typename V>
139 void fill_with_stride(std::vector<V> &dest,
140 const std::vector<V> &srcv,
141 unsigned int stride) {
142 for (
unsigned int i = 0; i < (uint)srcv.size();
144 dest.push_back(srcv[i]);
147 spd(
const path &csv_path,
148 const std::string &wave_col_name =
"wavelength",
149 const std::string &power_col_name =
"power",
150 const char &sep =
',',
151 const unsigned int stride = SPD_STRIDE,
152 const std::function<WaveLength(WaveLength)>
153 &wave_transform = [](
auto j) {
return j; },
154 const std::function<Power(Power)> &power_transform =
155 [](
auto j) {
return j; }) {
156 wavelength_power.clear();
157 path csv_path_abs = RUNTIME_PATH / csv_path;
161 std::vector<Power> temp;
163 temp = doc.GetColumn<Power>(power_col_name);
164 }
catch (
const std::out_of_range &err) {
165 throw std::runtime_error(std::string(err.what()) +
166 " :: " + power_col_name +
168 csv_path_abs.string());
170 std::vector<Power> powers;
171 fill_with_stride<Power>(powers, temp, stride);
172 std::vector<WaveLength> tempv;
174 tempv = doc.GetColumn<WaveLength>(wave_col_name);
175 }
catch (
const std::out_of_range &error) {
176 throw std::runtime_error(std::string(error.what()) +
177 " :: " + wave_col_name +
179 csv_path_abs.string());
181 COMP_CHECK(tempv.size() == temp.size(), tempv.size(),
183 std::vector<WaveLength> wlengths;
184 fill_with_stride<WaveLength>(wlengths, tempv, stride);
186 wavelength_power.clear();
187 COMP_CHECK(powers.size() == wlengths.size(),
188 powers.size(), wlengths.size());
189 for (
auto wl : wlengths) {
191 throw std::runtime_error(
192 "wavelength can not be less than 0");
195 std::map<WaveLength, Power> tempwp;
196 for (uint i = 0; i < (uint)wlengths.size(); i++) {
197 auto wave_value = wave_transform(wlengths[i]);
198 auto power_value = power_transform(powers[i]);
199 tempwp.insert(make_pair(wave_value, power_value));
201 std::sort(wlengths.begin(), wlengths.end(),
202 [](
auto i,
auto j) { return i < j; });
203 wave_start = wlengths[0];
204 wave_end = wlengths[wlengths.size() - 1];
205 for (uint i = 0; i < wlengths.size(); i++) {
207 make_pair(wlengths[i], tempwp.at(wlengths[i]));
208 wavelength_power.insert(pw);
215 void resample(
const spd &s);
216 void resample(
const WaveLength &waveLStart,
217 const WaveLength &waveLEnd,
218 const uint &outSize);
219 spd resample_c(
const spd &s)
const;
220 spd resample_c(
const uint &outSize)
const;
221 spd resample_c(
const WaveLength &waveLStart,
222 const WaveLength &waveLEnd,
223 const uint &outSize)
const;
226 std::vector<Power> ps;
227 for (
auto pw : wavelength_power) {
228 ps.push_back(pw.second);
232 std::vector<WaveLength> wavelengths()
const {
233 std::vector<WaveLength> ps;
234 for (
auto pw : wavelength_power) {
235 ps.push_back(pw.first);
237 std::sort(ps.begin(), ps.end(),
238 [](
auto i,
auto j) { return i < j; });
241 spd interpolate(Real low = 0.0,
242 Real high = FLT_MAX)
const {
245 normal_power.interpolate(low, high);
246 auto wlengths = wavelengths();
247 auto ss =
spd(normal_power2, wlengths);
250 spd clamp(Power low = 0.0, Power high = FLT_MAX)
const {
252 std::vector<Power> nvs;
253 for (
auto np : normal_power.
values) {
254 nvs.push_back(dclamp<Power>(np, low, high));
257 auto wlengths = wavelengths();
258 auto ss =
spd(normal_power2, wlengths);
261 spd normalized()
const {
return interpolate(0.0, 1.0); }
263 auto spd = normalized();
266 int min_wave()
const {
267 auto it = std::min_element(
268 wavelength_power.begin(), wavelength_power.end(),
269 [](
const auto &k1,
const auto &k2) {
270 return k1.first < k2.first;
273 it == wavelength_power.end() ? -1.0 : it->first;
276 int max_wave()
const {
277 auto it = std::max_element(
278 wavelength_power.begin(), wavelength_power.end(),
279 [](
const auto &k1,
const auto &k2) {
280 return k1.first < k2.first;
283 it == wavelength_power.end() ? -1.0 : it->first;
286 Power min_power()
const {
287 auto it = std::min_element(
288 wavelength_power.begin(), wavelength_power.end(),
289 [](
const auto &k1,
const auto &k2) {
290 return k1.second < k2.second;
293 it == wavelength_power.end() ? -1.0 : it->second;
296 Power max_power()
const {
297 auto it = std::max_element(
298 wavelength_power.begin(), wavelength_power.end(),
299 [](
const auto &k1,
const auto &k2) {
300 return k1.second < k2.second;
303 it == wavelength_power.end() ? -1.0 : it->second;
307 return (uint)wavelength_power.size();
309 Power integrate(
const spd &nspd)
const {
310 COMP_CHECK(size() == nspd.size(), size(), nspd.size());
311 WaveLength x1 = min_wave();
312 WaveLength x2 = max_wave();
314 Power stepsize = (x2 - x1) /
static_cast<Power
>(size());
316 auto waves = wavelengths();
317 for (
unsigned int i = 0; i < size(); i++) {
318 auto pw = wavelength_power.at(waves[i]);
319 auto v = nspd[waves[i]];
322 return val * stepsize;
324 void apply(Power pvalue,
325 const std::function<Power(Power, Power)> &fn) {
326 for (
auto &pr : wavelength_power) {
327 pr.second = fn(pr.second, pvalue);
332 const std::function<Power(Power, Power)> &fn)
const {
333 std::vector<WaveLength> waves;
334 std::vector<Power> powers;
335 for (
auto &pr : wavelength_power) {
336 Power p = fn(pr.second, pvalue);
337 waves.push_back(pr.first);
341 auto sp =
spd(sw, waves);
344 bool apply(WaveLength wave_length, Power pvalue,
345 const std::function<Power(Power, Power)> &fn) {
346 if (in(wave_length)) {
347 Power power_value = wavelength_power.at(wave_length);
348 wavelength_power[wave_length] =
349 fn(power_value, pvalue);
354 bool apply(
const spd &s,
357 auto waves = wavelengths();
358 auto swaves = s.wavelengths();
360 if (waves == swaves) {
381 const std::function<
spd(
spd,
spd)> &eqfn,
382 const std::function<
bool(
383 spd, WaveLength, Power)> &uneqfn)
const {
385 if (apply(s, eqfn, ss)) {
388 auto swaves = s.wavelengths();
389 for (
const auto &w : swaves) {
391 if (!uneqfn(ss, w, spower))
392 ss.update(w, spower);
396 Power interpolate_wave_power(WaveLength wl)
const {
398 auto waves = wavelengths();
399 auto wsize = (int)waves.size();
401 std::lower_bound(waves.begin(), waves.end(), wl);
402 if (lower != waves.end()) {
403 auto index = std::distance(waves.begin(), lower);
405 throw std::runtime_error(
406 "wavelength is below the available range");
408 auto index2 = index - 1;
409 Power p1 = wavelength_power.at(waves[index]);
410 Power p2 = wavelength_power.at(waves[index2]);
411 return (p1 + p2) / 2.0;
414 throw std::runtime_error(
415 "wavelength is above the available range");
417 Power operator[](WaveLength wave_length)
const {
418 if (in(wave_length)) {
419 Power p = wavelength_power.at(wave_length);
422 return interpolate_wave_power(wave_length);
424 bool in(WaveLength wave_length)
const {
425 auto it = wavelength_power.find(wave_length);
426 if (it != wavelength_power.end()) {
431 void insert(WaveLength wave_length, Power pvalue) {
432 if (!in(wave_length)) {
433 wavelength_power.insert(
434 make_pair(wave_length, pvalue));
437 void update(WaveLength wave_length, Power pvalue) {
438 wavelength_power.insert_or_assign(wave_length, pvalue);
440 void add(WaveLength wave_length, Power pvalue) {
442 apply(wave_length, pvalue,
443 [](Power i, Power j) {
return i + j; });
445 update(wave_length, pvalue);
448 void scale(Power pvalue) {
449 apply(pvalue, [](Power i, Power j) {
return i * j; });
451 spd operator*(Power pvalue)
const {
452 return apply_c(pvalue,
453 [](
auto i,
auto j) {
return i * j; });
455 spd &operator*=(Power pvalue) {
456 apply(pvalue, [](Power i, Power j) {
return i * j; });
459 friend spd operator*(Power pvalue,
const spd &s) {
462 spd operator-(Power pvalue)
const {
463 return apply_c(pvalue,
464 [](
auto i,
auto j) {
return i - j; });
466 friend spd operator-(Power pvalue,
const spd &s) {
470 spd operator+(Power pvalue)
const {
471 return apply_c(pvalue,
472 [](
auto i,
auto j) {
return i + j; });
474 friend spd operator+(Power pvalue,
const spd &s) {
477 spd &operator+=(Power pvalue) {
478 apply(pvalue, [](Power i, Power j) {
return i + j; });
481 spd &operator+=(
const spd &s) {
484 auto pwrs = i.powers() + j.powers();
485 return spd(pwrs, i.wavelengths());
491 throw std::runtime_error(
"spd's don't match");
496 auto rho_rspd =
spd(CSV_PARENT /
"rho-r-2012.csv",
497 WCOL_NAME, PCOL_NAME, SEP, SPD_STRIDE);
499 static spd rho_r = rho_rspd.normalized();
501 auto rho_gspd =
spd(CSV_PARENT /
"rho-g-2012.csv",
502 WCOL_NAME, PCOL_NAME, SEP, SPD_STRIDE);
504 static spd rho_g = rho_gspd;
506 auto rho_bspd =
spd(CSV_PARENT /
"rho-b-2012.csv",
507 WCOL_NAME, PCOL_NAME, SEP, SPD_STRIDE);
509 static spd rho_b = rho_bspd;
512 spd(CSV_PARENT /
"cie-x-bar-1964.csv", WCOL_NAME,
513 PCOL_NAME, SEP, SPD_STRIDE);
515 static spd cie_xbar_spd = cie_xbarspd.normalized();
518 spd(CSV_PARENT /
"cie-y-bar-1964.csv", WCOL_NAME,
519 PCOL_NAME, SEP, SPD_STRIDE);
521 static spd cie_ybar_spd = cie_ybarspd.normalized();
524 spd(CSV_PARENT /
"cie-z-bar-1964.csv", WCOL_NAME,
525 PCOL_NAME, SEP, SPD_STRIDE);
527 static spd cie_zbar_spd = cie_zbarspd.normalized();
529 auto stand_d65 =
spd(CSV_PARENT /
"cie-d65-standard.csv",
530 WCOL_NAME, PCOL_NAME, SEP, SPD_STRIDE);
532 static spd standard_d65 = stand_d65.normalized();
535 Power get_cie_val(
const spd &qlambda,
const spd &cie_bar) {
537 auto qwaves = qlambda.wavelengths();
538 auto qmaxwave = qlambda.max_wave();
539 auto qminwave = qlambda.min_wave();
540 auto qwsize = (uint)qwaves.size();
541 auto cie = cie_bar.resample_c(qminwave, qmaxwave, qwsize);
542 for (
const auto &wave : qwaves) {
543 sum += qlambda[wave] * cie[wave];
545 auto scale = (qmaxwave - qminwave) / Real(qwsize);
549 Power get_cie_val(
const spd &qlambda,
const spd &rlambda,
550 const spd &cie_bar) {
552 auto rmaxwave = rlambda.max_wave();
553 auto rminwave = rlambda.min_wave();
554 auto rwaves = rlambda.wavelengths();
555 auto rwsize = (uint)rwaves.size();
557 qlambda.resample_c(rminwave, rmaxwave, rwsize);
558 spd cie = cie_bar.resample_c(rminwave, rmaxwave, rwsize);
559 auto waves = qlambda.wavelengths();
560 for (
const auto &wave : rwaves) {
561 sum += q_lambda[wave] * rlambda[wave] * cie[wave];
564 (rmaxwave - rminwave) / Real(CIE_Y_integral * rwsize);
569 Power get_cie_x(
const spd &qlambda) {
570 return get_cie_val(qlambda, cie_xbar_spd);
573 Power get_cie_x(
const spd &qlambda,
const spd &rlambda) {
574 return get_cie_val(qlambda, rlambda, cie_xbar_spd);
577 Power get_cie_y(
const spd &qlambda) {
578 return get_cie_val(qlambda, cie_ybar_spd);
581 Power get_cie_y(
const spd &qlambda,
const spd &rlambda) {
582 return get_cie_val(qlambda, rlambda, cie_ybar_spd);
585 Power get_cie_z(
const spd &qlambda) {
586 return get_cie_val(qlambda, cie_zbar_spd);
589 Power get_cie_z(
const spd &qlambda,
const spd &rlambda) {
590 return get_cie_val(qlambda, rlambda, cie_zbar_spd);
593 void get_cie_values(
const spd &qlambda, Power &x, Power &y,
595 x = get_cie_x(qlambda);
596 y = get_cie_y(qlambda);
597 z = get_cie_z(qlambda);
600 void get_cie_values(
const spd &qlambda,
const spd &rlambda,
601 Power &x, Power &y, Power &z) {
602 x = get_cie_x(qlambda, rlambda);
603 y = get_cie_y(qlambda, rlambda);
604 z = get_cie_z(qlambda, rlambda);
607 void get_cie_values(
const spd &qlambda,
vec3 &xyz) {
609 get_cie_values(qlambda, x, y, z);
611 Power sum = xyz.sum();
617 void get_cie_values(
const spd &qlambda,
const spd &rlambda,
620 get_cie_values(qlambda, rlambda, x, y, z);
622 Power sum = xyz.sum();
628 inline std::ostream &operator<<(std::ostream &out,
630 auto waves = ss.wavelengths();
631 auto powers = ss.powers();
632 return out <<
"spectrum power distribution: " << std::endl
633 <<
"waves " << waves << std::endl
634 <<
"powers: " << powers << std::endl;