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