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