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
GradToVec(GradTransGradient & rG,GradTransVector & rV,const SdrObject * pObj)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
VecToGrad(GradTransVector & rV,GradTransGradient & rG,GradTransGradient & rGOld,const SdrObject * pObj,sal_Bool bMoveSingle,sal_Bool bMoveFirst)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