LBIBCell
 All Classes Functions Variables Friends Pages
FastNeighborList.hpp
1 /* Copyright (c) 2013 Simon Tanaka <tanakas"at"gmx"dot"ch>
2  * 2014 Simon Tanaka <tanakas"at"gmx"dot"ch>
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20  * THE SOFTWARE.
21  *
22  */
23 #ifndef FASTNEIGHBORLIST_HPP
24 #define FASTNEIGHBORLIST_HPP
25 
26 #include <vector>
27 #include <map>
28 #include <cmath>
29 #include <algorithm>
30 #include <cassert>
31 
32 namespace UtilLib {
33 namespace geometry {
34 
35 namespace {
40 struct listindex {
44  unsigned int x;
45 
49  unsigned int y;
50 };
51 
60 inline double distance( const double x1,
61  const double y1,
62  const double x2,
63  const double y2) {
64  return std::sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
65 }
66 }
67 
68 //##########################################################################
69 // declaration:
70 //##########################################################################
75 template <typename T>
77 public:
85  fastneighborlist(const double LX,
86  const double LY,
87  const unsigned int NX,
88  const unsigned int NY);
89 
94  void addElement(T element);
95 
101  bool removeElement(T element);
102 
107  void reset(std::map<unsigned int,T> elementmap);
108 
116  void getGeometryNodesWithinRadius( std::vector<T>& queryresult,
117  const double posx,
118  const double posy,
119  const double radius) const;
120 
129  void getGeometryNodesWithinRadiusWithAvoidance( std::vector<T>& queryresult,
130  const double posx,
131  const double posy,
132  const double radius,
133  const unsigned int avoidDomainID) const;
143  void getGeometryNodesWithinRadiusWithAvoidanceClosest( std::vector<T>& queryresult,
144  const double posx,
145  const double posy,
146  const double radius,
147  const unsigned int avoidDomainID) const;
148 
152  void displayContent() const;
153 
154 private:
161  unsigned int removeElementAtIndex(T element, listindex index);
162 
168  unsigned int removeElementBruteForce(T element);
169 
176  void appendContentOfCell(std::vector<T> &vec,
177  unsigned int j,
178  unsigned int i) const;
179 
187  void appendContentOfNeighboringCells(std::vector<T>& queryresult,
188  const double posx,
189  const double posy,
190  const double radius) const;
191 
198  inline listindex getIndex(double posx,
199  double posy) const;
200 
204  void clearList(void);
205 
209  const double BinSizeX_;
210 
214  const double BinSizeY_;
215 
219  std::vector< std::vector< std::vector< T > > > list_;
220 };
221 
222 
223 //##########################################################################
224 // implementation:
225 //##########################################################################
226 template<typename T>
228  const double LY,
229  const unsigned int NX,
230  const unsigned int NY) : BinSizeX_(double(LX)/double(NX)),
231  BinSizeY_(double(LY)/double(NY))
232 {
233  assert(LX > 0.0);
234  assert(LY > 0.0);
235  assert(NX > 0);
236  assert(NY > 0);
237 
238  this->list_.resize(NY);
239  for (auto &it : this->list_) {
240  it.resize(NX);
241  }
242 }
243 
244 template<typename T>
246 {
247  listindex ind = this->getIndex(element->getXPos(), element->getYPos());
248  assert(ind.y < this->list_.size());
249  assert(ind.x < this->list_[0].size());
250  this->list_[ind.y][ind.x].push_back(element);
251 }
252 
253 template<typename T>
255 {
256 
257  unsigned int count(0);
258  listindex ind = this->getIndex(element->getXPos(),element->getYPos());
259  listindex tempind;
260 
261  // step 1: first try the bin according to the position of element:
262  count = this->removeElementAtIndex(element,ind);
263  assert( (count==0) || (count==1) );
264  if (count==1) {return true;}
265 
266  // step 2a: check neighboring bin to the left:
267  if (ind.x > 0) {
268  tempind.x = ind.x - 1;
269  tempind.y = ind.y;
270  count = this->removeElementAtIndex(element,tempind);
271  }
272  assert( (count==0) || (count==1) );
273  if (count==1) {return true;}
274 
275  // step 2b: check neighboring bin to the right:
276  if (ind.x < this->list_[0].size()-1) {
277  tempind.x = ind.x + 1;
278  tempind.y = ind.y;
279  count = this->removeElementAtIndex(element,tempind);
280  }
281  assert( (count==0) || (count==1) );
282  if (count==1) {return true;}
283 
284  // step 2c: check neighboring bin to the bottom:
285  if (ind.y > 0) {
286  tempind.x = ind.x;
287  tempind.y = ind.y - 1;
288  count = this->removeElementAtIndex(element,tempind);
289  }
290  assert( (count==0) || (count==1) );
291  if (count==1) {return true;}
292 
293  // step 2d: check neighboring bin to the top:
294  if (ind.y < this->list_.size() - 1) {
295  tempind.x = ind.x;
296  tempind.y = ind.y + 1;
297  count = this->removeElementAtIndex(element,tempind);
298  }
299  assert( (count==0) || (count==1) );
300  if (count==1) {return true;}
301 
302  // step 2e: check neighboring bin to the bottom left:
303  if (ind.x > 0) {
304  tempind.x = ind.x - 1;
305  if (ind.y > 0) {
306  tempind.y = ind.y - 1;
307  count = this->removeElementAtIndex(element,tempind);
308  }
309  }
310  assert( (count==0) || (count==1) );
311  if (count==1) {return true;}
312 
313  // step 2f: check neighboring bin to the bottom right:
314  if (ind.x < this->list_[0].size() - 1) {
315  tempind.x = ind.x + 1;
316  if (ind.y > 0) {
317  tempind.y = ind.y - 1;
318  count = this->removeElementAtIndex(element,tempind);
319  }
320  }
321  assert( (count==0) || (count==1) );
322  if (count==1) {return true;}
323 
324  // step 2g: check neighboring bin to the top left:
325  if (ind.x > 0) {
326  tempind.x = ind.x - 1;
327  if (ind.y < this->list_.size() - 1) {
328  tempind.y = ind.y + 1;
329  count = this->removeElementAtIndex(element,tempind);
330  }
331  }
332  assert( (count==0) || (count==1) );
333  if (count==1) {return true;}
334 
335  // step 2h: check neighboring bin to the top right:
336  if (ind.x < this->list_[0].size() - 1) {
337  tempind.x = ind.x + 1;
338  if (ind.y < this->list_.size() - 1) {
339  tempind.y = ind.y + 1;
340  count = this->removeElementAtIndex(element,tempind);
341  }
342  }
343  assert( (count==0) || (count==1) );
344  if (count==1) {return true;}
345 
346  // step 3: if still not found, screen brute force for the element:
347  unsigned int num = this->removeElementBruteForce(element);
348  assert( (num==0) || (num==1) );
349  return (bool) num;
350 }
351 
352 template<typename T>
353 unsigned int fastneighborlist<T>::removeElementAtIndex(T element, listindex index) {
354  unsigned int count(0);
355 
356  // erase-remove idiom using lambda:
357  this->list_[index.y][index.x].erase( std::remove_if( this->list_[index.y][index.x].begin(),
358  this->list_[index.y][index.x].end(),
359  [element,&count](T node){
360  if (node == element) {
361  count++;
362  return true;
363  }
364  return false;
365  }),
366  this->list_[index.y][index.x].end()
367  );
368  return count;
369 }
370 
371 template<typename T>
372 unsigned int fastneighborlist<T>::removeElementBruteForce(T element)
373 {
374  unsigned int count(0);
375  listindex ind;
376  const size_t sizeX = this->list_[0].size();
377 
378  for (size_t iy = 0;
379  iy < this->list_.size();
380  ++iy) {
381  ind.y = iy;
382  for (size_t ix = 0;
383  ix < sizeX;
384  ++ix) {
385  ind.x = ix;
386  count = this->removeElementAtIndex(element,ind);
387  }
388  }
389  assert( (count==0) || (count==1) );
390  return count;
391 }
392 
393 template<typename T>
394 void fastneighborlist<T>::reset(std::map<unsigned int, T> elementmap)
395 {
396  this->clearList();
397 
398  for (auto& it : elementmap) {
399  this->addElement(it.second);
400  }
401 }
402 
403 template<typename T>
404 void fastneighborlist<T>::getGeometryNodesWithinRadius( std::vector<T>& queryresult,
405  const double posx,
406  const double posy,
407  const double radius) const
408 {
409  queryresult.clear();
410  this->appendContentOfNeighboringCells(queryresult, posx, posy, radius);
411 
412  // erase-remove idiom using lambda:
413  queryresult.erase( std::remove_if( queryresult.begin(),
414  queryresult.end(),
415  [posx,posy,radius](T node){
416  if (distance(posx,posy,node->getXPos(),node->getYPos()) > radius) {
417  return true;
418  }
419  return false;
420  }),
421  queryresult.end()
422  );
423 }
424 
425 template<typename T>
427  const double posx,
428  const double posy,
429  const double radius,
430  const unsigned int avoidDomainID) const
431 {
432  this->getGeometryNodesWithinRadius(queryresult, posx, posy, radius);
433 
434  // erase-remove idiom using lambda expression:
435  queryresult.erase( std::remove_if( queryresult.begin(),
436  queryresult.end(),
437  [avoidDomainID](T node) {
438  if (node->getDomainIdOfAdjacentConnections() == avoidDomainID) {
439  return true;
440  }
441  return false;
442  }),
443  queryresult.end()
444  );
445 }
446 template<typename T>
448  const double posx,
449  const double posy,
450  const double radius,
451  const unsigned int avoidDomainID) const
452 {
453  this->getGeometryNodesWithinRadiusWithAvoidance(queryresult, posx, posy, radius, avoidDomainID);
454 
455  // find the minimum distance *GeometryNode* using lambda expression:
456  if (queryresult.size() > 1) {
457  auto min_it = std::min_element( queryresult.begin(),
458  queryresult.end(),
459  [posx,posy] (T node1, T node2) {
460  return distance(posx,posy,node1->getXPos(),node1->getYPos()) < distance(posx,posy,node2->getXPos(),node2->getYPos());
461  }
462  );
463 
464  queryresult.clear();
465  queryresult.push_back(*min_it);
466  }
467 }
468 
469 template<typename T>
471 {
472  for (auto ity=0; ity<this->list_.size(); ++ity) {
473  for (auto itx=0; itx<this->list_[0].size(); ++itx) {
474  std::cout << "[x=" << itx << ", y=" << ity << "]" << "\t";
475 
476  for (auto it : this->list_[ity][itx]) {
477  std::cout << "(" << it->getXPos() << "," << it->getYPos() << ")" << "\t";
478  }
479  std::cout<<"\n";
480  }
481  }
482  std::cout<<"\n";
483 }
484 
485 template<typename T>
486 void fastneighborlist<T>::appendContentOfCell(std::vector<T> &vec,
487  unsigned int j,
488  unsigned int i) const {
489  vec.insert(vec.end(), this->list_[j][i].begin(), this->list_[j][i].end());
490 }
491 
492 template<typename T>
493 void fastneighborlist<T>::appendContentOfNeighboringCells(std::vector<T>& queryresult,
494  const double posx,
495  const double posy,
496  const double radius) const {
497  // bounding box:
498  listindex minind = this->getIndex(posx-radius,posy-radius);
499  listindex maxind = this->getIndex(posx+radius,posy+radius);
500 
501  for (unsigned int j=minind.y; j<maxind.y+1; ++j) {
502  for (unsigned int i=minind.x; i<maxind.x+1; ++i) {
503  this->appendContentOfCell(queryresult,j,i);
504  }
505  }
506 }
507 
508 template<typename T>
509 listindex fastneighborlist<T>::getIndex(double posx,
510  double posy) const
511 {
512  listindex ind;
513  if (posx < 0.0) posx = 0.0;
514  if (posy < 0.0) posy = 0.0;
515  ind.x = std::floor(posx/this->BinSizeX_);
516  ind.y = std::floor(posy/this->BinSizeY_);
517  if (ind.x >= this->list_[0].size()) ind.x = this->list_[0].size()-1;
518  if (ind.y >= this->list_.size()) ind.y = this->list_.size()-1;
519  return ind;
520 }
521 
522 template<typename T>
523 void fastneighborlist<T>::clearList()
524 {
525  for (auto& ity : this->list_) {
526  for (auto& itx : ity) {
527  itx.clear();
528  }
529  }
530 }
531 
532 
533 }
534 }
535 
536 
537 
538 #endif // FASTNEIGHBORLIST_HPP
void addElement(T element)
addElement Adds an element into the fastneighborlist data structure.
fastneighborlist(const double LX, const double LY, const unsigned int NX, const unsigned int NY)
fastneighborlist Constructor
The fastneighborlist class is a class template putting objects of type T into a celllist data structu...
void getGeometryNodesWithinRadius(std::vector< T > &queryresult, const double posx, const double posy, const double radius) const
range query, returns all elements wich are within the radius.
void getGeometryNodesWithinRadiusWithAvoidanceClosest(std::vector< T > &queryresult, const double posx, const double posy, const double radius, const unsigned int avoidDomainID) const
return closest GeometryNode, but only nodes with domainID different from avoidDomainID ...
bool removeElement(T element)
removeElement Removes an element from the fastneighborlist data structure.
void reset(std::map< unsigned int, T > elementmap)
Completely rebuilds the fastneighborlist. T must expose getXPos(), getYPos()
void getGeometryNodesWithinRadiusWithAvoidance(std::vector< T > &queryresult, const double posx, const double posy, const double radius, const unsigned int avoidDomainID) const
range query, but only nodes with domainID different from avoidDomainID
void displayContent() const
displayContent Displays all the content in form [xindex,yindex]: (posx,posy) ...