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