Blue Brain BioExplorer
PointOctree.cpp
Go to the documentation of this file.
1 /*
2  *
3  * The Blue Brain BioExplorer is a tool for scientists to extract and analyse
4  * scientific data from visualization
5  *
6  * This file is part of Blue Brain BioExplorer <https://github.com/BlueBrain/BioExplorer>
7  *
8  * Copyright 2020-2024 Blue BrainProject / EPFL
9  *
10  * This program is free software: you can redistribute it and/or modify it under
11  * the terms of the GNU General Public License as published by the Free Software
12  * Foundation, either version 3 of the License, or (at your option) any later
13  * version.
14  *
15  * This program is distributed in the hope that it will be useful, but WITHOUT
16  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License along with
21  * this program. If not, see <https://www.gnu.org/licenses/>.
22  */
23 
24 #include "PointOctree.h"
25 
28 
29 namespace core
30 {
31 typedef std::map<uint32_t, PointOctreeNode> PointOctreeLevelMap;
32 
33 PointOctree::PointOctree(const OctreePoints &points, double voxelSize, const Vector3f &minAABB, const Vector3f &maxAABB)
34  : _volumeDimensions(Vector3ui(0u, 0u, 0u))
35  , _volumeSize(0u)
36 {
37  CORE_INFO("Number of points: " << points.size() / 5);
38  Vector3ui octreeSize(_pow2roundup(std::ceil((maxAABB.x - minAABB.x) / voxelSize)),
39  _pow2roundup(std::ceil((maxAABB.y - minAABB.y) / voxelSize)),
40  _pow2roundup(std::ceil((maxAABB.z - minAABB.z) / voxelSize)));
41 
42  // This octree is always cubic
43  _octreeSize = std::max(std::max(octreeSize.x, octreeSize.y), octreeSize.z);
44 
45  CORE_INFO("Point Octree size : " << _octreeSize);
46 
47  _depth = std::log2(_octreeSize) + 1u;
48  std::vector<PointOctreeLevelMap> octree(_depth);
49 
50  CORE_INFO("Point Octree depth : " << _depth << " " << octree.size());
51 
52  if (_depth == 0)
53  return;
54 
55  for (uint32_t i = 0; i < points.size(); ++i)
56  {
57  CORE_PROGRESS("Building octree from points", i, points.size());
58  const uint32_t xpos = std::floor((points[i].position.x - minAABB.x) / voxelSize);
59  const uint32_t ypos = std::floor((points[i].position.y - minAABB.y) / voxelSize);
60  const uint32_t zpos = std::floor((points[i].position.z - minAABB.z) / voxelSize);
61  const double value = points[i].value;
62 
63  const uint32_t indexX = xpos;
64  const uint32_t indexY = ypos * (uint32_t)_octreeSize;
65  const uint32_t indexZ = zpos * (uint32_t)_octreeSize * (uint32_t)_octreeSize;
66 
67  auto it = octree[0].find(indexX + indexY + indexZ);
68  if (it == octree[0].end())
69  {
70  PointOctreeNode *child = nullptr;
71  for (uint32_t level = 0; level < _depth; ++level)
72  {
73  bool newNode = false;
74  const uint32_t divisor = std::pow(2, level);
75  const Vector3f center(xpos, ypos, zpos);
76 
77  const uint32_t nBlock = _octreeSize / divisor;
78  const uint32_t index = std::floor(xpos / divisor) + nBlock * std::floor(ypos / divisor) +
79  nBlock * nBlock * std::floor(zpos / divisor);
80 
81  const double size = voxelSize * (level + 1u);
82 
83  if (octree[level].find(index) == octree[level].end())
84  {
85  Vector3f p{(points[i].position.x - minAABB.x) / voxelSize,
86  (points[i].position.y - minAABB.y) / voxelSize,
87  (points[i].position.z - minAABB.z) / voxelSize};
88 
89  octree[level].insert(PointOctreeLevelMap::value_type(index, PointOctreeNode(p, size)));
90  newNode = true;
91  }
92 
93  octree[level].at(index).addValue(value);
94 
95  if ((level > 0) && (child != nullptr))
96  octree[level].at(index).setChild(child);
97 
98  if (newNode)
99  child = &(octree[level].at(index));
100  else
101  child = nullptr;
102  }
103  }
104  else
105  {
106  for (uint32_t level = 0; level < _depth; ++level)
107  {
108  const uint32_t divisor = std::pow(2, level);
109  const uint32_t nBlock = _octreeSize / divisor;
110  const uint32_t index = std::floor(xpos / divisor) + nBlock * std::floor(ypos / divisor) +
111  nBlock * nBlock * std::floor(zpos / divisor);
112  octree[level].at(index).addValue(value);
113  }
114  }
115  }
116  for (uint32_t i = 0; i < octree.size(); ++i)
117  CORE_DEBUG("Number of leaves [" << i << "]: " << octree[i].size());
118 
119  _offsetPerLevel.resize(_depth);
120  _offsetPerLevel[_depth - 1u] = 0;
121  uint32_t previousOffset = 0u;
122  for (uint32_t i = _depth - 1u; i > 0u; --i)
123  {
124  _offsetPerLevel[i - 1u] = previousOffset + octree[i].size();
125  previousOffset = _offsetPerLevel[i - 1u];
126  }
127 
128  uint32_t totalNodeNumber = 0;
129 
130  for (uint32_t i = 0; i < octree.size(); ++i)
131  totalNodeNumber += octree[i].size();
132 
133  // need to be initialized with zeros
134  _flatIndices.resize(totalNodeNumber * 2u, 0);
135  _flatData.resize(totalNodeNumber * FIELD_POINT_DATA_SIZE);
136 
137  // The root node
138  _flattenChildren(&(octree[_depth - 1u].at(0)), _depth - 1u);
139  _volumeDimensions =
140  Vector3ui(std::ceil((maxAABB.x - minAABB.x) / voxelSize), std::ceil((maxAABB.y - minAABB.y) / voxelSize),
141  std::ceil((maxAABB.z - minAABB.z) / voxelSize));
142  _volumeSize = (uint32_t)_volumeDimensions.x * (uint32_t)_volumeDimensions.y * (uint32_t)_volumeDimensions.z;
143 }
144 
146 
147 void PointOctree::_flattenChildren(PointOctreeNode *node, uint32_t level)
148 {
149  const std::vector<PointOctreeNode *> children = node->getChildren();
150  const auto &position = node->getCenter();
151  const auto value = node->getValue();
152  if ((children.empty()) || (level == 0))
153  {
154  _flatData[_offsetPerLevel[level] * FIELD_POINT_DATA_SIZE + FIELD_POINT_OFFSET_POSITION_X] = position.x;
155  _flatData[_offsetPerLevel[level] * FIELD_POINT_DATA_SIZE + FIELD_POINT_OFFSET_POSITION_Y] = position.y;
156  _flatData[_offsetPerLevel[level] * FIELD_POINT_DATA_SIZE + FIELD_POINT_OFFSET_POSITION_Z] = position.z;
157  _flatData[_offsetPerLevel[level] * FIELD_POINT_DATA_SIZE + FIELD_POINT_OFFSET_VALUE] = value;
158 
159  _offsetPerLevel[level] += 1u;
160  return;
161  }
162  _flatData[_offsetPerLevel[level] * FIELD_POINT_DATA_SIZE + FIELD_POINT_OFFSET_POSITION_X] = position.x;
163  _flatData[_offsetPerLevel[level] * FIELD_POINT_DATA_SIZE + FIELD_POINT_OFFSET_POSITION_Y] = position.y;
164  _flatData[_offsetPerLevel[level] * FIELD_POINT_DATA_SIZE + FIELD_POINT_OFFSET_POSITION_Z] = position.z;
165  _flatData[_offsetPerLevel[level] * FIELD_POINT_DATA_SIZE + FIELD_POINT_OFFSET_VALUE] = value;
166 
167  _flatIndices[_offsetPerLevel[level] * 2u] = _offsetPerLevel[level - 1];
168  _flatIndices[_offsetPerLevel[level] * 2u + 1] = _offsetPerLevel[level - 1] + children.size() - 1u;
169  _offsetPerLevel[level] += 1u;
170 
171  for (PointOctreeNode *child : children)
172  _flattenChildren(child, level - 1u);
173 }
174 } // namespace core
The PointOctreeNode class implement a spherical node of the Octree acceleration structure used by the...
~PointOctree()
Destroy the PointOctree object.
PointOctree(const OctreePoints &points, double voxelSize, const Vector3f &minAABB, const Vector3f &maxAABB)
Construct a new PointOctree object.
Definition: PointOctree.cpp:33
glm::vec3 Vector3f
Definition: MathTypes.h:137
glm::vec< 3, uint32_t > Vector3ui
Definition: MathTypes.h:134
std::map< uint32_t, PointOctreeNode > PointOctreeLevelMap
Definition: PointOctree.cpp:31
std::vector< OctreePoint > OctreePoints
Definition: Types.h:433
#define FIELD_POINT_OFFSET_POSITION_X
Definition: CommonTypes.h:93
#define FIELD_POINT_DATA_SIZE
Definition: CommonTypes.h:92
#define FIELD_POINT_OFFSET_POSITION_Y
Definition: CommonTypes.h:94
#define FIELD_POINT_OFFSET_VALUE
Definition: CommonTypes.h:96
#define FIELD_POINT_OFFSET_POSITION_Z
Definition: CommonTypes.h:95
#define CORE_DEBUG(__msg)
Definition: Logs.h:38
#define CORE_INFO(__msg)
Definition: Logs.h:33
#define CORE_PROGRESS(__msg, __progress, __maxValue)
Definition: Logs.h:47