1 #include "v_network.hh"
3 /** Initializes the Voronoi network object. The geometry is set up to match a
4 * corresponding container class, and memory is allocated for the network.
5 * \param[in] c a reference to a container or container_poly class. */
6 template<class c_class
>
7 voronoi_network::voronoi_network(c_class
&c
,double net_tol_
) :
8 bx(c
.bx
), bxy(c
.bxy
), by(c
.by
), bxz(c
.bxz
), byz(c
.byz
), bz(c
.bz
),
9 nx(c
.nx
), ny(c
.ny
), nz(c
.nz
), nxyz(nx
*ny
*nz
),
10 xsp(nx
/bx
), ysp(ny
/by
), zsp(nz
/bz
), net_tol(net_tol_
) {
13 // Allocate memory for vertex structure
14 pts
=new double*[nxyz
];
19 pts
[l
]=new double[4*init_network_vertex_memory
];
20 idmem
[l
]=new int[init_network_vertex_memory
];
21 ptsc
[l
]=0;ptsmem
[l
]=init_network_vertex_memory
;
24 // Allocate memory for network edges and related statistics
25 edc
=0;edmem
=init_network_vertex_memory
*nxyz
;
28 pered
=new unsigned int*[edmem
];
29 raded
=new block
*[edmem
];
34 // Allocate memory for back pointers
38 // Allocate edge memory
39 for(l
=0;l
<edmem
;l
++) {
40 ed
[l
]=new int[2*init_network_edge_memory
];
41 ne
[l
]=ed
[l
]+init_network_edge_memory
;
43 for(l
=0;l
<edmem
;l
++) raded
[l
]=new block
[init_network_edge_memory
];
44 for(l
=0;l
<edmem
;l
++) pered
[l
]=new unsigned int[init_network_edge_memory
];
45 for(l
=0;l
<edmem
;l
++) {nu
[l
]=nec
[l
]=0;numem
[l
]=init_network_edge_memory
;}
48 vmap
=new int[4*init_vertices
];
49 map_mem
=init_vertices
;
52 /** The voronoi_network destructor removes the dynamically allocated memory. */
53 voronoi_network::~voronoi_network() {
56 // Remove Voronoi mapping array
59 // Remove individual edge arrays
60 for(l
=0;l
<edmem
;l
++) delete [] pered
[l
];
61 for(l
=0;l
<edmem
;l
++) delete [] raded
[l
];
62 for(l
=0;l
<edmem
;l
++) delete [] ed
[l
];
64 // Remove back pointers
65 delete [] regp
;delete [] reg
;
67 // Remove memory for edges and related statistics
68 delete [] numem
;delete [] nec
;delete [] nu
;
69 delete [] raded
;delete [] pered
;
70 delete [] ne
;delete [] ed
;
72 // Remove vertex structure arrays
77 delete [] ptsmem
;delete [] ptsc
;
78 delete [] idmem
;delete [] pts
;
81 /** Increase network memory for a particular region. */
82 void voronoi_network::add_network_memory(int l
) {
85 // Check to see that an absolute maximum in memory allocation
86 // has not been reached, to prevent runaway allocation
87 if(ptsmem
[l
]>max_network_vertex_memory
)
88 voro_fatal_error("Container vertex maximum memory allocation exceeded",VOROPP_MEMORY_ERROR
);
90 // Allocate new arrays
91 double *npts(new double[4*ptsmem
[l
]]);
92 int *nidmem(new int[ptsmem
[l
]]);
94 // Copy the contents of the old arrays into the new ones
95 for(int i
=0;i
<4*ptsc
[l
];i
++) npts
[i
]=pts
[l
][i
];
96 for(int i
=0;i
<ptsc
[l
];i
++) nidmem
[i
]=idmem
[l
][i
];
98 // Delete old arrays and update pointers to the new ones
99 delete [] pts
[l
];delete [] idmem
[l
];
100 pts
[l
]=npts
;idmem
[l
]=nidmem
;
103 /** Increase edge network memory. */
104 void voronoi_network::add_edge_network_memory() {
108 // Allocate new arrays
109 int **ned(new int*[edmem
]);
110 int **nne(new int*[edmem
]);
111 block
**nraded(new block
*[edmem
]);
112 unsigned int **npered(new unsigned int*[edmem
]);
113 int *nnu(new int[edmem
]);
114 int *nnec(new int[edmem
]);
115 int *nnumem(new int[edmem
]);
116 int *nreg(new int[edmem
]);
117 int *nregp(new int[edmem
]);
119 // Copy the contents of the old arrays into the new ones
132 // Carry out new allocation
134 ned
[i
]=new int[2*init_network_edge_memory
];
135 nne
[i
]=ned
[i
]+init_network_edge_memory
;
136 nnu
[i
]=nnec
[i
]=0;nnumem
[i
]=init_network_edge_memory
;
137 nraded
[i
]=new block
[init_network_edge_memory
];
138 npered
[i
++]=new unsigned int[init_network_edge_memory
];
141 // Delete old arrays and update pointers to the new ones
144 delete [] raded
;raded
=nraded
;
145 delete [] pered
;pered
=npered
;
147 delete [] nec
;nec
=nnec
;
148 delete [] numem
;numem
=nnumem
;
149 delete [] reg
;reg
=nreg
;
150 delete [] regp
;regp
=nregp
;
153 /** Increase a particular vertex memory. */
154 void voronoi_network::add_particular_vertex_memory(int l
) {
157 // Check that the vertex allocation does not exceed a maximum safe
159 if(numem
[l
]>max_vertex_order
)
160 voro_fatal_error("Particular vertex maximum memory allocation exceeded",VOROPP_MEMORY_ERROR
);
162 // Allocate new arrays
163 int *ned(new int[2*numem
[l
]]);
164 int *nne(ned
+numem
[l
]);
165 block
*nraded(new block
[numem
[l
]]);
166 unsigned int *npered(new unsigned int[numem
[l
]]);
168 // Copy the contents of the old arrays into the new ones
169 for(int i
=0;i
<nu
[l
];i
++) {
171 nraded
[i
]=raded
[l
][i
];
172 npered
[i
]=pered
[l
][i
];
174 for(int i
=0;i
<nec
[l
];i
++) nne
[i
]=ne
[l
][i
];
176 // Delete old arrays and update pointers to the new ones
177 delete [] ed
[l
];ed
[l
]=ned
;ne
[l
]=nne
;
178 delete [] raded
[l
];raded
[l
]=nraded
;
179 delete [] pered
[l
];pered
[l
]=npered
;
183 /** Increases the memory for the vertex mapping.
184 * \param[in] pmem the amount of memory needed. */
185 void voronoi_network::add_mapping_memory(int pmem
) {
186 do {map_mem
<<=1;} while(map_mem
<pmem
);
188 vmap
=new int[4*map_mem
];
191 /** Clears the class of all vertices and edges. */
192 void voronoi_network::clear_network() {
195 for(l
=0;l
<nxyz
;l
++) ptsc
[l
]=0;
196 for(l
=0;l
<edmem
;l
++) nu
[l
]=0;
199 /** Outputs the network in a format that can be read by gnuplot.
200 * \param[in] fp a file handle to write to. */
201 void voronoi_network::draw_network(FILE *fp
) {
206 ptsp
=pts
[reg
[l
]]+4*regp
[l
];
207 x
=*(ptsp
++);y
=*(ptsp
++);z
=*ptsp
;
208 for(q
=0;q
<nu
[l
];q
++) {
209 unpack_periodicity(pered
[l
][q
],ai
,aj
,ak
);
210 if(ed
[l
][q
]<l
&&ai
==0&&aj
==0&&ak
==0) continue;
211 ptsp
=pts
[reg
[ed
[l
][q
]]]+4*regp
[ed
[l
][q
]];
212 fprintf(fp
,"%g %g %g\n%g %g %g\n\n\n",x
,y
,z
,
213 *ptsp
+bx
*ai
+bxy
*aj
+bxz
*ak
,
214 ptsp
[1]+by
*aj
+byz
*ak
,ptsp
[2]+bz
*ak
);
219 /** Prints out the network.
220 * \param[in] fp a file handle to write to.
221 * \param[in] reverse_remove a boolean value, setting whether or not to remove
223 void voronoi_network::print_network(FILE *fp
,bool reverse_remove
) {
224 int ai
,aj
,ak
,j
,l
,ll
,q
;
225 double x
,y
,z
,x2
,y2
,z2
,*ptsp
;
227 // Print the vertex table
228 fprintf(fp
,"Vertex table:\n%d\n",edc
);
231 ptsp
=pts
[reg
[l
]];j
=4*regp
[l
];
232 fprintf(fp
,"%d %g %g %g %g",l
,ptsp
[j
],ptsp
[j
+1],ptsp
[j
+2],ptsp
[j
+3]);
233 for(ll
=0;ll
<nec
[l
];ll
++) fprintf(fp
," %d",ne
[l
][ll
]);
237 // Print out the edge table, loop over vertices
238 fputs("\nEdge table:\n",fp
);
241 // Store the position of this vertex
242 ptsp
=pts
[reg
[l
]];j
=4*regp
[l
];
243 x
=ptsp
[j
];y
=ptsp
[j
+1];z
=ptsp
[j
+2];
245 // Loop over edges of this vertex
246 for(q
=0;q
<nu
[l
];q
++) {
248 unpack_periodicity(pered
[l
][q
],ai
,aj
,ak
);
250 // If this option is enabled, then the code will not
251 // print edges from i to j for j<i.
252 if(reverse_remove
) if(ed
[l
][q
]<l
&&ai
==0&&aj
==0&&ak
==0) continue;
254 fprintf(fp
,"%d -> %d",l
,ed
[l
][q
]);
255 raded
[l
][q
].print(fp
);
257 // Compute and print the length of the edge
258 ptsp
=pts
[reg
[ed
[l
][q
]]];j
=4*regp
[ed
[l
][q
]];
259 x2
=ptsp
[j
]+ai
*bx
+aj
*bxy
+ak
*bxz
-x
;
260 y2
=ptsp
[j
+1]+aj
*by
+ak
*byz
-y
;
261 z2
=ptsp
[j
+2]+ak
*bz
-z
;
262 fprintf(fp
," %d %d %d %g\n",ai
,aj
,ak
,sqrt(x2
*x2
+y2
*y2
+z2
*z2
));
267 // Converts three periodic image displacements into a single unsigned integer.
268 // \param[in] i the periodic image in the x direction.
269 // \param[in] j the periodic image in the y direction.
270 // \param[in] k the periodic image in the z direction.
271 // \return The packed integer. */
272 inline unsigned int voronoi_network::pack_periodicity(int i
,int j
,int k
) {
273 unsigned int pa
=((unsigned int) (127+i
));
274 pa
<<=8;pa
+=((unsigned int) (127+j
));
275 pa
<<=8;pa
+=((unsigned int) (127+k
));
279 /** Unpacks an unsigned integer into three periodic image displacements.
280 * \param[in] pa the packed integer.
281 // \param[out] i the periodic image in the x direction.
282 // \param[out] j the periodic image in the y direction.
283 // \param[out] k the periodic image in the z direction. */
284 inline void voronoi_network::unpack_periodicity(unsigned int pa
,int &i
,int &j
,int &k
) {
285 i
=((signed int) (pa
>>16))-127;
286 j
=((signed int) ((pa
>>8)&255))-127;
287 k
=((signed int) (pa
&255))-127;
290 /** Adds a Voronoi cell to the network structure. The routine first checks all
291 * of the Voronoi cell vertices and merges them with existing ones where
292 * possible. Edges are then added to the structure.
293 * \param[in] c a reference to a Voronoi cell.
294 * \param[in] (x,y,z) the position of the Voronoi cell.
295 * \param[in] idn the ID number of the particle associated with the cell. */
296 template<class v_cell
>
297 void voronoi_network::add_to_network_internal(v_cell
&c
,int idn
,double x
,double y
,double z
,double rad
,int *cmap
) {
298 int i
,j
,k
,ijk
,l
,q
,ai
,aj
,ak
,*vmp(cmap
);
299 double gx
,gy
,vx
,vy
,vz
,crad
,*cp(c
.pts
);
301 // Loop over the vertices of the Voronoi cell
302 for(l
=0;l
<c
.p
;l
++,vmp
+=4) {
304 // Compute the real position of this vertex, and evaluate its
305 // position along the non-rectangular axes
306 vx
=x
+cp
[3*l
]*0.5;vy
=y
+cp
[3*l
+1]*0.5;vz
=z
+cp
[3*l
+2]*0.5;
307 gx
=vx
-vy
*(bxy
/by
)+vz
*(bxy
*byz
-by
*bxz
)/(by
*bz
);
310 // Compute the adjusted radius, which will be needed either way
311 crad
=0.5*sqrt(cp
[3*l
]*cp
[3*l
]+cp
[3*l
+1]*cp
[3*l
+1]+cp
[3*l
+2]*cp
[3*l
+2])-rad
;
313 // Check to see if a vertex very close to this one already
314 // exists in the network
315 if(search_previous(gx
,gy
,vx
,vy
,vz
,ijk
,q
,vmp
[1],vmp
[2],vmp
[3])) {
317 // If it does, then just map the Voronoi cell
321 // Store this radius if it smaller than the current
323 if(pts
[ijk
][4*q
+3]>crad
) pts
[ijk
][4*q
+3]=crad
;
325 k
=step_int(vz
*zsp
);if(k
<0||k
>=nz
) {ak
=step_div(k
,nz
);vx
-=bxz
*ak
;vy
-=byz
*ak
;vz
-=bz
*ak
;k
-=ak
*nz
;} else ak
=0;
326 j
=step_int(gy
*ysp
);if(j
<0||j
>=ny
) {aj
=step_div(j
,ny
);vx
-=bxy
*aj
;vy
-=by
*aj
;j
-=aj
*ny
;} else aj
=0;
327 i
=step_int(gx
*xsp
);if(i
<0||i
>=nx
) {ai
=step_div(i
,nx
);vx
-=bx
*ai
;i
-=ai
*nx
;} else ai
=0;
329 vmp
[1]=ai
;vmp
[2]=aj
;vmp
[3]=ak
;
332 if(edc
==edmem
) add_edge_network_memory();
333 if(ptsc
[ijk
]==ptsmem
[ijk
]) add_network_memory(ijk
);
335 reg
[edc
]=ijk
;regp
[edc
]=ptsc
[ijk
];
336 pts
[ijk
][4*ptsc
[ijk
]]=vx
;
337 pts
[ijk
][4*ptsc
[ijk
]+1]=vy
;
338 pts
[ijk
][4*ptsc
[ijk
]+2]=vz
;
339 pts
[ijk
][4*ptsc
[ijk
]+3]=crad
;
340 idmem
[ijk
][ptsc
[ijk
]++]=edc
;
344 // Add the neighbor information to this vertex
345 add_neighbor(*vmp
,idn
);
348 add_edges_to_network(c
,x
,y
,z
,rad
,cmap
);
351 /** Adds a neighboring particle ID to a vertex in the Voronoi network, first
352 * checking that the ID is not already recorded.
353 * \param[in] k the Voronoi vertex.
354 * \param[in] idn the particle ID number. */
355 inline void voronoi_network::add_neighbor(int k
,int idn
) {
356 for(int i
=0;i
<nec
[k
];i
++) if(ne
[k
][i
]==idn
) return;
357 if(nec
[k
]==numem
[k
]) add_particular_vertex_memory(k
);
361 /** Adds edges to the network structure, after the vertices have been
362 * considered. This routine assumes that the cmap array has a mapping between
363 * Voronoi cell vertices and Voronoi network vertices. */
364 template<class v_cell
>
365 void voronoi_network::add_edges_to_network(v_cell
&c
,double x
,double y
,double z
,double rad
,int *cmap
) {
366 int i
,j
,ai
,aj
,ak
,bi
,bj
,bk
,k
,l
,q
,*vmp
;unsigned int cper
;
367 double vx
,vy
,vz
,wx
,wy
,wz
,dx
,dy
,dz
,dis
;double *pp
;
369 vmp
=cmap
+4*l
;k
=*(vmp
++);ai
=*(vmp
++);aj
=*(vmp
++);ak
=*vmp
;
370 pp
=pts
[reg
[k
]]+4*regp
[k
];
371 vx
=pp
[0]+ai
*bx
+aj
*bxy
+ak
*bxz
;
372 vy
=pp
[1]+aj
*by
+ak
*byz
;
374 for(q
=0;q
<c
.nu
[l
];q
++) {
377 j
=*(vmp
++);bi
=*(vmp
++);bj
=*(vmp
++);bk
=*vmp
;
379 // Skip if this is a self-connecting edge
380 if(j
==k
&&bi
==ai
&&bj
==aj
&&bk
==ak
) continue;
381 cper
=pack_periodicity(bi
-ai
,bj
-aj
,bk
-ak
);
382 pp
=pts
[reg
[j
]]+(4*regp
[j
]);
383 wx
=pp
[0]+bi
*bx
+bj
*bxy
+bk
*bxz
;
384 wy
=pp
[1]+bj
*by
+bk
*byz
;
386 dx
=wx
-vx
;dy
=wy
-vy
;dz
=wz
-vz
;
387 dis
=(x
-vx
)*dx
+(y
-vy
)*dy
+(z
-vz
)*dz
;
388 dis
/=dx
*dx
+dy
*dy
+dz
*dz
;
389 if(dis
<0) dis
=0;if(dis
>1) dis
=1;
390 wx
=vx
-x
+dis
*dx
;wy
=vy
-y
+dis
*dy
;wz
=vz
-z
+dis
*dz
;
391 int nat
=not_already_there(k
,j
,cper
);
393 if(nu
[k
]==numem
[k
]) add_particular_vertex_memory(k
);
395 raded
[k
][nu
[k
]].first(sqrt(wx
*wx
+wy
*wy
+wz
*wz
)-rad
,dis
);
396 pered
[k
][nu
[k
]++]=cper
;
398 raded
[k
][nat
].add(sqrt(wx
*wx
+wy
*wy
+wz
*wz
)-rad
,dis
);
404 template<class v_cell
>
405 void voronoi_network::add_to_network_rectangular_internal(v_cell
&c
,int idn
,double x
,double y
,double z
,double rad
,int *cmap
) {
406 int i
,j
,k
,ijk
,l
,q
,ai
,aj
,ak
,*vmp(cmap
);
407 double vx
,vy
,vz
,crad
,*cp(c
.pts
);
409 for(l
=0;l
<c
.p
;l
++,vmp
+=4) {
410 vx
=x
+cp
[3*l
]*0.5;vy
=y
+cp
[3*l
+1]*0.5;vz
=z
+cp
[3*l
+2]*0.5;
411 crad
=0.5*sqrt(cp
[3*l
]*cp
[3*l
]+cp
[3*l
+1]*cp
[3*l
+1]+cp
[3*l
+2]*cp
[3*l
+2])-rad
;
412 if(safe_search_previous_rect(vx
,vy
,vz
,ijk
,q
,vmp
[1],vmp
[2],vmp
[3])) {
415 // Store this radius if it smaller than the current
417 if(pts
[ijk
][4*q
+3]>crad
) pts
[ijk
][4*q
+3]=crad
;
422 vz
-=ak
*bz
;vy
-=ak
*byz
;vx
-=ak
*bxz
;k
-=ak
*nz
;
427 vy
-=aj
*by
;vx
-=aj
*bxy
;j
-=aj
*ny
;
438 if(edc
==edmem
) add_edge_network_memory();
439 if(ptsc
[ijk
]==ptsmem
[ijk
]) add_network_memory(ijk
);
440 reg
[edc
]=ijk
;regp
[edc
]=ptsc
[ijk
];
441 pts
[ijk
][4*ptsc
[ijk
]]=vx
;
442 pts
[ijk
][4*ptsc
[ijk
]+1]=vy
;
443 pts
[ijk
][4*ptsc
[ijk
]+2]=vz
;
444 pts
[ijk
][4*ptsc
[ijk
]+3]=crad
;
445 idmem
[ijk
][ptsc
[ijk
]++]=edc
;
449 add_neighbor(*vmp
,idn
);
452 add_edges_to_network(c
,x
,y
,z
,rad
,cmap
);
455 int voronoi_network::not_already_there(int k
,int j
,unsigned int cper
) {
456 for(int i
=0;i
<nu
[k
];i
++) if(ed
[k
][i
]==j
&&pered
[k
][i
]==cper
) return i
;
460 bool voronoi_network::search_previous(double gx
,double gy
,double x
,double y
,double z
,int &ijk
,int &q
,int &pi
,int &pj
,int &pk
) {
461 int ai
=step_int((gx
-net_tol
)*xsp
),bi
=step_int((gx
+net_tol
)*xsp
);
462 int aj
=step_int((gy
-net_tol
)*ysp
),bj
=step_int((gy
+net_tol
)*ysp
);
463 int ak
=step_int((z
-net_tol
)*zsp
),bk
=step_int((z
+net_tol
)*zsp
);
465 double px
,py
,pz
,px2
,py2
,px3
,*pp
;
467 for(k
=ak
;k
<=bk
;k
++) {
468 pk
=step_div(k
,nz
);px
=pk
*bxz
;py
=pk
*byz
;pz
=pk
*bz
;mk
=k
-nz
*pk
;
469 for(j
=aj
;j
<=bj
;j
++) {
470 pj
=step_div(j
,ny
);px2
=px
+pj
*bxy
;py2
=py
+pj
*by
;mj
=j
-ny
*pj
;
471 for(i
=ai
;i
<=bi
;i
++) {
472 pi
=step_div(i
,nx
);px3
=px2
+pi
*bx
;mi
=i
-nx
*pi
;
473 ijk
=mi
+nx
*(mj
+ny
*mk
);
475 for(q
=0;q
<ptsc
[ijk
];q
++,pp
+=4) if(abs(*pp
+px3
-x
)<net_tol
&&abs(pp
[1]+py2
-y
)<net_tol
&&abs(pp
[2]+pz
-z
)<net_tol
) return true;
482 bool voronoi_network::safe_search_previous_rect(double x
,double y
,double z
,int &ijk
,int &q
,int &ci
,int &cj
,int &ck
) {
483 const double tol(0.5*net_tol
);
484 if(search_previous_rect(x
+tol
,y
+tol
,z
+tol
,ijk
,q
,ci
,cj
,ck
)) return true;
485 if(search_previous_rect(x
-tol
,y
+tol
,z
+tol
,ijk
,q
,ci
,cj
,ck
)) return true;
486 if(search_previous_rect(x
+tol
,y
-tol
,z
+tol
,ijk
,q
,ci
,cj
,ck
)) return true;
487 if(search_previous_rect(x
-tol
,y
-tol
,z
+tol
,ijk
,q
,ci
,cj
,ck
)) return true;
488 if(search_previous_rect(x
+tol
,y
+tol
,z
-tol
,ijk
,q
,ci
,cj
,ck
)) return true;
489 if(search_previous_rect(x
-tol
,y
+tol
,z
-tol
,ijk
,q
,ci
,cj
,ck
)) return true;
490 if(search_previous_rect(x
+tol
,y
-tol
,z
-tol
,ijk
,q
,ci
,cj
,ck
)) return true;
491 return search_previous_rect(x
-tol
,y
-tol
,z
-tol
,ijk
,q
,ci
,cj
,ck
);
494 bool voronoi_network::search_previous_rect(double x
,double y
,double z
,int &ijk
,int &q
,int &ci
,int &cj
,int &ck
) {
495 int k
=step_int(z
*zsp
);
498 z
-=ck
*bz
;y
-=ck
*byz
;x
-=ck
*bxz
;k
-=ck
*nz
;
501 int j
=step_int(y
*ysp
);
504 y
-=cj
*by
;x
-=cj
*bxy
;j
-=cj
*ny
;
513 ijk
+=nx
*(j
+ny
*k
);double *pp(pts
[ijk
]);
514 for(q
=0;q
<ptsc
[ijk
];q
++,pp
+=4)
515 if(abs(*pp
-x
)<net_tol
&&abs(pp
[1]-y
)<net_tol
&&abs(pp
[2]-z
)<net_tol
) return true;
519 /** Custom int function, that gives consistent stepping for negative numbers.
520 * With normal int, we have (-1.5,-0.5,0.5,1.5) -> (-1,0,0,1).
521 * With this routine, we have (-1.5,-0.5,0.5,1.5) -> (-2,-1,0,1). */
522 inline int voronoi_network::step_int(double a
) {
523 return a
<0?int(a
)-1:int(a
);
526 /** Custom integer division function, that gives consistent stepping for
527 * negative numbers. */
528 inline int voronoi_network::step_div(int a
,int b
) {
529 return a
>=0?a
/b
:-1+(a
+1)/b
;
532 // Explicit instantiation
533 template voronoi_network::voronoi_network(container_periodic
&, double);
534 template voronoi_network::voronoi_network(container_periodic_poly
&, double);
535 template void voronoi_network::add_to_network
<voronoicell
>(voronoicell
&, int, double, double, double, double);
536 template void voronoi_network::add_to_network
<voronoicell_neighbor
>(voronoicell_neighbor
&, int, double, double, double, double);
537 template void voronoi_network::add_to_network_rectangular
<voronoicell
>(voronoicell
&, int, double, double, double, double);
538 template void voronoi_network::add_to_network_rectangular
<voronoicell_neighbor
>(voronoicell_neighbor
&, int, double, double, double, double);