Voro++
|
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 : August 30th 2011 00006 00007 /** \file cell.cc 00008 * \brief Function implementations for the voronoicell and related classes. */ 00009 00010 #include <cstring> 00011 using namespace std; 00012 00013 #include "config.hh" 00014 #include "common.hh" 00015 #include "cell.hh" 00016 00017 namespace voro { 00018 00019 /** Constructs a Voronoi cell and sets up the initial memory. */ 00020 voronoicell_base::voronoicell_base() : 00021 current_vertices(init_vertices), current_vertex_order(init_vertex_order), 00022 current_delete_size(init_delete_size), current_delete2_size(init_delete2_size), 00023 ed(new int*[current_vertices]), nu(new int[current_vertices]), 00024 pts(new double[3*current_vertices]), mem(new int[current_vertex_order]), 00025 mec(new int[current_vertex_order]), mep(new int*[current_vertex_order]), 00026 ds(new int[current_delete_size]), stacke(ds+current_delete_size), 00027 ds2(new int[current_delete2_size]), stacke2(ds2+current_delete_size), 00028 current_marginal(init_marginal), marg(new int[current_marginal]) { 00029 int i; 00030 for(i=0;i<3;i++) { 00031 mem[i]=init_n_vertices;mec[i]=0; 00032 mep[i]=new int[init_n_vertices*((i<<1)+1)]; 00033 } 00034 mem[3]=init_3_vertices;mec[3]=0; 00035 mep[3]=new int[init_3_vertices*7]; 00036 for(i=4;i<current_vertex_order;i++) { 00037 mem[i]=init_n_vertices;mec[i]=0; 00038 mep[i]=new int[init_n_vertices*((i<<1)+1)]; 00039 } 00040 } 00041 00042 /** The voronoicell destructor deallocates all the dynamic memory. */ 00043 voronoicell_base::~voronoicell_base() { 00044 for(int i=current_vertex_order-1;i>=0;i--) if(mem[i]>0) delete [] mep[i]; 00045 delete [] marg; 00046 delete [] ds2;delete [] ds; 00047 delete [] mep;delete [] mec; 00048 delete [] mem;delete [] pts; 00049 delete [] nu;delete [] ed; 00050 } 00051 00052 /** Ensures that enough memory is allocated prior to carrying out a copy. 00053 * \param[in] vc a reference to the specialized version of the calling class. 00054 * \param[in] vb a pointered to the class to be copied. */ 00055 template<class vc_class> 00056 void voronoicell_base::check_memory_for_copy(vc_class &vc,voronoicell_base* vb) { 00057 while(current_vertex_order<vb->current_vertex_order) add_memory_vorder(vc); 00058 for(int i=0;i<current_vertex_order;i++) while(mem[i]<vb->mec[i]) add_memory(vc,i,ds2); 00059 while(current_vertices<vb->p) add_memory_vertices(vc); 00060 } 00061 00062 /** Copies the vertex and edge information from another class. The routine 00063 * assumes that enough memory is available for the copy. 00064 * \param[in] vb a pointer to the class to copy. */ 00065 void voronoicell_base::copy(voronoicell_base* vb) { 00066 int i,j; 00067 p=vb->p;up=0; 00068 for(i=0;i<current_vertex_order;i++) { 00069 mec[i]=vb->mec[i]; 00070 for(j=0;j<mec[i]*(2*i+1);j++) mep[i][j]=vb->mep[i][j]; 00071 for(j=0;j<mec[i]*(2*i+1);j+=2*i+1) ed[mep[i][j+2*i]]=mep[i]+j; 00072 } 00073 for(i=0;i<p;i++) nu[i]=vb->nu[i]; 00074 for(i=0;i<3*p;i++) pts[i]=vb->pts[i]; 00075 } 00076 00077 /** Copies the information from another voronoicell class into this 00078 * class, extending memory allocation if necessary. 00079 * \param[in] c the class to copy. */ 00080 void voronoicell_neighbor::operator=(voronoicell &c) { 00081 voronoicell_base *vb=((voronoicell_base*) &c); 00082 check_memory_for_copy(*this,vb);copy(vb); 00083 int i,j; 00084 for(i=0;i<c.current_vertex_order;i++) { 00085 for(j=0;j<c.mec[i]*i;j++) mne[i][j]=0; 00086 for(j=0;j<c.mec[i];j++) ne[c.mep[i][(2*i+1)*j+2*i]]=mne[i]+(j*i); 00087 } 00088 } 00089 00090 /** Copies the information from another voronoicell_neighbor class into this 00091 * class, extending memory allocation if necessary. 00092 * \param[in] c the class to copy. */ 00093 void voronoicell_neighbor::operator=(voronoicell_neighbor &c) { 00094 voronoicell_base *vb=((voronoicell_base*) &c); 00095 check_memory_for_copy(*this,vb);copy(vb); 00096 int i,j; 00097 for(i=0;i<c.current_vertex_order;i++) { 00098 for(j=0;j<c.mec[i]*i;j++) mne[i][j]=c.mne[i][j]; 00099 for(j=0;j<c.mec[i];j++) ne[c.mep[i][(2*i+1)*j+2*i]]=mne[i]+(j*i); 00100 } 00101 } 00102 00103 /** Translates the vertices of the Voronoi cell by a given vector. 00104 * \param[in] (x,y,z) the coordinates of the vector. */ 00105 void voronoicell_base::translate(double x,double y,double z) { 00106 x*=2;y*=2;z*=2; 00107 double *ptsp=pts; 00108 while(ptsp<pts+3*p) { 00109 *(ptsp++)=x;*(ptsp++)=y;*(ptsp++)=z; 00110 } 00111 } 00112 00113 /** Increases the memory storage for a particular vertex order, by increasing 00114 * the size of the of the corresponding mep array. If the arrays already exist, 00115 * their size is doubled; if they don't exist, then new ones of size 00116 * init_n_vertices are allocated. The routine also ensures that the pointers in 00117 * the ed array are updated, by making use of the back pointers. For the cases 00118 * where the back pointer has been temporarily overwritten in the marginal 00119 * vertex code, the auxiliary delete stack is scanned to find out how to update 00120 * the ed value. If the template has been instantiated with the neighbor 00121 * tracking turned on, then the routine also reallocates the corresponding mne 00122 * array. 00123 * \param[in] i the order of the vertex memory to be increased. */ 00124 template<class vc_class> 00125 void voronoicell_base::add_memory(vc_class &vc,int i,int *stackp2) { 00126 int s=(i<<1)+1; 00127 if(mem[i]==0) { 00128 vc.n_allocate(i,init_n_vertices); 00129 mep[i]=new int[init_n_vertices*s]; 00130 mem[i]=init_n_vertices; 00131 #if VOROPP_VERBOSE >=2 00132 fprintf(stderr,"Order %d vertex memory created\n",i); 00133 #endif 00134 } else { 00135 int j=0,k,*l; 00136 mem[i]<<=1; 00137 if(mem[i]>max_n_vertices) voro_fatal_error("Point memory allocation exceeded absolute maximum",VOROPP_MEMORY_ERROR); 00138 #if VOROPP_VERBOSE >=2 00139 fprintf(stderr,"Order %d vertex memory scaled up to %d\n",i,mem[i]); 00140 #endif 00141 l=new int[s*mem[i]]; 00142 int m=0; 00143 vc.n_allocate_aux1(i); 00144 while(j<s*mec[i]) { 00145 k=mep[i][j+(i<<1)]; 00146 if(k>=0) { 00147 ed[k]=l+j; 00148 vc.n_set_to_aux1_offset(k,m); 00149 } else { 00150 int *dsp; 00151 for(dsp=ds2;dsp<stackp2;dsp++) { 00152 if(ed[*dsp]==mep[i]+j) { 00153 ed[*dsp]=l+j; 00154 vc.n_set_to_aux1_offset(*dsp,m); 00155 break; 00156 } 00157 } 00158 if(dsp==stackp2) voro_fatal_error("Couldn't relocate dangling pointer",VOROPP_INTERNAL_ERROR); 00159 #if VOROPP_VERBOSE >=3 00160 fputs("Relocated dangling pointer",stderr); 00161 #endif 00162 } 00163 for(k=0;k<s;k++,j++) l[j]=mep[i][j]; 00164 for(k=0;k<i;k++,m++) vc.n_copy_to_aux1(i,m); 00165 } 00166 delete [] mep[i]; 00167 mep[i]=l; 00168 vc.n_switch_to_aux1(i); 00169 } 00170 } 00171 00172 /** Doubles the maximum number of vertices allowed, by reallocating the ed, nu, 00173 * and pts arrays. If the allocation exceeds the absolute maximum set in 00174 * max_vertices, then the routine exits with a fatal error. If the template has 00175 * been instantiated with the neighbor tracking turned on, then the routine 00176 * also reallocates the ne array. */ 00177 template<class vc_class> 00178 void voronoicell_base::add_memory_vertices(vc_class &vc) { 00179 int i=(current_vertices<<1),j,**pp,*pnu; 00180 if(i>max_vertices) voro_fatal_error("Vertex memory allocation exceeded absolute maximum",VOROPP_MEMORY_ERROR); 00181 #if VOROPP_VERBOSE >=2 00182 fprintf(stderr,"Vertex memory scaled up to %d\n",i); 00183 #endif 00184 double *ppts; 00185 pp=new int*[i]; 00186 for(j=0;j<current_vertices;j++) pp[j]=ed[j]; 00187 delete [] ed;ed=pp; 00188 vc.n_add_memory_vertices(i); 00189 pnu=new int[i]; 00190 for(j=0;j<current_vertices;j++) pnu[j]=nu[j]; 00191 delete [] nu;nu=pnu; 00192 ppts=new double[3*i]; 00193 for(j=0;j<3*current_vertices;j++) ppts[j]=pts[j]; 00194 delete [] pts;pts=ppts; 00195 current_vertices=i; 00196 } 00197 00198 /** Doubles the maximum allowed vertex order, by reallocating mem, mep, and mec 00199 * arrays. If the allocation exceeds the absolute maximum set in 00200 * max_vertex_order, then the routine causes a fatal error. If the template has 00201 * been instantiated with the neighbor tracking turned on, then the routine 00202 * also reallocates the mne array. */ 00203 template<class vc_class> 00204 void voronoicell_base::add_memory_vorder(vc_class &vc) { 00205 int i=(current_vertex_order<<1),j,*p1,**p2; 00206 if(i>max_vertex_order) voro_fatal_error("Vertex order memory allocation exceeded absolute maximum",VOROPP_MEMORY_ERROR); 00207 #if VOROPP_VERBOSE >=2 00208 fprintf(stderr,"Vertex order memory scaled up to %d\n",i); 00209 #endif 00210 p1=new int[i]; 00211 for(j=0;j<current_vertex_order;j++) p1[j]=mem[j];while(j<i) p1[j++]=0; 00212 delete [] mem;mem=p1; 00213 p2=new int*[i]; 00214 for(j=0;j<current_vertex_order;j++) p2[j]=mep[j]; 00215 delete [] mep;mep=p2; 00216 p1=new int[i]; 00217 for(j=0;j<current_vertex_order;j++) p1[j]=mec[j];while(j<i) p1[j++]=0; 00218 delete [] mec;mec=p1; 00219 vc.n_add_memory_vorder(i); 00220 current_vertex_order=i; 00221 } 00222 00223 /** Doubles the size allocation of the main delete stack. If the allocation 00224 * exceeds the absolute maximum set in max_delete_size, then routine causes a 00225 * fatal error. */ 00226 void voronoicell_base::add_memory_ds(int *&stackp) { 00227 current_delete_size<<=1; 00228 if(current_delete_size>max_delete_size) voro_fatal_error("Delete stack 1 memory allocation exceeded absolute maximum",VOROPP_MEMORY_ERROR); 00229 #if VOROPP_VERBOSE >=2 00230 fprintf(stderr,"Delete stack 1 memory scaled up to %d\n",current_delete_size); 00231 #endif 00232 int *dsn=new int[current_delete_size],*dsnp=dsn,*dsp=ds; 00233 while(dsp<stackp) *(dsnp++)=*(dsp++); 00234 delete [] ds;ds=dsn;stackp=dsnp; 00235 stacke=ds+current_delete_size; 00236 } 00237 00238 /** Doubles the size allocation of the auxiliary delete stack. If the 00239 * allocation exceeds the absolute maximum set in max_delete2_size, then the 00240 * routine causes a fatal error. */ 00241 void voronoicell_base::add_memory_ds2(int *&stackp2) { 00242 current_delete2_size<<=1; 00243 if(current_delete2_size>max_delete2_size) voro_fatal_error("Delete stack 2 memory allocation exceeded absolute maximum",VOROPP_MEMORY_ERROR); 00244 #if VOROPP_VERBOSE >=2 00245 fprintf(stderr,"Delete stack 2 memory scaled up to %d\n",current_delete2_size); 00246 #endif 00247 int *dsn=new int[current_delete2_size],*dsnp=dsn,*dsp=ds2; 00248 while(dsp<stackp2) *(dsnp++)=*(dsp++); 00249 delete [] ds2;ds2=dsn;stackp2=dsnp; 00250 stacke2=ds2+current_delete2_size; 00251 } 00252 00253 /** Initializes a Voronoi cell as a rectangular box with the given dimensions. 00254 * \param[in] (xmin,xmax) the minimum and maximum x coordinates. 00255 * \param[in] (ymin,ymax) the minimum and maximum y coordinates. 00256 * \param[in] (zmin,zmax) the minimum and maximum z coordinates. */ 00257 void voronoicell_base::init_base(double xmin,double xmax,double ymin,double ymax,double zmin,double zmax) { 00258 for(int i=0;i<current_vertex_order;i++) mec[i]=0;up=0; 00259 mec[3]=p=8;xmin*=2;xmax*=2;ymin*=2;ymax*=2;zmin*=2;zmax*=2; 00260 *pts=xmin;pts[1]=ymin;pts[2]=zmin; 00261 pts[3]=xmax;pts[4]=ymin;pts[5]=zmin; 00262 pts[6]=xmin;pts[7]=ymax;pts[8]=zmin; 00263 pts[9]=xmax;pts[10]=ymax;pts[11]=zmin; 00264 pts[12]=xmin;pts[13]=ymin;pts[14]=zmax; 00265 pts[15]=xmax;pts[16]=ymin;pts[17]=zmax; 00266 pts[18]=xmin;pts[19]=ymax;pts[20]=zmax; 00267 pts[21]=xmax;pts[22]=ymax;pts[23]=zmax; 00268 int *q=mep[3]; 00269 *q=1;q[1]=4;q[2]=2;q[3]=2;q[4]=1;q[5]=0;q[6]=0; 00270 q[7]=3;q[8]=5;q[9]=0;q[10]=2;q[11]=1;q[12]=0;q[13]=1; 00271 q[14]=0;q[15]=6;q[16]=3;q[17]=2;q[18]=1;q[19]=0;q[20]=2; 00272 q[21]=2;q[22]=7;q[23]=1;q[24]=2;q[25]=1;q[26]=0;q[27]=3; 00273 q[28]=6;q[29]=0;q[30]=5;q[31]=2;q[32]=1;q[33]=0;q[34]=4; 00274 q[35]=4;q[36]=1;q[37]=7;q[38]=2;q[39]=1;q[40]=0;q[41]=5; 00275 q[42]=7;q[43]=2;q[44]=4;q[45]=2;q[46]=1;q[47]=0;q[48]=6; 00276 q[49]=5;q[50]=3;q[51]=6;q[52]=2;q[53]=1;q[54]=0;q[55]=7; 00277 *ed=q;ed[1]=q+7;ed[2]=q+14;ed[3]=q+21; 00278 ed[4]=q+28;ed[5]=q+35;ed[6]=q+42;ed[7]=q+49; 00279 *nu=nu[1]=nu[2]=nu[3]=nu[4]=nu[5]=nu[6]=nu[7]=3; 00280 } 00281 00282 /** Initializes a Voronoi cell as a regular octahedron. 00283 * \param[in] l The distance from the octahedron center to a vertex. Six 00284 * vertices are initialized at (-l,0,0), (l,0,0), (0,-l,0), 00285 * (0,l,0), (0,0,-l), and (0,0,l). */ 00286 void voronoicell_base::init_octahedron_base(double l) { 00287 for(int i=0;i<current_vertex_order;i++) mec[i]=0;up=0; 00288 mec[4]=p=6;l*=2; 00289 *pts=-l;pts[1]=0;pts[2]=0; 00290 pts[3]=l;pts[4]=0;pts[5]=0; 00291 pts[6]=0;pts[7]=-l;pts[8]=0; 00292 pts[9]=0;pts[10]=l;pts[11]=0; 00293 pts[12]=0;pts[13]=0;pts[14]=-l; 00294 pts[15]=0;pts[16]=0;pts[17]=l; 00295 int *q=mep[4]; 00296 *q=2;q[1]=5;q[2]=3;q[3]=4;q[4]=0;q[5]=0;q[6]=0;q[7]=0;q[8]=0; 00297 q[9]=2;q[10]=4;q[11]=3;q[12]=5;q[13]=2;q[14]=2;q[15]=2;q[16]=2;q[17]=1; 00298 q[18]=0;q[19]=4;q[20]=1;q[21]=5;q[22]=0;q[23]=3;q[24]=0;q[25]=1;q[26]=2; 00299 q[27]=0;q[28]=5;q[29]=1;q[30]=4;q[31]=2;q[32]=3;q[33]=2;q[34]=1;q[35]=3; 00300 q[36]=0;q[37]=3;q[38]=1;q[39]=2;q[40]=3;q[41]=3;q[42]=1;q[43]=1;q[44]=4; 00301 q[45]=0;q[46]=2;q[47]=1;q[48]=3;q[49]=1;q[50]=3;q[51]=3;q[52]=1;q[53]=5; 00302 *ed=q;ed[1]=q+9;ed[2]=q+18;ed[3]=q+27;ed[4]=q+36;ed[5]=q+45; 00303 *nu=nu[1]=nu[2]=nu[3]=nu[4]=nu[5]=4; 00304 } 00305 00306 /** Initializes a Voronoi cell as a tetrahedron. It assumes that the normal to 00307 * the face for the first three vertices points inside. 00308 * \param (x0,y0,z0) a position vector for the first vertex. 00309 * \param (x1,y1,z1) a position vector for the second vertex. 00310 * \param (x2,y2,z2) a position vector for the third vertex. 00311 * \param (x3,y3,z3) a position vector for the fourth vertex. */ 00312 void voronoicell_base::init_tetrahedron_base(double x0,double y0,double z0,double x1,double y1,double z1,double x2,double y2,double z2,double x3,double y3,double z3) { 00313 for(int i=0;i<current_vertex_order;i++) mec[i]=0;up=0; 00314 mec[3]=p=4; 00315 *pts=x0*2;pts[1]=y0*2;pts[2]=z0*2; 00316 pts[3]=x1*2;pts[4]=y1*2;pts[5]=z1*2; 00317 pts[6]=x2*2;pts[7]=y2*2;pts[8]=z2*2; 00318 pts[9]=x3*2;pts[10]=y3*2;pts[11]=z3*2; 00319 int *q=mep[3]; 00320 *q=1;q[1]=3;q[2]=2;q[3]=0;q[4]=0;q[5]=0;q[6]=0; 00321 q[7]=0;q[8]=2;q[9]=3;q[10]=0;q[11]=2;q[12]=1;q[13]=1; 00322 q[14]=0;q[15]=3;q[16]=1;q[17]=2;q[18]=2;q[19]=1;q[20]=2; 00323 q[21]=0;q[22]=1;q[23]=2;q[24]=1;q[25]=2;q[26]=1;q[27]=3; 00324 *ed=q;ed[1]=q+7;ed[2]=q+14;ed[3]=q+21; 00325 *nu=nu[1]=nu[2]=nu[3]=3; 00326 } 00327 00328 /** Checks that the relational table of the Voronoi cell is accurate, and 00329 * prints out any errors. This algorithm is O(p), so running it every time the 00330 * plane routine is called will result in a significant slowdown. */ 00331 void voronoicell_base::check_relations() { 00332 int i,j; 00333 for(i=0;i<p;i++) for(j=0;j<nu[i];j++) if(ed[ed[i][j]][ed[i][nu[i]+j]]!=i) 00334 printf("Relational error at point %d, edge %d.\n",i,j); 00335 } 00336 00337 /** This routine checks for any two vertices that are connected by more than 00338 * one edge. The plane algorithm is designed so that this should not happen, so 00339 * any occurrences are most likely errors. Note that the routine is O(p), so 00340 * running it every time the plane routine is called will result in a 00341 * significant slowdown. */ 00342 void voronoicell_base::check_duplicates() { 00343 int i,j,k; 00344 for(i=0;i<p;i++) for(j=1;j<nu[i];j++) for(k=0;k<j;k++) if(ed[i][j]==ed[i][k]) 00345 printf("Duplicate edges: (%d,%d) and (%d,%d) [%d]\n",i,j,i,k,ed[i][j]); 00346 } 00347 00348 /** Constructs the relational table if the edges have been specified. */ 00349 void voronoicell_base::construct_relations() { 00350 int i,j,k,l; 00351 for(i=0;i<p;i++) for(j=0;j<nu[i];j++) { 00352 k=ed[i][j]; 00353 l=0; 00354 while(ed[k][l]!=i) { 00355 l++; 00356 if(l==nu[k]) voro_fatal_error("Relation table construction failed",VOROPP_INTERNAL_ERROR); 00357 } 00358 ed[i][nu[i]+j]=l; 00359 } 00360 } 00361 00362 /** Starting from a point within the current cutting plane, this routine attempts 00363 * to find an edge to a point outside the cutting plane. This prevents the plane 00364 * routine from . 00365 * \param[in] vc a reference to the specialized version of the calling class. 00366 * \param[in,out] up */ 00367 template<class vc_class> 00368 inline bool voronoicell_base::search_for_outside_edge(vc_class &vc,int &up) { 00369 int i,lp,lw,*j(ds2),*stackp2(ds2); 00370 double l; 00371 *(stackp2++)=up; 00372 while(j<stackp2) { 00373 up=*(j++); 00374 for(i=0;i<nu[up];i++) { 00375 lp=ed[up][i]; 00376 lw=m_test(lp,l); 00377 if(lw==-1) return true; 00378 else if(lw==0) add_to_stack(vc,lp,stackp2); 00379 } 00380 } 00381 return false; 00382 } 00383 00384 /** Adds a point to the auxiliary delete stack if it is not already there. 00385 * \param[in] vc a reference to the specialized version of the calling class. 00386 * \param[in] lp the index of the point to add. 00387 * \param[in,out] stackp2 a pointer to the end of the stack entries. */ 00388 template<class vc_class> 00389 inline void voronoicell_base::add_to_stack(vc_class &vc,int lp,int *&stackp2) { 00390 for(int *k(ds2);k<stackp2;k++) if(*k==lp) return; 00391 if(stackp2==stacke2) add_memory_ds2(stackp2); 00392 *(stackp2++)=lp; 00393 } 00394 00395 /** Cuts the Voronoi cell by a particle whose center is at a separation of 00396 * (x,y,z) from the cell center. The value of rsq should be initially set to 00397 * \f$x^2+y^2+z^2\f$. 00398 * \param[in] vc a reference to the specialized version of the calling class. 00399 * \param[in] (x,y,z) the normal vector to the plane. 00400 * \param[in] rsq the distance along this vector of the plane. 00401 * \param[in] p_id the plane ID (for neighbor tracking only). 00402 * \return False if the plane cut deleted the cell entirely, true otherwise. */ 00403 template<class vc_class> 00404 bool voronoicell_base::nplane(vc_class &vc,double x,double y,double z,double rsq,int p_id) { 00405 int count=0,i,j,k,lp=up,cp,qp,rp,*stackp(ds),*stackp2(ds2),*dsp; 00406 int us=0,ls=0,qs,iqs,cs,uw,qw,lw; 00407 int *edp,*edd; 00408 double u,l,r,q;bool complicated_setup=false,new_double_edge=false,double_edge=false; 00409 00410 // Initialize the safe testing routine 00411 n_marg=0;px=x;py=y;pz=z;prsq=rsq; 00412 00413 // Test approximately sqrt(n)/4 points for their proximity to the plane 00414 // and keep the one which is closest 00415 uw=m_test(up,u); 00416 00417 // Starting from an initial guess, we now move from vertex to vertex, 00418 // to try and find an edge which intersects the cutting plane, 00419 // or a vertex which is on the plane 00420 try { 00421 if(uw==1) { 00422 00423 // The test point is inside the cutting plane. 00424 us=0; 00425 do { 00426 lp=ed[up][us]; 00427 lw=m_test(lp,l); 00428 if(l<u) break; 00429 us++; 00430 } while (us<nu[up]); 00431 00432 if(us==nu[up]) { 00433 return false; 00434 } 00435 00436 ls=ed[up][nu[up]+us]; 00437 while(lw==1) { 00438 if(++count>=p) throw true; 00439 u=l;up=lp; 00440 for(us=0;us<ls;us++) { 00441 lp=ed[up][us]; 00442 lw=m_test(lp,l); 00443 if(l<u) break; 00444 } 00445 if(us==ls) { 00446 us++; 00447 while(us<nu[up]) { 00448 lp=ed[up][us]; 00449 lw=m_test(lp,l); 00450 if(l<u) break; 00451 us++; 00452 } 00453 if(us==nu[up]) { 00454 return false; 00455 } 00456 } 00457 ls=ed[up][nu[up]+us]; 00458 } 00459 00460 // If the last point in the iteration is within the 00461 // plane, we need to do the complicated setup 00462 // routine. Otherwise, we use the regular iteration. 00463 if(lw==0) { 00464 up=lp; 00465 complicated_setup=true; 00466 } else complicated_setup=false; 00467 } else if(uw==-1) { 00468 us=0; 00469 do { 00470 qp=ed[up][us]; 00471 qw=m_test(qp,q); 00472 if(u<q) break; 00473 us++; 00474 } while (us<nu[up]); 00475 if(us==nu[up]) return true; 00476 00477 while(qw==-1) { 00478 qs=ed[up][nu[up]+us]; 00479 if(++count>=p) throw true; 00480 u=q;up=qp; 00481 for(us=0;us<qs;us++) { 00482 qp=ed[up][us]; 00483 qw=m_test(qp,q); 00484 if(u<q) break; 00485 } 00486 if(us==qs) { 00487 us++; 00488 while(us<nu[up]) { 00489 qp=ed[up][us]; 00490 qw=m_test(qp,q); 00491 if(u<q) break; 00492 us++; 00493 } 00494 if(us==nu[up]) return true; 00495 } 00496 } 00497 if(qw==1) { 00498 lp=up;ls=us;l=u; 00499 up=qp;us=ed[lp][nu[lp]+ls];u=q; 00500 complicated_setup=false; 00501 } else { 00502 up=qp; 00503 complicated_setup=true; 00504 } 00505 } else { 00506 00507 // Our original test point was on the plane, so we 00508 // automatically head for the complicated setup 00509 // routine 00510 complicated_setup=true; 00511 } 00512 } 00513 catch(bool except) { 00514 // This routine is a fall-back, in case floating point errors 00515 // cause the usual search routine to fail. In the fall-back 00516 // routine, we just test every edge to find one straddling 00517 // the plane. 00518 #if VOROPP_VERBOSE >=1 00519 fputs("Bailed out of convex calculation\n",stderr); 00520 #endif 00521 qw=1;lw=0; 00522 for(qp=0;qp<p;qp++) { 00523 qw=m_test(qp,q); 00524 if(qw==1) { 00525 00526 // The point is inside the cutting space. Now 00527 // see if we can find a neighbor which isn't. 00528 for(us=0;us<nu[qp];us++) { 00529 lp=ed[qp][us]; 00530 if(lp<qp) { 00531 lw=m_test(lp,l); 00532 if(lw!=1) break; 00533 } 00534 } 00535 if(us<nu[qp]) { 00536 up=qp; 00537 if(lw==0) { 00538 complicated_setup=true; 00539 } else { 00540 complicated_setup=false; 00541 u=q; 00542 ls=ed[up][nu[up]+us]; 00543 } 00544 break; 00545 } 00546 } else if(qw==-1) { 00547 00548 // The point is outside the cutting space. See 00549 // if we can find a neighbor which isn't. 00550 for(ls=0;ls<nu[qp];ls++) { 00551 up=ed[qp][ls]; 00552 if(up<qp) { 00553 uw=m_test(up,u); 00554 if(uw!=-1) break; 00555 } 00556 } 00557 if(ls<nu[qp]) { 00558 if(uw==0) { 00559 up=qp; 00560 complicated_setup=true; 00561 } else { 00562 complicated_setup=false; 00563 lp=qp;l=q; 00564 us=ed[lp][nu[lp]+ls]; 00565 } 00566 break; 00567 } 00568 } else { 00569 00570 // The point is in the plane, so we just 00571 // proceed with the complicated setup routine 00572 up=qp; 00573 complicated_setup=true; 00574 break; 00575 } 00576 } 00577 if(qp==p) return qw==-1?true:false; 00578 } 00579 00580 // We're about to add the first point of the new facet. In either 00581 // routine, we have to add a point, so first check there's space for 00582 // it. 00583 if(p==current_vertices) add_memory_vertices(vc); 00584 00585 if(complicated_setup) { 00586 00587 // We want to be strict about reaching the conclusion that the 00588 // cell is entirely within the cutting plane. It's not enough 00589 // to find a vertex that has edges which are all inside or on 00590 // the plane. If the vertex has neighbors that are also on the 00591 // plane, we should check those too. 00592 if(!search_for_outside_edge(vc,up)) return false; 00593 00594 // The search algorithm found a point which is on the cutting 00595 // plane. We leave that point in place, and create a new one at 00596 // the same location. 00597 pts[3*p]=pts[3*up]; 00598 pts[3*p+1]=pts[3*up+1]; 00599 pts[3*p+2]=pts[3*up+2]; 00600 00601 // Search for a collection of edges of the test vertex which 00602 // are outside of the cutting space. Begin by testing the 00603 // zeroth edge. 00604 i=0; 00605 lp=*ed[up]; 00606 lw=m_test(lp,l); 00607 if(lw!=-1) { 00608 00609 // The first edge is either inside the cutting space, 00610 // or lies within the cutting plane. Test the edges 00611 // sequentially until we find one that is outside. 00612 rp=lw; 00613 do { 00614 i++; 00615 00616 // If we reached the last edge with no luck 00617 // then all of the vertices are inside 00618 // or on the plane, so the cell is completely 00619 // deleted 00620 if(i==nu[up]) return false; 00621 lp=ed[up][i]; 00622 lw=m_test(lp,l); 00623 } while (lw!=-1); 00624 j=i+1; 00625 00626 // We found an edge outside the cutting space. Keep 00627 // moving through these edges until we find one that's 00628 // inside or on the plane. 00629 while(j<nu[up]) { 00630 lp=ed[up][j]; 00631 lw=m_test(lp,l); 00632 if(lw!=-1) break; 00633 j++; 00634 } 00635 00636 // Compute the number of edges for the new vertex. In 00637 // general it will be the number of outside edges 00638 // found, plus two. But we need to recognize the 00639 // special case when all but one edge is outside, and 00640 // the remaining one is on the plane. For that case we 00641 // have to reduce the edge count by one to prevent 00642 // doubling up. 00643 if(j==nu[up]&&i==1&&rp==0) { 00644 nu[p]=nu[up]; 00645 double_edge=true; 00646 } else nu[p]=j-i+2; 00647 k=1; 00648 00649 // Add memory for the new vertex if needed, and 00650 // initialize 00651 while (nu[p]>=current_vertex_order) add_memory_vorder(vc); 00652 if(mec[nu[p]]==mem[nu[p]]) add_memory(vc,nu[p],stackp2); 00653 vc.n_set_pointer(p,nu[p]); 00654 ed[p]=mep[nu[p]]+((nu[p]<<1)+1)*mec[nu[p]]++; 00655 ed[p][nu[p]<<1]=p; 00656 00657 // Copy the edges of the original vertex into the new 00658 // one. Delete the edges of the original vertex, and 00659 // update the relational table. 00660 us=cycle_down(i,up); 00661 while(i<j) { 00662 qp=ed[up][i]; 00663 qs=ed[up][nu[up]+i]; 00664 vc.n_copy(p,k,up,i); 00665 ed[p][k]=qp; 00666 ed[p][nu[p]+k]=qs; 00667 ed[qp][qs]=p; 00668 ed[qp][nu[qp]+qs]=k; 00669 ed[up][i]=-1; 00670 i++;k++; 00671 } 00672 qs=i==nu[up]?0:i; 00673 } else { 00674 00675 // In this case, the zeroth edge is outside the cutting 00676 // plane. Begin by searching backwards from the last 00677 // edge until we find an edge which isn't outside. 00678 i=nu[up]-1; 00679 lp=ed[up][i]; 00680 lw=m_test(lp,l); 00681 while(lw==-1) { 00682 i--; 00683 00684 // If i reaches zero, then we have a point in 00685 // the plane all of whose edges are outside 00686 // the cutting space, so we just exit 00687 if(i==0) return true; 00688 lp=ed[up][i]; 00689 lw=m_test(lp,l); 00690 } 00691 00692 // Now search forwards from zero 00693 j=1; 00694 qp=ed[up][j]; 00695 qw=m_test(qp,q); 00696 while(qw==-1) { 00697 j++; 00698 qp=ed[up][j]; 00699 qw=m_test(qp,l); 00700 } 00701 00702 // Compute the number of edges for the new vertex. In 00703 // general it will be the number of outside edges 00704 // found, plus two. But we need to recognize the 00705 // special case when all but one edge is outside, and 00706 // the remaining one is on the plane. For that case we 00707 // have to reduce the edge count by one to prevent 00708 // doubling up. 00709 if(i==j&&qw==0) { 00710 double_edge=true; 00711 nu[p]=nu[up]; 00712 } else { 00713 nu[p]=nu[up]-i+j+1; 00714 } 00715 00716 // Add memory to store the vertex if it doesn't exist 00717 // already 00718 k=1; 00719 while(nu[p]>=current_vertex_order) add_memory_vorder(vc); 00720 if(mec[nu[p]]==mem[nu[p]]) add_memory(vc,nu[p],stackp2); 00721 00722 // Copy the edges of the original vertex into the new 00723 // one. Delete the edges of the original vertex, and 00724 // update the relational table. 00725 vc.n_set_pointer(p,nu[p]); 00726 ed[p]=mep[nu[p]]+((nu[p]<<1)+1)*mec[nu[p]]++; 00727 ed[p][nu[p]<<1]=p; 00728 us=i++; 00729 while(i<nu[up]) { 00730 qp=ed[up][i]; 00731 qs=ed[up][nu[up]+i]; 00732 vc.n_copy(p,k,up,i); 00733 ed[p][k]=qp; 00734 ed[p][nu[p]+k]=qs; 00735 ed[qp][qs]=p; 00736 ed[qp][nu[qp]+qs]=k; 00737 ed[up][i]=-1; 00738 i++;k++; 00739 } 00740 i=0; 00741 while(i<j) { 00742 qp=ed[up][i]; 00743 qs=ed[up][nu[up]+i]; 00744 vc.n_copy(p,k,up,i); 00745 ed[p][k]=qp; 00746 ed[p][nu[p]+k]=qs; 00747 ed[qp][qs]=p; 00748 ed[qp][nu[qp]+qs]=k; 00749 ed[up][i]=-1; 00750 i++;k++; 00751 } 00752 qs=j; 00753 } 00754 if(!double_edge) { 00755 vc.n_copy(p,k,up,qs); 00756 vc.n_set(p,0,p_id); 00757 } else vc.n_copy(p,0,up,qs); 00758 00759 // Add this point to the auxiliary delete stack 00760 if(stackp2==stacke2) add_memory_ds2(stackp2); 00761 *(stackp2++)=up; 00762 00763 // Look at the edges on either side of the group that was 00764 // detected. We're going to commence facet computation by 00765 // moving along one of them. We are going to end up coming back 00766 // along the other one. 00767 cs=k; 00768 qp=up;q=u; 00769 i=ed[up][us]; 00770 us=ed[up][nu[up]+us]; 00771 up=i; 00772 ed[qp][nu[qp]<<1]=-p; 00773 00774 } else { 00775 00776 // The search algorithm found an intersected edge between the 00777 // points lp and up. Create a new vertex between them which 00778 // lies on the cutting plane. Since u and l differ by at least 00779 // the tolerance, this division should never screw up. 00780 if(stackp==stacke) add_memory_ds(stackp); 00781 *(stackp++)=up; 00782 r=u/(u-l);l=1-r; 00783 pts[3*p]=pts[3*lp]*r+pts[3*up]*l; 00784 pts[3*p+1]=pts[3*lp+1]*r+pts[3*up+1]*l; 00785 pts[3*p+2]=pts[3*lp+2]*r+pts[3*up+2]*l; 00786 00787 // This point will always have three edges. Connect one of them 00788 // to lp. 00789 nu[p]=3; 00790 if(mec[3]==mem[3]) add_memory(vc,3,stackp2); 00791 vc.n_set_pointer(p,3); 00792 vc.n_set(p,0,p_id); 00793 vc.n_copy(p,1,up,us); 00794 vc.n_copy(p,2,lp,ls); 00795 ed[p]=mep[3]+7*mec[3]++; 00796 ed[p][6]=p; 00797 ed[up][us]=-1; 00798 ed[lp][ls]=p; 00799 ed[lp][nu[lp]+ls]=1; 00800 ed[p][1]=lp; 00801 ed[p][nu[p]+1]=ls; 00802 cs=2; 00803 00804 // Set the direction to move in 00805 qs=cycle_up(us,up); 00806 qp=up;q=u; 00807 } 00808 00809 // When the code reaches here, we have initialized the first point, and 00810 // we have a direction for moving it to construct the rest of the facet 00811 cp=p;rp=p;p++; 00812 while(qp!=up||qs!=us) { 00813 00814 // We're currently tracing round an intersected facet. Keep 00815 // moving around it until we find a point or edge which 00816 // intersects the plane. 00817 lp=ed[qp][qs]; 00818 lw=m_test(lp,l); 00819 00820 if(lw==1) { 00821 00822 // The point is still in the cutting space. Just add it 00823 // to the delete stack and keep moving. 00824 qs=cycle_up(ed[qp][nu[qp]+qs],lp); 00825 qp=lp; 00826 q=l; 00827 if(stackp==stacke) add_memory_ds(stackp); 00828 *(stackp++)=qp; 00829 00830 } else if(lw==-1) { 00831 00832 // The point is outside of the cutting space, so we've 00833 // found an intersected edge. Introduce a regular point 00834 // at the point of intersection. Connect it to the 00835 // point we just tested. Also connect it to the previous 00836 // new point in the facet we're constructing. 00837 if(p==current_vertices) add_memory_vertices(vc); 00838 r=q/(q-l);l=1-r; 00839 pts[3*p]=pts[3*lp]*r+pts[3*qp]*l; 00840 pts[3*p+1]=pts[3*lp+1]*r+pts[3*qp+1]*l; 00841 pts[3*p+2]=pts[3*lp+2]*r+pts[3*qp+2]*l; 00842 nu[p]=3; 00843 if(mec[3]==mem[3]) add_memory(vc,3,stackp2); 00844 ls=ed[qp][qs+nu[qp]]; 00845 vc.n_set_pointer(p,3); 00846 vc.n_set(p,0,p_id); 00847 vc.n_copy(p,1,qp,qs); 00848 vc.n_copy(p,2,lp,ls); 00849 ed[p]=mep[3]+7*mec[3]++; 00850 *ed[p]=cp; 00851 ed[p][1]=lp; 00852 ed[p][3]=cs; 00853 ed[p][4]=ls; 00854 ed[p][6]=p; 00855 ed[lp][ls]=p; 00856 ed[lp][nu[lp]+ls]=1; 00857 ed[cp][cs]=p; 00858 ed[cp][nu[cp]+cs]=0; 00859 ed[qp][qs]=-1; 00860 qs=cycle_up(qs,qp); 00861 cp=p++; 00862 cs=2; 00863 } else { 00864 00865 // We've found a point which is on the cutting plane. 00866 // We're going to introduce a new point right here, but 00867 // first we need to figure out the number of edges it 00868 // has. 00869 if(p==current_vertices) add_memory_vertices(vc); 00870 00871 // If the previous vertex detected a double edge, our 00872 // new vertex will have one less edge. 00873 k=double_edge?0:1; 00874 qs=ed[qp][nu[qp]+qs]; 00875 qp=lp; 00876 iqs=qs; 00877 00878 // Start testing the edges of the current point until 00879 // we find one which isn't outside the cutting space 00880 do { 00881 k++; 00882 qs=cycle_up(qs,qp); 00883 lp=ed[qp][qs]; 00884 lw=m_test(lp,l); 00885 } while (lw==-1); 00886 00887 // Now we need to find out whether this marginal vertex 00888 // we are on has been visited before, because if that's 00889 // the case, we need to add vertices to the existing 00890 // new vertex, rather than creating a fresh one. We also 00891 // need to figure out whether we're in a case where we 00892 // might be creating a duplicate edge. 00893 j=-ed[qp][nu[qp]<<1]; 00894 if(qp==up&&qs==us) { 00895 00896 // If we're heading into the final part of the 00897 // new facet, then we never worry about the 00898 // duplicate edge calculation. 00899 new_double_edge=false; 00900 if(j>0) k+=nu[j]; 00901 } else { 00902 if(j>0) { 00903 00904 // This vertex was visited before, so 00905 // count those vertices to the ones we 00906 // already have. 00907 k+=nu[j]; 00908 00909 // The only time when we might make a 00910 // duplicate edge is if the point we're 00911 // going to move to next is also a 00912 // marginal point, so test for that 00913 // first. 00914 if(lw==0) { 00915 00916 // Now see whether this marginal point 00917 // has been visited before. 00918 i=-ed[lp][nu[lp]<<1]; 00919 if(i>0) { 00920 00921 // Now see if the last edge of that other 00922 // marginal point actually ends up here. 00923 if(ed[i][nu[i]-1]==j) { 00924 new_double_edge=true; 00925 k-=1; 00926 } else new_double_edge=false; 00927 } else { 00928 00929 // That marginal point hasn't been visited 00930 // before, so we probably don't have to worry 00931 // about duplicate edges, except in the 00932 // case when that's the way into the end 00933 // of the facet, because that way always creates 00934 // an edge. 00935 if(j==rp&&lp==up&&ed[qp][nu[qp]+qs]==us) { 00936 new_double_edge=true; 00937 k-=1; 00938 } else new_double_edge=false; 00939 } 00940 } else new_double_edge=false; 00941 } else { 00942 00943 // The vertex hasn't been visited 00944 // before, but let's see if it's 00945 // marginal 00946 if(lw==0) { 00947 00948 // If it is, we need to check 00949 // for the case that it's a 00950 // small branch, and that we're 00951 // heading right back to where 00952 // we came from 00953 i=-ed[lp][nu[lp]<<1]; 00954 if(i==cp) { 00955 new_double_edge=true; 00956 k-=1; 00957 } else new_double_edge=false; 00958 } else new_double_edge=false; 00959 } 00960 } 00961 00962 // k now holds the number of edges of the new vertex 00963 // we are forming. Add memory for it if it doesn't exist 00964 // already. 00965 while(k>=current_vertex_order) add_memory_vorder(vc); 00966 if(mec[k]==mem[k]) add_memory(vc,k,stackp2); 00967 00968 // Now create a new vertex with order k, or augment 00969 // the existing one 00970 if(j>0) { 00971 00972 // If we're augmenting a vertex but we don't 00973 // actually need any more edges, just skip this 00974 // routine to avoid memory confusion 00975 if(nu[j]!=k) { 00976 // Allocate memory and copy the edges 00977 // of the previous instance into it 00978 vc.n_set_aux1(k); 00979 edp=mep[k]+((k<<1)+1)*mec[k]++; 00980 i=0; 00981 while(i<nu[j]) { 00982 vc.n_copy_aux1(j,i); 00983 edp[i]=ed[j][i]; 00984 edp[k+i]=ed[j][nu[j]+i]; 00985 i++; 00986 } 00987 edp[k<<1]=j; 00988 00989 // Remove the previous instance with 00990 // fewer vertices from the memory 00991 // structure 00992 edd=mep[nu[j]]+((nu[j]<<1)+1)*--mec[nu[j]]; 00993 if(edd!=ed[j]) { 00994 for(lw=0;lw<=(nu[j]<<1);lw++) ed[j][lw]=edd[lw]; 00995 vc.n_set_aux2_copy(j,nu[j]); 00996 vc.n_copy_pointer(edd[nu[j]<<1],j); 00997 ed[edd[nu[j]<<1]]=ed[j]; 00998 } 00999 vc.n_set_to_aux1(j); 01000 ed[j]=edp; 01001 } else i=nu[j]; 01002 } else { 01003 01004 // Allocate a new vertex of order k 01005 vc.n_set_pointer(p,k); 01006 ed[p]=mep[k]+((k<<1)+1)*mec[k]++; 01007 ed[p][k<<1]=p; 01008 if(stackp2==stacke2) add_memory_ds2(stackp2); 01009 *(stackp2++)=qp; 01010 pts[3*p]=pts[3*qp]; 01011 pts[3*p+1]=pts[3*qp+1]; 01012 pts[3*p+2]=pts[3*qp+2]; 01013 ed[qp][nu[qp]<<1]=-p; 01014 j=p++; 01015 i=0; 01016 } 01017 nu[j]=k; 01018 01019 // Unless the previous case was a double edge, connect 01020 // the first available edge of the new vertex to the 01021 // last one in the facet 01022 if(!double_edge) { 01023 ed[j][i]=cp; 01024 ed[j][nu[j]+i]=cs; 01025 vc.n_set(j,i,p_id); 01026 ed[cp][cs]=j; 01027 ed[cp][nu[cp]+cs]=i; 01028 i++; 01029 } 01030 01031 // Copy in the edges of the underlying vertex, 01032 // and do one less if this was a double edge 01033 qs=iqs; 01034 while(i<(new_double_edge?k:k-1)) { 01035 qs=cycle_up(qs,qp); 01036 lp=ed[qp][qs];ls=ed[qp][nu[qp]+qs]; 01037 vc.n_copy(j,i,qp,qs); 01038 ed[j][i]=lp; 01039 ed[j][nu[j]+i]=ls; 01040 ed[lp][ls]=j; 01041 ed[lp][nu[lp]+ls]=i; 01042 ed[qp][qs]=-1; 01043 i++; 01044 } 01045 qs=cycle_up(qs,qp); 01046 cs=i; 01047 cp=j; 01048 vc.n_copy(j,new_double_edge?0:cs,qp,qs); 01049 01050 // Update the double_edge flag, to pass it 01051 // to the next instance of this routine 01052 double_edge=new_double_edge; 01053 } 01054 } 01055 01056 // Connect the final created vertex to the initial one 01057 ed[cp][cs]=rp; 01058 *ed[rp]=cp; 01059 ed[cp][nu[cp]+cs]=0; 01060 ed[rp][nu[rp]]=cs; 01061 01062 // Delete points: first, remove any duplicates 01063 dsp=ds; 01064 while(dsp<stackp) { 01065 j=*dsp; 01066 if(ed[j][nu[j]]!=-1) { 01067 ed[j][nu[j]]=-1; 01068 dsp++; 01069 } else *dsp=*(--stackp); 01070 } 01071 01072 // Add the points in the auxiliary delete stack, 01073 // and reset their back pointers 01074 for(dsp=ds2;dsp<stackp2;dsp++) { 01075 j=*dsp; 01076 ed[j][nu[j]<<1]=j; 01077 if(ed[j][nu[j]]!=-1) { 01078 ed[j][nu[j]]=-1; 01079 if(stackp==stacke) add_memory_ds(stackp); 01080 *(stackp++)=j; 01081 } 01082 } 01083 01084 // Scan connections and add in extras 01085 for(dsp=ds;dsp<stackp;dsp++) { 01086 cp=*dsp; 01087 for(edp=ed[cp];edp<ed[cp]+nu[cp];edp++) { 01088 qp=*edp; 01089 if(qp!=-1) { 01090 if(ed[qp][nu[qp]]!=-1) { 01091 if(stackp==stacke) add_memory_ds(stackp); 01092 *(stackp++)=qp; 01093 ed[qp][nu[qp]]=-1; 01094 } 01095 } 01096 } 01097 } 01098 up=0; 01099 01100 // Delete them from the array structure 01101 while(stackp>ds) { 01102 --p; 01103 while(ed[p][nu[p]]==-1) { 01104 j=nu[p]; 01105 edp=ed[p];edd=(mep[j]+((j<<1)+1)*--mec[j]); 01106 while(edp<ed[p]+(j<<1)+1) *(edp++)=*(edd++); 01107 vc.n_set_aux2_copy(p,j); 01108 vc.n_copy_pointer(ed[p][(j<<1)],p); 01109 ed[ed[p][(j<<1)]]=ed[p]; 01110 --p; 01111 } 01112 up=*(--stackp); 01113 if(up<p) { 01114 01115 // Vertex management 01116 pts[3*up]=pts[3*p]; 01117 pts[3*up+1]=pts[3*p+1]; 01118 pts[3*up+2]=pts[3*p+2]; 01119 01120 // Memory management 01121 j=nu[up]; 01122 edp=ed[up];edd=(mep[j]+((j<<1)+1)*--mec[j]); 01123 while(edp<ed[up]+(j<<1)+1) *(edp++)=*(edd++); 01124 vc.n_set_aux2_copy(up,j); 01125 vc.n_copy_pointer(ed[up][j<<1],up); 01126 vc.n_copy_pointer(up,p); 01127 ed[ed[up][j<<1]]=ed[up]; 01128 01129 // Edge management 01130 ed[up]=ed[p]; 01131 nu[up]=nu[p]; 01132 for(i=0;i<nu[up];i++) ed[ed[up][i]][ed[up][nu[up]+i]]=up; 01133 ed[up][nu[up]<<1]=up; 01134 } else up=p++; 01135 } 01136 01137 // Check for any vertices of zero order 01138 if(*mec>0) voro_fatal_error("Zero order vertex formed",VOROPP_INTERNAL_ERROR); 01139 01140 // Collapse any order 2 vertices and exit 01141 return collapse_order2(vc); 01142 } 01143 01144 /** During the creation of a new facet in the plane routine, it is possible 01145 * that some order two vertices may arise. This routine removes them. 01146 * Suppose an order two vertex joins c and d. If there's a edge between 01147 * c and d already, then the order two vertex is just removed; otherwise, 01148 * the order two vertex is removed and c and d are joined together directly. 01149 * It is possible this process will create order two or order one vertices, 01150 * and the routine is continually run until all of them are removed. 01151 * \return False if the vertex removal was unsuccessful, indicative of the cell 01152 * reducing to zero volume and disappearing; true if the vertex removal 01153 * was successful. */ 01154 template<class vc_class> 01155 inline bool voronoicell_base::collapse_order2(vc_class &vc) { 01156 if(!collapse_order1(vc)) return false; 01157 int a,b,i,j,k,l; 01158 while(mec[2]>0) { 01159 01160 // Pick a order 2 vertex and read in its edges 01161 i=--mec[2]; 01162 j=mep[2][5*i];k=mep[2][5*i+1]; 01163 if(j==k) { 01164 #if VOROPP_VERBOSE >=1 01165 fputs("Order two vertex joins itself",stderr); 01166 #endif 01167 return false; 01168 } 01169 01170 // Scan the edges of j to see if joins k 01171 for(l=0;l<nu[j];l++) { 01172 if(ed[j][l]==k) break; 01173 } 01174 01175 // If j doesn't already join k, join them together. 01176 // Otherwise delete the connection to the current 01177 // vertex from j and k. 01178 a=mep[2][5*i+2];b=mep[2][5*i+3];i=mep[2][5*i+4]; 01179 if(l==nu[j]) { 01180 ed[j][a]=k; 01181 ed[k][b]=j; 01182 ed[j][nu[j]+a]=b; 01183 ed[k][nu[k]+b]=a; 01184 } else { 01185 if(!delete_connection(vc,j,a,false)) return false; 01186 if(!delete_connection(vc,k,b,true)) return false; 01187 } 01188 01189 // Compact the memory 01190 --p; 01191 if(up==i) up=0; 01192 if(p!=i) { 01193 if(up==p) up=i; 01194 pts[3*i]=pts[3*p]; 01195 pts[3*i+1]=pts[3*p+1]; 01196 pts[3*i+2]=pts[3*p+2]; 01197 for(k=0;k<nu[p];k++) ed[ed[p][k]][ed[p][nu[p]+k]]=i; 01198 vc.n_copy_pointer(i,p); 01199 ed[i]=ed[p]; 01200 nu[i]=nu[p]; 01201 ed[i][nu[i]<<1]=i; 01202 } 01203 01204 // Collapse any order 1 vertices if they were created 01205 if(!collapse_order1(vc)) return false; 01206 } 01207 return true; 01208 } 01209 01210 /** Order one vertices can potentially be created during the order two collapse 01211 * routine. This routine keeps removing them until there are none left. 01212 * \return False if the vertex removal was unsuccessful, indicative of the cell 01213 * having zero volume and disappearing; true if the vertex removal was 01214 * successful. */ 01215 template<class vc_class> 01216 inline bool voronoicell_base::collapse_order1(vc_class &vc) { 01217 int i,j,k; 01218 while(mec[1]>0) { 01219 up=0; 01220 #if VOROPP_VERBOSE >=1 01221 fputs("Order one collapse\n",stderr); 01222 #endif 01223 i=--mec[1]; 01224 j=mep[1][3*i];k=mep[1][3*i+1]; 01225 i=mep[1][3*i+2]; 01226 if(!delete_connection(vc,j,k,false)) return false; 01227 --p; 01228 if(up==i) up=0; 01229 if(p!=i) { 01230 if(up==p) up=i; 01231 pts[3*i]=pts[3*p]; 01232 pts[3*i+1]=pts[3*p+1]; 01233 pts[3*i+2]=pts[3*p+2]; 01234 for(k=0;k<nu[p];k++) ed[ed[p][k]][ed[p][nu[p]+k]]=i; 01235 vc.n_copy_pointer(i,p); 01236 ed[i]=ed[p]; 01237 nu[i]=nu[p]; 01238 ed[i][nu[i]<<1]=i; 01239 } 01240 } 01241 return true; 01242 } 01243 01244 /** This routine deletes the kth edge of vertex j and reorganizes the memory. 01245 * If the neighbor computation is enabled, we also have to supply an handedness 01246 * flag to decide whether to preserve the plane on the left or right of the 01247 * connection. 01248 * \return False if a zero order vertex was formed, indicative of the cell 01249 * disappearing; true if the vertex removal was successful. */ 01250 template<class vc_class> 01251 inline bool voronoicell_base::delete_connection(vc_class &vc,int j,int k,bool hand) { 01252 int q=hand?k:cycle_up(k,j); 01253 int i=nu[j]-1,l,*edp,*edd,m; 01254 #if VOROPP_VERBOSE >=1 01255 if(i<1) { 01256 fputs("Zero order vertex formed\n",stderr); 01257 return false; 01258 } 01259 #endif 01260 if(mec[i]==mem[i]) add_memory(vc,i,ds2); 01261 vc.n_set_aux1(i); 01262 for(l=0;l<q;l++) vc.n_copy_aux1(j,l); 01263 while(l<i) { 01264 vc.n_copy_aux1_shift(j,l); 01265 l++; 01266 } 01267 edp=mep[i]+((i<<1)+1)*mec[i]++; 01268 edp[i<<1]=j; 01269 for(l=0;l<k;l++) { 01270 edp[l]=ed[j][l]; 01271 edp[l+i]=ed[j][l+nu[j]]; 01272 } 01273 while(l<i) { 01274 m=ed[j][l+1]; 01275 edp[l]=m; 01276 k=ed[j][l+nu[j]+1]; 01277 edp[l+i]=k; 01278 ed[m][nu[m]+k]--; 01279 l++; 01280 } 01281 01282 edd=mep[nu[j]]+((nu[j]<<1)+1)*--mec[nu[j]]; 01283 for(l=0;l<=(nu[j]<<1);l++) ed[j][l]=edd[l]; 01284 vc.n_set_aux2_copy(j,nu[j]); 01285 vc.n_set_to_aux2(edd[nu[j]<<1]); 01286 vc.n_set_to_aux1(j); 01287 ed[edd[nu[j]<<1]]=edd; 01288 ed[j]=edp; 01289 nu[j]=i; 01290 return true; 01291 } 01292 01293 /** Calculates the volume of the Voronoi cell, by decomposing the cell into 01294 * tetrahedra extending outward from the zeroth vertex, whose volumes are 01295 * evaluated using a scalar triple product. 01296 * \return A floating point number holding the calculated volume. */ 01297 double voronoicell_base::volume() { 01298 const double fe=1/48.0; 01299 double vol=0; 01300 int i,j,k,l,m,n; 01301 double ux,uy,uz,vx,vy,vz,wx,wy,wz; 01302 for(i=1;i<p;i++) { 01303 ux=*pts-pts[3*i]; 01304 uy=pts[1]-pts[3*i+1]; 01305 uz=pts[2]-pts[3*i+2]; 01306 for(j=0;j<nu[i];j++) { 01307 k=ed[i][j]; 01308 if(k>=0) { 01309 ed[i][j]=-1-k; 01310 l=cycle_up(ed[i][nu[i]+j],k); 01311 vx=pts[3*k]-*pts; 01312 vy=pts[3*k+1]-pts[1]; 01313 vz=pts[3*k+2]-pts[2]; 01314 m=ed[k][l];ed[k][l]=-1-m; 01315 while(m!=i) { 01316 n=cycle_up(ed[k][nu[k]+l],m); 01317 wx=pts[3*m]-*pts; 01318 wy=pts[3*m+1]-pts[1]; 01319 wz=pts[3*m+2]-pts[2]; 01320 vol+=ux*vy*wz+uy*vz*wx+uz*vx*wy-uz*vy*wx-uy*vx*wz-ux*vz*wy; 01321 k=m;l=n;vx=wx;vy=wy;vz=wz; 01322 m=ed[k][l];ed[k][l]=-1-m; 01323 } 01324 } 01325 } 01326 } 01327 reset_edges(); 01328 return vol*fe; 01329 } 01330 01331 /** Calculates the areas of each face of the Voronoi cell and prints the 01332 * results to an output stream. 01333 * \param[out] v the vector to store the results in. */ 01334 void voronoicell_base::face_areas(vector<double> &v) { 01335 double area; 01336 v.clear(); 01337 int i,j,k,l,m,n; 01338 double ux,uy,uz,vx,vy,vz,wx,wy,wz; 01339 for(i=1;i<p;i++) for(j=0;j<nu[i];j++) { 01340 k=ed[i][j]; 01341 if(k>=0) { 01342 area=0; 01343 ed[i][j]=-1-k; 01344 l=cycle_up(ed[i][nu[i]+j],k); 01345 m=ed[k][l];ed[k][l]=-1-m; 01346 while(m!=i) { 01347 n=cycle_up(ed[k][nu[k]+l],m); 01348 ux=pts[3*k]-pts[3*i]; 01349 uy=pts[3*k+1]-pts[3*i+1]; 01350 uz=pts[3*k+2]-pts[3*i+2]; 01351 vx=pts[3*m]-pts[3*i]; 01352 vy=pts[3*m+1]-pts[3*i+1]; 01353 vz=pts[3*m+2]-pts[3*i+2]; 01354 wx=uy*vz-uz*vy; 01355 wy=uz*vx-ux*vz; 01356 wz=ux*vy-uy*vx; 01357 area+=sqrt(wx*wx+wy*wy+wz*wz); 01358 k=m;l=n; 01359 m=ed[k][l];ed[k][l]=-1-m; 01360 } 01361 v.push_back(0.125*area); 01362 } 01363 } 01364 reset_edges(); 01365 } 01366 01367 01368 /** Calculates the total surface area of the Voronoi cell. 01369 * \return The computed area. */ 01370 double voronoicell_base::surface_area() { 01371 double area=0; 01372 int i,j,k,l,m,n; 01373 double ux,uy,uz,vx,vy,vz,wx,wy,wz; 01374 for(i=1;i<p;i++) for(j=0;j<nu[i];j++) { 01375 k=ed[i][j]; 01376 if(k>=0) { 01377 ed[i][j]=-1-k; 01378 l=cycle_up(ed[i][nu[i]+j],k); 01379 m=ed[k][l];ed[k][l]=-1-m; 01380 while(m!=i) { 01381 n=cycle_up(ed[k][nu[k]+l],m); 01382 ux=pts[3*k]-pts[3*i]; 01383 uy=pts[3*k+1]-pts[3*i+1]; 01384 uz=pts[3*k+2]-pts[3*i+2]; 01385 vx=pts[3*m]-pts[3*i]; 01386 vy=pts[3*m+1]-pts[3*i+1]; 01387 vz=pts[3*m+2]-pts[3*i+2]; 01388 wx=uy*vz-uz*vy; 01389 wy=uz*vx-ux*vz; 01390 wz=ux*vy-uy*vx; 01391 area+=sqrt(wx*wx+wy*wy+wz*wz); 01392 k=m;l=n; 01393 m=ed[k][l];ed[k][l]=-1-m; 01394 } 01395 } 01396 } 01397 reset_edges(); 01398 return 0.125*area; 01399 } 01400 01401 01402 /** Calculates the centroid of the Voronoi cell, by decomposing the cell into 01403 * tetrahedra extending outward from the zeroth vertex. 01404 * \param[out] (cx,cy,cz) references to floating point numbers in which to 01405 * pass back the centroid vector. */ 01406 void voronoicell_base::centroid(double &cx,double &cy,double &cz) { 01407 double tvol,vol=0;cx=cy=cz=0; 01408 int i,j,k,l,m,n; 01409 double ux,uy,uz,vx,vy,vz,wx,wy,wz; 01410 for(i=1;i<p;i++) { 01411 ux=*pts-pts[3*i]; 01412 uy=pts[1]-pts[3*i+1]; 01413 uz=pts[2]-pts[3*i+2]; 01414 for(j=0;j<nu[i];j++) { 01415 k=ed[i][j]; 01416 if(k>=0) { 01417 ed[i][j]=-1-k; 01418 l=cycle_up(ed[i][nu[i]+j],k); 01419 vx=pts[3*k]-*pts; 01420 vy=pts[3*k+1]-pts[1]; 01421 vz=pts[3*k+2]-pts[2]; 01422 m=ed[k][l];ed[k][l]=-1-m; 01423 while(m!=i) { 01424 n=cycle_up(ed[k][nu[k]+l],m); 01425 wx=pts[3*m]-*pts; 01426 wy=pts[3*m+1]-pts[1]; 01427 wz=pts[3*m+2]-pts[2]; 01428 tvol=ux*vy*wz+uy*vz*wx+uz*vx*wy-uz*vy*wx-uy*vx*wz-ux*vz*wy; 01429 vol+=tvol; 01430 cx+=(wx+vx-ux)*tvol; 01431 cy+=(wy+vy-uy)*tvol; 01432 cz+=(wz+vz-uz)*tvol; 01433 k=m;l=n;vx=wx;vy=wy;vz=wz; 01434 m=ed[k][l];ed[k][l]=-1-m; 01435 } 01436 } 01437 } 01438 } 01439 reset_edges(); 01440 if(vol>tolerance_sq) { 01441 vol=0.125/vol; 01442 cx=cx*vol+0.5*(*pts); 01443 cy=cy*vol+0.5*pts[1]; 01444 cz=cz*vol+0.5*pts[2]; 01445 } else cx=cy=cz=0; 01446 } 01447 01448 /** Computes the maximum radius squared of a vertex from the center of the 01449 * cell. It can be used to determine when enough particles have been testing an 01450 * all planes that could cut the cell have been considered. 01451 * \return The maximum radius squared of a vertex.*/ 01452 double voronoicell_base::max_radius_squared() { 01453 double r,s,*ptsp=pts+3,*ptse=pts+3*p; 01454 r=*pts*(*pts)+pts[1]*pts[1]+pts[2]*pts[2]; 01455 while(ptsp<ptse) { 01456 s=*ptsp*(*ptsp);ptsp++; 01457 s+=*ptsp*(*ptsp);ptsp++; 01458 s+=*ptsp*(*ptsp);ptsp++; 01459 if(s>r) r=s; 01460 } 01461 return r; 01462 } 01463 01464 /** Calculates the total edge distance of the Voronoi cell. 01465 * \return A floating point number holding the calculated distance. */ 01466 double voronoicell_base::total_edge_distance() { 01467 int i,j,k; 01468 double dis=0,dx,dy,dz; 01469 for(i=0;i<p-1;i++) for(j=0;j<nu[i];j++) { 01470 k=ed[i][j]; 01471 if(k>i) { 01472 dx=pts[3*k]-pts[3*i]; 01473 dy=pts[3*k+1]-pts[3*i+1]; 01474 dz=pts[3*k+2]-pts[3*i+2]; 01475 dis+=sqrt(dx*dx+dy*dy+dz*dz); 01476 } 01477 } 01478 return 0.5*dis; 01479 } 01480 01481 /** Outputs the edges of the Voronoi cell in POV-Ray format to an open file 01482 * stream, displacing the cell by given vector. 01483 * \param[in] (x,y,z) a displacement vector to be added to the cell's position. 01484 * \param[in] fp a file handle to write to. */ 01485 void voronoicell_base::draw_pov(double x,double y,double z,FILE* fp) { 01486 int i,j,k;double *ptsp=pts,*pt2; 01487 char posbuf1[128],posbuf2[128]; 01488 for(i=0;i<p;i++,ptsp+=3) { 01489 sprintf(posbuf1,"%g,%g,%g",x+*ptsp*0.5,y+ptsp[1]*0.5,z+ptsp[2]*0.5); 01490 fprintf(fp,"sphere{<%s>,r}\n",posbuf1); 01491 for(j=0;j<nu[i];j++) { 01492 k=ed[i][j]; 01493 if(k<i) { 01494 pt2=pts+3*k; 01495 sprintf(posbuf2,"%g,%g,%g",x+*pt2*0.5,y+0.5*pt2[1],z+0.5*pt2[2]); 01496 if(strcmp(posbuf1,posbuf2)!=0) fprintf(fp,"cylinder{<%s>,<%s>,r}\n",posbuf1,posbuf2); 01497 } 01498 } 01499 } 01500 } 01501 01502 /** Outputs the edges of the Voronoi cell in gnuplot format to an output stream. 01503 * \param[in] (x,y,z) a displacement vector to be added to the cell's position. 01504 * \param[in] fp a file handle to write to. */ 01505 void voronoicell_base::draw_gnuplot(double x,double y,double z,FILE *fp) { 01506 int i,j,k,l,m; 01507 for(i=1;i<p;i++) for(j=0;j<nu[i];j++) { 01508 k=ed[i][j]; 01509 if(k>=0) { 01510 fprintf(fp,"%g %g %g\n",x+0.5*pts[3*i],y+0.5*pts[3*i+1],z+0.5*pts[3*i+2]); 01511 l=i;m=j; 01512 do { 01513 ed[k][ed[l][nu[l]+m]]=-1-l; 01514 ed[l][m]=-1-k; 01515 l=k; 01516 fprintf(fp,"%g %g %g\n",x+0.5*pts[3*k],y+0.5*pts[3*k+1],z+0.5*pts[3*k+2]); 01517 } while (search_edge(l,m,k)); 01518 fputs("\n\n",fp); 01519 } 01520 } 01521 reset_edges(); 01522 } 01523 01524 inline bool voronoicell_base::search_edge(int l,int &m,int &k) { 01525 for(m=0;m<nu[l];m++) { 01526 k=ed[l][m]; 01527 if(k>=0) return true; 01528 } 01529 return false; 01530 } 01531 01532 /** Outputs the Voronoi cell in the POV mesh2 format, described in section 01533 * 1.3.2.2 of the POV-Ray documentation. The mesh2 output consists of a list of 01534 * vertex vectors, followed by a list of triangular faces. The routine also 01535 * makes use of the optional inside_vector specification, which makes the mesh 01536 * object solid, so the the POV-Ray Constructive Solid Geometry (CSG) can be 01537 * applied. 01538 * \param[in] (x,y,z) a displacement vector to be added to the cell's position. 01539 * \param[in] fp a file handle to write to. */ 01540 void voronoicell_base::draw_pov_mesh(double x,double y,double z,FILE *fp) { 01541 int i,j,k,l,m,n; 01542 double *ptsp=pts; 01543 fprintf(fp,"mesh2 {\nvertex_vectors {\n%d\n",p); 01544 for(i=0;i<p;i++,ptsp+=3) fprintf(fp,",<%g,%g,%g>\n",x+*ptsp*0.5,y+ptsp[1]*0.5,z+ptsp[2]*0.5); 01545 fprintf(fp,"}\nface_indices {\n%d\n",(p-2)<<1); 01546 for(i=1;i<p;i++) for(j=0;j<nu[i];j++) { 01547 k=ed[i][j]; 01548 if(k>=0) { 01549 ed[i][j]=-1-k; 01550 l=cycle_up(ed[i][nu[i]+j],k); 01551 m=ed[k][l];ed[k][l]=-1-m; 01552 while(m!=i) { 01553 n=cycle_up(ed[k][nu[k]+l],m); 01554 fprintf(fp,",<%d,%d,%d>\n",i,k,m); 01555 k=m;l=n; 01556 m=ed[k][l];ed[k][l]=-1-m; 01557 } 01558 } 01559 } 01560 fputs("}\ninside_vector <0,0,1>\n}\n",fp); 01561 reset_edges(); 01562 } 01563 01564 /** Several routines in the class that gather cell-based statistics internally 01565 * track their progress by flipping edges to negative so that they know what 01566 * parts of the cell have already been tested. This function resets them back 01567 * to positive. When it is called, it assumes that every edge in the routine 01568 * should have already been flipped to negative, and it bails out with an 01569 * internal error if it encounters a positive edge. */ 01570 inline void voronoicell_base::reset_edges() { 01571 int i,j; 01572 for(i=0;i<p;i++) for(j=0;j<nu[i];j++) { 01573 if(ed[i][j]>=0) voro_fatal_error("Edge reset routine found a previously untested edge",VOROPP_INTERNAL_ERROR); 01574 ed[i][j]=-1-ed[i][j]; 01575 } 01576 } 01577 01578 /** Checks to see if a given vertex is inside, outside or within the test 01579 * plane. If the point is far away from the test plane, the routine immediately 01580 * returns whether it is inside or outside. If the routine is close the the 01581 * plane and within the specified tolerance, then the special check_marginal() 01582 * routine is called. 01583 * \param[in] n the vertex to test. 01584 * \param[out] ans the result of the scalar product used in evaluating the 01585 * location of the point. 01586 * \return -1 if the point is inside the plane, 1 if the point is outside the 01587 * plane, or 0 if the point is within the plane. */ 01588 inline int voronoicell_base::m_test(int n,double &ans) { 01589 double *pp=pts+n+(n<<1); 01590 ans=*(pp++)*px; 01591 ans+=*(pp++)*py; 01592 ans+=*pp*pz-prsq; 01593 if(ans<-tolerance2) { 01594 return -1; 01595 } else if(ans>tolerance2) { 01596 return 1; 01597 } 01598 return check_marginal(n,ans); 01599 } 01600 01601 /** Checks to see if a given vertex is inside, outside or within the test 01602 * plane, for the case when the point has been detected to be very close to the 01603 * plane. The routine ensures that the returned results are always consistent 01604 * with previous tests, by keeping a table of any marginal results. The routine 01605 * first sees if the vertex is in the table, and if it finds a previously 01606 * computed result it uses that. Otherwise, it computes a result for this 01607 * vertex and adds it the table. 01608 * \param[in] n the vertex to test. 01609 * \param[in] ans the result of the scalar product used in evaluating 01610 * the location of the point. 01611 * \return -1 if the point is inside the plane, 1 if the point is outside the 01612 * plane, or 0 if the point is within the plane. */ 01613 int voronoicell_base::check_marginal(int n,double &ans) { 01614 int i; 01615 for(i=0;i<n_marg;i+=2) if(marg[i]==n) return marg[i+1]; 01616 if(n_marg==current_marginal) { 01617 current_marginal<<=1; 01618 if(current_marginal>max_marginal) 01619 voro_fatal_error("Marginal case buffer allocation exceeded absolute maximum",VOROPP_MEMORY_ERROR); 01620 #if VOROPP_VERBOSE >=2 01621 fprintf(stderr,"Marginal cases buffer scaled up to %d\n",i); 01622 #endif 01623 int *pmarg=new int[current_marginal]; 01624 for(int j=0;j<n_marg;j++) pmarg[j]=marg[j]; 01625 delete [] marg; 01626 marg=pmarg; 01627 } 01628 marg[n_marg++]=n; 01629 marg[n_marg++]=ans>tolerance?1:(ans<-tolerance?-1:0); 01630 return marg[n_marg-1]; 01631 } 01632 01633 /** For each face of the Voronoi cell, this routine prints the out the normal 01634 * vector of the face, and scales it to the distance from the cell center to 01635 * that plane. 01636 * \param[out] v the vector to store the results in. */ 01637 void voronoicell_base::normals(vector<double> &v) { 01638 int i,j,k; 01639 v.clear(); 01640 for(i=1;i<p;i++) for(j=0;j<nu[i];j++) { 01641 k=ed[i][j]; 01642 if(k>=0) normals_search(v,i,j,k); 01643 } 01644 reset_edges(); 01645 } 01646 01647 /** This inline routine is called by normals(). It attempts to construct a 01648 * single normal vector that is associated with a particular face. It first 01649 * traces around the face, trying to find two vectors along the face edges 01650 * whose vector product is above the numerical tolerance. It then constructs 01651 * the normal vector using this product. If the face is too small, and none of 01652 * the vector products are large enough, the routine may return (0,0,0) as the 01653 * normal vector. 01654 * \param[in] v the vector to store the results in. 01655 * \param[in] i the initial vertex of the face to test. 01656 * \param[in] j the index of an edge of the vertex. 01657 * \param[in] k the neighboring vertex of i, set to ed[i][j]. */ 01658 inline void voronoicell_base::normals_search(vector<double> &v,int i,int j,int k) { 01659 ed[i][j]=-1-k; 01660 int l=cycle_up(ed[i][nu[i]+j],k),m; 01661 double ux,uy,uz,vx,vy,vz,wx,wy,wz,wmag; 01662 do { 01663 m=ed[k][l];ed[k][l]=-1-m; 01664 ux=pts[3*m]-pts[3*k]; 01665 uy=pts[3*m+1]-pts[3*k+1]; 01666 uz=pts[3*m+2]-pts[3*k+2]; 01667 01668 // Test to see if the length of this edge is above the tolerance 01669 if(ux*ux+uy*uy+uz*uz>tolerance_sq) { 01670 while(m!=i) { 01671 l=cycle_up(ed[k][nu[k]+l],m); 01672 k=m;m=ed[k][l];ed[k][l]=-1-m; 01673 vx=pts[3*m]-pts[3*k]; 01674 vy=pts[3*m+1]-pts[3*k+1]; 01675 vz=pts[3*m+2]-pts[3*k+2]; 01676 01677 // Construct the vector product of this edge with 01678 // the previous one 01679 wx=uz*vy-uy*vz; 01680 wy=ux*vz-uz*vx; 01681 wz=uy*vx-ux*vy; 01682 wmag=wx*wx+wy*wy+wz*wz; 01683 01684 // Test to see if this vector product of the 01685 // two edges is above the tolerance 01686 if(wmag>tolerance_sq) { 01687 01688 // Construct the normal vector and print it 01689 wmag=1/sqrt(wmag); 01690 v.push_back(wx*wmag); 01691 v.push_back(wy*wmag); 01692 v.push_back(wz*wmag); 01693 01694 // Mark all of the remaining edges of this 01695 // face and exit 01696 while(m!=i) { 01697 l=cycle_up(ed[k][nu[k]+l],m); 01698 k=m;m=ed[k][l];ed[k][l]=-1-m; 01699 } 01700 return; 01701 } 01702 } 01703 v.push_back(0); 01704 v.push_back(0); 01705 v.push_back(0); 01706 return; 01707 } 01708 l=cycle_up(ed[k][nu[k]+l],m); 01709 k=m; 01710 } while (k!=i); 01711 v.push_back(0); 01712 v.push_back(0); 01713 v.push_back(0); 01714 } 01715 01716 01717 /** Returns the number of faces of a computed Voronoi cell. 01718 * \return The number of faces. */ 01719 int voronoicell_base::number_of_faces() { 01720 int i,j,k,l,m,s=0; 01721 for(i=1;i<p;i++) for(j=0;j<nu[i];j++) { 01722 k=ed[i][j]; 01723 if(k>=0) { 01724 s++; 01725 ed[i][j]=-1-k; 01726 l=cycle_up(ed[i][nu[i]+j],k); 01727 do { 01728 m=ed[k][l]; 01729 ed[k][l]=-1-m; 01730 l=cycle_up(ed[k][nu[k]+l],m); 01731 k=m; 01732 } while (k!=i); 01733 01734 } 01735 } 01736 reset_edges(); 01737 return s; 01738 } 01739 01740 /** Returns a vector of the vertex orders. 01741 * \param[out] v the vector to store the results in. */ 01742 void voronoicell_base::vertex_orders(vector<int> &v) { 01743 v.resize(p); 01744 for(int i=0;i<p;i++) v[i]=nu[i]; 01745 } 01746 01747 /** Outputs the vertex orders. 01748 * \param[out] fp the file handle to write to. */ 01749 void voronoicell_base::output_vertex_orders(FILE *fp) { 01750 if(p>0) { 01751 fprintf(fp,"%d",*nu); 01752 for(int *nup=nu+1;nup<nu+p;nup++) fprintf(fp," %d",*nup); 01753 } 01754 } 01755 01756 /** Returns a vector of the vertex vectors using the local coordinate system. 01757 * \param[out] v the vector to store the results in. */ 01758 void voronoicell_base::vertices(vector<double> &v) { 01759 v.resize(3*p); 01760 double *ptsp=pts; 01761 for(int i=0;i<3*p;i+=3) { 01762 v[i]=*(ptsp++)*0.5; 01763 v[i+1]=*(ptsp++)*0.5; 01764 v[i+2]=*(ptsp++)*0.5; 01765 } 01766 } 01767 01768 /** Outputs the vertex vectors using the local coordinate system. 01769 * \param[out] fp the file handle to write to. */ 01770 void voronoicell_base::output_vertices(FILE *fp) { 01771 if(p>0) { 01772 fprintf(fp,"(%g,%g,%g)",*pts*0.5,pts[1]*0.5,pts[2]*0.5); 01773 for(double *ptsp=pts+3;ptsp<pts+3*p;ptsp+=3) fprintf(fp," (%g,%g,%g)",*ptsp*0.5,ptsp[1]*0.5,ptsp[2]*0.5); 01774 } 01775 } 01776 01777 01778 /** Returns a vector of the vertex vectors in the global coordinate system. 01779 * \param[out] v the vector to store the results in. 01780 * \param[in] (x,y,z) the position vector of the particle in the global 01781 * coordinate system. */ 01782 void voronoicell_base::vertices(double x,double y,double z,vector<double> &v) { 01783 v.resize(3*p); 01784 double *ptsp=pts; 01785 for(int i=0;i<3*p;i+=3) { 01786 v[i]=x+*(ptsp++)*0.5; 01787 v[i+1]=y+*(ptsp++)*0.5; 01788 v[i+2]=z+*(ptsp++)*0.5; 01789 } 01790 } 01791 01792 /** Outputs the vertex vectors using the global coordinate system. 01793 * \param[out] fp the file handle to write to. 01794 * \param[in] (x,y,z) the position vector of the particle in the global 01795 * coordinate system. */ 01796 void voronoicell_base::output_vertices(double x,double y,double z,FILE *fp) { 01797 if(p>0) { 01798 fprintf(fp,"(%g,%g,%g)",x+*pts*0.5,y+pts[1]*0.5,z+pts[2]*0.5); 01799 for(double *ptsp=pts+3;ptsp<pts+3*p;ptsp+=3) fprintf(fp," (%g,%g,%g)",x+*ptsp*0.5,y+ptsp[1]*0.5,z+ptsp[2]*0.5); 01800 } 01801 } 01802 01803 /** This routine returns the perimeters of each face. 01804 * \param[out] v the vector to store the results in. */ 01805 void voronoicell_base::face_perimeters(vector<double> &v) { 01806 v.clear(); 01807 int i,j,k,l,m; 01808 double dx,dy,dz,perim; 01809 for(i=1;i<p;i++) for(j=0;j<nu[i];j++) { 01810 k=ed[i][j]; 01811 if(k>=0) { 01812 dx=pts[3*k]-pts[3*i]; 01813 dy=pts[3*k+1]-pts[3*i+1]; 01814 dz=pts[3*k+2]-pts[3*i+2]; 01815 perim=sqrt(dx*dx+dy*dy+dz*dz); 01816 ed[i][j]=-1-k; 01817 l=cycle_up(ed[i][nu[i]+j],k); 01818 do { 01819 m=ed[k][l]; 01820 dx=pts[3*m]-pts[3*k]; 01821 dy=pts[3*m+1]-pts[3*k+1]; 01822 dz=pts[3*m+2]-pts[3*k+2]; 01823 perim+=sqrt(dx*dx+dy*dy+dz*dz); 01824 ed[k][l]=-1-m; 01825 l=cycle_up(ed[k][nu[k]+l],m); 01826 k=m; 01827 } while (k!=i); 01828 v.push_back(0.5*perim); 01829 } 01830 } 01831 reset_edges(); 01832 } 01833 01834 /** For each face, this routine outputs a bracketed sequence of numbers 01835 * containing a list of all the vertices that make up that face. 01836 * \param[out] v the vector to store the results in. */ 01837 void voronoicell_base::face_vertices(vector<int> &v) { 01838 int i,j,k,l,m,vp(0),vn; 01839 v.clear(); 01840 for(i=1;i<p;i++) for(j=0;j<nu[i];j++) { 01841 k=ed[i][j]; 01842 if(k>=0) { 01843 v.push_back(0); 01844 v.push_back(i); 01845 ed[i][j]=-1-k; 01846 l=cycle_up(ed[i][nu[i]+j],k); 01847 do { 01848 v.push_back(k); 01849 m=ed[k][l]; 01850 ed[k][l]=-1-m; 01851 l=cycle_up(ed[k][nu[k]+l],m); 01852 k=m; 01853 } while (k!=i); 01854 vn=v.size(); 01855 v[vp]=vn-vp-1; 01856 vp=vn; 01857 } 01858 } 01859 reset_edges(); 01860 } 01861 01862 /** Outputs a list of the number of edges in each face. 01863 * \param[out] v the vector to store the results in. */ 01864 void voronoicell_base::face_orders(vector<int> &v) { 01865 int i,j,k,l,m,q; 01866 v.clear(); 01867 for(i=1;i<p;i++) for(j=0;j<nu[i];j++) { 01868 k=ed[i][j]; 01869 if(k>=0) { 01870 q=1; 01871 ed[i][j]=-1-k; 01872 l=cycle_up(ed[i][nu[i]+j],k); 01873 do { 01874 q++; 01875 m=ed[k][l]; 01876 ed[k][l]=-1-m; 01877 l=cycle_up(ed[k][nu[k]+l],m); 01878 k=m; 01879 } while (k!=i); 01880 v.push_back(q);; 01881 } 01882 } 01883 reset_edges(); 01884 } 01885 01886 /** Computes the number of edges that each face has and outputs a frequency 01887 * table of the results. 01888 * \param[out] v the vector to store the results in. */ 01889 void voronoicell_base::face_freq_table(vector<int> &v) { 01890 int i,j,k,l,m,q; 01891 v.clear(); 01892 for(i=1;i<p;i++) for(j=0;j<nu[i];j++) { 01893 k=ed[i][j]; 01894 if(k>=0) { 01895 q=1; 01896 ed[i][j]=-1-k; 01897 l=cycle_up(ed[i][nu[i]+j],k); 01898 do { 01899 q++; 01900 m=ed[k][l]; 01901 ed[k][l]=-1-m; 01902 l=cycle_up(ed[k][nu[k]+l],m); 01903 k=m; 01904 } while (k!=i); 01905 if((unsigned int) q>=v.size()) v.resize(q+1,0); 01906 v[q]++; 01907 } 01908 } 01909 reset_edges(); 01910 } 01911 01912 /** This routine tests to see whether the cell intersects a plane by starting 01913 * from the guess point up. If up intersects, then it immediately returns true. 01914 * Otherwise, it calls the plane_intersects_track() routine. 01915 * \param[in] (x,y,z) the normal vector to the plane. 01916 * \param[in] rsq the distance along this vector of the plane. 01917 * \return False if the plane does not intersect the plane, true if it does. */ 01918 bool voronoicell_base::plane_intersects(double x,double y,double z,double rsq) { 01919 double g=x*pts[3*up]+y*pts[3*up+1]+z*pts[3*up+2]; 01920 if(g<rsq) return plane_intersects_track(x,y,z,rsq,g); 01921 return true; 01922 } 01923 01924 /** This routine tests to see if a cell intersects a plane. It first tests a 01925 * random sample of approximately sqrt(p)/4 points. If any of those are 01926 * intersect, then it immediately returns true. Otherwise, it takes the closest 01927 * point and passes that to plane_intersect_track() routine. 01928 * \param[in] (x,y,z) the normal vector to the plane. 01929 * \param[in] rsq the distance along this vector of the plane. 01930 * \return False if the plane does not intersect the plane, true if it does. */ 01931 bool voronoicell_base::plane_intersects_guess(double x,double y,double z,double rsq) { 01932 up=0; 01933 double g=x*pts[3*up]+y*pts[3*up+1]+z*pts[3*up+2]; 01934 if(g<rsq) { 01935 int ca=1,cc=p>>3,mp=1; 01936 double m; 01937 while(ca<cc) { 01938 m=x*pts[3*mp]+y*pts[3*mp+1]+z*pts[3*mp+2]; 01939 if(m>g) { 01940 if(m>rsq) return true; 01941 g=m;up=mp; 01942 } 01943 ca+=mp++; 01944 } 01945 return plane_intersects_track(x,y,z,rsq,g); 01946 } 01947 return true; 01948 } 01949 01950 /* This routine tests to see if a cell intersects a plane, by tracing over the cell from 01951 * vertex to vertex, starting at up. It is meant to be called either by plane_intersects() 01952 * or plane_intersects_track(), when those routines cannot immediately resolve the case. 01953 * \param[in] (x,y,z) the normal vector to the plane. 01954 * \param[in] rsq the distance along this vector of the plane. 01955 * \param[in] g the distance of up from the plane. 01956 * \return False if the plane does not intersect the plane, true if it does. */ 01957 inline bool voronoicell_base::plane_intersects_track(double x,double y,double z,double rsq,double g) { 01958 int count=0,ls,us,tp; 01959 double t; 01960 01961 // The test point is outside of the cutting space 01962 for(us=0;us<nu[up];us++) { 01963 tp=ed[up][us]; 01964 t=x*pts[3*tp]+y*pts[3*tp+1]+z*pts[3*tp+2]; 01965 if(t>g) { 01966 ls=ed[up][nu[up]+us]; 01967 up=tp; 01968 while (t<rsq) { 01969 if(++count>=p) { 01970 #if VOROPP_VERBOSE >=1 01971 fputs("Bailed out of convex calculation",stderr); 01972 #endif 01973 for(tp=0;tp<p;tp++) if(x*pts[3*tp]+y*pts[3*tp+1]+z*pts[3*tp+2]>rsq) return true; 01974 return false; 01975 } 01976 01977 // Test all the neighbors of the current point 01978 // and find the one which is closest to the 01979 // plane 01980 for(us=0;us<ls;us++) { 01981 tp=ed[up][us]; 01982 g=x*pts[3*tp]+y*pts[3*tp+1]+z*pts[3*tp+2]; 01983 if(g>t) break; 01984 } 01985 if(us==ls) { 01986 us++; 01987 while(us<nu[up]) { 01988 tp=ed[up][us]; 01989 g=x*pts[3*tp]+y*pts[3*tp+1]+z*pts[3*tp+2]; 01990 if(g>t) break; 01991 us++; 01992 } 01993 if(us==nu[up]) return false; 01994 } 01995 ls=ed[up][nu[up]+us];up=tp;t=g; 01996 } 01997 return true; 01998 } 01999 } 02000 return false; 02001 } 02002 02003 /** Counts the number of edges of the Voronoi cell. 02004 * \return the number of edges. */ 02005 int voronoicell_base::number_of_edges() { 02006 int edges=0,*nup=nu; 02007 while(nup<nu+p) edges+=*(nup++); 02008 return edges>>1; 02009 } 02010 02011 /** Outputs a custom string of information about the Voronoi cell. The string 02012 * of information follows a similar style as the C printf command, and detailed 02013 * information about its format is available at 02014 * http://math.lbl.gov/voro++/doc/custom.html. 02015 * \param[in] format the custom string to print. 02016 * \param[in] i the ID of the particle associated with this Voronoi cell. 02017 * \param[in] (x,y,z) the position of the particle associated with this Voronoi 02018 * cell. 02019 * \param[in] r a radius associated with the particle. 02020 * \param[in] fp the file handle to write to. */ 02021 void voronoicell_base::output_custom(const char *format,int i,double x,double y,double z,double r,FILE *fp) { 02022 char *fmp=(const_cast<char*>(format)); 02023 vector<int> vi; 02024 vector<double> vd; 02025 while(*fmp!=0) { 02026 if(*fmp=='%') { 02027 fmp++; 02028 switch(*fmp) { 02029 02030 // Particle-related output 02031 case 'i': fprintf(fp,"%d",i);break; 02032 case 'x': fprintf(fp,"%g",x);break; 02033 case 'y': fprintf(fp,"%g",y);break; 02034 case 'z': fprintf(fp,"%g",z);break; 02035 case 'q': fprintf(fp,"%g %g %g",x,y,z);break; 02036 case 'r': fprintf(fp,"%g",r);break; 02037 02038 // Vertex-related output 02039 case 'w': fprintf(fp,"%d",p);break; 02040 case 'p': output_vertices(fp);break; 02041 case 'P': output_vertices(x,y,z,fp);break; 02042 case 'o': output_vertex_orders(fp);break; 02043 case 'm': fprintf(fp,"%g",0.25*max_radius_squared());break; 02044 02045 // Edge-related output 02046 case 'g': fprintf(fp,"%d",number_of_edges());break; 02047 case 'E': fprintf(fp,"%g",total_edge_distance());break; 02048 case 'e': face_perimeters(vd);voro_print_vector(vd,fp);break; 02049 02050 // Face-related output 02051 case 's': fprintf(fp,"%d",number_of_faces());break; 02052 case 'F': fprintf(fp,"%g",surface_area());break; 02053 case 'A': { 02054 face_freq_table(vi); 02055 voro_print_vector(vi,fp); 02056 } break; 02057 case 'a': face_orders(vi);voro_print_vector(vi,fp);break; 02058 case 'f': face_areas(vd);voro_print_vector(vd,fp);break; 02059 case 't': { 02060 face_vertices(vi); 02061 voro_print_face_vertices(vi,fp); 02062 } break; 02063 case 'l': normals(vd); 02064 voro_print_positions(vd,fp); 02065 break; 02066 case 'n': neighbors(vi); 02067 voro_print_vector(vi,fp); 02068 break; 02069 02070 // Volume-related output 02071 case 'v': fprintf(fp,"%g",volume());break; 02072 case 'c': { 02073 double cx,cy,cz; 02074 centroid(cx,cy,cz); 02075 fprintf(fp,"%g %g %g",cx,cy,cz); 02076 } break; 02077 case 'C': { 02078 double cx,cy,cz; 02079 centroid(cx,cy,cz); 02080 fprintf(fp,"%g %g %g",x+cx,y+cy,z+cz); 02081 } break; 02082 02083 // End-of-string reached 02084 case 0: fmp--;break; 02085 02086 // The percent sign is not part of a 02087 // control sequence 02088 default: putc('%',fp);putc(*fmp,fp); 02089 } 02090 } else putc(*fmp,fp); 02091 fmp++; 02092 } 02093 fputs("\n",fp); 02094 } 02095 02096 /** This initializes the class to be a rectangular box. It calls the base class 02097 * initialization routine to set up the edge and vertex information, and then 02098 * sets up the neighbor information, with initial faces being assigned ID 02099 * numbers from -1 to -6. 02100 * \param[in] (xmin,xmax) the minimum and maximum x coordinates. 02101 * \param[in] (ymin,ymax) the minimum and maximum y coordinates. 02102 * \param[in] (zmin,zmax) the minimum and maximum z coordinates. */ 02103 void voronoicell_neighbor::init(double xmin,double xmax,double ymin,double ymax,double zmin,double zmax) { 02104 init_base(xmin,xmax,ymin,ymax,zmin,zmax); 02105 int *q=mne[3]; 02106 *q=-5;q[1]=-3;q[2]=-1; 02107 q[3]=-5;q[4]=-2;q[5]=-3; 02108 q[6]=-5;q[7]=-1;q[8]=-4; 02109 q[9]=-5;q[10]=-4;q[11]=-2; 02110 q[12]=-6;q[13]=-1;q[14]=-3; 02111 q[15]=-6;q[16]=-3;q[17]=-2; 02112 q[18]=-6;q[19]=-4;q[20]=-1; 02113 q[21]=-6;q[22]=-2;q[23]=-4; 02114 *ne=q;ne[1]=q+3;ne[2]=q+6;ne[3]=q+9; 02115 ne[4]=q+12;ne[5]=q+15;ne[6]=q+18;ne[7]=q+21; 02116 } 02117 02118 /** This initializes the class to be an octahedron. It calls the base class 02119 * initialization routine to set up the edge and vertex information, and then 02120 * sets up the neighbor information, with the initial faces being assigned ID 02121 * numbers from -1 to -8. 02122 * \param[in] l The distance from the octahedron center to a vertex. Six 02123 * vertices are initialized at (-l,0,0), (l,0,0), (0,-l,0), 02124 * (0,l,0), (0,0,-l), and (0,0,l). */ 02125 void voronoicell_neighbor::init_octahedron(double l) { 02126 init_octahedron_base(l); 02127 int *q=mne[4]; 02128 *q=-5;q[1]=-6;q[2]=-7;q[3]=-8; 02129 q[4]=-1;q[5]=-2;q[6]=-3;q[7]=-4; 02130 q[8]=-6;q[9]=-5;q[10]=-2;q[11]=-1; 02131 q[12]=-8;q[13]=-7;q[14]=-4;q[15]=-3; 02132 q[16]=-5;q[17]=-8;q[18]=-3;q[19]=-2; 02133 q[20]=-7;q[21]=-6;q[22]=-1;q[23]=-4; 02134 *ne=q;ne[1]=q+4;ne[2]=q+8;ne[3]=q+12;ne[4]=q+16;ne[5]=q+20; 02135 } 02136 02137 /** This initializes the class to be a tetrahedron. It calls the base class 02138 * initialization routine to set up the edge and vertex information, and then 02139 * sets up the neighbor information, with the initial faces being assigned ID 02140 * numbers from -1 to -4. 02141 * \param (x0,y0,z0) a position vector for the first vertex. 02142 * \param (x1,y1,z1) a position vector for the second vertex. 02143 * \param (x2,y2,z2) a position vector for the third vertex. 02144 * \param (x3,y3,z3) a position vector for the fourth vertex. */ 02145 void voronoicell_neighbor::init_tetrahedron(double x0,double y0,double z0,double x1,double y1,double z1,double x2,double y2,double z2,double x3,double y3,double z3) { 02146 init_tetrahedron_base(x0,y0,z0,x1,y1,z1,x2,y2,z2,x3,y3,z3); 02147 int *q=mne[3]; 02148 *q=-4;q[1]=-3;q[2]=-2; 02149 q[3]=-3;q[4]=-4;q[5]=-1; 02150 q[6]=-4;q[7]=-2;q[8]=-1; 02151 q[9]=-2;q[10]=-3;q[11]=-1; 02152 *ne=q;ne[1]=q+3;ne[2]=q+6;ne[3]=q+9; 02153 } 02154 02155 /** This routine checks to make sure the neighbor information of each face is 02156 * consistent. */ 02157 void voronoicell_neighbor::check_facets() { 02158 int i,j,k,l,m,q; 02159 for(i=1;i<p;i++) for(j=0;j<nu[i];j++) { 02160 k=ed[i][j]; 02161 if(k>=0) { 02162 ed[i][j]=-1-k; 02163 q=ne[i][j]; 02164 l=cycle_up(ed[i][nu[i]+j],k); 02165 do { 02166 m=ed[k][l]; 02167 ed[k][l]=-1-m; 02168 fprintf(stderr,"Facet error at (%d,%d)=%d, started from (%d,%d)=%d\n",k,l,ne[k][l],i,j,q); 02169 l=cycle_up(ed[k][nu[k]+l],m); 02170 k=m; 02171 } while (k!=i); 02172 } 02173 } 02174 reset_edges(); 02175 } 02176 02177 /** The class constructor allocates memory for storing neighbor information. */ 02178 voronoicell_neighbor::voronoicell_neighbor() { 02179 int i; 02180 mne=new int*[current_vertex_order]; 02181 ne=new int*[current_vertices]; 02182 for(i=0;i<3;i++) mne[i]=new int[init_n_vertices*i]; 02183 mne[3]=new int[init_3_vertices*3]; 02184 for(i=4;i<current_vertex_order;i++) mne[i]=new int[init_n_vertices*i]; 02185 } 02186 02187 /** The class destructor frees the dynamically allocated memory for storing 02188 * neighbor information. */ 02189 voronoicell_neighbor::~voronoicell_neighbor() { 02190 for(int i=current_vertex_order-1;i>=0;i--) if(mem[i]>0) delete [] mne[i]; 02191 delete [] mne; 02192 delete [] ne; 02193 } 02194 02195 /** Computes a vector list of neighbors. */ 02196 void voronoicell_neighbor::neighbors(vector<int> &v) { 02197 v.clear(); 02198 int i,j,k,l,m; 02199 for(i=1;i<p;i++) for(j=0;j<nu[i];j++) { 02200 k=ed[i][j]; 02201 if(k>=0) { 02202 v.push_back(ne[i][j]); 02203 ed[i][j]=-1-k; 02204 l=cycle_up(ed[i][nu[i]+j],k); 02205 do { 02206 m=ed[k][l]; 02207 ed[k][l]=-1-m; 02208 l=cycle_up(ed[k][nu[k]+l],m); 02209 k=m; 02210 } while (k!=i); 02211 } 02212 } 02213 reset_edges(); 02214 } 02215 02216 /** Prints the vertices, their edges, the relation table, and also notifies if 02217 * any memory errors are visible. */ 02218 void voronoicell_base::print_edges() { 02219 int j; 02220 double *ptsp=pts; 02221 for(int i=0;i<p;i++,ptsp+=3) { 02222 printf("%d %d ",i,nu[i]); 02223 for(j=0;j<nu[i];j++) printf(" %d",ed[i][j]); 02224 printf(" "); 02225 while(j<(nu[i]<<1)) printf(" %d",ed[i][j]); 02226 printf(" %d",ed[i][j]); 02227 print_edges_neighbors(i); 02228 printf(" %g %g %g %p",*ptsp,ptsp[1],ptsp[2],(void*) ed[i]); 02229 if(ed[i]>=mep[nu[i]]+mec[nu[i]]*((nu[i]<<1)+1)) puts(" Memory error"); 02230 else puts(""); 02231 } 02232 } 02233 02234 /** This prints out the neighbor information for vertex i. */ 02235 void voronoicell_neighbor::print_edges_neighbors(int i) { 02236 if(nu[i]>0) { 02237 int j=0; 02238 printf(" ("); 02239 while(j<nu[i]-1) printf("%d,",ne[i][j++]); 02240 printf("%d)",ne[i][j]); 02241 } else printf(" ()"); 02242 } 02243 02244 // Explicit instantiation 02245 template bool voronoicell_base::nplane(voronoicell&,double,double,double,double,int); 02246 template bool voronoicell_base::nplane(voronoicell_neighbor&,double,double,double,double,int); 02247 template void voronoicell_base::check_memory_for_copy(voronoicell&,voronoicell_base*); 02248 template void voronoicell_base::check_memory_for_copy(voronoicell_neighbor&,voronoicell_base*); 02249 02250 }