00001 // Voro++, a 3D cell-based Voronoi library 00002 // 00003 // Author : Chris H. Rycroft (LBL / UC Berkeley) 00004 // Email : chr@alum.mit.edu 00005 // Date : July 1st 2008 00006 00007 /** \file cell.hh 00008 * \brief Header file for the voronoicell_base template and related classes. */ 00009 00010 #ifndef VOROPP_CELL_HH 00011 #define VOROPP_CELL_HH 00012 00013 #include "config.hh" 00014 #include <cstdlib> 00015 #include <iostream> 00016 #include <fstream> 00017 #include <cmath> 00018 using namespace std; 00019 00020 /** \brief Function for printing fatal error messages and exiting. 00021 * 00022 * Function for printing fatal error messages and exiting. */ 00023 void voropp_fatal_error(const char *p,int status) { 00024 cerr << "voro++: " << p << endl; 00025 exit(status); 00026 } 00027 00028 /** \brief A class to reliably carry out floating point comparisons, storing 00029 * marginal cases for future reference. 00030 * 00031 * Floating point comparisons can be unreliable on some processor 00032 * architectures, and can produce unpredictable results. On a number of popular 00033 * Intel processors, floating point numbers are held to higher precision when 00034 * in registers than when in memory. When a register is swapped from a register 00035 * to memory, a truncation error, and in some situations this can create 00036 * circumstances where for two numbers c and d, the program finds c>d first, 00037 * but later c<d. The programmer has no control over when the swaps between 00038 * memory and registers occur, and recompiling with slightly different code can 00039 * give different results. One solution to avoid this is to force the compiler 00040 * to evaluate everything in memory (e.g. by using the -ffloat-store option in 00041 * the GNU C++ compiler) but this could be viewed overkill, since it slows the 00042 * code down, and the extra register precision is useful. 00043 * 00044 * In the plane cutting routine of the voronoicell class, we need to reliably 00045 * know whether a vertex lies inside, outside, or on the cutting plane, since 00046 * if it changed during the tracing process there would be confusion. This 00047 * class makes these tests reliable, by storing the results of marginal cases, 00048 * where the vertex lies within tolerance2 of the cutting plane. If that vertex 00049 * is tested again, then code looks up the value of the table in a buffer, 00050 * rather than doing the floating point comparison again. Only vertices which 00051 * are close to the plane are stored and tested, so this routine should create 00052 * minimal computational overhead. 00053 */ 00054 class suretest { 00055 public: 00056 /** This is a pointer to the array in the voronoicell class 00057 * which holds the vertex coordinates.*/ 00058 fpoint *p; 00059 suretest(); 00060 ~suretest(); 00061 inline void init(fpoint x,fpoint y,fpoint z,fpoint rsq); 00062 inline int test(int n,fpoint &ans); 00063 private: 00064 int check_marginal(int n,fpoint &ans); 00065 /** This stores the current memory allocation for the marginal 00066 * cases. */ 00067 int current_marginal; 00068 /** This stores the total number of marginal points which are 00069 * currently in the buffer. */ 00070 int sc; 00071 /** This array contains a list of the marginal points, and also 00072 * the outcomes of the marginal tests. */ 00073 int *sn; 00074 /** The x coordinate of the normal vector to the test plane. */ 00075 fpoint px; 00076 /** The y coordinate of the normal vector to the test plane. */ 00077 fpoint py; 00078 /** The z coordinate of the normal vector to the test plane. */ 00079 fpoint pz; 00080 /** The magnitude of the normal vector to the test plane. */ 00081 fpoint prsq; 00082 }; 00083 00084 class neighbor_track; 00085 00086 /** \brief A class encapsulating all the routines for storing and calculating 00087 * a single Voronoi cell. 00088 * 00089 * This class encapsulates all the routines for storing and calculating a 00090 * single Voronoi cell. The cell can first be initialized by the init() function 00091 * to be a rectangular box. The box can then be successively cut by planes 00092 * using the plane function. Other routines exist for outputting the cell, 00093 * computing its volume, or finding the largest distance of a vertex from the 00094 * cell center. The cell is described by two arrays. pts[] is a floating point 00095 * array which holds the vertex positions. ed[] holds the table of edges, and 00096 * also a relation table that determines how two vertices are connected to one 00097 * another. The relation table is redundant, but helps speed up the 00098 * computation. The function check_relations() checks that the relational table 00099 * is valid. */ 00100 template <class n_option> 00101 class voronoicell_base { 00102 public: 00103 /** This is a two dimensional array that holds information about 00104 * the edge connections of the vertices that make up the cell. 00105 * The two dimensional array is not allocated in the usual method. 00106 * To account for the fact the different vertices have different 00107 * orders, and thus require different amounts of storage, the 00108 * elements of ed[i] point to one-dimensional arrays in the mep[] 00109 * array of different sizes. 00110 * 00111 * More specifically, if vertex i has order m, then ed[i] 00112 * points to a one-dimensional array in mep[m] that has 2*m+1 00113 * entries. The first m elements hold the neighboring edges, so 00114 * that the jth edge of vertex i is held in ed[i][j]. The next 00115 * m elements hold a table of relations which is redundant but 00116 * helps speed up the computation. It satisfies the relation 00117 * ed[ed[i][j]][ed[i][m+j]]=i. The final entry holds a back 00118 * pointer, so that ed[i+2*m]=i. These are used when 00119 * rearranging the memory. */ 00120 int **ed; 00121 /** This array holds the order of the vertices in the Voronoi cell. 00122 * This array is dynamically allocated, with its current size 00123 * held by current_vertices. */ 00124 int *nu; 00125 /** This holds the current size of the arrays ed and nu, which 00126 * hold the vertex information. If more vertices are created 00127 * than can fit in this array, then it is dynamically extended 00128 * using the add_memory_vertices routine. */ 00129 int current_vertices; 00130 /** This holds the current maximum allowed order of a vertex, 00131 * which sets the size of the mem, mep, and mec arrays. If a 00132 * vertex is created with more vertices than this, the arrays 00133 * are dynamically extended using the add_memory_vorder routine. 00134 */ 00135 int current_vertex_order; 00136 /** This sets the size of the main delete stack. */ 00137 int current_delete_size; 00138 /** This sets the size of the auxiliary delete stack. */ 00139 int current_delete2_size; 00140 /** This in an array with size 3*current_vertices for holding 00141 * the positions of the vertices. */ 00142 fpoint *pts; 00143 /** This sets the total number of vertices in the current cell. 00144 */ 00145 int p; 00146 /** This is the index of particular point in the cell, which is used to start 00147 * the tracing routines for plane intersection and cutting. These 00148 * routines will work starting from any point, but it's often most 00149 * efficient to start from the last point considered, since in many cases, 00150 * the cell construction algorithm may consider many planes with similar 00151 * vectors concurrently. */ 00152 int up; 00153 /** This is a class used in the plane routine for carrying out 00154 * reliable comparisons of whether points in the cell are 00155 * inside, outside, or on the current cutting plane. */ 00156 suretest sure; 00157 voronoicell_base(); 00158 ~voronoicell_base(); 00159 void init(fpoint xmin,fpoint xmax,fpoint ymin,fpoint ymax,fpoint zmin,fpoint zmax); 00160 inline void init_octahedron(fpoint l); 00161 inline void init_tetrahedron(fpoint x0,fpoint y0,fpoint z0,fpoint x1,fpoint y1,fpoint z1,fpoint x2,fpoint y2,fpoint z2,fpoint x3,fpoint y3,fpoint z3); 00162 void draw_pov(ostream &os,fpoint x,fpoint y,fpoint z); 00163 inline void draw_pov(const char *filename,fpoint x,fpoint y,fpoint z); 00164 inline void draw_pov(fpoint x,fpoint y,fpoint z); 00165 void draw_pov_mesh(ostream &os,fpoint x,fpoint y,fpoint z); 00166 inline void draw_pov_mesh(const char *filename,fpoint x,fpoint y,fpoint z); 00167 inline void draw_pov_mesh(fpoint x,fpoint y,fpoint z); 00168 void draw_gnuplot(ostream &os,fpoint x,fpoint y,fpoint z); 00169 inline void draw_gnuplot(const char *filename,fpoint x,fpoint y,fpoint z); 00170 inline void draw_gnuplot(fpoint x,fpoint y,fpoint z); 00171 fpoint volume(); 00172 fpoint max_radius_squared(); 00173 fpoint total_edge_distance(); 00174 fpoint surface_area(); 00175 void centroid(fpoint &cx,fpoint &cy,fpoint &cz); 00176 int number_of_faces(); 00177 int number_of_edges(); 00178 void output_vertex_orders(ostream &os); 00179 void output_vertices(ostream &os); 00180 void output_vertices(ostream &os,fpoint x,fpoint y,fpoint z); 00181 void output_face_areas(ostream &os); 00182 void output_face_orders(ostream &os); 00183 void output_face_freq_table(ostream &os); 00184 void output_face_vertices(ostream &os); 00185 void output_face_perimeters(ostream &os); 00186 void output_normals(ostream &os); 00187 void output_neighbors(ostream &os,bool later=false); 00188 bool nplane(fpoint x,fpoint y,fpoint z,fpoint rs,int p_id); 00189 inline bool nplane(fpoint x,fpoint y,fpoint z,int p_id); 00190 inline bool plane(fpoint x,fpoint y,fpoint z,fpoint rs); 00191 inline bool plane(fpoint x,fpoint y,fpoint z); 00192 bool plane_intersects(fpoint x,fpoint y,fpoint z,fpoint rs); 00193 bool plane_intersects_guess(fpoint x,fpoint y,fpoint z,fpoint rs); 00194 inline void init_test(int n); 00195 void add_vertex(fpoint x,fpoint y,fpoint z,int a); 00196 void add_vertex(fpoint x,fpoint y,fpoint z,int a,int b); 00197 void add_vertex(fpoint x,fpoint y,fpoint z,int a,int b,int c); 00198 void add_vertex(fpoint x,fpoint y,fpoint z,int a,int b,int c,int d); 00199 void add_vertex(fpoint x,fpoint y,fpoint z,int a,int b,int c,int d,int e); 00200 void construct_relations(); 00201 void check_relations(); 00202 void check_duplicates(); 00203 void print_edges(); 00204 void label_facets(); 00205 void check_facets(); 00206 inline void perturb(fpoint r); 00207 private: 00208 /** This a one dimensional array that holds the current sizes 00209 * of the memory allocations for them mep array.*/ 00210 int *mem; 00211 /** This is a two dimensional array for holding the information 00212 * about the edges of the Voronoi cell. mep[p] is a 00213 * one-dimensional array for holding the edge information about 00214 * all vertices of order p, with each vertex holding 2*p+1 00215 * integers of information. The total number of vertices held 00216 * on mep[p] is stored in mem[p]. If the space runs out, the 00217 * code allocates more using the add_memory() routine. */ 00218 int **mep; 00219 /** This is a one dimensional array that holds the current 00220 * number of vertices of order p that are stored in the mep[p] 00221 * array. */ 00222 int *mec; 00223 /** This is the delete stack, used to store the vertices which 00224 * are going to be deleted during the plane cutting procedure. 00225 */ 00226 int *ds; 00227 /** This is the auxiliary delete stack, which has size set by 00228 * current_delete2_size. */ 00229 int *ds2; 00230 /** This holds the number of points currently on the auxiliary 00231 * delete stack. */ 00232 int stack2; 00233 /** This object contains all the functions required to carry 00234 * out the neighbor computation. If the neighbor_none class is 00235 * used for n_option, then all these functions are blank. If 00236 * the neighbor_track class is used, then the neighbor tracking 00237 * is enabled. All the functions for the n_option classes are 00238 * declared inline, so that they should all be completely 00239 * integrated into the routine during compilation. */ 00240 n_option neighbor; 00241 inline int cycle_up(int a,int p); 00242 inline int cycle_down(int a,int p); 00243 void add_memory(int i); 00244 void add_memory_vertices(); 00245 void add_memory_vorder(); 00246 void add_memory_ds(); 00247 void add_memory_ds2(); 00248 inline bool collapse_order1(); 00249 inline bool collapse_order2(); 00250 inline bool delete_connection(int j,int k,bool hand); 00251 inline bool plane_intersects_track(fpoint x,fpoint y,fpoint z,fpoint rs,fpoint g); 00252 inline void reset_edges(); 00253 inline void output_normals_search(ostream &os,int i,int j,int k); 00254 friend class neighbor_track; 00255 }; 00256 00257 /** \brief A class passed to the voronoicell_base template to switch off 00258 * neighbor computation. 00259 * 00260 * This is a class full of empty routines for neighbor computation. If the 00261 * voronoicell_base template is instantiated with this class, then it 00262 * has the effect of switching off all neighbor computation. Since all these 00263 * routines are declared inline, it should have the effect of a zero speed 00264 * overhead in the resulting code. */ 00265 class neighbor_none { 00266 public: 00267 /** This is a blank constructor. */ 00268 neighbor_none(voronoicell_base<neighbor_none> *ivc) {}; 00269 /** This is a blank placeholder function that does nothing. */ 00270 inline void allocate(int i,int m) {}; 00271 /** This is a blank placeholder function that does nothing. */ 00272 inline void add_memory_vertices(int i) {}; 00273 /** This is a blank placeholder function that does nothing. */ 00274 inline void add_memory_vorder(int i) {}; 00275 /** This is a blank placeholder function that does nothing. */ 00276 inline void init() {}; 00277 /** This is a blank placeholder function that does nothing. */ 00278 inline void init_octahedron() {}; 00279 /** This is a blank placeholder function that does nothing. */ 00280 inline void init_tetrahedron() {}; 00281 /** This is a blank placeholder function that does nothing. */ 00282 inline void set_pointer(int p,int n) {}; 00283 /** This is a blank placeholder function that does nothing. */ 00284 inline void copy(int a,int b,int c,int d) {}; 00285 /** This is a blank placeholder function that does nothing. */ 00286 inline void set(int a,int b,int c) {}; 00287 /** This is a blank placeholder function that does nothing. */ 00288 inline void set_aux1(int k) {}; 00289 /** This is a blank placeholder function that does nothing. */ 00290 inline void copy_aux1(int a,int b) {}; 00291 /** This is a blank placeholder function that does nothing. */ 00292 inline void copy_aux1_shift(int a,int b) {}; 00293 /** This is a blank placeholder function that does nothing. */ 00294 inline void set_aux2_copy(int a,int b) {}; 00295 /** This is a blank placeholder function that does nothing. */ 00296 inline void copy_pointer(int a,int b) {}; 00297 /** This is a blank placeholder function that does nothing. */ 00298 inline void set_to_aux1(int j) {}; 00299 /** This is a blank placeholder function that does nothing. */ 00300 inline void set_to_aux2(int j) {}; 00301 /** This is a blank placeholder function that does nothing. */ 00302 inline void print_edges(int i) {}; 00303 /** This is a blank placeholder function that does nothing. */ 00304 inline void allocate_aux1(int i) {}; 00305 /** This is a blank placeholder function that does nothing. */ 00306 inline void switch_to_aux1(int i) {}; 00307 /** This is a blank placeholder function that does nothing. */ 00308 inline void copy_to_aux1(int i,int m) {}; 00309 /** This is a blank placeholder function that does nothing. */ 00310 inline void set_to_aux1_offset(int k,int m) {}; 00311 /** This is a blank placeholder function that does nothing. */ 00312 inline void neighbors(ostream &os,bool later) {}; 00313 /** This is a blank placeholder function that does nothing. */ 00314 inline void label_facets() {}; 00315 /** This is a blank placeholder function that does nothing. */ 00316 inline void check_facets() {}; 00317 }; 00318 00319 /** \brief A class passed to the voronoicell_base template to switch on the 00320 * neighbor computation. 00321 * 00322 * This class encapsulates all the routines which are required to carry out the 00323 * neighbor tracking. If the voronoicell_base template is instantiated with 00324 * this class, then the neighbor computation is enabled. All these routines are 00325 * simple and declared inline, so they should be directly integrated into the 00326 * functions in the voronoicell class during compilation, without zero function 00327 * call overhead. */ 00328 class neighbor_track { 00329 public: 00330 /** This two dimensional array holds the neighbor information 00331 * associated with each vertex. mne[p] is a one dimensional 00332 * array which holds all of the neighbor information for 00333 * vertices of order p. */ 00334 int **mne; 00335 /** This is a two dimensional array that holds the neighbor 00336 * information associated with each vertex. ne[i] points to a 00337 * one-dimensional array in mne[nu[i]]. ne[i][j] holds the 00338 * neighbor information associated with the jth edge of vertex 00339 * i. It is set to the ID number of the plane that made the 00340 * face that is clockwise from the jth edge. */ 00341 int **ne; 00342 neighbor_track(voronoicell_base<neighbor_track> *ivc); 00343 ~neighbor_track(); 00344 /** This is a pointer back to the voronoicell class which 00345 * created this class. It is used to reference the members of 00346 * that class in computations. */ 00347 voronoicell_base<neighbor_track> *vc; 00348 inline void allocate(int i,int m); 00349 inline void add_memory_vertices(int i); 00350 inline void add_memory_vorder(int i); 00351 inline void init(); 00352 inline void init_octahedron(); 00353 inline void init_tetrahedron(); 00354 inline void set_pointer(int p,int n); 00355 inline void copy(int a,int b,int c,int d); 00356 inline void set(int a,int b,int c); 00357 inline void set_aux1(int k); 00358 inline void copy_aux1(int a,int b); 00359 inline void copy_aux1_shift(int a,int b); 00360 inline void set_aux2_copy(int a,int b); 00361 inline void copy_pointer(int a,int b); 00362 inline void set_to_aux1(int j); 00363 inline void set_to_aux2(int j); 00364 inline void print_edges(int i); 00365 inline void allocate_aux1(int i); 00366 inline void switch_to_aux1(int i); 00367 inline void copy_to_aux1(int i,int m); 00368 inline void set_to_aux1_offset(int k,int m); 00369 inline void neighbors(ostream &os,bool later); 00370 inline void label_facets(); 00371 inline void check_facets(); 00372 private: 00373 /** This is an auxiliary pointer which is used in some of the 00374 * low level neighbor operations. */ 00375 int *paux1; 00376 /** This is a second auxiliary pointer which is used in some 00377 * of the low level neighbor operations. */ 00378 int *paux2; 00379 }; 00380 00381 /** The basic voronoicell class. */ 00382 typedef voronoicell_base<neighbor_none> voronoicell; 00383 00384 /** A neighbor-tracking version of the voronoicell. */ 00385 typedef voronoicell_base<neighbor_track> voronoicell_neighbor; 00386 #endif