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