xref: /AOO41X/main/svx/source/svdraw/gradtrns.cxx (revision f6e50924346d0b8c0b07c91832a97665dd718b0c)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_svx.hxx"
26 
27 #include "gradtrns.hxx"
28 #include <svx/svdobj.hxx>
29 #include <basegfx/range/b2drange.hxx>
30 #include <basegfx/matrix/b2dhommatrix.hxx>
31 #include <basegfx/matrix/b2dhommatrixtools.hxx>
32 #include <vcl/salbtype.hxx>     // FRound
33 
34 //////////////////////////////////////////////////////////////////////////////
35 
GradToVec(GradTransGradient & rG,GradTransVector & rV,const SdrObject * pObj)36 void GradTransformer::GradToVec(GradTransGradient& rG, GradTransVector& rV, const SdrObject* pObj)
37 {
38     // handle start color
39     rV.aCol1 = rG.aGradient.GetStartColor();
40     if(100 != rG.aGradient.GetStartIntens())
41     {
42         const double fFact((double)rG.aGradient.GetStartIntens() / 100.0);
43         rV.aCol1 = Color(rV.aCol1.getBColor() * fFact);
44     }
45 
46     // handle end color
47     rV.aCol2 = rG.aGradient.GetEndColor();
48     if(100 != rG.aGradient.GetEndIntens())
49     {
50         const double fFact((double)rG.aGradient.GetEndIntens() / 100.0);
51         rV.aCol2 = Color(rV.aCol2.getBColor() * fFact);
52     }
53 
54     // calc the basic positions
55     const Rectangle aObjectSnapRectangle(pObj->GetSnapRect());
56     const basegfx::B2DRange aRange(aObjectSnapRectangle.Left(), aObjectSnapRectangle.Top(), aObjectSnapRectangle.Right(), aObjectSnapRectangle.Bottom());
57     const basegfx::B2DPoint aCenter(aRange.getCenter());
58     basegfx::B2DPoint aStartPos, aEndPos;
59 
60     switch(rG.aGradient.GetGradientStyle())
61     {
62         case XGRAD_LINEAR :
63         {
64             aStartPos = basegfx::B2DPoint(aCenter.getX(), aRange.getMinY());
65             aEndPos = basegfx::B2DPoint(aCenter.getX(), aRange.getMaximum().getY());
66 
67             if(rG.aGradient.GetBorder())
68             {
69                 basegfx::B2DVector aFullVec(aStartPos - aEndPos);
70                 const double fLen = (aFullVec.getLength() * (100.0 - (double)rG.aGradient.GetBorder())) / 100.0;
71                 aFullVec.normalize();
72                 aStartPos = aEndPos + (aFullVec * fLen);
73             }
74 
75             if(rG.aGradient.GetAngle())
76             {
77                 const double fAngle = (double)rG.aGradient.GetAngle() * (F_PI180 / 10.0);
78                 const basegfx::B2DHomMatrix aTransformation(basegfx::tools::createRotateAroundPoint(aCenter, -fAngle));
79 
80                 aStartPos *= aTransformation;
81                 aEndPos *= aTransformation;
82             }
83             break;
84         }
85         case XGRAD_AXIAL :
86         {
87             aStartPos = aCenter;
88             aEndPos = basegfx::B2DPoint(aCenter.getX(), aRange.getMaximum().getY());
89 
90             if(rG.aGradient.GetBorder())
91             {
92                 basegfx::B2DVector aFullVec(aEndPos - aStartPos);
93                 const double fLen = (aFullVec.getLength() * (100.0 - (double)rG.aGradient.GetBorder())) / 100.0;
94                 aFullVec.normalize();
95                 aEndPos = aStartPos + (aFullVec * fLen);
96             }
97 
98             if(rG.aGradient.GetAngle())
99             {
100                 const double fAngle = (double)rG.aGradient.GetAngle() * (F_PI180 / 10.0);
101                 const basegfx::B2DHomMatrix aTransformation(basegfx::tools::createRotateAroundPoint(aCenter, -fAngle));
102 
103                 aStartPos *= aTransformation;
104                 aEndPos *= aTransformation;
105             }
106             break;
107         }
108         case XGRAD_RADIAL :
109         case XGRAD_SQUARE :
110         {
111             aStartPos = basegfx::B2DPoint(aRange.getMinX(), aRange.getMaximum().getY());
112             aEndPos = basegfx::B2DPoint(aRange.getMinX(), aRange.getMinY());
113 
114             if(rG.aGradient.GetBorder())
115             {
116                 basegfx::B2DVector aFullVec(aStartPos - aEndPos);
117                 const double fLen = (aFullVec.getLength() * (100.0 - (double)rG.aGradient.GetBorder())) / 100.0;
118                 aFullVec.normalize();
119                 aStartPos = aEndPos + (aFullVec * fLen);
120             }
121 
122             if(rG.aGradient.GetAngle())
123             {
124                 const double fAngle = (double)rG.aGradient.GetAngle() * (F_PI180 / 10.0);
125                 const basegfx::B2DHomMatrix aTransformation(basegfx::tools::createRotateAroundPoint(aEndPos, -fAngle));
126 
127                 aStartPos *= aTransformation;
128                 aEndPos *= aTransformation;
129             }
130 
131             if(rG.aGradient.GetXOffset() || rG.aGradient.GetYOffset())
132             {
133                 basegfx::B2DPoint aOffset(
134                     (aRange.getWidth() * rG.aGradient.GetXOffset()) / 100.0,
135                     (aRange.getHeight() * rG.aGradient.GetYOffset()) / 100.0);
136 
137                 aStartPos += aOffset;
138                 aEndPos += aOffset;
139             }
140 
141             break;
142         }
143         case XGRAD_ELLIPTICAL :
144         case XGRAD_RECT :
145         {
146             aStartPos = basegfx::B2DPoint(aRange.getMinX(), aCenter.getY());
147             aEndPos = basegfx::B2DPoint(aRange.getMinX(), aRange.getMinY());
148 
149             if(rG.aGradient.GetBorder())
150             {
151                 basegfx::B2DVector aFullVec(aStartPos - aEndPos);
152                 const double fLen = (aFullVec.getLength() * (100.0 - (double)rG.aGradient.GetBorder())) / 100.0;
153                 aFullVec.normalize();
154                 aStartPos = aEndPos + (aFullVec * fLen);
155             }
156 
157             if(rG.aGradient.GetAngle())
158             {
159                 const double fAngle = (double)rG.aGradient.GetAngle() * (F_PI180 / 10.0);
160                 const basegfx::B2DHomMatrix aTransformation(basegfx::tools::createRotateAroundPoint(aEndPos, -fAngle));
161 
162                 aStartPos *= aTransformation;
163                 aEndPos *= aTransformation;
164             }
165 
166             if(rG.aGradient.GetXOffset() || rG.aGradient.GetYOffset())
167             {
168                 basegfx::B2DPoint aOffset(
169                     (aRange.getWidth() * rG.aGradient.GetXOffset()) / 100.0,
170                     (aRange.getHeight() * rG.aGradient.GetYOffset()) / 100.0);
171 
172                 aStartPos += aOffset;
173                 aEndPos += aOffset;
174             }
175 
176             break;
177         }
178     }
179 
180     // set values for vector positions now
181     rV.maPositionA = aStartPos;
182     rV.maPositionB = aEndPos;
183 }
184 
185 //////////////////////////////////////////////////////////////////////////////
186 
VecToGrad(GradTransVector & rV,GradTransGradient & rG,GradTransGradient & rGOld,const SdrObject * pObj,sal_Bool bMoveSingle,sal_Bool bMoveFirst)187 void GradTransformer::VecToGrad(GradTransVector& rV, GradTransGradient& rG, GradTransGradient& rGOld, const SdrObject* pObj,
188     sal_Bool bMoveSingle, sal_Bool bMoveFirst)
189 {
190     // fill old gradient to new gradient to have a base
191     rG = rGOld;
192 
193     // handle color changes
194     if(rV.aCol1 != rGOld.aGradient.GetStartColor())
195     {
196         rG.aGradient.SetStartColor(rV.aCol1);
197         rG.aGradient.SetStartIntens(100);
198     }
199     if(rV.aCol2 != rGOld.aGradient.GetEndColor())
200     {
201         rG.aGradient.SetEndColor(rV.aCol2);
202         rG.aGradient.SetEndIntens(100);
203     }
204 
205     // calc the basic positions
206     const Rectangle aObjectSnapRectangle(pObj->GetSnapRect());
207     const basegfx::B2DRange aRange(aObjectSnapRectangle.Left(), aObjectSnapRectangle.Top(), aObjectSnapRectangle.Right(), aObjectSnapRectangle.Bottom());
208     const basegfx::B2DPoint aCenter(aRange.getCenter());
209     basegfx::B2DPoint aStartPos(rV.maPositionA);
210     basegfx::B2DPoint aEndPos(rV.maPositionB);
211 
212     switch(rG.aGradient.GetGradientStyle())
213     {
214         case XGRAD_LINEAR :
215         {
216             if(!bMoveSingle || (bMoveSingle && !bMoveFirst))
217             {
218                 basegfx::B2DVector aFullVec(aEndPos - aStartPos);
219 
220                 if(bMoveSingle)
221                 {
222                     aFullVec = aEndPos - aCenter;
223                 }
224 
225                 aFullVec.normalize();
226 
227                 double fNewFullAngle(atan2(aFullVec.getY(), aFullVec.getX()));
228                 fNewFullAngle /= F_PI180;
229                 fNewFullAngle *= -10.0;
230                 fNewFullAngle += 900.0;
231 
232                 // clip
233                 while(fNewFullAngle < 0.0)
234                 {
235                     fNewFullAngle += 3600.0;
236                 }
237 
238                 while(fNewFullAngle >= 3600.0)
239                 {
240                     fNewFullAngle -= 3600.0;
241                 }
242 
243                 // to int and set
244                 sal_Int32 nNewAngle = FRound(fNewFullAngle);
245 
246                 if(nNewAngle != rGOld.aGradient.GetAngle())
247                 {
248                     rG.aGradient.SetAngle(nNewAngle);
249                 }
250             }
251 
252             if(!bMoveSingle || (bMoveSingle && bMoveFirst))
253             {
254                 const basegfx::B2DVector aFullVec(aEndPos - aStartPos);
255                 const basegfx::B2DPoint aBottomLeft(aRange.getMinX(), aRange.getMaximum().getY());
256                 const basegfx::B2DPoint aTopLeft(aRange.getMinX(), aRange.getMinY());
257                 const basegfx::B2DVector aOldVec(aBottomLeft - aTopLeft);
258                 const double fFullLen(aFullVec.getLength());
259                 const double fOldLen(aOldVec.getLength());
260                 const double fNewBorder((fFullLen * 100.0) / fOldLen);
261                 sal_Int32 nNewBorder(100L - FRound(fNewBorder));
262 
263                 // clip
264                 if(nNewBorder < 0L)
265                 {
266                     nNewBorder = 0L;
267                 }
268 
269                 if(nNewBorder > 100L)
270                 {
271                     nNewBorder = 100L;
272                 }
273 
274                 // set
275                 if(nNewBorder != rG.aGradient.GetBorder())
276                 {
277                     rG.aGradient.SetBorder((sal_uInt16)nNewBorder);
278                 }
279             }
280 
281             break;
282         }
283         case XGRAD_AXIAL :
284         {
285             if(!bMoveSingle || (bMoveSingle && !bMoveFirst))
286             {
287                 basegfx::B2DVector aFullVec(aEndPos - aCenter);
288                 const basegfx::B2DVector aOldVec(basegfx::B2DPoint(aCenter.getX(), aRange.getMaximum().getY()) - aCenter);
289                 const double fFullLen(aFullVec.getLength());
290                 const double fOldLen(aOldVec.getLength());
291                 const double fNewBorder((fFullLen * 100.0) / fOldLen);
292                 sal_Int32 nNewBorder = 100 - FRound(fNewBorder);
293 
294                 // clip
295                 if(nNewBorder < 0L)
296                 {
297                     nNewBorder = 0L;
298                 }
299 
300                 if(nNewBorder > 100L)
301                 {
302                     nNewBorder = 100L;
303                 }
304 
305                 // set
306                 if(nNewBorder != rG.aGradient.GetBorder())
307                 {
308                     rG.aGradient.SetBorder((sal_uInt16)nNewBorder);
309                 }
310 
311                 aFullVec.normalize();
312                 double fNewFullAngle(atan2(aFullVec.getY(), aFullVec.getX()));
313                 fNewFullAngle /= F_PI180;
314                 fNewFullAngle *= -10.0;
315                 fNewFullAngle += 900.0;
316 
317                 // clip
318                 while(fNewFullAngle < 0.0)
319                 {
320                     fNewFullAngle += 3600.0;
321                 }
322 
323                 while(fNewFullAngle >= 3600.0)
324                 {
325                     fNewFullAngle -= 3600.0;
326                 }
327 
328                 // to int and set
329                 const sal_Int32 nNewAngle(FRound(fNewFullAngle));
330 
331                 if(nNewAngle != rGOld.aGradient.GetAngle())
332                 {
333                     rG.aGradient.SetAngle(nNewAngle);
334                 }
335             }
336 
337             break;
338         }
339         case XGRAD_RADIAL :
340         case XGRAD_SQUARE :
341         {
342             if(!bMoveSingle || (bMoveSingle && !bMoveFirst))
343             {
344                 const basegfx::B2DPoint aTopLeft(aRange.getMinX(), aRange.getMinY());
345                 const basegfx::B2DPoint aOffset(aEndPos - aTopLeft);
346                 sal_Int32 nNewXOffset(FRound((aOffset.getX() * 100.0) / aRange.getWidth()));
347                 sal_Int32 nNewYOffset(FRound((aOffset.getY() * 100.0) / aRange.getHeight()));
348 
349                 // clip
350                 if(nNewXOffset < 0L)
351                 {
352                     nNewXOffset = 0L;
353                 }
354 
355                 if(nNewXOffset > 100L)
356                 {
357                     nNewXOffset = 100L;
358                 }
359 
360                 if(nNewYOffset < 0L)
361                 {
362                     nNewYOffset = 0L;
363                 }
364 
365                 if(nNewYOffset > 100L)
366                 {
367                     nNewYOffset = 100L;
368                 }
369 
370                 rG.aGradient.SetXOffset((sal_uInt16)nNewXOffset);
371                 rG.aGradient.SetYOffset((sal_uInt16)nNewYOffset);
372 
373                 aStartPos -= aOffset;
374                 aEndPos -= aOffset;
375             }
376 
377             if(!bMoveSingle || (bMoveSingle && bMoveFirst))
378             {
379                 basegfx::B2DVector aFullVec(aStartPos - aEndPos);
380                 const basegfx::B2DPoint aBottomLeft(aRange.getMinX(), aRange.getMaximum().getY());
381                 const basegfx::B2DPoint aTopLeft(aRange.getMinX(), aRange.getMinY());
382                 const basegfx::B2DVector aOldVec(aBottomLeft - aTopLeft);
383                 const double fFullLen(aFullVec.getLength());
384                 const double fOldLen(aOldVec.getLength());
385                 const double fNewBorder((fFullLen * 100.0) / fOldLen);
386                 sal_Int32 nNewBorder(100L - FRound(fNewBorder));
387 
388                 // clip
389                 if(nNewBorder < 0L)
390                 {
391                     nNewBorder = 0L;
392                 }
393 
394                 if(nNewBorder > 100L)
395                 {
396                     nNewBorder = 100L;
397                 }
398 
399                 // set
400                 if(nNewBorder != rG.aGradient.GetBorder())
401                 {
402                     rG.aGradient.SetBorder((sal_uInt16)nNewBorder);
403                 }
404 
405                 // angle is not definitely necessary for these modes, but it makes
406                 // controlling more fun for the user
407                 aFullVec.normalize();
408                 double fNewFullAngle(atan2(aFullVec.getY(), aFullVec.getX()));
409                 fNewFullAngle /= F_PI180;
410                 fNewFullAngle *= -10.0;
411                 fNewFullAngle += 900.0;
412 
413                 // clip
414                 while(fNewFullAngle < 0.0)
415                 {
416                     fNewFullAngle += 3600.0;
417                 }
418 
419                 while(fNewFullAngle >= 3600.0)
420                 {
421                     fNewFullAngle -= 3600.0;
422                 }
423 
424                 // to int and set
425                 const sal_Int32 nNewAngle(FRound(fNewFullAngle));
426 
427                 if(nNewAngle != rGOld.aGradient.GetAngle())
428                 {
429                     rG.aGradient.SetAngle(nNewAngle);
430                 }
431             }
432 
433             break;
434         }
435         case XGRAD_ELLIPTICAL :
436         case XGRAD_RECT :
437         {
438             if(!bMoveSingle || (bMoveSingle && !bMoveFirst))
439             {
440                 const basegfx::B2DPoint aTopLeft(aRange.getMinX(), aRange.getMinY());
441                 const basegfx::B2DPoint aOffset(aEndPos - aTopLeft);
442                 sal_Int32 nNewXOffset(FRound((aOffset.getX() * 100.0) / aRange.getWidth()));
443                 sal_Int32 nNewYOffset(FRound((aOffset.getY() * 100.0) / aRange.getHeight()));
444 
445                 // clip
446                 if(nNewXOffset < 0L)
447                 {
448                     nNewXOffset = 0L;
449                 }
450 
451                 if(nNewXOffset > 100L)
452                 {
453                     nNewXOffset = 100L;
454                 }
455 
456                 if(nNewYOffset < 0L)
457                 {
458                     nNewYOffset = 0L;
459                 }
460 
461                 if(nNewYOffset > 100L)
462                 {
463                     nNewYOffset = 100L;
464                 }
465 
466                 rG.aGradient.SetXOffset((sal_uInt16)nNewXOffset);
467                 rG.aGradient.SetYOffset((sal_uInt16)nNewYOffset);
468 
469                 aStartPos -= aOffset;
470                 aEndPos -= aOffset;
471             }
472 
473             if(!bMoveSingle || (bMoveSingle && bMoveFirst))
474             {
475                 basegfx::B2DVector aFullVec(aStartPos - aEndPos);
476                 const basegfx::B2DPoint aTopLeft(aRange.getMinX(), aRange.getMinY());
477                 const basegfx::B2DPoint aCenterLeft(aRange.getMinX(), aRange.getHeight());
478                 const basegfx::B2DVector aOldVec(aCenterLeft - aTopLeft);
479                 const double fFullLen(aFullVec.getLength());
480                 const double fOldLen(aOldVec.getLength());
481                 const double fNewBorder((fFullLen * 100.0) / fOldLen);
482                 sal_Int32 nNewBorder(100L - FRound(fNewBorder));
483 
484                 // clip
485                 if(nNewBorder < 0L)
486                 {
487                     nNewBorder = 0L;
488                 }
489 
490                 if(nNewBorder > 100L)
491                 {
492                     nNewBorder = 100L;
493                 }
494 
495                 // set
496                 if(nNewBorder != rG.aGradient.GetBorder())
497                 {
498                     rG.aGradient.SetBorder((sal_uInt16)nNewBorder);
499                 }
500 
501                 // angle is not definitely necessary for these modes, but it makes
502                 // controlling more fun for the user
503                 aFullVec.normalize();
504                 double fNewFullAngle(atan2(aFullVec.getY(), aFullVec.getX()));
505                 fNewFullAngle /= F_PI180;
506                 fNewFullAngle *= -10.0;
507                 fNewFullAngle += 900.0;
508 
509                 // clip
510                 while(fNewFullAngle < 0.0)
511                 {
512                     fNewFullAngle += 3600.0;
513                 }
514 
515                 while(fNewFullAngle >= 3600.0)
516                 {
517                     fNewFullAngle -= 3600.0;
518                 }
519 
520                 // to int and set
521                 const sal_Int32 nNewAngle(FRound(fNewFullAngle));
522 
523                 if(nNewAngle != rGOld.aGradient.GetAngle())
524                 {
525                     rG.aGradient.SetAngle(nNewAngle);
526                 }
527             }
528 
529             break;
530         }
531     }
532 }
533 
534 // eof
535