📄 chtrconstr.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.
------------------------------------------------------------------------------
Triangulator for Chaco VRML - based on Graphics Gems V.
----------------------------------------------------------------------------*/
#include <ChTriangle.h>
#include <math.h>
#include <memory.h>
/* Return a new node to be added into the query tree */
int ChTriangulator::newnode()
{
if (q_idx < m_qSize)
return q_idx++;
else
{
TRACE("newnode: Query-table overflow\n");
throw CH_EX_TRIANGULATION;
return -1;
}
}
/* Return a free trapezoid */
int ChTriangulator::newtrap()
{
if (tr_idx < m_trSize)
{
tr[tr_idx].lseg = -1;
tr[tr_idx].rseg = -1;
tr[tr_idx].state = ST_VALID;
return tr_idx++;
}
else
{
TRACE( "newtrap: Trapezoid-table overflow\n");
throw CH_EX_TRIANGULATION;
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 ChTriangulator::_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 ChTriangulator::_equal_to(point_t *v0, point_t *v1)
{
return (FP_EQUAL(v0->y, v1->y) && FP_EQUAL(v0->x, v1->x));
}
int ChTriangulator::_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 ChTriangulator::_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 ChTriangulator::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, m_trSize * sizeof(*tr));
memset((void *)qs, 0, m_qSize * 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
*/
int ChTriangulator::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 ChTriangulator::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 ChTriangulator::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:
TRACE( "Haggu !!!!!\n");
// throw CH_EX_TRIANGULATION; ???????
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 ChTriangulator::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 ChTriangulator::add_segment(int segnum)
{
segment_t s;
segment_t *so = &seg[segnum];
int tu, tl, sk, tfirst, tlast, tnext;
int tfirstr = -1, tlastr, tfirstl, tlastl;
int i1, i2, t, tn;
//int t1, t2;
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 + -