00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include "octree.h"
00036
00037 #include <iterator>
00038 #include <future>
00039 #include <ciso646>
00040
00041 template<typename T, std::size_t dim>
00042 Octree_<T,dim>::Octree_(): parent{nullptr}, depth{0}
00043 {
00044 for(size_t i=0; i< nbCells; ++i) cells[i]=nullptr;
00045 }
00046
00047 template<typename T, std::size_t dim>
00048 Octree_<T,dim>::Octree_(const Octree_<T,dim>& o):
00049 bb{o.bb.center, o.bb.radius}, depth{o.depth}
00050 {
00051 if (!o.parent)
00052 parent = nullptr;
00053
00054 if(o.isLeaf())
00055 {
00056
00057 for(size_t i=0; i<nbCells; ++i)
00058 cells[i]= nullptr;
00059
00060 data.insert(data.end(), o.data.begin(), o.data.end());
00061 }
00062 else
00063 {
00064
00065 for(size_t i=0; i<nbCells;++i)
00066 {
00067 cells[i] = new Octree_<T,dim>(*(o.cells[i]));
00068
00069 cells[i]->parent = this;
00070 }
00071 }
00072 }
00073 template<typename T, std::size_t dim>
00074 Octree_<T,dim>::Octree_(Octree_<T,dim>&& o):
00075 parent{nullptr}, bb{o.bb.center, o.bb.radius}, depth{o.depth}
00076 {
00077
00078 assert(o.isRoot());
00079
00080 if(o.isLeaf())
00081 {
00082
00083 data.insert(data.end(),
00084 std::make_move_iterator(o.data.begin()),
00085 std::make_move_iterator(o.data.end()));
00086 }
00087
00088 for(size_t i=0; i<nbCells; ++i)
00089 {
00090 cells[i] = o.cells[i];
00091
00092 o.cells[i]=nullptr;
00093 }
00094 }
00095
00096 template<typename T, std::size_t dim>
00097 Octree_<T,dim>::~Octree_()
00098 {
00099
00100 if(!isLeaf())
00101 for(size_t i=0; i<nbCells; ++i)
00102 delete cells[i];
00103 }
00104
00105 template<typename T, std::size_t dim>
00106 Octree_<T,dim>& Octree_<T,dim>::operator=(const Octree_<T,dim>&o)
00107 {
00108 if (!o.parent)
00109 parent = nullptr;
00110
00111 depth=o.depth;
00112
00113 if(o.isLeaf())
00114 {
00115
00116 for(size_t i=0; i<nbCells; ++i)
00117 cells[i]= nullptr;
00118
00119 data.insert(data.end(), o.data.begin(), o.data.end());
00120 }
00121 else
00122 {
00123
00124 for(size_t i=0; i<nbCells; ++i)
00125 {
00126 cells[i] = new Octree_<T,dim>(*(o.cells[i]));
00127
00128 cells[i]->parent = this;
00129 }
00130 }
00131 return *this;
00132 }
00133
00134 template<typename T, std::size_t dim>
00135 Octree_<T,dim>& Octree_<T,dim>::operator=(Octree_<T,dim>&&o)
00136 {
00137
00138 assert(o.isRoot());
00139
00140 parent = nullptr;
00141 bb.center = o.bb.center;
00142 bb.radius = o.bb.radius;
00143
00144 depth = o.depth;
00145
00146 if(o.isLeaf())
00147 {
00148
00149 data.insert(data.end(),
00150 std::make_move_iterator(o.data.begin()),
00151 std::make_move_iterator(o.data.end()));
00152 }
00153
00154
00155 for(size_t i=0; i<nbCells; ++i)
00156 {
00157 cells[i] = o.cells[i];
00158
00159 o.cells[i]=nullptr;
00160 }
00161
00162 return *this;
00163 }
00164
00165 template<typename T, std::size_t dim>
00166 bool Octree_<T,dim>::isLeaf() const
00167 {
00168 return (cells[0]==nullptr);
00169 }
00170 template<typename T, std::size_t dim>
00171 bool Octree_<T,dim>::isRoot() const
00172 {
00173 return (parent==nullptr);
00174 }
00175 template<typename T, std::size_t dim>
00176 bool Octree_<T,dim>::isEmpty() const
00177 {
00178 return (data.size() == 0);
00179 }
00180 template<typename T, std::size_t dim>
00181 size_t Octree_<T,dim>::idx(const Point& pt) const
00182 {
00183 size_t id = 0;
00184
00185 for(size_t i=0; i<dim; ++i)
00186 id|= ((pt(i) > bb.center(i)) << i);
00187
00188 return id;
00189 }
00190
00191 template<typename T, std::size_t dim>
00192 size_t Octree_<T,dim>::idx(const DP& pts, const Data d) const
00193 {
00194 return idx(pts.features.col(d).head(dim));
00195 }
00196 template<typename T, std::size_t dim>
00197 size_t Octree_<T,dim>::getDepth() const
00198 {
00199 return depth;
00200 }
00201 template<typename T, std::size_t dim>
00202 T Octree_<T,dim>::getRadius() const
00203 {
00204 return bb.radius;
00205 }
00206 template<typename T, std::size_t dim>
00207 typename Octree_<T,dim>::Point Octree_<T,dim>::getCenter() const
00208 {
00209 return bb.center;
00210 }
00211 template<typename T, std::size_t dim>
00212 typename Octree_<T,dim>::DataContainer * Octree_<T,dim>::getData()
00213 {
00214 return &data;
00215 }
00216 template<typename T, std::size_t dim>
00217 Octree_<T,dim>* Octree_<T,dim>::operator[](size_t idx)
00218 {
00219 assert(idx<nbCells);
00220 return cells[idx];
00221 }
00222
00223 template<typename T, std::size_t dim>
00224 typename Octree_<T,dim>::DataContainer Octree_<T,dim>::toData(const DP& pts, const std::vector<Id>& ids)
00225 {
00226 return DataContainer{ids.begin(), ids.end()};
00227 }
00228
00229
00230 template<typename T, std::size_t dim>
00231 bool Octree_<T,dim>::build(const DP& pts, size_t maxDataByNode, T maxSizeByNode, bool parallelBuild)
00232 {
00233 typedef typename PM::Vector Vector;
00234
00235
00236 BoundingBox box;
00237
00238 Vector minValues = pts.features.rowwise().minCoeff();
00239 Vector maxValues = pts.features.rowwise().maxCoeff();
00240
00241 Point min = minValues.head(dim);
00242 Point max = maxValues.head(dim);
00243
00244 Point radii = max - min;
00245 box.center = min + radii * 0.5;
00246
00247 box.radius = radii(0);
00248 for(size_t i=1; i<dim; ++i)
00249 if (box.radius < radii(i)) box.radius = radii(i);
00250
00251 box.radius*=0.5;
00252
00253
00254 const size_t nbpts = pts.getNbPoints();
00255 std::vector<Id> indexes;
00256 indexes.reserve(nbpts);
00257
00258 for(size_t i=0; i<nbpts; ++i)
00259 indexes.emplace_back(Id(i));
00260
00261 DataContainer datas = toData(pts, indexes);
00262
00263
00264 return this->build(pts, std::move(datas), std::move(box), maxDataByNode, maxSizeByNode, parallelBuild);
00265 }
00266
00267
00268 template<typename T, std::size_t dim>
00269 struct OctreeHelper;
00270
00271 template<typename T>
00272 struct OctreeHelper<T,3>
00273 {
00274 static const typename Octree_<T,3>::Point offsetTable[Octree_<T,3>::nbCells];
00275 };
00276 template<typename T>
00277 const typename Octree_<T,3>::Point OctreeHelper<T,3>::offsetTable[Octree_<T,3>::nbCells] =
00278 {
00279 {-0.5, -0.5, -0.5},
00280 {+0.5, -0.5, -0.5},
00281 {-0.5, +0.5, -0.5},
00282 {+0.5, +0.5, -0.5},
00283 {-0.5, -0.5, +0.5},
00284 {+0.5, -0.5, +0.5},
00285 {-0.5, +0.5, +0.5},
00286 {+0.5, +0.5, +0.5}
00287 };
00288
00289 template<typename T>
00290 struct OctreeHelper<T,2>
00291 {
00292 static const typename Octree_<T,2>::Point offsetTable[Octree_<T,2>::nbCells];
00293 };
00294 template<typename T>
00295 const typename Octree_<T,2>::Point OctreeHelper<T,2>::offsetTable[Octree_<T,2>::nbCells] =
00296 {
00297 {-0.5, -0.5},
00298 {+0.5, -0.5},
00299 {-0.5, +0.5},
00300 {+0.5, +0.5}
00301 };
00302
00303 template<typename T, std::size_t dim>
00304 bool Octree_<T,dim>::build(const DP& pts, DataContainer&& datas, BoundingBox && bb,
00305 size_t maxDataByNode, T maxSizeByNode, bool parallelBuild)
00306 {
00307
00308 this->bb.center = bb.center;
00309 this->bb.radius = bb.radius;
00310
00311
00312 if((bb.radius*2.0 <= maxSizeByNode) or (datas.size() <= maxDataByNode))
00313 {
00314
00315 data.insert(data.end(),
00316 std::make_move_iterator(datas.begin()), make_move_iterator(datas.end()));
00317 return (isLeaf());
00318 }
00319
00320
00321 const std::size_t nbData = datas.size();
00322
00323 DataContainer sDatas[nbCells];
00324 for(size_t i=0; i<nbCells; ++i)
00325 sDatas[i].reserve(nbData);
00326
00327 for(auto&& d : datas)
00328 (sDatas[idx(pts, d)]).emplace_back(d);
00329
00330 for(size_t i=0; i<nbCells; ++i)
00331 sDatas[i].shrink_to_fit();
00332
00333
00334 BoundingBox boxes[nbCells];
00335 const T half_radius = this->bb.radius * 0.5;
00336 for(size_t i=0; i<nbCells; ++i)
00337 {
00338 const Point offset = OctreeHelper<T,dim>::offsetTable[i] * this->bb.radius;
00339 boxes[i].radius = half_radius;
00340 boxes[i].center = this->bb.center + offset;
00341 }
00342
00343
00344 bool ret = true;
00345 std::vector<std::future<void>> futures;
00346
00347 for(size_t i=0; i<nbCells; ++i)
00348 {
00349 auto compute = [maxDataByNode, maxSizeByNode, i, &pts, &sDatas, &boxes, this](){
00350 this->cells[i] = new Octree_<T,dim>();
00351
00352 this->cells[i]->depth = this->depth+1;
00353
00354 this->cells[i]->parent = this;
00355
00356 this->cells[i]->build(pts, std::move(sDatas[i]), std::move(boxes[i]), maxDataByNode, maxSizeByNode, false);
00357 };
00358
00359 if(parallelBuild)
00360 futures.push_back( std::async( std::launch::async, compute ));
00361 else
00362 compute();
00363 }
00364
00365 for(auto& f : futures) f.get();
00366
00367 return (!isLeaf() and ret);
00368 }
00369
00370
00371 template<typename T, std::size_t dim>
00372 template<typename Callback>
00373 bool Octree_<T,dim>::visit(Callback& cb)
00374 {
00375
00376
00377 if (!cb(*this)) return false;
00378
00379
00380 if (!isLeaf())
00381 for (size_t i=0; i<nbCells; ++i)
00382 if (!cells[i]->visit(cb)) return false;
00383
00384 return true;
00385 }