LCOV - code coverage report
Current view: top level - basegfx/source/polygon - b2dtrapezoid.cxx (source / functions) Hit Total Coverage
Test: commit e02a6cb2c3e2b23b203b422e4e0680877f232636 Lines: 0 447 0.0 %
Date: 2014-04-14 Functions: 0 29 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include <basegfx/polygon/b2dtrapezoid.hxx>
      21             : #include <basegfx/range/b1drange.hxx>
      22             : #include <basegfx/polygon/b2dpolygontools.hxx>
      23             : #include <list>
      24             : 
      25             : 
      26             : 
      27             : namespace basegfx
      28             : {
      29             :     namespace trapezoidhelper
      30             :     {
      31             : 
      32             :         // helper class to hold a simple ege. This is only used for horizontal edges
      33             :         // currently, thus the YPositions will be equal. I did not create a special
      34             :         // class for this since holdingthe pointers is more effective and also can be
      35             :         // used as baseclass for the traversing edges
      36             : 
      37             :         class TrDeSimpleEdge
      38             :         {
      39             :         protected:
      40             :             // pointers to start and end point
      41             :             const B2DPoint*     mpStart;
      42             :             const B2DPoint*     mpEnd;
      43             : 
      44             :         public:
      45             :             // constructor
      46           0 :             TrDeSimpleEdge(
      47             :                 const B2DPoint* pStart,
      48             :                 const B2DPoint* pEnd)
      49             :             :   mpStart(pStart),
      50           0 :                 mpEnd(pEnd)
      51             :             {
      52           0 :             }
      53             : 
      54             :             // data read access
      55           0 :             const B2DPoint& getStart() const { return *mpStart; }
      56           0 :             const B2DPoint& getEnd() const { return *mpEnd; }
      57             :         };
      58             : 
      59             : 
      60             :         // define vector of simple edges
      61             : 
      62             :         typedef ::std::vector< TrDeSimpleEdge > TrDeSimpleEdges;
      63             : 
      64             : 
      65             :         // helper class for holding a traversing edge. It will always have some
      66             :         // distance in YPos. The slope (in a numerically useful form, see comments) is
      67             :         // hold and used in SortValue to allow sorting traversing edges by Y, X and slope
      68             :         // (in that order)
      69             : 
      70             :         class TrDeEdgeEntry : public TrDeSimpleEdge
      71             :         {
      72             :         private:
      73             :             // the slope in a numerical useful form for sorting
      74             :             sal_uInt32          mnSortValue;
      75             : 
      76             :         public:
      77             :             // convenience data read access
      78           0 :             double getDeltaX() const { return mpEnd->getX() - mpStart->getX(); }
      79           0 :             double getDeltaY() const { return mpEnd->getY() - mpStart->getY(); }
      80             : 
      81             :             // convenience data read access. SortValue is created on demand since
      82             :             // it is not always used
      83           0 :             sal_uInt32 getSortValue() const
      84             :             {
      85           0 :                 if(0 != mnSortValue)
      86           0 :                     return mnSortValue;
      87             : 
      88             :                 // get radiant; has to be in the range ]0.0 .. pi[, thus scale to full
      89             :                 // sal_uInt32 range for maximum precision
      90           0 :                 const double fRadiant(atan2(getDeltaY(), getDeltaX()) * (SAL_MAX_UINT32 / F_PI));
      91             : 
      92             :                 // convert to sal_uInt32 value
      93           0 :                 const_cast< TrDeEdgeEntry* >(this)->mnSortValue = sal_uInt32(fRadiant);
      94             : 
      95           0 :                 return mnSortValue;
      96             :             }
      97             : 
      98             :             // constructor. SortValue can be given when known, use zero otherwise
      99           0 :             TrDeEdgeEntry(
     100             :                 const B2DPoint* pStart,
     101             :                 const B2DPoint* pEnd,
     102             :                 sal_uInt32 nSortValue = 0)
     103             :             :   TrDeSimpleEdge(pStart, pEnd),
     104           0 :                 mnSortValue(nSortValue)
     105             :             {
     106             :                 // force traversal of deltaY downward
     107           0 :                 if(mpEnd->getY() < mpStart->getY())
     108             :                 {
     109           0 :                     std::swap(mpStart, mpEnd);
     110             :                 }
     111             : 
     112             :                 // no horizontal edges allowed, all neeed to traverse vertically
     113             :                 OSL_ENSURE(mpEnd->getY() > mpStart->getY(), "Illegal TrDeEdgeEntry constructed (!)");
     114           0 :             }
     115             : 
     116             :             // data write access to StartPoint
     117           0 :             void setStart( const B2DPoint* pNewStart)
     118             :             {
     119             :                 OSL_ENSURE(0 != pNewStart, "No null pointer allowed here (!)");
     120             : 
     121           0 :                 if(mpStart != pNewStart)
     122             :                 {
     123           0 :                     mpStart = pNewStart;
     124             : 
     125             :                     // no horizontal edges allowed, all neeed to traverse vertivally
     126             :                     OSL_ENSURE(mpEnd->getY() > mpStart->getY(), "Illegal TrDeEdgeEntry constructed (!)");
     127             :                 }
     128           0 :             }
     129             : 
     130             :             // data write access to EndPoint
     131           0 :             void setEnd( const B2DPoint* pNewEnd)
     132             :             {
     133             :                 OSL_ENSURE(0 != pNewEnd, "No null pointer allowed here (!)");
     134             : 
     135           0 :                 if(mpEnd != pNewEnd)
     136             :                 {
     137           0 :                     mpEnd = pNewEnd;
     138             : 
     139             :                     // no horizontal edges allowed, all neeed to traverse vertivally
     140             :                     OSL_ENSURE(mpEnd->getY() > mpStart->getY(), "Illegal TrDeEdgeEntry constructed (!)");
     141             :                 }
     142           0 :             }
     143             : 
     144             :             // operator for sort support. Sort by Y, X and slope (in that order)
     145           0 :             bool operator<(const TrDeEdgeEntry& rComp) const
     146             :             {
     147           0 :                 if(fTools::equal(getStart().getY(), rComp.getStart().getY(), fTools::getSmallValue()))
     148             :                 {
     149           0 :                     if(fTools::equal(getStart().getX(), rComp.getStart().getX(), fTools::getSmallValue()))
     150             :                     {
     151             :                         // when start points are equal, use the direction the edge is pointing
     152             :                         // to. That value is created on demand and derived from atan2 in the
     153             :                         // range ]0.0 .. pi[ (without extremas, we always have a deltaY in this
     154             :                         // class) and scaled to sal_uInt32 range for best precision. 0 means no angle,
     155             :                         // while SAL_MAX_UINT32 means pi. Thus, the higher the value, the more left
     156             :                         // the edge traverses.
     157           0 :                         return (getSortValue() > rComp.getSortValue());
     158             :                     }
     159             :                     else
     160             :                     {
     161           0 :                         return fTools::less(getStart().getX(), rComp.getStart().getX());
     162             :                     }
     163             :                 }
     164             :                 else
     165             :                 {
     166           0 :                     return fTools::less(getStart().getY(), rComp.getStart().getY());
     167             :                 }
     168             :             }
     169             : 
     170             :             // method for cut support
     171           0 :             B2DPoint getCutPointForGivenY(double fGivenY)
     172             :             {
     173             :                 // Calculate cut point locally (do not use interpolate) since it is numerically
     174             :                 // necessary to guarantee the new, equal Y-coordinate
     175           0 :                 const double fFactor((fGivenY - getStart().getY()) / getDeltaY());
     176           0 :                 const double fDeltaXNew(fFactor * getDeltaX());
     177             : 
     178           0 :                 return B2DPoint(getStart().getX() + fDeltaXNew, fGivenY);
     179             :             }
     180             :         };
     181             : 
     182             : 
     183             :         // define double linked list of edges (for fast random insert)
     184             : 
     185             :         typedef ::std::list< TrDeEdgeEntry > TrDeEdgeEntries;
     186             : 
     187             :     } // end of anonymous namespace
     188             : } // end of namespace basegfx
     189             : 
     190             : 
     191             : 
     192             : namespace basegfx
     193             : {
     194             :     namespace trapezoidhelper
     195             :     {
     196             :         // FIXME: templatize this and use it for TrDeEdgeEntries too ...
     197             : 
     198             :         /// Class to allow efficient allocation and release of B2DPoints
     199             :         class PointBlockAllocator
     200             :         {
     201             :             static const size_t nBlockSize = 32;
     202             :             size_t nCurPoint;
     203             :             B2DPoint *mpPointBase;
     204             :             /// Special case the first allocation to avoid it.
     205             :             B2DPoint maFirstStackBlock[nBlockSize];
     206             :             std::vector< B2DPoint * > maBlocks;
     207             :         public:
     208           0 :             PointBlockAllocator() :
     209             :                 nCurPoint( nBlockSize ),
     210           0 :                 mpPointBase( maFirstStackBlock )
     211             :             {
     212           0 :             }
     213             : 
     214           0 :             ~PointBlockAllocator()
     215           0 :             {
     216           0 :                 while(maBlocks.size() > 0)
     217             :                 {
     218           0 :                     delete [] maBlocks.back();
     219           0 :                     maBlocks.pop_back();
     220             :                 }
     221           0 :             }
     222             : 
     223           0 :             B2DPoint *allocatePoint()
     224             :             {
     225           0 :                 if(nCurPoint >= nBlockSize)
     226             :                 {
     227           0 :                     mpPointBase = new B2DPoint[nBlockSize];
     228           0 :                     maBlocks.push_back(mpPointBase);
     229           0 :                     nCurPoint = 0;
     230             :                 }
     231           0 :                 return mpPointBase + nCurPoint++;
     232             :             }
     233             : 
     234           0 :             B2DPoint *allocatePoint(const B2DTuple &rPoint)
     235             :             {
     236           0 :                 B2DPoint *pPoint = allocatePoint();
     237           0 :                 *pPoint = rPoint;
     238           0 :                 return pPoint;
     239             :             }
     240             : 
     241             :             /// This is a very uncommon case but why not ...
     242           0 :             void freeIfLast(B2DPoint *pPoint)
     243             :             {
     244             :                 // just re-use the last point if we can.
     245           0 :                 if ( nCurPoint > 0 && pPoint == mpPointBase + nCurPoint - 1 )
     246           0 :                     nCurPoint--;
     247           0 :             }
     248             :         };
     249             : 
     250             :         // helper class to handle the complete trapezoid subdivision of a PolyPolygon
     251           0 :         class TrapezoidSubdivider
     252             :         {
     253             :         private:
     254             :             // local data
     255             :             sal_uInt32                  mnInitialEdgeEntryCount;
     256             :             TrDeEdgeEntries             maTrDeEdgeEntries;
     257             :             ::std::vector< B2DPoint >   maPoints;
     258             :             /// new points allocated for cuts
     259             :             PointBlockAllocator         maNewPoints;
     260             : 
     261           0 :             void addEdgeSorted(
     262             :                 TrDeEdgeEntries::iterator aCurrent,
     263             :                 const TrDeEdgeEntry& rNewEdge)
     264             :             {
     265             :                 // Loop while new entry is bigger, use operator<
     266           0 :                 while(aCurrent != maTrDeEdgeEntries.end() && (*aCurrent) < rNewEdge)
     267             :                 {
     268           0 :                     ++aCurrent;
     269             :                 }
     270             : 
     271             :                 // Insert before first which is smaller or equal or at end
     272           0 :                 maTrDeEdgeEntries.insert(aCurrent, rNewEdge);
     273           0 :             }
     274             : 
     275           0 :             bool splitEdgeAtGivenPoint(
     276             :                 TrDeEdgeEntries::reference aEdge,
     277             :                 const B2DPoint& rCutPoint,
     278             :                 TrDeEdgeEntries::iterator aCurrent)
     279             :             {
     280             :                 // do not create edges without deltaY: do not split when start is identical
     281           0 :                 if(aEdge.getStart().equal(rCutPoint, fTools::getSmallValue()))
     282             :                 {
     283           0 :                     return false;
     284             :                 }
     285             : 
     286             :                 // do not create edges without deltaY: do not split when end is identical
     287           0 :                 if(aEdge.getEnd().equal(rCutPoint, fTools::getSmallValue()))
     288             :                 {
     289           0 :                     return false;
     290             :                 }
     291             : 
     292           0 :                 const double fOldDeltaYStart(rCutPoint.getY() - aEdge.getStart().getY());
     293             : 
     294           0 :                 if(fTools::lessOrEqual(fOldDeltaYStart, 0.0))
     295             :                 {
     296             :                     // do not split: the resulting edge would be horizontal
     297             :                     // correct it to new start point
     298           0 :                     aEdge.setStart(&rCutPoint);
     299           0 :                     return false;
     300             :                 }
     301             : 
     302           0 :                 const double fNewDeltaYStart(aEdge.getEnd().getY() - rCutPoint.getY());
     303             : 
     304           0 :                 if(fTools::lessOrEqual(fNewDeltaYStart, 0.0))
     305             :                 {
     306             :                     // do not split: the resulting edge would be horizontal
     307             :                     // correct it to new end point
     308           0 :                     aEdge.setEnd(&rCutPoint);
     309           0 :                     return false;
     310             :                 }
     311             : 
     312             :                 // Create new entry
     313             :                 const TrDeEdgeEntry aNewEdge(
     314             :                     &rCutPoint,
     315           0 :                     &aEdge.getEnd(),
     316           0 :                     aEdge.getSortValue());
     317             : 
     318             :                 // Correct old entry
     319           0 :                 aEdge.setEnd(&rCutPoint);
     320             : 
     321             :                 // Insert sorted (to avoid new sort)
     322           0 :                 addEdgeSorted(aCurrent, aNewEdge);
     323             : 
     324           0 :                 return true;
     325             :             }
     326             : 
     327           0 :             bool testAndCorrectEdgeIntersection(
     328             :                 TrDeEdgeEntries::reference aEdgeA,
     329             :                 TrDeEdgeEntries::reference aEdgeB,
     330             :                 TrDeEdgeEntries::iterator aCurrent)
     331             :             {
     332             :                 // Exclude simple cases: same start or end point
     333           0 :                 if(aEdgeA.getStart().equal(aEdgeB.getStart(), fTools::getSmallValue()))
     334             :                 {
     335           0 :                     return false;
     336             :                 }
     337             : 
     338           0 :                 if(aEdgeA.getStart().equal(aEdgeB.getEnd(), fTools::getSmallValue()))
     339             :                 {
     340           0 :                     return false;
     341             :                 }
     342             : 
     343           0 :                 if(aEdgeA.getEnd().equal(aEdgeB.getStart(), fTools::getSmallValue()))
     344             :                 {
     345           0 :                     return false;
     346             :                 }
     347             : 
     348           0 :                 if(aEdgeA.getEnd().equal(aEdgeB.getEnd(), fTools::getSmallValue()))
     349             :                 {
     350           0 :                     return false;
     351             :                 }
     352             : 
     353             :                 // Exclude simple cases: one of the edges has no length anymore
     354           0 :                 if(aEdgeA.getStart().equal(aEdgeA.getEnd(), fTools::getSmallValue()))
     355             :                 {
     356           0 :                     return false;
     357             :                 }
     358             : 
     359           0 :                 if(aEdgeB.getStart().equal(aEdgeB.getEnd(), fTools::getSmallValue()))
     360             :                 {
     361           0 :                     return false;
     362             :                 }
     363             : 
     364             :                 // check if one point is on the other edge (a touch, not a cut)
     365           0 :                 const B2DVector aDeltaB(aEdgeB.getDeltaX(), aEdgeB.getDeltaY());
     366             : 
     367           0 :                 if(tools::isPointOnEdge(aEdgeA.getStart(), aEdgeB.getStart(), aDeltaB))
     368             :                 {
     369           0 :                     return splitEdgeAtGivenPoint(aEdgeB, aEdgeA.getStart(), aCurrent);
     370             :                 }
     371             : 
     372           0 :                 if(tools::isPointOnEdge(aEdgeA.getEnd(), aEdgeB.getStart(), aDeltaB))
     373             :                 {
     374           0 :                     return splitEdgeAtGivenPoint(aEdgeB, aEdgeA.getEnd(), aCurrent);
     375             :                 }
     376             : 
     377           0 :                 const B2DVector aDeltaA(aEdgeA.getDeltaX(), aEdgeA.getDeltaY());
     378             : 
     379           0 :                 if(tools::isPointOnEdge(aEdgeB.getStart(), aEdgeA.getStart(), aDeltaA))
     380             :                 {
     381           0 :                     return splitEdgeAtGivenPoint(aEdgeA, aEdgeB.getStart(), aCurrent);
     382             :                 }
     383             : 
     384           0 :                 if(tools::isPointOnEdge(aEdgeB.getEnd(), aEdgeA.getStart(), aDeltaA))
     385             :                 {
     386           0 :                     return splitEdgeAtGivenPoint(aEdgeA, aEdgeB.getEnd(), aCurrent);
     387             :                 }
     388             : 
     389             :                 // check for cut inside edges. Use both t-values to choose the more precise
     390             :                 // one later
     391           0 :                 double fCutA(0.0);
     392           0 :                 double fCutB(0.0);
     393             : 
     394           0 :                 if(tools::findCut(
     395           0 :                     aEdgeA.getStart(), aDeltaA,
     396           0 :                     aEdgeB.getStart(), aDeltaB,
     397             :                     CUTFLAG_LINE,
     398             :                     &fCutA,
     399           0 :                     &fCutB))
     400             :                 {
     401             :                     // use a simple metric (length criteria) for choosing the numerically
     402             :                     // better cut
     403           0 :                     const double fSimpleLengthA(aDeltaA.getX() + aDeltaA.getY());
     404           0 :                     const double fSimpleLengthB(aDeltaB.getX() + aDeltaB.getY());
     405           0 :                     const bool bAIsLonger(fSimpleLengthA > fSimpleLengthB);
     406             :                     B2DPoint* pNewPoint = bAIsLonger
     407           0 :                         ? maNewPoints.allocatePoint(aEdgeA.getStart() + (fCutA * aDeltaA))
     408           0 :                         : maNewPoints.allocatePoint(aEdgeB.getStart() + (fCutB * aDeltaB));
     409             : 
     410             :                     // try to split both edges
     411           0 :                     bool bRetval = splitEdgeAtGivenPoint(aEdgeA, *pNewPoint, aCurrent);
     412           0 :                     bRetval |= splitEdgeAtGivenPoint(aEdgeB, *pNewPoint, aCurrent);
     413             : 
     414           0 :                     if(!bRetval)
     415           0 :                         maNewPoints.freeIfLast(pNewPoint);
     416             : 
     417           0 :                     return bRetval;
     418             :                 }
     419             : 
     420           0 :                 return false;
     421             :             }
     422             : 
     423           0 :             void solveHorizontalEdges(TrDeSimpleEdges& rTrDeSimpleEdges)
     424             :             {
     425           0 :                 if(rTrDeSimpleEdges.size() && maTrDeEdgeEntries.size())
     426             :                 {
     427             :                     // there were horizontal edges. These can be excluded, but
     428             :                     // cuts with other edges need to be solved and added before
     429             :                     // ignoring them
     430           0 :                     sal_uInt32 a(0);
     431             : 
     432           0 :                     for(a = 0; a < rTrDeSimpleEdges.size(); a++)
     433             :                     {
     434             :                         // get horizontal edge as candidate; prepare its range and fixed Y
     435           0 :                         const TrDeSimpleEdge& rHorEdge = rTrDeSimpleEdges[a];
     436           0 :                         const B1DRange aRange(rHorEdge.getStart().getX(), rHorEdge.getEnd().getX());
     437           0 :                         const double fFixedY(rHorEdge.getStart().getY());
     438             : 
     439             :                         // loop over traversing edges
     440           0 :                         TrDeEdgeEntries::iterator aCurrent(maTrDeEdgeEntries.begin());
     441             : 
     442           0 :                         do
     443             :                         {
     444             :                             // get compare edge
     445           0 :                             TrDeEdgeEntries::reference aCompare(*aCurrent++);
     446             : 
     447           0 :                             if(fTools::lessOrEqual(aCompare.getEnd().getY(), fFixedY))
     448             :                             {
     449             :                                 // edge ends above horizontal edge, continue
     450           0 :                                 continue;
     451             :                             }
     452             : 
     453           0 :                             if(fTools::moreOrEqual(aCompare.getStart().getY(), fFixedY))
     454             :                             {
     455             :                                 // edge starts below horizontal edge, continue
     456           0 :                                 continue;
     457             :                             }
     458             : 
     459             :                             // vertical overlap, get horizontal range
     460           0 :                             const B1DRange aCompareRange(aCompare.getStart().getX(), aCompare.getEnd().getX());
     461             : 
     462           0 :                             if(aRange.overlaps(aCompareRange))
     463             :                             {
     464             :                                 // possible cut, get cut point
     465           0 :                                 const B2DPoint aSplit(aCompare.getCutPointForGivenY(fFixedY));
     466             : 
     467           0 :                                 if(fTools::more(aSplit.getX(), aRange.getMinimum())
     468           0 :                                     && fTools::less(aSplit.getX(), aRange.getMaximum()))
     469             :                                 {
     470             :                                     // cut is in XRange of horizontal edge, potentially needed cut
     471           0 :                                     B2DPoint* pNewPoint = maNewPoints.allocatePoint(aSplit);
     472             : 
     473           0 :                                     if(!splitEdgeAtGivenPoint(aCompare, *pNewPoint, aCurrent))
     474             :                                     {
     475           0 :                                         maNewPoints.freeIfLast(pNewPoint);
     476             :                                     }
     477           0 :                                 }
     478             :                             }
     479             :                         }
     480           0 :                         while(aCurrent != maTrDeEdgeEntries.end()
     481           0 :                             && fTools::less(aCurrent->getStart().getY(), fFixedY));
     482             :                     }
     483             :                 }
     484           0 :             }
     485             : 
     486             :         public:
     487           0 :             explicit TrapezoidSubdivider(
     488             :                 const B2DPolyPolygon& rSourcePolyPolygon)
     489             :             :   mnInitialEdgeEntryCount(0),
     490             :                 maTrDeEdgeEntries(),
     491             :                 maPoints(),
     492           0 :                 maNewPoints()
     493             :             {
     494           0 :                 B2DPolyPolygon aSource(rSourcePolyPolygon);
     495           0 :                 const sal_uInt32 nPolygonCount(rSourcePolyPolygon.count());
     496           0 :                 TrDeSimpleEdges aTrDeSimpleEdges;
     497           0 :                 sal_uInt32 a(0), b(0);
     498           0 :                 sal_uInt32 nAllPointCount(0);
     499             : 
     500             :                 // ensure there are no curves used
     501           0 :                 if(aSource.areControlPointsUsed())
     502             :                 {
     503           0 :                     aSource = aSource.getDefaultAdaptiveSubdivision();
     504             :                 }
     505             : 
     506           0 :                 for(a = 0; a < nPolygonCount; a++)
     507             :                 {
     508             :                     // 1st run: count points
     509           0 :                     const B2DPolygon aPolygonCandidate(aSource.getB2DPolygon(a));
     510           0 :                     const sal_uInt32 nCount(aPolygonCandidate.count());
     511             : 
     512           0 :                     if(nCount > 2)
     513             :                     {
     514           0 :                         nAllPointCount += nCount;
     515             :                     }
     516           0 :                 }
     517             : 
     518           0 :                 if(nAllPointCount)
     519             :                 {
     520             :                     // reserve needed points. CAUTION: maPoints size is NOT to be changed anymore
     521             :                     // after 2nd loop since pointers to it are used in the edges
     522           0 :                     maPoints.reserve(nAllPointCount);
     523             : 
     524           0 :                     for(a = 0; a < nPolygonCount; a++)
     525             :                     {
     526             :                         // 2nd run: add points
     527           0 :                         const B2DPolygon aPolygonCandidate(aSource.getB2DPolygon(a));
     528           0 :                         const sal_uInt32 nCount(aPolygonCandidate.count());
     529             : 
     530           0 :                         if(nCount > 2)
     531             :                         {
     532           0 :                             for(b = 0; b < nCount; b++)
     533             :                             {
     534           0 :                                 maPoints.push_back(aPolygonCandidate.getB2DPoint(b));
     535             :                             }
     536             :                         }
     537           0 :                     }
     538             : 
     539             :                     // Moved the edge construction to a 3rd run: doing it in the 2nd run is
     540             :                     // possible(and i used it), but requires a working vector::reserve()
     541             :                     // implementation, else the vector will be reallocated and the pointers
     542             :                     // in the edges may be wrong. Security first here.
     543           0 :                     sal_uInt32 nStartIndex(0);
     544             : 
     545           0 :                     for(a = 0; a < nPolygonCount; a++)
     546             :                     {
     547           0 :                         const B2DPolygon aPolygonCandidate(aSource.getB2DPolygon(a));
     548           0 :                         const sal_uInt32 nCount(aPolygonCandidate.count());
     549             : 
     550           0 :                         if(nCount > 2)
     551             :                         {
     552             :                             // get the last point of the current polygon
     553           0 :                             B2DPoint* pPrev(&maPoints[nCount + nStartIndex - 1]);
     554             : 
     555           0 :                             for(b = 0; b < nCount; b++)
     556             :                             {
     557             :                                 // get next point
     558           0 :                                 B2DPoint* pCurr(&maPoints[nStartIndex++]);
     559             : 
     560           0 :                                 if(fTools::equal(pPrev->getY(), pCurr->getY(), fTools::getSmallValue()))
     561             :                                 {
     562             :                                     // horizontal edge, check for single point
     563           0 :                                     if(!fTools::equal(pPrev->getX(), pCurr->getX(), fTools::getSmallValue()))
     564             :                                     {
     565             :                                         // X-order not needed, just add
     566           0 :                                         aTrDeSimpleEdges.push_back(TrDeSimpleEdge(pPrev, pCurr));
     567             : 
     568           0 :                                         const double fMiddle((pPrev->getY() + pCurr->getY()) * 0.5);
     569           0 :                                         pPrev->setY(fMiddle);
     570           0 :                                         pCurr->setY(fMiddle);
     571             :                                     }
     572             :                                 }
     573             :                                 else
     574             :                                 {
     575             :                                     // vertical edge. Positive Y-direction is guaranteed by the
     576             :                                     // TrDeEdgeEntry constructor
     577           0 :                                     maTrDeEdgeEntries.push_back(TrDeEdgeEntry(pPrev, pCurr, 0));
     578           0 :                                     mnInitialEdgeEntryCount++;
     579             :                                 }
     580             : 
     581             :                                 // prepare next step
     582           0 :                                 pPrev = pCurr;
     583             :                             }
     584             :                         }
     585           0 :                     }
     586             :                 }
     587             : 
     588           0 :                 if(!maTrDeEdgeEntries.empty())
     589             :                 {
     590             :                     // single and initial sort of traversing edges
     591           0 :                     maTrDeEdgeEntries.sort();
     592             : 
     593             :                     // solve horizontal edges if there are any detected
     594           0 :                     solveHorizontalEdges(aTrDeSimpleEdges);
     595           0 :                 }
     596           0 :             }
     597             : 
     598           0 :             void Subdivide(B2DTrapezoidVector& ro_Result)
     599             :             {
     600             :                 // This is the central subdivider. The strategy is to use the first two entries
     601             :                 // from the traversing edges as a potential trapezoid and do the needed corrections
     602             :                 // and adaptions on the way.
     603             : 
     604             :                 // There always must be two edges with the same YStart value: When adding the polygons
     605             :                 // in the constructor, there is always a topmost point from which two edges start; when
     606             :                 // the topmost is an edge, there is a start and end of this edge from which two edges
     607             :                 // start. All cases have two edges with same StartY (QED).
     608             : 
     609             :                 // Based on this these edges get corrected when:
     610             :                 // - one is longer than the other
     611             :                 // - they intersect
     612             :                 // - they intersect with other edges
     613             :                 // - another edge starts inside the thought trapezoid
     614             : 
     615             :                 // All this cases again produce a valid state so that the first two edges have a common
     616             :                 // Ystart again. Some cases lead to a restart of the process, some allow consuming the
     617             :                 // edges and create the intended trapezoid.
     618             : 
     619             :                 // Be careful when doing chages here: It is essential to keep all possible paths
     620             :                 // in valid states and to be numerically correct. This is especially needed e.g.
     621             :                 // by using fTools::equal(..) in the more robust small-value incarnation.
     622           0 :                 B1DRange aLeftRange;
     623           0 :                 B1DRange aRightRange;
     624             : 
     625           0 :                 if(!maTrDeEdgeEntries.empty())
     626             :                 {
     627             :                     // measuring shows that the relation between edges and created trapezoids is
     628             :                     // mostly in the 1:1 range, thus reserve as much trapezoids as edges exist. Do
     629             :                     // not use maTrDeEdgeEntries.size() since that may be a non-constant time
     630             :                     // operation for Lists. Instead, use mnInitialEdgeEntryCount which will contain
     631             :                     // the roughly counted adds to the List
     632           0 :                     ro_Result.reserve(ro_Result.size() + mnInitialEdgeEntryCount);
     633             :                 }
     634             : 
     635           0 :                 while(!maTrDeEdgeEntries.empty())
     636             :                 {
     637             :                     // Prepare current operator and get first edge
     638           0 :                     TrDeEdgeEntries::iterator aCurrent(maTrDeEdgeEntries.begin());
     639           0 :                     TrDeEdgeEntries::reference aLeft(*aCurrent++);
     640             : 
     641           0 :                     if(aCurrent == maTrDeEdgeEntries.end())
     642             :                     {
     643             :                         // Should not happen: No 2nd edge; consume the single edge
     644             :                         // to not have an endless loop and start next. During development
     645             :                         // i constantly had breakpoints here, so i am sure enough to add an
     646             :                         // assertion here
     647             :                         OSL_FAIL("Trapeziod decomposer in illegal state (!)");
     648           0 :                         maTrDeEdgeEntries.pop_front();
     649           0 :                         continue;
     650             :                     }
     651             : 
     652             :                     // get second edge
     653           0 :                     TrDeEdgeEntries::reference aRight(*aCurrent++);
     654             : 
     655           0 :                     if(!fTools::equal(aLeft.getStart().getY(), aRight.getStart().getY(), fTools::getSmallValue()))
     656             :                     {
     657             :                         // Should not happen: We have a 2nd edge, but YStart is on another
     658             :                         // line; consume the single edge to not have an endless loop and start
     659             :                         // next. During development i constantly had breakpoints here, so i am
     660             :                         // sure enough to add an assertion here
     661             :                         OSL_FAIL("Trapeziod decomposer in illegal state (!)");
     662           0 :                         maTrDeEdgeEntries.pop_front();
     663           0 :                         continue;
     664             :                     }
     665             : 
     666             :                     // aLeft and aRight build a thought trapezoid now. They have a common
     667             :                     // start line (same Y for start points). Potentially, one of the edges
     668             :                     // is longer than the other. It is only needed to look at the shorter
     669             :                     // length which build the potential trapezoid. To do so, get the end points
     670             :                     // locally and adapt the evtl. longer one. Use only aLeftEnd and aRightEnd
     671             :                     // from here on, not the aLeft.getEnd() or aRight.getEnd() accesses.
     672           0 :                     B2DPoint aLeftEnd(aLeft.getEnd());
     673           0 :                     B2DPoint aRightEnd(aRight.getEnd());
     674             : 
     675             :                     // check if end points are on the same line. If yes, no adaption
     676             :                     // needs to be prepared. Also remember which one actually is longer.
     677           0 :                     const bool bEndOnSameLine(fTools::equal(aLeftEnd.getY(), aRightEnd.getY(), fTools::getSmallValue()));
     678           0 :                     bool bLeftIsLonger(false);
     679             : 
     680           0 :                     if(!bEndOnSameLine)
     681             :                     {
     682             :                         // check which edge is longer and correct accordingly
     683           0 :                         bLeftIsLonger = fTools::more(aLeftEnd.getY(), aRightEnd.getY());
     684             : 
     685           0 :                         if(bLeftIsLonger)
     686             :                         {
     687           0 :                             aLeftEnd = aLeft.getCutPointForGivenY(aRightEnd.getY());
     688             :                         }
     689             :                         else
     690             :                         {
     691           0 :                             aRightEnd = aRight.getCutPointForGivenY(aLeftEnd.getY());
     692             :                         }
     693             :                     }
     694             : 
     695             :                     // check for same start and end points
     696           0 :                     const bool bSameStartPoint(aLeft.getStart().equal(aRight.getStart(), fTools::getSmallValue()));
     697           0 :                     const bool bSameEndPoint(aLeftEnd.equal(aRightEnd, fTools::getSmallValue()));
     698             : 
     699             :                     // check the simple case that the edges form a 'blind' edge (deadend)
     700           0 :                     if(bSameStartPoint && bSameEndPoint)
     701             :                     {
     702             :                         // correct the longer edge if prepared
     703           0 :                         if(!bEndOnSameLine)
     704             :                         {
     705           0 :                             if(bLeftIsLonger)
     706             :                             {
     707           0 :                                 B2DPoint* pNewPoint = maNewPoints.allocatePoint(aLeftEnd);
     708             : 
     709           0 :                                 if(!splitEdgeAtGivenPoint(aLeft, *pNewPoint, aCurrent))
     710             :                                 {
     711           0 :                                     maNewPoints.freeIfLast(pNewPoint);
     712             :                                 }
     713             :                             }
     714             :                             else
     715             :                             {
     716           0 :                                 B2DPoint* pNewPoint = maNewPoints.allocatePoint(aRightEnd);
     717             : 
     718           0 :                                 if(!splitEdgeAtGivenPoint(aRight, *pNewPoint, aCurrent))
     719             :                                 {
     720           0 :                                     maNewPoints.freeIfLast(pNewPoint);
     721             :                                 }
     722             :                             }
     723             :                         }
     724             : 
     725             :                         // consume both edges and start next run
     726           0 :                         maTrDeEdgeEntries.pop_front();
     727           0 :                         maTrDeEdgeEntries.pop_front();
     728             : 
     729           0 :                         continue;
     730             :                     }
     731             : 
     732             :                     // check if the edges self-intersect. This can only happen when
     733             :                     // start and end point are different
     734           0 :                     bool bRangesSet(false);
     735             : 
     736           0 :                     if(!(bSameStartPoint || bSameEndPoint))
     737             :                     {
     738             :                         // get XRanges of edges
     739           0 :                         aLeftRange = B1DRange(aLeft.getStart().getX(), aLeftEnd.getX());
     740           0 :                         aRightRange = B1DRange(aRight.getStart().getX(), aRightEnd.getX());
     741           0 :                         bRangesSet = true;
     742             : 
     743             :                         // use fast range test first
     744           0 :                         if(aLeftRange.overlaps(aRightRange))
     745             :                         {
     746             :                             // real cut test and correction. If correction was needed,
     747             :                             // start new run
     748           0 :                             if(testAndCorrectEdgeIntersection(aLeft, aRight, aCurrent))
     749             :                             {
     750           0 :                                 continue;
     751             :                             }
     752             :                         }
     753             :                     }
     754             : 
     755             :                     // now we need to check if there are intersections with other edges
     756             :                     // or if other edges start inside the candidate trapezoid
     757           0 :                     if(aCurrent != maTrDeEdgeEntries.end()
     758           0 :                         && fTools::less(aCurrent->getStart().getY(), aLeftEnd.getY()))
     759             :                     {
     760             :                         // get XRanges of edges
     761           0 :                         if(!bRangesSet)
     762             :                         {
     763           0 :                             aLeftRange = B1DRange(aLeft.getStart().getX(), aLeftEnd.getX());
     764           0 :                             aRightRange = B1DRange(aRight.getStart().getX(), aRightEnd.getX());
     765             :                         }
     766             : 
     767             :                         // build full XRange for fast check
     768           0 :                         B1DRange aAllRange(aLeftRange);
     769           0 :                         aAllRange.expand(aRightRange);
     770             : 
     771             :                         // prepare loop iterator; aCurrent needs to stay unchanged for
     772             :                         // eventual sorted insertions of new EdgeNodes. Also prepare stop flag
     773           0 :                         TrDeEdgeEntries::iterator aLoop(aCurrent);
     774           0 :                         bool bDone(false);
     775             : 
     776           0 :                         do
     777             :                         {
     778             :                             // get compare edge and its XRange
     779           0 :                             TrDeEdgeEntries::reference aCompare(*aLoop++);
     780             : 
     781             :                             // avoid edges using the same start point as one of
     782             :                             // the edges. These can neither have their start point
     783             :                             // in the thought trapezoid nor cut with one of the edges
     784           0 :                             if(aCompare.getStart().equal(aRight.getStart(), fTools::getSmallValue()))
     785             :                             {
     786           0 :                                 continue;
     787             :                             }
     788             : 
     789             :                             // get compare XRange
     790           0 :                             const B1DRange aCompareRange(aCompare.getStart().getX(), aCompare.getEnd().getX());
     791             : 
     792             :                             // use fast range test first
     793           0 :                             if(aAllRange.overlaps(aCompareRange))
     794             :                             {
     795             :                                 // check for start point inside thought trapezoid
     796           0 :                                 if(fTools::more(aCompare.getStart().getY(), aLeft.getStart().getY()))
     797             :                                 {
     798             :                                     // calculate the two possible split points at compare's Y
     799           0 :                                     const B2DPoint aSplitLeft(aLeft.getCutPointForGivenY(aCompare.getStart().getY()));
     800           0 :                                     const B2DPoint aSplitRight(aRight.getCutPointForGivenY(aCompare.getStart().getY()));
     801             : 
     802             :                                     // check for start point of aCompare being inside thought
     803             :                                     // trapezoid
     804           0 :                                     if(aCompare.getStart().getX() >= aSplitLeft.getX() &&
     805           0 :                                         aCompare.getStart().getX() <= aSplitRight.getX())
     806             :                                     {
     807             :                                         // is inside, correct and restart loop
     808           0 :                                         B2DPoint* pNewLeft = maNewPoints.allocatePoint(aSplitLeft);
     809             : 
     810           0 :                                         if(splitEdgeAtGivenPoint(aLeft, *pNewLeft, aCurrent))
     811             :                                         {
     812           0 :                                             bDone = true;
     813             :                                         }
     814             :                                         else
     815             :                                         {
     816           0 :                                             maNewPoints.freeIfLast(pNewLeft);
     817             :                                         }
     818             : 
     819           0 :                                         B2DPoint* pNewRight = maNewPoints.allocatePoint(aSplitRight);
     820             : 
     821           0 :                                         if(splitEdgeAtGivenPoint(aRight, *pNewRight, aCurrent))
     822             :                                         {
     823           0 :                                             bDone = true;
     824             :                                         }
     825             :                                         else
     826             :                                         {
     827           0 :                                             maNewPoints.freeIfLast(pNewRight);
     828             :                                         }
     829           0 :                                     }
     830             :                                 }
     831             : 
     832           0 :                                 if(!bDone && aLeftRange.overlaps(aCompareRange))
     833             :                                 {
     834             :                                     // test for concrete cut of compare edge with left edge
     835           0 :                                     bDone = testAndCorrectEdgeIntersection(aLeft, aCompare, aCurrent);
     836             :                                 }
     837             : 
     838           0 :                                 if(!bDone && aRightRange.overlaps(aCompareRange))
     839             :                                 {
     840             :                                     // test for concrete cut of compare edge with Right edge
     841           0 :                                     bDone = testAndCorrectEdgeIntersection(aRight, aCompare, aCurrent);
     842             :                                 }
     843             :                             }
     844             :                         }
     845           0 :                         while(!bDone
     846           0 :                             && aLoop != maTrDeEdgeEntries.end()
     847           0 :                             && fTools::less(aLoop->getStart().getY(), aLeftEnd.getY()));
     848             : 
     849           0 :                         if(bDone)
     850             :                         {
     851             :                             // something needed to be changed; start next loop
     852           0 :                             continue;
     853             :                         }
     854             :                     }
     855             : 
     856             :                     // when we get here, the intended trapezoid can be used. It needs to
     857             :                     // be corrected, eventually (if prepared); but this is no reason not to
     858             :                     // use it in the same loop iteration
     859           0 :                     if(!bEndOnSameLine)
     860             :                     {
     861           0 :                         if(bLeftIsLonger)
     862             :                         {
     863           0 :                             B2DPoint* pNewPoint = maNewPoints.allocatePoint(aLeftEnd);
     864             : 
     865           0 :                             if(!splitEdgeAtGivenPoint(aLeft, *pNewPoint, aCurrent))
     866             :                             {
     867           0 :                                 maNewPoints.freeIfLast(pNewPoint);
     868             :                             }
     869             :                         }
     870             :                         else
     871             :                         {
     872           0 :                             B2DPoint* pNewPoint = maNewPoints.allocatePoint(aRightEnd);
     873             : 
     874           0 :                             if(!splitEdgeAtGivenPoint(aRight, *pNewPoint, aCurrent))
     875             :                             {
     876           0 :                                 maNewPoints.freeIfLast(pNewPoint);
     877             :                             }
     878             :                         }
     879             :                     }
     880             : 
     881             :                     // the two edges start at the same Y, they use the same DeltaY, they
     882             :                     // do not cut themselves and not any other edge in range. Create a
     883             :                     // B2DTrapezoid and consume both edges
     884             :                     ro_Result.push_back(
     885             :                         B2DTrapezoid(
     886           0 :                             aLeft.getStart().getX(),
     887           0 :                             aRight.getStart().getX(),
     888           0 :                             aLeft.getStart().getY(),
     889           0 :                             aLeftEnd.getX(),
     890           0 :                             aRightEnd.getX(),
     891           0 :                             aLeftEnd.getY()));
     892             : 
     893           0 :                     maTrDeEdgeEntries.pop_front();
     894           0 :                     maTrDeEdgeEntries.pop_front();
     895           0 :                 }
     896           0 :             }
     897             :         };
     898             :     } // end of anonymous namespace
     899             : } // end of namespace basegfx
     900             : 
     901             : 
     902             : 
     903             : namespace basegfx
     904             : {
     905           0 :     B2DTrapezoid::B2DTrapezoid(
     906             :         const double& rfTopXLeft,
     907             :         const double& rfTopXRight,
     908             :         const double& rfTopY,
     909             :         const double& rfBottomXLeft,
     910             :         const double& rfBottomXRight,
     911             :         const double& rfBottomY)
     912             :     :   mfTopXLeft(rfTopXLeft),
     913             :         mfTopXRight(rfTopXRight),
     914             :         mfTopY(rfTopY),
     915             :         mfBottomXLeft(rfBottomXLeft),
     916             :         mfBottomXRight(rfBottomXRight),
     917           0 :         mfBottomY(rfBottomY)
     918             :     {
     919             :         // guarantee mfTopXRight >= mfTopXLeft
     920           0 :         if(mfTopXLeft > mfTopXRight)
     921             :         {
     922           0 :             std::swap(mfTopXLeft, mfTopXRight);
     923             :         }
     924             : 
     925             :         // guarantee mfBottomXRight >= mfBottomXLeft
     926           0 :         if(mfBottomXLeft > mfBottomXRight)
     927             :         {
     928           0 :             std::swap(mfBottomXLeft, mfBottomXRight);
     929             :         }
     930             : 
     931             :         // guarantee mfBottomY >= mfTopY
     932           0 :         if(mfTopY > mfBottomY)
     933             :         {
     934           0 :             std::swap(mfTopY, mfBottomY);
     935           0 :             std::swap(mfTopXLeft, mfBottomXLeft);
     936           0 :             std::swap(mfTopXRight, mfBottomXRight);
     937             :         }
     938           0 :     }
     939             : 
     940           0 :     B2DPolygon B2DTrapezoid::getB2DPolygon() const
     941             :     {
     942           0 :         B2DPolygon aRetval;
     943             : 
     944           0 :         aRetval.append(B2DPoint(getTopXLeft(), getTopY()));
     945           0 :         aRetval.append(B2DPoint(getTopXRight(), getTopY()));
     946           0 :         aRetval.append(B2DPoint(getBottomXRight(), getBottomY()));
     947           0 :         aRetval.append(B2DPoint(getBottomXLeft(), getBottomY()));
     948           0 :         aRetval.setClosed(true);
     949             : 
     950           0 :         return aRetval;
     951             :     }
     952             : } // end of namespace basegfx
     953             : 
     954             : 
     955             : 
     956             : namespace basegfx
     957             : {
     958             :     namespace tools
     959             :     {
     960             :         // convert Source PolyPolygon to trapezoids
     961           0 :         void trapezoidSubdivide(B2DTrapezoidVector& ro_Result, const B2DPolyPolygon& rSourcePolyPolygon)
     962             :         {
     963           0 :             trapezoidhelper::TrapezoidSubdivider aTrapezoidSubdivider(rSourcePolyPolygon);
     964             : 
     965           0 :             aTrapezoidSubdivider.Subdivide(ro_Result);
     966           0 :         }
     967             : 
     968           0 :         void createLineTrapezoidFromEdge(
     969             :             B2DTrapezoidVector& ro_Result,
     970             :             const B2DPoint& rPointA,
     971             :             const B2DPoint& rPointB,
     972             :             double fLineWidth)
     973             :         {
     974           0 :             if(fTools::lessOrEqual(fLineWidth, 0.0))
     975             :             {
     976             :                 // no line witdh
     977           0 :                 return;
     978             :             }
     979             : 
     980           0 :             if(rPointA.equal(rPointB, fTools::getSmallValue()))
     981             :             {
     982             :                 // points are equal, no edge
     983           0 :                 return;
     984             :             }
     985             : 
     986           0 :             const double fHalfLineWidth(0.5 * fLineWidth);
     987             : 
     988           0 :             if(fTools::equal(rPointA.getX(), rPointB.getX(), fTools::getSmallValue()))
     989             :             {
     990             :                 // vertical line
     991           0 :                 const double fLeftX(rPointA.getX() - fHalfLineWidth);
     992           0 :                 const double fRightX(rPointA.getX() + fHalfLineWidth);
     993             : 
     994             :                 ro_Result.push_back(
     995             :                     B2DTrapezoid(
     996             :                         fLeftX,
     997             :                         fRightX,
     998           0 :                         std::min(rPointA.getY(), rPointB.getY()),
     999             :                         fLeftX,
    1000             :                         fRightX,
    1001           0 :                         std::max(rPointA.getY(), rPointB.getY())));
    1002             :             }
    1003           0 :             else if(fTools::equal(rPointA.getY(), rPointB.getY(), fTools::getSmallValue()))
    1004             :             {
    1005             :                 // horizontal line
    1006           0 :                 const double fLeftX(std::min(rPointA.getX(), rPointB.getX()));
    1007           0 :                 const double fRightX(std::max(rPointA.getX(), rPointB.getX()));
    1008             : 
    1009             :                 ro_Result.push_back(
    1010             :                     B2DTrapezoid(
    1011             :                         fLeftX,
    1012             :                         fRightX,
    1013           0 :                         rPointA.getY() - fHalfLineWidth,
    1014             :                         fLeftX,
    1015             :                         fRightX,
    1016           0 :                         rPointA.getY() + fHalfLineWidth));
    1017             :             }
    1018             :             else
    1019             :             {
    1020             :                 // diagonal line
    1021             :                 // create perpendicular vector
    1022           0 :                 const B2DVector aDelta(rPointB - rPointA);
    1023           0 :                 B2DVector aPerpendicular(-aDelta.getY(), aDelta.getX());
    1024           0 :                 aPerpendicular.setLength(fHalfLineWidth);
    1025             : 
    1026             :                 // create StartLow, StartHigh, EndLow and EndHigh
    1027           0 :                 const B2DPoint aStartLow(rPointA + aPerpendicular);
    1028           0 :                 const B2DPoint aStartHigh(rPointA - aPerpendicular);
    1029           0 :                 const B2DPoint aEndHigh(rPointB - aPerpendicular);
    1030           0 :                 const B2DPoint aEndLow(rPointB + aPerpendicular);
    1031             : 
    1032             :                 // create EdgeEntries
    1033           0 :                 basegfx::trapezoidhelper::TrDeEdgeEntries aTrDeEdgeEntries;
    1034             : 
    1035           0 :                 aTrDeEdgeEntries.push_back(basegfx::trapezoidhelper::TrDeEdgeEntry(&aStartLow, &aStartHigh, 0));
    1036           0 :                 aTrDeEdgeEntries.push_back(basegfx::trapezoidhelper::TrDeEdgeEntry(&aStartHigh, &aEndHigh, 0));
    1037           0 :                 aTrDeEdgeEntries.push_back(basegfx::trapezoidhelper::TrDeEdgeEntry(&aEndHigh, &aEndLow, 0));
    1038           0 :                 aTrDeEdgeEntries.push_back(basegfx::trapezoidhelper::TrDeEdgeEntry(&aEndLow, &aStartLow, 0));
    1039           0 :                 aTrDeEdgeEntries.sort();
    1040             : 
    1041             :                 // here we know we have exactly four edges, and they do not cut, touch or
    1042             :                 // intersect. This makes processing much easier. Get the first two as start
    1043             :                 // edges for the thought trapezoid
    1044           0 :                 basegfx::trapezoidhelper::TrDeEdgeEntries::iterator aCurrent(aTrDeEdgeEntries.begin());
    1045           0 :                 basegfx::trapezoidhelper::TrDeEdgeEntries::reference aLeft(*aCurrent++);
    1046           0 :                 basegfx::trapezoidhelper::TrDeEdgeEntries::reference aRight(*aCurrent++);
    1047           0 :                 const bool bEndOnSameLine(fTools::equal(aLeft.getEnd().getY(), aRight.getEnd().getY(), fTools::getSmallValue()));
    1048             : 
    1049           0 :                 if(bEndOnSameLine)
    1050             :                 {
    1051             :                     // create two triangle trapezoids
    1052             :                     ro_Result.push_back(
    1053             :                         B2DTrapezoid(
    1054           0 :                             aLeft.getStart().getX(),
    1055           0 :                             aRight.getStart().getX(),
    1056           0 :                             aLeft.getStart().getY(),
    1057           0 :                             aLeft.getEnd().getX(),
    1058           0 :                             aRight.getEnd().getX(),
    1059           0 :                             aLeft.getEnd().getY()));
    1060             : 
    1061           0 :                     basegfx::trapezoidhelper::TrDeEdgeEntries::reference aLeft2(*aCurrent++);
    1062           0 :                     basegfx::trapezoidhelper::TrDeEdgeEntries::reference aRight2(*aCurrent++);
    1063             : 
    1064             :                     ro_Result.push_back(
    1065             :                         B2DTrapezoid(
    1066           0 :                             aLeft2.getStart().getX(),
    1067           0 :                             aRight2.getStart().getX(),
    1068           0 :                             aLeft2.getStart().getY(),
    1069           0 :                             aLeft2.getEnd().getX(),
    1070           0 :                             aRight2.getEnd().getX(),
    1071           0 :                             aLeft2.getEnd().getY()));
    1072             :                 }
    1073             :                 else
    1074             :                 {
    1075             :                     // create three trapezoids. Check which edge is longer and
    1076             :                     // correct accordingly
    1077           0 :                     const bool bLeftIsLonger(fTools::more(aLeft.getEnd().getY(), aRight.getEnd().getY()));
    1078             : 
    1079           0 :                     if(bLeftIsLonger)
    1080             :                     {
    1081           0 :                         basegfx::trapezoidhelper::TrDeEdgeEntries::reference aRight2(*aCurrent++);
    1082           0 :                         basegfx::trapezoidhelper::TrDeEdgeEntries::reference aLeft2(*aCurrent++);
    1083           0 :                         const B2DPoint aSplitLeft(aLeft.getCutPointForGivenY(aRight.getEnd().getY()));
    1084           0 :                         const B2DPoint aSplitRight(aRight2.getCutPointForGivenY(aLeft.getEnd().getY()));
    1085             : 
    1086             :                         ro_Result.push_back(
    1087             :                             B2DTrapezoid(
    1088           0 :                                 aLeft.getStart().getX(),
    1089           0 :                                 aRight.getStart().getX(),
    1090           0 :                                 aLeft.getStart().getY(),
    1091           0 :                                 aSplitLeft.getX(),
    1092           0 :                                 aRight.getEnd().getX(),
    1093           0 :                                 aRight.getEnd().getY()));
    1094             : 
    1095             :                         ro_Result.push_back(
    1096             :                             B2DTrapezoid(
    1097           0 :                                 aSplitLeft.getX(),
    1098           0 :                                 aRight.getEnd().getX(),
    1099           0 :                                 aRight.getEnd().getY(),
    1100           0 :                                 aLeft2.getStart().getX(),
    1101           0 :                                 aSplitRight.getX(),
    1102           0 :                                 aLeft2.getStart().getY()));
    1103             : 
    1104             :                         ro_Result.push_back(
    1105             :                             B2DTrapezoid(
    1106           0 :                                 aLeft2.getStart().getX(),
    1107           0 :                                 aSplitRight.getX(),
    1108           0 :                                 aLeft2.getStart().getY(),
    1109           0 :                                 aLeft2.getEnd().getX(),
    1110           0 :                                 aRight2.getEnd().getX(),
    1111           0 :                                 aLeft2.getEnd().getY()));
    1112             :                     }
    1113             :                     else
    1114             :                     {
    1115           0 :                         basegfx::trapezoidhelper::TrDeEdgeEntries::reference aLeft2(*aCurrent++);
    1116           0 :                         basegfx::trapezoidhelper::TrDeEdgeEntries::reference aRight2(*aCurrent++);
    1117           0 :                         const B2DPoint aSplitRight(aRight.getCutPointForGivenY(aLeft.getEnd().getY()));
    1118           0 :                         const B2DPoint aSplitLeft(aLeft2.getCutPointForGivenY(aRight.getEnd().getY()));
    1119             : 
    1120             :                         ro_Result.push_back(
    1121             :                             B2DTrapezoid(
    1122           0 :                                 aLeft.getStart().getX(),
    1123           0 :                                 aRight.getStart().getX(),
    1124           0 :                                 aLeft.getStart().getY(),
    1125           0 :                                 aLeft.getEnd().getX(),
    1126           0 :                                 aSplitRight.getX(),
    1127           0 :                                 aLeft.getEnd().getY()));
    1128             : 
    1129             :                         ro_Result.push_back(
    1130             :                             B2DTrapezoid(
    1131           0 :                                 aLeft.getEnd().getX(),
    1132           0 :                                 aSplitRight.getX(),
    1133           0 :                                 aLeft.getEnd().getY(),
    1134           0 :                                 aSplitLeft.getX(),
    1135           0 :                                 aRight.getEnd().getX(),
    1136           0 :                                 aRight2.getStart().getY()));
    1137             : 
    1138             :                         ro_Result.push_back(
    1139             :                             B2DTrapezoid(
    1140           0 :                                 aSplitLeft.getX(),
    1141           0 :                                 aRight.getEnd().getX(),
    1142           0 :                                 aRight2.getStart().getY(),
    1143           0 :                                 aLeft2.getEnd().getX(),
    1144           0 :                                 aRight2.getEnd().getX(),
    1145           0 :                                 aLeft2.getEnd().getY()));
    1146             :                     }
    1147           0 :                 }
    1148             :             }
    1149             :         }
    1150             : 
    1151           0 :         void createLineTrapezoidFromB2DPolygon(
    1152             :             B2DTrapezoidVector& ro_Result,
    1153             :             const B2DPolygon& rPolygon,
    1154             :             double fLineWidth)
    1155             :         {
    1156           0 :             if(fTools::lessOrEqual(fLineWidth, 0.0))
    1157             :             {
    1158           0 :                 return;
    1159             :             }
    1160             : 
    1161             :             // ensure there are no curves used
    1162           0 :             B2DPolygon aSource(rPolygon);
    1163             : 
    1164           0 :             if(aSource.areControlPointsUsed())
    1165             :             {
    1166           0 :             const double fPrecisionFactor = 0.25;
    1167           0 :                 aSource = adaptiveSubdivideByDistance( aSource, fLineWidth * fPrecisionFactor );
    1168             :             }
    1169             : 
    1170           0 :             const sal_uInt32 nPointCount(aSource.count());
    1171             : 
    1172           0 :             if(!nPointCount)
    1173             :             {
    1174           0 :                 return;
    1175             :             }
    1176             : 
    1177           0 :             const sal_uInt32 nEdgeCount(aSource.isClosed() ? nPointCount : nPointCount - 1);
    1178           0 :             B2DPoint aCurrent(aSource.getB2DPoint(0));
    1179             : 
    1180           0 :             ro_Result.reserve(ro_Result.size() + (3 * nEdgeCount));
    1181             : 
    1182           0 :             for(sal_uInt32 a(0); a < nEdgeCount; a++)
    1183             :             {
    1184           0 :                 const sal_uInt32 nNextIndex((a + 1) % nPointCount);
    1185           0 :                 const B2DPoint aNext(aSource.getB2DPoint(nNextIndex));
    1186             : 
    1187           0 :                 createLineTrapezoidFromEdge(ro_Result, aCurrent, aNext, fLineWidth);
    1188           0 :                 aCurrent = aNext;
    1189           0 :             }
    1190             :         }
    1191             : 
    1192           0 :         void createLineTrapezoidFromB2DPolyPolygon(
    1193             :             B2DTrapezoidVector& ro_Result,
    1194             :             const B2DPolyPolygon& rPolyPolygon,
    1195             :             double fLineWidth)
    1196             :         {
    1197           0 :             if(fTools::lessOrEqual(fLineWidth, 0.0))
    1198             :             {
    1199           0 :                 return;
    1200             :             }
    1201             : 
    1202             :             // ensure there are no curves used
    1203           0 :             B2DPolyPolygon aSource(rPolyPolygon);
    1204             : 
    1205           0 :             if(aSource.areControlPointsUsed())
    1206             :             {
    1207           0 :                 aSource = aSource.getDefaultAdaptiveSubdivision();
    1208             :             }
    1209             : 
    1210           0 :             const sal_uInt32 nCount(aSource.count());
    1211             : 
    1212           0 :             if(!nCount)
    1213             :             {
    1214           0 :                 return;
    1215             :             }
    1216             : 
    1217           0 :             for(sal_uInt32 a(0); a < nCount; a++)
    1218             :             {
    1219             :                 createLineTrapezoidFromB2DPolygon(
    1220             :                     ro_Result,
    1221             :                     aSource.getB2DPolygon(a),
    1222           0 :                     fLineWidth);
    1223           0 :             }
    1224             :         }
    1225             : 
    1226             :     } // end of namespace tools
    1227             : } // end of namespace basegfx
    1228             : 
    1229             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10