de65914f43
- modifiche per integrare vroni con le nostre librerie - spostamento header in Extern per evitare duplicati.
382 lines
16 KiB
C++
382 lines
16 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 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;
|
|
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;
|
|
|
|
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;
|
|
|
|
#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)) {
|
|
is_special = true;
|
|
centers[0] = c1;
|
|
centers[1] = c2;
|
|
radii[0] = rr1;
|
|
radii[1] = rr2;
|
|
num_sol = 2;
|
|
}
|
|
}
|
|
|
|
if (!is_special) {
|
|
/* */
|
|
/* and finally the general case... */
|
|
/* */
|
|
//printf("ordinary\n");
|
|
num_sol = CircCircCircCenters(c1, c2, c3, rr1, rr2, rr3, 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, 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;
|
|
}
|
|
|
|
|
|
|
|
|
|
|