1 // Voro++, a 3D cell-based Voronoi library
3 // Author : Chris H. Rycroft (LBL / UC Berkeley)
4 // Email : chr@alum.mit.edu
5 // Date : July 1st 2008
8 * \brief Function implementations for the voronoicell_base template and
13 /** Constructs a Voronoi cell and sets up the initial memory. */
14 template<class n_option
>
15 voronoicell_base
<n_option
>::voronoicell_base() :
16 current_vertices(init_vertices
), current_vertex_order(init_vertex_order
),
17 current_delete_size(init_delete_size
), current_delete2_size(init_delete2_size
),
20 ds
=new int[current_delete_size
];
21 ds2
=new int[current_delete2_size
];
22 mem
=new int[current_vertex_order
];
23 mec
=new int[current_vertex_order
];
24 mep
=new int*[current_vertex_order
];
25 ed
=new int*[current_vertices
];
26 nu
=new int[current_vertices
];
27 pts
=new fpoint
[3*current_vertices
];
30 mem
[i
]=init_n_vertices
;
31 mep
[i
]=new int[init_n_vertices
*(2*i
+1)];
34 mem
[3]=init_3_vertices
;
35 mep
[3]=new int[init_3_vertices
*7];
37 for(i
=4;i
<current_vertex_order
;i
++) {
38 mem
[i
]=init_n_vertices
;
39 mep
[i
]=new int[init_n_vertices
*(2*i
+1)];
44 /** The voronoicell destructor deallocates all the dynamic memory. */
45 template<class n_option
>
46 voronoicell_base
<n_option
>::~voronoicell_base() {
49 for(int i
=0;i
<current_vertex_order
;i
++) if (mem
[i
]>0) delete [] mep
[i
];
58 /** Increases the memory storage for a particular vertex order, by increasing
59 * the size of the of the mep and mne <em>(neighbor option only)</em> arrays.
60 * If the arrays already exist, their size is doubled; if they don't exist,
61 * then new ones of size init_n_vertices are allocated. The routine also ensures
62 * that the pointers in the ed array are updated, by making use of the back
63 * pointers. For the cases where the back pointer has been temporarily
64 * overwritten in the marginal vertex code, the auxiliary delete stack is
65 * scanned to find out how to update the ed value.
66 * \param[in] i The order of the vertex memory to be increased.*/
67 template<class n_option
>
68 void voronoicell_base
<n_option
>::add_memory(int i
) {
71 neighbor
.allocate(i
,init_n_vertices
);
72 mep
[i
]=new int[init_n_vertices
*s
];
73 mem
[i
]=init_n_vertices
;
74 #if VOROPP_VERBOSE >=2
75 cerr
<< "Order " << i
<< " vertex memory created " << endl
;
80 if (mem
[i
]>max_n_vertices
) throw fatal_error("Point memory allocation exceeded absolute maximum");
81 #if VOROPP_VERBOSE >=2
82 cerr
<< "Order " << i
<< " vertex memory scaled up to " << mem
[i
] << endl
;
86 neighbor
.allocate_aux1(i
);
91 neighbor
.set_to_aux1_offset(k
,m
);
94 for(o
=0;o
<stack2
;o
++) {
95 if(ed
[ds2
[o
]]==mep
[i
]+j
) {
97 neighbor
.set_to_aux1_offset(ds2
[o
],m
);
101 if(o
==stack2
) throw fatal_error("Couldn't relocate dangling pointer");
102 #if VOROPP_VERBOSE >=3
103 cerr
<< "Relocated dangling pointer" << endl
;
106 for(k
=0;k
<s
;k
++,j
++) l
[j
]=mep
[i
][j
];
107 for(k
=0;k
<i
;k
++,m
++) neighbor
.copy_to_aux1(i
,m
);
111 neighbor
.switch_to_aux1(i
);
115 /** Doubles the maximum number of vertices allowed, by reallocating the ed, nu,
116 * pts, and ne <em>(neighbor option only)</em> arrays. If the allocation
117 * exceeds the absolute maximum set in max_vertices, then the routine throws a
119 template<class n_option
>
120 void voronoicell_base
<n_option
>::add_memory_vertices() {
121 int i
=2*current_vertices
,j
,**pp
,*pnu
;
122 if (i
>max_vertices
) throw fatal_error("Vertex memory allocation exceeded absolute maximum");
123 #if VOROPP_VERBOSE >=2
124 cerr
<< "Vertex memory scaled up to " << i
<< endl
;
128 for(j
=0;j
<current_vertices
;j
++) pp
[j
]=ed
[j
];
130 neighbor
.add_memory_vertices(i
);
132 for(j
=0;j
<current_vertices
;j
++) pnu
[j
]=nu
[j
];
134 ppts
=new fpoint
[3*i
];
135 for(j
=0;j
<3*current_vertices
;j
++) ppts
[j
]=pts
[j
];
136 delete [] pts
;sure
.p
=pts
=ppts
;
140 /** Doubles the maximum allowed vertex order, by reallocating mem, mep, mec,
141 * and mnu <em>(neighbor option only)</em> arrays. If the allocation exceeds
142 * the absolute maximum set in max_vertex_order, then the routine causes a fatal
144 template<class n_option
>
145 void voronoicell_base
<n_option
>::add_memory_vorder() {
146 int i
=2*current_vertex_order
,j
,*p1
,**p2
;
147 if (i
>max_vertex_order
) throw fatal_error("Vertex order memory allocation exceeded absolute maximum");
148 #if VOROPP_VERBOSE >=2
149 cerr
<< "Vertex order memory scaled up to " << i
<< endl
;
152 for(j
=0;j
<current_vertex_order
;j
++) p1
[j
]=mem
[j
];while(j
<i
) p1
[j
++]=0;
153 delete [] mem
;mem
=p1
;
155 for(j
=0;j
<current_vertex_order
;j
++) p2
[j
]=mep
[j
];
156 delete [] mep
;mep
=p2
;
158 for(j
=0;j
<current_vertex_order
;j
++) p1
[j
]=mec
[j
];while(j
<i
) p1
[j
++]=0;
159 delete [] mec
;mec
=p1
;
160 neighbor
.add_memory_vorder(i
);
161 current_vertex_order
=i
;
164 /** Doubles the size allocation of the main delete stack. If the allocation
165 * exceeds the absolute maximum set in max_delete_size, then routine causes a
167 template<class n_option
>
168 void voronoicell_base
<n_option
>::add_memory_ds() {
169 int i
=2*current_delete_size
,j
,*pds
;
170 if (i
>max_delete_size
) throw fatal_error("Delete stack 1 memory allocation exceeded absolute maximum");
171 #if VOROPP_VERBOSE >=2
172 cerr
<< "Delete stack 1 memory scaled up to " << i
<< endl
;
175 for(j
=0;j
<current_delete_size
;j
++) pds
[j
]=ds
[j
];
177 current_delete_size
=i
;
180 /** Doubles the size allocation of the auxiliary delete stack. If the
181 * allocation exceeds the absolute maximum set in max_delete2_size, then the
182 * routine causes a fatal error. */
183 template<class n_option
>
184 void voronoicell_base
<n_option
>::add_memory_ds2() {
185 int i
=2*current_delete2_size
,j
,*pds2
;
186 if (i
>max_delete2_size
) throw fatal_error("Delete stack 2 memory allocation exceeded absolute maximum");
187 #if VOROPP_VERBOSE >=2
188 cerr
<< "Delete stack 2 memory scaled up to " << i
<< endl
;
191 for(j
=0;j
<current_delete2_size
;j
++) pds2
[j
]=ds2
[j
];
192 delete [] ds2
;ds2
=pds2
;
193 current_delete2_size
=i
;
196 /** Initializes a Voronoi cell as a rectangular box with the given dimensions */
197 template<class n_option
>
198 void voronoicell_base
<n_option
>::init(fpoint xmin
,fpoint xmax
,fpoint ymin
,fpoint ymax
,fpoint zmin
,fpoint zmax
) {
199 for(int i
=0;i
<current_vertex_order
;i
++) mec
[i
]=0;up
=0;
200 mec
[3]=p
=8;xmin
*=2;xmax
*=2;ymin
*=2;ymax
*=2;zmin
*=2;zmax
*=2;
201 pts
[0]=xmin
;pts
[1]=ymin
;pts
[2]=zmin
;
202 pts
[3]=xmax
;pts
[4]=ymin
;pts
[5]=zmin
;
203 pts
[6]=xmin
;pts
[7]=ymax
;pts
[8]=zmin
;
204 pts
[9]=xmax
;pts
[10]=ymax
;pts
[11]=zmin
;
205 pts
[12]=xmin
;pts
[13]=ymin
;pts
[14]=zmax
;
206 pts
[15]=xmax
;pts
[16]=ymin
;pts
[17]=zmax
;
207 pts
[18]=xmin
;pts
[19]=ymax
;pts
[20]=zmax
;
208 pts
[21]=xmax
;pts
[22]=ymax
;pts
[23]=zmax
;
210 q
[0]=1;q
[1]=4;q
[2]=2;q
[3]=2;q
[4]=1;q
[5]=0;q
[6]=0;
211 q
[7]=3;q
[8]=5;q
[9]=0;q
[10]=2;q
[11]=1;q
[12]=0;q
[13]=1;
212 q
[14]=0;q
[15]=6;q
[16]=3;q
[17]=2;q
[18]=1;q
[19]=0;q
[20]=2;
213 q
[21]=2;q
[22]=7;q
[23]=1;q
[24]=2;q
[25]=1;q
[26]=0;q
[27]=3;
214 q
[28]=6;q
[29]=0;q
[30]=5;q
[31]=2;q
[32]=1;q
[33]=0;q
[34]=4;
215 q
[35]=4;q
[36]=1;q
[37]=7;q
[38]=2;q
[39]=1;q
[40]=0;q
[41]=5;
216 q
[42]=7;q
[43]=2;q
[44]=4;q
[45]=2;q
[46]=1;q
[47]=0;q
[48]=6;
217 q
[49]=5;q
[50]=3;q
[51]=6;q
[52]=2;q
[53]=1;q
[54]=0;q
[55]=7;
218 ed
[0]=q
;ed
[1]=q
+7;ed
[2]=q
+14;ed
[3]=q
+21;
219 ed
[4]=q
+28;ed
[5]=q
+35;ed
[6]=q
+42;ed
[7]=q
+49;
221 nu
[0]=nu
[1]=nu
[2]=nu
[3]=nu
[4]=nu
[5]=nu
[6]=nu
[7]=3;
224 /** Initializes a Voronoi cell as a regular octahedron.
225 * \param[in] l The distance from the octahedron center to a vertex. Six vertices
226 * are initialized at (-l,0,0), (l,0,0), (0,-l,0), (0,l,0), (0,0,-l), and (0,0,l).*/
227 template<class n_option
>
228 inline void voronoicell_base
<n_option
>::init_octahedron(fpoint l
) {
229 for(int i
=0;i
<current_vertex_order
;i
++) mec
[i
]=0;up
=0;
231 pts
[0]=-l
;pts
[1]=0;pts
[2]=0;
232 pts
[3]=l
;pts
[4]=0;pts
[5]=0;
233 pts
[6]=0;pts
[7]=-l
;pts
[8]=0;
234 pts
[9]=0;pts
[10]=l
;pts
[11]=0;
235 pts
[12]=0;pts
[13]=0;pts
[14]=-l
;
236 pts
[15]=0;pts
[16]=0;pts
[17]=l
;
238 q
[0]=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;
239 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;
240 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;
241 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;
242 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;
243 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;
244 ed
[0]=q
;ed
[1]=q
+9;ed
[2]=q
+18;ed
[3]=q
+27;ed
[4]=q
+36;ed
[5]=q
+45;
245 neighbor
.init_octahedron();
246 nu
[0]=nu
[1]=nu
[2]=nu
[3]=nu
[4]=nu
[5]=4;
249 /** Initializes a Voronoi cell as a tetrahedron. It assumes that the normal to
250 * the face for the first three vertices points inside.
251 * \param (x0,y0,z0) A position vector for the first vertex.
252 * \param (x1,y1,z1) A position vector for the second vertex.
253 * \param (x2,y2,z2) A position vector for the third vertex.
254 * \param (x3,y3,z3) A position vector for the fourth vertex. */
255 template<class n_option
>
256 inline void voronoicell_base
<n_option
>::init_tetrahedron(fpoint x0
,fpoint y0
,fpoint z0
,fpoint x1
,fpoint y1
,fpoint z1
,fpoint x2
,fpoint y2
,fpoint z2
,fpoint x3
,fpoint y3
,fpoint z3
) {
257 for(int i
=0;i
<current_vertex_order
;i
++) mec
[i
]=0;up
=0;
259 pts
[0]=x0
*2;pts
[1]=y0
*2;pts
[2]=z0
*2;
260 pts
[3]=x1
*2;pts
[4]=y1
*2;pts
[5]=z1
*2;
261 pts
[6]=x2
*2;pts
[7]=y2
*2;pts
[8]=z2
*2;
262 pts
[9]=x3
*2;pts
[10]=y3
*2;pts
[11]=z3
*2;
264 q
[0]=1;q
[1]=3;q
[2]=2;q
[3]=0;q
[4]=0;q
[5]=0;q
[6]=0;
265 q
[7]=0;q
[8]=2;q
[9]=3;q
[10]=0;q
[11]=2;q
[12]=1;q
[13]=1;
266 q
[14]=0;q
[15]=3;q
[16]=1;q
[17]=2;q
[18]=2;q
[19]=1;q
[20]=2;
267 q
[21]=0;q
[22]=1;q
[23]=2;q
[24]=1;q
[25]=2;q
[26]=1;q
[27]=3;
268 ed
[0]=q
;ed
[1]=q
+7;ed
[2]=q
+14;ed
[3]=q
+21;
269 neighbor
.init_tetrahedron();
270 nu
[0]=nu
[1]=nu
[2]=nu
[3]=3;
273 /** Initializes an arbitrary test object using the add_vertex() and
274 * construct_relations() routines. See the source code for information about
275 * the specific objects.
276 * \param[in] n the number of the test object (from 0 to 9)
278 template<class n_option
>
279 inline void voronoicell_base
<n_option
>::init_test(int n
) {
280 for(int i
=0;i
<current_vertex_order
;i
++) mec
[i
]=0;up
=p
=0;
283 // A peaked object, with a high vertex 6, and a ridge
284 // at z=0 from vertex 1 to 2. This can be used to test
285 // the order 1 vertex collapse routine.
286 add_vertex(1,-2,-1,3,1,5);
287 add_vertex(0,-1,1,5,0,2);
288 add_vertex(0,1,0,1,3,6,4);
289 add_vertex(1,4,-1,4,6,2,0);
290 add_vertex(-1,4,-1,3,5,2,6);
291 add_vertex(-1,-2,-1,4,0,1);
292 add_vertex(0,3,0,4,2,3);
295 // A truncated pyramid shape, with vertex 4 in the z=0
296 // plane. This can be used to test order 4 vertex
298 add_vertex(-2,2,-1,3,4,1);
299 add_vertex(2,2,-1,0,5,2);
300 add_vertex(2,-2,-1,1,6,3);
301 add_vertex(-2,-2,-1,2,7,0);
302 add_vertex(-1,1,0,0,7,5);
303 add_vertex(1,1,1,1,4,6);
304 add_vertex(1,-1,1,7,2,5);
305 add_vertex(-1,-1,1,4,3,6);
308 // An object with two peaks at vertices 4 and 6,
309 // connected with a trough at vertex 5. It can be used
310 // to test the part of the routine that deals with
311 // augmenting existing vertices.
312 add_vertex(1,-2,-1,1,3,4);
313 add_vertex(-1,-2,-1,2,0,4,5);
314 add_vertex(-1,2,-1,1,6,3);
315 add_vertex(1,2,-1,2,6,5,0);
316 add_vertex(0,-1,1,5,1,0);
317 add_vertex(0,0,0,1,4,3,6);
318 add_vertex(0,1,1,2,5,3);
321 // A box with a pyramid on top of it. This a good
322 // test object to make sure that the code can handle
323 // object with vertices of different orders.
324 add_vertex(-1,-1,-1,4,3,1);
325 add_vertex(1,-1,-1,0,2,5);
326 add_vertex(1,1,-1,6,1,3);
327 add_vertex(-1,1,-1,2,0,7);
328 add_vertex(-1,-1,1,7,0,5,8);
329 add_vertex(1,-1,1,4,1,6,8);
330 add_vertex(1,1,1,5,2,7,8);
331 add_vertex(-1,1,1,6,3,4,8);
332 add_vertex(0,0,2,7,4,5,6);
335 // A shape with two peaks (vertices 6 and 9) connected
336 // with a trough (vertices 7 and 8). It can be used as
337 // a basic test of the double edge skipping in the plane
338 // generation routine, whereby an edge is omitted if
339 // the routine is tracing along a part it has already
341 add_vertex(1,-3,-1,5,6,1);
342 add_vertex(-1,-3,-1,0,6,2);
343 add_vertex(-3,0,-1,1,7,8,3);
344 add_vertex(-1,3,-1,2,9,4);
345 add_vertex(1,3,-1,3,9,5);
346 add_vertex(3,0,-1,4,8,7,0);
347 add_vertex(0,-2,1,7,1,0);
348 add_vertex(0,-1,0,8,2,6,5);
349 add_vertex(0,1,0,9,2,7,5);
350 add_vertex(0,2,1,3,8,4);
353 // An object with four peaks (vertices 8 to 11)
354 // connected by a trough (vertex 16). It can be used to
355 // the test multiple augmentation of edges of a
356 // particular vertex.
357 add_vertex(-1,-3,-1,7,1,8,12);
358 add_vertex(1,-3,-1,2,12,8,0);
359 add_vertex(3,-1,-1,3,9,13,1);
360 add_vertex(3,1,-1,4,13,9,2);
361 add_vertex(1,3,-1,5,10,14,3);
362 add_vertex(-1,3,-1,6,14,10,4);
363 add_vertex(-3,1,-1,7,11,15,5);
364 add_vertex(-3,-1,-1,0,15,11,6);
365 add_vertex(0,-2,1,0,1,12);
366 add_vertex(2,0,1,2,3,13);
367 add_vertex(0,2,1,14,4,5);
368 add_vertex(-2,0,1,7,15,6);
369 add_vertex(0,-1,0.5,0,8,1,16);
370 add_vertex(1,0,0.5,2,9,3,16);
371 add_vertex(0,1,0.5,4,10,5,16);
372 add_vertex(-1,0,0.5,6,11,7,16);
373 add_vertex(0,0,0,15,12,13,14);
376 // An object with four peaks (vertices 8 to 11)
377 // connected by a sequence of ridges. It can be used to
378 // the test multiple cases of double edge skipping
379 // on the same vertex.
380 add_vertex(-1,-3,-1,7,1,8,12);
381 add_vertex(1,-3,-1,2,12,8,0);
382 add_vertex(3,-1,-1,3,9,13,1);
383 add_vertex(3,1,-1,4,13,9,2);
384 add_vertex(1,3,-1,5,10,14,3);
385 add_vertex(-1,3,-1,6,14,10,4);
386 add_vertex(-3,1,-1,7,11,15,5);
387 add_vertex(-3,-1,-1,0,15,11,6);
388 add_vertex(0,-2,1,0,1,12);
389 add_vertex(2,0,1,2,3,13);
390 add_vertex(0,2,1,14,4,5);
391 add_vertex(-2,0,1,7,15,6);
392 add_vertex(0,-1,0,0,8,1,16);
393 add_vertex(1,0,0,2,9,3,16);
394 add_vertex(0,1,0,4,10,5,16);
395 add_vertex(-1,0,0,6,11,7,16);
396 add_vertex(0,0,0,15,12,13,14);
399 // A variation on the zeroth test shape, with a peak
400 // (vertices 7 and 8) connected to a ridge at z=0
401 // (vertices 4 and 5)
402 add_vertex(2,-3,-1,3,4,1);
403 add_vertex(-2,-3,-1,0,4,2);
404 add_vertex(-2,3,-1,1,7,3);
405 add_vertex(2,3,-1,2,6,0);
406 add_vertex(0,-2,0,0,5,1);
407 add_vertex(0,1,0,4,6,7);
408 add_vertex(1,2,1,7,5,3);
409 add_vertex(-1,2,1,5,6,2);
412 // A triangular object with a skewed peak, that can be used to
413 // test the order two vertex removal routine
414 add_vertex(3,-2,-1,2,3,1);
415 add_vertex(-3,-2,-1,0,4,2);
416 add_vertex(0,4,-1,1,5,0);
417 add_vertex(1.5,-1,0,7,0,6);
418 add_vertex(-1.5,-1,0,1,7,8);
419 add_vertex(0,2,0,8,6,2);
420 add_vertex(0.75,0.5,0,9,3,5);
421 add_vertex(0,-1,0,4,3,9);
422 add_vertex(-0.75,0.5,0,4,9,5);
423 add_vertex(0,0,1,8,7,6);
426 // This a tetrahedron with some low-order extraneous edges, and can
427 // be used to test the order 1 and order 2 removal routines
428 add_vertex(0,0,0,3,1,2);
429 add_vertex(1,0,1,3,2,0);
430 add_vertex(1,1,0,3,0,1);
431 add_vertex(2,0,0,6,4,2,1,0);
432 add_vertex(3,1,0,3,6,8,5);
434 add_vertex(4,0,0,4,3,7,8);
436 add_vertex(4,1,0,6,4);
439 construct_relations();
440 neighbor
.label_facets();
443 /** Adds an order one vertex to the memory structure, and specifies its edge.
444 * \param[in] (x,y,z) are the coordinates of the vertex
445 * \param[in] a is the first and only edge of this vertex
447 template<class n_option
>
448 void voronoicell_base
<n_option
>::add_vertex(fpoint x
,fpoint y
,fpoint z
,int a
) {
449 pts
[3*p
]=x
;pts
[3*p
+1]=y
;pts
[3*p
+2]=z
;nu
[p
]=1;
450 if (mem
[1]==mec
[1]) add_memory(1);
451 neighbor
.set_pointer(p
,1);
452 int *q
=mep
[1]+3*mec
[1]++;ed
[p
]=q
;
456 /** Adds an order 2 vertex to the memory structure, and specifies its edges. */
457 template<class n_option
>
458 void voronoicell_base
<n_option
>::add_vertex(fpoint x
,fpoint y
,fpoint z
,int a
,int b
) {
459 pts
[3*p
]=x
;pts
[3*p
+1]=y
;pts
[3*p
+2]=z
;nu
[p
]=2;
460 if (mem
[2]==mec
[2]) add_memory(2);
461 neighbor
.set_pointer(p
,2);
462 int *q
=mep
[2]+5*mec
[2]++;ed
[p
]=q
;
463 q
[0]=a
;q
[1]=b
;q
[4]=p
++;
466 /** Adds an order 3 vertex to the memory structure, and specifies its edges. */
467 template<class n_option
>
468 void voronoicell_base
<n_option
>::add_vertex(fpoint x
,fpoint y
,fpoint z
,int a
,int b
,int c
) {
469 pts
[3*p
]=x
;pts
[3*p
+1]=y
;pts
[3*p
+2]=z
;nu
[p
]=3;
470 if (mem
[3]==mec
[3]) add_memory(3);
471 neighbor
.set_pointer(p
,3);
472 int *q
=mep
[3]+7*mec
[3]++;ed
[p
]=q
;
473 q
[0]=a
;q
[1]=b
;q
[2]=c
;q
[6]=p
++;
476 /** Adds an order 4 vertex to the memory structure, and specifies its edges. */
477 template<class n_option
>
478 void voronoicell_base
<n_option
>::add_vertex(fpoint x
,fpoint y
,fpoint z
,int a
,int b
,int c
,int d
) {
479 pts
[3*p
]=x
;pts
[3*p
+1]=y
;pts
[3*p
+2]=z
;nu
[p
]=4;
480 if (mem
[4]==mec
[4]) add_memory(4);
481 neighbor
.set_pointer(p
,4);
482 int *q
=mep
[4]+9*mec
[4]++;ed
[p
]=q
;
483 q
[0]=a
;q
[1]=b
;q
[2]=c
;q
[3]=d
;q
[8]=p
++;
486 /** Adds an order 5 vertex to the memory structure, and specifies its edges. */
487 template<class n_option
>
488 void voronoicell_base
<n_option
>::add_vertex(fpoint x
,fpoint y
,fpoint z
,int a
,int b
,int c
,int d
,int e
) {
489 pts
[3*p
]=x
;pts
[3*p
+1]=y
;pts
[3*p
+2]=z
;nu
[p
]=5;
490 if (mem
[5]==mec
[5]) add_memory(5);
491 neighbor
.set_pointer(p
,5);
492 int *q
=mep
[5]+11*mec
[5]++;ed
[p
]=q
;
493 q
[0]=a
;q
[1]=b
;q
[2]=c
;q
[3]=d
;q
[4]=e
;q
[10]=p
++;
496 /** Checks that the relational table of the Voronoi cell is accurate, and prints
497 * out any errors. This algorithm is O(p), so running it every time the plane
498 * routine is called will result in a significant slowdown. */
499 template<class n_option
>
500 inline void voronoicell_base
<n_option
>::check_relations() {
503 for(j
=0;j
<nu
[i
];j
++) {
504 if (ed
[ed
[i
][j
]][ed
[i
][nu
[i
]+j
]]!=i
) cout
<< "Relational error at point " << i
<< ", edge " << j
<< "." << endl
;
509 /** This routine checks for any two vertices that are connected by more than one
510 * edge. The plane algorithm is designed so that this should not happen, so any
511 * occurrences are most likely errors. Note that the routine is O(p), so
512 * running it every time the plane routine is called will result in a significant
514 template<class n_option
>
515 inline void voronoicell_base
<n_option
>::check_duplicates() {
518 for(j
=1;j
<nu
[i
];j
++) {
520 if (ed
[i
][j
]==ed
[i
][k
]) cout
<< "Duplicate edges: (" << i
<< "," << j
<< ") and (" << i
<< "," << k
<< ") [" << ed
[i
][j
] << "]" << endl
;
526 /** Constructs the relational table if the edges have been specified. */
527 template<class n_option
>
528 inline void voronoicell_base
<n_option
>::construct_relations() {
530 for(i
=0;i
<p
;i
++) for(j
=0;j
<nu
[i
];j
++) {
535 if (l
==nu
[k
]) throw fatal_error("Relation table construction failed");
541 /** Cuts the Voronoi cell by a particle whose center is at a separation of
542 * (x,y,z) from the cell center. The value of rsq should be initially set to
543 * \f$x^2+y^2+z^2\f$. */
544 template<class n_option
>
545 bool voronoicell_base
<n_option
>::nplane(fpoint x
,fpoint y
,fpoint z
,fpoint rsq
,int p_id
) {
546 int count
=0,i
,j
,k
,lp
=up
,cp
,qp
,rp
,stack
=0;stack2
=0;
547 int us
=0,ls
=0,qs
,iqs
,cs
,uw
,qw
,lw
;
549 fpoint u
,l
,r
,q
;bool complicated_setup
=false,new_double_edge
=false,double_edge
=false;
550 //Initialize the safe testing routine
551 sure
.init(x
,y
,z
,rsq
);
553 //Test approximately sqrt(n)/4 points for their proximity to the plane
554 //and keep the one which is closest
557 // Starting from an initial guess, we now move from vertex to vertex,
558 // to try and find an edge which intersects the cutting plane,
559 // or a vertex which is on the plane
562 // The test point is inside the cutting plane.
575 ls
=ed
[up
][nu
[up
]+us
];
577 if(++count
>=p
) throw true;
579 for(us
=0;us
<ls
;us
++) {
596 ls
=ed
[up
][nu
[up
]+us
];
599 // If the last point in the iteration is within the
600 // plane, we need to do the complicated setup
601 // routine. Otherwise, we use the regular iteration.
604 complicated_setup
=true;
605 } else complicated_setup
=false;
614 if(us
==nu
[up
]) return true;
617 qs
=ed
[up
][nu
[up
]+us
];
618 if(++count
>=p
) throw true;
620 for(us
=0;us
<qs
;us
++) {
633 if(us
==nu
[up
]) return true;
638 up
=qp
;us
=ed
[lp
][nu
[lp
]+ls
];u
=q
;
639 complicated_setup
=false;
642 complicated_setup
=true;
646 // Our original test point was on the plane, so we
647 // automatically head for the complicated setup
649 complicated_setup
=true;
653 // This routine is a fall-back, in case floating point errors
654 // cause the usual search routine to fail. In the fall-back
655 // routine, we just test every edge to find one straddling
657 #if VOROPP_VERBOSE >=1
658 cerr
<< "Bailed out of convex calculation\n";
661 for(qp
=0;qp
<p
;qp
++) {
665 // The point is inside the cutting space. Now
666 // see if we can find a neighbor which isn't.
667 for(us
=0;us
<nu
[qp
];us
++) {
677 complicated_setup
=true;
679 complicated_setup
=false;
681 ls
=ed
[up
][nu
[up
]+us
];
687 // The point is outside the cutting space. See
688 // if we can find a neighbor which isn't.
689 for(ls
=0;ls
<nu
[qp
];ls
++) {
699 complicated_setup
=true;
701 complicated_setup
=false;
703 us
=ed
[lp
][nu
[lp
]+ls
];
709 // The point is in the plane, so we just
710 // proceed with the complicated setup routine
712 complicated_setup
=true;
716 if(qp
==p
) return qw
==-1?true:false;
719 // We're about to add the first point of the new facet. In either
720 // routine, we have to add a point, so first check there's space for
722 if(p
==current_vertices
) add_memory_vertices();
724 if (complicated_setup
) {
725 // The search algorithm found a point which is on the cutting
726 // plane. We leave that point in place, and create a new one at
727 // the same location.
729 pts
[3*p
+1]=pts
[3*up
+1];
730 pts
[3*p
+2]=pts
[3*up
+2];
732 // Search for a collection of edges of the test vertex which
733 // are outside of the cutting space. Begin by testing the
740 // The first edge is either inside the cutting space,
741 // or lies within the cutting plane. Test the edges
742 // sequentially until we find one that is outside.
747 // If we reached the last edge with no luck
748 // then all of the vertices are inside
749 // or on the plane, so the cell is completely
751 if (i
==nu
[up
]) return false;
757 // We found an edge outside the cutting space. Keep
758 // moving through these edges until we find one that's
759 // inside or on the plane.
767 // Compute the number of edges for the new vertex. In
768 // general it will be the number of outside edges
769 // found, plus two. But we need to recognize the
770 // special case when all but one edge is outside, and
771 // the remaining one is on the plane. For that case we
772 // have to reduce the edge count by one to prevent
774 if(j
==nu
[up
]&&i
==1&&rp
==0) {
780 // Add memory for the new vertex if needed, and
782 while (nu
[p
]>=current_vertex_order
) add_memory_vorder();
783 if (mec
[nu
[p
]]==mem
[nu
[p
]]) add_memory(nu
[p
]);
784 neighbor
.set_pointer(p
,nu
[p
]);
785 ed
[p
]=mep
[nu
[p
]]+(2*nu
[p
]+1)*mec
[nu
[p
]]++;
788 // Copy the edges of the original vertex into the new
789 // one. Delete the edges of the original vertex, and
790 // update the relational table.
795 neighbor
.copy(p
,k
,up
,i
);
806 // In this case, the zeroth edge is outside the cutting
807 // plane. Begin by searching backwards from the last
808 // edge until we find an edge which isn't outside.
815 // If i reaches zero, then we have a point in
816 // the plane all of whose edges are outside
817 // the cutting space, so we just exit
818 if (i
==0) return true;
823 // Now search forwards from zero
833 // Compute the number of edges for the new vertex. In
834 // general it will be the number of outside edges
835 // found, plus two. But we need to recognize the
836 // special case when all but one edge is outside, and
837 // the remaining one is on the plane. For that case we
838 // have to reduce the edge count by one to prevent
847 // Add memory to store the vertex if it doesn't exist
850 while(nu
[p
]>=current_vertex_order
) add_memory_vorder();
851 if (mec
[nu
[p
]]==mem
[nu
[p
]]) add_memory(nu
[p
]);
853 // Copy the edges of the original vertex into the new
854 // one. Delete the edges of the original vertex, and
855 // update the relational table.
856 neighbor
.set_pointer(p
,nu
[p
]);
857 ed
[p
]=mep
[nu
[p
]]+(2*nu
[p
]+1)*mec
[nu
[p
]]++;
863 neighbor
.copy(p
,k
,up
,i
);
875 neighbor
.copy(p
,k
,up
,i
);
886 neighbor
.copy(p
,k
,up
,qs
);
887 neighbor
.set(p
,0,p_id
);
888 } else neighbor
.copy(p
,0,up
,qs
);
890 // Add this point to the auxiliary delete stack
891 if (stack2
==current_delete2_size
) add_memory_ds2();
894 // Look at the edges on either side of the group that was
895 // detected. We're going to commence facet computation by
896 // moving along one of them. We are going to end up coming back
897 // along the other one.
901 us
=ed
[up
][nu
[up
]+us
];
907 // The search algorithm found an intersected edge between the
908 // points lp and up. Create a new vertex between them which
909 // lies on the cutting plane. Since u and l differ by at least
910 // the tolerance, this division should never screw up.
911 if (stack
==current_delete_size
) add_memory_ds();
914 pts
[3*p
]=(pts
[3*lp
]*u
-pts
[3*up
]*l
)*r
;
915 pts
[3*p
+1]=(pts
[3*lp
+1]*u
-pts
[3*up
+1]*l
)*r
;
916 pts
[3*p
+2]=(pts
[3*lp
+2]*u
-pts
[3*up
+2]*l
)*r
;
918 // This point will always have three edges. Connect one of them
921 if (mec
[3]==mem
[3]) add_memory(3);
922 neighbor
.set_pointer(p
,3);
923 neighbor
.set(p
,0,p_id
);
924 neighbor
.copy(p
,1,up
,us
);
925 neighbor
.copy(p
,2,lp
,ls
);
926 ed
[p
]=mep
[3]+7*mec
[3]++;
935 // Set the direction to move in
940 // When the code reaches here, we have initialized the first point, and
941 // we have a direction for moving it to construct the rest of the facet
943 while(qp
!=up
||qs
!=us
) {
945 // We're currently tracing round an intersected facet. Keep
946 // moving around it until we find a point or edge which
947 // intersects the plane.
953 // The point is still in the cutting space. Just add it
954 // to the delete stack and keep moving.
955 if (stack
==current_delete_size
) add_memory_ds();
956 qs
=cycle_up(ed
[qp
][nu
[qp
]+qs
],lp
);
963 // The point is outside of the cutting space, so we've
964 // found an intersected edge. Introduce a regular point
965 // at the point of intersection. Connect it to the
966 // point we just tested. Also connect it to the previous
967 // new point in the facet we're constructing.
968 if(p
==current_vertices
) add_memory_vertices();
970 pts
[3*p
]=(pts
[3*lp
]*q
-pts
[3*qp
]*l
)*r
;
971 pts
[3*p
+1]=(pts
[3*lp
+1]*q
-pts
[3*qp
+1]*l
)*r
;
972 pts
[3*p
+2]=(pts
[3*lp
+2]*q
-pts
[3*qp
+2]*l
)*r
;
974 if (mec
[3]==mem
[3]) add_memory(3);
975 ls
=ed
[qp
][qs
+nu
[qp
]];
976 neighbor
.set_pointer(p
,3);
977 neighbor
.set(p
,0,p_id
);
978 neighbor
.copy(p
,1,qp
,qs
);
979 neighbor
.copy(p
,2,lp
,ls
);
980 ed
[p
]=mep
[3]+7*mec
[3]++;
996 // We've found a point which is on the cutting plane.
997 // We're going to introduce a new point right here, but
998 // first we need to figure out the number of edges it
1000 if(p
==current_vertices
) add_memory_vertices();
1002 // If the previous vertex detected a double edge, our
1003 // new vertex will have one less edge.
1005 qs
=ed
[qp
][nu
[qp
]+qs
];
1009 // Start testing the edges of the current point until
1010 // we find one which isn't outside the cutting space
1018 // Now we need to find out whether this marginal vertex
1019 // we are on has been visited before, because if that's
1020 // the case, we need to add vertices to the existing
1021 // new vertex, rather than creating a fresh one. We also
1022 // need to figure out whether we're in a case where we
1023 // might be creating a duplicate edge.
1024 j
=-ed
[qp
][2*nu
[qp
]];
1025 if(qp
==up
&&qs
==us
) {
1027 // If we're heading into the final part of the
1028 // new facet, then we never worry about the
1029 // duplicate edge calculation.
1030 new_double_edge
=false;
1035 // This vertex was visited before, so
1036 // count those vertices to the ones we
1040 // The only time when we might make a
1041 // duplicate edge is if the point we're
1042 // going to move to next is also a
1043 // marginal point, so test for that
1047 // Now see whether this marginal point
1048 // has been visited before.
1049 i
=-ed
[lp
][2*nu
[lp
]];
1052 // Now see if the last edge of that other
1053 // marginal point actually ends up here.
1054 if(ed
[i
][nu
[i
]-1]==j
) {
1055 new_double_edge
=true;
1057 } else new_double_edge
=false;
1060 // That marginal point hasn't been visited
1061 // before, so we probably don't have to worry
1062 // about duplicate edges, except in the
1063 // case when that's the way into the end
1064 // of the facet, because that way always creates
1066 if (j
==rp
&&lp
==up
&&ed
[qp
][nu
[qp
]+qs
]==us
) {
1067 new_double_edge
=true;
1069 } else new_double_edge
=false;
1071 } else new_double_edge
=false;
1074 // The vertex hasn't been visited
1075 // before, but let's see if it's
1079 // If it is, we need to check
1080 // for the case that it's a
1081 // small branch, and that we're
1082 // heading right back to where
1084 i
=-ed
[lp
][2*nu
[lp
]];
1086 new_double_edge
=true;
1088 } else new_double_edge
=false;
1089 } else new_double_edge
=false;
1093 // k now holds the number of edges of the new vertex
1094 // we are forming. Add memory for it if it doesn't exist
1096 while(k
>=current_vertex_order
) add_memory_vorder();
1097 if (mec
[k
]==mem
[k
]) add_memory(k
);
1099 // Now create a new vertex with order k, or augment
1103 // If we're augmenting a vertex but we don't
1104 // actually need any more edges, just skip this
1105 // routine to avoid memory confusion
1107 // Allocate memory and copy the edges
1108 // of the previous instance into it
1109 neighbor
.set_aux1(k
);
1110 edp
=mep
[k
]+(2*k
+1)*mec
[k
]++;
1113 neighbor
.copy_aux1(j
,i
);
1115 edp
[k
+i
]=ed
[j
][nu
[j
]+i
];
1120 // Remove the previous instance with
1121 // fewer vertices from the memory
1123 edd
=mep
[nu
[j
]]+(2*nu
[j
]+1)*--mec
[nu
[j
]];
1125 for(lw
=0;lw
<=2*nu
[j
];lw
++) ed
[j
][lw
]=edd
[lw
];
1126 neighbor
.set_aux2_copy(j
,nu
[j
]);
1127 neighbor
.copy_pointer(edd
[2*nu
[j
]],j
);
1128 ed
[edd
[2*nu
[j
]]]=ed
[j
];
1130 neighbor
.set_to_aux1(j
);
1135 // Allocate a new vertex of order k
1136 neighbor
.set_pointer(p
,k
);
1137 ed
[p
]=mep
[k
]+(2*k
+1)*mec
[k
]++;
1139 if (stack2
==current_delete2_size
) add_memory_ds2();
1142 pts
[3*p
+1]=pts
[3*qp
+1];
1143 pts
[3*p
+2]=pts
[3*qp
+2];
1144 ed
[qp
][2*nu
[qp
]]=-p
;
1150 // Unless the previous case was a double edge, connect
1151 // the first available edge of the new vertex to the
1152 // last one in the facet
1156 neighbor
.set(j
,i
,p_id
);
1158 ed
[cp
][nu
[cp
]+cs
]=i
;
1162 // Copy in the edges of the underlying vertex,
1163 // and do one less if this was a double edge
1165 while(i
<(new_double_edge
?k
:k
-1)) {
1167 lp
=ed
[qp
][qs
];ls
=ed
[qp
][nu
[qp
]+qs
];
1168 neighbor
.copy(j
,i
,qp
,qs
);
1172 ed
[lp
][nu
[lp
]+ls
]=i
;
1179 neighbor
.copy(j
,new_double_edge
?0:cs
,qp
,qs
);
1181 // Update the double_edge flag, to pass it
1182 // to the next instance of this routine
1183 double_edge
=new_double_edge
;
1187 // Connect the final created vertex to the initial one
1190 ed
[cp
][nu
[cp
]+cs
]=0;
1191 ed
[rp
][nu
[rp
]+0]=cs
;
1193 // Delete points: first, remove any duplicates
1197 if(ed
[j
][nu
[j
]]!=-1) {
1200 } else ds
[i
]=ds
[--stack
];
1203 // Add the points in the auxiliary delete stack,
1204 // and reset their back pointers
1205 for(i
=0;i
<stack2
;i
++) {
1208 if(ed
[j
][nu
[j
]]!=-1) {
1210 if (stack
==current_delete_size
) add_memory_ds();
1215 // Scan connections and add in extras
1216 for(i
=0;i
<stack
;i
++) {
1218 for(j
=0;j
<nu
[cp
];j
++) {
1221 if (ed
[qp
][nu
[qp
]]!=-1) {
1222 if (stack
==current_delete_size
) add_memory_ds();
1231 // Delete them from the array structure
1233 while(ed
[--p
][nu
[p
]]==-1) {
1236 for(i
=0;i
<=2*j
;i
++) ed
[p
][i
]=(mep
[j
]+(2*j
+1)*mec
[j
])[i
];
1237 neighbor
.set_aux2_copy(p
,j
);
1238 neighbor
.copy_pointer(ed
[p
][2*j
],p
);
1239 ed
[ed
[p
][2*j
]]=ed
[p
];
1244 // Vertex management
1246 pts
[3*up
+1]=pts
[3*p
+1];
1247 pts
[3*up
+2]=pts
[3*p
+2];
1249 // Memory management
1252 for(i
=0;i
<=2*j
;i
++) ed
[up
][i
]=(mep
[j
]+(2*j
+1)*mec
[j
])[i
];
1253 neighbor
.set_aux2_copy(up
,j
);
1254 neighbor
.copy_pointer(ed
[up
][2*j
],up
);
1255 neighbor
.copy_pointer(up
,p
);
1256 ed
[ed
[up
][2*j
]]=ed
[up
];
1261 for(i
=0;i
<nu
[up
];i
++) {
1262 if (ed
[up
][i
]==-1) throw fatal_error("fishy");
1263 ed
[ed
[up
][i
]][ed
[up
][nu
[up
]+i
]]=up
;
1265 ed
[up
][2*nu
[up
]]=up
;
1269 // Check for any vertices of zero order
1270 if (mec
[0]>0) throw fatal_error("Zero order vertex formed");
1272 // Collapse any order 2 vertices and exit
1273 return collapse_order2();
1276 /** During the creation of a new facet in the plane routine, it is possible
1277 * that some order two vertices may arise. This routine removes them.
1278 * Suppose an order two vertex joins c and d. If there's a edge between
1279 * c and d already, then the order two vertex is just removed; otherwise,
1280 * the order two vertex is removed and c and d are joined together directly.
1281 * It is possible this process will create order two or order one vertices,
1282 * and the routine is continually run until all of them are removed.
1283 * \return false if the vertex removal was unsuccessful, indicative of
1284 * the cell reducing to zero volume and disappearing; true if the vertex
1285 * removal was successful. */
1286 template<class n_option
>
1287 inline bool voronoicell_base
<n_option
>::collapse_order2() {
1288 if(!collapse_order1()) return false;
1292 // Pick a order 2 vertex and read in its edges
1294 j
=mep
[2][5*i
];k
=mep
[2][5*i
+1];
1296 #if VOROPP_VERBOSE >=1
1297 cerr
<< "Order two vertex joins itself" << endl
;
1302 // Scan the edges of j to see if joins k
1303 for(l
=0;l
<nu
[j
];l
++) {
1304 if(ed
[j
][l
]==k
) break;
1307 // If j doesn't already join k, join them together.
1308 // Otherwise delete the connection to the current
1309 // vertex from j and k.
1310 a
=mep
[2][5*i
+2];b
=mep
[2][5*i
+3];i
=mep
[2][5*i
+4];
1317 if (!delete_connection(j
,a
,false)) return false;
1318 if (!delete_connection(k
,b
,true)) return false;
1321 // Compact the memory
1327 pts
[3*i
+1]=pts
[3*p
+1];
1328 pts
[3*i
+2]=pts
[3*p
+2];
1329 for(k
=0;k
<nu
[p
];k
++) ed
[ed
[p
][k
]][ed
[p
][nu
[p
]+k
]]=i
;
1330 neighbor
.copy_pointer(i
,p
);
1336 // Collapse any order 1 vertices if they were created
1337 if(!collapse_order1()) return false;
1342 /** Order one vertices can potentially be created during the order two collapse
1343 * routine. This routine keeps removing them until there are none left.
1344 * \return false if the vertex removal was unsuccessful, indicative of
1345 * the cell having zero volume and disappearing; true if the vertex removal
1346 * was successful. */
1347 template<class n_option
>
1348 inline bool voronoicell_base
<n_option
>::collapse_order1() {
1352 #if VOROPP_VERBOSE >=1
1353 cerr
<< "Order one collapse" << endl
;
1356 j
=mep
[1][3*i
];k
=mep
[1][3*i
+1];
1358 if(!delete_connection(j
,k
,false)) return false;
1364 pts
[3*i
+1]=pts
[3*p
+1];
1365 pts
[3*i
+2]=pts
[3*p
+2];
1366 for(k
=0;k
<nu
[p
];k
++) ed
[ed
[p
][k
]][ed
[p
][nu
[p
]+k
]]=i
;
1367 neighbor
.copy_pointer(i
,p
);
1376 /** This routine deletes the kth edge of vertex j and reorganizes the memory.
1377 * If the neighbor computation is enabled, we also have to supply an
1378 * handedness flag to decide whether to preserve the plane on the left
1379 * or right of the connection.
1380 * \return false if a zero order vertex was formed, indicative of the cell
1381 * disappearing; true if the vertex removal was successful. */
1382 template<class n_option
>
1383 inline bool voronoicell_base
<n_option
>::delete_connection(int j
,int k
,bool hand
) {
1384 int q
=hand
?k
:cycle_up(k
,j
);
1385 int i
=nu
[j
]-1,l
,*edp
,*edd
,m
;
1387 cout
<< "Zero order vertex formed" << endl
;
1390 if(mec
[i
]==mem
[i
]) add_memory(i
);
1391 neighbor
.set_aux1(i
);
1392 for(l
=0;l
<q
;l
++) neighbor
.copy_aux1(j
,l
);
1394 neighbor
.copy_aux1_shift(j
,l
);
1397 edp
=mep
[i
]+(2*i
+1)*mec
[i
]++;
1401 edp
[l
+i
]=ed
[j
][l
+nu
[j
]];
1412 edd
=mep
[nu
[j
]]+(2*nu
[j
]+1)*--mec
[nu
[j
]];
1413 for(l
=0;l
<=2*nu
[j
];l
++) ed
[j
][l
]=edd
[l
];
1414 neighbor
.set_aux2_copy(j
,nu
[j
]);
1415 neighbor
.set_to_aux2(edd
[2*nu
[j
]]);
1416 neighbor
.set_to_aux1(j
);
1417 ed
[edd
[2*nu
[j
]]]=edd
;
1423 /** Cuts a Voronoi cell using the influence of a particle at (x,y,z), first
1424 * calculating the modulus squared of this vector before passing it to the
1425 * main nplane() routine. Zero is supplied as the plane ID, which will be
1426 * ignored unless neighbor tracking is enabled.
1427 * \param[in] (x,y,z) The vector to cut the cell by. */
1428 template<class n_option
>
1429 inline bool voronoicell_base
<n_option
>::plane(fpoint x
,fpoint y
,fpoint z
) {
1430 fpoint rsq
=x
*x
+y
*y
+z
*z
;
1431 return nplane(x
,y
,z
,rsq
,0);
1434 /** This version of the plane routine just makes up the plane ID to be zero. It
1435 * will only be referenced if neighbor tracking is enabled.
1436 * \param[in] (x,y,z) The vector to cut the cell by.
1437 * \param[in] rsq The modulus squared of the vector. */
1438 template<class n_option
>
1439 inline bool voronoicell_base
<n_option
>::plane(fpoint x
,fpoint y
,fpoint z
,fpoint rsq
) {
1440 return nplane(x
,y
,z
,rsq
,0);
1443 /** This routine calculates the modulus squared of the vector before passing it
1444 * to the main nplane() routine with full arguments.
1445 * \param[in] (x,y,z) The vector to cut the cell by.
1446 * \param[in] p_id The plane ID (for neighbor tracking only).*/
1447 template<class n_option
>
1448 inline bool voronoicell_base
<n_option
>::nplane(fpoint x
,fpoint y
,fpoint z
,int p_id
) {
1449 fpoint rsq
=x
*x
+y
*y
+z
*z
;
1450 return nplane(x
,y
,z
,rsq
,p_id
);
1453 /** This is a simple inline function for picking out the index of the next edge
1454 * counterclockwise at the current vertex.
1455 * \param[in] a The index of an edge of the current vertex.
1456 * \param[in] p The number of the vertex.
1457 * \return 0 if a=nu[p]-1, or a+1 otherwise. */
1458 template<class n_option
>
1459 inline int voronoicell_base
<n_option
>::cycle_up(int a
,int p
) {
1460 return a
==nu
[p
]-1?0:a
+1;
1463 /** This is a simple inline function for picking out the index of the next edge
1464 * clockwise from the current vertex.
1465 * \param[in] a The index of an edge of the current vertex.
1466 * \param[in] p The number of the vertex.
1467 * \return nu[p]-1 if a=0, or a-1 otherwise. */
1468 template<class n_option
>
1469 inline int voronoicell_base
<n_option
>::cycle_down(int a
,int p
) {
1470 return a
==0?nu
[p
]-1:a
-1;
1473 /** Calculates the volume of the Voronoi cell, by decomposing the cell into
1474 * tetrahedra extending outward from the zeroth vertex, which are evaluated
1475 * using a scalar triple product.
1476 * \return A floating point number holding the calculated volume. */
1477 template<class n_option
>
1478 fpoint voronoicell_base
<n_option
>::volume() {
1479 const fpoint fe
=1/48.0;
1482 fpoint ux
,uy
,uz
,vx
,vy
,vz
,wx
,wy
,wz
;
1485 uy
=pts
[1]-pts
[3*i
+1];
1486 uz
=pts
[2]-pts
[3*i
+2];
1487 for(j
=0;j
<nu
[i
];j
++) {
1491 l
=cycle_up(ed
[i
][nu
[i
]+j
],k
);
1493 vy
=pts
[3*k
+1]-pts
[1];
1494 vz
=pts
[3*k
+2]-pts
[2];
1495 m
=ed
[k
][l
];ed
[k
][l
]=-1-m
;
1497 n
=cycle_up(ed
[k
][nu
[k
]+l
],m
);
1499 wy
=pts
[3*m
+1]-pts
[1];
1500 wz
=pts
[3*m
+2]-pts
[2];
1501 vol
+=ux
*vy
*wz
+uy
*vz
*wx
+uz
*vx
*wy
-uz
*vy
*wx
-uy
*vx
*wz
-ux
*vz
*wy
;
1502 k
=m
;l
=n
;vx
=wx
;vy
=wy
;vz
=wz
;
1503 m
=ed
[k
][l
];ed
[k
][l
]=-1-m
;
1509 for(j
=0;j
<nu
[i
];j
++) {
1510 if(ed
[i
][j
]>=0) throw fatal_error("Volume routine didn't look everywhere");
1511 ed
[i
][j
]=-1-ed
[i
][j
];
1518 /** Computes the maximum radius squared of a vertex from the center
1519 * of the cell. It can be used to determine when enough particles have
1520 * been testing an all planes that could cut the cell have been considered.
1521 * \return The maximum radius squared of a vertex.*/
1522 template<class n_option
>
1523 fpoint voronoicell_base
<n_option
>::maxradsq() {
1525 r
=pts
[0]*pts
[0]+pts
[1]*pts
[1]+pts
[2]*pts
[2];
1526 for(i
=3;i
<3*p
;i
+=3) {
1527 s
=pts
[i
]*pts
[i
]+pts
[i
+1]*pts
[i
+1]+pts
[i
+2]*pts
[i
+2];
1533 /** Outputs the edges of the Voronoi cell (in POV-Ray format) to an open file
1534 * stream, displacing the cell by an amount (x,y,z).
1535 * \param[in] &os A output stream to write to.
1536 * \param[in] (x,y,z) A displacement vector to be added to the cell's position. */
1537 template<class n_option
>
1538 void voronoicell_base
<n_option
>::draw_pov(ostream
&os
,fpoint x
,fpoint y
,fpoint z
) {
1539 int i
,j
,k
;fpoint ux
,uy
,uz
;
1542 ux
=x
+0.5*pts
[3*i
];uy
=y
+0.5*pts
[3*i
+1];uz
=z
+0.5*pts
[3*i
+2];
1543 if (neighbor
.internal_wall(i
)) os
<< "sphere{<" << ux
<< "," << uy
<< "," << uz
<< ">,r}\n";
1544 for(j
=0;j
<nu
[i
];j
++) {
1546 if (k
<i
&&!neighbor
.internal_wall(i
,j
)) os
<< "cylinder{<" << ux
<< "," << uy
<< "," << uz
<< ">,<" << x
+0.5*pts
[3*k
] << "," << y
+0.5*pts
[3*k
+1] << "," << z
+0.5*pts
[3*k
+2] << ">,r}\n";
1552 inline bool neighbor_track::internal_wall(int i
) {
1553 for(int j
=0;j
<vc
->nu
[i
];j
++) {
1554 if(ne
[i
][j
]!=-99) return true;
1559 inline bool neighbor_track::internal_wall(int i
,int j
) {
1560 return ne
[i
][j
]==-99&&ne
[i
][j
==vc
->nu
[i
]-1?0:j
+1]==-99;
1563 /** An overloaded version of the draw_pov routine, that outputs the edges of
1564 * the Voronoi cell (in POV-Ray format) to a file.
1565 * \param[in] filename The file to write to.
1566 * \param[in] (x,y,z) A displacement vector to be added to the cell's position.
1568 template<class n_option
>
1569 inline void voronoicell_base
<n_option
>::draw_pov(const char *filename
,fpoint x
,fpoint y
,fpoint z
) {
1571 os
.open(filename
,ofstream::out
|ofstream::trunc
);
1576 /** An overloaded version of the draw_pov routine, that outputs the edges of the
1577 * Voronoi cell (in POV-Ray format) to standard output.
1578 * \param[in] (x,y,z) A displacement vector to be added to the cell's position.
1580 template<class n_option
>
1581 inline void voronoicell_base
<n_option
>::draw_pov(fpoint x
,fpoint y
,fpoint z
) {
1582 draw_pov(cout
,x
,y
,z
);
1585 /** Outputs the edges of the Voronoi cell (in gnuplot format) to an output stream.
1586 * \param[in] &os A reference to an output stream to write to.
1587 * \param[in] (x,y,z) A displacement vector to be added to the cell's position.
1589 template<class n_option
>
1590 void voronoicell_base
<n_option
>::draw_gnuplot(ostream
&os
,fpoint x
,fpoint y
,fpoint z
) {
1591 int i
,j
,k
;fpoint ux
,uy
,uz
;
1593 ux
=x
+0.5*pts
[3*i
];uy
=y
+0.5*pts
[3*i
+1];uz
=z
+0.5*pts
[3*i
+2];
1594 for(j
=0;j
<nu
[i
];j
++) {
1596 if (ed
[i
][j
]<i
) os
<< ux
<< " " << uy
<< " " << uz
<< "\n" << x
+0.5*pts
[3*k
] << " " << y
+0.5*pts
[3*k
+1] << " " << z
+0.5*pts
[3*k
+2] << "\n\n\n";
1601 /** An overloaded version of the draw_gnuplot routine that writes directly to
1603 * \param[in] filename The name of the file to write to.
1604 * \param[in] (x,y,z) A displacement vector to be added to the cell's position.
1606 template<class n_option
>
1607 inline void voronoicell_base
<n_option
>::draw_gnuplot(const char *filename
,fpoint x
,fpoint y
,fpoint z
) {
1609 os
.open(filename
,ofstream::out
|ofstream::trunc
);
1610 draw_gnuplot(os
,x
,y
,z
);
1614 /** An overloaded version of the draw_gnuplot routine, that prints to the
1616 * \param[in] (x,y,z) A displacement vector to be added to the cell's position.
1618 template<class n_option
>
1619 inline void voronoicell_base
<n_option
>::draw_gnuplot(fpoint x
,fpoint y
,fpoint z
) {
1620 draw_gnuplot(cout
,x
,y
,z
);
1623 /** Outputs the Voronoi cell in the POV mesh2 format, described in section
1624 * 1.3.2.2 of the POV-Ray documentation. The mesh2 output consists of a list of
1625 * vertex vectors, followed by a list of triangular faces. The routine also
1626 * makes use of the optional inside_vector specification, which makes the mesh
1627 * object solid, so the the POV-Ray Constructive Solid Geometry (CSG) can be
1629 * \param[in] &os An output stream to write to.
1630 * \param[in] (x,y,z) A displacement vector to be added to the cell's position.
1632 template<class n_option
>
1633 inline void voronoicell_base
<n_option
>::draw_pov_mesh(ostream
&os
,fpoint x
,fpoint y
,fpoint z
) {
1635 os
<< "mesh2 {\nvertex_vectors {\n" << p
<< ",\n";
1637 os
<< "<" << x
+0.5*pts
[3*i
] << "," << y
+0.5*pts
[3*i
+1] << "," << z
+0.5*pts
[3*i
+2] << ">,\n";
1639 os
<< "}\nface_indices {\n" << 2*(p
-2) << ",\n";
1641 for(j
=0;j
<nu
[i
];j
++) {
1645 l
=cycle_up(ed
[i
][nu
[i
]+j
],k
);
1646 m
=ed
[k
][l
];ed
[k
][l
]=-1-m
;
1648 n
=cycle_up(ed
[k
][nu
[k
]+l
],m
);
1649 os
<< "<" << i
<< "," << k
<< "," << m
<< ">\n";
1651 m
=ed
[k
][l
];ed
[k
][l
]=-1-m
;
1657 for(j
=0;j
<nu
[i
];j
++) {
1658 if(ed
[i
][j
]>=0) throw fatal_error("Mesh routine didn't look everywhere");
1659 ed
[i
][j
]=-1-ed
[i
][j
];
1662 os
<< "}\ninside_vector <0,0,1>\n}\n";
1665 /** An overloaded version of the draw_pov_mesh routine, that writes directly to a
1667 * \param[in] filename A filename to write to.
1668 * \param[in] (x,y,z) A displacement vector to be added to the cell's position.
1670 template<class n_option
>
1671 inline void voronoicell_base
<n_option
>::draw_pov_mesh(const char *filename
,fpoint x
,fpoint y
,fpoint z
) {
1673 os
.open(filename
,ofstream::out
|ofstream::trunc
);
1674 draw_pov_mesh(os
,x
,y
,z
);
1678 /** An overloaded version of the draw_pov_mesh routine, that prints to the
1680 * \param[in] (x,y,z) A displacement vector to be added to the cell's position.
1682 template<class n_option
>
1683 inline void voronoicell_base
<n_option
>::draw_pov_mesh(fpoint x
,fpoint y
,fpoint z
) {
1684 draw_pov_mesh(cout
,x
,y
,z
);
1687 /** Randomly perturbs the points in the Voronoi cell by an amount r. */
1688 template<class n_option
>
1689 inline void voronoicell_base
<n_option
>::perturb(fpoint r
) {
1690 for(int i
=0;i
<3*p
;i
++) {
1691 pts
[i
]+=(2*fpoint(rand())/RAND_MAX
-1)*r
;
1695 /** Initializes the suretest class and creates a buffer for marginal points. */
1696 suretest::suretest() : current_marginal(init_marginal
) {
1697 sn
=new int[2*current_marginal
];
1700 /** Suretest destructor to free memory allocation. */
1701 suretest::~suretest() {
1705 /** Sets up the suretest class with a particular test plane, and removes
1706 * any special cases from the table. */
1707 inline void suretest::init(fpoint x
,fpoint y
,fpoint z
,fpoint rsq
) {
1708 sc
=0;px
=x
;py
=y
;pz
=z
;prsq
=rsq
;
1712 inline int suretest::test(int n
,fpoint
&ans
) {
1713 ans
=px
*p
[3*n
]+py
*p
[3*n
+1]+pz
*p
[3*n
+2]-prsq
;
1714 if(ans
<-tolerance2
) {
1716 } else if(ans
>tolerance2
) {
1719 return check_marginal(n
,ans
);
1722 int suretest::check_marginal(int n
,fpoint
&ans
) {
1724 for(i
=0;i
<sc
;i
+=2) if(sn
[i
]==n
) return sn
[i
+1];
1725 if (sc
==2*current_marginal
) {
1726 i
=2*current_marginal
;
1727 if (i
>max_marginal
) throw fatal_error("Marginal case buffer allocation exceeded absolute maximum");
1728 #if VOROPP_VERBOSE >=2
1729 cerr
<< "Marginal cases buffer scaled up to " << i
<< endl
;
1731 int *psn
=new int[2*i
];
1732 for(int j
=0;j
<2*current_marginal
;j
++) psn
[j
]=sn
[j
];
1733 delete [] sn
;sn
=psn
;
1736 sn
[sc
++]=ans
>tolerance
?1:(ans
<-tolerance
?-1:0);
1740 /** Prints the vertices, their edges, the relation table, and also notifies if
1741 * any glaring memory errors are visible. */
1742 template<class n_option
>
1743 void voronoicell_base
<n_option
>::print_edges() {
1745 for(int i
=0;i
<p
;i
++) {
1746 cout
<< i
<< " " << nu
[i
] << " ";
1747 for(j
=0;j
<nu
[i
];j
++) cout
<< " " << ed
[i
][j
];
1749 while(j
<2*nu
[i
]) cout
<< " " << ed
[i
][j
++];
1750 cout
<< " " << ed
[i
][j
];
1751 neighbor
.print_edges(i
);
1752 cout
<< " " << pts
[3*i
] << " " << pts
[3*i
+1] << " " << pts
[3*i
+2];
1753 cout
<< " " << ed
[i
];
1754 if (ed
[i
]>=mep
[nu
[i
]]+mec
[nu
[i
]]*(2*nu
[i
]+1)) cout
<< " Memory error";
1759 /** Prints out a list of all the facets and their vertices. If the neighbor option
1760 * is defined, it lists each cutting plane. */
1761 template<class n_option
>
1762 void voronoicell_base
<n_option
>::facets(ostream
&os
) {
1765 for(j
=0;j
<nu
[i
];j
++) {
1768 neighbor
.print(os
,i
,j
);
1770 l
=cycle_up(ed
[i
][nu
[i
]+j
],k
);
1773 neighbor
.print(os
,k
,l
);
1776 l
=cycle_up(ed
[k
][nu
[k
]+l
],m
);
1784 for(j
=0;j
<nu
[i
];j
++) {
1785 if(ed
[i
][j
]>=0) throw fatal_error("Facet evaluation routine didn't look everywhere");
1786 ed
[i
][j
]=-1-ed
[i
][j
];
1791 /** Returns the number of faces of a computed Voronoi cell.
1792 * \return The number of faces. */
1793 template<class n_option
>
1794 int voronoicell_base
<n_option
>::number_of_faces() {
1797 for(j
=0;j
<nu
[i
];j
++) {
1802 l
=cycle_up(ed
[i
][nu
[i
]+j
],k
);
1806 l
=cycle_up(ed
[k
][nu
[k
]+l
],m
);
1813 for(j
=0;j
<nu
[i
];j
++) {
1814 if(ed
[i
][j
]>=0) throw fatal_error("Face evaluation routine didn't look everywhere");
1815 ed
[i
][j
]=-1-ed
[i
][j
];
1821 /** This routine is a placeholder which just prints the ID of a
1823 * \param[in] &os The output stream to write to.
1824 * \param[in] i The ID of a vertex.
1825 * \param[in] j The particular plane of interest (ignored in this routine). */
1826 void neighbor_none::print(ostream
&os
,int i
,int j
) {
1830 /** An overloaded version of facets() which output the results to the standard
1832 template<class n_option
>
1833 inline void voronoicell_base
<n_option
>::facets() {
1837 /** An overloaded version of facets(), which outputs the results to a file.
1838 * \param[in] filename The name of the file to write to. */
1839 template<class n_option
>
1840 inline void voronoicell_base
<n_option
>::facets(const char *filename
) {
1842 os
.open(filename
,ofstream::out
|ofstream::trunc
);
1847 /** Examines all the facets, and evaluates them by the number of vertices that
1849 * \param[in] &os An open output stream to write to. */
1850 template<class n_option
>
1851 void voronoicell_base
<n_option
>::facet_statistics(ostream
&os
) {
1852 int *stat
,*pstat
,current_facet_size
=init_facet_size
,newc
,maxf
=0;
1853 stat
=new int[current_facet_size
];
1855 for(i
=0;i
<current_facet_size
;i
++) stat
[i
]=0;
1857 for(j
=0;j
<nu
[i
];j
++) {
1862 l
=cycle_up(ed
[i
][nu
[i
]+j
],k
);
1867 l
=cycle_up(ed
[k
][nu
[k
]+l
],m
);
1870 if (q
>=current_facet_size
) {
1871 newc
=current_facet_size
*2;
1872 pstat
=new int[newc
];
1873 for(k
=0;k
<current_facet_size
;k
++) pstat
[k
]=stat
[k
];
1874 while(k
<newc
) pstat
[k
]=0;
1876 current_facet_size
=newc
;
1885 for(j
=0;j
<nu
[i
];j
++) {
1886 if(ed
[i
][j
]>=0) throw fatal_error("Facet statistics routine didn't look everywhere");
1887 ed
[i
][j
]=-1-ed
[i
][j
];
1890 for(i
=0;i
<=maxf
;i
++) os
<< i
<< " " << stat
[i
] << endl
;
1894 /** An overloaded version of facet_statistics() which outputs the results to
1895 * standard output. */
1896 template<class n_option
>
1897 inline void voronoicell_base
<n_option
>::facet_statistics() {
1898 facet_statistics(cout
);
1901 /** An overloaded version of facet_statistics() which outputs the results to
1903 * \param[in] filename The name of the file to write to. */
1904 template<class n_option
>
1905 inline void voronoicell_base
<n_option
>::facet_statistics(const char *filename
) {
1907 os
.open(filename
,ofstream::out
|ofstream::trunc
);
1908 facet_statistics(os
);
1912 /** If the template is instantiated with the neighbor tracking turned on,
1913 * then this routine will label all the facets of the current cell. Otherwise
1914 * this routine does nothing. */
1915 template<class n_option
>
1916 void voronoicell_base
<n_option
>::label_facets() {
1917 neighbor
.label_facets();
1920 /** If the template is instantiated with the neighbor tracking turned on, then
1921 * this routine will print out a list of all the neighbors of a given cell.
1922 * Otherwise, this routine does nothing.
1923 * \param[in] &os An open output stream to write to. */
1924 template<class n_option
>
1925 void voronoicell_base
<n_option
>::neighbors(ostream
&os
) {
1926 neighbor
.neighbors(os
);
1929 /** If the template is instantiated with the neighbor tracking turned on, then
1930 * this routine will check that the neighbor information is consistent, by
1931 * tracing around every facet, and ensuring that all the neighbor information
1932 * for that facet refers to the same neighbor. If the neighbor tracking isn't
1933 * turned on, this routine does nothing. */
1934 template<class n_option
>
1935 void voronoicell_base
<n_option
>::check_facets() {
1936 neighbor
.check_facets();
1939 /** This routine tests to see whether the cell intersects a plane by starting
1940 * from the guess point up. If up intersects, then it immediately returns true.
1941 * Otherwise, it calls the plane_intersects_track() routine.
1942 * \param[in] (x,y,z) The normal vector to the plane.
1943 * \param[in] rsq The distance along this vector of the plane.
1944 * \return false if the plane does not intersect the plane, true if it does.*/
1945 template<class n_option
>
1946 bool voronoicell_base
<n_option
>::plane_intersects(fpoint x
,fpoint y
,fpoint z
,fpoint rsq
) {
1947 fpoint g
=x
*pts
[3*up
]+y
*pts
[3*up
+1]+z
*pts
[3*up
+2];
1948 if (g
<rsq
) return plane_intersects_track(x
,y
,z
,rsq
,g
);
1952 /** This routine tests to see if a cell intersects a plane. It first tests a
1953 * random sample of approximately sqrt(p)/4 points. If any of those are
1954 * intersect, then it immediately returns true. Otherwise, it takes the closest
1955 * point and passes that to plane_intersect_track() routine.
1956 * \param[in] (x,y,z) The normal vector to the plane.
1957 * \param[in] rsq The distance along this vector of the plane.
1958 * \return false if the plane does not intersect the plane, true if it does.*/
1959 template<class n_option
>
1960 bool voronoicell_base
<n_option
>::plane_intersects_guess(fpoint x
,fpoint y
,fpoint z
,fpoint rsq
) {
1962 fpoint g
=x
*pts
[3*up
]+y
*pts
[3*up
+1]+z
*pts
[3*up
+2];
1964 int ca
=1,cc
=p
>>3,mp
=1;
1967 m
=x
*pts
[3*mp
]+y
*pts
[3*mp
+1]+z
*pts
[3*mp
+2];
1969 if (m
>rsq
) return true;
1974 return plane_intersects_track(x
,y
,z
,rsq
,g
);
1979 /* This routine tests to see if a cell intersects a plane, by tracing over the cell from
1980 * vertex to vertex, starting at up. It is meant to be called either by plane_intersects()
1981 * or plane_intersects_track(), when those routines cannot immediately resolve the case.
1982 * \param[in] (x,y,z) The normal vector to the plane.
1983 * \param[in] rsq The distance along this vector of the plane.
1984 * \param[in] g The distance of up from the plane.
1985 * \return false if the plane does not intersect the plane, true if it does.*/
1986 template<class n_option
>
1987 inline bool voronoicell_base
<n_option
>::plane_intersects_track(fpoint x
,fpoint y
,fpoint z
,fpoint rsq
,fpoint g
) {
1988 int count
=0,ls
,us
,tp
;
1990 // The test point is outside of the cutting space
1991 for(us
=0;us
<nu
[up
];us
++) {
1993 t
=x
*pts
[3*tp
]+y
*pts
[3*tp
+1]+z
*pts
[3*tp
+2];
1995 ls
=ed
[up
][nu
[up
]+us
];
1999 #if VOROPP_VERBOSE >=1
2000 cerr
<< "Bailed out of convex calculation" << endl
;
2002 for(tp
=0;tp
<p
;tp
++) if (x
*pts
[3*tp
]+y
*pts
[3*tp
+1]+z
*pts
[3*tp
+2]>rsq
) return true;
2006 // Test all the neighbors of the current point
2007 // and find the one which is closest to the
2009 for(us
=0;us
<ls
;us
++) {
2011 g
=x
*pts
[3*tp
]+y
*pts
[3*tp
+1]+z
*pts
[3*tp
+2];
2018 g
=x
*pts
[3*tp
]+y
*pts
[3*tp
+1]+z
*pts
[3*tp
+2];
2022 if (us
==nu
[up
]) return false;
2024 ls
=ed
[up
][nu
[up
]+us
];up
=tp
;t
=g
;
2032 /** This constructs the neighbor_track class, within a current
2033 * voronoicell_neighbor class. It allocates memory for neighbor storage in a
2034 * similar way to the voronoicell constructor. */
2035 neighbor_track::neighbor_track(voronoicell_base
<neighbor_track
> *ivc
) : vc(ivc
) {
2037 mne
=new int*[vc
->current_vertex_order
];
2038 ne
=new int*[vc
->current_vertices
];
2039 for(i
=0;i
<3;i
++) mne
[i
]=new int[init_n_vertices
*i
];
2040 mne
[3]=new int[init_3_vertices
*3];
2041 for(i
=4;i
<vc
->current_vertex_order
;i
++) mne
[i
]=new int[init_n_vertices
*i
];
2044 /** The destructor for the neighbor_track class deallocates the arrays
2045 * for neighbor tracking. */
2046 neighbor_track::~neighbor_track() {
2047 for(int i
=0;i
<vc
->current_vertex_order
;i
++) if (vc
->mem
[i
]>0) delete [] mne
[i
];
2052 /** This allocates a single array for neighbor tracking.
2053 * \param[in] i the vertex order of the array to be extended.
2054 * \param[in] m the size of the array to be extended. */
2055 inline void neighbor_track::allocate(int i
,int m
) {
2056 mne
[i
]=new int[m
*i
];
2059 /** This increases the size of the ne[] array.
2060 * \param[in] i the new size of the array. */
2061 inline void neighbor_track::add_memory_vertices(int i
) {
2064 for(int j
=0;j
<vc
->current_vertices
;j
++) pp
[j
]=ne
[j
];
2068 /** This increases the size of the maximum allowable vertex
2069 * order in the neighbor tracking. */
2070 inline void neighbor_track::add_memory_vorder(int i
) {
2073 for(int j
=0;j
<vc
->current_vertex_order
;j
++) p2
[j
]=mne
[j
];
2074 delete [] mne
;mne
=p2
;
2077 /** This initializes the neighbor information for a rectangular box
2078 * and is called during the initialization routine for the voronoicell
2080 inline void neighbor_track::init() {
2083 q
[0]=-5;q
[1]=-3;q
[2]=-1;
2084 q
[3]=-5;q
[4]=-2;q
[5]=-3;
2085 q
[6]=-5;q
[7]=-1;q
[8]=-4;
2086 q
[9]=-5;q
[10]=-4;q
[11]=-2;
2087 q
[12]=-6;q
[13]=-1;q
[14]=-3;
2088 q
[15]=-6;q
[16]=-3;q
[17]=-2;
2089 q
[18]=-6;q
[19]=-4;q
[20]=-1;
2090 q
[21]=-6;q
[22]=-2;q
[23]=-4;
2091 ne
[0]=q
;ne
[1]=q
+3;ne
[2]=q
+6;ne
[3]=q
+9;
2092 ne
[4]=q
+12;ne
[5]=q
+15;ne
[6]=q
+18;ne
[7]=q
+21;
2095 /** This initializes the neighbor information for an octahedron. The eight
2096 * initial faces are assigned ID numbers from -1 to -8. */
2097 inline void neighbor_track::init_octahedron() {
2100 q
[0]=-5;q
[1]=-6;q
[2]=-7;q
[3]=-8;
2101 q
[4]=-1;q
[5]=-2;q
[6]=-3;q
[7]=-4;
2102 q
[8]=-6;q
[9]=-5;q
[10]=-2;q
[11]=-1;
2103 q
[12]=-8;q
[13]=-7;q
[14]=-4;q
[15]=-3;
2104 q
[16]=-5;q
[17]=-8;q
[18]=-3;q
[19]=-2;
2105 q
[20]=-7;q
[21]=-6;q
[22]=-1;q
[23]=-4;
2106 ne
[0]=q
;ne
[1]=q
+4;ne
[2]=q
+8;ne
[3]=q
+12;ne
[4]=q
+16;ne
[5]=q
+20;
2109 /** This initializes the neighbor information for an tetrahedron. The four
2110 * initial faces are assigned ID numbers from -1 to -4.*/
2111 inline void neighbor_track::init_tetrahedron() {
2114 q
[0]=-4;q
[1]=-3;q
[2]=-2;
2115 q
[3]=-3;q
[4]=-4;q
[5]=-1;
2116 q
[6]=-4;q
[7]=-2;q
[8]=-1;
2117 q
[9]=-2;q
[10]=-3;q
[11]=-1;
2118 ne
[0]=q
;ne
[1]=q
+3;ne
[2]=q
+6;ne
[3]=q
+9;
2121 /** This is a basic operation to set a new pointer in the ne[] array.
2122 * \param[in] p the index in the ne[] array to set.
2123 * \param[in] n the order of the vertex. */
2124 inline void neighbor_track::set_pointer(int p
,int n
) {
2125 ne
[p
]=mne
[n
]+n
*vc
->mec
[n
];
2128 /** This is a basic operation to copy ne[c][d] to ne[a][b]. */
2129 inline void neighbor_track::copy(int a
,int b
,int c
,int d
) {
2133 /** This is a basic operation to carry out ne[a][b]=c. */
2134 inline void neighbor_track::set(int a
,int b
,int c
) {
2138 /** This is a basic operation to set the auxiliary pointer
2140 * \param[in] k the order of the vertex to point to. */
2141 inline void neighbor_track::set_aux1(int k
) {
2142 paux1
=mne
[k
]+k
*vc
->mec
[k
];
2145 /** This is a basic operation to copy a neighbor into paux1.*/
2146 inline void neighbor_track::copy_aux1(int a
,int b
) {
2150 /** This is a basic operation to copy a neighbor into paux1 with a shift. It is
2151 * used in the delete_connection() routine of the voronoicell class. */
2152 inline void neighbor_track::copy_aux1_shift(int a
,int b
) {
2153 paux1
[b
]=ne
[a
][b
+1];
2156 /** This routine sets the second auxiliary pointer to a new section
2157 * of memory, and then copies existing neighbor information into it. */
2158 inline void neighbor_track::set_aux2_copy(int a
,int b
) {
2159 paux2
=mne
[b
]+b
*vc
->mec
[b
];
2160 for(int i
=0;i
<b
;i
++) ne
[a
][i
]=paux2
[i
];
2163 /** This is a basic routine to copy ne[b] into ne[a]. */
2164 inline void neighbor_track::copy_pointer(int a
,int b
) {
2168 /** This sets ne[j] to the first auxiliary pointer. */
2169 inline void neighbor_track::set_to_aux1(int j
) {
2173 /** This sets ne[j] to the second auxiliary pointer. */
2174 inline void neighbor_track::set_to_aux2(int j
) {
2178 /** This prints out the neighbor information for vertex i. */
2179 inline void neighbor_track::print_edges(int i
) {
2181 for(int j
=0;j
<vc
->nu
[i
];j
++) {
2182 cout
<< ne
[i
][j
] << (j
==vc
->nu
[i
]-1?")":",");
2186 /** This allocates a new array and sets the auxiliary pointer
2188 inline void neighbor_track::allocate_aux1(int i
) {
2189 paux1
=new int[i
*vc
->mem
[i
]];
2192 /** This deletes a particular neighbor array and switches the
2193 * pointer to the auxiliary pointer. */
2194 inline void neighbor_track::switch_to_aux1(int i
) {
2199 /** This routine copies neighbor information into the
2200 * auxiliary pointer. */
2201 inline void neighbor_track::copy_to_aux1(int i
,int m
) {
2205 /** This sets ne[k] to the auxiliary pointer with an offset. */
2206 inline void neighbor_track::set_to_aux1_offset(int k
,int m
) {
2210 /** This routine checks to make sure the neighbor information of each facets is
2212 void neighbor_track::check_facets() {
2213 int **edp
,*nup
;edp
=vc
->ed
;nup
=vc
->nu
;
2215 for(i
=0;i
<vc
->p
;i
++) {
2216 for(j
=0;j
<nup
[i
];j
++) {
2221 l
=vc
->cycle_up(edp
[i
][nup
[i
]+j
],k
);
2225 if (ne
[k
][l
]!=q
) cerr
<< "Facet error at (" << k
<< "," << l
<< ")=" << ne
[k
][l
] << ", started from (" << i
<< "," << j
<< ")=" << q
<< endl
;
2226 l
=vc
->cycle_up(edp
[k
][nup
[k
]+l
],m
);
2232 for(i
=0;i
<vc
->p
;i
++) {
2233 for(j
=0;j
<nup
[i
];j
++) {
2234 if(edp
[i
][j
]>=0) throw fatal_error("Facet labeling routine didn't look everywhere");
2235 edp
[i
][j
]=-1-edp
[i
][j
];
2240 /** This routine provides a list of plane IDs.
2241 * \param[in] &os An output stream to write to. */
2242 void neighbor_track::neighbors(ostream
&os
) {
2243 int **edp
,*nup
;edp
=vc
->ed
;nup
=vc
->nu
;
2245 for(i
=0;i
<vc
->p
;i
++) {
2246 for(j
=0;j
<nup
[i
];j
++) {
2249 os
<< " " << ne
[i
][j
];
2251 l
=vc
->cycle_up(edp
[i
][nup
[i
]+j
],k
);
2255 l
=vc
->cycle_up(edp
[k
][nup
[k
]+l
],m
);
2261 for(i
=0;i
<vc
->p
;i
++) {
2262 for(j
=0;j
<nup
[i
];j
++) {
2263 if(edp
[i
][j
]>=0) throw fatal_error("Neighbor routine didn't look everywhere");
2264 edp
[i
][j
]=-1-edp
[i
][j
];
2269 /** This routine labels the facets in an arbitrary order, starting from one. */
2270 void neighbor_track::label_facets() {
2271 int **edp
,*nup
;edp
=vc
->ed
;nup
=vc
->nu
;
2273 for(i
=0;i
<vc
->p
;i
++) {
2274 for(j
=0;j
<nup
[i
];j
++) {
2279 l
=vc
->cycle_up(edp
[i
][nup
[i
]+j
],k
);
2284 l
=vc
->cycle_up(edp
[k
][nup
[k
]+l
],m
);
2291 for(i
=0;i
<vc
->p
;i
++) {
2292 for(j
=0;j
<nup
[i
];j
++) {
2293 if(edp
[i
][j
]>=0) throw fatal_error("Facet labeling routine didn't look everywhere");
2294 edp
[i
][j
]=-1-edp
[i
][j
];
2299 /** This routine prints out a bracketed pair showing a vertex number, and the
2300 * corresponding neighbor information.
2301 * \param[in] &os The output stream to write to.
2302 * \param[in] i The vertex number to print.
2303 * \param[in] j The index of the neighbor information to print. */
2304 void neighbor_track::print(ostream
&os
,int i
,int j
) {
2305 os
<< "(" << i
<< "," << ne
[i
][j
] << ")";