📄 devrgn.c
字号:
if (pRect->left < pExtents->left)
pExtents->left = pRect->left;
if (pRect->right > pExtents->right)
pExtents->right = pRect->right;
pRect++;
}
}
/***********************************************************************
* REGION_Coalesce
*
* Attempt to merge the rects in the current band with those in the
* previous one. Used only by REGION_RegionOp.
*
* Results:
* The new index for the previous band.
*
* Side Effects:
* If coalescing takes place:
* - rectangles in the previous band will have their bottom fields
* altered.
* - pReg->numRects will be decreased.
*
*/
static MWCOORD
REGION_Coalesce (
MWCLIPREGION *pReg, /* Region to coalesce */
MWCOORD prevStart, /* Index of start of previous band */
MWCOORD curStart /* Index of start of current band */
) {
MWRECT *pPrevRect; /* Current rect in previous band */
MWRECT *pCurRect; /* Current rect in current band */
MWRECT *pRegEnd; /* End of region */
MWCOORD curNumRects; /* Number of rectangles in current band */
MWCOORD prevNumRects; /* Number of rectangles in previous band */
MWCOORD bandtop; /* top coordinate for current band */
pRegEnd = &pReg->rects[pReg->numRects];
pPrevRect = &pReg->rects[prevStart];
prevNumRects = curStart - prevStart;
/*
* Figure out how many rectangles are in the current band. Have to do
* this because multiple bands could have been added in REGION_RegionOp
* at the end when one region has been exhausted.
*/
pCurRect = &pReg->rects[curStart];
bandtop = pCurRect->top;
for (curNumRects = 0;
(pCurRect != pRegEnd) && (pCurRect->top == bandtop);
curNumRects++)
{
pCurRect++;
}
if (pCurRect != pRegEnd)
{
/*
* If more than one band was added, we have to find the start
* of the last band added so the next coalescing job can start
* at the right place... (given when multiple bands are added,
* this may be pointless -- see above).
*/
pRegEnd--;
while (pRegEnd[-1].top == pRegEnd->top)
{
pRegEnd--;
}
curStart = pRegEnd - pReg->rects;
pRegEnd = pReg->rects + pReg->numRects;
}
if ((curNumRects == prevNumRects) && (curNumRects != 0)) {
pCurRect -= curNumRects;
/*
* The bands may only be coalesced if the bottom of the previous
* matches the top scanline of the current.
*/
if (pPrevRect->bottom == pCurRect->top)
{
/*
* Make sure the bands have rects in the same places. This
* assumes that rects have been added in such a way that they
* cover the most area possible. I.e. two rects in a band must
* have some horizontal space between them.
*/
do
{
if ((pPrevRect->left != pCurRect->left) ||
(pPrevRect->right != pCurRect->right))
{
/*
* The bands don't line up so they can't be coalesced.
*/
return (curStart);
}
pPrevRect++;
pCurRect++;
prevNumRects -= 1;
} while (prevNumRects != 0);
pReg->numRects -= curNumRects;
pCurRect -= curNumRects;
pPrevRect -= curNumRects;
/*
* The bands may be merged, so set the bottom of each rect
* in the previous band to that of the corresponding rect in
* the current band.
*/
do
{
pPrevRect->bottom = pCurRect->bottom;
pPrevRect++;
pCurRect++;
curNumRects -= 1;
} while (curNumRects != 0);
/*
* If only one band was added to the region, we have to backup
* curStart to the start of the previous band.
*
* If more than one band was added to the region, copy the
* other bands down. The assumption here is that the other bands
* came from the same region as the current one and no further
* coalescing can be done on them since it's all been done
* already... curStart is already in the right place.
*/
if (pCurRect == pRegEnd)
{
curStart = prevStart;
}
else
{
do
{
*pPrevRect++ = *pCurRect++;
} while (pCurRect != pRegEnd);
}
}
}
return (curStart);
}
/***********************************************************************
* REGION_RegionOp
*
* Apply an operation to two regions. Called by GdUnion,
* GdXor, GdSubtract, GdIntersect...
*
* Results:
* None.
*
* Side Effects:
* The new region is overwritten.
*
* Notes:
* The idea behind this function is to view the two regions as sets.
* Together they cover a rectangle of area that this function divides
* into horizontal bands where points are covered only by one region
* or by both. For the first case, the nonOverlapFunc is called with
* each the band and the band's upper and lower extents. For the
* second, the overlapFunc is called to process the entire band. It
* is responsible for clipping the rectangles in the band, though
* this function provides the boundaries.
* At the end of each band, the new region is coalesced, if possible,
* to reduce the number of rectangles in the region.
*
*/
static void
REGION_RegionOp(
MWCLIPREGION *newReg, /* Place to store result */
MWCLIPREGION *reg1, /* First region in operation */
MWCLIPREGION *reg2, /* 2nd region in operation */
void (*overlapFunc)(), /* Function to call for over-lapping bands */
void (*nonOverlap1Func)(), /* Function to call for non-overlapping bands in region 1 */
void (*nonOverlap2Func)() /* Function to call for non-overlapping bands in region 2 */
) {
MWRECT *r1; /* Pointer into first region */
MWRECT *r2; /* Pointer into 2d region */
MWRECT *r1End; /* End of 1st region */
MWRECT *r2End; /* End of 2d region */
MWCOORD ybot; /* Bottom of intersection */
MWCOORD ytop; /* Top of intersection */
MWRECT *oldRects; /* Old rects for newReg */
MWCOORD prevBand; /* Index of start of
* previous band in newReg */
MWCOORD curBand; /* Index of start of current
* band in newReg */
MWRECT *r1BandEnd; /* End of current band in r1 */
MWRECT *r2BandEnd; /* End of current band in r2 */
MWCOORD top; /* Top of non-overlapping band */
MWCOORD 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;
r2 = reg2->rects;
r1End = r1 + reg1->numRects;
r2End = r2 + reg2->numRects;
/*
* newReg may be one of the src regions so we can't empty it. We keep a
* note of its rects pointer (so that we can free them later), preserve its
* extents and simply set numRects to zero.
*/
oldRects = newReg->rects;
newReg->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 Xrealloc() at the end of this function eventually.
*/
newReg->size = MWMAX(reg1->numRects,reg2->numRects) * 2;
if (! (newReg->rects = malloc( sizeof(MWRECT) * newReg->size )))
{
newReg->size = 0;
return;
}
/*
* 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;
else
ybot = reg2->extents.top;
/*
* 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 = newReg->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 = MWMAX(r1->top,ybot);
bot = MWMIN(r1->bottom,r2->top);
if ((top != bot) && (nonOverlap1Func != (void (*)())NULL))
{
(* nonOverlap1Func) (newReg, r1, r1BandEnd, top, bot);
}
ytop = r2->top;
}
else if (r2->top < r1->top)
{
top = MWMAX(r2->top,ybot);
bot = MWMIN(r2->bottom,r1->top);
if ((top != bot) && (nonOverlap2Func != (void (*)())NULL))
{
(* nonOverlap2Func) (newReg, 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 (newReg->numRects != curBand)
{
prevBand = REGION_Coalesce (newReg, prevBand, curBand);
}
/*
* Now see if we've hit an intersecting band. The two bands only
* intersect if ybot > ytop
*/
ybot = MWMIN(r1->bottom, r2->bottom);
curBand = newReg->numRects;
if (ybot > ytop)
{
(* overlapFunc) (newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot);
}
if (newReg->numRects != curBand)
{
prevBand = REGION_Coalesce (newReg, prevBand, curBand);
}
/*
* If we've finished with a band (bottom == 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 = newReg->numRects;
if (r1 != r1End)
{
if (nonOverlap1Func != (void (*)())NULL)
{
do
{
r1BandEnd = r1;
while ((r1BandEnd < r1End) && (r1BandEnd->top == r1->top))
{
r1BandEnd++;
}
(* nonOverlap1Func) (newReg, r1, r1BandEnd,
MWMAX(r1->top,ybot), r1->bottom);
r1 = r1BandEnd;
} while (r1 != r1End);
}
}
else if ((r2 != r2End) && (nonOverlap2Func != (void (*)())NULL))
{
do
{
r2BandEnd = r2;
while ((r2BandEnd < r2End) && (r2BandEnd->top == r2->top))
{
r2BandEnd++;
}
(* nonOverlap2Func) (newReg, r2, r2BandEnd,
MWMAX(r2->top,ybot), r2->bottom);
r2 = r2BandEnd;
} while (r2 != r2End);
}
if (newReg->numRects != curBand)
{
(void) REGION_Coalesce (newReg, 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. This never goes to 0, however...
*
* 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 (newReg->numRects < (newReg->size >> 1))
{
if (REGION_NOT_EMPTY(newReg))
{
MWRECT *prev_rects = newReg->rects;
newReg->size = newReg->numRects;
newReg->rects = realloc( newReg->rects, sizeof(MWRECT) * newReg->size );
if (! newReg->rects)
newReg->rects = prev_rects;
}
else
{
/*
* No point in doing the extra work involved in an Xrealloc if
* the region is empty
*/
newReg->size = 1;
free( newReg->rects );
newReg->rects = malloc( sizeof(MWRECT) );
}
}
free( oldRects );
}
/***********************************************************************
* Region Intersection
***********************************************************************/
/***********************************************************************
* REGION_IntersectO
*
* Handle an overlapping band for REGION_Intersect.
*
* Results:
* None.
*
* Side Effects:
* Rectangles may be added to the region.
*
*/
static void
REGION_IntersectO(MWCLIPREGION *pReg, MWRECT *r1, MWRECT *r1End,
MWRECT *r2, MWRECT *r2End, MWCOORD top, MWCOORD bottom)
{
MWCOORD left, right;
MWRECT *pNextRect;
pNextRect = &pReg->rects[pReg->numRects];
while ((r1 != r1End) && (r2 != r2End))
{
left = MWMAX(r1->left, r2->left);
right = MWMIN(r1->right, r2->right);
/*
* If there's any overlap between the two rectangles, add that
* overlap to the new region.
* There's no need to check for subsumption because the only way
* such a need could arise is if some region has two rectangles
* right next to each other. Since that should never happen...
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -