20#include <osl/diagnose.h>
77 const double& fInvariantCoord,
78 std::ptrdiff_t nPolyIdx,
79 EdgeDirection eEdgeDirection ) :
88 std::ptrdiff_t getTargetPolygonIndex()
const {
return mnPolygonIdx; }
89 void setTargetPolygonIndex( std::ptrdiff_t nIdx ) {
mnPolygonIdx = nIdx; }
125 typedef std::list< ActiveEdge > ListOfEdges;
171 SweepLineEvent(
double fPos,
174 EdgeDirection eDirection) :
181 double getPos()
const {
return mfPos; }
187 bool operator<(
const SweepLineEvent& rRHS )
const {
return mfPos < rRHS.mfPos; }
234 void setPolygonPoolIndex( std::ptrdiff_t nIdx ) {
mnIdx = nIdx; }
237 void append(
const B2DPoint& rPoint )
240 maPoints.back().getX() == rPoint.getX() ||
241 maPoints.back().getY() == rPoint.getY(),
242 "ImplPolygon::append(): added point violates 90 degree line angle constraint!" );
274 std::ptrdiff_t intersect( SweepLineEvent
const & rEvent,
275 ActiveEdge& rActiveEdge,
276 VectorOfPolygons& rPolygonPool,
277 B2DPolyPolygon& rRes,
278 bool isFinishingEdge )
281 "ImplPolygon::intersect(): called on already finished polygon!" );
282 OSL_PRECOND( !isFinishingEdge || &rEvent.getRect() == &rActiveEdge.getRect(),
283 "ImplPolygon::intersect(): inconsistent ending!" );
285 const B2DPoint aIntersectionPoint( rEvent.getPos(),
286 rActiveEdge.getInvariantCoord() );
290 append(aIntersectionPoint);
292 if( isFinishingEdge )
295 if( rEvent.getEdgeType() == SweepLineEvent::STARTING_EDGE)
296 handleFinalOwnRightEdge(rActiveEdge);
298 handleFinalOwnLeftEdge(rActiveEdge,
305 else if( metOwnEdge(rEvent,rActiveEdge) )
307 handleInitialOwnEdge(rEvent, rActiveEdge);
315 OSL_ENSURE( rActiveEdge.getTargetPolygonIndex() != -1,
316 "ImplPolygon::intersect(): non-trivial intersection hit empty polygon!" );
318 const bool isHittingLeftEdge(
319 rActiveEdge.getEdgeDirection() == ActiveEdge::PROCEED_LEFT);
321 if( isHittingLeftEdge )
322 return handleComplexLeftEdge(rActiveEdge,
327 return handleComplexRightEdge(rActiveEdge,
334 void handleInitialOwnEdge(SweepLineEvent
const & rEvent,
335 ActiveEdge
const & rActiveEdge)
const
337 const bool isActiveEdgeProceedLeft(
338 rActiveEdge.getEdgeDirection() == ActiveEdge::PROCEED_LEFT);
339 const bool isSweepLineEnteringRect(
340 rEvent.getEdgeType() == SweepLineEvent::STARTING_EDGE);
342 OSL_ENSURE( isSweepLineEnteringRect == isActiveEdgeProceedLeft,
343 "ImplPolygon::intersect(): sweep initial own edge hit: wrong polygon order" );
345 OSL_ENSURE( isSweepLineEnteringRect ||
347 "ImplPolygon::intersect(): sweep initial own edge hit: wrong leading edge" );
350 void handleFinalOwnRightEdge(ActiveEdge& rActiveEdge)
352 OSL_ENSURE( rActiveEdge.getEdgeDirection() == ActiveEdge::PROCEED_RIGHT,
353 "ImplPolygon::handleInitialOwnRightEdge(): start edge wrong polygon order" );
355 rActiveEdge.setTargetPolygonIndex(
mnIdx);
359 void handleFinalOwnLeftEdge(ActiveEdge
const & rActiveEdge,
360 VectorOfPolygons& rPolygonPool,
361 B2DPolyPolygon& rRes)
363 OSL_ENSURE( rActiveEdge.getEdgeDirection() == ActiveEdge::PROCEED_LEFT,
364 "ImplPolygon::handleFinalOwnLeftEdge(): end edge wrong polygon order" );
366 const bool isHittingOurTail(
367 rActiveEdge.getTargetPolygonIndex() ==
mnIdx);
369 if( isHittingOurTail )
374 const std::ptrdiff_t nTmpIdx=rActiveEdge.getTargetPolygonIndex();
380 rTmp.maPoints.begin(),
381 rTmp.maPoints.end());
384 ActiveEdge*
const pFarEdge=rTmp.mpLeadingRightEdge;
387 pFarEdge->setTargetPolygonIndex(
mnIdx);
390 rPolygonPool.free(nTmpIdx);
394 std::ptrdiff_t handleComplexLeftEdge(ActiveEdge& rActiveEdge,
395 const B2DPoint& rIntersectionPoint,
396 VectorOfPolygons& rPolygonPool,
397 B2DPolyPolygon& rRes)
399 const bool isHittingOurTail(
400 rActiveEdge.getTargetPolygonIndex() ==
mnIdx);
401 if( isHittingOurTail )
407 const std::ptrdiff_t nIdxNewPolygon=rPolygonPool.alloc();
408 rPolygonPool.get(nIdxNewPolygon).setPolygonPoolIndex(nIdxNewPolygon);
409 rPolygonPool.get(nIdxNewPolygon).append(rIntersectionPoint);
411 rActiveEdge.setTargetPolygonIndex(nIdxNewPolygon);
413 return nIdxNewPolygon;
417 const std::ptrdiff_t nTmpIdx=rActiveEdge.getTargetPolygonIndex();
423 rTmp.maPoints.begin(),
424 rTmp.maPoints.end());
426 rTmp.maPoints.clear();
427 rTmp.append(rIntersectionPoint);
430 ActiveEdge*
const pFarEdge=rTmp.mpLeadingRightEdge;
431 ActiveEdge*
const pNearEdge=&rActiveEdge;
433 rTmp.mpLeadingRightEdge =
nullptr;
434 pNearEdge->setTargetPolygonIndex(nTmpIdx);
437 pFarEdge->setTargetPolygonIndex(
mnIdx);
443 std::ptrdiff_t handleComplexRightEdge(ActiveEdge& rActiveEdge,
444 const B2DPoint& rIntersectionPoint,
445 VectorOfPolygons& rPolygonPool)
447 const std::ptrdiff_t nTmpIdx=rActiveEdge.getTargetPolygonIndex();
450 rTmp.append(rIntersectionPoint);
452 rActiveEdge.setTargetPolygonIndex(
mnIdx);
455 rTmp.mpLeadingRightEdge =
nullptr;
461 static bool metOwnEdge(SweepLineEvent
const & rEvent,
462 ActiveEdge
const & rActiveEdge)
464 const bool bHitOwnEdge=&rEvent.getRect() == &rActiveEdge.getRect();
469 B2DPolygon getPolygon()
const
473 aRes.append(aPoint, 1);
474 aRes.setClosed(
true );
480 void finish(B2DPolyPolygon& rRes)
485 "ImplPolygon::finish(): first and last point violate 90 degree line angle constraint!" );
490 rRes.append(getPolygon());
517 void setupSweepLineEventListFromRanges(
VectorOfEvents& o_rEventVector,
518 const std::vector<B2DRange>& rRanges,
519 const std::vector<B2VectorOrientation>& rOrientations )
523 o_rEventVector.clear();
524 o_rEventVector.reserve( 2*rRanges.size() );
530 std::vector<B2DRange>::const_iterator aCurrRect=rRanges.begin();
531 std::vector<B2VectorOrientation>::const_iterator aCurrOrientation=rOrientations.begin();
532 const std::vector<B2DRange>::const_iterator aEnd=rRanges.end();
533 const std::vector<B2VectorOrientation>::const_iterator aEndOrientation=rOrientations.end();
534 while( aCurrRect != aEnd && aCurrOrientation != aEndOrientation )
538 o_rEventVector.emplace_back( rCurrRect.getMinX(),
540 SweepLineEvent::STARTING_EDGE,
542 SweepLineEvent::PROCEED_UP : SweepLineEvent::PROCEED_DOWN );
546 std::vector<B2DRange>::const_reverse_iterator aCurrRectR=rRanges.rbegin();
547 std::vector<B2VectorOrientation>::const_reverse_iterator aCurrOrientationR=rOrientations.rbegin();
548 const std::vector<B2DRange>::const_reverse_iterator aEndR=rRanges.rend();
549 while( aCurrRectR != aEndR )
553 o_rEventVector.emplace_back( rCurrRect.getMaxX(),
555 SweepLineEvent::FINISHING_EDGE,
557 SweepLineEvent::PROCEED_DOWN : SweepLineEvent::PROCEED_UP );
571 std::stable_sort( o_rEventVector.begin(),
572 o_rEventVector.end() );
598 void createActiveEdgesFromStartEvent( ListOfEdges & io_rEdgeList,
599 VectorOfPolygons & io_rPolygonPool,
600 SweepLineEvent
const & rCurrEvent )
602 ListOfEdges aNewEdges;
604 const bool bGoesDown=rCurrEvent.getEdgeDirection() == SweepLineEvent::PROCEED_DOWN;
608 const std::ptrdiff_t nIdxPolygon=io_rPolygonPool.alloc();
609 io_rPolygonPool.get(nIdxPolygon).setPolygonPoolIndex(nIdxPolygon);
612 aNewEdges.emplace_back(
615 bGoesDown ? nIdxPolygon : -1,
616 bGoesDown ? ActiveEdge::PROCEED_LEFT : ActiveEdge::PROCEED_RIGHT );
618 aNewEdges.emplace_back(
621 bGoesDown ? -1 : nIdxPolygon,
622 bGoesDown ? ActiveEdge::PROCEED_RIGHT : ActiveEdge::PROCEED_LEFT );
635 const double nMinY( rRect.getMinY() );
636 const double nMaxY( rRect.getMaxY() );
637 ListOfEdges::iterator aCurr( io_rEdgeList.begin() );
638 const ListOfEdges::iterator aEnd ( io_rEdgeList.end() );
639 while( aCurr != aEnd )
641 const double nCurrY( aCurr->getInvariantCoord() );
643 if( nCurrY >= nMinY &&
644 aNewEdges.size() == 2 )
650 io_rEdgeList.splice( aCurr,
662 io_rEdgeList.splice( aCurr,
674 io_rEdgeList.splice( aCurr,
678 bool isSameRect(ActiveEdge
const & rEdge,
681 return &rEdge.getRect() == &rRect;
686 template<
typename Cont,
typename Iter> Iter eraseFromList(Cont&,
const Iter&);
687 template<> ListOfEdges::iterator eraseFromList(
688 ListOfEdges& rList,
const ListOfEdges::iterator& aIter)
690 return rList.erase(aIter);
692 template<> ListOfEdges::reverse_iterator eraseFromList(
693 ListOfEdges& rList,
const ListOfEdges::reverse_iterator& aIter)
695 return ListOfEdges::reverse_iterator(
696 rList.erase(std::prev(aIter.base())));
699 template<
int bPerformErase,
700 typename Iterator>
void processActiveEdges(
703 ListOfEdges& rActiveEdgeList,
704 SweepLineEvent
const & rCurrEvent,
705 VectorOfPolygons& rPolygonPool,
706 B2DPolyPolygon& rRes )
714 first = std::find_if(first, last,
715 [&rCurrRect](ActiveEdge& anEdge) {
return isSameRect(anEdge, rCurrRect); });
721 std::ptrdiff_t nCurrPolyIdx=-1;
724 if( nCurrPolyIdx == -1 )
725 nCurrPolyIdx=
first->getTargetPolygonIndex();
727 assert(nCurrPolyIdx != -1);
738 rPolygonPool.get(nCurrPolyIdx).intersect(
746 if( bPerformErase && (bExit || !nCount) )
747 first = eraseFromList(rActiveEdgeList,first);
759 template<
int bPerformErase>
void processActiveEdgesTopDown(
760 SweepLineEvent& rCurrEvent,
761 ListOfEdges& rActiveEdgeList,
762 VectorOfPolygons& rPolygonPool,
763 B2DPolyPolygon& rRes )
765 processActiveEdges<bPerformErase>(
766 rActiveEdgeList.
begin(),
767 rActiveEdgeList.
end(),
774 template<
int bPerformErase>
void processActiveEdgesBottomUp(
775 SweepLineEvent& rCurrEvent,
776 ListOfEdges& rActiveEdgeList,
777 VectorOfPolygons& rPolygonPool,
778 B2DPolyPolygon& rRes )
780 processActiveEdges<bPerformErase>(
781 rActiveEdgeList. rbegin(),
782 rActiveEdgeList. rend(),
789 enum{
NoErase=0, PerformErase=1 };
791 void handleStartingEdge( SweepLineEvent& rCurrEvent,
792 ListOfEdges& rActiveEdgeList,
793 VectorOfPolygons& rPolygonPool,
794 B2DPolyPolygon& rRes)
797 createActiveEdgesFromStartEvent( rActiveEdgeList,
801 if( rCurrEvent.getEdgeDirection() == SweepLineEvent::PROCEED_DOWN )
802 processActiveEdgesTopDown<NoErase>(
803 rCurrEvent, rActiveEdgeList, rPolygonPool, rRes);
805 processActiveEdgesBottomUp<NoErase>(
806 rCurrEvent, rActiveEdgeList, rPolygonPool, rRes);
809 void handleFinishingEdge( SweepLineEvent& rCurrEvent,
810 ListOfEdges& rActiveEdgeList,
811 VectorOfPolygons& rPolygonPool,
812 B2DPolyPolygon& rRes)
814 if( rCurrEvent.getEdgeDirection() == SweepLineEvent::PROCEED_DOWN )
815 processActiveEdgesTopDown<PerformErase>(
816 rCurrEvent, rActiveEdgeList, rPolygonPool, rRes);
818 processActiveEdgesBottomUp<PerformErase>(
819 rCurrEvent, rActiveEdgeList, rPolygonPool, rRes);
822 void handleSweepLineEvent( SweepLineEvent& rCurrEvent,
823 ListOfEdges& rActiveEdgeList,
824 VectorOfPolygons& rPolygonPool,
825 B2DPolyPolygon& rRes)
827 if( rCurrEvent.getEdgeType() == SweepLineEvent::STARTING_EDGE )
828 handleStartingEdge(rCurrEvent,rActiveEdgeList,rPolygonPool,rRes);
830 handleFinishingEdge(rCurrEvent,rActiveEdgeList,rPolygonPool,rRes);
837 const std::vector<B2VectorOrientation>& rOrientations)
858 setupSweepLineEventListFromRanges( aSweepLineEvents,
863 VectorOfPolygons aPolygonPool;
864 ListOfEdges aActiveEdgeList;
867 aPolygonPool.
reserve( rRanges.size() );
869 for (
auto& aSweepLineEvent : aSweepLineEvents)
870 handleSweepLineEvent(aSweepLineEvent, aActiveEdgeList, aPolygonPool, aRes);
const B2DRectangle * mpAssociatedRect
Associated rectangle.
ActiveEdge * mpLeadingRightEdge
Refers to the current leading edge element of this polygon, or NULL.
double mfPos
position of the event, in the direction of the line sweep
std::ptrdiff_t mnPolygonIdx
Index of the polygon this edge is currently involved with.
double mfInvariantCoord
The invariant coordinate value of this edge (e.g.
EdgeType meEdgeType
'upper' or 'lower' edge of original rectangle.
std::ptrdiff_t mnIdx
current index into vector pool
EdgeDirection meEdgeDirection
'left' or 'right'
std::vector< B2DPoint > maPoints
Container for the actual polygon points.
bool mbIsFinished
When true, this polygon is 'done', i.e. nothing must be added anymore.
void reserve(sal_uInt32 nCount)
A two-dimensional interval over doubles.
B2DPolyPolygon solveCrossovers(const B2DPolyPolygon &rCandidate, size_t *pPointLimit)
Solve all crossovers (aka self-intersections) in a polyPolygon.
@ Positive
mathematically positive oriented
B2DRange B2DRectangle
Alias name for interface clarity (not everybody is aware of the identity)
constexpr OUStringLiteral first
enumrange< T >::Iterator begin(enumrange< T >)
::std::vector< EventSharedPtr > VectorOfEvents
bool operator<(const wwFont &r1, const wwFont &r2)