/*****************************************************************************/ /* */ /* 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 #include #include #include #include /* */ /* 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); // MODIF visto che degenera come linea nel codice originale veniva chiamato AddEdgeToBuffer, ma visto // che il parametro non varia linearmente meglio gestirlo come hyperbola AddHyperbolaToBuffer( i, t1, t2, u, v, VDColor) ; 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, ¬_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= 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"