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

1908 lines
58 KiB
C++

/*****************************************************************************/
/* */
/* Copyright (C) 1999-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 standard libraries */
/* */
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <float.h>
#include <math.h>
/* */
/* get my header files */
/* */
#include "fpkernel.h"
#include "vronivector.h"
#include "vroni_object.h"
#include "defs.h"
#include "numerics.h"
#include "offset.h"
#define BLOCK_SIZE 1024
#define MINI 16
#define PAGE_SIZE 65536
#ifdef VRONI_INFO
void vroniObject::InitRelaxationMemory(double_arg t)
{
max_relaxation = curr_relaxation = t;
return;
}
void vroniObject::UpdateRelaxationMemory(double_arg t)
{
curr_relaxation = VroniMax(curr_relaxation, t);
return;
}
void vroniObject::ConfirmRelaxationMemory()
{
max_relaxation = VroniMax(max_relaxation, curr_relaxation);
return;
}
double vroniObject::ReportRelaxationMemory()
{
return max_relaxation;
}
#endif
void vroniObject::SetRootTooLarge(double_arg t)
{
too_large = t;
return;
}
void vroniObject::SetDeg2Flag(void)
{
deg2_nodes_inserted = true;
return;
}
vr_bool vroniObject::GetDeg2Flag(void)
{
return deg2_nodes_inserted;
}
void vroniObject::SetNodesSqdFlag()
{
VD_nodes_squared = false;
return;
}
vr_bool vroniObject::GetNodesSqdFlag(void)
{
return VD_nodes_squared;
}
void vroniObject::PrintVDCounters(void)
{
printf("\nnum_free_nodes: %d\n", num_free_nodes);
printf("num_free_edges: %d\n", num_free_edges);
printf("num_nodes: %d\n", num_nodes);
printf("num_edges: %d\n", num_edges);
printf("nodes used: %d\n", num_nodes - num_free_nodes);
printf("edges used: %d\n", num_edges - num_free_edges);
return;
}
#ifdef GRAPHICS
void vroniObject::FindClosestNode(double_arg x1, double_arg y1)
{
double dist_min, dist, x, y;
int i, i_min, n1;
coord p;
dist_min = VroniMax(bb_max.x - bb_min.x, bb_max.y - bb_min.y);
dist_min = VroniMax(dist_min, 1.0);
dist_min = dist_min * dist_min;
i_min = 0;
for (i = 4; i < num_edges; ++i) {
if (! IsEdgeDeleted(i) ) {
n1 = GetStartNode(i);
p = GetNodeCoord(n1);
x = p.x - x1;
y = p.y - y1;
dist = x * x + y * y;
if (dist < dist_min) {
dist_min = dist;
i_min = n1;
}
n1 = GetEndNode(i);
p = GetNodeCoord(n1);
x = p.x - x1;
y = p.y - y1;
dist = x * x + y * y;
if (dist < dist_min) {
dist_min = dist;
i_min = n1;
}
}
}
AddToCurBuffer(i_min, VDN, AlertColor);
#ifdef VR_TRACE
PrintNodeData(i_min, "closest");
#endif
return;
}
#endif
int vroniObject::GetVDIdentifier(void)
{
return VD_identifier;
}
vr_bool vroniObject::GetVDStatus(void)
{
return VD_computed;
}
void vroniObject::ResetVDStatus(void)
{
VD_computed = false;
}
void vroniObject::SetVDStatusTrue(void)
{
VD_computed = true;
}
int vroniObject::GetNumberOfNodes(void)
{
return num_nodes;
}
int vroniObject::GetNumberOfEdges(void)
{
return num_edges;
}
void vroniObject::DeleteNode(int n)
{
assert(InNodesList(n));
if (num_free_nodes >= max_num_free_nodes) {
// MODIF modifico quantità di memoria richiesta dall'allocazione in analogia con std::vector
// max_num_free_nodes += BLOCK_SIZE;
max_num_free_nodes = ( num_free_nodes + 1) * 2 ;
gentlyResizeSTLVector(free_nodes, max_num_free_nodes, "vd:free_nodes");
}
free_nodes[num_free_nodes] = n;
SetNodeStatus(n, DELETED);
++num_free_nodes;
return;
}
void vroniObject::DeleteEdge(int e)
{
assert(InEdgesList(e));
edges[e].lft = NIL;
edges[e].rgt = NIL;
MarkEdgeDeleted(e);
if (num_free_edges >= max_num_free_edges) {
// MODIF modifico quantità di memoria richiesta dall'allocazione in analogia con std::vector
// max_num_free_edges += BLOCK_SIZE;
max_num_free_edges = ( num_free_edges + 1) * 2 ;
gentlyResizeSTLVector(free_edges, max_num_free_edges, "vd:free_edges");
}
free_edges[num_free_edges] = e;
++num_free_edges;
return;
}
int vroniObject::StoreNode(double_arg x, double_arg y, double_arg r2)
{
int i;
node *ptr;
if (num_free_nodes > 0) {
--num_free_nodes;
i = free_nodes[num_free_nodes];
if (i >= num_nodes) num_nodes = i + 1;
assert(InNodesList(i));
assert(IsNodeDeleted(i));
}
else {
if (num_nodes >= max_num_nodes) {
// MODIF modifico quantità di memoria richiesta dall'allocazione in analogia con std::vector
// max_num_nodes += PAGE_SIZE;
max_num_nodes = ( num_nodes + 1) * 2 ;
gentlyResizeSTLVector(nodes, max_num_nodes, "vd:nodes");
}
i = num_nodes;
++num_nodes;
}
ptr = &(nodes[i]);
ptr->p.x = x;
ptr->p.y = y;
ptr->r2 = r2;
ptr->status = UNCHECKED;
ptr->edge = NIL;
ptr->site = NIL;
ptr->deg2 = false;
#ifdef EXT_APPL_VD
ptr->ext_appl = ean_NIL;
#endif
#ifdef WRITE_VD
ptr->idx = NIL;
#endif
return i;
}
void vroniObject::InitNodes(int number)
{
if (max_num_nodes < number) {
max_num_nodes = number;
gentlyResizeSTLVector(nodes, max_num_nodes, "vd:nodes");
}
num_nodes = 0;
if (max_num_free_nodes < number) {
// MODIF modifico quantità di memoria richiesta dall'allocazione
// max_num_free_nodes = BLOCK_SIZE;
max_num_free_nodes = number;
gentlyResizeSTLVector(free_nodes, max_num_free_nodes, "vd:free_nodes");
}
num_free_nodes = 0;
return;
}
int vroniObject::StoreEdge(int n1, int n2, int lft, int rgt, t_site ltype, t_site rtype)
{
int i;
edge *ptr;
if (num_free_edges > 0) {
--num_free_edges;
i = free_edges[num_free_edges];
if (i >= num_edges) num_edges = i + 1;
assert(InEdgesList(i));
assert(IsEdgeDeleted(i));
}
else {
if (num_edges >= max_num_edges) {
// MODIF modifico quantità di memoria richiesta dall'allocazione in analogia con std::vector
// max_num_edges += PAGE_SIZE;
max_num_edges = ( num_edges + 1) * 2 ;
gentlyResizeSTLVector(edges, max_num_edges, "vd:edges");
}
i = num_edges;
++num_edges;
}
ptr = &(edges[i]);
ptr->n1 = n1;
ptr->n2 = n2;
ptr->lft = lft;
ptr->rgt = rgt;
ptr->ltype = ltype;
ptr->rtype = rtype;
ptr->s_ccw = NIL;
ptr->e_ccw = NIL;
ptr->s_cw = NIL;
ptr->e_cw = NIL;
ptr->del = false;
#ifdef EXT_APPL_VD
ptr->ext_appl = eae_NIL;
#endif
return i;
}
void vroniObject::InitEdges(int number)
{
if (max_num_edges < number) {
max_num_edges = number;
gentlyResizeSTLVector(edges, max_num_edges, "vd:edges");
}
num_edges = 0;
if (max_num_free_edges < number) {
// MODIF modifico quantità di memoria richiesta dall'allocazione
// max_num_free_edges = BLOCK_SIZE;
max_num_free_edges = number;
gentlyResizeSTLVector(free_edges, max_num_free_edges, "vd:free_edges");
}
num_free_edges = 0;
return;
}
void vroniObject::FreeVDData()
{
nodes.clear();
edges.clear();
free_nodes.clear();
free_edges.clear();
FreeMemory((void**) &dummies, "vd:dummies");
max_num_nodes = 0;
num_nodes = 0;
max_num_edges = 0;
num_edges = 0;
max_num_free_nodes = 0;
num_free_nodes = 0;
max_num_free_edges = 0;
num_free_edges = 0;
max_num_dummies = 0;
num_dummies = 0;
VD_computed = false;
deg2_nodes_inserted = false;
VD_nodes_squared = true;
return;
}
void vroniObject::ResetVDData(void)
{
num_nodes = 0;
num_edges = 0;
num_free_nodes = 0;
num_free_edges = 0;
num_dummies = 0;
VD_computed = false;
deg2_nodes_inserted = false;
VD_nodes_squared = true;
return;
}
vr_bool vroniObject::InEdgesList(int index)
{
return ((index >= 0) && (index < num_edges) &&
(num_edges <= max_num_edges));
}
vr_bool vroniObject::InNodesList(int index)
{
return ((index >= 0) && (index < num_nodes) &&
(num_nodes <= max_num_nodes));
}
void vroniObject::ComputeInitialVD(void)
{
coord n4, n5, n6, n7;
double r4, r5, r6, r7, infty, dist_min;
int i, j, number, k;
assert(num_edges == 0);
assert(num_nodes == 0);
assert(num_pnts > 4);
VD_computed = false;
IncrementVDIdentifier();
/* */
/* reserve enough memory for the Voronoi nodes and edges. note that we */
/* need more nodes and edges than predicted by theory since we subdivide */
/* conic edges at their apices. */
/* */
number = VroniMax(num_pnts, num_segs);
InitNodes(4 * number);
InitEdges(6 * number);
i = num_pnts - 2;
j = num_pnts - 1;
assert(pnts[0].p.x == pnts[1].p.x);
assert(pnts[0].p.y < pnts[1].p.y);
assert(pnts[i].p.x == pnts[j].p.x);
assert(pnts[i].p.y < pnts[j].p.y);
assert(pnts[0].p.x < pnts[i].p.x);
assert(pnts[0].p.y == pnts[i].p.y);
assert(pnts[1].p.x < pnts[j].p.x);
assert(pnts[1].p.y == pnts[j].p.y);
assert(pnts[0].p.x < pnts[2].p.x);
assert(pnts[j].p.x > pnts[2].p.x);
assert(pnts[0].p.y < pnts[2].p.y);
assert(pnts[j].p.y > pnts[2].p.y);
/* */
/* compute the four Voronoi nodes of the Voronoi cell of pnts[2] w.r.t. */
/* the four dummy corner points pnts[0[,pnts[1],pnts[i],pnts[j]. */
/* */
if (!PntPntPntCntr(0, 1, 2, &n4, &r4)) {
VD_Warning("GetInitialVD() - serious numerical problems!\n");
}
if (!PntPntPntCntr(1, 2, j, &n5, &r5)) {
VD_Warning("GetInitialVD() - serious numerical problems!\n");
}
if (!PntPntPntCntr(2, i, j, &n6, &r6)) {
VD_Warning("GetInitialVD() - serious numerical problems!\n");
}
if (!PntPntPntCntr(0, 2, i, &n7, &r7)) {
VD_Warning("GetInitialVD() - serious numerical problems!\n");
}
/* */
/* compute dummy x,y-coordinates for the "end" nodes n0,...n3 of the */
/* four rays originating at n4,...,n7. */
/* */
infty = sqrt(DBL_MAX / 10.0);
/* */
/* store the four dummy Voronoi nodes. */
/* */
k = StoreNode(n4.x - infty, n4.y, infty);
assert(k == 0);
k = StoreNode(n5.x, n5.y + infty, infty);
assert(k == 1);
k = StoreNode(n6.x + infty, n6.y, infty);
assert(k == 2);
k = StoreNode(n7.x, n7.y - infty, infty);
assert(k == 3);
/* */
/* store the four true Voronoi nodes. */
/* */
k = StoreNode(n4.x, n4.y, r4);
assert(k == 4);
k = StoreNode(n5.x, n5.y, r5);
assert(k == 5);
k = StoreNode(n6.x, n6.y, r6);
assert(k == 6);
k = StoreNode(n7.x, n7.y, r7);
assert(k == 7);
/* */
/* store the four Voronoi rays. */
/* */
k = StoreEdge(0, 4, 1, 0, PNT, PNT);
assert(k == 0);
k = StoreEdge(1, 5, j, 1, PNT, PNT);
assert(k == 1);
k = StoreEdge(2, 6, i, j, PNT, PNT);
assert(k == 2);
k = StoreEdge(3, 7, 0, i, PNT, PNT);
assert(k == 3);
/* */
/* store the four true Voronoi edges (which bound the Voronoi cell of the */
/* point pnts[2]). */
/* */
k = StoreEdge(4, 5, 1, 2, PNT, PNT);
assert(k == 4);
#ifdef GRAPHICS
if (graphics) AddToCurBuffer(k, VDE, VDCurrColor);
#endif
k = StoreEdge(5, 6, j, 2, PNT, PNT);
assert(k == 5);
#ifdef GRAPHICS
if (graphics) AddToCurBuffer(k, VDE, VDCurrColor);
#endif
k = StoreEdge(6, 7, i, 2, PNT, PNT);
assert(k == 6);
#ifdef GRAPHICS
if (graphics) AddToCurBuffer(k, VDE, VDCurrColor);
#endif
k = StoreEdge(7, 4, 0, 2, PNT, PNT);
assert(k == 7);
#ifdef GRAPHICS
if (graphics) AddToCurBuffer(k, VDE, VDCurrColor);
#endif
/* */
/* store four dummy Voronoi edges (which "bound" the Voronoi cells of the */
/* points pnts[0], pnts[1], pnts[i], pnts[j]). */
/* */
k = StoreEdge(0, 1, NIL, 1, UNKNOWN, PNT);
assert(k == 8);
k = StoreEdge(1, 2, NIL, j, UNKNOWN, PNT);
assert(k == 9);
k = StoreEdge(2, 3, NIL, i, UNKNOWN, PNT);
assert(k == 10);
k = StoreEdge(3, 0, NIL, 0, UNKNOWN, PNT);
assert(k == 11);
/* */
/* add all CCW/CW pointers */
/* */
edges[0].e_ccw = 7;
edges[0].e_cw = 4;
edges[0].s_ccw = 8;
edges[0].s_cw = 11;
edges[1].e_ccw = 4;
edges[1].e_cw = 5;
edges[1].s_ccw = 9;
edges[1].s_cw = 8;
edges[2].e_ccw = 5;
edges[2].e_cw = 6;
edges[2].s_ccw = 10;
edges[2].s_cw = 9;
edges[3].e_ccw = 6;
edges[3].e_cw = 7;
edges[3].s_ccw = 11;
edges[3].s_cw = 10;
edges[4].s_ccw = 0;
edges[4].s_cw = 7;
edges[4].e_ccw = 5;
edges[4].e_cw = 1;
edges[5].s_ccw = 1;
edges[5].s_cw = 4;
edges[5].e_ccw = 6;
edges[5].e_cw = 2;
edges[6].s_ccw = 2;
edges[6].s_cw = 5;
edges[6].e_ccw = 7;
edges[6].e_cw = 3;
edges[7].s_ccw = 3;
edges[7].s_cw = 6;
edges[7].e_ccw = 4;
edges[7].e_cw = 0;
edges[8].s_ccw = 11;
edges[8].s_cw = 0;
edges[8].e_ccw = 1;
edges[8].e_cw = 9;
edges[9].s_ccw = 8;
edges[9].s_cw = 1;
edges[9].e_ccw = 2;
edges[9].e_cw = 10;
edges[10].s_ccw = 9;
edges[10].s_cw = 2;
edges[10].e_ccw = 3;
edges[10].e_cw = 11;
edges[11].s_ccw = 10;
edges[11].s_cw = 3;
edges[11].e_ccw = 0;
edges[11].e_cw = 8;
/* */
/* set pointers from the five points to edges of their Voronoi cells. */
/* */
pnts[0].vd = 11;
pnts[1].vd = 8;
pnts[2].vd = 4;
pnts[j].vd = 9;
pnts[i].vd = 10;
/* */
/* store an incident Voronoi edge with every node. */
/* */
nodes[0].edge = 0;
nodes[1].edge = 1;
nodes[2].edge = 2;
nodes[3].edge = 3;
nodes[4].edge = 0;
nodes[5].edge = 1;
nodes[6].edge = 2;
nodes[7].edge = 3;
/* */
/* insert point pnt[2] into the grid. */
/* */
(void) InsertPntIntoGrid(2, &dist_min);
/* */
/* mark the five points for drawing. */
/* */
#ifdef GRAPHICS
if (graphics) {
pnts[0].draw = true;
pnts[1].draw = true;
pnts[2].draw = true;
pnts[i].draw = true;
pnts[j].draw = true;
AddToCurBuffer(2, PNT, SiteCurrColor);
}
#endif
return;
}
#ifdef GRAPHICS
// MODIF : alla funzione AddEdgeToBuffer sono passati anche i parametri in cui viengono calcolati i due punti del bisettore
void vroniObject::AddVDEdgeToBuffer(int i)
{
int n1, n2;
double t1, t2;
coord u, v;
n1 = GetStartNode(i);
n2 = GetEndNode(i);
// MODIF : lo step size viene modificato come in AddVDToBuffer
double delta_x = bb_max.x - bb_min.x ;
double delta_y = bb_max.y - bb_min.y ;
double delta = VroniMax(delta_x, delta_y) ;
if (le(delta, ZERO)) delta = ZERO ;
SetStepSize(delta) ;
switch(edges[i].ltype) {
case(PNT):
switch(edges[i].rtype) {
case(PNT): /* PNT-PNT: line bisector */
GetNodeData(n1, &u, &t1);
GetNodeData(n2, &v, &t2);
AddEdgeToBuffer(nodes[n1].p.x, nodes[n1].p.y,
nodes[n2].p.x, nodes[n2].p.y,
VDColor, t1, t2);
break;
case(SEG): /* PNT-SEG: parabola bisector */
GetNodeData(n1, &u, &t1);
GetNodeData(n2, &v, &t2);
AddParabolaToBuffer(i, t1, t2, u, v, VDColor);
break;
case(ARC):
#ifdef GENUINE_ARCS
GetNodeData(n1, &u, &t1);
GetNodeData(n2, &v, &t2);
AddHyperbolaEllipseToBuffer(i, t1, t2, u, v, VDColor);
#endif
break;
default:
break;
}
break;
case(SEG):
switch(edges[i].rtype) {
case(PNT): /* SEG-PNT: parabola bisector */
GetNodeData(n1, &u, &t1);
GetNodeData(n2, &v, &t2);
AddParabolaToBuffer(i, t1, t2, u, v, VDColor);
break;
case(SEG): /* SEG-SEG: line bisector */
GetNodeData(n1, &u, &t1);
GetNodeData(n2, &v, &t2);
AddEdgeToBuffer(nodes[n1].p.x, nodes[n1].p.y,
nodes[n2].p.x, nodes[n2].p.y,
VDColor, t1, t2);
break;
case(ARC):
#ifdef GENUINE_ARCS
GetNodeData(n1, &u, &t1);
GetNodeData(n2, &v, &t2);
AddParabolaToBuffer(i, t1, t2, u, v, VDColor);
#endif
break;
default:
break;
}
break;
case(ARC):
switch(edges[i].rtype) {
case(PNT):
#ifdef GENUINE_ARCS
GetNodeData(n1, &u, &t1);
GetNodeData(n2, &v, &t2);
AddHyperbolaEllipseToBuffer(i, t1, t2, u, v, VDColor);
#endif
break;
case(SEG):
#ifdef GENUINE_ARCS
GetNodeData(n1, &u, &t1);
GetNodeData(n2, &v, &t2);
AddParabolaToBuffer(i, t1, t2, u, v, VDColor);
#endif
break;
case(ARC):
#ifdef GENUINE_ARCS
GetNodeData(n1, &u, &t1);
GetNodeData(n2, &v, &t2);
AddHyperbolaEllipseToBuffer(i, t1, t2, u, v, VDColor);
#endif
break;
default:
break;
}
break;
default:
break;
}
// MODIF : non serve allocare il buffer dei nodi ( eviti problemi di memory leak)
// AddNodeToBuffer(n1, VDColor);
// AddNodeToBuffer(n2, VDColor);
return;
}
void vroniObject::AddVDToBuffer(vr_bool left_vd, vr_bool right_vd)
{
int i, j, not_needed;
double delta_x, delta_y, delta;
vr_bool unrestricted;
///void SetStepSize(double_arg delta);
/* */
/* delete all VD edges currently stored in the graphics buffer */
/* */
assert(num_edges > 11);
assert(num_nodes > 7);
ResetVDBuffer();
/* */
/* are we required to output the VD only on the "left" or right side of */
/* the input segments/arcs? */
/* */
if (left_vd && right_vd) {
left_vd = right_vd = false;
}
unrestricted = !(left_vd || right_vd);
/* */
/* compute the discretization threshold for approximating non-linear */
/* bisectors. */
/* */
delta_x = bb_max.x - bb_min.x;
delta_y = bb_max.y - bb_min.y;
delta = VroniMax(delta_x, delta_y);
if (le(delta, ZERO)) delta = ZERO;
SetStepSize(delta);
/* */
/* terminate the four VD rays within a region that can be handled. */
/* */
delta_x = 10.0 * (pnts[num_pnts-1].p.x - pnts[0].p.x);
delta_y = 10.0 * (pnts[num_pnts-1].p.y - pnts[0].p.y);
if (unrestricted) {
AddEdgeToBuffer(nodes[edges[0].n2].p.x, nodes[edges[0].n2].p.y,
nodes[edges[0].n2].p.x-delta_x, nodes[edges[0].n1].p.y,
VDColor);
AddEdgeToBuffer(nodes[edges[2].n2].p.x, nodes[edges[2].n2].p.y,
nodes[edges[2].n2].p.x+delta_x, nodes[edges[2].n1].p.y,
VDColor);
AddEdgeToBuffer(nodes[edges[1].n2].p.x, nodes[edges[1].n2].p.y,
nodes[edges[1].n1].p.x, nodes[edges[1].n2].p.y+delta_y,
VDColor);
AddEdgeToBuffer(nodes[edges[3].n2].p.x, nodes[edges[3].n2].p.y,
nodes[edges[3].n1].p.x, nodes[edges[3].n2].p.y-delta_y,
VDColor);
for (i = 4; i < num_edges; ++i) {
if ((! IsEdgeDeleted(i) ) &&
(edges[i].lft != NIL) && (edges[i].rgt != NIL)) {
AddVDEdgeToBuffer(i);
}
}
}
else {
/* */
/* find those VD edges that are to be output */
/* */
InitializeEdgeData(unrestricted, left_vd, false, &not_needed);
j = -1;
AdvanceActiveEdge(i, j, false);
while (i != NIL) {
switch(i) {
case 0:
AddEdgeToBuffer(nodes[edges[0].n2].p.x, nodes[edges[0].n2].p.y,
nodes[edges[0].n2].p.x-delta_x,
nodes[edges[0].n1].p.y,
VDColor);
break;
case 1:
AddEdgeToBuffer(nodes[edges[2].n2].p.x, nodes[edges[2].n2].p.y,
nodes[edges[2].n2].p.x+delta_x,
nodes[edges[2].n1].p.y,
VDColor);
break;
case 2:
AddEdgeToBuffer(nodes[edges[1].n2].p.x, nodes[edges[1].n2].p.y,
nodes[edges[1].n1].p.x,
nodes[edges[1].n2].p.y+delta_y,
VDColor);
break;
case 3:
AddEdgeToBuffer(nodes[edges[3].n2].p.x, nodes[edges[3].n2].p.y,
nodes[edges[3].n1].p.x,
nodes[edges[3].n2].p.y-delta_y,
VDColor);
break;
default:
AddVDEdgeToBuffer(i);
break;
}
AdvanceActiveEdge(i, j, false);
}
}
return;
}
void vroniObject::AddDelToBuffer(void)
{
int i;
assert(num_edges > 11);
assert(num_nodes > 7);
for (i = 4; i < num_edges; ++i) {
if ((! IsEdgeDeleted(i) ) &&
( edges[i].lft >= 2) && (edges[i].lft < (num_pnts - 2)) &&
(edges[i].rgt >= 2) && (edges[i].rgt < (num_pnts - 2))) {
switch(edges[i].ltype) {
case(PNT):
switch(edges[i].rtype) {
case(PNT): /* PNT-PNT: line bisector */
AddEdgeToBuffer(pnts[edges[i].lft].p.x, pnts[edges[i].lft].p.y,
pnts[edges[i].rgt].p.x, pnts[edges[i].rgt].p.y,
DTColor);
break;
default:
break;
}
break;
default:
break;
}
}
}
return;
}
#define PrintNodeStatus(N) \
{ \
if (nodes[N].deg2) { \
if (nodes[N].status == UNCHECKED) \
fprintf(stderr, \
"CheckVDCell - deg-2 node %d has status UNCHECKED\n", N); \
else if (nodes[N].status == CHECKED) \
fprintf(stderr, \
"CheckVDCell - deg-2 node %d has status CHECKED\n", N); \
else if (nodes[N].status == DELETED) \
fprintf(stderr, \
"CheckVDCell - deg-2 node %d has status DELETED\n", N); \
else if (nodes[N].status == VISITED) \
fprintf(stderr, \
"CheckVDCell - deg-2 node %d has status VISITED\n", N); \
else if (nodes[N].status == DUMMY) \
fprintf(stderr, \
"CheckVDCell - deg-2 node %d has status DUMMY\n", N); \
else if (nodes[N].status == MISC) \
fprintf(stderr, \
"CheckVDCell - deg-2 node %d has status MISC\n", N); \
} \
else { \
if (nodes[N].status == UNCHECKED) \
fprintf(stderr, \
"CheckVDCell - deg-3 node %d has status UNCHECKED\n", N); \
else if (nodes[N].status == CHECKED) \
fprintf(stderr, \
"CheckVDCell - deg-3 node %d has status CHECKED\n", N); \
else if (nodes[N].status == DELETED) \
fprintf(stderr, \
"CheckVDCell - deg-3 node %d has status DELETED\n", N); \
else if (nodes[N].status == VISITED) \
fprintf(stderr, \
"CheckVDCell - deg-3 node %d has status VISITED\n", N); \
else if (nodes[N].status == DUMMY) \
fprintf(stderr, \
"CheckVDCell - deg-3 node %d has status DUMMY\n", N); \
else if (nodes[N].status == MISC) \
fprintf(stderr, \
"CheckVDCell - deg-3 node %d has status MISC\n", N); \
} \
}
vr_bool vroniObject::CheckVDCell(int i, int e0, t_site t, vr_bool arcs_recovered)
{
int e, e1, n, n1, n2, cntr = 0;
vr_bool success = true;
e = e0;
if (IsLftSite(e, i, t)) {
n = edges[e].n1;
}
else if (IsRgtSite(e, i, t)) {
n = edges[e].n2;
}
else {
fprintf(stderr,
"CheckVDCell - site %d of type %d not lft/rgt of edge %d\n",
i, t, e);
#ifdef VR_TRACE
PrintSiteData(i, t, "CheckVD");
#endif
return false;
}
arcs_recovered = false;
do {
#ifdef VR_TRACE
if (proto) printf("checking edge %2d of site %2d (site type %d)\n",
e, i, t);
#endif
if (!InEdgesList(e)) {
fprintf(stderr,
"CheckVDCell - edge %d is not in the edge list\n", e);
success = false;
}
if ( IsEdgeDeleted(e) ) {
fprintf(stderr,
"CheckVDCell - edge %d is marked as deleted\n", e);
success = false;
}
if (!IsLftSite(e, i, t) && !IsRgtSite(e, i, t)) {
fprintf(stderr,
"CheckVDCell - site %d of type %d not lft/rgt of edge %d\n",
i, t, e);
success = false;
}
n1 = edges[e].n1;
if (!InNodesList(n1)) {
fprintf(stderr,
"CheckVDCell - start node %d of edge %d not in list\n", n1, e);
success = false;
}
if ((n1 > 3) && (nodes[n1].r2 == 0.0) && (nodes[n1].site == NIL)) {
fprintf(stderr,
"CheckVDCell - node %d has radius 0.0 but does not coincide with point\n", n1);
success = false;
}
if (!(nodes[n1].deg2 || (nodes[n1].status == UNCHECKED))) {
PrintNodeStatus(n1);
success = false;
}
if (!((nodes[n1].edge == e) || (nodes[n1].edge == edges[e].s_ccw) ||
(nodes[n1].edge == edges[e].s_cw))) {
fprintf(stderr,
"CheckVDCell - edge %d not incident at its start node %d - %d\n",
e, n1, nodes[n1].edge);
success = false;
}
if (nodes[n1].deg2) {
if (edges[e].s_ccw != edges[e].s_cw) {
fprintf(stderr,
"CheckVDCell - deg-2 start node %d of edge %d has more than two incident edges!\n",
n1, e);
success = false;
}
}
else {
if (edges[e].s_ccw == edges[e].s_cw) {
fprintf(stderr,
"CheckVDCell - deg-3 start node %d of edge %d has only two incident edges!\n",
n1, e);
success = false;
}
}
n2 = edges[e].n2;
if (!InNodesList(n2)) {
fprintf(stderr,
"CheckVDCell - end node %d of edge %d not in list\n", n2, e);
success = false;
}
if ((n2 > 3) && (nodes[n2].r2 == 0.0) && (nodes[n2].site == NIL)) {
fprintf(stderr,
"CheckVDCell - node %d has radius 0.0 but does not coincide with point\n", n2);
success = false;
}
if (!(nodes[n2].deg2 || (nodes[n2].status == UNCHECKED))) {
PrintNodeStatus(n2);
success = false;
}
if (!((nodes[n2].edge == e) || (nodes[n2].edge == edges[e].e_ccw) ||
(nodes[n2].edge == edges[e].e_cw))) {
fprintf(stderr,
"CheckVDCell - edge %d not incident at its end node %d - %d\n",
e, n2, nodes[n2].edge);
success = false;
}
if (nodes[n2].deg2) {
if (edges[e].e_ccw != edges[e].e_cw) {
fprintf(stderr,
"CheckVDCell - deg-2 start node %d of edge %d has more than two incident edges!\n",
n2, e);
success = false;
}
}
else {
if (edges[e].e_ccw == edges[e].e_cw) {
fprintf(stderr,
"CheckVDCell - deg-3 start node %d of edge %d has only two incident edges!\n",
n2, e);
success = false;
}
}
e1 = edges[e].s_cw;
if (!InEdgesList(e1)) {
fprintf(stderr,
"CheckVDCell - edge %d ptd s_cw by edge %d not in list\n",
e1, e);
success = false;
}
if (!((edges[e1].s_ccw == e) || (edges[e1].e_ccw == e))) {
fprintf(stderr,
"CheckVDCell - edge %d does not ptr back ccw (s_cw) to %d\n",
e1, e);
fprintf(stderr,
"CheckVDCell - edges[%d].s_ccw = %d, edges[%d].e_ccw = %d\n",
e1, edges[e1].s_ccw, e1, edges[e1].e_ccw);
fprintf(stderr,
"CheckVDCell - edges[%d].s_cw = %d, edges[%d].e_cw = %d\n",
e1, edges[e1].s_cw, e1, edges[e1].e_cw);
success = false;
}
e1 = edges[e].e_cw;
if (!InEdgesList(e1)) {
fprintf(stderr,
"CheckVDCell - edge %d ptd e_cw by edge %d not in list\n",
e1, e);
success = false;
}
if (!((edges[e1].s_ccw == e) || (edges[e1].e_ccw == e))) {
fprintf(stderr,
"CheckVDCell - edge %d does not ptr back ccw (e_cw) to %d\n",
e1, e);
fprintf(stderr,
"CheckVDCell - edges[%d].s_ccw = %d, edges[%d].e_ccw = %d\n",
e1, edges[e1].s_ccw, e1, edges[e1].e_ccw);
fprintf(stderr,
"CheckVDCell - edges[%d].s_cw = %d, edges[%d].e_cw = %d\n",
e1, edges[e1].s_cw, e1, edges[e1].e_cw);
success = false;
}
e1 = edges[e].s_ccw;
if (!InEdgesList(e1)) {
fprintf(stderr,
"CheckVDCell - edge %d ptd s_ccw by edge %d not in list\n",
e1, e);
success = false;
}
if (!((edges[e1].s_cw == e) || (edges[e1].e_cw == e))) {
fprintf(stderr,
"CheckVDCell - edge %d does not ptr back cw (s_ccw) to %d\n",
e1, e);
fprintf(stderr,
"CheckVDCell - edges[%d].s_ccw = %d, edges[%d].e_ccw = %d\n",
e1, edges[e1].s_ccw, e1, edges[e1].e_ccw);
fprintf(stderr,
"CheckVDCell - edges[%d].s_cw = %d, edges[%d].e_cw = %d\n",
e1, edges[e1].s_cw, e1, edges[e1].e_cw);
success = false;
}
e1 = edges[e].e_ccw;
if (!InEdgesList(e1)) {
fprintf(stderr,
"CheckVDCell - edge %d ptd e_ccw by edge %d not in list\n",
e1, e);
success = false;
}
if (!((edges[e1].s_cw == e) || (edges[e1].e_cw == e))) {
fprintf(stderr,
"CheckVDCell - edge %d does not ptr back cw (e_ccw) to %d\n",
e1, e);
fprintf(stderr,
"CheckVDCell - edges[%d].s_ccw = %d, edges[%d].e_ccw = %d\n",
e1, edges[e1].s_ccw, e1, edges[e1].e_ccw);
fprintf(stderr,
"CheckVDCell - edges[%d].s_cw = %d, edges[%d].e_cw = %d\n",
e1, edges[e1].s_cw, e1, edges[e1].e_cw);
success = false;
}
e = GetCCWEdge(e, n);
n = GetOtherNode(e, n);
++cntr;
} while ((e != e0) && (cntr < num_edges));
if (!success) {
if (t == PNT)
fprintf(stderr,
"CheckVDCell - the error(s) occurred for pnt %d\n", i);
else if (t == SEG)
fprintf(stderr,
"CheckVDCell - the error(s) occurred for seg %d\n", i);
else if (t == ARC)
fprintf(stderr,
"CheckVDCell - the error(s) occurred for seg %d\n", i);
else {
fprintf(stderr,
"CheckVDCell - the error(s) occurred for site %d ", i);
fprintf(stderr,
"of unknown type\n");
}
}
return success;
}
#endif
vr_bool vroniObject::CheckVD(vr_bool arcs_recovered)
{
#ifdef GRAPHICS
int i, e;
vr_bool success = true;
for (i = 0; i < num_pnts; ++i) {
if (pnts[i].draw && !IsDeletedPnt(i)) {
e = GetVDPtr(i, PNT);
if ((e == NIL) || IsEdgeDeleted(e)) {
AddToCurBuffer(i, PNT, AlertColor);
fprintf(stderr, "CheckVDCell - pnt %d has no VD edge!\n", i);
success = false;
}
else {
if (!CheckVDCell(i, e, PNT, arcs_recovered)) {
AddToCurBuffer(i, PNT, AlertColor);
success = false;
}
}
}
}
for (i = 0; i < num_segs; ++i) {
if (segs[i].draw) {
e = GetVDPtr(i, SEG);
if ((e == NIL) || IsEdgeDeleted(e)) {
AddToCurBuffer(i, SEG, AlertColor);
fprintf(stderr, "CheckVDCell - seg %d has no VD edge!\n", i);
success = false;
}
else {
if (!CheckVDCell(i, e, SEG, arcs_recovered)) {
AddToCurBuffer(i, SEG, AlertColor);
success = false;
}
}
}
}
for (i = 0; i < num_arcs; ++i) {
if (arcs[i].draw) {
e = GetVDPtr(i, ARC);
if ((e == NIL) || IsEdgeDeleted(e)) {
AddToCurBuffer(i, ARC, AlertColor);
fprintf(stderr, "CheckVDCell - arc %d has no VD edge!\n", i);
success = false;
}
else {
if (!CheckVDCell(i, e, ARC, arcs_recovered)) {
AddToCurBuffer(i, ARC, AlertColor);
success = false;
}
}
}
}
#ifdef VR_TRACE
if (proto) {
for (i = 0; i < num_edges; ++i) {
if (! IsEdgeDeleted(i) ) {
printf("edges[%2d] - lft = %2d, rgt = %2d, start = %2d, end = %2d, ltyp = %1d, rtyp = %1d\n",
i, edges[i].lft, edges[i].rgt, edges[i].n1, edges[i].n2,
edges[i].ltype, edges[i].rtype);
printf(" s_ccw = %2d, s_cw = %2d, e_ccw = %2d, e_cw = %2d\n",
edges[i].s_ccw, edges[i].s_cw, edges[i].e_ccw, edges[i].e_cw);
}
else {
printf("edges[%2d] - deleted!\n", i);
}
}
for (i = 0; i < num_nodes; ++i) {
if (!((nodes[i].status == DELETED) || (nodes[i].status == MISC))) {
printf("nodes[%2d] - (%f,%f)\n", i, nodes[i].p.x, nodes[i].p.y);
}
else {
printf("nodes[%2d] - deleted!\n", i);
}
}
}
#endif
#ifdef VRONI_WARN
if (!success && verbose) {
printf("\nnum_pnts = %d; num_segs = %d; num_arcs = %d\n", num_pnts,
num_segs, num_arcs);
}
#endif
return success;
#else
arcs_recovered = false;
return true;
#endif
}
void vroniObject::InsertDummyNode(int e, int n, vr_bool store)
{
int i1, i2, n2, e1, e0;
t_site t1, t2;
GetLftSiteData(e, &i1, &t1);
GetRgtSiteData(e, &i2, &t2);
n2 = GetEndNode(e);
e1 = StoreEdge(n, n2, i1, i2, t1, t2);
#ifdef VR_TRACE
if (center) {
printf("InsertDummyNode - edge e = %d, new edge e1 = %d, ", e, e1);
printf("endnode = %d, new node n = %d\n", n2, n);
}
#endif
SetIncidentEdge(n, e);
if (GetIncidentEdge(n2) == e) SetIncidentEdge(n2, e1);
e0 = GetCCWEdge(e, n2);
SetCCWEdge(e1, n2, e0);
SetCWEdge(e0, n2, e1);
e0 = GetCWEdge(e, n2);
SetCWEdge(e1, n2, e0);
SetCCWEdge(e0, n2, e1);
SetEndNode(e, n);
SetCWEdge(e, n, e1);
SetCCWEdge(e, n, e1);
SetCWEdge(e1, n, e);
SetCCWEdge(e1, n, e);
if (store) {
if (num_dummies >= max_num_dummies) {
max_num_dummies += MINI;
dummies = (dummy_node*) ReallocateArray(dummies, max_num_dummies,
sizeof(dummy_node),
"vd:dummies");
}
dummies[num_dummies].e1 = e;
dummies[num_dummies].e2 = e1;
dummies[num_dummies].n = n;
++num_dummies;
MarkNodeDummy(n);
}
SetNodeDegree(n, true);
ExtApplInsertDummyNode; /* let the user add user-specific code */
return;
}
void vroniObject::DeleteDummyNodes(void)
{
int e1, e2, n, e, i, n2, j;
t_site t;
for (j = 0; j < num_dummies; ++j) {
e1 = dummies[j].e1;
e2 = dummies[j].e2;
n = dummies[j].n;
assert(IsNodeDummy(n));
if (GetStartNode(e1) == n) {
VroniSwap(e1, e2, e);
}
assert(GetEndNode(e1) == n);
assert(GetStartNode(e2) == n);
assert(GetCCWEdge(e1, n) == e2);
assert(GetCWEdge(e1, n) == e2);
assert(GetCCWEdge(e2, n) == e1);
assert(GetCWEdge(e2, n) == e1);
n2 = GetEndNode(e2);
SetEndNode(e1, n2);
if (GetIncidentEdge(n2) == e2) SetIncidentEdge(n2, e1);
e = GetCCWEdge(e2, n2);
SetCCWEdge(e1, n2, e);
SetCWEdge(e, n2, e1);
e = GetCWEdge(e2, n2);
SetCWEdge(e1, n2, e);
SetCCWEdge(e, n2, e1);
GetLftSiteData(e2, &i, &t);
SetVDPtr(i, t, e1);
GetRgtSiteData(e2, &i, &t);
SetVDPtr(i, t, e1);
DeleteNode(n);
DeleteEdge(e2);
}
num_dummies = 0;
return;
}
void vroniObject::TakeSquareOfNodes(void)
{
int i;
for (i = 0; i < num_nodes; ++i) {
assert(nodes[i].r2 >= 0.0);
nodes[i].r2 = sqrt(nodes[i].r2);
}
SetNodesSqdFlag();
return;
}
void vroniObject::PrintNodeData(int n, const char *string)
{
assert(InNodesList(n));
FP_printf("%s, node %d: (%24.20f,%24.20f), radius = %24.20f\n",
string, n, FP_PRNTARG(nodes[n].p.x), FP_PRNTARG(nodes[n].p.y), FP_PRNTARG(nodes[n].r2));
switch(nodes[n].status) {
case(UNCHECKED):
printf(" status UNCHECKED, ");
break;
case(CHECKED):
printf(" status CHECKED, ");
break;
case(DELETED):
printf(" status DELETED, ");
break;
case(VISITED):
printf(" status VISITED, ");
break;
case(DUMMY):
printf(" status DUMMY, ");
break;
case(MISC):
printf(" status MISC, ");
break;
default:
printf(" status Unknown!, ");
break;
}
printf("edge: %d, site: %d, ", nodes[n].edge, nodes[n].site);
if (nodes[n].deg2) printf("degree-2 node.\n");
else printf("degree-3 node.\n");
fflush(stdout);
return;
}
void vroniObject::PrintEdgeData(int e, const char *string)
{
assert(InEdgesList(e));
printf("%s, edge %d: n1=%d, n2=%d\n",
string, e, edges[e].n1, edges[e].n2);
FP_printf("n1: (%f, %f); n2: (%f, %f)\n",
FP_PRNTARG(nodes[edges[e].n1].p.x), FP_PRNTARG(nodes[edges[e].n1].p.y),
FP_PRNTARG(nodes[edges[e].n2].p.x), FP_PRNTARG(nodes[edges[e].n2].p.y));
printf(" lft = %d, rgt = %d, ltype = %d, rtype = %d\n",
edges[e].lft, edges[e].rgt, edges[e].ltype, edges[e].rtype);
printf(" s_ccw = %d, s_cw = %d, e_ccw = %d, e_cw = %d",
edges[e].s_ccw, edges[e].s_cw, edges[e].e_ccw, edges[e].e_cw);
if ( IsEdgeDeleted(e) ) printf(", deleted.\n");
else printf(".\n");
fflush(stdout);
return;
}
void vroniObject::PrintVDData(const char *string)
{
int n, e;
printf("\nVD data printed from within %s:\n", string);
for (n = 4; n < num_nodes; ++n) PrintNodeData(n, string);
for (e = 0; e < num_edges; ++e) PrintEdgeData(e, string);
return;
}
inline double vroniObject::ClassifySolSite(int i, t_site i_type,
coord c, double r)
{
if (i_type == PNT)
return ClassifySolPnt(i, c, r);
else if (i_type == SEG)
return ClassifySolSeg(i, c, r);
else
return ClassifySolArc(i, c, r);
}
int vroniObject::ClassifySolutions(int i, int j, int k, int e,
t_site i_type, t_site j_type,
t_site k_type, vr_bool i_is_old,
vr_bool j_is_old, vr_bool k_is_old,
coord *centers, double *radii,
int *num_sol, double eps,
vr_bool *problematic)
{
int m, m1, n1, n2, best_sol, new_site;
t_site new_site_type;
double best_qual, qual;
coord c, old_node, sv, ev, p;
vr_bool check_sidedness = false;
double seg_a, seg_b, seg_c, seg_l;
double ai = 0.0, bi = 0.0, ci = 0.0, ri = 0.0;
coord q1, q2, q3, sp, ep, arc_c, pi;
double r1, r2;
int i1, i2, i3;
t_site t1, t2, t3;
double d1, d2, d3, d4, rad1, rad2;
double cs1, cs2, cs3;
double r;
assert((*num_sol+2) < VRONI_MAXSOL);
*problematic = false;
/* */
/* Get start and end nodes (and their coordinates) of edge */
/* */
n1 = GetStartNode(e);
n2 = GetEndNode(e);
GetNodeData(n1, &q1, &r1);
GetNodeData(n2, &q2, &r2);
if (r1 > r2) {
rad1 = r2;
rad2 = r1;
q3 = q1;
}
else {
rad1 = r1;
rad2 = r2;
q3 = q2;
}
/* */
/* get the defining sites of this VD edge */
/* */
GetLftSiteData(e, &i1, &t1);
GetRgtSiteData(e, &i2, &t2);
if (t1 == PNT) {
i3 = i1;
t3 = t1;
}
else {
i3 = i2;
t3 = t2;
}
if (t3 == PNT) {
pi = GetPntCoords(i3);
}
else if (t3 == SEG) {
GetSegEqnData(i3, &ai, &bi, &ci);
}
else {
assert(t3 == ARC);
pi = GetArcCenter(i3);
ri = GetArcRadius(i3);
}
/* */
/* add old nodes as potential candidates for a center */
/* */
centers[*num_sol] = q1;
radii[*num_sol] = r1;
++(*num_sol);
centers[*num_sol] = q2;
radii[*num_sol] = r2;
++(*num_sol);
if (IsNodeDeleted(n1)) old_node = q2; /* old node that is not deleted */
else old_node = q1; /* old node that is not deleted */
d1 = PntPntDist(q1, q2);
if (le(d1, eps)) {
/* */
/* if the old bisector edge is tiny then we simply return the old node */
/* */
if (IsNodeDeleted(n1)) return (*num_sol-1);
else return (*num_sol-2);
}
/* */
/* get newly inserted site */
/* */
if (!i_is_old) {
new_site = i;
new_site_type = i_type;
}
else if (!j_is_old) {
new_site = j;
new_site_type = i_type;
}
else {
assert(!k_is_old);
new_site = k;
new_site_type = k_type;
}
/* */
/* check whether the old node lies within the cone of influence of the */
/* new site */
/* */
if (new_site_type == SEG) {
GetSegEqnData(new_site, &seg_a, &seg_b, &seg_c);
seg_l = GetSegLgth(new_site);
sp = GetSegStartCoord(new_site);
ep = GetSegEndCoord(new_site);
check_sidedness =
(IsInSegCone(sp, old_node, seg_a, seg_b, seg_l) == 0);
}
else if (new_site_type == ARC) {
arc_c = GetArcCenter(new_site);
sp = GetArcStartCoord(new_site);
sv = VecSub(sp, arc_c);
ep = GetArcEndCoord(new_site);
ev = VecSub(ep, arc_c);
p = VecSub(old_node, arc_c);
check_sidedness = (IsInArcCone(sv, ev, p) == 0);
}
best_sol = NIL;
best_qual = LARGE;
/* */
/* classify the solutions relative to the old VD edge, the radii of */
/* the old VD nodes, and relative to the input sites */
/* */
m1 = *num_sol - 3;
for (m = 0; m < *num_sol; ++m) {
c = centers[m];
r = radii[m];
if ((r < too_large) || (best_qual > r)) {
/* */
/* carry out checks only if a better solution might be found */
/* */
if (r > too_large) qual = r;
else qual = 0.0;
/* node-edge classification: check whether the new node is in the */
/* cones/strips defined by the old nodes */
/* */
d1 = PntSiteConeClassificator(i1, t1, q2, q1, c, eps);
d1 = Abs(d1);
d2 = PntSiteConeClassificator(i2, t2, q1, q2, c, eps);
d2 = Abs(d2);
/* */
/* check whether the new node is on the same side of i1 and i2 */
/* as the old nodes */
/* */
if (gt(rad2, ZERO)) {
if (t1 != PNT) d3 = NodeSidednessClassificator(i1, t1, q3, c);
else d3 = 0.0;
if (t2 != PNT) d4 = NodeSidednessClassificator(i2, t2, q3, c);
else d4 = 0.0;
}
else {
d3 = d4 = 0.0;
}
#ifdef TRACE
printf("e = %d, i1/t1 = %d/%d, i2/t2 = %d/%d\n", e, i1, t1, i2, t2);
printf("q1 = (%20.16f %20.16f)\n", q1.x, q1.y);
printf("q2 = (%20.16f %20.16f)\n", q2.x, q2.y);
printf("p = (%20.16f %20.16f)\n", p.x, p.y);
printf("d1 = %20.16f, d2 = %20.16f\n", d1, d2);
printf("d3 = %20.16f, d4 = %20.16f\n", d3, d4);
#endif
qual += Max4(d1, d2, d3, d4);
/* */
/* node-sidedness classification */
/* */
if (check_sidedness)
qual += NodeSidednessClassificator(new_site, new_site_type,
old_node, c);
#ifdef VR_TRACE
if ((i == 4) && (j == 2) && (k == 2)) {
printf("q1 = (%20.16f %20.16f)\n", q1.x, q1.y);
printf("q2 = (%20.16f %20.16f)\n", q2.x, q2.y);
printf("c = (%20.16f %20.16f)\n", c.x, c.y);
printf("d1 = %20.16f, d2 = %20.16f\n", d1, d2);
printf("d3 = %20.16f, d4 = %20.16f\n", d3, d4);
}
#endif
/* */
/* node-site classification */
/* */
/*
qual +=
ClassifySolSite(i, i_type, c, r) +
ClassifySolSite(j, j_type, c, r) +
ClassifySolSite(k, k_type, c, r);
*/
cs1 = ClassifySolSite(i, i_type, c, r);
cs2 = ClassifySolSite(j, j_type, c, r);
cs3 = ClassifySolSite(k, k_type, c, r);
qual += Max3(cs1, cs2, cs3);
/* */
/* node-radii classification */
/* */
if (t3 == PNT) d1 = PntPntDist(c, pi);
else if (t3 == SEG) d1 = AbsPntLineDist(ai, bi, ci, c);
else d1 = AbsPntCircleDist(pi, ri, c);
if (d1 < rad1) qual += rad1 - d1;
else if (d1 > rad2) qual += d1 - rad2;
if (qual < best_qual) {
best_qual = qual;
best_sol = m;
}
#ifdef VR_TRACE
if ((i == 6) && (j == 10) && (k == 11)) {
printf("pot sol[%d] (2): (%20.16f, %20.16f)\nr=%20.16f, q=%20.16f\n",
m, centers[m].x, centers[m].y, radii[m], qualities[m]);
}
#endif
}
if ((m == m1) && le(best_qual, DECENT)) break;
}
if (gt(best_qual, GRAZE)) *problematic = true;
#ifdef VRONI_INFO
UpdateRelaxationMemory(VroniMax(eps, best_qual));
#endif
return best_sol;
}
/* */
/* intersects the ray originating at pnts[i1], with direction vector v, */
/* with the bisector e. note that e is defined by i1 and by one other */
/* site. if an intersection is found then it computes the intersection point */
/* w and returns true. */
/* */
/* note: we assume that v is a unit vector! */
/* */
vr_bool vroniObject::IntersectRayBisector(int i1, const coord & v, int e,
coord *w, double *r2)
{
int i2, j;
t_site t2;
double t, lgth, a, b, c;
coord p, q, u;
double radii[16], rr, qual1, qual2;
coord centers[16], cc;
#ifdef GENUINE_ARCS
double rr2;
#endif
int numsol;
assert(InPntsList(i1));
assert(InEdgesList(e));
assert(IsLftSite(e, i1, PNT) || IsRgtSite(e, i1, PNT));
assert(eq(VecLen(v) - 1.0, ZERO));
if (IsLftSite(e, i1, PNT)) {GetRgtSiteData(e, &i2, &t2);}
else {GetLftSiteData(e, &i2, &t2);}
p = GetPntCoords(i1);
switch(t2) {
case(PNT):
assert(InPntsList(i2));
q = GetPntCoords(i2);
u = VecSub(q, p);
lgth = VecLenSq(u);
t = VecDotProd(u, v);
if (!eq(t, ZERO)) {
t = lgth / (2.0 * t);
if (ge(t, ZERO)) {
*w = RayPnt(p, v, t);
*r2 = Abs(t);
return true;
}
}
return false;
case(SEG):
assert(InSegsList(i2));
if (IsSegStartPnt(i2, i1) || IsSegEndPnt(i2, i1)) {
*w = p;
*r2 = 0.0;
return true;
}
GetSegEqnData(i2, &a, &b, &c);
if (!IntersectRayOffsetSeg(p, v, a, b, c, 1, 1, centers, radii,
&numsol)) {
/* */
/* point i1 is too close to (supporting line of) i2 */
/* */
SetInvalidSites(i1, PNT, i2, SEG, ZERO_MAX);
restart = true;
return false;
}
*r2 = -1.0;
c = VecDotProd(v, p);
//Check solutions
for (j = 0; j < numsol; ++j) {
cc = centers[j];
rr = radii[j];
/* */
/* we are interested in a point which is in CI of seg and in the */
/* positive half-plane defined by the line and which lies on the */
/* old VD edge */
/* */
if (VecDotProd(v, cc) >= c) {
if( *r2 >= 0.0 ) {
qual1 = NodeEdgeClassificator(e, *w, ZERO) +
ClassifySolSite(i1, PNT, *w, *r2) +
ClassifySolSite(i2, SEG, *w, *r2);
qual2 = NodeEdgeClassificator(e, cc, ZERO) +
ClassifySolSite(i1, PNT, cc, rr) +
ClassifySolSite(i2, SEG, cc, rr);
if (qual2 < qual1) {
*r2 = rr;
*w = cc;
}
}
else {
*r2 = rr;
*w = cc;
}
}
}
return (*r2 >= 0.0) ? true : false;
#ifdef GENUINE_ARCS
case(ARC):
assert(InArcsList(i2));
//this is the line orthogonal to v and through the point p.
c = VecDotProd(v, p);
//The arc's circle
q = GetArcCenter(i2);
rr2 = GetArcRadius(i2);
//Get all points equidistant to the circle, point and line
numsol = CircCircSegCenters(q, p, rr2, 0, v.x, v.y, c, centers, radii,
ZERO);
*r2 = -1.0;
//Check solutions
for(j=0; j<numsol; j++) {
cc = centers[j];
rr = radii[j];
/* */
/* we are interested in a point which is in CI of arc and in the */
/* positive half-plane defined by the line and which lies on the */
/* old VD edge */
/* */
if (VecDotProd(v, cc) >= c) {
if ( *r2 >= 0.0 ) {
qual1 = NodeEdgeClassificator(e, *w, ZERO) +
ClassifySolSite(i1, PNT, *w, *r2) +
ClassifySolSite(i2, ARC, *w, *r2);
qual2 = NodeEdgeClassificator(e, cc, ZERO) +
ClassifySolSite(i1, PNT, cc, rr) +
ClassifySolSite(i2, ARC, cc, rr);
if (qual2 < qual1) {
*r2 = rr;
*w = cc;
}
}
else {
*r2 = rr;
*w = cc;
}
}
}
return (*r2 >= 0.0) ? true : false;
#endif
default:
VD_Warning("IntersectRayBisector() - unrecognized site type");
return false;
}
}
#include "ext_appl_vd.cc"