merged tag ooo/OOO330_m14
[LibreOffice.git] / basegfx / source / polygon / b2dpolypolygoncutter.cxx
blob4f9cf3a75f72c7f0dc041ba6b71a31350e33c094
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_basegfx.hxx"
30 #include <osl/diagnose.h>
31 #include <basegfx/numeric/ftools.hxx>
32 #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
33 #include <basegfx/point/b2dpoint.hxx>
34 #include <basegfx/vector/b2dvector.hxx>
35 #include <basegfx/polygon/b2dpolygon.hxx>
36 #include <basegfx/polygon/b2dpolygontools.hxx>
37 #include <basegfx/polygon/b2dpolygoncutandtouch.hxx>
38 #include <basegfx/range/b2drange.hxx>
39 #include <basegfx/polygon/b2dpolypolygontools.hxx>
40 #include <basegfx/curve/b2dcubicbezier.hxx>
41 #include <vector>
42 #include <algorithm>
44 //////////////////////////////////////////////////////////////////////////////
46 namespace basegfx
48 namespace
50 //////////////////////////////////////////////////////////////////////////////
52 struct StripHelper
54 B2DRange maRange;
55 sal_Int32 mnDepth;
56 B2VectorOrientation meOrinetation;
59 //////////////////////////////////////////////////////////////////////////////
61 struct PN
63 public:
64 B2DPoint maPoint;
65 sal_uInt32 mnI;
66 sal_uInt32 mnIP;
67 sal_uInt32 mnIN;
70 //////////////////////////////////////////////////////////////////////////////
72 struct VN
74 public:
75 B2DVector maPrev;
76 B2DVector maNext;
78 // to have the correct curve segments in the crossover checks,
79 // it is necessary to keep the original next vectors, too. Else,
80 // it may happen to use a already switched next vector which
81 // would interpolate the wrong comparison point
82 B2DVector maOriginalNext;
85 //////////////////////////////////////////////////////////////////////////////
87 struct SN
89 public:
90 PN* mpPN;
92 bool operator<(const SN& rComp) const
94 if(fTools::equal(mpPN->maPoint.getX(), rComp.mpPN->maPoint.getX()))
96 if(fTools::equal(mpPN->maPoint.getY(), rComp.mpPN->maPoint.getY()))
98 return (mpPN->mnI < rComp.mpPN->mnI);
100 else
102 return fTools::less(mpPN->maPoint.getY(), rComp.mpPN->maPoint.getY());
105 else
107 return fTools::less(mpPN->maPoint.getX(), rComp.mpPN->maPoint.getX());
112 //////////////////////////////////////////////////////////////////////////////
114 typedef ::std::vector< PN > PNV;
115 typedef ::std::vector< VN > VNV;
116 typedef ::std::vector< SN > SNV;
118 //////////////////////////////////////////////////////////////////////////////
120 class solver
122 private:
123 const B2DPolyPolygon maOriginal;
124 PNV maPNV;
125 VNV maVNV;
126 SNV maSNV;
128 unsigned mbIsCurve : 1;
129 unsigned mbChanged : 1;
131 void impAddPolygon(const sal_uInt32 aPos, const B2DPolygon& rGeometry)
133 const sal_uInt32 nCount(rGeometry.count());
134 PN aNewPN;
135 VN aNewVN;
136 SN aNewSN;
138 for(sal_uInt32 a(0); a < nCount; a++)
140 const B2DPoint aPoint(rGeometry.getB2DPoint(a));
141 aNewPN.maPoint = aPoint;
142 aNewPN.mnI = aPos + a;
143 aNewPN.mnIP = aPos + ((a != 0) ? a - 1 : nCount - 1);
144 aNewPN.mnIN = aPos + ((a + 1 == nCount) ? 0 : a + 1);
145 maPNV.push_back(aNewPN);
147 if(mbIsCurve)
149 aNewVN.maPrev = rGeometry.getPrevControlPoint(a) - aPoint;
150 aNewVN.maNext = rGeometry.getNextControlPoint(a) - aPoint;
151 aNewVN.maOriginalNext = aNewVN.maNext;
152 maVNV.push_back(aNewVN);
155 aNewSN.mpPN = &maPNV[maPNV.size() - 1];
156 maSNV.push_back(aNewSN);
160 bool impLeftOfEdges(const B2DVector& rVecA, const B2DVector& rVecB, const B2DVector& rTest)
162 // tests if rTest is left of both directed line segments along the line -rVecA, rVecB. Test is
163 // with border.
164 if(rVecA.cross(rVecB) > 0.0)
166 // b is left turn seen from a, test if Test is left of both and so inside (left is seeen as inside)
167 const bool bBoolA(fTools::moreOrEqual(rVecA.cross(rTest), 0.0));
168 const bool bBoolB(fTools::lessOrEqual(rVecB.cross(rTest), 0.0));
170 return (bBoolA && bBoolB);
172 else
174 // b is right turn seen from a, test if Test is right of both and so outside (left is seeen as inside)
175 const bool bBoolA(fTools::lessOrEqual(rVecA.cross(rTest), 0.0));
176 const bool bBoolB(fTools::moreOrEqual(rVecB.cross(rTest), 0.0));
178 return (!(bBoolA && bBoolB));
182 void impSwitchNext(PN& rPNa, PN& rPNb)
184 ::std::swap(rPNa.mnIN, rPNb.mnIN);
186 if(mbIsCurve)
188 VN& rVNa = maVNV[rPNa.mnI];
189 VN& rVNb = maVNV[rPNb.mnI];
191 ::std::swap(rVNa.maNext, rVNb.maNext);
194 if(!mbChanged)
196 mbChanged = true;
200 B2DCubicBezier createSegment(const PN& rPN, bool bPrev) const
202 const B2DPoint& rStart(rPN.maPoint);
203 const B2DPoint& rEnd(maPNV[bPrev ? rPN.mnIP : rPN.mnIN].maPoint);
204 const B2DVector& rCPA(bPrev ? maVNV[rPN.mnI].maPrev : maVNV[rPN.mnI].maNext);
205 // Use maOriginalNext, not maNext to create the original (yet unchanged)
206 // curve segment. Otherwise, this segment would NOT ne correct.
207 const B2DVector& rCPB(bPrev ? maVNV[maPNV[rPN.mnIP].mnI].maOriginalNext : maVNV[maPNV[rPN.mnIN].mnI].maPrev);
209 return B2DCubicBezier(rStart, rStart + rCPA, rEnd + rCPB, rEnd);
212 void impHandleCommon(PN& rPNa, PN& rPNb)
214 if(mbIsCurve)
216 const B2DCubicBezier aNextA(createSegment(rPNa, false));
217 const B2DCubicBezier aPrevA(createSegment(rPNa, true));
219 if(aNextA.equal(aPrevA))
221 // deadend on A (identical edge)
222 return;
225 const B2DCubicBezier aNextB(createSegment(rPNb, false));
226 const B2DCubicBezier aPrevB(createSegment(rPNb, true));
228 if(aNextB.equal(aPrevB))
230 // deadend on B (identical edge)
231 return;
234 if(aPrevA.equal(aPrevB))
236 // common edge in same direction
237 if(aNextA.equal(aNextB))
239 // common edge in same direction continues
240 return;
242 else
244 // common edge in same direction leave
245 // action is done on enter
246 return;
249 else if(aPrevA.equal(aNextB))
251 // common edge in opposite direction
252 if(aNextA.equal(aPrevB))
254 // common edge in opposite direction continues
255 return;
257 else
259 // common edge in opposite direction leave
260 impSwitchNext(rPNa, rPNb);
263 else if(aNextA.equal(aNextB))
265 // common edge in same direction enter
266 // search leave edge
267 PN* pPNa2 = &maPNV[rPNa.mnIN];
268 PN* pPNb2 = &maPNV[rPNb.mnIN];
269 bool bOnEdge(true);
273 const B2DCubicBezier aNextA2(createSegment(*pPNa2, false));
274 const B2DCubicBezier aNextB2(createSegment(*pPNb2, false));
276 if(aNextA2.equal(aNextB2))
278 pPNa2 = &maPNV[pPNa2->mnIN];
279 pPNb2 = &maPNV[pPNb2->mnIN];
281 else
283 bOnEdge = false;
286 while(bOnEdge && pPNa2 != &rPNa && pPNa2 != &rPNa);
288 if(bOnEdge)
290 // loop over two identical polygon paths
291 return;
293 else
295 // enter at rPNa, rPNb; leave at pPNa2, pPNb2. No common edges
296 // at enter/leave. Check for crossover.
297 const B2DVector aPrevCA(aPrevA.interpolatePoint(0.5) - aPrevA.getStartPoint());
298 const B2DVector aNextCA(aNextA.interpolatePoint(0.5) - aNextA.getStartPoint());
299 const B2DVector aPrevCB(aPrevB.interpolatePoint(0.5) - aPrevB.getStartPoint());
300 const bool bEnter(impLeftOfEdges(aPrevCA, aNextCA, aPrevCB));
302 const B2DCubicBezier aNextA2(createSegment(*pPNa2, false));
303 const B2DCubicBezier aPrevA2(createSegment(*pPNa2, true));
304 const B2DCubicBezier aNextB2(createSegment(*pPNb2, false));
305 const B2DVector aPrevCA2(aPrevA2.interpolatePoint(0.5) - aPrevA2.getStartPoint());
306 const B2DVector aNextCA2(aNextA2.interpolatePoint(0.5) - aNextA2.getStartPoint());
307 const B2DVector aNextCB2(aNextB2.interpolatePoint(0.5) - aNextB2.getStartPoint());
308 const bool bLeave(impLeftOfEdges(aPrevCA2, aNextCA2, aNextCB2));
310 if(bEnter != bLeave)
312 // crossover
313 impSwitchNext(rPNa, rPNb);
317 else if(aNextA.equal(aPrevB))
319 // common edge in opposite direction enter
320 impSwitchNext(rPNa, rPNb);
322 else
324 // no common edges, check for crossover
325 const B2DVector aPrevCA(aPrevA.interpolatePoint(0.5) - aPrevA.getStartPoint());
326 const B2DVector aNextCA(aNextA.interpolatePoint(0.5) - aNextA.getStartPoint());
327 const B2DVector aPrevCB(aPrevB.interpolatePoint(0.5) - aPrevB.getStartPoint());
328 const B2DVector aNextCB(aNextB.interpolatePoint(0.5) - aNextB.getStartPoint());
330 const bool bEnter(impLeftOfEdges(aPrevCA, aNextCA, aPrevCB));
331 const bool bLeave(impLeftOfEdges(aPrevCA, aNextCA, aNextCB));
333 if(bEnter != bLeave)
335 // crossover
336 impSwitchNext(rPNa, rPNb);
340 else
342 const B2DPoint& rNextA(maPNV[rPNa.mnIN].maPoint);
343 const B2DPoint& rPrevA(maPNV[rPNa.mnIP].maPoint);
345 if(rNextA.equal(rPrevA))
347 // deadend on A
348 return;
351 const B2DPoint& rNextB(maPNV[rPNb.mnIN].maPoint);
352 const B2DPoint& rPrevB(maPNV[rPNb.mnIP].maPoint);
354 if(rNextB.equal(rPrevB))
356 // deadend on B
357 return;
360 if(rPrevA.equal(rPrevB))
362 // common edge in same direction
363 if(rNextA.equal(rNextB))
365 // common edge in same direction continues
366 return;
368 else
370 // common edge in same direction leave
371 // action is done on enter
372 return;
375 else if(rPrevA.equal(rNextB))
377 // common edge in opposite direction
378 if(rNextA.equal(rPrevB))
380 // common edge in opposite direction continues
381 return;
383 else
385 // common edge in opposite direction leave
386 impSwitchNext(rPNa, rPNb);
389 else if(rNextA.equal(rNextB))
391 // common edge in same direction enter
392 // search leave edge
393 PN* pPNa2 = &maPNV[rPNa.mnIN];
394 PN* pPNb2 = &maPNV[rPNb.mnIN];
395 bool bOnEdge(true);
399 const B2DPoint& rNextA2(maPNV[pPNa2->mnIN].maPoint);
400 const B2DPoint& rNextB2(maPNV[pPNb2->mnIN].maPoint);
402 if(rNextA2.equal(rNextB2))
404 pPNa2 = &maPNV[pPNa2->mnIN];
405 pPNb2 = &maPNV[pPNb2->mnIN];
407 else
409 bOnEdge = false;
412 while(bOnEdge && pPNa2 != &rPNa && pPNa2 != &rPNa);
414 if(bOnEdge)
416 // loop over two identical polygon paths
417 return;
419 else
421 // enter at rPNa, rPNb; leave at pPNa2, pPNb2. No common edges
422 // at enter/leave. Check for crossover.
423 const B2DPoint& aPointE(rPNa.maPoint);
424 const B2DVector aPrevAE(rPrevA - aPointE);
425 const B2DVector aNextAE(rNextA - aPointE);
426 const B2DVector aPrevBE(rPrevB - aPointE);
428 const B2DPoint& aPointL(pPNa2->maPoint);
429 const B2DVector aPrevAL(maPNV[pPNa2->mnIP].maPoint - aPointL);
430 const B2DVector aNextAL(maPNV[pPNa2->mnIN].maPoint - aPointL);
431 const B2DVector aNextBL(maPNV[pPNb2->mnIN].maPoint - aPointL);
433 const bool bEnter(impLeftOfEdges(aPrevAE, aNextAE, aPrevBE));
434 const bool bLeave(impLeftOfEdges(aPrevAL, aNextAL, aNextBL));
436 if(bEnter != bLeave)
438 // crossover; switch start or end
439 impSwitchNext(rPNa, rPNb);
443 else if(rNextA.equal(rPrevB))
445 // common edge in opposite direction enter
446 impSwitchNext(rPNa, rPNb);
448 else
450 // no common edges, check for crossover
451 const B2DPoint& aPoint(rPNa.maPoint);
452 const B2DVector aPrevA(rPrevA - aPoint);
453 const B2DVector aNextA(rNextA - aPoint);
454 const B2DVector aPrevB(rPrevB - aPoint);
455 const B2DVector aNextB(rNextB - aPoint);
457 const bool bEnter(impLeftOfEdges(aPrevA, aNextA, aPrevB));
458 const bool bLeave(impLeftOfEdges(aPrevA, aNextA, aNextB));
460 if(bEnter != bLeave)
462 // crossover
463 impSwitchNext(rPNa, rPNb);
469 void impSolve()
471 // sort by point to identify common nodes
472 ::std::sort(maSNV.begin(), maSNV.end());
474 // handle common nodes
475 const sal_uInt32 nNodeCount(maSNV.size());
477 for(sal_uInt32 a(0); a < nNodeCount - 1; a++)
479 // test a before using it, not after. Also use nPointCount instead of aSortNodes.size()
480 PN& rPNb = *(maSNV[a].mpPN);
482 for(sal_uInt32 b(a + 1); b < nNodeCount && rPNb.maPoint.equal(maSNV[b].mpPN->maPoint); b++)
484 impHandleCommon(rPNb, *maSNV[b].mpPN);
489 public:
490 solver(const B2DPolygon& rOriginal)
491 : maOriginal(B2DPolyPolygon(rOriginal)),
492 mbIsCurve(false),
493 mbChanged(false)
495 const sal_uInt32 nOriginalCount(rOriginal.count());
497 if(nOriginalCount)
499 B2DPolygon aGeometry(tools::addPointsAtCutsAndTouches(rOriginal));
500 aGeometry.removeDoublePoints();
501 aGeometry = tools::simplifyCurveSegments(aGeometry);
502 mbIsCurve = aGeometry.areControlPointsUsed();
504 const sal_uInt32 nPointCount(aGeometry.count());
506 // If it's not a pezier polygon, at least four points are needed to create
507 // a self-intersection. If it's a bezier polygon, the minimum point number
508 // is two, since with a single point You get a curve, but no self-intersection
509 if(nPointCount > 3 || (nPointCount > 1 && mbIsCurve))
511 // reserve space in point, control and sort vector.
512 maSNV.reserve(nPointCount);
513 maPNV.reserve(nPointCount);
514 maVNV.reserve(mbIsCurve ? nPointCount : 0);
516 // fill data
517 impAddPolygon(0, aGeometry);
519 // solve common nodes
520 impSolve();
525 solver(const B2DPolyPolygon& rOriginal)
526 : maOriginal(rOriginal),
527 mbIsCurve(false),
528 mbChanged(false)
530 sal_uInt32 nOriginalCount(maOriginal.count());
532 if(nOriginalCount)
534 B2DPolyPolygon aGeometry(tools::addPointsAtCutsAndTouches(maOriginal, true));
535 aGeometry.removeDoublePoints();
536 aGeometry = tools::simplifyCurveSegments(aGeometry);
537 mbIsCurve = aGeometry.areControlPointsUsed();
538 nOriginalCount = aGeometry.count();
540 if(nOriginalCount)
542 sal_uInt32 nPointCount(0);
543 sal_uInt32 a(0);
545 // count points
546 for(a = 0; a < nOriginalCount; a++)
548 const B2DPolygon aCandidate(aGeometry.getB2DPolygon(a));
549 const sal_uInt32 nCandCount(aCandidate.count());
551 // If it's not a bezier curve, at least three points would be needed to have a
552 // topological relevant (not empty) polygon. Since its not known here if trivial
553 // edges (dead ends) will be kept or sorted out, add non-bezier polygons with
554 // more than one point.
555 // For bezier curves, the minimum for defining an area is also one.
556 if(nCandCount)
558 nPointCount += nCandCount;
562 if(nPointCount)
564 // reserve space in point, control and sort vector.
565 maSNV.reserve(nPointCount);
566 maPNV.reserve(nPointCount);
567 maVNV.reserve(mbIsCurve ? nPointCount : 0);
569 // fill data
570 sal_uInt32 nInsertIndex(0);
572 for(a = 0; a < nOriginalCount; a++)
574 const B2DPolygon aCandidate(aGeometry.getB2DPolygon(a));
575 const sal_uInt32 nCandCount(aCandidate.count());
577 // use same condition as above, the data vector is
578 // pre-allocated
579 if(nCandCount)
581 impAddPolygon(nInsertIndex, aCandidate);
582 nInsertIndex += nCandCount;
586 // solve common nodes
587 impSolve();
593 B2DPolyPolygon getB2DPolyPolygon()
595 if(mbChanged)
597 B2DPolyPolygon aRetval;
598 const sal_uInt32 nCount(maPNV.size());
599 sal_uInt32 nCountdown(nCount);
601 for(sal_uInt32 a(0); nCountdown && a < nCount; a++)
603 PN& rPN = maPNV[a];
605 if(SAL_MAX_UINT32 != rPN.mnI)
607 // unused node, start new part polygon
608 B2DPolygon aNewPart;
609 PN* pPNCurr = &rPN;
613 const B2DPoint& rPoint = pPNCurr->maPoint;
614 aNewPart.append(rPoint);
616 if(mbIsCurve)
618 const VN& rVNCurr = maVNV[pPNCurr->mnI];
620 if(!rVNCurr.maPrev.equalZero())
622 aNewPart.setPrevControlPoint(aNewPart.count() - 1, rPoint + rVNCurr.maPrev);
625 if(!rVNCurr.maNext.equalZero())
627 aNewPart.setNextControlPoint(aNewPart.count() - 1, rPoint + rVNCurr.maNext);
631 pPNCurr->mnI = SAL_MAX_UINT32;
632 nCountdown--;
633 pPNCurr = &(maPNV[pPNCurr->mnIN]);
635 while(pPNCurr != &rPN && SAL_MAX_UINT32 != pPNCurr->mnI);
637 // close and add
638 aNewPart.setClosed(true);
639 aRetval.append(aNewPart);
643 return aRetval;
645 else
647 // no change, return original
648 return maOriginal;
653 //////////////////////////////////////////////////////////////////////////////
655 } // end of anonymous namespace
656 } // end of namespace basegfx
658 //////////////////////////////////////////////////////////////////////////////
660 namespace basegfx
662 namespace tools
664 //////////////////////////////////////////////////////////////////////////////
666 B2DPolyPolygon solveCrossovers(const B2DPolyPolygon& rCandidate)
668 if(rCandidate.count() > 1L)
670 solver aSolver(rCandidate);
671 return aSolver.getB2DPolyPolygon();
673 else
675 return rCandidate;
679 //////////////////////////////////////////////////////////////////////////////
681 B2DPolyPolygon solveCrossovers(const B2DPolygon& rCandidate)
683 solver aSolver(rCandidate);
684 return aSolver.getB2DPolyPolygon();
687 //////////////////////////////////////////////////////////////////////////////
689 B2DPolyPolygon stripNeutralPolygons(const B2DPolyPolygon& rCandidate)
691 B2DPolyPolygon aRetval;
693 for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
695 const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
697 if(ORIENTATION_NEUTRAL != tools::getOrientation(aCandidate))
699 aRetval.append(aCandidate);
703 return aRetval;
706 //////////////////////////////////////////////////////////////////////////////
708 B2DPolyPolygon stripDispensablePolygons(const B2DPolyPolygon& rCandidate, bool bKeepAboveZero)
710 const sal_uInt32 nCount(rCandidate.count());
711 B2DPolyPolygon aRetval;
713 if(nCount)
715 if(nCount == 1L)
717 if(!bKeepAboveZero && ORIENTATION_POSITIVE == tools::getOrientation(rCandidate.getB2DPolygon(0L)))
719 aRetval = rCandidate;
722 else
724 sal_uInt32 a, b;
725 ::std::vector< StripHelper > aHelpers;
726 aHelpers.resize(nCount);
728 for(a = 0L; a < nCount; a++)
730 const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
731 StripHelper* pNewHelper = &(aHelpers[a]);
732 pNewHelper->maRange = tools::getRange(aCandidate);
733 pNewHelper->meOrinetation = tools::getOrientation(aCandidate);
734 pNewHelper->mnDepth = (ORIENTATION_NEGATIVE == pNewHelper->meOrinetation ? -1L : 0L);
737 for(a = 0L; a < nCount - 1L; a++)
739 const B2DPolygon aCandA(rCandidate.getB2DPolygon(a));
740 StripHelper& rHelperA = aHelpers[a];
742 for(b = a + 1L; b < nCount; b++)
744 const B2DPolygon aCandB(rCandidate.getB2DPolygon(b));
745 StripHelper& rHelperB = aHelpers[b];
746 const bool bAInB(rHelperB.maRange.isInside(rHelperA.maRange) && tools::isInside(aCandB, aCandA, true));
747 const bool bBInA(rHelperA.maRange.isInside(rHelperB.maRange) && tools::isInside(aCandA, aCandB, true));
749 if(bAInB && bBInA)
751 // congruent
752 if(rHelperA.meOrinetation == rHelperB.meOrinetation)
754 // two polys or two holes. Lower one of them to get one of them out of the way.
755 // Since each will be contained in the other one, both will be increased, too.
756 // So, for lowering, increase only one of them
757 rHelperA.mnDepth++;
759 else
761 // poly and hole. They neutralize, so get rid of both. Move securely below zero.
762 rHelperA.mnDepth = -((sal_Int32)nCount);
763 rHelperB.mnDepth = -((sal_Int32)nCount);
766 else
768 if(bAInB)
770 if(ORIENTATION_NEGATIVE == rHelperB.meOrinetation)
772 rHelperA.mnDepth--;
774 else
776 rHelperA.mnDepth++;
779 else if(bBInA)
781 if(ORIENTATION_NEGATIVE == rHelperA.meOrinetation)
783 rHelperB.mnDepth--;
785 else
787 rHelperB.mnDepth++;
794 for(a = 0L; a < nCount; a++)
796 const StripHelper& rHelper = aHelpers[a];
797 bool bAcceptEntry(bKeepAboveZero ? 1L <= rHelper.mnDepth : 0L == rHelper.mnDepth);
799 if(bAcceptEntry)
801 aRetval.append(rCandidate.getB2DPolygon(a));
807 return aRetval;
810 //////////////////////////////////////////////////////////////////////////////
812 B2DPolyPolygon prepareForPolygonOperation(const B2DPolygon& rCandidate)
814 solver aSolver(rCandidate);
815 B2DPolyPolygon aRetval(stripNeutralPolygons(aSolver.getB2DPolyPolygon()));
817 return correctOrientations(aRetval);
820 B2DPolyPolygon prepareForPolygonOperation(const B2DPolyPolygon& rCandidate)
822 solver aSolver(rCandidate);
823 B2DPolyPolygon aRetval(stripNeutralPolygons(aSolver.getB2DPolyPolygon()));
825 return correctOrientations(aRetval);
828 B2DPolyPolygon solvePolygonOperationOr(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB)
830 if(!rCandidateA.count())
832 return rCandidateB;
834 else if(!rCandidateB.count())
836 return rCandidateA;
838 else
840 // concatenate polygons, solve crossovers and throw away all sub-polygons
841 // which have a depth other than 0.
842 B2DPolyPolygon aRetval(rCandidateA);
844 aRetval.append(rCandidateB);
845 aRetval = solveCrossovers(aRetval);
846 aRetval = stripNeutralPolygons(aRetval);
848 return stripDispensablePolygons(aRetval, false);
852 B2DPolyPolygon solvePolygonOperationXor(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB)
854 if(!rCandidateA.count())
856 return rCandidateB;
858 else if(!rCandidateB.count())
860 return rCandidateA;
862 else
864 // XOR is pretty simple: By definition it is the simple concatenation of
865 // the single polygons since we imply XOR fill rule. Make it intersection-free
866 // and correct orientations
867 B2DPolyPolygon aRetval(rCandidateA);
869 aRetval.append(rCandidateB);
870 aRetval = solveCrossovers(aRetval);
871 aRetval = stripNeutralPolygons(aRetval);
873 return correctOrientations(aRetval);
877 B2DPolyPolygon solvePolygonOperationAnd(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB)
879 if(!rCandidateA.count())
881 return B2DPolyPolygon();
883 else if(!rCandidateB.count())
885 return B2DPolyPolygon();
887 else
889 // concatenate polygons, solve crossovers and throw away all sub-polygons
890 // with a depth of < 1. This means to keep all polygons where at least two
891 // polygons do overlap.
892 B2DPolyPolygon aRetval(rCandidateA);
894 aRetval.append(rCandidateB);
895 aRetval = solveCrossovers(aRetval);
896 aRetval = stripNeutralPolygons(aRetval);
898 return stripDispensablePolygons(aRetval, true);
902 B2DPolyPolygon solvePolygonOperationDiff(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB)
904 if(!rCandidateA.count())
906 return B2DPolyPolygon();
908 else if(!rCandidateB.count())
910 return rCandidateA;
912 else
914 // Make B topologically to holes and append to A
915 B2DPolyPolygon aRetval(rCandidateB);
917 aRetval.flip();
918 aRetval.append(rCandidateA);
920 // solve crossovers and throw away all sub-polygons which have a
921 // depth other than 0.
922 aRetval = basegfx::tools::solveCrossovers(aRetval);
923 aRetval = basegfx::tools::stripNeutralPolygons(aRetval);
925 return basegfx::tools::stripDispensablePolygons(aRetval, false);
929 B2DPolyPolygon mergeToSinglePolyPolygon(const std::vector< basegfx::B2DPolyPolygon >& rInput)
931 std::vector< basegfx::B2DPolyPolygon > aInput(rInput);
933 // first step: prepareForPolygonOperation and simple merge of non-overlapping
934 // PolyPolygons for speedup; this is possible for the wanted OR-operation
935 if(aInput.size())
937 std::vector< basegfx::B2DPolyPolygon > aResult;
938 aResult.reserve(aInput.size());
940 for(sal_uInt32 a(0); a < aInput.size(); a++)
942 const basegfx::B2DPolyPolygon aCandidate(prepareForPolygonOperation(aInput[a]));
944 if(aResult.size())
946 const B2DRange aCandidateRange(aCandidate.getB2DRange());
947 bool bCouldMergeSimple(false);
949 for(sal_uInt32 b(0); !bCouldMergeSimple && b < aResult.size(); b++)
951 basegfx::B2DPolyPolygon aTarget(aResult[b]);
952 const B2DRange aTargetRange(aTarget.getB2DRange());
954 if(!aCandidateRange.overlaps(aTargetRange))
956 aTarget.append(aCandidate);
957 aResult[b] = aTarget;
958 bCouldMergeSimple = true;
962 if(!bCouldMergeSimple)
964 aResult.push_back(aCandidate);
967 else
969 aResult.push_back(aCandidate);
973 aInput = aResult;
976 // second step: melt pairwise to a single PolyPolygon
977 while(aInput.size() > 1)
979 std::vector< basegfx::B2DPolyPolygon > aResult;
980 aResult.reserve((aInput.size() / 2) + 1);
982 for(sal_uInt32 a(0); a < aInput.size(); a += 2)
984 if(a + 1 < aInput.size())
986 // a pair for processing
987 aResult.push_back(solvePolygonOperationOr(aInput[a], aInput[a + 1]));
989 else
991 // last single PolyPolygon; copy to target to not lose it
992 aResult.push_back(aInput[a]);
996 aInput = aResult;
999 // third step: get result
1000 if(1 == aInput.size())
1002 return aInput[0];
1005 return B2DPolyPolygon();
1008 //////////////////////////////////////////////////////////////////////////////
1010 } // end of namespace tools
1011 } // end of namespace basegfx
1013 //////////////////////////////////////////////////////////////////////////////
1014 // eof