该代码为静态生成八叉树代码,一经创建,不可改变
step1:节点数据结构
//结构体
struct Point {
double x;
double y;
double z;
void setPoint(double x, double y, double z) {
this->x = x;
this->y = y;
this->z = z;
}
Point() {}
Point(double x, double y, double z) {
this->x = x;
this->y = y;
this->z = z;
}
};
typedef struct Octree_Node {
int count; //该节点往下所包含点的个数
std::vector<Point> points; //用来在叶子节点保存点云
Octree_Node *nodes[8]; //8个孩子节点
Octree_Node *parent; //父节点
int level; //该节点在八叉树中的深度
Point centel; //八叉树格子中心位置
double length; //八叉树小格子宽度
//初始化八叉树节点(父节点,格子宽度,深度)
void init(Octree_Node *parent, double length, int level) {
this->parent = parent;
for (int i = 0; i < 8; i++) {
nodes[i] = NULL;
}
centel.setPoint(0, 0, 0);
this->level = level;
this->length = length;
}
//释放该节点
void destory() {
this->parent = NULL;
for (int i = 0; i < 8; i++) {
nodes[i] = NULL;
}
}
}Octree_Node, *Octree_Struct;
//类成员
Octree_Struct octree; //八叉树root节点
std::vector<Point> pointCloud;
double max_x; //八叉树包围盒大小
double max_z;
double max_y;
double octLength;
step2:初始化点云数据
for (int i = 0; i < 1000; i++) {
Point point;
point.setPoint(rand() % 1000, rand() % 1000, rand() % 1000);
pointCloud.push_back(point);
}
step3: 根据点云规模创建相应大小的八叉树
//初始化八叉树(包围盒大小pointCloud)
void CreatOctreeByPointCloud() {
this->max_x = pointCloud.at(0).x;
this->max_y = pointCloud.at(0).y;
this->max_z = pointCloud.at(0).z;
std::vector<Point>::iterator it = pointCloud.begin();
for (; it != pointCloud.end(); it++) {
this->max_x = this->max_x < (*it).x ? (*it).x : this->max_x;
this->max_y = this->max_y < (*it).y ? (*it).y : this->max_y;
this->max_z = this->max_z < (*it).z ? (*it).z : this->max_z;
}
octree = new Octree_Node();
//octLength为手动设置叶子节点格子大小,根据点云规模设置,越小八叉树分的越细
double length = octLength;
double maxLength;
int level = 1;
maxLength = max_x > max_y ? max_x : max_y;
maxLength = maxLength > max_z ? maxLength : max_z;
while (length < maxLength) { //maxLength为最小能包含所有点的边长
length *= 2; //但在八叉树中,每层都是子节点的两倍,
//所以根节点的length要大于maxLength
level++;
}
//根节点octree
//length:根节点每个格子的宽度,格子为正方体
//level:将要创建的八叉树的深度的最大值,
// 比如深度为5的八叉树,根节点的level就是5,叶子节点为1
octree->init(NULL, length, level); //初始化根节点(该函数在Step1)
//生成一个空的八叉树,不包含任何数据
creat(octree);
//把数据放到八叉树中,并把不包含数据的地方释放掉
addPointCloud(pointCloud);
}
//递归生产八叉树空节点
void creat(Octree_Struct octree) {
if (octree->level == 1) {
return;
}
for (int i = 0; i < 8; i++) {
octree->nodes[i] = new Octree_Node();
octree->nodes[i]->init(octree, octree->length / 2, octree->level - 1);
if (i == 0 || i == 1 || i == 4 || i == 5)
octree->nodes[i]->centel.y = octree->centel.y + octree->length / 2;
if (i == 2 || i == 3 || i == 6 || i == 7)
octree->nodes[i]->centel.y = octree->centel.y - octree->length / 2;
if (i == 0 || i == 2 || i == 4 || i == 6)
octree->nodes[i]->centel.x = octree->centel.x + octree->length / 2;
if (i == 1 || i == 3 || i == 5 || i == 7)
octree->nodes[i]->centel.x = octree->centel.x - octree->length / 2;
if (i == 0 || i == 1 || i == 2 || i == 3)
octree->nodes[i]->centel.z = octree->centel.z + octree->length / 2;
if (i == 4 || i == 5 || i == 6 || i == 7)
octree->nodes[i]->centel.z = octree->centel.z - octree->length / 2;
creat(octree->nodes[i]);
}
}
把每个点放到它该在的位置(对应叶子节点中)
//添加点云到八叉树中
void addPointCloud(std::vector<Point> pointCloud) {
std::vector<Point>::iterator it = pointCloud.begin();
for (; it != pointCloud.end(); it++) {
octree->count++;
addNode(octree, *it);
}
addNodeEnd(octree);
}
void addNode(Octree_Struct octree, Point point) {
if (octree->level == 1) {
octree->points.push_back(point);
return;
}
if (point.x >= octree->centel.x && point.y >= octree->centel.y && point.z >= octree->centel.z) {
octree->nodes[0]->count++;
addNode(octree->nodes[0], point);
}
else if (point.x < octree->centel.x && point.y >= octree->centel.y && point.z >= octree->centel.z) {
octree->nodes[1]->count++;
addNode(octree->nodes[1], point);
}
else if (point.x >= octree->centel.x && point.y < octree->centel.y && point.z >= octree->centel.z) {
octree->nodes[2]->count++;
addNode(octree->nodes[2], point);
}
else if (point.x < octree->centel.x && point.y < octree->centel.y && point.z >= octree->centel.z) {
octree->nodes[3]->count++;
addNode(octree->nodes[3], point);
}
else if (point.x >= octree->centel.x && point.y >= octree->centel.y && point.z < octree->centel.z) {
octree->nodes[4]->count++;
addNode(octree->nodes[4], point);
}
else if (point.x < octree->centel.x && point.y >= octree->centel.y && point.z < octree->centel.z) {
octree->nodes[5]->count++;
addNode(octree->nodes[5], point);
}
else if (point.x >= octree->centel.x && point.y < octree->centel.y && point.z < octree->centel.z) {
octree->nodes[6]->count++;
addNode(octree->nodes[6], point);
}
else if (point.x < octree->centel.x && point.y < octree->centel.y && point.z < octree->centel.z) {
octree->nodes[7]->count++;
addNode(octree->nodes[7], point);
}
}
当所有点都添加到八叉树中后,把空节点释放掉
void addNodeEnd(Octree_Struct octree) {
for (int i = 0; i < 8; i++) {
if (octree->nodes[i] != NULL) {
addNodeEnd(octree->nodes[i]);
if (octree->nodes[i]->count == 0) {
octree->nodes[i]->parent = NULL;
delete octree->nodes[i];
octree->nodes[i] = NULL;
}
}
}
}
至此,八叉树已经创建好了
Step4:销毁八叉树
void destory(Octree_Struct octree) {
for (int i = 0; i < 8; i++) {
if (octree->nodes[i] != NULL) {
destory(octree->nodes[i]);
octree->nodes[i]->parent = NULL;
octree->nodes[i]->points.clear();
delete octree->nodes[i];
}
}
if (octree->parent == NULL) {
pointCloud.clear();
delete octree;
}
}
完整代码:
#pragma once
#include <iostream>
#include <vector>
#include <math.h>
class Octree{
public:
Octree() {}
~Octree() { destory(octree); }
struct Point {
double x;
double y;
double z;
void setPoint(double x, double y, double z) {
this->x = x;
this->y = y;
this->z = z;
}
Point() {}
Point(double x, double y, double z) {
this->x = x;
this->y = y;
this->z = z;
}
};
typedef struct Octree_Node {
int count;
std::vector<Point> points;
Octree_Node *nodes[8];
Octree_Node *parent;
int level;
Point centel;
double length;
void init(Octree_Node *parent, double length, int level) {
this->parent = parent;
for (int i = 0; i < 8; i++) {
nodes[i] = NULL;
}
centel.setPoint(0, 0, 0);
this->level = level;
this->length = length;
}
void destory() {
this->parent = NULL;
for (int i = 0; i < 8; i++) {
nodes[i] = NULL;
}
}
}Octree_Node, *Octree_Struct;
Octree_Struct octree;
double octLength;
std::vector<Point> pointCloud;
double max_x;
double max_z;
double max_y;
void setPoint(std::vector<Point> points) {
int size = points.size();
for (int i = 0; i < size; i++) {
pointCloud.push_back(points[i]);
}
}
void CreatOctreeByPointCloud() {
this->max_x = pointCloud.at(0).x;
this->max_y = pointCloud.at(0).y;
this->max_z = pointCloud.at(0).z;
//计算八叉树深度和宽度
std::vector<Point>::iterator it = pointCloud.begin();
for (; it != pointCloud.end(); it++) {
this->max_x = this->max_x < (*it).x ? (*it).x : this->max_x;
this->max_y = this->max_y < (*it).y ? (*it).y : this->max_y;
this->max_z = this->max_z < (*it).z ? (*it).z : this->max_z;
}
double length = octLength;
double maxLength;
int level = 1;
maxLength = max_x > max_y ? max_x : max_y;
maxLength = maxLength > max_z ? maxLength : max_z;
while (length < maxLength) {
length *= 2;
level++;
}
//初始化八叉树
octree = new Octree_Node();
octree->init(NULL, length, level);
creat(octree);
addPointCloud(pointCloud);
}
void creat(Octree_Struct octree) {
if (octree->level == 1) {
return;
}
for (int i = 0; i < 8; i++) {
octree->nodes[i] = new Octree_Node();
octree->nodes[i]->init(octree, octree->length / 2, octree->level - 1);
if (i == 0 || i == 1 || i == 4 || i == 5)
octree->nodes[i]->centel.y = octree->centel.y + octree->length / 2;
if (i == 2 || i == 3 || i == 6 || i == 7)
octree->nodes[i]->centel.y = octree->centel.y - octree->length / 2;
if (i == 0 || i == 2 || i == 4 || i == 6)
octree->nodes[i]->centel.x = octree->centel.x + octree->length / 2;
if (i == 1 || i == 3 || i == 5 || i == 7)
octree->nodes[i]->centel.x = octree->centel.x - octree->length / 2;
if (i == 0 || i == 1 || i == 2 || i == 3)
octree->nodes[i]->centel.z = octree->centel.z + octree->length / 2;
if (i == 4 || i == 5 || i == 6 || i == 7)
octree->nodes[i]->centel.z = octree->centel.z - octree->length / 2;
creat(octree->nodes[i]);
}
}
void addPointCloud(std::vector<Point> pointCloud) {
std::vector<Point>::iterator it = pointCloud.begin();
for (; it != pointCloud.end(); it++) {
octree->count++;
addNode(octree, *it);
}
addNodeEnd(octree);
}
void addNode(Octree_Struct octree, Point point) {
if (octree->level == 1) {
octree->points.push_back(point);
return;
}
if (point.x >= octree->centel.x && point.y >= octree->centel.y && point.z >= octree->centel.z) {
octree->nodes[0]->count++;
addNode(octree->nodes[0], point);
}
else if (point.x < octree->centel.x && point.y >= octree->centel.y && point.z >= octree->centel.z) {
octree->nodes[1]->count++;
addNode(octree->nodes[1], point);
}
else if (point.x >= octree->centel.x && point.y < octree->centel.y && point.z >= octree->centel.z) {
octree->nodes[2]->count++;
addNode(octree->nodes[2], point);
}
else if (point.x < octree->centel.x && point.y < octree->centel.y && point.z >= octree->centel.z) {
octree->nodes[3]->count++;
addNode(octree->nodes[3], point);
}
else if (point.x >= octree->centel.x && point.y >= octree->centel.y && point.z < octree->centel.z) {
octree->nodes[4]->count++;
addNode(octree->nodes[4], point);
}
else if (point.x < octree->centel.x && point.y >= octree->centel.y && point.z < octree->centel.z) {
octree->nodes[5]->count++;
addNode(octree->nodes[5], point);
}
else if (point.x >= octree->centel.x && point.y < octree->centel.y && point.z < octree->centel.z) {
octree->nodes[6]->count++;
addNode(octree->nodes[6], point);
}
else if (point.x < octree->centel.x && point.y < octree->centel.y && point.z < octree->centel.z) {
octree->nodes[7]->count++;
addNode(octree->nodes[7], point);
}
}
void addNodeEnd(Octree_Struct octree) {
for (int i = 0; i < 8; i++) {
if (octree->nodes[i] != NULL) {
addNodeEnd(octree->nodes[i]);
if (octree->nodes[i]->count == 0) {
octree->nodes[i]->parent = NULL;
delete octree->nodes[i];
octree->nodes[i] = NULL;
}
}
}
}
void destory(Octree_Struct octree) {
for (int i = 0; i < 8; i++) {
if (octree->nodes[i] != NULL) {
destory(octree->nodes[i]);
octree->nodes[i]->parent = NULL;
octree->nodes[i]->points.clear();
delete octree->nodes[i];
}
}
if (octree->parent == NULL) {
pointCloud.clear();
delete octree;
}
}
};
main.cpp
#include "Octree3.h"
int main(int argc, char *argv[])
{
int size = 10;
std::vector<Octree::Point> pointCloud;
for (int i = 0; i < size; i++) {
pointCloud.push_back(Octree::Point(rand() % 1000 - 500, rand() % 1000 - 500, rand() % 1000 - 500));
}
Octree oct;
oct.octLength = 10;
oct.setPoint(pointCloud);
oct.CreatOctreeByPointCloud();
}
八叉树可视化