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
7 /** \file v_compute_2d.cc
8 * \brief Function implementantions for the 2D voro_compute class. */
10 #include "worklist_2d.hh"
11 #include "v_compute_2d.hh"
12 #include "rad_option.hh"
13 #include "container_2d.hh"
14 #include "ctr_boundary_2d.hh"
18 /** The class constructor initializes constants from the container class, and
19 * sets up the mask and queue used for Voronoi computations.
20 * \param[in] con_ a reference to the container class to use.
21 * \param[in] (hx_,hy_) the size of the mask to use. */
22 template<class c_class_2d
>
23 voro_compute_2d
<c_class_2d
>::voro_compute_2d(c_class_2d
&con_
,int hx_
,int hy_
) :
24 con(con_
), boxx(con_
.boxx
), boxy(con_
.boxy
), xsp(con_
.xsp
),
25 ysp(con_
.ysp
), hx(hx_
), hy(hy_
), hxy(hx_
*hy_
), ps(con_
.ps
),
26 id(con_
.id
), p(con_
.p
), co(con_
.co
), bxsq(boxx
*boxx
+boxy
*boxy
),
27 mv(0), qu_size(2*(2+hx
+hy
)), wl(con_
.wl
), mrad(con_
.mrad
),
28 mask(new unsigned int[hxy
]), qu(new int[qu_size
]), qu_l(qu
+qu_size
) {
32 /** Scans all of the particles within a block to see if any of them have a
33 * smaller distance to the given test vector. If one is found, the routine
34 * updates the minimum distance and store information about this particle.
35 * \param[in] ij the index of the block.
36 * \param[in] (x,y) the test vector to consider (which may have already had a
37 * periodic displacement applied to it).
38 * \param[in] (di,dj) the coordinates of the current block, to store if the
39 * particle record is updated.
40 * \param[in,out] w a reference to a particle record in which to store
41 * information about the particle whose Voronoi cell the
43 * \param[in,out] mrs the current minimum distance, that may be updated if a
44 * closer particle is found. */
45 template<class c_class_2d
>
46 inline void voro_compute_2d
<c_class_2d
>::scan_all(int ij
,double x
,double y
,int di
,int dj
,particle_record_2d
&w
,double &mrs
) {
47 double x1
,y1
,rs
;bool in_block
=false;
48 for(int l
=0;l
<co
[ij
];l
++) {
51 rs
=con
.r_current_sub(x1
*x1
+y1
*y1
,ij
,l
);
52 if(rs
<mrs
) {mrs
=rs
;w
.l
=l
;in_block
=true;}
54 if(in_block
) {w
.ij
=ij
;w
.di
=di
;w
.dj
=dj
;}
57 /** Finds the Voronoi cell that given vector is within. For containers that are
58 * not radially dependent, this corresponds to findig the particle that is
59 * closest to the vector; for the radical tessellation containers, this
60 * corresponds to a finding the minimum weighted distance.
61 * \param[in] (x,y) the vector to consider.
62 * \param[in] (ci,cj) the coordinates of the block that the test particle is
63 * in relative to the container data structure.
64 * \param[in] ij the index of the block that the test particle is in.
65 * \param[out] w a reference to a particle record in which to store information
66 * about the particle whose Voronoi cell the vector is within.
67 * \param[out] mrs the minimum computed distance. */
68 template<class c_class_2d
>
69 void voro_compute_2d
<c_class_2d
>::find_voronoi_cell(double x
,double y
,int ci
,int cj
,int ij
,particle_record_2d
&w
,double &mrs
) {
71 int i
,j
,di
,dj
,ei
,ej
,f
,g
,disp
;
72 double fx
,fy
,mxs
,mys
,*radp
;
73 unsigned int q
,*e
,*mij
;
75 // Init setup for parameters to return
76 w
.ij
=-1;mrs
=large_number
;
78 con
.initialize_search(ci
,cj
,ij
,i
,j
,disp
);
80 // Test all particles in the particle's local region first
81 scan_all(ij
,x
,y
,0,0,w
,mrs
);
83 // Now compute the fractional position of the particle within its
84 // region and store it in (fx,fy). We use this to compute an index
85 // (di,dj) of which subregion the particle is within.
87 con
.frac_pos(x
,y
,ci
,cj
,fx
,fy
);
88 di
=int(fx
*xsp
*wl_fgrid_2d
);dj
=int(fy
*ysp
*wl_fgrid_2d
);
90 // The indices (di,dj) tell us which worklist to use, to test the
91 // blocks in the optimal order. But we only store worklists for the
92 // eighth of the region where di, dj, and dk are all less than half the
93 // full grid. The rest of the cases are handled by symmetry. In this
94 // section, we detect for these cases, by reflecting high values of di,
95 // dj. For these cases, a mask is constructed in m1 and m2
96 // which is used to flip the worklist information when it is loaded.
99 m1
=127+(3<<21);m2
=1+(1<<21);di
=wl_fgrid_2d
-1-di
;if(di
<0) di
=0;
100 } else {m1
=m2
=0;mxs
=fx
;}
101 if(dj
>=wl_hgrid_2d
) {
103 m1
|=(127<<7)+(3<<24);m2
|=(1<<7)+(1<<24);dj
=wl_fgrid_2d
-1-dj
;if(dj
<0) dj
=0;
106 // Do a quick test to account for the case when the minimum radius is
107 // small enought that no other blocks need to be considered
108 rs
=con
.r_max_add(mrs
);
109 if(mxs
*mxs
>rs
&&mys
*mys
>rs
) return;
111 // Now compute which worklist we are going to use, and set radp and e to
112 // point at the right offsets
113 ij
=di
+wl_hgrid_2d
*dj
;
114 radp
=mrad
+ij
*wl_seq_length_2d
;
115 e
=(const_cast<unsigned int*> (wl
))+ij
*wl_seq_length_2d
;
117 // Read in how many items in the worklist can be tested without having to
118 // worry about writing to the mask
122 // If mrs is less than the minimum distance to any untested
123 // block, then we are done
124 if(con
.r_max_add(mrs
)<radp
[g
]) return;
127 // Load in a block off the worklist, permute it with the
128 // symmetry mask, and decode its position. These are all
129 // integer bit operations so they should run very fast.
132 dj
=(q
>>7)&127;dj
-=64;
134 // Check that the worklist position is in range
135 ei
=di
+i
;if(ei
<0||ei
>=hx
) continue;
136 ej
=dj
+j
;if(ej
<0||ej
>=hy
) continue;
138 // Call the compute_min_max_radius() function. This returns
139 // true if the minimum distance to the block is bigger than the
140 // current mrs, in which case we skip this block and move on.
141 // Otherwise, it computes the maximum distance to the block and
142 // returns it in crs.
143 if(compute_min_radius(di
,dj
,fx
,fy
,mrs
)) continue;
145 // Now compute which region we are going to loop over, adding a
146 // displacement for the periodic cases
147 ij
=con
.region_index(ci
,cj
,ei
,ej
,qx
,qy
,disp
);
149 // If mrs is bigger than the maximum distance to the block,
150 // then we have to test all particles in the block for
151 // intersections. Otherwise, we do additional checks and skip
152 // those particles which can't possibly intersect the block.
153 scan_all(ij
,x
-qx
,y
-qy
,di
,dj
,w
,mrs
);
156 // Update mask value and initialize queue
158 if(mv
==0) {reset_mask();mv
=1;}
159 int *qu_s
=qu
,*qu_e
=qu
;
161 while(g
<wl_seq_length_2d
-1) {
163 // If mrs is less than the minimum distance to any untested
164 // block, then we are done
165 if(con
.r_max_add(mrs
)<radp
[g
]) return;
168 // Load in a block off the worklist, permute it with the
169 // symmetry mask, and decode its position. These are all
170 // integer bit operations so they should run very fast.
173 dj
=(q
>>7)&127;dj
-=64;
175 // Compute the position in the mask of the current block. If
176 // this lies outside the mask, then skip it. Otherwise, mark
178 ei
=di
+i
;if(ei
<0||ei
>=hx
) continue;
179 ej
=dj
+j
;if(ej
<0||ej
>=hy
) continue;
183 // Skip this block if it is further away than the current
185 if(compute_min_radius(di
,dj
,fx
,fy
,mrs
)) continue;
187 // Now compute which region we are going to loop over, adding a
188 // displacement for the periodic cases
189 ij
=con
.region_index(ci
,cj
,ei
,ej
,qx
,qy
,disp
);
190 scan_all(ij
,x
-qx
,y
-qy
,di
,dj
,w
,mrs
);
192 if(qu_e
>qu_l
-8) add_list_memory(qu_s
,qu_e
);
193 scan_bits_mask_add(q
,mij
,ei
,ej
,qu_e
);
196 // Do a check to see if we've reached the radius cutoff
197 if(con
.r_max_add(mrs
)<radp
[g
]) return;
199 // We were unable to completely compute the cell based on the blocks in
200 // the worklist, so now we have to go block by block, reading in items
204 // Read the next entry of the queue
205 if(qu_s
==qu_l
) qu_s
=qu
;
206 ei
=*(qu_s
++);ej
=*(qu_s
++);
208 if(compute_min_radius(di
,dj
,fx
,fy
,mrs
)) continue;
210 ij
=con
.region_index(ci
,cj
,ei
,ej
,qx
,qy
,disp
);
212 scan_all(ij
,x
-qx
,y
-qy
,di
,dj
,w
,mrs
);
214 // Test the neighbors of the current block, and add them to the
215 // block list if they haven't already been tested
216 if((qu_s
<=qu_e
?(qu_l
-qu_e
)+(qu_s
-qu
):qu_s
-qu_e
)<18) add_list_memory(qu_s
,qu_e
);
217 add_to_mask(ei
,ej
,qu_e
);
221 /** Scans the six orthogonal neighbors of a given block and adds them to the
222 * queue if they haven't been considered already. It assumes that the queue
223 * will definitely have enough memory to add six entries at the end.
224 * \param[in] (ei,ej,ek) the block to consider.
225 * \param[in,out] qu_e a pointer to the end of the queue. */
226 template<class c_class_2d
>
227 inline void voro_compute_2d
<c_class_2d
>::add_to_mask(int ei
,int ej
,int *&qu_e
) {
228 unsigned int *mij
=mask
+ei
+hx
*ej
;
229 if(ej
>0) if(*(mij
-hx
)!=mv
) {if(qu_e
==qu_l
) qu_e
=qu
;*(mij
-hx
)=mv
;*(qu_e
++)=ei
;*(qu_e
++)=ej
-1;}
230 if(ei
>0) if(*(mij
-1)!=mv
) {if(qu_e
==qu_l
) qu_e
=qu
;*(mij
-1)=mv
;*(qu_e
++)=ei
-1;*(qu_e
++)=ej
;}
231 if(ei
<hx
-1) if(*(mij
+1)!=mv
) {if(qu_e
==qu_l
) qu_e
=qu
;*(mij
+1)=mv
;*(qu_e
++)=ei
+1;*(qu_e
++)=ej
;}
232 if(ej
<hy
-1) if(*(mij
+hx
)!=mv
) {if(qu_e
==qu_l
) qu_e
=qu
;*(mij
+hx
)=mv
;*(qu_e
++)=ei
;*(qu_e
++)=ej
+1;}
235 /** Scans a worklist entry and adds any blocks to the queue
236 * \param[in] (ei,ej,ek) the block to consider.
237 * \param[in,out] qu_e a pointer to the end of the queue. */
238 template<class c_class_2d
>
239 inline void voro_compute_2d
<c_class_2d
>::scan_bits_mask_add(unsigned int q
,unsigned int *mij
,int ei
,int ej
,int *&qu_e
) {
240 const unsigned int b1
=1<<21,b2
=1<<22,b3
=1<<24,b4
=1<<25;
242 if(ei
>0) {*(mij
-1)=mv
;*(qu_e
++)=ei
-1;*(qu_e
++)=ej
;}
243 if((q
&b1
)==0&&ei
<hx
-1) {*(mij
+1)=mv
;*(qu_e
++)=ei
+1;*(qu_e
++)=ej
;}
244 } else if((q
&b1
)==b1
&&ei
<hx
-1) {*(mij
+1)=mv
;*(qu_e
++)=ei
+1;*(qu_e
++)=ej
;}
246 if(ej
>0) {*(mij
-hx
)=mv
;*(qu_e
++)=ei
;*(qu_e
++)=ej
-1;}
247 if((q
&b3
)==0&&ej
<hy
-1) {*(mij
+hx
)=mv
;*(qu_e
++)=ei
;*(qu_e
++)=ej
+1;}
248 } else if((q
&b3
)==b3
&&ej
<hy
-1) {*(mij
+hx
)=mv
;*(qu_e
++)=ei
;*(qu_e
++)=ej
+1;}
251 /** This routine computes a Voronoi cell for a single particle in the
252 * container. It can be called by the user, but is also forms the core part of
253 * several of the main functions, such as store_cell_volumes(), print_all(),
254 * and the drawing routines. The algorithm constructs the cell by testing over
255 * the neighbors of the particle, working outwards until it reaches those
256 * particles which could not possibly intersect the cell. For maximum
257 * efficiency, this algorithm is divided into three parts. In the first
258 * section, the algorithm tests over the blocks which are in the immediate
259 * vicinity of the particle, by making use of one of the precomputed worklists.
260 * The code then continues to test blocks on the worklist, but also begins to
261 * construct a list of neighboring blocks outside the worklist which may need
262 * to be test. In the third section, the routine starts testing these
263 * neighboring blocks, evaluating whether or not a particle in them could
264 * possibly intersect the cell. For blocks that intersect the cell, it tests
265 * the particles in that block, and then adds the block neighbors to the list
266 * of potential places to consider.
267 * \param[in,out] c a reference to a voronoicell object.
268 * \param[in] ij the index of the block that the test particle is in.
269 * \param[in] s the index of the particle within the test block.
270 * \param[in] (ci,cj) the coordinates of the block that the test particle is
271 * in relative to the container data structure.
272 * \return False if the Voronoi cell was completely removed during the
273 * computation and has zero volume, true otherwise. */
274 template<class c_class_2d
>
275 template<class v_cell_2d
>
276 bool voro_compute_2d
<c_class_2d
>::compute_cell(v_cell_2d
&c
,int ij
,int s
,int ci
,int cj
) {
277 static const int count_list
[8]={7,11,15,19,26,35,45,59},*count_e
=count_list
+8;
278 double x
,y
,x1
,y1
,qx
=0,qy
=0;
279 double xlo
,ylo
,xhi
,yhi
,x2
,y2
,rs
;
280 int i
,j
,di
,dj
,ei
,ej
,f
,g
,l
,disp
;
281 double fx
,fy
,gxs
,gys
,*radp
;
282 unsigned int q
,*e
,*mij
;
284 // Initialize the Voronoi cell to fill the entire container
285 if(!con
.initialize_voronoicell(c
,ij
,s
,ci
,cj
,i
,j
,x
,y
,disp
)) return false;
287 if(!con
.boundary_cuts(c
,ij
,x
,y
)) return false;
290 int next_count
=3,*count_p
=(const_cast<int*> (count_list
));
292 // Test all particles in the particle's local region first
294 if(con
.skip(ij
,l
,x
,y
)) continue;
297 rs
=con
.r_scale(x1
*x1
+y1
*y1
,ij
,l
);
298 if(!c
.nplane(x1
,y1
,rs
,id
[ij
][l
])) return false;
302 if(con
.skip(ij
,l
,x
,y
)) {l
++;continue;}
305 rs
=con
.r_scale(x1
*x1
+y1
*y1
,ij
,l
);
306 if(!c
.nplane(x1
,y1
,rs
,id
[ij
][l
])) return false;
310 // Now compute the maximum distance squared from the cell center to a
311 // vertex. This is used to cut off the calculation since we only need
312 // to test out to twice this range.
313 mrs
=c
.max_radius_squared();
315 // Now compute the fractional position of the particle within its
316 // region and store it in (fx,fy,fz). We use this to compute an index
317 // (di,dj,dk) of which subregion the particle is within.
319 con
.frac_pos(x
,y
,ci
,cj
,fx
,fy
);
320 di
=int(fx
*xsp
*wl_fgrid_2d
);dj
=int(fy
*ysp
*wl_fgrid_2d
);
322 // The indices (di,dj,dk) tell us which worklist to use, to test the
323 // blocks in the optimal order. But we only store worklists for the
324 // eighth of the region where di, dj, and dk are all less than half the
325 // full grid. The rest of the cases are handled by symmetry. In this
326 // section, we detect for these cases, by reflecting high values of di,
327 // dj, and dk. For these cases, a mask is constructed in m1 and m2
328 // which is used to flip the worklist information when it is loaded.
329 if(di
>=wl_hgrid_2d
) {
331 m1
=127+(3<<21);m2
=1+(1<<21);di
=wl_fgrid_2d
-1-di
;if(di
<0) di
=0;
332 } else {m1
=m2
=0;gxs
=boxx
-fx
;}
333 if(dj
>=wl_hgrid_2d
) {
335 m1
|=(127<<7)+(3<<24);m2
|=(1<<7)+(1<<24);dj
=wl_fgrid_2d
-1-dj
;if(dj
<0) dj
=0;
339 // Now compute which worklist we are going to use, and set radp and e to
340 // point at the right offsets
341 ij
=di
+wl_hgrid_2d
*dj
;
342 radp
=mrad
+ij
*wl_seq_length_2d
;
343 e
=(const_cast<unsigned int*> (wl
))+ij
*wl_seq_length_2d
;
345 // Read in how many items in the worklist can be tested without having to
346 // worry about writing to the mask
350 // At the intervals specified by count_list, we recompute the
351 // maximum radius squared
353 mrs
=c
.max_radius_squared();
354 if(count_p
!=count_e
) next_count
=*(count_p
++);
357 // If mrs is less than the minimum distance to any untested
358 // block, then we are done
359 if(con
.r_ctest(radp
[g
],mrs
)) return true;
362 // Load in a block off the worklist, permute it with the
363 // symmetry mask, and decode its position. These are all
364 // integer bit operations so they should run very fast.
367 dj
=(q
>>7)&127;dj
-=64;
369 // Check that the worklist position is in range
370 ei
=di
+i
;if(ei
<0||ei
>=hx
) continue;
371 ej
=dj
+j
;if(ej
<0||ej
>=hy
) continue;
373 // Call the compute_min_max_radius() function. This returns
374 // true if the minimum distance to the block is bigger than the
375 // current mrs, in which case we skip this block and move on.
376 // Otherwise, it computes the maximum distance to the block and
377 // returns it in crs.
378 if(compute_min_max_radius(di
,dj
,fx
,fy
,gxs
,gys
,crs
,mrs
)) continue;
380 // Now compute which region we are going to loop over, adding a
381 // displacement for the periodic cases
382 ij
=con
.region_index(ci
,cj
,ei
,ej
,qx
,qy
,disp
);
383 if(!con
.boundary_cuts(c
,ij
,x
,y
)) return false;
385 // If mrs is bigger than the maximum distance to the block,
386 // then we have to test all particles in the block for
387 // intersections. Otherwise, we do additional checks and skip
388 // those particles which can't possibly intersect the block.
391 if(!con
.r_ctest(crs
,mrs
)) {
393 if(con
.skip(ij
,l
,x
,y
)) {l
++;continue;}
396 rs
=con
.r_scale(x1
*x1
+y1
*y1
,ij
,l
);
397 if(!c
.nplane(x1
,y1
,rs
,id
[ij
][l
])) return false;
402 if(con
.skip(ij
,l
,x
,y
)) {l
++;continue;}
406 if(con
.r_scale_check(rs
,mrs
,ij
,l
)&&!c
.nplane(x1
,y1
,rs
,id
[ij
][l
])) return false;
413 // If we reach here, we were unable to compute the entire cell using
414 // the first part of the worklist. This section of the algorithm
415 // continues the worklist, but it now starts preparing the mask that we
416 // need if we end up going block by block. We do the same as before,
417 // but we put a mark down on the mask for every block that's tested.
418 // The worklist also contains information about which neighbors of each
419 // block are not also on the worklist, and we start storing those
420 // points in a list in case we have to go block by block. Update the
421 // mask counter, and if it wraps around then reset the whole mask; that
422 // will only happen once every 2^32 tries.
424 if(mv
==0) {reset_mask();mv
=1;}
426 // Set the queue pointers
427 int *qu_s
=qu
,*qu_e
=qu
;
429 while(g
<wl_seq_length_2d
-1) {
431 // At the intervals specified by count_list, we recompute the
432 // maximum radius squared
434 mrs
=c
.max_radius_squared();
435 if(count_p
!=count_e
) next_count
=*(count_p
++);
438 // If mrs is less than the minimum distance to any untested
439 // block, then we are done
440 if(con
.r_ctest(radp
[g
],mrs
)) return true;
443 // Load in a block off the worklist, permute it with the
444 // symmetry mask, and decode its position. These are all
445 // integer bit operations so they should run very fast.
448 dj
=(q
>>7)&127;dj
-=64;
450 // Compute the position in the mask of the current block. If
451 // this lies outside the mask, then skip it. Otherwise, mark
453 ei
=di
+i
;if(ei
<0||ei
>=hx
) continue;
454 ej
=dj
+j
;if(ej
<0||ej
>=hy
) continue;
458 // Call the compute_min_max_radius() function. This returns
459 // true if the minimum distance to the block is bigger than the
460 // current mrs, in which case we skip this block and move on.
461 // Otherwise, it computes the maximum distance to the block and
462 // returns it in crs.
463 if(compute_min_max_radius(di
,dj
,fx
,fy
,gxs
,gys
,crs
,mrs
)) continue;
465 // Now compute which region we are going to loop over, adding a
466 // displacement for the periodic cases
467 ij
=con
.region_index(ci
,cj
,ei
,ej
,qx
,qy
,disp
);
468 if(!con
.boundary_cuts(c
,ij
,x
,y
)) return false;
470 // If mrs is bigger than the maximum distance to the block,
471 // then we have to test all particles in the block for
472 // intersections. Otherwise, we do additional checks and skip
473 // those particles which can't possibly intersect the block.
476 if(!con
.r_ctest(crs
,mrs
)) {
478 if(con
.skip(ij
,l
,x
,y
)) {l
++;continue;}
481 rs
=con
.r_scale(x1
*x1
+y1
*y1
,ij
,l
);
482 if(!c
.nplane(x1
,y1
,rs
,id
[ij
][l
])) return false;
487 if(con
.skip(ij
,l
,x
,y
)) {l
++;continue;}
491 if(con
.r_scale_check(rs
,mrs
,ij
,l
)&&!c
.nplane(x1
,y1
,rs
,id
[ij
][l
])) return false;
497 // If there might not be enough memory on the list for these
498 // additions, then add more
499 if(qu_e
>qu_l
-8) add_list_memory(qu_s
,qu_e
);
501 // Test the parts of the worklist element which tell us what
502 // neighbors of this block are not on the worklist. Store them
503 // on the block list, and mark the mask.
504 scan_bits_mask_add(q
,mij
,ei
,ej
,qu_e
);
507 // Do a check to see if we've reached the radius cutoff
508 if(con
.r_ctest(radp
[g
],mrs
)) return true;
510 // We were unable to completely compute the cell based on the blocks in
511 // the worklist, so now we have to go block by block, reading in items
515 // If we reached the end of the list memory loop back to the
517 if(qu_s
==qu_l
) qu_s
=qu
;
519 // Read in a block off the list, and compute the upper and lower
520 // coordinates in each of the three dimensions
521 ei
=*(qu_s
++);ej
=*(qu_s
++);
522 xlo
=(ei
-i
)*boxx
-fx
;xhi
=xlo
+boxx
;
523 ylo
=(ej
-j
)*boxy
-fy
;yhi
=ylo
+boxy
;
525 // Carry out plane tests to see if any particle in this block
526 // could possibly intersect the cell
529 if(corner_test(c
,xlo
,ylo
,xhi
,yhi
)) continue;
531 if(corner_test(c
,xlo
,yhi
,xhi
,ylo
)) continue;
533 if(edge_x_test(c
,xlo
,ylo
,yhi
)) continue;
537 if(corner_test(c
,xhi
,ylo
,xlo
,yhi
)) continue;
539 if(corner_test(c
,xhi
,yhi
,xlo
,ylo
)) continue;
541 if(edge_x_test(c
,xhi
,ylo
,yhi
)) continue;
545 if(edge_y_test(c
,xlo
,ylo
,xhi
)) continue;
547 if(edge_y_test(c
,xlo
,yhi
,xhi
)) continue;
548 } else voro_fatal_error("Compute cell routine revisiting central block, which should never\nhappen.",VOROPP_INTERNAL_ERROR
);
551 // Now compute the region that we are going to test over, and
552 // set a displacement vector for the periodic cases
553 ij
=con
.region_index(ci
,cj
,ei
,ej
,qx
,qy
,disp
);
554 if(!con
.boundary_cuts(c
,ij
,x
,y
)) return false;
556 // Loop over all the elements in the block to test for cuts. It
557 // would be possible to exclude some of these cases by testing
558 // against mrs, but this will probably not save time.
562 if(con
.skip(ij
,l
,x
,y
)) {l
++;continue;}
565 rs
=con
.r_scale(x1
*x1
+y1
*y1
,ij
,l
);
566 if(!c
.nplane(x1
,y1
,rs
,id
[ij
][l
])) return false;
571 // If there's not much memory on the block list then add more
572 if((qu_s
<=qu_e
?(qu_l
-qu_e
)+(qu_s
-qu
):qu_s
-qu_e
)<8) add_list_memory(qu_s
,qu_e
);
574 // Test the neighbors of the current block, and add them to the
575 // block list if they haven't already been tested
576 add_to_mask(ei
,ej
,qu_e
);
582 /** This function checks to see whether a particular block can possibly have
583 * any intersection with a Voronoi cell, for the case when the closest point
584 * from the cell center to the block is on an edge which points along the z
586 * \param[in,out] c a reference to a Voronoi cell.
587 * \param[in] (xl,yl) the relative x and y coordinates of the corner of the
588 * block closest to the cell center.
589 * \param[in] (xh,yh) the relative x and y coordinates of the corner of the
590 * block furthest away from the cell center.
591 * \return False if the block may intersect, true if does not. */
592 template<class c_class_2d
>
593 template<class v_cell_2d
>
594 inline bool voro_compute_2d
<c_class_2d
>::corner_test(v_cell_2d
&c
,double xl
,double yl
,double xh
,double yh
) {
595 con
.r_prime(xl
*xl
+yl
*yl
);
596 if(c
.plane_intersects_guess(xl
,yh
,con
.r_cutoff(xl
*xl
+yl
*yh
))) return false;
597 // if(c.plane_intersects(xl,yl,con.r_cutoff(xl*xl+yl*yl))) return false; XXX not needed?
598 if(c
.plane_intersects(xh
,yl
,con
.r_cutoff(xl
*xh
+yl
*yl
))) return false;
602 /** This function checks to see whether a particular block can possibly have
603 * any intersection with a Voronoi cell, for the case when the closest point
604 * from the cell center to the block is on a face aligned with the x direction.
605 * \param[in,out] c a reference to a Voronoi cell.
606 * \param[in] xl the minimum distance from the cell center to the face.
607 * \param[in] (y0,y1) the minimum and maximum relative y coordinates of the
609 * \param[in] (z0,z1) the minimum and maximum relative z coordinates of the
611 * \return False if the block may intersect, true if does not. */
612 template<class c_class_2d
>
613 template<class v_cell_2d
>
614 inline bool voro_compute_2d
<c_class_2d
>::edge_x_test(v_cell_2d
&c
,double xl
,double y0
,double y1
) {
616 if(c
.plane_intersects_guess(xl
,y0
,con
.r_cutoff(xl
*xl
))) return false;
617 if(c
.plane_intersects(xl
,y1
,con
.r_cutoff(xl
*xl
))) return false;
621 /** This function checks to see whether a particular block can possibly have
622 * any intersection with a Voronoi cell, for the case when the closest point
623 * from the cell center to the block is on a face aligned with the y direction.
624 * \param[in,out] c a reference to a Voronoi cell.
625 * \param[in] yl the minimum distance from the cell center to the face.
626 * \param[in] (x0,x1) the minimum and maximum relative x coordinates of the
628 * \param[in] (z0,z1) the minimum and maximum relative z coordinates of the
630 * \return False if the block may intersect, true if does not. */
631 template<class c_class_2d
>
632 template<class v_cell_2d
>
633 inline bool voro_compute_2d
<c_class_2d
>::edge_y_test(v_cell_2d
&c
,double x0
,double yl
,double x1
) {
635 if(c
.plane_intersects_guess(x0
,yl
,con
.r_cutoff(yl
*yl
))) return false;
636 if(c
.plane_intersects(x1
,yl
,con
.r_cutoff(yl
*yl
))) return false;
640 /** This routine checks to see whether a point is within a particular distance
641 * of a nearby region. If the point is within the distance of the region, then
642 * the routine returns true, and computes the maximum distance from the point
643 * to the region. Otherwise, the routine returns false.
644 * \param[in] (di,dj) the position of the nearby region to be tested,
645 * relative to the region that the point is in.
646 * \param[in] (fx,fy) the displacement of the point within its region.
647 * \param[in] (gxs,gys) the maximum squared distances from the point to the
648 * sides of its region.
649 * \param[out] crs a reference in which to return the maximum distance to the
650 * region (only computed if the routine returns positive).
651 * \param[in] mrs the distance to be tested.
652 * \return False if the region is further away than mrs, true if the region in
654 template<class c_class_2d
>
655 bool voro_compute_2d
<c_class_2d
>::compute_min_max_radius(int di
,int dj
,double fx
,double fy
,double gxs
,double gys
,double &crs
,double mrs
) {
663 if(con
.r_ctest(crs
,mrs
)) return true;
664 crs
+=bxsq
+2*xlo
*boxx
+2*ylo
*boxy
;
668 if(con
.r_ctest(crs
,mrs
)) return true;
669 crs
+=bxsq
+2*xlo
*boxx
-2*ylo
*boxy
;
671 if(con
.r_ctest(crs
,mrs
)) return true;
672 crs
+=gys
+boxx
*(2*xlo
+boxx
);
680 if(con
.r_ctest(crs
,mrs
)) return true;
681 crs
+=bxsq
-2*xlo
*boxx
+2*ylo
*boxy
;
685 if(con
.r_ctest(crs
,mrs
)) return true;
686 crs
+=bxsq
-2*xlo
*boxx
-2*ylo
*boxy
;
688 if(con
.r_ctest(crs
,mrs
)) return true;
689 crs
+=gys
+boxx
*(-2*xlo
+boxx
);
695 if(con
.r_ctest(crs
,mrs
)) return true;
696 crs
+=boxy
*(2*ylo
+boxy
);
700 if(con
.r_ctest(crs
,mrs
)) return true;
701 crs
+=boxy
*(-2*ylo
+boxy
);
702 } else voro_fatal_error("Min/max radius function called for central block, which should never\nhappen.",VOROPP_INTERNAL_ERROR
);
708 template<class c_class_2d
>
709 bool voro_compute_2d
<c_class_2d
>::compute_min_radius(int di
,int dj
,double fx
,double fy
,double mrs
) {
712 if(di
>0) {t
=di
*boxx
-fx
;crs
=t
*t
;}
713 else if(di
<0) {t
=(di
+1)*boxx
-fx
;crs
=t
*t
;}
716 if(dj
>0) {t
=dj
*boxy
-fy
;crs
+=t
*t
;}
717 else if(dj
<0) {t
=(dj
+1)*boxy
-fy
;crs
+=t
*t
;}
719 return crs
>con
.r_max_add(mrs
);
722 /** Adds memory to the queue.
723 * \param[in,out] qu_s a reference to the queue start pointer.
724 * \param[in,out] qu_e a reference to the queue end pointer. */
725 template<class c_class_2d
>
726 inline void voro_compute_2d
<c_class_2d
>::add_list_memory(int*& qu_s
,int*& qu_e
) {
728 int *qu_n
=new int[qu_size
],*qu_c
=qu_n
;
729 #if VOROPP_VERBOSE >=2
730 fprintf(stderr
,"List memory scaled up to %d\n",qu_size
);
733 while(qu_s
<qu_e
) *(qu_c
++)=*(qu_s
++);
735 while(qu_s
<qu_l
) *(qu_c
++)=*(qu_s
++);qu_s
=qu
;
736 while(qu_s
<qu_e
) *(qu_c
++)=*(qu_s
++);
744 // Explicit template instantiation
745 template voro_compute_2d
<container_2d
>::voro_compute_2d(container_2d
&,int,int);
746 template voro_compute_2d
<container_poly_2d
>::voro_compute_2d(container_poly_2d
&,int,int);
747 template voro_compute_2d
<container_boundary_2d
>::voro_compute_2d(container_boundary_2d
&,int,int);
748 template bool voro_compute_2d
<container_2d
>::compute_cell(voronoicell_2d
&,int,int,int,int);
749 template bool voro_compute_2d
<container_2d
>::compute_cell(voronoicell_neighbor_2d
&,int,int,int,int);
750 template void voro_compute_2d
<container_2d
>::find_voronoi_cell(double,double,int,int,int,particle_record_2d
&,double&);
751 template bool voro_compute_2d
<container_poly_2d
>::compute_cell(voronoicell_2d
&,int,int,int,int);
752 template bool voro_compute_2d
<container_poly_2d
>::compute_cell(voronoicell_neighbor_2d
&,int,int,int,int);
753 template void voro_compute_2d
<container_poly_2d
>::find_voronoi_cell(double,double,int,int,int,particle_record_2d
&,double&);
754 template bool voro_compute_2d
<container_boundary_2d
>::compute_cell(voronoicell_nonconvex_2d
&,int,int,int,int);
755 template bool voro_compute_2d
<container_boundary_2d
>::compute_cell(voronoicell_nonconvex_neighbor_2d
&,int,int,int,int);