LCOV - code coverage report
Current view: top level - libreoffice/basegfx/source/polygon - b2dtrapezoid.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 0 434 0.0 %
Date: 2012-12-27 Functions: 0 24 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             :         // helper class to handle the complete trapezoid subdivision of a PolyPolygon
     197             :         class TrapezoidSubdivider
     198             :         {
     199             :         private:
     200             :             // local data
     201             :             sal_uInt32                  mnInitialEdgeEntryCount;
     202             :             TrDeEdgeEntries             maTrDeEdgeEntries;
     203             :             ::std::vector< B2DPoint >   maPoints;
     204             :             ::std::vector< B2DPoint* >  maNewPoints;
     205             : 
     206           0 :             void addEdgeSorted(
     207             :                 TrDeEdgeEntries::iterator aCurrent,
     208             :                 const TrDeEdgeEntry& rNewEdge)
     209             :             {
     210             :                 // Loop while new entry is bigger, use operator<
     211           0 :                 while(aCurrent != maTrDeEdgeEntries.end() && (*aCurrent) < rNewEdge)
     212             :                 {
     213           0 :                     ++aCurrent;
     214             :                 }
     215             : 
     216             :                 // Insert before first which is smaller or equal or at end
     217           0 :                 maTrDeEdgeEntries.insert(aCurrent, rNewEdge);
     218           0 :             }
     219             : 
     220           0 :             bool splitEdgeAtGivenPoint(
     221             :                 TrDeEdgeEntries::reference aEdge,
     222             :                 const B2DPoint& rCutPoint,
     223             :                 TrDeEdgeEntries::iterator aCurrent)
     224             :             {
     225             :                 // do not create edges without deltaY: do not split when start is identical
     226           0 :                 if(aEdge.getStart().equal(rCutPoint, fTools::getSmallValue()))
     227             :                 {
     228           0 :                     return false;
     229             :                 }
     230             : 
     231             :                 // do not create edges without deltaY: do not split when end is identical
     232           0 :                 if(aEdge.getEnd().equal(rCutPoint, fTools::getSmallValue()))
     233             :                 {
     234           0 :                     return false;
     235             :                 }
     236             : 
     237           0 :                 const double fOldDeltaYStart(rCutPoint.getY() - aEdge.getStart().getY());
     238             : 
     239           0 :                 if(fTools::lessOrEqual(fOldDeltaYStart, 0.0))
     240             :                 {
     241             :                     // do not split: the resulting edge would be horizontal
     242             :                     // correct it to new start point
     243           0 :                     aEdge.setStart(&rCutPoint);
     244           0 :                     return false;
     245             :                 }
     246             : 
     247           0 :                 const double fNewDeltaYStart(aEdge.getEnd().getY() - rCutPoint.getY());
     248             : 
     249           0 :                 if(fTools::lessOrEqual(fNewDeltaYStart, 0.0))
     250             :                 {
     251             :                     // do not split: the resulting edge would be horizontal
     252             :                     // correct it to new end point
     253           0 :                     aEdge.setEnd(&rCutPoint);
     254           0 :                     return false;
     255             :                 }
     256             : 
     257             :                 // Create new entry
     258             :                 const TrDeEdgeEntry aNewEdge(
     259             :                     &rCutPoint,
     260           0 :                     &aEdge.getEnd(),
     261           0 :                     aEdge.getSortValue());
     262             : 
     263             :                 // Correct old entry
     264           0 :                 aEdge.setEnd(&rCutPoint);
     265             : 
     266             :                 // Insert sorted (to avoid new sort)
     267           0 :                 addEdgeSorted(aCurrent, aNewEdge);
     268             : 
     269           0 :                 return true;
     270             :             }
     271             : 
     272           0 :             bool testAndCorrectEdgeIntersection(
     273             :                 TrDeEdgeEntries::reference aEdgeA,
     274             :                 TrDeEdgeEntries::reference aEdgeB,
     275             :                 TrDeEdgeEntries::iterator aCurrent)
     276             :             {
     277             :                 // Exclude simple cases: same start or end point
     278           0 :                 if(aEdgeA.getStart().equal(aEdgeB.getStart(), fTools::getSmallValue()))
     279             :                 {
     280           0 :                     return false;
     281             :                 }
     282             : 
     283           0 :                 if(aEdgeA.getStart().equal(aEdgeB.getEnd(), fTools::getSmallValue()))
     284             :                 {
     285           0 :                     return false;
     286             :                 }
     287             : 
     288           0 :                 if(aEdgeA.getEnd().equal(aEdgeB.getStart(), fTools::getSmallValue()))
     289             :                 {
     290           0 :                     return false;
     291             :                 }
     292             : 
     293           0 :                 if(aEdgeA.getEnd().equal(aEdgeB.getEnd(), fTools::getSmallValue()))
     294             :                 {
     295           0 :                     return false;
     296             :                 }
     297             : 
     298             :                 // Exclude simple cases: one of the edges has no length anymore
     299           0 :                 if(aEdgeA.getStart().equal(aEdgeA.getEnd(), fTools::getSmallValue()))
     300             :                 {
     301           0 :                     return false;
     302             :                 }
     303             : 
     304           0 :                 if(aEdgeB.getStart().equal(aEdgeB.getEnd(), fTools::getSmallValue()))
     305             :                 {
     306           0 :                     return false;
     307             :                 }
     308             : 
     309             :                 // check if one point is on the other edge (a touch, not a cut)
     310           0 :                 const B2DVector aDeltaB(aEdgeB.getDeltaX(), aEdgeB.getDeltaY());
     311             : 
     312           0 :                 if(tools::isPointOnEdge(aEdgeA.getStart(), aEdgeB.getStart(), aDeltaB))
     313             :                 {
     314           0 :                     return splitEdgeAtGivenPoint(aEdgeB, aEdgeA.getStart(), aCurrent);
     315             :                 }
     316             : 
     317           0 :                 if(tools::isPointOnEdge(aEdgeA.getEnd(), aEdgeB.getStart(), aDeltaB))
     318             :                 {
     319           0 :                     return splitEdgeAtGivenPoint(aEdgeB, aEdgeA.getEnd(), aCurrent);
     320             :                 }
     321             : 
     322           0 :                 const B2DVector aDeltaA(aEdgeA.getDeltaX(), aEdgeA.getDeltaY());
     323             : 
     324           0 :                 if(tools::isPointOnEdge(aEdgeB.getStart(), aEdgeA.getStart(), aDeltaA))
     325             :                 {
     326           0 :                     return splitEdgeAtGivenPoint(aEdgeA, aEdgeB.getStart(), aCurrent);
     327             :                 }
     328             : 
     329           0 :                 if(tools::isPointOnEdge(aEdgeB.getEnd(), aEdgeA.getStart(), aDeltaA))
     330             :                 {
     331           0 :                     return splitEdgeAtGivenPoint(aEdgeA, aEdgeB.getEnd(), aCurrent);
     332             :                 }
     333             : 
     334             :                 // check for cut inside edges. Use both t-values to choose the more precise
     335             :                 // one later
     336           0 :                 double fCutA(0.0);
     337           0 :                 double fCutB(0.0);
     338             : 
     339           0 :                 if(tools::findCut(
     340           0 :                     aEdgeA.getStart(), aDeltaA,
     341           0 :                     aEdgeB.getStart(), aDeltaB,
     342             :                     CUTFLAG_LINE,
     343             :                     &fCutA,
     344           0 :                     &fCutB))
     345             :                 {
     346             :                     // use a simple metric (length criteria) for choosing the numerically
     347             :                     // better cut
     348           0 :                     const double fSimpleLengthA(aDeltaA.getX() + aDeltaA.getY());
     349           0 :                     const double fSimpleLengthB(aDeltaB.getX() + aDeltaB.getY());
     350           0 :                     const bool bAIsLonger(fSimpleLengthA > fSimpleLengthB);
     351             :                     B2DPoint* pNewPoint = bAIsLonger
     352           0 :                         ? new B2DPoint(aEdgeA.getStart() + (fCutA * aDeltaA))
     353           0 :                         : new B2DPoint(aEdgeB.getStart() + (fCutB * aDeltaB));
     354           0 :                     bool bRetval(false);
     355             : 
     356             :                     // try to split both edges
     357           0 :                     bRetval = splitEdgeAtGivenPoint(aEdgeA, *pNewPoint, aCurrent);
     358           0 :                     bRetval |= splitEdgeAtGivenPoint(aEdgeB, *pNewPoint, aCurrent);
     359             : 
     360           0 :                     if(bRetval)
     361             :                     {
     362           0 :                         maNewPoints.push_back(pNewPoint);
     363             :                     }
     364             :                     else
     365             :                     {
     366           0 :                         delete pNewPoint;
     367             :                     }
     368             : 
     369           0 :                     return bRetval;
     370             :                 }
     371             : 
     372           0 :                 return false;
     373             :             }
     374             : 
     375           0 :             void solveHorizontalEdges(TrDeSimpleEdges& rTrDeSimpleEdges)
     376             :             {
     377           0 :                 if(rTrDeSimpleEdges.size() && maTrDeEdgeEntries.size())
     378             :                 {
     379             :                     // there were horizontal edges. These can be excluded, but
     380             :                     // cuts with other edges need to be solved and added before
     381             :                     // ignoring them
     382           0 :                     sal_uInt32 a(0);
     383             : 
     384           0 :                     for(a = 0; a < rTrDeSimpleEdges.size(); a++)
     385             :                     {
     386             :                         // get horizontal edge as candidate; prepare it's range and fixed Y
     387           0 :                         const TrDeSimpleEdge& rHorEdge = rTrDeSimpleEdges[a];
     388           0 :                         const B1DRange aRange(rHorEdge.getStart().getX(), rHorEdge.getEnd().getX());
     389           0 :                         const double fFixedY(rHorEdge.getStart().getY());
     390             : 
     391             :                         // loop over traversing edges
     392           0 :                         TrDeEdgeEntries::iterator aCurrent(maTrDeEdgeEntries.begin());
     393             : 
     394           0 :                         do
     395             :                         {
     396             :                             // get compare edge
     397           0 :                             TrDeEdgeEntries::reference aCompare(*aCurrent++);
     398             : 
     399           0 :                             if(fTools::lessOrEqual(aCompare.getEnd().getY(), fFixedY))
     400             :                             {
     401             :                                 // edge ends above horizontal edge, continue
     402           0 :                                 continue;
     403             :                             }
     404             : 
     405           0 :                             if(fTools::moreOrEqual(aCompare.getStart().getY(), fFixedY))
     406             :                             {
     407             :                                 // edge starts below horizontal edge, continue
     408           0 :                                 continue;
     409             :                             }
     410             : 
     411             :                             // vertical overlap, get horizontal range
     412           0 :                             const B1DRange aCompareRange(aCompare.getStart().getX(), aCompare.getEnd().getX());
     413             : 
     414           0 :                             if(aRange.overlaps(aCompareRange))
     415             :                             {
     416             :                                 // possible cut, get cut point
     417           0 :                                 const B2DPoint aSplit(aCompare.getCutPointForGivenY(fFixedY));
     418             : 
     419           0 :                                 if(fTools::more(aSplit.getX(), aRange.getMinimum())
     420           0 :                                     && fTools::less(aSplit.getX(), aRange.getMaximum()))
     421             :                                 {
     422             :                                     // cut is in XRange of horizontal edge, potenitally needed cut
     423           0 :                                     B2DPoint* pNewPoint = new B2DPoint(aSplit);
     424             : 
     425           0 :                                     if(splitEdgeAtGivenPoint(aCompare, *pNewPoint, aCurrent))
     426             :                                     {
     427           0 :                                         maNewPoints.push_back(pNewPoint);
     428             :                                     }
     429             :                                     else
     430             :                                     {
     431           0 :                                         delete pNewPoint;
     432             :                                     }
     433           0 :                                 }
     434             :                             }
     435             :                         }
     436           0 :                         while(aCurrent != maTrDeEdgeEntries.end()
     437           0 :                             && fTools::less(aCurrent->getStart().getY(), fFixedY));
     438             :                     }
     439             :                 }
     440           0 :             }
     441             : 
     442             :         public:
     443           0 :             explicit TrapezoidSubdivider(
     444             :                 const B2DPolyPolygon& rSourcePolyPolygon)
     445             :             :   mnInitialEdgeEntryCount(0),
     446             :                 maTrDeEdgeEntries(),
     447             :                 maPoints(),
     448           0 :                 maNewPoints()
     449             :             {
     450           0 :                 B2DPolyPolygon aSource(rSourcePolyPolygon);
     451           0 :                 const sal_uInt32 nPolygonCount(rSourcePolyPolygon.count());
     452           0 :                 TrDeSimpleEdges aTrDeSimpleEdges;
     453           0 :                 sal_uInt32 a(0), b(0);
     454           0 :                 sal_uInt32 nAllPointCount(0);
     455             : 
     456             :                 // ensure there are no curves used
     457           0 :                 if(aSource.areControlPointsUsed())
     458             :                 {
     459           0 :                     aSource = aSource.getDefaultAdaptiveSubdivision();
     460             :                 }
     461             : 
     462           0 :                 for(a = 0; a < nPolygonCount; a++)
     463             :                 {
     464             :                     // 1st run: count points
     465           0 :                     const B2DPolygon aPolygonCandidate(aSource.getB2DPolygon(a));
     466           0 :                     const sal_uInt32 nCount(aPolygonCandidate.count());
     467             : 
     468           0 :                     if(nCount > 2)
     469             :                     {
     470           0 :                         nAllPointCount += nCount;
     471             :                     }
     472           0 :                 }
     473             : 
     474           0 :                 if(nAllPointCount)
     475             :                 {
     476             :                     // reserve needed points. CAUTION: maPoints size is NOT to be changed anymore
     477             :                     // after 2nd loop since pointers to it are used in the edges
     478           0 :                     maPoints.reserve(nAllPointCount);
     479             : 
     480           0 :                     for(a = 0; a < nPolygonCount; a++)
     481             :                     {
     482             :                         // 2nd run: add points
     483           0 :                         const B2DPolygon aPolygonCandidate(aSource.getB2DPolygon(a));
     484           0 :                         const sal_uInt32 nCount(aPolygonCandidate.count());
     485             : 
     486           0 :                         if(nCount > 2)
     487             :                         {
     488           0 :                             for(b = 0; b < nCount; b++)
     489             :                             {
     490           0 :                                 maPoints.push_back(aPolygonCandidate.getB2DPoint(b));
     491             :                             }
     492             :                         }
     493           0 :                     }
     494             : 
     495             :                     // Moved the edge construction to a 3rd run: doing it in the 2nd run is
     496             :                     // possible(and i used it), but requires a working vector::reserve()
     497             :                     // implementation, else the vector will be reallocated and the pointers
     498             :                     // in the edges may be wrong. Security first here.
     499           0 :                     sal_uInt32 nStartIndex(0);
     500             : 
     501           0 :                     for(a = 0; a < nPolygonCount; a++)
     502             :                     {
     503           0 :                         const B2DPolygon aPolygonCandidate(aSource.getB2DPolygon(a));
     504           0 :                         const sal_uInt32 nCount(aPolygonCandidate.count());
     505             : 
     506           0 :                         if(nCount > 2)
     507             :                         {
     508             :                             // get the last point of the current polygon
     509           0 :                             B2DPoint* pPrev(&maPoints[nCount + nStartIndex - 1]);
     510             : 
     511           0 :                             for(b = 0; b < nCount; b++)
     512             :                             {
     513             :                                 // get next point
     514           0 :                                 B2DPoint* pCurr(&maPoints[nStartIndex++]);
     515             : 
     516           0 :                                 if(fTools::equal(pPrev->getY(), pCurr->getY(), fTools::getSmallValue()))
     517             :                                 {
     518             :                                     // horizontal edge, check for single point
     519           0 :                                     if(!fTools::equal(pPrev->getX(), pCurr->getX(), fTools::getSmallValue()))
     520             :                                     {
     521             :                                         // X-order not needed, just add
     522           0 :                                         aTrDeSimpleEdges.push_back(TrDeSimpleEdge(pPrev, pCurr));
     523             : 
     524           0 :                                         const double fMiddle((pPrev->getY() + pCurr->getY()) * 0.5);
     525           0 :                                         pPrev->setY(fMiddle);
     526           0 :                                         pCurr->setY(fMiddle);
     527             :                                     }
     528             :                                 }
     529             :                                 else
     530             :                                 {
     531             :                                     // vertical edge. Positive Y-direction is guaranteed by the
     532             :                                     // TrDeEdgeEntry constructor
     533           0 :                                     maTrDeEdgeEntries.push_back(TrDeEdgeEntry(pPrev, pCurr, 0));
     534           0 :                                     mnInitialEdgeEntryCount++;
     535             :                                 }
     536             : 
     537             :                                 // prepare next step
     538           0 :                                 pPrev = pCurr;
     539             :                             }
     540             :                         }
     541           0 :                     }
     542             :                 }
     543             : 
     544           0 :                 if(!maTrDeEdgeEntries.empty())
     545             :                 {
     546             :                     // single and initial sort of traversing edges
     547           0 :                     maTrDeEdgeEntries.sort();
     548             : 
     549             :                     // solve horizontal edges if there are any detected
     550           0 :                     solveHorizontalEdges(aTrDeSimpleEdges);
     551           0 :                 }
     552           0 :             }
     553             : 
     554           0 :             ~TrapezoidSubdivider()
     555           0 :             {
     556             :                 // delete the extra points created for cuts
     557           0 :                 const sal_uInt32 nCount(maNewPoints.size());
     558             : 
     559           0 :                 for(sal_uInt32 a(0); a < nCount; a++)
     560             :                 {
     561           0 :                     delete maNewPoints[a];
     562             :                 }
     563           0 :             }
     564             : 
     565           0 :             void Subdivide(B2DTrapezoidVector& ro_Result)
     566             :             {
     567             :                 // This is the central subdivider. The strategy is to use the first two entries
     568             :                 // from the traversing edges as a potential trapezoid and do the needed corrections
     569             :                 // and adaptions on the way.
     570             :                 //
     571             :                 // There always must be two edges with the same YStart value: When adding the polygons
     572             :                 // in the constructor, there is always a topmost point from which two edges start; when
     573             :                 // the topmost is an edge, there is a start and end of this edge from which two edges
     574             :                 // start. All cases have two edges with same StartY (QED).
     575             :                 //
     576             :                 // Based on this these edges get corrected when:
     577             :                 // - one is longer than the other
     578             :                 // - they intersect
     579             :                 // - they intersect with other edges
     580             :                 // - another edge starts inside the thought trapezoid
     581             :                 //
     582             :                 // All this cases again produce a valid state so that the first two edges have a common
     583             :                 // Ystart again. Some cases lead to a restart of the process, some allow consuming the
     584             :                 // edges and create the intended trapezoid.
     585             :                 //
     586             :                 // Be careful when doing chages here: It is essential to keep all possible paths
     587             :                 // in valid states and to be numerically correct. This is especially needed e.g.
     588             :                 // by using fTools::equal(..) in the more robust small-value incarnation.
     589           0 :                 B1DRange aLeftRange;
     590           0 :                 B1DRange aRightRange;
     591             : 
     592           0 :                 if(!maTrDeEdgeEntries.empty())
     593             :                 {
     594             :                     // measuring shows that the relation between edges and created trapezoids is
     595             :                     // mostly in the 1:1 range, thus reserve as much trapezoids as edges exist. Do
     596             :                     // not use maTrDeEdgeEntries.size() since that may be a non-constant time
     597             :                     // operation for Lists. Instead, use mnInitialEdgeEntryCount which will contain
     598             :                     // the roughly counted adds to the List
     599           0 :                     ro_Result.reserve(ro_Result.size() + mnInitialEdgeEntryCount);
     600             :                 }
     601             : 
     602           0 :                 while(!maTrDeEdgeEntries.empty())
     603             :                 {
     604             :                     // Prepare current operator and get first edge
     605           0 :                     TrDeEdgeEntries::iterator aCurrent(maTrDeEdgeEntries.begin());
     606           0 :                     TrDeEdgeEntries::reference aLeft(*aCurrent++);
     607             : 
     608           0 :                     if(aCurrent == maTrDeEdgeEntries.end())
     609             :                     {
     610             :                         // Should not happen: No 2nd edge; consume the single edge
     611             :                         // to not have an endless loop and start next. During development
     612             :                         // i constantly had breakpoints here, so i am sure enough to add an
     613             :                         // assertion here
     614             :                         OSL_FAIL("Trapeziod decomposer in illegal state (!)");
     615           0 :                         maTrDeEdgeEntries.pop_front();
     616           0 :                         continue;
     617             :                     }
     618             : 
     619             :                     // get second edge
     620           0 :                     TrDeEdgeEntries::reference aRight(*aCurrent++);
     621             : 
     622           0 :                     if(!fTools::equal(aLeft.getStart().getY(), aRight.getStart().getY(), fTools::getSmallValue()))
     623             :                     {
     624             :                         // Should not happen: We have a 2nd edge, but YStart is on another
     625             :                         // line; consume the single edge to not have an endless loop and start
     626             :                         // next. During development i constantly had breakpoints here, so i am
     627             :                         // sure enough to add an assertion here
     628             :                         OSL_FAIL("Trapeziod decomposer in illegal state (!)");
     629           0 :                         maTrDeEdgeEntries.pop_front();
     630           0 :                         continue;
     631             :                     }
     632             : 
     633             :                     // aLeft and aRight build a thought trapezoid now. They have a common
     634             :                     // start line (same Y for start points). Potentially, one of the edges
     635             :                     // is longer than the other. It is only needed to look at the shorter
     636             :                     // length which build the potential trapezoid. To do so, get the end points
     637             :                     // locally and adapt the evtl. longer one. Use only aLeftEnd and aRightEnd
     638             :                     // from here on, not the aLeft.getEnd() or aRight.getEnd() accesses.
     639           0 :                     B2DPoint aLeftEnd(aLeft.getEnd());
     640           0 :                     B2DPoint aRightEnd(aRight.getEnd());
     641             : 
     642             :                     // check if end points are on the same line. If yes, no adaption
     643             :                     // needs to be prepared. Also remember which one actually is longer.
     644           0 :                     const bool bEndOnSameLine(fTools::equal(aLeftEnd.getY(), aRightEnd.getY(), fTools::getSmallValue()));
     645           0 :                     bool bLeftIsLonger(false);
     646             : 
     647           0 :                     if(!bEndOnSameLine)
     648             :                     {
     649             :                         // check which edge is longer and correct accordingly
     650           0 :                         bLeftIsLonger = fTools::more(aLeftEnd.getY(), aRightEnd.getY());
     651             : 
     652           0 :                         if(bLeftIsLonger)
     653             :                         {
     654           0 :                             aLeftEnd = aLeft.getCutPointForGivenY(aRightEnd.getY());
     655             :                         }
     656             :                         else
     657             :                         {
     658           0 :                             aRightEnd = aRight.getCutPointForGivenY(aLeftEnd.getY());
     659             :                         }
     660             :                     }
     661             : 
     662             :                     // check for same start and end points
     663           0 :                     const bool bSameStartPoint(aLeft.getStart().equal(aRight.getStart(), fTools::getSmallValue()));
     664           0 :                     const bool bSameEndPoint(aLeftEnd.equal(aRightEnd, fTools::getSmallValue()));
     665             : 
     666             :                     // check the simple case that the edges form a 'blind' edge (deadend)
     667           0 :                     if(bSameStartPoint && bSameEndPoint)
     668             :                     {
     669             :                         // correct the longer edge if prepared
     670           0 :                         if(!bEndOnSameLine)
     671             :                         {
     672           0 :                             if(bLeftIsLonger)
     673             :                             {
     674           0 :                                 B2DPoint* pNewPoint = new B2DPoint(aLeftEnd);
     675             : 
     676           0 :                                 if(splitEdgeAtGivenPoint(aLeft, *pNewPoint, aCurrent))
     677             :                                 {
     678           0 :                                     maNewPoints.push_back(pNewPoint);
     679             :                                 }
     680             :                                 else
     681             :                                 {
     682           0 :                                     delete pNewPoint;
     683             :                                 }
     684             :                             }
     685             :                             else
     686             :                             {
     687           0 :                                 B2DPoint* pNewPoint = new B2DPoint(aRightEnd);
     688             : 
     689           0 :                                 if(splitEdgeAtGivenPoint(aRight, *pNewPoint, aCurrent))
     690             :                                 {
     691           0 :                                     maNewPoints.push_back(pNewPoint);
     692             :                                 }
     693             :                                 else
     694             :                                 {
     695           0 :                                     delete pNewPoint;
     696             :                                 }
     697             :                             }
     698             :                         }
     699             : 
     700             :                         // consume both edges and start next run
     701           0 :                         maTrDeEdgeEntries.pop_front();
     702           0 :                         maTrDeEdgeEntries.pop_front();
     703             : 
     704           0 :                         continue;
     705             :                     }
     706             : 
     707             :                     // check if the edges self-intersect. This can only happen when
     708             :                     // start and end point are different
     709           0 :                     bool bRangesSet(false);
     710             : 
     711           0 :                     if(!(bSameStartPoint || bSameEndPoint))
     712             :                     {
     713             :                         // get XRanges of edges
     714           0 :                         aLeftRange = B1DRange(aLeft.getStart().getX(), aLeftEnd.getX());
     715           0 :                         aRightRange = B1DRange(aRight.getStart().getX(), aRightEnd.getX());
     716           0 :                         bRangesSet = true;
     717             : 
     718             :                         // use fast range test first
     719           0 :                         if(aLeftRange.overlaps(aRightRange))
     720             :                         {
     721             :                             // real cut test and correction. If correction was needed,
     722             :                             // start new run
     723           0 :                             if(testAndCorrectEdgeIntersection(aLeft, aRight, aCurrent))
     724             :                             {
     725           0 :                                 continue;
     726             :                             }
     727             :                         }
     728             :                     }
     729             : 
     730             :                     // now we need to check if there are intersections with other edges
     731             :                     // or if other edges start inside the candidate trapezoid
     732           0 :                     if(aCurrent != maTrDeEdgeEntries.end()
     733           0 :                         && fTools::less(aCurrent->getStart().getY(), aLeftEnd.getY()))
     734             :                     {
     735             :                         // get XRanges of edges
     736           0 :                         if(!bRangesSet)
     737             :                         {
     738           0 :                             aLeftRange = B1DRange(aLeft.getStart().getX(), aLeftEnd.getX());
     739           0 :                             aRightRange = B1DRange(aRight.getStart().getX(), aRightEnd.getX());
     740             :                         }
     741             : 
     742             :                         // build full XRange for fast check
     743           0 :                         B1DRange aAllRange(aLeftRange);
     744           0 :                         aAllRange.expand(aRightRange);
     745             : 
     746             :                         // prepare loop iterator; aCurrent needs to stay unchanged for
     747             :                         // eventual sorted insertions of new EdgeNodes. Also prepare stop flag
     748           0 :                         TrDeEdgeEntries::iterator aLoop(aCurrent);
     749           0 :                         bool bDone(false);
     750             : 
     751           0 :                         do
     752             :                         {
     753             :                             // get compare edge and it's XRange
     754           0 :                             TrDeEdgeEntries::reference aCompare(*aLoop++);
     755             : 
     756             :                             // avoid edges using the same start point as one of
     757             :                             // the edges. These can neither have their start point
     758             :                             // in the thought trapezoid nor cut with one of the edges
     759           0 :                             if(aCompare.getStart().equal(aRight.getStart(), fTools::getSmallValue()))
     760             :                             {
     761           0 :                                 continue;
     762             :                             }
     763             : 
     764             :                             // get compare XRange
     765           0 :                             const B1DRange aCompareRange(aCompare.getStart().getX(), aCompare.getEnd().getX());
     766             : 
     767             :                             // use fast range test first
     768           0 :                             if(aAllRange.overlaps(aCompareRange))
     769             :                             {
     770             :                                 // check for start point inside thought trapezoid
     771           0 :                                 if(fTools::more(aCompare.getStart().getY(), aLeft.getStart().getY()))
     772             :                                 {
     773             :                                     // calculate the two possible split points at compare's Y
     774           0 :                                     const B2DPoint aSplitLeft(aLeft.getCutPointForGivenY(aCompare.getStart().getY()));
     775           0 :                                     const B2DPoint aSplitRight(aRight.getCutPointForGivenY(aCompare.getStart().getY()));
     776             : 
     777             :                                     // check for start point of aCompare being inside thought
     778             :                                     // trapezoid
     779           0 :                                     if(aCompare.getStart().getX() >= aSplitLeft.getX() &&
     780           0 :                                         aCompare.getStart().getX() <= aSplitRight.getX())
     781             :                                     {
     782             :                                         // is inside, correct and restart loop
     783           0 :                                         B2DPoint* pNewLeft = new B2DPoint(aSplitLeft);
     784             : 
     785           0 :                                         if(splitEdgeAtGivenPoint(aLeft, *pNewLeft, aCurrent))
     786             :                                         {
     787           0 :                                             maNewPoints.push_back(pNewLeft);
     788           0 :                                             bDone = true;
     789             :                                         }
     790             :                                         else
     791             :                                         {
     792           0 :                                             delete pNewLeft;
     793             :                                         }
     794             : 
     795           0 :                                         B2DPoint* pNewRight = new B2DPoint(aSplitRight);
     796             : 
     797           0 :                                         if(splitEdgeAtGivenPoint(aRight, *pNewRight, aCurrent))
     798             :                                         {
     799           0 :                                             maNewPoints.push_back(pNewRight);
     800           0 :                                             bDone = true;
     801             :                                         }
     802             :                                         else
     803             :                                         {
     804           0 :                                             delete pNewRight;
     805             :                                         }
     806           0 :                                     }
     807             :                                 }
     808             : 
     809           0 :                                 if(!bDone && aLeftRange.overlaps(aCompareRange))
     810             :                                 {
     811             :                                     // test for concrete cut of compare edge with left edge
     812           0 :                                     bDone = testAndCorrectEdgeIntersection(aLeft, aCompare, aCurrent);
     813             :                                 }
     814             : 
     815           0 :                                 if(!bDone && aRightRange.overlaps(aCompareRange))
     816             :                                 {
     817             :                                     // test for concrete cut of compare edge with Right edge
     818           0 :                                     bDone = testAndCorrectEdgeIntersection(aRight, aCompare, aCurrent);
     819             :                                 }
     820             :                             }
     821             :                         }
     822           0 :                         while(!bDone
     823           0 :                             && aLoop != maTrDeEdgeEntries.end()
     824           0 :                             && fTools::less(aLoop->getStart().getY(), aLeftEnd.getY()));
     825             : 
     826           0 :                         if(bDone)
     827             :                         {
     828             :                             // something needed to be changed; start next loop
     829           0 :                             continue;
     830             :                         }
     831             :                     }
     832             : 
     833             :                     // when we get here, the intended trapezoid can be used. It needs to
     834             :                     // be corrected, eventually (if prepared); but this is no reason not to
     835             :                     // use it in the same loop iteration
     836           0 :                     if(!bEndOnSameLine)
     837             :                     {
     838           0 :                         if(bLeftIsLonger)
     839             :                         {
     840           0 :                             B2DPoint* pNewPoint = new B2DPoint(aLeftEnd);
     841             : 
     842           0 :                             if(splitEdgeAtGivenPoint(aLeft, *pNewPoint, aCurrent))
     843             :                             {
     844           0 :                                 maNewPoints.push_back(pNewPoint);
     845             :                             }
     846             :                             else
     847             :                             {
     848           0 :                                 delete pNewPoint;
     849             :                             }
     850             :                         }
     851             :                         else
     852             :                         {
     853           0 :                             B2DPoint* pNewPoint = new B2DPoint(aRightEnd);
     854             : 
     855           0 :                             if(splitEdgeAtGivenPoint(aRight, *pNewPoint, aCurrent))
     856             :                             {
     857           0 :                                 maNewPoints.push_back(pNewPoint);
     858             :                             }
     859             :                             else
     860             :                             {
     861           0 :                                 delete pNewPoint;
     862             :                             }
     863             :                         }
     864             :                     }
     865             : 
     866             :                     // the two edges start at the same Y, they use the same DeltaY, they
     867             :                     // do not cut themselves and not any other edge in range. Create a
     868             :                     // B2DTrapezoid and consume both edges
     869             :                     ro_Result.push_back(
     870             :                         B2DTrapezoid(
     871           0 :                             aLeft.getStart().getX(),
     872           0 :                             aRight.getStart().getX(),
     873           0 :                             aLeft.getStart().getY(),
     874           0 :                             aLeftEnd.getX(),
     875           0 :                             aRightEnd.getX(),
     876           0 :                             aLeftEnd.getY()));
     877             : 
     878           0 :                     maTrDeEdgeEntries.pop_front();
     879           0 :                     maTrDeEdgeEntries.pop_front();
     880           0 :                 }
     881           0 :             }
     882             :         };
     883             :     } // end of anonymous namespace
     884             : } // end of namespace basegfx
     885             : 
     886             : //////////////////////////////////////////////////////////////////////////////
     887             : 
     888             : namespace basegfx
     889             : {
     890           0 :     B2DTrapezoid::B2DTrapezoid(
     891             :         const double& rfTopXLeft,
     892             :         const double& rfTopXRight,
     893             :         const double& rfTopY,
     894             :         const double& rfBottomXLeft,
     895             :         const double& rfBottomXRight,
     896             :         const double& rfBottomY)
     897             :     :   mfTopXLeft(rfTopXLeft),
     898             :         mfTopXRight(rfTopXRight),
     899             :         mfTopY(rfTopY),
     900             :         mfBottomXLeft(rfBottomXLeft),
     901             :         mfBottomXRight(rfBottomXRight),
     902           0 :         mfBottomY(rfBottomY)
     903             :     {
     904             :         // guarantee mfTopXRight >= mfTopXLeft
     905           0 :         if(mfTopXLeft > mfTopXRight)
     906             :         {
     907           0 :             std::swap(mfTopXLeft, mfTopXRight);
     908             :         }
     909             : 
     910             :         // guarantee mfBottomXRight >= mfBottomXLeft
     911           0 :         if(mfBottomXLeft > mfBottomXRight)
     912             :         {
     913           0 :             std::swap(mfBottomXLeft, mfBottomXRight);
     914             :         }
     915             : 
     916             :         // guarantee mfBottomY >= mfTopY
     917           0 :         if(mfTopY > mfBottomY)
     918             :         {
     919           0 :             std::swap(mfTopY, mfBottomY);
     920           0 :             std::swap(mfTopXLeft, mfBottomXLeft);
     921           0 :             std::swap(mfTopXRight, mfBottomXRight);
     922             :         }
     923           0 :     }
     924             : 
     925           0 :     B2DPolygon B2DTrapezoid::getB2DPolygon() const
     926             :     {
     927           0 :         B2DPolygon aRetval;
     928             : 
     929           0 :         aRetval.append(B2DPoint(getTopXLeft(), getTopY()));
     930           0 :         aRetval.append(B2DPoint(getTopXRight(), getTopY()));
     931           0 :         aRetval.append(B2DPoint(getBottomXRight(), getBottomY()));
     932           0 :         aRetval.append(B2DPoint(getBottomXLeft(), getBottomY()));
     933           0 :         aRetval.setClosed(true);
     934             : 
     935           0 :         return aRetval;
     936             :     }
     937             : } // end of namespace basegfx
     938             : 
     939             : //////////////////////////////////////////////////////////////////////////////
     940             : 
     941             : namespace basegfx
     942             : {
     943             :     namespace tools
     944             :     {
     945             :         // convert Source PolyPolygon to trapezoids
     946           0 :         void trapezoidSubdivide(B2DTrapezoidVector& ro_Result, const B2DPolyPolygon& rSourcePolyPolygon)
     947             :         {
     948           0 :             trapezoidhelper::TrapezoidSubdivider aTrapezoidSubdivider(rSourcePolyPolygon);
     949             : 
     950           0 :             aTrapezoidSubdivider.Subdivide(ro_Result);
     951           0 :         }
     952             : 
     953           0 :         void createLineTrapezoidFromEdge(
     954             :             B2DTrapezoidVector& ro_Result,
     955             :             const B2DPoint& rPointA,
     956             :             const B2DPoint& rPointB,
     957             :             double fLineWidth)
     958             :         {
     959           0 :             if(fTools::lessOrEqual(fLineWidth, 0.0))
     960             :             {
     961             :                 // no line witdh
     962           0 :                 return;
     963             :             }
     964             : 
     965           0 :             if(rPointA.equal(rPointB, fTools::getSmallValue()))
     966             :             {
     967             :                 // points are equal, no edge
     968           0 :                 return;
     969             :             }
     970             : 
     971           0 :             const double fHalfLineWidth(0.5 * fLineWidth);
     972             : 
     973           0 :             if(fTools::equal(rPointA.getX(), rPointB.getX(), fTools::getSmallValue()))
     974             :             {
     975             :                 // vertical line
     976           0 :                 const double fLeftX(rPointA.getX() - fHalfLineWidth);
     977           0 :                 const double fRightX(rPointA.getX() + fHalfLineWidth);
     978             : 
     979             :                 ro_Result.push_back(
     980             :                     B2DTrapezoid(
     981             :                         fLeftX,
     982             :                         fRightX,
     983           0 :                         std::min(rPointA.getY(), rPointB.getY()),
     984             :                         fLeftX,
     985             :                         fRightX,
     986           0 :                         std::max(rPointA.getY(), rPointB.getY())));
     987             :             }
     988           0 :             else if(fTools::equal(rPointA.getY(), rPointB.getY(), fTools::getSmallValue()))
     989             :             {
     990             :                 // horizontal line
     991           0 :                 const double fLeftX(std::min(rPointA.getX(), rPointB.getX()));
     992           0 :                 const double fRightX(std::max(rPointA.getX(), rPointB.getX()));
     993             : 
     994             :                 ro_Result.push_back(
     995             :                     B2DTrapezoid(
     996             :                         fLeftX,
     997             :                         fRightX,
     998           0 :                         rPointA.getY() - fHalfLineWidth,
     999             :                         fLeftX,
    1000             :                         fRightX,
    1001           0 :                         rPointA.getY() + fHalfLineWidth));
    1002             :             }
    1003             :             else
    1004             :             {
    1005             :                 // diagonal line
    1006             :                 // create perpendicular vector
    1007           0 :                 const B2DVector aDelta(rPointB - rPointA);
    1008           0 :                 B2DVector aPerpendicular(-aDelta.getY(), aDelta.getX());
    1009           0 :                 aPerpendicular.setLength(fHalfLineWidth);
    1010             : 
    1011             :                 // create StartLow, StartHigh, EndLow and EndHigh
    1012           0 :                 const B2DPoint aStartLow(rPointA + aPerpendicular);
    1013           0 :                 const B2DPoint aStartHigh(rPointA - aPerpendicular);
    1014           0 :                 const B2DPoint aEndHigh(rPointB - aPerpendicular);
    1015           0 :                 const B2DPoint aEndLow(rPointB + aPerpendicular);
    1016             : 
    1017             :                 // create EdgeEntries
    1018           0 :                 basegfx::trapezoidhelper::TrDeEdgeEntries aTrDeEdgeEntries;
    1019             : 
    1020           0 :                 aTrDeEdgeEntries.push_back(basegfx::trapezoidhelper::TrDeEdgeEntry(&aStartLow, &aStartHigh, 0));
    1021           0 :                 aTrDeEdgeEntries.push_back(basegfx::trapezoidhelper::TrDeEdgeEntry(&aStartHigh, &aEndHigh, 0));
    1022           0 :                 aTrDeEdgeEntries.push_back(basegfx::trapezoidhelper::TrDeEdgeEntry(&aEndHigh, &aEndLow, 0));
    1023           0 :                 aTrDeEdgeEntries.push_back(basegfx::trapezoidhelper::TrDeEdgeEntry(&aEndLow, &aStartLow, 0));
    1024           0 :                 aTrDeEdgeEntries.sort();
    1025             : 
    1026             :                 // here we know we have exactly four edges, and they do not cut, touch or
    1027             :                 // intersect. This makes processing much easier. Get the first two as start
    1028             :                 // edges for the thought trapezoid
    1029           0 :                 basegfx::trapezoidhelper::TrDeEdgeEntries::iterator aCurrent(aTrDeEdgeEntries.begin());
    1030           0 :                 basegfx::trapezoidhelper::TrDeEdgeEntries::reference aLeft(*aCurrent++);
    1031           0 :                 basegfx::trapezoidhelper::TrDeEdgeEntries::reference aRight(*aCurrent++);
    1032           0 :                 const bool bEndOnSameLine(fTools::equal(aLeft.getEnd().getY(), aRight.getEnd().getY(), fTools::getSmallValue()));
    1033             : 
    1034           0 :                 if(bEndOnSameLine)
    1035             :                 {
    1036             :                     // create two triangle trapezoids
    1037             :                     ro_Result.push_back(
    1038             :                         B2DTrapezoid(
    1039           0 :                             aLeft.getStart().getX(),
    1040           0 :                             aRight.getStart().getX(),
    1041           0 :                             aLeft.getStart().getY(),
    1042           0 :                             aLeft.getEnd().getX(),
    1043           0 :                             aRight.getEnd().getX(),
    1044           0 :                             aLeft.getEnd().getY()));
    1045             : 
    1046           0 :                     basegfx::trapezoidhelper::TrDeEdgeEntries::reference aLeft2(*aCurrent++);
    1047           0 :                     basegfx::trapezoidhelper::TrDeEdgeEntries::reference aRight2(*aCurrent++);
    1048             : 
    1049             :                     ro_Result.push_back(
    1050             :                         B2DTrapezoid(
    1051           0 :                             aLeft2.getStart().getX(),
    1052           0 :                             aRight2.getStart().getX(),
    1053           0 :                             aLeft2.getStart().getY(),
    1054           0 :                             aLeft2.getEnd().getX(),
    1055           0 :                             aRight2.getEnd().getX(),
    1056           0 :                             aLeft2.getEnd().getY()));
    1057             :                 }
    1058             :                 else
    1059             :                 {
    1060             :                     // create three trapezoids. Check which edge is longer and
    1061             :                     // correct accordingly
    1062           0 :                     const bool bLeftIsLonger(fTools::more(aLeft.getEnd().getY(), aRight.getEnd().getY()));
    1063             : 
    1064           0 :                     if(bLeftIsLonger)
    1065             :                     {
    1066           0 :                         basegfx::trapezoidhelper::TrDeEdgeEntries::reference aRight2(*aCurrent++);
    1067           0 :                         basegfx::trapezoidhelper::TrDeEdgeEntries::reference aLeft2(*aCurrent++);
    1068           0 :                         const B2DPoint aSplitLeft(aLeft.getCutPointForGivenY(aRight.getEnd().getY()));
    1069           0 :                         const B2DPoint aSplitRight(aRight2.getCutPointForGivenY(aLeft.getEnd().getY()));
    1070             : 
    1071             :                         ro_Result.push_back(
    1072             :                             B2DTrapezoid(
    1073           0 :                                 aLeft.getStart().getX(),
    1074           0 :                                 aRight.getStart().getX(),
    1075           0 :                                 aLeft.getStart().getY(),
    1076           0 :                                 aSplitLeft.getX(),
    1077           0 :                                 aRight.getEnd().getX(),
    1078           0 :                                 aRight.getEnd().getY()));
    1079             : 
    1080             :                         ro_Result.push_back(
    1081             :                             B2DTrapezoid(
    1082           0 :                                 aSplitLeft.getX(),
    1083           0 :                                 aRight.getEnd().getX(),
    1084           0 :                                 aRight.getEnd().getY(),
    1085           0 :                                 aLeft2.getStart().getX(),
    1086           0 :                                 aSplitRight.getX(),
    1087           0 :                                 aLeft2.getStart().getY()));
    1088             : 
    1089             :                         ro_Result.push_back(
    1090             :                             B2DTrapezoid(
    1091           0 :                                 aLeft2.getStart().getX(),
    1092           0 :                                 aSplitRight.getX(),
    1093           0 :                                 aLeft2.getStart().getY(),
    1094           0 :                                 aLeft2.getEnd().getX(),
    1095           0 :                                 aRight2.getEnd().getX(),
    1096           0 :                                 aLeft2.getEnd().getY()));
    1097             :                     }
    1098             :                     else
    1099             :                     {
    1100           0 :                         basegfx::trapezoidhelper::TrDeEdgeEntries::reference aLeft2(*aCurrent++);
    1101           0 :                         basegfx::trapezoidhelper::TrDeEdgeEntries::reference aRight2(*aCurrent++);
    1102           0 :                         const B2DPoint aSplitRight(aRight.getCutPointForGivenY(aLeft.getEnd().getY()));
    1103           0 :                         const B2DPoint aSplitLeft(aLeft2.getCutPointForGivenY(aRight.getEnd().getY()));
    1104             : 
    1105             :                         ro_Result.push_back(
    1106             :                             B2DTrapezoid(
    1107           0 :                                 aLeft.getStart().getX(),
    1108           0 :                                 aRight.getStart().getX(),
    1109           0 :                                 aLeft.getStart().getY(),
    1110           0 :                                 aLeft.getEnd().getX(),
    1111           0 :                                 aSplitRight.getX(),
    1112           0 :                                 aLeft.getEnd().getY()));
    1113             : 
    1114             :                         ro_Result.push_back(
    1115             :                             B2DTrapezoid(
    1116           0 :                                 aLeft.getEnd().getX(),
    1117           0 :                                 aSplitRight.getX(),
    1118           0 :                                 aLeft.getEnd().getY(),
    1119           0 :                                 aSplitLeft.getX(),
    1120           0 :                                 aRight.getEnd().getX(),
    1121           0 :                                 aRight2.getStart().getY()));
    1122             : 
    1123             :                         ro_Result.push_back(
    1124             :                             B2DTrapezoid(
    1125           0 :                                 aSplitLeft.getX(),
    1126           0 :                                 aRight.getEnd().getX(),
    1127           0 :                                 aRight2.getStart().getY(),
    1128           0 :                                 aLeft2.getEnd().getX(),
    1129           0 :                                 aRight2.getEnd().getX(),
    1130           0 :                                 aLeft2.getEnd().getY()));
    1131             :                     }
    1132           0 :                 }
    1133             :             }
    1134             :         }
    1135             : 
    1136           0 :         void createLineTrapezoidFromB2DPolygon(
    1137             :             B2DTrapezoidVector& ro_Result,
    1138             :             const B2DPolygon& rPolygon,
    1139             :             double fLineWidth)
    1140             :         {
    1141           0 :             if(fTools::lessOrEqual(fLineWidth, 0.0))
    1142             :             {
    1143             :                 return;
    1144             :             }
    1145             : 
    1146             :             // ensure there are no curves used
    1147           0 :             B2DPolygon aSource(rPolygon);
    1148             : 
    1149           0 :             if(aSource.areControlPointsUsed())
    1150             :             {
    1151           0 :             const double fPrecisionFactor = 0.25;
    1152           0 :                 aSource = adaptiveSubdivideByDistance( aSource, fLineWidth * fPrecisionFactor );
    1153             :             }
    1154             : 
    1155           0 :             const sal_uInt32 nPointCount(aSource.count());
    1156             : 
    1157           0 :             if(!nPointCount)
    1158             :             {
    1159             :                 return;
    1160             :             }
    1161             : 
    1162           0 :             const sal_uInt32 nEdgeCount(aSource.isClosed() ? nPointCount : nPointCount - 1);
    1163           0 :             B2DPoint aCurrent(aSource.getB2DPoint(0));
    1164             : 
    1165           0 :             ro_Result.reserve(ro_Result.size() + (3 * nEdgeCount));
    1166             : 
    1167           0 :             for(sal_uInt32 a(0); a < nEdgeCount; a++)
    1168             :             {
    1169           0 :                 const sal_uInt32 nNextIndex((a + 1) % nPointCount);
    1170           0 :                 const B2DPoint aNext(aSource.getB2DPoint(nNextIndex));
    1171             : 
    1172           0 :                 createLineTrapezoidFromEdge(ro_Result, aCurrent, aNext, fLineWidth);
    1173           0 :                 aCurrent = aNext;
    1174           0 :             }
    1175             :         }
    1176             : 
    1177           0 :         void createLineTrapezoidFromB2DPolyPolygon(
    1178             :             B2DTrapezoidVector& ro_Result,
    1179             :             const B2DPolyPolygon& rPolyPolygon,
    1180             :             double fLineWidth)
    1181             :         {
    1182           0 :             if(fTools::lessOrEqual(fLineWidth, 0.0))
    1183             :             {
    1184             :                 return;
    1185             :             }
    1186             : 
    1187             :             // ensure there are no curves used
    1188           0 :             B2DPolyPolygon aSource(rPolyPolygon);
    1189             : 
    1190           0 :             if(aSource.areControlPointsUsed())
    1191             :             {
    1192           0 :                 aSource = aSource.getDefaultAdaptiveSubdivision();
    1193             :             }
    1194             : 
    1195           0 :             const sal_uInt32 nCount(aSource.count());
    1196             : 
    1197           0 :             if(!nCount)
    1198             :             {
    1199             :                 return;
    1200             :             }
    1201             : 
    1202           0 :             for(sal_uInt32 a(0); a < nCount; a++)
    1203             :             {
    1204             :                 createLineTrapezoidFromB2DPolygon(
    1205             :                     ro_Result,
    1206             :                     aSource.getB2DPolygon(a),
    1207           0 :                     fLineWidth);
    1208           0 :             }
    1209             :         }
    1210             : 
    1211             :     } // end of namespace tools
    1212             : } // end of namespace basegfx
    1213             : 
    1214             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10