Added volume / surface area routines.
[voro++.git] / trunk / src / cell.cc
blobdfa3d92d7e536a5b8a1814693e4eb66620716c33
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
7 /** \file cell.cc
8 * \brief Function implementations for the voronoicell and related classes. */
10 #include <cmath>
11 #include <cstring>
13 #include "config.hh"
14 #include "common.hh"
15 #include "cell.hh"
17 namespace voro {
19 /** Constructs a Voronoi cell and sets up the initial memory. */
20 voronoicell_base::voronoicell_base(double max_len_sq) :
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 current_xsearch_size(init_xsearch_size),
24 ed(new int*[current_vertices]), nu(new int[current_vertices]),
25 mask(new unsigned int[current_vertices]),
26 pts(new double[current_vertices<<2]), tol(tolerance*max_len_sq),
27 tol_cu(tol*sqrt(tol)), big_tol(big_tolerance_fac*tol), mem(new int[current_vertex_order]),
28 mec(new int[current_vertex_order]),
29 mep(new int*[current_vertex_order]), ds(new int[current_delete_size]),
30 stacke(ds+current_delete_size), ds2(new int[current_delete2_size]),
31 stacke2(ds2+current_delete2_size), xse(new int[current_xsearch_size]),
32 stacke3(xse+current_xsearch_size), maskc(0) {
33 int i;
34 for(i=0;i<current_vertices;i++) mask[i]=0;
35 for(i=0;i<3;i++) {
36 mem[i]=init_n_vertices;mec[i]=0;
37 mep[i]=new int[init_n_vertices*((i<<1)+1)];
39 mem[3]=init_3_vertices;mec[3]=0;
40 mep[3]=new int[init_3_vertices*7];
41 for(i=4;i<current_vertex_order;i++) {
42 mem[i]=init_n_vertices;mec[i]=0;
43 mep[i]=new int[init_n_vertices*((i<<1)+1)];
47 /** The voronoicell destructor deallocates all the dynamic memory. */
48 voronoicell_base::~voronoicell_base() {
49 for(int i=current_vertex_order-1;i>=0;i--) if(mem[i]>0) delete [] mep[i];
50 delete [] xse;
51 delete [] ds2;delete [] ds;
52 delete [] mep;delete [] mec;
53 delete [] mem;delete [] pts;
54 delete [] mask;
55 delete [] nu;delete [] ed;
58 /** Ensures that enough memory is allocated prior to carrying out a copy.
59 * \param[in] vc a reference to the specialized version of the calling class.
60 * \param[in] vb a pointered to the class to be copied. */
61 template<class vc_class>
62 void voronoicell_base::check_memory_for_copy(vc_class &vc,voronoicell_base* vb) {
63 while(current_vertex_order<vb->current_vertex_order) add_memory_vorder(vc);
64 for(int i=0;i<current_vertex_order;i++) while(mem[i]<vb->mec[i]) add_memory(vc,i);
65 while(current_vertices<vb->p) add_memory_vertices(vc);
68 /** Copies the vertex and edge information from another class. The routine
69 * assumes that enough memory is available for the copy.
70 * \param[in] vb a pointer to the class to copy. */
71 void voronoicell_base::copy(voronoicell_base* vb) {
72 int i,j;
73 p=vb->p;up=0;
74 for(i=0;i<current_vertex_order;i++) {
75 mec[i]=vb->mec[i];
76 for(j=0;j<mec[i]*(2*i+1);j++) mep[i][j]=vb->mep[i][j];
77 for(j=0;j<mec[i]*(2*i+1);j+=2*i+1) ed[mep[i][j+2*i]]=mep[i]+j;
79 for(i=0;i<p;i++) nu[i]=vb->nu[i];
80 for(i=0;i<(p<<2);i++) pts[i]=vb->pts[i];
83 /** Copies the information from another voronoicell class into this
84 * class, extending memory allocation if necessary.
85 * \param[in] c the class to copy. */
86 void voronoicell_neighbor::operator=(voronoicell &c) {
87 voronoicell_base *vb=((voronoicell_base*) &c);
88 check_memory_for_copy(*this,vb);copy(vb);
89 int i,j;
90 for(i=0;i<c.current_vertex_order;i++) {
91 for(j=0;j<c.mec[i]*i;j++) mne[i][j]=0;
92 for(j=0;j<c.mec[i];j++) ne[c.mep[i][(2*i+1)*j+2*i]]=mne[i]+(j*i);
96 /** Copies the information from another voronoicell_neighbor class into this
97 * class, extending memory allocation if necessary.
98 * \param[in] c the class to copy. */
99 void voronoicell_neighbor::operator=(voronoicell_neighbor &c) {
100 voronoicell_base *vb=((voronoicell_base*) &c);
101 check_memory_for_copy(*this,vb);copy(vb);
102 int i,j;
103 for(i=0;i<c.current_vertex_order;i++) {
104 for(j=0;j<c.mec[i]*i;j++) mne[i][j]=c.mne[i][j];
105 for(j=0;j<c.mec[i];j++) ne[c.mep[i][(2*i+1)*j+2*i]]=mne[i]+(j*i);
109 /** Translates the vertices of the Voronoi cell by a given vector.
110 * \param[in] (x,y,z) the coordinates of the vector. */
111 void voronoicell_base::translate(double x,double y,double z) {
112 x*=2;y*=2;z*=2;
113 double *ptsp=pts;
114 while(ptsp<pts+(p<<2)) {
115 *(ptsp++)+=x;*(ptsp++)+=y;*ptsp+=z;ptsp+=2;
119 /** Increases the memory storage for a particular vertex order, by increasing
120 * the size of the of the corresponding mep array. If the arrays already exist,
121 * their size is doubled; if they don't exist, then new ones of size
122 * init_n_vertices are allocated. The routine also ensures that the pointers in
123 * the ed array are updated, by making use of the back pointers. For the cases
124 * where the back pointer has been temporarily overwritten in the marginal
125 * vertex code, the auxiliary delete stack is scanned to find out how to update
126 * the ed value. If the template has been instantiated with the neighbor
127 * tracking turned on, then the routine also reallocates the corresponding mne
128 * array.
129 * \param[in] i the order of the vertex memory to be increased. */
130 template<class vc_class>
131 void voronoicell_base::add_memory(vc_class &vc,int i) {
132 int s=(i<<1)+1;
133 if(mem[i]==0) {
134 vc.n_allocate(i,init_n_vertices);
135 mep[i]=new int[init_n_vertices*s];
136 mem[i]=init_n_vertices;
137 #if VOROPP_VERBOSE >=2
138 fprintf(stderr,"Order %d vertex memory created\n",i);
139 #endif
140 } else {
141 int j=0,k,*l;
142 mem[i]<<=1;
143 if(mem[i]>max_n_vertices) voro_fatal_error("Point memory allocation exceeded absolute maximum",VOROPP_MEMORY_ERROR);
144 #if VOROPP_VERBOSE >=2
145 fprintf(stderr,"Order %d vertex memory scaled up to %d\n",i,mem[i]);
146 #endif
147 l=new int[s*mem[i]];
148 int m=0;
149 vc.n_allocate_aux1(i);
150 while(j<s*mec[i]) {
151 k=mep[i][j+(i<<1)];
152 if(k>=0) {
153 ed[k]=l+j;
154 vc.n_set_to_aux1_offset(k,m);
155 } else {
156 int *dsp;
157 for(dsp=ds2;dsp<stackp2;dsp++) {
158 if(ed[*dsp]==mep[i]+j) {
159 ed[*dsp]=l+j;
160 vc.n_set_to_aux1_offset(*dsp,m);
161 break;
164 if(dsp==stackp2) {
165 for(dsp=xse;dsp<stackp3;dsp++) {
166 if(ed[*dsp]==mep[i]+j) {
167 ed[*dsp]=l+j;
168 vc.n_set_to_aux1_offset(*dsp,m);
169 break;
172 if(dsp==stackp3) voro_fatal_error("Couldn't relocate dangling pointer",VOROPP_INTERNAL_ERROR);
174 #if VOROPP_VERBOSE >=3
175 fputs("Relocated dangling pointer",stderr);
176 #endif
178 for(k=0;k<s;k++,j++) l[j]=mep[i][j];
179 for(k=0;k<i;k++,m++) vc.n_copy_to_aux1(i,m);
181 delete [] mep[i];
182 mep[i]=l;
183 vc.n_switch_to_aux1(i);
187 /** Doubles the maximum number of vertices allowed, by reallocating the ed, nu,
188 * and pts arrays. If the allocation exceeds the absolute maximum set in
189 * max_vertices, then the routine exits with a fatal error. If the template has
190 * been instantiated with the neighbor tracking turned on, then the routine
191 * also reallocates the ne array. */
192 template<class vc_class>
193 void voronoicell_base::add_memory_vertices(vc_class &vc) {
194 int i=(current_vertices<<1),j,**pp,*pnu;
195 unsigned int* pmask;
196 if(i>max_vertices) voro_fatal_error("Vertex memory allocation exceeded absolute maximum",VOROPP_MEMORY_ERROR);
197 #if VOROPP_VERBOSE >=2
198 fprintf(stderr,"Vertex memory scaled up to %d\n",i);
199 #endif
200 double *ppts;
201 pp=new int*[i];
202 for(j=0;j<current_vertices;j++) pp[j]=ed[j];
203 delete [] ed;ed=pp;
204 vc.n_add_memory_vertices(i);
205 pnu=new int[i];
206 for(j=0;j<current_vertices;j++) pnu[j]=nu[j];
207 delete [] nu;nu=pnu;
208 pmask=new unsigned int[i];
209 for(j=0;j<current_vertices;j++) pmask[j]=mask[j];
210 while(j<i) pmask[j++]=0;
211 delete [] mask;mask=pmask;
212 ppts=new double[i<<2];
213 for(j=0;j<(current_vertices<<2);j++) ppts[j]=pts[j];
214 delete [] pts;pts=ppts;
215 current_vertices=i;
218 /** Doubles the maximum allowed vertex order, by reallocating mem, mep, and mec
219 * arrays. If the allocation exceeds the absolute maximum set in
220 * max_vertex_order, then the routine causes a fatal error. If the template has
221 * been instantiated with the neighbor tracking turned on, then the routine
222 * also reallocates the mne array. */
223 template<class vc_class>
224 void voronoicell_base::add_memory_vorder(vc_class &vc) {
225 int i=(current_vertex_order<<1),j,*p1,**p2;
226 if(i>max_vertex_order) voro_fatal_error("Vertex order memory allocation exceeded absolute maximum",VOROPP_MEMORY_ERROR);
227 #if VOROPP_VERBOSE >=2
228 fprintf(stderr,"Vertex order memory scaled up to %d\n",i);
229 #endif
230 p1=new int[i];
231 for(j=0;j<current_vertex_order;j++) p1[j]=mem[j];while(j<i) p1[j++]=0;
232 delete [] mem;mem=p1;
233 p2=new int*[i];
234 for(j=0;j<current_vertex_order;j++) p2[j]=mep[j];
235 delete [] mep;mep=p2;
236 p1=new int[i];
237 for(j=0;j<current_vertex_order;j++) p1[j]=mec[j];while(j<i) p1[j++]=0;
238 delete [] mec;mec=p1;
239 vc.n_add_memory_vorder(i);
240 current_vertex_order=i;
243 /** Doubles the size allocation of the main delete stack. If the allocation
244 * exceeds the absolute maximum set in max_delete_size, then routine causes a
245 * fatal error. */
246 void voronoicell_base::add_memory_ds() {
247 current_delete_size<<=1;
248 if(current_delete_size>max_delete_size) voro_fatal_error("Delete stack 1 memory allocation exceeded absolute maximum",VOROPP_MEMORY_ERROR);
249 #if VOROPP_VERBOSE >=2
250 fprintf(stderr,"Delete stack 1 memory scaled up to %d\n",current_delete_size);
251 #endif
252 int *dsn=new int[current_delete_size],*dsnp=dsn,*dsp=ds;
253 while(dsp<stackp) *(dsnp++)=*(dsp++);
254 delete [] ds;ds=dsn;stackp=dsnp;
255 stacke=ds+current_delete_size;
258 /** Doubles the size allocation of the auxiliary delete stack. If the
259 * allocation exceeds the absolute maximum set in max_delete2_size, then the
260 * routine causes a fatal error. */
261 void voronoicell_base::add_memory_ds2() {
262 current_delete2_size<<=1;
263 if(current_delete2_size>max_delete2_size) voro_fatal_error("Delete stack 2 memory allocation exceeded absolute maximum",VOROPP_MEMORY_ERROR);
264 #if VOROPP_VERBOSE >=2
265 fprintf(stderr,"Delete stack 2 memory scaled up to %d\n",current_delete2_size);
266 #endif
267 int *dsn=new int[current_delete2_size],*dsnp=dsn,*dsp=ds2;
268 while(dsp<stackp2) *(dsnp++)=*(dsp++);
269 delete [] ds2;ds2=dsn;stackp2=dsnp;
270 stacke2=ds2+current_delete2_size;
273 /** Doubles the size allocation of the auxiliary delete stack. If the
274 * allocation exceeds the absolute maximum set in max_delete2_size, then the
275 * routine causes a fatal error. */
276 void voronoicell_base::add_memory_xse() {
277 current_xsearch_size<<=1;
278 if(current_xsearch_size>max_xsearch_size) voro_fatal_error("Extra search stack memory allocation exceeded absolute maximum",VOROPP_MEMORY_ERROR);
279 #if VOROPP_VERBOSE >=2
280 fprintf(stderr,"Extra search stack memory scaled up to %d\n",current_xsearch_size);
281 #endif
282 int *dsn=new int[current_xsearch_size],*dsnp=dsn,*dsp=xse;
283 while(dsp<stackp3) *(dsnp++)=*(dsp++);
284 delete [] xse;xse=dsn;stackp3=dsnp;
285 stacke3=xse+current_xsearch_size;
289 /** Initializes a Voronoi cell as a rectangular box with the given dimensions.
290 * \param[in] (xmin,xmax) the minimum and maximum x coordinates.
291 * \param[in] (ymin,ymax) the minimum and maximum y coordinates.
292 * \param[in] (zmin,zmax) the minimum and maximum z coordinates. */
293 void voronoicell_base::init_base(double xmin,double xmax,double ymin,double ymax,double zmin,double zmax) {
294 for(int i=0;i<current_vertex_order;i++) mec[i]=0;up=0;
295 mec[3]=p=8;xmin*=2;xmax*=2;ymin*=2;ymax*=2;zmin*=2;zmax*=2;
296 *pts=xmin;pts[1]=ymin;pts[2]=zmin;
297 pts[4]=xmax;pts[5]=ymin;pts[6]=zmin;
298 pts[8]=xmin;pts[9]=ymax;pts[10]=zmin;
299 pts[12]=xmax;pts[13]=ymax;pts[14]=zmin;
300 pts[16]=xmin;pts[17]=ymin;pts[18]=zmax;
301 pts[20]=xmax;pts[21]=ymin;pts[22]=zmax;
302 pts[24]=xmin;pts[25]=ymax;pts[26]=zmax;
303 pts[28]=xmax;pts[29]=ymax;pts[30]=zmax;
304 int *q=mep[3];
305 *q=1;q[1]=4;q[2]=2;q[3]=2;q[4]=1;q[5]=0;q[6]=0;
306 q[7]=3;q[8]=5;q[9]=0;q[10]=2;q[11]=1;q[12]=0;q[13]=1;
307 q[14]=0;q[15]=6;q[16]=3;q[17]=2;q[18]=1;q[19]=0;q[20]=2;
308 q[21]=2;q[22]=7;q[23]=1;q[24]=2;q[25]=1;q[26]=0;q[27]=3;
309 q[28]=6;q[29]=0;q[30]=5;q[31]=2;q[32]=1;q[33]=0;q[34]=4;
310 q[35]=4;q[36]=1;q[37]=7;q[38]=2;q[39]=1;q[40]=0;q[41]=5;
311 q[42]=7;q[43]=2;q[44]=4;q[45]=2;q[46]=1;q[47]=0;q[48]=6;
312 q[49]=5;q[50]=3;q[51]=6;q[52]=2;q[53]=1;q[54]=0;q[55]=7;
313 *ed=q;ed[1]=q+7;ed[2]=q+14;ed[3]=q+21;
314 ed[4]=q+28;ed[5]=q+35;ed[6]=q+42;ed[7]=q+49;
315 *nu=nu[1]=nu[2]=nu[3]=nu[4]=nu[5]=nu[6]=nu[7]=3;
318 /** Initializes an L-shaped Voronoi cell of a fixed size for testing the
319 * convexity robustness. */
320 void voronoicell::init_l_shape() {
321 for(int i=0;i<current_vertex_order;i++) mec[i]=0;up=0;
322 mec[3]=p=12;
323 const double j=0;
324 *pts=-2;pts[1]=-2;pts[2]=-2;
325 pts[4]=2;pts[5]=-2;pts[6]=-2;
326 pts[8]=-2;pts[9]=0;pts[10]=-2;
327 pts[12]=-j;pts[13]=j;pts[14]=-2;
328 pts[16]=0;pts[17]=2;pts[18]=-2;
329 pts[20]=2;pts[21]=2;pts[22]=-2;
330 pts[24]=-2;pts[25]=-2;pts[26]=2;
331 pts[28]=2;pts[29]=-2;pts[30]=2;
332 pts[32]=-2;pts[33]=0;pts[34]=2;
333 pts[36]=-j;pts[37]=j;pts[38]=2;
334 pts[40]=0;pts[41]=2;pts[42]=2;
335 pts[44]=2;pts[45]=2;pts[46]=2;
336 int *q=mep[3];
337 *q=1;q[1]=6;q[2]=2;q[6]=0;
338 q[7]=5;q[8]=7;q[9]=0;q[13]=1;
339 q[14]=0;q[15]=8;q[16]=3;q[20]=2;
340 q[21]=2;q[22]=9;q[23]=4;q[27]=3;
341 q[28]=3;q[29]=10;q[30]=5;q[34]=4;
342 q[35]=4;q[36]=11;q[37]=1;q[41]=5;
343 q[42]=8;q[43]=0;q[44]=7;q[48]=6;
344 q[49]=6;q[50]=1;q[51]=11;q[55]=7;
345 q[56]=9;q[57]=2;q[58]=6;q[62]=8;
346 q[63]=10;q[64]=3;q[65]=8;q[69]=9;
347 q[70]=11;q[71]=4;q[72]=9;q[76]=10;
348 q[77]=7;q[78]=5;q[79]=10;q[83]=11;
349 *ed=q;ed[1]=q+7;ed[2]=q+14;ed[3]=q+21;ed[4]=q+28;ed[5]=q+35;
350 ed[6]=q+42;ed[7]=q+49;ed[8]=q+56;ed[9]=q+63;ed[10]=q+70;ed[11]=q+77;
351 for(int i=0;i<12;i++) nu[i]=3;
352 construct_relations();
355 /** Initializes a Voronoi cell as a regular octahedron.
356 * \param[in] l The distance from the octahedron center to a vertex. Six
357 * vertices are initialized at (-l,0,0), (l,0,0), (0,-l,0),
358 * (0,l,0), (0,0,-l), and (0,0,l). */
359 void voronoicell_base::init_octahedron_base(double l) {
360 for(int i=0;i<current_vertex_order;i++) mec[i]=0;up=0;
361 mec[4]=p=6;l*=2;
362 *pts=-l;pts[1]=0;pts[2]=0;
363 pts[4]=l;pts[5]=0;pts[6]=0;
364 pts[8]=0;pts[9]=-l;pts[10]=0;
365 pts[12]=0;pts[13]=l;pts[14]=0;
366 pts[16]=0;pts[17]=0;pts[18]=-l;
367 pts[20]=0;pts[21]=0;pts[22]=l;
368 int *q=mep[4];
369 *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;
370 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;
371 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;
372 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;
373 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;
374 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;
375 *ed=q;ed[1]=q+9;ed[2]=q+18;ed[3]=q+27;ed[4]=q+36;ed[5]=q+45;
376 *nu=nu[1]=nu[2]=nu[3]=nu[4]=nu[5]=4;
379 /** Initializes a Voronoi cell as a tetrahedron. It assumes that the normal to
380 * the face for the first three vertices points inside.
381 * \param (x0,y0,z0) a position vector for the first vertex.
382 * \param (x1,y1,z1) a position vector for the second vertex.
383 * \param (x2,y2,z2) a position vector for the third vertex.
384 * \param (x3,y3,z3) a position vector for the fourth vertex. */
385 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) {
386 for(int i=0;i<current_vertex_order;i++) mec[i]=0;up=0;
387 mec[3]=p=4;
388 *pts=x0*2;pts[1]=y0*2;pts[2]=z0*2;
389 pts[4]=x1*2;pts[5]=y1*2;pts[6]=z1*2;
390 pts[8]=x2*2;pts[9]=y2*2;pts[10]=z2*2;
391 pts[12]=x3*2;pts[13]=y3*2;pts[14]=z3*2;
392 int *q=mep[3];
393 *q=1;q[1]=3;q[2]=2;q[3]=0;q[4]=0;q[5]=0;q[6]=0;
394 q[7]=0;q[8]=2;q[9]=3;q[10]=0;q[11]=2;q[12]=1;q[13]=1;
395 q[14]=0;q[15]=3;q[16]=1;q[17]=2;q[18]=2;q[19]=1;q[20]=2;
396 q[21]=0;q[22]=1;q[23]=2;q[24]=1;q[25]=2;q[26]=1;q[27]=3;
397 *ed=q;ed[1]=q+7;ed[2]=q+14;ed[3]=q+21;
398 *nu=nu[1]=nu[2]=nu[3]=3;
401 /** Checks that the relational table of the Voronoi cell is accurate, and
402 * prints out any errors. This algorithm is O(p), so running it every time the
403 * plane routine is called will result in a significant slowdown. */
404 void voronoicell_base::check_relations() {
405 int i,j;
406 for(i=0;i<p;i++) for(j=0;j<nu[i];j++) if(ed[ed[i][j]][ed[i][nu[i]+j]]!=i)
407 printf("Relational error at point %d, edge %d.\n",i,j);
410 /** This routine checks for any two vertices that are connected by more than
411 * one edge. The plane algorithm is designed so that this should not happen, so
412 * any occurrences are most likely errors. Note that the routine is O(p), so
413 * running it every time the plane routine is called will result in a
414 * significant slowdown. */
415 void voronoicell_base::check_duplicates() {
416 int i,j,k;
417 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])
418 printf("Duplicate edges: (%d,%d) and (%d,%d) [%d]\n",i,j,i,k,ed[i][j]);
421 /** Constructs the relational table if the edges have been specified. */
422 void voronoicell_base::construct_relations() {
423 int i,j,k,l;
424 for(i=0;i<p;i++) for(j=0;j<nu[i];j++) {
425 k=ed[i][j];
426 l=0;
427 while(ed[k][l]!=i) {
428 l++;
429 if(l==nu[k]) voro_fatal_error("Relation table construction failed",VOROPP_INTERNAL_ERROR);
431 ed[i][nu[i]+j]=l;
435 /** Starting from a point within the current cutting plane, this routine attempts
436 * to find an edge to a point outside the cutting plane. This prevents the plane
437 * routine from .
438 * \param[in,out] up */
439 inline bool voronoicell_base::search_for_outside_edge(int &up) {
440 int i,lp,lw,*j=ds2,sc2=stackp2-ds2;
441 double l;
442 *(stackp2++)=up;
443 while(j<stackp2) {
444 up=*(j++);
445 for(i=0;i<nu[up];i++) {
446 lp=ed[up][i];
447 lw=m_test(lp,l);
448 if(lw==0) {
449 stackp2=ds2+sc2;
450 return true;
452 else if(lw==1) add_to_stack(sc2,lp);
455 stackp2=ds2+sc2;
456 return false;
459 /** Adds a point to the auxiliary delete stack if it is not already there.
460 * \param[in] vc a reference to the specialized version of the calling class.
461 * \param[in] lp the index of the point to add.
462 * \param[in,out] stackp2 a pointer to the end of the stack entries. */
463 inline void voronoicell_base::add_to_stack(int sc2,int lp) {
464 for(int *k=ds2+sc2;k<stackp2;k++) if(*k==lp) return;
465 if(stackp2==stacke2) add_memory_ds2();
466 *(stackp2++)=lp;
469 /** Assuming that the point up is outside the cutting plane, this routine
470 * searches upwards along edges trying to find an edge that intersects the
471 * cutting plane.
472 * \param[in] rsq the distance along this vector of the plane.
473 * \param[in,out] u the dot product of point up with the normal.
474 * \return True if the cutting plane was reached, false otherwise. */
475 inline bool voronoicell_base::search_upward(unsigned int &uw,int &lp,int &ls,int &us,double &l,double &u) {
476 int vs;
477 lp=up;l=u;
479 // The test point is outside of the cutting space
480 for(ls=0;ls<nu[lp];ls++) {
481 up=ed[lp][ls];
482 uw=m_test(up,u);
483 if(u>l) break;
485 if(ls==nu[lp]) if(definite_max(lp,ls,l,u,uw)) {
486 up=lp;
487 return false;
490 while(uw==0) {
491 //if(++count>=p) failsafe_find(lp,ls,us,l,u);
493 // Test all the neighbors of the current point
494 // and find the one which is closest to the
495 // plane
496 vs=ed[lp][nu[lp]+ls];lp=up;l=u;
497 for(ls=0;ls<nu[lp];ls++) {
498 if(ls==vs) continue;
499 up=ed[lp][ls];
500 uw=m_test(up,u);
501 if(u>l) break;
503 if(ls==nu[lp]&&definite_max(lp,ls,l,u,uw)) {
504 up=lp;
505 return false;
508 us=ed[lp][nu[lp]+ls];
509 return true;
512 /** Checks whether a particular point lp is a definite maximum, searching
513 * through any possible minor non-convexities, for a better maximum.
514 * \param[in] (x,y,z) the normal vector to the plane. */
515 bool voronoicell_base::definite_max(int &lp,int &ls,double &l,double &u,unsigned int &uw) {
516 int tp=lp,ts,qp=0;
517 unsigned int qw;
518 double q;
520 // Check to see whether point up is a well-defined maximum. Otherwise
521 // any neighboring vertices of up that are marginal need to be
522 // followed, to see if they lead to a better maximum.
523 for(ts=0;ts<nu[tp];ts++) {
524 qp=ed[tp][ts];
525 m_test(qp,q);
526 if(q>l-big_tol) break;
528 if(ts==nu[tp]) return true;
530 // The point tp is marginal, so it will be necessary to do the
531 // flood-fill search. Mark the point tp and the point qp, and search
532 // any remaining neighbors of the point tp.
533 int *stackp=ds+1;
534 flip(lp);
535 flip(qp);
536 *ds=qp;
537 ts++;
538 while(ts<nu[tp]) {
539 qp=ed[tp][ts];
540 m_test(qp,q);
541 if(q>l-big_tol) {
542 if(stackp==stacke) add_memory_ds();
543 *(stackp++)=up;
544 flip(up);
546 ts++;
549 // Consider additional marginal points, starting with the original
550 // point qp
551 int *spp=ds;
552 while(spp<stackp) {
553 tp=*(spp++);
554 for(ts=0;ts<nu[tp];ts++) {
555 qp=ed[tp][ts];
557 // Skip the point if it's already marked
558 if(ed[qp][nu[qp]<<1]<0) continue;
559 qw=m_test(qp,q);
561 // This point is a better maximum. Reset markers and
562 // return true.
563 if(q>l) {
564 flip(lp);
565 lp=tp;
566 ls=ts;
567 m_test(lp,l);
568 up=qp;
569 uw=qw;
570 u=q;
571 while(stackp>ds) flip(*(--stackp));
572 return false;
575 // The point is marginal and therefore must also be
576 // considered
577 if(q>l-big_tol) {
578 if(stackp==stacke) {
579 int nn=stackp-spp;
580 add_memory_ds();
581 spp=stackp-nn;
583 *(stackp++)=qp;
584 flip(qp);
589 // Reset markers and return false
590 flip(lp);
591 while(stackp>ds) flip(*(--stackp));
592 return true;
595 inline bool voronoicell_base::search_downward(unsigned int &lw,int &lp,int &ls,int &us,double &l,double &u) {
596 int vs;
598 // The test point is outside of the cutting space
599 for(us=0;us<nu[up];us++) {
600 lp=ed[up][us];
601 lw=m_test(lp,l);
602 if(u>l) break;
604 if(us==nu[up]) if(definite_min(lp,us,l,u,lw)) return false;
606 while(lw==2) {
607 //if(++count>=p) failsafe_find(lp,ls,us,l,u);
609 // Test all the neighbors of the current point
610 // and find the one which is closest to the
611 // plane
612 vs=ed[up][nu[up]+us];up=lp;u=l;
613 for(us=0;us<nu[up];us++) {
614 if(us==vs) continue;
615 lp=ed[up][us];
616 lw=m_test(lp,l);
617 if(u>l) break;
619 if(us==nu[up]&&definite_min(lp,us,l,u,lw)) return false;
621 ls=ed[up][nu[up]+us];
622 return true;
625 bool voronoicell_base::definite_min(int &lp,int &us,double &l,double &u,unsigned int &lw) {
626 int tp=up,ts,qp=0;
627 unsigned int qw;
628 double q;
630 // Check to see whether point up is a well-defined maximum. Otherwise
631 // any neighboring vertices of up that are marginal need to be
632 // followed, to see if they lead to a better maximum.
633 for(ts=0;ts<nu[tp];ts++) {
634 qp=ed[tp][ts];
635 m_test(qp,q);
636 if(q<u+big_tol) break;
638 if(ts==nu[tp]) return true;
640 // The point tp is marginal, so it will be necessary to do the
641 // flood-fill search. Mark the point tp and the point qp, and search
642 // any remaining neighbors of the point tp.
643 int *stackp=ds+1;
644 flip(up);
645 flip(qp);
646 *ds=qp;
647 ts++;
648 while(ts<nu[tp]) {
649 qp=ed[tp][ts];
650 m_test(qp,q);
651 if(q<u+big_tol) {
652 if(stackp==stacke) add_memory_ds();
653 *(stackp++)=lp;
654 flip(lp);
656 ts++;
659 // Consider additional marginal points, starting with the original
660 // point qp
661 int *spp=ds;
662 while(spp<stackp) {
663 tp=*(spp++);
664 for(ts=0;ts<nu[tp];ts++) {
665 qp=ed[tp][ts];
667 // Skip the point if it's already marked
668 if(ed[qp][nu[qp]<<1]<0) continue;
669 qw=m_test(qp,q);
671 // This point is a better minimum. Reset markers and
672 // return true.
673 if(q<u) {
674 flip(up);
675 up=tp;
676 us=ts;
677 m_test(up,u);
678 lp=qp;
679 lw=qw;
680 l=q;
681 while(stackp>ds) flip(*(--stackp));
682 return false;
685 // The point is marginal and therefore must also be
686 // considered
687 if(q<u+big_tol) {
688 if(stackp==stacke) {
689 int nn=stackp-spp;
690 add_memory_ds();
691 spp=stackp-nn;
693 *(stackp++)=qp;
694 flip(qp);
699 // Reset markers and return false
700 flip(up);
701 while(stackp>ds) flip(*(--stackp));
702 return true;
705 /** Cuts the Voronoi cell by a particle whose center is at a separation of
706 * (x,y,z) from the cell center. The value of rsq should be initially set to
707 * \f$x^2+y^2+z^2\f$.
708 * \param[in] vc a reference to the specialized version of the calling class.
709 * \param[in] (x,y,z) the normal vector to the plane.
710 * \param[in] rsq the distance along this vector of the plane.
711 * \param[in] p_id the plane ID (for neighbor tracking only).
712 * \return False if the plane cut deleted the cell entirely, true otherwise. */
713 template<class vc_class>
714 bool voronoicell_base::nplane(vc_class &vc,double x,double y,double z,double rsq,int p_id) {
715 int i,j,lp=up,cp,qp,*dsp;
716 int us=0,ls=0;
717 unsigned int uw,lw;
718 int *edp,*edd;stackp=ds;
719 double u,l=0;up=0;
721 // Initialize the safe testing routine
722 px=x;py=y;pz=z;prsq=rsq;
723 maskc+=4;
724 if(maskc<4) reset_mask();
726 uw=m_test(up,u);
727 if(uw==2) {
728 if(!search_downward(lw,lp,ls,us,l,u)) return false;
729 if(lw==1) {up=lp;lp=-1;}
730 } else if(uw==0) {
731 if(!search_upward(uw,lp,ls,us,l,u)) return true;
732 if(uw==1) lp=-1;
733 } else {
734 lp=-1;
737 // Set stack pointers
738 stackp=ds;stackp2=ds2;stackp3=xse;
740 // Store initial number of vertices
741 int op=p;
743 if(create_facet(vc,lp,ls,l,us,u,p_id)) return false;
744 int k=0;int xtra=0;
745 while(xse+k<stackp3) {
746 lp=xse[k++];
747 uw=m_test(lp,l);
748 for(ls=0;ls<nu[lp];ls++) {
749 up=ed[lp][ls];
751 // Skip if this is a new vertex
752 uw=m_test(up,u);
753 if(up>=op) continue;
755 if(uw==0) {
756 if(u>-big_tol&&ed[up][nu[up]<<1]!=-1) {
757 ed[up][nu[up]<<1]=-1;
758 if(stackp3==stacke3) add_memory_xse();
759 *(stackp3++)=up;
761 } else if(uw==1) {
763 // This is a possible facet starting
764 // from a vertex on the cutting plane
765 if(create_facet(vc,-1,0,0,0,u,p_id)) return false;
766 } else {
768 // This is a new facet
769 us=ed[lp][nu[lp]+ls];
770 m_test(lp,l);
771 if(create_facet(vc,lp,ls,l,us,u,p_id)) return false;
774 xtra++;
777 // Reset back pointers on extra search stack
778 for(dsp=xse;dsp<stackp3;dsp++) {
779 j=*dsp;
780 ed[j][nu[j]<<1]=j;
783 // Delete points: first, remove any duplicates
784 dsp=ds;
785 while(dsp<stackp) {
786 j=*dsp;
787 if(ed[j][nu[j]]!=-1) {
788 ed[j][nu[j]]=-1;
789 dsp++;
790 } else *dsp=*(--stackp);
793 // Add the points in the auxiliary delete stack,
794 // and reset their back pointers
795 for(dsp=ds2;dsp<stackp2;dsp++) {
796 j=*dsp;
797 ed[j][nu[j]<<1]=j;
798 if(ed[j][nu[j]]!=-1) {
799 ed[j][nu[j]]=-1;
800 if(stackp==stacke) add_memory_ds();
801 *(stackp++)=j;
805 // Scan connections and add in extras
806 for(dsp=ds;dsp<stackp;dsp++) {
807 cp=*dsp;
808 for(edp=ed[cp];edp<ed[cp]+nu[cp];edp++) {
809 qp=*edp;
810 if(qp!=-1&&ed[qp][nu[qp]]!=-1) {
811 if(stackp==stacke) {
812 int dis=stackp-dsp;
813 add_memory_ds();
814 dsp=ds+dis;
816 *(stackp++)=qp;
817 ed[qp][nu[qp]]=-1;
821 up=0;
823 // Delete them from the array structure
824 while(stackp>ds) {
825 --p;
826 while(ed[p][nu[p]]==-1) {
827 j=nu[p];
828 edp=ed[p];edd=(mep[j]+((j<<1)+1)*--mec[j]);
829 while(edp<ed[p]+(j<<1)+1) *(edp++)=*(edd++);
830 vc.n_set_aux2_copy(p,j);
831 vc.n_copy_pointer(ed[p][(j<<1)],p);
832 ed[ed[p][(j<<1)]]=ed[p];
833 --p;
835 up=*(--stackp);
836 if(up<p) {
838 // Vertex management
839 pts[(up<<2)]=pts[(p<<2)];
840 pts[(up<<2)+1]=pts[(p<<2)+1];
841 pts[(up<<2)+2]=pts[(p<<2)+2];
843 // Memory management
844 j=nu[up];
845 edp=ed[up];edd=(mep[j]+((j<<1)+1)*--mec[j]);
846 while(edp<ed[up]+(j<<1)+1) *(edp++)=*(edd++);
847 vc.n_set_aux2_copy(up,j);
848 vc.n_copy_pointer(ed[up][j<<1],up);
849 vc.n_copy_pointer(up,p);
850 ed[ed[up][j<<1]]=ed[up];
852 // Edge management
853 ed[up]=ed[p];
854 nu[up]=nu[p];
855 for(i=0;i<nu[up];i++) ed[ed[up][i]][ed[up][nu[up]+i]]=up;
856 ed[up][nu[up]<<1]=up;
857 } else up=p++;
860 // Check for any vertices of zero order
861 if(*mec>0) voro_fatal_error("Zero order vertex formed",VOROPP_INTERNAL_ERROR);
863 // Collapse any order 2 vertices and exit
864 return collapse_order2(vc);
867 /** Creates a new facet.
868 * \return True if cell deleted, false otherwise. */
869 template<class vc_class>
870 bool voronoicell_base::create_facet(vc_class &vc,int lp,int ls,double l,int us,double u,int p_id) {
871 int i,j,k,qp,qs,iqs,cp,cs,rp,*edp,*edd;
872 unsigned int lw,qw;
873 bool new_double_edge=false,double_edge=false;
874 double q,r;
876 // We're about to add the first point of the new facet. In either
877 // routine, we have to add a point, so first check there's space for
878 // it.
879 if(p==current_vertices) add_memory_vertices(vc);
881 if(lp==-1) {
883 // We want to be strict about reaching the conclusion that the
884 // cell is entirely within the cutting plane. It's not enough
885 // to find a vertex that has edges which are all inside or on
886 // the plane. If the vertex has neighbors that are also on the
887 // plane, we should check those too.
888 if(!search_for_outside_edge(up)) return true;
890 // The search algorithm found a point which is on the cutting
891 // plane. We leave that point in place, and create a new one at
892 // the same location.
893 pts[(p<<2)]=pts[(up<<2)];
894 pts[(p<<2)+1]=pts[(up<<2)+1];
895 pts[(p<<2)+2]=pts[(up<<2)+2];
897 // Search for a collection of edges of the test vertex which
898 // are outside of the cutting space. Begin by testing the
899 // zeroth edge.
900 i=0;
901 lp=*ed[up];
902 lw=m_testx(lp,l);
903 if(lw!=0) {
905 // The first edge is either inside the cutting space,
906 // or lies within the cutting plane. Test the edges
907 // sequentially until we find one that is outside.
908 unsigned int rw=lw;
909 do {
910 i++;
912 // If we reached the last edge with no luck
913 // then all of the vertices are inside
914 // or on the plane, so the cell is completely
915 // deleted
916 if(i==nu[up]) return true;
917 lp=ed[up][i];
918 lw=m_testx(lp,l);
919 } while (lw!=0);
920 j=i+1;
922 // We found an edge outside the cutting space. Keep
923 // moving through these edges until we find one that's
924 // inside or on the plane.
925 while(j<nu[up]) {
926 lp=ed[up][j];
927 lw=m_testx(lp,l);
928 if(lw!=0) break;
929 j++;
932 // Compute the number of edges for the new vertex. In
933 // general it will be the number of outside edges
934 // found, plus two. But we need to recognize the
935 // special case when all but one edge is outside, and
936 // the remaining one is on the plane. For that case we
937 // have to reduce the edge count by one to prevent
938 // doubling up.
939 if(j==nu[up]&&i==1&&rw==1) {
940 nu[p]=nu[up];
941 double_edge=true;
942 } else nu[p]=j-i+2;
943 k=1;
945 // Add memory for the new vertex if needed, and
946 // initialize
947 while (nu[p]>=current_vertex_order) add_memory_vorder(vc);
948 if(mec[nu[p]]==mem[nu[p]]) add_memory(vc,nu[p]);
949 vc.n_set_pointer(p,nu[p]);
950 ed[p]=mep[nu[p]]+((nu[p]<<1)+1)*mec[nu[p]]++;
951 ed[p][nu[p]<<1]=p;
953 // Copy the edges of the original vertex into the new
954 // one. Delete the edges of the original vertex, and
955 // update the relational table.
956 us=cycle_down(i,up);
957 while(i<j) {
958 qp=ed[up][i];
959 qs=ed[up][nu[up]+i];
960 vc.n_copy(p,k,up,i);
961 ed[p][k]=qp;
962 ed[p][nu[p]+k]=qs;
963 ed[qp][qs]=p;
964 ed[qp][nu[qp]+qs]=k;
965 ed[up][i]=-1;
966 i++;k++;
968 qs=i==nu[up]?0:i;
969 } else {
971 // In this case, the zeroth edge is outside the cutting
972 // plane. Begin by searching backwards from the last
973 // edge until we find an edge which isn't outside.
974 i=nu[up]-1;
975 lp=ed[up][i];
976 lw=m_testx(lp,l);
977 while(lw==0) {
978 i--;
980 // If i reaches zero, then we have a point in
981 // the plane all of whose edges are outside
982 // the cutting space, so we just exit
983 if(i==0) return false;
984 lp=ed[up][i];
985 lw=m_testx(lp,l);
988 // Now search forwards from zero
989 j=1;
990 qp=ed[up][j];
991 qw=m_testx(qp,q);
992 while(qw==0) {
993 j++;
994 qp=ed[up][j];
995 qw=m_testx(qp,l);
998 // Compute the number of edges for the new vertex. In
999 // general it will be the number of outside edges
1000 // found, plus two. But we need to recognize the
1001 // special case when all but one edge is outside, and
1002 // the remaining one is on the plane. For that case we
1003 // have to reduce the edge count by one to prevent
1004 // doubling up.
1005 if(i==j&&qw==1) {
1006 double_edge=true;
1007 nu[p]=nu[up];
1008 } else {
1009 nu[p]=nu[up]-i+j+1;
1012 // Add memory to store the vertex if it doesn't exist
1013 // already
1014 k=1;
1015 while(nu[p]>=current_vertex_order) add_memory_vorder(vc);
1016 if(mec[nu[p]]==mem[nu[p]]) add_memory(vc,nu[p]);
1018 // Copy the edges of the original vertex into the new
1019 // one. Delete the edges of the original vertex, and
1020 // update the relational table.
1021 vc.n_set_pointer(p,nu[p]);
1022 ed[p]=mep[nu[p]]+((nu[p]<<1)+1)*mec[nu[p]]++;
1023 ed[p][nu[p]<<1]=p;
1024 us=i++;
1025 while(i<nu[up]) {
1026 qp=ed[up][i];
1027 qs=ed[up][nu[up]+i];
1028 vc.n_copy(p,k,up,i);
1029 ed[p][k]=qp;
1030 ed[p][nu[p]+k]=qs;
1031 ed[qp][qs]=p;
1032 ed[qp][nu[qp]+qs]=k;
1033 ed[up][i]=-1;
1034 i++;k++;
1036 i=0;
1037 while(i<j) {
1038 qp=ed[up][i];
1039 qs=ed[up][nu[up]+i];
1040 vc.n_copy(p,k,up,i);
1041 ed[p][k]=qp;
1042 ed[p][nu[p]+k]=qs;
1043 ed[qp][qs]=p;
1044 ed[qp][nu[qp]+qs]=k;
1045 ed[up][i]=-1;
1046 i++;k++;
1048 qs=j;
1050 if(!double_edge) {
1051 vc.n_copy(p,k,up,qs);
1052 vc.n_set(p,0,p_id);
1053 } else vc.n_copy(p,0,up,qs);
1055 // Add this point to the auxiliary delete stack
1056 if(stackp2==stacke2) add_memory_ds2();
1057 *(stackp2++)=up;
1059 // Look at the edges on either side of the group that was
1060 // detected. We're going to commence facet computation by
1061 // moving along one of them. We are going to end up coming back
1062 // along the other one.
1063 cs=k;
1064 qp=up;q=u;
1065 i=ed[up][us];
1066 us=ed[up][nu[up]+us];
1067 up=i;
1068 ed[qp][nu[qp]<<1]=-p;
1070 } else {
1072 // The search algorithm found an intersected edge between the
1073 // points lp and up. Create a new vertex between them which
1074 // lies on the cutting plane. Since u and l differ by at least
1075 // the tolerance, this division should never screw up.
1076 if(stackp==stacke) add_memory_ds();
1077 *(stackp++)=up;
1078 r=u/(u-l);l=1-r;
1079 pts[p<<2]=pts[lp<<2]*r+pts[up<<2]*l;
1080 pts[(p<<2)+1]=pts[(lp<<2)+1]*r+pts[(up<<2)+1]*l;
1081 pts[(p<<2)+2]=pts[(lp<<2)+2]*r+pts[(up<<2)+2]*l;
1083 // This point will always have three edges. Connect one of them
1084 // to lp.
1085 nu[p]=3;
1086 if(mec[3]==mem[3]) add_memory(vc,3);
1087 vc.n_set_pointer(p,3);
1088 vc.n_set(p,0,p_id);
1089 vc.n_copy(p,1,up,us);
1090 vc.n_copy(p,2,lp,ls);
1091 ed[p]=mep[3]+7*mec[3]++;
1092 ed[p][6]=p;
1093 ed[up][us]=-1;
1094 ed[lp][ls]=p;
1095 ed[lp][nu[lp]+ls]=1;
1096 ed[p][1]=lp;
1097 ed[p][nu[p]+1]=ls;
1098 cs=2;
1100 // Set the direction to move in
1101 qs=cycle_up(us,up);
1102 qp=up;q=u;
1105 // When the code reaches here, we have initialized the first point, and
1106 // we have a direction for moving it to construct the rest of the facet
1107 cp=p;rp=p;p++;
1108 while(qp!=up||qs!=us) {
1110 // We're currently tracing round an intersected facet. Keep
1111 // moving around it until we find a point or edge which
1112 // intersects the plane.
1113 lp=ed[qp][qs];
1114 lw=m_testx(lp,l);
1116 if(lw==2) {
1118 // The point is still in the cutting space. Just add it
1119 // to the delete stack and keep moving.
1120 qs=cycle_up(ed[qp][nu[qp]+qs],lp);
1121 qp=lp;
1122 q=l;
1123 if(stackp==stacke) add_memory_ds();
1124 *(stackp++)=qp;
1126 } else if(lw==0) {
1128 // The point is outside of the cutting space, so we've
1129 // found an intersected edge. Introduce a regular point
1130 // at the point of intersection. Connect it to the
1131 // point we just tested. Also connect it to the previous
1132 // new point in the facet we're constructing.
1133 if(p==current_vertices) add_memory_vertices(vc);
1134 r=q/(q-l);l=1-r;
1135 pts[p<<2]=pts[lp<<2]*r+pts[qp<<2]*l;
1136 pts[(p<<2)+1]=pts[(lp<<2)+1]*r+pts[(qp<<2)+1]*l;
1137 pts[(p<<2)+2]=pts[(lp<<2)+2]*r+pts[(qp<<2)+2]*l;
1138 nu[p]=3;
1139 if(mec[3]==mem[3]) add_memory(vc,3);
1140 ls=ed[qp][qs+nu[qp]];
1141 vc.n_set_pointer(p,3);
1142 vc.n_set(p,0,p_id);
1143 vc.n_copy(p,1,qp,qs);
1144 vc.n_copy(p,2,lp,ls);
1145 ed[p]=mep[3]+7*mec[3]++;
1146 *ed[p]=cp;
1147 ed[p][1]=lp;
1148 ed[p][3]=cs;
1149 ed[p][4]=ls;
1150 ed[p][6]=p;
1151 ed[lp][ls]=p;
1152 ed[lp][nu[lp]+ls]=1;
1153 ed[cp][cs]=p;
1154 ed[cp][nu[cp]+cs]=0;
1155 ed[qp][qs]=-1;
1156 qs=cycle_up(qs,qp);
1157 cp=p++;
1158 cs=2;
1159 } else {
1161 // We've found a point which is on the cutting plane.
1162 // We're going to introduce a new point right here, but
1163 // first we need to figure out the number of edges it
1164 // has.
1165 if(p==current_vertices) add_memory_vertices(vc);
1167 // If the previous vertex detected a double edge, our
1168 // new vertex will have one less edge.
1169 k=double_edge?0:1;
1170 qs=ed[qp][nu[qp]+qs];
1171 qp=lp;
1172 iqs=qs;
1174 // Start testing the edges of the current point until
1175 // we find one which isn't outside the cutting space
1176 do {
1177 k++;
1178 qs=cycle_up(qs,qp);
1179 lp=ed[qp][qs];
1180 lw=m_testx(lp,l);
1181 } while (lw==0);
1183 // Now we need to find out whether this marginal vertex
1184 // we are on has been visited before, because if that's
1185 // the case, we need to add vertices to the existing
1186 // new vertex, rather than creating a fresh one. We also
1187 // need to figure out whether we're in a case where we
1188 // might be creating a duplicate edge.
1189 j=-ed[qp][nu[qp]<<1];
1190 if(qp==up&&qs==us) {
1192 // If we're heading into the final part of the
1193 // new facet, then we never worry about the
1194 // duplicate edge calculation.
1195 new_double_edge=false;
1196 if(j>0) k+=nu[j];
1197 } else {
1198 if(j>0) {
1200 // This vertex was visited before, so
1201 // count those vertices to the ones we
1202 // already have.
1203 k+=nu[j];
1205 // The only time when we might make a
1206 // duplicate edge is if the point we're
1207 // going to move to next is also a
1208 // marginal point, so test for that
1209 // first.
1210 if(lw==1) {
1212 // Now see whether this marginal point
1213 // has been visited before.
1214 i=-ed[lp][nu[lp]<<1];
1215 if(i>0) {
1217 // Now see if the last edge of that other
1218 // marginal point actually ends up here.
1219 if(ed[i][nu[i]-1]==j) {
1220 new_double_edge=true;
1221 k-=1;
1222 } else new_double_edge=false;
1223 } else {
1225 // That marginal point hasn't been visited
1226 // before, so we probably don't have to worry
1227 // about duplicate edges, except in the
1228 // case when that's the way into the end
1229 // of the facet, because that way always creates
1230 // an edge.
1231 if(j==rp&&lp==up&&ed[qp][nu[qp]+qs]==us) {
1232 new_double_edge=true;
1233 k-=1;
1234 } else new_double_edge=false;
1236 } else new_double_edge=false;
1237 } else {
1239 // The vertex hasn't been visited
1240 // before, but let's see if it's
1241 // marginal
1242 if(lw==1) {
1244 // If it is, we need to check
1245 // for the case that it's a
1246 // small branch, and that we're
1247 // heading right back to where
1248 // we came from
1249 i=-ed[lp][nu[lp]<<1];
1250 if(i==cp) {
1251 new_double_edge=true;
1252 k-=1;
1253 } else new_double_edge=false;
1254 } else new_double_edge=false;
1258 // k now holds the number of edges of the new vertex
1259 // we are forming. Add memory for it if it doesn't exist
1260 // already.
1261 while(k>=current_vertex_order) add_memory_vorder(vc);
1262 if(mec[k]==mem[k]) add_memory(vc,k);
1264 // Now create a new vertex with order k, or augment
1265 // the existing one
1266 if(j>0) {
1268 // If we're augmenting a vertex but we don't
1269 // actually need any more edges, just skip this
1270 // routine to avoid memory confusion
1271 if(nu[j]!=k) {
1273 // Allocate memory and copy the edges
1274 // of the previous instance into it
1275 vc.n_set_aux1(k);
1276 edp=mep[k]+((k<<1)+1)*mec[k]++;
1277 i=0;
1278 while(i<nu[j]) {
1279 vc.n_copy_aux1(j,i);
1280 edp[i]=ed[j][i];
1281 edp[k+i]=ed[j][nu[j]+i];
1282 i++;
1284 edp[k<<1]=j;
1286 // Remove the previous instance with
1287 // fewer vertices from the memory
1288 // structure
1289 edd=mep[nu[j]]+((nu[j]<<1)+1)*--mec[nu[j]];
1290 if(edd!=ed[j]) {
1291 for(int lll=0;lll<=(nu[j]<<1);lll++) ed[j][lll]=edd[lll];
1292 vc.n_set_aux2_copy(j,nu[j]);
1293 vc.n_copy_pointer(edd[nu[j]<<1],j);
1294 ed[edd[nu[j]<<1]]=ed[j];
1296 vc.n_set_to_aux1(j);
1297 ed[j]=edp;
1298 } else i=nu[j];
1299 } else {
1301 // Allocate a new vertex of order k
1302 vc.n_set_pointer(p,k);
1303 ed[p]=mep[k]+((k<<1)+1)*mec[k]++;
1304 ed[p][k<<1]=p;
1305 if(stackp2==stacke2) add_memory_ds2();
1306 *(stackp2++)=qp;
1307 pts[p<<2]=pts[qp<<2];
1308 pts[(p<<2)+1]=pts[(qp<<2)+1];
1309 pts[(p<<2)+2]=pts[(qp<<2)+2];
1310 ed[qp][nu[qp]<<1]=-p;
1311 j=p++;
1312 i=0;
1314 nu[j]=k;
1316 // Unless the previous case was a double edge, connect
1317 // the first available edge of the new vertex to the
1318 // last one in the facet
1319 if(!double_edge) {
1320 ed[j][i]=cp;
1321 ed[j][nu[j]+i]=cs;
1322 vc.n_set(j,i,p_id);
1323 ed[cp][cs]=j;
1324 ed[cp][nu[cp]+cs]=i;
1325 i++;
1328 // Copy in the edges of the underlying vertex,
1329 // and do one less if this was a double edge
1330 qs=iqs;
1331 while(i<(new_double_edge?k:k-1)) {
1332 qs=cycle_up(qs,qp);
1333 lp=ed[qp][qs];ls=ed[qp][nu[qp]+qs];
1334 vc.n_copy(j,i,qp,qs);
1335 ed[j][i]=lp;
1336 ed[j][nu[j]+i]=ls;
1337 ed[lp][ls]=j;
1338 ed[lp][nu[lp]+ls]=i;
1339 ed[qp][qs]=-1;
1340 i++;
1342 qs=cycle_up(qs,qp);
1343 cs=i;
1344 cp=j;
1345 vc.n_copy(j,new_double_edge?0:cs,qp,qs);
1347 // Update the double_edge flag, to pass it
1348 // to the next instance of this routine
1349 double_edge=new_double_edge;
1353 // Connect the final created vertex to the initial one
1354 ed[cp][cs]=rp;
1355 *ed[rp]=cp;
1356 ed[cp][nu[cp]+cs]=0;
1357 ed[rp][nu[rp]]=cs;
1358 return false;
1361 /** During the creation of a new facet in the plane routine, it is possible
1362 * that some order two vertices may arise. This routine removes them.
1363 * Suppose an order two vertex joins c and d. If there's a edge between
1364 * c and d already, then the order two vertex is just removed; otherwise,
1365 * the order two vertex is removed and c and d are joined together directly.
1366 * It is possible this process will create order two or order one vertices,
1367 * and the routine is continually run until all of them are removed.
1368 * \return False if the vertex removal was unsuccessful, indicative of the cell
1369 * reducing to zero volume and disappearing; true if the vertex removal
1370 * was successful. */
1371 template<class vc_class>
1372 inline bool voronoicell_base::collapse_order2(vc_class &vc) {
1373 if(!collapse_order1(vc)) return false;
1374 int a,b,i,j,k,l;
1375 while(mec[2]>0) {
1377 // Pick a order 2 vertex and read in its edges
1378 i=--mec[2];
1379 j=mep[2][5*i];k=mep[2][5*i+1];
1380 if(j==k) {
1381 #if VOROPP_VERBOSE >=1
1382 fputs("Order two vertex joins itself",stderr);
1383 #endif
1384 return false;
1387 // Scan the edges of j to see if joins k
1388 for(l=0;l<nu[j];l++) {
1389 if(ed[j][l]==k) break;
1392 // If j doesn't already join k, join them together.
1393 // Otherwise delete the connection to the current
1394 // vertex from j and k.
1395 a=mep[2][5*i+2];b=mep[2][5*i+3];i=mep[2][5*i+4];
1396 if(l==nu[j]) {
1397 ed[j][a]=k;
1398 ed[k][b]=j;
1399 ed[j][nu[j]+a]=b;
1400 ed[k][nu[k]+b]=a;
1401 } else {
1402 if(!delete_connection(vc,j,a,false)) return false;
1403 if(!delete_connection(vc,k,b,true)) return false;
1406 // Compact the memory
1407 --p;
1408 if(up==i) up=0;
1409 if(p!=i) {
1410 if(up==p) up=i;
1411 pts[i<<2]=pts[p<<2];
1412 pts[(i<<2)+1]=pts[(p<<2)+1];
1413 pts[(i<<2)+2]=pts[(p<<2)+2];
1414 for(k=0;k<nu[p];k++) ed[ed[p][k]][ed[p][nu[p]+k]]=i;
1415 vc.n_copy_pointer(i,p);
1416 ed[i]=ed[p];
1417 nu[i]=nu[p];
1418 ed[i][nu[i]<<1]=i;
1421 // Collapse any order 1 vertices if they were created
1422 if(!collapse_order1(vc)) return false;
1424 return true;
1427 /** Order one vertices can potentially be created during the order two collapse
1428 * routine. This routine keeps removing them until there are none left.
1429 * \return False if the vertex removal was unsuccessful, indicative of the cell
1430 * having zero volume and disappearing; true if the vertex removal was
1431 * successful. */
1432 template<class vc_class>
1433 bool voronoicell_base::collapse_order1(vc_class &vc) {
1434 int i,j,k;
1435 while(mec[1]>0) {
1436 up=0;
1437 #if VOROPP_VERBOSE >=1
1438 fputs("Order one collapse\n",stderr);
1439 #endif
1440 i=--mec[1];
1441 j=mep[1][3*i];k=mep[1][3*i+1];
1442 i=mep[1][3*i+2];
1443 if(!delete_connection(vc,j,k,false)) return false;
1444 --p;
1445 if(up==i) up=0;
1446 if(p!=i) {
1447 if(up==p) up=i;
1448 pts[i<<2]=pts[p<<2];
1449 pts[(i<<2)+1]=pts[(p<<2)+1];
1450 pts[(i<<2)+2]=pts[(p<<2)+2];
1451 for(k=0;k<nu[p];k++) ed[ed[p][k]][ed[p][nu[p]+k]]=i;
1452 vc.n_copy_pointer(i,p);
1453 ed[i]=ed[p];
1454 nu[i]=nu[p];
1455 ed[i][nu[i]<<1]=i;
1458 return true;
1461 /** This routine deletes the kth edge of vertex j and reorganizes the memory.
1462 * If the neighbor computation is enabled, we also have to supply an handedness
1463 * flag to decide whether to preserve the plane on the left or right of the
1464 * connection.
1465 * \return False if a zero order vertex was formed, indicative of the cell
1466 * disappearing; true if the vertex removal was successful. */
1467 template<class vc_class>
1468 bool voronoicell_base::delete_connection(vc_class &vc,int j,int k,bool hand) {
1469 int q=hand?k:cycle_up(k,j);
1470 int i=nu[j]-1,l,*edp,*edd,m;
1471 #if VOROPP_VERBOSE >=1
1472 if(i<1) {
1473 fputs("Zero order vertex formed\n",stderr);
1474 return false;
1476 #endif
1477 if(mec[i]==mem[i]) add_memory(vc,i);
1478 vc.n_set_aux1(i);
1479 for(l=0;l<q;l++) vc.n_copy_aux1(j,l);
1480 while(l<i) {
1481 vc.n_copy_aux1_shift(j,l);
1482 l++;
1484 edp=mep[i]+((i<<1)+1)*mec[i]++;
1485 edp[i<<1]=j;
1486 for(l=0;l<k;l++) {
1487 edp[l]=ed[j][l];
1488 edp[l+i]=ed[j][l+nu[j]];
1490 while(l<i) {
1491 m=ed[j][l+1];
1492 edp[l]=m;
1493 k=ed[j][l+nu[j]+1];
1494 edp[l+i]=k;
1495 ed[m][nu[m]+k]--;
1496 l++;
1499 edd=mep[nu[j]]+((nu[j]<<1)+1)*--mec[nu[j]];
1500 for(l=0;l<=(nu[j]<<1);l++) ed[j][l]=edd[l];
1501 vc.n_set_aux2_copy(j,nu[j]);
1502 vc.n_copy_pointer(edd[nu[j]<<1],j);
1503 vc.n_set_to_aux1(j);
1504 ed[edd[nu[j]<<1]]=ed[j];
1505 ed[j]=edp;
1506 nu[j]=i;
1507 return true;
1510 /** This routine is a fall-back, in case floating point errors caused the usual
1511 * search routine to fail. In the fall-back routine, we just test every edge to
1512 * find one straddling the plane. */
1513 bool voronoicell_base::failsafe_find(int &lp,int &ls,int &us,double &l,double &u) {
1514 fputs("Bailed out of convex calculation (not supported yet)\n",stderr);
1515 exit(1);
1516 /* qw=1;lw=0;
1517 for(qp=0;qp<p;qp++) {
1518 qw=m_test(qp,q);
1519 if(qw==1) {
1521 // The point is inside the cutting space. Now
1522 // see if we can find a neighbor which isn't.
1523 for(us=0;us<nu[qp];us++) {
1524 lp=ed[qp][us];
1525 if(lp<qp) {
1526 lw=m_test(lp,l);
1527 if(lw!=1) break;
1530 if(us<nu[qp]) {
1531 up=qp;
1532 if(lw==0) {
1533 complicated_setup=true;
1534 } else {
1535 complicated_setup=false;
1536 u=q;
1537 ls=ed[up][nu[up]+us];
1539 break;
1541 } else if(qw==-1) {
1543 // The point is outside the cutting space. See
1544 // if we can find a neighbor which isn't.
1545 for(ls=0;ls<nu[qp];ls++) {
1546 up=ed[qp][ls];
1547 if(up<qp) {
1548 uw=m_test(up,u);
1549 if(uw!=-1) break;
1552 if(ls<nu[qp]) {
1553 if(uw==0) {
1554 up=qp;
1555 complicated_setup=true;
1556 } else {
1557 complicated_setup=false;
1558 lp=qp;l=q;
1559 us=ed[lp][nu[lp]+ls];
1561 break;
1563 } else {
1565 // The point is in the plane, so we just
1566 // proceed with the complicated setup routine
1567 up=qp;
1568 complicated_setup=true;
1569 break;
1572 if(qp==p) return qw==-1?true:false;*/
1575 /** Calculates the volume of the Voronoi cell, by decomposing the cell into
1576 * tetrahedra extending outward from the zeroth vertex, whose volumes are
1577 * evaluated using a scalar triple product.
1578 * \return A floating point number holding the calculated volume. */
1579 double voronoicell_base::volume() {
1580 const double fe=1/48.0;
1581 double vol=0;
1582 int i,j,k,l,m,n;
1583 double ux,uy,uz,vx,vy,vz,wx,wy,wz;
1584 for(i=1;i<p;i++) {
1585 ux=*pts-pts[i<<2];
1586 uy=pts[1]-pts[(i<<2)+1];
1587 uz=pts[2]-pts[(i<<2)+2];
1588 for(j=0;j<nu[i];j++) {
1589 k=ed[i][j];
1590 if(k>=0) {
1591 ed[i][j]=-1-k;
1592 l=cycle_up(ed[i][nu[i]+j],k);
1593 vx=pts[k<<2]-*pts;
1594 vy=pts[(k<<2)+1]-pts[1];
1595 vz=pts[(k<<2)+2]-pts[2];
1596 m=ed[k][l];ed[k][l]=-1-m;
1597 while(m!=i) {
1598 n=cycle_up(ed[k][nu[k]+l],m);
1599 wx=pts[(m<<2)]-*pts;
1600 wy=pts[(m<<2)+1]-pts[1];
1601 wz=pts[(m<<2)+2]-pts[2];
1602 vol+=ux*vy*wz+uy*vz*wx+uz*vx*wy-uz*vy*wx-uy*vx*wz-ux*vz*wy;
1603 k=m;l=n;vx=wx;vy=wy;vz=wz;
1604 m=ed[k][l];ed[k][l]=-1-m;
1609 reset_edges();
1610 return vol*fe;
1613 /** Calculates the contributions to the Minkowski functionals for this Voronoi cell.
1614 * \param[in] r the radius to consider.
1615 * \param[out] ar the area functional.
1616 * \param[out] vo the volume functional. */
1617 void voronoicell_base::minkowski(double r,double &ar,double &vo) {
1618 int i,j,k,l,m,n;
1619 ar=vo=0;
1620 for(i=1;i<p;i++) for(j=0;j<nu[i];j++) {
1621 k=ed[i][j];
1622 if(k>=0) {
1623 ed[i][j]=-1-k;
1624 l=cycle_up(ed[i][nu[i]+j],k);
1625 m=ed[k][l];ed[k][l]=-1-m;
1626 while(m!=i) {
1627 n=cycle_up(ed[k][nu[k]+l],m);
1628 minkowski_contrib(i,k,m,r,ar,vo);
1629 k=m;l=n;
1630 m=ed[k][l];ed[k][l]=-1-m;
1634 vo*=0.125;
1635 ar*=0.25;
1636 reset_edges();
1639 inline void voronoicell_base::minkowski_contrib(int i,int k,int m,double r,double &ar,double &vo) {
1640 double ix=pts[4*i],iy=pts[4*i+1],iz=pts[4*i+2],
1641 kx=pts[4*k],ky=pts[4*k+1],kz=pts[4*k+2],
1642 mx=pts[4*m],my=pts[4*m+1],mz=pts[4*m+2],
1643 ux=kx-ix,uy=ky-iy,uz=kz-iz,vx=mx-kx,vy=my-ky,vz=mz-kz,
1644 e1x=uz*vy-uy*vz,e1y=ux*vz-uz*vx,e1z=uy*vx-ux*vy,e2x,e2y,e2z,
1645 wmag=e1x*e1x+e1y*e1y+e1z*e1z;
1646 if(wmag<tol*tol) return;
1647 wmag=1/sqrt(wmag);
1648 e1x*=wmag;e1y*=wmag;e1z*=wmag;
1650 // Compute second orthonormal vector
1651 if(fabs(e1x)>0.5) {
1652 e2x=-e1y;e2y=e1x;e2z=0;
1653 } else if(fabs(e1y)>0.5) {
1654 e2x=0;e2y=-e1z;e2z=e1y;
1655 } else {
1656 e2x=e1z;e2y=0;e2z=-e1x;
1658 wmag=1/sqrt(e2x*e2x+e2y*e2y+e2z*e2z);
1659 e2x*=wmag;e2y*=wmag;e2z*=wmag;
1661 // Compute third orthonormal vector
1662 double e3x=e1z*e2y-e1y*e2z,
1663 e3y=e1x*e2z-e1z*e2x,
1664 e3z=e1y*e2x-e1x*e2y,
1665 x0=e1x*ix+e1y*iy+e1z*iz;
1666 if(x0<tol) return;
1668 double ir=e2x*ix+e2y*iy+e2z*iz,is=e3x*ix+e3y*iy+e3z*iz,
1669 kr=e2x*kx+e2y*ky+e2z*kz,ks=e3x*kx+e3y*ky+e3z*kz,
1670 mr=e2x*mx+e2y*my+e2z*mz,ms=e3x*mx+e3y*my+e3z*mz;
1671 printf("(%g,%g,%g)\n",e1x,e1y,e1z);
1672 printf("(%g,%g,%g)\n",e2x,e2y,e2z);
1673 printf("(%g,%g,%g)\n",e3x,e3y,e3z);
1674 printf("%g %g %g %g %g %g\n",ir,is,kr,ks,mr,ms);
1676 minkowski_edge(x0,ir,is,kr,ks,r,ar,vo);
1677 minkowski_edge(x0,kr,ks,mr,ms,r,ar,vo);
1678 minkowski_edge(x0,mr,ms,ir,is,r,ar,vo);
1681 void voronoicell_base::minkowski_edge(double x0,double r1,double s1,double r2,double s2,double r,double &ar,double &vo) {
1682 double r12=r2-r1,s12=s2-s1,l12=r12*r12+s12*s12;
1683 printf("ME %g %g %g %g\n",r1,s1,r2,s2);
1684 if(l12<tol*tol) return;
1685 l12=1/sqrt(l12);r12*=l12;s12*=l12;
1686 double y0=-s12*r1+r12*s1;
1687 printf("ME2 y0=(%g,%g) z0=%g z0=%g\n",y0,-s12*r2+r12*s2,-r12*r1-s12*s1,r12*r2+s12*s2);
1688 if(fabs(y0)<tol) return;
1689 minkowski_formula(x0,y0,r12*r1+s12*s1,r,ar,vo);
1690 minkowski_formula(x0,y0,-r12*r2-s12*s2,r,ar,vo);
1693 void voronoicell_base::minkowski_formula(double x0,double y0,double z0,double r,double &ar,double &vo) {
1694 printf("MF %g %g %g\n",x0,y0,z0);
1695 const double pi=3.1415926535897932384626433832795;
1696 if(fabs(z0)<tol) return;
1697 double si;
1698 if(z0<0) {z0=-z0;si=-1;} else si=1;
1699 if(y0<0) {y0=-y0;si=-si;}
1700 double xs=x0*x0,ys=y0*y0,zs=z0*z0,res=xs+ys,rvs=res+zs,theta=atan(z0/y0),rs=r*r,rc=rs*r,temp,voc,arc;
1701 if(r<x0) {
1702 puts("hi");
1703 temp=2*theta-0.5*pi-asin((zs*xs-ys*rvs)/(res*(ys+zs)));
1704 voc=rc/6.*temp;
1705 arc=rs*0.5*temp;
1706 } else if(rs<res) {
1707 temp=0.5*pi+asin((zs*xs-ys*rvs)/(res*(ys+zs)));
1708 voc=theta*0.5*(rs*x0-xs*x0/3.)-rc/6.*temp;
1709 arc=theta*x0*r-rs*0.5*temp;
1710 } else if(rs<rvs) {
1711 temp=theta-pi*0.5+asin(y0/sqrt(rs-xs));
1712 double temp2=(rs*x0-xs*x0/3.),
1713 x2s=rs*xs/res,y2s=rs*ys/res,
1714 temp3=asin((x2s-y2s-xs)/(rs-xs)),
1715 temp4=asin((zs*xs-ys*rvs)/(res*(ys+zs))),
1716 temp5=sqrt(rs-res);
1717 voc=0.5*temp*temp2+x0*y0/6.*temp5+r*rs/6*(temp3-temp4);
1718 arc=x0*r*temp-0.5*temp2*y0*r/((rs-xs)*temp5)+x0*y0/6.*r/temp5+rs*0.5*temp3+rs*rs/3.*2*xs*ys/(res*(rs-xs)*sqrt((rs-xs)*(rs-xs)-(x2s-y2s-xs)*(x2s-y2s-xs)))-rs*0.5*temp4;
1719 } else {
1720 voc=x0*y0*z0/6.;
1721 arc=0;
1723 vo+=voc*si;
1724 ar+=arc*si;
1728 /** Calculates the areas of each face of the Voronoi cell and prints the
1729 * results to an output stream.
1730 * \param[out] v the vector to store the results in. */
1731 void voronoicell_base::face_areas(std::vector<double> &v) {
1732 double area;
1733 v.clear();
1734 int i,j,k,l,m,n;
1735 double ux,uy,uz,vx,vy,vz,wx,wy,wz;
1736 for(i=1;i<p;i++) for(j=0;j<nu[i];j++) {
1737 k=ed[i][j];
1738 if(k>=0) {
1739 area=0;
1740 ed[i][j]=-1-k;
1741 l=cycle_up(ed[i][nu[i]+j],k);
1742 m=ed[k][l];ed[k][l]=-1-m;
1743 while(m!=i) {
1744 n=cycle_up(ed[k][nu[k]+l],m);
1745 ux=pts[4*k]-pts[4*i];
1746 uy=pts[4*k+1]-pts[4*i+1];
1747 uz=pts[4*k+2]-pts[4*i+2];
1748 vx=pts[4*m]-pts[4*i];
1749 vy=pts[4*m+1]-pts[4*i+1];
1750 vz=pts[4*m+2]-pts[4*i+2];
1751 wx=uy*vz-uz*vy;
1752 wy=uz*vx-ux*vz;
1753 wz=ux*vy-uy*vx;
1754 area+=sqrt(wx*wx+wy*wy+wz*wz);
1755 k=m;l=n;
1756 m=ed[k][l];ed[k][l]=-1-m;
1758 v.push_back(0.125*area);
1761 reset_edges();
1765 /** Calculates the total surface area of the Voronoi cell.
1766 * \return The computed area. */
1767 double voronoicell_base::surface_area() {
1768 double area=0;
1769 int i,j,k,l,m,n;
1770 double ux,uy,uz,vx,vy,vz,wx,wy,wz;
1771 for(i=1;i<p;i++) for(j=0;j<nu[i];j++) {
1772 k=ed[i][j];
1773 if(k>=0) {
1774 ed[i][j]=-1-k;
1775 l=cycle_up(ed[i][nu[i]+j],k);
1776 m=ed[k][l];ed[k][l]=-1-m;
1777 while(m!=i) {
1778 n=cycle_up(ed[k][nu[k]+l],m);
1779 ux=pts[4*k]-pts[4*i];
1780 uy=pts[4*k+1]-pts[4*i+1];
1781 uz=pts[4*k+2]-pts[4*i+2];
1782 vx=pts[4*m]-pts[4*i];
1783 vy=pts[4*m+1]-pts[4*i+1];
1784 vz=pts[4*m+2]-pts[4*i+2];
1785 wx=uy*vz-uz*vy;
1786 wy=uz*vx-ux*vz;
1787 wz=ux*vy-uy*vx;
1788 area+=sqrt(wx*wx+wy*wy+wz*wz);
1789 k=m;l=n;
1790 m=ed[k][l];ed[k][l]=-1-m;
1794 reset_edges();
1795 return 0.125*area;
1799 /** Calculates the centroid of the Voronoi cell, by decomposing the cell into
1800 * tetrahedra extending outward from the zeroth vertex.
1801 * \param[out] (cx,cy,cz) references to floating point numbers in which to
1802 * pass back the centroid vector. */
1803 void voronoicell_base::centroid(double &cx,double &cy,double &cz) {
1804 double tvol,vol=0;cx=cy=cz=0;
1805 int i,j,k,l,m,n;
1806 double ux,uy,uz,vx,vy,vz,wx,wy,wz;
1807 for(i=1;i<p;i++) {
1808 ux=*pts-pts[4*i];
1809 uy=pts[1]-pts[4*i+1];
1810 uz=pts[2]-pts[4*i+2];
1811 for(j=0;j<nu[i];j++) {
1812 k=ed[i][j];
1813 if(k>=0) {
1814 ed[i][j]=-1-k;
1815 l=cycle_up(ed[i][nu[i]+j],k);
1816 vx=pts[4*k]-*pts;
1817 vy=pts[4*k+1]-pts[1];
1818 vz=pts[4*k+2]-pts[2];
1819 m=ed[k][l];ed[k][l]=-1-m;
1820 while(m!=i) {
1821 n=cycle_up(ed[k][nu[k]+l],m);
1822 wx=pts[4*m]-*pts;
1823 wy=pts[4*m+1]-pts[1];
1824 wz=pts[4*m+2]-pts[2];
1825 tvol=ux*vy*wz+uy*vz*wx+uz*vx*wy-uz*vy*wx-uy*vx*wz-ux*vz*wy;
1826 vol+=tvol;
1827 cx+=(wx+vx-ux)*tvol;
1828 cy+=(wy+vy-uy)*tvol;
1829 cz+=(wz+vz-uz)*tvol;
1830 k=m;l=n;vx=wx;vy=wy;vz=wz;
1831 m=ed[k][l];ed[k][l]=-1-m;
1836 reset_edges();
1837 if(vol>tol_cu) {
1838 vol=0.125/vol;
1839 cx=cx*vol+0.5*(*pts);
1840 cy=cy*vol+0.5*pts[1];
1841 cz=cz*vol+0.5*pts[2];
1842 } else cx=cy=cz=0;
1845 /** Computes the maximum radius squared of a vertex from the center of the
1846 * cell. It can be used to determine when enough particles have been testing an
1847 * all planes that could cut the cell have been considered.
1848 * \return The maximum radius squared of a vertex.*/
1849 double voronoicell_base::max_radius_squared() {
1850 double r,s,*ptsp=pts+4,*ptse=pts+(p<<2);
1851 r=*pts*(*pts)+pts[1]*pts[1]+pts[2]*pts[2];
1852 while(ptsp<ptse) {
1853 s=*ptsp*(*ptsp);ptsp++;
1854 s+=*ptsp*(*ptsp);ptsp++;
1855 s+=*ptsp*(*ptsp);ptsp+=2;
1856 if(s>r) r=s;
1858 return r;
1861 /** Calculates the total edge distance of the Voronoi cell.
1862 * \return A floating point number holding the calculated distance. */
1863 double voronoicell_base::total_edge_distance() {
1864 int i,j,k;
1865 double dis=0,dx,dy,dz;
1866 for(i=0;i<p-1;i++) for(j=0;j<nu[i];j++) {
1867 k=ed[i][j];
1868 if(k>i) {
1869 dx=pts[k<<2]-pts[i<<2];
1870 dy=pts[(k<<2)+1]-pts[(i<<2)+1];
1871 dz=pts[(k<<2)+2]-pts[(i<<2)+2];
1872 dis+=sqrt(dx*dx+dy*dy+dz*dz);
1875 return 0.5*dis;
1878 /** Outputs the edges of the Voronoi cell in POV-Ray format to an open file
1879 * stream, displacing the cell by given vector.
1880 * \param[in] (x,y,z) a displacement vector to be added to the cell's position.
1881 * \param[in] fp a file handle to write to. */
1882 void voronoicell_base::draw_pov(double x,double y,double z,FILE* fp) {
1883 int i,j,k;double *ptsp=pts,*pt2;
1884 char posbuf1[128],posbuf2[128];
1885 for(i=0;i<p;i++,ptsp+=4) {
1886 sprintf(posbuf1,"%g,%g,%g",x+*ptsp*0.5,y+ptsp[1]*0.5,z+ptsp[2]*0.5);
1887 fprintf(fp,"sphere{<%s>,r}\n",posbuf1);
1888 for(j=0;j<nu[i];j++) {
1889 k=ed[i][j];
1890 if(k<i) {
1891 pt2=pts+(k<<2);
1892 sprintf(posbuf2,"%g,%g,%g",x+*pt2*0.5,y+0.5*pt2[1],z+0.5*pt2[2]);
1893 if(strcmp(posbuf1,posbuf2)!=0) fprintf(fp,"cylinder{<%s>,<%s>,r}\n",posbuf1,posbuf2);
1899 /** Outputs the edges of the Voronoi cell in gnuplot format to an output stream.
1900 * \param[in] (x,y,z) a displacement vector to be added to the cell's position.
1901 * \param[in] fp a file handle to write to. */
1902 void voronoicell_base::draw_gnuplot(double x,double y,double z,FILE *fp) {
1903 int i,j,k,l,m;
1904 for(i=1;i<p;i++) for(j=0;j<nu[i];j++) {
1905 k=ed[i][j];
1906 if(k>=0) {
1907 fprintf(fp,"%g %g %g\n",x+0.5*pts[i<<2],y+0.5*pts[(i<<2)+1],z+0.5*pts[(i<<2)+2]);
1908 l=i;m=j;
1909 do {
1910 ed[k][ed[l][nu[l]+m]]=-1-l;
1911 ed[l][m]=-1-k;
1912 l=k;
1913 fprintf(fp,"%g %g %g\n",x+0.5*pts[k<<2],y+0.5*pts[(k<<2)+1],z+0.5*pts[(k<<2)+2]);
1914 } while (search_edge(l,m,k));
1915 fputs("\n\n",fp);
1918 reset_edges();
1921 inline bool voronoicell_base::search_edge(int l,int &m,int &k) {
1922 for(m=0;m<nu[l];m++) {
1923 k=ed[l][m];
1924 if(k>=0) return true;
1926 return false;
1929 /** Outputs the Voronoi cell in the POV mesh2 format, described in section
1930 * 1.3.2.2 of the POV-Ray documentation. The mesh2 output consists of a list of
1931 * vertex vectors, followed by a list of triangular faces. The routine also
1932 * makes use of the optional inside_vector specification, which makes the mesh
1933 * object solid, so that the POV-Ray Constructive Solid Geometry (CSG) can be
1934 * applied.
1935 * \param[in] (x,y,z) a displacement vector to be added to the cell's position.
1936 * \param[in] fp a file handle to write to. */
1937 void voronoicell_base::draw_pov_mesh(double x,double y,double z,FILE *fp) {
1938 int i,j,k,l,m,n;
1939 double *ptsp=pts;
1940 fprintf(fp,"mesh2 {\nvertex_vectors {\n%d\n",p);
1941 for(i=0;i<p;i++,ptsp+=4) fprintf(fp,",<%g,%g,%g>\n",x+*ptsp*0.5,y+ptsp[1]*0.5,z+ptsp[2]*0.5);
1942 fprintf(fp,"}\nface_indices {\n%d\n",(p-2)<<1);
1943 for(i=1;i<p;i++) for(j=0;j<nu[i];j++) {
1944 k=ed[i][j];
1945 if(k>=0) {
1946 ed[i][j]=-1-k;
1947 l=cycle_up(ed[i][nu[i]+j],k);
1948 m=ed[k][l];ed[k][l]=-1-m;
1949 while(m!=i) {
1950 n=cycle_up(ed[k][nu[k]+l],m);
1951 fprintf(fp,",<%d,%d,%d>\n",i,k,m);
1952 k=m;l=n;
1953 m=ed[k][l];ed[k][l]=-1-m;
1957 fputs("}\ninside_vector <0,0,1>\n}\n",fp);
1958 reset_edges();
1961 /** Several routines in the class that gather cell-based statistics internally
1962 * track their progress by flipping edges to negative so that they know what
1963 * parts of the cell have already been tested. This function resets them back
1964 * to positive. When it is called, it assumes that every edge in the routine
1965 * should have already been flipped to negative, and it bails out with an
1966 * internal error if it encounters a positive edge. */
1967 inline void voronoicell_base::reset_edges() {
1968 int i,j;
1969 for(i=0;i<p;i++) for(j=0;j<nu[i];j++) {
1970 if(ed[i][j]>=0) voro_fatal_error("Edge reset routine found a previously untested edge",VOROPP_INTERNAL_ERROR);
1971 ed[i][j]=-1-ed[i][j];
1975 /** Checks to see if a given vertex is inside, outside or within the test
1976 * plane. If the point is far away from the test plane, the routine immediately
1977 * returns whether it is inside or outside. If the routine is close the the
1978 * plane and within the specified tolerance, then the special check_marginal()
1979 * routine is called.
1980 * \param[in] n the vertex to test.
1981 * \param[out] ans the result of the scalar product used in evaluating the
1982 * location of the point.
1983 * \return -1 if the point is inside the plane, 1 if the point is outside the
1984 * plane, or 0 if the point is within the plane. */
1985 inline unsigned int voronoicell_base::m_test(int n,double &ans) {
1986 if(mask[n]>=maskc) {
1987 ans=pts[4*n+3];
1988 return mask[n]&3;
1989 } else return m_calc(n,ans);
1992 unsigned int voronoicell_base::m_calc(int n,double &ans) {
1993 double *pp=pts+4*n;
1994 ans=*(pp++)*px;
1995 ans+=*(pp++)*py;
1996 ans+=*(pp++)*pz-prsq;
1997 *pp=ans;
1998 unsigned int maskr=ans<-tol?0:(ans>tol?2:1);
1999 mask[n]=maskc|maskr;
2000 return maskr;
2004 /** Checks to see if a given vertex is inside, outside or within the test
2005 * plane. If the point is far away from the test plane, the routine immediately
2006 * returns whether it is inside or outside. If the routine is close the the
2007 * plane and within the specified tolerance, then the special check_marginal()
2008 * routine is called.
2009 * \param[in] n the vertex to test.
2010 * \param[out] ans the result of the scalar product used in evaluating the
2011 * location of the point.
2012 * \return -1 if the point is inside the plane, 1 if the point is outside the
2013 * plane, or 0 if the point is within the plane. */
2014 inline unsigned int voronoicell_base::m_testx(int n,double &ans) {
2015 unsigned int maskr;
2016 if(mask[n]>=maskc) {
2017 ans=pts[4*n+3];
2018 maskr=mask[n]&3;
2019 } else maskr=m_calc(n,ans);
2020 if(maskr==0&&ans>-big_tol&&ed[n][nu[n]<<1]!=-1) {
2021 ed[n][nu[n]<<1]=-1;
2022 if(stackp3==stacke3) add_memory_xse();
2023 *(stackp3++)=n;
2025 return maskr;
2028 /** This routine calculates the unit normal vectors for every face.
2029 * \param[out] v the vector to store the results in. */
2030 void voronoicell_base::normals(std::vector<double> &v) {
2031 int i,j,k;
2032 v.clear();
2033 for(i=1;i<p;i++) for(j=0;j<nu[i];j++) {
2034 k=ed[i][j];
2035 if(k>=0) normals_search(v,i,j,k);
2037 reset_edges();
2040 /** This inline routine is called by normals(). It attempts to construct a
2041 * single normal vector that is associated with a particular face. It first
2042 * traces around the face, trying to find two vectors along the face edges
2043 * whose vector product is above the numerical tolerance. It then constructs
2044 * the normal vector using this product. If the face is too small, and none of
2045 * the vector products are large enough, the routine may return (0,0,0) as the
2046 * normal vector.
2047 * \param[in] v the vector to store the results in.
2048 * \param[in] i the initial vertex of the face to test.
2049 * \param[in] j the index of an edge of the vertex.
2050 * \param[in] k the neighboring vertex of i, set to ed[i][j]. */
2051 inline void voronoicell_base::normals_search(std::vector<double> &v,int i,int j,int k) {
2052 ed[i][j]=-1-k;
2053 int l=cycle_up(ed[i][nu[i]+j],k),m;
2054 double ux,uy,uz,vx,vy,vz,wx,wy,wz,wmag;
2055 do {
2056 m=ed[k][l];ed[k][l]=-1-m;
2057 ux=pts[4*m]-pts[4*k];
2058 uy=pts[4*m+1]-pts[4*k+1];
2059 uz=pts[4*m+2]-pts[4*k+2];
2061 // Test to see if the length of this edge is above the tolerance
2062 if(ux*ux+uy*uy+uz*uz>tol) {
2063 while(m!=i) {
2064 l=cycle_up(ed[k][nu[k]+l],m);
2065 k=m;m=ed[k][l];ed[k][l]=-1-m;
2066 vx=pts[4*m]-pts[4*k];
2067 vy=pts[4*m+1]-pts[4*k+1];
2068 vz=pts[4*m+2]-pts[4*k+2];
2070 // Construct the vector product of this edge with
2071 // the previous one
2072 wx=uz*vy-uy*vz;
2073 wy=ux*vz-uz*vx;
2074 wz=uy*vx-ux*vy;
2075 wmag=wx*wx+wy*wy+wz*wz;
2077 // Test to see if this vector product of the
2078 // two edges is above the tolerance
2079 if(wmag>tol) {
2081 // Construct the normal vector and print it
2082 wmag=1/sqrt(wmag);
2083 v.push_back(wx*wmag);
2084 v.push_back(wy*wmag);
2085 v.push_back(wz*wmag);
2087 // Mark all of the remaining edges of this
2088 // face and exit
2089 while(m!=i) {
2090 l=cycle_up(ed[k][nu[k]+l],m);
2091 k=m;m=ed[k][l];ed[k][l]=-1-m;
2093 return;
2096 v.push_back(0);
2097 v.push_back(0);
2098 v.push_back(0);
2099 return;
2101 l=cycle_up(ed[k][nu[k]+l],m);
2102 k=m;
2103 } while (k!=i);
2104 v.push_back(0);
2105 v.push_back(0);
2106 v.push_back(0);
2110 /** Returns the number of faces of a computed Voronoi cell.
2111 * \return The number of faces. */
2112 int voronoicell_base::number_of_faces() {
2113 int i,j,k,l,m,s=0;
2114 for(i=1;i<p;i++) for(j=0;j<nu[i];j++) {
2115 k=ed[i][j];
2116 if(k>=0) {
2117 s++;
2118 ed[i][j]=-1-k;
2119 l=cycle_up(ed[i][nu[i]+j],k);
2120 do {
2121 m=ed[k][l];
2122 ed[k][l]=-1-m;
2123 l=cycle_up(ed[k][nu[k]+l],m);
2124 k=m;
2125 } while (k!=i);
2129 reset_edges();
2130 return s;
2133 /** Returns a vector of the vertex orders.
2134 * \param[out] v the vector to store the results in. */
2135 void voronoicell_base::vertex_orders(std::vector<int> &v) {
2136 v.resize(p);
2137 for(int i=0;i<p;i++) v[i]=nu[i];
2140 /** Outputs the vertex orders.
2141 * \param[out] fp the file handle to write to. */
2142 void voronoicell_base::output_vertex_orders(FILE *fp) {
2143 if(p>0) {
2144 fprintf(fp,"%d",*nu);
2145 for(int *nup=nu+1;nup<nu+p;nup++) fprintf(fp," %d",*nup);
2149 /** Returns a vector of the vertex vectors using the local coordinate system.
2150 * \param[out] v the vector to store the results in. */
2151 void voronoicell_base::vertices(std::vector<double> &v) {
2152 v.resize(p<<2);
2153 double *ptsp=pts;
2154 for(int i=0;i<3*p;i+=3) {
2155 v[i]=*(ptsp++)*0.5;
2156 v[i+1]=*(ptsp++)*0.5;
2157 v[i+2]=*ptsp*0.5;ptsp+=2;
2161 /** Outputs the vertex vectors using the local coordinate system.
2162 * \param[out] fp the file handle to write to. */
2163 void voronoicell_base::output_vertices(FILE *fp) {
2164 if(p>0) {
2165 fprintf(fp,"(%g,%g,%g)",*pts*0.5,pts[1]*0.5,pts[2]*0.5);
2166 for(double *ptsp=pts+4;ptsp<pts+(p<<2);ptsp+=4) fprintf(fp," (%g,%g,%g)",*ptsp*0.5,ptsp[1]*0.5,ptsp[2]*0.5);
2171 /** Returns a vector of the vertex vectors in the global coordinate system.
2172 * \param[out] v the vector to store the results in.
2173 * \param[in] (x,y,z) the position vector of the particle in the global
2174 * coordinate system. */
2175 void voronoicell_base::vertices(double x,double y,double z,std::vector<double> &v) {
2176 v.resize(3*p);
2177 double *ptsp=pts;
2178 for(int i=0;i<3*p;i+=3) {
2179 v[i]=x+*(ptsp++)*0.5;
2180 v[i+1]=y+*(ptsp++)*0.5;
2181 v[i+2]=z+*ptsp*0.5;ptsp+=2;
2185 /** Outputs the vertex vectors using the global coordinate system.
2186 * \param[out] fp the file handle to write to.
2187 * \param[in] (x,y,z) the position vector of the particle in the global
2188 * coordinate system. */
2189 void voronoicell_base::output_vertices(double x,double y,double z,FILE *fp) {
2190 if(p>0) {
2191 fprintf(fp,"(%g,%g,%g)",x+*pts*0.5,y+pts[1]*0.5,z+pts[2]*0.5);
2192 for(double *ptsp=pts+4;ptsp<pts+(p<<2);ptsp+=4) fprintf(fp," (%g,%g,%g)",x+*ptsp*0.5,y+ptsp[1]*0.5,z+ptsp[2]*0.5);
2196 /** This routine returns the perimeters of each face.
2197 * \param[out] v the vector to store the results in. */
2198 void voronoicell_base::face_perimeters(std::vector<double> &v) {
2199 v.clear();
2200 int i,j,k,l,m;
2201 double dx,dy,dz,perim;
2202 for(i=1;i<p;i++) for(j=0;j<nu[i];j++) {
2203 k=ed[i][j];
2204 if(k>=0) {
2205 dx=pts[k<<2]-pts[i<<2];
2206 dy=pts[(k<<2)+1]-pts[(i<<2)+1];
2207 dz=pts[(k<<2)+2]-pts[(i<<2)+2];
2208 perim=sqrt(dx*dx+dy*dy+dz*dz);
2209 ed[i][j]=-1-k;
2210 l=cycle_up(ed[i][nu[i]+j],k);
2211 do {
2212 m=ed[k][l];
2213 dx=pts[m<<2]-pts[k<<2];
2214 dy=pts[(m<<2)+1]-pts[(k<<2)+1];
2215 dz=pts[(m<<2)+2]-pts[(k<<2)+2];
2216 perim+=sqrt(dx*dx+dy*dy+dz*dz);
2217 ed[k][l]=-1-m;
2218 l=cycle_up(ed[k][nu[k]+l],m);
2219 k=m;
2220 } while (k!=i);
2221 v.push_back(0.5*perim);
2224 reset_edges();
2227 /** For each face, this routine outputs a bracketed sequence of numbers
2228 * containing a list of all the vertices that make up that face.
2229 * \param[out] v the vector to store the results in. */
2230 void voronoicell_base::face_vertices(std::vector<int> &v) {
2231 int i,j,k,l,m,vp(0),vn;
2232 v.clear();
2233 for(i=1;i<p;i++) for(j=0;j<nu[i];j++) {
2234 k=ed[i][j];
2235 if(k>=0) {
2236 v.push_back(0);
2237 v.push_back(i);
2238 ed[i][j]=-1-k;
2239 l=cycle_up(ed[i][nu[i]+j],k);
2240 do {
2241 v.push_back(k);
2242 m=ed[k][l];
2243 ed[k][l]=-1-m;
2244 l=cycle_up(ed[k][nu[k]+l],m);
2245 k=m;
2246 } while (k!=i);
2247 vn=v.size();
2248 v[vp]=vn-vp-1;
2249 vp=vn;
2252 reset_edges();
2255 /** Outputs a list of the number of edges in each face.
2256 * \param[out] v the vector to store the results in. */
2257 void voronoicell_base::face_orders(std::vector<int> &v) {
2258 int i,j,k,l,m,q;
2259 v.clear();
2260 for(i=1;i<p;i++) for(j=0;j<nu[i];j++) {
2261 k=ed[i][j];
2262 if(k>=0) {
2263 q=1;
2264 ed[i][j]=-1-k;
2265 l=cycle_up(ed[i][nu[i]+j],k);
2266 do {
2267 q++;
2268 m=ed[k][l];
2269 ed[k][l]=-1-m;
2270 l=cycle_up(ed[k][nu[k]+l],m);
2271 k=m;
2272 } while (k!=i);
2273 v.push_back(q);;
2276 reset_edges();
2279 /** Computes the number of edges that each face has and outputs a frequency
2280 * table of the results.
2281 * \param[out] v the vector to store the results in. */
2282 void voronoicell_base::face_freq_table(std::vector<int> &v) {
2283 int i,j,k,l,m,q;
2284 v.clear();
2285 for(i=1;i<p;i++) for(j=0;j<nu[i];j++) {
2286 k=ed[i][j];
2287 if(k>=0) {
2288 q=1;
2289 ed[i][j]=-1-k;
2290 l=cycle_up(ed[i][nu[i]+j],k);
2291 do {
2292 q++;
2293 m=ed[k][l];
2294 ed[k][l]=-1-m;
2295 l=cycle_up(ed[k][nu[k]+l],m);
2296 k=m;
2297 } while (k!=i);
2298 if((unsigned int) q>=v.size()) v.resize(q+1,0);
2299 v[q]++;
2302 reset_edges();
2305 /** This routine tests to see whether the cell intersects a plane by starting
2306 * from the guess point up. If up intersects, then it immediately returns true.
2307 * Otherwise, it calls the plane_intersects_track() routine.
2308 * \param[in] (x,y,z) the normal vector to the plane.
2309 * \param[in] rsq the distance along this vector of the plane.
2310 * \return False if the plane does not intersect the plane, true if it does. */
2311 bool voronoicell_base::plane_intersects(double x,double y,double z,double rsq) {
2312 double g=x*pts[up<<2]+y*pts[(up<<2)+1]+z*pts[(up<<2)+2];
2313 if(g<rsq) return plane_intersects_track(x,y,z,rsq,g);
2314 return true;
2317 /** This routine tests to see if a cell intersects a plane. It first tests a
2318 * random sample of approximately sqrt(p)/4 points. If any of those are
2319 * intersect, then it immediately returns true. Otherwise, it takes the closest
2320 * point and passes that to plane_intersect_track() routine.
2321 * \param[in] (x,y,z) the normal vector to the plane.
2322 * \param[in] rsq the distance along this vector of the plane.
2323 * \return False if the plane does not intersect the plane, true if it does. */
2324 bool voronoicell_base::plane_intersects_guess(double x,double y,double z,double rsq) {
2325 up=0;
2326 double g=x*pts[up<<2]+y*pts[(up<<2)+1]+z*pts[(up<<2)+2];
2327 if(g<rsq) {
2328 int ca=1,cc=p>>3,mp=1;
2329 double m;
2330 while(ca<cc) {
2331 m=x*pts[4*mp]+y*pts[4*mp+1]+z*pts[4*mp+2];
2332 if(m>g) {
2333 if(m>rsq) return true;
2334 g=m;up=mp;
2336 ca+=mp++;
2338 return plane_intersects_track(x,y,z,rsq,g);
2340 return true;
2343 /* This routine tests to see if a cell intersects a plane, by tracing over the
2344 * cell from vertex to vertex, starting at up. It is meant to be called either
2345 * by plane_intersects() or plane_intersects_track(), when those routines
2346 * cannot immediately resolve the case.
2347 * \param[in] (x,y,z) the normal vector to the plane.
2348 * \param[in] rsq the distance along this vector of the plane.
2349 * \param[in] g the distance of up from the plane.
2350 * \return False if the plane does not intersect the plane, true if it does. */
2351 inline bool voronoicell_base::plane_intersects_track(double x,double y,double z,double rsq,double g) {
2353 for(int tp=0;tp<p;tp++) if(x*pts[tp<<2]+y*pts[(tp<<2)+1]+z*pts[(tp<<2)+2]>rsq) return true;
2354 return false;
2356 int ls,us,lp;
2357 double l,u;
2358 unsigned int uw;
2360 // Initialize the safe testing routine
2361 px=x;py=y;pz=z;prsq=rsq;
2362 maskc+=4;
2363 if(maskc<4) reset_mask();
2365 return search_upward(uw,lp,ls,us,l,u);
2368 int count=0,ls,us,tp;
2369 double t;
2370 // The test point is outside of the cutting space
2371 for(us=0;us<nu[up];us++) {
2372 tp=ed[up][us];
2373 t=x*pts[tp<<2]+y*pts[(tp<<2)+1]+z*pts[(tp<<2)+2];
2374 if(t>g) {
2375 ls=ed[up][nu[up]+us];
2376 up=tp;
2377 while (t<rsq) {
2378 if(++count>=p) {
2379 #if VOROPP_VERBOSE >=1
2380 fputs("Bailed out of convex calculation",stderr);
2381 #endif
2382 for(tp=0;tp<p;tp++) if(x*pts[tp<<2]+y*pts[(tp<<2)+1]+z*pts[(tp<<2)+2]>rsq) return true;
2383 return false;
2386 // Test all the neighbors of the current point
2387 // and find the one which is closest to the
2388 // plane
2389 for(us=0;us<ls;us++) {
2390 tp=ed[up][us];double *pp=pts+(tp<<2);
2391 g=x*(*pp)+y*pp[1]+z*pp[2];
2392 if(g>t) break;
2394 if(us==ls) {
2395 us++;
2396 while(us<nu[up]) {
2397 tp=ed[up][us];double *pp=pts+(tp<<2);
2398 g=x*(*pp)+y*pp[1]+z*pp[2];
2399 if(g>t) break;
2400 us++;
2402 if(us==nu[up]) return false;
2404 ls=ed[up][nu[up]+us];up=tp;t=g;
2406 return true;
2409 return false;*/
2412 /** Counts the number of edges of the Voronoi cell.
2413 * \return the number of edges. */
2414 int voronoicell_base::number_of_edges() {
2415 int edges=0,*nup=nu;
2416 while(nup<nu+p) edges+=*(nup++);
2417 return edges>>1;
2420 /** Outputs a custom string of information about the Voronoi cell. The string
2421 * of information follows a similar style as the C printf command, and detailed
2422 * information about its format is available at
2423 * http://math.lbl.gov/voro++/doc/custom.html.
2424 * \param[in] format the custom string to print.
2425 * \param[in] i the ID of the particle associated with this Voronoi cell.
2426 * \param[in] (x,y,z) the position of the particle associated with this Voronoi
2427 * cell.
2428 * \param[in] r a radius associated with the particle.
2429 * \param[in] fp the file handle to write to. */
2430 void voronoicell_base::output_custom(const char *format,int i,double x,double y,double z,double r,FILE *fp) {
2431 char *fmp=(const_cast<char*>(format));
2432 std::vector<int> vi;
2433 std::vector<double> vd;
2434 while(*fmp!=0) {
2435 if(*fmp=='%') {
2436 fmp++;
2437 switch(*fmp) {
2439 // Particle-related output
2440 case 'i': fprintf(fp,"%d",i);break;
2441 case 'x': fprintf(fp,"%g",x);break;
2442 case 'y': fprintf(fp,"%g",y);break;
2443 case 'z': fprintf(fp,"%g",z);break;
2444 case 'q': fprintf(fp,"%g %g %g",x,y,z);break;
2445 case 'r': fprintf(fp,"%g",r);break;
2447 // Vertex-related output
2448 case 'w': fprintf(fp,"%d",p);break;
2449 case 'p': output_vertices(fp);break;
2450 case 'P': output_vertices(x,y,z,fp);break;
2451 case 'o': output_vertex_orders(fp);break;
2452 case 'm': fprintf(fp,"%g",0.25*max_radius_squared());break;
2454 // Edge-related output
2455 case 'g': fprintf(fp,"%d",number_of_edges());break;
2456 case 'E': fprintf(fp,"%g",total_edge_distance());break;
2457 case 'e': face_perimeters(vd);voro_print_vector(vd,fp);break;
2459 // Face-related output
2460 case 's': fprintf(fp,"%d",number_of_faces());break;
2461 case 'F': fprintf(fp,"%g",surface_area());break;
2462 case 'A': {
2463 face_freq_table(vi);
2464 voro_print_vector(vi,fp);
2465 } break;
2466 case 'a': face_orders(vi);voro_print_vector(vi,fp);break;
2467 case 'f': face_areas(vd);voro_print_vector(vd,fp);break;
2468 case 't': {
2469 face_vertices(vi);
2470 voro_print_face_vertices(vi,fp);
2471 } break;
2472 case 'l': normals(vd);
2473 voro_print_positions(vd,fp);
2474 break;
2475 case 'n': neighbors(vi);
2476 voro_print_vector(vi,fp);
2477 break;
2479 // Volume-related output
2480 case 'v': fprintf(fp,"%g",volume());break;
2481 case 'c': {
2482 double cx,cy,cz;
2483 centroid(cx,cy,cz);
2484 fprintf(fp,"%g %g %g",cx,cy,cz);
2485 } break;
2486 case 'C': {
2487 double cx,cy,cz;
2488 centroid(cx,cy,cz);
2489 fprintf(fp,"%g %g %g",x+cx,y+cy,z+cz);
2490 } break;
2492 // End-of-string reached
2493 case 0: fmp--;break;
2495 // The percent sign is not part of a
2496 // control sequence
2497 default: putc('%',fp);putc(*fmp,fp);
2499 } else putc(*fmp,fp);
2500 fmp++;
2502 fputs("\n",fp);
2505 /** This initializes the class to be a rectangular box. It calls the base class
2506 * initialization routine to set up the edge and vertex information, and then
2507 * sets up the neighbor information, with initial faces being assigned ID
2508 * numbers from -1 to -6.
2509 * \param[in] (xmin,xmax) the minimum and maximum x coordinates.
2510 * \param[in] (ymin,ymax) the minimum and maximum y coordinates.
2511 * \param[in] (zmin,zmax) the minimum and maximum z coordinates. */
2512 void voronoicell_neighbor::init(double xmin,double xmax,double ymin,double ymax,double zmin,double zmax) {
2513 init_base(xmin,xmax,ymin,ymax,zmin,zmax);
2514 int *q=mne[3];
2515 *q=-5;q[1]=-3;q[2]=-1;
2516 q[3]=-5;q[4]=-2;q[5]=-3;
2517 q[6]=-5;q[7]=-1;q[8]=-4;
2518 q[9]=-5;q[10]=-4;q[11]=-2;
2519 q[12]=-6;q[13]=-1;q[14]=-3;
2520 q[15]=-6;q[16]=-3;q[17]=-2;
2521 q[18]=-6;q[19]=-4;q[20]=-1;
2522 q[21]=-6;q[22]=-2;q[23]=-4;
2523 *ne=q;ne[1]=q+3;ne[2]=q+6;ne[3]=q+9;
2524 ne[4]=q+12;ne[5]=q+15;ne[6]=q+18;ne[7]=q+21;
2527 /** This initializes the class to be an octahedron. It calls the base class
2528 * initialization routine to set up the edge and vertex information, and then
2529 * sets up the neighbor information, with the initial faces being assigned ID
2530 * numbers from -1 to -8.
2531 * \param[in] l The distance from the octahedron center to a vertex. Six
2532 * vertices are initialized at (-l,0,0), (l,0,0), (0,-l,0),
2533 * (0,l,0), (0,0,-l), and (0,0,l). */
2534 void voronoicell_neighbor::init_octahedron(double l) {
2535 init_octahedron_base(l);
2536 int *q=mne[4];
2537 *q=-5;q[1]=-6;q[2]=-7;q[3]=-8;
2538 q[4]=-1;q[5]=-2;q[6]=-3;q[7]=-4;
2539 q[8]=-6;q[9]=-5;q[10]=-2;q[11]=-1;
2540 q[12]=-8;q[13]=-7;q[14]=-4;q[15]=-3;
2541 q[16]=-5;q[17]=-8;q[18]=-3;q[19]=-2;
2542 q[20]=-7;q[21]=-6;q[22]=-1;q[23]=-4;
2543 *ne=q;ne[1]=q+4;ne[2]=q+8;ne[3]=q+12;ne[4]=q+16;ne[5]=q+20;
2546 /** This initializes the class to be a tetrahedron. It calls the base class
2547 * initialization routine to set up the edge and vertex information, and then
2548 * sets up the neighbor information, with the initial faces being assigned ID
2549 * numbers from -1 to -4.
2550 * \param (x0,y0,z0) a position vector for the first vertex.
2551 * \param (x1,y1,z1) a position vector for the second vertex.
2552 * \param (x2,y2,z2) a position vector for the third vertex.
2553 * \param (x3,y3,z3) a position vector for the fourth vertex. */
2554 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) {
2555 init_tetrahedron_base(x0,y0,z0,x1,y1,z1,x2,y2,z2,x3,y3,z3);
2556 int *q=mne[3];
2557 *q=-4;q[1]=-3;q[2]=-2;
2558 q[3]=-3;q[4]=-4;q[5]=-1;
2559 q[6]=-4;q[7]=-2;q[8]=-1;
2560 q[9]=-2;q[10]=-3;q[11]=-1;
2561 *ne=q;ne[1]=q+3;ne[2]=q+6;ne[3]=q+9;
2564 /** This routine checks to make sure the neighbor information of each face is
2565 * consistent. */
2566 void voronoicell_neighbor::check_facets() {
2567 int i,j,k,l,m,q;
2568 for(i=1;i<p;i++) for(j=0;j<nu[i];j++) {
2569 k=ed[i][j];
2570 if(k>=0) {
2571 ed[i][j]=-1-k;
2572 q=ne[i][j];
2573 l=cycle_up(ed[i][nu[i]+j],k);
2574 do {
2575 m=ed[k][l];
2576 ed[k][l]=-1-m;
2577 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);
2578 l=cycle_up(ed[k][nu[k]+l],m);
2579 k=m;
2580 } while (k!=i);
2583 reset_edges();
2586 /** The class constructor allocates memory for storing neighbor information. */
2587 void voronoicell_neighbor::memory_setup() {
2588 int i;
2589 mne=new int*[current_vertex_order];
2590 ne=new int*[current_vertices];
2591 for(i=0;i<3;i++) mne[i]=new int[init_n_vertices*i];
2592 mne[3]=new int[init_3_vertices*3];
2593 for(i=4;i<current_vertex_order;i++) mne[i]=new int[init_n_vertices*i];
2596 /** The class destructor frees the dynamically allocated memory for storing
2597 * neighbor information. */
2598 voronoicell_neighbor::~voronoicell_neighbor() {
2599 for(int i=current_vertex_order-1;i>=0;i--) if(mem[i]>0) delete [] mne[i];
2600 delete [] mne;
2601 delete [] ne;
2604 /** Computes a vector list of neighbors. */
2605 void voronoicell_neighbor::neighbors(std::vector<int> &v) {
2606 v.clear();
2607 int i,j,k,l,m;
2608 for(i=1;i<p;i++) for(j=0;j<nu[i];j++) {
2609 k=ed[i][j];
2610 if(k>=0) {
2611 v.push_back(ne[i][j]);
2612 ed[i][j]=-1-k;
2613 l=cycle_up(ed[i][nu[i]+j],k);
2614 do {
2615 m=ed[k][l];
2616 ed[k][l]=-1-m;
2617 l=cycle_up(ed[k][nu[k]+l],m);
2618 k=m;
2619 } while (k!=i);
2622 reset_edges();
2625 /** Prints the vertices, their edges, the relation table, and also notifies if
2626 * any memory errors are visible. */
2627 void voronoicell_base::print_edges() {
2628 int j;
2629 double *ptsp=pts;
2630 for(int i=0;i<p;i++,ptsp+=4) {
2631 printf("%d %d ",i,nu[i]);
2632 for(j=0;j<nu[i];j++) printf(" %d",ed[i][j]);
2633 printf(" ");
2634 while(j<(nu[i]<<1)) printf(" %d",ed[i][j]);
2635 printf(" %d",ed[i][j]);
2636 print_edges_neighbors(i);
2637 printf(" %g %g %g %p",*ptsp,ptsp[1],ptsp[2],(void*) ed[i]);
2638 if(ed[i]>=mep[nu[i]]+mec[nu[i]]*((nu[i]<<1)+1)) puts(" Memory error");
2639 else puts("");
2643 /** This prints out the neighbor information for vertex i. */
2644 void voronoicell_neighbor::print_edges_neighbors(int i) {
2645 if(nu[i]>0) {
2646 int j=0;
2647 printf(" (");
2648 while(j<nu[i]-1) printf("%d,",ne[i][j++]);
2649 printf("%d)",ne[i][j]);
2650 } else printf(" ()");
2653 // Explicit instantiation
2654 template bool voronoicell_base::nplane(voronoicell&,double,double,double,double,int);
2655 template bool voronoicell_base::nplane(voronoicell_neighbor&,double,double,double,double,int);
2656 template void voronoicell_base::check_memory_for_copy(voronoicell&,voronoicell_base*);
2657 template void voronoicell_base::check_memory_for_copy(voronoicell_neighbor&,voronoicell_base*);