1 | //--------------------------------------------------------------------------------- |
2 | // |
3 | // Little Color Management System |
4 | // Copyright (c) 1998-2017 Marti Maria Saguer |
5 | // |
6 | // Permission is hereby granted, free of charge, to any person obtaining |
7 | // a copy of this software and associated documentation files (the "Software"), |
8 | // to deal in the Software without restriction, including without limitation |
9 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, |
10 | // and/or sell copies of the Software, and to permit persons to whom the Software |
11 | // is furnished to do so, subject to the following conditions: |
12 | // |
13 | // The above copyright notice and this permission notice shall be included in |
14 | // all copies or substantial portions of the Software. |
15 | // |
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
17 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO |
18 | // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
19 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
20 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
21 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
22 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
23 | // |
24 | //--------------------------------------------------------------------------------- |
25 | // |
26 | |
27 | #include "lcms2_internal.h" |
28 | |
29 | |
30 | #define DSWAP(x, y) {cmsFloat64Number tmp = (x); (x)=(y); (y)=tmp;} |
31 | |
32 | |
33 | // Initiate a vector |
34 | void CMSEXPORT _cmsVEC3init(cmsContext ContextID, cmsVEC3* r, cmsFloat64Number x, cmsFloat64Number y, cmsFloat64Number z) |
35 | { |
36 | cmsUNUSED_PARAMETER(ContextID); |
37 | r -> n[VX] = x; |
38 | r -> n[VY] = y; |
39 | r -> n[VZ] = z; |
40 | } |
41 | |
42 | // Vector subtraction |
43 | void CMSEXPORT _cmsVEC3minus(cmsContext ContextID, cmsVEC3* r, const cmsVEC3* a, const cmsVEC3* b) |
44 | { |
45 | cmsUNUSED_PARAMETER(ContextID); |
46 | r -> n[VX] = a -> n[VX] - b -> n[VX]; |
47 | r -> n[VY] = a -> n[VY] - b -> n[VY]; |
48 | r -> n[VZ] = a -> n[VZ] - b -> n[VZ]; |
49 | } |
50 | |
51 | // Vector cross product |
52 | void CMSEXPORT _cmsVEC3cross(cmsContext ContextID, cmsVEC3* r, const cmsVEC3* u, const cmsVEC3* v) |
53 | { |
54 | cmsUNUSED_PARAMETER(ContextID); |
55 | r ->n[VX] = u->n[VY] * v->n[VZ] - v->n[VY] * u->n[VZ]; |
56 | r ->n[VY] = u->n[VZ] * v->n[VX] - v->n[VZ] * u->n[VX]; |
57 | r ->n[VZ] = u->n[VX] * v->n[VY] - v->n[VX] * u->n[VY]; |
58 | } |
59 | |
60 | // Vector dot product |
61 | cmsFloat64Number CMSEXPORT _cmsVEC3dot(cmsContext ContextID, const cmsVEC3* u, const cmsVEC3* v) |
62 | { |
63 | cmsUNUSED_PARAMETER(ContextID); |
64 | return u->n[VX] * v->n[VX] + u->n[VY] * v->n[VY] + u->n[VZ] * v->n[VZ]; |
65 | } |
66 | |
67 | // Euclidean length |
68 | cmsFloat64Number CMSEXPORT _cmsVEC3length(cmsContext ContextID, const cmsVEC3* a) |
69 | { |
70 | cmsUNUSED_PARAMETER(ContextID); |
71 | return sqrt(a ->n[VX] * a ->n[VX] + |
72 | a ->n[VY] * a ->n[VY] + |
73 | a ->n[VZ] * a ->n[VZ]); |
74 | } |
75 | |
76 | // Euclidean distance |
77 | cmsFloat64Number CMSEXPORT _cmsVEC3distance(cmsContext ContextID, const cmsVEC3* a, const cmsVEC3* b) |
78 | { |
79 | cmsFloat64Number d1 = a ->n[VX] - b ->n[VX]; |
80 | cmsFloat64Number d2 = a ->n[VY] - b ->n[VY]; |
81 | cmsFloat64Number d3 = a ->n[VZ] - b ->n[VZ]; |
82 | |
83 | cmsUNUSED_PARAMETER(ContextID); |
84 | |
85 | return sqrt(d1*d1 + d2*d2 + d3*d3); |
86 | } |
87 | |
88 | |
89 | |
90 | // 3x3 Identity |
91 | void CMSEXPORT _cmsMAT3identity(cmsContext ContextID, cmsMAT3* a) |
92 | { |
93 | _cmsVEC3init(ContextID, &a-> v[0], 1.0, 0.0, 0.0); |
94 | _cmsVEC3init(ContextID, &a-> v[1], 0.0, 1.0, 0.0); |
95 | _cmsVEC3init(ContextID, &a-> v[2], 0.0, 0.0, 1.0); |
96 | } |
97 | |
98 | static |
99 | cmsBool CloseEnough(cmsFloat64Number a, cmsFloat64Number b) |
100 | { |
101 | return fabs(b - a) < (1.0 / 65535.0); |
102 | } |
103 | |
104 | |
105 | cmsBool CMSEXPORT _cmsMAT3isIdentity(cmsContext ContextID, const cmsMAT3* a) |
106 | { |
107 | cmsMAT3 Identity; |
108 | int i, j; |
109 | |
110 | _cmsMAT3identity(ContextID, &Identity); |
111 | |
112 | for (i=0; i < 3; i++) |
113 | for (j=0; j < 3; j++) |
114 | if (!CloseEnough(a ->v[i].n[j], Identity.v[i].n[j])) return FALSE; |
115 | |
116 | return TRUE; |
117 | } |
118 | |
119 | |
120 | // Multiply two matrices |
121 | void CMSEXPORT _cmsMAT3per(cmsContext ContextID, cmsMAT3* r, const cmsMAT3* a, const cmsMAT3* b) |
122 | { |
123 | #define ROWCOL(i, j) \ |
124 | a->v[i].n[0]*b->v[0].n[j] + a->v[i].n[1]*b->v[1].n[j] + a->v[i].n[2]*b->v[2].n[j] |
125 | |
126 | _cmsVEC3init(ContextID, &r-> v[0], ROWCOL(0,0), ROWCOL(0,1), ROWCOL(0,2)); |
127 | _cmsVEC3init(ContextID, &r-> v[1], ROWCOL(1,0), ROWCOL(1,1), ROWCOL(1,2)); |
128 | _cmsVEC3init(ContextID, &r-> v[2], ROWCOL(2,0), ROWCOL(2,1), ROWCOL(2,2)); |
129 | |
130 | #undef ROWCOL //(i, j) |
131 | } |
132 | |
133 | |
134 | |
135 | // Inverse of a matrix b = a^(-1) |
136 | cmsBool CMSEXPORT _cmsMAT3inverse(cmsContext ContextID, const cmsMAT3* a, cmsMAT3* b) |
137 | { |
138 | cmsFloat64Number det, c0, c1, c2; |
139 | cmsUNUSED_PARAMETER(ContextID); |
140 | |
141 | c0 = a -> v[1].n[1]*a -> v[2].n[2] - a -> v[1].n[2]*a -> v[2].n[1]; |
142 | c1 = -a -> v[1].n[0]*a -> v[2].n[2] + a -> v[1].n[2]*a -> v[2].n[0]; |
143 | c2 = a -> v[1].n[0]*a -> v[2].n[1] - a -> v[1].n[1]*a -> v[2].n[0]; |
144 | |
145 | det = a -> v[0].n[0]*c0 + a -> v[0].n[1]*c1 + a -> v[0].n[2]*c2; |
146 | |
147 | if (fabs(det) < MATRIX_DET_TOLERANCE) return FALSE; // singular matrix; can't invert |
148 | |
149 | b -> v[0].n[0] = c0/det; |
150 | b -> v[0].n[1] = (a -> v[0].n[2]*a -> v[2].n[1] - a -> v[0].n[1]*a -> v[2].n[2])/det; |
151 | b -> v[0].n[2] = (a -> v[0].n[1]*a -> v[1].n[2] - a -> v[0].n[2]*a -> v[1].n[1])/det; |
152 | b -> v[1].n[0] = c1/det; |
153 | b -> v[1].n[1] = (a -> v[0].n[0]*a -> v[2].n[2] - a -> v[0].n[2]*a -> v[2].n[0])/det; |
154 | b -> v[1].n[2] = (a -> v[0].n[2]*a -> v[1].n[0] - a -> v[0].n[0]*a -> v[1].n[2])/det; |
155 | b -> v[2].n[0] = c2/det; |
156 | b -> v[2].n[1] = (a -> v[0].n[1]*a -> v[2].n[0] - a -> v[0].n[0]*a -> v[2].n[1])/det; |
157 | b -> v[2].n[2] = (a -> v[0].n[0]*a -> v[1].n[1] - a -> v[0].n[1]*a -> v[1].n[0])/det; |
158 | |
159 | return TRUE; |
160 | } |
161 | |
162 | |
163 | // Solve a system in the form Ax = b |
164 | cmsBool CMSEXPORT _cmsMAT3solve(cmsContext ContextID, cmsVEC3* x, cmsMAT3* a, cmsVEC3* b) |
165 | { |
166 | cmsMAT3 m, a_1; |
167 | |
168 | memmove(&m, a, sizeof(cmsMAT3)); |
169 | |
170 | if (!_cmsMAT3inverse(ContextID, &m, &a_1)) return FALSE; // Singular matrix |
171 | |
172 | _cmsMAT3eval(ContextID, x, &a_1, b); |
173 | return TRUE; |
174 | } |
175 | |
176 | // Evaluate a vector across a matrix |
177 | void CMSEXPORT _cmsMAT3eval(cmsContext ContextID, cmsVEC3* r, const cmsMAT3* a, const cmsVEC3* v) |
178 | { |
179 | cmsUNUSED_PARAMETER(ContextID); |
180 | |
181 | r->n[VX] = a->v[0].n[VX]*v->n[VX] + a->v[0].n[VY]*v->n[VY] + a->v[0].n[VZ]*v->n[VZ]; |
182 | r->n[VY] = a->v[1].n[VX]*v->n[VX] + a->v[1].n[VY]*v->n[VY] + a->v[1].n[VZ]*v->n[VZ]; |
183 | r->n[VZ] = a->v[2].n[VX]*v->n[VX] + a->v[2].n[VY]*v->n[VY] + a->v[2].n[VZ]*v->n[VZ]; |
184 | } |
185 | |
186 | |
187 | |