Skip to content

Commit f3888cf

Browse files
committed
Use octree traversal to implement star browser functions
Improves performance of the star browser by using the octree to avoid processing unnecessary stars. - Store node depth instead of size in static octree - Implement "breadth-first" octree traversal with iterative depth-first processing - Rewrite the star browser comparison functions to use breadth-first traversal
1 parent 2bd4250 commit f3888cf

File tree

5 files changed

+388
-183
lines changed

5 files changed

+388
-183
lines changed

src/celengine/octree.h

Lines changed: 61 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@ struct StaticOctreeNode
3737
{
3838
using PointType = Eigen::Matrix<PREC, 3, 1>;
3939

40-
StaticOctreeNode(const PointType&, PREC);
40+
StaticOctreeNode(const PointType&, OctreeDepthType);
4141

4242
PointType center;
43-
PREC scale;
43+
OctreeDepthType depth;
4444
OctreeNodeIndex right{ InvalidOctreeNode };
4545
OctreeObjectIndex first{ 0 };
4646
OctreeObjectIndex last{ 0 };
@@ -49,9 +49,9 @@ struct StaticOctreeNode
4949

5050
template<class PREC>
5151
StaticOctreeNode<PREC>::StaticOctreeNode(const PointType& _center,
52-
PREC _scale) :
52+
OctreeDepthType _depth) :
5353
center(_center),
54-
scale(_scale)
54+
depth(_depth)
5555
{
5656
}
5757

@@ -95,6 +95,9 @@ class StaticOctree
9595
template<typename PROCESSOR>
9696
void processDepthFirst(PROCESSOR&) const;
9797

98+
template<typename PROCESSOR>
99+
void processBreadthFirst(PROCESSOR&) const;
100+
98101
OctreeObjectIndex size() const;
99102
OctreeNodeIndex nodeCount() const;
100103

@@ -104,8 +107,14 @@ class StaticOctree
104107
private:
105108
using NodeType = detail::StaticOctreeNode<PREC>;
106109

110+
template<typename PROCESSOR>
111+
bool processToDepth(PROCESSOR&, OctreeDepthType) const;
112+
107113
std::vector<NodeType> m_nodes;
108114
std::vector<OBJ> m_objects;
115+
std::vector<PREC> m_sizes;
116+
OctreeDepthType m_minPopulated{ UINT32_MAX };
117+
OctreeDepthType m_maxDepth{ 0 };
109118

110119
template<class TRAITS, class STORAGE>
111120
friend class DynamicOctree;
@@ -117,25 +126,69 @@ void
117126
StaticOctree<OBJ, PREC>::processDepthFirst(PROCESSOR& processor) const
118127
{
119128
OctreeNodeIndex nodeIdx = 0;
120-
OctreeNodeIndex endIdx = nodeCount();
129+
const OctreeNodeIndex endIdx = nodeCount();
121130
while (nodeIdx < endIdx)
122131
{
123132
const NodeType& node = m_nodes[nodeIdx];
124-
if (!processor.checkNode(node.center, node.scale, node.brightFactor))
133+
if (!processor.checkNode(node.center, m_sizes[node.depth], node.brightFactor))
125134
{
126135
nodeIdx = node.right;
127136
continue;
128137
}
129138

130139
for (OctreeObjectIndex idx = node.first; idx < node.last; ++idx)
131-
{
132140
processor.process(m_objects[idx]);
133-
}
134141

135142
++nodeIdx;
136143
}
137144
}
138145

146+
// Simulate a breadth-first search by doing an interative depth-first search,
147+
// starting at the minimum populated depth. The search terminates when no nodes
148+
// at the requested depth are reached.
149+
template<class OBJ, class PREC>
150+
template<typename PROCESSOR>
151+
void
152+
StaticOctree<OBJ, PREC>::processBreadthFirst(PROCESSOR& processor) const
153+
{
154+
for (OctreeDepthType depth = m_minPopulated; depth <= m_maxDepth; ++depth)
155+
{
156+
if (!processToDepth(processor, depth))
157+
break;
158+
}
159+
}
160+
161+
template<class OBJ, class PREC>
162+
template<typename PROCESSOR>
163+
bool
164+
StaticOctree<OBJ, PREC>::processToDepth(PROCESSOR& processor, OctreeDepthType depth) const
165+
{
166+
OctreeNodeIndex nodeIdx = 0;
167+
const OctreeNodeIndex endIdx = nodeCount();
168+
bool result = false;
169+
while (nodeIdx < endIdx)
170+
{
171+
const NodeType& node = m_nodes[nodeIdx];
172+
if (!processor.checkNode(node.center, m_sizes[node.depth], node.brightFactor))
173+
{
174+
nodeIdx = node.right;
175+
}
176+
else if (node.depth == depth)
177+
{
178+
result = true;
179+
for (OctreeObjectIndex idx = node.first; idx < node.last; ++idx)
180+
processor.process(m_objects[idx]);
181+
nodeIdx = node.right;
182+
}
183+
else
184+
{
185+
++nodeIdx;
186+
}
187+
}
188+
189+
return result;
190+
}
191+
139192
template<class OBJ, class PREC>
140193
OctreeObjectIndex
141194
StaticOctree<OBJ, PREC>::size() const

src/celengine/octreebuilder.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,9 +264,14 @@ DynamicOctree<TRAITS, STORAGE>::build()
264264
while (!nodeStack.empty())
265265
{
266266
auto [nodeIdx, depth] = nodeStack.back();
267+
nodeStack.pop_back();
268+
267269
const NodeType& node = m_nodes[nodeIdx];
268270
buildNode(*staticOctree, node, depth, prevByDepth);
269-
nodeStack.pop_back();
271+
if (depth < staticOctree->m_minPopulated && !node.objIndices.empty())
272+
staticOctree->m_minPopulated = depth;
273+
if (depth > staticOctree->m_maxDepth)
274+
staticOctree->m_maxDepth = depth;
270275

271276
if (node.children == nullptr)
272277
continue;
@@ -281,6 +286,8 @@ DynamicOctree<TRAITS, STORAGE>::build()
281286
for (OctreeObjectIndex objIndex : m_excluded)
282287
staticOctree->m_objects.emplace_back(std::move(m_objects[objIndex]));
283288

289+
staticOctree->m_sizes = std::move(m_sizes);
290+
284291
return staticOctree;
285292
}
286293

@@ -302,7 +309,7 @@ DynamicOctree<TRAITS, STORAGE>::buildNode(StaticOctreeType& staticOctree,
302309

303310
prevByDepth.push_back(staticNodeIdx);
304311

305-
auto& staticNode = staticOctree.m_nodes.emplace_back(node.center, m_sizes[depth]);
312+
auto& staticNode = staticOctree.m_nodes.emplace_back(node.center, depth);
306313

307314
if (node.objIndices.empty())
308315
return;

0 commit comments

Comments
 (0)