📄 miregion.c
字号:
for (i = numRects; --i > 0;) { box++; /* Look for a region to append box to */ for (j = numRI, rit = ri; --j >= 0; rit++) { reg = &rit->reg; riBox = REGION_END(reg); if (box->y1 == riBox->y1 && box->y2 == riBox->y2) { /* box is in same band as riBox. Merge or append it */ if (box->x1 <= riBox->x2) { /* Merge it with riBox */ if (box->x1 < riBox->x2) *pOverlap = TRUE; if (box->x2 > riBox->x2) riBox->x2 = box->x2; } else { RECTALLOC(reg, 1); *REGION_TOP(reg) = *box; reg->data->numRects++; } goto NextRect; /* So sue me */ } else if (box->y1 >= riBox->y2) { /* Put box into new band */ if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2; if (reg->extents.x1 > box->x1) reg->extents.x1 = box->x1; Coalesce(reg, rit->prevBand, rit->curBand); rit->curBand = reg->data->numRects; RECTALLOC(reg, 1); *REGION_TOP(reg) = *box; reg->data->numRects++; goto NextRect; } /* Well, this region was inappropriate. Try the next one. */ } /* for j */ /* Uh-oh. No regions were appropriate. Create a new one. */ if (sizeRI == numRI) { /* Oops, allocate space for new region information */ sizeRI <<= 1; Must_have_memory = TRUE; /* XXX */ ri = (RegionInfo *) xrealloc(ri, sizeRI * sizeof(RegionInfo)); Must_have_memory = FALSE; /* XXX */ rit = &ri[numRI]; } numRI++; rit->prevBand = 0; rit->curBand = 0; rit->reg.extents = *box; rit->reg.data = (RegDataPtr)NULL; miRectAlloc(&rit->reg, (i+numRI) / numRI); /* MUST force allocation */NextRect: ; } /* for i */ /* Make a final pass over each region in order to Coalesce and set extents.x2 and extents.y2 */ for (j = numRI, rit = ri; --j >= 0; rit++) { reg = &rit->reg; riBox = REGION_END(reg); reg->extents.y2 = riBox->y2; if (reg->extents.x2 < riBox->x2) reg->extents.x2 = riBox->x2; Coalesce(reg, rit->prevBand, rit->curBand); if (reg->data->numRects == 1) /* keep unions happy below */ { xfreeData(reg); reg->data = (RegDataPtr)NULL; } } /* Step 3: Union all regions into a single region */ while (numRI > 1) { int half = numRI/2; for (j = numRI & 1; j < (half + (numRI & 1)); j++) { reg = &ri[j].reg; hreg = &ri[j+half].reg; miRegionOp(reg, reg, hreg, miUnionO, TRUE, TRUE, pOverlap); if (hreg->extents.x1 < reg->extents.x1) reg->extents.x1 = hreg->extents.x1; if (hreg->extents.y1 < reg->extents.y1) reg->extents.y1 = hreg->extents.y1; if (hreg->extents.x2 > reg->extents.x2) reg->extents.x2 = hreg->extents.x2; if (hreg->extents.y2 > reg->extents.y2) reg->extents.y2 = hreg->extents.y2; xfreeData(hreg); } numRI -= half; } *badreg = ri[0].reg; xfree(ri); good(badreg); return TRUE;}RegionPtrmiRectsToRegion(nrects, prect, ctype) int nrects; register xRectangle *prect; int ctype;{ register RegionPtr pRgn; register RegDataPtr pData; register BoxPtr pBox; register int i; int x1, y1, x2, y2; pRgn = miRegionCreate(NullBox, 0); if (!nrects) return pRgn; if (nrects == 1) { x1 = prect->x; y1 = prect->y; if ((x2 = x1 + (int) prect->width) > MAXSHORT) x2 = MAXSHORT; if ((y2 = y1 + (int) prect->height) > MAXSHORT) y2 = MAXSHORT; if (x1 != x2 && y1 != y2) { pRgn->extents.x1 = x1; pRgn->extents.y1 = y1; pRgn->extents.x2 = x2; pRgn->extents.y2 = y2; pRgn->data = (RegDataPtr)NULL; } return pRgn; } Must_have_memory = TRUE; /* XXX */ pData = xallocData(nrects); pBox = (BoxPtr) (pData + 1); Must_have_memory = FALSE; /* XXX */ for (i = nrects; --i >= 0; prect++) { x1 = prect->x; y1 = prect->y; if ((x2 = x1 + (int) prect->width) > MAXSHORT) x2 = MAXSHORT; if ((y2 = y1 + (int) prect->height) > MAXSHORT) y2 = MAXSHORT; if (x1 != x2 && y1 != y2) { pBox->x1 = x1; pBox->y1 = y1; pBox->x2 = x2; pBox->y2 = y2; pBox++; } } if (pBox != (BoxPtr) (pData + 1)) { pData->size = nrects; pData->numRects = pBox - (BoxPtr) (pData + 1); pRgn->data = pData; if (ctype != CT_YXBANDED) { Bool overlap; /* result ignored */ pRgn->extents.x1 = pRgn->extents.x2 = 0; miRegionValidate(pRgn, &overlap); } else miSetExtents(pRgn); good(pRgn); } else { xfree (pData); } return pRgn;}/*====================================================================== * Region Subtraction *====================================================================*//*- *----------------------------------------------------------------------- * miSubtractO -- * Overlapping band subtraction. x1 is the left-most point not yet * checked. * * Results: * TRUE if successful. * * Side Effects: * pReg may have rectangles added to it. * *----------------------------------------------------------------------- *//*ARGSUSED*/static BoolmiSubtractO (pReg, r1, r1End, r2, r2End, y1, y2, pOverlap) register RegionPtr pReg; register BoxPtr r1; BoxPtr r1End; register BoxPtr r2; BoxPtr r2End; register int y1; int y2; Bool *pOverlap;{ register BoxPtr pNextRect; register int x1; x1 = r1->x1; assert(y1<y2); assert(r1 != r1End && r2 != r2End); pNextRect = REGION_TOP(pReg); do { if (r2->x2 <= x1) { /* * Subtrahend entirely to left of minuend: go to next subtrahend. */ r2++; } else if (r2->x1 <= x1) { /* * Subtrahend preceeds minuend: nuke left edge of minuend. */ x1 = r2->x2; if (x1 >= r1->x2) { /* * Minuend completely covered: advance to next minuend and * reset left fence to edge of new minuend. */ r1++; if (r1 != r1End) x1 = r1->x1; } else { /* * Subtrahend now used up since it doesn't extend beyond * minuend */ r2++; } } else if (r2->x1 < r1->x2) { /* * Left part of subtrahend covers part of minuend: add uncovered * part of minuend to region and skip to next subtrahend. */ assert(x1<r2->x1); NEWRECT(pReg, pNextRect, x1, y1, r2->x1, y2); x1 = r2->x2; if (x1 >= r1->x2) { /* * Minuend used up: advance to new... */ r1++; if (r1 != r1End) x1 = r1->x1; } else { /* * Subtrahend used up */ r2++; } } else { /* * Minuend used up: add any remaining piece before advancing. */ if (r1->x2 > x1) NEWRECT(pReg, pNextRect, x1, y1, r1->x2, y2); r1++; if (r1 != r1End) x1 = r1->x1; } } while ((r1 != r1End) && (r2 != r2End)); /* * Add remaining minuend rectangles to region. */ while (r1 != r1End) { assert(x1<r1->x2); NEWRECT(pReg, pNextRect, x1, y1, r1->x2, y2); r1++; if (r1 != r1End) x1 = r1->x1; } return TRUE;} /*- *----------------------------------------------------------------------- * miSubtract -- * Subtract regS from regM and leave the result in regD. * S stands for subtrahend, M for minuend and D for difference. * * Results: * TRUE if successful. * * Side Effects: * regD is overwritten. * *----------------------------------------------------------------------- */BoolmiSubtract(regD, regM, regS) register RegionPtr regD; register RegionPtr regM; register RegionPtr regS; { Bool overlap; /* result ignored */ good(regM); good(regS); good(regD); /* check for trivial rejects */ if (REGION_NIL(regM) || REGION_NIL(regS) || !EXTENTCHECK(®M->extents, ®S->extents)) { return miRegionCopy(regD, regM); } else if (regM == regS) { xfreeData(regD); regD->extents.x2 = regD->extents.x1; regD->extents.y2 = regD->extents.y1; regD->data = &miEmptyData; return TRUE; } /* Add those rectangles in region 1 that aren't in region 2, do yucky substraction for overlaps, and just throw away rectangles in region 2 that aren't in region 1 */ if (!miRegionOp(regD, regM, regS, miSubtractO, TRUE, FALSE, &overlap)) return FALSE; /* * Can't alter RegD's extents before we call miRegionOp because * it might be one of the source regions and miRegionOp depends * on the extents of those regions being unaltered. Besides, this * way there's no checking against rectangles that will be nuked * due to coalescing, so we have to examine fewer rectangles. */ miSetExtents(regD); good(regD); return TRUE;}/*====================================================================== * Region Inversion *====================================================================*//*- *----------------------------------------------------------------------- * miInverse -- * Take a region and a box and return a region that is everything * in the box but not in the region. The careful reader will note * that this is the same as subtracting the region from the box... * * Results: * TRUE. * * Side Effects: * newReg is overwritten. * *----------------------------------------------------------------------- */BoolmiInverse(newReg, reg1, invRect) RegionPtr newReg; /* Destination region */ RegionPtr reg1; /* Region to invert */ BoxPtr invRect; /* Bounding box for inversion */{ RegionRec invReg; /* Quick and dirty region made from the * bounding box */ Bool overlap; /* result ignored */ good(reg1); good(newReg); /* check for trivial rejects */ if (REGION_NIL(reg1) || !EXTENTCHECK(invRect, ®1->extents)) { newReg->extents = *invRect; xfreeData(newReg); newReg->data = (RegDataPtr)NULL; return TRUE; } /* Add those rectangles in region 1 that aren't in region 2, do yucky substraction for overlaps, and just throw away rectangles in region 2 that aren't in region 1 */ invReg.extents = *invRect; invReg.data = (RegDataPtr)NULL; if (!miRegionOp(newReg, &invReg, reg1, miSubtractO, TRUE, FALSE, &overlap)) return FALSE; /* * Can't alter newReg's extents before we call miRegionOp because * it might be one of the source regions and miRegionOp depends * on the extents of those regions being unaltered. Besides, this * way there's no checking against rectangles that will be nuked * due to coalescing, so we have to examine fewer rectangles. */ miSetExtents(newReg); good(newReg); return TRUE;}/* * RectIn(region, rect) * This routine takes a pointer to a region and a pointer to a box * and determines if the box is outside/inside/partly inside the region. * * The idea is to travel through the list of rectangles trying to cover the * passed box with them. Anytime a piece of the rectangle isn't covered * by a band of rectangles, partOut is set TRUE. Any time a rectangle in * the region covers part of the box, partIn is set TRUE. The process ends * when either the box has been completely covered (we reached a band that * doesn't overlap the box, partIn is TRUE and partOut is false), the * box has been partially covered (partIn == partOut == TRUE -- because of * the banding, the first time this is true we know the box is only * partially in the region) or is outside the region (we reached a band * that doesn't overlap the box at all and partIn is false) */intmiRectIn(region, prect) register RegionPtr region; register BoxPtr prect;{ register int x; register int y; register BoxPtr pbox; register BoxPtr pboxEnd; int partIn, partOut; int numRects; good(region); numRects = REGION_NUM_RECTS(region); /* useful optimization */ if (!numRects || !EXTENTCHECK(®ion->extents, prect)) return(rgnOUT); if (numRects == 1) { /* We know that it must be rgnIN or rgnPART */ if (SUBSUMES(®ion->extents, prect)) return(rgnIN); else return(rgnPART); } partOut = FALSE; partIn = FALSE; /* (x,y) starts at upper left of rect, moving to the right and down */ x = prect->x1; y = prect->y1; /* can stop when both partOut and partIn are TRUE, or we reach prect->y2 */ for (pbox = REGION_BOXPTR(region), pboxEnd = pbox + numRects; pbox != pboxEnd; pbox++) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -