xref: /aoo42x/main/svx/source/svdraw/gradtrns.cxx (revision f6e50924)
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 
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 
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