|
|
1.1 root 1: /* $Header: XRegion.c,v 11.13 87/09/03 17:20:59 newman Exp $ */
2: /************************************************************************
3: Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
4: and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
5:
6: All Rights Reserved
7:
8: Permission to use, copy, modify, and distribute this software and its
9: documentation for any purpose and without fee is hereby granted,
10: provided that the above copyright notice appear in all copies and that
11: both that copyright notice and this permission notice appear in
12: supporting documentation, and that the names of Digital or MIT not be
13: used in advertising or publicity pertaining to distribution of the
14: software without specific, written prior permission.
15:
16: DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
17: ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
18: DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
19: ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
20: WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21: ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
22: SOFTWARE.
23:
24: ************************************************************************/
25: /*
26: * The functions in this file implement the Region abstraction used extensively
27: * throughout the X11 sample server. A Region is simply an area, as the name
28: * implies, and is implemented as a "y-x-banded" array of rectangles. To
29: * explain: Each Region is made up of a certain number of rectangles sorted
30: * by y coordinate first, and then by x coordinate.
31: *
32: * Furthermore, the rectangles are banded such that every rectangle with a
33: * given upper-left y coordinate (y1) will have the same lower-right y
34: * coordinate (y2) and vice versa. If a rectangle has scanlines in a band, it
35: * will span the entire vertical distance of the band. This means that some
36: * areas that could be merged into a taller rectangle will be represented as
37: * several shorter rectangles to account for shorter rectangles to its left
38: * or right but within its "vertical scope".
39: *
40: * An added constraint on the rectangles is that they must cover as much
41: * horizontal area as possible. E.g. no two rectangles in a band are allowed
42: * to touch.
43: *
44: * Whenever possible, bands will be merged together to cover a greater vertical
45: * distance (and thus reduce the number of rectangles). Two bands can be merged
46: * only if the bottom of one touches the top of the other and they have
47: * rectangles in the same places (of the same width, of course). This maintains
48: * the y-x-banding that's so nice to have...
49: */
50:
51: #include "Xlib.h"
52: #include "Xutil.h"
53: #include "region.h"
54: #include "poly.h"
55:
56: #ifdef DEBUG
57: #define assert(expr) {if (!(expr)) FatalError("Assertion failed file
58: %s, line %d: expr\n", __FILE__, __LINE__); }
59: #else
60: #define assert(expr)
61: #endif
62:
63: extern char *_XAllocScratch();
64: /* Create a new empty region */
65: Region
66: XCreateRegion()
67: {
68: Region temp;
69:
70: temp = ( Region )Xmalloc( (unsigned) sizeof( REGION ));
71: temp->rects = ( BOX * )Xmalloc( (unsigned) sizeof( BOX ));
72: temp->numRects = 0;
73: temp->extents.x1 = 0;
74: temp->extents.y1 = 0;
75: temp->extents.x2 = 0;
76: temp->extents.y2 = 0;
77: temp->size = 1;
78: return( temp );
79: }
80:
81: XClipBox( r, rect )
82: Region r;
83: XRectangle *rect;
84: {
85: rect->x = r->extents.x1;
86: rect->y = r->extents.y1;
87: rect->width = r->extents.x2 - r->extents.x1;
88: rect->height = r->extents.y2 - r->extents.y1;
89: }
90:
91:
92: /*-
93: *-----------------------------------------------------------------------
94: * miSetExtents --
95: * Reset the extents of a region to what they should be. Called by
96: * miSubtract and miIntersect b/c they can't figure it out along the
97: * way or do so easily, as miUnion can.
98: *
99: * Results:
100: * None.
101: *
102: * Side Effects:
103: * The region's 'extents' structure is overwritten.
104: *
105: *-----------------------------------------------------------------------
106: */
107: /* static void*/
108: miSetExtents (pReg)
109: Region pReg;
110: {
111: register BoxPtr pBox,
112: pBoxEnd,
113: pExtents;
114:
115: pExtents = &pReg->extents;
116: pBox = pReg->rects;
117: pBoxEnd = &pBox[pReg->numRects - 1];
118:
119: /*
120: * Since pBox is the first rectangle in the region, it must have the
121: * smallest y1 and since pBoxEnd is the last rectangle in the region,
122: * it must have the largest y2, because of banding. Initialize x1 and
123: * x2 from pBox and pBoxEnd, resp., as good things to initialize them
124: * to...
125: */
126: pExtents->x1 = pBox->x1;
127: pExtents->y1 = pBox->y1;
128: pExtents->x2 = pBoxEnd->x2;
129: pExtents->y2 = pBoxEnd->y2;
130:
131: assert(pExtents->y1 < pExtents->y2);
132: while (pBox <= pBoxEnd)
133: {
134: if (pBox->x1 < pExtents->x1)
135: {
136: pExtents->x1 = pBox->x1;
137: }
138: if (pBox->x2 > pExtents->x2)
139: {
140: pExtents->x2 = pBox->x2;
141: }
142: pBox++;
143: }
144: assert(pExtents->x1 < pExtents->x2);
145: }
146:
147: XSetRegion( dpy, gc, r )
148: Display *dpy;
149: GC gc;
150: register Region r;
151: {
152: register int i;
153: register XRectangle *xr;
154: LockDisplay (dpy);
155: xr = (XRectangle *)
156: _XAllocScratch(dpy, (unsigned long)(r->numRects * sizeof (XRectangle)));
157: for (i = 0; i < r->numRects; i++) {
158: xr->x = r->rects[i].x1;
159: xr->y = r->rects[i].y1;
160: xr->width = r->rects[i].x2 - r->rects[i].x1;
161: xr->height = r->rects[i].y2 - r->rects[i].y1;
162: }
163: _XSetClipRectangles(dpy, gc,r->extents.x1,r->extents.y1, xr,
164: r->numRects,Unsorted);
165: UnlockDisplay(dpy);
166: SyncHandle();
167: }
168:
169: XDestroyRegion( r )
170: Region r;
171: {
172: Xfree( (char *) r->rects );
173: Xfree( (char *) r );
174: }
175:
176:
177: /* TranslateRegion(pRegion, x, y)
178: translates in place
179: added by raymond
180: */
181:
182: void
183: XOffsetRegion(pRegion, x, y)
184: register Region pRegion;
185: register int x;
186: register int y;
187: {
188: register int nbox;
189: register BOX *pbox;
190:
191: pbox = pRegion->rects;
192: nbox = pRegion->numRects;
193:
194: while(nbox--)
195: {
196: pbox->x1 += x;
197: pbox->x2 += x;
198: pbox->y1 += y;
199: pbox->y2 += y;
200: pbox++;
201: }
202: pRegion->extents.x1 += x;
203: pRegion->extents.x2 += x;
204: pRegion->extents.y1 += y;
205: pRegion->extents.y2 += y;
206: }
207:
208: XShrinkRegion( r, dx, dy )
209: Region r;
210: int dx, dy;
211: {
212: int i,h,w;
213: float sx,sy;
214: int cx,cy,newcx,newcy;
215: BoxPtr rect;
216:
217: /* figure out ratios */
218: h = r->extents.y2 - r->extents.y1;
219: w = r->extents.x2 - r->extents.x1;
220: sx = ((float)(w+dx))/w;
221: sy = ((float)(h+dy))/h;
222: rect = &(r->rects[0]);
223: for(i=0; i<r->numRects; i++)
224: {
225: cx = (rect->x1 + rect->x2)/2;
226: cy = (rect->y1 + rect->y2)/2;
227:
228: /* shrink or expand box */
229: rect->x1 = rect->x1 * sx;
230: rect->x2 = rect->x2 * sx;
231: rect->y1 = rect->y1 * sy;
232: rect->y2 = rect->y2 * sy;
233:
234: /* recenter box around old center */
235: newcx = (rect->x1 + rect->x2)/2;
236: newcy = (rect->y1 + rect->y2)/2;
237: rect->x1 = rect->x1 - (newcx - cx);
238: rect->x2 = rect->x2 - (newcx - cx);
239: rect->y1 = rect->y1 - (newcy - cy);
240: rect->y2 = rect->y2 - (newcy - cy);
241:
242: /* adjust for shrinkage problems */
243: if ( dx < 0 )
244: {
245: if ( rect->x1 > cx ) rect->x1 = cx;
246: if ( rect->x2 < cx ) rect->x2 = cx;
247: }
248: if ( dy < 0 )
249: {
250: if ( rect->y1 > cy ) rect->y1 = cy;
251: if ( rect->y2 < cy ) rect->y2 = cy;
252: }
253: EXTENTS(rect,r);
254: (rect)++;
255: }
256: }
257:
258: #ifdef notdef
259: /***********************************************************
260: * Bop down the array of rects until we have passed
261: * scanline y. numRects is the size of the array.
262: ***********************************************************/
263:
264: static BOX
265: *IndexRects(rects, numRects, y)
266: register BOX *rects;
267: register int numRects;
268: register int y;
269: {
270: while ((numRects--) && (rects->y2 <= y))
271: rects++;
272: return(rects);
273: }
274: #endif
275:
276: /*======================================================================
277: * Region Intersection
278: *====================================================================*/
279: /*-
280: *-----------------------------------------------------------------------
281: * miIntersectO --
282: * Handle an overlapping band for miIntersect.
283: *
284: * Results:
285: * None.
286: *
287: * Side Effects:
288: * Rectangles may be added to the region.
289: *
290: *-----------------------------------------------------------------------
291: */
292: /* static void*/
293: miIntersectO (pReg, r1, r1End, r2, r2End, y1, y2)
294: register Region pReg;
295: register BoxPtr r1;
296: BoxPtr r1End;
297: register BoxPtr r2;
298: BoxPtr r2End;
299: short y1;
300: short y2;
301: {
302: register short x1;
303: register short x2;
304: register BoxPtr pNextRect;
305:
306: pNextRect = &pReg->rects[pReg->numRects];
307:
308: while ((r1 != r1End) && (r2 != r2End))
309: {
310: x1 = max(r1->x1,r2->x1);
311: x2 = min(r1->x2,r2->x2);
312:
313: /*
314: * If there's any overlap between the two rectangles, add that
315: * overlap to the new region.
316: * There's no need to check for subsumption because the only way
317: * such a need could arise is if some region has two rectangles
318: * right next to each other. Since that should never happen...
319: */
320: if (x1 < x2)
321: {
322: assert(y1<y2);
323:
324: MEMCHECK(pReg, pNextRect, pReg->rects);
325: pNextRect->x1 = x1;
326: pNextRect->y1 = y1;
327: pNextRect->x2 = x2;
328: pNextRect->y2 = y2;
329: pReg->numRects += 1;
330: pNextRect++;
331: assert(pReg->numRects <= pReg->size);
332: }
333:
334: /*
335: * Need to advance the pointers. Shift the one that extends
336: * to the right the least, since the other still has a chance to
337: * overlap with that region's next rectangle, if you see what I mean.
338: */
339: if (r1->x2 < r2->x2)
340: {
341: r1++;
342: }
343: else if (r2->x2 < r1->x2)
344: {
345: r2++;
346: }
347: else
348: {
349: r1++;
350: r2++;
351: }
352: }
353: }
354:
355: XIntersectRegion(reg1, reg2, newReg)
356: Region reg1;
357: Region reg2; /* source regions */
358: register Region newReg; /* destination Region */
359: {
360: /* check for trivial reject */
361: if ( (!(reg1->numRects)) || (!(reg2->numRects)) ||
362: (!EXTENTCHECK(®1->extents, ®2->extents)))
363: {
364: newReg->numRects = 0;
365: return(1);
366: }
367:
368: miRegionOp (newReg, reg1, reg2, miIntersectO, NULL, NULL);
369:
370: if (newReg->numRects != 0)
371: {
372: /*
373: * Can't alter newReg's extents before we call miRegionOp because
374: * it might be one of the source regions and miRegionOp depends
375: * on the extents of those regions being the same. Besides, this
376: * way there's no checking against rectangles that will be nuked
377: * due to coalescing, so we have to examine fewer rectangles.
378: */
379: miSetExtents(newReg);
380: }
381: return(1);
382: }
383:
384: void bcopy();
385: void
386: miRegionCopy(dstrgn, rgn)
387: register Region dstrgn;
388: register Region rgn;
389:
390: {
391: if (dstrgn != rgn) /* don't want to copy to itself */
392: {
393: if (dstrgn->size < rgn->numRects)
394: {
395: if (dstrgn->rects)
396: {
397: dstrgn->rects = (BOX *) Xrealloc(dstrgn->rects,
398: rgn->numRects * (sizeof(BOX)));
399: }
400: dstrgn->size = rgn->numRects;
401: }
402: dstrgn->numRects = rgn->numRects;
403: dstrgn->extents.x1 = rgn->extents.x1;
404: dstrgn->extents.y1 = rgn->extents.y1;
405: dstrgn->extents.x2 = rgn->extents.x2;
406: dstrgn->extents.y2 = rgn->extents.y2;
407:
408: bcopy(rgn->rects, dstrgn->rects, rgn->numRects * sizeof(BOX));
409: }
410: }
411:
412: /*
413: * combinRegs(newReg, reg1, reg2)
414: * if one region is above or below the other.
415: */
416:
417: /* static void*/
418: combineRegs(newReg, reg1, reg2)
419: register Region newReg;
420: Region reg1;
421: Region reg2;
422: {
423: register Region tempReg;
424: register BOX *rects;
425: register BOX *rects1;
426: register BOX *rects2;
427: register int total;
428:
429: rects1 = reg1->rects;
430: rects2 = reg2->rects;
431:
432: total = reg1->numRects + reg2->numRects;
433: tempReg = XCreateRegion();
434: tempReg->size = total;
435: /* region 1 is below region 2 */
436: if (reg1->extents.y1 > reg2->extents.y1)
437: {
438: miRegionCopy(tempReg, reg2);
439: rects = &tempReg->rects[tempReg->numRects];
440: total -= tempReg->numRects;
441: while (total--)
442: *rects++ = *rects1++;
443: }
444: else
445: {
446: miRegionCopy(tempReg, reg1);
447: rects = &tempReg->rects[tempReg->numRects];
448: total -= tempReg->numRects;
449: while (total--)
450: *rects++ = *rects2++;
451: }
452: tempReg->extents = reg1->extents;
453: tempReg->numRects = reg1->numRects + reg2->numRects;
454: EXTENTS(®2->extents, tempReg);
455: miRegionCopy(newReg, tempReg);
456: Xfree((char *)tempReg);
457: }
458:
459: #ifdef notdef
460: /*
461: * QuickCheck checks to see if it does not have to go through all the
462: * the ugly code for the region call. It returns 1 if it did all
463: * the work for Union, otherwise 0 - still work to be done.
464: */
465:
466: static int
467: QuickCheck(newReg, reg1, reg2)
468: Region newReg, reg1, reg2;
469: {
470:
471: /* if unioning with itself or no rects to union with */
472: if ( (reg1 == reg2) || (!(reg1->numRects)) )
473: {
474: miRegionCopy(newReg, reg2);
475: return(TRUE);
476: }
477:
478: /* if nothing to union */
479: if (!(reg2->numRects))
480: {
481: miRegionCopy(newReg, reg1);
482: return(TRUE);
483: }
484:
485: /* could put an extent check to see if add above or below */
486:
487: if ((reg1->extents.y1 >= reg2->extents.y2) ||
488: (reg2->extents.y1 >= reg1->extents.y2) )
489: {
490: combineRegs(newReg, reg1, reg2);
491: return(TRUE);
492: }
493: return(FALSE);
494: }
495: #endif
496:
497: #ifdef notdef
498: /* TopRects(rects, reg1, reg2)
499: * N.B. We now assume that reg1 and reg2 intersect. Therefore we are
500: * NOT checking in the two while loops for stepping off the end of the
501: * region.
502: */
503:
504: static int
505: TopRects(newReg, rects, reg1, reg2, FirstRect)
506: register Region newReg;
507: register BOX *rects;
508: register Region reg1;
509: register Region reg2;
510: BOX *FirstRect;
511: {
512: register BOX *tempRects;
513:
514: /* need to add some rects from region 1 */
515: if (reg1->extents.y1 < reg2->extents.y1)
516: {
517: tempRects = reg1->rects;
518: while(tempRects->y1 < reg2->extents.y1)
519: {
520: MEMCHECK(newReg, rects, FirstRect);
521: ADDRECTNOX(newReg,rects, tempRects->x1, tempRects->y1,
522: tempRects->x2, MIN(tempRects->y2, reg2->extents.y1));
523: tempRects++;
524: }
525: }
526: /* need to add some rects from region 2 */
527: if (reg2->extents.y1 < reg1->extents.y1)
528: {
529: tempRects = reg2->rects;
530: while (tempRects->y1 < reg1->extents.y1)
531: {
532: MEMCHECK(newReg, rects, FirstRect);
533: ADDRECTNOX(newReg, rects, tempRects->x1,tempRects->y1,
534: tempRects->x2, MIN(tempRects->y2, reg1->extents.y1));
535: tempRects++;
536: }
537: }
538: return(1);
539: }
540: #endif
541:
542: /*======================================================================
543: * Generic Region Operator
544: *====================================================================*/
545:
546: /*-
547: *-----------------------------------------------------------------------
548: * miCoalesce --
549: * Attempt to merge the boxes in the current band with those in the
550: * previous one. Used only by miRegionOp.
551: *
552: * Results:
553: * The new index for the previous band.
554: *
555: * Side Effects:
556: * If coalescing takes place:
557: * - rectangles in the previous band will have their y2 fields
558: * altered.
559: * - pReg->numRects will be decreased.
560: *
561: *-----------------------------------------------------------------------
562: */
563: /* static int*/
564: miCoalesce (pReg, prevStart, curStart)
565: register Region pReg; /* Region to coalesce */
566: int prevStart; /* Index of start of previous band */
567: int curStart; /* Index of start of current band */
568: {
569: register BoxPtr pPrevBox; /* Current box in previous band */
570: register BoxPtr pCurBox; /* Current box in current band */
571: register BoxPtr pRegEnd; /* End of region */
572: int curNumRects; /* Number of rectangles in current
573: * band */
574: int prevNumRects; /* Number of rectangles in previous
575: * band */
576: int bandY1; /* Y1 coordinate for current band */
577:
578: pRegEnd = &pReg->rects[pReg->numRects];
579:
580: pPrevBox = &pReg->rects[prevStart];
581: prevNumRects = curStart - prevStart;
582:
583: /*
584: * Figure out how many rectangles are in the current band. Have to do
585: * this because multiple bands could have been added in miRegionOp
586: * at the end when one region has been exhausted.
587: */
588: pCurBox = &pReg->rects[curStart];
589: bandY1 = pCurBox->y1;
590: for (curNumRects = 0;
591: (pCurBox != pRegEnd) && (pCurBox->y1 == bandY1);
592: curNumRects++)
593: {
594: pCurBox++;
595: }
596:
597: if (pCurBox != pRegEnd)
598: {
599: /*
600: * If more than one band was added, we have to find the start
601: * of the last band added so the next coalescing job can start
602: * at the right place... (given when multiple bands are added,
603: * this may be pointless -- see above).
604: */
605: pRegEnd--;
606: while (pRegEnd[-1].y1 == pRegEnd->y1)
607: {
608: pRegEnd--;
609: }
610: curStart = pRegEnd - pReg->rects;
611: pRegEnd = pReg->rects + pReg->numRects;
612: }
613:
614: if ((curNumRects == prevNumRects) && (curNumRects != 0)) {
615: pCurBox -= curNumRects;
616: /*
617: * The bands may only be coalesced if the bottom of the previous
618: * matches the top scanline of the current.
619: */
620: if (pPrevBox->y2 == pCurBox->y1)
621: {
622: /*
623: * Make sure the bands have boxes in the same places. This
624: * assumes that boxes have been added in such a way that they
625: * cover the most area possible. I.e. two boxes in a band must
626: * have some horizontal space between them.
627: */
628: do
629: {
630: if ((pPrevBox->x1 != pCurBox->x1) ||
631: (pPrevBox->x2 != pCurBox->x2))
632: {
633: /*
634: * The bands don't line up so they can't be coalesced.
635: */
636: return (curStart);
637: }
638: pPrevBox++;
639: pCurBox++;
640: prevNumRects -= 1;
641: } while (prevNumRects != 0);
642:
643: pReg->numRects -= curNumRects;
644: pCurBox -= curNumRects;
645: pPrevBox -= curNumRects;
646:
647: /*
648: * The bands may be merged, so set the bottom y of each box
649: * in the previous band to that of the corresponding box in
650: * the current band.
651: */
652: do
653: {
654: pPrevBox->y2 = pCurBox->y2;
655: pPrevBox++;
656: pCurBox++;
657: curNumRects -= 1;
658: } while (curNumRects != 0);
659:
660: /*
661: * If only one band was added to the region, we have to backup
662: * curStart to the start of the previous band.
663: *
664: * If more than one band was added to the region, copy the
665: * other bands down. The assumption here is that the other bands
666: * came from the same region as the current one and no further
667: * coalescing can be done on them since it's all been done
668: * already... curStart is already in the right place.
669: */
670: if (pCurBox == pRegEnd)
671: {
672: curStart = prevStart;
673: }
674: else
675: {
676: do
677: {
678: *pPrevBox++ = *pCurBox++;
679: } while (pCurBox != pRegEnd);
680: }
681:
682: }
683: }
684: return (curStart);
685: }
686:
687: /*-
688: *-----------------------------------------------------------------------
689: * miRegionOp --
690: * Apply an operation to two regions. Called by miUnion, miInverse,
691: * miSubtract, miIntersect...
692: *
693: * Results:
694: * None.
695: *
696: * Side Effects:
697: * The new region is overwritten.
698: *
699: * Notes:
700: * The idea behind this function is to view the two regions as sets.
701: * Together they cover a rectangle of area that this function divides
702: * into horizontal bands where points are covered only by one region
703: * or by both. For the first case, the nonOverlapFunc is called with
704: * each the band and the band's upper and lower extents. For the
705: * second, the overlapFunc is called to process the entire band. It
706: * is responsible for clipping the rectangles in the band, though
707: * this function provides the boundaries.
708: * At the end of each band, the new region is coalesced, if possible,
709: * to reduce the number of rectangles in the region.
710: *
711: *-----------------------------------------------------------------------
712: */
713: /* static void*/
714: miRegionOp(newReg, reg1, reg2, overlapFunc, nonOverlap1Func, nonOverlap2Func)
715: register Region newReg; /* Place to store result */
716: Region reg1; /* First region in operation */
717: Region reg2; /* 2d region in operation */
718: void (*overlapFunc)(); /* Function to call for over-
719: * lapping bands */
720: void (*nonOverlap1Func)(); /* Function to call for non-
721: * overlapping bands in region
722: * 1 */
723: void (*nonOverlap2Func)(); /* Function to call for non-
724: * overlapping bands in region
725: * 2 */
726: {
727: register BoxPtr r1; /* Pointer into first region */
728: register BoxPtr r2; /* Pointer into 2d region */
729: BoxPtr r1End; /* End of 1st region */
730: BoxPtr r2End; /* End of 2d region */
731: register short ybot; /* Bottom of intersection */
732: register short ytop; /* Top of intersection */
733: BoxPtr oldRects; /* Old rects for newReg */
734: int prevBand; /* Index of start of
735: * previous band in newReg */
736: int curBand; /* Index of start of current
737: * band in newReg */
738: register BoxPtr r1BandEnd; /* End of current band in r1 */
739: register BoxPtr r2BandEnd; /* End of current band in r2 */
740: short top; /* Top of non-overlapping
741: * band */
742: short bot; /* Bottom of non-overlapping
743: * band */
744:
745: /*
746: * Initialization:
747: * set r1, r2, r1End and r2End appropriately, preserve the important
748: * parts of the destination region until the end in case it's one of
749: * the two source regions, then mark the "new" region empty, allocating
750: * another array of rectangles for it to use.
751: */
752: r1 = reg1->rects;
753: r2 = reg2->rects;
754: r1End = r1 + reg1->numRects;
755: r2End = r2 + reg2->numRects;
756:
757: oldRects = newReg->rects;
758:
759: EMPTY_REGION(newReg);
760:
761: /*
762: * Allocate a reasonable number of rectangles for the new region. The idea
763: * is to allocate enough so the individual functions don't need to
764: * reallocate and copy the array, which is time consuming, yet we don't
765: * have to worry about using too much memory. I hope to be able to
766: * nuke the Xrealloc() at the end of this function eventually.
767: */
768: newReg->size = max(reg1->numRects,reg2->numRects) * 2;
769:
770: newReg->rects = (BoxPtr) Xmalloc (sizeof(BoxRec) * newReg->size);
771:
772: /*
773: * Initialize ybot and ytop.
774: * In the upcoming loop, ybot and ytop serve different functions depending
775: * on whether the band being handled is an overlapping or non-overlapping
776: * band.
777: * In the case of a non-overlapping band (only one of the regions
778: * has points in the band), ybot is the bottom of the most recent
779: * intersection and thus clips the top of the rectangles in that band.
780: * ytop is the top of the next intersection between the two regions and
781: * serves to clip the bottom of the rectangles in the current band.
782: * For an overlapping band (where the two regions intersect), ytop clips
783: * the top of the rectangles of both regions and ybot clips the bottoms.
784: */
785: if (reg1->extents.y1 < reg2->extents.y1)
786: {
787: ybot = reg1->extents.y1;
788: ytop = reg2->extents.y1;
789: }
790: else
791: {
792: ybot = reg2->extents.y1;
793: ytop = reg1->extents.y1;
794: }
795:
796: /*
797: * prevBand serves to mark the start of the previous band so rectangles
798: * can be coalesced into larger rectangles. qv. miCoalesce, above.
799: * In the beginning, there is no previous band, so prevBand == curBand
800: * (curBand is set later on, of course, but the first band will always
801: * start at index 0). prevBand and curBand must be indices because of
802: * the possible expansion, and resultant moving, of the new region's
803: * array of rectangles.
804: */
805: prevBand = 0;
806:
807: do
808: {
809: curBand = newReg->numRects;
810:
811: /*
812: * This algorithm proceeds one source-band (as opposed to a
813: * destination band, which is determined by where the two regions
814: * intersect) at a time. r1BandEnd and r2BandEnd serve to mark the
815: * rectangle after the last one in the current band for their
816: * respective regions.
817: */
818: r1BandEnd = r1;
819: while ((r1BandEnd != r1End) && (r1BandEnd->y1 == r1->y1))
820: {
821: r1BandEnd++;
822: }
823:
824: r2BandEnd = r2;
825: while ((r2BandEnd != r2End) && (r2BandEnd->y1 == r2->y1))
826: {
827: r2BandEnd++;
828: }
829:
830: /*
831: * First handle the band that doesn't intersect, if any.
832: *
833: * Note that attention is restricted to one band in the
834: * non-intersecting region at once, so if a region has n
835: * bands between the current position and the next place it overlaps
836: * the other, this entire loop will be passed through n times.
837: */
838: if (r1->y1 < r2->y1)
839: {
840: top = max(r1->y1,ybot);
841: bot = min(r1->y2,r2->y1);
842:
843: if ((top != bot) && (nonOverlap1Func != (void (*)())NULL))
844: {
845: (* nonOverlap1Func) (newReg, r1, r1BandEnd, top, bot);
846: }
847:
848: ytop = r2->y1;
849: }
850: else if (r2->y1 < r1->y1)
851: {
852: top = max(r2->y1,ybot);
853: bot = min(r2->y2,r1->y1);
854:
855: if ((top != bot) && (nonOverlap2Func != (void (*)())NULL))
856: {
857: (* nonOverlap2Func) (newReg, r2, r2BandEnd, top, bot);
858: }
859:
860: ytop = r1->y1;
861: }
862: else
863: {
864: ytop = r1->y1;
865: }
866:
867: /*
868: * If any rectangles got added to the region, try and coalesce them
869: * with rectangles from the previous band. Note we could just do
870: * this test in miCoalesce, but some machines incur a not
871: * inconsiderable cost for function calls, so...
872: */
873: if (newReg->numRects != curBand)
874: {
875: prevBand = miCoalesce (newReg, prevBand, curBand);
876: }
877:
878: /*
879: * Now see if we've hit an intersecting band. The two bands only
880: * intersect if ybot > ytop
881: */
882: ybot = min(r1->y2, r2->y2);
883: curBand = newReg->numRects;
884: if (ybot > ytop)
885: {
886: (* overlapFunc) (newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot);
887:
888: }
889:
890: if (newReg->numRects != curBand)
891: {
892: prevBand = miCoalesce (newReg, prevBand, curBand);
893: }
894:
895: /*
896: * If we've finished with a band (y2 == ybot) we skip forward
897: * in the region to the next band.
898: */
899: if (r1->y2 == ybot)
900: {
901: r1 = r1BandEnd;
902: }
903: if (r2->y2 == ybot)
904: {
905: r2 = r2BandEnd;
906: }
907: } while ((r1 != r1End) && (r2 != r2End));
908:
909: /*
910: * Deal with whichever region still has rectangles left.
911: */
912: curBand = newReg->numRects;
913: if (r1 != r1End)
914: {
915: if (nonOverlap1Func != (void (*)())NULL)
916: {
917: do
918: {
919: r1BandEnd = r1;
920: while ((r1BandEnd < r1End) && (r1BandEnd->y1 == r1->y1))
921: {
922: r1BandEnd++;
923: }
924: (* nonOverlap1Func) (newReg, r1, r1BandEnd,
925: max(r1->y1,ybot), r1->y2);
926: r1 = r1BandEnd;
927: } while (r1 != r1End);
928: }
929: }
930: else if ((r2 != r2End) && (nonOverlap2Func != (void (*)())NULL))
931: {
932: do
933: {
934: r2BandEnd = r2;
935: while ((r2BandEnd < r2End) && (r2BandEnd->y1 == r2->y1))
936: {
937: r2BandEnd++;
938: }
939: (* nonOverlap2Func) (newReg, r2, r2BandEnd,
940: max(r2->y1,ybot), r2->y2);
941: r2 = r2BandEnd;
942: } while (r2 != r2End);
943: }
944:
945: if (newReg->numRects != curBand)
946: {
947: (void) miCoalesce (newReg, prevBand, curBand);
948: }
949:
950: /*
951: * A bit of cleanup. To keep regions from growing without bound,
952: * we shrink the array of rectangles to match the new number of
953: * rectangles in the region. This never goes to 0, however...
954: *
955: * Only do this stuff if the number of rectangles allocated is more than
956: * twice the number of rectangles in the region (a simple optimization...).
957: */
958: if (newReg->numRects < (newReg->size >> 1))
959: {
960: if (REGION_NOT_EMPTY(newReg))
961: {
962: newReg->size = newReg->numRects;
963: newReg->rects = (BoxPtr) Xrealloc (newReg->rects,
964: sizeof(BoxRec) * newReg->size);
965: }
966: else
967: {
968: /*
969: * No point in doing the extra work involved in an Xrealloc if
970: * the region is empty
971: */
972: newReg->size = 1;
973: Xfree((char *) newReg->rects);
974: newReg->rects = (BoxPtr) Xmalloc(sizeof(BoxRec));
975: }
976: }
977: Xfree ((char *) oldRects);
978: }
979:
980:
981: /*======================================================================
982: * Region Union
983: *====================================================================*/
984:
985: /*-
986: *-----------------------------------------------------------------------
987: * miUnionNonO --
988: * Handle a non-overlapping band for the union operation. Just
989: * Adds the rectangles into the region. Doesn't have to check for
990: * subsumption or anything.
991: *
992: * Results:
993: * None.
994: *
995: * Side Effects:
996: * pReg->numRects is incremented and the final rectangles overwritten
997: * with the rectangles we're passed.
998: *
999: *-----------------------------------------------------------------------
1000: */
1001: /* static void*/
1002: miUnionNonO (pReg, r, rEnd, y1, y2)
1003: register Region pReg;
1004: register BoxPtr r;
1005: BoxPtr rEnd;
1006: register short y1;
1007: register short y2;
1008: {
1009: register BoxPtr pNextRect;
1010:
1011: pNextRect = &pReg->rects[pReg->numRects];
1012:
1013: assert(y1 < y2);
1014:
1015: while (r != rEnd)
1016: {
1017: assert(r->x1 < r->x2);
1018: MEMCHECK(pReg, pNextRect, pReg->rects);
1019: pNextRect->x1 = r->x1;
1020: pNextRect->y1 = y1;
1021: pNextRect->x2 = r->x2;
1022: pNextRect->y2 = y2;
1023: pReg->numRects += 1;
1024: pNextRect++;
1025:
1026: assert(pReg->numRects<=pReg->size);
1027: r++;
1028: }
1029:
1030: }
1031:
1032:
1033: /*-
1034: *-----------------------------------------------------------------------
1035: * miUnionO --
1036: * Handle an overlapping band for the union operation. Picks the
1037: * left-most rectangle each time and merges it into the region.
1038: *
1039: * Results:
1040: * None.
1041: *
1042: * Side Effects:
1043: * Rectangles are overwritten in pReg->rects and pReg->numRects will
1044: * be changed.
1045: *
1046: *-----------------------------------------------------------------------
1047: */
1048:
1049: /* static void*/
1050: miUnionO (pReg, r1, r1End, r2, r2End, y1, y2)
1051: register Region pReg;
1052: register BoxPtr r1;
1053: BoxPtr r1End;
1054: register BoxPtr r2;
1055: BoxPtr r2End;
1056: register short y1;
1057: register short y2;
1058: {
1059: register BoxPtr pNextRect;
1060:
1061: pNextRect = &pReg->rects[pReg->numRects];
1062:
1063: #define MERGERECT(r) \
1064: if ((pReg->numRects != 0) && \
1065: (pNextRect[-1].y1 == y1) && \
1066: (pNextRect[-1].y2 == y2) && \
1067: (pNextRect[-1].x2 >= r->x1)) \
1068: { \
1069: if (pNextRect[-1].x2 < r->x2) \
1070: { \
1071: pNextRect[-1].x2 = r->x2; \
1072: assert(pNextRect[-1].x1<pNextRect[-1].x2); \
1073: } \
1074: } \
1075: else \
1076: { \
1077: MEMCHECK(pReg, pNextRect, pReg->rects); \
1078: pNextRect->y1 = y1; \
1079: pNextRect->y2 = y2; \
1080: pNextRect->x1 = r->x1; \
1081: pNextRect->x2 = r->x2; \
1082: pReg->numRects += 1; \
1083: pNextRect += 1; \
1084: } \
1085: assert(pReg->numRects<=pReg->size);\
1086: r++;
1087:
1088: assert (y1<y2);
1089: while ((r1 != r1End) && (r2 != r2End))
1090: {
1091: if (r1->x1 < r2->x1)
1092: {
1093: MERGERECT(r1);
1094: }
1095: else
1096: {
1097: MERGERECT(r2);
1098: }
1099: }
1100:
1101: if (r1 != r1End)
1102: {
1103: do
1104: {
1105: MERGERECT(r1);
1106: } while (r1 != r1End);
1107: }
1108: else while (r2 != r2End)
1109: {
1110: MERGERECT(r2);
1111: }
1112: }
1113:
1114: XUnionRegion(reg1, reg2, newReg)
1115: Region reg1;
1116: Region reg2; /* source regions */
1117: Region newReg; /* destination Region */
1118: {
1119: /* checks all the simple cases */
1120:
1121: /*
1122: * Region 1 and 2 are the same or region 1 is empty
1123: */
1124: if ( (reg1 == reg2) || (!(reg1->numRects)) )
1125: {
1126: if (newReg != reg2)
1127: miRegionCopy(newReg, reg2);
1128: return(TRUE);
1129: }
1130:
1131: /*
1132: * if nothing to union (region 2 empty)
1133: */
1134: if (!(reg2->numRects))
1135: {
1136: if (newReg != reg1)
1137: miRegionCopy(newReg, reg1);
1138: return(TRUE);
1139: }
1140:
1141: /*
1142: * Region 1 completely subsumes region 2
1143: */
1144: if ((reg1->numRects == 1) &&
1145: (reg1->extents.x1 <= reg2->extents.x1) &&
1146: (reg1->extents.y1 <= reg2->extents.y1) &&
1147: (reg1->extents.x2 >= reg2->extents.x2) &&
1148: (reg1->extents.y2 >= reg2->extents.y2))
1149: {
1150: if (newReg != reg1)
1151: miRegionCopy(newReg, reg1);
1152: return(TRUE);
1153: }
1154:
1155: /*
1156: * Region 2 completely subsumes region 1
1157: */
1158: if ((reg2->numRects == 1) &&
1159: (reg2->extents.x1 <= reg1->extents.x1) &&
1160: (reg2->extents.y1 <= reg1->extents.y1) &&
1161: (reg2->extents.x2 >= reg1->extents.x2) &&
1162: (reg2->extents.y2 >= reg1->extents.y2))
1163: {
1164: if (newReg != reg2)
1165: miRegionCopy(newReg, reg2);
1166: return(TRUE);
1167: }
1168:
1169: miRegionOp (newReg, reg1, reg2, miUnionO, miUnionNonO, miUnionNonO);
1170:
1171: newReg->extents.x1 = min(reg1->extents.x1, reg2->extents.x1);
1172: newReg->extents.y1 = min(reg1->extents.y1, reg2->extents.y1);
1173: newReg->extents.x2 = max(reg1->extents.x2, reg2->extents.x2);
1174: newReg->extents.y2 = max(reg1->extents.y2, reg2->extents.y2);
1175:
1176: return(1);
1177: }
1178:
1179:
1180: /*======================================================================
1181: * Region Subtraction
1182: *====================================================================*/
1183:
1184: /*-
1185: *-----------------------------------------------------------------------
1186: * miSubtractNonO --
1187: * Deal with non-overlapping band for subtraction. Any parts from
1188: * region 2 we discard. Anything from region 1 we add to the region.
1189: *
1190: * Results:
1191: * None.
1192: *
1193: * Side Effects:
1194: * pReg may be affected.
1195: *
1196: *-----------------------------------------------------------------------
1197: */
1198: /* static void*/
1199: miSubtractNonO1 (pReg, r, rEnd, y1, y2)
1200: register Region pReg;
1201: register BoxPtr r;
1202: BoxPtr rEnd;
1203: register short y1;
1204: register short y2;
1205: {
1206: register BoxPtr pNextRect;
1207:
1208: pNextRect = &pReg->rects[pReg->numRects];
1209:
1210: assert(y1<y2);
1211:
1212: while (r != rEnd)
1213: {
1214: assert(r->x1<r->x2);
1215: MEMCHECK(pReg, pNextRect, pReg->rects);
1216: pNextRect->x1 = r->x1;
1217: pNextRect->y1 = y1;
1218: pNextRect->x2 = r->x2;
1219: pNextRect->y2 = y2;
1220: pReg->numRects += 1;
1221: pNextRect++;
1222:
1223: assert(pReg->numRects <= pReg->size);
1224:
1225: r++;
1226: }
1227: }
1228:
1229: /*-
1230: *-----------------------------------------------------------------------
1231: * miSubtractO --
1232: * Overlapping band subtraction. x1 is the left-most point not yet
1233: * checked.
1234: *
1235: * Results:
1236: * None.
1237: *
1238: * Side Effects:
1239: * pReg may have rectangles added to it.
1240: *
1241: *-----------------------------------------------------------------------
1242: */
1243: /* static void*/
1244: miSubtractO (pReg, r1, r1End, r2, r2End, y1, y2)
1245: register Region pReg;
1246: register BoxPtr r1;
1247: BoxPtr r1End;
1248: register BoxPtr r2;
1249: BoxPtr r2End;
1250: register short y1;
1251: register short y2;
1252: {
1253: register BoxPtr pNextRect;
1254: register int x1;
1255:
1256: x1 = r1->x1;
1257:
1258: assert(y1<y2);
1259: pNextRect = &pReg->rects[pReg->numRects];
1260:
1261: while ((r1 != r1End) && (r2 != r2End))
1262: {
1263: if (r2->x2 <= x1)
1264: {
1265: /*
1266: * Subtrahend missed the boat: go to next subtrahend.
1267: */
1268: r2++;
1269: }
1270: else if (r2->x1 <= x1)
1271: {
1272: /*
1273: * Subtrahend preceeds minuend: nuke left edge of minuend.
1274: */
1275: x1 = r2->x2;
1276: if (x1 >= r1->x2)
1277: {
1278: /*
1279: * Minuend completely covered: advance to next minuend and
1280: * reset left fence to edge of new minuend.
1281: */
1282: r1++;
1283: x1 = r1->x1;
1284: }
1285: else
1286: {
1287: /*
1288: * Subtrahend now used up since it doesn't extend beyond
1289: * minuend
1290: */
1291: r2++;
1292: }
1293: }
1294: else if (r2->x1 < r1->x2)
1295: {
1296: /*
1297: * Left part of subtrahend covers part of minuend: add uncovered
1298: * part of minuend to region and skip to next subtrahend.
1299: */
1300: assert(x1<r2->x1);
1301: MEMCHECK(pReg, pNextRect, pReg->rects);
1302: pNextRect->x1 = x1;
1303: pNextRect->y1 = y1;
1304: pNextRect->x2 = r2->x1;
1305: pNextRect->y2 = y2;
1306: pReg->numRects += 1;
1307: pNextRect++;
1308:
1309: assert(pReg->numRects<=pReg->size);
1310:
1311: x1 = r2->x2;
1312: if (x1 >= r1->x2)
1313: {
1314: /*
1315: * Minuend used up: advance to new...
1316: */
1317: r1++;
1318: x1 = r1->x1;
1319: }
1320: else
1321: {
1322: /*
1323: * Subtrahend used up
1324: */
1325: r2++;
1326: }
1327: }
1328: else
1329: {
1330: /*
1331: * Minuend used up: add any remaining piece before advancing.
1332: */
1333: if (r1->x2 > x1)
1334: {
1335: MEMCHECK(pReg, pNextRect, pReg->rects);
1336: pNextRect->x1 = x1;
1337: pNextRect->y1 = y1;
1338: pNextRect->x2 = r1->x2;
1339: pNextRect->y2 = y2;
1340: pReg->numRects += 1;
1341: pNextRect++;
1342: assert(pReg->numRects<=pReg->size);
1343: }
1344: r1++;
1345: x1 = r1->x1;
1346: }
1347: }
1348:
1349: /*
1350: * Add remaining minuend rectangles to region.
1351: */
1352: while (r1 != r1End)
1353: {
1354: assert(x1<r1->x2);
1355: MEMCHECK(pReg, pNextRect, pReg->rects);
1356: pNextRect->x1 = x1;
1357: pNextRect->y1 = y1;
1358: pNextRect->x2 = r1->x2;
1359: pNextRect->y2 = y2;
1360: pReg->numRects += 1;
1361: pNextRect++;
1362:
1363: assert(pReg->numRects<=pReg->size);
1364:
1365: r1++;
1366: if (r1 != r1End)
1367: {
1368: x1 = r1->x1;
1369: }
1370: }
1371: }
1372:
1373: /*-
1374: *-----------------------------------------------------------------------
1375: * miSubtract --
1376: * Subtract regS from regM and leave the result in regD.
1377: * S stands for subtrahend, M for minuend and D for difference.
1378: *
1379: * Results:
1380: * TRUE.
1381: *
1382: * Side Effects:
1383: * regD is overwritten.
1384: *
1385: *-----------------------------------------------------------------------
1386: */
1387:
1388: XSubtractRegion(regM, regS, regD)
1389: Region regM;
1390: Region regS;
1391: register Region regD;
1392: {
1393: /* check for trivial reject */
1394: if ( (!(regM->numRects)) || (!(regS->numRects)) ||
1395: (!EXTENTCHECK(®M->extents, ®S->extents)) )
1396: {
1397: miRegionCopy(regD, regM);
1398: return(1);
1399: }
1400:
1401: miRegionOp (regD, regM, regS, miSubtractO, miSubtractNonO1, NULL);
1402:
1403: if (regD->numRects != 0)
1404: {
1405: /*
1406: * Can't alter newReg's extents before we call miRegionOp because
1407: * it might be one of the source regions and miRegionOp depends
1408: * on the extents of those regions being the unaltered. Besides, this
1409: * way there's no checking against rectangles that will be nuked
1410: * due to coalescing, so we have to examine fewer rectangles.
1411: */
1412: miSetExtents (regD);
1413: }
1414: return(1);
1415: }
1416:
1417: XXorRegion( sra, srb, dr )
1418: Region sra, srb, dr;
1419: {
1420: Region tra, trb;
1421:
1422: tra = (Region)Xmalloc((unsigned) sizeof(REGION));
1423: trb = (Region)Xmalloc((unsigned) sizeof(REGION));
1424: (void) XSubtractRegion(sra,srb,tra);
1425: (void) XSubtractRegion(srb,sra,trb);
1426: (void) XUnionRegion(tra,trb,dr);
1427: }
1428:
1429: /*
1430: * Check to see if the region is empty. Assumes a region is passed
1431: * as a parameter
1432: */
1433: int
1434: XEmptyRegion( r )
1435: Region r;
1436: {
1437: if( r->size == 0 && r->numRects == 0 && r->extents.x1 == 0 &&
1438: r->extents.x2 == 0 && r->extents.y1 == 0 && r->extents.y2 ==0 )
1439: return( TRUE );
1440: else return( FALSE );
1441: }
1442:
1443: /*
1444: * Check to see if two regions are equal
1445: */
1446: int
1447: XEqualRegion( r1, r2 )
1448: Region r1, r2;
1449: {
1450: int i;
1451:
1452: if ( r1->size != r2->size ) return( FALSE );
1453: else if( r1->numRects != r2->numRects ) return( FALSE );
1454: else if ( r1->extents.x1 != r2->extents.x1 ) return( FALSE );
1455: else if ( r1->extents.x2 != r2->extents.x2 ) return( FALSE );
1456: else if ( r1->extents.y1 != r2->extents.y1 ) return( FALSE );
1457: else if ( r1->extents.y2 != r2->extents.y2 ) return( FALSE );
1458: else for( i=0; i < r1->numRects; i++ ) {
1459: if ( r1->rects[i].x1 != r2->rects[i].x1 ) return( FALSE );
1460: else if ( r1->rects[i].x2 != r2->rects[i].x2 ) return( FALSE );
1461: else if ( r1->rects[i].y1 != r2->rects[i].y1 ) return( FALSE );
1462: else if ( r1->rects[i].y2 != r2->rects[i].y2 ) return( FALSE );
1463: }
1464: return( TRUE );
1465: }
1466:
1467: int
1468: XPointInRegion( pRegion, x, y )
1469: Region pRegion;
1470: int x, y;
1471: {
1472: int i;
1473:
1474: if (pRegion->numRects == 0)
1475: return(FALSE);
1476: if (!INBOX(pRegion->extents, x, y))
1477: return(FALSE);
1478: for (i=0; i<pRegion->numRects; i++)
1479: {
1480: if (INBOX (pRegion->rects[i], x, y))
1481: return(TRUE);
1482: }
1483: return(FALSE);
1484: }
1485:
1486: int
1487: XRectInRegion(region, rx, ry, rwidth, rheight)
1488: register Region region;
1489: int rx, ry;
1490: unsigned int rwidth, rheight;
1491: {
1492: register BoxPtr pbox;
1493: register BoxPtr pboxEnd;
1494: Box rect;
1495: register BoxPtr prect = ▭
1496: int partIn, partOut;
1497:
1498: prect->x1 = rx;
1499: prect->y1 = ry;
1500: prect->x2 = rwidth + rx;
1501: prect->y2 = rheight + ry;
1502:
1503: /* this is (just) a useful optimization */
1504: if ((region->numRects == 0) || !EXTENTCHECK(®ion->extents, prect))
1505: return(RectangleOut);
1506:
1507: partOut = FALSE;
1508: partIn = FALSE;
1509:
1510: /* can stop when both partOut and partIn are TRUE, or we reach prect->y2 */
1511: for (pbox = region->rects, pboxEnd = pbox + region->numRects;
1512: pbox < pboxEnd;
1513: pbox++)
1514: {
1515:
1516: if (pbox->y2 <= ry)
1517: continue; /* getting up to speed or skipping remainder of band */
1518:
1519: if (pbox->y1 > ry)
1520: {
1521: partOut = TRUE; /* missed part of rectangle above */
1522: if (partIn || (pbox->y1 >= prect->y2))
1523: break;
1524: ry = pbox->y1; /* x guaranteed to be == prect->x1 */
1525: }
1526:
1527: if (pbox->x2 <= rx)
1528: continue; /* not far enough over yet */
1529:
1530: if (pbox->x1 > rx)
1531: {
1532: partOut = TRUE; /* missed part of rectangle to left */
1533: if (partIn)
1534: break;
1535: }
1536:
1537: if (pbox->x1 < prect->x2)
1538: {
1539: partIn = TRUE; /* definitely overlap */
1540: if (partOut)
1541: break;
1542: }
1543:
1544: if (pbox->x2 >= prect->x2)
1545: {
1546: ry = pbox->y2; /* finished with this band */
1547: if (ry >= prect->y2)
1548: break;
1549: rx = prect->x1; /* reset x out to left again */
1550: } else
1551: {
1552: /*
1553: * Because boxes in a band are maximal width, if the first box
1554: * to overlap the rectangle doesn't completely cover it in that
1555: * band, the rectangle must be partially out, since some of it
1556: * will be uncovered in that band. partIn will have been set true
1557: * by now...
1558: */
1559: partOut = TRUE;
1560: break;
1561: }
1562:
1563: }
1564:
1565: return(partIn ? ((ry < prect->y2) ? RectanglePart : RectangleIn) :
1566: RectangleOut);
1567: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.