update dev300-m58
[ooovba.git] / basegfx / source / tools / gradienttools.cxx
blobe652834c2609a270d7ae9c379e489435f839d63c
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: canvastools.cxx,v $
10 * $Revision: 1.12 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_basegfx.hxx"
34 #include <basegfx/tools/gradienttools.hxx>
36 #include <basegfx/point/b2dpoint.hxx>
37 #include <basegfx/range/b2drange.hxx>
39 namespace basegfx
41 /** Most of the setup for linear & axial gradient is the same, except
42 for the border treatment. Factored out here.
44 static void init1DGradientInfo(ODFGradientInfo& o_rGradientInfo,
45 const B2DRange& rTargetRange,
46 sal_uInt32 nSteps,
47 double fBorder,
48 double fAngle,
49 bool bAxial)
51 o_rGradientInfo.maTextureTransform.identity();
52 o_rGradientInfo.maBackTextureTransform.identity();
53 o_rGradientInfo.mnSteps = nSteps;
55 double fTargetSizeX(rTargetRange.getWidth());
56 double fTargetSizeY(rTargetRange.getHeight());
57 double fTargetOffsetX(rTargetRange.getMinX());
58 double fTargetOffsetY(rTargetRange.getMinY());
60 // add object expansion
61 if(0.0 != fAngle)
63 const double fAbsCos(fabs(cos(fAngle)));
64 const double fAbsSin(fabs(sin(fAngle)));
65 const double fNewX(fTargetSizeX * fAbsCos + fTargetSizeY * fAbsSin);
66 const double fNewY(fTargetSizeY * fAbsCos + fTargetSizeX * fAbsSin);
67 fTargetOffsetX -= (fNewX - fTargetSizeX) / 2.0;
68 fTargetOffsetY -= (fNewY - fTargetSizeY) / 2.0;
69 fTargetSizeX = fNewX;
70 fTargetSizeY = fNewY;
73 // add object scale before rotate
74 o_rGradientInfo.maTextureTransform.scale(fTargetSizeX, fTargetSizeY);
76 // add texture rotate after scale to keep perpendicular angles
77 if(0.0 != fAngle)
79 B2DPoint aCenter(0.5, 0.5);
80 aCenter *= o_rGradientInfo.maTextureTransform;
82 o_rGradientInfo.maTextureTransform.translate(-aCenter.getX(), -aCenter.getY());
83 o_rGradientInfo.maTextureTransform.rotate(fAngle);
84 o_rGradientInfo.maTextureTransform.translate(aCenter.getX(), aCenter.getY());
87 // add object translate
88 o_rGradientInfo.maTextureTransform.translate(fTargetOffsetX, fTargetOffsetY);
90 // prepare aspect for texture
91 o_rGradientInfo.mfAspectRatio = (0.0 != fTargetSizeY) ? fTargetSizeX / fTargetSizeY : 1.0;
93 // build transform from u,v to [0.0 .. 1.0]. As base, use inverse texture transform
94 o_rGradientInfo.maBackTextureTransform = o_rGradientInfo.maTextureTransform;
95 o_rGradientInfo.maBackTextureTransform.invert();
97 double fSizeWithoutBorder=0;
98 if( bAxial )
100 fSizeWithoutBorder = (1.0 - fBorder) * 0.5;
101 o_rGradientInfo.maBackTextureTransform.translate(0.0, -0.5);
103 else
105 fSizeWithoutBorder = 1.0 - fBorder;
106 o_rGradientInfo.maBackTextureTransform.translate(0.0, -fBorder);
109 if(!fTools::equal(fSizeWithoutBorder, 0.0))
110 o_rGradientInfo.maBackTextureTransform.scale(1.0, 1.0 / fSizeWithoutBorder);
113 /** Most of the setup for radial & ellipsoidal gradient is the same,
114 except for the border treatment. Factored out here.
116 static void initEllipticalGradientInfo(ODFGradientInfo& o_rGradientInfo,
117 const B2DRange& rTargetRange,
118 const B2DVector& rOffset,
119 sal_uInt32 nSteps,
120 double fBorder,
121 double fAngle,
122 bool bCircular)
124 o_rGradientInfo.maTextureTransform.identity();
125 o_rGradientInfo.maBackTextureTransform.identity();
126 o_rGradientInfo.mnSteps = nSteps;
128 double fTargetSizeX(rTargetRange.getWidth());
129 double fTargetSizeY(rTargetRange.getHeight());
130 double fTargetOffsetX(rTargetRange.getMinX());
131 double fTargetOffsetY(rTargetRange.getMinY());
133 // add object expansion
134 if( bCircular )
136 const double fOriginalDiag(sqrt((fTargetSizeX * fTargetSizeX) + (fTargetSizeY * fTargetSizeY)));
137 fTargetOffsetX -= (fOriginalDiag - fTargetSizeX) / 2.0;
138 fTargetOffsetY -= (fOriginalDiag - fTargetSizeY) / 2.0;
139 fTargetSizeX = fOriginalDiag;
140 fTargetSizeY = fOriginalDiag;
142 else
144 fTargetOffsetX -= (0.4142 / 2.0 ) * fTargetSizeX;
145 fTargetOffsetY -= (0.4142 / 2.0 ) * fTargetSizeY;
146 fTargetSizeX = 1.4142 * fTargetSizeX;
147 fTargetSizeY = 1.4142 * fTargetSizeY;
150 // add object scale before rotate
151 o_rGradientInfo.maTextureTransform.scale(fTargetSizeX, fTargetSizeY);
153 if( !bCircular )
155 // add texture rotate after scale to keep perpendicular angles
156 if(0.0 != fAngle)
158 B2DPoint aCenter(0.5, 0.5);
159 aCenter *= o_rGradientInfo.maTextureTransform;
161 o_rGradientInfo.maTextureTransform.translate(-aCenter.getX(), -aCenter.getY());
162 o_rGradientInfo.maTextureTransform.rotate(fAngle);
163 o_rGradientInfo.maTextureTransform.translate(aCenter.getX(), aCenter.getY());
167 // add defined offsets after rotation
168 if(0.5 != rOffset.getX() || 0.5 != rOffset.getY())
170 // use original target size
171 fTargetOffsetX += (rOffset.getX() - 0.5) * rTargetRange.getWidth();
172 fTargetOffsetY += (rOffset.getY() - 0.5) * rTargetRange.getHeight();
175 // add object translate
176 o_rGradientInfo.maTextureTransform.translate(fTargetOffsetX, fTargetOffsetY);
178 // prepare aspect for texture
179 o_rGradientInfo.mfAspectRatio = (0.0 != fTargetSizeY) ? fTargetSizeX / fTargetSizeY : 1.0;
181 // build transform from u,v to [0.0 .. 1.0]. As base, use inverse texture transform
182 o_rGradientInfo.maBackTextureTransform = o_rGradientInfo.maTextureTransform;
183 o_rGradientInfo.maBackTextureTransform.invert();
184 o_rGradientInfo.maBackTextureTransform.translate(-0.5, -0.5);
185 const double fHalfBorder((1.0 - fBorder) * 0.5);
187 if(!fTools::equal(fHalfBorder, 0.0))
189 const double fFactor(1.0 / fHalfBorder);
190 o_rGradientInfo.maBackTextureTransform.scale(fFactor, fFactor);
194 /** Setup for rect & square gradient is exactly the same. Factored out
195 here.
197 static void initRectGradientInfo(ODFGradientInfo& o_rGradientInfo,
198 const B2DRange& rTargetRange,
199 const B2DVector& rOffset,
200 sal_uInt32 nSteps,
201 double fBorder,
202 double fAngle)
204 o_rGradientInfo.maTextureTransform.identity();
205 o_rGradientInfo.maBackTextureTransform.identity();
206 o_rGradientInfo.mnSteps = nSteps;
208 double fTargetSizeX(rTargetRange.getWidth());
209 double fTargetSizeY(rTargetRange.getHeight());
210 double fTargetOffsetX(rTargetRange.getMinX());
211 double fTargetOffsetY(rTargetRange.getMinY());
213 // add object expansion
214 if(0.0 != fAngle)
216 const double fAbsCos(fabs(cos(fAngle)));
217 const double fAbsSin(fabs(sin(fAngle)));
218 const double fNewX(fTargetSizeX * fAbsCos + fTargetSizeY * fAbsSin);
219 const double fNewY(fTargetSizeY * fAbsCos + fTargetSizeX * fAbsSin);
220 fTargetOffsetX -= (fNewX - fTargetSizeX) / 2.0;
221 fTargetOffsetY -= (fNewY - fTargetSizeY) / 2.0;
222 fTargetSizeX = fNewX;
223 fTargetSizeY = fNewY;
226 // add object scale before rotate
227 o_rGradientInfo.maTextureTransform.scale(fTargetSizeX, fTargetSizeY);
229 // add texture rotate after scale to keep perpendicular angles
230 if(0.0 != fAngle)
232 B2DPoint aCenter(0.5, 0.5);
233 aCenter *= o_rGradientInfo.maTextureTransform;
235 o_rGradientInfo.maTextureTransform.translate(-aCenter.getX(), -aCenter.getY());
236 o_rGradientInfo.maTextureTransform.rotate(fAngle);
237 o_rGradientInfo.maTextureTransform.translate(aCenter.getX(), aCenter.getY());
240 // add defined offsets after rotation
241 if(0.5 != rOffset.getX() || 0.5 != rOffset.getY())
243 // use scaled target size
244 fTargetOffsetX += (rOffset.getX() - 0.5) * fTargetSizeX;
245 fTargetOffsetY += (rOffset.getY() - 0.5) * fTargetSizeY;
248 // add object translate
249 o_rGradientInfo.maTextureTransform.translate(fTargetOffsetX, fTargetOffsetY);
251 // prepare aspect for texture
252 o_rGradientInfo.mfAspectRatio = (0.0 != fTargetSizeY) ? fTargetSizeX / fTargetSizeY : 1.0;
254 // build transform from u,v to [0.0 .. 1.0]. As base, use inverse texture transform
255 o_rGradientInfo.maBackTextureTransform = o_rGradientInfo.maTextureTransform;
256 o_rGradientInfo.maBackTextureTransform.invert();
257 o_rGradientInfo.maBackTextureTransform.translate(-0.5, -0.5);
258 const double fHalfBorder((1.0 - fBorder) * 0.5);
260 if(!fTools::equal(fHalfBorder, 0.0))
262 const double fFactor(1.0 / fHalfBorder);
263 o_rGradientInfo.maBackTextureTransform.scale(fFactor, fFactor);
267 namespace tools
269 ODFGradientInfo& createLinearODFGradientInfo(ODFGradientInfo& o_rGradientInfo,
270 const B2DRange& rTargetArea,
271 sal_uInt32 nSteps,
272 double fBorder,
273 double fAngle)
275 init1DGradientInfo(o_rGradientInfo,
276 rTargetArea,
277 nSteps,
278 fBorder,
279 fAngle,
280 false);
281 return o_rGradientInfo;
284 ODFGradientInfo& createAxialODFGradientInfo(ODFGradientInfo& o_rGradientInfo,
285 const B2DRange& rTargetArea,
286 sal_uInt32 nSteps,
287 double fBorder,
288 double fAngle)
290 init1DGradientInfo(o_rGradientInfo,
291 rTargetArea,
292 nSteps,
293 fBorder,
294 fAngle,
295 true);
296 return o_rGradientInfo;
299 ODFGradientInfo& createRadialODFGradientInfo(ODFGradientInfo& o_rGradientInfo,
300 const B2DRange& rTargetArea,
301 const B2DVector& rOffset,
302 sal_uInt32 nSteps,
303 double fBorder)
305 initEllipticalGradientInfo(o_rGradientInfo,
306 rTargetArea,
307 rOffset,
308 nSteps,
309 fBorder,
310 0.0,
311 true);
312 return o_rGradientInfo;
315 ODFGradientInfo& createEllipticalODFGradientInfo(ODFGradientInfo& o_rGradientInfo,
316 const B2DRange& rTargetArea,
317 const B2DVector& rOffset,
318 sal_uInt32 nSteps,
319 double fBorder,
320 double fAngle)
322 initEllipticalGradientInfo(o_rGradientInfo,
323 rTargetArea,
324 rOffset,
325 nSteps,
326 fBorder,
327 fAngle,
328 false);
329 return o_rGradientInfo;
332 ODFGradientInfo& createSquareODFGradientInfo(ODFGradientInfo& o_rGradientInfo,
333 const B2DRange& rTargetArea,
334 const B2DVector& rOffset,
335 sal_uInt32 nSteps,
336 double fBorder,
337 double fAngle)
339 initRectGradientInfo(o_rGradientInfo,
340 rTargetArea,
341 rOffset,
342 nSteps,
343 fBorder,
344 fAngle);
345 return o_rGradientInfo;
348 ODFGradientInfo& createRectangularODFGradientInfo(ODFGradientInfo& o_rGradientInfo,
349 const B2DRange& rTargetArea,
350 const B2DVector& rOffset,
351 sal_uInt32 nSteps,
352 double fBorder,
353 double fAngle)
355 initRectGradientInfo(o_rGradientInfo,
356 rTargetArea,
357 rOffset,
358 nSteps,
359 fBorder,
360 fAngle);
361 return o_rGradientInfo;
364 } // namespace tools
366 } // namespace basegfx