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/tools/gradienttools.hxx>
21 #include <basegfx/point/b2dpoint.hxx>
22 #include <basegfx/range/b2drange.hxx>
23 #include <basegfx/matrix/b2dhommatrixtools.hxx>
27 /** Most of the setup for linear & axial gradient is the same, except
28 for the border treatment. Factored out here.
30 static void init1DGradientInfo(ODFGradientInfo
& o_rGradientInfo
,
31 const B2DRange
& rTargetRange
,
37 o_rGradientInfo
.maTextureTransform
.identity();
38 o_rGradientInfo
.maBackTextureTransform
.identity();
39 o_rGradientInfo
.mnSteps
= nSteps
;
43 double fTargetSizeX(rTargetRange
.getWidth());
44 double fTargetSizeY(rTargetRange
.getHeight());
45 double fTargetOffsetX(rTargetRange
.getMinX());
46 double fTargetOffsetY(rTargetRange
.getMinY());
48 // add object expansion
51 const double fAbsCos(fabs(cos(fAngle
)));
52 const double fAbsSin(fabs(sin(fAngle
)));
53 const double fNewX(fTargetSizeX
* fAbsCos
+ fTargetSizeY
* fAbsSin
);
54 const double fNewY(fTargetSizeY
* fAbsCos
+ fTargetSizeX
* fAbsSin
);
55 fTargetOffsetX
-= (fNewX
- fTargetSizeX
) / 2.0;
56 fTargetOffsetY
-= (fNewY
- fTargetSizeY
) / 2.0;
61 const double fSizeWithoutBorder
=1.0 - fBorder
;
64 o_rGradientInfo
.maTextureTransform
.scale(1.0, fSizeWithoutBorder
* .5);
65 o_rGradientInfo
.maTextureTransform
.translate(0.0, 0.5);
69 if(!fTools::equal(fSizeWithoutBorder
, 1.0))
71 o_rGradientInfo
.maTextureTransform
.scale(1.0, fSizeWithoutBorder
);
72 o_rGradientInfo
.maTextureTransform
.translate(0.0, fBorder
);
76 o_rGradientInfo
.maTextureTransform
.scale(fTargetSizeX
, fTargetSizeY
);
78 // add texture rotate after scale to keep perpendicular angles
81 const B2DPoint
aCenter(0.5*fTargetSizeX
,
83 o_rGradientInfo
.maTextureTransform
*=
84 basegfx::tools::createRotateAroundPoint(aCenter
, fAngle
);
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].
94 o_rGradientInfo
.maBackTextureTransform
= o_rGradientInfo
.maTextureTransform
;
95 o_rGradientInfo
.maBackTextureTransform
.invert();
98 /** Most of the setup for radial & ellipsoidal gradient is the same,
99 except for the border treatment. Factored out here.
101 static void initEllipticalGradientInfo(ODFGradientInfo
& o_rGradientInfo
,
102 const B2DRange
& rTargetRange
,
103 const B2DVector
& rOffset
,
109 o_rGradientInfo
.maTextureTransform
.identity();
110 o_rGradientInfo
.maBackTextureTransform
.identity();
111 o_rGradientInfo
.mnSteps
= nSteps
;
115 double fTargetSizeX(rTargetRange
.getWidth());
116 double fTargetSizeY(rTargetRange
.getHeight());
117 double fTargetOffsetX(rTargetRange
.getMinX());
118 double fTargetOffsetY(rTargetRange
.getMinY());
120 // add object expansion
123 const double fOriginalDiag(sqrt((fTargetSizeX
* fTargetSizeX
) + (fTargetSizeY
* fTargetSizeY
)));
124 fTargetOffsetX
-= (fOriginalDiag
- fTargetSizeX
) / 2.0;
125 fTargetOffsetY
-= (fOriginalDiag
- fTargetSizeY
) / 2.0;
126 fTargetSizeX
= fOriginalDiag
;
127 fTargetSizeY
= fOriginalDiag
;
131 fTargetOffsetX
-= (0.4142 / 2.0 ) * fTargetSizeX
;
132 fTargetOffsetY
-= (0.4142 / 2.0 ) * fTargetSizeY
;
133 fTargetSizeX
= 1.4142 * fTargetSizeX
;
134 fTargetSizeY
= 1.4142 * fTargetSizeY
;
137 const double fHalfBorder((1.0 - fBorder
) * 0.5);
138 o_rGradientInfo
.maTextureTransform
.scale(fHalfBorder
, fHalfBorder
);
140 o_rGradientInfo
.maTextureTransform
.translate(0.5, 0.5);
141 o_rGradientInfo
.maTextureTransform
.scale(fTargetSizeX
, fTargetSizeY
);
143 // add texture rotate after scale to keep perpendicular angles
144 if( !bCircular
&& 0.0 != fAngle
)
146 const B2DPoint
aCenter(0.5*fTargetSizeX
,
148 o_rGradientInfo
.maTextureTransform
*=
149 basegfx::tools::createRotateAroundPoint(aCenter
, fAngle
);
152 // add defined offsets after rotation
153 if(0.5 != rOffset
.getX() || 0.5 != rOffset
.getY())
155 // use original target size
156 fTargetOffsetX
+= (rOffset
.getX() - 0.5) * rTargetRange
.getWidth();
157 fTargetOffsetY
+= (rOffset
.getY() - 0.5) * rTargetRange
.getHeight();
160 // add object translate
161 o_rGradientInfo
.maTextureTransform
.translate(fTargetOffsetX
, fTargetOffsetY
);
163 // prepare aspect for texture
164 o_rGradientInfo
.mfAspectRatio
= (0.0 != fTargetSizeY
) ? fTargetSizeX
/ fTargetSizeY
: 1.0;
166 // build transform from u,v to [0.0 .. 1.0].
167 o_rGradientInfo
.maBackTextureTransform
= o_rGradientInfo
.maTextureTransform
;
168 o_rGradientInfo
.maBackTextureTransform
.invert();
171 /** Setup for rect & square gradient is exactly the same. Factored out
174 static void initRectGradientInfo(ODFGradientInfo
& o_rGradientInfo
,
175 const B2DRange
& rTargetRange
,
176 const B2DVector
& rOffset
,
182 o_rGradientInfo
.maTextureTransform
.identity();
183 o_rGradientInfo
.maBackTextureTransform
.identity();
184 o_rGradientInfo
.mnSteps
= nSteps
;
188 double fTargetSizeX(rTargetRange
.getWidth());
189 double fTargetSizeY(rTargetRange
.getHeight());
190 double fTargetOffsetX(rTargetRange
.getMinX());
191 double fTargetOffsetY(rTargetRange
.getMinY());
193 // add object expansion
196 const double fSquareWidth(std::max(fTargetSizeX
, fTargetSizeY
));
197 fTargetOffsetX
-= (fSquareWidth
- fTargetSizeX
) / 2.0;
198 fTargetOffsetY
-= (fSquareWidth
- fTargetSizeY
) / 2.0;
199 fTargetSizeX
= fTargetSizeY
= fSquareWidth
;
202 // add object expansion
205 const double fAbsCos(fabs(cos(fAngle
)));
206 const double fAbsSin(fabs(sin(fAngle
)));
207 const double fNewX(fTargetSizeX
* fAbsCos
+ fTargetSizeY
* fAbsSin
);
208 const double fNewY(fTargetSizeY
* fAbsCos
+ fTargetSizeX
* fAbsSin
);
209 fTargetOffsetX
-= (fNewX
- fTargetSizeX
) / 2.0;
210 fTargetOffsetY
-= (fNewY
- fTargetSizeY
) / 2.0;
211 fTargetSizeX
= fNewX
;
212 fTargetSizeY
= fNewY
;
215 const double fHalfBorder((1.0 - fBorder
) * 0.5);
216 o_rGradientInfo
.maTextureTransform
.scale(fHalfBorder
, fHalfBorder
);
218 o_rGradientInfo
.maTextureTransform
.translate(0.5, 0.5);
219 o_rGradientInfo
.maTextureTransform
.scale(fTargetSizeX
, fTargetSizeY
);
221 // add texture rotate after scale to keep perpendicular angles
224 const B2DPoint
aCenter(0.5*fTargetSizeX
,
226 o_rGradientInfo
.maTextureTransform
*=
227 basegfx::tools::createRotateAroundPoint(aCenter
, fAngle
);
230 // add defined offsets after rotation
231 if(0.5 != rOffset
.getX() || 0.5 != rOffset
.getY())
233 // use scaled target size
234 fTargetOffsetX
+= (rOffset
.getX() - 0.5) * fTargetSizeX
;
235 fTargetOffsetY
+= (rOffset
.getY() - 0.5) * fTargetSizeY
;
238 // add object translate
239 o_rGradientInfo
.maTextureTransform
.translate(fTargetOffsetX
, fTargetOffsetY
);
241 // prepare aspect for texture
242 o_rGradientInfo
.mfAspectRatio
= (0.0 != fTargetSizeY
) ? fTargetSizeX
/ fTargetSizeY
: 1.0;
244 // build transform from u,v to [0.0 .. 1.0]. As base, use inverse texture transform
245 o_rGradientInfo
.maBackTextureTransform
= o_rGradientInfo
.maTextureTransform
;
246 o_rGradientInfo
.maBackTextureTransform
.invert();
251 ODFGradientInfo
& createLinearODFGradientInfo(ODFGradientInfo
& o_rGradientInfo
,
252 const B2DRange
& rTargetArea
,
257 init1DGradientInfo(o_rGradientInfo
,
263 return o_rGradientInfo
;
266 ODFGradientInfo
& createAxialODFGradientInfo(ODFGradientInfo
& o_rGradientInfo
,
267 const B2DRange
& rTargetArea
,
272 init1DGradientInfo(o_rGradientInfo
,
278 return o_rGradientInfo
;
281 ODFGradientInfo
& createRadialODFGradientInfo(ODFGradientInfo
& o_rGradientInfo
,
282 const B2DRange
& rTargetArea
,
283 const B2DVector
& rOffset
,
287 initEllipticalGradientInfo(o_rGradientInfo
,
294 return o_rGradientInfo
;
297 ODFGradientInfo
& createEllipticalODFGradientInfo(ODFGradientInfo
& o_rGradientInfo
,
298 const B2DRange
& rTargetArea
,
299 const B2DVector
& rOffset
,
304 initEllipticalGradientInfo(o_rGradientInfo
,
311 return o_rGradientInfo
;
314 ODFGradientInfo
& createSquareODFGradientInfo(ODFGradientInfo
& o_rGradientInfo
,
315 const B2DRange
& rTargetArea
,
316 const B2DVector
& rOffset
,
321 initRectGradientInfo(o_rGradientInfo
,
328 return o_rGradientInfo
;
331 ODFGradientInfo
& createRectangularODFGradientInfo(ODFGradientInfo
& o_rGradientInfo
,
332 const B2DRange
& rTargetArea
,
333 const B2DVector
& rOffset
,
338 initRectGradientInfo(o_rGradientInfo
,
345 return o_rGradientInfo
;
350 } // namespace basegfx
352 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */