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