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