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