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