739088af9f
- aggiornamento versione.
308 lines
13 KiB
C++
308 lines
13 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 "fpkernel.h"
|
|
#include "vronivector.h"
|
|
#include "vroni_object.h"
|
|
#include "defs.h"
|
|
#include "numerics.h"
|
|
#include "roots.h"
|
|
|
|
|
|
|
|
/* */
|
|
/* computes the center cntr and the radius r2 of the circle tangential */
|
|
/* to the arct arcs[i] and passing through the points pnts[j],pnts[k]. */
|
|
/* it returns false if the radius is too large to be computed numerically, */
|
|
/* or if it is obvious that problems have occurred. if two centers exist */
|
|
/* then we choose the center that lies on the Voronoi edge e. the vr_bool */
|
|
/* flag problematic is set if a center was computed but its correctness is */
|
|
/* doubtful. */
|
|
/* */
|
|
vr_bool vroniObject::ArcPntPntCntr(int i, int j, int k, int e,
|
|
coord* cntr, double *r2,
|
|
vr_bool *problematic)
|
|
{
|
|
int t;
|
|
coord c1, c2, c3;
|
|
double rr1, rr2, rr3, eps;
|
|
#ifdef VRONI_DBG_WARN
|
|
coord spi, epi;
|
|
#endif
|
|
coord v;
|
|
coord centers[VRONI_MAXSOL];
|
|
double radii[VRONI_MAXSOL];
|
|
vr_bool j_on_i = false;
|
|
int num_sol = 0, best_sol = NIL, cocirc = 0;
|
|
double dist2, dist3;
|
|
double sign = 1.0;
|
|
|
|
assert(InArcsList(i));
|
|
assert(InPntsList(j));
|
|
assert(InPntsList(k));
|
|
*problematic = false;
|
|
|
|
/* */
|
|
/* check whether the two points are identical. */
|
|
/* */
|
|
if (j == k) {
|
|
VD_Dbg_Warning("ArcPntPntCntr() - two identical points!");
|
|
return false;
|
|
}
|
|
|
|
/* */
|
|
/* we sort the two point indices in order to guarantee that the center of */
|
|
/* these three sites is always computed consistently. */
|
|
/* */
|
|
SortTwoNumbers(j, k, t);
|
|
|
|
c1 = GetArcCenter(i);
|
|
rr1 = GetArcRadius(i);
|
|
rr2 = 0.0;
|
|
rr3 = 0.0;
|
|
|
|
/* */
|
|
/* check whether one of the points is an endpoint of arcs[i]. */
|
|
/* */
|
|
if (IsArcStartPnt(i, k) || IsArcEndPnt(i, k)) VroniSwap(j, k, t);
|
|
c2 = GetPntCoords(j);
|
|
c3 = GetPntCoords(k);
|
|
if (IsArcStartPnt(i, j) || IsArcEndPnt(i, j)) {
|
|
if (IsArcStartPnt(i, k) || IsArcEndPnt(i, k)) {
|
|
/* */
|
|
/* both points are endpoints of the arc */
|
|
/* */
|
|
*cntr = c1;
|
|
*r2 = rr1;
|
|
return true;
|
|
}
|
|
else {
|
|
dist2 = 0.0;
|
|
dist3 = PntPntDist(c1,c3) - rr1;
|
|
j_on_i = true;
|
|
}
|
|
}
|
|
else {
|
|
dist2 = PntPntDist(c1,c2) - rr1;
|
|
dist3 = PntPntDist(c1,c3) - rr1;
|
|
}
|
|
|
|
eps = ZERO;
|
|
|
|
#ifdef TRACE
|
|
if ((e == 107) && (i == 6)) { printf("arc%d-pnt%d-pnt%d: \n(%20.16f, %20.16f) %20.16f;\n%d:(%20.16f, %20.16f);\n%d:(%20.16f, %20.16f)\n", i, j, k, c1.x, c1.y, rr1, j, c2.x, c2.y, k, c3.x, c3.y);
|
|
if (IsArcStartPnt(i, j)) printf("%d is start of arc %d\n", j, i);
|
|
if (IsArcEndPnt(i, j)) printf("%d is end of arc %d\n", j, i);
|
|
if (IsArcStartPnt(i, k)) printf("%d is start of arc %d\n", k, i);
|
|
if (IsArcEndPnt(i, k)) printf("%d is end of arc %d\n", k, i);
|
|
spi = GetArcStartCoord(i);
|
|
epi = GetArcEndCoord(i);
|
|
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);
|
|
}
|
|
#endif
|
|
|
|
while (eps <= ZERO_MAX) {
|
|
|
|
cocirc = 0;
|
|
num_sol = 0;
|
|
|
|
if (eq(dist2, eps)) {
|
|
if (!j_on_i && DoArcPntIntersect(i, c2, eps)) {
|
|
/* */
|
|
/* c2 is inside of CI of i and on i */
|
|
/* */
|
|
VD_Dbg_Warning("ArcPntPntCntr() - point lies in interior of arc!");
|
|
SetInvalidSites(i, ARC, j, PNT, eps);
|
|
restart = false;
|
|
return false;
|
|
}
|
|
cocirc = 1;
|
|
}
|
|
|
|
if (eq(dist3, eps)) {
|
|
if (DoArcPntIntersect(i, c3, eps)) {
|
|
/* */
|
|
/* c3 is inside of CI of i and on i */
|
|
/* */
|
|
VD_Dbg_Warning("ArcPntPntCntr() - point lies in interior of arc!");
|
|
SetInvalidSites(i, ARC, k, PNT, eps);
|
|
restart = false;
|
|
return false;
|
|
}
|
|
++cocirc;
|
|
}
|
|
|
|
if (cocirc == 2) {
|
|
/* */
|
|
/* the two points lie on the same circle as i */
|
|
/* */
|
|
centers[0] = c1;
|
|
radii[0] = rr1;
|
|
num_sol = 1;
|
|
}
|
|
else if (j_on_i) {
|
|
/* */
|
|
/* point j is on arc */
|
|
/* */
|
|
v = VecSub(c2, c1);
|
|
num_sol = IntersectRayPoint(c2, v, c3, centers, radii, eps);
|
|
}
|
|
else {
|
|
/* */
|
|
/* standard case: find solution that is equidistant to three */
|
|
/* (degenerate) circles. */
|
|
/* */
|
|
if (dist2 <= -eps) {
|
|
sign = -1.0;
|
|
#ifdef VRONI_WARN
|
|
if (dist3 > eps) {
|
|
VD_Warning("ArcPntPntCntr() - sign mismatch!");
|
|
coord spi, epi;
|
|
spi = GetArcStartCoord(i);
|
|
epi = GetArcEndCoord(i);
|
|
c1 = GetArcCenter(i);
|
|
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);
|
|
c2 = GetPntCoords(j);
|
|
printf("%20.16f %20.16f\n", c2.x, c2.y);
|
|
c3 = GetPntCoords(k);
|
|
printf("%20.16f %20.16f\n", c3.x, c3.y);
|
|
printf("dist2 = %20.16f\n", dist2);
|
|
printf("dist3 = %20.16f\n", dist3);
|
|
printf("eps = %20.16f\n", eps);
|
|
}
|
|
#endif
|
|
}
|
|
else if (dist2 >= eps) {
|
|
sign = 1.0;
|
|
#ifdef VRONI_WARN
|
|
if (dist3 < -eps) {
|
|
VD_Warning("ArcPntPntCntr() - sign mismatch!");
|
|
coord spi, epi;
|
|
spi = GetArcStartCoord(i);
|
|
epi = GetArcEndCoord(i);
|
|
c1 = GetArcCenter(i);
|
|
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);
|
|
c2 = GetPntCoords(j);
|
|
printf("%20.16f %20.16f\n", c2.x, c2.y);
|
|
c3 = GetPntCoords(k);
|
|
printf("%20.16f %20.16f\n", c3.x, c3.y);
|
|
printf("dist2 = %20.16f\n", dist2);
|
|
printf("dist3 = %20.16f\n", dist3);
|
|
printf("eps = %20.16f\n", eps);
|
|
printf("checking for containment\n");
|
|
printf("c3 on circle: %d\n", DoArcPntIntersect(i, c3, eps));
|
|
}
|
|
#endif
|
|
}
|
|
else {
|
|
sign = Sign(dist3);
|
|
}
|
|
num_sol = CircPntPntCenters(c1, c2, c3, rr1, sign, centers, radii);
|
|
if (num_sol == 0)
|
|
num_sol = CircCircCircCenters(c1, c2, c3, rr1, rr2, rr3, centers,
|
|
radii, eps);
|
|
}
|
|
|
|
/* */
|
|
/* classify all solutions and pick the best solution */
|
|
/* */
|
|
best_sol = ClassifySolutions(i, j, k, e, ARC, PNT, 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(rr1, ZERO_MAX)) {
|
|
/* */
|
|
/* this is an arc with a very small radius; we replace it by a seg */
|
|
/* */
|
|
VD_Dbg_Warning("ArcPntPntCntr() - arc with small radius!");
|
|
ReplaceArc(i);
|
|
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("ArcPntPntCntr() - arc with short cord!");
|
|
ReplaceArc(i);
|
|
restart = true;
|
|
return false;
|
|
}
|
|
else if (eq(PntPntDist(c2,c3), ZERO_MAX)) {
|
|
/* */
|
|
/* both points are very close to each other. */
|
|
/* */
|
|
VD_Dbg_Warning("ArcPntPntCntr() - points are too close!");
|
|
SetInvalidSites(j, PNT, k, PNT, ZERO_MAX);
|
|
restart = false;
|
|
return false;
|
|
}
|
|
|
|
#ifdef VRONI_DBG_WARN
|
|
spi = GetArcStartCoord(i);
|
|
epi = GetArcEndCoord(i);
|
|
c1 = GetArcCenter(i);
|
|
printf("\nCenter not computed for arc(%d)-pnt(%d)-pnt(%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);
|
|
c2 = GetPntCoords(j);
|
|
printf("%20.16f %20.16f\n", 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;
|
|
}
|
|
|
|
|
|
|