Update ooo320-m1
[ooovba.git] / basegfx / source / polygon / b2dpolypolygoncutter.cxx
blob83e92edd75bed24d2bc39149cceeb43c14466d38
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: b2dpolypolygoncutter.cxx,v $
10 * $Revision: 1.17 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_basegfx.hxx"
33 #include <osl/diagnose.h>
34 #include <basegfx/numeric/ftools.hxx>
35 #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
36 #include <basegfx/point/b2dpoint.hxx>
37 #include <basegfx/vector/b2dvector.hxx>
38 #include <basegfx/polygon/b2dpolygon.hxx>
39 #include <basegfx/polygon/b2dpolygontools.hxx>
40 #include <basegfx/polygon/b2dpolygoncutandtouch.hxx>
41 #include <basegfx/range/b2drange.hxx>
42 #include <basegfx/polygon/b2dpolypolygontools.hxx>
43 #include <basegfx/curve/b2dcubicbezier.hxx>
44 #include <vector>
45 #include <algorithm>
47 //////////////////////////////////////////////////////////////////////////////
49 namespace basegfx
51 namespace
53 //////////////////////////////////////////////////////////////////////////////
55 struct StripHelper
57 B2DRange maRange;
58 sal_Int32 mnDepth;
59 B2VectorOrientation meOrinetation;
62 //////////////////////////////////////////////////////////////////////////////
64 struct PN
66 public:
67 B2DPoint maPoint;
68 sal_uInt32 mnI;
69 sal_uInt32 mnIP;
70 sal_uInt32 mnIN;
73 //////////////////////////////////////////////////////////////////////////////
75 struct VN
77 public:
78 B2DVector maPrev;
79 B2DVector maNext;
81 // to have the correct curve segments in the crossover checks,
82 // it is necessary to keep the original next vectors, too. Else,
83 // it may happen to use a already switched next vector which
84 // would interpolate the wrong comparison point
85 B2DVector maOriginalNext;
88 //////////////////////////////////////////////////////////////////////////////
90 struct SN
92 public:
93 PN* mpPN;
95 bool operator<(const SN& rComp) const
97 if(fTools::equal(mpPN->maPoint.getX(), rComp.mpPN->maPoint.getX()))
99 if(fTools::equal(mpPN->maPoint.getY(), rComp.mpPN->maPoint.getY()))
101 return (mpPN->mnI < rComp.mpPN->mnI);
103 else
105 return fTools::less(mpPN->maPoint.getY(), rComp.mpPN->maPoint.getY());
108 else
110 return fTools::less(mpPN->maPoint.getX(), rComp.mpPN->maPoint.getX());
115 //////////////////////////////////////////////////////////////////////////////
117 typedef ::std::vector< PN > PNV;
118 typedef ::std::vector< VN > VNV;
119 typedef ::std::vector< SN > SNV;
121 //////////////////////////////////////////////////////////////////////////////
123 class solver
125 private:
126 const B2DPolyPolygon maOriginal;
127 PNV maPNV;
128 VNV maVNV;
129 SNV maSNV;
131 unsigned mbIsCurve : 1;
132 unsigned mbChanged : 1;
134 void impAddPolygon(const sal_uInt32 aPos, const B2DPolygon& rGeometry)
136 const sal_uInt32 nCount(rGeometry.count());
137 PN aNewPN;
138 VN aNewVN;
139 SN aNewSN;
141 for(sal_uInt32 a(0); a < nCount; a++)
143 const B2DPoint aPoint(rGeometry.getB2DPoint(a));
144 aNewPN.maPoint = aPoint;
145 aNewPN.mnI = aPos + a;
146 aNewPN.mnIP = aPos + ((a != 0) ? a - 1 : nCount - 1);
147 aNewPN.mnIN = aPos + ((a + 1 == nCount) ? 0 : a + 1);
148 maPNV.push_back(aNewPN);
150 if(mbIsCurve)
152 aNewVN.maPrev = rGeometry.getPrevControlPoint(a) - aPoint;
153 aNewVN.maNext = rGeometry.getNextControlPoint(a) - aPoint;
154 aNewVN.maOriginalNext = aNewVN.maNext;
155 maVNV.push_back(aNewVN);
158 aNewSN.mpPN = &maPNV[maPNV.size() - 1];
159 maSNV.push_back(aNewSN);
163 bool impLeftOfEdges(const B2DVector& rVecA, const B2DVector& rVecB, const B2DVector& rTest)
165 // tests if rTest is left of both directed line segments along the line -rVecA, rVecB. Test is
166 // with border.
167 if(rVecA.cross(rVecB) > 0.0)
169 // b is left turn seen from a, test if Test is left of both and so inside (left is seeen as inside)
170 const bool bBoolA(fTools::moreOrEqual(rVecA.cross(rTest), 0.0));
171 const bool bBoolB(fTools::lessOrEqual(rVecB.cross(rTest), 0.0));
173 return (bBoolA && bBoolB);
175 else
177 // b is right turn seen from a, test if Test is right of both and so outside (left is seeen as inside)
178 const bool bBoolA(fTools::lessOrEqual(rVecA.cross(rTest), 0.0));
179 const bool bBoolB(fTools::moreOrEqual(rVecB.cross(rTest), 0.0));
181 return (!(bBoolA && bBoolB));
185 void impSwitchNext(PN& rPNa, PN& rPNb)
187 ::std::swap(rPNa.mnIN, rPNb.mnIN);
189 if(mbIsCurve)
191 VN& rVNa = maVNV[rPNa.mnI];
192 VN& rVNb = maVNV[rPNb.mnI];
194 ::std::swap(rVNa.maNext, rVNb.maNext);
197 if(!mbChanged)
199 mbChanged = true;
203 B2DCubicBezier createSegment(const PN& rPN, bool bPrev) const
205 const B2DPoint& rStart(rPN.maPoint);
206 const B2DPoint& rEnd(maPNV[bPrev ? rPN.mnIP : rPN.mnIN].maPoint);
207 const B2DVector& rCPA(bPrev ? maVNV[rPN.mnI].maPrev : maVNV[rPN.mnI].maNext);
208 // Use maOriginalNext, not maNext to create the original (yet unchanged)
209 // curve segment. Otherwise, this segment would NOT ne correct.
210 const B2DVector& rCPB(bPrev ? maVNV[maPNV[rPN.mnIP].mnI].maOriginalNext : maVNV[maPNV[rPN.mnIN].mnI].maPrev);
212 return B2DCubicBezier(rStart, rStart + rCPA, rEnd + rCPB, rEnd);
215 void impHandleCommon(PN& rPNa, PN& rPNb)
217 if(mbIsCurve)
219 const B2DCubicBezier aNextA(createSegment(rPNa, false));
220 const B2DCubicBezier aPrevA(createSegment(rPNa, true));
222 if(aNextA.equal(aPrevA))
224 // deadend on A (identical edge)
225 return;
228 const B2DCubicBezier aNextB(createSegment(rPNb, false));
229 const B2DCubicBezier aPrevB(createSegment(rPNb, true));
231 if(aNextB.equal(aPrevB))
233 // deadend on B (identical edge)
234 return;
237 if(aPrevA.equal(aPrevB))
239 // common edge in same direction
240 if(aNextA.equal(aNextB))
242 // common edge in same direction continues
243 return;
245 else
247 // common edge in same direction leave
248 // action is done on enter
249 return;
252 else if(aPrevA.equal(aNextB))
254 // common edge in opposite direction
255 if(aNextA.equal(aPrevB))
257 // common edge in opposite direction continues
258 return;
260 else
262 // common edge in opposite direction leave
263 impSwitchNext(rPNa, rPNb);
266 else if(aNextA.equal(aNextB))
268 // common edge in same direction enter
269 // search leave edge
270 PN* pPNa2 = &maPNV[rPNa.mnIN];
271 PN* pPNb2 = &maPNV[rPNb.mnIN];
272 bool bOnEdge(true);
276 const B2DCubicBezier aNextA2(createSegment(*pPNa2, false));
277 const B2DCubicBezier aNextB2(createSegment(*pPNb2, false));
279 if(aNextA2.equal(aNextB2))
281 pPNa2 = &maPNV[pPNa2->mnIN];
282 pPNb2 = &maPNV[pPNb2->mnIN];
284 else
286 bOnEdge = false;
289 while(bOnEdge && pPNa2 != &rPNa && pPNa2 != &rPNa);
291 if(bOnEdge)
293 // loop over two identical polygon paths
294 return;
296 else
298 // enter at rPNa, rPNb; leave at pPNa2, pPNb2. No common edges
299 // at enter/leave. Check for crossover.
300 const B2DVector aPrevCA(aPrevA.interpolatePoint(0.5) - aPrevA.getStartPoint());
301 const B2DVector aNextCA(aNextA.interpolatePoint(0.5) - aNextA.getStartPoint());
302 const B2DVector aPrevCB(aPrevB.interpolatePoint(0.5) - aPrevB.getStartPoint());
303 const bool bEnter(impLeftOfEdges(aPrevCA, aNextCA, aPrevCB));
305 const B2DCubicBezier aNextA2(createSegment(*pPNa2, false));
306 const B2DCubicBezier aPrevA2(createSegment(*pPNa2, true));
307 const B2DCubicBezier aNextB2(createSegment(*pPNb2, false));
308 const B2DVector aPrevCA2(aPrevA2.interpolatePoint(0.5) - aPrevA2.getStartPoint());
309 const B2DVector aNextCA2(aNextA2.interpolatePoint(0.5) - aNextA2.getStartPoint());
310 const B2DVector aNextCB2(aNextB2.interpolatePoint(0.5) - aNextB2.getStartPoint());
311 const bool bLeave(impLeftOfEdges(aPrevCA2, aNextCA2, aNextCB2));
313 if(bEnter != bLeave)
315 // crossover
316 impSwitchNext(rPNa, rPNb);
320 else if(aNextA.equal(aPrevB))
322 // common edge in opposite direction enter
323 impSwitchNext(rPNa, rPNb);
325 else
327 // no common edges, check for crossover
328 const B2DVector aPrevCA(aPrevA.interpolatePoint(0.5) - aPrevA.getStartPoint());
329 const B2DVector aNextCA(aNextA.interpolatePoint(0.5) - aNextA.getStartPoint());
330 const B2DVector aPrevCB(aPrevB.interpolatePoint(0.5) - aPrevB.getStartPoint());
331 const B2DVector aNextCB(aNextB.interpolatePoint(0.5) - aNextB.getStartPoint());
333 const bool bEnter(impLeftOfEdges(aPrevCA, aNextCA, aPrevCB));
334 const bool bLeave(impLeftOfEdges(aPrevCA, aNextCA, aNextCB));
336 if(bEnter != bLeave)
338 // crossover
339 impSwitchNext(rPNa, rPNb);
343 else
345 const B2DPoint& rNextA(maPNV[rPNa.mnIN].maPoint);
346 const B2DPoint& rPrevA(maPNV[rPNa.mnIP].maPoint);
348 if(rNextA.equal(rPrevA))
350 // deadend on A
351 return;
354 const B2DPoint& rNextB(maPNV[rPNb.mnIN].maPoint);
355 const B2DPoint& rPrevB(maPNV[rPNb.mnIP].maPoint);
357 if(rNextB.equal(rPrevB))
359 // deadend on B
360 return;
363 if(rPrevA.equal(rPrevB))
365 // common edge in same direction
366 if(rNextA.equal(rNextB))
368 // common edge in same direction continues
369 return;
371 else
373 // common edge in same direction leave
374 // action is done on enter
375 return;
378 else if(rPrevA.equal(rNextB))
380 // common edge in opposite direction
381 if(rNextA.equal(rPrevB))
383 // common edge in opposite direction continues
384 return;
386 else
388 // common edge in opposite direction leave
389 impSwitchNext(rPNa, rPNb);
392 else if(rNextA.equal(rNextB))
394 // common edge in same direction enter
395 // search leave edge
396 PN* pPNa2 = &maPNV[rPNa.mnIN];
397 PN* pPNb2 = &maPNV[rPNb.mnIN];
398 bool bOnEdge(true);
402 const B2DPoint& rNextA2(maPNV[pPNa2->mnIN].maPoint);
403 const B2DPoint& rNextB2(maPNV[pPNb2->mnIN].maPoint);
405 if(rNextA2.equal(rNextB2))
407 pPNa2 = &maPNV[pPNa2->mnIN];
408 pPNb2 = &maPNV[pPNb2->mnIN];
410 else
412 bOnEdge = false;
415 while(bOnEdge && pPNa2 != &rPNa && pPNa2 != &rPNa);
417 if(bOnEdge)
419 // loop over two identical polygon paths
420 return;
422 else
424 // enter at rPNa, rPNb; leave at pPNa2, pPNb2. No common edges
425 // at enter/leave. Check for crossover.
426 const B2DPoint& aPointE(rPNa.maPoint);
427 const B2DVector aPrevAE(rPrevA - aPointE);
428 const B2DVector aNextAE(rNextA - aPointE);
429 const B2DVector aPrevBE(rPrevB - aPointE);
431 const B2DPoint& aPointL(pPNa2->maPoint);
432 const B2DVector aPrevAL(maPNV[pPNa2->mnIP].maPoint - aPointL);
433 const B2DVector aNextAL(maPNV[pPNa2->mnIN].maPoint - aPointL);
434 const B2DVector aNextBL(maPNV[pPNb2->mnIN].maPoint - aPointL);
436 const bool bEnter(impLeftOfEdges(aPrevAE, aNextAE, aPrevBE));
437 const bool bLeave(impLeftOfEdges(aPrevAL, aNextAL, aNextBL));
439 if(bEnter != bLeave)
441 // crossover; switch start or end
442 impSwitchNext(rPNa, rPNb);
446 else if(rNextA.equal(rPrevB))
448 // common edge in opposite direction enter
449 impSwitchNext(rPNa, rPNb);
451 else
453 // no common edges, check for crossover
454 const B2DPoint& aPoint(rPNa.maPoint);
455 const B2DVector aPrevA(rPrevA - aPoint);
456 const B2DVector aNextA(rNextA - aPoint);
457 const B2DVector aPrevB(rPrevB - aPoint);
458 const B2DVector aNextB(rNextB - aPoint);
460 const bool bEnter(impLeftOfEdges(aPrevA, aNextA, aPrevB));
461 const bool bLeave(impLeftOfEdges(aPrevA, aNextA, aNextB));
463 if(bEnter != bLeave)
465 // crossover
466 impSwitchNext(rPNa, rPNb);
472 void impSolve()
474 // sort by point to identify common nodes
475 ::std::sort(maSNV.begin(), maSNV.end());
477 // handle common nodes
478 const sal_uInt32 nNodeCount(maSNV.size());
480 for(sal_uInt32 a(0); a < nNodeCount - 1; a++)
482 // test a before using it, not after. Also use nPointCount instead of aSortNodes.size()
483 PN& rPNb = *(maSNV[a].mpPN);
485 for(sal_uInt32 b(a + 1); b < nNodeCount && rPNb.maPoint.equal(maSNV[b].mpPN->maPoint); b++)
487 impHandleCommon(rPNb, *maSNV[b].mpPN);
492 public:
493 solver(const B2DPolygon& rOriginal)
494 : maOriginal(B2DPolyPolygon(rOriginal)),
495 mbIsCurve(false),
496 mbChanged(false)
498 const sal_uInt32 nOriginalCount(rOriginal.count());
500 if(nOriginalCount)
502 B2DPolygon aGeometry(tools::addPointsAtCutsAndTouches(rOriginal));
503 aGeometry.removeDoublePoints();
504 aGeometry = tools::simplifyCurveSegments(aGeometry);
505 mbIsCurve = aGeometry.areControlPointsUsed();
507 const sal_uInt32 nPointCount(aGeometry.count());
509 // If it's not a pezier polygon, at least four points are needed to create
510 // a self-intersection. If it's a bezier polygon, the minimum point number
511 // is two, since with a single point You get a curve, but no self-intersection
512 if(nPointCount > 3 || (nPointCount > 1 && mbIsCurve))
514 // reserve space in point, control and sort vector.
515 maSNV.reserve(nPointCount);
516 maPNV.reserve(nPointCount);
517 maVNV.reserve(mbIsCurve ? nPointCount : 0);
519 // fill data
520 impAddPolygon(0, aGeometry);
522 // solve common nodes
523 impSolve();
528 solver(const B2DPolyPolygon& rOriginal)
529 : maOriginal(rOriginal),
530 mbIsCurve(false),
531 mbChanged(false)
533 sal_uInt32 nOriginalCount(maOriginal.count());
535 if(nOriginalCount)
537 B2DPolyPolygon aGeometry(tools::addPointsAtCutsAndTouches(maOriginal, true));
538 aGeometry.removeDoublePoints();
539 aGeometry = tools::simplifyCurveSegments(aGeometry);
540 mbIsCurve = aGeometry.areControlPointsUsed();
541 nOriginalCount = aGeometry.count();
543 if(nOriginalCount)
545 sal_uInt32 nPointCount(0);
546 sal_uInt32 a(0);
548 // count points
549 for(a = 0; a < nOriginalCount; a++)
551 const B2DPolygon aCandidate(aGeometry.getB2DPolygon(a));
552 const sal_uInt32 nCandCount(aCandidate.count());
554 // If it's not a bezier curve, at least three points would be needed to have a
555 // topological relevant (not empty) polygon. Since its not known here if trivial
556 // edges (dead ends) will be kept or sorted out, add non-bezier polygons with
557 // more than one point.
558 // For bezier curves, the minimum for defining an area is also one.
559 if(nCandCount)
561 nPointCount += nCandCount;
565 if(nPointCount)
567 // reserve space in point, control and sort vector.
568 maSNV.reserve(nPointCount);
569 maPNV.reserve(nPointCount);
570 maVNV.reserve(mbIsCurve ? nPointCount : 0);
572 // fill data
573 sal_uInt32 nInsertIndex(0);
575 for(a = 0; a < nOriginalCount; a++)
577 const B2DPolygon aCandidate(aGeometry.getB2DPolygon(a));
578 const sal_uInt32 nCandCount(aCandidate.count());
580 // use same condition as above, the data vector is
581 // pre-allocated
582 if(nCandCount)
584 impAddPolygon(nInsertIndex, aCandidate);
585 nInsertIndex += nCandCount;
589 // solve common nodes
590 impSolve();
596 B2DPolyPolygon getB2DPolyPolygon()
598 if(mbChanged)
600 B2DPolyPolygon aRetval;
601 const sal_uInt32 nCount(maPNV.size());
602 sal_uInt32 nCountdown(nCount);
604 for(sal_uInt32 a(0); nCountdown && a < nCount; a++)
606 PN& rPN = maPNV[a];
608 if(SAL_MAX_UINT32 != rPN.mnI)
610 // unused node, start new part polygon
611 B2DPolygon aNewPart;
612 PN* pPNCurr = &rPN;
616 const B2DPoint& rPoint = pPNCurr->maPoint;
617 aNewPart.append(rPoint);
619 if(mbIsCurve)
621 const VN& rVNCurr = maVNV[pPNCurr->mnI];
623 if(!rVNCurr.maPrev.equalZero())
625 aNewPart.setPrevControlPoint(aNewPart.count() - 1, rPoint + rVNCurr.maPrev);
628 if(!rVNCurr.maNext.equalZero())
630 aNewPart.setNextControlPoint(aNewPart.count() - 1, rPoint + rVNCurr.maNext);
634 pPNCurr->mnI = SAL_MAX_UINT32;
635 nCountdown--;
636 pPNCurr = &(maPNV[pPNCurr->mnIN]);
638 while(pPNCurr != &rPN && SAL_MAX_UINT32 != pPNCurr->mnI);
640 // close and add
641 aNewPart.setClosed(true);
642 aRetval.append(aNewPart);
646 return aRetval;
648 else
650 // no change, return original
651 return maOriginal;
656 //////////////////////////////////////////////////////////////////////////////
658 } // end of anonymous namespace
659 } // end of namespace basegfx
661 //////////////////////////////////////////////////////////////////////////////
663 namespace basegfx
665 namespace tools
667 //////////////////////////////////////////////////////////////////////////////
669 B2DPolyPolygon solveCrossovers(const B2DPolyPolygon& rCandidate)
671 if(rCandidate.count() > 1L)
673 solver aSolver(rCandidate);
674 return aSolver.getB2DPolyPolygon();
676 else
678 return rCandidate;
682 //////////////////////////////////////////////////////////////////////////////
684 B2DPolyPolygon solveCrossovers(const B2DPolygon& rCandidate)
686 solver aSolver(rCandidate);
687 return aSolver.getB2DPolyPolygon();
690 //////////////////////////////////////////////////////////////////////////////
692 B2DPolyPolygon stripNeutralPolygons(const B2DPolyPolygon& rCandidate)
694 B2DPolyPolygon aRetval;
696 for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
698 const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
700 if(ORIENTATION_NEUTRAL != tools::getOrientation(aCandidate))
702 aRetval.append(aCandidate);
706 return aRetval;
709 //////////////////////////////////////////////////////////////////////////////
711 B2DPolyPolygon stripDispensablePolygons(const B2DPolyPolygon& rCandidate, bool bKeepAboveZero)
713 const sal_uInt32 nCount(rCandidate.count());
714 B2DPolyPolygon aRetval;
716 if(nCount)
718 if(nCount == 1L)
720 if(!bKeepAboveZero && ORIENTATION_POSITIVE == tools::getOrientation(rCandidate.getB2DPolygon(0L)))
722 aRetval = rCandidate;
725 else
727 sal_uInt32 a, b;
728 ::std::vector< StripHelper > aHelpers;
729 aHelpers.resize(nCount);
731 for(a = 0L; a < nCount; a++)
733 const B2DPolygon aCandidate(rCandidate.getB2DPolygon(a));
734 StripHelper* pNewHelper = &(aHelpers[a]);
735 pNewHelper->maRange = tools::getRange(aCandidate);
736 pNewHelper->meOrinetation = tools::getOrientation(aCandidate);
737 pNewHelper->mnDepth = (ORIENTATION_NEGATIVE == pNewHelper->meOrinetation ? -1L : 0L);
740 for(a = 0L; a < nCount - 1L; a++)
742 const B2DPolygon aCandA(rCandidate.getB2DPolygon(a));
743 StripHelper& rHelperA = aHelpers[a];
745 for(b = a + 1L; b < nCount; b++)
747 const B2DPolygon aCandB(rCandidate.getB2DPolygon(b));
748 StripHelper& rHelperB = aHelpers[b];
749 const bool bAInB(rHelperB.maRange.isInside(rHelperA.maRange) && tools::isInside(aCandB, aCandA, true));
750 const bool bBInA(rHelperA.maRange.isInside(rHelperB.maRange) && tools::isInside(aCandA, aCandB, true));
752 if(bAInB && bBInA)
754 // congruent
755 if(rHelperA.meOrinetation == rHelperB.meOrinetation)
757 // two polys or two holes. Lower one of them to get one of them out of the way.
758 // Since each will be contained in the other one, both will be increased, too.
759 // So, for lowering, increase only one of them
760 rHelperA.mnDepth++;
762 else
764 // poly and hole. They neutralize, so get rid of both. Move securely below zero.
765 rHelperA.mnDepth = -((sal_Int32)nCount);
766 rHelperB.mnDepth = -((sal_Int32)nCount);
769 else
771 if(bAInB)
773 if(ORIENTATION_NEGATIVE == rHelperB.meOrinetation)
775 rHelperA.mnDepth--;
777 else
779 rHelperA.mnDepth++;
782 else if(bBInA)
784 if(ORIENTATION_NEGATIVE == rHelperA.meOrinetation)
786 rHelperB.mnDepth--;
788 else
790 rHelperB.mnDepth++;
797 for(a = 0L; a < nCount; a++)
799 const StripHelper& rHelper = aHelpers[a];
800 bool bAcceptEntry(bKeepAboveZero ? 1L <= rHelper.mnDepth : 0L == rHelper.mnDepth);
802 if(bAcceptEntry)
804 aRetval.append(rCandidate.getB2DPolygon(a));
810 return aRetval;
813 //////////////////////////////////////////////////////////////////////////////
815 B2DPolyPolygon prepareForPolygonOperation(const B2DPolygon& rCandidate)
817 solver aSolver(rCandidate);
818 B2DPolyPolygon aRetval(stripNeutralPolygons(aSolver.getB2DPolyPolygon()));
820 return correctOrientations(aRetval);
823 B2DPolyPolygon prepareForPolygonOperation(const B2DPolyPolygon& rCandidate)
825 solver aSolver(rCandidate);
826 B2DPolyPolygon aRetval(stripNeutralPolygons(aSolver.getB2DPolyPolygon()));
828 return correctOrientations(aRetval);
831 B2DPolyPolygon solvePolygonOperationOr(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB)
833 if(!rCandidateA.count())
835 return rCandidateB;
837 else if(!rCandidateB.count())
839 return rCandidateA;
841 else
843 // concatenate polygons, solve crossovers and throw away all sub-polygons
844 // which have a depth other than 0.
845 B2DPolyPolygon aRetval(rCandidateA);
847 aRetval.append(rCandidateB);
848 aRetval = solveCrossovers(aRetval);
849 aRetval = stripNeutralPolygons(aRetval);
851 return stripDispensablePolygons(aRetval, false);
855 B2DPolyPolygon solvePolygonOperationXor(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB)
857 if(!rCandidateA.count())
859 return rCandidateB;
861 else if(!rCandidateB.count())
863 return rCandidateA;
865 else
867 // XOR is pretty simple: By definition it is the simple concatenation of
868 // the single polygons since we imply XOR fill rule. Make it intersection-free
869 // and correct orientations
870 B2DPolyPolygon aRetval(rCandidateA);
872 aRetval.append(rCandidateB);
873 aRetval = solveCrossovers(aRetval);
874 aRetval = stripNeutralPolygons(aRetval);
876 return correctOrientations(aRetval);
880 B2DPolyPolygon solvePolygonOperationAnd(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB)
882 if(!rCandidateA.count())
884 return B2DPolyPolygon();
886 else if(!rCandidateB.count())
888 return B2DPolyPolygon();
890 else
892 // concatenate polygons, solve crossovers and throw away all sub-polygons
893 // with a depth of < 1. This means to keep all polygons where at least two
894 // polygons do overlap.
895 B2DPolyPolygon aRetval(rCandidateA);
897 aRetval.append(rCandidateB);
898 aRetval = solveCrossovers(aRetval);
899 aRetval = stripNeutralPolygons(aRetval);
901 return stripDispensablePolygons(aRetval, true);
905 B2DPolyPolygon solvePolygonOperationDiff(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB)
907 if(!rCandidateA.count())
909 return B2DPolyPolygon();
911 else if(!rCandidateB.count())
913 return rCandidateA;
915 else
917 // Make B topologically to holes and append to A
918 B2DPolyPolygon aRetval(rCandidateB);
920 aRetval.flip();
921 aRetval.append(rCandidateA);
923 // solve crossovers and throw away all sub-polygons which have a
924 // depth other than 0.
925 aRetval = basegfx::tools::solveCrossovers(aRetval);
926 aRetval = basegfx::tools::stripNeutralPolygons(aRetval);
928 return basegfx::tools::stripDispensablePolygons(aRetval, false);
932 B2DPolyPolygon mergeToSinglePolyPolygon(const std::vector< basegfx::B2DPolyPolygon >& rInput)
934 std::vector< basegfx::B2DPolyPolygon > aInput(rInput);
936 // first step: prepareForPolygonOperation and simple merge of non-overlapping
937 // PolyPolygons for speedup; this is possible for the wanted OR-operation
938 if(aInput.size())
940 std::vector< basegfx::B2DPolyPolygon > aResult;
941 aResult.reserve(aInput.size());
943 for(sal_uInt32 a(0); a < aInput.size(); a++)
945 const basegfx::B2DPolyPolygon aCandidate(prepareForPolygonOperation(aInput[a]));
947 if(aResult.size())
949 const B2DRange aCandidateRange(aCandidate.getB2DRange());
950 bool bCouldMergeSimple(false);
952 for(sal_uInt32 b(0); !bCouldMergeSimple && b < aResult.size(); b++)
954 basegfx::B2DPolyPolygon aTarget(aResult[b]);
955 const B2DRange aTargetRange(aTarget.getB2DRange());
957 if(!aCandidateRange.overlaps(aTargetRange))
959 aTarget.append(aCandidate);
960 aResult[b] = aTarget;
961 bCouldMergeSimple = true;
965 if(!bCouldMergeSimple)
967 aResult.push_back(aCandidate);
970 else
972 aResult.push_back(aCandidate);
976 aInput = aResult;
979 // second step: melt pairwise to a single PolyPolygon
980 while(aInput.size() > 1)
982 std::vector< basegfx::B2DPolyPolygon > aResult;
983 aResult.reserve((aInput.size() / 2) + 1);
985 for(sal_uInt32 a(0); a < aInput.size(); a += 2)
987 if(a + 1 < aInput.size())
989 // a pair for processing
990 aResult.push_back(solvePolygonOperationOr(aInput[a], aInput[a + 1]));
992 else
994 // last single PolyPolygon; copy to target to not lose it
995 aResult.push_back(aInput[a]);
999 aInput = aResult;
1002 // third step: get result
1003 if(1 == aInput.size())
1005 return aInput[0];
1008 return B2DPolyPolygon();
1011 //////////////////////////////////////////////////////////////////////////////
1013 } // end of namespace tools
1014 } // end of namespace basegfx
1016 //////////////////////////////////////////////////////////////////////////////
1017 // eof