1 /*
2  * Copyright (c) 2019-2020 Kevin Townsend (KTOWN)
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zsl/colorimetry.h>
8 
9 /**
10  * CIE 1931 2 Degree Standard Observer Color Matching Functions from 380 nm
11  * to 830 nm in 5nm steps.
12  *
13  * @section Using the Color Matching Functions
14  *
15  * The calculation of CIE chromaticity coordinates for a given colored object
16  * requires the multiplication of its spectral power at each wavelength times
17  * the weighting factor from each of the three (X, Y, Z) color matching
18  * functions. Summing these contributions gives three values called the
19  * tristimulus values, from which the chromaticity coordinates are derived.
20  *
21  * For a visual representation of the color matching function see:
22  * https://en.wikipedia.org/wiki/File:CIE_1931_XYZ_Color_Matching_Functions.svg
23  */
24 static const struct zsl_clr_obs_data zsl_clr_obs_2_deg_data = {
25 	.observer = ZSL_CLR_OBS_2_DEG,
26 	.name = "CIE 1931 2 degree standard observer",
27 	.data = {
28 		{ 1.2990000E-04, 3.9200000E-06, 6.0610000E-04, },       /* 360 nm */
29 		{ 2.3210000E-04, 6.9700000E-06, 1.0860000E-03, },       /* 365 nm */
30 		{ 4.1490000E-04, 1.2390000E-05, 1.9460000E-03, },       /* 370 nm */
31 		{ 7.4160000E-04, 2.2020000E-05, 3.4860000E-03, },       /* 375 nm */
32 		{ 1.3680000E-03, 4.0000000E-05, 6.4500000E-04, },       /* 380 nm */
33 		{ 2.2360000E-03, 6.0000000E-05, 1.0550000E-02, },       /* 385 nm */
34 		{ 4.2430000E-03, 1.2000000E-04, 2.0050000E-02, },       /* 390 nm */
35 		{ 7.6500000E-03, 2.1700000E-04, 3.6210000E-02, },       /* 395 nm */
36 		{ 1.4310000E-02, 4.0000000E-04, 6.7850000E-02, },       /* 400 nm */
37 		{ 2.3190000E-02, 6.4000000E-04, 1.1020000E-01, },       /* 405 nm */
38 		{ 4.3510000E-02, 1.2100000E-03, 2.0740000E-01, },       /* 410 nm */
39 		{ 7.7630000E-02, 2.1800000E-03, 3.7130000E-01, },       /* 415 nm */
40 		{ 1.3438000E-01, 4.0000000E-03, 6.4560000E-01, },       /* 420 nm */
41 		{ 2.1477000E-01, 7.3000000E-03, 1.0390500E+00, },       /* 425 nm */
42 		{ 2.8390000E-01, 1.1600000E-02, 1.3856000E+00, },       /* 430 nm */
43 		{ 3.2850000E-01, 1.6840000E-02, 1.6229600E+00, },       /* 435 nm */
44 		{ 3.4828000E-01, 2.3000000E-02, 1.7470600E+00, },       /* 440 nm */
45 		{ 3.4806000E-01, 2.9800000E-02, 1.7826000E+00, },       /* 445 nm */
46 		{ 3.3620000E-01, 3.8000000E-02, 1.7721100E+00, },       /* 450 nm */
47 		{ 3.1870000E-01, 4.8000000E-02, 1.7441000E+00, },       /* 455 nm */
48 		{ 2.9080000E-01, 6.0000000E-02, 1.6692000E+00, },       /* 460 nm */
49 		{ 2.5110000E-01, 7.3900000E-02, 1.5281000E+00, },       /* 465 nm */
50 		{ 1.9536000E-01, 9.0980000E-02, 1.2876400E+00, },       /* 470 nm */
51 		{ 1.4210000E-01, 1.1260000E-01, 1.0419000E+00, },       /* 475 nm */
52 		{ 9.5640000E-02, 1.3902000E-01, 8.1295000E-01, },       /* 480 nm */
53 		{ 5.7950000E-02, 1.6930000E-01, 6.1620000E-01, },       /* 485 nm */
54 		{ 3.2010000E-02, 2.0802000E-01, 4.6518000E-01, },       /* 490 nm */
55 		{ 1.4700000E-02, 2.5860000E-01, 3.5330000E-01, },       /* 495 nm */
56 		{ 4.9000000E-03, 3.2300000E-01, 2.7200000E-01, },       /* 500 nm */
57 		{ 2.4000000E-03, 4.0730000E-01, 2.1230000E-01, },       /* 505 nm */
58 		{ 9.3000000E-03, 5.0300000E-01, 1.5820000E-01, },       /* 510 nm */
59 		{ 2.9100000E-02, 6.0820000E-01, 1.1170000E-01, },       /* 515 nm */
60 		{ 6.3270000E-02, 7.1000000E-01, 7.8250000E-02, },       /* 520 nm */
61 		{ 1.0960000E-01, 7.9320000E-01, 5.7250000E-02, },       /* 525 nm */
62 		{ 1.6550000E-01, 8.6200000E-01, 4.2160000E-02, },       /* 530 nm */
63 		{ 2.2575000E-01, 9.1485000E-01, 2.9840000E-02, },       /* 535 nm */
64 		{ 2.9040000E-01, 9.5400000E-01, 2.0300000E-02, },       /* 540 nm */
65 		{ 3.5970000E-01, 9.8030000E-01, 1.3400000E-02, },       /* 545 nm */
66 		{ 4.3345000E-01, 9.9495000E-01, 8.7500000E-03, },       /* 550 nm */
67 		{ 5.1205000E-01, 1.0000000E+00, 5.7500000E-03, },       /* 555 nm */
68 		{ 5.9450000E-01, 9.9500000E-01, 3.9000000E-03, },       /* 560 nm */
69 		{ 6.7840000E-01, 9.7860000E-01, 2.7500000E-03, },       /* 565 nm */
70 		{ 7.6210000E-01, 9.5200000E-01, 2.1000000E-03, },       /* 570 nm */
71 		{ 8.4250000E-01, 9.1540000E-01, 1.8000000E-03, },       /* 575 nm */
72 		{ 9.1630000E-01, 8.7000000E-01, 1.6500000E-03, },       /* 580 nm */
73 		{ 9.7860000E-01, 8.1630000E-01, 1.4000000E-03, },       /* 585 nm */
74 		{ 1.0263000E+00, 7.5700000E-01, 1.1000000E-03, },       /* 590 nm */
75 		{ 1.0567000E+00, 6.9490000E-01, 1.0000000E-03, },       /* 595 nm */
76 		{ 1.0622000E+00, 6.3100000E-01, 8.0000000E-04, },       /* 600 nm */
77 		{ 1.0456000E+00, 5.6680000E-01, 6.0000000E-04, },       /* 605 nm */
78 		{ 1.0026000E+00, 5.0300000E-01, 3.4000000E-04, },       /* 610 nm */
79 		{ 9.3840000E-01, 4.4120000E-01, 2.4000000E-04, },       /* 615 nm */
80 		{ 8.5450000E-01, 3.8100000E-01, 1.9000000E-04, },       /* 620 nm */
81 		{ 7.5140000E-01, 3.2100000E-01, 1.0000000E-04, },       /* 625 nm */
82 		{ 6.4240000E-01, 2.6500000E-01, 5.0000000E-04, },       /* 630 nm */
83 		{ 5.4190000E-01, 2.1700000E-01, 3.0000000E-04, },       /* 635 nm */
84 		{ 4.4790000E-01, 1.7500000E-01, 2.0000000E-04, },       /* 640 nm */
85 		{ 3.6080000E-01, 1.3800000E-01, 1.0000000E-04, },       /* 645 nm */
86 		{ 2.8350000E-01, 1.0700000E-01, 0.0000000E+00, },       /* 650 nm */
87 		{ 2.1870000E-01, 8.1600000E-02, 0.0000000E+00, },       /* 655 nm */
88 		{ 1.6490000E-01, 6.1000000E-02, 0.0000000E+00, },       /* 660 nm */
89 		{ 1.2120000E-01, 4.4580000E-02, 0.0000000E+00, },       /* 665 nm */
90 		{ 8.7400000E-02, 3.2000000E-02, 0.0000000E+00, },       /* 670 nm */
91 		{ 6.3600000E-02, 2.3200000E-02, 0.0000000E+00, },       /* 675 nm */
92 		{ 4.6770000E-02, 1.7000000E-02, 0.0000000E+00, },       /* 680 nm */
93 		{ 3.2900000E-02, 1.1920000E-02, 0.0000000E+00, },       /* 685 nm */
94 		{ 2.2700000E-02, 8.2100000E-03, 0.0000000E+00, },       /* 690 nm */
95 		{ 1.5840000E-02, 5.7230000E-03, 0.0000000E+00, },       /* 695 nm */
96 		{ 1.1359000E-02, 4.1020000E-03, 0.0000000E+00, },       /* 700 nm */
97 		{ 8.1110000E-03, 2.9290000E-03, 0.0000000E+00, },       /* 705 nm */
98 		{ 5.7900000E-03, 2.0910000E-03, 0.0000000E+00, },       /* 710 nm */
99 		{ 4.1090000E-03, 1.4840000E-03, 0.0000000E+00, },       /* 715 nm */
100 		{ 2.8990000E-03, 1.0470000E-03, 0.0000000E+00, },       /* 720 nm */
101 		{ 2.0490000E-03, 7.4000000E-04, 0.0000000E+00, },       /* 725 nm */
102 		{ 1.4400000E-03, 5.2000000E-04, 0.0000000E+00, },       /* 730 nm */
103 		{ 1.0000000E-03, 3.6100000E-04, 0.0000000E+00, },       /* 735 nm */
104 		{ 6.9000000E-04, 2.4900000E-04, 0.0000000E+00, },       /* 740 nm */
105 		{ 4.7600000E-04, 1.7190000E-04, 0.0000000E+00, },       /* 745 nm */
106 		{ 3.3200000E-04, 1.2000000E-04, 0.0000000E+00, },       /* 750 nm */
107 		{ 2.3500000E-04, 8.4800000E-05, 0.0000000E+00, },       /* 755 nm */
108 		{ 1.6600000E-04, 6.0000000E-05, 0.0000000E+00, },       /* 760 nm */
109 		{ 1.7700000E-04, 4.2400000E-05, 0.0000000E+00, },       /* 765 nm */
110 		{ 8.3000000E-05, 3.0000000E-05, 0.0000000E+00, },       /* 770 nm */
111 		{ 5.9000000E-05, 2.1000000E-05, 0.0000000E+00, },       /* 775 nm */
112 		{ 4.2000000E-05, 1.5000000E-05, 0.0000000E+00, },       /* 780 nm */
113 		{ 2.9350000E-05, 1.0600000E-05, 0.0000000E+00, },       /* 785 nm */
114 		{ 2.0670000E-05, 7.4700000E-06, 0.0000000E+00, },       /* 790 nm */
115 		{ 1.4560000E-05, 5.2600000E-06, 0.0000000E+00, },       /* 795 nm */
116 		{ 1.0250000E-05, 3.7000000E-06, 0.0000000E+00, },       /* 800 nm */
117 		{ 7.2200000E-06, 2.6100000E-06, 0.0000000E+00, },       /* 805 nm */
118 		{ 5.0900000E-06, 1.8400000E-06, 0.0000000E+00, },       /* 810 nm */
119 		{ 3.5800000E-06, 1.2900000E-06, 0.0000000E+00, },       /* 815 nm */
120 		{ 2.5200000E-06, 9.1000000E-07, 0.0000000E+00, },       /* 820 nm */
121 		{ 1.7800000E-06, 6.4000000E-07, 0.0000000E+00, },       /* 825 nm */
122 		{ 1.2500000E-06, 4.5000000E-07, 0.0000000E+00, }        /* 830 nm */
123 	}
124 };
125 
126 /**
127  * CIE 1964 10 degree supplementary standard observer color matching functions
128  * from 380 nm to 830 nm in 5nm steps.
129  */
130 static const struct zsl_clr_obs_data zsl_clr_obs_10_deg_data = {
131 	.observer = ZSL_CLR_OBS_10_DEG,
132 	.name = "CIE 1964 10 degree standard observer",
133 	.data = {
134 		{ 0.000000122200, 0.000000013398, 0.000000535027 },     /* 360 nm */
135 		{ 0.000000919270, 0.000000100650, 0.000004028300 },     /* 365 nm */
136 		{ 0.000005958600, 0.000000651100, 0.000026143700 },     /* 370 nm */
137 		{ 0.000033266000, 0.000003625000, 0.000146220000 },     /* 375 nm */
138 		{ 0.000159952000, 0.000017364000, 0.000704776000 },     /* 380 nm */
139 		{ 0.000662440000, 0.000071560000, 0.002927800000 },     /* 385 nm */
140 		{ 0.002361600000, 0.000253400000, 0.010482200000 },     /* 390 nm */
141 		{ 0.007242300000, 0.000768500000, 0.032344000000 },     /* 395 nm */
142 		{ 0.019109700000, 0.002004400000, 0.086010900000 },     /* 400 nm */
143 		{ 0.043400000000, 0.004509000000, 0.197120000000 },     /* 405 nm */
144 		{ 0.084736000000, 0.008756000000, 0.389366000000 },     /* 410 nm */
145 		{ 0.140638000000, 0.014456000000, 0.656760000000 },     /* 415 nm */
146 		{ 0.204492000000, 0.021391000000, 0.972542000000 },     /* 420 nm */
147 		{ 0.264737000000, 0.029497000000, 1.282500000000 },     /* 425 nm */
148 		{ 0.314679000000, 0.038676000000, 1.553480000000 },     /* 430 nm */
149 		{ 0.357719000000, 0.049602000000, 1.798500000000 },     /* 435 nm */
150 		{ 0.383734000000, 0.062077000000, 1.967280000000 },     /* 440 nm */
151 		{ 0.386726000000, 0.074704000000, 2.027300000000 },     /* 445 nm */
152 		{ 0.370702000000, 0.089456000000, 1.994800000000 },     /* 450 nm */
153 		{ 0.342957000000, 0.106256000000, 1.900700000000 },     /* 455 nm */
154 		{ 0.302273000000, 0.128201000000, 1.745370000000 },     /* 460 nm */
155 		{ 0.254085000000, 0.152761000000, 1.554900000000 },     /* 465 nm */
156 		{ 0.195618000000, 0.185190000000, 1.317560000000 },     /* 470 nm */
157 		{ 0.132349000000, 0.219940000000, 1.030200000000 },     /* 475 nm */
158 		{ 0.080507000000, 0.253589000000, 0.772125000000 },     /* 480 nm */
159 		{ 0.041072000000, 0.297665000000, 0.570060000000 },     /* 485 nm */
160 		{ 0.016172000000, 0.339133000000, 0.415254000000 },     /* 490 nm */
161 		{ 0.005132000000, 0.395379000000, 0.302356000000 },     /* 495 nm */
162 		{ 0.003816000000, 0.460777000000, 0.218502000000 },     /* 500 nm */
163 		{ 0.015444000000, 0.531360000000, 0.159249000000 },     /* 505 nm */
164 		{ 0.037465000000, 0.606741000000, 0.112044000000 },     /* 510 nm */
165 		{ 0.071358000000, 0.685660000000, 0.082248000000 },     /* 515 nm */
166 		{ 0.117749000000, 0.761757000000, 0.060709000000 },     /* 520 nm */
167 		{ 0.172953000000, 0.823330000000, 0.043050000000 },     /* 525 nm */
168 		{ 0.236491000000, 0.875211000000, 0.030451000000 },     /* 530 nm */
169 		{ 0.304213000000, 0.923810000000, 0.020584000000 },     /* 535 nm */
170 		{ 0.376772000000, 0.961988000000, 0.013676000000 },     /* 540 nm */
171 		{ 0.451584000000, 0.982200000000, 0.007918000000 },     /* 545 nm */
172 		{ 0.529826000000, 0.991761000000, 0.003988000000 },     /* 550 nm */
173 		{ 0.616053000000, 0.999110000000, 0.001091000000 },     /* 555 nm */
174 		{ 0.705224000000, 0.997340000000, 0.000000000000 },     /* 560 nm */
175 		{ 0.793832000000, 0.982380000000, 0.000000000000 },     /* 565 nm */
176 		{ 0.878655000000, 0.955552000000, 0.000000000000 },     /* 570 nm */
177 		{ 0.951162000000, 0.915175000000, 0.000000000000 },     /* 575 nm */
178 		{ 1.014160000000, 0.868934000000, 0.000000000000 },     /* 580 nm */
179 		{ 1.074300000000, 0.825623000000, 0.000000000000 },     /* 585 nm */
180 		{ 1.118520000000, 0.777405000000, 0.000000000000 },     /* 590 nm */
181 		{ 1.134300000000, 0.720353000000, 0.000000000000 },     /* 595 nm */
182 		{ 1.123990000000, 0.658341000000, 0.000000000000 },     /* 600 nm */
183 		{ 1.089100000000, 0.593878000000, 0.000000000000 },     /* 605 nm */
184 		{ 1.030480000000, 0.527963000000, 0.000000000000 },     /* 610 nm */
185 		{ 0.950740000000, 0.461834000000, 0.000000000000 },     /* 615 nm */
186 		{ 0.856297000000, 0.398057000000, 0.000000000000 },     /* 620 nm */
187 		{ 0.754930000000, 0.339554000000, 0.000000000000 },     /* 625 nm */
188 		{ 0.647467000000, 0.283493000000, 0.000000000000 },     /* 630 nm */
189 		{ 0.535110000000, 0.228254000000, 0.000000000000 },     /* 635 nm */
190 		{ 0.431567000000, 0.179828000000, 0.000000000000 },     /* 640 nm */
191 		{ 0.343690000000, 0.140211000000, 0.000000000000 },     /* 645 nm */
192 		{ 0.268329000000, 0.107633000000, 0.000000000000 },     /* 650 nm */
193 		{ 0.204300000000, 0.081187000000, 0.000000000000 },     /* 655 nm */
194 		{ 0.152568000000, 0.060281000000, 0.000000000000 },     /* 660 nm */
195 		{ 0.112210000000, 0.044096000000, 0.000000000000 },     /* 665 nm */
196 		{ 0.081260600000, 0.031800400000, 0.000000000000 },     /* 670 nm */
197 		{ 0.057930000000, 0.022601700000, 0.000000000000 },     /* 675 nm */
198 		{ 0.040850800000, 0.015905100000, 0.000000000000 },     /* 680 nm */
199 		{ 0.028623000000, 0.011130300000, 0.000000000000 },     /* 685 nm */
200 		{ 0.019941300000, 0.007748800000, 0.000000000000 },     /* 690 nm */
201 		{ 0.013842000000, 0.005375100000, 0.000000000000 },     /* 695 nm */
202 		{ 0.009576880000, 0.003717740000, 0.000000000000 },     /* 700 nm */
203 		{ 0.006605200000, 0.002564560000, 0.000000000000 },     /* 705 nm */
204 		{ 0.004552630000, 0.001768470000, 0.000000000000 },     /* 710 nm */
205 		{ 0.003144700000, 0.001222390000, 0.000000000000 },     /* 715 nm */
206 		{ 0.002174960000, 0.000846190000, 0.000000000000 },     /* 720 nm */
207 		{ 0.001505700000, 0.000586440000, 0.000000000000 },     /* 725 nm */
208 		{ 0.001044760000, 0.000407410000, 0.000000000000 },     /* 730 nm */
209 		{ 0.000727450000, 0.000284041000, 0.000000000000 },     /* 735 nm */
210 		{ 0.000508258000, 0.000198730000, 0.000000000000 },     /* 740 nm */
211 		{ 0.000356380000, 0.000139550000, 0.000000000000 },     /* 745 nm */
212 		{ 0.000250969000, 0.000098428000, 0.000000000000 },     /* 750 nm */
213 		{ 0.000177730000, 0.000069819000, 0.000000000000 },     /* 755 nm */
214 		{ 0.000126390000, 0.000049737000, 0.000000000000 },     /* 760 nm */
215 		{ 0.000090151000, 0.000035540500, 0.000000000000 },     /* 765 nm */
216 		{ 0.000064525800, 0.000025486000, 0.000000000000 },     /* 770 nm */
217 		{ 0.000046339000, 0.000018338400, 0.000000000000 },     /* 775 nm */
218 		{ 0.000033411700, 0.000013249000, 0.000000000000 },     /* 780 nm */
219 		{ 0.000024209000, 0.000009619600, 0.000000000000 },     /* 785 nm */
220 		{ 0.000017611500, 0.000007012800, 0.000000000000 },     /* 790 nm */
221 		{ 0.000012855000, 0.000005129800, 0.000000000000 },     /* 795 nm */
222 		{ 0.000009413630, 0.000003764730, 0.000000000000 },     /* 800 nm */
223 		{ 0.000006913000, 0.000002770810, 0.000000000000 },     /* 805 nm */
224 		{ 0.000005093470, 0.000002046130, 0.000000000000 },     /* 810 nm */
225 		{ 0.000003767100, 0.000001516770, 0.000000000000 },     /* 815 nm */
226 		{ 0.000002795310, 0.000001128090, 0.000000000000 },     /* 820 nm */
227 		{ 0.000002082000, 0.000000842160, 0.000000000000 },     /* 825 nm */
228 		{ 0.000001553140, 0.000000629700, 0.000000000000 }      /* 830 nm */
229 		}
230 	};
231 
232 	void
zsl_clr_obs_get(enum zsl_clr_obs obs,const struct zsl_clr_obs_data ** data)233 	zsl_clr_obs_get(enum zsl_clr_obs obs, const struct zsl_clr_obs_data **data)
234 	{
235 		switch (obs) {
236 		case ZSL_CLR_OBS_10_DEG:
237 			*data = &zsl_clr_obs_10_deg_data;
238 			break;
239 		case ZSL_CLR_OBS_2_DEG:
240 			*data = &zsl_clr_obs_2_deg_data;
241 			break;
242 		}
243 	}
244