2 * \brief Function implementations for the voronoicell_2d class. */
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
) {
16 /** The voronoicell_2d destructor deallocates all of the dynamic memory. */
17 voronoicell_base_2d::~voronoicell_base_2d() {
23 /** Initializes a Voronoi cell as a rectangle with the given dimensions.
24 * \param[in] (xmin,xmax) the minimum and maximum x coordinates.
25 * \param[in] (ymin,ymax) the minimum and maximum y coordinates. */
26 void voronoicell_base_2d::init_base(double xmin
,double xmax
,double ymin
,double ymax
) {
27 p
=4;xmin
*=2;xmax
*=2;ymin
*=2;ymax
*=2;
28 *pts
=xmin
;pts
[1]=ymin
;
29 pts
[2]=xmax
;pts
[3]=ymin
;
30 pts
[4]=xmax
;pts
[5]=ymax
;
31 pts
[6]=xmin
;pts
[7]=ymax
;
33 *q
=1;q
[1]=3;q
[2]=2;q
[3]=0;q
[4]=3;q
[5]=1;q
[6]=0;q
[7]=2;
36 /** Outputs the edges of the Voronoi cell in gnuplot format to an output
38 * \param[in] (x,y) a displacement vector to be added to the cell's position.
39 * \param[in] fp the file handle to write to. */
40 void voronoicell_base_2d::draw_gnuplot(double x
,double y
,FILE *fp
) {
44 fprintf(fp
,"%g %g\n",x
+0.5*pts
[2*k
],y
+0.5*pts
[2*k
+1]);
47 fprintf(fp
,"%g %g\n\n",x
+0.5*pts
[0],y
+0.5*pts
[1]);
50 /** Outputs the edges of the Voronoi cell in POV-Ray format to an open file
51 * stream, displacing the cell by given vector.
52 * \param[in] (x,y) a displacement vector to be added to the cell's position.
53 * \param[in] fp the file handle to write to. */
54 void voronoicell_base_2d::draw_pov(double x
,double y
,FILE *fp
) {
58 fprintf(fp
,"sphere{<%g,%g,0>,r}\ncylinder{<%g,%g,0>,<"
59 ,x
+0.5*pts
[2*k
],y
+0.5*pts
[2*k
+1]
60 ,x
+0.5*pts
[2*k
],y
+0.5*pts
[2*k
+1]);
62 fprintf(fp
,"%g,%g,0>,r}\n",x
+0.5*pts
[2*k
],y
+0.5*pts
[2*k
+1]);
66 /** Computes the maximum radius squared of a vertex from the center of the
67 * cell. It can be used to determine when enough particles have been testing an
68 * all planes that could cut the cell have been considered.
69 * \return The maximum radius squared of a vertex.*/
70 double voronoicell_base_2d::max_radius_squared() {
71 double r
,s
,*ptsp(pts
+2),*ptse(pts
+2*p
);
72 r
=*pts
*(*pts
)+pts
[1]*pts
[1];
74 s
=*ptsp
*(*ptsp
);ptsp
++;
75 s
+=*ptsp
*(*ptsp
);ptsp
++;
81 /** Cuts the Voronoi cell by a particle whose center is at a separation of
82 * (x,y) from the cell center. The value of rsq should be initially set to
84 * \param[in] (x,y) the normal vector to the plane.
85 * \param[in] rsq the distance along this vector of the plane.
86 * \return False if the plane cut deleted the cell entirely, true otherwise. */
87 bool voronoicell_base_2d::plane_intersects(double x
,double y
,double rsq
) {
91 // First try and find a vertex that is within the cutting plane, if
92 // there is one. If one can't be found, then the cell is not cut by
93 // this plane and the routine immediately returns true.
96 up2
=ed
[2*up
];u2
=pos(x
,y
,rsq
,up2
);
97 up3
=ed
[2*up
+1];u3
=pos(x
,y
,rsq
,up3
);
102 if(up2
==up3
) return false;
106 while(u3
<tolerance
) {
109 if(up2
==up3
) return false;
118 /** Cuts the Voronoi cell by a particle whose center is at a separation of
119 * (x,y) from the cell center. The value of rsq should be initially set to
121 * \param[in] (x,y) the normal vector to the plane.
122 * \param[in] rsq the distance along this vector of the plane.
123 * \return False if the plane cut deleted the cell entirely, true otherwise. */
124 template<class vc_class
>
125 bool voronoicell_base_2d::nplane(vc_class
&vc
,double x
,double y
,double rsq
,int p_id
) {
129 // First try and find a vertex that is within the cutting plane, if
130 // there is one. If one can't be found, then the cell is not cut by
131 // this plane and the routine immediately returns true.
134 up2
=ed
[2*up
];u2
=pos(x
,y
,rsq
,up2
);
135 up3
=ed
[2*up
+1];u3
=pos(x
,y
,rsq
,up3
);
137 while(u2
<tolerance
) {
140 if(up2
==up3
) return true;
144 while(u3
<tolerance
) {
147 if(up2
==up3
) return true;
153 return nplane_cut(vc
,x
,y
,rsq
,p_id
,u
,up
);
157 template<class vc_class
>
158 bool voronoicell_base_2d::nplane_cut(vc_class
&vc
,double x
,double y
,double rsq
,int p_id
,double u
,int up
) {
159 int cp
,lp
,up2
,up3
,*stackp
=ds
;
162 // Add this point to the delete stack, and search counter-clockwise to
163 // find additional points that need to be deleted.
167 while(u2
>tolerance
) {
168 if(stackp
==stacke
) add_memory_ds(stackp
);
173 if(up2
==up
) return false;
176 // Consider the first point that was found in the counter-clockwise
177 // direction that was not inside the cutting plane. If it lies on the
178 // cutting plane then do nothing. Otherwise, introduce a new vertex.
179 if(u2
>-tolerance
) cp
=up2
;
181 if(p
==current_vertices
) add_memory_vertices(vc
);
184 pts
[2*p
]=(pts
[2*lp
]*u2
-pts
[2*up2
]*l
)*fac
;
185 pts
[2*p
+1]=(pts
[2*lp
+1]*u2
-pts
[2*up2
+1]*l
)*fac
;
192 // Search clockwise for additional points that need to be deleted
193 l
=u
;up3
=ed
[2*up
+1];u3
=pos(x
,y
,rsq
,up3
);
194 while(u3
>tolerance
) {
195 if(stackp
==stacke
) add_memory_ds(stackp
);
203 // Either adjust the existing vertex or create new one, and connect it
204 // with the vertex found on the previous search in the counter-clockwise
211 if(p
==current_vertices
) add_memory_vertices(vc
);
214 pts
[2*p
]=(pts
[2*lp
]*u3
-pts
[2*up3
]*l
)*fac
;
215 pts
[2*p
+1]=(pts
[2*lp
+1]*u3
-pts
[2*up3
+1]*l
)*fac
;
223 // Mark points on the delete stack
224 for(int *sp
=ds
;sp
<stackp
;sp
++) ed
[*sp
*2]=-1;
226 // Remove them from the memory structure
228 while(ed
[2*--p
]==-1);
234 pts
[2*up
+1]=pts
[2*p
+1];
237 ed
[2*up
+1]=ed
[2*p
+1];
243 /** Returns a vector of the vertex vectors using the local coordinate system.
244 * \param[out] v the vector to store the results in. */
245 void voronoicell_base_2d::vertices(vector
<double> &v
) {
248 for(int i
=0;i
<2*p
;i
+=2) {
250 v
[i
+1]=*(ptsp
++)*0.5;
254 /** Outputs the vertex vectors using the local coordinate system.
255 * \param[out] fp the file handle to write to. */
256 void voronoicell_base_2d::output_vertices(FILE *fp
) {
258 fprintf(fp
,"(%g,%g)",*pts
*0.5,pts
[1]*0.5);
259 for(double *ptsp
=pts
+2;ptsp
<pts
+2*p
;ptsp
+=2) fprintf(fp
," (%g,%g)",*ptsp
*0.5,ptsp
[1]*0.5);
263 /** Returns a vector of the vertex vectors in the global coordinate system.
264 * \param[out] v the vector to store the results in.
265 * \param[in] (x,y,z) the position vector of the particle in the global
266 * coordinate system. */
267 void voronoicell_base_2d::vertices(double x
,double y
,vector
<double> &v
) {
270 for(int i
=0;i
<2*p
;i
+=2) {
271 v
[i
]=x
+*(ptsp
++)*0.5;
272 v
[i
+1]=y
+*(ptsp
++)*0.5;
276 /** Outputs the vertex vectors using the global coordinate system.
277 * \param[out] fp the file handle to write to.
278 * \param[in] (x,y,z) the position vector of the particle in the global
279 * coordinate system. */
280 void voronoicell_base_2d::output_vertices(double x
,double y
,FILE *fp
) {
282 fprintf(fp
,"(%g,%g)",x
+*pts
*0.5,y
+pts
[1]*0.5);
283 for(double *ptsp
=pts
+2;ptsp
<pts
+2*p
;ptsp
+=2) fprintf(fp
," (%g,%g)",x
+*ptsp
*0.5,y
+ptsp
[1]*0.5);
287 /** Calculates the perimeter of the Voronoi cell.
288 * \return A floating point number holding the calculated distance. */
289 double voronoicell_base_2d::perimeter() {
291 int k
=0,l
;double perim
=0,dx
,dy
;
294 dx
=pts
[2*k
]-pts
[2*l
];
295 dy
=pts
[2*k
+1]-pts
[2*l
+1];
296 perim
+=sqrt(dx
*dx
+dy
*dy
);
302 /** Calculates the perimeter of the Voronoi cell.
303 * \return A floating point number holding the calculated distance. */
304 void voronoicell_base_2d::edge_lengths(vector
<double> &vd
) {
305 if(p
==0) {vd
.clear();return;}
307 int i
=0,k
=0,l
;double dx
,dy
;
310 dx
=pts
[2*k
]-pts
[2*l
];
311 dy
=pts
[2*k
+1]-pts
[2*l
+1];
312 vd
[i
++]=sqrt(dx
*dx
+dy
*dy
);
317 /** Calculates the perimeter of the Voronoi cell.
318 * \return A floating point number holding the calculated distance. */
319 void voronoicell_base_2d::normals(vector
<double> &vd
) {
320 if(p
==0) {vd
.clear();return;}
322 int i
=0,k
=0,l
;double dx
,dy
,nor
;
325 dx
=pts
[2*k
]-pts
[2*l
];
326 dy
=pts
[2*k
+1]-pts
[2*l
+1];
328 if(nor
>tolerance_sq
) {
341 /** Calculates the area of the Voronoi cell.
342 * \return A floating point number holding the calculated distance. */
343 double voronoicell_base_2d::area() {
345 int k(*ed
);double area
=0,x
=*pts
,y
=pts
[1],dx1
,dy1
,dx2
,dy2
;
346 dx1
=pts
[2*k
]-x
;dy1
=pts
[2*k
+1]-y
;
349 dx2
=pts
[2*k
]-x
;dy2
=pts
[2*k
+1]-y
;
350 area
+=dx1
*dy2
-dx2
*dy1
;
357 /** Calculates the centroid of the Voronoi cell.
358 * \param[out] (cx,cy) The coordinates of the centroid. */
359 void voronoicell_base_2d::centroid(double &cx
,double &cy
) {
361 static const double third
=1/3.0;
364 double area
,tarea
=0,x
=*pts
,y
=pts
[1],dx1
,dy1
,dx2
,dy2
;
365 dx1
=pts
[2*k
]-x
;dy1
=pts
[2*k
+1]-y
;
368 dx2
=pts
[2*k
]-x
;dy2
=pts
[2*k
+1]-y
;
369 area
=dx1
*dy2
-dx2
*dy1
;
386 /** Computes the Voronoi cells for all particles in the container, and for each
387 * cell, outputs a line containing custom information about the cell structure.
388 * The output format is specified using an input string with control sequences
389 * similar to the standard C printf() routine.
390 * \param[in] format the format of the output lines, using control sequences to
391 * denote the different cell statistics.
392 * \param[in] i the ID of the particle associated with this Voronoi cell.
393 * \param[in] (x,y) the position of the particle associated with this Voronoi
395 * \param[in] r a radius associated with the particle.
396 * \param[in] fp the file handle to write to. */
397 void voronoicell_base_2d::output_custom(const char *format
,int i
,double x
,double y
,double r
,FILE *fp
) {
398 char *fmp(const_cast<char*>(format
));
406 // Particle-related output
407 case 'i': fprintf(fp
,"%d",i
);break;
408 case 'x': fprintf(fp
,"%g",x
);break;
409 case 'y': fprintf(fp
,"%g",y
);break;
410 case 'q': fprintf(fp
,"%g %g",x
,y
);break;
411 case 'r': fprintf(fp
,"%g",r
);break;
413 // Vertex-related output
414 case 'w': fprintf(fp
,"%d",p
);break;
415 case 'p': output_vertices(fp
);break;
416 case 'P': output_vertices(x
,y
,fp
);break;
417 case 'm': fprintf(fp
,"%g",0.25*max_radius_squared());break;
419 // Edge-related output
420 case 'g': fprintf(fp
,"%d",p
);break;
421 case 'E': fprintf(fp
,"%g",perimeter());break;
422 case 'e': edge_lengths(vd
);voro_print_vector(vd
,fp
);break;
423 case 'l': normals(vd
);
424 voro_print_positions_2d(vd
,fp
);
426 case 'n': neighbors(vi
);
427 voro_print_vector(vi
,fp
);
430 // Area-related output
431 case 'a': fprintf(fp
,"%g",area());break;
435 fprintf(fp
,"%g %g",cx
,cy
);
440 fprintf(fp
,"%g %g",x
+cx
,y
+cy
);
443 // End-of-string reached
446 // The percent sign is not part of a
448 default: putc('%',fp
);putc(*fmp
,fp
);
450 } else putc(*fmp
,fp
);
456 /** Doubles the storage for the vertices, by reallocating the pts and ed
457 * arrays. If the allocation exceeds the absolute maximum set in max_vertices,
458 * then the routine exits with a fatal error. */
459 template<class vc_class
>
460 void voronoicell_base_2d::add_memory_vertices(vc_class
&vc
) {
461 double *ppe(pts
+2*current_vertices
);
462 int *ede(ed
+2*current_vertices
);
464 // Double the memory allocation and check it is within range
465 current_vertices
<<=1;
466 if(current_vertices
>max_vertices
) voro_fatal_error("Vertex memory allocation exceeded absolute maximum",VOROPP_MEMORY_ERROR
);
467 #if VOROPP_VERBOSE >=2
468 fprintf(stderr
,"Vertex memory scaled up to %d\n",current_vertices
);
471 // Copy the vertex positions
472 double *npts(new double[2*current_vertices
]),*npp(npts
),*pp(pts
);
473 while(pp
<ppe
) *(npp
++)=*(pp
++);
474 delete [] pts
;pts
=npts
;
476 // Copy the edge table
477 int *ned(new int[2*current_vertices
]),*nep(ned
),*edp(ed
);
478 while(edp
<ede
) *(nep
++)=*(edp
++);
481 // Double the neighbor information if necessary
482 vc
.n_add_memory_vertices();
485 inline void voronoicell_neighbor_2d::n_add_memory_vertices() {
486 int *nne
=new int[current_vertices
],*nee
=ne
+(current_vertices
>>1),*nep
=ne
,*nnep
=nne
;
487 while(nep
<nee
) *(nnep
++)=*(nep
++);
491 void voronoicell_neighbor_2d::neighbors(vector
<int> &v
) {
493 for(int i
=0;i
<p
;i
++) v
[i
]=ne
[i
];
496 void voronoicell_neighbor_2d::init(double xmin
,double xmax
,double ymin
,double ymax
) {
497 init_base(xmin
,xmax
,ymin
,ymax
);
498 *ne
=-3;ne
[1]=-2;ne
[2]=-4;ne
[3]=-1;
501 /** Doubles the size allocation of the delete stack. If the allocation exceeds
502 * the absolute maximum set in max_delete_size, then routine causes a fatal
504 * \param[in] stackp a reference to the current stack pointer. */
505 void voronoicell_base_2d::add_memory_ds(int *&stackp
) {
506 current_delete_size
<<=1;
507 if(current_delete_size
>max_delete_size
) voro_fatal_error("Delete stack 1 memory allocation exceeded absolute maximum",VOROPP_MEMORY_ERROR
);
508 #if VOROPP_VERBOSE >=2
509 fprintf(stderr
,"Delete stack 1 memory scaled up to %d\n",current_delete_size
);
511 int *dsn(new int[current_delete_size
]),*dsnp(dsn
),*dsp(ds
);
512 while(dsp
<stackp
) *(dsnp
++)=*(dsp
++);
513 delete [] ds
;ds
=dsn
;stackp
=dsnp
;
514 stacke
=ds
+current_delete_size
;
517 // Explicit instantiation
518 template bool voronoicell_base_2d::nplane(voronoicell_2d
&,double,double,double,int);
519 template bool voronoicell_base_2d::nplane(voronoicell_neighbor_2d
&,double,double,double,int);
520 template bool voronoicell_base_2d::nplane_cut(voronoicell_2d
&,double,double,double,int,double,int);
521 template bool voronoicell_base_2d::nplane_cut(voronoicell_neighbor_2d
&,double,double,double,int,double,int);
522 template void voronoicell_base_2d::add_memory_vertices(voronoicell_2d
&);
523 template void voronoicell_base_2d::add_memory_vertices(voronoicell_neighbor_2d
&);
524 template bool voronoicell_base_2d::nplane(voronoicell_nonconvex_2d
&,double,double,double,int);
525 template bool voronoicell_base_2d::nplane(voronoicell_nonconvex_neighbor_2d
&,double,double,double,int);
526 template bool voronoicell_base_2d::nplane_cut(voronoicell_nonconvex_2d
&,double,double,double,int,double,int);
527 template bool voronoicell_base_2d::nplane_cut(voronoicell_nonconvex_neighbor_2d
&,double,double,double,int,double,int);
528 template void voronoicell_base_2d::add_memory_vertices(voronoicell_nonconvex_2d
&);
529 template void voronoicell_base_2d::add_memory_vertices(voronoicell_nonconvex_neighbor_2d
&);