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 .
21 #include "gradtrns.hxx"
22 #include <svx/svdobj.hxx>
23 #include <basegfx/range/b2drange.hxx>
24 #include <basegfx/matrix/b2dhommatrix.hxx>
25 #include <basegfx/matrix/b2dhommatrixtools.hxx>
26 #include <tools/helpers.hxx>
30 void GradTransformer::GradToVec(GradTransGradient
& rG
, GradTransVector
& rV
, const SdrObject
* pObj
)
33 rV
.aCol1
= rG
.aGradient
.GetStartColor();
34 if(100 != rG
.aGradient
.GetStartIntens())
36 const double fFact((double)rG
.aGradient
.GetStartIntens() / 100.0);
37 rV
.aCol1
= Color(rV
.aCol1
.getBColor() * fFact
);
41 rV
.aCol2
= rG
.aGradient
.GetEndColor();
42 if(100 != rG
.aGradient
.GetEndIntens())
44 const double fFact((double)rG
.aGradient
.GetEndIntens() / 100.0);
45 rV
.aCol2
= Color(rV
.aCol2
.getBColor() * fFact
);
48 // calc the basic positions
49 const Rectangle
aObjectSnapRectangle(pObj
->GetSnapRect());
50 const basegfx::B2DRange
aRange(aObjectSnapRectangle
.Left(), aObjectSnapRectangle
.Top(), aObjectSnapRectangle
.Right(), aObjectSnapRectangle
.Bottom());
51 const basegfx::B2DPoint
aCenter(aRange
.getCenter());
52 basegfx::B2DPoint aStartPos
, aEndPos
;
54 switch(rG
.aGradient
.GetGradientStyle())
56 case css::awt::GradientStyle_LINEAR
:
58 aStartPos
= basegfx::B2DPoint(aCenter
.getX(), aRange
.getMinY());
59 aEndPos
= basegfx::B2DPoint(aCenter
.getX(), aRange
.getMaximum().getY());
61 if(rG
.aGradient
.GetBorder())
63 basegfx::B2DVector
aFullVec(aStartPos
- aEndPos
);
64 const double fLen
= (aFullVec
.getLength() * (100.0 - (double)rG
.aGradient
.GetBorder())) / 100.0;
66 aStartPos
= aEndPos
+ (aFullVec
* fLen
);
69 if(rG
.aGradient
.GetAngle())
71 const double fAngle
= (double)rG
.aGradient
.GetAngle() * (F_PI180
/ 10.0);
72 const basegfx::B2DHomMatrix
aTransformation(basegfx::tools::createRotateAroundPoint(aCenter
, -fAngle
));
74 aStartPos
*= aTransformation
;
75 aEndPos
*= aTransformation
;
79 case css::awt::GradientStyle_AXIAL
:
82 aEndPos
= basegfx::B2DPoint(aCenter
.getX(), aRange
.getMaximum().getY());
84 if(rG
.aGradient
.GetBorder())
86 basegfx::B2DVector
aFullVec(aEndPos
- aStartPos
);
87 const double fLen
= (aFullVec
.getLength() * (100.0 - (double)rG
.aGradient
.GetBorder())) / 100.0;
89 aEndPos
= aStartPos
+ (aFullVec
* fLen
);
92 if(rG
.aGradient
.GetAngle())
94 const double fAngle
= (double)rG
.aGradient
.GetAngle() * (F_PI180
/ 10.0);
95 const basegfx::B2DHomMatrix
aTransformation(basegfx::tools::createRotateAroundPoint(aCenter
, -fAngle
));
97 aStartPos
*= aTransformation
;
98 aEndPos
*= aTransformation
;
102 case css::awt::GradientStyle_RADIAL
:
103 case css::awt::GradientStyle_SQUARE
:
105 aStartPos
= basegfx::B2DPoint(aRange
.getMinX(), aRange
.getMaximum().getY());
106 aEndPos
= basegfx::B2DPoint(aRange
.getMinX(), aRange
.getMinY());
108 if(rG
.aGradient
.GetBorder())
110 basegfx::B2DVector
aFullVec(aStartPos
- aEndPos
);
111 const double fLen
= (aFullVec
.getLength() * (100.0 - (double)rG
.aGradient
.GetBorder())) / 100.0;
112 aFullVec
.normalize();
113 aStartPos
= aEndPos
+ (aFullVec
* fLen
);
116 if(rG
.aGradient
.GetAngle())
118 const double fAngle
= (double)rG
.aGradient
.GetAngle() * (F_PI180
/ 10.0);
119 const basegfx::B2DHomMatrix
aTransformation(basegfx::tools::createRotateAroundPoint(aEndPos
, -fAngle
));
121 aStartPos
*= aTransformation
;
122 aEndPos
*= aTransformation
;
125 if(rG
.aGradient
.GetXOffset() || rG
.aGradient
.GetYOffset())
127 basegfx::B2DPoint
aOffset(
128 (aRange
.getWidth() * rG
.aGradient
.GetXOffset()) / 100.0,
129 (aRange
.getHeight() * rG
.aGradient
.GetYOffset()) / 100.0);
131 aStartPos
+= aOffset
;
137 case css::awt::GradientStyle_ELLIPTICAL
:
138 case css::awt::GradientStyle_RECT
:
140 aStartPos
= basegfx::B2DPoint(aRange
.getMinX(), aCenter
.getY());
141 aEndPos
= basegfx::B2DPoint(aRange
.getMinX(), aRange
.getMinY());
143 if(rG
.aGradient
.GetBorder())
145 basegfx::B2DVector
aFullVec(aStartPos
- aEndPos
);
146 const double fLen
= (aFullVec
.getLength() * (100.0 - (double)rG
.aGradient
.GetBorder())) / 100.0;
147 aFullVec
.normalize();
148 aStartPos
= aEndPos
+ (aFullVec
* fLen
);
151 if(rG
.aGradient
.GetAngle())
153 const double fAngle
= (double)rG
.aGradient
.GetAngle() * (F_PI180
/ 10.0);
154 const basegfx::B2DHomMatrix
aTransformation(basegfx::tools::createRotateAroundPoint(aEndPos
, -fAngle
));
156 aStartPos
*= aTransformation
;
157 aEndPos
*= aTransformation
;
160 if(rG
.aGradient
.GetXOffset() || rG
.aGradient
.GetYOffset())
162 basegfx::B2DPoint
aOffset(
163 (aRange
.getWidth() * rG
.aGradient
.GetXOffset()) / 100.0,
164 (aRange
.getHeight() * rG
.aGradient
.GetYOffset()) / 100.0);
166 aStartPos
+= aOffset
;
176 // set values for vector positions now
177 rV
.maPositionA
= aStartPos
;
178 rV
.maPositionB
= aEndPos
;
183 void GradTransformer::VecToGrad(GradTransVector
& rV
, GradTransGradient
& rG
, GradTransGradient
& rGOld
, const SdrObject
* pObj
,
184 bool bMoveSingle
, bool bMoveFirst
)
186 // fill old gradient to new gradient to have a base
189 // handle color changes
190 if(rV
.aCol1
!= rGOld
.aGradient
.GetStartColor())
192 rG
.aGradient
.SetStartColor(rV
.aCol1
);
193 rG
.aGradient
.SetStartIntens(100);
195 if(rV
.aCol2
!= rGOld
.aGradient
.GetEndColor())
197 rG
.aGradient
.SetEndColor(rV
.aCol2
);
198 rG
.aGradient
.SetEndIntens(100);
201 // calc the basic positions
202 const Rectangle
aObjectSnapRectangle(pObj
->GetSnapRect());
203 const basegfx::B2DRange
aRange(aObjectSnapRectangle
.Left(), aObjectSnapRectangle
.Top(), aObjectSnapRectangle
.Right(), aObjectSnapRectangle
.Bottom());
204 const basegfx::B2DPoint
aCenter(aRange
.getCenter());
205 basegfx::B2DPoint
aStartPos(rV
.maPositionA
);
206 basegfx::B2DPoint
aEndPos(rV
.maPositionB
);
208 switch(rG
.aGradient
.GetGradientStyle())
210 case css::awt::GradientStyle_LINEAR
:
212 if(!bMoveSingle
|| (bMoveSingle
&& !bMoveFirst
))
214 basegfx::B2DVector
aFullVec(aEndPos
- aStartPos
);
218 aFullVec
= aEndPos
- aCenter
;
221 aFullVec
.normalize();
223 double fNewFullAngle(atan2(aFullVec
.getY(), aFullVec
.getX()));
224 fNewFullAngle
/= F_PI180
;
225 fNewFullAngle
*= -10.0;
226 fNewFullAngle
+= 900.0;
229 while(fNewFullAngle
< 0.0)
231 fNewFullAngle
+= 3600.0;
234 while(fNewFullAngle
>= 3600.0)
236 fNewFullAngle
-= 3600.0;
240 sal_Int32 nNewAngle
= FRound(fNewFullAngle
);
242 if(nNewAngle
!= rGOld
.aGradient
.GetAngle())
244 rG
.aGradient
.SetAngle(nNewAngle
);
248 if(!bMoveSingle
|| (bMoveSingle
&& bMoveFirst
))
250 const basegfx::B2DVector
aFullVec(aEndPos
- aStartPos
);
251 const basegfx::B2DPoint
aBottomLeft(aRange
.getMinX(), aRange
.getMaximum().getY());
252 const basegfx::B2DPoint
aTopLeft(aRange
.getMinX(), aRange
.getMinY());
253 const basegfx::B2DVector
aOldVec(aBottomLeft
- aTopLeft
);
254 const double fFullLen(aFullVec
.getLength());
255 const double fOldLen(aOldVec
.getLength());
256 const double fNewBorder((fFullLen
* 100.0) / fOldLen
);
257 sal_Int32
nNewBorder(100L - FRound(fNewBorder
));
265 if(nNewBorder
> 100L)
271 if(nNewBorder
!= rG
.aGradient
.GetBorder())
273 rG
.aGradient
.SetBorder((sal_uInt16
)nNewBorder
);
279 case css::awt::GradientStyle_AXIAL
:
281 if(!bMoveSingle
|| (bMoveSingle
&& !bMoveFirst
))
283 basegfx::B2DVector
aFullVec(aEndPos
- aCenter
);
284 const basegfx::B2DVector
aOldVec(basegfx::B2DPoint(aCenter
.getX(), aRange
.getMaximum().getY()) - aCenter
);
285 const double fFullLen(aFullVec
.getLength());
286 const double fOldLen(aOldVec
.getLength());
287 const double fNewBorder((fFullLen
* 100.0) / fOldLen
);
288 sal_Int32 nNewBorder
= 100 - FRound(fNewBorder
);
296 if(nNewBorder
> 100L)
302 if(nNewBorder
!= rG
.aGradient
.GetBorder())
304 rG
.aGradient
.SetBorder((sal_uInt16
)nNewBorder
);
307 aFullVec
.normalize();
308 double fNewFullAngle(atan2(aFullVec
.getY(), aFullVec
.getX()));
309 fNewFullAngle
/= F_PI180
;
310 fNewFullAngle
*= -10.0;
311 fNewFullAngle
+= 900.0;
314 while(fNewFullAngle
< 0.0)
316 fNewFullAngle
+= 3600.0;
319 while(fNewFullAngle
>= 3600.0)
321 fNewFullAngle
-= 3600.0;
325 const sal_Int32
nNewAngle(FRound(fNewFullAngle
));
327 if(nNewAngle
!= rGOld
.aGradient
.GetAngle())
329 rG
.aGradient
.SetAngle(nNewAngle
);
335 case css::awt::GradientStyle_RADIAL
:
336 case css::awt::GradientStyle_SQUARE
:
338 if(!bMoveSingle
|| (bMoveSingle
&& !bMoveFirst
))
340 const basegfx::B2DPoint
aTopLeft(aRange
.getMinX(), aRange
.getMinY());
341 const basegfx::B2DPoint
aOffset(aEndPos
- aTopLeft
);
342 sal_Int32
nNewXOffset(FRound((aOffset
.getX() * 100.0) / aRange
.getWidth()));
343 sal_Int32
nNewYOffset(FRound((aOffset
.getY() * 100.0) / aRange
.getHeight()));
351 if(nNewXOffset
> 100L)
361 if(nNewYOffset
> 100L)
366 rG
.aGradient
.SetXOffset((sal_uInt16
)nNewXOffset
);
367 rG
.aGradient
.SetYOffset((sal_uInt16
)nNewYOffset
);
369 aStartPos
-= aOffset
;
373 if(!bMoveSingle
|| (bMoveSingle
&& bMoveFirst
))
375 basegfx::B2DVector
aFullVec(aStartPos
- aEndPos
);
376 const basegfx::B2DPoint
aBottomLeft(aRange
.getMinX(), aRange
.getMaximum().getY());
377 const basegfx::B2DPoint
aTopLeft(aRange
.getMinX(), aRange
.getMinY());
378 const basegfx::B2DVector
aOldVec(aBottomLeft
- aTopLeft
);
379 const double fFullLen(aFullVec
.getLength());
380 const double fOldLen(aOldVec
.getLength());
381 const double fNewBorder((fFullLen
* 100.0) / fOldLen
);
382 sal_Int32
nNewBorder(100L - FRound(fNewBorder
));
390 if(nNewBorder
> 100L)
396 if(nNewBorder
!= rG
.aGradient
.GetBorder())
398 rG
.aGradient
.SetBorder((sal_uInt16
)nNewBorder
);
401 // angle is not definitely necessary for these modes, but it makes
402 // controlling more fun for the user
403 aFullVec
.normalize();
404 double fNewFullAngle(atan2(aFullVec
.getY(), aFullVec
.getX()));
405 fNewFullAngle
/= F_PI180
;
406 fNewFullAngle
*= -10.0;
407 fNewFullAngle
+= 900.0;
410 while(fNewFullAngle
< 0.0)
412 fNewFullAngle
+= 3600.0;
415 while(fNewFullAngle
>= 3600.0)
417 fNewFullAngle
-= 3600.0;
421 const sal_Int32
nNewAngle(FRound(fNewFullAngle
));
423 if(nNewAngle
!= rGOld
.aGradient
.GetAngle())
425 rG
.aGradient
.SetAngle(nNewAngle
);
431 case css::awt::GradientStyle_ELLIPTICAL
:
432 case css::awt::GradientStyle_RECT
:
434 if(!bMoveSingle
|| (bMoveSingle
&& !bMoveFirst
))
436 const basegfx::B2DPoint
aTopLeft(aRange
.getMinX(), aRange
.getMinY());
437 const basegfx::B2DPoint
aOffset(aEndPos
- aTopLeft
);
438 sal_Int32
nNewXOffset(FRound((aOffset
.getX() * 100.0) / aRange
.getWidth()));
439 sal_Int32
nNewYOffset(FRound((aOffset
.getY() * 100.0) / aRange
.getHeight()));
447 if(nNewXOffset
> 100L)
457 if(nNewYOffset
> 100L)
462 rG
.aGradient
.SetXOffset((sal_uInt16
)nNewXOffset
);
463 rG
.aGradient
.SetYOffset((sal_uInt16
)nNewYOffset
);
465 aStartPos
-= aOffset
;
469 if(!bMoveSingle
|| (bMoveSingle
&& bMoveFirst
))
471 basegfx::B2DVector
aFullVec(aStartPos
- aEndPos
);
472 const basegfx::B2DPoint
aTopLeft(aRange
.getMinX(), aRange
.getMinY());
473 const basegfx::B2DPoint
aCenterLeft(aRange
.getMinX(), aCenter
.getY());
474 const basegfx::B2DVector
aOldVec(aCenterLeft
- aTopLeft
);
475 const double fFullLen(aFullVec
.getLength());
476 const double fOldLen(aOldVec
.getLength());
477 const double fNewBorder((fFullLen
* 100.0) / fOldLen
);
478 sal_Int32
nNewBorder(100L - FRound(fNewBorder
));
486 if(nNewBorder
> 100L)
492 if(nNewBorder
!= rG
.aGradient
.GetBorder())
494 rG
.aGradient
.SetBorder((sal_uInt16
)nNewBorder
);
497 // angle is not definitely necessary for these modes, but it makes
498 // controlling more fun for the user
499 aFullVec
.normalize();
500 double fNewFullAngle(atan2(aFullVec
.getY(), aFullVec
.getX()));
501 fNewFullAngle
/= F_PI180
;
502 fNewFullAngle
*= -10.0;
503 fNewFullAngle
+= 900.0;
506 while(fNewFullAngle
< 0.0)
508 fNewFullAngle
+= 3600.0;
511 while(fNewFullAngle
>= 3600.0)
513 fNewFullAngle
-= 3600.0;
517 const sal_Int32
nNewAngle(FRound(fNewFullAngle
));
519 if(nNewAngle
!= rGOld
.aGradient
.GetAngle())
521 rG
.aGradient
.SetAngle(nNewAngle
);
532 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */