Reset platonic code.
[voro++.git] / branches / 2d_boundary / src / container_2d.cc
blob7033b97b6386aee9d720d216605ce87997e52ff2
1 /** \file container_2d.cc
2 * \brief Function implementations for the container_2d class. */
4 #include "container_2d.hh"
6 #include <iostream>
7 #include <cstring>
8 #include <math.h>
9 using namespace std;
11 /** The class constructor sets up the geometry of container, initializing the
12 * minimum and maximum coordinates in each direction, and setting whether each
13 * direction is periodic or not. It divides the container into a rectangular
14 * grid of blocks, and allocates memory for each of these for storing particle
15 * positions and IDs.
16 * \param[in] (ax_,bx_) the minimum and maximum x coordinates.
17 * \param[in] (ay_,by_) the minimum and maximum y coordinates.
18 * \param[in] (nx_,ny_) the number of grid blocks in each of the three
19 * coordinate directions.
20 * \param[in] (xperiodic_,yperiodic_) flags setting whether the container is periodic
21 * in each coordinate direction.
22 * \param[in] init_mem the initial memory allocation for each block. */
23 container_2d::container_2d(double ax_,double bx_,double ay_,
24 double by_,int nx_,int ny_,bool xperiodic_,bool yperiodic_,bool convex_,int init_mem)
25 : ax(ax_), bx(bx_), ay(ay_), by(by_), boxx((bx_-ax_)/nx_), boxy((by_-ay_)/ny_),
26 xsp(1/boxx), ysp(1/boxy), nx(nx_), ny(ny_), nxy(nx*ny),
27 xperiodic(xperiodic_), yperiodic(yperiodic_), convex(convex_),
28 co(new int[nxy]), mem(new int[nxy]), id(new int*[nxy]),
29 wid(new int*[nxy]), p(new double*[nxy]), nlab(new unsigned int*[nxy]),
30 plab(new int**[nxy]), soi(NULL), noofbnds(0), bnds_size(init_bnds_size),
31 bnds(new double[2*bnds_size]), edb(new int[50]), bndpts(new int*[nxy]) {
32 int l;
33 debug=false;
35 for(l=0;l<nxy;l++) co[l]=0;
36 for(l=0;l<nxy;l++) mem[l]=init_mem;
37 for(l=0;l<nxy;l++) {
38 id[l]=new int[init_mem];
39 bndpts[l]=new int[init_mem];
41 for(l=0;l<nxy;l++) p[l]=new double[2*init_mem];
42 for(l=0;l<nxy;l++) {
43 wid[l]=new int[6];
44 wid[l][0]=1;
46 for(l=0;l<nxy;l++) nlab[l]=new unsigned int[init_mem];
47 for(l=0;l<nxy;l++) plab[l]=new int*[init_mem];
50 /** The container destructor frees the dynamically allocated memory. */
51 container_2d::~container_2d() {
52 int l;
54 // Clear "sphere of influence" array if it has been allocated
55 if(soi!=NULL) delete [] soi;
57 // Delete the boundary arrays
58 delete [] edb;
59 delete [] bnds;
61 // Deallocate the block-level arrays
62 for(l=nxy-1;l>=0;l--) delete [] plab[l];
63 for(l=nxy-1;l>=0;l--) delete [] nlab[l];
64 for(l=nxy-1;l>=0;l--) delete [] wid[l];
65 for(l=nxy-1;l>=0;l--) delete [] p[l];
66 for(l=nxy-1;l>=0;l--) delete [] id[l];
68 // Delete the two-dimensional arrays
69 delete [] plab;
70 delete [] nlab;
71 delete [] p;
72 delete [] wid;
73 delete [] id;
74 delete [] mem;
75 delete [] co;
78 /** Put a particle into the correct region of the container.
79 * \param[in] n the numerical ID of the inserted particle.
80 * \param[in] (x,y) the position vector of the inserted particle. */
81 void container_2d::put(int n,double x,double y, int boundloc) {
82 int ij;
83 if(put_locate_block(ij,x,y)) {
84 id[ij][co[ij]]=n;
85 bndpts[ij][co[ij]]=boundloc;
86 double *pp(p[ij]+2*co[ij]++);
87 *(pp++)=x;*pp=y;
91 /** This routine takes a particle position vector, tries to remap it into the
92 * primary domain. If successful, it computes the region into which it can be
93 * stored and checks that there is enough memory within this region to store
94 * it.
95 * \param[out] ij the region index.
96 * \param[in,out] (x,y) the particle position, remapped into the primary
97 * domain if necessary.
98 * \return True if the particle can be successfully placed into the container,
99 * false otherwise. */
100 inline bool container_2d::put_locate_block(int &ij,double &x,double &y) {
101 if(put_remap(ij,x,y)) {
102 if(co[ij]==mem[ij]) add_particle_memory(ij);
103 return true;
105 #if VOROPP_REPORT_OUT_OF_BOUNDS ==1
106 fprintf(stderr,"Out of bounds: (x,y)=(%g,%g)\n",x,y);
107 #endif
108 return false;
111 /** Takes a particle position vector and computes the region index into which
112 * it should be stored. If the container is periodic, then the routine also
113 * maps the particle position to ensure it is in the primary domain. If the
114 * container is not periodic, the routine bails out.
115 * \param[out] ij the region index.
116 * \param[in,out] (x,y) the particle position, remapped into the primary
117 * domain if necessary.
118 * \return True if the particle can be successfully placed into the container,
119 * false otherwise. */
120 inline bool container_2d::put_remap(int &ij,double &x,double &y) {
121 int l;
123 ij=step_int((x-ax)*xsp);
124 if(xperiodic) {l=step_mod(ij,nx);x+=boxx*(l-ij);ij=l;}
125 else if(ij<0||ij>=nx) return false;
127 int j(step_int((y-ay)*ysp));
128 if(yperiodic) {l=step_mod(j,ny);y+=boxy*(l-j);j=l;}
129 else if(j<0||j>=ny) return false;
131 ij+=nx*j;
132 return true;
135 /** This does the additional set-up for non-convex containers. We assume that
136 * **p, **id, *co, *mem, *bnds, and noofbnds have already been setup. We then
137 * proceed to setup **wid, *soi, and THE PROBLEM POINTS BOOLEAN ARRAY.
138 * This algorithm keeps the importing seperate from the set-up */
139 void container_2d::setup(){
140 probpts=new bool[noofbnds];
141 extpts=new bool[noofbnds];
142 double lx, ly, cx, cy, nx, ny;//last (x,y), current (x,y), next (x,y)
143 int widl=1, maxwid=1, fwid=1, nwid, lwid;
144 bool first=true;
146 tmp=tmpp=new int[3*init_temp_label_size];
147 tmpe=tmp+3*init_temp_label_size;
149 while(widl!=noofbnds){
150 extpts[widl]=first;
151 cx=bnds[2*widl]; cy=bnds[2*widl+1];
152 nwid=edb[2*widl]; lwid=edb[2*widl+1];
153 lx=bnds[lwid*2]; ly=bnds[lwid*2+1];
154 nx=bnds[2*nwid]; ny=bnds[2*nwid+1];
156 tag_walls(cx,cy,nx,ny,widl);
157 semi_circle_labelling(cx,cy,nx,ny,widl);
159 //make sure that the cos(angle)>1 and the angle points inward
160 if(((((lx-cx)*(nx-cx))+((ly-cy)*(ny-cy)))>tolerance) &&
161 (crossproductz(lx-cx,ly-cy,nx-cx,ny-cy)==1)){
162 probpts[widl]=true;
163 }else{
164 probpts[widl]=false;
166 widl=edb[2*widl];
167 if(widl>maxwid) maxwid=widl;
168 if(widl==fwid){
169 widl=maxwid+1;
170 fwid=widl;
171 maxwid++;
172 first=false;
177 //at this point *tmp is completed RUN CHRIS' ALGORITH TO CREATE *SOI and *SOIP
178 create_label_table();
180 // Remove temporary array
181 delete [] tmp;
184 /** Given two points, tags all the computational boxes that the line segment
185 * specified by the two points
186 * goes through. param[in] (x1,y1) this is one point
187 * \param[in] (x2,y2) this is the other point.
188 * \param[in] wid this is the wall id bnds[2*wid] is the x index of the first
189 * vertex in the c-c direction. */
190 void container_2d::tag_walls(double x1, double y1, double x2, double y2, int wid){
191 int cgrid=0, cgridx=0, cgridy=0, fgrid=0;
192 double slope, slopec, cx=ax+boxx, cy=ay+boxy, gridx, gridy;
194 if(x2<x1){
195 double tmpx=x1, tmpy=y1;
196 x1=x2; y1=y2; x2=tmpx; y2=tmpy;
198 while(cy<y1){
199 cgrid+=nx;
200 cy+=boxy;
201 cgridy++;
202 }while(cx<x1){
203 cgrid++;
204 cx+=boxx;
205 cgridx++;
207 cy=ay+boxy; cx=ax+boxx;
208 while(cy<y2){
209 fgrid+=nx;
210 cy+=boxy;
211 }while(cx<x2){
212 fgrid++;
213 cx+=boxx;
214 }if(cx==x2 && x2!=x1 && cx!=ax+(boxx*nx)) fgrid++;
215 if((x2-x1)==0){
216 while(cgrid!=fgrid){
217 tag(wid,cgrid);
218 if(y1<y2) cgrid+=nx;
219 if(y1>y2) cgrid-=nx;
221 tag(wid,cgrid);
222 return;
225 slope=((y2-y1)/(x2-x1));
226 if(slope>0 && cy==y2 && cy!=ay+(boxy*ny)) fgrid+=nx;
227 if(slope==0){
228 for(int i=cgrid; i<=fgrid; i++){
229 tag(wid,i);
230 if(x1>=x2){
231 tag(fgrid,wid);
232 return;
237 if(slope>0){
238 gridx=ax+((1+cgridx)*boxx);
239 gridy=ay+((1+cgridy)*boxy);
241 while(cgrid!=fgrid){
242 tag(wid,cgrid);
243 if(gridx==x1){
244 cgrid++;
245 gridx+=boxx;
246 continue;
247 }if(gridy==y1){
248 cgrid+=nx;
249 gridy+=boxy;
250 continue;
252 slopec=((gridy-y1)/(gridx-x1));
253 if(slope>slopec){
254 cgrid+=nx;
255 x1+=((1/slope)*(gridy-y1));
256 y1=gridy;
257 cgridy++;
258 gridy+=boxy;
259 } else if(slope<slopec){
260 cgrid++;
261 y1+=(slope*(gridx-x1));
262 x1=gridx;
263 cgridx++;
264 gridx+=boxx;
265 } else if(slope==slopec){
266 cgrid+=(nx+1);
267 x1=gridx;
268 y1=gridy;
269 cgridx++;
270 cgridy++;
271 tag(wid,cgrid-1);
272 tag(wid,cgrid-nx);
273 gridx+=boxx;
274 gridy+=boxy;
276 if (x1>=x2){
277 tag(fgrid, wid);
278 return;
282 tag(wid,cgrid);
283 return;
286 if(slope<0){
287 gridx=ax+((1+cgridx)*boxx);
288 gridy=ay+(cgridy*boxy);
290 while(cgrid!=fgrid){
291 tag(wid, cgrid);
292 if(gridx==x1){
293 cgrid++;
294 gridx+=boxx;
295 continue;
296 }if(gridy==y1){
297 cgrid-=nx;
298 gridy-=boxy;
299 continue;
301 slopec=((gridy-y1)/(gridx-x1));
302 if(slope>slopec){
303 cgrid++;
304 cgridx++;
305 y1+=(slope*(gridx-x1));
306 x1=gridx;
307 gridx+=boxx;
308 } else if(slope<slopec){
309 cgrid-=nx;
310 cgridy--;
311 x1+=((1/slope)*(gridy-y1));
312 y1=gridy;
313 gridy-=boxy;
314 } else if(slope==slopec){
315 cgrid-=(nx-1);
316 x1=gridx;
317 y1=gridy;
318 gridx+=boxx;
319 gridy-=boxy;
320 cgridx++;
321 cgridy++;
322 tag(wid,cgrid-1);
323 tag(wid,cgrid+nx);
326 if (x1>=x2){
327 tag(fgrid, wid);
328 return;
331 tag(wid,cgrid);
335 /* A helper function for semi-circle-labelling. If crossproductz(x1,y1,particlex,particley)>0 then the particle is on the appropriate side of the wall to be tagged. */
336 int container_2d::crossproductz(double x1, double y1, double x2, double y2){
337 if(((x1*y2)-(x2*y1))>0) return 1;
338 else return -1;
341 /* Tags particles that are within a semicircle (on the appropriate side) of a boundary.
342 * \param[in] (x1,y1) the start point of the wall segment, arranged so that it
343 * is the first point reached in the counter-clockwise
344 * direction.
345 * \param[in] (x2,y2) the end points of the wall segment. */
346 void container_2d::semi_circle_labelling(double x1, double y1, double x2, double y2, int bid){
347 cout << " \n semi-circle-labelling\n bid=" << bid << "\n (x1,y1)(x2,y2)=(" << x1 << "," << y1
348 << ")(" << x2 << "," << y2 << ") \n" << endl;
349 voropp_loop_2d l(*this);
350 double xmin,xmax,ymin,ymax, radius=(dist(x1,y1,x2,y2)/2),dummy1,dummy2,midx=(x1+x2)/2,
351 midy=(y1+y2)/2;
352 double cpx,cpy; //these stand for "current particle x" and "current particle y"
353 int box; //this holds the current computational box that we're in.
354 printf("SCC %g %g %g %g\n",x1,y1,x2,y2);
356 // First we will initialize the voropp_loop_2d object to a rectangle
357 // containing all the points we are interested in plus some extraneous
358 // points. The larger the slope between (x1,y1) and (x2,y2) is, the
359 // more extraneous points we get- might change this later on.
360 if(x1!=x2) {
361 if(x1>x2) {
362 xmin=x2;
363 xmax=x1;
364 ymin=min(y1,y2);
365 ymax=((y1+y2)/2)+radius;
366 } else {
367 xmin=x1;
368 xmax=x2;
369 ymax=max(y1,y2);
370 ymin=((y1+y2)/2)-radius;
372 } else {
373 if(y1>y2) {
374 ymax=y1;
375 ymin=y2;
376 xmax=x1;
377 xmin=x1-radius;
378 } else {
379 ymax=y2;
380 ymin=y1;
381 xmin=x1;
382 xmax=x1+radius;
386 // Now loop through all the particles in the boxes we found. Tagging
387 // the ones that are within radius of (midx,midy) and are on the
388 // appropriate side of the wall.
389 box=l.init(midx,midy,radius, dummy1,dummy2);
390 do {
391 for(int j=0;j<co[box];j++){
392 cpx=p[box][2*j];
393 cpy=p[box][2*j+1];
394 cout << "\n now checking (x,y)=(" << cpx <<"," <<cpy<<")\n"<<endl;
395 if(dist(midx,midy,cpx,cpy)<=radius&&
396 crossproductz((x1-x2),(y1-y2),(cpx-x2),(cpy-y2))>0&&
397 (cpx!=x1||cpy==y1)&&(cpx!=x2||cpy!=y2)) {
398 if(tmpp==tmpe) add_temporary_label_memory();
399 *(tmpp++)=box;
400 *(tmpp++)=j;
401 *(tmpp++)=bid;
402 printf("JKL %g %g\n",cpx,cpy);
403 cout << "WE ADDED ONE!" << endl;
406 } while((box=l.inc(dummy1,dummy2))!=-1);
409 void container_2d::create_label_table() {
410 int ij,q,*pp,tlab(0);
412 // Clear label counters
413 for(ij=0;ij<nxy;ij++) for(q=0;q<co[ij];q++) nlab[ij][q]=0;
415 // Increment label counters
416 for(pp=tmp;pp<tmpp;pp+=3) {nlab[*pp][pp[1]]++;tlab++;}
418 // Check for case of no labels at all (which may be common)
419 if(tlab==0) {
420 #if VOROPP_VERBOSE >=2
421 fputs("No labels needed",stderr);
422 #endif
423 return;
426 // If there was already a table from a previous call, remove it
427 if(soi!=NULL) delete [] soi;
429 // Allocate the label array, and set up pointers from each particle
430 // to the corresponding location
431 pp=soi=new int[tlab];
432 for(ij=0;ij<nxy;ij++) for(q=0;q<co[ij];pp+=nlab[ij][q++]) plab[ij][q]=pp;
434 // Fill in the label entries
435 for(pp=tmp;pp<tmpp;pp+=3) *(plab[*pp][pp[1]]++)=pp[2];
437 // Reset the label pointers
438 pp=soi;
439 for(ij=0;ij<nxy;ij++) for(q=0;q<co[ij];pp+=nlab[ij][q++]) plab[ij][q]=pp;
442 /** Draws the boundaries. (Note: this currently assumes that each boundary loop
443 * is a continuous block in the bnds array, which will be true for the import
444 * function. However, it may not be true in other cases, in which case this
445 * routine would have to be extended.) */
446 void container_2d::draw_boundary(FILE *fp) {
447 int i;
449 for(i=0;i<noofbnds;i++) {
450 fprintf(fp,"%d %g %g\n",i,bnds[2*i],bnds[2*i+1]);
452 // If a loop is detected, than complete the loop in the output file
453 // and insert a newline
454 if(edb[i]<i) fprintf(fp,"%g %g\n\n",bnds[2*edb[i]],bnds[2*edb[i]+1]);
458 /** Increases the size of the temporary label memory. */
459 void container_2d::add_temporary_label_memory() {
460 int size(tmpe-tmp);
461 size<<=1;
462 if(size>3*max_temp_label_size)
463 voropp_fatal_error("Absolute temporary label memory allocation exceeded",VOROPP_MEMORY_ERROR);
464 #if VOROPP_VERBOSE >=3
465 fprintf(stderr,"Temporary label memory in region scaled up to %d\n",size);
466 #endif
467 int *ntmp(new int[size]),*tp(tmp);tmpp=ntmp;
468 while(tp<tmpe) *(tmpp++)=*(tp++);
469 delete [] tmp;
470 tmp=ntmp;tmpe=tmp+size;
473 /** Increases the memory allocation for the boundary points. */
474 void container_2d::add_boundary_memory() {
475 int i,size(bnds_size<<1);
476 if(size>max_bnds_size)
477 voropp_fatal_error("Absolute bounds memory allocation exceeded",VOROPP_MEMORY_ERROR);
478 #if VOROPP_VERBOSE >=3
479 fprintf(stderr,"Bounds memory scaled up to %d\n",size);
480 #endif
482 // Reallocate the boundary vertex information
483 double *nbnds(new double[2*size]);
484 for(i=0;i<2*noofbnds;i++) nbnds[i]=bnds[i];
485 delete [] nbnds;bnds=nbnds;
487 // Reallocate the edge information
488 int *nedb(new int[2*size]);
489 for(i=0;i<noofbnds;i++) nedb[i]=edb[i];
490 delete [] edb;edb=nedb;
492 /** given two particles, a generator and a potential cutting particle, this returns true iff the cutting
493 particle and the generator are on the same side of all relevant walls. **/
495 bool container_2d::OKCuttingParticle(double gx, double gy, int gbox, int gindex, double cx, double cy, int cbox, int cindex, bool boundary, int bid){
496 int cwid, nwid;
497 double widx1, widy1, widx2, widy2;
499 if(boundary){
500 int nwid=edb[2*bid];
501 int lwid=edb[2*bid+1];
502 double nx=bnds[2*nwid]-gx; double ny=bnds[2*nwid+1]-gy;
503 double lx=bnds[2*lwid]-gx; double ly=bnds[2*lwid+1]-gy;
504 double nxp=-ny, nyp=nx, lxp=ly, lyp=-lx;
507 // if(extpts[bid]){
508 if(crossproductz(lx,ly,nx,ny)==1){
509 nxp*=-1; nyp*=-1; lxp*=-1; lyp*=-1;
510 if((((lxp*(cx-gx))+(lyp*(cy-gy)))>0) && (((nxp*(cx-gx))+(nyp*(cy-gy)))>0)){
512 return false;
514 }else{
515 if((((lxp*(cx-gx))+(lyp*(cy-gy)))<0) || (((nxp*(cx-gx))+(nyp*(cy-gy)))<0)){
516 return false;
519 /* }else{
520 nxp=-ny; nyp=nx; lxp=ly; lyp=-lx;
521 if(crossproductz(lx,ly,nx,ny)==1){
523 if((((lxp*(cx-gx))+(lyp*(cy-gy)))<tolerance) || (((nxp*(cx-gx))+(nyp*(cy-gy)))<tolerance)){
524 return false;
526 }else{
527 nxp*=-1; nyp*=-1; lxp*=-1; lyp*=-1;
529 if((((lxp*(cx-gx))+(lyp*(cy-gy)))>tolerance) && (((nxp*(cx-gx))+(nyp*(cy-gy)))>tolerance)){
530 return false;
534 */ }
540 for(int i=0;i<(signed int)nlab[cbox][cindex];i++){
541 cwid=plab[cbox][cindex][i];
542 widx1=bnds[2*cwid];
543 widy1=bnds[2*cwid+1];
544 nwid=edb[2*cwid];
545 widx2=bnds[2*nwid];
546 widy2=bnds[2*nwid+1];
547 if(((cx==widx1 && cy==widy1) || (cx==widx2 && cy==widy2)) || (boundary && ((gx==widx1 && gy==widy1) || (gx==widx2 && gy==widy2)))) continue;
548 if(crossproductz(gx-widx1,gy-widy1,widx2-widx1,widy2-widy1)!=
549 crossproductz(cx-widx1,cy-widy1,widx2-widx1,widy2-widy1)) return false;
551 return true;
554 /** Increase memory for a particular region.
555 * \param[in] i the index of the region to reallocate. */
556 void container_2d::add_particle_memory(int i) {
557 int l;
558 mem[i]<<=1;
559 if(mem[i]>max_particle_memory)
560 voropp_fatal_error("Absolute maximum particle memory allocation exceeded",VOROPP_MEMORY_ERROR);
561 #if VOROPP_VERBOSE >=3
562 fprintf(stderr,"Particle memory in region %d scaled up to %d\n",i,mem[i]);
563 #endif
565 // Create new arrays and copy across the data
566 int *idp(new int[mem[i]]);
567 int *bndptsp(new int[mem[i]]);
568 for(l=0;l<co[i];l++) {
569 idp[l]=id[i][l];
570 bndptsp[l]=id[i][l];
572 double *pp(new double[2*mem[i]]);
573 for(l=0;l<2*co[i];l++) pp[l]=p[i][l];
574 unsigned int *nlabp(new unsigned int[mem[i]]);
575 for(l=0;l<co[i];l++) nlabp[l]=nlab[i][l];
576 int **plabp(new int*[mem[i]]);
577 for(l=0;l<co[i];l++) plabp[l]=plab[i][l];
579 // Delete the original arrays and update the pointers
580 delete [] id[i];id[i]=idp;
581 delete [] bndpts[i]; bndpts[i]=bndptsp;
582 delete [] p[i];p[i]=pp;
583 delete [] nlab[i];nlab[i]=nlabp;
584 delete [] plab[i];plab[i]=plabp;
587 void container_2d::add_edb_memory(int i){
588 int *edbp(new int[50*(i+1)]);
589 for(int l=0;l<(50*i);l++){
590 edbp[l]=edb[l];
592 delete [] edb; edb=edbp;
594 /** Imports a list of particles from an input stream.
595 * \param[in] fp a file handle to read from. */
596 void container_2d::import(FILE *fp) {
597 int i,sm;
598 bool boundary(false);
599 double x,y;
600 char *buf(new char[512]);
602 while(fgets(buf,512,fp)!=NULL) {
603 if(strcmp(buf,"#Start\n")==0||strcmp(buf,"# Start\n")==0) {
605 // Check that two consecutive start tokens haven't been
606 // encountered
607 if(boundary) voropp_fatal_error("File import error - two start tokens found",VOROPP_FILE_ERROR);
608 // Remember this position in the boundary array to
609 // connect the end of the loop
610 sm=noofbnds;
611 boundary=true;
613 } else if(strcmp(buf,"#End\n")==0||strcmp(buf,"# End\n")==0) {
615 // Check that two consecutive end tokens haven't been
616 // encountered
617 if(!boundary) voropp_fatal_error("File import error - two end tokens found",VOROPP_FILE_ERROR);
618 // Assuming that at least one point was read, set the edge
619 // to connect back to the start point
620 edb[2*sm+1]=noofbnds-1;
621 edb[2*(noofbnds-1)]=sm;
622 boundary=false;
623 } else {
625 // Try and read three entries from the line
626 if(sscanf(buf,"%d %lg %lg",&i,&x,&y)!=3) voropp_fatal_error("File import error #1",VOROPP_FILE_ERROR);
627 if(!boundary) put(i,x,y, -1);
628 if(boundary) {
629 put(i,x,y,noofbnds);
630 // Unless this is the start of a boundary loop,
631 // connect the previous vertex to this one
632 if(noofbnds%25==0){
633 add_edb_memory(noofbnds/25);
635 if(noofbnds!=sm){
636 edb[(noofbnds-1)*2]=noofbnds;
637 edb[(noofbnds*2)+1]=noofbnds-1;
639 bnds[2*noofbnds]=x;
640 bnds[2*(noofbnds++)+1]=y;
645 if(!feof(fp)) voropp_fatal_error("File import error #2",VOROPP_FILE_ERROR);
646 delete [] buf;
649 /** Clears a container of particles. */
650 void container_2d::clear() {
651 for(int* cop=co;cop<co+nxy;cop++) *cop=0;
654 /** Dumps all the particle positions and IDs to a file.
655 * \param[in] fp the file handle to write to. */
656 void container_2d::draw_particles(FILE *fp) {
657 int ij,q;
658 for(ij=0;ij<nxy;ij++) for(q=0;q<co[ij];q++)
659 fprintf(fp,"%d %g %g\n",id[ij][q],p[ij][2*q],p[ij][2*q+1]);
662 /** Dumps all the particle positions in POV-Ray format.
663 * \param[in] fp the file handle to write to. */
664 void container_2d::draw_particles_pov(FILE *fp) {
665 int ij,q;
666 for(ij=0;ij<nxy;ij++) for(q=0;q<co[ij];q++)
667 fprintf(fp,"// id %d\nsphere{<%g,%g,0>,s\n",id[ij][q],p[ij][2*q],p[ij][2*q+1]);
670 /** Computes the Voronoi cells for all particles and saves the output in
671 * gnuplot format.
672 * \param[in] fp a file handle to write to. */
673 void container_2d::draw_cells_gnuplot(FILE *fp) {
674 int i,j,ij=0,q;
675 double x,y;
676 voronoicell_2d c;
677 for(j=0;j<ny;j++) for(i=0;i<nx;i++,ij++) for(q=0;q<co[ij];q++) {
678 x=p[ij][2*q];y=p[ij][2*q+1];
679 if(compute_cell_sphere(c,i,j,ij,q,x,y)) c.draw_gnuplot(x,y,fp);
683 /** Computes the Voronoi cells for all particles within a rectangular box, and
684 * saves the output in POV-Ray format.
685 * \param[in] fp a file handle to write to. */
686 void container_2d::draw_cells_pov(FILE *fp) {
687 int i,j,ij=0,q;
688 double x,y;
689 voronoicell_2d c;
690 for(j=0;j<ny;j++) for(i=0;i<nx;i++,ij++) for(q=0;q<co[ij];q++) {
691 x=p[ij][2*q];y=p[ij][2*q+1];
692 if(compute_cell_sphere(c,i,j,ij,q,x,y)) {
693 fprintf(fp,"// cell %d\n",id[ij][q]);
694 c.draw_pov(x,y,0,fp);
699 /** Computes the Voronoi cells for all particles in the container, and for each
700 * cell, outputs a line containing custom information about the cell structure.
701 * The output format is specified using an input string with control sequences
702 * similar to the standard C printf() routine.
703 * \param[in] format the format of the output lines, using control sequences to
704 * denote the different cell statistics.
705 * \param[in] fp a file handle to write to. */
706 void container_2d::print_custom(const char *format,FILE *fp) {
707 int i,j,ij=0,q;
708 double x,y;
709 voronoicell_2d c;
710 for(j=0;j<ny;j++) for(i=0;i<nx;i++,ij++) for(q=0;q<co[ij];q++) {
711 x=p[ij][2*q];y=p[ij][2*q+1];
712 if(compute_cell_sphere(c,i,j,ij,q,x,y)) c.output_custom(format,id[ij][q],x,y,default_radius,fp);
716 /** Initializes a voronoicell_2d class to fill the entire container.
717 * \param[in] c a reference to a voronoicell_2d class.
718 * \param[in] (x,y) the position of the particle that . */
719 //NEED TO CHANGE
720 bool container_2d::initialize_voronoicell(voronoicell_2d &c,double x,double y) {
722 double x1,x2,y1,y2;
723 if(xperiodic) x1=-(x2=0.5*(bx-ax));else {x1=ax-x;x2=bx-x;}
724 if(yperiodic) y1=-(y2=0.5*(by-ay));else {y1=ay-y;y2=by-y;}
725 c.init(x1,x2,y1,y2);
726 return true;
730 bool container_2d::initialize_voronoicell_nonconvex(voronoicell_2d &c, double x, double y, int bid){
731 double* bnds_loc=new double[noofbnds*2];
732 int fbid=bid, cntbndno=1;
733 bnds_loc[0]=0; bnds_loc[1]=0;
734 bid=edb[2*bid];
736 while(bid!=fbid){
737 if(bid==(noofbnds)) bid=0;
738 bnds_loc[cntbndno*2]=bnds[bid*2]-x;
739 bnds_loc[cntbndno*2+1]=bnds[bid*2+1]-y;
740 cntbndno++;
741 bid=edb[2*bid];
743 c.init_nonconvex(bnds_loc, cntbndno);
744 return true;
751 void container_2d::container_projection(double x, double y, double &ccx, double &ccy, double &nx, double &ny){
752 double ccs, slope, distx, disty;
753 while(true){
754 if((ccx-x)==0 && (ccy>y)){
755 ccy=by; ccx=x;
756 nx=ax; ny=by;
757 break;
758 }else if((ccx-x)==0 && (ccy<y)){
759 ccy=ay; ccx=x;
760 nx=bx; ny=ay;
761 break;
763 ccs= (ccy-y)/(ccx-x);
764 if((ccs==0) && (ccx>x)){
765 ccx=bx; ccy=y;
766 nx=bx; ny=by;
767 break;
768 }else if((ccs==0) && (ccx<x)){
769 ccx=ax; ccy=y;
770 nx=ax; ny=ay;
771 break;
773 if(ccs>0){
774 if(ccx>x){
775 slope=(by-y)/(bx-x);
776 if(ccs==slope){
777 ccx=bx; ccy=by;
778 nx=ax; ny=by;
779 break;
780 }else if(ccs>slope){
781 disty=by-y;
782 ccy=by;
783 ccx=x+(disty/ccs);
784 nx=ax; ny=by;
785 break;
786 }else{
787 distx=bx-x;
788 ccx=bx;
789 ccy=y+(ccs*distx);
790 nx=bx; ny=by;
791 break;
793 }else{
794 slope=(ay-y)/(ax-x);
795 if(ccs==slope){
796 ccx=ax; ccy=ay;
797 nx=bx; ny=ay;
798 break;
799 }else if(ccs>slope){
800 disty=ay-y;
801 ccy=ay;
802 ccx=x+(disty/ccs);
803 nx=bx;ny=ay;
804 break;
805 }else{
806 distx=ax-x;
807 ccx=ax;
808 ccy=y+(ccs*distx);
809 nx=ax; ny=ay;
810 break;
813 }else{
814 if(ccx>x){
815 slope=(ay-y)/(bx-x);
816 if(ccs==slope){
817 ccx=bx;
818 ccy=ay;
819 nx=bx; ny=by;
820 break;
821 }else if(ccs>slope){
822 distx=bx-x;
823 ccx=bx;
824 ccy=y+(ccs*distx);
825 nx=bx; ny=by;
826 break;
827 }else{
828 disty=ay-y;
829 ccy=ay;
830 ccx=x+(disty/ccs);
831 nx=bx; ny=ay;
832 break;
834 }else{
835 slope=(by-y)/(ax-x);
836 if(ccs==slope){
837 ccx=ax;
838 ccy=by;
839 nx=ax; ny=ay;
840 break;
841 }else if(ccs>slope){
842 distx=ax-x;
843 ccx=ax;
844 ccy=y+(distx*ccs);
845 nx=ax; ny=ay;
846 break;
847 }else{
848 disty=by-y;
849 ccy=by;
850 ccx=x+(disty/ccs);
851 nx=ax; ny=by;
852 break;
859 bool container_2d::initialize_voronoicell_boundary(voronoicell_2d &c, double x, double y, int bid){
860 double* bnds_loc=new double[14];
861 double ccx, ccy, cx, cy, nx, ny, dum1, dum2;
862 int noofbndsloc, ccwid, cwid;
863 ccwid=edb[2*bid];
864 cwid=edb[2*bid+1];
865 ccx=bnds[2*ccwid]; ccy=bnds[2*ccwid+1];
866 cx=bnds[2*cwid]; cy=bnds[2*cwid+1];
867 //compute the counter-clockwise and clockwise projection;
868 container_projection(x,y,ccx,ccy, nx, ny);
869 container_projection(x,y,cx,cy, dum1, dum2);
872 //construct bnds_loc;
873 bnds_loc[0]=0; bnds_loc[1]=0;
874 bnds_loc[2]=ccx-x; bnds_loc[3]=ccy-y;
875 noofbndsloc=2;
876 while(true){
877 if(nx==ax && ny==ay){
878 if(cx==ax && (fabs(cy-ay)<fabs(ccy-ay))){
879 bnds_loc[2*noofbndsloc]=cx-x;
880 bnds_loc[2*noofbndsloc+1]=cy-y;
881 noofbndsloc++;
882 c.init_nonconvex(bnds_loc,noofbndsloc);
883 return true;
884 }else{
885 bnds_loc[2*noofbndsloc]=nx-x;
886 bnds_loc[2*noofbndsloc+1]=ny-y;
887 noofbndsloc++;
888 ccx=ax; ccy=ay; nx=bx; ny=ay;
889 continue;
891 }else if(nx==bx && ny==ay){
892 if(cy==ay && (fabs(cx-bx)<fabs(ccx-bx))){
893 bnds_loc[2*noofbndsloc]=cx-x;
894 bnds_loc[2*noofbndsloc+1]=cy-y;
895 noofbndsloc++;
896 c.init_nonconvex(bnds_loc,noofbndsloc);
897 return true;
898 }else{
899 bnds_loc[2*noofbndsloc]=nx-x;
900 bnds_loc[2*noofbndsloc+1]=ny-y;
901 noofbndsloc++;
902 ccx=bx; ccy=ay; nx=bx; ny=by;
903 continue;
905 }else if(nx==bx && ny==by){
906 if(cx==bx && (fabs(cy-by)<fabs(ccy-by))){
907 bnds_loc[2*noofbndsloc]=cx-x;
908 bnds_loc[2*noofbndsloc+1]=cy-y;
909 noofbndsloc++;
910 c.init_nonconvex(bnds_loc,noofbndsloc);
911 return true;
912 }else{
913 bnds_loc[2*noofbndsloc]=nx-x;
914 bnds_loc[2*noofbndsloc+1]=ny-y;
915 noofbndsloc++;
916 nx=ax; ny=by; ccx=bx; ccy=by;
917 continue;
919 }else if(nx==ax && ny==by){
920 if(cy==by && (fabs(cx-ax)<fabs(ccx-ax))){
921 bnds_loc[2*noofbndsloc]=cx-x;
922 bnds_loc[2*noofbndsloc+1]=cy-y;
923 noofbndsloc++;
924 c.init_nonconvex(bnds_loc,noofbndsloc);
925 return true;
926 }else{
927 bnds_loc[2*noofbndsloc]=nx-x;
928 bnds_loc[2*noofbndsloc+1]=ny-y;
929 noofbndsloc++;
930 nx=ax; ny=ay; ccx=ax; ccy=by;
932 }else{
933 cout << "major error in init_boundary" << endl;
946 /** Computes all Voronoi cells and sums their areas.
947 * \return The computed area. */
948 double container_2d::sum_cell_areas() {
949 int i,j,ij=0,q;
950 double x,y,sum=0;
951 voronoicell_2d c;
952 for(j=0;j<ny;j++) for(i=0;i<nx;i++,ij++) for(q=0;q<co[ij];q++) {
953 x=p[ij][2*q];y=p[ij][2*q+1];
954 if(compute_cell_sphere(c,i,j,ij,q,x,y)) sum+=c.cell_area();
956 return sum;
959 /** Computes all of the Voronoi cells in the container, but does nothing
960 * with the output. It is useful for measuring the pure computation time
961 * of the Voronoi algorithm, without any additional calculations such as
962 * volume evaluation or cell output. */
963 void container_2d::compute_all_cells() {
964 int i,j,ij=0,q;
965 for(j=0;j<ny;j++){
966 for(i=0;i<nx;i++,ij++){
967 for(q=0;q<co[ij];q++){
968 voronoicell_2d c;
969 cout << " " << i << " " << j << " " << q << " " << endl;
970 compute_cell_sphere(c,i,j,ij,q);
976 //Reports the state of bndpts, plab, nlab, wid, and edb after setup() has been run.
977 void container_2d::debug_output(){
978 int lid;
980 cout << "problem points \n";
981 for(int i=0; i<nxy; i++){
982 for(int j=0; j<co[i]; j++){
983 lid=bndpts[i][j];
984 if(lid!=-1 && probpts[lid]) cout << lid << ", (x,y)=(" << p[i][2*j] << "," << p[i][2*j+1] << ") \n" << endl;
988 cout << "semi_circle_labelling \n";
989 for(int i=0; i<nxy; i++){
990 for(int j=0; j<co[i]; j++){
991 cout << " \t computational box= " << i << "\n \t \t paricle_no= " << id[i][j] << "(x,y)=(" << p[i][2*j] << "," << p[i][2*j+1] << ")" << "\n \t \t \t wall_ids=" << endl;
992 for(int q=0;q<(signed int)nlab[i][j];q++){
993 cout << "\n \t \t \t \t " << plab[i][j][q] << " " << endl;
998 cout << "wall_tags \n";
999 for(int i=0; i<nxy; i++){
1000 cout << " \t computational box # " << i << " wall tags \n ";
1001 for(int j=1; j<wid[i][0] ; j++){
1002 cout << "\t \t" << wid[i][j] << " \n";
1006 for (int i=0; i<noofbnds; i++){
1007 cout << "\n wid=" << i << "\n lwid=" << edb[2*i+1] << "\n nwid=" << edb[2*i] << endl;
1011 void container_2d::initial_cut_nonconvex(voronoicell_2d &c,double x, double y, int bid){
1012 int wid1, wid2;
1013 double widx1, widy1, widx2, widy2, rs;
1014 wid1=edb[2*bid]; wid2=edb[2*bid+1];
1015 widx1=bnds[2*wid1]-x; widy1=bnds[2*wid1+1]-y;
1016 widx2=bnds[2*wid2]-x; widy2=bnds[2*wid2+1]-y;
1017 c.initialize_regions(widx1, widy1, widx2, widy2, extpts[bid]);
1018 rs=widx1*widx1+widy1*widy1;
1019 c.halfplane(widx1,widy1,rs, -widy2, widx2);
1020 rs=widx2*widx2+widy2*widy2;
1021 c.halfplane(widx2,widy2,rs, widy1, -widx1);
1023 void container_2d::initial_cut(voronoicell_2d &c,double x, double y, int bid){
1024 int wid1, wid2;
1025 double widx1, widy1, widx2, widy2, rs;
1026 wid1=edb[2*bid]; wid2=edb[2*bid+1];
1027 widx1=bnds[2*wid1]-x; widy1=bnds[2*wid1+1]-y;
1028 widx2=bnds[2*wid2]-x; widy2=bnds[2*wid2+1]-y;
1029 rs=widx1*widx1+widy1*widy1;
1030 c.plane(widx1,widy1,rs);
1031 rs=widx2*widx2+widy2*widy2;
1032 c.plane(widx2,widy2,rs);
1035 /** This routine computes the Voronoi cell for a give particle, by successively
1036 * testing over particles within larger and larger concentric circles. This
1037 * routine is simple and fast, although it may not work well for anisotropic
1038 * arrangements of particles.
1039 * \param[in,out] c a reference to a voronoicell object.
1040 * \param[in] (i,j) the coordinates of the block that the test particle is
1041 * in.
1042 * \param[in] ij the index of the block that the test particle is in, set to
1043 * i+nx*j.
1044 * \param[in] s the index of the particle within the test block.
1045 * \param[in] (x,y) the coordinates of the particle.
1046 * \return False if the Voronoi cell was completely removed during the
1047 * computation and has zero volume, true otherwise. */
1048 bool container_2d::compute_cell_sphere(voronoicell_2d &c,int i,int j,int ij,int s,double x,double y) {
1049 // This length scale determines how large the spherical shells should
1050 // be, and it should be set to approximately the particle diameter
1051 const double length_scale=0.5*sqrt((bx-ax)*(by-ay)/(nx*ny));
1052 bool problem_point=false, boundary=false;
1053 double x1,y1,qx,qy,lr=0,lrs=0,ur,urs,rs,wx1,wy1,wx2,wy2;
1054 int q,t,bid, widc, widc2;
1055 voropp_loop_2d l(*this);
1057 //Check if the current point is a problem point, if it is we will need to use plane-nonconvex, and init_nonconvex
1058 bid=bndpts[ij][s];
1059 if(bid!=-1 && probpts[bid]){
1060 if(!initialize_voronoicell_boundary(c,x,y,bid)) return false;
1061 problem_point=true;
1062 boundary=true;
1063 initial_cut_nonconvex(c,x,y,bid);
1065 }else if(bid!=-1){
1066 if(!initialize_voronoicell_boundary(c,x,y,bid)) return false;
1067 initial_cut(c,x,y,bid);
1068 boundary=true;
1070 }else{
1071 if(!initialize_voronoicell(c,x,y)) return false;
1073 // Now the cell is cut by testing neighboring particles in concentric
1074 // shells. Once the test shell becomes twice as large as the Voronoi
1075 // cell we can stop testing.
1076 while(lrs<c.max_radius_squared()) {
1077 ur=lr+0.5*length_scale;urs=ur*ur;
1078 t=l.init(x,y,ur,qx,qy);
1079 do {
1080 //CUT BY ALL WALLS PASSING THROUGH THE COMPUTATIONAL BOX HERE, USE WID
1081 for(int b=1;b<wid[t][0];b++){
1082 widc=wid[t][b];
1083 if(widc>(noofbnds-1)) continue;
1084 wx1=bnds[2*widc]-x; wy1=bnds[2*widc+1]-y;
1086 widc2=edb[2*widc];
1087 wx2=bnds[2*widc2]-x; wy2=bnds[2*widc2+1]-y;
1088 if((wx1==0 && wy1==0) || (wx2==0 && wy2==0)) continue;
1089 c.wallcut(wx1,wy1,wx2,wy2);
1091 for(q=0;q<co[t];q++) {
1093 //HERE CHECK IF THE CUTTING PARTICLE IS ON THE WRONG SIDE OF ANY WALL USING SOI
1094 x1=p[t][2*q]+qx;y1=p[t][2*q+1]+qy;//qx,qy??
1096 if(!(x1==x && y1==y) && OKCuttingParticle(x,y,ij,s,x1,y1,t,q, boundary, bid)){
1097 x1=x1-x; y1=y1-y;
1098 rs=x1*x1+y1*y1;
1099 if(lrs-tolerance<rs&&rs<urs&&(q!=s||ij!=t)) {
1100 if(problem_point){
1101 if(!c.plane_nonconvex(x1,y1,rs)) return false;
1102 }else{
1103 if(!c.plane(x1,y1,rs)) return false;
1109 } while((t=l.inc(qx,qy))!=-1);//loops through boxes in the shell
1110 lr=ur;lrs=urs;
1112 if(problem_point){
1113 initial_cut_nonconvex(c,x,y,bid);
1114 }else if(boundary){
1115 initial_cut(c,x,y,bid);
1117 return true;
1120 /** Creates a voropp_loop_2d object, by setting the necessary constants about the
1121 * container geometry from a pointer to the current container class.
1122 * \param[in] con a reference to the associated container class. */
1123 voropp_loop_2d::voropp_loop_2d(container_2d &con) : boxx(con.bx-con.ax), boxy(con.by-con.ay),
1124 xsp(con.xsp),ysp(con.ysp),
1125 ax(con.ax),ay(con.ay),nx(con.nx),ny(con.ny),nxy(con.nxy),
1126 xperiodic(con.xperiodic),yperiodic(con.yperiodic) {}
1128 /** Initializes a voropp_loop_2d object, by finding all blocks which are within a
1129 * given sphere. It calculates the index of the first block that needs to be
1130 * tested and sets the periodic displacement vector accordingly.
1131 * \param[in] (vx,vy) the position vector of the center of the sphere.
1132 * \param[in] r the radius of the sphere.
1133 * \param[out] (px,py) the periodic displacement vector for the first block to
1134 * be tested.??????
1135 * \return The index of the first block to be tested. */
1136 int voropp_loop_2d::init(double vx,double vy,double r,double &px,double &py) {
1137 ai=step_int((vx-ax-r)*xsp);
1138 bi=step_int((vx-ax+r)*xsp);
1139 if(!xperiodic) {
1140 if(ai<0) {ai=0;if(bi<0) bi=0;}
1141 if(bi>=nx) {bi=nx-1;if(ai>=nx) ai=nx-1;}
1143 aj=step_int((vy-ay-r)*ysp);
1144 bj=step_int((vy-ay+r)*ysp);
1145 if(!yperiodic) {
1146 if(aj<0) {aj=0;if(bj<0) bj=0;}
1147 if(bj>=ny) {bj=ny-1;if(aj>=ny) aj=ny-1;}
1149 i=ai;j=aj;
1150 aip=ip=step_mod(i,nx);apx=px=step_div(i,nx)*boxx;
1151 ajp=jp=step_mod(j,ny);apy=py=step_div(j,ny)*boxy;
1152 inc1=aip-step_mod(bi,nx)+nx;
1153 s=aip+nx*ajp;
1154 return s;
1157 /** Initializes a voropp_loop_2d object, by finding all blocks which overlap a given
1158 * rectangular box. It calculates the index of the first block that needs to be
1159 * tested and sets the periodic displacement vector (px,py,pz) accordingly.
1160 * \param[in] (xmin,xmax) the minimum and maximum x coordinates of the box.
1161 * \param[in] (ymin,ymax) the minimum and maximum y coordinates of the box.
1162 * \param[out] (px,py) the periodic displacement vector for the first block
1163 * to be tested.
1164 * \return The index of the first block to be tested. */
1165 int voropp_loop_2d::init(double xmin,double xmax,double ymin,double ymax,double &px,double &py) {
1166 ai=step_int((xmin-ax)*xsp);
1167 bi=step_int((xmax-ax)*xsp);
1168 if(!xperiodic) {
1169 if(ai<0) {ai=0;if(bi<0) bi=0;}
1170 if(bi>=nx) {bi=nx-1;if(ai>=nx) ai=nx-1;}
1172 aj=step_int((ymin-ay)*ysp);
1173 bj=step_int((ymax-ay)*ysp);
1174 if(!yperiodic) {
1175 if(aj<0) {aj=0;if(bj<0) bj=0;}
1176 if(bj>=ny) {bj=ny-1;if(aj>=ny) aj=ny-1;}
1178 i=ai;j=aj;
1179 aip=ip=step_mod(i,nx);apx=px=step_div(i,nx)*boxx;
1180 ajp=jp=step_mod(j,ny);apy=py=step_div(j,ny)*boxy;
1181 inc1=aip-step_mod(bi,nx)+nx;
1182 s=aip+nx*ajp;
1183 return s;
1186 /** Returns the next block to be tested in a loop, and updates the periodicity
1187 * vector if necessary.
1188 * \param[in,out] (px,py) the current block on entering the function, which is
1189 * updated to the next block on exiting the function. */
1190 int voropp_loop_2d::inc(double &px,double &py) {
1191 if(i<bi) {
1192 i++;
1193 if(ip<nx-1) {ip++;s++;} else {ip=0;s+=1-nx;px+=boxx;}
1194 return s;
1195 } else if(j<bj) {
1196 i=ai;ip=aip;px=apx;j++;
1197 if(jp<ny-1) {jp++;s+=inc1;} else {jp=0;s+=inc1-nxy;py+=boxy;}
1198 return s;
1199 } else return -1;