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