faunus
spheres_searcher.h
1 #ifndef VORONOTALT_SPHERES_SEARCHER_H_
2 #define VORONOTALT_SPHERES_SEARCHER_H_
3 
4 #include <vector>
5 #include <algorithm>
6 
7 #include "basic_types_and_functions.h"
8 
9 namespace voronotalt
10 {
11 
13 {
14 public:
15  SpheresSearcher() noexcept
16  {
17  }
18 
19  explicit SpheresSearcher(const std::vector<SimpleSphere>& spheres) noexcept
20  {
21  init(spheres);
22  }
23 
24  void init(const std::vector<SimpleSphere>& spheres) noexcept
25  {
26  spheres_=spheres;
27  grid_parameters_=GridParameters(spheres_);
28  init_boxes();
29  }
30 
31  bool update(const std::vector<SimpleSphere>& spheres, const std::vector<UnsignedInt>& ids_to_update) noexcept
32  {
33  if(ids_to_update.empty())
34  {
35  return false;
36  }
37 
38  if(ids_to_update.size()>size_threshold_for_full_rebuild())
39  {
40  init(spheres);
41  return true;
42  }
43 
44  for(UnsignedInt i=0;i<ids_to_update.size();i++)
45  {
46  if(ids_to_update[i]>=spheres.size() || !update_sphere(ids_to_update[i], spheres[ids_to_update[i]]))
47  {
48  init(spheres);
49  return true;
50  }
51  }
52 
53  return true;
54  }
55 
56  void assign(const SpheresSearcher& obj) noexcept
57  {
58  grid_parameters_=obj.grid_parameters_;
59 
60  spheres_.resize(obj.spheres_.size());
61  map_of_boxes_.resize(obj.map_of_boxes_.size());
62  boxes_.resize(obj.boxes_.size());
63 
64  {
65 #ifdef VORONOTALT_OPENMP
66 #pragma omp parallel for
67 #endif
68  for(UnsignedInt i=0;i<obj.spheres_.size();i++)
69  {
70  spheres_[i]=obj.spheres_[i];
71  }
72  }
73 
74  {
75 #ifdef VORONOTALT_OPENMP
76 #pragma omp parallel for
77 #endif
78  for(UnsignedInt i=0;i<obj.map_of_boxes_.size();i++)
79  {
80  map_of_boxes_[i]=obj.map_of_boxes_[i];
81  }
82  }
83 
84  {
85 #ifdef VORONOTALT_OPENMP
86 #pragma omp parallel for
87 #endif
88  for(UnsignedInt i=0;i<obj.boxes_.size();i++)
89  {
90  boxes_[i]=obj.boxes_[i];
91  }
92  }
93  }
94 
95  const std::vector<SimpleSphere>& searchable_spheres() const noexcept
96  {
97  return spheres_;
98  }
99 
100  bool find_colliding_ids(const UnsignedInt& central_id, std::vector<ValuedID>& colliding_ids, const bool discard_hidden, int& exclusion_status) const noexcept
101  {
102  colliding_ids.clear();
103  exclusion_status=0;
104  if(central_id<spheres_.size())
105  {
106  const SimpleSphere& central_sphere=spheres_[central_id];
107  const GridPoint gp(central_sphere, grid_parameters_.box_size, grid_parameters_.grid_offset);
108  GridPoint dgp=gp;
109  for(int dx=-1;dx<=1;dx++)
110  {
111  dgp.x=gp.x+dx;
112  for(int dy=-1;dy<=1;dy++)
113  {
114  dgp.y=gp.y+dy;
115  for(int dz=-1;dz<=1;dz++)
116  {
117  dgp.z=gp.z+dz;
118  const int index=dgp.index(grid_parameters_.grid_size);
119  if(index>=0)
120  {
121  const int box_id=map_of_boxes_[index];
122  if(box_id>=0)
123  {
124  const std::vector<UnsignedInt>& ids=boxes_[box_id];
125  for(UnsignedInt i=0;i<ids.size();i++)
126  {
127  const UnsignedInt id=ids[i];
128  const SimpleSphere& candidate_sphere=spheres_[id];
129  if(id!=central_id && sphere_intersects_sphere(central_sphere, candidate_sphere))
130  {
131  if(discard_hidden
132  && sphere_contains_sphere(candidate_sphere, central_sphere)
133  && (!sphere_equals_sphere(candidate_sphere, central_sphere) || central_id>id))
134  {
135  colliding_ids.clear();
136  exclusion_status=1;
137  return false;
138  }
139  else if(!discard_hidden
140  || !sphere_contains_sphere(central_sphere, candidate_sphere))
141  {
142  colliding_ids.push_back(ValuedID(distance_to_center_of_intersection_circle_of_two_spheres(central_sphere, candidate_sphere), id));
143  }
144  }
145  }
146  }
147  }
148  }
149  }
150  }
151  }
152  if(!colliding_ids.empty())
153  {
154  std::sort(colliding_ids.begin(), colliding_ids.end());
155  }
156  return (!colliding_ids.empty());
157  }
158 
159 private:
160  struct GridPoint
161  {
162  int x;
163  int y;
164  int z;
165 
166  GridPoint() noexcept: x(0), y(0), z(0)
167  {
168  }
169 
170  GridPoint(const SimpleSphere& s, const Float grid_step) noexcept
171  {
172  init(s, grid_step);
173  }
174 
175  GridPoint(const SimpleSphere& s, const Float grid_step, const GridPoint& grid_offset) noexcept
176  {
177  init(s, grid_step, grid_offset);
178  }
179 
180  void init(const SimpleSphere& s, const Float grid_step) noexcept
181  {
182  x=static_cast<int>(s.p.x/grid_step);
183  y=static_cast<int>(s.p.y/grid_step);
184  z=static_cast<int>(s.p.z/grid_step);
185  }
186 
187  void init(const SimpleSphere& s, const Float grid_step, const GridPoint& grid_offset) noexcept
188  {
189  x=static_cast<int>(s.p.x/grid_step)-grid_offset.x;
190  y=static_cast<int>(s.p.y/grid_step)-grid_offset.y;
191  z=static_cast<int>(s.p.z/grid_step)-grid_offset.z;
192  }
193 
194  int index(const GridPoint& grid_size) const noexcept
195  {
196  return ((x>=0 && y>=0 && z>=0 && x<grid_size.x && y<grid_size.y && z<grid_size.z) ? (z*grid_size.x*grid_size.y+y*grid_size.x+x) : (-1));
197  }
198 
199  bool operator<(const GridPoint& gp) const noexcept
200  {
201  return (x<gp.x || (x==gp.x && y<gp.y) || (x==gp.x && y==gp.y && z<gp.z));
202  }
203 
204  bool operator==(const GridPoint& gp) const noexcept
205  {
206  return (x==gp.x && y==gp.y && z==gp.z);
207  }
208  };
209 
210  struct GridParameters
211  {
212  GridPoint grid_offset;
213  GridPoint grid_size;
214  Float box_size;
215  int padding_;
216 
217  GridParameters() noexcept : box_size(FLOATCONST(1.0)), padding_(1)
218  {
219  grid_size.x=1;
220  grid_size.y=1;
221  grid_size.z=1;
222  }
223 
224  explicit GridParameters(const std::vector<SimpleSphere>& spheres) noexcept : box_size(FLOATCONST(1.0)), padding_(1)
225  {
226  init(spheres);
227  }
228 
229  GridParameters(const std::vector<SimpleSphere>& spheres, const int padding) noexcept : box_size(FLOATCONST(1.0)), padding_(padding)
230  {
231  init(spheres);
232  }
233 
234  void init(const std::vector<SimpleSphere>& spheres) noexcept
235  {
236  box_size=FLOATCONST(1.0);
237  padding_=std::max(0, padding_);
238 
239  for(UnsignedInt i=0;i<spheres.size();i++)
240  {
241  const SimpleSphere& s=spheres[i];
242  box_size=std::max(box_size, s.r*FLOATCONST(2.0)+FLOATCONST(0.25));
243  }
244 
245  for(UnsignedInt i=0;i<spheres.size();i++)
246  {
247  const GridPoint gp(spheres[i], box_size);
248  if(i==0)
249  {
250  grid_offset=gp;
251  grid_size=gp;
252  }
253  else
254  {
255  grid_offset.x=std::min(grid_offset.x, gp.x-padding_);
256  grid_offset.y=std::min(grid_offset.y, gp.y-padding_);
257  grid_offset.z=std::min(grid_offset.z, gp.z-padding_);
258  grid_size.x=std::max(grid_size.x, gp.x+padding_);
259  grid_size.y=std::max(grid_size.y, gp.y+padding_);
260  grid_size.z=std::max(grid_size.z, gp.z+padding_);
261  }
262  }
263 
264  grid_size.x=grid_size.x-grid_offset.x+1;
265  grid_size.y=grid_size.y-grid_offset.y+1;
266  grid_size.z=grid_size.z-grid_offset.z+1;
267  }
268 
269  bool operator==(const GridParameters& gp) const noexcept
270  {
271  return (box_size==gp.box_size && grid_offset==gp.grid_offset && grid_size==gp.grid_size);
272  }
273  };
274 
275  UnsignedInt size_threshold_for_full_rebuild() const noexcept
276  {
277  return static_cast<UnsignedInt>(spheres_.size()/2);
278  }
279 
280  void init_boxes() noexcept
281  {
282  map_of_boxes_.clear();
283  boxes_.clear();
284 
285  map_of_boxes_.resize(grid_parameters_.grid_size.x*grid_parameters_.grid_size.y*grid_parameters_.grid_size.z, -1);
286 
287  for(UnsignedInt i=0;i<spheres_.size();i++)
288  {
289  const GridPoint gp(spheres_[i], grid_parameters_.box_size, grid_parameters_.grid_offset);
290  const int index=gp.index(grid_parameters_.grid_size);
291  const int box_id=map_of_boxes_[index];
292  if(box_id<0)
293  {
294  map_of_boxes_[index]=static_cast<int>(boxes_.size());
295  boxes_.push_back(std::vector<UnsignedInt>(1, i));
296  }
297  else
298  {
299  boxes_[box_id].push_back(i);
300  }
301  }
302  }
303 
304  bool update_sphere(const UnsignedInt& sphere_id, const SimpleSphere& moved_sphere) noexcept
305  {
306  if(sphere_id<spheres_.size() && moved_sphere.r<=spheres_[sphere_id].r)
307  {
308  const GridPoint gp1(moved_sphere, grid_parameters_.box_size, grid_parameters_.grid_offset);
309  const int index1=gp1.index(grid_parameters_.grid_size);
310  if(index1>=0)
311  {
312  const GridPoint gp0(spheres_[sphere_id], grid_parameters_.box_size, grid_parameters_.grid_offset);
313  const int index0=gp0.index(grid_parameters_.grid_size);
314  if(index0>=0)
315  {
316  if(index1!=index0)
317  {
318  {
319  const int box_id0=map_of_boxes_[index0];
320  if(box_id0<0)
321  {
322  return false;
323  }
324  else
325  {
326  std::vector<UnsignedInt>& v0=boxes_[box_id0];
327  std::vector<UnsignedInt>::iterator it=std::lower_bound(v0.begin(), v0.end(), sphere_id);
328  if(it!=v0.end() && (*it)==sphere_id)
329  {
330  v0.erase(it);
331  }
332  }
333  }
334 
335  {
336  const int box_id1=map_of_boxes_[index1];
337  if(box_id1<0)
338  {
339  map_of_boxes_[index1]=static_cast<int>(boxes_.size());
340  boxes_.push_back(std::vector<UnsignedInt>(1, sphere_id));
341  }
342  else
343  {
344  std::vector<UnsignedInt>& v1=boxes_[box_id1];
345  std::vector<UnsignedInt>::iterator it=std::lower_bound(v1.begin(), v1.end(), sphere_id);
346  if(it==v1.end() || (*it)!=sphere_id)
347  {
348  v1.insert(it, sphere_id);
349  }
350  }
351  }
352  }
353  spheres_[sphere_id]=moved_sphere;
354  return true;
355  }
356  }
357  }
358  return false;
359  }
360 
361  std::vector<SimpleSphere> spheres_;
362  GridParameters grid_parameters_;
363  std::vector<int> map_of_boxes_;
364  std::vector< std::vector<UnsignedInt> > boxes_;
365 };
366 
367 }
368 
369 #endif /* VORONOTALT_SPHERES_SEARCHER_H_ */
Definition: spheres_searcher.h:12
Definition: basic_types_and_functions.h:83
Definition: basic_types_and_functions.h:19
Definition: basic_types_and_functions.h:49