f3e15b8c8d
- aggiunti file della libreria e progetto visual studio.
1058 lines
32 KiB
C++
1058 lines
32 KiB
C++
/*****************************************************************************/
|
|
/* */
|
|
/* Copyright (C) 2001-2023 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: 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 <stdio.h>
|
|
#include <stdlib.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 "wmat.h"
|
|
#include "offset.h"
|
|
|
|
|
|
#ifdef MAT
|
|
|
|
|
|
|
|
#define ComputeContact(S, P, Q, A, B, T) \
|
|
{\
|
|
if (S) { \
|
|
P.x = Q.x - A * T; \
|
|
P.y = Q.y - B * T; \
|
|
} \
|
|
else { \
|
|
P.x = Q.x + A * T; \
|
|
P.y = Q.y + B * T; \
|
|
} \
|
|
}
|
|
|
|
|
|
|
|
#define WmatErrorCheck(dist, wmat_dist_sq, ZERO, wmat_cosine, cosine, i, t, r1, r2) \
|
|
{\
|
|
if (gt(dist - wmat_dist_sq, ZERO) && gt(wmat_cosine - cosine, ZERO)) { \
|
|
if ((t < r1) || (t > r2)) { \
|
|
printf("WMAT violation I for edge %d and parameter %f\n", i, t); \
|
|
printf("wmat_cosine = %f, cosine = %f\n", wmat_cosine, cosine); \
|
|
printf("wmat_dist_sq = %20.16f, dist = %20.16f\n", wmat_dist_sq, dist); \
|
|
printf("r1 = %20.16f, r2 = %20.16f\n", r1, r2);\
|
|
} \
|
|
} \
|
|
else if ((t >= r1) && (t <= r2)) { \
|
|
if (lt(dist - wmat_dist_sq, ZERO) || lt(wmat_cosine - cosine, ZERO)) { \
|
|
printf("WMAT violation II for edge %d and parameter %f\n", i, t); \
|
|
printf("wmat_cosine = %f, cosine = %f\n", wmat_cosine, cosine); \
|
|
printf("wmat_dist_sq = %20.16f, dist = %20.16f\n", wmat_dist_sq, dist); \
|
|
printf("r1 = %20.16f, r2 = %20.16f\n", r1, r2);\
|
|
} \
|
|
} \
|
|
}
|
|
|
|
|
|
|
|
/* */
|
|
/* the weighted medial axis (WMAT) is the subset of all those points P of */
|
|
/* the Voronoi diaram (VD) that meet the following requirements: */
|
|
/* (1) the clearance disk centered at P touches the input sites in at */
|
|
/* least two disjoint contact points C1 and C2. */
|
|
/* (2) the distance between C1 and C2 is greater than the (user-defined) */
|
|
/* threshold wmat_dist. */
|
|
/* (3) the angle formed by (C1,P,C2) is greater than the (user-defined) */
|
|
/* threshold wmat_angle. */
|
|
/* note that the WMAT is identical to the standard medial axis (MAT) for */
|
|
/* wmat_dist = wmat_angle = 0. see wmat.pdf in ../READMEs for a figure. */
|
|
/* */
|
|
/* for edge i of the VD, we store the WMAT data in the record */
|
|
/* edges[i].w_mat as follows: */
|
|
/* the vr_bool in_w_mat is true if a portion of this VD edge also belongs */
|
|
/* to the WMAT. */
|
|
/* r_min and r_max denote the minimum and maximum contour clearances of */
|
|
/* those points of this VD edge that belong to the WMAT. due to our specific */
|
|
/* parameterization of the VD edges, we have */
|
|
/* min{t1,t2} <= r_min <= r_max <= max{t1,t2}, where t1 and t2 are the */
|
|
/* contour clearances (radii) of the start node and end node of the VD edge. */
|
|
/* let P1 be the point on the VD edge that corresponds to the clearance */
|
|
/* radius r_min, and P2 the point that corresponds to r_max. the */
|
|
/* intersection (contact point) of the left defining site of the VD edge */
|
|
/* with a disk with radius r_min centered at P1 is stored in lft_mn_pnt,*/
|
|
/* and the intersection (contact point) of the right defining defining site */
|
|
/* of the VD edge with a disk with radius r_min centered at P1 is stored */
|
|
/* in rgt_mn_pnt. similar for P2 and lft_mx_pnt, rgt_mx_pnt. */
|
|
/* */
|
|
/* For closed contours, a one-sided computation of the WMAT may be requested */
|
|
/* by specifying the run-time options "--left_offset" or "--right_offset". */
|
|
/* */
|
|
|
|
|
|
|
|
vr_bool vroniObject::GetWMATStatus(void)
|
|
{
|
|
return WMAT_computed;
|
|
}
|
|
|
|
|
|
|
|
void vroniObject::ResetWMATStatus(void)
|
|
{
|
|
int i, num_edges;
|
|
|
|
num_edges = GetNumberOfEdges();
|
|
|
|
for (i = 0; i < num_edges; ++i) {
|
|
SetWmatEdge(i, false);
|
|
}
|
|
|
|
WMAT_computed = false;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
#ifdef WMAT
|
|
void vroniObject::CheckWMAT(double wmat_dist, double wmat_angle)
|
|
{
|
|
int num_edges, i, j, n1, n2, lft, rgt;
|
|
t_site t_lft, t_rgt;
|
|
double t, t1, t2, t3, r1, r2, a1, a2, b1, b2, c1, c2;
|
|
coord p1, p2, q1, q2, u1, u2;
|
|
double delta, wmat_dist_sq, wmat_cosine, cosine, dist;
|
|
vr_bool s1, s2;
|
|
|
|
num_edges = GetNumberOfEdges();
|
|
wmat_cosine = cos(wmat_angle);
|
|
wmat_dist_sq = wmat_dist * wmat_dist;
|
|
delta = 0.1 * wmat_dist;
|
|
if (lt(delta, SMALL)) delta = SMALL; /* must not be equal to 0.0!!!! */
|
|
|
|
for (i = 4; i < num_edges; ++i) {
|
|
if (IsWmatEdge(i)) {
|
|
n1 = GetStartNode(i);
|
|
n2 = GetEndNode(i);
|
|
GetNodeData(n1, &p1, &t1);
|
|
GetNodeData(n2, &p2, &t2);
|
|
if (t1 > t2) {
|
|
Swap(t1, t2, r1);
|
|
}
|
|
else {
|
|
p1 = p2;
|
|
}
|
|
|
|
r1 = GetWmatRMin(i);
|
|
r2 = GetWmatRMax(i);
|
|
|
|
GetLftSiteData(i, &lft, &t_lft);
|
|
GetRgtSiteData(i, &rgt, &t_rgt);
|
|
if ((t_lft == PNT) && (t_rgt == SEG)) {
|
|
Swap(lft, rgt, j);
|
|
t_lft = SEG;
|
|
t_rgt = PNT;
|
|
}
|
|
|
|
t3 = t2 + delta * 0.5;
|
|
if (t_lft == SEG) {
|
|
GetSegEqnData(lft, &a1, &b1, &c1);
|
|
if (PntLineDist(a1, b1, c1, p1) >= 0.0) s1 = true;
|
|
else s1 = false;
|
|
if (t_rgt == SEG) {
|
|
/* */
|
|
/* SEG-SEG: line bisector */
|
|
/* */
|
|
GetSegEqnData(rgt, &a2, &b2, &c2);
|
|
if (PntLineDist(a2, b2, c2, p1) >= 0.0) {
|
|
s2 = true;
|
|
if (s1) cosine = a1 * a2 + b1 * b2;
|
|
else cosine = - a1 * a2 - b1 * b2;
|
|
}
|
|
else {
|
|
s2 = false;
|
|
if (s1) cosine = - a1 * a2 - b1 * b2;
|
|
else cosine = a1 * a2 + b1 * b2;
|
|
}
|
|
for (t = t1; t < t3; t += delta) {
|
|
if (t > t2) t = t2;
|
|
EvaluateLineData(i, t, &p2);
|
|
ComputeContact(s1, q1, p2, a1, b1, t);
|
|
ComputeContact(s2, q2, p2, a2, b2, t);
|
|
dist = PntPntDistSq(q1, q2);
|
|
WmatErrorCheck(dist, wmat_dist_sq, ZERO, wmat_cosine, cosine,
|
|
i, t, r1, r2);
|
|
}
|
|
}
|
|
else if (t_rgt == PNT) {
|
|
/* */
|
|
/* SEG-PNT: parabola bisector */
|
|
/* */
|
|
assert(!(IsSegStartPnt(lft, rgt) || IsSegEndPnt(lft, rgt)));
|
|
q2 = GetPntCoords(rgt);
|
|
for (t = t1; t < t3; t += delta) {
|
|
if (t > t2) t = t2;
|
|
EvaluateParabolaData(i, lft, t, &p2);
|
|
ComputeContact(s1, q1, p2, a1, b1, t);
|
|
dist = PntPntDistSq(q1, q2);
|
|
u2 = VecSub(p2, q2);
|
|
if (s1) cosine = a1 * u2.x + b1 * u2.y;
|
|
else cosine = - a1 * u2.x - b1 * u2.y;
|
|
if (eq(t, TINY)) cosine = 1.0;
|
|
else cosine /= t;
|
|
WmatErrorCheck(dist, wmat_dist_sq, ZERO, wmat_cosine, cosine,
|
|
i, t, r1, r2);
|
|
}
|
|
}
|
|
else {
|
|
throw std::runtime_error("VRONI error: CheckWMAT() - cannot handle this site type!");
|
|
}
|
|
}
|
|
else if (t_lft == PNT) {
|
|
/* */
|
|
/* PNT-PNT: (hyperbola) line bisector */
|
|
/* */
|
|
q1 = GetPntCoords(lft);
|
|
q2 = GetPntCoords(rgt);
|
|
dist = PntPntDistSq(q1, q2);
|
|
for (t = t1; t < t3; t += delta) {
|
|
if (t > t2) t = t2;
|
|
EvaluateHyperbolaData(i, t, &p2);
|
|
u1 = VecSub(p2, q1);
|
|
u2 = VecSub(p2, q2);
|
|
if (eq(t, TINY))
|
|
cosine = 1.0;
|
|
else
|
|
cosine = VecDotProd(u1, u2) / (t * t);
|
|
WmatErrorCheck(dist, wmat_dist_sq, ZERO, wmat_cosine, cosine,
|
|
i, t, r1, r2);
|
|
}
|
|
}
|
|
else {
|
|
throw std::runtime_error("VRONI error: CheckWMAT() - cannot handle this site type!");
|
|
}
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef WMAT
|
|
void vroniObject::ComputeWMATParabola(int i, int i1, int i2, double_arg wmat_cosine,
|
|
double_arg wmat_dist_sq)
|
|
#else
|
|
void vroniObject::ComputeWMATParabola(int i, int i1, int i2)
|
|
#endif
|
|
{
|
|
int n1, n2;
|
|
coord p1, p2, p;
|
|
double t1, t2, t_min, delta;
|
|
t_site site2 = PNT;
|
|
#ifdef WMAT
|
|
double a1, b1, c1, d, t_max;
|
|
coord q1, q2;
|
|
vr_bool s1;
|
|
#endif
|
|
|
|
assert(InEdgesList(i));
|
|
assert(InSegsList(i1));
|
|
assert(InPntsList(i2));
|
|
|
|
#ifdef GENUINE_ARCS
|
|
GetLftSiteData(i, &n2, &site2);
|
|
if (site2 == SEG) GetRgtSiteData(i, &n2, &site2);
|
|
assert((site2 == PNT) || (site2 == ARC));
|
|
#endif
|
|
|
|
if ((site2 == PNT) && (IsSegStartPnt(i1, i2) || IsSegEndPnt(i1, i2)) ) {
|
|
SetWmatEdge(i, false);
|
|
return;
|
|
}
|
|
|
|
n1 = GetStartNode(i);
|
|
n2 = GetEndNode(i);
|
|
GetNodeData(n1, &p1, &t1);
|
|
GetNodeData(n2, &p2, &t2);
|
|
if (t2 < t1) {
|
|
Swap(t1, t2, t_min);
|
|
Swap(p1, p2, p);
|
|
}
|
|
|
|
if (le(t2, ZERO)) { /* degenerate segment */
|
|
SetWmatEdge(i, false);
|
|
return;
|
|
}
|
|
|
|
#ifdef WMAT
|
|
GetSegEqnData(i1, &a1, &b1, &c1);
|
|
q1 = GetPntCoords(i2);
|
|
d = PntLineDist(a1, b1, c1, q1);
|
|
if (d < 0.0) {
|
|
s1 = false;
|
|
d = -d;
|
|
}
|
|
else {
|
|
s1 = true;
|
|
}
|
|
|
|
/* */
|
|
/* let delta be the distance between p1 and the contact point on the */
|
|
/* line segment, for a disk with clearance radius t. we get */
|
|
/* delta * delta = 2 * t * d ... yields lower bound for t. */
|
|
/* */
|
|
if (eq(d, ZERO)) {
|
|
if (wmat_dist_sq == 0.0) {
|
|
t_min = 0.0;
|
|
}
|
|
else {
|
|
SetWmatEdge(i, false);
|
|
return;
|
|
}
|
|
}
|
|
else {
|
|
t_min = wmat_dist_sq * 0.5 / d;
|
|
}
|
|
|
|
if (t_min >= t2) { /* distance too small */
|
|
SetWmatEdge(i, false);
|
|
return;
|
|
}
|
|
|
|
/* */
|
|
/* d = t * (1 - cos(wmat_angle)) ... yields upper bound for t. */
|
|
/* */
|
|
delta = 1 - wmat_cosine;
|
|
if (eq(delta, TINY))
|
|
t_max = DBL_MAX;
|
|
else
|
|
t_max = d / delta;
|
|
|
|
t_min = Max(t1, t_min);
|
|
t_max = Min(t2, t_max);
|
|
if (t_max <= t_min) { /* angle too small */
|
|
SetWmatEdge(i, false);
|
|
return;
|
|
}
|
|
SetWmatRMin(i, t_min);
|
|
SetWmatRMax(i, t_max);
|
|
|
|
/* */
|
|
/* make sure that the parameterization formula is initialized */
|
|
/* */
|
|
if (GetEdgeDataInit(i)) {
|
|
CreateParabolaData(i);
|
|
SetEdgeDataInit(i, false);
|
|
}
|
|
|
|
/* */
|
|
/* compute the contact points */
|
|
/* */
|
|
if (IsLftSite(i, i1, SEG)) {
|
|
assert(IsRgtSite(i, i2, PNT));
|
|
EvaluateParabolaData(i, i1, t_min, &q1);
|
|
ComputeContact(s1, p2, q1, a1, b1, t_min);
|
|
SetWmatLftMnPnt(i, p2);
|
|
SetWmatRgtMnPnt(i, p1);
|
|
EvaluateParabolaData(i, i1, t_max, &q2);
|
|
ComputeContact(s1, p2, q2, a1, b1, t_max);
|
|
SetWmatLftMxPnt(i, p2);
|
|
SetWmatRgtMxPnt(i, p1);
|
|
}
|
|
else {
|
|
assert(IsRgtSite(i, i1, SEG));
|
|
assert(IsLftSite(i, i2, PNT));
|
|
EvaluateParabolaData(i, i2, t_min, &q1);
|
|
ComputeContact(s1, p2, q1, a1, b1, t_min);
|
|
SetWmatLftMnPnt(i, p1);
|
|
SetWmatRgtMnPnt(i, p2);
|
|
EvaluateParabolaData(i, i2, t_max, &q2);
|
|
ComputeContact(s1, p2, q2, a1, b1, t_max);
|
|
SetWmatLftMxPnt(i, p1);
|
|
SetWmatRgtMxPnt(i, p2);
|
|
}
|
|
#endif
|
|
|
|
if (t1 == 0.0) {
|
|
delta = PntPntDist(p1, p2) - t2;
|
|
if (gt(delta, ZERO)) {
|
|
SetWmatEdge(i, true);
|
|
}
|
|
else {
|
|
SetWmatEdge(i, false);
|
|
}
|
|
}
|
|
else {
|
|
SetWmatEdge(i, true);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
#ifdef WMAT
|
|
void vroniObject::ComputeWMATHyperbola(int i, int i1, int i2, double_arg wmat_cosine,
|
|
double_arg wmat_dist_sq)
|
|
#else
|
|
void vroniObject::ComputeWMATHyperbola(int i)
|
|
#endif
|
|
{
|
|
int n1, n2;
|
|
double t1, t2, t_max;
|
|
coord p1, p2, p;
|
|
double delta;
|
|
#ifdef WMAT
|
|
double d_sq;
|
|
coord q1, q2;
|
|
#endif
|
|
|
|
assert(InEdgesList(i));
|
|
|
|
n1 = GetStartNode(i);
|
|
n2 = GetEndNode(i);
|
|
GetNodeData(n1, &p1, &t1);
|
|
GetNodeData(n2, &p2, &t2);
|
|
if (t2 < t1) {
|
|
Swap(t1, t2, t_max);
|
|
Swap(p1, p2, p);
|
|
}
|
|
|
|
if (le(t2, ZERO)) { /* degenerate segment */
|
|
SetWmatEdge(i, false);
|
|
return;
|
|
}
|
|
|
|
#ifdef WMAT
|
|
assert(InPntsList(i1));
|
|
assert(InPntsList(i2));
|
|
q1 = GetPntCoords(i1);
|
|
q2 = GetPntCoords(i2);
|
|
d_sq = PntPntDistSq(q1, q2);
|
|
|
|
if (d_sq <= wmat_dist_sq) { /* distance is too small */
|
|
SetWmatEdge(i, false);
|
|
return;
|
|
}
|
|
|
|
/* */
|
|
/* d_sq = 2 * t * t * (1 - cos(wmat_angle)) ... yields upper bound for t */
|
|
/* */
|
|
delta = 1 - wmat_cosine;
|
|
if (eq(delta, TINY))
|
|
t_max = DBL_MAX;
|
|
else
|
|
t_max = sqrt(0.5 * d_sq / delta);
|
|
|
|
if (t2 < t_max) {
|
|
SetWmatRMax(i, t2);
|
|
}
|
|
else if (t_max <= t1) {
|
|
SetWmatEdge(i, false);
|
|
return;
|
|
}
|
|
else {
|
|
SetWmatRMax(i, t_max);
|
|
}
|
|
SetWmatRMin(i, t1);
|
|
|
|
/* */
|
|
/* store the contact points */
|
|
/* */
|
|
SetWmatLftMnPnt(i, q1);
|
|
SetWmatLftMxPnt(i, q1);
|
|
SetWmatRgtMnPnt(i, q2);
|
|
SetWmatRgtMxPnt(i, q2);
|
|
|
|
/* */
|
|
/* make sure that the parameterization formula is initialized */
|
|
/* */
|
|
if (GetEdgeDataInit(i)) {
|
|
CreateHyperbolaData(i);
|
|
SetEdgeDataInit(i, false);
|
|
}
|
|
#endif
|
|
|
|
if (t1 == 0.0) {
|
|
delta = PntPntDist(p1, p2) - t2;
|
|
if (gt(delta, ZERO)) {
|
|
SetWmatEdge(i, true);
|
|
}
|
|
else {
|
|
SetWmatEdge(i, false);
|
|
}
|
|
}
|
|
else {
|
|
SetWmatEdge(i, true);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
#ifdef WMAT
|
|
void vroniObject::ComputeWMATLine(int i, int i1, int i2, double wmat_cosine,
|
|
double wmat_dist_sq)
|
|
#else
|
|
void vroniObject::ComputeWMATLine(int i)
|
|
#endif
|
|
{
|
|
int n1, n2;
|
|
double t1, t2, t_min, delta;
|
|
coord p1, p2, q1;
|
|
#ifdef WMAT
|
|
double a1, b1, c1, a2, b2, c2, cosine;
|
|
coord q2;
|
|
vr_bool s1, s2;
|
|
#endif
|
|
|
|
assert(InEdgesList(i));
|
|
|
|
n1 = GetStartNode(i);
|
|
n2 = GetEndNode(i);
|
|
GetNodeData(n1, &p1, &t1);
|
|
GetNodeData(n2, &p2, &t2);
|
|
if (t1 <= t2) {
|
|
q1 = p2;
|
|
}
|
|
else {
|
|
q1 = p1;
|
|
Swap(t1, t2, t_min);
|
|
}
|
|
|
|
if (le(t2, ZERO)) { /* degnerate segment */
|
|
SetWmatEdge(i, false);
|
|
return;
|
|
}
|
|
|
|
#ifdef WMAT
|
|
assert(InSegsList(i1));
|
|
assert(InSegsList(i2));
|
|
|
|
GetSegEqnData(i1, &a1, &b1, &c1);
|
|
GetSegEqnData(i2, &a2, &b2, &c2);
|
|
|
|
/* */
|
|
/* compute the cosine of the angle between the normals; make sure that */
|
|
/* normals point into the correct direction. */
|
|
/* */
|
|
if (PntLineDist(a1, b1, c1, q1) >= 0.0) {
|
|
s1 = true;
|
|
if (PntLineDist(a2, b2, c2, q1) >= 0.0) {
|
|
s2 = true;
|
|
cosine = a1 * a2 + b1 * b2;
|
|
}
|
|
else {
|
|
s2 = false;
|
|
cosine = - a1 * a2 - b1 * b2;
|
|
}
|
|
}
|
|
else {
|
|
s1 = false;
|
|
if (PntLineDist(a2, b2, c2, q1) >= 0.0) {
|
|
s2 = true;
|
|
cosine = - a1 * a2 - b1 * b2;
|
|
}
|
|
else {
|
|
s2 = false;
|
|
cosine = a1 * a2 + b1 * b2;
|
|
}
|
|
}
|
|
|
|
if (cosine >= wmat_cosine) { /* angle is too small */
|
|
SetWmatEdge(i, false);
|
|
return;
|
|
}
|
|
|
|
delta = 1 - cosine;
|
|
if (eq(delta, TINY))
|
|
t_min = DBL_MAX;
|
|
else
|
|
t_min = sqrt(0.5 * wmat_dist_sq / delta);
|
|
|
|
if (t_min >= t2) {
|
|
SetWmatEdge(i, false);
|
|
return;
|
|
}
|
|
else {
|
|
t_min = Max(t1, t_min);
|
|
SetWmatRMin(i, t_min);
|
|
}
|
|
SetWmatRMax(i, t2);
|
|
|
|
/* */
|
|
/* make sure that the parameterization formula is initialized */
|
|
/* */
|
|
if (GetEdgeDataInit(i)) {
|
|
CreateLineData(i);
|
|
SetEdgeDataInit(i, false);
|
|
}
|
|
|
|
/* */
|
|
/* compute the contact points */
|
|
/* */
|
|
assert(IsLftSite(i, i1, SEG));
|
|
assert(IsRgtSite(i, i2, SEG));
|
|
if (t1 == t2) q1 = p1;
|
|
else EvaluateLineData(i, t_min, &q1);
|
|
ComputeContact(s1, p1, q1, a1, b1, t_min);
|
|
SetWmatLftMnPnt(i, p1);
|
|
ComputeContact(s2, p2, q1, a2, b2, t_min);
|
|
SetWmatRgtMnPnt(i, p2);
|
|
|
|
if (t1 == t2) q2 = p2;
|
|
else EvaluateLineData(i, t2, &q2);
|
|
ComputeContact(s1, p1, q2, a1, b1, t2);
|
|
SetWmatLftMxPnt(i, p1);
|
|
ComputeContact(s2, p2, q2, a2, b2, t2);
|
|
SetWmatRgtMxPnt(i, p2);
|
|
#endif
|
|
|
|
if (t1 == 0.0) {
|
|
delta = PntPntDist(p1, p2) - t2;
|
|
if (gt(delta, ZERO)) {
|
|
SetWmatEdge(i, true);
|
|
}
|
|
else {
|
|
SetWmatEdge(i, false);
|
|
}
|
|
}
|
|
else {
|
|
SetWmatEdge(i, true);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
#ifdef WMAT
|
|
void vroniObject::ComputeWMATEdge(int e, double_arg wmat_cosine, double_arg wmat_dist_sq)
|
|
#else
|
|
void vroniObject::ComputeWMATEdge(int e)
|
|
#endif
|
|
{
|
|
int i1, i2;
|
|
t_site ltype, rtype;
|
|
|
|
assert(InEdgesList(e));
|
|
|
|
GetLftSiteData(e, &i1, <ype);
|
|
GetRgtSiteData(e, &i2, &rtype);
|
|
|
|
switch(ltype) {
|
|
case(PNT):
|
|
switch(rtype) {
|
|
case(PNT): /* PNT-PNT: line (hyperbolic) bisector */
|
|
#ifdef WMAT
|
|
ComputeWMATHyperbola(e, i1, i2, wmat_cosine, wmat_dist_sq);
|
|
#else
|
|
ComputeWMATHyperbola(e);
|
|
#endif
|
|
break;
|
|
case(SEG): /* PNT-SEG: parabola bisector */
|
|
#ifdef WMAT
|
|
ComputeWMATParabola(e, i2, i1, wmat_cosine, wmat_dist_sq);
|
|
#else
|
|
ComputeWMATParabola(e, i2, i1);
|
|
#endif
|
|
break;
|
|
case(ARC):
|
|
#ifdef GENUINE_ARCS
|
|
#ifndef WMAT
|
|
ComputeWMATHyperbola(e);
|
|
#endif
|
|
#endif
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case(SEG):
|
|
switch(rtype) {
|
|
case(PNT): /* SEG-PNT: parabola bisector */
|
|
#ifdef WMAT
|
|
ComputeWMATParabola(e, i1, i2, wmat_cosine, wmat_dist_sq);
|
|
#else
|
|
ComputeWMATParabola(e, i1, i2);
|
|
#endif
|
|
break;
|
|
case(SEG): /* SEG-SEG: line bisector */
|
|
#ifdef WMAT
|
|
ComputeWMATLine(e, i1, i2, wmat_cosine, wmat_dist_sq);
|
|
#else
|
|
ComputeWMATLine(e);
|
|
#endif
|
|
break;
|
|
case(ARC):
|
|
#ifdef GENUINE_ARCS
|
|
#ifndef WMAT
|
|
ComputeWMATParabola(e,i1,i2);
|
|
#endif
|
|
#endif
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case(ARC):
|
|
#ifdef GENUINE_ARCS
|
|
#ifndef WMAT
|
|
switch(rtype) {
|
|
case(PNT):
|
|
ComputeWMATHyperbola(e);
|
|
break;
|
|
case(SEG):
|
|
ComputeWMATParabola(e, i2, i1);
|
|
break;
|
|
case(ARC):
|
|
ComputeWMATHyperbola(e);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
#endif
|
|
#endif
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
void vroniObject::ComputeWMAT(double wmat_angle, double wmat_dist,
|
|
vr_bool time, vr_bool left_wmat, vr_bool right_wmat)
|
|
{
|
|
int i, j, not_needed;
|
|
vr_bool unrestricted;
|
|
#ifdef WMAT
|
|
double wmat_dist_sq, wmat_cosine;
|
|
#endif
|
|
|
|
assert(GetVDStatus());
|
|
assert(scale_factor > 0.0);
|
|
|
|
if (GetNodesSqdFlag()) TakeSquareOfNodes();
|
|
if (!GetDeg2Flag()) InsertDegreeTwoNodes();
|
|
|
|
if (wmat_angle < 0.0) wmat_angle = 0.0;
|
|
else if(wmat_angle > M_PI) wmat_angle = M_PI;
|
|
if (wmat_dist < 0.0) wmat_dist = 0.0;
|
|
|
|
#ifdef WMAT
|
|
wmat_dist = ScaleV(wmat_dist);
|
|
wmat_dist_sq = wmat_dist * wmat_dist;
|
|
wmat_cosine = cos(wmat_angle);
|
|
#endif
|
|
if (left_wmat && right_wmat) {
|
|
left_wmat = right_wmat = false;
|
|
}
|
|
|
|
/* */
|
|
/* first call to this function. allocate memory and initialize the */
|
|
/* flags for the edge data. */
|
|
/* */
|
|
#ifdef WMAT
|
|
#ifdef GENUINE_ARCS
|
|
if (num_arcs > 0)
|
|
throw std::runtime_error("VRONI error: ComputeWMAT() - computation of wMAT not supported for circular arcs!");
|
|
#endif
|
|
VD_Info("...computing weighted medial axis -- ");
|
|
#else
|
|
VD_Info("...computing medial axis -- ");
|
|
#endif
|
|
if (time) cpu_time_wmat = elapsed();
|
|
|
|
#ifdef GRAPHICS
|
|
if (graphics) ResetCurBuffer();
|
|
#endif
|
|
unrestricted = !(left_wmat || right_wmat);
|
|
|
|
/* */
|
|
/* allocate memory and initialize the flags for the edge data. */
|
|
/* */
|
|
InitializeEdgeData(unrestricted, left_wmat, false, ¬_needed);
|
|
|
|
/* */
|
|
/* let the user call some application-specific function */
|
|
/* */
|
|
ExtApplFuncWMATInit;
|
|
|
|
j = -1;
|
|
AdvanceActiveEdge(i, j, false);
|
|
while (i != NIL) {
|
|
/* */
|
|
/* compute the WMAT-data for this edge */
|
|
/* */
|
|
#ifdef WMAT
|
|
ComputeWMATEdge(i, wmat_cosine, wmat_dist_sq);
|
|
#else
|
|
ComputeWMATEdge(i);
|
|
#endif
|
|
/* */
|
|
/* let the user call some application-specific function */
|
|
/* */
|
|
ExtApplFuncWMATLoop;
|
|
|
|
AdvanceActiveEdge(i, j, false);
|
|
}
|
|
if (time) cpu_time_wmat = elapsed();
|
|
|
|
VD_Info("done!\n");
|
|
WMAT_computed = true;
|
|
|
|
/* */
|
|
/* let the user call some application-specific function */
|
|
/* */
|
|
ExtApplFuncWMATComputed;
|
|
|
|
#ifdef GRAPHICS
|
|
if (graphics) {
|
|
AddWMATToBuffer();
|
|
}
|
|
#endif
|
|
|
|
#ifdef WMAT
|
|
#ifndef NDEBUG
|
|
CheckWMAT(wmat_dist, wmat_angle);
|
|
#endif
|
|
#endif
|
|
|
|
/* */
|
|
/* let the user call some application-specific function */
|
|
/* */
|
|
ExtApplFuncWMATDone;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/* */
|
|
/* this function adds the edges of the wMAT to VRONI's graphics buffer for */
|
|
/* subsequent graphics display. please note that all conic VD edges are */
|
|
/* approximated by straight-line segments relative to a heuristically chosen */
|
|
/* approximation threshold prior to output! */
|
|
/* */
|
|
#ifdef GRAPHICS
|
|
void vroniObject::AddWMATToBuffer(void)
|
|
{
|
|
double delta_x, delta_y, delta;
|
|
///void SetStepSize(double_arg delta);
|
|
t_site t_lft, t_rgt;
|
|
int num_edges, i, lft, rgt;
|
|
coord u, v;
|
|
#ifdef WMAT
|
|
double t1, t2;
|
|
#else
|
|
double t1, t2, t;
|
|
int n1, n2;
|
|
coord dummy;
|
|
#endif
|
|
|
|
num_edges = GetNumberOfEdges();
|
|
|
|
/* */
|
|
/* compute the discretization threshold for approximating non-linear */
|
|
/* bisectors. */
|
|
/* */
|
|
delta_x = bb_max.x - bb_min.x;
|
|
delta_y = bb_max.y - bb_min.y;
|
|
delta = Max(delta_x, delta_y);
|
|
if (le(delta, ZERO)) delta = ZERO;
|
|
SetStepSize(delta);
|
|
|
|
for (i = 4; i < num_edges; ++i) {
|
|
if (IsWmatEdge(i)) {
|
|
#ifdef WMAT
|
|
t1 = GetWmatRMin(i);
|
|
t2 = GetWmatRMax(i);
|
|
#else
|
|
n1 = GetStartNode(i);
|
|
n2 = GetEndNode(i);
|
|
GetNodeData(n1, &u, &t1);
|
|
GetNodeData(n2, &v, &t2);
|
|
if (t2 < t1) {
|
|
Swap(t1, t2, t);
|
|
Swap(u, v, dummy);
|
|
}
|
|
#endif
|
|
GetLftSiteData(i, &lft, &t_lft);
|
|
GetRgtSiteData(i, &rgt, &t_rgt);
|
|
switch(t_lft) {
|
|
case(PNT):
|
|
switch(t_rgt) {
|
|
case(PNT): /* PNT-PNT: line (hyperbola) bisector */
|
|
#ifdef WMAT
|
|
EvaluateHyperbolaData(i, t1, &u);
|
|
EvaluateHyperbolaData(i, t2, &v);
|
|
#endif
|
|
AddEdgeToBuffer(u.x, u.y, v.x, v.y, WMATColor);
|
|
break;
|
|
case(SEG): /* PNT-SEG: parabola bisector */
|
|
#ifdef WMAT
|
|
if (IsSegStartPnt(rgt, lft) || IsSegEndPnt(rgt, lft)) {
|
|
EvaluateLineData(i, t1, &u);
|
|
EvaluateLineData(i, t2, &v);
|
|
}
|
|
else {
|
|
EvaluateParabolaData(i, rgt, t1, &u);
|
|
EvaluateParabolaData(i, rgt, t2, &v);
|
|
}
|
|
#endif
|
|
AddParabolaToBuffer(i, t1, t2, u, v, WMATColor);
|
|
break;
|
|
case(ARC):
|
|
#ifdef GENUINE_ARCS
|
|
AddHyperbolaEllipseToBuffer(i, t1, t2, u, v, WMATColor);
|
|
#endif
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case(SEG):
|
|
switch(t_rgt) {
|
|
case(PNT): /* SEG-PNT: parabola bisector */
|
|
#ifdef WMAT
|
|
if (IsSegStartPnt(lft, rgt) || IsSegEndPnt(lft, rgt)) {
|
|
EvaluateLineData(i, t1, &u);
|
|
EvaluateLineData(i, t2, &v);
|
|
}
|
|
else {
|
|
EvaluateParabolaData(i, lft, t1, &u);
|
|
EvaluateParabolaData(i, lft, t2, &v);
|
|
}
|
|
#endif
|
|
AddParabolaToBuffer(i, t1, t2, u, v, WMATColor);
|
|
break;
|
|
case(SEG): /* SEG-SEG: line bisector */
|
|
#ifdef WMAT
|
|
if (GetEdgeFlagDeg(i)) {
|
|
GetNodeData(GetStartNode(i), &u, &t1);
|
|
GetNodeData(GetEndNode(i), &v, &t2);
|
|
}
|
|
else {
|
|
EvaluateLineData(i, t1, &u);
|
|
EvaluateLineData(i, t2, &v);
|
|
}
|
|
#endif
|
|
AddEdgeToBuffer(u.x, u.y, v.x, v.y, WMATColor);
|
|
break;
|
|
case(ARC):
|
|
#ifdef GENUINE_ARCS
|
|
AddParabolaToBuffer(i, t1, t2, u, v, WMATColor);
|
|
#endif
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case(ARC):
|
|
#ifdef GENUINE_ARCS
|
|
switch(t_rgt) {
|
|
case(PNT):
|
|
#ifdef WMAT
|
|
if (IsArcStartPnt(lft, rgt) || IsArcEndPnt(lft, rgt)) {
|
|
EvaluateLineData(i, t1, &u);
|
|
EvaluateLineData(i, t2, &v);
|
|
}
|
|
else {
|
|
EvaluateParabolaData(i, lft, t1, &u);
|
|
EvaluateParabolaData(i, lft, t2, &v);
|
|
}
|
|
#endif
|
|
AddHyperbolaEllipseToBuffer(i, t1, t2, u, v, WMATColor);
|
|
break;
|
|
case(SEG):
|
|
#ifdef WMAT
|
|
if (GetEdgeFlagDeg(i)) {
|
|
GetNodeData(GetStartNode(i), &u, &t1);
|
|
GetNodeData(GetEndNode(i), &v, &t2);
|
|
}
|
|
else {
|
|
EvaluateLineData(i, t1, &u);
|
|
EvaluateLineData(i, t2, &v);
|
|
}
|
|
#endif
|
|
AddParabolaToBuffer(i, t1, t2, u, v, WMATColor);
|
|
break;
|
|
case(ARC):
|
|
AddHyperbolaEllipseToBuffer(i, t1, t2, u, v, WMATColor);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
#endif
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef EXT_APPL_WMAT
|
|
eam_type vroniObject::GetExtApplWMAT(int E)
|
|
{
|
|
assert(InEdgesList(E));
|
|
return edges[E].w_mat.ext_appl;
|
|
}
|
|
|
|
|
|
void vroniObject::SetExtApplWMAT(int E, eam_type ext_appl)
|
|
{
|
|
assert(InEdgesList(E));
|
|
edges[E].w_mat.ext_appl = ext_appl;
|
|
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#include "ext_appl_wmat.cc"
|
|
|
|
|
|
#endif
|
|
|
|
|