/src/libreoffice/include/basegfx/matrix/hommatrixtemplate.hxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
5 | | * This Source Code Form is subject to the terms of the Mozilla Public |
6 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
7 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
11 | | * Licensed to the Apache Software Foundation (ASF) under one or more |
12 | | * contributor license agreements. See the NOTICE file distributed |
13 | | * with this work for additional information regarding copyright |
14 | | * ownership. The ASF licenses this file to you under the Apache |
15 | | * License, Version 2.0 (the "License"); you may not use this file |
16 | | * except in compliance with the License. You may obtain a copy of |
17 | | * the License at http://www.apache.org/licenses/LICENSE-2.0 . |
18 | | */ |
19 | | |
20 | | #pragma once |
21 | | |
22 | | #include <sal/types.h> |
23 | | #include <basegfx/numeric/ftools.hxx> |
24 | | #include <cassert> |
25 | | #include <cmath> |
26 | | |
27 | | namespace basegfx::internal |
28 | | { |
29 | | |
30 | | inline constexpr double implGetDefaultValue(sal_uInt16 nRow, sal_uInt16 nColumn) |
31 | 4.58M | { |
32 | 4.58M | if(nRow == nColumn) |
33 | 1.15M | return 1.0; |
34 | 3.43M | return 0.0; |
35 | 4.58M | } |
36 | | |
37 | | template < sal_uInt16 RowSize > class ImplMatLine |
38 | | { |
39 | | double mfValue[RowSize]; |
40 | | |
41 | | public: |
42 | | ImplMatLine() = default; |
43 | | |
44 | | explicit ImplMatLine(sal_uInt16 nRow) |
45 | | { |
46 | | for(sal_uInt16 a(0); a < RowSize; a++) |
47 | | { |
48 | | mfValue[a] = implGetDefaultValue(nRow, a); |
49 | | } |
50 | | } |
51 | | |
52 | | double get(sal_uInt16 nColumn) const |
53 | 9.46M | { |
54 | 9.46M | return mfValue[nColumn]; |
55 | 9.46M | } |
56 | | |
57 | | void set(sal_uInt16 nColumn, const double& rValue) |
58 | 4.90M | { |
59 | 4.90M | mfValue[nColumn] = rValue; |
60 | 4.90M | } |
61 | | }; |
62 | | |
63 | | template < sal_uInt16 RowSize > class ImplHomMatrixTemplate |
64 | | { |
65 | | ImplMatLine< RowSize > maLine[RowSize]; |
66 | | |
67 | | public: |
68 | | // Is last line used? |
69 | | bool isLastLineDefault() const |
70 | 28.1k | { |
71 | 140k | for(sal_uInt16 a(0); a < RowSize; a++) |
72 | 112k | { |
73 | 112k | const double fDefault(implGetDefaultValue((RowSize - 1), a)); |
74 | 112k | const double fLineValue(maLine[RowSize-1].get(a)); |
75 | | |
76 | 112k | if(fDefault != fLineValue) |
77 | 0 | { |
78 | 0 | return false; |
79 | 0 | } |
80 | 112k | } |
81 | 28.1k | return true; |
82 | 28.1k | } |
83 | | |
84 | | ImplHomMatrixTemplate() |
85 | 186k | { |
86 | | // complete initialization with identity matrix, all lines |
87 | | // were initialized with a trailing 1 followed by 0's. |
88 | 932k | for(sal_uInt16 a(0); a < RowSize; a++) |
89 | 745k | { |
90 | 3.72M | for(sal_uInt16 b(0); b < RowSize; b++) |
91 | 2.98M | maLine[a].set(b, implGetDefaultValue(a, b) ); |
92 | 745k | } |
93 | 186k | } |
94 | | |
95 | | ImplHomMatrixTemplate(const ImplHomMatrixTemplate& rToBeCopied) |
96 | 89.2k | { |
97 | 89.2k | operator=(rToBeCopied); |
98 | 89.2k | } |
99 | | |
100 | | ImplHomMatrixTemplate& operator=(const ImplHomMatrixTemplate& rToBeCopied) |
101 | 111k | { |
102 | 111k | if (this != &rToBeCopied) |
103 | 111k | { |
104 | | // complete initialization using copy |
105 | 558k | for(sal_uInt16 a(0); a < RowSize; a++) |
106 | 446k | { |
107 | 446k | maLine[a] = rToBeCopied.maLine[a]; |
108 | 446k | } |
109 | 111k | } |
110 | 111k | return *this; |
111 | 111k | } |
112 | | |
113 | 22.4k | static sal_uInt16 getEdgeLength() { return RowSize; } |
114 | | |
115 | | double get(sal_uInt16 nRow, sal_uInt16 nColumn) const |
116 | 9.35M | { |
117 | 9.35M | return maLine[nRow].get(nColumn); |
118 | 9.35M | } |
119 | | |
120 | | void set(sal_uInt16 nRow, sal_uInt16 nColumn, const double& rValue) |
121 | 1.92M | { |
122 | 1.92M | maLine[nRow].set(nColumn, rValue); |
123 | 1.92M | } |
124 | | |
125 | | // Left-upper decomposition |
126 | | bool ludcmp(sal_uInt16 nIndex[], sal_Int16& nParity) |
127 | 22.4k | { |
128 | 22.4k | double fBig, fSum, fDum; |
129 | 22.4k | double fStorage[RowSize]; |
130 | 22.4k | sal_uInt16 a, b, c; |
131 | | |
132 | | // #i30874# Initialize nAMax (compiler warns) |
133 | 22.4k | sal_uInt16 nAMax = 0; |
134 | | |
135 | 22.4k | nParity = 1; |
136 | | |
137 | | // Calc the max of each line. If a line is empty, |
138 | | // stop immediately since matrix is not invertible then. |
139 | 112k | for(a = 0; a < RowSize; a++) |
140 | 89.9k | { |
141 | 89.9k | fBig = 0.0; |
142 | | |
143 | 449k | for(b = 0; b < RowSize; b++) |
144 | 359k | { |
145 | 359k | double fTemp(fabs(get(a, b))); |
146 | | |
147 | 359k | if(::basegfx::fTools::more(fTemp, fBig)) |
148 | 95.9k | { |
149 | 95.9k | fBig = fTemp; |
150 | 95.9k | } |
151 | 359k | } |
152 | | |
153 | 89.9k | if(::basegfx::fTools::equalZero(fBig)) |
154 | 6 | { |
155 | 6 | return false; |
156 | 6 | } |
157 | | |
158 | 89.9k | assert(fBig != 0 && "help coverity see it's not zero"); |
159 | 89.8k | fStorage[a] = 1.0 / fBig; |
160 | 89.8k | } |
161 | | |
162 | | // start normalizing |
163 | 112k | for(b = 0; b < RowSize; b++) |
164 | 89.8k | { |
165 | 224k | for(a = 0; a < b; a++) |
166 | 134k | { |
167 | 134k | fSum = get(a, b); |
168 | | |
169 | 224k | for(c = 0; c < a; c++) |
170 | 89.8k | { |
171 | 89.8k | fSum -= get(a, c) * get(c, b); |
172 | 89.8k | } |
173 | | |
174 | 134k | set(a, b, fSum); |
175 | 134k | } |
176 | | |
177 | 89.8k | fBig = 0.0; |
178 | | |
179 | 314k | for(a = b; a < RowSize; a++) |
180 | 224k | { |
181 | 224k | fSum = get(a, b); |
182 | | |
183 | 449k | for(c = 0; c < b; c++) |
184 | 224k | { |
185 | 224k | fSum -= get(a, c) * get(c, b); |
186 | 224k | } |
187 | | |
188 | 224k | set(a, b, fSum); |
189 | 224k | fDum = fStorage[a] * fabs(fSum); |
190 | | |
191 | 224k | if(::basegfx::fTools::moreOrEqual(fDum, fBig)) |
192 | 92.7k | { |
193 | 92.7k | fBig = fDum; |
194 | 92.7k | nAMax = a; |
195 | 92.7k | } |
196 | 224k | } |
197 | | |
198 | 89.8k | if(b != nAMax) |
199 | 2.81k | { |
200 | 14.0k | for(c = 0; c < RowSize; c++) |
201 | 11.2k | { |
202 | 11.2k | fDum = get(nAMax, c); |
203 | 11.2k | set(nAMax, c, get(b, c)); |
204 | 11.2k | set(b, c, fDum); |
205 | 11.2k | } |
206 | | |
207 | 2.81k | nParity = -nParity; |
208 | 2.81k | fStorage[nAMax] = fStorage[b]; |
209 | 2.81k | } |
210 | | |
211 | 89.8k | nIndex[b] = nAMax; |
212 | | |
213 | | // here the failure of precision occurs |
214 | 89.8k | const double fValBB(fabs(get(b, b))); |
215 | | |
216 | 89.8k | if(::basegfx::fTools::equalZero(fValBB)) |
217 | 0 | { |
218 | 0 | return false; |
219 | 0 | } |
220 | | |
221 | 89.8k | if(b != (RowSize - 1)) |
222 | 67.4k | { |
223 | 67.4k | fDum = 1.0 / get(b, b); |
224 | | |
225 | 202k | for(a = b + 1; a < RowSize; a++) |
226 | 134k | { |
227 | 134k | set(a, b, get(a, b) * fDum); |
228 | 134k | } |
229 | 67.4k | } |
230 | 89.8k | } |
231 | | |
232 | 22.4k | return true; |
233 | 22.4k | } |
234 | | |
235 | | void lubksb(const sal_uInt16 nIndex[], double fRow[]) const |
236 | 89.8k | { |
237 | 89.8k | sal_uInt16 b, ip; |
238 | 89.8k | sal_Int16 a, a2 = -1; |
239 | 89.8k | double fSum; |
240 | | |
241 | 449k | for(a = 0; a < RowSize; a++) |
242 | 359k | { |
243 | 359k | ip = nIndex[a]; |
244 | 359k | fSum = fRow[ip]; |
245 | 359k | fRow[ip] = fRow[a]; |
246 | | |
247 | 359k | if(a2 >= 0) |
248 | 134k | { |
249 | 359k | for(b = a2; b < a; b++) |
250 | 224k | { |
251 | 224k | fSum -= get(a, b) * fRow[b]; |
252 | 224k | } |
253 | 134k | } |
254 | 224k | else if(!::basegfx::fTools::equalZero(fSum)) |
255 | 89.8k | { |
256 | 89.8k | a2 = a; |
257 | 89.8k | } |
258 | | |
259 | 359k | fRow[a] = fSum; |
260 | 359k | } |
261 | | |
262 | 449k | for(a = (RowSize - 1); a >= 0; a--) |
263 | 359k | { |
264 | 359k | fSum = fRow[a]; |
265 | | |
266 | 898k | for(b = a + 1; b < RowSize; b++) |
267 | 539k | { |
268 | 539k | fSum -= get(a, b) * fRow[b]; |
269 | 539k | } |
270 | | |
271 | 359k | const double fValueAA(get(a, a)); |
272 | | |
273 | 359k | if(!::basegfx::fTools::equalZero(fValueAA)) |
274 | 359k | { |
275 | 359k | fRow[a] = fSum / get(a, a); |
276 | 359k | } |
277 | 359k | } |
278 | 89.8k | } |
279 | | |
280 | | bool isIdentity() const |
281 | 76.0k | { |
282 | 356k | for(sal_uInt16 a(0); a < RowSize; a++) |
283 | 286k | { |
284 | 1.41M | for(sal_uInt16 b(0); b < RowSize; b++) |
285 | 1.13M | { |
286 | 1.13M | const double fDefault(implGetDefaultValue(a, b)); |
287 | 1.13M | const double fValueAB(get(a, b)); |
288 | | |
289 | 1.13M | if(!::basegfx::fTools::equal(fDefault, fValueAB)) |
290 | 5.93k | { |
291 | 5.93k | return false; |
292 | 5.93k | } |
293 | 1.13M | } |
294 | 286k | } |
295 | | |
296 | 70.1k | return true; |
297 | 76.0k | } |
298 | | |
299 | | bool isInvertible() const |
300 | | { |
301 | | ImplHomMatrixTemplate aWork(*this); |
302 | | sal_uInt16 nIndex[RowSize]; |
303 | | sal_Int16 nParity; |
304 | | |
305 | | return aWork.ludcmp(nIndex, nParity); |
306 | | } |
307 | | |
308 | | void doInvert(const ImplHomMatrixTemplate& rWork, const sal_uInt16 nIndex[]) |
309 | 22.4k | { |
310 | 22.4k | double fArray[RowSize]; |
311 | | |
312 | 112k | for(sal_uInt16 a(0); a < RowSize; a++) |
313 | 89.8k | { |
314 | | // prepare line |
315 | 89.8k | sal_uInt16 b; |
316 | 449k | for( b = 0; b < RowSize; b++) |
317 | 359k | { |
318 | 359k | fArray[b] = implGetDefaultValue(a, b); |
319 | 359k | } |
320 | | |
321 | | // expand line |
322 | 89.8k | rWork.lubksb(nIndex, fArray); |
323 | | |
324 | | // copy line transposed to this matrix |
325 | 449k | for( b = 0; b < RowSize; b++) |
326 | 359k | { |
327 | 359k | set(b, a, fArray[b]); |
328 | 359k | } |
329 | 89.8k | } |
330 | 22.4k | } |
331 | | |
332 | | double doDeterminant() const |
333 | 0 | { |
334 | 0 | ImplHomMatrixTemplate aWork(*this); |
335 | 0 | sal_uInt16 nIndex[RowSize]; |
336 | 0 | sal_Int16 nParity; |
337 | 0 | double fRetval(0.0); |
338 | |
|
339 | 0 | if(aWork.ludcmp(nIndex, nParity)) |
340 | 0 | { |
341 | 0 | fRetval = static_cast<double>(nParity); |
342 | 0 | for(sal_uInt16 a(0); a < RowSize; a++) |
343 | 0 | { |
344 | 0 | fRetval *= aWork.get(a, a); |
345 | 0 | } |
346 | 0 | } |
347 | |
|
348 | 0 | return fRetval; |
349 | 0 | } |
350 | | |
351 | | void doAddMatrix(const ImplHomMatrixTemplate& rMat) |
352 | 0 | { |
353 | 0 | for(sal_uInt16 a(0); a < RowSize; a++) |
354 | 0 | { |
355 | 0 | for(sal_uInt16 b(0); b < RowSize; b++) |
356 | 0 | { |
357 | 0 | set(a, b, get(a, b) + rMat.get(a, b)); |
358 | 0 | } |
359 | 0 | } |
360 | 0 | } |
361 | | |
362 | | void doSubMatrix(const ImplHomMatrixTemplate& rMat) |
363 | 0 | { |
364 | 0 | for(sal_uInt16 a(0); a < RowSize; a++) |
365 | 0 | { |
366 | 0 | for(sal_uInt16 b(0); b < RowSize; b++) |
367 | 0 | { |
368 | 0 | set(a, b, get(a, b) - rMat.get(a, b)); |
369 | 0 | } |
370 | 0 | } |
371 | 0 | } |
372 | | |
373 | | void doMulMatrix(const ImplHomMatrixTemplate& rMat) |
374 | 35.0k | { |
375 | | // create a copy as source for the original values |
376 | 35.0k | const ImplHomMatrixTemplate aCopy(*this); |
377 | | |
378 | | // TODO: maybe optimize cases where last line is [0 0 1]. |
379 | | |
380 | 35.0k | double fValue(0.0); |
381 | | |
382 | 175k | for(sal_uInt16 a(0); a < RowSize; ++a) |
383 | 140k | { |
384 | 700k | for(sal_uInt16 b(0); b < RowSize; ++b) |
385 | 560k | { |
386 | 560k | fValue = 0.0; |
387 | | |
388 | 2.80M | for(sal_uInt16 c(0); c < RowSize; ++c) |
389 | 2.24M | fValue += aCopy.get(c, b) * rMat.get(a, c); |
390 | | |
391 | 560k | set(a, b, fValue); |
392 | 560k | } |
393 | 140k | } |
394 | 35.0k | } |
395 | | |
396 | | bool isEqual(const ImplHomMatrixTemplate& rMat) const |
397 | 6.45k | { |
398 | 8.21k | for(sal_uInt16 a(0); a < RowSize; a++) |
399 | 8.21k | { |
400 | 24.0k | for(sal_uInt16 b(0); b < RowSize; b++) |
401 | 22.3k | { |
402 | 22.3k | const double fValueA(get(a, b)); |
403 | 22.3k | const double fValueB(rMat.get(a, b)); |
404 | | |
405 | 22.3k | if(!::basegfx::fTools::equal(fValueA, fValueB)) |
406 | 6.45k | { |
407 | 6.45k | return false; |
408 | 6.45k | } |
409 | 22.3k | } |
410 | 8.21k | } |
411 | | |
412 | 0 | return true; |
413 | 6.45k | } |
414 | | }; |
415 | | |
416 | | } // namespace basegfx::internal |
417 | | |
418 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |