// Each band contains all rectangles between upper and lower border. // For Union, Intersect, Xor and Exclude operations rectangles of // equal height are evaluated. The borders of the bands should always // be chosen such that this is possible.
// If possible, rectangles within the bands are condensed.
// When converting polygons all points of the polygon are registered // in the individual bands (for each band they are stored as // points in a list). After registration of these points they are // converted to rectangles and the points in the list are deleted.
// copy all elements of the list with separations
ImplRegionBandSep* pNewSep;
ImplRegionBandSep* pPrevSep = nullptr;
ImplRegionBandSep* pSep = rRegionBand.mpFirstSep; while ( pSep )
{ // create new and copy data
pNewSep = new ImplRegionBandSep;
pNewSep->mnXLeft = pSep->mnXLeft;
pNewSep->mnXRight = pSep->mnXRight;
pNewSep->mbRemoved = pSep->mbRemoved;
pNewSep->mpNextSep = nullptr; if ( pSep == rRegionBand.mpFirstSep )
mpFirstSep = pNewSep; else
pPrevSep->mpNextSep = pNewSep;
// delete elements of the list
ImplRegionBandSep* pSep = mpFirstSep; while ( pSep )
{
ImplRegionBandSep* pTempSep = pSep->mpNextSep; delete pSep;
pSep = pTempSep;
}
// delete elements of the list
ImplRegionBandPoint* pPoint = mpFirstBandPoint; while ( pPoint )
{
ImplRegionBandPoint* pTempPoint = pPoint->mpNextBandPoint; delete pPoint;
pPoint = pTempPoint;
}
}
// generate separations from lines and process union with existing // separations
void ImplRegionBand::ProcessPoints()
{ // check Pointlist
ImplRegionBandPoint* pRegionBandPoint = mpFirstBandPoint; while ( pRegionBandPoint )
{ // within list? if ( pRegionBandPoint->mpNextBandPoint )
{ // start/stop? if ( pRegionBandPoint->mbEndPoint && pRegionBandPoint->mpNextBandPoint->mbEndPoint )
{ // same direction? -> remove next point! if ( pRegionBandPoint->meLineType == pRegionBandPoint->mpNextBandPoint->meLineType )
{
ImplRegionBandPoint* pSaveRegionBandPoint = pRegionBandPoint->mpNextBandPoint;
pRegionBandPoint->mpNextBandPoint = pRegionBandPoint->mpNextBandPoint->mpNextBandPoint; delete pSaveRegionBandPoint;
}
}
}
// continue with next element in the list
pRegionBandPoint = pRegionBandPoint->mpNextBandPoint;
}
// look if line already touched the band
ImplRegionBandPoint* pRegionBandPoint = mpFirstBandPoint;
ImplRegionBandPoint* pLastTestedRegionBandPoint = nullptr; while( pRegionBandPoint )
{ if ( pRegionBandPoint->mnLineId == nLineId )
{ if ( bEndPoint )
{ if( !pRegionBandPoint->mbEndPoint )
{ // remove old band point if( !mpFirstBandPoint->mpNextBandPoint )
{ // if we've only got one point => replace first point
pRegionBandPoint->mnX = nX;
pRegionBandPoint->mbEndPoint = true; returntrue;
} else
{ // remove current point if( !pLastTestedRegionBandPoint )
{ // remove and delete old first point
ImplRegionBandPoint* pSaveBandPoint = mpFirstBandPoint;
mpFirstBandPoint = mpFirstBandPoint->mpNextBandPoint; delete pSaveBandPoint;
} else
{ // remove and delete current band point
pLastTestedRegionBandPoint->mpNextBandPoint = pRegionBandPoint->mpNextBandPoint; delete pRegionBandPoint;
}
break;
}
}
} else returnfalse;
}
// use next element
pLastTestedRegionBandPoint = pRegionBandPoint;
pRegionBandPoint = pRegionBandPoint->mpNextBandPoint;
}
// search appropriate position and insert point into the list
ImplRegionBandPoint* pNewRegionBandPoint;
pRegionBandPoint = mpFirstBandPoint;
pLastTestedRegionBandPoint = nullptr; while ( pRegionBandPoint )
{ // new point completely left? -> insert as first point if ( nX <= pRegionBandPoint->mnX )
{
pNewRegionBandPoint = new ImplRegionBandPoint;
pNewRegionBandPoint->mnX = nX;
pNewRegionBandPoint->mnLineId = nLineId;
pNewRegionBandPoint->mbEndPoint = bEndPoint;
pNewRegionBandPoint->meLineType = eLineType;
pNewRegionBandPoint->mpNextBandPoint = pRegionBandPoint;
// connections to the new point if ( !pLastTestedRegionBandPoint )
mpFirstBandPoint = pNewRegionBandPoint; else
pLastTestedRegionBandPoint->mpNextBandPoint = pNewRegionBandPoint;
returntrue;
}
// use next element
pLastTestedRegionBandPoint = pRegionBandPoint;
pRegionBandPoint = pRegionBandPoint->mpNextBandPoint;
}
// not inserted -> add to the end of the list
pNewRegionBandPoint = new ImplRegionBandPoint;
pNewRegionBandPoint->mnX = nX;
pNewRegionBandPoint->mnLineId = nLineId;
pNewRegionBandPoint->mbEndPoint = bEndPoint;
pNewRegionBandPoint->meLineType = eLineType;
pNewRegionBandPoint->mpNextBandPoint = nullptr;
// connections to the new point
pLastTestedRegionBandPoint->mpNextBandPoint = pNewRegionBandPoint;
// new separation overlapping from left? -> extend boundary if ( (nXRight >= pSep->mnXLeft) && (nXLeft <= pSep->mnXLeft) )
pSep->mnXLeft = nXLeft;
// new separation overlapping from right? -> extend boundary if ( (nXLeft <= pSep->mnXRight) && (nXRight > pSep->mnXRight) )
{
pSep->mnXRight = nXRight; break;
}
// not inserted, but last element? -> add to the end of the list if ( !pSep->mpNextSep && (nXLeft > pSep->mnXRight) )
{
pNewSep = new ImplRegionBandSep;
pNewSep->mnXLeft = nXLeft;
pNewSep->mnXRight = nXRight;
pNewSep->mbRemoved = false;
// band empty? -> nothing to do if ( !mpFirstSep ) return;
// process real intersection
ImplRegionBandSep* pSep = mpFirstSep; while ( pSep )
{ // new separation completely outside? -> remove separation if ( (nXRight < pSep->mnXLeft) || (nXLeft > pSep->mnXRight) ) // will be removed from the optimizer
pSep->mbRemoved = true;
// new separation overlapping from left? -> reduce right boundary if ( (nXLeft <= pSep->mnXLeft) &&
(nXRight <= pSep->mnXRight) &&
(nXRight >= pSep->mnXLeft) )
pSep->mnXRight = nXRight;
// new separation overlapping from right? -> reduce right boundary if ( (nXLeft >= pSep->mnXLeft) &&
(nXLeft <= pSep->mnXRight) &&
(nXRight >= pSep->mnXRight) )
pSep->mnXLeft = nXLeft;
// new separation within the actual one? -> reduce both boundaries if ( (nXLeft >= pSep->mnXLeft) && (nXRight <= pSep->mnXRight) )
{
pSep->mnXRight = nXRight;
pSep->mnXLeft = nXLeft;
}
// band empty? -> nothing to do if ( !mpFirstSep ) return;
// process real exclusion
ImplRegionBandSep* pNewSep;
ImplRegionBandSep* pPrevSep = nullptr;
ImplRegionBandSep* pSep = mpFirstSep; while ( pSep )
{ bool bSepProcessed = false;
// new separation completely overlapping? -> remove separation if ( (nXLeft <= pSep->mnXLeft) && (nXRight >= pSep->mnXRight) )
{ // will be removed from the optimizer
pSep->mbRemoved = true;
bSepProcessed = true;
}
// new separation overlapping from left? -> reduce boundary if ( !bSepProcessed )
{ if ( (nXRight >= pSep->mnXLeft) && (nXLeft <= pSep->mnXLeft) )
{
pSep->mnXLeft = nXRight+1;
bSepProcessed = true;
}
}
// new separation overlapping from right? -> reduce boundary if ( !bSepProcessed )
{ if ( (nXLeft <= pSep->mnXRight) && (nXRight > pSep->mnXRight) )
{
pSep->mnXRight = nXLeft-1;
bSepProcessed = true;
}
}
// new separation within the actual one? -> reduce boundary // and add new entry for reminder if ( !bSepProcessed )
{ if ( (nXLeft >= pSep->mnXLeft) && (nXRight <= pSep->mnXRight) )
{
pNewSep = new ImplRegionBandSep;
pNewSep->mnXLeft = pSep->mnXLeft;
pNewSep->mnXRight = nXLeft-1;
pNewSep->mbRemoved = false;
pSep->mnXLeft = nXRight+1;
// connections from the new separation
pNewSep->mpNextSep = pSep;
// connections to the new separation if ( pSep == mpFirstSep )
mpFirstSep = pNewSep; else
pPrevSep->mpNextSep = pNewSep;
}
}
// In general, we can distinguish 11 cases of intersection // (details below). The old implementation explicitly handled 7 // cases (numbered in the order of appearance, use CVS to get your // hands on the old version), therefore, I've sticked to that // order, and added four more cases. The code below references // those numbers via #1, #2, etc.
// Num Mnem newX:oldX newY:oldY Description Result Can quit?
// #1 Empty band - - The band is empty, thus, simply add new bandSep just add Yes
// #2 apart - - The rectangles are disjunct, add new one as is just add Yes
// #3 atop == == The rectangles are _exactly_ the same, remove existing just remove Yes
// #4 around < > The new rectangle extends the old to both sides intersect No
// #5 left < < The new rectangle is left of the old (but intersects) intersect Yes
// #5b left-atop < == The new is left of the old, and coincides on the right intersect Yes
// #6 right > > The new is right of the old (but intersects) intersect No
// #6b right-atop == > The new is right of the old, and coincides on the left intersect No
// #7 inside > < The new is fully inside the old intersect Yes
// #8 inside-right > == The new is fully inside the old, coincides on the right intersect Yes
// #9 inside-left == < The new is fully inside the old, coincides on the left intersect Yes
// Then, to correctly perform XOr, the segment that's switched off // (i.e. the overlapping part of the old and the new segment) must // be extended by one pixel value at each border: // 1 1 // 0 4 0 4 // 111100000001111
// Clearly, the leading band sep now goes from 0 to 3, and the // trailing band sep from 11 to 14. This mimics the xor look of a // bitmap operation.
// band empty? -> add element if ( !mpFirstSep )
{
mpFirstSep = new ImplRegionBandSep;
mpFirstSep->mnXLeft = nXLeft;
mpFirstSep->mnXRight = nXRight;
mpFirstSep->mbRemoved = false;
mpFirstSep->mpNextSep = nullptr; return;
}
// process real xor
ImplRegionBandSep* pNewSep;
ImplRegionBandSep* pPrevSep = nullptr;
ImplRegionBandSep* pSep = mpFirstSep;
// did the current segment actually touch the new rect? If // not, skip all comparisons, go on, loop and try to find // intersecting bandSep if( nXLeft <= nOldRight )
{ if( nXRight < nOldLeft )
{ // #2
pPrevSep = nullptr; // do not run accidentally into the "right" case when breaking the loop break;
} elseif( nXLeft == nOldLeft && nXRight != nOldRight )
{ // # 6b, 9
// cannot break here, simply mark segment as removed, // and go on with adapted nXLeft/nXRight
pSep->mbRemoved = true;
} else
{
pSep->mnXLeft = nXRight+1; // 9
pPrevSep = nullptr; // do not run accidentally into the "right" case when breaking the loop break;
}
} else// if( nXLeft != nOldLeft && nXRight != nOldRight ) follows automatically
{ // #4,5,6,7
SAL_WARN_IF( nXLeft == nOldLeft || nXRight == nOldRight, "vcl", "ImplRegionBand::XOr(): Case 4,5,6,7 expected all coordinates to be not equal!" );
// but since we generally don't have to care whether // it's 4 or 6 (only that we must not stop processing // here), condensed that in such a way that only the // coordinates get shuffled into correct ordering.
// now, nOldLeft<nXLeft<=nOldRight<nXRight always // holds. Note that we need the nXLeft<=nOldRight here, as // the intersection part might be only one pixel (original // nXLeft==nXRight)
SAL_WARN_IF( nOldLeft==nXLeft || nXLeft>nOldRight || nOldRight>=nXRight, "vcl", "ImplRegionBand::XOr(): Case 4,5,6,7 expected coordinates to be ordered now!" );
// Create a copy of the given band (we tell the constructor to copy the points together // with the seps.)
ImplRegionBand* pLowerBand = new ImplRegionBand(*this, false);
// Insert new band into list of bands.
pLowerBand->mpNextBand = mpNextBand;
mpNextBand = pLowerBand;
pLowerBand->mpPrevBand = this; if (pLowerBand->mpNextBand != nullptr)
pLowerBand->mpNextBand->mpPrevBand = pLowerBand;
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.