f3e15b8c8d
- aggiunti file della libreria e progetto visual studio.
434 lines
18 KiB
C++
434 lines
18 KiB
C++
/*****************************************************************************/
|
|
/* */
|
|
/* Copyright (C) 2007-2023 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 segment */
|
|
/* */
|
|
vr_bool vroniObject::ArcArcSegCntr(int i, int j, int k, int e,
|
|
coord* cntr, double *r2,
|
|
vr_bool *problematic, int *site)
|
|
{
|
|
int m, n1;
|
|
coord c1, c2;
|
|
double rr1, rr2, t;
|
|
double s1a, s1b, s1c;
|
|
coord centers[VRONI_MAXSOL];
|
|
double radii[VRONI_MAXSOL];
|
|
int num_sol = 0, best_sol = NIL;
|
|
double eps = ZERO;
|
|
coord spi, spj, epj, epi;
|
|
coord ep, sp, v, w;
|
|
vr_bool counter_tangential, no_check, is_special;
|
|
vr_bool spi_in_common, epi_in_common;
|
|
int i_in, j_in, k_in;
|
|
double d_c1c2;
|
|
|
|
i_in = i;
|
|
j_in = j;
|
|
k_in = k;
|
|
|
|
*problematic = false;
|
|
|
|
/* */
|
|
/* Guarantee that permutations of i,j lead to same center */
|
|
/* */
|
|
SortTwoNumbers(i, j, m);
|
|
|
|
/* */
|
|
/* Check whether the three cites are all in lists */
|
|
/* */
|
|
assert(InArcsList(i));
|
|
assert(InArcsList(j));
|
|
assert(InSegsList(k));
|
|
|
|
/* */
|
|
/* check whether the two arcs are identical. */
|
|
/* */
|
|
if (i == j) {
|
|
VD_Dbg_Warning("ArcArcSegCntr() - the same arc!");
|
|
return false;
|
|
}
|
|
m = Get1stVtx(i, ARC);
|
|
if (IsArcStartPnt(j, m) || IsArcEndPnt(j, m)) {
|
|
m = Get2ndVtx(i, ARC);
|
|
if (IsArcStartPnt(j, m) || IsArcEndPnt(j, m)) {
|
|
if (le(PntPntDist(GetArcCenter(i),GetArcCenter(j)),
|
|
GetIntersectionThreshold())) {
|
|
SetInvalidSites(i, ARC, j, ARC, GetIntersectionThreshold());
|
|
restart = false;
|
|
return false; /* duplicate arcs ! */
|
|
}
|
|
}
|
|
}
|
|
|
|
/* */
|
|
/* check whether the three sites share a common end point */
|
|
/* */
|
|
m = Get1stVtx(k, SEG);
|
|
if (IsArcStartPnt(i, m) || IsArcEndPnt(i, m)) {
|
|
if (IsArcStartPnt(j, m) || IsArcEndPnt(j, m)) {
|
|
*cntr = GetPntCoords(m);
|
|
*r2 = 0.0;
|
|
*site = m;
|
|
return true; /* common end point */
|
|
}
|
|
}
|
|
m = Get2ndVtx(k, SEG);
|
|
if (IsArcStartPnt(i, m) || IsArcEndPnt(i, m)) {
|
|
if (IsArcStartPnt(j, m) || IsArcEndPnt(j, m)) {
|
|
*cntr = GetPntCoords(m);
|
|
*r2 = 0.0;
|
|
*site = m;
|
|
return true; /* common end point */
|
|
}
|
|
}
|
|
|
|
c1 = GetArcCenter(i);
|
|
c2 = GetArcCenter(j);
|
|
rr1 = GetArcRadius(i);
|
|
rr2 = GetArcRadius(j);
|
|
spi = GetArcStartCoord(i);
|
|
spj = GetArcStartCoord(j);
|
|
epj = GetArcEndCoord(j);
|
|
epi = GetArcEndCoord(i);
|
|
|
|
GetSegEqnData(k, &s1a, &s1b, &s1c);
|
|
s1c *= -1;
|
|
|
|
d_c1c2 = PntPntDist(c1,c2);
|
|
|
|
//printf(" arc%d-arc%d-seg%d with (%e,%e;%e), (%e,%e;%e), (%e,%e,%e) \n", i, j, k,
|
|
// c1.x, c1.y,rr1, c2.x,c2.y,rr2, s1a,s1b,s1c);
|
|
|
|
|
|
while (eps <= ZERO_MAX) {
|
|
|
|
is_special = false;
|
|
no_check = false;
|
|
num_sol = 0;
|
|
|
|
/* */
|
|
/* check whether one endpoint of arc i is very close to one endpoint */
|
|
/* of 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) {
|
|
counter_tangential = ((VecDet(c1,c2,spi) + VecDet(c1,c2,epi)) *
|
|
(VecDet(c1,c2,spj) + VecDet(c1,c2,epj)) <= eps);
|
|
|
|
if (counter_tangential &&
|
|
(Abs(d_c1c2 - Abs(rr1-rr2)) <= eps)) {
|
|
/* */
|
|
/* the arcs are (nearly) tangential and have a point in common */
|
|
/* */
|
|
//printf("\ttwo tangential arcs %d-%d and seg %d\n", i, j, k);
|
|
n1 = GetStartNode(e);
|
|
if (!IsNodeDeleted(n1)) n1 = GetEndNode(e);
|
|
GetNodeData(n1, &v, &t);
|
|
num_sol = 1;
|
|
centers[0] = v;
|
|
radii[0] = t;
|
|
is_special = true;
|
|
|
|
if (!IsNodeDeleted(n1)) {
|
|
/* */
|
|
/* 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 = IntersectRaySegment(ep, v, s1a, s1b, s1c, centers,
|
|
radii, eps);
|
|
}
|
|
else {
|
|
no_check = true;
|
|
}
|
|
}
|
|
else if (counter_tangential && (Abs(d_c1c2 - rr1-rr2) <= eps)) {
|
|
/* */
|
|
/* the arcs are counter-tangential and lie on different sides */
|
|
/* of the line through their centers */
|
|
/* */
|
|
if (spi_in_common) ep = spi;
|
|
else ep = epi;
|
|
v = VecSub(ep, c1);
|
|
num_sol = IntersectRaySegment(ep, v, s1a, s1b, s1c, centers, radii,
|
|
eps);
|
|
is_special = true;
|
|
}
|
|
}
|
|
|
|
if (!is_special) {
|
|
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 */
|
|
/* */
|
|
centers[0] = MidPoint(c1, c2);
|
|
radii[0] = (rr1 + rr2) / 2.0;
|
|
num_sol = 1;
|
|
is_special = true;
|
|
}
|
|
else if (Abs(Abs(c1.x*s1a+c1.y*s1b-s1c)-rr1) <= eps) {
|
|
/* */
|
|
/* the arc and the line are tangential. check whether they */
|
|
/* share an end point */
|
|
/* */
|
|
counter_tangential = true;
|
|
if (PntPntDist(spi,GetSegStartCoord(k)) <= eps) {
|
|
ep = GetSegStartCoord(k);
|
|
sp = GetSegEndCoord(k);
|
|
v = VecSub(sp, ep);
|
|
w = VecSub(epi, ep);
|
|
counter_tangential = (VecDotProd(v, w) < 0.0) ? false : true;
|
|
}
|
|
else if (PntPntDist(epi,GetSegStartCoord(k)) <= eps) {
|
|
ep = GetSegStartCoord(k);
|
|
sp = GetSegEndCoord(k);
|
|
v = VecSub(sp, ep);
|
|
w = VecSub(spi, ep);
|
|
counter_tangential = (VecDotProd(v, w) < 0.0) ? false : true;
|
|
}
|
|
else if (PntPntDist(spi,GetSegEndCoord(k)) <= eps) {
|
|
ep = GetSegEndCoord(k);
|
|
sp = GetSegStartCoord(k);
|
|
v = VecSub(sp, ep);
|
|
w = VecSub(epi, ep);
|
|
counter_tangential = (VecDotProd(v, w) < 0.0) ? false : true;
|
|
}
|
|
else if (PntPntDist(epi,GetSegEndCoord(k)) <= eps) {
|
|
ep = GetSegEndCoord(k);
|
|
sp = GetSegStartCoord(k);
|
|
v = VecSub(sp, ep);
|
|
w = VecSub(spi, ep);
|
|
counter_tangential = (VecDotProd(v, w) < 0.0) ? false : true;
|
|
}
|
|
|
|
if (!counter_tangential) {
|
|
//printf("arc%d and seg%d tangential, 2nd arc%d\n", i,k,j);
|
|
v = MakeVec(-s1a, -s1b);
|
|
num_sol = IntersectRayCircle(ep, v, c2, rr2, centers, radii,
|
|
eps);
|
|
is_special = true;
|
|
}
|
|
}
|
|
else if (Abs(Abs(c2.x*s1a+c2.y*s1b-s1c) - rr2) <= eps) {
|
|
/* */
|
|
/* the arc and the line are tangential. check whether they */
|
|
/* share an end point */
|
|
/* */
|
|
counter_tangential = true;
|
|
if (PntPntDist(spj,GetSegStartCoord(k)) <= eps) {
|
|
ep = GetSegStartCoord(k);
|
|
sp = GetSegEndCoord(k);
|
|
v = VecSub(sp, ep);
|
|
w = VecSub(epj, ep);
|
|
counter_tangential = (VecDotProd(v, w) < 0.0) ? false : true;
|
|
}
|
|
else if (PntPntDist(epj,GetSegStartCoord(k)) <= eps) {
|
|
ep = GetSegStartCoord(k);
|
|
sp = GetSegEndCoord(k);
|
|
v = VecSub(sp, ep);
|
|
w = VecSub(spj, ep);
|
|
counter_tangential = (VecDotProd(v, w) < 0.0) ? false : true;
|
|
}
|
|
else if (PntPntDist(spj,GetSegEndCoord(k)) <= eps) {
|
|
ep = GetSegEndCoord(k);
|
|
sp = GetSegStartCoord(k);
|
|
v = VecSub(sp, ep);
|
|
w = VecSub(epj, ep);
|
|
counter_tangential = (VecDotProd(v, w) < 0.0) ? false : true;
|
|
}
|
|
else if (PntPntDist(epj,GetSegEndCoord(k)) <= eps) {
|
|
ep = GetSegEndCoord(k);
|
|
sp = GetSegStartCoord(k);
|
|
v = VecSub(sp, ep);
|
|
w = VecSub(spj, ep);
|
|
counter_tangential = (VecDotProd(v, w) < 0.0) ? false : true;
|
|
}
|
|
|
|
if (!counter_tangential) {
|
|
//printf("arc%d and seg%d tangential, 2nd arc%d\n", i,k,j);
|
|
v = MakeVec(-s1a, -s1b);
|
|
num_sol = IntersectRayCircle(ep, v, c1, rr1, centers, radii,
|
|
eps);
|
|
is_special = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!is_special) {
|
|
/* */
|
|
/* and finally the general case... */
|
|
/* */
|
|
//printf("ordinary\n");
|
|
num_sol = CircCircSegCenters(c1, c2, rr1, rr2, s1a,s1b,s1c, centers,
|
|
radii, eps);
|
|
}
|
|
|
|
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_in, e, ARC, ARC, SEG,
|
|
false, true, true, centers, radii,
|
|
&num_sol, eps, problematic);
|
|
assert((0 <= best_sol) && (best_sol < num_sol));
|
|
#ifdef TRACE
|
|
if ((i_in == 4) && (j_in == 2) && (k_in == 2)) {
|
|
printf("problematic = %d, eps = %20.16f\n", *problematic, eps);
|
|
printf("num_sol = %d, best_sol = %d\n", num_sol, best_sol);
|
|
printf("center = (%20.16f %20.16f)\n", centers[best_sol].x,
|
|
centers[best_sol].y);
|
|
printf("radius = %20.16f\n", radii[best_sol]);
|
|
printf("zero_max = %20.16f\n", ZERO_MAX);
|
|
printf("e = %d: i = %d, j = %d, k = %d\n", e, i_in, j_in, k_in);
|
|
}
|
|
#endif
|
|
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("ArcArcSegCntr() - 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("ArcArcSegCntr() - 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("ArcArcSegCntr() - 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("ArcArcSegCntr() - arc with short cord!");
|
|
ReplaceArc(j);
|
|
restart = true;
|
|
return false;
|
|
}
|
|
else if (eq(GetSegLgth(k), ZERO_MAX)) {
|
|
/* */
|
|
/* this is a seg with a very small length; we replace it */
|
|
/* */
|
|
VD_Dbg_Warning("ArcArcSegCntr() - seg with small length!");
|
|
ReplaceSeg(k);
|
|
restart = true;
|
|
return false;
|
|
}
|
|
else if (CheckIntersectionsLocally(i, ARC, j, ARC, k, SEG)) {
|
|
restart = true;
|
|
return false;
|
|
}
|
|
|
|
#ifdef VRONI_DBG_WARN
|
|
spi = GetArcStartCoord(i);
|
|
spj = GetArcStartCoord(j);
|
|
epi = GetArcEndCoord(i);
|
|
epj = GetArcEndCoord(j);
|
|
c1 = GetArcCenter(i);
|
|
c2 = GetArcCenter(j);
|
|
printf("\nCenter not computed for arc-arc-seg and edge e = %d:\n",
|
|
e);
|
|
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);
|
|
ep = GetSegStartCoord(k);
|
|
sp = GetSegEndCoord(k);
|
|
printf("%20.16f %20.16f %20.16f %20.16f\n",
|
|
sp.x, sp.y, ep.x, ep.y);
|
|
#endif
|
|
|
|
*cntr = centers[best_sol];
|
|
*r2 = radii[best_sol];
|
|
restart = false;
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
|