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 <osl/diagnose.h> 31*cdf0e10cSrcweir #include <basegfx/numeric/ftools.hxx> 32*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygoncutter.hxx> 33*cdf0e10cSrcweir #include <basegfx/point/b2dpoint.hxx> 34*cdf0e10cSrcweir #include <basegfx/vector/b2dvector.hxx> 35*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygon.hxx> 36*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygontools.hxx> 37*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygoncutandtouch.hxx> 38*cdf0e10cSrcweir #include <basegfx/range/b2drange.hxx> 39*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygontools.hxx> 40*cdf0e10cSrcweir #include <basegfx/curve/b2dcubicbezier.hxx> 41*cdf0e10cSrcweir #include <vector> 42*cdf0e10cSrcweir #include <algorithm> 43*cdf0e10cSrcweir 44*cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 45*cdf0e10cSrcweir 46*cdf0e10cSrcweir namespace basegfx 47*cdf0e10cSrcweir { 48*cdf0e10cSrcweir namespace 49*cdf0e10cSrcweir { 50*cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 51*cdf0e10cSrcweir 52*cdf0e10cSrcweir struct StripHelper 53*cdf0e10cSrcweir { 54*cdf0e10cSrcweir B2DRange maRange; 55*cdf0e10cSrcweir sal_Int32 mnDepth; 56*cdf0e10cSrcweir B2VectorOrientation meOrinetation; 57*cdf0e10cSrcweir }; 58*cdf0e10cSrcweir 59*cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 60*cdf0e10cSrcweir 61*cdf0e10cSrcweir struct PN 62*cdf0e10cSrcweir { 63*cdf0e10cSrcweir public: 64*cdf0e10cSrcweir B2DPoint maPoint; 65*cdf0e10cSrcweir sal_uInt32 mnI; 66*cdf0e10cSrcweir sal_uInt32 mnIP; 67*cdf0e10cSrcweir sal_uInt32 mnIN; 68*cdf0e10cSrcweir }; 69*cdf0e10cSrcweir 70*cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 71*cdf0e10cSrcweir 72*cdf0e10cSrcweir struct VN 73*cdf0e10cSrcweir { 74*cdf0e10cSrcweir public: 75*cdf0e10cSrcweir B2DVector maPrev; 76*cdf0e10cSrcweir B2DVector maNext; 77*cdf0e10cSrcweir 78*cdf0e10cSrcweir // to have the correct curve segments in the crossover checks, 79*cdf0e10cSrcweir // it is necessary to keep the original next vectors, too. Else, 80*cdf0e10cSrcweir // it may happen to use a already switched next vector which 81*cdf0e10cSrcweir // would interpolate the wrong comparison point 82*cdf0e10cSrcweir B2DVector maOriginalNext; 83*cdf0e10cSrcweir }; 84*cdf0e10cSrcweir 85*cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 86*cdf0e10cSrcweir 87*cdf0e10cSrcweir struct SN 88*cdf0e10cSrcweir { 89*cdf0e10cSrcweir public: 90*cdf0e10cSrcweir PN* mpPN; 91*cdf0e10cSrcweir 92*cdf0e10cSrcweir bool operator<(const SN& rComp) const 93*cdf0e10cSrcweir { 94*cdf0e10cSrcweir if(fTools::equal(mpPN->maPoint.getX(), rComp.mpPN->maPoint.getX())) 95*cdf0e10cSrcweir { 96*cdf0e10cSrcweir if(fTools::equal(mpPN->maPoint.getY(), rComp.mpPN->maPoint.getY())) 97*cdf0e10cSrcweir { 98*cdf0e10cSrcweir return (mpPN->mnI < rComp.mpPN->mnI); 99*cdf0e10cSrcweir } 100*cdf0e10cSrcweir else 101*cdf0e10cSrcweir { 102*cdf0e10cSrcweir return fTools::less(mpPN->maPoint.getY(), rComp.mpPN->maPoint.getY()); 103*cdf0e10cSrcweir } 104*cdf0e10cSrcweir } 105*cdf0e10cSrcweir else 106*cdf0e10cSrcweir { 107*cdf0e10cSrcweir return fTools::less(mpPN->maPoint.getX(), rComp.mpPN->maPoint.getX()); 108*cdf0e10cSrcweir } 109*cdf0e10cSrcweir } 110*cdf0e10cSrcweir }; 111*cdf0e10cSrcweir 112*cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 113*cdf0e10cSrcweir 114*cdf0e10cSrcweir typedef ::std::vector< PN > PNV; 115*cdf0e10cSrcweir typedef ::std::vector< VN > VNV; 116*cdf0e10cSrcweir typedef ::std::vector< SN > SNV; 117*cdf0e10cSrcweir 118*cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 119*cdf0e10cSrcweir 120*cdf0e10cSrcweir class solver 121*cdf0e10cSrcweir { 122*cdf0e10cSrcweir private: 123*cdf0e10cSrcweir const B2DPolyPolygon maOriginal; 124*cdf0e10cSrcweir PNV maPNV; 125*cdf0e10cSrcweir VNV maVNV; 126*cdf0e10cSrcweir SNV maSNV; 127*cdf0e10cSrcweir 128*cdf0e10cSrcweir unsigned mbIsCurve : 1; 129*cdf0e10cSrcweir unsigned mbChanged : 1; 130*cdf0e10cSrcweir 131*cdf0e10cSrcweir void impAddPolygon(const sal_uInt32 aPos, const B2DPolygon& rGeometry) 132*cdf0e10cSrcweir { 133*cdf0e10cSrcweir const sal_uInt32 nCount(rGeometry.count()); 134*cdf0e10cSrcweir PN aNewPN; 135*cdf0e10cSrcweir VN aNewVN; 136*cdf0e10cSrcweir SN aNewSN; 137*cdf0e10cSrcweir 138*cdf0e10cSrcweir for(sal_uInt32 a(0); a < nCount; a++) 139*cdf0e10cSrcweir { 140*cdf0e10cSrcweir const B2DPoint aPoint(rGeometry.getB2DPoint(a)); 141*cdf0e10cSrcweir aNewPN.maPoint = aPoint; 142*cdf0e10cSrcweir aNewPN.mnI = aPos + a; 143*cdf0e10cSrcweir aNewPN.mnIP = aPos + ((a != 0) ? a - 1 : nCount - 1); 144*cdf0e10cSrcweir aNewPN.mnIN = aPos + ((a + 1 == nCount) ? 0 : a + 1); 145*cdf0e10cSrcweir maPNV.push_back(aNewPN); 146*cdf0e10cSrcweir 147*cdf0e10cSrcweir if(mbIsCurve) 148*cdf0e10cSrcweir { 149*cdf0e10cSrcweir aNewVN.maPrev = rGeometry.getPrevControlPoint(a) - aPoint; 150*cdf0e10cSrcweir aNewVN.maNext = rGeometry.getNextControlPoint(a) - aPoint; 151*cdf0e10cSrcweir aNewVN.maOriginalNext = aNewVN.maNext; 152*cdf0e10cSrcweir maVNV.push_back(aNewVN); 153*cdf0e10cSrcweir } 154*cdf0e10cSrcweir 155*cdf0e10cSrcweir aNewSN.mpPN = &maPNV[maPNV.size() - 1]; 156*cdf0e10cSrcweir maSNV.push_back(aNewSN); 157*cdf0e10cSrcweir } 158*cdf0e10cSrcweir } 159*cdf0e10cSrcweir 160*cdf0e10cSrcweir bool impLeftOfEdges(const B2DVector& rVecA, const B2DVector& rVecB, const B2DVector& rTest) 161*cdf0e10cSrcweir { 162*cdf0e10cSrcweir // tests if rTest is left of both directed line segments along the line -rVecA, rVecB. Test is 163*cdf0e10cSrcweir // with border. 164*cdf0e10cSrcweir if(rVecA.cross(rVecB) > 0.0) 165*cdf0e10cSrcweir { 166*cdf0e10cSrcweir // b is left turn seen from a, test if Test is left of both and so inside (left is seeen as inside) 167*cdf0e10cSrcweir const bool bBoolA(fTools::moreOrEqual(rVecA.cross(rTest), 0.0)); 168*cdf0e10cSrcweir const bool bBoolB(fTools::lessOrEqual(rVecB.cross(rTest), 0.0)); 169*cdf0e10cSrcweir 170*cdf0e10cSrcweir return (bBoolA && bBoolB); 171*cdf0e10cSrcweir } 172*cdf0e10cSrcweir else 173*cdf0e10cSrcweir { 174*cdf0e10cSrcweir // b is right turn seen from a, test if Test is right of both and so outside (left is seeen as inside) 175*cdf0e10cSrcweir const bool bBoolA(fTools::lessOrEqual(rVecA.cross(rTest), 0.0)); 176*cdf0e10cSrcweir const bool bBoolB(fTools::moreOrEqual(rVecB.cross(rTest), 0.0)); 177*cdf0e10cSrcweir 178*cdf0e10cSrcweir return (!(bBoolA && bBoolB)); 179*cdf0e10cSrcweir } 180*cdf0e10cSrcweir } 181*cdf0e10cSrcweir 182*cdf0e10cSrcweir void impSwitchNext(PN& rPNa, PN& rPNb) 183*cdf0e10cSrcweir { 184*cdf0e10cSrcweir ::std::swap(rPNa.mnIN, rPNb.mnIN); 185*cdf0e10cSrcweir 186*cdf0e10cSrcweir if(mbIsCurve) 187*cdf0e10cSrcweir { 188*cdf0e10cSrcweir VN& rVNa = maVNV[rPNa.mnI]; 189*cdf0e10cSrcweir VN& rVNb = maVNV[rPNb.mnI]; 190*cdf0e10cSrcweir 191*cdf0e10cSrcweir ::std::swap(rVNa.maNext, rVNb.maNext); 192*cdf0e10cSrcweir } 193*cdf0e10cSrcweir 194*cdf0e10cSrcweir if(!mbChanged) 195*cdf0e10cSrcweir { 196*cdf0e10cSrcweir mbChanged = true; 197*cdf0e10cSrcweir } 198*cdf0e10cSrcweir } 199*cdf0e10cSrcweir 200*cdf0e10cSrcweir B2DCubicBezier createSegment(const PN& rPN, bool bPrev) const 201*cdf0e10cSrcweir { 202*cdf0e10cSrcweir const B2DPoint& rStart(rPN.maPoint); 203*cdf0e10cSrcweir const B2DPoint& rEnd(maPNV[bPrev ? rPN.mnIP : rPN.mnIN].maPoint); 204*cdf0e10cSrcweir const B2DVector& rCPA(bPrev ? maVNV[rPN.mnI].maPrev : maVNV[rPN.mnI].maNext); 205*cdf0e10cSrcweir // Use maOriginalNext, not maNext to create the original (yet unchanged) 206*cdf0e10cSrcweir // curve segment. Otherwise, this segment would NOT ne correct. 207*cdf0e10cSrcweir const B2DVector& rCPB(bPrev ? maVNV[maPNV[rPN.mnIP].mnI].maOriginalNext : maVNV[maPNV[rPN.mnIN].mnI].maPrev); 208*cdf0e10cSrcweir 209*cdf0e10cSrcweir return B2DCubicBezier(rStart, rStart + rCPA, rEnd + rCPB, rEnd); 210*cdf0e10cSrcweir } 211*cdf0e10cSrcweir 212*cdf0e10cSrcweir void impHandleCommon(PN& rPNa, PN& rPNb) 213*cdf0e10cSrcweir { 214*cdf0e10cSrcweir if(mbIsCurve) 215*cdf0e10cSrcweir { 216*cdf0e10cSrcweir const B2DCubicBezier aNextA(createSegment(rPNa, false)); 217*cdf0e10cSrcweir const B2DCubicBezier aPrevA(createSegment(rPNa, true)); 218*cdf0e10cSrcweir 219*cdf0e10cSrcweir if(aNextA.equal(aPrevA)) 220*cdf0e10cSrcweir { 221*cdf0e10cSrcweir // deadend on A (identical edge) 222*cdf0e10cSrcweir return; 223*cdf0e10cSrcweir } 224*cdf0e10cSrcweir 225*cdf0e10cSrcweir const B2DCubicBezier aNextB(createSegment(rPNb, false)); 226*cdf0e10cSrcweir const B2DCubicBezier aPrevB(createSegment(rPNb, true)); 227*cdf0e10cSrcweir 228*cdf0e10cSrcweir if(aNextB.equal(aPrevB)) 229*cdf0e10cSrcweir { 230*cdf0e10cSrcweir // deadend on B (identical edge) 231*cdf0e10cSrcweir return; 232*cdf0e10cSrcweir } 233*cdf0e10cSrcweir 234*cdf0e10cSrcweir if(aPrevA.equal(aPrevB)) 235*cdf0e10cSrcweir { 236*cdf0e10cSrcweir // common edge in same direction 237*cdf0e10cSrcweir if(aNextA.equal(aNextB)) 238*cdf0e10cSrcweir { 239*cdf0e10cSrcweir // common edge in same direction continues 240*cdf0e10cSrcweir return; 241*cdf0e10cSrcweir } 242*cdf0e10cSrcweir else 243*cdf0e10cSrcweir { 244*cdf0e10cSrcweir // common edge in same direction leave 245*cdf0e10cSrcweir // action is done on enter 246*cdf0e10cSrcweir return; 247*cdf0e10cSrcweir } 248*cdf0e10cSrcweir } 249*cdf0e10cSrcweir else if(aPrevA.equal(aNextB)) 250*cdf0e10cSrcweir { 251*cdf0e10cSrcweir // common edge in opposite direction 252*cdf0e10cSrcweir if(aNextA.equal(aPrevB)) 253*cdf0e10cSrcweir { 254*cdf0e10cSrcweir // common edge in opposite direction continues 255*cdf0e10cSrcweir return; 256*cdf0e10cSrcweir } 257*cdf0e10cSrcweir else 258*cdf0e10cSrcweir { 259*cdf0e10cSrcweir // common edge in opposite direction leave 260*cdf0e10cSrcweir impSwitchNext(rPNa, rPNb); 261*cdf0e10cSrcweir } 262*cdf0e10cSrcweir } 263*cdf0e10cSrcweir else if(aNextA.equal(aNextB)) 264*cdf0e10cSrcweir { 265*cdf0e10cSrcweir // common edge in same direction enter 266*cdf0e10cSrcweir // search leave edge 267*cdf0e10cSrcweir PN* pPNa2 = &maPNV[rPNa.mnIN]; 268*cdf0e10cSrcweir PN* pPNb2 = &maPNV[rPNb.mnIN]; 269*cdf0e10cSrcweir bool bOnEdge(true); 270*cdf0e10cSrcweir 271*cdf0e10cSrcweir do 272*cdf0e10cSrcweir { 273*cdf0e10cSrcweir const B2DCubicBezier aNextA2(createSegment(*pPNa2, false)); 274*cdf0e10cSrcweir const B2DCubicBezier aNextB2(createSegment(*pPNb2, false)); 275*cdf0e10cSrcweir 276*cdf0e10cSrcweir if(aNextA2.equal(aNextB2)) 277*cdf0e10cSrcweir { 278*cdf0e10cSrcweir pPNa2 = &maPNV[pPNa2->mnIN]; 279*cdf0e10cSrcweir pPNb2 = &maPNV[pPNb2->mnIN]; 280*cdf0e10cSrcweir } 281*cdf0e10cSrcweir else 282*cdf0e10cSrcweir { 283*cdf0e10cSrcweir bOnEdge = false; 284*cdf0e10cSrcweir } 285*cdf0e10cSrcweir } 286*cdf0e10cSrcweir while(bOnEdge && pPNa2 != &rPNa && pPNa2 != &rPNa); 287*cdf0e10cSrcweir 288*cdf0e10cSrcweir if(bOnEdge) 289*cdf0e10cSrcweir { 290*cdf0e10cSrcweir // loop over two identical polygon paths 291*cdf0e10cSrcweir return; 292*cdf0e10cSrcweir } 293*cdf0e10cSrcweir else 294*cdf0e10cSrcweir { 295*cdf0e10cSrcweir // enter at rPNa, rPNb; leave at pPNa2, pPNb2. No common edges 296*cdf0e10cSrcweir // at enter/leave. Check for crossover. 297*cdf0e10cSrcweir const B2DVector aPrevCA(aPrevA.interpolatePoint(0.5) - aPrevA.getStartPoint()); 298*cdf0e10cSrcweir const B2DVector aNextCA(aNextA.interpolatePoint(0.5) - aNextA.getStartPoint()); 299*cdf0e10cSrcweir const B2DVector aPrevCB(aPrevB.interpolatePoint(0.5) - aPrevB.getStartPoint()); 300*cdf0e10cSrcweir const bool bEnter(impLeftOfEdges(aPrevCA, aNextCA, aPrevCB)); 301*cdf0e10cSrcweir 302*cdf0e10cSrcweir const B2DCubicBezier aNextA2(createSegment(*pPNa2, false)); 303*cdf0e10cSrcweir const B2DCubicBezier aPrevA2(createSegment(*pPNa2, true)); 304*cdf0e10cSrcweir const B2DCubicBezier aNextB2(createSegment(*pPNb2, false)); 305*cdf0e10cSrcweir const B2DVector aPrevCA2(aPrevA2.interpolatePoint(0.5) - aPrevA2.getStartPoint()); 306*cdf0e10cSrcweir const B2DVector aNextCA2(aNextA2.interpolatePoint(0.5) - aNextA2.getStartPoint()); 307*cdf0e10cSrcweir const B2DVector aNextCB2(aNextB2.interpolatePoint(0.5) - aNextB2.getStartPoint()); 308*cdf0e10cSrcweir const bool bLeave(impLeftOfEdges(aPrevCA2, aNextCA2, aNextCB2)); 309*cdf0e10cSrcweir 310*cdf0e10cSrcweir if(bEnter != bLeave) 311*cdf0e10cSrcweir { 312*cdf0e10cSrcweir // crossover 313*cdf0e10cSrcweir impSwitchNext(rPNa, rPNb); 314*cdf0e10cSrcweir } 315*cdf0e10cSrcweir } 316*cdf0e10cSrcweir } 317*cdf0e10cSrcweir else if(aNextA.equal(aPrevB)) 318*cdf0e10cSrcweir { 319*cdf0e10cSrcweir // common edge in opposite direction enter 320*cdf0e10cSrcweir impSwitchNext(rPNa, rPNb); 321*cdf0e10cSrcweir } 322*cdf0e10cSrcweir else 323*cdf0e10cSrcweir { 324*cdf0e10cSrcweir // no common edges, check for crossover 325*cdf0e10cSrcweir const B2DVector aPrevCA(aPrevA.interpolatePoint(0.5) - aPrevA.getStartPoint()); 326*cdf0e10cSrcweir const B2DVector aNextCA(aNextA.interpolatePoint(0.5) - aNextA.getStartPoint()); 327*cdf0e10cSrcweir const B2DVector aPrevCB(aPrevB.interpolatePoint(0.5) - aPrevB.getStartPoint()); 328*cdf0e10cSrcweir const B2DVector aNextCB(aNextB.interpolatePoint(0.5) - aNextB.getStartPoint()); 329*cdf0e10cSrcweir 330*cdf0e10cSrcweir const bool bEnter(impLeftOfEdges(aPrevCA, aNextCA, aPrevCB)); 331*cdf0e10cSrcweir const bool bLeave(impLeftOfEdges(aPrevCA, aNextCA, aNextCB)); 332*cdf0e10cSrcweir 333*cdf0e10cSrcweir if(bEnter != bLeave) 334*cdf0e10cSrcweir { 335*cdf0e10cSrcweir // crossover 336*cdf0e10cSrcweir impSwitchNext(rPNa, rPNb); 337*cdf0e10cSrcweir } 338*cdf0e10cSrcweir } 339*cdf0e10cSrcweir } 340*cdf0e10cSrcweir else 341*cdf0e10cSrcweir { 342*cdf0e10cSrcweir const B2DPoint& rNextA(maPNV[rPNa.mnIN].maPoint); 343*cdf0e10cSrcweir const B2DPoint& rPrevA(maPNV[rPNa.mnIP].maPoint); 344*cdf0e10cSrcweir 345*cdf0e10cSrcweir if(rNextA.equal(rPrevA)) 346*cdf0e10cSrcweir { 347*cdf0e10cSrcweir // deadend on A 348*cdf0e10cSrcweir return; 349*cdf0e10cSrcweir } 350*cdf0e10cSrcweir 351*cdf0e10cSrcweir const B2DPoint& rNextB(maPNV[rPNb.mnIN].maPoint); 352*cdf0e10cSrcweir const B2DPoint& rPrevB(maPNV[rPNb.mnIP].maPoint); 353*cdf0e10cSrcweir 354*cdf0e10cSrcweir if(rNextB.equal(rPrevB)) 355*cdf0e10cSrcweir { 356*cdf0e10cSrcweir // deadend on B 357*cdf0e10cSrcweir return; 358*cdf0e10cSrcweir } 359*cdf0e10cSrcweir 360*cdf0e10cSrcweir if(rPrevA.equal(rPrevB)) 361*cdf0e10cSrcweir { 362*cdf0e10cSrcweir // common edge in same direction 363*cdf0e10cSrcweir if(rNextA.equal(rNextB)) 364*cdf0e10cSrcweir { 365*cdf0e10cSrcweir // common edge in same direction continues 366*cdf0e10cSrcweir return; 367*cdf0e10cSrcweir } 368*cdf0e10cSrcweir else 369*cdf0e10cSrcweir { 370*cdf0e10cSrcweir // common edge in same direction leave 371*cdf0e10cSrcweir // action is done on enter 372*cdf0e10cSrcweir return; 373*cdf0e10cSrcweir } 374*cdf0e10cSrcweir } 375*cdf0e10cSrcweir else if(rPrevA.equal(rNextB)) 376*cdf0e10cSrcweir { 377*cdf0e10cSrcweir // common edge in opposite direction 378*cdf0e10cSrcweir if(rNextA.equal(rPrevB)) 379*cdf0e10cSrcweir { 380*cdf0e10cSrcweir // common edge in opposite direction continues 381*cdf0e10cSrcweir return; 382*cdf0e10cSrcweir } 383*cdf0e10cSrcweir else 384*cdf0e10cSrcweir { 385*cdf0e10cSrcweir // common edge in opposite direction leave 386*cdf0e10cSrcweir impSwitchNext(rPNa, rPNb); 387*cdf0e10cSrcweir } 388*cdf0e10cSrcweir } 389*cdf0e10cSrcweir else if(rNextA.equal(rNextB)) 390*cdf0e10cSrcweir { 391*cdf0e10cSrcweir // common edge in same direction enter 392*cdf0e10cSrcweir // search leave edge 393*cdf0e10cSrcweir PN* pPNa2 = &maPNV[rPNa.mnIN]; 394*cdf0e10cSrcweir PN* pPNb2 = &maPNV[rPNb.mnIN]; 395*cdf0e10cSrcweir bool bOnEdge(true); 396*cdf0e10cSrcweir 397*cdf0e10cSrcweir do 398*cdf0e10cSrcweir { 399*cdf0e10cSrcweir const B2DPoint& rNextA2(maPNV[pPNa2->mnIN].maPoint); 400*cdf0e10cSrcweir const B2DPoint& rNextB2(maPNV[pPNb2->mnIN].maPoint); 401*cdf0e10cSrcweir 402*cdf0e10cSrcweir if(rNextA2.equal(rNextB2)) 403*cdf0e10cSrcweir { 404*cdf0e10cSrcweir pPNa2 = &maPNV[pPNa2->mnIN]; 405*cdf0e10cSrcweir pPNb2 = &maPNV[pPNb2->mnIN]; 406*cdf0e10cSrcweir } 407*cdf0e10cSrcweir else 408*cdf0e10cSrcweir { 409*cdf0e10cSrcweir bOnEdge = false; 410*cdf0e10cSrcweir } 411*cdf0e10cSrcweir } 412*cdf0e10cSrcweir while(bOnEdge && pPNa2 != &rPNa && pPNa2 != &rPNa); 413*cdf0e10cSrcweir 414*cdf0e10cSrcweir if(bOnEdge) 415*cdf0e10cSrcweir { 416*cdf0e10cSrcweir // loop over two identical polygon paths 417*cdf0e10cSrcweir return; 418*cdf0e10cSrcweir } 419*cdf0e10cSrcweir else 420*cdf0e10cSrcweir { 421*cdf0e10cSrcweir // enter at rPNa, rPNb; leave at pPNa2, pPNb2. No common edges 422*cdf0e10cSrcweir // at enter/leave. Check for crossover. 423*cdf0e10cSrcweir const B2DPoint& aPointE(rPNa.maPoint); 424*cdf0e10cSrcweir const B2DVector aPrevAE(rPrevA - aPointE); 425*cdf0e10cSrcweir const B2DVector aNextAE(rNextA - aPointE); 426*cdf0e10cSrcweir const B2DVector aPrevBE(rPrevB - aPointE); 427*cdf0e10cSrcweir 428*cdf0e10cSrcweir const B2DPoint& aPointL(pPNa2->maPoint); 429*cdf0e10cSrcweir const B2DVector aPrevAL(maPNV[pPNa2->mnIP].maPoint - aPointL); 430*cdf0e10cSrcweir const B2DVector aNextAL(maPNV[pPNa2->mnIN].maPoint - aPointL); 431*cdf0e10cSrcweir const B2DVector aNextBL(maPNV[pPNb2->mnIN].maPoint - aPointL); 432*cdf0e10cSrcweir 433*cdf0e10cSrcweir const bool bEnter(impLeftOfEdges(aPrevAE, aNextAE, aPrevBE)); 434*cdf0e10cSrcweir const bool bLeave(impLeftOfEdges(aPrevAL, aNextAL, aNextBL)); 435*cdf0e10cSrcweir 436*cdf0e10cSrcweir if(bEnter != bLeave) 437*cdf0e10cSrcweir { 438*cdf0e10cSrcweir // crossover; switch start or end 439*cdf0e10cSrcweir impSwitchNext(rPNa, rPNb); 440*cdf0e10cSrcweir } 441*cdf0e10cSrcweir } 442*cdf0e10cSrcweir } 443*cdf0e10cSrcweir else if(rNextA.equal(rPrevB)) 444*cdf0e10cSrcweir { 445*cdf0e10cSrcweir // common edge in opposite direction enter 446*cdf0e10cSrcweir impSwitchNext(rPNa, rPNb); 447*cdf0e10cSrcweir } 448*cdf0e10cSrcweir else 449*cdf0e10cSrcweir { 450*cdf0e10cSrcweir // no common edges, check for crossover 451*cdf0e10cSrcweir const B2DPoint& aPoint(rPNa.maPoint); 452*cdf0e10cSrcweir const B2DVector aPrevA(rPrevA - aPoint); 453*cdf0e10cSrcweir const B2DVector aNextA(rNextA - aPoint); 454*cdf0e10cSrcweir const B2DVector aPrevB(rPrevB - aPoint); 455*cdf0e10cSrcweir const B2DVector aNextB(rNextB - aPoint); 456*cdf0e10cSrcweir 457*cdf0e10cSrcweir const bool bEnter(impLeftOfEdges(aPrevA, aNextA, aPrevB)); 458*cdf0e10cSrcweir const bool bLeave(impLeftOfEdges(aPrevA, aNextA, aNextB)); 459*cdf0e10cSrcweir 460*cdf0e10cSrcweir if(bEnter != bLeave) 461*cdf0e10cSrcweir { 462*cdf0e10cSrcweir // crossover 463*cdf0e10cSrcweir impSwitchNext(rPNa, rPNb); 464*cdf0e10cSrcweir } 465*cdf0e10cSrcweir } 466*cdf0e10cSrcweir } 467*cdf0e10cSrcweir } 468*cdf0e10cSrcweir 469*cdf0e10cSrcweir void impSolve() 470*cdf0e10cSrcweir { 471*cdf0e10cSrcweir // sort by point to identify common nodes 472*cdf0e10cSrcweir ::std::sort(maSNV.begin(), maSNV.end()); 473*cdf0e10cSrcweir 474*cdf0e10cSrcweir // handle common nodes 475*cdf0e10cSrcweir const sal_uInt32 nNodeCount(maSNV.size()); 476*cdf0e10cSrcweir 477*cdf0e10cSrcweir for(sal_uInt32 a(0); a < nNodeCount - 1; a++) 478*cdf0e10cSrcweir { 479*cdf0e10cSrcweir // test a before using it, not after. Also use nPointCount instead of aSortNodes.size() 480*cdf0e10cSrcweir PN& rPNb = *(maSNV[a].mpPN); 481*cdf0e10cSrcweir 482*cdf0e10cSrcweir for(sal_uInt32 b(a + 1); b < nNodeCount && rPNb.maPoint.equal(maSNV[b].mpPN->maPoint); b++) 483*cdf0e10cSrcweir { 484*cdf0e10cSrcweir impHandleCommon(rPNb, *maSNV[b].mpPN); 485*cdf0e10cSrcweir } 486*cdf0e10cSrcweir } 487*cdf0e10cSrcweir } 488*cdf0e10cSrcweir 489*cdf0e10cSrcweir public: 490*cdf0e10cSrcweir solver(const B2DPolygon& rOriginal) 491*cdf0e10cSrcweir : maOriginal(B2DPolyPolygon(rOriginal)), 492*cdf0e10cSrcweir mbIsCurve(false), 493*cdf0e10cSrcweir mbChanged(false) 494*cdf0e10cSrcweir { 495*cdf0e10cSrcweir const sal_uInt32 nOriginalCount(rOriginal.count()); 496*cdf0e10cSrcweir 497*cdf0e10cSrcweir if(nOriginalCount) 498*cdf0e10cSrcweir { 499*cdf0e10cSrcweir B2DPolygon aGeometry(tools::addPointsAtCutsAndTouches(rOriginal)); 500*cdf0e10cSrcweir aGeometry.removeDoublePoints(); 501*cdf0e10cSrcweir aGeometry = tools::simplifyCurveSegments(aGeometry); 502*cdf0e10cSrcweir mbIsCurve = aGeometry.areControlPointsUsed(); 503*cdf0e10cSrcweir 504*cdf0e10cSrcweir const sal_uInt32 nPointCount(aGeometry.count()); 505*cdf0e10cSrcweir 506*cdf0e10cSrcweir // If it's not a pezier polygon, at least four points are needed to create 507*cdf0e10cSrcweir // a self-intersection. If it's a bezier polygon, the minimum point number 508*cdf0e10cSrcweir // is two, since with a single point You get a curve, but no self-intersection 509*cdf0e10cSrcweir if(nPointCount > 3 || (nPointCount > 1 && mbIsCurve)) 510*cdf0e10cSrcweir { 511*cdf0e10cSrcweir // reserve space in point, control and sort vector. 512*cdf0e10cSrcweir maSNV.reserve(nPointCount); 513*cdf0e10cSrcweir maPNV.reserve(nPointCount); 514*cdf0e10cSrcweir maVNV.reserve(mbIsCurve ? nPointCount : 0); 515*cdf0e10cSrcweir 516*cdf0e10cSrcweir // fill data 517*cdf0e10cSrcweir impAddPolygon(0, aGeometry); 518*cdf0e10cSrcweir 519*cdf0e10cSrcweir // solve common nodes 520*cdf0e10cSrcweir impSolve(); 521*cdf0e10cSrcweir } 522*cdf0e10cSrcweir } 523*cdf0e10cSrcweir } 524*cdf0e10cSrcweir 525*cdf0e10cSrcweir solver(const B2DPolyPolygon& rOriginal) 526*cdf0e10cSrcweir : maOriginal(rOriginal), 527*cdf0e10cSrcweir mbIsCurve(false), 528*cdf0e10cSrcweir mbChanged(false) 529*cdf0e10cSrcweir { 530*cdf0e10cSrcweir sal_uInt32 nOriginalCount(maOriginal.count()); 531*cdf0e10cSrcweir 532*cdf0e10cSrcweir if(nOriginalCount) 533*cdf0e10cSrcweir { 534*cdf0e10cSrcweir B2DPolyPolygon aGeometry(tools::addPointsAtCutsAndTouches(maOriginal, true)); 535*cdf0e10cSrcweir aGeometry.removeDoublePoints(); 536*cdf0e10cSrcweir aGeometry = tools::simplifyCurveSegments(aGeometry); 537*cdf0e10cSrcweir mbIsCurve = aGeometry.areControlPointsUsed(); 538*cdf0e10cSrcweir nOriginalCount = aGeometry.count(); 539*cdf0e10cSrcweir 540*cdf0e10cSrcweir if(nOriginalCount) 541*cdf0e10cSrcweir { 542*cdf0e10cSrcweir sal_uInt32 nPointCount(0); 543*cdf0e10cSrcweir sal_uInt32 a(0); 544*cdf0e10cSrcweir 545*cdf0e10cSrcweir // count points 546*cdf0e10cSrcweir for(a = 0; a < nOriginalCount; a++) 547*cdf0e10cSrcweir { 548*cdf0e10cSrcweir const B2DPolygon aCandidate(aGeometry.getB2DPolygon(a)); 549*cdf0e10cSrcweir const sal_uInt32 nCandCount(aCandidate.count()); 550*cdf0e10cSrcweir 551*cdf0e10cSrcweir // If it's not a bezier curve, at least three points would be needed to have a 552*cdf0e10cSrcweir // topological relevant (not empty) polygon. Since its not known here if trivial 553*cdf0e10cSrcweir // edges (dead ends) will be kept or sorted out, add non-bezier polygons with 554*cdf0e10cSrcweir // more than one point. 555*cdf0e10cSrcweir // For bezier curves, the minimum for defining an area is also one. 556*cdf0e10cSrcweir if(nCandCount) 557*cdf0e10cSrcweir { 558*cdf0e10cSrcweir nPointCount += nCandCount; 559*cdf0e10cSrcweir } 560*cdf0e10cSrcweir } 561*cdf0e10cSrcweir 562*cdf0e10cSrcweir if(nPointCount) 563*cdf0e10cSrcweir { 564*cdf0e10cSrcweir // reserve space in point, control and sort vector. 565*cdf0e10cSrcweir maSNV.reserve(nPointCount); 566*cdf0e10cSrcweir maPNV.reserve(nPointCount); 567*cdf0e10cSrcweir maVNV.reserve(mbIsCurve ? nPointCount : 0); 568*cdf0e10cSrcweir 569*cdf0e10cSrcweir // fill data 570*cdf0e10cSrcweir sal_uInt32 nInsertIndex(0); 571*cdf0e10cSrcweir 572*cdf0e10cSrcweir for(a = 0; a < nOriginalCount; a++) 573*cdf0e10cSrcweir { 574*cdf0e10cSrcweir const B2DPolygon aCandidate(aGeometry.getB2DPolygon(a)); 575*cdf0e10cSrcweir const sal_uInt32 nCandCount(aCandidate.count()); 576*cdf0e10cSrcweir 577*cdf0e10cSrcweir // use same condition as above, the data vector is 578*cdf0e10cSrcweir // pre-allocated 579*cdf0e10cSrcweir if(nCandCount) 580*cdf0e10cSrcweir { 581*cdf0e10cSrcweir impAddPolygon(nInsertIndex, aCandidate); 582*cdf0e10cSrcweir nInsertIndex += nCandCount; 583*cdf0e10cSrcweir } 584*cdf0e10cSrcweir } 585*cdf0e10cSrcweir 586*cdf0e10cSrcweir // solve common nodes 587*cdf0e10cSrcweir impSolve(); 588*cdf0e10cSrcweir } 589*cdf0e10cSrcweir } 590*cdf0e10cSrcweir } 591*cdf0e10cSrcweir } 592*cdf0e10cSrcweir 593*cdf0e10cSrcweir B2DPolyPolygon getB2DPolyPolygon() 594*cdf0e10cSrcweir { 595*cdf0e10cSrcweir if(mbChanged) 596*cdf0e10cSrcweir { 597*cdf0e10cSrcweir B2DPolyPolygon aRetval; 598*cdf0e10cSrcweir const sal_uInt32 nCount(maPNV.size()); 599*cdf0e10cSrcweir sal_uInt32 nCountdown(nCount); 600*cdf0e10cSrcweir 601*cdf0e10cSrcweir for(sal_uInt32 a(0); nCountdown && a < nCount; a++) 602*cdf0e10cSrcweir { 603*cdf0e10cSrcweir PN& rPN = maPNV[a]; 604*cdf0e10cSrcweir 605*cdf0e10cSrcweir if(SAL_MAX_UINT32 != rPN.mnI) 606*cdf0e10cSrcweir { 607*cdf0e10cSrcweir // unused node, start new part polygon 608*cdf0e10cSrcweir B2DPolygon aNewPart; 609*cdf0e10cSrcweir PN* pPNCurr = &rPN; 610*cdf0e10cSrcweir 611*cdf0e10cSrcweir do 612*cdf0e10cSrcweir { 613*cdf0e10cSrcweir const B2DPoint& rPoint = pPNCurr->maPoint; 614*cdf0e10cSrcweir aNewPart.append(rPoint); 615*cdf0e10cSrcweir 616*cdf0e10cSrcweir if(mbIsCurve) 617*cdf0e10cSrcweir { 618*cdf0e10cSrcweir const VN& rVNCurr = maVNV[pPNCurr->mnI]; 619*cdf0e10cSrcweir 620*cdf0e10cSrcweir if(!rVNCurr.maPrev.equalZero()) 621*cdf0e10cSrcweir { 622*cdf0e10cSrcweir aNewPart.setPrevControlPoint(aNewPart.count() - 1, rPoint + rVNCurr.maPrev); 623*cdf0e10cSrcweir } 624*cdf0e10cSrcweir 625*cdf0e10cSrcweir if(!rVNCurr.maNext.equalZero()) 626*cdf0e10cSrcweir { 627*cdf0e10cSrcweir aNewPart.setNextControlPoint(aNewPart.count() - 1, rPoint + rVNCurr.maNext); 628*cdf0e10cSrcweir } 629*cdf0e10cSrcweir } 630*cdf0e10cSrcweir 631*cdf0e10cSrcweir pPNCurr->mnI = SAL_MAX_UINT32; 632*cdf0e10cSrcweir nCountdown--; 633*cdf0e10cSrcweir pPNCurr = &(maPNV[pPNCurr->mnIN]); 634*cdf0e10cSrcweir } 635*cdf0e10cSrcweir while(pPNCurr != &rPN && SAL_MAX_UINT32 != pPNCurr->mnI); 636*cdf0e10cSrcweir 637*cdf0e10cSrcweir // close and add 638*cdf0e10cSrcweir aNewPart.setClosed(true); 639*cdf0e10cSrcweir aRetval.append(aNewPart); 640*cdf0e10cSrcweir } 641*cdf0e10cSrcweir } 642*cdf0e10cSrcweir 643*cdf0e10cSrcweir return aRetval; 644*cdf0e10cSrcweir } 645*cdf0e10cSrcweir else 646*cdf0e10cSrcweir { 647*cdf0e10cSrcweir // no change, return original 648*cdf0e10cSrcweir return maOriginal; 649*cdf0e10cSrcweir } 650*cdf0e10cSrcweir } 651*cdf0e10cSrcweir }; 652*cdf0e10cSrcweir 653*cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 654*cdf0e10cSrcweir 655*cdf0e10cSrcweir } // end of anonymous namespace 656*cdf0e10cSrcweir } // end of namespace basegfx 657*cdf0e10cSrcweir 658*cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 659*cdf0e10cSrcweir 660*cdf0e10cSrcweir namespace basegfx 661*cdf0e10cSrcweir { 662*cdf0e10cSrcweir namespace tools 663*cdf0e10cSrcweir { 664*cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 665*cdf0e10cSrcweir 666*cdf0e10cSrcweir B2DPolyPolygon solveCrossovers(const B2DPolyPolygon& rCandidate) 667*cdf0e10cSrcweir { 668*cdf0e10cSrcweir if(rCandidate.count() > 1L) 669*cdf0e10cSrcweir { 670*cdf0e10cSrcweir solver aSolver(rCandidate); 671*cdf0e10cSrcweir return aSolver.getB2DPolyPolygon(); 672*cdf0e10cSrcweir } 673*cdf0e10cSrcweir else 674*cdf0e10cSrcweir { 675*cdf0e10cSrcweir return rCandidate; 676*cdf0e10cSrcweir } 677*cdf0e10cSrcweir } 678*cdf0e10cSrcweir 679*cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 680*cdf0e10cSrcweir 681*cdf0e10cSrcweir B2DPolyPolygon solveCrossovers(const B2DPolygon& rCandidate) 682*cdf0e10cSrcweir { 683*cdf0e10cSrcweir solver aSolver(rCandidate); 684*cdf0e10cSrcweir return aSolver.getB2DPolyPolygon(); 685*cdf0e10cSrcweir } 686*cdf0e10cSrcweir 687*cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 688*cdf0e10cSrcweir 689*cdf0e10cSrcweir B2DPolyPolygon stripNeutralPolygons(const B2DPolyPolygon& rCandidate) 690*cdf0e10cSrcweir { 691*cdf0e10cSrcweir B2DPolyPolygon aRetval; 692*cdf0e10cSrcweir 693*cdf0e10cSrcweir for(sal_uInt32 a(0L); a < rCandidate.count(); a++) 694*cdf0e10cSrcweir { 695*cdf0e10cSrcweir const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a)); 696*cdf0e10cSrcweir 697*cdf0e10cSrcweir if(ORIENTATION_NEUTRAL != tools::getOrientation(aCandidate)) 698*cdf0e10cSrcweir { 699*cdf0e10cSrcweir aRetval.append(aCandidate); 700*cdf0e10cSrcweir } 701*cdf0e10cSrcweir } 702*cdf0e10cSrcweir 703*cdf0e10cSrcweir return aRetval; 704*cdf0e10cSrcweir } 705*cdf0e10cSrcweir 706*cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 707*cdf0e10cSrcweir 708*cdf0e10cSrcweir B2DPolyPolygon stripDispensablePolygons(const B2DPolyPolygon& rCandidate, bool bKeepAboveZero) 709*cdf0e10cSrcweir { 710*cdf0e10cSrcweir const sal_uInt32 nCount(rCandidate.count()); 711*cdf0e10cSrcweir B2DPolyPolygon aRetval; 712*cdf0e10cSrcweir 713*cdf0e10cSrcweir if(nCount) 714*cdf0e10cSrcweir { 715*cdf0e10cSrcweir if(nCount == 1L) 716*cdf0e10cSrcweir { 717*cdf0e10cSrcweir if(!bKeepAboveZero && ORIENTATION_POSITIVE == tools::getOrientation(rCandidate.getB2DPolygon(0L))) 718*cdf0e10cSrcweir { 719*cdf0e10cSrcweir aRetval = rCandidate; 720*cdf0e10cSrcweir } 721*cdf0e10cSrcweir } 722*cdf0e10cSrcweir else 723*cdf0e10cSrcweir { 724*cdf0e10cSrcweir sal_uInt32 a, b; 725*cdf0e10cSrcweir ::std::vector< StripHelper > aHelpers; 726*cdf0e10cSrcweir aHelpers.resize(nCount); 727*cdf0e10cSrcweir 728*cdf0e10cSrcweir for(a = 0L; a < nCount; a++) 729*cdf0e10cSrcweir { 730*cdf0e10cSrcweir const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a)); 731*cdf0e10cSrcweir StripHelper* pNewHelper = &(aHelpers[a]); 732*cdf0e10cSrcweir pNewHelper->maRange = tools::getRange(aCandidate); 733*cdf0e10cSrcweir pNewHelper->meOrinetation = tools::getOrientation(aCandidate); 734*cdf0e10cSrcweir pNewHelper->mnDepth = (ORIENTATION_NEGATIVE == pNewHelper->meOrinetation ? -1L : 0L); 735*cdf0e10cSrcweir } 736*cdf0e10cSrcweir 737*cdf0e10cSrcweir for(a = 0L; a < nCount - 1L; a++) 738*cdf0e10cSrcweir { 739*cdf0e10cSrcweir const B2DPolygon aCandA(rCandidate.getB2DPolygon(a)); 740*cdf0e10cSrcweir StripHelper& rHelperA = aHelpers[a]; 741*cdf0e10cSrcweir 742*cdf0e10cSrcweir for(b = a + 1L; b < nCount; b++) 743*cdf0e10cSrcweir { 744*cdf0e10cSrcweir const B2DPolygon aCandB(rCandidate.getB2DPolygon(b)); 745*cdf0e10cSrcweir StripHelper& rHelperB = aHelpers[b]; 746*cdf0e10cSrcweir const bool bAInB(rHelperB.maRange.isInside(rHelperA.maRange) && tools::isInside(aCandB, aCandA, true)); 747*cdf0e10cSrcweir const bool bBInA(rHelperA.maRange.isInside(rHelperB.maRange) && tools::isInside(aCandA, aCandB, true)); 748*cdf0e10cSrcweir 749*cdf0e10cSrcweir if(bAInB && bBInA) 750*cdf0e10cSrcweir { 751*cdf0e10cSrcweir // congruent 752*cdf0e10cSrcweir if(rHelperA.meOrinetation == rHelperB.meOrinetation) 753*cdf0e10cSrcweir { 754*cdf0e10cSrcweir // two polys or two holes. Lower one of them to get one of them out of the way. 755*cdf0e10cSrcweir // Since each will be contained in the other one, both will be increased, too. 756*cdf0e10cSrcweir // So, for lowering, increase only one of them 757*cdf0e10cSrcweir rHelperA.mnDepth++; 758*cdf0e10cSrcweir } 759*cdf0e10cSrcweir else 760*cdf0e10cSrcweir { 761*cdf0e10cSrcweir // poly and hole. They neutralize, so get rid of both. Move securely below zero. 762*cdf0e10cSrcweir rHelperA.mnDepth = -((sal_Int32)nCount); 763*cdf0e10cSrcweir rHelperB.mnDepth = -((sal_Int32)nCount); 764*cdf0e10cSrcweir } 765*cdf0e10cSrcweir } 766*cdf0e10cSrcweir else 767*cdf0e10cSrcweir { 768*cdf0e10cSrcweir if(bAInB) 769*cdf0e10cSrcweir { 770*cdf0e10cSrcweir if(ORIENTATION_NEGATIVE == rHelperB.meOrinetation) 771*cdf0e10cSrcweir { 772*cdf0e10cSrcweir rHelperA.mnDepth--; 773*cdf0e10cSrcweir } 774*cdf0e10cSrcweir else 775*cdf0e10cSrcweir { 776*cdf0e10cSrcweir rHelperA.mnDepth++; 777*cdf0e10cSrcweir } 778*cdf0e10cSrcweir } 779*cdf0e10cSrcweir else if(bBInA) 780*cdf0e10cSrcweir { 781*cdf0e10cSrcweir if(ORIENTATION_NEGATIVE == rHelperA.meOrinetation) 782*cdf0e10cSrcweir { 783*cdf0e10cSrcweir rHelperB.mnDepth--; 784*cdf0e10cSrcweir } 785*cdf0e10cSrcweir else 786*cdf0e10cSrcweir { 787*cdf0e10cSrcweir rHelperB.mnDepth++; 788*cdf0e10cSrcweir } 789*cdf0e10cSrcweir } 790*cdf0e10cSrcweir } 791*cdf0e10cSrcweir } 792*cdf0e10cSrcweir } 793*cdf0e10cSrcweir 794*cdf0e10cSrcweir for(a = 0L; a < nCount; a++) 795*cdf0e10cSrcweir { 796*cdf0e10cSrcweir const StripHelper& rHelper = aHelpers[a]; 797*cdf0e10cSrcweir bool bAcceptEntry(bKeepAboveZero ? 1L <= rHelper.mnDepth : 0L == rHelper.mnDepth); 798*cdf0e10cSrcweir 799*cdf0e10cSrcweir if(bAcceptEntry) 800*cdf0e10cSrcweir { 801*cdf0e10cSrcweir aRetval.append(rCandidate.getB2DPolygon(a)); 802*cdf0e10cSrcweir } 803*cdf0e10cSrcweir } 804*cdf0e10cSrcweir } 805*cdf0e10cSrcweir } 806*cdf0e10cSrcweir 807*cdf0e10cSrcweir return aRetval; 808*cdf0e10cSrcweir } 809*cdf0e10cSrcweir 810*cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 811*cdf0e10cSrcweir 812*cdf0e10cSrcweir B2DPolyPolygon prepareForPolygonOperation(const B2DPolygon& rCandidate) 813*cdf0e10cSrcweir { 814*cdf0e10cSrcweir solver aSolver(rCandidate); 815*cdf0e10cSrcweir B2DPolyPolygon aRetval(stripNeutralPolygons(aSolver.getB2DPolyPolygon())); 816*cdf0e10cSrcweir 817*cdf0e10cSrcweir return correctOrientations(aRetval); 818*cdf0e10cSrcweir } 819*cdf0e10cSrcweir 820*cdf0e10cSrcweir B2DPolyPolygon prepareForPolygonOperation(const B2DPolyPolygon& rCandidate) 821*cdf0e10cSrcweir { 822*cdf0e10cSrcweir solver aSolver(rCandidate); 823*cdf0e10cSrcweir B2DPolyPolygon aRetval(stripNeutralPolygons(aSolver.getB2DPolyPolygon())); 824*cdf0e10cSrcweir 825*cdf0e10cSrcweir return correctOrientations(aRetval); 826*cdf0e10cSrcweir } 827*cdf0e10cSrcweir 828*cdf0e10cSrcweir B2DPolyPolygon solvePolygonOperationOr(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB) 829*cdf0e10cSrcweir { 830*cdf0e10cSrcweir if(!rCandidateA.count()) 831*cdf0e10cSrcweir { 832*cdf0e10cSrcweir return rCandidateB; 833*cdf0e10cSrcweir } 834*cdf0e10cSrcweir else if(!rCandidateB.count()) 835*cdf0e10cSrcweir { 836*cdf0e10cSrcweir return rCandidateA; 837*cdf0e10cSrcweir } 838*cdf0e10cSrcweir else 839*cdf0e10cSrcweir { 840*cdf0e10cSrcweir // concatenate polygons, solve crossovers and throw away all sub-polygons 841*cdf0e10cSrcweir // which have a depth other than 0. 842*cdf0e10cSrcweir B2DPolyPolygon aRetval(rCandidateA); 843*cdf0e10cSrcweir 844*cdf0e10cSrcweir aRetval.append(rCandidateB); 845*cdf0e10cSrcweir aRetval = solveCrossovers(aRetval); 846*cdf0e10cSrcweir aRetval = stripNeutralPolygons(aRetval); 847*cdf0e10cSrcweir 848*cdf0e10cSrcweir return stripDispensablePolygons(aRetval, false); 849*cdf0e10cSrcweir } 850*cdf0e10cSrcweir } 851*cdf0e10cSrcweir 852*cdf0e10cSrcweir B2DPolyPolygon solvePolygonOperationXor(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB) 853*cdf0e10cSrcweir { 854*cdf0e10cSrcweir if(!rCandidateA.count()) 855*cdf0e10cSrcweir { 856*cdf0e10cSrcweir return rCandidateB; 857*cdf0e10cSrcweir } 858*cdf0e10cSrcweir else if(!rCandidateB.count()) 859*cdf0e10cSrcweir { 860*cdf0e10cSrcweir return rCandidateA; 861*cdf0e10cSrcweir } 862*cdf0e10cSrcweir else 863*cdf0e10cSrcweir { 864*cdf0e10cSrcweir // XOR is pretty simple: By definition it is the simple concatenation of 865*cdf0e10cSrcweir // the single polygons since we imply XOR fill rule. Make it intersection-free 866*cdf0e10cSrcweir // and correct orientations 867*cdf0e10cSrcweir B2DPolyPolygon aRetval(rCandidateA); 868*cdf0e10cSrcweir 869*cdf0e10cSrcweir aRetval.append(rCandidateB); 870*cdf0e10cSrcweir aRetval = solveCrossovers(aRetval); 871*cdf0e10cSrcweir aRetval = stripNeutralPolygons(aRetval); 872*cdf0e10cSrcweir 873*cdf0e10cSrcweir return correctOrientations(aRetval); 874*cdf0e10cSrcweir } 875*cdf0e10cSrcweir } 876*cdf0e10cSrcweir 877*cdf0e10cSrcweir B2DPolyPolygon solvePolygonOperationAnd(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB) 878*cdf0e10cSrcweir { 879*cdf0e10cSrcweir if(!rCandidateA.count()) 880*cdf0e10cSrcweir { 881*cdf0e10cSrcweir return B2DPolyPolygon(); 882*cdf0e10cSrcweir } 883*cdf0e10cSrcweir else if(!rCandidateB.count()) 884*cdf0e10cSrcweir { 885*cdf0e10cSrcweir return B2DPolyPolygon(); 886*cdf0e10cSrcweir } 887*cdf0e10cSrcweir else 888*cdf0e10cSrcweir { 889*cdf0e10cSrcweir // concatenate polygons, solve crossovers and throw away all sub-polygons 890*cdf0e10cSrcweir // with a depth of < 1. This means to keep all polygons where at least two 891*cdf0e10cSrcweir // polygons do overlap. 892*cdf0e10cSrcweir B2DPolyPolygon aRetval(rCandidateA); 893*cdf0e10cSrcweir 894*cdf0e10cSrcweir aRetval.append(rCandidateB); 895*cdf0e10cSrcweir aRetval = solveCrossovers(aRetval); 896*cdf0e10cSrcweir aRetval = stripNeutralPolygons(aRetval); 897*cdf0e10cSrcweir 898*cdf0e10cSrcweir return stripDispensablePolygons(aRetval, true); 899*cdf0e10cSrcweir } 900*cdf0e10cSrcweir } 901*cdf0e10cSrcweir 902*cdf0e10cSrcweir B2DPolyPolygon solvePolygonOperationDiff(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB) 903*cdf0e10cSrcweir { 904*cdf0e10cSrcweir if(!rCandidateA.count()) 905*cdf0e10cSrcweir { 906*cdf0e10cSrcweir return B2DPolyPolygon(); 907*cdf0e10cSrcweir } 908*cdf0e10cSrcweir else if(!rCandidateB.count()) 909*cdf0e10cSrcweir { 910*cdf0e10cSrcweir return rCandidateA; 911*cdf0e10cSrcweir } 912*cdf0e10cSrcweir else 913*cdf0e10cSrcweir { 914*cdf0e10cSrcweir // Make B topologically to holes and append to A 915*cdf0e10cSrcweir B2DPolyPolygon aRetval(rCandidateB); 916*cdf0e10cSrcweir 917*cdf0e10cSrcweir aRetval.flip(); 918*cdf0e10cSrcweir aRetval.append(rCandidateA); 919*cdf0e10cSrcweir 920*cdf0e10cSrcweir // solve crossovers and throw away all sub-polygons which have a 921*cdf0e10cSrcweir // depth other than 0. 922*cdf0e10cSrcweir aRetval = basegfx::tools::solveCrossovers(aRetval); 923*cdf0e10cSrcweir aRetval = basegfx::tools::stripNeutralPolygons(aRetval); 924*cdf0e10cSrcweir 925*cdf0e10cSrcweir return basegfx::tools::stripDispensablePolygons(aRetval, false); 926*cdf0e10cSrcweir } 927*cdf0e10cSrcweir } 928*cdf0e10cSrcweir 929*cdf0e10cSrcweir B2DPolyPolygon mergeToSinglePolyPolygon(const std::vector< basegfx::B2DPolyPolygon >& rInput) 930*cdf0e10cSrcweir { 931*cdf0e10cSrcweir std::vector< basegfx::B2DPolyPolygon > aInput(rInput); 932*cdf0e10cSrcweir 933*cdf0e10cSrcweir // first step: prepareForPolygonOperation and simple merge of non-overlapping 934*cdf0e10cSrcweir // PolyPolygons for speedup; this is possible for the wanted OR-operation 935*cdf0e10cSrcweir if(aInput.size()) 936*cdf0e10cSrcweir { 937*cdf0e10cSrcweir std::vector< basegfx::B2DPolyPolygon > aResult; 938*cdf0e10cSrcweir aResult.reserve(aInput.size()); 939*cdf0e10cSrcweir 940*cdf0e10cSrcweir for(sal_uInt32 a(0); a < aInput.size(); a++) 941*cdf0e10cSrcweir { 942*cdf0e10cSrcweir const basegfx::B2DPolyPolygon aCandidate(prepareForPolygonOperation(aInput[a])); 943*cdf0e10cSrcweir 944*cdf0e10cSrcweir if(aResult.size()) 945*cdf0e10cSrcweir { 946*cdf0e10cSrcweir const B2DRange aCandidateRange(aCandidate.getB2DRange()); 947*cdf0e10cSrcweir bool bCouldMergeSimple(false); 948*cdf0e10cSrcweir 949*cdf0e10cSrcweir for(sal_uInt32 b(0); !bCouldMergeSimple && b < aResult.size(); b++) 950*cdf0e10cSrcweir { 951*cdf0e10cSrcweir basegfx::B2DPolyPolygon aTarget(aResult[b]); 952*cdf0e10cSrcweir const B2DRange aTargetRange(aTarget.getB2DRange()); 953*cdf0e10cSrcweir 954*cdf0e10cSrcweir if(!aCandidateRange.overlaps(aTargetRange)) 955*cdf0e10cSrcweir { 956*cdf0e10cSrcweir aTarget.append(aCandidate); 957*cdf0e10cSrcweir aResult[b] = aTarget; 958*cdf0e10cSrcweir bCouldMergeSimple = true; 959*cdf0e10cSrcweir } 960*cdf0e10cSrcweir } 961*cdf0e10cSrcweir 962*cdf0e10cSrcweir if(!bCouldMergeSimple) 963*cdf0e10cSrcweir { 964*cdf0e10cSrcweir aResult.push_back(aCandidate); 965*cdf0e10cSrcweir } 966*cdf0e10cSrcweir } 967*cdf0e10cSrcweir else 968*cdf0e10cSrcweir { 969*cdf0e10cSrcweir aResult.push_back(aCandidate); 970*cdf0e10cSrcweir } 971*cdf0e10cSrcweir } 972*cdf0e10cSrcweir 973*cdf0e10cSrcweir aInput = aResult; 974*cdf0e10cSrcweir } 975*cdf0e10cSrcweir 976*cdf0e10cSrcweir // second step: melt pairwise to a single PolyPolygon 977*cdf0e10cSrcweir while(aInput.size() > 1) 978*cdf0e10cSrcweir { 979*cdf0e10cSrcweir std::vector< basegfx::B2DPolyPolygon > aResult; 980*cdf0e10cSrcweir aResult.reserve((aInput.size() / 2) + 1); 981*cdf0e10cSrcweir 982*cdf0e10cSrcweir for(sal_uInt32 a(0); a < aInput.size(); a += 2) 983*cdf0e10cSrcweir { 984*cdf0e10cSrcweir if(a + 1 < aInput.size()) 985*cdf0e10cSrcweir { 986*cdf0e10cSrcweir // a pair for processing 987*cdf0e10cSrcweir aResult.push_back(solvePolygonOperationOr(aInput[a], aInput[a + 1])); 988*cdf0e10cSrcweir } 989*cdf0e10cSrcweir else 990*cdf0e10cSrcweir { 991*cdf0e10cSrcweir // last single PolyPolygon; copy to target to not lose it 992*cdf0e10cSrcweir aResult.push_back(aInput[a]); 993*cdf0e10cSrcweir } 994*cdf0e10cSrcweir } 995*cdf0e10cSrcweir 996*cdf0e10cSrcweir aInput = aResult; 997*cdf0e10cSrcweir } 998*cdf0e10cSrcweir 999*cdf0e10cSrcweir // third step: get result 1000*cdf0e10cSrcweir if(1 == aInput.size()) 1001*cdf0e10cSrcweir { 1002*cdf0e10cSrcweir return aInput[0]; 1003*cdf0e10cSrcweir } 1004*cdf0e10cSrcweir 1005*cdf0e10cSrcweir return B2DPolyPolygon(); 1006*cdf0e10cSrcweir } 1007*cdf0e10cSrcweir 1008*cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 1009*cdf0e10cSrcweir 1010*cdf0e10cSrcweir } // end of namespace tools 1011*cdf0e10cSrcweir } // end of namespace basegfx 1012*cdf0e10cSrcweir 1013*cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////// 1014*cdf0e10cSrcweir // eof 1015