Version 6.1.0.2, tag libreoffice-6.1.0.2
[LibreOffice.git] / basegfx / source / tools / gradienttools.cxx
blobb05d9b219a535839fd0c961be5b42febb7a5c337
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/utils/gradienttools.hxx>
21 #include <basegfx/point/b2dpoint.hxx>
22 #include <basegfx/range/b2drange.hxx>
23 #include <basegfx/matrix/b2dhommatrixtools.hxx>
25 namespace basegfx
27 bool ODFGradientInfo::operator==(const ODFGradientInfo& rODFGradientInfo) const
29 return getTextureTransform() == rODFGradientInfo.getTextureTransform()
30 && getAspectRatio() == rODFGradientInfo.getAspectRatio()
31 && getSteps() == rODFGradientInfo.getSteps();
34 const B2DHomMatrix& ODFGradientInfo::getBackTextureTransform() const
36 if(maBackTextureTransform.isIdentity())
38 const_cast< ODFGradientInfo* >(this)->maBackTextureTransform = getTextureTransform();
39 const_cast< ODFGradientInfo* >(this)->maBackTextureTransform.invert();
42 return maBackTextureTransform;
45 /** Most of the setup for linear & axial gradient is the same, except
46 for the border treatment. Factored out here.
48 ODFGradientInfo init1DGradientInfo(
49 const B2DRange& rTargetRange,
50 sal_uInt32 nSteps,
51 double fBorder,
52 double fAngle,
53 bool bAxial)
55 B2DHomMatrix aTextureTransform;
57 fAngle = -fAngle;
59 double fTargetSizeX(rTargetRange.getWidth());
60 double fTargetSizeY(rTargetRange.getHeight());
61 double fTargetOffsetX(rTargetRange.getMinX());
62 double fTargetOffsetY(rTargetRange.getMinY());
64 // add object expansion
65 const bool bAngleUsed(!fTools::equalZero(fAngle));
67 if(bAngleUsed)
69 const double fAbsCos(fabs(cos(fAngle)));
70 const double fAbsSin(fabs(sin(fAngle)));
71 const double fNewX(fTargetSizeX * fAbsCos + fTargetSizeY * fAbsSin);
72 const double fNewY(fTargetSizeY * fAbsCos + fTargetSizeX * fAbsSin);
74 fTargetOffsetX -= (fNewX - fTargetSizeX) / 2.0;
75 fTargetOffsetY -= (fNewY - fTargetSizeY) / 2.0;
76 fTargetSizeX = fNewX;
77 fTargetSizeY = fNewY;
80 const double fSizeWithoutBorder(1.0 - fBorder);
82 if(bAxial)
84 aTextureTransform.scale(1.0, fSizeWithoutBorder * 0.5);
85 aTextureTransform.translate(0.0, 0.5);
87 else
89 if(!fTools::equal(fSizeWithoutBorder, 1.0))
91 aTextureTransform.scale(1.0, fSizeWithoutBorder);
92 aTextureTransform.translate(0.0, fBorder);
96 aTextureTransform.scale(fTargetSizeX, fTargetSizeY);
98 // add texture rotate after scale to keep perpendicular angles
99 if(bAngleUsed)
101 const B2DPoint aCenter(0.5 * fTargetSizeX, 0.5 * fTargetSizeY);
103 aTextureTransform *= basegfx::utils::createRotateAroundPoint(aCenter, fAngle);
106 // add object translate
107 aTextureTransform.translate(fTargetOffsetX, fTargetOffsetY);
109 // prepare aspect for texture
110 const double fAspectRatio(fTools::equalZero(fTargetSizeY) ? 1.0 : fTargetSizeX / fTargetSizeY);
112 return ODFGradientInfo(aTextureTransform, fAspectRatio, nSteps);
115 /** Most of the setup for radial & ellipsoidal gradient is the same,
116 except for the border treatment. Factored out here.
118 ODFGradientInfo initEllipticalGradientInfo(
119 const B2DRange& rTargetRange,
120 const B2DVector& rOffset,
121 sal_uInt32 nSteps,
122 double fBorder,
123 double fAngle,
124 bool bCircular)
126 B2DHomMatrix aTextureTransform;
128 fAngle = -fAngle;
130 double fTargetSizeX(rTargetRange.getWidth());
131 double fTargetSizeY(rTargetRange.getHeight());
132 double fTargetOffsetX(rTargetRange.getMinX());
133 double fTargetOffsetY(rTargetRange.getMinY());
135 // add object expansion
136 if(bCircular)
138 const double fOriginalDiag(sqrt((fTargetSizeX * fTargetSizeX) + (fTargetSizeY * fTargetSizeY)));
140 fTargetOffsetX -= (fOriginalDiag - fTargetSizeX) / 2.0;
141 fTargetOffsetY -= (fOriginalDiag - fTargetSizeY) / 2.0;
142 fTargetSizeX = fOriginalDiag;
143 fTargetSizeY = fOriginalDiag;
145 else
147 fTargetOffsetX -= (0.4142 / 2.0 ) * fTargetSizeX;
148 fTargetOffsetY -= (0.4142 / 2.0 ) * fTargetSizeY;
149 fTargetSizeX = 1.4142 * fTargetSizeX;
150 fTargetSizeY = 1.4142 * fTargetSizeY;
153 const double fHalfBorder((1.0 - fBorder) * 0.5);
155 aTextureTransform.scale(fHalfBorder, fHalfBorder);
156 aTextureTransform.translate(0.5, 0.5);
157 aTextureTransform.scale(fTargetSizeX, fTargetSizeY);
159 // add texture rotate after scale to keep perpendicular angles
160 if(!bCircular && !fTools::equalZero(fAngle))
162 const B2DPoint aCenter(0.5 * fTargetSizeX, 0.5 * fTargetSizeY);
164 aTextureTransform *= basegfx::utils::createRotateAroundPoint(aCenter, fAngle);
167 // add defined offsets after rotation
168 if(!fTools::equal(0.5, rOffset.getX()) || !fTools::equal(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 aTextureTransform.translate(fTargetOffsetX, fTargetOffsetY);
178 // prepare aspect for texture
179 const double fAspectRatio(fTargetSizeY == 0.0 ? 1.0 : (fTargetSizeX / fTargetSizeY));
181 return ODFGradientInfo(aTextureTransform, fAspectRatio, nSteps);
184 /** Setup for rect & square gradient is exactly the same. Factored out
185 here.
187 ODFGradientInfo initRectGradientInfo(
188 const B2DRange& rTargetRange,
189 const B2DVector& rOffset,
190 sal_uInt32 nSteps,
191 double fBorder,
192 double fAngle,
193 bool bSquare)
195 B2DHomMatrix aTextureTransform;
197 fAngle = -fAngle;
199 double fTargetSizeX(rTargetRange.getWidth());
200 double fTargetSizeY(rTargetRange.getHeight());
201 double fTargetOffsetX(rTargetRange.getMinX());
202 double fTargetOffsetY(rTargetRange.getMinY());
204 // add object expansion
205 if(bSquare)
207 const double fSquareWidth(std::max(fTargetSizeX, fTargetSizeY));
209 fTargetOffsetX -= (fSquareWidth - fTargetSizeX) / 2.0;
210 fTargetOffsetY -= (fSquareWidth - fTargetSizeY) / 2.0;
211 fTargetSizeX = fTargetSizeY = fSquareWidth;
214 // add object expansion
215 const bool bAngleUsed(!fTools::equalZero(fAngle));
217 if(bAngleUsed)
219 const double fAbsCos(fabs(cos(fAngle)));
220 const double fAbsSin(fabs(sin(fAngle)));
221 const double fNewX(fTargetSizeX * fAbsCos + fTargetSizeY * fAbsSin);
222 const double fNewY(fTargetSizeY * fAbsCos + fTargetSizeX * fAbsSin);
224 fTargetOffsetX -= (fNewX - fTargetSizeX) / 2.0;
225 fTargetOffsetY -= (fNewY - fTargetSizeY) / 2.0;
226 fTargetSizeX = fNewX;
227 fTargetSizeY = fNewY;
230 const double fHalfBorder((1.0 - fBorder) * 0.5);
232 aTextureTransform.scale(fHalfBorder, fHalfBorder);
233 aTextureTransform.translate(0.5, 0.5);
234 aTextureTransform.scale(fTargetSizeX, fTargetSizeY);
236 // add texture rotate after scale to keep perpendicular angles
237 if(bAngleUsed)
239 const B2DPoint aCenter(0.5 * fTargetSizeX, 0.5 * fTargetSizeY);
241 aTextureTransform *= basegfx::utils::createRotateAroundPoint(aCenter, fAngle);
244 // add defined offsets after rotation
245 if(!fTools::equal(0.5, rOffset.getX()) || !fTools::equal(0.5, rOffset.getY()))
247 // use scaled target size
248 fTargetOffsetX += (rOffset.getX() - 0.5) * fTargetSizeX;
249 fTargetOffsetY += (rOffset.getY() - 0.5) * fTargetSizeY;
252 // add object translate
253 aTextureTransform.translate(fTargetOffsetX, fTargetOffsetY);
255 // prepare aspect for texture
256 const double fAspectRatio(fTargetSizeY == 0.0 ? 1.0 : (fTargetSizeX / fTargetSizeY));
258 return ODFGradientInfo(aTextureTransform, fAspectRatio, nSteps);
261 namespace utils
263 ODFGradientInfo createLinearODFGradientInfo(
264 const B2DRange& rTargetArea,
265 sal_uInt32 nSteps,
266 double fBorder,
267 double fAngle)
269 return init1DGradientInfo(
270 rTargetArea,
271 nSteps,
272 fBorder,
273 fAngle,
274 false);
277 ODFGradientInfo createAxialODFGradientInfo(
278 const B2DRange& rTargetArea,
279 sal_uInt32 nSteps,
280 double fBorder,
281 double fAngle)
283 return init1DGradientInfo(
284 rTargetArea,
285 nSteps,
286 fBorder,
287 fAngle,
288 true);
291 ODFGradientInfo createRadialODFGradientInfo(
292 const B2DRange& rTargetArea,
293 const B2DVector& rOffset,
294 sal_uInt32 nSteps,
295 double fBorder)
297 return initEllipticalGradientInfo(
298 rTargetArea,
299 rOffset,
300 nSteps,
301 fBorder,
302 0.0,
303 true);
306 ODFGradientInfo createEllipticalODFGradientInfo(
307 const B2DRange& rTargetArea,
308 const B2DVector& rOffset,
309 sal_uInt32 nSteps,
310 double fBorder,
311 double fAngle)
313 return initEllipticalGradientInfo(
314 rTargetArea,
315 rOffset,
316 nSteps,
317 fBorder,
318 fAngle,
319 false);
322 ODFGradientInfo createSquareODFGradientInfo(
323 const B2DRange& rTargetArea,
324 const B2DVector& rOffset,
325 sal_uInt32 nSteps,
326 double fBorder,
327 double fAngle)
329 return initRectGradientInfo(
330 rTargetArea,
331 rOffset,
332 nSteps,
333 fBorder,
334 fAngle,
335 true);
338 ODFGradientInfo createRectangularODFGradientInfo(
339 const B2DRange& rTargetArea,
340 const B2DVector& rOffset,
341 sal_uInt32 nSteps,
342 double fBorder,
343 double fAngle)
345 return initRectGradientInfo(
346 rTargetArea,
347 rOffset,
348 nSteps,
349 fBorder,
350 fAngle,
351 false);
354 double getLinearGradientAlpha(const B2DPoint& rUV, const ODFGradientInfo& rGradInfo)
356 const B2DPoint aCoor(rGradInfo.getBackTextureTransform() * rUV);
358 // Ignore Y, this is not needed at all for Y-Oriented gradients
359 // if(aCoor.getX() < 0.0 || aCoor.getX() > 1.0)
360 // {
361 // return 0.0;
362 // }
364 if(aCoor.getY() <= 0.0)
366 return 0.0; // start value for inside
369 if(aCoor.getY() >= 1.0)
371 return 1.0; // end value for outside
374 const sal_uInt32 nSteps(rGradInfo.getSteps());
376 if(nSteps)
378 return floor(aCoor.getY() * nSteps) / double(nSteps - 1);
381 return aCoor.getY();
384 double getAxialGradientAlpha(const B2DPoint& rUV, const ODFGradientInfo& rGradInfo)
386 const B2DPoint aCoor(rGradInfo.getBackTextureTransform() * rUV);
388 // Ignore Y, this is not needed at all for Y-Oriented gradients
389 //if(aCoor.getX() < 0.0 || aCoor.getX() > 1.0)
391 // return 0.0;
394 const double fAbsY(fabs(aCoor.getY()));
396 if(fAbsY >= 1.0)
398 return 1.0; // use end value when outside in Y
401 const sal_uInt32 nSteps(rGradInfo.getSteps());
403 if(nSteps)
405 return floor(fAbsY * nSteps) / double(nSteps - 1);
408 return fAbsY;
411 double getRadialGradientAlpha(const B2DPoint& rUV, const ODFGradientInfo& rGradInfo)
413 const B2DPoint aCoor(rGradInfo.getBackTextureTransform() * rUV);
415 if(aCoor.getX() < -1.0 || aCoor.getX() > 1.0 || aCoor.getY() < -1.0 || aCoor.getY() > 1.0)
417 return 0.0;
420 const double t(1.0 - sqrt(aCoor.getX() * aCoor.getX() + aCoor.getY() * aCoor.getY()));
421 const sal_uInt32 nSteps(rGradInfo.getSteps());
423 if(nSteps && t < 1.0)
425 return floor(t * nSteps) / double(nSteps - 1);
428 return t;
431 double getEllipticalGradientAlpha(const B2DPoint& rUV, const ODFGradientInfo& rGradInfo)
433 return getRadialGradientAlpha(rUV, rGradInfo); // only matrix setup differs
436 double getSquareGradientAlpha(const B2DPoint& rUV, const ODFGradientInfo& rGradInfo)
438 const B2DPoint aCoor(rGradInfo.getBackTextureTransform() * rUV);
439 const double fAbsX(fabs(aCoor.getX()));
441 if(fAbsX >= 1.0)
443 return 0.0;
446 const double fAbsY(fabs(aCoor.getY()));
448 if(fAbsY >= 1.0)
450 return 0.0;
453 const double t(1.0 - std::max(fAbsX, fAbsY));
454 const sal_uInt32 nSteps(rGradInfo.getSteps());
456 if(nSteps && t < 1.0)
458 return floor(t * nSteps) / double(nSteps - 1);
461 return t;
464 double getRectangularGradientAlpha(const B2DPoint& rUV, const ODFGradientInfo& rGradInfo)
466 return getSquareGradientAlpha(rUV, rGradInfo); // only matrix setup differs
468 } // namespace utils
469 } // namespace basegfx
471 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */