Files
vroni/arc_arc_pnt.cc
T
SaraP 739088af9f Vroni 7.8 :
- aggiornamento versione.
2025-01-29 16:24:30 +01:00

401 lines
17 KiB
C++

/*****************************************************************************/
/* */
/* Copyright (C) 2007-2025 S. Huber, 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: Stefan Huber, 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 <math.h>
#include <float.h>
/* */
/* get my header files */
/* */
#include "vroni_object.h"
#include "vronivector.h"
#include "fpkernel.h"
#include "defs.h"
#include "numerics.h"
#include "roots.h"
/* */
/* Calculate the Voronoi center of two arcs and one point */
/* */
vr_bool vroniObject::ArcArcPntCntr(int i, int j, int k, int e,
coord* cntr, double *r2,
vr_bool *problematic, int* site)
{
int t, n1;
coord c1, c2, c3;
double rr1, rr2, rr3 = 0, rad, d_c1c2;
coord centers[VRONI_MAXSOL];
double radii[VRONI_MAXSOL];
int num_sol = 0, best_sol = NIL, old_num_sol = 0, special_sol = 0;
double eps = ZERO;
coord spi, spj, epj, epi, ep, v;
int i_in, j_in;
vr_bool no_check, is_arc_endpoint, is_special;
vr_bool spi_in_common, epi_in_common, counter_tangential;
coord special_centers[2];
double special_radii[2];
i_in = i;
j_in = j;
*problematic = false;
/* */
/* Guarantee that permutations of i,j lead to same center */
/* */
SortTwoNumbers(i, j, t);
/* */
/* Check whether the three sites are all in lists */
/* */
assert(InArcsList(i));
assert(InArcsList(j));
assert(InPntsList(k));
/* */
/* check whether the two arcs are identical. */
/* */
if (i == j) {
VD_Dbg_Warning("ArcArcPntCntr() - the same arc!");
return false;
}
n1 = Get1stVtx(i, ARC);
if (IsArcStartPnt(j, n1) || IsArcEndPnt(j, n1)) {
n1 = Get2ndVtx(i, ARC);
if (IsArcStartPnt(j, n1) || IsArcEndPnt(j, n1)) {
if (le(PntPntDist(GetArcCenter(i),GetArcCenter(j)),
GetIntersectionThreshold())) {
SetInvalidSites(i, ARC, j, ARC, GetIntersectionThreshold());
restart = false;
return false; /* duplicate arcs ! */
}
}
}
/* */
/* check whether the point pnts[k] is an endpoint of arcs[i] and */
/* arcs[j]. */
/* */
if ((IsArcStartPnt(i,k) || IsArcEndPnt(i,k)) &&
(IsArcStartPnt(j,k) || IsArcEndPnt(j,k))) {
/* */
/* pnt k is a common end-point of i and j. */
/* */
// printf("Point %d splits arc %d and arc %d\n", k, i, j);
*cntr = GetPntCoords(k);
*r2 = 0.0;
*site = k;
return true;
}
rr1 = GetArcRadius(i);
rr2 = GetArcRadius(j);
rr3 = 0.0;
if (rr2 > rr1) {
/* */
/* make sure that first arc has the larger radius */
/* */
double tmpr;
VroniSwap(rr1, rr2, tmpr);
VroniSwap(i, j, t);
}
c1 = GetArcCenter(i);
c2 = GetArcCenter(j);
c3 = GetPntCoords(k);
if (IsArcStartPnt(i,k) || IsArcEndPnt(i,k)) {
v = VecSub(c1, c3);
old_num_sol = IntersectRayCircle(c3, v, c2, rr2, centers, radii, ZERO);
is_arc_endpoint = true;
}
else if (IsArcStartPnt(j,k) || IsArcEndPnt(j,k)) {
v = VecSub(c2, c3);
old_num_sol = IntersectRayCircle(c3, v, c1, rr1, centers, radii, ZERO);
is_arc_endpoint = true;
}
else {
is_arc_endpoint = false;
}
d_c1c2 = PntPntDist(c1,c2);
spi = GetArcStartCoord(i);
spj = GetArcStartCoord(j);
epj = GetArcEndCoord(j);
epi = GetArcEndCoord(i);
while (eps <= ZERO_MAX) {
no_check = false;
is_special = false;
num_sol = old_num_sol;
special_sol = 0;
#ifdef TRACE
if ((e == 15) && (i_in == 5)) {
printf("\narc%d-arc%d-pnt%d: (%20.16f, %20.16f; %20.16f), (%20.16f, %20.16f; %20.16f), (%20.16f, %20.16f)\n", i, j, k, c1.x, c1.y, rr1, c2.x, c2.y, rr2, c3.x, c3.y);
printf("is_arc_endpoint = %d\n", is_arc_endpoint);
}
if ((i_in == 0) && (k == 6)) {
printf("\narc%d-arc%d-pnt%d: (%20.16f, %20.16f; %20.16f), (%20.16f, %20.16f; %20.16f), (%20.16f, %20.16f)\n", i, j, k, c1.x, c1.y, rr1, c2.x, c2.y, rr2, c3.x, c3.y);
printf("is_arc_endpoint = %d\n", is_arc_endpoint);
}
#endif
if (!is_arc_endpoint) {
counter_tangential = ((VecDet(c1,c2,spi) + VecDet(c1,c2,epi)) *
(VecDet(c1,c2,spj) + VecDet(c1,c2,epj)) <= eps);
if (DoArcPntIntersect(i_in, c3, eps)) {
/* */
/* pnt c3 is on arc i_in */
/* */
VD_Dbg_Warning("ArcArcPntCntr() - point lies in interior of arc!");
SetInvalidSites(i_in, ARC, k, PNT, eps);
restart = false;
return false;
}
/* */
/* check whether one endpoint of arc i is very close to one */
/* endpoint of arc j */
/* */
if ((PntPntDist(spi,spj) <= eps) || (PntPntDist(spi,epj) <= eps)) {
spi_in_common = true;
epi_in_common = false;
}
else if ((PntPntDist(epi,spj) <= eps) || (PntPntDist(epi,epj) <= eps)) {
spi_in_common = false;
epi_in_common = true;
}
else {
spi_in_common = false;
epi_in_common = false;
}
if (spi_in_common || epi_in_common) {
/* */
/* one endpoint of arc i is very close to one endpoint of j */
/* */
if (counter_tangential &&
(Abs(d_c1c2 - Abs(rr1-rr2)) <= eps)) {
/* */
/* the arcs are (nearly) tangential */
/* */
//printf("\ttwo tangential arcs %d-%d and pnt %d\n", i, j, k);
is_special = true;
n1 = GetStartNode(e);
if (!IsNodeDeleted(n1)) n1 = GetEndNode(e);
GetNodeData(n1, &v, &rad);
num_sol = 1;
centers[0] = v;
radii[0] = rad;
if (!IsNodeDeleted(n1)) {
/* */
/* get start point and direction of the ray on which the */
/* bisector lies */
/* */
num_sol = 0;
if (spi_in_common) ep = spi;
else ep = epi;
v = VecSub(ep, c1);
num_sol = IntersectRayCircle(ep, v, c3, rr3, centers, radii,
eps);
}
else {
no_check = true;
}
}
else if (counter_tangential && (Abs(rr1+rr2 - d_c1c2) <= eps)) {
/* */
/* the arcs are counter-tangential and lie on different sides */
/* of the line through their centers */
/* */
is_special = true;
//printf("\ttwo counter-tangential circles (%d-%d-%d)\n", i, j ,k);
/* */
/* get start point and direction of the ray on which the */
/* bisector lies */
/* */
if (spi_in_common) ep = spi;
else ep = epi;
v = VecSub(ep, c1);
num_sol = IntersectRayCircle(ep, v, c3, rr3, centers, radii,
eps);
}
}
else if ((d_c1c2 <= eps) && (Abs(rr1-rr2) <= eps)) {
/* */
/* the arcs lie (nearly) on the same circle but do not share an */
/* end point: their common center is the only possible VD node */
/* */
//printf("\tspecial case: cocircular disjoint circles: %d-%d-%d\n", i, j ,k);
is_special = true;
centers[0] = MidPoint(c1, c2);
radii[0] = (rr1 + rr2) / 2.0;
num_sol = 1;
}
else if (counter_tangential && (Abs(rr1+rr2 - d_c1c2) <= eps)) {
/* */
/* the arcs are counter-tangential but do not share an endpoint: */
/* check whether one end point lies on line through centers */
/* */
if (eq(VecDet(c1,c2,spi), eps) || eq(VecDet(c1,c2,epi), eps) ||
eq(VecDet(c1,c2,spj), eps) || eq(VecDet(c1,c2,epj), eps)) {
if (CouldBeFine(eps, c1, rr1, c3, rr3)) {
special_centers[special_sol] = c1;
special_radii[special_sol] = rr1;
++special_sol;
}
if (CouldBeFine(eps, c2, rr2, c3, rr3)) {
special_centers[special_sol] = c2;
special_radii[special_sol] = rr2;
++special_sol;
}
}
}
if (!is_special) {
/* */
/* and finally the general case... */
/* */
//printf("ordinary\n");
num_sol = CircCircCircCenters(c1, c2, c3, rr1, rr2, rr3, centers,
radii, eps);
if (special_sol == 2) {
centers[num_sol] = special_centers[1];
radii[num_sol] = special_radii[1];
--special_sol;
++num_sol;
}
if (special_sol == 1) {
centers[num_sol] = special_centers[0];
radii[num_sol] = special_radii[0];
--special_sol;
++num_sol;
}
}
}
if ((num_sol > 0) && no_check)
best_sol = 0;
else
/* */
/* classify all solutions and pick the best solution */
/* */
best_sol = ClassifySolutions(i_in, j_in, k, e, ARC, ARC, PNT,
false, true, true, centers, radii,
&num_sol, eps, problematic);
assert((0 <= best_sol) && (best_sol < num_sol));
if (!*problematic) {
*cntr = centers[best_sol];
*r2 = radii[best_sol];
return true;
}
else {
eps *= 10.0;
}
}
if (eq(GetArcRadius(i), ZERO_MAX)) {
/* */
/* this is an arc with a very small radius; we replace it */
/* by a seg */
/* */
VD_Dbg_Warning("ArcArcPntCntr() - arc with small radius!");
ReplaceArc(i);
restart = true;
return false;
}
else if (eq(GetArcRadius(j), ZERO_MAX)) {
/* */
/* this is an arc with a very small radius; we replace it */
/* by a seg */
/* */
VD_Dbg_Warning("ArcArcPntCntr() - arc with small radius!");
ReplaceArc(j);
restart = true;
return false;
}
else if (eq(PntPntDist(GetArcStartCoord(i), GetArcEndCoord(i)), ZERO_MAX)) {
/* */
/* this is an arc with a very short cord; we replace it by a seg */
/* */
VD_Dbg_Warning("ArcArcPntCntr() - arc with short cord!");
ReplaceArc(i);
restart = true;
return false;
}
else if (eq(PntPntDist(GetArcStartCoord(j), GetArcEndCoord(j)), ZERO_MAX)) {
/* */
/* this is an arc with a very short cord; we replace it by a seg */
/* */
VD_Dbg_Warning("ArcArcPntCntr() - arc with short cord!");
ReplaceArc(j);
restart = true;
return false;
}
else if (CheckIntersectionsLocally(i, ARC, j, ARC, k, PNT)) {
restart = true;
return false;
}
#ifdef VRONI_DBG_WARN
spi = GetArcStartCoord(i);
spj = GetArcStartCoord(j);
epj = GetArcEndCoord(j);
epi = GetArcEndCoord(i);
c1 = GetArcCenter(i);
c2 = GetArcCenter(j);
printf("\nCenter not computed for arc-arc-pnt: %d-%d-%d\n", i, j, k);
printf("%20.16f %20.16f %20.16f %20.16f %20.16f %20.16f\n",
spi.x, spi.y, epi.x, epi.y, c1.x, c1.y);
printf("%20.16f %20.16f %20.16f %20.16f %20.16f %20.16f\n",
spj.x, spj.y, epj.x, epj.y, c2.x, c2.y);
c3 = GetPntCoords(k);
printf("%20.16f %20.16f\n", c3.x, c3.y);
#endif
*cntr = centers[best_sol];
*r2 = radii[best_sol];
restart = false;
return false;
}