/*****************************************************************************/ /* */ /* 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 #include #include #include #include #include /* */ /* 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 */