1*cdf0e10cSrcweir /************************************************************************* 2*cdf0e10cSrcweir * 3*cdf0e10cSrcweir * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4*cdf0e10cSrcweir * 5*cdf0e10cSrcweir * Copyright 2000, 2010 Oracle and/or its affiliates. 6*cdf0e10cSrcweir * 7*cdf0e10cSrcweir * OpenOffice.org - a multi-platform office productivity suite 8*cdf0e10cSrcweir * 9*cdf0e10cSrcweir * This file is part of OpenOffice.org. 10*cdf0e10cSrcweir * 11*cdf0e10cSrcweir * OpenOffice.org is free software: you can redistribute it and/or modify 12*cdf0e10cSrcweir * it under the terms of the GNU Lesser General Public License version 3 13*cdf0e10cSrcweir * only, as published by the Free Software Foundation. 14*cdf0e10cSrcweir * 15*cdf0e10cSrcweir * OpenOffice.org is distributed in the hope that it will be useful, 16*cdf0e10cSrcweir * but WITHOUT ANY WARRANTY; without even the implied warranty of 17*cdf0e10cSrcweir * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18*cdf0e10cSrcweir * GNU Lesser General Public License version 3 for more details 19*cdf0e10cSrcweir * (a copy is included in the LICENSE file that accompanied this code). 20*cdf0e10cSrcweir * 21*cdf0e10cSrcweir * You should have received a copy of the GNU Lesser General Public License 22*cdf0e10cSrcweir * version 3 along with OpenOffice.org. If not, see 23*cdf0e10cSrcweir * <http://www.openoffice.org/license.html> 24*cdf0e10cSrcweir * for a copy of the LGPLv3 License. 25*cdf0e10cSrcweir * 26*cdf0e10cSrcweir ************************************************************************/ 27*cdf0e10cSrcweir 28*cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 29*cdf0e10cSrcweir #include "precompiled_basegfx.hxx" 30*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygontriangulator.hxx> 31*cdf0e10cSrcweir #include <osl/diagnose.h> 32*cdf0e10cSrcweir #include <basegfx/point/b2dpoint.hxx> 33*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygon.hxx> 34*cdf0e10cSrcweir #include <basegfx/vector/b2dvector.hxx> 35*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygontools.hxx> 36*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygontools.hxx> 37*cdf0e10cSrcweir #include <basegfx/range/b2drange.hxx> 38*cdf0e10cSrcweir #include <basegfx/numeric/ftools.hxx> 39*cdf0e10cSrcweir 40*cdf0e10cSrcweir #include <algorithm> 41*cdf0e10cSrcweir 42*cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 43*cdf0e10cSrcweir 44*cdf0e10cSrcweir namespace basegfx 45*cdf0e10cSrcweir { 46*cdf0e10cSrcweir namespace 47*cdf0e10cSrcweir { 48*cdf0e10cSrcweir class EdgeEntry 49*cdf0e10cSrcweir { 50*cdf0e10cSrcweir EdgeEntry* mpNext; 51*cdf0e10cSrcweir B2DPoint maStart; 52*cdf0e10cSrcweir B2DPoint maEnd; 53*cdf0e10cSrcweir double mfAtan2; 54*cdf0e10cSrcweir 55*cdf0e10cSrcweir public: 56*cdf0e10cSrcweir EdgeEntry(const B2DPoint& rStart, const B2DPoint& rEnd) 57*cdf0e10cSrcweir : mpNext(0L), 58*cdf0e10cSrcweir maStart(rStart), 59*cdf0e10cSrcweir maEnd(rEnd), 60*cdf0e10cSrcweir mfAtan2(0.0) 61*cdf0e10cSrcweir { 62*cdf0e10cSrcweir // make sure edge goes down. If horizontal, let it go to the right (left-handed). 63*cdf0e10cSrcweir bool bSwap(false); 64*cdf0e10cSrcweir 65*cdf0e10cSrcweir if(::basegfx::fTools::equal(maStart.getY(), maEnd.getY())) 66*cdf0e10cSrcweir { 67*cdf0e10cSrcweir if(maStart.getX() > maEnd.getX()) 68*cdf0e10cSrcweir { 69*cdf0e10cSrcweir bSwap = true; 70*cdf0e10cSrcweir } 71*cdf0e10cSrcweir } 72*cdf0e10cSrcweir else if(maStart.getY() > maEnd.getY()) 73*cdf0e10cSrcweir { 74*cdf0e10cSrcweir bSwap = true; 75*cdf0e10cSrcweir } 76*cdf0e10cSrcweir 77*cdf0e10cSrcweir if(bSwap) 78*cdf0e10cSrcweir { 79*cdf0e10cSrcweir maStart = rEnd; 80*cdf0e10cSrcweir maEnd = rStart; 81*cdf0e10cSrcweir } 82*cdf0e10cSrcweir 83*cdf0e10cSrcweir mfAtan2 = atan2(maEnd.getY() - maStart.getY(), maEnd.getX() - maStart.getX()); 84*cdf0e10cSrcweir } 85*cdf0e10cSrcweir 86*cdf0e10cSrcweir ~EdgeEntry() 87*cdf0e10cSrcweir { 88*cdf0e10cSrcweir } 89*cdf0e10cSrcweir 90*cdf0e10cSrcweir bool operator<(const EdgeEntry& rComp) const 91*cdf0e10cSrcweir { 92*cdf0e10cSrcweir if(::basegfx::fTools::equal(maStart.getY(), rComp.maStart.getY())) 93*cdf0e10cSrcweir { 94*cdf0e10cSrcweir if(::basegfx::fTools::equal(maStart.getX(), rComp.maStart.getX())) 95*cdf0e10cSrcweir { 96*cdf0e10cSrcweir // same in x and y -> same start point. Sort emitting vectors from left to right. 97*cdf0e10cSrcweir return (mfAtan2 > rComp.mfAtan2); 98*cdf0e10cSrcweir } 99*cdf0e10cSrcweir 100*cdf0e10cSrcweir return (maStart.getX() < rComp.maStart.getX()); 101*cdf0e10cSrcweir } 102*cdf0e10cSrcweir 103*cdf0e10cSrcweir return (maStart.getY() < rComp.maStart.getY()); 104*cdf0e10cSrcweir } 105*cdf0e10cSrcweir 106*cdf0e10cSrcweir bool operator==(const EdgeEntry& rComp) const 107*cdf0e10cSrcweir { 108*cdf0e10cSrcweir return (maStart.equal(rComp.maStart) && maEnd.equal(rComp.maEnd)); 109*cdf0e10cSrcweir } 110*cdf0e10cSrcweir 111*cdf0e10cSrcweir bool operator!=(const EdgeEntry& rComp) const 112*cdf0e10cSrcweir { 113*cdf0e10cSrcweir return !(*this == rComp); 114*cdf0e10cSrcweir } 115*cdf0e10cSrcweir 116*cdf0e10cSrcweir const B2DPoint& getStart() const { return maStart; } 117*cdf0e10cSrcweir const B2DPoint& getEnd() const { return maEnd; } 118*cdf0e10cSrcweir 119*cdf0e10cSrcweir EdgeEntry* getNext() const { return mpNext; } 120*cdf0e10cSrcweir void setNext(EdgeEntry* pNext) { mpNext = pNext; } 121*cdf0e10cSrcweir }; 122*cdf0e10cSrcweir 123*cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 124*cdf0e10cSrcweir 125*cdf0e10cSrcweir typedef ::std::vector< EdgeEntry > EdgeEntries; 126*cdf0e10cSrcweir typedef ::std::vector< EdgeEntry* > EdgeEntryPointers; 127*cdf0e10cSrcweir 128*cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 129*cdf0e10cSrcweir 130*cdf0e10cSrcweir class Triangulator 131*cdf0e10cSrcweir { 132*cdf0e10cSrcweir EdgeEntry* mpList; 133*cdf0e10cSrcweir EdgeEntries maStartEntries; 134*cdf0e10cSrcweir EdgeEntryPointers maNewEdgeEntries; 135*cdf0e10cSrcweir B2DPolygon maResult; 136*cdf0e10cSrcweir 137*cdf0e10cSrcweir void handleClosingEdge(const B2DPoint& rStart, const B2DPoint& rEnd); 138*cdf0e10cSrcweir bool CheckPointInTriangle(EdgeEntry* pEdgeA, EdgeEntry* pEdgeB, const B2DPoint& rTestPoint); 139*cdf0e10cSrcweir void createTriangle(const B2DPoint& rA, const B2DPoint& rB, const B2DPoint& rC); 140*cdf0e10cSrcweir 141*cdf0e10cSrcweir public: 142*cdf0e10cSrcweir Triangulator(const B2DPolyPolygon& rCandidate); 143*cdf0e10cSrcweir ~Triangulator(); 144*cdf0e10cSrcweir 145*cdf0e10cSrcweir const B2DPolygon getResult() const { return maResult; } 146*cdf0e10cSrcweir }; 147*cdf0e10cSrcweir 148*cdf0e10cSrcweir void Triangulator::handleClosingEdge(const B2DPoint& rStart, const B2DPoint& rEnd) 149*cdf0e10cSrcweir { 150*cdf0e10cSrcweir // create an entry, else the comparison might use the wrong edges 151*cdf0e10cSrcweir EdgeEntry aNew(rStart, rEnd); 152*cdf0e10cSrcweir EdgeEntry* pCurr = mpList; 153*cdf0e10cSrcweir EdgeEntry* pPrev = 0L; 154*cdf0e10cSrcweir 155*cdf0e10cSrcweir while(pCurr 156*cdf0e10cSrcweir && pCurr->getStart().getY() <= aNew.getStart().getY() 157*cdf0e10cSrcweir && *pCurr != aNew) 158*cdf0e10cSrcweir { 159*cdf0e10cSrcweir pPrev = pCurr; 160*cdf0e10cSrcweir pCurr = pCurr->getNext(); 161*cdf0e10cSrcweir } 162*cdf0e10cSrcweir 163*cdf0e10cSrcweir if(pCurr && *pCurr == aNew) 164*cdf0e10cSrcweir { 165*cdf0e10cSrcweir // found closing edge, remove 166*cdf0e10cSrcweir if(pPrev) 167*cdf0e10cSrcweir { 168*cdf0e10cSrcweir pPrev->setNext(pCurr->getNext()); 169*cdf0e10cSrcweir } 170*cdf0e10cSrcweir else 171*cdf0e10cSrcweir { 172*cdf0e10cSrcweir mpList = pCurr->getNext(); 173*cdf0e10cSrcweir } 174*cdf0e10cSrcweir } 175*cdf0e10cSrcweir else 176*cdf0e10cSrcweir { 177*cdf0e10cSrcweir // insert closing edge 178*cdf0e10cSrcweir EdgeEntry* pNew = new EdgeEntry(aNew); 179*cdf0e10cSrcweir maNewEdgeEntries.push_back(pNew); 180*cdf0e10cSrcweir pCurr = mpList; 181*cdf0e10cSrcweir pPrev = 0L; 182*cdf0e10cSrcweir 183*cdf0e10cSrcweir while(pCurr && *pCurr < *pNew) 184*cdf0e10cSrcweir { 185*cdf0e10cSrcweir pPrev = pCurr; 186*cdf0e10cSrcweir pCurr = pCurr->getNext(); 187*cdf0e10cSrcweir } 188*cdf0e10cSrcweir 189*cdf0e10cSrcweir if(pPrev) 190*cdf0e10cSrcweir { 191*cdf0e10cSrcweir pNew->setNext(pPrev->getNext()); 192*cdf0e10cSrcweir pPrev->setNext(pNew); 193*cdf0e10cSrcweir } 194*cdf0e10cSrcweir else 195*cdf0e10cSrcweir { 196*cdf0e10cSrcweir pNew->setNext(mpList); 197*cdf0e10cSrcweir mpList = pNew; 198*cdf0e10cSrcweir } 199*cdf0e10cSrcweir } 200*cdf0e10cSrcweir } 201*cdf0e10cSrcweir 202*cdf0e10cSrcweir bool Triangulator::CheckPointInTriangle(EdgeEntry* pEdgeA, EdgeEntry* pEdgeB, const B2DPoint& rTestPoint) 203*cdf0e10cSrcweir { 204*cdf0e10cSrcweir // inside triangle or on edge? 205*cdf0e10cSrcweir if(tools::isPointInTriangle(pEdgeA->getStart(), pEdgeA->getEnd(), pEdgeB->getEnd(), rTestPoint, true)) 206*cdf0e10cSrcweir { 207*cdf0e10cSrcweir // but not on point 208*cdf0e10cSrcweir if(!rTestPoint.equal(pEdgeA->getEnd()) && !rTestPoint.equal(pEdgeB->getEnd())) 209*cdf0e10cSrcweir { 210*cdf0e10cSrcweir // found point in triangle -> split triangle inserting two edges 211*cdf0e10cSrcweir EdgeEntry* pStart = new EdgeEntry(pEdgeA->getStart(), rTestPoint); 212*cdf0e10cSrcweir EdgeEntry* pEnd = new EdgeEntry(*pStart); 213*cdf0e10cSrcweir maNewEdgeEntries.push_back(pStart); 214*cdf0e10cSrcweir maNewEdgeEntries.push_back(pEnd); 215*cdf0e10cSrcweir 216*cdf0e10cSrcweir pStart->setNext(pEnd); 217*cdf0e10cSrcweir pEnd->setNext(pEdgeA->getNext()); 218*cdf0e10cSrcweir pEdgeA->setNext(pStart); 219*cdf0e10cSrcweir 220*cdf0e10cSrcweir return false; 221*cdf0e10cSrcweir } 222*cdf0e10cSrcweir } 223*cdf0e10cSrcweir 224*cdf0e10cSrcweir return true; 225*cdf0e10cSrcweir } 226*cdf0e10cSrcweir 227*cdf0e10cSrcweir void Triangulator::createTriangle(const B2DPoint& rA, const B2DPoint& rB, const B2DPoint& rC) 228*cdf0e10cSrcweir { 229*cdf0e10cSrcweir maResult.append(rA); 230*cdf0e10cSrcweir maResult.append(rB); 231*cdf0e10cSrcweir maResult.append(rC); 232*cdf0e10cSrcweir } 233*cdf0e10cSrcweir 234*cdf0e10cSrcweir // consume as long as there are edges 235*cdf0e10cSrcweir Triangulator::Triangulator(const B2DPolyPolygon& rCandidate) 236*cdf0e10cSrcweir : mpList(0L) 237*cdf0e10cSrcweir { 238*cdf0e10cSrcweir // add all available edges to the single linked local list which will be sorted 239*cdf0e10cSrcweir // by Y,X,atan2 when adding nodes 240*cdf0e10cSrcweir if(rCandidate.count()) 241*cdf0e10cSrcweir { 242*cdf0e10cSrcweir for(sal_uInt32 a(0L); a < rCandidate.count(); a++) 243*cdf0e10cSrcweir { 244*cdf0e10cSrcweir const B2DPolygon aPolygonCandidate(rCandidate.getB2DPolygon(a)); 245*cdf0e10cSrcweir const sal_uInt32 nCount(aPolygonCandidate.count()); 246*cdf0e10cSrcweir 247*cdf0e10cSrcweir if(nCount > 2L) 248*cdf0e10cSrcweir { 249*cdf0e10cSrcweir B2DPoint aPrevPnt(aPolygonCandidate.getB2DPoint(nCount - 1L)); 250*cdf0e10cSrcweir 251*cdf0e10cSrcweir for(sal_uInt32 b(0L); b < nCount; b++) 252*cdf0e10cSrcweir { 253*cdf0e10cSrcweir B2DPoint aNextPnt(aPolygonCandidate.getB2DPoint(b)); 254*cdf0e10cSrcweir 255*cdf0e10cSrcweir if( !aPrevPnt.equal(aNextPnt) ) 256*cdf0e10cSrcweir { 257*cdf0e10cSrcweir maStartEntries.push_back(EdgeEntry(aPrevPnt, aNextPnt)); 258*cdf0e10cSrcweir } 259*cdf0e10cSrcweir 260*cdf0e10cSrcweir aPrevPnt = aNextPnt; 261*cdf0e10cSrcweir } 262*cdf0e10cSrcweir } 263*cdf0e10cSrcweir } 264*cdf0e10cSrcweir 265*cdf0e10cSrcweir if(maStartEntries.size()) 266*cdf0e10cSrcweir { 267*cdf0e10cSrcweir // sort initial list 268*cdf0e10cSrcweir ::std::sort(maStartEntries.begin(), maStartEntries.end()); 269*cdf0e10cSrcweir 270*cdf0e10cSrcweir // insert to own simply linked list 271*cdf0e10cSrcweir EdgeEntries::iterator aPos(maStartEntries.begin()); 272*cdf0e10cSrcweir mpList = &(*aPos++); 273*cdf0e10cSrcweir EdgeEntry* pLast = mpList; 274*cdf0e10cSrcweir 275*cdf0e10cSrcweir while(aPos != maStartEntries.end()) 276*cdf0e10cSrcweir { 277*cdf0e10cSrcweir EdgeEntry* pEntry = &(*aPos++); 278*cdf0e10cSrcweir pLast->setNext(pEntry); 279*cdf0e10cSrcweir pLast = pEntry; 280*cdf0e10cSrcweir } 281*cdf0e10cSrcweir } 282*cdf0e10cSrcweir } 283*cdf0e10cSrcweir 284*cdf0e10cSrcweir while(mpList) 285*cdf0e10cSrcweir { 286*cdf0e10cSrcweir if(mpList->getNext() && mpList->getNext()->getStart().equal(mpList->getStart())) 287*cdf0e10cSrcweir { 288*cdf0e10cSrcweir // next candidate. There are two edges and start point is equal. 289*cdf0e10cSrcweir // Length is not zero. 290*cdf0e10cSrcweir EdgeEntry* pEdgeA = mpList; 291*cdf0e10cSrcweir EdgeEntry* pEdgeB = pEdgeA->getNext(); 292*cdf0e10cSrcweir 293*cdf0e10cSrcweir if( pEdgeA->getEnd().equal(pEdgeB->getEnd()) ) 294*cdf0e10cSrcweir { 295*cdf0e10cSrcweir // start and end equal -> neutral triangle, delete both 296*cdf0e10cSrcweir mpList = pEdgeB->getNext(); 297*cdf0e10cSrcweir } 298*cdf0e10cSrcweir else 299*cdf0e10cSrcweir { 300*cdf0e10cSrcweir const B2DVector aLeft(pEdgeA->getEnd() - pEdgeA->getStart()); 301*cdf0e10cSrcweir const B2DVector aRight(pEdgeB->getEnd() - pEdgeA->getStart()); 302*cdf0e10cSrcweir 303*cdf0e10cSrcweir if(ORIENTATION_NEUTRAL == getOrientation(aLeft, aRight)) 304*cdf0e10cSrcweir { 305*cdf0e10cSrcweir // edges are parallel and have different length -> neutral triangle, 306*cdf0e10cSrcweir // delete both edges and handle closing edge 307*cdf0e10cSrcweir mpList = pEdgeB->getNext(); 308*cdf0e10cSrcweir handleClosingEdge(pEdgeA->getEnd(), pEdgeB->getEnd()); 309*cdf0e10cSrcweir } 310*cdf0e10cSrcweir else 311*cdf0e10cSrcweir { 312*cdf0e10cSrcweir // not parallel, look for points inside 313*cdf0e10cSrcweir B2DRange aRange(pEdgeA->getStart(), pEdgeA->getEnd()); 314*cdf0e10cSrcweir aRange.expand(pEdgeB->getEnd()); 315*cdf0e10cSrcweir EdgeEntry* pTestEdge = pEdgeB->getNext(); 316*cdf0e10cSrcweir bool bNoPointInTriangle(true); 317*cdf0e10cSrcweir 318*cdf0e10cSrcweir // look for start point in triangle 319*cdf0e10cSrcweir while(bNoPointInTriangle && pTestEdge) 320*cdf0e10cSrcweir { 321*cdf0e10cSrcweir if(aRange.getMaxY() < pTestEdge->getStart().getY()) 322*cdf0e10cSrcweir { 323*cdf0e10cSrcweir // edge is below test range and edges are sorted -> stop looking 324*cdf0e10cSrcweir break; 325*cdf0e10cSrcweir } 326*cdf0e10cSrcweir else 327*cdf0e10cSrcweir { 328*cdf0e10cSrcweir // do not look for edges with same start point, they are sorted and cannot end inside. 329*cdf0e10cSrcweir if(!pTestEdge->getStart().equal(pEdgeA->getStart())) 330*cdf0e10cSrcweir { 331*cdf0e10cSrcweir if(aRange.isInside(pTestEdge->getStart())) 332*cdf0e10cSrcweir { 333*cdf0e10cSrcweir bNoPointInTriangle = CheckPointInTriangle(pEdgeA, pEdgeB, pTestEdge->getStart()); 334*cdf0e10cSrcweir } 335*cdf0e10cSrcweir } 336*cdf0e10cSrcweir } 337*cdf0e10cSrcweir 338*cdf0e10cSrcweir // next candidate 339*cdf0e10cSrcweir pTestEdge = pTestEdge->getNext(); 340*cdf0e10cSrcweir } 341*cdf0e10cSrcweir 342*cdf0e10cSrcweir if(bNoPointInTriangle) 343*cdf0e10cSrcweir { 344*cdf0e10cSrcweir // look for end point in triange 345*cdf0e10cSrcweir pTestEdge = pEdgeB->getNext(); 346*cdf0e10cSrcweir 347*cdf0e10cSrcweir while(bNoPointInTriangle && pTestEdge) 348*cdf0e10cSrcweir { 349*cdf0e10cSrcweir if(aRange.getMaxY() < pTestEdge->getStart().getY()) 350*cdf0e10cSrcweir { 351*cdf0e10cSrcweir // edge is below test range and edges are sorted -> stop looking 352*cdf0e10cSrcweir break; 353*cdf0e10cSrcweir } 354*cdf0e10cSrcweir else 355*cdf0e10cSrcweir { 356*cdf0e10cSrcweir // do not look for edges with same end point, they are sorted and cannot end inside. 357*cdf0e10cSrcweir if(!pTestEdge->getEnd().equal(pEdgeA->getStart())) 358*cdf0e10cSrcweir { 359*cdf0e10cSrcweir if(aRange.isInside(pTestEdge->getEnd())) 360*cdf0e10cSrcweir { 361*cdf0e10cSrcweir bNoPointInTriangle = CheckPointInTriangle(pEdgeA, pEdgeB, pTestEdge->getEnd()); 362*cdf0e10cSrcweir } 363*cdf0e10cSrcweir } 364*cdf0e10cSrcweir } 365*cdf0e10cSrcweir 366*cdf0e10cSrcweir // next candidate 367*cdf0e10cSrcweir pTestEdge = pTestEdge->getNext(); 368*cdf0e10cSrcweir } 369*cdf0e10cSrcweir } 370*cdf0e10cSrcweir 371*cdf0e10cSrcweir if(bNoPointInTriangle) 372*cdf0e10cSrcweir { 373*cdf0e10cSrcweir // create triangle, remove edges, handle closing edge 374*cdf0e10cSrcweir mpList = pEdgeB->getNext(); 375*cdf0e10cSrcweir createTriangle(pEdgeA->getStart(), pEdgeB->getEnd(), pEdgeA->getEnd()); 376*cdf0e10cSrcweir handleClosingEdge(pEdgeA->getEnd(), pEdgeB->getEnd()); 377*cdf0e10cSrcweir } 378*cdf0e10cSrcweir } 379*cdf0e10cSrcweir } 380*cdf0e10cSrcweir } 381*cdf0e10cSrcweir else 382*cdf0e10cSrcweir { 383*cdf0e10cSrcweir // only one entry at start point, delete it 384*cdf0e10cSrcweir mpList = mpList->getNext(); 385*cdf0e10cSrcweir } 386*cdf0e10cSrcweir } 387*cdf0e10cSrcweir } 388*cdf0e10cSrcweir 389*cdf0e10cSrcweir Triangulator::~Triangulator() 390*cdf0e10cSrcweir { 391*cdf0e10cSrcweir EdgeEntryPointers::iterator aIter(maNewEdgeEntries.begin()); 392*cdf0e10cSrcweir 393*cdf0e10cSrcweir while(aIter != maNewEdgeEntries.end()) 394*cdf0e10cSrcweir { 395*cdf0e10cSrcweir delete (*aIter++); 396*cdf0e10cSrcweir } 397*cdf0e10cSrcweir } 398*cdf0e10cSrcweir 399*cdf0e10cSrcweir } // end of anonymous namespace 400*cdf0e10cSrcweir } // end of namespace basegfx 401*cdf0e10cSrcweir 402*cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 403*cdf0e10cSrcweir 404*cdf0e10cSrcweir namespace basegfx 405*cdf0e10cSrcweir { 406*cdf0e10cSrcweir namespace triangulator 407*cdf0e10cSrcweir { 408*cdf0e10cSrcweir B2DPolygon triangulate(const B2DPolygon& rCandidate) 409*cdf0e10cSrcweir { 410*cdf0e10cSrcweir B2DPolygon aRetval; 411*cdf0e10cSrcweir 412*cdf0e10cSrcweir // subdivide locally (triangulate does not work with beziers), remove double and neutral points 413*cdf0e10cSrcweir B2DPolygon aCandidate(rCandidate.areControlPointsUsed() ? tools::adaptiveSubdivideByAngle(rCandidate) : rCandidate); 414*cdf0e10cSrcweir aCandidate.removeDoublePoints(); 415*cdf0e10cSrcweir aCandidate = tools::removeNeutralPoints(aCandidate); 416*cdf0e10cSrcweir 417*cdf0e10cSrcweir if(2L == aCandidate.count()) 418*cdf0e10cSrcweir { 419*cdf0e10cSrcweir // candidate IS a triangle, just append 420*cdf0e10cSrcweir aRetval.append(aCandidate); 421*cdf0e10cSrcweir } 422*cdf0e10cSrcweir else if(aCandidate.count() > 2L) 423*cdf0e10cSrcweir { 424*cdf0e10cSrcweir if(tools::isConvex(aCandidate)) 425*cdf0e10cSrcweir { 426*cdf0e10cSrcweir // polygon is convex, just use a triangle fan 427*cdf0e10cSrcweir tools::addTriangleFan(aCandidate, aRetval); 428*cdf0e10cSrcweir } 429*cdf0e10cSrcweir else 430*cdf0e10cSrcweir { 431*cdf0e10cSrcweir // polygon is concave. 432*cdf0e10cSrcweir const B2DPolyPolygon aCandPolyPoly(aCandidate); 433*cdf0e10cSrcweir Triangulator aTriangulator(aCandPolyPoly); 434*cdf0e10cSrcweir aRetval = aTriangulator.getResult(); 435*cdf0e10cSrcweir } 436*cdf0e10cSrcweir } 437*cdf0e10cSrcweir 438*cdf0e10cSrcweir return aRetval; 439*cdf0e10cSrcweir } 440*cdf0e10cSrcweir 441*cdf0e10cSrcweir B2DPolygon triangulate(const B2DPolyPolygon& rCandidate) 442*cdf0e10cSrcweir { 443*cdf0e10cSrcweir B2DPolygon aRetval; 444*cdf0e10cSrcweir 445*cdf0e10cSrcweir // subdivide locally (triangulate does not work with beziers) 446*cdf0e10cSrcweir B2DPolyPolygon aCandidate(rCandidate.areControlPointsUsed() ? tools::adaptiveSubdivideByAngle(rCandidate) : rCandidate); 447*cdf0e10cSrcweir 448*cdf0e10cSrcweir if(1L == aCandidate.count()) 449*cdf0e10cSrcweir { 450*cdf0e10cSrcweir // single polygon -> single polygon triangulation 451*cdf0e10cSrcweir const B2DPolygon aSinglePolygon(aCandidate.getB2DPolygon(0L)); 452*cdf0e10cSrcweir aRetval = triangulate(aSinglePolygon); 453*cdf0e10cSrcweir } 454*cdf0e10cSrcweir else 455*cdf0e10cSrcweir { 456*cdf0e10cSrcweir Triangulator aTriangulator(aCandidate); 457*cdf0e10cSrcweir aRetval = aTriangulator.getResult(); 458*cdf0e10cSrcweir } 459*cdf0e10cSrcweir 460*cdf0e10cSrcweir return aRetval; 461*cdf0e10cSrcweir } 462*cdf0e10cSrcweir } // end of namespace triangulator 463*cdf0e10cSrcweir } // end of namespace basegfx 464*cdf0e10cSrcweir 465*cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 466*cdf0e10cSrcweir // eof 467