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>
21 #include <basegfx/range/b2drange.hxx>
23 #include <osl/diagnose.h>
29 void createSinCosOrthogonal(double& o_rSin
, double& o_rCos
, double fRadiant
)
31 if( fTools::equalZero( fmod( fRadiant
, F_PI2
) ) )
34 const sal_Int32
nQuad(
35 (4 + fround( 4/F_2PI
*fmod( fRadiant
, F_2PI
) )) % 4 );
43 case 1: // -3/2pi,1/2pi
53 case 3: // -1/2pi,3/2pi
59 OSL_FAIL( "createSinCos: Impossible case reached" );
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
)
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
);
89 B2DHomMatrix
createShearXB2DHomMatrix(double fShearX
)
93 if(!fTools::equalZero(fShearX
))
95 aRetval
.set(0, 1, fShearX
);
101 B2DHomMatrix
createShearYB2DHomMatrix(double fShearY
)
103 B2DHomMatrix aRetval
;
105 if(!fTools::equalZero(fShearY
))
107 aRetval
.set(1, 0, fShearY
);
113 B2DHomMatrix
createRotateB2DHomMatrix(double fRadiant
)
115 B2DHomMatrix aRetval
;
117 if(!fTools::equalZero(fRadiant
))
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
);
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
);
145 B2DHomMatrix
createScaleShearXRotateTranslateB2DHomMatrix(
146 double fScaleX
, double fScaleY
,
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
);
161 if(fTools::equalZero(fShearX
))
164 if(fTools::equalZero(fRadiant
))
166 /// no rotate, take shortcut
167 return createScaleTranslateB2DHomMatrix(fScaleX
, fScaleY
, fTranslateX
, fTranslateY
);
171 /// rotate and scale used, no shear
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
);
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
);
206 /// scale, shear and rotate used
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
);
226 B2DHomMatrix
createShearXRotateTranslateB2DHomMatrix(
229 double fTranslateX
, double fTranslateY
)
231 if(fTools::equalZero(fShearX
))
234 if(fTools::equalZero(fRadiant
))
236 /// no shear, no rotate, take shortcut
237 return createTranslateB2DHomMatrix(fTranslateX
, fTranslateY
);
241 /// no shear, but rotate used
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
);
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
);
276 /// shear and rotate used
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
);
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
);
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
);
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
);
335 B2DHomMatrix
createRotateAroundPoint(
336 double fPointX
, double fPointY
,
339 B2DHomMatrix aRetval
;
341 if(!fTools::equalZero(fRadiant
))
346 createSinCosOrthogonal(fSin
, fCos
, fRadiant
);
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
));
360 BASEGFX_DLLPUBLIC B2DHomMatrix
createRotateAroundCenterKeepAspectRatioStayInsideRange(
361 const basegfx::B2DRange
& rTargetRange
,
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
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
);
389 rTargetRange
.getCenterX() - (0.5 * fScaleMin
* aFullRange
.getWidth()),
390 rTargetRange
.getCenterY() - (0.5 * fScaleMin
* aFullRange
.getHeight()));
394 // just scale/translate needed
395 aRetval
*= createScaleTranslateB2DHomMatrix(
396 rTargetRange
.getRange(),
397 rTargetRange
.getMinimum());
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
)
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()))
436 rTargetRange
.getMinX(),
437 rTargetRange
.getMinY());
443 B2DHomMatrix
createCoordinateSystemTransform(
444 const B2DPoint
& rOrigin
,
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: */