LCOV - code coverage report
Current view: top level - basegfx/source/polygon - b2dpolygontools.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 717 1381 51.9 %
Date: 2012-08-25 Functions: 41 63 65.1 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 748 2427 30.8 %

           Branch data     Line data    Source code
       1                 :            : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2                 :            : /*************************************************************************
       3                 :            :  *
       4                 :            :  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       5                 :            :  *
       6                 :            :  * Copyright 2000, 2010 Oracle and/or its affiliates.
       7                 :            :  *
       8                 :            :  * OpenOffice.org - a multi-platform office productivity suite
       9                 :            :  *
      10                 :            :  * This file is part of OpenOffice.org.
      11                 :            :  *
      12                 :            :  * OpenOffice.org is free software: you can redistribute it and/or modify
      13                 :            :  * it under the terms of the GNU Lesser General Public License version 3
      14                 :            :  * only, as published by the Free Software Foundation.
      15                 :            :  *
      16                 :            :  * OpenOffice.org is distributed in the hope that it will be useful,
      17                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      18                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      19                 :            :  * GNU Lesser General Public License version 3 for more details
      20                 :            :  * (a copy is included in the LICENSE file that accompanied this code).
      21                 :            :  *
      22                 :            :  * You should have received a copy of the GNU Lesser General Public License
      23                 :            :  * version 3 along with OpenOffice.org.  If not, see
      24                 :            :  * <http://www.openoffice.org/license.html>
      25                 :            :  * for a copy of the LGPLv3 License.
      26                 :            :  *
      27                 :            :  ************************************************************************/
      28                 :            : 
      29                 :            : #include <basegfx/numeric/ftools.hxx>
      30                 :            : #include <basegfx/polygon/b2dpolygontools.hxx>
      31                 :            : #include <osl/diagnose.h>
      32                 :            : #include <rtl/math.hxx>
      33                 :            : #include <rtl/instance.hxx>
      34                 :            : #include <basegfx/polygon/b2dpolygon.hxx>
      35                 :            : #include <basegfx/polygon/b2dpolypolygon.hxx>
      36                 :            : #include <basegfx/range/b2drange.hxx>
      37                 :            : #include <basegfx/curve/b2dcubicbezier.hxx>
      38                 :            : #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
      39                 :            : #include <basegfx/point/b3dpoint.hxx>
      40                 :            : #include <basegfx/matrix/b3dhommatrix.hxx>
      41                 :            : #include <basegfx/matrix/b2dhommatrix.hxx>
      42                 :            : #include <basegfx/curve/b2dbeziertools.hxx>
      43                 :            : #include <basegfx/matrix/b2dhommatrixtools.hxx>
      44                 :            : #include <osl/mutex.hxx>
      45                 :            : 
      46                 :            : #include <numeric>
      47                 :            : #include <limits>
      48                 :            : 
      49                 :            : // #i37443#
      50                 :            : #define ANGLE_BOUND_START_VALUE     (2.25)
      51                 :            : #define ANGLE_BOUND_MINIMUM_VALUE   (0.1)
      52                 :            : #define COUNT_SUBDIVIDE_DEFAULT     (4L)
      53                 :            : #ifdef DBG_UTIL
      54                 :            : static double fAngleBoundStartValue = ANGLE_BOUND_START_VALUE;
      55                 :            : #endif
      56                 :            : #define STEPSPERQUARTER     (3)
      57                 :            : 
      58                 :            : //////////////////////////////////////////////////////////////////////////////
      59                 :            : 
      60                 :            : namespace basegfx
      61                 :            : {
      62                 :            :     namespace tools
      63                 :            :     {
      64                 :          0 :         void openWithGeometryChange(B2DPolygon& rCandidate)
      65                 :            :         {
      66         [ #  # ]:          0 :             if(rCandidate.isClosed())
      67                 :            :             {
      68         [ #  # ]:          0 :                 if(rCandidate.count())
      69                 :            :                 {
      70         [ #  # ]:          0 :                     rCandidate.append(rCandidate.getB2DPoint(0));
      71                 :            : 
      72 [ #  # ][ #  # ]:          0 :                     if(rCandidate.areControlPointsUsed() && rCandidate.isPrevControlPointUsed(0))
                 [ #  # ]
      73                 :            :                     {
      74 [ #  # ][ #  # ]:          0 :                         rCandidate.setPrevControlPoint(rCandidate.count() - 1, rCandidate.getPrevControlPoint(0));
      75                 :          0 :                         rCandidate.resetPrevControlPoint(0);
      76                 :            :                     }
      77                 :            :                 }
      78                 :            : 
      79                 :          0 :                 rCandidate.setClosed(false);
      80                 :            :             }
      81                 :          0 :         }
      82                 :            : 
      83                 :      21168 :         void closeWithGeometryChange(B2DPolygon& rCandidate)
      84                 :            :         {
      85         [ +  - ]:      21168 :             if(!rCandidate.isClosed())
      86                 :            :             {
      87 [ +  - ][ +  + ]:      40006 :                 while(rCandidate.count() > 1 && rCandidate.getB2DPoint(0) == rCandidate.getB2DPoint(rCandidate.count() - 1))
         [ +  - ][ +  - ]
         [ +  - ][ +  + ]
         [ +  + ][ +  + ]
           [ +  +  #  #  
                   #  # ]
      88                 :            :                 {
      89 [ +  + ][ +  + ]:      18838 :                     if(rCandidate.areControlPointsUsed() && rCandidate.isPrevControlPointUsed(rCandidate.count() - 1))
                 [ +  + ]
      90                 :            :                     {
      91         [ +  - ]:       2113 :                         rCandidate.setPrevControlPoint(0, rCandidate.getPrevControlPoint(rCandidate.count() - 1));
      92                 :            :                     }
      93                 :            : 
      94                 :      18838 :                     rCandidate.remove(rCandidate.count() - 1);
      95                 :            :                 }
      96                 :            : 
      97                 :      21168 :                 rCandidate.setClosed(true);
      98                 :            :             }
      99                 :      21168 :         }
     100                 :            : 
     101                 :      51131 :         void checkClosed(B2DPolygon& rCandidate)
     102                 :            :         {
     103                 :            :             // #i80172# Removed unnecessary assertion
     104                 :            :             // OSL_ENSURE(!rCandidate.isClosed(), "checkClosed: already closed (!)");
     105                 :            : 
     106 [ +  - ][ +  - ]:      51131 :             if(rCandidate.count() > 1 && rCandidate.getB2DPoint(0) == rCandidate.getB2DPoint(rCandidate.count() - 1))
         [ +  - ][ +  - ]
         [ +  - ][ +  + ]
         [ +  - ][ +  - ]
           [ +  +  #  #  
                   #  # ]
     107                 :            :             {
     108                 :      17232 :                 closeWithGeometryChange(rCandidate);
     109                 :            :             }
     110                 :      51131 :         }
     111                 :            : 
     112                 :            :         // Get successor and predecessor indices. Returning the same index means there
     113                 :            :         // is none. Same for successor.
     114                 :        175 :         sal_uInt32 getIndexOfPredecessor(sal_uInt32 nIndex, const B2DPolygon& rCandidate)
     115                 :            :         {
     116                 :            :             OSL_ENSURE(nIndex < rCandidate.count(), "getIndexOfPredecessor: Access to polygon out of range (!)");
     117                 :            : 
     118         [ -  + ]:        175 :             if(nIndex)
     119                 :            :             {
     120                 :          0 :                 return nIndex - 1L;
     121                 :            :             }
     122         [ +  - ]:        175 :             else if(rCandidate.count())
     123                 :            :             {
     124                 :        175 :                 return rCandidate.count() - 1L;
     125                 :            :             }
     126                 :            :             else
     127                 :            :             {
     128                 :        175 :                 return nIndex;
     129                 :            :             }
     130                 :            :         }
     131                 :            : 
     132                 :        175 :         sal_uInt32 getIndexOfSuccessor(sal_uInt32 nIndex, const B2DPolygon& rCandidate)
     133                 :            :         {
     134                 :            :             OSL_ENSURE(nIndex < rCandidate.count(), "getIndexOfPredecessor: Access to polygon out of range (!)");
     135                 :            : 
     136         [ +  + ]:        175 :             if(nIndex + 1L < rCandidate.count())
     137                 :            :             {
     138                 :        155 :                 return nIndex + 1L;
     139                 :            :             }
     140         [ +  - ]:         20 :             else if(nIndex + 1L == rCandidate.count())
     141                 :            :             {
     142                 :         20 :                 return 0L;
     143                 :            :             }
     144                 :            :             else
     145                 :            :             {
     146                 :        175 :                 return nIndex;
     147                 :            :             }
     148                 :            :         }
     149                 :            : 
     150                 :      13792 :         B2VectorOrientation getOrientation(const B2DPolygon& rCandidate)
     151                 :            :         {
     152                 :      13792 :             B2VectorOrientation eRetval(ORIENTATION_NEUTRAL);
     153                 :            : 
     154 [ +  + ][ -  + ]:      13792 :             if(rCandidate.count() > 2L || rCandidate.areControlPointsUsed())
                 [ +  + ]
     155                 :            :             {
     156         [ +  - ]:      13687 :                 const double fSignedArea(getSignedArea(rCandidate));
     157                 :            : 
     158                 :      13687 :                 if(fTools::equalZero(fSignedArea))
     159                 :            :                 {
     160                 :            :                     // ORIENTATION_NEUTRAL, already set
     161                 :            :                 }
     162         [ +  + ]:      13687 :                 if(fSignedArea > 0.0)
     163                 :            :                 {
     164                 :       7791 :                     eRetval = ORIENTATION_POSITIVE;
     165                 :            :                 }
     166         [ +  + ]:       5896 :                 else if(fSignedArea < 0.0)
     167                 :            :                 {
     168                 :      13687 :                     eRetval = ORIENTATION_NEGATIVE;
     169                 :            :                 }
     170                 :            :             }
     171                 :            : 
     172                 :      13792 :             return eRetval;
     173                 :            :         }
     174                 :            : 
     175                 :          0 :         B2VectorContinuity getContinuityInPoint(const B2DPolygon& rCandidate, sal_uInt32 nIndex)
     176                 :            :         {
     177                 :          0 :             return rCandidate.getContinuityInPoint(nIndex);
     178                 :            :         }
     179                 :            : 
     180                 :          0 :         B2DPolygon adaptiveSubdivideByDistance(const B2DPolygon& rCandidate, double fDistanceBound)
     181                 :            :         {
     182         [ #  # ]:          0 :             if(rCandidate.areControlPointsUsed())
     183                 :            :             {
     184         [ #  # ]:          0 :                 const sal_uInt32 nPointCount(rCandidate.count());
     185         [ #  # ]:          0 :                 B2DPolygon aRetval;
     186                 :            : 
     187         [ #  # ]:          0 :                 if(nPointCount)
     188                 :            :                 {
     189                 :            :                     // prepare edge-oriented loop
     190 [ #  # ][ #  # ]:          0 :                     const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1);
     191         [ #  # ]:          0 :                     B2DCubicBezier aBezier;
     192         [ #  # ]:          0 :                     aBezier.setStartPoint(rCandidate.getB2DPoint(0));
     193                 :            : 
     194                 :            :                     // perf: try to avoid too many realloctions by guessing the result's pointcount
     195         [ #  # ]:          0 :                     aRetval.reserve(nPointCount*4);
     196                 :            : 
     197                 :            :                     // add start point (always)
     198         [ #  # ]:          0 :                     aRetval.append(aBezier.getStartPoint());
     199                 :            : 
     200         [ #  # ]:          0 :                     for(sal_uInt32 a(0L); a < nEdgeCount; a++)
     201                 :            :                     {
     202                 :            :                         // get next and control points
     203                 :          0 :                         const sal_uInt32 nNextIndex((a + 1) % nPointCount);
     204         [ #  # ]:          0 :                         aBezier.setEndPoint(rCandidate.getB2DPoint(nNextIndex));
     205         [ #  # ]:          0 :                         aBezier.setControlPointA(rCandidate.getNextControlPoint(a));
     206         [ #  # ]:          0 :                         aBezier.setControlPointB(rCandidate.getPrevControlPoint(nNextIndex));
     207         [ #  # ]:          0 :                         aBezier.testAndSolveTrivialBezier();
     208                 :            : 
     209 [ #  # ][ #  # ]:          0 :                         if(aBezier.isBezier())
     210                 :            :                         {
     211                 :            :                             // add curved edge and generate DistanceBound
     212                 :          0 :                             double fBound(0.0);
     213                 :            : 
     214         [ #  # ]:          0 :                             if(0.0 == fDistanceBound)
     215                 :            :                             {
     216                 :            :                                 // If not set, use B2DCubicBezier functionality to guess a rough value
     217 [ #  # ][ #  # ]:          0 :                                 const double fRoughLength((aBezier.getEdgeLength() + aBezier.getControlPolygonLength()) / 2.0);
     218                 :            : 
     219                 :            :                                 // take 1/100th of the rough curve length
     220                 :          0 :                                 fBound = fRoughLength * 0.01;
     221                 :            :                             }
     222                 :            :                             else
     223                 :            :                             {
     224                 :            :                                 // use given bound value
     225                 :          0 :                                 fBound = fDistanceBound;
     226                 :            :                             }
     227                 :            : 
     228                 :            :                             // make sure bound value is not too small. The base units are 1/100th mm, thus
     229                 :            :                             // just make sure it's not smaller then 1/100th of that
     230         [ #  # ]:          0 :                             if(fBound < 0.01)
     231                 :            :                             {
     232                 :          0 :                                 fBound = 0.01;
     233                 :            :                             }
     234                 :            : 
     235                 :            :                             // call adaptive subdivide which adds edges to aRetval accordingly
     236         [ #  # ]:          0 :                             aBezier.adaptiveSubdivideByDistance(aRetval, fBound);
     237                 :            :                         }
     238                 :            :                         else
     239                 :            :                         {
     240                 :            :                             // add non-curved edge
     241         [ #  # ]:          0 :                             aRetval.append(aBezier.getEndPoint());
     242                 :            :                         }
     243                 :            : 
     244                 :            :                         // prepare next step
     245                 :          0 :                         aBezier.setStartPoint(aBezier.getEndPoint());
     246                 :            :                     }
     247                 :            : 
     248 [ #  # ][ #  # ]:          0 :                     if(rCandidate.isClosed())
     249                 :            :                     {
     250                 :            :                         // set closed flag and correct last point (which is added double now).
     251         [ #  # ]:          0 :                         closeWithGeometryChange(aRetval);
     252         [ #  # ]:          0 :                     }
     253                 :            :                 }
     254                 :            : 
     255 [ #  # ][ #  # ]:          0 :                 return aRetval;
     256                 :            :             }
     257                 :            :             else
     258                 :            :             {
     259                 :          0 :                 return rCandidate;
     260                 :            :             }
     261                 :            :         }
     262                 :            : 
     263                 :         25 :         B2DPolygon adaptiveSubdivideByAngle(const B2DPolygon& rCandidate, double fAngleBound)
     264                 :            :         {
     265         [ +  - ]:         25 :             if(rCandidate.areControlPointsUsed())
     266                 :            :             {
     267         [ +  - ]:         25 :                 const sal_uInt32 nPointCount(rCandidate.count());
     268         [ +  - ]:         25 :                 B2DPolygon aRetval;
     269                 :            : 
     270         [ +  - ]:         25 :                 if(nPointCount)
     271                 :            :                 {
     272                 :            :                     // prepare edge-oriented loop
     273 [ +  - ][ +  - ]:         25 :                     const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1);
     274         [ +  - ]:         25 :                     B2DCubicBezier aBezier;
     275         [ +  - ]:         25 :                     aBezier.setStartPoint(rCandidate.getB2DPoint(0));
     276                 :            : 
     277                 :            :                     // perf: try to avoid too many realloctions by guessing the result's pointcount
     278         [ +  - ]:         25 :                     aRetval.reserve(nPointCount*4);
     279                 :            : 
     280                 :            :                     // add start point (always)
     281         [ +  - ]:         25 :                     aRetval.append(aBezier.getStartPoint());
     282                 :            : 
     283                 :            :                     // #i37443# prepare convenient AngleBound if none was given
     284         [ +  - ]:         25 :                     if(0.0 == fAngleBound)
     285                 :            :                     {
     286                 :            : #ifdef DBG_UTIL
     287                 :            :                         fAngleBound = fAngleBoundStartValue;
     288                 :            : #else
     289                 :         25 :                         fAngleBound = ANGLE_BOUND_START_VALUE;
     290                 :            : #endif
     291                 :            :                     }
     292         [ #  # ]:          0 :                     else if(fTools::less(fAngleBound, ANGLE_BOUND_MINIMUM_VALUE))
     293                 :            :                     {
     294                 :          0 :                         fAngleBound = 0.1;
     295                 :            :                     }
     296                 :            : 
     297         [ +  + ]:        150 :                     for(sal_uInt32 a(0L); a < nEdgeCount; a++)
     298                 :            :                     {
     299                 :            :                         // get next and control points
     300                 :        125 :                         const sal_uInt32 nNextIndex((a + 1) % nPointCount);
     301         [ +  - ]:        125 :                         aBezier.setEndPoint(rCandidate.getB2DPoint(nNextIndex));
     302         [ +  - ]:        125 :                         aBezier.setControlPointA(rCandidate.getNextControlPoint(a));
     303         [ +  - ]:        125 :                         aBezier.setControlPointB(rCandidate.getPrevControlPoint(nNextIndex));
     304         [ +  - ]:        125 :                         aBezier.testAndSolveTrivialBezier();
     305                 :            : 
     306 [ +  - ][ +  + ]:        125 :                         if(aBezier.isBezier())
     307                 :            :                         {
     308                 :            :                             // call adaptive subdivide
     309         [ +  - ]:        100 :                             aBezier.adaptiveSubdivideByAngle(aRetval, fAngleBound, true);
     310                 :            :                         }
     311                 :            :                         else
     312                 :            :                         {
     313                 :            :                             // add non-curved edge
     314         [ +  - ]:         25 :                             aRetval.append(aBezier.getEndPoint());
     315                 :            :                         }
     316                 :            : 
     317                 :            :                         // prepare next step
     318                 :        125 :                         aBezier.setStartPoint(aBezier.getEndPoint());
     319                 :            :                     }
     320                 :            : 
     321 [ +  - ][ +  - ]:         25 :                     if(rCandidate.isClosed())
     322                 :            :                     {
     323                 :            :                         // set closed flag and correct last point (which is added double now).
     324         [ +  - ]:         25 :                         closeWithGeometryChange(aRetval);
     325         [ +  - ]:         25 :                     }
     326                 :            :                 }
     327                 :            : 
     328 [ +  - ][ +  - ]:         25 :                 return aRetval;
     329                 :            :             }
     330                 :            :             else
     331                 :            :             {
     332                 :         25 :                 return rCandidate;
     333                 :            :             }
     334                 :            :         }
     335                 :            : 
     336                 :          0 :         B2DPolygon adaptiveSubdivideByCount(const B2DPolygon& rCandidate, sal_uInt32 nCount)
     337                 :            :         {
     338         [ #  # ]:          0 :             if(rCandidate.areControlPointsUsed())
     339                 :            :             {
     340         [ #  # ]:          0 :                 const sal_uInt32 nPointCount(rCandidate.count());
     341         [ #  # ]:          0 :                 B2DPolygon aRetval;
     342                 :            : 
     343         [ #  # ]:          0 :                 if(nPointCount)
     344                 :            :                 {
     345                 :            :                     // prepare edge-oriented loop
     346 [ #  # ][ #  # ]:          0 :                     const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1);
     347         [ #  # ]:          0 :                     B2DCubicBezier aBezier;
     348         [ #  # ]:          0 :                     aBezier.setStartPoint(rCandidate.getB2DPoint(0));
     349                 :            : 
     350                 :            :                     // perf: try to avoid too many realloctions by guessing the result's pointcount
     351         [ #  # ]:          0 :                     aRetval.reserve(nPointCount*4);
     352                 :            : 
     353                 :            :                     // add start point (always)
     354         [ #  # ]:          0 :                     aRetval.append(aBezier.getStartPoint());
     355                 :            : 
     356                 :            :                     // #i37443# prepare convenient count if none was given
     357         [ #  # ]:          0 :                     if(0L == nCount)
     358                 :            :                     {
     359                 :          0 :                         nCount = COUNT_SUBDIVIDE_DEFAULT;
     360                 :            :                     }
     361                 :            : 
     362         [ #  # ]:          0 :                     for(sal_uInt32 a(0L); a < nEdgeCount; a++)
     363                 :            :                     {
     364                 :            :                         // get next and control points
     365                 :          0 :                         const sal_uInt32 nNextIndex((a + 1) % nPointCount);
     366         [ #  # ]:          0 :                         aBezier.setEndPoint(rCandidate.getB2DPoint(nNextIndex));
     367         [ #  # ]:          0 :                         aBezier.setControlPointA(rCandidate.getNextControlPoint(a));
     368         [ #  # ]:          0 :                         aBezier.setControlPointB(rCandidate.getPrevControlPoint(nNextIndex));
     369         [ #  # ]:          0 :                         aBezier.testAndSolveTrivialBezier();
     370                 :            : 
     371 [ #  # ][ #  # ]:          0 :                         if(aBezier.isBezier())
     372                 :            :                         {
     373                 :            :                             // call adaptive subdivide
     374         [ #  # ]:          0 :                             aBezier.adaptiveSubdivideByCount(aRetval, nCount);
     375                 :            :                         }
     376                 :            :                         else
     377                 :            :                         {
     378                 :            :                             // add non-curved edge
     379         [ #  # ]:          0 :                             aRetval.append(aBezier.getEndPoint());
     380                 :            :                         }
     381                 :            : 
     382                 :            :                         // prepare next step
     383                 :          0 :                         aBezier.setStartPoint(aBezier.getEndPoint());
     384                 :            :                     }
     385                 :            : 
     386 [ #  # ][ #  # ]:          0 :                     if(rCandidate.isClosed())
     387                 :            :                     {
     388                 :            :                         // set closed flag and correct last point (which is added double now).
     389         [ #  # ]:          0 :                         closeWithGeometryChange(aRetval);
     390         [ #  # ]:          0 :                     }
     391                 :            :                 }
     392                 :            : 
     393 [ #  # ][ #  # ]:          0 :                 return aRetval;
     394                 :            :             }
     395                 :            :             else
     396                 :            :             {
     397                 :          0 :                 return rCandidate;
     398                 :            :             }
     399                 :            :         }
     400                 :            : 
     401                 :       7116 :         bool isInside(const B2DPolygon& rCandidate, const B2DPoint& rPoint, bool bWithBorder)
     402                 :            :         {
     403 [ +  - ][ -  + ]:       7116 :             const B2DPolygon aCandidate(rCandidate.areControlPointsUsed() ? rCandidate.getDefaultAdaptiveSubdivision() : rCandidate);
         [ #  # ][ +  - ]
     404                 :            : 
     405 [ +  + ][ +  - ]:       7116 :             if(bWithBorder && isPointOnPolygon(aCandidate, rPoint, true))
         [ +  + ][ +  + ]
     406                 :            :             {
     407                 :       3713 :                 return true;
     408                 :            :             }
     409                 :            :             else
     410                 :            :             {
     411                 :       3403 :                 bool bRetval(false);
     412         [ +  - ]:       3403 :                 const sal_uInt32 nPointCount(aCandidate.count());
     413                 :            : 
     414         [ +  - ]:       3403 :                 if(nPointCount)
     415                 :            :                 {
     416         [ +  - ]:       3403 :                     B2DPoint aCurrentPoint(aCandidate.getB2DPoint(nPointCount - 1L));
     417                 :            : 
     418         [ +  + ]:      29201 :                     for(sal_uInt32 a(0L); a < nPointCount; a++)
     419                 :            :                     {
     420                 :      25798 :                         const B2DPoint aPreviousPoint(aCurrentPoint);
     421         [ +  - ]:      25798 :                         aCurrentPoint = aCandidate.getB2DPoint(a);
     422                 :            : 
     423                 :            :                         // cross-over in Y?
     424                 :      25798 :                         const bool bCompYA(fTools::more(aPreviousPoint.getY(), rPoint.getY()));
     425                 :      25798 :                         const bool bCompYB(fTools::more(aCurrentPoint.getY(), rPoint.getY()));
     426                 :            : 
     427         [ +  + ]:      25798 :                         if(bCompYA != bCompYB)
     428                 :            :                         {
     429                 :            :                             // cross-over in X?
     430                 :       6324 :                             const bool bCompXA(fTools::more(aPreviousPoint.getX(), rPoint.getX()));
     431                 :       6324 :                             const bool bCompXB(fTools::more(aCurrentPoint.getX(), rPoint.getX()));
     432                 :            : 
     433         [ +  + ]:       6324 :                             if(bCompXA == bCompXB)
     434                 :            :                             {
     435         [ +  + ]:       6250 :                                 if(bCompXA)
     436                 :            :                                 {
     437                 :       3083 :                                     bRetval = !bRetval;
     438                 :            :                                 }
     439                 :            :                             }
     440                 :            :                             else
     441                 :            :                             {
     442                 :            :                                 const double fCompare(
     443                 :         74 :                                     aCurrentPoint.getX() - (aCurrentPoint.getY() - rPoint.getY()) *
     444                 :         74 :                                     (aPreviousPoint.getX() - aCurrentPoint.getX()) /
     445                 :         74 :                                     (aPreviousPoint.getY() - aCurrentPoint.getY()));
     446                 :            : 
     447         [ +  + ]:         74 :                                 if(fTools::more(fCompare, rPoint.getX()))
     448                 :            :                                 {
     449                 :         74 :                                     bRetval = !bRetval;
     450                 :            :                                 }
     451                 :            :                             }
     452                 :            :                         }
     453                 :      29201 :                     }
     454                 :            :                 }
     455                 :            : 
     456                 :       3403 :                 return bRetval;
     457         [ +  - ]:       7116 :             }
     458                 :            :         }
     459                 :            : 
     460                 :       1475 :         bool isInside(const B2DPolygon& rCandidate, const B2DPolygon& rPolygon, bool bWithBorder)
     461                 :            :         {
     462 [ +  - ][ -  + ]:       1475 :             const B2DPolygon aCandidate(rCandidate.areControlPointsUsed() ? rCandidate.getDefaultAdaptiveSubdivision() : rCandidate);
         [ #  # ][ +  - ]
     463 [ +  - ][ -  + ]:       1475 :             const B2DPolygon aPolygon(rPolygon.areControlPointsUsed() ? rPolygon.getDefaultAdaptiveSubdivision() : rPolygon);
         [ #  # ][ +  - ]
     464         [ +  - ]:       1475 :             const sal_uInt32 nPointCount(aPolygon.count());
     465                 :            : 
     466         [ +  + ]:       7649 :             for(sal_uInt32 a(0L); a < nPointCount; a++)
     467                 :            :             {
     468         [ +  - ]:       6174 :                 const B2DPoint aTestPoint(aPolygon.getB2DPoint(a));
     469                 :            : 
     470 [ +  - ][ +  + ]:       6174 :                 if(!isInside(aCandidate, aTestPoint, bWithBorder))
     471                 :            :                 {
     472                 :       6174 :                     return false;
     473                 :            :                 }
     474         [ +  + ]:       6174 :             }
     475                 :            : 
     476 [ +  - ][ +  - ]:       1475 :             return true;
     477                 :            :         }
     478                 :            : 
     479                 :    4365804 :         B2DRange getRange(const B2DPolygon& rCandidate)
     480                 :            :         {
     481                 :            :             // changed to use internally buffered version at B2DPolygon
     482                 :    4365804 :             return rCandidate.getB2DRange();
     483                 :            :         }
     484                 :            : 
     485                 :      13687 :         double getSignedArea(const B2DPolygon& rCandidate)
     486                 :            :         {
     487 [ +  - ][ -  + ]:      13687 :             const B2DPolygon aCandidate(rCandidate.areControlPointsUsed() ? rCandidate.getDefaultAdaptiveSubdivision() : rCandidate);
         [ #  # ][ +  - ]
     488                 :      13687 :             double fRetval(0.0);
     489         [ +  - ]:      13687 :             const sal_uInt32 nPointCount(aCandidate.count());
     490                 :            : 
     491         [ +  - ]:      13687 :             if(nPointCount > 2)
     492                 :            :             {
     493         [ +  + ]:      86438 :                 for(sal_uInt32 a(0L); a < nPointCount; a++)
     494                 :            :                 {
     495 [ +  + ][ +  - ]:      72751 :                     const B2DPoint aPreviousPoint(aCandidate.getB2DPoint((!a) ? nPointCount - 1L : a - 1L));
     496         [ +  - ]:      72751 :                     const B2DPoint aCurrentPoint(aCandidate.getB2DPoint(a));
     497                 :            : 
     498                 :      72751 :                     fRetval += aPreviousPoint.getX() * aCurrentPoint.getY();
     499                 :      72751 :                     fRetval -= aPreviousPoint.getY() * aCurrentPoint.getX();
     500                 :      72751 :                 }
     501                 :            : 
     502                 :      13687 :                 fRetval /= 2.0;
     503                 :            : 
     504                 :            :                 // correct to zero if small enough. Also test the quadratic
     505                 :            :                 // of the result since the precision is near quadratic due to
     506                 :            :                 // the algorithm
     507 [ +  + ][ -  + ]:      13687 :                 if(fTools::equalZero(fRetval) || fTools::equalZero(fRetval * fRetval))
         [ +  + ][ +  + ]
     508                 :            :                 {
     509                 :         29 :                     fRetval = 0.0;
     510                 :            :                 }
     511                 :            :             }
     512                 :            : 
     513         [ +  - ]:      13687 :             return fRetval;
     514                 :            :         }
     515                 :            : 
     516                 :          0 :         double getArea(const B2DPolygon& rCandidate)
     517                 :            :         {
     518                 :          0 :             double fRetval(0.0);
     519                 :            : 
     520 [ #  # ][ #  # ]:          0 :             if(rCandidate.count() > 2 || rCandidate.areControlPointsUsed())
         [ #  # ][ #  # ]
                 [ #  # ]
     521                 :            :             {
     522         [ #  # ]:          0 :                 fRetval = getSignedArea(rCandidate);
     523                 :          0 :                 const double fZero(0.0);
     524                 :            : 
     525         [ #  # ]:          0 :                 if(fTools::less(fRetval, fZero))
     526                 :            :                 {
     527                 :          0 :                     fRetval = -fRetval;
     528                 :            :                 }
     529                 :            :             }
     530                 :            : 
     531                 :          0 :             return fRetval;
     532                 :            :         }
     533                 :            : 
     534                 :         30 :         double getEdgeLength(const B2DPolygon& rCandidate, sal_uInt32 nIndex)
     535                 :            :         {
     536                 :         30 :             const sal_uInt32 nPointCount(rCandidate.count());
     537                 :            :             OSL_ENSURE(nIndex < nPointCount, "getEdgeLength: Access to polygon out of range (!)");
     538                 :         30 :             double fRetval(0.0);
     539                 :            : 
     540         [ +  - ]:         30 :             if(nPointCount)
     541                 :            :             {
     542                 :         30 :                 const sal_uInt32 nNextIndex((nIndex + 1) % nPointCount);
     543                 :            : 
     544         [ -  + ]:         30 :                 if(rCandidate.areControlPointsUsed())
     545                 :            :                 {
     546         [ #  # ]:          0 :                     B2DCubicBezier aEdge;
     547                 :            : 
     548         [ #  # ]:          0 :                     aEdge.setStartPoint(rCandidate.getB2DPoint(nIndex));
     549         [ #  # ]:          0 :                     aEdge.setControlPointA(rCandidate.getNextControlPoint(nIndex));
     550         [ #  # ]:          0 :                     aEdge.setControlPointB(rCandidate.getPrevControlPoint(nNextIndex));
     551         [ #  # ]:          0 :                     aEdge.setEndPoint(rCandidate.getB2DPoint(nNextIndex));
     552                 :            : 
     553 [ #  # ][ #  # ]:          0 :                     fRetval = aEdge.getLength();
     554                 :            :                 }
     555                 :            :                 else
     556                 :            :                 {
     557         [ +  - ]:         30 :                     const B2DPoint aCurrent(rCandidate.getB2DPoint(nIndex));
     558         [ +  - ]:         30 :                     const B2DPoint aNext(rCandidate.getB2DPoint(nNextIndex));
     559                 :            : 
     560         [ +  - ]:         30 :                     fRetval = B2DVector(aNext - aCurrent).getLength();
     561                 :            :                 }
     562                 :            :             }
     563                 :            : 
     564                 :         30 :             return fRetval;
     565                 :            :         }
     566                 :            : 
     567                 :         15 :         double getLength(const B2DPolygon& rCandidate)
     568                 :            :         {
     569                 :         15 :             double fRetval(0.0);
     570                 :         15 :             const sal_uInt32 nPointCount(rCandidate.count());
     571                 :            : 
     572         [ +  - ]:         15 :             if(nPointCount)
     573                 :            :             {
     574         [ -  + ]:         15 :                 const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1L);
     575                 :            : 
     576         [ -  + ]:         15 :                 if(rCandidate.areControlPointsUsed())
     577                 :            :                 {
     578         [ #  # ]:          0 :                     B2DCubicBezier aEdge;
     579         [ #  # ]:          0 :                     aEdge.setStartPoint(rCandidate.getB2DPoint(0));
     580                 :            : 
     581         [ #  # ]:          0 :                     for(sal_uInt32 a(0); a < nEdgeCount; a++)
     582                 :            :                     {
     583                 :          0 :                         const sal_uInt32 nNextIndex((a + 1) % nPointCount);
     584         [ #  # ]:          0 :                         aEdge.setControlPointA(rCandidate.getNextControlPoint(a));
     585         [ #  # ]:          0 :                         aEdge.setControlPointB(rCandidate.getPrevControlPoint(nNextIndex));
     586         [ #  # ]:          0 :                         aEdge.setEndPoint(rCandidate.getB2DPoint(nNextIndex));
     587                 :            : 
     588         [ #  # ]:          0 :                         fRetval += aEdge.getLength();
     589                 :          0 :                         aEdge.setStartPoint(aEdge.getEndPoint());
     590         [ #  # ]:          0 :                     }
     591                 :            :                 }
     592                 :            :                 else
     593                 :            :                 {
     594         [ +  - ]:         15 :                     B2DPoint aCurrent(rCandidate.getB2DPoint(0));
     595                 :            : 
     596         [ +  + ]:         35 :                     for(sal_uInt32 a(0); a < nEdgeCount; a++)
     597                 :            :                     {
     598                 :         20 :                         const sal_uInt32 nNextIndex((a + 1) % nPointCount);
     599         [ +  - ]:         20 :                         const B2DPoint aNext(rCandidate.getB2DPoint(nNextIndex));
     600                 :            : 
     601         [ +  - ]:         20 :                         fRetval += B2DVector(aNext - aCurrent).getLength();
     602                 :         20 :                         aCurrent = aNext;
     603                 :         35 :                     }
     604                 :            :                 }
     605                 :            :             }
     606                 :            : 
     607                 :         15 :             return fRetval;
     608                 :            :         }
     609                 :            : 
     610                 :         15 :         B2DPoint getPositionAbsolute(const B2DPolygon& rCandidate, double fDistance, double fLength)
     611                 :            :         {
     612                 :         15 :             B2DPoint aRetval;
     613         [ +  - ]:         15 :             const sal_uInt32 nPointCount(rCandidate.count());
     614                 :            : 
     615         [ -  + ]:         15 :             if( 1L == nPointCount )
     616                 :            :             {
     617                 :            :                 // only one point (i.e. no edge) - simply take that point
     618         [ #  # ]:          0 :                 aRetval = rCandidate.getB2DPoint(0);
     619                 :            :             }
     620         [ +  - ]:         15 :             else if(nPointCount > 1L)
     621                 :            :             {
     622 [ +  - ][ -  + ]:         15 :                 const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1);
     623                 :         15 :                 sal_uInt32 nIndex(0L);
     624                 :         15 :                 bool bIndexDone(false);
     625                 :            : 
     626                 :            :                 // get length if not given
     627         [ -  + ]:         15 :                 if(fTools::equalZero(fLength))
     628                 :            :                 {
     629         [ #  # ]:          0 :                     fLength = getLength(rCandidate);
     630                 :            :                 }
     631                 :            : 
     632         [ -  + ]:         15 :                 if(fTools::less(fDistance, 0.0))
     633                 :            :                 {
     634                 :            :                     // handle fDistance < 0.0
     635 [ #  # ][ #  # ]:          0 :                     if(rCandidate.isClosed())
     636                 :            :                     {
     637                 :            :                         // if fDistance < 0.0 increment with multiple of fLength
     638                 :          0 :                         sal_uInt32 nCount(sal_uInt32(-fDistance / fLength));
     639                 :          0 :                         fDistance += double(nCount + 1L) * fLength;
     640                 :            :                     }
     641                 :            :                     else
     642                 :            :                     {
     643                 :            :                         // crop to polygon start
     644                 :          0 :                         fDistance = 0.0;
     645                 :          0 :                         bIndexDone = true;
     646                 :            :                     }
     647                 :            :                 }
     648         [ -  + ]:         15 :                 else if(fTools::moreOrEqual(fDistance, fLength))
     649                 :            :                 {
     650                 :            :                     // handle fDistance >= fLength
     651 [ #  # ][ #  # ]:          0 :                     if(rCandidate.isClosed())
     652                 :            :                     {
     653                 :            :                         // if fDistance >= fLength decrement with multiple of fLength
     654                 :          0 :                         sal_uInt32 nCount(sal_uInt32(fDistance / fLength));
     655                 :          0 :                         fDistance -= (double)(nCount) * fLength;
     656                 :            :                     }
     657                 :            :                     else
     658                 :            :                     {
     659                 :            :                         // crop to polygon end
     660                 :          0 :                         fDistance = 0.0;
     661                 :          0 :                         nIndex = nEdgeCount;
     662                 :          0 :                         bIndexDone = true;
     663                 :            :                     }
     664                 :            :                 }
     665                 :            : 
     666                 :            :                 // look for correct index. fDistance is now [0.0 .. fLength[
     667         [ +  - ]:         15 :                 double fEdgeLength(getEdgeLength(rCandidate, nIndex));
     668                 :            : 
     669         [ +  + ]:         30 :                 while(!bIndexDone)
     670                 :            :                 {
     671                 :            :                     // edge found must be on the half-open range
     672                 :            :                     // [0,fEdgeLength).
     673                 :            :                     // Note that in theory, we cannot move beyond
     674                 :            :                     // the last polygon point, since fDistance>=fLength
     675                 :            :                     // is checked above. Unfortunately, with floating-
     676                 :            :                     // point calculations, this case might happen.
     677                 :            :                     // Handled by nIndex check below
     678 [ +  - ][ -  + ]:         15 :                     if(nIndex < nEdgeCount && fTools::moreOrEqual(fDistance, fEdgeLength))
                 [ -  + ]
     679                 :            :                     {
     680                 :            :                         // go to next edge
     681                 :          0 :                         fDistance -= fEdgeLength;
     682         [ #  # ]:          0 :                         fEdgeLength = getEdgeLength(rCandidate, ++nIndex);
     683                 :            :                     }
     684                 :            :                     else
     685                 :            :                     {
     686                 :            :                         // it's on this edge, stop
     687                 :         15 :                         bIndexDone = true;
     688                 :            :                     }
     689                 :            :                 }
     690                 :            : 
     691                 :            :                 // get the point using nIndex
     692         [ +  - ]:         15 :                 aRetval = rCandidate.getB2DPoint(nIndex);
     693                 :            : 
     694                 :            :                 // if fDistance != 0.0, move that length on the edge. The edge
     695                 :            :                 // length is in fEdgeLength.
     696         [ +  - ]:         15 :                 if(!fTools::equalZero(fDistance))
     697                 :            :                 {
     698         [ -  + ]:         15 :                     if(fTools::moreOrEqual(fDistance, fEdgeLength))
     699                 :            :                     {
     700                 :            :                         // end point of choosen edge
     701                 :          0 :                         const sal_uInt32 nNextIndex((nIndex + 1) % nPointCount);
     702         [ #  # ]:          0 :                         aRetval = rCandidate.getB2DPoint(nNextIndex);
     703                 :            :                     }
     704         [ -  + ]:         15 :                     else if(fTools::equalZero(fDistance))
     705                 :            :                     {
     706                 :            :                         // start point of choosen edge
     707                 :          0 :                         aRetval = aRetval;
     708                 :            :                     }
     709                 :            :                     else
     710                 :            :                     {
     711                 :            :                         // inside edge
     712                 :         15 :                         const sal_uInt32 nNextIndex((nIndex + 1) % nPointCount);
     713         [ +  - ]:         15 :                         const B2DPoint aNextPoint(rCandidate.getB2DPoint(nNextIndex));
     714                 :         15 :                         bool bDone(false);
     715                 :            : 
     716                 :            :                         // add calculated average value to the return value
     717 [ +  - ][ -  + ]:         15 :                         if(rCandidate.areControlPointsUsed())
     718                 :            :                         {
     719                 :            :                             // get as bezier segment
     720                 :            :                             const B2DCubicBezier aBezierSegment(
     721                 :            :                                 aRetval, rCandidate.getNextControlPoint(nIndex),
     722 [ #  # ][ #  # ]:          0 :                                 rCandidate.getPrevControlPoint(nNextIndex), aNextPoint);
                 [ #  # ]
     723                 :            : 
     724 [ #  # ][ #  # ]:          0 :                             if(aBezierSegment.isBezier())
     725                 :            :                             {
     726                 :            :                                 // use B2DCubicBezierHelper to bridge the non-linear gap between
     727                 :            :                                 // length and bezier distances
     728         [ #  # ]:          0 :                                 const B2DCubicBezierHelper aBezierSegmentHelper(aBezierSegment);
     729         [ #  # ]:          0 :                                 const double fBezierDistance(aBezierSegmentHelper.distanceToRelative(fDistance));
     730                 :            : 
     731         [ #  # ]:          0 :                                 aRetval = aBezierSegment.interpolatePoint(fBezierDistance);
     732                 :          0 :                                 bDone = true;
     733         [ #  # ]:          0 :                             }
     734                 :            :                         }
     735                 :            : 
     736         [ +  - ]:         15 :                         if(!bDone)
     737                 :            :                         {
     738                 :         15 :                             const double fRelativeInEdge(fDistance / fEdgeLength);
     739         [ +  - ]:         15 :                             aRetval = interpolate(aRetval, aNextPoint, fRelativeInEdge);
     740                 :         15 :                         }
     741                 :            :                     }
     742                 :            :                 }
     743                 :            :             }
     744                 :            : 
     745                 :         15 :             return aRetval;
     746                 :            :         }
     747                 :            : 
     748                 :          0 :         B2DPoint getPositionRelative(const B2DPolygon& rCandidate, double fDistance, double fLength)
     749                 :            :         {
     750                 :            :             // get length if not given
     751         [ #  # ]:          0 :             if(fTools::equalZero(fLength))
     752                 :            :             {
     753                 :          0 :                 fLength = getLength(rCandidate);
     754                 :            :             }
     755                 :            : 
     756                 :            :             // multiply fDistance with real length to get absolute position and
     757                 :            :             // use getPositionAbsolute
     758                 :          0 :             return getPositionAbsolute(rCandidate, fDistance * fLength, fLength);
     759                 :            :         }
     760                 :            : 
     761                 :         10 :         B2DPolygon getSnippetAbsolute(const B2DPolygon& rCandidate, double fFrom, double fTo, double fLength)
     762                 :            :         {
     763                 :         10 :             const sal_uInt32 nPointCount(rCandidate.count());
     764                 :            : 
     765         [ +  - ]:         10 :             if(nPointCount)
     766                 :            :             {
     767                 :            :                 // get length if not given
     768         [ -  + ]:         10 :                 if(fTools::equalZero(fLength))
     769                 :            :                 {
     770                 :          0 :                     fLength = getLength(rCandidate);
     771                 :            :                 }
     772                 :            : 
     773                 :            :                 // test and correct fFrom
     774         [ -  + ]:         10 :                 if(fTools::less(fFrom, 0.0))
     775                 :            :                 {
     776                 :          0 :                     fFrom = 0.0;
     777                 :            :                 }
     778                 :            : 
     779                 :            :                 // test and correct fTo
     780         [ -  + ]:         10 :                 if(fTools::more(fTo, fLength))
     781                 :            :                 {
     782                 :          0 :                     fTo = fLength;
     783                 :            :                 }
     784                 :            : 
     785                 :            :                 // test and correct relationship of fFrom, fTo
     786         [ -  + ]:         10 :                 if(fTools::more(fFrom, fTo))
     787                 :            :                 {
     788                 :          0 :                     fFrom = fTo = (fFrom + fTo) / 2.0;
     789                 :            :                 }
     790                 :            : 
     791 [ +  + ][ -  + ]:         10 :                 if(fTools::equalZero(fFrom) && fTools::equal(fTo, fLength))
                 [ -  + ]
     792                 :            :                 {
     793                 :            :                     // no change, result is the whole polygon
     794                 :          0 :                     return rCandidate;
     795                 :            :                 }
     796                 :            :                 else
     797                 :            :                 {
     798         [ +  - ]:         10 :                     B2DPolygon aRetval;
     799 [ +  - ][ -  + ]:         10 :                     const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1);
     800                 :         10 :                     double fPositionOfStart(0.0);
     801                 :         10 :                     bool bStartDone(false);
     802                 :         10 :                     bool bEndDone(false);
     803                 :            : 
     804 [ +  + ][ +  + ]:         25 :                     for(sal_uInt32 a(0L); !(bStartDone && bEndDone) && a < nEdgeCount; a++)
         [ +  + ][ +  + ]
     805                 :            :                     {
     806         [ +  - ]:         15 :                         const double fEdgeLength(getEdgeLength(rCandidate, a));
     807                 :            : 
     808         [ +  + ]:         15 :                         if(!bStartDone)
     809                 :            :                         {
     810         [ +  + ]:         10 :                             if(fTools::equalZero(fFrom))
     811                 :            :                             {
     812 [ +  - ][ +  - ]:          5 :                                 aRetval.append(rCandidate.getB2DPoint(a));
     813                 :            : 
     814 [ -  + ][ +  - ]:          5 :                                 if(rCandidate.areControlPointsUsed())
     815                 :            :                                 {
     816 [ #  # ][ #  # ]:          0 :                                     aRetval.setNextControlPoint(aRetval.count() - 1, rCandidate.getNextControlPoint(a));
                 [ #  # ]
     817                 :            :                                 }
     818                 :            : 
     819                 :          5 :                                 bStartDone = true;
     820                 :            :                             }
     821 [ +  - ][ +  - ]:          5 :                             else if(fTools::moreOrEqual(fFrom, fPositionOfStart) && fTools::less(fFrom, fPositionOfStart + fEdgeLength))
         [ +  - ][ +  - ]
     822                 :            :                             {
     823                 :            :                                 // calculate and add start point
     824         [ -  + ]:          5 :                                 if(fTools::equalZero(fEdgeLength))
     825                 :            :                                 {
     826 [ #  # ][ #  # ]:          0 :                                     aRetval.append(rCandidate.getB2DPoint(a));
     827                 :            : 
     828 [ #  # ][ #  # ]:          0 :                                     if(rCandidate.areControlPointsUsed())
     829                 :            :                                     {
     830 [ #  # ][ #  # ]:          0 :                                         aRetval.setNextControlPoint(aRetval.count() - 1, rCandidate.getNextControlPoint(a));
                 [ #  # ]
     831                 :            :                                     }
     832                 :            :                                 }
     833                 :            :                                 else
     834                 :            :                                 {
     835                 :          5 :                                     const sal_uInt32 nNextIndex((a + 1) % nPointCount);
     836         [ +  - ]:          5 :                                     const B2DPoint aStart(rCandidate.getB2DPoint(a));
     837         [ +  - ]:          5 :                                     const B2DPoint aEnd(rCandidate.getB2DPoint(nNextIndex));
     838                 :          5 :                                     bool bDone(false);
     839                 :            : 
     840 [ +  - ][ -  + ]:          5 :                                     if(rCandidate.areControlPointsUsed())
     841                 :            :                                     {
     842                 :            :                                         const B2DCubicBezier aBezierSegment(
     843                 :            :                                             aStart, rCandidate.getNextControlPoint(a),
     844 [ #  # ][ #  # ]:          0 :                                             rCandidate.getPrevControlPoint(nNextIndex), aEnd);
                 [ #  # ]
     845                 :            : 
     846 [ #  # ][ #  # ]:          0 :                                         if(aBezierSegment.isBezier())
     847                 :            :                                         {
     848                 :            :                                             // use B2DCubicBezierHelper to bridge the non-linear gap between
     849                 :            :                                             // length and bezier distances
     850         [ #  # ]:          0 :                                             const B2DCubicBezierHelper aBezierSegmentHelper(aBezierSegment);
     851         [ #  # ]:          0 :                                             const double fBezierDistance(aBezierSegmentHelper.distanceToRelative(fFrom - fPositionOfStart));
     852         [ #  # ]:          0 :                                             B2DCubicBezier aRight;
     853                 :            : 
     854         [ #  # ]:          0 :                                             aBezierSegment.split(fBezierDistance, 0, &aRight);
     855         [ #  # ]:          0 :                                             aRetval.append(aRight.getStartPoint());
     856 [ #  # ][ #  # ]:          0 :                                             aRetval.setNextControlPoint(aRetval.count() - 1, aRight.getControlPointA());
     857         [ #  # ]:          0 :                                             bDone = true;
     858         [ #  # ]:          0 :                                         }
     859                 :            :                                     }
     860                 :            : 
     861         [ +  - ]:          5 :                                     if(!bDone)
     862                 :            :                                     {
     863                 :          5 :                                         const double fRelValue((fFrom - fPositionOfStart) / fEdgeLength);
     864         [ +  - ]:          5 :                                         aRetval.append(interpolate(aStart, aEnd, fRelValue));
     865                 :          5 :                                     }
     866                 :            :                                 }
     867                 :            : 
     868                 :          5 :                                 bStartDone = true;
     869                 :            : 
     870                 :            :                                 // if same point, end is done, too.
     871         [ -  + ]:          5 :                                 if(fFrom == fTo)
     872                 :            :                                 {
     873                 :          0 :                                     bEndDone = true;
     874                 :            :                                 }
     875                 :            :                             }
     876                 :            :                         }
     877                 :            : 
     878 [ +  - ][ +  - ]:         15 :                         if(!bEndDone && fTools::moreOrEqual(fTo, fPositionOfStart) && fTools::less(fTo, fPositionOfStart + fEdgeLength))
         [ +  + ][ +  - ]
                 [ +  + ]
     879                 :            :                         {
     880                 :            :                             // calculate and add end point
     881         [ -  + ]:          5 :                             if(fTools::equalZero(fEdgeLength))
     882                 :            :                             {
     883                 :          0 :                                 const sal_uInt32 nNextIndex((a + 1) % nPointCount);
     884 [ #  # ][ #  # ]:          0 :                                 aRetval.append(rCandidate.getB2DPoint(nNextIndex));
     885                 :            : 
     886 [ #  # ][ #  # ]:          0 :                                 if(rCandidate.areControlPointsUsed())
     887                 :            :                                 {
     888 [ #  # ][ #  # ]:          0 :                                     aRetval.setPrevControlPoint(aRetval.count() - 1, rCandidate.getPrevControlPoint(nNextIndex));
                 [ #  # ]
     889                 :            :                                 }
     890                 :            :                             }
     891                 :            :                             else
     892                 :            :                             {
     893                 :          5 :                                 const sal_uInt32 nNextIndex((a + 1) % nPointCount);
     894         [ +  - ]:          5 :                                 const B2DPoint aStart(rCandidate.getB2DPoint(a));
     895         [ +  - ]:          5 :                                 const B2DPoint aEnd(rCandidate.getB2DPoint(nNextIndex));
     896                 :          5 :                                 bool bDone(false);
     897                 :            : 
     898 [ +  - ][ -  + ]:          5 :                                 if(rCandidate.areControlPointsUsed())
     899                 :            :                                 {
     900                 :            :                                     const B2DCubicBezier aBezierSegment(
     901                 :            :                                         aStart, rCandidate.getNextControlPoint(a),
     902 [ #  # ][ #  # ]:          0 :                                         rCandidate.getPrevControlPoint(nNextIndex), aEnd);
                 [ #  # ]
     903                 :            : 
     904 [ #  # ][ #  # ]:          0 :                                     if(aBezierSegment.isBezier())
     905                 :            :                                     {
     906                 :            :                                         // use B2DCubicBezierHelper to bridge the non-linear gap between
     907                 :            :                                         // length and bezier distances
     908         [ #  # ]:          0 :                                         const B2DCubicBezierHelper aBezierSegmentHelper(aBezierSegment);
     909         [ #  # ]:          0 :                                         const double fBezierDistance(aBezierSegmentHelper.distanceToRelative(fTo - fPositionOfStart));
     910         [ #  # ]:          0 :                                         B2DCubicBezier aLeft;
     911                 :            : 
     912         [ #  # ]:          0 :                                         aBezierSegment.split(fBezierDistance, &aLeft, 0);
     913         [ #  # ]:          0 :                                         aRetval.append(aLeft.getEndPoint());
     914 [ #  # ][ #  # ]:          0 :                                         aRetval.setPrevControlPoint(aRetval.count() - 1, aLeft.getControlPointB());
     915         [ #  # ]:          0 :                                         bDone = true;
     916         [ #  # ]:          0 :                                     }
     917                 :            :                                 }
     918                 :            : 
     919         [ +  - ]:          5 :                                 if(!bDone)
     920                 :            :                                 {
     921                 :          5 :                                     const double fRelValue((fTo - fPositionOfStart) / fEdgeLength);
     922         [ +  - ]:          5 :                                     aRetval.append(interpolate(aStart, aEnd, fRelValue));
     923                 :          5 :                                 }
     924                 :            :                             }
     925                 :            : 
     926                 :          5 :                             bEndDone = true;
     927                 :            :                         }
     928                 :            : 
     929         [ +  + ]:         15 :                         if(!bEndDone)
     930                 :            :                         {
     931         [ +  - ]:         10 :                             if(bStartDone)
     932                 :            :                             {
     933                 :            :                                 // add segments end point
     934                 :         10 :                                 const sal_uInt32 nNextIndex((a + 1) % nPointCount);
     935 [ +  - ][ +  - ]:         10 :                                 aRetval.append(rCandidate.getB2DPoint(nNextIndex));
     936                 :            : 
     937 [ -  + ][ +  - ]:         10 :                                 if(rCandidate.areControlPointsUsed())
     938                 :            :                                 {
     939 [ #  # ][ #  # ]:          0 :                                     aRetval.setPrevControlPoint(aRetval.count() - 1, rCandidate.getPrevControlPoint(nNextIndex));
                 [ #  # ]
     940 [ #  # ][ #  # ]:          0 :                                     aRetval.setNextControlPoint(aRetval.count() - 1, rCandidate.getNextControlPoint(nNextIndex));
                 [ #  # ]
     941                 :            :                                 }
     942                 :            :                             }
     943                 :            : 
     944                 :            :                             // increment fPositionOfStart
     945                 :         10 :                             fPositionOfStart += fEdgeLength;
     946                 :            :                         }
     947                 :            :                     }
     948 [ +  - ][ +  - ]:         10 :                     return aRetval;
     949                 :            :                 }
     950                 :            :             }
     951                 :            :             else
     952                 :            :             {
     953                 :         10 :                 return rCandidate;
     954                 :            :             }
     955                 :            :         }
     956                 :            : 
     957                 :      39008 :         CutFlagValue findCut(
     958                 :            :             const B2DPoint& rEdge1Start, const B2DVector& rEdge1Delta,
     959                 :            :             const B2DPoint& rEdge2Start, const B2DVector& rEdge2Delta,
     960                 :            :             CutFlagValue aCutFlags,
     961                 :            :             double* pCut1, double* pCut2)
     962                 :            :         {
     963                 :      39008 :             CutFlagValue aRetval(CUTFLAG_NONE);
     964                 :      39008 :             double fCut1(0.0);
     965                 :      39008 :             double fCut2(0.0);
     966                 :      39008 :             bool bFinished(!((bool)(aCutFlags & CUTFLAG_ALL)));
     967                 :            : 
     968                 :            :             // test for same points?
     969 [ +  - ][ +  - ]:      39008 :             if(!bFinished
                 [ +  - ]
     970                 :            :                 && (aCutFlags & (CUTFLAG_START1|CUTFLAG_END1))
     971                 :            :                 && (aCutFlags & (CUTFLAG_START2|CUTFLAG_END2)))
     972                 :            :             {
     973                 :            :                 // same startpoint?
     974 [ +  - ][ +  - ]:      39008 :                 if(!bFinished && (aCutFlags & (CUTFLAG_START1|CUTFLAG_START2)) == (CUTFLAG_START1|CUTFLAG_START2))
     975                 :            :                 {
     976         [ -  + ]:      39008 :                     if(rEdge1Start.equal(rEdge2Start))
     977                 :            :                     {
     978                 :          0 :                         bFinished = true;
     979                 :          0 :                         aRetval = (CUTFLAG_START1|CUTFLAG_START2);
     980                 :            :                     }
     981                 :            :                 }
     982                 :            : 
     983                 :            :                 // same endpoint?
     984 [ +  - ][ +  - ]:      39008 :                 if(!bFinished && (aCutFlags & (CUTFLAG_END1|CUTFLAG_END2)) == (CUTFLAG_END1|CUTFLAG_END2))
     985                 :            :                 {
     986                 :      39008 :                     const B2DPoint aEnd1(rEdge1Start + rEdge1Delta);
     987                 :      39008 :                     const B2DPoint aEnd2(rEdge2Start + rEdge2Delta);
     988                 :            : 
     989         [ -  + ]:      39008 :                     if(aEnd1.equal(aEnd2))
     990                 :            :                     {
     991                 :          0 :                         bFinished = true;
     992                 :          0 :                         aRetval = (CUTFLAG_END1|CUTFLAG_END2);
     993                 :          0 :                         fCut1 = fCut2 = 1.0;
     994                 :      39008 :                     }
     995                 :            :                 }
     996                 :            : 
     997                 :            :                 // startpoint1 == endpoint2?
     998 [ +  - ][ +  - ]:      39008 :                 if(!bFinished && (aCutFlags & (CUTFLAG_START1|CUTFLAG_END2)) == (CUTFLAG_START1|CUTFLAG_END2))
     999                 :            :                 {
    1000                 :      39008 :                     const B2DPoint aEnd2(rEdge2Start + rEdge2Delta);
    1001                 :            : 
    1002         [ -  + ]:      39008 :                     if(rEdge1Start.equal(aEnd2))
    1003                 :            :                     {
    1004                 :          0 :                         bFinished = true;
    1005                 :          0 :                         aRetval = (CUTFLAG_START1|CUTFLAG_END2);
    1006                 :          0 :                         fCut1 = 0.0;
    1007                 :          0 :                         fCut2 = 1.0;
    1008                 :      39008 :                     }
    1009                 :            :                 }
    1010                 :            : 
    1011                 :            :                 // startpoint2 == endpoint1?
    1012 [ +  - ][ +  - ]:      39008 :                 if(!bFinished&& (aCutFlags & (CUTFLAG_START2|CUTFLAG_END1)) == (CUTFLAG_START2|CUTFLAG_END1))
    1013                 :            :                 {
    1014                 :      39008 :                     const B2DPoint aEnd1(rEdge1Start + rEdge1Delta);
    1015                 :            : 
    1016         [ -  + ]:      39008 :                     if(rEdge2Start.equal(aEnd1))
    1017                 :            :                     {
    1018                 :          0 :                         bFinished = true;
    1019                 :          0 :                         aRetval = (CUTFLAG_START2|CUTFLAG_END1);
    1020                 :          0 :                         fCut1 = 1.0;
    1021                 :          0 :                         fCut2 = 0.0;
    1022                 :      39008 :                     }
    1023                 :            :                 }
    1024                 :            :             }
    1025                 :            : 
    1026 [ +  - ][ +  - ]:      39008 :             if(!bFinished && (aCutFlags & CUTFLAG_LINE))
    1027                 :            :             {
    1028 [ +  - ][ +  - ]:      39008 :                 if(!bFinished && (aCutFlags & CUTFLAG_START1))
    1029                 :            :                 {
    1030                 :            :                     // start1 on line 2 ?
    1031 [ +  - ][ +  + ]:      39008 :                     if(isPointOnEdge(rEdge1Start, rEdge2Start, rEdge2Delta, &fCut2))
    1032                 :            :                     {
    1033                 :        296 :                         bFinished = true;
    1034                 :        296 :                         aRetval = (CUTFLAG_LINE|CUTFLAG_START1);
    1035                 :            :                     }
    1036                 :            :                 }
    1037                 :            : 
    1038 [ +  + ][ +  - ]:      39008 :                 if(!bFinished && (aCutFlags & CUTFLAG_START2))
    1039                 :            :                 {
    1040                 :            :                     // start2 on line 1 ?
    1041 [ +  - ][ -  + ]:      38712 :                     if(isPointOnEdge(rEdge2Start, rEdge1Start, rEdge1Delta, &fCut1))
    1042                 :            :                     {
    1043                 :          0 :                         bFinished = true;
    1044                 :          0 :                         aRetval = (CUTFLAG_LINE|CUTFLAG_START2);
    1045                 :            :                     }
    1046                 :            :                 }
    1047                 :            : 
    1048 [ +  + ][ +  - ]:      39008 :                 if(!bFinished && (aCutFlags & CUTFLAG_END1))
    1049                 :            :                 {
    1050                 :            :                     // end1 on line 2 ?
    1051                 :      38712 :                     const B2DPoint aEnd1(rEdge1Start + rEdge1Delta);
    1052                 :            : 
    1053 [ -  + ][ +  - ]:      38712 :                     if(isPointOnEdge(aEnd1, rEdge2Start, rEdge2Delta, &fCut2))
    1054                 :            :                     {
    1055                 :          0 :                         bFinished = true;
    1056                 :          0 :                         aRetval = (CUTFLAG_LINE|CUTFLAG_END1);
    1057                 :      38712 :                     }
    1058                 :            :                 }
    1059                 :            : 
    1060 [ +  + ][ +  - ]:      39008 :                 if(!bFinished && (aCutFlags & CUTFLAG_END2))
    1061                 :            :                 {
    1062                 :            :                     // end2 on line 1 ?
    1063                 :      38712 :                     const B2DPoint aEnd2(rEdge2Start + rEdge2Delta);
    1064                 :            : 
    1065 [ -  + ][ +  - ]:      38712 :                     if(isPointOnEdge(aEnd2, rEdge1Start, rEdge1Delta, &fCut1))
    1066                 :            :                     {
    1067                 :          0 :                         bFinished = true;
    1068                 :          0 :                         aRetval = (CUTFLAG_LINE|CUTFLAG_END2);
    1069                 :      38712 :                     }
    1070                 :            :                 }
    1071                 :            : 
    1072         [ +  + ]:      39008 :                 if(!bFinished)
    1073                 :            :                 {
    1074                 :            :                     // cut in line1, line2 ?
    1075                 :      38712 :                     fCut1 = (rEdge1Delta.getX() * rEdge2Delta.getY()) - (rEdge1Delta.getY() * rEdge2Delta.getX());
    1076                 :            : 
    1077         [ +  - ]:      38712 :                     if(!fTools::equalZero(fCut1))
    1078                 :            :                     {
    1079                 :      38712 :                         fCut1 = (rEdge2Delta.getY() * (rEdge2Start.getX() - rEdge1Start.getX())
    1080                 :      38712 :                             + rEdge2Delta.getX() * (rEdge1Start.getY() - rEdge2Start.getY())) / fCut1;
    1081                 :            : 
    1082                 :      38712 :                         const double fZero(0.0);
    1083                 :      38712 :                         const double fOne(1.0);
    1084                 :            : 
    1085                 :            :                         // inside parameter range edge1 AND fCut2 is calcable
    1086   [ +  +  +  -  :      87728 :                         if(fTools::more(fCut1, fZero) && fTools::less(fCut1, fOne)
           +  - ][ +  + ]
                 [ +  + ]
    1087 [ +  + ][ +  + ]:      49016 :                             && (!fTools::equalZero(rEdge2Delta.getX()) || !fTools::equalZero(rEdge2Delta.getY())))
    1088                 :            :                         {
    1089                 :            :                             // take the mopre precise calculation of the two possible
    1090         [ -  + ]:       5152 :                             if(fabs(rEdge2Delta.getX()) > fabs(rEdge2Delta.getY()))
    1091                 :            :                             {
    1092                 :          0 :                                 fCut2 = (rEdge1Start.getX() + fCut1
    1093                 :          0 :                                     * rEdge1Delta.getX() - rEdge2Start.getX()) / rEdge2Delta.getX();
    1094                 :            :                             }
    1095                 :            :                             else
    1096                 :            :                             {
    1097                 :       5152 :                                 fCut2 = (rEdge1Start.getY() + fCut1
    1098                 :       5152 :                                     * rEdge1Delta.getY() - rEdge2Start.getY()) / rEdge2Delta.getY();
    1099                 :            :                             }
    1100                 :            : 
    1101                 :            :                             // inside parameter range edge2, too
    1102 [ -  + ][ #  # ]:       5152 :                             if(fTools::more(fCut2, fZero) && fTools::less(fCut2, fOne))
                 [ -  + ]
    1103                 :            :                             {
    1104                 :          0 :                                 bFinished = true;
    1105                 :      38712 :                                 aRetval = CUTFLAG_LINE;
    1106                 :            :                             }
    1107                 :            :                         }
    1108                 :            :                     }
    1109                 :            :                 }
    1110                 :            :             }
    1111                 :            : 
    1112                 :            :             // copy values if wanted
    1113         [ +  - ]:      39008 :             if(pCut1)
    1114                 :            :             {
    1115                 :      39008 :                 *pCut1 = fCut1;
    1116                 :            :             }
    1117                 :            : 
    1118         [ -  + ]:      39008 :             if(pCut2)
    1119                 :            :             {
    1120                 :          0 :                 *pCut2 = fCut2;
    1121                 :            :             }
    1122                 :            : 
    1123                 :      39008 :             return aRetval;
    1124                 :            :         }
    1125                 :            : 
    1126                 :     155144 :         bool isPointOnEdge(
    1127                 :            :             const B2DPoint& rPoint,
    1128                 :            :             const B2DPoint& rEdgeStart,
    1129                 :            :             const B2DVector& rEdgeDelta,
    1130                 :            :             double* pCut)
    1131                 :            :         {
    1132                 :     155144 :             bool bDeltaXIsZero(fTools::equalZero(rEdgeDelta.getX()));
    1133                 :     155144 :             bool bDeltaYIsZero(fTools::equalZero(rEdgeDelta.getY()));
    1134                 :     155144 :             const double fZero(0.0);
    1135                 :     155144 :             const double fOne(1.0);
    1136                 :            : 
    1137 [ -  + ][ +  + ]:     155144 :             if(bDeltaXIsZero && bDeltaYIsZero)
    1138                 :            :             {
    1139                 :            :                 // no line, just a point
    1140                 :          0 :                 return false;
    1141                 :            :             }
    1142         [ +  + ]:     155144 :             else if(bDeltaXIsZero)
    1143                 :            :             {
    1144                 :            :                 // vertical line
    1145         [ +  + ]:      77720 :                 if(fTools::equal(rPoint.getX(), rEdgeStart.getX()))
    1146                 :            :                 {
    1147                 :        296 :                     double fValue = (rPoint.getY() - rEdgeStart.getY()) / rEdgeDelta.getY();
    1148                 :            : 
    1149 [ +  - ][ +  - ]:        296 :                     if(fTools::more(fValue, fZero) && fTools::less(fValue, fOne))
                 [ +  - ]
    1150                 :            :                     {
    1151         [ +  - ]:        296 :                         if(pCut)
    1152                 :            :                         {
    1153                 :        296 :                             *pCut = fValue;
    1154                 :            :                         }
    1155                 :            : 
    1156                 :        296 :                         return true;
    1157                 :            :                     }
    1158                 :            :                 }
    1159                 :            :             }
    1160         [ +  - ]:      77424 :             else if(bDeltaYIsZero)
    1161                 :            :             {
    1162                 :            :                 // horizontal line
    1163         [ -  + ]:      77424 :                 if(fTools::equal(rPoint.getY(), rEdgeStart.getY()))
    1164                 :            :                 {
    1165                 :          0 :                     double fValue = (rPoint.getX() - rEdgeStart.getX()) / rEdgeDelta.getX();
    1166                 :            : 
    1167 [ #  # ][ #  # ]:          0 :                     if(fTools::more(fValue, fZero) && fTools::less(fValue, fOne))
                 [ #  # ]
    1168                 :            :                     {
    1169         [ #  # ]:          0 :                         if(pCut)
    1170                 :            :                         {
    1171                 :          0 :                             *pCut = fValue;
    1172                 :            :                         }
    1173                 :            : 
    1174                 :          0 :                         return true;
    1175                 :            :                     }
    1176                 :            :                 }
    1177                 :            :             }
    1178                 :            :             else
    1179                 :            :             {
    1180                 :            :                 // any angle line
    1181                 :          0 :                 double fTOne = (rPoint.getX() - rEdgeStart.getX()) / rEdgeDelta.getX();
    1182                 :          0 :                 double fTTwo = (rPoint.getY() - rEdgeStart.getY()) / rEdgeDelta.getY();
    1183                 :            : 
    1184         [ #  # ]:          0 :                 if(fTools::equal(fTOne, fTTwo))
    1185                 :            :                 {
    1186                 :            :                     // same parameter representation, point is on line. Take
    1187                 :            :                     // middle value for better results
    1188                 :          0 :                     double fValue = (fTOne + fTTwo) / 2.0;
    1189                 :            : 
    1190 [ #  # ][ #  # ]:          0 :                     if(fTools::more(fValue, fZero) && fTools::less(fValue, fOne))
                 [ #  # ]
    1191                 :            :                     {
    1192                 :            :                         // point is inside line bounds, too
    1193         [ #  # ]:          0 :                         if(pCut)
    1194                 :            :                         {
    1195                 :          0 :                             *pCut = fValue;
    1196                 :            :                         }
    1197                 :            : 
    1198                 :          0 :                         return true;
    1199                 :            :                     }
    1200                 :            :                 }
    1201                 :            :             }
    1202                 :            : 
    1203                 :     155144 :             return false;
    1204                 :            :         }
    1205                 :            : 
    1206                 :       3297 :         void applyLineDashing(const B2DPolygon& rCandidate, const ::std::vector<double>& rDotDashArray, B2DPolyPolygon* pLineTarget, B2DPolyPolygon* pGapTarget, double fDotDashLength)
    1207                 :            :         {
    1208                 :       3297 :             const sal_uInt32 nPointCount(rCandidate.count());
    1209                 :       3297 :             const sal_uInt32 nDotDashCount(rDotDashArray.size());
    1210                 :            : 
    1211         [ +  + ]:       3297 :             if(fTools::lessOrEqual(fDotDashLength, 0.0))
    1212                 :            :             {
    1213                 :         43 :                 fDotDashLength = ::std::accumulate(rDotDashArray.begin(), rDotDashArray.end(), 0.0);
    1214                 :            :             }
    1215                 :            : 
    1216 [ +  - ][ -  + ]:       3297 :             if(fTools::more(fDotDashLength, 0.0) && (pLineTarget || pGapTarget) && nPointCount)
         [ #  # ][ +  - ]
         [ +  - ][ +  - ]
    1217                 :            :             {
    1218                 :            :                 // clear targets
    1219         [ +  - ]:       3297 :                 if(pLineTarget)
    1220                 :            :                 {
    1221         [ +  - ]:       3297 :                     pLineTarget->clear();
    1222                 :            :                 }
    1223                 :            : 
    1224         [ -  + ]:       3297 :                 if(pGapTarget)
    1225                 :            :                 {
    1226         [ #  # ]:          0 :                     pGapTarget->clear();
    1227                 :            :                 }
    1228                 :            : 
    1229                 :            :                 // prepare current edge's start
    1230         [ +  - ]:       3297 :                 B2DCubicBezier aCurrentEdge;
    1231 [ +  - ][ +  + ]:       3297 :                 const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1);
    1232         [ +  - ]:       3297 :                 aCurrentEdge.setStartPoint(rCandidate.getB2DPoint(0));
    1233                 :            : 
    1234                 :            :                 // prepare DotDashArray iteration and the line/gap switching bool
    1235                 :       3297 :                 sal_uInt32 nDotDashIndex(0);
    1236                 :       3297 :                 bool bIsLine(true);
    1237         [ +  - ]:       3297 :                 double fDotDashMovingLength(rDotDashArray[0]);
    1238         [ +  - ]:       3297 :                 B2DPolygon aSnippet;
    1239                 :            : 
    1240                 :            :                 // iterate over all edges
    1241         [ +  + ]:       6880 :                 for(sal_uInt32 a(0); a < nEdgeCount; a++)
    1242                 :            :                 {
    1243                 :            :                     // update current edge (fill in C1, C2 and end point)
    1244                 :       3583 :                     double fLastDotDashMovingLength(0.0);
    1245                 :       3583 :                     const sal_uInt32 nNextIndex((a + 1) % nPointCount);
    1246         [ +  - ]:       3583 :                     aCurrentEdge.setControlPointA(rCandidate.getNextControlPoint(a));
    1247         [ +  - ]:       3583 :                     aCurrentEdge.setControlPointB(rCandidate.getPrevControlPoint(nNextIndex));
    1248         [ +  - ]:       3583 :                     aCurrentEdge.setEndPoint(rCandidate.getB2DPoint(nNextIndex));
    1249                 :            : 
    1250                 :            :                     // check if we have a trivial bezier segment -> possible fallback to edge
    1251         [ +  - ]:       3583 :                     aCurrentEdge.testAndSolveTrivialBezier();
    1252                 :            : 
    1253 [ +  - ][ -  + ]:       3583 :                     if(aCurrentEdge.isBezier())
    1254                 :            :                     {
    1255                 :            :                         // bezier segment
    1256         [ #  # ]:          0 :                         const B2DCubicBezierHelper aCubicBezierHelper(aCurrentEdge);
    1257         [ #  # ]:          0 :                         const double fEdgeLength(aCubicBezierHelper.getLength());
    1258                 :            : 
    1259         [ #  # ]:          0 :                         if(!fTools::equalZero(fEdgeLength))
    1260                 :            :                         {
    1261         [ #  # ]:          0 :                             while(fTools::less(fDotDashMovingLength, fEdgeLength))
    1262                 :            :                             {
    1263                 :            :                                 // new split is inside edge, create and append snippet [fLastDotDashMovingLength, fDotDashMovingLength]
    1264 [ #  # ][ #  # ]:          0 :                                 const bool bHandleLine(bIsLine && pLineTarget);
    1265 [ #  # ][ #  # ]:          0 :                                 const bool bHandleGap(!bIsLine && pGapTarget);
    1266                 :            : 
    1267 [ #  # ][ #  # ]:          0 :                                 if(bHandleLine || bHandleGap)
    1268                 :            :                                 {
    1269         [ #  # ]:          0 :                                     const double fBezierSplitStart(aCubicBezierHelper.distanceToRelative(fLastDotDashMovingLength));
    1270         [ #  # ]:          0 :                                     const double fBezierSplitEnd(aCubicBezierHelper.distanceToRelative(fDotDashMovingLength));
    1271         [ #  # ]:          0 :                                     B2DCubicBezier aBezierSnippet(aCurrentEdge.snippet(fBezierSplitStart, fBezierSplitEnd));
    1272                 :            : 
    1273 [ #  # ][ #  # ]:          0 :                                     if(!aSnippet.count())
    1274                 :            :                                     {
    1275         [ #  # ]:          0 :                                         aSnippet.append(aBezierSnippet.getStartPoint());
    1276                 :            :                                     }
    1277                 :            : 
    1278         [ #  # ]:          0 :                                     aSnippet.appendBezierSegment(aBezierSnippet.getControlPointA(), aBezierSnippet.getControlPointB(), aBezierSnippet.getEndPoint());
    1279                 :            : 
    1280         [ #  # ]:          0 :                                     if(bHandleLine)
    1281                 :            :                                     {
    1282         [ #  # ]:          0 :                                         pLineTarget->append(aSnippet);
    1283                 :            :                                     }
    1284                 :            :                                     else
    1285                 :            :                                     {
    1286         [ #  # ]:          0 :                                         pGapTarget->append(aSnippet);
    1287                 :            :                                     }
    1288                 :            : 
    1289 [ #  # ][ #  # ]:          0 :                                     aSnippet.clear();
    1290                 :            :                                 }
    1291                 :            : 
    1292                 :            :                                 // prepare next DotDashArray step and flip line/gap flag
    1293                 :          0 :                                 fLastDotDashMovingLength = fDotDashMovingLength;
    1294         [ #  # ]:          0 :                                 fDotDashMovingLength += rDotDashArray[(++nDotDashIndex) % nDotDashCount];
    1295                 :          0 :                                 bIsLine = !bIsLine;
    1296                 :            :                             }
    1297                 :            : 
    1298                 :            :                             // append closing snippet [fLastDotDashMovingLength, fEdgeLength]
    1299 [ #  # ][ #  # ]:          0 :                             const bool bHandleLine(bIsLine && pLineTarget);
    1300 [ #  # ][ #  # ]:          0 :                             const bool bHandleGap(!bIsLine && pGapTarget);
    1301                 :            : 
    1302 [ #  # ][ #  # ]:          0 :                             if(bHandleLine || bHandleGap)
    1303                 :            :                             {
    1304         [ #  # ]:          0 :                                 B2DCubicBezier aRight;
    1305         [ #  # ]:          0 :                                 const double fBezierSplit(aCubicBezierHelper.distanceToRelative(fLastDotDashMovingLength));
    1306                 :            : 
    1307         [ #  # ]:          0 :                                 aCurrentEdge.split(fBezierSplit, 0, &aRight);
    1308                 :            : 
    1309 [ #  # ][ #  # ]:          0 :                                 if(!aSnippet.count())
    1310                 :            :                                 {
    1311         [ #  # ]:          0 :                                     aSnippet.append(aRight.getStartPoint());
    1312                 :            :                                 }
    1313                 :            : 
    1314 [ #  # ][ #  # ]:          0 :                                 aSnippet.appendBezierSegment(aRight.getControlPointA(), aRight.getControlPointB(), aRight.getEndPoint());
    1315                 :            :                             }
    1316                 :            : 
    1317                 :            :                             // prepare move to next edge
    1318                 :          0 :                             fDotDashMovingLength -= fEdgeLength;
    1319                 :          0 :                         }
    1320                 :            :                     }
    1321                 :            :                     else
    1322                 :            :                     {
    1323                 :            :                         // simple edge
    1324         [ +  - ]:       3583 :                         const double fEdgeLength(aCurrentEdge.getEdgeLength());
    1325                 :            : 
    1326         [ +  - ]:       3583 :                         if(!fTools::equalZero(fEdgeLength))
    1327                 :            :                         {
    1328         [ +  + ]:     190048 :                             while(fTools::less(fDotDashMovingLength, fEdgeLength))
    1329                 :            :                             {
    1330                 :            :                                 // new split is inside edge, create and append snippet [fLastDotDashMovingLength, fDotDashMovingLength]
    1331 [ +  + ][ +  - ]:     186465 :                                 const bool bHandleLine(bIsLine && pLineTarget);
    1332 [ +  + ][ -  + ]:     186465 :                                 const bool bHandleGap(!bIsLine && pGapTarget);
    1333                 :            : 
    1334 [ +  + ][ -  + ]:     186465 :                                 if(bHandleLine || bHandleGap)
    1335                 :            :                                 {
    1336 [ +  - ][ +  + ]:      94031 :                                     if(!aSnippet.count())
    1337                 :            :                                     {
    1338         [ +  - ]:      93833 :                                         aSnippet.append(interpolate(aCurrentEdge.getStartPoint(), aCurrentEdge.getEndPoint(), fLastDotDashMovingLength / fEdgeLength));
    1339                 :            :                                     }
    1340                 :            : 
    1341         [ +  - ]:      94031 :                                     aSnippet.append(interpolate(aCurrentEdge.getStartPoint(), aCurrentEdge.getEndPoint(), fDotDashMovingLength / fEdgeLength));
    1342                 :            : 
    1343         [ +  - ]:      94031 :                                     if(bHandleLine)
    1344                 :            :                                     {
    1345         [ +  - ]:      94031 :                                         pLineTarget->append(aSnippet);
    1346                 :            :                                     }
    1347                 :            :                                     else
    1348                 :            :                                     {
    1349         [ #  # ]:          0 :                                         pGapTarget->append(aSnippet);
    1350                 :            :                                     }
    1351                 :            : 
    1352         [ +  - ]:      94031 :                                     aSnippet.clear();
    1353                 :            :                                 }
    1354                 :            : 
    1355                 :            :                                 // prepare next DotDashArray step and flip line/gap flag
    1356                 :     186465 :                                 fLastDotDashMovingLength = fDotDashMovingLength;
    1357         [ +  - ]:     186465 :                                 fDotDashMovingLength += rDotDashArray[(++nDotDashIndex) % nDotDashCount];
    1358                 :     186465 :                                 bIsLine = !bIsLine;
    1359                 :            :                             }
    1360                 :            : 
    1361                 :            :                             // append snippet [fLastDotDashMovingLength, fEdgeLength]
    1362 [ +  + ][ +  - ]:       3583 :                             const bool bHandleLine(bIsLine && pLineTarget);
    1363 [ +  + ][ -  + ]:       3583 :                             const bool bHandleGap(!bIsLine && pGapTarget);
    1364                 :            : 
    1365 [ +  + ][ -  + ]:       3583 :                             if(bHandleLine || bHandleGap)
    1366                 :            :                             {
    1367 [ +  - ][ +  - ]:       1898 :                                 if(!aSnippet.count())
    1368                 :            :                                 {
    1369         [ +  - ]:       1898 :                                     aSnippet.append(interpolate(aCurrentEdge.getStartPoint(), aCurrentEdge.getEndPoint(), fLastDotDashMovingLength / fEdgeLength));
    1370                 :            :                                 }
    1371                 :            : 
    1372         [ +  - ]:       1898 :                                 aSnippet.append(aCurrentEdge.getEndPoint());
    1373                 :            :                             }
    1374                 :            : 
    1375                 :            :                             // prepare move to next edge
    1376                 :       3583 :                             fDotDashMovingLength -= fEdgeLength;
    1377                 :            :                         }
    1378                 :            :                     }
    1379                 :            : 
    1380                 :            :                     // prepare next edge step (end point gets new start point)
    1381                 :       3583 :                     aCurrentEdge.setStartPoint(aCurrentEdge.getEndPoint());
    1382                 :            :                 }
    1383                 :            : 
    1384                 :            :                 // append last intermediate results (if exists)
    1385 [ +  - ][ +  + ]:       3297 :                 if(aSnippet.count())
    1386                 :            :                 {
    1387 [ +  - ][ +  - ]:       1700 :                     if(bIsLine && pLineTarget)
    1388                 :            :                     {
    1389         [ +  - ]:       1700 :                         pLineTarget->append(aSnippet);
    1390                 :            :                     }
    1391 [ #  # ][ #  # ]:          0 :                     else if(!bIsLine && pGapTarget)
    1392                 :            :                     {
    1393         [ #  # ]:       1700 :                         pGapTarget->append(aSnippet);
    1394                 :            :                     }
    1395                 :            :                 }
    1396                 :            : 
    1397                 :            :                 // check if start and end polygon may be merged
    1398         [ +  - ]:       3297 :                 if(pLineTarget)
    1399                 :            :                 {
    1400         [ +  - ]:       3297 :                     const sal_uInt32 nCount(pLineTarget->count());
    1401                 :            : 
    1402         [ +  + ]:       3297 :                     if(nCount > 1)
    1403                 :            :                     {
    1404                 :            :                         // these polygons were created above, there exists none with less than two points,
    1405                 :            :                         // thus dircet point access below is allowed
    1406         [ +  - ]:       3142 :                         const B2DPolygon aFirst(pLineTarget->getB2DPolygon(0));
    1407         [ +  - ]:       3142 :                         B2DPolygon aLast(pLineTarget->getB2DPolygon(nCount - 1));
    1408                 :            : 
    1409 [ +  - ][ +  - ]:       3142 :                         if(aFirst.getB2DPoint(0).equal(aLast.getB2DPoint(aLast.count() - 1)))
         [ +  - ][ +  + ]
    1410                 :            :                         {
    1411                 :            :                             // start of first and end of last are the same -> merge them
    1412         [ +  - ]:         54 :                             aLast.append(aFirst);
    1413         [ +  - ]:         54 :                             aLast.removeDoublePoints();
    1414         [ +  - ]:         54 :                             pLineTarget->setB2DPolygon(0, aLast);
    1415         [ +  - ]:         54 :                             pLineTarget->remove(nCount - 1);
    1416 [ +  - ][ +  - ]:       3142 :                         }
    1417                 :            :                     }
    1418                 :            :                 }
    1419                 :            : 
    1420         [ -  + ]:       3297 :                 if(pGapTarget)
    1421                 :            :                 {
    1422         [ #  # ]:          0 :                     const sal_uInt32 nCount(pGapTarget->count());
    1423                 :            : 
    1424         [ #  # ]:          0 :                     if(nCount > 1)
    1425                 :            :                     {
    1426                 :            :                         // these polygons were created above, there exists none with less than two points,
    1427                 :            :                         // thus dircet point access below is allowed
    1428         [ #  # ]:          0 :                         const B2DPolygon aFirst(pGapTarget->getB2DPolygon(0));
    1429         [ #  # ]:          0 :                         B2DPolygon aLast(pGapTarget->getB2DPolygon(nCount - 1));
    1430                 :            : 
    1431 [ #  # ][ #  # ]:          0 :                         if(aFirst.getB2DPoint(0).equal(aLast.getB2DPoint(aLast.count() - 1)))
         [ #  # ][ #  # ]
    1432                 :            :                         {
    1433                 :            :                             // start of first and end of last are the same -> merge them
    1434         [ #  # ]:          0 :                             aLast.append(aFirst);
    1435         [ #  # ]:          0 :                             aLast.removeDoublePoints();
    1436         [ #  # ]:          0 :                             pGapTarget->setB2DPolygon(0, aLast);
    1437         [ #  # ]:          0 :                             pGapTarget->remove(nCount - 1);
    1438 [ #  # ][ #  # ]:          0 :                         }
    1439                 :            :                     }
    1440 [ +  - ][ +  - ]:       3297 :                 }
    1441                 :            :             }
    1442                 :            :             else
    1443                 :            :             {
    1444                 :            :                 // parameters make no sense, just add source to targets
    1445         [ #  # ]:          0 :                 if(pLineTarget)
    1446                 :            :                 {
    1447                 :          0 :                     pLineTarget->append(rCandidate);
    1448                 :            :                 }
    1449                 :            : 
    1450         [ #  # ]:          0 :                 if(pGapTarget)
    1451                 :            :                 {
    1452                 :          0 :                     pGapTarget->append(rCandidate);
    1453                 :            :                 }
    1454                 :            :             }
    1455                 :       3297 :         }
    1456                 :            : 
    1457                 :            :         // test if point is inside epsilon-range around an edge defined
    1458                 :            :         // by the two given points. Can be used for HitTesting. The epsilon-range
    1459                 :            :         // is defined to be the rectangle centered to the given edge, using height
    1460                 :            :         // 2 x fDistance, and the circle around both points with radius fDistance.
    1461                 :          8 :         bool isInEpsilonRange(const B2DPoint& rEdgeStart, const B2DPoint& rEdgeEnd, const B2DPoint& rTestPosition, double fDistance)
    1462                 :            :         {
    1463                 :            :             // build edge vector
    1464                 :          8 :             const B2DVector aEdge(rEdgeEnd - rEdgeStart);
    1465                 :          8 :             bool bDoDistanceTestStart(false);
    1466                 :          8 :             bool bDoDistanceTestEnd(false);
    1467                 :            : 
    1468 [ -  + ][ +  - ]:          8 :             if(aEdge.equalZero())
    1469                 :            :             {
    1470                 :            :                 // no edge, just a point. Do one of the distance tests.
    1471                 :          0 :                 bDoDistanceTestStart = true;
    1472                 :            :             }
    1473                 :            :             else
    1474                 :            :             {
    1475                 :            :                 // edge has a length. Create perpendicular vector.
    1476         [ +  - ]:          8 :                 const B2DVector aPerpend(getPerpendicular(aEdge));
    1477                 :            :                 double fCut(
    1478                 :          8 :                     (aPerpend.getY() * (rTestPosition.getX() - rEdgeStart.getX())
    1479                 :          8 :                     + aPerpend.getX() * (rEdgeStart.getY() - rTestPosition.getY())) /
    1480                 :          8 :                     (aEdge.getX() * aEdge.getX() + aEdge.getY() * aEdge.getY()));
    1481                 :          8 :                 const double fZero(0.0);
    1482                 :          8 :                 const double fOne(1.0);
    1483                 :            : 
    1484         [ -  + ]:          8 :                 if(fTools::less(fCut, fZero))
    1485                 :            :                 {
    1486                 :            :                     // left of rEdgeStart
    1487                 :          0 :                     bDoDistanceTestStart = true;
    1488                 :            :                 }
    1489         [ -  + ]:          8 :                 else if(fTools::more(fCut, fOne))
    1490                 :            :                 {
    1491                 :            :                     // right of rEdgeEnd
    1492                 :          0 :                     bDoDistanceTestEnd = true;
    1493                 :            :                 }
    1494                 :            :                 else
    1495                 :            :                 {
    1496                 :            :                     // inside line [0.0 .. 1.0]
    1497                 :          8 :                     const B2DPoint aCutPoint(interpolate(rEdgeStart, rEdgeEnd, fCut));
    1498                 :          8 :                     const B2DVector aDelta(rTestPosition - aCutPoint);
    1499         [ +  - ]:          8 :                     const double fDistanceSquare(aDelta.scalar(aDelta));
    1500                 :            : 
    1501         [ -  + ]:          8 :                     if(fDistanceSquare <= fDistance * fDistance)
    1502                 :            :                     {
    1503                 :          0 :                         return true;
    1504                 :            :                     }
    1505                 :            :                     else
    1506                 :            :                     {
    1507                 :          8 :                         return false;
    1508                 :          8 :                     }
    1509         [ -  + ]:          8 :                 }
    1510                 :            :             }
    1511                 :            : 
    1512         [ #  # ]:          0 :             if(bDoDistanceTestStart)
    1513                 :            :             {
    1514                 :          0 :                 const B2DVector aDelta(rTestPosition - rEdgeStart);
    1515         [ #  # ]:          0 :                 const double fDistanceSquare(aDelta.scalar(aDelta));
    1516                 :            : 
    1517         [ #  # ]:          0 :                 if(fDistanceSquare <= fDistance * fDistance)
    1518                 :            :                 {
    1519                 :          0 :                     return true;
    1520         [ #  # ]:          0 :                 }
    1521                 :            :             }
    1522         [ #  # ]:          0 :             else if(bDoDistanceTestEnd)
    1523                 :            :             {
    1524                 :          0 :                 const B2DVector aDelta(rTestPosition - rEdgeEnd);
    1525         [ #  # ]:          0 :                 const double fDistanceSquare(aDelta.scalar(aDelta));
    1526                 :            : 
    1527         [ #  # ]:          0 :                 if(fDistanceSquare <= fDistance * fDistance)
    1528                 :            :                 {
    1529                 :          0 :                     return true;
    1530         [ #  # ]:          0 :                 }
    1531                 :            :             }
    1532                 :            : 
    1533                 :          8 :             return false;
    1534                 :            :         }
    1535                 :            : 
    1536                 :            :         // test if point is inside epsilon-range around the given Polygon. Can be used
    1537                 :            :         // for HitTesting. The epsilon-range is defined to be the tube around the polygon
    1538                 :            :         // with distance fDistance and rounded edges (start and end point).
    1539                 :          2 :         bool isInEpsilonRange(const B2DPolygon& rCandidate, const B2DPoint& rTestPosition, double fDistance)
    1540                 :            :         {
    1541                 :            :             // force to non-bezier polygon
    1542         [ +  - ]:          2 :             const B2DPolygon aCandidate(rCandidate.getDefaultAdaptiveSubdivision());
    1543         [ +  - ]:          2 :             const sal_uInt32 nPointCount(aCandidate.count());
    1544                 :            : 
    1545         [ +  - ]:          2 :             if(nPointCount)
    1546                 :            :             {
    1547 [ +  - ][ +  - ]:          2 :                 const sal_uInt32 nEdgeCount(aCandidate.isClosed() ? nPointCount : nPointCount - 1L);
    1548         [ +  - ]:          2 :                 B2DPoint aCurrent(aCandidate.getB2DPoint(0));
    1549                 :            : 
    1550         [ +  - ]:          2 :                 if(nEdgeCount)
    1551                 :            :                 {
    1552                 :            :                     // edges
    1553         [ +  + ]:         10 :                     for(sal_uInt32 a(0); a < nEdgeCount; a++)
    1554                 :            :                     {
    1555                 :          8 :                         const sal_uInt32 nNextIndex((a + 1) % nPointCount);
    1556         [ +  - ]:          8 :                         const B2DPoint aNext(aCandidate.getB2DPoint(nNextIndex));
    1557                 :            : 
    1558 [ +  - ][ -  + ]:          8 :                         if(isInEpsilonRange(aCurrent, aNext, rTestPosition, fDistance))
    1559                 :            :                         {
    1560                 :          0 :                             return true;
    1561                 :            :                         }
    1562                 :            : 
    1563                 :            :                         // prepare next step
    1564         [ +  - ]:         16 :                         aCurrent = aNext;
    1565                 :          8 :                     }
    1566                 :            :                 }
    1567                 :            :                 else
    1568                 :            :                 {
    1569                 :            :                     // no edges, but points -> not closed. Check single point. Just
    1570                 :            :                     // use isInEpsilonRange with twice the same point, it handles those well
    1571 [ #  # ][ #  # ]:          0 :                     if(isInEpsilonRange(aCurrent, aCurrent, rTestPosition, fDistance))
    1572                 :            :                     {
    1573                 :          2 :                         return true;
    1574                 :            :                     }
    1575         [ +  - ]:          2 :                 }
    1576                 :            :             }
    1577                 :            : 
    1578         [ +  - ]:          2 :             return false;
    1579                 :            :         }
    1580                 :            : 
    1581                 :      23911 :         B2DPolygon createPolygonFromRect( const B2DRectangle& rRect, double fRadiusX, double fRadiusY )
    1582                 :            :         {
    1583                 :      23911 :             const double fZero(0.0);
    1584                 :      23911 :             const double fOne(1.0);
    1585                 :            : 
    1586                 :            :             // crop to useful values
    1587         [ -  + ]:      23911 :             if(fTools::less(fRadiusX, fZero))
    1588                 :            :             {
    1589                 :          0 :                 fRadiusX = fZero;
    1590                 :            :             }
    1591         [ -  + ]:      23911 :             else if(fTools::more(fRadiusX, fOne))
    1592                 :            :             {
    1593                 :          0 :                 fRadiusX = fOne;
    1594                 :            :             }
    1595                 :            : 
    1596         [ -  + ]:      23911 :             if(fTools::less(fRadiusY, fZero))
    1597                 :            :             {
    1598                 :          0 :                 fRadiusY = fZero;
    1599                 :            :             }
    1600         [ -  + ]:      23911 :             else if(fTools::more(fRadiusY, fOne))
    1601                 :            :             {
    1602                 :          0 :                 fRadiusY = fOne;
    1603                 :            :             }
    1604                 :            : 
    1605 [ -  + ][ #  # ]:      23911 :             if(fZero == fRadiusX || fZero == fRadiusY)
    1606                 :            :             {
    1607         [ +  - ]:      23911 :                 B2DPolygon aRetval;
    1608                 :            : 
    1609                 :            :                 // at least in one direction no radius, use rectangle.
    1610                 :            :                 // Do not use createPolygonFromRect() here since original
    1611                 :            :                 // creator (historical reasons) still creates a start point at the
    1612                 :            :                 // bottom center, so do the same here to get the same line patterns.
    1613                 :            :                 // Due to this the order of points is different, too.
    1614 [ +  - ][ +  - ]:      23911 :                 const B2DPoint aBottomCenter(rRect.getCenter().getX(), rRect.getMaxY());
    1615         [ +  - ]:      23911 :                 aRetval.append(aBottomCenter);
    1616                 :            : 
    1617 [ +  - ][ +  - ]:      23911 :                 aRetval.append( B2DPoint( rRect.getMinX(), rRect.getMaxY() ) );
                 [ +  - ]
    1618 [ +  - ][ +  - ]:      23911 :                 aRetval.append( B2DPoint( rRect.getMinX(), rRect.getMinY() ) );
                 [ +  - ]
    1619 [ +  - ][ +  - ]:      23911 :                 aRetval.append( B2DPoint( rRect.getMaxX(), rRect.getMinY() ) );
                 [ +  - ]
    1620 [ +  - ][ +  - ]:      23911 :                 aRetval.append( B2DPoint( rRect.getMaxX(), rRect.getMaxY() ) );
                 [ +  - ]
    1621                 :            : 
    1622                 :            :                 // close
    1623         [ +  - ]:      23911 :                 aRetval.setClosed( true );
    1624                 :            : 
    1625 [ +  - ][ +  - ]:      23911 :                 return aRetval;
    1626                 :            :             }
    1627 [ #  # ][ #  # ]:          0 :             else if(fOne == fRadiusX && fOne == fRadiusY)
    1628                 :            :             {
    1629                 :            :                 // in both directions full radius, use ellipse
    1630         [ #  # ]:          0 :                 const B2DPoint aCenter(rRect.getCenter());
    1631         [ #  # ]:          0 :                 const double fRectRadiusX(rRect.getWidth() / 2.0);
    1632         [ #  # ]:          0 :                 const double fRectRadiusY(rRect.getHeight() / 2.0);
    1633                 :            : 
    1634         [ #  # ]:          0 :                 return createPolygonFromEllipse( aCenter, fRectRadiusX, fRectRadiusY );
    1635                 :            :             }
    1636                 :            :             else
    1637                 :            :             {
    1638         [ #  # ]:          0 :                 B2DPolygon aRetval;
    1639         [ #  # ]:          0 :                 const double fBowX((rRect.getWidth() / 2.0) * fRadiusX);
    1640         [ #  # ]:          0 :                 const double fBowY((rRect.getHeight() / 2.0) * fRadiusY);
    1641                 :          0 :                 const double fKappa((M_SQRT2 - 1.0) * 4.0 / 3.0);
    1642                 :            : 
    1643                 :            :                 // create start point at bottom center
    1644         [ #  # ]:          0 :                 if(fOne != fRadiusX)
    1645                 :            :                 {
    1646 [ #  # ][ #  # ]:          0 :                     const B2DPoint aBottomCenter(rRect.getCenter().getX(), rRect.getMaxY());
    1647         [ #  # ]:          0 :                     aRetval.append(aBottomCenter);
    1648                 :            :                 }
    1649                 :            : 
    1650                 :            :                 // create first bow
    1651                 :            :                 {
    1652 [ #  # ][ #  # ]:          0 :                     const B2DPoint aBottomRight(rRect.getMaxX(), rRect.getMaxY());
    1653                 :          0 :                     const B2DPoint aStart(aBottomRight + B2DPoint(-fBowX, 0.0));
    1654                 :          0 :                     const B2DPoint aStop(aBottomRight + B2DPoint(0.0, -fBowY));
    1655         [ #  # ]:          0 :                     aRetval.append(aStart);
    1656         [ #  # ]:          0 :                     aRetval.appendBezierSegment(interpolate(aStart, aBottomRight, fKappa), interpolate(aStop, aBottomRight, fKappa), aStop);
    1657                 :            :                 }
    1658                 :            : 
    1659                 :            :                 // create second bow
    1660                 :            :                 {
    1661 [ #  # ][ #  # ]:          0 :                     const B2DPoint aTopRight(rRect.getMaxX(), rRect.getMinY());
    1662                 :          0 :                     const B2DPoint aStart(aTopRight + B2DPoint(0.0, fBowY));
    1663                 :          0 :                     const B2DPoint aStop(aTopRight + B2DPoint(-fBowX, 0.0));
    1664         [ #  # ]:          0 :                     aRetval.append(aStart);
    1665         [ #  # ]:          0 :                     aRetval.appendBezierSegment(interpolate(aStart, aTopRight, fKappa), interpolate(aStop, aTopRight, fKappa), aStop);
    1666                 :            :                 }
    1667                 :            : 
    1668                 :            :                 // create third bow
    1669                 :            :                 {
    1670 [ #  # ][ #  # ]:          0 :                     const B2DPoint aTopLeft(rRect.getMinX(), rRect.getMinY());
    1671                 :          0 :                     const B2DPoint aStart(aTopLeft + B2DPoint(fBowX, 0.0));
    1672                 :          0 :                     const B2DPoint aStop(aTopLeft + B2DPoint(0.0, fBowY));
    1673         [ #  # ]:          0 :                     aRetval.append(aStart);
    1674         [ #  # ]:          0 :                     aRetval.appendBezierSegment(interpolate(aStart, aTopLeft, fKappa), interpolate(aStop, aTopLeft, fKappa), aStop);
    1675                 :            :                 }
    1676                 :            : 
    1677                 :            :                 // create forth bow
    1678                 :            :                 {
    1679 [ #  # ][ #  # ]:          0 :                     const B2DPoint aBottomLeft(rRect.getMinX(), rRect.getMaxY());
    1680                 :          0 :                     const B2DPoint aStart(aBottomLeft + B2DPoint(0.0, -fBowY));
    1681                 :          0 :                     const B2DPoint aStop(aBottomLeft + B2DPoint(fBowX, 0.0));
    1682         [ #  # ]:          0 :                     aRetval.append(aStart);
    1683         [ #  # ]:          0 :                     aRetval.appendBezierSegment(interpolate(aStart, aBottomLeft, fKappa), interpolate(aStop, aBottomLeft, fKappa), aStop);
    1684                 :            :                 }
    1685                 :            : 
    1686                 :            :                 // close
    1687         [ #  # ]:          0 :                 aRetval.setClosed( true );
    1688                 :            : 
    1689                 :            :                 // remove double created points if there are extreme radii envolved
    1690 [ #  # ][ #  # ]:          0 :                 if(fOne == fRadiusX || fOne == fRadiusY)
    1691                 :            :                 {
    1692         [ #  # ]:          0 :                     aRetval.removeDoublePoints();
    1693                 :            :                 }
    1694                 :            : 
    1695 [ #  # ][ #  # ]:      23911 :                 return aRetval;
    1696                 :            :             }
    1697                 :            :         }
    1698                 :            : 
    1699                 :    1008221 :         B2DPolygon createPolygonFromRect( const B2DRectangle& rRect )
    1700                 :            :         {
    1701                 :    1008221 :             B2DPolygon aRetval;
    1702                 :            : 
    1703 [ +  - ][ +  - ]:    1008221 :             aRetval.append( B2DPoint( rRect.getMinX(), rRect.getMinY() ) );
                 [ +  - ]
    1704 [ +  - ][ +  - ]:    1008221 :             aRetval.append( B2DPoint( rRect.getMaxX(), rRect.getMinY() ) );
                 [ +  - ]
    1705 [ +  - ][ +  - ]:    1008221 :             aRetval.append( B2DPoint( rRect.getMaxX(), rRect.getMaxY() ) );
                 [ +  - ]
    1706 [ +  - ][ +  - ]:    1008221 :             aRetval.append( B2DPoint( rRect.getMinX(), rRect.getMaxY() ) );
                 [ +  - ]
    1707                 :            : 
    1708                 :            :             // close
    1709         [ +  - ]:    1008221 :             aRetval.setClosed( true );
    1710                 :            : 
    1711                 :    1008221 :             return aRetval;
    1712                 :            :         }
    1713                 :            : 
    1714                 :            :         namespace
    1715                 :            :         {
    1716                 :            :             struct theUnitPolygon :
    1717                 :            :                 public rtl::StaticWithInit<B2DPolygon, theUnitPolygon>
    1718                 :            :             {
    1719                 :         33 :                 B2DPolygon operator () ()
    1720                 :            :                 {
    1721                 :         33 :                     B2DPolygon aRetval;
    1722                 :            : 
    1723         [ +  - ]:         33 :                     aRetval.append( B2DPoint( 0.0, 0.0 ) );
    1724         [ +  - ]:         33 :                     aRetval.append( B2DPoint( 1.0, 0.0 ) );
    1725         [ +  - ]:         33 :                     aRetval.append( B2DPoint( 1.0, 1.0 ) );
    1726         [ +  - ]:         33 :                     aRetval.append( B2DPoint( 0.0, 1.0 ) );
    1727                 :            : 
    1728                 :            :                     // close
    1729         [ +  - ]:         33 :                     aRetval.setClosed( true );
    1730                 :            : 
    1731                 :         33 :                     return aRetval;
    1732                 :            :                 }
    1733                 :            :             };
    1734                 :            :         }
    1735                 :            : 
    1736                 :       1331 :         B2DPolygon createUnitPolygon()
    1737                 :            :         {
    1738                 :       1331 :             return theUnitPolygon::get();
    1739                 :            :         }
    1740                 :            : 
    1741                 :          0 :         B2DPolygon createPolygonFromCircle( const B2DPoint& rCenter, double fRadius )
    1742                 :            :         {
    1743                 :          0 :             return createPolygonFromEllipse( rCenter, fRadius, fRadius );
    1744                 :            :         }
    1745                 :            : 
    1746                 :          9 :         B2DPolygon impCreateUnitCircle(sal_uInt32 nStartQuadrant)
    1747                 :            :         {
    1748         [ +  - ]:          9 :             B2DPolygon aUnitCircle;
    1749                 :          9 :             const double fKappa((M_SQRT2 - 1.0) * 4.0 / 3.0);
    1750                 :          9 :             const double fScaledKappa(fKappa * (1.0 / STEPSPERQUARTER));
    1751         [ +  - ]:          9 :             const B2DHomMatrix aRotateMatrix(createRotateB2DHomMatrix(F_PI2 / STEPSPERQUARTER));
    1752                 :            : 
    1753                 :          9 :             B2DPoint aPoint(1.0, 0.0);
    1754                 :          9 :             B2DPoint aForward(1.0, fScaledKappa);
    1755                 :          9 :             B2DPoint aBackward(1.0, -fScaledKappa);
    1756                 :            : 
    1757         [ +  + ]:          9 :             if(0 != nStartQuadrant)
    1758                 :            :             {
    1759         [ +  - ]:          8 :                 const B2DHomMatrix aQuadrantMatrix(createRotateB2DHomMatrix(F_PI2 * (nStartQuadrant % 4)));
    1760         [ +  - ]:          8 :                 aPoint *= aQuadrantMatrix;
    1761         [ +  - ]:          8 :                 aBackward *= aQuadrantMatrix;
    1762 [ +  - ][ +  - ]:          8 :                 aForward *= aQuadrantMatrix;
    1763                 :            :             }
    1764                 :            : 
    1765         [ +  - ]:          9 :             aUnitCircle.append(aPoint);
    1766                 :            : 
    1767         [ +  + ]:        117 :             for(sal_uInt32 a(0); a < STEPSPERQUARTER * 4; a++)
    1768                 :            :             {
    1769         [ +  - ]:        108 :                 aPoint *= aRotateMatrix;
    1770         [ +  - ]:        108 :                 aBackward *= aRotateMatrix;
    1771         [ +  - ]:        108 :                 aUnitCircle.appendBezierSegment(aForward, aBackward, aPoint);
    1772         [ +  - ]:        108 :                 aForward *= aRotateMatrix;
    1773                 :            :             }
    1774                 :            : 
    1775         [ +  - ]:          9 :             aUnitCircle.setClosed(true);
    1776         [ +  - ]:          9 :             aUnitCircle.removeDoublePoints();
    1777                 :            : 
    1778         [ +  - ]:          9 :             return aUnitCircle;
    1779                 :            :         }
    1780                 :            : 
    1781                 :         88 :         B2DPolygon createPolygonFromUnitCircle(sal_uInt32 nStartQuadrant)
    1782                 :            :         {
    1783   [ +  -  -  + ]:         88 :             switch(nStartQuadrant % 4)
    1784                 :            :             {
    1785                 :            :                 case 1 :
    1786                 :            :                 {
    1787 [ +  + ][ +  - ]:         75 :                     static B2DPolygon aUnitCircleStartQuadrantOne;
         [ +  - ][ #  # ]
    1788                 :            : 
    1789         [ +  + ]:         75 :                     if(!aUnitCircleStartQuadrantOne.count())
    1790                 :            :                     {
    1791         [ +  - ]:          8 :                         ::osl::Mutex m_mutex;
    1792 [ +  - ][ +  - ]:          8 :                         aUnitCircleStartQuadrantOne = impCreateUnitCircle(1);
         [ +  - ][ +  - ]
    1793                 :            :                     }
    1794                 :            : 
    1795                 :         75 :                     return aUnitCircleStartQuadrantOne;
    1796                 :            :                 }
    1797                 :            :                 case 2 :
    1798                 :            :                 {
    1799 [ #  # ][ #  # ]:          0 :                     static B2DPolygon aUnitCircleStartQuadrantTwo;
         [ #  # ][ #  # ]
    1800                 :            : 
    1801         [ #  # ]:          0 :                     if(!aUnitCircleStartQuadrantTwo.count())
    1802                 :            :                     {
    1803         [ #  # ]:          0 :                         ::osl::Mutex m_mutex;
    1804 [ #  # ][ #  # ]:          0 :                         aUnitCircleStartQuadrantTwo = impCreateUnitCircle(2);
         [ #  # ][ #  # ]
    1805                 :            :                     }
    1806                 :            : 
    1807                 :          0 :                     return aUnitCircleStartQuadrantTwo;
    1808                 :            :                 }
    1809                 :            :                 case 3 :
    1810                 :            :                 {
    1811 [ #  # ][ #  # ]:          0 :                     static B2DPolygon aUnitCircleStartQuadrantThree;
         [ #  # ][ #  # ]
    1812                 :            : 
    1813         [ #  # ]:          0 :                     if(!aUnitCircleStartQuadrantThree.count())
    1814                 :            :                     {
    1815         [ #  # ]:          0 :                         ::osl::Mutex m_mutex;
    1816 [ #  # ][ #  # ]:          0 :                         aUnitCircleStartQuadrantThree = impCreateUnitCircle(3);
         [ #  # ][ #  # ]
    1817                 :            :                     }
    1818                 :            : 
    1819                 :          0 :                     return aUnitCircleStartQuadrantThree;
    1820                 :            :                 }
    1821                 :            :                 default : // case 0 :
    1822                 :            :                 {
    1823 [ +  + ][ +  - ]:         13 :                     static B2DPolygon aUnitCircleStartQuadrantZero;
         [ +  - ][ #  # ]
    1824                 :            : 
    1825         [ +  + ]:         13 :                     if(!aUnitCircleStartQuadrantZero.count())
    1826                 :            :                     {
    1827         [ +  - ]:          1 :                         ::osl::Mutex m_mutex;
    1828 [ +  - ][ +  - ]:          1 :                         aUnitCircleStartQuadrantZero = impCreateUnitCircle(0);
         [ +  - ][ +  - ]
    1829                 :            :                     }
    1830                 :            : 
    1831                 :         88 :                     return aUnitCircleStartQuadrantZero;
    1832                 :            :                 }
    1833                 :            :             }
    1834                 :            :         }
    1835                 :            : 
    1836                 :         13 :         B2DPolygon createPolygonFromEllipse( const B2DPoint& rCenter, double fRadiusX, double fRadiusY )
    1837                 :            :         {
    1838         [ +  - ]:         13 :             B2DPolygon aRetval(createPolygonFromUnitCircle());
    1839         [ +  - ]:         13 :             const B2DHomMatrix aMatrix(createScaleTranslateB2DHomMatrix(fRadiusX, fRadiusY, rCenter.getX(), rCenter.getY()));
    1840                 :            : 
    1841         [ +  - ]:         13 :             aRetval.transform(aMatrix);
    1842                 :            : 
    1843         [ +  - ]:         13 :             return aRetval;
    1844                 :            :         }
    1845                 :            : 
    1846                 :        868 :         B2DPolygon createPolygonFromUnitEllipseSegment( double fStart, double fEnd )
    1847                 :            :         {
    1848                 :        868 :             B2DPolygon aRetval;
    1849                 :            : 
    1850                 :            :             // truncate fStart, fEnd to a range of [0.0 .. F_2PI[ where F_2PI
    1851                 :            :             // falls back to 0.0 to ensure a unique definition
    1852         [ -  + ]:        868 :             if(fTools::less(fStart, 0.0))
    1853                 :            :             {
    1854                 :          0 :                 fStart = 0.0;
    1855                 :            :             }
    1856                 :            : 
    1857         [ -  + ]:        868 :             if(fTools::moreOrEqual(fStart, F_2PI))
    1858                 :            :             {
    1859                 :          0 :                 fStart = 0.0;
    1860                 :            :             }
    1861                 :            : 
    1862         [ -  + ]:        868 :             if(fTools::less(fEnd, 0.0))
    1863                 :            :             {
    1864                 :          0 :                 fEnd = 0.0;
    1865                 :            :             }
    1866                 :            : 
    1867         [ -  + ]:        868 :             if(fTools::moreOrEqual(fEnd, F_2PI))
    1868                 :            :             {
    1869                 :          0 :                 fEnd = 0.0;
    1870                 :            :             }
    1871                 :            : 
    1872         [ -  + ]:        868 :             if(fTools::equal(fStart, fEnd))
    1873                 :            :             {
    1874                 :            :                 // same start and end angle, add single point
    1875         [ #  # ]:          0 :                 aRetval.append(B2DPoint(cos(fStart), sin(fStart)));
    1876                 :            :             }
    1877                 :            :             else
    1878                 :            :             {
    1879                 :        868 :                 const sal_uInt32 nSegments(STEPSPERQUARTER * 4);
    1880                 :        868 :                 const double fAnglePerSegment(F_PI2 / STEPSPERQUARTER);
    1881                 :        868 :                 const sal_uInt32 nStartSegment(sal_uInt32(fStart / fAnglePerSegment) % nSegments);
    1882                 :        868 :                 const sal_uInt32 nEndSegment(sal_uInt32(fEnd / fAnglePerSegment) % nSegments);
    1883                 :        868 :                 const double fKappa((M_SQRT2 - 1.0) * 4.0 / 3.0);
    1884                 :        868 :                 const double fScaledKappa(fKappa * (1.0 / STEPSPERQUARTER));
    1885                 :            : 
    1886                 :        868 :                 B2DPoint aSegStart(cos(fStart), sin(fStart));
    1887         [ +  - ]:        868 :                 aRetval.append(aSegStart);
    1888                 :            : 
    1889 [ +  + ][ +  - ]:        868 :                 if(nStartSegment == nEndSegment && fTools::more(fEnd, fStart))
                 [ +  + ]
    1890                 :            :                 {
    1891                 :            :                     // start and end in one sector and in the right order, create in one segment
    1892                 :         76 :                     const B2DPoint aSegEnd(cos(fEnd), sin(fEnd));
    1893                 :         76 :                     const double fFactor(fScaledKappa * ((fEnd - fStart) / fAnglePerSegment));
    1894                 :            : 
    1895                 :            :                     aRetval.appendBezierSegment(
    1896                 :         76 :                         aSegStart + (B2DPoint(-aSegStart.getY(), aSegStart.getX()) * fFactor),
    1897                 :         76 :                         aSegEnd - (B2DPoint(-aSegEnd.getY(), aSegEnd.getX()) * fFactor),
    1898         [ +  - ]:        228 :                         aSegEnd);
    1899                 :            :                 }
    1900                 :            :                 else
    1901                 :            :                 {
    1902                 :        792 :                     double fSegEndRad((nStartSegment + 1) * fAnglePerSegment);
    1903                 :        792 :                     double fFactor(fScaledKappa * ((fSegEndRad - fStart) / fAnglePerSegment));
    1904                 :        792 :                     B2DPoint aSegEnd(cos(fSegEndRad), sin(fSegEndRad));
    1905                 :            : 
    1906                 :            :                     aRetval.appendBezierSegment(
    1907                 :        792 :                         aSegStart + (B2DPoint(-aSegStart.getY(), aSegStart.getX()) * fFactor),
    1908                 :        792 :                         aSegEnd - (B2DPoint(-aSegEnd.getY(), aSegEnd.getX()) * fFactor),
    1909         [ +  - ]:       2376 :                         aSegEnd);
    1910                 :            : 
    1911                 :        792 :                     sal_uInt32 nSegment((nStartSegment + 1) % nSegments);
    1912                 :        792 :                     aSegStart = aSegEnd;
    1913                 :            : 
    1914         [ +  + ]:       1664 :                     while(nSegment != nEndSegment)
    1915                 :            :                     {
    1916                 :            :                         // No end in this sector, add full sector.
    1917                 :        872 :                         fSegEndRad = (nSegment + 1) * fAnglePerSegment;
    1918                 :        872 :                         aSegEnd = B2DPoint(cos(fSegEndRad), sin(fSegEndRad));
    1919                 :            : 
    1920                 :            :                         aRetval.appendBezierSegment(
    1921                 :        872 :                             aSegStart + (B2DPoint(-aSegStart.getY(), aSegStart.getX()) * fScaledKappa),
    1922                 :        872 :                             aSegEnd - (B2DPoint(-aSegEnd.getY(), aSegEnd.getX()) * fScaledKappa),
    1923         [ +  - ]:       2616 :                             aSegEnd);
    1924                 :            : 
    1925                 :        872 :                         nSegment = (nSegment + 1) % nSegments;
    1926                 :        872 :                         aSegStart = aSegEnd;
    1927                 :            :                     }
    1928                 :            : 
    1929                 :            :                     // End in this sector
    1930                 :        792 :                     const double fSegStartRad(nSegment * fAnglePerSegment);
    1931                 :        792 :                     fFactor = fScaledKappa * ((fEnd - fSegStartRad) / fAnglePerSegment);
    1932                 :        792 :                     aSegEnd = B2DPoint(cos(fEnd), sin(fEnd));
    1933                 :            : 
    1934                 :            :                     aRetval.appendBezierSegment(
    1935                 :        792 :                         aSegStart + (B2DPoint(-aSegStart.getY(), aSegStart.getX()) * fFactor),
    1936                 :        792 :                         aSegEnd - (B2DPoint(-aSegEnd.getY(), aSegEnd.getX()) * fFactor),
    1937         [ +  - ]:       2376 :                         aSegEnd);
    1938                 :        868 :                 }
    1939                 :            :             }
    1940                 :            : 
    1941                 :            :             // remove double points between segments created by segmented creation
    1942         [ +  - ]:        868 :             aRetval.removeDoublePoints();
    1943                 :            : 
    1944                 :        868 :             return aRetval;
    1945                 :            :         }
    1946                 :            : 
    1947                 :        868 :         B2DPolygon createPolygonFromEllipseSegment( const B2DPoint& rCenter, double fRadiusX, double fRadiusY, double fStart, double fEnd )
    1948                 :            :         {
    1949         [ +  - ]:        868 :             B2DPolygon aRetval(createPolygonFromUnitEllipseSegment(fStart, fEnd));
    1950         [ +  - ]:        868 :             const B2DHomMatrix aMatrix(createScaleTranslateB2DHomMatrix(fRadiusX, fRadiusY, rCenter.getX(), rCenter.getY()));
    1951                 :            : 
    1952         [ +  - ]:        868 :             aRetval.transform(aMatrix);
    1953                 :            : 
    1954         [ +  - ]:        868 :             return aRetval;
    1955                 :            :         }
    1956                 :            : 
    1957                 :       1170 :         bool hasNeutralPoints(const B2DPolygon& rCandidate)
    1958                 :            :         {
    1959                 :            :             OSL_ENSURE(!rCandidate.areControlPointsUsed(), "hasNeutralPoints: ATM works not for curves (!)");
    1960                 :       1170 :             const sal_uInt32 nPointCount(rCandidate.count());
    1961                 :            : 
    1962         [ +  + ]:       1170 :             if(nPointCount > 2L)
    1963                 :            :             {
    1964         [ +  - ]:       1130 :                 B2DPoint aPrevPoint(rCandidate.getB2DPoint(nPointCount - 1L));
    1965         [ +  - ]:       1130 :                 B2DPoint aCurrPoint(rCandidate.getB2DPoint(0L));
    1966                 :            : 
    1967         [ +  + ]:       6650 :                 for(sal_uInt32 a(0L); a < nPointCount; a++)
    1968                 :            :                 {
    1969         [ +  - ]:       5520 :                     const B2DPoint aNextPoint(rCandidate.getB2DPoint((a + 1) % nPointCount));
    1970                 :       5520 :                     const B2DVector aPrevVec(aPrevPoint - aCurrPoint);
    1971                 :       5520 :                     const B2DVector aNextVec(aNextPoint - aCurrPoint);
    1972         [ +  - ]:       5520 :                     const B2VectorOrientation aOrientation(getOrientation(aNextVec, aPrevVec));
    1973                 :            : 
    1974         [ +  + ]:       5520 :                     if(ORIENTATION_NEUTRAL == aOrientation)
    1975                 :            :                     {
    1976                 :            :                         // current has neutral orientation
    1977                 :        165 :                         return true;
    1978                 :            :                     }
    1979                 :            :                     else
    1980                 :            :                     {
    1981                 :            :                         // prepare next
    1982                 :       5355 :                         aPrevPoint = aCurrPoint;
    1983         [ +  + ]:      10875 :                         aCurrPoint = aNextPoint;
    1984                 :            :                     }
    1985 [ +  + ][ +  + ]:      12170 :                 }
         [ +  + ][ +  + ]
    1986                 :            :             }
    1987                 :            : 
    1988                 :       1170 :             return false;
    1989                 :            :         }
    1990                 :            : 
    1991                 :       1170 :         B2DPolygon removeNeutralPoints(const B2DPolygon& rCandidate)
    1992                 :            :         {
    1993         [ +  + ]:       1170 :             if(hasNeutralPoints(rCandidate))
    1994                 :            :             {
    1995         [ +  - ]:        165 :                 const sal_uInt32 nPointCount(rCandidate.count());
    1996         [ +  - ]:        165 :                 B2DPolygon aRetval;
    1997         [ +  - ]:        165 :                 B2DPoint aPrevPoint(rCandidate.getB2DPoint(nPointCount - 1L));
    1998         [ +  - ]:        165 :                 B2DPoint aCurrPoint(rCandidate.getB2DPoint(0L));
    1999                 :            : 
    2000         [ +  + ]:       1555 :                 for(sal_uInt32 a(0L); a < nPointCount; a++)
    2001                 :            :                 {
    2002         [ +  - ]:       1390 :                     const B2DPoint aNextPoint(rCandidate.getB2DPoint((a + 1) % nPointCount));
    2003                 :       1390 :                     const B2DVector aPrevVec(aPrevPoint - aCurrPoint);
    2004                 :       1390 :                     const B2DVector aNextVec(aNextPoint - aCurrPoint);
    2005         [ +  - ]:       1390 :                     const B2VectorOrientation aOrientation(getOrientation(aNextVec, aPrevVec));
    2006                 :            : 
    2007         [ +  + ]:       1390 :                     if(ORIENTATION_NEUTRAL == aOrientation)
    2008                 :            :                     {
    2009                 :            :                         // current has neutral orientation, leave it out and prepare next
    2010                 :        650 :                         aCurrPoint = aNextPoint;
    2011                 :            :                     }
    2012                 :            :                     else
    2013                 :            :                     {
    2014                 :            :                         // add current point
    2015         [ +  - ]:        740 :                         aRetval.append(aCurrPoint);
    2016                 :            : 
    2017                 :            :                         // prepare next
    2018                 :        740 :                         aPrevPoint = aCurrPoint;
    2019                 :        740 :                         aCurrPoint = aNextPoint;
    2020                 :            :                     }
    2021                 :       1390 :                 }
    2022                 :            : 
    2023 [ +  - ][ +  + ]:        195 :                 while(aRetval.count() && ORIENTATION_NEUTRAL == getOrientationForIndex(aRetval, 0L))
         [ +  - ][ +  + ]
                 [ +  + ]
    2024                 :            :                 {
    2025         [ +  - ]:         30 :                     aRetval.remove(0L);
    2026                 :            :                 }
    2027                 :            : 
    2028                 :            :                 // copy closed state
    2029 [ +  - ][ +  - ]:        165 :                 aRetval.setClosed(rCandidate.isClosed());
    2030                 :            : 
    2031 [ +  - ][ +  - ]:        165 :                 return aRetval;
    2032                 :            :             }
    2033                 :            :             else
    2034                 :            :             {
    2035                 :       1170 :                 return rCandidate;
    2036                 :            :             }
    2037                 :            :         }
    2038                 :            : 
    2039                 :          0 :         bool isConvex(const B2DPolygon& rCandidate)
    2040                 :            :         {
    2041                 :            :             OSL_ENSURE(!rCandidate.areControlPointsUsed(), "isConvex: ATM works not for curves (!)");
    2042                 :          0 :             const sal_uInt32 nPointCount(rCandidate.count());
    2043                 :            : 
    2044         [ #  # ]:          0 :             if(nPointCount > 2L)
    2045                 :            :             {
    2046         [ #  # ]:          0 :                 const B2DPoint aPrevPoint(rCandidate.getB2DPoint(nPointCount - 1L));
    2047         [ #  # ]:          0 :                 B2DPoint aCurrPoint(rCandidate.getB2DPoint(0L));
    2048                 :          0 :                 B2DVector aCurrVec(aPrevPoint - aCurrPoint);
    2049                 :          0 :                 B2VectorOrientation aOrientation(ORIENTATION_NEUTRAL);
    2050                 :            : 
    2051         [ #  # ]:          0 :                 for(sal_uInt32 a(0L); a < nPointCount; a++)
    2052                 :            :                 {
    2053         [ #  # ]:          0 :                     const B2DPoint aNextPoint(rCandidate.getB2DPoint((a + 1) % nPointCount));
    2054                 :          0 :                     const B2DVector aNextVec(aNextPoint - aCurrPoint);
    2055         [ #  # ]:          0 :                     const B2VectorOrientation aCurrentOrientation(getOrientation(aNextVec, aCurrVec));
    2056                 :            : 
    2057         [ #  # ]:          0 :                     if(ORIENTATION_NEUTRAL == aOrientation)
    2058                 :            :                     {
    2059                 :            :                         // set start value, maybe neutral again
    2060                 :          0 :                         aOrientation = aCurrentOrientation;
    2061                 :            :                     }
    2062                 :            :                     else
    2063                 :            :                     {
    2064 [ #  # ][ #  # ]:          0 :                         if(ORIENTATION_NEUTRAL != aCurrentOrientation && aCurrentOrientation != aOrientation)
    2065                 :            :                         {
    2066                 :            :                             // different orientations found, that's it
    2067                 :          0 :                             return false;
    2068                 :            :                         }
    2069                 :            :                     }
    2070                 :            : 
    2071                 :            :                     // prepare next
    2072                 :          0 :                     aCurrPoint = aNextPoint;
    2073 [ #  # ][ #  # ]:          0 :                     aCurrVec = -aNextVec;
    2074 [ #  # ][ #  # ]:          0 :                 }
         [ #  # ][ #  # ]
    2075                 :            :             }
    2076                 :            : 
    2077                 :          0 :             return true;
    2078                 :            :         }
    2079                 :            : 
    2080                 :        175 :         B2VectorOrientation getOrientationForIndex(const B2DPolygon& rCandidate, sal_uInt32 nIndex)
    2081                 :            :         {
    2082                 :            :             OSL_ENSURE(nIndex < rCandidate.count(), "getOrientationForIndex: index out of range (!)");
    2083 [ +  - ][ +  - ]:        175 :             const B2DPoint aPrev(rCandidate.getB2DPoint(getIndexOfPredecessor(nIndex, rCandidate)));
    2084         [ +  - ]:        175 :             const B2DPoint aCurr(rCandidate.getB2DPoint(nIndex));
    2085 [ +  - ][ +  - ]:        175 :             const B2DPoint aNext(rCandidate.getB2DPoint(getIndexOfSuccessor(nIndex, rCandidate)));
    2086                 :        175 :             const B2DVector aBack(aPrev - aCurr);
    2087                 :        175 :             const B2DVector aForw(aNext - aCurr);
    2088                 :            : 
    2089         [ +  - ]:        175 :             return getOrientation(aForw, aBack);
    2090                 :            :         }
    2091                 :            : 
    2092                 :      39583 :         bool isPointOnLine(const B2DPoint& rStart, const B2DPoint& rEnd, const B2DPoint& rCandidate, bool bWithPoints)
    2093                 :            :         {
    2094 [ +  + ][ +  + ]:      39583 :             if(rCandidate.equal(rStart) || rCandidate.equal(rEnd))
                 [ +  + ]
    2095                 :            :             {
    2096                 :            :                 // candidate is in epsilon around start or end -> inside
    2097                 :       3561 :                 return bWithPoints;
    2098                 :            :             }
    2099         [ +  + ]:      36022 :             else if(rStart.equal(rEnd))
    2100                 :            :             {
    2101                 :            :                 // start and end are equal, but candidate is outside their epsilon -> outside
    2102                 :         30 :                 return false;
    2103                 :            :             }
    2104                 :            :             else
    2105                 :            :             {
    2106                 :      35992 :                 const B2DVector aEdgeVector(rEnd - rStart);
    2107                 :      35992 :                 const B2DVector aTestVector(rCandidate - rStart);
    2108                 :            : 
    2109 [ +  + ][ +  - ]:      35992 :                 if(areParallel(aEdgeVector, aTestVector))
    2110                 :            :                 {
    2111                 :       2598 :                     const double fZero(0.0);
    2112                 :       2598 :                     const double fOne(1.0);
    2113                 :       2598 :                     const double fParamTestOnCurr(fabs(aEdgeVector.getX()) > fabs(aEdgeVector.getY())
    2114                 :       1076 :                         ? aTestVector.getX() / aEdgeVector.getX()
    2115         [ +  + ]:       3674 :                         : aTestVector.getY() / aEdgeVector.getY());
    2116                 :            : 
    2117 [ +  + ][ +  + ]:       2598 :                     if(fTools::more(fParamTestOnCurr, fZero) && fTools::less(fParamTestOnCurr, fOne))
                 [ +  + ]
    2118                 :            :                     {
    2119                 :       2598 :                         return true;
    2120                 :            :                     }
    2121                 :            :                 }
    2122                 :            : 
    2123                 :      39583 :                 return false;
    2124                 :            :             }
    2125                 :            :         }
    2126                 :            : 
    2127                 :       6176 :         bool isPointOnPolygon(const B2DPolygon& rCandidate, const B2DPoint& rPoint, bool bWithPoints)
    2128                 :            :         {
    2129 [ +  - ][ -  + ]:       6176 :             const B2DPolygon aCandidate(rCandidate.areControlPointsUsed() ? rCandidate.getDefaultAdaptiveSubdivision() : rCandidate);
         [ #  # ][ +  - ]
    2130         [ +  - ]:       6176 :             const sal_uInt32 nPointCount(aCandidate.count());
    2131                 :            : 
    2132         [ +  - ]:       6176 :             if(nPointCount > 1L)
    2133                 :            :             {
    2134 [ +  - ][ +  - ]:       6176 :                 const sal_uInt32 nLoopCount(aCandidate.isClosed() ? nPointCount : nPointCount - 1L);
    2135         [ +  - ]:       6176 :                 B2DPoint aCurrentPoint(aCandidate.getB2DPoint(0L));
    2136                 :            : 
    2137         [ +  + ]:      45759 :                 for(sal_uInt32 a(0L); a < nLoopCount; a++)
    2138                 :            :                 {
    2139         [ +  - ]:      39583 :                     const B2DPoint aNextPoint(aCandidate.getB2DPoint((a + 1L) % nPointCount));
    2140                 :            : 
    2141 [ +  - ][ +  + ]:      39583 :                     if(isPointOnLine(aCurrentPoint, aNextPoint, rPoint, bWithPoints))
    2142                 :            :                     {
    2143                 :       3713 :                         return true;
    2144                 :            :                     }
    2145                 :            : 
    2146         [ +  + ]:      75453 :                     aCurrentPoint = aNextPoint;
    2147         [ +  + ]:      45759 :                 }
    2148                 :            :             }
    2149 [ #  # ][ #  # ]:          0 :             else if(nPointCount && bWithPoints)
    2150                 :            :             {
    2151         [ #  # ]:          0 :                 return rPoint.equal(aCandidate.getB2DPoint(0L));
    2152                 :            :             }
    2153                 :            : 
    2154         [ +  - ]:       6176 :             return false;
    2155                 :            :         }
    2156                 :            : 
    2157                 :          0 :         bool isPointInTriangle(const B2DPoint& rA, const B2DPoint& rB, const B2DPoint& rC, const B2DPoint& rCandidate, bool bWithBorder)
    2158                 :            :         {
    2159         [ #  # ]:          0 :             if(arePointsOnSameSideOfLine(rA, rB, rC, rCandidate, bWithBorder))
    2160                 :            :             {
    2161         [ #  # ]:          0 :                 if(arePointsOnSameSideOfLine(rB, rC, rA, rCandidate, bWithBorder))
    2162                 :            :                 {
    2163         [ #  # ]:          0 :                     if(arePointsOnSameSideOfLine(rC, rA, rB, rCandidate, bWithBorder))
    2164                 :            :                     {
    2165                 :          0 :                         return true;
    2166                 :            :                     }
    2167                 :            :                 }
    2168                 :            :             }
    2169                 :            : 
    2170                 :          0 :             return false;
    2171                 :            :         }
    2172                 :            : 
    2173                 :          0 :         bool arePointsOnSameSideOfLine(const B2DPoint& rStart, const B2DPoint& rEnd, const B2DPoint& rCandidateA, const B2DPoint& rCandidateB, bool bWithLine)
    2174                 :            :         {
    2175                 :          0 :             const B2DVector aLineVector(rEnd - rStart);
    2176                 :          0 :             const B2DVector aVectorToA(rEnd - rCandidateA);
    2177         [ #  # ]:          0 :             const double fCrossA(aLineVector.cross(aVectorToA));
    2178                 :            : 
    2179         [ #  # ]:          0 :             if(fTools::equalZero(fCrossA))
    2180                 :            :             {
    2181                 :            :                 // one point on the line
    2182                 :          0 :                 return bWithLine;
    2183                 :            :             }
    2184                 :            : 
    2185                 :          0 :             const B2DVector aVectorToB(rEnd - rCandidateB);
    2186         [ #  # ]:          0 :             const double fCrossB(aLineVector.cross(aVectorToB));
    2187                 :            : 
    2188         [ #  # ]:          0 :             if(fTools::equalZero(fCrossB))
    2189                 :            :             {
    2190                 :            :                 // one point on the line
    2191                 :          0 :                 return bWithLine;
    2192                 :            :             }
    2193                 :            : 
    2194                 :            :             // return true if they both have the same sign
    2195                 :          0 :             return ((fCrossA > 0.0) == (fCrossB > 0.0));
    2196                 :            :         }
    2197                 :            : 
    2198                 :          0 :         void addTriangleFan(const B2DPolygon& rCandidate, B2DPolygon& rTarget)
    2199                 :            :         {
    2200                 :          0 :             const sal_uInt32 nCount(rCandidate.count());
    2201                 :            : 
    2202         [ #  # ]:          0 :             if(nCount > 2L)
    2203                 :            :             {
    2204         [ #  # ]:          0 :                 const B2DPoint aStart(rCandidate.getB2DPoint(0L));
    2205         [ #  # ]:          0 :                 B2DPoint aLast(rCandidate.getB2DPoint(1L));
    2206                 :            : 
    2207         [ #  # ]:          0 :                 for(sal_uInt32 a(2L); a < nCount; a++)
    2208                 :            :                 {
    2209         [ #  # ]:          0 :                     const B2DPoint aCurrent(rCandidate.getB2DPoint(a));
    2210         [ #  # ]:          0 :                     rTarget.append(aStart);
    2211         [ #  # ]:          0 :                     rTarget.append(aLast);
    2212         [ #  # ]:          0 :                     rTarget.append(aCurrent);
    2213                 :            : 
    2214                 :            :                     // prepare next
    2215                 :          0 :                     aLast = aCurrent;
    2216                 :          0 :                 }
    2217                 :            :             }
    2218                 :          0 :         }
    2219                 :            : 
    2220                 :            :         namespace
    2221                 :            :         {
    2222                 :            :             /// return 0 for input of 0, -1 for negative and 1 for positive input
    2223                 :        270 :             inline int lcl_sgn( const double n )
    2224                 :            :             {
    2225         [ +  + ]:        270 :                 return n == 0.0 ? 0 : 1 - 2*::rtl::math::isSignBitSet(n);
    2226                 :            :             }
    2227                 :            :         }
    2228                 :            : 
    2229                 :         50 :         bool isRectangle( const B2DPolygon& rPoly )
    2230                 :            :         {
    2231                 :            :             // polygon must be closed to resemble a rect, and contain
    2232                 :            :             // at least four points.
    2233   [ +  +  +  +  :        135 :             if( !rPoly.isClosed() ||
           +  + ][ +  + ]
    2234                 :         45 :                 rPoly.count() < 4 ||
    2235                 :         40 :                 rPoly.areControlPointsUsed() )
    2236                 :            :             {
    2237                 :         15 :                 return false;
    2238                 :            :             }
    2239                 :            : 
    2240                 :            :             // number of 90 degree turns the polygon has taken
    2241                 :         35 :             int nNumTurns(0);
    2242                 :            : 
    2243                 :         35 :             int  nVerticalEdgeType=0;
    2244                 :         35 :             int  nHorizontalEdgeType=0;
    2245                 :         35 :             bool bNullVertex(true);
    2246                 :         35 :             bool bCWPolygon(false);  // when true, polygon is CW
    2247                 :            :                                      // oriented, when false, CCW
    2248                 :         35 :             bool bOrientationSet(false); // when false, polygon
    2249                 :            :                                          // orientation has not yet
    2250                 :            :                                          // been determined.
    2251                 :            : 
    2252                 :            :             // scan all _edges_ (which involves coming back to point 0
    2253                 :            :             // for the last edge - thus the modulo operation below)
    2254                 :         35 :             const sal_Int32 nCount( rPoly.count() );
    2255         [ +  + ]:        160 :             for( sal_Int32 i=0; i<nCount; ++i )
    2256                 :            :             {
    2257                 :        135 :                 const B2DPoint& rPoint0( rPoly.getB2DPoint(i % nCount) );
    2258         [ +  - ]:        135 :                 const B2DPoint& rPoint1( rPoly.getB2DPoint((i+1) % nCount) );
    2259                 :            : 
    2260                 :            :                 // is 0 for zero direction vector, 1 for south edge and -1
    2261                 :            :                 // for north edge (standard screen coordinate system)
    2262                 :        135 :                 int nCurrVerticalEdgeType( lcl_sgn( rPoint1.getY() - rPoint0.getY() ) );
    2263                 :            : 
    2264                 :            :                 // is 0 for zero direction vector, 1 for east edge and -1
    2265                 :            :                 // for west edge (standard screen coordinate system)
    2266                 :        135 :                 int nCurrHorizontalEdgeType( lcl_sgn(rPoint1.getX() - rPoint0.getX()) );
    2267                 :            : 
    2268 [ +  + ][ +  + ]:        135 :                 if( nCurrVerticalEdgeType && nCurrHorizontalEdgeType )
    2269                 :          5 :                     return false; // oblique edge - for sure no rect
    2270                 :            : 
    2271 [ +  + ][ -  + ]:        130 :                 const bool bCurrNullVertex( !nCurrVerticalEdgeType && !nCurrHorizontalEdgeType );
    2272                 :            : 
    2273                 :            :                 // current vertex is equal to previous - just skip,
    2274                 :            :                 // until we have a real edge
    2275         [ -  + ]:        130 :                 if( bCurrNullVertex )
    2276                 :          0 :                     continue;
    2277                 :            : 
    2278                 :            :                 // if previous edge has two identical points, because
    2279                 :            :                 // no previous edge direction was available, simply
    2280                 :            :                 // take this first non-null edge as the start
    2281                 :            :                 // direction. That's what will happen here, if
    2282                 :            :                 // bNullVertex is false
    2283         [ +  + ]:        130 :                 if( !bNullVertex )
    2284                 :            :                 {
    2285                 :            :                     // 2D cross product - is 1 for CW and -1 for CCW turns
    2286                 :            :                     const int nCrossProduct( nHorizontalEdgeType*nCurrVerticalEdgeType -
    2287                 :        100 :                                              nVerticalEdgeType*nCurrHorizontalEdgeType );
    2288                 :            : 
    2289         [ +  + ]:        100 :                     if( !nCrossProduct )
    2290                 :          5 :                         continue; // no change in orientation -
    2291                 :            :                                   // collinear edges - just go on
    2292                 :            : 
    2293                 :            :                     // if polygon orientation is not set, we'll
    2294                 :            :                     // determine it now
    2295         [ +  + ]:         95 :                     if( !bOrientationSet )
    2296                 :            :                     {
    2297                 :         30 :                         bCWPolygon = nCrossProduct == 1;
    2298                 :         30 :                         bOrientationSet = true;
    2299                 :            :                     }
    2300                 :            :                     else
    2301                 :            :                     {
    2302                 :            :                         // if current turn orientation is not equal
    2303                 :            :                         // initial orientation, this is not a
    2304                 :            :                         // rectangle (as rectangles have consistent
    2305                 :            :                         // orientation).
    2306         [ +  + ]:         65 :                         if( (nCrossProduct == 1) != bCWPolygon )
    2307                 :          5 :                             return false;
    2308                 :            :                     }
    2309                 :            : 
    2310                 :         90 :                     ++nNumTurns;
    2311                 :            : 
    2312                 :            :                     // More than four 90 degree turns are an
    2313                 :            :                     // indication that this must not be a rectangle.
    2314         [ -  + ]:         90 :                     if( nNumTurns > 4 )
    2315                 :          0 :                         return false;
    2316                 :            :                 }
    2317                 :            : 
    2318                 :            :                 // store current state for the next turn
    2319                 :        120 :                 nVerticalEdgeType   = nCurrVerticalEdgeType;
    2320                 :        120 :                 nHorizontalEdgeType = nCurrHorizontalEdgeType;
    2321      [ +  +  + ]:        255 :                 bNullVertex         = false; // won't reach this line,
    2322                 :            :                                              // if bCurrNullVertex is
    2323                 :            :                                              // true - see above
    2324         [ +  + ]:        270 :             }
    2325                 :            : 
    2326                 :         50 :             return true;
    2327                 :            :         }
    2328                 :            : 
    2329                 :      12740 :         B3DPolygon createB3DPolygonFromB2DPolygon(const B2DPolygon& rCandidate, double fZCoordinate)
    2330                 :            :         {
    2331         [ -  + ]:      12740 :             if(rCandidate.areControlPointsUsed())
    2332                 :            :             {
    2333                 :            :                 // call myself recursively with subdivided input
    2334         [ #  # ]:          0 :                 const B2DPolygon aCandidate(adaptiveSubdivideByAngle(rCandidate));
    2335 [ #  # ][ #  # ]:          0 :                 return createB3DPolygonFromB2DPolygon(aCandidate, fZCoordinate);
    2336                 :            :             }
    2337                 :            :             else
    2338                 :            :             {
    2339         [ +  - ]:      12740 :                 B3DPolygon aRetval;
    2340                 :            : 
    2341 [ +  - ][ +  + ]:      56224 :                 for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
    2342                 :            :                 {
    2343         [ +  - ]:      43484 :                     B2DPoint aPoint(rCandidate.getB2DPoint(a));
    2344         [ +  - ]:      43484 :                     aRetval.append(B3DPoint(aPoint.getX(), aPoint.getY(), fZCoordinate));
    2345                 :      43484 :                 }
    2346                 :            : 
    2347                 :            :                 // copy closed state
    2348 [ +  - ][ +  - ]:      12740 :                 aRetval.setClosed(rCandidate.isClosed());
    2349                 :            : 
    2350 [ +  - ][ +  - ]:      12740 :                 return aRetval;
    2351                 :            :             }
    2352                 :            :         }
    2353                 :            : 
    2354                 :       1939 :         B2DPolygon createB2DPolygonFromB3DPolygon(const B3DPolygon& rCandidate, const B3DHomMatrix& rMat)
    2355                 :            :         {
    2356                 :       1939 :             B2DPolygon aRetval;
    2357         [ +  - ]:       1939 :             const sal_uInt32 nCount(rCandidate.count());
    2358         [ +  - ]:       1939 :             const bool bIsIdentity(rMat.isIdentity());
    2359                 :            : 
    2360         [ +  + ]:       9695 :             for(sal_uInt32 a(0L); a < nCount; a++)
    2361                 :            :             {
    2362         [ +  - ]:       7756 :                 B3DPoint aCandidate(rCandidate.getB3DPoint(a));
    2363                 :            : 
    2364         [ -  + ]:       7756 :                 if(!bIsIdentity)
    2365                 :            :                 {
    2366         [ #  # ]:          0 :                     aCandidate *= rMat;
    2367                 :            :                 }
    2368                 :            : 
    2369         [ +  - ]:       7756 :                 aRetval.append(B2DPoint(aCandidate.getX(), aCandidate.getY()));
    2370                 :       7756 :             }
    2371                 :            : 
    2372                 :            :             // copy closed state
    2373 [ +  - ][ +  - ]:       1939 :             aRetval.setClosed(rCandidate.isClosed());
    2374                 :            : 
    2375                 :       1939 :             return aRetval;
    2376                 :            :         }
    2377                 :            : 
    2378                 :          0 :         double getSmallestDistancePointToEdge(const B2DPoint& rPointA, const B2DPoint& rPointB, const B2DPoint& rTestPoint, double& rCut)
    2379                 :            :         {
    2380         [ #  # ]:          0 :             if(rPointA.equal(rPointB))
    2381                 :            :             {
    2382                 :          0 :                 rCut = 0.0;
    2383                 :          0 :                 const B2DVector aVector(rTestPoint - rPointA);
    2384         [ #  # ]:          0 :                 return aVector.getLength();
    2385                 :            :             }
    2386                 :            :             else
    2387                 :            :             {
    2388                 :            :                 // get the relative cut value on line vector (Vector1) for cut with perpendicular through TestPoint
    2389                 :          0 :                 const B2DVector aVector1(rPointB - rPointA);
    2390                 :          0 :                 const B2DVector aVector2(rTestPoint - rPointA);
    2391                 :          0 :                 const double fDividend((aVector2.getX() * aVector1.getX()) + (aVector2.getY() * aVector1.getY()));
    2392                 :          0 :                 const double fDivisor((aVector1.getX() * aVector1.getX()) + (aVector1.getY() * aVector1.getY()));
    2393                 :          0 :                 const double fCut(fDividend / fDivisor);
    2394                 :            : 
    2395         [ #  # ]:          0 :                 if(fCut < 0.0)
    2396                 :            :                 {
    2397                 :            :                     // not in line range, get distance to PointA
    2398                 :          0 :                     rCut = 0.0;
    2399         [ #  # ]:          0 :                     return aVector2.getLength();
    2400                 :            :                 }
    2401         [ #  # ]:          0 :                 else if(fCut > 1.0)
    2402                 :            :                 {
    2403                 :            :                     // not in line range, get distance to PointB
    2404                 :          0 :                     rCut = 1.0;
    2405                 :          0 :                     const B2DVector aVector(rTestPoint - rPointB);
    2406         [ #  # ]:          0 :                     return aVector.getLength();
    2407                 :            :                 }
    2408                 :            :                 else
    2409                 :            :                 {
    2410                 :            :                     // in line range
    2411                 :          0 :                     const B2DPoint aCutPoint(rPointA + fCut * aVector1);
    2412                 :          0 :                     const B2DVector aVector(rTestPoint - aCutPoint);
    2413                 :          0 :                     rCut = fCut;
    2414         [ #  # ]:          0 :                     return aVector.getLength();
    2415                 :          0 :                 }
    2416                 :            :             }
    2417                 :            :         }
    2418                 :            : 
    2419                 :          0 :         double getSmallestDistancePointToPolygon(const B2DPolygon& rCandidate, const B2DPoint& rTestPoint, sal_uInt32& rEdgeIndex, double& rCut)
    2420                 :            :         {
    2421                 :          0 :             double fRetval(DBL_MAX);
    2422         [ #  # ]:          0 :             const sal_uInt32 nPointCount(rCandidate.count());
    2423                 :            : 
    2424         [ #  # ]:          0 :             if(nPointCount > 1L)
    2425                 :            :             {
    2426                 :          0 :                 const double fZero(0.0);
    2427 [ #  # ][ #  # ]:          0 :                 const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1L);
    2428         [ #  # ]:          0 :                 B2DCubicBezier aBezier;
    2429         [ #  # ]:          0 :                 aBezier.setStartPoint(rCandidate.getB2DPoint(0));
    2430                 :            : 
    2431         [ #  # ]:          0 :                 for(sal_uInt32 a(0L); a < nEdgeCount; a++)
    2432                 :            :                 {
    2433                 :          0 :                     const sal_uInt32 nNextIndex((a + 1) % nPointCount);
    2434         [ #  # ]:          0 :                     aBezier.setEndPoint(rCandidate.getB2DPoint(nNextIndex));
    2435                 :            :                     double fEdgeDist;
    2436                 :            :                     double fNewCut;
    2437                 :          0 :                     bool bEdgeIsCurve(false);
    2438                 :            : 
    2439 [ #  # ][ #  # ]:          0 :                     if(rCandidate.areControlPointsUsed())
    2440                 :            :                     {
    2441         [ #  # ]:          0 :                         aBezier.setControlPointA(rCandidate.getNextControlPoint(a));
    2442         [ #  # ]:          0 :                         aBezier.setControlPointB(rCandidate.getPrevControlPoint(nNextIndex));
    2443         [ #  # ]:          0 :                         aBezier.testAndSolveTrivialBezier();
    2444         [ #  # ]:          0 :                         bEdgeIsCurve = aBezier.isBezier();
    2445                 :            :                     }
    2446                 :            : 
    2447         [ #  # ]:          0 :                     if(bEdgeIsCurve)
    2448                 :            :                     {
    2449         [ #  # ]:          0 :                         fEdgeDist = aBezier.getSmallestDistancePointToBezierSegment(rTestPoint, fNewCut);
    2450                 :            :                     }
    2451                 :            :                     else
    2452                 :            :                     {
    2453         [ #  # ]:          0 :                         fEdgeDist = getSmallestDistancePointToEdge(aBezier.getStartPoint(), aBezier.getEndPoint(), rTestPoint, fNewCut);
    2454                 :            :                     }
    2455                 :            : 
    2456 [ #  # ][ #  # ]:          0 :                     if(DBL_MAX == fRetval || fEdgeDist < fRetval)
    2457                 :            :                     {
    2458                 :          0 :                         fRetval = fEdgeDist;
    2459                 :          0 :                         rEdgeIndex = a;
    2460                 :          0 :                         rCut = fNewCut;
    2461                 :            : 
    2462         [ #  # ]:          0 :                         if(fTools::equal(fRetval, fZero))
    2463                 :            :                         {
    2464                 :            :                             // already found zero distance, cannot get better. Ensure numerical zero value and end loop.
    2465                 :          0 :                             fRetval = 0.0;
    2466                 :            :                             break;
    2467                 :            :                         }
    2468                 :            :                     }
    2469                 :            : 
    2470                 :            :                     // prepare next step
    2471                 :          0 :                     aBezier.setStartPoint(aBezier.getEndPoint());
    2472                 :            :                 }
    2473                 :            : 
    2474         [ #  # ]:          0 :                 if(1.0 == rCut)
    2475                 :            :                 {
    2476                 :            :                     // correct rEdgeIndex when not last point
    2477 [ #  # ][ #  # ]:          0 :                     if(rCandidate.isClosed())
    2478                 :            :                     {
    2479         [ #  # ]:          0 :                         rEdgeIndex = getIndexOfSuccessor(rEdgeIndex, rCandidate);
    2480                 :          0 :                         rCut = 0.0;
    2481                 :            :                     }
    2482                 :            :                     else
    2483                 :            :                     {
    2484         [ #  # ]:          0 :                         if(rEdgeIndex != nEdgeCount - 1L)
    2485                 :            :                         {
    2486                 :          0 :                             rEdgeIndex++;
    2487                 :          0 :                             rCut = 0.0;
    2488                 :            :                         }
    2489                 :            :                     }
    2490         [ #  # ]:          0 :                 }
    2491                 :            :             }
    2492                 :            : 
    2493                 :          0 :             return fRetval;
    2494                 :            :         }
    2495                 :            : 
    2496                 :          0 :         B2DPoint distort(const B2DPoint& rCandidate, const B2DRange& rOriginal, const B2DPoint& rTopLeft, const B2DPoint& rTopRight, const B2DPoint& rBottomLeft, const B2DPoint& rBottomRight)
    2497                 :            :         {
    2498 [ #  # ][ #  # ]:          0 :             if(fTools::equalZero(rOriginal.getWidth()) || fTools::equalZero(rOriginal.getHeight()))
         [ #  # ][ #  # ]
         [ #  # ][ #  # ]
           [ #  #  #  #  
                   #  # ]
    2499                 :            :             {
    2500                 :          0 :                 return rCandidate;
    2501                 :            :             }
    2502                 :            :             else
    2503                 :            :             {
    2504                 :          0 :                 const double fRelativeX((rCandidate.getX() - rOriginal.getMinX()) / rOriginal.getWidth());
    2505                 :          0 :                 const double fRelativeY((rCandidate.getY() - rOriginal.getMinY()) / rOriginal.getHeight());
    2506                 :          0 :                 const double fOneMinusRelativeX(1.0 - fRelativeX);
    2507                 :          0 :                 const double fOneMinusRelativeY(1.0 - fRelativeY);
    2508                 :          0 :                 const double fNewX((fOneMinusRelativeY) * ((fOneMinusRelativeX) * rTopLeft.getX() + fRelativeX * rTopRight.getX()) +
    2509                 :          0 :                     fRelativeY * ((fOneMinusRelativeX) * rBottomLeft.getX() + fRelativeX * rBottomRight.getX()));
    2510                 :          0 :                 const double fNewY((fOneMinusRelativeX) * ((fOneMinusRelativeY) * rTopLeft.getY() + fRelativeY * rBottomLeft.getY()) +
    2511                 :          0 :                     fRelativeX * ((fOneMinusRelativeY) * rTopRight.getY() + fRelativeY * rBottomRight.getY()));
    2512                 :            : 
    2513                 :          0 :                 return B2DPoint(fNewX, fNewY);
    2514                 :            :             }
    2515                 :            :         }
    2516                 :            : 
    2517                 :          0 :         B2DPolygon distort(const B2DPolygon& rCandidate, const B2DRange& rOriginal, const B2DPoint& rTopLeft, const B2DPoint& rTopRight, const B2DPoint& rBottomLeft, const B2DPoint& rBottomRight)
    2518                 :            :         {
    2519                 :          0 :             const sal_uInt32 nPointCount(rCandidate.count());
    2520                 :            : 
    2521 [ #  # ][ #  # ]:          0 :             if(nPointCount && 0.0 != rOriginal.getWidth() && 0.0 != rOriginal.getHeight())
         [ #  # ][ #  # ]
    2522                 :            :             {
    2523         [ #  # ]:          0 :                 B2DPolygon aRetval;
    2524                 :            : 
    2525         [ #  # ]:          0 :                 for(sal_uInt32 a(0L); a < nPointCount; a++)
    2526                 :            :                 {
    2527 [ #  # ][ #  # ]:          0 :                     aRetval.append(distort(rCandidate.getB2DPoint(a), rOriginal, rTopLeft, rTopRight, rBottomLeft, rBottomRight));
                 [ #  # ]
    2528                 :            : 
    2529 [ #  # ][ #  # ]:          0 :                     if(rCandidate.areControlPointsUsed())
    2530                 :            :                     {
    2531 [ #  # ][ #  # ]:          0 :                         if(!rCandidate.getPrevControlPoint(a).equalZero())
                 [ #  # ]
    2532                 :            :                         {
    2533 [ #  # ][ #  # ]:          0 :                             aRetval.setPrevControlPoint(a, distort(rCandidate.getPrevControlPoint(a), rOriginal, rTopLeft, rTopRight, rBottomLeft, rBottomRight));
                 [ #  # ]
    2534                 :            :                         }
    2535                 :            : 
    2536 [ #  # ][ #  # ]:          0 :                         if(!rCandidate.getNextControlPoint(a).equalZero())
                 [ #  # ]
    2537                 :            :                         {
    2538 [ #  # ][ #  # ]:          0 :                             aRetval.setNextControlPoint(a, distort(rCandidate.getNextControlPoint(a), rOriginal, rTopLeft, rTopRight, rBottomLeft, rBottomRight));
                 [ #  # ]
    2539                 :            :                         }
    2540                 :            :                     }
    2541                 :            :                 }
    2542                 :            : 
    2543 [ #  # ][ #  # ]:          0 :                 aRetval.setClosed(rCandidate.isClosed());
    2544 [ #  # ][ #  # ]:          0 :                 return aRetval;
    2545                 :            :             }
    2546                 :            :             else
    2547                 :            :             {
    2548                 :          0 :                 return rCandidate;
    2549                 :            :             }
    2550                 :            :         }
    2551                 :            : 
    2552                 :         40 :         B2DPolygon expandToCurve(const B2DPolygon& rCandidate)
    2553                 :            :         {
    2554                 :         40 :             B2DPolygon aRetval(rCandidate);
    2555                 :            : 
    2556 [ +  - ][ +  + ]:        278 :             for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
    2557                 :            :             {
    2558         [ +  - ]:        238 :                 expandToCurveInPoint(aRetval, a);
    2559                 :            :             }
    2560                 :            : 
    2561                 :         40 :             return aRetval;
    2562                 :            :         }
    2563                 :            : 
    2564                 :        238 :         bool expandToCurveInPoint(B2DPolygon& rCandidate, sal_uInt32 nIndex)
    2565                 :            :         {
    2566                 :            :             OSL_ENSURE(nIndex < rCandidate.count(), "expandToCurveInPoint: Access to polygon out of range (!)");
    2567                 :        238 :             bool bRetval(false);
    2568                 :        238 :             const sal_uInt32 nPointCount(rCandidate.count());
    2569                 :            : 
    2570         [ +  - ]:        238 :             if(nPointCount)
    2571                 :            :             {
    2572                 :            :                 // predecessor
    2573         [ +  + ]:        238 :                 if(!rCandidate.isPrevControlPointUsed(nIndex))
    2574                 :            :                 {
    2575 [ +  + ][ +  + ]:         94 :                     if(!rCandidate.isClosed() && 0 == nIndex)
                 [ +  + ]
    2576                 :            :                     {
    2577                 :            :                         // do not create previous vector for start point of open polygon
    2578                 :            :                     }
    2579                 :            :                     else
    2580                 :            :                     {
    2581                 :         88 :                         const sal_uInt32 nPrevIndex((nIndex + (nPointCount - 1)) % nPointCount);
    2582 [ +  - ][ +  - ]:         88 :                         rCandidate.setPrevControlPoint(nIndex, interpolate(rCandidate.getB2DPoint(nIndex), rCandidate.getB2DPoint(nPrevIndex), 1.0 / 3.0));
    2583                 :         88 :                         bRetval = true;
    2584                 :            :                     }
    2585                 :            :                 }
    2586                 :            : 
    2587                 :            :                 // successor
    2588         [ +  + ]:        238 :                 if(!rCandidate.isNextControlPointUsed(nIndex))
    2589                 :            :                 {
    2590 [ +  + ][ +  + ]:         94 :                     if(!rCandidate.isClosed() && nIndex + 1 == nPointCount)
                 [ +  + ]
    2591                 :            :                     {
    2592                 :            :                         // do not create next vector for end point of open polygon
    2593                 :            :                     }
    2594                 :            :                     else
    2595                 :            :                     {
    2596                 :         88 :                         const sal_uInt32 nNextIndex((nIndex + 1) % nPointCount);
    2597 [ +  - ][ +  - ]:         88 :                         rCandidate.setNextControlPoint(nIndex, interpolate(rCandidate.getB2DPoint(nIndex), rCandidate.getB2DPoint(nNextIndex), 1.0 / 3.0));
    2598                 :         88 :                         bRetval = true;
    2599                 :            :                     }
    2600                 :            :                 }
    2601                 :            :             }
    2602                 :            : 
    2603                 :        238 :             return bRetval;
    2604                 :            :         }
    2605                 :            : 
    2606                 :          0 :         bool setContinuityInPoint(B2DPolygon& rCandidate, sal_uInt32 nIndex, B2VectorContinuity eContinuity)
    2607                 :            :         {
    2608                 :            :             OSL_ENSURE(nIndex < rCandidate.count(), "setContinuityInPoint: Access to polygon out of range (!)");
    2609                 :          0 :             bool bRetval(false);
    2610                 :          0 :             const sal_uInt32 nPointCount(rCandidate.count());
    2611                 :            : 
    2612         [ #  # ]:          0 :             if(nPointCount)
    2613                 :            :             {
    2614         [ #  # ]:          0 :                 const B2DPoint aCurrentPoint(rCandidate.getB2DPoint(nIndex));
    2615                 :            : 
    2616   [ #  #  #  # ]:          0 :                 switch(eContinuity)
    2617                 :            :                 {
    2618                 :            :                     case CONTINUITY_NONE :
    2619                 :            :                     {
    2620 [ #  # ][ #  # ]:          0 :                         if(rCandidate.isPrevControlPointUsed(nIndex))
    2621                 :            :                         {
    2622 [ #  # ][ #  # ]:          0 :                             if(!rCandidate.isClosed() && 0 == nIndex)
         [ #  # ][ #  # ]
    2623                 :            :                             {
    2624                 :            :                                 // remove existing previous vector for start point of open polygon
    2625         [ #  # ]:          0 :                                 rCandidate.resetPrevControlPoint(nIndex);
    2626                 :            :                             }
    2627                 :            :                             else
    2628                 :            :                             {
    2629                 :          0 :                                 const sal_uInt32 nPrevIndex((nIndex + (nPointCount - 1)) % nPointCount);
    2630 [ #  # ][ #  # ]:          0 :                                 rCandidate.setPrevControlPoint(nIndex, interpolate(aCurrentPoint, rCandidate.getB2DPoint(nPrevIndex), 1.0 / 3.0));
    2631                 :            :                             }
    2632                 :            : 
    2633                 :          0 :                             bRetval = true;
    2634                 :            :                         }
    2635                 :            : 
    2636 [ #  # ][ #  # ]:          0 :                         if(rCandidate.isNextControlPointUsed(nIndex))
    2637                 :            :                         {
    2638 [ #  # ][ #  # ]:          0 :                             if(!rCandidate.isClosed() && nIndex == nPointCount + 1)
         [ #  # ][ #  # ]
    2639                 :            :                             {
    2640                 :            :                                 // remove next vector for end point of open polygon
    2641         [ #  # ]:          0 :                                 rCandidate.resetNextControlPoint(nIndex);
    2642                 :            :                             }
    2643                 :            :                             else
    2644                 :            :                             {
    2645                 :          0 :                                 const sal_uInt32 nNextIndex((nIndex + 1) % nPointCount);
    2646 [ #  # ][ #  # ]:          0 :                                 rCandidate.setNextControlPoint(nIndex, interpolate(aCurrentPoint, rCandidate.getB2DPoint(nNextIndex), 1.0 / 3.0));
    2647                 :            :                             }
    2648                 :            : 
    2649                 :          0 :                             bRetval = true;
    2650                 :            :                         }
    2651                 :            : 
    2652                 :          0 :                         break;
    2653                 :            :                     }
    2654                 :            :                     case CONTINUITY_C1 :
    2655                 :            :                     {
    2656 [ #  # ][ #  # ]:          0 :                         if(rCandidate.isPrevControlPointUsed(nIndex) && rCandidate.isNextControlPointUsed(nIndex))
         [ #  # ][ #  # ]
                 [ #  # ]
    2657                 :            :                         {
    2658                 :            :                             // lengths both exist since both are used
    2659         [ #  # ]:          0 :                             B2DVector aVectorPrev(rCandidate.getPrevControlPoint(nIndex) - aCurrentPoint);
    2660         [ #  # ]:          0 :                             B2DVector aVectorNext(rCandidate.getNextControlPoint(nIndex) - aCurrentPoint);
    2661         [ #  # ]:          0 :                             const double fLenPrev(aVectorPrev.getLength());
    2662         [ #  # ]:          0 :                             const double fLenNext(aVectorNext.getLength());
    2663         [ #  # ]:          0 :                             aVectorPrev.normalize();
    2664         [ #  # ]:          0 :                             aVectorNext.normalize();
    2665         [ #  # ]:          0 :                             const B2VectorOrientation aOrientation(getOrientation(aVectorPrev, aVectorNext));
    2666                 :            : 
    2667 [ #  # ][ #  # ]:          0 :                             if(ORIENTATION_NEUTRAL == aOrientation && aVectorPrev.scalar(aVectorNext) < 0.0)
         [ #  # ][ #  # ]
    2668                 :            :                             {
    2669                 :            :                                 // parallel and opposite direction; check length
    2670         [ #  # ]:          0 :                                 if(fTools::equal(fLenPrev, fLenNext))
    2671                 :            :                                 {
    2672                 :            :                                     // this would be even C2, but we want C1. Use the lengths of the corresponding edges.
    2673                 :          0 :                                     const sal_uInt32 nPrevIndex((nIndex + (nPointCount - 1)) % nPointCount);
    2674                 :          0 :                                     const sal_uInt32 nNextIndex((nIndex + 1) % nPointCount);
    2675 [ #  # ][ #  # ]:          0 :                                     const double fLenPrevEdge(B2DVector(rCandidate.getB2DPoint(nPrevIndex) - aCurrentPoint).getLength() * (1.0 / 3.0));
    2676 [ #  # ][ #  # ]:          0 :                                     const double fLenNextEdge(B2DVector(rCandidate.getB2DPoint(nNextIndex) - aCurrentPoint).getLength() * (1.0 / 3.0));
    2677                 :            : 
    2678                 :            :                                     rCandidate.setControlPoints(nIndex,
    2679                 :            :                                         aCurrentPoint + (aVectorPrev * fLenPrevEdge),
    2680         [ #  # ]:          0 :                                         aCurrentPoint + (aVectorNext * fLenNextEdge));
    2681                 :          0 :                                     bRetval = true;
    2682                 :            :                                 }
    2683                 :            :                             }
    2684                 :            :                             else
    2685                 :            :                             {
    2686                 :            :                                 // not parallel or same direction, set vectors and length
    2687         [ #  # ]:          0 :                                 const B2DVector aNormalizedPerpendicular(getNormalizedPerpendicular(aVectorPrev + aVectorNext));
    2688                 :            : 
    2689         [ #  # ]:          0 :                                 if(ORIENTATION_POSITIVE == aOrientation)
    2690                 :            :                                 {
    2691                 :            :                                     rCandidate.setControlPoints(nIndex,
    2692                 :            :                                         aCurrentPoint - (aNormalizedPerpendicular * fLenPrev),
    2693         [ #  # ]:          0 :                                         aCurrentPoint + (aNormalizedPerpendicular * fLenNext));
    2694                 :            :                                 }
    2695                 :            :                                 else
    2696                 :            :                                 {
    2697                 :            :                                     rCandidate.setControlPoints(nIndex,
    2698                 :            :                                         aCurrentPoint + (aNormalizedPerpendicular * fLenPrev),
    2699         [ #  # ]:          0 :                                         aCurrentPoint - (aNormalizedPerpendicular * fLenNext));
    2700                 :            :                                 }
    2701                 :            : 
    2702                 :          0 :                                 bRetval = true;
    2703                 :          0 :                             }
    2704                 :            :                         }
    2705                 :          0 :                         break;
    2706                 :            :                     }
    2707                 :            :                     case CONTINUITY_C2 :
    2708                 :            :                     {
    2709 [ #  # ][ #  # ]:          0 :                         if(rCandidate.isPrevControlPointUsed(nIndex) && rCandidate.isNextControlPointUsed(nIndex))
         [ #  # ][ #  # ]
                 [ #  # ]
    2710                 :            :                         {
    2711                 :            :                             // lengths both exist since both are used
    2712         [ #  # ]:          0 :                             B2DVector aVectorPrev(rCandidate.getPrevControlPoint(nIndex) - aCurrentPoint);
    2713         [ #  # ]:          0 :                             B2DVector aVectorNext(rCandidate.getNextControlPoint(nIndex) - aCurrentPoint);
    2714 [ #  # ][ #  # ]:          0 :                             const double fCommonLength((aVectorPrev.getLength() + aVectorNext.getLength()) / 2.0);
    2715         [ #  # ]:          0 :                             aVectorPrev.normalize();
    2716         [ #  # ]:          0 :                             aVectorNext.normalize();
    2717         [ #  # ]:          0 :                             const B2VectorOrientation aOrientation(getOrientation(aVectorPrev, aVectorNext));
    2718                 :            : 
    2719 [ #  # ][ #  # ]:          0 :                             if(ORIENTATION_NEUTRAL == aOrientation && aVectorPrev.scalar(aVectorNext) < 0.0)
         [ #  # ][ #  # ]
    2720                 :            :                             {
    2721                 :            :                                 // parallel and opposite direction; set length. Use one direction for better numerical correctness
    2722                 :          0 :                                 const B2DVector aScaledDirection(aVectorPrev * fCommonLength);
    2723                 :            : 
    2724                 :            :                                 rCandidate.setControlPoints(nIndex,
    2725                 :            :                                     aCurrentPoint + aScaledDirection,
    2726         [ #  # ]:          0 :                                     aCurrentPoint - aScaledDirection);
    2727                 :            :                             }
    2728                 :            :                             else
    2729                 :            :                             {
    2730                 :            :                                 // not parallel or same direction, set vectors and length
    2731         [ #  # ]:          0 :                                 const B2DVector aNormalizedPerpendicular(getNormalizedPerpendicular(aVectorPrev + aVectorNext));
    2732                 :          0 :                                 const B2DVector aPerpendicular(aNormalizedPerpendicular * fCommonLength);
    2733                 :            : 
    2734         [ #  # ]:          0 :                                 if(ORIENTATION_POSITIVE == aOrientation)
    2735                 :            :                                 {
    2736                 :            :                                     rCandidate.setControlPoints(nIndex,
    2737                 :            :                                         aCurrentPoint - aPerpendicular,
    2738         [ #  # ]:          0 :                                         aCurrentPoint + aPerpendicular);
    2739                 :            :                                 }
    2740                 :            :                                 else
    2741                 :            :                                 {
    2742                 :            :                                     rCandidate.setControlPoints(nIndex,
    2743                 :            :                                         aCurrentPoint + aPerpendicular,
    2744         [ #  # ]:          0 :                                         aCurrentPoint - aPerpendicular);
    2745                 :          0 :                                 }
    2746                 :            :                             }
    2747                 :            : 
    2748                 :          0 :                             bRetval = true;
    2749                 :            :                         }
    2750                 :          0 :                         break;
    2751                 :            :                     }
    2752                 :          0 :                 }
    2753                 :            :             }
    2754                 :            : 
    2755                 :          0 :             return bRetval;
    2756                 :            :         }
    2757                 :            : 
    2758                 :       3002 :         B2DPolygon growInNormalDirection(const B2DPolygon& rCandidate, double fValue)
    2759                 :            :         {
    2760         [ +  - ]:       3002 :             if(0.0 != fValue)
    2761                 :            :             {
    2762         [ -  + ]:       3002 :                 if(rCandidate.areControlPointsUsed())
    2763                 :            :                 {
    2764                 :            :                     // call myself recursively with subdivided input
    2765         [ #  # ]:          0 :                     const B2DPolygon aCandidate(adaptiveSubdivideByAngle(rCandidate));
    2766 [ #  # ][ #  # ]:          0 :                     return growInNormalDirection(aCandidate, fValue);
    2767                 :            :                 }
    2768                 :            :                 else
    2769                 :            :                 {
    2770         [ +  - ]:       3002 :                     B2DPolygon aRetval;
    2771         [ +  - ]:       3002 :                     const sal_uInt32 nPointCount(rCandidate.count());
    2772                 :            : 
    2773         [ +  - ]:       3002 :                     if(nPointCount)
    2774                 :            :                     {
    2775         [ +  - ]:       3002 :                         B2DPoint aPrev(rCandidate.getB2DPoint(nPointCount - 1L));
    2776         [ +  - ]:       3002 :                         B2DPoint aCurrent(rCandidate.getB2DPoint(0L));
    2777                 :            : 
    2778         [ +  + ]:      12008 :                         for(sal_uInt32 a(0L); a < nPointCount; a++)
    2779                 :            :                         {
    2780 [ +  + ][ +  - ]:       9006 :                             const B2DPoint aNext(rCandidate.getB2DPoint(a + 1L == nPointCount ? 0L : a + 1L));
    2781                 :       9006 :                             const B2DVector aBack(aPrev - aCurrent);
    2782                 :       9006 :                             const B2DVector aForw(aNext - aCurrent);
    2783         [ +  - ]:       9006 :                             const B2DVector aPerpBack(getNormalizedPerpendicular(aBack));
    2784         [ +  - ]:       9006 :                             const B2DVector aPerpForw(getNormalizedPerpendicular(aForw));
    2785                 :       9006 :                             B2DVector aDirection(aPerpBack - aPerpForw);
    2786         [ +  - ]:       9006 :                             aDirection.normalize();
    2787                 :       9006 :                             aDirection *= fValue;
    2788         [ +  - ]:       9006 :                             aRetval.append(aCurrent + aDirection);
    2789                 :            : 
    2790                 :            :                             // prepare next step
    2791                 :       9006 :                             aPrev = aCurrent;
    2792                 :       9006 :                             aCurrent = aNext;
    2793                 :      12008 :                         }
    2794                 :            :                     }
    2795                 :            : 
    2796                 :            :                     // copy closed state
    2797 [ +  - ][ +  - ]:       3002 :                     aRetval.setClosed(rCandidate.isClosed());
    2798                 :            : 
    2799 [ +  - ][ +  - ]:       3002 :                     return aRetval;
    2800                 :            :                 }
    2801                 :            :             }
    2802                 :            :             else
    2803                 :            :             {
    2804                 :       3002 :                 return rCandidate;
    2805                 :            :             }
    2806                 :            :         }
    2807                 :            : 
    2808                 :          0 :         B2DPolygon reSegmentPolygon(const B2DPolygon& rCandidate, sal_uInt32 nSegments)
    2809                 :            :         {
    2810                 :          0 :             B2DPolygon aRetval;
    2811         [ #  # ]:          0 :             const sal_uInt32 nPointCount(rCandidate.count());
    2812                 :            : 
    2813 [ #  # ][ #  # ]:          0 :             if(nPointCount && nSegments)
    2814                 :            :             {
    2815                 :            :                 // get current segment count
    2816 [ #  # ][ #  # ]:          0 :                 const sal_uInt32 nSegmentCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1L);
    2817                 :            : 
    2818         [ #  # ]:          0 :                 if(nSegmentCount == nSegments)
    2819                 :            :                 {
    2820         [ #  # ]:          0 :                     aRetval = rCandidate;
    2821                 :            :                 }
    2822                 :            :                 else
    2823                 :            :                 {
    2824         [ #  # ]:          0 :                     const double fLength(getLength(rCandidate));
    2825 [ #  # ][ #  # ]:          0 :                     const sal_uInt32 nLoopCount(rCandidate.isClosed() ? nSegments : nSegments + 1L);
    2826                 :            : 
    2827         [ #  # ]:          0 :                     for(sal_uInt32 a(0L); a < nLoopCount; a++)
    2828                 :            :                     {
    2829                 :          0 :                         const double fRelativePos((double)a / (double)nSegments); // 0.0 .. 1.0
    2830         [ #  # ]:          0 :                         const B2DPoint aNewPoint(getPositionRelative(rCandidate, fRelativePos, fLength));
    2831         [ #  # ]:          0 :                         aRetval.append(aNewPoint);
    2832                 :          0 :                     }
    2833                 :            : 
    2834                 :            :                     // copy closed flag
    2835 [ #  # ][ #  # ]:          0 :                     aRetval.setClosed(rCandidate.isClosed());
    2836                 :            :                 }
    2837                 :            :             }
    2838                 :            : 
    2839                 :          0 :             return aRetval;
    2840                 :            :         }
    2841                 :            : 
    2842                 :          0 :         B2DPolygon interpolate(const B2DPolygon& rOld1, const B2DPolygon& rOld2, double t)
    2843                 :            :         {
    2844                 :            :             OSL_ENSURE(rOld1.count() == rOld2.count(), "B2DPolygon interpolate: Different geometry (!)");
    2845                 :            : 
    2846 [ #  # ][ #  # ]:          0 :             if(fTools::lessOrEqual(t, 0.0) || rOld1 == rOld2)
         [ #  # ][ #  # ]
           [ #  #  #  # ]
    2847                 :            :             {
    2848                 :          0 :                 return rOld1;
    2849                 :            :             }
    2850         [ #  # ]:          0 :             else if(fTools::moreOrEqual(t, 1.0))
    2851                 :            :             {
    2852                 :          0 :                 return rOld2;
    2853                 :            :             }
    2854                 :            :             else
    2855                 :            :             {
    2856         [ #  # ]:          0 :                 B2DPolygon aRetval;
    2857 [ #  # ][ #  # ]:          0 :                 const bool bInterpolateVectors(rOld1.areControlPointsUsed() || rOld2.areControlPointsUsed());
         [ #  # ][ #  # ]
    2858 [ #  # ][ #  # ]:          0 :                 aRetval.setClosed(rOld1.isClosed() && rOld2.isClosed());
         [ #  # ][ #  # ]
                 [ #  # ]
    2859                 :            : 
    2860 [ #  # ][ #  # ]:          0 :                 for(sal_uInt32 a(0L); a < rOld1.count(); a++)
    2861                 :            :                 {
    2862 [ #  # ][ #  # ]:          0 :                     aRetval.append(interpolate(rOld1.getB2DPoint(a), rOld2.getB2DPoint(a), t));
                 [ #  # ]
    2863                 :            : 
    2864         [ #  # ]:          0 :                     if(bInterpolateVectors)
    2865                 :            :                     {
    2866 [ #  # ][ #  # ]:          0 :                         aRetval.setPrevControlPoint(a, interpolate(rOld1.getPrevControlPoint(a), rOld2.getPrevControlPoint(a), t));
                 [ #  # ]
    2867 [ #  # ][ #  # ]:          0 :                         aRetval.setNextControlPoint(a, interpolate(rOld1.getNextControlPoint(a), rOld2.getNextControlPoint(a), t));
                 [ #  # ]
    2868                 :            :                     }
    2869                 :            :                 }
    2870                 :            : 
    2871 [ #  # ][ #  # ]:          0 :                 return aRetval;
    2872                 :            :             }
    2873                 :            :         }
    2874                 :            : 
    2875                 :            :         // #i76891#
    2876                 :      20838 :         B2DPolygon simplifyCurveSegments(const B2DPolygon& rCandidate)
    2877                 :            :         {
    2878                 :      20838 :             const sal_uInt32 nPointCount(rCandidate.count());
    2879                 :            : 
    2880 [ +  + ][ +  + ]:      20838 :             if(nPointCount && rCandidate.areControlPointsUsed())
                 [ +  - ]
    2881                 :            :             {
    2882                 :            :                 // prepare loop
    2883 [ +  - ][ +  + ]:        180 :                 const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1);
    2884         [ +  - ]:        180 :                 B2DPolygon aRetval;
    2885         [ +  - ]:        180 :                 B2DCubicBezier aBezier;
    2886         [ +  - ]:        180 :                 aBezier.setStartPoint(rCandidate.getB2DPoint(0));
    2887                 :            : 
    2888                 :            :                 // try to avoid costly reallocations
    2889         [ +  - ]:        180 :                 aRetval.reserve( nEdgeCount+1);
    2890                 :            : 
    2891                 :            :                 // add start point
    2892         [ +  - ]:        180 :                 aRetval.append(aBezier.getStartPoint());
    2893                 :            : 
    2894         [ +  + ]:       1248 :                 for(sal_uInt32 a(0L); a < nEdgeCount; a++)
    2895                 :            :                 {
    2896                 :            :                     // get values for edge
    2897                 :       1068 :                     const sal_uInt32 nNextIndex((a + 1) % nPointCount);
    2898         [ +  - ]:       1068 :                     aBezier.setEndPoint(rCandidate.getB2DPoint(nNextIndex));
    2899         [ +  - ]:       1068 :                     aBezier.setControlPointA(rCandidate.getNextControlPoint(a));
    2900         [ +  - ]:       1068 :                     aBezier.setControlPointB(rCandidate.getPrevControlPoint(nNextIndex));
    2901         [ +  - ]:       1068 :                     aBezier.testAndSolveTrivialBezier();
    2902                 :            : 
    2903                 :            :                     // still bezier?
    2904 [ +  - ][ +  + ]:       1068 :                     if(aBezier.isBezier())
    2905                 :            :                     {
    2906                 :            :                         // add edge with control vectors
    2907         [ +  - ]:        860 :                         aRetval.appendBezierSegment(aBezier.getControlPointA(), aBezier.getControlPointB(), aBezier.getEndPoint());
    2908                 :            :                     }
    2909                 :            :                     else
    2910                 :            :                     {
    2911                 :            :                         // add edge
    2912         [ +  - ]:        208 :                         aRetval.append(aBezier.getEndPoint());
    2913                 :            :                     }
    2914                 :            : 
    2915                 :            :                     // next point
    2916                 :       1068 :                     aBezier.setStartPoint(aBezier.getEndPoint());
    2917                 :            :                 }
    2918                 :            : 
    2919 [ +  - ][ +  + ]:        180 :                 if(rCandidate.isClosed())
    2920                 :            :                 {
    2921                 :            :                     // set closed flag, rescue control point and correct last double point
    2922         [ +  - ]:         96 :                     closeWithGeometryChange(aRetval);
    2923                 :            :                 }
    2924                 :            : 
    2925 [ +  - ][ +  - ]:        180 :                 return aRetval;
                 [ +  - ]
    2926                 :            :             }
    2927                 :            :             else
    2928                 :            :             {
    2929                 :      20838 :                 return rCandidate;
    2930                 :            :             }
    2931                 :            :         }
    2932                 :            : 
    2933                 :            :         // makes the given indexed point the new polygon start point. To do that, the points in the
    2934                 :            :         // polygon will be rotated. This is only valid for closed polygons, for non-closed ones
    2935                 :            :         // an assertion will be triggered
    2936                 :          0 :         B2DPolygon makeStartPoint(const B2DPolygon& rCandidate, sal_uInt32 nIndexOfNewStatPoint)
    2937                 :            :         {
    2938                 :          0 :             const sal_uInt32 nPointCount(rCandidate.count());
    2939                 :            : 
    2940 [ #  # ][ #  # ]:          0 :             if(nPointCount > 2 && nIndexOfNewStatPoint != 0 && nIndexOfNewStatPoint < nPointCount)
                 [ #  # ]
    2941                 :            :             {
    2942                 :            :                 OSL_ENSURE(rCandidate.isClosed(), "makeStartPoint: only valid for closed polygons (!)");
    2943         [ #  # ]:          0 :                 B2DPolygon aRetval;
    2944                 :            : 
    2945         [ #  # ]:          0 :                 for(sal_uInt32 a(0); a < nPointCount; a++)
    2946                 :            :                 {
    2947                 :          0 :                     const sal_uInt32 nSourceIndex((a + nIndexOfNewStatPoint) % nPointCount);
    2948 [ #  # ][ #  # ]:          0 :                     aRetval.append(rCandidate.getB2DPoint(nSourceIndex));
    2949                 :            : 
    2950 [ #  # ][ #  # ]:          0 :                     if(rCandidate.areControlPointsUsed())
    2951                 :            :                     {
    2952 [ #  # ][ #  # ]:          0 :                         aRetval.setPrevControlPoint(a, rCandidate.getPrevControlPoint(nSourceIndex));
    2953 [ #  # ][ #  # ]:          0 :                         aRetval.setNextControlPoint(a, rCandidate.getNextControlPoint(nSourceIndex));
    2954                 :            :                     }
    2955                 :            :                 }
    2956                 :            : 
    2957 [ #  # ][ #  # ]:          0 :                 return aRetval;
    2958                 :            :             }
    2959                 :            : 
    2960                 :          0 :             return rCandidate;
    2961                 :            :         }
    2962                 :            : 
    2963                 :          0 :         B2DPolygon createEdgesOfGivenLength(const B2DPolygon& rCandidate, double fLength, double fStart, double fEnd)
    2964                 :            :         {
    2965                 :          0 :             B2DPolygon aRetval;
    2966                 :            : 
    2967         [ #  # ]:          0 :             if(fLength < 0.0)
    2968                 :            :             {
    2969                 :          0 :                 fLength = 0.0;
    2970                 :            :             }
    2971                 :            : 
    2972         [ #  # ]:          0 :             if(!fTools::equalZero(fLength))
    2973                 :            :             {
    2974         [ #  # ]:          0 :                 if(fStart < 0.0)
    2975                 :            :                 {
    2976                 :          0 :                     fStart = 0.0;
    2977                 :            :                 }
    2978                 :            : 
    2979         [ #  # ]:          0 :                 if(fEnd < 0.0)
    2980                 :            :                 {
    2981                 :          0 :                     fEnd = 0.0;
    2982                 :            :                 }
    2983                 :            : 
    2984         [ #  # ]:          0 :                 if(fEnd < fStart)
    2985                 :            :                 {
    2986                 :          0 :                     fEnd = fStart;
    2987                 :            :                 }
    2988                 :            : 
    2989                 :            :                 // iterate and consume pieces with fLength. First subdivide to reduce input to line segments
    2990 [ #  # ][ #  # ]:          0 :                 const B2DPolygon aCandidate(rCandidate.areControlPointsUsed() ? rCandidate.getDefaultAdaptiveSubdivision() : rCandidate);
         [ #  # ][ #  # ]
    2991         [ #  # ]:          0 :                 const sal_uInt32 nPointCount(aCandidate.count());
    2992                 :            : 
    2993         [ #  # ]:          0 :                 if(nPointCount > 1)
    2994                 :            :                 {
    2995                 :          0 :                     const bool bEndActive(!fTools::equalZero(fEnd));
    2996 [ #  # ][ #  # ]:          0 :                     const sal_uInt32 nEdgeCount(aCandidate.isClosed() ? nPointCount : nPointCount - 1);
    2997         [ #  # ]:          0 :                     B2DPoint aCurrent(aCandidate.getB2DPoint(0));
    2998                 :          0 :                     double fPositionInEdge(fStart);
    2999                 :          0 :                     double fAbsolutePosition(fStart);
    3000                 :            : 
    3001         [ #  # ]:          0 :                     for(sal_uInt32 a(0); a < nEdgeCount; a++)
    3002                 :            :                     {
    3003                 :          0 :                         const sal_uInt32 nNextIndex((a + 1) % nPointCount);
    3004         [ #  # ]:          0 :                         const B2DPoint aNext(aCandidate.getB2DPoint(nNextIndex));
    3005                 :          0 :                         const B2DVector aEdge(aNext - aCurrent);
    3006         [ #  # ]:          0 :                         double fEdgeLength(aEdge.getLength());
    3007                 :            : 
    3008         [ #  # ]:          0 :                         if(!fTools::equalZero(fEdgeLength))
    3009                 :            :                         {
    3010         [ #  # ]:          0 :                             while(fTools::less(fPositionInEdge, fEdgeLength))
    3011                 :            :                             {
    3012                 :            :                                 // move position on edge forward as long as on edge
    3013                 :          0 :                                 const double fScalar(fPositionInEdge / fEdgeLength);
    3014         [ #  # ]:          0 :                                 aRetval.append(aCurrent + (aEdge * fScalar));
    3015                 :          0 :                                 fPositionInEdge += fLength;
    3016                 :            : 
    3017         [ #  # ]:          0 :                                 if(bEndActive)
    3018                 :            :                                 {
    3019                 :          0 :                                     fAbsolutePosition += fLength;
    3020                 :            : 
    3021         [ #  # ]:          0 :                                     if(fTools::more(fAbsolutePosition, fEnd))
    3022                 :            :                                     {
    3023                 :          0 :                                         break;
    3024                 :            :                                     }
    3025                 :            :                                 }
    3026                 :            :                             }
    3027                 :            : 
    3028                 :            :                             // substract length of current edge
    3029                 :          0 :                             fPositionInEdge -= fEdgeLength;
    3030                 :            :                         }
    3031                 :            : 
    3032 [ #  # ][ #  # ]:          0 :                         if(bEndActive && fTools::more(fAbsolutePosition, fEnd))
                 [ #  # ]
    3033                 :            :                         {
    3034                 :            :                             break;
    3035                 :            :                         }
    3036                 :            : 
    3037                 :            :                         // prepare next step
    3038         [ #  # ]:          0 :                         aCurrent = aNext;
    3039         [ #  # ]:          0 :                     }
    3040                 :            : 
    3041                 :            :                     // keep closed state
    3042 [ #  # ][ #  # ]:          0 :                     aRetval.setClosed(aCandidate.isClosed());
    3043                 :            :                 }
    3044                 :            :                 else
    3045                 :            :                 {
    3046                 :            :                     // source polygon has only one point, return unchanged
    3047         [ #  # ]:          0 :                     aRetval = aCandidate;
    3048         [ #  # ]:          0 :                 }
    3049                 :            :             }
    3050                 :            : 
    3051                 :          0 :             return aRetval;
    3052                 :            :         }
    3053                 :            : 
    3054                 :          0 :         B2DPolygon createWaveline(const B2DPolygon& rCandidate, double fWaveWidth, double fWaveHeight)
    3055                 :            :         {
    3056                 :          0 :             B2DPolygon aRetval;
    3057                 :            : 
    3058         [ #  # ]:          0 :             if(fWaveWidth < 0.0)
    3059                 :            :             {
    3060                 :          0 :                 fWaveWidth = 0.0;
    3061                 :            :             }
    3062                 :            : 
    3063         [ #  # ]:          0 :             if(fWaveHeight < 0.0)
    3064                 :            :             {
    3065                 :          0 :                 fWaveHeight = 0.0;
    3066                 :            :             }
    3067                 :            : 
    3068                 :          0 :             const bool bHasWidth(!fTools::equalZero(fWaveWidth));
    3069                 :            : 
    3070         [ #  # ]:          0 :             if(bHasWidth)
    3071                 :            :             {
    3072                 :          0 :                 const bool bHasHeight(!fTools::equalZero(fWaveHeight));
    3073         [ #  # ]:          0 :                 if(bHasHeight)
    3074                 :            :                 {
    3075                 :            :                     // width and height, create waveline. First subdivide to reduce input to line segments
    3076                 :            :                     // of WaveWidth. Last segment may be missing. If this turns out to be a problem, it
    3077                 :            :                     // may be added here again using the original last point from rCandidate. It may
    3078                 :            :                     // also be the case that rCandidate was closed. To simplify things it is handled here
    3079                 :            :                     // as if it was opened.
    3080                 :            :                     // Result from createEdgesOfGivenLength contains no curved segments, handle as straight
    3081                 :            :                     // edges.
    3082         [ #  # ]:          0 :                     const B2DPolygon aEqualLenghEdges(createEdgesOfGivenLength(rCandidate, fWaveWidth));
    3083         [ #  # ]:          0 :                     const sal_uInt32 nPointCount(aEqualLenghEdges.count());
    3084                 :            : 
    3085         [ #  # ]:          0 :                     if(nPointCount > 1)
    3086                 :            :                     {
    3087                 :            :                         // iterate over straight edges, add start point
    3088         [ #  # ]:          0 :                         B2DPoint aCurrent(aEqualLenghEdges.getB2DPoint(0));
    3089         [ #  # ]:          0 :                         aRetval.append(aCurrent);
    3090                 :            : 
    3091         [ #  # ]:          0 :                         for(sal_uInt32 a(0); a < nPointCount - 1; a++)
    3092                 :            :                         {
    3093                 :          0 :                             const sal_uInt32 nNextIndex((a + 1) % nPointCount);
    3094         [ #  # ]:          0 :                             const B2DPoint aNext(aEqualLenghEdges.getB2DPoint(nNextIndex));
    3095                 :          0 :                             const B2DVector aEdge(aNext - aCurrent);
    3096         [ #  # ]:          0 :                             const B2DVector aPerpendicular(getNormalizedPerpendicular(aEdge));
    3097                 :          0 :                             const B2DVector aControlOffset((aEdge * 0.467308) - (aPerpendicular * fWaveHeight));
    3098                 :            : 
    3099                 :            :                             // add curve segment
    3100                 :            :                             aRetval.appendBezierSegment(
    3101                 :            :                                 aCurrent + aControlOffset,
    3102                 :            :                                 aNext - aControlOffset,
    3103         [ #  # ]:          0 :                                 aNext);
    3104                 :            : 
    3105                 :            :                             // prepare next step
    3106                 :          0 :                             aCurrent = aNext;
    3107                 :          0 :                         }
    3108         [ #  # ]:          0 :                     }
    3109                 :            :                 }
    3110                 :            :                 else
    3111                 :            :                 {
    3112                 :            :                     // width but no height -> return original polygon
    3113         [ #  # ]:          0 :                     aRetval = rCandidate;
    3114                 :            :                 }
    3115                 :            :             }
    3116                 :            :             else
    3117                 :            :             {
    3118                 :            :                 // no width -> no waveline, stay empty and return
    3119                 :            :             }
    3120                 :            : 
    3121                 :          0 :             return aRetval;
    3122                 :            :         }
    3123                 :            : 
    3124                 :            :         // snap points of horizontal or vertical edges to discrete values
    3125                 :          0 :         B2DPolygon snapPointsOfHorizontalOrVerticalEdges(const B2DPolygon& rCandidate)
    3126                 :            :         {
    3127                 :          0 :             const sal_uInt32 nPointCount(rCandidate.count());
    3128                 :            : 
    3129         [ #  # ]:          0 :             if(nPointCount > 1)
    3130                 :            :             {
    3131                 :            :                 // Start by copying the source polygon to get a writeable copy. The closed state is
    3132                 :            :                 // copied by aRetval's initialisation, too, so no need to copy it in this method
    3133         [ #  # ]:          0 :                 B2DPolygon aRetval(rCandidate);
    3134                 :            : 
    3135                 :            :                 // prepare geometry data. Get rounded from original
    3136 [ #  # ][ #  # ]:          0 :                 B2ITuple aPrevTuple(basegfx::fround(rCandidate.getB2DPoint(nPointCount - 1)));
    3137         [ #  # ]:          0 :                 B2DPoint aCurrPoint(rCandidate.getB2DPoint(0));
    3138         [ #  # ]:          0 :                 B2ITuple aCurrTuple(basegfx::fround(aCurrPoint));
    3139                 :            : 
    3140                 :            :                 // loop over all points. This will also snap the implicit closing edge
    3141                 :            :                 // even when not closed, but that's no problem here
    3142         [ #  # ]:          0 :                 for(sal_uInt32 a(0); a < nPointCount; a++)
    3143                 :            :                 {
    3144                 :            :                     // get next point. Get rounded from original
    3145                 :          0 :                     const bool bLastRun(a + 1 == nPointCount);
    3146         [ #  # ]:          0 :                     const sal_uInt32 nNextIndex(bLastRun ? 0 : a + 1);
    3147         [ #  # ]:          0 :                     const B2DPoint aNextPoint(rCandidate.getB2DPoint(nNextIndex));
    3148         [ #  # ]:          0 :                     const B2ITuple aNextTuple(basegfx::fround(aNextPoint));
    3149                 :            : 
    3150                 :            :                     // get the states
    3151                 :          0 :                     const bool bPrevVertical(aPrevTuple.getX() == aCurrTuple.getX());
    3152                 :          0 :                     const bool bNextVertical(aNextTuple.getX() == aCurrTuple.getX());
    3153                 :          0 :                     const bool bPrevHorizontal(aPrevTuple.getY() == aCurrTuple.getY());
    3154                 :          0 :                     const bool bNextHorizontal(aNextTuple.getY() == aCurrTuple.getY());
    3155 [ #  # ][ #  # ]:          0 :                     const bool bSnapX(bPrevVertical || bNextVertical);
    3156 [ #  # ][ #  # ]:          0 :                     const bool bSnapY(bPrevHorizontal || bNextHorizontal);
    3157                 :            : 
    3158 [ #  # ][ #  # ]:          0 :                     if(bSnapX || bSnapY)
    3159                 :            :                     {
    3160                 :            :                         const B2DPoint aSnappedPoint(
    3161                 :          0 :                             bSnapX ? aCurrTuple.getX() : aCurrPoint.getX(),
    3162 [ #  # ][ #  # ]:          0 :                             bSnapY ? aCurrTuple.getY() : aCurrPoint.getY());
    3163                 :            : 
    3164         [ #  # ]:          0 :                         aRetval.setB2DPoint(a, aSnappedPoint);
    3165                 :            :                     }
    3166                 :            : 
    3167                 :            :                     // prepare next point
    3168         [ #  # ]:          0 :                     if(!bLastRun)
    3169                 :            :                     {
    3170                 :          0 :                         aPrevTuple = aCurrTuple;
    3171                 :          0 :                         aCurrPoint = aNextPoint;
    3172                 :          0 :                         aCurrTuple = aNextTuple;
    3173                 :            :                     }
    3174                 :          0 :                 }
    3175                 :            : 
    3176 [ #  # ][ #  # ]:          0 :                 return aRetval;
    3177                 :            :             }
    3178                 :            :             else
    3179                 :            :             {
    3180                 :          0 :                 return rCandidate;
    3181                 :            :             }
    3182                 :            :         }
    3183                 :            : 
    3184                 :            :     } // end of namespace tools
    3185                 :            : } // end of namespace basegfx
    3186                 :            : 
    3187                 :            : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10