1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: b2dmultirange.cxx,v $
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 <basegfx/tools/b2dclipstate.hxx>
35 #include <basegfx/range/b2drange.hxx>
36 #include <basegfx/range/b2dpolyrange.hxx>
37 #include <basegfx/range/b2drangeclipper.hxx>
38 #include <basegfx/polygon/b2dpolygon.hxx>
39 #include <basegfx/polygon/b2dpolygontools.hxx>
40 #include <basegfx/polygon/b2dpolypolygon.hxx>
41 #include <basegfx/polygon/b2dpolypolygontools.hxx>
42 #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
48 struct ImplB2DClipState
51 enum Operation
{UNION
, INTERSECT
, XOR
, SUBTRACT
};
60 explicit ImplB2DClipState( const B2DRange
& rRange
) :
64 tools::createPolygonFromRect(rRange
)),
68 explicit ImplB2DClipState( const B2DPolygon
& rPoly
) :
75 explicit ImplB2DClipState( const B2DPolyPolygon
& rPoly
) :
82 bool isCleared() const
84 return !maClipPoly
.count()
85 && !maPendingPolygons
.count()
86 && !maPendingRanges
.count();
91 maPendingPolygons
.clear();
92 maPendingRanges
.clear();
97 bool isNullClipPoly() const
99 return maClipPoly
.count() == 1
100 && !maClipPoly
.getB2DPolygon(0).count();
105 return !maPendingPolygons
.count()
106 && !maPendingRanges
.count()
112 maPendingPolygons
.clear();
113 maPendingRanges
.clear();
115 maClipPoly
.append(B2DPolygon());
116 mePendingOps
= UNION
;
119 bool operator==(const ImplB2DClipState
& rRHS
) const
121 return maPendingPolygons
== rRHS
.maPendingPolygons
122 && maPendingRanges
== rRHS
.maPendingRanges
123 && maClipPoly
== rRHS
.maClipPoly
124 && mePendingOps
== rRHS
.mePendingOps
;
127 void addRange(const B2DRange
& rRange
, Operation eOp
)
129 if( rRange
.isEmpty() )
132 commitPendingPolygons();
133 if( mePendingOps
!= eOp
)
134 commitPendingRanges();
137 maPendingRanges
.appendElement(
139 ORIENTATION_POSITIVE
);
142 void addPolygon(B2DPolygon aPoly
, Operation eOp
)
144 commitPendingRanges();
145 if( mePendingOps
!= eOp
)
146 commitPendingPolygons();
149 maPendingPolygons
.append(aPoly
);
152 void addPolyPolygon(B2DPolyPolygon aPoly
, Operation eOp
)
154 commitPendingRanges();
155 if( mePendingOps
!= eOp
)
156 commitPendingPolygons();
159 maPendingPolygons
.append(aPoly
);
162 void addClipState(const ImplB2DClipState
& rOther
, Operation eOp
)
164 if( rOther
.mePendingOps
== mePendingOps
165 && !rOther
.maClipPoly
.count()
166 && !rOther
.maPendingPolygons
.count() )
168 maPendingRanges
.appendPolyRange( rOther
.maPendingRanges
);
172 commitPendingRanges();
173 commitPendingPolygons();
174 rOther
.commitPendingRanges();
175 rOther
.commitPendingPolygons();
177 maPendingPolygons
= rOther
.maClipPoly
;
182 void unionRange(const B2DRange
& rRange
)
187 addRange(rRange
,UNION
);
190 void unionPolygon(const B2DPolygon
& rPoly
)
195 addPolygon(rPoly
,UNION
);
198 void unionPolyPolygon(const B2DPolyPolygon
& rPolyPoly
)
203 addPolyPolygon(rPolyPoly
,UNION
);
206 void unionClipState(const ImplB2DClipState
& rOther
)
211 addClipState(rOther
, UNION
);
214 void intersectRange(const B2DRange
& rRange
)
219 addRange(rRange
,INTERSECT
);
222 void intersectPolygon(const B2DPolygon
& rPoly
)
227 addPolygon(rPoly
,INTERSECT
);
230 void intersectPolyPolygon(const B2DPolyPolygon
& rPolyPoly
)
235 addPolyPolygon(rPolyPoly
,INTERSECT
);
238 void intersectClipState(const ImplB2DClipState
& rOther
)
243 addClipState(rOther
, INTERSECT
);
246 void subtractRange(const B2DRange
& rRange
)
251 addRange(rRange
,SUBTRACT
);
254 void subtractPolygon(const B2DPolygon
& rPoly
)
259 addPolygon(rPoly
,SUBTRACT
);
262 void subtractPolyPolygon(const B2DPolyPolygon
& rPolyPoly
)
267 addPolyPolygon(rPolyPoly
,SUBTRACT
);
270 void subtractClipState(const ImplB2DClipState
& rOther
)
275 addClipState(rOther
, SUBTRACT
);
278 void xorRange(const B2DRange
& rRange
)
280 addRange(rRange
,XOR
);
283 void xorPolygon(const B2DPolygon
& rPoly
)
285 addPolygon(rPoly
,XOR
);
288 void xorPolyPolygon(const B2DPolyPolygon
& rPolyPoly
)
290 addPolyPolygon(rPolyPoly
,XOR
);
293 void xorClipState(const ImplB2DClipState
& rOther
)
295 addClipState(rOther
, XOR
);
298 B2DPolyPolygon
getClipPoly() const
300 commitPendingRanges();
301 commitPendingPolygons();
307 void commitPendingPolygons() const
309 if( !maPendingPolygons
.count() )
312 // assumption: maClipPoly has kept polygons prepared for
313 // clipping; i.e. no neutral polygons & correct
315 maPendingPolygons
= tools::prepareForPolygonOperation(maPendingPolygons
);
316 const bool bIsEmpty
=isNullClipPoly();
317 const bool bIsCleared
=!maClipPoly
.count();
321 OSL_ASSERT( !bIsCleared
);
324 maClipPoly
= maPendingPolygons
;
326 maClipPoly
= tools::solvePolygonOperationOr(
331 OSL_ASSERT( !bIsEmpty
);
334 maClipPoly
= maPendingPolygons
;
336 maClipPoly
= tools::solvePolygonOperationAnd(
342 maClipPoly
= maPendingPolygons
;
343 else if( bIsCleared
)
345 // not representable, strictly speaking,
346 // using polygons with the common even/odd
347 // or nonzero winding number fill rule. If
348 // we'd want to represent it, fill rule
349 // would need to be "non-negative winding
350 // number" (and we then would return
353 // going for an ugly hack meanwhile
354 maClipPoly
= tools::solvePolygonOperationXor(
356 tools::createPolygonFromRect(B2DRange(-1E20
,-1E20
,1E20
,1E20
))),
360 maClipPoly
= tools::solvePolygonOperationXor(
365 OSL_ASSERT( !bIsEmpty
);
367 // first union all pending ones, subtract en bloc then
368 maPendingPolygons
= solveCrossovers(maPendingPolygons
);
369 maPendingPolygons
= stripNeutralPolygons(maPendingPolygons
);
370 maPendingPolygons
= stripDispensablePolygons(maPendingPolygons
, false);
374 // not representable, strictly speaking,
375 // using polygons with the common even/odd
376 // or nonzero winding number fill rule. If
377 // we'd want to represent it, fill rule
378 // would need to be "non-negative winding
379 // number" (and we then would return
382 // going for an ugly hack meanwhile
383 maClipPoly
= tools::solvePolygonOperationDiff(
385 tools::createPolygonFromRect(B2DRange(-1E20
,-1E20
,1E20
,1E20
))),
389 maClipPoly
= tools::solvePolygonOperationDiff(
395 maPendingPolygons
.clear();
396 mePendingOps
= UNION
;
399 void commitPendingRanges() const
401 if( !maPendingRanges
.count() )
404 // use the specialized range clipper for the win
405 B2DPolyPolygon aCollectedRanges
;
406 const bool bIsEmpty
=isNullClipPoly();
407 const bool bIsCleared
=!maClipPoly
.count();
411 OSL_ASSERT( !bIsCleared
);
413 aCollectedRanges
= maPendingRanges
.solveCrossovers();
414 aCollectedRanges
= stripNeutralPolygons(aCollectedRanges
);
415 aCollectedRanges
= stripDispensablePolygons(aCollectedRanges
, false);
417 maClipPoly
= aCollectedRanges
;
419 maClipPoly
= tools::solvePolygonOperationOr(
424 OSL_ASSERT( !bIsEmpty
);
426 aCollectedRanges
= maPendingRanges
.solveCrossovers();
427 aCollectedRanges
= stripNeutralPolygons(aCollectedRanges
);
428 if( maPendingRanges
.count() > 1 )
429 aCollectedRanges
= stripDispensablePolygons(aCollectedRanges
, true);
432 maClipPoly
= aCollectedRanges
;
434 maClipPoly
= tools::solvePolygonOperationAnd(
439 aCollectedRanges
= maPendingRanges
.solveCrossovers();
440 aCollectedRanges
= stripNeutralPolygons(aCollectedRanges
);
441 aCollectedRanges
= correctOrientations(aCollectedRanges
);
444 maClipPoly
= aCollectedRanges
;
445 else if( bIsCleared
)
447 // not representable, strictly speaking,
448 // using polygons with the common even/odd
449 // or nonzero winding number fill rule. If
450 // we'd want to represent it, fill rule
451 // would need to be "non-negative winding
452 // number" (and we then would return
455 // going for an ugly hack meanwhile
456 maClipPoly
= tools::solvePolygonOperationXor(
458 tools::createPolygonFromRect(B2DRange(-1E20
,-1E20
,1E20
,1E20
))),
462 maClipPoly
= tools::solvePolygonOperationXor(
467 OSL_ASSERT( !bIsEmpty
);
469 // first union all pending ranges, subtract en bloc then
470 aCollectedRanges
= maPendingRanges
.solveCrossovers();
471 aCollectedRanges
= stripNeutralPolygons(aCollectedRanges
);
472 aCollectedRanges
= stripDispensablePolygons(aCollectedRanges
, false);
476 // not representable, strictly speaking,
477 // using polygons with the common even/odd
478 // or nonzero winding number fill rule. If
479 // we'd want to represent it, fill rule
480 // would need to be "non-negative winding
481 // number" (and we then would return
484 // going for an ugly hack meanwhile
485 maClipPoly
= tools::solvePolygonOperationDiff(
487 tools::createPolygonFromRect(B2DRange(-1E20
,-1E20
,1E20
,1E20
))),
491 maClipPoly
= tools::solvePolygonOperationDiff(
497 maPendingRanges
.clear();
498 mePendingOps
= UNION
;
501 mutable B2DPolyPolygon maPendingPolygons
;
502 mutable B2DPolyRange maPendingRanges
;
503 mutable B2DPolyPolygon maClipPoly
;
504 mutable Operation mePendingOps
;
507 B2DClipState::B2DClipState() :
511 B2DClipState::~B2DClipState()
514 B2DClipState::B2DClipState( const B2DClipState
& rOrig
) :
518 B2DClipState::B2DClipState( const B2DRange
& rRange
) :
519 mpImpl( ImplB2DClipState(rRange
) )
522 B2DClipState::B2DClipState( const B2DPolygon
& rPoly
) :
523 mpImpl( ImplB2DClipState(rPoly
) )
526 B2DClipState::B2DClipState( const B2DPolyPolygon
& rPolyPoly
) :
527 mpImpl( ImplB2DClipState(rPolyPoly
) )
530 B2DClipState
& B2DClipState::operator=( const B2DClipState
& rRHS
)
532 mpImpl
= rRHS
.mpImpl
;
536 void B2DClipState::makeUnique()
538 mpImpl
.make_unique();
541 void B2DClipState::makeNull()
546 bool B2DClipState::isNull() const
548 return mpImpl
->isNull();
551 void B2DClipState::makeClear()
556 bool B2DClipState::isCleared() const
558 return mpImpl
->isCleared();
561 bool B2DClipState::operator==(const B2DClipState
& rRHS
) const
563 if(mpImpl
.same_object(rRHS
.mpImpl
))
566 return ((*mpImpl
) == (*rRHS
.mpImpl
));
569 bool B2DClipState::operator!=(const B2DClipState
& rRHS
) const
571 return !(*this == rRHS
);
574 void B2DClipState::unionRange(const B2DRange
& rRange
)
576 mpImpl
->unionRange(rRange
);
579 void B2DClipState::unionPolygon(const B2DPolygon
& rPoly
)
581 mpImpl
->unionPolygon(rPoly
);
584 void B2DClipState::unionPolyPolygon(const B2DPolyPolygon
& rPolyPoly
)
586 mpImpl
->unionPolyPolygon(rPolyPoly
);
589 void B2DClipState::unionClipState(const B2DClipState
& rState
)
591 mpImpl
->unionClipState(*rState
.mpImpl
);
594 void B2DClipState::intersectRange(const B2DRange
& rRange
)
596 mpImpl
->intersectRange(rRange
);
599 void B2DClipState::intersectPolygon(const B2DPolygon
& rPoly
)
601 mpImpl
->intersectPolygon(rPoly
);
604 void B2DClipState::intersectPolyPolygon(const B2DPolyPolygon
& rPolyPoly
)
606 mpImpl
->intersectPolyPolygon(rPolyPoly
);
609 void B2DClipState::intersectClipState(const B2DClipState
& rState
)
611 mpImpl
->intersectClipState(*rState
.mpImpl
);
614 void B2DClipState::subtractRange(const B2DRange
& rRange
)
616 mpImpl
->subtractRange(rRange
);
619 void B2DClipState::subtractPolygon(const B2DPolygon
& rPoly
)
621 mpImpl
->subtractPolygon(rPoly
);
624 void B2DClipState::subtractPolyPolygon(const B2DPolyPolygon
& rPolyPoly
)
626 mpImpl
->subtractPolyPolygon(rPolyPoly
);
629 void B2DClipState::subtractClipState(const B2DClipState
& rState
)
631 mpImpl
->subtractClipState(*rState
.mpImpl
);
634 void B2DClipState::xorRange(const B2DRange
& rRange
)
636 mpImpl
->xorRange(rRange
);
639 void B2DClipState::xorPolygon(const B2DPolygon
& rPoly
)
641 mpImpl
->xorPolygon(rPoly
);
644 void B2DClipState::xorPolyPolygon(const B2DPolyPolygon
& rPolyPoly
)
646 mpImpl
->xorPolyPolygon(rPolyPoly
);
649 void B2DClipState::xorClipState(const B2DClipState
& rState
)
651 mpImpl
->xorClipState(*rState
.mpImpl
);
654 B2DPolyPolygon
B2DClipState::getClipPoly() const
656 return mpImpl
->getClipPoly();
659 } // end of namespace tools
660 } // end of namespace basegfx