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