LCOV - code coverage report
Current view: top level - basegfx/source/tools - gradienttools.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 54 162 33.3 %
Date: 2015-06-13 12:38:46 Functions: 6 17 35.3 %
Legend: Lines: hit not hit

          Line data    Source code
       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/tools/gradienttools.hxx>
      21             : #include <basegfx/point/b2dpoint.hxx>
      22             : #include <basegfx/range/b2drange.hxx>
      23             : #include <basegfx/matrix/b2dhommatrixtools.hxx>
      24             : 
      25             : namespace basegfx
      26             : {
      27           0 :     bool ODFGradientInfo::operator==(const ODFGradientInfo& rODFGradientInfo) const
      28             :     {
      29           0 :         return getTextureTransform() == rODFGradientInfo.getTextureTransform()
      30           0 :             && getAspectRatio() == rODFGradientInfo.getAspectRatio()
      31           0 :             && getSteps() == rODFGradientInfo.getSteps();
      32             :     }
      33             : 
      34      367462 :     const B2DHomMatrix& ODFGradientInfo::getBackTextureTransform() const
      35             :     {
      36      367462 :         if(maBackTextureTransform.isIdentity())
      37             :         {
      38          41 :             const_cast< ODFGradientInfo* >(this)->maBackTextureTransform = getTextureTransform();
      39          41 :             const_cast< ODFGradientInfo* >(this)->maBackTextureTransform.invert();
      40             :         }
      41             : 
      42      367462 :         return maBackTextureTransform;
      43             :     }
      44             : 
      45             :     /** Most of the setup for linear & axial gradient is the same, except
      46             :         for the border treatment. Factored out here.
      47             :     */
      48        1805 :     ODFGradientInfo init1DGradientInfo(
      49             :         const B2DRange& rTargetRange,
      50             :         sal_uInt32 nSteps,
      51             :         double fBorder,
      52             :         double fAngle,
      53             :         bool bAxial)
      54             :     {
      55        1805 :         B2DHomMatrix aTextureTransform;
      56             : 
      57        1805 :         fAngle = -fAngle;
      58             : 
      59        1805 :         double fTargetSizeX(rTargetRange.getWidth());
      60        1805 :         double fTargetSizeY(rTargetRange.getHeight());
      61        1805 :         double fTargetOffsetX(rTargetRange.getMinX());
      62        1805 :         double fTargetOffsetY(rTargetRange.getMinY());
      63             : 
      64             :         // add object expansion
      65        1805 :         const bool bAngleUsed(!fTools::equalZero(fAngle));
      66             : 
      67        1805 :         if(bAngleUsed)
      68             :         {
      69         425 :             const double fAbsCos(fabs(cos(fAngle)));
      70         425 :             const double fAbsSin(fabs(sin(fAngle)));
      71         425 :             const double fNewX(fTargetSizeX * fAbsCos + fTargetSizeY * fAbsSin);
      72         425 :             const double fNewY(fTargetSizeY * fAbsCos + fTargetSizeX * fAbsSin);
      73             : 
      74         425 :             fTargetOffsetX -= (fNewX - fTargetSizeX) / 2.0;
      75         425 :             fTargetOffsetY -= (fNewY - fTargetSizeY) / 2.0;
      76         425 :             fTargetSizeX = fNewX;
      77         425 :             fTargetSizeY = fNewY;
      78             :         }
      79             : 
      80        1805 :         const double fSizeWithoutBorder(1.0 - fBorder);
      81             : 
      82        1805 :         if(bAxial)
      83             :         {
      84         381 :             aTextureTransform.scale(1.0, fSizeWithoutBorder * 0.5);
      85         381 :             aTextureTransform.translate(0.0, 0.5);
      86             :         }
      87             :         else
      88             :         {
      89        1424 :             if(!fTools::equal(fSizeWithoutBorder, 1.0))
      90             :             {
      91           0 :                 aTextureTransform.scale(1.0, fSizeWithoutBorder);
      92           0 :                 aTextureTransform.translate(0.0, fBorder);
      93             :             }
      94             :         }
      95             : 
      96        1805 :         aTextureTransform.scale(fTargetSizeX, fTargetSizeY);
      97             : 
      98             :         // add texture rotate after scale to keep perpendicular angles
      99        1805 :         if(bAngleUsed)
     100             :         {
     101         425 :             const B2DPoint aCenter(0.5 * fTargetSizeX, 0.5 * fTargetSizeY);
     102             : 
     103         425 :             aTextureTransform *= basegfx::tools::createRotateAroundPoint(aCenter, fAngle);
     104             :         }
     105             : 
     106             :         // add object translate
     107        1805 :         aTextureTransform.translate(fTargetOffsetX, fTargetOffsetY);
     108             : 
     109             :         // prepare aspect for texture
     110        1805 :         const double fAspectRatio(fTools::equalZero(fTargetSizeY) ?  1.0 : fTargetSizeX / fTargetSizeY);
     111             : 
     112        1805 :         return ODFGradientInfo(aTextureTransform, fAspectRatio, nSteps);
     113             :     }
     114             : 
     115             :     /** Most of the setup for radial & ellipsoidal gradient is the same,
     116             :         except for the border treatment. Factored out here.
     117             :     */
     118           0 :     ODFGradientInfo initEllipticalGradientInfo(
     119             :         const B2DRange& rTargetRange,
     120             :         const B2DVector& rOffset,
     121             :         sal_uInt32 nSteps,
     122             :         double fBorder,
     123             :         double fAngle,
     124             :         bool bCircular)
     125             :     {
     126           0 :         B2DHomMatrix aTextureTransform;
     127             : 
     128           0 :         fAngle = -fAngle;
     129             : 
     130           0 :         double fTargetSizeX(rTargetRange.getWidth());
     131           0 :         double fTargetSizeY(rTargetRange.getHeight());
     132           0 :         double fTargetOffsetX(rTargetRange.getMinX());
     133           0 :         double fTargetOffsetY(rTargetRange.getMinY());
     134             : 
     135             :         // add object expansion
     136           0 :         if(bCircular)
     137             :         {
     138           0 :             const double fOriginalDiag(sqrt((fTargetSizeX * fTargetSizeX) + (fTargetSizeY * fTargetSizeY)));
     139             : 
     140           0 :             fTargetOffsetX -= (fOriginalDiag - fTargetSizeX) / 2.0;
     141           0 :             fTargetOffsetY -= (fOriginalDiag - fTargetSizeY) / 2.0;
     142           0 :             fTargetSizeX = fOriginalDiag;
     143           0 :             fTargetSizeY = fOriginalDiag;
     144             :         }
     145             :         else
     146             :         {
     147           0 :             fTargetOffsetX -= (0.4142 / 2.0 ) * fTargetSizeX;
     148           0 :             fTargetOffsetY -= (0.4142 / 2.0 ) * fTargetSizeY;
     149           0 :             fTargetSizeX = 1.4142 * fTargetSizeX;
     150           0 :             fTargetSizeY = 1.4142 * fTargetSizeY;
     151             :         }
     152             : 
     153           0 :         const double fHalfBorder((1.0 - fBorder) * 0.5);
     154             : 
     155           0 :         aTextureTransform.scale(fHalfBorder, fHalfBorder);
     156           0 :         aTextureTransform.translate(0.5, 0.5);
     157           0 :         aTextureTransform.scale(fTargetSizeX, fTargetSizeY);
     158             : 
     159             :         // add texture rotate after scale to keep perpendicular angles
     160           0 :         if(!bCircular && !fTools::equalZero(fAngle))
     161             :         {
     162           0 :             const B2DPoint aCenter(0.5 * fTargetSizeX, 0.5 * fTargetSizeY);
     163             : 
     164           0 :             aTextureTransform *= basegfx::tools::createRotateAroundPoint(aCenter, fAngle);
     165             :         }
     166             : 
     167             :         // add defined offsets after rotation
     168           0 :         if(!fTools::equal(0.5, rOffset.getX()) || !fTools::equal(0.5, rOffset.getY()))
     169             :         {
     170             :             // use original target size
     171           0 :             fTargetOffsetX += (rOffset.getX() - 0.5) * rTargetRange.getWidth();
     172           0 :             fTargetOffsetY += (rOffset.getY() - 0.5) * rTargetRange.getHeight();
     173             :         }
     174             : 
     175             :         // add object translate
     176           0 :         aTextureTransform.translate(fTargetOffsetX, fTargetOffsetY);
     177             : 
     178             :         // prepare aspect for texture
     179           0 :         const double fAspectRatio((0.0 != fTargetSizeY) ?  fTargetSizeX / fTargetSizeY : 1.0);
     180             : 
     181           0 :         return ODFGradientInfo(aTextureTransform, fAspectRatio, nSteps);
     182             :     }
     183             : 
     184             :     /** Setup for rect & square gradient is exactly the same. Factored out
     185             :         here.
     186             :     */
     187           0 :     ODFGradientInfo initRectGradientInfo(
     188             :         const B2DRange& rTargetRange,
     189             :         const B2DVector& rOffset,
     190             :         sal_uInt32 nSteps,
     191             :         double fBorder,
     192             :         double fAngle,
     193             :         bool bSquare)
     194             :     {
     195           0 :         B2DHomMatrix aTextureTransform;
     196             : 
     197           0 :         fAngle = -fAngle;
     198             : 
     199           0 :         double fTargetSizeX(rTargetRange.getWidth());
     200           0 :         double fTargetSizeY(rTargetRange.getHeight());
     201           0 :         double fTargetOffsetX(rTargetRange.getMinX());
     202           0 :         double fTargetOffsetY(rTargetRange.getMinY());
     203             : 
     204             :         // add object expansion
     205           0 :         if(bSquare)
     206             :         {
     207           0 :             const double fSquareWidth(std::max(fTargetSizeX, fTargetSizeY));
     208             : 
     209           0 :             fTargetOffsetX -= (fSquareWidth - fTargetSizeX) / 2.0;
     210           0 :             fTargetOffsetY -= (fSquareWidth - fTargetSizeY) / 2.0;
     211           0 :             fTargetSizeX = fTargetSizeY = fSquareWidth;
     212             :         }
     213             : 
     214             :         // add object expansion
     215           0 :         const bool bAngleUsed(!fTools::equalZero(fAngle));
     216             : 
     217           0 :         if(bAngleUsed)
     218             :         {
     219           0 :             const double fAbsCos(fabs(cos(fAngle)));
     220           0 :             const double fAbsSin(fabs(sin(fAngle)));
     221           0 :             const double fNewX(fTargetSizeX * fAbsCos + fTargetSizeY * fAbsSin);
     222           0 :             const double fNewY(fTargetSizeY * fAbsCos + fTargetSizeX * fAbsSin);
     223             : 
     224           0 :             fTargetOffsetX -= (fNewX - fTargetSizeX) / 2.0;
     225           0 :             fTargetOffsetY -= (fNewY - fTargetSizeY) / 2.0;
     226           0 :             fTargetSizeX = fNewX;
     227           0 :             fTargetSizeY = fNewY;
     228             :         }
     229             : 
     230           0 :         const double fHalfBorder((1.0 - fBorder) * 0.5);
     231             : 
     232           0 :         aTextureTransform.scale(fHalfBorder, fHalfBorder);
     233           0 :         aTextureTransform.translate(0.5, 0.5);
     234           0 :         aTextureTransform.scale(fTargetSizeX, fTargetSizeY);
     235             : 
     236             :         // add texture rotate after scale to keep perpendicular angles
     237           0 :         if(bAngleUsed)
     238             :         {
     239           0 :             const B2DPoint aCenter(0.5 * fTargetSizeX, 0.5 * fTargetSizeY);
     240             : 
     241           0 :             aTextureTransform *= basegfx::tools::createRotateAroundPoint(aCenter, fAngle);
     242             :         }
     243             : 
     244             :         // add defined offsets after rotation
     245           0 :         if(!fTools::equal(0.5, rOffset.getX()) || !fTools::equal(0.5, rOffset.getY()))
     246             :         {
     247             :             // use scaled target size
     248           0 :             fTargetOffsetX += (rOffset.getX() - 0.5) * fTargetSizeX;
     249           0 :             fTargetOffsetY += (rOffset.getY() - 0.5) * fTargetSizeY;
     250             :         }
     251             : 
     252             :         // add object translate
     253           0 :         aTextureTransform.translate(fTargetOffsetX, fTargetOffsetY);
     254             : 
     255             :         // prepare aspect for texture
     256           0 :         const double fAspectRatio((0.0 != fTargetSizeY) ? fTargetSizeX / fTargetSizeY : 1.0);
     257             : 
     258           0 :         return ODFGradientInfo(aTextureTransform, fAspectRatio, nSteps);
     259             :     }
     260             : 
     261             :     namespace tools
     262             :     {
     263        1424 :         ODFGradientInfo createLinearODFGradientInfo(
     264             :             const B2DRange& rTargetArea,
     265             :             sal_uInt32 nSteps,
     266             :             double fBorder,
     267             :             double fAngle)
     268             :         {
     269             :             return init1DGradientInfo(
     270             :                 rTargetArea,
     271             :                 nSteps,
     272             :                 fBorder,
     273             :                 fAngle,
     274        1424 :                 false);
     275             :         }
     276             : 
     277         381 :         ODFGradientInfo createAxialODFGradientInfo(
     278             :             const B2DRange& rTargetArea,
     279             :             sal_uInt32 nSteps,
     280             :             double fBorder,
     281             :             double fAngle)
     282             :         {
     283             :             return init1DGradientInfo(
     284             :                 rTargetArea,
     285             :                 nSteps,
     286             :                 fBorder,
     287             :                 fAngle,
     288         381 :                 true);
     289             :         }
     290             : 
     291           0 :         ODFGradientInfo createRadialODFGradientInfo(
     292             :             const B2DRange& rTargetArea,
     293             :             const B2DVector& rOffset,
     294             :             sal_uInt32 nSteps,
     295             :             double fBorder)
     296             :         {
     297             :             return initEllipticalGradientInfo(
     298             :                 rTargetArea,
     299             :                 rOffset,
     300             :                 nSteps,
     301             :                 fBorder,
     302             :                 0.0,
     303           0 :                 true);
     304             :         }
     305             : 
     306           0 :         ODFGradientInfo createEllipticalODFGradientInfo(
     307             :             const B2DRange& rTargetArea,
     308             :             const B2DVector& rOffset,
     309             :             sal_uInt32 nSteps,
     310             :             double fBorder,
     311             :             double fAngle)
     312             :         {
     313             :             return initEllipticalGradientInfo(
     314             :                 rTargetArea,
     315             :                 rOffset,
     316             :                 nSteps,
     317             :                 fBorder,
     318             :                 fAngle,
     319           0 :                 false);
     320             :         }
     321             : 
     322           0 :         ODFGradientInfo createSquareODFGradientInfo(
     323             :             const B2DRange& rTargetArea,
     324             :             const B2DVector& rOffset,
     325             :             sal_uInt32 nSteps,
     326             :             double fBorder,
     327             :             double fAngle)
     328             :         {
     329             :             return initRectGradientInfo(
     330             :                 rTargetArea,
     331             :                 rOffset,
     332             :                 nSteps,
     333             :                 fBorder,
     334             :                 fAngle,
     335           0 :                 true);
     336             :         }
     337             : 
     338           0 :         ODFGradientInfo createRectangularODFGradientInfo(
     339             :             const B2DRange& rTargetArea,
     340             :             const B2DVector& rOffset,
     341             :             sal_uInt32 nSteps,
     342             :             double fBorder,
     343             :             double fAngle)
     344             :         {
     345             :             return initRectGradientInfo(
     346             :                 rTargetArea,
     347             :                 rOffset,
     348             :                 nSteps,
     349             :                 fBorder,
     350             :                 fAngle,
     351           0 :                 false);
     352             :         }
     353             : 
     354      183639 :         double getLinearGradientAlpha(const B2DPoint& rUV, const ODFGradientInfo& rGradInfo)
     355             :         {
     356      183639 :             const B2DPoint aCoor(rGradInfo.getBackTextureTransform() * rUV);
     357             : 
     358             :             // Ignore Y, this is not needed at all for Y-Oriented gradients
     359             :             // if(aCoor.getX() < 0.0 || aCoor.getX() > 1.0)
     360             :             // {
     361             :             //     return 0.0;
     362             :             // }
     363             : 
     364      183639 :             if(aCoor.getY() <= 0.0)
     365             :             {
     366        7476 :                 return 0.0; // start value for inside
     367             :             }
     368             : 
     369      176163 :             if(aCoor.getY() >= 1.0)
     370             :             {
     371           0 :                 return 1.0; // end value for outside
     372             :             }
     373             : 
     374      176163 :             const sal_uInt32 nSteps(rGradInfo.getSteps());
     375             : 
     376      176163 :             if(nSteps)
     377             :             {
     378      176163 :                 return floor(aCoor.getY() * nSteps) / double(nSteps - 1);
     379             :             }
     380             : 
     381           0 :             return aCoor.getY();
     382             :         }
     383             : 
     384      183817 :         double getAxialGradientAlpha(const B2DPoint& rUV, const ODFGradientInfo& rGradInfo)
     385             :         {
     386      183817 :             const B2DPoint aCoor(rGradInfo.getBackTextureTransform() * rUV);
     387             : 
     388             :             // Ignore Y, this is not needed at all for Y-Oriented gradients
     389             :             //if(aCoor.getX() < 0.0 || aCoor.getX() > 1.0)
     390             :             //{
     391             :             //    return 0.0;
     392             :             //}
     393             : 
     394      183817 :             const double fAbsY(fabs(aCoor.getY()));
     395             : 
     396      183817 :             if(fAbsY >= 1.0)
     397             :             {
     398          13 :                 return 1.0; // use end value when outside in Y
     399             :             }
     400             : 
     401      183804 :             const sal_uInt32 nSteps(rGradInfo.getSteps());
     402             : 
     403      183804 :             if(nSteps)
     404             :             {
     405      183804 :                 return floor(fAbsY * nSteps) / double(nSteps - 1);
     406             :             }
     407             : 
     408           0 :             return fAbsY;
     409             :         }
     410             : 
     411           0 :         double getRadialGradientAlpha(const B2DPoint& rUV, const ODFGradientInfo& rGradInfo)
     412             :         {
     413           0 :             const B2DPoint aCoor(rGradInfo.getBackTextureTransform() * rUV);
     414             : 
     415           0 :             if(aCoor.getX() < -1.0 || aCoor.getX() > 1.0 || aCoor.getY() < -1.0 || aCoor.getY() > 1.0)
     416             :             {
     417           0 :                 return 0.0;
     418             :             }
     419             : 
     420           0 :             const double t(1.0 - sqrt(aCoor.getX() * aCoor.getX() + aCoor.getY() * aCoor.getY()));
     421           0 :             const sal_uInt32 nSteps(rGradInfo.getSteps());
     422             : 
     423           0 :             if(nSteps && t < 1.0)
     424             :             {
     425           0 :                 return floor(t * nSteps) / double(nSteps - 1);
     426             :             }
     427             : 
     428           0 :             return t;
     429             :         }
     430             : 
     431           0 :         double getEllipticalGradientAlpha(const B2DPoint& rUV, const ODFGradientInfo& rGradInfo)
     432             :         {
     433           0 :             return getRadialGradientAlpha(rUV, rGradInfo); // only matrix setup differs
     434             :         }
     435             : 
     436           0 :         double getSquareGradientAlpha(const B2DPoint& rUV, const ODFGradientInfo& rGradInfo)
     437             :         {
     438           0 :             const B2DPoint aCoor(rGradInfo.getBackTextureTransform() * rUV);
     439           0 :             const double fAbsX(fabs(aCoor.getX()));
     440             : 
     441           0 :             if(fAbsX >= 1.0)
     442             :             {
     443           0 :                 return 0.0;
     444             :             }
     445             : 
     446           0 :             const double fAbsY(fabs(aCoor.getY()));
     447             : 
     448           0 :             if(fAbsY >= 1.0)
     449             :             {
     450           0 :                 return 0.0;
     451             :             }
     452             : 
     453           0 :             const double t(1.0 - std::max(fAbsX, fAbsY));
     454           0 :             const sal_uInt32 nSteps(rGradInfo.getSteps());
     455             : 
     456           0 :             if(nSteps && t < 1.0)
     457             :             {
     458           0 :                 return floor(t * nSteps) / double(nSteps - 1);
     459             :             }
     460             : 
     461           0 :             return t;
     462             :         }
     463             : 
     464           0 :         double getRectangularGradientAlpha(const B2DPoint& rUV, const ODFGradientInfo& rGradInfo)
     465             :         {
     466           0 :             return getSquareGradientAlpha(rUV, rGradInfo); // only matrix setup differs
     467             :         }
     468             :     } // namespace tools
     469             : } // namespace basegfx
     470             : 
     471             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.11