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