Theclassdefinesanelementofthesweeplinelist.The sweepline'spositionjumpsinstepsdefinedbythe coordinatesofthesortedSweepLineEvententries.
*/ class SweepLineEvent
{ public: /** The two possible sweep line rectangle edges differ by onecoordinatevalue-thestartingedgehasthe lower,thefinishingedgethehighervalue.
*/ enum EdgeType { /// edge with lower coordinate value
STARTING_EDGE=0, /// edge with higher coordinate value
FINISHING_EDGE=1
};
/** The two possible sweep line directions
*/ enum EdgeDirection {
PROCEED_UP=0,
PROCEED_DOWN=1
};
/// Add point to the end of the existing points void append( const B2DPoint& rPoint )
{
OSL_PRECOND( maPoints.empty() ||
maPoints.back().getX() == rPoint.getX() ||
maPoints.back().getY() == rPoint.getY(), "ImplPolygon::append(): added point violates 90 degree line angle constraint!" );
if( isHittingOurTail )
finish(rRes); // just finish. no fuss. else
{ // temp poly hits final left edge const std::ptrdiff_t nTmpIdx=rActiveEdge.getTargetPolygonIndex();
ImplPolygon& rTmp=rPolygonPool.get(nTmpIdx);
// active edge's polygon has points // already. ours need to go in front of them.
maPoints.insert(maPoints.end(),
rTmp.maPoints.begin(),
rTmp.maPoints.end());
// adjust leading edges, we're switching the polygon
ActiveEdge* const pFarEdge=rTmp.mpLeadingRightEdge;
// so "this" is done - need new polygon to collect // further points const std::ptrdiff_t nIdxNewPolygon=rPolygonPool.alloc();
rPolygonPool.get(nIdxNewPolygon).setPolygonPoolIndex(nIdxNewPolygon);
rPolygonPool.get(nIdxNewPolygon).append(rIntersectionPoint);
// active edge's polygon has points // already. ours need to go in front of them.
maPoints.insert(maPoints.end(),
rTmp.maPoints.begin(),
rTmp.maPoints.end());
/// True when sweep line hits our own active edge staticbool metOwnEdge(SweepLineEvent const & rEvent,
ActiveEdge const & rActiveEdge)
{ constbool bHitOwnEdge=&rEvent.getRect() == &rActiveEdge.getRect(); return bHitOwnEdge;
}
/// Retrieve B2DPolygon from this object
B2DPolygon getPolygon() const
{
B2DPolygon aRes; for (autoconst& aPoint : maPoints)
aRes.append(aPoint, 1);
aRes.setClosed( true ); return aRes;
}
/** Finish this polygon, push to result set.
*/ void finish(B2DPolyPolygon& rRes)
{
OSL_PRECOND( maPoints.empty() ||
maPoints.front().getX() == maPoints.back().getX() ||
maPoints.front().getY() == maPoints.back().getY(), "ImplPolygon::finish(): first and last point violate 90 degree line angle constraint!" );
/** Refers to the current leading edge element of this polygon,orNULL.Theleadingedgedenotesthe'front' ofthepolygonvertexsequence,i.e.thecoordinates atthepolygon'sleadingedgearereturnedfrom maPoints.front()
*/
ActiveEdge* mpLeadingRightEdge;
/// current index into vector pool
std::ptrdiff_t mnIdx;
/// Container for the actual polygon points
std::vector<B2DPoint> maPoints;
/// When true, this polygon is 'done', i.e. nothing must be added anymore. bool mbIsFinished;
};
/** Init sweep line event list
Thismethodfillstheeventlistwiththesweepline eventsgeneratedfromtheinputrectangles,andsortsthem withincreasingx.
*/ void setupSweepLineEventListFromRanges( VectorOfEvents& o_rEventVector, const std::vector<B2DRange>& rRanges, const std::vector<B2VectorOrientation>& rOrientations )
{ // we need exactly 2*rectVec.size() events: one for the // left, and one for the right edge of each rectangle
o_rEventVector.clear();
o_rEventVector.reserve( 2*rRanges.size() );
// generate events // ===============
// first pass: add all left edges in increasing order
std::vector<B2DRange>::const_iterator aCurrRect=rRanges.begin();
std::vector<B2VectorOrientation>::const_iterator aCurrOrientation=rOrientations.begin(); const std::vector<B2DRange>::const_iterator aEnd=rRanges.end(); const std::vector<B2VectorOrientation>::const_iterator aEndOrientation=rOrientations.end(); while( aCurrRect != aEnd && aCurrOrientation != aEndOrientation )
{ const B2DRectangle& rCurrRect( *aCurrRect++ );
// since we use stable_sort, the order of events with the // same x value will not change. The elaborate two-pass // add above thus ensures, that for each two rectangles // with similar left and right x coordinates, the // rectangle whose left event comes first will have its // right event come last. This is advantageous for the // clip algorithm below, see handleRightEdgeCrossing().
// start event - new rect starts here, needs polygon to // collect points into const std::ptrdiff_t nIdxPolygon=io_rPolygonPool.alloc();
io_rPolygonPool.get(nIdxPolygon).setPolygonPoolIndex(nIdxPolygon);
// furthermore, have to respect a special tie-breaking // rule here, for edges which share the same y value: // newly added upper edges must be inserted _before_ any // other edge with the same y value, and newly added lower // edges must be _after_ all other edges with the same // y. This ensures that the left vertical edge processing // below encounters the upper edge of the current rect // first, and the lower edge last, which automatically // starts and finishes this rect correctly (as only then, // the polygon will have their associated active edges // set). constdouble nMinY( rRect.getMinY() ); constdouble nMaxY( rRect.getMaxY() );
ListOfEdges::iterator aCurr( io_rEdgeList.begin() ); const ListOfEdges::iterator aEnd ( io_rEdgeList.end() ); while( aCurr != aEnd )
{ constdouble nCurrY( aCurr->getInvariantCoord() );
if( nCurrY >= nMinY &&
aNewEdges.size() == 2 ) // only add, if not yet done.
{ // insert upper edge _before_ aCurr. Thus, it will // be the first entry for a range of equal y // values. Using splice here, since we hold // references to the moved list element!
io_rEdgeList.splice( aCurr,
aNewEdges,
aNewEdges.begin() );
}
if( nCurrY > nMaxY )
{ // insert lower edge _before_ aCurr. Thus, it will // be the last entry for a range of equal y values // (aCurr is the first entry strictly larger than // nMaxY). Using splice here, since we hold // references to the moved list element!
io_rEdgeList.splice( aCurr,
aNewEdges,
aNewEdges.begin() ); // done with insertion, can early-exit here. return;
}
++aCurr;
}
// append remainder of aNewList (might still contain 2 or // 1 elements, depending of the contents of io_rEdgeList).
io_rEdgeList.splice( aCurr,
aNewEdges );
}
// fast-forward to rCurrEvent's first active edge (holds // for both starting and finishing sweep line events, a // rect is regarded _outside_ any rects whose events have // started earlier
first = std::find_if(first, last,
[&rCurrRect](ActiveEdge& anEdge) { return isSameRect(anEdge, rCurrRect); });
void handleStartingEdge( SweepLineEvent& rCurrEvent,
ListOfEdges& rActiveEdgeList,
VectorOfPolygons& rPolygonPool,
B2DPolyPolygon& rRes)
{ // inject two new active edges for rect
createActiveEdgesFromStartEvent( rActiveEdgeList,
rPolygonPool,
rCurrEvent );
namespace utils
{
B2DPolyPolygon solveCrossovers(const std::vector<B2DRange>& rRanges, const std::vector<B2VectorOrientation>& rOrientations)
{ // sweep-line algorithm to generate a poly-polygon // from a bunch of rectangles // ===============================================
// This algorithm uses the well-known sweep line // concept, explained in every good text book about // computational geometry.
// We start with creating two structures for every // rectangle, one representing the left x coordinate, // one representing the right x coordinate (and both // referencing the original rect). These structs are // sorted with increasing x coordinates.
// Then, we start processing the resulting list from // the beginning. Every entry in the list defines a // point in time of the line sweeping from left to // right across all rectangles.
VectorOfEvents aSweepLineEvents;
setupSweepLineEventListFromRanges( aSweepLineEvents,
rRanges,
rOrientations );
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.