C++ 八叉树:我做错了吗?插入速度非常慢
我正在将一个基于八叉树的容器从10点到10亿点写入内存。。由于加载的数据量很大,我需要注意内存消耗 一切似乎都正常工作,并根据需要进行分段,但插入时间非常缓慢。可能是因为数据在父对象到子对象之间的重新分配。 我能做些什么来优化它吗?我是否正确地实施了这一点? 我可以在每个节点中保留向量以包含最大数量的点,但这会显著增加所需的内存 使用一个简单的R树型容器,我在48秒内加载了4.68亿个点。。 使用下面的八叉树,我在245秒内加载C++ 八叉树:我做错了吗?插入速度非常慢,c++,memory-management,octree,C++,Memory Management,Octree,我正在将一个基于八叉树的容器从10点到10亿点写入内存。。由于加载的数据量很大,我需要注意内存消耗 一切似乎都正常工作,并根据需要进行分段,但插入时间非常缓慢。可能是因为数据在父对象到子对象之间的重新分配。 我能做些什么来优化它吗?我是否正确地实施了这一点? 我可以在每个节点中保留向量以包含最大数量的点,但这会显著增加所需的内存 使用一个简单的R树型容器,我在48秒内加载了4.68亿个点。。 使用下面的八叉树,我在245秒内加载 class OctreeNode { public
class OctreeNode {
public:
std::vector<std::shared_ptr<OctreeNode>> Children;
std::vector<TPoint> Data;
BoundingBox Bounds;
OctreeNode(){}
OctreeNode(BoundingBox bounds) : Bounds(bounds){
}
~OctreeNode(void){}
void Split();
};
typedef std::shared_ptr<OctreeNode> OctreeNodePtr;
void OctreeNode::Split()
{
Point box[8];
Bounds.Get8Corners(box);
Point center = Bounds.Center;
Children.reserve(8);
Children.push_back(OctreeNodePtr(new OctreeNode(BoundingBox::From(box[0], center))));
Children.push_back(OctreeNodePtr(new OctreeNode(BoundingBox::From(box[1], center))));
Children.push_back(OctreeNodePtr(new OctreeNode(BoundingBox::From(box[3], center))));
Children.push_back(OctreeNodePtr(new OctreeNode(BoundingBox::From(box[2], center))));
Children.push_back(OctreeNodePtr(new OctreeNode(BoundingBox::From(box[5], center))));
Children.push_back(OctreeNodePtr(new OctreeNode(BoundingBox::From(box[4], center))));
Children.push_back(OctreeNodePtr(new OctreeNode(BoundingBox::From(box[6], center))));
Children.push_back(OctreeNodePtr(new OctreeNode(BoundingBox::From(box[7], center))));
}
Octree::Octree(BoundingBox bounds) : Bounds(bounds)
{
_root = OctreeNodePtr(new OctreeNode(bounds));
_root->Split();
}
Octree::~Octree()
{
}
bool Octree::InsertPoint(TPoint &p)
{
return InsertPoint(p, _root);
}
bool Octree::InsertPoint(TPoint &p, const OctreeNodePtr &parent)
{
if (parent->Children.size() != 0){
for (size_t i = 0; i < parent->Children.size(); i++){
OctreeNodePtr ¤tNode = parent->Children[i];
if (currentNode->Bounds.IsContained(p.ToPoint3d())){
return InsertPoint(p, currentNode);
}
}
// Was not able to insert a point.
return false;
}
BoundingBox newBounds = parent->Bounds;
newBounds.Extend(p.ToPoint3d());
// Check for split condition...
if (parent->Data.size() == MaxPerNode && newBounds.XLength() > 0.01){
// Split it...thus generating children nodes
parent->Split();
// Resize the children arrays so that we don't have to keep allocating when redistributing points..
for (size_t i = 0; i < parent->Children.size(); i++){
parent->Children[i]->Data.reserve(parent->Data.size());
}
// Distribute the points that were in the parent to its children..
for (size_t i = 0; i < parent->Data.size(); i++){
TPoint originalPoint = parent->Data[i];
if (!InsertPoint(originalPoint, parent)){
printf("Failed to insert point\n");
break;
}
}
// Insert the current point.
if (!InsertPoint(p, parent)){
printf("Failed to insert point\n");
}
// Resize the arrays back so it fits the size of the data.....
for (size_t i = 0; i < parent->Children.size(); i++){
parent->Children[i]->Data.shrink_to_fit();
}
// clear out the parent information
parent->Data.clear();
parent->Data.shrink_to_fit();
return true;
} else {
// Node is valid so insert the data..
if (parent->Data.size() <= 100000){
parent->Data.push_back(p);
} else {
printf("Too much data in tiny node... Stop adding\n");
}
return true;
}
}
void Octree::Compress(){
Compress(_root);
}
void Octree::Compress(const OctreeNodePtr &parent){
if (parent->Children.size() > 0){
// Look for and remove useless cells who do not contain children or point cloud data.
size_t j = 0;
bool removed = false;
while (j < parent->Children.size()){
if (parent->Children[j]->Children.size() == 0 && parent->Children[j]->Data.size() == 0){
parent->Children.erase(parent->Children.begin() + j);
removed = true;
} else {
Compress(parent->Children[j]);
++j;
}
}
if (removed)
parent->Children.shrink_to_fit();
return;
}
parent->Data.shrink_to_fit();
}
类八进制{
公众:
性病媒儿童;
std::矢量数据;
边界框边界;
八叉树节点(){}
八叉树节点(边界框边界):边界(边界){
}
~OctreeNode(void){}
无效分割();
};
typedef std::shared_ptr OctreeNodePtr;
void OctreeNode::Split()
{
积分箱[8];
边界。获取8个角(框);
点中心=边界。中心;
儿童保护区(8);
向后推(OctreeNodePtr(新的OctreeNode(BoundingBox::From)(框[0],中心));
向后推(OctreeNodePtr(新的OctreeNode(BoundingBox::From)(框[1],中心));
向后推(OctreeNodePtr(新的OctreeNode(BoundingBox::From)(框[3],中间));
向后推(OctreeNodePtr(新的OctreeNode(BoundingBox::From)(框[2],中间));
向后推(OctreeNodePtr(新的OctreeNode(BoundingBox::From)(方框[5],中间));
向后推(OctreeNodePtr(新的OctreeNode(BoundingBox::From)(方框[4],中间));
向后推(OctreeNodePtr(新的OctreeNode(BoundingBox::From)(方框[6],中间));
向后推(OctreeNodePtr(新的OctreeNode(BoundingBox::From)(方框[7],中间));
}
八叉树::八叉树(边界框边界):边界(边界)
{
_root=OctreeNodePtr(新的OctreeNode(边界));
_root->Split();
}
八叉树::~Octree()
{
}
布尔八叉树::插入点(TPoint&p)
{
返回插入点(p,_根);
}
bool八叉树::InsertPoint(TPoint&p,const-OctreeNodePtr&parent)
{
如果(父级->子级.size()!=0){
对于(size_t i=0;i只是一件小事,但要取代它:
Children.push_back(OctreeNodePtr(new OctreeNode(BoundingBox::From(box[0], center))));
为此:
Children.push_back(std::make_shared<OctreeNode>(BoundingBox::From(box[0], center)));
Children.push_back(std::make_shared(BoundingBox::From(box[0],center));
将稍微减少加载时间并减少内存消耗
这对于任何共享ptr都是正确的。make_shared route将控制块与共享对象合并。我在这里看到的是,要插入点,您需要遍历8个子对象,并检查每个子对象是否在内部 八叉树的主要优点是,根据边界框中心和数据的位置,可以