📄 trconstr.cpp
字号:
/*----------------------------------------------------------------------------
_ _ _
/\ | | | (_)
/ \ _ __ __| |_ __ ___ _ __ ___ ___ __| |_ __ _
/ /\ \ | '_ \ / _` | '__/ _ \| '_ ` _ \ / _ \/ _` | |/ _` |
/ ____ \| | | | (_| | | | (_) | | | | | | __/ (_| | | (_| |
/_/ \_\_| |_|\__,_|_| \___/|_| |_| |_|\___|\__,_|_|\__,_|
The contents of this file are subject to the Andromedia Public
License Version 1.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of
the License at http://www.andromedia.com/APL/
Software distributed under the License is distributed on an
"AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
implied. See the License for the specific language governing
rights and limitations under the License.
The Original Code is Pueblo client code, released November 4, 1998.
The Initial Developer of the Original Code is Andromedia Incorporated.
Portions created by Andromedia are Copyright (C) 1998 Andromedia
Incorporated. All Rights Reserved.
Andromedia Incorporated 415.365.6700
818 Mission Street - 2nd Floor 415.365.6701 fax
San Francisco, CA 94103
Contributor(s):
--------------------------------------------------------------------------
Chaco team: Dan Greening, Glenn Crocker, Jim Doubek,
Coyote Lussier, Pritham Shetty.
Wrote and designed original codebase.
------------------------------------------------------------------------------
----------------------------------------------------------------------------*/
#include <TrBasic.h>
#include <math.h>
#include <memory.h>
static int q_idx;
static int tr_idx;
/* Return a new node to be added into the query tree */
static int newnode()
{
if (q_idx < QSIZE)
return q_idx++;
else
{
fprintf(stderr, "newnode: Query-table overflow\n");
return -1;
}
}
/* Return a free trapezoid */
static int newtrap()
{
if (tr_idx < TRSIZE)
{
tr[tr_idx].lseg = -1;
tr[tr_idx].rseg = -1;
tr[tr_idx].state = ST_VALID;
return tr_idx++;
}
else
{
fprintf(stderr, "newtrap: Trapezoid-table overflow\n");
return -1;
}
}
/* Return the maximum of the two points into the yval structure */
static int _max(point_t *yval, point_t *v0, point_t *v1)
{
if (v0->y > v1->y + C_EPS)
*yval = *v0;
else if (FP_EQUAL(v0->y, v1->y))
{
if (v0->x > v1->x + C_EPS)
*yval = *v0;
else
*yval = *v1;
}
else
*yval = *v1;
return 0;
}
/* Return the minimum of the two points into the yval structure */
static int _min(point_t *yval, point_t *v0, point_t *v1)
{
if (v0->y < v1->y - C_EPS)
*yval = *v0;
else if (FP_EQUAL(v0->y, v1->y))
{
if (v0->x < v1->x)
*yval = *v0;
else
*yval = *v1;
}
else
*yval = *v1;
return 0;
}
int _greater_than(point_t *v0, point_t *v1)
{
if (v0->y > v1->y + C_EPS)
return TRUE;
else if (v0->y < v1->y - C_EPS)
return FALSE;
else
return (v0->x > v1->x);
}
int _equal_to(point_t *v0, point_t *v1)
{
return (FP_EQUAL(v0->y, v1->y) && FP_EQUAL(v0->x, v1->x));
}
int _greater_than_equal_to(point_t *v0, point_t *v1)
{
if (v0->y > v1->y + C_EPS)
return TRUE;
else if (v0->y < v1->y - C_EPS)
return FALSE;
else
return (v0->x >= v1->x);
}
int _less_than(point_t *v0, point_t *v1)
{
if (v0->y < v1->y - C_EPS)
return TRUE;
else if (v0->y > v1->y + C_EPS)
return FALSE;
else
return (v0->x < v1->x);
}
/* Initilialise the query structure (Q) and the trapezoid table (T)
* when the first segment is added to start the trapezoidation
*/
int init_query_structure(int segnum)
{
int i1, i2, i3, i4, i5, i6, i7, root;
int t1, t2, t3, t4;
segment_t *s = &seg[segnum];
memset((void *)tr, 0, sizeof(tr));
memset((void *)qs, 0, sizeof(qs));
i1 = newnode();
qs[i1].nodetype = T_Y;
_max(&qs[i1].yval, &s->v0, &s->v1); /* root */
root = i1;
qs[i1].right = i2 = newnode();
qs[i2].nodetype = T_SINK;
qs[i2].parent = i1;
qs[i1].left = i3 = newnode();
qs[i3].nodetype = T_Y;
_min(&qs[i3].yval, &s->v0, &s->v1); /* root */
qs[i3].parent = i1;
qs[i3].left = i4 = newnode();
qs[i4].nodetype = T_SINK;
qs[i4].parent = i3;
qs[i3].right = i5 = newnode();
qs[i5].nodetype = T_X;
qs[i5].segnum = segnum;
qs[i5].parent = i3;
qs[i5].left = i6 = newnode();
qs[i6].nodetype = T_SINK;
qs[i6].parent = i5;
qs[i5].right = i7 = newnode();
qs[i7].nodetype = T_SINK;
qs[i7].parent = i5;
t1 = newtrap(); /* middle left */
t2 = newtrap(); /* middle right */
t3 = newtrap(); /* bottom-most */
t4 = newtrap(); /* topmost */
tr[t1].hi = tr[t2].hi = tr[t4].lo = qs[i1].yval;
tr[t1].lo = tr[t2].lo = tr[t3].hi = qs[i3].yval;
tr[t4].hi.y = (double) (INFINITY);
tr[t4].hi.x = (double) (INFINITY);
tr[t3].lo.y = (double) -1* (INFINITY);
tr[t3].lo.x = (double) -1* (INFINITY);
tr[t1].rseg = tr[t2].lseg = segnum;
tr[t1].u0 = tr[t2].u0 = t4;
tr[t1].d0 = tr[t2].d0 = t3;
tr[t4].d0 = tr[t3].u0 = t1;
tr[t4].d1 = tr[t3].u1 = t2;
tr[t1].sink = i6;
tr[t2].sink = i7;
tr[t3].sink = i4;
tr[t4].sink = i2;
tr[t1].state = tr[t2].state = ST_VALID;
tr[t3].state = tr[t4].state = ST_VALID;
qs[i2].trnum = t4;
qs[i4].trnum = t3;
qs[i6].trnum = t1;
qs[i7].trnum = t2;
s->is_inserted = TRUE;
return root;
}
/* Retun TRUE if the vertex v is to the left of line segment no.
* segnum
*/
static int is_left_of(int segnum, point_t *v)
{
segment_t *s = &seg[segnum];
double area;
if (_greater_than(&s->v1, &s->v0)) /* seg. going upwards */
{
if (FP_EQUAL(s->v1.y, v->y))
{
if (v->x < s->v1.x)
area = 1.0;
else
area = -1.0;
}
else if (FP_EQUAL(s->v0.y, v->y))
{
if (v->x < s->v0.x)
area = 1.0;
else
area = -1.0;
}
else
area = CROSS(s->v0, s->v1, (*v));
}
else /* v0 > v1 */
{
if (FP_EQUAL(s->v1.y, v->y))
{
if (v->x < s->v1.x)
area = 1.0;
else
area = -1.0;
}
else if (FP_EQUAL(s->v0.y, v->y))
{
if (v->x < s->v0.x)
area = 1.0;
else
area = -1.0;
}
else
area = CROSS(s->v1, s->v0, (*v));
}
if (area > 0.0)
return TRUE;
else
return FALSE;
}
int is_collinear(int segnum, point_t *v, int is_swapped)
{
segment_t *s = &seg[segnum];
int n;
/* First check if the endpoint is already inserted */
if (!is_swapped)
n = MODULO_NEXT(segnum + 1, global.nseg);
else
if ((n = segnum - 1) == 0)
n = 1;
return seg[n].is_inserted;
}
/* This is query routine which determines which trapezoid does the
* point v lie in. The return value is the trapezoid number
*/
int locate_endpoint(point_t *v, point_t *vo, int r)
{
node_t *rptr = &qs[r];
switch (rptr->nodetype)
{
case T_SINK:
return rptr->trnum;
case T_Y:
if (_greater_than(v, &rptr->yval)) /* above */
return locate_endpoint(v, vo, rptr->right);
else if (_equal_to(v, &rptr->yval)) /* the point is already */
{ /* inserted. */
if (_greater_than(vo, &rptr->yval)) /* above */
return locate_endpoint(v, vo, rptr->right);
else
return locate_endpoint(v, vo, rptr->left); /* below */
}
else
return locate_endpoint(v, vo, rptr->left); /* below */
case T_X:
if (_equal_to(v, &seg[rptr->segnum].v0) ||
_equal_to(v, &seg[rptr->segnum].v1))
{
if (FP_EQUAL(v->y, vo->y)) /* horizontal segment */
{
if (vo->x < v->x)
return locate_endpoint(v, vo, rptr->left); /* left */
else
return locate_endpoint(v, vo, rptr->right); /* right */
}
else if (is_left_of(rptr->segnum, vo))
return locate_endpoint(v, vo, rptr->left); /* left */
else
return locate_endpoint(v, vo, rptr->right); /* right */
}
else if (is_left_of(rptr->segnum, v))
return locate_endpoint(v, vo, rptr->left); /* left */
else
return locate_endpoint(v, vo, rptr->right); /* right */
default:
fprintf(stderr, "Haggu !!!!!\n");
break;
}
return 0;
}
/* Thread in the segment into the existing trapezoidation. The
* limiting trapezoids are given by tfirst and tlast (which are the
* trapezoids containing the two endpoints of the segment
*/
int merge_trapezoids(int segnum, int tfirst, int tlast, int side)
{
int t, tnext, cond;
int ptnext;
/* First merge polys on the LHS */
t = tfirst;
while ((t > 0) && _greater_than_equal_to(&tr[t].lo, &tr[tlast].lo))
{
if (side == S_LEFT)
cond = ((((tnext = tr[t].d0) > 0) && (tr[tnext].rseg == segnum)) ||
(((tnext = tr[t].d1) > 0) && (tr[tnext].rseg == segnum)));
else
cond = ((((tnext = tr[t].d0) > 0) && (tr[tnext].lseg == segnum)) ||
(((tnext = tr[t].d1) > 0) && (tr[tnext].lseg == segnum)));
if (cond)
{
if ((tr[t].lseg == tr[tnext].lseg) &&
(tr[t].rseg == tr[tnext].rseg)) /* good neighbours */
{ /* merge them */
/* Use the upper node as the new node i.e. t */
ptnext = qs[tr[tnext].sink].parent;
if (qs[ptnext].left == tr[tnext].sink)
qs[ptnext].left = tr[t].sink;
else
qs[ptnext].right = tr[t].sink; /* redirect parent */
/* Change the upper neighbours of the lower trapezoids */
if ((tr[t].d0 = tr[tnext].d0) > 0)
if (tr[tr[t].d0].u0 == tnext)
tr[tr[t].d0].u0 = t;
else if (tr[tr[t].d0].u1 == tnext)
tr[tr[t].d0].u1 = t;
if ((tr[t].d1 = tr[tnext].d1) > 0)
if (tr[tr[t].d1].u0 == tnext)
tr[tr[t].d1].u0 = t;
else if (tr[tr[t].d1].u1 == tnext)
tr[tr[t].d1].u1 = t;
tr[t].lo = tr[tnext].lo;
tr[tnext].state = ST_INVALID; /* invalidate the lower */
/* trapezium */
}
else /* not good neighbours */
t = tnext;
}
else /* do not satisfy the outer if */
t = tnext;
} /* end-while */
return 0;
}
/* Add in the new segment into the trapezoidation and update Q and T
* structures
*/
int add_segment(int segnum)
{
segment_t s;
segment_t *so = &seg[segnum];
int tu, tl, sk, tfirst, tlast, tnext;
int tfirstr, tlastr, tfirstl, tlastl;
int i1, i2, t, t1, t2, tn;
point_t vper, tpt;
int tritop = 0, tribot = 0, is_swapped = 0;
int tmptriseg;
s = seg[segnum];
if (_greater_than(&s.v1, &s.v0)) /* Get higher vertex in v0 */
{
int tmp;
tpt = s.v0;
s.v0 = s.v1;
s.v1 = tpt;
tmp = s.root0;
s.root0 = s.root1;
s.root1 = tmp;
is_swapped = TRUE;
}
if ((is_swapped) ? !inserted(segnum, LASTPT) :
!inserted(segnum, FIRSTPT)) /* insert v0 in the tree */
{
int tmp_d;
tu = locate_endpoint(&s.v0, &s.v1, s.root0);
tl = newtrap(); /* tl is the new lower trapezoid */
tr[tl].state = ST_VALID;
tr[tl] = tr[tu];
tr[tu].lo.y = tr[tl].hi.y = s.v0.y;
tr[tu].lo.x = tr[tl].hi.x = s.v0.x;
tr[tu].d0 = tl;
tr[tu].d1 = 0;
tr[tl].u0 = tu;
tr[tl].u1 = 0;
if (((tmp_d = tr[tl].d0) > 0) && (tr[tmp_d].u0 == tu))
tr[tmp_d].u0 = tl;
if (((tmp_d = tr[tl].d0) > 0) && (tr[tmp_d].u1 == tu))
tr[tmp_d].u1 = tl;
if (((tmp_d = tr[tl].d1) > 0) && (tr[tmp_d].u0 == tu))
tr[tmp_d].u0 = tl;
if (((tmp_d = tr[tl].d1) > 0) && (tr[tmp_d].u1 == tu))
tr[tmp_d].u1 = tl;
/* Now update the query structure and obtain the sinks for the */
/* two trapezoids */
i1 = newnode(); /* Upper trapezoid sink */
i2 = newnode(); /* Lower trapezoid sink */
sk = tr[tu].sink;
qs[sk].nodetype = T_Y;
qs[sk].yval = s.v0;
qs[sk].segnum = segnum; /* not really reqd ... maybe later */
qs[sk].left = i2;
qs[sk].right = i1;
qs[i1].nodetype = T_SINK;
qs[i1].trnum = tu;
qs[i1].parent = sk;
qs[i2].nodetype = T_SINK;
qs[i2].trnum = tl;
qs[i2].parent = sk;
tr[tu].sink = i1;
tr[tl].sink = i2;
tfirst = tl;
}
else /* v0 already present */
{ /* Get the topmost intersecting trapezoid */
vper.x = s.v0.x + EPS * (s.v1.x - s.v0.x);
vper.y = s.v0.y + EPS * (s.v1.y - s.v0.y);
tfirst = locate_endpoint(&s.v0, &s.v1, s.root0);
tritop = 1;
}
if ((is_swapped) ? !inserted(segnum, FIRSTPT) :
!inserted(segnum, LASTPT)) /* insert v1 in the tree */
{
int tmp_d;
tu = locate_endpoint(&s.v1, &s.v0, s.root1);
tl = newtrap(); /* tl is the new lower trapezoid */
tr[tl].state = ST_VALID;
tr[tl] = tr[tu];
tr[tu].lo.y = tr[tl].hi.y = s.v1.y;
tr[tu].lo.x = tr[tl].hi.x = s.v1.x;
tr[tu].d0 = tl;
tr[tu].d1 = 0;
tr[tl].u0 = tu;
tr[tl].u1 = 0;
if (((tmp_d = tr[tl].d0) > 0) && (tr[tmp_d].u0 == tu))
tr[tmp_d].u0 = tl;
if (((tmp_d = tr[tl].d0) > 0) && (tr[tmp_d].u1 == tu))
tr[tmp_d].u1 = tl;
if (((tmp_d = tr[tl].d1) > 0) && (tr[tmp_d].u0 == tu))
tr[tmp_d].u0 = tl;
if (((tmp_d = tr[tl].d1) > 0) && (tr[tmp_d].u1 == tu))
tr[tmp_d].u1 = tl;
/* Now update the query structure and obtain the sinks for the */
/* two trapezoids */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -