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 #include <basegfx/matrix/b2dhommatrixtools.hxx> 21 #include <basegfx/range/b2drange.hxx> 22 23 #include <osl/diagnose.h> 24 25 namespace basegfx::utils 26 { createSinCosOrthogonal(double & o_rSin,double & o_rCos,double fRadiant)27 void createSinCosOrthogonal(double& o_rSin, double& o_rCos, double fRadiant) 28 { 29 if( fTools::equalZero( fmod( fRadiant, F_PI2 ) ) ) 30 { 31 // determine quadrant 32 const sal_Int32 nQuad( 33 (4 + fround( 4/F_2PI*fmod( fRadiant, F_2PI ) )) % 4 ); 34 switch( nQuad ) 35 { 36 case 0: // -2pi,0,2pi 37 o_rSin = 0.0; 38 o_rCos = 1.0; 39 break; 40 41 case 1: // -3/2pi,1/2pi 42 o_rSin = 1.0; 43 o_rCos = 0.0; 44 break; 45 46 case 2: // -pi,pi 47 o_rSin = 0.0; 48 o_rCos = -1.0; 49 break; 50 51 case 3: // -1/2pi,3/2pi 52 o_rSin = -1.0; 53 o_rCos = 0.0; 54 break; 55 56 default: 57 OSL_FAIL( "createSinCos: Impossible case reached" ); 58 } 59 } 60 else 61 { 62 // TODO(P1): Maybe use glibc's sincos here (though 63 // that's kinda non-portable...) 64 o_rSin = sin(fRadiant); 65 o_rCos = cos(fRadiant); 66 } 67 } 68 createScaleB2DHomMatrix(double fScaleX,double fScaleY)69 B2DHomMatrix createScaleB2DHomMatrix(double fScaleX, double fScaleY) 70 { 71 B2DHomMatrix aRetval; 72 const double fOne(1.0); 73 74 if(!fTools::equal(fScaleX, fOne)) 75 { 76 aRetval.set(0, 0, fScaleX); 77 } 78 79 if(!fTools::equal(fScaleY, fOne)) 80 { 81 aRetval.set(1, 1, fScaleY); 82 } 83 84 return aRetval; 85 } 86 createShearXB2DHomMatrix(double fShearX)87 B2DHomMatrix createShearXB2DHomMatrix(double fShearX) 88 { 89 B2DHomMatrix aRetval; 90 91 if(!fTools::equalZero(fShearX)) 92 { 93 aRetval.set(0, 1, fShearX); 94 } 95 96 return aRetval; 97 } 98 createShearYB2DHomMatrix(double fShearY)99 B2DHomMatrix createShearYB2DHomMatrix(double fShearY) 100 { 101 B2DHomMatrix aRetval; 102 103 if(!fTools::equalZero(fShearY)) 104 { 105 aRetval.set(1, 0, fShearY); 106 } 107 108 return aRetval; 109 } 110 createRotateB2DHomMatrix(double fRadiant)111 B2DHomMatrix createRotateB2DHomMatrix(double fRadiant) 112 { 113 B2DHomMatrix aRetval; 114 115 if(!fTools::equalZero(fRadiant)) 116 { 117 double fSin(0.0); 118 double fCos(1.0); 119 120 createSinCosOrthogonal(fSin, fCos, fRadiant); 121 aRetval.set(0, 0, fCos); 122 aRetval.set(1, 1, fCos); 123 aRetval.set(1, 0, fSin); 124 aRetval.set(0, 1, -fSin); 125 } 126 127 return aRetval; 128 } 129 createTranslateB2DHomMatrix(double fTranslateX,double fTranslateY)130 B2DHomMatrix createTranslateB2DHomMatrix(double fTranslateX, double fTranslateY) 131 { 132 B2DHomMatrix aRetval; 133 134 if(!(fTools::equalZero(fTranslateX) && fTools::equalZero(fTranslateY))) 135 { 136 aRetval.set(0, 2, fTranslateX); 137 aRetval.set(1, 2, fTranslateY); 138 } 139 140 return aRetval; 141 } 142 createScaleShearXRotateTranslateB2DHomMatrix(double fScaleX,double fScaleY,double fShearX,double fRadiant,double fTranslateX,double fTranslateY)143 B2DHomMatrix createScaleShearXRotateTranslateB2DHomMatrix( 144 double fScaleX, double fScaleY, 145 double fShearX, 146 double fRadiant, 147 double fTranslateX, double fTranslateY) 148 { 149 const double fOne(1.0); 150 151 if(fTools::equal(fScaleX, fOne) && fTools::equal(fScaleY, fOne)) 152 { 153 /// no scale, take shortcut 154 return createShearXRotateTranslateB2DHomMatrix(fShearX, fRadiant, fTranslateX, fTranslateY); 155 } 156 else 157 { 158 /// scale used 159 if(fTools::equalZero(fShearX)) 160 { 161 /// no shear 162 if(fTools::equalZero(fRadiant)) 163 { 164 /// no rotate, take shortcut 165 return createScaleTranslateB2DHomMatrix(fScaleX, fScaleY, fTranslateX, fTranslateY); 166 } 167 else 168 { 169 /// rotate and scale used, no shear 170 double fSin(0.0); 171 double fCos(1.0); 172 173 createSinCosOrthogonal(fSin, fCos, fRadiant); 174 175 B2DHomMatrix aRetval( 176 /* Row 0, Column 0 */ fCos * fScaleX, 177 /* Row 0, Column 1 */ fScaleY * -fSin, 178 /* Row 0, Column 2 */ fTranslateX, 179 /* Row 1, Column 0 */ fSin * fScaleX, 180 /* Row 1, Column 1 */ fScaleY * fCos, 181 /* Row 1, Column 2 */ fTranslateY); 182 183 return aRetval; 184 } 185 } 186 else 187 { 188 /// scale and shear used 189 if(fTools::equalZero(fRadiant)) 190 { 191 /// scale and shear, but no rotate 192 B2DHomMatrix aRetval( 193 /* Row 0, Column 0 */ fScaleX, 194 /* Row 0, Column 1 */ fScaleY * fShearX, 195 /* Row 0, Column 2 */ fTranslateX, 196 /* Row 1, Column 0 */ 0.0, 197 /* Row 1, Column 1 */ fScaleY, 198 /* Row 1, Column 2 */ fTranslateY); 199 200 return aRetval; 201 } 202 else 203 { 204 /// scale, shear and rotate used 205 double fSin(0.0); 206 double fCos(1.0); 207 208 createSinCosOrthogonal(fSin, fCos, fRadiant); 209 210 B2DHomMatrix aRetval( 211 /* Row 0, Column 0 */ fCos * fScaleX, 212 /* Row 0, Column 1 */ fScaleY * ((fCos * fShearX) - fSin), 213 /* Row 0, Column 2 */ fTranslateX, 214 /* Row 1, Column 0 */ fSin * fScaleX, 215 /* Row 1, Column 1 */ fScaleY * ((fSin * fShearX) + fCos), 216 /* Row 1, Column 2 */ fTranslateY); 217 218 return aRetval; 219 } 220 } 221 } 222 } 223 createShearXRotateTranslateB2DHomMatrix(double fShearX,double fRadiant,double fTranslateX,double fTranslateY)224 B2DHomMatrix createShearXRotateTranslateB2DHomMatrix( 225 double fShearX, 226 double fRadiant, 227 double fTranslateX, double fTranslateY) 228 { 229 if(fTools::equalZero(fShearX)) 230 { 231 /// no shear 232 if(fTools::equalZero(fRadiant)) 233 { 234 /// no shear, no rotate, take shortcut 235 return createTranslateB2DHomMatrix(fTranslateX, fTranslateY); 236 } 237 else 238 { 239 /// no shear, but rotate used 240 double fSin(0.0); 241 double fCos(1.0); 242 243 createSinCosOrthogonal(fSin, fCos, fRadiant); 244 245 B2DHomMatrix aRetval( 246 /* Row 0, Column 0 */ fCos, 247 /* Row 0, Column 1 */ -fSin, 248 /* Row 0, Column 2 */ fTranslateX, 249 /* Row 1, Column 0 */ fSin, 250 /* Row 1, Column 1 */ fCos, 251 /* Row 1, Column 2 */ fTranslateY); 252 253 return aRetval; 254 } 255 } 256 else 257 { 258 /// shear used 259 if(fTools::equalZero(fRadiant)) 260 { 261 /// no rotate, but shear used 262 B2DHomMatrix aRetval( 263 /* Row 0, Column 0 */ 1.0, 264 /* Row 0, Column 1 */ fShearX, 265 /* Row 0, Column 2 */ fTranslateX, 266 /* Row 1, Column 0 */ 0.0, 267 /* Row 1, Column 1 */ 1.0, 268 /* Row 1, Column 2 */ fTranslateY); 269 270 return aRetval; 271 } 272 else 273 { 274 /// shear and rotate used 275 double fSin(0.0); 276 double fCos(1.0); 277 278 createSinCosOrthogonal(fSin, fCos, fRadiant); 279 280 B2DHomMatrix aRetval( 281 /* Row 0, Column 0 */ fCos, 282 /* Row 0, Column 1 */ (fCos * fShearX) - fSin, 283 /* Row 0, Column 2 */ fTranslateX, 284 /* Row 1, Column 0 */ fSin, 285 /* Row 1, Column 1 */ (fSin * fShearX) + fCos, 286 /* Row 1, Column 2 */ fTranslateY); 287 288 return aRetval; 289 } 290 } 291 } 292 createScaleTranslateB2DHomMatrix(double fScaleX,double fScaleY,double fTranslateX,double fTranslateY)293 B2DHomMatrix createScaleTranslateB2DHomMatrix( 294 double fScaleX, double fScaleY, 295 double fTranslateX, double fTranslateY) 296 { 297 const double fOne(1.0); 298 299 if(fTools::equal(fScaleX, fOne) && fTools::equal(fScaleY, fOne)) 300 { 301 /// no scale, take shortcut 302 return createTranslateB2DHomMatrix(fTranslateX, fTranslateY); 303 } 304 else 305 { 306 /// scale used 307 if(fTools::equalZero(fTranslateX) && fTools::equalZero(fTranslateY)) 308 { 309 /// no translate, but scale. 310 B2DHomMatrix aRetval; 311 312 aRetval.set(0, 0, fScaleX); 313 aRetval.set(1, 1, fScaleY); 314 315 return aRetval; 316 } 317 else 318 { 319 /// translate and scale 320 B2DHomMatrix aRetval( 321 /* Row 0, Column 0 */ fScaleX, 322 /* Row 0, Column 1 */ 0.0, 323 /* Row 0, Column 2 */ fTranslateX, 324 /* Row 1, Column 0 */ 0.0, 325 /* Row 1, Column 1 */ fScaleY, 326 /* Row 1, Column 2 */ fTranslateY); 327 328 return aRetval; 329 } 330 } 331 } 332 createRotateAroundPoint(double fPointX,double fPointY,double fRadiant)333 B2DHomMatrix createRotateAroundPoint( 334 double fPointX, double fPointY, 335 double fRadiant) 336 { 337 B2DHomMatrix aRetval; 338 339 if(!fTools::equalZero(fRadiant)) 340 { 341 double fSin(0.0); 342 double fCos(1.0); 343 344 createSinCosOrthogonal(fSin, fCos, fRadiant); 345 346 aRetval.set3x2( 347 /* Row 0, Column 0 */ fCos, 348 /* Row 0, Column 1 */ -fSin, 349 /* Row 0, Column 2 */ (fPointX * (1.0 - fCos)) + (fSin * fPointY), 350 /* Row 1, Column 0 */ fSin, 351 /* Row 1, Column 1 */ fCos, 352 /* Row 1, Column 2 */ (fPointY * (1.0 - fCos)) - (fSin * fPointX)); 353 } 354 355 return aRetval; 356 } 357 createRotateAroundCenterKeepAspectRatioStayInsideRange(const basegfx::B2DRange & rTargetRange,double fRotate)358 BASEGFX_DLLPUBLIC B2DHomMatrix createRotateAroundCenterKeepAspectRatioStayInsideRange( 359 const basegfx::B2DRange& rTargetRange, 360 double fRotate) 361 { 362 basegfx::B2DHomMatrix aRetval; 363 364 // RotGrfFlyFrame: Create a transformation that maps the range inside of itself 365 // so that it fits, takes as much space as possible and keeps the aspect ratio 366 if(0.0 != fRotate) 367 { 368 // Fit rotated graphic to center of available space, keeping page ratio: 369 // Adapt scaling ratio of unit object and rotate it 370 aRetval.scale(1.0, rTargetRange.getHeight() / rTargetRange.getWidth()); 371 aRetval.rotate(fRotate); 372 373 // get the range to see where we are in unit coordinates 374 basegfx::B2DRange aFullRange(0.0, 0.0, 1.0, 1.0); 375 aFullRange.transform(aRetval); 376 377 // detect needed scales in X/Y and choose the smallest for staying inside the 378 // available space while keeping aspect ratio of the source 379 const double fScaleX(rTargetRange.getWidth() / aFullRange.getWidth()); 380 const double fScaleY(rTargetRange.getHeight() / aFullRange.getHeight()); 381 const double fScaleMin(std::min(fScaleX, fScaleY)); 382 383 // TopLeft to zero, then scale, then move to center of available space 384 aRetval.translate(-aFullRange.getMinX(), -aFullRange.getMinY()); 385 aRetval.scale(fScaleMin, fScaleMin); 386 aRetval.translate( 387 rTargetRange.getCenterX() - (0.5 * fScaleMin * aFullRange.getWidth()), 388 rTargetRange.getCenterY() - (0.5 * fScaleMin * aFullRange.getHeight())); 389 } 390 else 391 { 392 // just scale/translate needed 393 aRetval *= createScaleTranslateB2DHomMatrix( 394 rTargetRange.getRange(), 395 rTargetRange.getMinimum()); 396 } 397 398 return aRetval; 399 } 400 401 /// special for the case to map from source range to target range createSourceRangeTargetRangeTransform(const B2DRange & rSourceRange,const B2DRange & rTargetRange)402 B2DHomMatrix createSourceRangeTargetRangeTransform( 403 const B2DRange& rSourceRange, 404 const B2DRange& rTargetRange) 405 { 406 B2DHomMatrix aRetval; 407 408 if(&rSourceRange == &rTargetRange) 409 { 410 return aRetval; 411 } 412 413 if(!fTools::equalZero(rSourceRange.getMinX()) || !fTools::equalZero(rSourceRange.getMinY())) 414 { 415 aRetval.set(0, 2, -rSourceRange.getMinX()); 416 aRetval.set(1, 2, -rSourceRange.getMinY()); 417 } 418 419 const double fSourceW(rSourceRange.getWidth()); 420 const double fSourceH(rSourceRange.getHeight()); 421 const bool bDivX(!fTools::equalZero(fSourceW) && !fTools::equal(fSourceW, 1.0)); 422 const bool bDivY(!fTools::equalZero(fSourceH) && !fTools::equal(fSourceH, 1.0)); 423 const double fScaleX(bDivX ? rTargetRange.getWidth() / fSourceW : rTargetRange.getWidth()); 424 const double fScaleY(bDivY ? rTargetRange.getHeight() / fSourceH : rTargetRange.getHeight()); 425 426 if(!fTools::equalZero(fScaleX) || !fTools::equalZero(fScaleY)) 427 { 428 aRetval.scale(fScaleX, fScaleY); 429 } 430 431 if(!fTools::equalZero(rTargetRange.getMinX()) || !fTools::equalZero(rTargetRange.getMinY())) 432 { 433 aRetval.translate( 434 rTargetRange.getMinX(), 435 rTargetRange.getMinY()); 436 } 437 438 return aRetval; 439 } 440 createCoordinateSystemTransform(const B2DPoint & rOrigin,const B2DVector & rX,const B2DVector & rY)441 B2DHomMatrix createCoordinateSystemTransform( 442 const B2DPoint& rOrigin, 443 const B2DVector& rX, 444 const B2DVector& rY) 445 { 446 return basegfx::B2DHomMatrix( 447 rX.getX(), rY.getX(), rOrigin.getX(), 448 rX.getY(), rY.getY(), rOrigin.getY()); 449 } 450 getColumn(const B2DHomMatrix & rMatrix,sal_uInt16 nCol)451 B2DTuple getColumn(const B2DHomMatrix& rMatrix, sal_uInt16 nCol) 452 { 453 return B2DTuple(rMatrix.get(0, nCol), rMatrix.get(1, nCol)); 454 } 455 } // end of namespace 456 457 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 458