Files
secondo/Algebras/TransportationMode/Triangulate.cpp

4141 lines
104 KiB
C++
Raw Normal View History

2026-01-23 17:03:45 +08:00
/*
----
This file is part of SECONDO.
Copyright (C) 2004, University in Hagen, Department of Computer Science,
Database Systems for New Applications.
SECONDO is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
SECONDO is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with SECONDO; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
----
//paragraph [1] Title: [{\Large \bf \begin {center}] [\end {center}}]
//[TOC] [\tableofcontents]
[1] Source File of the Transportation Mode Algebra
May, 2010 Jianqiu Xu
[TOC]
1 Overview
This source file essentially contains the necessary implementations of
doing triangulation for polygon with and without holes.
The original implementation is from Atul Narkhede and Dinesh Manocha
[TOC]
1 Overview
2 Defines and includes
*/
#include "Triangulate.h"
using namespace std;
static int choose_idx;
static int permute[SEGSIZE];
node_t qs[QSIZE]; /* Query structure */
trap_t tr[TRSIZE]; /* Trapezoid structure */
segment_t seg[SEGSIZE]; /* Segment table */
static int q_idx;
static int tr_idx;
/* Table to hold all the monotone
polygons . Each monotone polygon
is a circularly linked list */
static monchain_t mchain[TRSIZE];
/* chain init. information. This
is used to decide which
monotone polygon to split if
there are several other
polygons touching at the same
vertex */
static vertexchain_t vert[SEGSIZE];
/* contains position of any vertex in
the monotone chain for the polygon */
static int mon[SEGSIZE];
static int visited[TRSIZE];
static int chain_idx, op_idx, mon_idx;
/*
Generate a random permutation of the segments 1..n
*/
int generate_random_ordering(int n)
{
struct timeval tval;
struct timezone tzone;
register int i;
int m, st[SEGSIZE], *p;
choose_idx = 1;
gettimeofday(&tval, &tzone);
// srand48(tval.tv_sec);
for (i = 0; i <= n; i++)
st[i] = i;
p = st;
for (i = 1; i <= n; i++, p++)
{
// m = lrand48() % (n + 1 - i) + 1;
m = i % (n + 1 - i) + 1;
permute[i] = p[m];
if (m != 1)
p[m] = p[1];
}
return 0;
}
static int initialise(int n)
{
register int i;
for (i = 1; i <= n; i++)
seg[i].is_inserted = FALSE;
generate_random_ordering(n);
return 0;
}
/*
Return the next segment in the generated random ordering of all the
segments in S
*/
int choose_segment()
{
// int i;
#ifdef DEBUG
fprintf(stderr, "choose_segment: %d\n", permute[choose_idx]);
#endif
return permute[choose_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 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;
}
/*
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;
}
}
/*
Initilialise the query structure (Q) and the trapezoid table (T)
when the first segment is added to start the trapezoidation. The
query-tree starts out with 4 trapezoids, one S-node and 2 Y-nodes
*/
static 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];
q_idx = tr_idx = 1;
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) (MYINFINITY);
tr[t4].hi.x = (double) (MYINFINITY);
tr[t3].lo.y = (double) -1* (MYINFINITY);
tr[t3].lo.x = (double) -1* (MYINFINITY);
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;
}
int math_N(int n, int h)
{
register int i;
double v;
for (i = 0, v = (int) n; i < h; i++)
v = log2(v);
return (int) ceil((double) 1.0*n/v);
}
/*Get log*n for given n*/
int math_logstar_n(int n)
{
register int i;
double v;
for (i = 0, v = (double) n; v >= 1; i++)
v = log2(v);
return (i - 1);
}
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);
}
/*
Returns true if the corresponding endpoint of the given segment is
already inserted into the segment tree. Use the simple test of
whether the segment which shares this endpoint is already inserted
*/
static int inserted(int segnum, int whichpt)
{
if (whichpt == FIRSTPT)
return seg[seg[segnum].prev].is_inserted;
else
return seg[seg[segnum].next].is_inserted;
}
/*
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. Merges all
possible trapezoids which flank this segment and have been recently
divided because of its insertion
*/
static 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;
}
/*
Retun TRUE if the vertex v is to the left of line segment no.
segnum. Takes care of the degenerate cases when both the vertices
have the same y--cood, etc.
*/
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;
}
/*
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;
}
cout<<__FILE__<<" "<<__LINE__<<endl;
assert(false);
return 0;
}
/*
Add in the new segment into the trapezoidation and update Q and T
structures. First locate the two endpoints of the segment in the
Q-structure. Then start from the topmost trapezoid and go down to
the lower trapezoid dividing all the trapezoids in between .
*/
static int add_segment(int segnum)
{
segment_t s;
// segment_t *so = &seg[segnum];
// int tu, tl, sk, tfirst, tlast, tnext;
int tu, tl, sk, tfirst, tlast;
int tfirstr, tlastr, tfirstl, tlastl;
// int i1, i2, t, t1, t2, tn;
int i1, i2, t, tn;
point_t tpt;
int tritop =0, tribot = 0, is_swapped = 0;
int tmptriseg;
s = seg[segnum];
// cout<<"( "<<s.v0.x<<" "<<s.v0.y<<")"<<endl;
// cout<<"( "<<s.v1.x<<" "<<s.v1.y<<")"<<endl;
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 */
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 */
i1 = newnode(); /* Upper trapezoid sink */
i2 = newnode(); /* Lower trapezoid sink */
sk = tr[tu].sink;
qs[sk].nodetype = T_Y;
qs[sk].yval = s.v1;
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;
tlast = tu;
}
else /* v1 already present */
{ /* Get the lowermost intersecting trapezoid */
tlast = locate_endpoint(&s.v1, &s.v0, s.root1);
tribot = 1;
}
/* Thread the segment into the query tree creating a new X-node */
/* First, split all the trapezoids which are intersected by s into */
/* two */
t = tfirst; /* topmost trapezoid */
while ((t > 0) &&
_greater_than_equal_to(&tr[t].lo, &tr[tlast].lo))
/* traverse from top to bot */
{
int t_sav, tn_sav;
sk = tr[t].sink;
i1 = newnode(); /* left trapezoid sink */
i2 = newnode(); /* right trapezoid sink */
qs[sk].nodetype = T_X;
qs[sk].segnum = segnum;
qs[sk].left = i1;
qs[sk].right = i2;
qs[i1].nodetype = T_SINK; /* left trapezoid (use existing one) */
qs[i1].trnum = t;
qs[i1].parent = sk;
qs[i2].nodetype = T_SINK; /* right trapezoid (allocate new) */
qs[i2].trnum = tn = newtrap();
tr[tn].state = ST_VALID;
qs[i2].parent = sk;
if (t == tfirst)
tfirstr = tn;
if (_equal_to(&tr[t].lo, &tr[tlast].lo))
tlastr = tn;
tr[tn] = tr[t];
tr[t].sink = i1;
tr[tn].sink = i2;
t_sav = t;
tn_sav = tn;
/* error */
if ((tr[t].d0 <= 0) && (tr[t].d1 <= 0)) /* case cannot arise */
{
fprintf(stderr, "add_segment: error\n");
break;
}
/* only one trapezoid below. partition t into two and make the */
/* two resulting trapezoids t and tn as the upper neighbours of */
/* the sole lower trapezoid */
else if ((tr[t].d0 > 0) && (tr[t].d1 <= 0))
{ /* Only one trapezoid below */
if ((tr[t].u0 > 0) && (tr[t].u1 > 0))
{ /* continuation of a chain from abv. */
if (tr[t].usave > 0) /* three upper neighbours */
{
if (tr[t].uside == S_LEFT)
{
tr[tn].u0 = tr[t].u1;
tr[t].u1 = -1;
tr[tn].u1 = tr[t].usave;
tr[tr[t].u0].d0 = t;
tr[tr[tn].u0].d0 = tn;
tr[tr[tn].u1].d0 = tn;
}
else /* intersects in the right */
{
tr[tn].u1 = -1;
tr[tn].u0 = tr[t].u1;
tr[t].u1 = tr[t].u0;
tr[t].u0 = tr[t].usave;
tr[tr[t].u0].d0 = t;
tr[tr[t].u1].d0 = t;
tr[tr[tn].u0].d0 = tn;
}
tr[t].usave = tr[tn].usave = 0;
}
else /* No usave.... simple case */
{
tr[tn].u0 = tr[t].u1;
tr[t].u1 = tr[tn].u1 = -1;
tr[tr[tn].u0].d0 = tn;
}
}
else
{ /* fresh seg. or upward cusp */
int tmp_u = tr[t].u0;
int td0, td1;
if (((td0 = tr[tmp_u].d0) > 0) &&
((td1 = tr[tmp_u].d1) > 0))
{ /* upward cusp */
if ((tr[td0].rseg > 0) &&
!is_left_of(tr[td0].rseg, &s.v1))
{
tr[t].u0 = tr[t].u1 = tr[tn].u1 = -1;
tr[tr[tn].u0].d1 = tn;
}
else /* cusp going leftwards */
{
tr[tn].u0 = tr[tn].u1 = tr[t].u1 = -1;
tr[tr[t].u0].d0 = t;
}
}
else /* fresh segment */
{
tr[tr[t].u0].d0 = t;
tr[tr[t].u0].d1 = tn;
}
}
if (FP_EQUAL(tr[t].lo.y, tr[tlast].lo.y) &&
FP_EQUAL(tr[t].lo.x, tr[tlast].lo.x) && tribot)
{ /* bottom forms a triangle */
if (is_swapped)
tmptriseg = seg[segnum].prev;
else
tmptriseg = seg[segnum].next;
if ((tmptriseg > 0) && is_left_of(tmptriseg, &s.v0))
{
/* L-R downward cusp */
tr[tr[t].d0].u0 = t;
tr[tn].d0 = tr[tn].d1 = -1;
}
else
{
/* R-L downward cusp */
tr[tr[tn].d0].u1 = tn;
tr[t].d0 = tr[t].d1 = -1;
}
}
else
{
if ((tr[tr[t].d0].u0 > 0) && (tr[tr[t].d0].u1 > 0))
{
if (tr[tr[t].d0].u0 == t) /* passes thru LHS */
{
tr[tr[t].d0].usave = tr[tr[t].d0].u1;
tr[tr[t].d0].uside = S_LEFT;
}
else
{
tr[tr[t].d0].usave = tr[tr[t].d0].u0;
tr[tr[t].d0].uside = S_RIGHT;
}
}
tr[tr[t].d0].u0 = t;
tr[tr[t].d0].u1 = tn;
}
t = tr[t].d0;
}
else if ((tr[t].d0 <= 0) && (tr[t].d1 > 0))
{ /* Only one trapezoid below */
if ((tr[t].u0 > 0) && (tr[t].u1 > 0))
{ /* continuation of a chain from abv. */
if (tr[t].usave > 0) /* three upper neighbours */
{
if (tr[t].uside == S_LEFT)
{
tr[tn].u0 = tr[t].u1;
tr[t].u1 = -1;
tr[tn].u1 = tr[t].usave;
tr[tr[t].u0].d0 = t;
tr[tr[tn].u0].d0 = tn;
tr[tr[tn].u1].d0 = tn;
}
else /* intersects in the right */
{
tr[tn].u1 = -1;
tr[tn].u0 = tr[t].u1;
tr[t].u1 = tr[t].u0;
tr[t].u0 = tr[t].usave;
tr[tr[t].u0].d0 = t;
tr[tr[t].u1].d0 = t;
tr[tr[tn].u0].d0 = tn;
}
tr[t].usave = tr[tn].usave = 0;
}
else /* No usave.... simple case */
{
tr[tn].u0 = tr[t].u1;
tr[t].u1 = tr[tn].u1 = -1;
tr[tr[tn].u0].d0 = tn;
}
}
else
{ /* fresh seg. or upward cusp */
int tmp_u = tr[t].u0;
int td0, td1;
if (((td0 = tr[tmp_u].d0) > 0) &&
((td1 = tr[tmp_u].d1) > 0))
{ /* upward cusp */
if ((tr[td0].rseg > 0) &&
!is_left_of(tr[td0].rseg, &s.v1))
{
tr[t].u0 = tr[t].u1 = tr[tn].u1 = -1;
tr[tr[tn].u0].d1 = tn;
}
else
{
tr[tn].u0 = tr[tn].u1 = tr[t].u1 = -1;
tr[tr[t].u0].d0 = t;
}
}
else /* fresh segment */
{
tr[tr[t].u0].d0 = t;
tr[tr[t].u0].d1 = tn;
}
}
if (FP_EQUAL(tr[t].lo.y, tr[tlast].lo.y) &&
FP_EQUAL(tr[t].lo.x, tr[tlast].lo.x) && tribot)
{ /* bottom forms a triangle */
// int tmpseg;
if (is_swapped)
tmptriseg = seg[segnum].prev;
else
tmptriseg = seg[segnum].next;
// if ((tmpseg > 0) && is_left_of(tmpseg, &s.v0)){
if ((tmptriseg > 0) && is_left_of(tmptriseg, &s.v0)){
/* L-R downward cusp */
tr[tr[t].d1].u0 = t;
tr[tn].d0 = tr[tn].d1 = -1;
}
else
{
/* R-L downward cusp */
tr[tr[tn].d1].u1 = tn;
tr[t].d0 = tr[t].d1 = -1;
}
}
else
{
if ((tr[tr[t].d1].u0 > 0) && (tr[tr[t].d1].u1 > 0))
{
if (tr[tr[t].d1].u0 == t) /* passes thru LHS */
{
tr[tr[t].d1].usave = tr[tr[t].d1].u1;
tr[tr[t].d1].uside = S_LEFT;
}
else
{
tr[tr[t].d1].usave = tr[tr[t].d1].u0;
tr[tr[t].d1].uside = S_RIGHT;
}
}
tr[tr[t].d1].u0 = t;
tr[tr[t].d1].u1 = tn;
}
t = tr[t].d1;
}
/* two trapezoids below. Find out which one is intersected by */
/* this segment and proceed down that one */
else
{
// int tmpseg = tr[tr[t].d0].rseg;
double y0, yt;
point_t tmppt;
int tnext, i_d0, i_d1;
i_d0 = i_d1 = FALSE;
if (FP_EQUAL(tr[t].lo.y, s.v0.y))
{
if (tr[t].lo.x > s.v0.x)
i_d0 = TRUE;
else
i_d1 = TRUE;
}
else
{
tmppt.y = y0 = tr[t].lo.y;
yt = (y0 - s.v0.y)/(s.v1.y - s.v0.y);
tmppt.x = s.v0.x + yt * (s.v1.x - s.v0.x);
if (_less_than(&tmppt, &tr[t].lo))
i_d0 = TRUE;
else
i_d1 = TRUE;
}
/* check continuity from the top so that the lower-neighbour */
/* values are properly filled for the upper trapezoid */
if ((tr[t].u0 > 0) && (tr[t].u1 > 0))
{ /* continuation of a chain from abv. */
if (tr[t].usave > 0) /* three upper neighbours */
{
if (tr[t].uside == S_LEFT)
{
tr[tn].u0 = tr[t].u1;
tr[t].u1 = -1;
tr[tn].u1 = tr[t].usave;
tr[tr[t].u0].d0 = t;
tr[tr[tn].u0].d0 = tn;
tr[tr[tn].u1].d0 = tn;
}
else /* intersects in the right */
{
tr[tn].u1 = -1;
tr[tn].u0 = tr[t].u1;
tr[t].u1 = tr[t].u0;
tr[t].u0 = tr[t].usave;
tr[tr[t].u0].d0 = t;
tr[tr[t].u1].d0 = t;
tr[tr[tn].u0].d0 = tn;
}
tr[t].usave = tr[tn].usave = 0;
}
else /* No usave.... simple case */
{
tr[tn].u0 = tr[t].u1;
tr[tn].u1 = -1;
tr[t].u1 = -1;
tr[tr[tn].u0].d0 = tn;
}
}
else
{ /* fresh seg. or upward cusp */
int tmp_u = tr[t].u0;
int td0, td1;
if (((td0 = tr[tmp_u].d0) > 0) &&
((td1 = tr[tmp_u].d1) > 0))
{ /* upward cusp */
if ((tr[td0].rseg > 0) &&
!is_left_of(tr[td0].rseg, &s.v1))
{
tr[t].u0 = tr[t].u1 = tr[tn].u1 = -1;
tr[tr[tn].u0].d1 = tn;
}
else
{
tr[tn].u0 = tr[tn].u1 = tr[t].u1 = -1;
tr[tr[t].u0].d0 = t;
}
}
else /* fresh segment */
{
tr[tr[t].u0].d0 = t;
tr[tr[t].u0].d1 = tn;
}
}
if (FP_EQUAL(tr[t].lo.y, tr[tlast].lo.y) &&
FP_EQUAL(tr[t].lo.x, tr[tlast].lo.x) && tribot)
{
/* this case arises only at the lowest trapezoid.. i.e.
tlast, if the lower endpoint of the segment is
already inserted in the structure */
tr[tr[t].d0].u0 = t;
tr[tr[t].d0].u1 = -1;
tr[tr[t].d1].u0 = tn;
tr[tr[t].d1].u1 = -1;
tr[tn].d0 = tr[t].d1;
tr[t].d1 = tr[tn].d1 = -1;
tnext = tr[t].d1;
}
else if (i_d0)
/* intersecting d0 */
{
tr[tr[t].d0].u0 = t;
tr[tr[t].d0].u1 = tn;
tr[tr[t].d1].u0 = tn;
tr[tr[t].d1].u1 = -1;
/* new code to determine the bottom neighbours of the */
/* newly partitioned trapezoid */
tr[t].d1 = -1;
tnext = tr[t].d0;
}
else /* intersecting d1 */
{
tr[tr[t].d0].u0 = t;
tr[tr[t].d0].u1 = -1;
tr[tr[t].d1].u0 = t;
tr[tr[t].d1].u1 = tn;
/* new code to determine the bottom neighbours of the */
/* newly partitioned trapezoid */
tr[tn].d0 = tr[t].d1;
tr[tn].d1 = -1;
tnext = tr[t].d1;
}
t = tnext;
}
tr[t_sav].rseg = tr[tn_sav].lseg = segnum;
} // end-while
// Now combine those trapezoids which share common segments. We can
// use the pointers to the parent to connect these together. This
// works only because all these new trapezoids have been formed
// due to splitting by the segment, and hence have only one parent
tfirstl = tfirst;
tlastl = tlast;
merge_trapezoids(segnum, tfirstl, tlastl, S_LEFT);
merge_trapezoids(segnum, tfirstr, tlastr, S_RIGHT);
seg[segnum].is_inserted = TRUE;
return 0;
}
/*
Update the roots stored for each of the endpoints of the segment.
This is done to speed up the location-query for the endpoint when
the segment is inserted into the trapezoidation subsequently
*/
static int find_new_roots(int segnum)
{
segment_t *s = &seg[segnum];
if (s->is_inserted)
return 0;
s->root0 = locate_endpoint(&s->v0, &s->v1, s->root0);
s->root0 = tr[s->root0].sink;
s->root1 = locate_endpoint(&s->v1, &s->v0, s->root1);
s->root1 = tr[s->root1].sink;
return 0;
}
/*
Main routine to perform trapezoidation
*/
int construct_trapezoids(int nseg)
{
register int i;
int root, h;
/* Add the first segment and get the query structure and trapezoid */
/* list initialised */
root = init_query_structure(choose_segment());
for (i = 1; i <= nseg; i++)
seg[i].root0 = seg[i].root1 = root;
for (h = 1; h <= math_logstar_n(nseg); h++)
{
for (i = math_N(nseg, h -1) + 1; i <= math_N(nseg, h); i++)
add_segment(choose_segment());
/* Find a new root for each of the segment endpoints */
for (i = 1; i <= nseg; i++)
find_new_roots(i);
}
for (i = math_N(nseg, math_logstar_n(nseg)) + 1; i <= nseg; i++)
add_segment(choose_segment());
return 0;
}
/*
Function returns TRUE if the trapezoid lies inside the polygon
*/
static int inside_polygon(trap_t *t)
{
int rseg = t->rseg;
if (t->state == ST_INVALID)
return 0;
if ((t->lseg <= 0) || (t->rseg <= 0))
return 0;
if (((t->u0 <= 0) && (t->u1 <= 0)) ||
((t->d0 <= 0) && (t->d1 <= 0))) /* triangle */
return (_greater_than(&seg[rseg].v1, &seg[rseg].v0));
return 0;
}
/*
return a new mon structure from the table
*/
static int newmon()
{
return ++mon_idx;
}
/*
return a new chain element from the table
*/
static int new_chain_element()
{
return ++chain_idx;
}
static double get_angle(point_t *vp0, point_t *vpnext, point_t *vp1)
{
point_t v0, v1;
v0.x = vpnext->x - vp0->x;
v0.y = vpnext->y - vp0->y;
v1.x = vp1->x - vp0->x;
v1.y = vp1->y - vp0->y;
if (CROSS_SINE(v0, v1) >= 0) /* sine is positive */
return DOT(v0, v1)/LENGTH(v0)/LENGTH(v1);
else
return (-1.0 * DOT(v0, v1)/LENGTH(v0)/LENGTH(v1) - 2);
}
/*
(v0, v1) is the new diagonal to be added to the polygon. Find which
chain to use and return the positions of v0 and v1 in p and q
*/
static int get_vertex_positions(int v0, int v1, int *ip, int *iq)
{
vertexchain_t *vp0, *vp1;
register int i;
double angle, temp;
int tp, tq;
vp0 = &vert[v0];
vp1 = &vert[v1];
/* p is identified as follows. Scan from (v0, v1) rightwards till */
/* you hit the first segment starting from v0. That chain is the */
/* chain of our interest */
angle = -4.0;
for (i = 0; i < 4; i++)
{
if (vp0->vnext[i] <= 0)
continue;
if ((temp = get_angle(&vp0->pt, &(vert[vp0->vnext[i]].pt),
&vp1->pt)) > angle)
{
angle = temp;
tp = i;
}
}
*ip = tp;
/* Do similar actions for q */
angle = -4.0;
for (i = 0; i < 4; i++)
{
if (vp1->vnext[i] <= 0)
continue;
if ((temp = get_angle(&vp1->pt, &(vert[vp1->vnext[i]].pt),
&vp0->pt)) > angle)
{
angle = temp;
tq = i;
}
}
*iq = tq;
return 0;
}
/*
v0 and v1 are specified in anti-clockwise order with respect to
the current monotone polygon mcur. Split the current polygon into
two polygons using the diagonal (v0, v1)
*/
static int make_new_monotone_poly(int mcur, int v0, int v1)
{
int p, q, ip, iq;
int mnew = newmon();
int i, j, nf0, nf1;
vertexchain_t *vp0, *vp1;
vp0 = &vert[v0];
vp1 = &vert[v1];
get_vertex_positions(v0, v1, &ip, &iq);
p = vp0->vpos[ip];
q = vp1->vpos[iq];
/* At this stage, we have got the positions of v0 and v1 in the */
/* desired chain. Now modify the linked lists */
i = new_chain_element(); /* for the new list */
j = new_chain_element();
mchain[i].vnum = v0;
mchain[j].vnum = v1;
mchain[i].next = mchain[p].next;
mchain[mchain[p].next].prev = i;
mchain[i].prev = j;
mchain[j].next = i;
mchain[j].prev = mchain[q].prev;
mchain[mchain[q].prev].next = j;
mchain[p].next = q;
mchain[q].prev = p;
nf0 = vp0->nextfree;
nf1 = vp1->nextfree;
vp0->vnext[ip] = v1;
vp0->vpos[nf0] = i;
vp0->vnext[nf0] = mchain[mchain[i].next].vnum;
vp1->vpos[nf1] = j;
vp1->vnext[nf1] = v0;
vp0->nextfree++;
vp1->nextfree++;
#ifdef DEBUG
fprintf(stderr, "make_poly: mcur = %d, (v0, v1) = (%d, %d)\n",
mcur, v0, v1);
fprintf(stderr, "next posns = (p, q) = (%d, %d)\n", p, q);
#endif
mon[mcur] = p;
mon[mnew] = i;
return mnew;
}
/*
recursively visit all the trapezoids
*/
static int traverse_polygon(int mcur, int trnum, int from, int dir)
{
trap_t *t = &tr[trnum];
// int howsplit, mnew;
int mnew;
// int v0, v1, v0next, v1next;
int v0, v1;
// int retval, tmp;
int retval;
int do_switch = FALSE;
if ((trnum <= 0) || visited[trnum])
return 0;
visited[trnum] = TRUE;
/* We have much more information available here.
rseg: goes upwards
lseg: goes downwards
Initially assume that dir = TR_FROM_DN (from the left)
Switch v0 and v1 if necessary afterwards
special cases for triangles with cusps at the opposite ends.
take care of this first */
if ((t->u0 <= 0) && (t->u1 <= 0))
{
if ((t->d0 > 0) && (t->d1 > 0)) /* downward opening triangle */
{
v0 = tr[t->d1].lseg;
v1 = t->lseg;
if (from == t->d1)
{
do_switch = TRUE;
mnew = make_new_monotone_poly(mcur, v1, v0);
traverse_polygon(mcur, t->d1, trnum, TR_FROM_UP);
traverse_polygon(mnew, t->d0, trnum, TR_FROM_UP);
}
else
{
mnew = make_new_monotone_poly(mcur, v0, v1);
traverse_polygon(mcur, t->d0, trnum, TR_FROM_UP);
traverse_polygon(mnew, t->d1, trnum, TR_FROM_UP);
}
}
else
{
retval = SP_NOSPLIT; /* Just traverse all neighbours */
traverse_polygon(mcur, t->u0, trnum, TR_FROM_DN);
traverse_polygon(mcur, t->u1, trnum, TR_FROM_DN);
traverse_polygon(mcur, t->d0, trnum, TR_FROM_UP);
traverse_polygon(mcur, t->d1, trnum, TR_FROM_UP);
}
}
else if ((t->d0 <= 0) && (t->d1 <= 0))
{
if ((t->u0 > 0) && (t->u1 > 0)) /* upward opening triangle */
{
v0 = t->rseg;
v1 = tr[t->u0].rseg;
if (from == t->u1)
{
do_switch = TRUE;
mnew = make_new_monotone_poly(mcur, v1, v0);
traverse_polygon(mcur, t->u1, trnum, TR_FROM_DN);
traverse_polygon(mnew, t->u0, trnum, TR_FROM_DN);
}
else
{
mnew = make_new_monotone_poly(mcur, v0, v1);
traverse_polygon(mcur, t->u0, trnum, TR_FROM_DN);
traverse_polygon(mnew, t->u1, trnum, TR_FROM_DN);
}
}
else
{
retval = SP_NOSPLIT; /* Just traverse all neighbours */
traverse_polygon(mcur, t->u0, trnum, TR_FROM_DN);
traverse_polygon(mcur, t->u1, trnum, TR_FROM_DN);
traverse_polygon(mcur, t->d0, trnum, TR_FROM_UP);
traverse_polygon(mcur, t->d1, trnum, TR_FROM_UP);
}
}
else if ((t->u0 > 0) && (t->u1 > 0))
{
if ((t->d0 > 0) && (t->d1 > 0)) /* downward + upward cusps */
{
v0 = tr[t->d1].lseg;
v1 = tr[t->u0].rseg;
retval = SP_2UP_2DN;
if (((dir == TR_FROM_DN) && (t->d1 == from)) ||
((dir == TR_FROM_UP) && (t->u1 == from)))
{
do_switch = TRUE;
mnew = make_new_monotone_poly(mcur, v1, v0);
traverse_polygon(mcur, t->u1, trnum, TR_FROM_DN);
traverse_polygon(mcur, t->d1, trnum, TR_FROM_UP);
traverse_polygon(mnew, t->u0, trnum, TR_FROM_DN);
traverse_polygon(mnew, t->d0, trnum, TR_FROM_UP);
}
else
{
mnew = make_new_monotone_poly(mcur, v0, v1);
traverse_polygon(mcur, t->u0, trnum, TR_FROM_DN);
traverse_polygon(mcur, t->d0, trnum, TR_FROM_UP);
traverse_polygon(mnew, t->u1, trnum, TR_FROM_DN);
traverse_polygon(mnew, t->d1, trnum, TR_FROM_UP);
}
}
else /* only downward cusp */
{
if (_equal_to(&t->lo, &seg[t->lseg].v1))
{
v0 = tr[t->u0].rseg;
v1 = seg[t->lseg].next;
retval = SP_2UP_LEFT;
if ((dir == TR_FROM_UP) && (t->u0 == from))
{
do_switch = TRUE;
mnew = make_new_monotone_poly(mcur, v1, v0);
traverse_polygon(mcur, t->u0, trnum, TR_FROM_DN);
traverse_polygon(mnew, t->d0, trnum, TR_FROM_UP);
traverse_polygon(mnew, t->u1, trnum, TR_FROM_DN);
traverse_polygon(mnew, t->d1, trnum, TR_FROM_UP);
}
else
{
mnew = make_new_monotone_poly(mcur, v0, v1);
traverse_polygon(mcur, t->u1, trnum, TR_FROM_DN);
traverse_polygon(mcur, t->d0, trnum, TR_FROM_UP);
traverse_polygon(mcur, t->d1, trnum, TR_FROM_UP);
traverse_polygon(mnew, t->u0, trnum, TR_FROM_DN);
}
}
else
{
v0 = t->rseg;
v1 = tr[t->u0].rseg;
retval = SP_2UP_RIGHT;
if ((dir == TR_FROM_UP) && (t->u1 == from))
{
do_switch = TRUE;
mnew = make_new_monotone_poly(mcur, v1, v0);
traverse_polygon(mcur, t->u1, trnum, TR_FROM_DN);
traverse_polygon(mnew, t->d1, trnum, TR_FROM_UP);
traverse_polygon(mnew, t->d0, trnum, TR_FROM_UP);
traverse_polygon(mnew, t->u0, trnum, TR_FROM_DN);
}
else
{
mnew = make_new_monotone_poly(mcur, v0, v1);
traverse_polygon(mcur, t->u0, trnum, TR_FROM_DN);
traverse_polygon(mcur, t->d0, trnum, TR_FROM_UP);
traverse_polygon(mcur, t->d1, trnum, TR_FROM_UP);
traverse_polygon(mnew, t->u1, trnum, TR_FROM_DN);
}
}
}
}
else if ((t->u0 > 0) || (t->u1 > 0)) /* no downward cusp */
{
if ((t->d0 > 0) && (t->d1 > 0)) /* only upward cusp */
{
if (_equal_to(&t->hi, &seg[t->lseg].v0))
{
v0 = tr[t->d1].lseg;
v1 = t->lseg;
retval = SP_2DN_LEFT;
if (!((dir == TR_FROM_DN) && (t->d0 == from)))
{
do_switch = TRUE;
mnew = make_new_monotone_poly(mcur, v1, v0);
traverse_polygon(mcur, t->u1, trnum, TR_FROM_DN);
traverse_polygon(mcur, t->d1, trnum, TR_FROM_UP);
traverse_polygon(mcur, t->u0, trnum, TR_FROM_DN);
traverse_polygon(mnew, t->d0, trnum, TR_FROM_UP);
}
else
{
mnew = make_new_monotone_poly(mcur, v0, v1);
traverse_polygon(mcur, t->d0, trnum, TR_FROM_UP);
traverse_polygon(mnew, t->u0, trnum, TR_FROM_DN);
traverse_polygon(mnew, t->u1, trnum, TR_FROM_DN);
traverse_polygon(mnew, t->d1, trnum, TR_FROM_UP);
}
}
else
{
v0 = tr[t->d1].lseg;
v1 = seg[t->rseg].next;
retval = SP_2DN_RIGHT;
if ((dir == TR_FROM_DN) && (t->d1 == from))
{
do_switch = TRUE;
mnew = make_new_monotone_poly(mcur, v1, v0);
traverse_polygon(mcur, t->d1, trnum, TR_FROM_UP);
traverse_polygon(mnew, t->u1, trnum, TR_FROM_DN);
traverse_polygon(mnew, t->u0, trnum, TR_FROM_DN);
traverse_polygon(mnew, t->d0, trnum, TR_FROM_UP);
}
else
{
mnew = make_new_monotone_poly(mcur, v0, v1);
traverse_polygon(mcur, t->u0, trnum, TR_FROM_DN);
traverse_polygon(mcur, t->d0, trnum, TR_FROM_UP);
traverse_polygon(mcur, t->u1, trnum, TR_FROM_DN);
traverse_polygon(mnew, t->d1, trnum, TR_FROM_UP);
}
}
}
else /* no cusp */
{
if (_equal_to(&t->hi, &seg[t->lseg].v0) &&
_equal_to(&t->lo, &seg[t->rseg].v0))
{
v0 = t->rseg;
v1 = t->lseg;
retval = SP_SIMPLE_LRDN;
if (dir == TR_FROM_UP)
{
do_switch = TRUE;
mnew = make_new_monotone_poly(mcur, v1, v0);
traverse_polygon(mcur, t->u0, trnum, TR_FROM_DN);
traverse_polygon(mcur, t->u1, trnum, TR_FROM_DN);
traverse_polygon(mnew, t->d1, trnum, TR_FROM_UP);
traverse_polygon(mnew, t->d0, trnum, TR_FROM_UP);
}
else
{
mnew = make_new_monotone_poly(mcur, v0, v1);
traverse_polygon(mcur, t->d1, trnum, TR_FROM_UP);
traverse_polygon(mcur, t->d0, trnum, TR_FROM_UP);
traverse_polygon(mnew, t->u0, trnum, TR_FROM_DN);
traverse_polygon(mnew, t->u1, trnum, TR_FROM_DN);
}
}
else if (_equal_to(&t->hi, &seg[t->rseg].v1) &&
_equal_to(&t->lo, &seg[t->lseg].v1))
{
v0 = seg[t->rseg].next;
v1 = seg[t->lseg].next;
retval = SP_SIMPLE_LRUP;
if (dir == TR_FROM_UP)
{
do_switch = TRUE;
mnew = make_new_monotone_poly(mcur, v1, v0);
traverse_polygon(mcur, t->u0, trnum, TR_FROM_DN);
traverse_polygon(mcur, t->u1, trnum, TR_FROM_DN);
traverse_polygon(mnew, t->d1, trnum, TR_FROM_UP);
traverse_polygon(mnew, t->d0, trnum, TR_FROM_UP);
}
else
{
mnew = make_new_monotone_poly(mcur, v0, v1);
traverse_polygon(mcur, t->d1, trnum, TR_FROM_UP);
traverse_polygon(mcur, t->d0, trnum, TR_FROM_UP);
traverse_polygon(mnew, t->u0, trnum, TR_FROM_DN);
traverse_polygon(mnew, t->u1, trnum, TR_FROM_DN);
}
}
else /* no split possible */
{
retval = SP_NOSPLIT;
traverse_polygon(mcur, t->u0, trnum, TR_FROM_DN);
traverse_polygon(mcur, t->d0, trnum, TR_FROM_UP);
traverse_polygon(mcur, t->u1, trnum, TR_FROM_DN);
traverse_polygon(mcur, t->d1, trnum, TR_FROM_UP);
}
}
}
return retval;
}
/*
Main routine to get monotone polygons from the trapezoidation of
the polygon.
*/
int monotonate_trapezoids(int n)
{
register int i;
int tr_start;
memset((void *)vert, 0, sizeof(vert));
memset((void *)visited, 0, sizeof(visited));
memset((void *)mchain, 0, sizeof(mchain));
memset((void *)mon, 0, sizeof(mon));
/* First locate a trapezoid which lies inside the polygon */
/* and which is triangular */
for (i = 0; i < TRSIZE; i++)
if (inside_polygon(&tr[i]))
break;
tr_start = i;
/* Initialise the mon data-structure and start spanning all the */
/* trapezoids within the polygon */
#if 0
for (i = 1; i <= n; i++)
{
mchain[i].prev = i - 1;
mchain[i].next = i + 1;
mchain[i].vnum = i;
vert[i].pt = seg[i].v0;
vert[i].vnext[0] = i + 1; /* next vertex */
vert[i].vpos[0] = i; /* locn. of next vertex */
vert[i].nextfree = 1;
}
mchain[1].prev = n;
mchain[n].next = 1;
vert[n].vnext[0] = 1;
vert[n].vpos[0] = n;
chain_idx = n;
mon_idx = 0;
mon[0] = 1; /* position of any vertex in the first */
/* chain */
#else
for (i = 1; i <= n; i++)
{
mchain[i].prev = seg[i].prev;
mchain[i].next = seg[i].next;
mchain[i].vnum = i;
vert[i].pt = seg[i].v0;
vert[i].vnext[0] = seg[i].next; /* next vertex */
vert[i].vpos[0] = i; /* locn. of next vertex */
vert[i].nextfree = 1;
}
chain_idx = n;
mon_idx = 0;
mon[0] = 1; /* position of any vertex in the first */
/* chain */
#endif
/* traverse the polygon */
if (tr[tr_start].u0 > 0)
traverse_polygon(0, tr_start, tr[tr_start].u0, TR_FROM_UP);
else if (tr[tr_start].d0 > 0)
traverse_polygon(0, tr_start, tr[tr_start].d0, TR_FROM_DN);
/* return the number of polygons created */
return newmon();
}
/*
A greedy corner-cutting algorithm to triangulate a y-monotone
polygon in O(n) time.
Joseph O-Rourke, Computational Geometry in C.
*/
static int triangulate_single_polygon(int nvert, int posmax,
int side, int op[][3])
{
register int v;
int rc[SEGSIZE], ri = 0; /* reflex chain */
int endv, tmp, vpos;
if (side == TRI_RHS) /* RHS segment is a single segment */
{
rc[0] = mchain[posmax].vnum;
tmp = mchain[posmax].next;
rc[1] = mchain[tmp].vnum;
ri = 1;
vpos = mchain[tmp].next;
v = mchain[vpos].vnum;
if ((endv = mchain[mchain[posmax].prev].vnum) == 0)
endv = nvert;
}
else /* LHS is a single segment */
{
tmp = mchain[posmax].next;
rc[0] = mchain[tmp].vnum;
tmp = mchain[tmp].next;
rc[1] = mchain[tmp].vnum;
ri = 1;
vpos = mchain[tmp].next;
v = mchain[vpos].vnum;
endv = mchain[posmax].vnum;
}
while ((v != endv) || (ri > 1))
{
if (ri > 0) /* reflex chain is non-empty */
{
if (CROSS(vert[v].pt, vert[rc[ri - 1]].pt,
vert[rc[ri]].pt) > 0)
{ /* convex corner: cut if off */
op[op_idx][0] = rc[ri - 1];
op[op_idx][1] = rc[ri];
op[op_idx][2] = v;
op_idx++;
ri--;
}
else /* non-convex */
{ /* add v to the chain */
ri++;
rc[ri] = v;
vpos = mchain[vpos].next;
v = mchain[vpos].vnum;
}
}
else /* reflex-chain empty: add v to the */
{ /* reflex chain and advance it */
rc[++ri] = v;
vpos = mchain[vpos].next;
v = mchain[vpos].vnum;
}
} /* end-while */
/* reached the bottom vertex. Add in the triangle formed */
op[op_idx][0] = rc[ri - 1];
op[op_idx][1] = rc[ri];
op[op_idx][2] = v;
op_idx++;
ri--;
return 0;
}
/*
For each monotone polygon, find the ymax and ymin (to determine the
two y-monotone chains) and pass on this monotone polygon for greedy
triangulation.
Take care not to triangulate duplicate monotone polygons
*/
int triangulate_monotone_polygons(int nvert, int nmonpoly, int op[][3])
{
register int i;
point_t ymax, ymin;
int p, vfirst, posmax, posmin, v;
int vcount, processed;
#ifdef DEBUG
for (i = 0; i < nmonpoly; i++)
{
fprintf(stderr, "\n\nPolygon %d: ", i);
vfirst = mchain[mon[i]].vnum;
p = mchain[mon[i]].next;
fprintf (stderr, "%d ", mchain[mon[i]].vnum);
while (mchain[p].vnum != vfirst)
{
fprintf(stderr, "%d ", mchain[p].vnum);
p = mchain[p].next;
}
}
fprintf(stderr, "\n");
#endif
op_idx = 0;
for (i = 0; i < nmonpoly; i++)
{
vcount = 1;
processed = FALSE;
vfirst = mchain[mon[i]].vnum;
ymax = ymin = vert[vfirst].pt;
posmax = posmin = mon[i];
mchain[mon[i]].marked = TRUE;
p = mchain[mon[i]].next;
while ((v = mchain[p].vnum) != vfirst)
{
if (mchain[p].marked)
{
processed = TRUE;
break; /* break from while */
}
else
mchain[p].marked = TRUE;
if (_greater_than(&vert[v].pt, &ymax))
{
ymax = vert[v].pt;
posmax = p;
}
if (_less_than(&vert[v].pt, &ymin))
{
ymin = vert[v].pt;
posmin = p;
}
p = mchain[p].next;
vcount++;
}
if (processed) /* Go to next polygon */
continue;
if (vcount == 3) /* already a triangle */
{
op[op_idx][0] = mchain[p].vnum;
op[op_idx][1] = mchain[mchain[p].next].vnum;
op[op_idx][2] = mchain[mchain[p].prev].vnum;
op_idx++;
}
else /* triangulate the polygon */
{
v = mchain[mchain[posmax].next].vnum;
if (_equal_to(&vert[v].pt, &ymin))
{ /* LHS is a single line */
triangulate_single_polygon(nvert, posmax, TRI_LHS, op);
}
else
triangulate_single_polygon(nvert, posmax, TRI_RHS, op);
}
}
#ifdef DEBUG
for (i = 0; i < op_idx; i++)
fprintf(stderr, "tri #%d: (%d, %d, %d)\n", i, op[i][0], op[i][1],
op[i][2]);
#endif
return op_idx;
}
/*
Input specified as contours.
Outer contour must be anti-clockwise.
All inner contours must be clockwise.
Every contour is specified by giving all its points in order. No
point shoud be repeated. i.e. if the outer contour is a square,
only the four distinct endpoints shopudl be specified in order.
ncontours: contours
cntr: An array describing the number of points in each
contour. Thus, cntr[i] = points in the i'th contour.
vertices: Input array of vertices. Vertices for each contour
immediately follow those for previous one. Array location
vertices[0] must NOT be used (i.e. i/p starts from
vertices[1] instead. The output triangles are
specified w.r.t. the indices of these vertices.
triangles: Output array to hold triangles.
Enough space must be allocated for all the arrays before calling
this routine
*/
int triangulate_polygon(int ncontours, int cntr[], vector<double> vertices_x,
vector<double> vertices_y, int (*triangles)[3])
{
// cout<<"ncontours "<<ncontours<<endl;
register int i;
int nmonpoly, ccount, npoints, genus;
int n;
memset((void *)seg, 0, sizeof(seg));
ccount = 0;
i = 1;
assert(vertices_x.size() < SEGSIZE);
while (ccount < ncontours)
{
int j;
int first, last;
npoints = cntr[ccount];
// cout<<"npoints "<<npoints<<endl;
first = i;
last = first + npoints - 1;
for (j = 0; j < npoints; j++, i++)
{
// seg[i].v0.x = vertices[i][0];
// seg[i].v0.y = vertices[i][1];
seg[i].v0.x = vertices_x[i];
seg[i].v0.y = vertices_y[i];
// cout<<"x "<<seg[i].v0.x<<endl;
// cout<<"y "<<seg[i].v0.y<<endl;
if (i == last)
{
seg[i].next = first;
seg[i].prev = i-1;
seg[i-1].v1 = seg[i].v0;
}
else if (i == first)
{
seg[i].next = i+1;
seg[i].prev = last;
seg[last].v1 = seg[i].v0;
}
else
{
seg[i].prev = i-1;
seg[i].next = i+1;
seg[i-1].v1 = seg[i].v0;
}
seg[i].is_inserted = FALSE;
}
ccount++;
}
genus = ncontours - 1;
n = i-1;
initialise(n);
construct_trapezoids(n);
nmonpoly = monotonate_trapezoids(n);
int no_tri = triangulate_monotone_polygons(n, nmonpoly, triangles);
return no_tri;
}
//////////////////////////////////////////////////////////////////////////////
/////////// another implementation of triangulation /////////////////////////
/////////// 2011.7 from code project/////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
Dimension GlobDim::mDim = DIM_NONE;
/*
initialize the polygon, input points
*/
void HPolygon::Init( const char name[])
{
int n, ni;
double x, y;
FILE *f = fopen( name, "rt");
if (!f)
THROW_FILE( "can not open file", name);
printf( "Reading file: %s\n", name );
fscanf( f, "%d", &n);
mtabSize.resize( n);
for ( int i=0; i<n; ++i){
fscanf( f, "%d", &ni);
mtabSize[i] = ni;
for ( int j=0; j<ni; ++j)
{
fscanf( f, "%lg %lg", &x, &y);
mtabPnt.insert( mtabPnt.end(), Vect2D( x, y) );
}
}
fclose( f);
}
/*
new initialization function, read the input from vectors instead of files
*/
void HPolygon::Init2(int ncontours, int cntr[], vector<double>& vertices_x,
vector<double>& vertices_y)
{
int n = ncontours;
mtabSize.resize(n);
int point_id = 1;
int count = 0;
for ( int i = 0; i< n; i++){
int ni = cntr[i];
mtabSize[i] = ni;
// cout<<"ni "<<ni<<endl;
/* double first_x, first_y;
int first_p_id;*/
double first_x = 0.0;
double first_y = 0.0;
int first_p_id = 0;
for ( int j = 0; j < ni; j++){
double x = vertices_x[j + count];
double y = vertices_y[j + count];
// cout<<"x "<<x<<" y "<<y<<endl;
mtabPnt.insert( mtabPnt.end(), Vect2D( x, y) );
if(j == 0){
first_x = x;
first_y = y;
first_p_id = point_id;
}
p_id_list.push_back(point_id);
point_id++;
}
mtabSize[i]++;
mtabPnt.insert( mtabPnt.end(), Vect2D( first_x, first_y) );
count += ni;
p_id_list.push_back(first_p_id);//no ++ !!!
// count += ni;
}
}
void HPolygon::Triangulate()
{
// printf( "Triangulation started\n" );
HGrid grid;
grid.Init( mtabPnt, mtabSize);
grid.Generate();
vector<HTri>::iterator itri;
IterGCell itr;
for ( itr = grid.CellBegin(); itr != grid.CellEnd(); ++itr)
{
itri = mtabCell.insert( mtabCell.end(), HTri() );
(*itri).rIndex( 0) = (*(*itr)->Node( 0))->Index();
(*itri).rIndex( 1) = (*(*itr)->Node( 1))->Index();
(*itri).rIndex( 2) = (*(*itr)->Node( 2))->Index();
}
}
/*
new form of triangulation
*/
int HPolygon::Triangulation2(int ncontours, int cntr[],
vector<double>& vertices_x,
vector<double>& vertices_y)
{
//try
// {
// HPolygon poly;
// if ( argc != 3 ){
// printf("usage: hgrd [input file with points][output tecplot file]\n");
// return 1;
// }
// poly.Init( argv[1]);
// poly.Triangulate();
// poly.WriteTEC( argv[2]);
// }
// catch ( Except *pe)
// {
// ASSERT( pe);
// TRACE_EXCEPTION( *pe);
// TRACE_TO_STDERR( *pe);
// delete pe;
// }
// for(unsigned int i = 0;i < vertices_x.size();i++){
// cout<<vertices_x[i]<<" "<<vertices_y[i]<<endl;
// }
// cout<<mtabPnt.max_size()<<endl; ////////268,435,455
Init2(ncontours, cntr, vertices_x,vertices_y);
Triangulate();
int triangle_no = OutPut();
return triangle_no;
}
/*
output the result into files
*/
void HPolygon::WriteTEC( const char name[])
{
printf( "Writing TECPLOT file: %s\n", name );
FILE *f = fopen( name, "wt");
fprintf( f, "TITLE = \"polygon\"\n");
fprintf( f, "VARIABLES = \"X\", \"Y\"\n");
fprintf( f, "ZONE T=\"TRIANGLES\", ");
fprintf( f, "N=%2ld, ", (long int)mtabPnt.size() );
fprintf( f, "E=%2ld, F=FEPOINT, ET=TRIANGLE C=BLACK\n ",
(long int)mtabCell.size() );
size_t i;
for ( i=0; i<mtabPnt.size(); ++i)
fprintf( f, "%lg %lg\n", mtabPnt[i].X(), mtabPnt[i].Y() );
for ( i=0; i<mtabCell.size(); ++i)
fprintf( f, "%d %d %d\n", 1+mtabCell[i].Index(0),
1+mtabCell[i].Index(1), 1+mtabCell[i].Index(2) );
fclose( f);
}
int HPolygon::OutPut()
{
// for (int i = 0; i < mtabPnt.size(); ++i)
// printf( "%lg %lg\n", mtabPnt[i].X(), mtabPnt[i].Y() );
//
//
// for (int i = 0; i< mtabCell.size(); ++i)
// printf( "%d %d %d\n", 1+mtabCell[i].Index(0),
// 1+mtabCell[i].Index(1), 1+mtabCell[i].Index(2) );
// cout<<mtabPnt.size()<<" "<<mtabCell.size()<<endl;
return mtabCell.size();
}
MGFloat Angle( const Vect2D &nd, const Vect2D &nd1, const Vect2D &nd2)
{
static Vect2D v1, v2;
static MGFloat dvect, dsin, dcos;
//v1 = nd1 - nd;
//v2 = nd2 - nd;
v1 = (nd1 - nd).module();
v2 = (nd2 - nd).module();
dsin = v1.X()*v2.Y() - v2.X()*v1.Y();
dcos = v1.X()*v2.X() + v1.Y()*v2.Y();
if ( fabs( dsin) < ZERO && fabs( dcos) < ZERO)
return M_PI_2;
dvect = atan2( dsin, dcos);
return dvect;
}
/*
check vector crossing
*/
bool CheckCrossing( const Vect2D& v1, const Vect2D& v2, const Vect2D& v3,
const Vect2D& v4)
{
Vect2D vv, vv1, vv2;
MGFloat t1, t2, t;
MGFloat h1, h2;
vv = v2 - v1;
vv1 = v3 - v1;
vv2 = v4 - v1;
ASSERT( fabs( vv.module() ) > ZERO );
t1 = vv * vv1 / vv.module();
t2 = vv * vv2 / vv.module();
h1 = (vv.X()*vv1.Y() - vv.Y()*vv1.X()) / vv.module();
h2 = (vv.X()*vv2.Y() - vv.Y()*vv2.X()) / vv.module();
if ( fabs( h2 - h1) < ZERO)
return false;
t = t1 - (t2 - t1)/(h2 - h1) * h1;
if ( t > 0.0 && t < vv.module() && h1 * h2 < ZERO )
return true;
else
return false;
}
bool AreNeigbours( const IterGCell& ic1, const IterGCell& ic2)
{
char sbuf[256];
bool b1, b2;
// TRACE2( "itrcl = %d %d", ic1, *ic1);
// (*ic1)->DumpTri();
// TRACE2( "itrcl = %d %d", ic2, *ic2);
// (*ic2)->DumpTri();
b1 = b2 = false;
for ( int i=0; i<NUM_TRI; ++i)
{
// if ( (*ic1)->Cell(i) != NULL)
if ( (*ic1)->Cell(i) == ic2 )
b1 = true;
// if ( (*ic2)->Cell(i) != NULL)
if ( (*ic2)->Cell(i) == ic1 )
b2 = true;
}
sprintf( sbuf, " b1 = %d b2 = %d", static_cast<int>(b1),
static_cast<int>(b2) );
TM_TRACE( sbuf);
if ( !b1 || !b2)
THROW_INTERNAL( "Not neighbours found");
return true;
}
/*
class HGrdTri
main class for triangulation, grid
*/
HGrdTri::HGrdTri() : mbIsOutside( false)
{
for ( MGInt i=0; i<NUM_TRI; i++)
{
// mlstNod[i] = NULL;
// mlstCell[i] = NULL;
mlstNod[i] = (IterGPnt)NULL;
mlstCell[i] = (IterGCell)NULL;
}
}
/*
check whether two grids are visible
*/
bool HGrdTri::IsVisible( const IterGCell& icl, const Vect2D& vct)
{
static Vect2D vfac, v1, v2;
static MGFloat d1, d2;
// static char sbuf[1024];
if ( Cell(0) == icl )
{
v1 = *( (*Node(0)) ) - *( (*Node(2)) );
v2 = *( (*Node(1)) ) - *( (*Node(2)) );
vfac = vct - *( (*Node(2)) );
}
else if ( Cell(1) == icl )
{
v1 = *( (*Node(1)) ) - *( (*Node(0)) );
v2 = *( (*Node(2)) ) - *( (*Node(0)) );
vfac = vct - *( (*Node(0)) );
}
else if ( Cell(2) == icl )
{
v1 = *( (*Node(2)) ) - *( (*Node(1)) );
v2 = *( (*Node(0)) ) - *( (*Node(1)) );
vfac = vct - *( (*Node(1)) );
}
else
{
ASSERT( 0);
}
d1 = v1.X()*vfac.Y() - v1.Y()*vfac.X();
d2 = v2.X()*vfac.Y() - v2.Y()*vfac.X();
d1 /= vfac.module();
d2 /= vfac.module();
if ( (d2 > ZERO && d1 < -ZERO) )
return false;
else
return true;
}
bool HGrdTri::IsVisibleDump( const IterGCell& icl, const Vect2D& vct)
{
// static Vect2D vfac, v1, v2;
// static MGFloat d1, d2;
// static char sbuf[1024];
Vect2D vfac, v1, v2;
MGFloat d1, d2;
THROW_INTERNAL("Should not be used !!!");
if ( Cell(0) == icl )
{
v1 = *( (*Node(0)) ) - *( (*Node(2)) );
v2 = *( (*Node(1)) ) - *( (*Node(2)) );
vfac = vct - *( (*Node(2)) );
}
else if ( Cell(1) == icl )
{
v1 = *( (*Node(1)) ) - *( (*Node(0)) );
v2 = *( (*Node(2)) ) - *( (*Node(0)) );
vfac = vct - *( (*Node(0)) );
}
else if ( Cell(2) == icl )
{
v1 = *( (*Node(2)) ) - *( (*Node(1)) );
v2 = *( (*Node(0)) ) - *( (*Node(1)) );
vfac = vct - *( (*Node(1)) );
}
else
{
ASSERT( 0);
}
d1 = v1.X()*vfac.Y() - v1.Y()*vfac.X();
d2 = v2.X()*vfac.Y() - v2.Y()*vfac.X();
if ( d1 * d2 > ZERO )
{
TM_TRACE2( "v1 = (%lg %lg)", v1.X(), v1.Y() );
TM_TRACE2( "v2 = (%lg %lg)", v2.X(), v2.Y() );
TM_TRACE2( "vf = (%lg %lg)", vfac.X(), vfac.Y() );
TM_TRACE2( "d1 = %lg d1 = %lg", d1, d2 );
return false;
}
else
return true;
}
/*
for a grid, set its neighbors
*/
void HGrdTri::SetNeighbour( const IterGCell& itrcl)
{
static HGrdTri *ptr;
// ASSERT( itrcl != NULL);
ASSERT( itrcl != (IterGCell)NULL);
ptr = (*itrcl);
ASSERT( ptr);
if ( ( ptr->Node(1) == Node(0) && ptr->Node(0) == Node(1) ) ||
( ptr->Node(0) == Node(0) && ptr->Node(2) == Node(1) ) ||
( ptr->Node(2) == Node(0) && ptr->Node(1) == Node(1) ) )
{
rCell(0) = itrcl;
}
else
if ( ( ptr->Node(1) == Node(1) && ptr->Node(0) == Node(2) ) ||
( ptr->Node(0) == Node(1) && ptr->Node(2) == Node(2) ) ||
( ptr->Node(2) == Node(1) && ptr->Node(1) == Node(2) ) )
{
rCell(1) = itrcl;
}
else
if ( ( ptr->Node(1) == Node(2) && ptr->Node(0) == Node(0) ) ||
( ptr->Node(0) == Node(2) && ptr->Node(2) == Node(0) ) ||
( ptr->Node(2) == Node(2) && ptr->Node(1) == Node(0) ) )
{
rCell(2) = itrcl;
}
}
void HGrdTri::NullifyThis( HGrdTri *pcl)
{
for ( MGInt i=0; i<NUM_TRI; i++)
{
// if ( mlstCell[i] != NULL)
// if ( (*mlstCell[i]) == pcl)
// mlstCell[i] = NULL;
if ( mlstCell[i] != (IterGCell)NULL)
if ( (*mlstCell[i]) == pcl)
mlstCell[i] = (IterGCell)NULL;
}
}
void HGrdTri::NullifyThis( HFroSeg *pseg)
{
if ( ( pseg->PntLf() == Node(0) && pseg->PntLf() == Node(1) ) ||
( pseg->PntRt() == Node(0) && pseg->PntRt() == Node(1) ) )
{
// rCell(0) = NULL;
rCell(0) = (IterGCell)NULL;
}
else
if ( ( pseg->PntLf() == Node(1) && pseg->PntLf() == Node(2) ) ||
( pseg->PntRt() == Node(1) && pseg->PntRt() == Node(2) ) )
{
// rCell(1) = NULL;
rCell(1) = (IterGCell)NULL;
}
else
if ( ( pseg->PntLf() == Node(2) && pseg->PntLf() == Node(0) ) ||
( pseg->PntRt() == Node(2) && pseg->PntRt() == Node(0) ) )
{
// rCell(2) = NULL;
rCell(2) = (IterGCell)NULL;
}
}
void HGrdTri::InvalidateNeighb()
{
for ( MGInt i=0; i<NUM_TRI; i++)
{
// if ( mlstCell[i] != NULL)
if ( mlstCell[i] != (IterGCell)NULL)
(*mlstCell[i])->NullifyThis( this);
}
}
bool HGrdTri::IsInside( const Vect2D& vct)
{
// ::TODO:: new and faster algorithm should be introduced
MGFloat alf;
alf = ::Angle( vct, *(*Node(0)), *(*Node(1)) );
alf += ::Angle( vct, *(*Node(1)), *(*Node(2)) );
alf += ::Angle( vct, *(*Node(2)), *(*Node(0)) );
if ( fabs(alf) < M_PI )
return false;
else
return true;
}
/*
set the center point of a triangle
*/
bool HGrdTri::SetCircCenter()
{
static MGFloat x1, y1, x2, y2, x3, y3;
static MGFloat xr, yr, d;
x1 = (*Node(0))->X();
y1 = (*Node(0))->Y();
x2 = (*Node(1))->X();
y2 = (*Node(1))->Y();
x3 = (*Node(2))->X();
y3 = (*Node(2))->Y();
d = y3*(x2 - x1) + y2*(x1 - x3) + y1*(x3 - x2);
if ( fabs( d) < ZERO)
{
DumpTri();
// TM_TRACE1( "d = %lg", d);
printf("%.6f\n", d);
printf("(%.7f %.7f)\n", x1, y1);
printf("(%.7f %.7f)\n", x2, y2);
printf("(%.7f %.7f)\n", x3, y3);
// cout<<"SetCircCenter() "<<"error "<<endl;
return true;
// THROW_INTERNAL( "Problem inside SetCircCenter() !!!");
}
xr = x1*x1*(y3-y2) + x2*x2*(y1-y3) + x3*x3*(y2-y1) +
y1*y1*(y3-y2) + y2*y2*(y1-y3) + y3*y3*(y2-y1);
xr *= -0.5/d;
yr = x1*x1*(x3-x2) + x2*x2*(x1-x3) + x3*x3*(x2-x1) +
y1*y1*(x3-x2) + y2*y2*(x1-x3) + y3*y3*(x2-x1);
yr *= 0.5/d;
mCircCenter = Vect2D( xr, yr);
return false;
}
Vect2D HGrdTri::Center()
{
return ( *(*Node(0)) + *(*Node(1)) + *(*Node(2)) )/3.0;
}
IterGCell HGrdTri::NextCell( const Vect2D& vct)
{
static Vect2D v1, v2;
// if ( Cell(0) != NULL)
if ( Cell(0) != (IterGCell)NULL){
v1 = *(*Node(1)) - *(*Node(0));
v1 = Vect2D( -v1.Y(), v1.X() );
v2 = ( *(*Node(1)) + *(*Node(0)) )/2.0;
v2 = vct - v2;
if ( v1 * v2 < 0.0 )
return Cell(0);
}
// if ( Cell(1) != NULL)
if ( Cell(1) != (IterGCell)NULL){
v1 = *(*Node(2)) - *(*Node(1));
v1 = Vect2D( -v1.Y(), v1.X() );
v2 = ( *(*Node(2)) + *(*Node(1)) )/2.0;
v2 = vct - v2;
if ( v1 * v2 < 0.0 )
return Cell(1);
}
// if ( Cell(2) != NULL)
if ( Cell(2) != (IterGCell)NULL){
v1 = *(*Node(0)) - *(*Node(2));
v1 = Vect2D( -v1.Y(), v1.X() );
v2 = ( *(*Node(0)) + *(*Node(2)) )/2.0;
v2 = vct - v2;
if ( v1 * v2 < 0.0 )
return Cell(2);
}
return (IterGCell)NULL;
}
/*
iterate to next cell to access
*/
IterGCell HGrdTri::NextCell( HFroSeg *pseg, const IterGCell& iclprv)
{
IterGCell itrnb, itr1, itr2;
Vect2D v1, v2, v3, v4;
v1 = *(*(pseg->PntLf()));
v2 = *(*(pseg->PntRt()));
// if ( iclprv == NULL)
if ( iclprv == (IterGCell)NULL){
if ( Node(0) == pseg->PntLf() )
{
v3 = *(*Node(1));
v4 = *(*Node(2));
itrnb = Cell(1);
if ( Node(1) == pseg->PntRt() || Node(2) == pseg->PntRt() )
// return NULL;
return (IterGCell)NULL;
}
else if ( Node(1) == pseg->PntLf() )
{
v3 = *(*Node(2));
v4 = *(*Node(0));
itrnb = Cell(2);
if ( Node(2) == pseg->PntRt() || Node(0) == pseg->PntRt() )
// return NULL;
return (IterGCell)NULL;
}
else if ( Node(2) == pseg->PntLf() )
{
v3 = *(*Node(0));
v4 = *(*Node(1));
itrnb = Cell(0);
if ( Node(0) == pseg->PntRt() || Node(1) == pseg->PntRt() )
// return NULL;
return (IterGCell)NULL;
}
else
{
THROW_INTERNAL("NextCell - seg: node not found");
}
if ( ::CheckCrossing( v1, v2, v3, v4 ) == true)
{
return itrnb;
}
else
// return NULL;
return (IterGCell)NULL;
}
else
{
int k;
for ( int i=0; i<NUM_TRI; ++i)
{
if ( iclprv != Cell(i) )
{
if ( i == NUM_TRI-1)
k = 0;
else
k = i+1;
v3 = *(*Node(i));
v4 = *(*Node(k));
if ( ::CheckCrossing( v1, v2, v3, v4 ) == true)
return Cell(i);
}
}
// return NULL;
return (IterGCell)NULL;
}
}
bool HGrdTri::IsInsideCirc( const Vect2D& vct)
{
static MGFloat R2, r2;
static Vect2D vtmp, v0;
v0 = CircCenter();
vtmp = v0 - *( (*Node(0)) );
R2 = vtmp * vtmp;
vtmp = v0 - vct;
r2 = vtmp * vtmp;
if ( r2 < R2)
return true;
return false;
}
/*
class HFront
*/
HFront::~HFront()
{
iterator i;
for ( i= begin(); i != end(); i++)
if ( *i != NULL) delete (*i);
}
MGFloat HFront::Angle( const Vect2D& vct)
{
iterator itr;
MGFloat alf;
IterGPnt ipnt1, ipnt2;
alf = 0.0;
for ( itr = begin(); itr != end(); itr++)
{
ipnt1 = (*itr)->PntLf();
ipnt2 = (*itr)->PntRt();
alf += ::Angle( vct, *(*ipnt1), *(*ipnt2) );
}
return alf;
}
/*
class HGrid
*/
HGrid::~HGrid()
{
CollGPnt::iterator itrpnt;
CollGCell::iterator itrcell;
for ( itrpnt = mcolPnt.begin(); itrpnt != mcolPnt.end(); itrpnt++)
if ( (*itrpnt) != NULL) delete (*itrpnt);
for ( itrcell = mcolCell.begin(); itrcell != mcolCell.end(); itrcell++)
if ( (*itrcell) != NULL) delete (*itrcell);
}
void HGrid::Init( const vector<Vect2D>& tabp, const vector<MGInt>& tabn )
{
MGInt i, j, nprev;
IterFro ifro;
HGrdPnt *ppnt;
IterGPnt ip0, ipp, ipa;
HFroSeg *pfro;
Vect2D v0, v1, v2;
map< Vect2D, IterGPnt> mapNod;
map< Vect2D, IterGPnt>::iterator imap;
// char sbuf[512];
double d;
nprev = 0;
for ( i=0; i<(MGInt)tabn.size(); ++i)
{
v1 = tabp[nprev];
v2 = tabp[nprev+tabn[i]-1];
d = (v2-v1).module();
if ( (v2-v1).module() < ZERO)
{
ifro = mcolFro.insert( mcolFro.end(), HFront() );
imap = mapNod.find( tabp[nprev]);
if ( imap != mapNod.end() )
{
ip0 = ipp = ipa = (*imap).second;
}
else
{
ppnt = MGNEW HGrdPnt( tabp[nprev]);
ppnt->rIndex() = nprev;
ip0 = ipp = ipa = InsertPoint( ppnt);
mapNod.insert( map< Vect2D, IterGPnt>::value_type( *ppnt, ipa));
}
v0 = *(*ip0);
for ( j=1; j<tabn[i]; ++j)
{
v1 = *(*ipp);
v2 = tabp[nprev+j];
if ( (v2 - v1).module() > ZERO)
{
if ( j != tabn[i]-1 || (tabp[nprev+j] - v0 ).module() > ZERO)
{
imap = mapNod.find( tabp[nprev+j]);
if ( imap != mapNod.end() )
{
ipa = (*imap).second;
ppnt = *ipa;
}
else
{
ppnt = MGNEW HGrdPnt( tabp[nprev+j]);
ppnt->rIndex() = nprev+j;
ipa = InsertPoint( ppnt);
mapNod.insert( map< Vect2D,
IterGPnt>::value_type( *ppnt, ipa) );
}
pfro = MGNEW HFroSeg( ipp, ipa);
(*ifro).insert( (*ifro).end(), pfro);
ipp = ipa;
}
}
}
v1 = *(*ipp);
v2 = *(*ip0);
if ( (v2 - v1).module() > ZERO)
{
pfro = MGNEW HFroSeg( ipp, ip0);
(*ifro).insert( (*ifro).end(), pfro);
}
}
nprev += tabn[i];
}
IterFro itrfro;
IterFSeg itrsg;
IterGPnt ip1, ip2;
for ( itrfro = mcolFro.begin(); itrfro != mcolFro.end(); ++itrfro)
{
// TRACE1( "Front size = %d\n", (*itrfro).size() );
itrsg = (*itrfro).begin();
ip0 = (*itrsg)->PntLf();
ip1 = (*itrsg)->PntRt();
for ( ++itrsg; itrsg != (*itrfro).end(); ++itrsg)
{
if ( (*itrsg)->PntLf() != ip1 )
{
TM_TRACE( "Front not consistent !!!\n");
}
ip1 = (*itrsg)->PntRt();
v1 = *(*(*itrsg)->PntLf());
v2 = *(*(*itrsg)->PntRt());
if ( (v2 - v1).module() < ZERO)
TM_TRACE1( "seg length = %24.16lg\n", (v2 - v1).module() );
}
if ( ip0 != ip1 )
{
TM_TRACE( "Front not consistent (closure problem) !!!\n");
}
}
// ASSERT(0);
#ifdef _DEBUG
FILE *f = fopen( "front.plt", "wt");
int isize = 0;
for ( isize = 0, itrfro = mcolFro.begin(); itrfro != mcolFro.end();
++itrfro, ++isize)
{
fprintf( f, "VARIABLES = \"X\", \"Y\"\n" );
fprintf( f, "ZONE I=%d F=POINT\n", (*itrfro).size()+1);
for ( itrsg = (*itrfro).begin(); itrsg != (*itrfro).end(); ++itrsg)
{
v1 = *(*(*itrsg)->PntLf());
v2 = *(*(*itrsg)->PntRt());
fprintf( f, "%lg %lg\n", v1.X(), v1.Y() );
}
fprintf( f, "%lg %lg\n", v2.X(), v2.Y() );
}
fclose( f);
#endif // _DEBUG
}
HFroSeg* HGrid::NewFace( MGInt i, IterGCell icl)
{
HFroSeg* psg;
THROW_ALLOC( psg = MGNEW HFroSeg() );
switch ( i)
{
case 0:
psg->rPntLf() = (*icl)->Node(0);
psg->rPntRt() = (*icl)->Node(1);
// if ( icl != NULL ){
if ( icl != (IterGCell)NULL ){
psg->rCellUp() = icl;
psg->rCellLo() = (*icl)->Cell(0);
}
break;
case 1:
psg->rPntLf() = (*icl)->Node(1);
psg->rPntRt() = (*icl)->Node(2);
// if ( icl != NULL)
if ( icl != (IterGCell)NULL){
psg->rCellUp() = icl;
psg->rCellLo() = (*icl)->Cell(1);
}
break;
case 2:
psg->rPntLf() = (*icl)->Node(2);
psg->rPntRt() = (*icl)->Node(0);
// if ( icl != NULL)
if ( icl != (IterGCell)NULL){
psg->rCellUp() = icl;
psg->rCellLo() = (*icl)->Cell(2);
}
break;
default:
if ( psg) delete psg;
ASSERT( 0);
return NULL;
};
return psg;
}
/*
check neighbor
*/
bool HGrid::CheckNeighb( IterGCell icl, CollFSeg& lstsg,
const Vect2D& vct, const IterGCell& ipvcl)
{
HGrdTri *pthis;
pthis = (HGrdTri*)( (*icl) );
if ( pthis->IsInsideCirc( vct ) == true )
{
HGrdTri *ptri;
HFroSeg *pseg;
IterGCell itri;
IterGPnt ipnt;
bool bVis;
for ( int i=0; i<NUM_TRI; i++)
{
// if ( (*icl)->Cell(i) != ipvcl || ipvcl == NULL)
if ( (*icl)->Cell(i) != ipvcl || ipvcl == (IterGCell)NULL){
pseg = NewFace( i, icl); // this allocate memory for pseg !!!
itri = (*icl)->Cell(i);
bVis = false;
// if ( itri != NULL )
if ( itri != (IterGCell)NULL )
if ( (*itri)->IsOutside() == true)
// itri = NULL;
itri = (IterGCell)NULL;
// if ( itri != NULL)
if ( itri != (IterGCell)NULL){
ptri = (HGrdTri*)( (*itri) );
ASSERT( ptri);
bVis = ptri->IsVisible( icl, vct);
}
// if ( itri != NULL && bVis)
if ( itri != (IterGCell)NULL && bVis){
if ( CheckNeighb( itri, lstsg, vct, icl ) == true )
{
delete pseg;
}
else
{
lstsg.insert( lstsg.end(), pseg );
// pseg->rCellUp() = NULL;
pseg->rCellUp() = (IterGCell)NULL;
}
}
else
{
lstsg.insert( lstsg.end(), pseg );
// pseg->rCellUp() = NULL;
pseg->rCellUp() = (IterGCell)NULL;
}
}
}
ptri = (HGrdTri*)( (*icl) );
ptri->InvalidateNeighb();
mcolCell.erase( icl);
delete ptri;
return true;
}
return false;
}
MGInt HGrid::InsertPointIntoMesh( IterGPnt pntitr)
{
Vect2D vct;
IterGCell itrcl, itrcl2, itrcl0, itrclout;
HGrdTri *ptri;
CollFSeg *plstsg;
IterFSeg itrsg, itrsg2;
HFroSeg *pseg;
static int num = 0;
++num;
vct = *(*pntitr);
// sprintf( sbuf, "POINT No = %d; x=%14.8lg, y=%14.8lg", num, vct.X(), vct.Y());
// TRACE1( "%s", sbuf);
itrcl = mcolCell.begin();
do
{
itrcl0 = (*itrcl)->NextCell( vct);
// if ( itrcl0 == NULL)
if ( itrcl0 == (IterGCell)NULL)
break;
itrcl = itrcl0;
}
while ( true);
THROW_ALLOC( plstsg = MGNEW CollFSeg );
// next function creates segments bounding Delaunay cavity (stored in plstsg)
// removes cavity triangles from mcolCell;
// ALL ITERATORS TO THOSE CELLS ARE THEN INVALID !!!
// iterators to those cells are set to NULL
// CheckNeighb( itrcl, *plstsg, vct, NULL);
CheckNeighb( itrcl, *plstsg, vct, (IterGCell)NULL);
// sorting segments stored in plstsg
itrsg = plstsg->end();
itrsg--;
do
{
for ( itrsg2 = plstsg->begin(); itrsg2 != plstsg->end(); itrsg2++)
{
if ( (*itrsg)->PntLf() == (*itrsg2)->PntRt() )
{
pseg = (*itrsg2);
plstsg->erase( itrsg2);
itrsg = plstsg->insert( itrsg, pseg );
break;
}
}
}
while ( itrsg != plstsg->begin() );
// creating new triangles and connections between triangles in Delaunay cavity
// itrcl0 = itrcl2 = NULL;
itrcl0 = itrcl2 = (IterGCell)NULL;
for ( itrsg = plstsg->begin(); itrsg != plstsg->end(); itrsg++)
{
THROW_ALLOC( ptri = MGNEW HGrdTri );
itrclout = (*itrsg)->CellLo();
ptri->rNode(0) = (*itrsg)->PntLf();
ptri->rNode(1) = (*itrsg)->PntRt();
ptri->rNode(2) = pntitr;
ptri->rCell(0) = itrclout;
if ( ptri->SetCircCenter() )
{
FILE *f = fopen( "cavity.plt", "wt");
ExportTECTmp( f);
fclose( f);
TM_TRACE1( "num = %d", num);
TM_TRACE2( "new point = %lg %lg", vct.X(), vct.Y() );
TM_TRACE1( "no of segs bounding cavity = %d", plstsg->size() );
FILE *ff = fopen( "cavity_front.plt", "wt");
fprintf( ff, "VARIABLES = \"X\", \"Y\"\n");
fprintf( ff, "ZONE I=%d F=POINT\n", (int) (plstsg->size()+1) );
fprintf( ff, "%lg %lg\n", (*(*plstsg->begin())->PntLf())->X(),
(*(*plstsg->begin())->PntLf())->Y() );
for ( itrsg = plstsg->begin(); itrsg != plstsg->end(); itrsg++)
fprintf( ff, "%lg %lg\n", (*(*itrsg)->PntRt())->X(),
(*(*itrsg)->PntRt())->Y() );
fclose( ff);
THROW_INTERNAL("Flat triangle !!!");
}
itrcl = InsertCell( ptri);
// if ( itrclout != NULL)
if ( itrclout != (IterGCell)NULL)
(*itrclout)->SetNeighbour( itrcl);
// if ( itrcl0 == NULL)
if ( itrcl0 == (IterGCell)NULL)
itrcl0 = itrcl;
// if ( itrcl2 != NULL)
if ( itrcl2 != (IterGCell)NULL){
(*itrcl)->rCell(2) = itrcl2;
(*itrcl2)->rCell(1) = itrcl;
}
itrcl2 = itrcl;
}
// if ( itrcl2 != NULL && itrcl0 != NULL)
if ( itrcl2 != (IterGCell)NULL && itrcl0 != (IterGCell)NULL)
{
(*itrcl0)->rCell(2) = itrcl2;
(*itrcl2)->rCell(1) = itrcl0;
}
// removing all segments stored in plstsg
for ( itrsg = plstsg->begin(); itrsg != plstsg->end(); itrsg++)
if ( (*itrsg) != NULL ) delete (*itrsg);
if ( plstsg) delete plstsg;
return num;
}
bool HGrid::PointExists( const Vect2D& vct)
{
// Leaf<IterFacGPnt> *pndlf;
// IterFacGPnt ipn;
//
// pndlf = mPntQTree.ClosestItem( vct );
// if ( pndlf != NULL)
// {
// ipn = pndlf->Data();
//
// if ( fabs( (*ipn)->X() - vct.X() ) < ZERO &&
// fabs( (*ipn)->Y() - vct.Y() ) < ZERO )
// {
// return true;
// }
// }
//
return false;
}
// creates basic trinagulation (two triangles) and inserts all boundary points
void HGrid::InitTriangles()
{
CollGPnt::iterator itr;
Vect2D vmin, vmax, vct;
bool bFirst = true;
HGrdPnt *pnd1, *pnd2, *pnd3, *pnd4;
HGrdTri *ptri1, *ptri2;
IterGPnt ind1, ind2, ind3, ind4;
IterGCell itri1, itri2;
// ind1 = ind2 = ind3 = ind4 = NULL;
ind1 = ind2 = ind3 = ind4 = (IterGPnt)NULL;
// itri1 = itri2 = NULL;
itri1 = itri2 = (IterGCell)NULL;
// finding limits
for ( itr = mcolPnt.begin(); itr != mcolPnt.end(); itr++)
{
vct = *(*itr);
if ( bFirst)
{
vmin = vmax = vct;
bFirst = false;
}
else
{
if ( vct.X() > vmax.X() ) vmax.rX() = vct.X();
if ( vct.Y() > vmax.Y() ) vmax.rY() = vct.Y();
if ( vct.X() < vmin.X() ) vmin.rX() = vct.X();
if ( vct.Y() < vmin.Y() ) vmin.rY() = vct.Y();
}
}
vct = (vmax - vmin)/1.5;
vmax += vct;
vmin -= vct;
mBox = HRect( vmin.X(), vmin.Y(), vmax.X(), vmax.Y() );
// creating starting triangulation containing two cells and four points
THROW_ALLOC( pnd1 = MGNEW HGrdPnt( vmin) );
THROW_ALLOC( pnd2 = MGNEW HGrdPnt( vmax.X(), vmin.Y()) );
THROW_ALLOC( pnd3 = MGNEW HGrdPnt( vmax) );
THROW_ALLOC( pnd4 = MGNEW HGrdPnt( vmin.X(), vmax.Y()) );
THROW_ALLOC( ptri1 = MGNEW HGrdTri() );
THROW_ALLOC( ptri2 = MGNEW HGrdTri() );
mind1 = ind1 = InsertPoint( pnd1);
mind2 = ind2 = InsertPoint( pnd2);
mind3 = ind3 = InsertPoint( pnd3);
mind4 = ind4 = InsertPoint( pnd4);
itri1 = InsertCell( ptri1);
itri2 = InsertCell( ptri2);
ptri1->rNode(0) = ind1;
ptri1->rNode(1) = ind2;
ptri1->rNode(2) = ind3;
ptri2->rNode(0) = ind3;
ptri2->rNode(1) = ind4;
ptri2->rNode(2) = ind1;
ptri1->rCell(2) = itri2;
ptri2->rCell(2) = itri1;
ptri1->SetCircCenter();
ptri2->SetCircCenter();
// inserting frontal points into mesh
IterFro itrfro;
IterFSeg itrsg;
map<HGrdPnt*,int> mapNod;
map<HGrdPnt*,int>::iterator imap;
for ( itrfro = mcolFro.begin(); itrfro != mcolFro.end(); itrfro++)
{
for ( itrsg = (*itrfro).begin(); itrsg != (*itrfro).end(); itrsg++)
{
itr = (*itrsg)->rPntRt();
if ( ( imap = mapNod.find( *itr) ) == mapNod.end() )
{
InsertPointIntoMesh( itr);
mapNod.insert( map<HGrdPnt*,int>::value_type( *itr, 0) );
}
}
}
#ifdef _DEBUG
FILE *ftmp = fopen( "initial.plt", "wt");
ExportTECTmp( ftmp);
fclose( ftmp);
#endif // _DEBUG
}
bool HGrid::IsOutside( const Vect2D& vct)
{
IterFro itrfro;
IterFSeg itrsg;
Vect2D v1, v2;
double x;
//// winding algorithm
// MGFloat alf;
// for ( itrfro = mcolFro.begin(); itrfro != mcolFro.end(); itrfro++)
// {
// alf += (*itrfro).Angle( vct);
// }
// if ( fabs(alf) < M_PI )
// return true;
// else
// return false;
// ray casting algorithm
MGInt cross = 0;
for ( itrfro = mcolFro.begin(); itrfro != mcolFro.end(); itrfro++)
for ( itrsg = (*itrfro).begin(); itrsg != (*itrfro).end(); itrsg++)
{
v1 = *(*(*itrsg)->PntLf());
v2 = *(*(*itrsg)->PntRt());
if ( ( v1.Y() > vct.Y() && v2.Y() <= vct.Y() ) ||
( v2.Y() > vct.Y() && v1.Y() <= vct.Y() ) )
{
// x = ( v1.X()*v2.Y() - v1.Y()*v2.X() ) / ( v2.Y() - v1.Y() );
x = (v2.X() - v1.X())*(vct.Y() - v1.Y())/(v2.Y() - v1.Y())
+ v1.X();
if ( x > vct.X() )
++cross;
}
}
if ( (cross % 2) == 1 )
return false;
else
return true;
}
void HGrid::FlagOuterTris()
{
IterFro itrfro;
IterFSeg itrsg;
IterGCell itr, itrnb, itrcl;;
Vect2D vout, vcnt, vc1, vc2;
CollGCell colCell;
// // flaging all triangles lying outside domain using N^2 algo
// for ( itr = mcolCell.begin(); itr != mcolCell.end(); itr++)
// {
// if( IsOutside( (*itr)->Center() ) )
// (*itr)->rIsOutside() = true;
// else
// (*itr)->rIsOutside() = false;
// }
Vect2D v1, v2, vct;
// MGInt cross = 0;
HGrdTri *ptri;
MGFloat x, y1, y2;
multimap<MGFloat, HGrdTri*> mapCell;
multimap<MGFloat, HGrdTri*>::iterator imap, ifirst, ilast;
for ( itr = mcolCell.begin(); itr != mcolCell.end(); itr++)
{
vct = (*itr)->Center();
(*itr)->rCross() = 0;
mapCell.insert( multimap<MGFloat, HGrdTri*>::value_type( vct.Y(),
(*itr) ) );
}
for ( itrfro = mcolFro.begin(); itrfro != mcolFro.end(); itrfro++)
for ( itrsg = (*itrfro).begin(); itrsg != (*itrfro).end(); itrsg++)
{
v1 = *(*(*itrsg)->PntLf());
v2 = *(*(*itrsg)->PntRt());
if ( v1.Y() > v2.Y() )
{
y1 = v2.Y();
y2 = v1.Y();
}
else
{
y1 = v1.Y();
y2 = v2.Y();
}
ifirst = mapCell.lower_bound( y1 );
ilast = mapCell.upper_bound( y2 );
for ( imap = ifirst; imap != ilast; ++imap)
{
ptri = (*imap).second;
vct = ptri->Center();
if ( ( v1.Y() > vct.Y() && v2.Y() <= vct.Y() ) ||
( v2.Y() > vct.Y() && v1.Y() <= vct.Y() ) )
{
x = (v2.X() - v1.X())*(vct.Y() - v1.Y())/(v2.Y() - v1.Y())
+ v1.X();
if ( x > vct.X() )
++(ptri->rCross());
}
}
}
for ( itr = mcolCell.begin(); itr != mcolCell.end(); itr++)
{
if ( ((*itr)->rCross() % 2) == 1 )
(*itr)->rIsOutside() = false;
else
(*itr)->rIsOutside() = true;
}
}
void HGrid::RemoveOuterTris()
{
IterGCell itr, itr2;
HGrdTri *ptri;
// itr2 = NULL;
itr2 = (IterGCell)NULL;
for ( itr = mcolCell.begin(); itr != mcolCell.end(); itr++)
{
// if ( itr2 != NULL)
if ( itr2 != (IterGCell)NULL){
ptri = *itr2;
(*itr2)->InvalidateNeighb();
mcolCell.erase( itr2);
delete ptri;
itr2 = (IterGCell)NULL;
}
if ( (*itr)->IsOutside() )
itr2 = itr;
}
// if ( itr2 != NULL)
if ( itr2 != (IterGCell)NULL){
ptri = *itr2;
(*itr2)->InvalidateNeighb();
mcolCell.erase( itr2);
delete ptri;
itr2 = (IterGCell)NULL;
}
if ( *mind1) delete *mind1;
if ( *mind2) delete *mind2;
if ( *mind3) delete *mind3;
if ( *mind4) delete *mind4;
mcolPnt.erase( mind1);
mcolPnt.erase( mind2);
mcolPnt.erase( mind3);
mcolPnt.erase( mind4);
mind1 = (IterGPnt)NULL;
mind2 = (IterGPnt)NULL;
mind3 = (IterGPnt)NULL;
mind4 = (IterGPnt)NULL;
}
bool HGrid::CheckSwapTriangles( HGrdTri *ptri1, HGrdTri *ptri2)
{
HGrdTri tri1, tri2;
tri1 = *ptri1;
tri2 = *ptri2;
SwapTriangles( &tri1, &tri2, false);
if ( !tri1.Check() || !tri2.Check() )
return false;
if ( tri1.Area() < 0 || tri2.Area() < 0 )
return false;
return true;
}
/*
switch two triangles
*/
void HGrid::SwapTriangles( HGrdTri *ptri1, HGrdTri *ptri2, bool bgo)
{
MGInt ifc1, ifc2;
IterGPnt ip1, ip2, ip3, ip4;
IterGCell ic1, ic2, ic3, ic4;
IterGCell itri1, itri2;
// TRACE( "--- swapping !!!");
if ( ptri2->Node(1) == ptri1->Node(0) && ptri2->Node(0) == ptri1->Node(1) )
{
ip1 = ptri2->Node(1);
ip2 = ptri2->Node(2);
ip3 = ptri2->Node(0);
ip4 = ptri1->Node(2);
ifc1 = 0;
ifc2 = 0;
ic1 = ptri2->Cell(1);
ic2 = ptri2->Cell(2);
ic3 = ptri1->Cell(1);
ic4 = ptri1->Cell(2);
itri1 = ptri2->Cell(0);
itri2 = ptri1->Cell(0);
}
else
if ( ptri2->Node(0) == ptri1->Node(0) && ptri2->Node(2) == ptri1->Node(1) )
{
ip1 = ptri2->Node(0);
ip2 = ptri2->Node(1);
ip3 = ptri2->Node(2);
ip4 = ptri1->Node(2);
ifc1 = 0;
ifc2 = 2;
ic1 = ptri2->Cell(0);
ic2 = ptri2->Cell(1);
ic3 = ptri1->Cell(1);
ic4 = ptri1->Cell(2);
itri1 = ptri2->Cell(2);
itri2 = ptri1->Cell(0);
}
else
if ( ptri2->Node(2) == ptri1->Node(0) && ptri2->Node(1) == ptri1->Node(1) )
{
ip1 = ptri2->Node(2);
ip2 = ptri2->Node(0);
ip3 = ptri2->Node(1);
ip4 = ptri1->Node(2);
ifc1 = 0;
ifc2 = 1;
ic1 = ptri2->Cell(2);
ic2 = ptri2->Cell(0);
ic3 = ptri1->Cell(1);
ic4 = ptri1->Cell(2);
itri1 = ptri2->Cell(1);
itri2 = ptri1->Cell(0);
}
else
if ( ptri2->Node(1) == ptri1->Node(2) && ptri2->Node(0) == ptri1->Node(0) )
{
ip1 = ptri2->Node(1);
ip2 = ptri2->Node(2);
ip3 = ptri2->Node(0);
ip4 = ptri1->Node(1);
ifc1 = 2;
ifc2 = 0;
ic1 = ptri2->Cell(1);
ic2 = ptri2->Cell(2);
ic3 = ptri1->Cell(0);
ic4 = ptri1->Cell(1);
itri1 = ptri2->Cell(0);
itri2 = ptri1->Cell(2);
}
else
if ( ptri2->Node(0) == ptri1->Node(2) && ptri2->Node(2) == ptri1->Node(0) )
{
ip1 = ptri2->Node(0);
ip2 = ptri2->Node(1);
ip3 = ptri2->Node(2);
ip4 = ptri1->Node(1);
ifc1 = 2;
ifc2 = 2;
ic1 = ptri2->Cell(0);
ic2 = ptri2->Cell(1);
ic3 = ptri1->Cell(0);
ic4 = ptri1->Cell(1);
itri1 = ptri2->Cell(2);
itri2 = ptri1->Cell(2);
}
else
if ( ptri2->Node(2) == ptri1->Node(2) && ptri2->Node(1) == ptri1->Node(0) )
{
ip1 = ptri2->Node(2);
ip2 = ptri2->Node(0);
ip3 = ptri2->Node(1);
ip4 = ptri1->Node(1);
ifc1 = 2;
ifc2 = 1;
ic1 = ptri2->Cell(2);
ic2 = ptri2->Cell(0);
ic3 = ptri1->Cell(0);
ic4 = ptri1->Cell(1);
itri1 = ptri2->Cell(1);
itri2 = ptri1->Cell(2);
}
else
if ( ptri2->Node(1) == ptri1->Node(1) && ptri2->Node(0) == ptri1->Node(2) )
{
ip1 = ptri2->Node(1);
ip2 = ptri2->Node(2);
ip3 = ptri2->Node(0);
ip4 = ptri1->Node(0);
ifc1 = 1;
ifc2 = 0;
ic1 = ptri2->Cell(1);
ic2 = ptri2->Cell(2);
ic3 = ptri1->Cell(2);
ic4 = ptri1->Cell(0);
itri1 = ptri2->Cell(0);
itri2 = ptri1->Cell(1);
}
else
if ( ptri2->Node(0) == ptri1->Node(1) && ptri2->Node(2) == ptri1->Node(2) )
{
ip1 = ptri2->Node(0);
ip2 = ptri2->Node(1);
ip3 = ptri2->Node(2);
ip4 = ptri1->Node(0);
ifc1 = 1;
ifc2 = 2;
ic1 = ptri2->Cell(0);
ic2 = ptri2->Cell(1);
ic3 = ptri1->Cell(2);
ic4 = ptri1->Cell(0);
itri1 = ptri2->Cell(2);
itri2 = ptri1->Cell(1);
}
else
if ( ptri2->Node(2) == ptri1->Node(1) && ptri2->Node(1) == ptri1->Node(2) )
{
ip1 = ptri2->Node(2);
ip2 = ptri2->Node(0);
ip3 = ptri2->Node(1);
ip4 = ptri1->Node(0);
ifc1 = 1;
ifc2 = 1;
ic1 = ptri2->Cell(2);
ic2 = ptri2->Cell(0);
ic3 = ptri1->Cell(2);
ic4 = ptri1->Cell(0);
itri1 = ptri2->Cell(1);
itri2 = ptri1->Cell(1);
}
ASSERT( itri1 != (IterGCell)NULL && itri2 != (IterGCell)NULL);
ptri1->rNode(0) = ip2;
ptri1->rNode(1) = ip4;
ptri1->rNode(2) = ip1;
ptri1->rCell(0) = itri2;
ptri1->rCell(1) = ic4;
ptri1->rCell(2) = ic1;
ptri2->rNode(0) = ip4;
ptri2->rNode(1) = ip2;
ptri2->rNode(2) = ip3;
ptri2->rCell(0) = itri1;
ptri2->rCell(1) = ic2;
ptri2->rCell(2) = ic3;
if ( bgo)
{
if ( ic1 != (IterGCell)NULL ){
if ( (*ic1)->Cell(0) == itri2)
(*ic1)->rCell(0) = itri1;
else if ( (*ic1)->Cell(1) == itri2)
(*ic1)->rCell(1) = itri1;
else if ( (*ic1)->Cell(2) == itri2)
(*ic1)->rCell(2) = itri1;
else
ASSERT(0);
}
if ( ic3 != (IterGCell)NULL){
if ( (*ic3)->Cell(0) == itri1)
(*ic3)->rCell(0) = itri2;
else if ( (*ic3)->Cell(1) == itri1)
(*ic3)->rCell(1) = itri2;
else if ( (*ic3)->Cell(2) == itri1)
(*ic3)->rCell(2) = itri2;
else
ASSERT(0);
}
}
}
/*
checking bounding
*/
void HGrid::CheckBoundIntegr()
{
// char sbuf[256];
IterFro itrfro;
IterFSeg itrsg;
Vect2D v1, v2, v3, v4;
// CollGCell colCell;
CollGCell colPath;
CollFSeg colSeg;
IterFSeg iseg;
IterGCell itr, itrnb, itrcl;
Vect2D vcnt;
bool bReady, bFound;
// MGInt k, i=0;
MGInt k;
list<IterGCell> lstCell;
list<IterGCell>::iterator itrtmp;
multimap< HGrdPnt*, IterGCell > mapNod;
pair< multimap< HGrdPnt*, IterGCell >::iterator,
multimap< HGrdPnt*, IterGCell >::iterator> range[2];
// no of points per froseg
multimap< HGrdPnt*, IterGCell >::iterator itrmap1, itrmap2;
// getting number of front segments
int no = 0;
for ( itrfro = mcolFro.begin(); itrfro != mcolFro.end(); itrfro++)
for ( itrsg = (*itrfro).begin(); itrsg != (*itrfro).end(); itrsg++)
++no;
for ( itr = mcolCell.begin(); itr != mcolCell.end(); itr++)
for ( k=0; k<NUM_TRI; ++k)
mapNod.insert( multimap<HGrdPnt*,
IterGCell>::value_type(*(*itr)->Node(k), itr) );
int iii=0;
int nrec = 0;
for ( itrfro = mcolFro.begin(); itrfro != mcolFro.end(); itrfro++)
for ( itrsg = (*itrfro).begin(); itrsg != (*itrfro).end(); itrsg++)
{
++iii;
//if ( iii - 1000*(iii/1000) == 0)
// printf( "triang. iter = %d / %d nrec = %d\n", iii, no, nrec);
range[0] = mapNod.equal_range( *(*itrsg)->PntLf() );
range[1] = mapNod.equal_range( *(*itrsg)->PntRt() );
bReady = false;
for ( itrmap1=range[0].first; itrmap1!=range[0].second; itrmap1++)
{
itrcl = (*itrmap1).second;
lstCell.insert( lstCell.begin(), itrcl );
for ( itrmap2=range[1].first; itrmap2!=range[1].second;
itrmap2++)
{
if ( *itrcl == *(*itrmap2).second )
{
bReady = true;
goto out_of_loops;
}
}
}
out_of_loops:
// the segment is missing - must be recovered
if ( ! bReady)
{
++nrec;
//printf( "triang. iter = %d / %d nrec = %d\n", iii, no, nrec);
v1 = *(*((*itrsg)->PntLf()));
v2 = *(*((*itrsg)->PntRt()));
// TRACE( "\n" );
// sprintf( sbuf, "seg (%lg, %lg) (%lg, %lg) - lstCell.size = %d",
// v1.X(), v1.Y(), v2.X(), v2.Y(), lstCell.size() );
// TRACE( sbuf);
bFound = false;
for ( itrtmp = lstCell.begin(); itrtmp != lstCell.end();
++itrtmp)
{
itr = *itrtmp;
if(( itrnb = (*itr)->NextCell( *itrsg,
(IterGCell)NULL) ) != (IterGCell)NULL)
{
bFound = true;
break;
}
}
if ( bFound)
{
IterGCell itr1, itr2, itro1=(IterGCell)NULL,
itro2=(IterGCell)NULL;
stack<IterGCell> stackCell;
// CheckGrid();
itr1 = itr;
itr2 = itrnb;
// TRACE2( "v1 = %lg %lg", v1.X(), v1.Y() );
// TRACE2( "v2 = %lg %lg", v2.X(), v2.Y() );
int niter = 0;
do
{
++niter;
// TRACE( "--- loop start");
// TRACE2( "itrcl = %d / %d", itr1, *itr1);
// (*itr1)->DumpTri();
// TRACE2( "itrcl = %d / %d", itr2, *itr2);
// (*itr2)->DumpTri();
// check if swap is possible if not then try with another triangles
while ( /*! (*itr2)->IsVisible( itr1, v1) ||*/
! CheckSwapTriangles( *itr1, *itr2 )
|| ( itr1 == itro1 && itr2 == itro2 ) )
// avoid swaping the same triangles again
{
stackCell.push( itr1);
itr = itr2;
itr2 = (*itr)->NextCell( *itrsg, itr1);
itr1 = itr;
ASSERT( itr2 != (IterGCell)NULL);
}
itro1 = itr1;
itro2 = itr2;
// pre swapping - remove itr1 and itr2 from map
for ( k=0; k< NUM_TRI; ++k)
{
range[0] = mapNod.equal_range( *(*itr1)->Node(k) );
for ( itrmap1=range[0].first;
itrmap1!=range[0].second; itrmap1++)
{
if ( (*itrmap1).second == itr1 )
{
mapNod.erase( itrmap1);
break;
}
}
range[0] = mapNod.equal_range( *(*itr2)->Node(k) );
for ( itrmap1=range[0].first;
itrmap1!=range[0].second; itrmap1++)
{
if ( (*itrmap1).second == itr2 )
{
mapNod.erase( itrmap1);
break;
}
}
}
if ( ! CheckSwapTriangles( *itr1, *itr2 ) )
THROW_INTERNAL( "Recovery: Swap not possible !!!");
SwapTriangles( *itr1, *itr2 );
// post swapping - insert modified itr1 and itr2 into map
for ( k=0; k< NUM_TRI; ++k)
{
mapNod.insert( multimap<HGrdPnt*,
IterGCell>::value_type( *(*itr1)->Node(k), itr1) );
mapNod.insert( multimap<HGrdPnt*,
IterGCell>::value_type( *(*itr2)->Node(k), itr2) );
}
if ( stackCell.empty() )
{
itrcl = (IterGCell)NULL;
itrnb = (IterGCell)NULL;
if((itr = (*itr1)->NextCell( (*itrsg),
(IterGCell)NULL )) != (IterGCell)NULL)
{
itrcl = itr1;
itrnb = itr;
}
if ( (itr = (*itr2)->NextCell( (*itrsg),
(IterGCell)NULL )) != (IterGCell)NULL)
{
itrcl = itr2;
itrnb = itr;
}
itr1 = itrcl;
itr2 = itrnb;
}
else{
itr1 = stackCell.top();
stackCell.pop();
if ( stackCell.empty() )
itr2 = (*itr1)->NextCell(*itrsg, (IterGCell)NULL);
else
itr2 = (*itr1)->NextCell(*itrsg,
(IterGCell)stackCell.top());
}
}
while ( itr1 != (IterGCell)NULL && itr2 != (IterGCell)NULL);
(*itrsg)->mbtmp = true;
}
else
{
char sbuf[1024];
sprintf( sbuf, "recovery problem with seg(%lg, %lg)(%lg, %lg)",
v1.X(), v1.Y(), v2.X(), v2.Y() );
TM_TRACE( sbuf);
TM_TRACE1( "recovwry lstCell.size = %d", lstCell.size() );
TM_TRACE1( "%d edges already recovered", nrec);
FILE *ff = fopen( "lstcell.plt", "wt");
for ( itrtmp = lstCell.begin(); itrtmp != lstCell.end();
++itrtmp)
{
(*(*itrtmp))->DumpTEC( ff);
}
fclose( ff);
printf( "%s\n", sbuf);
printf( "recovery lstCell.size = %d\n", (int)lstCell.size() );
(*itrsg)->mbtmp = true;
FILE *f = fopen( "recovery.plt", "wt");
ExportTECTmp( f);
fclose( f);
THROW_INTERNAL( "Recovery problem !!!");
}
}
lstCell.erase( lstCell.begin(), lstCell.end() );
}
// printf( "%d edges recovered\n", nrec);
}
void HGrid::Generate()
{
clock_t start, tstart, finish;
double duration;
try
{
tstart = clock();
start = clock();
InitTriangles();
finish = clock();
duration = (double)(finish - start) / CLOCKS_PER_SEC;
// printf( "InitTriangles() - %2.1f seconds\n\n", duration );
//FILE *f = fopen( "ini.plt", "wt");
//ExportTECTmp( f);
//fclose( f);
TM_TRACE( "CheckBoundIntegr()");
// printf( "CheckBoundIntegr()\n");
start = clock();
CheckBoundIntegr();
finish = clock();
duration = (double)(finish - start) / CLOCKS_PER_SEC;
// printf( "CheckBoundIntegr() - %2.1f seconds\n\n", duration );
TM_TRACE( "FlagOuterTris()");
// printf( "FlagOuterTris()\n");
FlagOuterTris();
TM_TRACE( "RemoveOuterTris()");
// printf( "RemoveOuterTris()\n");
RemoveOuterTris();
finish = clock();
duration = (double)(finish - tstart) / CLOCKS_PER_SEC;
// printf( "Generation total - %2.1f seconds\n\n", duration );
// FILE *f = fopen( "param.plt", "wt");
// ExportTECTmp( f);
// fclose( f);
}
catch ( Except *pe)
{
ASSERT( pe);
TM_TRACE_EXCEPTION( *pe);
TM_TRACE_TO_STDERR( *pe);
delete pe;
}
}
void HGrid::ExportTECTmp( FILE *f)
{
IterGPnt pntitr;
Vect2D vct;
IterGCell cellitr, itrcl;
MGInt id1, id2, id3, id4;
MGInt ltri, ltmp;
map<void*,MGInt,less<void*> > tmpMap;
TM_TRACE( "ExportTEC");
fprintf( f, "TITLE = \"surface\"\n");
fprintf( f, "VARIABLES = \"X\", \"Y\"\n");
fprintf( f, "ZONE T=\"TRIANGLES\", ");
fprintf( f, "N=%2ld, ", (long int) mcolPnt.size() );
fprintf( f, "E=%2d, F=FEPOINT, ET=QUADRILATERAL C=BLACK\n ",
ltri = (MGInt)mcolCell.size() );
ltmp = 0;
for ( pntitr = mcolPnt.begin(); pntitr != mcolPnt.end(); pntitr++)
{
ltmp++;
vct = *(*pntitr);
fprintf( f, "%20.10lg %20.10lg\n", vct.X(), vct.Y() );
tmpMap.insert( map<void*,MGInt,
less<void*> >::value_type((void*)(*pntitr), ltmp ));
}
TM_TRACE( "after Pnt");
ltri = 0;
for ( cellitr = mcolCell.begin(); cellitr != mcolCell.end(); cellitr++)
{
ltri++;
pntitr = (*cellitr)->Node(0);
id1 = tmpMap[ (*pntitr)];
pntitr = (*cellitr)->Node(1);
id2 = tmpMap[ (*pntitr)];
pntitr = (*cellitr)->Node(2);
id4 = id3 = tmpMap[ (*pntitr)];
fprintf( f, "%9ld %9ld %9ld %9ld\n", (long int)id1, (long int)id2,
(long int)id3, (long int)id4 );
}
TM_TRACE( "after Cells");
}
void HGrid::CheckGrid()
{
// char sbuf[256];
bool bFound;
IterGCell itr, itrnb;
// TRACE("CheckGrid()\n");
for ( itr = mcolCell.begin(); itr != mcolCell.end(); ++itr)
{
// sprintf( sbuf, "cel = %d | %d %d %d", itr, (*itr)->Cell(0),
//(*itr)->Cell(1), (*itr)->Cell(2) );
// TRACE( sbuf);
for ( int i=0; i<NUM_TRI; ++i)
{
bFound = true;
itrnb = (*itr)->Cell(i);
if ( itrnb != (IterGCell)NULL){
ASSERT( *itrnb );
bFound = false;
for ( int k=0; k<NUM_TRI; ++k)
{
if ( (*itrnb)->Cell(k) == itr )
bFound = true;
}
}
if ( ! bFound)
{
THROW_INTERNAL( "Cells pointers are not consistent !");
}
}
}
}
void HGrid::WriteFrontTEC( const char name[])
{
}
INIT_TRACE;