cgv
Loading...
Searching...
No Matches
quadtree.h
1#pragma once
2
3#include <vector>
4#include <cassert>
5#include <cgv/math/fvec.h>
6#include <cgv/media/axis_aligned_box.h>
7
8namespace cgv {
9 namespace data {
10 template <typename T>
12 {
13 public:
17 {
18 virtual const vec2_type& get_point(int i) const = 0;
19 };
20 protected:
21 struct node
22 {
23 bool is_leaf;
24 int children[4];
25 node() : is_leaf(true) { children[0] = children[1] = children[2] = children[3] = -1; }
27 unsigned size() const { unsigned s = 0; while (s < 4 && children[s] != -1) ++s; return s; }
28 };
29 box2_type box;
30 const point_provider& provider;
31 int root_idx;
32 std::vector<node> nodes;
33
34 const node& get_node(int ni) const { return nodes[ni]; }
35 node& ref_node(int ni) { return nodes[ni]; }
36
37 bool is_leaf(int ni) const { return nodes[ni].is_leaf; }
38 void add_point_to_leaf(int pi, int ni) {
39 node& n = ref_node(ni);
40 assert(n.is_leaf && n.size() < 4);
41 n.children[n.size()] = pi;
42 }
43 bool split_leaf(int ni, const vec2_type& x) {
44 if (!is_leaf(ni))
45 return false;
46 int c0 = (int)nodes.size();
47 nodes.resize(nodes.size() + 4);
48 node& n = ref_node(ni);
49 for (unsigned j = 0; j < 4; ++j) {
50 int pi = n.children[j];
51 if (pi != -1) {
52 const vec2_type& p = provider.get_point(pi);
53 unsigned k = 0;
54 if (p(0) > x(0))
55 k += 1;
56 if (p(1) > x(1))
57 k += 2;
58 add_point_to_leaf(pi, c0 + k);
59 }
60 n.children[j] = c0 + j;
61 }
62 n.is_leaf = false;
63 return true;
64 }
65 public:
66 quadtree(const point_provider& _provider, const box2_type& _box) : provider(_provider), box(_box) { nodes.push_back(node()); root_idx = 0; }
67 bool empty() const { return is_leaf(get_root_index()) && get_node(get_root_index()).size() == 0; }
68 int get_root_index() const { return root_idx; }
69 bool collides(const vec2_type& x, T d, int ni = -1, box2_type b = box2_type()) const {
70 if (ni == -1) {
71 ni = get_root_index();
72 b = box;
73 }
74 // check for overlap
75 if (x(0) + d > b.get_min_pnt()(0) && x(0) - d < b.get_max_pnt()(0) &&
76 x(1) + d > b.get_min_pnt()(1) && x(1) - d < b.get_max_pnt()(1)) {
77 // in leaf case compare to points
78 if (is_leaf(ni)) {
79 const node& n = get_node(ni);
80 for (unsigned j = 0; j < 4; ++j) {
81 if (n.children[j] == -1)
82 break;
83 if ((provider.get_point(n.children[j])-x).length() < d)
84 return true;
85 }
86 return false;
87 }
88 else {
89 vec2_type c = b.get_center();
90 const node& n = get_node(ni);
91 return
92 collides(x, d, n.children[0], box2_type(b.get_min_pnt(), c)) ||
93 collides(x, d, n.children[1], box2_type(vec2_type(c(0), b.get_min_pnt()(1)), vec2_type(b.get_max_pnt()(0), c(1)))) ||
94 collides(x, d, n.children[2], box2_type(vec2_type(b.get_min_pnt()(0), c(1)), vec2_type(c(0), b.get_max_pnt()(1)))) ||
95 collides(x, d, n.children[3], box2_type(c, b.get_max_pnt()));
96 }
97 }
98 else
99 return false;
100 }
101 void insert(const vec2_type& p, int pi) {
102 int ni = get_root_index();
103 box2_type b = box;
104 while (true) {
105 if (is_leaf(ni)) {
106 const node& n = get_node(ni);
107 if (n.size() < 4) {
108 add_point_to_leaf(pi, ni);
109 return;
110 }
111 split_leaf(ni, b.get_center());
112 }
113 vec2_type x = b.get_center();
114 int k = 0;
115 if (p(0) > x(0)) {
116 k += 1;
117 b.ref_min_pnt()(0) = x(0);
118 }
119 else
120 b.ref_max_pnt()(0) = x(0);
121
122 if (p(1) > x(1)) {
123 k += 2;
124 b.ref_min_pnt()(1) = x(1);
125 }
126 else
127 b.ref_max_pnt()(1) = x(1);
128
129 ni = get_node(ni).children[k];
130 }
131 }
132 };
133 }
134}
A vector with zero based index.
Definition fvec.h:27
An axis aligned box, defined by to points: min and max.
the cgv namespace
Definition print.h:11
unsigned size() const
in case of leaf, return the number of contained points
Definition quadtree.h:27