vroni 7.6 :
- aggiunti file della libreria e progetto visual studio.
This commit is contained in:
@@ -0,0 +1,561 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) Martin Held 1999-2023 */
|
||||
/* */
|
||||
/* */
|
||||
/* 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 read the file STANDARD_REPLY.txt for a detailed explanation, and */
|
||||
/* 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-172 */
|
||||
/* Voice Mail: (+43 662) 8044-6304 */
|
||||
/* Snail Mail: Martin Held */
|
||||
/* FB Informatik */
|
||||
/* Universitaet Salzburg */
|
||||
/* A-5020 Salzburg, Austria */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Please read the README and README_data files before 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>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/* */
|
||||
/* get my header files */
|
||||
/* */
|
||||
#include "fpkernel.h"
|
||||
#include "coord.h"
|
||||
#include "vroni_object.h"
|
||||
|
||||
|
||||
/* */
|
||||
/* function prototypes of functions provided in this file; see arg_eval.cc */
|
||||
/* for the default values of most of those parameters. */
|
||||
/* */
|
||||
vroniObject& API_VD(); /* get access to underlying VD */
|
||||
void API_ParseCommandLineArgs(int argc, char *argv[], vr_bool *graphics,
|
||||
vr_bool *color_graphics, vr_bool *full_screen);
|
||||
void API_InitializeProgram(void); /* call this routine once prior */
|
||||
/* calling any other routine of */
|
||||
/* VRONI */
|
||||
void API_GetInputData(vr_bool *input_received);
|
||||
void API_ProceedWithoutGraphics(vr_bool new_input);
|
||||
void API_ResetAll(void); /* call this routine whenever */
|
||||
/* new data is to be input and */
|
||||
/* VRONI's data structures are */
|
||||
/* to be reset; note that this */
|
||||
/* function won't free memory */
|
||||
/* allocated */
|
||||
void API_TerminateProgram(void); /* call this routine to release */
|
||||
/* all memory allocated by VRONI*/
|
||||
void API_HandleInput(char input_file[], /* name of the input file */
|
||||
vr_bool *new_input, /* true if new data has been */
|
||||
/* read */
|
||||
vr_bool read_polygon, /* read ".dat" format */
|
||||
vr_bool read_poly, /* read ".poly" format */
|
||||
vr_bool read_sites, /* read ".site" format */
|
||||
vr_bool read_xdr, /* read ".xdr" format */
|
||||
vr_bool read_e00, /* read ".e00" format */
|
||||
vr_bool read_polylines, /* read ".polylines" format */
|
||||
vr_bool read_usgs, /* read ".usgs" format */
|
||||
vr_bool read_dxf, /* read ".dxf" format */
|
||||
vr_bool read_pnts, /* read ".pnt" format */
|
||||
vr_bool read_graphml); /* read ".graphml" format */
|
||||
void API_FileInput(char input_file[], /* name of the input file */
|
||||
vr_bool *new_input); /* true if new data has been */
|
||||
/* read */
|
||||
/* this function requires the */
|
||||
/* user to stick to my naming */
|
||||
/* convention for the extension */
|
||||
/* of the input file relative */
|
||||
/* to the data format used */
|
||||
void API_ArrayInput(int number_of_points, /* data in point_data[0,..,k] */
|
||||
/* for k := number_of_points-1 */
|
||||
in_pnts *point_data, /* see ext_appl_inout.h */
|
||||
int number_of_segments,
|
||||
in_segs *segment_data, /* see ext_appl_inout.h */
|
||||
int number_of_arcs,
|
||||
in_arcs *arc_data, /* see ext_appl_inout.h */
|
||||
vr_bool *new_input);
|
||||
void API_ComputeVD(vr_bool save_data, /* save input data to file? */
|
||||
vr_bool new_data, /* first call for this data? */
|
||||
vr_bool time, /* do you want to time the */
|
||||
/* computation? */
|
||||
int bound, /* scale factor for bounding */
|
||||
/* box; default value: 3 */
|
||||
int sample, /* sampling factor for sampling */
|
||||
/* segs/arcs; default: 0; */
|
||||
/* see SampleData() in */
|
||||
/* approx.cc */
|
||||
int approx, /* approximation factor for */
|
||||
/* circular arcs; default: 0; */
|
||||
/* see ApproxArcsHeuristic() in */
|
||||
/* approx.cc. obsolet by now! */
|
||||
char output_file[], /* name of the output file; */
|
||||
/* irrelevant if save_data is */
|
||||
/* false */
|
||||
vr_bool discard_duplicate_sites,
|
||||
/* shall the code check prior */
|
||||
/* to the computation whether */
|
||||
/* duplicate segs/arcs have */
|
||||
/* been input? default: false. */
|
||||
vr_bool pnts_only, /* compute VD/DT of points only */
|
||||
vr_bool write_vd_dt, /* output point VD/DT */
|
||||
char vd_dt_file[], /* output file for point VD/DT */
|
||||
vr_bool clean_up); /* shall we clean up the data */
|
||||
/* prior to the VD computation? */
|
||||
void API_ComputeOff(vr_bool time, /* do you want to time the */
|
||||
/* computation? */
|
||||
char off_file[], /* name of the file that will */
|
||||
/* contain the offsets computed */
|
||||
vr_bool write_off, /* shall we output the offsets */
|
||||
/* to off_file[]? */
|
||||
vr_bool dxf_format, /* if offsets are to be output: */
|
||||
/* shall we use DXF format? */
|
||||
double t_offset, /* compute offset curve(s) for */
|
||||
/* offset distance t_offset */
|
||||
double d_offset, /* incremental step-over */
|
||||
/* distance for further offset */
|
||||
/* curves */
|
||||
vr_bool auto_offset, /* shall we use my heuristic */
|
||||
/* for finding offset distances */
|
||||
/* that create a family of */
|
||||
/* offsets? */
|
||||
vr_bool left_offset, /* true if offsets are to be */
|
||||
/* computed only on the left */
|
||||
/* side of input segments */
|
||||
vr_bool right_offset); /* true if offsets are to be */
|
||||
/* computed only on the right */
|
||||
/* side of input segments */
|
||||
#ifdef MAT
|
||||
void API_ComputeWMAT(vr_bool auto_wmat, /* shall we use my heuristic */
|
||||
/* for finding nice WMAT */
|
||||
/* thresholds? */
|
||||
double wmat_angle, /* angle threshold for WMAT */
|
||||
/* computation;in radians, out */
|
||||
/* of the interval [0, pi] */
|
||||
double wmat_dist, /* distance threshold for WMAT */
|
||||
/* computation */
|
||||
vr_bool time, /* do you want to time the */
|
||||
/* computation? */
|
||||
vr_bool left_wmat, /* true if WMAT is to be */
|
||||
/* computed only on the left */
|
||||
/* side of input segments */
|
||||
vr_bool right_wmat); /* true if WMAT is to be */
|
||||
/* computed only on the right */
|
||||
/* side of input segments */
|
||||
#endif
|
||||
#ifdef WRITE_VD
|
||||
void API_Output_VD(char vd_file[], /* name of the file that will */
|
||||
/* contain the VD polygons */
|
||||
double vd_apx_dist, /* sampling distance used for */
|
||||
/* approximating conic VD edges */
|
||||
vr_bool left_vd, /* true if VD is to be */
|
||||
/* output only on the left */
|
||||
/* side of input segments */
|
||||
vr_bool right_vd); /* true if VD is to be */
|
||||
/* output on the right */
|
||||
/* side of input segments */
|
||||
#endif
|
||||
void API_ComputeOutputMIC(vr_bool time, /* do you want to time the */
|
||||
/* computation? */
|
||||
vr_bool left_mic, /* true if MIC is to be */
|
||||
/* computed only on the left */
|
||||
/* side of input segments */
|
||||
vr_bool right_mic, /* true if MIC is to be */
|
||||
/* computed only on the right */
|
||||
/* side of input segments */
|
||||
coord *center, /* x,y-coordinates of a MIC */
|
||||
/* center */
|
||||
double *radius); /* radius of a MIC circle */
|
||||
void API_ResetOffsetData(void); /* discard all offsets computed */
|
||||
/* so far */
|
||||
|
||||
void API_HandleError(void); /* VRONI exception handling */
|
||||
|
||||
|
||||
const char* API_GetProgName();
|
||||
const char* API_GetProgVersion();
|
||||
const char* API_GetProgYear();
|
||||
|
||||
|
||||
/* */
|
||||
/* maintain pre-existing API functions by using a static VRONI object */
|
||||
/* */
|
||||
static vroniObject static_vd;
|
||||
|
||||
|
||||
|
||||
vroniObject& API_VD()
|
||||
{
|
||||
return static_vd;
|
||||
}
|
||||
|
||||
|
||||
void API_HandleError(void)
|
||||
{
|
||||
static_vd.apiHandleError();
|
||||
|
||||
exit(2);
|
||||
}
|
||||
|
||||
|
||||
void API_ParseCommandLineArgs(int argc, char *argv[], vr_bool *graphics,
|
||||
vr_bool *color_graphics, vr_bool *full_screen)
|
||||
{
|
||||
try {
|
||||
static_vd.ParseCommandLineArgs(argc, argv, graphics,
|
||||
color_graphics, full_screen);
|
||||
}
|
||||
catch ( ... ) {
|
||||
API_HandleError();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void API_InitializeProgram(void)
|
||||
{
|
||||
try {
|
||||
static_vd.apiInitializeProgram();
|
||||
}
|
||||
catch ( ... ) {
|
||||
API_HandleError();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void API_GetInputData(vr_bool *input_received)
|
||||
{
|
||||
try {
|
||||
static_vd.GetInputData(input_received);
|
||||
}
|
||||
catch ( ... ) {
|
||||
API_HandleError();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void API_ProceedWithoutGraphics(vr_bool new_input)
|
||||
{
|
||||
try {
|
||||
static_vd.ProceedWithoutGraphics(new_input);
|
||||
}
|
||||
catch ( ... ) {
|
||||
API_HandleError();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void API_CheckThresholds(void)
|
||||
{
|
||||
try {
|
||||
API_InitializeProgram();
|
||||
}
|
||||
catch ( ... ) {
|
||||
API_HandleError();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void API_HandleInput(char input_file[], vr_bool *new_input,
|
||||
vr_bool read_polygon, vr_bool read_poly,
|
||||
vr_bool read_sites, vr_bool read_xdr,
|
||||
vr_bool read_e00, vr_bool read_polylines,
|
||||
vr_bool read_usgs, vr_bool read_dxf,
|
||||
vr_bool read_pnts, vr_bool read_graphml)
|
||||
{
|
||||
try {
|
||||
static_vd.apiHandleInput(input_file, new_input,
|
||||
read_polygon, read_poly,
|
||||
read_sites, read_xdr,
|
||||
read_e00, read_polylines,
|
||||
read_usgs, read_dxf,
|
||||
read_pnts, read_graphml);
|
||||
}
|
||||
catch ( ... ) {
|
||||
API_HandleError();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void API_FileInput(char input_file[], vr_bool *new_input)
|
||||
{
|
||||
try {
|
||||
static_vd.apiFileInput(input_file, new_input);
|
||||
}
|
||||
catch ( ... ) {
|
||||
API_HandleError();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void API_ArrayInput(int number_of_points, in_pnts *point_data,
|
||||
int number_of_segments, in_segs *segment_data,
|
||||
int number_of_arcs, in_arcs *arc_data,
|
||||
vr_bool *new_input)
|
||||
{
|
||||
try {
|
||||
static_vd.apiArrayInput(number_of_points, point_data,
|
||||
number_of_segments, segment_data,
|
||||
number_of_arcs, arc_data,
|
||||
new_input);
|
||||
}
|
||||
catch ( ... ) {
|
||||
API_HandleError();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void API_ComputeVD(vr_bool save_data, vr_bool new_input, vr_bool time,
|
||||
int bound, int sample, int approx, char output_file[],
|
||||
vr_bool discard_dupl_s, vr_bool pnts_only, vr_bool write_vd,
|
||||
char vd_dt_file[], vr_bool clean_up)
|
||||
{
|
||||
try {
|
||||
static_vd.apiComputeVD(save_data, new_input, time,
|
||||
bound, sample, approx, output_file,
|
||||
discard_dupl_s, pnts_only, write_vd,
|
||||
vd_dt_file, clean_up);
|
||||
}
|
||||
catch ( ... ) {
|
||||
API_HandleError();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef WRITE_VD
|
||||
/* */
|
||||
/* Please be warned that this function results in an approximation of all */
|
||||
/* conic VD edges by straight-line segments and, thus, destroys the VD */
|
||||
/* computed by VRONI. */
|
||||
/* It is only to be used if an export of an (approximate) VD is sought, and */
|
||||
/* if no further computations on the VD computed by VRONI are required! */
|
||||
/* */
|
||||
void API_Output_VD(char vd_file[], double vd_apx_dist,
|
||||
vr_bool left_vd, vr_bool right_vd)
|
||||
{
|
||||
try {
|
||||
static_vd.apiOutput_VD(vd_file, vd_apx_dist, left_vd, right_vd);
|
||||
}
|
||||
catch ( ... ) {
|
||||
API_HandleError();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
void API_TerminateProgram(void)
|
||||
{
|
||||
return static_vd.apiTerminateProgram();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void API_ComputeOff(vr_bool time, char off_file[], vr_bool write_off,
|
||||
vr_bool dxf_format, double t_offset,
|
||||
double d_offset, vr_bool auto_offset, vr_bool left_offset,
|
||||
vr_bool right_offset)
|
||||
{
|
||||
try {
|
||||
static_vd.apiComputeOff(time, off_file, write_off,
|
||||
dxf_format, t_offset,
|
||||
d_offset, auto_offset, left_offset,
|
||||
right_offset);
|
||||
}
|
||||
catch ( ... ) {
|
||||
API_HandleError();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef MAT
|
||||
void API_ComputeWMAT(vr_bool auto_wmat, double wmat_angle, double wmat_dist,
|
||||
vr_bool time, vr_bool left_wmat, vr_bool right_wmat)
|
||||
{
|
||||
try {
|
||||
static_vd.apiComputeWMAT(auto_wmat, wmat_angle, wmat_dist,
|
||||
time, left_wmat, right_wmat);
|
||||
}
|
||||
catch ( ... ) {
|
||||
API_HandleError();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* this function outputs a description of the MA within a polygon. */
|
||||
/* note that it will only work if the input represents one closed polygon, */
|
||||
/* and if the MA construction was restricted to the interior of that */
|
||||
/* polygon. starting at a root node chosen at VRONI's discretion, the MA */
|
||||
/* tree is output as a list of numbered quintuples */
|
||||
/* (node_id, pnt_coord, radius, parent_node_id, edge_classifier), */
|
||||
/* where */
|
||||
/* node_id ... the ID number (non-negative integer) of the node; */
|
||||
/* it depends on VRONI's data structure and is */
|
||||
/* assigned at VRONI's discretion; */
|
||||
/* pnt_coord ... x,y coordinates of the MA node; */
|
||||
/* radius ... radius of clearance disk at that node; */
|
||||
/* parent_node_id ... the ID number of the parent node of the current */
|
||||
/* node in the MA tree; set to -1 for the root; */
|
||||
/* edge_classifier ... an enumeration type that describes the type of the */
|
||||
/* MA edge between the current node and its parent; */
|
||||
/* it is set to */
|
||||
/* 1 if the MA edge is defined by two vertices, */
|
||||
/* i.e., if it is part of a hyperbolic bisector, */
|
||||
/* 2 if the MA edge is defined by two segments, */
|
||||
/* i.e., if it is part of a straight-line bisector,*/
|
||||
/* 3 if a vertex is on the left of the MA edge */
|
||||
/* as one looks towards the parent of the node, */
|
||||
/* i.e., if it is part of a parabolic bisector, */
|
||||
/* 4 if a vertex is on the right of the MA edge */
|
||||
/* as one looks towards the parent of the node, */
|
||||
/* i.e., if it is part of a parabolic bisector; */
|
||||
/* 9 for the root node. */
|
||||
/* */
|
||||
void API_OutputMA(char vdma_file[])
|
||||
{
|
||||
#ifdef MAT
|
||||
try {
|
||||
static_vd.OutputMA(vdma_file);
|
||||
}
|
||||
catch ( ... ) {
|
||||
API_HandleError();
|
||||
}
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void API_ComputeOutputMIC(vr_bool time, vr_bool left_mic, vr_bool right_mic,
|
||||
coord *center, double *radius)
|
||||
{
|
||||
try {
|
||||
static_vd.apiComputeOutputMIC(time, left_mic, right_mic, center, radius);
|
||||
}
|
||||
catch ( ... ) {
|
||||
API_HandleError();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void API_ResetAll(void)
|
||||
{
|
||||
static_vd.apiResetAll();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void API_ResetOffsetData(void)
|
||||
{
|
||||
static_vd.apiResetOffsetData();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const char* API_GetProgName()
|
||||
{
|
||||
return static_vd.apiGetProgName();
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char* API_GetProgVersion()
|
||||
{
|
||||
return static_vd.apiGetProgVersion();
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char* API_GetProgYear()
|
||||
{
|
||||
return static_vd.apiGetProgYear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
#include "ext_appl_defs.cc"
|
||||
@@ -0,0 +1,572 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* 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-611 */
|
||||
/* 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>
|
||||
|
||||
|
||||
/* */
|
||||
/* get my header files */
|
||||
/* */
|
||||
#include "vroni_object.h"
|
||||
#include "fpkernel.h"
|
||||
#include "numerics.h"
|
||||
#include "approx.h"
|
||||
|
||||
|
||||
|
||||
#define SAMPLE_RATE 0.1
|
||||
#define PAGE_SIZE 32768
|
||||
|
||||
|
||||
#define UpdateBoundingBox(XC, YC) \
|
||||
{\
|
||||
if (XC > bb_max.x) bb_max.x = XC; \
|
||||
else if (XC < bb_min.x) bb_min.x = XC; \
|
||||
if (YC > bb_max.y) bb_max.y = YC; \
|
||||
else if (YC < bb_min.y) bb_min.y = YC; \
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void vroniObject::ApproxArcsHeuristic(int approx)
|
||||
{
|
||||
int i1, i2, i3, i4;
|
||||
double xc1, yc1, xc3, yc3, angle_s, angle_e;
|
||||
double x_dist, y_dist, dist, min, radius, incr, alpha;
|
||||
coord p1, p2, p3;
|
||||
int i;
|
||||
#ifdef EXT_APPL_SITES
|
||||
eas_type ext_appl;
|
||||
#endif
|
||||
|
||||
assert(approx > 0);
|
||||
x_dist = bb_max.x - bb_min.x;
|
||||
y_dist = bb_max.y - bb_min.y;
|
||||
dist = Max(x_dist, y_dist);
|
||||
assert(dist > 0.0);
|
||||
if (eq(dist, ZERO)) dist = 1.0;
|
||||
|
||||
for (i = 0; i < num_arcs; ++i) {
|
||||
/* */
|
||||
/* obtain the arc data. */
|
||||
/* */
|
||||
p1 = GetArcStartCoord(i);
|
||||
p2 = GetArcEndCoord(i);
|
||||
p3 = GetArcCenter(i);
|
||||
radius = GetArcRadius(i);
|
||||
#ifdef EXT_APPL_SITES
|
||||
ext_appl = GetExtApplArc(i);
|
||||
#endif
|
||||
|
||||
/* */
|
||||
/* discretize the arc and replace it by line segments. */
|
||||
/* */
|
||||
if (GetArcOrientation(i)) {
|
||||
/* */
|
||||
/* the original orientation of the arc was CCW. note that we */
|
||||
/* store all input arcs as CCW arcs! */
|
||||
/* */
|
||||
i1 = Get1stVtx(i, ARC);
|
||||
i2 = Get2ndVtx(i, ARC);
|
||||
xc1 = p1.x;
|
||||
yc1 = p1.y;
|
||||
xc3 = p3.x;
|
||||
yc3 = p3.y;
|
||||
|
||||
angle_s = atan2(yc1 - yc3, xc1 - xc3);
|
||||
angle_e = atan2(p2.y - yc3, p2.x - xc3);
|
||||
if (angle_s < 0.0) angle_s += M_2PI;
|
||||
if (angle_e < 0.0) angle_e += M_2PI;
|
||||
if (angle_e < angle_s) angle_e += M_2PI;
|
||||
if (gt(radius, ZERO))
|
||||
incr = M_2PI * dist / (radius * approx);
|
||||
else
|
||||
incr = M_2PI;
|
||||
min = (angle_e - angle_s) / 2.99;
|
||||
incr = Min(incr, min);
|
||||
angle_e -= incr;
|
||||
alpha = angle_s + incr;
|
||||
|
||||
while (alpha < angle_e) {
|
||||
xc1 = xc3 + radius * cos(alpha);
|
||||
yc1 = yc3 + radius * sin(alpha);
|
||||
#ifdef EXT_APPL_PNTS
|
||||
i4 = StorePnt(xc1, yc1, eap_NIL);
|
||||
#else
|
||||
i4 = StorePnt(xc1, yc1);
|
||||
#endif
|
||||
UpdateBoundingBox(xc1, yc1);
|
||||
#ifdef EXT_APPL_SITES
|
||||
i3 = StoreSeg(i1, i4, ext_appl);
|
||||
#else
|
||||
i3 = StoreSeg(i1, i4);
|
||||
#endif
|
||||
#ifdef GRAPHICS
|
||||
if (graphics) {
|
||||
AddSegToBuffer(i3, ArcColor);
|
||||
AddPntToBuffer(i4, ArcColor);
|
||||
}
|
||||
#endif
|
||||
i1 = i4;
|
||||
alpha += incr;
|
||||
}
|
||||
|
||||
alpha = alpha + (angle_e - alpha) / 2.0;
|
||||
xc1 = xc3 + radius * cos(alpha);
|
||||
yc1 = yc3 + radius * sin(alpha);
|
||||
#ifdef EXT_APPL_PNTS
|
||||
i4 = StorePnt(xc1, yc1, eap_NIL);
|
||||
#else
|
||||
i4 = StorePnt(xc1, yc1);
|
||||
#endif
|
||||
UpdateBoundingBox(xc1, yc1);
|
||||
#ifdef EXT_APPL_SITES
|
||||
i3 = StoreSeg(i1, i4, ext_appl);
|
||||
#else
|
||||
i3 = StoreSeg(i1, i4);
|
||||
#endif
|
||||
#ifdef GRAPHICS
|
||||
if (graphics) {
|
||||
AddSegToBuffer(i3, ArcColor);
|
||||
AddPntToBuffer(i4, ArcColor);
|
||||
}
|
||||
#endif
|
||||
#ifdef EXT_APPL_SITES
|
||||
i3 = StoreSeg(i4, i2, ext_appl);
|
||||
#else
|
||||
i3 = StoreSeg(i4, i2);
|
||||
#endif
|
||||
#ifdef GRAPHICS
|
||||
if (graphics) {
|
||||
AddSegToBuffer(i3, ArcColor);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
/* */
|
||||
/* the original orientation of the arc was CW. note that we */
|
||||
/* store all input arcs as CCW arcs! */
|
||||
/* */
|
||||
i1 = Get1stVtx(i, ARC);
|
||||
i2 = Get2ndVtx(i, ARC);
|
||||
xc1 = p1.x;
|
||||
yc1 = p1.y;
|
||||
xc3 = p3.x;
|
||||
yc3 = p3.y;
|
||||
|
||||
angle_s = atan2(yc1 - yc3, xc1 - xc3);
|
||||
angle_e = atan2(p2.y - yc3, p2.x - xc3);
|
||||
if (angle_s < 0.0) angle_s += M_2PI;
|
||||
if (angle_e < 0.0) angle_e += M_2PI;
|
||||
if (angle_e < angle_s) angle_e += M_2PI;
|
||||
if (gt(radius, ZERO))
|
||||
incr = M_2PI * dist / (radius * approx);
|
||||
else
|
||||
incr = M_2PI;
|
||||
min = (angle_e - angle_s) / 2.99;
|
||||
incr = Min(incr, min);
|
||||
angle_s += incr;
|
||||
alpha = angle_e - incr;
|
||||
|
||||
while (alpha > angle_s) {
|
||||
xc1 = xc3 + radius * cos(alpha);
|
||||
yc1 = yc3 + radius * sin(alpha);
|
||||
#ifdef EXT_APPL_PNTS
|
||||
i4 = StorePnt(xc1, yc1, eap_NIL);
|
||||
#else
|
||||
i4 = StorePnt(xc1, yc1);
|
||||
#endif
|
||||
UpdateBoundingBox(xc1, yc1);
|
||||
#ifdef EXT_APPL_SITES
|
||||
i3 = StoreSeg(i2, i4, ext_appl);
|
||||
#else
|
||||
i3 = StoreSeg(i2, i4);
|
||||
#endif
|
||||
#ifdef GRAPHICS
|
||||
if (graphics) {
|
||||
AddSegToBuffer(i3, ArcColor);
|
||||
AddPntToBuffer(i4, ArcColor);
|
||||
}
|
||||
#endif
|
||||
i2 = i4;
|
||||
alpha -= incr;
|
||||
}
|
||||
|
||||
alpha = alpha + (angle_s - alpha) / 2.0;
|
||||
xc1 = xc3 + radius * cos(alpha);
|
||||
yc1 = yc3 + radius * sin(alpha);
|
||||
#ifdef EXT_APPL_PNTS
|
||||
i4 = StorePnt(xc1, yc1, eap_NIL);
|
||||
#else
|
||||
i4 = StorePnt(xc1, yc1);
|
||||
#endif
|
||||
UpdateBoundingBox(xc1, yc1);
|
||||
#ifdef EXT_APPL_SITES
|
||||
i3 = StoreSeg(i2, i4, ext_appl);
|
||||
#else
|
||||
i3 = StoreSeg(i2, i4);
|
||||
#endif
|
||||
#ifdef GRAPHICS
|
||||
if (graphics) {
|
||||
AddSegToBuffer(i3, ArcColor);
|
||||
AddPntToBuffer(i4, ArcColor);
|
||||
}
|
||||
#endif
|
||||
#ifdef EXT_APPL_SITES
|
||||
i3 = StoreSeg(i4, i1, ext_appl);
|
||||
#else
|
||||
i3 = StoreSeg(i4, i1);
|
||||
#endif
|
||||
#ifdef GRAPHICS
|
||||
if (graphics) {
|
||||
AddSegToBuffer(i3, ArcColor);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
/* no circular arcs left! */
|
||||
/* */
|
||||
num_arcs = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* this routine allows to replace (input) circular arcs by polygonal */
|
||||
/* approximations. let A be an arc with center C and radius R. */
|
||||
/* a polygonal approximation APX of A is considered valid with respect */
|
||||
/* to the user-specified (non-negative) parameter apx_absolute if the */
|
||||
/* following inequality holds for all points P of APX: */
|
||||
/* R <= d(C,P) <= R + apx_absolute, */
|
||||
/* where d(C,P) denotes the Euclidean distance between C and P. */
|
||||
/* similarly, APX is valid with respect to apx_relative if */
|
||||
/* R <= d(C,P) <= R * (1 + apx_relative) */
|
||||
/* for all P of APX. */
|
||||
/* */
|
||||
/* the polygonal approximation APX is obtained as a sequence of line */
|
||||
/* segments that are tangent to A. furthermore, all line segments of APX */
|
||||
/* are assigned the index of A in order to facilitate the computation of */
|
||||
/* the VD and to help with the subsequent recovery of the approximate VD of */
|
||||
/* the original arcs. while this routine may be used as a blueprint for */
|
||||
/* modeling your own arc approximation, the flag arcs_apx may >>only<< be */
|
||||
/* set if exactly this approximation mechanism has been used -- the validity */
|
||||
/* of the simplified computations carried out by VRONI if two segments are */
|
||||
/* derived from the same arc depends on the properties of my approximation */
|
||||
/* mechanism!!!! */
|
||||
/* */
|
||||
/* furthermore, please be warned that the simplified VD computation is bound */
|
||||
/* to run into problems if the radii of an arc's start point and end point */
|
||||
/* differ! for this reason, AdjustArcs() is called in order to adapt the */
|
||||
/* radii and adjust the center, if needed. obviously, adjusting the center */
|
||||
/* will destroy tangency properties between subsequent arcs. since there is */
|
||||
/* no obviously correct way to deal with inconsistent radii, the user is */
|
||||
/* strongly urged to supply the coordinates of the start point, end point */
|
||||
/* and center of every arc with >maximum< (double) precision, and to */
|
||||
/* re-compute this data prior to calling VRONI (if needed), rather than to */
|
||||
/* force VRONI to adjust the center and radii in its own way!!! */
|
||||
/* */
|
||||
/* note: if the input data is scaled by VRONI to make it fit into the unit */
|
||||
/* square, then the thresholds apx_absolute and apx_relative are adjusted */
|
||||
/* appropriately by VRONI. thus, if scaling was performed then the */
|
||||
/* thresholds used within this routine need not equal the thresholds input */
|
||||
/* by the user. */
|
||||
/* */
|
||||
void vroniObject::ApproxArcsBounded(double apx_absolute, double apx_relative)
|
||||
{
|
||||
#ifndef ARC_APX
|
||||
if ((num_arcs > 0) && ((apx_absolute > 0.0) || (apx_relative > 0.0))) {
|
||||
VD_Warning("ApproxArcsBounded() - compile-time option `-DARC_APX' not used!\n");
|
||||
return;
|
||||
}
|
||||
#else
|
||||
int i, i1, i2, i3, i4, k, number;
|
||||
double xc3, yc3, xc4, yc4;
|
||||
double radius, max_incr;
|
||||
coord p1, p2, p3;
|
||||
int num_critical_arcs;
|
||||
vr_bool ccw_orientation;
|
||||
#ifdef EXT_APPL_SITES
|
||||
eas_type ext_appl;
|
||||
#endif
|
||||
vronivector<coord> apx_vtx;
|
||||
int max_num_apx_vtx = 0;
|
||||
|
||||
/* */
|
||||
/* memorize the number of input points and line segments! (approximating */
|
||||
/* the circular arcs will add a few line segments...) */
|
||||
/* */
|
||||
SetOriginalSegNumber();
|
||||
SetOriginalPntNumber();
|
||||
|
||||
/* make sure that all circular arcs have consistent radii. if necessary, */
|
||||
/* we'll adjust the centers!! */
|
||||
/* */
|
||||
PreprocessArcs(&num_critical_arcs);
|
||||
|
||||
/* */
|
||||
/* compute the maximum angular increment if relative errors are to be */
|
||||
/* used */
|
||||
/* */
|
||||
assert((apx_absolute > 0.0) || (apx_relative > 0.0));
|
||||
if (apx_relative > 0.0) {
|
||||
apx_absolute = 0.0;
|
||||
if (apx_relative > (M_SQRT2 - 1.0)) {
|
||||
apx_relative = M_SQRT2 - 1.0;
|
||||
max_incr = M_PI_4 / 4.0;
|
||||
}
|
||||
else {
|
||||
max_incr = acos(1.0 / (1.0 + apx_relative));
|
||||
}
|
||||
}
|
||||
else if (apx_absolute <= 0.0) {
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if (data_scaled) {
|
||||
assert(gt(scale_factor, ZERO));
|
||||
apx_absolute *= scale_factor;
|
||||
}
|
||||
max_incr = M_PI_4 / 4.0;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_arcs; ++i) {
|
||||
/* */
|
||||
/* obtain the arc data. */
|
||||
/* */
|
||||
p1 = GetArcStartCoord(i);
|
||||
p2 = GetArcEndCoord(i);
|
||||
p3 = GetArcCenter(i);
|
||||
radius = GetArcRadius(i);
|
||||
assert(gt(radius, ZERO));
|
||||
xc3 = p3.x;
|
||||
yc3 = p3.y;
|
||||
#ifdef EXT_APPL_SITES
|
||||
ext_appl = GetExtApplArc(i);
|
||||
#endif
|
||||
|
||||
/* */
|
||||
/* discretize the arc and replace it by line segments. */
|
||||
/* */
|
||||
if (GetArcOrientation(i)) {
|
||||
/* */
|
||||
/* the original orientation of the arc was CCW. note that we */
|
||||
/* store all input arcs as CCW arcs! */
|
||||
/* */
|
||||
i1 = Get1stVtx(i, ARC);
|
||||
i2 = Get2ndVtx(i, ARC);
|
||||
ccw_orientation = true;
|
||||
}
|
||||
else {
|
||||
/* */
|
||||
/* the original orientation of the arc was CW. */
|
||||
/* */
|
||||
i2 = Get1stVtx(i, ARC);
|
||||
i1 = Get2ndVtx(i, ARC);
|
||||
ccw_orientation = false;
|
||||
}
|
||||
|
||||
/* */
|
||||
/* compute the new pnts and segs */
|
||||
/* */
|
||||
ApproxArc(p1, p2, xc3, yc3, radius, ccw_orientation,
|
||||
apx_absolute, apx_vtx, max_num_apx_vtx, max_incr, number);
|
||||
|
||||
/* */
|
||||
/* store the new pnts and segs */
|
||||
/* */
|
||||
for (k = 0; k < number; ++k) {
|
||||
xc4 = apx_vtx[k].x;
|
||||
yc4 = apx_vtx[k].y;
|
||||
#ifdef EXT_APPL_PNTS
|
||||
i4 = StorePnt(xc4, yc4, eap_NIL);
|
||||
#else
|
||||
i4 = StorePnt(xc4, yc4);
|
||||
#endif
|
||||
SetPntArc(i4, i);
|
||||
UpdateBoundingBox(xc4, yc4);
|
||||
#ifdef EXT_APPL_SITES
|
||||
i3 = StoreSeg(i1, i4, ext_appl);
|
||||
#else
|
||||
i3 = StoreSeg(i1, i4);
|
||||
#endif
|
||||
SetSegArc(i3, i);
|
||||
#ifdef GRAPHICS
|
||||
if (graphics) {
|
||||
AddSegToBuffer(i3, ArcColor);
|
||||
AddPntToBuffer(i4, ArcColor);
|
||||
}
|
||||
#endif
|
||||
i1 = i4;
|
||||
}
|
||||
#ifdef EXT_APPL_SITES
|
||||
i3 = StoreSeg(i1, i2, ext_appl);
|
||||
#else
|
||||
i3 = StoreSeg(i1, i2);
|
||||
#endif
|
||||
SetSegArc(i3, i);
|
||||
#ifdef GRAPHICS
|
||||
if (graphics) AddSegToBuffer(i3, ArcColor);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* */
|
||||
/* no circular arcs left! */
|
||||
/* */
|
||||
apx_vtx.clear();
|
||||
SetOriginalArcNumber();
|
||||
num_arcs = 0;
|
||||
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
void vroniObject::SampleData(int sample)
|
||||
{
|
||||
int i, i4;
|
||||
double radius, sample_rate, xc1, yc1, xc3, yc3, angle_s, angle_e;
|
||||
coord vec, a, p1, p2, p3;
|
||||
double incr, min, x_dist, y_dist, dist, delta, alpha;
|
||||
|
||||
assert(sample > 0);
|
||||
|
||||
isolated_pnts = true;
|
||||
|
||||
x_dist = bb_max.x - bb_min.x;
|
||||
y_dist = bb_max.y - bb_min.y;
|
||||
dist = Max(x_dist, y_dist);
|
||||
assert(dist > 0.0);
|
||||
if (eq(dist, ZERO)) dist = 1.0;
|
||||
|
||||
sample_rate = dist * SAMPLE_RATE / sample;
|
||||
|
||||
for (i = 0; i < num_segs; ++i) {
|
||||
p1 = GetSegStartCoord(i);
|
||||
p2 = GetSegEndCoord(i);
|
||||
|
||||
vec = VecSub(p2, p1);
|
||||
delta = VecLen(vec);
|
||||
|
||||
if (gt(delta, ZERO) && (sample_rate < delta)) {
|
||||
vec = VecDiv(delta, vec);
|
||||
incr = sample_rate;
|
||||
delta -= sample_rate;
|
||||
while (incr < delta) {
|
||||
a = RayPnt(p1, vec, incr);
|
||||
#ifdef EXT_APPL_PNTS
|
||||
i4 = StorePnt(a.x, a.y, eap_NIL);
|
||||
#else
|
||||
i4 = StorePnt(a.x, a.y);
|
||||
#endif
|
||||
#ifdef GRAPHICS
|
||||
if (graphics) AddPntToBuffer(i4, SegColor);
|
||||
#endif
|
||||
incr += sample_rate;
|
||||
}
|
||||
incr = incr + (delta - incr) / 2.0;
|
||||
a = RayPnt(p1, vec, incr);
|
||||
#ifdef EXT_APPL_PNTS
|
||||
i4 = StorePnt(a.x, a.y, eap_NIL);
|
||||
#else
|
||||
i4 = StorePnt(a.x, a.y);
|
||||
#endif
|
||||
#ifdef GRAPHICS
|
||||
if (graphics) AddPntToBuffer(i4, SegColor);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
sample_rate /= 2.0;
|
||||
|
||||
for (i = 0; i < num_arcs; ++i) {
|
||||
p1 = GetArcStartCoord(i);
|
||||
p2 = GetArcEndCoord(i);
|
||||
p3 = GetArcCenter(i);
|
||||
radius = GetArcRadius(i);
|
||||
xc1 = p1.x;
|
||||
yc1 = p1.y;
|
||||
xc3 = p3.x;
|
||||
yc3 = p3.y;
|
||||
|
||||
angle_s = atan2(yc1 - yc3, xc1 - xc3);
|
||||
angle_e = atan2(p2.y - yc3, p2.x - xc3);
|
||||
if (angle_s < 0.0) angle_s += M_2PI;
|
||||
if (angle_e < 0.0) angle_e += M_2PI;
|
||||
if (angle_e < angle_s) angle_e += M_2PI;
|
||||
if (gt(radius, ZERO))
|
||||
incr = 2.0 * asin(sample_rate / radius);
|
||||
else
|
||||
incr = M_2PI;
|
||||
min = (angle_e - angle_s) / 2.99;
|
||||
incr = Min(incr, min);
|
||||
angle_e -= incr;
|
||||
alpha = angle_s + incr;
|
||||
|
||||
while (alpha < angle_e) {
|
||||
xc1 = xc3 + radius * cos(alpha);
|
||||
yc1 = yc3 + radius * sin(alpha);
|
||||
#ifdef EXT_APPL_PNTS
|
||||
i4 = StorePnt(xc1, yc1, eap_NIL);
|
||||
#else
|
||||
i4 = StorePnt(xc1, yc1);
|
||||
#endif
|
||||
UpdateBoundingBox(xc1, yc1);
|
||||
#ifdef GRAPHICS
|
||||
if (graphics) AddPntToBuffer(i4, ArcColor);
|
||||
#endif
|
||||
alpha += incr;
|
||||
}
|
||||
alpha = alpha + (angle_e - alpha) / 2.0;
|
||||
xc1 = xc3 + radius * cos(alpha);
|
||||
yc1 = yc3 + radius * sin(alpha);
|
||||
#ifdef EXT_APPL_PNTS
|
||||
i4 = StorePnt(xc1, yc1, eap_NIL);
|
||||
#else
|
||||
i4 = StorePnt(xc1, yc1);
|
||||
#endif
|
||||
UpdateBoundingBox(xc1, yc1);
|
||||
#ifdef GRAPHICS
|
||||
if (graphics) AddPntToBuffer(i4, ArcColor);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* */
|
||||
/* no line segments and circular arcs left! reset the counters. */
|
||||
/* */
|
||||
num_arcs = 0;
|
||||
num_segs = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 2003--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 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef VRONI_APPROX_H
|
||||
#define VRONI_APPROX_H
|
||||
|
||||
inline void ApproxArc(const coord & p1, const coord & p2,
|
||||
double_arg xc3, double_arg yc3, double_arg radius,
|
||||
vr_bool ccw_orientation, double_arg apx_absolute,
|
||||
vronivector<coord> & apx_vtx, int & max_num_apx_vtx,
|
||||
double_arg max_incr, int & number)
|
||||
{
|
||||
double incr;
|
||||
/* */
|
||||
/* determine the start angle and end angle of the arc */
|
||||
/* */
|
||||
double angle_s = atan2(p1.y - yc3, p1.x - xc3);
|
||||
double angle_e = atan2(p2.y - yc3, p2.x - xc3);
|
||||
|
||||
if (angle_s < 0.0) angle_s += M_2PI;
|
||||
if (angle_e < 0.0) angle_e += M_2PI;
|
||||
if (angle_e < angle_s) angle_e += M_2PI;
|
||||
|
||||
/* */
|
||||
/* determine the angular increment incr: we will insert points at */
|
||||
/* the angles angle_s + 0.5 * incr, angle_s + 1.5 * incr, ..., */
|
||||
/* angle_e - 0.5 * incr (for a CCW arc). */
|
||||
/* */
|
||||
|
||||
if (apx_absolute > 0.0) {
|
||||
incr = acos(radius / (radius + apx_absolute));
|
||||
incr = Min(incr, max_incr);
|
||||
}
|
||||
else {
|
||||
incr = max_incr;
|
||||
}
|
||||
incr *= 10.0;
|
||||
assert(gt(incr, ZERO));
|
||||
double diff = (angle_e - angle_s);
|
||||
incr = diff / (2.0 * incr);
|
||||
number = REAL_TO_INT(Ceiling(incr));
|
||||
if (number <= 0) number = 1;
|
||||
incr = diff / ((double) (number));
|
||||
|
||||
/* */
|
||||
/* the new pnts will lie at a distance lgth from the arc's center */
|
||||
/* */
|
||||
// double lgth = radius / cos(incr / 2.0);
|
||||
double lgth = radius;
|
||||
double alpha;
|
||||
if (ccw_orientation) {
|
||||
alpha = angle_s + incr / 2.0;
|
||||
}
|
||||
else {
|
||||
alpha = angle_e - incr / 2.0;
|
||||
incr = - incr;
|
||||
}
|
||||
|
||||
/* */
|
||||
/* allocate memory for the new vertices to be computed */
|
||||
/* */
|
||||
if (number > max_num_apx_vtx) {
|
||||
max_num_apx_vtx = number;
|
||||
gentlyResizeSTLVector(apx_vtx, max_num_apx_vtx, "approx:apx_vtx");
|
||||
}
|
||||
|
||||
/* */
|
||||
/* compute and store the new pnts and segs */
|
||||
/* */
|
||||
//printf("p1.x = %20.16f, p1.y = %20.16f\n", p1.x, p1.y);
|
||||
//printf("p2.x = %20.16f, p2.y = %20.16f\n", p2.x, p2.y);
|
||||
for (int k = 0; k < number; ++k) {
|
||||
assert(k <= max_num_apx_vtx);
|
||||
apx_vtx[k].x = xc3 + lgth * cos(alpha);
|
||||
apx_vtx[k].y = yc3 + lgth * sin(alpha);
|
||||
//printf("alpha = %20.16f\n", alpha);
|
||||
alpha += incr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
+712
@@ -0,0 +1,712 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 2007-2023 S. Huber, 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: Stefan Huber, 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
|
||||
/* */
|
||||
/* get my header files */
|
||||
/* */
|
||||
#include "vroni_object.h"
|
||||
#include "vronivector.h"
|
||||
#include "fpkernel.h"
|
||||
#include "defs.h"
|
||||
#include "numerics.h"
|
||||
#include "roots.h"
|
||||
#include "vddata.h"
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* Calculate the Voronoi center of three arcs */
|
||||
/* */
|
||||
vr_bool vroniObject::ArcArcArcCntr(int i, int j, int k, int e,
|
||||
coord* cntr, double *r2,
|
||||
vr_bool *problematic, int *site)
|
||||
{
|
||||
int t, m, n, best_sol, n1;
|
||||
coord c1, c2, c3;
|
||||
double rr1, rr2, rr3, rad;
|
||||
coord centers[VRONI_MAXSOL];
|
||||
double radii[VRONI_MAXSOL];
|
||||
int num_sol=0;
|
||||
coord tmp;
|
||||
int tmpi;
|
||||
double tmpr;
|
||||
coord spi, epi, spj, epj, spk, epk;
|
||||
double eps;
|
||||
int i_in, j_in, k_in;
|
||||
vr_bool ik_joint = false, jk_joint = false, ij_joint = false, no_check;
|
||||
vr_bool ik_tangent = false, jk_tangent = false, ij_tangent = false, is_special;
|
||||
vr_bool jk_counter = false, ij_counter = false, ik_counter = false;
|
||||
double d_c1c2, d_c1c3, d_c2c3;
|
||||
coord ep, v;
|
||||
|
||||
#ifdef TRACE
|
||||
if ((i == 0) && (j == 1) && (k == 23)) {
|
||||
printf("arc %d-arc %d-arc %d\n", i, j, k);
|
||||
printf("start1 : (%20.16f %20.16f)\n", GetArcStartCoord(i).x,
|
||||
GetArcStartCoord(i).y);
|
||||
printf("end1 : (%20.16f %20.16f)\n", GetArcEndCoord(i).x,
|
||||
GetArcEndCoord(i).y);
|
||||
printf("center1: (%20.16f %20.16f)\n", GetArcCenter(i).x,
|
||||
GetArcCenter(i).y);
|
||||
printf("start2 : (%20.16f %20.16f)\n", GetArcStartCoord(j).x,
|
||||
GetArcStartCoord(j).y);
|
||||
printf("end2 : (%20.16f %20.16f)\n", GetArcEndCoord(j).x,
|
||||
GetArcEndCoord(j).y);
|
||||
printf("center2: (%20.16f %20.16f)\n", GetArcCenter(j).x,
|
||||
GetArcCenter(j).y);
|
||||
printf("start3 : (%20.16f %20.16f)\n", GetArcStartCoord(k).x,
|
||||
GetArcStartCoord(k).y);
|
||||
printf("end3 : (%20.16f %20.16f)\n", GetArcEndCoord(k).x,
|
||||
GetArcEndCoord(k).y);
|
||||
printf("center3: (%20.16f %20.16f)\n", GetArcCenter(k).x,
|
||||
GetArcCenter(k).y);
|
||||
}
|
||||
#endif
|
||||
|
||||
i_in = i;
|
||||
j_in = j;
|
||||
k_in = k;
|
||||
|
||||
*site = NIL;
|
||||
*problematic = false;
|
||||
|
||||
/* */
|
||||
/* Guarantee that permutations of i,j,k lead to same center */
|
||||
/* */
|
||||
SortThreeNumbers(i,j,k,t);
|
||||
|
||||
/* */
|
||||
/* Check whether the three cites are all in lists */
|
||||
/* */
|
||||
assert(InArcsList(i));
|
||||
assert(InArcsList(j));
|
||||
assert(InArcsList(k));
|
||||
|
||||
/* */
|
||||
/* check whether the three sites share a common end point, or whether two */
|
||||
/* of them are identical */
|
||||
/* */
|
||||
eps = GetIntersectionThreshold();
|
||||
m = Get1stVtx(k, ARC);
|
||||
if (IsArcStartPnt(i, m) || IsArcEndPnt(i, m)) {
|
||||
if (IsArcStartPnt(j, m) || IsArcEndPnt(j, m)) {
|
||||
n = Get2ndVtx(k, ARC);
|
||||
if (IsArcStartPnt(i, n) || IsArcEndPnt(i, n)) {
|
||||
if (le(PntPntDist(GetArcCenter(i),GetArcCenter(k)), eps)) {
|
||||
SetInvalidSites(i, ARC, k, ARC, eps);
|
||||
restart = false;
|
||||
return false; /* duplicate arcs ! */
|
||||
}
|
||||
}
|
||||
else if (IsArcStartPnt(j, n) || IsArcEndPnt(j, n)) {
|
||||
if (le(PntPntDist(GetArcCenter(j),GetArcCenter(k)), eps)) {
|
||||
SetInvalidSites(j, ARC, k, ARC, eps);
|
||||
restart = false;
|
||||
return false; /* duplicate arcs ! */
|
||||
}
|
||||
}
|
||||
*cntr = GetPntCoords(m);
|
||||
*r2 = 0.0;
|
||||
*site = m;
|
||||
return true; /* common end point */
|
||||
}
|
||||
ik_joint = true;
|
||||
}
|
||||
else if (IsArcStartPnt(j, m) || IsArcEndPnt(j, m)) {
|
||||
jk_joint = true;
|
||||
}
|
||||
m = Get2ndVtx(k, ARC);
|
||||
if (IsArcStartPnt(i, m) || IsArcEndPnt(i, m)) {
|
||||
if (ik_joint) {
|
||||
if (le(PntPntDist(GetArcCenter(i),GetArcCenter(k)), eps)) {
|
||||
SetInvalidSites(i, ARC, k, ARC, eps);
|
||||
restart = false;
|
||||
return false; /* duplicate arcs ! */
|
||||
}
|
||||
}
|
||||
if (IsArcStartPnt(j, m) || IsArcEndPnt(j, m)) {
|
||||
if (jk_joint) {
|
||||
if (le(PntPntDist(GetArcCenter(j),GetArcCenter(k)), eps)) {
|
||||
SetInvalidSites(j, ARC, k, ARC, eps);
|
||||
restart = false;
|
||||
return false; /* duplicate arcs ! */
|
||||
}
|
||||
}
|
||||
*cntr = GetPntCoords(m);
|
||||
*r2 = 0.0;
|
||||
*site = m;
|
||||
return true; /* common end point */
|
||||
}
|
||||
}
|
||||
else if (IsArcStartPnt(j, m) || IsArcEndPnt(j, m)) {
|
||||
if (jk_joint) {
|
||||
if (le(PntPntDist(GetArcCenter(j),GetArcCenter(k)), eps)) {
|
||||
SetInvalidSites(j, ARC, k, ARC, eps);
|
||||
restart = false;
|
||||
return false; /* duplicate arcs ! */
|
||||
}
|
||||
}
|
||||
}
|
||||
m = Get1stVtx(i, ARC);
|
||||
if (IsArcStartPnt(j, m) || IsArcEndPnt(j, m)) {
|
||||
m = Get2ndVtx(i, ARC);
|
||||
if (IsArcStartPnt(j, m) || IsArcEndPnt(j, m)) {
|
||||
if (le(PntPntDist(GetArcCenter(i),GetArcCenter(j)), eps)) {
|
||||
SetInvalidSites(i, ARC, j, ARC, eps);
|
||||
restart = false;
|
||||
return false; /* duplicate arcs ! */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
eps = ZERO;
|
||||
|
||||
while (eps <= ZERO_MAX) {
|
||||
no_check = false;
|
||||
ij_joint = false;
|
||||
jk_joint = false;
|
||||
ik_joint = false;
|
||||
is_special = false;
|
||||
num_sol = 0;
|
||||
|
||||
/* */
|
||||
/* check whether any pair of the arcs has (roughly) a common endpoint */
|
||||
/* */
|
||||
spi = GetArcStartCoord(i);
|
||||
epi = GetArcEndCoord(i);
|
||||
spj = GetArcStartCoord(j);
|
||||
epj = GetArcEndCoord(j);
|
||||
spk = GetArcStartCoord(k);
|
||||
epk = GetArcEndCoord(k);
|
||||
if ((PntPntDist(spi,spj) <= eps) || (PntPntDist(spi,epj) <= eps) ||
|
||||
(PntPntDist(epi,spj) <= eps) || (PntPntDist(epi,epj) <= eps))
|
||||
ij_joint = true;
|
||||
if ((PntPntDist(spj,spk) <= eps) || (PntPntDist(spj,epk) <= eps) ||
|
||||
(PntPntDist(epj,spk) <= eps) || (PntPntDist(epj,epk) <= eps))
|
||||
jk_joint = true;
|
||||
if ((PntPntDist(spi,spk) <= eps) || (PntPntDist(spi,epk) <= eps) ||
|
||||
(PntPntDist(epi,spk) <= eps) || (PntPntDist(epi,epk) <= eps))
|
||||
ik_joint = true;
|
||||
|
||||
/* */
|
||||
/* if common endpoints exist then we rearrange the indices of the */
|
||||
/* arcs such that the first and the second arc have a common endpoint */
|
||||
/* and, possibly, also the second and the third arc have a common */
|
||||
/* endpoint */
|
||||
/* */
|
||||
if (ij_joint) {
|
||||
if (jk_joint) { /* keep original i-j-k order */
|
||||
}
|
||||
else if (ik_joint) { /* put into the order j-i-k */
|
||||
Swap(i, j, tmpi);
|
||||
Swap(spi, spj, tmp);
|
||||
Swap(epi, epj, tmp);
|
||||
jk_joint = true;
|
||||
ik_joint = false;
|
||||
}
|
||||
else { /* keep original i-j-k order */
|
||||
}
|
||||
}
|
||||
else if (ik_joint) {
|
||||
if (jk_joint) { /* put into the order i-k-j */
|
||||
Swap(j, k, tmpi);
|
||||
Swap(spj, spk, tmp);
|
||||
Swap(epj, epk, tmp);
|
||||
ij_joint = true;
|
||||
ik_joint = false;
|
||||
}
|
||||
else { /* put into the order i-k-j */
|
||||
Swap(j, k, tmpi);
|
||||
Swap(spj, spk, tmp);
|
||||
Swap(epj, epk, tmp);
|
||||
ij_joint = true;
|
||||
ik_joint = false;
|
||||
}
|
||||
}
|
||||
else if (jk_joint) { /* put into the order k-j-i */
|
||||
Swap(i, k, tmpi);
|
||||
Swap(spi, spk, tmp);
|
||||
Swap(epi, epk, tmp);
|
||||
ij_joint = true;
|
||||
jk_joint = false;
|
||||
}
|
||||
else { /* keep original i-j-k order */
|
||||
}
|
||||
|
||||
c1 = GetArcCenter(i);
|
||||
c2 = GetArcCenter(j);
|
||||
c3 = GetArcCenter(k);
|
||||
rr1 = GetArcRadius(i);
|
||||
rr2 = GetArcRadius(j);
|
||||
rr3 = GetArcRadius(k);
|
||||
|
||||
d_c1c2 = PntPntDist(c1,c2);
|
||||
d_c2c3 = PntPntDist(c2,c3);
|
||||
d_c1c3 = PntPntDist(c1,c3);
|
||||
|
||||
if (ij_joint) {
|
||||
if (Abs(rr1+rr2 - d_c1c2) <= eps) {
|
||||
ij_counter = ((VecDet(c1,c2,spi) + VecDet(c1,c2,epi))*
|
||||
(VecDet(c1,c2,spj) + VecDet(c1,c2,epj)) <= eps);
|
||||
ij_tangent = false;
|
||||
}
|
||||
else {
|
||||
ij_counter = false;
|
||||
ij_tangent = ((Abs(Abs(rr1-rr2) - d_c1c2) <= eps) &&
|
||||
((VecDet(c1,c2,spi) + VecDet(c1,c2,epi))*
|
||||
(VecDet(c1,c2,spj) + VecDet(c1,c2,epj)) <= eps));
|
||||
}
|
||||
if (jk_joint) {
|
||||
if (Abs(rr2+rr3 - d_c2c3) <= eps) {
|
||||
jk_counter = ((VecDet(c2,c3,spj) + VecDet(c2,c3,epj))*
|
||||
(VecDet(c2,c3,spk) + VecDet(c2,c3,epk)) <= eps);
|
||||
jk_tangent = false;
|
||||
}
|
||||
else {
|
||||
jk_counter = false;
|
||||
jk_tangent = ((Abs(Abs(rr2-rr3) - d_c2c3) <= eps) &&
|
||||
((VecDet(c2,c3,spj) + VecDet(c2,c3,epj))*
|
||||
(VecDet(c2,c3,spk) + VecDet(c2,c3,epk)) <= eps));
|
||||
}
|
||||
}
|
||||
else {
|
||||
jk_counter = jk_tangent = false;
|
||||
}
|
||||
if (ik_joint) {
|
||||
if (Abs(rr1+rr3 - d_c1c3) <= eps) {
|
||||
ik_counter = ((VecDet(c1,c3,spj) + VecDet(c1,c3,epj))*
|
||||
(VecDet(c1,c3,spk) + VecDet(c1,c3,epk)) <= eps);
|
||||
ik_tangent = false;
|
||||
}
|
||||
else {
|
||||
ik_counter = false;
|
||||
ik_tangent = ((Abs(Abs(rr1-rr3) - d_c1c3) <= eps) &&
|
||||
((VecDet(c1,c3,spj) + VecDet(c1,c3,epj))*
|
||||
(VecDet(c1,c3,spk) + VecDet(c1,c3,epk)) <= eps));
|
||||
}
|
||||
}
|
||||
else {
|
||||
ik_counter = ik_tangent = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ij_counter = ij_tangent = jk_counter = jk_tangent = false;
|
||||
ik_counter = ik_tangent = false;
|
||||
}
|
||||
|
||||
if (!(ij_counter || ij_tangent)) {
|
||||
if (ik_tangent || ik_counter) {
|
||||
Swap(ij_counter, ik_counter, tmpi);
|
||||
Swap(ij_tangent, ik_tangent, tmpi);
|
||||
Swap(j, k, tmpi);
|
||||
Swap(spj, spk, tmp);
|
||||
Swap(epj, epk, tmp);
|
||||
Swap(c2, c3, tmp);
|
||||
Swap(rr2, rr3, tmpr);
|
||||
Swap(d_c1c2, d_c1c3, tmpr);
|
||||
}
|
||||
else if (jk_tangent || jk_counter) {
|
||||
Swap(ij_counter, jk_counter, tmpi);
|
||||
Swap(ij_tangent, jk_tangent, tmpi);
|
||||
Swap(i, k, tmpi);
|
||||
Swap(spi, spk, tmp);
|
||||
Swap(epi, epk, tmp);
|
||||
Swap(c1, c3, tmp);
|
||||
Swap(rr1, rr3, tmpr);
|
||||
Swap(d_c1c2, d_c2c3, tmpr);
|
||||
}
|
||||
}
|
||||
else if (!(jk_counter || jk_tangent)) {
|
||||
if (ik_tangent || ik_counter) {
|
||||
Swap(ij_counter, ik_counter, tmpi);
|
||||
Swap(ij_tangent, ik_tangent, tmpi);
|
||||
Swap(j, k, tmpi);
|
||||
Swap(spj, spk, tmp);
|
||||
Swap(epj, epk, tmp);
|
||||
Swap(c2, c3, tmp);
|
||||
Swap(rr2, rr3, tmpr);
|
||||
Swap(d_c1c2, d_c1c3, tmpr);
|
||||
|
||||
Swap(ij_counter, jk_counter, tmpi);
|
||||
Swap(ij_tangent, jk_tangent, tmpi);
|
||||
Swap(i, j, tmpi);
|
||||
Swap(spi, spj, tmp);
|
||||
Swap(epi, epj, tmp);
|
||||
Swap(c1, c2, tmp);
|
||||
Swap(rr1, rr2, tmpr);
|
||||
Swap(d_c2c3, d_c1c3, tmpr);
|
||||
}
|
||||
}
|
||||
|
||||
if (jk_counter || jk_tangent) {
|
||||
if (ij_tangent && jk_tangent) {
|
||||
/* */
|
||||
/* two tangential joints? then the three arcs should lie */
|
||||
/* roughly on the same circle! */
|
||||
/* */
|
||||
if ((d_c1c2 <= eps) && (d_c2c3 <= eps) && (d_c1c3 <= eps)) {
|
||||
num_sol = 1;
|
||||
centers[0].x = (c1.x + c2.x + c3.x) / 3.0;
|
||||
centers[0].y = (c1.y + c2.y + c3.y) / 3.0;
|
||||
radii[0] = (rr1 + rr2 + rr3) / 3.0;
|
||||
no_check = true;
|
||||
is_special = true;
|
||||
}
|
||||
}
|
||||
else if (ij_tangent && jk_counter) {
|
||||
/* */
|
||||
/* one meeting is tangential, the other is counter-tangential */
|
||||
/* */
|
||||
if (d_c1c2 <= eps) {
|
||||
num_sol = 1;
|
||||
centers[0] = MidPoint(c1,c2);
|
||||
radii[0] = (rr1 + rr2) / 2.0;
|
||||
no_check = true;
|
||||
is_special = true;
|
||||
}
|
||||
}
|
||||
else if (ij_counter && jk_tangent) {
|
||||
/* */
|
||||
/* one meeting is tangential, the other is counter-tangential */
|
||||
/* */
|
||||
if (d_c2c3 <= eps) {
|
||||
num_sol = 1;
|
||||
centers[0] = MidPoint(c2,c3);
|
||||
radii[0] = (rr2 + rr3) / 2.0;
|
||||
no_check = true;
|
||||
is_special = true;
|
||||
}
|
||||
}
|
||||
else if (ij_counter && jk_counter) {
|
||||
/* */
|
||||
/* both meetings are counter-tangential */
|
||||
/* */
|
||||
num_sol = 1;
|
||||
centers[0] = c2;
|
||||
radii[0] = rr2;
|
||||
no_check = true;
|
||||
is_special = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_special) {
|
||||
if (ij_counter) {
|
||||
/* */
|
||||
/* two counter-tangential arcs with common endpoint and on */
|
||||
/* different sides of the center-line */
|
||||
/* */
|
||||
//printf("\ttwo counter-tangential circles (%d-%d-%d)\n", i, j ,k);
|
||||
if ((PntPntDist(spi,spj) <= eps) || (PntPntDist(spi,epj) <= eps))
|
||||
ep = spi;
|
||||
else
|
||||
ep = epi;
|
||||
v = VecSub(ep, c1);
|
||||
num_sol = IntersectRayCircle(ep, v, c3, rr3, centers, radii, eps);
|
||||
is_special = true;
|
||||
}
|
||||
else if (ij_tangent) {
|
||||
/* */
|
||||
/* two tangential arcs with common endpoint */
|
||||
/* */
|
||||
// printf("\ttwo tangential circles (%d-%d-%d)\n", i, j ,k);
|
||||
|
||||
if ((i == i_in) || (j == i_in)) {
|
||||
n1 = GetStartNode(e);
|
||||
if (!IsNodeDeleted(n1)) n1 = GetEndNode(e);
|
||||
if (IsNodeDeleted(n1)) {
|
||||
GetNodeData(n1, &tmp, &rad);
|
||||
num_sol = 1;
|
||||
centers[0] = tmp;
|
||||
radii[0] = rad;
|
||||
no_check = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!no_check) {
|
||||
if ((PntPntDist(spi,spj) <= eps) || (PntPntDist(spi,epj) <= eps))
|
||||
ep = spi;
|
||||
else
|
||||
ep = epi;
|
||||
v = VecSub(ep, c1);
|
||||
num_sol = IntersectRayCircle(ep, v, c3, rr3, centers, radii,
|
||||
eps);
|
||||
|
||||
}
|
||||
is_special = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_special) {
|
||||
ij_tangent = (!ij_joint) && ((d_c1c2 <= eps) &&
|
||||
(Abs(rr1-rr2) <= eps));
|
||||
ik_tangent = (!ik_joint) && ((d_c1c3 <= eps) &&
|
||||
(Abs(rr1-rr3) <= eps));
|
||||
jk_tangent = (!jk_joint) && ((d_c2c3 <= eps) &&
|
||||
(Abs(rr2-rr3) <= eps));
|
||||
}
|
||||
if (!is_special && (ij_tangent || jk_tangent || ik_tangent)) {
|
||||
if ((ij_tangent && ik_tangent) || (ij_tangent && jk_tangent) ||
|
||||
(ik_tangent && jk_tangent)) {
|
||||
/* */
|
||||
/* three arcs on a common circle without common endpoint */
|
||||
/* */
|
||||
//printf("\tthree common circles\n");
|
||||
num_sol = 1;
|
||||
centers[0].x = (c1.x + c2.x + c3.x) / 3.0;
|
||||
centers[0].y = (c1.y + c2.y + c3.y) / 3.0;
|
||||
radii[0] = (rr1 + rr2 + rr3) / 3.0;
|
||||
no_check = true;
|
||||
is_special = true;
|
||||
}
|
||||
else {
|
||||
/* */
|
||||
/* two arcs on the same circle, but without common endpoint */
|
||||
/* */
|
||||
if (ik_tangent) {
|
||||
Swap(j, k, tmpi);
|
||||
Swap(c2, c3, tmp);
|
||||
Swap(rr2, rr3, tmpr);
|
||||
}
|
||||
else if (jk_tangent) {
|
||||
Swap(i, k, tmpi);
|
||||
Swap(c1, c3, tmp);
|
||||
Swap(rr1, rr3, tmpr);
|
||||
}
|
||||
//printf("\tspecial case: cocircular disjoint circles: %d-%d-%d\n", i, j ,k);
|
||||
num_sol = 1;
|
||||
centers[0] = MidPoint(c1,c2);
|
||||
radii[0] = (rr1 + rr2) / 2.0;
|
||||
no_check = true;
|
||||
is_special = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_special) {
|
||||
/* */
|
||||
/* if two arcs are counter-tangential but do not share an endpoint: */
|
||||
/* check whether one endpoint lies on line through centers */
|
||||
/* */
|
||||
if ((!ij_joint) && (Abs(rr1+rr2 - d_c1c2) <= eps)) {
|
||||
if (eq(VecDet(c1,c2,spi), eps) ||
|
||||
eq(VecDet(c1,c2,epi), eps) ||
|
||||
eq(VecDet(c1,c2,spj), eps) ||
|
||||
eq(VecDet(c1,c2,epj), eps)) {
|
||||
is_special = true;
|
||||
centers[0] = c1;
|
||||
centers[1] = c2;
|
||||
radii[0] = rr1;
|
||||
radii[1] = rr2;
|
||||
num_sol = 2;
|
||||
}
|
||||
}
|
||||
if ((!jk_joint) && (Abs(rr2+rr3 - d_c2c3) <= eps)) {
|
||||
if (eq(VecDet(c2,c3,spj), eps) ||
|
||||
eq(VecDet(c2,c3,epj), eps) ||
|
||||
eq(VecDet(c2,c3,spk), eps) ||
|
||||
eq(VecDet(c2,c3,epk), eps)) {
|
||||
is_special = true;
|
||||
centers[0] = c2;
|
||||
centers[1] = c3;
|
||||
radii[0] = rr2;
|
||||
radii[1] = rr3;
|
||||
num_sol = 2;
|
||||
}
|
||||
}
|
||||
if ((!ik_joint) && (Abs(rr1+rr3 - d_c1c3) <= eps)) {
|
||||
if (eq(VecDet(c1,c3,spi), eps) ||
|
||||
eq(VecDet(c1,c3,epi), eps) ||
|
||||
eq(VecDet(c1,c3,spk), eps) ||
|
||||
eq(VecDet(c1,c3,epk), eps)) {
|
||||
is_special = true;
|
||||
centers[0] = c1;
|
||||
centers[1] = c3;
|
||||
radii[0] = rr1;
|
||||
radii[1] = rr3;
|
||||
num_sol = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_special) {
|
||||
/* */
|
||||
/* general case */
|
||||
/* */
|
||||
#ifdef TRACE
|
||||
if ((i == 4416) && (j == 4617) && (k == 4713)) {
|
||||
printf("\tordinary\n");
|
||||
printf("rr1 = %20.16f\n", rr1);
|
||||
printf("rr2 = %20.16f\n", rr2);
|
||||
printf("rr3 = %20.16f\n", rr3);
|
||||
}
|
||||
#endif
|
||||
//Determining good sequence of arcs to get good results
|
||||
if ( rr1 < rr2 ) {
|
||||
coord tmpc;
|
||||
double tmpd;
|
||||
int tmpi;
|
||||
Swap(c1,c2, tmpc);
|
||||
Swap(rr1,rr2, tmpd);
|
||||
Swap(i,j, tmpi);
|
||||
}
|
||||
if ( rr1 < rr3 ) {
|
||||
coord tmpc;
|
||||
double tmpd;
|
||||
int tmpi;
|
||||
Swap(c1,c3, tmpc);
|
||||
Swap(rr1,rr3, tmpd);
|
||||
Swap(i,k, tmpi);
|
||||
}
|
||||
if ( rr2 < rr3 ) {
|
||||
coord tmpc;
|
||||
double tmpd;
|
||||
int tmpi;
|
||||
Swap(c2,c3, tmpc);
|
||||
Swap(rr2,rr3, tmpd);
|
||||
Swap(j,k, tmpi);
|
||||
}
|
||||
|
||||
num_sol = CircCircCircCenters(c1, c2, c3, rr1, rr2, rr3, centers,
|
||||
radii, eps);
|
||||
#ifdef TRACE
|
||||
printf("in the general case! num_sol = %d\n", num_sol);
|
||||
printf("i_in = %d, j_in = %d, k_in = %d\n", i_in, j_in, k_in);
|
||||
#endif
|
||||
}
|
||||
|
||||
if ((num_sol > 0) && no_check)
|
||||
best_sol = 0;
|
||||
else
|
||||
/* */
|
||||
/* classify all solutions and pick the best solution */
|
||||
/* */
|
||||
best_sol = ClassifySolutions(i_in, j_in, k_in, e, ARC, ARC, ARC,
|
||||
false, true, true, centers, radii,
|
||||
&num_sol, eps, problematic);
|
||||
assert((0 <= best_sol) && (best_sol < num_sol));
|
||||
if (!*problematic) {
|
||||
*cntr = centers[best_sol];
|
||||
*r2 = radii[best_sol];
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
eps *= 10.0;
|
||||
}
|
||||
}
|
||||
|
||||
if (eq(GetArcRadius(i), ZERO_MAX)) {
|
||||
/* */
|
||||
/* this is an arc with a very small radius; we replace it */
|
||||
/* by a seg */
|
||||
/* */
|
||||
VD_Dbg_Warning("ArcArcArcCntr() - arc with small radius!");
|
||||
ReplaceArc(i);
|
||||
restart = true;
|
||||
return false;
|
||||
}
|
||||
else if (eq(GetArcRadius(j), ZERO_MAX)) {
|
||||
/* */
|
||||
/* this is an arc with a very small radius; we replace it */
|
||||
/* by a seg */
|
||||
/* */
|
||||
VD_Dbg_Warning("ArcArcArcCntr() - arc with small radius!");
|
||||
ReplaceArc(j);
|
||||
restart = true;
|
||||
return false;
|
||||
}
|
||||
else if (eq(GetArcRadius(k), ZERO_MAX)) {
|
||||
/* */
|
||||
/* this is an arc with a very small radius; we replace it */
|
||||
/* by a seg */
|
||||
/* */
|
||||
VD_Dbg_Warning("ArcArcArcCntr() - arc with small radius!");
|
||||
ReplaceArc(k);
|
||||
restart = true;
|
||||
return false;
|
||||
}
|
||||
else if (eq(PntPntDist(GetArcStartCoord(i), GetArcEndCoord(i)), ZERO_MAX)) {
|
||||
/* */
|
||||
/* this is an arc with a very short cord; we replace it by a seg */
|
||||
/* */
|
||||
VD_Dbg_Warning("ArcArcArcCntr() - arc with short cord!");
|
||||
ReplaceArc(i);
|
||||
restart = true;
|
||||
return false;
|
||||
}
|
||||
else if (eq(PntPntDist(GetArcStartCoord(j), GetArcEndCoord(j)), ZERO_MAX)) {
|
||||
/* */
|
||||
/* this is an arc with a very short cord; we replace it by a seg */
|
||||
/* */
|
||||
VD_Dbg_Warning("ArcArcArcCntr() - arc with short cord!");
|
||||
ReplaceArc(j);
|
||||
restart = true;
|
||||
return false;
|
||||
}
|
||||
else if (eq(PntPntDist(GetArcStartCoord(k), GetArcEndCoord(k)), ZERO_MAX)) {
|
||||
/* */
|
||||
/* this is an arc with a very short cord; we replace it by a seg */
|
||||
/* */
|
||||
VD_Dbg_Warning("ArcArcArcCntr() - arc with short cord!");
|
||||
ReplaceArc(k);
|
||||
restart = true;
|
||||
return false;
|
||||
}
|
||||
else if (CheckIntersectionsLocally(i, ARC, j, ARC, k, ARC)) {
|
||||
restart = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef VRONI_DBG_WARN
|
||||
spi = GetArcStartCoord(i);
|
||||
spj = GetArcStartCoord(j);
|
||||
spk = GetArcStartCoord(k);
|
||||
epj = GetArcEndCoord(j);
|
||||
epi = GetArcEndCoord(i);
|
||||
epk = GetArcEndCoord(k);
|
||||
c1 = GetArcCenter(i);
|
||||
c2 = GetArcCenter(j);
|
||||
c3 = GetArcCenter(k);
|
||||
printf("\nCenter not computed for arc-arc-arc:\n");
|
||||
printf("%20.16f %20.16f %20.16f %20.16f %20.16f %20.16f\n",
|
||||
spi.x, spi.y, epi.x, epi.y, c1.x, c1.y);
|
||||
printf("%20.16f %20.16f %20.16f %20.16f %20.16f %20.16f\n",
|
||||
spj.x, spj.y, epj.x, epj.y, c2.x, c2.y);
|
||||
printf("%20.16f %20.16f %20.16f %20.16f %20.16f %20.16f\n",
|
||||
spk.x, spk.y, epk.x, epk.y, c3.x, c3.y);
|
||||
#endif
|
||||
|
||||
*cntr = centers[best_sol];
|
||||
*r2 = radii[best_sol];
|
||||
restart = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+381
@@ -0,0 +1,381 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 2007-2023 S. Huber, 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: Stefan Huber, 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
|
||||
|
||||
/* */
|
||||
/* get my header files */
|
||||
/* */
|
||||
#include "vroni_object.h"
|
||||
#include "vronivector.h"
|
||||
#include "fpkernel.h"
|
||||
#include "defs.h"
|
||||
#include "numerics.h"
|
||||
#include "roots.h"
|
||||
|
||||
|
||||
/* */
|
||||
/* Calculate the Voronoi center of two arcs and one point */
|
||||
/* */
|
||||
vr_bool vroniObject::ArcArcPntCntr(int i, int j, int k, int e,
|
||||
coord* cntr, double *r2,
|
||||
vr_bool *problematic, int* site)
|
||||
{
|
||||
int t, n1;
|
||||
coord c1, c2, c3;
|
||||
double rr1, rr2, rr3 = 0, rad, d_c1c2;
|
||||
|
||||
coord centers[VRONI_MAXSOL];
|
||||
double radii[VRONI_MAXSOL];
|
||||
int num_sol = 0, best_sol = NIL, old_num_sol = 0;
|
||||
double eps = ZERO;
|
||||
coord spi, spj, epj, epi, ep, v;
|
||||
int i_in, j_in;
|
||||
vr_bool no_check, is_arc_endpoint, is_special;
|
||||
vr_bool spi_in_common, epi_in_common, counter_tangential;
|
||||
|
||||
i_in = i;
|
||||
j_in = j;
|
||||
|
||||
*problematic = false;
|
||||
|
||||
/* */
|
||||
/* Guarantee that permutations of i,j lead to same center */
|
||||
/* */
|
||||
SortTwoNumbers(i, j, t);
|
||||
|
||||
/* */
|
||||
/* Check whether the three sites are all in lists */
|
||||
/* */
|
||||
assert(InArcsList(i));
|
||||
assert(InArcsList(j));
|
||||
assert(InPntsList(k));
|
||||
|
||||
/* */
|
||||
/* check whether the two arcs are identical. */
|
||||
/* */
|
||||
if (i == j) {
|
||||
VD_Dbg_Warning("ArcArcPntCntr() - the same arc!");
|
||||
return false;
|
||||
}
|
||||
n1 = Get1stVtx(i, ARC);
|
||||
if (IsArcStartPnt(j, n1) || IsArcEndPnt(j, n1)) {
|
||||
n1 = Get2ndVtx(i, ARC);
|
||||
if (IsArcStartPnt(j, n1) || IsArcEndPnt(j, n1)) {
|
||||
if (le(PntPntDist(GetArcCenter(i),GetArcCenter(j)),
|
||||
GetIntersectionThreshold())) {
|
||||
SetInvalidSites(i, ARC, j, ARC, GetIntersectionThreshold());
|
||||
restart = false;
|
||||
return false; /* duplicate arcs ! */
|
||||
}
|
||||
}
|
||||
}
|
||||
/* */
|
||||
/* check whether the point pnts[k] is an endpoint of arcs[i] and */
|
||||
/* arcs[j]. */
|
||||
/* */
|
||||
if ((IsArcStartPnt(i,k) || IsArcEndPnt(i,k)) &&
|
||||
(IsArcStartPnt(j,k) || IsArcEndPnt(j,k))) {
|
||||
/* */
|
||||
/* pnt k is a common end-point of i and j. */
|
||||
/* */
|
||||
// printf("Point %d splits arc %d and arc %d\n", k, i, j);
|
||||
*cntr = GetPntCoords(k);
|
||||
*r2 = 0.0;
|
||||
*site = k;
|
||||
return true;
|
||||
}
|
||||
|
||||
rr1 = GetArcRadius(i);
|
||||
rr2 = GetArcRadius(j);
|
||||
rr3 = 0.0;
|
||||
|
||||
if (rr2 > rr1) {
|
||||
/* */
|
||||
/* make sure that first arc has the larger radius */
|
||||
/* */
|
||||
double tmpr;
|
||||
Swap(rr1, rr2, tmpr);
|
||||
Swap(i, j, t);
|
||||
}
|
||||
|
||||
c1 = GetArcCenter(i);
|
||||
c2 = GetArcCenter(j);
|
||||
c3 = GetPntCoords(k);
|
||||
|
||||
if (IsArcStartPnt(i,k) || IsArcEndPnt(i,k)) {
|
||||
v = VecSub(c1, c3);
|
||||
old_num_sol = IntersectRayCircle(c3, v, c2, rr2, centers, radii, ZERO);
|
||||
is_arc_endpoint = true;
|
||||
}
|
||||
else if (IsArcStartPnt(j,k) || IsArcEndPnt(j,k)) {
|
||||
v = VecSub(c2, c3);
|
||||
old_num_sol = IntersectRayCircle(c3, v, c1, rr1, centers, radii, ZERO);
|
||||
is_arc_endpoint = true;
|
||||
}
|
||||
else {
|
||||
is_arc_endpoint = false;
|
||||
}
|
||||
|
||||
d_c1c2 = PntPntDist(c1,c2);
|
||||
spi = GetArcStartCoord(i);
|
||||
spj = GetArcStartCoord(j);
|
||||
epj = GetArcEndCoord(j);
|
||||
epi = GetArcEndCoord(i);
|
||||
|
||||
while (eps <= ZERO_MAX) {
|
||||
no_check = false;
|
||||
is_special = false;
|
||||
num_sol = old_num_sol;
|
||||
|
||||
#ifdef TRACE
|
||||
if ((e == 15) && (i_in == 5)) {
|
||||
printf("\narc%d-arc%d-pnt%d: (%20.16f, %20.16f; %20.16f), (%20.16f, %20.16f; %20.16f), (%20.16f, %20.16f)\n", i, j, k, c1.x, c1.y, rr1, c2.x, c2.y, rr2, c3.x, c3.y);
|
||||
printf("is_arc_endpoint = %d\n", is_arc_endpoint);
|
||||
}
|
||||
if ((i_in == 0) && (k == 6)) {
|
||||
printf("\narc%d-arc%d-pnt%d: (%20.16f, %20.16f; %20.16f), (%20.16f, %20.16f; %20.16f), (%20.16f, %20.16f)\n", i, j, k, c1.x, c1.y, rr1, c2.x, c2.y, rr2, c3.x, c3.y);
|
||||
printf("is_arc_endpoint = %d\n", is_arc_endpoint);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!is_arc_endpoint) {
|
||||
|
||||
counter_tangential = ((VecDet(c1,c2,spi) + VecDet(c1,c2,epi)) *
|
||||
(VecDet(c1,c2,spj) + VecDet(c1,c2,epj)) <= eps);
|
||||
|
||||
if (DoArcPntIntersect(i_in, c3, eps)) {
|
||||
/* */
|
||||
/* pnt c3 is on arc i_in */
|
||||
/* */
|
||||
VD_Dbg_Warning("ArcArcPntCntr() - point lies in interior of arc!");
|
||||
SetInvalidSites(i_in, ARC, k, PNT, eps);
|
||||
restart = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* */
|
||||
/* check whether one endpoint of arc i is very close to one */
|
||||
/* endpoint of arc j */
|
||||
/* */
|
||||
if ((PntPntDist(spi,spj) <= eps) || (PntPntDist(spi,epj) <= eps)) {
|
||||
spi_in_common = true;
|
||||
epi_in_common = false;
|
||||
}
|
||||
else if ((PntPntDist(epi,spj) <= eps) || (PntPntDist(epi,epj) <= eps)) {
|
||||
spi_in_common = false;
|
||||
epi_in_common = true;
|
||||
}
|
||||
else {
|
||||
spi_in_common = false;
|
||||
epi_in_common = false;
|
||||
}
|
||||
|
||||
if (spi_in_common || epi_in_common) {
|
||||
/* */
|
||||
/* one endpoint of arc i is very close to one endpoint of j */
|
||||
/* */
|
||||
if (counter_tangential &&
|
||||
(Abs(d_c1c2 - Abs(rr1-rr2)) <= eps)) {
|
||||
/* */
|
||||
/* the arcs are (nearly) tangential */
|
||||
/* */
|
||||
//printf("\ttwo tangential arcs %d-%d and pnt %d\n", i, j, k);
|
||||
is_special = true;
|
||||
n1 = GetStartNode(e);
|
||||
if (!IsNodeDeleted(n1)) n1 = GetEndNode(e);
|
||||
GetNodeData(n1, &v, &rad);
|
||||
num_sol = 1;
|
||||
centers[0] = v;
|
||||
radii[0] = rad;
|
||||
|
||||
if (!IsNodeDeleted(n1)) {
|
||||
/* */
|
||||
/* get start point and direction of the ray on which the */
|
||||
/* bisector lies */
|
||||
/* */
|
||||
num_sol = 0;
|
||||
if (spi_in_common) ep = spi;
|
||||
else ep = epi;
|
||||
v = VecSub(ep, c1);
|
||||
num_sol = IntersectRayCircle(ep, v, c3, rr3, centers, radii,
|
||||
eps);
|
||||
}
|
||||
else {
|
||||
no_check = true;
|
||||
}
|
||||
}
|
||||
else if (counter_tangential && (Abs(rr1+rr2 - d_c1c2) <= eps)) {
|
||||
/* */
|
||||
/* the arcs are counter-tangential and lie on different sides */
|
||||
/* of the line through their centers */
|
||||
/* */
|
||||
is_special = true;
|
||||
//printf("\ttwo counter-tangential circles (%d-%d-%d)\n", i, j ,k);
|
||||
|
||||
/* */
|
||||
/* get start point and direction of the ray on which the */
|
||||
/* bisector lies */
|
||||
/* */
|
||||
if (spi_in_common) ep = spi;
|
||||
else ep = epi;
|
||||
v = VecSub(ep, c1);
|
||||
num_sol = IntersectRayCircle(ep, v, c3, rr3, centers, radii,
|
||||
eps);
|
||||
}
|
||||
}
|
||||
else if ((d_c1c2 <= eps) && (Abs(rr1-rr2) <= eps)) {
|
||||
/* */
|
||||
/* the arcs lie (nearly) on the same circle but do not share an */
|
||||
/* end point: their common center is the only possible VD node */
|
||||
/* */
|
||||
//printf("\tspecial case: cocircular disjoint circles: %d-%d-%d\n", i, j ,k);
|
||||
is_special = true;
|
||||
centers[0] = MidPoint(c1, c2);
|
||||
radii[0] = (rr1 + rr2) / 2.0;
|
||||
num_sol = 1;
|
||||
}
|
||||
else if (counter_tangential && (Abs(rr1+rr2 - d_c1c2) <= eps)) {
|
||||
/* */
|
||||
/* the arcs are counter-tangential but do not share an endpoint: */
|
||||
/* check whether one end point lies on line through centers */
|
||||
/* */
|
||||
if (eq(VecDet(c1,c2,spi), eps) || eq(VecDet(c1,c2,epi), eps) ||
|
||||
eq(VecDet(c1,c2,spj), eps) || eq(VecDet(c1,c2,epj), eps)) {
|
||||
is_special = true;
|
||||
centers[0] = c1;
|
||||
centers[1] = c2;
|
||||
radii[0] = rr1;
|
||||
radii[1] = rr2;
|
||||
num_sol = 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_special) {
|
||||
/* */
|
||||
/* and finally the general case... */
|
||||
/* */
|
||||
//printf("ordinary\n");
|
||||
num_sol = CircCircCircCenters(c1, c2, c3, rr1, rr2, rr3, centers,
|
||||
radii, eps);
|
||||
}
|
||||
}
|
||||
|
||||
if ((num_sol > 0) && no_check)
|
||||
best_sol = 0;
|
||||
else
|
||||
/* */
|
||||
/* classify all solutions and pick the best solution */
|
||||
/* */
|
||||
best_sol = ClassifySolutions(i_in, j_in, k, e, ARC, ARC, PNT,
|
||||
false, true, true, centers, radii,
|
||||
&num_sol, eps, problematic);
|
||||
|
||||
assert((0 <= best_sol) && (best_sol < num_sol));
|
||||
if (!*problematic) {
|
||||
*cntr = centers[best_sol];
|
||||
*r2 = radii[best_sol];
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
eps *= 10.0;
|
||||
}
|
||||
}
|
||||
|
||||
if (eq(GetArcRadius(i), ZERO_MAX)) {
|
||||
/* */
|
||||
/* this is an arc with a very small radius; we replace it */
|
||||
/* by a seg */
|
||||
/* */
|
||||
VD_Dbg_Warning("ArcArcPntCntr() - arc with small radius!");
|
||||
ReplaceArc(i);
|
||||
restart = true;
|
||||
return false;
|
||||
}
|
||||
else if (eq(GetArcRadius(j), ZERO_MAX)) {
|
||||
/* */
|
||||
/* this is an arc with a very small radius; we replace it */
|
||||
/* by a seg */
|
||||
/* */
|
||||
VD_Dbg_Warning("ArcArcPntCntr() - arc with small radius!");
|
||||
ReplaceArc(j);
|
||||
restart = true;
|
||||
return false;
|
||||
}
|
||||
else if (eq(PntPntDist(GetArcStartCoord(i), GetArcEndCoord(i)), ZERO_MAX)) {
|
||||
/* */
|
||||
/* this is an arc with a very short cord; we replace it by a seg */
|
||||
/* */
|
||||
VD_Dbg_Warning("ArcArcPntCntr() - arc with short cord!");
|
||||
ReplaceArc(i);
|
||||
restart = true;
|
||||
return false;
|
||||
}
|
||||
else if (eq(PntPntDist(GetArcStartCoord(j), GetArcEndCoord(j)), ZERO_MAX)) {
|
||||
/* */
|
||||
/* this is an arc with a very short cord; we replace it by a seg */
|
||||
/* */
|
||||
VD_Dbg_Warning("ArcArcPntCntr() - arc with short cord!");
|
||||
ReplaceArc(j);
|
||||
restart = true;
|
||||
return false;
|
||||
}
|
||||
else if (CheckIntersectionsLocally(i, ARC, j, ARC, k, PNT)) {
|
||||
restart = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef VRONI_DBG_WARN
|
||||
spi = GetArcStartCoord(i);
|
||||
spj = GetArcStartCoord(j);
|
||||
epj = GetArcEndCoord(j);
|
||||
epi = GetArcEndCoord(i);
|
||||
c1 = GetArcCenter(i);
|
||||
c2 = GetArcCenter(j);
|
||||
printf("\nCenter not computed for arc-arc-pnt: %d-%d-%d\n", i, j, k);
|
||||
printf("%20.16f %20.16f %20.16f %20.16f %20.16f %20.16f\n",
|
||||
spi.x, spi.y, epi.x, epi.y, c1.x, c1.y);
|
||||
printf("%20.16f %20.16f %20.16f %20.16f %20.16f %20.16f\n",
|
||||
spj.x, spj.y, epj.x, epj.y, c2.x, c2.y);
|
||||
c3 = GetPntCoords(k);
|
||||
printf("%20.16f %20.16f\n", c3.x, c3.y);
|
||||
#endif
|
||||
|
||||
*cntr = centers[best_sol];
|
||||
*r2 = radii[best_sol];
|
||||
restart = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+433
@@ -0,0 +1,433 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 2007-2023 S. Huber, 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: Stefan Huber, 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
|
||||
|
||||
/* */
|
||||
/* get my header files */
|
||||
/* */
|
||||
#include "vroni_object.h"
|
||||
#include "vronivector.h"
|
||||
#include "fpkernel.h"
|
||||
#include "defs.h"
|
||||
#include "numerics.h"
|
||||
#include "roots.h"
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* Calculate the Voronoi center of two arcs and segment */
|
||||
/* */
|
||||
vr_bool vroniObject::ArcArcSegCntr(int i, int j, int k, int e,
|
||||
coord* cntr, double *r2,
|
||||
vr_bool *problematic, int *site)
|
||||
{
|
||||
int m, n1;
|
||||
coord c1, c2;
|
||||
double rr1, rr2, t;
|
||||
double s1a, s1b, s1c;
|
||||
coord centers[VRONI_MAXSOL];
|
||||
double radii[VRONI_MAXSOL];
|
||||
int num_sol = 0, best_sol = NIL;
|
||||
double eps = ZERO;
|
||||
coord spi, spj, epj, epi;
|
||||
coord ep, sp, v, w;
|
||||
vr_bool counter_tangential, no_check, is_special;
|
||||
vr_bool spi_in_common, epi_in_common;
|
||||
int i_in, j_in, k_in;
|
||||
double d_c1c2;
|
||||
|
||||
i_in = i;
|
||||
j_in = j;
|
||||
k_in = k;
|
||||
|
||||
*problematic = false;
|
||||
|
||||
/* */
|
||||
/* Guarantee that permutations of i,j lead to same center */
|
||||
/* */
|
||||
SortTwoNumbers(i, j, m);
|
||||
|
||||
/* */
|
||||
/* Check whether the three cites are all in lists */
|
||||
/* */
|
||||
assert(InArcsList(i));
|
||||
assert(InArcsList(j));
|
||||
assert(InSegsList(k));
|
||||
|
||||
/* */
|
||||
/* check whether the two arcs are identical. */
|
||||
/* */
|
||||
if (i == j) {
|
||||
VD_Dbg_Warning("ArcArcSegCntr() - the same arc!");
|
||||
return false;
|
||||
}
|
||||
m = Get1stVtx(i, ARC);
|
||||
if (IsArcStartPnt(j, m) || IsArcEndPnt(j, m)) {
|
||||
m = Get2ndVtx(i, ARC);
|
||||
if (IsArcStartPnt(j, m) || IsArcEndPnt(j, m)) {
|
||||
if (le(PntPntDist(GetArcCenter(i),GetArcCenter(j)),
|
||||
GetIntersectionThreshold())) {
|
||||
SetInvalidSites(i, ARC, j, ARC, GetIntersectionThreshold());
|
||||
restart = false;
|
||||
return false; /* duplicate arcs ! */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
/* check whether the three sites share a common end point */
|
||||
/* */
|
||||
m = Get1stVtx(k, SEG);
|
||||
if (IsArcStartPnt(i, m) || IsArcEndPnt(i, m)) {
|
||||
if (IsArcStartPnt(j, m) || IsArcEndPnt(j, m)) {
|
||||
*cntr = GetPntCoords(m);
|
||||
*r2 = 0.0;
|
||||
*site = m;
|
||||
return true; /* common end point */
|
||||
}
|
||||
}
|
||||
m = Get2ndVtx(k, SEG);
|
||||
if (IsArcStartPnt(i, m) || IsArcEndPnt(i, m)) {
|
||||
if (IsArcStartPnt(j, m) || IsArcEndPnt(j, m)) {
|
||||
*cntr = GetPntCoords(m);
|
||||
*r2 = 0.0;
|
||||
*site = m;
|
||||
return true; /* common end point */
|
||||
}
|
||||
}
|
||||
|
||||
c1 = GetArcCenter(i);
|
||||
c2 = GetArcCenter(j);
|
||||
rr1 = GetArcRadius(i);
|
||||
rr2 = GetArcRadius(j);
|
||||
spi = GetArcStartCoord(i);
|
||||
spj = GetArcStartCoord(j);
|
||||
epj = GetArcEndCoord(j);
|
||||
epi = GetArcEndCoord(i);
|
||||
|
||||
GetSegEqnData(k, &s1a, &s1b, &s1c);
|
||||
s1c *= -1;
|
||||
|
||||
d_c1c2 = PntPntDist(c1,c2);
|
||||
|
||||
//printf(" arc%d-arc%d-seg%d with (%e,%e;%e), (%e,%e;%e), (%e,%e,%e) \n", i, j, k,
|
||||
// c1.x, c1.y,rr1, c2.x,c2.y,rr2, s1a,s1b,s1c);
|
||||
|
||||
|
||||
while (eps <= ZERO_MAX) {
|
||||
|
||||
is_special = false;
|
||||
no_check = false;
|
||||
num_sol = 0;
|
||||
|
||||
/* */
|
||||
/* check whether one endpoint of arc i is very close to one endpoint */
|
||||
/* of j */
|
||||
/* */
|
||||
if ((PntPntDist(spi,spj) <= eps) || (PntPntDist(spi,epj) <= eps)) {
|
||||
spi_in_common = true;
|
||||
epi_in_common = false;
|
||||
}
|
||||
else if ((PntPntDist(epi,spj) <= eps) || (PntPntDist(epi,epj) <= eps)) {
|
||||
spi_in_common = false;
|
||||
epi_in_common = true;
|
||||
}
|
||||
else {
|
||||
spi_in_common = false;
|
||||
epi_in_common = false;
|
||||
}
|
||||
|
||||
if (spi_in_common || epi_in_common) {
|
||||
counter_tangential = ((VecDet(c1,c2,spi) + VecDet(c1,c2,epi)) *
|
||||
(VecDet(c1,c2,spj) + VecDet(c1,c2,epj)) <= eps);
|
||||
|
||||
if (counter_tangential &&
|
||||
(Abs(d_c1c2 - Abs(rr1-rr2)) <= eps)) {
|
||||
/* */
|
||||
/* the arcs are (nearly) tangential and have a point in common */
|
||||
/* */
|
||||
//printf("\ttwo tangential arcs %d-%d and seg %d\n", i, j, k);
|
||||
n1 = GetStartNode(e);
|
||||
if (!IsNodeDeleted(n1)) n1 = GetEndNode(e);
|
||||
GetNodeData(n1, &v, &t);
|
||||
num_sol = 1;
|
||||
centers[0] = v;
|
||||
radii[0] = t;
|
||||
is_special = true;
|
||||
|
||||
if (!IsNodeDeleted(n1)) {
|
||||
/* */
|
||||
/* get start point and direction of the ray on which the */
|
||||
/* bisector lies */
|
||||
/* */
|
||||
if (spi_in_common) ep = spi;
|
||||
else ep = epi;
|
||||
v = VecSub(ep, c1);
|
||||
num_sol = IntersectRaySegment(ep, v, s1a, s1b, s1c, centers,
|
||||
radii, eps);
|
||||
}
|
||||
else {
|
||||
no_check = true;
|
||||
}
|
||||
}
|
||||
else if (counter_tangential && (Abs(d_c1c2 - rr1-rr2) <= eps)) {
|
||||
/* */
|
||||
/* the arcs are counter-tangential and lie on different sides */
|
||||
/* of the line through their centers */
|
||||
/* */
|
||||
if (spi_in_common) ep = spi;
|
||||
else ep = epi;
|
||||
v = VecSub(ep, c1);
|
||||
num_sol = IntersectRaySegment(ep, v, s1a, s1b, s1c, centers, radii,
|
||||
eps);
|
||||
is_special = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_special) {
|
||||
if ((d_c1c2 <= eps) && (Abs(rr1-rr2) <= eps)) {
|
||||
/* */
|
||||
/* the arcs lie (nearly) on the same circle but do not share an */
|
||||
/* end point: their common center is the only possible VD node */
|
||||
/* */
|
||||
centers[0] = MidPoint(c1, c2);
|
||||
radii[0] = (rr1 + rr2) / 2.0;
|
||||
num_sol = 1;
|
||||
is_special = true;
|
||||
}
|
||||
else if (Abs(Abs(c1.x*s1a+c1.y*s1b-s1c)-rr1) <= eps) {
|
||||
/* */
|
||||
/* the arc and the line are tangential. check whether they */
|
||||
/* share an end point */
|
||||
/* */
|
||||
counter_tangential = true;
|
||||
if (PntPntDist(spi,GetSegStartCoord(k)) <= eps) {
|
||||
ep = GetSegStartCoord(k);
|
||||
sp = GetSegEndCoord(k);
|
||||
v = VecSub(sp, ep);
|
||||
w = VecSub(epi, ep);
|
||||
counter_tangential = (VecDotProd(v, w) < 0.0) ? false : true;
|
||||
}
|
||||
else if (PntPntDist(epi,GetSegStartCoord(k)) <= eps) {
|
||||
ep = GetSegStartCoord(k);
|
||||
sp = GetSegEndCoord(k);
|
||||
v = VecSub(sp, ep);
|
||||
w = VecSub(spi, ep);
|
||||
counter_tangential = (VecDotProd(v, w) < 0.0) ? false : true;
|
||||
}
|
||||
else if (PntPntDist(spi,GetSegEndCoord(k)) <= eps) {
|
||||
ep = GetSegEndCoord(k);
|
||||
sp = GetSegStartCoord(k);
|
||||
v = VecSub(sp, ep);
|
||||
w = VecSub(epi, ep);
|
||||
counter_tangential = (VecDotProd(v, w) < 0.0) ? false : true;
|
||||
}
|
||||
else if (PntPntDist(epi,GetSegEndCoord(k)) <= eps) {
|
||||
ep = GetSegEndCoord(k);
|
||||
sp = GetSegStartCoord(k);
|
||||
v = VecSub(sp, ep);
|
||||
w = VecSub(spi, ep);
|
||||
counter_tangential = (VecDotProd(v, w) < 0.0) ? false : true;
|
||||
}
|
||||
|
||||
if (!counter_tangential) {
|
||||
//printf("arc%d and seg%d tangential, 2nd arc%d\n", i,k,j);
|
||||
v = MakeVec(-s1a, -s1b);
|
||||
num_sol = IntersectRayCircle(ep, v, c2, rr2, centers, radii,
|
||||
eps);
|
||||
is_special = true;
|
||||
}
|
||||
}
|
||||
else if (Abs(Abs(c2.x*s1a+c2.y*s1b-s1c) - rr2) <= eps) {
|
||||
/* */
|
||||
/* the arc and the line are tangential. check whether they */
|
||||
/* share an end point */
|
||||
/* */
|
||||
counter_tangential = true;
|
||||
if (PntPntDist(spj,GetSegStartCoord(k)) <= eps) {
|
||||
ep = GetSegStartCoord(k);
|
||||
sp = GetSegEndCoord(k);
|
||||
v = VecSub(sp, ep);
|
||||
w = VecSub(epj, ep);
|
||||
counter_tangential = (VecDotProd(v, w) < 0.0) ? false : true;
|
||||
}
|
||||
else if (PntPntDist(epj,GetSegStartCoord(k)) <= eps) {
|
||||
ep = GetSegStartCoord(k);
|
||||
sp = GetSegEndCoord(k);
|
||||
v = VecSub(sp, ep);
|
||||
w = VecSub(spj, ep);
|
||||
counter_tangential = (VecDotProd(v, w) < 0.0) ? false : true;
|
||||
}
|
||||
else if (PntPntDist(spj,GetSegEndCoord(k)) <= eps) {
|
||||
ep = GetSegEndCoord(k);
|
||||
sp = GetSegStartCoord(k);
|
||||
v = VecSub(sp, ep);
|
||||
w = VecSub(epj, ep);
|
||||
counter_tangential = (VecDotProd(v, w) < 0.0) ? false : true;
|
||||
}
|
||||
else if (PntPntDist(epj,GetSegEndCoord(k)) <= eps) {
|
||||
ep = GetSegEndCoord(k);
|
||||
sp = GetSegStartCoord(k);
|
||||
v = VecSub(sp, ep);
|
||||
w = VecSub(spj, ep);
|
||||
counter_tangential = (VecDotProd(v, w) < 0.0) ? false : true;
|
||||
}
|
||||
|
||||
if (!counter_tangential) {
|
||||
//printf("arc%d and seg%d tangential, 2nd arc%d\n", i,k,j);
|
||||
v = MakeVec(-s1a, -s1b);
|
||||
num_sol = IntersectRayCircle(ep, v, c1, rr1, centers, radii,
|
||||
eps);
|
||||
is_special = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_special) {
|
||||
/* */
|
||||
/* and finally the general case... */
|
||||
/* */
|
||||
//printf("ordinary\n");
|
||||
num_sol = CircCircSegCenters(c1, c2, rr1, rr2, s1a,s1b,s1c, centers,
|
||||
radii, eps);
|
||||
}
|
||||
|
||||
if ((num_sol > 0) && no_check)
|
||||
best_sol = 0;
|
||||
else
|
||||
/* */
|
||||
/* classify all solutions and pick the best solution */
|
||||
/* */
|
||||
best_sol = ClassifySolutions(i_in, j_in, k_in, e, ARC, ARC, SEG,
|
||||
false, true, true, centers, radii,
|
||||
&num_sol, eps, problematic);
|
||||
assert((0 <= best_sol) && (best_sol < num_sol));
|
||||
#ifdef TRACE
|
||||
if ((i_in == 4) && (j_in == 2) && (k_in == 2)) {
|
||||
printf("problematic = %d, eps = %20.16f\n", *problematic, eps);
|
||||
printf("num_sol = %d, best_sol = %d\n", num_sol, best_sol);
|
||||
printf("center = (%20.16f %20.16f)\n", centers[best_sol].x,
|
||||
centers[best_sol].y);
|
||||
printf("radius = %20.16f\n", radii[best_sol]);
|
||||
printf("zero_max = %20.16f\n", ZERO_MAX);
|
||||
printf("e = %d: i = %d, j = %d, k = %d\n", e, i_in, j_in, k_in);
|
||||
}
|
||||
#endif
|
||||
if (!*problematic) {
|
||||
*cntr = centers[best_sol];
|
||||
*r2 = radii[best_sol];
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
eps *= 10.0;
|
||||
}
|
||||
}
|
||||
|
||||
if (eq(GetArcRadius(i), ZERO_MAX)) {
|
||||
/* */
|
||||
/* this is an arc with a very small radius; we replace it by */
|
||||
/* a seg */
|
||||
/* */
|
||||
VD_Dbg_Warning("ArcArcSegCntr() - arc with small radius!");
|
||||
ReplaceArc(i);
|
||||
restart = true;
|
||||
return false;
|
||||
}
|
||||
else if (eq(GetArcRadius(j), ZERO_MAX)) {
|
||||
/* */
|
||||
/* this is an arc with a very small radius; we replace it by */
|
||||
/* a seg */
|
||||
/* */
|
||||
VD_Dbg_Warning("ArcArcSegCntr() - arc with small radius!");
|
||||
ReplaceArc(j);
|
||||
restart = true;
|
||||
return false;
|
||||
}
|
||||
else if (eq(PntPntDist(GetArcStartCoord(i), GetArcEndCoord(i)), ZERO_MAX)) {
|
||||
/* */
|
||||
/* this is an arc with a very short cord; we replace it by a seg */
|
||||
/* */
|
||||
VD_Dbg_Warning("ArcArcSegCntr() - arc with short cord!");
|
||||
ReplaceArc(i);
|
||||
restart = true;
|
||||
return false;
|
||||
}
|
||||
else if (eq(PntPntDist(GetArcStartCoord(j), GetArcEndCoord(j)), ZERO_MAX)) {
|
||||
/* */
|
||||
/* this is an arc with a very short cord; we replace it by a seg */
|
||||
/* */
|
||||
VD_Dbg_Warning("ArcArcSegCntr() - arc with short cord!");
|
||||
ReplaceArc(j);
|
||||
restart = true;
|
||||
return false;
|
||||
}
|
||||
else if (eq(GetSegLgth(k), ZERO_MAX)) {
|
||||
/* */
|
||||
/* this is a seg with a very small length; we replace it */
|
||||
/* */
|
||||
VD_Dbg_Warning("ArcArcSegCntr() - seg with small length!");
|
||||
ReplaceSeg(k);
|
||||
restart = true;
|
||||
return false;
|
||||
}
|
||||
else if (CheckIntersectionsLocally(i, ARC, j, ARC, k, SEG)) {
|
||||
restart = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef VRONI_DBG_WARN
|
||||
spi = GetArcStartCoord(i);
|
||||
spj = GetArcStartCoord(j);
|
||||
epi = GetArcEndCoord(i);
|
||||
epj = GetArcEndCoord(j);
|
||||
c1 = GetArcCenter(i);
|
||||
c2 = GetArcCenter(j);
|
||||
printf("\nCenter not computed for arc-arc-seg and edge e = %d:\n",
|
||||
e);
|
||||
printf("%20.16f %20.16f %20.16f %20.16f %20.16f %20.16f\n",
|
||||
spi.x, spi.y, epi.x, epi.y, c1.x, c1.y);
|
||||
printf("%20.16f %20.16f %20.16f %20.16f %20.16f %20.16f\n",
|
||||
spj.x, spj.y, epj.x, epj.y, c2.x, c2.y);
|
||||
ep = GetSegStartCoord(k);
|
||||
sp = GetSegEndCoord(k);
|
||||
printf("%20.16f %20.16f %20.16f %20.16f\n",
|
||||
sp.x, sp.y, ep.x, ep.y);
|
||||
#endif
|
||||
|
||||
*cntr = centers[best_sol];
|
||||
*r2 = radii[best_sol];
|
||||
restart = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+1055
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,46 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 2007-2023 M. Held, S. Huber */
|
||||
/* */
|
||||
/* 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: Stefan Huber, 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 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
#ifndef VRONI_ARC_COMMON_H
|
||||
#define VRONI_ARC_COMMON_H
|
||||
|
||||
|
||||
//Uncomment this line to print quality messages
|
||||
//#define ARC_QUALITY_MSG
|
||||
|
||||
|
||||
/** Test if pnt is in arc-cone. */
|
||||
inline vr_bool vroniObject::IsPntInArcCone(int arc, coord pnt)
|
||||
{
|
||||
return IsPntInArcConeEps(arc, pnt, ZERO);
|
||||
}
|
||||
|
||||
/** Test if pnt is in arc-cone. */
|
||||
inline vr_bool vroniObject::IsPntInArcConeStrict(int arc, coord pnt)
|
||||
{
|
||||
return IsPntInArcConeEps(arc, pnt, -ZERO);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
+307
@@ -0,0 +1,307 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 2007-2023 S. Huber, 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: Stefan Huber, 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 <stdlib.h>
|
||||
#include <stdio.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 "roots.h"
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* computes the center cntr and the radius r2 of the circle tangential */
|
||||
/* to the arct arcs[i] and passing through the points pnts[j],pnts[k]. */
|
||||
/* it returns false if the radius is too large to be computed numerically, */
|
||||
/* or if it is obvious that problems have occurred. if two centers exist */
|
||||
/* then we choose the center that lies on the Voronoi edge e. the vr_bool */
|
||||
/* flag problematic is set if a center was computed but its correctness is */
|
||||
/* doubtful. */
|
||||
/* */
|
||||
vr_bool vroniObject::ArcPntPntCntr(int i, int j, int k, int e,
|
||||
coord* cntr, double *r2,
|
||||
vr_bool *problematic)
|
||||
{
|
||||
int t;
|
||||
coord c1, c2, c3;
|
||||
double rr1, rr2, rr3, eps;
|
||||
#ifdef VRONI_DBG_WARN
|
||||
coord spi, epi;
|
||||
#endif
|
||||
coord v;
|
||||
coord centers[VRONI_MAXSOL];
|
||||
double radii[VRONI_MAXSOL];
|
||||
vr_bool j_on_i = false;
|
||||
int num_sol = 0, best_sol = NIL, cocirc = 0;
|
||||
double dist2, dist3;
|
||||
double sign = 1.0;
|
||||
|
||||
assert(InArcsList(i));
|
||||
assert(InPntsList(j));
|
||||
assert(InPntsList(k));
|
||||
*problematic = false;
|
||||
|
||||
/* */
|
||||
/* check whether the two points are identical. */
|
||||
/* */
|
||||
if (j == k) {
|
||||
VD_Dbg_Warning("ArcPntPntCntr() - two identical points!");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* */
|
||||
/* we sort the two point indices in order to guarantee that the center of */
|
||||
/* these three sites is always computed consistently. */
|
||||
/* */
|
||||
SortTwoNumbers(j, k, t);
|
||||
|
||||
c1 = GetArcCenter(i);
|
||||
rr1 = GetArcRadius(i);
|
||||
rr2 = 0.0;
|
||||
rr3 = 0.0;
|
||||
|
||||
/* */
|
||||
/* check whether one of the points is an endpoint of arcs[i]. */
|
||||
/* */
|
||||
if (IsArcStartPnt(i, k) || IsArcEndPnt(i, k)) Swap(j, k, t);
|
||||
c2 = GetPntCoords(j);
|
||||
c3 = GetPntCoords(k);
|
||||
if (IsArcStartPnt(i, j) || IsArcEndPnt(i, j)) {
|
||||
if (IsArcStartPnt(i, k) || IsArcEndPnt(i, k)) {
|
||||
/* */
|
||||
/* both points are endpoints of the arc */
|
||||
/* */
|
||||
*cntr = c1;
|
||||
*r2 = rr1;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
dist2 = 0.0;
|
||||
dist3 = PntPntDist(c1,c3) - rr1;
|
||||
j_on_i = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
dist2 = PntPntDist(c1,c2) - rr1;
|
||||
dist3 = PntPntDist(c1,c3) - rr1;
|
||||
}
|
||||
|
||||
eps = ZERO;
|
||||
|
||||
#ifdef TRACE
|
||||
if ((e == 107) && (i == 6)) { printf("arc%d-pnt%d-pnt%d: \n(%20.16f, %20.16f) %20.16f;\n%d:(%20.16f, %20.16f);\n%d:(%20.16f, %20.16f)\n", i, j, k, c1.x, c1.y, rr1, j, c2.x, c2.y, k, c3.x, c3.y);
|
||||
if (IsArcStartPnt(i, j)) printf("%d is start of arc %d\n", j, i);
|
||||
if (IsArcEndPnt(i, j)) printf("%d is end of arc %d\n", j, i);
|
||||
if (IsArcStartPnt(i, k)) printf("%d is start of arc %d\n", k, i);
|
||||
if (IsArcEndPnt(i, k)) printf("%d is end of arc %d\n", k, i);
|
||||
spi = GetArcStartCoord(i);
|
||||
epi = GetArcEndCoord(i);
|
||||
printf("%20.16f %20.16f %20.16f %20.16f %20.16f %20.16f\n",
|
||||
spi.x, spi.y, epi.x, epi.y, c1.x, c1.y);
|
||||
}
|
||||
#endif
|
||||
|
||||
while (eps <= ZERO_MAX) {
|
||||
|
||||
cocirc = 0;
|
||||
num_sol = 0;
|
||||
|
||||
if (eq(dist2, eps)) {
|
||||
if (!j_on_i && DoArcPntIntersect(i, c2, eps)) {
|
||||
/* */
|
||||
/* c2 is inside of CI of i and on i */
|
||||
/* */
|
||||
VD_Dbg_Warning("ArcPntPntCntr() - point lies in interior of arc!");
|
||||
SetInvalidSites(i, ARC, j, PNT, eps);
|
||||
restart = false;
|
||||
return false;
|
||||
}
|
||||
cocirc = 1;
|
||||
}
|
||||
|
||||
if (eq(dist3, eps)) {
|
||||
if (DoArcPntIntersect(i, c3, eps)) {
|
||||
/* */
|
||||
/* c3 is inside of CI of i and on i */
|
||||
/* */
|
||||
VD_Dbg_Warning("ArcPntPntCntr() - point lies in interior of arc!");
|
||||
SetInvalidSites(i, ARC, k, PNT, eps);
|
||||
restart = false;
|
||||
return false;
|
||||
}
|
||||
++cocirc;
|
||||
}
|
||||
|
||||
if (cocirc == 2) {
|
||||
/* */
|
||||
/* the two points lie on the same circle as i */
|
||||
/* */
|
||||
centers[0] = c1;
|
||||
radii[0] = rr1;
|
||||
num_sol = 1;
|
||||
}
|
||||
else if (j_on_i) {
|
||||
/* */
|
||||
/* point j is on arc */
|
||||
/* */
|
||||
v = VecSub(c2, c1);
|
||||
num_sol = IntersectRayPoint(c2, v, c3, centers, radii, eps);
|
||||
}
|
||||
else {
|
||||
/* */
|
||||
/* standard case: find solution that is equidistant to three */
|
||||
/* (degenerate) circles. */
|
||||
/* */
|
||||
if (dist2 <= -eps) {
|
||||
sign = -1.0;
|
||||
#ifdef VRONI_WARN
|
||||
if (dist3 > eps) {
|
||||
VD_Warning("ArcPntPntCntr() - sign mismatch!");
|
||||
coord spi, epi;
|
||||
spi = GetArcStartCoord(i);
|
||||
epi = GetArcEndCoord(i);
|
||||
c1 = GetArcCenter(i);
|
||||
printf("%20.16f %20.16f %20.16f %20.16f %20.16f %20.16f\n",
|
||||
spi.x, spi.y, epi.x, epi.y, c1.x, c1.y);
|
||||
c2 = GetPntCoords(j);
|
||||
printf("%20.16f %20.16f\n", c2.x, c2.y);
|
||||
c3 = GetPntCoords(k);
|
||||
printf("%20.16f %20.16f\n", c3.x, c3.y);
|
||||
printf("dist2 = %20.16f\n", dist2);
|
||||
printf("dist3 = %20.16f\n", dist3);
|
||||
printf("eps = %20.16f\n", eps);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if (dist2 >= eps) {
|
||||
sign = 1.0;
|
||||
#ifdef VRONI_WARN
|
||||
if (dist3 < -eps) {
|
||||
VD_Warning("ArcPntPntCntr() - sign mismatch!");
|
||||
coord spi, epi;
|
||||
spi = GetArcStartCoord(i);
|
||||
epi = GetArcEndCoord(i);
|
||||
c1 = GetArcCenter(i);
|
||||
printf("%20.16f %20.16f %20.16f %20.16f %20.16f %20.16f\n",
|
||||
spi.x, spi.y, epi.x, epi.y, c1.x, c1.y);
|
||||
c2 = GetPntCoords(j);
|
||||
printf("%20.16f %20.16f\n", c2.x, c2.y);
|
||||
c3 = GetPntCoords(k);
|
||||
printf("%20.16f %20.16f\n", c3.x, c3.y);
|
||||
printf("dist2 = %20.16f\n", dist2);
|
||||
printf("dist3 = %20.16f\n", dist3);
|
||||
printf("eps = %20.16f\n", eps);
|
||||
printf("checking for containment\n");
|
||||
printf("c3 on circle: %d\n", DoArcPntIntersect(i, c3, eps));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
sign = Sign(dist3);
|
||||
}
|
||||
num_sol = CircPntPntCenters(c1, c2, c3, rr1, sign, centers, radii);
|
||||
if (num_sol == 0)
|
||||
num_sol = CircCircCircCenters(c1, c2, c3, rr1, rr2, rr3, centers,
|
||||
radii, eps);
|
||||
}
|
||||
|
||||
/* */
|
||||
/* classify all solutions and pick the best solution */
|
||||
/* */
|
||||
best_sol = ClassifySolutions(i, j, k, e, ARC, PNT, PNT,
|
||||
false, true, true, centers, radii,
|
||||
&num_sol, eps, problematic);
|
||||
assert((0 <= best_sol) && (best_sol < num_sol));
|
||||
if (!*problematic) {
|
||||
*cntr = centers[best_sol];
|
||||
*r2 = radii[best_sol];
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
eps *= 10.0;
|
||||
}
|
||||
}
|
||||
|
||||
if (eq(rr1, ZERO_MAX)) {
|
||||
/* */
|
||||
/* this is an arc with a very small radius; we replace it by a seg */
|
||||
/* */
|
||||
VD_Dbg_Warning("ArcPntPntCntr() - arc with small radius!");
|
||||
ReplaceArc(i);
|
||||
restart = true;
|
||||
return false;
|
||||
}
|
||||
else if (eq(PntPntDist(GetArcStartCoord(i), GetArcEndCoord(i)), ZERO_MAX)) {
|
||||
/* */
|
||||
/* this is an arc with a very short cord; we replace it by a seg */
|
||||
/* */
|
||||
VD_Dbg_Warning("ArcPntPntCntr() - arc with short cord!");
|
||||
ReplaceArc(i);
|
||||
restart = true;
|
||||
return false;
|
||||
}
|
||||
else if (eq(PntPntDist(c2,c3), ZERO_MAX)) {
|
||||
/* */
|
||||
/* both points are very close to each other. */
|
||||
/* */
|
||||
VD_Dbg_Warning("ArcPntPntCntr() - points are too close!");
|
||||
SetInvalidSites(j, PNT, k, PNT, ZERO_MAX);
|
||||
restart = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef VRONI_DBG_WARN
|
||||
spi = GetArcStartCoord(i);
|
||||
epi = GetArcEndCoord(i);
|
||||
c1 = GetArcCenter(i);
|
||||
printf("\nCenter not computed for arc(%d)-pnt(%d)-pnt(%d):\n",
|
||||
i, j, k);
|
||||
printf("%20.16f %20.16f %20.16f %20.16f %20.16f %20.16f\n",
|
||||
spi.x, spi.y, epi.x, epi.y, c1.x, c1.y);
|
||||
c2 = GetPntCoords(j);
|
||||
printf("%20.16f %20.16f\n", c2.x, c2.y);
|
||||
c3 = GetPntCoords(k);
|
||||
printf("%20.16f %20.16f\n", c3.x, c3.y);
|
||||
#endif
|
||||
|
||||
*cntr = centers[best_sol];
|
||||
*r2 = radii[best_sol];
|
||||
restart = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+329
@@ -0,0 +1,329 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 2007-2023 S. Huber, 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: Stefan Huber, 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
|
||||
/* */
|
||||
/* get my header files */
|
||||
/* */
|
||||
#include "vroni_object.h"
|
||||
#include "vronivector.h"
|
||||
#include "fpkernel.h"
|
||||
#include "numerics.h"
|
||||
#include "defs.h"
|
||||
#include "roots.h"
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* Calculate the Voronoi center of arc, seg and pnt */
|
||||
/* */
|
||||
vr_bool vroniObject::ArcSegPntCntr(int i, int j, int k, int e,
|
||||
coord* cntr, double *r2,
|
||||
vr_bool *problematic, int* site)
|
||||
{
|
||||
coord c1, c2;
|
||||
double rr1, rr2;
|
||||
double s1a, s1b, s1c;
|
||||
coord centers[VRONI_MAXSOL];
|
||||
double radii[VRONI_MAXSOL];
|
||||
int num_sol = 0, best_sol = NIL, old_num_sol = 0;;
|
||||
double d_c1c2;
|
||||
|
||||
double eps = ZERO;
|
||||
vr_bool counter_tangential, is_endpoint, is_special, is_tangent;
|
||||
vr_bool is_pnt_on_line, is_pnt_on_circle;
|
||||
coord spi, epi;
|
||||
coord ep, sp, u, v, w;
|
||||
#ifdef VRONI_DBG_WARN
|
||||
coord spj, epj;
|
||||
#endif
|
||||
|
||||
/* */
|
||||
/* Check whether the three sites are all in lists */
|
||||
/* */
|
||||
assert(InArcsList(i));
|
||||
assert(InSegsList(j));
|
||||
assert(InPntsList(k));
|
||||
|
||||
*problematic = false;
|
||||
|
||||
if ((IsArcStartPnt(i,k) || IsArcEndPnt(i,k)) &&
|
||||
(IsSegStartPnt(j,k) || IsSegEndPnt(j,k))) {
|
||||
/* */
|
||||
/* pnt k is a common end-point of i and j. */
|
||||
/* */
|
||||
//printf("\n\nPoint splits arc-seg\n\n");
|
||||
|
||||
*cntr = GetPntCoords(k);
|
||||
*r2 = 0.0;
|
||||
*site = k;
|
||||
return true;
|
||||
}
|
||||
|
||||
c1 = GetArcCenter(i);
|
||||
c2 = GetPntCoords(k);
|
||||
|
||||
rr1 = GetArcRadius(i);
|
||||
rr2 = 0;
|
||||
|
||||
GetSegEqnData(j, &s1a, &s1b, &s1c);
|
||||
s1c*=-1;
|
||||
|
||||
spi = GetArcStartCoord(i);
|
||||
epi = GetArcEndCoord(i);
|
||||
|
||||
#ifdef TRACE
|
||||
printf("arc%d-seg%d-pnt%d:\n", i, j, k);
|
||||
printf("arc: (%20.16f %20.16f) %20.16f\n", c1.x, c1.y, rr1);
|
||||
printf("pnt: (%20.16f %20.16f %20.16f)\n", s1a, s1b, s1c);
|
||||
#endif
|
||||
|
||||
d_c1c2 = PntPntDist(c1, c2);
|
||||
|
||||
if (IsArcStartPnt(i,k) || IsArcEndPnt(i,k)) {
|
||||
if ( Abs(PntLineDist(s1a, s1b, -s1c, c1)) < rr1 )
|
||||
v = VecSub(c1, c2);
|
||||
else
|
||||
v = VecSub(c2, c1);
|
||||
is_endpoint = true;
|
||||
old_num_sol = IntersectRaySegment(c2, v, s1a, s1b, s1c, centers, radii,
|
||||
ZERO);
|
||||
}
|
||||
else if (IsSegStartPnt(j,k) || IsSegEndPnt(j,k)) {
|
||||
u = VecSub(c1,c2);
|
||||
v = MakeVec(s1a, s1b);
|
||||
|
||||
/* */
|
||||
/* if arc is between c1 and c2 and v points away from c1, or */
|
||||
/* if arc is not between c1 and c2 and v points to c1, */
|
||||
/* then invert v */
|
||||
/* */
|
||||
if ((d_c1c2 > rr1) && (v.x*u.x + v.y*u.y < 0)) v = VecMult(-1.0, v);
|
||||
if ((d_c1c2 < rr1) && (v.x*u.x + v.y*u.y > 0)) v = VecMult(-1.0, v);
|
||||
is_endpoint = true;
|
||||
old_num_sol = IntersectRayCircle(c2, v, c1, rr1, centers, radii, ZERO);
|
||||
}
|
||||
else {
|
||||
is_endpoint = false;
|
||||
}
|
||||
|
||||
while (eps <= ZERO_MAX) {
|
||||
|
||||
is_special = false;
|
||||
num_sol = old_num_sol;
|
||||
|
||||
if (!is_endpoint) {
|
||||
if (DoArcPntIntersect(i, c2, eps)) {
|
||||
VD_Dbg_Warning("ArcSegPntCntr() - point lies in interior of arc!");
|
||||
SetInvalidSites(i, ARC, k, PNT, eps);
|
||||
restart = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
is_pnt_on_line = (Abs(PntLineDist(s1a, s1b, -s1c, c2)) <= eps);
|
||||
is_pnt_on_circle = (Abs(d_c1c2-rr1) <= eps);
|
||||
is_tangent = (Abs(Abs(c1.x*s1a+c1.y*s1b-s1c)-rr1) <= eps);
|
||||
|
||||
if (is_pnt_on_line && is_pnt_on_circle && is_tangent) {
|
||||
/* */
|
||||
/* circle and line are tangent in the pnt */
|
||||
/* */
|
||||
if (IsPntInArcCone(i, c2)) {
|
||||
centers[0]= c2;
|
||||
radii[0] = 0.0;
|
||||
}
|
||||
else {
|
||||
centers[0]= c1;
|
||||
radii[0] = rr1;
|
||||
}
|
||||
num_sol = 1;
|
||||
is_special = true;
|
||||
}
|
||||
else if (is_pnt_on_circle && IsPntInArcCone(i,c2) && (rr1 > eps)) {
|
||||
/* */
|
||||
/* pnt is on the circle */
|
||||
/* */
|
||||
if (Abs(PntLineDist(s1a, s1b, -s1c, c1)) < rr1)
|
||||
v = VecSub(c1, c2);
|
||||
else
|
||||
v = VecSub(c2, c1);
|
||||
|
||||
num_sol = IntersectRaySegment(c2, v, s1a, s1b, s1c, centers,
|
||||
radii, eps);
|
||||
is_special = true;
|
||||
}
|
||||
else if (is_pnt_on_line) {
|
||||
/* */
|
||||
/* pnt is on the line */
|
||||
/* */
|
||||
//printf("asp: special case: point is on line\n");
|
||||
u = VecSub(c1,c2);
|
||||
v = MakeVec(s1a, s1b);
|
||||
|
||||
/* */
|
||||
/* if arc is between c1 and c2 and v points away from c1, */
|
||||
/* or */
|
||||
/* if arc is not between c1 and c2 and v points to c1, */
|
||||
/* then invert v */
|
||||
/* */
|
||||
if (((d_c1c2 > rr1) && (v.x*u.x + v.y*u.y) < 0))
|
||||
v = VecMult(-1.0, v);
|
||||
if (((d_c1c2 < rr1) && (v.x*u.x + v.y*u.y) > 0))
|
||||
v = VecMult(-1.0, v);
|
||||
num_sol = IntersectRayCircle(c2, v, c1, rr1, centers, radii, eps);
|
||||
is_special = true;
|
||||
}
|
||||
else if (is_tangent) {
|
||||
/* */
|
||||
/* line is tangent to circle */
|
||||
/* */
|
||||
counter_tangential = true;
|
||||
if (PntPntDist(GetArcStartCoord(i),GetSegStartCoord(j)) <= eps) {
|
||||
ep = GetSegStartCoord(j);
|
||||
sp = GetSegEndCoord(j);
|
||||
v = VecSub(sp, ep);
|
||||
w = VecSub(epi, ep);
|
||||
counter_tangential = (VecDotProd(v, w) < 0.0) ? false : true;
|
||||
}
|
||||
else if (PntPntDist(GetArcEndCoord(i),GetSegStartCoord(j)) <= eps) {
|
||||
ep = GetSegStartCoord(j);
|
||||
sp = GetSegEndCoord(j);
|
||||
v = VecSub(sp, ep);
|
||||
w = VecSub(spi, ep);
|
||||
counter_tangential = (VecDotProd(v, w) < 0.0) ? false : true;
|
||||
}
|
||||
else if (PntPntDist(GetArcStartCoord(i),GetSegEndCoord(j)) <= eps) {
|
||||
ep = GetSegEndCoord(j);
|
||||
sp = GetSegStartCoord(j);
|
||||
v = VecSub(sp, ep);
|
||||
w = VecSub(epi, ep);
|
||||
counter_tangential = (VecDotProd(v, w) < 0.0) ? false : true;
|
||||
}
|
||||
else if (PntPntDist(GetArcEndCoord(i),GetSegEndCoord(j)) <= eps) {
|
||||
ep = GetSegEndCoord(j);
|
||||
sp = GetSegStartCoord(j);
|
||||
v = VecSub(sp, ep);
|
||||
w = VecSub(spi, ep);
|
||||
counter_tangential = (VecDotProd(v, w) < 0.0) ? false : true;
|
||||
}
|
||||
|
||||
if (!counter_tangential) {
|
||||
if ((s1a*c2.x+s1b*c2.y-s1c) > 0.0) v = MakeVec(s1a, s1b);
|
||||
else v = MakeVec(-s1a, -s1b);
|
||||
num_sol = IntersectRayCircle(ep, v, c2, 0.0, centers, radii,
|
||||
eps);
|
||||
is_special = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_special) {
|
||||
/* */
|
||||
/* and finally the general case... */
|
||||
/* */
|
||||
//printf("ordinary\n");
|
||||
num_sol = CircCircSegCenters(c1, c2, rr1, rr2, s1a, s1b, s1c,
|
||||
centers, radii, eps);
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
/* classify all solutions and pick the best solution */
|
||||
/* */
|
||||
best_sol = ClassifySolutions(i, j, k, e, ARC, SEG, PNT,
|
||||
false, true, true, centers, radii,
|
||||
&num_sol, eps, problematic);
|
||||
assert((0 <= best_sol) && (best_sol < num_sol));
|
||||
if (!*problematic) {
|
||||
*cntr = centers[best_sol];
|
||||
*r2 = radii[best_sol];
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
eps *= 10.0;
|
||||
}
|
||||
}
|
||||
|
||||
if (eq(rr1, ZERO_MAX)) {
|
||||
/* */
|
||||
/* this is an arc with a very small radius; we replace it by */
|
||||
/* by a seg */
|
||||
/* */
|
||||
VD_Dbg_Warning("ArcSegPntCntr() - arc with small radius!");
|
||||
ReplaceArc(i);
|
||||
restart = true;
|
||||
return false;
|
||||
}
|
||||
else if (eq(PntPntDist(GetArcStartCoord(i), GetArcEndCoord(i)), ZERO_MAX)) {
|
||||
/* */
|
||||
/* this is an arc with a very short cord; we replace it by a seg */
|
||||
/* */
|
||||
VD_Dbg_Warning("ArcSegPntCntr() - arc with short cord!");
|
||||
ReplaceArc(i);
|
||||
restart = true;
|
||||
return false;
|
||||
}
|
||||
else if (eq(GetSegLgth(j), ZERO_MAX)) {
|
||||
/* */
|
||||
/* this is a seg with a very small length; we replace it */
|
||||
/* */
|
||||
VD_Dbg_Warning("ArcSegPntCntr() - seg with small length!");
|
||||
ReplaceSeg(j);
|
||||
restart = true;
|
||||
return false;
|
||||
}
|
||||
else if (CheckIntersectionsLocally(i, ARC, j, SEG, k, PNT)) {
|
||||
restart = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef VRONI_DBG_WARN
|
||||
spi = GetArcStartCoord(i);
|
||||
epi = GetArcEndCoord(i);
|
||||
c1 = GetArcCenter(i);
|
||||
printf("\nCenter not computed for arc-seg-pnt:\n");
|
||||
printf("%20.16f %20.16f %20.16f %20.16f %20.16f %20.16f\n",
|
||||
spi.x, spi.y, epi.x, epi.y, c1.x, c1.y);
|
||||
epj = GetSegStartCoord(j);
|
||||
spj = GetSegEndCoord(j);
|
||||
printf("%20.16f %20.16f %20.16f %20.16f\n",
|
||||
spj.x, spj.y, epj.x, epj.y);
|
||||
c2 = GetPntCoords(k);
|
||||
printf("%20.16f %20.16f\n", c2.x, c2.y);
|
||||
#endif
|
||||
|
||||
*cntr = centers[best_sol];
|
||||
*r2 = radii[best_sol];
|
||||
restart = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+331
@@ -0,0 +1,331 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 2007-2023 S. Huber, 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: Stefan Huber, 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 <stdlib.h>
|
||||
#include <stdio.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 "roots.h"
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* Calculate the Voronoi center of arc and two segs */
|
||||
/* */
|
||||
vr_bool vroniObject::ArcSegSegCntr(int i, int j, int k, int e, coord* cntr,
|
||||
double *r2, vr_bool *problematic, int *site)
|
||||
{
|
||||
int m;
|
||||
coord c1;
|
||||
double rr1;
|
||||
double s1a, s1b, s1c;
|
||||
double s2a, s2b, s2c;
|
||||
coord centers[VRONI_MAXSOL];
|
||||
double radii[VRONI_MAXSOL];
|
||||
int num_sol = 0, best_sol = NIL;
|
||||
|
||||
double eps = ZERO;
|
||||
coord v, w, sp, ep, spi, epi, spj, epj;
|
||||
vr_bool counter_tangential;
|
||||
#ifdef VRONI_DBG_WARN
|
||||
coord spk, epk;
|
||||
#endif
|
||||
|
||||
/* */
|
||||
/* Check whether the three cites are all in lists */
|
||||
/* */
|
||||
assert(InArcsList(i));
|
||||
assert(InSegsList(j));
|
||||
assert(InSegsList(k));
|
||||
|
||||
*problematic = false;
|
||||
|
||||
/* */
|
||||
/* we sort the two seg indices in order to guarantee that the center of */
|
||||
/* these three sites is always computed consistently. */
|
||||
/* */
|
||||
SortTwoNumbers(j, k, m);
|
||||
|
||||
/* */
|
||||
/* check whether the three sites share a common end point */
|
||||
/* */
|
||||
m = Get1stVtx(k, SEG);
|
||||
if (IsArcStartPnt(i, m) || IsArcEndPnt(i, m)) {
|
||||
if (IsSegStartPnt(j, m) || IsSegEndPnt(j, m)) {
|
||||
*cntr = GetPntCoords(m);
|
||||
*r2 = 0.0;
|
||||
*site = m;
|
||||
return true; /* common end point */
|
||||
}
|
||||
}
|
||||
m = Get2ndVtx(k, SEG);
|
||||
if (IsArcStartPnt(i, m) || IsArcEndPnt(i, m)) {
|
||||
if (IsSegStartPnt(j, m) || IsSegEndPnt(j, m)) {
|
||||
*cntr = GetPntCoords(m);
|
||||
*r2 = 0.0;
|
||||
*site = m;
|
||||
return true; /* common end point */
|
||||
}
|
||||
}
|
||||
|
||||
c1 = GetArcCenter(i);
|
||||
rr1 = GetArcRadius(i);
|
||||
|
||||
GetSegEqnData(j, &s1a, &s1b, &s1c);
|
||||
s1c*= -1.0;
|
||||
|
||||
GetSegEqnData(k, &s2a, &s2b, &s2c);
|
||||
s2c*= -1.0;
|
||||
|
||||
if (((s1a < -ZERO) && (s2a > ZERO)) ||
|
||||
((s1a > ZERO) && (s2a < ZERO))) {
|
||||
s2a *= -1.0;
|
||||
s2b *= -1.0;
|
||||
s2c *= -1.0;
|
||||
}
|
||||
else if (((s1b < -ZERO) && (s2b > ZERO)) ||
|
||||
((s1b > ZERO) && (s2b < ZERO))) {
|
||||
s2a *= -1.0;
|
||||
s2b *= -1.0;
|
||||
s2c *= -1.0;
|
||||
}
|
||||
|
||||
while (eps <= ZERO_MAX) {
|
||||
num_sol = 0;
|
||||
|
||||
//If second segment is tangential to arc --> let it be segment j
|
||||
if ((Abs(Abs(s2a*c1.x+s2b*c1.y-s2c)-rr1) <= eps) &&
|
||||
((PntPntDist(GetArcStartCoord(i), GetSegStartCoord(k)) <= eps) ||
|
||||
(PntPntDist(GetArcStartCoord(i), GetSegEndCoord(k)) <= eps) ||
|
||||
(PntPntDist(GetArcEndCoord(i), GetSegStartCoord(k)) <= eps) ||
|
||||
(PntPntDist(GetArcEndCoord(i), GetSegEndCoord(k)) <= eps)) &&
|
||||
!(IsPntInArcCone(i,GetSegStartCoord(k)) &&
|
||||
IsPntInArcCone(i,GetSegEndCoord(k)))) {
|
||||
int tmpi;
|
||||
double tmpd;
|
||||
|
||||
Swap(j, k, tmpi);
|
||||
Swap(s1a, s2a, tmpd);
|
||||
Swap(s1b, s2b, tmpd);
|
||||
Swap(s1c, s2c, tmpd);
|
||||
}
|
||||
|
||||
spi = GetArcStartCoord(i);
|
||||
epi = GetArcEndCoord(i);
|
||||
spj = GetSegStartCoord(j);
|
||||
epj = GetSegEndCoord(j);
|
||||
|
||||
#ifdef TRACE
|
||||
if ((i == 1305) && (((j == 1605) && (k == 1604)) ||
|
||||
((j == 1604) && (k == 1605)))) {
|
||||
printf("arc%d-seg%d-seg%d: eps = %20.16f\n", i, j, k, eps);
|
||||
printf("start arc: (%20.16f %20.16f)\n", spi.x, spi.y);
|
||||
printf("end arc: (%20.16f %20.16f)\n", epi.x, epi.y);
|
||||
printf("center arc: (%20.16f %20.16f)\n", c1.x, c1.y);
|
||||
printf("start seg 1: (%20.16f %20.16f)\n", spj.x, spj.y);
|
||||
printf("end seg 1: (%20.16f %20.16f)\n", epj.x, epj.y);
|
||||
printf("start seg 2: (%20.16f %20.16f)\n", GetSegStartCoord(k).x,
|
||||
GetSegStartCoord(k).y);
|
||||
printf("end seg 2: (%20.16f %20.16f)\n", GetSegEndCoord(k).x,
|
||||
GetSegEndCoord(k).y);
|
||||
}
|
||||
#endif
|
||||
|
||||
//Segment tangential to arc!
|
||||
//Do not change the eps to eps_MAX here! See arcs_347
|
||||
if (Abs(Abs(s1a*c1.x+s1b*c1.y-s1c)-rr1) <= eps) {
|
||||
counter_tangential = true;
|
||||
if (PntPntDist(spi,spj) <= eps) {
|
||||
ep = spj;
|
||||
sp = epj;
|
||||
v = VecSub(sp, ep);
|
||||
w = VecSub(epi, ep);
|
||||
counter_tangential = (VecDotProd(v, w) < 0.0) ? false : true;
|
||||
}
|
||||
else if (PntPntDist(epi,spj) <= eps) {
|
||||
ep = spj;
|
||||
sp = epj;
|
||||
v = VecSub(sp, ep);
|
||||
w = VecSub(spi, ep);
|
||||
counter_tangential = (VecDotProd(v, w) < 0.0) ? false : true;
|
||||
}
|
||||
else if (PntPntDist(spi,epj) <= eps) {
|
||||
ep = epj;
|
||||
sp = spj;
|
||||
v = VecSub(sp, ep);
|
||||
w = VecSub(epi, ep);
|
||||
counter_tangential = (VecDotProd(v, w) < 0.0) ? false : true;
|
||||
}
|
||||
else if (PntPntDist(epi,epj) <= eps) {
|
||||
ep = epj;
|
||||
sp = spj;
|
||||
v = VecSub(sp, ep);
|
||||
w = VecSub(spi, ep);
|
||||
counter_tangential = (VecDotProd(v, w) < 0.0) ? false : true;
|
||||
}
|
||||
|
||||
if (!counter_tangential) {
|
||||
//Intersect the ray and get all centers
|
||||
v.x = s1a;
|
||||
v.y = s1b;
|
||||
num_sol = IntersectRaySegment(ep, v, s2a, s2b, s2c, centers, radii,
|
||||
eps);
|
||||
}
|
||||
else {
|
||||
num_sol = CircSegSegCenters(c1, rr1, s1a,s1b,s1c, s2a,s2b,s2c,
|
||||
centers, radii, eps);
|
||||
}
|
||||
}
|
||||
//parallel segments with common endpoint
|
||||
else if ((Abs(s1a-s2a) <= eps) && (Abs(s1b-s2b) <= eps) &&
|
||||
(Abs(s1c-s2c) <= eps) &&
|
||||
((PntPntDist(spj,GetSegStartCoord(k)) <= eps) ||
|
||||
(PntPntDist(spj,GetSegEndCoord(k)) <= eps) ||
|
||||
(PntPntDist(epj,GetSegStartCoord(k)) <= eps) ||
|
||||
(PntPntDist(epj,GetSegEndCoord(k)) <= eps))) {
|
||||
//Get the common endpoint
|
||||
if( PntPntDist(spj, GetSegStartCoord(k))<= eps ||
|
||||
PntPntDist(spj, GetSegEndCoord(k))<= eps )
|
||||
ep = spj;
|
||||
else
|
||||
ep = epj;
|
||||
v = MakeVec(s1a, s1b);
|
||||
|
||||
num_sol = IntersectRayCircle(ep, v, c1, rr1, centers, radii, eps);
|
||||
}
|
||||
else {
|
||||
//Calculate all equidistant points
|
||||
num_sol = CircSegSegCenters(c1, rr1, s1a,s1b,s1c, s2a,s2b,s2c,
|
||||
centers, radii, eps);
|
||||
}
|
||||
|
||||
/* */
|
||||
/* classify all solutions and pick the best solution */
|
||||
/* */
|
||||
best_sol = ClassifySolutions(i, j, k, e, ARC, SEG, SEG,
|
||||
false, true, true, centers, radii,
|
||||
&num_sol, eps, problematic);
|
||||
assert((0 <= best_sol) && (best_sol < num_sol));
|
||||
#ifdef TRACE
|
||||
if ((i == 40) && (((j == 2) && (k == 42)) ||
|
||||
((j == 42) && (k == 2)))) {
|
||||
printf("arc %d, seg %d, seg %d\n", i, j, k);
|
||||
for (m = 0; m < num_sol; ++m) {
|
||||
printf("centers[%d]: (%20.16f %20.16f)\n", m,
|
||||
centers[m].x, centers[m].y);
|
||||
printf("radii[%d]: %20.16f\n", m, radii[m]);
|
||||
}
|
||||
printf("problematic = %d, eps = %20.16f\n", *problematic, eps);
|
||||
}
|
||||
#endif
|
||||
if (!*problematic) {
|
||||
*cntr = centers[best_sol];
|
||||
*r2 = radii[best_sol];
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
eps *= 10.0;
|
||||
}
|
||||
}
|
||||
|
||||
if (eq(rr1, ZERO_MAX)) {
|
||||
/* */
|
||||
/* this is an arc with a very small radius; we replace it */
|
||||
/* by a seg */
|
||||
/* */
|
||||
VD_Dbg_Warning("ArcSegSegCntr() - arc with small radius!");
|
||||
ReplaceArc(i);
|
||||
restart = true;
|
||||
return false;
|
||||
}
|
||||
else if (eq(PntPntDist(GetArcStartCoord(i), GetArcEndCoord(i)), ZERO_MAX)) {
|
||||
/* */
|
||||
/* this is an arc with a very short cord; we replace it by a seg */
|
||||
/* */
|
||||
VD_Dbg_Warning("ArcArcArcCntr() - arc with short cord!");
|
||||
ReplaceArc(i);
|
||||
restart = true;
|
||||
return false;
|
||||
}
|
||||
else if (eq(GetSegLgth(j), ZERO_MAX)) {
|
||||
/* */
|
||||
/* this is a seg with a very small length; we replace it */
|
||||
/* */
|
||||
VD_Dbg_Warning("ArcSegSegCntr() - seg with small length!");
|
||||
ReplaceSeg(j);
|
||||
restart = true;
|
||||
return false;
|
||||
}
|
||||
else if (eq(GetSegLgth(k), ZERO_MAX)) {
|
||||
/* */
|
||||
/* this is a seg with a very small length; we replace it */
|
||||
/* */
|
||||
VD_Dbg_Warning("ArcSegSegCntr() - seg with small length!");
|
||||
ReplaceSeg(k);
|
||||
restart = true;
|
||||
return false;
|
||||
}
|
||||
else if (CheckIntersectionsLocally(i, ARC, j, SEG, k, SEG)) {
|
||||
restart = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef VRONI_DBG_WARN
|
||||
spi = GetArcStartCoord(i);
|
||||
epi = GetArcEndCoord(i);
|
||||
c1 = GetArcCenter(i);
|
||||
printf("\nCenter not computed for arc-seg-seg: %d-%d-%d\n",
|
||||
i, j, k);
|
||||
printf("%20.16f %20.16f %20.16f %20.16f %20.16f %20.16f\n",
|
||||
spi.x, spi.y, epi.x, epi.y, c1.x, c1.y);
|
||||
epj = GetSegStartCoord(j);
|
||||
spj = GetSegEndCoord(j);
|
||||
epk = GetSegStartCoord(k);
|
||||
spk = GetSegEndCoord(k);
|
||||
printf("%20.16f %20.16f %20.16f %20.16f\n",
|
||||
spj.x, spj.y, epj.x, epj.y);
|
||||
printf("%20.16f %20.16f %20.16f %20.16f\n",
|
||||
spk.x, spk.y, epk.x, epk.y);
|
||||
#endif
|
||||
|
||||
*cntr = centers[best_sol];
|
||||
*r2 = radii[best_sol];
|
||||
restart = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+709
@@ -0,0 +1,709 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 1999-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 <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include "vronivector.h"
|
||||
|
||||
/* */
|
||||
/* get my header files */
|
||||
/* */
|
||||
#include "vroni_object.h"
|
||||
#include "fpkernel.h"
|
||||
|
||||
#include "defs.h"
|
||||
#include "ext_appl_defs.h"
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* this function parses the command-line arguments */
|
||||
/* */
|
||||
vr_bool vroniObject::ArgEval(int argc, char *argv[], vr_bool *color_graphics,
|
||||
vr_bool *graphics, vr_bool *save_data,
|
||||
char *output_file, vr_bool *read_input,
|
||||
char *input_file, vr_bool *read_poly,
|
||||
int *step_size, vr_bool *verbose,
|
||||
vr_bool *write_ipe, vr_bool *help, vr_bool *time,
|
||||
vr_bool *statistics, vr_bool *print_copy,
|
||||
vr_bool *quiet, int *bound, int *sample,
|
||||
vr_bool *scale, int *approx, vr_bool *read_sites,
|
||||
vr_bool *read_xdr, vr_bool *read_graphml,
|
||||
vr_bool *discard_dupl_s,
|
||||
int *p_step_size, vr_bool *read_e00,
|
||||
vr_bool *read_dxf, vr_bool *read_polylines,
|
||||
double *t_offset, double *d_offset,
|
||||
vr_bool *write_off, char *off_file,
|
||||
int *o_step_size, vr_bool *auto_offset,
|
||||
vr_bool *full_screen, vr_bool *read_usgs,
|
||||
vr_bool *left_offset, vr_bool *right_offset,
|
||||
vr_bool *compute_wmat, double *wmat_angle,
|
||||
double *wmat_dist, vr_bool *auto_wmat,
|
||||
vr_bool *pnts_only, vr_bool *compute_mic,
|
||||
int *a_step_size, vr_bool *check_data,
|
||||
vr_bool *write_vd_dt, char *vd_dt_file,
|
||||
vr_bool *read_pnts, vr_bool *dxf_format,
|
||||
vr_bool *read_file, vr_bool *write_ma,
|
||||
char *ma_file, vr_bool *clean_up,
|
||||
vr_bool *write_vd, char *vd_file,
|
||||
double *vd_apx_dist,
|
||||
vr_bool *left_vd, vr_bool *right_vd,
|
||||
vr_bool *vr_incr, char *vr_file,
|
||||
int *inputprec, int *mpfr_prec, int *seed)
|
||||
{
|
||||
int count = 1;
|
||||
vr_bool success = true;
|
||||
vr_bool ext_appl_success = false;
|
||||
|
||||
/* */
|
||||
/* let the user call some application-specific function */
|
||||
/* */
|
||||
ExtApplFuncArgEvalInit;
|
||||
|
||||
/* */
|
||||
/* default initializations */
|
||||
/* */
|
||||
*seed = 0;
|
||||
*color_graphics = true;
|
||||
*save_data = false;
|
||||
*read_input = false;
|
||||
*read_poly = false;
|
||||
*read_sites = false;
|
||||
*read_xdr = false;
|
||||
*read_graphml = false;
|
||||
*read_polylines = false;
|
||||
*read_e00 = false;
|
||||
*read_usgs = false;
|
||||
*read_dxf = false;
|
||||
*read_pnts = false;
|
||||
*read_file = false;
|
||||
*graphics = false;
|
||||
*step_size = INT_MAX;
|
||||
*p_step_size = INT_MAX;
|
||||
*o_step_size = INT_MAX;
|
||||
*a_step_size = INT_MAX;
|
||||
*verbose = false;
|
||||
*write_ipe = false;
|
||||
*help = false;
|
||||
*time = false;
|
||||
*statistics = false;
|
||||
*print_copy = true;
|
||||
*quiet = false;
|
||||
*sample = 0;
|
||||
*bound = 3;
|
||||
*scale = true;
|
||||
*approx = 0;
|
||||
*discard_dupl_s = false;
|
||||
*t_offset = 0.0;
|
||||
*d_offset = 0.0;
|
||||
*write_off = false;
|
||||
*auto_offset = false;
|
||||
*full_screen = false;
|
||||
*left_offset = false;
|
||||
*right_offset = false;
|
||||
*compute_wmat = false;
|
||||
*wmat_angle = 0.0;
|
||||
*wmat_dist = 0.0;
|
||||
*auto_wmat = false;
|
||||
*pnts_only = false;
|
||||
*compute_mic = false;
|
||||
*check_data = true;
|
||||
*dxf_format = false;
|
||||
*write_ma = false;
|
||||
*clean_up = false;
|
||||
*write_vd = false;
|
||||
*left_vd = false;
|
||||
*right_vd = false;
|
||||
*vr_incr = false;
|
||||
*vd_apx_dist = 0.0;
|
||||
*inputprec = -1;
|
||||
*mpfr_prec = 23;
|
||||
strcpy(vd_file, "");
|
||||
strcpy(vd_dt_file, "");
|
||||
strcpy(output_file, "");
|
||||
strcpy(input_file, "");
|
||||
strcpy(vr_file, "");
|
||||
|
||||
/* */
|
||||
/* parse the command-line arguments */
|
||||
/* */
|
||||
while ((count < argc) && success) {
|
||||
|
||||
if (strcmp(argv[count],"--duplicate") == 0) {
|
||||
*discard_dupl_s = true;
|
||||
}
|
||||
else if (strcmp(argv[count],"--no_check") == 0) {
|
||||
*check_data = false;
|
||||
}
|
||||
else if (strcmp(argv[count],"--quiet") == 0) {
|
||||
*quiet = true;
|
||||
}
|
||||
else if (strcmp(argv[count],"--verbose") == 0) {
|
||||
*verbose = true;
|
||||
}
|
||||
else if (strcmp(argv[count],"--b+w") == 0) {
|
||||
*color_graphics = false;
|
||||
}
|
||||
else if (strcmp(argv[count],"--OGL") == 0) {
|
||||
#ifdef GRAPHICS
|
||||
*graphics = true;
|
||||
#endif
|
||||
}
|
||||
else if (strcmp(argv[count],"--Ipe") == 0) {
|
||||
if(! *save_data) {
|
||||
*write_ipe = true;
|
||||
++count;
|
||||
if ((success = (count < argc))) strcpy(output_file, argv[count]);
|
||||
}
|
||||
}
|
||||
else if (strcmp(argv[count],"--seed") == 0) {
|
||||
++count;
|
||||
if ((success = (count < argc))) *seed = atoi(argv[count]);
|
||||
if (*seed < 0) *seed = 0;
|
||||
}
|
||||
else if (strcmp(argv[count],"--step") == 0) {
|
||||
*graphics = true;
|
||||
++count;
|
||||
if ((success = (count < argc))) *step_size = atoi(argv[count]);
|
||||
if (*step_size < 1) *step_size = 1;
|
||||
}
|
||||
else if (strcmp(argv[count],"--pstep") == 0) {
|
||||
*graphics = true;
|
||||
++count;
|
||||
if ((success = (count < argc))) *p_step_size = atoi(argv[count]);
|
||||
if (*p_step_size < 1) *p_step_size = 1;
|
||||
}
|
||||
else if (strcmp(argv[count],"--ostep") == 0) {
|
||||
*graphics = true;
|
||||
++count;
|
||||
if ((success = (count < argc))) *o_step_size = atoi(argv[count]);
|
||||
if (*o_step_size < 1) *o_step_size = 1;
|
||||
}
|
||||
else if (strcmp(argv[count],"--astep") == 0) {
|
||||
*graphics = true;
|
||||
++count;
|
||||
if ((success = (count < argc))) *a_step_size = atoi(argv[count]);
|
||||
if (*a_step_size < 1) *a_step_size = 1;
|
||||
}
|
||||
else if (strcmp(argv[count],"--full") == 0) {
|
||||
*full_screen = true;
|
||||
}
|
||||
else if (strcmp(argv[count],"--pnts_only") == 0) {
|
||||
*pnts_only = true;
|
||||
}
|
||||
else if (strcmp(argv[count],"--stat") == 0) {
|
||||
*statistics = true;
|
||||
}
|
||||
else if (strcmp(argv[count],"--copy") == 0) {
|
||||
*print_copy = false;
|
||||
}
|
||||
else if (strcmp(argv[count],"--time") == 0) {
|
||||
*time = true;
|
||||
}
|
||||
else if (strcmp(argv[count],"--help") == 0) {
|
||||
*help = true;
|
||||
}
|
||||
else if (strcmp(argv[count],"--noscale") == 0) {
|
||||
*scale = false;
|
||||
}
|
||||
else if (strcmp(argv[count],"--auto_offset") == 0) {
|
||||
*auto_offset = true;
|
||||
}
|
||||
else if (strcmp(argv[count],"--wmat") == 0) {
|
||||
*compute_wmat = true;
|
||||
}
|
||||
else if (strcmp(argv[count],"--auto_wmat") == 0) {
|
||||
*auto_wmat = true;
|
||||
*compute_wmat = true;
|
||||
}
|
||||
else if (strcmp(argv[count],"--wmat_angle") == 0) {
|
||||
++count;
|
||||
if ((success = (count < argc))) *wmat_angle = atof(argv[count]);
|
||||
if (*wmat_angle < 0.0) *wmat_angle = 0.0;
|
||||
*compute_wmat = true;
|
||||
}
|
||||
else if (strcmp(argv[count],"--wmat_dist") == 0) {
|
||||
++count;
|
||||
if ((success = (count < argc))) *wmat_dist = atof(argv[count]);
|
||||
if (*wmat_dist < 0.0) *wmat_dist = 0.0;
|
||||
*compute_wmat = true;
|
||||
}
|
||||
else if (strcmp(argv[count],"--left_offset") == 0) {
|
||||
*left_offset = true;
|
||||
}
|
||||
else if (strcmp(argv[count],"--right_offset") == 0) {
|
||||
*right_offset = true;
|
||||
}
|
||||
else if (strcmp(argv[count],"--mic") == 0) {
|
||||
#ifdef MIC
|
||||
*compute_mic = true;
|
||||
#endif
|
||||
}
|
||||
else if (strcmp(argv[count],"--save") == 0) {
|
||||
if(! *write_ipe) {
|
||||
*save_data = true;
|
||||
++count;
|
||||
if ((success = (count < argc))) strcpy(output_file, argv[count]);
|
||||
}
|
||||
}
|
||||
else if (strcmp(argv[count],"--vd_dt") == 0) {
|
||||
*write_vd_dt = true;
|
||||
++count;
|
||||
if ((success = (count < argc))) strcpy(vd_dt_file, argv[count]);
|
||||
}
|
||||
else if (strcmp(argv[count],"--vr_incr") == 0) {
|
||||
*vr_incr = true;
|
||||
++count;
|
||||
if ((success = (count < argc))) strcpy(vr_file, argv[count]);
|
||||
}
|
||||
else if (strcmp(argv[count],"--approx") == 0) {
|
||||
++count;
|
||||
if ((success = (count < argc))) *approx = atoi(argv[count]);
|
||||
if (*approx < 0) *approx = 0;
|
||||
}
|
||||
else if (strcmp(argv[count],"--bound") == 0) {
|
||||
++count;
|
||||
if ((success = (count < argc))) *bound = atoi(argv[count]);
|
||||
if (*bound < 3) *bound = 3;
|
||||
}
|
||||
else if (strcmp(argv[count],"--file") == 0) {
|
||||
*read_file = true;
|
||||
++count;
|
||||
if ((success = (count < argc))) strcpy(input_file, argv[count]);
|
||||
}
|
||||
else if (strcmp(argv[count],"--input") == 0) {
|
||||
*read_input = true;
|
||||
++count;
|
||||
if ((success = (count < argc))) strcpy(input_file, argv[count]);
|
||||
}
|
||||
else if (strcmp(argv[count],"--poly") == 0) {
|
||||
*read_poly = true;
|
||||
++count;
|
||||
if ((success = (count < argc))) strcpy(input_file, argv[count]);
|
||||
}
|
||||
else if (strcmp(argv[count],"--pnts") == 0) {
|
||||
*read_pnts = true;
|
||||
++count;
|
||||
if ((success = (count < argc))) strcpy(input_file, argv[count]);
|
||||
}
|
||||
else if (strcmp(argv[count],"--polylines") == 0) {
|
||||
*read_polylines = true;
|
||||
++count;
|
||||
if ((success = (count < argc))) strcpy(input_file, argv[count]);
|
||||
}
|
||||
else if (strcmp(argv[count],"--xdr") == 0) {
|
||||
*read_xdr = true;
|
||||
++count;
|
||||
if ((success = (count < argc))) strcpy(input_file, argv[count]);
|
||||
}
|
||||
else if (strcmp(argv[count],"--usgs") == 0) {
|
||||
*read_usgs = true;
|
||||
++count;
|
||||
if ((success = (count < argc))) strcpy(input_file, argv[count]);
|
||||
}
|
||||
else if (strcmp(argv[count],"--e00") == 0) {
|
||||
*read_e00 = true;
|
||||
++count;
|
||||
if ((success = (count < argc))) strcpy(input_file, argv[count]);
|
||||
}
|
||||
else if (strcmp(argv[count],"--dxf") == 0) {
|
||||
*read_dxf = true;
|
||||
++count;
|
||||
if ((success = (count < argc))) strcpy(input_file, argv[count]);
|
||||
}
|
||||
else if (strcmp(argv[count],"--sites") == 0) {
|
||||
*read_sites = true;
|
||||
++count;
|
||||
if ((success = (count < argc))) strcpy(input_file, argv[count]);
|
||||
}
|
||||
else if (strcmp(argv[count],"--graphml") == 0) {
|
||||
*read_graphml = true;
|
||||
++count;
|
||||
if ((success = (count < argc))) strcpy(input_file, argv[count]);
|
||||
}
|
||||
else if (strcmp(argv[count],"--offset") == 0) {
|
||||
++count;
|
||||
if ((success = (count < argc))) *t_offset = atof(argv[count]);
|
||||
if (*t_offset < 0.0) *t_offset = 0.0;
|
||||
}
|
||||
else if (strcmp(argv[count],"--doffset") == 0) {
|
||||
++count;
|
||||
if ((success = (count < argc))) *d_offset = atof(argv[count]);
|
||||
if (*t_offset < 0.0) *d_offset = 0.0;
|
||||
}
|
||||
else if (strcmp(argv[count],"--off") == 0) {
|
||||
*write_off = true;
|
||||
++count;
|
||||
if ((success = (count < argc))) strcpy(off_file, argv[count]);
|
||||
}
|
||||
else if (strcmp(argv[count],"--ma") == 0) {
|
||||
*write_ma = true;
|
||||
++count;
|
||||
if ((success = (count < argc))) strcpy(ma_file, argv[count]);
|
||||
}
|
||||
else if (strcmp(argv[count],"--off_dxf") == 0) {
|
||||
*write_off = true;
|
||||
*dxf_format = true;
|
||||
++count;
|
||||
if ((success = (count < argc))) strcpy(off_file, argv[count]);
|
||||
}
|
||||
else if (strcmp(argv[count],"--clean") == 0) {
|
||||
*clean_up = true;
|
||||
}
|
||||
#ifdef WRITE_VD
|
||||
else if (strcmp(argv[count],"--vd") == 0) {
|
||||
*write_vd = true;
|
||||
++count;
|
||||
if ((success = (count < argc))) strcpy(vd_file, argv[count]);
|
||||
}
|
||||
else if (strcmp(argv[count],"--vd_apx_dist") == 0) {
|
||||
++count;
|
||||
if ((success = (count < argc))) *vd_apx_dist = atof(argv[count]);
|
||||
}
|
||||
else if (strcmp(argv[count],"--left_vd") == 0) {
|
||||
*left_vd = true;
|
||||
}
|
||||
else if (strcmp(argv[count],"--right_vd") == 0) {
|
||||
*right_vd = true;
|
||||
}
|
||||
#endif
|
||||
#ifdef TRACE
|
||||
else if (strcmp(argv[count],"--write") == 0) {
|
||||
write_debug = true;
|
||||
}
|
||||
else if (strcmp(argv[count],"--center") == 0) {
|
||||
center = true;
|
||||
}
|
||||
else if (strcmp(argv[count],"--proto") == 0) {
|
||||
proto = true;
|
||||
}
|
||||
else if (strcmp(argv[count],"--cntr") == 0) {
|
||||
++count;
|
||||
if ((success = (count < argc))) max_cntr = atoi(argv[count]);
|
||||
if (max_cntr < 1) max_cntr = 0;
|
||||
}
|
||||
#endif
|
||||
#ifdef WITH_COREBACKEND
|
||||
else if (strcmp(argv[count],"--inputprec") == 0) {
|
||||
++count;
|
||||
if ((success = (count < argc))) *inputprec = atoi(argv[count]);
|
||||
if (*inputprec < -1) *inputprec = -1;
|
||||
}
|
||||
#elif defined(WITH_MPFRBACKEND)
|
||||
else if (strcmp(argv[count],"--mpfr-prec") == 0) {
|
||||
++count;
|
||||
*mpfr_prec = 0;
|
||||
if ((success = (count < argc))) *mpfr_prec = atoi(argv[count]);
|
||||
if (*mpfr_prec < 23) *mpfr_prec = 23; //TODO: Appropriate warning
|
||||
}
|
||||
#endif
|
||||
#ifdef OTHER
|
||||
else if (strcmp(argv[count],"--cgal") == 0) {
|
||||
cgal = true;
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
/* */
|
||||
/* perhaps this is a user-supplied run-time option? let the user */
|
||||
/* call some application-specific function. make sure to set the */
|
||||
/* vr_bool flag ext_appl_success appropriately when using this */
|
||||
/* application-specific function! */
|
||||
/* */
|
||||
ExtApplFuncArgEvalParse;
|
||||
|
||||
success = ext_appl_success;
|
||||
}
|
||||
++count;
|
||||
}
|
||||
|
||||
if (*read_pnts) *pnts_only = true;
|
||||
if (*pnts_only && (*bound < 5)) *bound = 5;
|
||||
|
||||
if (!*graphics) {
|
||||
*step_size = INT_MAX;
|
||||
*p_step_size = INT_MAX;
|
||||
*o_step_size = INT_MAX;
|
||||
}
|
||||
|
||||
/* */
|
||||
/* let the user call some application-specific function */
|
||||
/* */
|
||||
ExtApplFuncArgEvalDone;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void vroniObject::EvalError(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"\nUsage: vroni [--help] [--stat] ");
|
||||
fprintf(stderr,"[--bound NNN] [--noscale] [--duplicate] [--time]\n");
|
||||
fprintf(stderr,
|
||||
" [--no_check] [--pnts_only] [--vd_dt XXX]");
|
||||
fprintf(stderr,
|
||||
" [--file XXX] [--save XXX]\n");
|
||||
/*
|
||||
fprintf(stderr,
|
||||
" [--poly XXX] [--input XXX] [--sites XXX]");
|
||||
fprintf(stderr,
|
||||
" [--usgs XXX] [--dxf XXX]\n");
|
||||
fprintf(stderr,
|
||||
" [--polylines XXX] [--xdr XXX] [--e00 XXX]");
|
||||
fprintf(stderr,
|
||||
" [--pnts XXX]\n");
|
||||
*/
|
||||
#ifdef OGL_GRAPHICS
|
||||
fprintf(stderr,
|
||||
" [--OGL] [--b+w] [--step NNN] [--pstep NNN]");
|
||||
fprintf(stderr,
|
||||
" [--ostep NNN]\n");
|
||||
fprintf(stderr,
|
||||
" [--astep NNN] [--Ipe XXX] [--full] [--clean]\n");
|
||||
#endif
|
||||
/*
|
||||
fprintf(stderr,
|
||||
" [--approx NNN]\n");
|
||||
*/
|
||||
fprintf(stderr,
|
||||
" [--auto_offset] [--offset FFF] [--doffset FFF] [--off XXX]\n");
|
||||
fprintf(stderr,
|
||||
" [--off_dxf XXX] [--left_offset] [--right_offset] [--mic]\n");
|
||||
#ifdef WMAT
|
||||
fprintf(stderr,
|
||||
" [--wmat] [--wmat_angle FFF] [--wmat_dist FFF]");
|
||||
fprintf(stderr,
|
||||
" [--auto_wmat]\n");
|
||||
#endif
|
||||
#ifdef WRITE_VD
|
||||
fprintf(stderr,
|
||||
" [--vd] [--vd_apx_dist] [--left_vd] [--right_vd]\n");
|
||||
#endif
|
||||
#ifdef VRONI_INFO
|
||||
fprintf(stderr,
|
||||
" [--quiet] [--verbose]\n");
|
||||
#endif
|
||||
#ifdef TRACE
|
||||
fprintf(stderr,
|
||||
" [--center] [--write] [--proto] [--cntr]\n");
|
||||
#endif
|
||||
#ifdef OTHER
|
||||
fprintf(stderr,
|
||||
" [--cgal]\n");
|
||||
#endif
|
||||
#ifdef WITH_MPFRBACKEND
|
||||
fprintf(stderr,
|
||||
" [--mpfr-prec NNN]\n");
|
||||
#elif defined(WITH_COREBACKEND)
|
||||
fprintf(stderr,
|
||||
" [--inputprec NNN]\n");
|
||||
#endif
|
||||
|
||||
/* */
|
||||
/* let the user call some application-specific function */
|
||||
/* */
|
||||
ExtApplFuncEvalErrorOption;
|
||||
|
||||
fprintf(stderr,
|
||||
"\n");
|
||||
fprintf(stderr,
|
||||
"--help: causes the program to print this help message\n");
|
||||
#ifdef VRONI_INFO
|
||||
fprintf(stderr,
|
||||
"--verbose: write warning and informatory messages to stdout\n");
|
||||
fprintf(stderr,
|
||||
"--quiet: do not output warning or informatory messages\n");
|
||||
#endif
|
||||
#ifdef GRAPHICS
|
||||
#ifdef OGL_GRAPHICS
|
||||
fprintf(stderr,
|
||||
"--OGL: enable an interactive OGL display\n");
|
||||
#endif
|
||||
fprintf(stderr,
|
||||
"--full: full-screen graphics window\n");
|
||||
fprintf(stderr,
|
||||
"--Ipe XXX: write data in Ipe 7.0 (.ipe) format to file `XXX'\n");
|
||||
fprintf(stderr,
|
||||
"--b+w: b/w rather than color graphics\n");
|
||||
fprintf(stderr,
|
||||
"--step NNN: insert NNN input segments before redrawing\n");
|
||||
fprintf(stderr,
|
||||
"--pstep NNN: insert NNN input points before redrawing\n");
|
||||
fprintf(stderr,
|
||||
"--astep NNN: insert NNN input arcs before redrawing\n");
|
||||
fprintf(stderr,
|
||||
"--ostep NNN: compute NNN offsets before redrawing\n");
|
||||
#endif
|
||||
fprintf(stderr,
|
||||
"--pnts_only: consider only points/vertices and compute only point VD/DT\n");
|
||||
fprintf(stderr,
|
||||
"--vd_dt XXX: output point VD/DT to file `XXX'; only used in\n");
|
||||
fprintf(stderr,
|
||||
" conjunction with option \"--pnts_only\"\n");
|
||||
fprintf(stderr,
|
||||
"--vr_incr XXX: output Voronoi regions file `XXX', one after the other;\n");
|
||||
fprintf(stderr,
|
||||
" only used in conjunction with option \"--pnts_only\"\n");
|
||||
fprintf(stderr,
|
||||
"--save XXX: save data in Martin's `sites' format to file `XXX'\n");
|
||||
#ifdef WRITE_VD
|
||||
fprintf(stderr,
|
||||
"--vd XXX: output approximate VD faces to file `XXX' in OBJ format\n"); fprintf(stderr,
|
||||
"--vd_apx_dist d: sampling distance for approxmating conic VD edges\n");
|
||||
fprintf(stderr,
|
||||
"--left_vd: output VD only on left side of input segments\n");
|
||||
fprintf(stderr,
|
||||
"--right_vd: output VD only on right side of input segments\n");
|
||||
#endif
|
||||
#ifdef WITH_COREBACKEND
|
||||
fprintf(stderr,
|
||||
"--inputprec NNN: Input precision (CORE library). -1 for CORE_INFTY\n");
|
||||
#elif defined(WITH_MPFRBACKEND)
|
||||
fprintf(stderr,
|
||||
"--mpfr-prec NNN: Precision to use in MPFR backend, must be at least 23\n");
|
||||
#endif
|
||||
fprintf(stderr,
|
||||
"--bound NNN: compute the VD only in a region whose width is\n");
|
||||
fprintf(stderr,
|
||||
" (2NNN+1) times the width of the bounding box of the\n");
|
||||
fprintf(stderr,
|
||||
" input data; similar for the height. default: NNN = 3.\n");
|
||||
/*
|
||||
fprintf(stderr,
|
||||
"--approx NNN: integer approximation factor for approximating arcs\n");
|
||||
*/
|
||||
fprintf(stderr,
|
||||
"--noscale: do not scale the input data in order to convert it to `nice'\n");
|
||||
fprintf(stderr,
|
||||
" coordinates. (default: scale the data.)\n");
|
||||
fprintf(stderr,
|
||||
" strongly recommended not to use this option!\n");
|
||||
fprintf(stderr,
|
||||
"--duplicate: check for duplicate segs/arcs prior to running the\n");
|
||||
fprintf(stderr,
|
||||
" VD code. (default: check during computation.)\n");
|
||||
fprintf(stderr,
|
||||
" time-consuming!!\n");
|
||||
fprintf(stderr,
|
||||
"--no_check: do not apply a time-consuming all-pairs check if\n");
|
||||
fprintf(stderr,
|
||||
" self-intersections are suspected.\n");
|
||||
fprintf(stderr,
|
||||
"--time: time the computation of the Voronoi diagram\n");
|
||||
fprintf(stderr,
|
||||
"--stat: compute and output some statistics\n");
|
||||
fprintf(stderr,
|
||||
"--offset t: compute offset curves for offset distance t.\n");
|
||||
fprintf(stderr,
|
||||
"--doffset d: compute offset pattern for offsets t, t+d, t+2d,...\n");
|
||||
fprintf(stderr,
|
||||
"--auto_offset: compute offset pattern according to `nice' offsets\n");
|
||||
fprintf(stderr,
|
||||
" automatically determined by the program\n");
|
||||
fprintf(stderr,
|
||||
"--left_offset: compute offset pattern only on left side of input segments\n");
|
||||
fprintf(stderr,
|
||||
"--right_offset: compute offset pattern only on right side of input segments\n");
|
||||
fprintf(stderr,
|
||||
"--off XXX: output the offset data in my .dat format to file `XXX'\n");
|
||||
fprintf(stderr,
|
||||
"--off_dxf XXX: output the offset data in .dxf format to file `XXX'\n");
|
||||
fprintf(stderr,
|
||||
"--mic: compute the maximum inscribed/empty circle.\n");
|
||||
#ifdef MAT
|
||||
fprintf(stderr,
|
||||
"--wmat: compute (weighted) medial axis\n");
|
||||
#endif
|
||||
#ifdef WMAT
|
||||
fprintf(stderr,
|
||||
"--wmat_angle a: angle threshold for WMAT computation\n");
|
||||
fprintf(stderr,
|
||||
"--wmat_dist d: distance threshold for WMAT computation\n");
|
||||
fprintf(stderr,
|
||||
"--auto_wmat: compute WMAT according to `nice' thresholds\n");
|
||||
fprintf(stderr,
|
||||
" automatically determined by the program\n");
|
||||
#endif
|
||||
fprintf(stderr,
|
||||
"--file XXX: read input data from file `XXX'; the appropriate input\n");
|
||||
fprintf(stderr,
|
||||
" function is selected automatically based on the extension\n");
|
||||
fprintf(stderr,
|
||||
" of the file.\n");
|
||||
fprintf(stderr,
|
||||
" The following input formats are supported:\n");
|
||||
fprintf(stderr,
|
||||
" *.dat: read data in Martin's format from file `*.dat';\n");
|
||||
fprintf(stderr,
|
||||
" *.poly: read polygon in simplified format from file `*.poly';\n");
|
||||
fprintf(stderr,
|
||||
" *.site: read sites (pnts, segs, arcs) from file `*.site';\n");
|
||||
fprintf(stderr,
|
||||
" *.line: read polygonal chains from file `*.line';\n");
|
||||
fprintf(stderr,
|
||||
" *.usgs: read data in USGS format from file `*.usgs';\n");
|
||||
fprintf(stderr,
|
||||
" *.xdr: read data in Facet_XDR format from file `*.xdr';\n");
|
||||
fprintf(stderr,
|
||||
" *.e00: read data in ArcInfo export format from file `*.e00';\n");
|
||||
fprintf(stderr,
|
||||
" *.dxf: read data in AutoCAD's dxf format from file `*.dxf';\n");
|
||||
fprintf(stderr,
|
||||
" *.pnt: read point data from file `*.pnt';\n");
|
||||
fprintf(stderr,
|
||||
" *.xml: read data in Ipe 6 .xml format from file `*.xml'.\n");
|
||||
fprintf(stderr,
|
||||
" *.ipe: read data in Ipe 6 XML format from file `*.ipe'.\n");
|
||||
fprintf(stderr,
|
||||
" *.bdm: read polygons in .bdm format from file `*.bdm'.\n");
|
||||
#ifdef OTHER
|
||||
fprintf(stderr,
|
||||
"--cgal: write data to `cgal.cin' as input for CGAL's VD code\n");
|
||||
#endif
|
||||
fprintf(stderr,
|
||||
"--clean: clean up the data by looking for intersections prior to\n");
|
||||
fprintf(stderr,
|
||||
" the VD computation.\n");
|
||||
|
||||
/* */
|
||||
/* let the user call some application-specific function */
|
||||
/* */
|
||||
ExtApplFuncEvalErrorExplain;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#include "ext_appl_arg_eval.cc"
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 1999-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.c". */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* 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 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#ifndef VRONI_BASIC_H
|
||||
#define VRONI_BASIC_H
|
||||
|
||||
|
||||
#include "consts.h"
|
||||
#include "util.h"
|
||||
#include "types.h"
|
||||
|
||||
|
||||
|
||||
#define BASIC_MINI 1.0e-20
|
||||
|
||||
#ifndef RAND
|
||||
|
||||
#define RND_MAX 2147483647
|
||||
|
||||
#define UniformRandom(x) \
|
||||
{\
|
||||
x = ((double) random()) / RND_MAX; }
|
||||
|
||||
#define RandomInteger(N) \
|
||||
(\
|
||||
assert(N > 0), \
|
||||
basic_i_local = random(), \
|
||||
basic_i_local - (basic_i_local / (N)) * (N))
|
||||
|
||||
#define InitRandom(seed) \
|
||||
{\
|
||||
srandom(seed); }
|
||||
|
||||
#else
|
||||
|
||||
#ifdef RAND_MAX
|
||||
#define RND_MAX RAND_MAX
|
||||
#else
|
||||
#define RND_MAX 32767
|
||||
#endif
|
||||
|
||||
#define UniformRandom(x) \
|
||||
{\
|
||||
x = ((double) rand()) / RND_MAX; \
|
||||
}
|
||||
|
||||
#define RandomInteger(N) \
|
||||
(\
|
||||
assert(N > 0), \
|
||||
basic_i_local = rand(), \
|
||||
basic_i_local - (basic_i_local / (N)) * (N))
|
||||
|
||||
|
||||
#define InitRandom(seed) \
|
||||
{\
|
||||
srand(seed); }
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
#define ScaleX(xc) (scale_factor * (xc - shift.x))
|
||||
|
||||
#define ScaleY(yc) (scale_factor * (yc - shift.y))
|
||||
|
||||
#define ScaleV(value) (value * scale_factor)
|
||||
|
||||
#define UnscaleX(xc) (assert(scale_factor > 0.0), xc / scale_factor + shift.x)
|
||||
|
||||
#define UnscaleY(yc) (assert(scale_factor > 0.0), yc / scale_factor + shift.y)
|
||||
|
||||
#define UnscaleV(value) (assert(scale_factor > 0.0), value / scale_factor)
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
#define CirBBox(p, r, bb_min, bb_max) {\
|
||||
(bb_min).x = (p).x - r; \
|
||||
(bb_min).y = (p).y - r; \
|
||||
(bb_max).x = (p).x + r; \
|
||||
(bb_max).y = (p).y + r; }
|
||||
|
||||
|
||||
#define TriBBox(a, b, c, bb_min, bb_max) {\
|
||||
MinMax3((a).x, (b).x, (c).x, (bb_min).x, (bb_max).x); \
|
||||
MinMax3((a).y, (b).y, (c).y, (bb_min).y, (bb_max).y); }
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
+605
@@ -0,0 +1,605 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 1999-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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <float.h>
|
||||
|
||||
/* */
|
||||
/* get my header files */
|
||||
/* */
|
||||
#include "fpkernel.h"
|
||||
#include "vronivector.h"
|
||||
#include "vroni_object.h"
|
||||
#include "defs.h"
|
||||
|
||||
|
||||
|
||||
#define PAGE_SIZE 32768
|
||||
|
||||
|
||||
|
||||
#define NotIdenticalPoint(I, J) \
|
||||
((pnts[I].p.x != pnts[J].p.x) || (pnts[I].p.y != pnts[J].p.y))
|
||||
|
||||
|
||||
|
||||
#define StorePIndex(I, J, K, T) \
|
||||
{\
|
||||
assert(I < max_num_p_indices); \
|
||||
assert(InPntsList(J)); \
|
||||
p_indices[I].site = K; \
|
||||
p_indices[I].type = T; \
|
||||
p_indices[I].pnt_data = pnts[J]; \
|
||||
}
|
||||
|
||||
|
||||
void vroniObject::ResetCleanStatus(void)
|
||||
{
|
||||
data_sorted = false;
|
||||
clean_initialized = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
vr_bool vroniObject::InReverseIndList(int i)
|
||||
{
|
||||
return ((i >= 0) && (i < max_num_reverse_ind));
|
||||
}
|
||||
|
||||
|
||||
inline void vroniObject::InsertReverseIndex(const int ipnt, const int isite,
|
||||
const index_type tsite)
|
||||
{
|
||||
assert(InPntsList(ipnt));
|
||||
assert(InReverseIndList(ipnt));
|
||||
|
||||
if (reverse_ind[ipnt].type == ISO_PNT) {
|
||||
assert(reverse_ind[ipnt].next == NIL);
|
||||
reverse_ind[ipnt].site = isite;
|
||||
reverse_ind[ipnt].type = tsite;
|
||||
}
|
||||
else {
|
||||
assert((reverse_ind[ipnt].type == SEG_START) ||
|
||||
(reverse_ind[ipnt].type == SEG_END) ||
|
||||
(reverse_ind[ipnt].type == ARC_START) ||
|
||||
(reverse_ind[ipnt].type == ARC_END));
|
||||
|
||||
if (num_reverse_ind >= max_num_reverse_ind) {
|
||||
max_num_reverse_ind += PAGE_SIZE;
|
||||
gentlyResizeSTLVector(reverse_ind, max_num_reverse_ind, "clean_data:reverse_ind");
|
||||
}
|
||||
reverse_ind[num_reverse_ind].site = isite;
|
||||
reverse_ind[num_reverse_ind].type = tsite;
|
||||
reverse_ind[num_reverse_ind].next = reverse_ind[ipnt].next;
|
||||
reverse_ind[ipnt].next = num_reverse_ind;
|
||||
++num_reverse_ind;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define GetReverseSite(I) (assert(InReverseIndList(I)), reverse_ind[I].site)
|
||||
|
||||
#define GetReverseType(I) (assert(InReverseIndList(I)), reverse_ind[I].type)
|
||||
|
||||
#define GetReverseNext(I) (assert(InReverseIndList(I)), reverse_ind[I].next)
|
||||
|
||||
#define SetReverseSite(I, S) (assert(InReverseIndList(I)), \
|
||||
reverse_ind[I].site = S)
|
||||
|
||||
#define SetReverseType(I, T) (assert(InReverseIndList(I)), \
|
||||
reverse_ind[I].type = T)
|
||||
|
||||
#define SetReverseNext(I, N) (assert(InReverseIndList(I)), \
|
||||
reverse_ind[I].next = N)
|
||||
|
||||
|
||||
|
||||
int p_comp(const void *a, const void *b)
|
||||
{
|
||||
if (((pnt*)a)->p.x < ((pnt*)b)->p.x)
|
||||
return -1;
|
||||
else if (((pnt*)a)->p.x > ((pnt*)b)->p.x)
|
||||
return 1;
|
||||
else {
|
||||
if (((pnt*)a)->p.y < ((pnt*)b)->p.y)
|
||||
return -1;
|
||||
else if (((pnt*)a)->p.y > ((pnt*)b)->p.y)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Defines a lexicographic order on segment indices. The first part is formed
|
||||
* by the smaller index of the two segment points, the second is formed by the
|
||||
* larger index.
|
||||
*/
|
||||
|
||||
int s_comp(const void *a, const void *b)
|
||||
{
|
||||
if (((seg*)a)->i1 < ((seg*)a)->i2) {
|
||||
if (((seg*)b)->i1 < ((seg*)b)->i2) {
|
||||
if (((seg*)a)->i1 < ((seg*)b)->i1) return -1;
|
||||
else if (((seg*)a)->i1 > ((seg*)b)->i1) return 1;
|
||||
else {
|
||||
if (((seg*)a)->i2 < ((seg*)b)->i2) return -1;
|
||||
else if (((seg*)a)->i2 > ((seg*)b)->i2) return 1;
|
||||
else return 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (((seg*)a)->i1 < ((seg*)b)->i2) return -1;
|
||||
else if (((seg*)a)->i1 > ((seg*)b)->i2) return 1;
|
||||
else {
|
||||
if (((seg*)a)->i2 < ((seg*)b)->i1) return -1;
|
||||
else if (((seg*)a)->i2 > ((seg*)b)->i1) return 1;
|
||||
else return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (((seg*)b)->i1 < ((seg*)b)->i2) {
|
||||
if (((seg*)a)->i2 < ((seg*)b)->i1) return -1;
|
||||
else if (((seg*)a)->i2 > ((seg*)b)->i1) return 1;
|
||||
else {
|
||||
if (((seg*)a)->i1 < ((seg*)b)->i2) return -1;
|
||||
else if (((seg*)a)->i1 > ((seg*)b)->i2) return 1;
|
||||
else return 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (((seg*)a)->i2 < ((seg*)b)->i2) return -1;
|
||||
else if (((seg*)a)->i2 > ((seg*)b)->i2) return 1;
|
||||
else {
|
||||
if (((seg*)a)->i1 < ((seg*)b)->i1) return -1;
|
||||
else if (((seg*)a)->i1 > ((seg*)b)->i1) return 1;
|
||||
else return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline bool s_equal(const seg & a, const seg & b) {
|
||||
return ((a.i1 == b.i1 && a.i2 == b.i2) ||
|
||||
(a.i1 == b.i2 && a.i2 == b.i1));
|
||||
}
|
||||
|
||||
|
||||
int a_comp(const void *a, const void *b)
|
||||
{
|
||||
if (((arc*)a)->i1 < ((arc*)b)->i1) return -1;
|
||||
else if (((arc*)a)->i1 > ((arc*)b)->i1) return 1;
|
||||
else {
|
||||
if (((arc*)a)->i2 < ((arc*)b)->i2) return -1;
|
||||
else if (((arc*)a)->i2 > ((arc*)b)->i2) return 1;
|
||||
else {
|
||||
if (((arc*)a)->c.x < ((arc*)b)->c.x) return -1;
|
||||
else if (((arc*)a)->c.x > ((arc*)b)->c.x) return 1;
|
||||
else {
|
||||
if (((arc*)a)->c.y < ((arc*)b)->c.y) return -1;
|
||||
else if (((arc*)a)->c.y > ((arc*)b)->c.y) return 1;
|
||||
else return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline bool a_equal(const arc & a, const arc & b)
|
||||
{
|
||||
return ((a.i1 == b.i1) && (a.i2 == b.i2) &&
|
||||
(a.c.x == b.c.x) && (a.c.y == b.c.y));
|
||||
}
|
||||
|
||||
vr_bool vroniObject::GetDataSorted(void)
|
||||
{
|
||||
return data_sorted;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void vroniObject::FreeReverseIndex(void)
|
||||
{
|
||||
reverse_ind.clear();
|
||||
|
||||
max_num_reverse_ind = 0;
|
||||
num_reverse_ind = 0;
|
||||
|
||||
reverse_index_exists = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void vroniObject::SetUpReverseIndex(int number_of_segs, int number_of_arcs,
|
||||
vr_bool set_idx)
|
||||
{
|
||||
int number, i, j, k;
|
||||
|
||||
/* */
|
||||
/* make sure that every point knows all its incident segs and arcs. */
|
||||
/* */
|
||||
number = num_pnts + number_of_segs + number_of_arcs;
|
||||
|
||||
if (number >= max_num_reverse_ind) {
|
||||
max_num_reverse_ind = number;
|
||||
gentlyResizeSTLVector(reverse_ind, max_num_reverse_ind, "clean_data:reverse_ind");
|
||||
}
|
||||
|
||||
assert(number >= num_pnts);
|
||||
for (i = 0; i < num_pnts; ++i) {
|
||||
SetReverseType(i, ISO_PNT);
|
||||
SetReverseNext(i, NIL);
|
||||
SetReverseSite(i, i);
|
||||
}
|
||||
num_reverse_ind = num_pnts;
|
||||
|
||||
if (set_idx) {
|
||||
for (i = 0; i < num_pnts; ++i) {
|
||||
SetPntVDPtr(i, i);
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 0; j < number_of_segs; ++j) {
|
||||
k = Get1stVtxSeg(j);
|
||||
assert(InPntsList(k));
|
||||
InsertReverseIndex(k, j, SEG_START);
|
||||
k = Get2ndVtxSeg(j);
|
||||
assert(InPntsList(k));
|
||||
InsertReverseIndex(k, j, SEG_END);
|
||||
}
|
||||
for (j = 0; j < number_of_arcs; ++j) {
|
||||
k = Get1stVtxArc(j);
|
||||
assert(InPntsList(k));
|
||||
InsertReverseIndex(k, j, ARC_START);
|
||||
k = Get2ndVtxArc(j);
|
||||
assert(InPntsList(k));
|
||||
InsertReverseIndex(k, j, ARC_END);
|
||||
}
|
||||
|
||||
reverse_index_exists = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* this routine sorts all points and vertices in lexicographic order, */
|
||||
/* eliminates duplicate points/vertices, and discards zero-length segs/arcs. */
|
||||
/* */
|
||||
void vroniObject::CleanData(int *removed, int *removed_segs, int *removed_arcs,
|
||||
vr_bool discard_duplicate_sites)
|
||||
{
|
||||
int i, j, k, num_help, nn, number;
|
||||
index_type tsite;
|
||||
int isite, s;
|
||||
|
||||
if (!clean_initialized) {
|
||||
clean_initialized = true;
|
||||
if (!discard_duplicate_sites) {
|
||||
/* */
|
||||
/* no need to sort the data; identical points will be discovered on */
|
||||
/* the fly! */
|
||||
/* */
|
||||
*removed = *removed_segs = *removed_arcs = 0;
|
||||
|
||||
data_sorted = false;
|
||||
reverse_index_exists = false;
|
||||
|
||||
#ifdef GRAPHICS
|
||||
if (graphics) UpdateBuffer();
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
num_help = num_pnts;
|
||||
}
|
||||
else {
|
||||
isolated_pnts = false;
|
||||
num_help = num_pnts;
|
||||
}
|
||||
|
||||
/* */
|
||||
/* make sure that every point knows all its incident segs and arcs. */
|
||||
/* */
|
||||
if ((num_segs > 0) || (num_arcs > 0))
|
||||
SetUpReverseIndex(num_segs, num_arcs, true);
|
||||
|
||||
/* */
|
||||
/* sort pnts[] according to lexicographical order */
|
||||
/* */
|
||||
qsort(&(pnts[0]), num_pnts, sizeof(pnt), p_comp);
|
||||
data_sorted = true;
|
||||
|
||||
/* */
|
||||
/* re-number the vertices of the data */
|
||||
/* */
|
||||
if ((num_segs == 0) && (num_arcs == 0)) {
|
||||
j = 0;
|
||||
for (i = 1; i < num_pnts; ++i) {
|
||||
if (!IsDeletedPnt(i)) {
|
||||
if (NotIdenticalPoint(i, j)) {
|
||||
++j;
|
||||
pnts[j] = pnts[i];
|
||||
}
|
||||
#ifdef ORDERED
|
||||
else if (pnts[j].key > pnts[i].key) {
|
||||
pnts[j].key = pnts[i].key;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
isolated_pnts = true;
|
||||
++j;
|
||||
num_pnts = j;
|
||||
*removed = num_help - num_pnts;
|
||||
|
||||
#ifdef GRAPHICS
|
||||
/* */
|
||||
/* update the drawing buffer accordingly */
|
||||
/* */
|
||||
if (graphics) UpdateBuffer();
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
j = 0;
|
||||
number = num_pnts - 2;
|
||||
for (i = 0; i < num_pnts; ++i) {
|
||||
s = GetPntVDPtr(i);
|
||||
SetPntVDPtr(i, NIL);
|
||||
if (!IsDeletedPnt(i)) {
|
||||
if (NotIdenticalPoint(i, j)) {
|
||||
++j;
|
||||
pnts[j] = pnts[i];
|
||||
}
|
||||
#ifdef ORDERED
|
||||
else if (pnts[j].key > pnts[i].key) {
|
||||
pnts[j].key = pnts[i].key;
|
||||
}
|
||||
#endif
|
||||
while (s != NIL) {
|
||||
tsite = GetReverseType(s);
|
||||
isite = GetReverseSite(s);
|
||||
switch(tsite) {
|
||||
case ISO_PNT:
|
||||
if ((i >= 2) && (i < number)) isolated_pnts = true;
|
||||
break;
|
||||
case SEG_START:
|
||||
assert(InSegsList(isite));
|
||||
Set1stVtxSeg(isite, j);
|
||||
break;
|
||||
case SEG_END:
|
||||
assert(InSegsList(isite));
|
||||
Set2ndVtxSeg(isite, j);
|
||||
break;
|
||||
case ARC_START:
|
||||
assert(InArcsList(isite));
|
||||
Set1stVtxArc(isite, j);
|
||||
break;
|
||||
case ARC_END:
|
||||
assert(InArcsList(isite));
|
||||
Set2ndVtxArc(isite, j);
|
||||
break;
|
||||
default:
|
||||
assert((tsite == SEG_START) || (tsite == SEG_END) ||
|
||||
(tsite == ARC_START) || (tsite == ARC_END) ||
|
||||
(tsite == ISO_PNT));
|
||||
break;
|
||||
}
|
||||
s = GetReverseNext(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
++j;
|
||||
num_pnts = j;
|
||||
*removed = num_help - num_pnts;
|
||||
|
||||
/* */
|
||||
/* discard zero-length segs */
|
||||
/* */
|
||||
if (num_segs > 0) {
|
||||
i = 0;
|
||||
nn = num_segs;
|
||||
while ((i < num_segs) && (num_segs > 0)) {
|
||||
j = Get1stVtxSeg(i);
|
||||
assert(InPntsList(j));
|
||||
k = Get2ndVtxSeg(i);
|
||||
assert(InPntsList(k));
|
||||
if (j == k) {
|
||||
j = num_segs - 1;
|
||||
CopySegData(i, j);
|
||||
num_segs = j;
|
||||
}
|
||||
else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
if (discard_duplicate_sites && (num_segs > 0)) {
|
||||
/* */
|
||||
/* sort segs according to lexicographical order */
|
||||
/* */
|
||||
qsort(&(segs[0]), num_segs, sizeof(seg), s_comp);
|
||||
|
||||
/* */
|
||||
/* eliminate duplicate segs */
|
||||
/* */
|
||||
i = 0;
|
||||
for (j = 1; j < num_segs; ++j) {
|
||||
if (!s_equal(segs[i], segs[j])){
|
||||
++i;
|
||||
CopySegData(i, j);
|
||||
}
|
||||
}
|
||||
num_segs = i + 1;
|
||||
}
|
||||
|
||||
*removed_segs = nn - num_segs;
|
||||
}
|
||||
else {
|
||||
*removed_segs = 0;
|
||||
}
|
||||
|
||||
#ifdef GENUINE_ARCS
|
||||
/* */
|
||||
/* discard zero-length arcs */
|
||||
/* */
|
||||
if (num_arcs > 0) {
|
||||
i = 0;
|
||||
nn = num_arcs;
|
||||
while ((i < num_arcs) && (num_arcs > 0)) {
|
||||
j = Get1stVtxArc(i);
|
||||
assert(InPntsList(j));
|
||||
k = Get2ndVtxArc(i);
|
||||
assert(InPntsList(k));
|
||||
if (j == k) {
|
||||
j = num_arcs - 1;
|
||||
CopyArcData(i, j);
|
||||
num_arcs = j;
|
||||
}
|
||||
else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
if (discard_duplicate_sites && (num_arcs > 0)) {
|
||||
/* */
|
||||
/* sort arcs according to lexicographical order */
|
||||
/* */
|
||||
qsort(&(arcs[0]), num_arcs, sizeof(arc), a_comp);
|
||||
|
||||
/* */
|
||||
/* eliminate duplicate arcs */
|
||||
/* */
|
||||
i = 0;
|
||||
for (j = 1; j < num_arcs; ++j) {
|
||||
if (!a_equal(arcs[i], arcs[j])) {
|
||||
++i;
|
||||
CopyArcData(i, j);
|
||||
}
|
||||
}
|
||||
num_arcs = i + 1;
|
||||
}
|
||||
|
||||
*removed_arcs = nn - num_arcs;
|
||||
}
|
||||
else {
|
||||
*removed_arcs = 0;
|
||||
}
|
||||
#else
|
||||
*removed_arcs = 0;
|
||||
#endif
|
||||
|
||||
FreeReverseIndex();
|
||||
|
||||
#ifdef GRAPHICS
|
||||
/* */
|
||||
/* update the drawing buffer accordingly */
|
||||
/* */
|
||||
if (graphics) UpdateBuffer();
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void vroniObject::RepairPntLinks(int i_del, int i_old, vr_bool repair_now)
|
||||
{
|
||||
int isite, s, t, tsite;
|
||||
int curr_num_arcs;
|
||||
|
||||
if (i_old == i_del) return;
|
||||
if (data_sorted && !repair_now) {
|
||||
restart = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!reverse_index_exists) {
|
||||
curr_num_arcs = num_arcs;
|
||||
/* */
|
||||
/* make sure that every point knows all its incident segs and */
|
||||
/* arcs. */
|
||||
/* */
|
||||
SetUpReverseIndex(num_segs, curr_num_arcs, false);
|
||||
}
|
||||
|
||||
assert(reverse_index_exists);
|
||||
assert(InPntsList(i_del));
|
||||
assert(InPntsList(i_old));
|
||||
|
||||
/* */
|
||||
/* reset all links in segs[] and arcs[] that refer to pnts[i_del]. */
|
||||
/* */
|
||||
s = i_del;
|
||||
while (s != NIL) {
|
||||
tsite = GetReverseType(s);
|
||||
isite = GetReverseSite(s);
|
||||
switch(tsite) {
|
||||
case SEG_START:
|
||||
assert(InSegsList(isite));
|
||||
Set1stVtxSeg(isite, i_old);
|
||||
break;
|
||||
case SEG_END:
|
||||
assert(InSegsList(isite));
|
||||
Set2ndVtxSeg(isite, i_old);
|
||||
break;
|
||||
case ARC_START:
|
||||
assert(InArcsList(isite));
|
||||
Set1stVtxArc(isite, i_old);
|
||||
break;
|
||||
case ARC_END:
|
||||
assert(InArcsList(isite));
|
||||
Set2ndVtxArc(isite, i_old);
|
||||
break;
|
||||
default:
|
||||
assert((tsite == SEG_START) || (tsite == SEG_END) ||
|
||||
(tsite == ARC_START) || (tsite == ARC_END) ||
|
||||
(tsite == ISO_PNT));
|
||||
break;
|
||||
}
|
||||
s = GetReverseNext(s);
|
||||
}
|
||||
|
||||
s = i_old;
|
||||
while (s != NIL) {
|
||||
t = GetReverseNext(s);
|
||||
if (t == NIL) SetReverseNext(s, i_del);
|
||||
s = t;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
+957
@@ -0,0 +1,957 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) Martin Held 1999-2023 */
|
||||
/* */
|
||||
/* This code is provided at no charge to you for non-commercial purposes */
|
||||
/* only and only for use internal to your institution. You may use this */
|
||||
/* code for academic evaluation and applications, following standard */
|
||||
/* rules of academic conduct including crediting the author(s) and the */
|
||||
/* copyright holder in any publications. This code is not in the public */
|
||||
/* domain, and may not be duplicated, altered, sold or re-distributed */
|
||||
/* without obtaining the prior written consent of the copyright holder. */
|
||||
/* No part of this code may be used for or included in any commercial */
|
||||
/* application unless your institution obtains a commercial license. */
|
||||
/* Please contact the author, Martin Held (held@cs.sbg.ac.at), for */
|
||||
/* commercial licensing terms. */
|
||||
/* */
|
||||
/* 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. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* 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 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Please read the README.txt and README_data.txt files before compiling or */
|
||||
/* using this code! */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* get standard libraries */
|
||||
/* */
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <limits.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* */
|
||||
/* get my header files */
|
||||
/* */
|
||||
#include "fpkernel.h"
|
||||
#include "vronivector.h"
|
||||
#include "vroni_object.h"
|
||||
#include "defs.h"
|
||||
#include "random.h"
|
||||
#include "numerics.h"
|
||||
|
||||
|
||||
/*
|
||||
* please turn those define's only on if you know what you do! (they are
|
||||
* here only for my debugging purposes!!
|
||||
*
|
||||
#define TRACE_VD
|
||||
#define INIT_FORCED
|
||||
#define TRACE_INPUT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/* */
|
||||
/* this subroutine drives the computation of the voronoi diagram. the VD is */
|
||||
/* computed in an area whose width equals (2*bound+1) times the width of the */
|
||||
/* bounding box of the input data, and whose height equals (2*bound+1) times */
|
||||
/* the height of the bounding box of the input data. */
|
||||
/* */
|
||||
/* if ComputeVD() were to be called from a user's application program then */
|
||||
/* it is the responsibility of this application program to initialize all */
|
||||
/* arrays appropriately. see ReadPolygon(), ReadPoly() or ReadSites() in the */
|
||||
/* file io.c. It might be best to interface to this subroutine only via the */
|
||||
/* API-functions provided; see main(). */
|
||||
/* */
|
||||
void vroniObject::ComputeVD(vr_bool save_data, vr_bool new_input,
|
||||
int step_size, vr_bool time, int bound,
|
||||
int sample, int approx, char output_file[],
|
||||
vr_bool discard_duplicate_sites, int p_step_size,
|
||||
vr_bool *finished, int a_step_size,
|
||||
vr_bool pnts_only, vr_bool write_vd_dt,
|
||||
char vd_dt_file[],
|
||||
vr_bool left_vd, vr_bool right_vd,
|
||||
vr_bool clean_up)
|
||||
{
|
||||
#ifdef GRAPHICS
|
||||
int i;
|
||||
#endif
|
||||
|
||||
int j;
|
||||
#ifdef TRACE
|
||||
vr_bool trace_write_debug = false;
|
||||
#endif
|
||||
#ifdef TRACE_INPUT
|
||||
vr_bool trace_pnt = true, trace_seg = true, trace_arc = true;
|
||||
#endif
|
||||
#ifdef VRONI_INFO
|
||||
double eps;
|
||||
#endif
|
||||
|
||||
/* */
|
||||
/* make sure that the compile-time options selected by the user are */
|
||||
/* reasonable. */
|
||||
/* */
|
||||
#ifdef INVERSE
|
||||
#ifndef SORTED
|
||||
throw std::runtime_error("VRONI error: ComputeVD() - Inverse sorting requires -DSORTED and -DINVERSE!");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef RANDOM
|
||||
#ifdef SORTED
|
||||
throw std::runtime_error("VRONI error: ComputeVD() - Do not use -DRANDOM and -DSORTED together!");
|
||||
#else /* else if not SORTED */
|
||||
#ifdef ORDERED
|
||||
throw std::runtime_error("VRONI error: ComputeVD() - Do not use -DRANDOM and -DORDERED together!");
|
||||
#else /* else if not ORDERED */
|
||||
#ifdef FORCED
|
||||
throw std::runtime_error("VRONI error: ComputeVD() - Do not use -DRANDOM and -DFORCED together!");
|
||||
#endif /* endif FORCED */
|
||||
#endif /* endif ORDERED */
|
||||
#endif /* endif SORTED */
|
||||
#else /* else if not RANDOM */
|
||||
#ifdef SORTED
|
||||
#ifdef ORDERED
|
||||
throw std::runtime_error("VRONI error: ComputeVD() - Do not use -DSORTED and -DORDERED together!");
|
||||
#else /* else if not ORDERED */
|
||||
#ifdef FORCED
|
||||
throw std::runtime_error("VRONI error: ComputeVD() - Do not use -DSORTED and -DFORCED together!");
|
||||
#endif /* endif FORCED */
|
||||
#endif /* endif ORDERED */
|
||||
#else /* else if not SORTED */
|
||||
#ifdef ORDERED
|
||||
#ifdef FORCED
|
||||
throw std::runtime_error("VRONI error: ComputeVD() - Do not use -DORDERED and -DFORCED together!");
|
||||
#endif /* endif FORCED */
|
||||
#endif /* endif ORDERED */
|
||||
#endif /* endif SORTED */
|
||||
#endif /* endif RANDOM */
|
||||
#ifndef RANDOM
|
||||
#ifndef SORTED
|
||||
#ifndef ORDERED
|
||||
#ifndef FORCED
|
||||
VD_Warning("ComputeVD() - it is recommended to use -DRANDOM!");
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#ifdef INIT_FORCED
|
||||
#ifndef RANDOM
|
||||
VD_Warning("ComputeVD() - please use -INIT_FORCED only with -DRANDOM!");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* */
|
||||
/* actual start of code for inserting sites into a VD */
|
||||
/* */
|
||||
#ifdef GRAPHICS
|
||||
if (graphics) ResetCurBuffer(); /* only if OpenGL display is enabled */
|
||||
#else
|
||||
step_size = INT_MAX;
|
||||
p_step_size = INT_MAX;
|
||||
a_step_size = INT_MAX;
|
||||
left_vd = false;
|
||||
right_vd = false;
|
||||
#endif
|
||||
|
||||
/* */
|
||||
/* check whether there seems to be input data; note that every seg or arc */
|
||||
/* results in two pnts to handled! */
|
||||
/* */
|
||||
if (num_pnts <= 0) {
|
||||
VD_Warning("ComputeVD() - no sites!");
|
||||
*finished = true;
|
||||
initialized = false;
|
||||
return;
|
||||
}
|
||||
else {
|
||||
*finished = false;
|
||||
}
|
||||
|
||||
/* */
|
||||
/* branch depending on whether this call of ComputeVD() is for */
|
||||
/* - entirely new data, with no pre-existing VD and no appropriate */
|
||||
/* preprocessing done yet; */
|
||||
/* - for another round of insertions of sites into an already existing */
|
||||
/* VD, with preprocessing already done; */
|
||||
/* - a restart of the code on data that had already been subjected to */
|
||||
/* preprocessing once; this may happen if the input data suffers from */
|
||||
/* deficiencies such as self-intersections. */
|
||||
/* */
|
||||
if (restart) {
|
||||
if (vr_incr) {
|
||||
if (vr_file_handle != ((FILE*)NULL)) fclose(vr_file_handle);
|
||||
}
|
||||
restart = false;
|
||||
if (restart_due_to_intersection) {
|
||||
restart_due_to_intersection = false;
|
||||
restart_without_intersection = 0;
|
||||
++intersection_counter;
|
||||
}
|
||||
else {
|
||||
++restart_counter;
|
||||
++restart_without_intersection;
|
||||
}
|
||||
if (restart_without_intersection > MAX_RESTART) {
|
||||
throw std::runtime_error("VRONI error: ComputeVD() - aborting computation -- too many restarts!");
|
||||
}
|
||||
#ifdef VRONI_INFO
|
||||
else if (!quiet) {
|
||||
printf("warning in ComputeVD() - restart # %d of VD computation!\n",
|
||||
restart_counter + intersection_counter);
|
||||
}
|
||||
#endif
|
||||
ExtApplComputeRestarts;
|
||||
#ifdef GRAPHICS
|
||||
ResetBufferData();
|
||||
#endif
|
||||
ResetVDData();
|
||||
ResetVDConstructionData();
|
||||
ResetFlags();
|
||||
#ifdef VRONI_INFO
|
||||
InitRelaxationMemory(TINY);
|
||||
#endif
|
||||
|
||||
sample = 0;
|
||||
new_input = true;
|
||||
discard_duplicate_sites = true;
|
||||
|
||||
#ifdef INIT_FORCED
|
||||
fprintf(fcd_output, "\n");
|
||||
fclose(fcd_output);
|
||||
#endif
|
||||
|
||||
/* */
|
||||
/* let the user call some application-specific function */
|
||||
/* */
|
||||
ExtApplFuncRestart;
|
||||
}
|
||||
else if (new_input) {
|
||||
#ifdef VRONI_INFO
|
||||
InitRelaxationMemory(TINY);
|
||||
#endif
|
||||
removed_pnts = removed_segs = removed_arcs = 0;
|
||||
restart_counter = intersection_counter = 0;
|
||||
restart_without_intersection = 0;
|
||||
bbox_added = false;
|
||||
io_troubles = false;
|
||||
|
||||
cpu_time_pre = 0.0;
|
||||
cpu_time_pnt = 0.0;
|
||||
cpu_time_seg = 0.0;
|
||||
cpu_time_arc = 0.0;
|
||||
cpu_time_cln = 0.0;
|
||||
|
||||
/* */
|
||||
/* we reset the random number generator in order to guarantee that the */
|
||||
/* randomized incremental insertion will yield the same result when */
|
||||
/* applying it repeatedly to the same data set. */
|
||||
/* */
|
||||
InitRandom(vr_seed);
|
||||
|
||||
#ifdef INIT_FORCED
|
||||
/* the next three lines might cause troubles on your machine... */
|
||||
system("rm forced_order_pnts.txt");
|
||||
system("rm forced_order_segs.txt");
|
||||
system("rm forced_order_arcs.txt");
|
||||
#endif
|
||||
}
|
||||
else if (!initialized) {
|
||||
VD_Warning("ComputeVD() - no input!?");
|
||||
*finished = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (new_input) {
|
||||
/* */
|
||||
/* preprocessing phase of the VD algorithm */
|
||||
/* */
|
||||
VD_Info("...preprocessing -- ");
|
||||
|
||||
if (time) (void) elapsed();
|
||||
|
||||
num_pnts_deleted = 0;
|
||||
initialized = true;
|
||||
new_input = false;
|
||||
restart = false;
|
||||
troubles = false;
|
||||
desperate = false;
|
||||
numerical = false;
|
||||
written = false;
|
||||
done_pnts = false;
|
||||
done_segs = false;
|
||||
done_arcs = false;
|
||||
first_pnts = true;
|
||||
first_segs = true;
|
||||
#ifdef GENUINE_ARCS
|
||||
first_arcs = true;
|
||||
#endif
|
||||
incremental = false;
|
||||
|
||||
/* */
|
||||
/* compute the bounding box of the points pnts[0,...,num_pnts-1]. */
|
||||
/* */
|
||||
if (!bbox_initialized) SetBoundingBox();
|
||||
if ((num_arcs > 0) && bbox_initialized &&
|
||||
(!bbox_added || (num_critical_arcs > 0))) ExtendBoundingBox();
|
||||
|
||||
/* */
|
||||
/* scale the data if scaling is requested. */
|
||||
/* */
|
||||
if (bbox_initialized) {
|
||||
if (scale_data && !data_scaled) {
|
||||
ScaleData();
|
||||
#if defined(OGL_GRAPHICS)
|
||||
if (graphics && data_scaled) UpdateScaleData();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
/* enlarge the bounding box according to "bound" by adding four dummy */
|
||||
/* points. */
|
||||
/* */
|
||||
if (bbox_initialized && !bbox_added) AddDummyCorners(bound);
|
||||
|
||||
/* */
|
||||
/* if requested, replace the segs/arcs by a dense sample of points, */
|
||||
/* note that we also need to adjust the bounding box if arcs are */
|
||||
/* sampled. */
|
||||
/* */
|
||||
if ((sample > 0) && ((num_segs > 0) || (num_arcs > 0)))
|
||||
SampleData(sample);
|
||||
|
||||
/* */
|
||||
/* if requested, approximate the circular arcs. note that we also need */
|
||||
/* to adjust the bounding box. */
|
||||
/* */
|
||||
|
||||
if (pnts_only) {
|
||||
/* */
|
||||
/* we'll only compute the VD and DT of points. */
|
||||
/* */
|
||||
num_segs = 0;
|
||||
num_arcs = 0;
|
||||
isolated_pnts = true;
|
||||
}
|
||||
|
||||
#ifndef GENUINE_ARCS
|
||||
if (num_arcs > 0)
|
||||
throw std::runtime_error("VRONI error: ComputeVD() - genuine circular arcs not supported!\n");
|
||||
#endif
|
||||
|
||||
#ifdef OTHER
|
||||
if (cgal && (restart_counter == 0)) {
|
||||
VD_Info("...writing input data for CGAL's VD code --");
|
||||
WriteCgalSites("cgal_data.cin");
|
||||
VD_Info(" done.\n");
|
||||
printf("note that VRONI's CPU timing is incorrect due to this file I/O!\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
/* */
|
||||
/* sort the vertices in lexicographic order, discard duplicate */
|
||||
/* vertices, and remove zero-length segs/arcs. */
|
||||
/* */
|
||||
if (clean_up) discard_duplicate_sites = true;
|
||||
CleanData(&removed_pnts, &removed_segs, &removed_arcs,
|
||||
discard_duplicate_sites);
|
||||
pnts_deleted = false;
|
||||
|
||||
/* */
|
||||
/* preprocess the circular arcs */
|
||||
/* */
|
||||
SetPreprocessingThreshold(GetIntersectionThreshold());
|
||||
num_critical_arcs = 0;
|
||||
#ifdef GENUINE_ARCS
|
||||
if (num_arcs > 0) PreprocessArcs(&num_critical_arcs);
|
||||
#endif
|
||||
done_arcs = (num_arcs == 0);
|
||||
|
||||
/* */
|
||||
/* preprocess the line segments */
|
||||
/* */
|
||||
num_critical_segs = 0;
|
||||
if (num_segs > 0) PreprocessSegments(&num_critical_segs);
|
||||
if (restart) return;
|
||||
done_segs = (num_segs == 0);
|
||||
|
||||
/* */
|
||||
/* build a grid for speeding up the nearest-neighbor search */
|
||||
/* */
|
||||
BuildGrid();
|
||||
|
||||
if (vr_incr && pnts_only) vr_file_handle = OpenFileVD(vr_file, "w");
|
||||
|
||||
if (time) cpu_time_pre += elapsed();
|
||||
|
||||
/* */
|
||||
/* let the user call some application-specific function */
|
||||
/* */
|
||||
ExtApplFuncNewInput;
|
||||
|
||||
#ifndef NDEBUG
|
||||
CheckBoundingBox();
|
||||
#endif
|
||||
|
||||
#ifdef GRAPHICS
|
||||
if (graphics && (p_step_size < INT_MAX)) return;
|
||||
#endif
|
||||
|
||||
VD_Info("done!\n");
|
||||
}
|
||||
|
||||
if (!done_pnts) {
|
||||
/***********************************************************************/
|
||||
/* */
|
||||
/* compute the Voronoi diagram of the points/vertices. */
|
||||
/* */
|
||||
/***********************************************************************/
|
||||
if (first_pnts) {
|
||||
/* */
|
||||
/* pnt-specific preprocessing: compute the initial VD and */
|
||||
/* initialize the insertion order of the pnts */
|
||||
/* */
|
||||
VD_Info("...computing VD of points -- ");
|
||||
if (time) (void)elapsed();
|
||||
if ((num_segs == 0) && (num_arcs == 0)) pnts_only = true;
|
||||
first_pnts = false;
|
||||
ComputeInitialVD();
|
||||
InitSiteOrder(PNT);
|
||||
n_pnts = 3;
|
||||
max_n_pnts = num_pnts - 2;
|
||||
assert(max_n_pnts >= 3);
|
||||
#ifdef INIT_FORCED
|
||||
fcd_output = OpenFileVD("forced_order_pnts.txt", "a");
|
||||
fprintf(fcd_output, "restart: %d\n", restart_counter);
|
||||
#endif
|
||||
#ifdef TRACE_INPUT
|
||||
if (trace_pnt) {
|
||||
ClipWriteSiteData(2, PNT, "cwsd.site");
|
||||
// printf("2\n%20.16f %20.16f\n", pnts[2].p.x, pnts[2].p.y);
|
||||
}
|
||||
#endif
|
||||
#ifdef GRAPHICS
|
||||
draw_segs = false;
|
||||
draw_arcs = false;
|
||||
if (graphics) {
|
||||
if (p_step_size < INT_MAX) {
|
||||
draw_pnts = true;
|
||||
incremental = true;
|
||||
ResetVDBuffer();
|
||||
AddVDToBuffer(false, false);
|
||||
AddDelToBuffer();
|
||||
return;
|
||||
}
|
||||
if ((step_size < INT_MAX) || (a_step_size < INT_MAX)) {
|
||||
draw_pnts = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (vr_incr && pnts_only) {
|
||||
assert(vr_file_handle != ((FILE*)NULL));
|
||||
WriteVoronoiRegion(2, vr_file_handle);
|
||||
}
|
||||
|
||||
/* */
|
||||
/* let the user call some application-specific function */
|
||||
/* */
|
||||
ExtApplFuncFirstPnts;
|
||||
}
|
||||
|
||||
/* */
|
||||
/* insert the points pnts[3,...,num_pnts-3] into the VD according to */
|
||||
/* the insertion order selected. */
|
||||
/* recall that pnts[0,1,2,num_pnts-2,num_pnts-1] have been inserted */
|
||||
/* into the VD by ComputeInitialVD(). */
|
||||
/* */
|
||||
#ifdef GRAPHICS
|
||||
i = 0;
|
||||
while ((i < p_step_size) && (n_pnts < max_n_pnts)) {
|
||||
++i;
|
||||
#else
|
||||
while (n_pnts < max_n_pnts) {
|
||||
#endif
|
||||
j = GetNextSite();
|
||||
#ifdef INIT_FORCED
|
||||
fprintf(fcd_output, "%d\n", j);
|
||||
#endif
|
||||
#ifdef TRACE_INPUT
|
||||
if (trace_pnt) {
|
||||
ClipWriteSiteData(j, PNT, "cwsd.site");
|
||||
// printf("2\n%20.16f %20.16f\n", pnts[j].p.x, pnts[j].p.y);
|
||||
}
|
||||
#endif
|
||||
InsertPntIntoVD(j);
|
||||
if (restart) return;
|
||||
|
||||
/* */
|
||||
/* output the newly computed Voronoi region of pnts[j], if required */
|
||||
/* */
|
||||
if (vr_incr && pnts_only) {
|
||||
assert(vr_file_handle != ((FILE*)NULL));
|
||||
WriteVoronoiRegion(j, vr_file_handle);
|
||||
}
|
||||
|
||||
++n_pnts;
|
||||
}
|
||||
|
||||
if (n_pnts == max_n_pnts) {
|
||||
/* */
|
||||
/* all pnts have been inserted into the VD */
|
||||
/* */
|
||||
FreeGrid();
|
||||
FreeTree();
|
||||
FreeReverseIndex();
|
||||
|
||||
#ifdef INIT_FORCED
|
||||
fprintf(fcd_output, "\n");
|
||||
fclose(fcd_output);
|
||||
#endif
|
||||
#ifdef GRAPHICS
|
||||
if (graphics) {
|
||||
if (p_step_size == INT_MAX) ResetCurBuffer();
|
||||
ResetVDBuffer();
|
||||
if ((num_segs == 0) || (p_step_size < INT_MAX) ||
|
||||
(step_size < INT_MAX)) AddVDToBuffer(false, false);
|
||||
AddDelToBuffer();
|
||||
}
|
||||
#endif
|
||||
/* */
|
||||
/* if more than just the VD/DT of points is sought */
|
||||
/* */
|
||||
if (!done_segs || !done_arcs) {
|
||||
TakeSquareOfNodes();
|
||||
InsertDegreeTwoNodes();
|
||||
}
|
||||
done_pnts = true;
|
||||
|
||||
if (vr_incr && pnts_only) {
|
||||
assert(vr_file_handle != ((FILE*)NULL));
|
||||
fclose(vr_file_handle);
|
||||
}
|
||||
|
||||
if (time) cpu_time_pnt += elapsed();
|
||||
VD_Info("done!\n");
|
||||
#ifndef NDEBUG
|
||||
if (!CheckVD(false)) {
|
||||
VD_Warning("ComputeVD() - topological problem in point VD!");
|
||||
troubles = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* */
|
||||
/* let the user call some application-specific function */
|
||||
/* */
|
||||
ExtApplFuncDonePnts;
|
||||
|
||||
#ifdef GRAPHICS
|
||||
if (graphics &&
|
||||
((p_step_size < INT_MAX) || (step_size < INT_MAX)))
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
#ifdef GRAPHICS
|
||||
else if (graphics) {
|
||||
ResetVDBuffer();
|
||||
AddVDToBuffer(false, false);
|
||||
AddDelToBuffer();
|
||||
|
||||
#ifdef TRACE
|
||||
if (grid_used) DrawGrid();
|
||||
else DrawTree();
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (done_pnts && !done_segs) {
|
||||
/***********************************************************************/
|
||||
/* */
|
||||
/* insert the straight-line segments into the VD */
|
||||
/* */
|
||||
/***********************************************************************/
|
||||
if (first_segs) {
|
||||
/* */
|
||||
/* seg-specific preprocessing: initialize the insertion order of */
|
||||
/* the segs */
|
||||
/* */
|
||||
VD_Info("...computing VD of segments -- ");
|
||||
if (time) (void)elapsed();
|
||||
first_segs = false;
|
||||
InitSiteOrder(SEG);
|
||||
n_segs = 0;
|
||||
#ifdef INIT_FORCED
|
||||
fcd_output = OpenFileVD("forced_order_segs.txt", "a");
|
||||
fprintf(fcd_output, "restart: %d\n", restart_counter);
|
||||
#endif
|
||||
#ifdef GRAPHICS
|
||||
draw_segs = true;
|
||||
if (graphics && (step_size < INT_MAX))
|
||||
incremental = true;
|
||||
else
|
||||
incremental = false;
|
||||
#endif
|
||||
/* */
|
||||
/* let the user call some application-specific function */
|
||||
/* */
|
||||
ExtApplFuncFirstSegs;
|
||||
|
||||
/*if (restart_counter == 5) SetDebugFlagVD(true);*/
|
||||
}
|
||||
|
||||
/* */
|
||||
/* insert the segments segs[0,...,num_segs-1] into the VD in the */
|
||||
/* order selected. */
|
||||
/* */
|
||||
#ifdef GRAPHICS
|
||||
i = 0;
|
||||
while ((i < step_size) && (n_segs < num_segs)) {
|
||||
++i;
|
||||
#else
|
||||
while (n_segs < num_segs) {
|
||||
#endif
|
||||
#ifdef TRACE
|
||||
if (trace_write_debug) WriteProcessedSites("debug.site");
|
||||
#endif
|
||||
j = GetNextSite();
|
||||
#ifdef INIT_FORCED
|
||||
fprintf(fcd_output, "%d\n", j);
|
||||
#endif
|
||||
#ifdef TRACE_INPUT
|
||||
if (trace_seg) {
|
||||
//printf("0\n%20.16f %20.16f %20.16f %20.16f\n",
|
||||
// pnts[segs[j].i1].p.x, pnts[segs[j].i1].p.y,
|
||||
// pnts[segs[j].i2].p.x, pnts[segs[j].i2].p.y);
|
||||
ClipWriteSiteData(j, SEG, "cwsd.site");
|
||||
}
|
||||
#endif
|
||||
InsertSegIntoVD(j);
|
||||
|
||||
if (restart) {
|
||||
#ifdef TRACE_INPUT
|
||||
ClipWriteSiteData(j, UNKNOWN, "cwsd.site");
|
||||
#endif
|
||||
#ifdef TRACE_INPUT
|
||||
if (trace_seg) WriteSiteData(j, SEG, "restart\n");
|
||||
#ifdef GRAPHICS
|
||||
if (graphics) AddToCurBuffer(j, SEG, AlertColor);
|
||||
#endif
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
#ifdef VRONI_INFO
|
||||
ConfirmRelaxationMemory();
|
||||
#endif
|
||||
|
||||
++n_segs;
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (!CheckVD(false)) {
|
||||
fprintf(stderr, "CheckVD - topological problem in VD! ***\n");
|
||||
troubles = true;
|
||||
}
|
||||
#ifdef VRONI_INFO
|
||||
else {
|
||||
if (!quiet) printf("VD OK after %d segs\n", n_segs);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
if (n_segs == num_segs) {
|
||||
/* */
|
||||
/* all segs have been inserted into the VD */
|
||||
/* */
|
||||
done_segs = true;
|
||||
if (time) cpu_time_seg += elapsed();
|
||||
VD_Info("done!\n");
|
||||
#ifdef INIT_FORCED
|
||||
fprintf(fcd_output, "\n");
|
||||
fclose(fcd_output);
|
||||
#endif
|
||||
#ifndef NDEBUG
|
||||
if (!done_arcs) {
|
||||
if (!CheckVD(false)) {
|
||||
VD_Warning("ComputeVD() - topological problem in seg VD!");
|
||||
troubles = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* */
|
||||
/* let the user call some application-specific function */
|
||||
/* */
|
||||
ExtApplFuncDoneSegs;
|
||||
}
|
||||
|
||||
#ifdef GRAPHICS
|
||||
if (graphics && (step_size < INT_MAX)) {
|
||||
ResetVDBuffer();
|
||||
AddVDToBuffer(false, false);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef GENUINE_ARCS
|
||||
if (done_pnts && done_segs && !done_arcs) {
|
||||
|
||||
/***********************************************************************/
|
||||
/* */
|
||||
/* insert the circular arcs */
|
||||
/* */
|
||||
/***********************************************************************/
|
||||
if (first_arcs) {
|
||||
/* */
|
||||
/* arc-specific preprocessing: initialize the insertion order of */
|
||||
/* the arcs */
|
||||
/* */
|
||||
VD_Info("...computing VD of circular arcs -- ");
|
||||
if (time) (void)elapsed();
|
||||
first_arcs = false;
|
||||
ResetVDConstructionData();
|
||||
InitSiteOrder(ARC);
|
||||
n_arcs = 0;
|
||||
#ifdef INIT_FORCED
|
||||
fcd_output = OpenFileVD("forced_order_arcs.txt", "a");
|
||||
fprintf(fcd_output, "restart: %d\n", restart_counter);
|
||||
#endif
|
||||
#ifdef GRAPHICS
|
||||
draw_arcs = true;
|
||||
if (graphics && (a_step_size < INT_MAX))
|
||||
incremental = true;
|
||||
else
|
||||
incremental = false;
|
||||
#endif
|
||||
/* */
|
||||
/* let the user call some application-specific function */
|
||||
/* */
|
||||
ExtApplFuncFirstArcs;
|
||||
|
||||
#ifdef GRAPHICS
|
||||
if (graphics && (a_step_size < INT_MAX)) {
|
||||
ResetVDBuffer();
|
||||
AddVDToBuffer(false, false);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* */
|
||||
/* insert the circular arcs arcs[0,...,num_arcs-1] into the VD, */
|
||||
/* either in the order they were stored or in random order. */
|
||||
/* */
|
||||
#ifdef GRAPHICS
|
||||
i = 0;
|
||||
while ((i < a_step_size) && (n_arcs < num_arcs)) {
|
||||
++i;
|
||||
#else
|
||||
while (n_arcs < num_arcs) {
|
||||
#endif
|
||||
#ifdef TRACE
|
||||
if (trace_write_debug) WriteProcessedSites("debug.site");
|
||||
#endif
|
||||
j = GetNextSite();
|
||||
#ifdef INIT_FORCED
|
||||
fprintf(fcd_output, "%d\n", j);
|
||||
#endif
|
||||
#ifdef TRACE_INPUT
|
||||
if (trace_arc) {
|
||||
// printf("arc %d\n", j);
|
||||
// printf("1\n%20.16f %20.16f %20.16f %20.16f %20.16f %20.16f\n",
|
||||
// pnts[arcs[j].i1].p.x, pnts[arcs[j].i1].p.y,
|
||||
// pnts[arcs[j].i2].p.x, pnts[arcs[j].i2].p.y,
|
||||
// arcs[j].c.x, arcs[j].c.y);
|
||||
ClipWriteSiteData(j, ARC, "cwsd.site");
|
||||
}
|
||||
#endif
|
||||
InsertArcIntoVD(j);
|
||||
|
||||
if (restart) {
|
||||
#ifdef TRACE_INPUT
|
||||
ClipWriteSiteData(j, UNKNOWN, "cwsd.site");
|
||||
#endif
|
||||
#ifdef TRACE_INPUT
|
||||
if (trace_arc) WriteSiteData(j, ARC, "restart\n");
|
||||
#ifdef GRAPHICS
|
||||
if (graphics) AddToCurBuffer(j, ARC, AlertColor);
|
||||
#endif
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
#ifdef VRONI_INFO
|
||||
ConfirmRelaxationMemory();
|
||||
#endif
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (!CheckVD(false)) {
|
||||
VD_Warning("CheckVD - topological problem in VD");
|
||||
troubles = true;
|
||||
}
|
||||
#ifdef VRONI_INFO
|
||||
else {
|
||||
if (!quiet) printf("VD OK after %d arcs\n", n_arcs + 1);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
++n_arcs;
|
||||
}
|
||||
|
||||
if (n_arcs == num_arcs) {
|
||||
/* */
|
||||
/* all arcs have been inserted into the VD */
|
||||
/* */
|
||||
done_arcs = true;
|
||||
if (time) cpu_time_arc += elapsed();
|
||||
VD_Info("done!\n");
|
||||
|
||||
/* */
|
||||
/* let the user call some application-specific function */
|
||||
/* */
|
||||
ExtApplFuncDoneArcs;
|
||||
|
||||
#ifdef INIT_FORCED
|
||||
fprintf(fcd_output, "\n");
|
||||
fclose(fcd_output);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef GRAPHICS
|
||||
if (graphics && (a_step_size < INT_MAX)) {
|
||||
ResetVDBuffer();
|
||||
AddVDToBuffer(false, false);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
if (!done_arcs) {
|
||||
throw std::runtime_error("VRONI error: ComputeVD() - circular arcs cannot be handled without approximation!");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (done_pnts && done_segs && done_arcs) {
|
||||
|
||||
if (desperate && (restart_counter < MAX_RESTART)) {
|
||||
restart = true;
|
||||
return;
|
||||
}
|
||||
|
||||
/* */
|
||||
/* do we have isolated points? */
|
||||
/* */
|
||||
if ((num_segs > 0) || (num_arcs > 0)) {
|
||||
if (!GetDataSorted()) {
|
||||
CheckIsolatedPnts();
|
||||
}
|
||||
}
|
||||
else {
|
||||
isolated_pnts = true;
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (!CheckVD(false)) {
|
||||
VD_Warning("ComputeVD() - topological problem(s) in VD!");
|
||||
}
|
||||
else {
|
||||
VD_Info("\nComputeVD() - VD is topologically correct!");
|
||||
}
|
||||
#endif
|
||||
|
||||
SetVDStatusTrue();
|
||||
|
||||
#ifdef GRAPHICS
|
||||
if (graphics && ((num_segs > 0) || (num_arcs > 0))) {
|
||||
draw_pnts = false;
|
||||
incremental = false;
|
||||
ResetVDBuffer();
|
||||
if (step_size == INT_MAX) ResetCurBuffer();
|
||||
AddVDToBuffer(left_vd, right_vd);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* */
|
||||
/* let the user call some application-specific function */
|
||||
/* */
|
||||
ExtApplFuncDoneVD;
|
||||
|
||||
if (!written) {
|
||||
if (save_data) {
|
||||
VD_Info("\n...writing the output data -- ");
|
||||
WriteSites(output_file);
|
||||
written = true;
|
||||
VD_Info("done!\n");
|
||||
}
|
||||
if (pnts_only && write_vd_dt) {
|
||||
VD_Info("\n...writing VD/DT data -- ");
|
||||
WriteVDDT(vd_dt_file);
|
||||
VD_Info("done!\n");
|
||||
}
|
||||
written = true;
|
||||
}
|
||||
|
||||
#ifdef VRONI_INFO
|
||||
if (!quiet) {
|
||||
if (IsCheckComplete() || (intersection_counter > 0)) {
|
||||
eps = GetIntersectionThreshold();
|
||||
if (IsCheckComplete()) eps /= 10.0;
|
||||
}
|
||||
else {
|
||||
eps = 0.0;
|
||||
}
|
||||
printf("\nComputeVD() - intersection threshold used: %2.1e\n", eps);
|
||||
#ifdef VRONI_DBG_WARN
|
||||
printf("ComputeVD() - maximum relaxation used: %2.1e\n",
|
||||
ReportRelaxationMemory());
|
||||
#endif
|
||||
if ((restart_counter + intersection_counter) > 0) {
|
||||
printf("\nComputeVD() - problems with the input data caused %d restart(s)!",
|
||||
restart_counter + intersection_counter);
|
||||
}
|
||||
else if (io_troubles) {
|
||||
VD_Warning("ComputeVD() - problems with input data occurred!");
|
||||
}
|
||||
if (desperate) {
|
||||
VD_Warning("ComputeVD() - VD computed; desperate mode was used!");
|
||||
}
|
||||
else if (troubles) {
|
||||
VD_Warning("ComputeVD() - VD computed; problems occurred!?");
|
||||
}
|
||||
else if (numerical) {
|
||||
VD_Warning("ComputeVD() - VD computed; numerical instabilities!?");
|
||||
}
|
||||
else {
|
||||
VD_Info("\nComputeVD() - VD computed successfully!\n");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
*finished = true;
|
||||
initialized = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 2010-2023 M. Held, S. Huber */
|
||||
/* */
|
||||
/* 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: Stefan Huber, 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 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef VRONI_CONSTS_H
|
||||
#define VRONI_CONSTS_H
|
||||
|
||||
|
||||
|
||||
#ifndef DOUBLE_OVERRIDE
|
||||
/* */
|
||||
/* please do not change the following tolerance thresholds */
|
||||
/* */
|
||||
#define TINY 1.0e-14 /* about the size of the machine precision */
|
||||
#define SMALL 0.0078125 /* 0.01 >= SMALL = 1/128 >> ZERO */
|
||||
#define INVERSE_SMALL 128.0 /* INVERSE_SMALL = 1/SMALL */
|
||||
/* */
|
||||
/* the following tolerance thresholds may be changed if you know what you do */
|
||||
/* */
|
||||
#define ZERO 1.0e-13 /* small number with ZERO >= TINY */
|
||||
#define ZERO_MAX 1.0e-5 /* SMALL >> ZERO_MAX >= ZERO */
|
||||
#define ZERO_IO 1.0e-5 /* SMALL >> ZERO_IO >= ZERO_MAX */
|
||||
#define DECENT 1.0e-10 /* = ZERO_MAX / 1000 */
|
||||
#define GRAZE 1.0e-4 /* = ZERO_MAX * 10 */
|
||||
/* */
|
||||
/* the following thresholds depend on thresholds defined in previous lines */
|
||||
/* */
|
||||
#define THRESHOLD 1.0e-6 /* THRESHOLD = ZERO_MAX / 10.0 */
|
||||
#define ZERO2 1.0e-26 /* ZERO2 = ZERO * ZERO */
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#define NIL -1
|
||||
#define APPROX 10
|
||||
#define MAX_RESTART 50 /* max. number of retries if computation fails */
|
||||
|
||||
#ifdef WITH_MPFRBACKEND
|
||||
|
||||
extern double SMALL;
|
||||
extern double INVERSE_SMALL;
|
||||
extern double ZERO_IO;
|
||||
extern double ZERO_MAX;
|
||||
extern double ZERO;
|
||||
extern double ZERO2;
|
||||
extern double THRESHOLD;
|
||||
extern double TINY;
|
||||
|
||||
#elif defined(WITH_COREBACKEND)
|
||||
|
||||
const double SMALL = 0;
|
||||
/* INVERSE_SMALL is not used anyway of SMALL == 0, so keep value from
|
||||
plain value. */
|
||||
const double INVERSE_SMALL = 128;
|
||||
const double ZERO_IO = 1.0e-6;
|
||||
const double ZERO_MAX = 0;
|
||||
const double ZERO = 0;
|
||||
const double ZERO2 = 0;
|
||||
const double THRESHOLD = 0;
|
||||
const double TINY = 0;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifndef DOUBLE_OVERRIDE
|
||||
|
||||
|
||||
#ifndef M_E
|
||||
#define M_E 2.71828182845904553488
|
||||
#endif
|
||||
#ifndef M_1_E
|
||||
#define M_1_E 0.36787944117144227851
|
||||
#endif
|
||||
#ifndef M_LOG2E
|
||||
#define M_LOG2E 1.44269504088896360904
|
||||
#endif
|
||||
#ifndef M_LOG10E
|
||||
#define M_LOG10E 0.43429448190325182765
|
||||
#endif
|
||||
#ifndef M_LN2
|
||||
#define M_LN2 0.69314718055994530942
|
||||
#endif
|
||||
#ifndef M_LN10
|
||||
#define M_LN10 2.30258509299404568402
|
||||
#endif
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
#ifndef M_PI_2
|
||||
#define M_PI_2 1.57079632679489661923
|
||||
#endif
|
||||
#ifndef M_PI_4
|
||||
#define M_PI_4 0.78539816339744830962
|
||||
#endif
|
||||
#ifndef M_PI_8
|
||||
#define M_PI_8 0.39269908169872415481
|
||||
#endif
|
||||
#ifndef M_1_PI
|
||||
#define M_1_PI 0.31830988618379067154
|
||||
#endif
|
||||
#ifndef M_2_PI
|
||||
#define M_2_PI 0.63661977236758134308
|
||||
#endif
|
||||
#ifndef M_2PI
|
||||
#define M_2PI 6.28318530717958623199
|
||||
#endif
|
||||
#ifndef M_180_PI
|
||||
#define M_180_PI 57.2957795130823208767
|
||||
#endif
|
||||
#ifndef M_PI_180
|
||||
#define M_PI_180 0.01745329251994329576
|
||||
#endif
|
||||
#ifndef M_2_SQRTPI
|
||||
#define M_2_SQRTPI 1.12837916709551257390
|
||||
#endif
|
||||
#ifndef M_SQRT2
|
||||
#define M_SQRT2 1.41421356237309504880
|
||||
#endif
|
||||
#ifndef M_SQRT1_2
|
||||
#define M_SQRT1_2 0.70710678118654752440
|
||||
#endif
|
||||
#ifndef M_SQRT3
|
||||
#define M_SQRT3 1.73205080756887719317
|
||||
#endif
|
||||
#ifndef M_SQRT1_3
|
||||
#define M_SQRT1_3 0.57735026918962584208
|
||||
#endif
|
||||
#ifndef M_1_3
|
||||
#define M_1_3 0.33333333333333333333
|
||||
#endif
|
||||
|
||||
#elif defined(WITH_MPFRBACKEND)
|
||||
|
||||
extern double M_1_3;
|
||||
extern double M_180_PI;
|
||||
extern double M_PI_180;
|
||||
#undef M_SQRT2
|
||||
extern double M_SQRT2;
|
||||
#undef M_PI_4
|
||||
extern double M_PI_4;
|
||||
#undef M_PI_2
|
||||
extern double M_PI_2;
|
||||
#undef M_PI
|
||||
extern double M_PI;
|
||||
#undef M_2PI
|
||||
extern double M_2PI;
|
||||
|
||||
#else
|
||||
//defined(WITH_COREBACKEND)
|
||||
|
||||
const double M_1_3 = double(1) / 3;
|
||||
#undef M_SQRT2
|
||||
const double M_SQRT2 = sqrt(double(2));
|
||||
#undef M_PI
|
||||
const double M_PI = pi();
|
||||
#undef M_PI_4
|
||||
const double M_PI_4 = M_PI / 4;
|
||||
#undef M_PI_2
|
||||
const double M_PI_2 = M_PI / 2;;
|
||||
#undef M_2PI
|
||||
const double M_2PI = M_PI * 2;
|
||||
const double M_180_PI = 180 / M_PI;
|
||||
const double M_PI_180 = M_PI * 180;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,31 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 2010-2023 M. Held, S. Huber */
|
||||
/* */
|
||||
/* 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.c". */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Written by: Stefan Huber */
|
||||
/* Modified: 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 my header files */
|
||||
/* */
|
||||
#include "fpkernel.h"
|
||||
|
||||
#include "coord.h"
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 2010-2023 M. Held, S. Huber */
|
||||
/* */
|
||||
/* 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: Stefan Huber */
|
||||
/* Modified: 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 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
#ifndef VRONI_COORD_H
|
||||
#define VRONI_COORD_H
|
||||
|
||||
|
||||
#ifndef DOUBLE_OVERRIDE
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
#include "fpkernel.h"
|
||||
|
||||
/** Defines a vector in the plane */
|
||||
struct coord {
|
||||
double x;
|
||||
double y;
|
||||
inline coord(double_arg x, double_arg y) : x(x), y(y) {}
|
||||
//Ensure construction doesn't implicitly initialize elements - done explicitly later anyway
|
||||
inline coord() {}
|
||||
};
|
||||
|
||||
struct coord3D {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
inline coord3D(double_arg x, double_arg y, double_arg z) : x(x), y(y), z(z) {}
|
||||
//Ensure construction doesn't implicitly initialize elements - done explicitly later anyway
|
||||
inline coord3D() {}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/** Computes determinant of 3x3 matrix given by homogeneous coordinates
|
||||
* of the three column vectors u, v and w. */
|
||||
inline static double VecDet(coord u, coord v, coord w)
|
||||
{
|
||||
return (((u).x - (v).x) * ((v).y - (w).y) + ((v).y - (u).y) * ((v).x - (w).x));
|
||||
}
|
||||
|
||||
|
||||
/** Computes standard inner-product of vectors u and v */
|
||||
inline static double VecDotProd(coord u, coord v)
|
||||
{
|
||||
return (((u).x * (v).x) + ((u).y * (v).y));
|
||||
}
|
||||
|
||||
|
||||
/** Adds two vectors */
|
||||
inline static coord VecAdd(coord p, coord q)
|
||||
{
|
||||
coord r;
|
||||
r.x = p.x + q.x;
|
||||
r.y = p.y + q.y;
|
||||
return r;
|
||||
}
|
||||
|
||||
/** Subtracs two vectors */
|
||||
inline static coord VecSub(coord p, coord q)
|
||||
{
|
||||
coord r;
|
||||
r.x = p.x - q.x;
|
||||
r.y = p.y - q.y;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/** Multiply vector with scalar */
|
||||
inline static coord VecMult(double_arg scalar, const coord & u)
|
||||
{
|
||||
coord r;
|
||||
r.x = scalar * u.x;
|
||||
r.y = scalar * u.y;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
/** Divide vector by scalar */
|
||||
inline static coord VecDiv(double_arg scalar, const coord & u)
|
||||
{
|
||||
return VecMult(1.0/scalar, u);
|
||||
}
|
||||
|
||||
|
||||
/** Get vector -p of p */
|
||||
inline static coord VecInv(coord p)
|
||||
{
|
||||
coord q;
|
||||
q.x = -p.x;
|
||||
q.y = -p.y;
|
||||
return q;
|
||||
}
|
||||
|
||||
|
||||
/** Squared vector length */
|
||||
inline static double VecLenSq(coord p)
|
||||
{
|
||||
return (p.x*p.x + p.y*p.y);
|
||||
}
|
||||
|
||||
|
||||
/** Vector length */
|
||||
inline static double VecLen(coord p)
|
||||
{
|
||||
return sqrt(VecLenSq(p));
|
||||
}
|
||||
|
||||
/** Normalize vector */
|
||||
inline static coord VecNorm(coord p)
|
||||
{
|
||||
return VecDiv(VecLen(p), p);
|
||||
}
|
||||
|
||||
|
||||
/** Get counter clock-wise 90 degree rotation */
|
||||
inline static coord VecCCW(coord p)
|
||||
{
|
||||
coord q;
|
||||
q.x = -p.y;
|
||||
q.y = p.x;
|
||||
return q;
|
||||
}
|
||||
|
||||
|
||||
/** Get clock-wise 90 degree rotation */
|
||||
inline static coord VecCW(coord p)
|
||||
{
|
||||
coord q;
|
||||
q.x = p.y;
|
||||
q.y = -p.x;
|
||||
return q;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Make vector by its coordinates */
|
||||
inline static coord MakeVec(double_arg x, double_arg y)
|
||||
{
|
||||
coord p;
|
||||
p.x = x;
|
||||
p.y = y;
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
/* */
|
||||
/* Copyright (C) 1999-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 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef VRONI_CORE_ATAN2_H
|
||||
#define VRONI_CPRE_ATAN2_H
|
||||
|
||||
|
||||
inline double atan2local(const double &y, const double &x)
|
||||
{
|
||||
if( fabs(x) >= fabs(y) )
|
||||
{
|
||||
// Sector to the right
|
||||
if( x > 0 )
|
||||
{
|
||||
const double phi = y/x;
|
||||
return atan(phi);
|
||||
}
|
||||
// Sector to the left
|
||||
else if( x < 0 )
|
||||
{
|
||||
const double phi = y/x;
|
||||
if( y >= 0) {
|
||||
return atan(phi) + M_PI;
|
||||
} else {
|
||||
return atan(phi) - M_PI;
|
||||
}
|
||||
}
|
||||
// Hence, x and y are zero
|
||||
else
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
else if( fabs(y) >= fabs(x) )
|
||||
{
|
||||
// Sector to the top
|
||||
if( y > 0 )
|
||||
{
|
||||
const double phi = x/y;
|
||||
return M_PI_2 - atan(phi);
|
||||
}
|
||||
// Sector to the bottom
|
||||
if( y < 0 )
|
||||
{
|
||||
const double phi = x/y;
|
||||
return - M_PI_2 - atan(phi);
|
||||
}
|
||||
// Actually, the impossible case, x=y=0. Should be catched above.
|
||||
else
|
||||
{
|
||||
assert(false);
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
}
|
||||
// This can only happen, if x or y is NaN.
|
||||
else
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
+1970
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,70 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 1999-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 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef VRONI_DEFS_H
|
||||
#define VRONI_DEFS_H
|
||||
|
||||
#define PROG_NAME "V R O N I"
|
||||
#define PROG_VERSION "7.6"
|
||||
#define PROG_YEAR "1999-2023"
|
||||
|
||||
/* */
|
||||
/* get the definitions for "exterior applications" */
|
||||
/* */
|
||||
#include "ext_appl_defs.h"
|
||||
|
||||
/* */
|
||||
/* colors for OpenGL drawing */
|
||||
/* */
|
||||
#define Brown 0
|
||||
#define Green 1
|
||||
#define Blue 2
|
||||
#define White 3
|
||||
#define Red 4
|
||||
#define Cyan 5
|
||||
#define Yellow 6
|
||||
#define Orange 7
|
||||
#define Magenta 8
|
||||
#define Black 9
|
||||
#define NumColors 10
|
||||
|
||||
|
||||
#define NoColor Black
|
||||
#define SupColor White
|
||||
#define PntColor Green
|
||||
#define SegColor Green
|
||||
#define ArcColor Cyan
|
||||
#define CirColor Yellow
|
||||
#define AlertColor Red
|
||||
#define CurrColor Blue
|
||||
#define MICColor Yellow
|
||||
#define VDColor Red
|
||||
#define GridColor Brown
|
||||
#define TreeColor Brown
|
||||
#define VDCurrColor Magenta
|
||||
#define DTCurrColor Orange
|
||||
#define SiteCurrColor Blue
|
||||
#define DTColor White
|
||||
#define OffColor White
|
||||
#define WMATColor Blue
|
||||
|
||||
#endif
|
||||
+816
@@ -0,0 +1,816 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 1999-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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
|
||||
/* */
|
||||
/* get my header files */
|
||||
/* */
|
||||
#include "fpkernel.h"
|
||||
#include "vroni_object.h"
|
||||
#include "roots.h"
|
||||
#include "numerics.h"
|
||||
#include "geom.h"
|
||||
|
||||
|
||||
#define SAMPLE 100
|
||||
|
||||
vr_bool vroniObject::DesperatePntPntPntCntr(const coord & A, const coord & B,
|
||||
const coord & C,
|
||||
coord *cntr, double *r2)
|
||||
{
|
||||
int i, j = NIL;
|
||||
coord AB, BC, CA;
|
||||
coord u, v, w, p, dir, mid;
|
||||
double ab, bc, ca;
|
||||
double s = 0.0, t_min, t_max, delta;
|
||||
double t[SAMPLE+1];
|
||||
double dist, new_dist = LARGE, old_dist = LARGE;
|
||||
|
||||
AB = VecSub(B, A);
|
||||
ab = VecLen(AB);
|
||||
assert(ab >= 0.0);
|
||||
BC = VecSub(C, B);
|
||||
bc = VecLen(BC);
|
||||
assert(bc >= 0.0);
|
||||
CA = VecSub(A, C);
|
||||
ca = VecLen(CA);
|
||||
assert(ca >= 0.0);
|
||||
|
||||
if (ab <= ca) {
|
||||
if (ca <= bc) {
|
||||
/* ab, ca <= bc */
|
||||
u = B;
|
||||
v = C;
|
||||
w = A;
|
||||
dir = VecDiv(bc, BC);
|
||||
}
|
||||
else {
|
||||
/* ab, bc <= ca */
|
||||
u = A;
|
||||
v = C;
|
||||
w = B;
|
||||
dir = VecDiv(ca, CA);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (ab <= bc) {
|
||||
/* ab, ca <= bc */
|
||||
u = B;
|
||||
v = C;
|
||||
w = A;
|
||||
dir = VecDiv(bc, BC);
|
||||
}
|
||||
else {
|
||||
/* ca, bc <= ab */
|
||||
u = A;
|
||||
v = B;
|
||||
w = C;
|
||||
dir = VecDiv(ab, AB);
|
||||
}
|
||||
}
|
||||
dir = VecCCW(dir);
|
||||
|
||||
mid = MidPoint(u, v);
|
||||
t_min = - too_large;
|
||||
t_max = too_large;
|
||||
|
||||
#ifdef VRONI_DBG_WARNINGS
|
||||
printf("DesperatePntPntPntCntr:\n");
|
||||
printf("t_min = %20.16f\n", t_min);
|
||||
printf("t_max = %20.16f\n", t_max);
|
||||
printf("A = (%20.16f, %20.16f)\n", A.x, A.y);
|
||||
printf("B = (%20.16f, %20.16f)\n", B.x, B.y);
|
||||
printf("C = (%20.16f, %20.16f)\n", C.x, C.y);
|
||||
printf("dir = (%20.16f, %20.16f)\n", dir.x, dir.y);
|
||||
printf("mid = (%20.16f, %20.16f)\n", mid.x, mid.y);
|
||||
#endif
|
||||
|
||||
do {
|
||||
old_dist = new_dist;
|
||||
delta = (t_max - t_min) / SAMPLE;
|
||||
t[0] = t_min;
|
||||
t[SAMPLE] = t_max;
|
||||
for (i = 1; i < SAMPLE; ++i) t[i] = t_min + i * delta;
|
||||
|
||||
for (i = 0; i <= SAMPLE; ++i) {
|
||||
p.x = mid.x + t[i] * dir.x;
|
||||
p.y = mid.y + t[i] * dir.y;
|
||||
dist = PntPntDist(u, p) - PntPntDist(w, p);
|
||||
if (dist < 0.0) dist = -dist;
|
||||
if (dist < new_dist) {
|
||||
new_dist = dist;
|
||||
j = i;
|
||||
s = t[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (new_dist < old_dist) {
|
||||
if (j == 0) {
|
||||
t_min = t[0];
|
||||
t_max = t[2];
|
||||
}
|
||||
else if (j == SAMPLE) {
|
||||
t_min = t[SAMPLE-2];
|
||||
t_max = t[SAMPLE];
|
||||
}
|
||||
else {
|
||||
t_min = t[j-1];
|
||||
t_max = t[j+1];
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef VRONI_DBG_WARNINGS
|
||||
printf("t_min = %20.16f\n", t_min);
|
||||
printf("t_max = %20.16f\n", t_max);
|
||||
printf("s = %20.16f\n", s);
|
||||
printf("dist = %20.16f\n", new_dist);
|
||||
#endif
|
||||
} while (new_dist < old_dist);
|
||||
|
||||
p.x = mid.x + s * dir.x;
|
||||
p.y = mid.y + s * dir.y;
|
||||
*r2 = (PntPntDist(u, p) + PntPntDist(v, p) + PntPntDist(w, p)) / 3.0;
|
||||
*cntr = p;
|
||||
|
||||
#ifdef VRONI_DBG_WARNINGS
|
||||
printf("cntr = (%20.16f, %20.16f)\n", cntr->x, cntr->y);
|
||||
printf("rad = %20.16f\n", *r2);
|
||||
#endif
|
||||
|
||||
*r2 = *r2 * *r2;
|
||||
|
||||
return (j != NIL);
|
||||
}
|
||||
|
||||
|
||||
vr_bool vroniObject::NumericalPntPntPntCntr(const coord & A, const coord & B,
|
||||
const coord & C,
|
||||
coord *cntr, double *r2)
|
||||
{
|
||||
double alpha, beta, gamma, delta, t;
|
||||
coord AB, BC, CA, P, Q, U, V;
|
||||
double aaa[2][2], bbb[2], xy[2];
|
||||
int I0, I1, J0, J1, exists;
|
||||
double ab, bc, ca;
|
||||
vr_bool success;
|
||||
|
||||
/* */
|
||||
/* check whether two points are nearly identical. we return a circle */
|
||||
/* whose diameter is given by those points which do not coincide. */
|
||||
/* */
|
||||
AB = VecSub(B, A);
|
||||
ab = VecLen(AB);
|
||||
assert(ab >= 0.0);
|
||||
if (le(ab, ZERO_MAX)) {
|
||||
AB = MidPoint(A, B);
|
||||
*cntr = MidPoint(AB, C);
|
||||
*r2 = PntPntDist(AB, C) / 2.0;
|
||||
return true;
|
||||
}
|
||||
BC = VecSub(C, B);
|
||||
bc = VecLen(BC);
|
||||
assert(bc >= 0.0);
|
||||
if (le(bc, ZERO)) {
|
||||
BC = MidPoint(B, C);
|
||||
*cntr = MidPoint(BC, A);
|
||||
*r2 = PntPntDist(BC, A) / 2.0;
|
||||
return true;
|
||||
}
|
||||
CA = VecSub(A, C);
|
||||
ca = VecLen(CA);
|
||||
assert(ca >= 0.0);
|
||||
if (le(ca, ZERO)) {
|
||||
CA = MidPoint(C, A);
|
||||
*cntr = MidPoint(CA, B);
|
||||
*r2 = PntPntDist(CA, B) / 2.0;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* */
|
||||
/* normalize the vectors */
|
||||
/* */
|
||||
AB = VecDiv(ab, AB);
|
||||
BC = VecDiv(bc, BC);
|
||||
CA = VecDiv(ca, CA);
|
||||
|
||||
/* */
|
||||
/* find those two vectors that are the least parallel. */
|
||||
/* */
|
||||
alpha = VecDotProd(AB, BC);
|
||||
alpha = Abs(alpha);
|
||||
beta = VecDotProd(BC, CA);
|
||||
beta = Abs(beta);
|
||||
gamma = VecDotProd(CA, AB);
|
||||
gamma = Abs(gamma);
|
||||
delta = Min3(alpha, beta, gamma);
|
||||
|
||||
/* */
|
||||
/* assume that the angle between AB and AC is closest to a right */
|
||||
/* angle. if ab > ca then we construct the line perpendicular to AB */
|
||||
/* through the midpoint of A,B and intersect it with the corresponding */
|
||||
/* line w.r.t. A,C. the point of intersection will be expressed in */
|
||||
/* terms of the line perpendicular to AB. similar for the other cases. */
|
||||
/* */
|
||||
if (delta == gamma) {
|
||||
P = MidPoint(A, B);
|
||||
Q = VecCCW(AB);
|
||||
U = MidPoint(A, C);
|
||||
V = VecCCW(CA);
|
||||
if (ab < ca) {
|
||||
LineLineIntersection(aaa, bbb, xy, I0, J0, I1, J1, P, Q, U, V, *cntr,
|
||||
exists);
|
||||
}
|
||||
else {
|
||||
LineLineIntersection(aaa, bbb, xy, I0, J0, I1, J1, U, V, P, Q, *cntr,
|
||||
exists);
|
||||
}
|
||||
}
|
||||
else if (delta == alpha) {
|
||||
P = MidPoint(A, B);
|
||||
Q = VecCCW(AB);
|
||||
U = MidPoint(B, C);
|
||||
V = VecCCW(BC);
|
||||
if (ab < bc) {
|
||||
LineLineIntersection(aaa, bbb, xy, I0, J0, I1, J1, P, Q, U, V, *cntr,
|
||||
exists);
|
||||
}
|
||||
else {
|
||||
LineLineIntersection(aaa, bbb, xy, I0, J0, I1, J1, U, V, P, Q, *cntr,
|
||||
exists);
|
||||
}
|
||||
}
|
||||
else {
|
||||
P = MidPoint(C, A);
|
||||
Q = VecCCW(CA);
|
||||
U = MidPoint(B, C);
|
||||
V = VecCCW(BC);
|
||||
if (ca < bc) {
|
||||
LineLineIntersection(aaa, bbb, xy, I0, J0, I1, J1, P, Q, U, V, *cntr,
|
||||
exists);
|
||||
}
|
||||
else {
|
||||
LineLineIntersection(aaa, bbb, xy, I0, J0, I1, J1, U, V, P, Q, *cntr,
|
||||
exists);
|
||||
}
|
||||
}
|
||||
|
||||
if (exists == 1) {
|
||||
*r2 = PntPntDist(A, *cntr);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
/* */
|
||||
/* we'll try to find a center using an alternative approach: we find */
|
||||
/* a parameter t such that cntr = P + t * Q. thus, we require */
|
||||
/* d(A, cntr) = d(C, cntr). */
|
||||
/* */
|
||||
P = MidPoint(A, B);
|
||||
Q = VecCCW(AB); /* note: Q is a unit vector! */
|
||||
V = VecSub(P, C);
|
||||
delta = VecDotProd(Q, V) * 2.0;
|
||||
|
||||
if (ne(delta, ZERO)) {
|
||||
ab = ab * ab / 4.0;
|
||||
t = (ab - VecLenSq(V)) / delta;
|
||||
*cntr = RayPnt(P, Q, t);
|
||||
*r2 = ab + t * t;
|
||||
*r2 = sqrt(*r2);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
success = DesperatePntPntPntCntr(A, B, C, cntr, r2);
|
||||
if (success) *r2 = sqrt(*r2);
|
||||
return success;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define NS 10
|
||||
|
||||
void vroniObject::DesperateComputeCenter(int e, int i, t_site ti,
|
||||
coord *w, double *r2)
|
||||
{
|
||||
int n, j, k, num_samples[3];
|
||||
int i_sites[3], min_ind[3], new_min, new_max;
|
||||
t_site s_types[3];
|
||||
coord p, u, v, cntr;
|
||||
coord samples[3][NS+1];
|
||||
coord start[3], end[3];
|
||||
double t, angle_s, angle_e, angle, du, dv, radius;
|
||||
double dist, dist1, dist2, dist3, dist_diff = LARGE, old_diff;
|
||||
#ifdef VR_TRACE
|
||||
int counter = 1;
|
||||
#endif
|
||||
|
||||
#ifdef VR_TRACE
|
||||
#endif
|
||||
#ifdef VR_TRACE
|
||||
printf("in DesperateComputeCenter()\n");
|
||||
#endif
|
||||
|
||||
GetLftSiteData(e, &i_sites[0], &s_types[0]);
|
||||
GetRgtSiteData(e, &i_sites[1], &s_types[1]);
|
||||
i_sites[2] = i;
|
||||
s_types[2] = ti;
|
||||
*r2 = LARGE;
|
||||
|
||||
#ifdef VR_TRACE
|
||||
printf("site %d/%d, site %d/%d, site %d/%d\n", i, ti,
|
||||
i_sites[0], s_types[0], i_sites[1], s_types[1]);
|
||||
int i_sites[3], min_ind[3], new_min, new_max;
|
||||
t_site s_types[3];
|
||||
#endif
|
||||
|
||||
for (j = 0; j < 3; j += 1) {
|
||||
if (s_types[j] == PNT) {
|
||||
start[j] = end[j] = GetPntCoords(i_sites[j]);
|
||||
}
|
||||
else if (s_types[j] == SEG) {
|
||||
start[j] = GetSegStartCoord(i_sites[j]);
|
||||
end[j] = GetSegEndCoord(i_sites[j]);
|
||||
}
|
||||
else if (s_types[j] == ARC) {
|
||||
start[j] = GetArcStartCoord(i_sites[j]);
|
||||
end[j] = GetArcEndCoord(i_sites[j]);
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
#ifdef VR_TRACE
|
||||
printf("s1: (%20.16f,%20.16f)\ne1: (%20.16f,%20.16f)\n",
|
||||
start[0].x, start[0].y, end[0].x, end[0].y);
|
||||
printf("s2: (%20.16f,%20.16f)\ne2: (%20.16f,%20.16f)\n",
|
||||
start[1].x, start[1].y, end[1].x, end[1].y);
|
||||
printf("s3: (%20.16f,%20.16f)\ne3: (%20.16f,%20.16f)\n\n",
|
||||
start[2].x, start[2].y, end[2].x, end[2].y);
|
||||
#endif
|
||||
old_diff = dist_diff;
|
||||
for (j = 0; j < 3; j += 1) {
|
||||
if (s_types[j] == PNT) {
|
||||
samples[j][0] = start[j];
|
||||
num_samples[j] = 1;
|
||||
}
|
||||
else if (s_types[j] == SEG) {
|
||||
num_samples[j] = NS + 1;
|
||||
samples[j][0] = u = start[j];
|
||||
samples[j][NS] = v = end[j];
|
||||
for (k = 1; k <= NS-1; ++k) {
|
||||
t = ((double) k) / NS;
|
||||
samples[j][k] = LinearComb(u, v, t);
|
||||
}
|
||||
}
|
||||
else if (s_types[j] == ARC) {
|
||||
num_samples[j] = NS + 1;
|
||||
samples[j][0] = u = start[j];
|
||||
samples[j][NS] = v = end[j];
|
||||
p = GetArcCenter(i_sites[j]);
|
||||
angle_s = atan2(u.y - p.y, u.x - p.x);
|
||||
angle_e = atan2(v.y - p.y, v.x - p.x);
|
||||
if (angle_s < 0.0) angle_s += M_2PI;
|
||||
if (angle_e < 0.0) angle_e += M_2PI;
|
||||
if (angle_e < angle_s) angle_e += M_2PI;
|
||||
du = PntPntDist(u, p);
|
||||
dv = PntPntDist(v, p);
|
||||
for (k = 1; k <= NS-1; ++k) {
|
||||
t = ((double) k) / NS;
|
||||
angle = (1.0 - t) * angle_s + t * angle_e;
|
||||
radius = (1.0 - t) * du + t * dv;
|
||||
samples[j][k].x = p.x + radius * cos(angle);
|
||||
samples[j][k].y = p.y + radius * sin(angle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (n = 0; n < num_samples[0]; ++n) {
|
||||
for (j = 0; j < num_samples[1]; ++j) {
|
||||
for (k = 0; k < num_samples[2]; ++k) {
|
||||
if (NumericalPntPntPntCntr(samples[0][n], samples[1][j],
|
||||
samples[2][k], &cntr, &radius)) {
|
||||
dist1 = ComputeSiteDistance(i_sites[0], s_types[0], cntr);
|
||||
dist2 = ComputeSiteDistance(i_sites[1], s_types[1], cntr);
|
||||
dist3 = ComputeSiteDistance(i_sites[2], s_types[2], cntr);
|
||||
dist = Abs(dist1 - radius) +
|
||||
Abs(dist2 - radius) + Abs(dist3 - radius);
|
||||
if (dist < dist_diff) {
|
||||
dist_diff = dist;
|
||||
min_ind[0] = n;
|
||||
min_ind[1] = j;
|
||||
min_ind[2] = k;
|
||||
|
||||
*r2 = (dist1 + dist2 + dist3) / 3.0;
|
||||
*w = cntr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef VR_TRACE
|
||||
printf("new radius after %2d round: %20.16f for (%d/%d, %d/%d, %d/%d)\n",
|
||||
counter, *r2, i_sites[0], s_types[0], i_sites[1], s_types[1],
|
||||
i_sites[2], s_types[2]);
|
||||
printf(" dist_diff = %20.16f\n", dist_diff);
|
||||
printf(" center = (%20.16f %20.16f)\n", w->x, w->y);
|
||||
++counter;
|
||||
#endif
|
||||
|
||||
if (dist_diff < old_diff) {
|
||||
for (j = 0; j < 3; j += 1) {
|
||||
if (s_types[j] == PNT) {
|
||||
start[j] = end[j] = samples[j][0];
|
||||
}
|
||||
else {
|
||||
if (min_ind[j] == 0) {
|
||||
new_min = 0;
|
||||
new_max = 2;
|
||||
}
|
||||
else if (min_ind[j] == NS) {
|
||||
new_min = NS - 2;
|
||||
new_max = NS;
|
||||
}
|
||||
else {
|
||||
new_min = min_ind[j] - 1;
|
||||
new_max = min_ind[j] + 1;
|
||||
}
|
||||
u = start[j];
|
||||
v = end[j];
|
||||
if (s_types[j] == SEG) {
|
||||
t = new_min / ((double) NS);
|
||||
start[j] = LinearComb(u, v, t);
|
||||
t = new_max / ((double) NS);
|
||||
end[j] = LinearComb(u, v, t);
|
||||
}
|
||||
else {
|
||||
p = GetArcCenter(i_sites[j]);
|
||||
angle_s = atan2(u.y - p.y, u.x - p.x);
|
||||
angle_e = atan2(v.y - p.y, v.x - p.x);
|
||||
if (angle_s < 0.0) angle_s += M_2PI;
|
||||
if (angle_e < 0.0) angle_e += M_2PI;
|
||||
if (angle_e < angle_s) angle_e += M_2PI;
|
||||
du = PntPntDist(u, p);
|
||||
dv = PntPntDist(v, p);
|
||||
t = ((double) new_min) / NS;
|
||||
angle = (1.0 - t) * angle_s + t * angle_e;
|
||||
radius = (1.0 - t) * du + t * dv;
|
||||
start[j].x = p.x + radius * cos(angle);
|
||||
start[j].y = p.y + radius * sin(angle);
|
||||
t = ((double) new_max) / NS;
|
||||
angle = (1.0 - t) * angle_s + t * angle_e;
|
||||
radius = (1.0 - t) * du + t * dv;
|
||||
end[j].x = p.x + radius * cos(angle);
|
||||
end[j].y = p.y + radius * sin(angle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (dist_diff < old_diff);
|
||||
|
||||
/* */
|
||||
/* compare to and choose among old nodes */
|
||||
/* */
|
||||
n = GetStartNode(e);
|
||||
GetNodeData(n, &cntr, &radius);
|
||||
dist1 = ComputeSiteDistance(i_sites[0], s_types[0], cntr);
|
||||
dist2 = ComputeSiteDistance(i_sites[1], s_types[1], cntr);
|
||||
dist3 = ComputeSiteDistance(i_sites[2], s_types[2], cntr);
|
||||
dist = Abs(dist1 - radius) + Abs(dist2 - radius) + Abs(dist3 - radius);
|
||||
if (dist < old_diff) {
|
||||
*r2 = (dist1 + dist2 + dist3) / 3.0;
|
||||
*w = cntr;
|
||||
old_diff = dist;
|
||||
}
|
||||
n = GetEndNode(e);
|
||||
GetNodeData(n, &cntr, &radius);
|
||||
dist1 = ComputeSiteDistance(i_sites[0], s_types[0], cntr);
|
||||
dist2 = ComputeSiteDistance(i_sites[1], s_types[1], cntr);
|
||||
dist3 = ComputeSiteDistance(i_sites[2], s_types[2], cntr);
|
||||
dist = Abs(dist1 - radius) + Abs(dist2 - radius) + Abs(dist3 - radius);
|
||||
if (dist < old_diff) {
|
||||
*r2 = (dist1 + dist2 + dist3) / 3.0;
|
||||
*w = cntr;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int vroniObject::DesperateFindMostViolatedNodeSeg(int i1, int j)
|
||||
{
|
||||
int e, k1, k2, n;
|
||||
coord p, q1, q2;
|
||||
double dist1, dist2, radius1, radius2;
|
||||
double a, b, c, lgth;
|
||||
|
||||
e = GetVDPtr(i1, PNT);
|
||||
k1 = GetEndNode(e);
|
||||
k2 = GetStartNode(e);
|
||||
GetNodeData(k1, &q1, &radius1);
|
||||
GetNodeData(k2, &q2, &radius2);
|
||||
GetSegEqnData(j, &a, &b, &c);
|
||||
lgth = GetSegLgth(j);
|
||||
p = GetSegStartCoord(j);
|
||||
|
||||
if (GetNodeSite(k1) != i1)
|
||||
dist1 = AbsPntSegDist(p, q1, a, b, c, lgth, TINY) - radius1;
|
||||
else
|
||||
dist1 = 0.0;
|
||||
if (GetNodeSite(k2) != i1)
|
||||
dist2 = AbsPntSegDist(p, q2, a, b, c, lgth, TINY) - radius2;
|
||||
else
|
||||
dist2 = 0.0;
|
||||
|
||||
if (dist1 < dist2) n = StoreNode(q1.x, q1.y, radius1);
|
||||
else n = StoreNode(q2.x, q2.y, radius2);
|
||||
InsertDummyNode(e, n, false);
|
||||
|
||||
desperate = true;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void vroniObject::DesperatePreserveVoronoiCellSeg(int i, t_site t, int i0)
|
||||
{
|
||||
int e, n, e0, k, k0, e_max;
|
||||
double a, b, c, r_2, d, r_max, d_max;
|
||||
coord q, w_max;
|
||||
|
||||
troubles = true;
|
||||
|
||||
e = GetVDPtr(i, t);
|
||||
assert(InEdgesList(e));
|
||||
assert(IsLftSite(e, i, t) || IsRgtSite(e, i, t));
|
||||
|
||||
GetSegEqnData(i0, &a, &b, &c);
|
||||
|
||||
if (IsRgtSite(e, i, t)) {
|
||||
k = GetEndNode(e);
|
||||
k0 = GetStartNode(e);
|
||||
}
|
||||
else {
|
||||
k = GetStartNode(e);
|
||||
k0 = GetEndNode(e);
|
||||
}
|
||||
GetNodeData(k0, &q, &r_2);
|
||||
d_max = AbsPntLineDist(a, b, c, q);
|
||||
e_max = e;
|
||||
w_max = q;
|
||||
r_max = r_2;
|
||||
e0 = e;
|
||||
|
||||
do {
|
||||
GetNodeData(k, &q, &r_2);
|
||||
d = AbsPntLineDist(a, b, c, q);
|
||||
if (d > d_max) {
|
||||
d_max = d;
|
||||
w_max = q;
|
||||
e_max = e;
|
||||
r_max = r_2;
|
||||
}
|
||||
e = GetCCWEdge(e, k);
|
||||
k = GetOtherNode(e, k);
|
||||
} while (e != e0);
|
||||
|
||||
n = StoreNode(w_max.x, w_max.y, r_max);
|
||||
InsertDummyNode(e_max, n, true);
|
||||
|
||||
desperate = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void vroniObject::DesperateBreakLoopSeg(int i0)
|
||||
{
|
||||
int start, number, n, k, j, e, k0, e_max;
|
||||
double a, b, c, d_max, r_max, d1, d0, r1_2, r0_2;
|
||||
coord q1, q0, w_max;
|
||||
|
||||
troubles = true;
|
||||
|
||||
number = GetLoopStackSizeFunc();
|
||||
start = GetLoopStackMinFunc();
|
||||
|
||||
GetSegEqnData(i0, &a, &b, &c);
|
||||
d_max = -1.0;
|
||||
e_max = NIL;
|
||||
r_max = 0.0;
|
||||
w_max = GetSegStartCoord(i0);
|
||||
|
||||
for (j = start; j < number; ++j) {
|
||||
e = GetLoopStackElementFunc(j);
|
||||
k = GetStartNode(e);
|
||||
k0 = GetEndNode(e);
|
||||
GetNodeData(k0, &q0, &r0_2);
|
||||
d0 = AbsPntLineDist(a, b, c, q0);
|
||||
GetNodeData(k, &q1, &r1_2);
|
||||
d1 = AbsPntLineDist(a, b, c, q1);
|
||||
|
||||
if (d0 > d_max) {
|
||||
d_max = d0;
|
||||
e_max = e;
|
||||
w_max = q0;
|
||||
r_max = r0_2;
|
||||
}
|
||||
if (d1 > d_max) {
|
||||
d_max = d1;
|
||||
e_max = e;
|
||||
w_max = q1;
|
||||
r_max = r1_2;
|
||||
}
|
||||
}
|
||||
|
||||
assert(e_max != NIL);
|
||||
n = StoreNode(w_max.x, w_max.y, r_max);
|
||||
InsertDummyNode(e_max, n, true);
|
||||
|
||||
desperate = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int vroniObject::DesperateFindMostViolatedNodeArc(int i1, int j)
|
||||
{
|
||||
int e, k1, k2, n;
|
||||
coord p, q1, q2, ns, ne;
|
||||
double dist1, dist2, r, radius1, radius2;
|
||||
|
||||
e = GetVDPtr(i1, PNT);
|
||||
k1 = GetEndNode(e);
|
||||
k2 = GetStartNode(e);
|
||||
GetNodeData(k1, &q1, &radius1);
|
||||
GetNodeData(k2, &q2, &radius2);
|
||||
ns = GetArcStartNormal(j);
|
||||
ne = GetArcEndNormal(j);
|
||||
p = GetArcCenter(j);
|
||||
r = GetArcRadius(j);
|
||||
|
||||
if (GetNodeSite(k1) != i1) {
|
||||
q1 = VecSub(q1, p);
|
||||
dist1 = AbsPntArcDist(ns, ne, q1, r, TINY) - radius1;
|
||||
}
|
||||
else
|
||||
dist1 = 0.0;
|
||||
if (GetNodeSite(k2) != i1) {
|
||||
q2 = VecSub(q2, p);
|
||||
dist2 = AbsPntArcDist(ns, ne, q2, r, TINY) - radius2;
|
||||
}
|
||||
else
|
||||
dist2 = 0.0;
|
||||
|
||||
if (dist1 < dist2) n = StoreNode(q1.x, q1.y, radius1);
|
||||
else n = StoreNode(q2.x, q2.y, radius2);
|
||||
InsertDummyNode(e, n, false);
|
||||
|
||||
desperate = true;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void vroniObject::DesperatePreserveVoronoiCellArc(int i, t_site t, int i0)
|
||||
{
|
||||
int e, n, e0, k, k0, e_max;
|
||||
double r, r_2, d, r_max, d_max;
|
||||
coord p, q, w_max;
|
||||
|
||||
troubles = true;
|
||||
|
||||
e = GetVDPtr(i, t);
|
||||
assert(InEdgesList(e));
|
||||
assert(IsLftSite(e, i, t) || IsRgtSite(e, i, t));
|
||||
|
||||
if (IsRgtSite(e, i, t)) {
|
||||
k = GetEndNode(e);
|
||||
k0 = GetStartNode(e);
|
||||
}
|
||||
else {
|
||||
k = GetStartNode(e);
|
||||
k0 = GetEndNode(e);
|
||||
}
|
||||
GetNodeData(k0, &q, &r_2);
|
||||
p = GetArcCenter(i0);
|
||||
r = GetArcRadius(i0);
|
||||
d_max = AbsPntCircleDist(p, r, q);
|
||||
e_max = e;
|
||||
w_max = q;
|
||||
r_max = r_2;
|
||||
e0 = e;
|
||||
|
||||
do {
|
||||
GetNodeData(k, &q, &r_2);
|
||||
d = AbsPntCircleDist(p, r, q);
|
||||
if (d > d_max) {
|
||||
d_max = d;
|
||||
w_max = q;
|
||||
e_max = e;
|
||||
r_max = r_2;
|
||||
}
|
||||
e = GetCCWEdge(e, k);
|
||||
k = GetOtherNode(e, k);
|
||||
} while (e != e0);
|
||||
|
||||
n = StoreNode(w_max.x, w_max.y, r_max);
|
||||
InsertDummyNode(e_max, n, true);
|
||||
|
||||
desperate = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void vroniObject::DesperateBreakLoopArc(int i0)
|
||||
{
|
||||
int start, number, n, k, j, e, k0, e_max;
|
||||
double d_max, r_max, d1, d0, r1_2, r0_2, r;
|
||||
coord q1, q0, w_max, c;
|
||||
|
||||
troubles = true;
|
||||
|
||||
number = GetLoopStackSizeFunc();
|
||||
start = GetLoopStackMinFunc();
|
||||
|
||||
c = GetArcCenter(i0);
|
||||
r = GetArcRadius(i0);
|
||||
d_max = -1.0;
|
||||
e_max = NIL;
|
||||
r_max = 0.0;
|
||||
w_max = GetArcStartCoord(i0);
|
||||
|
||||
for (j = start; j < number; ++j) {
|
||||
|
||||
e = GetLoopStackElementFunc(j);
|
||||
|
||||
k = GetStartNode(e);
|
||||
k0 = GetEndNode(e);
|
||||
GetNodeData(k0, &q0, &r0_2);
|
||||
GetNodeData(k, &q1, &r1_2);
|
||||
|
||||
d0 = PntPntDist(c,q0);
|
||||
d0 = Abs(d0-r);
|
||||
|
||||
d1 = PntPntDist(c,q1);
|
||||
d1 = Abs(d1-r);
|
||||
|
||||
if (d0 > d_max) {
|
||||
d_max = d0;
|
||||
e_max = e;
|
||||
w_max = q0;
|
||||
r_max = r0_2;
|
||||
}
|
||||
if (d1 > d_max) {
|
||||
d_max = d1;
|
||||
e_max = e;
|
||||
w_max = q1;
|
||||
r_max = r1_2;
|
||||
}
|
||||
}
|
||||
|
||||
assert(e_max != NIL);
|
||||
n = StoreNode(w_max.x, w_max.y, r_max);
|
||||
InsertDummyNode(e_max, n, true);
|
||||
|
||||
desperate = true;
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,484 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) Martin Held 1999-2023 */
|
||||
/* */
|
||||
/* */
|
||||
/* 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 radius;
|
||||
#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,
|
||||
&radius);
|
||||
center.x = center.y = radius = 0.0; /* avoid compiler complaints since */
|
||||
/* we don't use those variables... */
|
||||
#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)) {
|
||||
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 WRITE_VD
|
||||
|
||||
void vroniObject::HandleWriteVDOutput(void)
|
||||
{
|
||||
if (write_vd)
|
||||
API_Output_VD(vd_file, vd_apx_dist, left_vd, right_vd);
|
||||
|
||||
return;
|
||||
}
|
||||
#endif /* WRITE_VD */
|
||||
|
||||
|
||||
|
||||
#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 radius;
|
||||
#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
|
||||
if (computed && finished && !mic_computed && !pnts_only) {
|
||||
if (compute_mic) {
|
||||
#ifdef MIC
|
||||
draw_mic = true;
|
||||
ComputeMIC(time_it, left_offset, right_offset, ¢er, &radius);
|
||||
center.x = center.y = radius = 0.0; /* avoid GCC complaints ...*/
|
||||
mic_computed = true;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if (computed && finished && !quiet && off_finished) {
|
||||
/* */
|
||||
/* 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 */
|
||||
@@ -0,0 +1,46 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 1999-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 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
void API_ParseCommandLineArgs(int argc, char *argv[], vr_bool *graphics,
|
||||
vr_bool *color_graphics, vr_bool *full_screen);
|
||||
|
||||
void API_InitializeProgram(void);
|
||||
|
||||
void API_GetInputData(vr_bool *input_received);
|
||||
|
||||
void API_ProceedWithoutGraphics(vr_bool new_input);
|
||||
|
||||
void InitializeGraphics(int argc, char *argv[], vr_bool color_graphics,
|
||||
vr_bool full_screen);
|
||||
|
||||
void ProcessGraphicsEvents(void);
|
||||
|
||||
void API_TerminateProgram(void);
|
||||
|
||||
void API_HandleError(void);
|
||||
|
||||
const char* API_GetProgName();
|
||||
|
||||
const char* API_GetProgVersion();
|
||||
|
||||
const char* API_GetProgYear();
|
||||
+207
@@ -0,0 +1,207 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 1993-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 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
#include "vroni_object.h"
|
||||
|
||||
#ifdef NO_CPUTIME
|
||||
|
||||
double vroniObject::elapsed()
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
#else /* ifndef NO_CPUTIME */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* */
|
||||
/* Note: CPUTIME_IN_MILLISECONDS can be defined in the Imakefile by using */
|
||||
/* flag "-DCPUTIME_IN_MILLISECONDS". Same for the other flags. */
|
||||
/* */
|
||||
#ifdef CPUTIME_IN_MILLISECONDS
|
||||
#include <sys/resource.h>
|
||||
#ifndef RUSAGE_CHILDREN
|
||||
#undef CPUTIME_IN_MILLISECONDS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef CPUTIME_BY_CHRONO
|
||||
#include <chrono>
|
||||
|
||||
/* */
|
||||
/* This procedure computes the CPU time used by the calling process since */
|
||||
/* the last call. It is based on the chrono library of C++. */
|
||||
/* Call it before and after the execution of some instructions of your */
|
||||
/* program, whose CPU consumption you would like to know. The first value */
|
||||
/* returned can be ignored, and the second value gives the actual CPU */
|
||||
/* consumption in the form milliseconds.microseconds. (I.e., 12345 microsecs */
|
||||
/* are returned as 12.345 millisecs.) */
|
||||
/* */
|
||||
double vroniObject::elapsed()
|
||||
{
|
||||
double cpu_time;
|
||||
|
||||
if (!elapsed_initialized) {
|
||||
elapsed_initialized = true;
|
||||
start = std::chrono::high_resolution_clock::now();
|
||||
cpu_time = 0.0;
|
||||
}
|
||||
else {
|
||||
auto end = std::chrono::high_resolution_clock::now();
|
||||
auto diff = end - start;
|
||||
cpu_time = std::chrono::duration<double, std::micro>(diff).count() / 1000.0;
|
||||
start = end;
|
||||
}
|
||||
|
||||
return cpu_time;
|
||||
}
|
||||
#else
|
||||
#ifdef CPUTIME_IN_MILLISECONDS
|
||||
|
||||
/* */
|
||||
/* This procedure computes the CPU time used by the calling process since */
|
||||
/* the last call. (The sum of both system and user time is reported.) */
|
||||
/* Call it before and after the execution of some instructions of your */
|
||||
/* program, whose CPU consumption you would like to know. The first value */
|
||||
/* returned can be ignored, and the second value gives the actual CPU */
|
||||
/* consumption in the form milliseconds.microseconds. (I.e., 12345 microsecs */
|
||||
/* are returned as 12.345 millisecs.) */
|
||||
/* */
|
||||
double vroniObject::elapsed()
|
||||
{
|
||||
double cpu_time;
|
||||
unsigned long new_secs, secs, new_usecs, usecs, new_add_secs;
|
||||
int getrusage(int who, struct rusage *rusage);
|
||||
struct rusage rusage_self, rusage_children;
|
||||
|
||||
getrusage(RUSAGE_SELF, &rusage_self);
|
||||
getrusage(RUSAGE_CHILDREN, &rusage_children);
|
||||
|
||||
new_secs = rusage_self.ru_utime.tv_sec +
|
||||
rusage_self.ru_stime.tv_sec +
|
||||
rusage_children.ru_utime.tv_sec +
|
||||
rusage_children.ru_stime.tv_sec;
|
||||
new_usecs = rusage_self.ru_utime.tv_usec +
|
||||
rusage_self.ru_stime.tv_usec +
|
||||
rusage_children.ru_utime.tv_usec +
|
||||
rusage_children.ru_stime.tv_usec;
|
||||
|
||||
if (new_usecs >= 1000000) {
|
||||
new_add_secs = new_usecs / 1000000;
|
||||
new_usecs -= new_add_secs * 1000000;
|
||||
new_secs += new_add_secs;
|
||||
}
|
||||
|
||||
if (total_usecs > new_usecs) {
|
||||
secs = new_secs - total_secs - 1;
|
||||
usecs = new_usecs - total_usecs + 1000000;
|
||||
}
|
||||
else {
|
||||
secs = new_secs - total_secs;
|
||||
usecs = new_usecs - total_usecs;
|
||||
}
|
||||
|
||||
total_secs = new_secs;
|
||||
total_usecs = new_usecs;
|
||||
|
||||
cpu_time = 1.0e3 * (double) secs + 1.0e-3 * (double) usecs;
|
||||
|
||||
return cpu_time;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#else /* ifndef CPUTIME_IN_MILLISECONDS */
|
||||
|
||||
#ifdef CPUTIME_VIA_CLOCK
|
||||
|
||||
|
||||
#define CLOCK_UNITS 1000.0 /* this could be figured out automatically */
|
||||
|
||||
/* */
|
||||
/* This procedure computes the CPU time used by the calling process since */
|
||||
/* the last call. (The sum of both system and user time is reported.) */
|
||||
/* Call it before and after the execution of some instructions of your */
|
||||
/* program, whose CPU consumption you would like to know. The first value */
|
||||
/* returned can be ignored, and the second value gives the actual CPU */
|
||||
/* consumption in the form milliseconds.microseconds. (I.e., 12345 microsecs */
|
||||
/* are returned as 12.345 millisecs.) */
|
||||
/* */
|
||||
double vroniObject::elapsed()
|
||||
{
|
||||
double cpu_time;
|
||||
clock_t finish;
|
||||
|
||||
#ifndef CLOCKS_PER_SEC
|
||||
#define CLOCKS_PER_SEC sysconf(_SC_CLK_TCK)
|
||||
#endif
|
||||
|
||||
if (!elapsed_initialized) {
|
||||
total_cpu_time = clock();
|
||||
elapsed_initialized = true;
|
||||
}
|
||||
finish = clock();
|
||||
|
||||
cpu_time = ((double) (finish - total_cpu_time)) *
|
||||
(CLOCK_UNITS / CLOCKS_PER_SEC);
|
||||
total_cpu_time = finish;
|
||||
|
||||
return cpu_time;
|
||||
}
|
||||
|
||||
#else /* ifndef CPUTIME_IN_MILLISECONDS || CPUTIME_VIA_CLOCK */
|
||||
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/times.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* */
|
||||
/* This procedure computes the CPU time used by the calling process since */
|
||||
/* the last call. (The sum of both system and user time is reported.) */
|
||||
/* Call it before and after the execution of some instructions of your */
|
||||
/* program, whose CPU consumption you would like to know. The first value */
|
||||
/* returned can be ignored, and the second value gives the actual CPU */
|
||||
/* consumption (in milliseconds). */
|
||||
/* */
|
||||
double vroniObject::elapsed()
|
||||
{
|
||||
long dummy;
|
||||
double cpu_time;
|
||||
struct tms buffer;
|
||||
|
||||
if (HZ == 0) HZ = sysconf(_SC_CLK_TCK);
|
||||
|
||||
times(&buffer);
|
||||
dummy = buffer.tms_utime + buffer.tms_stime +
|
||||
buffer.tms_cutime + buffer.tms_cstime;
|
||||
cpu_time = (double) ((dummy - total) * 1000.0) / HZ;
|
||||
total = dummy;
|
||||
|
||||
return cpu_time;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,6 @@
|
||||
/* */
|
||||
/* this file is reserved for application-specific routines for handling */
|
||||
/* run-time options */
|
||||
/* */
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
/* */
|
||||
/* this file is reserved for application-specific routines that need to */
|
||||
/* access my sites data structures */
|
||||
/* */
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
/* */
|
||||
/* this file is reserved for application-specific routines that need to */
|
||||
/* access my offset data structures */
|
||||
/* */
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* 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-611 */
|
||||
/* Voice Mail: (+43 662) 8044-6304 */
|
||||
/* Snail Mail: Martin Held */
|
||||
/* FB Informatik */
|
||||
/* Universitaet Salzburg */
|
||||
/* A-5020 Salzburg, Austria */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifdef EXT_APPL_PNTS
|
||||
const eap_type eap_NIL = -1;
|
||||
#else
|
||||
#define eap_NIL -1
|
||||
#endif
|
||||
|
||||
#ifdef EXT_APPL_SITES
|
||||
const eas_type eas_NIL = -1;
|
||||
#else
|
||||
#define eas_NIL -1
|
||||
#endif
|
||||
|
||||
#ifdef EXT_APPL_VD
|
||||
const ean_type ean_NIL = -1;
|
||||
const eae_type eae_NIL = -1;
|
||||
#else
|
||||
#define ean_NIL -1
|
||||
#define eae_NIL -1
|
||||
#endif
|
||||
|
||||
#ifdef EXT_APPL_OFF
|
||||
const eao_type eao_NIL = -1;
|
||||
#else
|
||||
#define eao_NIL -1
|
||||
#endif
|
||||
|
||||
#ifdef EXT_APPL_WMAT
|
||||
const eam_type eam_NIL = -1;
|
||||
#else
|
||||
#define eam_NIL -1
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
+187
@@ -0,0 +1,187 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* 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-611 */
|
||||
/* Voice Mail: (+43 662) 8044-6304 */
|
||||
/* Snail Mail: Martin Held */
|
||||
/* FB Informatik */
|
||||
/* Universitaet Salzburg */
|
||||
/* A-5020 Salzburg, Austria */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef VRONI_EXT_APPL_DEFS_H
|
||||
#define VRONI_EXT_APPL_DEFS_H
|
||||
|
||||
/* */
|
||||
/* the following data types are used for user-defined entities that are to */
|
||||
/* be stored as part of my data structures. you are welcome to redefine them */
|
||||
/* according to your needs. however, please note that it is your task to */
|
||||
/* make sure that the functions and macros for I/O operations are modified */
|
||||
/* accordingly in io_parse.c !! also, you'd need to redefine the constants */
|
||||
/* eap_NIL, eas_NIL, ean_NIL, eae_NIL, eam_NIL, and eao_NIL in the file */
|
||||
/* ext_appl_defs.c to whatever constant integral value or structure that can */
|
||||
/* be used for initializing the exterior application structures. see the */
|
||||
/* sample use for eap_... below. */
|
||||
/* */
|
||||
|
||||
typedef int eap_type; /* ext. appl. hook for pnt */
|
||||
typedef int eas_type; /* ext. appl. hook for seg and arc */
|
||||
typedef int ean_type; /* ext. appl. hook for node */
|
||||
typedef int eae_type; /* ext. appl. hook for edge */
|
||||
typedef int eam_type; /* ext. appl. hook for wmat */
|
||||
typedef int eao_type; /* ext. appl. hook for off_data */
|
||||
|
||||
/*
|
||||
* sample user-specific eap data:
|
||||
*
|
||||
* typedef struct {
|
||||
* long id;
|
||||
* char ch[10];
|
||||
* } eap_type;
|
||||
*/
|
||||
|
||||
extern const eap_type eap_NIL;
|
||||
extern const eas_type eas_NIL;
|
||||
extern const ean_type ean_NIL;
|
||||
extern const eam_type eam_NIL;
|
||||
extern const eao_type eao_NIL;
|
||||
extern const eae_type eae_NIL;
|
||||
|
||||
|
||||
#define ExtApplFuncNewInput
|
||||
|
||||
#define ExtApplFuncRestart
|
||||
|
||||
#define ExtApplFuncFirstPnts
|
||||
|
||||
#define ExtApplFuncDonePnts
|
||||
|
||||
#define ExtApplFuncFirstSegs
|
||||
|
||||
#define ExtApplFuncDoneSegs
|
||||
|
||||
#define ExtApplFuncDoneSegs
|
||||
|
||||
#define ExtApplFuncDoneArcs
|
||||
|
||||
#define ExtApplFuncFirstArcs
|
||||
|
||||
#define ExtApplFuncDoneVD
|
||||
|
||||
#define ExtApplFuncReset
|
||||
|
||||
#define ExtApplFuncIsoOffset
|
||||
|
||||
#define ExtApplFuncIsoOffsetDone
|
||||
|
||||
#define ExtApplFuncOffsetInit
|
||||
|
||||
#define ExtApplFuncOffsetRepeat
|
||||
|
||||
#define ExtApplFuncOffLoops
|
||||
|
||||
#define ExtApplFuncOffDone
|
||||
|
||||
#define ExtApplFuncOffStart
|
||||
|
||||
#define ExtApplFuncOffSegment
|
||||
|
||||
#define ExtApplFuncOffsetEnd
|
||||
|
||||
#define ExtApplFuncWMATInit
|
||||
|
||||
#define ExtApplFuncWMATLoop
|
||||
|
||||
#define ExtApplFuncWMATComputed
|
||||
|
||||
#define ExtApplFuncWMATDone
|
||||
|
||||
#define ExtApplFuncMICInit
|
||||
|
||||
#define ExtApplFuncMICDone
|
||||
|
||||
#define ExtApplFuncMICNotFound
|
||||
|
||||
#define ExtApplFuncVD_Warning
|
||||
|
||||
#define ExtApplFuncVD_Dbg_Warning
|
||||
|
||||
#define ExtApplFuncVD_IO_Warning
|
||||
|
||||
#define ExtApplFuncVD_Info
|
||||
|
||||
#define ExtApplFuncArgEvalParse
|
||||
|
||||
#define ExtApplFuncArgEvalInit
|
||||
|
||||
#define ExtApplFuncArgEvalDone
|
||||
|
||||
#define ExtApplFuncEvalErrorOption
|
||||
|
||||
#define ExtApplFuncEvalErrorExplain
|
||||
|
||||
#define ExtApplFuncReadOptCoord
|
||||
|
||||
#define ExtApplFuncReadOptNumber
|
||||
|
||||
#define ExtApplFuncReadNumber
|
||||
|
||||
#define ExtApplFuncReadPntData
|
||||
|
||||
#define ExtApplFuncReadSiteData
|
||||
|
||||
#define ExtApplFuncReadVectorData
|
||||
|
||||
#define ExtApplFuncWritePntData
|
||||
|
||||
#define ExtApplIsCorrectSide
|
||||
|
||||
#define ExtApplInsertDummyNode
|
||||
|
||||
#define ExtApplResetGraphicsData
|
||||
|
||||
#define ExtApplInitializeEdgeData
|
||||
|
||||
#define ExtApplInitializeProgram
|
||||
|
||||
#define ExtApplRemoveSeg
|
||||
|
||||
#define ExtApplRemoveArc
|
||||
|
||||
#define ExtApplSetStepSize
|
||||
|
||||
#define ExtApplSegPntIntersection
|
||||
|
||||
#define ExtApplArcPntIntersection
|
||||
|
||||
#define ExtApplSegSegIntersection
|
||||
|
||||
#define ExtApplSegArcIntersection
|
||||
|
||||
#define ExtApplArcArcIntersection
|
||||
|
||||
#define ExtApplHandleSeg
|
||||
|
||||
#define ExtApplHandleArc
|
||||
|
||||
#define ExtApplComputeRestarts
|
||||
|
||||
#define ExtApplAddDummyCorners
|
||||
|
||||
#define ExtApplScanVDEdges
|
||||
|
||||
#define ExtApplFuncVRONI_HandleError
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 2003--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 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef VRONI_EXT_APPL_INOUT_H
|
||||
#define VRONI_EXT_APPL_INOUT_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
class vroniObject;
|
||||
|
||||
#ifndef VRONI_COORD_H
|
||||
typedef struct {
|
||||
double x; /* x-coordinate */
|
||||
double y; /* y-coordinate */
|
||||
} coord; /********** point/vector ******************************/
|
||||
#endif
|
||||
|
||||
/* Make sure that double arg is defined, to ensure that external appliations do
|
||||
not break if they don't include fpkernel.h */
|
||||
#ifndef double_arg
|
||||
#define double_arg double
|
||||
#endif
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* The following data structures and macros may be modified at the user's */
|
||||
/* discretion. They are only used in API_HandleArrayInput() in */
|
||||
/* api_functions.c. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
typedef struct {
|
||||
double x1; /* x-coordinate */
|
||||
double y1; /* y-coordinate */
|
||||
#ifdef EXT_APPL_PNTS
|
||||
eap_type ext_appl;/* this field can be set by an application program to */
|
||||
/* refer to a user-defined entity. */
|
||||
#endif
|
||||
} in_pnts; /********** point/vector ******************************/
|
||||
|
||||
|
||||
typedef struct {
|
||||
double x1; /* x-coordinate start */
|
||||
double y1; /* y-coordinate start */
|
||||
double x2; /* x-coordinate end */
|
||||
double y2; /* y-coordinate end */
|
||||
#ifdef EXT_APPL_SITES
|
||||
eas_type ext_appl;/* this field can be set by an application program to */
|
||||
/* refer to a user-defined entity. */
|
||||
#endif
|
||||
} in_segs; /********** point/vector ******************************/
|
||||
|
||||
|
||||
typedef struct {
|
||||
double x1; /* x-coordinate start */
|
||||
double y1; /* y-coordinate start */
|
||||
double x2; /* x-coordinate end */
|
||||
double y2; /* y-coordinate end */
|
||||
double x3; /* x-coordinate center */
|
||||
double y3; /* y-coordinate center */
|
||||
vr_bool attr; /* orientation; true for CCW arcs, false for CW arcs */
|
||||
#ifdef EXT_APPL_SITES
|
||||
eas_type ext_appl;/* this field can be set by an application program to */
|
||||
/* refer to a user-defined entity. */
|
||||
#endif
|
||||
} in_arcs; /********** point/vector ******************************/
|
||||
|
||||
|
||||
/* api_functions.c */
|
||||
|
||||
vroniObject& API_VD();
|
||||
|
||||
void API_HandleError(void);
|
||||
|
||||
void API_ResetAll(void);
|
||||
|
||||
void API_ComputeOutputMIC(vr_bool time, vr_bool left_mic, vr_bool right_mic,
|
||||
coord *center, double *radius);
|
||||
|
||||
#ifdef MAT
|
||||
void API_ComputeWMAT(vr_bool auto_wmat, double wmat_angle, double wmat_dist,
|
||||
vr_bool time, vr_bool left_wmat, vr_bool right_wmat);
|
||||
#endif
|
||||
|
||||
#ifdef WRITE_VD
|
||||
void API_Output_VD(char vd_file[], double vd_apx_dist,
|
||||
vr_bool left_vd, vr_bool right_vd);
|
||||
#endif
|
||||
|
||||
void API_CheckThresholds(void); /* obsolet; calls API_InitializeProgram() */
|
||||
|
||||
void API_InitializeProgram(void);
|
||||
|
||||
void API_HandleInput(char input_file[], vr_bool *new_input,
|
||||
vr_bool read_polygon, vr_bool read_poly,
|
||||
vr_bool read_sites, vr_bool read_xdr,
|
||||
vr_bool read_e00, vr_bool read_polylines,
|
||||
vr_bool read_usgs, vr_bool read_dxf,
|
||||
vr_bool read_pnts, vr_bool read_graphml);
|
||||
|
||||
void API_FileInput(char input_file[], vr_bool *new_input);
|
||||
|
||||
void API_ComputeVD(vr_bool save_data, vr_bool new_input, vr_bool time,
|
||||
int bound, int sample, int approx, char output_file[],
|
||||
vr_bool discard_dupl_s, vr_bool pnts_only, vr_bool write_vd,
|
||||
char vd_dt_file[], vr_bool clean_up);
|
||||
|
||||
void API_TerminateProgram(void);
|
||||
|
||||
void API_ComputeOff(vr_bool time, char off_file[], vr_bool write_off,
|
||||
vr_bool dxf_format, double t_offset,
|
||||
double d_offset, vr_bool auto_offset, vr_bool left_offset,
|
||||
vr_bool right_offset);
|
||||
|
||||
void API_ArrayInput(int number_of_points, in_pnts *point_data,
|
||||
int number_of_segments, in_segs *segment_data,
|
||||
int number_of_arcs, in_arcs *arc_data,
|
||||
vr_bool *new_input);
|
||||
|
||||
void API_OutputMA(char vdma_file[]);
|
||||
|
||||
void API_ResetOffsetData(void);
|
||||
|
||||
const char* API_GetProgName();
|
||||
|
||||
const char* API_GetProgVersion();
|
||||
|
||||
const char* API_GetProgYear();
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,4 @@
|
||||
/* */
|
||||
/* this file is reserved for application-specific routines that need to */
|
||||
/* model an I/O routine of their own */
|
||||
/* */
|
||||
@@ -0,0 +1,6 @@
|
||||
/* */
|
||||
/* this file is reserved for application-specific routines that need to */
|
||||
/* access my MIC data. */
|
||||
/* */
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
/* */
|
||||
/* this file is reserved for application-specific routines that need to */
|
||||
/* access my offset data structures */
|
||||
/* */
|
||||
@@ -0,0 +1,4 @@
|
||||
/* */
|
||||
/* this file is reserved for application-specific routines that need to */
|
||||
/* access my "redraw" data structures */
|
||||
/* */
|
||||
@@ -0,0 +1,6 @@
|
||||
/* */
|
||||
/* this file is reserved for application-specific routines that need to */
|
||||
/* access my VD data structures */
|
||||
/* */
|
||||
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* 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 */
|
||||
/* Date: July 22, 2002 */
|
||||
/* */
|
||||
/* 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 my header files */
|
||||
/* */
|
||||
#include "coord.h"
|
||||
#include "vddata.h"
|
||||
#include "ext_appl_inout.h"
|
||||
#include "ext_appl_vroni_object.h"
|
||||
|
||||
|
||||
/* */
|
||||
/* VRONI object derived class implementation */
|
||||
/* */
|
||||
|
||||
extApplVroniObject::extApplVroniObject()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
extApplVroniObject::~extApplVroniObject()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool extApplVroniObject::EdgeDataNeedInitializing()
|
||||
{
|
||||
return (e_data_init ? true : false);
|
||||
}
|
||||
|
||||
|
||||
void extApplVroniObject::InitializeAllEdgeData()
|
||||
{
|
||||
vr_bool unrestricted = 1;
|
||||
vr_bool left_offset = 0;
|
||||
vr_bool compute_mic = 0;
|
||||
int mic_edge = NIL;
|
||||
|
||||
return InitializeEdgeData(unrestricted, left_offset, compute_mic, &mic_edge);
|
||||
}
|
||||
|
||||
|
||||
bool extApplVroniObject::IsDegenerateEdge(int ie)
|
||||
{
|
||||
if (GetEdgeFlagDeg(ie)) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* 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-611 */
|
||||
/* Voice Mail: (+43 662) 8044-6304 */
|
||||
/* Snail Mail: Martin Held */
|
||||
/* FB Informatik */
|
||||
/* Universitaet Salzburg */
|
||||
/* A-5020 Salzburg, Austria */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef VRONI_EXT_APPL_VRONI_OBJECT_H
|
||||
#define VRONI_EXT_APPL_VRONI_OBJECT_H
|
||||
|
||||
#include "vroni_object.h"
|
||||
|
||||
|
||||
/* */
|
||||
/* VRONI object derived class declaration */
|
||||
/* */
|
||||
class extApplVroniObject : public vroniObject
|
||||
{
|
||||
public:
|
||||
|
||||
//
|
||||
// CONSTRUCTOR / DESTRUCTOR
|
||||
//
|
||||
extApplVroniObject();
|
||||
|
||||
virtual ~extApplVroniObject();
|
||||
|
||||
|
||||
//
|
||||
// EXTRA FUNCTIONS
|
||||
//
|
||||
bool EdgeDataNeedInitializing();
|
||||
|
||||
void InitializeAllEdgeData();
|
||||
|
||||
bool IsDegenerateEdge(int ie);
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
private:
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,6 @@
|
||||
/* */
|
||||
/* this file is reserved for application-specific routines that need to */
|
||||
/* access my WMAT data */
|
||||
/* */
|
||||
|
||||
|
||||
+231
@@ -0,0 +1,231 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 1999-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 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef VRONI_FP_KERNEL_H
|
||||
#define VRONI_FP_KERNEL_H
|
||||
|
||||
#ifdef WITH_COREBACKEND
|
||||
/* Set CORE Level to 4. Otherwise all unsigned long no longer work */
|
||||
#define CORE_LEVEL 4
|
||||
|
||||
#ifdef WITH_CORE_EXPR_WRAPPER
|
||||
#include<ExprWrapper.h>
|
||||
#else
|
||||
#include<CORE/CORE.h>
|
||||
#endif /* WITH_CORE_EXPR_WRAPPER */
|
||||
|
||||
|
||||
#undef double
|
||||
#ifdef WITH_COREBACKEND_BIGFLOAT
|
||||
#define double CORE::BigFloat
|
||||
#else
|
||||
/* allow double to be used as Expr */
|
||||
#define double Expr
|
||||
#endif
|
||||
|
||||
#define double_arg const double &
|
||||
|
||||
//This is used to indicate that double gets a different meaning!
|
||||
#define DOUBLE_OVERRIDE
|
||||
|
||||
#include <formattedIO.h>
|
||||
|
||||
#define TO_MDOUBLE(x) (x).doubleValue()
|
||||
|
||||
inline CORE::BigInt cut_comma(const Expr & x) {
|
||||
CORE::BigInt v = floor(x);
|
||||
if(v < 0) {
|
||||
return v + 1;
|
||||
} else {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
#include "coreatan2.h"
|
||||
|
||||
inline int intfloor(const Expr & e) {
|
||||
return floor(e).intValue();
|
||||
}
|
||||
|
||||
inline unsigned int uintceil(const Expr & e) {
|
||||
return (unsigned)ceil(e).intValue();
|
||||
}
|
||||
|
||||
//REAL_TO_INT behaves like (int)(x)
|
||||
#define REAL_TO_INT(x) cut_comma(x).intValue()
|
||||
#define REAL_TO_GLINT(x) cut_comma(x).intValue()
|
||||
#define REAL_TO_FLOAT(x) (x).floatValue()
|
||||
#define BIGINT_TO_INT(x) (x).intValue()
|
||||
#define TO_REAL(x) double(x)
|
||||
|
||||
//Definitions for functions undefined in CORE
|
||||
#define isnan(x) 0
|
||||
#define atan2(y,x) atan2local((y),(x))
|
||||
#define signbit(x) ((x) < 0 ? 1 : 0)
|
||||
|
||||
#define CORE_EXPR_OPS(name, x) { \
|
||||
std::map<std::string, unsigned int > m; \
|
||||
(x).rep()->rekCollectOp(m); \
|
||||
for(std::map<std::string, unsigned int>::iterator it = m.begin(); it != m.end(); ++it) { \
|
||||
std::cout << it->second << "\t: " << it->first << std::endl; \
|
||||
}}
|
||||
|
||||
#ifdef WITH_CORE_EXPR_WRAPPER
|
||||
inline void CORE_EXPR_SEQ(std::string name, const Expr & x) {
|
||||
std::map<unsigned int, std::string > m;
|
||||
(x).rep()->rekSequen(m);
|
||||
for (std::map<unsigned int, std::string>::iterator it = m.begin(); it != m.end(); ++it) {
|
||||
std::cout << it->second << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
inline void CORE_EXPR_DEBUG1(std::string name, const Expr & x) {
|
||||
std::cout << name << " depth: " << (x).rep()->getDepth() << std::endl;
|
||||
std::cout << name << " elementCount: " << (x).rep()->getElementCount() << std::endl;
|
||||
CORE_EXPR_SEQ(name, (x));
|
||||
std::cout << name << " value: " << (x) << std::endl;
|
||||
}
|
||||
#else
|
||||
inline void CORE_EXPR_SEQ(std::string name, const Expr & x) {}
|
||||
inline void CORE_EXPR_DEBUG1(std::string name, const Expr & x) {}
|
||||
#endif
|
||||
|
||||
//IO
|
||||
#define FP_printf formattedIO::fmc_printf
|
||||
#define FP_fprintf formattedIO::fmc_fprintf
|
||||
|
||||
inline const double * FP_PRNTARG(const double & x) { return &x; }
|
||||
|
||||
//[sf]scanf methods
|
||||
#define FP_fscanf formattedIO::cfscanf
|
||||
#define FP_sscanf formattedIO::csscanf
|
||||
|
||||
|
||||
// The second argument is the SHA1sum of "shift\n". This avoids a
|
||||
// conflict with a shift function in CORE - VRONI uses some
|
||||
// variables named shift
|
||||
#define shift a68fe7dac8c32f30ad04d52fab4aa46be1068d82
|
||||
|
||||
#elif defined(WITH_MPFRBACKEND)
|
||||
|
||||
#include <mpfr_class.h>
|
||||
|
||||
#include <formattedIO.h>
|
||||
|
||||
typedef double machine_double;
|
||||
#undef double
|
||||
|
||||
#ifdef WITH_CORE_EXPR_WRAPPER
|
||||
#include<ExprWrapper.h>
|
||||
#define double Expr<Mpfr_class>
|
||||
#else
|
||||
#define double Mpfr_class
|
||||
#endif /* WITH_CORE_EXPR_WRAPPER */
|
||||
|
||||
#define double_arg const double &
|
||||
|
||||
//This is used to indicate that double gets a different meaning!
|
||||
#define DOUBLE_OVERRIDE
|
||||
|
||||
|
||||
#define TO_MDOUBLE(x) (x).doubleValue()
|
||||
#define REAL_TO_INT(x) (x).intValue()
|
||||
#define REAL_TO_GLINT(x) (x).intValue()
|
||||
#define REAL_TO_FLOAT(x) (x).floatValue()
|
||||
#define TO_REAL(x) double(x)
|
||||
|
||||
inline void CORE_EXPR_DEBUG1(std::string , const double & ) {}
|
||||
|
||||
inline long intfloor(const double & e) {
|
||||
return floor(e).intValue();
|
||||
}
|
||||
|
||||
inline unsigned long uintceil(const double & e) {
|
||||
return ceil(e).intValue();
|
||||
}
|
||||
|
||||
//Definitions for functions undefined in CORE
|
||||
#if WITH_CORE_EXPR_WRAPPER
|
||||
#define is_nan(x) 0
|
||||
#define sign_bit(x) ((x) < 0 ? 1 : 0)
|
||||
#endif
|
||||
|
||||
//IO
|
||||
#define FP_printf formattedIO::fmc_printf
|
||||
#define FP_fprintf formattedIO::fmc_fprintf
|
||||
|
||||
inline const double * FP_PRNTARG(const double & x) { return &x; }
|
||||
|
||||
//[sf]scanf methods
|
||||
#define FP_fscanf formattedIO::cfscanf
|
||||
#define FP_sscanf formattedIO::csscanf
|
||||
|
||||
|
||||
#else
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#define TO_MDOUBLE(x) (x)
|
||||
#define REAL_TO_INT(x) (int)(x)
|
||||
#define REAL_TO_GLINT(x) (GLint)(x)
|
||||
#define REAL_TO_FLOAT(x) (float)(x)
|
||||
#define BIGINT_TO_INT(x) (x)
|
||||
#define TO_REAL(x) (x)
|
||||
|
||||
#define machine_double double
|
||||
|
||||
#define double_arg double
|
||||
|
||||
inline int intfloor(const double e) {
|
||||
return (int)(floor(e));
|
||||
}
|
||||
|
||||
inline unsigned int uintceil(const double e) {
|
||||
return (unsigned)ceil(e);
|
||||
}
|
||||
|
||||
#define CORE_EXPR_DEBUG1(x,y)
|
||||
|
||||
#define is_nan(x) isnan(x)
|
||||
#define sign_bit(x) signbit(x)
|
||||
|
||||
#ifdef DOUBLE_OVERRIDE
|
||||
#error "DOUBLE_OVERRIDE should not be defined here!"
|
||||
#endif
|
||||
|
||||
//IO
|
||||
#define FP_printf printf
|
||||
#define FP_fprintf fprintf
|
||||
|
||||
#define FP_PRNTARG(x) (x)
|
||||
|
||||
//[sf]scanf methods
|
||||
#define FP_fscanf fscanf
|
||||
#define FP_sscanf sscanf
|
||||
|
||||
|
||||
|
||||
#endif /* LIB_CORE */
|
||||
|
||||
#endif /* VRONI_FP_KERNEL_H */
|
||||
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 2010-2023 M. Held, S. Huber */
|
||||
/* */
|
||||
/* 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: Stefan Huber, 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 <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* */
|
||||
/* get my header files */
|
||||
/* */
|
||||
#include "fpkernel.h"
|
||||
#include "vroni_object.h"
|
||||
#include "random.h"
|
||||
|
||||
|
||||
/* */
|
||||
/* Compute point on circle with center c and radius r at angle phi */
|
||||
/* */
|
||||
coord vroniObject::CirclePnt(const coord & c, double_arg r, double_arg phi)
|
||||
{
|
||||
coord q;
|
||||
q.x = c.x + r*cos(phi);
|
||||
q.y = c.y + r*sin(phi);
|
||||
return q;
|
||||
}
|
||||
|
||||
/* */
|
||||
/* Compute a point distributed uniformly random */
|
||||
/* */
|
||||
coord vroniObject::UniformRandomPoint()
|
||||
{
|
||||
coord q;
|
||||
UniformRandom(q.x);
|
||||
UniformRandom(q.y);
|
||||
return q;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 2010-2023 M. Held, S. Huber */
|
||||
/* */
|
||||
/* 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: Stefan Huber, 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 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef VRONI_GEOM_H
|
||||
#define VRONI_GEOM_H
|
||||
|
||||
#include "util.h"
|
||||
|
||||
|
||||
/** Compute squared distance between two points */
|
||||
inline double vroniObject::PntPntDistSq(coord pi, coord pj)
|
||||
{
|
||||
const double x = pi.x - pj.x;
|
||||
const double y = pi.y - pj.y;
|
||||
return x*x + y*y;
|
||||
}
|
||||
|
||||
/** Compute distance between two points */
|
||||
inline double vroniObject::PntPntDist(coord pi, coord pj)
|
||||
{
|
||||
const double x = pi.x - pj.x;
|
||||
const double y = pi.y - pj.y;
|
||||
return sqrt(x*x + y*y);
|
||||
}
|
||||
|
||||
/** Compute mid point on the line (pi,pj) */
|
||||
inline coord vroniObject::MidPoint(coord pi, coord pj)
|
||||
{
|
||||
coord q;
|
||||
q.x = (pi.x + pj.x) / 2.0;
|
||||
q.y = (pi.y + pj.y) / 2.0;
|
||||
return q;
|
||||
}
|
||||
|
||||
/** Compute centroid point of the triangle (pi,pj,pk) */
|
||||
inline coord vroniObject::Centroid(coord pi, coord pj, coord pk)
|
||||
{
|
||||
coord q;
|
||||
q.x = (pi.x + pj.x + pk.x)/3.0;
|
||||
q.y = (pi.y + pj.y + pk.y)/3.0;
|
||||
return q;
|
||||
}
|
||||
|
||||
/** Build linar combination of vectors p and r by parameter t */
|
||||
inline coord vroniObject::LinearComb(const coord & p, const coord & r,
|
||||
double_arg t)
|
||||
{
|
||||
coord q;
|
||||
q.x = p.x + t*(r.x-p.x);
|
||||
q.y = p.y + t*(r.y-p.y);
|
||||
return q;
|
||||
}
|
||||
|
||||
/** Get the point q = p + t*v */
|
||||
inline coord vroniObject::RayPnt(const coord & p, const coord & v,
|
||||
double_arg t)
|
||||
{
|
||||
coord q;
|
||||
q.x = p.x + t*v.x;
|
||||
q.y = p.y + t*v.y;
|
||||
return q;
|
||||
}
|
||||
|
||||
/** Compute (signed) distance of point p to circle (c,r). Positive
|
||||
* values indicate that p is outside the circle (c,r). */
|
||||
inline double vroniObject::PntCircleDist(const coord & c, double_arg r,
|
||||
const coord & p)
|
||||
{
|
||||
return PntPntDist(p, c) - r;
|
||||
}
|
||||
|
||||
/** Compute absolute distance of point p tor circle (c,r) */
|
||||
inline double vroniObject::AbsPntCircleDist(const coord & c, double_arg r,
|
||||
const coord & p)
|
||||
{
|
||||
return Abs(PntCircleDist(c, r, p));
|
||||
}
|
||||
|
||||
/** Test if point p is on circle (c,r) */
|
||||
inline int vroniObject::IsPntOnCircle(const coord & c, double_arg r, const coord & p)
|
||||
{
|
||||
return eq(PntCircleDist(c,r,p), ZERO);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Compute the signed distance of the point p to the line given by
|
||||
* the equation a*x + b*y + c = 0. A positive result means that
|
||||
* p lies in the positive half-plane defined by the line. */
|
||||
inline double vroniObject::PntLineDist(double_arg a, double_arg b, double_arg c, const coord & p)
|
||||
{
|
||||
return a*p.x + b*p.y + c;
|
||||
}
|
||||
|
||||
|
||||
/** Compute the absolute distance of the point p to the line given by
|
||||
* the equation a*x + b*y + c = 0 */
|
||||
inline double vroniObject::AbsPntLineDist(double_arg a, double_arg b, double_arg c, const coord & p)
|
||||
{
|
||||
return Abs( PntLineDist(a, b, c, p));
|
||||
}
|
||||
|
||||
|
||||
inline vr_bool vroniObject::IsBetweenVoronoiNodes(int e, const coord & p, double eps)
|
||||
{
|
||||
return (NodeEdgeClassificator(e, p, eps) == 0.0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+1476
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,611 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 2003-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: (+4 662) 8044-611 */
|
||||
/* Voice Mail: (+4 662) 8044-6304 */
|
||||
/* Snail Mail: Martin Held */
|
||||
/* FB Informatik */
|
||||
/* Universitaet Salzburg */
|
||||
/* A-5020 Salzburg, Austria */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* this file maintains a simple regular grid which is used for speeding up */
|
||||
/* the search for nearest neighbors during the construction of point VDs. */
|
||||
/* initially, a grid suitable for num_pnts * N_Percent many points is */
|
||||
/* maintained. based on the average number of points per cell, either a grid */
|
||||
/* or a quadtree-like structure is then constructed on the full set of */
|
||||
/* num_pnts many points. the layout of both grids is adapted to the aspect */
|
||||
/* ratio of the bounding box of the points. the number of cells of the */
|
||||
/* second grid depends on the average number of points per cell in the first */
|
||||
/* grid, and varies from num_pnts many cells to num_pnts * MAX_FACTOR */
|
||||
/* many cells. for small datasets with 8 * num_pnts * N_Percent < N_Trivial */
|
||||
/* only one grid with num_pnts * STD_FACTOR many cells is constructed. */
|
||||
/* */
|
||||
/* whether or not a tree or a grid is used depends on how non-uniformly the */
|
||||
/* points are distributed. if tons of points would end up in only very few */
|
||||
/* cells then the grid would be useless, and the nearest-neighbor search on */
|
||||
/* K points would exhibit O(K^2) complexity. as stated above, a hopefully */
|
||||
/* good guess of the distribution of the points is attempted by computing */
|
||||
/* the average number of points per cell within the first grid, for a random */
|
||||
/* sample of num_pnts * N_Percent points. let me clearly state that i do */
|
||||
/* realize that this approach has no theoretical guarantee to avoid a */
|
||||
/* quadratic complexity. (yes, it is possible to contrive datasets that fool */
|
||||
/* my approach: put half of the points extremely close to the lower-left */
|
||||
/* corner of the unit square, and the other half of the points extremely */
|
||||
/* close to the upper-right corner of the unit square. then even the */
|
||||
/* handling of the first grid for the first few percent of the points will */
|
||||
/* exhibit a quadratic time complexity...) and, yes, i could complicate the */
|
||||
/* code even further to catch such a situation. however, it seems that even */
|
||||
/* highly non-uniform data is handled nicely by the grid, and extreme cases */
|
||||
/* are handled by the tree. that is, i do not really feel a need to improve */
|
||||
/* this approach... */
|
||||
/* */
|
||||
|
||||
/* */
|
||||
/* get standard libraries */
|
||||
/* */
|
||||
#include <stdio.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 "numerics.h"
|
||||
|
||||
|
||||
|
||||
#define PAGE_SIZE 32768
|
||||
|
||||
#define N_Percent 0.03
|
||||
#define N_Trivial 1500
|
||||
#define N_Occupy 10
|
||||
#define MAX_FACTOR 4
|
||||
#define STD_FACTOR 2
|
||||
|
||||
|
||||
#define InsertIntoCell(k, ipnt) \
|
||||
{\
|
||||
assert(InGrid(k)); \
|
||||
assert(InPntsList(ipnt)); \
|
||||
\
|
||||
if (num_pnt_list >= max_num_pnt_list) { \
|
||||
max_num_pnt_list += PAGE_SIZE; \
|
||||
pnt_list = (pnt_node*) ReallocateArray(pnt_list, max_num_pnt_list, \
|
||||
sizeof(pnt_node), \
|
||||
"grid:pnt_list"); \
|
||||
} \
|
||||
\
|
||||
pnt_list[num_pnt_list].pnt = ipnt; \
|
||||
pnt_list[num_pnt_list].next = the_grid[k]; \
|
||||
the_grid[k] = num_pnt_list; \
|
||||
++num_pnt_list; \
|
||||
}
|
||||
|
||||
#define Convert(i, j, k) \
|
||||
{ \
|
||||
k = i * N_y + j; \
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define DetermineCell(x, y, i, j) \
|
||||
{ \
|
||||
assert(x > grid_min_x); \
|
||||
i = REAL_TO_INT((x - grid_min_x) / grid_x); \
|
||||
assert((i >= 0) && (i < max_num_raster_x)); \
|
||||
if (x < raster_x[i]) { \
|
||||
--i; \
|
||||
} \
|
||||
else if (x > raster_x[i+1]) { \
|
||||
++i; \
|
||||
} \
|
||||
assert((i >= 0) && (i < N_x)); \
|
||||
\
|
||||
assert(y > grid_min_y); \
|
||||
j = REAL_TO_INT((y - grid_min_y) / grid_y); \
|
||||
if (y < raster_y[j]) { \
|
||||
--j; \
|
||||
} \
|
||||
else if (y > raster_y[j+1]) { \
|
||||
++j; \
|
||||
} \
|
||||
assert((j >= 0) && (j < N_y)); \
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#define Invert(k, i, j) \
|
||||
{ \
|
||||
i = k / N_y; \
|
||||
assert((0 <= i) && (i < N_x)); \
|
||||
j = k - i * N_y; \
|
||||
assert((0 <= j) && (j < N_y)); \
|
||||
}
|
||||
|
||||
|
||||
#define ScanCell(i, j, k, p, q, ind_pnt, pnt_i, dist, dist_min, i_min) \
|
||||
{\
|
||||
Convert(i, j, k); \
|
||||
assert(InGrid(k)); \
|
||||
ind_pnt = the_grid[k]; \
|
||||
\
|
||||
while (ind_pnt != NIL) { \
|
||||
pnt_i = pnt_list[ind_pnt].pnt; \
|
||||
q = GetPntCoords(pnt_i); \
|
||||
dist = PntPntDistSq(p, q); \
|
||||
if (dist < dist_min) {\
|
||||
i_min = pnt_i; \
|
||||
dist_min = dist; \
|
||||
} \
|
||||
ind_pnt = pnt_list[ind_pnt].next; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
|
||||
void vroniObject::FreeGrid(void)
|
||||
{
|
||||
FreeMemory((void**) &the_grid, "grid:grid");
|
||||
raster_x.clear();
|
||||
raster_y.clear();
|
||||
FreeMemory((void**) &pnt_list, "grid:pnt_list");
|
||||
FreeMemory((void**) &first_N_pnts, "grid:first_N_pnts");
|
||||
|
||||
N = 0;
|
||||
N_x = 0;
|
||||
N_y = 0;
|
||||
num_pnt_list = 0;
|
||||
max_num_pnt_list = 0;
|
||||
max_num_grid = 0;
|
||||
max_num_raster_x = 0;
|
||||
max_num_raster_y = 0;
|
||||
first_counter = 0;
|
||||
grid_used = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void vroniObject::InitGrid(void)
|
||||
{
|
||||
int k;
|
||||
|
||||
assert(N > 0);
|
||||
assert(N_x * N_y <= N);
|
||||
|
||||
if (N > max_num_grid) {
|
||||
max_num_grid = N;
|
||||
the_grid = (int*) ReallocateArray(the_grid, max_num_grid, sizeof(int),
|
||||
"grid:grid");
|
||||
}
|
||||
|
||||
/* */
|
||||
/* initially, all grid cells are empty. */
|
||||
/* */
|
||||
for (k = 0; k < N; ++k) the_grid[k] = NIL;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
vr_bool vroniObject::InGrid(int cell)
|
||||
{
|
||||
return ((0 <= cell) && (cell < max_num_grid));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void vroniObject::InitRaster(void)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
if (N_x >= max_num_raster_x) {
|
||||
max_num_raster_x = N_x + 1;
|
||||
gentlyResizeSTLVector(raster_x, max_num_raster_x, "grid:raster_x");
|
||||
}
|
||||
if (N_y >= max_num_raster_y) {
|
||||
max_num_raster_y = N_y + 1;
|
||||
gentlyResizeSTLVector(raster_y, max_num_raster_y, "grid:raster_y");
|
||||
}
|
||||
|
||||
for (i = 0; i < N_x; ++i) raster_x[i] = grid_min_x + i * grid_x;
|
||||
raster_x[N_x] = grid_max_x;
|
||||
for (j = 0; j < N_y; ++j) raster_y[j] = grid_min_y + j * grid_y;
|
||||
raster_y[N_y] = grid_max_y;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void vroniObject::InitPntList(int number)
|
||||
{
|
||||
if (number > max_num_pnt_list) {
|
||||
max_num_pnt_list = number;
|
||||
pnt_list = (pnt_node*) ReallocateArray(pnt_list, max_num_pnt_list,
|
||||
sizeof(pnt_node),
|
||||
"grid:pnt_list");
|
||||
}
|
||||
num_pnt_list = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
#ifdef GRAPHICS
|
||||
|
||||
void vroniObject::DrawCell(int i, int j)
|
||||
{
|
||||
int i1, j1;
|
||||
coord p, q;
|
||||
|
||||
i1 = i + 1;
|
||||
j1 = j + 1;
|
||||
|
||||
p.x = raster_x[i];
|
||||
q.x = raster_x[i1];
|
||||
p.y = raster_y[j];
|
||||
q.y = raster_y[j];
|
||||
AddEdgeToBuffer(p.x, p.y, q.x, q.y, GridColor);
|
||||
p.y = raster_y[j1];
|
||||
q.y = raster_y[j1];
|
||||
AddEdgeToBuffer(p.x, p.y, q.x, q.y, GridColor);
|
||||
p.x = raster_x[i];
|
||||
q.x = raster_x[i];
|
||||
p.y = raster_y[j];
|
||||
q.y = raster_y[j1];
|
||||
AddEdgeToBuffer(p.x, p.y, q.x, q.y, GridColor);
|
||||
p.x = raster_x[i1];
|
||||
q.x = raster_x[i1];
|
||||
AddEdgeToBuffer(p.x, p.y, q.x, q.y, GridColor);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void vroniObject::DrawGrid(void)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < N_x; ++i) {
|
||||
for (j = 0; j < N_y; ++j) {
|
||||
DrawCell(i, j);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void vroniObject::SetUpGrid(int number)
|
||||
{
|
||||
double n_pnt;
|
||||
|
||||
assert(number >= 0);
|
||||
|
||||
n_pnt = sqrt((double) number);
|
||||
N_x = REAL_TO_INT(n_pnt * grid_a);
|
||||
N_y = REAL_TO_INT(n_pnt * grid_b);
|
||||
if (N_x < 1) N_x = 1;
|
||||
if (N_y < 1) N_y = 1;
|
||||
N = N_x * N_y;
|
||||
|
||||
grid_x = grid_delta_x / N_x;
|
||||
grid_y = grid_delta_y / N_y;
|
||||
|
||||
InitGrid();
|
||||
InitRaster();
|
||||
InitPntList(num_pnts);
|
||||
|
||||
grid_used = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void vroniObject::BuildGrid(void)
|
||||
{
|
||||
double eps;
|
||||
int number;
|
||||
|
||||
eps = ZERO * 1000.0;
|
||||
if (eq(eps, ZERO)) eps = 1.0e-10;
|
||||
|
||||
/* */
|
||||
/* determine the grid size and location */
|
||||
/* */
|
||||
grid_delta_x = (bb_max.x - bb_min.x) * 0.01;
|
||||
grid_delta_y = (bb_max.y - bb_min.y) * 0.01;
|
||||
if (le(grid_delta_x, eps)) grid_delta_x = eps;
|
||||
if (le(grid_delta_y, eps)) grid_delta_y = eps;
|
||||
grid_min_x = bb_min.x - grid_delta_x;
|
||||
grid_max_x = bb_max.x + grid_delta_x;
|
||||
grid_min_y = bb_min.y - grid_delta_y;
|
||||
grid_max_y = bb_max.y + grid_delta_y;
|
||||
grid_delta_x = grid_max_x - grid_min_x;
|
||||
grid_delta_y = grid_max_y - grid_min_y;
|
||||
assert(gt(grid_delta_x, ZERO));
|
||||
assert(gt(grid_delta_y, ZERO));
|
||||
|
||||
/* */
|
||||
/* initialize the grid raster; we adapt the grid somewhat according to */
|
||||
/* the aspect ratio of the bounding box of the points. roughly, the */
|
||||
/* number of cells equals the number of points. */
|
||||
/* */
|
||||
grid_a = sqrt(grid_delta_x / grid_delta_y);
|
||||
if (grid_a < 0.001) {
|
||||
grid_a = 0.001;
|
||||
grid_b = 1000.0;
|
||||
}
|
||||
else if (grid_a > 1000.0) {
|
||||
grid_a = 1000.0;
|
||||
grid_b = 0.001;
|
||||
}
|
||||
else {
|
||||
grid_b = 1.0 / grid_a;
|
||||
}
|
||||
|
||||
assert((N_Percent > 0.0) && (N_Percent <= 1.0));
|
||||
assert(N_Trivial >= 0);
|
||||
|
||||
/* */
|
||||
/* decide whether to use only one grid for all points, or a smaller grid */
|
||||
/* for the first few percent of the points, and a larger grid (or a tree) */
|
||||
/* for the full set of points. */
|
||||
/* */
|
||||
number = (int) (num_pnts * N_Percent);
|
||||
if (number < N_Trivial) number *= 2;
|
||||
if (number < N_Trivial) number *= 2;
|
||||
if (number < N_Trivial) number *= 2;
|
||||
|
||||
if (number >= N_Trivial) {
|
||||
N_Initial = number;
|
||||
first_N_pnts = (int*) ReallocateArray(first_N_pnts, N_Initial + 2,
|
||||
sizeof(int),
|
||||
"grid:first_N_pnts");
|
||||
}
|
||||
else {
|
||||
number = num_pnts;
|
||||
N_Initial = -1;
|
||||
}
|
||||
|
||||
SetUpGrid((int) (number * STD_FACTOR));
|
||||
|
||||
first_counter = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void vroniObject::DeletePntFromGrid(int index)
|
||||
{
|
||||
int i, j, k;
|
||||
coord p;
|
||||
|
||||
assert(InPntsList(index));
|
||||
|
||||
p = GetPntCoords(index);
|
||||
DetermineCell(p.x, p.y, i, j);
|
||||
Convert(i, j, k);
|
||||
assert(InGrid(k));
|
||||
|
||||
assert(pnt_list[the_grid[k]].pnt == index);
|
||||
the_grid[k] = pnt_list[the_grid[k]].next;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int vroniObject::InsertPntIntoGrid(int index, double *min_dist)
|
||||
{
|
||||
int i, j, k, n, m, i_min, pnt_i, ind_pnt;
|
||||
double x, y, dist, dist_min;
|
||||
int num;
|
||||
double factor;
|
||||
coord p, q;
|
||||
|
||||
assert(InPntsList(index));
|
||||
|
||||
p = GetPntCoords(index);
|
||||
DetermineCell(p.x, p.y, i, j);
|
||||
Convert(i, j, k);
|
||||
assert(InGrid(k));
|
||||
|
||||
dist_min = DBL_MAX;
|
||||
i_min = NIL;
|
||||
ScanCell(i, j, k, p, q, ind_pnt, pnt_i, dist, dist_min, i_min);
|
||||
*min_dist = dist_min;
|
||||
|
||||
if (gt(dist_min, ZERO2)) {
|
||||
InsertIntoCell(k, index);
|
||||
|
||||
if (first_counter <= N_Initial) {
|
||||
assert(first_counter >= 0);
|
||||
if (first_counter < N_Initial) {
|
||||
first_N_pnts[first_counter] = index;
|
||||
}
|
||||
else {
|
||||
first_N_pnts[first_counter] = index;
|
||||
num = 0;
|
||||
for (n = 0; n < N; ++n) {
|
||||
if (the_grid[n] != NIL) ++num;
|
||||
}
|
||||
assert(num > 0);
|
||||
factor = N_Initial / ((double) num);
|
||||
if (factor > N_Occupy) {
|
||||
grid_used = false;
|
||||
assert(N_Initial >= 0);
|
||||
i_min = InitTree(num_pnts, first_N_pnts, N_Initial, min_dist);
|
||||
FreeGrid();
|
||||
}
|
||||
else {
|
||||
if (factor < STD_FACTOR) factor = STD_FACTOR;
|
||||
else if (factor > MAX_FACTOR) factor = MAX_FACTOR;
|
||||
SetUpGrid(REAL_TO_INT(num_pnts * factor));
|
||||
for (n = 0; n < N_Initial; ++n) {
|
||||
assert(InPntsList(first_N_pnts[n]));
|
||||
m = first_N_pnts[n];
|
||||
x = GetPntCoords(m).x;
|
||||
y = GetPntCoords(m).y;
|
||||
DetermineCell(x, y, i, j);
|
||||
Convert(i, j, k);
|
||||
assert(InGrid(k));
|
||||
InsertIntoCell(k, m);
|
||||
}
|
||||
assert(index == first_N_pnts[N_Initial]);
|
||||
DetermineCell(p.x, p.y, i, j);
|
||||
Convert(i, j, k);
|
||||
assert(InGrid(k));
|
||||
ScanCell(i, j, k, p, q, ind_pnt, pnt_i, dist, dist_min, i_min);
|
||||
*min_dist = dist_min;
|
||||
if (gt(dist_min, ZERO2)) InsertIntoCell(k, index);
|
||||
}
|
||||
}
|
||||
++first_counter;
|
||||
}
|
||||
}
|
||||
|
||||
return i_min;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int vroniObject::FindNearestNeighborGrid(int index, int i_min, double *min_dist)
|
||||
{
|
||||
int i, j, k, ind_pnt, pnt_i, i1, i2, j1, j2, m;
|
||||
double dist, dist_min, delta;
|
||||
vr_bool lft, rgt, top, bot;
|
||||
coord p, q;
|
||||
|
||||
assert(InPntsList(index));
|
||||
dist_min = *min_dist;
|
||||
p = GetPntCoords(index);
|
||||
|
||||
/* */
|
||||
/* find the cell that contains the point pnts[index] whose nearest */
|
||||
/* neighbor is sought. */
|
||||
/* */
|
||||
DetermineCell(p.x, p.y, i, j);
|
||||
|
||||
/* */
|
||||
/* search the cells around position i, j until a nearest neighbor is */
|
||||
/* found. we terminate the search as soon as the nearest-neighbor circle */
|
||||
/* does not intersect any neighboring cell that has not yet been searched.*/
|
||||
/* */
|
||||
i1 = i2 = i;
|
||||
j1 = j2 = j;
|
||||
|
||||
lft = rgt = top = bot = true;
|
||||
while (lft || rgt || top || bot) {
|
||||
if (lft) {
|
||||
if (i1 > 0) {
|
||||
delta = p.x - raster_x[i1];
|
||||
delta = delta * delta;
|
||||
if (delta < dist_min) {
|
||||
--i1;
|
||||
for (j = j1; j <= j2; ++j) {
|
||||
ScanCell(i1, j, k, p, q, ind_pnt, pnt_i, dist, dist_min,
|
||||
i_min);
|
||||
}
|
||||
}
|
||||
else {
|
||||
lft = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
lft = false;
|
||||
}
|
||||
}
|
||||
if (rgt) {
|
||||
m = i2 + 1;
|
||||
if (m < N_x) {
|
||||
delta = p.x - raster_x[m];
|
||||
delta = delta * delta;
|
||||
if (delta < dist_min) {
|
||||
i2 = m;
|
||||
for (j = j1; j <= j2; ++j) {
|
||||
ScanCell(i2, j, k, p, q, ind_pnt, pnt_i, dist, dist_min,
|
||||
i_min);
|
||||
}
|
||||
}
|
||||
else {
|
||||
rgt = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
rgt = false;
|
||||
}
|
||||
}
|
||||
if (bot) {
|
||||
if (j1 > 0) {
|
||||
delta = p.y - raster_y[j1];
|
||||
delta = delta * delta;
|
||||
if (delta < dist_min) {
|
||||
--j1;
|
||||
for (i = i1; i <= i2; ++i) {
|
||||
ScanCell(i, j1, k, p, q, ind_pnt, pnt_i, dist, dist_min,
|
||||
i_min);
|
||||
}
|
||||
}
|
||||
else {
|
||||
bot = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
bot = false;
|
||||
}
|
||||
}
|
||||
if (top) {
|
||||
m = j2 + 1;
|
||||
if (m < N_y) {
|
||||
delta = p.y - raster_y[m];
|
||||
delta = delta * delta;
|
||||
if (delta < dist_min) {
|
||||
j2 = m;
|
||||
for (i = i1; i <= i2; ++i) {
|
||||
ScanCell(i, j2, k, p, q, ind_pnt, pnt_i, dist, dist_min,
|
||||
i_min);
|
||||
}
|
||||
}
|
||||
else {
|
||||
top = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
top = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(i_min != NIL);
|
||||
assert(dist_min < DBL_MAX);
|
||||
*min_dist = dist_min;
|
||||
|
||||
return i_min;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 1999-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 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef VRONI_HEADER_H
|
||||
#define VRONI_HEADER_H
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,243 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 2003--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" 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: (+4 662) 8044-611 */
|
||||
/* Voice Mail: (+4 662) 8044-6304 */
|
||||
/* Snail Mail: Martin Held */
|
||||
/* FB Informatik */
|
||||
/* Universitaet Salzburg */
|
||||
/* A-5020 Salzburg, Austria */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* this file contains the subroutines and functions used for manipulating */
|
||||
/* a heap-based priority queue. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
/* */
|
||||
/* get my header files */
|
||||
/* */
|
||||
#include "vroni_object.h"
|
||||
|
||||
|
||||
#define HEAP_BLOCK_SIZE 32768
|
||||
|
||||
|
||||
|
||||
void vroniObject::StoreHeapData(int idx, double s_key, int s_ref)
|
||||
{
|
||||
assert(InHeapInsert(idx));
|
||||
heap[idx].key = s_key;
|
||||
heap[idx].ref = s_ref;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void vroniObject::GetHeapData(int idx, double *s_key, int *s_ref)
|
||||
{
|
||||
assert(InHeap(idx));
|
||||
*s_key = heap[idx].key;
|
||||
*s_ref = heap[idx].ref;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
vr_bool vroniObject::InHeapInsert(int idx)
|
||||
{
|
||||
return ((idx >= 0) && (idx < max_num_heap));
|
||||
}
|
||||
|
||||
|
||||
vr_bool vroniObject::InHeap(int idx)
|
||||
{
|
||||
return ((idx >= 0) && (idx < num_heap) && (num_heap < max_num_heap));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void vroniObject::FreeHeap(void)
|
||||
{
|
||||
heap.clear();
|
||||
|
||||
max_num_heap = 0;
|
||||
num_heap = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void vroniObject::DumpOnHeap(double_arg key, int ref)
|
||||
{
|
||||
if (num_heap >= max_num_heap) {
|
||||
max_num_heap += HEAP_BLOCK_SIZE;
|
||||
gentlyResizeSTLVector(heap, max_num_heap, "heap:heap");
|
||||
}
|
||||
|
||||
StoreHeapData(num_heap, key, ref);
|
||||
++num_heap;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void vroniObject::UpdateHeap(double_arg key, int ref)
|
||||
{
|
||||
int i, j, j1, j2;
|
||||
|
||||
i = 0;
|
||||
j1 = 2 * i + 1;
|
||||
j2 = j1 + 1;
|
||||
|
||||
while (j2 < num_heap) {
|
||||
if (heap[j1].key < heap[j2].key) j = j1;
|
||||
else j = j2;
|
||||
if (heap[j].key < key) {
|
||||
heap[i] = heap[j];
|
||||
i = j;
|
||||
j1 = 2 * i + 1;
|
||||
j2 = j1 + 1;
|
||||
}
|
||||
else {
|
||||
j1 = j2 = num_heap;
|
||||
}
|
||||
}
|
||||
|
||||
if (j1 < num_heap) {
|
||||
if (heap[j1].key < key) {
|
||||
heap[i] = heap[j1];
|
||||
StoreHeapData(j1, key, ref);
|
||||
}
|
||||
else {
|
||||
StoreHeapData(i, key, ref);
|
||||
}
|
||||
}
|
||||
else {
|
||||
StoreHeapData(i, key, ref);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void vroniObject::ExtendHeap(double_arg key, int ref)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
j = num_heap;
|
||||
++num_heap;
|
||||
|
||||
if (num_heap >= max_num_heap) {
|
||||
max_num_heap += HEAP_BLOCK_SIZE;
|
||||
gentlyResizeSTLVector(heap, max_num_heap, "heap:heap");
|
||||
}
|
||||
|
||||
while (j > 0) {
|
||||
i = (j - 1) / 2;
|
||||
if (heap[i].key > key) {
|
||||
heap[j] = heap[i];
|
||||
j = i;
|
||||
}
|
||||
else {
|
||||
StoreHeapData(j, key, ref);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
StoreHeapData(0, key, ref);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void vroniObject::InsertIntoHeap(double_arg key, int ref)
|
||||
{
|
||||
if (deleted) {
|
||||
UpdateHeap(key, ref);
|
||||
}
|
||||
else {
|
||||
ExtendHeap(key, ref);
|
||||
}
|
||||
deleted = false;
|
||||
not_updated = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
vr_bool vroniObject::DeleteFromHeap(double *key, int *ref)
|
||||
{
|
||||
if (deleted && not_updated) {
|
||||
if (num_heap <= 1) {
|
||||
num_heap = 0;
|
||||
return false;
|
||||
}
|
||||
--num_heap;
|
||||
UpdateHeap(heap[num_heap].key, heap[num_heap].ref);
|
||||
not_updated = false;
|
||||
deleted = false;
|
||||
}
|
||||
else if (num_heap <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GetHeapData(0, key, ref);
|
||||
|
||||
not_updated = true;
|
||||
deleted = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void vroniObject::InitHeap(void)
|
||||
{
|
||||
if(heap.size() == 0) {
|
||||
max_num_heap = 0;
|
||||
}
|
||||
if (num_pnts > max_num_heap) {
|
||||
max_num_heap = num_pnts;
|
||||
gentlyResizeSTLVector(heap, max_num_heap, "heap:heap");
|
||||
}
|
||||
num_heap = 0;
|
||||
deleted = false;
|
||||
not_updated = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void vroniObject::ResetHeap(void)
|
||||
{
|
||||
num_heap = 0;
|
||||
deleted = false;
|
||||
not_updated = false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
+1728
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,88 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 1999-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.c". */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* 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 */
|
||||
/* Universitaet Salzburg */
|
||||
/* FB Informatik */
|
||||
/* A-5020 Salzburg, Austria */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
||||
#ifndef VRONI_INTERSECTIONS_H
|
||||
#define VRONI_INTERSECTIONS_H
|
||||
|
||||
#include <string.h>
|
||||
|
||||
//#ifdef VRONI_INFO
|
||||
#ifdef VRONI_DBG_WARN
|
||||
#define IntWarning(S1, I1, S2, I2) \
|
||||
{\
|
||||
if (verbose) { \
|
||||
printf("\nwarning in ComputeVD() - the %s %d and the %s %d intersect!\n",\
|
||||
S1, I1, S2, I2); \
|
||||
if (strcmp(S1, "pnt") == 0) { \
|
||||
printf("pnt %d: (%20.16f,%20.16f)\n", I1, \
|
||||
UnscaleX(pnts[I1].p.x), \
|
||||
UnscaleY(pnts[I1].p.y)); \
|
||||
} \
|
||||
else if (strcmp(S1, "seg") == 0) { \
|
||||
printf("seg %d: (%20.16f,%20.16f) to (%20.16f,%20.16f)\n", I1, \
|
||||
UnscaleX(pnts[segs[I1].i1].p.x), \
|
||||
UnscaleY(pnts[segs[I1].i1].p.y), \
|
||||
UnscaleX(pnts[segs[I1].i2].p.x), \
|
||||
UnscaleY(pnts[segs[I1].i2].p.y)); \
|
||||
} \
|
||||
else if (strcmp(S1, "arc") == 0) { \
|
||||
printf("arc %d: (%20.16f,%20.16f) to (%20.16f,%20.16f) centered at (%20.16f,%20.16f)\n", I1, \
|
||||
UnscaleX(pnts[arcs[I1].i1].p.x), \
|
||||
UnscaleY(pnts[arcs[I1].i1].p.y), \
|
||||
UnscaleX(pnts[arcs[I1].i2].p.x), \
|
||||
UnscaleY(pnts[arcs[I1].i2].p.y), \
|
||||
UnscaleX(arcs[I1].c.x), \
|
||||
UnscaleY(arcs[I1].c.y)); \
|
||||
} \
|
||||
if (strcmp(S2, "pnt") == 0) { \
|
||||
printf("pnt %d: (%20.16f,%20.16f)\n", I2, \
|
||||
UnscaleX(pnts[I2].p.x), \
|
||||
UnscaleY(pnts[I2].p.y)); \
|
||||
} \
|
||||
else if (strcmp(S2, "seg") == 0) { \
|
||||
printf("seg %d: (%20.16f,%20.16f) to (%20.16f,%20.16f)\n", I2, \
|
||||
UnscaleX(pnts[segs[I2].i1].p.x), \
|
||||
UnscaleY(pnts[segs[I2].i1].p.y), \
|
||||
UnscaleX(pnts[segs[I2].i2].p.x), \
|
||||
UnscaleY(pnts[segs[I2].i2].p.y)); \
|
||||
} \
|
||||
else if (strcmp(S2, "arc") == 0) { \
|
||||
printf("arc %d: (%20.16f,%20.16f) to (%20.16f,%20.16f) centered at (%20.16f,%20.16f)\n", I2, \
|
||||
UnscaleX(pnts[arcs[I2].i1].p.x), \
|
||||
UnscaleY(pnts[arcs[I2].i1].p.y), \
|
||||
UnscaleX(pnts[arcs[I2].i2].p.x), \
|
||||
UnscaleY(pnts[arcs[I2].i2].p.y), \
|
||||
UnscaleX(arcs[I2].c.x), \
|
||||
UnscaleY(arcs[I2].c.y)); \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
#else
|
||||
#define IntWarning(S1, I1, S2, I2) {}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
+602
@@ -0,0 +1,602 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 1999-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 <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* */
|
||||
/* get my header files */
|
||||
/* */
|
||||
#include "fpkernel.h"
|
||||
#include "vronivector.h"
|
||||
#include "vroni_object.h"
|
||||
#include "defs.h"
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* the following functions read data encoded in one of my input formats. */
|
||||
/* they rely on basic "parsers" to read simple entities that are provided in */
|
||||
/* io_parse.cc. you are welcome to adapt those parsers to your needs. also, */
|
||||
/* i'll happily add exterior application macros at points of your choice. if */
|
||||
/* such (mostly non-invasive) changes should not suffice to parse your input */
|
||||
/* then i'd strongly suggest to implement your own input functions, using my */
|
||||
/* code as a blueprint for your implementation. please understand that there */
|
||||
/* is no chance for me to provide parsers that are flexible enough to handle */
|
||||
/* arbitrary input formats yet simple enough to be understood by folks with */
|
||||
/* perhaps only a casual knowledge and experience in C/C++ programming... */
|
||||
/* */
|
||||
|
||||
|
||||
void vroniObject::ReadContour(FILE *input)
|
||||
{
|
||||
int i, i0, i1, number, orientation, attr, last_attr;
|
||||
double xc1, yc1, xc2, yc2, xc3, yc3;
|
||||
#ifdef EXT_APPL_SITES
|
||||
eas_type eas_data;
|
||||
#endif
|
||||
|
||||
/* */
|
||||
/* get the number of contour elements */
|
||||
/* */
|
||||
if (!ReadNumber(input, &number))
|
||||
throw std::runtime_error("VRONI error: ReadContour() - premature end of file!");
|
||||
if (number < 0) number = - number;
|
||||
if (number < 1)
|
||||
throw std::runtime_error("VRONI error: ReadContour() - less than one vertex!");
|
||||
InitStoragePnts(number + 10);
|
||||
InitStorageSegs(number + 10);
|
||||
|
||||
/* */
|
||||
/* read the orientation of the contour. (we don't trust it, though.) */
|
||||
/* */
|
||||
if (!ReadOptionalNumber(input, &orientation))
|
||||
throw std::runtime_error("VRONI error: ReadContour() - premature end of file!");
|
||||
|
||||
/* */
|
||||
/* read the start point of the first segment/arc */
|
||||
/* */
|
||||
if (!ReadNumber(input, &attr))
|
||||
throw std::runtime_error("VRONI error: ReadContour() - premature end of file!");
|
||||
if ((attr < -1) || (attr > 1))
|
||||
throw std::runtime_error("VRONI error: ReadContour() - unknown data format!");
|
||||
if (!ReadVectorData(input, &xc1, &yc1))
|
||||
throw std::runtime_error("VRONI error: ReadContour() - premature end of file!");
|
||||
#ifdef EXT_APPL_PNTS
|
||||
i1 = HandlePnt(xc1, yc1, eap_NIL);
|
||||
#else
|
||||
i1 = HandlePnt(xc1, yc1);
|
||||
#endif
|
||||
|
||||
i0 = i1;
|
||||
last_attr = attr;
|
||||
|
||||
for (i = 1; i < number; ++i) {
|
||||
/* */
|
||||
/* read the individual segments/arcs */
|
||||
/* */
|
||||
#ifdef EXT_APPL_SITES
|
||||
if (!ReadSiteData(input, &xc2, &yc2, &eas_data))
|
||||
#else
|
||||
if (!ReadSiteData(input, &xc2, &yc2))
|
||||
#endif
|
||||
throw std::runtime_error("VRONI error: ReadContour() - premature end of file!");
|
||||
if (!ReadNumber(input, &attr))
|
||||
throw std::runtime_error("VRONI error: ReadContour() - premature end of file!");
|
||||
if (!ReadVectorData(input, &xc3, &yc3))
|
||||
throw std::runtime_error("VRONI error: ReadContour() - premature end of file!");
|
||||
|
||||
if (last_attr == SEG) {
|
||||
/* */
|
||||
/* the last object was a line segment */
|
||||
/* */
|
||||
#ifdef EXT_APPL_SITES
|
||||
AddSeg(&i1, xc3, yc3, eas_data);
|
||||
#else
|
||||
AddSeg(&i1, xc3, yc3);
|
||||
#endif
|
||||
}
|
||||
else if ((last_attr == -ARC) || (last_attr == ARC)) {
|
||||
/* */
|
||||
/* the last object was a circular arc */
|
||||
/* */
|
||||
#ifdef EXT_APPL_SITES
|
||||
AddArc(&i1, xc3, yc3, xc2, yc2, last_attr, eas_data);
|
||||
#else
|
||||
AddArc(&i1, xc3, yc3, xc2, yc2, last_attr);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
throw std::runtime_error("VRONI error: ReadContour() - unknown data format!");
|
||||
|
||||
last_attr = attr;
|
||||
}
|
||||
|
||||
/* */
|
||||
/* close the contour */
|
||||
/* */
|
||||
#ifdef EXT_APPL_SITES
|
||||
if (!ReadSiteData(input, &xc2, &yc2, &eas_data))
|
||||
#else
|
||||
if (!ReadSiteData(input, &xc2, &yc2))
|
||||
#endif
|
||||
throw std::runtime_error("VRONI error: ReadContour() - premature end of file!");
|
||||
|
||||
if (last_attr == SEG) {
|
||||
/* */
|
||||
/* the last object was a line segment */
|
||||
/* */
|
||||
#ifdef EXT_APPL_SITES
|
||||
CloseSeg(i1, i0, eas_data);
|
||||
#else
|
||||
CloseSeg(i1, i0);
|
||||
#endif
|
||||
}
|
||||
else if ((last_attr == -ARC) || (last_attr == ARC)) {
|
||||
/* */
|
||||
/* the last object was a circular arc */
|
||||
/* */
|
||||
#ifdef EXT_APPL_SITES
|
||||
CloseArc(i1, i0, xc2, yc2, last_attr, eas_data);
|
||||
#else
|
||||
CloseArc(i1, i0, xc2, yc2, last_attr);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
throw std::runtime_error("VRONI error: ReadContour() - unknown data format!");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* this function reads a simply-connected or multiply-connected polygon */
|
||||
/* specified in my format for curvilinear data. */
|
||||
/* */
|
||||
void vroniObject::ReadPolygon(char input_file[], vr_bool *new_input)
|
||||
{
|
||||
double xc1, yc1, xc2, yc2;
|
||||
int i, number;
|
||||
FILE *input;
|
||||
|
||||
input = OpenFileVD(input_file, "r");
|
||||
|
||||
/* */
|
||||
/* read enclosing bounding box (we don't trust it, though) */
|
||||
/* */
|
||||
if (!ReadOptionalCoord(input, &xc1))
|
||||
throw std::runtime_error("VRONI error: ReadPolygon() - premature end of file!");
|
||||
if (!ReadOptionalCoord(input, &yc1))
|
||||
throw std::runtime_error("VRONI error: ReadPolygon() - premature end of file!");
|
||||
if (!ReadOptionalCoord(input, &xc2))
|
||||
throw std::runtime_error("VRONI error: ReadPolygon() - premature end of file!");
|
||||
if (!ReadOptionalCoord(input, &yc2))
|
||||
throw std::runtime_error("VRONI error: ReadPolygon() - premature end of file!");
|
||||
|
||||
/* */
|
||||
/* get the number of contours */
|
||||
/* */
|
||||
if (!ReadNumber(input, &number))
|
||||
throw std::runtime_error("VRONI error: ReadPolygon() - Premature end of file!");
|
||||
|
||||
for (i = 0; i < number; ++i) {
|
||||
/* */
|
||||
/* handle each contour */
|
||||
/* */
|
||||
ReadContour(input);
|
||||
}
|
||||
|
||||
fclose(input);
|
||||
*new_input = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* this function reads a simply-connected polygon specified in my simplified */
|
||||
/* format for polygons. */
|
||||
/* */
|
||||
void vroniObject::ReadPoly(char input_file[], vr_bool *new_input)
|
||||
{
|
||||
double xc1, yc1;
|
||||
int i0 = NIL, i1, number = 0;
|
||||
FILE *input;
|
||||
#ifdef EXT_APPL_SITES
|
||||
eas_type eas_data, eas_data_0;
|
||||
#endif
|
||||
|
||||
input = OpenFileVD(input_file, "r");
|
||||
|
||||
/* */
|
||||
/* get the number of contour elements */
|
||||
/* */
|
||||
if (!ReadOptionalNumber(input, &number))
|
||||
throw std::runtime_error("VRONI error: ReadPoly() - premature end of file!");
|
||||
if (number > 0) {
|
||||
InitPnts(number + 10);
|
||||
InitSegs(number + 10);
|
||||
}
|
||||
|
||||
/* */
|
||||
/* read the start point of the first segment */
|
||||
/* */
|
||||
#ifdef EXT_APPL_SITES
|
||||
if (!ReadSiteData(input, &xc1, &yc1, &eas_data_0))
|
||||
#else
|
||||
if (!ReadSiteData(input, &xc1, &yc1))
|
||||
#endif
|
||||
throw std::runtime_error("VRONI error: ReadPoly() - premature end of file!");
|
||||
#ifdef EXT_APPL_PNTS
|
||||
i1 = HandlePnt(xc1, yc1, eap_NIL);
|
||||
#else
|
||||
i1 = HandlePnt(xc1, yc1);
|
||||
#endif
|
||||
i0 = i1;
|
||||
|
||||
/* */
|
||||
/* read the individual segments */
|
||||
/* */
|
||||
#ifdef EXT_APPL_SITES
|
||||
while (ReadSiteData(input, &xc1, &yc1, &eas_data)) {
|
||||
AddSeg(&i1, xc1, yc1, eas_data);
|
||||
}
|
||||
#else
|
||||
while (ReadSiteData(input, &xc1, &yc1)) {
|
||||
AddSeg(&i1, xc1, yc1);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* */
|
||||
/* close the polygon */
|
||||
/* */
|
||||
#ifdef EXT_APPL_SITES
|
||||
CloseSeg(i1, i0, eas_data_0);
|
||||
#else
|
||||
CloseSeg(i1, i0);
|
||||
#endif
|
||||
|
||||
fclose(input);
|
||||
*new_input = (i0 != NIL);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* this function reads a list of points. */
|
||||
/* */
|
||||
void vroniObject::ReadPoints(char input_file[], vr_bool *new_input)
|
||||
{
|
||||
double xc1, yc1;
|
||||
int i0 = NIL, number = NIL;
|
||||
#ifdef EXT_APPL_PNTS
|
||||
eap_type eap_data;
|
||||
#endif
|
||||
FILE *input;
|
||||
|
||||
input = OpenFileVD(input_file, "r");
|
||||
|
||||
/* */
|
||||
/* if known, get the number of points. (if unknown, we will allocate */
|
||||
/* memory "on the fly" as necessary.) */
|
||||
/* */
|
||||
if (!ReadOptionalNumber(input, &number))
|
||||
throw std::runtime_error("VRONI error: ReadPoints() - premature end of file!");
|
||||
if (number > 0) InitPnts(number + 10);
|
||||
|
||||
#ifdef EXT_APPL_PNTS
|
||||
while (ReadPntData(input, &xc1, &yc1, &eap_data)) {
|
||||
i0 = HandlePnt(xc1, yc1, eap_data);
|
||||
}
|
||||
#else
|
||||
while (ReadPntData(input, &xc1, &yc1)) {
|
||||
i0 = HandlePnt(xc1, yc1);
|
||||
}
|
||||
#endif
|
||||
|
||||
fclose(input);
|
||||
*new_input = (i0 != NIL);
|
||||
isolated_pnts = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* this function reads a set of polygonal chains. */
|
||||
/* */
|
||||
void vroniObject::ReadPolylines(char input_file[], vr_bool *new_input)
|
||||
{
|
||||
double xc1, yc1, xc0, yc0;
|
||||
int i, i1 = NIL, number = 0, i0;
|
||||
FILE *input;
|
||||
#ifdef EXT_APPL_SITES
|
||||
eas_type eas_data, eas_data_0;
|
||||
#endif
|
||||
|
||||
input = OpenFileVD(input_file, "r");
|
||||
|
||||
while (ReadNumber(input, &number)) {
|
||||
/* */
|
||||
/* read the number of vertices of the next chain */
|
||||
/* */
|
||||
if (number < 1)
|
||||
throw std::runtime_error("VRONI error: ReadPolylines() - less than one vertex per chain!");
|
||||
|
||||
/* */
|
||||
/* read first vertex of the next chain */
|
||||
/* */
|
||||
#ifdef EXT_APPL_SITES
|
||||
if (!ReadSiteData(input, &xc1, &yc1, &eas_data_0))
|
||||
#else
|
||||
if (!ReadSiteData(input, &xc1, &yc1))
|
||||
#endif
|
||||
throw std::runtime_error("VRONI error: ReadPolylines() - premature end of file!");
|
||||
#ifdef EXT_APPL_PNTS
|
||||
i1 = HandlePnt(xc1, yc1, eap_NIL);
|
||||
#else
|
||||
i1 = HandlePnt(xc1, yc1);
|
||||
#endif
|
||||
i0 = i1;
|
||||
xc0 = xc1;
|
||||
yc0 = yc1;
|
||||
if (number == 1) isolated_pnts = true;
|
||||
--number;
|
||||
for (i = 1; i < number; ++i) {
|
||||
/* */
|
||||
/* read the remaining vertices of this chain */
|
||||
/* */
|
||||
#ifdef EXT_APPL_SITES
|
||||
if (!ReadSiteData(input, &xc1, &yc1, &eas_data))
|
||||
#else
|
||||
if (!ReadSiteData(input, &xc1, &yc1))
|
||||
#endif
|
||||
throw std::runtime_error("VRONI error: ReadPolylines() - premature end of file!");
|
||||
#ifdef EXT_APPL_SITES
|
||||
AddSeg(&i1, xc1, yc1, eas_data);
|
||||
#else
|
||||
AddSeg(&i1, xc1, yc1);
|
||||
#endif
|
||||
}
|
||||
if (number > 0) {
|
||||
#ifdef EXT_APPL_SITES
|
||||
if (!ReadSiteData(input, &xc1, &yc1, &eas_data))
|
||||
#else
|
||||
if (!ReadSiteData(input, &xc1, &yc1))
|
||||
#endif
|
||||
throw std::runtime_error("VRONI error: ReadPolylines() - premature end of file!");
|
||||
if ((xc0 != xc1) || (yc0 != yc1)) {
|
||||
#ifdef EXT_APPL_SITES
|
||||
AddSeg(&i1, xc1, yc1, eas_data);
|
||||
#else
|
||||
AddSeg(&i1, xc1, yc1);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
#ifdef EXT_APPL_SITES
|
||||
CloseSeg(i1, i0, eas_data_0);
|
||||
#else
|
||||
CloseSeg(i1, i0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(input);
|
||||
*new_input = ((number != 0) || isolated_pnts);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* this function reads a set of polygons specified in .bdm format */
|
||||
/* */
|
||||
void vroniObject::ReadBDM(char input_file[], vr_bool *new_input)
|
||||
{
|
||||
double xc1, yc1;
|
||||
int i, i1 = NIL, i0 = NIL, number = 0;
|
||||
FILE *input;
|
||||
#ifdef EXT_APPL_SITES
|
||||
eas_type eas_data, eas_data_0;
|
||||
#endif
|
||||
|
||||
input = OpenFileVD(input_file, "r");
|
||||
|
||||
while (ReadNumber(input, &number)) {
|
||||
/* */
|
||||
/* read the number of vertices of the next chain */
|
||||
/* */
|
||||
if (number < 3)
|
||||
throw std::runtime_error("VRONI error: ReadBDM() - less than three vertices per polygon!");
|
||||
|
||||
/* */
|
||||
/* read first vertex of the next polygon */
|
||||
/* */
|
||||
#ifdef EXT_APPL_SITES
|
||||
if (!ReadSiteData(input, &xc1, &yc1, &eas_data_0))
|
||||
#else
|
||||
if (!ReadSiteData(input, &xc1, &yc1))
|
||||
#endif
|
||||
throw std::runtime_error("VRONI error: ReadBDM() - premature end of file!");
|
||||
#ifdef EXT_APPL_PNTS
|
||||
i1 = HandlePnt(xc1, yc1, eap_NIL);
|
||||
#else
|
||||
i1 = HandlePnt(xc1, yc1);
|
||||
#endif
|
||||
i0 = i1;
|
||||
|
||||
for (i = 1; i < number; ++i) {
|
||||
/* */
|
||||
/* read the remaining vertices of this chain */
|
||||
/* */
|
||||
#ifdef EXT_APPL_SITES
|
||||
if (!ReadSiteData(input, &xc1, &yc1, &eas_data))
|
||||
#else
|
||||
if (!ReadSiteData(input, &xc1, &yc1))
|
||||
#endif
|
||||
throw std::runtime_error("VRONI error: ReadBDM() - premature end of file!");
|
||||
#ifdef EXT_APPL_SITES
|
||||
AddSeg(&i1, xc1, yc1, eas_data);
|
||||
#else
|
||||
AddSeg(&i1, xc1, yc1);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* */
|
||||
/* close the polygon */
|
||||
/* */
|
||||
#ifdef EXT_APPL_SITES
|
||||
CloseSeg(i1, i0, eas_data_0);
|
||||
#else
|
||||
CloseSeg(i1, i0);
|
||||
#endif
|
||||
}
|
||||
|
||||
fclose(input);
|
||||
*new_input = (number != 0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* this function reads individual sites (points, segments, arcs) from a file.*/
|
||||
/* */
|
||||
/* data format: */
|
||||
/* */
|
||||
/* segment */
|
||||
/* 0 */
|
||||
/* x_start y_start x_end y_end */
|
||||
/* point */
|
||||
/* 2 */
|
||||
/* x y */
|
||||
/* arc CCW */
|
||||
/* 1 */
|
||||
/* x_start y_start x_end y_end x_center y_center */
|
||||
/* arc CW */
|
||||
/* -1 */
|
||||
/* x_start y_start x_end y_end x_center y_center */
|
||||
/* */
|
||||
/* */
|
||||
void vroniObject::ReadSites(char input_file[], vr_bool *new_input)
|
||||
{
|
||||
double xc1, yc1, xc2, yc2, xc3, yc3;
|
||||
int attr;
|
||||
FILE *input;
|
||||
#ifdef EXT_APPL_PNTS
|
||||
eap_type eap_data;
|
||||
#endif
|
||||
#ifdef EXT_APPL_SITES
|
||||
eas_type eas_data;
|
||||
#endif
|
||||
|
||||
input = OpenFileVD(input_file, "r");
|
||||
|
||||
while (ReadNumber(input, &attr)) {
|
||||
if (attr == PNT) {
|
||||
#ifdef EXT_APPL_PNTS
|
||||
if (!ReadPntData(input, &xc1, &yc1, &eap_data))
|
||||
#else
|
||||
if (!ReadPntData(input, &xc1, &yc1))
|
||||
#endif
|
||||
throw std::runtime_error("VRONI error: ReadSites() - premature end of file!");
|
||||
#ifdef EXT_APPL_PNTS
|
||||
(void) HandlePnt(xc1, yc1, eap_data);
|
||||
#else
|
||||
(void) HandlePnt(xc1, yc1);
|
||||
#endif
|
||||
*new_input = true;
|
||||
isolated_pnts = true;
|
||||
}
|
||||
else if (attr == SEG) {
|
||||
if (!ReadVectorData(input, &xc1, &yc1))
|
||||
throw std::runtime_error("VRONI error: ReadSites() - premature end of file!");
|
||||
#ifdef EXT_APPL_SITES
|
||||
if (!ReadSiteData(input, &xc2, &yc2, &eas_data))
|
||||
#else
|
||||
if (!ReadSiteData(input, &xc2, &yc2))
|
||||
#endif
|
||||
throw std::runtime_error("VRONI error: ReadSites() - premature end of file!");
|
||||
#ifdef EXT_APPL_SITES
|
||||
HandleSeg(xc1, yc1, xc2, yc2, eas_data);
|
||||
#else
|
||||
HandleSeg(xc1, yc1, xc2, yc2);
|
||||
#endif
|
||||
*new_input = true;
|
||||
}
|
||||
else if ((attr == ARC) || (attr == -ARC)) {
|
||||
if (!ReadVectorData(input, &xc1, &yc1))
|
||||
throw std::runtime_error("VRONI error: ReadSites() - premature end of file!");
|
||||
if (!ReadVectorData(input, &xc2, &yc2))
|
||||
throw std::runtime_error("VRONI error: ReadSites() - premature end of file!");
|
||||
#ifdef EXT_APPL_SITES
|
||||
if (!ReadSiteData(input, &xc3, &yc3, &eas_data))
|
||||
#else
|
||||
if (!ReadSiteData(input, &xc3, &yc3))
|
||||
#endif
|
||||
throw std::runtime_error("VRONI error: ReadSites() - premature end of file!");
|
||||
#ifdef EXT_APPL_SITES
|
||||
HandleArc(xc1, yc1, xc2, yc2, xc3, yc3, attr, eas_data);
|
||||
#else
|
||||
HandleArc(xc1, yc1, xc2, yc2, xc3, yc3, attr);
|
||||
#endif
|
||||
*new_input = true;
|
||||
}
|
||||
else
|
||||
throw std::runtime_error("VRONI error: ReadSites() - unknown data format!");
|
||||
}
|
||||
|
||||
fclose(input);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
FILE *vroniObject::OpenFileVD(const char *file_name, const char *access)
|
||||
{
|
||||
FILE *file;
|
||||
|
||||
if ((file = fopen(file_name, access)) == NULL)
|
||||
throw std::runtime_error("VRONI error: OpenFileVD() - I/O file could not be opened!");
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#include "ext_appl_io.cc"
|
||||
+274
@@ -0,0 +1,274 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* 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-611 */
|
||||
/* Voice Mail: (+43 662) 8044-6304 */
|
||||
/* Snail Mail: Martin Held */
|
||||
/* FB Informatik */
|
||||
/* Universitaet Salzburg */
|
||||
/* A-5020 Salzburg, Austria */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* provide support for debug output. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
/* */
|
||||
/* get standard libraries */
|
||||
/* */
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
/* */
|
||||
/* get my header files */
|
||||
/* */
|
||||
#include "fpkernel.h"
|
||||
#include "vronivector.h"
|
||||
#include "vroni_object.h"
|
||||
#include "defs.h"
|
||||
#include "numerics.h"
|
||||
|
||||
/*
|
||||
* please turn those define's only on if you know what you do! (they are
|
||||
* here only for my debugging purposes!!
|
||||
*
|
||||
#define INIT_FORCED
|
||||
#define TRACE_INPUT
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
void vroniObject::WriteSites(const char *output_file)
|
||||
{
|
||||
int i, number;
|
||||
FILE *output;
|
||||
|
||||
output = OpenFileVD(output_file, "w");
|
||||
for (i = 2; i < num_pnts-2; ++i) {
|
||||
FP_fprintf(output, "2\n%20.16f %20.16f\n", FP_PRNTARG(pnts[i].p.x), FP_PRNTARG(pnts[i].p.y));
|
||||
}
|
||||
for (i = 0; i < num_segs; ++i) {
|
||||
if ((pnts[segs[i].i1].p.x != pnts[segs[i].i2].p.x) ||
|
||||
(pnts[segs[i].i1].p.y != pnts[segs[i].i2].p.y))
|
||||
FP_fprintf(output, "0\n%20.16f %20.16f %20.16f %20.16f\n",
|
||||
FP_PRNTARG(pnts[segs[i].i1].p.x),
|
||||
FP_PRNTARG(pnts[segs[i].i1].p.y),
|
||||
FP_PRNTARG(pnts[segs[i].i2].p.x),
|
||||
FP_PRNTARG(pnts[segs[i].i2].p.y));
|
||||
}
|
||||
|
||||
number = num_arcs;
|
||||
for (i = 0; i < number; ++i) {
|
||||
if ((pnts[arcs[i].i1].p.x != pnts[arcs[i].i2].p.x) ||
|
||||
(pnts[arcs[i].i1].p.y != pnts[arcs[i].i2].p.y))
|
||||
FP_fprintf(output, "1\n%20.16f %20.16f %20.16f %20.16f %20.16f %20.16f\n",
|
||||
FP_PRNTARG(pnts[arcs[i].i1].p.x),
|
||||
FP_PRNTARG(pnts[arcs[i].i1].p.y),
|
||||
FP_PRNTARG(pnts[arcs[i].i2].p.x),
|
||||
FP_PRNTARG(pnts[arcs[i].i2].p.y),
|
||||
FP_PRNTARG(arcs[i].c.x), FP_PRNTARG(arcs[i].c.y));
|
||||
}
|
||||
|
||||
fclose(output);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
#ifdef TRACE
|
||||
void vroniObject::WriteSiteData(int j, t_site type, const char* qual_string)
|
||||
{
|
||||
printf("%s", qual_string);
|
||||
|
||||
if (type == PNT) {
|
||||
assert(InPntsList(j));
|
||||
printf("pnt %d: (%21.17f, %21.17f)\n",
|
||||
j, pnts[j].p.x, pnts[j].p.y);
|
||||
}
|
||||
else if (type == SEG) {
|
||||
assert(InSegsList(j));
|
||||
printf("seg %d: (%21.17f, %21.17f), (%21.17f, %21.17f)\n",
|
||||
j, pnts[segs[j].i1].p.x, pnts[segs[j].i1].p.y,
|
||||
pnts[segs[j].i2].p.x, pnts[segs[j].i2].p.y);
|
||||
}
|
||||
else if (type == ARC) {
|
||||
assert(InArcsList(j));
|
||||
printf("arc %d: (%21.17f, %21.17f), (%21.17f, %21.17f)\n",
|
||||
j, pnts[arcs[j].i1].p.x, pnts[arcs[j].i1].p.y,
|
||||
pnts[arcs[j].i2].p.x, pnts[arcs[j].i2].p.y);
|
||||
printf("center: (%21.17f, %21.17f)\n",
|
||||
arcs[j].c.x, arcs[j].c.y);
|
||||
}
|
||||
else {
|
||||
assert(0 == 1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void vroniObject::WriteProcessedSites(const char *output_file)
|
||||
{
|
||||
#ifdef GRAPHICS
|
||||
FILE *output;
|
||||
|
||||
int i;
|
||||
coord q;
|
||||
q.x = 0.18;
|
||||
q.y = 0.38;
|
||||
|
||||
output = OpenFileVD(output_file, "w");
|
||||
|
||||
for (i = 2; i < num_pnts-2; ++i) {
|
||||
if(PntPntDist(q, pnts[i].p) < 0.03)
|
||||
if (pnts[i].draw)
|
||||
fprintf(output, "2\n%24.20f %24.20f\n", pnts[i].p.x, pnts[i].p.y);
|
||||
}
|
||||
for (i = 0; i < num_segs; ++i) {
|
||||
if((PntPntDist(q, pnts[segs[i].i1].p) < 0.03) ||
|
||||
(PntPntDist(q, pnts[segs[i].i2].p) < 0.03))
|
||||
if (segs[i].draw)
|
||||
fprintf(output, "0\n%24.20f %24.20f %24.20f %24.20f\n",
|
||||
pnts[segs[i].i1].p.x, pnts[segs[i].i1].p.y,
|
||||
pnts[segs[i].i2].p.x, pnts[segs[i].i2].p.y);
|
||||
}
|
||||
|
||||
for (i = 0; i < num_arcs; ++i) {
|
||||
if (arcs[i].draw)
|
||||
fprintf(output, "1\n%24.20f %24.20f %24.20f %24.20f %24.20f %24.20f\n",
|
||||
pnts[arcs[i].i1].p.x, pnts[arcs[i].i1].p.y,
|
||||
pnts[arcs[i].i2].p.x, pnts[arcs[i].i2].p.y,
|
||||
arcs[i].c.x, arcs[i].c.y);
|
||||
}
|
||||
|
||||
fclose(output);
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
#define ClipPnt(x1, y1) \
|
||||
((x1 >= clip_min.x) && (x1 <= clip_max.x) && \
|
||||
(y1 >= clip_min.y) && (y1 <= clip_max.y))
|
||||
|
||||
|
||||
#define ClipSeg(x1, y1, x2, y2) \
|
||||
((Min(x1, x2) <= clip_max.x) && (Max(x1, x2) >= clip_min.x) && \
|
||||
(Min(y1, y2) <= clip_max.y) && (Max(y1, y2) >= clip_min.y))
|
||||
|
||||
|
||||
|
||||
|
||||
void vroniObject::WriteDisplayedSites(double_arg xmin, double_arg ymin, double_arg xmax, double_arg ymax,
|
||||
const char *output_file)
|
||||
{
|
||||
#ifdef GRAPHICS
|
||||
int i;
|
||||
FILE *output;
|
||||
double x1, y1, x2, y2;
|
||||
|
||||
output = OpenFileVD(output_file, "w");
|
||||
ExportClipWindow(xmin, ymin, xmax, ymax);
|
||||
|
||||
for (i = 2; i < num_pnts-2; ++i) {
|
||||
if (pnts[i].draw) {
|
||||
x1 = pnts[i].p.x;
|
||||
y1 = pnts[i].p.y;
|
||||
if (ClipPnt(x1, y1)) {
|
||||
fprintf(output, "2\n%24.20f %24.20f\n", x1, y1);
|
||||
printf("pnt %d:\n%24.20f %24.20f\n", i, x1, y1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < num_segs; ++i) {
|
||||
if (segs[i].draw) {
|
||||
x1 = pnts[segs[i].i1].p.x;
|
||||
y1 = pnts[segs[i].i1].p.y;
|
||||
x2 = pnts[segs[i].i2].p.x;
|
||||
y2 = pnts[segs[i].i2].p.y;
|
||||
if (ClipSeg(x1, y1, x2, y2)) {
|
||||
fprintf(output, "0\n%24.20f %24.20f %24.20f %24.20f\n",
|
||||
x1, y1, x2, y2);
|
||||
printf("seg %d:\n%24.20f %24.20f %24.20f %24.20f\n",
|
||||
i, x1, y1, x2, y2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(output);
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void vroniObject::ExportClipWindow(double_arg xmin, double_arg ymin, double_arg xmax, double_arg ymax)
|
||||
{
|
||||
clip_min.x = xmin;
|
||||
clip_max.x = xmax;
|
||||
clip_min.y = ymin;
|
||||
clip_max.y = ymax;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef TRACE_INPUT
|
||||
|
||||
void vroniObject::ClipWriteSiteData(int j, t_site type, const char *output_file)
|
||||
{
|
||||
FILE *output;
|
||||
|
||||
output = OpenFileVD(output_file, "a+");
|
||||
|
||||
if (type == PNT) {
|
||||
assert(InPntsList(j));
|
||||
fprintf(output, "2\n%24.20f %24.20f\n", pnts[j].p.x, pnts[j].p.y);
|
||||
}
|
||||
else if (type == SEG) {
|
||||
assert(InSegsList(j));
|
||||
fprintf(output, "0\n%24.20f %24.20f %24.20f %24.20f\n",
|
||||
pnts[segs[j].i1].p.x, pnts[segs[j].i1].p.y,
|
||||
pnts[segs[j].i2].p.x, pnts[segs[j].i2].p.y);
|
||||
}
|
||||
else if (type == ARC) {
|
||||
assert(InArcsList(j));
|
||||
fprintf(output, "1\n %24.20f %24.20f %24.20f %24.20f ",
|
||||
pnts[arcs[j].i1].p.x, pnts[arcs[j].i1].p.y,
|
||||
pnts[arcs[j].i2].p.x, pnts[arcs[j].i2].p.y);
|
||||
fprintf(output, "%24.20f %24.20f\n",
|
||||
arcs[j].c.x, arcs[j].c.y);
|
||||
}
|
||||
else if (type == UNKNOWN) {
|
||||
fprintf(output, "restart!\n");
|
||||
}
|
||||
else {
|
||||
assert(0 == 1);
|
||||
}
|
||||
|
||||
fclose(output);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,709 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 2003--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 <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
|
||||
/* */
|
||||
/* get my header files */
|
||||
/* */
|
||||
#include "vronivector.h"
|
||||
#include "vroni_object.h"
|
||||
#include "fpkernel.h"
|
||||
#include "defs.h"
|
||||
#include "ext_appl_defs.h"
|
||||
#include "io_dxf.h"
|
||||
|
||||
|
||||
|
||||
#define LINE_LENGTH 1024
|
||||
#define NEWLINE '\n'
|
||||
#define CARRIAGE '\r'
|
||||
|
||||
#define InitBBox \
|
||||
{\
|
||||
bb_min.x = bb_min.y = DBL_MAX; \
|
||||
bb_max.x = bb_max.y = - DBL_MAX; \
|
||||
}
|
||||
|
||||
|
||||
#define IsSpace(x)\
|
||||
((x == ' ') || (x == '\t') || (x == '\r') || (x == '\n') || (x == '\f'))
|
||||
|
||||
|
||||
#define SkipUntilDXFCode(input, code, string, dxf_code) \
|
||||
{ \
|
||||
do { \
|
||||
if (!ReadNewDXFPair(input, code, string, LINE_LENGTH)) \
|
||||
throw std::runtime_error("VRONI error: ReadDXFFile() - premature end of file!"); \
|
||||
} while (atoi(code) != dxf_code); \
|
||||
}
|
||||
|
||||
|
||||
#define SkipUntilDXFString(input, code, string, dxf_string) \
|
||||
{ \
|
||||
do { \
|
||||
if (!ReadNewDXFPair(input, code, string, LINE_LENGTH)) \
|
||||
throw std::runtime_error("VRONI error: ReadDXFFile() - premature end of file!"); \
|
||||
} while (strcmp(string, dxf_string)); \
|
||||
if (!ReadNewDXFPair(input, code, string, LINE_LENGTH)) \
|
||||
throw std::runtime_error("VRONI error: ReadDXFFile() - premature end of file!"); \
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
vr_bool ReadNewLine(FILE *input, char *line, int size, vr_bool read_string)
|
||||
{
|
||||
char *s;
|
||||
int i;
|
||||
|
||||
do {
|
||||
s = fgets(line, size, input);
|
||||
if (s == (char*)NULL) return false;
|
||||
i = ((int) strlen(s)) - 1;
|
||||
while((i >= 0) && IsSpace(s[i])) {
|
||||
s[i]='\0';
|
||||
i--;
|
||||
}
|
||||
if (i >= 0) {
|
||||
while (IsSpace(s[0])) ++s;
|
||||
line = strcpy(line, s);
|
||||
}
|
||||
else if (read_string) {
|
||||
i = 0;
|
||||
}
|
||||
} while (i < 0);
|
||||
|
||||
if (i < 0) return false;
|
||||
else return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
vr_bool ReadNewDXFPair(FILE *input, char *code, char *string, int size)
|
||||
{
|
||||
if (!ReadNewLine(input, code, size, false)) return false;
|
||||
if (!ReadNewLine(input, string, size, true)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* This is a >>VERY<< rudimentary interface for reading AutoCAD DXF files. */
|
||||
/* Note that this interface is not as general as it ought to be. That is, */
|
||||
/* likely it will cough on lots of DXF files. Currently, it supports POINT, */
|
||||
/* LINE, ARC, CIRCLE, POLYLINE and LWPOLYLINE entities, including "closed" */
|
||||
/* flags and bulge factors for the latter two entities. It does not handle */
|
||||
/* BLOCKs or INSERTs or LAYERs, or any other codes that turn objects on or */
|
||||
/* off, or that move or resize them. Also, this routine does not care about */
|
||||
/* z-coordinates, and it does not support binary files. */
|
||||
/* */
|
||||
void vroniObject::ReadDXFFile(char input_file[], vr_bool *new_input)
|
||||
{
|
||||
FILE *input;
|
||||
char code[LINE_LENGTH+1];
|
||||
char string[LINE_LENGTH+1];
|
||||
int dxf_code, i;
|
||||
double xc1 = 0.0, yc1 = 0.0, xc2 = 0.0, yc2 = 0.0;
|
||||
double rad = 0.0, bulge = 0.0, old_bulge = 0.0, s_a = 0.0, e_a = 0.0;
|
||||
vr_bool xc1_set, yc1_set, xc2_set, yc2_set;
|
||||
vr_bool rad_set, s_a_set, e_a_set;
|
||||
vr_bool pnt_read, seg_read, arc_read, cir_read, poly_closed = false;
|
||||
vr_bool poly_started = false;;
|
||||
|
||||
*new_input = false;
|
||||
isolated_pnts = false;
|
||||
InitBBox;
|
||||
input = OpenFileVD(input_file, "r");
|
||||
|
||||
if (!ReadNewDXFPair(input, code, string, LINE_LENGTH)) return;
|
||||
|
||||
while (strcmp(string, "EOF")) {
|
||||
if ((!strcmp(string, "POINT")) ||
|
||||
(!strcmp(string, "LINE")) ||
|
||||
(!strcmp(string, "CIRCLE")) ||
|
||||
(!strcmp(string, "ARC"))) {
|
||||
/* */
|
||||
/* input point, line segment, circle or circular arc. */
|
||||
/* */
|
||||
xc1_set = yc1_set = false;
|
||||
xc2_set = yc2_set = false;
|
||||
rad_set = s_a_set = e_a_set = false;
|
||||
pnt_read = seg_read = arc_read = cir_read = false;
|
||||
if (!strcmp(string, "POINT")) pnt_read = true;
|
||||
if (!strcmp(string, "LINE")) seg_read = true;
|
||||
if (!strcmp(string, "ARC")) arc_read = true;
|
||||
if (!strcmp(string, "CIRCLE")) cir_read = true;
|
||||
do {
|
||||
if (!ReadNewDXFPair(input, code, string, LINE_LENGTH))
|
||||
throw std::runtime_error("VRONI error: ReadDXFFile() - premature end of file!");
|
||||
dxf_code = atoi(code);
|
||||
switch(dxf_code) {
|
||||
case 10:
|
||||
xc1 = atof(string);
|
||||
xc1_set = true;
|
||||
break;
|
||||
case 20:
|
||||
yc1 = atof(string);
|
||||
yc1_set = true;
|
||||
break;
|
||||
case 11:
|
||||
xc2 = atof(string);
|
||||
xc2_set = true;
|
||||
break;
|
||||
case 21:
|
||||
yc2 = atof(string);
|
||||
yc2_set = true;
|
||||
break;
|
||||
case 40:
|
||||
rad = atof(string);
|
||||
rad_set = true;
|
||||
break;
|
||||
case 50:
|
||||
s_a = atof(string);
|
||||
s_a_set = true;
|
||||
break;
|
||||
case 51:
|
||||
e_a = atof(string);
|
||||
e_a_set = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} while (dxf_code != 0);
|
||||
|
||||
if (xc1_set && yc1_set) {
|
||||
*new_input = true;
|
||||
if (seg_read && xc2_set && yc2_set) {
|
||||
#ifdef EXT_APPL_SITES
|
||||
HandleSeg(xc1, yc1, xc2, yc2, eas_NIL);
|
||||
#else
|
||||
HandleSeg(xc1, yc1, xc2, yc2);
|
||||
#endif
|
||||
}
|
||||
else if (arc_read && rad_set && s_a_set && e_a_set){
|
||||
s_a *= M_PI_180;
|
||||
e_a *= M_PI_180;
|
||||
#ifdef EXT_APPL_SITES
|
||||
HandleArc(xc1 + rad * cos(s_a), yc1 + rad * sin(s_a),
|
||||
xc1 + rad * cos(e_a), yc1 + rad * sin(e_a),
|
||||
xc1, yc1, ARC, eas_NIL);
|
||||
#else
|
||||
HandleArc(xc1 + rad * cos(s_a), yc1 + rad * sin(s_a),
|
||||
xc1 + rad * cos(e_a), yc1 + rad * sin(e_a),
|
||||
xc1, yc1, ARC);
|
||||
#endif
|
||||
}
|
||||
else if (cir_read && rad_set) {
|
||||
#ifdef EXT_APPL_SITES
|
||||
HandleArc(xc1 + rad, yc1, xc1 - rad, yc1, xc1, yc1,
|
||||
ARC, eas_NIL);
|
||||
HandleArc(xc1 - rad, yc1, xc1 + rad, yc1, xc1, yc1,
|
||||
ARC, eas_NIL);
|
||||
#else
|
||||
HandleArc(xc1 + rad, yc1, xc1 - rad, yc1, xc1, yc1,
|
||||
ARC);
|
||||
HandleArc(xc1 - rad, yc1, xc1 + rad, yc1, xc1, yc1,
|
||||
ARC);
|
||||
#endif
|
||||
}
|
||||
else if (pnt_read) {
|
||||
#ifdef EXT_APPL_PNTS
|
||||
(void) HandlePnt(xc1, yc1, eap_NIL);
|
||||
#else
|
||||
(void) HandlePnt(xc1, yc1);
|
||||
#endif
|
||||
isolated_pnts = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!strcmp(string, "LWPOLYLINE")) {
|
||||
/* */
|
||||
/* "light-weight" polygonal curve. */
|
||||
/* */
|
||||
DXFStartPoly();
|
||||
xc1_set = false;
|
||||
yc1_set = false;
|
||||
bulge = 0.0;
|
||||
poly_closed = false;
|
||||
do {
|
||||
if (!ReadNewDXFPair(input, code, string, LINE_LENGTH))
|
||||
throw std::runtime_error("VRONI error: ReadDXFFile() - premature end of file!");
|
||||
dxf_code = atoi(code);
|
||||
switch(dxf_code) {
|
||||
case 10:
|
||||
case 20:
|
||||
if (dxf_code == 10) {
|
||||
xc1 = atof(string);
|
||||
xc1_set = true;
|
||||
}
|
||||
else {
|
||||
yc1 = atof(string);
|
||||
yc1_set = true;
|
||||
}
|
||||
if (xc1_set && yc1_set) {
|
||||
*new_input = true;
|
||||
DXFAddPolyVertex(xc1, yc1, bulge);
|
||||
xc1_set = false;
|
||||
yc1_set = false;
|
||||
bulge = 0.0;
|
||||
}
|
||||
break;
|
||||
case 42:
|
||||
bulge = atof(string);
|
||||
break;
|
||||
case 70:
|
||||
poly_closed = (vr_bool) (1&atoi(string));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} while (dxf_code != 0);
|
||||
|
||||
if (poly_closed) {
|
||||
DXFClosePoly(bulge);
|
||||
bulge = 0.0;
|
||||
}
|
||||
}
|
||||
else if (!strcmp(string, "POLYLINE")) {
|
||||
/* */
|
||||
/* polygonal curve. */
|
||||
/* */
|
||||
poly_closed = false;
|
||||
do {
|
||||
if (!ReadNewDXFPair(input, code, string, LINE_LENGTH))
|
||||
throw std::runtime_error("VRONI error: ReadDXFFile() - premature end of file!");
|
||||
dxf_code = atoi(code);
|
||||
switch(dxf_code) {
|
||||
case 70:
|
||||
poly_closed = (vr_bool) (1&atoi(string));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} while (dxf_code != 0);
|
||||
|
||||
if (strcmp(string, "VERTEX"))
|
||||
SkipUntilDXFString(input, code, string, "VERTEX");
|
||||
DXFStartPoly();
|
||||
poly_started = true;
|
||||
old_bulge = 0.0;
|
||||
}
|
||||
else if (!strcmp(string, "VERTEX")) {
|
||||
/* */
|
||||
/* vertex of a polygon. */
|
||||
/* */
|
||||
xc1_set = false;
|
||||
yc1_set = false;
|
||||
bulge = 0.0;
|
||||
do {
|
||||
if (!ReadNewDXFPair(input, code, string, LINE_LENGTH))
|
||||
throw std::runtime_error("VRONI error: ReadDXFFile() - premature end of file!");
|
||||
dxf_code = atoi(code);
|
||||
switch(dxf_code) {
|
||||
case 10:
|
||||
xc1 = atof(string);
|
||||
xc1_set = true;
|
||||
break;
|
||||
case 20:
|
||||
yc1 = atof(string);
|
||||
yc1_set = true;
|
||||
break;
|
||||
case 42:
|
||||
bulge = atof(string);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} while (dxf_code != 0);
|
||||
|
||||
if (poly_started && xc1_set && yc1_set) {
|
||||
*new_input = true;
|
||||
DXFAddPolyVertex(xc1, yc1, old_bulge);
|
||||
old_bulge = bulge;
|
||||
}
|
||||
xc1_set = false;
|
||||
yc1_set = false;
|
||||
}
|
||||
else if (!strcmp(string, "SEQEND")) {
|
||||
if (poly_closed) DXFClosePoly(old_bulge);
|
||||
poly_started = false;
|
||||
if (!ReadNewDXFPair(input, code, string, LINE_LENGTH))
|
||||
throw std::runtime_error("VRONI error: ReadDXFFile() - premature end of file!");
|
||||
}
|
||||
else if (string[0] == '$') {
|
||||
/* */
|
||||
/* some initialization stuff. we don't care about it. */
|
||||
/* */
|
||||
if (!ReadNewDXFPair(input, code, string, LINE_LENGTH))
|
||||
throw std::runtime_error("VRONI error: ReadDXFFile() - premature end of file!");
|
||||
}
|
||||
else if (string[0] == '{') {
|
||||
/* */
|
||||
/* some application-specific stuff. we don't care about it. */
|
||||
/* */
|
||||
i = ((int) strlen(string)) - 1;
|
||||
if (string[i] != '}') {
|
||||
SkipUntilDXFString(input, code, string, "}");
|
||||
}
|
||||
else {
|
||||
if (!ReadNewDXFPair(input, code, string, LINE_LENGTH))
|
||||
throw std::runtime_error("VRONI error: ReadDXFFile() - premature end of file!");
|
||||
}
|
||||
}
|
||||
else if (!strcmp(string, "LAYER")) {
|
||||
/* */
|
||||
/* information on a layer. we skip it. */
|
||||
/* */
|
||||
SkipUntilDXFCode(input, code, string, 0);
|
||||
}
|
||||
else if (!strcmp(string, "BLOCK")) {
|
||||
/* */
|
||||
/* information on a block. we skip it. */
|
||||
/* */
|
||||
SkipUntilDXFString(input, code, string, "ENDBLK");
|
||||
}
|
||||
else if (!strcmp(string, "INSERT")) {
|
||||
/* */
|
||||
/* information on inserting a block. we skip it. */
|
||||
/* */
|
||||
SkipUntilDXFCode(input, code, string, 0);
|
||||
}
|
||||
else if (!strcmp(string, "SPLINE")) {
|
||||
/* */
|
||||
/* information on a spline. we skip it. */
|
||||
/* */
|
||||
SkipUntilDXFCode(input, code, string, 0);
|
||||
}
|
||||
else if (!strcmp(string, "ELLIPSE")) {
|
||||
/* */
|
||||
/* information on an ellipse. we skip it. */
|
||||
/* */
|
||||
SkipUntilDXFCode(input, code, string, 0);
|
||||
}
|
||||
else if (!strcmp(string, "TEXT")) {
|
||||
/* */
|
||||
/* text. we skip it. */
|
||||
/* */
|
||||
SkipUntilDXFCode(input, code, string, 0);
|
||||
}
|
||||
else if (!strcmp(string, "DIMENSION")) {
|
||||
/* */
|
||||
/* dimensons. we skip it. */
|
||||
/* */
|
||||
SkipUntilDXFCode(input, code, string, 0);
|
||||
}
|
||||
else if (!strcmp(string, "HATCH")) {
|
||||
/* */
|
||||
/* information on hatching. we skip it. */
|
||||
/* */
|
||||
SkipUntilDXFCode(input, code, string, 0);
|
||||
}
|
||||
else {
|
||||
/* */
|
||||
/* some dxf code that we don't care about. */
|
||||
/* */
|
||||
if (!ReadNewDXFPair(input, code, string, LINE_LENGTH))
|
||||
throw std::runtime_error("VRONI error: ReadDXFFile() - premature end of file!");
|
||||
}
|
||||
}
|
||||
|
||||
fclose(input);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* this routines writes the standard start-up DXF lines. */
|
||||
/* */
|
||||
void vroniObject::StartDXFFile(FILE *dxf_file)
|
||||
{
|
||||
fprintf(dxf_file, " 0\nSECTION\n 2\nHEADER\n" );
|
||||
fprintf(dxf_file, " 0\nENDSEC\n" );
|
||||
fprintf(dxf_file, " 0\nSECTION\n 2\nENTITIES\n" );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* this routines writes the standard finishing DXF lines. */
|
||||
/* */
|
||||
void vroniObject::FinishDXFFile(FILE *dxf_file)
|
||||
{
|
||||
if (dxf_file != (FILE*)NULL) {
|
||||
fprintf(dxf_file, " 0\nENDSEC\n 0\nEOF\n");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void vroniObject::WriteDXFEntity(FILE *dxf_file, int color)
|
||||
{
|
||||
// write Handle
|
||||
fprintf(dxf_file, " 5\n%d\n", dxf_handle);
|
||||
dxf_handle++;
|
||||
|
||||
// write subclass marker (AcDbEntity)
|
||||
fprintf(dxf_file, "100\nAcDbEntity\n");
|
||||
|
||||
// write layer name
|
||||
fprintf(dxf_file, " 8\nVRONI\n");
|
||||
|
||||
// write color number
|
||||
if (color >= 0) fprintf(dxf_file, " 62\n%3d\n", color);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* */
|
||||
/* output a 2D line segment in DXF format. */
|
||||
/* */
|
||||
void vroniObject::WriteDXFLine(FILE *dxf_file, double_arg xc1, double_arg yc1,
|
||||
double_arg xc2, double_arg yc2, int color)
|
||||
{
|
||||
if (dxf_file != (FILE*)NULL) {
|
||||
fprintf(dxf_file, " 0\nLINE\n" );
|
||||
WriteDXFEntity(dxf_file, color);
|
||||
fprintf(dxf_file, "100\nAcDbLine\n" );
|
||||
FP_fprintf(dxf_file, " 10\n%f\n 20\n%f\n 30\n0.0\n", FP_PRNTARG(xc1), FP_PRNTARG(yc1) );
|
||||
FP_fprintf(dxf_file, " 11\n%f\n 21\n%f\n 31\n0.0\n", FP_PRNTARG(xc2), FP_PRNTARG(yc2) );
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error("VRONI error: WriteDXFLine() - DXF output file not opened properly!");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* output a 2D point in DXF format. */
|
||||
/* */
|
||||
void vroniObject::WriteDXFPoint(FILE *dxf_file, double_arg xc1, double_arg yc1,
|
||||
int color)
|
||||
{
|
||||
if (dxf_file != (FILE*)NULL) {
|
||||
fprintf(dxf_file, " 0\nPOINT\n" );
|
||||
WriteDXFEntity(dxf_file, color);
|
||||
fprintf(dxf_file, "100\nAcDbPoint\n" );
|
||||
FP_fprintf(dxf_file, " 10\n%f\n 20\n%f\n 30\n0.0\n", FP_PRNTARG(xc1), FP_PRNTARG(yc1) );
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error("VRONI error: WriteDXFPoint() - DXF output file not opened properly!");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* output a 2D circle in DXF format. */
|
||||
/* */
|
||||
void vroniObject::WriteDXFCircle(FILE *dxf_file, double_arg xc1, double_arg yc1,
|
||||
double_arg radius, int color)
|
||||
{
|
||||
if (dxf_file != (FILE*)NULL) {
|
||||
fprintf(dxf_file, " 0\nCIRCLE\n" );
|
||||
WriteDXFEntity(dxf_file, color);
|
||||
fprintf(dxf_file, "100\nAcDbCircle\n" );
|
||||
FP_fprintf(dxf_file, " 10\n%f\n 20\n%f\n 30\n0.0\n", FP_PRNTARG(xc1), FP_PRNTARG(yc1) );
|
||||
FP_fprintf(dxf_file, " 40\n%f\n", FP_PRNTARG(radius) );
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error("VRONI error: WriteDXFCircle() - DXF output file not properly opened!");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* output a 2D circular arc in DXF format. */
|
||||
/* */
|
||||
void vroniObject::WriteDXFArc(FILE *dxf_file, double_arg xc1, double_arg yc1,
|
||||
double_arg xc2, double_arg yc2,
|
||||
double_arg xc3, double_arg yc3, vr_bool ccw_flag, int color)
|
||||
{
|
||||
double s_a, s_e;
|
||||
|
||||
double dx, dy, r;
|
||||
|
||||
|
||||
if (dxf_file != (FILE*)NULL) {
|
||||
fprintf(dxf_file, " 0\nARC\n" );
|
||||
WriteDXFEntity(dxf_file, color);
|
||||
fprintf(dxf_file, "100\nAcDbCircle\n" );
|
||||
FP_fprintf(dxf_file, " 10\n%f\n 20\n%f\n 30\n0.0\n", FP_PRNTARG(xc3), FP_PRNTARG(yc3) );
|
||||
dx = xc1 - xc3;
|
||||
dy = yc1 - yc3;
|
||||
r = sqrt( dx*dx + dy*dy );
|
||||
|
||||
FP_fprintf(dxf_file, " 40\n%f\n", FP_PRNTARG(r) );
|
||||
|
||||
s_a = atan2( dy, dx );
|
||||
s_e = atan2( yc2 - yc3, xc2 - xc3 );
|
||||
if ( s_a < 0.0 ) s_a += 2*M_PI;
|
||||
if ( s_e < 0.0 ) s_e += 2*M_PI;
|
||||
s_a *= M_180_PI;
|
||||
s_e *= M_180_PI;
|
||||
fprintf(dxf_file, "100\nAcDbArc\n" );
|
||||
if ( ccw_flag )
|
||||
FP_fprintf(dxf_file, " 50\n%f\n 51\n%f\n", FP_PRNTARG(s_a), FP_PRNTARG(s_e) );
|
||||
else
|
||||
FP_fprintf(dxf_file, " 50\n%f\n 51\n%f\n", FP_PRNTARG(s_e), FP_PRNTARG(s_a) );
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error("VRONI error: WriteDXFArc() - DXF output file not properly opened!");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* output the start code for "LWPOLYLINE" in DXF format. */
|
||||
/* */
|
||||
void vroniObject::WriteDXFLWPoly_Start(FILE *dxf_file, vr_bool closed,
|
||||
int color)
|
||||
{
|
||||
if (dxf_file != (FILE*)NULL) {
|
||||
fprintf(dxf_file, " 0\nLWPOLYLINE\n" );
|
||||
WriteDXFEntity(dxf_file, color);
|
||||
fprintf(dxf_file, "100\nAcDbPolyline\n" );
|
||||
if (closed) fprintf(dxf_file, " 70\n 1\n" );
|
||||
else fprintf(dxf_file, " 70\n 0\n" );
|
||||
fprintf(dxf_file, " 6\nCONTINUOUS\n");
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error("VRONI error: WriteDXFLWPoly_Start() - DXF output file not properly opened!");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* output the start code for "POLYLINE" in DXF format. */
|
||||
/* */
|
||||
void vroniObject::WriteDXFPoly_Start(FILE *dxf_file, vr_bool closed, int color)
|
||||
{
|
||||
if (dxf_file != (FILE*)NULL) {
|
||||
fprintf(dxf_file, " 0\nPOLYLINE\n" );
|
||||
WriteDXFEntity(dxf_file, color );
|
||||
fprintf(dxf_file, "100\nAcDb2dPolyline\n" );
|
||||
if (closed) fprintf(dxf_file, " 70\n 1\n" );
|
||||
else fprintf(dxf_file, " 70\n 0\n" );
|
||||
fprintf(dxf_file, " 6\nCONTINUOUS\n");
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error("VRONI error: WriteDXFPoly_Start() - DXF output file not properly opened!");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* output the end code for "POLYLINE" in DXF format. */
|
||||
/* */
|
||||
void vroniObject::WriteDXFPoly_End(FILE *dxf_file)
|
||||
{
|
||||
if (dxf_file != (FILE*)NULL) {
|
||||
fprintf(dxf_file, " 0\nSEQEND\n");
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error("VRONI error: WriteDXFPoly_End() - DXF output file not properly opened!");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* output one vertex of a "LWPOLYLINE" in DXF format. */
|
||||
/* */
|
||||
void vroniObject::WriteDXFLWPoly_Vertex(FILE *dxf_file, double_arg xc1, double_arg yc1,
|
||||
double_arg bulge)
|
||||
{
|
||||
if (dxf_file != (FILE*)NULL) {
|
||||
FP_fprintf(dxf_file, " 10\n%f\n 20\n%f\n 30\n0.0\n", FP_PRNTARG(xc1), FP_PRNTARG(yc1));
|
||||
if (bulge != 0.0) FP_fprintf(dxf_file, " 42\n%f\n", FP_PRNTARG(bulge));
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error("VRONI error: WriteDXFLWPoly_Vertex() - DXF output file not properly opened!");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* output one vertex of a "POLYLINE" in DXF format. */
|
||||
/* */
|
||||
void vroniObject::WriteDXFPoly_Vertex(FILE *dxf_file, double_arg xc1, double_arg yc1,
|
||||
double_arg bulge)
|
||||
{
|
||||
if (dxf_file != (FILE*)NULL) {
|
||||
fprintf(dxf_file, " 0\nVERTEX\n");
|
||||
FP_fprintf(dxf_file, " 10\n%f\n 20\n%f\n 30\n0.0\n", FP_PRNTARG(xc1), FP_PRNTARG(yc1));
|
||||
if (bulge != 0.0) FP_fprintf(dxf_file, " 42\n%f\n", FP_PRNTARG(bulge));
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error("VRONI error: WriteDXFPoly_Vertex() - DXF output file not properly opened!");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 2003--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 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef VRONI_IO_DXF_H
|
||||
#define VRONI_IO_DXF_H
|
||||
|
||||
/* */
|
||||
/* I'm not sure whether those are indeed the colors used in DXF files. */
|
||||
/* Unfortunately, I do not seem to be able to get my hands on a decent */
|
||||
/* specification of DXF... */
|
||||
/* */
|
||||
#define DXF_NO_COLOR -1
|
||||
#define DXF_RED 1
|
||||
#define DXF_YELLOW 2
|
||||
#define DXF_GREEN 2
|
||||
#define DXF_CYAN 4
|
||||
#define DXF_BLUE 5
|
||||
#define DXF_MAGENTA 6
|
||||
#define DXF_WHITE 7
|
||||
|
||||
#endif
|
||||
+330
@@ -0,0 +1,330 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* 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-611 */
|
||||
/* Voice Mail: (+43 662) 8044-6304 */
|
||||
/* Snail Mail: Martin Held */
|
||||
/* FB Informatik */
|
||||
/* Universitaet Salzburg */
|
||||
/* A-5020 Salzburg, Austria */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* routines for printing the help information and the copyright notice. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* get standard libraries */
|
||||
/* */
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* */
|
||||
/* get my header files */
|
||||
/* */
|
||||
#include "fpkernel.h"
|
||||
#include "vronivector.h"
|
||||
#include "vroni_object.h"
|
||||
#include "defs.h"
|
||||
|
||||
|
||||
|
||||
void vroniObject::Copyright(void)
|
||||
{
|
||||
printf("\n");
|
||||
printf("(***********************************************************");
|
||||
printf("******************)\n");
|
||||
printf("(* ");
|
||||
printf(" *)\n");
|
||||
printf("(* Copyright (C) %9s M. Held", PROG_YEAR);
|
||||
printf(" *)\n");
|
||||
printf("(* ");
|
||||
printf(" *)\n");
|
||||
printf("(* ");
|
||||
printf(" *)\n");
|
||||
printf("(* %9s %5s ",
|
||||
PROG_NAME, PROG_VERSION);
|
||||
|
||||
printf(" *)\n");
|
||||
printf("(* ");
|
||||
printf(" *)\n");
|
||||
printf("(* ");
|
||||
printf(" *)\n");
|
||||
printf("(* Start this program as `vroni --help' in order to get a sh");
|
||||
printf("ort summary of *)\n");
|
||||
printf("(* how to use it. ");
|
||||
printf(" *)\n");
|
||||
printf("(* ");
|
||||
printf(" *)\n");
|
||||
printf("(* Please report bugs to held@cs.sbg.ac.at. ");
|
||||
printf(" *)\n");
|
||||
printf("(* ");
|
||||
printf(" *)\n");
|
||||
printf("(* ");
|
||||
printf(" *)\n");
|
||||
printf("(* ");
|
||||
printf(" *)\n");
|
||||
printf("(* C O P Y R I G H T ");
|
||||
printf(" *)\n");
|
||||
printf("(* ");
|
||||
printf(" *)\n");
|
||||
printf("(* This code is provided at no charge to you for purely non-profit purposes *)\n");
|
||||
printf("(* and only for use internal to your institution. You may use this code for *)\n");
|
||||
printf("(* academic applications, following standard rules of academic conduct *)\n");
|
||||
printf("(* including crediting the author(s) and the copyright holder in any *)\n");
|
||||
printf("(* publication. This code is not in the public domain, and no parts of it *)\n");
|
||||
printf("(* may be duplicated, altered, sold, re-distributed (in either source-code *)\n");
|
||||
printf("(* or binary format), or used as a blueprint for somebody else's own *)\n");
|
||||
printf("(* implementation without obtaining the prior written consent of the *)\n");
|
||||
printf("(* copyright holder. All rights reserved! *)\n");
|
||||
printf("(* *)\n");
|
||||
printf("(* Free use of this code is restricted to purely non-profit purposes within *)\n");
|
||||
printf("(* academic research institutions. Absolutely all other forms of use require *)\n");
|
||||
printf("(* the signing of a non-disclosure agreement or of a commercial license. *)\n");
|
||||
printf("(* Please contact me, Martin Held (held@cs.sbg.ac.at), for commercial *)\n");
|
||||
printf("(* evaluation and licensing terms. *)\n");
|
||||
printf("(* *)\n");
|
||||
printf("(* D I S C L A I M E R *)\n");
|
||||
printf("(* *)\n");
|
||||
printf("(* In any case, this code is provided `as is', and you use it at your own *)\n");
|
||||
printf("(* risk. The author does not accept any responsibility, to the extent *)\n");
|
||||
printf("(* permitted by applicable law, for the consequences of using it or for its *)\n");
|
||||
printf("(* usefulness for any particular application. *)\n");
|
||||
printf("(* ");
|
||||
printf(" *)\n");
|
||||
printf("(***********************************************************");
|
||||
printf("******************)\n");
|
||||
printf("\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void vroniObject::Help(void)
|
||||
{
|
||||
printf("\n\n");
|
||||
printf("(***********************************************************");
|
||||
printf("******************)\n");
|
||||
printf("(* ");
|
||||
printf(" *)\n");
|
||||
printf("(* Start this program as `vroni --help' in order to get a sh");
|
||||
printf("ort summary of *)\n");
|
||||
printf("(* how to use it. ");
|
||||
printf(" *)\n");
|
||||
printf("(* ");
|
||||
printf(" *)\n");
|
||||
printf("(* Please make sure to read the files README and README.data");
|
||||
printf(". *)\n");
|
||||
printf("(* ");
|
||||
printf(" *)\n");
|
||||
printf("(***********************************************************");
|
||||
printf("******************)\n");
|
||||
printf("\n\nSummary of keyboard short-cuts used in the GUI:\n\n");
|
||||
|
||||
printf("`h' ... hit the `h'-key while the cursor is within the drawing\n");
|
||||
printf(" canvas in order to reproduce this message.\n");
|
||||
printf("`p' ... tells my code that you will now enter a new polygon.\n");
|
||||
printf(" the vertices of the polygon are entered via mouse");
|
||||
printf("-clicks\n");
|
||||
printf("`c' ... to close the polygonal chain which you have entered.\n");
|
||||
printf("`v' ... to compute the Voronoi diagram. It is also used for\n");
|
||||
printf(" advancing the graphics display if `--step' was selected\n");
|
||||
printf(" as a command-line option.\n");
|
||||
printf("`u' ... to redraw the entities displayed in the drawing canvas;\n");
|
||||
printf(" it also resizes the display such that all entities fit\n");
|
||||
printf(" nicely within the graphics window.\n");
|
||||
printf("`i' ... to zoom in.\n");
|
||||
printf("`o' ... to zoom out.\n");
|
||||
printf("`z' ... to zoom into a rectangular region; this region is ");
|
||||
printf("specified\n");
|
||||
printf(" by clicking first at its lower-left and then at its\n");
|
||||
printf(" upper-right corner.\n");
|
||||
printf("`d' ... to erase the drawing canvas and delete all data.\n");
|
||||
printf("`m' ... toggle; draw or not draw the vertex markers.\n");
|
||||
printf("`n' ... toggle; draw or not draw the Voronoi nodes.\n");
|
||||
printf("`e' ... toggle; draw or not draw the Voronoi edges.\n");
|
||||
printf("`a' ... toggle; draw or not draw the arcs.\n");
|
||||
printf("`s' ... toggle; draw or not draw the segments.\n");
|
||||
printf("`t' ... multiple toggle; draw or not draw VD, DT or WMAT.\n");
|
||||
printf("`f' ... toggle; draw or not draw offset curves.\n");
|
||||
printf("`x' ... toggle; draw or not draw the maximum inscribed circle.\n");
|
||||
printf("`q' ... to terminate the program.\n");
|
||||
printf("\nPlease note that the interface does not recognize upper-case ");
|
||||
printf("letters.\n");
|
||||
printf("\nA listing of the command-line options is produced by using the ");
|
||||
printf("option `--help'.\n\n");
|
||||
printf("Color codes used in the GUI:\n");
|
||||
printf("green ....... input sites (points and line segments).\n");
|
||||
printf("white ....... Delaunay triangulation, offsets\n");
|
||||
printf("red ......... Voronoi diagram.\n");
|
||||
printf("yellow ...... Delaunay circles, current site (if step mode is activated),\n");
|
||||
printf(" maximum inscribed circle.\n");
|
||||
printf("magenta ..... current Voronoi cell (if step mode is activated).\n");
|
||||
printf("cyan ........ input sites (circular arcs), weighted medial axis.\n");
|
||||
printf("blue ........ alert color.\n");
|
||||
printf("orange ...... current node (if step mode is activated).\n\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* */
|
||||
/* prints value of a variable. typical usage: */
|
||||
/* int i = 0; */
|
||||
/* PrintVarValue(stdout, (void*) &new_input, "new_input", vroniBOOLEAN); */
|
||||
/* PrintVarValue(stdout, (void*) &bound, "bound", vroniINTEGER); */
|
||||
/* PrintVarValue(stdout, (void*) output_file, "output_file", vroniCHARS); */
|
||||
/* PrintVarValue(stdout, (void*) &apx_absolute,"apx_absolute",vroniDOUBLE);*/
|
||||
/* PrintVarValue(stdout, (void*) &(pnts[0].p), "p", vroniCOORD); */
|
||||
/* PrintVarValue(stdout, (void*) &i, "pnts", vroniPNTS); */
|
||||
/* */
|
||||
void vroniObject::PrintVarValue(FILE *output, void *v, char const *var_name, my_types t)
|
||||
{
|
||||
char my_string[100], number[100], tmp[100];
|
||||
|
||||
switch(t) {
|
||||
case(vroniCHARS):
|
||||
fprintf(output, "%40s = %s\n", var_name, (char*)v);
|
||||
break;
|
||||
case(vroniINTEGER):
|
||||
fprintf(output, "%40s = %12d\n", var_name, *(int*)v);
|
||||
break;
|
||||
case(vroniDOUBLE):
|
||||
FP_fprintf(output, "%40s = %30.17f\n", var_name, FP_PRNTARG(*(double*)v));
|
||||
break;
|
||||
case(vroniBOOLEAN):
|
||||
if (*(vr_bool*)v)
|
||||
fprintf(output, "%40s = TRUE\n", var_name);
|
||||
else
|
||||
fprintf(output, "%40s = FALSE\n", var_name);
|
||||
break;
|
||||
case(vroniCOORD):
|
||||
my_string[0] = '\0';
|
||||
strcat(my_string, var_name);
|
||||
strcat(my_string, ".x");
|
||||
FP_fprintf(output, "%40s = %30.17f\n", my_string, FP_PRNTARG((*(coord*)v).x));
|
||||
my_string[0] = '\0';
|
||||
strcat(my_string, var_name);
|
||||
strcat(my_string, ".y");
|
||||
FP_fprintf(output, "%40s = %30.17f\n", my_string, FP_PRNTARG((*(coord*)v).y));
|
||||
break;
|
||||
case(vroniN_STATUS):
|
||||
my_string[0] = '\0';
|
||||
switch(*(t_site*)v) {
|
||||
case(UNCHECKED):
|
||||
strcat(my_string, "UNCHECKED");
|
||||
break;
|
||||
case(CHECKED):
|
||||
strcat(my_string, "CHECKED");
|
||||
break;
|
||||
case(DELETED):
|
||||
strcat(my_string, "DELETED");
|
||||
break;
|
||||
case(VISITED):
|
||||
strcat(my_string, "VISITED");
|
||||
break;
|
||||
case(DUMMY):
|
||||
strcat(my_string, "DUMMY");
|
||||
break;
|
||||
case(MISC):
|
||||
strcat(my_string, "MISC");
|
||||
break;
|
||||
default:
|
||||
strcat(my_string, "***** type not known *****");
|
||||
break;
|
||||
}
|
||||
fprintf(output, "%40s = %s\n", var_name, my_string);
|
||||
break;
|
||||
case(vroniT_SITE):
|
||||
my_string[0] = '\0';
|
||||
switch(*(t_site*)v) {
|
||||
case(SEG):
|
||||
strcat(my_string, "SEG");
|
||||
break;
|
||||
case(ARC):
|
||||
strcat(my_string, "ARC");
|
||||
break;
|
||||
case(PNT):
|
||||
strcat(my_string, "PNT");
|
||||
break;
|
||||
case(VDN):
|
||||
strcat(my_string, "VDN");
|
||||
break;
|
||||
case(VDE):
|
||||
strcat(my_string, "VDE");
|
||||
break;
|
||||
case(DTE):
|
||||
strcat(my_string, "DTE");
|
||||
break;
|
||||
case(CCW):
|
||||
strcat(my_string, "CCW");
|
||||
break;
|
||||
case(CW):
|
||||
strcat(my_string, "CW");
|
||||
break;
|
||||
case(UNKNOWN):
|
||||
strcat(my_string, "UNKNOWN");
|
||||
break;
|
||||
default:
|
||||
strcat(my_string, "***** type not known *****");
|
||||
break;
|
||||
}
|
||||
fprintf(output, "%40s = %s\n", var_name, my_string);
|
||||
break;
|
||||
case(vroniPNTS):
|
||||
my_string[0] = '\0';
|
||||
strcat(my_string, var_name);
|
||||
strcat(my_string, "[");
|
||||
number[0] = '\0';
|
||||
sprintf(number, "%d", *(int*)v);
|
||||
strcat(my_string, number);
|
||||
strcat(my_string, "]");
|
||||
if (InPntsList(*(int*)v)) {
|
||||
strcpy(tmp, my_string);
|
||||
strcat(my_string, ".p ");
|
||||
PrintVarValue(output, &(pnts[*(int*)v].p), my_string, vroniCOORD);
|
||||
strcpy(my_string, tmp);
|
||||
strcat(my_string, ".vd ");
|
||||
PrintVarValue(output, &(pnts[*(int*)v].vd), my_string,
|
||||
vroniINTEGER);
|
||||
strcpy(my_string, tmp);
|
||||
strcat(my_string, ".node");
|
||||
PrintVarValue(output, &(pnts[*(int*)v].node), my_string,
|
||||
vroniINTEGER);
|
||||
strcpy(my_string, tmp);
|
||||
strcat(my_string, ".vis ");
|
||||
PrintVarValue(output, &(pnts[*(int*)v].vis), my_string, vroniBOOLEAN);
|
||||
strcpy(my_string, tmp);
|
||||
strcat(my_string, ".s ");
|
||||
PrintVarValue(output, &(pnts[*(int*)v].s), my_string, vroniBOOLEAN);
|
||||
strcpy(my_string, tmp);
|
||||
strcat(my_string, ".del ");
|
||||
PrintVarValue(output, &(pnts[*(int*)v].del), my_string, vroniBOOLEAN);
|
||||
}
|
||||
else {
|
||||
number[0] = '\0';
|
||||
strcat(number, "***** index out of range! *****");
|
||||
PrintVarValue(output, &(number), my_string, vroniCHARS);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
my_string[0] = '\0';
|
||||
strcat(my_string, "***** type not known *****");
|
||||
PrintVarValue(output, &(var_name), my_string, vroniCHARS);
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
+822
@@ -0,0 +1,822 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* 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.pdf" 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 */
|
||||
/* */
|
||||
/* Acknowledgment: XML input coded by Christian Spielberger. */
|
||||
/* */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* provide support for .e00 and other miscellaneous input formats. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
/* */
|
||||
/* get standard libraries */
|
||||
/* */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
/* */
|
||||
/* get my header files */
|
||||
/* */
|
||||
#include "fpkernel.h"
|
||||
#include "vronivector.h"
|
||||
#include "vroni_object.h"
|
||||
#include "defs.h"
|
||||
|
||||
|
||||
/* */
|
||||
/* move file pointer to next line */
|
||||
/* */
|
||||
#define F_NEW_LINE \
|
||||
{while (((c=fgetc(input)) != '\n') && ( c != EOF)) {}}
|
||||
|
||||
|
||||
/* */
|
||||
/* This function multiplies a point (x, y) with a homogeneous transformation */
|
||||
/* matrix. Thus, */
|
||||
/* */
|
||||
/* x_new = a11 * x_old + a12 * y_old + vx, */
|
||||
/* y_new = a21 * x_old + a22 * y_old + vy. */
|
||||
/* */
|
||||
void Transform(double *x, double *y, double_arg a11, double_arg a21, double_arg a12,
|
||||
double_arg a22, double_arg vx, double_arg vy)
|
||||
{
|
||||
double x0, y0;
|
||||
|
||||
x0 = *x;
|
||||
y0 = *y;
|
||||
|
||||
*x = a11 * x0 + a12 * y0 + vx;
|
||||
*y = a21 * x0 + a22 * y0 + vy;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* this function reads data in USGS format. every polygonal chain is */
|
||||
/* specified as a sequence of (x,y)-pairs. note that all coordinates are */
|
||||
/* positive; a negative coordinate serves as a delimiter between chains. */
|
||||
/* also, we do not take care of isolated points! */
|
||||
/* */
|
||||
void vroniObject::ReadUSGS(char input_file[], vr_bool *new_input)
|
||||
{
|
||||
double xc1, yc1;
|
||||
int i1, number = 0;
|
||||
FILE *input;
|
||||
|
||||
input = OpenFileVD(input_file, "r");
|
||||
*new_input = false;
|
||||
isolated_pnts = false;
|
||||
|
||||
while (EOF != FP_fscanf(input, "%lf", &xc1)) {
|
||||
if (xc1 < 0.0) {
|
||||
/* */
|
||||
/* end of the last polygonal chain */
|
||||
/* */
|
||||
if (number > 0) {
|
||||
if (number == 1)
|
||||
isolated_pnts = true;
|
||||
*new_input = true;
|
||||
}
|
||||
number = 0;
|
||||
}
|
||||
else {
|
||||
if (EOF == FP_fscanf(input, "%lf", &yc1))
|
||||
throw std::runtime_error("VRONI error: ReadUSGS() - premature end of file!");
|
||||
#ifdef EXT_APPL_PNTS
|
||||
|
||||
if (number == 0)
|
||||
i1 = HandlePnt(xc1, yc1, eap_NIL);
|
||||
#else
|
||||
|
||||
if (number == 0)
|
||||
i1 = HandlePnt(xc1, yc1);
|
||||
#endif
|
||||
#ifdef EXT_APPL_SITES
|
||||
|
||||
else
|
||||
AddSeg(&i1, xc1, yc1, eas_NIL);
|
||||
#else
|
||||
|
||||
else
|
||||
AddSeg(&i1, xc1, yc1);
|
||||
#endif
|
||||
|
||||
++number;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(input);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void vroniObject::SkipText(FILE *in_file, char ch)
|
||||
{
|
||||
char dummy;
|
||||
|
||||
do {
|
||||
if (fscanf(in_file, "%c", &dummy) == EOF)
|
||||
throw std::runtime_error("VRONI error: ReadXDRFile() - premature end of file!");
|
||||
}
|
||||
while (dummy != ch);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
char vroniObject::ParseText(FILE *in_file, char ch1, char ch2)
|
||||
{
|
||||
char dummy;
|
||||
|
||||
if (fscanf(in_file, "%c", &dummy) == EOF)
|
||||
throw std::runtime_error("VRONI error: ReadXDRFile() - premature end of file!");
|
||||
if ((dummy == ch1) || (dummy == ch2))
|
||||
return dummy;
|
||||
if (fscanf(in_file, "%c", &dummy) == EOF)
|
||||
throw std::runtime_error("VRONI error: ReadXDRFile() - premature end of file!");
|
||||
if ((dummy == ch1) || (dummy == ch2))
|
||||
return dummy;
|
||||
if (fscanf(in_file, "%c", &dummy) == EOF)
|
||||
throw std::runtime_error("VRONI error: ReadXDRFile() - premature end of file!");
|
||||
return dummy;
|
||||
}
|
||||
|
||||
|
||||
|
||||
vr_bool vroniObject::FindText(FILE *in_file, char ch)
|
||||
{
|
||||
char dummy;
|
||||
|
||||
do {
|
||||
if (fscanf(in_file, "%c", &dummy) == EOF)
|
||||
return false;
|
||||
}
|
||||
while (dummy != ch);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void vroniObject::HandleBlock(FILE *in_file)
|
||||
{
|
||||
int number;
|
||||
char ch;
|
||||
double xc, yc, zc;
|
||||
int i, i1;
|
||||
|
||||
if (fscanf(in_file, "%d", &number) == EOF)
|
||||
throw std::runtime_error("VRONI error: ReadXDRFile() - premature end of file!");
|
||||
|
||||
ch = ParseText(in_file, '(', '[');
|
||||
|
||||
if (ch == '[') {
|
||||
if (FP_fscanf(in_file, "%lf", &xc) == EOF)
|
||||
throw std::runtime_error("VRONI error: ReadXDRFile() - premature end of file!");
|
||||
SkipText(in_file, ',');
|
||||
if (FP_fscanf(in_file, "%lf", &yc) == EOF)
|
||||
throw std::runtime_error("VRONI error: ReadXDRFile() - premature end of file!");
|
||||
SkipText(in_file, ',');
|
||||
if (FP_fscanf(in_file, "%lf", &zc) == EOF)
|
||||
throw std::runtime_error("VRONI error: ReadXDRFile() - premature end of file!");
|
||||
#ifdef EXT_APPL_PNTS
|
||||
i1 = HandlePnt(xc, yc, eap_NIL);
|
||||
#else
|
||||
i1 = HandlePnt(xc, yc);
|
||||
#endif
|
||||
|
||||
for (i = 1; i < number; ++i) {
|
||||
SkipText(in_file, '[');
|
||||
if (FP_fscanf(in_file, "%lf", &xc) == EOF)
|
||||
throw std::runtime_error("VRONI error: ReadXDRFile() - premature end of file!");
|
||||
SkipText(in_file, ',');
|
||||
if (FP_fscanf(in_file, "%lf", &yc) == EOF)
|
||||
throw std::runtime_error("VRONI error: ReadXDRFile() - premature end of file!");
|
||||
SkipText(in_file, ',');
|
||||
if (FP_fscanf(in_file, "%lf", &zc) == EOF)
|
||||
throw std::runtime_error("VRONI error: ReadXDRFile() - premature end of file!");
|
||||
#ifdef EXT_APPL_SITES
|
||||
AddSeg(&i1, xc, yc, eas_NIL);
|
||||
#else
|
||||
AddSeg(&i1, xc, yc);
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
else if (ch == '(') {
|
||||
for (i = 0; i < number; ++i) {
|
||||
SkipText(in_file, '<');
|
||||
HandleBlock(in_file);
|
||||
}
|
||||
}
|
||||
|
||||
SkipText(in_file, ')');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* */
|
||||
/* this is a VERY rudimentary interface for reading Facet_XDR_text_files. */
|
||||
/* note that this interface is not as general as it ought to be. that is, */
|
||||
/* likely it will cough on lots of XDR files. i may try to improve it once */
|
||||
/* i get my hands on a simple description of this format. */
|
||||
/* */
|
||||
void vroniObject::ReadXDRFile(char input_file[], vr_bool *new_input)
|
||||
{
|
||||
FILE *input;
|
||||
vr_bool cont = false;
|
||||
|
||||
input = OpenFileVD(input_file, "r");
|
||||
|
||||
SkipText(input, '[');
|
||||
SkipText(input, '(');
|
||||
SkipText(input, '<');
|
||||
|
||||
do {
|
||||
HandleBlock(input);
|
||||
|
||||
cont = FindText(input, ',');
|
||||
if (cont) {
|
||||
SkipText(input, '(');
|
||||
SkipText(input, '<');
|
||||
}
|
||||
}
|
||||
while (cont);
|
||||
|
||||
fclose(input);
|
||||
|
||||
*new_input = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* this is a VERY rudimentary interface for reading ArcInfo export files. */
|
||||
/* note that this interface is not as general as it ought to be. that is, */
|
||||
/* likely it will cough on lots of E00 files. i may try to improve it once */
|
||||
/* i get my hands on a simple description of this format. */
|
||||
/* */
|
||||
void vroniObject::ReadE00File(char input_file[], vr_bool *new_input)
|
||||
{
|
||||
FILE *input;
|
||||
char ch[100];
|
||||
double xc1, yc1, xc2, yc2;
|
||||
int i, number, version, id, startnode, endnode, lft, rgt, num_vtx;
|
||||
|
||||
input = OpenFileVD(input_file, "r");
|
||||
|
||||
|
||||
while (!(EOF == fscanf(input,"%s", ch))) {
|
||||
if ((ch[0] == 'A') && (ch[1] == 'R') && (ch[2] == 'C')) {
|
||||
if (EOF == fscanf(input,"%d", &version))
|
||||
throw std::runtime_error("VRONI error: ReadE00() - unexpected data format!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (EOF == fscanf(input,"%d", &number))
|
||||
throw std::runtime_error("VRONI error: ReadE00() - unexpected data format!");
|
||||
|
||||
while (number != -1) {
|
||||
if (EOF == fscanf(input,"%d %d %d %d %d %d", &id, &startnode, &endnode,
|
||||
&lft, &rgt, &num_vtx))
|
||||
throw std::runtime_error("VRONI error: ReadE00() - unexpected data format!");
|
||||
if (num_vtx < 2)
|
||||
throw std::runtime_error("VRONI error: ReadE00() - unexpected data format!");
|
||||
if (EOF == FP_fscanf(input, "%lf %lf", &xc1, &yc1))
|
||||
throw std::runtime_error("VRONI error: ReadE00() - premature end of file!");
|
||||
|
||||
for (i = 2; i <= num_vtx; ++i) {
|
||||
if (EOF == FP_fscanf(input, "%lf %lf", &xc2, &yc2))
|
||||
throw std::runtime_error("VRONI error: ReadE00() - premature end of file!");
|
||||
#ifdef EXT_APPL_SITES
|
||||
/* */
|
||||
/* NIL is used as I don't have any application-specific data; you */
|
||||
/* may want to add an integer link to some exterior data field that */
|
||||
/* is to be stored with this segment. */
|
||||
/* */
|
||||
HandleSeg(xc1, yc1, xc2, yc2, eas_NIL);
|
||||
#else
|
||||
HandleSeg(xc1, yc1, xc2, yc2);
|
||||
#endif
|
||||
xc1 = xc2;
|
||||
yc1 = yc2;
|
||||
}
|
||||
if (EOF == fscanf(input,"%d", &number))
|
||||
throw std::runtime_error("VRONI error: ReadE00() - unexpected data format!");
|
||||
}
|
||||
|
||||
*new_input = true;
|
||||
|
||||
fclose(input);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* This function reads XML arc-to-data in the format */
|
||||
/* radius 0 0 radius x_center y_center x_target y_target */
|
||||
/* for a CCW arc, and */
|
||||
/* radius 0 0 -radius x_center y_center x_target y_target */
|
||||
/* for a CW arc. The radius is positiv for CCW orientation and negative for */
|
||||
/* CW orientation. If there is only vertex data in the format */
|
||||
/* x y */
|
||||
/* at the current position, then it is returned in xt, yt and r is set to */
|
||||
/* zero. */
|
||||
/* A full circle is read in the format */
|
||||
/* radius 0 0 radius x_center y_center */
|
||||
/* True is returned, if it was successful. Otherwise, false is returned. */
|
||||
/* */
|
||||
/* In type the kind of read data is returned. */
|
||||
/* 0 for start point, 1 for successive points, 2 for arcs, */
|
||||
/* 3 for full circle, 4 for the closing seg, 5 path ended correctly */
|
||||
/* */
|
||||
vr_bool ReadXMLseg(FILE *input,
|
||||
double *r, double *xc, double *yc, double *xt, double *yt,
|
||||
char *type)
|
||||
{
|
||||
vr_bool ret;
|
||||
double xh, yh;
|
||||
int pos;
|
||||
char c;
|
||||
|
||||
ret = false;
|
||||
pos = FP_fscanf(input, "%lf %lf 0 %lf %lf %lf %lf %lf",
|
||||
&xh, &yh, r, xc, yc, xt, yt);
|
||||
c = fgetc(input);
|
||||
|
||||
switch(pos) {
|
||||
case 0:
|
||||
|
||||
if(c == 'h') {
|
||||
*type = 4;
|
||||
ret = true;
|
||||
}
|
||||
else
|
||||
*type = 5;
|
||||
|
||||
break;
|
||||
case 2:
|
||||
*xt = xh;
|
||||
*r = 0.0;
|
||||
*type = 1;
|
||||
*yt = yh;
|
||||
ret = true;
|
||||
if(c == 'm')
|
||||
*type = 0;
|
||||
else
|
||||
*type = 1;
|
||||
break;
|
||||
case 5:
|
||||
if(c == 'e') {
|
||||
*type = 3;
|
||||
ret = true;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
*type = 2;
|
||||
ret = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* add the segment to VRONI's input data */
|
||||
/* */
|
||||
void vroniObject::AddXMLseg(int *i1, double_arg xt, double_arg yt,
|
||||
double_arg xc, double_arg yc, double_arg r,
|
||||
char type, int i0)
|
||||
{
|
||||
int ih;
|
||||
int orient;
|
||||
|
||||
if (r<0)
|
||||
orient = -ARC;
|
||||
else
|
||||
orient = ARC;
|
||||
|
||||
switch(type) {
|
||||
case 0:
|
||||
#ifdef EXT_APPL_PNTS
|
||||
|
||||
*i1 = HandlePnt(xt, yt, eap_NIL);
|
||||
#else
|
||||
|
||||
*i1 = HandlePnt(xt, yt);
|
||||
#endif
|
||||
|
||||
break;
|
||||
case 1:
|
||||
#ifdef EXT_APPL_SITES
|
||||
|
||||
AddSeg(i1, xt, yt, eas_NIL);
|
||||
#else
|
||||
|
||||
AddSeg(i1, xt, yt);
|
||||
#endif
|
||||
|
||||
break;
|
||||
case 2:
|
||||
#ifdef EXT_APPL_SITES
|
||||
|
||||
AddArc(i1, xt, yt, xc, yc, orient, eas_NIL);
|
||||
#else
|
||||
|
||||
AddArc(i1, xt, yt, xc, yc, orient);
|
||||
#endif
|
||||
|
||||
break;
|
||||
case 3:
|
||||
#ifdef EXT_APPL_PNTS
|
||||
|
||||
*i1 = HandlePnt(xc+fabs(r), yc, eap_NIL);
|
||||
ih = *i1;
|
||||
#else
|
||||
*i1 = HandlePnt(xc+r, yc);
|
||||
ih = *i1;
|
||||
#endif
|
||||
#ifdef EXT_APPL_SITES
|
||||
AddArc(i1, xc, yc+r, xc, yc, orient, eas_NIL);
|
||||
AddArc(i1, xc-fabs(r), yc, xc, yc, orient, eas_NIL);
|
||||
AddArc(i1, xc, yc-r, xc, yc, orient, eas_NIL);
|
||||
CloseArc(*i1, ih, xc, yc, orient, eas_NIL);
|
||||
#else
|
||||
AddArc(i1, xc, yc+r, xc, yc, orient);
|
||||
AddArc(i1, xc-fabs(r), yc, xc, yc, orient);
|
||||
AddArc(i1, xc, yc-r, xc, yc, orient);
|
||||
CloseArc(*i1, ih, xc, yc, orient);
|
||||
#endif
|
||||
|
||||
break;
|
||||
case 4:
|
||||
/* */
|
||||
/* close the chain */
|
||||
/* */
|
||||
#ifdef EXT_APPL_SITES
|
||||
CloseSeg(*i1, i0, eas_NIL);
|
||||
#else
|
||||
CloseSeg(*i1, i0);
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
vr_bool vroniObject::ReadIpePath(FILE *input)
|
||||
{
|
||||
double xc, yc, r, xt, yt;
|
||||
double a11, a12, a21, a22, vx, vy;
|
||||
int pos;
|
||||
int i0 = NIL, i1;
|
||||
vr_bool ok;
|
||||
vr_bool tr;
|
||||
vr_bool arcOrientChange;
|
||||
char type;
|
||||
char c;
|
||||
const char *sstr2[] = {"matrix=\"", ">"};
|
||||
const char *sstr3[] = {">"};
|
||||
|
||||
i1 = NIL;
|
||||
ok = true;
|
||||
arcOrientChange = false;
|
||||
|
||||
/* read transformation matrix */
|
||||
switch(fSeeks(input, sstr2, 2)) {
|
||||
case 1:
|
||||
pos = FP_fscanf(input, "%lf %lf %lf %lf %lf %lf", &a11, &a21, &a12,
|
||||
&a22, &vx, &vy);
|
||||
tr = (pos==6);
|
||||
if (!tr) {
|
||||
printf("ReadXML(): file position: %ld", ftell(input));
|
||||
throw std::runtime_error("VRONI error: ReadXML() - matrix could not be read correctly!");
|
||||
}
|
||||
else {
|
||||
arcOrientChange = ((a12 * a21 - a11 * a22) > 0.0);
|
||||
}
|
||||
ok = (fSeeks(input, sstr3, 1) != 0);
|
||||
break;
|
||||
case 2:
|
||||
a11=1.0;
|
||||
a21=0;
|
||||
a12=0;
|
||||
a22=1.0;
|
||||
vx=0;
|
||||
vy=0;
|
||||
tr = false;
|
||||
ok = true;
|
||||
break;
|
||||
default:
|
||||
tr = false;
|
||||
ok = (fSeeks(input, sstr3, 1) != 0);
|
||||
break;
|
||||
}
|
||||
|
||||
while (ok) {
|
||||
|
||||
F_NEW_LINE;
|
||||
ok = ReadXMLseg(input, &r, &xc, &yc, &xt, &yt, &type);
|
||||
|
||||
if (ok) {
|
||||
if (tr) {
|
||||
if ((type==2) || (type==3))
|
||||
Transform(&xc, &yc, a11, a21, a12, a22, vx, vy);
|
||||
Transform(&xt, &yt, a11, a21, a12, a22, vx, vy);
|
||||
}
|
||||
if(arcOrientChange)
|
||||
r = -r;
|
||||
AddXMLseg(&i1, xt, yt, xc, yc, r, type, i0);
|
||||
|
||||
if(type==0) {
|
||||
i0 = i1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(type!=5) {
|
||||
printf("ReadXML(): file position: %ld", ftell(input));
|
||||
throw std::runtime_error("VRONI error: ReadXML() - sub path not read correctly!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (i1!=NIL);
|
||||
}
|
||||
|
||||
|
||||
vr_bool vroniObject::ReadIpeMark(FILE *input)
|
||||
{
|
||||
double xt, yt;
|
||||
double a11, a12, a21, a22, vx, vy;
|
||||
vr_bool stop;
|
||||
vr_bool ok;
|
||||
vr_bool tr;
|
||||
int pos;
|
||||
const char *sstr2[] = {"matrix=\"", "pos=\"", ">"};
|
||||
|
||||
stop = false;
|
||||
ok = false;
|
||||
tr = false;
|
||||
a11=1.0;
|
||||
a21=0;
|
||||
a12=0;
|
||||
a22=1.0;
|
||||
vx=0;
|
||||
vy=0;
|
||||
|
||||
while (!stop) {
|
||||
switch(fSeeks(input, sstr2, 2)) {
|
||||
case 1:
|
||||
pos = FP_fscanf(input, "%lf %lf %lf %lf %lf %lf", &a11, &a21, &a12,
|
||||
&a22, &vx, &vy);
|
||||
tr = (pos==6);
|
||||
if (!tr) {
|
||||
printf("ReadXML(): file position: %ld", ftell(input));
|
||||
throw std::runtime_error("VRONI error: ReadXML() - matrix could not be read correctly!");
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
pos = FP_fscanf(input, "%lf %lf", &xt, &yt);
|
||||
if (pos==2) {
|
||||
ok = true;
|
||||
}
|
||||
stop = true;
|
||||
|
||||
break;
|
||||
default:
|
||||
stop = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
if (tr)
|
||||
Transform(&xt, &yt, a11, a21, a12, a22, vx, vy);
|
||||
#ifdef EXT_APPL_PNTS
|
||||
|
||||
HandlePnt(xt, yt, eap_NIL);
|
||||
#else
|
||||
|
||||
HandlePnt(xt, yt);
|
||||
#endif
|
||||
|
||||
}
|
||||
else { /* if (ok) */
|
||||
printf("file position: %ld", ftell(input));
|
||||
throw std::runtime_error("VRONI error: ReadXML() - Ipe mark not read correctly!");
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
void vroniObject::ReadXML(char input_file[], vr_bool *new_input)
|
||||
{
|
||||
vr_bool ret = false;
|
||||
char type;
|
||||
FILE *input;
|
||||
|
||||
/* define the search strings */
|
||||
const char *sstr0[] = {"<page"};
|
||||
const char *sstr1[] = {"<path","<mark"};
|
||||
|
||||
input = OpenFileVD(input_file, "r");
|
||||
if (input == NULL)
|
||||
throw std::runtime_error("VRONI error: ReadXML() - input file could not be opened!");
|
||||
|
||||
/* Ignore until <page> tag */
|
||||
if (fSeeks(input, sstr0, 1)) {
|
||||
while ((type = static_cast<char>(fSeeks(input, sstr1, 2)))) {
|
||||
switch(type) {
|
||||
case 1:
|
||||
ret |= ReadIpePath(input);
|
||||
break;
|
||||
case 2:
|
||||
ret |= ReadIpeMark(input);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*new_input = ret;
|
||||
}
|
||||
fclose(input);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
vr_bool vroniObject::ReadGraphMLNode(FILE *input)
|
||||
{
|
||||
vr_bool stop, x_read, y_read;
|
||||
double xc, yc;
|
||||
int pos;
|
||||
const char *sstr2[] = {"<data key=\"x\">", "<data key=\"y\">"};
|
||||
|
||||
stop = false;
|
||||
x_read = false;
|
||||
y_read = false;
|
||||
|
||||
while (!stop) {
|
||||
switch(fSeeks(input, sstr2, 2)) {
|
||||
case 1:
|
||||
pos = FP_fscanf(input, "%lf", &xc);
|
||||
if (!(pos == 1)) {
|
||||
printf("ReadGraphML(): file position: %ld", ftell(input));
|
||||
throw std::runtime_error("VRONI error: ReadGraphML() - x-coordinate could not be read correctly!");
|
||||
}
|
||||
else {
|
||||
x_read = true;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
pos = FP_fscanf(input, "%lf", &yc);
|
||||
if (!(pos == 1)) {
|
||||
printf("ReadGraphML(): file position: %ld", ftell(input));
|
||||
throw std::runtime_error("VRONI error: ReadGraphML() - y-coordinate could not be read correctly!");
|
||||
}
|
||||
else {
|
||||
y_read = true;
|
||||
}
|
||||
default:
|
||||
stop = true;
|
||||
break;
|
||||
}
|
||||
stop = stop || (x_read && y_read);
|
||||
}
|
||||
|
||||
if (x_read && y_read) {
|
||||
#ifdef EXT_APPL_PNTS
|
||||
(void) HandlePnt(xc, yc, eap_NIL);
|
||||
#else
|
||||
|
||||
(void) HandlePnt(xc, yc);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
vr_bool vroniObject::ReadGraphMLEdge(FILE *input)
|
||||
{
|
||||
vr_bool ok = true;
|
||||
int i1, i2, i3;
|
||||
int pos;
|
||||
|
||||
|
||||
pos = FP_fscanf(input, "source=\"%d\" target=\"%d\"", &i1, &i2);
|
||||
if (!(pos == 2)) {
|
||||
printf("ReadGraphML(): file position: %ld", ftell(input));
|
||||
throw std::runtime_error("VRONI error: ReadGraphML() - edge could not be read correctly!");
|
||||
}
|
||||
else {
|
||||
/* */
|
||||
/* we need to offset the point indices by 2 due to two dummy points */
|
||||
/* that define the left corners of the bounding box */
|
||||
/* */
|
||||
#ifdef EXT_APPL_SITES
|
||||
i3 = StoreSeg(i1 + 2, i2 + 2, eas_NIL);
|
||||
#else
|
||||
i3 = StoreSeg(i1 + 2, i2 + 2);
|
||||
#endif
|
||||
#ifdef GRAPHICS
|
||||
if (graphics) {
|
||||
AddSegToBuffer(i3, SegColor);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* this function reads data of the Salzburg Database in GraphML format. */
|
||||
/* please note that this function is tailored towards the formatting used by */
|
||||
/* the Salzburg Database. it is not(!) a general-purpose parser of GraphML */
|
||||
/* files! */
|
||||
/* */
|
||||
void vroniObject::ReadGraphML(char input_file[], vr_bool *new_input)
|
||||
{
|
||||
vr_bool ret = false;
|
||||
char type;
|
||||
FILE *input;
|
||||
|
||||
/* define the search strings */
|
||||
const char *sstr0[] = {"<graph "};
|
||||
const char *sstr1[] = {"<node ","<edge "};
|
||||
|
||||
input = OpenFileVD(input_file, "r");
|
||||
if (input == NULL)
|
||||
throw std::runtime_error("VRONI error: ReadGraphML() - input file could not be opened!");
|
||||
|
||||
/* Ignore until <graph> tag */
|
||||
if (fSeeks(input, sstr0, 1)) {
|
||||
while ((type = static_cast<char>(fSeeks(input, sstr1, 2)))) {
|
||||
switch(type) {
|
||||
case 1:
|
||||
ret |= ReadGraphMLNode(input);
|
||||
break;
|
||||
case 2:
|
||||
ret |= ReadGraphMLEdge(input);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*new_input = ret;
|
||||
}
|
||||
|
||||
fclose(input);
|
||||
|
||||
return;
|
||||
}
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* 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-611 */
|
||||
/* Voice Mail: (+43 662) 8044-6304 */
|
||||
/* Snail Mail: Martin Held */
|
||||
/* FB Informatik */
|
||||
/* Universitaet Salzburg */
|
||||
/* A-5020 Salzburg, Austria */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* output routines for generating test data for VD codes implemented */
|
||||
/* by other colleagues. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
/* */
|
||||
/* get standard libraries */
|
||||
/* */
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
/* */
|
||||
/* get my header files */
|
||||
/* */
|
||||
#include "fpkernel.h"
|
||||
#include "vronivector.h"
|
||||
#include "defs.h"
|
||||
#include "numerics.h"
|
||||
|
||||
#ifdef OTHER
|
||||
|
||||
/* */
|
||||
/* function prototypes of functions provided in this file */
|
||||
/* */
|
||||
void WriteCgalSites(char output_file[]);
|
||||
|
||||
|
||||
|
||||
void WriteCgalSites(char output_file[])
|
||||
{
|
||||
int i;
|
||||
FILE *output;
|
||||
|
||||
output = OpenFileVD(output_file, "w");
|
||||
|
||||
/*
|
||||
for (i = 2; i < num_pnts-2; ++i) {
|
||||
fprintf(output, "p\n%20.16f %20.16f\n", pnts[i].p.x, pnts[i].p.y);
|
||||
}
|
||||
*/
|
||||
|
||||
for (i = 0; i < num_segs; ++i) {
|
||||
fprintf(output, "s\n%20.16f %20.16f %20.16f %20.16f\n",
|
||||
pnts[segs[i].i1].p.x, pnts[segs[i].i1].p.y,
|
||||
pnts[segs[i].i2].p.x, pnts[segs[i].i2].p.y);
|
||||
}
|
||||
|
||||
fclose(output);
|
||||
|
||||
if (num_arcs > 0)
|
||||
throw std::runtime_error("VRONI error: WriteCgalSites() - circular arcs not supported by CGAL's VD code!");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
+252
@@ -0,0 +1,252 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* 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.pdf" 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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include "vronivector.h"
|
||||
|
||||
/* */
|
||||
/* get my header files */
|
||||
/* */
|
||||
#include "fpkernel.h"
|
||||
#include "vroni_object.h"
|
||||
#include "defs.h"
|
||||
#include "ext_appl_defs.h"
|
||||
|
||||
|
||||
/* */
|
||||
/* the following functions provide the basic functionality for parsing my */
|
||||
/* data files. you are welcome to adapt them to your needs. however, please */
|
||||
/* note that my own data files do not contain "exterior application" data. */
|
||||
/* thus, you won't be able to parse my sample data files after switching to */
|
||||
/* "exterior application" or after modifying the I/O strings. all input */
|
||||
/* functions return "false" if EOF or an incorrect data format is */
|
||||
/* encountered, and "true" otherwise. you are welcome to modify those */
|
||||
/* functions according to your needs. in particular, please note that the */
|
||||
/* exterior application macros (e.g., ExtApplFuncReadOptNumber) allow you */
|
||||
/* to modify the code in a non-invasive manner. however, please make sure */
|
||||
/* not to change the characteristics of the functions' return values! */
|
||||
/* */
|
||||
/* see io_basic.c for details on my input routines that use those functions. */
|
||||
/* */
|
||||
|
||||
|
||||
|
||||
vr_bool vroniObject::ReadOptionalNumber(FILE *input, int *data)
|
||||
{
|
||||
ExtApplFuncReadOptNumber;
|
||||
|
||||
if (EOF == fscanf(input, "%d", data))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
vr_bool vroniObject::ReadOptionalCoord(FILE *input, double *xy)
|
||||
{
|
||||
ExtApplFuncReadOptCoord;
|
||||
|
||||
if (EOF == FP_fscanf(input, "%lf", xy))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
vr_bool vroniObject::ReadNumber(FILE *input, int *data)
|
||||
{
|
||||
ExtApplFuncReadNumber;
|
||||
|
||||
if (EOF == fscanf(input, "%d", data))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#ifdef EXT_APPL_PNTS
|
||||
vr_bool vroniObject::ReadPntData(FILE *input, double *xc, double *yc, eap_type *eap_data)
|
||||
{
|
||||
/*
|
||||
* sample line for user-specific eap data:
|
||||
* if (EOF == fscanf(input, "%lf, %lf, %ld, %s", xc, yc,
|
||||
* &(eap_data->id), eap_data->ch))
|
||||
*/
|
||||
|
||||
ExtApplFuncReadPntData;
|
||||
|
||||
if (EOF == FP_fscanf(input, "%lf %lf %d", xc, yc, eap_data))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
vr_bool vroniObject::ReadPntData(FILE *input, double *xc, double *yc)
|
||||
{
|
||||
ExtApplFuncReadPntData;
|
||||
|
||||
if (EOF == FP_fscanf(input, "%lf %lf", xc, yc))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef EXT_APPL_SITES
|
||||
vr_bool vroniObject::ReadSiteData(FILE *input, double *xc, double *yc, eas_type *eas_data)
|
||||
{
|
||||
ExtApplFuncReadSiteData;
|
||||
|
||||
if (EOF == FP_fscanf(input, "%lf %lf %d", xc, yc, eas_data))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
vr_bool vroniObject::ReadSiteData(FILE *input, double *xc, double *yc)
|
||||
{
|
||||
ExtApplFuncReadSiteData;
|
||||
|
||||
if (EOF == FP_fscanf(input, "%lf %lf", xc, yc))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
vr_bool vroniObject::ReadVectorData(FILE *input, double *xc, double *yc)
|
||||
{
|
||||
ExtApplFuncReadVectorData;
|
||||
|
||||
if (EOF == FP_fscanf(input, "%lf %lf", xc, yc))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#ifdef EXT_APPL_PNTS
|
||||
void vroniObject::WritePntData(FILE *output, double_arg xc, double_arg yc, eap_type *eap_data)
|
||||
{
|
||||
ExtApplFuncWritePntData;
|
||||
|
||||
FP_fprintf(output, "%f %f %d\n", FP_PRNTARG(xc), FP_PRNTARG(yc), *eap_data);
|
||||
/*
|
||||
* sample line for user-specific eap data
|
||||
*
|
||||
* fprintf(output, "%10d %10d %12ld %10s\n",
|
||||
* (int) (xc + 0.5), (int) (yc + 0.5),
|
||||
* eap_data->id, eap_data->ch);
|
||||
*/
|
||||
|
||||
return;
|
||||
}
|
||||
#else
|
||||
void vroniObject::WritePntData(FILE *output, double_arg xc, double_arg yc)
|
||||
{
|
||||
ExtApplFuncWritePntData;
|
||||
|
||||
FP_fprintf(output, "%20.16f %20.16f\n", FP_PRNTARG(xc), FP_PRNTARG(yc));
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* This function sets the file pointer of file "input" after the next */
|
||||
/* occurrence of one of the input strings. It returns the position (index+1) */
|
||||
/* of the string found in the array of strings. If EOF is reached before any */
|
||||
/* of the strings was found, zero is returned. */
|
||||
/* */
|
||||
short vroniObject::fSeeks(FILE *input, /* pointer to the file handle */
|
||||
const char *strings[], /* array of strings to be searched for */
|
||||
short nbr) /* number of strings in strings[] */
|
||||
{
|
||||
int *p = (int*) NULL; /* array of indices of current string position */
|
||||
int *len = (int*) NULL; /* array of string lengths */
|
||||
char sc; /* char sought */
|
||||
char rc; /* char read */
|
||||
short fidx; /* index of string found */
|
||||
short cidx; /* index of current string */
|
||||
|
||||
len = (int*) ReallocateArray(len, nbr, sizeof(int), "fSeek:len");
|
||||
for (cidx = 0; cidx < nbr; cidx++)
|
||||
len[cidx] = (int) strlen(strings[cidx]);
|
||||
|
||||
p = (int*) ReallocateArray(p, nbr, sizeof(int), "fSeek:p");
|
||||
for(cidx = 0; cidx < nbr; cidx++)
|
||||
p[cidx] = 0;
|
||||
|
||||
fidx = 0;
|
||||
cidx = 0;
|
||||
|
||||
/* */
|
||||
/* loop through file */
|
||||
/* */
|
||||
while(!fidx && ((rc=fgetc(input))!=EOF)) {
|
||||
|
||||
/* */
|
||||
/* loop over all search strings */
|
||||
/* */
|
||||
for(cidx = 0; (cidx < nbr) && !fidx; cidx++) {
|
||||
/* */
|
||||
/* retrieve char sought */
|
||||
/* */
|
||||
sc = strings[cidx][p[cidx]];
|
||||
/* */
|
||||
/* has the char sought been found ? */
|
||||
/* */
|
||||
if(rc == sc) {
|
||||
/* */
|
||||
/* was it the last char of the current string */
|
||||
/* */
|
||||
if((p[cidx] + 1) == len[cidx])
|
||||
fidx = cidx + 1; /* ready for exit */
|
||||
|
||||
else
|
||||
p[cidx]++; /* try next char of current string */
|
||||
|
||||
}
|
||||
else {
|
||||
/* */
|
||||
/* restart at first char of current string */
|
||||
/* */
|
||||
p[cidx] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FreeMemory((void**) &len, "fSeek:len");
|
||||
FreeMemory((void**) &p, "fSeek:p");
|
||||
|
||||
return fidx;
|
||||
}
|
||||
+428
@@ -0,0 +1,428 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* 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-611 */
|
||||
/* Voice Mail: (+43 662) 8044-6304 */
|
||||
/* Snail Mail: Martin Held */
|
||||
/* FB Informatik */
|
||||
/* Universitaet Salzburg */
|
||||
/* A-5020 Salzburg, Austria */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* output routines for VD and DT. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* get standard libraries */
|
||||
/* */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* */
|
||||
/* get my header files */
|
||||
/* */
|
||||
#include "fpkernel.h"
|
||||
#include "vronivector.h"
|
||||
#include "vroni_object.h"
|
||||
#include "defs.h"
|
||||
|
||||
|
||||
/* #define GEOMVIEW */
|
||||
/* #define OBJ */
|
||||
|
||||
|
||||
|
||||
|
||||
void vroniObject::WriteVoronoiRegion(int i, FILE *output)
|
||||
{
|
||||
int i1, number, e, e0, e1, n, n1;
|
||||
coord p;
|
||||
t_site t1;
|
||||
|
||||
p = GetPntCoords(i);
|
||||
|
||||
fprintf(output, "\nVoronoi polygon of pnt %d (%23.16f %23.16f):\n", i - 2,
|
||||
FP_PRNTARG(UnscaleX(p.x)),
|
||||
FP_PRNTARG(UnscaleY(p.y)));
|
||||
|
||||
number = num_pnts - 2;
|
||||
e0 = GetVDPtr(i, PNT); /* get VD edge that belongs to this region */
|
||||
assert(InEdgesList(e0));
|
||||
e = e0;
|
||||
#ifndef NDEBUG
|
||||
if (IsLftSite(e, i, PNT)) n1 = GetStartNode(e);
|
||||
else n1 = GetEndNode(e);
|
||||
#endif
|
||||
|
||||
/* */
|
||||
/* CCW traversal of the boundary of the Voronoi region of pnt i. */
|
||||
/* */
|
||||
do {
|
||||
/* */
|
||||
/* process VD edge e */
|
||||
/* */
|
||||
if (IsLftSite(e, i, PNT)) {
|
||||
n = GetStartNode(e);
|
||||
assert(n1 == n);
|
||||
n1 = GetEndNode(e);
|
||||
e1 = GetCWEdge(e, n1);
|
||||
GetRgtSiteData(e, &i1, &t1); /* other defining site of edge e */
|
||||
}
|
||||
else {
|
||||
assert(IsRgtSite(e, i, PNT));
|
||||
n = GetEndNode(e);
|
||||
assert(n1 == n);
|
||||
n1 = GetStartNode(e);
|
||||
e1 = GetCWEdge(e, n1);
|
||||
GetLftSiteData(e, &i1, &t1); /* other defining site of edge e */
|
||||
}
|
||||
assert(t1 == PNT);
|
||||
if (!IsDeg2Node(n)) {
|
||||
/* */
|
||||
/* degree-two nodes are artifacts of my algorithm; since they */
|
||||
/* do not really belong to the VD, we'll skip them. */
|
||||
/* */
|
||||
p = GetNodeCoord(n);
|
||||
if ((i1 <= 1) || (i1 >= number)) i1 = NIL;
|
||||
if (i1 != NIL)
|
||||
FP_fprintf(output, "%23.16f %23.16f %d\n",
|
||||
FP_PRNTARG(UnscaleX(p.x)),
|
||||
FP_PRNTARG(UnscaleY(p.y)),
|
||||
i1 - 2);
|
||||
else
|
||||
FP_fprintf(output, "%23.16f %23.16f %d\n",
|
||||
FP_PRNTARG(UnscaleX(p.x)), FP_PRNTARG(UnscaleY(p.y)),
|
||||
NIL);
|
||||
}
|
||||
e = e1;
|
||||
} while (e != e0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void vroniObject::WriteVDDT(char output_file[])
|
||||
#ifdef GEOMVIEW /******************* OFF output for Geomview *****************/
|
||||
{
|
||||
FILE *output;
|
||||
int i, i1, i2, i3, number, e0, e1, n, num_nodes;
|
||||
int pnt_cntr = 0, tri_cntr = 0;
|
||||
t_site t1, t2, t3;
|
||||
#ifdef EXT_APPL_PNTS
|
||||
eap_type eap_data;
|
||||
#endif
|
||||
|
||||
output = OpenFileVD(output_file, "w");
|
||||
assert(gt(scale_factor, ZERO));
|
||||
|
||||
/* */
|
||||
/* count the number of points and triangles, and write to Geomview file */
|
||||
/* */
|
||||
number = num_pnts - 2;
|
||||
for (i = 2; i < number; ++i) {
|
||||
if (!IsDeletedPnt(i)) ++pnt_cntr;
|
||||
}
|
||||
num_nodes = GetNumberOfNodes();
|
||||
for (n = 0; n < num_nodes; ++n) {
|
||||
if ((GetNodeStatus(n) != MISC) && (GetNodeStatus(n) != DELETED)) {
|
||||
if (!IsDeg2Node(n)) {
|
||||
assert(IsNodeUnchecked(n));
|
||||
e0 = GetIncidentEdge(n);
|
||||
assert(InEdgesList(e0));
|
||||
e1 = GetCCWEdge(e0, n);
|
||||
if (IsEndNode(e0, n)) {
|
||||
GetLftSiteData(e0, &i1, &t1);
|
||||
GetRgtSiteData(e0, &i2, &t2);
|
||||
}
|
||||
else {
|
||||
GetLftSiteData(e0, &i2, &t2);
|
||||
GetRgtSiteData(e0, &i1, &t1);
|
||||
}
|
||||
if (IsEndNode(e1, n)) {
|
||||
GetRgtSiteData(e1, &i3, &t3);
|
||||
}
|
||||
else {
|
||||
GetLftSiteData(e1, &i3, &t3);
|
||||
}
|
||||
if ((i1 <= 1) || (i1 >= number)) i1 = NIL;
|
||||
if ((i2 <= 1) || (i2 >= number)) i2 = NIL;
|
||||
if ((i3 <= 1) || (i3 >= number)) i3 = NIL;
|
||||
if ((i1 != NIL) && (i2 != NIL) && (i3 != NIL)) {
|
||||
/* */
|
||||
/* all three points are original input points */
|
||||
/* */
|
||||
++tri_cntr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf(output, "OFF\n");
|
||||
fprintf(output, "%d %d %d\n", pnt_cntr, tri_cntr, 3 * tri_cntr);
|
||||
|
||||
/* */
|
||||
/* write the point sites in sorted order. (the first two and the last two */
|
||||
/* points are not output since they do not belong to the original input.) */
|
||||
/* */
|
||||
for (i = 2; i < number; ++i) {
|
||||
if (!IsDeletedPnt(i)) {
|
||||
#ifdef EXT_APPL_PNTS /* write coords plus site ID */
|
||||
eap_data = GetExtApplPnt(i);
|
||||
WritePntData(output, UnscaleX(GetPntCoords(i).x), UnscaleY(GetPntCoords(i).y),
|
||||
&eap_data);
|
||||
#else /* write coords only */
|
||||
WritePntData(output, UnscaleX(GetPntCoords(i).x), UnscaleY(GetPntCoords(i).y));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
/* output all triangles of the DT; the vertices of all triangles are */
|
||||
/* arranged in CCW order. */
|
||||
/* */
|
||||
for (n = 0; n < num_nodes; ++n) {
|
||||
/* */
|
||||
/* loop through all nodes and check whether they are part of the final */
|
||||
/* VD. */
|
||||
/* */
|
||||
if ((GetNodeStatus(n) != MISC) && (GetNodeStatus(n) != DELETED)) {
|
||||
if (!IsDeg2Node(n)) {
|
||||
/* */
|
||||
/* this is a genuine degree-three node of the VD that */
|
||||
/* corresponds to a triangle of the DT */
|
||||
/* */
|
||||
assert(IsNodeUnchecked(n));
|
||||
e0 = GetIncidentEdge(n);
|
||||
assert(InEdgesList(e0));
|
||||
e1 = GetCCWEdge(e0, n);
|
||||
if (IsEndNode(e0, n)) {
|
||||
GetLftSiteData(e0, &i1, &t1);
|
||||
GetRgtSiteData(e0, &i2, &t2);
|
||||
}
|
||||
else {
|
||||
GetLftSiteData(e0, &i2, &t2);
|
||||
GetRgtSiteData(e0, &i1, &t1);
|
||||
}
|
||||
if (IsEndNode(e1, n)) {
|
||||
GetRgtSiteData(e1, &i3, &t3);
|
||||
}
|
||||
else {
|
||||
GetLftSiteData(e1, &i3, &t3);
|
||||
}
|
||||
if ((i1 <= 1) || (i1 >= number)) i1 = NIL;
|
||||
if ((i2 <= 1) || (i2 >= number)) i2 = NIL;
|
||||
if ((i3 <= 1) || (i3 >= number)) i3 = NIL;
|
||||
if ((i1 != NIL) && (i2 != NIL) && (i3 != NIL)) {
|
||||
/* */
|
||||
/* all three points are original input points */
|
||||
/* */
|
||||
assert(t1 == PNT);
|
||||
assert(t2 == PNT);
|
||||
assert(t3 == PNT);
|
||||
fprintf(output, "3 %d %d %d 0 255 0\n",
|
||||
i1 - 2 , i2 - 2, i3 - 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(output);
|
||||
|
||||
return;
|
||||
}
|
||||
#else
|
||||
#ifdef OBJ /********************** output in OBJ format **********************/
|
||||
{
|
||||
FILE *output;
|
||||
int i, i1, i2, i3, number, e0, e1, n, num_nodes;
|
||||
t_site t1, t2, t3;
|
||||
#ifdef EXT_APPL_PNTS
|
||||
eap_type eap_data;
|
||||
#endif
|
||||
|
||||
output = OpenFileVD(output_file, "w");
|
||||
assert(gt(scale_factor, ZERO));
|
||||
|
||||
/* */
|
||||
/* write the point sites in sorted order. (the first two and the last two */
|
||||
/* points are not output since they do not belong to the original input.) */
|
||||
/* */
|
||||
number = num_pnts - 2;
|
||||
for (i = 2; i < number; ++i) {
|
||||
if (!IsDeletedPnt(i)) {
|
||||
#ifdef EXT_APPL_PNTS /* write coords plus site ID */
|
||||
eap_data = GetExtApplPnt(i);
|
||||
WritePntData(output, UnscaleX(GetPntCoords(i).x), UnscaleY(GetPntCoords(i).y),
|
||||
&eap_data);
|
||||
#else /* write coords only */
|
||||
WritePntData(output, UnscaleX(GetPntCoords(i).x), UnscaleY(GetPntCoords(i).y));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
/* output all triangles of the DT; the vertices of all triangles are */
|
||||
/* arranged in CCW order. */
|
||||
/* */
|
||||
num_nodes = GetNumberOfNodes();
|
||||
for (n = 0; n < num_nodes; ++n) {
|
||||
/* */
|
||||
/* loop through all nodes and check whether they are part of the final */
|
||||
/* VD. */
|
||||
/* */
|
||||
if ((GetNodeStatus(n) != MISC) && (GetNodeStatus(n) != DELETED)) {
|
||||
if (!IsDeg2Node(n)) {
|
||||
/* */
|
||||
/* this is a genuine degree-three node of the VD that */
|
||||
/* corresponds to a triangle of the DT */
|
||||
/* */
|
||||
assert(IsNodeUnchecked(n));
|
||||
e0 = GetIncidentEdge(n);
|
||||
assert(InEdgesList(e0));
|
||||
e1 = GetCCWEdge(e0, n);
|
||||
if (IsEndNode(e0, n)) {
|
||||
GetLftSiteData(e0, &i1, &t1);
|
||||
GetRgtSiteData(e0, &i2, &t2);
|
||||
}
|
||||
else {
|
||||
GetLftSiteData(e0, &i2, &t2);
|
||||
GetRgtSiteData(e0, &i1, &t1);
|
||||
}
|
||||
if (IsEndNode(e1, n)) {
|
||||
GetRgtSiteData(e1, &i3, &t3);
|
||||
}
|
||||
else {
|
||||
GetLftSiteData(e1, &i3, &t3);
|
||||
}
|
||||
if ((i1 <= 1) || (i1 >= number)) i1 = NIL;
|
||||
if ((i2 <= 1) || (i2 >= number)) i2 = NIL;
|
||||
if ((i3 <= 1) || (i3 >= number)) i3 = NIL;
|
||||
if ((i1 != NIL) && (i2 != NIL) && (i3 != NIL)) {
|
||||
/* */
|
||||
/* all three points are original input points */
|
||||
/* */
|
||||
assert(t1 == PNT);
|
||||
assert(t2 == PNT);
|
||||
assert(t3 == PNT);
|
||||
fprintf(output, "f %d %d %d\n", i1 - 1 , i2 - 1, i3 - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(output);
|
||||
|
||||
return;
|
||||
}
|
||||
#else /******************** standard output **********************************/
|
||||
{
|
||||
FILE *output;
|
||||
int i, i1, i2, i3, number, e0, e1, n, num_nodes;
|
||||
coord p;
|
||||
t_site t1, t2, t3;
|
||||
#ifdef EXT_APPL_PNTS
|
||||
eap_type eap_data;
|
||||
#endif
|
||||
|
||||
output = OpenFileVD(output_file, "w");
|
||||
assert(gt(scale_factor, ZERO));
|
||||
|
||||
/* */
|
||||
/* write the point sites in sorted order. (the first two and the last two */
|
||||
/* points are not output since they do not belong to the original input.) */
|
||||
/* */
|
||||
number = num_pnts - 2;
|
||||
fprintf(output, "%d\n", number - 2);
|
||||
for (i = 2; i < number; ++i) {
|
||||
if (!IsDeletedPnt(i)) {
|
||||
#ifdef EXT_APPL_PNTS /* write coords plus site ID */
|
||||
eap_data = GetExtApplPnt(i);
|
||||
WritePntData(output, UnscaleX(GetPntCoords(i).x), UnscaleY(GetPntCoords(i).y),
|
||||
&eap_data);
|
||||
#else /* write coords only */
|
||||
WritePntData(output, UnscaleX(GetPntCoords(i).x), UnscaleY(GetPntCoords(i).y));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
/* traverse all Voronoi regions and write their boundaries in CCW order */
|
||||
/* */
|
||||
for (i = 2; i < number; ++i) {
|
||||
if (!IsDeletedPnt(i)) {
|
||||
WriteVoronoiRegion(i, output);
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
/* output all triangles of the DT; the vertices of all triangles are */
|
||||
/* arranged in CCW order. */
|
||||
/* */
|
||||
fprintf(output, "\nDelaunay triangles:\n");
|
||||
|
||||
num_nodes = GetNumberOfNodes();
|
||||
for (n = 0; n < num_nodes; ++n) {
|
||||
/* */
|
||||
/* loop through all nodes and check whether they are part of the final */
|
||||
/* VD. */
|
||||
/* */
|
||||
if ((GetNodeStatus(n) != MISC) && (GetNodeStatus(n) != DELETED)) {
|
||||
if (!IsDeg2Node(n)) {
|
||||
/* */
|
||||
/* this is a genuine degree-three node of the VD that */
|
||||
/* corresponds to a triangle of the DT */
|
||||
/* */
|
||||
assert(IsNodeUnchecked(n));
|
||||
e0 = GetIncidentEdge(n);
|
||||
assert(InEdgesList(e0));
|
||||
e1 = GetCCWEdge(e0, n);
|
||||
if (IsEndNode(e0, n)) {
|
||||
GetLftSiteData(e0, &i1, &t1);
|
||||
GetRgtSiteData(e0, &i2, &t2);
|
||||
}
|
||||
else {
|
||||
GetLftSiteData(e0, &i2, &t2);
|
||||
GetRgtSiteData(e0, &i1, &t1);
|
||||
}
|
||||
if (IsEndNode(e1, n)) {
|
||||
GetRgtSiteData(e1, &i3, &t3);
|
||||
}
|
||||
else {
|
||||
GetLftSiteData(e1, &i3, &t3);
|
||||
}
|
||||
if ((i1 <= 1) || (i1 >= number)) i1 = NIL;
|
||||
if ((i2 <= 1) || (i2 >= number)) i2 = NIL;
|
||||
if ((i3 <= 1) || (i3 >= number)) i3 = NIL;
|
||||
if ((i1 != NIL) && (i2 != NIL) && (i3 != NIL)) {
|
||||
/* */
|
||||
/* all three points are original input points */
|
||||
/* */
|
||||
assert(t1 == PNT);
|
||||
assert(t2 == PNT);
|
||||
assert(t3 == PNT);
|
||||
fprintf(output, "%d %d %d\n", i1 - 2 , i2 - 2, i3 - 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(output);
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,104 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 1996-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". */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Purpose: This is an interface to Ipe. */
|
||||
/* */
|
||||
/* Acknowledgements: based on fragments written by Ch. Spielberger. */
|
||||
/* */
|
||||
/* E-Mail: held@cs.sbg.ac.at */
|
||||
/* Fax Mail: (+43 662) 8044-172 */
|
||||
/* Voice Mail: (+43 662) 6044-6304 */
|
||||
/* Snail Mail: Martin Held */
|
||||
/* Universitaet Salzburg */
|
||||
/* FB Informatik */
|
||||
/* A-5020 Salzburg, Austria */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
#ifndef IPE7_IO_H
|
||||
#define IPE7_IO_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
|
||||
|
||||
#define XMIN 0.0
|
||||
#define XMAX 452.0
|
||||
#define YMIN 0.0
|
||||
#define YMAX 568.0
|
||||
|
||||
#define LAYER0 "boundary"
|
||||
#define LAYER1 "voronoi"
|
||||
#define LAYER2 "MAT"
|
||||
#define LAYER3 "delaunay"
|
||||
#define LAYER4 "offset"
|
||||
#define LAYER5 "MIC"
|
||||
#define LAYER6 "bd_vertices"
|
||||
#define LAYER7 "vd_nodes"
|
||||
|
||||
#define COLOR0 "seagreen"
|
||||
#define COLOR1 "red"
|
||||
#define COLOR2 "black"
|
||||
#define COLOR3 "blue"
|
||||
#define COLOR4 "lightgray"
|
||||
#define COLOR5 "yellow"
|
||||
#define COLOR6 "black"
|
||||
#define COLOR7 "violet"
|
||||
|
||||
#define PEN0 "ultrafat"
|
||||
#define PEN1 "normal"
|
||||
#define PEN2 "fat"
|
||||
#define PEN3 "normal"
|
||||
#define PEN4 "normal"
|
||||
#define PEN5 "normal"
|
||||
#define PEN6 "normal"
|
||||
#define PEN7 "normal"
|
||||
|
||||
|
||||
FILE *InitIpeFile(char *filename);
|
||||
|
||||
FILE *InitIpe(char *filename, double_arg xl, double_arg xr, double_arg yl, double_arg yr);
|
||||
|
||||
void CloseIpeFile(FILE *ipe_file);
|
||||
|
||||
void WriteBeginPath(FILE *ipe_file, double x1, double y1);
|
||||
|
||||
void WriteBeginGroup(FILE *ipe_file, short int layer);
|
||||
|
||||
void WriteEndGroup(FILE *ipe_file);
|
||||
|
||||
|
||||
void WriteArcCCW(FILE *ipe_file, double_arg xc, double_arg yc, double_arg r,
|
||||
double_arg alpha, double_arg beta);
|
||||
|
||||
void WriteArcCW(FILE *ipe_file, double_arg xc, double_arg yc, double_arg r,
|
||||
double_arg alpha, double_arg beta);
|
||||
|
||||
void WriteMark(FILE *ipe_file, int type, int size, double_arg x, double_arg y);
|
||||
|
||||
void SetIpeDimensions(double_arg xmin, double_arg xmax, double_arg ymin, double_arg ymax);
|
||||
|
||||
void SetWorldDimensions(double_arg xmin, double_arg xmax, double_arg ymin, double_arg ymax);
|
||||
|
||||
void SetScaleFactor(void);
|
||||
|
||||
void InitIpeDimensions(double_arg xmin, double_arg ymin, double_arg xmax, double_arg ymax,
|
||||
double_arg ixmin, double_arg iymin, double_arg ixmax, double_arg iymax);
|
||||
|
||||
double scaleX(double x);
|
||||
double scaleY(double y);
|
||||
|
||||
void WriteLineSegment(FILE *ipe_file,
|
||||
double x1, double y1, double x2, double y2);
|
||||
|
||||
void WriteCircularArc(FILE *ipe_file, double_arg xc, double_arg yc,
|
||||
double_arg x1, double_arg y1, double_arg x2, double_arg y2, vr_bool ccw);
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,231 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 1996-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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <iostream>
|
||||
|
||||
/* */
|
||||
/* get my header files */
|
||||
/* */
|
||||
#include "fpkernel.h"
|
||||
#include "vronivector.h"
|
||||
#include "vroni_object.h"
|
||||
#include "defs.h"
|
||||
|
||||
|
||||
|
||||
void * vroniObject::ReallocateArray(void *old_ptr, int number, size_t size,
|
||||
char const *var_name)
|
||||
{
|
||||
void *new_ptr;
|
||||
|
||||
if (old_ptr != (void*)NULL) {
|
||||
#ifdef DEBUG_MEMORY
|
||||
UpdateMemoryStatus(old_ptr, mem_reallocated, size, number);
|
||||
#endif /* DEBUG_MEMORY */
|
||||
new_ptr = (void*) realloc((void*) old_ptr, number * size);
|
||||
if (new_ptr == (void*)NULL) {
|
||||
fprintf(stderr,
|
||||
"ReallocateArray() - Cannot get %d elements of %d bytes for array `%s'.\n",
|
||||
number, (int) size, var_name);
|
||||
throw std::runtime_error("VRONI error: ReallocateArray() - memory reallocation failed!");
|
||||
}
|
||||
}
|
||||
else {
|
||||
new_ptr = (void*) calloc(number, size);
|
||||
if (new_ptr == (void*)NULL) {
|
||||
fprintf(stderr,
|
||||
"ReallocateArray() - Cannot get %d elements of %d bytes for array `%s'.\n",
|
||||
number, (int) size, var_name);
|
||||
throw std::runtime_error("VRONI error: ReallocateArray() - memory allocation failed!");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MEMORY
|
||||
UpdateMemoryStatus(new_ptr, mem_allocated, size, number);
|
||||
#endif /* DEBUG_MEMORY */
|
||||
|
||||
return new_ptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef DEBUG_MEMORY
|
||||
void vroniObject::UpdateMemoryStatus(void *ptr, memory_status status,
|
||||
size_t size, unsigned int high)
|
||||
{
|
||||
int i;
|
||||
|
||||
switch(status) {
|
||||
case(mem_allocated):
|
||||
if (memory_dbg_cursor < MAX_MEMORY_CURSOR) {
|
||||
memory_history[memory_dbg_cursor].array_ptr = ptr;
|
||||
memory_history[memory_dbg_cursor].size = size;
|
||||
memory_history[memory_dbg_cursor].high = high;
|
||||
++memory_dbg_cursor;
|
||||
curr_memory += size * high;
|
||||
if (curr_memory > max_memory) max_memory = curr_memory;
|
||||
}
|
||||
else {
|
||||
fprintf(stderr,
|
||||
"UpdateMemoryStatus: too many memory allocations\n");
|
||||
}
|
||||
break;
|
||||
case(mem_reallocated):
|
||||
if (ptr != NULL) {
|
||||
i = SearchMemoryHistory(ptr);
|
||||
if (i >= 0) {
|
||||
if (memory_history[i].size != size) {
|
||||
fprintf(stderr,
|
||||
"UpdateMemoryStatus: size of realloc elements ");
|
||||
fprintf(stderr, "does not match orginal size!***\n");
|
||||
}
|
||||
curr_memory -= size * memory_history[i].high;
|
||||
memory_history[i].high = 0;
|
||||
}
|
||||
else {
|
||||
fprintf(stderr,
|
||||
"UpdateMemoryStatus: memory allocation and ");
|
||||
fprintf(stderr, "deallocation is messed up!\n");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case(mem_freed):
|
||||
i = SearchMemoryHistory(ptr);
|
||||
if (i >= 0) {
|
||||
curr_memory -= memory_history[i].size * memory_history[i].high;
|
||||
memory_history[i].high = 0;
|
||||
}
|
||||
else
|
||||
fprintf(stderr,
|
||||
"UpdateMemoryStatus: memory allocation and deallocation is messed up!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int vroniObject::SearchMemoryHistory(void *ptr)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = memory_dbg_cursor - 1;
|
||||
|
||||
while (i >= 0) {
|
||||
if (memory_history[i].array_ptr == ptr) return i;
|
||||
--i;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
#endif /* DEBUG_MEMORY */
|
||||
|
||||
|
||||
|
||||
unsigned long vroniObject::ReportMaxNumberBytes(void)
|
||||
{
|
||||
#ifdef DEBUG_MEMORY
|
||||
return max_memory;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned long vroniObject::ReportCurrNumberBytes(void)
|
||||
{
|
||||
#ifdef DEBUG_MEMORY
|
||||
return curr_memory;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG_MEMORY
|
||||
vr_bool vroniObject::IndexOutOfBounds(void *array_ptr, char const *var_name, size_t size,
|
||||
int index)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = SearchMemoryHistory(array_ptr);
|
||||
if (i >= 0) {
|
||||
if (size != memory_history[i].size) {
|
||||
fprintf(stderr,
|
||||
"IndexOutOfBounds() - Bytes per component of `%s[]' do not match bytes ",
|
||||
var_name);
|
||||
fprintf(stderr, "specified!\n");
|
||||
fprintf(stderr,
|
||||
" Bytes per component: %d bytes; bytes specified: %d\n",
|
||||
memory_history[i].size, size);
|
||||
}
|
||||
return ((index < 0) || (index >= (int) memory_history[i].high));
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "IndexOutOfBounds() - `%s[]' has already been ",
|
||||
var_name);
|
||||
fprintf(stderr, "deallocated!\n");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif /* DEBUG_MEMORY */
|
||||
|
||||
|
||||
|
||||
void vroniObject::FreeMemory(void **ptr, char const *var_name)
|
||||
{
|
||||
if (*ptr == NULL) return;
|
||||
|
||||
#ifdef DEBUG_MEMORY
|
||||
UpdateMemoryStatus(*ptr, mem_freed, 0, 0);
|
||||
#endif /* DEBUG_MEMORY */
|
||||
|
||||
free(*ptr);
|
||||
*ptr = NULL;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
vr_bool vroniObject::AllMemoryFreed()
|
||||
{
|
||||
#ifdef DEBUG_MEMORY
|
||||
int i;
|
||||
|
||||
for (i = 0; i < memory_dbg_cursor; ++i) {
|
||||
if (memory_history[i].high != 0) return false;
|
||||
}
|
||||
#endif /* DEBUG_MEMORY */
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* 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-172 */
|
||||
/* 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 <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 "offset.h"
|
||||
|
||||
#ifdef MIC
|
||||
|
||||
|
||||
|
||||
vr_bool vroniObject::GetMICStatus(void)
|
||||
{
|
||||
return MIC_computed;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void vroniObject::ResetMICStatus(void)
|
||||
{
|
||||
MIC_computed = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* this function computes the maximum inscribed/empty circle (MIC). */
|
||||
/* */
|
||||
/* for closed contours, a one-sided computation of the MIC may be requested */
|
||||
/* by specifying the run-time options "--left_offset" or "--right_offset". */
|
||||
/* note that this function won't compute the MIC if no restriction to a */
|
||||
/* particular side is specified. */
|
||||
/* */
|
||||
void vroniObject::ComputeMIC(vr_bool time, vr_bool left_mic, vr_bool right_mic,
|
||||
coord *center, double *radius)
|
||||
{
|
||||
int e, n;
|
||||
double t1, t2, t;
|
||||
vr_bool unrestricted;
|
||||
coord p;
|
||||
|
||||
assert(GetVDStatus());
|
||||
assert(gt(scale_factor, ZERO));
|
||||
|
||||
if (GetNodesSqdFlag()) TakeSquareOfNodes();
|
||||
if (!GetDeg2Flag()) InsertDegreeTwoNodes();
|
||||
|
||||
#ifdef GRAPHICS
|
||||
if (graphics) {
|
||||
ResetCurBuffer();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (left_mic && right_mic) {
|
||||
left_mic = right_mic = false;
|
||||
}
|
||||
|
||||
/* */
|
||||
/* first call to this function. allocate memory and initialize the */
|
||||
/* flags for the edge data. */
|
||||
/* */
|
||||
VD_Info("...computing maximum inscribed circle -- ");
|
||||
if (time) cpu_time_mic = elapsed();
|
||||
|
||||
unrestricted = !(left_mic || right_mic);
|
||||
if (unrestricted) {
|
||||
if (time) cpu_time_mic = 0.0;
|
||||
VD_Warning("ComputeMIC() - no interior region specified!");
|
||||
MIC_computed = false;
|
||||
return;
|
||||
}
|
||||
|
||||
/* */
|
||||
/* let the user call some application-specific function */
|
||||
/* */
|
||||
ExtApplFuncMICInit;
|
||||
|
||||
/* */
|
||||
/* allocate memory and initialize the flags for the edge data, and find */
|
||||
/* the center of the MIC on the fly. */
|
||||
/* */
|
||||
InitializeEdgeData(unrestricted, left_mic, true, &e);
|
||||
|
||||
/* */
|
||||
/* the center of the MIC coincides with one node, n, of the VD edge e. */
|
||||
/* */
|
||||
if (e != NIL) {
|
||||
GetEdgeParam(e, &t1, &t2);
|
||||
if (t1 >= t2) {
|
||||
t = t1;
|
||||
n = GetStartNode(e);
|
||||
}
|
||||
else {
|
||||
t = t2;
|
||||
n = GetEndNode(e);
|
||||
}
|
||||
p = GetNodeCoord(n);
|
||||
|
||||
if (time) cpu_time_mic = elapsed();
|
||||
VD_Info("done!\n");
|
||||
MIC_computed = true;
|
||||
|
||||
#ifdef GRAPHICS
|
||||
if (graphics) {
|
||||
AddCirToBuffer(p, t);
|
||||
AddToCurBuffer(n, VDN, MICColor);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* */
|
||||
/* the MIC has radius t and coordinates (p.x, p.y). note that VRONI */
|
||||
/* transforms the input data. thus, the MIC data has to be transformed */
|
||||
/* back to the original ccordinate system as follows: */
|
||||
/* */
|
||||
center->x = UnscaleX(p.x);
|
||||
center->y = UnscaleY(p.y);
|
||||
*radius = UnscaleV(t);
|
||||
/*
|
||||
printf("center: %20.16f %20.16f\n", center->x, center->y);
|
||||
printf("radius: %20.16f\n", *radius);
|
||||
printf("1\n%20.16f %20.16f %20.16f %20.16f %20.16f %20.16f\n",
|
||||
center->x - *radius, center->y, center->x + *radius, center->y, center->x, center->y);
|
||||
printf("1\n%20.16f %20.16f %20.16f %20.16f %20.16f %20.16f\n",
|
||||
center->x + *radius, center->y, center->x - *radius, center->y, center->x, center->y);
|
||||
*/
|
||||
|
||||
|
||||
/* */
|
||||
/* let the user call some application-specific function */
|
||||
/* */
|
||||
ExtApplFuncMICDone;
|
||||
}
|
||||
else {
|
||||
/* */
|
||||
/* no valid MIC could be found. since every clearance disk of a VD */
|
||||
/* node is a valid candidate for the MIC >>if<< the node lies on the */
|
||||
/* appropriate side of the input sites, as requested by the user, this */
|
||||
/* can only happen if the input sites do not form closed contours! */
|
||||
/* (i.e., if no VD node lies on the appropriate side!) */
|
||||
/* */
|
||||
if (time) cpu_time_mic = elapsed();
|
||||
MIC_computed = false;
|
||||
|
||||
VD_Info("done!\n");
|
||||
VD_Warning("ComputeMIC() - MIC not found!");
|
||||
|
||||
/* */
|
||||
/* let the user call some application-specific function */
|
||||
/* */
|
||||
ExtApplFuncMICNotFound;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef GRAPHICS
|
||||
void AddMICToBuffer(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#include "ext_appl_mic.cc"
|
||||
|
||||
#endif
|
||||
+1037
File diff suppressed because it is too large
Load Diff
+208
@@ -0,0 +1,208 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 1999-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 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef VRONI_NUMERICS_H
|
||||
#define VRONI_NUMERICS_H
|
||||
|
||||
|
||||
#define Det2D(u, v, w) \
|
||||
(((u).x - (v).x) * ((v).y - (w).y) + ((v).y - (u).y) * ((v).x - (w).x))
|
||||
|
||||
|
||||
/* */
|
||||
/* this macro solves the equation p + s * q = u + t * v */
|
||||
/* for the parameter s, with p and u being points and q and v */
|
||||
/* being direction vectors of the lines through p and u. */
|
||||
/* if the equation cannot be solved (since the two lines are parallel) then */
|
||||
/* exists = 0; if the solution is not unique then exists = 2; and */
|
||||
/* exists = 1, otherwise. also, w := p + xy[0] * q. */
|
||||
/* */
|
||||
/* A[2][2], B[2], xy[2], I0, I1, J0, J1 are used internally within this */
|
||||
/* macro. */
|
||||
/* */
|
||||
#define LineLineIntersection(A, B, xy, I0, J0, I1, J1, p, q, u, v, w, exists) \
|
||||
{\
|
||||
A[0][0] = (q).x; \
|
||||
A[1][0] = (q).y; \
|
||||
A[0][1] = - (v).x; \
|
||||
A[1][1] = - (v).y; \
|
||||
B[0] = (u).x - (p).x; \
|
||||
B[1] = (u).y - (p).y; \
|
||||
LinearEqnSolver_2x2(A, B, xy, exists, I0, J0, I1, J1); \
|
||||
if (exists == 1) { \
|
||||
(w).x = (p).x + xy[0] * (q).x; \
|
||||
(w).y = (p).y + xy[0] * (q).y; \
|
||||
}\
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* P ... query point */
|
||||
/* U ... start point of segment */
|
||||
/* A, B, C ... normalized line coefficients, where (B,-A) is the unit */
|
||||
/* direction vector of the line segment */
|
||||
/* L ... length of the line segment */
|
||||
/* */
|
||||
#define IsInSegConeStrict(U, P, A, B, L) \
|
||||
(numerics_h_local = ((P).x - (U).x) * (B) - ((P).y - (U).y) * (A), \
|
||||
((numerics_h_local < (L)) ? ((numerics_h_local <= 0.0) ? -1 : 0) : 1))
|
||||
|
||||
|
||||
#define IsInSegCone(U, P, A, B, L) \
|
||||
(numerics_h_local = ((P).x - (U).x) * (B) - ((P).y - (U).y) * (A), \
|
||||
((numerics_h_local <= ((L) + ZERO)) ? ((numerics_h_local < -ZERO) ? -1 : 0) : 1))
|
||||
|
||||
|
||||
#define IsInSegConeZero(U, P, A, B, L, eps) \
|
||||
(numerics_h_local = ((P).x - (U).x) * (B) - ((P).y - (U).y) * (A), \
|
||||
((numerics_h_local <= ((L) + (eps))) ? ((numerics_h_local < -(eps)) ? -1 : 0) : 1))
|
||||
|
||||
|
||||
#define PntSegDist(U, P, A, B, C, L, eps) \
|
||||
((IsInSegConeZero(U, P, A, B, L, eps) == 0) ? \
|
||||
(PntLineDist(A, B, C, P)) : LARGE)
|
||||
|
||||
|
||||
#define AbsPntSegDist(U, P, A, B, C, L, eps) \
|
||||
((IsInSegConeZero(U, P, A, B, L, eps) == 0) ? \
|
||||
(AbsPntLineDist(A, B, C, P)) : LARGE)
|
||||
|
||||
|
||||
#define xParabola(A, a, b, sign, dist, t, k1, k2, r, x) \
|
||||
{ \
|
||||
numerics_h_det = r * r + 2.0 * t * (r * k1 - dist * k2) - dist * dist; \
|
||||
if (numerics_h_det <= 0.0) { \
|
||||
(x) = A - a * t * k2; \
|
||||
} \
|
||||
else { \
|
||||
(x) = A - a * t * k2 + sign * b * sqrt(numerics_h_det); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define yParabola(B, a, b, sign, dist, t, k1, k2, r, y) \
|
||||
{ \
|
||||
numerics_h_det = r * r + 2.0 * t * (r * k1 - dist * k2) - dist * dist; \
|
||||
if (numerics_h_det <= 0.0) { \
|
||||
(y) = B - b * t * k2; \
|
||||
} \
|
||||
else { \
|
||||
(y) = B - b * t * k2 - sign * a * sqrt(numerics_h_det); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define xHyperEll(A, C, sign, dist, dy, t, k1, k2, r1, r2, r1t, r2t, ht, x) \
|
||||
{ \
|
||||
r1t = r1 + k1 * t; \
|
||||
r2t = r2 + k2 * t; \
|
||||
ht = (r2t * r2t - r1t * r1t - dist * dist) / (2.0 * dist); \
|
||||
numerics_h_det = r1t * r1t - ht * ht; \
|
||||
if (numerics_h_det <= 0.0) { \
|
||||
(x) = A - C * t; \
|
||||
} \
|
||||
else { \
|
||||
(x) = A - C * t + sign * dy * sqrt(numerics_h_det); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
#define yHyperEll(B, D, sign, dist, dx, t, k1, k2, r1, r2, r1t, r2t, ht, y) \
|
||||
{ \
|
||||
r1t = r1 + k1 * t; \
|
||||
r2t = r2 + k2 * t; \
|
||||
ht = (r2t * r2t - r1t * r1t - dist * dist) / (2.0 * dist); \
|
||||
numerics_h_det = r1t * r1t - ht * ht; \
|
||||
if (numerics_h_det <= 0.0) { \
|
||||
(y) = B - D * t; \
|
||||
} \
|
||||
else { \
|
||||
(y) = B - D * t - sign * dx * sqrt(numerics_h_det); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* A, B, C ... normalized coefficients of the equation of the arc's chord */
|
||||
/* such that the arc's center is to the left of the chord */
|
||||
/* P ... query point */
|
||||
/* */
|
||||
/* note: we assume that the arc is oriented CCW, and that a point-on-circle */
|
||||
/* test has been performed! */
|
||||
/* */
|
||||
#define IsOnArc(A, B, C, P) \
|
||||
(PntLineDist(A, B, C, P) <= ZERO)
|
||||
|
||||
|
||||
#define IsOnArcStrict(A, B, C, P) \
|
||||
(PntLineDist(A, B, C, P) < 0.0)
|
||||
|
||||
|
||||
#define IsOnArcZero(A, B, C, P, eps) \
|
||||
(PntLineDist(A, B, C, P) <= (eps))
|
||||
|
||||
|
||||
/* */
|
||||
/* VS ... unit outwards normal vector of arc at start point */
|
||||
/* VE ... unit outwards normal vector of arc at end point */
|
||||
/* CP ... vector from arc's center to query point */
|
||||
/* */
|
||||
/* note: (1) we assume that the arc is oriented CCW, and */
|
||||
/* that it spans less than 180 degrees! */
|
||||
/* (2) if a point is inside a circle then its distance to the circle */
|
||||
/* is negative. */
|
||||
/* */
|
||||
#define IsInArcCone(VS, VE, CP) \
|
||||
((((VS).x * (CP).y - (VS).y * (CP).x) >= -ZERO) ? \
|
||||
((((VE).y * (CP).x - (VE).x * (CP).y) >= -ZERO) ? 0 : -1) : 1)
|
||||
|
||||
|
||||
#define IsInArcConeZero(VS, VE, CP, eps) \
|
||||
((((VS).x * (CP).y - (VS).y * (CP).x) >= -(eps)) ? \
|
||||
((((VE).y * (CP).x - (VE).x * (CP).y) >= -(eps)) ? 0 : -1) : 1)
|
||||
|
||||
|
||||
#define IsInArcConeStrict(VS, VE, CP) \
|
||||
((((VS).x * (CP).y - (VS).y * (CP).x) > 0.0) ? \
|
||||
((((VE).y * (CP).x - (VE).x * (CP).y) > 0.0) ? 0 : -1) : 1)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define PntArcDist(VS, VE, CP, R, eps) \
|
||||
((((VS).x * (CP).y - (VS).y * (CP).x) >= -(eps)) ? \
|
||||
((((VE).y * (CP).x - (VE).x * (CP).y) >= -(eps)) ? (VecLen(CP) - R) \
|
||||
: LARGE) : LARGE)
|
||||
|
||||
|
||||
#define AbsPntArcDist(VS, VE, CP, R, Z) \
|
||||
((((VS).x * (CP).y - (VS).y * (CP).x) >= -(Z)) ? \
|
||||
((((VE).y * (CP).x - (VE).x * (CP).y) >= -(Z)) ? \
|
||||
(numerics_h_local = VecLen(CP) - R, \
|
||||
((numerics_h_local < 0.0) ? -numerics_h_local : numerics_h_local)) : \
|
||||
LARGE) : LARGE)
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 1999-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". */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef VRONI_OFFSET_H
|
||||
#define VRONI_OFFSET_H
|
||||
|
||||
|
||||
/* */
|
||||
/* the offset curves are stored as closed loops in the array offset_list[]. */
|
||||
/* the individual offset segments are stored in the array offset_data[]. */
|
||||
/* the i-th offset curve contains the offset segments whose indices range */
|
||||
/* from offset_list[i].start to offset_list[i].end. the actual offset */
|
||||
/* distance of the i-th offset curve is stored in offset_list[i].offset. */
|
||||
/* there is a total of num_offset_list many offset curves. */
|
||||
/* */
|
||||
struct off_list {
|
||||
int start; /* index of first segment of this offset curve . */
|
||||
int end; /* index of last segment of this offset curve. */
|
||||
double offset; /* boundary clearance for this offset curve. */
|
||||
//Ensure construction doesn't implicitly initialize elements - done explicitly later anyway
|
||||
inline off_list() {}
|
||||
}; /* data for one offset curve. */
|
||||
|
||||
struct off_data {
|
||||
int site; /* index of corresponding site (contour segment). */
|
||||
t_site type; /* type of corresponding contour segment: PNT, LINE, */
|
||||
/* or CCW, CW. */
|
||||
coord p; /* coordinates of start point of offset segment */
|
||||
#ifdef EXT_APPL_OFF
|
||||
eao_type ext_appl;
|
||||
#endif
|
||||
//Ensure construction doesn't implicitly initialize elements - done explicitly later anyway
|
||||
inline off_data() {}
|
||||
}; /* data for one offset segment */
|
||||
|
||||
off_list* GetOffsetList(int i);
|
||||
off_data* GetOffsetData(int i);
|
||||
|
||||
#define SetEdgeFlagNew(I, F) \
|
||||
{\
|
||||
assert(InEdgeFlagList(I)); \
|
||||
edge_flags[I].e_new = F;\
|
||||
}
|
||||
|
||||
|
||||
#define SetEdgeFlagDeg(I, F) \
|
||||
{\
|
||||
assert(InEdgeFlagList(I)); \
|
||||
edge_flags[I].deg = F;\
|
||||
}
|
||||
|
||||
|
||||
#define SetEdgeDataInit(I, F) \
|
||||
{\
|
||||
assert(InEdgeDataList(I)); \
|
||||
edge_data[I].init = F;\
|
||||
}
|
||||
|
||||
|
||||
#define GetEdgeFlagNew(I) (assert(InEdgeFlagList(I)), edge_flags[I].e_new)
|
||||
|
||||
|
||||
#define GetEdgeFlagDeg(I) (assert(InEdgeFlagList(I)), edge_flags[I].deg)
|
||||
|
||||
|
||||
#define GetEdgeDataInit(I) (assert(InEdgeDataList(I)), edge_data[I].init)
|
||||
|
||||
|
||||
#define AdvanceActiveEdge(I, J, delete) \
|
||||
{\
|
||||
if (delete) { \
|
||||
assert(InActiveEdgeList(J)); \
|
||||
--num_active_edges; \
|
||||
if ((num_active_edges >= 0) && (J < num_active_edges)) { \
|
||||
I = active_edges[J] = active_edges[num_active_edges]; \
|
||||
} \
|
||||
else { \
|
||||
I = NIL; \
|
||||
} \
|
||||
} \
|
||||
else { \
|
||||
++J; \
|
||||
if (J < num_active_edges) { \
|
||||
I = active_edges[J]; \
|
||||
} \
|
||||
else { \
|
||||
I = NIL; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
+229
@@ -0,0 +1,229 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 1999-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 <stdlib.h>
|
||||
#include <stdio.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 "roots.h"
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* computes the center cntr and the radius (squared) r2 of the circle */
|
||||
/* passing through the points pnts[i],pnts[j],pnts[k]. it returns false */
|
||||
/* if the radius is too large to be computed numerically. */
|
||||
/* */
|
||||
vr_bool vroniObject::PntPntPntCntr(int i, int j, int k,
|
||||
coord *cntr, double *r2)
|
||||
{
|
||||
double alpha, beta, gamma, delta, t;
|
||||
coord AB, BC, CA, P, Q, U, V, A, B, C;
|
||||
double aaa[2][2], bbb[2], xy[2];
|
||||
int I0, I1, J0, J1, exists, m;
|
||||
double ab, bc, ca;
|
||||
|
||||
assert(InPntsList(i));
|
||||
assert(InPntsList(j));
|
||||
assert(InPntsList(k));
|
||||
|
||||
/* */
|
||||
/* we sort the three indices in order to guarantee that the center of */
|
||||
/* three points is always computed consistently. */
|
||||
/* */
|
||||
SortThreeNumbers(i, j, k, m);
|
||||
|
||||
/* */
|
||||
/* check whether two points are identical. */
|
||||
/* */
|
||||
if ((i == j) || (j == k)) {
|
||||
VD_Dbg_Warning("PntPntPntCntr() - two identical points!");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* */
|
||||
/* check whether two points are nearly identical. */
|
||||
/* */
|
||||
A = GetPntCoords(i);
|
||||
B = GetPntCoords(j);
|
||||
C = GetPntCoords(k);
|
||||
|
||||
AB = VecSub(B, A);
|
||||
ab = VecLen(AB);
|
||||
assert(ab >= 0.0);
|
||||
if (le(ab, ZERO)) {
|
||||
VD_Dbg_Warning("PntPntPntCntr() - two points too close");
|
||||
SetInvalidSites(i, PNT, j, PNT, ZERO);
|
||||
return false;
|
||||
}
|
||||
BC = VecSub(C, B);
|
||||
bc = VecLen(BC);
|
||||
assert(bc >= 0.0);
|
||||
if (le(bc, ZERO)) {
|
||||
VD_Dbg_Warning("PntPntPntCntr() - two points too close");
|
||||
SetInvalidSites(j, PNT, k, PNT, ZERO);
|
||||
return false;
|
||||
}
|
||||
CA = VecSub(A, C);
|
||||
ca = VecLen(CA);
|
||||
assert(ca >= 0.0);
|
||||
if (le(ca, ZERO)) {
|
||||
VD_Dbg_Warning("PntPntPntCntr() - two points too close");
|
||||
SetInvalidSites(i, PNT, k, PNT, ZERO);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* */
|
||||
/* normalize the vectors */
|
||||
/* */
|
||||
AB = VecDiv(ab, AB);
|
||||
BC = VecDiv(bc, BC);
|
||||
CA = VecDiv(ca, CA);
|
||||
|
||||
/* */
|
||||
/* find those two vectors that are the least parallel. */
|
||||
/* */
|
||||
alpha = VecDotProd(AB, BC);
|
||||
alpha = Abs(alpha);
|
||||
beta = VecDotProd(BC, CA);
|
||||
beta = Abs(beta);
|
||||
gamma = VecDotProd(CA, AB);
|
||||
gamma = Abs(gamma);
|
||||
delta = Min3(alpha, beta, gamma);
|
||||
|
||||
/* */
|
||||
/* assume that the angle between AB and AC is closest to a right */
|
||||
/* angle. if ab > ca then we construct the line perpendicular to AB */
|
||||
/* through the midpoint of A,B and intersect it with the corresponding */
|
||||
/* line w.r.t. A,C. the point of intersection will be expressed in */
|
||||
/* terms of the line perpendicular to AB. similar for the other cases. */
|
||||
/* */
|
||||
if (delta == gamma) {
|
||||
P = MidPoint(A, B);
|
||||
Q = VecCCW(AB);
|
||||
U = MidPoint(A, C);
|
||||
V = VecCCW(CA);
|
||||
if (ab < ca) {
|
||||
LineLineIntersection(aaa, bbb, xy, I0, J0, I1, J1, P, Q, U, V, *cntr,
|
||||
exists);
|
||||
}
|
||||
else {
|
||||
LineLineIntersection(aaa, bbb, xy, I0, J0, I1, J1, U, V, P, Q, *cntr,
|
||||
exists);
|
||||
}
|
||||
}
|
||||
else if (delta == alpha) {
|
||||
P = MidPoint(A, B);
|
||||
Q = VecCCW(AB);
|
||||
U = MidPoint(B, C);
|
||||
V = VecCCW(BC);
|
||||
if (ab < bc) {
|
||||
LineLineIntersection(aaa, bbb, xy, I0, J0, I1, J1, P, Q, U, V, *cntr,
|
||||
exists);
|
||||
}
|
||||
else {
|
||||
LineLineIntersection(aaa, bbb, xy, I0, J0, I1, J1, U, V, P, Q, *cntr,
|
||||
exists);
|
||||
}
|
||||
}
|
||||
else {
|
||||
P = MidPoint(C, A);
|
||||
Q = VecCCW(CA);
|
||||
U = MidPoint(B, C);
|
||||
V = VecCCW(BC);
|
||||
if (ca < bc) {
|
||||
LineLineIntersection(aaa, bbb, xy, I0, J0, I1, J1, P, Q, U, V, *cntr,
|
||||
exists);
|
||||
}
|
||||
else {
|
||||
LineLineIntersection(aaa, bbb, xy, I0, J0, I1, J1, U, V, P, Q, *cntr,
|
||||
exists);
|
||||
}
|
||||
}
|
||||
|
||||
if (exists == 1) {
|
||||
*r2 = PntPntDistSq(A, *cntr);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
/* */
|
||||
/* we'll try to find a center using an alternative approach: we find */
|
||||
/* a parameter t such that cntr = P + t * Q. thus, we require */
|
||||
/* d(A, cntr) = d(C, cntr). */
|
||||
/* */
|
||||
P = MidPoint(A, B);
|
||||
Q = VecCCW(AB); /* note: Q is a unit vector! */
|
||||
V = VecSub(P, C);
|
||||
delta = VecDotProd(Q, V) * 2.0;
|
||||
|
||||
if (ne(delta, TINY)) {
|
||||
ab = ab * ab / 4.0;
|
||||
t = (ab - VecLenSq(V)) / delta;
|
||||
*cntr = RayPnt(P, Q, t);
|
||||
*r2 = ab + t * t;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
/* */
|
||||
/* We could not find a center. Let's check whether two points are */
|
||||
/* very close. */
|
||||
/* */
|
||||
if (le(ab, ZERO_MAX)) {
|
||||
VD_Dbg_Warning("PntPntPntCntr() - two points too close");
|
||||
SetInvalidSites(i, PNT, j, PNT, ZERO_MAX);
|
||||
return false;
|
||||
}
|
||||
if (le(bc, ZERO_MAX)) {
|
||||
VD_Dbg_Warning("PntPntPntCntr() - two points too close");
|
||||
SetInvalidSites(j, PNT, k, PNT, ZERO_MAX);
|
||||
return false;
|
||||
}
|
||||
if (le(ca, ZERO_MAX)) {
|
||||
VD_Dbg_Warning("PntPntPntCntr() - two points too close");
|
||||
SetInvalidSites(i, PNT, k, PNT, ZERO_MAX);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VD_Warning("PntPntPntCntr() - cannot find center!");
|
||||
#ifdef VRONI_DBG_WARN
|
||||
printf("A = (%20.16f, %20.16f)\n", A.x, A.y);
|
||||
printf("B = (%20.16f, %20.16f)\n", B.x, B.y);
|
||||
printf("C = (%20.16f, %20.16f)\n", C.x, C.y);
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,834 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* 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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 1999-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 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef VRONI_RANDOM_H
|
||||
#define VRONI_RANDOM_H
|
||||
|
||||
|
||||
#ifndef RAND
|
||||
|
||||
#define RND_MAX 2147483647
|
||||
|
||||
#define UniformRandom(x) \
|
||||
{\
|
||||
x = ((double) random()) / RND_MAX; }
|
||||
|
||||
#define RandomInteger(N) \
|
||||
(\
|
||||
assert(N > 0), \
|
||||
random() % N)
|
||||
|
||||
#define InitRandom(seed) \
|
||||
{\
|
||||
srandom(seed); }
|
||||
|
||||
#else
|
||||
|
||||
#ifdef RAND_MAX
|
||||
#define RND_MAX RAND_MAX
|
||||
#else
|
||||
#define RND_MAX 32767
|
||||
#endif
|
||||
|
||||
#define UniformRandom(x) \
|
||||
{\
|
||||
x = ((double) rand()) / RND_MAX; \
|
||||
}
|
||||
|
||||
#define RandomInteger(N) \
|
||||
(\
|
||||
assert(N > 0), \
|
||||
rand() % N)
|
||||
|
||||
#define InitRandom(seed) \
|
||||
{\
|
||||
srand(seed); }
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,676 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 1999-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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
/* */
|
||||
/* get my header files */
|
||||
/* */
|
||||
#include "fpkernel.h"
|
||||
#include "vronivector.h"
|
||||
#include "vroni_object.h"
|
||||
#include "defs.h"
|
||||
#include "numerics.h"
|
||||
#include "ipe_io.h"
|
||||
|
||||
|
||||
#ifdef GRAPHICS
|
||||
|
||||
|
||||
|
||||
#define MINI 32
|
||||
#define BLOCK_SIZE 1024
|
||||
#define PAGE_SIZE 65536
|
||||
|
||||
|
||||
|
||||
void vroniObject::ResetBufferData(void)
|
||||
{
|
||||
num_pnt_buf = 0;
|
||||
num_seg_buf = 0;
|
||||
num_arc_buf = 0;
|
||||
num_vde_buf = 0;
|
||||
num_vdn_buf = 0;
|
||||
num_off_buf = 0;
|
||||
num_cur_buf = 0;
|
||||
num_cir_buf = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void vroniObject::ResetOffsetBuffer(void)
|
||||
{
|
||||
num_off_buf = 0;
|
||||
num_cur_buf = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void vroniObject::ResetCurBuffer(void)
|
||||
{
|
||||
num_cur_buf = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void vroniObject::ResetVDBuffer(void)
|
||||
{
|
||||
num_vde_buf = 0;
|
||||
num_vdn_buf = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void vroniObject::AddNodeToBuffer(int index, int color)
|
||||
{
|
||||
if (num_vdn_buf >= max_num_vdn_buf) {
|
||||
max_num_vdn_buf += BLOCK_SIZE;
|
||||
vdn_buf = (buffer*) ReallocateArray(vdn_buf, max_num_vdn_buf,
|
||||
sizeof(buffer), "redraw:vdn_buf");
|
||||
}
|
||||
vdn_buf[num_vdn_buf].index = index;
|
||||
vdn_buf[num_vdn_buf].color = color;
|
||||
++num_vdn_buf;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void vroniObject::AddPntToBuffer(int index, int color)
|
||||
{
|
||||
if (num_pnt_buf >= max_num_pnt_buf) {
|
||||
max_num_pnt_buf += BLOCK_SIZE;
|
||||
pnt_buf = (buffer*) ReallocateArray(pnt_buf, max_num_pnt_buf,
|
||||
sizeof(buffer), "redraw:pnt_buf");
|
||||
}
|
||||
pnt_buf[num_pnt_buf].index = index;
|
||||
pnt_buf[num_pnt_buf].color = color;
|
||||
++num_pnt_buf;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void vroniObject::AddSegToBuffer(int index, int color)
|
||||
{
|
||||
if (num_seg_buf >= max_num_seg_buf) {
|
||||
max_num_seg_buf += BLOCK_SIZE;
|
||||
seg_buf = (buffer*) ReallocateArray(seg_buf, max_num_seg_buf,
|
||||
sizeof(buffer), "redraw:seg_buf");
|
||||
}
|
||||
seg_buf[num_seg_buf].index = index;
|
||||
seg_buf[num_seg_buf].color = color;
|
||||
++num_seg_buf;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void vroniObject::AddArcToBuffer(int index, int color)
|
||||
{
|
||||
if (num_arc_buf >= max_num_arc_buf) {
|
||||
max_num_arc_buf += BLOCK_SIZE;
|
||||
arc_buf = (buffer*) ReallocateArray(arc_buf, max_num_arc_buf,
|
||||
sizeof(buffer), "redraw:arc_buf");
|
||||
}
|
||||
arc_buf[num_arc_buf].index = index;
|
||||
arc_buf[num_arc_buf].color = color;
|
||||
++num_arc_buf;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void vroniObject::AddEdgeToBuffer(double_arg x1, double_arg y1,
|
||||
double_arg x2, double_arg y2, int color)
|
||||
{
|
||||
if (num_vde_buf >= max_num_vde_buf) {
|
||||
max_num_vde_buf += PAGE_SIZE;
|
||||
gentlyResizeSTLVector(vde_buf, max_num_vde_buf, "redraw:vde_buf");
|
||||
}
|
||||
vde_buf[num_vde_buf].p1.x = x1;
|
||||
vde_buf[num_vde_buf].p1.y = y1;
|
||||
vde_buf[num_vde_buf].p2.x = x2;
|
||||
vde_buf[num_vde_buf].p2.y = y2;
|
||||
vde_buf[num_vde_buf].color = color;
|
||||
++num_vde_buf;
|
||||
|
||||
/*
|
||||
if (color == WMATColor) {
|
||||
printf("0\n%20.16f %20.16f %20.16f %20.16f\n", x1, y1, x2, y2);
|
||||
}
|
||||
*/
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void vroniObject::AddOffToBuffer(double_arg x1, double_arg y1,
|
||||
double_arg x2, double_arg y2,
|
||||
double_arg x3, double_arg y3,
|
||||
double_arg r, vr_bool ccw, int color)
|
||||
{
|
||||
if (num_off_buf >= max_num_off_buf) {
|
||||
max_num_off_buf += PAGE_SIZE;
|
||||
gentlyResizeSTLVector(off_buf, max_num_off_buf, "redraw:off_buf");
|
||||
}
|
||||
off_buf[num_off_buf].p1.x = x1;
|
||||
off_buf[num_off_buf].p1.y = y1;
|
||||
off_buf[num_off_buf].p2.x = x2;
|
||||
off_buf[num_off_buf].p2.y = y2;
|
||||
off_buf[num_off_buf].p3.x = x3;
|
||||
off_buf[num_off_buf].p3.y = y3;
|
||||
off_buf[num_off_buf].r = r;
|
||||
off_buf[num_off_buf].ccw = ccw;
|
||||
off_buf[num_off_buf].color = color;
|
||||
++num_off_buf;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void vroniObject::AddCirToBuffer(coord cntr, double_arg radius)
|
||||
{
|
||||
if (num_cir_buf >= max_num_cir_buf) {
|
||||
max_num_cir_buf += PAGE_SIZE;
|
||||
gentlyResizeSTLVector(cir_buf, max_num_cir_buf, "redraw:cir_buf");
|
||||
}
|
||||
cir_buf[num_cir_buf].cntr = cntr;
|
||||
cir_buf[num_cir_buf].radius = radius;
|
||||
++num_cir_buf;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void vroniObject::FreeDrawingBuffer(void)
|
||||
{
|
||||
FreeMemory((void**) &arc_buf, "redraw:arc_buf");
|
||||
FreeMemory((void**) &seg_buf, "redraw:seg_buf");
|
||||
FreeMemory((void**) &pnt_buf, "redraw:pnt_buf");
|
||||
vde_buf.clear();
|
||||
off_buf.clear();
|
||||
cir_buf.clear();
|
||||
FreeMemory((void**) &vdn_buf, "redraw:vdn_buf");
|
||||
FreeMemory((void**) &cur_buf, "redraw:cur_buf");
|
||||
|
||||
num_cir_buf = 0;
|
||||
num_cur_buf = 0;
|
||||
num_vde_buf = 0;
|
||||
num_off_buf = 0;
|
||||
num_vdn_buf = 0;
|
||||
num_pnt_buf = 0;
|
||||
num_seg_buf = 0;
|
||||
num_arc_buf = 0;
|
||||
max_num_cir_buf = 0;
|
||||
max_num_cur_buf = 0;
|
||||
max_num_vde_buf = 0;
|
||||
max_num_off_buf = 0;
|
||||
max_num_vdn_buf = 0;
|
||||
max_num_pnt_buf = 0;
|
||||
max_num_seg_buf = 0;
|
||||
max_num_arc_buf = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void vroniObject::UpdateBuffer(void)
|
||||
{
|
||||
int i, number;
|
||||
|
||||
ResetBufferData();
|
||||
|
||||
for (i = 0; i < num_pnts; ++i) {
|
||||
AddPntToBuffer(i, PntColor);
|
||||
}
|
||||
|
||||
for (i = 0; i < num_segs; ++i)
|
||||
AddSegToBuffer(i, SegColor);
|
||||
|
||||
number = num_arcs;
|
||||
|
||||
for (i = 0; i < number; ++i)
|
||||
AddArcToBuffer(i, SegColor);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void vroniObject::AddToCurBuffer(int index, t_site type, int color)
|
||||
{
|
||||
if (num_cur_buf >= max_num_cur_buf) {
|
||||
max_num_cur_buf += BLOCK_SIZE;
|
||||
cur_buf = (cur_buffer*) ReallocateArray(cur_buf, max_num_cur_buf,
|
||||
sizeof(cur_buffer),
|
||||
"redraw:cur_buf");
|
||||
}
|
||||
cur_buf[num_cur_buf].index = index;
|
||||
cur_buf[num_cur_buf].type = type;
|
||||
cur_buf[num_cur_buf].color = color;
|
||||
++num_cur_buf;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* */
|
||||
/* this function writes the input data and the VD to a file in the */
|
||||
/* Ipe 7 Xml Format. */
|
||||
/* */
|
||||
void vroniObject::WriteIpeOutput(char *filename)
|
||||
{
|
||||
int i;
|
||||
coord p1, p2, p3;
|
||||
FILE *fp;
|
||||
fp = InitIpe(filename, bb_min.x, bb_max.x, bb_min.y, bb_max.y);
|
||||
|
||||
if (draw_segs || draw_arcs) WriteBeginGroup(fp, 0);
|
||||
if (draw_arcs) {
|
||||
for (i = 0; i < num_arc_buf; ++i) {
|
||||
if (!incremental || arcs[arc_buf[i].index].draw) {
|
||||
p3 = GetArcCenter(arc_buf[i].index);
|
||||
p1 = GetArcStartCoord(arc_buf[i].index);
|
||||
p2 = GetArcEndCoord(arc_buf[i].index);
|
||||
WriteCircularArc(fp, p3.x, p3.y, p1.x, p1.y, p2.x, p2.y, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (draw_segs) {
|
||||
for (i = 0; i < num_seg_buf; ++i) {
|
||||
if (!incremental || segs[seg_buf[i].index].draw) {
|
||||
p1 = GetSegStartCoord(seg_buf[i].index);
|
||||
p2 = GetSegEndCoord(seg_buf[i].index);
|
||||
WriteLineSegment(fp, p1.x, p1.y, p2.x, p2.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (draw_segs || draw_arcs) WriteEndGroup(fp);
|
||||
|
||||
if (draw_vde) {
|
||||
WriteBeginGroup(fp, 1);
|
||||
for (i = 0; i < num_vde_buf; ++i) {
|
||||
if (vde_buf[i].color == VDColor)
|
||||
WriteLineSegment(fp,
|
||||
vde_buf[i].p1.x, vde_buf[i].p1.y,
|
||||
vde_buf[i].p2.x, vde_buf[i].p2.y);
|
||||
}
|
||||
WriteEndGroup(fp);
|
||||
}
|
||||
|
||||
if (draw_dte) {
|
||||
WriteBeginGroup(fp, 3);
|
||||
for (i = 0; i < num_vde_buf; ++i) {
|
||||
if (vde_buf[i].color == DTColor)
|
||||
WriteLineSegment(fp,
|
||||
vde_buf[i].p1.x, vde_buf[i].p1.y,
|
||||
vde_buf[i].p2.x, vde_buf[i].p2.y);
|
||||
}
|
||||
WriteEndGroup(fp);
|
||||
}
|
||||
|
||||
if (draw_off) {
|
||||
WriteBeginGroup(fp, 4);
|
||||
for (i = 0; i < num_off_buf; ++i) {
|
||||
if (off_buf[i].r == 0) {
|
||||
WriteLineSegment(fp,
|
||||
off_buf[i].p1.x, off_buf[i].p1.y,
|
||||
off_buf[i].p2.x, off_buf[i].p2.y);
|
||||
}
|
||||
else {
|
||||
WriteCircularArc(fp,
|
||||
off_buf[i].p3.x, off_buf[i].p3.y,
|
||||
off_buf[i].p1.x, off_buf[i].p1.y,
|
||||
off_buf[i].p2.x, off_buf[i].p2.y,
|
||||
!off_buf[i].ccw);
|
||||
}
|
||||
}
|
||||
WriteEndGroup(fp);
|
||||
}
|
||||
|
||||
if (draw_mat) {
|
||||
WriteBeginGroup(fp, 2);
|
||||
for (i = 0; i < num_vde_buf; ++i) {
|
||||
if (vde_buf[i].color == WMATColor)
|
||||
WriteLineSegment(fp,
|
||||
vde_buf[i].p1.x, vde_buf[i].p1.y,
|
||||
vde_buf[i].p2.x, vde_buf[i].p2.y);
|
||||
}
|
||||
WriteEndGroup(fp);
|
||||
}
|
||||
|
||||
if (draw_mic) {
|
||||
if (num_cir_buf == 1) {
|
||||
WriteBeginGroup(fp, 5);
|
||||
WriteCircularArc(fp,
|
||||
cir_buf[0].cntr.x,
|
||||
cir_buf[0].cntr.y,
|
||||
cir_buf[0].cntr.x,
|
||||
cir_buf[0].cntr.y - cir_buf[0].radius,
|
||||
cir_buf[0].cntr.x,
|
||||
cir_buf[0].cntr.y + cir_buf[0].radius, true);
|
||||
WriteCircularArc(fp,
|
||||
cir_buf[0].cntr.x,
|
||||
cir_buf[0].cntr.y,
|
||||
cir_buf[0].cntr.x,
|
||||
cir_buf[0].cntr.y + cir_buf[0].radius,
|
||||
cir_buf[0].cntr.x,
|
||||
cir_buf[0].cntr.y - cir_buf[0].radius, true);
|
||||
WriteEndGroup(fp);
|
||||
}
|
||||
}
|
||||
|
||||
if (draw_vde && draw_vdn) {
|
||||
WriteBeginGroup(fp, 7);
|
||||
for (i = 0; i < num_vdn_buf; ++i) {
|
||||
WriteMark(fp, 2, 6,
|
||||
nodes[vdn_buf[i].index].p.x, nodes[vdn_buf[i].index].p.y);
|
||||
}
|
||||
WriteEndGroup(fp);
|
||||
}
|
||||
|
||||
if (draw_pnts) {
|
||||
WriteBeginGroup(fp, 6);
|
||||
for (i = 2; i < num_pnt_buf - 2; ++i) {
|
||||
assert(InPntsList(pnt_buf[i].index));
|
||||
if (!incremental || pnts[pnt_buf[i].index].draw)
|
||||
WriteMark(fp, 2, 6,
|
||||
pnts[pnt_buf[i].index].p.x, pnts[pnt_buf[i].index].p.y);
|
||||
}
|
||||
WriteEndGroup(fp);
|
||||
}
|
||||
|
||||
CloseIpeFile(fp);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef OGL_GRAPHICS
|
||||
|
||||
void vroniObject::BuffToDrawArc(int j, int color)
|
||||
{
|
||||
assert(InArcsList(j));
|
||||
assert(InPntsList(arcs[j].i1));
|
||||
assert(InPntsList(arcs[j].i2));
|
||||
DrawArc(GetArcStartCoord(j), GetArcEndCoord(j), GetArcCenter(j),
|
||||
GetArcRadius(j), color);
|
||||
|
||||
coord pos;
|
||||
coord norm;
|
||||
|
||||
pos.x = GetArcStartCoord(j).x - GetArcEndCoord(j).x;
|
||||
pos.y = GetArcStartCoord(j).y - GetArcEndCoord(j).y;
|
||||
norm = VecCCW(pos);
|
||||
norm.x /= VecLen(pos);
|
||||
norm.y /= VecLen(pos);
|
||||
pos.x = GetArcCenter(j).x + norm.x*GetArcRadius(j);
|
||||
pos.y = GetArcCenter(j).y + norm.y*GetArcRadius(j);
|
||||
|
||||
int s, e;
|
||||
s = Get1stVtxArc(j);
|
||||
e = Get2ndVtxArc(j);
|
||||
DrawText(pos, color, " a%d %d->%d", j, s,e);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void vroniObject::BuffToDrawSeg(int j, int color)
|
||||
{
|
||||
assert(InSegsList(j));
|
||||
assert(InPntsList(segs[j].i1));
|
||||
assert(InPntsList(segs[j].i2));
|
||||
DrawSeg(GetSegStartCoord(j), GetSegEndCoord(j), color);
|
||||
|
||||
coord pos;
|
||||
pos = MidPoint(GetSegStartCoord(j), GetSegEndCoord(j));
|
||||
|
||||
int s, e;
|
||||
s = Get1stVtxSeg(j);
|
||||
e = Get2ndVtxSeg(j);
|
||||
DrawText(pos, color, " s%d %d->%d", j, s, e);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void vroniObject::Redraw(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_vde_buf; ++i) {
|
||||
if (vde_buf[i].color == GridColor) {
|
||||
DrawSeg(vde_buf[i].p1, vde_buf[i].p2, GridColor);
|
||||
}
|
||||
else if (vde_buf[i].color == TreeColor) {
|
||||
DrawSeg(vde_buf[i].p1, vde_buf[i].p2, TreeColor);
|
||||
}
|
||||
}
|
||||
/*
|
||||
if (num_cir_buf == 1) DrawCircle(circle_cntr, circle_radius, CirColor);
|
||||
*/
|
||||
|
||||
if (draw_vde) {
|
||||
for (i = 0; i < num_vde_buf; ++i) {
|
||||
if (vde_buf[i].color == VDColor) {
|
||||
DrawSeg(vde_buf[i].p1, vde_buf[i].p2, vde_buf[i].color);
|
||||
}
|
||||
}
|
||||
if (draw_mic) {
|
||||
for (i = 0; i < num_vde_buf; ++i) {
|
||||
if (vde_buf[i].color == CirColor)
|
||||
DrawSeg(vde_buf[i].p1, vde_buf[i].p2, vde_buf[i].color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (draw_mat) {
|
||||
for (i = 0; i < num_vde_buf; ++i) {
|
||||
if (vde_buf[i].color == WMATColor)
|
||||
DrawSeg(vde_buf[i].p1, vde_buf[i].p2, vde_buf[i].color);
|
||||
}
|
||||
}
|
||||
|
||||
if (draw_dte) {
|
||||
for (i = 0; i < num_vde_buf; ++i) {
|
||||
if (vde_buf[i].color == DTColor)
|
||||
DrawSeg(vde_buf[i].p1, vde_buf[i].p2, vde_buf[i].color);
|
||||
}
|
||||
}
|
||||
|
||||
if (draw_off) {
|
||||
for (i = 0; i < num_off_buf; ++i) {
|
||||
if (off_buf[i].r == 0) {
|
||||
DrawSeg(off_buf[i].p1, off_buf[i].p2, off_buf[i].color);
|
||||
}
|
||||
else {
|
||||
if (off_buf[i].ccw)
|
||||
DrawArc(off_buf[i].p2, off_buf[i].p1, off_buf[i].p3,
|
||||
off_buf[i].r, off_buf[i].color);
|
||||
else
|
||||
DrawArc(off_buf[i].p1, off_buf[i].p2, off_buf[i].p3,
|
||||
off_buf[i].r, off_buf[i].color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (draw_arcs) {
|
||||
for (i = 0; i < num_arc_buf; ++i) {
|
||||
if (arcs[arc_buf[i].index].draw)
|
||||
BuffToDrawArc(arc_buf[i].index, arc_buf[i].color);
|
||||
else if (!incremental)
|
||||
BuffToDrawArc(arc_buf[i].index, arc_buf[i].color);
|
||||
}
|
||||
}
|
||||
|
||||
if (draw_segs && draw_arcs) {
|
||||
for (i = 0; i < num_seg_buf; ++i) {
|
||||
if ((!incremental || segs[seg_buf[i].index].draw) &&
|
||||
seg_buf[i].color == SegColor)
|
||||
BuffToDrawSeg(seg_buf[i].index, seg_buf[i].color);
|
||||
}
|
||||
}
|
||||
else if (draw_segs) {
|
||||
for (i = 0; i < num_seg_buf; ++i) {
|
||||
if (!incremental || segs[seg_buf[i].index].draw)
|
||||
BuffToDrawSeg(seg_buf[i].index, seg_buf[i].color);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < num_cur_buf; ++i) {
|
||||
switch(cur_buf[i].type) {
|
||||
case(SEG):
|
||||
assert(InSegsList(cur_buf[i].index));
|
||||
BuffToDrawSeg(cur_buf[i].index, cur_buf[i].color);
|
||||
break;
|
||||
case(ARC):
|
||||
assert(InArcsList(cur_buf[i].index));
|
||||
BuffToDrawArc(cur_buf[i].index, cur_buf[i].color);
|
||||
break;
|
||||
case(VDE):
|
||||
assert(InEdgesList(cur_buf[i].index));
|
||||
if (draw_vde && (cur_buf[i].color == VDColor))
|
||||
DrawSeg(nodes[edges[cur_buf[i].index].n1].p,
|
||||
nodes[edges[cur_buf[i].index].n2].p, cur_buf[i].color);
|
||||
else if (draw_mat && (cur_buf[i].color == WMATColor))
|
||||
DrawSeg(nodes[edges[cur_buf[i].index].n1].p,
|
||||
nodes[edges[cur_buf[i].index].n2].p, cur_buf[i].color);
|
||||
break;
|
||||
case(DTE):
|
||||
assert(InPntsList(edges[cur_buf[i].index].n1));
|
||||
assert(InPntsList(edges[cur_buf[i].index].n2));
|
||||
DrawSeg(pnts[edges[cur_buf[i].index].n1].p,
|
||||
pnts[edges[cur_buf[i].index].n2].p, cur_buf[i].color);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (draw_vde && draw_vdn) {
|
||||
for (i = 0; i < num_vdn_buf; ++i) {
|
||||
DrawPnt(nodes[vdn_buf[i].index].p, vdn_buf[i].color, true);
|
||||
DrawText(nodes[vdn_buf[i].index].p, vdn_buf[i].color, " n%d",
|
||||
vdn_buf[i].index);
|
||||
}
|
||||
}
|
||||
|
||||
if (draw_pnts) {
|
||||
for (i = 0; i < num_pnt_buf; ++i) {
|
||||
assert(InPntsList(pnt_buf[i].index));
|
||||
if (!incremental ||
|
||||
(pnts[pnt_buf[i].index].draw && !pnts[pnt_buf[i].index].del)) {
|
||||
DrawPnt(pnts[pnt_buf[i].index].p, pnt_buf[i].color, false);
|
||||
DrawText(pnts[pnt_buf[i].index].p, pnt_buf[i].color, " p%d",
|
||||
pnt_buf[i].index);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else if (GetVDStatus() && !incremental) {
|
||||
for (i = 0; i < num_pnt_buf; ++i) {
|
||||
assert(InPntsList(pnt_buf[i].index));
|
||||
if (!HasIncidentSite(pnt_buf[i].index) &&
|
||||
!IsDeletedPnt(pnt_buf[i].index)) {
|
||||
DrawPnt(pnts[pnt_buf[i].index].p, pnt_buf[i].color, false);
|
||||
}
|
||||
DrawText(pnts[pnt_buf[i].index].p, pnt_buf[i].color, " p%d",
|
||||
pnt_buf[i].index);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < num_cur_buf; ++i) {
|
||||
switch(cur_buf[i].type) {
|
||||
case(PNT):
|
||||
assert(InPntsList(cur_buf[i].index));
|
||||
DrawPnt(pnts[cur_buf[i].index].p, cur_buf[i].color, true);
|
||||
break;
|
||||
case(VDN):
|
||||
assert(InNodesList(cur_buf[i].index));
|
||||
if ((draw_vde && (cur_buf[i].color != MICColor)) ||
|
||||
(draw_mic && (cur_buf[i].color == MICColor)))
|
||||
DrawPnt(nodes[cur_buf[i].index].p, cur_buf[i].color, true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (draw_mic) {
|
||||
for (i = 0; i < num_cir_buf; ++i) {
|
||||
DrawCircle(cir_buf[i].cntr, cir_buf[i].radius, MICColor);
|
||||
}
|
||||
}
|
||||
|
||||
for(i=0; i<GetNumberOfEdges(); i++) {
|
||||
coord pos;
|
||||
pos = MidPoint(nodes[edges[i].n1].p, nodes[edges[i].n2].p);
|
||||
|
||||
DrawText(pos, VDColor, " e%d (%d>%d)", i, edges[i].n1, edges[i].n2);
|
||||
}
|
||||
|
||||
if (!(draw_pnts || draw_segs || draw_arcs || draw_vde))
|
||||
VD_Warning("Redraw() - draw at least points or segs?");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#endif /* OGL_GRAPHICS */
|
||||
|
||||
|
||||
|
||||
#include "ext_appl_redraw.cc"
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,273 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 1999-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". */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef VRONI_ROOTS_H
|
||||
#define VRONI_ROOTS_H
|
||||
|
||||
int Roots3(double lead, double a, double b, double c, double roots[]);
|
||||
int Roots4(double lead, double a, double b, double c, double d,
|
||||
double roots[]);
|
||||
|
||||
#define ROOTS_ZERO 1.0e-50
|
||||
#define ROOTS_ZERO2 1.0e-100
|
||||
//#define ROOTS_ZERO 1.0e-14
|
||||
//#define ROOTS_ZERO2 1.0e-28
|
||||
#define DISCR_ZERO 1.0e-8
|
||||
#define ROOT_SMALL 0.125 /* ROOT_SMALL = 1/8 >> ZERO */
|
||||
#define ROOT_INV_SMALL 8.0 /* ROOT_INV_SMALL = 1/ROOT_SMALL */
|
||||
|
||||
/* */
|
||||
/* This macro solves the following second-degree polynomial equation: */
|
||||
/* */
|
||||
/* a * x^2 + b * x + c = 0. */
|
||||
/* */
|
||||
/* The roots are stored in roots[0] and roots[1]. Note that only real */
|
||||
/* roots are sought. The number of real roots found is stored in num_roots. */
|
||||
/* */
|
||||
#define Roots2abc(a, b, c, roots, num_roots) \
|
||||
{ \
|
||||
while (eq(a, ROOT_SMALL) && eq(b, ROOT_SMALL) && eq(c, ROOT_SMALL) && ((a != 0.0) || (b != 0.0) || (c != 0.0))) { \
|
||||
a *= 2.0; \
|
||||
b *= 2.0; \
|
||||
c *= 2.0; \
|
||||
} \
|
||||
while ((Abs(a) > ROOT_INV_SMALL) && (Abs(b) > ROOT_INV_SMALL) && (Abs(c) > ROOT_INV_SMALL)) { \
|
||||
a /= 2.0; \
|
||||
b /= 2.0; \
|
||||
c /= 2.0; \
|
||||
} \
|
||||
if (eq(a, ROOTS_ZERO)) { \
|
||||
if (eq(b, ROOTS_ZERO)) { \
|
||||
if (eq(c, ROOTS_ZERO)) { \
|
||||
num_roots = -1; \
|
||||
} \
|
||||
else { \
|
||||
num_roots = 0; \
|
||||
} \
|
||||
} \
|
||||
else { \
|
||||
roots[0] = - c / b; \
|
||||
num_roots = 1; \
|
||||
} \
|
||||
} \
|
||||
else { \
|
||||
basic_h_local_delta = b * b - 4 * a * c; \
|
||||
if (basic_h_local_delta > 0.0) { \
|
||||
if (b > 0) { \
|
||||
basic_h_local = - 0.5 * (b + sqrt(basic_h_local_delta)); \
|
||||
} \
|
||||
else { \
|
||||
basic_h_local = - 0.5 * (b - sqrt(basic_h_local_delta)); \
|
||||
} \
|
||||
if (eq(basic_h_local, ROOTS_ZERO)) { \
|
||||
roots[0] = basic_h_local / a; \
|
||||
num_roots = 1; \
|
||||
} \
|
||||
else { \
|
||||
roots[0] = basic_h_local / a; \
|
||||
roots[1] = c / basic_h_local; \
|
||||
num_roots = 2; \
|
||||
} \
|
||||
} \
|
||||
else if (eq(basic_h_local_delta, DISCR_ZERO)) { \
|
||||
roots[0] = - b / (2.0 * a); \
|
||||
num_roots = 1; \
|
||||
} \
|
||||
else { \
|
||||
num_roots = 0; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* This macro solves the following second-degree polynomial equation: */
|
||||
/* */
|
||||
/* x^2 + p * x + q = 0. */
|
||||
/* */
|
||||
/* The roots are stored in roots[0] and roots[1]. Note that only real */
|
||||
/* roots are sought. The number of real roots found is stored in num_roots. */
|
||||
/* */
|
||||
#define Roots2pq(p, q, roots, num_roots) \
|
||||
{ \
|
||||
basic_h_local_delta = p * p - 4 * q; \
|
||||
if (basic_h_local_delta > 0.0) { \
|
||||
if (p > 0) { \
|
||||
basic_h_local = - 0.5 * (p + sqrt(basic_h_local_delta)); \
|
||||
} \
|
||||
else { \
|
||||
basic_h_local = - 0.5 * (p - sqrt(basic_h_local_delta)); \
|
||||
} \
|
||||
if (eq(basic_h_local, ROOTS_ZERO)) { \
|
||||
roots[0] = basic_h_local; \
|
||||
num_roots = 1; \
|
||||
} \
|
||||
else { \
|
||||
roots[0] = basic_h_local; \
|
||||
roots[1] = q / basic_h_local; \
|
||||
num_roots = 2; \
|
||||
} \
|
||||
} \
|
||||
else if (eq(basic_h_local_delta, ROOTS_ZERO2)) { \
|
||||
roots[0] = - 0.5 * p; \
|
||||
num_roots = 1; \
|
||||
} \
|
||||
else { \
|
||||
num_roots = 0; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* This macro solves the following 2x2 linear system: */
|
||||
/* */
|
||||
/* A[0][0] * x + A[0][1] * y = B[0] */
|
||||
/* A[1][1] * x + A[1][1] * y = B[1] */
|
||||
/* */
|
||||
/* If a unique solution exists, then exists := 1, and the solution is stored */
|
||||
/* in xy[2]. If the solution is not unique, then exists := 2, and a solution */
|
||||
/* is stored in xy[2]. Otherwise, exists := 0. */
|
||||
/* */
|
||||
/* i, j, I, J are dummy integers needed within the macro. */
|
||||
/* */
|
||||
#define LinearEqnSolver_2x2(A, B, xy, exists, i, j, I, J) \
|
||||
{ \
|
||||
/* */ \
|
||||
/* find a column with a non-zero element */ \
|
||||
/* */ \
|
||||
exists = 0; \
|
||||
if (!eq((A)[0][0], ROOTS_ZERO) || !eq((A)[1][0], ROOTS_ZERO)) { \
|
||||
I = 0; \
|
||||
J = 1; \
|
||||
} \
|
||||
else if (!eq((A)[0][1], ROOTS_ZERO) || !eq((A)[1][1], ROOTS_ZERO)) { \
|
||||
I = 1; \
|
||||
J = 0; \
|
||||
} \
|
||||
else { \
|
||||
if (eq((B)[0], ROOTS_ZERO) && eq((B)[1], ROOTS_ZERO)) { \
|
||||
(xy)[0] = (xy)[1] = 0.0; \
|
||||
(exists) = 2; \
|
||||
} \
|
||||
I = J = 0; \
|
||||
} \
|
||||
\
|
||||
/* */ \
|
||||
/* determine i s.t. Abs(A[i][I]) is maximum. */ \
|
||||
/* */ \
|
||||
if ((I > 0) || (J > 0)) { \
|
||||
if (Abs((A)[0][I]) > Abs((A)[1][I])) { \
|
||||
i = 0; \
|
||||
j = 1; \
|
||||
} \
|
||||
else { \
|
||||
i = 1; \
|
||||
j = 0; \
|
||||
} \
|
||||
\
|
||||
basic_h_local_quot = (A)[j][I] / (A)[i][I]; \
|
||||
basic_h_local_delta = (A)[j][J] - basic_h_local_quot * (A)[i][J]; \
|
||||
if (!eq(basic_h_local_delta, ROOTS_ZERO)) { \
|
||||
(xy)[J] = ((B)[j] - basic_h_local_quot * (B)[i]) / basic_h_local_delta; \
|
||||
(xy)[I] = ((B)[i] - (xy)[J] * (A)[i][J]) / (A)[i][I]; \
|
||||
(exists) = 1; \
|
||||
} \
|
||||
else { \
|
||||
basic_h_local_delta = (B)[j] - basic_h_local_quot * (B)[i]; \
|
||||
if (eq(basic_h_local_delta, ROOTS_ZERO)) { \
|
||||
(xy)[J] = 0.0; \
|
||||
(xy)[I] = (B)[i] / (A)[i][I]; \
|
||||
(exists) = 2; \
|
||||
} \
|
||||
else { \
|
||||
(exists) = 0; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* This macro solves the following 2x2 linear system: */
|
||||
/* */
|
||||
/* A[0][0] * x + A[0][1] * y = B[0] */
|
||||
/* A[1][1] * x + A[1][1] * y = B[1] */
|
||||
/* */
|
||||
/* If a unique solution exists, then exists := 1, and the solution is stored */
|
||||
/* in xy[2]. If the solution is not unique, then exists := 2, and a solution */
|
||||
/* is stored in xy[2]. Otherwise, exists := 0. */
|
||||
/* */
|
||||
/* i, j, I, J are dummy integers needed within the macro. */
|
||||
/* */
|
||||
#define LinearEqnSolver_2x2_Zero(A, B, xy, exists, i, j, I, J) \
|
||||
{ \
|
||||
/* */ \
|
||||
/* find a column with a non-zero element */ \
|
||||
/* */ \
|
||||
exists = 0; \
|
||||
if (!eq((A)[0][0], ROOTS_ZERO) || !eq((A)[1][0], ROOTS_ZERO)) { \
|
||||
I = 0; \
|
||||
J = 1; \
|
||||
} \
|
||||
else if (!eq((A)[0][1], ROOTS_ZERO) || !eq((A)[1][1], ROOTS_ZERO)) { \
|
||||
I = 1; \
|
||||
J = 0; \
|
||||
} \
|
||||
else { \
|
||||
if (eq((B)[0], ROOTS_ZERO) && eq((B)[1], ROOTS_ZERO)) { \
|
||||
(xy)[0] = (xy)[1] = 0.0; \
|
||||
(exists) = 2; \
|
||||
} \
|
||||
I = J = 0; \
|
||||
} \
|
||||
\
|
||||
/* */ \
|
||||
/* determine i s.t. Abs(A[i][I]) is maximum. */ \
|
||||
/* */ \
|
||||
if ((I > 0) || (J > 0)) { \
|
||||
if (Abs((A)[0][I]) > Abs((A)[1][I])) { \
|
||||
i = 0; \
|
||||
j = 1; \
|
||||
} \
|
||||
else { \
|
||||
i = 1; \
|
||||
j = 0; \
|
||||
} \
|
||||
\
|
||||
basic_h_local_quot = (A)[j][I] / (A)[i][I]; \
|
||||
basic_h_local_delta = (A)[j][J] - basic_h_local_quot * (A)[i][J]; \
|
||||
if (!eq(basic_h_local_delta, ROOTS_ZERO)) { \
|
||||
(xy)[J] = ((B)[j] - basic_h_local_quot * (B)[i]) / basic_h_local_delta; \
|
||||
(xy)[I] = ((B)[i] - (xy)[J] * (A)[i][J]) / (A)[i][I]; \
|
||||
(exists) = 1; \
|
||||
} \
|
||||
else { \
|
||||
basic_h_local_delta = (B)[j] - basic_h_local_quot * (B)[i]; \
|
||||
if (eq(basic_h_local_delta, ROOTS_ZERO)) { \
|
||||
(xy)[J] = 0.0; \
|
||||
(xy)[I] = (B)[i] / (A)[i][I]; \
|
||||
(exists) = 2; \
|
||||
} \
|
||||
else { \
|
||||
(exists) = 0; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
+323
@@ -0,0 +1,323 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 1999-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 <stdlib.h>
|
||||
#include <stdio.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 "roots.h"
|
||||
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* computes the center cntr and the radius r2 of the circle tangential */
|
||||
/* to the segment segs[i] and passing through the points pnts[j],pnts[k]. */
|
||||
/* it returns false if the radius is too large to be computed numerically, */
|
||||
/* or if it is obvious that problems have occurred. if two centers exist */
|
||||
/* then we choose the center that lies on the Voronoi edge e. the vr_bool */
|
||||
/* flag problematic is set if a center was computed but its correctness is */
|
||||
/* doubtful. */
|
||||
/* */
|
||||
vr_bool vroniObject::SegPntPntCntr(int i, int j, int k, int e, coord *cntr,
|
||||
double *r2, vr_bool *problematic)
|
||||
{
|
||||
double dist, a, b, c;
|
||||
coord p, q, Q, V;
|
||||
double t, delta, lgth, eps, d_p_q, d2;
|
||||
double alpha, beta, x, y, z, alpha_p, alpha_q;
|
||||
coord m, v, n, u, tempc;
|
||||
int n1, ii;
|
||||
double roots[2];
|
||||
#ifdef TRACE
|
||||
vr_bool debug = true;
|
||||
#endif
|
||||
int num_sol = 0, best_sol = NIL;
|
||||
double radii[VRONI_MAXSOL];
|
||||
coord centers[VRONI_MAXSOL];
|
||||
|
||||
assert(InSegsList(i));
|
||||
assert(InPntsList(j));
|
||||
assert(InPntsList(k));
|
||||
assert(!(eq(GetSegLgth(i), ZERO)));
|
||||
|
||||
#ifdef TRACE
|
||||
if ((i == 6) && (j == 10) && (k == 11)) {
|
||||
printf("\nSegPntPntCntr() - seg %d\n", i);
|
||||
printf("start - (%24.20f %24.20f)\n", GetSegStartCoord(i).x,
|
||||
GetSegStartCoord(i).y);
|
||||
printf("end - (%24.20f %24.20f)\n", GetSegEndCoord(i).x,
|
||||
GetSegEndCoord(i).y);
|
||||
printf("pnt[%d] - (%24.20f %24.20f)\n", j, pnts[j].p.x, pnts[j].p.y);
|
||||
printf("pnt[%d] - (%24.20f %24.20f)\n", k, pnts[k].p.x, pnts[k].p.y);
|
||||
}
|
||||
#endif
|
||||
|
||||
*problematic = false;
|
||||
|
||||
/* */
|
||||
/* check whether the two points are identical. */
|
||||
/* */
|
||||
if (j == k) {
|
||||
VD_Dbg_Warning("SegPntPntCntr() - two identical points!");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* */
|
||||
/* we sort the two point indices in order to guarantee that the center of */
|
||||
/* these three sites is always computed consistently. */
|
||||
/* */
|
||||
SortTwoNumbers(j, k, n1);
|
||||
|
||||
/* */
|
||||
/* check whether one of the points is an endpoint of segs[i]. */
|
||||
/* */
|
||||
if (IsSegStartPnt(i, k) || IsSegEndPnt(i, k)) Swap(j, k, n1);
|
||||
|
||||
p = GetPntCoords(j);
|
||||
q = GetPntCoords(k);
|
||||
d2 = PntPntDistSq(p, q);
|
||||
d_p_q = sqrt(d2);
|
||||
lgth = GetSegLgth(i);
|
||||
eps = ZERO;
|
||||
|
||||
while (eps <= ZERO_MAX) {
|
||||
|
||||
num_sol = 0;
|
||||
|
||||
if (eq(d_p_q, eps)) {
|
||||
/* */
|
||||
/* both points are very close to each other. */
|
||||
/* */
|
||||
VD_Dbg_Warning("SegPntPntCntr() - points are too close!");
|
||||
SetInvalidSites(j, PNT, k, PNT, eps);
|
||||
restart = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsSegStartPnt(i, j) || IsSegEndPnt(i, j)) {
|
||||
if (IsSegStartPnt(i, k) || IsSegEndPnt(i, k)) {
|
||||
VD_Dbg_Warning("SegPntPntCntr() - both points are endpoints!");
|
||||
*problematic = true;
|
||||
}
|
||||
else {
|
||||
GetSegEqnData(i, &a, &b, &c);
|
||||
dist = PntLineDist(a, b, c, q);
|
||||
|
||||
if (eq(dist, eps)) {
|
||||
/* */
|
||||
/* both points lie on the line! this doesn't make much sense! */
|
||||
/* either the input data is corrupted, or we've run into a */
|
||||
/* problem... */
|
||||
/* */
|
||||
Q = GetSegStartCoord(i);
|
||||
if (IsInSegConeZero(Q, q, a, b, lgth, eps) == 0) {
|
||||
SetInvalidSites(i, SEG, k, PNT, eps);
|
||||
restart = false;
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
VD_Dbg_Warning("SegPntPntCntr() - both points lie on seg!");
|
||||
*problematic = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
V = VecSub(p, q);
|
||||
if (dist > 0.0) {
|
||||
Q = MakeVec( -a, -b);
|
||||
}
|
||||
else {
|
||||
Q = MakeVec( a, b);
|
||||
}
|
||||
delta = VecDotProd(Q, V);
|
||||
|
||||
if (!eq(delta, eps)) {
|
||||
t = (- 0.5) * d2 / delta;
|
||||
centers[0] = RayPnt(p, Q, t);
|
||||
radii[0] = Abs(t);
|
||||
num_sol = 1;
|
||||
}
|
||||
else {
|
||||
/* */
|
||||
/* the bisector of p,q is parallel to the line!? */
|
||||
/* */
|
||||
VD_Dbg_Warning("SegPntPntCntr() - cannot find center!");
|
||||
*problematic = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert(!(eq(GetSegLgth(i), ZERO)));
|
||||
p = GetPntCoords(j);
|
||||
q = GetPntCoords(k);
|
||||
v = VecSub(q, p);
|
||||
dist = VecLenSq(v) / 4.0;
|
||||
v = VecMult(0.5, v);
|
||||
n = VecCCW(v);
|
||||
|
||||
GetSegEqnData(i, &a, &b, &c);
|
||||
|
||||
alpha_p = PntLineDist(a, b, c, p);
|
||||
if (eq(alpha_p, eps)) {
|
||||
/* */
|
||||
/* point p lies on the line!? */
|
||||
/* */
|
||||
u = GetSegStartCoord(i);
|
||||
if (IsInSegConeZero(u, p, a, b, lgth, eps) == 0) {
|
||||
SetInvalidSites(i, SEG, j, PNT, eps);
|
||||
restart = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
alpha_q = PntLineDist(a, b, c, q);
|
||||
if (eq(alpha_q, eps)) {
|
||||
/* */
|
||||
/* point q lies on the line!? */
|
||||
/* */
|
||||
u = GetSegStartCoord(i);
|
||||
if (IsInSegConeZero(u, q, a, b, lgth, eps) == 0) {
|
||||
SetInvalidSites(i, SEG, k, PNT, eps);
|
||||
restart = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
alpha = (alpha_p + alpha_q) / 2.0;
|
||||
beta = n.x * a + n.y * b;
|
||||
y = 2 * alpha * beta;
|
||||
beta = beta * beta;
|
||||
alpha = alpha * alpha;
|
||||
x = beta - dist;
|
||||
z = alpha - dist;
|
||||
m = MidPoint(p, q);
|
||||
|
||||
/* */
|
||||
/* solve the quadratic equation. */
|
||||
/* */
|
||||
Roots2abc(x, y, z, roots, num_sol);
|
||||
|
||||
for (ii = 0; ii < num_sol; ++ii) {
|
||||
centers[ii] = RayPnt(m, n, roots[ii]);
|
||||
radii[ii] = PntPntDist(centers[ii], p);
|
||||
#ifdef TRACE
|
||||
printf("c[%d]: (%20.16f %20.16f)\n", ii,
|
||||
centers[ii].x, centers[ii].y);
|
||||
printf("r[%d] = %20.16f\n", ii, radii[ii]);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TRACE
|
||||
if (debug) {
|
||||
printf("Eqn x = %24.20f\n", x);
|
||||
printf("Eqn y = %24.20f\n", y);
|
||||
printf("Eqn z = %24.20f\n", z);
|
||||
printf("num_sol: %d\n", num_sol);
|
||||
printf("t1 = %20.16f\n", roots[0]);
|
||||
printf("t2 = %20.16f\n", roots[1]);
|
||||
printf("p: (%20.16f, %20.16f)\n", p.x, p.y);
|
||||
printf("q: (%20.16f, %20.16f)\n", q.x, q.y);
|
||||
printf("start: %d = (%20.16f, %20.16f); rad = %20.16f\n",
|
||||
GetStartNode(e),nodes[GetStartNode(e)].p.x,
|
||||
nodes[GetStartNode(e)].p.y, nodes[GetStartNode(e)].r2);
|
||||
printf("end: %d = (%20.16f, %20.16f); rad = %20.16f\n", GetEndNode(e),
|
||||
nodes[GetEndNode(e)].p.x, nodes[GetEndNode(e)].p.y,
|
||||
nodes[GetEndNode(e)].r2);
|
||||
if (IsNodeDeleted(GetStartNode(e))) printf("start node deleted\n");
|
||||
if (IsNodeDeleted(GetEndNode(e))) printf("end node deleted\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
/* */
|
||||
/* we have up to two possible centers. we select the center that */
|
||||
/* (ideally) lies within the cones of influence of the segments and */
|
||||
/* on the Voronoi edge e. */
|
||||
/* */
|
||||
best_sol = ClassifySolutions(i, j, k, e, SEG, PNT, PNT,
|
||||
false, true, true, centers, radii,
|
||||
&num_sol, eps, problematic);
|
||||
assert((0 <= best_sol) && (best_sol < num_sol));
|
||||
#ifdef TRACE
|
||||
printf("best_sol = %d, problematic = %d\n", best_sol, *problematic);
|
||||
#endif
|
||||
|
||||
if (!*problematic) {
|
||||
*cntr = centers[best_sol];
|
||||
*r2 = radii[best_sol];
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
eps *= 10.0;
|
||||
}
|
||||
}
|
||||
|
||||
if (eq(lgth, ZERO_MAX)) {
|
||||
/* */
|
||||
/* this is a seg with a very small length; we replace it */
|
||||
/* */
|
||||
VD_Dbg_Warning("SegPntPntCntr() - seg with small length!");
|
||||
ReplaceSeg(i);
|
||||
restart = true;
|
||||
return false;
|
||||
}
|
||||
else if (eq(d_p_q, ZERO_MAX)) {
|
||||
/* */
|
||||
/* both points are very close to each other. */
|
||||
/* */
|
||||
VD_Dbg_Warning("SegPntPntCntr() - points are too close!");
|
||||
SetInvalidSites(j, PNT, k, PNT, ZERO_MAX);
|
||||
restart = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef VRONI_DBG_WARN
|
||||
printf("\nCenter not computed for seg-pnt-pnt:\n");
|
||||
Q = GetSegStartCoord(i);
|
||||
V = GetSegEndCoord(i);
|
||||
printf("%20.16f %20.16f %20.16f %20.16f\n", Q.x, Q.y, V.x, V.y);
|
||||
p = GetPntCoords(j);
|
||||
q = GetPntCoords(k);
|
||||
printf("%20.16f %20.16f\n", p.x, p.y);
|
||||
printf("%20.16f %20.16f\n", q.x, q.y);
|
||||
#endif
|
||||
|
||||
*cntr = centers[best_sol];
|
||||
*r2 = radii[best_sol];
|
||||
restart = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
+336
@@ -0,0 +1,336 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 1999-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 <stdlib.h>
|
||||
#include <stdio.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 "roots.h"
|
||||
|
||||
/* #define TRACE */
|
||||
|
||||
|
||||
#define Determine2Sidedness(ai, bi, ci, pnt, dist, eps) \
|
||||
{\
|
||||
dist = PntLineDist(ai, bi, ci, pnt); \
|
||||
if (eq(dist, eps)) { \
|
||||
restart = true; \
|
||||
} \
|
||||
else if (dist < 0.0) { \
|
||||
ai = -ai; \
|
||||
bi = -bi; \
|
||||
ci = -ci; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
/* */
|
||||
/* computes the center cntr and the radius r2 of the circle tangential */
|
||||
/* to the segments segs[i], segs[j] and passing through the point pnts[k].*/
|
||||
/* it returns false if the radius is too large to be computed numerically, */
|
||||
/* or if it is obvious that problems have occurred. */
|
||||
/* */
|
||||
vr_bool vroniObject::SegSegPntCntr(int i, int j, int k, int e, coord *cntr,
|
||||
double *r2, vr_bool *problematic, int *site)
|
||||
{
|
||||
coord p, q, u, v, w, Q, centers[VRONI_MAXSOL];
|
||||
int n1;
|
||||
double ai, bi, ci, aj, bj, cj;
|
||||
double alpha, beta, dist, x, y, z;
|
||||
double roots[2], eps;
|
||||
#ifdef TRACE
|
||||
vr_bool debug = false;
|
||||
coord pi, pj;
|
||||
#endif
|
||||
int i_in, j_in;
|
||||
int num_sol = 0, best_sol = NIL, m;
|
||||
double radii[VRONI_MAXSOL];
|
||||
double lgth_i, lgth_j;
|
||||
|
||||
|
||||
assert(InSegsList(i));
|
||||
assert(InSegsList(j));
|
||||
assert(InPntsList(k));
|
||||
assert(!(eq(GetSegLgth(i), ZERO)));
|
||||
assert(!(eq(GetSegLgth(j), ZERO)));
|
||||
|
||||
eps = ZERO;
|
||||
i_in = i;
|
||||
j_in = j;
|
||||
|
||||
*site = NIL;
|
||||
*problematic = false;
|
||||
|
||||
/* */
|
||||
/* we sort the two segment indices in order to guarantee that the center */
|
||||
/* of these three sites is always computed consistently. */
|
||||
/* */
|
||||
SortTwoNumbers(i, j, n1);
|
||||
|
||||
#ifdef TRACE
|
||||
if (debug) {
|
||||
printf("SegSegPntCntr - seg1=%d seg2=%d\n", i, j);
|
||||
p = GetSegStartCoord(i);
|
||||
printf("start (%d) - (%20.16f %20.16f)\n", i, p.x, p.y);
|
||||
p = GetSegEndCoord(i);
|
||||
printf(" end (%d) - (%20.16f %20.16f)\n", i, p.x, p.y);
|
||||
p = GetSegStartCoord(j);
|
||||
printf("start (%d) - (%20.16f %20.16f)\n", j, p.x, p.y);
|
||||
p = GetSegEndCoord(j);
|
||||
printf(" end (%d) - (%20.16f %20.16f)\n", j, p.x, p.y);
|
||||
printf("SegSegPntCntr - pnt %d\n", k);
|
||||
printf("pnt[%d] - (%20.16f %20.16f)\n", k, pnts[k].p.x, pnts[k].p.y);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* */
|
||||
/* check whether the two segments are identical. */
|
||||
/* */
|
||||
if (i == j) {
|
||||
VD_Dbg_Warning("SegSegPntCntr() - the same segment!");
|
||||
return false;
|
||||
}
|
||||
n1 = Get1stVtx(i, SEG);
|
||||
if (IsSegStartPnt(j, n1) || IsSegEndPnt(j, n1)) {
|
||||
n1 = Get2ndVtx(i, SEG);
|
||||
if (IsSegStartPnt(j, n1) || IsSegEndPnt(j, n1)) {
|
||||
SetInvalidSites(i, SEG, j, SEG, ZERO);
|
||||
restart = false;
|
||||
return false; /* duplicate segs ! */
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
/* check whether the point pnts[k] is an endpoint of segs[i] or */
|
||||
/* segs[j]. */
|
||||
/* */
|
||||
p = GetPntCoords(k);
|
||||
if (IsSegStartPnt(j, k) || IsSegEndPnt(j, k)) Swap(i, j, n1);
|
||||
if (IsSegStartPnt(j, k) || IsSegEndPnt(j, k)) {
|
||||
/* */
|
||||
/* pnts[k] is an endpoint of both segs[i] and segs[j]. */
|
||||
/* */
|
||||
*cntr = p;
|
||||
*r2 = 0.0;
|
||||
*site = k;
|
||||
return true;
|
||||
}
|
||||
|
||||
lgth_i = GetSegLgth(i);
|
||||
lgth_j = GetSegLgth(j);
|
||||
|
||||
while (eps <= ZERO_MAX) {
|
||||
|
||||
num_sol = 0;
|
||||
restart = false;
|
||||
|
||||
if (IsSegStartPnt(i, k) || IsSegEndPnt(i, k)) {
|
||||
/* */
|
||||
/* compute the center cntr and the radius r2 of the circle */
|
||||
/* tangential to the segments segs[i], segs[j] and passing */
|
||||
/* through the point pnts[k], where pnts[k] is an endpoint of */
|
||||
/* segs[i]. */
|
||||
/* */
|
||||
/* get the precomputed line data. */
|
||||
/* */
|
||||
GetSegEqnData(i, &ai, &bi, &ci);
|
||||
if (IsLftRgtSite(e, i , SEG)) {
|
||||
n1 = GetStartNode(e);
|
||||
if (!IsNodeDeleted(n1)) n1 = GetEndNode(e);
|
||||
w = GetNodeCoord(n1);
|
||||
Determine2Sidedness(ai, bi, ci, w, dist, eps);
|
||||
n1 = 1;
|
||||
}
|
||||
else {
|
||||
n1 = 0;
|
||||
}
|
||||
GetSegEqnData(j, &aj, &bj, &cj);
|
||||
w = MakeVec( ai, bi);
|
||||
|
||||
/* */
|
||||
/* we intersect the bisector between segs[i] and p with the */
|
||||
/* offset of segs[j] in order to find the appropriate offset */
|
||||
/* value. in general, we will get two solutions. */
|
||||
/* */
|
||||
if (!IntersectRayOffsetSeg(p, w, aj, bj, cj, n1, 1, centers, roots,
|
||||
&num_sol)) {
|
||||
q = GetSegStartCoord(j);
|
||||
if (IsInSegConeZero(q, p, aj, bj, lgth_j, eps) == 0) {
|
||||
SetInvalidSites(j, SEG, k, PNT, eps);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* */
|
||||
/* get the precomputed line data and determine sidedness of point */
|
||||
/* p relative to the lines. */
|
||||
/* */
|
||||
n1 = GetStartNode(e);
|
||||
if (IsNodeDeleted(n1)) n1 = GetEndNode(e);
|
||||
GetSegEqnData(i, &ai, &bi, &ci);
|
||||
Determine2Sidedness(ai, bi, ci, p, dist, eps);
|
||||
if (restart) {
|
||||
u = GetSegStartCoord(i);
|
||||
if (IsInSegConeZero(u, p, ai, bi, lgth_i, eps) == 0) {
|
||||
SetInvalidSites(i, SEG, k, PNT, eps);
|
||||
VD_Dbg_Warning("SegSegPntCntr() - point on segment!");
|
||||
restart = false;
|
||||
return false;
|
||||
}
|
||||
restart = false;
|
||||
q = GetNodeCoord(n1);
|
||||
Determine2Sidedness(ai, bi, ci, q, dist, eps);
|
||||
}
|
||||
if (!restart) {
|
||||
GetSegEqnData(j, &aj, &bj, &cj);
|
||||
Determine2Sidedness(aj, bj, cj, p, dist, eps);
|
||||
if (restart) {
|
||||
u = GetSegStartCoord(j);
|
||||
if (IsInSegConeZero(u, p, aj, bj, lgth_j, eps) == 0) {
|
||||
SetInvalidSites(j, SEG, k, PNT, eps);
|
||||
VD_Dbg_Warning("SegSegPntCntr() - point on segment!");
|
||||
restart = false;
|
||||
return false;
|
||||
}
|
||||
restart = false;
|
||||
q = GetNodeCoord(n1);
|
||||
Determine2Sidedness(aj, bj, cj, q, dist, eps);
|
||||
}
|
||||
}
|
||||
|
||||
if (!restart) {
|
||||
/* */
|
||||
/* we compute the bisector Q + lambda * w of the two lines. */
|
||||
/* */
|
||||
if (!SegSegBisector(i, j, ai, bi, aj, bj, cj, &Q, &w)) {
|
||||
VD_Dbg_Warning("SegSegPntCntr() - cannot compute bisector!");
|
||||
}
|
||||
else {
|
||||
/* */
|
||||
/* intersect the line and the circle by solving a */
|
||||
/* second-degree equation. */
|
||||
/* */
|
||||
u = VecSub(Q, p);
|
||||
alpha = PntLineDist(ai, bi, ci, Q);
|
||||
beta = w.x * ai + w.y * bi;
|
||||
x = VecLenSq(w) - beta * beta;
|
||||
y = 2.0 * (VecDotProd(u, w) - alpha * beta);
|
||||
z = VecLenSq(u) - alpha * alpha;
|
||||
Roots2abc(x, y, z, roots, num_sol);
|
||||
|
||||
if (num_sol == 2) {
|
||||
centers[0] = RayPnt(Q, w, roots[0]);
|
||||
centers[1] = RayPnt(Q, w, roots[1]);
|
||||
|
||||
#ifdef TRACE
|
||||
if (debug) {
|
||||
printf("SegSegPntCntr - u = (%20.16f, %20.16f)\n", u.x, u.y);
|
||||
printf("SegSegPntCntr - v = (%20.16f, %20.16f)\n", v.x, v.y);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if (num_sol == 1) {
|
||||
centers[0] = RayPnt(Q, w, roots[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
restart = false;
|
||||
|
||||
/* */
|
||||
/* we have up to two possible centers. we select the center that */
|
||||
/* (ideally) lies within the cones of influence of the segments and */
|
||||
/* on the Voronoi edge e. */
|
||||
/* */
|
||||
for (m = 0; m < num_sol; ++m) {
|
||||
radii[m] = PntPntDist(centers[m], p);
|
||||
}
|
||||
best_sol = ClassifySolutions(i_in, j_in, k, e, SEG, SEG, PNT,
|
||||
false, true, true, centers, radii,
|
||||
&num_sol, eps, problematic);
|
||||
assert((0 <= best_sol) && (best_sol < num_sol));
|
||||
if (!*problematic) {
|
||||
*cntr = centers[best_sol];
|
||||
*r2 = radii[best_sol];
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
eps *= 10.0;
|
||||
}
|
||||
}
|
||||
|
||||
if (eq(lgth_i, ZERO_MAX)) {
|
||||
/* */
|
||||
/* this is a seg with a very small length; we replace it */
|
||||
/* */
|
||||
VD_Dbg_Warning("SegSegPntCntr() - seg with small length!");
|
||||
ReplaceSeg(i);
|
||||
restart = true;
|
||||
return false;
|
||||
}
|
||||
else if (eq(lgth_j, ZERO_MAX)) {
|
||||
/* */
|
||||
/* this is a seg with a very small length; we replace it */
|
||||
/* */
|
||||
VD_Dbg_Warning("SegSegPntCntr() - seg with small length!");
|
||||
ReplaceSeg(j);
|
||||
restart = true;
|
||||
return false;
|
||||
}
|
||||
else if (CheckIntersectionsLocally(i, SEG, j, SEG, k, PNT)) {
|
||||
restart = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef VRONI_DBG_WARN
|
||||
printf("\nCenter not computed for seg-seg-pnt:\n");
|
||||
q = GetSegStartCoord(i);
|
||||
v = GetSegEndCoord(i);
|
||||
printf("%20.16f %20.16f %20.16f %20.16f\n", q.x, q.y, v.x, v.y);
|
||||
q = GetSegStartCoord(j);
|
||||
v = GetSegEndCoord(j);
|
||||
printf("%20.16f %20.16f %20.16f %20.16f\n", q.x, q.y, v.x, v.y);
|
||||
p = GetPntCoords(k);
|
||||
printf("%20.16f %20.16f\n", p.x, p.y);
|
||||
#endif
|
||||
|
||||
*cntr = centers[best_sol];
|
||||
*r2 = radii[best_sol];
|
||||
restart = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
+588
@@ -0,0 +1,588 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 1999-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 <stdlib.h>
|
||||
#include <stdio.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 "roots.h"
|
||||
|
||||
|
||||
|
||||
#define Determine3Sidedness(a, b, c, old_start, old_end, dist, eps) \
|
||||
{\
|
||||
dist = PntLineDist(a, b, c, old_start); \
|
||||
if (eq(dist, eps)) { \
|
||||
dist = PntLineDist(a, b, c, old_end); \
|
||||
if (eq(dist, eps)) { \
|
||||
restart = true; \
|
||||
} \
|
||||
} \
|
||||
if (dist < 0.0) { \
|
||||
a = -a; \
|
||||
b = -b; \
|
||||
c = -c; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
/* */
|
||||
/* computes the center cntr and the radius r2 of the circle tangential */
|
||||
/* to the three segments segs[i], segs[j], segs[k]. it returns false if */
|
||||
/* the radius is too large to be computed numerically, or if it is obvious */
|
||||
/* that problems have occurred. */
|
||||
/* note that we assume that the new center lies on the same sides of */
|
||||
/* segs[i], segs[j], segs[k] as the node old_start on edge e, where e */
|
||||
/* is defined by segs[i], segs[j]. */
|
||||
/* */
|
||||
vr_bool vroniObject::SegSegSegCntr(int i, int j, int k, int e, coord *cntr,
|
||||
double *r2, vr_bool *problematic, int *site)
|
||||
{
|
||||
int m, n, n1, n2;
|
||||
double dist, ai, bi, ci, aj, bj, cj, ak, bk, ck, c, t;
|
||||
coord Q, V, U, W, X, old_end, old_start;
|
||||
double A[2][2], B[2], xy[2], alpha, beta, gamma, delta;
|
||||
double radius1, radius2, eps;
|
||||
int exists = 0, I0, I1, J0, J1, K;
|
||||
vr_bool success;
|
||||
vr_bool ij = false, ik = false, jk = false;
|
||||
coord centers[VRONI_MAXSOL];
|
||||
double radii[VRONI_MAXSOL];
|
||||
int num_sol = 0, best_sol = NIL;
|
||||
coord u, v;
|
||||
#ifdef TRACE
|
||||
double rad_min, rad_max;
|
||||
#endif
|
||||
int i_in, j_in, k_in;
|
||||
double lgth_i, lgth_j, lgth_k;
|
||||
|
||||
assert(InSegsList(i));
|
||||
assert(InSegsList(j));
|
||||
assert(InSegsList(k));
|
||||
assert(!(eq(GetSegLgth(i), ZERO)));
|
||||
assert(!(eq(GetSegLgth(j), ZERO)));
|
||||
assert(!(eq(GetSegLgth(k), ZERO)));
|
||||
|
||||
eps = ZERO;
|
||||
i_in = i;
|
||||
j_in = j;
|
||||
k_in = k;
|
||||
|
||||
*site = NIL;
|
||||
*problematic = false;
|
||||
|
||||
#ifdef TRACE
|
||||
if ((i_in == 100) && (j_in == 103) && (k_in == 104)) {
|
||||
printf("SegSegSegCntr - seg1=%d seg2=%d seg3=%d\n", i, j, k);
|
||||
Q = GetSegStartCoord(i);
|
||||
printf("start (%d) - %19.16f %19.16f\n", i, Q.x, Q.y);
|
||||
Q = GetSegEndCoord(i);
|
||||
printf("end (%d) - %19.16f %19.16f\n", i, Q.x, Q.y);
|
||||
Q = GetSegStartCoord(j);
|
||||
printf("start (%d) - %19.16f %19.16f\n", j, Q.x, Q.y);
|
||||
Q = GetSegEndCoord(j);
|
||||
printf("end (%d) - %19.16f %19.16f\n", j, Q.x, Q.y);
|
||||
Q = GetSegStartCoord(k);
|
||||
printf("start (%d) - %19.16f %19.16f\n", k, Q.x, Q.y);
|
||||
Q = GetSegEndCoord(k);
|
||||
printf("end (%d) - %19.16f %19.16f\n", k, Q.x, Q.y);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* */
|
||||
/* we sort the indices of line segments in order to guarantee that the */
|
||||
/* center of these three sites is always computed consistently. */
|
||||
/* */
|
||||
K = k;
|
||||
SortThreeNumbers(i, j, k, m);
|
||||
|
||||
/* */
|
||||
/* check whether two segments are identical. */
|
||||
/* */
|
||||
if ((i == j) || (j == k)) {
|
||||
VD_Dbg_Warning("SegSegSegCntr() - two identical segments!");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* */
|
||||
/* check whether the three segments share a common end point, or whether */
|
||||
/* two of them are identical */
|
||||
/* */
|
||||
m = Get1stVtx(k, SEG);
|
||||
if (IsSegStartPnt(i, m) || IsSegEndPnt(i, m)) {
|
||||
if (IsSegStartPnt(j, m) || IsSegEndPnt(j, m)) {
|
||||
n = Get2ndVtx(k, SEG);
|
||||
if (IsSegStartPnt(i, n) || IsSegEndPnt(i, n)) {
|
||||
SetInvalidSites(i, SEG, k, SEG, ZERO);
|
||||
restart = false;
|
||||
return false; /* duplicate segs ! */
|
||||
}
|
||||
else if (IsSegStartPnt(j, n) || IsSegEndPnt(j, n)) {
|
||||
SetInvalidSites(j, SEG, k, SEG, ZERO);
|
||||
restart = false;
|
||||
return false; /* duplicate segs ! */
|
||||
}
|
||||
else {
|
||||
*cntr = GetPntCoords(m);
|
||||
*r2 = 0.0;
|
||||
*site = m;
|
||||
return true; /* common end point */
|
||||
}
|
||||
}
|
||||
ik = true;
|
||||
}
|
||||
else if (IsSegStartPnt(j, m) || IsSegEndPnt(j, m)) {
|
||||
jk = true;
|
||||
}
|
||||
m = Get2ndVtx(k, SEG);
|
||||
if (IsSegStartPnt(i, m) || IsSegEndPnt(i, m)) {
|
||||
if (ik) {
|
||||
SetInvalidSites(i, SEG, k, SEG, ZERO);
|
||||
restart = false;
|
||||
return false; /* duplicate segs ! */
|
||||
}
|
||||
if (IsSegStartPnt(j, m) || IsSegEndPnt(j, m)) {
|
||||
if (jk) {
|
||||
SetInvalidSites(j, SEG, k, SEG, ZERO);
|
||||
restart = false;
|
||||
return false; /* duplicate segs ! */
|
||||
}
|
||||
else {
|
||||
*cntr = GetPntCoords(m);
|
||||
*r2 = 0.0;
|
||||
*site = m;
|
||||
return true; /* common end point */
|
||||
}
|
||||
}
|
||||
ik = true;
|
||||
}
|
||||
else if (IsSegStartPnt(j, m) || IsSegEndPnt(j, m)) {
|
||||
if (jk) {
|
||||
SetInvalidSites(j, SEG, k, SEG, ZERO);
|
||||
restart = false;
|
||||
return false; /* duplicate segs ! */
|
||||
}
|
||||
jk = true;
|
||||
}
|
||||
m = Get1stVtx(i, SEG);
|
||||
if (IsSegStartPnt(j, m) || IsSegEndPnt(j, m)) {
|
||||
m = Get2ndVtx(i, SEG);
|
||||
if (IsSegStartPnt(j, m) || IsSegEndPnt(j, m)) {
|
||||
SetInvalidSites(i, SEG, j, SEG, ZERO);
|
||||
restart = false;
|
||||
return false; /* duplicate segs ! */
|
||||
}
|
||||
ij = true;
|
||||
}
|
||||
else {
|
||||
m = Get2ndVtx(i, SEG);
|
||||
if (IsSegStartPnt(j, m) || IsSegEndPnt(j, m)) {
|
||||
ij = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
/* get the precomputed line data. */
|
||||
/* */
|
||||
n1 = GetStartNode(e);
|
||||
if (IsNodeDeleted(n1)) {
|
||||
n2 = n1;
|
||||
n1 = GetEndNode(e);
|
||||
}
|
||||
else {
|
||||
n2 = GetEndNode(e);
|
||||
}
|
||||
GetNodeData(n1, &old_start, &radius1);
|
||||
GetNodeData(n2, &old_end, &radius2);
|
||||
#ifdef TRACE
|
||||
if (radius1 < radius2) {
|
||||
rad_min = radius1;
|
||||
rad_max = radius2;
|
||||
}
|
||||
else {
|
||||
rad_min = radius2;
|
||||
rad_max = radius1;
|
||||
}
|
||||
if (center)
|
||||
printf("SegSegSeg: min radius = %19.16f, max radius = %19.16f\n",
|
||||
rad_min, rad_max);
|
||||
#endif
|
||||
|
||||
lgth_i = GetSegLgth(i);
|
||||
lgth_j = GetSegLgth(j);
|
||||
lgth_k = GetSegLgth(k);
|
||||
|
||||
while (eps <= ZERO_MAX) {
|
||||
|
||||
num_sol = 0;
|
||||
restart = false;
|
||||
|
||||
/* */
|
||||
/* determine the correct side of each line segment */
|
||||
/* */
|
||||
GetSegEqnData(i, &ai, &bi, &ci);
|
||||
if (K != i) {
|
||||
assert(IsLftRgtSite(e, i, SEG));
|
||||
Determine3Sidedness(ai, bi, ci, old_end, old_start, dist, eps);
|
||||
}
|
||||
else {
|
||||
Determine3Sidedness(ai, bi, ci, old_start, old_end, dist, eps);
|
||||
}
|
||||
if (restart) {
|
||||
VD_Dbg_Warning("SegSegSegCntr() - degenerate bisector!");
|
||||
}
|
||||
if (!restart) {
|
||||
GetSegEqnData(j, &aj, &bj, &cj);
|
||||
if (K != j) {
|
||||
assert(IsLftRgtSite(e, j, SEG));
|
||||
Determine3Sidedness(aj, bj, cj, old_end, old_start, dist, eps);
|
||||
}
|
||||
else {
|
||||
Determine3Sidedness(aj, bj, cj, old_start, old_end, dist, eps);
|
||||
}
|
||||
if (restart) {
|
||||
VD_Dbg_Warning("SegSegSegCntr() - degenerate bisector!");
|
||||
}
|
||||
}
|
||||
if (!restart) {
|
||||
GetSegEqnData(k, &ak, &bk, &ck);
|
||||
if (K != k) {
|
||||
assert(IsLftRgtSite(e, k, SEG));
|
||||
Determine3Sidedness(ak, bk, ck, old_end, old_start, dist, eps);
|
||||
}
|
||||
else {
|
||||
Determine3Sidedness(ak, bk, ck, old_start, old_end, dist, eps);
|
||||
}
|
||||
if (restart) {
|
||||
VD_Dbg_Warning("SegSegSegCntr() - degenerate bisector!");
|
||||
}
|
||||
}
|
||||
|
||||
if (!restart) {
|
||||
/* */
|
||||
/* first attempt to compute that Voronoi node. */
|
||||
/* */
|
||||
/* let's see whether we can compute the center by intersecting the */
|
||||
/* offset segments. */
|
||||
/* */
|
||||
A[0][0] = ai - aj;
|
||||
A[1][0] = ai - ak;
|
||||
A[0][1] = bi - bj;
|
||||
A[1][1] = bi - bk;
|
||||
B[0] = cj - ci;
|
||||
B[1] = ck - ci;
|
||||
LinearEqnSolver_2x2_Zero(A, B, xy, exists, I0, J0, I1, J1);
|
||||
|
||||
if (exists == 1) {
|
||||
/* */
|
||||
/* we've found a center. */
|
||||
/* */
|
||||
centers[num_sol].x = xy[0];
|
||||
centers[num_sol].y = xy[1];
|
||||
if (K == i) dist = PntLineDist(ai, bi, ci, centers[num_sol]);
|
||||
else if (K == j) dist = PntLineDist(aj, bj, cj, centers[num_sol]);
|
||||
else if (K == k) dist = PntLineDist(ak, bk, ck, centers[num_sol]);
|
||||
radii[num_sol] = Abs(dist);
|
||||
num_sol += 1;
|
||||
}
|
||||
|
||||
/* */
|
||||
/* second attempt to compute that Voronoi node. */
|
||||
/* */
|
||||
/* we compute the bisector between two segments, and intersect it */
|
||||
/* with the offset segment of the third segment. in an attempt to */
|
||||
/* minimize numerical instabilities we pay attention to the angles */
|
||||
/* between the segments: we pick the pair of segments that enclose */
|
||||
/* an angle which is closest to a right angle. however, if two */
|
||||
/* segments share endpoints then we prefer to use those segments */
|
||||
/* irrelevant of the angle enclosed. */
|
||||
/* */
|
||||
if (ij && ik && jk) {
|
||||
alpha = ai * ak + bi * bk;
|
||||
beta = ai * aj + bi * bj;
|
||||
gamma = aj * ak + bj * bk;
|
||||
delta = Max3(alpha, beta, gamma);
|
||||
}
|
||||
else if (ij) {
|
||||
delta = beta = 0.0;
|
||||
alpha = ai * ak + bi * bk;
|
||||
alpha = Abs(alpha);
|
||||
gamma = aj * ak + bj * bk;
|
||||
gamma = Abs(gamma);
|
||||
}
|
||||
else if (ik) {
|
||||
delta = alpha = 0.0;
|
||||
beta = ai * aj + bi * bj;
|
||||
beta = Abs(beta);
|
||||
gamma = aj * ak + bj * bk;
|
||||
gamma = Abs(gamma);
|
||||
}
|
||||
else if (jk) {
|
||||
delta = gamma = 0.0;
|
||||
alpha = ai * ak + bi * bk;
|
||||
alpha = Abs(alpha);
|
||||
beta = ai * aj + bi * bj;
|
||||
beta = Abs(beta);
|
||||
}
|
||||
else {
|
||||
alpha = ai * ak + bi * bk;
|
||||
alpha = Abs(alpha);
|
||||
beta = ai * aj + bi * bj;
|
||||
beta = Abs(beta);
|
||||
gamma = aj * ak + bj * bk;
|
||||
gamma = Abs(gamma);
|
||||
delta = Min3(alpha, beta, gamma);
|
||||
}
|
||||
|
||||
if (delta == alpha)
|
||||
success = SegSegBisector(i, k, ai, bi, ak, bk, ck, &Q, &V);
|
||||
else if (delta == beta)
|
||||
success = SegSegBisector(i, j, ai, bi, aj, bj, cj, &Q, &V);
|
||||
else /* (delta == gamma) */
|
||||
success = SegSegBisector(j, k, aj, bj, ak, bk, ck, &Q, &V);
|
||||
|
||||
if (!success) {
|
||||
/* */
|
||||
/* we could not compute that bisector: we use the old bisector! */
|
||||
/* */
|
||||
Q = old_start;
|
||||
V = VecSub(old_end, old_start);
|
||||
if (K == i) {
|
||||
delta = gamma = 2.0;
|
||||
}
|
||||
else if (K == j) {
|
||||
delta = alpha = 2.0;
|
||||
}
|
||||
else {
|
||||
delta = beta = 2.0;
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
/* we intersect the bisector of the two segments with the offset of */
|
||||
/* the third segment */
|
||||
/* */
|
||||
if (delta == alpha) {
|
||||
if (beta < gamma) {
|
||||
W.x = aj - ak;
|
||||
W.y = bj - bk;
|
||||
c = cj - ck;
|
||||
}
|
||||
else {
|
||||
W.x = aj - ai;
|
||||
W.y = bj - bi;
|
||||
c = cj - ci;
|
||||
}
|
||||
}
|
||||
else if (delta == beta) {
|
||||
if (alpha < gamma) {
|
||||
W.x = ak - ai;
|
||||
W.y = bk - bi;
|
||||
c = ck - ci;
|
||||
}
|
||||
else {
|
||||
W.x = ak - aj;
|
||||
W.y = bk - bj;
|
||||
c = ck - cj;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (alpha < beta) {
|
||||
W.x = ai - ak;
|
||||
W.y = bi - bk;
|
||||
c = ci - ck;
|
||||
}
|
||||
else {
|
||||
W.x = ai - aj;
|
||||
W.y = bi - bj;
|
||||
c = ci - cj;
|
||||
}
|
||||
}
|
||||
delta = - VecDotProd(W, V);
|
||||
|
||||
if (!eq(delta, TINY)) {
|
||||
t = (c + VecDotProd(W,Q)) / delta;
|
||||
centers[num_sol] = RayPnt(Q, V, t);
|
||||
if (K == i) dist = PntLineDist(ai, bi, ci, centers[num_sol]);
|
||||
else if (K == j) dist = PntLineDist(aj, bj, cj, centers[num_sol]);
|
||||
else if (K == k) dist = PntLineDist(ak, bk, ck, centers[num_sol]);
|
||||
radii[num_sol] = Abs(dist);
|
||||
num_sol += 1;
|
||||
}
|
||||
|
||||
/* */
|
||||
/* third attempt to compute that Voronoi node. */
|
||||
/* */
|
||||
/* we will compute the bisectors of two segments and will intersect */
|
||||
/* them. we first find the bisector between the segments which */
|
||||
/* enclose the smallest angle. (thus, their normal vectors enclose */
|
||||
/* the largest angle!) */
|
||||
/* */
|
||||
if ((ij && ik && jk) || (!(ij || ik || jk))) {
|
||||
alpha = ai * ak + bi * bk;
|
||||
beta = ai * aj + bi * bj;
|
||||
gamma = aj * ak + bj * bk;
|
||||
delta = Min3(alpha, beta, gamma);
|
||||
}
|
||||
else if (ij) {
|
||||
delta = beta = -1.0;
|
||||
if (ik) alpha = 1.0;
|
||||
else alpha = ai * ak + bi * bk;
|
||||
if (jk) gamma = 1.0;
|
||||
else gamma = aj * ak + bj * bk;
|
||||
}
|
||||
else if (ik) {
|
||||
delta = alpha = -1.0;
|
||||
beta = ai * aj + bi * bj;
|
||||
if (jk) gamma = 1.0;
|
||||
else gamma = aj * ak + bj * bk;
|
||||
}
|
||||
else {
|
||||
alpha = ai * ak + bi * bk;
|
||||
beta = ai * aj + bi * bj;
|
||||
delta = gamma = -1.0;
|
||||
}
|
||||
|
||||
if (delta == alpha)
|
||||
success = SegSegBisector(i, k, ai, bi, ak, bk, ck, &Q, &V);
|
||||
else if (delta == beta)
|
||||
success = SegSegBisector(i, j, ai, bi, aj, bj, cj, &Q, &V);
|
||||
else
|
||||
success = SegSegBisector(j, k, aj, bj, ak, bk, ck, &Q, &V);
|
||||
|
||||
if (success) {
|
||||
/* */
|
||||
/* we then find the bisector between the segments which enclose */
|
||||
/* the largest angle. (thus, their normal vectors enclose the */
|
||||
/* smallest angle!) */
|
||||
/* */
|
||||
delta = Max3(alpha, beta, gamma);
|
||||
if (delta == alpha)
|
||||
success = SegSegBisector(i, k, ai, bi, ak, bk, ck, &U, &W);
|
||||
else if (delta == beta)
|
||||
success = SegSegBisector(i, j, ai, bi, aj, bj, cj, &U, &W);
|
||||
else
|
||||
success = SegSegBisector(j, k, aj, bj, ak, bk, ck, &U, &W);
|
||||
|
||||
if (success) {
|
||||
/* */
|
||||
/* let's solve the 2x2 linear system and hope for the best. */
|
||||
/* */
|
||||
LineLineIntersection(A, B, xy, I0, J0, I1, J1, Q, V, U, W, X,
|
||||
exists);
|
||||
if (exists == 1) {
|
||||
centers[num_sol] = X;
|
||||
if (K == i) dist = PntLineDist(ai, bi, ci, X);
|
||||
else if (K == j) dist = PntLineDist(aj, bj, cj, X);
|
||||
else if (K == k) dist = PntLineDist(ak, bk, ck, X);
|
||||
radii[num_sol] = Abs(dist);
|
||||
num_sol += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
restart = false;
|
||||
|
||||
/* */
|
||||
/* we have up to three possible centers. we select the center that */
|
||||
/* (ideally) lies within the cones of influence of the segments and on */
|
||||
/* the Voronoi edge e. */
|
||||
/* */
|
||||
best_sol = ClassifySolutions(i_in, j_in, k_in, e, SEG, SEG, SEG,
|
||||
true, true, false, centers, radii,
|
||||
&num_sol, eps, problematic);
|
||||
assert((0 <= best_sol) && (best_sol < num_sol));
|
||||
if (!*problematic) {
|
||||
*cntr = centers[best_sol];
|
||||
*r2 = radii[best_sol];
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
eps *= 10.0;
|
||||
}
|
||||
}
|
||||
|
||||
if (eq(lgth_i, ZERO_MAX)) {
|
||||
/* */
|
||||
/* this is a seg with a very small length; we replace it */
|
||||
/* */
|
||||
VD_Dbg_Warning("SegSegSegCntr() - seg with small length!");
|
||||
ReplaceSeg(i);
|
||||
restart = true;
|
||||
return false;
|
||||
}
|
||||
else if (eq(lgth_j, ZERO_MAX)) {
|
||||
/* */
|
||||
/* this is a seg with a very small length; we replace it */
|
||||
/* */
|
||||
VD_Dbg_Warning("SegSegSegCntr() - seg with small length!");
|
||||
ReplaceSeg(j);
|
||||
restart = true;
|
||||
return false;
|
||||
}
|
||||
else if (eq(lgth_k, ZERO_MAX)) {
|
||||
/* */
|
||||
/* this is a seg with a very small length; we replace it */
|
||||
/* */
|
||||
VD_Dbg_Warning("SegSegSegCntr() - seg with small length!");
|
||||
ReplaceSeg(k);
|
||||
restart = true;
|
||||
return false;
|
||||
}
|
||||
else if (CheckIntersectionsLocally(i, SEG, j, SEG, k, SEG)) {
|
||||
restart = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef VRONI_DBG_WARN
|
||||
printf("\nCenter not computed for seg-seg-seg:\n");
|
||||
Q = GetSegStartCoord(i);
|
||||
V = GetSegEndCoord(i);
|
||||
printf("%20.16f %20.16f %20.16f %20.16f\n", Q.x, Q.y, V.x, V.y);
|
||||
Q = GetSegStartCoord(j);
|
||||
V = GetSegEndCoord(j);
|
||||
printf("%20.16f %20.16f %20.16f %20.16f\n", Q.x, Q.y, V.x, V.y);
|
||||
Q = GetSegStartCoord(k);
|
||||
V = GetSegEndCoord(k);
|
||||
printf("%20.16f %20.16f %20.16f %20.16f\n", Q.x, Q.y, V.x, V.y);
|
||||
#endif
|
||||
|
||||
*cntr = centers[best_sol];
|
||||
*r2 = radii[best_sol];
|
||||
restart = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 2000-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 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef VRONI_STACK_H
|
||||
#define VRONI_STACK_H
|
||||
|
||||
#define Push(data) \
|
||||
{\
|
||||
++num_stack; \
|
||||
if (num_stack >= max_num_stack) { \
|
||||
max_num_stack += STACK_INCR; \
|
||||
stack = (STACK_TYPE*) ReallocateArray(stack, max_num_stack, sizeof(STACK_TYPE), STACK_STRING); \
|
||||
} \
|
||||
stack[num_stack] = data; \
|
||||
}
|
||||
|
||||
|
||||
#define Pop(data) \
|
||||
{\
|
||||
assert(num_stack > 0); \
|
||||
data = stack[num_stack]; \
|
||||
--num_stack; \
|
||||
}
|
||||
|
||||
|
||||
#define GetStackSize (num_stack)
|
||||
|
||||
#define StackIsNotEmpty (num_stack > 0)
|
||||
|
||||
#define StackIsEmpty (num_stack <= 0)
|
||||
|
||||
#define ResetStack { num_stack = 0; }
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,530 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 2003-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: (+4 662) 8044-611 */
|
||||
/* Voice Mail: (+4 662) 8044-6304 */
|
||||
/* Snail Mail: Martin Held */
|
||||
/* FB Informatik */
|
||||
/* Universitaet Salzburg */
|
||||
/* A-5020 Salzburg, Austria */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* this file maintains a quadtree-like data structure which is used for */
|
||||
/* speeding up the search for nearest neighbors during the construction of */
|
||||
/* VDs of highly non-uniformly distributed points. the tree is generated */
|
||||
/* "on the fly" with no additional preprocessing. when a new point is to be */
|
||||
/* inserted into the tree, the cell/node that contains it is located. if its */
|
||||
/* squared distance to the nearest neighbor is less than ZERO2 = ZERO^2 */
|
||||
/* then the point is not inserted. otherwise, the cell that contains it is */
|
||||
/* split into four sub-cells of (typically) non-equal size by using this */
|
||||
/* point as the splitter. cells that cannot immediately searched during the */
|
||||
/* tree traversal are maintained in a heap that is ordered according to the */
|
||||
/* distance of the cell from the point to be inserted. */
|
||||
/* */
|
||||
/* please note that a random insertion of the points is assumed. (this is */
|
||||
/* the default compile-time option for VRONI!) inserting the points in some */
|
||||
/* prearranged form, such as sorted by x-coordinates, is likely to cause the */
|
||||
/* depth of the tree to grow substantially, which may once again result in */
|
||||
/* an overall quadratic time complexity. in order to enforce fairly balanced */
|
||||
/* splits during the first few levels, good splitters are determined by an */
|
||||
/* explicit search among all points that are to be inserted at once. (recall */
|
||||
/* that this tree is only constructed once the handling of the first few */
|
||||
/* percent of the points by means of a grid indicated a highly non-uniform */
|
||||
/* distribution of the points.) */
|
||||
/* */
|
||||
|
||||
|
||||
/* */
|
||||
/* get standard libraries */
|
||||
/* */
|
||||
#include <stdio.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 "heap.cc"
|
||||
|
||||
|
||||
#define Initial_Depth 2
|
||||
|
||||
|
||||
#define GetSplitter(node_idx) \
|
||||
(\
|
||||
assert(InTree(node_idx)), \
|
||||
tree[node_idx].splitter \
|
||||
)
|
||||
|
||||
#define SetChild_1(node_idx, ind) \
|
||||
{\
|
||||
assert(InTree(node_idx)); \
|
||||
tree[node_idx].ch1 = ind; \
|
||||
}
|
||||
|
||||
#define GetChild_1(node_idx) \
|
||||
(\
|
||||
assert(InTree(node_idx)), \
|
||||
tree[node_idx].ch1 \
|
||||
)
|
||||
|
||||
#define SetChild_2(node_idx, ind) \
|
||||
{\
|
||||
assert(InTree(node_idx)); \
|
||||
tree[node_idx].ch2 = ind; \
|
||||
}
|
||||
|
||||
#define GetChild_2(node_idx) \
|
||||
(\
|
||||
assert(InTree(node_idx)), \
|
||||
tree[node_idx].ch2 \
|
||||
)
|
||||
|
||||
#define SetChild_3(node_idx, ind) \
|
||||
{\
|
||||
assert(InTree(node_idx)); \
|
||||
tree[node_idx].ch3 = ind; \
|
||||
}
|
||||
|
||||
#define GetChild_3(node_idx) \
|
||||
(\
|
||||
assert(InTree(node_idx)), \
|
||||
tree[node_idx].ch3 \
|
||||
)
|
||||
|
||||
#define SetChild_4(node_idx, ind) \
|
||||
{\
|
||||
assert(InTree(node_idx)); \
|
||||
tree[node_idx].ch4 = ind; \
|
||||
}
|
||||
|
||||
#define GetChild_4(node_idx) \
|
||||
(\
|
||||
assert(InTree(node_idx)), \
|
||||
tree[node_idx].ch4 \
|
||||
)
|
||||
|
||||
|
||||
#define UpdateDistance(split, diff, min_ind, min_dist) \
|
||||
{\
|
||||
if (diff < min_dist) { \
|
||||
min_dist = diff; \
|
||||
min_ind = split; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
#define MakeTreeNode(node_idx, ind, addr) \
|
||||
{ \
|
||||
if (num_tree >= max_num_tree) { \
|
||||
max_num_tree += HEAP_BLOCK_SIZE; \
|
||||
tree = (tree_node*) ReallocateArray(tree, max_num_tree, \
|
||||
sizeof(tree_node), "tree:tree"); \
|
||||
} \
|
||||
node_idx = num_tree; \
|
||||
addr = &(tree[node_idx]); \
|
||||
addr->splitter = ind; \
|
||||
addr->ch1 = addr->ch2 = addr->ch3 = addr->ch4 = NIL; \
|
||||
\
|
||||
++num_tree; \
|
||||
}
|
||||
|
||||
|
||||
#define RememberCell(node_idx, dist, distance) \
|
||||
{\
|
||||
if (node_idx != NIL) {\
|
||||
if ((dist) <= distance) InsertIntoHeap(dist, node_idx); \
|
||||
}\
|
||||
}
|
||||
|
||||
|
||||
#define RecoverNextCell(node_idx, diff) \
|
||||
(\
|
||||
DeleteFromHeap(&diff, &node_idx) \
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
void vroniObject::RecursiveInitTree(double x_min, double y_min,
|
||||
double x_max, double y_max,
|
||||
int *first_N_points, int *m, int level)
|
||||
{
|
||||
double q_x, q_y, p_x, p_y, min_dist, min_diff, diff_x, diff_y, diff;
|
||||
int i_diff, n, ind;
|
||||
tree_node *addr;
|
||||
|
||||
/* */
|
||||
/* looking for a good splitter: we determine the point that is closest to */
|
||||
/* the center of this cell. */
|
||||
/* */
|
||||
/* */
|
||||
q_x = (x_min + x_max) / 2.0;
|
||||
q_y = (y_min + y_max) / 2.0;
|
||||
|
||||
min_diff = DBL_MAX;
|
||||
i_diff = NIL;
|
||||
|
||||
for (n = 0; n < *m; ++n) {
|
||||
p_x = GetPntCoords(first_N_points[n]).x;
|
||||
p_y = GetPntCoords(first_N_points[n]).y;
|
||||
if ((x_min <= p_x) && (p_x <= x_max) &&
|
||||
(y_min <= p_y) && (p_y <= y_max)) {
|
||||
diff_x = q_x - p_x;
|
||||
diff_y = q_y - p_y;
|
||||
diff = diff_x * diff_x + diff_y * diff_y;
|
||||
if (diff < min_diff) {
|
||||
i_diff = n;
|
||||
min_diff = diff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i_diff == NIL) return;
|
||||
|
||||
assert(InPntsList(first_N_points[i_diff]));
|
||||
if (root_of_tree == NIL) {
|
||||
/* */
|
||||
/* use this splitter as the first point to be inserted into the tree. */
|
||||
/* */
|
||||
ind = first_N_points[i_diff];
|
||||
MakeTreeNode(root_of_tree, ind, addr);
|
||||
assert(root_of_tree == 0);
|
||||
}
|
||||
else {
|
||||
(void) InsertPntIntoTree(first_N_points[i_diff], &min_dist, true);
|
||||
}
|
||||
p_x = GetPntCoords(first_N_points[i_diff]).x;
|
||||
p_y = GetPntCoords(first_N_points[i_diff]).y;
|
||||
--(*m);
|
||||
first_N_points[i_diff] = first_N_points[*m];
|
||||
|
||||
if (level < Initial_Depth) {
|
||||
/* */
|
||||
/* look for good splitters in the four sub-cells. */
|
||||
/* */
|
||||
RecursiveInitTree(x_min, y_min, p_x, p_y, first_N_points, m, level + 1);
|
||||
RecursiveInitTree(x_min, p_y, p_x, y_max, first_N_points, m, level + 1);
|
||||
RecursiveInitTree(p_x, y_min, x_max, p_y, first_N_points, m, level + 1);
|
||||
RecursiveInitTree(p_x, p_y, x_max, y_max, first_N_points, m, level + 1);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int vroniObject::InitTree(int number, int *first_N_points, int N_Initial,
|
||||
double *min_dist)
|
||||
{
|
||||
double eps;
|
||||
int m, n, i_min;
|
||||
|
||||
if (number>= max_num_tree) {
|
||||
max_num_tree = number;
|
||||
tree = (tree_node*) ReallocateArray(tree, max_num_tree,
|
||||
sizeof(tree_node), "tree:tree");
|
||||
}
|
||||
max_num_tree = 0;
|
||||
num_tree = 0;
|
||||
root_of_tree = NIL;
|
||||
|
||||
eps = ZERO_MAX;
|
||||
|
||||
/* */
|
||||
/* determine the location of the tree */
|
||||
/* */
|
||||
tree_delta_x = (bb_max.x - bb_min.x) * 0.01;
|
||||
tree_delta_y = (bb_max.y - bb_min.y) * 0.01;
|
||||
if (le(tree_delta_x, eps)) tree_delta_x = eps;
|
||||
if (le(tree_delta_y, eps)) tree_delta_y = eps;
|
||||
tree_min_x = bb_min.x - tree_delta_x;
|
||||
tree_max_x = bb_max.x + tree_delta_x;
|
||||
tree_min_y = bb_min.y - tree_delta_y;
|
||||
tree_max_y = bb_max.y + tree_delta_y;
|
||||
tree_delta_x = tree_max_x - tree_min_x;
|
||||
tree_delta_y = tree_max_y - tree_min_y;
|
||||
assert(gt(tree_delta_x, ZERO));
|
||||
assert(gt(tree_delta_y, ZERO));
|
||||
|
||||
/* */
|
||||
/* insert all points that have been processed so far into the tree. we */
|
||||
/* start finding a few good splitters for some top levels of the tree. */
|
||||
/* */
|
||||
assert(N_Initial >= 1);
|
||||
m = N_Initial;
|
||||
RecursiveInitTree(tree_min_x, tree_min_y, tree_max_x, tree_max_y,
|
||||
first_N_points, &m, 0);
|
||||
assert(root_of_tree != NIL);
|
||||
|
||||
/* */
|
||||
/* insert all remaining points */
|
||||
/* */
|
||||
for (n = 0; n < m; ++n) {
|
||||
i_min = InsertPntIntoTree(first_N_points[n], min_dist, true);
|
||||
}
|
||||
assert(InPntsList(first_N_points[N_Initial]));
|
||||
i_min = InsertPntIntoTree(first_N_points[N_Initial], min_dist, false);
|
||||
|
||||
return i_min;
|
||||
}
|
||||
|
||||
|
||||
|
||||
vr_bool vroniObject::InTree(int idx)
|
||||
{
|
||||
return ((idx >= 0) && (idx < num_tree));
|
||||
}
|
||||
|
||||
|
||||
void vroniObject::FreeTree(void)
|
||||
{
|
||||
FreeHeap();
|
||||
|
||||
FreeMemory((void**) &tree, "tree:tree");
|
||||
|
||||
max_num_tree = 0;
|
||||
num_tree = 0;
|
||||
root_of_tree = NIL;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* */
|
||||
/* insert pnts[ind] into the tree, and determine its nearest neighbor */
|
||||
/* (unless the flag no_distance is true). */
|
||||
/* */
|
||||
int vroniObject::InsertPntIntoTree(int ind, double *dist_min,
|
||||
vr_bool no_distance)
|
||||
{
|
||||
coord p, q;
|
||||
int root, min_ind, split;
|
||||
int child, next;
|
||||
double min_dist, diff, diff_x, diff_y, diff2_x, diff2_y;
|
||||
tree_node *addr;
|
||||
vr_bool remember_insert;
|
||||
int root_insert, child_insert;
|
||||
|
||||
p = GetPntCoords(ind);
|
||||
min_dist = DBL_MAX;
|
||||
min_ind = NIL;
|
||||
next = root_of_tree;
|
||||
remember_insert = true;
|
||||
root_insert = NIL;
|
||||
child_insert = NIL;
|
||||
assert(p.x > tree_min_x);
|
||||
assert(p.y > tree_min_y);
|
||||
assert(p.x < tree_max_x);
|
||||
assert(p.y < tree_max_y);
|
||||
assert(next == 0);
|
||||
|
||||
ResetHeap();
|
||||
|
||||
do {
|
||||
/* */
|
||||
/* search entire tree for a nearest neighbor */
|
||||
/* */
|
||||
do {
|
||||
/* */
|
||||
/* search one subtree for a nearest neighbor */
|
||||
/* */
|
||||
root = next;
|
||||
split = GetSplitter(root);
|
||||
q = GetPntCoords(split);
|
||||
diff_x = p.x - q.x;
|
||||
diff_y = p.y - q.y;
|
||||
diff2_x = diff_x * diff_x;
|
||||
diff2_y = diff_y * diff_y;
|
||||
diff = diff2_x + diff2_y;
|
||||
|
||||
UpdateDistance(split, diff, min_ind, min_dist);
|
||||
|
||||
if (diff_x < 0.0) {
|
||||
/* */
|
||||
/* point is left of the vertical line through this splitter */
|
||||
/* */
|
||||
if (diff_y < 0.0) {
|
||||
/* */
|
||||
/* point is below the horizontal line through this splitter */
|
||||
/* */
|
||||
next = GetChild_2(root);
|
||||
RememberCell(next, diff2_y, min_dist);
|
||||
next = GetChild_3(root);
|
||||
RememberCell(next, diff2_x, min_dist);
|
||||
next = GetChild_1(root);
|
||||
child = 1;
|
||||
}
|
||||
else {
|
||||
/* */
|
||||
/* point is above the horizontal line through this splitter */
|
||||
/* */
|
||||
next = GetChild_1(root);
|
||||
RememberCell(next, diff2_y, min_dist);
|
||||
next = GetChild_4(root);
|
||||
RememberCell(next, diff2_x, min_dist);
|
||||
next = GetChild_2(root);
|
||||
child = 2;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* */
|
||||
/* point is right of the vertical line through this splitter */
|
||||
/* */
|
||||
if (diff_y < 0.0) {
|
||||
/* */
|
||||
/* point is below the horizontal line through this splitter */
|
||||
/* */
|
||||
next = GetChild_4(root);
|
||||
RememberCell(next, diff2_y, min_dist);
|
||||
next = GetChild_1(root);
|
||||
RememberCell(next, diff2_x, min_dist);
|
||||
next = GetChild_3(root);
|
||||
child = 3;
|
||||
}
|
||||
else {
|
||||
/* */
|
||||
/* point is above the horizontal line through this splitter */
|
||||
/* */
|
||||
next = GetChild_3(root);
|
||||
RememberCell(next, diff2_y, min_dist);
|
||||
next = GetChild_2(root);
|
||||
RememberCell(next, diff2_x, min_dist);
|
||||
next = GetChild_4(root);
|
||||
child = 4;
|
||||
}
|
||||
}
|
||||
} while (next != NIL);
|
||||
|
||||
if (remember_insert) {
|
||||
remember_insert = false;
|
||||
root_insert = root;
|
||||
child_insert = child;
|
||||
if (no_distance) ResetHeap();
|
||||
}
|
||||
|
||||
while ((next == NIL) && RecoverNextCell(root, diff)) {
|
||||
if (diff <= min_dist) next = root;
|
||||
}
|
||||
|
||||
} while (next != NIL);
|
||||
|
||||
if (gt(min_dist, ZERO2)) {
|
||||
assert(root_insert != NIL);
|
||||
assert(child_insert != NIL);
|
||||
MakeTreeNode(next, ind, addr);
|
||||
switch(child_insert) {
|
||||
case 1:
|
||||
SetChild_1(root_insert, next);
|
||||
break;
|
||||
case 2:
|
||||
SetChild_2(root_insert, next);
|
||||
break;
|
||||
case 3:
|
||||
SetChild_3(root_insert, next);
|
||||
break;
|
||||
case 4:
|
||||
SetChild_4(root_insert, next);
|
||||
break;
|
||||
default:
|
||||
assert((1 <= child_insert) && (child_insert <= 4));
|
||||
}
|
||||
}
|
||||
|
||||
assert(min_ind != NIL);
|
||||
*dist_min = min_dist;
|
||||
|
||||
return min_ind;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef GRAPHICS
|
||||
void vroniObject::RecursiveDrawTree(double x_min, double y_min,
|
||||
double_arg x_max, double_arg y_max,
|
||||
int root)
|
||||
{
|
||||
coord p1, p2, q;
|
||||
int split, next;
|
||||
|
||||
while (root != NIL) {
|
||||
split = GetSplitter(root);
|
||||
q = GetPntCoords(split);
|
||||
|
||||
p1.x = x_min;
|
||||
p1.y = q.y;
|
||||
p2.x = x_max;
|
||||
p2.y = q.y;
|
||||
AddEdgeToBuffer(p1.x, p1.y, p2.x, p2.y, TreeColor);
|
||||
p1.x = q.x;
|
||||
p1.y = y_min;
|
||||
p2.x = q.x;
|
||||
p2.y = y_max;
|
||||
AddEdgeToBuffer(p1.x, p1.y, p2.x, p2.y, TreeColor);
|
||||
|
||||
next = GetChild_1(root);
|
||||
if (next != NIL) {
|
||||
RecursiveDrawTree(x_min, y_min, q.x, q.y, next);
|
||||
}
|
||||
next = GetChild_2(root);
|
||||
if (next != NIL) {
|
||||
RecursiveDrawTree(x_min, q.y, q.x, y_max, next);
|
||||
}
|
||||
next = GetChild_3(root);
|
||||
if (next != NIL) {
|
||||
RecursiveDrawTree(q.x, y_min, x_max, q.y, next);
|
||||
}
|
||||
root = GetChild_4(root);
|
||||
if (root != NIL) {
|
||||
x_min = q.x;
|
||||
y_min = q.y;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void vroniObject::DrawTree(void)
|
||||
{
|
||||
coord p1, p2, p3, p4;
|
||||
|
||||
p1.x = tree_min_x;
|
||||
p1.y = tree_min_y;
|
||||
p2.x = tree_max_x;
|
||||
p2.y = tree_min_y;
|
||||
p3.x = tree_max_x;
|
||||
p3.y = tree_max_y;
|
||||
p4.x = tree_min_x;
|
||||
p4.y = tree_max_y;
|
||||
|
||||
AddEdgeToBuffer(p1.x, p1.y, p2.x, p2.y, TreeColor);
|
||||
AddEdgeToBuffer(p2.x, p2.y, p3.x, p3.y, TreeColor);
|
||||
AddEdgeToBuffer(p3.x, p3.y, p4.x, p4.y, TreeColor);
|
||||
AddEdgeToBuffer(p4.x, p4.y, p1.x, p1.y, TreeColor);
|
||||
|
||||
RecursiveDrawTree(tree_min_x, tree_min_y, tree_max_x, tree_max_y,
|
||||
root_of_tree);
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,42 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* 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: Stefan Huber */
|
||||
/* Modified: 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 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
#ifndef VRONI_TYPES_H
|
||||
#define VRONI_TYPES_H
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef HAVE_BOOL
|
||||
#include <stdbool.h>
|
||||
typedef bool vr_bool;
|
||||
#else
|
||||
#define false 0
|
||||
#define true (!false)
|
||||
typedef unsigned char vr_bool;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,287 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 2010-2023 M. Held, S. Huber */
|
||||
/* */
|
||||
/* 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: Stefan Huber, 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 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef VRONI_UTIL_H
|
||||
#define VRONI_UTIL_H
|
||||
|
||||
#ifndef DOUBLE_OVERRIDE
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
#include "consts.h"
|
||||
|
||||
|
||||
inline static int Sign(double_arg x)
|
||||
{
|
||||
if ((x == 0.0) || (x == -0.0))
|
||||
return 0;
|
||||
|
||||
if ( x > 0.0)
|
||||
return 1;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/** Like Sign but closed interval (-eps, eps) is identified with 0 */
|
||||
inline static int SignEps(double_arg x, double_arg eps)
|
||||
{
|
||||
if (x > eps)
|
||||
return 1;
|
||||
else if (x < -eps)
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline static double Abs(double_arg x)
|
||||
{
|
||||
return fabs(x);
|
||||
}
|
||||
|
||||
inline static void Swap_d(double* x, double* y)
|
||||
{
|
||||
double t = *y;
|
||||
*y = *x;
|
||||
*x = t;
|
||||
}
|
||||
|
||||
inline static void Swap_i(int* x, int* y)
|
||||
{
|
||||
int t = *y;
|
||||
*y = *x;
|
||||
*x = t;
|
||||
}
|
||||
|
||||
inline static double Ceiling(double_arg x)
|
||||
{
|
||||
return ceil(x);
|
||||
}
|
||||
|
||||
#ifndef DOUBLE_OVERRIDE
|
||||
//function currently unused. In case it is used later, it requires
|
||||
//another way to calculate the CubicRoot for CORE and possibly MPFR
|
||||
inline static double CubicRoot(double_arg x)
|
||||
{
|
||||
const double r = pow(x, M_1_3);
|
||||
if(Sign(x)<0)
|
||||
return -r;
|
||||
else
|
||||
return r;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#define Sq(x) ((x) * (x))
|
||||
|
||||
#define Swap(i1, i2, i) \
|
||||
{(i) = (i1); \
|
||||
(i1) = (i2); \
|
||||
(i2) = (i); }
|
||||
|
||||
#define Min(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define Max(a, b) ((b) < (a) ? (a) : (b))
|
||||
#define Min3(a, b, c) (((a) < (b)) ? \
|
||||
(((a) < (c)) ? \
|
||||
(a) : (c)) \
|
||||
: \
|
||||
(((b) < (c)) ? \
|
||||
(b) : (c)))
|
||||
#define Max3(a, b, c) (((a) < (b)) ? \
|
||||
(((b) < (c)) ? \
|
||||
(c) : (b)) \
|
||||
: \
|
||||
(((a) < (c)) ? \
|
||||
(c) : (a)))
|
||||
#define Min4(a, b, c, d) (((a) < (b)) ? \
|
||||
(((a) < (c)) ? \
|
||||
(((a) < (d)) ?\
|
||||
(a) : (d)) \
|
||||
: \
|
||||
(((c) < (d)) ? \
|
||||
(c) : (d))) \
|
||||
: \
|
||||
(((b) < (c)) ? \
|
||||
(((b) < (d)) ? \
|
||||
(b) : (d)) \
|
||||
: \
|
||||
(((c) < (d)) ? \
|
||||
(c) : (d))))
|
||||
#define Max4(a, b, c, d) (((a) < (b)) ? \
|
||||
(((b) < (c)) ? \
|
||||
(((c) < (d)) ?\
|
||||
(d) : (c)) \
|
||||
: \
|
||||
(((b) < (d)) ? \
|
||||
(d) : (b))) \
|
||||
: \
|
||||
(((a) < (c)) ? \
|
||||
(((c) < (d)) ? \
|
||||
(d) : (c)) \
|
||||
: \
|
||||
(((a) < (d)) ? \
|
||||
(d) : (a))))
|
||||
|
||||
#define MinMax3(a, b, c, min, max) {\
|
||||
if ((a) < (b)) {\
|
||||
if ((a) < (c)) {\
|
||||
min = (a); \
|
||||
if ((b) < (c)) max = (c); \
|
||||
else max = (b); \
|
||||
}\
|
||||
else { \
|
||||
min = (c); \
|
||||
max = (b); \
|
||||
}\
|
||||
}\
|
||||
else { \
|
||||
if ((a) < (c)) {\
|
||||
min = (b); \
|
||||
max = (c); \
|
||||
} \
|
||||
else { \
|
||||
max = (a); \
|
||||
if ((b) < (c)) min = (b); \
|
||||
else min = (c); \
|
||||
} \
|
||||
}\
|
||||
}
|
||||
|
||||
|
||||
#define MinMax4(a, b, c, d, min, max) {\
|
||||
if ((a) < (b)) {\
|
||||
if ((a) < (c)) {\
|
||||
min = (a); \
|
||||
if ((b) < (c)) max = (c); \
|
||||
else max = (b); \
|
||||
} \
|
||||
else { \
|
||||
min = (c); \
|
||||
max = (b); \
|
||||
} \
|
||||
}\
|
||||
else { \
|
||||
if ((a) < (c)) { \
|
||||
min = (b); \
|
||||
max = (c); \
|
||||
} \
|
||||
else { \
|
||||
max = (a); \
|
||||
if ((b) < (c)) min = (b); \
|
||||
else min = (c); \
|
||||
}\
|
||||
} \
|
||||
if ((d) < min) min = (d); \
|
||||
else if ((d) > max) max = (d); \
|
||||
}
|
||||
|
||||
|
||||
#define SortTwoNumbers(a, b, c) {\
|
||||
if (a > b) { \
|
||||
c = a; \
|
||||
a = b; \
|
||||
b = c; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define SortThreeNumbers(a, b, c, d) {\
|
||||
if (a < b) {\
|
||||
if (a < c) {\
|
||||
if (b > c) {\
|
||||
d = b; \
|
||||
b = c; \
|
||||
c = d; \
|
||||
}\
|
||||
}\
|
||||
else { \
|
||||
d = a; \
|
||||
a = c; \
|
||||
c = b; \
|
||||
b = d; \
|
||||
}\
|
||||
}\
|
||||
else { \
|
||||
if (a < c) { \
|
||||
d = a; \
|
||||
a = b; \
|
||||
b = d; \
|
||||
} \
|
||||
else { \
|
||||
if (b < c) {\
|
||||
d = a; \
|
||||
a = b; \
|
||||
b = c; \
|
||||
c = d; \
|
||||
}\
|
||||
else { \
|
||||
d = a; \
|
||||
a = c; \
|
||||
c = d; \
|
||||
}\
|
||||
}\
|
||||
}\
|
||||
}
|
||||
|
||||
|
||||
#define MinMax(a, b, min, max) {\
|
||||
if ((b) < (a)) {\
|
||||
min = (b); \
|
||||
max = (a); \
|
||||
} \
|
||||
else { \
|
||||
min = (a); \
|
||||
max = (b); \
|
||||
} \
|
||||
}
|
||||
|
||||
|
||||
#define MinMaxQ(a, b, min, max) \
|
||||
(((b) < (a)) ? (min = (b), max = (a)) : (min = (a), max = (b)))
|
||||
|
||||
|
||||
#define MinMax3Q(a, b, c, min, max) \
|
||||
(((b) < (a)) ? (((c) < (b)) ? (min = (c), max = (a)) : \
|
||||
(((c) > (a)) ? (min = (b), max = (c)) : \
|
||||
(min = (b), max = (a)))) : \
|
||||
(((c) > (b)) ? (min = (a), max = (c)) : \
|
||||
(((c) > (a)) ? (min = (a), max = (b)) : \
|
||||
(min = (c), max = (b)))))
|
||||
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* some macros for epsilon-based comparisons with respect to zero... */
|
||||
/* */
|
||||
#define lt(a, b) ( ((a) < -b) )
|
||||
#define ge(a, b) (! ((a) < -b) )
|
||||
#define le(a, b) ( ((a) <= b) )
|
||||
#define gt(a, b) (! ((a) <= b) )
|
||||
#define eq(a, eps) ( (((a) <= eps) && !((a) < -eps)) )
|
||||
#define ne(a, eps) ( !eq(a,eps) )
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
+1880
File diff suppressed because it is too large
Load Diff
+747
@@ -0,0 +1,747 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* 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 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
/* #define TRACE */
|
||||
|
||||
#include "vroni_object.h"
|
||||
|
||||
|
||||
|
||||
void vroniObject::FreeVDConstructionData(void)
|
||||
{
|
||||
FreeMemory((void**) &pnt_visited, "voronoi:pnt_visited");
|
||||
FreeMemory((void**) &sites_visited, "voronoi:sites_visited");
|
||||
FreeMemory((void**) &nodes_checked, "voronoi:nodes_checked");
|
||||
FreeMemory((void**) &preserve, "voronoi:preserve");
|
||||
FreeMemory((void**) &loop_stack, "voronoi:loop_stack");
|
||||
|
||||
num_visited = 0;
|
||||
max_num_visited = 0;
|
||||
num_pnt_visited = 0;
|
||||
max_num_pnt_visited = 0;
|
||||
num_checked = 0;
|
||||
max_num_checked = 0;
|
||||
num_preserve = 0;
|
||||
max_num_preserve = 0;
|
||||
num_loop_stack = 0;
|
||||
max_num_loop_stack = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void vroniObject::ResetVDConstructionData(void)
|
||||
{
|
||||
num_visited = 0;
|
||||
num_pnt_visited = 0;
|
||||
num_preserve = 0;
|
||||
num_loop_stack = 0;
|
||||
num_checked = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void vroniObject::ResetNodeStatus(int e, int n)
|
||||
{
|
||||
int k, e1, e2;
|
||||
|
||||
k = GetOtherNode(e, n);
|
||||
|
||||
while (IsDeg2Node(k) && (IsNodeChecked(k) || IsNodeVisited(k))) {
|
||||
MarkNodeUnchecked(k);
|
||||
e1 = GetCCWEdge(e, k);
|
||||
assert(GetCCWEdge(e1, k) == e);
|
||||
e = e1;
|
||||
k = GetOtherNode(e, k);
|
||||
}
|
||||
|
||||
if (!(IsNodeChecked(k) || IsNodeVisited(k))) return;
|
||||
|
||||
MarkNodeUnchecked(k);
|
||||
|
||||
e1 = GetCCWEdge(e, k);
|
||||
e2 = GetCWEdge(e, k);
|
||||
ResetNodeStatus(e1, k);
|
||||
ResetNodeStatus(e2, k);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void vroniObject::ResetTreeDeleteStatus(int e, int n)
|
||||
{
|
||||
int k, e1, e2;
|
||||
|
||||
k = GetOtherNode(e, n);
|
||||
|
||||
while (IsDeg2Node(k) && IsNodeDeleted(k)) {
|
||||
MarkNodeVisited(k);
|
||||
e1 = GetCCWEdge(e, k);
|
||||
assert(GetCCWEdge(e1, k) == e);
|
||||
e = e1;
|
||||
k = GetOtherNode(e, k);
|
||||
}
|
||||
|
||||
if (!IsNodeDeleted(k)) return;
|
||||
|
||||
MarkNodeVisited(k);
|
||||
|
||||
e1 = GetCCWEdge(e, k);
|
||||
e2 = GetCWEdge(e, k);
|
||||
ResetTreeDeleteStatus(e1, k);
|
||||
ResetTreeDeleteStatus(e2, k);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* this routine inserts the closest point between segs[i] and the point */
|
||||
/* or arc i1 as a degree-2 node if it lies on their common VD edge e. */
|
||||
/* */
|
||||
void vroniObject::InsertApexDegreeTwoNodeSeg(int e, int i, int i1, t_site t1)
|
||||
{
|
||||
int n, n1, n2;
|
||||
coord c1, ss, se, p1, p2, v, w, q1, q2, p, u1, u2, apex;
|
||||
double t, d, r1, r2, a, b, sa, sb, sc;
|
||||
|
||||
assert(InEdgesList(e));
|
||||
assert(t1==PNT || t1==ARC);
|
||||
assert(t1==ARC || InPntsList(i1));
|
||||
assert(t1==PNT || InArcsList(i1));
|
||||
assert(InSegsList(i));
|
||||
|
||||
#ifndef GENUINE_ARCS
|
||||
assert(t1!=ARC);
|
||||
#endif
|
||||
|
||||
if ((t1 == PNT) && (IsSegStartPnt(i, i1) || IsSegEndPnt(i, i1))) {
|
||||
/* */
|
||||
/* pnts[i1] is the start point or end point of segs[i]. create a */
|
||||
/* dummy node at pnts[i1] if the VD edge extends to both sides of */
|
||||
/* segs[i]. */
|
||||
/* */
|
||||
if (IsSegStartPnt(i, i1)) p1 = GetSegStartCoord(i);
|
||||
else p1 = GetSegEndCoord(i);
|
||||
|
||||
if (!HasIncidentSite(i1)) {
|
||||
/* */
|
||||
/* segs[i] is the first site incident at pnts[i1] that has been */
|
||||
/* inserted. */
|
||||
/* */
|
||||
InsertSiteNode(e, p1, n, i1);
|
||||
}
|
||||
else {
|
||||
n1 = GetStartNode(e);
|
||||
n2 = GetEndNode(e);
|
||||
GetNodeData(n1, &q1, &r1);
|
||||
GetNodeData(n2, &q2, &r2);
|
||||
if (gt(r1, ZERO) && gt(r2, ZERO)) {
|
||||
p = GetPntCoords(i1);
|
||||
u1 = VecSub(q1, p1);
|
||||
u2 = VecSub(q2, p1);
|
||||
if (VecDotProd(u1, u2) < 0.0) {
|
||||
InsertSiteNode(e, p1, n, i1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* */
|
||||
/* get seg and pnt/arc data */
|
||||
/* */
|
||||
GetSegEqnData(i, &sa, &sb, &sc);
|
||||
ss = GetSegStartCoord(i);
|
||||
se = GetSegEndCoord(i);
|
||||
c1 = (t1 == PNT) ? GetPntCoords(i1) : GetArcCenter(i1);
|
||||
|
||||
/* */
|
||||
/* project c1 onto seg */
|
||||
/* */
|
||||
v = VecSub(se, ss);
|
||||
d = VecLen(v);
|
||||
v = VecDiv(d, v);
|
||||
w = VecSub(c1, ss);
|
||||
t = VecDotProd(v, w);
|
||||
|
||||
if ((t <= 0.0) || (t >= d)) return; /* projection not in CoI */
|
||||
p2 = RayPnt(ss, v, t);
|
||||
|
||||
if (t1 == PNT) {
|
||||
p1 = c1;
|
||||
}
|
||||
else {
|
||||
r1 = GetArcRadius(i1);
|
||||
GetChordEqnData(i1, &a, &b, &d);
|
||||
w = MakeVec(sa, sb);
|
||||
p1 = RayPnt(c1, w, r1);
|
||||
if (!IsOnArcStrict(a, b, d, p1)) {
|
||||
p1 = RayPnt(c1, w, -r1);
|
||||
if (!IsOnArcStrict(a, b, d, p1)) return;
|
||||
}
|
||||
}
|
||||
|
||||
apex = MidPoint(p1, p2);
|
||||
if (IsBetweenVoronoiNodes(e, apex, ZERO)) {
|
||||
/* */
|
||||
/* we've found an apex! */
|
||||
/* */
|
||||
d = PntPntDist(p1, apex);
|
||||
n = StoreNode(apex.x, apex.y, d);
|
||||
InsertDummyNode(e, n, false);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* this routine inserts the closest point between arcs[i] and the point/arc*/
|
||||
/* pnts/arcs[i1] as a degree-2 node if it lies on their common VD edge e. */
|
||||
/* t1 determines whether i1 is pnt or arc. */
|
||||
/* */
|
||||
#ifdef GENUINE_ARCS
|
||||
void vroniObject::InsertApexDegreeTwoNodeArc(int e, int i, int i1, t_site t1)
|
||||
{
|
||||
int n, n1, n2;
|
||||
coord w, c1, v, c, p1, p2, q1, q2, p, u1, u2;
|
||||
double d, r, r1, r2;
|
||||
double a, b;
|
||||
coord apex;
|
||||
|
||||
assert(InEdgesList(e));
|
||||
assert(InArcsList(i));
|
||||
assert(t1==PNT || t1==ARC);
|
||||
assert(t1==PNT || InArcsList(i1));
|
||||
assert(t1==ARC || InPntsList(i1));
|
||||
|
||||
if ((t1 == PNT) && (IsArcStartPnt(i, i1) || IsArcEndPnt(i, i1))) {
|
||||
/* */
|
||||
/* pnts[i1] is the start point or end point of segs[i]. create a */
|
||||
/* dummy node at pnts[i1] if the VD edge extends to both sides of */
|
||||
/* segs[i]. */
|
||||
/* */
|
||||
p = GetPntCoords(i1);
|
||||
|
||||
if (!HasIncidentSite(i1)) {
|
||||
/* */
|
||||
/* segs[i] is the first site incident at pnts[i1] that has been */
|
||||
/* inserted. */
|
||||
/* */
|
||||
InsertSiteNode(e, p, n, i1);
|
||||
}
|
||||
else {
|
||||
n1 = GetStartNode(e);
|
||||
n2 = GetEndNode(e);
|
||||
GetNodeData(n1, &q1, &r1);
|
||||
GetNodeData(n2, &q2, &r2);
|
||||
if (gt(r1, ZERO) && gt(r2, ZERO)) {
|
||||
u1 = VecSub(q1, p);
|
||||
u2 = VecSub(q2, p);
|
||||
if (VecDotProd(u1, u2) < 0.0) {
|
||||
/* */
|
||||
/* this is a VD edge that extends to both sides of the arc i */
|
||||
/* */
|
||||
InsertSiteNode(e, p, n, i1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* */
|
||||
/* we check whether i and i1 contain a pair of points p1, p2 */
|
||||
/* whose midpoint defines an apex of the bisector e. */
|
||||
/* */
|
||||
c = GetArcCenter(i);
|
||||
r = GetArcRadius(i);
|
||||
c1 = (t1 == PNT) ? GetPntCoords(i1) : GetArcCenter(i1);
|
||||
v = VecSub(c1, c);
|
||||
d = VecLen(v);
|
||||
|
||||
if (le(d, ZERO)) {
|
||||
/* */
|
||||
/* the point is at the center of the arc, or the arcs are */
|
||||
/* concentric. in either case no apex exists. */
|
||||
/* */
|
||||
return;
|
||||
}
|
||||
v = VecDiv(d, v);
|
||||
GetChordEqnData(i, &a, &b, &d);
|
||||
p2 = RayPnt(c, v, r);
|
||||
if (!IsOnArcStrict(a, b, d, p2)) {
|
||||
p2 = RayPnt(c, v, -r);
|
||||
if (!IsOnArcStrict(a, b, d, p2)) return;
|
||||
}
|
||||
|
||||
if (t1 == PNT) {
|
||||
p1 = c1;
|
||||
}
|
||||
else {
|
||||
r1 = GetArcRadius(i1);
|
||||
GetChordEqnData(i1, &a, &b, &d);
|
||||
p1 = RayPnt(c1, v, r1);
|
||||
if (!IsOnArcStrict(a, b, d, p1)) {
|
||||
p1 = RayPnt(c1, v, -r1);
|
||||
if (!IsOnArcStrict(a, b, d, p1)) return;
|
||||
}
|
||||
}
|
||||
|
||||
apex = MidPoint(p1, p2);
|
||||
|
||||
if (IsBetweenVoronoiNodes(e, apex, ZERO)) {
|
||||
/* */
|
||||
/* we've found an apex! */
|
||||
/* */
|
||||
d = PntPntDist(p1, apex);
|
||||
n = StoreNode(apex.x, apex.y, d);
|
||||
InsertDummyNode(e, n, false);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* the loop stack contains edges leading from n1 to n3, plus the actual */
|
||||
/* loop. we'll delete the prefix from n1 to n3. */
|
||||
/* */
|
||||
void vroniObject::PurifyLoop(int n1, int n3)
|
||||
{
|
||||
int number, k, j, e = 0, k0;
|
||||
|
||||
GetLoopStackSize(number);
|
||||
|
||||
for (j = 0; j < number; ++j) {
|
||||
GetLoopStackElement(j, e);
|
||||
k = GetStartNode(e);
|
||||
k0 = GetEndNode(e);
|
||||
if ((k == n3) || (k0 == n3)) {
|
||||
if (n1 != n3) ++j;
|
||||
ResetLoopStackMin(j);
|
||||
return;
|
||||
}
|
||||
}
|
||||
assert(1 == 0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* */
|
||||
/* check whether a loop of VD nodes marked for deletion exists. we start at */
|
||||
/* VD edge e at node n and visit neighboring nodes that have also been */
|
||||
/* flagged as "visited" in the previous step of the insertion of a new line */
|
||||
/* segment. (those nodes will be deleted afterwards.) during the scan we */
|
||||
/* convert the status of those nodes from "visited" to "deleted". if we */
|
||||
/* encounter during this (recursive) scan a node that carries already the */
|
||||
/* status "deleted" then we know that a loop exists. all edges traversed */
|
||||
/* are stored in a stack, which is reset whenever it is clear that some set */
|
||||
/* of edges traversed so far does not form a loop. */
|
||||
/* */
|
||||
vr_bool vroniObject::LoopExists(int e, int n, int *m)
|
||||
{
|
||||
int k, e1, e2, size;
|
||||
|
||||
k = GetOtherNode(e, n);
|
||||
GetLoopStackSize(size);
|
||||
PushOntoLoopStack(e);
|
||||
|
||||
while (IsDeg2Node(k) && IsNodeVisited(k)) {
|
||||
MarkNodeDeleted(k);
|
||||
e1 = GetCCWEdge(e, k);
|
||||
assert(GetCCWEdge(e1, k) == e);
|
||||
e = e1;
|
||||
k = GetOtherNode(e, k);
|
||||
PushOntoLoopStack(e);
|
||||
}
|
||||
|
||||
if (IsNodeDeleted(k)) {
|
||||
*m = k;
|
||||
return true;
|
||||
}
|
||||
else if (!IsNodeVisited(k)) {
|
||||
ResetLoopStackSize(size);
|
||||
return false;
|
||||
}
|
||||
|
||||
MarkNodeDeleted(k);
|
||||
|
||||
e1 = GetCCWEdge(e, k);
|
||||
if (LoopExists(e1, k, m))
|
||||
return true;
|
||||
e2 = GetCWEdge(e, k);
|
||||
if (LoopExists(e2, k, m))
|
||||
return true;
|
||||
else {
|
||||
ResetLoopStackSize(size);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
vr_bool vroniObject::ComputeCenter(int e, int i3, t_site t3,
|
||||
coord *w, double *r2,
|
||||
vr_bool *problematic, int *site)
|
||||
{
|
||||
int i1, i2;
|
||||
t_site t1, t2;
|
||||
vr_bool computed = false;
|
||||
coord centers[VRONI_MAXSOL];
|
||||
double radii[VRONI_MAXSOL];
|
||||
int num_sol = 0, best_sol = NIL;
|
||||
|
||||
*problematic = false;
|
||||
*site = NIL;
|
||||
|
||||
GetLftSiteData(e, &i1, &t1);
|
||||
GetRgtSiteData(e, &i2, &t2);
|
||||
|
||||
#ifdef TRACE
|
||||
if ((i3 == 13) && (t3 == ARC)) {
|
||||
printf("ComputeCenter(): e = %d\n", e);
|
||||
printf("ComputeCenter(): i1 = %d, t1 = %d\n", i1, t1);
|
||||
printf("ComputeCenter(): i2 = %d, t2 = %d\n", i2, t2);
|
||||
printf("ComputeCenter(): i3 = %d, t3 = %d\n", i3, t3);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (t1 == PNT) {
|
||||
if (t2 == PNT) {
|
||||
if (t3 == PNT) {
|
||||
computed = PntPntPntCntr(i1, i2, i3, w, r2);
|
||||
}
|
||||
else if (t3 == SEG) {
|
||||
computed = SegPntPntCntr(i3, i1, i2, e, w, r2, problematic);
|
||||
}
|
||||
#ifdef GENUINE_ARCS
|
||||
else if (t3 == ARC) {
|
||||
computed = ArcPntPntCntr(i3, i1, i2, e, w, r2, problematic);
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
VD_Warning("ComputeCenter() - site type not available");
|
||||
}
|
||||
}
|
||||
else if (t2 == SEG) {
|
||||
if (t3 == PNT) {
|
||||
computed = SegPntPntCntr(i2, i1, i3, e, w, r2, problematic);
|
||||
}
|
||||
else if (t3 == SEG) {
|
||||
computed = SegSegPntCntr(i3, i2, i1, e, w, r2, problematic, site);
|
||||
}
|
||||
#ifdef GENUINE_ARCS
|
||||
else if (t3 == ARC) {
|
||||
computed = ArcSegPntCntr(i3, i2, i1, e, w, r2, problematic, site);
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
VD_Warning("ComputeCenter() - site type not available");
|
||||
}
|
||||
}
|
||||
#ifdef GENUINE_ARCS
|
||||
else if (t2 == ARC) {
|
||||
if (t3 == ARC) {
|
||||
computed = ArcArcPntCntr(i3, i2, i1, e, w, r2, problematic, site);
|
||||
}
|
||||
else {
|
||||
VD_Warning("ComputeCenter() - site type not available");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
VD_Warning("ComputeCenter() - site type not available");
|
||||
}
|
||||
}
|
||||
else if (t1 == SEG) {
|
||||
if (t2 == PNT) {
|
||||
if (t3 == SEG) {
|
||||
computed = SegSegPntCntr(i3, i1, i2, e, w, r2, problematic, site);
|
||||
}
|
||||
#ifdef GENUINE_ARCS
|
||||
else if (t3 == ARC) {
|
||||
computed = ArcSegPntCntr(i3, i1, i2, e, w, r2, problematic, site);
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
VD_Warning("ComputeCenter() - site type not available");
|
||||
}
|
||||
}
|
||||
else if (t2 == SEG) {
|
||||
if (t3 == SEG) {
|
||||
computed = SegSegSegCntr(i1, i2, i3, e, w, r2, problematic, site);
|
||||
}
|
||||
#ifdef GENUINE_ARCS
|
||||
else if (t3 == ARC) {
|
||||
computed = ArcSegSegCntr(i3, i2, i1, e, w, r2, problematic, site);
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
VD_Warning("ComputeCenter() - site type not available");
|
||||
}
|
||||
}
|
||||
#ifdef GENUINE_ARCS
|
||||
else if (t2 == ARC) {
|
||||
if (t3 == ARC) {
|
||||
computed = ArcArcSegCntr(i3, i2, i1, e, w, r2, problematic, site);
|
||||
}
|
||||
else {
|
||||
VD_Warning("ComputeCenter() - site type not available");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
VD_Warning("ComputeCenter() - site type not available");
|
||||
}
|
||||
}
|
||||
#ifdef GENUINE_ARCS
|
||||
else if (t1 == ARC) {
|
||||
if (t2 == PNT) {
|
||||
if (t3 == ARC) {
|
||||
computed = ArcArcPntCntr(i3, i1, i2, e, w, r2, problematic, site);
|
||||
}
|
||||
|
||||
else {
|
||||
VD_Warning("ComputeCenter() - site type not available");
|
||||
}
|
||||
}
|
||||
else if (t2 == SEG) {
|
||||
if (t3 == ARC) {
|
||||
computed = ArcArcSegCntr(i3, i1, i2, e, w, r2, problematic, site);
|
||||
}
|
||||
|
||||
else {
|
||||
VD_Warning("ComputeCenter() - site type not available");
|
||||
}
|
||||
}
|
||||
else if (t2 == ARC) {
|
||||
if (t3 == ARC) {
|
||||
computed = ArcArcArcCntr(i3, i2, i1, e, w, r2, problematic, site);
|
||||
}
|
||||
|
||||
else {
|
||||
VD_Warning("ComputeCenter() - site type not available");
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
VD_Warning("ComputeCenter() - site type not available");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
VD_Warning("ComputeCenter() - site type not available");
|
||||
}
|
||||
|
||||
if (computed) {
|
||||
if (*problematic) {
|
||||
#ifdef VRONI_DBG_WARN
|
||||
printf("Using DesperateComputeCenter for e = %d and i3 = %d\n",
|
||||
e, i3);
|
||||
printf("i1 = %d of type %d, i2 = %d of type %d\n", i1, t1, i2, t2);
|
||||
#endif
|
||||
centers[0] = *w;
|
||||
radii[0] = *r2;
|
||||
DesperateComputeCenter(e, i3, t3, w, r2);
|
||||
centers[1] = *w;
|
||||
radii[1] = *r2;
|
||||
num_sol = 2;
|
||||
best_sol = ClassifySolutions(i3, i2, i1, e, t3, t2, t1,
|
||||
false, true, true, centers, radii,
|
||||
&num_sol, ZERO_MAX, problematic);
|
||||
*w = centers[best_sol];
|
||||
*r2 = radii[best_sol];
|
||||
if (best_sol == 1) VD_Dbg_Warning("ComputeCenter() - DesperateComputeCenter() improved solution!\n");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void vroniObject::UpdateRecursive(int i, t_site t, int n, int e,
|
||||
int *el, int *er, int *nl, int *nr)
|
||||
{
|
||||
t_site t1, t2;
|
||||
int i1, i2;
|
||||
#ifdef TRACE
|
||||
vr_bool dbg_center = false;
|
||||
#endif
|
||||
int i0, n0, e0, k, e1, e2, site = NIL;
|
||||
int e1r, n1r, e2l, n2l;
|
||||
t_site t0;
|
||||
coord q;
|
||||
double r;
|
||||
vr_bool problematic;
|
||||
coord centers[4];
|
||||
double radii[4];
|
||||
int num_sol = 0, best_sol = NIL;
|
||||
|
||||
assert((t == SEG) || (t == ARC));
|
||||
|
||||
k = GetOtherNode(e, n);
|
||||
|
||||
#ifdef TRACE
|
||||
if (i == 2) dbg_center = true;
|
||||
else dbg_center = false;
|
||||
|
||||
if (dbg_center) {
|
||||
printf("UpdateRecursive - edge e=%d, node n=%d\n", e, n);
|
||||
printf("UpdateRecursive - checking node k=%d of degree %d",
|
||||
k, 3 - IsDeg2Node(k));
|
||||
if (IsNodeDeleted(k)) printf(" --- to be deleted\n");
|
||||
else printf(" --- to be kept\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (IsNodeDeleted(k)) {
|
||||
/* */
|
||||
/* the Voronoi edge edges[e] is to be deleted; proceed recursively */
|
||||
/* */
|
||||
if (IsDeg2Node(k)) {
|
||||
e1 = GetCCWEdge(e, k);
|
||||
UpdateRecursive(i, t, k, e1, el, er, nl, nr);
|
||||
if (restart) return;
|
||||
}
|
||||
else {
|
||||
e1 = GetCCWEdge(e, k);
|
||||
e2 = GetCWEdge(e, k);
|
||||
UpdateRecursive(i, t, k, e1, el, &e1r, nl, &n1r);
|
||||
if (restart) return;
|
||||
UpdateRecursive(i, t, k, e2, &e2l, er, &n2l, nr);
|
||||
if (restart) return;
|
||||
|
||||
/* */
|
||||
/* insert a new bisector and close a Voronoi cell. */
|
||||
/* */
|
||||
if (GetEndNode(e1r) == n1r) {
|
||||
GetRgtSiteData(e1r, &i0, &t0);
|
||||
}
|
||||
else {
|
||||
assert(GetStartNode(e1r) == n1r);
|
||||
GetLftSiteData(e1r, &i0, &t0);
|
||||
}
|
||||
e0 = StoreEdge(n1r, n2l, i, i0, t, t0);
|
||||
#ifdef TRACE
|
||||
if (dbg_center) {
|
||||
printf("new edge %2d between sites (%2d/0, %2d/%1d) ",
|
||||
e0, i, i0, t0);
|
||||
printf("computed\n");
|
||||
printf("edge %d - start node %d, end node %d\n", e0, n1r, n2l);
|
||||
}
|
||||
#endif
|
||||
CloseVoronoiCell(e1r, e0, e2l, n1r, n2l);
|
||||
|
||||
/* */
|
||||
/* make sure the VD edge pointer is up-to-date */
|
||||
/* */
|
||||
SetVDPtr(i0, t0, e0);
|
||||
}
|
||||
/* */
|
||||
/* delete edges[e] and nodes[k]. */
|
||||
/* */
|
||||
DeleteEdge(e);
|
||||
DeleteNode(k);
|
||||
#ifdef TRACE
|
||||
if (dbg_center) {
|
||||
printf("node %2d has been deleted!\n", k);
|
||||
printf("edge %2d has been deleted!\n", e);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
/* */
|
||||
/* the Voronoi node nodes[k] is to be kept. insert a replacement */
|
||||
/* node for nodes[n] (which will be deleted). */
|
||||
/* */
|
||||
if (!IsNodeDummy(k)) MarkNodeUnchecked(k);
|
||||
|
||||
#ifdef TRACE
|
||||
if (dbg_center) {
|
||||
printf("new center for edge %3d and site %3d of type %d\n", e, i, t);
|
||||
GetLftSiteData(e, &i1, &t1);
|
||||
GetRgtSiteData(e, &i2, &t2);
|
||||
printf(" defining sites of edge: %2d/%1d, %2d/%1d)\n",
|
||||
i1, t1, i2, t2);
|
||||
}
|
||||
#endif
|
||||
if (!ComputeCenter(e, i, t, &q, &r, &problematic, &site)) {
|
||||
if (restart) return;
|
||||
if (IsInvalidData(false))
|
||||
return;
|
||||
else {
|
||||
VD_Dbg_Warning("UpdateRecursive() - desperate mode (center)!");
|
||||
centers[0] = q;
|
||||
radii[0] = r;
|
||||
DesperateComputeCenter(e, i, t, &q, &r);
|
||||
centers[1] = q;
|
||||
radii[1] = r;
|
||||
num_sol = 2;
|
||||
GetLftSiteData(e, &i1, &t1);
|
||||
GetRgtSiteData(e, &i2, &t2);
|
||||
best_sol = ClassifySolutions(i, i2, i1, e, t, t2, t1,
|
||||
false, true, true, centers, radii,
|
||||
&num_sol, ZERO_MAX, &problematic);
|
||||
q = centers[best_sol];
|
||||
r = radii[best_sol];
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
/* store the new node, and locally prepare the VD for the update. */
|
||||
/* */
|
||||
n0 = StoreNode(q.x, q.y, r);
|
||||
if (site != NIL) SetNodeSite(n0, site);
|
||||
|
||||
#ifdef TRACE
|
||||
if (dbg_center) {
|
||||
GetLftSiteData(e, &i1, &t1);
|
||||
GetRgtSiteData(e, &i2, &t2);
|
||||
printf("new node %2d between sites (%2d/%1d, %2d/%1d, %2d/%1d) ",
|
||||
n0, i, t, i1, t1, i2, t2);
|
||||
printf("computed\n");
|
||||
printf(" (%f, %f), radius2 = %f\n", q.x, q.y, r);
|
||||
}
|
||||
#endif
|
||||
|
||||
UpdateNodeEdgeData(e, n, n0);
|
||||
*el = *er = e;
|
||||
*nl = *nr = n0;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,457 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* 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" 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 my header files */
|
||||
/* */
|
||||
#include "vroni_object.h"
|
||||
|
||||
#ifdef VRONI_INFO
|
||||
#define IntWarning(S1, I1, S2, I2) \
|
||||
{\
|
||||
if (verbose) { \
|
||||
printf("\nwarning in ComputeVD() - the %s %d and the %s %d intersect!\n",\
|
||||
S1, I1, S2, I2); \
|
||||
} \
|
||||
}
|
||||
#else
|
||||
#define IntWarning(S1, I1, S2, I2) {}
|
||||
#endif
|
||||
|
||||
/* */
|
||||
/* find the Voronoi node on the Voronoi boundary of pnts[i] whose Voronoi */
|
||||
/* disk is violated the most by the insertion of p. */
|
||||
/* */
|
||||
int vroniObject::FindMostViolatedNodePnt(int i, coord p)
|
||||
{
|
||||
int e, e0, k, k_min = NIL;
|
||||
coord q;
|
||||
double dist, dist_min, rad, rad_min;
|
||||
|
||||
e = GetPntVDPtr(i);
|
||||
assert(InEdgesList(e));
|
||||
assert(IsLftPnt(e, i) || IsRgtPnt(e, i));
|
||||
|
||||
if (IsRgtPnt(e, i)) k = GetEndNode(e);
|
||||
else k = GetStartNode(e);
|
||||
|
||||
assert(InNodesList(k));
|
||||
e0 = e;
|
||||
dist_min = 1.0;
|
||||
rad_min = 0.0;
|
||||
|
||||
/* */
|
||||
/* scan the Voronoi cell in CCW order. */
|
||||
/* */
|
||||
do {
|
||||
GetNodeData(k, &q, &rad);
|
||||
dist = PntPntDistSq(p, q);
|
||||
if (rad > dist) {
|
||||
/* */
|
||||
/* p is inside the Voronoi disk of nodes[k]. */
|
||||
/* */
|
||||
if (dist_min * rad > rad_min * dist) {
|
||||
dist_min = dist;
|
||||
rad_min = rad;
|
||||
k_min = k;
|
||||
}
|
||||
}
|
||||
e = GetCCWEdge(e, k);
|
||||
k = GetOtherNode(e, k);
|
||||
} while (e != e0);
|
||||
|
||||
if (k_min == NIL) {
|
||||
VD_Warning("FindMostViolatedNodePnt() - no Voronoi disk violated!");
|
||||
|
||||
troubles = true;
|
||||
|
||||
if (IsInvalidData(true)) return NIL;
|
||||
|
||||
if (IsRgtPnt(e, i)) k = GetEndNode(e);
|
||||
else k = GetStartNode(e);
|
||||
dist_min = -DBL_MAX;
|
||||
|
||||
do {
|
||||
GetNodeData(k, &q, &rad);
|
||||
dist = sqrt(rad) - PntPntDist(p, q);
|
||||
if (dist > dist_min) {
|
||||
dist_min = dist;
|
||||
rad_min = rad;
|
||||
k_min = k;
|
||||
}
|
||||
e = GetCCWEdge(e, k);
|
||||
k = GetOtherNode(e, k);
|
||||
} while (e != e0);
|
||||
}
|
||||
|
||||
return k_min;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void vroniObject::UpdateRecursivePnt(int i, int n, int e,
|
||||
int *el, int *er, int *nl, int *nr)
|
||||
{
|
||||
int i0, i1, i2, n0, e0, k, k1, k2, e1, e2;
|
||||
int e1r, n1r, e2l, n2l;
|
||||
coord p, q, u, A, B, C;
|
||||
double r2, dist, rad;
|
||||
vr_bool delete_node;
|
||||
|
||||
k = GetOtherNode(e, n);
|
||||
delete_node = false;
|
||||
e1 = e2 = NIL;
|
||||
|
||||
if (IsNodeUnchecked(k)) {
|
||||
/* */
|
||||
/* only if this node has not yet been visited; make sure to avoid a */
|
||||
/* loop! */
|
||||
/* */
|
||||
e1 = GetCCWEdge(e, k);
|
||||
e2 = GetCWEdge(e, k);
|
||||
k1 = GetEndNode(e1);
|
||||
if (k1 == k) {
|
||||
i1 = GetRgtSite(e1);
|
||||
}
|
||||
else {
|
||||
assert(k == GetStartNode(e1));
|
||||
i1 = GetLftSite(e1);
|
||||
}
|
||||
assert((IsLftPnt(e2, i1)) || (IsRgtPnt(e2, i1)));
|
||||
|
||||
if (i1 != NIL) {
|
||||
if (!IsPntVisited(i1)) {
|
||||
/* */
|
||||
/* the Voronoi region of i1 has not yet been entered. we don't */
|
||||
/* want to create two disconnected parts. */
|
||||
/* */
|
||||
k1 = GetOtherNode(e1, k);
|
||||
k2 = GetOtherNode(e2, k);
|
||||
|
||||
if (!(IsNodeDeleted(k1) || IsNodeDeleted(k2))) {
|
||||
/* */
|
||||
/* only if removing k would not create a loop. */
|
||||
/* */
|
||||
GetNodeData(k, &q, &r2);
|
||||
p = GetPntCoords(i);
|
||||
dist = PntPntDistSq(p, q) - r2;
|
||||
|
||||
if (lt(dist, ZERO2)) {
|
||||
/* */
|
||||
/* the Delaunay circle of this node is violated by the */
|
||||
/* insertion of p. */
|
||||
/* */
|
||||
SetPntVisited(i1, true);
|
||||
AddPntVisited(i1);
|
||||
MarkNodeDeleted(k);
|
||||
#ifdef TRACE
|
||||
#ifdef GRAPHICS
|
||||
if (graphics) AddToCurBuffer(k, VDN, CurrColor);
|
||||
#endif
|
||||
#endif
|
||||
delete_node = true;
|
||||
}
|
||||
else {
|
||||
MarkNodeChecked(k);
|
||||
AddNodeChecked(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (delete_node) {
|
||||
/* */
|
||||
/* the Voronoi edge edges[e] is to be deleted; proceed recursively */
|
||||
/* */
|
||||
assert(e1 != NIL);
|
||||
assert(e2 != NIL);
|
||||
UpdateRecursivePnt(i, k, e1, el, &e1r, nl, &n1r);
|
||||
if (restart) return;
|
||||
UpdateRecursivePnt(i, k, e2, &e2l, er, &n2l, nr);
|
||||
if (restart) return;
|
||||
|
||||
/* */
|
||||
/* insert a new bisector and close a Voronoi cell. */
|
||||
/* */
|
||||
if (GetEndNode(e1r) == n1r) {
|
||||
i0 = GetRgtSite(e1r);
|
||||
}
|
||||
else {
|
||||
assert(GetStartNode(e1r) == n1r);
|
||||
i0 = GetLftSite(e1r);
|
||||
}
|
||||
e0 = StoreEdge(n1r, n2l, i, i0, PNT, PNT);
|
||||
#ifdef GRAPHICS
|
||||
if (graphics) AddToCurBuffer(e0, VDE, VDCurrColor);
|
||||
#endif
|
||||
CloseVoronoiCell(e1r, e0, e2l, n1r, n2l);
|
||||
|
||||
/* */
|
||||
/* make sure the VD edge pointer is up-to-date */
|
||||
/* */
|
||||
SetPntVDPtr(i0, e0);
|
||||
|
||||
/* */
|
||||
/* delete edges[e] and nodes[k]. */
|
||||
/* */
|
||||
DeleteEdge(e);
|
||||
DeleteNode(k);
|
||||
}
|
||||
else {
|
||||
/* */
|
||||
/* the Voronoi node nodes[k] is to be kept. insert a replacement */
|
||||
/* node for nodes[n] (which will be deleted). */
|
||||
/* */
|
||||
i1 = GetLftSite(e);
|
||||
i2 = GetRgtSite(e);
|
||||
if (!PntPntPntCntr(i, i1, i2, &q, &r2)) {
|
||||
troubles = true;
|
||||
if (IsInvalidData(true)) {
|
||||
restart = true;
|
||||
return;
|
||||
}
|
||||
else {
|
||||
GetNodeData(n, &u, &rad);
|
||||
dist = PntPntDistSq(u, pnts[i].p) - rad;
|
||||
if (eq(dist, ZERO)) {
|
||||
q = u;
|
||||
r2 = rad;
|
||||
}
|
||||
else {
|
||||
A = GetPntCoords(i);
|
||||
B = GetPntCoords(i1);
|
||||
C = GetPntCoords(i2);
|
||||
DesperatePntPntPntCntr(A, B, C, &q, &r2);
|
||||
VD_Warning("UpdateRecursivePnt() - desperate mode for center used!\n");
|
||||
desperate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* */
|
||||
/* store the new node, and locally prepare the VD for the update. */
|
||||
/* */
|
||||
n0 = StoreNode(q.x, q.y, r2);
|
||||
MarkNodeChecked(n0);
|
||||
AddNodeChecked(n0);
|
||||
UpdateNodeEdgeData(e, n, n0);
|
||||
*el = *er = e;
|
||||
*nl = *nr = n0;
|
||||
#ifdef GRAPHICS
|
||||
if (graphics) AddToCurBuffer(n0, VDN, CurrColor);
|
||||
#endif
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void vroniObject::InsertPntIntoVD(int i)
|
||||
{
|
||||
int j, i0, e0, e1, e2, e3;
|
||||
int e1l, e1r, n1l, n1r, e2l, e2r, n2l, n2r, e3l, e3r, n3l, n3r;
|
||||
int n, i1, i2, i3;
|
||||
coord p;
|
||||
double min_dist, EPS;
|
||||
vr_bool grid_inserted;
|
||||
|
||||
|
||||
assert(InPntsList(i));
|
||||
EPS = ZERO2 * 100.0;
|
||||
|
||||
#ifdef GRAPHICS
|
||||
if (graphics) {
|
||||
ResetCurBuffer();
|
||||
ResetVDBuffer();
|
||||
MarkDrawSite(i, PNT);
|
||||
AddToCurBuffer(i, PNT, SiteCurrColor);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef TRACE
|
||||
printf("inserting pnt[%d]: (%20.16f %20.16f)\n", i,
|
||||
GetPntCoords(i).x, GetPntCoords(i).y);
|
||||
#endif
|
||||
|
||||
/* */
|
||||
/* add pnts[i] to the grid or to the 2d-tree. */
|
||||
/* */
|
||||
grid_inserted = false;
|
||||
if (grid_used) {
|
||||
j = InsertPntIntoGrid(i, &min_dist);
|
||||
/* */
|
||||
/* find the nearest neighbor pnts[j] of point pnts[i]. */
|
||||
/* */
|
||||
if (grid_used && gt(min_dist, ZERO2)) {
|
||||
grid_inserted = true;
|
||||
j = FindNearestNeighborGrid(i, j, &min_dist);
|
||||
}
|
||||
}
|
||||
else {
|
||||
j = InsertPntIntoTree(i, &min_dist, false);
|
||||
}
|
||||
assert(InPntsList(j));
|
||||
if (eq(min_dist, EPS)) {
|
||||
if (grid_inserted) DeletePntFromGrid(i);
|
||||
if ((GetPntCoords(i).x == GetPntCoords(j).x) &&
|
||||
(GetPntCoords(i).y == GetPntCoords(j).y)) {
|
||||
SetDeletedPnt(i, true); /* pnts[i].p == pnts[j].p !! */
|
||||
if ((num_segs > 0) || (num_arcs > 0))
|
||||
RepairPntLinks(i, j, false);
|
||||
if (!restart) ++num_pnts_deleted;
|
||||
}
|
||||
else {
|
||||
VD_Dbg_Warning("InsertPntIntoVD() - two points too close!");
|
||||
IntWarning("pnt", i, "pnt", j);
|
||||
MergePoints(i, j);
|
||||
restart_due_to_intersection = numerical = true;
|
||||
restart = true;
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef GRAPHICS
|
||||
#ifdef TRACE
|
||||
if (graphics) {
|
||||
AddCirToBuffer(GetPntCoords(i), sqrt(min_dist));
|
||||
AddToCurBuffer(j, PNT, AlertColor);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* */
|
||||
/* find the nearest Voronoi node in the Voronoi cell of j. */
|
||||
/* */
|
||||
p = GetPntCoords(i);
|
||||
n = FindMostViolatedNodePnt(j, p);
|
||||
if (restart) return;
|
||||
assert(InNodesList(n));
|
||||
#ifdef GRAPHICS
|
||||
#ifdef TRACE
|
||||
if (graphics) AddToCurBuffer(n, VDN, CurrColor);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* */
|
||||
/* recursively discard all nodes and edges that are to be deleted. also, */
|
||||
/* we insert the new Voronoi nodes and edges. */
|
||||
/* */
|
||||
e1 = GetIncidentEdge(n);
|
||||
e2 = GetCCWEdge(e1, n);
|
||||
e3 = GetCCWEdge(e2, n);
|
||||
MarkNodeDeleted(n);
|
||||
i1 = GetLftSite(e1);
|
||||
i2 = GetRgtSite(e1);
|
||||
i3 = GetLftSite(e2);
|
||||
if ((i3 == i1) || (i3 == i2)) i3 = GetRgtSite(e2);
|
||||
assert((i3 != i1) && (i3 != i2));
|
||||
AddPntVisited(i1);
|
||||
AddPntVisited(i2);
|
||||
AddPntVisited(i3);
|
||||
SetPntVisited(i1, true);
|
||||
SetPntVisited(i2, true);
|
||||
SetPntVisited(i3, true);
|
||||
UpdateRecursivePnt(i, n, e1, &e1l, &e1r, &n1l, &n1r);
|
||||
if (restart) return;
|
||||
UpdateRecursivePnt(i, n, e2, &e2l, &e2r, &n2l, &n2r);
|
||||
if (restart) return;
|
||||
UpdateRecursivePnt(i, n, e3, &e3l, &e3r, &n3l, &n3r);
|
||||
if (restart) return;
|
||||
|
||||
/* */
|
||||
/* close the three Voronoi cells around nodes[n], which is to be deleted.*/
|
||||
/* */
|
||||
if (GetEndNode(e1r) == n1r) {
|
||||
i0 = GetRgtSite(e1r);
|
||||
}
|
||||
else {
|
||||
assert(GetStartNode(e1r) == n1r);
|
||||
i0 = GetLftSite(e1r);
|
||||
}
|
||||
e0 = StoreEdge(n1r, n2l, i, i0, PNT, PNT);
|
||||
|
||||
/* */
|
||||
/* make sure the VD edge pointer is up-to-date */
|
||||
/* */
|
||||
SetPntVDPtr(i0, e0);
|
||||
|
||||
#ifdef GRAPHICS
|
||||
if (graphics) AddToCurBuffer(e0, VDE, VDCurrColor);
|
||||
#endif
|
||||
CloseVoronoiCell(e1r, e0, e2l, n1r, n2l);
|
||||
if (GetEndNode(e2r) == n2r) {
|
||||
i0 = GetRgtSite(e2r);
|
||||
}
|
||||
else {
|
||||
assert(GetStartNode(e2r) == n2r);
|
||||
i0 = GetLftSite(e2r);
|
||||
}
|
||||
e0 = StoreEdge(n2r, n3l, i, i0, PNT, PNT);
|
||||
|
||||
/* */
|
||||
/* make sure the VD edge pointer is up-to-date */
|
||||
/* */
|
||||
SetPntVDPtr(i0, e0);
|
||||
|
||||
#ifdef GRAPHICS
|
||||
if (graphics) AddToCurBuffer(e0, VDE, VDCurrColor);
|
||||
#endif
|
||||
CloseVoronoiCell(e2r, e0, e3l, n2r, n3l);
|
||||
if (GetEndNode(e3r) == n3r) {
|
||||
i0 = GetRgtSite(e3r);
|
||||
}
|
||||
else {
|
||||
assert(GetStartNode(e3r) == n3r);
|
||||
i0 = GetLftSite(e3r);
|
||||
}
|
||||
e0 = StoreEdge(n3r, n1l, i, i0, PNT, PNT);
|
||||
|
||||
/* */
|
||||
/* make sure the VD edge pointer is up-to-date */
|
||||
/* */
|
||||
SetPntVDPtr(i0, e0);
|
||||
|
||||
#ifdef GRAPHICS
|
||||
if (graphics) AddToCurBuffer(e0, VDE, VDCurrColor);
|
||||
#endif
|
||||
CloseVoronoiCell(e3r, e0, e1l, n3r, n1l);
|
||||
|
||||
/* */
|
||||
/* delete node nodes[n] */
|
||||
/* */
|
||||
DeleteNode(n);
|
||||
|
||||
/* */
|
||||
/* set the Voronoi pointer for site pnts[i] */
|
||||
/* */
|
||||
SetPntVDPtr(i, e0);
|
||||
|
||||
/* */
|
||||
/* reset flags */
|
||||
/* */
|
||||
ResetPntVisited(j);
|
||||
ResetNodeChecked(j);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -0,0 +1,271 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 2010-2023 M. Held, S. Huber */
|
||||
/* */
|
||||
/* 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: Stefan Huber */
|
||||
/* Modified: 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 <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* */
|
||||
/* get my header files */
|
||||
/* */
|
||||
#include "vroni_object.h"
|
||||
|
||||
|
||||
|
||||
/** Update node n of edge e to node n0 */
|
||||
void vroniObject::UpdateNodeEdgeData(int e, int n, int n0)
|
||||
{
|
||||
assert(IsEdgeIncident(e, n));
|
||||
|
||||
if (GetStartNode(e) == n)
|
||||
SetStartNode(e, n0);
|
||||
else
|
||||
SetEndNode(e, n0);
|
||||
|
||||
SetCCWEdge(e, n0, NIL);
|
||||
SetCWEdge(e, n0, NIL);
|
||||
SetIncidentEdge(n0, e);
|
||||
}
|
||||
|
||||
|
||||
/** Consider edges and nodes e1-n1-e0-n2-e2 in CW order. Set cw and ccw
|
||||
* pointers of e0 to e1, e2, GetCWEdge(e1,n1), GetCCWEdge(e2,n2) and vice
|
||||
* versa. */
|
||||
void vroniObject::CloseVoronoiCell(int e1, int e0, int e2, int n1, int n2)
|
||||
{
|
||||
int e;
|
||||
|
||||
SetCCWEdge(e1, n1, e0);
|
||||
SetCWEdge(e0, n1, e1);
|
||||
SetCWEdge(e2, n2, e0);
|
||||
SetCCWEdge(e0, n2, e2);
|
||||
e = GetCWEdge(e1, n1);
|
||||
if (e != NIL) {
|
||||
SetCWEdge(e, n1, e0);
|
||||
SetCCWEdge(e0, n1, e);
|
||||
}
|
||||
e = GetCCWEdge(e2, n2);
|
||||
if (e != NIL) {
|
||||
SetCCWEdge(e, n2, e0);
|
||||
SetCWEdge(e0, n2, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Copy segment s1 to segment s */
|
||||
void vroniObject::CopySegData(int s, int s1)
|
||||
{
|
||||
assert(InSegsList(s));
|
||||
assert(InSegsList(s1));
|
||||
segs[s] = segs[s1];
|
||||
}
|
||||
|
||||
|
||||
/** Copy arc s1 to arc s */
|
||||
void vroniObject::CopyArcData(int s, int s1)
|
||||
{
|
||||
assert(InArcsList(s));
|
||||
assert(InArcsList(s1));
|
||||
arcs[s] = arcs[s1];
|
||||
}
|
||||
|
||||
#ifdef WRITE_VD
|
||||
void vroniObject::SetVDEdge(int s, int t, int e)
|
||||
{
|
||||
if (t == PNT) {
|
||||
assert(InPntsList(s));
|
||||
pnts[s].vd_edge = e;
|
||||
} else if (t == SEG) {
|
||||
assert(InSegsList(s));
|
||||
segs[s].vd_edge = e;
|
||||
} else {
|
||||
#ifdef VRONI_WARN
|
||||
printf("\nwarning in SetVDEdge() - unknown site type %d\n", t);
|
||||
#endif
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
int vroniObject::GetVDEdge(int s, int t)
|
||||
{
|
||||
if (t == PNT) {
|
||||
assert(InPntsList(s));
|
||||
return pnts[s].vd_edge;
|
||||
} else if (t == SEG) {
|
||||
assert(InSegsList(s));
|
||||
return segs[s].vd_edge;
|
||||
} else {
|
||||
#ifdef VRONI_WARN
|
||||
printf("\nwarning in GetVDEdge() - unknown site type %d\n", t);
|
||||
#endif
|
||||
assert(false);
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
|
||||
void vroniObject::SetPntIndex(int i, int n)
|
||||
{
|
||||
assert(InPntsList(i));
|
||||
pnts[i].idx = n;
|
||||
}
|
||||
|
||||
|
||||
int vroniObject::GetPntIndex(int i)
|
||||
{
|
||||
assert(InPntsList(i));
|
||||
return pnts[i].idx;
|
||||
}
|
||||
|
||||
void vroniObject::SetNodeIndex(int i, int n)
|
||||
{
|
||||
assert(InNodesList(i));
|
||||
nodes[i].idx = n;
|
||||
}
|
||||
|
||||
int vroniObject::GetNodeIndex(int i)
|
||||
{
|
||||
assert(InNodesList(i));
|
||||
return nodes[i].idx;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ORDERED
|
||||
|
||||
/** Set key of site s of type t to n */
|
||||
void vroniObject::SetSiteNumber(int s, t_site t, int n)
|
||||
{
|
||||
if (t == PNT) {
|
||||
assert(InPntsList(s));
|
||||
pnts[s].key = n;
|
||||
} else if (t == SEG) {
|
||||
assert(InSegsList(s));
|
||||
segs[s].key = n;
|
||||
} else if (t == ARC) {
|
||||
assert(InArcsList(s));
|
||||
arcs[s].key = n;
|
||||
} else
|
||||
assert(false);
|
||||
}
|
||||
|
||||
/** Get key of site s of type n */
|
||||
int vroniObject::GetSiteNumber(int s, t_site t)
|
||||
{
|
||||
if (t == PNT) {
|
||||
assert(InPntsList(s));
|
||||
return pnts[s].key;
|
||||
} else if (t == SEG) {
|
||||
assert(InSegsList(s));
|
||||
return segs[s].key;
|
||||
} else if (t == ARC) {
|
||||
assert(InArcsList(s));
|
||||
return arcs[s].key;
|
||||
} else
|
||||
assert(false);
|
||||
return NIL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef EXT_APPL_VD
|
||||
|
||||
|
||||
ean_type vroniObject::GetExtApplNode(int n)
|
||||
{
|
||||
assert(InNodesList(n));
|
||||
return nodes[n].ext_appl;
|
||||
}
|
||||
|
||||
void vroniObject::SetExtApplNode(int n, ean_type t)
|
||||
{
|
||||
assert(InNodesList(n));
|
||||
nodes[n].ext_appl = t;
|
||||
}
|
||||
|
||||
|
||||
eae_type vroniObject::GetExtApplEdge(int e)
|
||||
{
|
||||
assert(InEdgesList(e));
|
||||
return edges[e].ext_appl;
|
||||
}
|
||||
|
||||
void vroniObject::SetExtApplEdge(int e, eae_type t)
|
||||
{
|
||||
assert(InEdgesList(e));
|
||||
edges[e].ext_appl = t;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef EXT_APPL_PNTS
|
||||
|
||||
eap_type vroniObject::GetExtApplPnt(int p)
|
||||
{
|
||||
assert(InPntsList(p));
|
||||
return pnts[p].ext_appl;
|
||||
}
|
||||
|
||||
void vroniObject::SetExtApplPnt(int p, eap_type t)
|
||||
{
|
||||
assert(InPntsList(p));
|
||||
pnts[p].ext_appl = t;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef EXT_APPL_SITES
|
||||
|
||||
eas_type vroniObject::GetExtApplSeg(int s)
|
||||
{
|
||||
assert(InSegsList(s));
|
||||
return segs[s].ext_appl;
|
||||
}
|
||||
|
||||
void vroniObject::SetExtApplSeg(int s, eas_type t)
|
||||
{
|
||||
assert(InSegsList(s));
|
||||
segs[s].ext_appl = t;
|
||||
}
|
||||
|
||||
eas_type vroniObject::GetExtApplArc(int s)
|
||||
{
|
||||
assert(InArcsList(s));
|
||||
return arcs[s].ext_appl;
|
||||
}
|
||||
|
||||
void vroniObject::SetExtApplArc(int s, eas_type t)
|
||||
{
|
||||
assert(InArcsList(s));
|
||||
arcs[s].ext_appl = t;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,342 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 2010-2023 M. Held, S. Huber */
|
||||
/* */
|
||||
/* 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: Stefan Huber, 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 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef VRONI_VDDATA_H
|
||||
#define VRONI_VDDATA_H
|
||||
|
||||
#ifndef DOUBLE_OVERRIDE
|
||||
#include <assert.h>
|
||||
#endif
|
||||
|
||||
#include "consts.h"
|
||||
#include "ext_appl_defs.h"
|
||||
#include "wmat.h"
|
||||
|
||||
|
||||
#if defined(OGL_GRAPHICS)
|
||||
#ifndef GRAPHICS
|
||||
#define GRAPHICS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Different types of input sites, Voronoi diagram objects, Delaunay
|
||||
* triangulation object, and offsetting object */
|
||||
typedef enum
|
||||
{
|
||||
/** Segment */
|
||||
SEG,
|
||||
/** Arc */
|
||||
ARC,
|
||||
/** Point */
|
||||
PNT,
|
||||
|
||||
/** Voronoi node */
|
||||
VDN,
|
||||
/** Voronoi edge */
|
||||
VDE,
|
||||
|
||||
/** Delaunay triangulation edge */
|
||||
DTE,
|
||||
|
||||
/** CCW offset arc */
|
||||
CCW,
|
||||
/** CW offset arc */
|
||||
CW,
|
||||
|
||||
UNKNOWN
|
||||
} t_site;
|
||||
|
||||
|
||||
|
||||
/** Status of voronoi node */
|
||||
typedef enum
|
||||
{
|
||||
/** not yet checked */
|
||||
UNCHECKED,
|
||||
/** keep this node */
|
||||
CHECKED,
|
||||
/** delete this node */
|
||||
DELETED,
|
||||
/** already visited, marked for deletion */
|
||||
VISITED,
|
||||
/** this is a dummy node */
|
||||
DUMMY,
|
||||
MISC
|
||||
} n_status;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Input vertex */
|
||||
struct pnt
|
||||
{
|
||||
/** Position of vertex */
|
||||
coord p;
|
||||
|
||||
/** An edge to the Voronoi cell of this point */
|
||||
int vd;
|
||||
/** A Voronoi node that concides with it */
|
||||
int node;
|
||||
|
||||
/** Already visited */
|
||||
vr_bool vis;
|
||||
/** Segment/arc that is incident has already been inserted. */
|
||||
vr_bool s;
|
||||
|
||||
/** Will be deleted during next restart */
|
||||
vr_bool del;
|
||||
|
||||
#ifdef WRITE_VD
|
||||
int vd_edge;
|
||||
int idx;
|
||||
#endif
|
||||
|
||||
#ifdef GRAPHICS
|
||||
/** We draw this point */
|
||||
vr_bool draw;
|
||||
#endif
|
||||
|
||||
#ifdef ORDERED
|
||||
/** number assinged in increasing order for every pnt */
|
||||
int key;
|
||||
#endif
|
||||
|
||||
#ifdef EXT_APPL_PNTS
|
||||
eap_type ext_appl;/* this field can be set by an application program to */
|
||||
/* refer to a user-defined entity. */
|
||||
#endif
|
||||
//Ensure construction doesn't implicitly initialize elements - done explicitly later anyway
|
||||
inline pnt() {}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/** Input segment */
|
||||
struct seg
|
||||
{
|
||||
/** Start point */
|
||||
int i1;
|
||||
/** End point */
|
||||
int i2;
|
||||
|
||||
/** parameter in a*x + b*x + c = 0 */
|
||||
double a;
|
||||
/** parameter in a*x + b*x + c = 0 */
|
||||
double b;
|
||||
/** parameter in a*x + b*x + c = 0 */
|
||||
double c;
|
||||
|
||||
/** length of line segment */
|
||||
double lgth;
|
||||
|
||||
/** an edge of the Voroni cell of this seg*/
|
||||
int vd;
|
||||
|
||||
#ifdef WRITE_VD
|
||||
int vd_edge;
|
||||
#endif
|
||||
|
||||
#ifdef GRAPHICS
|
||||
/** We draw this point */
|
||||
vr_bool draw;
|
||||
#endif
|
||||
|
||||
#ifdef ORDERED
|
||||
/** number assigned in increasing order for every pnt */
|
||||
int key;
|
||||
#endif
|
||||
|
||||
#ifdef EXT_APPL_SITES
|
||||
eas_type ext_appl;/* this field can be set by an application program to */
|
||||
/* refer to a user-defined entity. */
|
||||
#endif
|
||||
//Ensure construction doesn't implicitly initialize elements - done explicitly later anyway
|
||||
inline seg() {}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/** Input arc */
|
||||
struct arc
|
||||
{
|
||||
/** start point */
|
||||
int i1;
|
||||
/** end point */
|
||||
int i2;
|
||||
|
||||
/** center point */
|
||||
coord c;
|
||||
/** radius */
|
||||
double r;
|
||||
/** orientation */
|
||||
vr_bool ccw;
|
||||
|
||||
/** unit normal vector at start point point outwards */
|
||||
coord ns;
|
||||
/** unit normal vector at end point point outwards */
|
||||
coord ne;
|
||||
|
||||
/** parameter of chord line equation a*x + b*y + d = 0 */
|
||||
double a;
|
||||
/** parameter of chord line equation a*x + b*y + d = 0 */
|
||||
double b;
|
||||
/** parameter of chord line equation a*x + b*y + d = 0 */
|
||||
double d;
|
||||
|
||||
/** an edge of the voronoi cell of this arc */
|
||||
int vd;
|
||||
|
||||
#ifdef GRAPHICS
|
||||
/** We draw this point */
|
||||
vr_bool draw;
|
||||
#endif
|
||||
|
||||
#ifdef ORDERED
|
||||
/** number assigned in increasing order for every pnt */
|
||||
int key;
|
||||
#endif
|
||||
|
||||
#ifdef EXT_APPL_SITES
|
||||
eas_type ext_appl;/* this field can be set by an application program to */
|
||||
/* refer to a user-defined entity. */
|
||||
#endif
|
||||
//Ensure construction doesn't implicitly initialize elements - done explicitly later anyway
|
||||
inline arc() {}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Voronoi node */
|
||||
struct node
|
||||
{
|
||||
/** Position */
|
||||
coord p;
|
||||
/** Clearance.
|
||||
* Attention: During pnt-VD generation this is the squared clearance!!! */
|
||||
double r2;
|
||||
/** A degree-two node */
|
||||
vr_bool deg2;
|
||||
|
||||
/** Current status of node */
|
||||
n_status status;
|
||||
|
||||
/** an incident edge */
|
||||
int edge;
|
||||
/** an input point, if node coincides with some. NIL otherwise. */
|
||||
int site;
|
||||
|
||||
#ifdef WRITE_VD
|
||||
int idx;
|
||||
#endif
|
||||
|
||||
#ifdef EXT_APPL_VD
|
||||
ean_type ext_appl;/* this field can be set by an application program to */
|
||||
/* refer to a user-defined entity. */
|
||||
#endif
|
||||
//Ensure construction doesn't implicitly initialize elements - done explicitly later anyway
|
||||
inline node() {}
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct edge {
|
||||
int n1; /* start node */
|
||||
int n2; /* end node */
|
||||
int lft; /* left defining site */
|
||||
int rgt; /* right defining site */
|
||||
t_site ltype; /* type of left defining site: PNT, SEG, or ARC */
|
||||
t_site rtype; /* type of right defining site: PNT, SEG, or ARC */
|
||||
int s_ccw; /* next edge in CCW order around start node */
|
||||
int s_cw; /* next edge in CW order around start node */
|
||||
int e_ccw; /* next edge in CCW order around end node */
|
||||
int e_cw; /* next edge in CW order around end node */
|
||||
vr_bool del; /* edge to be deleted during the incremental insertion? */
|
||||
#ifdef MAT
|
||||
w_mat_data w_mat; /* data for the (weighted) medial axis */
|
||||
#endif
|
||||
#ifdef EXT_APPL_VD
|
||||
eae_type ext_appl;/* this field can be set by an application program to */
|
||||
/* refer to a user-defined entity. */
|
||||
#endif
|
||||
//Ensure construction doesn't implicitly initialize elements - done explicitly later anyway
|
||||
inline edge() {}
|
||||
}; /********** Voronoi edge ******************************/
|
||||
|
||||
|
||||
typedef struct {
|
||||
vr_bool active; /* for repeated offsetting: true if the offset value is */
|
||||
/* less than the maximum of the clearances of the nodes */
|
||||
/* of this VD edge. */
|
||||
vr_bool e_new; /* true if no offset curve (at the current offset) has */
|
||||
/* already intersected this bisector. */
|
||||
vr_bool deg; /* true if the clearance of the start node of this edge */
|
||||
/* is identical to the clearance of the end node */
|
||||
} e_flag; /************* status flags for Voronoi edges ***********/
|
||||
|
||||
struct e_formula {
|
||||
vr_bool init; /* true if a parameterization of this bisectors has not */
|
||||
/* yet been computed. */
|
||||
double A; /* coefficient of parameterization; see data_off.c */
|
||||
double B; /* coefficient of parameterization; see data_off.c */
|
||||
#ifdef GENUINE_ARCS
|
||||
double C; /* coefficient of parameterization; see data_off.c */
|
||||
double D; /* coefficient of parameterization; see data_off.c */
|
||||
#endif
|
||||
double d; /* coefficient of parameterization; see data_off.c */
|
||||
vr_bool k1; /* positive or negative sliding direction of site #1 */
|
||||
vr_bool k2; /* positive or negative sliding direction of site #2 */
|
||||
vr_bool sign; /* positive or negative sign in the parameterization? */
|
||||
//Ensure construction doesn't implicitly initialize elements - done explicitly later anyway
|
||||
inline e_formula() {}
|
||||
}; /******* parameterization data for Voronoi edges ********/
|
||||
|
||||
#ifdef ORDERED
|
||||
struct ordered_sites
|
||||
{
|
||||
int ind;
|
||||
int key;
|
||||
//Ensure construction doesn't implicitly initialize elements - done explicitly later anyway
|
||||
inline ordered_sites() {}
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef SORTED
|
||||
struct sorted_sites
|
||||
{
|
||||
int ind;
|
||||
double lgth;
|
||||
//Ensure construction doesn't implicitly initialize elements - done explicitly later anyway
|
||||
inline sorted_sites() {}
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* 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 */
|
||||
/* Date: Sep 23, 2001 */
|
||||
/* Modified: */
|
||||
/* */
|
||||
/* 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
#include <stack>
|
||||
|
||||
/* */
|
||||
/* get my header files */
|
||||
/* */
|
||||
#include "fpkernel.h"
|
||||
#include "vronivector.h"
|
||||
#include "vroni_object.h"
|
||||
#include "defs.h"
|
||||
#include "numerics.h"
|
||||
#include "util.h"
|
||||
|
||||
|
||||
|
||||
/* */
|
||||
/* we include the definitions of static data structures and the macros */
|
||||
/* associated */
|
||||
/* */
|
||||
#include "vd_data.cc"
|
||||
|
||||
|
||||
/* */
|
||||
/* we include the routines for InsertPntIntoVD(). */
|
||||
/* */
|
||||
#include "vd_pnt.cc"
|
||||
|
||||
|
||||
/* */
|
||||
/* we include the routines for InsertSegIntoVD(). */
|
||||
/* */
|
||||
#include "vd_seg.cc"
|
||||
|
||||
|
||||
#ifdef GENUINE_ARCS
|
||||
/* */
|
||||
/* we include the routines for InsertArcIntoVD(). */
|
||||
/* */
|
||||
#include "vd_arc.cc"
|
||||
#endif
|
||||
@@ -0,0 +1,31 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.7.34024.191
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vroni", "vroni.vcxproj", "{A09C108A-4C53-4851-BAE7-484DC4929EE8}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{A09C108A-4C53-4851-BAE7-484DC4929EE8}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{A09C108A-4C53-4851-BAE7-484DC4929EE8}.Debug|x64.Build.0 = Debug|x64
|
||||
{A09C108A-4C53-4851-BAE7-484DC4929EE8}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{A09C108A-4C53-4851-BAE7-484DC4929EE8}.Debug|x86.Build.0 = Debug|Win32
|
||||
{A09C108A-4C53-4851-BAE7-484DC4929EE8}.Release|x64.ActiveCfg = Release|x64
|
||||
{A09C108A-4C53-4851-BAE7-484DC4929EE8}.Release|x64.Build.0 = Release|x64
|
||||
{A09C108A-4C53-4851-BAE7-484DC4929EE8}.Release|x86.ActiveCfg = Release|Win32
|
||||
{A09C108A-4C53-4851-BAE7-484DC4929EE8}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {3396164E-DF8F-47B9-AD40-709FB3B2ABE5}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
+269
@@ -0,0 +1,269 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>17.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{a09c108a-4c53-4851-bae7-484dc4929ee8}</ProjectGuid>
|
||||
<RootNamespace>vroni</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.20348.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v141_xp</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v141_xp</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>ClangCL</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>ClangCL</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<TargetName>$(ProjectName)D$(PlatformArchitecture)</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<TargetName>$(ProjectName)D$(PlatformArchitecture)</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<TargetName>$(ProjectName)R$(PlatformArchitecture)</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<TargetName>$(ProjectName)R$(PlatformArchitecture)</TargetName>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS;NO_CPUTIME;HAVE_BOOL;MAT;MIC;GENUINE_ARCS;VRONI_INFO;RANDOM;RAND</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>copy $(TargetDir)$(TargetName).lib \EgtDev\Extern\vroni\Lib\</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS;NO_CPUTIME;HAVE_BOOL;MAT;MIC;GENUINE_ARCS;VRONI_INFO;RANDOM;RAND</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<WholeProgramOptimization>false</WholeProgramOptimization>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
|
||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||
<OmitFramePointers>true</OmitFramePointers>
|
||||
<EnableFiberSafeOptimizations>true</EnableFiberSafeOptimizations>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>copy $(TargetDir)$(TargetName).lib \EgtDev\Extern\vroni\Lib\</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_LIB;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS;NO_CPUTIME;HAVE_BOOL;MAT;MIC;GENUINE_ARCS;VRONI_INFO;RANDOM;RAND;_CRT_SECURE_NO_WARNINGS;NO_CPUTIME;HAVE_BOOL;MAT;MIC;GENUINE_ARCS;VRONI_INFO;RANDOM;RAND</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>copy $(TargetDir)$(TargetName).lib \EgtDev\Extern\vroni\Lib\</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_LIB;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS;NO_CPUTIME;HAVE_BOOL;MAT;MIC;GENUINE_ARCS;VRONI_INFO;RANDOM;RAND;_CRT_SECURE_NO_WARNINGS;NO_CPUTIME;HAVE_BOOL;MAT;MIC;GENUINE_ARCS;VRONI_INFO;RANDOM;RAND</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<LanguageStandard>stdcpp17</LanguageStandard>
|
||||
<DebugInformationFormat>None</DebugInformationFormat>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
|
||||
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
|
||||
<OmitFramePointers>true</OmitFramePointers>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>copy $(TargetDir)$(TargetName).lib \EgtDev\Extern\vroni\Lib\</Command>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="approx.h" />
|
||||
<ClInclude Include="arc_common.h" />
|
||||
<ClInclude Include="basic.h" />
|
||||
<ClInclude Include="consts.h" />
|
||||
<ClInclude Include="coord.h" />
|
||||
<ClInclude Include="coreatan2.h" />
|
||||
<ClInclude Include="defs.h" />
|
||||
<ClInclude Include="dvi_graphics_header.h" />
|
||||
<ClInclude Include="elapsed.h" />
|
||||
<ClInclude Include="ext_appl_defs.h" />
|
||||
<ClInclude Include="ext_appl_inout.h" />
|
||||
<ClInclude Include="ext_appl_vroni_object.h" />
|
||||
<ClInclude Include="fpkernel.h" />
|
||||
<ClInclude Include="geom.h" />
|
||||
<ClInclude Include="header.h" />
|
||||
<ClInclude Include="intersections.h" />
|
||||
<ClInclude Include="io_dxf.h" />
|
||||
<ClInclude Include="ipe_io.h" />
|
||||
<ClInclude Include="numerics.h" />
|
||||
<ClInclude Include="offset.h" />
|
||||
<ClInclude Include="random.h" />
|
||||
<ClInclude Include="roots.h" />
|
||||
<ClInclude Include="stack.h" />
|
||||
<ClInclude Include="types.h" />
|
||||
<ClInclude Include="util.h" />
|
||||
<ClInclude Include="vddata.h" />
|
||||
<ClInclude Include="vd_data.h" />
|
||||
<ClInclude Include="vronivector.h" />
|
||||
<ClInclude Include="vroni_object.h" />
|
||||
<ClInclude Include="wmat.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="api_functions.cc" />
|
||||
<ClCompile Include="approx.cc" />
|
||||
<ClCompile Include="arc_arc_arc.cc" />
|
||||
<ClCompile Include="arc_arc_pnt.cc" />
|
||||
<ClCompile Include="arc_arc_seg.cc" />
|
||||
<ClCompile Include="arc_common.cc" />
|
||||
<ClCompile Include="arc_pnt_pnt.cc" />
|
||||
<ClCompile Include="arc_seg_pnt.cc" />
|
||||
<ClCompile Include="arc_seg_seg.cc" />
|
||||
<ClCompile Include="arg_eval.cc" />
|
||||
<ClCompile Include="clean_data.cc" />
|
||||
<ClCompile Include="compute.cc" />
|
||||
<ClCompile Include="coord.cc" />
|
||||
<ClCompile Include="data.cc" />
|
||||
<ClCompile Include="data_off.cc" />
|
||||
<ClCompile Include="desperate.cc" />
|
||||
<ClCompile Include="driver.cc" />
|
||||
<ClCompile Include="elapsed.cc" />
|
||||
<ClCompile Include="ext_appl_arg_eval.cc" />
|
||||
<ClCompile Include="ext_appl_data.cc" />
|
||||
<ClCompile Include="ext_appl_data_off.cc" />
|
||||
<ClCompile Include="ext_appl_defs.cc" />
|
||||
<ClCompile Include="ext_appl_io.cc" />
|
||||
<ClCompile Include="ext_appl_mic.cc" />
|
||||
<ClCompile Include="ext_appl_offset.cc" />
|
||||
<ClCompile Include="ext_appl_redraw.cc" />
|
||||
<ClCompile Include="ext_appl_vd.cc" />
|
||||
<ClCompile Include="ext_appl_vroni_object.cc" />
|
||||
<ClCompile Include="ext_appl_wmat.cc" />
|
||||
<ClCompile Include="geom.cc" />
|
||||
<ClCompile Include="graphics_ogl.cc" />
|
||||
<ClCompile Include="grid.cc" />
|
||||
<ClCompile Include="heap.cc" />
|
||||
<ClCompile Include="intersections.cc" />
|
||||
<ClCompile Include="io_basic.cc" />
|
||||
<ClCompile Include="io_debug.cc" />
|
||||
<ClCompile Include="io_dxf.cc" />
|
||||
<ClCompile Include="io_help.cc" />
|
||||
<ClCompile Include="io_misc.cc" />
|
||||
<ClCompile Include="io_other.cc" />
|
||||
<ClCompile Include="io_parse.cc" />
|
||||
<ClCompile Include="io_vddt.cc" />
|
||||
<ClCompile Include="ipe_io.cc" />
|
||||
<ClCompile Include="memory.cc" />
|
||||
<ClCompile Include="mic.cc" />
|
||||
<ClCompile Include="misc.cc" />
|
||||
<ClCompile Include="numerics.cc" />
|
||||
<ClCompile Include="offset.cc" />
|
||||
<ClCompile Include="pnt_pnt_pnt.cc" />
|
||||
<ClCompile Include="prepro.cc" />
|
||||
<ClCompile Include="redraw.cc" />
|
||||
<ClCompile Include="seg_pnt_pnt.cc" />
|
||||
<ClCompile Include="seg_seg_pnt.cc" />
|
||||
<ClCompile Include="seg_seg_seg.cc" />
|
||||
<ClCompile Include="tree.cc" />
|
||||
<ClCompile Include="vddata.cc" />
|
||||
<ClCompile Include="vd_arc.cc" />
|
||||
<ClCompile Include="vd_basic.cc" />
|
||||
<ClCompile Include="vd_data.cc" />
|
||||
<ClCompile Include="vd_pnt.cc" />
|
||||
<ClCompile Include="vd_seg.cc" />
|
||||
<ClCompile Include="voronoi.cc" />
|
||||
<ClCompile Include="vroni_object.cc" />
|
||||
<ClCompile Include="wmat.cc" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,303 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="File di origine">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="File di intestazione">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="File di risorse">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="approx.h">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="arc_common.h">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="basic.h">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="consts.h">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="coord.h">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="coreatan2.h">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="defs.h">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="dvi_graphics_header.h">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="elapsed.h">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ext_appl_defs.h">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ext_appl_inout.h">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ext_appl_vroni_object.h">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="fpkernel.h">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="geom.h">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="header.h">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="intersections.h">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="io_dxf.h">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ipe_io.h">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="numerics.h">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="offset.h">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="random.h">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="roots.h">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="stack.h">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="types.h">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="util.h">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="vd_data.h">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="vddata.h">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="vroni_object.h">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="vronivector.h">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="wmat.h">
|
||||
<Filter>File di intestazione</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="api_functions.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="approx.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="arc_arc_arc.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="arc_arc_pnt.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="arc_arc_seg.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="arc_common.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="arc_pnt_pnt.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="arc_seg_pnt.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="arc_seg_seg.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="arg_eval.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="clean_data.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="compute.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="coord.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="data.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="data_off.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="desperate.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="driver.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="elapsed.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ext_appl_arg_eval.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ext_appl_data.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ext_appl_data_off.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ext_appl_defs.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ext_appl_io.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ext_appl_mic.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ext_appl_offset.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ext_appl_redraw.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ext_appl_vd.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ext_appl_vroni_object.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ext_appl_wmat.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="geom.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="graphics_ogl.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="grid.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="heap.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="intersections.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="io_basic.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="io_debug.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="io_dxf.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="io_help.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="io_misc.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="io_other.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="io_parse.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="io_vddt.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ipe_io.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="memory.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="mic.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="misc.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="numerics.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="offset.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pnt_pnt_pnt.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="prepro.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="redraw.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="seg_pnt_pnt.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="seg_seg_pnt.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="seg_seg_seg.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="tree.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="vd_arc.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="vd_basic.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="vd_data.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="vd_pnt.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="vd_seg.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="vddata.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="voronoi.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="vroni_object.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="wmat.cc">
|
||||
<Filter>File di origine</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
+1198
File diff suppressed because it is too large
Load Diff
+3076
File diff suppressed because it is too large
Load Diff
+109
@@ -0,0 +1,109 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* Copyright (C) 1999-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 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef VRONI_VECTOR_H
|
||||
#define VRONI_VECTOR_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <new>
|
||||
#include <iostream>
|
||||
#include <exception>
|
||||
|
||||
template<typename T>
|
||||
class vronivector {
|
||||
|
||||
private:
|
||||
unsigned int arraysize;
|
||||
T * array;
|
||||
|
||||
public:
|
||||
inline vronivector() : arraysize(0), array(NULL) {}
|
||||
|
||||
inline ~vronivector() {
|
||||
free(array);
|
||||
}
|
||||
|
||||
T * begin() {
|
||||
return array;
|
||||
}
|
||||
|
||||
T * end() {
|
||||
return array + arraysize;
|
||||
}
|
||||
|
||||
unsigned int size() {
|
||||
return arraysize;
|
||||
}
|
||||
|
||||
void inline reserve(unsigned int ) {}
|
||||
|
||||
void resize(unsigned int newsize) {
|
||||
|
||||
/* */
|
||||
/* Call destructor of elements no longer needed if the size of the */
|
||||
/* array is reduced */
|
||||
/* */
|
||||
for(unsigned int i = newsize; i < arraysize; ++i) {
|
||||
array[i].~T();
|
||||
}
|
||||
|
||||
// Reallocate
|
||||
T * newarray = (T*) realloc(array, newsize * sizeof(T));
|
||||
if (newarray == NULL) throw std::bad_alloc();
|
||||
|
||||
//Initialize new elements of array
|
||||
for(unsigned int i = arraysize; i < newsize; ++i) {
|
||||
new (&newarray[i]) T();
|
||||
}
|
||||
array = newarray;
|
||||
arraysize = newsize;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
free(array);
|
||||
array = NULL;
|
||||
arraysize = 0;
|
||||
}
|
||||
|
||||
|
||||
inline T & operator[](unsigned int ind) {
|
||||
return array[ind];
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <class vtype>
|
||||
inline void gentlyResizeSTLVector(vtype & v, unsigned int newsize,
|
||||
const char * vname) {
|
||||
try {
|
||||
v.reserve(newsize);
|
||||
v.resize(newsize);
|
||||
}
|
||||
catch (std::bad_alloc& c) {
|
||||
std::cerr << "\n" << "VRONI exception while trying to resize vector "
|
||||
<< vname << " (" << c.what() << ")" << std::endl;
|
||||
throw std::runtime_error("VRONI error: gentlyResizeSTLVector() - memory reallocation failed!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,150 @@
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* 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 */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifndef VRONI_WMAT_H
|
||||
#define VRONI_WMAT_H
|
||||
|
||||
#include "types.h"
|
||||
|
||||
|
||||
#ifdef WMAT
|
||||
#ifndef MAT
|
||||
#define MAT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef MAT
|
||||
|
||||
|
||||
typedef struct {
|
||||
vr_bool in_w_mat; /* true if a portion of this VD edge belongs also to */
|
||||
/* WMAT or MAT */
|
||||
#ifdef WMAT
|
||||
double r_min; /* minimum contour clearance of this edge */
|
||||
double r_max; /* maximum contour clearance of this edge */
|
||||
coord lft_mn_pnt; /* left contact point for disk with radius r_min */
|
||||
coord lft_mx_pnt; /* left contact point for disk with radius r_max */
|
||||
coord rgt_mn_pnt; /* right contact point for disk with radius r_min */
|
||||
coord rgt_mx_pnt; /* right contact point for disk with radius r_max */
|
||||
#endif
|
||||
#ifdef EXT_APPL_WMAT
|
||||
eam_type ext_appl;/* this field can be set by an application program to */
|
||||
/* refer to a user-defined entity. */
|
||||
#endif
|
||||
} w_mat_data; /*********** (weighted) medial axis *********************/
|
||||
|
||||
|
||||
|
||||
#define IsWmatEdge(E) \
|
||||
(\
|
||||
assert(InEdgesList(E)), \
|
||||
(edges[E].w_mat.in_w_mat))
|
||||
|
||||
|
||||
#define SetWmatEdge(E, B) \
|
||||
{\
|
||||
assert(InEdgesList(E)); \
|
||||
edges[E].w_mat.in_w_mat = B; \
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef WMAT
|
||||
#define GetWmatRMin(E) \
|
||||
(\
|
||||
assert(InEdgesList(E)), \
|
||||
(edges[E].w_mat.r_min))
|
||||
|
||||
|
||||
#define SetWmatRMin(E, R) \
|
||||
{\
|
||||
assert(InEdgesList(E)); \
|
||||
edges[E].w_mat.r_min = R; \
|
||||
}
|
||||
|
||||
|
||||
#define GetWmatRMax(E) \
|
||||
(\
|
||||
assert(InEdgesList(E)), \
|
||||
(edges[E].w_mat.r_max))
|
||||
|
||||
|
||||
#define SetWmatRMax(E, R) \
|
||||
{\
|
||||
assert(InEdgesList(E)); \
|
||||
edges[E].w_mat.r_max = R; \
|
||||
}
|
||||
|
||||
|
||||
#define GetWmatLftMnPnt(E) \
|
||||
(\
|
||||
assert(InEdgesList(E)), \
|
||||
(edges[E].w_mat.lft_mn_pnt))
|
||||
|
||||
|
||||
#define SetWmatLftMnPnt(E, P) \
|
||||
{\
|
||||
assert(InEdgesList(E)); \
|
||||
edges[E].w_mat.lft_mn_pnt = P; \
|
||||
}
|
||||
|
||||
|
||||
#define GetWmatRgtMnPnt(E) \
|
||||
(\
|
||||
assert(InEdgesList(E)), \
|
||||
(edges[E].w_mat.rgt_mn_pnt))
|
||||
|
||||
|
||||
#define SetWmatRgtMnPnt(E, P) \
|
||||
{\
|
||||
assert(InEdgesList(E)); \
|
||||
edges[E].w_mat.rgt_mn_pnt = P; \
|
||||
}
|
||||
|
||||
|
||||
#define GetWmatLftMxPnt(E) \
|
||||
(\
|
||||
assert(InEdgesList(E)), \
|
||||
(edges[E].w_mat.lft_mx_pnt))
|
||||
|
||||
|
||||
#define SetWmatLftMxPnt(E, P) \
|
||||
{\
|
||||
assert(InEdgesList(E)); \
|
||||
edges[E].w_mat.lft_mx_pnt = P; \
|
||||
}
|
||||
|
||||
|
||||
#define GetWmatRgtMxPnt(E) \
|
||||
(\
|
||||
assert(InEdgesList(E)), \
|
||||
(edges[E].w_mat.rgt_mx_pnt))
|
||||
|
||||
|
||||
#define SetWmatRgtMxPnt(E, P) \
|
||||
{\
|
||||
assert(InEdgesList(E)); \
|
||||
edges[E].w_mat.rgt_mx_pnt = P; \
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
Reference in New Issue
Block a user