Files
Arquivotheca.SunOS-4.1.4/usr.lib/libsunwindow/rect/rectlist.c
seta75D ff309bfe1c Init
2021-10-11 18:37:13 -03:00

727 lines
16 KiB
C

#ifndef lint
#ifdef sccs
static char sccsid[] = "@(#)rectlist.c 1.1 94/10/31 Copyr 1984 Sun Micro";
#endif
#endif
/*
* Copyright (c) 1984 by Sun Microsystems, Inc.
*/
/*
* Overview: Implements the interface to the data structure called
* a rectlist which is a list of rectangles.
*/
#include <sunwindow/rect.h>
#include <sunwindow/rectlist.h>
#ifndef KERNEL
#include <stdio.h>
#define RNTABLEINC 30
#else
#include <sys/param.h>
extern caddr_t kmem_zalloc();
#define RNTABLEINC NBPG/(sizeof(struct rectnode))
#endif
int rnTableIndex;
int rnTableOverflowed;
struct rectnode *rnTable; /* Array of alloced but not used nodes */
struct rectnode *rnFree; /* List of free nodes */
/*
* rectlist constants
*/
extern struct rectlist rl_null;
#define rnptr_null (struct rectnode *)0
struct rectnode *_rl_getrectnode(), **_rl_removerectnode();
bool rl_boundintersectsrect();
#ifndef KERNEL
/*
* rectlist geometry functions
*/
bool
rl_includespoint(rl, x, y)
register struct rectlist *rl;
coord x, y;
{
register struct rectnode *rn;
rl_coordoffset(rl, &x, &y);
if (rect_includespoint(&rl->rl_bound, x, y))
for (rn = rl->rl_head; rn; rn = rn->rn_next) {
if (rect_includespoint(&rn->rn_rect, x, y))
return (TRUE);
}
return (FALSE);
}
#endif !KERNEL
rl_intersection(rl1, rl2, rl)
register struct rectlist *rl1, *rl2, *rl;
{
struct rect r;
register struct rectnode *rn;
struct rectlist rltemp;
struct rectlist rlresult;
rltemp = rl_null;
rlresult = rl_null;
rl_rectoffset(rl1, &rl1->rl_bound, &r);
if (rl_boundintersectsrect(&r, rl2))
/*
* For each Rect in rl1 intersect with each Rect in rl2
*/
for (rn = rl1->rl_head; rn; rn = rn->rn_next) {
rl_rectoffset(rl1, &rn->rn_rect, &r);
(void)rl_rectintersection(&r, rl2, &rltemp);
_rl_append(&rlresult, &rltemp);
rltemp = rl_null; /* because appRLs consumed rltemp */
}
(void)rl_free(rl);
*rl = rlresult;
}
#ifndef KERNEL
rl_sort(rl1, rl, sortorder)
register struct rectlist *rl1, *rl;
int sortorder;
{
struct rectlist rltemp; /* Extract 'most' rect one at a time */
struct rectlist rlresult; /* Put 'most' rect here as pull off rltemp */
struct rectnode *rnTemp; /* Source index */
struct rectnode *rnResult; /* Result index */
struct rectnode *rnMost; /* Temp result index */
struct rect rMost, rtemp;
rltemp = rl_null;
rlresult = rl_null;
(void)rl_copy(rl1, &rlresult); /* Result same as input */
if (rl1 == rl)
rltemp = *rl; /* Cause will overwrite anyway */
else
(void)rl_copy(rl1, &rltemp); /* Don't damage input */
for (rnResult = rlresult.rl_head; rnResult;
rnResult = rnResult->rn_next) {
rnMost = NULL;
rMost = rect_null;
for (rnTemp = rltemp.rl_head; rnTemp; rnTemp = rnTemp->rn_next) {
if (rect_equal(&rnTemp->rn_rect, &rect_null))
continue; /* Already extracted this item */
if (rnMost == NULL) { /* Something to compare with */
rnMost = rnTemp;
rMost = rnMost->rn_rect;
continue;
}
rtemp = rnTemp->rn_rect;
if (rect_order(&rtemp, &rMost, sortorder)==TRUE) {
rnMost = rnTemp;
rMost = rtemp;
}
}
if (rnMost == NULL)
break; /* sorted all items */
rnResult->rn_rect = rMost;
rnMost->rn_rect = rect_null; /* Don't compare this item again */
}
(void)rl_free(rl);
*rl = rlresult;
}
#endif !KERNEL
rl_union(rl1, rl2, rl)
register struct rectlist *rl1, *rl2, *rl;
{
if (rl1 == rl)
_rl_union(rl, rl2);
else if (rl2 == rl)
_rl_union(rl, rl1);
else {
(void)rl_copy(rl1, rl);
_rl_union(rl, rl2);
}
}
rl_difference(rl1, rl2, rl)
register struct rectlist *rl1, *rl2, *rl;
{
struct rect r;
register struct rectnode *rn;
(void)rl_copy(rl1, rl);
rl_rectoffset(rl, &rl->rl_bound, &r);
if (rl_boundintersectsrect(&r, rl2)) {
/*
* For each Rect in rl2 remove from rl
*/
for (rn = rl2->rl_head; rn; rn = rn->rn_next) {
rl_rectoffset(rl2, &rn->rn_rect, &r);
_rl_removerect(&r, rl);
}
_rl_makebound(rl);
}
}
bool
rl_empty(rl)
register struct rectlist *rl;
{
register struct rectnode *rn;
if (rect_isnull(&(rl->rl_bound)))
return (TRUE);
for (rn = rl->rl_head; rn; rn = rn->rn_next) {
if (!rect_isnull(&(rn->rn_rect)))
return (FALSE);
}
return (TRUE);
}
bool
rl_equal(rl1, rl2)
register struct rectlist *rl1, *rl2;
{ register struct rectnode *rn1, *rn2;
if (!rect_equal(&rl1->rl_bound, &rl2->rl_bound) ||
rl1->rl_x!=rl2->rl_x || rl1->rl_y!=rl2->rl_y)
return (FALSE);
rn2 = rl2->rl_head;
for (rn1 = rl1->rl_head; ; rn1 = rn1->rn_next) {
if (rn1==NULL && rn2==NULL)
return (TRUE);
if (rn1==NULL || rn2==NULL)
return (FALSE);
if (!rect_equal(&rn1->rn_rect, &rn2->rn_rect))
return (FALSE);
rn2 = rn2->rn_next;
}
}
#ifndef KERNEL
/*
* rectlist with Rect geometry functions
*/
bool
rl_equalrect(r, rl)
register struct rect *r;
register struct rectlist *rl;
{
struct rect rtemp;
rl_rectoffset(rl, &rl->rl_bound, &rtemp);
if (rect_equal(r, &rtemp) && rl->rl_head == rl->rl_tail)
return (TRUE);
else
return (FALSE);
}
#endif !KERNEL
bool
rl_boundintersectsrect(r, rl)
register struct rect *r;
register struct rectlist *rl;
{
struct rect rtemp;
rl_rectoffset(rl, &rl->rl_bound, &rtemp);
return (rect_intersectsrect(&rtemp, r));
}
bool
rl_rectintersects(r, rl)
register struct rect *r;
register struct rectlist *rl;
{
struct rectnode *rn;
struct rect r1;
if (rl_boundintersectsrect(r, rl))
/* For each Rect in rl intersect with r */
for (rn = rl->rl_head; rn; rn = rn->rn_next) {
rl_rectoffset(rl, &rn->rn_rect, &r1);
if (rect_intersectsrect(r, &r1))
return (TRUE);
}
return (FALSE);
}
rl_rectintersection(r, rl1, rl)
register struct rect *r;
register struct rectlist *rl1, *rl;
{
struct rectnode *rn;
struct rect r1, rtemp;
struct rectlist rlresult;
rlresult = rl_null;
if (rl_boundintersectsrect(r, rl1))
/* For each Rect in rl1 intersect with r */
for (rn = rl1->rl_head; rn; rn = rn->rn_next) {
rl_rectoffset(rl1, &rn->rn_rect, &r1);
(void)rect_intersection(r, &r1, &rtemp);
_rl_appendrect(&rtemp, &rlresult);
}
(void)rl_free(rl);
*rl = rlresult;
}
rl_rectunion(r, rl1, rl)
register struct rect *r;
register struct rectlist *rl1, *rl;
{
struct rectlist rlresult;
struct rect rtemp;
register struct rectnode *rn;
rlresult = rl_null;
_rl_appendrect(r, &rlresult);
if (rl_boundintersectsrect(r, rl1))
for (rn = rl1->rl_head; rn; rn = rn->rn_next) {
rl_rectoffset(rl1, &rn->rn_rect, &rtemp);
_rl_removerect(&rtemp, &rlresult);
}
(void)rl_copy(rl1, rl);
_rl_append(rl, &rlresult);
}
rl_rectdifference(r, rl1, rl)
register struct rect *r;
register struct rectlist *rl1, *rl;
{
struct rect rtemp;
struct rectlist rltemp;
register struct rectnode *rn;
if (rect_isnull(r))
(void)rl_copy(rl1, rl);
else if (_rl_equal(rl1, &rl_null))
(void)rl_free(rl);
else {
if (rl1 == rl)
_rl_removerect(r, rl);
else {
(void)rl_free(rl);
for (rn = rl1->rl_head; rn; rn = rn->rn_next) {
rl_rectoffset(rl1,&rn->rn_rect, &rtemp);
rltemp = rl_null;
_rl_difrects(&rtemp, r, &rltemp);
_rl_append(rl, &rltemp);
}
}
_rl_makebound(rl);
}
}
/*
* rectlist initialization functions
*/
rl_initwithrect(r, rl)
register struct rect *r;
struct rectlist *rl;
{
*rl = rl_null;
_rl_appendrect(r, rl);
}
/*
* rectlist List Memory Management functions
*/
rl_copy(rl1, rl)
register struct rectlist *rl1, *rl;
{
register struct rectnode *rn;
if (rl1 != rl) {
(void)rl_free(rl);
*rl= *rl1;
rl->rl_head = 0;
rl->rl_tail = 0;
for (rn = rl1->rl_head; rn; rn = rn->rn_next)
_rl_appendrect(&rn->rn_rect, rl);
}
}
rl_free(rl)
register struct rectlist *rl;
{
register struct rectnode *rn, *rn_next, *rn_last = (struct rectnode *)0;
for (rn = rl->rl_head; rn; rn = rn_next) {
rn_next = rn->rn_next;
_rl_freerectnode(rn);
rn_last = rn;
}
if (rn_last != rl->rl_tail) {
#ifdef KERNEL
(void)printf("Malformed rl in rl_free in KERNEL\n");
#else
(void)fprintf(stderr, "Malformed rl in rl_free\n");
#endif
}
*rl = rl_null;
}
rl_coalesce(rl)
register struct rectlist *rl;
{
struct rectnode *rn;
struct rect rbound;
register int area = 0;
/*
* If already one rect in list then can't do any better.
*/
if (rl->rl_head == rl->rl_tail)
return;
/*
* Sum area in rect list
*/
for (rn = rl->rl_head; rn; rn = rn->rn_next) {
area += rn->rn_rect.r_width*rn->rn_rect.r_height;
}
/*
* If area of list = area of rl_bound then make a single entry list
*/
rl_rectoffset(rl, &rl->rl_bound, &rbound);
if (area == (rbound.r_width*rbound.r_height)) {
(void)rl_free(rl);
(void)rl_initwithrect(&rbound, rl);
}
}
rl_normalize(rl)
register struct rectlist *rl;
{
struct rectnode *rn;
if (rl->rl_x == 0 && rl->rl_y == 0)
return;
rl_rectoffset(rl, &rl->rl_bound, &rl->rl_bound);
for (rn = rl->rl_head; rn; rn = rn->rn_next) {
rl_rectoffset(rl, &rn->rn_rect, &rn->rn_rect);
}
rl->rl_x = 0;
rl->rl_y = 0;
}
#ifdef notdef
/* Debug Utilities */
rl_print(rl, tag)
struct rectlist *rl;
char *tag;
{
struct rectnode *rn;
#ifdef KERNEL
(void)printf(
#else
(void)fprintf(stderr,
#endif
"%s: Bounding ", tag);
rect_print(&rl->rl_bound);
#ifdef KERNEL
(void)printf(
#else
(void)fprintf(stderr,
#endif
"\n\t");
for (rn = rl->rl_head; rn; rn = rn->rn_next) {
rect_print(&rn->rn_rect);
#ifdef KERNEL
(void)printf(
#else
(void)fprintf(stderr,
#endif
"\n\t");
}
#ifdef KERNEL
(void)printf(
#else
(void)fprintf(stderr,
#endif
"using these offsets: x=%d, y=%d \n", rl->rl_x, rl->rl_y);
}
#endif /* notdef */
/*
* Private Routines
*/
/*
* Create node for r and app to rl
*/
_rl_appendrect(r, rl)
register struct rect *r;
register struct rectlist *rl;
{
register struct rectnode *rn;
if (rect_isnull(r))
return;
rn = _rl_getrectnode(r);
_rl_appendrectnode(rl, rn);
}
_rl_append(rlBase, rlAdd)
struct rectlist *rlBase, *rlAdd;
{
struct rect r;
struct rectnode *rn, *rn_next;
for (rn = rlAdd->rl_head; rn; rn = rn_next) {
rl_rectoffset(rlAdd, &rn->rn_rect, &r);
rl_coordoffset(rlBase, &r.r_left, &r.r_top);
rn->rn_rect.r_left = r.r_left;
rn->rn_rect.r_top = r.r_top;
rn_next = rn->rn_next;
_rl_appendrectnode(rlBase, rn); /* Modifies rn->rn_next */
}
}
struct rectnode *
_rl_getrectnode(r)
register struct rect *r;
{
register struct rectnode *rn;
if (!rnFree) {
/* free list empty, alloc from table */
if (!rnTable || rnTableIndex == RNTABLEINC) { /* table empty */
#ifdef KERNEL
/*
* Alloc only scheme (no freeing yet)
*/
rnTable = (struct rectnode *)kmem_zalloc(
RNTABLEINC * sizeof (struct rectnode));
if (rnTable == 0)
(void)printf("Kernel: couldn't allocate rnTable!\n");
#ifdef notdef /* Old non-dynamic stuff (RNTABLEINC was 1000) */
if (!rnTable)
rnTable = &rnKernTable[0];
else
(void)printf("rnTable overflow in _rl_getrectnode!");
/* Note: Add dynamic memory allocation here */
#endif notdef
#else
/*
* Alloc only scheme (no freeing yet)
*/
rnTable = (struct rectnode *) sv_calloc(
1, RNTABLEINC*sizeof(struct rectnode));
#endif KERNEL
rnTableOverflowed++;
rnTableIndex = 0;
}
rn = rnTable+rnTableIndex;
rnTableIndex++;
} else {
rn = rnFree;
rnFree = rnFree->rn_next;
}
rn->rn_next = rnptr_null;
rn->rn_rect = *r;
return (rn);
}
_rl_appendrectnode(rl, rn)
register struct rectlist *rl;
register struct rectnode *rn;
{
/* Fix up list pointers */
if (!rl->rl_head)
rl->rl_head = rn;
if (rl->rl_tail)
rl->rl_tail->rn_next = rn;
rl->rl_tail = rn;
rn->rn_next = 0;
/* Fix up rl->rl_bound */
rl->rl_bound = rect_bounding(&rn->rn_rect, &rl->rl_bound);
}
_rl_makebound(rl)
struct rectlist *rl;
{
struct rectnode *rn;
rl->rl_bound = rect_null;
for (rn = rl->rl_head; rn; rn = rn->rn_next)
rl->rl_bound = rect_bounding(&rl->rl_bound, &rn->rn_rect);
rl_coordoffset(rl, &rl->rl_bound.r_left, &rl->rl_bound.r_top);
}
_rl_difrects(r1, r2, rl)
register struct rect *r1, *r2;
register struct rectlist *rl;
/*
* Assuming this r1 and r2 intersect, place r1-r2 in rl.
* Doesn't free rl.
* rl may be unaffected if r1 is completely contained in r2.
*/
{
struct rect r;
struct rect r1L;
r1L = *r1;
/* Identify an included upper rect */
if (r1L.r_top < r2->r_top) {
rect_construct(&r, r1L.r_left, r1L.r_top, r1L.r_width,
(r2->r_top - r1L.r_top));
_rl_appendrect(&r, rl);
r1L.r_height -= (r2->r_top - r1L.r_top);
r1L.r_top = r2->r_top;
}
/* Identify an included lower rect */
if (rect_bottom(&r1L) > rect_bottom(r2)) {
rect_construct(&r, r1L.r_left, rect_bottom(r2)+1, r1L.r_width,
(rect_bottom(&r1L)-rect_bottom(r2)));
_rl_appendrect(&r, rl);
r1L.r_height -= (rect_bottom(&r1L) - rect_bottom(r2));
}
/* Identify an included r_left rect */
if (r1L.r_left < r2->r_left) {
rect_construct(&r, r1L.r_left, r1L.r_top,
r2->r_left - r1L.r_left, r1L.r_height);
_rl_appendrect(&r, rl);
}
/* Identify an included right rect */
if (rect_right(&r1L) > rect_right(r2)) {
rect_construct(&r, rect_right(r2)+1, r1L.r_top,
(rect_right(&r1L)-rect_right(r2)), r1L.r_height);
_rl_appendrect(&r, rl);
}
}
_rl_equal(rl1, rl2)
register struct rectlist *rl1, *rl2;
{
if (rl1->rl_x == rl2->rl_x && rl1->rl_y == rl2->rl_y &&
rl1->rl_head == rl2->rl_head && rl1->rl_tail == rl2->rl_tail &&
rect_equal(&rl1->rl_bound, &rl2->rl_bound))
return (TRUE);
else
return (FALSE);
}
_rl_freerectnode(rn)
register struct rectnode *rn;
{
rn->rn_next = rnFree;
rnFree = rn;
}
_rl_removerect(r, rl)
register struct rect *r;
register struct rectlist *rl;
{
struct rectnode **rnPtr, **rn_nextPtr;
struct rectlist rltemp;
struct rect rtemp;
if (rl->rl_head == 0)
return;
for (rnPtr = &(rl->rl_head); *rnPtr; rnPtr = rn_nextPtr) {
rl_rectoffset(rl, &((*rnPtr)->rn_rect), &rtemp);
rn_nextPtr = &((*rnPtr)->rn_next);
if (rect_intersectsrect(r, &rtemp)) {
rltemp = rl_null;
_rl_difrects(&rtemp, r, &rltemp);
if (rltemp.rl_head != rnptr_null)
_rl_replacernbyrl(rl, *rnPtr, &rltemp);
else {
/* Remove rn from rl */
rn_nextPtr = _rl_removerectnode(rl, rnPtr);
if (rn_nextPtr == 0)
break;
}
}
}
}
_rl_union(rlBase, rlAdd)
register struct rectlist *rlBase, *rlAdd;
{
register struct rectnode *rn;
struct rect r;
for (rn = rlAdd->rl_head; rn; rn = rn->rn_next) {
rl_rectoffset(rlAdd, &rn->rn_rect, &r);
(void)rl_rectunion(&r, rlBase, rlBase);
}
}
struct rectnode **
_rl_removerectnode(rl, rnPtr)
struct rectlist *rl;
struct rectnode **rnPtr;
{
struct rectnode *rnAxe, **rn_nextPtr;
if (rl->rl_head == rl->rl_tail) {
(void)rl_free(rl);
return (0);
} else {
rnAxe = *rnPtr;
rn_nextPtr = rnPtr;
*rn_nextPtr = rnAxe->rn_next;
if (rl->rl_tail == rnAxe)
rl->rl_tail = (struct rectnode *)rn_nextPtr;
/*
* Note: Can get away with the above cast only because
* rn_next pointers are the first fields in
* struct rectnode and the case where *rn_nextPtr is the
* header is handled in the first test in this function.
*/
_rl_freerectnode(rnAxe);
return (rn_nextPtr);
}
}
_rl_replacernbyrl(rlBase, rnAxe, rlAdd)
register struct rectlist *rlBase;
register struct rectnode *rnAxe;
register struct rectlist *rlAdd;
/*
* WARNING: rlBase.rl_bound remains unchanged.
* If replaced data possibly invalidates rlBase.rl_bound then
* need to eventually explicitely bound rlBase
*/
{
register struct rectnode *rn;
/* Adjust offsets of rlAdd */
if (rlAdd->rl_x != rlBase->rl_x ||
rlAdd->rl_y != rlBase->rl_y)
/* Modify values of rlAdd to be compatible with rlBase offset */
for (rn = rlAdd->rl_head; rn; rn = rn->rn_next) {
rl_rectoffset(rlAdd, &rn->rn_rect, &rn->rn_rect);
rl_coordoffset(rlBase,
&rn->rn_rect.r_left,&rn->rn_rect.r_top);
}
/* Insert rlAdd in place of rnAxe in rlBase */
if ((rlBase->rl_tail == rnAxe) && (rlAdd->rl_tail != rlAdd->rl_head))
rlBase->rl_tail = rlAdd->rl_tail;
rlAdd->rl_tail->rn_next = rnAxe->rn_next;
*rnAxe = *rlAdd->rl_head;
_rl_freerectnode(rlAdd->rl_head);
}