25 struct rtree_node :
public rtree_elt_base {
26 std::unique_ptr<rtree_elt_base> left, right;
27 rtree_node(
const base_node& bmin,
const base_node& bmax,
28 std::unique_ptr<rtree_elt_base> &&left_,
29 std::unique_ptr<rtree_elt_base> &&right_)
30 : rtree_elt_base(false, bmin, bmax), left(std::move(left_)),
31 right( std::move(right_)) { }
34 struct rtree_leaf :
public rtree_elt_base {
36 rtree_leaf(
const base_node& bmin,
const base_node& bmax,
37 rtree::pbox_cont& lst_)
38 : rtree_elt_base(true, bmin, bmax) { lst.swap(lst_); }
42 static void update_box(base_node& bmin, base_node& bmax,
43 const base_node& a,
const base_node& b) {
44 base_node::iterator itmin=bmin.begin(), itmax=bmax.begin();
46 itmin[i] = std::min(itmin[i], a.at(i));
47 itmax[i] = std::max(itmax[i], b.at(i));
51 inline static bool r1_ge_r2(
const base_node& min1,
const base_node& max1,
52 const base_node& min2,
const base_node& max2,
55 if ((min1[i] > min2[i]+EPS) || (max1[i] < max2[i]-EPS))
return false;
59 inline static bool r1_inter_r2(
const base_node& min1,
const base_node& max1,
60 const base_node& min2,
const base_node& max2,
63 if ((max1[i] < min2[i]-EPS) || (min1[i] > max2[i]+EPS))
return false;
68 struct intersection_p {
69 const base_node &min, &max;
70 const scalar_type EPS;
71 intersection_p(
const base_node& min_,
const base_node& max_, scalar_type EPS_)
72 : min(min_), max(max_), EPS(EPS_) {}
73 bool operator()(
const base_node& min2,
const base_node& max2)
const
74 {
return r1_inter_r2(min,max,min2,max2,EPS); }
75 bool accept(
const base_node& min2,
const base_node& max2)
const
76 {
return operator()(min2,max2); }
81 const base_node &min, &max;
82 const scalar_type EPS;
83 contains_p(
const base_node& min_,
const base_node& max_, scalar_type EPS_)
84 : min(min_), max(max_), EPS(EPS_) {}
85 bool operator()(
const base_node& min2,
const base_node& max2)
const
86 {
return r1_ge_r2(min2,max2,min,max,EPS); }
87 bool accept(
const base_node& min2,
const base_node& max2)
const
88 {
return r1_inter_r2(min,max,min2,max2,EPS); }
93 const base_node &min, &max;
94 const scalar_type EPS;
95 contained_p(
const base_node& min_,
const base_node& max_, scalar_type EPS_)
96 : min(min_), max(max_), EPS(EPS_) {}
97 bool accept(
const base_node& min2,
const base_node& max2)
const
98 {
return r1_inter_r2(min,max,min2,max2,EPS); }
99 bool operator()(
const base_node& min2,
const base_node& max2)
const
100 {
return r1_ge_r2(min,max,min2,max2,EPS); }
106 const scalar_type EPS;
107 has_point_p(
const base_node& P_, scalar_type EPS_) : P(P_), EPS(EPS_) {}
108 bool operator()(
const base_node& min2,
const base_node& max2)
const {
109 for (
size_type i = 0; i < P.size(); ++i) {
110 if (P[i] < min2[i]-EPS)
return false;
111 if (P[i] > max2[i]+EPS)
return false;
115 bool accept(
const base_node& min2,
const base_node& max2)
const
116 {
return operator()(min2,max2); }
121 struct intersect_line {
123 const base_small_vector dirv;
124 intersect_line(
const base_node& org_,
const base_small_vector &dirv_)
125 : org(org_), dirv(dirv_) {}
126 bool operator()(
const base_node& min2,
const base_node& max2)
const {
128 GMM_ASSERT1(N == min2.size(),
"Dimensions mismatch");
130 if (dirv[i] != scalar_type(0)) {
131 scalar_type a1=(min2[i]-org[i])/dirv[i], a2=(max2[i]-org[i])/dirv[i];
132 bool interf1 =
true, interf2 =
true;
135 scalar_type y1 = org[j] + a1*dirv[j], y2 = org[j] + a2*dirv[j];
136 if (y1 < min2[j] || y1 > max2[j]) interf1 =
false;
137 if (y2 < min2[j] || y2 > max2[j]) interf2 =
false;
139 if (interf1 || interf2)
return true;
143 bool accept(
const base_node& min2,
const base_node& max2)
const
144 {
return operator()(min2,max2); }
149 struct intersect_line_and_box {
151 const base_small_vector dirv;
152 const base_node min,max;
153 const scalar_type EPS;
154 intersect_line_and_box(
const base_node& org_,
155 const base_small_vector &dirv_,
156 const base_node& min_,
const base_node& max_,
158 : org(org_), dirv(dirv_), min(min_), max(max_), EPS(EPS_) {}
159 bool operator()(
const base_node& min2,
const base_node& max2)
const {
161 GMM_ASSERT1(N == min2.size(),
"Dimensions mismatch");
162 if (!(r1_inter_r2(min,max,min2,max2,EPS)))
return false;
164 if (dirv[i] != scalar_type(0)) {
165 scalar_type a1=(min2[i]-org[i])/dirv[i], a2=(max2[i]-org[i])/dirv[i];
166 bool interf1 =
true, interf2 =
true;
169 scalar_type y1 = org[j] + a1*dirv[j], y2 = org[j] + a2*dirv[j];
170 if (y1 < min2[j] || y1 > max2[j]) interf1 =
false;
171 if (y2 < min2[j] || y2 > max2[j]) interf2 =
false;
173 if (interf1 || interf2)
return true;
177 bool accept(
const base_node& min2,
const base_node& max2)
const
178 {
return operator()(min2,max2); }
181 size_type rtree::add_box(
const base_node &min,
const base_node &max,
185 GMM_WARNING3(
"Add a box when the tree is already built cancel the tree. "
186 "Unefficient operation.");
187 tree_built =
false; root = std::unique_ptr<rtree_elt_base>();
189 bi.min = &nodes[nodes.
add_node(min, EPS)];
190 bi.max = &nodes[nodes.
add_node(max, EPS)];
191 bi.id = (
id + 1) ?
id : boxes.size();
192 return boxes.emplace(std::move(bi)).first->id;
195 rtree::rtree(scalar_type EPS_)
196 : EPS(EPS_), boxes(box_index_topology_compare(EPS_)), tree_built(false)
199 void rtree::clear() {
200 root = std::unique_ptr<rtree_elt_base>();
206 template <
typename Predicate>
207 static void find_matching_boxes_(rtree_elt_base *n, rtree::pbox_set& boxlst,
208 const Predicate &p) {
210 const rtree_leaf *rl =
static_cast<rtree_leaf*
>(n);
211 for (rtree::pbox_cont::const_iterator it = rl->lst.begin();
212 it != rl->lst.end(); ++it) {
213 if (p(*(*it)->min, *(*it)->max)) { boxlst.insert(*it); }
216 const rtree_node *rn =
static_cast<rtree_node*
>(n);
217 if (p.accept(rn->left->rmin,rn->left->rmax))
218 bgeot::find_matching_boxes_(rn->left.get(), boxlst, p);
219 if (p.accept(rn->right->rmin,rn->right->rmax))
220 bgeot::find_matching_boxes_(rn->right.get(), boxlst, p);
224 void rtree::find_intersecting_boxes(
const base_node& bmin,
225 const base_node& bmax,
226 pbox_set& boxlst)
const {
229 GMM_ASSERT2(tree_built,
"Boxtree not initialised.");
231 find_matching_boxes_(root.get(),boxlst,intersection_p(bmin,bmax, EPS));
234 void rtree::find_containing_boxes(
const base_node& bmin,
235 const base_node& bmax,
236 pbox_set& boxlst)
const {
238 GMM_ASSERT2( tree_built,
"Boxtree not initialised.");
240 find_matching_boxes_(root.get(), boxlst, contains_p(bmin,bmax, EPS));
243 void rtree::find_contained_boxes(
const base_node& bmin,
244 const base_node& bmax,
245 pbox_set& boxlst)
const {
247 GMM_ASSERT2(tree_built,
"Boxtree not initialised.");
249 find_matching_boxes_(root.get(), boxlst, contained_p(bmin,bmax, EPS));
252 void rtree::find_boxes_at_point(
const base_node& P, pbox_set& boxlst)
const {
254 GMM_ASSERT2(tree_built,
"Boxtree not initialised.");
256 find_matching_boxes_(root.get(), boxlst, has_point_p(P, EPS));
259 void rtree::find_line_intersecting_boxes(
const base_node& org,
260 const base_small_vector& dirv,
261 pbox_set& boxlst)
const {
263 GMM_ASSERT2(tree_built,
"Boxtree not initialised.");
265 find_matching_boxes_(root.get(),boxlst,intersect_line(org, dirv));
268 void rtree::find_line_intersecting_boxes(
const base_node& org,
269 const base_small_vector& dirv,
270 const base_node& bmin,
271 const base_node& bmax,
272 pbox_set& boxlst)
const {
274 GMM_ASSERT2(tree_built,
"Boxtree not initialised.");
276 find_matching_boxes_(root.get(), boxlst,
277 intersect_line_and_box(org, dirv, bmin, bmax, EPS));
284 static bool split_test(
const rtree::pbox_cont& b,
285 const base_node& bmin,
const base_node& bmax,
286 unsigned dir, scalar_type& split_v) {
287 scalar_type v = bmin[dir] + (bmax[dir] - bmin[dir])/2; split_v = v;
289 for (rtree::pbox_cont::const_iterator it = b.begin(); it!=b.end(); ++it) {
290 if ((*it)->max->at(dir) < v) {
291 if (cnt == 0) split_v = (*it)->max->at(dir);
292 else split_v = std::max((*it)->max->at(dir),split_v);
296 return (cnt > 0 && cnt < b.size());
305 static std::unique_ptr<rtree_elt_base> build_tree_(rtree::pbox_cont b,
306 const base_node& bmin,
307 const base_node& bmax,
310 scalar_type split_v(0);
311 unsigned split_dir = unsigned((last_dir+1)%N);
312 bool split_ok =
false;
313 if (b.size() > rtree_elt_base::RECTS_PER_LEAF) {
314 for (
size_type itry=0; itry < N; ++itry) {
315 if (split_test(b, bmin, bmax, split_dir, split_v))
316 { split_ok =
true;
break; }
317 split_dir = unsigned((split_dir+1)%N);
322 for (rtree::pbox_cont::const_iterator it = b.begin();
323 it != b.end(); ++it) {
324 if ((*it)->min->at(split_dir) < split_v) cnt1++;
325 if ((*it)->max->at(split_dir) > split_v) cnt2++;
327 assert(cnt1); assert(cnt2);
328 GMM_ASSERT1(cnt1+cnt2 >= b.size(),
"internal error");
329 rtree::pbox_cont v1(cnt1), v2(cnt2);
330 base_node bmin1(bmax), bmax1(bmin);
331 base_node bmin2(bmax), bmax2(bmin);
333 for (rtree::pbox_cont::const_iterator it = b.begin();
334 it != b.end(); ++it) {
335 if ((*it)->min->at(split_dir) < split_v) {
337 update_box(bmin1,bmax1,*(*it)->min,*(*it)->max);
339 if ((*it)->max->at(split_dir) > split_v) {
341 update_box(bmin2,bmax2,*(*it)->min,*(*it)->max);
345 bmin1[k] = std::max(bmin1[k],bmin[k]);
346 bmax1[k] = std::min(bmax1[k],bmax[k]);
347 bmin2[k] = std::max(bmin2[k],bmin[k]);
348 bmax2[k] = std::min(bmax2[k],bmax[k]);
350 bmax1[split_dir] = std::min(bmax1[split_dir], split_v);
351 bmin2[split_dir] = std::max(bmin2[split_dir], split_v);
352 assert(cnt1 == v1.size()); assert(cnt2 == v2.size());
353 return std::make_unique<rtree_node>
355 build_tree_(v1, bmin1, bmax1, split_dir),
356 build_tree_(v2, bmin2, bmax2, split_dir));
358 return std::make_unique<rtree_leaf>(bmin, bmax, b);
362 void rtree::build_tree() {
364 if (boxes.size() == 0) { tree_built =
true;
return; }
365 getfem::local_guard lock = locks_.get_lock();
367 pbox_cont b(boxes.size());
368 pbox_cont::iterator b_it = b.begin();
369 base_node bmin(*boxes.begin()->min), bmax(*boxes.begin()->max);
370 for (box_cont::const_iterator it=boxes.begin(); it != boxes.end(); ++it) {
371 update_box(bmin,bmax,*(*it).min,*(*it).max);
374 root = build_tree_(b, bmin, bmax, 0);
379 static void dump_tree_(rtree_elt_base *p,
int level,
size_type& count) {
381 for (
int i=0; i < level; ++i) cout <<
" ";
382 cout <<
"span=" << p->rmin <<
".." << p->rmax <<
" ";
384 rtree_leaf *rl =
static_cast<rtree_leaf*
>(p);
385 cout <<
"Leaf [" << rl->lst.size() <<
" elts] = ";
386 for (
size_type i=0; i < rl->lst.size(); ++i)
387 cout <<
" " << rl->lst[i]->id;
389 count += rl->lst.size();
392 const rtree_node *rn =
static_cast<rtree_node*
>(p);
393 if (rn->left) { dump_tree_(rn->left.get(), level+1, count); }
394 if (rn->right) { dump_tree_(rn->right.get(), level+1, count); }
399 cout <<
"tree dump follows\n";
400 if (!root) build_tree();
402 dump_tree_(root.get(), 0, count);
403 cout <<
" --- end of tree dump, nb of rectangles: " << boxes.size()
404 <<
", rectangle ref in tree: " << count <<
"\n";
region-tree for window/point search on a set of rectangles.
size_type add_node(const base_node &pt, const scalar_type radius=0, bool remove_duplicated_nodes=true)
Add a point to the array or use an existing point, located within a distance smaller than radius.
size_t size_type
used as the common size type in the library