Virtual Testbed
Ship dynamics simulator for extreme conditions
bsp_tree.hh
Go to the documentation of this file.
1 #ifndef VTESTBED_GEOMETRY_BSP_TREE_HH
2 #define VTESTBED_GEOMETRY_BSP_TREE_HH
3 
4 #include <iosfwd>
5 #include <iterator>
6 #include <memory>
7 #include <queue>
8 #include <vector>
9 
10 #include <vtestbed/base/view.hh>
11 #include <vtestbed/geometry/plane.hh>
12 #include <vtestbed/geometry/polygon.hh>
13 #include <vtestbed/geometry/triangle.hh>
14 
30 namespace vtb {
31 
32  namespace geometry {
33 
39  template <class T>
41 
42  public:
43  using value_type = T;
45  using size_type = std::size_t;
46  using pointer = value_type*;
47  using const_pointer = const value_type*;
48  using reference = value_type&;
49  using const_reference = const value_type&;
51 
52  private:
53  std::queue<pointer> _queue;
54  pointer _ptr = nullptr;
55 
56  public:
57 
58  inline explicit
59  BSP_node_iterator(value_type& tree) {
60  if (!tree.empty()) { this->_queue.push(&tree); }
61  this->_ptr = this->current_node();
62  }
63 
64  BSP_node_iterator() = default;
65  BSP_node_iterator(const BSP_node_iterator&) = default;
67  BSP_node_iterator& operator=(const BSP_node_iterator&) = default;
68  BSP_node_iterator& operator=(BSP_node_iterator&&) = default;
69 
70  inline bool
71  operator==(const BSP_node_iterator& rhs) {
72  return this->_queue == rhs._queue;
73  }
74 
75  inline bool
76  operator!=(const BSP_node_iterator& rhs) {
77  return !this->operator==(rhs);
78  }
79 
80  inline pointer operator->() { return this->_ptr; }
81  inline const_pointer operator->() const { return this->_ptr; }
82  inline reference operator*() { return *this->_ptr; }
83  inline const_reference operator*() const { return *this->_ptr; }
84 
85  inline const_reference
86  operator++() {
87  auto& q = this->_queue;
88  auto& t = *q.front();
89  if (t.front()) { q.push(t.front().get()); }
90  if (t.back()) { q.push(t.back().get()); }
91  q.pop();
92  this->_ptr = q.empty() ? nullptr : this->current_node();
93  return *this->_ptr;
94  }
95 
96  inline BSP_node_iterator
97  operator++(int) {
98  BSP_node_iterator tmp(*this);
99  this->operator++();
100  return *tmp;
101  }
102 
103  private:
104 
105  inline const_pointer
106  current_node() const
107  { return this->_queue.front(); }
108 
109  inline pointer
110  current_node()
111  { return this->_queue.front(); }
112 
113  };
114 
115 
116  template <class T, int N>
117  struct BSP_traits;
118 
119  template <class T>
120  struct BSP_traits<T,3> {
121  using value_type = Triangle<T,3>;
122  };
123 
124  template <class T>
125  struct BSP_traits<T,2> {
127  };
128 
129  template <class T, int N>
130  class BSP_tree {
131 
132  public:
133  using scalar_type = T;
134  static constexpr const int dimensions = N;
136  using value_type = typename traits_type::value_type;
137  using plane_type = Plane<T,N>;
139  using reference = pointer&;
140  using const_reference = const pointer&;
146 
147  private:
148  using raw_pointer = BSP_tree<T,N>*;
149  using raw_const_pointer = const BSP_tree<T,N>*;
150  struct Polygon_and_plane {
151  plane_type plane;
152  value_type polygon;
153  inline
154  Polygon_and_plane(const plane_type& plane, const value_type& polygon):
155  plane(plane), polygon(polygon) {}
156  };
158 
159  private:
160  polygon_array _polygons;
161  plane_type _plane;
162  pointer _front;
163  pointer _back;
164  T _epsilon{1e-3};
165 
166  public:
167 
168  inline explicit
169  BSP_tree(const plane_type& plane, T eps):
170  _plane(plane), _epsilon(eps) {}
171 
172  inline explicit
173  BSP_tree(const plane_type& plane, T eps, polygon_array&& polygons):
174  _plane(plane), _epsilon(eps) {
175  this->insert(std::forward<polygon_array>(polygons));
176  }
177 
178  inline explicit
179  BSP_tree(polygon_array&& polygons, T eps): _epsilon(eps) {
180  this->insert(std::forward<polygon_array>(polygons));
181  }
182 
183  BSP_tree() = default;
184  BSP_tree(BSP_tree&&) = default;
185  BSP_tree& operator=(BSP_tree&&) = default;
186  inline BSP_tree(const BSP_tree& rhs) { this->deep_copy(rhs); }
187  inline BSP_tree& operator=(const BSP_tree& rhs)
188  { this->clear(); this->deep_copy(rhs); return *this; }
189  inline ~BSP_tree() { this->clear_nodes(); }
190 
191  void insert(polygon_array&& new_polygons);
192  void insert(BSP_tree&& rhs);
193  void clear();
194  void invert();
195  size_t subtract(const BSP_tree& rhs);
196  void sort();
197 
198  inline bool
199  has_plane() const {
200  return !all(plane().normal() == T{});
201  }
202 
203  inline const plane_type plane() const { return this->_plane; }
204  inline const_reference front() const { return this->_front; }
205  inline const_reference back() const { return this->_back; }
206 
207  inline const polygon_array&
208  polygons() const {
209  return this->_polygons;
210  }
211 
212  inline const value_type&
213  polygon(size_t i) const {
214  return this->_polygons[i];
215  }
216 
217  inline node_view
218  nodes() {
219  return node_view{node_iterator(*this), node_iterator()};
220  }
221 
222  inline node_const_view
223  nodes() const {
224  return node_const_view{
225  node_const_iterator(*this),
227  };
228  }
229 
230  bool empty() const;
231  inline scalar_type accuracy() const { return this->_epsilon; }
232  void accuracy(scalar_type rhs);
233  void dot(std::ostream& out) const;
234  void simplify();
235 
236  private:
237 
238  void insert(pair_array&& pairs);
239 
240  inline void
241  shallow_copy(const BSP_tree& rhs) {
242  this->_polygons = rhs._polygons;
243  this->_plane = rhs._plane;
244  }
245 
246  void
247  deep_copy(const BSP_tree& rhs);
248 
249  void
250  clear_nodes();
251 
252  // remove polygons that this tree contains
253  void
254  clip(polygon_array& polygons, const plane_type& plane) const;
255 
256  static inline raw_pointer
257  get_pointer(reference ptr) {
258  if (!ptr) { ptr.reset(new BSP_tree<T,N>); } return ptr.get();
259  }
260 
261  inline raw_pointer get_front()
262  { return get_pointer(this->_front); }
263  inline raw_pointer get_back()
264  { return get_pointer(this->_back); }
265 
266  static inline void
267  remove_empty(reference ptr) {
268  if (ptr && ptr->empty()) { ptr.reset(); }
269  }
270 
271  inline void
272  update_accuracy(T eps) {
273  if (eps < this->_epsilon) { this->_epsilon = eps; }
274  }
275 
276  };
277 
278  template <class T, int N>
279  inline BSP_tree<T,N>
280  set_union(const BSP_tree<T,N>& lhs, const BSP_tree<T,N>& rhs) {
281  BSP_tree<T,N> a(lhs), b(rhs);
282  a.subtract(rhs);
283  auto n = b.subtract(lhs);
284  if (n > 0) {
285  b.invert();
286  b.subtract(a);
287  b.invert();
288  a.insert(std::move(b));
289  }
290  a.sort();
291  return a;
292  }
293 
294  template <class T, int N>
295  inline BSP_tree<T,N>
296  set_difference(const BSP_tree<T,N>& lhs, const BSP_tree<T,N>& rhs) {
297  BSP_tree<T,N> a(lhs), b(rhs);
298  a.invert();
299  a.subtract(b);
300  b.subtract(a);
301  b.invert();
302  b.subtract(a);
303  b.invert();
304  a.insert(std::move(b));
305  a.invert();
306  a.sort();
307  return a;
308  }
309 
310  template <class T, int N>
311  inline BSP_tree<T,N>
312  set_intersection(const BSP_tree<T,N>& lhs, const BSP_tree<T,N>& rhs) {
313  BSP_tree<T,N> a(lhs), b(rhs);
314  a.invert();
315  b.subtract(a);
316  b.invert();
317  a.subtract(b);
318  b.subtract(a);
319  a.insert(std::move(b));
320  a.invert();
321  a.sort();
322  return a;
323  }
324 
325  }
326 
327 }
328 
329 #endif // vim:filetype=cpp
T set_intersection(T... args)
Main namespace.
Definition: convert.hh:9
Three- and two-dimensional plane.
Definition: plane.hh:28
Traverse BSP tree nodes using depth-first search.
Definition: bsp_tree.hh:40