Reset platonic code.
[voro++.git] / branches / 2d / src / v_connect / cell_2d.cc
blob09a8172506cbff05a632865bb06d2181a94a0219
1 /** \file cell_2d.cc
2 * \brief Function implementations for the voronoicell_2d class. */
4 //#include "cell_2d.cpp"
5 #include "cell_nc_2d.hh"
7 namespace voro {
9 /** Constructs a 2D Voronoi cell and sets up the initial memory. */
10 voronoicell_base_2d::voronoicell_base_2d() :
11 current_vertices(init_vertices), current_delete_size(init_delete_size),
12 ed(new int[2*current_vertices]), pts(new double[2*current_vertices]),
13 ds(new int[current_delete_size]), stacke(ds+current_delete_size) {full_connect=false;
17 /** The voronoicell_2d destructor deallocates all of the dynamic memory. */
18 voronoicell_base_2d::~voronoicell_base_2d() {
19 delete [] ds;
20 delete [] pts;
21 delete [] ed;
22 if(full_connect){
23 delete [] vertexg;
27 /** Initializes a Voronoi cell as a rectangle with the given dimensions.
28 * \param[in] (xmin,xmax) the minimum and maximum x coordinates.
29 * \param[in] (ymin,ymax) the minimum and maximum y coordinates. */
30 void voronoicell_base_2d::init_base(double xmin,double xmax,double ymin,double ymax) {
31 p=4;xmin*=2;xmax*=2;ymin*=2;ymax*=2;
32 *pts=xmin;pts[1]=ymin;
33 pts[2]=xmax;pts[3]=ymin;
34 pts[4]=xmax;pts[5]=ymax;
35 pts[6]=xmin;pts[7]=ymax;
36 int *q=ed;
37 *q=1;q[1]=3;q[2]=2;q[3]=0;q[4]=3;q[5]=1;q[6]=0;q[7]=2;
38 if(full_connect){
39 printf("\n\n\ninit_base full connect on!\n\n\n");
40 for(int i=0;i<p;i++){
41 vertexg[i].push_back(my_id);
45 //called from voro_connect. Given two vectors a and b, find a common element !=c
46 vector<int> voronoicell_base_2d::common_gen(vector<int> &a,vector<int> &b){
47 vector<int> newg;
48 for(int i=0;i<(signed int)a.size();i++){
49 for(int j=0;j<(signed int)b.size();j++){
50 if(b[j]==a[i]){
51 newg.push_back(b[j]);
52 continue;
56 return newg;
58 //called from voro_connect. Adds the generator g to a
59 void voronoicell_base_2d::add_vg(vector<int> &a,int g){
60 for(int i=0;i<a.size();i++){
61 if(a[i]==g) return;
63 a.push_back(g);
67 //called from voro_connect. copies vector n(new) onto vector o(old)
68 void voronoicell_base_2d::vg_copy(int o,int n){
69 vertexg[o]=vertexg[n];
72 /** Outputs the edges of the Voronoi cell in gnuplot format to an output
73 * stream.
74 * \param[in] (x,y) a displacement vector to be added to the cell's position.
75 * \param[in] fp the file handle to write to. */
76 void voronoicell_base_2d::draw_gnuplot(double x,double y,FILE *fp) {
77 if(p==0) return;
78 int k=0;
79 do {
80 fprintf(fp,"%g %g\n",x+0.5*pts[2*k],y+0.5*pts[2*k+1]);
81 k=ed[2*k];
82 } while (k!=0);
83 fprintf(fp,"%g %g\n\n",x+0.5*pts[0],y+0.5*pts[1]);
86 /** Outputs the edges of the Voronoi cell in POV-Ray format to an open file
87 * stream, displacing the cell by given vector.
88 * \param[in] (x,y) a displacement vector to be added to the cell's position.
89 * \param[in] fp the file handle to write to. */
90 void voronoicell_base_2d::draw_pov(double x,double y,FILE *fp) {
91 if(p==0) return;
92 int k=0;
93 do {
94 fprintf(fp,"sphere{<%g,%g,0>,r}\ncylinder{<%g,%g,0>,<"
95 ,x+0.5*pts[2*k],y+0.5*pts[2*k+1]
96 ,x+0.5*pts[2*k],y+0.5*pts[2*k+1]);
97 k=ed[2*k];
98 fprintf(fp,"%g,%g,0>,r}\n",x+0.5*pts[2*k],y+0.5*pts[2*k+1]);
99 } while (k!=0);
102 /** Computes the maximum radius squared of a vertex from the center of the
103 * cell. It can be used to determine when enough particles have been testing an
104 * all planes that could cut the cell have been considered.
105 * \return The maximum radius squared of a vertex.*/
106 double voronoicell_base_2d::max_radius_squared() {
107 double r,s,*ptsp(pts+2),*ptse(pts+2*p);
108 r=*pts*(*pts)+pts[1]*pts[1];
109 while(ptsp<ptse) {
110 s=*ptsp*(*ptsp);ptsp++;
111 s+=*ptsp*(*ptsp);ptsp++;
112 if(s>r) r=s;
114 return r;
117 /** Cuts the Voronoi cell by a particle whose center is at a separation of
118 * (x,y) from the cell center. The value of rsq should be initially set to
119 * \f$x^2+y^2\f$.
120 * \param[in] (x,y) the normal vector to the plane.
121 * \param[in] rsq the distance along this vector of the plane.
122 * \return False if the plane cut deleted the cell entirely, true otherwise. */
123 bool voronoicell_base_2d::plane_intersects(double x,double y,double rsq) {
124 int up=0,up2,up3;
125 double u,u2,u3;
127 // First try and find a vertex that is within the cutting plane, if
128 // there is one. If one can't be found, then the cell is not cut by
129 // this plane and the routine immediately returns true.
130 u=pos(x,y,rsq,up);
131 if(u<tolerance) {
132 up2=ed[2*up];u2=pos(x,y,rsq,up2);
133 up3=ed[2*up+1];u3=pos(x,y,rsq,up3);
134 if(u2>u3) {
135 while(u2<tolerance) {
136 up2=ed[2*up2];
137 u2=pos(x,y,rsq,up2);
138 if(up2==up3) return false;
140 up=up2;u=u2;
141 } else {
142 while(u3<tolerance) {
143 up3=ed[2*up3+1];
144 u3=pos(x,y,rsq,up3);
145 if(up2==up3) return false;
147 up=up3;u=u3;
150 return true;
154 /** Cuts the Voronoi cell by a particle whose center is at a separation of
155 * (x,y) from the cell center. The value of rsq should be initially set to
156 * \f$x^2+y^2\f$.
157 * \param[in] (x,y) the normal vector to the plane.
158 * \param[in] rsq the distance along this vector of the plane.
159 * \return False if the plane cut deleted the cell entirely, true otherwise. */
160 template<class vc_class>
161 bool voronoicell_base_2d::nplane(vc_class &vc,double x,double y,double rsq,int p_id) {
162 int up=0,up2,up3;
163 double u,u2,u3;
165 // First try and find a vertex that is within the cutting plane, if
166 // there is one. If one can't be found, then the cell is not cut by
167 // this plane and the routine immediately returns true.
168 u=pos(x,y,rsq,up);
169 if(u<tolerance) {
170 up2=ed[2*up];u2=pos(x,y,rsq,up2);
171 up3=ed[2*up+1];u3=pos(x,y,rsq,up3);
172 if(u2>u3) {
173 while(u2<tolerance) {
174 up2=ed[2*up2];
175 u2=pos(x,y,rsq,up2);
176 if(up2==up3) return true;
178 up=up2;u=u2;
179 } else {
180 while(u3<tolerance) {
181 up3=ed[2*up3+1];
182 u3=pos(x,y,rsq,up3);
183 if(up2==up3) return true;
185 up=up3;u=u3;
189 return nplane_cut(vc,x,y,rsq,p_id,u,up);
193 template<class vc_class>
194 bool voronoicell_base_2d::nplane_cut(vc_class &vc,double x,double y,double rsq,int p_id,double u,int up) {
198 int cp,lp,up2,up3,*stackp=ds;
199 double fac,l,u2,u3;
201 // Add this point to the delete stack, and search counter-clockwise to
202 // find additional points that need to be deleted.
203 *(stackp++)=up;
204 l=u;up2=ed[2*up];
205 u2=pos(x,y,rsq,up2);
206 while(u2>tolerance) {
207 if(stackp==stacke) add_memory_ds(stackp);
208 *(stackp++)=up2;
209 up2=ed[2*up2];
210 l=u2;
211 u2=pos(x,y,rsq,up2);
212 if(up2==up) return false;
215 // Consider the first point that was found in the counter-clockwise
216 // direction that was not inside the cutting plane. If it lies on the
217 // cutting plane then do nothing. Otherwise, introduce a new vertex.
218 if(u2>-tolerance){//ADDED
220 cp=up2;
221 if(vc.full_connect) vertexg[cp].push_back(p_id);;
223 else {
225 if(p==current_vertices) add_memory_vertices(vc);
226 lp=ed[2*up2+1];
227 fac=1/(u2-l);
228 pts[2*p]=(pts[2*lp]*u2-pts[2*up2]*l)*fac;
229 pts[2*p+1]=(pts[2*lp+1]*u2-pts[2*up2+1]*l)*fac;
230 vc.n_copy(p,lp);
232 if(vc.full_connect){//ADDED
233 vertexg[p]=vertexg[lp];
234 vertexg[p].push_back(p_id);
236 ed[2*p]=up2;
237 ed[2*up2+1]=p;
238 cp=p++;
241 // Search clockwise for additional points that need to be deleted
242 l=u;up3=ed[2*up+1];u3=pos(x,y,rsq,up3);
243 while(u3>tolerance) {
244 if(stackp==stacke) add_memory_ds(stackp);
245 *(stackp++)=up3;
246 up3=ed[2*up3+1];
247 l=u3;
248 u3=pos(x,y,rsq,up3);
249 if(up3==up2) break;
252 // Either adjust the existing vertex or create new one, and connect it
253 // with the vertex found on the previous search in the counter-clockwise
254 // direction
255 if(u3>-tolerance) {//>-TOLERANCE??
257 ed[2*cp+1]=up3;
258 ed[2*up3]=cp;
259 vc.n_set(up3,p_id);
260 if(vc.full_connect) vertexg[up3].push_back(p_id);
261 } else {
263 if(p==current_vertices){
265 add_memory_vertices(vc);
267 lp=ed[2*up3];
268 fac=1/(u3-l);
269 pts[2*p]=(pts[2*lp]*u3-pts[2*up3]*l)*fac;
270 pts[2*p+1]=(pts[2*lp+1]*u3-pts[2*up3+1]*l)*fac;
271 ed[2*p]=cp;
272 ed[2*cp+1]=p;
273 vc.n_set(p,p_id);
274 if(vc.full_connect){//ADDED
275 vertexg[p]=vertexg[lp];
276 vertexg[p].push_back(p_id);
279 ed[2*p+1]=up3;//ADD NEIGHBOR INFO TO P???
280 ed[2*up3]=p++;
283 // Mark points on the delete stack
284 for(int *sp=ds;sp<stackp;sp++) ed[*sp*2]=-1;
286 // Remove them from the memory structure
287 while(stackp>ds) {
288 while(ed[2*--p]==-1);
289 up=*(--stackp);
290 if(up<p) {//copy p to up?
292 ed[2*ed[2*p]+1]=up;
293 ed[2*ed[2*p+1]]=up;
294 pts[2*up]=pts[2*p];
295 pts[2*up+1]=pts[2*p+1];
297 vc.n_copy(up,p);
299 if(vc.full_connect){//ADDED
301 vc.vg_copy(up,p);
304 ed[2*up]=ed[2*p];
305 ed[2*up+1]=ed[2*p+1];
306 } else p++;
308 return true;
311 /** Returns a vector of the vertex vectors using the local coordinate system.
312 * \param[out] v the vector to store the results in. */
313 void voronoicell_base_2d::vertices(vector<double> &v) {
314 v.resize(2*p);
315 double *ptsp=pts;
316 for(int i=0;i<2*p;i+=2) {
317 v[i]=*(ptsp++)*0.5;
318 v[i+1]=*(ptsp++)*0.5;
322 /** Outputs the vertex vectors using the local coordinate system.
323 * \param[out] fp the file handle to write to. */
324 void voronoicell_base_2d::output_vertices(FILE *fp) {
325 if(p>0) {
326 fprintf(fp,"(%g,%g)",*pts*0.5,pts[1]*0.5);
327 for(double *ptsp=pts+2;ptsp<pts+2*p;ptsp+=2) fprintf(fp," (%g,%g)",*ptsp*0.5,ptsp[1]*0.5);
331 /** Returns a vector of the vertex vectors in the global coordinate system.
332 * \param[out] v the vector to store the results in.
333 * \param[in] (x,y,z) the position vector of the particle in the global
334 * coordinate system. */
335 void voronoicell_base_2d::vertices(double x,double y,vector<double> &v) {
336 v.resize(2*p);
337 double *ptsp=pts;
338 for(int i=0;i<2*p;i+=2) {
339 v[i]=x+*(ptsp++)*0.5;
340 v[i+1]=y+*(ptsp++)*0.5;
344 /** Outputs the vertex vectors using the global coordinate system.
345 * \param[out] fp the file handle to write to.
346 * \param[in] (x,y,z) the position vector of the particle in the global
347 * coordinate system. */
348 void voronoicell_base_2d::output_vertices(double x,double y,FILE *fp) {
349 if(p>0) {
350 fprintf(fp,"(%g,%g)",x+*pts*0.5,y+pts[1]*0.5);
351 for(double *ptsp=pts+2;ptsp<pts+2*p;ptsp+=2) fprintf(fp," (%g,%g)",x+*ptsp*0.5,y+ptsp[1]*0.5);
355 /** Calculates the perimeter of the Voronoi cell.
356 * \return A floating point number holding the calculated distance. */
357 double voronoicell_base_2d::perimeter() {
358 if(p==0) return 0;
359 int k=0,l;double perim=0,dx,dy;
360 do {
361 l=ed[2*k];
362 dx=pts[2*k]-pts[2*l];
363 dy=pts[2*k+1]-pts[2*l+1];
364 perim+=sqrt(dx*dx+dy*dy);
365 k=l;
366 } while (k!=0);
367 return 0.5*perim;
370 /** Calculates the perimeter of the Voronoi cell.
371 * \return A floating point number holding the calculated distance. */
372 void voronoicell_base_2d::edge_lengths(vector<double> &vd) {
373 if(p==0) {vd.clear();return;}
374 vd.resize(p);
375 int i=0,k=0,l;double dx,dy;
376 do {
377 l=ed[2*k];
378 dx=pts[2*k]-pts[2*l];
379 dy=pts[2*k+1]-pts[2*l+1];
380 vd[i++]=sqrt(dx*dx+dy*dy);
381 k=l;
382 } while (k!=0);
385 /** Calculates the perimeter of the Voronoi cell.
386 * \return A floating point number holding the calculated distance. */
387 void voronoicell_base_2d::normals(vector<double> &vd) {
388 if(p==0) {vd.clear();return;}
389 vd.resize(2*p);
390 int i=0,k=0,l;double dx,dy,nor;
391 do {
392 l=ed[2*k];
393 dx=pts[2*k]-pts[2*l];
394 dy=pts[2*k+1]-pts[2*l+1];
395 nor=dx*dx+dy*dy;
396 if(nor>tolerance_sq) {
397 nor=1/sqrt(nor);
398 vd[i++]=dy*nor;
399 vd[i++]=-dx*nor;
400 } else {
401 vd[i++]=0;
402 vd[i++]=0;
404 k=l;
405 } while (k!=0);
409 /** Calculates the area of the Voronoi cell.
410 * \return A floating point number holding the calculated distance. */
411 double voronoicell_base_2d::area() {
412 if(p==0) return 0;
413 int k(*ed);double area=0,x=*pts,y=pts[1],dx1,dy1,dx2,dy2;
414 dx1=pts[2*k]-x;dy1=pts[2*k+1]-y;
415 k=ed[2*k];
416 while(k!=0) {
417 dx2=pts[2*k]-x;dy2=pts[2*k+1]-y;
418 area+=dx1*dy2-dx2*dy1;
419 dx1=dx2;dy1=dy2;
420 k=ed[2*k];
422 return 0.125*area;
425 /** Calculates the centroid of the Voronoi cell.
426 * \param[out] (cx,cy) The coordinates of the centroid. */
427 void voronoicell_base_2d::centroid(double &cx,double &cy) {
428 cx=cy=0;
429 static const double third=1/3.0;
430 if(p==0) return;
431 int k(*ed);
432 double area,tarea=0,x=*pts,y=pts[1],dx1,dy1,dx2,dy2;
433 dx1=pts[2*k]-x;dy1=pts[2*k+1]-y;
434 k=ed[2*k];
435 while(k!=0) {
436 dx2=pts[2*k]-x;dy2=pts[2*k+1]-y;
437 area=dx1*dy2-dx2*dy1;
438 tarea+=area;
439 cx+=area*(dx1+dx2);
440 cy+=area*(dy1+dy2);
441 dx1=dx2;dy1=dy2;
442 k=ed[2*k];
444 tarea=third/tarea;
445 cx=0.5*(x+cx*tarea);
446 cy=0.5*(y+cy*tarea);
454 /** Computes the Voronoi cells for all particles in the container, and for each
455 * cell, outputs a line containing custom information about the cell structure.
456 * The output format is specified using an input string with control sequences
457 * similar to the standard C printf() routine.
458 * \param[in] format the format of the output lines, using control sequences to
459 * denote the different cell statistics.
460 * \param[in] i the ID of the particle associated with this Voronoi cell.
461 * \param[in] (x,y) the position of the particle associated with this Voronoi
462 * cell.
463 * \param[in] r a radius associated with the particle.
464 * \param[in] fp the file handle to write to. */
465 void voronoicell_base_2d::output_custom(const char *format,int i,double x,double y,double r,FILE *fp) {
466 char *fmp(const_cast<char*>(format));
467 vector<int> vi;
468 vector<double> vd;
469 while(*fmp!=0) {
470 if(*fmp=='%') {
471 fmp++;
472 switch(*fmp) {
474 // Particle-related output
475 case 'i': fprintf(fp,"%d",i);break;
476 case 'x': fprintf(fp,"%g",x);break;
477 case 'y': fprintf(fp,"%g",y);break;
478 case 'q': fprintf(fp,"%g %g",x,y);break;
479 case 'r': fprintf(fp,"%g",r);break;
481 // Vertex-related output
482 case 'w': fprintf(fp,"%d",p);break;
483 case 'p': output_vertices(fp);break;
484 case 'P': output_vertices(x,y,fp);break;
485 case 'm': fprintf(fp,"%g",0.25*max_radius_squared());break;
487 // Edge-related output
488 case 'g': fprintf(fp,"%d",p);break;
489 case 'E': fprintf(fp,"%g",perimeter());break;
490 case 'e': edge_lengths(vd);voro_print_vector(vd,fp);break;
491 case 'l': normals(vd);
492 voro_print_positions_2d(vd,fp);
493 break;
494 case 'n': neighbors(vi);
495 voro_print_vector(vi,fp);
496 break;
498 // Area-related output
499 case 'a': fprintf(fp,"%g",area());break;
500 case 'c': {
501 double cx,cy;
502 centroid(cx,cy);
503 fprintf(fp,"%g %g",cx,cy);
504 } break;
505 case 'C': {
506 double cx,cy;
507 centroid(cx,cy);
508 fprintf(fp,"%g %g",x+cx,y+cy);
509 } break;
511 // End-of-string reached
512 case 0: fmp--;break;
514 // The percent sign is not part of a
515 // control sequence
516 default: putc('%',fp);putc(*fmp,fp);
518 } else putc(*fmp,fp);
519 fmp++;
521 fputs("\n",fp);
524 /** Doubles the storage for the vertices, by reallocating the pts and ed
525 * arrays. If the allocation exceeds the absolute maximum set in max_vertices,
526 * then the routine exits with a fatal error. */
527 template<class vc_class>
528 void voronoicell_base_2d::add_memory_vertices(vc_class &vc) {
529 double *ppe(pts+2*current_vertices);
530 int *ede(ed+2*current_vertices);
532 // Double the memory allocation and check it is within range
533 current_vertices<<=1;
534 if(current_vertices>max_vertices) voro_fatal_error("Vertex memory allocation exceeded absolute maximum",VOROPP_MEMORY_ERROR);
535 #if VOROPP_VERBOSE >=2
536 fprintf(stderr,"Vertex memory scaled up to %d\n",current_vertices);
537 #endif
539 // Copy the vertex positions
540 double *npts(new double[2*current_vertices]),*npp(npts),*pp(pts);
541 while(pp<ppe) *(npp++)=*(pp++);
542 delete [] pts;pts=npts;
544 // Copy the edge table
545 int *ned(new int[2*current_vertices]),*nep(ned),*edp(ed);
546 while(edp<ede) *(nep++)=*(edp++);
547 delete [] ed;ed=ned;
549 // Double the neighbor information if necessary
550 vc.n_add_memory_vertices();
551 if(full_connect){//ADDED
552 vector<int> *nvertexg(new vector<int>[current_vertices]);
553 for(int i=0;i<(current_vertices>>1);i++) nvertexg[i]=vertexg[i];
554 delete [] vertexg;
555 vertexg=nvertexg;
559 inline void voronoicell_neighbor_2d::n_add_memory_vertices() {
560 int *nne=new int[current_vertices],*nee=ne+(current_vertices>>1),*nep=ne,*nnep=nne;
561 while(nep<nee) *(nnep++)=*(nep++);
562 delete [] ne;ne=nne;
565 void voronoicell_neighbor_2d::neighbors(vector<int> &v) {
566 v.resize(p);
567 for(int i=0;i<p;i++) v[i]=ne[i];
570 void voronoicell_neighbor_2d::init(double xmin,double xmax,double ymin,double ymax) {
571 init_base(xmin,xmax,ymin,ymax);
572 *ne=-3;ne[1]=-2;ne[2]=-4;ne[3]=-1;
575 /** Doubles the size allocation of the delete stack. If the allocation exceeds
576 * the absolute maximum set in max_delete_size, then routine causes a fatal
577 * error.
578 * \param[in] stackp a reference to the current stack pointer. */
579 void voronoicell_base_2d::add_memory_ds(int *&stackp) {
580 current_delete_size<<=1;
581 if(current_delete_size>max_delete_size) voro_fatal_error("Delete stack 1 memory allocation exceeded absolute maximum",VOROPP_MEMORY_ERROR);
582 #if VOROPP_VERBOSE >=2
583 fprintf(stderr,"Delete stack 1 memory scaled up to %d\n",current_delete_size);
584 #endif
585 int *dsn(new int[current_delete_size]),*dsnp(dsn),*dsp(ds);
586 while(dsp<stackp) *(dsnp++)=*(dsp++);
587 delete [] ds;ds=dsn;stackp=dsnp;
588 stacke=ds+current_delete_size;
591 // Explicit instantiation
592 template bool voronoicell_base_2d::nplane(voronoicell_2d&,double,double,double,int);
593 template bool voronoicell_base_2d::nplane(voronoicell_neighbor_2d&,double,double,double,int);
594 template bool voronoicell_base_2d::nplane_cut(voronoicell_2d&,double,double,double,int,double,int);
595 template bool voronoicell_base_2d::nplane_cut(voronoicell_neighbor_2d&,double,double,double,int,double,int);
596 template void voronoicell_base_2d::add_memory_vertices(voronoicell_2d&);
597 template void voronoicell_base_2d::add_memory_vertices(voronoicell_neighbor_2d&);
598 template bool voronoicell_base_2d::nplane(voronoicell_nonconvex_2d&,double,double,double,int);
599 template bool voronoicell_base_2d::nplane(voronoicell_nonconvex_neighbor_2d&,double,double,double,int);
600 template bool voronoicell_base_2d::nplane_cut(voronoicell_nonconvex_2d&,double,double,double,int,double,int);
601 template bool voronoicell_base_2d::nplane_cut(voronoicell_nonconvex_neighbor_2d&,double,double,double,int,double,int);
602 template void voronoicell_base_2d::add_memory_vertices(voronoicell_nonconvex_2d&);
603 template void voronoicell_base_2d::add_memory_vertices(voronoicell_nonconvex_neighbor_2d&);