📄 qregion_unix.cpp
字号:
int top; // Top of non-overlapping band int bot; // Bottom of non-overlapping band /* * Initialization: * set r1, r2, r1End and r2End appropriately, preserve the important * parts of the destination region until the end in case it's one of * the two source regions, then mark the "new" region empty, allocating * another array of rectangles for it to use. */ r1 = reg1->rects.data(); r2 = reg2->rects.data(); r1End = r1 + reg1->numRects; r2End = r2 + reg2->numRects; QVector<QRect> oldRects = dest.rects; dest.numRects = 0; /* * Allocate a reasonable number of rectangles for the new region. The idea * is to allocate enough so the individual functions don't need to * reallocate and copy the array, which is time consuming, yet we don't * have to worry about using too much memory. I hope to be able to * nuke the realloc() at the end of this function eventually. */ dest.rects.resize(qMax(reg1->numRects,reg2->numRects) * 2); /* * Initialize ybot and ytop. * In the upcoming loop, ybot and ytop serve different functions depending * on whether the band being handled is an overlapping or non-overlapping * band. * In the case of a non-overlapping band (only one of the regions * has points in the band), ybot is the bottom of the most recent * intersection and thus clips the top of the rectangles in that band. * ytop is the top of the next intersection between the two regions and * serves to clip the bottom of the rectangles in the current band. * For an overlapping band (where the two regions intersect), ytop clips * the top of the rectangles of both regions and ybot clips the bottoms. */ if (reg1->extents.top() < reg2->extents.top()) ybot = reg1->extents.top() - 1; else ybot = reg2->extents.top() - 1; /* * prevBand serves to mark the start of the previous band so rectangles * can be coalesced into larger rectangles. qv. miCoalesce, above. * In the beginning, there is no previous band, so prevBand == curBand * (curBand is set later on, of course, but the first band will always * start at index 0). prevBand and curBand must be indices because of * the possible expansion, and resultant moving, of the new region's * array of rectangles. */ prevBand = 0; do { curBand = dest.numRects; /* * This algorithm proceeds one source-band (as opposed to a * destination band, which is determined by where the two regions * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the * rectangle after the last one in the current band for their * respective regions. */ r1BandEnd = r1; while (r1BandEnd != r1End && r1BandEnd->top() == r1->top()) ++r1BandEnd; r2BandEnd = r2; while (r2BandEnd != r2End && r2BandEnd->top() == r2->top()) ++r2BandEnd; /* * First handle the band that doesn't intersect, if any. * * Note that attention is restricted to one band in the * non-intersecting region at once, so if a region has n * bands between the current position and the next place it overlaps * the other, this entire loop will be passed through n times. */ if (r1->top() < r2->top()) { top = qMax(r1->top(), ybot + 1); bot = qMin(r1->bottom(), r2->top() - 1); if (nonOverlap1Func != 0 && bot >= top) (*nonOverlap1Func)(dest, r1, r1BandEnd, top, bot); ytop = r2->top(); } else if (r2->top() < r1->top()) { top = qMax(r2->top(), ybot + 1); bot = qMin(r2->bottom(), r1->top() - 1); if (nonOverlap2Func != 0 && bot >= top) (*nonOverlap2Func)(dest, r2, r2BandEnd, top, bot); ytop = r1->top(); } else { ytop = r1->top(); } /* * If any rectangles got added to the region, try and coalesce them * with rectangles from the previous band. Note we could just do * this test in miCoalesce, but some machines incur a not * inconsiderable cost for function calls, so... */ if (dest.numRects != curBand) prevBand = miCoalesce(dest, prevBand, curBand); /* * Now see if we've hit an intersecting band. The two bands only * intersect if ybot >= ytop */ ybot = qMin(r1->bottom(), r2->bottom()); curBand = dest.numRects; if (ybot >= ytop) (*overlapFunc)(dest, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot); if (dest.numRects != curBand) prevBand = miCoalesce(dest, prevBand, curBand); /* * If we've finished with a band (y2 == ybot) we skip forward * in the region to the next band. */ if (r1->bottom() == ybot) r1 = r1BandEnd; if (r2->bottom() == ybot) r2 = r2BandEnd; } while (r1 != r1End && r2 != r2End); /* * Deal with whichever region still has rectangles left. */ curBand = dest.numRects; if (r1 != r1End) { if (nonOverlap1Func != 0) { do { r1BandEnd = r1; while (r1BandEnd < r1End && r1BandEnd->top() == r1->top()) ++r1BandEnd; (*nonOverlap1Func)(dest, r1, r1BandEnd, qMax(r1->top(), ybot + 1), r1->bottom()); r1 = r1BandEnd; } while (r1 != r1End); } } else if ((r2 != r2End) && (nonOverlap2Func != 0)) { do { r2BandEnd = r2; while (r2BandEnd < r2End && r2BandEnd->top() == r2->top()) ++r2BandEnd; (*nonOverlap2Func)(dest, r2, r2BandEnd, qMax(r2->top(), ybot + 1), r2->bottom()); r2 = r2BandEnd; } while (r2 != r2End); } if (dest.numRects != curBand) (void)miCoalesce(dest, prevBand, curBand); /* * A bit of cleanup. To keep regions from growing without bound, * we shrink the array of rectangles to match the new number of * rectangles in the region. * * Only do this stuff if the number of rectangles allocated is more than * twice the number of rectangles in the region (a simple optimization). */ if (qMax(4, dest.numRects) < (dest.rects.size() >> 1)) dest.rects.resize(dest.numRects);}/*====================================================================== * Region Union *====================================================================*//*- *----------------------------------------------------------------------- * miUnionNonO -- * Handle a non-overlapping band for the union operation. Just * Adds the rectangles into the region. Doesn't have to check for * subsumption or anything. * * Results: * None. * * Side Effects: * dest.numRects is incremented and the final rectangles overwritten * with the rectangles we're passed. * *----------------------------------------------------------------------- */static void miUnionNonO(register QRegionPrivate &dest, register const QRect *r, const QRect *rEnd, register int y1, register int y2){ register QRect *pNextRect; pNextRect = dest.rects.data() + dest.numRects; Q_ASSERT(y1 <= y2); while (r != rEnd) { Q_ASSERT(r->left() <= r->right()); MEMCHECK(dest, pNextRect, dest.rects) pNextRect->setCoords(r->left(), y1, r->right(), y2); dest.numRects++; ++pNextRect; ++r; }}/*- *----------------------------------------------------------------------- * miUnionO -- * Handle an overlapping band for the union operation. Picks the * left-most rectangle each time and merges it into the region. * * Results: * None. * * Side Effects: * Rectangles are overwritten in dest.rects and dest.numRects will * be changed. * *----------------------------------------------------------------------- */static void miUnionO(register QRegionPrivate &dest, register const QRect *r1, const QRect *r1End, register const QRect *r2, const QRect *r2End, register int y1, register int y2){ register QRect *pNextRect; pNextRect = dest.rects.data() + dest.numRects;#define MERGERECT(r) \ if ((dest.numRects != 0) && \ (pNextRect[-1].top() == y1) && \ (pNextRect[-1].bottom() == y2) && \ (pNextRect[-1].right() >= r->left()-1)) { \ if (pNextRect[-1].right() < r->right()) { \ pNextRect[-1].setRight(r->right()); \ dest.updateInnerRect(pNextRect[-1]); \ Q_ASSERT(pNextRect[-1].left() <= pNextRect[-1].right()); \ } \ } else { \ MEMCHECK(dest, pNextRect, dest.rects) \ pNextRect->setCoords(r->left(), y1, r->right(), y2); \ dest.updateInnerRect(*pNextRect); \ dest.numRects++; \ pNextRect++; \ } \ r++; Q_ASSERT(y1 <= y2); while (r1 != r1End && r2 != r2End) { if (r1->left() < r2->left()) { MERGERECT(r1) } else { MERGERECT(r2) } } if (r1 != r1End) { do { MERGERECT(r1) } while (r1 != r1End); } else { while (r2 != r2End) { MERGERECT(r2) } }}static void UnionRegion(const QRegionPrivate *reg1, const QRegionPrivate *reg2, QRegionPrivate &dest){ Q_ASSERT(!isEmpty(reg1) && !isEmpty(reg2)); Q_ASSERT(!reg1->contains(*reg2)); Q_ASSERT(!reg2->contains(*reg1)); Q_ASSERT(!EqualRegion(reg1, reg2)); Q_ASSERT(!reg1->canAppend(reg2)); Q_ASSERT(!reg2->canAppend(reg1)); if (reg1->innerArea > reg2->innerArea) { dest.innerArea = reg1->innerArea; dest.innerRect = reg1->innerRect; } else { dest.innerArea = reg2->innerArea; dest.innerRect = reg2->innerRect; } miRegionOp(dest, reg1, reg2, miUnionO, miUnionNonO, miUnionNonO); dest.extents.setCoords(qMin(reg1->extents.left(), reg2->extents.left()), qMin(reg1->extents.top(), reg2->extents.top()), qMax(reg1->extents.right(), reg2->extents.right()), qMax(reg1->extents.bottom(), reg2->extents.bottom()));}/*====================================================================== * Region Subtraction *====================================================================*//*- *----------------------------------------------------------------------- * miSubtractNonO -- * Deal with non-overlapping band for subtraction. Any parts from * region 2 we discard. Anything from region 1 we add to the region. * * Results: * None. * * Side Effects: * dest may be affected. * *----------------------------------------------------------------------- */static void miSubtractNonO1(register QRegionPrivate &dest, register const QRect *r, const QRect *rEnd, register int y1, register int y2){ register QRect *pNextRect; pNextRect = dest.rects.data() + dest.numRects; Q_ASSERT(y1<=y2); while (r != rEnd) { Q_ASSERT(r->left() <= r->right()); MEMCHECK(dest, pNextRect, dest.rects) pNextRect->setCoords(r->left(), y1, r->right(), y2); ++dest.numRects; ++pNextRect; ++r; }}/*- *----------------------------------------------------------------------- * miSubtractO -- * Overlapping band subtraction. x1 is the left-most point not yet * checked. * * Results: * None. * * Side Effects: * dest may have rectangles added to it. * *----------------------------------------------------------------------- */static void miSubtractO(register QRegionPrivate &dest, register const QRect *r1, const QRect *r1End, register const QRect *r2, const QRect *r2End, register int y1, register int y2){ register QRect *pNextRect; register int x1; x1 = r1->left(); Q_ASSERT(y1 <= y2); pNextRect = dest.rects.data() + dest.numRects; while (r1 != r1End && r2 != r2End) { if (r2->right() < x1) { /* * Subtrahend missed the boat: go to next subtrahend. */ ++r2; } else if (r2->left() <= x1) { /* * Subtrahend precedes minuend: nuke left edge of minuend. */ x1 = r2->right() + 1; if (x1 > r1->right()) { /* * Minuend completely covered: advance to next minuend and
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -