📄 miregion.c
字号:
} else if (!reg1->data && !reg2->data) { /* Covers about 80% of cases that aren't trivially rejected */ newReg->extents.x1 = max(reg1->extents.x1, reg2->extents.x1); newReg->extents.y1 = max(reg1->extents.y1, reg2->extents.y1); newReg->extents.x2 = min(reg1->extents.x2, reg2->extents.x2); newReg->extents.y2 = min(reg1->extents.y2, reg2->extents.y2); xfreeData(newReg); newReg->data = (RegDataPtr)NULL; } else if (!reg2->data && SUBSUMES(®2->extents, ®1->extents)) { return miRegionCopy(newReg, reg1); } else if (!reg1->data && SUBSUMES(®1->extents, ®2->extents)) { return miRegionCopy(newReg, reg2); } else if (reg1 == reg2) { return miRegionCopy(newReg, reg1); } else { /* General purpose intersection */ Bool overlap; /* result ignored */ if (!miRegionOp(newReg, reg1, reg2, miIntersectO, FALSE, FALSE, &overlap)) return FALSE; miSetExtents(newReg); } good(newReg); return(TRUE);}#define MERGERECT(r) \{ \ if (r->x1 <= x2) { \ /* Merge with current rectangle */ \ if (r->x1 < x2) *pOverlap = TRUE; \ if (x2 < r->x2) x2 = r->x2; \ } else { \ /* Add current rectangle, start new one */ \ NEWRECT(pReg, pNextRect, x1, y1, x2, y2); \ x1 = r->x1; \ x2 = r->x2; \ } \ r++; \}/*====================================================================== * Region Union *====================================================================*//*- *----------------------------------------------------------------------- * miUnionO -- * Handle an overlapping band for the union operation. Picks the * left-most rectangle each time and merges it into the region. * * Results: * TRUE if successful. * * Side Effects: * pReg is overwritten. * pOverlap is set to TRUE if any boxes overlap. * *----------------------------------------------------------------------- */static BoolmiUnionO (pReg, r1, r1End, r2, r2End, y1, y2, pOverlap) register RegionPtr pReg; register BoxPtr r1; BoxPtr r1End; register BoxPtr r2; BoxPtr r2End; short y1; short y2; Bool *pOverlap;{ register BoxPtr pNextRect; register int x1; /* left and right side of current union */ register int x2; assert (y1 < y2); assert(r1 != r1End && r2 != r2End); pNextRect = REGION_TOP(pReg); /* Start off current rectangle */ if (r1->x1 < r2->x1) { x1 = r1->x1; x2 = r1->x2; r1++; } else { x1 = r2->x1; x2 = r2->x2; r2++; } while (r1 != r1End && r2 != r2End) { if (r1->x1 < r2->x1) MERGERECT(r1) else MERGERECT(r2); } /* Finish off whoever (if any) is left */ if (r1 != r1End) { do { MERGERECT(r1); } while (r1 != r1End); } else if (r2 != r2End) { do { MERGERECT(r2); } while (r2 != r2End); } /* Add current rectangle */ NEWRECT(pReg, pNextRect, x1, y1, x2, y2); return TRUE;}Bool miUnion(newReg, reg1, reg2) RegionPtr newReg; /* destination Region */ register RegionPtr reg1; register RegionPtr reg2; /* source regions */{ Bool overlap; /* result ignored */ /* Return TRUE if some overlap between reg1, reg2 */ good(reg1); good(reg2); good(newReg); /* checks all the simple cases */ /* * Region 1 and 2 are the same */ if (reg1 == reg2) { return miRegionCopy(newReg, reg1); } /* * Region 1 is empty */ if (REGION_NIL(reg1)) { if (newReg != reg2) return miRegionCopy(newReg, reg2); return TRUE; } /* * Region 2 is empty */ if (REGION_NIL(reg2)) { if (newReg != reg1) return miRegionCopy(newReg, reg1); return TRUE; } /* * Region 1 completely subsumes region 2 */ if (!reg1->data && SUBSUMES(®1->extents, ®2->extents)) { if (newReg != reg1) return miRegionCopy(newReg, reg1); return TRUE; } /* * Region 2 completely subsumes region 1 */ if (!reg2->data && SUBSUMES(®2->extents, ®1->extents)) { if (newReg != reg2) return miRegionCopy(newReg, reg2); return TRUE; } if (!miRegionOp(newReg, reg1, reg2, miUnionO, TRUE, TRUE, &overlap)) return FALSE; newReg->extents.x1 = min(reg1->extents.x1, reg2->extents.x1); newReg->extents.y1 = min(reg1->extents.y1, reg2->extents.y1); newReg->extents.x2 = max(reg1->extents.x2, reg2->extents.x2); newReg->extents.y2 = max(reg1->extents.y2, reg2->extents.y2); good(newReg); return TRUE;}/*====================================================================== * Batch Rectangle Union *====================================================================*//*- *----------------------------------------------------------------------- * miRegionAppend -- * * "Append" the rgn rectangles onto the end of dstrgn, maintaining * knowledge of YX-banding when it's easy. Otherwise, dstrgn just * becomes a non-y-x-banded random collection of rectangles, and not * yet a true region. After a sequence of appends, the caller must * call miRegionValidate to ensure that a valid region is constructed. * * Results: * TRUE if successful. * * Side Effects: * dstrgn is modified if rgn has rectangles. * */BoolmiRegionAppend(dstrgn, rgn) register RegionPtr dstrgn; register RegionPtr rgn;{ int numRects, dnumRects, size; BoxPtr new, old; Bool prepend; if (!rgn->data && (dstrgn->data == &miEmptyData)) { dstrgn->extents = rgn->extents; dstrgn->data = (RegDataPtr)NULL; return TRUE; } numRects = REGION_NUM_RECTS(rgn); if (!numRects) return TRUE; prepend = FALSE; size = numRects; dnumRects = REGION_NUM_RECTS(dstrgn); if (!dnumRects && (size < 200)) size = 200; /* XXX pick numbers out of a hat */ RECTALLOC(dstrgn, size); old = REGION_RECTS(rgn); if (!dnumRects) dstrgn->extents = rgn->extents; else if (dstrgn->extents.x2 > dstrgn->extents.x1) { register BoxPtr first, last; first = old; last = REGION_BOXPTR(dstrgn) + (dnumRects - 1); if ((first->y1 > last->y2) || ((first->y1 == last->y1) && (first->y2 == last->y2) && (first->x1 > last->x2))) { if (rgn->extents.x1 < dstrgn->extents.x1) dstrgn->extents.x1 = rgn->extents.x1; if (rgn->extents.x2 > dstrgn->extents.x2) dstrgn->extents.x2 = rgn->extents.x2; dstrgn->extents.y2 = rgn->extents.y2; } else { first = REGION_BOXPTR(dstrgn); last = old + (numRects - 1); if ((first->y1 > last->y2) || ((first->y1 == last->y1) && (first->y2 == last->y2) && (first->x1 > last->x2))) { prepend = TRUE; if (rgn->extents.x1 < dstrgn->extents.x1) dstrgn->extents.x1 = rgn->extents.x1; if (rgn->extents.x2 > dstrgn->extents.x2) dstrgn->extents.x2 = rgn->extents.x2; dstrgn->extents.y1 = rgn->extents.y1; } else dstrgn->extents.x2 = dstrgn->extents.x1; } } if (prepend) { new = REGION_BOX(dstrgn, numRects); if (dnumRects == 1) *new = *REGION_BOXPTR(dstrgn); else memmove((char *)new,(char *)REGION_BOXPTR(dstrgn), dnumRects * sizeof(BoxRec)); new = REGION_BOXPTR(dstrgn); } else new = REGION_BOXPTR(dstrgn) + dnumRects; if (numRects == 1) *new = *old; else memmove((char *)new, (char *)old, numRects * sizeof(BoxRec)); dstrgn->data->numRects += numRects; return TRUE;} #define ExchangeRects(a, b) \{ \ BoxRec t; \ t = rects[a]; \ rects[a] = rects[b]; \ rects[b] = t; \}static voidQuickSortRects(rects, numRects) register BoxRec rects[]; register int numRects;{ register int y1; register int x1; register int i, j; register BoxPtr r; /* Always called with numRects > 1 */ do { if (numRects == 2) { if (rects[0].y1 > rects[1].y1 || (rects[0].y1 == rects[1].y1 && rects[0].x1 > rects[1].x1)) ExchangeRects(0, 1); return; } /* Choose partition element, stick in location 0 */ ExchangeRects(0, numRects >> 1); y1 = rects[0].y1; x1 = rects[0].x1; /* Partition array */ i = 0; j = numRects; do { r = &(rects[i]); do { r++; i++; } while (i != numRects && (r->y1 < y1 || (r->y1 == y1 && r->x1 < x1))); r = &(rects[j]); do { r--; j--; } while (y1 < r->y1 || (y1 == r->y1 && x1 < r->x1)); if (i < j) ExchangeRects(i, j); } while (i < j); /* Move partition element back to middle */ ExchangeRects(0, j); /* Recurse */ if (numRects-j-1 > 1) QuickSortRects(&rects[j+1], numRects-j-1); numRects = j; } while (numRects > 1);}/*- *----------------------------------------------------------------------- * miRegionValidate -- * * Take a ``region'' which is a non-y-x-banded random collection of * rectangles, and compute a nice region which is the union of all the * rectangles. * * Results: * TRUE if successful. * * Side Effects: * The passed-in ``region'' may be modified. * pOverlap set to TRUE if any retangles overlapped, else FALSE; * * Strategy: * Step 1. Sort the rectangles into ascending order with primary key y1 * and secondary key x1. * * Step 2. Split the rectangles into the minimum number of proper y-x * banded regions. This may require horizontally merging * rectangles, and vertically coalescing bands. With any luck, * this step in an identity tranformation (ala the Box widget), * or a coalescing into 1 box (ala Menus). * * Step 3. Merge the separate regions down to a single region by calling * miUnion. Maximize the work each miUnion call does by using * a binary merge. * *----------------------------------------------------------------------- */BoolmiRegionValidate(badreg, pOverlap) RegionPtr badreg; Bool *pOverlap;{ /* Descriptor for regions under construction in Step 2. */ typedef struct { RegionRec reg; int prevBand; int curBand; } RegionInfo; int numRects; /* Original numRects for badreg */ RegionInfo *ri; /* Array of current regions */ int numRI; /* Number of entries used in ri */ int sizeRI; /* Number of entries available in ri */ int i; /* Index into rects */ register int j; /* Index into ri */ register RegionInfo *rit; /* &ri[j] */ register RegionPtr reg; /* ri[j].reg */ register BoxPtr box; /* Current box in rects */ register BoxPtr riBox; /* Last box in ri[j].reg */ register RegionPtr hreg; /* ri[j_half].reg */ *pOverlap = FALSE; if (!badreg->data) { good(badreg); return TRUE; } numRects = badreg->data->numRects; if (!numRects) { good(badreg); return TRUE; } if (badreg->extents.x1 < badreg->extents.x2) { if ((numRects) == 1) { xfreeData(badreg); badreg->data = (RegDataPtr) NULL; } else { DOWNSIZE(badreg, numRects); } good(badreg); return TRUE; } /* Step 1: Sort the rects array into ascending (y1, x1) order */ QuickSortRects(REGION_BOXPTR(badreg), numRects); /* Step 2: Scatter the sorted array into the minimum number of regions */ /* Set up the first region to be the first rectangle in badreg */ /* Note that step 2 code will never overflow the ri[0].reg rects array */ Must_have_memory = TRUE; /* XXX */ ri = (RegionInfo *) xalloc(4 * sizeof(RegionInfo)); Must_have_memory = FALSE; /* XXX */ sizeRI = 4; numRI = 1; ri[0].prevBand = 0; ri[0].curBand = 0; ri[0].reg = *badreg; box = REGION_BOXPTR(&ri[0].reg); ri[0].reg.extents = *box; ri[0].reg.data->numRects = 1; /* Now scatter rectangles into the minimum set of valid regions. If the next rectangle to be added to a region would force an existing rectangle in the region to be split up in order to maintain y-x banding, just forget it. Try the next region. If it doesn't fit cleanly into any region, make a new one. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -