Skip to content

Commit 718326e

Browse files
authored
Adding KdTree and PointKdTreeSearcher (#115)
This revision includes: * Generic KdTree implementation * PointKdTreeSearcher based on KdTree * Performance improvements on Anisotropic kernel * Updating flatbuffers
1 parent 6b2363b commit 718326e

70 files changed

Lines changed: 3938 additions & 906 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ add_subdirectory(external/googletest EXCLUDE_FROM_ALL)
6262
if ((CMAKE_VERSION VERSION_EQUAL 3.3) OR (CMAKE_VERSION VERSION_GREATER 3.3))
6363
cmake_policy(SET CMP0063 NEW)
6464
endif()
65-
set(BENCHMARK_ENABLE_TESTING 0)
65+
set(BENCHMARK_ENABLE_TESTING OFF)
6666
add_subdirectory(external/googlebenchmark)
6767
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
6868
set(CMAKE_VISIBILITY_INLINES_HIDDEN 1)

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ The latest code is always available from the [`master`](https://github.com/doyub
1515
* PIC, FLIP, and APIC fluid simulators
1616
* Upwind, ENO, and FMM level set solvers
1717
* Jacobi, Gauss-Seidel, SOR, MG, CG, ICCG, and MGPCG linear system solvers
18+
* Spherical, SPH, Zhu & Bridson, and Anisotropic kernel for points-to-surface converter
1819
* Converters between signed distance function and triangular mesh
1920
* C++ and Python API
2021

include/jet/anisotropic_points_to_implicit2.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class AnisotropicPointsToImplicit2 final : public PointsToImplicit2 {
3636
//!
3737
AnisotropicPointsToImplicit2(double kernelRadius = 1.0,
3838
double cutOffDensity = 0.5,
39-
double positionSmoothingFactor = 0.0,
39+
double positionSmoothingFactor = 0.5,
4040
size_t minNumNeighbors = 8,
4141
bool isOutputSdf = true);
4242

include/jet/anisotropic_points_to_implicit3.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class AnisotropicPointsToImplicit3 final : public PointsToImplicit3 {
3636
//!
3737
AnisotropicPointsToImplicit3(double kernelRadius = 1.0,
3838
double cutOffDensity = 0.5,
39-
double positionSmoothingFactor = 0.0,
39+
double positionSmoothingFactor = 0.5,
4040
size_t minNumNeighbors = 25,
4141
bool isOutputSdf = true);
4242

include/jet/detail/bvh2-inl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ Bvh2<T>::Node::Node() : flags(0) {
2222

2323
template <typename T>
2424
void Bvh2<T>::Node::initLeaf(size_t it, const BoundingBox2D& b) {
25-
flags |= 2;
25+
flags = 2;
2626
item = it;
2727
bound = b;
2828
}

include/jet/detail/bvh3-inl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ Bvh3<T>::Node::Node() : flags(0) {
2222

2323
template <typename T>
2424
void Bvh3<T>::Node::initLeaf(size_t it, const BoundingBox3D& b) {
25-
flags |= 3;
25+
flags = 3;
2626
item = it;
2727
bound = b;
2828
}

include/jet/detail/kdtree-inl.h

Lines changed: 309 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,309 @@
1+
// Copyright (c) 2017 Doyub Kim
2+
//
3+
// I am making my contributions/submissions to this project solely in my
4+
// personal capacity and am not conveying any rights to any intellectual
5+
// property of any third parties.
6+
7+
#ifndef INCLUDE_JET_DETAIL_KDTREE_INL_H_
8+
#define INCLUDE_JET_DETAIL_KDTREE_INL_H_
9+
10+
#include <jet/kdtree.h>
11+
12+
#include <numeric>
13+
14+
namespace jet {
15+
16+
template <typename T, size_t K>
17+
KdTree<T, K>::Node::Node() {
18+
child = kMaxSize;
19+
}
20+
21+
template <typename T, size_t K>
22+
void KdTree<T, K>::Node::initLeaf(size_t it, const Point& pt) {
23+
flags = K;
24+
item = it;
25+
child = kMaxSize;
26+
point = pt;
27+
}
28+
29+
template <typename T, size_t K>
30+
void KdTree<T, K>::Node::initInternal(size_t axis, size_t it, size_t c,
31+
const Point& pt) {
32+
flags = axis;
33+
item = it;
34+
child = c;
35+
point = pt;
36+
}
37+
38+
template <typename T, size_t K>
39+
bool KdTree<T, K>::Node::isLeaf() const {
40+
return flags == K;
41+
}
42+
43+
//
44+
45+
template <typename T, size_t K>
46+
KdTree<T, K>::KdTree() {}
47+
48+
template <typename T, size_t K>
49+
void KdTree<T, K>::build(const ConstArrayAccessor1<Point>& points) {
50+
_points.resize(points.size());
51+
std::copy(points.begin(), points.end(), _points.begin());
52+
53+
if (_points.empty()) {
54+
return;
55+
}
56+
57+
_nodes.clear();
58+
59+
std::vector<size_t> itemIndices(_points.size());
60+
std::iota(std::begin(itemIndices), std::end(itemIndices), 0);
61+
62+
build(0, itemIndices.data(), _points.size(), 0);
63+
}
64+
65+
template <typename T, size_t K>
66+
void KdTree<T, K>::forEachNearbyPoint(
67+
const Point& origin, T radius,
68+
const std::function<void(size_t, const Point&)>& callback) const {
69+
const T r2 = radius * radius;
70+
71+
// prepare to traverse the tree for sphere
72+
static const int kMaxTreeDepth = 8 * sizeof(size_t);
73+
const Node* todo[kMaxTreeDepth];
74+
size_t todoPos = 0;
75+
76+
// traverse the tree nodes for sphere
77+
const Node* node = _nodes.data();
78+
79+
while (node != nullptr) {
80+
if (node->item != kMaxSize &&
81+
(node->point - origin).lengthSquared() <= r2) {
82+
callback(node->item, node->point);
83+
}
84+
85+
if (node->isLeaf()) {
86+
// grab next node to process from todo stack
87+
if (todoPos > 0) {
88+
// Dequeue
89+
--todoPos;
90+
node = todo[todoPos];
91+
} else {
92+
break;
93+
}
94+
} else {
95+
// get node children pointers for sphere
96+
const Node* firstChild = node + 1;
97+
const Node* secondChild = (Node*)&_nodes[node->child];
98+
99+
// advance to next child node, possibly enqueue other child
100+
const size_t axis = node->flags;
101+
const T plane = node->point[axis];
102+
if (plane - origin[axis] > radius) {
103+
node = firstChild;
104+
} else if (origin[axis] - plane > radius) {
105+
node = secondChild;
106+
} else {
107+
// enqueue secondChild in todo stack
108+
todo[todoPos] = secondChild;
109+
++todoPos;
110+
node = firstChild;
111+
}
112+
}
113+
}
114+
}
115+
116+
template <typename T, size_t K>
117+
bool KdTree<T, K>::hasNearbyPoint(const Point& origin, T radius) const {
118+
const T r2 = radius * radius;
119+
120+
// prepare to traverse the tree for sphere
121+
static const int kMaxTreeDepth = 8 * sizeof(size_t);
122+
const Node* todo[kMaxTreeDepth];
123+
size_t todoPos = 0;
124+
125+
// traverse the tree nodes for sphere
126+
const Node* node = _nodes.data();
127+
128+
while (node != nullptr) {
129+
if (node->item != kMaxSize &&
130+
(node->point - origin).lengthSquared() <= r2) {
131+
return true;
132+
}
133+
134+
if (node->isLeaf()) {
135+
// grab next node to process from todo stack
136+
if (todoPos > 0) {
137+
// Dequeue
138+
--todoPos;
139+
node = todo[todoPos];
140+
} else {
141+
break;
142+
}
143+
} else {
144+
// get node children pointers for sphere
145+
const Node* firstChild = node + 1;
146+
const Node* secondChild = (Node*)&_nodes[node->child];
147+
148+
// advance to next child node, possibly enqueue other child
149+
const size_t axis = node->flags;
150+
const T plane = node->point[axis];
151+
if (origin[axis] < plane && plane - origin[axis] > radius) {
152+
node = firstChild;
153+
} else if (origin[axis] > plane && origin[axis] - plane > radius) {
154+
node = secondChild;
155+
} else {
156+
// enqueue secondChild in todo stack
157+
todo[todoPos] = secondChild;
158+
++todoPos;
159+
node = firstChild;
160+
}
161+
}
162+
}
163+
164+
return false;
165+
}
166+
167+
template <typename T, size_t K>
168+
size_t KdTree<T, K>::nearestPoint(const Point& origin) const {
169+
// prepare to traverse the tree for sphere
170+
static const int kMaxTreeDepth = 8 * sizeof(size_t);
171+
const Node* todo[kMaxTreeDepth];
172+
size_t todoPos = 0;
173+
174+
// traverse the tree nodes for sphere
175+
const Node* node = _nodes.data();
176+
size_t nearest = 0;
177+
T minDist2 = (node->point - origin).lengthSquared();
178+
179+
while (node != nullptr) {
180+
const T newDist2 = (node->point - origin).lengthSquared();
181+
if (newDist2 <= minDist2) {
182+
nearest = node->item;
183+
minDist2 = newDist2;
184+
}
185+
186+
if (node->isLeaf()) {
187+
// grab next node to process from todo stack
188+
if (todoPos > 0) {
189+
// Dequeue
190+
--todoPos;
191+
node = todo[todoPos];
192+
} else {
193+
break;
194+
}
195+
} else {
196+
// get node children pointers for sphere
197+
const Node* firstChild = node + 1;
198+
const Node* secondChild = (Node*)&_nodes[node->child];
199+
200+
// advance to next child node, possibly enqueue other child
201+
const size_t axis = node->flags;
202+
const T plane = node->point[axis];
203+
const T minDist = std::sqrt(minDist2);
204+
if (plane - origin[axis] > minDist) {
205+
node = firstChild;
206+
} else if (origin[axis] - plane > minDist) {
207+
node = secondChild;
208+
} else {
209+
// enqueue secondChild in todo stack
210+
todo[todoPos] = secondChild;
211+
++todoPos;
212+
node = firstChild;
213+
}
214+
}
215+
}
216+
217+
return nearest;
218+
}
219+
220+
template <typename T, size_t K>
221+
void KdTree<T, K>::reserve(size_t numPoints, size_t numNodes) {
222+
_points.resize(numPoints);
223+
_nodes.resize(numNodes);
224+
}
225+
226+
template <typename T, size_t K>
227+
typename KdTree<T, K>::Iterator KdTree<T, K>::begin() {
228+
return _points.begin();
229+
};
230+
231+
template <typename T, size_t K>
232+
typename KdTree<T, K>::Iterator KdTree<T, K>::end() {
233+
return _points.end();
234+
};
235+
236+
template <typename T, size_t K>
237+
typename KdTree<T, K>::ConstIterator KdTree<T, K>::begin() const {
238+
return _points.begin();
239+
};
240+
241+
template <typename T, size_t K>
242+
typename KdTree<T, K>::ConstIterator KdTree<T, K>::end() const {
243+
return _points.end();
244+
};
245+
246+
template <typename T, size_t K>
247+
typename KdTree<T, K>::NodeIterator KdTree<T, K>::beginNode() {
248+
return _nodes.begin();
249+
};
250+
251+
template <typename T, size_t K>
252+
typename KdTree<T, K>::NodeIterator KdTree<T, K>::endNode() {
253+
return _nodes.end();
254+
};
255+
256+
template <typename T, size_t K>
257+
typename KdTree<T, K>::ConstNodeIterator KdTree<T, K>::beginNode() const {
258+
return _nodes.begin();
259+
};
260+
261+
template <typename T, size_t K>
262+
typename KdTree<T, K>::ConstNodeIterator KdTree<T, K>::endNode() const {
263+
return _nodes.end();
264+
};
265+
266+
template <typename T, size_t K>
267+
size_t KdTree<T, K>::build(size_t nodeIndex, size_t* itemIndices, size_t nItems,
268+
size_t currentDepth) {
269+
// add a node
270+
_nodes.emplace_back();
271+
272+
// initialize leaf node if termination criteria met
273+
if (nItems == 0) {
274+
_nodes[nodeIndex].initLeaf(kMaxSize, {});
275+
return currentDepth + 1;
276+
}
277+
if (nItems == 1) {
278+
_nodes[nodeIndex].initLeaf(itemIndices[0], _points[itemIndices[0]]);
279+
return currentDepth + 1;
280+
}
281+
282+
// choose which axis to split along
283+
BBox nodeBound;
284+
for (size_t i = 0; i < nItems; ++i) {
285+
nodeBound.merge(_points[itemIndices[i]]);
286+
}
287+
Point d = nodeBound.upperCorner - nodeBound.lowerCorner;
288+
size_t axis = static_cast<size_t>(d.dominantAxis());
289+
290+
// pick mid point
291+
std::nth_element(itemIndices, itemIndices + nItems / 2,
292+
itemIndices + nItems, [&](size_t a, size_t b) {
293+
return _points[a][axis] < _points[b][axis];
294+
});
295+
size_t midPoint = nItems / 2;
296+
297+
// recursively initialize children nodes
298+
size_t d0 = build(nodeIndex + 1, itemIndices, midPoint, currentDepth + 1);
299+
_nodes[nodeIndex].initInternal(axis, itemIndices[midPoint], _nodes.size(),
300+
_points[itemIndices[midPoint]]);
301+
size_t d1 = build(_nodes[nodeIndex].child, itemIndices + midPoint + 1,
302+
nItems - midPoint - 1, currentDepth + 1);
303+
304+
return std::max(d0, d1);
305+
}
306+
307+
} // namespace jet
308+
309+
#endif // INCLUDE_JET_DETAIL_KDTREE_INL_H_

include/jet/detail/serialization-inl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
namespace jet {
1515

1616
template <typename T>
17-
void serialize(const Array1<T>& array, std::vector<uint8_t>* buffer) {
17+
void serialize(const ConstArrayAccessor1<T>& array, std::vector<uint8_t>* buffer) {
1818
size_t size = sizeof(T) * array.size();
1919
serialize(reinterpret_cast<const uint8_t*>(array.data()), size, buffer);
2020
}

include/jet/jet.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@
134134
#include <jet/iterative_level_set_solver2.h>
135135
#include <jet/iterative_level_set_solver3.h>
136136
#include <jet/jet.h>
137+
#include <jet/kdtree.h>
137138
#include <jet/level_set_liquid_solver2.h>
138139
#include <jet/level_set_liquid_solver3.h>
139140
#include <jet/level_set_solver2.h>
@@ -180,6 +181,8 @@
180181
#include <jet/point_generator3.h>
181182
#include <jet/point_hash_grid_searcher2.h>
182183
#include <jet/point_hash_grid_searcher3.h>
184+
#include <jet/point_kdtree_searcher2.h>
185+
#include <jet/point_kdtree_searcher3.h>
183186
#include <jet/point_neighbor_searcher2.h>
184187
#include <jet/point_neighbor_searcher3.h>
185188
#include <jet/point_parallel_hash_grid_searcher2.h>

0 commit comments

Comments
 (0)