xref: /trunk/main/basegfx/source/matrix/b2dhommatrixtools.cxx (revision 45d1b581a3afed2711c07fe77472516d35fbd7b3)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 // MARKER(update_precomp.py): autogen include statement, do not remove
23 #include "precompiled_basegfx.hxx"
24 
25 #include <basegfx/matrix/b2dhommatrixtools.hxx>
26 #include <rtl/ustring.hxx>
27 #include <rtl/ustrbuf.hxx>
28 
29 namespace basegfx
30 {
exportToSvg(const B2DHomMatrix & rMatrix)31     ::rtl::OUString exportToSvg( const B2DHomMatrix& rMatrix )
32     {
33         rtl::OUStringBuffer aStrBuf;
34         aStrBuf.appendAscii("matrix(");
35 
36         aStrBuf.append(rMatrix.get(0,0));
37         aStrBuf.appendAscii(", ");
38 
39         aStrBuf.append(rMatrix.get(1,0));
40         aStrBuf.appendAscii(", ");
41 
42         aStrBuf.append(rMatrix.get(0,1));
43         aStrBuf.appendAscii(", ");
44 
45         aStrBuf.append(rMatrix.get(1,1));
46         aStrBuf.appendAscii(", ");
47 
48         aStrBuf.append(rMatrix.get(0,2));
49         aStrBuf.appendAscii(", ");
50 
51         aStrBuf.append(rMatrix.get(1,2));
52         aStrBuf.appendAscii(")");
53 
54         return aStrBuf.makeStringAndClear();
55     }
56 
57     namespace tools
58     {
createSinCosOrthogonal(double & o_rSin,double & o_rCos,double fRadiant)59         void createSinCosOrthogonal(double& o_rSin, double& o_rCos, double fRadiant)
60         {
61             if( fTools::equalZero( fmod( fRadiant, F_PI2 ) ) )
62             {
63                 // determine quadrant
64                 const sal_Int32 nQuad(
65                     (4 + fround( 4/F_2PI*fmod( fRadiant, F_2PI ) )) % 4 );
66                 switch( nQuad )
67                 {
68                     case 0: // -2pi,0,2pi
69                         o_rSin = 0.0;
70                         o_rCos = 1.0;
71                         break;
72 
73                     case 1: // -3/2pi,1/2pi
74                         o_rSin = 1.0;
75                         o_rCos = 0.0;
76                         break;
77 
78                     case 2: // -pi,pi
79                         o_rSin = 0.0;
80                         o_rCos = -1.0;
81                         break;
82 
83                     case 3: // -1/2pi,3/2pi
84                         o_rSin = -1.0;
85                         o_rCos = 0.0;
86                         break;
87 
88                     default:
89                         OSL_ENSURE( false, "createSinCos: Impossible case reached" );
90                 }
91             }
92             else
93             {
94                 // TODO(P1): Maybe use glibc's sincos here (though
95                 // that's kinda non-portable...)
96                 o_rSin = sin(fRadiant);
97                 o_rCos = cos(fRadiant);
98             }
99         }
100 
createScaleB2DHomMatrix(double fScaleX,double fScaleY)101         B2DHomMatrix createScaleB2DHomMatrix(double fScaleX, double fScaleY)
102         {
103             B2DHomMatrix aRetval;
104             const double fOne(1.0);
105 
106             if(!fTools::equal(fScaleX, fOne))
107             {
108                 aRetval.set(0, 0, fScaleX);
109             }
110 
111             if(!fTools::equal(fScaleY, fOne))
112             {
113                 aRetval.set(1, 1, fScaleY);
114             }
115 
116             return aRetval;
117         }
118 
createShearXB2DHomMatrix(double fShearX)119         B2DHomMatrix createShearXB2DHomMatrix(double fShearX)
120         {
121             B2DHomMatrix aRetval;
122 
123             if(!fTools::equalZero(fShearX))
124             {
125                 aRetval.set(0, 1, fShearX);
126             }
127 
128             return aRetval;
129         }
130 
createShearYB2DHomMatrix(double fShearY)131         B2DHomMatrix createShearYB2DHomMatrix(double fShearY)
132         {
133             B2DHomMatrix aRetval;
134 
135             if(!fTools::equalZero(fShearY))
136             {
137                 aRetval.set(1, 0, fShearY);
138             }
139 
140             return aRetval;
141         }
142 
createRotateB2DHomMatrix(double fRadiant)143         B2DHomMatrix createRotateB2DHomMatrix(double fRadiant)
144         {
145             B2DHomMatrix aRetval;
146 
147             if(!fTools::equalZero(fRadiant))
148             {
149                 double fSin(0.0);
150                 double fCos(1.0);
151 
152                 createSinCosOrthogonal(fSin, fCos, fRadiant);
153                 aRetval.set(0, 0, fCos);
154                 aRetval.set(1, 1, fCos);
155                 aRetval.set(1, 0, fSin);
156                 aRetval.set(0, 1, -fSin);
157             }
158 
159             return aRetval;
160         }
161 
createTranslateB2DHomMatrix(double fTranslateX,double fTranslateY)162         B2DHomMatrix createTranslateB2DHomMatrix(double fTranslateX, double fTranslateY)
163         {
164             B2DHomMatrix aRetval;
165 
166             if(!(fTools::equalZero(fTranslateX) && fTools::equalZero(fTranslateY)))
167             {
168                 aRetval.set(0, 2, fTranslateX);
169                 aRetval.set(1, 2, fTranslateY);
170             }
171 
172             return aRetval;
173         }
174 
createScaleShearXRotateTranslateB2DHomMatrix(double fScaleX,double fScaleY,double fShearX,double fRadiant,double fTranslateX,double fTranslateY)175         B2DHomMatrix createScaleShearXRotateTranslateB2DHomMatrix(
176             double fScaleX, double fScaleY,
177             double fShearX,
178             double fRadiant,
179             double fTranslateX, double fTranslateY)
180         {
181             const double fOne(1.0);
182 
183             if(fTools::equal(fScaleX, fOne) && fTools::equal(fScaleY, fOne))
184             {
185                 // no scale, take shortcut
186                 return createShearXRotateTranslateB2DHomMatrix(fShearX, fRadiant, fTranslateX, fTranslateY);
187             }
188             else
189             {
190                 // scale used
191                 if(fTools::equalZero(fShearX))
192                 {
193                     // no shear
194                     if(fTools::equalZero(fRadiant))
195                     {
196                         // no rotate, take shortcut
197                         return createScaleTranslateB2DHomMatrix(fScaleX, fScaleY, fTranslateX, fTranslateY);
198                     }
199                     else
200                     {
201                         // rotate and scale used, no shear
202                         double fSin(0.0);
203                         double fCos(1.0);
204 
205                         createSinCosOrthogonal(fSin, fCos, fRadiant);
206 
207                         B2DHomMatrix aRetval(
208                             /* Row 0, Column 0 */ fCos * fScaleX,
209                             /* Row 0, Column 1 */ fScaleY * -fSin,
210                             /* Row 0, Column 2 */ fTranslateX,
211                             /* Row 1, Column 0 */ fSin * fScaleX,
212                             /* Row 1, Column 1 */ fScaleY * fCos,
213                             /* Row 1, Column 2 */ fTranslateY);
214 
215                         return aRetval;
216                     }
217                 }
218                 else
219                 {
220                     // scale and shear used
221                     if(fTools::equalZero(fRadiant))
222                     {
223                         // scale and shear, but no rotate
224                         B2DHomMatrix aRetval(
225                             /* Row 0, Column 0 */ fScaleX,
226                             /* Row 0, Column 1 */ fScaleY * fShearX,
227                             /* Row 0, Column 2 */ fTranslateX,
228                             /* Row 1, Column 0 */ 0.0,
229                             /* Row 1, Column 1 */ fScaleY,
230                             /* Row 1, Column 2 */ fTranslateY);
231 
232                         return aRetval;
233                     }
234                     else
235                     {
236                         // scale, shear and rotate used
237                         double fSin(0.0);
238                         double fCos(1.0);
239 
240                         createSinCosOrthogonal(fSin, fCos, fRadiant);
241 
242                         B2DHomMatrix aRetval(
243                             /* Row 0, Column 0 */ fCos * fScaleX,
244                             /* Row 0, Column 1 */ fScaleY * ((fCos * fShearX) - fSin),
245                             /* Row 0, Column 2 */ fTranslateX,
246                             /* Row 1, Column 0 */ fSin * fScaleX,
247                             /* Row 1, Column 1 */ fScaleY * ((fSin * fShearX) + fCos),
248                             /* Row 1, Column 2 */ fTranslateY);
249 
250                         return aRetval;
251                     }
252                 }
253             }
254         }
255 
createShearXRotateTranslateB2DHomMatrix(double fShearX,double fRadiant,double fTranslateX,double fTranslateY)256         B2DHomMatrix createShearXRotateTranslateB2DHomMatrix(
257             double fShearX,
258             double fRadiant,
259             double fTranslateX, double fTranslateY)
260         {
261             if(fTools::equalZero(fShearX))
262             {
263                 // no shear
264                 if(fTools::equalZero(fRadiant))
265                 {
266                     // no shear, no rotate, take shortcut
267                     return createTranslateB2DHomMatrix(fTranslateX, fTranslateY);
268                 }
269                 else
270                 {
271                     // no shear, but rotate used
272                     double fSin(0.0);
273                     double fCos(1.0);
274 
275                     createSinCosOrthogonal(fSin, fCos, fRadiant);
276 
277                     B2DHomMatrix aRetval(
278                         /* Row 0, Column 0 */ fCos,
279                         /* Row 0, Column 1 */ -fSin,
280                         /* Row 0, Column 2 */ fTranslateX,
281                         /* Row 1, Column 0 */ fSin,
282                         /* Row 1, Column 1 */ fCos,
283                         /* Row 1, Column 2 */ fTranslateY);
284 
285                     return aRetval;
286                 }
287             }
288             else
289             {
290                 // shear used
291                 if(fTools::equalZero(fRadiant))
292                 {
293                     // no rotate, but shear used
294                     B2DHomMatrix aRetval(
295                         /* Row 0, Column 0 */ 1.0,
296                         /* Row 0, Column 1 */ fShearX,
297                         /* Row 0, Column 2 */ fTranslateX,
298                         /* Row 1, Column 0 */ 0.0,
299                         /* Row 1, Column 1 */ 1.0,
300                         /* Row 1, Column 2 */ fTranslateY);
301 
302                     return aRetval;
303                 }
304                 else
305                 {
306                     // shear and rotate used
307                     double fSin(0.0);
308                     double fCos(1.0);
309 
310                     createSinCosOrthogonal(fSin, fCos, fRadiant);
311 
312                     B2DHomMatrix aRetval(
313                         /* Row 0, Column 0 */ fCos,
314                         /* Row 0, Column 1 */ (fCos * fShearX) - fSin,
315                         /* Row 0, Column 2 */ fTranslateX,
316                         /* Row 1, Column 0 */ fSin,
317                         /* Row 1, Column 1 */ (fSin * fShearX) + fCos,
318                         /* Row 1, Column 2 */ fTranslateY);
319 
320                     return aRetval;
321                 }
322             }
323         }
324 
createScaleTranslateB2DHomMatrix(double fScaleX,double fScaleY,double fTranslateX,double fTranslateY)325         B2DHomMatrix createScaleTranslateB2DHomMatrix(
326             double fScaleX, double fScaleY,
327             double fTranslateX, double fTranslateY)
328         {
329             const double fOne(1.0);
330 
331             if(fTools::equal(fScaleX, fOne) && fTools::equal(fScaleY, fOne))
332             {
333                 // no scale, take shortcut
334                 return createTranslateB2DHomMatrix(fTranslateX, fTranslateY);
335             }
336             else
337             {
338                 // scale used
339                 if(fTools::equalZero(fTranslateX) && fTools::equalZero(fTranslateY))
340                 {
341                     // no translate, but scale.
342                     B2DHomMatrix aRetval;
343 
344                     aRetval.set(0, 0, fScaleX);
345                     aRetval.set(1, 1, fScaleY);
346 
347                     return aRetval;
348                 }
349                 else
350                 {
351                     // translate and scale
352                     B2DHomMatrix aRetval(
353                         /* Row 0, Column 0 */ fScaleX,
354                         /* Row 0, Column 1 */ 0.0,
355                         /* Row 0, Column 2 */ fTranslateX,
356                         /* Row 1, Column 0 */ 0.0,
357                         /* Row 1, Column 1 */ fScaleY,
358                         /* Row 1, Column 2 */ fTranslateY);
359 
360                     return aRetval;
361                 }
362             }
363         }
364 
createRotateAroundPoint(double fPointX,double fPointY,double fRadiant)365         B2DHomMatrix createRotateAroundPoint(
366             double fPointX, double fPointY,
367             double fRadiant)
368         {
369             B2DHomMatrix aRetval;
370 
371             if(!fTools::equalZero(fRadiant))
372             {
373                 double fSin(0.0);
374                 double fCos(1.0);
375 
376                 createSinCosOrthogonal(fSin, fCos, fRadiant);
377 
378                 aRetval.set3x2(
379                     /* Row 0, Column 0 */ fCos,
380                     /* Row 0, Column 1 */ -fSin,
381                     /* Row 0, Column 2 */ (fPointX * (1.0 - fCos)) + (fSin * fPointY),
382                     /* Row 1, Column 0 */ fSin,
383                     /* Row 1, Column 1 */ fCos,
384                     /* Row 1, Column 2 */ (fPointY * (1.0 - fCos)) - (fSin * fPointX));
385             }
386 
387             return aRetval;
388         }
389 
390         // special for the case to map from source range to target range
createSourceRangeTargetRangeTransform(const B2DRange & rSourceRange,const B2DRange & rTargetRange)391         B2DHomMatrix createSourceRangeTargetRangeTransform(
392             const B2DRange& rSourceRange,
393             const B2DRange& rTargetRange)
394         {
395             B2DHomMatrix aRetval;
396 
397             if(&rSourceRange == &rTargetRange)
398             {
399                 return aRetval;
400             }
401 
402             if(!fTools::equalZero(rSourceRange.getMinX()) || !fTools::equalZero(rSourceRange.getMinY()))
403             {
404                 aRetval.set(0, 2, -rSourceRange.getMinX());
405                 aRetval.set(1, 2, -rSourceRange.getMinY());
406             }
407 
408             const double fSourceW(rSourceRange.getWidth());
409             const double fSourceH(rSourceRange.getHeight());
410             const bool bDivX(!fTools::equalZero(fSourceW) && !fTools::equal(fSourceW, 1.0));
411             const bool bDivY(!fTools::equalZero(fSourceH) && !fTools::equal(fSourceH, 1.0));
412             const double fScaleX(bDivX ? rTargetRange.getWidth() / fSourceW : rTargetRange.getWidth());
413             const double fScaleY(bDivY ? rTargetRange.getHeight() / fSourceH : rTargetRange.getHeight());
414 
415             if(!fTools::equalZero(fScaleX) || !fTools::equalZero(fScaleY))
416             {
417                 aRetval.scale(fScaleX, fScaleY);
418             }
419 
420             if(!fTools::equalZero(rTargetRange.getMinX()) || !fTools::equalZero(rTargetRange.getMinY()))
421             {
422                 aRetval.translate(
423                     rTargetRange.getMinX(),
424                     rTargetRange.getMinY());
425             }
426 
427             return aRetval;
428         }
429 
430     } // end of namespace tools
431 } // end of namespace basegfx
432 
433 /* vim: set noet sw=4 ts=4: */
434