Files
SaraP 739088af9f Vroni 7.8 :
- aggiornamento versione.
2025-01-29 16:24:30 +01:00

1501 lines
51 KiB
C++

/*****************************************************************************/
/* */
/* Copyright (C) 2001-2025 M. Held */
/* */
/* This code is not in the public domain. All rights reserved! Please make */
/* sure to read the full copyright statement contained in "README.txt" or in */
/* the "main" file of this code, such as "main.cc". */
/* */
/*****************************************************************************/
/* */
/* Written by: Martin Held */
/* */
/* E-Mail: held@cs.sbg.ac.at */
/* Fax Mail: (+43 662) 8044-611 */
/* Voice Mail: (+43 662) 8044-6304 */
/* Snail Mail: Martin Held */
/* FB Informatik */
/* Universitaet Salzburg */
/* A-5020 Salzburg, Austria */
/* */
/*****************************************************************************/
/* */
/* get my header files */
/* */
#include "vroni_object.h"
void vroniObject::FindMostViolatedRecursiveSeg(int e, /* current VD edge */
int k0, /* start node of */
/* recursive scan */
int i1, /* pnt that coincides */
/* with k0 */
int j, /* segment to be */
/* inserted into VD */
int k, /* current node */
int *n, /* closest node found */
/* by scan */
double *dist) /* distance of */
/* node n */
{
coord p, q;
double dist2, rad, a, b, c, lgth;
int e1, e2, k1, n2;
#ifdef TRACE
vr_bool trace_mvns = true;
#endif
assert(InEdgesList(e));
assert(InPntsList(i1));
assert(InNodesList(k0));
assert(InNodesList(k));
assert(InSegsList(j));
assert(!(IsLftSite(e, i1, PNT) && IsRgtSite(e, i1, PNT)));
assert(GetNodeSite(k0) == i1);
k1 = GetOtherNode(e, k);
assert(InNodesList(k1));
#ifdef TRACE
if (trace_mvns) {
printf("FMVRS: e = %d, i1 = %d, j = %d, k = %d, k0 = %d, k1 = %d\n",
e, i1, j, k, k0, k1);
printf(" node_site(k1) = %d, deg-2(k1) = %d\n",
GetNodeSite(k1), IsDeg2Node(k1));
}
#endif
if (k1 == k0) {
/* */
/* we have returned to the start! */
/* */
*dist = DBL_MAX;
*n = NIL;
return;
}
if (GetNodeSite(k1) == i1) {
e1 = GetCCWEdge(e, k1);
e2 = GetCWEdge(e, k1);
FindMostViolatedRecursiveSeg(e1, k0, i1, j, k1, n, dist);
if (e1 != e2) {
FindMostViolatedRecursiveSeg(e2, k0, i1, j, k1, &n2, &dist2);
if (dist2 < *dist) {
*n = n2;
*dist = dist2;
}
}
}
else {
GetNodeData(k1, &q, &rad);
GetSegEqnData(j, &a, &b, &c);
lgth = GetSegLgth(j);
p = GetSegStartCoord(j);
*dist = AbsPntSegDist(p, q, a, b, c, lgth, TINY) - rad;
*n = k1;
}
return;
}
/* */
/* find the Voronoi node on the Voronoi boundary of the point pnts[i1] */
/* whose Voronoi disk is violated the most by the insertion of segs[j]. */
/* note that pnts[i1] and pnts[i2] are the endpoints of segs[j]. if */
/* the Voronoi cells of pnts[i1] and pnts[i2] share nodes then we take */
/* one of those nodes, and set node_shared = true. */
/* */
int vroniObject::FindMostViolatedNodeSeg(int i1, /* start point of seg */
int i2, /* end point of seg */
int j, /* segment to be inserted */
vr_bool *node_shared,
double *diff)
{
int e, e1, e0, k, k0, k_min = NIL, n, n1;
coord p, q;
double dist, dist1, dist_min, rad;
double a, b, c, lgth;
vr_bool shared0, shared, shared1;
#ifdef TRACE
vr_bool trace_mvns = true;
#endif
assert(InPntsList(i1));
assert(InPntsList(i2));
assert(InSegsList(j));
assert(IsSegStartPnt(j, i1) || IsSegEndPnt(j, i1));
assert(IsSegStartPnt(j, i2) || IsSegEndPnt(j, i2));
/* */
/* so far, no segment that is incident at this point has been inserted.*/
/* we'll scan the Voronoi region of the point in order to find the */
/* node whose Voronoi disk is most violated by the insertion of the */
/* segment segs[j]. */
/* */
e = GetVDPtr(i1, PNT);
assert(InEdgesList(e));
assert(IsLftSite(e, i1, PNT) || IsRgtSite(e, i1, PNT));
GetSegEqnData(j, &a, &b, &c);
lgth = GetSegLgth(j);
assert(!eq(lgth, ZERO));
p = GetSegStartCoord(j);
if (IsRgtSite(e, i1, PNT)) k = GetEndNode(e);
else k = GetStartNode(e);
assert(InNodesList(k));
e0 = e;
dist_min = LARGE;
dist = LARGE;
shared0 = false;
shared = IsLftRgtSite(e, i1, PNT) && IsLftRgtSite(e, i2, PNT);
#ifdef TRACE
if (trace_mvns)
printf("FMVNS: i1 = %d, i2 = %d, j = %d, k = %d\n", i1, i2, j, k);
#endif
do {
e1 = GetCCWEdge(e, k);
shared1 = IsLftRgtSite(e1, i1, PNT) && IsLftRgtSite(e1, i2, PNT);
shared = shared || shared1;
#ifdef TRACE
if (trace_mvns)
PrintNodeData(k, "checking");
#endif
if (GetNodeSite(k) == NIL) {
/* */
/* check whether q is in the cone of influence of segs[j]. */
/* */
GetNodeData(k, &q, &rad);
dist = AbsPntSegDist(p, q, a, b, c, lgth, TINY) - rad;
if (shared) {
/* */
/* this node belongs to the VD cells of pnts i1 and i2 */
/* */
if ((dist < dist_min) || (!shared0)) {
#ifdef TRACE
if (trace_mvns){
printf("node %d accepted (shared)\n", k);
printf("old distance: %f, new distance: %f\n",
dist_min, dist);
PrintNodeData(k, "FindMostViolatedSeg");
}
#endif
dist_min = dist;
k_min = k;
shared0 = true;
}
}
else if (dist < dist_min) {
/* */
/* so far we have not found a node that is shared by both cells */
/* */
#ifdef TRACE
if (trace_mvns){
printf("node %d accepted\n", k);
printf("old distance: %f, new distance: %f\n",
dist_min, dist);
PrintNodeData(k, "FindMostViolatedSeg");
}
#endif
dist_min = dist;
k_min = k;
}
}
e = e1;
k = GetOtherNode(e, k);
shared = shared1;
} while (e != e0);
*node_shared = shared0;
*diff = dist_min;
if (((k_min == NIL) || (dist_min >= 0.0)) && HasIncidentSite(i1)) {
/* */
/* at least one segment is already incident at this point. */
/* */
*node_shared = false;
k = GetPntNode(i1);
assert(InNodesList(k));
assert(GetNodeSite(k) == i1);
assert(IsDeg2Node(k));
e = GetIncidentEdge(k);
assert(InEdgesList(e));
assert((k == GetStartNode(e)) || (k == GetEndNode(e)));
e1 = GetCCWEdge(e, k);
assert(GetCWEdge(e, k) == e1);
assert(!(IsLftSite(e, i1, PNT) && IsRgtSite(e, i1, PNT)));
k0 = k;
#ifdef TRACE
if (trace_mvns)
printf("1st recursive call of FMVRS: e = %d, k0 = %d\n",
e, k0);
#endif
FindMostViolatedRecursiveSeg(e, k0, i1, j, k, &n, &dist);
#ifdef TRACE
if (trace_mvns)
printf("2nd recursive call of FMVRS: e1 = %d, k0 = %d\n",
e1, k0);
#endif
FindMostViolatedRecursiveSeg(e1, k0, i1, j, k, &n1, &dist1);
if (dist < dist1) {
k_min = n;
*diff = dist;
}
else {
k_min = n1;
*diff = dist1;
}
}
return k_min;
}
/* */
/* this routine first checks whether all VD nodes on the boundary of the */
/* Voronoi cell of site i of type t have been marked for deletion due to */
/* the insertion of the line segment i0. (as a matter of fact, t == PNT !) */
/* it then constructs a point on the boundary of the Voronoi cell of i */
/* which is guaranteed to be closer to pnt i than to seg i0. */
/* */
vr_bool vroniObject::PreserveVoronoiCellSeg(int i, t_site t, int i0)
{
int e, n, e0, k, k0, s, s0;
double dist, a, b, c, r0_2, r_2, r2, ap, bp, cp, d, d0, lgth;
coord p, q, q0, v, w, u;
#ifdef TRACE
if (debug_flag_VD) {
#ifdef GRAPHICS
if (graphics) AddToCurBuffer(i, t, AlertColor);
#endif
printf("in PreserveVoronoiCellSeg for site %d of type %d and line %d\n",
i, t, i0);
printf("start - (%f, %f)\n", pnts[segs[i0].i1].p.x,
pnts[segs[i0].i1].p.y);
printf("end - (%f, %f)\n", pnts[segs[i0].i2].p.x,
pnts[segs[i0].i2].p.y);
printf("pnt - (%f, %f)\n", pnts[i].p.x, pnts[i].p.y);
}
#endif
assert((t == PNT) && InPntsList(i));
/* */
/* we'll find a bisector on the boundary of the Voronoi cell of site i */
/* for which we can guarantee that some part of it will survive the */
/* insertion of the line segment segs[i0]. we will insert a dummy node */
/* on this bisector in order to prevent its removal. after the insertion */
/* of segs[i0] we will remove the dummy node. */
/* */
/* scan the Voronoi cell in CCW order and check whether all nodes */
/* really are to be deleted. */
/* */
e = GetVDPtr(i, t);
assert(InEdgesList(e));
assert(IsLftSite(e, i, t) || IsRgtSite(e, i, t));
if (IsRgtSite(e, i, t)) k = GetEndNode(e);
else k = GetStartNode(e);
e0 = e;
do {
if (!IsNodeVisited(k)) {
/* */
/* hm... this Voronoi cell has undeleted nodes! */
/* */
#ifdef TRACE
if (debug_flag_VD) {
printf("the node %d of this Voronoi cell is undeleted\n", k);
}
#endif
u = GetNodeCoord(k);
return true;
}
e = GetCCWEdge(e, k);
k = GetOtherNode(e, k);
} while (e != e0);
/* */
/* indeed, all Voronoi nodes of this cell are to be deleted. */
/* */
if (IsSegStartPnt(i0, i) || IsSegEndPnt(i0, i)) {
/* */
/* check whether there exists a node with radius 0.0. */
/* */
e = GetVDPtr(i, t);
if (IsRgtSite(e, i, t)) k = GetEndNode(e);
else k = GetStartNode(e);
e0 = e;
do {
if (i == GetNodeSite(k)) {
GetNodeData(k, &q, &r2);
assert(r2 == 0.0);
InsertSiteNode(e, q, n, i);
MarkNodeChecked(n);
#ifdef TRACE
if (debug_flag_VD) {
printf("dummy node with radius 0 inserted\n");
#ifdef GRAPHICS
if (graphics) AddToCurBuffer(n, VDN, AlertColor);
#endif
}
#endif
return true;
}
e = GetCCWEdge(e, k);
k = GetOtherNode(e, k);
} while (e != e0);
return false;
}
/* */
/* compute the coefficients of the equation of the line through p and */
/* the direction vector v of a ray that starts at p, points away from */
/* segs[i0], and is perpendicular to segs[i0]. */
/* */
p = GetPntCoords(i);
GetSegEqnData(i0, &a, &b, &c);
dist = PntLineDist(a, b, c, p);
if (eq(dist, zero)) {
lgth = GetSegLgth(i0);
u = GetSegStartCoord(i0);
if (IsInSegConeZero(u, p, a, b, lgth, zero) == 0) {
SetInvalidSites(i0, SEG, i, PNT, zero);
VD_Dbg_Warning("PreserveVoronoiCellSeg() - point lies on line!");
if (IsInvalidData(false)) {
restart = true;
return false;
}
}
}
if (dist > 0.0) {
ap = b;
bp = -a;
}
else {
ap = -b;
bp = a;
}
cp = - ap * p.x - bp * p.y;
v = MakeVec( -bp, ap);
/* */
/* scan the boundary of the VD cell of p and find a VD edge whose */
/* end points lie on different sides of the ray through p */
/* */
e = GetVDPtr(i, t);
if (IsRgtSite(e, i, t)) {
k = GetEndNode(e);
k0 = GetStartNode(e);
}
else {
k = GetStartNode(e);
k0 = GetEndNode(e);
}
GetNodeData(k0, &q0, &r0_2);
d0 = PntLineDist(ap, bp, cp, q0);
s0 = SignEps(d0, ZERO);
e0 = e;
do {
GetNodeData(k, &q, &r_2);
d = PntLineDist(ap, bp, cp, q);
s = SignEps(d, ZERO);
if ((s * s0 < 0) && gt(r_2, ZERO) && gt(r0_2, ZERO)) {
/* */
/* the nodes q0 and q lie on different sides of the line */
/* through p. */
/* */
if (IntersectRayBisector(i, v, e, &w, &r2)) {
if (IsBetweenVoronoiNodes(e, w, zero)) {
n = StoreNode(w.x, w.y, r2);
InsertDummyNode(e, n, true);
MarkNodeDummy(n);
#ifdef TRACE
if (debug_flag_VD) {
printf("dummy node inserted in PreserveVoronoiCellSeg\n");
#ifdef GRAPHICS
if (graphics) AddToCurBuffer(n, VDN, AlertColor);
#endif
}
#endif
return true;
}
}
}
s0 = s;
q0 = q;
r0_2 = r_2;
e = GetCCWEdge(e, k);
k = GetOtherNode(e, k);
} while (e != e0);
return false;
}
/* */
/* the insertion of seg i0 has caused a loop of VD nodes to get marked as */
/* deleted. all edges of the loop are stored in a stack (array) between the */
/* indices start and number. we scan the loop and insert a point on one */
/* loop edge that is guaranteed to be closer to one defining site of that */
/* loop edge than to the new seg i0. */
/* */
vr_bool vroniObject::BreakLoopSeg(int i0)
{
int start, number, n, k, j, e = 0, k0, s1, s0;
double a, b, c, lgth, d1, d0, r2, r1_2, r0_2, dist, dist1, ap, bp, cp;
int i = 0, i1;
coord u, p, q, q1, q0, v, w;
t_site t, t1;
GetLoopStackSize(number);
GetLoopStackMin(start);
if (start >= number) return true; /* false alarm: no edge within loop ! */
lgth = GetSegLgth(i0);
u = GetSegStartCoord(i0);
for (j = start; j < number; ++j) {
/* */
/* scan all VD edges of the loop */
/* */
GetLoopStackElement(j, e);
GetSegEqnData(i0, &a, &b, &c);
GetLftSiteData(e, &i, &t);
if (t == SEG) { /* we are not interested in a seg as defining site */
GetRgtSiteData(e, &i, &t);
}
else if (t == PNT) {
GetRgtSiteData(e, &i1, &t1);
if (t1 == PNT) {
/* */
/* two pnts define the current loop edge. we pick the pnt that */
/* is further from seg i0. */
/* */
q = GetPntCoords(i);
dist = AbsPntSegDist(u, q, a, b, c, lgth, TINY);
q = GetPntCoords(i1);
dist1 = AbsPntSegDist(u, q, a, b, c, lgth, TINY);
if (dist1 < dist) i = i1;
}
}
if (t == PNT) {
/* */
/* only if a pnt defines the current loop edge. we'll send a ray */
/* through p := pnts[i] and check whether it intersects the */
/* current loop edge. if p is an endpoint of seg i0 then we'll */
/* use the supporting line of seg i0; otherwise, we'll use a normal */
/* onto i0. in either case, we make sure to point the ray into the */
/* proper direction. */
/* */
p = GetPntCoords(i);
if (IsSegStartPnt(i0, i)) {
ap = a;
bp = b;
cp = c;
}
else if (IsSegEndPnt(i0, i)) {
ap = -a;
bp = -b;
cp = -c;
}
else {
dist = PntLineDist(a, b, c, p);
if (eq(dist, zero)) {
if (IsInSegConeZero(u, p, a, b, lgth, zero) == 0) {
SetInvalidSites(i0, SEG, i, PNT, zero);
VD_Dbg_Warning("BreakLoopSeg() - point lies on line!");
if (IsInvalidData(false)) restart = true;
return false;
}
}
if (dist < 0.0) {
a = -a;
b = -b;
c = -c;
}
ap = b;
bp = -a;
cp = - ap * p.x - bp * p.y;
}
k = GetStartNode(e);
k0 = GetEndNode(e);
GetNodeData(k0, &q0, &r0_2);
d0 = PntLineDist(ap, bp, cp, q0);
s0 = SignEps(d0, ZERO);
GetNodeData(k, &q1, &r1_2);
d1 = PntLineDist(ap, bp, cp, q1);
s1 = SignEps(d1, ZERO);
if ((s1 * s0 < 0) && gt(r1_2, ZERO) && gt(r0_2, ZERO) &&
IsNodeDeleted(k) && IsNodeDeleted(k0)) {
/* */
/* the nodes q0 and q1 lie on different sides of the ray */
/* through p; thus, the ray intersects the current loop edge! */
/* we insert the point of intersection as dummy node. */
/* */
v = MakeVec( -bp, ap);
if (IntersectRayBisector(i, v, e, &w, &r2)) {
if (IsBetweenVoronoiNodes(e, w, zero)) {
n = StoreNode(w.x, w.y, r2);
InsertDummyNode(e, n, true);
MarkNodeDummy(n);
#ifdef TRACE
#ifdef GRAPHICS
if (debug_flag_VD && graphics) AddToCurBuffer(n, VDN, AlertColor);
#endif
#endif
return true;
}
}
}
}
}
return false;
}
void vroniObject::MarkNonRecursiveSeg(int e, int n, int i,
std::stack<int>& e_stack,
std::stack<int>& n_stack,
std::stack<int>& i_stack)
{
int i0, i1, i2, k, e1, e2, k1, k2;
t_site t1, t2;
coord p, q;
double dist, rad, a, b, c, lgth;
#ifdef TRACE
if (debug_flag_VD) {
printf("MarkNonRecursiveSeg edge e = %d, site i = %d\n", e, i);
PrintNodeData(n, "search started here");
}
#endif
k = GetOtherNode(e, n);
do {
#ifdef TRACE
if (debug_flag_VD) {
printf("MarkNonRecursiveSeg - new node k = %d\n", k);
PrintNodeData(k, "new");
}
#endif
if (!IsNodeUnchecked(k))
/* */
/* this node has already been visited; make sure to avoid a loop. */
/* */
return;
if (IsDeg2Node(k)) {
e1 = GetCCWEdge(e, k);
assert(GetCWEdge(e, k) == e1);
k1 = GetOtherNode(e1, k);
i0 = GetNodeSite(k);
if (i0 != NIL) {
/* */
/* this is a degree-2 node that coincides with an endpoint of a */
/* segment. it should not be deleted! */
/* */
/* if (IsSegStartPnt(i, i0) || IsSegEndPnt(i, i0)) { */
MarkNodeChecked(k);
return;
}
GetNodeData(k, &q, &rad);
GetSegEqnData(i, &a, &b, &c);
lgth = GetSegLgth(i);
p = GetSegStartCoord(i);
dist = AbsPntSegDist(p, q, a, b, c, lgth, TINY) - rad;
#ifdef TRACE
if (debug_flag_VD) {
printf("dist-rad of deg-2 node %2d is %26.22f\n", k, dist);
}
#endif
if (le(dist, zero)) {
MarkNodeVisited(k);
#ifdef TRACE
#ifdef GRAPHICS
if (graphics) AddToCurBuffer(k, VDN, CurrColor);
#endif
if (debug_flag_VD) {
printf("node %2d to be deleted\n", k);
}
#endif
/* */
/* make sure that we don't delete an entire Voronoi cell. */
/* */
#ifdef TRACE
if (debug_flag_VD) {
PrintNodeData(k1, "might be checked next");
PrintEdgeData(e1, "incident edge");
}
#endif
if (IsNodeVisited(k1)) {
GetLftSiteData(e1, &i1, &t1);
GetRgtSiteData(e1, &i2, &t2);
if (t1 == PNT)
if (!HasIncidentSite(i1))
AddToPreserveBuffer(i1, t1);
if (t2 == PNT)
if (!HasIncidentSite(i2))
AddToPreserveBuffer(i2, t2);
return;
}
else {
if (IsNodeUnchecked(k1)) {
e = e1;
n = k;
k = k1;
#ifdef TRACE
if (debug_flag_VD) {
printf("MarkNonRecursiveSeg edge e = %d, ",
e);
printf("node n = %d of status %d, site i = %d\n",
n, GetNodeStatus(n), i);
printf("MarkNonRecursiveSeg new node k =%d\n",
k);
PrintNodeData(k, "new");
}
#endif
}
else {
return;
}
}
}
else {
MarkNodeChecked(k);
#ifdef TRACE
if (debug_flag_VD) PrintNodeData(k, "checked");
#ifdef GRAPHICS
if (graphics) AddToCurBuffer(k, VDN, GridColor);
#endif
#endif
return;
}
}
} while (IsDeg2Node(k));
i0 = GetNodeSite(k);
if (IsSegStartPnt(i, i0) || IsSegEndPnt(i, i0)) {
MarkNodeVisited(k);
return;
}
GetNodeData(k, &q, &rad);
GetSegEqnData(i, &a, &b, &c);
lgth = GetSegLgth(i);
p = GetSegStartCoord(i);
dist = AbsPntSegDist(p, q, a, b, c, lgth, TINY) - rad;
#ifdef TRACE
if (debug_flag_VD) {
printf("dist-rad of deg-? node %2d is %20.16f\n", k, dist);
if (le(dist, zero)) {
printf("yes, dist <= zero = %20.16f\n", zero);
}
else {
printf("no, dist > zero = %20.16f\n", zero);
}
}
#endif
if (le(dist, zero)) {
MarkNodeVisited(k);
#ifdef TRACE
#ifdef GRAPHICS
if (graphics) AddToCurBuffer(k, VDN, CurrColor);
#endif
if (debug_flag_VD) {
printf("node %2d to be deleted\n", k);
PrintNodeData(k, "deleted");
}
#endif
e1 = GetCCWEdge(e, k);
e2 = GetCWEdge(e, k);
k1 = GetEndNode(e1);
if (k1 == k) {
GetRgtSiteData(e1, &i1, &t1);
}
else {
assert(k == GetStartNode(e1));
GetLftSiteData(e1, &i1, &t1);
}
assert((IsLftSite(e2, i1, t1)) || (IsRgtSite(e2, i1, t1)));
k1 = GetOtherNode(e1, k);
k2 = GetOtherNode(e2, k);
/* */
/* make sure that we don't delete an entire Voronoi cell. */
/* */
if (IsNodeVisited(k1)) {
GetOtherSiteData(e1, i1, t1, &i2, &t2);
if (t2 == PNT)
if (!HasIncidentSite(i2))
AddToPreserveBuffer(i2, t2);
if (IsNodeVisited(k2)) {
if (t1 == PNT)
if (!HasIncidentSite(i1))
AddToPreserveBuffer(i1, t1);
GetOtherSiteData(e2, i1, t1, &i2, &t2);
if (t2 == PNT)
if(!HasIncidentSite(i2))
AddToPreserveBuffer(i2, t2);
}
}
else if (IsNodeVisited(k2)) {
GetOtherSiteData(e2, i1, t1, &i2, &t2);
if (t2 == PNT)
if (!HasIncidentSite(i2))
AddToPreserveBuffer(i2, t2);
}
#ifdef TRACE
if (debug_flag_VD) {
PrintNodeData(k1, "might be checked next");
PrintEdgeData(e1, "incident edge");
PrintNodeData(k2, "might be checked next");
PrintEdgeData(e2, "incident edge");
}
#endif
if (IsNodeUnchecked(k2)) {
e_stack.push(e2);
n_stack.push(k);
i_stack.push(i);
#ifdef TRACE
++stack_size;
#endif
}
if (IsNodeUnchecked(k1)) {
e_stack.push(e1);
n_stack.push(k);
i_stack.push(i);
#ifdef TRACE
++stack_size;
#endif
}
#ifdef TRACE
if (stack_size > max_stack_size) max_stack_size = stack_size;
#endif
}
else {
MarkNodeChecked(k);
#ifdef TRACE
if (debug_flag_VD) PrintNodeData(k, "checked");
#ifdef GRAPHICS
if (graphics) AddToCurBuffer(k, VDN, GridColor);
#endif
#endif
}
return;
}
void vroniObject::MarkRecursiveSeg(int e, int n, int i)
{
/* */
/* since deep recursions turned out to be a problem on some platforms, we */
/* resort to a stack to avoid explicit recursive calls. */
/* */
std::stack<int> e_stack, n_stack, i_stack;
#ifdef TRACE
stack_size = 0;
max_stack_size = 0;
#endif
MarkNonRecursiveSeg(e, n, i, e_stack, n_stack, i_stack);
while (!e_stack.empty()) {
assert((e_stack.size() == n_stack.size()) &&
(n_stack.size() == i_stack.size()));
e = e_stack.top();
e_stack.pop();
n = n_stack.top();
n_stack.pop();
i = i_stack.top();
i_stack.pop();
#ifdef TRACE
--stack_size;
#endif
MarkNonRecursiveSeg(e, n, i, e_stack, n_stack, i_stack);
}
#ifdef TRACE
printf("max_stack_size = %16d\n", max_stack_size);
#endif
return;
}
void vroniObject::InsertSegIntoVD(int i)
{
int k, j, j1, j2, n1, n2, n3;
int e, e0, e1, e2, e3;
t_site t0, t1, t2, t3;
int i0, i1, i2, i3;
int e1l, e1r, n1l, n1r, e2l, e2r, n2l, n2r, e3l, e3r, n3l, n3r;
vr_bool node_shared, preserved, broken;
double dist_min;
assert(InSegsList(i));
#ifdef GRAPHICS
if (graphics) {
ResetCurBuffer();
ResetVDBuffer();
}
#endif
ResetPreserveBuffer;
/* */
/* get the indices of the start point and of the end point of the segment.*/
/* */
j1 = Get1stVtx(i, SEG);
assert(InPntsList(j1));
j2 = Get2ndVtx(i, SEG);
assert(InPntsList(j2));
#ifdef TRACE
if (debug_flag_VD) {
printf("inserting seg %d with start %d and end %d\n", i, j1, j2);
printf("0\n%20.16f %20.16f %20.16f %20.16f\n",
pnts[j1].p.x, pnts[j1].p.y, pnts[j2].p.x, pnts[j2].p.y);
}
#endif
/* */
/* find the nearest Voronoi nodes in the Voronoi cells of j1 and j2. */
/* */
SetThreshold(zero, -ZERO);
/* */
/* find the nearest Voronoi nodes in the Voronoi cells of j1 and j2. */
/* */
n1 = FindMostViolatedNodeSeg(j1, j2, i, &node_shared, &dist_min);
if (n1 == NIL) {
SetThreshold(zero, TINY);
n1 = FindMostViolatedNodeSeg(j1, j2, i, &node_shared, &dist_min);
if (n1 == NIL) {
VD_Dbg_Warning("InsertSegIntoVD() - most violated node not found!");
if (IsInvalidData(true)) {
restart = true;
return;
}
else {
VD_Warning("InsertSegIntoVD() - desperate mode for MVN");
n1 = DesperateFindMostViolatedNodeSeg(j1, i);
node_shared = false;
assert(n1 != NIL);
}
}
}
#ifdef TRACE
if (debug_flag_VD) {
printf("InsertSegIntoVD - start node is %d; node_shared = %d\n",
n1, node_shared);
}
#endif
#ifdef VRONI_INFO
UpdateRelaxationMemory(zero);
#endif
assert(InNodesList(n1));
MarkNodeUnchecked(n1);
if (node_shared) {
n2 = n1;
}
else {
SetThreshold(zero, -ZERO);
n2 = FindMostViolatedNodeSeg(j2, j1, i, &node_shared, &dist_min);
if (n2 == NIL) {
SetThreshold(zero, TINY);
n2 = FindMostViolatedNodeSeg(j2, j1, i, &node_shared, &dist_min);
if (n2 == NIL) {
VD_Dbg_Warning("InsertSegIntoVD() - most violated node not found!");
if (IsInvalidData(true)) {
restart = true;
return;
}
else {
VD_Warning("InsertSegIntoVD() - desperate mode for MVN");
n2 = DesperateFindMostViolatedNodeSeg(j2, i);
node_shared = false;
assert(n2 != NIL);
}
}
}
if (n1 != n2) {
assert(InNodesList(n2));
MarkNodeUnchecked(n2);
}
else {
node_shared = true;
}
}
#ifdef TRACE
if (debug_flag_VD) {
printf("InsertSegIntoVD - end node is %d\n", n2);
}
#endif
#ifdef VRONI_INFO
UpdateRelaxationMemory(zero);
#endif
SetThreshold(zero, TINY);
do {
/* */
/* mark all Voronoi nodes that are to be deleted. */
/* */
#ifdef GRAPHICS
if (graphics) {
MarkDrawSite(i, SEG);
AddToCurBuffer(i, SEG, SiteCurrColor);
#ifdef TRACE
AddToCurBuffer(n1, VDN, DTColor);
AddToCurBuffer(n2, VDN, VDColor);
#endif
}
#endif
if (IsDeg2Node(n1)) {
e1 = GetIncidentEdge(n1);
e2 = GetCCWEdge(e1, n1);
e3 = e1;
GetLftSiteData(e1, &i1, &t1);
GetRgtSiteData(e1, &i2, &t2);
MarkNodeVisited(n1);
#ifdef TRACE
if (debug_flag_VD) {
printf("\n+++++ First call of MarkRecursiveSeg()\n");
}
#endif
MarkRecursiveSeg(e1, n1, i);
#ifdef TRACE
if (debug_flag_VD) {
printf("\n+++++ Second call of MarkRecursiveSeg()\n");
}
#endif
MarkRecursiveSeg(e2, n1, i);
}
else {
e1 = GetIncidentEdge(n1);
e2 = GetCCWEdge(e1, n1);
e3 = GetCCWEdge(e2, n1);
MarkNodeVisited(n1);
GetLftSiteData(e1, &i1, &t1);
GetRgtSiteData(e1, &i2, &t2);
GetLftSiteData(e2, &i3, &t3);
if (((i3 == i1) && (t3 == t1)) ||
((i3 == i2) && (t3 == t2)))
GetRgtSiteData(e2, &i3, &t3);
assert(!(((i3 == i1) && (t3 == t1)) &&
((i3 == i2) && (t3 == t2))));
#ifdef TRACE
if (debug_flag_VD) {
printf("\n==== First call of MarkRecursiveSeg()\n");
}
#endif
MarkRecursiveSeg(e1, n1, i);
#ifdef TRACE
if (debug_flag_VD) {
printf("\n==== Second call of MarkRecursiveSeg()\n");
}
#endif
MarkRecursiveSeg(e2, n1, i);
#ifdef TRACE
if (debug_flag_VD) {
printf("\n==== Third call of MarkRecursiveSeg()\n");
}
#endif
MarkRecursiveSeg(e3, n1, i);
}
/* */
/* check whether we've reached the end node n2. if it has not been */
/* reached then we'll enlarge the tolerance threshold zero and we'll */
/* try again. */
/* */
if (!IsNodeVisited(n2)) {
IncreaseThreshold(zero);
if (gt(zero, ZERO_MAX)) {
VD_Dbg_Warning("InsertSegIntoVD() - path not constructed!");
if (IsInvalidData(true)) {
restart = true;
return;
}
else {
VD_Warning("InsertSegIntoVD() - desperate mode (path)");
MarkNodeUnchecked(n2);
n2 = n1;
desperate = true;
troubles = true;
}
}
else {
ResetPreserveBuffer;
ResetNodeStatus(e1, n1);
ResetNodeStatus(e2, n1);
if (!IsDeg2Node(n1)) ResetNodeStatus(e3, n1);
}
#ifdef GRAPHICS
if (graphics) ResetCurBuffer();
#endif
}
#ifdef VRONI_DBG_WARN
else if (gt(zero, ZERO) && !quiet) {
printf("InsertSegIntoVD() -");
printf(" not reached end node till zero = %20.16f for seg %d!\n",
zero, i);
}
#endif
} while (!IsNodeVisited(n2));
#ifdef VRONI_INFO
UpdateRelaxationMemory(zero);
#endif
/* */
/* make sure that no VD cell is completely deleted. */
/* */
for (j = 0; j < num_preserve; ++j) {
SetThreshold(zero, ZERO);
do {
preserved = PreserveVoronoiCellSeg(preserve[j].site,
preserve[j].type, i);
if (!preserved) {
if (restart) return;
IncreaseThreshold(zero);
if (gt(zero, ZERO_MAX)) {
VD_Dbg_Warning("InsertSegIntoVD() - cell not preserved!");
if (IsInvalidData(true)) {
restart = true;
return;
}
else {
VD_Warning("InsertSegIntoVD() - desperate mode (preserve)");
DesperatePreserveVoronoiCellSeg(preserve[j].site,
preserve[j].type, i);
preserved = true;
}
}
}
#ifdef VRONI_DBG_WARN
else if (gt(zero, ZERO) && !quiet) {
printf("InsertSegIntoVD() - ");
printf("cell not preserved till zero = %20.16f for seg %d!\n",
zero, i);
}
#endif
} while (!preserved);
#ifdef VRONI_INFO
UpdateRelaxationMemory(zero);
#endif
}
ResetPreserveBuffer;
/* */
/* make sure that the structure that will be removed forms a tree. */
/* */
e1 = GetIncidentEdge(n1);
MarkNodeDeleted(n1);
ResetLoopStack();
while (LoopExists(e1, n1, &n3)) {
PurifyLoop(n1, n3);
SetThreshold(zero, ZERO);
do {
broken = BreakLoopSeg(i);
if (!broken) {
if (restart) return;
IncreaseThreshold(zero);
if (gt(zero, ZERO_MAX)) {
VD_Dbg_Warning("InsertSegIntoVD() - loop not removed!");
if (IsInvalidData(true)) {
restart = true;
return;
}
else {
VD_Warning("InsertSegIntoVD() - desperate mode (loop)");
DesperateBreakLoopSeg(i);
broken = true;
}
}
}
if (broken) {
#ifdef VRONI_DBG_WARN
if (gt(zero, ZERO) && le(zero, ZERO_MAX) && !quiet) {
printf("InsertSegIntoVD() - ");
printf("loop not broken till zero = %20.16f for seg %d!\n",
zero, i);
}
#endif
ResetLoopStack();
e1 = GetIncidentEdge(n1);
ResetTreeDeleteStatus(e1, n1);
if (n3 == n1) {
e2 = GetCCWEdge(e1, n1);
ResetTreeDeleteStatus(e2, n1);
e3 = GetCCWEdge(e2, n1);
if (e3 != e1) ResetTreeDeleteStatus(e3, n1);
}
MarkNodeDeleted(n1);
}
} while (!broken);
#ifdef VRONI_INFO
UpdateRelaxationMemory(zero);
#endif
}
e1 = GetIncidentEdge(n1);
e2 = GetCCWEdge(e1, n1);
ResetLoopStack();
while (LoopExists(e2, n1, &n3)) {
PurifyLoop(n1, n3);
SetThreshold(zero, ZERO);
do {
broken = BreakLoopSeg(i);
if (!broken) {
if (restart) return;
IncreaseThreshold(zero);
if (gt(zero, ZERO_MAX)) {
VD_Dbg_Warning("InsertSegIntoVD() - loop not removed!");
if (IsInvalidData(true)) {
restart = true;
return;
}
else {
VD_Warning("InsertSegIntoVD() - desperate mode (loop)");
DesperateBreakLoopSeg(i);
broken = true;
}
}
}
if (broken) {
#ifdef VRONI_DBG_WARN
if (gt(zero, ZERO) && le(zero, ZERO_MAX) && !quiet) {
printf("InsertSegIntoVD() - ");
printf("loop not broken till zero = %20.16f for seg %d!\n",
zero, i);
}
#endif
ResetLoopStack();
e2 = GetCCWEdge(e1, n1);
ResetTreeDeleteStatus(e2, n1);
if (n3 == n1) {
e3 = GetCCWEdge(e2, n1);
if (e3 != e1) ResetTreeDeleteStatus(e3, n1);
}
}
} while (!broken);
#ifdef VRONI_INFO
UpdateRelaxationMemory(zero);
#endif
}
e2 = GetCCWEdge(e1, n1);
e3 = GetCCWEdge(e2, n1);
ResetLoopStack();
if (e3 != e1) {
while (LoopExists(e3, n1, &n3)) {
PurifyLoop(n1, n3);
SetThreshold(zero, ZERO);
do {
broken = BreakLoopSeg(i);
if (!broken) {
if (restart) return;
IncreaseThreshold(zero);
if (gt(zero, ZERO_MAX)) {
VD_Dbg_Warning("InsertSegIntoVD() - loop not removed!");
if (IsInvalidData(true)) {
restart = true;
return;
}
else {
VD_Warning("InsertSegIntoVD() - desperate mode (loop)");
DesperateBreakLoopSeg(i);
broken = true;
}
}
}
if (broken) {
#ifdef VRONI_DBG_WARN
if (gt(zero, ZERO) && le(zero, ZERO_MAX) && !quiet) {
printf("InsertSegIntoVD() - ");
printf("loop not broken till zero = %20.16f for seg %d!\n",
zero, i);
}
#endif
ResetLoopStack();
e3 = GetCCWEdge(e2, n1);
ResetTreeDeleteStatus(e3, n1);
}
} while (!broken);
#ifdef VRONI_INFO
UpdateRelaxationMemory(zero);
#endif
}
}
/* */
/* recursively discard all nodes and edges that are to be deleted. */
/* also, we insert the new Voronoi nodes and edges. */
/* */
if (IsDeg2Node(n1)) {
e1 = GetIncidentEdge(n1);
e2 = GetCCWEdge(e1, n1);
#ifdef TRACE
if (debug_flag_VD)
printf("*** 1st call of UpdateRecursive - i = %d, n1 = %d, e1 = %d\n",
i, n1, e1);
#endif
UpdateRecursive(i, SEG, n1, e1, &e1l, &e1r, &n1l, &n1r);
if (restart) return;
#ifdef TRACE
if (debug_flag_VD)
printf("*** 2nd call of UpdateRecursive - i = %d, n1 = %d, e2 = %d\n",
i, n1, e2);
#endif
UpdateRecursive(i, SEG, n1, e2, &e2l, &e2r, &n2l, &n2r);
if (restart) return;
/* */
/* close the two Voronoi cells around nodes[n], which is to be */
/* deleted. */
/* */
/* cell 1: */
/* */
if (GetEndNode(e1r) == n1r) {
GetRgtSiteData(e1r, &i0, &t0);
}
else {
assert(GetStartNode(e1r) == n1r);
GetLftSiteData(e1r, &i0, &t0);
}
e0 = StoreEdge(n1r, n2l, i, i0, SEG, t0);
#ifdef TRACE
if (debug_flag_VD) {
printf("new edge %2d between sites (%2d/0, %2d/%1d) computed\n",
e0, i, i0, t0);
printf("edge %d - start node %d, end node %d\n", e0, n1r, n2l);
}
#endif
SetVDPtr(i0, t0, e0); /* make sure the VD edge pointer is up-to-date! */
CloseVoronoiCell(e1r, e0, e2l, n1r, n2l);
/* */
/* cell 2: */
/* */
if (GetEndNode(e2r) == n2r) {
GetRgtSiteData(e2r, &i0, &t0);
}
else {
assert(GetStartNode(e2r) == n2r);
GetLftSiteData(e2r, &i0, &t0);
}
e0 = StoreEdge(n2r, n1l, i, i0, SEG, t0);
#ifdef TRACE
if (debug_flag_VD) {
printf("new edge %2d between sites (%2d/0, %2d/%1d) computed\n",
e0, i, i0, t0);
printf("edge %d - start node %d, end node %d\n", e0, n2r, n1l);
}
#endif
SetVDPtr(i0, t0, e0); /* make sure the VD edge pointer is up-to-date! */
CloseVoronoiCell(e2r, e0, e1l, n2r, n1l);
}
else {
e1 = GetIncidentEdge(n1);
e2 = GetCCWEdge(e1, n1);
e3 = GetCCWEdge(e2, n1);
#ifdef TRACE
if (debug_flag_VD)
printf("*** 1st call of UpdateRecursive - i = %d, n1 = %d, e1 = %d\n",
i, n1, e1);
#endif
UpdateRecursive(i, SEG, n1, e1, &e1l, &e1r, &n1l, &n1r);
if (restart) return;
#ifdef TRACE
if (debug_flag_VD)
printf("*** 2nd call of UpdateRecursive - i = %d, n1 = %d, e2 = %d\n",
i, n1, e2);
#endif
UpdateRecursive(i, SEG, n1, e2, &e2l, &e2r, &n2l, &n2r);
if (restart) return;
#ifdef TRACE
if (debug_flag_VD)
printf("*** 3rd call of UpdateRecursive - i = %d, n1 = %d, e3 = %d\n",
i, n1, e3);
#endif
UpdateRecursive(i, SEG, n1, e3, &e3l, &e3r, &n3l, &n3r);
if (restart) return;
/* */
/* close the three Voronoi cells around nodes[n], which is to be */
/* deleted. */
/* */
/* cell 1: */
/* */
if (GetEndNode(e1r) == n1r) {
GetRgtSiteData(e1r, &i0, &t0);
}
else {
assert(GetStartNode(e1r) == n1r);
GetLftSiteData(e1r, &i0, &t0);
}
e0 = StoreEdge(n1r, n2l, i, i0, SEG, t0);
#ifdef TRACE
if (debug_flag_VD) {
printf("new edge %2d between sites (%2d/0, %2d/%1d) computed\n",
e0, i, i0, t0);
printf("edge %d - start node %d, end node %d\n", e0, n1r, n2l);
}
#endif
SetVDPtr(i0, t0, e0); /* make sure the VD edge pointer is up-to-date! */
CloseVoronoiCell(e1r, e0, e2l, n1r, n2l);
/* */
/* cell 2: */
/* */
if (GetEndNode(e2r) == n2r) {
GetRgtSiteData(e2r, &i0, &t0);
}
else {
assert(GetStartNode(e2r) == n2r);
GetLftSiteData(e2r, &i0, &t0);
}
e0 = StoreEdge(n2r, n3l, i, i0, SEG, t0);
#ifdef TRACE
if (debug_flag_VD) {
printf("new edge %2d between sites (%2d/0, %2d/%1d) computed\n",
e0, i, i0, t0);
printf("edge %d - start node %d, end node %d\n", e0, n2r, n3l);
}
#endif
SetVDPtr(i0, t0, e0); /* make sure the VD edge pointer is up-to-date! */
CloseVoronoiCell(e2r, e0, e3l, n2r, n3l);
/* */
/* cell 3: */
/* */
if (GetEndNode(e3r) == n3r) {
GetRgtSiteData(e3r, &i0, &t0);
}
else {
assert(GetStartNode(e3r) == n3r);
GetLftSiteData(e3r, &i0, &t0);
}
e0 = StoreEdge(n3r, n1l, i, i0, SEG, t0);
#ifdef TRACE
if (debug_flag_VD) {
printf("new edge %2d between sites (%2d/0, %2d/%1d) computed\n",
e0, i, i0, t0);
printf("edge %d - start node %d, end node %d\n", e0, n3r, n1l);
}
#endif
SetVDPtr(i0, t0, e0); /* make sure the VD edge pointer is up-to-date! */
CloseVoronoiCell(e3r, e0, e1l, n3r, n1l);
}
/* */
/* delete node nodes[n1] */
/* */
DeleteNode(n1);
#ifdef TRACE
if (debug_flag_VD) printf("node %2d has been deleted!\n", n1);
#endif
/* */
/* set the Voronoi pointer for site segs[i] */
/* */
SetVDPtr(i, SEG, e0);
DeleteDummyNodes();
/* */
/* make sure to have (dummy) degree-2 Voronoi nodes at the apices of the */
/* parabolic Voronoi arcs around seg[i]. */
/* */
e = GetVDPtr(i, SEG);
assert(InEdgesList(e));
assert(IsLftSite(e, i, SEG) || IsRgtSite(e, i, SEG));
if (IsRgtSite(e, i, SEG)) k = GetEndNode(e);
else k = GetStartNode(e);
e0 = e;
GetOtherSiteData(e, i, SEG, &i1, &t1);
do {
i0 = i1;
t0 = t1;
if (t1 == PNT || t1 == ARC) InsertApexDegreeTwoNodeSeg(e, i, i1, t1);
e = GetCCWEdge(e, k);
k = GetOtherNode(e, k);
GetOtherSiteData(e, i, SEG, &i1, &t1);
if ((i1 == i0) && (t1 == t0) && (e != e0)) {
e = GetCCWEdge(e, k);
k = GetOtherNode(e, k);
GetOtherSiteData(e, i, SEG, &i1, &t1);
}
} while (e != e0);
#ifndef NDEBUG
i1 = Get1stVtx(i, SEG);
assert(GetVDPtr(i1, PNT) != NIL);
i2 = Get2ndVtx(i, SEG);
assert(GetVDPtr(i2, PNT) != NIL);
#endif
#ifdef GRAPHICS
if (graphics) {
e = GetVDPtr(i, SEG);
assert(InEdgesList(e));
assert(IsLftSite(e, i, SEG) || IsRgtSite(e, i, SEG));
if (IsRgtSite(e, i, SEG)) k = GetEndNode(e);
else k = GetStartNode(e);
e0 = e;
do {
AddToCurBuffer(e, VDE, VDCurrColor);
e = GetCCWEdge(e, k);
k = GetOtherNode(e, k);
} while (e != e0);
}
#endif
return;
}
// #undef TRACE