1 // Voro++, a 3D cell-based Voronoi library
3 // Author : Chris H. Rycroft (LBL / UC Berkeley)
4 // Email : chr@alum.mit.edu
5 // Date : August 30th 2011
8 * \brief Function implementations for the voronoicell and related classes. */
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 mpz_q
[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
]) {
31 mem
[i
]=init_n_vertices
;mec
[i
]=0;
32 mep
[i
]=new int[init_n_vertices
*((i
<<1)+1)];
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)];
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
];
46 delete [] ds2
;delete [] ds
;
47 delete [] mep
;delete [] mec
;
48 delete [] mem
;delete [] pts
;
49 delete [] nu
;delete [] ed
;
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
);
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
) {
68 for(i
=0;i
<current_vertex_order
;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
;
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
];
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
);
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
);
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
);
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
);
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
) {
108 while(ptsp
<pts
+3*p
) {
109 *(ptsp
++)=x
;*(ptsp
++)=y
;*(ptsp
++)=z
;
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
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
) {
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
);
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
]);
143 vc
.n_allocate_aux1(i
);
148 vc
.n_set_to_aux1_offset(k
,m
);
151 for(dsp
=ds2
;dsp
<stackp2
;dsp
++) {
152 if(ed
[*dsp
]==mep
[i
]+j
) {
154 vc
.n_set_to_aux1_offset(*dsp
,m
);
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
);
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
);
168 vc
.n_switch_to_aux1(i
);
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
);
186 for(j
=0;j
<current_vertices
;j
++) pp
[j
]=ed
[j
];
188 vc
.n_add_memory_vertices(i
);
190 for(j
=0;j
<current_vertices
;j
++) pnu
[j
]=nu
[j
];
192 ppts
=new double[3*i
];
193 for(j
=0;j
<3*current_vertices
;j
++) ppts
[j
]=pts
[j
];
194 delete [] pts
;pts
=ppts
;
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
);
211 for(j
=0;j
<current_vertex_order
;j
++) p1
[j
]=mem
[j
];while(j
<i
) p1
[j
++]=0;
212 delete [] mem
;mem
=p1
;
214 for(j
=0;j
<current_vertex_order
;j
++) p2
[j
]=mep
[j
];
215 delete [] mep
;mep
=p2
;
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
;
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
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
);
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
;
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
);
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
;
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
;
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;
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;
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
;
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;
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;
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;
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;
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() {
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
);
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() {
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
]);
348 /** Constructs the relational table if the edges have been specified. */
349 void voronoicell_base::construct_relations() {
351 for(i
=0;i
<p
;i
++) for(j
=0;j
<nu
[i
];j
++) {
356 if(l
==nu
[k
]) voro_fatal_error("Relation table construction failed",VOROPP_INTERNAL_ERROR
);
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
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
);
374 for(i
=0;i
<nu
[up
];i
++) {
377 if(lw
==-1) return true;
378 else if(lw
==0) add_to_stack(vc
,lp
,stackp2
);
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
);
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
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
;
408 double u
,l
,r
,q
;bool complicated_setup
=false,new_double_edge
=false,double_edge
=false;
410 // Initialize the safe testing routine
411 n_marg
=0;px
=x
;py
=y
;pz
=z
;prsq
=rsq
;
413 // Test approximately sqrt(n)/4 points for their proximity to the plane
414 // and keep the one which is closest
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
423 // The test point is inside the cutting plane.
436 ls
=ed
[up
][nu
[up
]+us
];
438 if(++count
>=p
) throw true;
440 for(us
=0;us
<ls
;us
++) {
457 ls
=ed
[up
][nu
[up
]+us
];
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.
465 complicated_setup
=true;
466 } else complicated_setup
=false;
475 if(us
==nu
[up
]) return true;
478 qs
=ed
[up
][nu
[up
]+us
];
479 if(++count
>=p
) throw true;
481 for(us
=0;us
<qs
;us
++) {
494 if(us
==nu
[up
]) return true;
499 up
=qp
;us
=ed
[lp
][nu
[lp
]+ls
];u
=q
;
500 complicated_setup
=false;
503 complicated_setup
=true;
507 // Our original test point was on the plane, so we
508 // automatically head for the complicated setup
510 complicated_setup
=true;
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
518 #if VOROPP_VERBOSE >=1
519 fputs("Bailed out of convex calculation\n",stderr
);
522 for(qp
=0;qp
<p
;qp
++) {
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
++) {
538 complicated_setup
=true;
540 complicated_setup
=false;
542 ls
=ed
[up
][nu
[up
]+us
];
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
++) {
560 complicated_setup
=true;
562 complicated_setup
=false;
564 us
=ed
[lp
][nu
[lp
]+ls
];
570 // The point is in the plane, so we just
571 // proceed with the complicated setup routine
573 complicated_setup
=true;
577 if(qp
==p
) return qw
==-1?true:false;
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
583 if(p
==current_vertices
) add_memory_vertices(vc
);
585 if(complicated_setup
) {
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;
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.
598 pts
[3*p
+1]=pts
[3*up
+1];
599 pts
[3*p
+2]=pts
[3*up
+2];
601 // Search for a collection of edges of the test vertex which
602 // are outside of the cutting space. Begin by testing the
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.
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
620 if(i
==nu
[up
]) return false;
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.
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
643 if(j
==nu
[up
]&&i
==1&&rp
==0) {
649 // Add memory for the new vertex if needed, and
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
]]++;
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.
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.
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;
692 // Now search forwards from zero
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
716 // Add memory to store the vertex if it doesn't exist
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
);
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
]]++;
755 vc
.n_copy(p
,k
,up
,qs
);
757 } else vc
.n_copy(p
,0,up
,qs
);
759 // Add this point to the auxiliary delete stack
760 if(stackp2
==stacke2
) add_memory_ds2(stackp2
);
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.
770 us
=ed
[up
][nu
[up
]+us
];
772 ed
[qp
][nu
[qp
]<<1]=-p
;
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
);
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
;
787 // This point will always have three edges. Connect one of them
790 if(mec
[3]==mem
[3]) add_memory(vc
,3,stackp2
);
791 vc
.n_set_pointer(p
,3);
793 vc
.n_copy(p
,1,up
,us
);
794 vc
.n_copy(p
,2,lp
,ls
);
795 ed
[p
]=mep
[3]+7*mec
[3]++;
804 // Set the direction to move in
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
812 while(qp
!=up
||qs
!=us
) {
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.
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
);
827 if(stackp
==stacke
) add_memory_ds(stackp
);
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
);
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
;
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);
847 vc
.n_copy(p
,1,qp
,qs
);
848 vc
.n_copy(p
,2,lp
,ls
);
849 ed
[p
]=mep
[3]+7*mec
[3]++;
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
869 if(p
==current_vertices
) add_memory_vertices(vc
);
871 // If the previous vertex detected a double edge, our
872 // new vertex will have one less edge.
874 qs
=ed
[qp
][nu
[qp
]+qs
];
878 // Start testing the edges of the current point until
879 // we find one which isn't outside the cutting space
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];
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;
904 // This vertex was visited before, so
905 // count those vertices to the ones we
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
916 // Now see whether this marginal point
917 // has been visited before.
918 i
=-ed
[lp
][nu
[lp
]<<1];
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;
926 } else new_double_edge
=false;
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
935 if(j
==rp
&&lp
==up
&&ed
[qp
][nu
[qp
]+qs
]==us
) {
936 new_double_edge
=true;
938 } else new_double_edge
=false;
940 } else new_double_edge
=false;
943 // The vertex hasn't been visited
944 // before, but let's see if it's
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
953 i
=-ed
[lp
][nu
[lp
]<<1];
955 new_double_edge
=true;
957 } else new_double_edge
=false;
958 } else new_double_edge
=false;
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
965 while(k
>=current_vertex_order
) add_memory_vorder(vc
);
966 if(mec
[k
]==mem
[k
]) add_memory(vc
,k
,stackp2
);
968 // Now create a new vertex with order k, or augment
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
976 // Allocate memory and copy the edges
977 // of the previous instance into it
979 edp
=mep
[k
]+((k
<<1)+1)*mec
[k
]++;
984 edp
[k
+i
]=ed
[j
][nu
[j
]+i
];
989 // Remove the previous instance with
990 // fewer vertices from the memory
992 edd
=mep
[nu
[j
]]+((nu
[j
]<<1)+1)*--mec
[nu
[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
];
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
]++;
1008 if(stackp2
==stacke2
) add_memory_ds2(stackp2
);
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
;
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
1027 ed
[cp
][nu
[cp
]+cs
]=i
;
1031 // Copy in the edges of the underlying vertex,
1032 // and do one less if this was a double edge
1034 while(i
<(new_double_edge
?k
:k
-1)) {
1036 lp
=ed
[qp
][qs
];ls
=ed
[qp
][nu
[qp
]+qs
];
1037 vc
.n_copy(j
,i
,qp
,qs
);
1041 ed
[lp
][nu
[lp
]+ls
]=i
;
1048 vc
.n_copy(j
,new_double_edge
?0:cs
,qp
,qs
);
1050 // Update the double_edge flag, to pass it
1051 // to the next instance of this routine
1052 double_edge
=new_double_edge
;
1056 // Connect the final created vertex to the initial one
1059 ed
[cp
][nu
[cp
]+cs
]=0;
1062 // Delete points: first, remove any duplicates
1066 if(ed
[j
][nu
[j
]]!=-1) {
1069 } else *dsp
=*(--stackp
);
1072 // Add the points in the auxiliary delete stack,
1073 // and reset their back pointers
1074 for(dsp
=ds2
;dsp
<stackp2
;dsp
++) {
1077 if(ed
[j
][nu
[j
]]!=-1) {
1079 if(stackp
==stacke
) add_memory_ds(stackp
);
1084 // Scan connections and add in extras
1085 for(dsp
=ds
;dsp
<stackp
;dsp
++) {
1087 for(edp
=ed
[cp
];edp
<ed
[cp
]+nu
[cp
];edp
++) {
1089 if(qp
!=-1&&ed
[qp
][nu
[qp
]]!=-1) {
1090 if(stackp
==stacke
) {
1092 add_memory_ds(stackp
);
1102 // Delete them from the array structure
1105 while(ed
[p
][nu
[p
]]==-1) {
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
];
1117 // Vertex management
1119 pts
[3*up
+1]=pts
[3*p
+1];
1120 pts
[3*up
+2]=pts
[3*p
+2];
1122 // Memory management
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
];
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
;
1139 // Check for any vertices of zero order
1140 if(*mec
>0) voro_fatal_error("Zero order vertex formed",VOROPP_INTERNAL_ERROR
);
1142 // Collapse any order 2 vertices and exit
1143 return collapse_order2(vc
);
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;
1162 // Pick a order 2 vertex and read in its edges
1164 j
=mep
[2][5*i
];k
=mep
[2][5*i
+1];
1166 #if VOROPP_VERBOSE >=1
1167 fputs("Order two vertex joins itself",stderr
);
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;
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];
1187 if(!delete_connection(vc
,j
,a
,false)) return false;
1188 if(!delete_connection(vc
,k
,b
,true)) return false;
1191 // Compact the memory
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
);
1206 // Collapse any order 1 vertices if they were created
1207 if(!collapse_order1(vc
)) return false;
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
1217 template<class vc_class
>
1218 inline bool voronoicell_base::collapse_order1(vc_class
&vc
) {
1222 #if VOROPP_VERBOSE >=1
1223 fputs("Order one collapse\n",stderr
);
1226 j
=mep
[1][3*i
];k
=mep
[1][3*i
+1];
1228 if(!delete_connection(vc
,j
,k
,false)) return false;
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
);
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
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
1258 fputs("Zero order vertex formed\n",stderr
);
1262 if(mec
[i
]==mem
[i
]) add_memory(vc
,i
,ds2
);
1264 for(l
=0;l
<q
;l
++) vc
.n_copy_aux1(j
,l
);
1266 vc
.n_copy_aux1_shift(j
,l
);
1269 edp
=mep
[i
]+((i
<<1)+1)*mec
[i
]++;
1273 edp
[l
+i
]=ed
[j
][l
+nu
[j
]];
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
;
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;
1303 double ux
,uy
,uz
,vx
,vy
,vz
,wx
,wy
,wz
;
1306 uy
=pts
[1]-pts
[3*i
+1];
1307 uz
=pts
[2]-pts
[3*i
+2];
1308 for(j
=0;j
<nu
[i
];j
++) {
1312 l
=cycle_up(ed
[i
][nu
[i
]+j
],k
);
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
;
1318 n
=cycle_up(ed
[k
][nu
[k
]+l
],m
);
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
;
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(vector
<double> &v
) {
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
++) {
1346 l
=cycle_up(ed
[i
][nu
[i
]+j
],k
);
1347 m
=ed
[k
][l
];ed
[k
][l
]=-1-m
;
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];
1359 area
+=sqrt(wx
*wx
+wy
*wy
+wz
*wz
);
1361 m
=ed
[k
][l
];ed
[k
][l
]=-1-m
;
1363 v
.push_back(0.125*area
);
1370 /** Calculates the total surface area of the Voronoi cell.
1371 * \return The computed area. */
1372 double voronoicell_base::surface_area() {
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
++) {
1380 l
=cycle_up(ed
[i
][nu
[i
]+j
],k
);
1381 m
=ed
[k
][l
];ed
[k
][l
]=-1-m
;
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];
1393 area
+=sqrt(wx
*wx
+wy
*wy
+wz
*wz
);
1395 m
=ed
[k
][l
];ed
[k
][l
]=-1-m
;
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;
1411 double ux
,uy
,uz
,vx
,vy
,vz
,wx
,wy
,wz
;
1414 uy
=pts
[1]-pts
[3*i
+1];
1415 uz
=pts
[2]-pts
[3*i
+2];
1416 for(j
=0;j
<nu
[i
];j
++) {
1420 l
=cycle_up(ed
[i
][nu
[i
]+j
],k
);
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
;
1426 n
=cycle_up(ed
[k
][nu
[k
]+l
],m
);
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
;
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
;
1442 if(vol
>tolerance_sq
) {
1444 cx
=cx
*vol
+0.5*(*pts
);
1445 cy
=cy
*vol
+0.5*pts
[1];
1446 cz
=cz
*vol
+0.5*pts
[2];
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];
1458 s
=*ptsp
*(*ptsp
);ptsp
++;
1459 s
+=*ptsp
*(*ptsp
);ptsp
++;
1460 s
+=*ptsp
*(*ptsp
);ptsp
++;
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() {
1470 double dis
=0,dx
,dy
,dz
;
1471 for(i
=0;i
<p
-1;i
++) for(j
=0;j
<nu
[i
];j
++) {
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
);
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
++) {
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
);
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
) {
1509 for(i
=1;i
<p
;i
++) for(j
=0;j
<nu
[i
];j
++) {
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]);
1515 ed
[k
][ed
[l
][nu
[l
]+m
]]=-1-l
;
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
));
1526 inline bool voronoicell_base::search_edge(int l
,int &m
,int &k
) {
1527 for(m
=0;m
<nu
[l
];m
++) {
1529 if(k
>=0) return true;
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
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
) {
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
++) {
1552 l
=cycle_up(ed
[i
][nu
[i
]+j
],k
);
1553 m
=ed
[k
][l
];ed
[k
][l
]=-1-m
;
1555 n
=cycle_up(ed
[k
][nu
[k
]+l
],m
);
1556 fprintf(fp
,",<%d,%d,%d>\n",i
,k
,m
);
1558 m
=ed
[k
][l
];ed
[k
][l
]=-1-m
;
1562 fputs("}\ninside_vector <0,0,1>\n}\n",fp
);
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() {
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
];
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);
1595 if(ans
<-tolerance2
) {
1597 } else if(ans
>tolerance2
) {
1600 return check_marginal(n
,ans
);
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
) {
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
);
1625 int *pmarg
=new int[current_marginal
];
1626 for(int j
=0;j
<n_marg
;j
++) pmarg
[j
]=marg
[j
];
1631 marg
[n_marg
++]=ans
>tolerance
?1:(ans
<-tolerance
?-1:0);
1632 return marg
[n_marg
-1];
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
1638 * \param[out] v the vector to store the results in. */
1639 void voronoicell_base::normals(vector
<double> &v
) {
1642 for(i
=1;i
<p
;i
++) for(j
=0;j
<nu
[i
];j
++) {
1644 if(k
>=0) normals_search(v
,i
,j
,k
);
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
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(vector
<double> &v
,int i
,int j
,int 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
;
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];
1670 // Test to see if the length of this edge is above the tolerance
1671 if(ux
*ux
+uy
*uy
+uz
*uz
>tolerance_sq
) {
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];
1679 // Construct the vector product of this edge with
1684 wmag
=wx
*wx
+wy
*wy
+wz
*wz
;
1686 // Test to see if this vector product of the
1687 // two edges is above the tolerance
1688 if(wmag
>tolerance_sq
) {
1690 // Construct the normal vector and print it
1692 v
.push_back(wx
*wmag
);
1693 v
.push_back(wy
*wmag
);
1694 v
.push_back(wz
*wmag
);
1696 // Mark all of the remaining edges of this
1699 l
=cycle_up(ed
[k
][nu
[k
]+l
],m
);
1700 k
=m
;m
=ed
[k
][l
];ed
[k
][l
]=-1-m
;
1710 l
=cycle_up(ed
[k
][nu
[k
]+l
],m
);
1719 /** Returns the number of faces of a computed Voronoi cell.
1720 * \return The number of faces. */
1721 int voronoicell_base::number_of_faces() {
1723 for(i
=1;i
<p
;i
++) for(j
=0;j
<nu
[i
];j
++) {
1728 l
=cycle_up(ed
[i
][nu
[i
]+j
],k
);
1732 l
=cycle_up(ed
[k
][nu
[k
]+l
],m
);
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(vector
<int> &v
) {
1746 for(int i
=0;i
<p
;i
++) v
[i
]=nu
[i
];
1749 /** Outputs the vertex orders.
1750 * \param[out] fp the file handle to write to. */
1751 void voronoicell_base::output_vertex_orders(FILE *fp
) {
1753 fprintf(fp
,"%d",*nu
);
1754 for(int *nup
=nu
+1;nup
<nu
+p
;nup
++) fprintf(fp
," %d",*nup
);
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(vector
<double> &v
) {
1763 for(int i
=0;i
<3*p
;i
+=3) {
1765 v
[i
+1]=*(ptsp
++)*0.5;
1766 v
[i
+2]=*(ptsp
++)*0.5;
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
) {
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);
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
,vector
<double> &v
) {
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;
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
) {
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);
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(vector
<double> &v
) {
1810 double dx
,dy
,dz
,perim
;
1811 for(i
=1;i
<p
;i
++) for(j
=0;j
<nu
[i
];j
++) {
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
);
1819 l
=cycle_up(ed
[i
][nu
[i
]+j
],k
);
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
);
1827 l
=cycle_up(ed
[k
][nu
[k
]+l
],m
);
1830 v
.push_back(0.5*perim
);
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(vector
<int> &v
) {
1840 int i
,j
,k
,l
,m
,vp(0),vn
;
1842 for(i
=1;i
<p
;i
++) for(j
=0;j
<nu
[i
];j
++) {
1848 l
=cycle_up(ed
[i
][nu
[i
]+j
],k
);
1853 l
=cycle_up(ed
[k
][nu
[k
]+l
],m
);
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(vector
<int> &v
) {
1869 for(i
=1;i
<p
;i
++) for(j
=0;j
<nu
[i
];j
++) {
1874 l
=cycle_up(ed
[i
][nu
[i
]+j
],k
);
1879 l
=cycle_up(ed
[k
][nu
[k
]+l
],m
);
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(vector
<int> &v
) {
1894 for(i
=1;i
<p
;i
++) for(j
=0;j
<nu
[i
];j
++) {
1899 l
=cycle_up(ed
[i
][nu
[i
]+j
],k
);
1904 l
=cycle_up(ed
[k
][nu
[k
]+l
],m
);
1907 if((unsigned int) q
>=v
.size()) v
.resize(q
+1,0);
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
);
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
) {
1935 double g
=x
*pts
[3*up
]+y
*pts
[3*up
+1]+z
*pts
[3*up
+2];
1937 int ca
=1,cc
=p
>>3,mp
=1;
1940 m
=x
*pts
[3*mp
]+y
*pts
[3*mp
+1]+z
*pts
[3*mp
+2];
1942 if(m
>rsq
) return true;
1947 return plane_intersects_track(x
,y
,z
,rsq
,g
);
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
;
1963 // The test point is outside of the cutting space
1964 for(us
=0;us
<nu
[up
];us
++) {
1966 t
=x
*pts
[3*tp
]+y
*pts
[3*tp
+1]+z
*pts
[3*tp
+2];
1968 ls
=ed
[up
][nu
[up
]+us
];
1972 #if VOROPP_VERBOSE >=1
1973 fputs("Bailed out of convex calculation",stderr
);
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;
1979 // Test all the neighbors of the current point
1980 // and find the one which is closest to the
1982 for(us
=0;us
<ls
;us
++) {
1984 g
=x
*pts
[3*tp
]+y
*pts
[3*tp
+1]+z
*pts
[3*tp
+2];
1991 g
=x
*pts
[3*tp
]+y
*pts
[3*tp
+1]+z
*pts
[3*tp
+2];
1995 if(us
==nu
[up
]) return false;
1997 ls
=ed
[up
][nu
[up
]+us
];up
=tp
;t
=g
;
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
++);
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
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
));
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;
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;
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;
2052 // Face-related output
2053 case 's': fprintf(fp
,"%d",number_of_faces());break;
2054 case 'F': fprintf(fp
,"%g",surface_area());break;
2056 face_freq_table(vi
);
2057 voro_print_vector(vi
,fp
);
2059 case 'a': face_orders(vi
);voro_print_vector(vi
,fp
);break;
2060 case 'f': face_areas(vd
);voro_print_vector(vd
,fp
);break;
2063 voro_print_face_vertices(vi
,fp
);
2065 case 'l': normals(vd
);
2066 voro_print_positions(vd
,fp
);
2068 case 'n': neighbors(vi
);
2069 voro_print_vector(vi
,fp
);
2072 // Volume-related output
2073 case 'v': fprintf(fp
,"%g",volume());break;
2077 fprintf(fp
,"%g %g %g",cx
,cy
,cz
);
2082 fprintf(fp
,"%g %g %g",x
+cx
,y
+cy
,z
+cz
);
2085 // End-of-string reached
2086 case 0: fmp
--;break;
2088 // The percent sign is not part of a
2090 default: putc('%',fp
);putc(*fmp
,fp
);
2092 } else putc(*fmp
,fp
);
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
);
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;
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
);
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;
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
);
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;
2157 /** This routine checks to make sure the neighbor information of each face is
2159 void voronoicell_neighbor::check_facets() {
2161 for(i
=1;i
<p
;i
++) for(j
=0;j
<nu
[i
];j
++) {
2166 l
=cycle_up(ed
[i
][nu
[i
]+j
],k
);
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
);
2179 /** The class constructor allocates memory for storing neighbor information. */
2180 voronoicell_neighbor::voronoicell_neighbor() {
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
];
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
];
2197 /** Computes a vector list of neighbors. */
2198 void voronoicell_neighbor::neighbors(vector
<int> &v
) {
2201 for(i
=1;i
<p
;i
++) for(j
=0;j
<nu
[i
];j
++) {
2204 v
.push_back(ne
[i
][j
]);
2206 l
=cycle_up(ed
[i
][nu
[i
]+j
],k
);
2210 l
=cycle_up(ed
[k
][nu
[k
]+l
],m
);
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() {
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
]);
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");
2236 /** This prints out the neighbor information for vertex i. */
2237 void voronoicell_neighbor::print_edges_neighbors(int i
) {
2241 while(j
<nu
[i
]-1) printf("%d,",ne
[i
][j
++]);
2242 printf("%d)",ne
[i
][j
]);
2243 } else printf(" ()");
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
*);