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