2 * \brief Function implementations for the voronoicell_2d class. */
4 //#include "cell_2d.cpp"
5 #include "cell_nc_2d.hh"
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() {
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
;
37 *q
=1;q
[1]=3;q
[2]=2;q
[3]=0;q
[4]=3;q
[5]=1;q
[6]=0;q
[7]=2;
39 printf("\n\n\ninit_base full connect on!\n\n\n");
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
){
48 for(int i
=0;i
<(signed int)a
.size();i
++){
49 for(int j
=0;j
<(signed int)b
.size();j
++){
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
++){
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
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
) {
80 fprintf(fp
,"%g %g\n",x
+0.5*pts
[2*k
],y
+0.5*pts
[2*k
+1]);
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
) {
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]);
98 fprintf(fp
,"%g,%g,0>,r}\n",x
+0.5*pts
[2*k
],y
+0.5*pts
[2*k
+1]);
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];
110 s
=*ptsp
*(*ptsp
);ptsp
++;
111 s
+=*ptsp
*(*ptsp
);ptsp
++;
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
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
) {
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.
132 up2
=ed
[2*up
];u2
=pos(x
,y
,rsq
,up2
);
133 up3
=ed
[2*up
+1];u3
=pos(x
,y
,rsq
,up3
);
135 while(u2
<tolerance
) {
138 if(up2
==up3
) return false;
142 while(u3
<tolerance
) {
145 if(up2
==up3
) return false;
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
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
) {
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.
170 up2
=ed
[2*up
];u2
=pos(x
,y
,rsq
,up2
);
171 up3
=ed
[2*up
+1];u3
=pos(x
,y
,rsq
,up3
);
173 while(u2
<tolerance
) {
176 if(up2
==up3
) return true;
180 while(u3
<tolerance
) {
183 if(up2
==up3
) return true;
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
;
201 // Add this point to the delete stack, and search counter-clockwise to
202 // find additional points that need to be deleted.
206 while(u2
>tolerance
) {
207 if(stackp
==stacke
) add_memory_ds(stackp
);
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
221 if(vc
.full_connect
) vertexg
[cp
].push_back(p_id
);;
225 if(p
==current_vertices
) add_memory_vertices(vc
);
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
;
232 if(vc
.full_connect
){//ADDED
233 vertexg
[p
]=vertexg
[lp
];
234 vertexg
[p
].push_back(p_id
);
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
);
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
255 if(u3
>-tolerance
) {//>-TOLERANCE??
260 if(vc
.full_connect
) vertexg
[up3
].push_back(p_id
);
263 if(p
==current_vertices
){
265 add_memory_vertices(vc
);
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
;
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???
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
288 while(ed
[2*--p
]==-1);
290 if(up
<p
) {//copy p to up?
295 pts
[2*up
+1]=pts
[2*p
+1];
299 if(vc
.full_connect
){//ADDED
305 ed
[2*up
+1]=ed
[2*p
+1];
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
) {
316 for(int i
=0;i
<2*p
;i
+=2) {
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
) {
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
) {
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
) {
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() {
359 int k
=0,l
;double perim
=0,dx
,dy
;
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
);
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;}
375 int i
=0,k
=0,l
;double dx
,dy
;
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
);
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;}
390 int i
=0,k
=0,l
;double dx
,dy
,nor
;
393 dx
=pts
[2*k
]-pts
[2*l
];
394 dy
=pts
[2*k
+1]-pts
[2*l
+1];
396 if(nor
>tolerance_sq
) {
409 /** Calculates the area of the Voronoi cell.
410 * \return A floating point number holding the calculated distance. */
411 double voronoicell_base_2d::area() {
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
;
417 dx2
=pts
[2*k
]-x
;dy2
=pts
[2*k
+1]-y
;
418 area
+=dx1
*dy2
-dx2
*dy1
;
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
) {
429 static const double third
=1/3.0;
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
;
436 dx2
=pts
[2*k
]-x
;dy2
=pts
[2*k
+1]-y
;
437 area
=dx1
*dy2
-dx2
*dy1
;
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
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
));
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
);
494 case 'n': neighbors(vi
);
495 voro_print_vector(vi
,fp
);
498 // Area-related output
499 case 'a': fprintf(fp
,"%g",area());break;
503 fprintf(fp
,"%g %g",cx
,cy
);
508 fprintf(fp
,"%g %g",x
+cx
,y
+cy
);
511 // End-of-string reached
514 // The percent sign is not part of a
516 default: putc('%',fp
);putc(*fmp
,fp
);
518 } else putc(*fmp
,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
);
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
++);
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
];
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
++);
565 void voronoicell_neighbor_2d::neighbors(vector
<int> &v
) {
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
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
);
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
&);