739088af9f
- aggiornamento versione.
491 lines
17 KiB
C++
491 lines
17 KiB
C++
/*****************************************************************************/
|
|
/* */
|
|
/* Copyright (C) Martin Held 1999-2025 */
|
|
/* */
|
|
/* */
|
|
/* C O P Y R I G H T */
|
|
/* */
|
|
/* This code is provided at no charge to you for purely non-profit purposes */
|
|
/* and only for use internal to your institution. You may use this code for */
|
|
/* academic applications, following standard rules of academic conduct */
|
|
/* including crediting the author(s) and the copyright holder in any */
|
|
/* publication. This code is not in the public domain, and no parts of it */
|
|
/* may be duplicated, altered, sold, re-distributed (in either source-code */
|
|
/* or binary format), or used as a blueprint for somebody else's own */
|
|
/* implementation without obtaining the prior written consent of the */
|
|
/* copyright holder. All rights reserved! */
|
|
/* */
|
|
/* Free use of this code is restricted to purely non-profit purposes within */
|
|
/* academic research institutions. Absolutely all other forms of use require */
|
|
/* the signing of a non-disclosure agreement or of a commercial license. */
|
|
/* Please contact me, Martin Held (held@cs.sbg.ac.at), for commercial */
|
|
/* evaluation and licensing terms. */
|
|
/* */
|
|
/* D I S C L A I M E R */
|
|
/* */
|
|
/* In any case, this code is provided `as is', and you use it at your own */
|
|
/* risk. The author does not accept any responsibility, to the extent */
|
|
/* permitted by applicable law, for the consequences of using it or for its */
|
|
/* usefulness for any particular application. */
|
|
/* */
|
|
/* Please report any bugs to held@cs.sbg.ac.at. */
|
|
/* */
|
|
/*****************************************************************************/
|
|
/* */
|
|
/* 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 */
|
|
/* */
|
|
/*****************************************************************************/
|
|
/* */
|
|
/* Please read the files README.txt and README_data.txt prior to compiling */
|
|
/* or using this code! */
|
|
/* */
|
|
/*****************************************************************************/
|
|
|
|
/* */
|
|
/* get standard libraries */
|
|
/* */
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#include <limits.h>
|
|
#include <float.h>
|
|
#include <assert.h>
|
|
|
|
/* */
|
|
/* get my header files */
|
|
/* */
|
|
#include "fpkernel.h"
|
|
#include "vronivector.h"
|
|
#include "vroni_object.h"
|
|
#ifdef GRAPHICS
|
|
#include "numerics.h"
|
|
#endif
|
|
|
|
#define Bell '\007'
|
|
|
|
|
|
|
|
void vroniObject::ProceedWithoutGraphics(vr_bool new_data)
|
|
{
|
|
#ifdef MIC
|
|
coord center;
|
|
double rad;
|
|
#endif
|
|
|
|
if (!new_data) return;
|
|
new_input = new_data;
|
|
|
|
/* */
|
|
/* no interactive graphics; compute the VD */
|
|
/* */
|
|
API_ComputeVD(save_data, new_input, time_it, bound, sample, approx,
|
|
output_file, discard_dupl_s, pnts_only, write_vd_dt,
|
|
vd_dt_file, clean_up);
|
|
|
|
/* */
|
|
/* compute all offset curves */
|
|
/* */
|
|
if (auto_offset || (t_offset > 0.0))
|
|
API_ComputeOff(time_it, off_file, write_off, dxf_format,
|
|
t_offset, d_offset,
|
|
auto_offset, left_offset, right_offset);
|
|
|
|
#ifdef WRITE_VD
|
|
/* */
|
|
/* approximate conic VD edges by straight-line segments and write every */
|
|
/* Voronoi region as one polygon to an OBJ file. the clearance radii */
|
|
/* are added as z-coordinates of the vertices */
|
|
/* */
|
|
if (write_vd) {
|
|
API_Output_VD(vd_file, vd_apx_dist, left_vd, right_vd);
|
|
write_vd = false;
|
|
}
|
|
#endif
|
|
|
|
#ifdef MAT
|
|
/* */
|
|
/* compute the weighted medial axis */
|
|
/* */
|
|
if (compute_wmat && !pnts_only) {
|
|
API_ComputeWMAT(auto_wmat, wmat_angle, wmat_dist, time_it,
|
|
left_offset, right_offset);
|
|
if (write_ma) API_OutputMA(ma_file);
|
|
}
|
|
#endif
|
|
|
|
/* */
|
|
/* compute the maximum inscribed/empty circle */
|
|
/* */
|
|
#ifdef MIC
|
|
if (compute_mic && !pnts_only)
|
|
API_ComputeOutputMIC(time_it, left_offset, right_offset, ¢er, &rad);
|
|
center.x = center.y = rad = 0.0; /* avoid compiler complaints since */
|
|
/* we don't use those variables... */
|
|
#endif
|
|
|
|
#ifdef HSM
|
|
if (compute_path) {
|
|
ComputePath(time_it, path_file, write_path, dxf_format, tool_rad,
|
|
step_over, angle);
|
|
}
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
void vroniObject::ParseCommandLineArgs(int argc, char *argv[],
|
|
vr_bool *do_graphics,
|
|
vr_bool *color_graphics,
|
|
vr_bool *full_screen)
|
|
{
|
|
|
|
if (!ArgEval(argc, argv, color_graphics, do_graphics, &save_data,
|
|
output_file, &read_polygon, input_file, &read_poly,
|
|
&driver_step_size, &verbose, &write_ipe, &help, &time_it,
|
|
&statistics, &print_copy, &quiet, &bound, &sample,
|
|
&scale_data, &approx,
|
|
&read_sites, &read_xdr, &read_graphml, &discard_dupl_s,
|
|
&p_step_size, &read_e00, &read_dxf, &read_polylines,
|
|
&t_offset, &d_offset, &write_off, off_file, &o_step_size,
|
|
&auto_offset, full_screen, &read_usgs, &left_offset,
|
|
&right_offset, &compute_wmat, &wmat_angle, &wmat_dist,
|
|
&auto_wmat, &pnts_only, &compute_mic, &a_step_size,
|
|
&check_data, &write_vd_dt, vd_dt_file, &read_pnts,
|
|
&dxf_format, &read_file, &write_ma, ma_file, &clean_up,
|
|
&write_vd, vd_file, &vd_apx_dist, &left_vd, &right_vd,
|
|
&vr_incr, vr_file, &inputprec, &mpfr_prec, &vr_seed,
|
|
&compute_path, &tool_rad, &angle, &step_over,
|
|
&write_path, path_file)) {
|
|
Copyright();
|
|
EvalError();
|
|
throw std::runtime_error("VRONI error: ArgEval() - unrecognized CL option!");
|
|
}
|
|
else if (print_copy && !quiet) {
|
|
Copyright();
|
|
}
|
|
if (help) {
|
|
Help();
|
|
EvalError();
|
|
exit(0);
|
|
}
|
|
|
|
#ifdef GRAPHICS
|
|
graphics = *do_graphics;
|
|
if (read_pnts || pnts_only) draw_pnts = true;
|
|
#endif
|
|
|
|
#ifdef WITH_COREBACKEND
|
|
if(inputprec == -1) {
|
|
setDefaultInputDigits(CORE_INFTY);
|
|
} else {
|
|
setDefaultInputDigits(inputprec);
|
|
}
|
|
#elif defined(WITH_MPFRBACKEND)
|
|
set_mpfrbackend_prec(mpfr_prec, verbose);
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
void vroniObject::GetInputData(vr_bool *input_read)
|
|
{
|
|
vr_bool format_specified;
|
|
|
|
format_specified = read_polygon || read_poly || read_sites ||
|
|
read_xdr || read_e00 || read_polylines || read_usgs ||
|
|
read_dxf || read_pnts || read_graphml;
|
|
|
|
/* */
|
|
/* get input data */
|
|
/* */
|
|
if (format_specified || read_file) {
|
|
/* */
|
|
/* read sites from input file. use API_ArrayInput() for a simple way */
|
|
/* to feed data directly into VRONI. */
|
|
/* */
|
|
if (format_specified)
|
|
API_HandleInput(input_file, &new_input, read_polygon, read_poly,
|
|
read_sites, read_xdr, read_e00, read_polylines,
|
|
read_usgs, read_dxf, read_pnts, read_graphml);
|
|
else
|
|
API_FileInput(input_file, &new_input);
|
|
|
|
*input_read = new_input;
|
|
#if defined (OGL_GRAPHICS)
|
|
data_read = new_input;
|
|
draw_pnts = isolated_pnts;
|
|
#endif
|
|
}
|
|
else {
|
|
*input_read = false;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
#ifdef OGL_GRAPHICS
|
|
|
|
void vroniObject::HandleComputeVD(void)
|
|
{
|
|
vr_bool stop_for_debugging = false; /* for my debugging purposes */
|
|
vr_bool dummy_draw_pnts;
|
|
#ifdef MIC
|
|
coord center;
|
|
double rad;
|
|
#endif
|
|
|
|
if (!computed) {
|
|
if (io_flag == 1) VD_Info("done!\n");
|
|
new_input = data_read || new_input || (new_pnts > 0);
|
|
finished = !new_input;
|
|
}
|
|
io_flag = 2;
|
|
if (!finished) {
|
|
do {
|
|
ComputeVD(save_data, new_input, driver_step_size, time_it, bound, sample,
|
|
approx, output_file, discard_dupl_s, p_step_size,
|
|
&finished, a_step_size, pnts_only, write_vd_dt, vd_dt_file,
|
|
left_offset, right_offset, clean_up);
|
|
/*stop_for_debugging = true;*/
|
|
} while (restart && !stop_for_debugging);
|
|
computed = true;
|
|
data_read = false;
|
|
new_input = false;
|
|
if (finished && auto_offset) off_init = true;
|
|
}
|
|
if (computed && finished && !off_finished) {
|
|
if (auto_offset || (t_offset > 0.0)) {
|
|
if (off_init) {
|
|
if (data_scaled) {
|
|
assert(scale_factor > 0.0);
|
|
t_offset = UnscaleV(0.001);
|
|
}
|
|
else {
|
|
t_offset = 0.001;
|
|
}
|
|
if (num_pnts > 30)
|
|
d_offset = 30.0 * t_offset / log(log((double) num_pnts));
|
|
else
|
|
d_offset = 30.0 * t_offset;
|
|
if (d_offset < (10.0 * t_offset)) d_offset = 10.0 * t_offset;
|
|
if (num_pnts > 250000) d_offset *= 10.0;
|
|
off_init = false;
|
|
}
|
|
if (left_offset && right_offset) {
|
|
left_offset = right_offset = false;
|
|
}
|
|
if (gt(t_offset, ZERO))
|
|
ComputeOff(o_step_size, time_it, off_file, write_off, dxf_format,
|
|
t_offset, d_offset, &off_finished,
|
|
left_offset, right_offset);
|
|
else
|
|
off_finished = true;
|
|
}
|
|
else {
|
|
off_finished = true;
|
|
}
|
|
}
|
|
#ifdef WRITE_VD
|
|
if (computed && finished && write_vd) {
|
|
OutputVD(vd_file, vd_apx_dist, left_vd, right_vd);
|
|
write_vd = false;
|
|
}
|
|
#endif
|
|
#ifdef MAT
|
|
if (computed && finished && off_finished && !wmat_computed &&
|
|
!pnts_only) {
|
|
#ifdef WMAT
|
|
if (auto_wmat) {
|
|
if (data_scaled) {
|
|
assert(scale_factor > 0.0);
|
|
wmat_dist = 0.001 / scale_factor;
|
|
}
|
|
else {
|
|
wmat_dist = 0.001;
|
|
}
|
|
wmat_angle = 0.1;
|
|
}
|
|
#else
|
|
wmat_angle = wmat_dist = 0.0;
|
|
#endif
|
|
if (compute_wmat) {
|
|
draw_mat = true;
|
|
ComputeWMAT(wmat_angle, wmat_dist, time_it, left_offset,
|
|
right_offset);
|
|
wmat_computed = true;
|
|
if (write_ma) OutputMA(ma_file);
|
|
}
|
|
}
|
|
#endif
|
|
#ifdef MIC
|
|
if (computed && finished && !mic_computed && !pnts_only) {
|
|
if (compute_mic) {
|
|
draw_mic = true;
|
|
ComputeMIC(time_it, left_offset, right_offset, ¢er, &rad);
|
|
center.x = center.y = rad = 0.0; /* avoid GCC complaints ...*/
|
|
mic_computed = true;
|
|
}
|
|
}
|
|
#endif
|
|
#ifdef HSM
|
|
if (computed && finished && !path_computed) {
|
|
if (compute_path) {
|
|
ComputePath(time_it, path_file, write_path, dxf_format, tool_rad,
|
|
step_over, angle);
|
|
path_computed = true;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (computed && finished && !quiet && (off_finished || path_computed)) {
|
|
/* */
|
|
/* hey, let's ring the bell */
|
|
/* */
|
|
if (write_ipe) {
|
|
dummy_draw_pnts = draw_pnts;
|
|
draw_pnts = true;
|
|
WriteIpeOutput(output_file);
|
|
draw_pnts = dummy_draw_pnts;
|
|
}
|
|
printf("%c\n", Bell);
|
|
printf("%c\n", Bell);
|
|
printf("%c\n", Bell);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void vroniObject::ClosePolygon(void)
|
|
{
|
|
if (!computed && (io_flag != 2)) {
|
|
if (first_pnt != last_pnt) {
|
|
assert(first_pnt != NIL);
|
|
assert(last_pnt != NIL);
|
|
assert(new_pnts > 0);
|
|
#ifdef EXT_APPL_SITES
|
|
CloseSeg(last_pnt, first_pnt, eas_NIL);
|
|
#else
|
|
CloseSeg(last_pnt, first_pnt);
|
|
#endif
|
|
DrawSeg(GetPntCoords(last_pnt), GetPntCoords(first_pnt), SegColor);
|
|
new_input = true;
|
|
}
|
|
else {
|
|
new_input = (new_pnts > 0);
|
|
fprintf(stderr, "\n\n***** No polygon to close! *****\n");
|
|
}
|
|
first_pnt = NIL;
|
|
last_pnt = NIL;
|
|
new_pnts = 0;
|
|
|
|
new_input = data_read || new_input;
|
|
}
|
|
|
|
io_flag = 2;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void vroniObject::StartNewPolygon(void)
|
|
{
|
|
if (!computed) {
|
|
if (first_input) {
|
|
VD_Info("...storing the input data -- ");
|
|
first_input = false;
|
|
draw_pnts = true;
|
|
}
|
|
io_flag = 1;
|
|
first_pnt = NIL;
|
|
last_pnt = NIL;
|
|
isolated_pnts = true;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
void vroniObject::AddPolygonVertex(double_arg xc1, double_arg yc1)
|
|
{
|
|
int i;
|
|
|
|
if (!computed && (io_flag == 1)) {
|
|
|
|
if (first_pnt == NIL) {
|
|
#ifdef EXT_APPL_PNTS
|
|
first_pnt = HandlePnt(xc1, yc1, eap_NIL);
|
|
#else
|
|
first_pnt = HandlePnt(xc1, yc1);
|
|
#endif
|
|
last_pnt = first_pnt;
|
|
}
|
|
else {
|
|
i = last_pnt;
|
|
#ifdef EXT_APPL_SITES
|
|
AddSeg(&last_pnt, xc1, yc1, eas_NIL);
|
|
#else
|
|
AddSeg(&last_pnt, xc1, yc1);
|
|
#endif
|
|
DrawSeg(GetPntCoords(last_pnt), GetPntCoords(i), SegColor);
|
|
}
|
|
DrawPnt(GetPntCoords(last_pnt), PntColor, true);
|
|
if (pnts_only) {
|
|
StartNewPolygon();
|
|
#ifdef OGL_GRAPHICS
|
|
ResetRubberLine();
|
|
#endif
|
|
}
|
|
|
|
FlushDisplay();
|
|
|
|
++new_pnts;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void vroniObject::ResetOnlineGraphicsData(void)
|
|
{
|
|
first_input = true;
|
|
first_pnt = NIL;
|
|
last_pnt = NIL;
|
|
new_pnts = 0;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
void vroniObject::ResetDriverData(void)
|
|
{
|
|
computed = false;
|
|
finished = false;
|
|
off_finished = false;
|
|
off_init = false;
|
|
wmat_computed = false;
|
|
mic_computed = false;
|
|
vd_output = false;
|
|
io_flag = 0;
|
|
|
|
return;
|
|
}
|
|
|
|
#endif /* OGL_GRAPHICS */
|