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
34void 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
43void 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
52void 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
61cmsFloat64Number 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
68cmsFloat64Number 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
77cmsFloat64Number 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
91void 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
98static
99cmsBool CloseEnough(cmsFloat64Number a, cmsFloat64Number b)
100{
101 return fabs(b - a) < (1.0 / 65535.0);
102}
103
104
105cmsBool 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
121void 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)
136cmsBool 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
164cmsBool 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
177void 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