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