1 // Voro++, a 3D cell-based Voronoi library
3 // Author : Chris H. Rycroft (LBL / UC Berkeley)
4 // Email : chr@alum.mit.edu
5 // Date : August 30th 2011
8 * \brief Function implementations for the container and related classes. */
10 #include "container.hh"
14 /** The class constructor sets up the geometry of container, initializing the
15 * minimum and maximum coordinates in each direction, and setting whether each
16 * direction is periodic or not. It divides the container into a rectangular
17 * grid of blocks, and allocates memory for each of these for storing particle
19 * \param[in] (ax_,bx_) the minimum and maximum x coordinates.
20 * \param[in] (ay_,by_) the minimum and maximum y coordinates.
21 * \param[in] (az_,bz_) the minimum and maximum z coordinates.
22 * \param[in] (nx_,ny_,nz_) the number of grid blocks in each of the three
23 * coordinate directions.
24 * \param[in] (xperiodic_,yperiodic_,zperiodic_) flags setting whether the
25 * container is periodic in each
26 * coordinate direction.
27 * \param[in] init_mem the initial memory allocation for each block.
28 * \param[in] ps_ the number of floating point entries to store for each
30 container_base::container_base(double ax_
,double bx_
,double ay_
,double by_
,double az_
,double bz_
,
31 int nx_
,int ny_
,int nz_
,bool xperiodic_
,bool yperiodic_
,bool zperiodic_
,int init_mem
,int ps_
)
32 : voro_base(nx_
,ny_
,nz_
,(bx_
-ax_
)/nx_
,(by_
-ay_
)/ny_
,(bz_
-az_
)/nz_
),
33 ax(ax_
), bx(bx_
), ay(ay_
), by(by_
), az(az_
), bz(bz_
),
34 max_len_sq((bx
-ax
)*(bx
-ax
)*(xperiodic_
?0.25:1)+(by
-ay
)*(by
-ay
)*(yperiodic_
?0.25:1)
35 +(bz
-az
)*(bz
-az
)*(zperiodic_
?0.25:1)),
36 xperiodic(xperiodic_
), yperiodic(yperiodic_
), zperiodic(zperiodic_
),
37 id(new int*[nxyz
]), p(new double*[nxyz
]), co(new int[nxyz
]), mem(new int[nxyz
]), ps(ps_
) {
40 for(l
=0;l
<nxyz
;l
++) co
[l
]=0;
41 for(l
=0;l
<nxyz
;l
++) mem
[l
]=init_mem
;
42 for(l
=0;l
<nxyz
;l
++) id
[l
]=new int[init_mem
];
43 for(l
=0;l
<nxyz
;l
++) p
[l
]=new double[ps
*init_mem
];
46 /** The container destructor frees the dynamically allocated memory. */
47 container_base::~container_base() {
49 for(l
=0;l
<nxyz
;l
++) delete [] p
[l
];
50 for(l
=0;l
<nxyz
;l
++) delete [] id
[l
];
57 /** The class constructor sets up the geometry of container.
58 * \param[in] (ax_,bx_) the minimum and maximum x coordinates.
59 * \param[in] (ay_,by_) the minimum and maximum y coordinates.
60 * \param[in] (az_,bz_) the minimum and maximum z coordinates.
61 * \param[in] (nx_,ny_,nz_) the number of grid blocks in each of the three
62 * coordinate directions.
63 * \param[in] (xperiodic_,yperiodic_,zperiodic_) flags setting whether the
64 * container is periodic in each
65 * coordinate direction.
66 * \param[in] init_mem the initial memory allocation for each block. */
67 container::container(double ax_
,double bx_
,double ay_
,double by_
,double az_
,double bz_
,
68 int nx_
,int ny_
,int nz_
,bool xperiodic_
,bool yperiodic_
,bool zperiodic_
,int init_mem
)
69 : container_base(ax_
,bx_
,ay_
,by_
,az_
,bz_
,nx_
,ny_
,nz_
,xperiodic_
,yperiodic_
,zperiodic_
,init_mem
,3),
70 vc(*this,xperiodic_
?2*nx_
+1:nx_
,yperiodic_
?2*ny_
+1:ny_
,zperiodic_
?2*nz_
+1:nz_
) {}
72 /** The class constructor sets up the geometry of container.
73 * \param[in] (ax_,bx_) the minimum and maximum x coordinates.
74 * \param[in] (ay_,by_) the minimum and maximum y coordinates.
75 * \param[in] (az_,bz_) the minimum and maximum z coordinates.
76 * \param[in] (nx_,ny_,nz_) the number of grid blocks in each of the three
77 * coordinate directions.
78 * \param[in] (xperiodic_,yperiodic_,zperiodic_) flags setting whether the
79 * container is periodic in each
80 * coordinate direction.
81 * \param[in] init_mem the initial memory allocation for each block. */
82 container_poly::container_poly(double ax_
,double bx_
,double ay_
,double by_
,double az_
,double bz_
,
83 int nx_
,int ny_
,int nz_
,bool xperiodic_
,bool yperiodic_
,bool zperiodic_
,int init_mem
)
84 : container_base(ax_
,bx_
,ay_
,by_
,az_
,bz_
,nx_
,ny_
,nz_
,xperiodic_
,yperiodic_
,zperiodic_
,init_mem
,4),
85 vc(*this,xperiodic_
?2*nx_
+1:nx_
,yperiodic_
?2*ny_
+1:ny_
,zperiodic_
?2*nz_
+1:nz_
) {ppr
=p
;}
87 /** Put a particle into the correct region of the container.
88 * \param[in] n the numerical ID of the inserted particle.
89 * \param[in] (x,y,z) the position vector of the inserted particle. */
90 void container::put(int n
,double x
,double y
,double z
) {
92 if(put_locate_block(ijk
,x
,y
,z
)) {
94 double *pp
=p
[ijk
]+3*co
[ijk
]++;
95 *(pp
++)=x
;*(pp
++)=y
;*pp
=z
;
99 /** Put a particle into the correct region of the container.
100 * \param[in] n the numerical ID of the inserted particle.
101 * \param[in] (x,y,z) the position vector of the inserted particle.
102 * \param[in] r the radius of the particle. */
103 void container_poly::put(int n
,double x
,double y
,double z
,double r
) {
105 if(put_locate_block(ijk
,x
,y
,z
)) {
107 double *pp
=p
[ijk
]+4*co
[ijk
]++;
108 *(pp
++)=x
;*(pp
++)=y
;*(pp
++)=z
;*pp
=r
;
109 if(max_radius
<r
) max_radius
=r
;
113 /** Put a particle into the correct region of the container, also recording
114 * into which region it was stored.
115 * \param[in] vo the ordering class in which to record the region.
116 * \param[in] n the numerical ID of the inserted particle.
117 * \param[in] (x,y,z) the position vector of the inserted particle. */
118 void container::put(particle_order
&vo
,int n
,double x
,double y
,double z
) {
120 if(put_locate_block(ijk
,x
,y
,z
)) {
123 double *pp
=p
[ijk
]+3*co
[ijk
]++;
124 *(pp
++)=x
;*(pp
++)=y
;*pp
=z
;
128 /** Put a particle into the correct region of the container, also recording
129 * into which region it was stored.
130 * \param[in] vo the ordering class in which to record the region.
131 * \param[in] n the numerical ID of the inserted particle.
132 * \param[in] (x,y,z) the position vector of the inserted particle.
133 * \param[in] r the radius of the particle. */
134 void container_poly::put(particle_order
&vo
,int n
,double x
,double y
,double z
,double r
) {
136 if(put_locate_block(ijk
,x
,y
,z
)) {
139 double *pp
=p
[ijk
]+4*co
[ijk
]++;
140 *(pp
++)=x
;*(pp
++)=y
;*(pp
++)=z
;*pp
=r
;
141 if(max_radius
<r
) max_radius
=r
;
145 /** This routine takes a particle position vector, tries to remap it into the
146 * primary domain. If successful, it computes the region into which it can be
147 * stored and checks that there is enough memory within this region to store
149 * \param[out] ijk the region index.
150 * \param[in,out] (x,y,z) the particle position, remapped into the primary
151 * domain if necessary.
152 * \return True if the particle can be successfully placed into the container,
153 * false otherwise. */
154 bool container_base::put_locate_block(int &ijk
,double &x
,double &y
,double &z
) {
155 if(put_remap(ijk
,x
,y
,z
)) {
156 if(co
[ijk
]==mem
[ijk
]) add_particle_memory(ijk
);
159 #if VOROPP_REPORT_OUT_OF_BOUNDS ==1
160 fprintf(stderr
,"Out of bounds: (x,y,z)=(%g,%g,%g)\n",x
,y
,z
);
165 /** Takes a particle position vector and computes the region index into which
166 * it should be stored. If the container is periodic, then the routine also
167 * maps the particle position to ensure it is in the primary domain. If the
168 * container is not periodic, the routine bails out.
169 * \param[out] ijk the region index.
170 * \param[in,out] (x,y,z) the particle position, remapped into the primary
171 * domain if necessary.
172 * \return True if the particle can be successfully placed into the container,
173 * false otherwise. */
174 inline bool container_base::put_remap(int &ijk
,double &x
,double &y
,double &z
) {
177 ijk
=step_int((x
-ax
)*xsp
);
178 if(xperiodic
) {l
=step_mod(ijk
,nx
);x
+=boxx
*(l
-ijk
);ijk
=l
;}
179 else if(ijk
<0||ijk
>=nx
) return false;
181 int j
=step_int((y
-ay
)*ysp
);
182 if(yperiodic
) {l
=step_mod(j
,ny
);y
+=boxy
*(l
-j
);j
=l
;}
183 else if(j
<0||j
>=ny
) return false;
185 int k
=step_int((z
-az
)*zsp
);
186 if(zperiodic
) {l
=step_mod(k
,nz
);z
+=boxz
*(l
-k
);k
=l
;}
187 else if(k
<0||k
>=nz
) return false;
193 /** Takes a position vector and attempts to remap it into the primary domain.
194 * \param[out] (ai,aj,ak) the periodic image displacement that the vector is in,
195 * with (0,0,0) corresponding to the primary domain.
196 * \param[out] (ci,cj,ck) the index of the block that the position vector is
197 * within, once it has been remapped.
198 * \param[in,out] (x,y,z) the position vector to consider, which is remapped
199 * into the primary domain during the routine.
200 * \param[out] ijk the block index that the vector is within.
201 * \return True if the particle is within the container or can be remapped into
202 * it, false if it lies outside of the container bounds. */
203 inline bool container_base::remap(int &ai
,int &aj
,int &ak
,int &ci
,int &cj
,int &ck
,double &x
,double &y
,double &z
,int &ijk
) {
204 ci
=step_int((x
-ax
)*xsp
);
206 if(xperiodic
) {ai
=step_div(ci
,nx
);x
-=ai
*(bx
-ax
);ci
-=ai
*nx
;}
210 cj
=step_int((y
-ay
)*ysp
);
212 if(yperiodic
) {aj
=step_div(cj
,ny
);y
-=aj
*(by
-ay
);cj
-=aj
*ny
;}
216 ck
=step_int((z
-az
)*zsp
);
218 if(zperiodic
) {ak
=step_div(ck
,nz
);z
-=ak
*(bz
-az
);ck
-=ak
*nz
;}
226 /** Takes a vector and finds the particle whose Voronoi cell contains that
227 * vector. This is equivalent to finding the particle which is nearest to the
228 * vector. Additional wall classes are not considered by this routine.
229 * \param[in] (x,y,z) the vector to test.
230 * \param[out] (rx,ry,rz) the position of the particle whose Voronoi cell
231 * contains the vector. If the container is periodic,
232 * this may point to a particle in a periodic image of
233 * the primary domain.
234 * \param[out] pid the ID of the particle.
235 * \return True if a particle was found. If the container has no particles,
236 * then the search will not find a Voronoi cell and false is returned. */
237 bool container::find_voronoi_cell(double x
,double y
,double z
,double &rx
,double &ry
,double &rz
,int &pid
) {
238 int ai
,aj
,ak
,ci
,cj
,ck
,ijk
;
242 // If the given vector lies outside the domain, but the container
243 // is periodic, then remap it back into the domain
244 if(!remap(ai
,aj
,ak
,ci
,cj
,ck
,x
,y
,z
,ijk
)) return false;
245 vc
.find_voronoi_cell(x
,y
,z
,ci
,cj
,ck
,ijk
,w
,mrs
);
249 // Assemble the position vector of the particle to be returned,
250 // applying a periodic remapping if necessary
251 if(xperiodic
) {ci
+=w
.di
;if(ci
<0||ci
>=nx
) ai
+=step_div(ci
,nx
);}
252 if(yperiodic
) {cj
+=w
.dj
;if(cj
<0||cj
>=ny
) aj
+=step_div(cj
,ny
);}
253 if(zperiodic
) {ck
+=w
.dk
;if(ck
<0||ck
>=nz
) ak
+=step_div(ck
,nz
);}
254 rx
=p
[w
.ijk
][3*w
.l
]+ai
*(bx
-ax
);
255 ry
=p
[w
.ijk
][3*w
.l
+1]+aj
*(by
-ay
);
256 rz
=p
[w
.ijk
][3*w
.l
+2]+ak
*(bz
-az
);
261 // If no particle if found then just return false
265 /** Takes a vector and finds the particle whose Voronoi cell contains that
266 * vector. Additional wall classes are not considered by this routine.
267 * \param[in] (x,y,z) the vector to test.
268 * \param[out] (rx,ry,rz) the position of the particle whose Voronoi cell
269 * contains the vector. If the container is periodic,
270 * this may point to a particle in a periodic image of
271 * the primary domain.
272 * \param[out] pid the ID of the particle.
273 * \return True if a particle was found. If the container has no particles,
274 * then the search will not find a Voronoi cell and false is returned. */
275 bool container_poly::find_voronoi_cell(double x
,double y
,double z
,double &rx
,double &ry
,double &rz
,int &pid
) {
276 int ai
,aj
,ak
,ci
,cj
,ck
,ijk
;
280 // If the given vector lies outside the domain, but the container
281 // is periodic, then remap it back into the domain
282 if(!remap(ai
,aj
,ak
,ci
,cj
,ck
,x
,y
,z
,ijk
)) return false;
283 vc
.find_voronoi_cell(x
,y
,z
,ci
,cj
,ck
,ijk
,w
,mrs
);
287 // Assemble the position vector of the particle to be returned,
288 // applying a periodic remapping if necessary
289 if(xperiodic
) {ci
+=w
.di
;if(ci
<0||ci
>=nx
) ai
+=step_div(ci
,nx
);}
290 if(yperiodic
) {cj
+=w
.dj
;if(cj
<0||cj
>=ny
) aj
+=step_div(cj
,ny
);}
291 if(zperiodic
) {ck
+=w
.dk
;if(ck
<0||ck
>=nz
) ak
+=step_div(ck
,nz
);}
292 rx
=p
[w
.ijk
][4*w
.l
]+ai
*(bx
-ax
);
293 ry
=p
[w
.ijk
][4*w
.l
+1]+aj
*(by
-ay
);
294 rz
=p
[w
.ijk
][4*w
.l
+2]+ak
*(bz
-az
);
299 // If no particle if found then just return false
303 /** Increase memory for a particular region.
304 * \param[in] i the index of the region to reallocate. */
305 void container_base::add_particle_memory(int i
) {
306 int l
,nmem
=mem
[i
]<<1;
308 // Carry out a check on the memory allocation size, and
309 // print a status message if requested
310 if(nmem
>max_particle_memory
)
311 voro_fatal_error("Absolute maximum memory allocation exceeded",VOROPP_MEMORY_ERROR
);
312 #if VOROPP_VERBOSE >=3
313 fprintf(stderr
,"Particle memory in region %d scaled up to %d\n",i
,nmem
);
316 // Allocate new memory and copy in the contents of the old arrays
317 int *idp
=new int[nmem
];
318 for(l
=0;l
<co
[i
];l
++) idp
[l
]=id
[i
][l
];
319 double *pp
=new double[ps
*nmem
];
320 for(l
=0;l
<ps
*co
[i
];l
++) pp
[l
]=p
[i
][l
];
322 // Update pointers and delete old arrays
324 delete [] id
[i
];id
[i
]=idp
;
325 delete [] p
[i
];p
[i
]=pp
;
328 /** Import a list of particles from an open file stream into the container.
329 * Entries of four numbers (Particle ID, x position, y position, z position)
330 * are searched for. If the file cannot be successfully read, then the routine
331 * causes a fatal error.
332 * \param[in] fp the file handle to read from. */
333 void container::import(FILE *fp
) {
336 while((j
=fscanf(fp
,"%d %lg %lg %lg",&i
,&x
,&y
,&z
))==4) put(i
,x
,y
,z
);
337 if(j
!=EOF
) voro_fatal_error("File import error",VOROPP_FILE_ERROR
);
340 /** Import a list of particles from an open file stream, also storing the order
341 * of that the particles are read. Entries of four numbers (Particle ID, x
342 * position, y position, z position) are searched for. If the file cannot be
343 * successfully read, then the routine causes a fatal error.
344 * \param[in,out] vo a reference to an ordering class to use.
345 * \param[in] fp the file handle to read from. */
346 void container::import(particle_order
&vo
,FILE *fp
) {
349 while((j
=fscanf(fp
,"%d %lg %lg %lg",&i
,&x
,&y
,&z
))==4) put(vo
,i
,x
,y
,z
);
350 if(j
!=EOF
) voro_fatal_error("File import error",VOROPP_FILE_ERROR
);
353 /** Import a list of particles from an open file stream into the container.
354 * Entries of five numbers (Particle ID, x position, y position, z position,
355 * radius) are searched for. If the file cannot be successfully read, then the
356 * routine causes a fatal error.
357 * \param[in] fp the file handle to read from. */
358 void container_poly::import(FILE *fp
) {
361 while((j
=fscanf(fp
,"%d %lg %lg %lg %lg",&i
,&x
,&y
,&z
,&r
))==5) put(i
,x
,y
,z
,r
);
362 if(j
!=EOF
) voro_fatal_error("File import error",VOROPP_FILE_ERROR
);
365 /** Import a list of particles from an open file stream, also storing the order
366 * of that the particles are read. Entries of four numbers (Particle ID, x
367 * position, y position, z position, radius) are searched for. If the file
368 * cannot be successfully read, then the routine causes a fatal error.
369 * \param[in,out] vo a reference to an ordering class to use.
370 * \param[in] fp the file handle to read from. */
371 void container_poly::import(particle_order
&vo
,FILE *fp
) {
374 while((j
=fscanf(fp
,"%d %lg %lg %lg %lg",&i
,&x
,&y
,&z
,&r
))==5) put(vo
,i
,x
,y
,z
,r
);
375 if(j
!=EOF
) voro_fatal_error("File import error",VOROPP_FILE_ERROR
);
378 /** Outputs the a list of all the container regions along with the number of
379 * particles stored within each. */
380 void container_base::region_count() {
382 for(k
=0;k
<nz
;k
++) for(j
=0;j
<ny
;j
++) for(i
=0;i
<nx
;i
++)
383 printf("Region (%d,%d,%d): %d particles\n",i
,j
,k
,*(cop
++));
386 /** Clears a container of particles. */
387 void container::clear() {
388 for(int *cop
=co
;cop
<co
+nxyz
;cop
++) *cop
=0;
391 /** Clears a container of particles, also clearing resetting the maximum radius
393 void container_poly::clear() {
394 for(int *cop
=co
;cop
<co
+nxyz
;cop
++) *cop
=0;
398 /** Computes all the Voronoi cells and saves customized information about them.
399 * \param[in] format the custom output string to use.
400 * \param[in] fp a file handle to write to. */
401 void container::print_custom(const char *format
,FILE *fp
) {
402 c_loop_all
vl(*this);
403 print_custom(vl
,format
,fp
);
406 /** Computes all the Voronoi cells and saves customized
407 * information about them.
408 * \param[in] format the custom output string to use.
409 * \param[in] fp a file handle to write to. */
410 void container_poly::print_custom(const char *format
,FILE *fp
) {
411 c_loop_all
vl(*this);
412 print_custom(vl
,format
,fp
);
415 /** Computes all the Voronoi cells and saves customized information about them.
416 * \param[in] format the custom output string to use.
417 * \param[in] filename the name of the file to write to. */
418 void container::print_custom(const char *format
,const char *filename
) {
419 FILE *fp
=safe_fopen(filename
,"w");
420 print_custom(format
,fp
);
424 /** Computes all the Voronoi cells and saves customized
425 * information about them
426 * \param[in] format the custom output string to use.
427 * \param[in] filename the name of the file to write to. */
428 void container_poly::print_custom(const char *format
,const char *filename
) {
429 FILE *fp
=safe_fopen(filename
,"w");
430 print_custom(format
,fp
);
434 /** Computes all of the Voronoi cells in the container, but does nothing
435 * with the output. It is useful for measuring the pure computation time
436 * of the Voronoi algorithm, without any additional calculations such as
437 * volume evaluation or cell output. */
438 void container::compute_all_cells() {
439 voronoicell
c(*this);
440 c_loop_all
vl(*this);
441 if(vl
.start()) do compute_cell(c
,vl
);
445 /** Computes all of the Voronoi cells in the container, but does nothing
446 * with the output. It is useful for measuring the pure computation time
447 * of the Voronoi algorithm, without any additional calculations such as
448 * volume evaluation or cell output. */
449 void container_poly::compute_all_cells() {
450 voronoicell
c(*this);
451 c_loop_all
vl(*this);
452 if(vl
.start()) do compute_cell(c
,vl
);while(vl
.inc());
455 /** Calculates all of the Voronoi cells and sums their volumes. In most cases
456 * without walls, the sum of the Voronoi cell volumes should equal the volume
457 * of the container to numerical precision.
458 * \return The sum of all of the computed Voronoi volumes. */
459 double container::sum_cell_volumes() {
460 voronoicell
c(*this);
462 c_loop_all
vl(*this);
463 if(vl
.start()) do if(compute_cell(c
,vl
)) vol
+=c
.volume();while(vl
.inc());
467 /** Calculates all of the Voronoi cells and sums their volumes. In most cases
468 * without walls, the sum of the Voronoi cell volumes should equal the volume
469 * of the container to numerical precision.
470 * \return The sum of all of the computed Voronoi volumes. */
471 double container_poly::sum_cell_volumes() {
472 voronoicell
c(*this);
474 c_loop_all
vl(*this);
475 if(vl
.start()) do if(compute_cell(c
,vl
)) vol
+=c
.volume();while(vl
.inc());
479 /** This function tests to see if a given vector lies within the container
480 * bounds and any walls.
481 * \param[in] (x,y,z) the position vector to be tested.
482 * \return True if the point is inside the container, false if the point is
484 bool container_base::point_inside(double x
,double y
,double z
) {
485 if(x
<ax
||x
>bx
||y
<ay
||y
>by
||z
<az
||z
>bz
) return false;
486 return point_inside_walls(x
,y
,z
);
489 /** Draws an outline of the domain in gnuplot format.
490 * \param[in] fp the file handle to write to. */
491 void container_base::draw_domain_gnuplot(FILE *fp
) {
492 fprintf(fp
,"%g %g %g\n%g %g %g\n%g %g %g\n%g %g %g\n",ax
,ay
,az
,bx
,ay
,az
,bx
,by
,az
,ax
,by
,az
);
493 fprintf(fp
,"%g %g %g\n%g %g %g\n%g %g %g\n%g %g %g\n",ax
,by
,bz
,bx
,by
,bz
,bx
,ay
,bz
,ax
,ay
,bz
);
494 fprintf(fp
,"%g %g %g\n\n%g %g %g\n%g %g %g\n\n",ax
,by
,bz
,ax
,ay
,az
,ax
,ay
,bz
);
495 fprintf(fp
,"%g %g %g\n%g %g %g\n\n%g %g %g\n%g %g %g\n\n",bx
,ay
,az
,bx
,ay
,bz
,bx
,by
,az
,bx
,by
,bz
);
498 /** Draws an outline of the domain in POV-Ray format.
499 * \param[in] fp the file handle to write to. */
500 void container_base::draw_domain_pov(FILE *fp
) {
501 fprintf(fp
,"cylinder{<%g,%g,%g>,<%g,%g,%g>,rr}\n"
502 "cylinder{<%g,%g,%g>,<%g,%g,%g>,rr}\n",ax
,ay
,az
,bx
,ay
,az
,ax
,by
,az
,bx
,by
,az
);
503 fprintf(fp
,"cylinder{<%g,%g,%g>,<%g,%g,%g>,rr}\n"
504 "cylinder{<%g,%g,%g>,<%g,%g,%g>,rr}\n",ax
,by
,bz
,bx
,by
,bz
,ax
,ay
,bz
,bx
,ay
,bz
);
505 fprintf(fp
,"cylinder{<%g,%g,%g>,<%g,%g,%g>,rr}\n"
506 "cylinder{<%g,%g,%g>,<%g,%g,%g>,rr}\n",ax
,ay
,az
,ax
,by
,az
,bx
,ay
,az
,bx
,by
,az
);
507 fprintf(fp
,"cylinder{<%g,%g,%g>,<%g,%g,%g>,rr}\n"
508 "cylinder{<%g,%g,%g>,<%g,%g,%g>,rr}\n",bx
,ay
,bz
,bx
,by
,bz
,ax
,ay
,bz
,ax
,by
,bz
);
509 fprintf(fp
,"cylinder{<%g,%g,%g>,<%g,%g,%g>,rr}\n"
510 "cylinder{<%g,%g,%g>,<%g,%g,%g>,rr}\n",ax
,ay
,az
,ax
,ay
,bz
,bx
,ay
,az
,bx
,ay
,bz
);
511 fprintf(fp
,"cylinder{<%g,%g,%g>,<%g,%g,%g>,rr}\n"
512 "cylinder{<%g,%g,%g>,<%g,%g,%g>,rr}\n",bx
,by
,az
,bx
,by
,bz
,ax
,by
,az
,ax
,by
,bz
);
513 fprintf(fp
,"sphere{<%g,%g,%g>,rr}\nsphere{<%g,%g,%g>,rr}\n"
514 "sphere{<%g,%g,%g>,rr}\nsphere{<%g,%g,%g>,rr}\n",ax
,ay
,az
,bx
,ay
,az
,ax
,by
,az
,bx
,by
,az
);
515 fprintf(fp
,"sphere{<%g,%g,%g>,rr}\nsphere{<%g,%g,%g>,rr}\n"
516 "sphere{<%g,%g,%g>,rr}\nsphere{<%g,%g,%g>,rr}\n",ax
,ay
,bz
,bx
,ay
,bz
,ax
,by
,bz
,bx
,by
,bz
);
520 /** The wall_list constructor sets up an array of pointers to wall classes. */
521 wall_list::wall_list() : walls(new wall
*[init_wall_size
]), wep(walls
), wel(walls
+init_wall_size
),
522 current_wall_size(init_wall_size
) {}
524 /** The wall_list destructor frees the array of pointers to the wall classes.
526 wall_list::~wall_list() {
530 /** Adds all of the walls on another wall_list to this class.
531 * \param[in] wl a reference to the wall class. */
532 void wall_list::add_wall(wall_list
&wl
) {
533 for(wall
**wp
=wl
.walls
;wp
<wl
.wep
;wp
++) add_wall(*wp
);
536 /** Deallocates all of the wall classes pointed to by the wall_list. */
537 void wall_list::deallocate() {
538 for(wall
**wp
=walls
;wp
<wep
;wp
++) delete *wp
;
541 /** Increases the memory allocation for the walls array. */
542 void wall_list::increase_wall_memory() {
543 current_wall_size
<<=1;
544 if(current_wall_size
>max_wall_size
)
545 voro_fatal_error("Wall memory allocation exceeded absolute maximum",VOROPP_MEMORY_ERROR
);
546 wall
**nwalls
=new wall
*[current_wall_size
],**nwp
=nwalls
,**wp
=walls
;
547 while(wp
<wep
) *(nwp
++)=*(wp
++);
549 walls
=nwalls
;wel
=walls
+current_wall_size
;wep
=nwp
;