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 double[3*current_vertices
]), ptsq(new mpq_class
[3*current_vertices
]),
25 synced(false), mem(new int[current_vertex_order
]),
26 mec(new int[current_vertex_order
]), mep(new int*[current_vertex_order
]),
27 ds(new int[current_delete_size
]), stacke(ds
+current_delete_size
),
28 ds2(new int[current_delete2_size
]), stacke2(ds2
+current_delete_size
),
29 current_marginal(init_marginal
), marg(new int[current_marginal
]) {
32 mem
[i
]=init_n_vertices
;mec
[i
]=0;
33 mep
[i
]=new int[init_n_vertices
*((i
<<1)+1)];
35 mem
[3]=init_3_vertices
;mec
[3]=0;
36 mep
[3]=new int[init_3_vertices
*7];
37 for(i
=4;i
<current_vertex_order
;i
++) {
38 mem
[i
]=init_n_vertices
;mec
[i
]=0;
39 mep
[i
]=new int[init_n_vertices
*((i
<<1)+1)];
43 /** The voronoicell destructor deallocates all the dynamic memory. */
44 voronoicell_base::~voronoicell_base() {
45 for(int i
=current_vertex_order
-1;i
>=0;i
--) if(mem
[i
]>0) delete [] mep
[i
];
47 delete [] ds2
;delete [] ds
;
48 delete [] mep
;delete [] mec
;
49 delete [] mem
;delete [] ptsq
;delete [] pts
;
50 delete [] nu
;delete [] ed
;
53 /** Ensures that enough memory is allocated prior to carrying out a copy.
54 * \param[in] vc a reference to the specialized version of the calling class.
55 * \param[in] vb a pointered to the class to be copied. */
56 template<class vc_class
>
57 void voronoicell_base::check_memory_for_copy(vc_class
&vc
,voronoicell_base
* vb
) {
58 while(current_vertex_order
<vb
->current_vertex_order
) add_memory_vorder(vc
);
59 for(int i
=0;i
<current_vertex_order
;i
++) while(mem
[i
]<vb
->mec
[i
]) add_memory(vc
,i
,ds2
);
60 while(current_vertices
<vb
->p
) add_memory_vertices(vc
);
63 /** Copies the vertex and edge information from another class. The routine
64 * assumes that enough memory is available for the copy.
65 * \param[in] vb a pointer to the class to copy. */
66 void voronoicell_base::copy(voronoicell_base
* vb
) {
69 for(i
=0;i
<current_vertex_order
;i
++) {
71 for(j
=0;j
<mec
[i
]*(2*i
+1);j
++) mep
[i
][j
]=vb
->mep
[i
][j
];
72 for(j
=0;j
<mec
[i
]*(2*i
+1);j
+=2*i
+1) ed
[mep
[i
][j
+2*i
]]=mep
[i
]+j
;
74 for(i
=0;i
<p
;i
++) nu
[i
]=vb
->nu
[i
];
75 for(i
=0;i
<3*p
;i
++) ptsq
[i
]=vb
->ptsq
[i
];
79 /** Copies the information from another voronoicell class into this
80 * class, extending memory allocation if necessary.
81 * \param[in] c the class to copy. */
82 void voronoicell_neighbor::operator=(voronoicell
&c
) {
83 voronoicell_base
*vb
=((voronoicell_base
*) &c
);
84 check_memory_for_copy(*this,vb
);copy(vb
);
86 for(i
=0;i
<c
.current_vertex_order
;i
++) {
87 for(j
=0;j
<c
.mec
[i
]*i
;j
++) mne
[i
][j
]=0;
88 for(j
=0;j
<c
.mec
[i
];j
++) ne
[c
.mep
[i
][(2*i
+1)*j
+2*i
]]=mne
[i
]+(j
*i
);
92 /** Copies the information from another voronoicell_neighbor class into this
93 * class, extending memory allocation if necessary.
94 * \param[in] c the class to copy. */
95 void voronoicell_neighbor::operator=(voronoicell_neighbor
&c
) {
96 voronoicell_base
*vb
=((voronoicell_base
*) &c
);
97 check_memory_for_copy(*this,vb
);copy(vb
);
99 for(i
=0;i
<c
.current_vertex_order
;i
++) {
100 for(j
=0;j
<c
.mec
[i
]*i
;j
++) mne
[i
][j
]=c
.mne
[i
][j
];
101 for(j
=0;j
<c
.mec
[i
];j
++) ne
[c
.mep
[i
][(2*i
+1)*j
+2*i
]]=mne
[i
]+(j
*i
);
105 /** Translates the vertices of the Voronoi cell by a given vector.
106 * \param[in] (x,y,z) the coordinates of the vector. */
107 void voronoicell_base::translate(double x
,double y
,double z
) {
111 while(ptsp
<pts
+3*p
) {
112 *(ptsp
++)=x
;*(ptsp
++)=y
;*(ptsp
++)=z
;
116 /** Increases the memory storage for a particular vertex order, by increasing
117 * the size of the of the corresponding mep array. If the arrays already exist,
118 * their size is doubled; if they don't exist, then new ones of size
119 * init_n_vertices are allocated. The routine also ensures that the pointers in
120 * the ed array are updated, by making use of the back pointers. For the cases
121 * where the back pointer has been temporarily overwritten in the marginal
122 * vertex code, the auxiliary delete stack is scanned to find out how to update
123 * the ed value. If the template has been instantiated with the neighbor
124 * tracking turned on, then the routine also reallocates the corresponding mne
126 * \param[in] i the order of the vertex memory to be increased. */
127 template<class vc_class
>
128 void voronoicell_base::add_memory(vc_class
&vc
,int i
,int *stackp2
) {
131 vc
.n_allocate(i
,init_n_vertices
);
132 mep
[i
]=new int[init_n_vertices
*s
];
133 mem
[i
]=init_n_vertices
;
134 #if VOROPP_VERBOSE >=2
135 fprintf(stderr
,"Order %d vertex memory created\n",i
);
140 if(mem
[i
]>max_n_vertices
) voro_fatal_error("Point memory allocation exceeded absolute maximum",VOROPP_MEMORY_ERROR
);
141 #if VOROPP_VERBOSE >=2
142 fprintf(stderr
,"Order %d vertex memory scaled up to %d\n",i
,mem
[i
]);
146 vc
.n_allocate_aux1(i
);
151 vc
.n_set_to_aux1_offset(k
,m
);
154 for(dsp
=ds2
;dsp
<stackp2
;dsp
++) {
155 if(ed
[*dsp
]==mep
[i
]+j
) {
157 vc
.n_set_to_aux1_offset(*dsp
,m
);
161 if(dsp
==stackp2
) voro_fatal_error("Couldn't relocate dangling pointer",VOROPP_INTERNAL_ERROR
);
162 #if VOROPP_VERBOSE >=3
163 fputs("Relocated dangling pointer",stderr
);
166 for(k
=0;k
<s
;k
++,j
++) l
[j
]=mep
[i
][j
];
167 for(k
=0;k
<i
;k
++,m
++) vc
.n_copy_to_aux1(i
,m
);
171 vc
.n_switch_to_aux1(i
);
175 /** Doubles the maximum number of vertices allowed, by reallocating the ed, nu,
176 * and pts arrays. If the allocation exceeds the absolute maximum set in
177 * max_vertices, then the routine exits with a fatal error. If the template has
178 * been instantiated with the neighbor tracking turned on, then the routine
179 * also reallocates the ne array. */
180 template<class vc_class
>
181 void voronoicell_base::add_memory_vertices(vc_class
&vc
) {
182 int i
=(current_vertices
<<1),j
,**pp
,*pnu
;
183 if(i
>max_vertices
) voro_fatal_error("Vertex memory allocation exceeded absolute maximum",VOROPP_MEMORY_ERROR
);
184 #if VOROPP_VERBOSE >=2
185 fprintf(stderr
,"Vertex memory scaled up to %d\n",i
);
188 for(j
=0;j
<current_vertices
;j
++) pp
[j
]=ed
[j
];
190 vc
.n_add_memory_vertices(i
);
192 for(j
=0;j
<current_vertices
;j
++) pnu
[j
]=nu
[j
];
194 mpq_class
*pptsq
=new mpq_class
[3*i
];
195 for(j
=0;j
<3*current_vertices
;j
++) pptsq
[j
]=ptsq
[j
];
196 delete [] ptsq
;ptsq
=pptsq
;
197 double *ppts
=new double[3*i
];
198 for(j
=0;j
<3*current_vertices
;j
++) ppts
[j
]=pts
[j
];
199 delete [] pts
;pts
=ppts
;
203 /** Doubles the maximum allowed vertex order, by reallocating mem, mep, and mec
204 * arrays. If the allocation exceeds the absolute maximum set in
205 * max_vertex_order, then the routine causes a fatal error. If the template has
206 * been instantiated with the neighbor tracking turned on, then the routine
207 * also reallocates the mne array. */
208 template<class vc_class
>
209 void voronoicell_base::add_memory_vorder(vc_class
&vc
) {
210 int i
=(current_vertex_order
<<1),j
,*p1
,**p2
;
211 if(i
>max_vertex_order
) voro_fatal_error("Vertex order memory allocation exceeded absolute maximum",VOROPP_MEMORY_ERROR
);
212 #if VOROPP_VERBOSE >=2
213 fprintf(stderr
,"Vertex order memory scaled up to %d\n",i
);
216 for(j
=0;j
<current_vertex_order
;j
++) p1
[j
]=mem
[j
];while(j
<i
) p1
[j
++]=0;
217 delete [] mem
;mem
=p1
;
219 for(j
=0;j
<current_vertex_order
;j
++) p2
[j
]=mep
[j
];
220 delete [] mep
;mep
=p2
;
222 for(j
=0;j
<current_vertex_order
;j
++) p1
[j
]=mec
[j
];while(j
<i
) p1
[j
++]=0;
223 delete [] mec
;mec
=p1
;
224 vc
.n_add_memory_vorder(i
);
225 current_vertex_order
=i
;
228 /** Doubles the size allocation of the main delete stack. If the allocation
229 * exceeds the absolute maximum set in max_delete_size, then routine causes a
231 void voronoicell_base::add_memory_ds(int *&stackp
) {
232 current_delete_size
<<=1;
233 if(current_delete_size
>max_delete_size
) voro_fatal_error("Delete stack 1 memory allocation exceeded absolute maximum",VOROPP_MEMORY_ERROR
);
234 #if VOROPP_VERBOSE >=2
235 fprintf(stderr
,"Delete stack 1 memory scaled up to %d\n",current_delete_size
);
237 int *dsn
=new int[current_delete_size
],*dsnp
=dsn
,*dsp
=ds
;
238 while(dsp
<stackp
) *(dsnp
++)=*(dsp
++);
239 delete [] ds
;ds
=dsn
;stackp
=dsnp
;
240 stacke
=ds
+current_delete_size
;
243 /** Doubles the size allocation of the auxiliary delete stack. If the
244 * allocation exceeds the absolute maximum set in max_delete2_size, then the
245 * routine causes a fatal error. */
246 void voronoicell_base::add_memory_ds2(int *&stackp2
) {
247 current_delete2_size
<<=1;
248 if(current_delete2_size
>max_delete2_size
) voro_fatal_error("Delete stack 2 memory allocation exceeded absolute maximum",VOROPP_MEMORY_ERROR
);
249 #if VOROPP_VERBOSE >=2
250 fprintf(stderr
,"Delete stack 2 memory scaled up to %d\n",current_delete2_size
);
252 int *dsn
=new int[current_delete2_size
],*dsnp
=dsn
,*dsp
=ds2
;
253 while(dsp
<stackp2
) *(dsnp
++)=*(dsp
++);
254 delete [] ds2
;ds2
=dsn
;stackp2
=dsnp
;
255 stacke2
=ds2
+current_delete2_size
;
258 /** Initializes a Voronoi cell as a rectangular box with the given dimensions.
259 * \param[in] (xmin,xmax) the minimum and maximum x coordinates.
260 * \param[in] (ymin,ymax) the minimum and maximum y coordinates.
261 * \param[in] (zmin,zmax) the minimum and maximum z coordinates. */
262 void voronoicell_base::init_base(double xmin
,double xmax
,double ymin
,double ymax
,double zmin
,double zmax
) {
263 for(int i
=0;i
<current_vertex_order
;i
++) mec
[i
]=0;up
=0;
264 mec
[3]=p
=8;xmin
*=2;xmax
*=2;ymin
*=2;ymax
*=2;zmin
*=2;zmax
*=2;
265 *ptsq
=xmin
;ptsq
[1]=ymin
;ptsq
[2]=zmin
;
266 ptsq
[3]=xmax
;ptsq
[4]=ymin
;ptsq
[5]=zmin
;
267 ptsq
[6]=xmin
;ptsq
[7]=ymax
;ptsq
[8]=zmin
;
268 ptsq
[9]=xmax
;ptsq
[10]=ymax
;ptsq
[11]=zmin
;
269 ptsq
[12]=xmin
;ptsq
[13]=ymin
;ptsq
[14]=zmax
;
270 ptsq
[15]=xmax
;ptsq
[16]=ymin
;ptsq
[17]=zmax
;
271 ptsq
[18]=xmin
;ptsq
[19]=ymax
;ptsq
[20]=zmax
;
272 ptsq
[21]=xmax
;ptsq
[22]=ymax
;ptsq
[23]=zmax
;
274 *q
=1;q
[1]=4;q
[2]=2;q
[3]=2;q
[4]=1;q
[5]=0;q
[6]=0;
275 q
[7]=3;q
[8]=5;q
[9]=0;q
[10]=2;q
[11]=1;q
[12]=0;q
[13]=1;
276 q
[14]=0;q
[15]=6;q
[16]=3;q
[17]=2;q
[18]=1;q
[19]=0;q
[20]=2;
277 q
[21]=2;q
[22]=7;q
[23]=1;q
[24]=2;q
[25]=1;q
[26]=0;q
[27]=3;
278 q
[28]=6;q
[29]=0;q
[30]=5;q
[31]=2;q
[32]=1;q
[33]=0;q
[34]=4;
279 q
[35]=4;q
[36]=1;q
[37]=7;q
[38]=2;q
[39]=1;q
[40]=0;q
[41]=5;
280 q
[42]=7;q
[43]=2;q
[44]=4;q
[45]=2;q
[46]=1;q
[47]=0;q
[48]=6;
281 q
[49]=5;q
[50]=3;q
[51]=6;q
[52]=2;q
[53]=1;q
[54]=0;q
[55]=7;
282 *ed
=q
;ed
[1]=q
+7;ed
[2]=q
+14;ed
[3]=q
+21;
283 ed
[4]=q
+28;ed
[5]=q
+35;ed
[6]=q
+42;ed
[7]=q
+49;
284 *nu
=nu
[1]=nu
[2]=nu
[3]=nu
[4]=nu
[5]=nu
[6]=nu
[7]=3;
288 /** Initializes a Voronoi cell as a regular octahedron.
289 * \param[in] l The distance from the octahedron center to a vertex. Six
290 * vertices are initialized at (-l,0,0), (l,0,0), (0,-l,0),
291 * (0,l,0), (0,0,-l), and (0,0,l). */
292 void voronoicell_base::init_octahedron_base(double l
) {
293 for(int i
=0;i
<current_vertex_order
;i
++) mec
[i
]=0;up
=0;
295 *ptsq
=-l
;ptsq
[1]=0;ptsq
[2]=0;
296 ptsq
[3]=l
;ptsq
[4]=0;ptsq
[5]=0;
297 ptsq
[6]=0;ptsq
[7]=-l
;ptsq
[8]=0;
298 ptsq
[9]=0;ptsq
[10]=l
;ptsq
[11]=0;
299 ptsq
[12]=0;ptsq
[13]=0;ptsq
[14]=-l
;
300 ptsq
[15]=0;ptsq
[16]=0;ptsq
[17]=l
;
302 *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;
303 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;
304 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;
305 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;
306 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;
307 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;
308 *ed
=q
;ed
[1]=q
+9;ed
[2]=q
+18;ed
[3]=q
+27;ed
[4]=q
+36;ed
[5]=q
+45;
309 *nu
=nu
[1]=nu
[2]=nu
[3]=nu
[4]=nu
[5]=4;
313 /** Initializes a Voronoi cell as a tetrahedron. It assumes that the normal to
314 * the face for the first three vertices points inside.
315 * \param (x0,y0,z0) a position vector for the first vertex.
316 * \param (x1,y1,z1) a position vector for the second vertex.
317 * \param (x2,y2,z2) a position vector for the third vertex.
318 * \param (x3,y3,z3) a position vector for the fourth vertex. */
319 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
) {
320 for(int i
=0;i
<current_vertex_order
;i
++) mec
[i
]=0;up
=0;
322 *ptsq
=x0
*2;ptsq
[1]=y0
*2;ptsq
[2]=z0
*2;
323 ptsq
[3]=x1
*2;ptsq
[4]=y1
*2;ptsq
[5]=z1
*2;
324 ptsq
[6]=x2
*2;ptsq
[7]=y2
*2;ptsq
[8]=z2
*2;
325 ptsq
[9]=x3
*2;ptsq
[10]=y3
*2;ptsq
[11]=z3
*2;
327 *q
=1;q
[1]=3;q
[2]=2;q
[3]=0;q
[4]=0;q
[5]=0;q
[6]=0;
328 q
[7]=0;q
[8]=2;q
[9]=3;q
[10]=0;q
[11]=2;q
[12]=1;q
[13]=1;
329 q
[14]=0;q
[15]=3;q
[16]=1;q
[17]=2;q
[18]=2;q
[19]=1;q
[20]=2;
330 q
[21]=0;q
[22]=1;q
[23]=2;q
[24]=1;q
[25]=2;q
[26]=1;q
[27]=3;
331 *ed
=q
;ed
[1]=q
+7;ed
[2]=q
+14;ed
[3]=q
+21;
332 *nu
=nu
[1]=nu
[2]=nu
[3]=3;
335 /** Checks that the relational table of the Voronoi cell is accurate, and
336 * prints out any errors. This algorithm is O(p), so running it every time the
337 * plane routine is called will result in a significant slowdown. */
338 void voronoicell_base::check_relations() {
340 for(i
=0;i
<p
;i
++) for(j
=0;j
<nu
[i
];j
++) if(ed
[ed
[i
][j
]][ed
[i
][nu
[i
]+j
]]!=i
)
341 printf("Relational error at point %d, edge %d.\n",i
,j
);
344 /** This routine checks for any two vertices that are connected by more than
345 * one edge. The plane algorithm is designed so that this should not happen, so
346 * any occurrences are most likely errors. Note that the routine is O(p), so
347 * running it every time the plane routine is called will result in a
348 * significant slowdown. */
349 void voronoicell_base::check_duplicates() {
351 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
])
352 printf("Duplicate edges: (%d,%d) and (%d,%d) [%d]\n",i
,j
,i
,k
,ed
[i
][j
]);
355 /** Constructs the relational table if the edges have been specified. */
356 void voronoicell_base::construct_relations() {
358 for(i
=0;i
<p
;i
++) for(j
=0;j
<nu
[i
];j
++) {
363 if(l
==nu
[k
]) voro_fatal_error("Relation table construction failed",VOROPP_INTERNAL_ERROR
);
369 /** Cuts the Voronoi cell by a particle whose center is at a separation of
370 * (x,y,z) from the cell center. The value of rsq should be initially set to
372 * \param[in] vc a reference to the specialized version of the calling class.
373 * \param[in] (x,y,z) the normal vector to the plane.
374 * \param[in] rsq the distance along this vector of the plane.
375 * \param[in] p_id the plane ID (for neighbor tracking only).
376 * \return False if the plane cut deleted the cell entirely, true otherwise. */
377 template<class vc_class
>
378 bool voronoicell_base::nplane(vc_class
&vc
,double x
,double y
,double z
,double rsq
,int p_id
) {
379 int count
=0,i
,j
,k
,lp
=up
,cp
,qp
,rp
,*stackp(ds
),*stackp2(ds2
),*dsp
;
380 int us
=0,ls
=0,qs
,iqs
,cs
,uw
,qw
,lw
;
382 mpq_class u
,l
,r
,q
;bool complicated_setup
=false,new_double_edge
=false,double_edge
=false;
384 // Initialize the safe testing routine
385 n_marg
=0;px
=x
;py
=y
;pz
=z
;prsq
=rsq
;
387 // Test approximately sqrt(n)/4 points for their proximity to the plane
388 // and keep the one which is closest
391 // Starting from an initial guess, we now move from vertex to vertex,
392 // to try and find an edge which intersects the cutting plane,
393 // or a vertex which is on the plane
397 // The test point is inside the cutting plane.
410 ls
=ed
[up
][nu
[up
]+us
];
412 if(++count
>=p
) throw true;
414 for(us
=0;us
<ls
;us
++) {
431 ls
=ed
[up
][nu
[up
]+us
];
434 // If the last point in the iteration is within the
435 // plane, we need to do the complicated setup
436 // routine. Otherwise, we use the regular iteration.
439 complicated_setup
=true;
440 } else complicated_setup
=false;
449 if(us
==nu
[up
]) return true;
452 qs
=ed
[up
][nu
[up
]+us
];
453 if(++count
>=p
) throw true;
455 for(us
=0;us
<qs
;us
++) {
468 if(us
==nu
[up
]) return true;
473 up
=qp
;us
=ed
[lp
][nu
[lp
]+ls
];u
=q
;
474 complicated_setup
=false;
477 complicated_setup
=true;
481 // Our original test point was on the plane, so we
482 // automatically head for the complicated setup
484 complicated_setup
=true;
488 // This routine is a fall-back, in case floating point errors
489 // cause the usual search routine to fail. In the fall-back
490 // routine, we just test every edge to find one straddling
492 #if VOROPP_VERBOSE >=1
493 fputs("Bailed out of convex calculation\n",stderr
);
496 for(qp
=0;qp
<p
;qp
++) {
500 // The point is inside the cutting space. Now
501 // see if we can find a neighbor which isn't.
502 for(us
=0;us
<nu
[qp
];us
++) {
512 complicated_setup
=true;
514 complicated_setup
=false;
516 ls
=ed
[up
][nu
[up
]+us
];
522 // The point is outside the cutting space. See
523 // if we can find a neighbor which isn't.
524 for(ls
=0;ls
<nu
[qp
];ls
++) {
534 complicated_setup
=true;
536 complicated_setup
=false;
538 us
=ed
[lp
][nu
[lp
]+ls
];
544 // The point is in the plane, so we just
545 // proceed with the complicated setup routine
547 complicated_setup
=true;
551 if(qp
==p
) return qw
==-1?true:false;
556 // We're about to add the first point of the new facet. In either
557 // routine, we have to add a point, so first check there's space for
559 if(p
==current_vertices
) add_memory_vertices(vc
);
561 if(complicated_setup
) {
563 // The search algorithm found a point which is on the cutting
564 // plane. We leave that point in place, and create a new one at
565 // the same location.
566 ptsq
[3*p
]=ptsq
[3*up
];
567 ptsq
[3*p
+1]=ptsq
[3*up
+1];
568 ptsq
[3*p
+2]=ptsq
[3*up
+2];
570 // Search for a collection of edges of the test vertex which
571 // are outside of the cutting space. Begin by testing the
578 // The first edge is either inside the cutting space,
579 // or lies within the cutting plane. Test the edges
580 // sequentially until we find one that is outside.
585 // If we reached the last edge with no luck
586 // then all of the vertices are inside
587 // or on the plane, so the cell is completely
589 if(i
==nu
[up
]) return false;
595 // We found an edge outside the cutting space. Keep
596 // moving through these edges until we find one that's
597 // inside or on the plane.
605 // Compute the number of edges for the new vertex. In
606 // general it will be the number of outside edges
607 // found, plus two. But we need to recognize the
608 // special case when all but one edge is outside, and
609 // the remaining one is on the plane. For that case we
610 // have to reduce the edge count by one to prevent
612 if(j
==nu
[up
]&&i
==1&&rp
==0) {
618 // Add memory for the new vertex if needed, and
620 while (nu
[p
]>=current_vertex_order
) add_memory_vorder(vc
);
621 if(mec
[nu
[p
]]==mem
[nu
[p
]]) add_memory(vc
,nu
[p
],stackp2
);
622 vc
.n_set_pointer(p
,nu
[p
]);
623 ed
[p
]=mep
[nu
[p
]]+((nu
[p
]<<1)+1)*mec
[nu
[p
]]++;
626 // Copy the edges of the original vertex into the new
627 // one. Delete the edges of the original vertex, and
628 // update the relational table.
644 // In this case, the zeroth edge is outside the cutting
645 // plane. Begin by searching backwards from the last
646 // edge until we find an edge which isn't outside.
653 // If i reaches zero, then we have a point in
654 // the plane all of whose edges are outside
655 // the cutting space, so we just exit
656 if(i
==0) return true;
661 // Now search forwards from zero
671 // Compute the number of edges for the new vertex. In
672 // general it will be the number of outside edges
673 // found, plus two. But we need to recognize the
674 // special case when all but one edge is outside, and
675 // the remaining one is on the plane. For that case we
676 // have to reduce the edge count by one to prevent
685 // Add memory to store the vertex if it doesn't exist
688 while(nu
[p
]>=current_vertex_order
) add_memory_vorder(vc
);
689 if(mec
[nu
[p
]]==mem
[nu
[p
]]) add_memory(vc
,nu
[p
],stackp2
);
691 // Copy the edges of the original vertex into the new
692 // one. Delete the edges of the original vertex, and
693 // update the relational table.
694 vc
.n_set_pointer(p
,nu
[p
]);
695 ed
[p
]=mep
[nu
[p
]]+((nu
[p
]<<1)+1)*mec
[nu
[p
]]++;
724 vc
.n_copy(p
,k
,up
,qs
);
726 } else vc
.n_copy(p
,0,up
,qs
);
728 // Add this point to the auxiliary delete stack
729 if(stackp2
==stacke2
) add_memory_ds2(stackp2
);
732 // Look at the edges on either side of the group that was
733 // detected. We're going to commence facet computation by
734 // moving along one of them. We are going to end up coming back
735 // along the other one.
739 us
=ed
[up
][nu
[up
]+us
];
741 ed
[qp
][nu
[qp
]<<1]=-p
;
745 // The search algorithm found an intersected edge between the
746 // points lp and up. Create a new vertex between them which
747 // lies on the cutting plane. Since u and l differ by at least
748 // the tolerance, this division should never screw up.
749 if(stackp
==stacke
) add_memory_ds(stackp
);
752 ptsq
[3*p
]=ptsq
[3*lp
]*r
+ptsq
[3*up
]*l
;
753 ptsq
[3*p
+1]=ptsq
[3*lp
+1]*r
+ptsq
[3*up
+1]*l
;
754 ptsq
[3*p
+2]=ptsq
[3*lp
+2]*r
+ptsq
[3*up
+2]*l
;
756 // This point will always have three edges. Connect one of them
759 if(mec
[3]==mem
[3]) add_memory(vc
,3,stackp2
);
760 vc
.n_set_pointer(p
,3);
762 vc
.n_copy(p
,1,up
,us
);
763 vc
.n_copy(p
,2,lp
,ls
);
764 ed
[p
]=mep
[3]+7*mec
[3]++;
773 // Set the direction to move in
778 // When the code reaches here, we have initialized the first point, and
779 // we have a direction for moving it to construct the rest of the facet
781 while(qp
!=up
||qs
!=us
) {
783 // We're currently tracing round an intersected facet. Keep
784 // moving around it until we find a point or edge which
785 // intersects the plane.
791 // The point is still in the cutting space. Just add it
792 // to the delete stack and keep moving.
793 qs
=cycle_up(ed
[qp
][nu
[qp
]+qs
],lp
);
796 if(stackp
==stacke
) add_memory_ds(stackp
);
801 // The point is outside of the cutting space, so we've
802 // found an intersected edge. Introduce a regular point
803 // at the point of intersection. Connect it to the
804 // point we just tested. Also connect it to the previous
805 // new point in the facet we're constructing.
806 if(p
==current_vertices
) add_memory_vertices(vc
);
808 ptsq
[3*p
]=ptsq
[3*lp
]*r
+ptsq
[3*qp
]*l
;
809 ptsq
[3*p
+1]=ptsq
[3*lp
+1]*r
+ptsq
[3*qp
+1]*l
;
810 ptsq
[3*p
+2]=ptsq
[3*lp
+2]*r
+ptsq
[3*qp
+2]*l
;
812 if(mec
[3]==mem
[3]) add_memory(vc
,3,stackp2
);
813 ls
=ed
[qp
][qs
+nu
[qp
]];
814 vc
.n_set_pointer(p
,3);
816 vc
.n_copy(p
,1,qp
,qs
);
817 vc
.n_copy(p
,2,lp
,ls
);
818 ed
[p
]=mep
[3]+7*mec
[3]++;
834 // We've found a point which is on the cutting plane.
835 // We're going to introduce a new point right here, but
836 // first we need to figure out the number of edges it
838 if(p
==current_vertices
) add_memory_vertices(vc
);
840 // If the previous vertex detected a double edge, our
841 // new vertex will have one less edge.
843 qs
=ed
[qp
][nu
[qp
]+qs
];
847 // Start testing the edges of the current point until
848 // we find one which isn't outside the cutting space
856 // Now we need to find out whether this marginal vertex
857 // we are on has been visited before, because if that's
858 // the case, we need to add vertices to the existing
859 // new vertex, rather than creating a fresh one. We also
860 // need to figure out whether we're in a case where we
861 // might be creating a duplicate edge.
862 j
=-ed
[qp
][nu
[qp
]<<1];
865 // If we're heading into the final part of the
866 // new facet, then we never worry about the
867 // duplicate edge calculation.
868 new_double_edge
=false;
873 // This vertex was visited before, so
874 // count those vertices to the ones we
878 // The only time when we might make a
879 // duplicate edge is if the point we're
880 // going to move to next is also a
881 // marginal point, so test for that
885 // Now see whether this marginal point
886 // has been visited before.
887 i
=-ed
[lp
][nu
[lp
]<<1];
890 // Now see if the last edge of that other
891 // marginal point actually ends up here.
892 if(ed
[i
][nu
[i
]-1]==j
) {
893 new_double_edge
=true;
895 } else new_double_edge
=false;
898 // That marginal point hasn't been visited
899 // before, so we probably don't have to worry
900 // about duplicate edges, except in the
901 // case when that's the way into the end
902 // of the facet, because that way always creates
904 if(j
==rp
&&lp
==up
&&ed
[qp
][nu
[qp
]+qs
]==us
) {
905 new_double_edge
=true;
907 } else new_double_edge
=false;
909 } else new_double_edge
=false;
912 // The vertex hasn't been visited
913 // before, but let's see if it's
917 // If it is, we need to check
918 // for the case that it's a
919 // small branch, and that we're
920 // heading right back to where
922 i
=-ed
[lp
][nu
[lp
]<<1];
924 new_double_edge
=true;
926 } else new_double_edge
=false;
927 } else new_double_edge
=false;
931 // k now holds the number of edges of the new vertex
932 // we are forming. Add memory for it if it doesn't exist
934 while(k
>=current_vertex_order
) add_memory_vorder(vc
);
935 if(mec
[k
]==mem
[k
]) add_memory(vc
,k
,stackp2
);
937 // Now create a new vertex with order k, or augment
941 // If we're augmenting a vertex but we don't
942 // actually need any more edges, just skip this
943 // routine to avoid memory confusion
945 // Allocate memory and copy the edges
946 // of the previous instance into it
948 edp
=mep
[k
]+((k
<<1)+1)*mec
[k
]++;
953 edp
[k
+i
]=ed
[j
][nu
[j
]+i
];
958 // Remove the previous instance with
959 // fewer vertices from the memory
961 edd
=mep
[nu
[j
]]+((nu
[j
]<<1)+1)*--mec
[nu
[j
]];
963 for(lw
=0;lw
<=(nu
[j
]<<1);lw
++) ed
[j
][lw
]=edd
[lw
];
964 vc
.n_set_aux2_copy(j
,nu
[j
]);
965 vc
.n_copy_pointer(edd
[nu
[j
]<<1],j
);
966 ed
[edd
[nu
[j
]<<1]]=ed
[j
];
973 // Allocate a new vertex of order k
974 vc
.n_set_pointer(p
,k
);
975 ed
[p
]=mep
[k
]+((k
<<1)+1)*mec
[k
]++;
977 if(stackp2
==stacke2
) add_memory_ds2(stackp2
);
979 ptsq
[3*p
]=ptsq
[3*qp
];
980 ptsq
[3*p
+1]=ptsq
[3*qp
+1];
981 ptsq
[3*p
+2]=ptsq
[3*qp
+2];
982 ed
[qp
][nu
[qp
]<<1]=-p
;
988 // Unless the previous case was a double edge, connect
989 // the first available edge of the new vertex to the
990 // last one in the facet
1000 // Copy in the edges of the underlying vertex,
1001 // and do one less if this was a double edge
1003 while(i
<(new_double_edge
?k
:k
-1)) {
1005 lp
=ed
[qp
][qs
];ls
=ed
[qp
][nu
[qp
]+qs
];
1006 vc
.n_copy(j
,i
,qp
,qs
);
1010 ed
[lp
][nu
[lp
]+ls
]=i
;
1017 vc
.n_copy(j
,new_double_edge
?0:cs
,qp
,qs
);
1019 // Update the double_edge flag, to pass it
1020 // to the next instance of this routine
1021 double_edge
=new_double_edge
;
1025 // Connect the final created vertex to the initial one
1028 ed
[cp
][nu
[cp
]+cs
]=0;
1031 // Delete points: first, remove any duplicates
1035 if(ed
[j
][nu
[j
]]!=-1) {
1038 } else *dsp
=*(--stackp
);
1041 // Add the points in the auxiliary delete stack,
1042 // and reset their back pointers
1043 for(dsp
=ds2
;dsp
<stackp2
;dsp
++) {
1046 if(ed
[j
][nu
[j
]]!=-1) {
1048 if(stackp
==stacke
) add_memory_ds(stackp
);
1053 // Scan connections and add in extras
1054 for(dsp
=ds
;dsp
<stackp
;dsp
++) {
1056 for(edp
=ed
[cp
];edp
<ed
[cp
]+nu
[cp
];edp
++) {
1058 if(qp
!=-1&&ed
[qp
][nu
[qp
]]!=-1) {
1059 if(stackp
==stacke
) {
1061 add_memory_ds(stackp
);
1071 // Delete them from the array structure
1074 while(ed
[p
][nu
[p
]]==-1) {
1076 edp
=ed
[p
];edd
=(mep
[j
]+((j
<<1)+1)*--mec
[j
]);
1077 while(edp
<ed
[p
]+(j
<<1)+1) *(edp
++)=*(edd
++);
1078 vc
.n_set_aux2_copy(p
,j
);
1079 vc
.n_copy_pointer(ed
[p
][(j
<<1)],p
);
1080 ed
[ed
[p
][(j
<<1)]]=ed
[p
];
1086 // Vertex management
1087 ptsq
[3*up
]=ptsq
[3*p
];
1088 ptsq
[3*up
+1]=ptsq
[3*p
+1];
1089 ptsq
[3*up
+2]=ptsq
[3*p
+2];
1091 // Memory management
1093 edp
=ed
[up
];edd
=(mep
[j
]+((j
<<1)+1)*--mec
[j
]);
1094 while(edp
<ed
[up
]+(j
<<1)+1) *(edp
++)=*(edd
++);
1095 vc
.n_set_aux2_copy(up
,j
);
1096 vc
.n_copy_pointer(ed
[up
][j
<<1],up
);
1097 vc
.n_copy_pointer(up
,p
);
1098 ed
[ed
[up
][j
<<1]]=ed
[up
];
1103 for(i
=0;i
<nu
[up
];i
++) ed
[ed
[up
][i
]][ed
[up
][nu
[up
]+i
]]=up
;
1104 ed
[up
][nu
[up
]<<1]=up
;
1108 // Check for any vertices of zero order
1109 if(*mec
>0) voro_fatal_error("Zero order vertex formed",VOROPP_INTERNAL_ERROR
);
1111 // Collapse any order 2 vertices and exit
1112 return collapse_order2(vc
);
1115 /** During the creation of a new facet in the plane routine, it is possible
1116 * that some order two vertices may arise. This routine removes them.
1117 * Suppose an order two vertex joins c and d. If there's a edge between
1118 * c and d already, then the order two vertex is just removed; otherwise,
1119 * the order two vertex is removed and c and d are joined together directly.
1120 * It is possible this process will create order two or order one vertices,
1121 * and the routine is continually run until all of them are removed.
1122 * \return False if the vertex removal was unsuccessful, indicative of the cell
1123 * reducing to zero volume and disappearing; true if the vertex removal
1124 * was successful. */
1125 template<class vc_class
>
1126 inline bool voronoicell_base::collapse_order2(vc_class
&vc
) {
1127 if(!collapse_order1(vc
)) return false;
1131 // Pick a order 2 vertex and read in its edges
1133 j
=mep
[2][5*i
];k
=mep
[2][5*i
+1];
1135 #if VOROPP_VERBOSE >=1
1136 fputs("Order two vertex joins itself",stderr
);
1141 // Scan the edges of j to see if joins k
1142 for(l
=0;l
<nu
[j
];l
++) {
1143 if(ed
[j
][l
]==k
) break;
1146 // If j doesn't already join k, join them together.
1147 // Otherwise delete the connection to the current
1148 // vertex from j and k.
1149 a
=mep
[2][5*i
+2];b
=mep
[2][5*i
+3];i
=mep
[2][5*i
+4];
1156 if(!delete_connection(vc
,j
,a
,false)) return false;
1157 if(!delete_connection(vc
,k
,b
,true)) return false;
1160 // Compact the memory
1165 ptsq
[3*i
]=ptsq
[3*p
];
1166 ptsq
[3*i
+1]=ptsq
[3*p
+1];
1167 ptsq
[3*i
+2]=ptsq
[3*p
+2];
1168 for(k
=0;k
<nu
[p
];k
++) ed
[ed
[p
][k
]][ed
[p
][nu
[p
]+k
]]=i
;
1169 vc
.n_copy_pointer(i
,p
);
1175 // Collapse any order 1 vertices if they were created
1176 if(!collapse_order1(vc
)) return false;
1181 /** Order one vertices can potentially be created during the order two collapse
1182 * routine. This routine keeps removing them until there are none left.
1183 * \return False if the vertex removal was unsuccessful, indicative of the cell
1184 * having zero volume and disappearing; true if the vertex removal was
1186 template<class vc_class
>
1187 inline bool voronoicell_base::collapse_order1(vc_class
&vc
) {
1191 #if VOROPP_VERBOSE >=1
1192 fputs("Order one collapse\n",stderr
);
1195 j
=mep
[1][3*i
];k
=mep
[1][3*i
+1];
1197 if(!delete_connection(vc
,j
,k
,false)) return false;
1202 ptsq
[3*i
]=ptsq
[3*p
];
1203 ptsq
[3*i
+1]=ptsq
[3*p
+1];
1204 ptsq
[3*i
+2]=ptsq
[3*p
+2];
1205 for(k
=0;k
<nu
[p
];k
++) ed
[ed
[p
][k
]][ed
[p
][nu
[p
]+k
]]=i
;
1206 vc
.n_copy_pointer(i
,p
);
1215 /** This routine deletes the kth edge of vertex j and reorganizes the memory.
1216 * If the neighbor computation is enabled, we also have to supply an handedness
1217 * flag to decide whether to preserve the plane on the left or right of the
1219 * \return False if a zero order vertex was formed, indicative of the cell
1220 * disappearing; true if the vertex removal was successful. */
1221 template<class vc_class
>
1222 inline bool voronoicell_base::delete_connection(vc_class
&vc
,int j
,int k
,bool hand
) {
1223 int q
=hand
?k
:cycle_up(k
,j
);
1224 int i
=nu
[j
]-1,l
,*edp
,*edd
,m
;
1225 #if VOROPP_VERBOSE >=1
1227 fputs("Zero order vertex formed\n",stderr
);
1231 if(mec
[i
]==mem
[i
]) add_memory(vc
,i
,ds2
);
1233 for(l
=0;l
<q
;l
++) vc
.n_copy_aux1(j
,l
);
1235 vc
.n_copy_aux1_shift(j
,l
);
1238 edp
=mep
[i
]+((i
<<1)+1)*mec
[i
]++;
1242 edp
[l
+i
]=ed
[j
][l
+nu
[j
]];
1253 edd
=mep
[nu
[j
]]+((nu
[j
]<<1)+1)*--mec
[nu
[j
]];
1254 for(l
=0;l
<=(nu
[j
]<<1);l
++) ed
[j
][l
]=edd
[l
];
1255 vc
.n_set_aux2_copy(j
,nu
[j
]);
1256 vc
.n_set_to_aux2(edd
[nu
[j
]<<1]);
1257 vc
.n_set_to_aux1(j
);
1258 ed
[edd
[nu
[j
]<<1]]=edd
;
1264 /** Calculates the volume of the Voronoi cell, by decomposing the cell into
1265 * tetrahedra extending outward from the zeroth vertex, whose volumes are
1266 * evaluated using a scalar triple product.
1267 * \return A floating point number holding the calculated volume. */
1268 double voronoicell_base::volume() {
1270 const double fe
=1/48.0;
1273 double ux
,uy
,uz
,vx
,vy
,vz
,wx
,wy
,wz
;
1276 uy
=pts
[1]-pts
[3*i
+1];
1277 uz
=pts
[2]-pts
[3*i
+2];
1278 for(j
=0;j
<nu
[i
];j
++) {
1282 l
=cycle_up(ed
[i
][nu
[i
]+j
],k
);
1284 vy
=pts
[3*k
+1]-pts
[1];
1285 vz
=pts
[3*k
+2]-pts
[2];
1286 m
=ed
[k
][l
];ed
[k
][l
]=-1-m
;
1288 n
=cycle_up(ed
[k
][nu
[k
]+l
],m
);
1290 wy
=pts
[3*m
+1]-pts
[1];
1291 wz
=pts
[3*m
+2]-pts
[2];
1292 vol
+=ux
*vy
*wz
+uy
*vz
*wx
+uz
*vx
*wy
-uz
*vy
*wx
-uy
*vx
*wz
-ux
*vz
*wy
;
1293 k
=m
;l
=n
;vx
=wx
;vy
=wy
;vz
=wz
;
1294 m
=ed
[k
][l
];ed
[k
][l
]=-1-m
;
1303 /** Calculates the areas of each face of the Voronoi cell and prints the
1304 * results to an output stream.
1305 * \param[out] v the vector to store the results in. */
1306 void voronoicell_base::face_areas(vector
<double> &v
) {
1311 double ux
,uy
,uz
,vx
,vy
,vz
,wx
,wy
,wz
;
1312 for(i
=1;i
<p
;i
++) for(j
=0;j
<nu
[i
];j
++) {
1317 l
=cycle_up(ed
[i
][nu
[i
]+j
],k
);
1318 m
=ed
[k
][l
];ed
[k
][l
]=-1-m
;
1320 n
=cycle_up(ed
[k
][nu
[k
]+l
],m
);
1321 ux
=pts
[3*k
]-pts
[3*i
];
1322 uy
=pts
[3*k
+1]-pts
[3*i
+1];
1323 uz
=pts
[3*k
+2]-pts
[3*i
+2];
1324 vx
=pts
[3*m
]-pts
[3*i
];
1325 vy
=pts
[3*m
+1]-pts
[3*i
+1];
1326 vz
=pts
[3*m
+2]-pts
[3*i
+2];
1330 area
+=sqrt(wx
*wx
+wy
*wy
+wz
*wz
);
1332 m
=ed
[k
][l
];ed
[k
][l
]=-1-m
;
1334 v
.push_back(0.125*area
);
1341 /** Calculates the total surface area of the Voronoi cell.
1342 * \return The computed area. */
1343 double voronoicell_base::surface_area() {
1347 double ux
,uy
,uz
,vx
,vy
,vz
,wx
,wy
,wz
;
1348 for(i
=1;i
<p
;i
++) for(j
=0;j
<nu
[i
];j
++) {
1352 l
=cycle_up(ed
[i
][nu
[i
]+j
],k
);
1353 m
=ed
[k
][l
];ed
[k
][l
]=-1-m
;
1355 n
=cycle_up(ed
[k
][nu
[k
]+l
],m
);
1356 ux
=pts
[3*k
]-pts
[3*i
];
1357 uy
=pts
[3*k
+1]-pts
[3*i
+1];
1358 uz
=pts
[3*k
+2]-pts
[3*i
+2];
1359 vx
=pts
[3*m
]-pts
[3*i
];
1360 vy
=pts
[3*m
+1]-pts
[3*i
+1];
1361 vz
=pts
[3*m
+2]-pts
[3*i
+2];
1365 area
+=sqrt(wx
*wx
+wy
*wy
+wz
*wz
);
1367 m
=ed
[k
][l
];ed
[k
][l
]=-1-m
;
1376 /** Calculates the centroid of the Voronoi cell, by decomposing the cell into
1377 * tetrahedra extending outward from the zeroth vertex.
1378 * \param[out] (cx,cy,cz) references to floating point numbers in which to
1379 * pass back the centroid vector. */
1380 void voronoicell_base::centroid(double &cx
,double &cy
,double &cz
) {
1382 double tvol
,vol
=0;cx
=cy
=cz
=0;
1384 double ux
,uy
,uz
,vx
,vy
,vz
,wx
,wy
,wz
;
1387 uy
=pts
[1]-pts
[3*i
+1];
1388 uz
=pts
[2]-pts
[3*i
+2];
1389 for(j
=0;j
<nu
[i
];j
++) {
1393 l
=cycle_up(ed
[i
][nu
[i
]+j
],k
);
1395 vy
=pts
[3*k
+1]-pts
[1];
1396 vz
=pts
[3*k
+2]-pts
[2];
1397 m
=ed
[k
][l
];ed
[k
][l
]=-1-m
;
1399 n
=cycle_up(ed
[k
][nu
[k
]+l
],m
);
1401 wy
=pts
[3*m
+1]-pts
[1];
1402 wz
=pts
[3*m
+2]-pts
[2];
1403 tvol
=ux
*vy
*wz
+uy
*vz
*wx
+uz
*vx
*wy
-uz
*vy
*wx
-uy
*vx
*wz
-ux
*vz
*wy
;
1405 cx
+=(wx
+vx
-ux
)*tvol
;
1406 cy
+=(wy
+vy
-uy
)*tvol
;
1407 cz
+=(wz
+vz
-uz
)*tvol
;
1408 k
=m
;l
=n
;vx
=wx
;vy
=wy
;vz
=wz
;
1409 m
=ed
[k
][l
];ed
[k
][l
]=-1-m
;
1415 if(vol
>tolerance_sq
) {
1417 cx
=cx
*vol
+0.5*(*pts
);
1418 cy
=cy
*vol
+0.5*pts
[1];
1419 cz
=cz
*vol
+0.5*pts
[2];
1423 /** Computes the maximum radius squared of a vertex from the center of the
1424 * cell. It can be used to determine when enough particles have been testing an
1425 * all planes that could cut the cell have been considered.
1426 * \return The maximum radius squared of a vertex.*/
1427 double voronoicell_base::max_radius_squared() {
1429 double r
,s
,*ptsp
=pts
+3,*ptse
=pts
+3*p
;
1430 r
=*pts
*(*pts
)+pts
[1]*pts
[1]+pts
[2]*pts
[2];
1432 s
=*ptsp
*(*ptsp
);ptsp
++;
1433 s
+=*ptsp
*(*ptsp
);ptsp
++;
1434 s
+=*ptsp
*(*ptsp
);ptsp
++;
1440 /** Calculates the total edge distance of the Voronoi cell.
1441 * \return A floating point number holding the calculated distance. */
1442 double voronoicell_base::total_edge_distance() {
1445 double dis
=0,dx
,dy
,dz
;
1446 for(i
=0;i
<p
-1;i
++) for(j
=0;j
<nu
[i
];j
++) {
1449 dx
=pts
[3*k
]-pts
[3*i
];
1450 dy
=pts
[3*k
+1]-pts
[3*i
+1];
1451 dz
=pts
[3*k
+2]-pts
[3*i
+2];
1452 dis
+=sqrt(dx
*dx
+dy
*dy
+dz
*dz
);
1458 /** Outputs the edges of the Voronoi cell in POV-Ray format to an open file
1459 * stream, displacing the cell by given vector.
1460 * \param[in] (x,y,z) a displacement vector to be added to the cell's position.
1461 * \param[in] fp a file handle to write to. */
1462 void voronoicell_base::draw_pov(double x
,double y
,double z
,FILE* fp
) {
1464 int i
,j
,k
;double *ptsp
=pts
,*pt2
;
1465 char posbuf1
[128],posbuf2
[128];
1466 for(i
=0;i
<p
;i
++,ptsp
+=3) {
1467 sprintf(posbuf1
,"%g,%g,%g",x
+*ptsp
*0.5,y
+ptsp
[1]*0.5,z
+ptsp
[2]*0.5);
1468 fprintf(fp
,"sphere{<%s>,r}\n",posbuf1
);
1469 for(j
=0;j
<nu
[i
];j
++) {
1473 sprintf(posbuf2
,"%g,%g,%g",x
+*pt2
*0.5,y
+0.5*pt2
[1],z
+0.5*pt2
[2]);
1474 if(strcmp(posbuf1
,posbuf2
)!=0) fprintf(fp
,"cylinder{<%s>,<%s>,r}\n",posbuf1
,posbuf2
);
1480 /** Outputs the edges of the Voronoi cell in gnuplot format to an output stream.
1481 * \param[in] (x,y,z) a displacement vector to be added to the cell's position.
1482 * \param[in] fp a file handle to write to. */
1483 void voronoicell_base::draw_gnuplot(double x
,double y
,double z
,FILE *fp
) {
1486 for(i
=1;i
<p
;i
++) for(j
=0;j
<nu
[i
];j
++) {
1489 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]);
1492 ed
[k
][ed
[l
][nu
[l
]+m
]]=-1-l
;
1495 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]);
1496 } while (search_edge(l
,m
,k
));
1503 inline bool voronoicell_base::search_edge(int l
,int &m
,int &k
) {
1504 for(m
=0;m
<nu
[l
];m
++) {
1506 if(k
>=0) return true;
1511 /** Outputs the Voronoi cell in the POV mesh2 format, described in section
1512 * 1.3.2.2 of the POV-Ray documentation. The mesh2 output consists of a list of
1513 * vertex vectors, followed by a list of triangular faces. The routine also
1514 * makes use of the optional inside_vector specification, which makes the mesh
1515 * object solid, so the the POV-Ray Constructive Solid Geometry (CSG) can be
1517 * \param[in] (x,y,z) a displacement vector to be added to the cell's position.
1518 * \param[in] fp a file handle to write to. */
1519 void voronoicell_base::draw_pov_mesh(double x
,double y
,double z
,FILE *fp
) {
1523 fprintf(fp
,"mesh2 {\nvertex_vectors {\n%d\n",p
);
1524 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);
1525 fprintf(fp
,"}\nface_indices {\n%d\n",(p
-2)<<1);
1526 for(i
=1;i
<p
;i
++) for(j
=0;j
<nu
[i
];j
++) {
1530 l
=cycle_up(ed
[i
][nu
[i
]+j
],k
);
1531 m
=ed
[k
][l
];ed
[k
][l
]=-1-m
;
1533 n
=cycle_up(ed
[k
][nu
[k
]+l
],m
);
1534 fprintf(fp
,",<%d,%d,%d>\n",i
,k
,m
);
1536 m
=ed
[k
][l
];ed
[k
][l
]=-1-m
;
1540 fputs("}\ninside_vector <0,0,1>\n}\n",fp
);
1544 /** Several routines in the class that gather cell-based statistics internally
1545 * track their progress by flipping edges to negative so that they know what
1546 * parts of the cell have already been tested. This function resets them back
1547 * to positive. When it is called, it assumes that every edge in the routine
1548 * should have already been flipped to negative, and it bails out with an
1549 * internal error if it encounters a positive edge. */
1550 inline void voronoicell_base::reset_edges() {
1552 for(i
=0;i
<p
;i
++) for(j
=0;j
<nu
[i
];j
++) {
1553 if(ed
[i
][j
]>=0) voro_fatal_error("Edge reset routine found a previously untested edge",VOROPP_INTERNAL_ERROR
);
1554 ed
[i
][j
]=-1-ed
[i
][j
];
1558 /** Checks to see if a given vertex is inside, outside or within the test
1559 * plane. If the point is far away from the test plane, the routine immediately
1560 * returns whether it is inside or outside. If the routine is close the the
1561 * plane and within the specified tolerance, then the special check_marginal()
1562 * routine is called.
1563 * \param[in] n the vertex to test.
1564 * \param[out] ans the result of the scalar product used in evaluating the
1565 * location of the point.
1566 * \return -1 if the point is inside the plane, 1 if the point is outside the
1567 * plane, or 0 if the point is within the plane. */
1568 inline int voronoicell_base::m_test(int n
,mpq_class
&ans
) {
1569 mpq_class
*pp
=ptsq
+n
+(n
<<1);
1580 /** For each face of the Voronoi cell, this routine prints the out the normal
1581 * vector of the face, and scales it to the distance from the cell center to
1583 * \param[out] v the vector to store the results in. */
1584 void voronoicell_base::normals(vector
<double> &v
) {
1588 for(i
=1;i
<p
;i
++) for(j
=0;j
<nu
[i
];j
++) {
1590 if(k
>=0) normals_search(v
,i
,j
,k
);
1595 /** This inline routine is called by normals(). It attempts to construct a
1596 * single normal vector that is associated with a particular face. It first
1597 * traces around the face, trying to find two vectors along the face edges
1598 * whose vector product is above the numerical tolerance. It then constructs
1599 * the normal vector using this product. If the face is too small, and none of
1600 * the vector products are large enough, the routine may return (0,0,0) as the
1602 * \param[in] v the vector to store the results in.
1603 * \param[in] i the initial vertex of the face to test.
1604 * \param[in] j the index of an edge of the vertex.
1605 * \param[in] k the neighboring vertex of i, set to ed[i][j]. */
1606 inline void voronoicell_base::normals_search(vector
<double> &v
,int i
,int j
,int k
) {
1608 int l
=cycle_up(ed
[i
][nu
[i
]+j
],k
),m
;
1609 double ux
,uy
,uz
,vx
,vy
,vz
,wx
,wy
,wz
,wmag
;
1611 m
=ed
[k
][l
];ed
[k
][l
]=-1-m
;
1612 ux
=pts
[3*m
]-pts
[3*k
];
1613 uy
=pts
[3*m
+1]-pts
[3*k
+1];
1614 uz
=pts
[3*m
+2]-pts
[3*k
+2];
1616 // Test to see if the length of this edge is above the tolerance
1617 if(ux
*ux
+uy
*uy
+uz
*uz
>tolerance_sq
) {
1619 l
=cycle_up(ed
[k
][nu
[k
]+l
],m
);
1620 k
=m
;m
=ed
[k
][l
];ed
[k
][l
]=-1-m
;
1621 vx
=pts
[3*m
]-pts
[3*k
];
1622 vy
=pts
[3*m
+1]-pts
[3*k
+1];
1623 vz
=pts
[3*m
+2]-pts
[3*k
+2];
1625 // Construct the vector product of this edge with
1630 wmag
=wx
*wx
+wy
*wy
+wz
*wz
;
1632 // Test to see if this vector product of the
1633 // two edges is above the tolerance
1634 if(wmag
>tolerance_sq
) {
1636 // Construct the normal vector and print it
1638 v
.push_back(wx
*wmag
);
1639 v
.push_back(wy
*wmag
);
1640 v
.push_back(wz
*wmag
);
1642 // Mark all of the remaining edges of this
1645 l
=cycle_up(ed
[k
][nu
[k
]+l
],m
);
1646 k
=m
;m
=ed
[k
][l
];ed
[k
][l
]=-1-m
;
1656 l
=cycle_up(ed
[k
][nu
[k
]+l
],m
);
1665 /** Returns the number of faces of a computed Voronoi cell.
1666 * \return The number of faces. */
1667 int voronoicell_base::number_of_faces() {
1669 for(i
=1;i
<p
;i
++) for(j
=0;j
<nu
[i
];j
++) {
1674 l
=cycle_up(ed
[i
][nu
[i
]+j
],k
);
1678 l
=cycle_up(ed
[k
][nu
[k
]+l
],m
);
1688 /** Returns a vector of the vertex orders.
1689 * \param[out] v the vector to store the results in. */
1690 void voronoicell_base::vertex_orders(vector
<int> &v
) {
1692 for(int i
=0;i
<p
;i
++) v
[i
]=nu
[i
];
1695 /** Outputs the vertex orders.
1696 * \param[out] fp the file handle to write to. */
1697 void voronoicell_base::output_vertex_orders(FILE *fp
) {
1699 fprintf(fp
,"%d",*nu
);
1700 for(int *nup
=nu
+1;nup
<nu
+p
;nup
++) fprintf(fp
," %d",*nup
);
1704 /** Returns a vector of the vertex vectors using the local coordinate system.
1705 * \param[out] v the vector to store the results in. */
1706 void voronoicell_base::vertices(vector
<double> &v
) {
1710 for(int i
=0;i
<3*p
;i
+=3) {
1712 v
[i
+1]=*(ptsp
++)*0.5;
1713 v
[i
+2]=*(ptsp
++)*0.5;
1717 /** Outputs the vertex vectors using the local coordinate system.
1718 * \param[out] fp the file handle to write to. */
1719 void voronoicell_base::output_vertices(FILE *fp
) {
1722 fprintf(fp
,"(%g,%g,%g)",*pts
*0.5,pts
[1]*0.5,pts
[2]*0.5);
1723 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);
1728 /** Returns a vector of the vertex vectors in the global coordinate system.
1729 * \param[out] v the vector to store the results in.
1730 * \param[in] (x,y,z) the position vector of the particle in the global
1731 * coordinate system. */
1732 void voronoicell_base::vertices(double x
,double y
,double z
,vector
<double> &v
) {
1736 for(int i
=0;i
<3*p
;i
+=3) {
1737 v
[i
]=x
+*(ptsp
++)*0.5;
1738 v
[i
+1]=y
+*(ptsp
++)*0.5;
1739 v
[i
+2]=z
+*(ptsp
++)*0.5;
1743 /** Outputs the vertex vectors using the global coordinate system.
1744 * \param[out] fp the file handle to write to.
1745 * \param[in] (x,y,z) the position vector of the particle in the global
1746 * coordinate system. */
1747 void voronoicell_base::output_vertices(double x
,double y
,double z
,FILE *fp
) {
1750 fprintf(fp
,"(%g,%g,%g)",x
+*pts
*0.5,y
+pts
[1]*0.5,z
+pts
[2]*0.5);
1751 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);
1755 /** This routine returns the perimeters of each face.
1756 * \param[out] v the vector to store the results in. */
1757 void voronoicell_base::face_perimeters(vector
<double> &v
) {
1761 double dx
,dy
,dz
,perim
;
1762 for(i
=1;i
<p
;i
++) for(j
=0;j
<nu
[i
];j
++) {
1765 dx
=pts
[3*k
]-pts
[3*i
];
1766 dy
=pts
[3*k
+1]-pts
[3*i
+1];
1767 dz
=pts
[3*k
+2]-pts
[3*i
+2];
1768 perim
=sqrt(dx
*dx
+dy
*dy
+dz
*dz
);
1770 l
=cycle_up(ed
[i
][nu
[i
]+j
],k
);
1773 dx
=pts
[3*m
]-pts
[3*k
];
1774 dy
=pts
[3*m
+1]-pts
[3*k
+1];
1775 dz
=pts
[3*m
+2]-pts
[3*k
+2];
1776 perim
+=sqrt(dx
*dx
+dy
*dy
+dz
*dz
);
1778 l
=cycle_up(ed
[k
][nu
[k
]+l
],m
);
1781 v
.push_back(0.5*perim
);
1787 /** For each face, this routine outputs a bracketed sequence of numbers
1788 * containing a list of all the vertices that make up that face.
1789 * \param[out] v the vector to store the results in. */
1790 void voronoicell_base::face_vertices(vector
<int> &v
) {
1791 int i
,j
,k
,l
,m
,vp(0),vn
;
1793 for(i
=1;i
<p
;i
++) for(j
=0;j
<nu
[i
];j
++) {
1799 l
=cycle_up(ed
[i
][nu
[i
]+j
],k
);
1804 l
=cycle_up(ed
[k
][nu
[k
]+l
],m
);
1815 /** Outputs a list of the number of edges in each face.
1816 * \param[out] v the vector to store the results in. */
1817 void voronoicell_base::face_orders(vector
<int> &v
) {
1820 for(i
=1;i
<p
;i
++) for(j
=0;j
<nu
[i
];j
++) {
1825 l
=cycle_up(ed
[i
][nu
[i
]+j
],k
);
1830 l
=cycle_up(ed
[k
][nu
[k
]+l
],m
);
1839 /** Computes the number of edges that each face has and outputs a frequency
1840 * table of the results.
1841 * \param[out] v the vector to store the results in. */
1842 void voronoicell_base::face_freq_table(vector
<int> &v
) {
1845 for(i
=1;i
<p
;i
++) for(j
=0;j
<nu
[i
];j
++) {
1850 l
=cycle_up(ed
[i
][nu
[i
]+j
],k
);
1855 l
=cycle_up(ed
[k
][nu
[k
]+l
],m
);
1858 if((unsigned int) q
>=v
.size()) v
.resize(q
+1,0);
1865 /** This routine tests to see whether the cell intersects a plane by starting
1866 * from the guess point up. If up intersects, then it immediately returns true.
1867 * Otherwise, it calls the plane_intersects_track() routine.
1868 * \param[in] (x,y,z) the normal vector to the plane.
1869 * \param[in] rsq the distance along this vector of the plane.
1870 * \return False if the plane does not intersect the plane, true if it does. */
1871 bool voronoicell_base::plane_intersects(double xd
,double yd
,double zd
,double rsqd
) {
1872 mpq_class x
,y
,z
,rsq
,g
;
1873 x
=xd
;y
=yd
;z
=zd
;rsq
=rsqd
;
1874 g
=x
*ptsq
[3*up
]+y
*ptsq
[3*up
+1]+z
*ptsq
[3*up
+2];
1875 if(g
<rsq
) return plane_intersects_track(x
,y
,z
,rsq
,g
);
1879 /** This routine tests to see if a cell intersects a plane. It first tests a
1880 * random sample of approximately sqrt(p)/4 points. If any of those are
1881 * intersect, then it immediately returns true. Otherwise, it takes the closest
1882 * point and passes that to plane_intersect_track() routine.
1883 * \param[in] (x,y,z) the normal vector to the plane.
1884 * \param[in] rsq the distance along this vector of the plane.
1885 * \return False if the plane does not intersect the plane, true if it does. */
1886 bool voronoicell_base::plane_intersects_guess(double xd
,double yd
,double zd
,double rsqd
) {
1887 mpq_class x
,y
,z
,rsq
,g
,m
;
1888 x
=xd
;y
=yd
;z
=zd
;rsq
=rsqd
;
1890 g
=x
*ptsq
[3*up
]+y
*ptsq
[3*up
+1]+z
*ptsq
[3*up
+2];
1892 int ca
=1,cc
=p
>>3,mp
=1;
1894 m
=x
*ptsq
[3*mp
]+y
*ptsq
[3*mp
+1]+z
*ptsq
[3*mp
+2];
1896 if(m
>rsq
) return true;
1901 return plane_intersects_track(x
,y
,z
,rsq
,g
);
1906 /* This routine tests to see if a cell intersects a plane, by tracing over the cell from
1907 * vertex to vertex, starting at up. It is meant to be called either by plane_intersects()
1908 * or plane_intersects_track(), when those routines cannot immediately resolve the case.
1909 * \param[in] (x,y,z) the normal vector to the plane.
1910 * \param[in] rsq the distance along this vector of the plane.
1911 * \param[in] g the distance of up from the plane.
1912 * \return False if the plane does not intersect the plane, true if it does. */
1913 inline bool voronoicell_base::plane_intersects_track(mpq_class x
,mpq_class y
,mpq_class z
,mpq_class rsq
,mpq_class g
) {
1914 int count
=0,ls
,us
,tp
;
1917 // The test point is outside of the cutting space
1918 for(us
=0;us
<nu
[up
];us
++) {
1920 t
=x
*ptsq
[3*tp
]+y
*ptsq
[3*tp
+1]+z
*ptsq
[3*tp
+2];
1922 ls
=ed
[up
][nu
[up
]+us
];
1926 #if VOROPP_VERBOSE >=1
1927 fputs("Bailed out of convex calculation",stderr
);
1929 for(tp
=0;tp
<p
;tp
++) if(x
*ptsq
[3*tp
]+y
*ptsq
[3*tp
+1]+z
*ptsq
[3*tp
+2]>rsq
) return true;
1933 // Test all the neighbors of the current point
1934 // and find the one which is closest to the
1936 for(us
=0;us
<ls
;us
++) {
1938 g
=x
*ptsq
[3*tp
]+y
*ptsq
[3*tp
+1]+z
*ptsq
[3*tp
+2];
1945 g
=x
*ptsq
[3*tp
]+y
*ptsq
[3*tp
+1]+z
*ptsq
[3*tp
+2];
1949 if(us
==nu
[up
]) return false;
1951 ls
=ed
[up
][nu
[up
]+us
];up
=tp
;t
=g
;
1959 /** Counts the number of edges of the Voronoi cell.
1960 * \return the number of edges. */
1961 int voronoicell_base::number_of_edges() {
1962 int edges
=0,*nup
=nu
;
1963 while(nup
<nu
+p
) edges
+=*(nup
++);
1967 /** Outputs a custom string of information about the Voronoi cell. The string
1968 * of information follows a similar style as the C printf command, and detailed
1969 * information about its format is available at
1970 * http://math.lbl.gov/voro++/doc/custom.html.
1971 * \param[in] format the custom string to print.
1972 * \param[in] i the ID of the particle associated with this Voronoi cell.
1973 * \param[in] (x,y,z) the position of the particle associated with this Voronoi
1975 * \param[in] r a radius associated with the particle.
1976 * \param[in] fp the file handle to write to. */
1977 void voronoicell_base::output_custom(const char *format
,int i
,double x
,double y
,double z
,double r
,FILE *fp
) {
1978 char *fmp
=(const_cast<char*>(format
));
1986 // Particle-related output
1987 case 'i': fprintf(fp
,"%d",i
);break;
1988 case 'x': fprintf(fp
,"%g",x
);break;
1989 case 'y': fprintf(fp
,"%g",y
);break;
1990 case 'z': fprintf(fp
,"%g",z
);break;
1991 case 'q': fprintf(fp
,"%g %g %g",x
,y
,z
);break;
1992 case 'r': fprintf(fp
,"%g",r
);break;
1994 // Vertex-related output
1995 case 'w': fprintf(fp
,"%d",p
);break;
1996 case 'p': output_vertices(fp
);break;
1997 case 'P': output_vertices(x
,y
,z
,fp
);break;
1998 case 'o': output_vertex_orders(fp
);break;
1999 case 'm': fprintf(fp
,"%g",0.25*max_radius_squared());break;
2001 // Edge-related output
2002 case 'g': fprintf(fp
,"%d",number_of_edges());break;
2003 case 'E': fprintf(fp
,"%g",total_edge_distance());break;
2004 case 'e': face_perimeters(vd
);voro_print_vector(vd
,fp
);break;
2006 // Face-related output
2007 case 's': fprintf(fp
,"%d",number_of_faces());break;
2008 case 'F': fprintf(fp
,"%g",surface_area());break;
2010 face_freq_table(vi
);
2011 voro_print_vector(vi
,fp
);
2013 case 'a': face_orders(vi
);voro_print_vector(vi
,fp
);break;
2014 case 'f': face_areas(vd
);voro_print_vector(vd
,fp
);break;
2017 voro_print_face_vertices(vi
,fp
);
2019 case 'l': normals(vd
);
2020 voro_print_positions(vd
,fp
);
2022 case 'n': neighbors(vi
);
2023 voro_print_vector(vi
,fp
);
2026 // Volume-related output
2027 case 'v': fprintf(fp
,"%g",volume());break;
2031 fprintf(fp
,"%g %g %g",cx
,cy
,cz
);
2036 fprintf(fp
,"%g %g %g",x
+cx
,y
+cy
,z
+cz
);
2039 // End-of-string reached
2040 case 0: fmp
--;break;
2042 // The percent sign is not part of a
2044 default: putc('%',fp
);putc(*fmp
,fp
);
2046 } else putc(*fmp
,fp
);
2052 /** This initializes the class to be a rectangular box. It calls the base class
2053 * initialization routine to set up the edge and vertex information, and then
2054 * sets up the neighbor information, with initial faces being assigned ID
2055 * numbers from -1 to -6.
2056 * \param[in] (xmin,xmax) the minimum and maximum x coordinates.
2057 * \param[in] (ymin,ymax) the minimum and maximum y coordinates.
2058 * \param[in] (zmin,zmax) the minimum and maximum z coordinates. */
2059 void voronoicell_neighbor::init(double xmin
,double xmax
,double ymin
,double ymax
,double zmin
,double zmax
) {
2060 init_base(xmin
,xmax
,ymin
,ymax
,zmin
,zmax
);
2062 *q
=-5;q
[1]=-3;q
[2]=-1;
2063 q
[3]=-5;q
[4]=-2;q
[5]=-3;
2064 q
[6]=-5;q
[7]=-1;q
[8]=-4;
2065 q
[9]=-5;q
[10]=-4;q
[11]=-2;
2066 q
[12]=-6;q
[13]=-1;q
[14]=-3;
2067 q
[15]=-6;q
[16]=-3;q
[17]=-2;
2068 q
[18]=-6;q
[19]=-4;q
[20]=-1;
2069 q
[21]=-6;q
[22]=-2;q
[23]=-4;
2070 *ne
=q
;ne
[1]=q
+3;ne
[2]=q
+6;ne
[3]=q
+9;
2071 ne
[4]=q
+12;ne
[5]=q
+15;ne
[6]=q
+18;ne
[7]=q
+21;
2074 /** This initializes the class to be an octahedron. It calls the base class
2075 * initialization routine to set up the edge and vertex information, and then
2076 * sets up the neighbor information, with the initial faces being assigned ID
2077 * numbers from -1 to -8.
2078 * \param[in] l The distance from the octahedron center to a vertex. Six
2079 * vertices are initialized at (-l,0,0), (l,0,0), (0,-l,0),
2080 * (0,l,0), (0,0,-l), and (0,0,l). */
2081 void voronoicell_neighbor::init_octahedron(double l
) {
2082 init_octahedron_base(l
);
2084 *q
=-5;q
[1]=-6;q
[2]=-7;q
[3]=-8;
2085 q
[4]=-1;q
[5]=-2;q
[6]=-3;q
[7]=-4;
2086 q
[8]=-6;q
[9]=-5;q
[10]=-2;q
[11]=-1;
2087 q
[12]=-8;q
[13]=-7;q
[14]=-4;q
[15]=-3;
2088 q
[16]=-5;q
[17]=-8;q
[18]=-3;q
[19]=-2;
2089 q
[20]=-7;q
[21]=-6;q
[22]=-1;q
[23]=-4;
2090 *ne
=q
;ne
[1]=q
+4;ne
[2]=q
+8;ne
[3]=q
+12;ne
[4]=q
+16;ne
[5]=q
+20;
2093 /** This initializes the class to be a tetrahedron. It calls the base class
2094 * initialization routine to set up the edge and vertex information, and then
2095 * sets up the neighbor information, with the initial faces being assigned ID
2096 * numbers from -1 to -4.
2097 * \param (x0,y0,z0) a position vector for the first vertex.
2098 * \param (x1,y1,z1) a position vector for the second vertex.
2099 * \param (x2,y2,z2) a position vector for the third vertex.
2100 * \param (x3,y3,z3) a position vector for the fourth vertex. */
2101 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
) {
2102 init_tetrahedron_base(x0
,y0
,z0
,x1
,y1
,z1
,x2
,y2
,z2
,x3
,y3
,z3
);
2104 *q
=-4;q
[1]=-3;q
[2]=-2;
2105 q
[3]=-3;q
[4]=-4;q
[5]=-1;
2106 q
[6]=-4;q
[7]=-2;q
[8]=-1;
2107 q
[9]=-2;q
[10]=-3;q
[11]=-1;
2108 *ne
=q
;ne
[1]=q
+3;ne
[2]=q
+6;ne
[3]=q
+9;
2111 /** This routine checks to make sure the neighbor information of each face is
2113 void voronoicell_neighbor::check_facets() {
2115 for(i
=1;i
<p
;i
++) for(j
=0;j
<nu
[i
];j
++) {
2120 l
=cycle_up(ed
[i
][nu
[i
]+j
],k
);
2124 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
);
2125 l
=cycle_up(ed
[k
][nu
[k
]+l
],m
);
2133 /** The class constructor allocates memory for storing neighbor information. */
2134 voronoicell_neighbor::voronoicell_neighbor() {
2136 mne
=new int*[current_vertex_order
];
2137 ne
=new int*[current_vertices
];
2138 for(i
=0;i
<3;i
++) mne
[i
]=new int[init_n_vertices
*i
];
2139 mne
[3]=new int[init_3_vertices
*3];
2140 for(i
=4;i
<current_vertex_order
;i
++) mne
[i
]=new int[init_n_vertices
*i
];
2143 /** The class destructor frees the dynamically allocated memory for storing
2144 * neighbor information. */
2145 voronoicell_neighbor::~voronoicell_neighbor() {
2146 for(int i
=current_vertex_order
-1;i
>=0;i
--) if(mem
[i
]>0) delete [] mne
[i
];
2151 /** Computes a vector list of neighbors. */
2152 void voronoicell_neighbor::neighbors(vector
<int> &v
) {
2155 for(i
=1;i
<p
;i
++) for(j
=0;j
<nu
[i
];j
++) {
2158 v
.push_back(ne
[i
][j
]);
2160 l
=cycle_up(ed
[i
][nu
[i
]+j
],k
);
2164 l
=cycle_up(ed
[k
][nu
[k
]+l
],m
);
2172 /** Prints the vertices, their edges, the relation table, and also notifies if
2173 * any memory errors are visible. */
2174 void voronoicell_base::print_edges() {
2178 for(int i
=0;i
<p
;i
++,ptsp
+=3) {
2179 printf("%d %d ",i
,nu
[i
]);
2180 for(j
=0;j
<nu
[i
];j
++) printf(" %d",ed
[i
][j
]);
2182 while(j
<(nu
[i
]<<1)) printf(" %d",ed
[i
][j
]);
2183 printf(" %d",ed
[i
][j
]);
2184 print_edges_neighbors(i
);
2185 printf(" %g %g %g %p",*ptsp
,ptsp
[1],ptsp
[2],(void*) ed
[i
]);
2186 if(ed
[i
]>=mep
[nu
[i
]]+mec
[nu
[i
]]*((nu
[i
]<<1)+1)) puts(" Memory error");
2191 /** This prints out the neighbor information for vertex i. */
2192 void voronoicell_neighbor::print_edges_neighbors(int i
) {
2196 while(j
<nu
[i
]-1) printf("%d,",ne
[i
][j
++]);
2197 printf("%d)",ne
[i
][j
]);
2198 } else printf(" ()");
2201 void voronoicell_base::sync() {
2202 for(int i
=0;i
<3*p
;i
++) pts
[i
]=ptsq
[i
].get_d();
2205 // Explicit instantiation
2206 template bool voronoicell_base::nplane(voronoicell
&,double,double,double,double,int);
2207 template bool voronoicell_base::nplane(voronoicell_neighbor
&,double,double,double,double,int);
2208 template void voronoicell_base::check_memory_for_copy(voronoicell
&,voronoicell_base
*);
2209 template void voronoicell_base::check_memory_for_copy(voronoicell_neighbor
&,voronoicell_base
*);