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