Strip extra spaces from code.
[voro++.git] / branches / 2d / src / v_connect / v_compute_2d.cc
blob2201586a2e06cfb0b0885b295cc7edfbf75b38df
1 // Voro++, a 3D cell-based Voronoi library
2 //
3 // Author : Chris H. Rycroft (LBL / UC Berkeley)
4 // Email : chr@alum.mit.edu
5 // Date : August 30th 2011
7 /** \file 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"
16 namespace voro {
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) {
29 reset_mask();
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
42 * vector is within.
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++) {
49 x1=p[ij][ps*l]-x;
50 y1=p[ij][ps*l+1]-y;
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) {
70 double qx=0,qy=0,rs;
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.
86 unsigned int m1,m2;
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.
97 if(di>=wl_hgrid_2d) {
98 mxs=boxx-fx;
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) {
102 mys=boxy-fy;
103 m1|=(127<<7)+(3<<24);m2|=(1<<7)+(1<<24);dj=wl_fgrid_2d-1-dj;if(dj<0) dj=0;
104 } else mys=fy;
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
119 f=e[0];g=0;
120 do {
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;
125 g++;
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.
130 q=e[g];q^=m1;q+=m2;
131 di=q&127;di-=64;
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);
154 } while(g<f);
156 // Update mask value and initialize queue
157 mv++;
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;
166 g++;
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.
171 q=e[g];q^=m1;q+=m2;
172 di=q&127;di-=64;
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
177 // it.
178 ei=di+i;if(ei<0||ei>=hx) continue;
179 ej=dj+j;if(ej<0||ej>=hy) continue;
180 mij=mask+ei+hx*ej;
181 *mij=mv;
183 // Skip this block if it is further away than the current
184 // minimum radius
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
201 // off the list
202 while(qu_s!=qu_e) {
204 // Read the next entry of the queue
205 if(qu_s==qu_l) qu_s=qu;
206 ei=*(qu_s++);ej=*(qu_s++);
207 di=ei-i;dj=ej-j;
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;
241 if((q&b2)==b2) {
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;}
245 if((q&b4)==b4) {
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;
283 // Initialize the Voronoi cell to fill the entire container
284 if(!con.initialize_voronoicell(c,ij,s,ci,cj,i,j,x,y,disp)) return false;
285 con.r_init(ij,s);
286 if(!con.boundary_cuts(c,ij,x,y)) return false;
287 con.connect_to_cell(c,ij,s);
288 double crs,mrs;
289 int next_count=3,*count_p=(const_cast<int*> (count_list));
291 // Test all particles in the particle's local region first
292 for(l=0;l<s;l++) {
293 if(con.skip(ij,l,x,y)) continue;
294 x1=p[ij][ps*l]-x;
295 y1=p[ij][ps*l+1]-y;
296 rs=con.r_scale(x1*x1+y1*y1,ij,l);
297 if(!c.nplane(x1,y1,rs,id[ij][l])) return false;
299 l++;
300 while(l<co[ij]) {
301 if(con.skip(ij,l,x,y)) {l++;continue;}
302 x1=p[ij][ps*l]-x;
303 y1=p[ij][ps*l+1]-y;
304 rs=con.r_scale(x1*x1+y1*y1,ij,l);
305 if(!c.nplane(x1,y1,rs,id[ij][l])) return false;
306 l++;
309 // Now compute the maximum distance squared from the cell center to a
310 // vertex. This is used to cut off the calculation since we only need
311 // to test out to twice this range.
312 mrs=c.max_radius_squared();
314 // Now compute the fractional position of the particle within its
315 // region and store it in (fx,fy,fz). We use this to compute an index
316 // (di,dj,dk) of which subregion the particle is within.
317 unsigned int m1,m2;
318 con.frac_pos(x,y,ci,cj,fx,fy);
319 di=int(fx*xsp*wl_fgrid_2d);dj=int(fy*ysp*wl_fgrid_2d);
321 // The indices (di,dj,dk) tell us which worklist to use, to test the
322 // blocks in the optimal order. But we only store worklists for the
323 // eighth of the region where di, dj, and dk are all less than half the
324 // full grid. The rest of the cases are handled by symmetry. In this
325 // section, we detect for these cases, by reflecting high values of di,
326 // dj, and dk. For these cases, a mask is constructed in m1 and m2
327 // which is used to flip the worklist information when it is loaded.
328 if(di>=wl_hgrid_2d) {
329 gxs=fx;
330 m1=127+(3<<21);m2=1+(1<<21);di=wl_fgrid_2d-1-di;if(di<0) di=0;
331 } else {m1=m2=0;gxs=boxx-fx;}
332 if(dj>=wl_hgrid_2d) {
333 gys=fy;
334 m1|=(127<<7)+(3<<24);m2|=(1<<7)+(1<<24);dj=wl_fgrid_2d-1-dj;if(dj<0) dj=0;
335 } else gys=boxy-fy;
336 gxs*=gxs;gys*=gys;
338 // Now compute which worklist we are going to use, and set radp and e to
339 // point at the right offsets
340 ij=di+wl_hgrid_2d*dj;
341 radp=mrad+ij*wl_seq_length_2d;
342 e=(const_cast<unsigned int*> (wl))+ij*wl_seq_length_2d;
344 // Read in how many items in the worklist can be tested without having to
345 // worry about writing to the mask
346 f=e[0];g=0;
347 do {
349 // At the intervals specified by count_list, we recompute the
350 // maximum radius squared
351 if(g==next_count) {
352 mrs=c.max_radius_squared();
353 if(count_p!=count_e) next_count=*(count_p++);
356 // If mrs is less than the minimum distance to any untested
357 // block, then we are done
358 if(con.r_ctest(radp[g],mrs)) return true;
359 g++;
361 // Load in a block off the worklist, permute it with the
362 // symmetry mask, and decode its position. These are all
363 // integer bit operations so they should run very fast.
364 q=e[g];q^=m1;q+=m2;
365 di=q&127;di-=64;
366 dj=(q>>7)&127;dj-=64;
368 // Check that the worklist position is in range
369 ei=di+i;if(ei<0||ei>=hx) continue;
370 ej=dj+j;if(ej<0||ej>=hy) continue;
372 // Call the compute_min_max_radius() function. This returns
373 // true if the minimum distance to the block is bigger than the
374 // current mrs, in which case we skip this block and move on.
375 // Otherwise, it computes the maximum distance to the block and
376 // returns it in crs.
377 if(compute_min_max_radius(di,dj,fx,fy,gxs,gys,crs,mrs)) continue;
379 // Now compute which region we are going to loop over, adding a
380 // displacement for the periodic cases
381 ij=con.region_index(ci,cj,ei,ej,qx,qy,disp);
382 if(!con.boundary_cuts(c,ij,x,y)) return false;
384 // If mrs is bigger than the maximum distance to the block,
385 // then we have to test all particles in the block for
386 // intersections. Otherwise, we do additional checks and skip
387 // those particles which can't possibly intersect the block.
388 if(co[ij]>0) {
389 l=0;x2=x-qx;y2=y-qy;
390 if(!con.r_ctest(crs,mrs)) {
391 do {
392 if(con.skip(ij,l,x,y)) {l++;continue;}
393 x1=p[ij][ps*l]-x2;
394 y1=p[ij][ps*l+1]-y2;
395 rs=con.r_scale(x1*x1+y1*y1,ij,l);
396 if(!c.nplane(x1,y1,rs,id[ij][l])) return false;
397 l++;
398 } while (l<co[ij]);
399 } else {
400 do {
401 if(con.skip(ij,l,x,y)) {l++;continue;}
402 x1=p[ij][ps*l]-x2;
403 y1=p[ij][ps*l+1]-y2;
404 rs=x1*x1+y1*y1;
405 if(con.r_scale_check(rs,mrs,ij,l)&&!c.nplane(x1,y1,rs,id[ij][l])) return false;
406 l++;
407 } while (l<co[ij]);
410 } while(g<f);
412 // If we reach here, we were unable to compute the entire cell using
413 // the first part of the worklist. This section of the algorithm
414 // continues the worklist, but it now starts preparing the mask that we
415 // need if we end up going block by block. We do the same as before,
416 // but we put a mark down on the mask for every block that's tested.
417 // The worklist also contains information about which neighbors of each
418 // block are not also on the worklist, and we start storing those
419 // points in a list in case we have to go block by block. Update the
420 // mask counter, and if it wraps around then reset the whole mask; that
421 // will only happen once every 2^32 tries.
422 mv++;
423 if(mv==0) {reset_mask();mv=1;}
425 // Set the queue pointers
426 int *qu_s=qu,*qu_e=qu;
428 while(g<wl_seq_length_2d-1) {
430 // At the intervals specified by count_list, we recompute the
431 // maximum radius squared
432 if(g==next_count) {
433 mrs=c.max_radius_squared();
434 if(count_p!=count_e) next_count=*(count_p++);
437 // If mrs is less than the minimum distance to any untested
438 // block, then we are done
439 if(con.r_ctest(radp[g],mrs)) return true;
440 g++;
442 // Load in a block off the worklist, permute it with the
443 // symmetry mask, and decode its position. These are all
444 // integer bit operations so they should run very fast.
445 q=e[g];q^=m1;q+=m2;
446 di=q&127;di-=64;
447 dj=(q>>7)&127;dj-=64;
449 // Compute the position in the mask of the current block. If
450 // this lies outside the mask, then skip it. Otherwise, mark
451 // it.
452 ei=di+i;if(ei<0||ei>=hx) continue;
453 ej=dj+j;if(ej<0||ej>=hy) continue;
454 mij=mask+ei+hx*ej;
455 *mij=mv;
457 // Call the compute_min_max_radius() function. This returns
458 // true if the minimum distance to the block is bigger than the
459 // current mrs, in which case we skip this block and move on.
460 // Otherwise, it computes the maximum distance to the block and
461 // returns it in crs.
462 if(compute_min_max_radius(di,dj,fx,fy,gxs,gys,crs,mrs)) continue;
464 // Now compute which region we are going to loop over, adding a
465 // displacement for the periodic cases
466 ij=con.region_index(ci,cj,ei,ej,qx,qy,disp);
467 if(!con.boundary_cuts(c,ij,x,y)) return false;
469 // If mrs is bigger than the maximum distance to the block,
470 // then we have to test all particles in the block for
471 // intersections. Otherwise, we do additional checks and skip
472 // those particles which can't possibly intersect the block.
473 if(co[ij]>0) {
474 l=0;x2=x-qx;y2=y-qy;
475 if(!con.r_ctest(crs,mrs)) {
476 do {
477 if(con.skip(ij,l,x,y)) {l++;continue;}
478 x1=p[ij][ps*l]-x2;
479 y1=p[ij][ps*l+1]-y2;
480 rs=con.r_scale(x1*x1+y1*y1,ij,l);
481 if(!c.nplane(x1,y1,rs,id[ij][l])) return false;
482 l++;
483 } while (l<co[ij]);
484 } else {
485 do {
486 if(con.skip(ij,l,x,y)) {l++;continue;}
487 x1=p[ij][ps*l]-x2;
488 y1=p[ij][ps*l+1]-y2;
489 rs=x1*x1+y1*y1;
490 if(con.r_scale_check(rs,mrs,ij,l)&&!c.nplane(x1,y1,rs,id[ij][l])) return false;
491 l++;
492 } while (l<co[ij]);
496 // If there might not be enough memory on the list for these
497 // additions, then add more
498 if(qu_e>qu_l-8) add_list_memory(qu_s,qu_e);
500 // Test the parts of the worklist element which tell us what
501 // neighbors of this block are not on the worklist. Store them
502 // on the block list, and mark the mask.
503 scan_bits_mask_add(q,mij,ei,ej,qu_e);
506 // Do a check to see if we've reached the radius cutoff
507 if(con.r_ctest(radp[g],mrs)) return true;
509 // We were unable to completely compute the cell based on the blocks in
510 // the worklist, so now we have to go block by block, reading in items
511 // off the list
512 while(qu_s!=qu_e) {
514 // If we reached the end of the list memory loop back to the
515 // start
516 if(qu_s==qu_l) qu_s=qu;
518 // Read in a block off the list, and compute the upper and lower
519 // coordinates in each of the three dimensions
520 ei=*(qu_s++);ej=*(qu_s++);
521 xlo=(ei-i)*boxx-fx;xhi=xlo+boxx;
522 ylo=(ej-j)*boxy-fy;yhi=ylo+boxy;
524 // Carry out plane tests to see if any particle in this block
525 // could possibly intersect the cell
526 if(ei>i) {
527 if(ej>j) {
528 if(corner_test(c,xlo,ylo,xhi,yhi)) continue;
529 } else if(ej<j) {
530 if(corner_test(c,xlo,yhi,xhi,ylo)) continue;
531 } else {
532 if(edge_x_test(c,xlo,ylo,yhi)) continue;
534 } else if(ei<i) {
535 if(ej>j) {
536 if(corner_test(c,xhi,ylo,xlo,yhi)) continue;
537 } else if(ej<j) {
538 if(corner_test(c,xhi,yhi,xlo,ylo)) continue;
539 } else {
540 if(edge_x_test(c,xhi,ylo,yhi)) continue;
542 } else {
543 if(ej>j) {
544 if(edge_y_test(c,xlo,ylo,xhi)) continue;
545 } else if(ej<j) {
546 if(edge_y_test(c,xlo,yhi,xhi)) continue;
547 } else voro_fatal_error("Compute cell routine revisiting central block, which should never\nhappen.",VOROPP_INTERNAL_ERROR);
550 // Now compute the region that we are going to test over, and
551 // set a displacement vector for the periodic cases
552 ij=con.region_index(ci,cj,ei,ej,qx,qy,disp);
553 if(!con.boundary_cuts(c,ij,x,y)) return false;
555 // Loop over all the elements in the block to test for cuts. It
556 // would be possible to exclude some of these cases by testing
557 // against mrs, but this will probably not save time.
558 if(co[ij]>0) {
559 l=0;x2=x-qx;y2=y-qy;
560 do {
561 if(con.skip(ij,l,x,y)) {l++;continue;}
562 x1=p[ij][ps*l]-x2;
563 y1=p[ij][ps*l+1]-y2;
564 rs=con.r_scale(x1*x1+y1*y1,ij,l);
565 if(!c.nplane(x1,y1,rs,id[ij][l])) return false;
566 l++;
567 } while (l<co[ij]);
570 // If there's not much memory on the block list then add more
571 if((qu_s<=qu_e?(qu_l-qu_e)+(qu_s-qu):qu_s-qu_e)<8) add_list_memory(qu_s,qu_e);
573 // Test the neighbors of the current block, and add them to the
574 // block list if they haven't already been tested
575 add_to_mask(ei,ej,qu_e);
578 return true;
581 /** This function checks to see whether a particular block can possibly have
582 * any intersection with a Voronoi cell, for the case when the closest point
583 * from the cell center to the block is on an edge which points along the z
584 * direction.
585 * \param[in,out] c a reference to a Voronoi cell.
586 * \param[in] (xl,yl) the relative x and y coordinates of the corner of the
587 * block closest to the cell center.
588 * \param[in] (xh,yh) the relative x and y coordinates of the corner of the
589 * block furthest away from the cell center.
590 * \return False if the block may intersect, true if does not. */
591 template<class c_class_2d>
592 template<class v_cell_2d>
593 inline bool voro_compute_2d<c_class_2d>::corner_test(v_cell_2d &c,double xl,double yl,double xh,double yh) {
594 con.r_prime(xl*xl+yl*yl);
595 if(c.plane_intersects_guess(xl,yh,con.r_cutoff(xl*xl+yl*yh))) return false;
596 // if(c.plane_intersects(xl,yl,con.r_cutoff(xl*xl+yl*yl))) return false; XXX not needed?
597 if(c.plane_intersects(xh,yl,con.r_cutoff(xl*xh+yl*yl))) return false;
598 return true;
601 /** This function checks to see whether a particular block can possibly have
602 * any intersection with a Voronoi cell, for the case when the closest point
603 * from the cell center to the block is on a face aligned with the x direction.
604 * \param[in,out] c a reference to a Voronoi cell.
605 * \param[in] xl the minimum distance from the cell center to the face.
606 * \param[in] (y0,y1) the minimum and maximum relative y coordinates of the
607 * block.
608 * \param[in] (z0,z1) the minimum and maximum relative z coordinates of the
609 * block.
610 * \return False if the block may intersect, true if does not. */
611 template<class c_class_2d>
612 template<class v_cell_2d>
613 inline bool voro_compute_2d<c_class_2d>::edge_x_test(v_cell_2d &c,double xl,double y0,double y1) {
614 con.r_prime(xl*xl);
615 if(c.plane_intersects_guess(xl,y0,con.r_cutoff(xl*xl))) return false;
616 if(c.plane_intersects(xl,y1,con.r_cutoff(xl*xl))) return false;
617 return true;
620 /** This function checks to see whether a particular block can possibly have
621 * any intersection with a Voronoi cell, for the case when the closest point
622 * from the cell center to the block is on a face aligned with the y direction.
623 * \param[in,out] c a reference to a Voronoi cell.
624 * \param[in] yl the minimum distance from the cell center to the face.
625 * \param[in] (x0,x1) the minimum and maximum relative x coordinates of the
626 * block.
627 * \param[in] (z0,z1) the minimum and maximum relative z coordinates of the
628 * block.
629 * \return False if the block may intersect, true if does not. */
630 template<class c_class_2d>
631 template<class v_cell_2d>
632 inline bool voro_compute_2d<c_class_2d>::edge_y_test(v_cell_2d &c,double x0,double yl,double x1) {
633 con.r_prime(yl*yl);
634 if(c.plane_intersects_guess(x0,yl,con.r_cutoff(yl*yl))) return false;
635 if(c.plane_intersects(x1,yl,con.r_cutoff(yl*yl))) return false;
636 return true;
639 /** This routine checks to see whether a point is within a particular distance
640 * of a nearby region. If the point is within the distance of the region, then
641 * the routine returns true, and computes the maximum distance from the point
642 * to the region. Otherwise, the routine returns false.
643 * \param[in] (di,dj) the position of the nearby region to be tested,
644 * relative to the region that the point is in.
645 * \param[in] (fx,fy) the displacement of the point within its region.
646 * \param[in] (gxs,gys) the maximum squared distances from the point to the
647 * sides of its region.
648 * \param[out] crs a reference in which to return the maximum distance to the
649 * region (only computed if the routine returns positive).
650 * \param[in] mrs the distance to be tested.
651 * \return False if the region is further away than mrs, true if the region in
652 * within mrs.*/
653 template<class c_class_2d>
654 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) {
655 double xlo,ylo;
656 if(di>0) {
657 xlo=di*boxx-fx;
658 crs=xlo*xlo;
659 if(dj>0) {
660 ylo=dj*boxy-fy;
661 crs+=ylo*ylo;
662 if(con.r_ctest(crs,mrs)) return true;
663 crs+=bxsq+2*xlo*boxx+2*ylo*boxy;
664 } else if(dj<0) {
665 ylo=(dj+1)*boxy-fy;
666 crs+=ylo*ylo;
667 if(con.r_ctest(crs,mrs)) return true;
668 crs+=bxsq+2*xlo*boxx-2*ylo*boxy;
669 } else {
670 if(con.r_ctest(crs,mrs)) return true;
671 crs+=gys+boxx*(2*xlo+boxx);
673 } else if(di<0) {
674 xlo=(di+1)*boxx-fx;
675 crs=xlo*xlo;
676 if(dj>0) {
677 ylo=dj*boxy-fy;
678 crs+=ylo*ylo;
679 if(con.r_ctest(crs,mrs)) return true;
680 crs+=bxsq-2*xlo*boxx+2*ylo*boxy;
681 } else if(dj<0) {
682 ylo=(dj+1)*boxy-fy;
683 crs+=ylo*ylo;
684 if(con.r_ctest(crs,mrs)) return true;
685 crs+=bxsq-2*xlo*boxx-2*ylo*boxy;
686 } else {
687 if(con.r_ctest(crs,mrs)) return true;
688 crs+=gys+boxx*(-2*xlo+boxx);
690 } else {
691 if(dj>0) {
692 ylo=dj*boxy-fy;
693 crs=ylo*ylo;
694 if(con.r_ctest(crs,mrs)) return true;
695 crs+=boxy*(2*ylo+boxy);
696 } else if(dj<0) {
697 ylo=(dj+1)*boxy-fy;
698 crs=ylo*ylo;
699 if(con.r_ctest(crs,mrs)) return true;
700 crs+=boxy*(-2*ylo+boxy);
701 } else voro_fatal_error("Min/max radius function called for central block, which should never\nhappen.",VOROPP_INTERNAL_ERROR);
702 crs+=gxs;
704 return false;
707 template<class c_class_2d>
708 bool voro_compute_2d<c_class_2d>::compute_min_radius(int di,int dj,double fx,double fy,double mrs) {
709 double t,crs;
711 if(di>0) {t=di*boxx-fx;crs=t*t;}
712 else if(di<0) {t=(di+1)*boxx-fx;crs=t*t;}
713 else crs=0;
715 if(dj>0) {t=dj*boxy-fy;crs+=t*t;}
716 else if(dj<0) {t=(dj+1)*boxy-fy;crs+=t*t;}
718 return crs>con.r_max_add(mrs);
721 /** Adds memory to the queue.
722 * \param[in,out] qu_s a reference to the queue start pointer.
723 * \param[in,out] qu_e a reference to the queue end pointer. */
724 template<class c_class_2d>
725 inline void voro_compute_2d<c_class_2d>::add_list_memory(int*& qu_s,int*& qu_e) {
726 qu_size<<=1;
727 int *qu_n=new int[qu_size],*qu_c=qu_n;
728 #if VOROPP_VERBOSE >=2
729 fprintf(stderr,"List memory scaled up to %d\n",qu_size);
730 #endif
731 if(qu_s<=qu_e) {
732 while(qu_s<qu_e) *(qu_c++)=*(qu_s++);
733 } else {
734 while(qu_s<qu_l) *(qu_c++)=*(qu_s++);qu_s=qu;
735 while(qu_s<qu_e) *(qu_c++)=*(qu_s++);
737 delete [] qu;
738 qu_s=qu=qu_n;
739 qu_l=qu+qu_size;
740 qu_e=qu_c;
748 // Explicit template instantiation
749 template voro_compute_2d<container_2d>::voro_compute_2d(container_2d&,int,int);
750 template voro_compute_2d<container_poly_2d>::voro_compute_2d(container_poly_2d&,int,int);
751 template voro_compute_2d<container_boundary_2d>::voro_compute_2d(container_boundary_2d&,int,int);
752 template bool voro_compute_2d<container_2d>::compute_cell(voronoicell_2d&,int,int,int,int);
753 template bool voro_compute_2d<container_2d>::compute_cell(voronoicell_neighbor_2d&,int,int,int,int);
754 template void voro_compute_2d<container_2d>::find_voronoi_cell(double,double,int,int,int,particle_record_2d&,double&);
755 template bool voro_compute_2d<container_poly_2d>::compute_cell(voronoicell_2d&,int,int,int,int);
756 template bool voro_compute_2d<container_poly_2d>::compute_cell(voronoicell_neighbor_2d&,int,int,int,int);
757 template void voro_compute_2d<container_poly_2d>::find_voronoi_cell(double,double,int,int,int,particle_record_2d&,double&);
758 template bool voro_compute_2d<container_boundary_2d>::compute_cell(voronoicell_nonconvex_2d&,int,int,int,int);
759 template bool voro_compute_2d<container_boundary_2d>::compute_cell(voronoicell_nonconvex_neighbor_2d&,int,int,int,int);