Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / basegfx / source / matrix / b2dhommatrixtools.cxx
blob2c831854761b8a271bdf4c96f6b66828d9610dec
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <basegfx/matrix/b2dhommatrixtools.hxx>
21 #include <basegfx/range/b2drange.hxx>
23 #include <osl/diagnose.h>
25 namespace basegfx
27 namespace utils
29 void createSinCosOrthogonal(double& o_rSin, double& o_rCos, double fRadiant)
31 if( fTools::equalZero( fmod( fRadiant, F_PI2 ) ) )
33 // determine quadrant
34 const sal_Int32 nQuad(
35 (4 + fround( 4/F_2PI*fmod( fRadiant, F_2PI ) )) % 4 );
36 switch( nQuad )
38 case 0: // -2pi,0,2pi
39 o_rSin = 0.0;
40 o_rCos = 1.0;
41 break;
43 case 1: // -3/2pi,1/2pi
44 o_rSin = 1.0;
45 o_rCos = 0.0;
46 break;
48 case 2: // -pi,pi
49 o_rSin = 0.0;
50 o_rCos = -1.0;
51 break;
53 case 3: // -1/2pi,3/2pi
54 o_rSin = -1.0;
55 o_rCos = 0.0;
56 break;
58 default:
59 OSL_FAIL( "createSinCos: Impossible case reached" );
62 else
64 // TODO(P1): Maybe use glibc's sincos here (though
65 // that's kinda non-portable...)
66 o_rSin = sin(fRadiant);
67 o_rCos = cos(fRadiant);
71 B2DHomMatrix createScaleB2DHomMatrix(double fScaleX, double fScaleY)
73 B2DHomMatrix aRetval;
74 const double fOne(1.0);
76 if(!fTools::equal(fScaleX, fOne))
78 aRetval.set(0, 0, fScaleX);
81 if(!fTools::equal(fScaleY, fOne))
83 aRetval.set(1, 1, fScaleY);
86 return aRetval;
89 B2DHomMatrix createShearXB2DHomMatrix(double fShearX)
91 B2DHomMatrix aRetval;
93 if(!fTools::equalZero(fShearX))
95 aRetval.set(0, 1, fShearX);
98 return aRetval;
101 B2DHomMatrix createShearYB2DHomMatrix(double fShearY)
103 B2DHomMatrix aRetval;
105 if(!fTools::equalZero(fShearY))
107 aRetval.set(1, 0, fShearY);
110 return aRetval;
113 B2DHomMatrix createRotateB2DHomMatrix(double fRadiant)
115 B2DHomMatrix aRetval;
117 if(!fTools::equalZero(fRadiant))
119 double fSin(0.0);
120 double fCos(1.0);
122 createSinCosOrthogonal(fSin, fCos, fRadiant);
123 aRetval.set(0, 0, fCos);
124 aRetval.set(1, 1, fCos);
125 aRetval.set(1, 0, fSin);
126 aRetval.set(0, 1, -fSin);
129 return aRetval;
132 B2DHomMatrix createTranslateB2DHomMatrix(double fTranslateX, double fTranslateY)
134 B2DHomMatrix aRetval;
136 if(!(fTools::equalZero(fTranslateX) && fTools::equalZero(fTranslateY)))
138 aRetval.set(0, 2, fTranslateX);
139 aRetval.set(1, 2, fTranslateY);
142 return aRetval;
145 B2DHomMatrix createScaleShearXRotateTranslateB2DHomMatrix(
146 double fScaleX, double fScaleY,
147 double fShearX,
148 double fRadiant,
149 double fTranslateX, double fTranslateY)
151 const double fOne(1.0);
153 if(fTools::equal(fScaleX, fOne) && fTools::equal(fScaleY, fOne))
155 /// no scale, take shortcut
156 return createShearXRotateTranslateB2DHomMatrix(fShearX, fRadiant, fTranslateX, fTranslateY);
158 else
160 /// scale used
161 if(fTools::equalZero(fShearX))
163 /// no shear
164 if(fTools::equalZero(fRadiant))
166 /// no rotate, take shortcut
167 return createScaleTranslateB2DHomMatrix(fScaleX, fScaleY, fTranslateX, fTranslateY);
169 else
171 /// rotate and scale used, no shear
172 double fSin(0.0);
173 double fCos(1.0);
175 createSinCosOrthogonal(fSin, fCos, fRadiant);
177 B2DHomMatrix aRetval(
178 /* Row 0, Column 0 */ fCos * fScaleX,
179 /* Row 0, Column 1 */ fScaleY * -fSin,
180 /* Row 0, Column 2 */ fTranslateX,
181 /* Row 1, Column 0 */ fSin * fScaleX,
182 /* Row 1, Column 1 */ fScaleY * fCos,
183 /* Row 1, Column 2 */ fTranslateY);
185 return aRetval;
188 else
190 /// scale and shear used
191 if(fTools::equalZero(fRadiant))
193 /// scale and shear, but no rotate
194 B2DHomMatrix aRetval(
195 /* Row 0, Column 0 */ fScaleX,
196 /* Row 0, Column 1 */ fScaleY * fShearX,
197 /* Row 0, Column 2 */ fTranslateX,
198 /* Row 1, Column 0 */ 0.0,
199 /* Row 1, Column 1 */ fScaleY,
200 /* Row 1, Column 2 */ fTranslateY);
202 return aRetval;
204 else
206 /// scale, shear and rotate used
207 double fSin(0.0);
208 double fCos(1.0);
210 createSinCosOrthogonal(fSin, fCos, fRadiant);
212 B2DHomMatrix aRetval(
213 /* Row 0, Column 0 */ fCos * fScaleX,
214 /* Row 0, Column 1 */ fScaleY * ((fCos * fShearX) - fSin),
215 /* Row 0, Column 2 */ fTranslateX,
216 /* Row 1, Column 0 */ fSin * fScaleX,
217 /* Row 1, Column 1 */ fScaleY * ((fSin * fShearX) + fCos),
218 /* Row 1, Column 2 */ fTranslateY);
220 return aRetval;
226 B2DHomMatrix createShearXRotateTranslateB2DHomMatrix(
227 double fShearX,
228 double fRadiant,
229 double fTranslateX, double fTranslateY)
231 if(fTools::equalZero(fShearX))
233 /// no shear
234 if(fTools::equalZero(fRadiant))
236 /// no shear, no rotate, take shortcut
237 return createTranslateB2DHomMatrix(fTranslateX, fTranslateY);
239 else
241 /// no shear, but rotate used
242 double fSin(0.0);
243 double fCos(1.0);
245 createSinCosOrthogonal(fSin, fCos, fRadiant);
247 B2DHomMatrix aRetval(
248 /* Row 0, Column 0 */ fCos,
249 /* Row 0, Column 1 */ -fSin,
250 /* Row 0, Column 2 */ fTranslateX,
251 /* Row 1, Column 0 */ fSin,
252 /* Row 1, Column 1 */ fCos,
253 /* Row 1, Column 2 */ fTranslateY);
255 return aRetval;
258 else
260 /// shear used
261 if(fTools::equalZero(fRadiant))
263 /// no rotate, but shear used
264 B2DHomMatrix aRetval(
265 /* Row 0, Column 0 */ 1.0,
266 /* Row 0, Column 1 */ fShearX,
267 /* Row 0, Column 2 */ fTranslateX,
268 /* Row 1, Column 0 */ 0.0,
269 /* Row 1, Column 1 */ 1.0,
270 /* Row 1, Column 2 */ fTranslateY);
272 return aRetval;
274 else
276 /// shear and rotate used
277 double fSin(0.0);
278 double fCos(1.0);
280 createSinCosOrthogonal(fSin, fCos, fRadiant);
282 B2DHomMatrix aRetval(
283 /* Row 0, Column 0 */ fCos,
284 /* Row 0, Column 1 */ (fCos * fShearX) - fSin,
285 /* Row 0, Column 2 */ fTranslateX,
286 /* Row 1, Column 0 */ fSin,
287 /* Row 1, Column 1 */ (fSin * fShearX) + fCos,
288 /* Row 1, Column 2 */ fTranslateY);
290 return aRetval;
295 B2DHomMatrix createScaleTranslateB2DHomMatrix(
296 double fScaleX, double fScaleY,
297 double fTranslateX, double fTranslateY)
299 const double fOne(1.0);
301 if(fTools::equal(fScaleX, fOne) && fTools::equal(fScaleY, fOne))
303 /// no scale, take shortcut
304 return createTranslateB2DHomMatrix(fTranslateX, fTranslateY);
306 else
308 /// scale used
309 if(fTools::equalZero(fTranslateX) && fTools::equalZero(fTranslateY))
311 /// no translate, but scale.
312 B2DHomMatrix aRetval;
314 aRetval.set(0, 0, fScaleX);
315 aRetval.set(1, 1, fScaleY);
317 return aRetval;
319 else
321 /// translate and scale
322 B2DHomMatrix aRetval(
323 /* Row 0, Column 0 */ fScaleX,
324 /* Row 0, Column 1 */ 0.0,
325 /* Row 0, Column 2 */ fTranslateX,
326 /* Row 1, Column 0 */ 0.0,
327 /* Row 1, Column 1 */ fScaleY,
328 /* Row 1, Column 2 */ fTranslateY);
330 return aRetval;
335 B2DHomMatrix createRotateAroundPoint(
336 double fPointX, double fPointY,
337 double fRadiant)
339 B2DHomMatrix aRetval;
341 if(!fTools::equalZero(fRadiant))
343 double fSin(0.0);
344 double fCos(1.0);
346 createSinCosOrthogonal(fSin, fCos, fRadiant);
348 aRetval.set3x2(
349 /* Row 0, Column 0 */ fCos,
350 /* Row 0, Column 1 */ -fSin,
351 /* Row 0, Column 2 */ (fPointX * (1.0 - fCos)) + (fSin * fPointY),
352 /* Row 1, Column 0 */ fSin,
353 /* Row 1, Column 1 */ fCos,
354 /* Row 1, Column 2 */ (fPointY * (1.0 - fCos)) - (fSin * fPointX));
357 return aRetval;
360 BASEGFX_DLLPUBLIC B2DHomMatrix createRotateAroundCenterKeepAspectRatioStayInsideRange(
361 const basegfx::B2DRange& rTargetRange,
362 double fRotate)
364 basegfx::B2DHomMatrix aRetval;
366 // RotGrfFlyFrame: Create a transformation that maps the range inside of itself
367 // so that it fits, takes as much space as possible and keeps the aspect ratio
368 if(0.0 != fRotate)
370 // Fit rotated graphic to center of available space, keeping page ratio:
371 // Adapt scaling ratio of unit object and rotate it
372 aRetval.scale(1.0, rTargetRange.getHeight() / rTargetRange.getWidth());
373 aRetval.rotate(fRotate);
375 // get the range to see where we are in unit coordinates
376 basegfx::B2DRange aFullRange(0.0, 0.0, 1.0, 1.0);
377 aFullRange.transform(aRetval);
379 // detect needed scales in X/Y and choose the smallest for staying inside the
380 // available space while keeping aspect ratio of the source
381 const double fScaleX(rTargetRange.getWidth() / aFullRange.getWidth());
382 const double fScaleY(rTargetRange.getHeight() / aFullRange.getHeight());
383 const double fScaleMin(std::min(fScaleX, fScaleY));
385 // TopLeft to zero, then scale, then move to center of available space
386 aRetval.translate(-aFullRange.getMinX(), -aFullRange.getMinY());
387 aRetval.scale(fScaleMin, fScaleMin);
388 aRetval.translate(
389 rTargetRange.getCenterX() - (0.5 * fScaleMin * aFullRange.getWidth()),
390 rTargetRange.getCenterY() - (0.5 * fScaleMin * aFullRange.getHeight()));
392 else
394 // just scale/translate needed
395 aRetval *= createScaleTranslateB2DHomMatrix(
396 rTargetRange.getRange(),
397 rTargetRange.getMinimum());
400 return aRetval;
403 /// special for the case to map from source range to target range
404 B2DHomMatrix createSourceRangeTargetRangeTransform(
405 const B2DRange& rSourceRange,
406 const B2DRange& rTargetRange)
408 B2DHomMatrix aRetval;
410 if(&rSourceRange == &rTargetRange)
412 return aRetval;
415 if(!fTools::equalZero(rSourceRange.getMinX()) || !fTools::equalZero(rSourceRange.getMinY()))
417 aRetval.set(0, 2, -rSourceRange.getMinX());
418 aRetval.set(1, 2, -rSourceRange.getMinY());
421 const double fSourceW(rSourceRange.getWidth());
422 const double fSourceH(rSourceRange.getHeight());
423 const bool bDivX(!fTools::equalZero(fSourceW) && !fTools::equal(fSourceW, 1.0));
424 const bool bDivY(!fTools::equalZero(fSourceH) && !fTools::equal(fSourceH, 1.0));
425 const double fScaleX(bDivX ? rTargetRange.getWidth() / fSourceW : rTargetRange.getWidth());
426 const double fScaleY(bDivY ? rTargetRange.getHeight() / fSourceH : rTargetRange.getHeight());
428 if(!fTools::equalZero(fScaleX) || !fTools::equalZero(fScaleY))
430 aRetval.scale(fScaleX, fScaleY);
433 if(!fTools::equalZero(rTargetRange.getMinX()) || !fTools::equalZero(rTargetRange.getMinY()))
435 aRetval.translate(
436 rTargetRange.getMinX(),
437 rTargetRange.getMinY());
440 return aRetval;
443 B2DHomMatrix createCoordinateSystemTransform(
444 const B2DPoint& rOrigin,
445 const B2DVector& rX,
446 const B2DVector& rY)
448 return basegfx::B2DHomMatrix(
449 rX.getX(), rY.getX(), rOrigin.getX(),
450 rX.getY(), rY.getY(), rOrigin.getY());
453 B2DTuple getColumn(const B2DHomMatrix& rMatrix, sal_uInt16 nCol)
455 return B2DTuple(rMatrix.get(0, nCol), rMatrix.get(1, nCol));
457 } // end of namespace utils
458 } // end of namespace basegfx
460 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */