LibreOffice Module basegfx (master) 1
b2dhommatrixtools.cxx
Go to the documentation of this file.
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
22
23#include <osl/diagnose.h>
24
25namespace basegfx::utils
26{
27 void createSinCosOrthogonal(double& o_rSin, double& o_rCos, double fRadiant)
28 {
29 if( fTools::equalZero( fmod( fRadiant, M_PI_2 ) ) )
30 {
31 // determine quadrant
32 const sal_Int32 nQuad(
33 (4 + fround( M_2_PI*fmod( fRadiant, 2 * M_PI ) )) % 4 );
34 switch( nQuad )
35 {
36 case 0: // -2pi,0,2pi
37 o_rSin = 0.0;
38 o_rCos = 1.0;
39 break;
40
41 case 1: // -3/2pi,1/2pi
42 o_rSin = 1.0;
43 o_rCos = 0.0;
44 break;
45
46 case 2: // -pi,pi
47 o_rSin = 0.0;
48 o_rCos = -1.0;
49 break;
50
51 case 3: // -1/2pi,3/2pi
52 o_rSin = -1.0;
53 o_rCos = 0.0;
54 break;
55
56 default:
57 OSL_FAIL( "createSinCos: Impossible case reached" );
58 }
59 }
60 else
61 {
62 // TODO(P1): Maybe use glibc's sincos here (though
63 // that's kinda non-portable...)
64 o_rSin = sin(fRadiant);
65 o_rCos = cos(fRadiant);
66 }
67 }
68
69 B2DHomMatrix createScaleB2DHomMatrix(double fScaleX, double fScaleY)
70 {
71 B2DHomMatrix aRetval;
72 const double fOne(1.0);
73
74 if(!fTools::equal(fScaleX, fOne))
75 {
76 aRetval.set(0, 0, fScaleX);
77 }
78
79 if(!fTools::equal(fScaleY, fOne))
80 {
81 aRetval.set(1, 1, fScaleY);
82 }
83
84 return aRetval;
85 }
86
88 {
89 B2DHomMatrix aRetval;
90
91 if(!fTools::equalZero(fShearX))
92 {
93 aRetval.set(0, 1, fShearX);
94 }
95
96 return aRetval;
97 }
98
100 {
101 B2DHomMatrix aRetval;
102
103 if(!fTools::equalZero(fShearY))
104 {
105 aRetval.set(1, 0, fShearY);
106 }
107
108 return aRetval;
109 }
110
112 {
113 B2DHomMatrix aRetval;
114
115 if(!fTools::equalZero(fRadiant))
116 {
117 double fSin(0.0);
118 double fCos(1.0);
119
120 createSinCosOrthogonal(fSin, fCos, fRadiant);
121 aRetval.set(0, 0, fCos);
122 aRetval.set(1, 1, fCos);
123 aRetval.set(1, 0, fSin);
124 aRetval.set(0, 1, -fSin);
125 }
126
127 return aRetval;
128 }
129
130 B2DHomMatrix createTranslateB2DHomMatrix(double fTranslateX, double fTranslateY)
131 {
132 B2DHomMatrix aRetval;
133
134 if(!(fTools::equalZero(fTranslateX) && fTools::equalZero(fTranslateY)))
135 {
136 aRetval.set(0, 2, fTranslateX);
137 aRetval.set(1, 2, fTranslateY);
138 }
139
140 return aRetval;
141 }
142
144 double fScaleX, double fScaleY,
145 double fShearX,
146 double fRadiant,
147 double fTranslateX, double fTranslateY)
148 {
149 const double fOne(1.0);
150
151 if(fTools::equal(fScaleX, fOne) && fTools::equal(fScaleY, fOne))
152 {
154 return createShearXRotateTranslateB2DHomMatrix(fShearX, fRadiant, fTranslateX, fTranslateY);
155 }
156 else
157 {
159 if(fTools::equalZero(fShearX))
160 {
162 if(fTools::equalZero(fRadiant))
163 {
165 return createScaleTranslateB2DHomMatrix(fScaleX, fScaleY, fTranslateX, fTranslateY);
166 }
167 else
168 {
170 double fSin(0.0);
171 double fCos(1.0);
172
173 createSinCosOrthogonal(fSin, fCos, fRadiant);
174
175 B2DHomMatrix aRetval(
176 /* Row 0, Column 0 */ fCos * fScaleX,
177 /* Row 0, Column 1 */ fScaleY * -fSin,
178 /* Row 0, Column 2 */ fTranslateX,
179 /* Row 1, Column 0 */ fSin * fScaleX,
180 /* Row 1, Column 1 */ fScaleY * fCos,
181 /* Row 1, Column 2 */ fTranslateY);
182
183 return aRetval;
184 }
185 }
186 else
187 {
189 if(fTools::equalZero(fRadiant))
190 {
192 B2DHomMatrix aRetval(
193 /* Row 0, Column 0 */ fScaleX,
194 /* Row 0, Column 1 */ fScaleY * fShearX,
195 /* Row 0, Column 2 */ fTranslateX,
196 /* Row 1, Column 0 */ 0.0,
197 /* Row 1, Column 1 */ fScaleY,
198 /* Row 1, Column 2 */ fTranslateY);
199
200 return aRetval;
201 }
202 else
203 {
205 double fSin(0.0);
206 double fCos(1.0);
207
208 createSinCosOrthogonal(fSin, fCos, fRadiant);
209
210 B2DHomMatrix aRetval(
211 /* Row 0, Column 0 */ fCos * fScaleX,
212 /* Row 0, Column 1 */ fScaleY * ((fCos * fShearX) - fSin),
213 /* Row 0, Column 2 */ fTranslateX,
214 /* Row 1, Column 0 */ fSin * fScaleX,
215 /* Row 1, Column 1 */ fScaleY * ((fSin * fShearX) + fCos),
216 /* Row 1, Column 2 */ fTranslateY);
217
218 return aRetval;
219 }
220 }
221 }
222 }
223
225 double fShearX,
226 double fRadiant,
227 double fTranslateX, double fTranslateY)
228 {
229 if(fTools::equalZero(fShearX))
230 {
232 if(fTools::equalZero(fRadiant))
233 {
235 return createTranslateB2DHomMatrix(fTranslateX, fTranslateY);
236 }
237 else
238 {
240 double fSin(0.0);
241 double fCos(1.0);
242
243 createSinCosOrthogonal(fSin, fCos, fRadiant);
244
245 B2DHomMatrix aRetval(
246 /* Row 0, Column 0 */ fCos,
247 /* Row 0, Column 1 */ -fSin,
248 /* Row 0, Column 2 */ fTranslateX,
249 /* Row 1, Column 0 */ fSin,
250 /* Row 1, Column 1 */ fCos,
251 /* Row 1, Column 2 */ fTranslateY);
252
253 return aRetval;
254 }
255 }
256 else
257 {
259 if(fTools::equalZero(fRadiant))
260 {
262 B2DHomMatrix aRetval(
263 /* Row 0, Column 0 */ 1.0,
264 /* Row 0, Column 1 */ fShearX,
265 /* Row 0, Column 2 */ fTranslateX,
266 /* Row 1, Column 0 */ 0.0,
267 /* Row 1, Column 1 */ 1.0,
268 /* Row 1, Column 2 */ fTranslateY);
269
270 return aRetval;
271 }
272 else
273 {
275 double fSin(0.0);
276 double fCos(1.0);
277
278 createSinCosOrthogonal(fSin, fCos, fRadiant);
279
280 B2DHomMatrix aRetval(
281 /* Row 0, Column 0 */ fCos,
282 /* Row 0, Column 1 */ (fCos * fShearX) - fSin,
283 /* Row 0, Column 2 */ fTranslateX,
284 /* Row 1, Column 0 */ fSin,
285 /* Row 1, Column 1 */ (fSin * fShearX) + fCos,
286 /* Row 1, Column 2 */ fTranslateY);
287
288 return aRetval;
289 }
290 }
291 }
292
294 double fScaleX, double fScaleY,
295 double fTranslateX, double fTranslateY)
296 {
297 const double fOne(1.0);
298
299 if(fTools::equal(fScaleX, fOne) && fTools::equal(fScaleY, fOne))
300 {
302 return createTranslateB2DHomMatrix(fTranslateX, fTranslateY);
303 }
304 else
305 {
307 if(fTools::equalZero(fTranslateX) && fTools::equalZero(fTranslateY))
308 {
310 B2DHomMatrix aRetval;
311
312 aRetval.set(0, 0, fScaleX);
313 aRetval.set(1, 1, fScaleY);
314
315 return aRetval;
316 }
317 else
318 {
320 B2DHomMatrix aRetval(
321 /* Row 0, Column 0 */ fScaleX,
322 /* Row 0, Column 1 */ 0.0,
323 /* Row 0, Column 2 */ fTranslateX,
324 /* Row 1, Column 0 */ 0.0,
325 /* Row 1, Column 1 */ fScaleY,
326 /* Row 1, Column 2 */ fTranslateY);
327
328 return aRetval;
329 }
330 }
331 }
332
334 double fPointX, double fPointY,
335 double fRadiant)
336 {
337 B2DHomMatrix aRetval;
338
339 if(!fTools::equalZero(fRadiant))
340 {
341 double fSin(0.0);
342 double fCos(1.0);
343
344 createSinCosOrthogonal(fSin, fCos, fRadiant);
345
346 aRetval.set3x2(
347 /* Row 0, Column 0 */ fCos,
348 /* Row 0, Column 1 */ -fSin,
349 /* Row 0, Column 2 */ (fPointX * (1.0 - fCos)) + (fSin * fPointY),
350 /* Row 1, Column 0 */ fSin,
351 /* Row 1, Column 1 */ fCos,
352 /* Row 1, Column 2 */ (fPointY * (1.0 - fCos)) - (fSin * fPointX));
353 }
354
355 return aRetval;
356 }
357
359 const basegfx::B2DRange& rTargetRange,
360 double fRotate)
361 {
362 basegfx::B2DHomMatrix aRetval;
363
364 // RotGrfFlyFrame: Create a transformation that maps the range inside of itself
365 // so that it fits, takes as much space as possible and keeps the aspect ratio
366 if(0.0 != fRotate)
367 {
368 // Fit rotated graphic to center of available space, keeping page ratio:
369 // Adapt scaling ratio of unit object and rotate it
370 aRetval.scale(1.0, rTargetRange.getHeight() / rTargetRange.getWidth());
371 aRetval.rotate(fRotate);
372
373 // get the range to see where we are in unit coordinates
374 basegfx::B2DRange aFullRange(0.0, 0.0, 1.0, 1.0);
375 aFullRange.transform(aRetval);
376
377 // detect needed scales in X/Y and choose the smallest for staying inside the
378 // available space while keeping aspect ratio of the source
379 const double fScaleX(rTargetRange.getWidth() / aFullRange.getWidth());
380 const double fScaleY(rTargetRange.getHeight() / aFullRange.getHeight());
381 const double fScaleMin(std::min(fScaleX, fScaleY));
382
383 // TopLeft to zero, then scale, then move to center of available space
384 aRetval.translate(-aFullRange.getMinX(), -aFullRange.getMinY());
385 aRetval.scale(fScaleMin, fScaleMin);
386 aRetval.translate(
387 rTargetRange.getCenterX() - (0.5 * fScaleMin * aFullRange.getWidth()),
388 rTargetRange.getCenterY() - (0.5 * fScaleMin * aFullRange.getHeight()));
389 }
390 else
391 {
392 // just scale/translate needed
394 rTargetRange.getRange(),
395 rTargetRange.getMinimum());
396 }
397
398 return aRetval;
399 }
400
403 const B2DRange& rSourceRange,
404 const B2DRange& rTargetRange)
405 {
406 B2DHomMatrix aRetval;
407
408 if(&rSourceRange == &rTargetRange)
409 {
410 return aRetval;
411 }
412
413 if(!fTools::equalZero(rSourceRange.getMinX()) || !fTools::equalZero(rSourceRange.getMinY()))
414 {
415 aRetval.set(0, 2, -rSourceRange.getMinX());
416 aRetval.set(1, 2, -rSourceRange.getMinY());
417 }
418
419 const double fSourceW(rSourceRange.getWidth());
420 const double fSourceH(rSourceRange.getHeight());
421 const bool bDivX(!fTools::equalZero(fSourceW) && !fTools::equal(fSourceW, 1.0));
422 const bool bDivY(!fTools::equalZero(fSourceH) && !fTools::equal(fSourceH, 1.0));
423 const double fScaleX(bDivX ? rTargetRange.getWidth() / fSourceW : rTargetRange.getWidth());
424 const double fScaleY(bDivY ? rTargetRange.getHeight() / fSourceH : rTargetRange.getHeight());
425
426 if(!fTools::equalZero(fScaleX) || !fTools::equalZero(fScaleY))
427 {
428 aRetval.scale(fScaleX, fScaleY);
429 }
430
431 if(!fTools::equalZero(rTargetRange.getMinX()) || !fTools::equalZero(rTargetRange.getMinY()))
432 {
433 aRetval.translate(
434 rTargetRange.getMinX(),
435 rTargetRange.getMinY());
436 }
437
438 return aRetval;
439 }
440
442 const B2DPoint& rOrigin,
443 const B2DVector& rX,
444 const B2DVector& rY)
445 {
447 rX.getX(), rY.getX(), rOrigin.getX(),
448 rX.getY(), rY.getY(), rOrigin.getY());
449 }
450
451 B2DTuple getColumn(const B2DHomMatrix& rMatrix, sal_uInt16 nCol)
452 {
453 return B2DTuple(rMatrix.get(0, nCol), rMatrix.get(1, nCol));
454 }
455} // end of namespace
456
457/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void set3x2(double f_0x0, double f_0x1, double f_0x2, double f_1x0, double f_1x1, double f_1x2)
allow setting all needed values for a 3x2 matrix in one call.
void set(sal_uInt16 nRow, sal_uInt16 nColumn, double fValue)
void rotate(double fRadiant)
void translate(double fX, double fY)
double get(sal_uInt16 nRow, sal_uInt16 nColumn) const
void scale(double fX, double fY)
Base Point class with two double values.
Definition: b2dpoint.hxx:42
A two-dimensional interval over doubles.
Definition: b2drange.hxx:54
BASEGFX_DLLPUBLIC void transform(const B2DHomMatrix &rMatrix)
Transform Range by given transformation matrix.
Definition: b2drange.cxx:38
B2DVector getRange() const
return difference between upper and lower point. returns (0,0) for empty sets.
Definition: b2drange.hxx:98
B2DPoint getMinimum() const
get lower bound of the set. returns arbitrary values for empty sets.
Definition: b2drange.hxx:80
Base class for all Points/Vectors with two double values.
Definition: b2dtuple.hxx:39
Base Point class with two double values.
Definition: b2dvector.hxx:40
TYPE getWidth() const
return difference between upper and lower X value. returns 0 for empty sets.
Definition: Range2D.hxx:106
TYPE getMinX() const
get lower bound of the set. returns arbitrary values for empty sets.
Definition: Range2D.hxx:94
TYPE getMinY() const
get lower bound of the set. returns arbitrary values for empty sets.
Definition: Range2D.hxx:97
double getCenterX() const
return center X value of set. returns 0 for empty sets.
Definition: Range2D.hxx:112
double getCenterY() const
return center Y value of set. returns 0 for empty sets.
Definition: Range2D.hxx:115
TYPE getHeight() const
return difference between upper and lower Y value. returns 0 for empty sets.
Definition: Range2D.hxx:109
TYPE getX() const
Get X-Coordinate of 2D Tuple.
Definition: Tuple2D.hxx:63
TYPE getY() const
Get Y-Coordinate of 2D Tuple.
Definition: Tuple2D.hxx:66
bool equalZero(const T &rfVal)
Compare against small value.
Definition: ftools.hxx:156
bool equal(T const &rfValA, T const &rfValB)
Definition: ftools.hxx:169
B2DHomMatrix createCoordinateSystemTransform(const B2DPoint &rOrigin, const B2DVector &rX, const B2DVector &rY)
create based on given CoordinateSystem which is defined by origin and x/yaxis
B2DHomMatrix createScaleTranslateB2DHomMatrix(double fScaleX, double fScaleY, double fTranslateX, double fTranslateY)
B2DHomMatrix createRotateAroundPoint(double fPointX, double fPointY, double fRadiant)
special for the often used case of rotation around a point
B2DHomMatrix createShearYB2DHomMatrix(double fShearY)
B2DHomMatrix createRotateAroundCenterKeepAspectRatioStayInsideRange(const basegfx::B2DRange &rTargetRange, double fRotate)
special for creating a mapping for a Range rotated around it's center while keeping AspectRatio uncha...
B2DHomMatrix createScaleB2DHomMatrix(double fScaleX, double fScaleY)
Tooling methods for on-the-fly matrix generation e.g.
B2DHomMatrix createShearXB2DHomMatrix(double fShearX)
B2DTuple getColumn(const B2DHomMatrix &rMatrix, sal_uInt16 nCol)
get column vector from B2dHomMatrix, e.g. to extract coordinate system origin and x/yaxis
B2DHomMatrix createTranslateB2DHomMatrix(double fTranslateX, double fTranslateY)
B2DHomMatrix createRotateB2DHomMatrix(double fRadiant)
void createSinCosOrthogonal(double &o_rSin, double &o_rCos, double fRadiant)
If the rotation angle is an approximate multiple of pi/2, force fSin/fCos to -1/0/1,...
B2DHomMatrix createScaleShearXRotateTranslateB2DHomMatrix(double fScaleX, double fScaleY, double fShearX, double fRadiant, double fTranslateX, double fTranslateY)
Tooling methods for faster completely combined matrix creation when scale, shearX,...
B2DHomMatrix createShearXRotateTranslateB2DHomMatrix(double fShearX, double fRadiant, double fTranslateX, double fTranslateY)
B2DHomMatrix createSourceRangeTargetRangeTransform(const B2DRange &rSourceRange, const B2DRange &rTargetRange)
special for the case to map from source range to target range
B2IRange fround(const B2DRange &rRange)
Round double to nearest integer for 2D range.
Definition: b2drange.cxx:64