1*09dbbe93SAndrew Rist /************************************************************** 2cdf0e10cSrcweir * 3*09dbbe93SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 4*09dbbe93SAndrew Rist * or more contributor license agreements. See the NOTICE file 5*09dbbe93SAndrew Rist * distributed with this work for additional information 6*09dbbe93SAndrew Rist * regarding copyright ownership. The ASF licenses this file 7*09dbbe93SAndrew Rist * to you under the Apache License, Version 2.0 (the 8*09dbbe93SAndrew Rist * "License"); you may not use this file except in compliance 9*09dbbe93SAndrew Rist * with the License. You may obtain a copy of the License at 10*09dbbe93SAndrew Rist * 11*09dbbe93SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12*09dbbe93SAndrew Rist * 13*09dbbe93SAndrew Rist * Unless required by applicable law or agreed to in writing, 14*09dbbe93SAndrew Rist * software distributed under the License is distributed on an 15*09dbbe93SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*09dbbe93SAndrew Rist * KIND, either express or implied. See the License for the 17*09dbbe93SAndrew Rist * specific language governing permissions and limitations 18*09dbbe93SAndrew Rist * under the License. 19*09dbbe93SAndrew Rist * 20*09dbbe93SAndrew Rist *************************************************************/ 21*09dbbe93SAndrew Rist 22*09dbbe93SAndrew 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 { 35cdf0e10cSrcweir namespace trapezoidhelper 36cdf0e10cSrcweir { 37cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 38cdf0e10cSrcweir // helper class to hold a simple ege. This is only used for horizontal edges 39cdf0e10cSrcweir // currently, thus the YPositions will be equal. I did not create a special 40cdf0e10cSrcweir // class for this since holdingthe pointers is more effective and also can be 41cdf0e10cSrcweir // used as baseclass for the traversing edges 42cdf0e10cSrcweir 43cdf0e10cSrcweir class TrDeSimpleEdge 44cdf0e10cSrcweir { 45cdf0e10cSrcweir protected: 46cdf0e10cSrcweir // pointers to start and end point 47cdf0e10cSrcweir const B2DPoint* mpStart; 48cdf0e10cSrcweir const B2DPoint* mpEnd; 49cdf0e10cSrcweir 50cdf0e10cSrcweir public: 51cdf0e10cSrcweir // constructor 52cdf0e10cSrcweir TrDeSimpleEdge( 53cdf0e10cSrcweir const B2DPoint* pStart, 54cdf0e10cSrcweir const B2DPoint* pEnd) 55cdf0e10cSrcweir : mpStart(pStart), 56cdf0e10cSrcweir mpEnd(pEnd) 57cdf0e10cSrcweir { 58cdf0e10cSrcweir } 59cdf0e10cSrcweir 60cdf0e10cSrcweir // data read access 61cdf0e10cSrcweir const B2DPoint& getStart() const { return *mpStart; } 62cdf0e10cSrcweir const B2DPoint& getEnd() const { return *mpEnd; } 63cdf0e10cSrcweir }; 64cdf0e10cSrcweir 65cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 66cdf0e10cSrcweir // define vector of simple edges 67cdf0e10cSrcweir 68cdf0e10cSrcweir typedef ::std::vector< TrDeSimpleEdge > TrDeSimpleEdges; 69cdf0e10cSrcweir 70cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 71cdf0e10cSrcweir // helper class for holding a traversing edge. It will always have some 72cdf0e10cSrcweir // distance in YPos. The slope (in a numerically useful form, see comments) is 73cdf0e10cSrcweir // hold and used in SortValue to allow sorting traversing edges by Y, X and slope 74cdf0e10cSrcweir // (in that order) 75cdf0e10cSrcweir 76cdf0e10cSrcweir class TrDeEdgeEntry : public TrDeSimpleEdge 77cdf0e10cSrcweir { 78cdf0e10cSrcweir private: 79cdf0e10cSrcweir // the slope in a numerical useful form for sorting 80cdf0e10cSrcweir sal_uInt32 mnSortValue; 81cdf0e10cSrcweir 82cdf0e10cSrcweir public: 83cdf0e10cSrcweir // convenience data read access 84cdf0e10cSrcweir double getDeltaX() const { return mpEnd->getX() - mpStart->getX(); } 85cdf0e10cSrcweir double getDeltaY() const { return mpEnd->getY() - mpStart->getY(); } 86cdf0e10cSrcweir 87cdf0e10cSrcweir // convenience data read access. SortValue is created on demand since 88cdf0e10cSrcweir // it is not always used 89cdf0e10cSrcweir 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); 100cdf0e10cSrcweir 101cdf0e10cSrcweir return mnSortValue; 102cdf0e10cSrcweir } 103cdf0e10cSrcweir 104cdf0e10cSrcweir // constructor. SortValue can be given when known, use zero otherwise 105cdf0e10cSrcweir TrDeEdgeEntry( 106cdf0e10cSrcweir const B2DPoint* pStart, 107cdf0e10cSrcweir const B2DPoint* pEnd, 108cdf0e10cSrcweir sal_uInt32 nSortValue = 0) 109cdf0e10cSrcweir : TrDeSimpleEdge(pStart, pEnd), 110cdf0e10cSrcweir mnSortValue(nSortValue) 111cdf0e10cSrcweir { 112cdf0e10cSrcweir // force traversal of deltaY downward 113cdf0e10cSrcweir if(mpEnd->getY() < mpStart->getY()) 114cdf0e10cSrcweir { 115cdf0e10cSrcweir std::swap(mpStart, mpEnd); 116cdf0e10cSrcweir } 117cdf0e10cSrcweir 118cdf0e10cSrcweir // no horizontal edges allowed, all neeed to traverse vertically 119cdf0e10cSrcweir OSL_ENSURE(mpEnd->getY() > mpStart->getY(), "Illegal TrDeEdgeEntry constructed (!)"); 120cdf0e10cSrcweir } 121cdf0e10cSrcweir 122cdf0e10cSrcweir // data write access to StartPoint 123cdf0e10cSrcweir void setStart( const B2DPoint* pNewStart) 124cdf0e10cSrcweir { 125cdf0e10cSrcweir OSL_ENSURE(0 != pNewStart, "No null pointer allowed here (!)"); 126cdf0e10cSrcweir 127cdf0e10cSrcweir if(mpStart != pNewStart) 128cdf0e10cSrcweir { 129cdf0e10cSrcweir mpStart = pNewStart; 130cdf0e10cSrcweir 131cdf0e10cSrcweir // no horizontal edges allowed, all neeed to traverse vertivally 132cdf0e10cSrcweir OSL_ENSURE(mpEnd->getY() > mpStart->getY(), "Illegal TrDeEdgeEntry constructed (!)"); 133cdf0e10cSrcweir } 134cdf0e10cSrcweir } 135cdf0e10cSrcweir 136cdf0e10cSrcweir // data write access to EndPoint 137cdf0e10cSrcweir void setEnd( const B2DPoint* pNewEnd) 138cdf0e10cSrcweir { 139cdf0e10cSrcweir OSL_ENSURE(0 != pNewEnd, "No null pointer allowed here (!)"); 140cdf0e10cSrcweir 141cdf0e10cSrcweir if(mpEnd != pNewEnd) 142cdf0e10cSrcweir { 143cdf0e10cSrcweir mpEnd = pNewEnd; 144cdf0e10cSrcweir 145cdf0e10cSrcweir // no horizontal edges allowed, all neeed to traverse vertivally 146cdf0e10cSrcweir OSL_ENSURE(mpEnd->getY() > mpStart->getY(), "Illegal TrDeEdgeEntry constructed (!)"); 147cdf0e10cSrcweir } 148cdf0e10cSrcweir } 149cdf0e10cSrcweir 150cdf0e10cSrcweir // operator for sort support. Sort by Y, X and slope (in that order) 151cdf0e10cSrcweir 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 { 157cdf0e10cSrcweir // when start points are equal, use the direction the edge is pointing 158cdf0e10cSrcweir // to. That value is created on demand and derived from atan2 in the 159cdf0e10cSrcweir // range ]0.0 .. pi[ (without extremas, we always have a deltaY in this 160cdf0e10cSrcweir // class) and scaled to sal_uInt32 range for best precision. 0 means no angle, 161cdf0e10cSrcweir // while SAL_MAX_UINT32 means pi. Thus, the higher the value, the more left 162cdf0e10cSrcweir // the edge traverses. 163cdf0e10cSrcweir 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 176cdf0e10cSrcweir // method for cut support 177cdf0e10cSrcweir B2DPoint getCutPointForGivenY(double fGivenY) 178cdf0e10cSrcweir { 179cdf0e10cSrcweir // 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()); 183cdf0e10cSrcweir 184cdf0e10cSrcweir return B2DPoint(getStart().getX() + fDeltaXNew, fGivenY); 185cdf0e10cSrcweir } 186cdf0e10cSrcweir }; 187cdf0e10cSrcweir 188cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 189cdf0e10cSrcweir // define double linked list of edges (for fast random insert) 190cdf0e10cSrcweir 191cdf0e10cSrcweir typedef ::std::list< TrDeEdgeEntry > TrDeEdgeEntries; 192cdf0e10cSrcweir 193cdf0e10cSrcweir } // end of anonymous namespace 194cdf0e10cSrcweir } // end of namespace basegfx 195cdf0e10cSrcweir 196cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 197cdf0e10cSrcweir 198cdf0e10cSrcweir namespace basegfx 199cdf0e10cSrcweir { 200cdf0e10cSrcweir namespace trapezoidhelper 201cdf0e10cSrcweir { 202cdf0e10cSrcweir // helper class to handle the complete trapezoid subdivision of a PolyPolygon 203cdf0e10cSrcweir class TrapezoidSubdivider 204cdf0e10cSrcweir { 205cdf0e10cSrcweir private: 206cdf0e10cSrcweir // local data 207cdf0e10cSrcweir sal_uInt32 mnInitialEdgeEntryCount; 208cdf0e10cSrcweir TrDeEdgeEntries maTrDeEdgeEntries; 209cdf0e10cSrcweir ::std::vector< B2DPoint > maPoints; 210cdf0e10cSrcweir ::std::vector< B2DPoint* > maNewPoints; 211cdf0e10cSrcweir 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 226cdf0e10cSrcweir bool splitEdgeAtGivenPoint( 227cdf0e10cSrcweir TrDeEdgeEntries::reference aEdge, 228cdf0e10cSrcweir const B2DPoint& rCutPoint, 229cdf0e10cSrcweir TrDeEdgeEntries::iterator aCurrent) 230cdf0e10cSrcweir { 231cdf0e10cSrcweir // do not create edges without deltaY: do not split when start is identical 232cdf0e10cSrcweir if(aEdge.getStart().equal(rCutPoint, fTools::getSmallValue())) 233cdf0e10cSrcweir { 234cdf0e10cSrcweir return false; 235cdf0e10cSrcweir } 236cdf0e10cSrcweir 237cdf0e10cSrcweir // do not create edges without deltaY: do not split when end is identical 238cdf0e10cSrcweir if(aEdge.getEnd().equal(rCutPoint, fTools::getSmallValue())) 239cdf0e10cSrcweir { 240cdf0e10cSrcweir return false; 241cdf0e10cSrcweir } 242cdf0e10cSrcweir 243cdf0e10cSrcweir const double fOldDeltaYStart(rCutPoint.getY() - aEdge.getStart().getY()); 244cdf0e10cSrcweir 245cdf0e10cSrcweir if(fTools::lessOrEqual(fOldDeltaYStart, 0.0)) 246cdf0e10cSrcweir { 247cdf0e10cSrcweir // do not split: the resulting edge would be horizontal 248cdf0e10cSrcweir // correct it to new start point 249cdf0e10cSrcweir aEdge.setStart(&rCutPoint); 250cdf0e10cSrcweir return false; 251cdf0e10cSrcweir } 252cdf0e10cSrcweir 253cdf0e10cSrcweir const double fNewDeltaYStart(aEdge.getEnd().getY() - rCutPoint.getY()); 254cdf0e10cSrcweir 255cdf0e10cSrcweir if(fTools::lessOrEqual(fNewDeltaYStart, 0.0)) 256cdf0e10cSrcweir { 257cdf0e10cSrcweir // do not split: the resulting edge would be horizontal 258cdf0e10cSrcweir // correct it to new end point 259cdf0e10cSrcweir aEdge.setEnd(&rCutPoint); 260cdf0e10cSrcweir return false; 261cdf0e10cSrcweir } 262cdf0e10cSrcweir 263cdf0e10cSrcweir // Create new entry 264cdf0e10cSrcweir const TrDeEdgeEntry aNewEdge( 265cdf0e10cSrcweir &rCutPoint, 266cdf0e10cSrcweir &aEdge.getEnd(), 267cdf0e10cSrcweir aEdge.getSortValue()); 268cdf0e10cSrcweir 269cdf0e10cSrcweir // Correct old entry 270cdf0e10cSrcweir aEdge.setEnd(&rCutPoint); 271cdf0e10cSrcweir 272cdf0e10cSrcweir // Insert sorted (to avoid new sort) 273cdf0e10cSrcweir addEdgeSorted(aCurrent, aNewEdge); 274cdf0e10cSrcweir 275cdf0e10cSrcweir return true; 276cdf0e10cSrcweir } 277cdf0e10cSrcweir 278cdf0e10cSrcweir bool testAndCorrectEdgeIntersection( 279cdf0e10cSrcweir TrDeEdgeEntries::reference aEdgeA, 280cdf0e10cSrcweir TrDeEdgeEntries::reference aEdgeB, 281cdf0e10cSrcweir 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 } 288cdf0e10cSrcweir 289cdf0e10cSrcweir if(aEdgeA.getStart().equal(aEdgeB.getEnd(), fTools::getSmallValue())) 290cdf0e10cSrcweir { 291cdf0e10cSrcweir return false; 292cdf0e10cSrcweir } 293cdf0e10cSrcweir 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 305cdf0e10cSrcweir if(aEdgeA.getStart().equal(aEdgeA.getEnd(), fTools::getSmallValue())) 306cdf0e10cSrcweir { 307cdf0e10cSrcweir return false; 308cdf0e10cSrcweir } 309cdf0e10cSrcweir 310cdf0e10cSrcweir if(aEdgeB.getStart().equal(aEdgeB.getEnd(), fTools::getSmallValue())) 311cdf0e10cSrcweir { 312cdf0e10cSrcweir return false; 313cdf0e10cSrcweir } 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 341cdf0e10cSrcweir // 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, 350cdf0e10cSrcweir &fCutB)) 351cdf0e10cSrcweir { 352cdf0e10cSrcweir // use a simple metric (length criteria) for choosing the numerically 353cdf0e10cSrcweir // better cut 354cdf0e10cSrcweir const double fSimpleLengthA(aDeltaA.getX() + aDeltaA.getY()); 355cdf0e10cSrcweir const double fSimpleLengthB(aDeltaB.getX() + aDeltaB.getY()); 356cdf0e10cSrcweir const bool bAIsLonger(fSimpleLengthA > fSimpleLengthB); 357cdf0e10cSrcweir B2DPoint* pNewPoint = bAIsLonger 358cdf0e10cSrcweir ? new B2DPoint(aEdgeA.getStart() + (fCutA * aDeltaA)) 359cdf0e10cSrcweir : new B2DPoint(aEdgeB.getStart() + (fCutB * aDeltaB)); 360cdf0e10cSrcweir bool bRetval(false); 361cdf0e10cSrcweir 362cdf0e10cSrcweir // try to split both edges 363cdf0e10cSrcweir bRetval = splitEdgeAtGivenPoint(aEdgeA, *pNewPoint, aCurrent); 364cdf0e10cSrcweir bRetval |= splitEdgeAtGivenPoint(aEdgeB, *pNewPoint, aCurrent); 365cdf0e10cSrcweir 366cdf0e10cSrcweir if(bRetval) 367cdf0e10cSrcweir { 368cdf0e10cSrcweir maNewPoints.push_back(pNewPoint); 369cdf0e10cSrcweir } 370cdf0e10cSrcweir else 371cdf0e10cSrcweir { 372cdf0e10cSrcweir delete pNewPoint; 373cdf0e10cSrcweir } 374cdf0e10cSrcweir 375cdf0e10cSrcweir return bRetval; 376cdf0e10cSrcweir } 377cdf0e10cSrcweir 378cdf0e10cSrcweir return false; 379cdf0e10cSrcweir } 380cdf0e10cSrcweir 381cdf0e10cSrcweir void solveHorizontalEdges(TrDeSimpleEdges& rTrDeSimpleEdges) 382cdf0e10cSrcweir { 383cdf0e10cSrcweir if(rTrDeSimpleEdges.size() && maTrDeEdgeEntries.size()) 384cdf0e10cSrcweir { 385cdf0e10cSrcweir // there were horizontal edges. These can be excluded, but 386cdf0e10cSrcweir // cuts with other edges need to be solved and added before 387cdf0e10cSrcweir // ignoring them 388cdf0e10cSrcweir sal_uInt32 a(0); 389cdf0e10cSrcweir 390cdf0e10cSrcweir for(a = 0; a < rTrDeSimpleEdges.size(); a++) 391cdf0e10cSrcweir { 392cdf0e10cSrcweir // get horizontal edge as candidate; prepare it's range and fixed Y 393cdf0e10cSrcweir const TrDeSimpleEdge& rHorEdge = rTrDeSimpleEdges[a]; 394cdf0e10cSrcweir const B1DRange aRange(rHorEdge.getStart().getX(), rHorEdge.getEnd().getX()); 395cdf0e10cSrcweir const double fFixedY(rHorEdge.getStart().getY()); 396cdf0e10cSrcweir 397cdf0e10cSrcweir // loop over traversing edges 398cdf0e10cSrcweir TrDeEdgeEntries::iterator aCurrent(maTrDeEdgeEntries.begin()); 399cdf0e10cSrcweir 400cdf0e10cSrcweir do 401cdf0e10cSrcweir { 402cdf0e10cSrcweir // get compare edge 403cdf0e10cSrcweir TrDeEdgeEntries::reference aCompare(*aCurrent++); 404cdf0e10cSrcweir 405cdf0e10cSrcweir if(fTools::lessOrEqual(aCompare.getEnd().getY(), fFixedY)) 406cdf0e10cSrcweir { 407cdf0e10cSrcweir // edge ends above horizontal edge, continue 408cdf0e10cSrcweir continue; 409cdf0e10cSrcweir } 410cdf0e10cSrcweir 411cdf0e10cSrcweir if(fTools::moreOrEqual(aCompare.getStart().getY(), fFixedY)) 412cdf0e10cSrcweir { 413cdf0e10cSrcweir // edge starts below horizontal edge, continue 414cdf0e10cSrcweir continue; 415cdf0e10cSrcweir } 416cdf0e10cSrcweir 417cdf0e10cSrcweir // vertical overlap, get horizontal range 418cdf0e10cSrcweir const B1DRange aCompareRange(aCompare.getStart().getX(), aCompare.getEnd().getX()); 419cdf0e10cSrcweir 420cdf0e10cSrcweir if(aRange.overlaps(aCompareRange)) 421cdf0e10cSrcweir { 422cdf0e10cSrcweir // possible cut, get cut point 423cdf0e10cSrcweir const B2DPoint aSplit(aCompare.getCutPointForGivenY(fFixedY)); 424cdf0e10cSrcweir 425cdf0e10cSrcweir if(fTools::more(aSplit.getX(), aRange.getMinimum()) 426cdf0e10cSrcweir && fTools::less(aSplit.getX(), aRange.getMaximum())) 427cdf0e10cSrcweir { 428cdf0e10cSrcweir // cut is in XRange of horizontal edge, potenitally needed cut 429cdf0e10cSrcweir B2DPoint* pNewPoint = new B2DPoint(aSplit); 430cdf0e10cSrcweir 431cdf0e10cSrcweir if(splitEdgeAtGivenPoint(aCompare, *pNewPoint, aCurrent)) 432cdf0e10cSrcweir { 433cdf0e10cSrcweir maNewPoints.push_back(pNewPoint); 434cdf0e10cSrcweir } 435cdf0e10cSrcweir else 436cdf0e10cSrcweir { 437cdf0e10cSrcweir delete pNewPoint; 438cdf0e10cSrcweir } 439cdf0e10cSrcweir } 440cdf0e10cSrcweir } 441cdf0e10cSrcweir } 442cdf0e10cSrcweir while(aCurrent != maTrDeEdgeEntries.end() 443cdf0e10cSrcweir && fTools::less(aCurrent->getStart().getY(), fFixedY)); 444cdf0e10cSrcweir } 445cdf0e10cSrcweir } 446cdf0e10cSrcweir } 447cdf0e10cSrcweir 448cdf0e10cSrcweir public: 449cdf0e10cSrcweir TrapezoidSubdivider( 450cdf0e10cSrcweir const B2DPolyPolygon& rSourcePolyPolygon) 451cdf0e10cSrcweir : mnInitialEdgeEntryCount(0), 452cdf0e10cSrcweir maTrDeEdgeEntries(), 453cdf0e10cSrcweir maPoints(), 454cdf0e10cSrcweir maNewPoints() 455cdf0e10cSrcweir { 456cdf0e10cSrcweir B2DPolyPolygon aSource(rSourcePolyPolygon); 457cdf0e10cSrcweir const sal_uInt32 nPolygonCount(rSourcePolyPolygon.count()); 458cdf0e10cSrcweir TrDeSimpleEdges aTrDeSimpleEdges; 459cdf0e10cSrcweir sal_uInt32 a(0), b(0); 460cdf0e10cSrcweir sal_uInt32 nAllPointCount(0); 461cdf0e10cSrcweir 462cdf0e10cSrcweir // ensure there are no curves used 463cdf0e10cSrcweir if(aSource.areControlPointsUsed()) 464cdf0e10cSrcweir { 465cdf0e10cSrcweir aSource = aSource.getDefaultAdaptiveSubdivision(); 466cdf0e10cSrcweir } 467cdf0e10cSrcweir 468cdf0e10cSrcweir for(a = 0; a < nPolygonCount; a++) 469cdf0e10cSrcweir { 470cdf0e10cSrcweir // 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 { 482cdf0e10cSrcweir // reserve needed points. CAUTION: maPoints size is NOT to be changed anymore 483cdf0e10cSrcweir // 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 { 488cdf0e10cSrcweir // 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 501cdf0e10cSrcweir // Moved the edge construction to a 3rd run: doing it in the 2nd run is 502cdf0e10cSrcweir // possible(and i used it), but requires a working vector::reserve() 503cdf0e10cSrcweir // implementation, else the vector will be reallocated and the pointers 504cdf0e10cSrcweir // in the edges may be wrong. Security first here. 505cdf0e10cSrcweir sal_uInt32 nStartIndex(0); 506cdf0e10cSrcweir 507cdf0e10cSrcweir 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 { 514cdf0e10cSrcweir // get the last point of the current polygon 515cdf0e10cSrcweir B2DPoint* pPrev(&maPoints[nCount + nStartIndex - 1]); 516cdf0e10cSrcweir 517cdf0e10cSrcweir for(b = 0; b < nCount; b++) 518cdf0e10cSrcweir { 519cdf0e10cSrcweir // 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 528cdf0e10cSrcweir aTrDeSimpleEdges.push_back(TrDeSimpleEdge(pPrev, pCurr)); 529cdf0e10cSrcweir 530cdf0e10cSrcweir const double fMiddle((pPrev->getY() + pCurr->getY()) * 0.5); 531cdf0e10cSrcweir pPrev->setY(fMiddle); 532cdf0e10cSrcweir pCurr->setY(fMiddle); 533cdf0e10cSrcweir } 534cdf0e10cSrcweir } 535cdf0e10cSrcweir else 536cdf0e10cSrcweir { 537cdf0e10cSrcweir // vertical edge. Positive Y-direction is guaranteed by the 538cdf0e10cSrcweir // TrDeEdgeEntry constructor 539cdf0e10cSrcweir maTrDeEdgeEntries.push_back(TrDeEdgeEntry(pPrev, pCurr, 0)); 540cdf0e10cSrcweir mnInitialEdgeEntryCount++; 541cdf0e10cSrcweir } 542cdf0e10cSrcweir 543cdf0e10cSrcweir // prepare next step 544cdf0e10cSrcweir pPrev = pCurr; 545cdf0e10cSrcweir } 546cdf0e10cSrcweir } 547cdf0e10cSrcweir } 548cdf0e10cSrcweir } 549cdf0e10cSrcweir 550cdf0e10cSrcweir if(maTrDeEdgeEntries.size()) 551cdf0e10cSrcweir { 552cdf0e10cSrcweir // single and initial sort of traversing edges 553cdf0e10cSrcweir maTrDeEdgeEntries.sort(); 554cdf0e10cSrcweir 555cdf0e10cSrcweir // solve horizontal edges if there are any detected 556cdf0e10cSrcweir solveHorizontalEdges(aTrDeSimpleEdges); 557cdf0e10cSrcweir } 558cdf0e10cSrcweir } 559cdf0e10cSrcweir 560cdf0e10cSrcweir ~TrapezoidSubdivider() 561cdf0e10cSrcweir { 562cdf0e10cSrcweir // 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 571cdf0e10cSrcweir void Subdivide(B2DTrapezoidVector& ro_Result) 572cdf0e10cSrcweir { 573cdf0e10cSrcweir // This is the central subdivider. The strategy is to use the first two entries 574cdf0e10cSrcweir // from the traversing edges as a potential trapezoid and do the needed corrections 575cdf0e10cSrcweir // and adaptions on the way. 576cdf0e10cSrcweir // 577cdf0e10cSrcweir // There always must be two edges with the same YStart value: When adding the polygons 578cdf0e10cSrcweir // in the constructor, there is always a topmost point from which two edges start; when 579cdf0e10cSrcweir // the topmost is an edge, there is a start and end of this edge from which two edges 580cdf0e10cSrcweir // start. All cases have two edges with same StartY (QED). 581cdf0e10cSrcweir // 582cdf0e10cSrcweir // Based on this these edges get corrected when: 583cdf0e10cSrcweir // - one is longer than the other 584cdf0e10cSrcweir // - they intersect 585cdf0e10cSrcweir // - they intersect with other edges 586cdf0e10cSrcweir // - another edge starts inside the thought trapezoid 587cdf0e10cSrcweir // 588cdf0e10cSrcweir // All this cases again produce a valid state so that the first two edges have a common 589cdf0e10cSrcweir // Ystart again. Some cases lead to a restart of the process, some allow consuming the 590cdf0e10cSrcweir // edges and create the intended trapezoid. 591cdf0e10cSrcweir // 592cdf0e10cSrcweir // Be careful when doing chages here: It is essential to keep all possible paths 593cdf0e10cSrcweir // in valid states and to be numerically correct. This is especially needed e.g. 594cdf0e10cSrcweir // 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 602cdf0e10cSrcweir // not use maTrDeEdgeEntries.size() since that may be a non-constant time 603cdf0e10cSrcweir // operation for Lists. Instead, use mnInitialEdgeEntryCount which will contain 604cdf0e10cSrcweir // the roughly counted adds to the List 605cdf0e10cSrcweir ro_Result.reserve(ro_Result.size() + mnInitialEdgeEntryCount); 606cdf0e10cSrcweir } 607cdf0e10cSrcweir 608cdf0e10cSrcweir while(!maTrDeEdgeEntries.empty()) 609cdf0e10cSrcweir { 610cdf0e10cSrcweir // Prepare current operator and get first edge 611cdf0e10cSrcweir TrDeEdgeEntries::iterator aCurrent(maTrDeEdgeEntries.begin()); 612cdf0e10cSrcweir TrDeEdgeEntries::reference aLeft(*aCurrent++); 613cdf0e10cSrcweir 614cdf0e10cSrcweir if(aCurrent == maTrDeEdgeEntries.end()) 615cdf0e10cSrcweir { 616cdf0e10cSrcweir // Should not happen: No 2nd edge; consume the single edge 617cdf0e10cSrcweir // to not have an endless loop and start next. During development 618cdf0e10cSrcweir // i constantly had breakpoints here, so i am sure enough to add an 619cdf0e10cSrcweir // assertion here 620cdf0e10cSrcweir OSL_ENSURE(false, "Trapeziod decomposer in illegal state (!)"); 621cdf0e10cSrcweir maTrDeEdgeEntries.pop_front(); 622cdf0e10cSrcweir continue; 623cdf0e10cSrcweir } 624cdf0e10cSrcweir 625cdf0e10cSrcweir // get second edge 626cdf0e10cSrcweir TrDeEdgeEntries::reference aRight(*aCurrent++); 627cdf0e10cSrcweir 628cdf0e10cSrcweir if(!fTools::equal(aLeft.getStart().getY(), aRight.getStart().getY(), fTools::getSmallValue())) 629cdf0e10cSrcweir { 630cdf0e10cSrcweir // 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 632cdf0e10cSrcweir // next. During development i constantly had breakpoints here, so i am 633cdf0e10cSrcweir // sure enough to add an assertion here 634cdf0e10cSrcweir 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 642cdf0e10cSrcweir // 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 644cdf0e10cSrcweir // 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); 652cdf0e10cSrcweir 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 { 660cdf0e10cSrcweir aLeftEnd = aLeft.getCutPointForGivenY(aRightEnd.getY()); 661cdf0e10cSrcweir } 662cdf0e10cSrcweir else 663cdf0e10cSrcweir { 664cdf0e10cSrcweir 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 672cdf0e10cSrcweir // check the simple case that the edges form a 'blind' edge (deadend) 673cdf0e10cSrcweir if(bSameStartPoint && bSameEndPoint) 674cdf0e10cSrcweir { 675cdf0e10cSrcweir // correct the longer edge if prepared 676cdf0e10cSrcweir if(!bEndOnSameLine) 677cdf0e10cSrcweir { 678cdf0e10cSrcweir if(bLeftIsLonger) 679cdf0e10cSrcweir { 680cdf0e10cSrcweir B2DPoint* pNewPoint = new B2DPoint(aLeftEnd); 681cdf0e10cSrcweir 682cdf0e10cSrcweir if(splitEdgeAtGivenPoint(aLeft, *pNewPoint, aCurrent)) 683cdf0e10cSrcweir { 684cdf0e10cSrcweir maNewPoints.push_back(pNewPoint); 685cdf0e10cSrcweir } 686cdf0e10cSrcweir else 687cdf0e10cSrcweir { 688cdf0e10cSrcweir delete pNewPoint; 689cdf0e10cSrcweir } 690cdf0e10cSrcweir } 691cdf0e10cSrcweir else 692cdf0e10cSrcweir { 693cdf0e10cSrcweir B2DPoint* pNewPoint = new B2DPoint(aRightEnd); 694cdf0e10cSrcweir 695cdf0e10cSrcweir if(splitEdgeAtGivenPoint(aRight, *pNewPoint, aCurrent)) 696cdf0e10cSrcweir { 697cdf0e10cSrcweir maNewPoints.push_back(pNewPoint); 698cdf0e10cSrcweir } 699cdf0e10cSrcweir else 700cdf0e10cSrcweir { 701cdf0e10cSrcweir delete pNewPoint; 702cdf0e10cSrcweir } 703cdf0e10cSrcweir } 704cdf0e10cSrcweir } 705cdf0e10cSrcweir 706cdf0e10cSrcweir // consume both edges and start next run 707cdf0e10cSrcweir maTrDeEdgeEntries.pop_front(); 708cdf0e10cSrcweir maTrDeEdgeEntries.pop_front(); 709cdf0e10cSrcweir 710cdf0e10cSrcweir continue; 711cdf0e10cSrcweir } 712cdf0e10cSrcweir 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 738cdf0e10cSrcweir if(aCurrent != maTrDeEdgeEntries.end() 739cdf0e10cSrcweir && fTools::less(aCurrent->getStart().getY(), aLeftEnd.getY())) 740cdf0e10cSrcweir { 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 } 747cdf0e10cSrcweir 748cdf0e10cSrcweir // build full XRange for fast check 749cdf0e10cSrcweir B1DRange aAllRange(aLeftRange); 750cdf0e10cSrcweir aAllRange.expand(aRightRange); 751cdf0e10cSrcweir 752cdf0e10cSrcweir // prepare loop iterator; aCurrent needs to stay unchanged for 753cdf0e10cSrcweir // eventual sorted insertions of new EdgeNodes. Also prepare stop flag 754cdf0e10cSrcweir TrDeEdgeEntries::iterator aLoop(aCurrent); 755cdf0e10cSrcweir bool bDone(false); 756cdf0e10cSrcweir 757cdf0e10cSrcweir do 758cdf0e10cSrcweir { 759cdf0e10cSrcweir // get compare edge and it's XRange 760cdf0e10cSrcweir TrDeEdgeEntries::reference aCompare(*aLoop++); 761cdf0e10cSrcweir 762cdf0e10cSrcweir // avoid edges using the same start point as one of 763cdf0e10cSrcweir // the edges. These can neither have their start point 764cdf0e10cSrcweir // in the thought trapezoid nor cut with one of the edges 765cdf0e10cSrcweir if(aCompare.getStart().equal(aRight.getStart(), fTools::getSmallValue())) 766cdf0e10cSrcweir { 767cdf0e10cSrcweir continue; 768cdf0e10cSrcweir } 769cdf0e10cSrcweir 770cdf0e10cSrcweir // get compare XRange 771cdf0e10cSrcweir const B1DRange aCompareRange(aCompare.getStart().getX(), aCompare.getEnd().getX()); 772cdf0e10cSrcweir 773cdf0e10cSrcweir // use fast range test first 774cdf0e10cSrcweir if(aAllRange.overlaps(aCompareRange)) 775cdf0e10cSrcweir { 776cdf0e10cSrcweir // check for start point inside thought trapezoid 777cdf0e10cSrcweir if(fTools::more(aCompare.getStart().getY(), aLeft.getStart().getY())) 778cdf0e10cSrcweir { 779cdf0e10cSrcweir // calculate the two possible split points at compare's Y 780cdf0e10cSrcweir const B2DPoint aSplitLeft(aLeft.getCutPointForGivenY(aCompare.getStart().getY())); 781cdf0e10cSrcweir const B2DPoint aSplitRight(aRight.getCutPointForGivenY(aCompare.getStart().getY())); 782cdf0e10cSrcweir 783cdf0e10cSrcweir // check for start point of aCompare being inside thought 784cdf0e10cSrcweir // trapezoid 785cdf0e10cSrcweir if(aCompare.getStart().getX() >= aSplitLeft.getX() && 786cdf0e10cSrcweir aCompare.getStart().getX() <= aSplitRight.getX()) 787cdf0e10cSrcweir { 788cdf0e10cSrcweir // is inside, correct and restart loop 789cdf0e10cSrcweir B2DPoint* pNewLeft = new B2DPoint(aSplitLeft); 790cdf0e10cSrcweir 791cdf0e10cSrcweir if(splitEdgeAtGivenPoint(aLeft, *pNewLeft, aCurrent)) 792cdf0e10cSrcweir { 793cdf0e10cSrcweir maNewPoints.push_back(pNewLeft); 794cdf0e10cSrcweir bDone = true; 795cdf0e10cSrcweir } 796cdf0e10cSrcweir else 797cdf0e10cSrcweir { 798cdf0e10cSrcweir delete pNewLeft; 799cdf0e10cSrcweir } 800cdf0e10cSrcweir 801cdf0e10cSrcweir B2DPoint* pNewRight = new B2DPoint(aSplitRight); 802cdf0e10cSrcweir 803cdf0e10cSrcweir if(splitEdgeAtGivenPoint(aRight, *pNewRight, aCurrent)) 804cdf0e10cSrcweir { 805cdf0e10cSrcweir maNewPoints.push_back(pNewRight); 806cdf0e10cSrcweir bDone = true; 807cdf0e10cSrcweir } 808cdf0e10cSrcweir else 809cdf0e10cSrcweir { 810cdf0e10cSrcweir delete pNewRight; 811cdf0e10cSrcweir } 812cdf0e10cSrcweir } 813cdf0e10cSrcweir } 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 } 820cdf0e10cSrcweir 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 840cdf0e10cSrcweir // 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); 847cdf0e10cSrcweir 848cdf0e10cSrcweir if(splitEdgeAtGivenPoint(aLeft, *pNewPoint, aCurrent)) 849cdf0e10cSrcweir { 850cdf0e10cSrcweir maNewPoints.push_back(pNewPoint); 851cdf0e10cSrcweir } 852cdf0e10cSrcweir else 853cdf0e10cSrcweir { 854cdf0e10cSrcweir delete pNewPoint; 855cdf0e10cSrcweir } 856cdf0e10cSrcweir } 857cdf0e10cSrcweir else 858cdf0e10cSrcweir { 859cdf0e10cSrcweir B2DPoint* pNewPoint = new B2DPoint(aRightEnd); 860cdf0e10cSrcweir 861cdf0e10cSrcweir if(splitEdgeAtGivenPoint(aRight, *pNewPoint, aCurrent)) 862cdf0e10cSrcweir { 863cdf0e10cSrcweir maNewPoints.push_back(pNewPoint); 864cdf0e10cSrcweir } 865cdf0e10cSrcweir else 866cdf0e10cSrcweir { 867cdf0e10cSrcweir delete pNewPoint; 868cdf0e10cSrcweir } 869cdf0e10cSrcweir } 870cdf0e10cSrcweir } 871cdf0e10cSrcweir 872cdf0e10cSrcweir // the two edges start at the same Y, they use the same DeltaY, they 873cdf0e10cSrcweir // do not cut themselves and not any other edge in range. Create a 874cdf0e10cSrcweir // B2DTrapezoid and consume both edges 875cdf0e10cSrcweir ro_Result.push_back( 876cdf0e10cSrcweir B2DTrapezoid( 877cdf0e10cSrcweir aLeft.getStart().getX(), 878cdf0e10cSrcweir aRight.getStart().getX(), 879cdf0e10cSrcweir aLeft.getStart().getY(), 880cdf0e10cSrcweir aLeftEnd.getX(), 881cdf0e10cSrcweir aRightEnd.getX(), 882cdf0e10cSrcweir aLeftEnd.getY())); 883cdf0e10cSrcweir 884cdf0e10cSrcweir maTrDeEdgeEntries.pop_front(); 885cdf0e10cSrcweir maTrDeEdgeEntries.pop_front(); 886cdf0e10cSrcweir } 887cdf0e10cSrcweir } 888cdf0e10cSrcweir }; 889cdf0e10cSrcweir } // end of anonymous namespace 890cdf0e10cSrcweir } // end of namespace basegfx 891cdf0e10cSrcweir 892cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 893cdf0e10cSrcweir 894cdf0e10cSrcweir namespace basegfx 895cdf0e10cSrcweir { 896cdf0e10cSrcweir 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 { 910cdf0e10cSrcweir // guarantee mfTopXRight >= mfTopXLeft 911cdf0e10cSrcweir if(mfTopXLeft > mfTopXRight) 912cdf0e10cSrcweir { 913cdf0e10cSrcweir std::swap(mfTopXLeft, mfTopXRight); 914cdf0e10cSrcweir } 915cdf0e10cSrcweir 916cdf0e10cSrcweir // guarantee mfBottomXRight >= mfBottomXLeft 917cdf0e10cSrcweir if(mfBottomXLeft > mfBottomXRight) 918cdf0e10cSrcweir { 919cdf0e10cSrcweir std::swap(mfBottomXLeft, mfBottomXRight); 920cdf0e10cSrcweir } 921cdf0e10cSrcweir 922cdf0e10cSrcweir // guarantee mfBottomY >= mfTopY 923cdf0e10cSrcweir if(mfTopY > mfBottomY) 924cdf0e10cSrcweir { 925cdf0e10cSrcweir std::swap(mfTopY, mfBottomY); 926cdf0e10cSrcweir std::swap(mfTopXLeft, mfBottomXLeft); 927cdf0e10cSrcweir std::swap(mfTopXRight, mfBottomXRight); 928cdf0e10cSrcweir } 929cdf0e10cSrcweir } 930cdf0e10cSrcweir 931cdf0e10cSrcweir 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 { 951cdf0e10cSrcweir // convert Source PolyPolygon to trapezoids 952cdf0e10cSrcweir void trapezoidSubdivide(B2DTrapezoidVector& ro_Result, const B2DPolyPolygon& rSourcePolyPolygon) 953cdf0e10cSrcweir { 954cdf0e10cSrcweir trapezoidhelper::TrapezoidSubdivider aTrapezoidSubdivider(rSourcePolyPolygon); 955cdf0e10cSrcweir 956cdf0e10cSrcweir aTrapezoidSubdivider.Subdivide(ro_Result); 957cdf0e10cSrcweir } 958cdf0e10cSrcweir 959cdf0e10cSrcweir void createLineTrapezoidFromEdge( 960cdf0e10cSrcweir B2DTrapezoidVector& ro_Result, 961cdf0e10cSrcweir const B2DPoint& rPointA, 962cdf0e10cSrcweir const B2DPoint& rPointB, 963cdf0e10cSrcweir double fLineWidth) 964cdf0e10cSrcweir { 965cdf0e10cSrcweir if(fTools::lessOrEqual(fLineWidth, 0.0)) 966cdf0e10cSrcweir { 967cdf0e10cSrcweir // no line witdh 968cdf0e10cSrcweir return; 969cdf0e10cSrcweir } 970cdf0e10cSrcweir 971cdf0e10cSrcweir if(rPointA.equal(rPointB, fTools::getSmallValue())) 972cdf0e10cSrcweir { 973cdf0e10cSrcweir // points are equal, no edge 974cdf0e10cSrcweir return; 975cdf0e10cSrcweir } 976cdf0e10cSrcweir 977cdf0e10cSrcweir const double fHalfLineWidth(0.5 * fLineWidth); 978cdf0e10cSrcweir 979cdf0e10cSrcweir if(fTools::equal(rPointA.getX(), rPointB.getX(), fTools::getSmallValue())) 980cdf0e10cSrcweir { 981cdf0e10cSrcweir // vertical line 982cdf0e10cSrcweir const double fLeftX(rPointA.getX() - fHalfLineWidth); 983cdf0e10cSrcweir const double fRightX(rPointA.getX() + fHalfLineWidth); 984cdf0e10cSrcweir 985cdf0e10cSrcweir ro_Result.push_back( 986cdf0e10cSrcweir B2DTrapezoid( 987cdf0e10cSrcweir fLeftX, 988cdf0e10cSrcweir fRightX, 989cdf0e10cSrcweir std::min(rPointA.getY(), rPointB.getY()), 990cdf0e10cSrcweir fLeftX, 991cdf0e10cSrcweir fRightX, 992cdf0e10cSrcweir std::max(rPointA.getY(), rPointB.getY()))); 993cdf0e10cSrcweir } 994cdf0e10cSrcweir else if(fTools::equal(rPointA.getY(), rPointB.getY(), fTools::getSmallValue())) 995cdf0e10cSrcweir { 996cdf0e10cSrcweir // horizontal line 997cdf0e10cSrcweir const double fLeftX(std::min(rPointA.getX(), rPointB.getX())); 998cdf0e10cSrcweir const double fRightX(std::max(rPointA.getX(), rPointB.getX())); 999cdf0e10cSrcweir 1000cdf0e10cSrcweir ro_Result.push_back( 1001cdf0e10cSrcweir B2DTrapezoid( 1002cdf0e10cSrcweir fLeftX, 1003cdf0e10cSrcweir fRightX, 1004cdf0e10cSrcweir rPointA.getY() - fHalfLineWidth, 1005cdf0e10cSrcweir fLeftX, 1006cdf0e10cSrcweir fRightX, 1007cdf0e10cSrcweir rPointA.getY() + fHalfLineWidth)); 1008cdf0e10cSrcweir } 1009cdf0e10cSrcweir else 1010cdf0e10cSrcweir { 1011cdf0e10cSrcweir // diagonal line 1012cdf0e10cSrcweir // create perpendicular vector 1013cdf0e10cSrcweir const B2DVector aDelta(rPointB - rPointA); 1014cdf0e10cSrcweir B2DVector aPerpendicular(-aDelta.getY(), aDelta.getX()); 1015cdf0e10cSrcweir aPerpendicular.setLength(fHalfLineWidth); 1016cdf0e10cSrcweir 1017cdf0e10cSrcweir // create StartLow, StartHigh, EndLow and EndHigh 1018cdf0e10cSrcweir const B2DPoint aStartLow(rPointA + aPerpendicular); 1019cdf0e10cSrcweir const B2DPoint aStartHigh(rPointA - aPerpendicular); 1020cdf0e10cSrcweir const B2DPoint aEndHigh(rPointB - aPerpendicular); 1021cdf0e10cSrcweir const B2DPoint aEndLow(rPointB + aPerpendicular); 1022cdf0e10cSrcweir 1023cdf0e10cSrcweir // create EdgeEntries 1024cdf0e10cSrcweir basegfx::trapezoidhelper::TrDeEdgeEntries aTrDeEdgeEntries; 1025cdf0e10cSrcweir 1026cdf0e10cSrcweir aTrDeEdgeEntries.push_back(basegfx::trapezoidhelper::TrDeEdgeEntry(&aStartLow, &aStartHigh, 0)); 1027cdf0e10cSrcweir aTrDeEdgeEntries.push_back(basegfx::trapezoidhelper::TrDeEdgeEntry(&aStartHigh, &aEndHigh, 0)); 1028cdf0e10cSrcweir aTrDeEdgeEntries.push_back(basegfx::trapezoidhelper::TrDeEdgeEntry(&aEndHigh, &aEndLow, 0)); 1029cdf0e10cSrcweir aTrDeEdgeEntries.push_back(basegfx::trapezoidhelper::TrDeEdgeEntry(&aEndLow, &aStartLow, 0)); 1030cdf0e10cSrcweir aTrDeEdgeEntries.sort(); 1031cdf0e10cSrcweir 1032cdf0e10cSrcweir // here we know we have exactly four edges, and they do not cut, touch or 1033cdf0e10cSrcweir // intersect. This makes processing much easier. Get the first two as start 1034cdf0e10cSrcweir // edges for the thought trapezoid 1035cdf0e10cSrcweir basegfx::trapezoidhelper::TrDeEdgeEntries::iterator aCurrent(aTrDeEdgeEntries.begin()); 1036cdf0e10cSrcweir basegfx::trapezoidhelper::TrDeEdgeEntries::reference aLeft(*aCurrent++); 1037cdf0e10cSrcweir basegfx::trapezoidhelper::TrDeEdgeEntries::reference aRight(*aCurrent++); 1038cdf0e10cSrcweir const bool bEndOnSameLine(fTools::equal(aLeft.getEnd().getY(), aRight.getEnd().getY(), fTools::getSmallValue())); 1039cdf0e10cSrcweir 1040cdf0e10cSrcweir if(bEndOnSameLine) 1041cdf0e10cSrcweir { 1042cdf0e10cSrcweir // create two triangle trapezoids 1043cdf0e10cSrcweir ro_Result.push_back( 1044cdf0e10cSrcweir B2DTrapezoid( 1045cdf0e10cSrcweir aLeft.getStart().getX(), 1046cdf0e10cSrcweir aRight.getStart().getX(), 1047cdf0e10cSrcweir aLeft.getStart().getY(), 1048cdf0e10cSrcweir aLeft.getEnd().getX(), 1049cdf0e10cSrcweir aRight.getEnd().getX(), 1050cdf0e10cSrcweir aLeft.getEnd().getY())); 1051cdf0e10cSrcweir 1052cdf0e10cSrcweir basegfx::trapezoidhelper::TrDeEdgeEntries::reference aLeft2(*aCurrent++); 1053cdf0e10cSrcweir basegfx::trapezoidhelper::TrDeEdgeEntries::reference aRight2(*aCurrent++); 1054cdf0e10cSrcweir 1055cdf0e10cSrcweir ro_Result.push_back( 1056cdf0e10cSrcweir B2DTrapezoid( 1057cdf0e10cSrcweir aLeft2.getStart().getX(), 1058cdf0e10cSrcweir aRight2.getStart().getX(), 1059cdf0e10cSrcweir aLeft2.getStart().getY(), 1060cdf0e10cSrcweir aLeft2.getEnd().getX(), 1061cdf0e10cSrcweir aRight2.getEnd().getX(), 1062cdf0e10cSrcweir aLeft2.getEnd().getY())); 1063cdf0e10cSrcweir } 1064cdf0e10cSrcweir else 1065cdf0e10cSrcweir { 1066cdf0e10cSrcweir // create three trapezoids. Check which edge is longer and 1067cdf0e10cSrcweir // correct accordingly 1068cdf0e10cSrcweir const bool bLeftIsLonger(fTools::more(aLeft.getEnd().getY(), aRight.getEnd().getY())); 1069cdf0e10cSrcweir 1070cdf0e10cSrcweir if(bLeftIsLonger) 1071cdf0e10cSrcweir { 1072cdf0e10cSrcweir basegfx::trapezoidhelper::TrDeEdgeEntries::reference aRight2(*aCurrent++); 1073cdf0e10cSrcweir basegfx::trapezoidhelper::TrDeEdgeEntries::reference aLeft2(*aCurrent++); 1074cdf0e10cSrcweir const B2DPoint aSplitLeft(aLeft.getCutPointForGivenY(aRight.getEnd().getY())); 1075cdf0e10cSrcweir const B2DPoint aSplitRight(aRight2.getCutPointForGivenY(aLeft.getEnd().getY())); 1076cdf0e10cSrcweir 1077cdf0e10cSrcweir ro_Result.push_back( 1078cdf0e10cSrcweir B2DTrapezoid( 1079cdf0e10cSrcweir aLeft.getStart().getX(), 1080cdf0e10cSrcweir aRight.getStart().getX(), 1081cdf0e10cSrcweir aLeft.getStart().getY(), 1082cdf0e10cSrcweir aSplitLeft.getX(), 1083cdf0e10cSrcweir aRight.getEnd().getX(), 1084cdf0e10cSrcweir aRight.getEnd().getY())); 1085cdf0e10cSrcweir 1086cdf0e10cSrcweir ro_Result.push_back( 1087cdf0e10cSrcweir B2DTrapezoid( 1088cdf0e10cSrcweir aSplitLeft.getX(), 1089cdf0e10cSrcweir aRight.getEnd().getX(), 1090cdf0e10cSrcweir aRight.getEnd().getY(), 1091cdf0e10cSrcweir aLeft2.getStart().getX(), 1092cdf0e10cSrcweir aSplitRight.getX(), 1093cdf0e10cSrcweir aLeft2.getStart().getY())); 1094cdf0e10cSrcweir 1095cdf0e10cSrcweir ro_Result.push_back( 1096cdf0e10cSrcweir B2DTrapezoid( 1097cdf0e10cSrcweir aLeft2.getStart().getX(), 1098cdf0e10cSrcweir aSplitRight.getX(), 1099cdf0e10cSrcweir aLeft2.getStart().getY(), 1100cdf0e10cSrcweir aLeft2.getEnd().getX(), 1101cdf0e10cSrcweir aRight2.getEnd().getX(), 1102cdf0e10cSrcweir aLeft2.getEnd().getY())); 1103cdf0e10cSrcweir } 1104cdf0e10cSrcweir else 1105cdf0e10cSrcweir { 1106cdf0e10cSrcweir basegfx::trapezoidhelper::TrDeEdgeEntries::reference aLeft2(*aCurrent++); 1107cdf0e10cSrcweir basegfx::trapezoidhelper::TrDeEdgeEntries::reference aRight2(*aCurrent++); 1108cdf0e10cSrcweir const B2DPoint aSplitRight(aRight.getCutPointForGivenY(aLeft.getEnd().getY())); 1109cdf0e10cSrcweir const B2DPoint aSplitLeft(aLeft2.getCutPointForGivenY(aRight.getEnd().getY())); 1110cdf0e10cSrcweir 1111cdf0e10cSrcweir ro_Result.push_back( 1112cdf0e10cSrcweir B2DTrapezoid( 1113cdf0e10cSrcweir aLeft.getStart().getX(), 1114cdf0e10cSrcweir aRight.getStart().getX(), 1115cdf0e10cSrcweir aLeft.getStart().getY(), 1116cdf0e10cSrcweir aLeft.getEnd().getX(), 1117cdf0e10cSrcweir aSplitRight.getX(), 1118cdf0e10cSrcweir aLeft.getEnd().getY())); 1119cdf0e10cSrcweir 1120cdf0e10cSrcweir ro_Result.push_back( 1121cdf0e10cSrcweir B2DTrapezoid( 1122cdf0e10cSrcweir aLeft.getEnd().getX(), 1123cdf0e10cSrcweir aSplitRight.getX(), 1124cdf0e10cSrcweir aLeft.getEnd().getY(), 1125cdf0e10cSrcweir aSplitLeft.getX(), 1126cdf0e10cSrcweir aRight.getEnd().getX(), 1127cdf0e10cSrcweir aRight2.getStart().getY())); 1128cdf0e10cSrcweir 1129cdf0e10cSrcweir ro_Result.push_back( 1130cdf0e10cSrcweir B2DTrapezoid( 1131cdf0e10cSrcweir aSplitLeft.getX(), 1132cdf0e10cSrcweir aRight.getEnd().getX(), 1133cdf0e10cSrcweir aRight2.getStart().getY(), 1134cdf0e10cSrcweir aLeft2.getEnd().getX(), 1135cdf0e10cSrcweir aRight2.getEnd().getX(), 1136cdf0e10cSrcweir aLeft2.getEnd().getY())); 1137cdf0e10cSrcweir } 1138cdf0e10cSrcweir } 1139cdf0e10cSrcweir } 1140cdf0e10cSrcweir } 1141cdf0e10cSrcweir 1142cdf0e10cSrcweir void createLineTrapezoidFromB2DPolygon( 1143cdf0e10cSrcweir B2DTrapezoidVector& ro_Result, 1144cdf0e10cSrcweir const B2DPolygon& rPolygon, 1145cdf0e10cSrcweir double fLineWidth) 1146cdf0e10cSrcweir { 1147cdf0e10cSrcweir if(fTools::lessOrEqual(fLineWidth, 0.0)) 1148cdf0e10cSrcweir { 1149cdf0e10cSrcweir return; 1150cdf0e10cSrcweir } 1151cdf0e10cSrcweir 1152cdf0e10cSrcweir // ensure there are no curves used 1153cdf0e10cSrcweir B2DPolygon aSource(rPolygon); 1154cdf0e10cSrcweir 1155cdf0e10cSrcweir if(aSource.areControlPointsUsed()) 1156cdf0e10cSrcweir { 1157cdf0e10cSrcweir const double fPrecisionFactor = 0.25; 1158cdf0e10cSrcweir aSource = adaptiveSubdivideByDistance( aSource, fLineWidth * fPrecisionFactor ); 1159cdf0e10cSrcweir } 1160cdf0e10cSrcweir 1161cdf0e10cSrcweir const sal_uInt32 nPointCount(aSource.count()); 1162cdf0e10cSrcweir 1163cdf0e10cSrcweir if(!nPointCount) 1164cdf0e10cSrcweir { 1165cdf0e10cSrcweir return; 1166cdf0e10cSrcweir } 1167cdf0e10cSrcweir 1168cdf0e10cSrcweir const sal_uInt32 nEdgeCount(aSource.isClosed() ? nPointCount : nPointCount - 1); 1169cdf0e10cSrcweir B2DPoint aCurrent(aSource.getB2DPoint(0)); 1170cdf0e10cSrcweir 1171cdf0e10cSrcweir ro_Result.reserve(ro_Result.size() + (3 * nEdgeCount)); 1172cdf0e10cSrcweir 1173cdf0e10cSrcweir for(sal_uInt32 a(0); a < nEdgeCount; a++) 1174cdf0e10cSrcweir { 1175cdf0e10cSrcweir const sal_uInt32 nNextIndex((a + 1) % nPointCount); 1176cdf0e10cSrcweir const B2DPoint aNext(aSource.getB2DPoint(nNextIndex)); 1177cdf0e10cSrcweir 1178cdf0e10cSrcweir createLineTrapezoidFromEdge(ro_Result, aCurrent, aNext, fLineWidth); 1179cdf0e10cSrcweir aCurrent = aNext; 1180cdf0e10cSrcweir } 1181cdf0e10cSrcweir } 1182cdf0e10cSrcweir 1183cdf0e10cSrcweir void createLineTrapezoidFromB2DPolyPolygon( 1184cdf0e10cSrcweir B2DTrapezoidVector& ro_Result, 1185cdf0e10cSrcweir const B2DPolyPolygon& rPolyPolygon, 1186cdf0e10cSrcweir double fLineWidth) 1187cdf0e10cSrcweir { 1188cdf0e10cSrcweir if(fTools::lessOrEqual(fLineWidth, 0.0)) 1189cdf0e10cSrcweir { 1190cdf0e10cSrcweir return; 1191cdf0e10cSrcweir } 1192cdf0e10cSrcweir 1193cdf0e10cSrcweir // ensure there are no curves used 1194cdf0e10cSrcweir B2DPolyPolygon aSource(rPolyPolygon); 1195cdf0e10cSrcweir 1196cdf0e10cSrcweir if(aSource.areControlPointsUsed()) 1197cdf0e10cSrcweir { 1198cdf0e10cSrcweir aSource = aSource.getDefaultAdaptiveSubdivision(); 1199cdf0e10cSrcweir } 1200cdf0e10cSrcweir 1201cdf0e10cSrcweir const sal_uInt32 nCount(aSource.count()); 1202cdf0e10cSrcweir 1203cdf0e10cSrcweir if(!nCount) 1204cdf0e10cSrcweir { 1205cdf0e10cSrcweir return; 1206cdf0e10cSrcweir } 1207cdf0e10cSrcweir 1208cdf0e10cSrcweir for(sal_uInt32 a(0); a < nCount; a++) 1209cdf0e10cSrcweir { 1210cdf0e10cSrcweir createLineTrapezoidFromB2DPolygon( 1211cdf0e10cSrcweir ro_Result, 1212cdf0e10cSrcweir aSource.getB2DPolygon(a), 1213cdf0e10cSrcweir fLineWidth); 1214cdf0e10cSrcweir } 1215cdf0e10cSrcweir } 1216cdf0e10cSrcweir 1217cdf0e10cSrcweir } // end of namespace tools 1218cdf0e10cSrcweir } // end of namespace basegfx 1219cdf0e10cSrcweir 1220cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 1221cdf0e10cSrcweir // eof 1222