Voro++: cell.cc Source File

Voro++

- Main Page
- Data Structures
- Files

- File List
- Globals

cell.cc
Go to the documentation of this file.
1 // Voro++, a 3D cell-based Voronoi library
2 //
3 // Author : Chris H. Rycroft (LBL / UC Berkeley)
4 // Email : chr@alum.mit.edu
5 // Date : August 30th 2011
6
7 /** \file cell.cc
8 * \brief Function implementations for the voronoicell and related classes. */
9
10 #include <cmath>
11 #include <cstring>
12
13 #include "config.hh"
14 #include "common.hh"
15 #include "cell.hh"
16
17 namespace voro {
18
19 /** Constructs a Voronoi cell and sets up the initial memory. */
20 voronoicell_base::voronoicell_base() :
21 current_vertices(init_vertices), current_vertex_order(init_vertex_order),
22 current_delete_size(init_delete_size), current_delete2_size(init_delete2_size),
23 ed(new int*[current_vertices]), nu(new int[current_vertices]),
24 pts(new double[3*current_vertices]), mem(new int[current_vertex_order]),
25 mec(new int[current_vertex_order]), mep(new int*[current_vertex_order]),
26 ds(new int[current_delete_size]), stacke(ds+current_delete_size),
27 ds2(new int[current_delete2_size]), stacke2(ds2+current_delete_size),
28 current_marginal(init_marginal), marg(new int[current_marginal]) {
29 int i;
30 for(i=0;i<3;i++) {
31 mem[i]=init_n_vertices;mec[i]=0;
32 mep[i]=new int[init_n_vertices*((i<<1)+1)];
33 }
34 mem[3]=init_3_vertices;mec[3]=0;
35 mep[3]=new int[init_3_vertices*7];
36 for(i=4;i<current_vertex_order;i++) {
37 mem[i]=init_n_vertices;mec[i]=0;
38 mep[i]=new int[init_n_vertices*((i<<1)+1)];
39 }
40 }
41
42 /** The voronoicell destructor deallocates all the dynamic memory. */
43 voronoicell_base::~voronoicell_base() {
44 for(int i=current_vertex_order-1;i>=0;i--) if(mem[i]>0) delete [] mep[i];
45 delete [] marg;
46 delete [] ds2;delete [] ds;
47 delete [] mep;delete [] mec;
48 delete [] mem;delete [] pts;
49 delete [] nu;delete [] ed;
50 }
51
52 /** Ensures that enough memory is allocated prior to carrying out a copy.
53 * \param[in] vc a reference to the specialized version of the calling class.
54 * \param[in] vb a pointered to the class to be copied. */
55 template<class vc_class>
56 void voronoicell_base::check_memory_for_copy(vc_class &vc,voronoicell_base* vb) {
57 while(current_vertex_order<vb->current_vertex_order) add_memory_vorder(vc);
58 for(int i=0;i<current_vertex_order;i++) while(mem[i]<vb->mec[i]) add_memory(vc,i,ds2);
59 while(current_vertices<vb->p) add_memory_vertices(vc);
60 }
61
62 /** Copies the vertex and edge information from another class. The routine
63 * assumes that enough memory is available for the copy.
64 * \param[in] vb a pointer to the class to copy. */
65 void voronoicell_base::copy(voronoicell_base* vb) {
66 int i,j;
67 p=vb->p;up=0;
68 for(i=0;i<current_vertex_order;i++) {
69 mec[i]=vb->mec[i];
70 for(j=0;j<mec[i]*(2*i+1);j++) mep[i][j]=vb->mep[i][j];
71 for(j=0;j<mec[i]*(2*i+1);j+=2*i+1) ed[mep[i][j+2*i]]=mep[i]+j;
72 }
73 for(i=0;i<p;i++) nu[i]=vb->nu[i];
74 for(i=0;i<3*p;i++) pts[i]=vb->pts[i];
75 }
76
77 /** Copies the information from another voronoicell class into this
78 * class, extending memory allocation if necessary.
79 * \param[in] c the class to copy. */
80 void voronoicell_neighbor::operator=(voronoicell &c) {
81 voronoicell_base *vb=((voronoicell_base*) &c);
82 check_memory_for_copy(*this,vb);copy(vb);
83 int i,j;
84 for(i=0;i<c.current_vertex_order;i++) {
85 for(j=0;j<c.mec[i]*i;j++) mne[i][j]=0;
86 for(j=0;j<c.mec[i];j++) ne[c.mep[i][(2*i+1)*j+2*i]]=mne[i]+(j*i);
87 }
88 }
89
90 /** Copies the information from another voronoicell_neighbor class into this
91 * class, extending memory allocation if necessary.
92 * \param[in] c the class to copy. */
93 void voronoicell_neighbor::operator=(voronoicell_neighbor &c) {
94 voronoicell_base *vb=((voronoicell_base*) &c);
95 check_memory_for_copy(*this,vb);copy(vb);
96 int i,j;
97 for(i=0;i<c.current_vertex_order;i++) {
98 for(j=0;j<c.mec[i]*i;j++) mne[i][j]=c.mne[i][j];
99 for(j=0;j<c.mec[i];j++) ne[c.mep[i][(2*i+1)*j+2*i]]=mne[i]+(j*i);
100 }
101 }
102
103 /** Translates the vertices of the Voronoi cell by a given vector.
104 * \param[in] (x,y,z) the coordinates of the vector. */
105 void voronoicell_base::translate(double x,double y,double z) {
106 x*=2;y*=2;z*=2;
107 double *ptsp=pts;
108 while(ptsp<pts+3*p) {
109 *(ptsp++)=x;*(ptsp++)=y;*(ptsp++)=z;
110 }
111 }
112
113 /** Increases the memory storage for a particular vertex order, by increasing
114 * the size of the of the corresponding mep array. If the arrays already exist,
115 * their size is doubled; if they don't exist, then new ones of size
116 * init_n_vertices are allocated. The routine also ensures that the pointers in
117 * the ed array are updated, by making use of the back pointers. For the cases
118 * where the back pointer has been temporarily overwritten in the marginal
119 * vertex code, the auxiliary delete stack is scanned to find out how to update
120 * the ed value. If the template has been instantiated with the neighbor
121 * tracking turned on, then the routine also reallocates the corresponding mne
122 * array.
123 * \param[in] i the order of the vertex memory to be increased. */
124 template<class vc_class>
125 void voronoicell_base::add_memory(vc_class &vc,int i,int *stackp2) {
126 int s=(i<<1)+1;
127 if(mem[i]==0) {
128 vc.n_allocate(i,init_n_vertices);
129 mep[i]=new int[init_n_vertices*s];
130 mem[i]=init_n_vertices;
131 #if VOROPP_VERBOSE >=2
132 fprintf(stderr,"Order %d vertex memory created\n",i);
133 #endif
134 } else {
135 int j=0,k,*l;
136 mem[i]<<=1;
137 if(mem[i]>max_n_vertices) voro_fatal_error("Point memory allocation exceeded absolute maximum",VOROPP_MEMORY_ERROR);
138 #if VOROPP_VERBOSE >=2
139 fprintf(stderr,"Order %d vertex memory scaled up to %d\n",i,mem[i]);
140 #endif
141 l=new int[s*mem[i]];
142 int m=0;
143 vc.n_allocate_aux1(i);
144 while(j<s*mec[i]) {
145 k=mep[i][j+(i<<1)];
146 if(k>=0) {
147 ed[k]=l+j;
148 vc.n_set_to_aux1_offset(k,m);
149 } else {
150 int *dsp;
151 for(dsp=ds2;dsp<stackp2;dsp++) {
152 if(ed[*dsp]==mep[i]+j) {
153 ed[*dsp]=l+j;
154 vc.n_set_to_aux1_offset(*dsp,m);
155 break;
156 }
157 }
158 if(dsp==stackp2) voro_fatal_error("Couldn't relocate dangling pointer",VOROPP_INTERNAL_ERROR);
159 #if VOROPP_VERBOSE >=3
160 fputs("Relocated dangling pointer",stderr);
161 #endif
162 }
163 for(k=0;k<s;k++,j++) l[j]=mep[i][j];
164 for(k=0;k<i;k++,m++) vc.n_copy_to_aux1(i,m);
165 }
166 delete [] mep[i];
167 mep[i]=l;
168 vc.n_switch_to_aux1(i);
169 }
170 }
171
172 /** Doubles the maximum number of vertices allowed, by reallocating the ed, nu,
173 * and pts arrays. If the allocation exceeds the absolute maximum set in
174 * max_vertices, then the routine exits with a fatal error. If the template has
175 * been instantiated with the neighbor tracking turned on, then the routine
176 * also reallocates the ne array. */
177 template<class vc_class>
178 void voronoicell_base::add_memory_vertices(vc_class &vc) {
179 int i=(current_vertices<<1),j,**pp,*pnu;
180 if(i>max_vertices) voro_fatal_error("Vertex memory allocation exceeded absolute maximum",VOROPP_MEMORY_ERROR);
181 #if VOROPP_VERBOSE >=2
182 fprintf(stderr,"Vertex memory scaled up to %d\n",i);
183 #endif
184 double *ppts;
185 pp=new int*[i];
186 for(j=0;j<current_vertices;j++) pp[j]=ed[j];
187 delete [] ed;ed=pp;
188 vc.n_add_memory_vertices(i);
189 pnu=new int[i];
190 for(j=0;j<current_vertices;j++) pnu[j]=nu[j];
191 delete [] nu;nu=pnu;
192 ppts=new double[3*i];
193 for(j=0;j<3*current_vertices;j++) ppts[j]=pts[j];
194 delete [] pts;pts=ppts;
195 current_vertices=i;
196 }
197
198 /** Doubles the maximum allowed vertex order, by reallocating mem, mep, and mec
199 * arrays. If the allocation exceeds the absolute maximum set in
200 * max_vertex_order, then the routine causes a fatal error. If the template has
201 * been instantiated with the neighbor tracking turned on, then the routine
202 * also reallocates the mne array. */
203 template<class vc_class>
204 void voronoicell_base::add_memory_vorder(vc_class &vc) {
205 int i=(current_vertex_order<<1),j,*p1,**p2;
206 if(i>max_vertex_order) voro_fatal_error("Vertex order memory allocation exceeded absolute maximum",VOROPP_MEMORY_ERROR);
207 #if VOROPP_VERBOSE >=2
208 fprintf(stderr,"Vertex order memory scaled up to %d\n",i);
209 #endif
210 p1=new int[i];
211 for(j=0;j<current_vertex_order;j++) p1[j]=mem[j];while(j<i) p1[j++]=0;
212 delete [] mem;mem=p1;
213 p2=new int*[i];
214 for(j=0;j<current_vertex_order;j++) p2[j]=mep[j];
215 delete [] mep;mep=p2;
216 p1=new int[i];
217 for(j=0;j<current_vertex_order;j++) p1[j]=mec[j];while(j<i) p1[j++]=0;
218 delete [] mec;mec=p1;
219 vc.n_add_memory_vorder(i);
220 current_vertex_order=i;
221 }
222
223 /** Doubles the size allocation of the main delete stack. If the allocation
224 * exceeds the absolute maximum set in max_delete_size, then routine causes a
225 * fatal error. */
226 void voronoicell_base::add_memory_ds(int *&stackp) {
227 current_delete_size<<=1;
228 if(current_delete_size>max_delete_size) voro_fatal_error("Delete stack 1 memory allocation exceeded absolute maximum",VOROPP_MEMORY_ERROR);
229 #if VOROPP_VERBOSE >=2
230 fprintf(stderr,"Delete stack 1 memory scaled up to %d\n",current_delete_size);
231 #endif
232 int *dsn=new int[current_delete_size],*dsnp=dsn,*dsp=ds;
233 while(dsp<stackp) *(dsnp++)=*(dsp++);
234 delete [] ds;ds=dsn;stackp=dsnp;
235 stacke=ds+current_delete_size;
236 }
237
238 /** Doubles the size allocation of the auxiliary delete stack. If the
239 * allocation exceeds the absolute maximum set in max_delete2_size, then the
240 * routine causes a fatal error. */
241 void voronoicell_base::add_memory_ds2(int *&stackp2) {
242 current_delete2_size<<=1;
243 if(current_delete2_size>max_delete2_size) voro_fatal_error("Delete stack 2 memory allocation exceeded absolute maximum",VOROPP_MEMORY_ERROR);
244 #if VOROPP_VERBOSE >=2
245 fprintf(stderr,"Delete stack 2 memory scaled up to %d\n",current_delete2_size);
246 #endif
247 int *dsn=new int[current_delete2_size],*dsnp=dsn,*dsp=ds2;
248 while(dsp<stackp2) *(dsnp++)=*(dsp++);
249 delete [] ds2;ds2=dsn;stackp2=dsnp;
250 stacke2=ds2+current_delete2_size;
251 }
252
253 /** Initializes a Voronoi cell as a rectangular box with the given dimensions.
254 * \param[in] (xmin,xmax) the minimum and maximum x coordinates.
255 * \param[in] (ymin,ymax) the minimum and maximum y coordinates.
256 * \param[in] (zmin,zmax) the minimum and maximum z coordinates. */
257 void voronoicell_base::init_base(double xmin,double xmax,double ymin,double ymax,double zmin,double zmax) {
258 for(int i=0;i<current_vertex_order;i++) mec[i]=0;up=0;
259 mec[3]=p=8;xmin*=2;xmax*=2;ymin*=2;ymax*=2;zmin*=2;zmax*=2;
260 *pts=xmin;pts[1]=ymin;pts[2]=zmin;
261 pts[3]=xmax;pts[4]=ymin;pts[5]=zmin;
262 pts[6]=xmin;pts[7]=ymax;pts[8]=zmin;
263 pts[9]=xmax;pts[10]=ymax;pts[11]=zmin;
264 pts[12]=xmin;pts[13]=ymin;pts[14]=zmax;
265 pts[15]=xmax;pts[16]=ymin;pts[17]=zmax;
266 pts[18]=xmin;pts[19]=ymax;pts[20]=zmax;
267 pts[21]=xmax;pts[22]=ymax;pts[23]=zmax;
268 int *q=mep[3];
269 *q=1;q[1]=4;q[2]=2;q[3]=2;q[4]=1;q[5]=0;q[6]=0;
270 q[7]=3;q[8]=5;q[9]=0;q[10]=2;q[11]=1;q[12]=0;q[13]=1;
271 q[14]=0;q[15]=6;q[16]=3;q[17]=2;q[18]=1;q[19]=0;q[20]=2;
272 q[21]=2;q[22]=7;q[23]=1;q[24]=2;q[25]=1;q[26]=0;q[27]=3;
273 q[28]=6;q[29]=0;q[30]=5;q[31]=2;q[32]=1;q[33]=0;q[34]=4;
274 q[35]=4;q[36]=1;q[37]=7;q[38]=2;q[39]=1;q[40]=0;q[41]=5;
275 q[42]=7;q[43]=2;q[44]=4;q[45]=2;q[46]=1;q[47]=0;q[48]=6;
276 q[49]=5;q[50]=3;q[51]=6;q[52]=2;q[53]=1;q[54]=0;q[55]=7;
277 *ed=q;ed[1]=q+7;ed[2]=q+14;ed[3]=q+21;
278 ed[4]=q+28;ed[5]=q+35;ed[6]=q+42;ed[7]=q+49;
279 *nu=nu[1]=nu[2]=nu[3]=nu[4]=nu[5]=nu[6]=nu[7]=3;
280 }
281
282 /** Initializes a Voronoi cell as a regular octahedron.
283 * \param[in] l The distance from the octahedron center to a vertex. Six
284 * vertices are initialized at (-l,0,0), (l,0,0), (0,-l,0),
285 * (0,l,0), (0,0,-l), and (0,0,l). */
286 void voronoicell_base::init_octahedron_base(double l) {
287 for(int i=0;i<current_vertex_order;i++) mec[i]=0;up=0;
288 mec[4]=p=6;l*=2;
289 *pts=-l;pts[1]=0;pts[2]=0;
290 pts[3]=l;pts[4]=0;pts[5]=0;
291 pts[6]=0;pts[7]=-l;pts[8]=0;
292 pts[9]=0;pts[10]=l;pts[11]=0;
293 pts[12]=0;pts[13]=0;pts[14]=-l;
294 pts[15]=0;pts[16]=0;pts[17]=l;
295 int *q=mep[4];
296 *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;
297 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;
298 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;
299 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;
300 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;
301 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;
302 *ed=q;ed[1]=q+9;ed[2]=q+18;ed[3]=q+27;ed[4]=q+36;ed[5]=q+45;
303 *nu=nu[1]=nu[2]=nu[3]=nu[4]=nu[5]=4;
304 }
305
306 /** Initializes a Voronoi cell as a tetrahedron. It assumes that the normal to
307 * the face for the first three vertices points inside.
308 * \param (x0,y0,z0) a position vector for the first vertex.
309 * \param (x1,y1,z1) a position vector for the second vertex.
310 * \param (x2,y2,z2) a position vector for the third vertex.
311 * \param (x3,y3,z3) a position vector for the fourth vertex. */
312 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) {
313 for(int i=0;i<current_vertex_order;i++) mec[i]=0;up=0;
314 mec[3]=p=4;
315 *pts=x0*2;pts[1]=y0*2;pts[2]=z0*2;
316 pts[3]=x1*2;pts[4]=y1*2;pts[5]=z1*2;
317 pts[6]=x2*2;pts[7]=y2*2;pts[8]=z2*2;
318 pts[9]=x3*2;pts[10]=y3*2;pts[11]=z3*2;
319 int *q=mep[3];
320 *q=1;q[1]=3;q[2]=2;q[3]=0;q[4]=0;q[5]=0;q[6]=0;
321 q[7]=0;q[8]=2;q[9]=3;q[10]=0;q[11]=2;q[12]=1;q[13]=1;
322 q[14]=0;q[15]=3;q[16]=1;q[17]=2;q[18]=2;q[19]=1;q[20]=2;
323 q[21]=0;q[22]=1;q[23]=2;q[24]=1;q[25]=2;q[26]=1;q[27]=3;
324 *ed=q;ed[1]=q+7;ed[2]=q+14;ed[3]=q+21;
325 *nu=nu[1]=nu[2]=nu[3]=3;
326 }
327
328 /** Checks that the relational table of the Voronoi cell is accurate, and
329 * prints out any errors. This algorithm is O(p), so running it every time the
330 * plane routine is called will result in a significant slowdown. */
331 void voronoicell_base::check_relations() {
332 int i,j;
333 for(i=0;i<p;i++) for(j=0;j<nu[i];j++) if(ed[ed[i][j]][ed[i][nu[i]+j]]!=i)
334 printf("Relational error at point %d, edge %d.\n",i,j);
335 }
336
337 /** This routine checks for any two vertices that are connected by more than
338 * one edge. The plane algorithm is designed so that this should not happen, so
339 * any occurrences are most likely errors. Note that the routine is O(p), so
340 * running it every time the plane routine is called will result in a
341 * significant slowdown. */
342 void voronoicell_base::check_duplicates() {
343 int i,j,k;
344 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])
345 printf("Duplicate edges: (%d,%d) and (%d,%d) [%d]\n",i,j,i,k,ed[i][j]);
346 }
347
348 /** Constructs the relational table if the edges have been specified. */
349 void voronoicell_base::construct_relations() {
350 int i,j,k,l;
351 for(i=0;i<p;i++) for(j=0;j<nu[i];j++) {
352 k=ed[i][j];
353 l=0;
354 while(ed[k][l]!=i) {
355 l++;
356 if(l==nu[k]) voro_fatal_error("Relation table construction failed",VOROPP_INTERNAL_ERROR);
357 }
358 ed[i][nu[i]+j]=l;
359 }
360 }
361
362 /** Starting from a point within the current cutting plane, this routine attempts
363 * to find an edge to a point outside the cutting plane. This prevents the plane
364 * routine from .
365 * \param[in] vc a reference to the specialized version of the calling class.
366 * \param[in,out] up */
367 template<class vc_class>
368 inline bool voronoicell_base::search_for_outside_edge(vc_class &vc,int &up) {
369 int i,lp,lw,*j(ds2),*stackp2(ds2);
370 double l;
371 *(stackp2++)=up;
372 while(j<stackp2) {
373 up=*(j++);
374 for(i=0;i<nu[up];i++) {
375 lp=ed[up][i];
376 lw=m_test(lp,l);
377 if(lw==-1) return true;
378 else if(lw==0) add_to_stack(vc,lp,stackp2);
379 }
380 }
381 return false;
382 }
383
384 /** Adds a point to the auxiliary delete stack if it is not already there.
385 * \param[in] vc a reference to the specialized version of the calling class.
386 * \param[in] lp the index of the point to add.
387 * \param[in,out] stackp2 a pointer to the end of the stack entries. */
388 template<class vc_class>
389 inline void voronoicell_base::add_to_stack(vc_class &vc,int lp,int *&stackp2) {
390 for(int *k(ds2);k<stackp2;k++) if(*k==lp) return;
391 if(stackp2==stacke2) add_memory_ds2(stackp2);
392 *(stackp2++)=lp;
393 }
394
395 /** Cuts the Voronoi cell by a particle whose center is at a separation of
396 * (x,y,z) from the cell center. The value of rsq should be initially set to
397 * \f$x^2+y^2+z^2\f$.
398 * \param[in] vc a reference to the specialized version of the calling class.
399 * \param[in] (x,y,z) the normal vector to the plane.
400 * \param[in] rsq the distance along this vector of the plane.
401 * \param[in] p_id the plane ID (for neighbor tracking only).
402 * \return False if the plane cut deleted the cell entirely, true otherwise. */
403 template<class vc_class>
404 bool voronoicell_base::nplane(vc_class &vc,double x,double y,double z,double rsq,int p_id) {
405 int count=0,i,j,k,lp=up,cp,qp,rp,*stackp(ds),*stackp2(ds2),*dsp;
406 int us=0,ls=0,qs,iqs,cs,uw,qw,lw;
407 int *edp,*edd;
408 double u,l,r,q;bool complicated_setup=false,new_double_edge=false,double_edge=false;
409
410 // Initialize the safe testing routine
411 n_marg=0;px=x;py=y;pz=z;prsq=rsq;
412
413 // Test approximately sqrt(n)/4 points for their proximity to the plane
414 // and keep the one which is closest
415 uw=m_test(up,u);
416
417 // Starting from an initial guess, we now move from vertex to vertex,
418 // to try and find an edge which intersects the cutting plane,
419 // or a vertex which is on the plane
420 try {
421 if(uw==1) {
422
423 // The test point is inside the cutting plane.
424 us=0;
425 do {
426 lp=ed[up][us];
427 lw=m_test(lp,l);
428 if(l<u) break;
429 us++;
430 } while (us<nu[up]);
431
432 if(us==nu[up]) {
433 return false;
434 }
435
436 ls=ed[up][nu[up]+us];
437 while(lw==1) {
438 if(++count>=p) throw true;
439 u=l;up=lp;
440 for(us=0;us<ls;us++) {
441 lp=ed[up][us];
442 lw=m_test(lp,l);
443 if(l<u) break;
444 }
445 if(us==ls) {
446 us++;
447 while(us<nu[up]) {
448 lp=ed[up][us];
449 lw=m_test(lp,l);
450 if(l<u) break;
451 us++;
452 }
453 if(us==nu[up]) {
454 return false;
455 }
456 }
457 ls=ed[up][nu[up]+us];
458 }
459
460 // If the last point in the iteration is within the
461 // plane, we need to do the complicated setup
462 // routine. Otherwise, we use the regular iteration.
463 if(lw==0) {
464 up=lp;
465 complicated_setup=true;
466 } else complicated_setup=false;
467 } else if(uw==-1) {
468 us=0;
469 do {
470 qp=ed[up][us];
471 qw=m_test(qp,q);
472 if(u<q) break;
473 us++;
474 } while (us<nu[up]);
475 if(us==nu[up]) return true;
476
477 while(qw==-1) {
478 qs=ed[up][nu[up]+us];
479 if(++count>=p) throw true;
480 u=q;up=qp;
481 for(us=0;us<qs;us++) {
482 qp=ed[up][us];
483 qw=m_test(qp,q);
484 if(u<q) break;
485 }
486 if(us==qs) {
487 us++;
488 while(us<nu[up]) {
489 qp=ed[up][us];
490 qw=m_test(qp,q);
491 if(u<q) break;
492 us++;
493 }
494 if(us==nu[up]) return true;
495 }
496 }
497 if(qw==1) {
498 lp=up;ls=us;l=u;
499 up=qp;us=ed[lp][nu[lp]+ls];u=q;
500 complicated_setup=false;
501 } else {
502 up=qp;
503 complicated_setup=true;
504 }
505 } else {
506
507 // Our original test point was on the plane, so we
508 // automatically head for the complicated setup
509 // routine
510 complicated_setup=true;
511 }
512 }
513 catch(bool except) {
514 // This routine is a fall-back, in case floating point errors
515 // cause the usual search routine to fail. In the fall-back
516 // routine, we just test every edge to find one straddling
517 // the plane.
518 #if VOROPP_VERBOSE >=1
519 fputs("Bailed out of convex calculation\n",stderr);
520 #endif
521 qw=1;lw=0;
522 for(qp=0;qp<p;qp++) {
523 qw=m_test(qp,q);
524 if(qw==1) {
525
526 // The point is inside the cutting space. Now
527 // see if we can find a neighbor which isn't.
528 for(us=0;us<nu[qp];us++) {
529 lp=ed[qp][us];
530 if(lp<qp) {
531 lw=m_test(lp,l);
532 if(lw!=1) break;
533 }
534 }
535 if(us<nu[qp]) {
536 up=qp;
537 if(lw==0) {
538 complicated_setup=true;
539 } else {
540 complicated_setup=false;
541 u=q;
542 ls=ed[up][nu[up]+us];
543 }
544 break;
545 }
546 } else if(qw==-1) {
547
548 // The point is outside the cutting space. See
549 // if we can find a neighbor which isn't.
550 for(ls=0;ls<nu[qp];ls++) {
551 up=ed[qp][ls];
552 if(up<qp) {
553 uw=m_test(up,u);
554 if(uw!=-1) break;
555 }
556 }
557 if(ls<nu[qp]) {
558 if(uw==0) {
559 up=qp;
560 complicated_setup=true;
561 } else {
562 complicated_setup=false;
563 lp=qp;l=q;
564 us=ed[lp][nu[lp]+ls];
565 }
566 break;
567 }
568 } else {
569
570 // The point is in the plane, so we just
571 // proceed with the complicated setup routine
572 up=qp;
573 complicated_setup=true;
574 break;
575 }
576 }
577 if(qp==p) return qw==-1?true:false;
578 }
579
580 // We're about to add the first point of the new facet. In either
581 // routine, we have to add a point, so first check there's space for
582 // it.
583 if(p==current_vertices) add_memory_vertices(vc);
584
585 if(complicated_setup) {
586
587 // We want to be strict about reaching the conclusion that the
588 // cell is entirely within the cutting plane. It's not enough
589 // to find a vertex that has edges which are all inside or on
590 // the plane. If the vertex has neighbors that are also on the
591 // plane, we should check those too.
592 if(!search_for_outside_edge(vc,up)) return false;
593
594 // The search algorithm found a point which is on the cutting
595 // plane. We leave that point in place, and create a new one at
596 // the same location.
597 pts[3*p]=pts[3*up];
598 pts[3*p+1]=pts[3*up+1];
599 pts[3*p+2]=pts[3*up+2];
600
601 // Search for a collection of edges of the test vertex which
602 // are outside of the cutting space. Begin by testing the
603 // zeroth edge.
604 i=0;
605 lp=*ed[up];
606 lw=m_test(lp,l);
607 if(lw!=-1) {
608
609 // The first edge is either inside the cutting space,
610 // or lies within the cutting plane. Test the edges
611 // sequentially until we find one that is outside.
612 rp=lw;
613 do {
614 i++;
615
616 // If we reached the last edge with no luck
617 // then all of the vertices are inside
618 // or on the plane, so the cell is completely
619 // deleted
620 if(i==nu[up]) return false;
621 lp=ed[up][i];
622 lw=m_test(lp,l);
623 } while (lw!=-1);
624 j=i+1;
625
626 // We found an edge outside the cutting space. Keep
627 // moving through these edges until we find one that's
628 // inside or on the plane.
629 while(j<nu[up]) {
630 lp=ed[up][j];
631 lw=m_test(lp,l);
632 if(lw!=-1) break;
633 j++;
634 }
635
636 // Compute the number of edges for the new vertex. In
637 // general it will be the number of outside edges
638 // found, plus two. But we need to recognize the
639 // special case when all but one edge is outside, and
640 // the remaining one is on the plane. For that case we
641 // have to reduce the edge count by one to prevent
642 // doubling up.
643 if(j==nu[up]&&i==1&&rp==0) {
644 nu[p]=nu[up];
645 double_edge=true;
646 } else nu[p]=j-i+2;
647 k=1;
648
649 // Add memory for the new vertex if needed, and
650 // initialize
651 while (nu[p]>=current_vertex_order) add_memory_vorder(vc);
652 if(mec[nu[p]]==mem[nu[p]]) add_memory(vc,nu[p],stackp2);
653 vc.n_set_pointer(p,nu[p]);
654 ed[p]=mep[nu[p]]+((nu[p]<<1)+1)*mec[nu[p]]++;
655 ed[p][nu[p]<<1]=p;
656
657 // Copy the edges of the original vertex into the new
658 // one. Delete the edges of the original vertex, and
659 // update the relational table.
660 us=cycle_down(i,up);
661 while(i<j) {
662 qp=ed[up][i];
663 qs=ed[up][nu[up]+i];
664 vc.n_copy(p,k,up,i);
665 ed[p][k]=qp;
666 ed[p][nu[p]+k]=qs;
667 ed[qp][qs]=p;
668 ed[qp][nu[qp]+qs]=k;
669 ed[up][i]=-1;
670 i++;k++;
671 }
672 qs=i==nu[up]?0:i;
673 } else {
674
675 // In this case, the zeroth edge is outside the cutting
676 // plane. Begin by searching backwards from the last
677 // edge until we find an edge which isn't outside.
678 i=nu[up]-1;
679 lp=ed[up][i];
680 lw=m_test(lp,l);
681 while(lw==-1) {
682 i--;
683
684 // If i reaches zero, then we have a point in
685 // the plane all of whose edges are outside
686 // the cutting space, so we just exit
687 if(i==0) return true;
688 lp=ed[up][i];
689 lw=m_test(lp,l);
690 }
691
692 // Now search forwards from zero
693 j=1;
694 qp=ed[up][j];
695 qw=m_test(qp,q);
696 while(qw==-1) {
697 j++;
698 qp=ed[up][j];
699 qw=m_test(qp,l);
700 }
701
702 // Compute the number of edges for the new vertex. In
703 // general it will be the number of outside edges
704 // found, plus two. But we need to recognize the
705 // special case when all but one edge is outside, and
706 // the remaining one is on the plane. For that case we
707 // have to reduce the edge count by one to prevent
708 // doubling up.
709 if(i==j&&qw==0) {
710 double_edge=true;
711 nu[p]=nu[up];
712 } else {
713 nu[p]=nu[up]-i+j+1;
714 }
715
716 // Add memory to store the vertex if it doesn't exist
717 // already
718 k=1;
719 while(nu[p]>=current_vertex_order) add_memory_vorder(vc);
720 if(mec[nu[p]]==mem[nu[p]]) add_memory(vc,nu[p],stackp2);
721
722 // Copy the edges of the original vertex into the new
723 // one. Delete the edges of the original vertex, and
724 // update the relational table.
725 vc.n_set_pointer(p,nu[p]);
726 ed[p]=mep[nu[p]]+((nu[p]<<1)+1)*mec[nu[p]]++;
727 ed[p][nu[p]<<1]=p;
728 us=i++;
729 while(i<nu[up]) {
730 qp=ed[up][i];
731 qs=ed[up][nu[up]+i];
732 vc.n_copy(p,k,up,i);
733 ed[p][k]=qp;
734 ed[p][nu[p]+k]=qs;
735 ed[qp][qs]=p;
736 ed[qp][nu[qp]+qs]=k;
737 ed[up][i]=-1;
738 i++;k++;
739 }
740 i=0;
741 while(i<j) {
742 qp=ed[up][i];
743 qs=ed[up][nu[up]+i];
744 vc.n_copy(p,k,up,i);
745 ed[p][k]=qp;
746 ed[p][nu[p]+k]=qs;
747 ed[qp][qs]=p;
748 ed[qp][nu[qp]+qs]=k;
749 ed[up][i]=-1;
750 i++;k++;
751 }
752 qs=j;
753 }
754 if(!double_edge) {
755 vc.n_copy(p,k,up,qs);
756 vc.n_set(p,0,p_id);
757 } else vc.n_copy(p,0,up,qs);
758
759 // Add this point to the auxiliary delete stack
760 if(stackp2==stacke2) add_memory_ds2(stackp2);
761 *(stackp2++)=up;
762
763 // Look at the edges on either side of the group that was
764 // detected. We're going to commence facet computation by
765 // moving along one of them. We are going to end up coming back
766 // along the other one.
767 cs=k;
768 qp=up;q=u;
769 i=ed[up][us];
770 us=ed[up][nu[up]+us];
771 up=i;
772 ed[qp][nu[qp]<<1]=-p;
773
774 } else {
775
776 // The search algorithm found an intersected edge between the
777 // points lp and up. Create a new vertex between them which
778 // lies on the cutting plane. Since u and l differ by at least
779 // the tolerance, this division should never screw up.
780 if(stackp==stacke) add_memory_ds(stackp);
781 *(stackp++)=up;
782 r=u/(u-l);l=1-r;
783 pts[3*p]=pts[3*lp]*r+pts[3*up]*l;
784 pts[3*p+1]=pts[3*lp+1]*r+pts[3*up+1]*l;
785 pts[3*p+2]=pts[3*lp+2]*r+pts[3*up+2]*l;
786
787 // This point will always have three edges. Connect one of them
788 // to lp.
789 nu[p]=3;
790 if(mec[3]==mem[3]) add_memory(vc,3,stackp2);
791 vc.n_set_pointer(p,3);
792 vc.n_set(p,0,p_id);
793 vc.n_copy(p,1,up,us);
794 vc.n_copy(p,2,lp,ls);
795 ed[p]=mep[3]+7*mec[3]++;
796 ed[p][6]=p;
797 ed[up][us]=-1;
798 ed[lp][ls]=p;
799 ed[lp][nu[lp]+ls]=1;
800 ed[p][1]=lp;
801 ed[p][nu[p]+1]=ls;
802 cs=2;
803
804 // Set the direction to move in
805 qs=cycle_up(us,up);
806 qp=up;q=u;
807 }
808
809 // When the code reaches here, we have initialized the first point, and
810 // we have a direction for moving it to construct the rest of the facet
811 cp=p;rp=p;p++;
812 while(qp!=up||qs!=us) {
813
814 // We're currently tracing round an intersected facet. Keep
815 // moving around it until we find a point or edge which
816 // intersects the plane.
817 lp=ed[qp][qs];
818 lw=m_test(lp,l);
819
820 if(lw==1) {
821
822 // The point is still in the cutting space. Just add it
823 // to the delete stack and keep moving.
824 qs=cycle_up(ed[qp][nu[qp]+qs],lp);
825 qp=lp;
826 q=l;
827 if(stackp==stacke) add_memory_ds(stackp);
828 *(stackp++)=qp;
829
830 } else if(lw==-1) {
831
832 // The point is outside of the cutting space, so we've
833 // found an intersected edge. Introduce a regular point
834 // at the point of intersection. Connect it to the
835 // point we just tested. Also connect it to the previous
836 // new point in the facet we're constructing.
837 if(p==current_vertices) add_memory_vertices(vc);
838 r=q/(q-l);l=1-r;
839 pts[3*p]=pts[3*lp]*r+pts[3*qp]*l;
840 pts[3*p+1]=pts[3*lp+1]*r+pts[3*qp+1]*l;
841 pts[3*p+2]=pts[3*lp+2]*r+pts[3*qp+2]*l;
842 nu[p]=3;
843 if(mec[3]==mem[3]) add_memory(vc,3,stackp2);
844 ls=ed[qp][qs+nu[qp]];
845 vc.n_set_pointer(p,3);
846 vc.n_set(p,0,p_id);
847 vc.n_copy(p,1,qp,qs);
848 vc.n_copy(p,2,lp,ls);
849 ed[p]=mep[3]+7*mec[3]++;
850 *ed[p]=cp;
851 ed[p][1]=lp;
852 ed[p][3]=cs;
853 ed[p][4]=ls;
854 ed[p][6]=p;
855 ed[lp][ls]=p;
856 ed[lp][nu[lp]+ls]=1;
857 ed[cp][cs]=p;
858 ed[cp][nu[cp]+cs]=0;
859 ed[qp][qs]=-1;
860 qs=cycle_up(qs,qp);
861 cp=p++;
862 cs=2;
863 } else {
864
865 // We've found a point which is on the cutting plane.
866 // We're going to introduce a new point right here, but
867 // first we need to figure out the number of edges it
868 // has.
869 if(p==current_vertices) add_memory_vertices(vc);
870
871 // If the previous vertex detected a double edge, our
872 // new vertex will have one less edge.
873 k=double_edge?0:1;
874 qs=ed[qp][nu[qp]+qs];
875 qp=lp;
876 iqs=qs;
877
878 // Start testing the edges of the current point until
879 // we find one which isn't outside the cutting space
880 do {
881 k++;
882 qs=cycle_up(qs,qp);
883 lp=ed[qp][qs];
884 lw=m_test(lp,l);
885 } while (lw==-1);
886
887 // Now we need to find out whether this marginal vertex
888 // we are on has been visited before, because if that's
889 // the case, we need to add vertices to the existing
890 // new vertex, rather than creating a fresh one. We also
891 // need to figure out whether we're in a case where we
892 // might be creating a duplicate edge.
893 j=-ed[qp][nu[qp]<<1];
894 if(qp==up&&qs==us) {
895
896 // If we're heading into the final part of the
897 // new facet, then we never worry about the
898 // duplicate edge calculation.
899 new_double_edge=false;
900 if(j>0) k+=nu[j];
901 } else {
902 if(j>0) {
903
904 // This vertex was visited before, so
905 // count those vertices to the ones we
906 // already have.
907 k+=nu[j];
908
909 // The only time when we might make a
910 // duplicate edge is if the point we're
911 // going to move to next is also a
912 // marginal point, so test for that
913 // first.
914 if(lw==0) {
915
916 // Now see whether this marginal point
917 // has been visited before.
918 i=-ed[lp][nu[lp]<<1];
919 if(i>0) {
920
921 // Now see if the last edge of that other
922 // marginal point actually ends up here.
923 if(ed[i][nu[i]-1]==j) {
924 new_double_edge=true;
925 k-=1;
926 } else new_double_edge=false;
927 } else {
928
929 // That marginal point hasn't been visited
930 // before, so we probably don't have to worry
931 // about duplicate edges, except in the
932 // case when that's the way into the end
933 // of the facet, because that way always creates
934 // an edge.
935 if(j==rp&&lp==up&&ed[qp][nu[qp]+qs]==us) {
936 new_double_edge=true;
937 k-=1;
938 } else new_double_edge=false;
939 }
940 } else new_double_edge=false;
941 } else {
942
943 // The vertex hasn't been visited
944 // before, but let's see if it's
945 // marginal
946 if(lw==0) {
947
948 // If it is, we need to check
949 // for the case that it's a
950 // small branch, and that we're
951 // heading right back to where
952 // we came from
953 i=-ed[lp][nu[lp]<<1];
954 if(i==cp) {
955 new_double_edge=true;
956 k-=1;
957 } else new_double_edge=false;
958 } else new_double_edge=false;
959 }
960 }
961
962 // k now holds the number of edges of the new vertex
963 // we are forming. Add memory for it if it doesn't exist
964 // already.
965 while(k>=current_vertex_order) add_memory_vorder(vc);
966 if(mec[k]==mem[k]) add_memory(vc,k,stackp2);
967
968 // Now create a new vertex with order k, or augment
969 // the existing one
970 if(j>0) {
971
972 // If we're augmenting a vertex but we don't
973 // actually need any more edges, just skip this
974 // routine to avoid memory confusion
975 if(nu[j]!=k) {
976 // Allocate memory and copy the edges
977 // of the previous instance into it
978 vc.n_set_aux1(k);
979 edp=mep[k]+((k<<1)+1)*mec[k]++;
980 i=0;
981 while(i<nu[j]) {
982 vc.n_copy_aux1(j,i);
983 edp[i]=ed[j][i];
984 edp[k+i]=ed[j][nu[j]+i];
985 i++;
986 }
987 edp[k<<1]=j;
988
989 // Remove the previous instance with
990 // fewer vertices from the memory
991 // structure
992 edd=mep[nu[j]]+((nu[j]<<1)+1)*--mec[nu[j]];
993 if(edd!=ed[j]) {
994 for(lw=0;lw<=(nu[j]<<1);lw++) ed[j][lw]=edd[lw];
995 vc.n_set_aux2_copy(j,nu[j]);
996 vc.n_copy_pointer(edd[nu[j]<<1],j);
997 ed[edd[nu[j]<<1]]=ed[j];
998 }
999 vc.n_set_to_aux1(j);
1000 ed[j]=edp;
1001 } else i=nu[j];
1002 } else {
1003
1004 // Allocate a new vertex of order k
1005 vc.n_set_pointer(p,k);
1006 ed[p]=mep[k]+((k<<1)+1)*mec[k]++;
1007 ed[p][k<<1]=p;
1008 if(stackp2==stacke2) add_memory_ds2(stackp2);
1009 *(stackp2++)=qp;
1010 pts[3*p]=pts[3*qp];
1011 pts[3*p+1]=pts[3*qp+1];
1012 pts[3*p+2]=pts[3*qp+2];
1013 ed[qp][nu[qp]<<1]=-p;
1014 j=p++;
1015 i=0;
1016 }
1017 nu[j]=k;
1018
1019 // Unless the previous case was a double edge, connect
1020 // the first available edge of the new vertex to the
1021 // last one in the facet
1022 if(!double_edge) {
1023 ed[j][i]=cp;
1024 ed[j][nu[j]+i]=cs;
1025 vc.n_set(j,i,p_id);
1026 ed[cp][cs]=j;
1027 ed[cp][nu[cp]+cs]=i;
1028 i++;
1029 }
1030
1031 // Copy in the edges of the underlying vertex,
1032 // and do one less if this was a double edge
1033 qs=iqs;
1034 while(i<(new_double_edge?k:k-1)) {
1035 qs=cycle_up(qs,qp);
1036 lp=ed[qp][qs];ls=ed[qp][nu[qp]+qs];
1037 vc.n_copy(j,i,qp,qs);
1038 ed[j][i]=lp;
1039 ed[j][nu[j]+i]=ls;
1040 ed[lp][ls]=j;
1041 ed[lp][nu[lp]+ls]=i;
1042 ed[qp][qs]=-1;
1043 i++;
1044 }
1045 qs=cycle_up(qs,qp);
1046 cs=i;
1047 cp=j;
1048 vc.n_copy(j,new_double_edge?0:cs,qp,qs);
1049
1050 // Update the double_edge flag, to pass it
1051 // to the next instance of this routine
1052 double_edge=new_double_edge;
1053 }
1054 }
1055
1056 // Connect the final created vertex to the initial one
1057 ed[cp][cs]=rp;
1058 *ed[rp]=cp;
1059 ed[cp][nu[cp]+cs]=0;
1060 ed[rp][nu[rp]]=cs;
1061
1062 // Delete points: first, remove any duplicates
1063 dsp=ds;
1064 while(dsp<stackp) {
1065 j=*dsp;
1066 if(ed[j][nu[j]]!=-1) {
1067 ed[j][nu[j]]=-1;
1068 dsp++;
1069 } else *dsp=*(--stackp);
1070 }
1071
1072 // Add the points in the auxiliary delete stack,
1073 // and reset their back pointers
1074 for(dsp=ds2;dsp<stackp2;dsp++) {
1075 j=*dsp;
1076 ed[j][nu[j]<<1]=j;
1077 if(ed[j][nu[j]]!=-1) {
1078 ed[j][nu[j]]=-1;
1079 if(stackp==stacke) add_memory_ds(stackp);
1080 *(stackp++)=j;
1081 }
1082 }
1083
1084 // Scan connections and add in extras
1085 for(dsp=ds;dsp<stackp;dsp++) {
1086 cp=*dsp;
1087 for(edp=ed[cp];edp<ed[cp]+nu[cp];edp++) {
1088 qp=*edp;
1089 if(qp!=-1&&ed[qp][nu[qp]]!=-1) {
1090 if(stackp==stacke) {
1091 int dis=stackp-dsp;
1092 add_memory_ds(stackp);
1093 dsp=ds+dis;
1094 }
1095 *(stackp++)=qp;
1096 ed[qp][nu[qp]]=-1;
1097 }
1098 }
1099 }
1100 up=0;
1101
1102 // Delete them from the array structure
1103 while(stackp>ds) {
1104 --p;
1105 while(ed[p][nu[p]]==-1) {
1106 j=nu[p];
1107 edp=ed[p];edd=(mep[j]+((j<<1)+1)*--mec[j]);
1108 while(edp<ed[p]+(j<<1)+1) *(edp++)=*(edd++);
1109 vc.n_set_aux2_copy(p,j);
1110 vc.n_copy_pointer(ed[p][(j<<1)],p);
1111 ed[ed[p][(j<<1)]]=ed[p];
1112 --p;
1113 }
1114 up=*(--stackp);
1115 if(up<p) {
1116
1117 // Vertex management
1118 pts[3*up]=pts[3*p];
1119 pts[3*up+1]=pts[3*p+1];
1120 pts[3*up+2]=pts[3*p+2];
1121
1122 // Memory management
1123 j=nu[up];
1124 edp=ed[up];edd=(mep[j]+((j<<1)+1)*--mec[j]);
1125 while(edp<ed[up]+(j<<1)+1) *(edp++)=*(edd++);
1126 vc.n_set_aux2_copy(up,j);
1127 vc.n_copy_pointer(ed[up][j<<1],up);
1128 vc.n_copy_pointer(up,p);
1129 ed[ed[up][j<<1]]=ed[up];
1130
1131 // Edge management
1132 ed[up]=ed[p];
1133 nu[up]=nu[p];
1134 for(i=0;i<nu[up];i++) ed[ed[up][i]][ed[up][nu[up]+i]]=up;
1135 ed[up][nu[up]<<1]=up;
1136 } else up=p++;
1137 }
1138
1139 // Check for any vertices of zero order
1140 if(*mec>0) voro_fatal_error("Zero order vertex formed",VOROPP_INTERNAL_ERROR);
1141
1142 // Collapse any order 2 vertices and exit
1143 return collapse_order2(vc);
1144 }
1145
1146 /** During the creation of a new facet in the plane routine, it is possible
1147 * that some order two vertices may arise. This routine removes them.
1148 * Suppose an order two vertex joins c and d. If there's a edge between
1149 * c and d already, then the order two vertex is just removed; otherwise,
1150 * the order two vertex is removed and c and d are joined together directly.
1151 * It is possible this process will create order two or order one vertices,
1152 * and the routine is continually run until all of them are removed.
1153 * \return False if the vertex removal was unsuccessful, indicative of the cell
1154 * reducing to zero volume and disappearing; true if the vertex removal
1155 * was successful. */
1156 template<class vc_class>
1157 inline bool voronoicell_base::collapse_order2(vc_class &vc) {
1158 if(!collapse_order1(vc)) return false;
1159 int a,b,i,j,k,l;
1160 while(mec[2]>0) {
1161
1162 // Pick a order 2 vertex and read in its edges
1163 i=--mec[2];
1164 j=mep[2][5*i];k=mep[2][5*i+1];
1165 if(j==k) {
1166 #if VOROPP_VERBOSE >=1
1167 fputs("Order two vertex joins itself",stderr);
1168 #endif
1169 return false;
1170 }
1171
1172 // Scan the edges of j to see if joins k
1173 for(l=0;l<nu[j];l++) {
1174 if(ed[j][l]==k) break;
1175 }
1176
1177 // If j doesn't already join k, join them together.
1178 // Otherwise delete the connection to the current
1179 // vertex from j and k.
1180 a=mep[2][5*i+2];b=mep[2][5*i+3];i=mep[2][5*i+4];
1181 if(l==nu[j]) {
1182 ed[j][a]=k;
1183 ed[k][b]=j;
1184 ed[j][nu[j]+a]=b;
1185 ed[k][nu[k]+b]=a;
1186 } else {
1187 if(!delete_connection(vc,j,a,false)) return false;
1188 if(!delete_connection(vc,k,b,true)) return false;
1189 }
1190
1191 // Compact the memory
1192 --p;
1193 if(up==i) up=0;
1194 if(p!=i) {
1195 if(up==p) up=i;
1196 pts[3*i]=pts[3*p];
1197 pts[3*i+1]=pts[3*p+1];
1198 pts[3*i+2]=pts[3*p+2];
1199 for(k=0;k<nu[p];k++) ed[ed[p][k]][ed[p][nu[p]+k]]=i;
1200 vc.n_copy_pointer(i,p);
1201 ed[i]=ed[p];
1202 nu[i]=nu[p];
1203 ed[i][nu[i]<<1]=i;
1204 }
1205
1206 // Collapse any order 1 vertices if they were created
1207 if(!collapse_order1(vc)) return false;
1208 }
1209 return true;
1210 }
1211
1212 /** Order one vertices can potentially be created during the order two collapse
1213 * routine. This routine keeps removing them until there are none left.
1214 * \return False if the vertex removal was unsuccessful, indicative of the cell
1215 * having zero volume and disappearing; true if the vertex removal was
1216 * successful. */
1217 template<class vc_class>
1218 inline bool voronoicell_base::collapse_order1(vc_class &vc) {
1219 int i,j,k;
1220 while(mec[1]>0) {
1221 up=0;
1222 #if VOROPP_VERBOSE >=1
1223 fputs("Order one collapse\n",stderr);
1224 #endif
1225 i=--mec[1];
1226 j=mep[1][3*i];k=mep[1][3*i+1];
1227 i=mep[1][3*i+2];
1228 if(!delete_connection(vc,j,k,false)) return false;
1229 --p;
1230 if(up==i) up=0;
1231 if(p!=i) {
1232 if(up==p) up=i;
1233 pts[3*i]=pts[3*p];
1234 pts[3*i+1]=pts[3*p+1];
1235 pts[3*i+2]=pts[3*p+2];
1236 for(k=0;k<nu[p];k++) ed[ed[p][k]][ed[p][nu[p]+k]]=i;
1237 vc.n_copy_pointer(i,p);
1238 ed[i]=ed[p];
1239 nu[i]=nu[p];
1240 ed[i][nu[i]<<1]=i;
1241 }
1242 }
1243 return true;
1244 }
1245
1246 /** This routine deletes the kth edge of vertex j and reorganizes the memory.
1247 * If the neighbor computation is enabled, we also have to supply an handedness
1248 * flag to decide whether to preserve the plane on the left or right of the
1249 * connection.
1250 * \return False if a zero order vertex was formed, indicative of the cell
1251 * disappearing; true if the vertex removal was successful. */
1252 template<class vc_class>
1253 inline bool voronoicell_base::delete_connection(vc_class &vc,int j,int k,bool hand) {
1254 int q=hand?k:cycle_up(k,j);
1255 int i=nu[j]-1,l,*edp,*edd,m;
1256 #if VOROPP_VERBOSE >=1
1257 if(i<1) {
1258 fputs("Zero order vertex formed\n",stderr);
1259 return false;
1260 }
1261 #endif
1262 if(mec[i]==mem[i]) add_memory(vc,i,ds2);
1263 vc.n_set_aux1(i);
1264 for(l=0;l<q;l++) vc.n_copy_aux1(j,l);
1265 while(l<i) {
1266 vc.n_copy_aux1_shift(j,l);
1267 l++;
1268 }
1269 edp=mep[i]+((i<<1)+1)*mec[i]++;
1270 edp[i<<1]=j;
1271 for(l=0;l<k;l++) {
1272 edp[l]=ed[j][l];
1273 edp[l+i]=ed[j][l+nu[j]];
1274 }
1275 while(l<i) {
1276 m=ed[j][l+1];
1277 edp[l]=m;
1278 k=ed[j][l+nu[j]+1];
1279 edp[l+i]=k;
1280 ed[m][nu[m]+k]--;
1281 l++;
1282 }
1283
1284 edd=mep[nu[j]]+((nu[j]<<1)+1)*--mec[nu[j]];
1285 for(l=0;l<=(nu[j]<<1);l++) ed[j][l]=edd[l];
1286 vc.n_set_aux2_copy(j,nu[j]);
1287 vc.n_set_to_aux2(edd[nu[j]<<1]);
1288 vc.n_set_to_aux1(j);
1289 ed[edd[nu[j]<<1]]=edd;
1290 ed[j]=edp;
1291 nu[j]=i;
1292 return true;
1293 }
1294
1295 /** Calculates the volume of the Voronoi cell, by decomposing the cell into
1296 * tetrahedra extending outward from the zeroth vertex, whose volumes are
1297 * evaluated using a scalar triple product.
1298 * \return A floating point number holding the calculated volume. */
1299 double voronoicell_base::volume() {
1300 const double fe=1/48.0;
1301 double vol=0;
1302 int i,j,k,l,m,n;
1303 double ux,uy,uz,vx,vy,vz,wx,wy,wz;
1304 for(i=1;i<p;i++) {
1305 ux=*pts-pts[3*i];
1306 uy=pts[1]-pts[3*i+1];
1307 uz=pts[2]-pts[3*i+2];
1308 for(j=0;j<nu[i];j++) {
1309 k=ed[i][j];
1310 if(k>=0) {
1311 ed[i][j]=-1-k;
1312 l=cycle_up(ed[i][nu[i]+j],k);
1313 vx=pts[3*k]-*pts;
1314 vy=pts[3*k+1]-pts[1];
1315 vz=pts[3*k+2]-pts[2];
1316 m=ed[k][l];ed[k][l]=-1-m;
1317 while(m!=i) {
1318 n=cycle_up(ed[k][nu[k]+l],m);
1319 wx=pts[3*m]-*pts;
1320 wy=pts[3*m+1]-pts[1];
1321 wz=pts[3*m+2]-pts[2];
1322 vol+=ux*vy*wz+uy*vz*wx+uz*vx*wy-uz*vy*wx-uy*vx*wz-ux*vz*wy;
1323 k=m;l=n;vx=wx;vy=wy;vz=wz;
1324 m=ed[k][l];ed[k][l]=-1-m;
1325 }
1326 }
1327 }
1328 }
1329 reset_edges();
1330 return vol*fe;
1331 }
1332
1333 /** Calculates the areas of each face of the Voronoi cell and prints the
1334 * results to an output stream.
1335 * \param[out] v the vector to store the results in. */
1336 void voronoicell_base::face_areas(std::vector<double> &v) {
1337 double area;
1338 v.clear();
1339 int i,j,k,l,m,n;
1340 double ux,uy,uz,vx,vy,vz,wx,wy,wz;
1341 for(i=1;i<p;i++) for(j=0;j<nu[i];j++) {
1342 k=ed[i][j];
1343 if(k>=0) {
1344 area=0;
1345 ed[i][j]=-1-k;
1346 l=cycle_up(ed[i][nu[i]+j],k);
1347 m=ed[k][l];ed[k][l]=-1-m;
1348 while(m!=i) {
1349 n=cycle_up(ed[k][nu[k]+l],m);
1350 ux=pts[3*k]-pts[3*i];
1351 uy=pts[3*k+1]-pts[3*i+1];
1352 uz=pts[3*k+2]-pts[3*i+2];
1353 vx=pts[3*m]-pts[3*i];
1354 vy=pts[3*m+1]-pts[3*i+1];
1355 vz=pts[3*m+2]-pts[3*i+2];
1356 wx=uy*vz-uz*vy;
1357 wy=uz*vx-ux*vz;
1358 wz=ux*vy-uy*vx;
1359 area+=sqrt(wx*wx+wy*wy+wz*wz);
1360 k=m;l=n;
1361 m=ed[k][l];ed[k][l]=-1-m;
1362 }
1363 v.push_back(0.125*area);
1364 }
1365 }
1366 reset_edges();
1367 }
1368
1369
1370 /** Calculates the total surface area of the Voronoi cell.
1371 * \return The computed area. */
1372 double voronoicell_base::surface_area() {
1373 double area=0;
1374 int i,j,k,l,m,n;
1375 double ux,uy,uz,vx,vy,vz,wx,wy,wz;
1376 for(i=1;i<p;i++) for(j=0;j<nu[i];j++) {
1377 k=ed[i][j];
1378 if(k>=0) {
1379 ed[i][j]=-1-k;
1380 l=cycle_up(ed[i][nu[i]+j],k);
1381 m=ed[k][l];ed[k][l]=-1-m;
1382 while(m!=i) {
1383 n=cycle_up(ed[k][nu[k]+l],m);
1384 ux=pts[3*k]-pts[3*i];
1385 uy=pts[3*k+1]-pts[3*i+1];
1386 uz=pts[3*k+2]-pts[3*i+2];
1387 vx=pts[3*m]-pts[3*i];
1388 vy=pts[3*m+1]-pts[3*i+1];
1389 vz=pts[3*m+2]-pts[3*i+2];
1390 wx=uy*vz-uz*vy;
1391 wy=uz*vx-ux*vz;
1392 wz=ux*vy-uy*vx;
1393 area+=sqrt(wx*wx+wy*wy+wz*wz);
1394 k=m;l=n;
1395 m=ed[k][l];ed[k][l]=-1-m;
1396 }
1397 }
1398 }
1399 reset_edges();
1400 return 0.125*area;
1401 }
1402
1403
1404 /** Calculates the centroid of the Voronoi cell, by decomposing the cell into
1405 * tetrahedra extending outward from the zeroth vertex.
1406 * \param[out] (cx,cy,cz) references to floating point numbers in which to
1407 * pass back the centroid vector. */
1408 void voronoicell_base::centroid(double &cx,double &cy,double &cz) {
1409 double tvol,vol=0;cx=cy=cz=0;
1410 int i,j,k,l,m,n;
1411 double ux,uy,uz,vx,vy,vz,wx,wy,wz;
1412 for(i=1;i<p;i++) {
1413 ux=*pts-pts[3*i];
1414 uy=pts[1]-pts[3*i+1];
1415 uz=pts[2]-pts[3*i+2];
1416 for(j=0;j<nu[i];j++) {
1417 k=ed[i][j];
1418 if(k>=0) {
1419 ed[i][j]=-1-k;
1420 l=cycle_up(ed[i][nu[i]+j],k);
1421 vx=pts[3*k]-*pts;
1422 vy=pts[3*k+1]-pts[1];
1423 vz=pts[3*k+2]-pts[2];
1424 m=ed[k][l];ed[k][l]=-1-m;
1425 while(m!=i) {
1426 n=cycle_up(ed[k][nu[k]+l],m);
1427 wx=pts[3*m]-*pts;
1428 wy=pts[3*m+1]-pts[1];
1429 wz=pts[3*m+2]-pts[2];
1430 tvol=ux*vy*wz+uy*vz*wx+uz*vx*wy-uz*vy*wx-uy*vx*wz-ux*vz*wy;
1431 vol+=tvol;
1432 cx+=(wx+vx-ux)*tvol;
1433 cy+=(wy+vy-uy)*tvol;
1434 cz+=(wz+vz-uz)*tvol;
1435 k=m;l=n;vx=wx;vy=wy;vz=wz;
1436 m=ed[k][l];ed[k][l]=-1-m;
1437 }
1438 }
1439 }
1440 }
1441 reset_edges();
1442 if(vol>tolerance_sq) {
1443 vol=0.125/vol;
1444 cx=cx*vol+0.5*(*pts);
1445 cy=cy*vol+0.5*pts[1];
1446 cz=cz*vol+0.5*pts[2];
1447 } else cx=cy=cz=0;
1448 }
1449
1450 /** Computes the maximum radius squared of a vertex from the center of the
1451 * cell. It can be used to determine when enough particles have been testing an
1452 * all planes that could cut the cell have been considered.
1453 * \return The maximum radius squared of a vertex.*/
1454 double voronoicell_base::max_radius_squared() {
1455 double r,s,*ptsp=pts+3,*ptse=pts+3*p;
1456 r=*pts*(*pts)+pts[1]*pts[1]+pts[2]*pts[2];
1457 while(ptsp<ptse) {
1458 s=*ptsp*(*ptsp);ptsp++;
1459 s+=*ptsp*(*ptsp);ptsp++;
1460 s+=*ptsp*(*ptsp);ptsp++;
1461 if(s>r) r=s;
1462 }
1463 return r;
1464 }
1465
1466 /** Calculates the total edge distance of the Voronoi cell.
1467 * \return A floating point number holding the calculated distance. */
1468 double voronoicell_base::total_edge_distance() {
1469 int i,j,k;
1470 double dis=0,dx,dy,dz;
1471 for(i=0;i<p-1;i++) for(j=0;j<nu[i];j++) {
1472 k=ed[i][j];
1473 if(k>i) {
1474 dx=pts[3*k]-pts[3*i];
1475 dy=pts[3*k+1]-pts[3*i+1];
1476 dz=pts[3*k+2]-pts[3*i+2];
1477 dis+=sqrt(dx*dx+dy*dy+dz*dz);
1478 }
1479 }
1480 return 0.5*dis;
1481 }
1482
1483 /** Outputs the edges of the Voronoi cell in POV-Ray format to an open file
1484 * stream, displacing the cell by given vector.
1485 * \param[in] (x,y,z) a displacement vector to be added to the cell's position.
1486 * \param[in] fp a file handle to write to. */
1487 void voronoicell_base::draw_pov(double x,double y,double z,FILE* fp) {
1488 int i,j,k;double *ptsp=pts,*pt2;
1489 char posbuf1[128],posbuf2[128];
1490 for(i=0;i<p;i++,ptsp+=3) {
1491 sprintf(posbuf1,"%g,%g,%g",x+*ptsp*0.5,y+ptsp[1]*0.5,z+ptsp[2]*0.5);
1492 fprintf(fp,"sphere{<%s>,r}\n",posbuf1);
1493 for(j=0;j<nu[i];j++) {
1494 k=ed[i][j];
1495 if(k<i) {
1496 pt2=pts+3*k;
1497 sprintf(posbuf2,"%g,%g,%g",x+*pt2*0.5,y+0.5*pt2[1],z+0.5*pt2[2]);
1498 if(strcmp(posbuf1,posbuf2)!=0) fprintf(fp,"cylinder{<%s>,<%s>,r}\n",posbuf1,posbuf2);
1499 }
1500 }
1501 }
1502 }
1503
1504 /** Outputs the edges of the Voronoi cell in gnuplot format to an output stream.
1505 * \param[in] (x,y,z) a displacement vector to be added to the cell's position.
1506 * \param[in] fp a file handle to write to. */
1507 void voronoicell_base::draw_gnuplot(double x,double y,double z,FILE *fp) {
1508 int i,j,k,l,m;
1509 for(i=1;i<p;i++) for(j=0;j<nu[i];j++) {
1510 k=ed[i][j];
1511 if(k>=0) {
1512 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]);
1513 l=i;m=j;
1514 do {
1515 ed[k][ed[l][nu[l]+m]]=-1-l;
1516 ed[l][m]=-1-k;
1517 l=k;
1518 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]);
1519 } while (search_edge(l,m,k));
1520 fputs("\n\n",fp);
1521 }
1522 }
1523 reset_edges();
1524 }
1525
1526 inline bool voronoicell_base::search_edge(int l,int &m,int &k) {
1527 for(m=0;m<nu[l];m++) {
1528 k=ed[l][m];
1529 if(k>=0) return true;
1530 }
1531 return false;
1532 }
1533
1534 /** Outputs the Voronoi cell in the POV mesh2 format, described in section
1535 * 1.3.2.2 of the POV-Ray documentation. The mesh2 output consists of a list of
1536 * vertex vectors, followed by a list of triangular faces. The routine also
1537 * makes use of the optional inside_vector specification, which makes the mesh
1538 * object solid, so the the POV-Ray Constructive Solid Geometry (CSG) can be
1539 * applied.
1540 * \param[in] (x,y,z) a displacement vector to be added to the cell's position.
1541 * \param[in] fp a file handle to write to. */
1542 void voronoicell_base::draw_pov_mesh(double x,double y,double z,FILE *fp) {
1543 int i,j,k,l,m,n;
1544 double *ptsp=pts;
1545 fprintf(fp,"mesh2 {\nvertex_vectors {\n%d\n",p);
1546 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);
1547 fprintf(fp,"}\nface_indices {\n%d\n",(p-2)<<1);
1548 for(i=1;i<p;i++) for(j=0;j<nu[i];j++) {
1549 k=ed[i][j];
1550 if(k>=0) {
1551 ed[i][j]=-1-k;
1552 l=cycle_up(ed[i][nu[i]+j],k);
1553 m=ed[k][l];ed[k][l]=-1-m;
1554 while(m!=i) {
1555 n=cycle_up(ed[k][nu[k]+l],m);
1556 fprintf(fp,",<%d,%d,%d>\n",i,k,m);
1557 k=m;l=n;
1558 m=ed[k][l];ed[k][l]=-1-m;
1559 }
1560 }
1561 }
1562 fputs("}\ninside_vector <0,0,1>\n}\n",fp);
1563 reset_edges();
1564 }
1565
1566 /** Several routines in the class that gather cell-based statistics internally
1567 * track their progress by flipping edges to negative so that they know what
1568 * parts of the cell have already been tested. This function resets them back
1569 * to positive. When it is called, it assumes that every edge in the routine
1570 * should have already been flipped to negative, and it bails out with an
1571 * internal error if it encounters a positive edge. */
1572 inline void voronoicell_base::reset_edges() {
1573 int i,j;
1574 for(i=0;i<p;i++) for(j=0;j<nu[i];j++) {
1575 if(ed[i][j]>=0) voro_fatal_error("Edge reset routine found a previously untested edge",VOROPP_INTERNAL_ERROR);
1576 ed[i][j]=-1-ed[i][j];
1577 }
1578 }
1579
1580 /** Checks to see if a given vertex is inside, outside or within the test
1581 * plane. If the point is far away from the test plane, the routine immediately
1582 * returns whether it is inside or outside. If the routine is close the the
1583 * plane and within the specified tolerance, then the special check_marginal()
1584 * routine is called.
1585 * \param[in] n the vertex to test.
1586 * \param[out] ans the result of the scalar product used in evaluating the
1587 * location of the point.
1588 * \return -1 if the point is inside the plane, 1 if the point is outside the
1589 * plane, or 0 if the point is within the plane. */
1590 inline int voronoicell_base::m_test(int n,double &ans) {
1591 double *pp=pts+n+(n<<1);
1592 ans=*(pp++)*px;
1593 ans+=*(pp++)*py;
1594 ans+=*pp*pz-prsq;
1595 if(ans<-tolerance2) {
1596 return -1;
1597 } else if(ans>tolerance2) {
1598 return 1;
1599 }
1600 return check_marginal(n,ans);
1601 }
1602
1603 /** Checks to see if a given vertex is inside, outside or within the test
1604 * plane, for the case when the point has been detected to be very close to the
1605 * plane. The routine ensures that the returned results are always consistent
1606 * with previous tests, by keeping a table of any marginal results. The routine
1607 * first sees if the vertex is in the table, and if it finds a previously
1608 * computed result it uses that. Otherwise, it computes a result for this
1609 * vertex and adds it the table.
1610 * \param[in] n the vertex to test.
1611 * \param[in] ans the result of the scalar product used in evaluating
1612 * the location of the point.
1613 * \return -1 if the point is inside the plane, 1 if the point is outside the
1614 * plane, or 0 if the point is within the plane. */
1615 int voronoicell_base::check_marginal(int n,double &ans) {
1616 int i;
1617 for(i=0;i<n_marg;i+=2) if(marg[i]==n) return marg[i+1];
1618 if(n_marg==current_marginal) {
1619 current_marginal<<=1;
1620 if(current_marginal>max_marginal)
1621 voro_fatal_error("Marginal case buffer allocation exceeded absolute maximum",VOROPP_MEMORY_ERROR);
1622 #if VOROPP_VERBOSE >=2
1623 fprintf(stderr,"Marginal cases buffer scaled up to %d\n",i);
1624 #endif
1625 int *pmarg=new int[current_marginal];
1626 for(int j=0;j<n_marg;j++) pmarg[j]=marg[j];
1627 delete [] marg;
1628 marg=pmarg;
1629 }
1630 marg[n_marg++]=n;
1631 marg[n_marg++]=ans>tolerance?1:(ans<-tolerance?-1:0);
1632 return marg[n_marg-1];
1633 }
1634
1635 /** For each face of the Voronoi cell, this routine prints the out the normal
1636 * vector of the face, and scales it to the distance from the cell center to
1637 * that plane.
1638 * \param[out] v the vector to store the results in. */
1639 void voronoicell_base::normals(std::vector<double> &v) {
1640 int i,j,k;
1641 v.clear();
1642 for(i=1;i<p;i++) for(j=0;j<nu[i];j++) {
1643 k=ed[i][j];
1644 if(k>=0) normals_search(v,i,j,k);
1645 }
1646 reset_edges();
1647 }
1648
1649 /** This inline routine is called by normals(). It attempts to construct a
1650 * single normal vector that is associated with a particular face. It first
1651 * traces around the face, trying to find two vectors along the face edges
1652 * whose vector product is above the numerical tolerance. It then constructs
1653 * the normal vector using this product. If the face is too small, and none of
1654 * the vector products are large enough, the routine may return (0,0,0) as the
1655 * normal vector.
1656 * \param[in] v the vector to store the results in.
1657 * \param[in] i the initial vertex of the face to test.
1658 * \param[in] j the index of an edge of the vertex.
1659 * \param[in] k the neighboring vertex of i, set to ed[i][j]. */
1660 inline void voronoicell_base::normals_search(std::vector<double> &v,int i,int j,int k) {
1661 ed[i][j]=-1-k;
1662 int l=cycle_up(ed[i][nu[i]+j],k),m;
1663 double ux,uy,uz,vx,vy,vz,wx,wy,wz,wmag;
1664 do {
1665 m=ed[k][l];ed[k][l]=-1-m;
1666 ux=pts[3*m]-pts[3*k];
1667 uy=pts[3*m+1]-pts[3*k+1];
1668 uz=pts[3*m+2]-pts[3*k+2];
1669
1670 // Test to see if the length of this edge is above the tolerance
1671 if(ux*ux+uy*uy+uz*uz>tolerance_sq) {
1672 while(m!=i) {
1673 l=cycle_up(ed[k][nu[k]+l],m);
1674 k=m;m=ed[k][l];ed[k][l]=-1-m;
1675 vx=pts[3*m]-pts[3*k];
1676 vy=pts[3*m+1]-pts[3*k+1];
1677 vz=pts[3*m+2]-pts[3*k+2];
1678
1679 // Construct the vector product of this edge with
1680 // the previous one
1681 wx=uz*vy-uy*vz;
1682 wy=ux*vz-uz*vx;
1683 wz=uy*vx-ux*vy;
1684 wmag=wx*wx+wy*wy+wz*wz;
1685
1686 // Test to see if this vector product of the
1687 // two edges is above the tolerance
1688 if(wmag>tolerance_sq) {
1689
1690 // Construct the normal vector and print it
1691 wmag=1/sqrt(wmag);
1692 v.push_back(wx*wmag);
1693 v.push_back(wy*wmag);
1694 v.push_back(wz*wmag);
1695
1696 // Mark all of the remaining edges of this
1697 // face and exit
1698 while(m!=i) {
1699 l=cycle_up(ed[k][nu[k]+l],m);
1700 k=m;m=ed[k][l];ed[k][l]=-1-m;
1701 }
1702 return;
1703 }
1704 }
1705 v.push_back(0);
1706 v.push_back(0);
1707 v.push_back(0);
1708 return;
1709 }
1710 l=cycle_up(ed[k][nu[k]+l],m);
1711 k=m;
1712 } while (k!=i);
1713 v.push_back(0);
1714 v.push_back(0);
1715 v.push_back(0);
1716 }
1717
1718
1719 /** Returns the number of faces of a computed Voronoi cell.
1720 * \return The number of faces. */
1721 int voronoicell_base::number_of_faces() {
1722 int i,j,k,l,m,s=0;
1723 for(i=1;i<p;i++) for(j=0;j<nu[i];j++) {
1724 k=ed[i][j];
1725 if(k>=0) {
1726 s++;
1727 ed[i][j]=-1-k;
1728 l=cycle_up(ed[i][nu[i]+j],k);
1729 do {
1730 m=ed[k][l];
1731 ed[k][l]=-1-m;
1732 l=cycle_up(ed[k][nu[k]+l],m);
1733 k=m;
1734 } while (k!=i);
1735
1736 }
1737 }
1738 reset_edges();
1739 return s;
1740 }
1741
1742 /** Returns a vector of the vertex orders.
1743 * \param[out] v the vector to store the results in. */
1744 void voronoicell_base::vertex_orders(std::vector<int> &v) {
1745 v.resize(p);
1746 for(int i=0;i<p;i++) v[i]=nu[i];
1747 }
1748
1749 /** Outputs the vertex orders.
1750 * \param[out] fp the file handle to write to. */
1751 void voronoicell_base::output_vertex_orders(FILE *fp) {
1752 if(p>0) {
1753 fprintf(fp,"%d",*nu);
1754 for(int *nup=nu+1;nup<nu+p;nup++) fprintf(fp," %d",*nup);
1755 }
1756 }
1757
1758 /** Returns a vector of the vertex vectors using the local coordinate system.
1759 * \param[out] v the vector to store the results in. */
1760 void voronoicell_base::vertices(std::vector<double> &v) {
1761 v.resize(3*p);
1762 double *ptsp=pts;
1763 for(int i=0;i<3*p;i+=3) {
1764 v[i]=*(ptsp++)*0.5;
1765 v[i+1]=*(ptsp++)*0.5;
1766 v[i+2]=*(ptsp++)*0.5;
1767 }
1768 }
1769
1770 /** Outputs the vertex vectors using the local coordinate system.
1771 * \param[out] fp the file handle to write to. */
1772 void voronoicell_base::output_vertices(FILE *fp) {
1773 if(p>0) {
1774 fprintf(fp,"(%g,%g,%g)",*pts*0.5,pts[1]*0.5,pts[2]*0.5);
1775 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);
1776 }
1777 }
1778
1779
1780 /** Returns a vector of the vertex vectors in the global coordinate system.
1781 * \param[out] v the vector to store the results in.
1782 * \param[in] (x,y,z) the position vector of the particle in the global
1783 * coordinate system. */
1784 void voronoicell_base::vertices(double x,double y,double z,std::vector<double> &v) {
1785 v.resize(3*p);
1786 double *ptsp=pts;
1787 for(int i=0;i<3*p;i+=3) {
1788 v[i]=x+*(ptsp++)*0.5;
1789 v[i+1]=y+*(ptsp++)*0.5;
1790 v[i+2]=z+*(ptsp++)*0.5;
1791 }
1792 }
1793
1794 /** Outputs the vertex vectors using the global coordinate system.
1795 * \param[out] fp the file handle to write to.
1796 * \param[in] (x,y,z) the position vector of the particle in the global
1797 * coordinate system. */
1798 void voronoicell_base::output_vertices(double x,double y,double z,FILE *fp) {
1799 if(p>0) {
1800 fprintf(fp,"(%g,%g,%g)",x+*pts*0.5,y+pts[1]*0.5,z+pts[2]*0.5);
1801 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);
1802 }
1803 }
1804
1805 /** This routine returns the perimeters of each face.
1806 * \param[out] v the vector to store the results in. */
1807 void voronoicell_base::face_perimeters(std::vector<double> &v) {
1808 v.clear();
1809 int i,j,k,l,m;
1810 double dx,dy,dz,perim;
1811 for(i=1;i<p;i++) for(j=0;j<nu[i];j++) {
1812 k=ed[i][j];
1813 if(k>=0) {
1814 dx=pts[3*k]-pts[3*i];
1815 dy=pts[3*k+1]-pts[3*i+1];
1816 dz=pts[3*k+2]-pts[3*i+2];
1817 perim=sqrt(dx*dx+dy*dy+dz*dz);
1818 ed[i][j]=-1-k;
1819 l=cycle_up(ed[i][nu[i]+j],k);
1820 do {
1821 m=ed[k][l];
1822 dx=pts[3*m]-pts[3*k];
1823 dy=pts[3*m+1]-pts[3*k+1];
1824 dz=pts[3*m+2]-pts[3*k+2];
1825 perim+=sqrt(dx*dx+dy*dy+dz*dz);
1826 ed[k][l]=-1-m;
1827 l=cycle_up(ed[k][nu[k]+l],m);
1828 k=m;
1829 } while (k!=i);
1830 v.push_back(0.5*perim);
1831 }
1832 }
1833 reset_edges();
1834 }
1835
1836 /** For each face, this routine outputs a bracketed sequence of numbers
1837 * containing a list of all the vertices that make up that face.
1838 * \param[out] v the vector to store the results in. */
1839 void voronoicell_base::face_vertices(std::vector<int> &v) {
1840 int i,j,k,l,m,vp(0),vn;
1841 v.clear();
1842 for(i=1;i<p;i++) for(j=0;j<nu[i];j++) {
1843 k=ed[i][j];
1844 if(k>=0) {
1845 v.push_back(0);
1846 v.push_back(i);
1847 ed[i][j]=-1-k;
1848 l=cycle_up(ed[i][nu[i]+j],k);
1849 do {
1850 v.push_back(k);
1851 m=ed[k][l];
1852 ed[k][l]=-1-m;
1853 l=cycle_up(ed[k][nu[k]+l],m);
1854 k=m;
1855 } while (k!=i);
1856 vn=v.size();
1857 v[vp]=vn-vp-1;
1858 vp=vn;
1859 }
1860 }
1861 reset_edges();
1862 }
1863
1864 /** Outputs a list of the number of edges in each face.
1865 * \param[out] v the vector to store the results in. */
1866 void voronoicell_base::face_orders(std::vector<int> &v) {
1867 int i,j,k,l,m,q;
1868 v.clear();
1869 for(i=1;i<p;i++) for(j=0;j<nu[i];j++) {
1870 k=ed[i][j];
1871 if(k>=0) {
1872 q=1;
1873 ed[i][j]=-1-k;
1874 l=cycle_up(ed[i][nu[i]+j],k);
1875 do {
1876 q++;
1877 m=ed[k][l];
1878 ed[k][l]=-1-m;
1879 l=cycle_up(ed[k][nu[k]+l],m);
1880 k=m;
1881 } while (k!=i);
1882 v.push_back(q);;
1883 }
1884 }
1885 reset_edges();
1886 }
1887
1888 /** Computes the number of edges that each face has and outputs a frequency
1889 * table of the results.
1890 * \param[out] v the vector to store the results in. */
1891 void voronoicell_base::face_freq_table(std::vector<int> &v) {
1892 int i,j,k,l,m,q;
1893 v.clear();
1894 for(i=1;i<p;i++) for(j=0;j<nu[i];j++) {
1895 k=ed[i][j];
1896 if(k>=0) {
1897 q=1;
1898 ed[i][j]=-1-k;
1899 l=cycle_up(ed[i][nu[i]+j],k);
1900 do {
1901 q++;
1902 m=ed[k][l];
1903 ed[k][l]=-1-m;
1904 l=cycle_up(ed[k][nu[k]+l],m);
1905 k=m;
1906 } while (k!=i);
1907 if((unsigned int) q>=v.size()) v.resize(q+1,0);
1908 v[q]++;
1909 }
1910 }
1911 reset_edges();
1912 }
1913
1914 /** This routine tests to see whether the cell intersects a plane by starting
1915 * from the guess point up. If up intersects, then it immediately returns true.
1916 * Otherwise, it calls the plane_intersects_track() routine.
1917 * \param[in] (x,y,z) the normal vector to the plane.
1918 * \param[in] rsq the distance along this vector of the plane.
1919 * \return False if the plane does not intersect the plane, true if it does. */
1920 bool voronoicell_base::plane_intersects(double x,double y,double z,double rsq) {
1921 double g=x*pts[3*up]+y*pts[3*up+1]+z*pts[3*up+2];
1922 if(g<rsq) return plane_intersects_track(x,y,z,rsq,g);
1923 return true;
1924 }
1925
1926 /** This routine tests to see if a cell intersects a plane. It first tests a
1927 * random sample of approximately sqrt(p)/4 points. If any of those are
1928 * intersect, then it immediately returns true. Otherwise, it takes the closest
1929 * point and passes that to plane_intersect_track() routine.
1930 * \param[in] (x,y,z) the normal vector to the plane.
1931 * \param[in] rsq the distance along this vector of the plane.
1932 * \return False if the plane does not intersect the plane, true if it does. */
1933 bool voronoicell_base::plane_intersects_guess(double x,double y,double z,double rsq) {
1934 up=0;
1935 double g=x*pts[3*up]+y*pts[3*up+1]+z*pts[3*up+2];
1936 if(g<rsq) {
1937 int ca=1,cc=p>>3,mp=1;
1938 double m;
1939 while(ca<cc) {
1940 m=x*pts[3*mp]+y*pts[3*mp+1]+z*pts[3*mp+2];
1941 if(m>g) {
1942 if(m>rsq) return true;
1943 g=m;up=mp;
1944 }
1945 ca+=mp++;
1946 }
1947 return plane_intersects_track(x,y,z,rsq,g);
1948 }
1949 return true;
1950 }
1951
1952 /* This routine tests to see if a cell intersects a plane, by tracing over the cell from
1953 * vertex to vertex, starting at up. It is meant to be called either by plane_intersects()
1954 * or plane_intersects_track(), when those routines cannot immediately resolve the case.
1955 * \param[in] (x,y,z) the normal vector to the plane.
1956 * \param[in] rsq the distance along this vector of the plane.
1957 * \param[in] g the distance of up from the plane.
1958 * \return False if the plane does not intersect the plane, true if it does. */
1959 inline bool voronoicell_base::plane_intersects_track(double x,double y,double z,double rsq,double g) {
1960 int count=0,ls,us,tp;
1961 double t;
1962
1963 // The test point is outside of the cutting space
1964 for(us=0;us<nu[up];us++) {
1965 tp=ed[up][us];
1966 t=x*pts[3*tp]+y*pts[3*tp+1]+z*pts[3*tp+2];
1967 if(t>g) {
1968 ls=ed[up][nu[up]+us];
1969 up=tp;
1970 while (t<rsq) {
1971 if(++count>=p) {
1972 #if VOROPP_VERBOSE >=1
1973 fputs("Bailed out of convex calculation",stderr);
1974 #endif
1975 for(tp=0;tp<p;tp++) if(x*pts[3*tp]+y*pts[3*tp+1]+z*pts[3*tp+2]>rsq) return true;
1976 return false;
1977 }
1978
1979 // Test all the neighbors of the current point
1980 // and find the one which is closest to the
1981 // plane
1982 for(us=0;us<ls;us++) {
1983 tp=ed[up][us];
1984 g=x*pts[3*tp]+y*pts[3*tp+1]+z*pts[3*tp+2];
1985 if(g>t) break;
1986 }
1987 if(us==ls) {
1988 us++;
1989 while(us<nu[up]) {
1990 tp=ed[up][us];
1991 g=x*pts[3*tp]+y*pts[3*tp+1]+z*pts[3*tp+2];
1992 if(g>t) break;
1993 us++;
1994 }
1995 if(us==nu[up]) return false;
1996 }
1997 ls=ed[up][nu[up]+us];up=tp;t=g;
1998 }
1999 return true;
2000 }
2001 }
2002 return false;
2003 }
2004
2005 /** Counts the number of edges of the Voronoi cell.
2006 * \return the number of edges. */
2007 int voronoicell_base::number_of_edges() {
2008 int edges=0,*nup=nu;
2009 while(nup<nu+p) edges+=*(nup++);
2010 return edges>>1;
2011 }
2012
2013 /** Outputs a custom string of information about the Voronoi cell. The string
2014 * of information follows a similar style as the C printf command, and detailed
2015 * information about its format is available at
2016 * http://math.lbl.gov/voro++/doc/custom.html.
2017 * \param[in] format the custom string to print.
2018 * \param[in] i the ID of the particle associated with this Voronoi cell.
2019 * \param[in] (x,y,z) the position of the particle associated with this Voronoi
2020 * cell.
2021 * \param[in] r a radius associated with the particle.
2022 * \param[in] fp the file handle to write to. */
2023 void voronoicell_base::output_custom(const char *format,int i,double x,double y,double z,double r,FILE *fp) {
2024 char *fmp=(const_cast<char*>(format));
2025 std::vector<int> vi;
2026 std::vector<double> vd;
2027 while(*fmp!=0) {
2028 if(*fmp=='%') {
2029 fmp++;
2030 switch(*fmp) {
2031
2032 // Particle-related output
2033 case 'i': fprintf(fp,"%d",i);break;
2034 case 'x': fprintf(fp,"%g",x);break;
2035 case 'y': fprintf(fp,"%g",y);break;
2036 case 'z': fprintf(fp,"%g",z);break;
2037 case 'q': fprintf(fp,"%g %g %g",x,y,z);break;
2038 case 'r': fprintf(fp,"%g",r);break;
2039
2040 // Vertex-related output
2041 case 'w': fprintf(fp,"%d",p);break;
2042 case 'p': output_vertices(fp);break;
2043 case 'P': output_vertices(x,y,z,fp);break;
2044 case 'o': output_vertex_orders(fp);break;
2045 case 'm': fprintf(fp,"%g",0.25*max_radius_squared());break;
2046
2047 // Edge-related output
2048 case 'g': fprintf(fp,"%d",number_of_edges());break;
2049 case 'E': fprintf(fp,"%g",total_edge_distance());break;
2050 case 'e': face_perimeters(vd);voro_print_vector(vd,fp);break;
2051
2052 // Face-related output
2053 case 's': fprintf(fp,"%d",number_of_faces());break;
2054 case 'F': fprintf(fp,"%g",surface_area());break;
2055 case 'A': {
2056 face_freq_table(vi);
2057 voro_print_vector(vi,fp);
2058 } break;
2059 case 'a': face_orders(vi);voro_print_vector(vi,fp);break;
2060 case 'f': face_areas(vd);voro_print_vector(vd,fp);break;
2061 case 't': {
2062 face_vertices(vi);
2063 voro_print_face_vertices(vi,fp);
2064 } break;
2065 case 'l': normals(vd);
2066 voro_print_positions(vd,fp);
2067 break;
2068 case 'n': neighbors(vi);
2069 voro_print_vector(vi,fp);
2070 break;
2071
2072 // Volume-related output
2073 case 'v': fprintf(fp,"%g",volume());break;
2074 case 'c': {
2075 double cx,cy,cz;
2076 centroid(cx,cy,cz);
2077 fprintf(fp,"%g %g %g",cx,cy,cz);
2078 } break;
2079 case 'C': {
2080 double cx,cy,cz;
2081 centroid(cx,cy,cz);
2082 fprintf(fp,"%g %g %g",x+cx,y+cy,z+cz);
2083 } break;
2084
2085 // End-of-string reached
2086 case 0: fmp--;break;
2087
2088 // The percent sign is not part of a
2089 // control sequence
2090 default: putc('%',fp);putc(*fmp,fp);
2091 }
2092 } else putc(*fmp,fp);
2093 fmp++;
2094 }
2095 fputs("\n",fp);
2096 }
2097
2098 /** This initializes the class to be a rectangular box. It calls the base class
2099 * initialization routine to set up the edge and vertex information, and then
2100 * sets up the neighbor information, with initial faces being assigned ID
2101 * numbers from -1 to -6.
2102 * \param[in] (xmin,xmax) the minimum and maximum x coordinates.
2103 * \param[in] (ymin,ymax) the minimum and maximum y coordinates.
2104 * \param[in] (zmin,zmax) the minimum and maximum z coordinates. */
2105 void voronoicell_neighbor::init(double xmin,double xmax,double ymin,double ymax,double zmin,double zmax) {
2106 init_base(xmin,xmax,ymin,ymax,zmin,zmax);
2107 int *q=mne[3];
2108 *q=-5;q[1]=-3;q[2]=-1;
2109 q[3]=-5;q[4]=-2;q[5]=-3;
2110 q[6]=-5;q[7]=-1;q[8]=-4;
2111 q[9]=-5;q[10]=-4;q[11]=-2;
2112 q[12]=-6;q[13]=-1;q[14]=-3;
2113 q[15]=-6;q[16]=-3;q[17]=-2;
2114 q[18]=-6;q[19]=-4;q[20]=-1;
2115 q[21]=-6;q[22]=-2;q[23]=-4;
2116 *ne=q;ne[1]=q+3;ne[2]=q+6;ne[3]=q+9;
2117 ne[4]=q+12;ne[5]=q+15;ne[6]=q+18;ne[7]=q+21;
2118 }
2119
2120 /** This initializes the class to be an octahedron. It calls the base class
2121 * initialization routine to set up the edge and vertex information, and then
2122 * sets up the neighbor information, with the initial faces being assigned ID
2123 * numbers from -1 to -8.
2124 * \param[in] l The distance from the octahedron center to a vertex. Six
2125 * vertices are initialized at (-l,0,0), (l,0,0), (0,-l,0),
2126 * (0,l,0), (0,0,-l), and (0,0,l). */
2127 void voronoicell_neighbor::init_octahedron(double l) {
2128 init_octahedron_base(l);
2129 int *q=mne[4];
2130 *q=-5;q[1]=-6;q[2]=-7;q[3]=-8;
2131 q[4]=-1;q[5]=-2;q[6]=-3;q[7]=-4;
2132 q[8]=-6;q[9]=-5;q[10]=-2;q[11]=-1;
2133 q[12]=-8;q[13]=-7;q[14]=-4;q[15]=-3;
2134 q[16]=-5;q[17]=-8;q[18]=-3;q[19]=-2;
2135 q[20]=-7;q[21]=-6;q[22]=-1;q[23]=-4;
2136 *ne=q;ne[1]=q+4;ne[2]=q+8;ne[3]=q+12;ne[4]=q+16;ne[5]=q+20;
2137 }
2138
2139 /** This initializes the class to be a tetrahedron. It calls the base class
2140 * initialization routine to set up the edge and vertex information, and then
2141 * sets up the neighbor information, with the initial faces being assigned ID
2142 * numbers from -1 to -4.
2143 * \param (x0,y0,z0) a position vector for the first vertex.
2144 * \param (x1,y1,z1) a position vector for the second vertex.
2145 * \param (x2,y2,z2) a position vector for the third vertex.
2146 * \param (x3,y3,z3) a position vector for the fourth vertex. */
2147 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) {
2148 init_tetrahedron_base(x0,y0,z0,x1,y1,z1,x2,y2,z2,x3,y3,z3);
2149 int *q=mne[3];
2150 *q=-4;q[1]=-3;q[2]=-2;
2151 q[3]=-3;q[4]=-4;q[5]=-1;
2152 q[6]=-4;q[7]=-2;q[8]=-1;
2153 q[9]=-2;q[10]=-3;q[11]=-1;
2154 *ne=q;ne[1]=q+3;ne[2]=q+6;ne[3]=q+9;
2155 }
2156
2157 /** This routine checks to make sure the neighbor information of each face is
2158 * consistent. */
2159 void voronoicell_neighbor::check_facets() {
2160 int i,j,k,l,m,q;
2161 for(i=1;i<p;i++) for(j=0;j<nu[i];j++) {
2162 k=ed[i][j];
2163 if(k>=0) {
2164 ed[i][j]=-1-k;
2165 q=ne[i][j];
2166 l=cycle_up(ed[i][nu[i]+j],k);
2167 do {
2168 m=ed[k][l];
2169 ed[k][l]=-1-m;
2170 if(ne[k][l]!=q) fprintf(stderr,"Facet error at (%d,%d)=%d, started from (%d,%d)=%d\n",k,l,ne[k][l],i,j,q);
2171 l=cycle_up(ed[k][nu[k]+l],m);
2172 k=m;
2173 } while (k!=i);
2174 }
2175 }
2176 reset_edges();
2177 }
2178
2179 /** The class constructor allocates memory for storing neighbor information. */
2180 voronoicell_neighbor::voronoicell_neighbor() {
2181 int i;
2182 mne=new int*[current_vertex_order];
2183 ne=new int*[current_vertices];
2184 for(i=0;i<3;i++) mne[i]=new int[init_n_vertices*i];
2185 mne[3]=new int[init_3_vertices*3];
2186 for(i=4;i<current_vertex_order;i++) mne[i]=new int[init_n_vertices*i];
2187 }
2188
2189 /** The class destructor frees the dynamically allocated memory for storing
2190 * neighbor information. */
2191 voronoicell_neighbor::~voronoicell_neighbor() {
2192 for(int i=current_vertex_order-1;i>=0;i--) if(mem[i]>0) delete [] mne[i];
2193 delete [] mne;
2194 delete [] ne;
2195 }
2196
2197 /** Computes a vector list of neighbors. */
2198 void voronoicell_neighbor::neighbors(std::vector<int> &v) {
2199 v.clear();
2200 int i,j,k,l,m;
2201 for(i=1;i<p;i++) for(j=0;j<nu[i];j++) {
2202 k=ed[i][j];
2203 if(k>=0) {
2204 v.push_back(ne[i][j]);
2205 ed[i][j]=-1-k;
2206 l=cycle_up(ed[i][nu[i]+j],k);
2207 do {
2208 m=ed[k][l];
2209 ed[k][l]=-1-m;
2210 l=cycle_up(ed[k][nu[k]+l],m);
2211 k=m;
2212 } while (k!=i);
2213 }
2214 }
2215 reset_edges();
2216 }
2217
2218 /** Prints the vertices, their edges, the relation table, and also notifies if
2219 * any memory errors are visible. */
2220 void voronoicell_base::print_edges() {
2221 int j;
2222 double *ptsp=pts;
2223 for(int i=0;i<p;i++,ptsp+=3) {
2224 printf("%d %d ",i,nu[i]);
2225 for(j=0;j<nu[i];j++) printf(" %d",ed[i][j]);
2226 printf(" ");
2227 while(j<(nu[i]<<1)) printf(" %d",ed[i][j]);
2228 printf(" %d",ed[i][j]);
2229 print_edges_neighbors(i);
2230 printf(" %g %g %g %p",*ptsp,ptsp[1],ptsp[2],(void*) ed[i]);
2231 if(ed[i]>=mep[nu[i]]+mec[nu[i]]*((nu[i]<<1)+1)) puts(" Memory error");
2232 else puts("");
2233 }
2234 }
2235
2236 /** This prints out the neighbor information for vertex i. */
2237 void voronoicell_neighbor::print_edges_neighbors(int i) {
2238 if(nu[i]>0) {
2239 int j=0;
2240 printf(" (");
2241 while(j<nu[i]-1) printf("%d,",ne[i][j++]);
2242 printf("%d)",ne[i][j]);
2243 } else printf(" ()");
2244 }
2245
2246 // Explicit instantiation
2247 template bool voronoicell_base::nplane(voronoicell&,double,double,double,double,int);
2248 template bool voronoicell_base::nplane(voronoicell_neighbor&,double,double,double,double,int);
2249 template void voronoicell_base::check_memory_for_copy(voronoicell&,voronoicell_base*);
2250 template void voronoicell_base::check_memory_for_copy(voronoicell_neighbor&,voronoicell_base*);
2251
2252 }
voro::voronoicell_neighbor::init_tetrahedron
void 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)
Definition: cell.cc:2147
voro::voronoicell_base::output_vertex_orders
void output_vertex_orders(FILE *fp=stdout)
Definition: cell.cc:1751
voro::voronoicell_neighbor
Extension of the voronoicell_base class to represent a Voronoi cell with neighbor information...
Definition: cell.hh:403
voro::voronoicell_base::cycle_down
int cycle_down(int a, int p)
Definition: cell.hh:221
voro::voronoicell_base::centroid
void centroid(double &cx, double &cy, double &cz)
Definition: cell.cc:1408
voro::voronoicell_base::up
int up
Definition: cell.hh:60
voro::voronoicell_base::plane_intersects
bool plane_intersects(double x, double y, double z, double rsq)
Definition: cell.cc:1920
voro::voronoicell_base::face_areas
void face_areas(std::vector< double > &v)
Definition: cell.cc:1336
voro::voronoicell_base::reset_edges
void reset_edges()
Definition: cell.cc:1572
VOROPP_MEMORY_ERROR
#define VOROPP_MEMORY_ERROR
Definition: config.hh:113
voro::voronoicell_base::init_tetrahedron_base
void 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)
Definition: cell.cc:312
voro::voronoicell_base::draw_gnuplot
void draw_gnuplot(double x, double y, double z, FILE *fp=stdout)
Definition: cell.cc:1507
voro::voronoicell_base::neighbors
virtual void neighbors(std::vector< int > &v)
Definition: cell.hh:197
voro::voronoicell_base::mem
int * mem
Definition: cell.hh:225
voro::voronoicell_base::check_duplicates
void check_duplicates()
Definition: cell.cc:342
voro::voronoicell_base::mec
int * mec
Definition: cell.hh:229
voro::voronoicell_base::nu
int * nu
Definition: cell.hh:82
voro::voronoicell_base::construct_relations
void construct_relations()
Definition: cell.cc:349
voro::voronoicell_neighbor::ne
int ** ne
Definition: cell.hh:417
voro::voronoicell_base::current_vertices
int current_vertices
Definition: cell.hh:39
voro::voronoicell_neighbor::init
void init(double xmin, double xmax, double ymin, double ymax, double zmin, double zmax)
Definition: cell.cc:2105
voro::voronoicell_neighbor::print_edges_neighbors
virtual void print_edges_neighbors(int i)
Definition: cell.cc:2237
voro::voronoicell_base::p
int p
Definition: cell.hh:52
cell.hh
Header file for the voronoicell and related classes.
voro::voronoicell_base::current_vertex_order
int current_vertex_order
Definition: cell.hh:45
config.hh
Master configuration file for setting various compile-time options.
voro::voronoicell_base::ed
int ** ed
Definition: cell.hh:78
voro::voronoicell_base::nplane
bool nplane(vc_class &vc, double x, double y, double z, double rsq, int p_id)
Definition: cell.cc:404
voro::voronoicell_base::surface_area
double surface_area()
Definition: cell.cc:1372
voro::voronoicell_neighbor::init_octahedron
void init_octahedron(double l)
Definition: cell.cc:2127
voro::voronoicell_neighbor::neighbors
virtual void neighbors(std::vector< int > &v)
Definition: cell.cc:2198
voro::voronoicell_neighbor::~voronoicell_neighbor
~voronoicell_neighbor()
Definition: cell.cc:2191
voro::voronoicell_base::check_memory_for_copy
void check_memory_for_copy(vc_class &vc, voronoicell_base *vb)
Definition: cell.cc:56
voro::voronoicell_base::number_of_faces
int number_of_faces()
Definition: cell.cc:1721
VOROPP_INTERNAL_ERROR
#define VOROPP_INTERNAL_ERROR
Definition: config.hh:119
voro::voronoicell_base::vertices
void vertices(std::vector< double > &v)
Definition: cell.cc:1760
voro::voronoicell_base::pts
double * pts
Definition: cell.hh:85
voro::voronoicell_base::face_perimeters
void face_perimeters(std::vector< double > &v)
Definition: cell.cc:1807
voro::voronoicell_base::print_edges_neighbors
virtual void print_edges_neighbors(int i)
Definition: cell.hh:209
voro::voronoicell_base::current_delete2_size
int current_delete2_size
Definition: cell.hh:49
voro::voronoicell_neighbor::check_facets
void check_facets()
Definition: cell.cc:2159
voro::voronoicell_neighbor::voronoicell_neighbor
voronoicell_neighbor()
Definition: cell.cc:2180
voro::voronoicell_base::current_delete_size
int current_delete_size
Definition: cell.hh:47
voro::voronoicell_base::output_vertices
void output_vertices(FILE *fp=stdout)
Definition: cell.cc:1772
voro::voronoicell_neighbor::operator=
void operator=(voronoicell &c)
Definition: cell.cc:80
voro::voronoicell_base::number_of_edges
int number_of_edges()
Definition: cell.cc:2007
voro::voronoicell_base::draw_pov
void draw_pov(double x, double y, double z, FILE *fp=stdout)
Definition: cell.cc:1487
voro::voronoicell_base::max_radius_squared
double max_radius_squared()
Definition: cell.cc:1454
voro::voronoicell_neighbor::mne
int ** mne
Definition: cell.hh:410
voro::voronoicell_base::face_orders
void face_orders(std::vector< int > &v)
Definition: cell.cc:1866
voro::voronoicell_base::cycle_up
int cycle_up(int a, int p)
Definition: cell.hh:215
voro::voronoicell_base::face_vertices
void face_vertices(std::vector< int > &v)
Definition: cell.cc:1839
voro::voronoicell_base::init_octahedron_base
void init_octahedron_base(double l)
Definition: cell.cc:286
voro::voronoicell_base::plane_intersects_guess
bool plane_intersects_guess(double x, double y, double z, double rsq)
Definition: cell.cc:1933
voro::voronoicell_base::mep
int ** mep
Definition: cell.hh:237
common.hh
Header file for the small helper functions.
voro::voronoicell_base::total_edge_distance
double total_edge_distance()
Definition: cell.cc:1468
voro::voronoicell_base::copy
void copy(voronoicell_base *vb)
Definition: cell.cc:65
voro::voronoicell_base::face_freq_table
void face_freq_table(std::vector< int > &v)
Definition: cell.cc:1891
voro::voronoicell_base::output_custom
void output_custom(const char *format, FILE *fp=stdout)
Definition: cell.hh:182
voro::voronoicell_base
A class representing a single Voronoi cell.
Definition: cell.hh:33
voro::voronoicell
Extension of the voronoicell_base class to represent a Voronoi cell without neighbor information...
Definition: cell.hh:300
voro::voronoicell_base::~voronoicell_base
~voronoicell_base()
Definition: cell.cc:43
voro::voronoicell_base::draw_pov_mesh
void draw_pov_mesh(double x, double y, double z, FILE *fp=stdout)
Definition: cell.cc:1542
voro::voronoicell_base::init_base
void init_base(double xmin, double xmax, double ymin, double ymax, double zmin, double zmax)
Definition: cell.cc:257
voro::voronoicell_base::print_edges
void print_edges()
Definition: cell.cc:2220
voro::voronoicell_base::vertex_orders
void vertex_orders(std::vector< int > &v)
Definition: cell.cc:1744
voro::voronoicell_base::translate
void translate(double x, double y, double z)
Definition: cell.cc:105
voro::voronoicell_base::normals
void normals(std::vector< double > &v)
Definition: cell.cc:1639
voro::voronoicell_base::check_relations
void check_relations()
Definition: cell.cc:331
voro::voronoicell_base::volume
double volume()
Definition: cell.cc:1299
voro::voronoicell_base::voronoicell_base
voronoicell_base()
Definition: cell.cc:20