GetFEM++  5.3
bgeot_rtree.cc
1 /*===========================================================================
2 
3  Copyright (C) 2000-2017 Julien Pommier
4 
5  This file is a part of GetFEM++
6 
7  GetFEM++ is free software; you can redistribute it and/or modify it
8  under the terms of the GNU Lesser General Public License as published
9  by the Free Software Foundation; either version 3 of the License, or
10  (at your option) any later version along with the GCC Runtime Library
11  Exception either version 3.1 or (at your option) any later version.
12  This program is distributed in the hope that it will be useful, but
13  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15  License and GCC Runtime Library Exception for more details.
16  You should have received a copy of the GNU Lesser General Public License
17  along with this program; if not, write to the Free Software Foundation,
18  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19 
20 ===========================================================================*/
21 
22 #include "getfem/bgeot_rtree.h"
23 
24 namespace bgeot {
25 
26  struct rtree_node : public rtree_elt_base {
27  std::unique_ptr<rtree_elt_base> left, right;
28  rtree_node(const base_node& bmin, const base_node& bmax,
29  std::unique_ptr<rtree_elt_base> &&left_,
30  std::unique_ptr<rtree_elt_base> &&right_)
31  : rtree_elt_base(false, bmin, bmax), left(std::move(left_)),
32  right( std::move(right_)) { }
33  };
34 
35  struct rtree_leaf : public rtree_elt_base {
36  rtree::pbox_cont lst;
37  rtree_leaf(const base_node& bmin, const base_node& bmax,
38  rtree::pbox_cont& lst_)
39  : rtree_elt_base(true, bmin, bmax) { lst.swap(lst_); }
40  };
41 
42  /* enlarge box to hold [a..b] */
43  static void update_box(base_node& bmin, base_node& bmax,
44  const base_node& a, const base_node& b) {
45  base_node::iterator itmin=bmin.begin(), itmax=bmax.begin();
46  for (size_type i=0; i < a.size(); ++i) {
47  itmin[i] = std::min(itmin[i], a.at(i));
48  itmax[i] = std::max(itmax[i], b.at(i));
49  }
50  }
51 
52  inline static bool r1_ge_r2(const base_node& min1, const base_node& max1,
53  const base_node& min2, const base_node& max2) {
54  for (size_type i=0; i < min1.size(); ++i)
55  if (!(min1[i] <= min2[i] && max1[i] >= max2[i])) return false;
56  return true;
57  }
58 
59  inline static bool r1_inter_r2(const base_node& min1, const base_node& max1,
60  const base_node& min2, const base_node& max2) {
61  for (size_type i=0; i < min1.size(); ++i)
62  if (max1[i] < min2[i] || min1[i] > max2[i]) return false;
63  return true;
64  }
65 
66  /* some predicates for searches */
67  struct intersection_p {
68  const base_node min,max;
69  intersection_p(const base_node& min_, const base_node& max_)
70  : min(min_), max(max_) {}
71  bool operator()(const base_node& min2, const base_node& max2)
72  { return r1_inter_r2(min,max,min2,max2); }
73  bool accept(const base_node& min2, const base_node& max2)
74  { return operator()(min2,max2); }
75  };
76 
77  /* match boxes containing [min..max] */
78  struct contains_p {
79  const base_node min,max;
80  contains_p(const base_node& min_, const base_node& max_)
81  : min(min_), max(max_) {}
82  bool operator()(const base_node& min2, const base_node& max2)
83  { return r1_ge_r2(min2,max2,min,max); }
84  bool accept(const base_node& min2, const base_node& max2)
85  { return r1_inter_r2(min,max,min2,max2); }
86  };
87 
88  /* match boxes contained in [min..max] */
89  struct contained_p {
90  const base_node min,max;
91  contained_p(const base_node& min_, const base_node& max_)
92  : min(min_), max(max_) {}
93  bool accept(const base_node& min2, const base_node& max2)
94  { return r1_inter_r2(min,max,min2,max2); }
95  bool operator()(const base_node& min2, const base_node& max2)
96  { return r1_ge_r2(min,max,min2,max2); }
97  };
98 
99  /* match boxes containing P */
100  struct has_point_p {
101  const base_node P;
102  has_point_p(const base_node& P_) : P(P_) {}
103  bool operator()(const base_node& min2, const base_node& max2) {
104  for (size_type i=0; i < P.size(); ++i)
105  if (P[i] < min2[i] || P[i] > max2[i]) return false;
106  return true;
107  }
108  bool accept(const base_node& min2, const base_node& max2)
109  { return operator()(min2,max2); }
110  };
111 
112  /* match boxes intersecting the line passing through org and of
113  direction vector dirv.*/
114  struct intersect_line {
115  const base_node org;
116  const base_small_vector dirv;
117  intersect_line(const base_node& org_, const base_small_vector &dirv_)
118  : org(org_), dirv(dirv_) {}
119  bool operator()(const base_node& min2, const base_node& max2) {
120  size_type N = org.size();
121  GMM_ASSERT1(N == min2.size(), "Dimensions mismatch");
122  for (size_type i = 0; i < N; ++i)
123  if (dirv[i] != scalar_type(0)) {
124  scalar_type a1=(min2[i]-org[i])/dirv[i], a2=(max2[i]-org[i])/dirv[i];
125  bool interf1 = true, interf2 = true;
126  for (size_type j = 0; j < N; ++j)
127  if (j != i) {
128  scalar_type y1 = org[j] + a1*dirv[j], y2 = org[j] + a2*dirv[j];
129  if (y1 < min2[j] || y1 > max2[j]) interf1 = false;
130  if (y2 < min2[j] || y2 > max2[j]) interf2 = false;
131  }
132  if (interf1 || interf2) return true;
133  }
134  return false;
135  }
136  bool accept(const base_node& min2, const base_node& max2)
137  { return operator()(min2,max2); }
138  };
139 
140  /* match boxes intersecting the line passing through org and of
141  direction vector dirv.*/
142  struct intersect_line_and_box {
143  const base_node org;
144  const base_small_vector dirv;
145  const base_node min,max;
146  intersect_line_and_box(const base_node& org_,
147  const base_small_vector &dirv_,
148  const base_node& min_, const base_node& max_)
149  : org(org_), dirv(dirv_), min(min_), max(max_) {}
150  bool operator()(const base_node& min2, const base_node& max2) {
151  size_type N = org.size();
152  GMM_ASSERT1(N == min2.size(), "Dimensions mismatch");
153  if (!(r1_inter_r2(min,max,min2,max2))) return false;
154  for (size_type i = 0; i < N; ++i)
155  if (dirv[i] != scalar_type(0)) {
156  scalar_type a1=(min2[i]-org[i])/dirv[i], a2=(max2[i]-org[i])/dirv[i];
157  bool interf1 = true, interf2 = true;
158  for (size_type j = 0; j < N; ++j)
159  if (j != i) {
160  scalar_type y1 = org[j] + a1*dirv[j], y2 = org[j] + a2*dirv[j];
161  if (y1 < min2[j] || y1 > max2[j]) interf1 = false;
162  if (y2 < min2[j] || y2 > max2[j]) interf2 = false;
163  }
164  if (interf1 || interf2) return true;
165  }
166  return false;
167  }
168  bool accept(const base_node& min2, const base_node& max2)
169  { return operator()(min2,max2); }
170  };
171 
172 
173  template <typename Predicate>
174  static void find_matching_boxes_(rtree_elt_base *n, rtree::pbox_set& boxlst,
175  Predicate p) {
176  if (n->isleaf()) {
177  const rtree_leaf *rl = static_cast<rtree_leaf*>(n);
178  for (rtree::pbox_cont::const_iterator it = rl->lst.begin();
179  it != rl->lst.end(); ++it) {
180  if (p((*it)->min, (*it)->max)) { boxlst.insert(*it); }
181  }
182  } else {
183  const rtree_node *rn = static_cast<rtree_node*>(n);
184  if (p.accept(rn->left->rmin,rn->left->rmax))
185  bgeot::find_matching_boxes_(rn->left.get(), boxlst, p);
186  if (p.accept(rn->right->rmin,rn->right->rmax))
187  bgeot::find_matching_boxes_(rn->right.get(), boxlst, p);
188  }
189  }
190 
191  void rtree::find_intersecting_boxes(const base_node& bmin,
192  const base_node& bmax,
193  pbox_set& boxlst) {
194  boxlst.clear(); if (!root) build_tree();
195  if (root) find_matching_boxes_(root.get(),boxlst,intersection_p(bmin,bmax));
196  }
197 
198  void rtree::find_containing_boxes(const base_node& bmin,
199  const base_node& bmax, pbox_set& boxlst) {
200  boxlst.clear(); if (!root) build_tree();
201  if (root) find_matching_boxes_(root.get(), boxlst, contains_p(bmin,bmax));
202  }
203 
204  void rtree::find_contained_boxes(const base_node& bmin,
205  const base_node& bmax, pbox_set& boxlst) {
206  boxlst.clear(); if (!root) build_tree();
207  if (root) find_matching_boxes_(root.get(), boxlst, contained_p(bmin,bmax));
208  }
209 
210  void rtree::find_boxes_at_point(const base_node& P, pbox_set& boxlst) {
211  boxlst.clear(); if (!root) build_tree();
212  if (root) find_matching_boxes_(root.get(), boxlst, has_point_p(P));
213  }
214 
215  void rtree::find_line_intersecting_boxes(const base_node& org,
216  const base_small_vector& dirv,
217  pbox_set& boxlst) {
218  boxlst.clear(); if (!root) build_tree();
219  if (root) find_matching_boxes_(root.get(),boxlst,intersect_line(org, dirv));
220  }
221 
222  void rtree::find_line_intersecting_boxes(const base_node& org,
223  const base_small_vector& dirv,
224  const base_node& bmin,
225  const base_node& bmax,
226  pbox_set& boxlst) {
227  boxlst.clear(); if (!root) build_tree();
228  if (root)
229  find_matching_boxes_(root.get(), boxlst,
230  intersect_line_and_box(org, dirv, bmin, bmax));
231  }
232 
233  /*
234  try to split at the approximate center of the box. Could be much more
235  sophisticated
236  */
237  static bool split_test(const rtree::pbox_cont& b,
238  const base_node& bmin, const base_node& bmax,
239  unsigned dir, scalar_type& split_v) {
240  scalar_type v = bmin[dir] + (bmax[dir] - bmin[dir])/2; split_v = v;
241  size_type cnt = 0;
242  for (rtree::pbox_cont::const_iterator it = b.begin(); it!=b.end(); ++it) {
243  if ((*it)->max[dir] < v) {
244  if (cnt == 0) split_v = (*it)->max[dir];
245  else split_v = std::max((*it)->max[dir],split_v);
246  cnt++;
247  }
248  }
249  return (cnt > 0 && cnt < b.size());
250  }
251 
252  /*
253  there are many flavors of rtree ... this one is more or less a quadtree
254  where splitting does not occurs at predefined positions (hence the
255  split_test function above).
256  Regions of the tree do not overlap (box are splitted).
257  */
258  static std::unique_ptr<rtree_elt_base> build_tree_(rtree::pbox_cont b,
259  const base_node& bmin,
260  const base_node& bmax,
261  unsigned last_dir) {
262  size_type N=bmin.size();
263  scalar_type split_v(0);
264  unsigned split_dir = unsigned((last_dir+1)%N);
265  bool split_ok = false;
266  if (b.size() > rtree_elt_base::RECTS_PER_LEAF) {
267  for (size_type itry=0; itry < N; ++itry) {
268  if (split_test(b, bmin, bmax, split_dir, split_v))
269  { split_ok = true; break; }
270  split_dir = unsigned((split_dir+1)%N);
271  }
272  }
273  if (split_ok) {
274  size_type cnt1=0,cnt2=0;
275  for (rtree::pbox_cont::const_iterator it = b.begin();
276  it != b.end(); ++it) {
277  if ((*it)->min[split_dir] < split_v) cnt1++;
278  if ((*it)->max[split_dir] > split_v) cnt2++;
279  }
280  assert(cnt1); assert(cnt2);
281  GMM_ASSERT1(cnt1+cnt2 >= b.size(), "internal error");
282  rtree::pbox_cont v1(cnt1), v2(cnt2);
283  base_node bmin1(bmax), bmax1(bmin);
284  base_node bmin2(bmax), bmax2(bmin);
285  cnt1 = cnt2 = 0;
286  for (rtree::pbox_cont::const_iterator it = b.begin();
287  it != b.end(); ++it) {
288  if ((*it)->min[split_dir] < split_v) {
289  v1[cnt1++] = *it;
290  update_box(bmin1,bmax1,(*it)->min,(*it)->max);
291  }
292  if ((*it)->max[split_dir] > split_v) {
293  v2[cnt2++] = *it;
294  update_box(bmin2,bmax2,(*it)->min,(*it)->max);
295  }
296  }
297  for (size_type k=0; k < N; ++k) {
298  bmin1[k] = std::max(bmin1[k],bmin[k]);
299  bmax1[k] = std::min(bmax1[k],bmax[k]);
300  bmin2[k] = std::max(bmin2[k],bmin[k]);
301  bmax2[k] = std::min(bmax2[k],bmax[k]);
302  }
303  bmax1[split_dir] = std::min(bmax1[split_dir], split_v);
304  bmin2[split_dir] = std::max(bmin2[split_dir], split_v);
305  assert(cnt1 == v1.size()); assert(cnt2 == v2.size());
306  return std::make_unique<rtree_node>
307  (bmin, bmax,
308  build_tree_(v1, bmin1, bmax1, split_dir),
309  build_tree_(v2, bmin2, bmax2, split_dir));
310  } else {
311  return std::make_unique<rtree_leaf>(bmin, bmax, b);
312  }
313  }
314 
315  void rtree::build_tree() {
316  if (boxes.size() == 0) return;
317  getfem::local_guard lock = locks_.get_lock();
318  assert(root == 0);
319  pbox_cont b(boxes.size());
320  pbox_cont::iterator b_it = b.begin();
321  base_node bmin(boxes.front().min), bmax(boxes.front().max);
322  for (box_cont::const_iterator it=boxes.begin(); it != boxes.end(); ++it) {
323  update_box(bmin,bmax,(*it).min,(*it).max);
324  *b_it++ = &(*it);
325  }
326  root = build_tree_(b, bmin, bmax, 0);
327  }
328 
329  static void dump_tree_(rtree_elt_base *p, int level, size_type& count) {
330  if (!p) return;
331  for (int i=0; i < level; ++i) cout << " ";
332  cout << "span=" << p->rmin << ".." << p->rmax << " ";
333  if (p->isleaf()) {
334  rtree_leaf *rl = static_cast<rtree_leaf*>(p);
335  cout << "Leaf [" << rl->lst.size() << " elts] = ";
336  for (size_type i=0; i < rl->lst.size(); ++i)
337  cout << " " << rl->lst[i]->id;
338  cout << "\n";
339  count += rl->lst.size();
340  } else {
341  cout << "Node\n";
342  const rtree_node *rn = static_cast<rtree_node*>(p);
343  if (rn->left) { dump_tree_(rn->left.get(), level+1, count); }
344  if (rn->right) { dump_tree_(rn->right.get(), level+1, count); }
345  }
346  }
347 
348  void rtree::dump() {
349  cout << "tree dump follows\n";
350  if (!root) build_tree();
351  size_type count = 0;
352  dump_tree_(root.get(), 0, count);
353  cout << " --- end of tree dump, nb of rectangles: " << boxes.size()
354  << ", rectangle ref in tree: " << count << "\n";
355  }
356 }
size_t size_type
used as the common size type in the library
Definition: bgeot_poly.h:49
Basic Geometric Tools.
region-tree for window/point search on a set of rectangles.