SPH
Octree.h
Go to the documentation of this file.
1 #pragma once
2 
7 
10 #include "objects/geometry/Box.h"
11 #include "system/Profiler.h"
12 
14 
16 
17 /*struct OctreeNode {
18  StaticArray<AutoPtr<OctreeNode>, 8> children;
19  Box voxel;
20  Array<Size> points;
21  bool isLeaf = false;
22 
23  void setPoints(Array<Size>&& pts) {
24  points = std::move(pts);
25  isLeaf = true;
26  }
27 
28  void setPoints(const IndexSequence& sequence) {
29  points.reserve(sequence.size());
30  for (Size i : sequence) {
31  points.push(i);
32  }
33  isLeaf = true;
34  }
35 };
36 
37 class Octree : public FinderTemplate<Octree> {
38 private:
39  Box box;
40  AutoPtr<OctreeNode> root;
41 
42 protected:
43  virtual void buildImpl(ArrayView<const Vector> points) override {
44  PROFILE_SCOPE("Octree::buildImpl");
45  box = Box();
46  for (const Vector& p : points) {
47  box.extend(p);
48  }
49  root = makeNode(box, points, IndexSequence(0, points.size()));
50  }
51 
52  virtual void rebuildImpl(ArrayView<const Vector> points) override {
53  buildImpl(points);
54  }
55 
56 public:
57  Octree() = default;
58 
59  virtual Size findNeighbours(const Size index,
60  const Float radius,
61  Array<NeighbourRecord>& neighbours) const override {
62  PROFILE_SCOPE("Octree::findNeighbours");
63  SPH_ASSERT(neighbours.empty())
64  SPH_ASSERT(root);
65  findNeighboursInNode(*root, index, radius, neighbours);
66  return neighbours.size();
67  }
68 
69  virtual Size findNeighbours(const Vector& UNUSED(position),
70  const Float radius,
71  Array<NeighbourRecord>& neighbours) const override {
72  PROFILE_SCOPE("Octree::findNeighbours");
73  neighbours.clear();
74  SPH_ASSERT(root);
75  findNeighboursInNode(*root, 0, radius, neighbours);
76  NOT_IMPLEMENTED;
77  return neighbours.size();
78  }
79 
80  template <typename TFunctor>
81  void enumerateChildren(TFunctor&& functor) const {
82  enumerateChildrenNode(*root, std::forward<TFunctor>(functor));
83  }
84 
85 private:
86  template <typename TFunctor>
87  void enumerateChildrenNode(OctreeNode& node, TFunctor&& functor) const {
88  functor(node);
89  if (!node.isLeaf) {
90  for (auto& child : node.children) {
91  enumerateChildrenNode(*child, functor);
92  }
93  }
94  }
95 
96  void findNeighboursInNode(OctreeNode& node,
97  const Size index,
98  const Float radius,
99  Array<NeighbourRecord>& neighbours) const {
100  const Float radiusSqr = sqr(radius);
101  if (node.isLeaf) {
102  for (Size i : node.points) {
103  const Float distSqr = getSqrLength(values[i] - values[index]);
104  if (distSqr < radiusSqr && (this->findAll() || rankH[i] < rankH[index])) {
105  neighbours.push(NeighbourRecord{ i, distSqr });
106  }
107  }
108  } else {
109  const Vector& p = values[index];
110  const Size code = this->getCode(p, node.voxel);
111  Box voxel = node.children[code]->voxel;
112  if (getSqrLength(voxel.lower() - p) < radiusSqr && getSqrLength(voxel.upper() - p) < radiusSqr) {
113  // all points of the voxel are already the sphere, skip the checks and just add all points
114  this->enumerateChildrenNode(node, [this, &p, refRank, &neighbours](OctreeNode& n) INL {
115  if (!n.isLeaf) {
116  return;
117  }
118  for (Size i : n.points) {
119  const Float distSqr = getSqrLength(values[i] - p);
120  if (rankH[i] < refRank) {
121  neighbours.push(NeighbourRecord{ i, distSqr });
122  }
123  }
124  });
125  return;
126  }*/
127 /*Vector& l = voxel.lower();
128  Vector& u = voxel.upper();
129  const Vector r(radius);
130  l += r;
131  u -= r;
132  if (voxel.contains(p)) {
133  // sphere is entirely in this octant, no need to check the other octants
134  this->findNeighboursInNode(*node.children[code], index, radius, neighbours, refRank);
135  } else*/ /*{
136  for (Size i = 0; i < node.children.size(); ++i) {
137  OctreeNode& child = *node.children[i];
138  const bool intersect = (i == code) ? true : sphereIntersectsBox(p, radius, child.voxel);
139  if (intersect) {
140  SPH_ASSERT(node.children[i]);
141  this->findNeighboursInNode(child, index, radius, neighbours);
142  }
143  }
144  }
145  }
146  }
147 
148  template <typename TIdxs>
149  AutoPtr<OctreeNode> makeNode(const Box& voxel, ArrayView<const Vector> points, TIdxs&& idxs) {
150  AutoPtr<OctreeNode> node = makeAuto<OctreeNode>();
151  node->voxel = voxel;
152  if (idxs.size() <= MAX_CHILDREN_PER_LEAF) {
153  node->setPoints(std::forward<TIdxs>(idxs));
154  SPH_ASSERT(node->isLeaf);
155  } else {
156  StaticArray<Array<Size>, 8> octants;
157  for (Size i : idxs) {
158  SPH_ASSERT(voxel.contains(points[i]));
159  const Size idx = getCode(points[i], voxel);
160  octants[idx].push(i);
161  }
162  this->reset(std::forward<TIdxs>(idxs)); // dealloc
163  for (Size j = 0; j < node->children.size(); ++j) {
164  node->children[j] = makeNode(this->getVoxel(j, voxel), points, std::move(octants[j]));
165  }
166  SPH_ASSERT(!node->isLeaf);
167  }
168  return node;
169  }
170 
171  INLINE void reset(Array<Size>&& points) {
172  Array<Size>().swap(points);
173  }
174 
175  INLINE void reset(const IndexSequence&) {
176  // do nothing
177  }
178 
179  INLINE bool sphereIntersectsBox(const Vector& p, const Float radius, const Box& voxel) const {
180  Float dmin = 0._f;
181  for (Size i = 0; i < 3; ++i) {
182  if (p[i] < voxel.lower()[i]) {
183  dmin += sqr(p[i] - voxel.lower()[i]);
184  } else if (p[i] > voxel.upper()[i]) {
185  dmin += sqr(p[i] - voxel.upper()[i]);
186  }
187  }
188  return dmin <= sqr(radius);
189  }
190 
191  Box getVoxel(const Size code, const Box& voxel) const {
192  Box b = voxel;
193  const Vector size = 0.5_f * voxel.size();
194  if (code & 0x01) {
195  b.lower()[X] += size[X];
196  } else {
197  b.upper()[X] -= size[X];
198  }
199  if (code & 0x02) {
200  b.lower()[Y] += size[Y];
201  } else {
202  b.upper()[Y] -= size[Y];
203  }
204  if (code & 0x04) {
205  b.lower()[Z] += size[Z];
206  } else {
207  b.upper()[Z] -= size[Z];
208  }
209  return b;
210  }
211 
212  INLINE Size getCode(const Vector& p, const Box& voxel) const {
213  const Vector& center = voxel.center();
214  Size code = 0;
215  if (p[X] > center[X]) {
216  code |= 0x01;
217  }
218  if (p[Y] > center[Y]) {
219  code |= 0x02;
220  }
221  if (p[Z] > center[Z]) {
222  code |= 0x04;
223  }
224  SPH_ASSERT(code < 8);
225  return code;
226  }
227 };*/
228 
Generic dynamically allocated resizable storage.
NAMESPACE_SPH_BEGIN
Definition: BarnesHut.cpp:13
Object representing a three-dimensional axis-aligned box.
uint32_t Size
Integral type used to index arrays (by default).
Definition: Globals.h:16
#define NAMESPACE_SPH_END
Definition: Object.h:12
constexpr NAMESPACE_SPH_BEGIN Size MAX_CHILDREN_PER_LEAF
Definition: Octree.h:15
Tool to measure time spent in functions and profile the code.