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 <cstdio> 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 inline void init_test(int n); 00163 inline void add_vertex(fpoint x,fpoint y,fpoint z,int a); 00164 inline void add_vertex(fpoint x,fpoint y,fpoint z,int a,int b); 00165 inline void add_vertex(fpoint x,fpoint y,fpoint z,int a,int b,int c); 00166 inline void add_vertex(fpoint x,fpoint y,fpoint z,int a,int b,int c,int d); 00167 inline void add_vertex(fpoint x,fpoint y,fpoint z,int a,int b,int c,int d,int e); 00168 void draw_pov(ostream &os,fpoint x,fpoint y,fpoint z); 00169 inline void draw_pov(const char *filename,fpoint x,fpoint y,fpoint z); 00170 inline void draw_pov(fpoint x,fpoint y,fpoint z); 00171 void draw_pov_mesh(ostream &os,fpoint x,fpoint y,fpoint z); 00172 inline void draw_pov_mesh(const char *filename,fpoint x,fpoint y,fpoint z); 00173 inline void draw_pov_mesh(fpoint x,fpoint y,fpoint z); 00174 void draw_gnuplot(ostream &os,fpoint x,fpoint y,fpoint z); 00175 inline void draw_gnuplot(const char *filename,fpoint x,fpoint y,fpoint z); 00176 inline void draw_gnuplot(fpoint x,fpoint y,fpoint z); 00177 inline void check_relations(); 00178 inline void check_duplicates(); 00179 inline void construct_relations(); 00180 fpoint volume(); 00181 fpoint maxradsq(); 00182 int number_of_faces(); 00183 void print_edges(); 00184 inline void perturb(fpoint r); 00185 void facets(ostream &os); 00186 inline void facets(); 00187 inline void facets(const char *filename); 00188 void facet_statistics(ostream &os); 00189 inline void facet_statistics(); 00190 inline void facet_statistics(const char *filename); 00191 bool nplane(fpoint x,fpoint y,fpoint z,fpoint rs,int p_id); 00192 inline bool nplane(fpoint x,fpoint y,fpoint z,int p_id); 00193 inline bool plane(fpoint x,fpoint y,fpoint z,fpoint rs); 00194 inline bool plane(fpoint x,fpoint y,fpoint z); 00195 bool plane_intersects(fpoint x,fpoint y,fpoint z,fpoint rs); 00196 bool plane_intersects_guess(fpoint x,fpoint y,fpoint z,fpoint rs); 00197 void label_facets(); 00198 void neighbors(ostream &os); 00199 void check_facets(); 00200 private: 00201 /** This a one dimensional array that holds the current sizes 00202 * of the memory allocations for them mep array.*/ 00203 int *mem; 00204 /** This is a two dimensional array for holding the information 00205 * about the edges of the Voronoi cell. mep[p] is a 00206 * one-dimensional array for holding the edge information about 00207 * all vertices of order p, with each vertex holding 2*p+1 00208 * integers of information. The total number of vertices held 00209 * on mep[p] is stored in mem[p]. If the space runs out, the 00210 * code allocates more using the add_memory() routine. */ 00211 int **mep; 00212 /** This is a one dimensional array that holds the current 00213 * number of vertices of order p that are stored in the mep[p] 00214 * array. */ 00215 int *mec; 00216 /** This is the delete stack, used to store the vertices which 00217 * are going to be deleted during the plane cutting procedure. 00218 */ 00219 int *ds; 00220 /** This is the auxiliary delete stack, which has size set by 00221 * current_delete2_size. */ 00222 int *ds2; 00223 /** This holds the number of points currently on the auxiliary 00224 * delete stack. */ 00225 int stack2; 00226 /** This object contains all the functions required to carry 00227 * out the neighbor computation. If the neighbor_none class is 00228 * used for n_option, then all these functions are blank. If 00229 * the neighbor_track class is used, then the neighbor tracking 00230 * is enabled. All the functions for the n_option classes are 00231 * declared inline, so that they should all be completely 00232 * integrated into the routine during compilation. */ 00233 n_option neighbor; 00234 inline int cycle_up(int a,int p); 00235 inline int cycle_down(int a,int p); 00236 void add_memory(int i); 00237 void add_memory_vertices(); 00238 void add_memory_vorder(); 00239 void add_memory_ds(); 00240 void add_memory_ds2(); 00241 inline bool collapse_order1(); 00242 inline bool collapse_order2(); 00243 inline bool delete_connection(int j,int k,bool hand); 00244 inline bool plane_intersects_track(fpoint x,fpoint y,fpoint z,fpoint rs,fpoint g); 00245 inline void reset_edges(); 00246 friend class neighbor_track; 00247 }; 00248 00249 /** \brief A class passed to the voronoicell_base template to switch off 00250 * neighbor computation. 00251 * 00252 * This is a class full of empty routines for neighbor computation. If the 00253 * voronoicell_base template is instantiated with this class, then it 00254 * has the effect of switching off all neighbor computation. Since all these 00255 * routines are declared inline, it should have the effect of a zero speed 00256 * overhead in the resulting code. */ 00257 class neighbor_none { 00258 public: 00259 /** This is a blank constructor. */ 00260 neighbor_none(voronoicell_base<neighbor_none> *ivc) {}; 00261 /** This is a blank placeholder function that does nothing. */ 00262 inline void allocate(int i,int m) {}; 00263 /** This is a blank placeholder function that does nothing. */ 00264 inline void add_memory_vertices(int i) {}; 00265 /** This is a blank placeholder function that does nothing. */ 00266 inline void add_memory_vorder(int i) {}; 00267 /** This is a blank placeholder function that does nothing. */ 00268 inline void init() {}; 00269 /** This is a blank placeholder function that does nothing. */ 00270 inline void init_octahedron() {}; 00271 /** This is a blank placeholder function that does nothing. */ 00272 inline void init_tetrahedron() {}; 00273 /** This is a blank placeholder function that does nothing. */ 00274 inline void set_pointer(int p,int n) {}; 00275 /** This is a blank placeholder function that does nothing. */ 00276 inline void copy(int a,int b,int c,int d) {}; 00277 /** This is a blank placeholder function that does nothing. */ 00278 inline void set(int a,int b,int c) {}; 00279 /** This is a blank placeholder function that does nothing. */ 00280 inline void set_aux1(int k) {}; 00281 /** This is a blank placeholder function that does nothing. */ 00282 inline void copy_aux1(int a,int b) {}; 00283 /** This is a blank placeholder function that does nothing. */ 00284 inline void copy_aux1_shift(int a,int b) {}; 00285 /** This is a blank placeholder function that does nothing. */ 00286 inline void set_aux2_copy(int a,int b) {}; 00287 /** This is a blank placeholder function that does nothing. */ 00288 inline void copy_pointer(int a,int b) {}; 00289 /** This is a blank placeholder function that does nothing. */ 00290 inline void set_to_aux1(int j) {}; 00291 /** This is a blank placeholder function that does nothing. */ 00292 inline void set_to_aux2(int j) {}; 00293 /** This is a blank placeholder function that does nothing. */ 00294 inline void print_edges(int i) {}; 00295 /** This is a blank placeholder function that does nothing. */ 00296 inline void allocate_aux1(int i) {}; 00297 /** This is a blank placeholder function that does nothing. */ 00298 inline void switch_to_aux1(int i) {}; 00299 /** This is a blank placeholder function that does nothing. */ 00300 inline void copy_to_aux1(int i,int m) {}; 00301 /** This is a blank placeholder function that does nothing. */ 00302 inline void set_to_aux1_offset(int k,int m) {}; 00303 /** This is a blank placeholder function that does nothing. */ 00304 inline void print(ostream &os,int i,int j); 00305 /** This is a blank placeholder function that does nothing. */ 00306 inline void label_facets() {}; 00307 /** This is a blank placeholder function that does nothing. */ 00308 inline void neighbors(ostream &os) {}; 00309 /** This is a blank placeholder function that does nothing. */ 00310 inline void check_facets() {}; 00311 }; 00312 00313 /** \brief A class passed to the voronoicell_base template to switch on the 00314 * neighbor computation. 00315 * 00316 * This class encapsulates all the routines which are required to carry out the 00317 * neighbor tracking. If the voronoicell_base template is instantiated with 00318 * this class, then the neighbor computation is enabled. All these routines are 00319 * simple and declared inline, so they should be directly integrated into the 00320 * functions in the voronoicell class during compilation, without zero function 00321 * call overhead. */ 00322 class neighbor_track { 00323 public: 00324 /** This two dimensional array holds the neighbor information 00325 * associated with each vertex. mne[p] is a one dimensional 00326 * array which holds all of the neighbor information for 00327 * vertices of order p. */ 00328 int **mne; 00329 /** This is a two dimensional array that holds the neighbor 00330 * information associated with each vertex. ne[i] points to a 00331 * one-dimensional array in mne[nu[i]]. ne[i][j] holds the 00332 * neighbor information associated with the jth edge of vertex 00333 * i. It is set to the ID number of the plane that made the 00334 * face that is clockwise from the jth edge. */ 00335 int **ne; 00336 neighbor_track(voronoicell_base<neighbor_track> *ivc); 00337 ~neighbor_track(); 00338 /** This is a pointer back to the voronoicell class which 00339 * created this class. It is used to reference the members of 00340 * that class in computations. */ 00341 voronoicell_base<neighbor_track> *vc; 00342 inline void allocate(int i,int m); 00343 inline void add_memory_vertices(int i); 00344 inline void add_memory_vorder(int i); 00345 inline void init(); 00346 inline void init_octahedron(); 00347 inline void init_tetrahedron(); 00348 inline void set_pointer(int p,int n); 00349 inline void copy(int a,int b,int c,int d); 00350 inline void set(int a,int b,int c); 00351 inline void set_aux1(int k); 00352 inline void copy_aux1(int a,int b); 00353 inline void copy_aux1_shift(int a,int b); 00354 inline void set_aux2_copy(int a,int b); 00355 inline void copy_pointer(int a,int b); 00356 inline void set_to_aux1(int j); 00357 inline void set_to_aux2(int j); 00358 inline void print_edges(int i); 00359 inline void allocate_aux1(int i); 00360 inline void switch_to_aux1(int i); 00361 inline void copy_to_aux1(int i,int m); 00362 inline void set_to_aux1_offset(int k,int m); 00363 inline void print(ostream &os,int i,int j); 00364 inline void label_facets(); 00365 inline void neighbors(ostream &os); 00366 inline void check_facets(); 00367 private: 00368 /** This is an auxiliary pointer which is used in some of the 00369 * low level neighbor operations. */ 00370 int *paux1; 00371 /** This is a second auxiliary pointer which is used in some 00372 * of the low level neighbor operations. */ 00373 int *paux2; 00374 }; 00375 00376 /** The basic voronoicell class. */ 00377 typedef voronoicell_base<neighbor_none> voronoicell; 00378 00379 /** A neighbor-tracking version of the voronoicell. */ 00380 typedef voronoicell_base<neighbor_track> voronoicell_neighbor; 00381 #endif