f3e15b8c8d
- aggiunti file della libreria e progetto visual studio.
330 lines
14 KiB
C++
330 lines
14 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 "numerics.h"
|
|
#include "defs.h"
|
|
#include "roots.h"
|
|
|
|
|
|
|
|
/* */
|
|
/* Calculate the Voronoi center of arc, seg and pnt */
|
|
/* */
|
|
vr_bool vroniObject::ArcSegPntCntr(int i, int j, int k, int e,
|
|
coord* cntr, double *r2,
|
|
vr_bool *problematic, int* site)
|
|
{
|
|
coord c1, c2;
|
|
double rr1, rr2;
|
|
double s1a, s1b, s1c;
|
|
coord centers[VRONI_MAXSOL];
|
|
double radii[VRONI_MAXSOL];
|
|
int num_sol = 0, best_sol = NIL, old_num_sol = 0;;
|
|
double d_c1c2;
|
|
|
|
double eps = ZERO;
|
|
vr_bool counter_tangential, is_endpoint, is_special, is_tangent;
|
|
vr_bool is_pnt_on_line, is_pnt_on_circle;
|
|
coord spi, epi;
|
|
coord ep, sp, u, v, w;
|
|
#ifdef VRONI_DBG_WARN
|
|
coord spj, epj;
|
|
#endif
|
|
|
|
/* */
|
|
/* Check whether the three sites are all in lists */
|
|
/* */
|
|
assert(InArcsList(i));
|
|
assert(InSegsList(j));
|
|
assert(InPntsList(k));
|
|
|
|
*problematic = false;
|
|
|
|
if ((IsArcStartPnt(i,k) || IsArcEndPnt(i,k)) &&
|
|
(IsSegStartPnt(j,k) || IsSegEndPnt(j,k))) {
|
|
/* */
|
|
/* pnt k is a common end-point of i and j. */
|
|
/* */
|
|
//printf("\n\nPoint splits arc-seg\n\n");
|
|
|
|
*cntr = GetPntCoords(k);
|
|
*r2 = 0.0;
|
|
*site = k;
|
|
return true;
|
|
}
|
|
|
|
c1 = GetArcCenter(i);
|
|
c2 = GetPntCoords(k);
|
|
|
|
rr1 = GetArcRadius(i);
|
|
rr2 = 0;
|
|
|
|
GetSegEqnData(j, &s1a, &s1b, &s1c);
|
|
s1c*=-1;
|
|
|
|
spi = GetArcStartCoord(i);
|
|
epi = GetArcEndCoord(i);
|
|
|
|
#ifdef TRACE
|
|
printf("arc%d-seg%d-pnt%d:\n", i, j, k);
|
|
printf("arc: (%20.16f %20.16f) %20.16f\n", c1.x, c1.y, rr1);
|
|
printf("pnt: (%20.16f %20.16f %20.16f)\n", s1a, s1b, s1c);
|
|
#endif
|
|
|
|
d_c1c2 = PntPntDist(c1, c2);
|
|
|
|
if (IsArcStartPnt(i,k) || IsArcEndPnt(i,k)) {
|
|
if ( Abs(PntLineDist(s1a, s1b, -s1c, c1)) < rr1 )
|
|
v = VecSub(c1, c2);
|
|
else
|
|
v = VecSub(c2, c1);
|
|
is_endpoint = true;
|
|
old_num_sol = IntersectRaySegment(c2, v, s1a, s1b, s1c, centers, radii,
|
|
ZERO);
|
|
}
|
|
else if (IsSegStartPnt(j,k) || IsSegEndPnt(j,k)) {
|
|
u = VecSub(c1,c2);
|
|
v = MakeVec(s1a, s1b);
|
|
|
|
/* */
|
|
/* if arc is between c1 and c2 and v points away from c1, or */
|
|
/* if arc is not between c1 and c2 and v points to c1, */
|
|
/* then invert v */
|
|
/* */
|
|
if ((d_c1c2 > rr1) && (v.x*u.x + v.y*u.y < 0)) v = VecMult(-1.0, v);
|
|
if ((d_c1c2 < rr1) && (v.x*u.x + v.y*u.y > 0)) v = VecMult(-1.0, v);
|
|
is_endpoint = true;
|
|
old_num_sol = IntersectRayCircle(c2, v, c1, rr1, centers, radii, ZERO);
|
|
}
|
|
else {
|
|
is_endpoint = false;
|
|
}
|
|
|
|
while (eps <= ZERO_MAX) {
|
|
|
|
is_special = false;
|
|
num_sol = old_num_sol;
|
|
|
|
if (!is_endpoint) {
|
|
if (DoArcPntIntersect(i, c2, eps)) {
|
|
VD_Dbg_Warning("ArcSegPntCntr() - point lies in interior of arc!");
|
|
SetInvalidSites(i, ARC, k, PNT, eps);
|
|
restart = false;
|
|
return false;
|
|
}
|
|
|
|
is_pnt_on_line = (Abs(PntLineDist(s1a, s1b, -s1c, c2)) <= eps);
|
|
is_pnt_on_circle = (Abs(d_c1c2-rr1) <= eps);
|
|
is_tangent = (Abs(Abs(c1.x*s1a+c1.y*s1b-s1c)-rr1) <= eps);
|
|
|
|
if (is_pnt_on_line && is_pnt_on_circle && is_tangent) {
|
|
/* */
|
|
/* circle and line are tangent in the pnt */
|
|
/* */
|
|
if (IsPntInArcCone(i, c2)) {
|
|
centers[0]= c2;
|
|
radii[0] = 0.0;
|
|
}
|
|
else {
|
|
centers[0]= c1;
|
|
radii[0] = rr1;
|
|
}
|
|
num_sol = 1;
|
|
is_special = true;
|
|
}
|
|
else if (is_pnt_on_circle && IsPntInArcCone(i,c2) && (rr1 > eps)) {
|
|
/* */
|
|
/* pnt is on the circle */
|
|
/* */
|
|
if (Abs(PntLineDist(s1a, s1b, -s1c, c1)) < rr1)
|
|
v = VecSub(c1, c2);
|
|
else
|
|
v = VecSub(c2, c1);
|
|
|
|
num_sol = IntersectRaySegment(c2, v, s1a, s1b, s1c, centers,
|
|
radii, eps);
|
|
is_special = true;
|
|
}
|
|
else if (is_pnt_on_line) {
|
|
/* */
|
|
/* pnt is on the line */
|
|
/* */
|
|
//printf("asp: special case: point is on line\n");
|
|
u = VecSub(c1,c2);
|
|
v = MakeVec(s1a, s1b);
|
|
|
|
/* */
|
|
/* if arc is between c1 and c2 and v points away from c1, */
|
|
/* or */
|
|
/* if arc is not between c1 and c2 and v points to c1, */
|
|
/* then invert v */
|
|
/* */
|
|
if (((d_c1c2 > rr1) && (v.x*u.x + v.y*u.y) < 0))
|
|
v = VecMult(-1.0, v);
|
|
if (((d_c1c2 < rr1) && (v.x*u.x + v.y*u.y) > 0))
|
|
v = VecMult(-1.0, v);
|
|
num_sol = IntersectRayCircle(c2, v, c1, rr1, centers, radii, eps);
|
|
is_special = true;
|
|
}
|
|
else if (is_tangent) {
|
|
/* */
|
|
/* line is tangent to circle */
|
|
/* */
|
|
counter_tangential = true;
|
|
if (PntPntDist(GetArcStartCoord(i),GetSegStartCoord(j)) <= eps) {
|
|
ep = GetSegStartCoord(j);
|
|
sp = GetSegEndCoord(j);
|
|
v = VecSub(sp, ep);
|
|
w = VecSub(epi, ep);
|
|
counter_tangential = (VecDotProd(v, w) < 0.0) ? false : true;
|
|
}
|
|
else if (PntPntDist(GetArcEndCoord(i),GetSegStartCoord(j)) <= eps) {
|
|
ep = GetSegStartCoord(j);
|
|
sp = GetSegEndCoord(j);
|
|
v = VecSub(sp, ep);
|
|
w = VecSub(spi, ep);
|
|
counter_tangential = (VecDotProd(v, w) < 0.0) ? false : true;
|
|
}
|
|
else if (PntPntDist(GetArcStartCoord(i),GetSegEndCoord(j)) <= eps) {
|
|
ep = GetSegEndCoord(j);
|
|
sp = GetSegStartCoord(j);
|
|
v = VecSub(sp, ep);
|
|
w = VecSub(epi, ep);
|
|
counter_tangential = (VecDotProd(v, w) < 0.0) ? false : true;
|
|
}
|
|
else if (PntPntDist(GetArcEndCoord(i),GetSegEndCoord(j)) <= eps) {
|
|
ep = GetSegEndCoord(j);
|
|
sp = GetSegStartCoord(j);
|
|
v = VecSub(sp, ep);
|
|
w = VecSub(spi, ep);
|
|
counter_tangential = (VecDotProd(v, w) < 0.0) ? false : true;
|
|
}
|
|
|
|
if (!counter_tangential) {
|
|
if ((s1a*c2.x+s1b*c2.y-s1c) > 0.0) v = MakeVec(s1a, s1b);
|
|
else v = MakeVec(-s1a, -s1b);
|
|
num_sol = IntersectRayCircle(ep, v, c2, 0.0, 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);
|
|
}
|
|
}
|
|
|
|
/* */
|
|
/* classify all solutions and pick the best solution */
|
|
/* */
|
|
best_sol = ClassifySolutions(i, j, k, e, ARC, SEG, 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 */
|
|
/* by a seg */
|
|
/* */
|
|
VD_Dbg_Warning("ArcSegPntCntr() - 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("ArcSegPntCntr() - arc with short cord!");
|
|
ReplaceArc(i);
|
|
restart = true;
|
|
return false;
|
|
}
|
|
else if (eq(GetSegLgth(j), ZERO_MAX)) {
|
|
/* */
|
|
/* this is a seg with a very small length; we replace it */
|
|
/* */
|
|
VD_Dbg_Warning("ArcSegPntCntr() - seg with small length!");
|
|
ReplaceSeg(j);
|
|
restart = true;
|
|
return false;
|
|
}
|
|
else if (CheckIntersectionsLocally(i, ARC, j, SEG, k, PNT)) {
|
|
restart = true;
|
|
return false;
|
|
}
|
|
|
|
#ifdef VRONI_DBG_WARN
|
|
spi = GetArcStartCoord(i);
|
|
epi = GetArcEndCoord(i);
|
|
c1 = GetArcCenter(i);
|
|
printf("\nCenter not computed for arc-seg-pnt:\n");
|
|
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);
|
|
epj = GetSegStartCoord(j);
|
|
spj = GetSegEndCoord(j);
|
|
printf("%20.16f %20.16f %20.16f %20.16f\n",
|
|
spj.x, spj.y, epj.x, epj.y);
|
|
c2 = GetPntCoords(k);
|
|
printf("%20.16f %20.16f\n", c2.x, c2.y);
|
|
#endif
|
|
|
|
*cntr = centers[best_sol];
|
|
*r2 = radii[best_sol];
|
|
restart = false;
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
|