1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
22 #include <osl/diagnose.h>
23 #include <rtl/ustring.hxx>
24 #include <rtl/ustrbuf.hxx>
30 void createSinCosOrthogonal(double& o_rSin
, double& o_rCos
, double fRadiant
)
32 if( fTools::equalZero( fmod( fRadiant
, F_PI2
) ) )
35 const sal_Int32
nQuad(
36 (4 + fround( 4/F_2PI
*fmod( fRadiant
, F_2PI
) )) % 4 );
44 case 1: // -3/2pi,1/2pi
54 case 3: // -1/2pi,3/2pi
60 OSL_FAIL( "createSinCos: Impossible case reached" );
65 // TODO(P1): Maybe use glibc's sincos here (though
66 // that's kinda non-portable...)
67 o_rSin
= sin(fRadiant
);
68 o_rCos
= cos(fRadiant
);
72 B2DHomMatrix
createScaleB2DHomMatrix(double fScaleX
, double fScaleY
)
75 const double fOne(1.0);
77 if(!fTools::equal(fScaleX
, fOne
))
79 aRetval
.set(0, 0, fScaleX
);
82 if(!fTools::equal(fScaleY
, fOne
))
84 aRetval
.set(1, 1, fScaleY
);
90 B2DHomMatrix
createShearXB2DHomMatrix(double fShearX
)
94 if(!fTools::equalZero(fShearX
))
96 aRetval
.set(0, 1, fShearX
);
102 B2DHomMatrix
createShearYB2DHomMatrix(double fShearY
)
104 B2DHomMatrix aRetval
;
106 if(!fTools::equalZero(fShearY
))
108 aRetval
.set(1, 0, fShearY
);
114 B2DHomMatrix
createRotateB2DHomMatrix(double fRadiant
)
116 B2DHomMatrix aRetval
;
118 if(!fTools::equalZero(fRadiant
))
123 createSinCosOrthogonal(fSin
, fCos
, fRadiant
);
124 aRetval
.set(0, 0, fCos
);
125 aRetval
.set(1, 1, fCos
);
126 aRetval
.set(1, 0, fSin
);
127 aRetval
.set(0, 1, -fSin
);
133 B2DHomMatrix
createTranslateB2DHomMatrix(double fTranslateX
, double fTranslateY
)
135 B2DHomMatrix aRetval
;
137 if(!(fTools::equalZero(fTranslateX
) && fTools::equalZero(fTranslateY
)))
139 aRetval
.set(0, 2, fTranslateX
);
140 aRetval
.set(1, 2, fTranslateY
);
146 B2DHomMatrix
createScaleShearXRotateTranslateB2DHomMatrix(
147 double fScaleX
, double fScaleY
,
150 double fTranslateX
, double fTranslateY
)
152 const double fOne(1.0);
154 if(fTools::equal(fScaleX
, fOne
) && fTools::equal(fScaleY
, fOne
))
156 /// no scale, take shortcut
157 return createShearXRotateTranslateB2DHomMatrix(fShearX
, fRadiant
, fTranslateX
, fTranslateY
);
162 if(fTools::equalZero(fShearX
))
165 if(fTools::equalZero(fRadiant
))
167 /// no rotate, take shortcut
168 return createScaleTranslateB2DHomMatrix(fScaleX
, fScaleY
, fTranslateX
, fTranslateY
);
172 /// rotate and scale used, no shear
176 createSinCosOrthogonal(fSin
, fCos
, fRadiant
);
178 B2DHomMatrix
aRetval(
179 /* Row 0, Column 0 */ fCos
* fScaleX
,
180 /* Row 0, Column 1 */ fScaleY
* -fSin
,
181 /* Row 0, Column 2 */ fTranslateX
,
182 /* Row 1, Column 0 */ fSin
* fScaleX
,
183 /* Row 1, Column 1 */ fScaleY
* fCos
,
184 /* Row 1, Column 2 */ fTranslateY
);
191 /// scale and shear used
192 if(fTools::equalZero(fRadiant
))
194 /// scale and shear, but no rotate
195 B2DHomMatrix
aRetval(
196 /* Row 0, Column 0 */ fScaleX
,
197 /* Row 0, Column 1 */ fScaleY
* fShearX
,
198 /* Row 0, Column 2 */ fTranslateX
,
199 /* Row 1, Column 0 */ 0.0,
200 /* Row 1, Column 1 */ fScaleY
,
201 /* Row 1, Column 2 */ fTranslateY
);
207 /// scale, shear and rotate used
211 createSinCosOrthogonal(fSin
, fCos
, fRadiant
);
213 B2DHomMatrix
aRetval(
214 /* Row 0, Column 0 */ fCos
* fScaleX
,
215 /* Row 0, Column 1 */ fScaleY
* ((fCos
* fShearX
) - fSin
),
216 /* Row 0, Column 2 */ fTranslateX
,
217 /* Row 1, Column 0 */ fSin
* fScaleX
,
218 /* Row 1, Column 1 */ fScaleY
* ((fSin
* fShearX
) + fCos
),
219 /* Row 1, Column 2 */ fTranslateY
);
227 B2DHomMatrix
createShearXRotateTranslateB2DHomMatrix(
230 double fTranslateX
, double fTranslateY
)
232 if(fTools::equalZero(fShearX
))
235 if(fTools::equalZero(fRadiant
))
237 /// no shear, no rotate, take shortcut
238 return createTranslateB2DHomMatrix(fTranslateX
, fTranslateY
);
242 /// no shear, but rotate used
246 createSinCosOrthogonal(fSin
, fCos
, fRadiant
);
248 B2DHomMatrix
aRetval(
249 /* Row 0, Column 0 */ fCos
,
250 /* Row 0, Column 1 */ -fSin
,
251 /* Row 0, Column 2 */ fTranslateX
,
252 /* Row 1, Column 0 */ fSin
,
253 /* Row 1, Column 1 */ fCos
,
254 /* Row 1, Column 2 */ fTranslateY
);
262 if(fTools::equalZero(fRadiant
))
264 /// no rotate, but shear used
265 B2DHomMatrix
aRetval(
266 /* Row 0, Column 0 */ 1.0,
267 /* Row 0, Column 1 */ fShearX
,
268 /* Row 0, Column 2 */ fTranslateX
,
269 /* Row 1, Column 0 */ 0.0,
270 /* Row 1, Column 1 */ 1.0,
271 /* Row 1, Column 2 */ fTranslateY
);
277 /// shear and rotate used
281 createSinCosOrthogonal(fSin
, fCos
, fRadiant
);
283 B2DHomMatrix
aRetval(
284 /* Row 0, Column 0 */ fCos
,
285 /* Row 0, Column 1 */ (fCos
* fShearX
) - fSin
,
286 /* Row 0, Column 2 */ fTranslateX
,
287 /* Row 1, Column 0 */ fSin
,
288 /* Row 1, Column 1 */ (fSin
* fShearX
) + fCos
,
289 /* Row 1, Column 2 */ fTranslateY
);
296 B2DHomMatrix
createScaleTranslateB2DHomMatrix(
297 double fScaleX
, double fScaleY
,
298 double fTranslateX
, double fTranslateY
)
300 const double fOne(1.0);
302 if(fTools::equal(fScaleX
, fOne
) && fTools::equal(fScaleY
, fOne
))
304 /// no scale, take shortcut
305 return createTranslateB2DHomMatrix(fTranslateX
, fTranslateY
);
310 if(fTools::equalZero(fTranslateX
) && fTools::equalZero(fTranslateY
))
312 /// no translate, but scale.
313 B2DHomMatrix aRetval
;
315 aRetval
.set(0, 0, fScaleX
);
316 aRetval
.set(1, 1, fScaleY
);
322 /// translate and scale
323 B2DHomMatrix
aRetval(
324 /* Row 0, Column 0 */ fScaleX
,
325 /* Row 0, Column 1 */ 0.0,
326 /* Row 0, Column 2 */ fTranslateX
,
327 /* Row 1, Column 0 */ 0.0,
328 /* Row 1, Column 1 */ fScaleY
,
329 /* Row 1, Column 2 */ fTranslateY
);
336 B2DHomMatrix
createRotateAroundPoint(
337 double fPointX
, double fPointY
,
340 B2DHomMatrix aRetval
;
342 if(!fTools::equalZero(fRadiant
))
347 createSinCosOrthogonal(fSin
, fCos
, fRadiant
);
350 /* Row 0, Column 0 */ fCos
,
351 /* Row 0, Column 1 */ -fSin
,
352 /* Row 0, Column 2 */ (fPointX
* (1.0 - fCos
)) + (fSin
* fPointY
),
353 /* Row 1, Column 0 */ fSin
,
354 /* Row 1, Column 1 */ fCos
,
355 /* Row 1, Column 2 */ (fPointY
* (1.0 - fCos
)) - (fSin
* fPointX
));
361 BASEGFX_DLLPUBLIC B2DHomMatrix
createRotateAroundCenterKeepAspectRatioStayInsideRange(
362 const basegfx::B2DRange
& rTargetRange
,
365 basegfx::B2DHomMatrix aRetval
;
367 // RotGrfFlyFrame: Create a transformation that maps the range inside of itself
368 // so that it fits, takes as much space as possible and keeps the aspect ratio
371 // Fit rotated graphic to center of available space, keeping page ratio:
372 // Adapt scaling ratio of unit object and rotate it
373 aRetval
.scale(1.0, rTargetRange
.getHeight() / rTargetRange
.getWidth());
374 aRetval
.rotate(fRotate
);
376 // get the range to see where we are in unit coordinates
377 basegfx::B2DRange
aFullRange(0.0, 0.0, 1.0, 1.0);
378 aFullRange
.transform(aRetval
);
380 // detect needed scales in X/Y and choose the smallest for staying inside the
381 // available space while keeping aspect ratio of the source
382 const double fScaleX(rTargetRange
.getWidth() / aFullRange
.getWidth());
383 const double fScaleY(rTargetRange
.getHeight() / aFullRange
.getHeight());
384 const double fScaleMin(std::min(fScaleX
, fScaleY
));
386 // TopLeft to zero, then scale, then move to center of available space
387 aRetval
.translate(-aFullRange
.getMinX(), -aFullRange
.getMinY());
388 aRetval
.scale(fScaleMin
, fScaleMin
);
390 rTargetRange
.getCenterX() - (0.5 * fScaleMin
* aFullRange
.getWidth()),
391 rTargetRange
.getCenterY() - (0.5 * fScaleMin
* aFullRange
.getHeight()));
395 // just scale/translate needed
396 aRetval
*= createScaleTranslateB2DHomMatrix(
397 rTargetRange
.getRange(),
398 rTargetRange
.getMinimum());
404 /// special for the case to map from source range to target range
405 B2DHomMatrix
createSourceRangeTargetRangeTransform(
406 const B2DRange
& rSourceRange
,
407 const B2DRange
& rTargetRange
)
409 B2DHomMatrix aRetval
;
411 if(&rSourceRange
== &rTargetRange
)
416 if(!fTools::equalZero(rSourceRange
.getMinX()) || !fTools::equalZero(rSourceRange
.getMinY()))
418 aRetval
.set(0, 2, -rSourceRange
.getMinX());
419 aRetval
.set(1, 2, -rSourceRange
.getMinY());
422 const double fSourceW(rSourceRange
.getWidth());
423 const double fSourceH(rSourceRange
.getHeight());
424 const bool bDivX(!fTools::equalZero(fSourceW
) && !fTools::equal(fSourceW
, 1.0));
425 const bool bDivY(!fTools::equalZero(fSourceH
) && !fTools::equal(fSourceH
, 1.0));
426 const double fScaleX(bDivX
? rTargetRange
.getWidth() / fSourceW
: rTargetRange
.getWidth());
427 const double fScaleY(bDivY
? rTargetRange
.getHeight() / fSourceH
: rTargetRange
.getHeight());
429 if(!fTools::equalZero(fScaleX
) || !fTools::equalZero(fScaleY
))
431 aRetval
.scale(fScaleX
, fScaleY
);
434 if(!fTools::equalZero(rTargetRange
.getMinX()) || !fTools::equalZero(rTargetRange
.getMinY()))
437 rTargetRange
.getMinX(),
438 rTargetRange
.getMinY());
444 B2DHomMatrix
createCoordinateSystemTransform(
445 const B2DPoint
& rOrigin
,
449 return basegfx::B2DHomMatrix(
450 rX
.getX(), rY
.getX(), rOrigin
.getX(),
451 rX
.getY(), rY
.getY(), rOrigin
.getY());
454 B2DTuple
getColumn(const B2DHomMatrix
& rMatrix
, sal_uInt16 nCol
)
456 return B2DTuple(rMatrix
.get(0, nCol
), rMatrix
.get(1, nCol
));
458 } // end of namespace utils
459 } // end of namespace basegfx
461 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */