|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T o
Length: 12683 (0x318b)
Types: TextFile
Names: »overlap.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki
└─⟦526ad3590⟧ »EUUGD11/gnu-31mar87/X.V10.R4.tar.Z«
└─⟦2109abc41⟧
└─⟦this⟧ »./X.V10R4/X/overlap.c«
#include <X/mit-copyright.h>
/* Copyright Massachusetts Institute of Technology 1985 */
/* Routines to calculate how rectangles overlap and abut:
*
* Calc_overlaps, Do_overlap,
* Clip_raster, Clip_rectangle, Rec_intersection,
* Merge_vertical, Merge_rectangles
*/
#ifndef lint
static char *rcsid_overlap_c = "$Header: overlap.c,v 10.6 86/02/01 15:16:58 tony Rel $";
#endif
#include "Xint.h"
extern RECTANGLE *free_rectangles;
RECTANGLE **Do_overlap(), *Alloc_rectangle();
/* Calc_overlaps figures out how raster rast overlaps rectangles rects and
* recreates in rects a list of the maximally wide visible rectangles.
* It returns 0 if no overlap, 1 if overlap.
*/
int Calc_overlaps (rast, rects)
register RASTER *rast;
register RECTANGLE **rects;
{
register RECTANGLE *rbot, **prev;
int obscured;
obscured = 0;
prev = rects;
/* Go through the bottom rectangles and see which are obscured */
while (rbot = *prev) {
if (rast->left >= rbot->right || rbot->left >= rast->right ||
rast->top >= rbot->bottom || rbot->top >= rast->bottom) {
prev = &rbot->next;
} else {
prev = Do_overlap (rast, prev, rects);
FREERECT(rbot);
obscured = 1;
}
}
return (obscured);
}
/* Do_overlap figures out how raster front overlaps rectangle *prev and
* replaces *prev in recs with a list of the maximally wide visible
* rectangles. Returns an updated list pointer that points to *prev->next.
*/
RECTANGLE **Do_overlap (front, prev, recs)
register RASTER *front;
register RECTANGLE **prev;
RECTANGLE **recs;
{
register RECTANGLE *back, *r;
int overlap;
back = *prev;
*prev = back->next;
overlap = 0;
if (front->right < back->right) overlap += 8;
if (front->left > back->left) overlap += 4;
if (front->bottom < back->bottom) overlap += 2;
if (front->top > back->top) overlap += 1;
switch (overlap) {
case 0: /* Top completely covers bottom */
goto done;
/* In the next four cases the bottom shows in one rectangle. */
case 1: /* Back peeks out on top */
NEWRECT(r, back->left, back->right,
back->top, front->top, back->type);
break;
case 2: /* ...on bottom */
NEWRECT(r, back->left, back->right,
front->bottom, back->bottom, back->type);
break;
case 4: /* ...on left */
NEWRECT(r, back->left, front->left,
back->top, back->bottom, back->type);
*prev = back;
if TRUE(Merge_vertical (r, recs, 1))
goto refind;
break;
case 8: /* ...on right */
NEWRECT(r, front->right, back->right,
back->top, back->bottom, back->type);
*prev = back;
if TRUE(Merge_vertical (r, recs, 1))
goto refind;
break;
/* Now we have the cases where there are 2 rectangles */
case 3: /* ...on top & bottom */
NEWRECT(r, back->left, back->right,
back->top, front->top, back->type);
*prev = r;
prev = &r->next;
NEWRECT(r, back->left, back->right,
front->bottom, back->bottom, back->type);
break;
case 5: /* ...on top & left */
NEWRECT(r, back->left, back->right,
back->top, front->top, back->type);
r->next = *prev;
*prev = r;
prev = &r->next;
NEWRECT(r, back->left, front->left,
front->top, back->bottom, back->type);
if TRUE(Merge_vertical (r, recs, 0))
goto done;
break;
case 6: /* ...on bottom & left */
NEWRECT(r, back->left, back->right,
front->bottom, back->bottom, back->type);
r->next = *prev;
*prev = r;
prev = &r->next;
NEWRECT(r, back->left, front->left,
back->top, front->bottom, back->type);
if TRUE(Merge_vertical (r, recs, 0))
goto done;
break;
case 9: /* ...on top & right */
NEWRECT(r, back->left, back->right,
back->top, front->top, back->type);
r->next = *prev;
*prev = r;
prev = &r->next;
NEWRECT(r, front->right, back->right,
front->top, back->bottom, back->type);
if TRUE(Merge_vertical (r, recs, 0))
goto done;
break;
case 10: /* ...on bottom & right */
NEWRECT(r, back->left, back->right,
front->bottom, back->bottom, back->type);
r->next = *prev;
*prev = r;
prev = &r->next;
NEWRECT(r, front->right, back->right,
back->top, front->bottom, back->type);
if TRUE(Merge_vertical (r, recs, 0))
goto done;
break;
case 12: /* ...on left & right */
NEWRECT(r, back->left, front->left,
back->top, back->bottom, back->type);
*prev = back;
if TRUE(Merge_vertical (r, recs, 1)) {
/* refind insertion point */
prev = recs;
while ((r = *prev) != back)
prev = &r->next;
NEWRECT(r, front->right, back->right,
back->top, back->bottom, back->type);
if TRUE(Merge_vertical (r, recs, 1))
goto refind;
} else {
r->next = back->next;
*prev = r;
prev = &r->next;
NEWRECT(r, front->right, back->right,
back->top, back->bottom, back->type);
if TRUE(Merge_vertical (r, recs, 1))
goto done;
}
break;
/* Now the cases where there are 3 rectangles */
case 7: /* ...top, bottom, & left */
NEWRECT(r, back->left, front->left,
front->top, front->bottom, back->type);
*prev = r;
prev = &r->next;
NEWRECT(r, back->left, back->right,
back->top, front->top, back->type);
*prev = r;
prev = &r->next;
NEWRECT(r, back->left, back->right,
front->bottom, back->bottom, back->type);
break;
case 11: /* ...top, bottom, & right */
NEWRECT(r, front->right, back->right,
front->top, front->bottom, back->type);
*prev = r;
prev = &r->next;
NEWRECT(r, back->left, back->right,
back->top, front->top, back->type);
*prev = r;
prev = &r->next;
NEWRECT(r, back->left, back->right,
front->bottom, back->bottom, back->type);
break;
case 13: /* ...top, left, & right */
NEWRECT(r, back->left, back->right,
back->top, front->top, back->type);
r->next = *prev;
*prev = r;
prev = &r->next;
NEWRECT(r, back->left, front->left,
front->top, back->bottom, back->type);
if FALSE(Merge_vertical (r, recs, 0)) {
r->next = *prev;
*prev = r;
prev = &r->next;
}
NEWRECT(r, front->right, back->right,
front->top, back->bottom, back->type);
if TRUE(Merge_vertical (r, recs, 0))
goto done;
break;
case 14: /* ...left, right, & bottom */
NEWRECT(r, back->left, back->right,
front->bottom, back->bottom, back->type);
r->next = *prev;
*prev = r;
prev = &r->next;
NEWRECT(r, back->left, front->left,
back->top, front->bottom, back->type);
if FALSE(Merge_vertical (r, recs, 0)) {
r->next = *prev;
*prev = r;
prev = &r->next;
}
NEWRECT(r, front->right, back->right,
back->top, front->bottom, back->type);
if TRUE(Merge_vertical (r, recs, 0))
goto done;
break;
/* And the case where there are 4 rectangles */
case 15: /* ...left, right, top, & bottom */
NEWRECT(r, back->left, back->right,
back->top, front->top, back->type);
*prev = r;
prev = &r->next;
NEWRECT(r, back->left, front->left,
front->top, front->bottom, back->type);
*prev = r;
prev = &r->next;
NEWRECT(r, front->right, back->right,
front->top, front->bottom, back->type);
*prev = r;
prev = &r->next;
NEWRECT(r, back->left, back->right,
front->bottom, back->bottom, back->type);
break;
}
r->next = back->next;
*prev = r;
return (&r->next);
refind: /* refind insertion point */
prev = recs;
while ((r = *prev) != back)
prev = &r->next;
*prev = back->next;
done: return (prev);
}
/* Clip_raster modifies raster1 so that it all fits in raster2.
*/
Clip_raster (rast1, rast2)
register RASTER *rast1, *rast2;
{
if (rast1->right > rast2->right)
rast1->right = rast2->right;
if (rast1->left < rast2->left)
rast1->left = rast2->left;
if (rast1->bottom > rast2->bottom)
rast1->bottom = rast2->bottom;
if (rast1->top < rast2->top)
rast1->top = rast2->top;
if (rast1->left >= rast1->right ||
rast1->top >= rast1->bottom) {
rast1->right = rast1->left;
rast1->bottom = rast1->top;
}
}
/* Rec_intersection returns a rectangle which is the intersection of its
* 2 arguments. If they don't interesect, it returns NULL.
*/
RECTANGLE *Rec_intersection (rec1, rec2)
register RECTANGLE *rec1, *rec2;
{
register int l, r, t, b;
l = max(rec1->left, rec2->left);
r = min(rec1->right, rec2->right);
t = max(rec1->top, rec2->top);
b = min(rec1->bottom, rec2->bottom);
if (l >= r || t >= b)
return (NULL);
NEWRECT(rec1, l, r, t, b, new_rec);
return (rec1);
}
/* Clips a rectangle to fit in a raster. Returns 0 if part of the rectangle
* is inside, else frees the rectangle and returns 1.
*/
int Clip_rectangle (rect, rast)
register RECTANGLE *rect;
register RASTER *rast;
{
if (rect->left < rast->left)
rect->left = rast->left;
if (rect->right > rast->right)
rect->right = rast->right;
if (rect->top < rast->top)
rect->top = rast->top;
if (rect->bottom > rast->bottom)
rect->bottom = rast->bottom;
if (rect->left < rect->right &&
rect->top < rect->bottom)
return (0);
FREERECT(rect);
return (1);
}
/* Merge_vertical tries to find a rectangle in the list that abuts above or
* below with rec, and merges rec into it. If bothsides is non-zero, the
* merge might allow a further merge with an existing rectangle in the list,
* and if so, the earlier rectangle is merged into the later rectangle in
* the list. Returns 1 if a merge was made, else 0.
*/
Merge_vertical (rec, list, bothsides)
register RECTANGLE *rec, **list;
int bothsides;
{
register RECTANGLE *r;
r = *list;
while (1) {
if (r->type == rec->type &&
r->left == rec->left && r->right == rec->right) {
if (r->top == rec->bottom) {
r->top = rec->top;
FREERECT(rec);
if FALSE(bothsides)
return (1);
break;
} else if (r->bottom == rec->top) {
r->bottom = rec->bottom;
FREERECT(rec);
if FALSE(bothsides)
return (1);
break;
}
}
if ((r = r->next) == NULL)
return (0);
}
rec = r;
while (r = r->next) {
if (r->type == rec->type &&
r->left == rec->left && r->right == rec->right) {
if (r->top == rec->bottom)
r->top = rec->top;
else if (r->bottom == rec->top)
r->bottom = rec->bottom;
else
continue;
while ((r = *list) != rec)
list = &r->next;
*list = rec->next;
FREERECT(rec);
return (1);
}
}
return (1);
}
/* Merge_rectangles merges one list of rectangles into another. It may also
* resize rectangles to get wide rather than tall rectangles. It makes
* multiple passes since doing some merges may enable others to be made.
* Since the lists might be long, you would think sorting would help, but
* sorting actually seems to run slower.
*/
Merge_rectangles (r1, recs)
register RECTANGLE *r1, **recs;
{
register RECTANGLE *r2, **prev;
while (1) {
prev = recs;
while (r2 = *prev) {
if (r1->type != r2->type) {
prev = &r2->next;
continue;
}
if (r1->top == r2->top) {
if (r1->right == r2->left) {
if (r1->bottom == r2->bottom) {
r1->right = r2->right;
goto free;
} else if (r1->bottom < r2->bottom) {
r1->right = r2->right;
r2->top = r1->bottom;
goto remerge;
} else {
r1->top = r2->bottom;
r2->left = r1->left;
goto remerge;
}
} else if (r1->left == r2->right) {
if (r1->bottom == r2->bottom) {
r1->left = r2->left;
goto free;
} else if (r1->bottom < r2->bottom) {
r1->left = r2->left;
r2->top = r1->bottom;
goto remerge;
} else {
r1->top = r2->bottom;
r2->right = r1->right;
goto remerge;
}
}
} else if (r1->bottom == r2->bottom) {
if (r1->right == r2->left) {
if (r1->top < r2->top) {
r2->left = r1->left;
r1->bottom = r2->top;
goto remerge;
} else {
r1->right = r2->right;
r2->bottom = r1->top;
goto remerge;
}
} else if (r1->left == r2->right) {
if (r1->top < r2->top) {
r2->right = r1->right;
r1->bottom = r2->top;
goto remerge;
} else {
r1->left = r2->left;
r2->bottom = r1->top;
goto remerge;
}
}
} else if (r1->left == r2->left && r1->right == r2->right) {
if (r1->bottom == r2->top) {
r1->bottom = r2->bottom;
goto free;
} else if (r1->top == r2->bottom) {
r1->top = r2->top;
goto free;
}
}
prev = &r2->next;
continue;
free: *prev = r2->next;
FREERECT(r2);
prev = recs;
continue;
remerge: *prev = r2->next;
r2->next = r1;
r1 = r2;
prev = recs;
}
*prev = r1;
if ((r2 = r1->next) == NULL)
return;
r1->next = NULL;
r1 = r2;
}
}