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/utils/gradienttools.hxx>
21 #include <basegfx/point/b2dpoint.hxx>
22 #include <basegfx/range/b2drange.hxx>
23 #include <basegfx/matrix/b2dhommatrixtools.hxx>
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
,
55 B2DHomMatrix aTextureTransform
;
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
));
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;
80 const double fSizeWithoutBorder(1.0 - fBorder
);
84 aTextureTransform
.scale(1.0, fSizeWithoutBorder
* 0.5);
85 aTextureTransform
.translate(0.0, 0.5);
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
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
,
126 B2DHomMatrix aTextureTransform
;
130 double fTargetSizeX(rTargetRange
.getWidth());
131 double fTargetSizeY(rTargetRange
.getHeight());
132 double fTargetOffsetX(rTargetRange
.getMinX());
133 double fTargetOffsetY(rTargetRange
.getMinY());
135 // add object expansion
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
;
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
187 ODFGradientInfo
initRectGradientInfo(
188 const B2DRange
& rTargetRange
,
189 const B2DVector
& rOffset
,
195 B2DHomMatrix aTextureTransform
;
199 double fTargetSizeX(rTargetRange
.getWidth());
200 double fTargetSizeY(rTargetRange
.getHeight());
201 double fTargetOffsetX(rTargetRange
.getMinX());
202 double fTargetOffsetY(rTargetRange
.getMinY());
204 // add object expansion
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
));
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
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
);
263 ODFGradientInfo
createLinearODFGradientInfo(
264 const B2DRange
& rTargetArea
,
269 return init1DGradientInfo(
277 ODFGradientInfo
createAxialODFGradientInfo(
278 const B2DRange
& rTargetArea
,
283 return init1DGradientInfo(
291 ODFGradientInfo
createRadialODFGradientInfo(
292 const B2DRange
& rTargetArea
,
293 const B2DVector
& rOffset
,
297 return initEllipticalGradientInfo(
306 ODFGradientInfo
createEllipticalODFGradientInfo(
307 const B2DRange
& rTargetArea
,
308 const B2DVector
& rOffset
,
313 return initEllipticalGradientInfo(
322 ODFGradientInfo
createSquareODFGradientInfo(
323 const B2DRange
& rTargetArea
,
324 const B2DVector
& rOffset
,
329 return initRectGradientInfo(
338 ODFGradientInfo
createRectangularODFGradientInfo(
339 const B2DRange
& rTargetArea
,
340 const B2DVector
& rOffset
,
345 return initRectGradientInfo(
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)
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());
378 return floor(aCoor
.getY() * nSteps
) / double(nSteps
- 1);
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)
394 const double fAbsY(fabs(aCoor
.getY()));
398 return 1.0; // use end value when outside in Y
401 const sal_uInt32
nSteps(rGradInfo
.getSteps());
405 return floor(fAbsY
* nSteps
) / double(nSteps
- 1);
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)
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);
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()));
446 const double fAbsY(fabs(aCoor
.getY()));
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);
464 double getRectangularGradientAlpha(const B2DPoint
& rUV
, const ODFGradientInfo
& rGradInfo
)
466 return getSquareGradientAlpha(rUV
, rGradInfo
); // only matrix setup differs
469 } // namespace basegfx
471 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */