Voro++
cell.cc
Go to the documentation of this file.
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=0;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=0;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=0;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=0;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=0;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=0;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 }