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>
27 #include <vcl/canvastools.hxx>
30 void GradTransformer::GradToVec(GradTransGradient
const & rG
, GradTransVector
& rV
, const SdrObject
* pObj
)
33 rV
.aCol1
= rG
.aGradient
.GetStartColor();
34 if(100 != rG
.aGradient
.GetStartIntens())
36 const double fFact(static_cast<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(static_cast<double>(rG
.aGradient
.GetEndIntens()) / 100.0);
45 rV
.aCol2
= Color(rV
.aCol2
.getBColor() * fFact
);
48 // calc the basic positions
49 const tools::Rectangle
aObjectSnapRectangle(pObj
->GetSnapRect());
50 const basegfx::B2DRange aRange
= vcl::unotools::b2DRectangleFromRectangle(aObjectSnapRectangle
);
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 - static_cast<double>(rG
.aGradient
.GetBorder()))) / 100.0;
66 aStartPos
= aEndPos
+ (aFullVec
* fLen
);
69 if(rG
.aGradient
.GetAngle())
71 const double fAngle
= basegfx::deg2rad(rG
.aGradient
.GetAngle().get() / 10.0);
72 const basegfx::B2DHomMatrix
aTransformation(basegfx::utils::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 - static_cast<double>(rG
.aGradient
.GetBorder()))) / 100.0;
89 aEndPos
= aStartPos
+ (aFullVec
* fLen
);
92 if(rG
.aGradient
.GetAngle())
94 const double fAngle
= basegfx::deg2rad(rG
.aGradient
.GetAngle().get() / 10.0);
95 const basegfx::B2DHomMatrix
aTransformation(basegfx::utils::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 - static_cast<double>(rG
.aGradient
.GetBorder()))) / 100.0;
112 aFullVec
.normalize();
113 aStartPos
= aEndPos
+ (aFullVec
* fLen
);
116 if(rG
.aGradient
.GetAngle())
118 const double fAngle
= basegfx::deg2rad(rG
.aGradient
.GetAngle().get() / 10.0);
119 const basegfx::B2DHomMatrix
aTransformation(basegfx::utils::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 - static_cast<double>(rG
.aGradient
.GetBorder()))) / 100.0;
147 aFullVec
.normalize();
148 aStartPos
= aEndPos
+ (aFullVec
* fLen
);
151 if(rG
.aGradient
.GetAngle())
153 const double fAngle
= basegfx::deg2rad(rG
.aGradient
.GetAngle().get() / 10.0);
154 const basegfx::B2DHomMatrix
aTransformation(basegfx::utils::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
;
182 void GradTransformer::VecToGrad(GradTransVector
const & rV
, GradTransGradient
& rG
, GradTransGradient
const & rGOld
, const SdrObject
* pObj
,
183 bool bMoveSingle
, bool bMoveFirst
)
185 // fill old gradient to new gradient to have a base
188 // handle color changes
189 if(rV
.aCol1
!= rGOld
.aGradient
.GetStartColor())
191 rG
.aGradient
.SetStartColor(rV
.aCol1
);
192 rG
.aGradient
.SetStartIntens(100);
194 if(rV
.aCol2
!= rGOld
.aGradient
.GetEndColor())
196 rG
.aGradient
.SetEndColor(rV
.aCol2
);
197 rG
.aGradient
.SetEndIntens(100);
200 // calc the basic positions
201 const tools::Rectangle
aObjectSnapRectangle(pObj
->GetSnapRect());
202 const basegfx::B2DRange aRange
= vcl::unotools::b2DRectangleFromRectangle(aObjectSnapRectangle
);
203 const basegfx::B2DPoint
aCenter(aRange
.getCenter());
204 basegfx::B2DPoint
aStartPos(rV
.maPositionA
);
205 basegfx::B2DPoint
aEndPos(rV
.maPositionB
);
207 switch(rG
.aGradient
.GetGradientStyle())
209 case css::awt::GradientStyle_LINEAR
:
211 if(!bMoveSingle
|| !bMoveFirst
)
213 basegfx::B2DVector
aFullVec(aEndPos
- aStartPos
);
217 aFullVec
= aEndPos
- aCenter
;
220 aFullVec
.normalize();
222 double fNewFullAngle(basegfx::rad2deg(atan2(aFullVec
.getY(), aFullVec
.getX())));
223 fNewFullAngle
*= -10.0;
224 fNewFullAngle
+= 900.0;
227 while(fNewFullAngle
< 0.0)
229 fNewFullAngle
+= 3600.0;
232 while(fNewFullAngle
>= 3600.0)
234 fNewFullAngle
-= 3600.0;
238 Degree10
nNewAngle( FRound(fNewFullAngle
));
240 if(nNewAngle
!= rGOld
.aGradient
.GetAngle())
242 rG
.aGradient
.SetAngle(nNewAngle
);
246 if(!bMoveSingle
|| bMoveFirst
)
248 const basegfx::B2DVector
aFullVec(aEndPos
- aStartPos
);
249 const basegfx::B2DPoint
aBottomLeft(aRange
.getMinX(), aRange
.getMaximum().getY());
250 const basegfx::B2DPoint
aTopLeft(aRange
.getMinX(), aRange
.getMinY());
251 const basegfx::B2DVector
aOldVec(aBottomLeft
- aTopLeft
);
252 const double fFullLen(aFullVec
.getLength());
253 const double fOldLen(aOldVec
.getLength());
254 const double fNewBorder((fFullLen
* 100.0) / fOldLen
);
255 sal_Int32
nNewBorder(100 - FRound(fNewBorder
));
269 if(nNewBorder
!= rG
.aGradient
.GetBorder())
271 rG
.aGradient
.SetBorder(static_cast<sal_uInt16
>(nNewBorder
));
277 case css::awt::GradientStyle_AXIAL
:
279 if(!bMoveSingle
|| !bMoveFirst
)
281 basegfx::B2DVector
aFullVec(aEndPos
- aCenter
);
282 const basegfx::B2DVector
aOldVec(basegfx::B2DPoint(aCenter
.getX(), aRange
.getMaximum().getY()) - aCenter
);
283 const double fFullLen(aFullVec
.getLength());
284 const double fOldLen(aOldVec
.getLength());
285 const double fNewBorder((fFullLen
* 100.0) / fOldLen
);
286 sal_Int32 nNewBorder
= 100 - FRound(fNewBorder
);
300 if(nNewBorder
!= rG
.aGradient
.GetBorder())
302 rG
.aGradient
.SetBorder(static_cast<sal_uInt16
>(nNewBorder
));
305 aFullVec
.normalize();
306 double fNewFullAngle(basegfx::rad2deg(atan2(aFullVec
.getY(), aFullVec
.getX())));
307 fNewFullAngle
*= -10.0;
308 fNewFullAngle
+= 900.0;
311 while(fNewFullAngle
< 0.0)
313 fNewFullAngle
+= 3600.0;
316 while(fNewFullAngle
>= 3600.0)
318 fNewFullAngle
-= 3600.0;
322 const Degree10
nNewAngle(FRound(fNewFullAngle
));
324 if(nNewAngle
!= rGOld
.aGradient
.GetAngle())
326 rG
.aGradient
.SetAngle(nNewAngle
);
332 case css::awt::GradientStyle_RADIAL
:
333 case css::awt::GradientStyle_SQUARE
:
335 if(!bMoveSingle
|| !bMoveFirst
)
337 const basegfx::B2DPoint
aTopLeft(aRange
.getMinX(), aRange
.getMinY());
338 const basegfx::B2DPoint
aOffset(aEndPos
- aTopLeft
);
339 sal_Int32
nNewXOffset(FRound((aOffset
.getX() * 100.0) / aRange
.getWidth()));
340 sal_Int32
nNewYOffset(FRound((aOffset
.getY() * 100.0) / aRange
.getHeight()));
348 if(nNewXOffset
> 100)
358 if(nNewYOffset
> 100)
363 rG
.aGradient
.SetXOffset(static_cast<sal_uInt16
>(nNewXOffset
));
364 rG
.aGradient
.SetYOffset(static_cast<sal_uInt16
>(nNewYOffset
));
366 aStartPos
-= aOffset
;
370 if(!bMoveSingle
|| bMoveFirst
)
372 basegfx::B2DVector
aFullVec(aStartPos
- aEndPos
);
373 const basegfx::B2DPoint
aBottomLeft(aRange
.getMinX(), aRange
.getMaximum().getY());
374 const basegfx::B2DPoint
aTopLeft(aRange
.getMinX(), aRange
.getMinY());
375 const basegfx::B2DVector
aOldVec(aBottomLeft
- aTopLeft
);
376 const double fFullLen(aFullVec
.getLength());
377 const double fOldLen(aOldVec
.getLength());
378 const double fNewBorder((fFullLen
* 100.0) / fOldLen
);
379 sal_Int32
nNewBorder(100 - FRound(fNewBorder
));
393 if(nNewBorder
!= rG
.aGradient
.GetBorder())
395 rG
.aGradient
.SetBorder(static_cast<sal_uInt16
>(nNewBorder
));
398 // angle is not definitely necessary for these modes, but it makes
399 // controlling more fun for the user
400 aFullVec
.normalize();
401 double fNewFullAngle(basegfx::rad2deg(atan2(aFullVec
.getY(), aFullVec
.getX())));
402 fNewFullAngle
*= -10.0;
403 fNewFullAngle
+= 900.0;
406 while(fNewFullAngle
< 0.0)
408 fNewFullAngle
+= 3600.0;
411 while(fNewFullAngle
>= 3600.0)
413 fNewFullAngle
-= 3600.0;
417 const Degree10
nNewAngle(FRound(fNewFullAngle
));
419 if(nNewAngle
!= rGOld
.aGradient
.GetAngle())
421 rG
.aGradient
.SetAngle(nNewAngle
);
427 case css::awt::GradientStyle_ELLIPTICAL
:
428 case css::awt::GradientStyle_RECT
:
430 if(!bMoveSingle
|| !bMoveFirst
)
432 const basegfx::B2DPoint
aTopLeft(aRange
.getMinX(), aRange
.getMinY());
433 const basegfx::B2DPoint
aOffset(aEndPos
- aTopLeft
);
434 sal_Int32
nNewXOffset(FRound((aOffset
.getX() * 100.0) / aRange
.getWidth()));
435 sal_Int32
nNewYOffset(FRound((aOffset
.getY() * 100.0) / aRange
.getHeight()));
443 if(nNewXOffset
> 100)
453 if(nNewYOffset
> 100)
458 rG
.aGradient
.SetXOffset(static_cast<sal_uInt16
>(nNewXOffset
));
459 rG
.aGradient
.SetYOffset(static_cast<sal_uInt16
>(nNewYOffset
));
461 aStartPos
-= aOffset
;
465 if(!bMoveSingle
|| bMoveFirst
)
467 basegfx::B2DVector
aFullVec(aStartPos
- aEndPos
);
468 const basegfx::B2DPoint
aTopLeft(aRange
.getMinX(), aRange
.getMinY());
469 const basegfx::B2DPoint
aCenterLeft(aRange
.getMinX(), aCenter
.getY());
470 const basegfx::B2DVector
aOldVec(aCenterLeft
- aTopLeft
);
471 const double fFullLen(aFullVec
.getLength());
472 const double fOldLen(aOldVec
.getLength());
473 const double fNewBorder((fFullLen
* 100.0) / fOldLen
);
474 sal_Int32
nNewBorder(100 - FRound(fNewBorder
));
488 if(nNewBorder
!= rG
.aGradient
.GetBorder())
490 rG
.aGradient
.SetBorder(static_cast<sal_uInt16
>(nNewBorder
));
493 // angle is not definitely necessary for these modes, but it makes
494 // controlling more fun for the user
495 aFullVec
.normalize();
496 double fNewFullAngle(basegfx::rad2deg(atan2(aFullVec
.getY(), aFullVec
.getX())));
497 fNewFullAngle
*= -10.0;
498 fNewFullAngle
+= 900.0;
501 while(fNewFullAngle
< 0.0)
503 fNewFullAngle
+= 3600.0;
506 while(fNewFullAngle
>= 3600.0)
508 fNewFullAngle
-= 3600.0;
512 const Degree10
nNewAngle(FRound(fNewFullAngle
));
514 if(nNewAngle
!= rGOld
.aGradient
.GetAngle())
516 rG
.aGradient
.SetAngle(nNewAngle
);
527 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */