f3e15b8c8d
- aggiunti file della libreria e progetto visual studio.
835 lines
29 KiB
C++
835 lines
29 KiB
C++
/*****************************************************************************/
|
|
/* */
|
|
/* Copyright (C) 2002--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-172 */
|
|
/* 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>
|
|
#include <limits.h>
|
|
|
|
/* */
|
|
/* get my header files */
|
|
/* */
|
|
#include "fpkernel.h"
|
|
#include "vronivector.h"
|
|
#include "vroni_object.h"
|
|
#include "defs.h"
|
|
#include "numerics.h"
|
|
|
|
|
|
|
|
void vroniObject::SetPreprocessingThreshold(double_arg threshold)
|
|
{
|
|
if (!ThresholdReached()) preProZero = threshold * 10.0;
|
|
else preProZero = ZERO_IO;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
/* */
|
|
/* computes the line equations for all segments; very short segments are */
|
|
/* discarded and their endpoints are merged. */
|
|
/* */
|
|
void vroniObject::PreprocessSegments(int *num_critical_segs)
|
|
{
|
|
int i, i1, i2;
|
|
coord p, q, vec;
|
|
double dist, c, d, foo;
|
|
int number = 0;
|
|
vr_bool remove_segments = false;
|
|
|
|
for (i = 0; i < num_segs; ++i) {
|
|
p = GetSegStartCoord(i);
|
|
q = GetSegEndCoord(i);
|
|
vec = VecSub(q, p);
|
|
dist = VecLen(vec);
|
|
/* */
|
|
/* check whether the segment length is less than VRONI's threshold. if */
|
|
/* a segment is too short then we merge its endpoints and (lateron) */
|
|
/* delete that segment. care is taken that all other segments incident */
|
|
/* upon one of those two endpoints are updated accordingly. */
|
|
/* */
|
|
if (le(dist, preProZero)) {
|
|
if ((p.x != q.x) || (p.y != q.y)) {
|
|
if (GetDataSorted()) {
|
|
VD_IO_Warning("PreprocessSegments() - line segment too short!");
|
|
#ifdef VRONI_IO_WARN
|
|
printf("%20.16f %20.16f %20.16f %20.16f\n",
|
|
UnscaleX(p.x), UnscaleY(p.y),
|
|
UnscaleX(q.x), UnscaleY(q.y));
|
|
#endif
|
|
i1 = Get1stVtx(i, SEG);
|
|
i2 = Get2ndVtx(i, SEG);
|
|
MergePoints(i1, i2);
|
|
if (i1 > i2) {
|
|
RepairPntLinks(i1, i2, true);
|
|
SetDeletedPnt(i1, true);
|
|
}
|
|
else {
|
|
RepairPntLinks(i2, i1, true);
|
|
SetDeletedPnt(i2, true);
|
|
}
|
|
restart = true;
|
|
}
|
|
else {
|
|
/* */
|
|
/* we need to identify and eliminate duplicate vertices prior */
|
|
/* to merging any pair of vertices. */
|
|
/* */
|
|
VD_IO_Warning("PreprocessSegments() - line segment too short!");
|
|
#ifdef VRONI_IO_WARN
|
|
printf("%20.16f %20.16f %20.16f %20.16f\n",
|
|
UnscaleX(p.x), UnscaleY(p.y),
|
|
UnscaleX(q.x), UnscaleY(q.y));
|
|
#endif
|
|
restart = true;
|
|
return;
|
|
}
|
|
}
|
|
else {
|
|
/* */
|
|
/* this is a zero-length segment. it is deleted later in another */
|
|
/* call to CleanData(). */
|
|
/* */
|
|
VD_IO_Warning("PreprocessSegments() - zero-length segment!");
|
|
#ifdef VRONI_IO_WARN
|
|
printf("%20.16f %20.16f %20.16f %20.16f\n",
|
|
UnscaleX(p.x), UnscaleY(p.y),
|
|
UnscaleX(q.x), UnscaleY(q.y));
|
|
#endif
|
|
remove_segments = true;
|
|
}
|
|
}
|
|
else {
|
|
/* */
|
|
/* this is a normal segment. we compute the (Hessian) equation of */
|
|
/* of its supporting line. */
|
|
/* */
|
|
if (lt(dist, preProZero)) ++number;
|
|
vec = VecDiv(dist, vec);
|
|
c = vec.y * p.x - vec.x * p.y;
|
|
SetSegEqnData(i, -vec.y, vec.x, c);
|
|
foo = PntLineDist(-vec.y, vec.x, c, q);
|
|
if (!(eq(foo, ZERO))) {
|
|
/* */
|
|
/* the other endpoint does not satisfy that line's equation, for */
|
|
/* reasons unknown. we adjust the constant as good as this is */
|
|
/* possible on a floating-point arithmetic... */
|
|
/* */
|
|
VD_Warning("PreprocessSegments() - problematic seg equation!");
|
|
numerical = true;
|
|
d = vec.y * q.x - vec.x * q.y;
|
|
c = (c + d) / 2.0;
|
|
SetSegEqnData(i, -vec.y, vec.x, c);
|
|
}
|
|
SetSegLgth(i, dist);
|
|
}
|
|
}
|
|
|
|
if (remove_segments) restart = true;
|
|
*num_critical_segs = number;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
/* */
|
|
/* break up arcs that are larger than a quarter-circle and adjust the center */
|
|
/* of an arc if its radii differ. */
|
|
/* */
|
|
void vroniObject::AdjustArcs(int *num_critical_arcs)
|
|
{
|
|
double orient, dist, diff, radius, radius1, radius2, delta;
|
|
coord s, e, c, vec, m, nor, start, end;
|
|
int i, i1, i2;
|
|
int number;
|
|
|
|
double secdist;
|
|
|
|
#ifndef NDEBUG
|
|
int s_orient;
|
|
#endif
|
|
#ifdef EXT_APPL_SITES
|
|
eas_type ext_appl;
|
|
#endif
|
|
vr_bool remove_arcs = false;
|
|
|
|
*num_critical_arcs = 0;
|
|
|
|
for (i = 0; i < num_arcs; ++i) {
|
|
s = GetArcStartCoord(i);
|
|
e = GetArcEndCoord(i);
|
|
vec = VecSub(s, e);
|
|
dist = VecLen(vec);
|
|
if (le(dist, preProZero)) {
|
|
if ((s.x != e.x) || (s.y != e.y)) {
|
|
if (GetDataSorted()) {
|
|
VD_IO_Warning("AdjustArcs() - chord length too short!");
|
|
#ifdef VRONI_IO_WARN
|
|
c = GetArcCenter(i);
|
|
printf("%20.16f %20.16f %20.16f %20.16f %20.16f %20.16f\n",
|
|
UnscaleX(s.x), UnscaleY(s.y),
|
|
UnscaleX(e.x), UnscaleY(e.y),
|
|
UnscaleX(c.x), UnscaleY(c.y));
|
|
#endif
|
|
i1 = Get1stVtx(i, ARC);
|
|
i2 = Get2ndVtx(i, ARC);
|
|
MergePoints(i1, i2);
|
|
if (i1 > i2) {
|
|
RepairPntLinks(i1, i2, true);
|
|
SetDeletedPnt(i1, true);
|
|
}
|
|
else {
|
|
RepairPntLinks(i2, i1, true);
|
|
SetDeletedPnt(i2, true);
|
|
}
|
|
restart = true;
|
|
}
|
|
else {
|
|
/* */
|
|
/* we need to identify and eliminate duplicate vertices prior */
|
|
/* to merging any pair of vertices. */
|
|
/* */
|
|
VD_IO_Warning("AdjustArcs() - chord length too short!");
|
|
#ifdef VRONI_IO_WARN
|
|
c = GetArcCenter(i);
|
|
printf("%20.16f %20.16f %20.16f %20.16f %20.16f %20.16f\n",
|
|
UnscaleX(s.x), UnscaleY(s.y),
|
|
UnscaleX(e.x), UnscaleY(e.y),
|
|
UnscaleX(c.x), UnscaleY(c.y));
|
|
#endif
|
|
restart = true;
|
|
return;
|
|
}
|
|
}
|
|
else {
|
|
/* */
|
|
/* this is a zero-length arc. it is deleted later in another */
|
|
/* call to CleanData(). */
|
|
/* */
|
|
remove_arcs = true;
|
|
}
|
|
}
|
|
}
|
|
if (remove_arcs) restart = true;
|
|
if (restart) return;
|
|
|
|
number = 0;
|
|
i = 0;
|
|
while (i < num_arcs) {
|
|
s = GetArcStartCoord(i);
|
|
e = GetArcEndCoord(i);
|
|
c = GetArcCenter(i);
|
|
orient = VecDet(c, s, e);
|
|
if (orient < 0.0) {
|
|
vec = VecSub(s, e);
|
|
}
|
|
else {
|
|
vec = VecSub(e, s);
|
|
}
|
|
#ifndef NDEBUG
|
|
s_orient = SignEps(orient, ZERO);
|
|
#endif
|
|
dist = VecLen(vec);
|
|
delta = dist / 2.0;
|
|
#ifdef EXT_APPL_SITES
|
|
ext_appl = GetExtApplArc(i);
|
|
#endif
|
|
|
|
/* */
|
|
/* compute "the" radius. */
|
|
/* */
|
|
radius1 = PntPntDist(s, c);
|
|
radius2 = PntPntDist(e, c);
|
|
radius = (radius1 + radius2) / 2.0;
|
|
|
|
start = VecSub(s, c);
|
|
end = VecSub(e, c);
|
|
|
|
secdist = radius*radius - PntPntDistSq(s,e)/4.0;
|
|
if (secdist <= 0.0) secdist = radius;
|
|
else secdist = radius - sqrt(secdist);
|
|
|
|
if (radius <= preProZero) {
|
|
/* */
|
|
/* this arc has a tiny radius! */
|
|
/* */
|
|
VD_IO_Warning("AdjustArcs() - radius too small!");
|
|
#ifdef VRONI_IO_WARN
|
|
printf("%20.16f %20.16f %20.16f %20.16f %20.16f %20.16f\n",
|
|
UnscaleX(s.x), UnscaleY(s.y), UnscaleX(e.x), UnscaleY(e.y),
|
|
UnscaleX(c.x), UnscaleY(c.y));
|
|
#endif
|
|
numerical = true;
|
|
i1 = Get1stVtx(i, ARC);
|
|
i2 = Get2ndVtx(i, ARC);
|
|
#ifdef EXT_APPL_SITES
|
|
if (GetArcOrientation(i)) StoreSeg(i1, i2, ext_appl);
|
|
else StoreSeg(i2, i1, ext_appl);
|
|
#else
|
|
if (GetArcOrientation(i)) StoreSeg(i1, i2);
|
|
else StoreSeg(i2, i1);
|
|
#endif
|
|
RemoveArc(i);
|
|
}
|
|
else if(le(secdist, preProZero) || le(secdist/radius, preProZero)) {
|
|
/* */
|
|
/* The maximum radial distance between arc and its secant is less */
|
|
/* less than eps. */
|
|
/* */
|
|
VD_IO_Warning("AdjustArcs() - arc is almost segment!");
|
|
#ifdef VRONI_IO_WARN
|
|
printf("%20.16f %20.16f %20.16f %20.16f %20.16f %20.16f\n",
|
|
UnscaleX(s.x), UnscaleY(s.y), UnscaleX(e.x), UnscaleY(e.y),
|
|
UnscaleX(c.x), UnscaleY(c.y));
|
|
#endif
|
|
numerical = true;
|
|
i1 = Get1stVtx(i, ARC);
|
|
i2 = Get2ndVtx(i, ARC);
|
|
#ifdef EXT_APPL_SITES
|
|
if (GetArcOrientation(i)) StoreSeg(i1, i2, ext_appl);
|
|
else StoreSeg(i2, i1, ext_appl);
|
|
#else
|
|
if (GetArcOrientation(i)) StoreSeg(i1, i2);
|
|
else StoreSeg(i2, i1);
|
|
#endif
|
|
RemoveArc(i);
|
|
}
|
|
else {
|
|
diff = (radius1 - radius2);
|
|
if (ne(diff, ZERO)) {
|
|
/* */
|
|
/* the radii differ! we'll adjust the center... */
|
|
/* */
|
|
VD_IO_Warning("AdjustArcs() - center of arc adjusted!");
|
|
#ifdef VRONI_IO_WARN
|
|
printf("%20.16f %20.16f %20.16f %20.16f %20.16f %20.16f\n",
|
|
UnscaleX(s.x), UnscaleY(s.y), UnscaleX(e.x), UnscaleY(e.y),
|
|
UnscaleX(c.x), UnscaleY(c.y));
|
|
#endif
|
|
m = MidPoint(s, e);
|
|
nor = VecCCW(vec);
|
|
diff = radius * radius - delta * delta;
|
|
if (diff <= 0.0) diff = 0.0;
|
|
else diff = sqrt(diff) / dist;
|
|
nor = VecMult(diff, nor);
|
|
m = VecAdd(m, nor);
|
|
orient = VecDet(m, s, e);
|
|
#ifndef NDEBUG
|
|
assert((SignEps(orient, ZERO) == 0) || (s_orient == 0) ||
|
|
(SignEps(orient, ZERO) == s_orient));
|
|
#endif
|
|
radius1 = PntPntDist(s, m);
|
|
radius2 = PntPntDist(e, m);
|
|
radius = (radius1 + radius2) / 2.0;
|
|
assert(eq(radius1 - radius2, ZERO_MAX));
|
|
SetArcCenter(i, m);
|
|
++number;
|
|
}
|
|
else {
|
|
radius = (radius1 + radius2) / 2.0;
|
|
}
|
|
assert(radius > preProZero);
|
|
SetArcRadius(i, radius);
|
|
//printf("radius %30.16f\n", radius);
|
|
++i;
|
|
}
|
|
}
|
|
|
|
*num_critical_arcs = number;
|
|
if (remove_arcs) restart = true;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
/* */
|
|
/* arcs that are close to (or greater than) a semi-circle are broken */
|
|
/* up into pieces that are clearly smaller than a semi-circle. also, */
|
|
/* "the" radius of the circular arc is computed, and, if necessary, a */
|
|
/* new center is computed. */
|
|
/* */
|
|
/* note that we store all input arcs as CCW arcs! */
|
|
/* */
|
|
void vroniObject::PreprocessArcs(int *num_critical_arcs)
|
|
{
|
|
double orient, radius, a, b;
|
|
double dist, cosine;
|
|
coord s, e, c, cs, ce, vec, split, norm;
|
|
int i, i2;
|
|
#ifdef TRACE
|
|
vr_bool trace_prep = false;
|
|
#endif
|
|
|
|
/* */
|
|
/* make sure that all circular arcs have consistent radii. if necessary, */
|
|
/* we'll adjust the centers!! */
|
|
/* */
|
|
AdjustArcs(num_critical_arcs);
|
|
if (restart) return;
|
|
|
|
for (i = 0; i < num_arcs; ++i) {
|
|
s = GetArcStartCoord(i);
|
|
e = GetArcEndCoord(i);
|
|
c = GetArcCenter(i);
|
|
radius = GetArcRadius(i);
|
|
assert(radius > preProZero);
|
|
orient = VecDet(c, s, e);
|
|
|
|
//Get CW oriented p1-p2 vector.
|
|
if (orient < 0.0) {
|
|
vec = VecSub(s, e);
|
|
}
|
|
else {
|
|
vec = VecSub(e, s);
|
|
}
|
|
|
|
|
|
//Secant length and and arms-vectors
|
|
dist = VecLen(vec);
|
|
cs = VecSub(s, c);
|
|
ce = VecSub(e, c);
|
|
//Cosine of the angle of arc
|
|
cosine = VecDotProd(cs, ce) / (radius * radius);
|
|
|
|
//printf("arc%d c=(%e,%e), s=(%e,%e), e=(%e,%e)\n", i, c.x, c.y, s.x, s.y, e.x, e.y);
|
|
//printf("\tcs=(%e,%e), ce=(%e,%e), radius=%e\n", cs.x, cs.y, ce.x, ce.y, radius);
|
|
//printf("\tcosine: %e, orient: %e\n", cosine, orient);
|
|
|
|
|
|
//Almost a full circle --> split circle to quarter-circle
|
|
if ((Abs(1.0-cosine) <= SMALL) && (orient < 0.0)) {
|
|
VD_IO_Warning("PreprocessArcs() - arc equals full circle!");
|
|
#ifdef VRONI_IO_WARN
|
|
printf("%20.16f %20.16f %20.16f %20.16f %20.16f %20.16f\n",
|
|
UnscaleX(s.x), UnscaleY(s.y),
|
|
UnscaleX(e.x), UnscaleY(e.y),
|
|
UnscaleX(c.x), UnscaleY(c.y));
|
|
#endif
|
|
norm = VecCCW(cs);
|
|
|
|
split = VecSub(c, norm);
|
|
#ifdef EXT_APPL_PNTS
|
|
i2 = StorePnt(split.x, split.y, eap_NIL);
|
|
#else
|
|
i2 = StorePnt(split.x, split.y);
|
|
#endif
|
|
(void) SplitArc(i, i2);
|
|
|
|
|
|
split = VecSub(c, cs);
|
|
#ifdef EXT_APPL_PNTS
|
|
i2 = StorePnt(split.x, split.y, eap_NIL);
|
|
#else
|
|
i2 = StorePnt(split.x, split.y);
|
|
#endif
|
|
(void) SplitArc(i, i2);
|
|
|
|
|
|
split = VecAdd(c, norm);
|
|
#ifdef EXT_APPL_PNTS
|
|
i2 = StorePnt(split.x, split.y, eap_NIL);
|
|
#else
|
|
i2 = StorePnt(split.x, split.y);
|
|
#endif
|
|
(void) SplitArc(i, i2);
|
|
restart = true;
|
|
}
|
|
//Larger than quarter circle, smaller than semi-circle --> split it
|
|
//else if( cosine<0 && orient>=0 )
|
|
else if((Abs(cosine+1.0) <= SMALL) && (orient >= 0.0)) {
|
|
VD_IO_Warning("PreprocessArcs() - (almost) semi-circle!");
|
|
#ifdef VRONI_IO_WARN
|
|
printf("%20.16f %20.16f %20.16f %20.16f %20.16f %20.16f\n",
|
|
UnscaleX(s.x), UnscaleY(s.y), UnscaleX(e.x), UnscaleY(e.y),
|
|
UnscaleX(c.x), UnscaleY(c.y));
|
|
#endif
|
|
split = VecCCW(vec);
|
|
split = VecMult( -radius/dist, split);
|
|
|
|
split = VecAdd(c, split);
|
|
//printf("\tsplit at (%e,%e)\n", split.x, split.y);
|
|
#ifdef EXT_APPL_PNTS
|
|
i2 = StorePnt(split.x, split.y, eap_NIL);
|
|
#else
|
|
i2 = StorePnt(split.x, split.y);
|
|
#endif
|
|
(void) SplitArc(i, i2);
|
|
restart = true;
|
|
}
|
|
//Larger than semi-circle --> put it into four pieces
|
|
else if (orient < 0.0 ) {
|
|
VD_IO_Warning("PreprocessArcs() - larger than semi-circle!");
|
|
#ifdef VRONI_IO_WARN
|
|
printf("%20.16f %20.16f %20.16f %20.16f %20.16f %20.16f\n",
|
|
UnscaleX(s.x), UnscaleY(s.y),
|
|
UnscaleX(e.x), UnscaleY(e.y),
|
|
UnscaleX(c.x), UnscaleY(c.y));
|
|
#endif
|
|
split = VecCCW(vec);
|
|
split = VecMult( radius/dist, split);
|
|
|
|
split = VecAdd(c, split);
|
|
//printf("\tsplit at (%e,%e)\n", split.x, split.y);
|
|
#ifdef EXT_APPL_PNTS
|
|
i2 = StorePnt(split.x, split.y, eap_NIL);
|
|
#else
|
|
i2 = StorePnt(split.x, split.y);
|
|
#endif
|
|
(void) SplitArc(i, i2);
|
|
restart = true;
|
|
}
|
|
|
|
/* */
|
|
/* set the unit normal vectors at the start point and the end */
|
|
/* point */
|
|
/* */
|
|
#ifdef VRONI_WARN
|
|
if (!eq(VecLen(cs)-radius, ZERO_MAX)) {
|
|
printf("arc %d\n", i);
|
|
printf("distance1 = %20.16f, zero_max = %20.16f\n",
|
|
VecLen(cs)-radius, ZERO_MAX);
|
|
printf("distance2 = %20.16f, zero_max = %20.16f\n",
|
|
VecLen(ce)-radius, ZERO_MAX);
|
|
}
|
|
if (!eq(VecLen(ce)-radius, ZERO_MAX)) {
|
|
printf("arc %d\n", i);
|
|
printf("distance1 = %20.16f, zero_max = %20.16f\n",
|
|
VecLen(cs)-radius, ZERO_MAX);
|
|
printf("distance2 = %20.16f, zero_max = %20.16f\n",
|
|
VecLen(ce)-radius, ZERO_MAX);
|
|
}
|
|
#endif
|
|
assert( eq(VecLen(cs)-radius, ZERO_MAX));
|
|
assert( eq(VecLen(ce)-radius, ZERO_MAX));
|
|
cs = VecDiv(radius, cs);
|
|
ce = VecDiv(radius, ce);
|
|
#ifdef TRACE
|
|
if (trace_prep) {
|
|
if (!eq(VecLen(cs) - 1.0, ZERO) ||
|
|
!eq(VecLen(ce) - 1.0, ZERO)) {
|
|
printf("radius: %24.20f\n", radius);
|
|
printf("arc %d: VecLen(cs) = %24.20f\n",
|
|
i, VecLen(cs));
|
|
printf("arc %d: VecLen(ce) = %24.20f\n",
|
|
i, VecLen(ce));
|
|
}
|
|
}
|
|
#endif
|
|
SetArcStartNormal(i, cs);
|
|
SetArcEndNormal(i, ce);
|
|
|
|
/* */
|
|
/* compute the line equation of the chord */
|
|
/* */
|
|
if (gt(dist,ZERO)) {
|
|
vec = VecDiv(dist, vec);
|
|
a = vec.y * s.x - vec.x * s.y;
|
|
SetChordEqnData(i, -vec.y, vec.x, a);
|
|
b = PntLineDist(-vec.y, vec.x, a, e);
|
|
if (!(eq(b, ZERO))) {
|
|
VD_Warning("PreprocessArcs() - problematic chord equation");
|
|
numerical = true;
|
|
b = vec.y * e.x - vec.x * e.y;
|
|
a = (a + b) / 2.0;
|
|
SetChordEqnData(i, -vec.y, vec.x, a);
|
|
}
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
void vroniObject::ExtendBoundingBox(void)
|
|
{
|
|
double radius, delta;
|
|
coord p1, p2, p3;
|
|
int i, k, k1, k2;
|
|
|
|
for (i = 0; i < num_arcs; ++i) {
|
|
p1 = GetArcStartCoord(i);
|
|
p2 = GetArcEndCoord(i);
|
|
p3 = GetArcCenter(i);
|
|
radius = GetArcRadius(i);
|
|
|
|
if (p1.x >= p3.x) {
|
|
if (p1.y >= p3.y) k1 = 0;
|
|
else k1 = 3;
|
|
}
|
|
else {
|
|
if (p1.y >= p3.y) k1 = 1;
|
|
else k1 = 2;
|
|
}
|
|
if (p2.x >= p3.x) {
|
|
if (p2.y >= p3.y) k2 = 0;
|
|
else k2 = 3;
|
|
}
|
|
else {
|
|
if (p2.y >= p3.y) k2 = 1;
|
|
else k2 = 2;
|
|
}
|
|
|
|
if (k2 < k1) {
|
|
k2 += 4;
|
|
}
|
|
else if (k1 == k2) {
|
|
if (k1 == 0) {
|
|
if ((p1.x < p2.x) && (p1.y > p2.y)) k2 = 4;
|
|
}
|
|
else if (k1 == 1) {
|
|
if ((p1.x < p2.x) && (p1.y < p2.y)) k2 = 5;
|
|
}
|
|
else if (k1 == 2) {
|
|
if ((p1.x > p2.x) && (p1.y < p2.y)) k2 = 6;
|
|
}
|
|
else if (k1 == 3) {
|
|
if ((p1.x > p2.x) && (p1.y > p2.y)) k2 = 7;
|
|
}
|
|
}
|
|
|
|
for (k = k1; k < k2; ++k) {
|
|
switch(k) {
|
|
case 0:
|
|
case 4:
|
|
delta = p3.y + radius;
|
|
if (delta > bb_max.y) {
|
|
bb_max.y = delta;
|
|
}
|
|
break;
|
|
case 1:
|
|
case 5:
|
|
delta = p3.x - radius;
|
|
if (delta < bb_min.x) {
|
|
bb_min.x = delta;
|
|
}
|
|
break;
|
|
case 2:
|
|
case 6:
|
|
delta = p3.y - radius;
|
|
if (delta < bb_min.y) {
|
|
bb_min.y = delta;
|
|
}
|
|
break;
|
|
case 3:
|
|
case 7:
|
|
delta = p3.x + radius;
|
|
if (delta > bb_max.x) {
|
|
bb_max.x = delta;
|
|
}
|
|
break;
|
|
default:
|
|
assert(0 == 1);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
bb_min.x -= ZERO_MAX;
|
|
bb_min.y -= ZERO_MAX;
|
|
bb_max.x += ZERO_MAX;
|
|
bb_max.y += ZERO_MAX;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
void vroniObject::HandleBulge(const coord & p1, /* start point of arc */
|
|
const coord & p2, /* end point of arc */
|
|
double *bulge, /* bulge factor */
|
|
coord *center, /* center of arc */
|
|
double *radius, /* radius of arc */
|
|
int *attr) /* SEG, ARC or -ARC */
|
|
{
|
|
coord v, q;
|
|
double s, d;
|
|
|
|
if (eq(*bulge, ZERO)) {
|
|
/* */
|
|
/* circular arc degenerates to line segment */
|
|
/* */
|
|
*bulge = 0.0;
|
|
*attr = SEG;
|
|
return;
|
|
}
|
|
|
|
if (Abs(*bulge) > 1.0) {
|
|
/* */
|
|
/* this arc spans more than 180 degrees! if beta == 90 - alpha then */
|
|
/* tan beta = cot alpha; i.e., tan beta = 1 / bulge, where beta is */
|
|
/* one quarter of the included angle of the complementary arc! we can */
|
|
/* proceed as normal after inverting the direction vector v from the */
|
|
/* start point to the end point of the arc. */
|
|
/* */
|
|
*bulge = 1.0 / *bulge;
|
|
v = VecSub(p1, p2);
|
|
}
|
|
else {
|
|
v = VecSub(p2, p1);
|
|
}
|
|
d = VecLen(v);
|
|
if (eq(d, ZERO)) {
|
|
/* */
|
|
/* chord length too small; we replace the arc by a line segment. note: */
|
|
/* this might mishandle arcs that are close to a full circle! */
|
|
/* */
|
|
*bulge = 0.0;
|
|
*attr = SEG;
|
|
return;
|
|
}
|
|
|
|
*radius = d *(1.0 + *bulge * *bulge) / (4.0 * *bulge); /* radius */
|
|
s = *radius - d * *bulge / 2.0; /* radial offset */
|
|
q = MidPoint(p1, p2);
|
|
center->x = q.x - s * v.y / d;
|
|
center->y = q.y + s * v.x / d;
|
|
if (*radius < 0.0) *radius = - *radius;
|
|
if (*bulge > 0) *attr = ARC;
|
|
else *attr = - ARC;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
void vroniObject::ComputeBulge(const coord & p1, const coord & p2,
|
|
double *bulge, const coord & center,
|
|
double_arg radius, int attr)
|
|
{
|
|
coord v, q, w;
|
|
double s, d, delta;
|
|
|
|
if ((attr != ARC) && (attr != -ARC)) {
|
|
/* */
|
|
/* not a circular arc! */
|
|
/* */
|
|
*bulge = 0.0;
|
|
}
|
|
else {
|
|
v = VecSub(p2, p1);
|
|
d = VecLen(v);
|
|
if (eq(d, ZERO)) {
|
|
/* */
|
|
/* chord length too small; we replace arc by a line segment */
|
|
/* */
|
|
*bulge = 0.0;
|
|
}
|
|
else {
|
|
q = MidPoint(p1, p2);
|
|
w = VecSub(center, q);
|
|
s = VecLen(w);
|
|
*bulge = (radius - s) * 2.0 / d;
|
|
if (attr == ARC) {
|
|
delta = - w.x * v.y + w.y * v.x;
|
|
}
|
|
else {
|
|
delta = w.x * v.y - w.y * v.x;
|
|
*bulge = - *bulge;
|
|
}
|
|
|
|
/* */
|
|
/* check whether the arc spans more than 180 degrees! */
|
|
/* */
|
|
if (delta < 0.0) {
|
|
if (!eq(*bulge, ZERO)) {
|
|
*bulge = 1.0 / *bulge;
|
|
}
|
|
else {
|
|
/* */
|
|
/* this seems to be a gigantic arc that is close to a full */
|
|
/* circle, and bulge should be +/- infinity... we'll use a */
|
|
/* value that won't cause headaches in any subsequent */
|
|
/* processing. */
|
|
/* */
|
|
if (*bulge < 0.0) *bulge = (double) INT_MAX;
|
|
else *bulge = (double) INT_MIN;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void vroniObject::ReplaceArc(int i)
|
|
{
|
|
#ifdef EXT_APPL_SITES
|
|
eas_type ext_appl;
|
|
#endif
|
|
int i1, i2;
|
|
|
|
i1 = Get1stVtx(i, ARC);
|
|
i2 = Get2ndVtx(i, ARC);
|
|
#ifdef EXT_APPL_SITES
|
|
if (GetArcOrientation(i)) StoreSeg(i1, i2, ext_appl);
|
|
else StoreSeg(i2, i1, ext_appl);
|
|
#else
|
|
if (GetArcOrientation(i)) StoreSeg(i1, i2);
|
|
else StoreSeg(i2, i1);
|
|
#endif
|
|
RemoveArc(i);
|
|
|
|
restart_due_to_intersection = true;
|
|
numerical = true;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void vroniObject::ReplaceSeg(int i)
|
|
{
|
|
int i1, i2;
|
|
|
|
i1 = Get1stVtx(i, SEG);
|
|
i2 = Get2ndVtx(i, SEG);
|
|
|
|
MergePoints(i1, i2);
|
|
if (i1 > i2) {
|
|
RepairPntLinks(i1, i2, true);
|
|
SetDeletedPnt(i1, true);
|
|
}
|
|
else {
|
|
RepairPntLinks(i2, i1, true);
|
|
SetDeletedPnt(i2, true);
|
|
}
|
|
|
|
restart_due_to_intersection = true;
|
|
numerical = true;
|
|
|
|
return;
|
|
}
|
|
|