Files
SaraP 739088af9f Vroni 7.8 :
- aggiornamento versione.
2025-01-29 16:24:30 +01:00

1245 lines
42 KiB
C++

/*****************************************************************************/
/* */
/* Copyright (C) 2000-2025 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 */
/* */
/*****************************************************************************/
/* */
/* this file contains sample routines for computing VD-based offsets. */
/* */
/* please_ understand that those routines are meant as nothing but as */
/* samples to show how the VD can be used to compute offsets, and to */
/* highlight the use of the macros necessary for accessing the VD. those */
/* routines are _not_ intended to be regarded as a fully fledged code for */
/* generating tool paths, or for performing sophisticated multiple buffering */
/* in a GIS application. frankly stated, there are just too many diverse */
/* requirements with respect to offsetting to make it feasible for me to */
/* offer a general-purpose offsetting code without making it utterly */
/* complicated... */
/* */
/* that is, if the offsetting scheme implemented does not fit your needs, */
/* and if it doesn't look like you could use "exterior application macros" */
/* to influence the behavior of my code from outside to get it to generate */
/* offsets the way you want them generated, then, please, use my routines as */
/* a blue print for your own offsetting code, rather than to ask me to add */
/* specific features to my offsetting code in order to customize it for your */
/* purposes. needless to say, you are encouraged to use my macros for */
/* accessing my data structures. (i will strive to keep the I/O specs of all */
/* my access macros!) */
/* */
/*****************************************************************************/
/* */
/* get standard libraries */
/* */
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <math.h>
#include <assert.h>
#include <float.h>
/* */
/* get my header files */
/* */
#include "fpkernel.h"
#include "vronivector.h"
#include "vroni_object.h"
#include "defs.h"
#include "offset.h"
#include "numerics.h"
#include "io_dxf.h"
void vroniObject::SetMaxOffset(double_arg t)
{
max_t_offset = t;
return;
}
vr_bool vroniObject::InOffsetData(int I)
{
return ((I >= 0) && (I < num_offset_data) &&
(num_offset_data <= max_num_offset_data));
}
vr_bool vroniObject::InOffsetList(int I)
{
return ((I >= 0) && (I < num_offset_list) &&
(num_offset_list <= max_num_offset_list));
}
off_list* vroniObject::GetOffsetList(int i)
{
if (InOffsetList(i))
return &(offset_list[i]);
else
return NULL;
}
off_data* vroniObject::GetOffsetData(int i)
{
if (InOffsetData(i))
return &(offset_data[i]);
else
return NULL;
}
void vroniObject::ResetOffsetData(void)
{
num_offset_list = 0;
num_offset_data = 0;
cur_offset_list = 0;
return;
}
/* */
/* this function checks an offset arc and replaces it by a line segment if */
/* its orientation is wrong or problematic, e.g., since its arc length is */
/* small. */
/* */
vr_bool vroniObject::ScrutinizeArc(coord start, coord end, coord center,
vr_bool *ori, double eps,
vr_bool not_isolated)
{
coord vec_s, vec_e;
double det;
if (!not_isolated) return true;
if (eq(PntPntDist(start, end), eps)) {
/* */
/* this is a tiny arc that is filtered. (it will be replaced by a line */
/* segment.) */
/* */
return false;
}
if (*ori) det = VecDet(start, end, center);
else det = -VecDet(start, end, center);
if (eq(det, eps)) {
/* */
/* this arc is either a (correct) half-circle or a rather tiny arc */
/* */
vec_s = VecSub(start, center);
vec_e = VecSub(end, center);
if (VecDotProd(vec_e, vec_s) < 0.0) {
/* */
/* this arc is roughly a half circle */
/* */
return true;
}
}
if (det < 0.0) {
/* */
/* this arc seems to have the wrong orientation, for unknown reasons. */
/* we adjust the orientation. */
/* */
*ori = ! *ori;
VD_IO_Warning("ScrutinizeArc() - reversed orientation of arc!");
}
return true;
}
void vroniObject::FreeOffsetData(void)
{
offset_data.clear();
offset_list.clear();
num_offset_data = 0;
max_num_offset_data = 0;
num_offset_list = 0;
max_num_offset_list = 0;
return;
}
void vroniObject::ComputeIsolatedOffsets(double_arg t0, double_arg d_off)
{
int number, i, e, e0, n1, n2;
double min_t, tn2, x = 0.0, t;
coord w;
number = num_pnts - 2;
for (i = 2; i < number; ++i) {
if (!HasIncidentSite(i) && !IsDeletedPnt(i)) {
/* */
/* find minimum clearance of all Voronoi nodes of this cell */
/* */
e0 = GetVDPtr(i, PNT);
if (e0 == NIL) {
VD_Warning("ComputeIsolatedOffsets - null VD pointer!\n");
}
else {
e = e0;
if (IsLftSite(e, i, PNT)) {
n1 = GetEndNode(e);
}
else {
assert(IsRgtSite(e, i, PNT));
n1 = GetStartNode(e);
}
min_t = GetNodeParam(n1);
do {
n2 = GetOtherNode(e, n1);
tn2 = GetNodeParam(n2);
min_t = VroniMin(min_t, tn2);
n1 = n2;
e = GetCCWEdge(e, n1);
} while (e != e0);
/* */
/* compute concentric offset circles */
/* */
t = t0;
x = GetPntCoords(i).x;
w.y = GetPntCoords(i).y;
while (t <= min_t) {
NewOffsetCurve;
w.x = x + t;
StoreOffsetData(i, PNT, w);
w.x = x - t;
StoreOffsetData(i, PNT, w);
SetOffsetNumber;
#ifdef VISUAL_TEST_OFFSETS
if (small_increment) {
small_increment = false;
t *= 10.0;
}
else {
t += d_off;
}
#else
t += d_off;
#endif
/* */
/* let the user call some application-specific function */
/* */
ExtApplFuncIsoOffset;
}
#ifdef VISUAL_TEST_OFFSETS
small_increment = true;
#endif
}
}
}
/* */
/* let the user call some application-specific function */
/* */
ExtApplFuncIsoOffsetDone;
return;
}
/* */
/* this is the main function for my sample implementation of VD-based */
/* offsetting. please see API_ComputeOff() for an explanation of the */
/* parameters. also, please note that the offsets computed are stored in */
/* offset_data, and those records are not reset automatically when this */
/* function is called. */
/* */
void vroniObject::ComputeOff(int step_size, vr_bool time, char off_file[],
vr_bool write_off, vr_bool dxf_format,
double_arg t_offset, double_arg d_offset,
vr_bool *finished,
vr_bool left_offset, vr_bool right_offset)
{
double t1, t2;
int i, j, not_needed;
vr_bool delete_it, unrestricted;
#ifdef GRAPHICS
int cntr = 0;
#endif
assert(GetVDStatus());
if (GetNodesSqdFlag()) TakeSquareOfNodes();
if (!GetDeg2Flag()) InsertDegreeTwoNodes();
i = GetVDIdentifier();
if (offset_VD_ID != i) {
offset_VD_ID = i;
e_data_init = true;
}
if (e_data_init) {
/* */
/* first call to this function. allocate memory and initialize the */
/* flags for the edge data. */
/* */
VD_Info("...computing offset curves -- ");
if (time) (void)elapsed();
t = ScaleV(t_offset);
d_off = ScaleV(d_offset);
if (le(d_off, ZERO)) d_off = max_t_offset;
#ifdef GRAPHICS
if (graphics) ResetCurBuffer();
#else
step_size = INT_MAX;
#endif
if (t >= max_t_offset) {
*finished = true;
VD_Warning("ComputeOff() - requested offset is too large!");
}
else if (le(t, ZERO)) {
*finished = true;
VD_Warning("ComputeOff() - requested offset is too small!");
}
else {
*finished = false;
data_written = false;
unrestricted = !(left_offset || right_offset);
/* */
/* allocate memory and initialize the flags for the edge data. */
/* */
InitializeEdgeData(unrestricted, left_offset, false, &not_needed);
/* */
/* handle all offsets around isolated pnts */
/* */
if (isolated_pnts && unrestricted)
ComputeIsolatedOffsets(t, d_off);
cpu_time_off = 0.0;
/* */
/* let the user call some application-specific function */
/* */
ExtApplFuncOffsetInit;
}
}
else {
if (time) (void)elapsed();
t += d_off;
if (t >= max_t_offset) *finished = true;
/* */
/* let the user call some application-specific function */
/* */
ExtApplFuncOffsetRepeat;
}
while (!*finished) {
/* */
/* mark all edges that will be intersected by an offset curve with */
/* offset t. */
/* */
j = -1;
AdvanceActiveEdge(i, j, false);
while (i != NIL) {
delete_it = false;
if (GetEdgeFlagNew(i)) {
GetEdgeParam(i, &t1, &t2);
if (t >= VroniMin(t1, t2)) {
if (t < VroniMax(t1, t2)) {
/* */
/* this edge will be intersected by an offset curve. let's */
/* compute this offset curve. */
/* */
ComputeOffset(i, t);
SetEdgeFlagNew(i, true);
}
else {
/* */
/* for increasing values of t, this edge won't be */
/* intersected by any offset curve any more. */
/* */
delete_it = true;
}
}
}
else {
/* */
/* this edge has already been intersected by an offset curve */
/* for the current offset. */
/* */
SetEdgeFlagNew(i, true);
}
AdvanceActiveEdge(i, j, delete_it);
}
#ifdef GRAPHICS
if (graphics) {
++cntr;
if (cntr >= step_size) {
AddOffsetsToBuffer();
cntr = 0;
return;
}
}
#endif
/* */
/* all offsets for offset distance t * scale_factor have been */
/* computed. */
/* */
/* let the user call some application-specific function */
/* */
ExtApplFuncOffLoops;
#ifdef VISUAL_TEST_OFFSETS
if (small_increment) {
small_increment = false;
t *= 10.0;
}
else {
t += d_off;
}
#else
t += d_off;
#endif
if (t >= max_t_offset) *finished = true;
}
if (time) cpu_time_off += elapsed();
if (*finished) {
VD_Info("done!\n");
#ifdef GRAPHICS
if (graphics) {
AddOffsetsToBuffer();
}
#endif
if (!data_written) {
data_written = true;
if (write_off) {
VD_Info("...writing the offset data -- ");
if (dxf_format) WriteOffsetsDXF(off_file);
else WriteOffsets(off_file);
VD_Info("done!\n");
}
}
/* */
/* let the user call some application-specific function */
/* */
ExtApplFuncOffDone;
}
return;
}
void vroniObject::EvaluateBisectorData(int i, /* bisector */
double_arg t, /* boundary clearance */
coord *w) /* offset point */
{
int lft, rgt;
t_site t_lft, t_rgt;
enum {LINE, PARABOLA, HYPERBOLA, HYPERELL} conic;
GetLftSiteData(i, &lft, &t_lft);
GetRgtSiteData(i, &rgt, &t_rgt);
if ((t_lft == PNT) && (t_rgt == PNT)) {
conic = HYPERBOLA;
}
else if ((t_lft == PNT) || (t_lft == ARC)) {
if ((t_rgt == PNT) || (t_rgt == ARC)) {
if (t_lft == PNT) {
assert(t_rgt == ARC);
assert(InArcsList(rgt));
if (IsArcStartPnt(rgt, lft) || IsArcEndPnt(rgt, lft))
conic = LINE;
else
conic = HYPERELL;
}
else if (t_rgt == PNT) {
assert(t_lft == ARC);
assert(InArcsList(lft));
if (IsArcStartPnt(lft, rgt) || IsArcEndPnt(lft, rgt))
conic = LINE;
else
conic = HYPERELL;
}
else {
conic = HYPERELL;
}
}
else {
assert(t_rgt == SEG);
assert(InSegsList(rgt));
if ((t_lft == PNT) &&
(IsSegStartPnt(rgt, lft) || IsSegEndPnt(rgt, lft)))
conic = LINE;
else
conic = PARABOLA;
}
}
else {
if ((t_rgt == PNT) || (t_rgt == ARC)) {
assert(t_lft == SEG);
assert(InSegsList(lft));
if ((t_rgt == PNT) &&
(IsSegStartPnt(lft, rgt) || IsSegEndPnt(lft, rgt)))
conic = LINE;
else
conic = PARABOLA;
}
else {
conic = LINE;
}
}
if (GetEdgeDataInit(i)) {
/* */
/* initialize the parameterization formula for this Voronoi edge. */
/* */
if (conic == LINE) CreateLineData(i);
else if (conic == PARABOLA) CreateParabolaData(i);
else if (conic == HYPERBOLA) CreateHyperbolaData(i);
#ifdef GENUINE_ARCS
else if (conic == HYPERELL) CreateHyperbolaEllipseData(i);
#else
else if (conic == HYPERELL)
throw std::runtime_error("VRONI error: EvaluateBisectorData() - genuine arcs not supported!");
#endif
SetEdgeDataInit(i, false);
}
/* */
/* compute the offset point. */
/* */
if (conic == LINE) {
EvaluateLineData(i, t, w);
}
else if (conic == PARABOLA) {
if (t_lft == SEG)
EvaluateParabolaData(i, lft, t, w);
else
EvaluateParabolaData(i, rgt, t, w);
}
else if (conic == HYPERBOLA) {
EvaluateHyperbolaData(i, t, w);
}
#ifdef GENUINE_ARCS
else if (conic == HYPERELL) {
EvaluateHyperbolaEllipseData(i, t, w);
}
#else
else if (conic == HYPERELL)
throw std::runtime_error("VRONI error: EvaluateBisectorData() - genuine arcs not supported!");
#endif
return;
}
void vroniObject::ComputeOffset(int i, double_arg t)
{
int i0, i2, n1, n2, n;
int lft, rgt;
t_site t_lft, t_rgt, ti;
coord u, w;
double t1, t2;
vr_bool keep_going;
int i1;
NewOffsetCurve;
/* */
/* let the user call some application-specific function */
/* */
ExtApplFuncOffStart;
i0 = i;
n1 = GetStartNode(i);
n2 = GetEndNode(i);
t1 = GetNodeParam(n1);
t2 = GetNodeParam(n2);
//printf("\tComputeOffset i=%d, i0=%d, t=%e\n", i, i0, t);
do {
GetLftSiteData(i, &lft, &t_lft);
GetRgtSiteData(i, &rgt, &t_rgt);
EvaluateBisectorData(i, t, &w);
SetEdgeFlagNew(i, false);
/* */
/* store the computed point. make sure to include the reference to any */
/* original arc if arcs were approximated. */
/* */
if (t < t2) {
i2 = rgt;
ti = t_rgt;
i1 = NIL;
n = n2;
}
else {
assert(t < t1);
i2 = lft;
ti = t_lft;
i1 = NIL;
n = n1;
}
if (i1 == NIL) i1 = i2;
else ti = ARC;
if (ti == ARC) {
/* */
/* test whether point is inside or outside of arc. */
/* */
if (PntPntDist(GetArcCenter(i1), w) < GetArcRadius(i1))
ti = CCW;
else
ti = CW;
}
StoreOffsetData(i1, ti, w);
/* */
/* let the user call some application-specific function */
/* */
ExtApplFuncOffSegment;
/* */
/* find the next Voronoi edge */
/* */
keep_going = true;
do {
i = GetCCWEdge(i, n);
n1 = GetStartNode(i);
n2 = GetEndNode(i);
t1 = GetNodeParam(n1);
t2 = GetNodeParam(n2);
if ((t >= VroniMin(t1, t2)) && (t < VroniMax(t1, t2))) {
keep_going = false;
}
else {
n = GetOtherNode(i, n);
}
} while(keep_going);
} while (i != i0);
SetOffsetNumber;
/* */
/* let the user call some application-specific function */
/* */
ExtApplFuncOffsetEnd;
return;
}
#ifdef EXT_APPL_OFF
eao_type vroniObject::GetExtApplOffsetFunc(int O)
{
assert(InOffsetData(O));
return offset_data[O].ext_appl;
}
void vroniObject::SetExtApplOffsetFunc(int O, eao_type ext_appl)
{
assert(InOffsetData(O));
offset_data[O].ext_appl = ext_appl;
return;
}
#endif
void vroniObject::StartOffsets(void *output, int num_offset_loops)
{
/* */
/* write an approximate bounding box. note that this data need not be */
/* accurate, as we output the bbox of the input sites rather than the */
/* true bbox. */
/* */
/*
FP_fprintf((FILE*)output, "%f %f %f %f\n",
FP_PRNTARG(UnscaleX(GetPntCoords(0).x)), FP_PRNTARG(UnscaleY(GetPntCoords(0).y)),
FP_PRNTARG(UnscaleX(GetPntCoords(num_pnts-1).x)), FP_PRNTARG(UnscaleY(GetPntCoords(num_pnts-1).y)));
*/
/* */
/* write the number of individual closed offset loops */
/* */
fprintf((FILE*)output, "%d\n", num_offset_loops);
return;
}
void vroniObject::StartOffsetLoop(void *output, int num_offset_elements)
{
fprintf((FILE*)output, "\n%d\n1\n", num_offset_elements);
return;
}
void vroniObject::WriteOffsetSeg(void *output,
#ifdef EXT_APPL_OFF
eao_type ext_appl_off,
#endif
double_arg x1, double_arg y1,
double_arg x2, double_arg y2)
{
FP_fprintf((FILE*)output, "0\n%20.16f %20.16f %f %f\n", FP_PRNTARG(x1), FP_PRNTARG(y1), FP_PRNTARG(x2 - x1), FP_PRNTARG(y2 - y1));
return;
}
void vroniObject::WriteOffsetArc(void *output,
#ifdef EXT_APPL_OFF
eao_type ext_appl_off,
#endif
double_arg x1, double_arg y1,
double_arg , double_arg ,
double_arg xc, double_arg yc, vr_bool ccw)
{
if (ccw)
FP_fprintf((FILE*)output, "1\n%20.16f %20.16f %20.16f %20.16f\n", FP_PRNTARG(x1), FP_PRNTARG(y1), FP_PRNTARG(xc), FP_PRNTARG(yc));
else
FP_fprintf((FILE*)output, "-1\n%20.16f %20.16f %20.16f %20.16f\n", FP_PRNTARG(x1), FP_PRNTARG(y1), FP_PRNTARG(xc), FP_PRNTARG(yc));
return;
}
void vroniObject::EndOffsetLoop(void *, int, int, double_arg, double_arg)
{
/* dummy: no parameter names should avoid annoying compiler warnings about unused variables */
return;
}
void vroniObject::EndOffsets(void *, int , int , int )
{
/* dummy: no parameter names should avoid annoying compiler warnings about unused variables */
return;
}
/* */
/* this is the generic routine for exporting VRONI's offset data. it is used */
/* by VRONI to write offset data to .dat and .dxf files, and to add the */
/* offset data to the graphics buffer for display in the GUI. */
/* */
/* */
void vroniObject::apiOutputOffsets(void *output,
/* this is a pointer to a */
/* user-defined object, such as */
/* a file or a structure */
void (vroniObject::*StartOffsetsFuncPtr)(
void *output,
int num_offset_loops),
void (vroniObject::*StartOffsetLoopFuncPtr)(
void *output,
int num_offset_elements),
void (vroniObject::*WriteOffsetSegFuncPtr)(
void *output,
#ifdef EXT_APPL_OFF
eao_type ext_appl_off,
#endif
double_arg x1, double_arg y1,
double_arg x2, double_arg y2),
void (vroniObject::*WriteOffsetArcFuncPtr)(
void *output,
#ifdef EXT_APPL_OFF
eao_type ext_appl_off,
#endif
double_arg x1, double_arg y1,
double_arg x2, double_arg y2,
double_arg xc, double_arg yc,
vr_bool ccw),
void (vroniObject::*EndOffsetLoopFuncPtr)(
void *output,
int num_offset_segs,
int num_offset_arcs,
double_arg x0, double_arg y0),
void (vroniObject::*EndOffsetsFuncPtr)(
void *output,
int num_offset_loops,
int num_offset_segs,
int num_offset_arcs))
{
int i, j, k, m;
vr_bool ori;
int num_offset_segs = 0, num_offset_arcs = 0;
coord start, end, center;
/* */
/* start the offset curves */
/* */
(this->*StartOffsetsFuncPtr)(output, num_offset_list);
for (i = 0; i < num_offset_list; ++i) {
/* */
/* output one closed offset loop; the offset distance of this loop is */
/* stored in offset_list[i].offset. note that the orientation of a */
/* loop is dummy since there is no simple way for the code to */
/* determine the proper orientation of offset loops for general data. */
/* */
(this->*StartOffsetLoopFuncPtr)(
output, GetOffsetListEnd(i) - GetOffsetListStart(i) + 1
);
for (j = GetOffsetListStart(i); j <= GetOffsetListEnd(i); ++j) {
assert(InOffsetData(j));
start = GetOffsetPntCoords(j);
m = j + 1;
if (m > GetOffsetListEnd(i)) m = GetOffsetListStart(i);
end = GetOffsetPntCoords(m);
if (GetOffsetEleType(j) == PNT) {
/* */
/* CW circular arc centered at reflex vertex */
/* */
k = GetOffsetEleSite(j);
assert(InPntsList(k));
center = GetPntCoords(k);
ori = false;
if (ScrutinizeArc(start, end, center, &ori, ZERO_IO,
HasIncidentSite(k))) {
/* */
/* output an arc */
/* */
if (unscaleXYZ) {
(this->*WriteOffsetArcFuncPtr)(
output,
#ifdef EXT_APPL_OFF
GetExtApplOffsetFunc(j),
#endif
UnscaleX(start.x), UnscaleY(start.y),
UnscaleX(end.x), UnscaleY(end.y),
UnscaleX(center.x), UnscaleY(center.y), ori
);
}
else {
(this->*WriteOffsetArcFuncPtr)(
output,
#ifdef EXT_APPL_OFF
GetExtApplOffsetFunc(j),
#endif
start.x, start.y, end.x, end.y,
center.x, center.y, ori
);
}
++num_offset_arcs;
}
else {
/* */
/* replace arc by (tiny) line segment */
/* */
if (unscaleXYZ) {
(this->*WriteOffsetSegFuncPtr)(
output,
#ifdef EXT_APPL_OFF
GetExtApplOffsetFunc(j),
#endif
UnscaleX(start.x), UnscaleY(start.y),
UnscaleX(end.x), UnscaleY(end.y)
);
}
else {
(this->*WriteOffsetSegFuncPtr)(
output,
#ifdef EXT_APPL_OFF
GetExtApplOffsetFunc(j),
#endif
start.x, start.y, end.x, end.y
);
}
++num_offset_segs;
}
}
else if (GetOffsetEleType(j) == SEG) {
/* */
/* offset element is straight-line segment */
/* */
if (unscaleXYZ) {
(this->*WriteOffsetSegFuncPtr)(
output,
#ifdef EXT_APPL_OFF
GetExtApplOffsetFunc(j),
#endif
UnscaleX(start.x), UnscaleY(start.y),
UnscaleX(end.x), UnscaleY(end.y)
);
}
else {
(this->*WriteOffsetSegFuncPtr)(
output,
#ifdef EXT_APPL_OFF
GetExtApplOffsetFunc(j),
#endif
start.x, start.y, end.x, end.y
);
}
++num_offset_segs;
}
else if ((GetOffsetEleType(j) == CCW) ||
(GetOffsetEleType(j) == CW)) {
/* */
/* offset element is circular arc defined by an input arc */
/* */
k = GetOffsetEleSite(j);
assert(InArcsList(k));
center = GetArcCenter(k);
if (GetOffsetEleType(j) == CCW) ori = true;
else ori = false;
if (ScrutinizeArc(start, end, center, &ori, ZERO_IO, true)) {
/* */
/* output an arc */
/* */
if (unscaleXYZ) {
(this->*WriteOffsetArcFuncPtr)(
output,
#ifdef EXT_APPL_OFF
GetExtApplOffsetFunc(j),
#endif
UnscaleX(start.x), UnscaleY(start.y),
UnscaleX(end.x), UnscaleY(end.y),
UnscaleX(center.x), UnscaleY(center.y), ori
);
}
else {
(this->*WriteOffsetArcFuncPtr)(
output,
#ifdef EXT_APPL_OFF
GetExtApplOffsetFunc(j),
#endif
start.x, start.y, end.x, end.y,
center.x, center.y, ori
);
}
++num_offset_arcs;
}
else {
/* */
/* replace arc by (tiny) line segment */
/* */
if (unscaleXYZ) {
(this->*WriteOffsetSegFuncPtr)(
output,
#ifdef EXT_APPL_OFF
GetExtApplOffsetFunc(j),
#endif
UnscaleX(start.x), UnscaleY(start.y),
UnscaleX(end.x), UnscaleY(end.y)
);
}
else {
(this->*WriteOffsetSegFuncPtr)(
output,
#ifdef EXT_APPL_OFF
GetExtApplOffsetFunc(j),
#endif
start.x, start.y, end.x, end.y
);
}
++num_offset_segs;
}
}
else {
/* */
/* not exactly an offset type that the code should have assigned */
/* */
VD_Warning("apiOutputOffsets() - unknown site type!\n");
assert(0 == 1);
}
}
j = GetOffsetListStart(i);
if (unscaleXYZ) {
(this->*EndOffsetLoopFuncPtr)(output, num_offset_segs, num_offset_arcs,
UnscaleX(GetOffsetXCoord(j)),
UnscaleY(GetOffsetYCoord(j)));
}
else {
(this->*EndOffsetLoopFuncPtr)(output, num_offset_segs, num_offset_arcs,
GetOffsetXCoord(j), GetOffsetYCoord(j));
}
}
(this->*EndOffsetsFuncPtr)(
output, num_offset_list, num_offset_segs, num_offset_arcs
);
return;
}
void vroniObject::WriteOffsets(char off_file[])
{
FILE *off;
assert(gt(scale_factor, ZERO));
unscaleXYZ = true;
off = OpenFileVD(off_file, "w");
apiOutputOffsets(off, &vroniObject::StartOffsets,
&vroniObject::StartOffsetLoop,
&vroniObject::WriteOffsetSeg, &vroniObject::WriteOffsetArc,
&vroniObject::EndOffsetLoop, &vroniObject::EndOffsets);
fclose(off);
return;
}
/* toggle between LWPOLYLINE and POLYLINE */
static vr_bool LW_polyline = false;
void vroniObject::StartOffsetsDXF(void *output, int )
{
StartDXFFile((FILE*)output);
return;
}
void vroniObject::StartOffsetLoopDXF(void *output, int )
{
if (LW_polyline) WriteDXFLWPoly_Start((FILE*)output, true, DXF_RED);
else WriteDXFPoly_Start((FILE*)output, true, DXF_RED);
return;
}
void vroniObject::WriteOffsetSegDXF(void *output,
#ifdef EXT_APPL_OFF
eao_type ,
#endif
double_arg x1, double_arg y1,
double_arg , double_arg )
{
if (LW_polyline)
WriteDXFLWPoly_Vertex((FILE*)output,
x1, y1, 0.0);
else
WriteDXFPoly_Vertex((FILE*)output,
x1, y1, 0.0);
return;
}
void vroniObject::WriteOffsetArcDXF(void *output,
#ifdef EXT_APPL_OFF
eao_type ,
#endif
double_arg x1, double_arg y1,
double_arg x2, double_arg y2,
double_arg xc, double_arg yc, vr_bool ccw)
{
double radius, bulge;
coord start, end, center;
start.x = x1;
start.y = y1;
end.x = x2;
end.y = y2;
center.x = xc;
center.y = yc;
radius = PntPntDist(start, center);
if (ccw)
ComputeBulge(start, end, &bulge, center, radius, ARC);
else
ComputeBulge(start, end, &bulge, center, radius, -ARC);
if (LW_polyline)
WriteDXFLWPoly_Vertex((FILE*)output, start.x, start.y, bulge);
else
WriteDXFPoly_Vertex((FILE*)output, start.x, start.y, bulge);
return;
}
void vroniObject::EndOffsetLoopDXF(void *output, int, int, double_arg,
double_arg)
{
if (!LW_polyline) WriteDXFPoly_End((FILE*)output);
return;
}
void vroniObject::EndOffsetsDXF(void *output, int , int , int )
{
FinishDXFFile((FILE*)output);
return;
}
void vroniObject::WriteOffsetsDXF(char off_file[])
{
FILE *off;
assert(gt(scale_factor, ZERO));
unscaleXYZ = true;
off = OpenFileVD(off_file, "w");
apiOutputOffsets(off, &vroniObject::StartOffsetsDXF,
&vroniObject::StartOffsetLoopDXF,
&vroniObject::WriteOffsetSegDXF,
&vroniObject::WriteOffsetArcDXF,
&vroniObject::EndOffsetLoopDXF,
&vroniObject::EndOffsetsDXF);
fclose(off);
return;
}
#ifdef GRAPHICS
void vroniObject::StartOffsetsBuf(void* , int )
{
return;
}
void vroniObject::StartOffsetLoopBuf(void* , int )
{
return;
}
void vroniObject::WriteOffsetSegBuf(void* ,
#ifdef EXT_APPL_OFF
eao_type ext_appl_off,
#endif
double_arg x1, double_arg y1,
double_arg x2, double_arg y2)
{
AddOffToBuffer(x1, y1, x2, y2, 0.0, 0.0, 0.0, false, OffColor);
return;
}
void vroniObject::WriteOffsetArcBuf(void* ,
#ifdef EXT_APPL_OFF
eao_type ext_appl_off,
#endif
double_arg x1, double_arg y1,
double_arg x2, double_arg y2,
double_arg xc, double_arg yc, vr_bool ccw)
{
double radius;
radius = sqrt(pow(x1-xc,2) + pow(y1-yc,2));
AddOffToBuffer(x1, y1, x2, y2, xc, yc, radius, !ccw, OffColor);
return;
}
void vroniObject::EndOffsetLoopBuf(void* , int , int , double_arg , double_arg)
{
return;
}
void vroniObject::EndOffsetsBuf(void*, int , int , int )
{
return;
}
void vroniObject::AddOffsetsToBuffer(void)
{
int *foo = (int*)NIL; /* dummy pointer, we access VRONI's global data */
unscaleXYZ = false;
apiOutputOffsets(foo, &vroniObject::StartOffsetsBuf,
&vroniObject::StartOffsetLoopBuf,
&vroniObject::WriteOffsetSegBuf,
&vroniObject::WriteOffsetArcBuf,
&vroniObject::EndOffsetLoopBuf,
&vroniObject::EndOffsetsBuf);
unscaleXYZ = true;
return;
}
#endif
#include "ext_appl_offset.cc"