八叉树
判断子长方体的8个点是否在物体内,可判断这8个点是不是在整个物体所有面的内侧。
注:
(1)但如果物体不是凸壳呢,而是凹体呢???可能某个点在一个面外,但它仍在物体内。??????????
(2)每个子长方体里的Object* oo;对象都是该物体的完整模型,该物体的面片并不会被分解。
参考源代码如下:(octtree.h、octtree.cpp、main.cpp)
下载地址:http://download.csdn.net/download/gdf420/2874752
1、 octtree.h
#ifndef OCTTREE_H
#define OCTTREE_H
#include <vector>
using namespace std;
/*
三维空间点类
*/
struct Point{
public:
double x,y,z;
void setPoint(double _x,double _y,double _z){
x = _x; y = _y; z = _z;
}
bool equals(Point* p){//判断2个点是否相等
if(x != p->x)return false;
if(y != p->y)return false;
if(z != p->z)return false;
return true;
}
};
/*
平面方程类
void setFormula(Point* p[]):计算4个参数(a,b,c,d)
bool formpos(Point* p):在平面某一侧的正负
*/
struct Formula{
double a,b,c,d;
void setFormula(Point* p[]){
a=(p[1]->y-p[0]->y)*(p[2]->z-p[0]->z)-(p[2]->y-p[0]->y)*(p[1]->z-p[0]->z);
b=(p[1]->x-p[0]->x)*(p[2]->z-p[0]->z)-(p[2]->x-p[0]->x)*(p[1]->z-p[0]->z);
b=-(b);
c=(p[1]->x-p[0]->x)*(p[2]->y-p[0]->y)-(p[2]->x-p[0]->x)*(p[1]->y-p[0]->y);
d=-(a*p[0]->x+b*p[0]->y+c*p[0]->z);
}
bool formpos(Point* p){//点在面的内侧或外侧
double tmp;
tmp = a*p->x + b*p->y + c*p->z +d;
if(tmp > 0)return true;
else return false;
}//代入方程后值的正负
};
/*
多边形面类
bool hasPoint(Point* p):是否在平面顶点组里
*/
struct Face{
Point** vp; //顶点指针数组
int num; //顶点个数
Formula form; //平面方程
bool forminsidepos; //在多边形内的点带入方程的正负
bool hasPoint(Point* p){
for(int i = 0;i < num;i++){
if(vp[i]->equals(p))return true;
}
return false;
}
};
/*
物体类
bool isInside(Point* p)判断一个点是否在物体内
*/
struct Object{
Face** vf;//初始化还要包括每个面的正负情况
int num;
bool isInside(Point* p){
for(int i = 0;i < num;i++){//如果某点在面的外侧,则返回false
if(vf[i]->form.formpos(p) != vf[i]->forminsidepos){
return false;
}
}
return true;
}
};
/*
八叉树节点
init:初始化八叉树
*/
struct Node{
Node* np[8];
bool isfull; //该节点被填充
bool isempty; //该节点没有被填充
bool isdiv; //该节点部分被填充
double xmin,ymin,zmin,length;
int depth;
bool inside[27];//构成空间的27个顶点是否都在物体内部
Object* oo; //物体(子长方体仍然使用不变的Object,即物体面片不会被分割)
void init(Object* o,double x,double y,double z,double l,int d);
};
#endif
――――――――――――――
2、octtree.cpp:
#include <iostream>
using namespace std;
#include "octtree.h"
const int MAXDEP = 3;
void Node::init(Object* o,double x,double y,double z,double l,int d){
//初始化
for(int m = 0;m < 8;m++){
np[m] = NULL;
}
isfull = false;
isempty = false;
isdiv = false;
//分到了极限
if(d > MAXDEP){
isfull = true;
oo = o;
xmin = x;
ymin = y;
zmin = z;
length = l;
depth = d;
}
//能继续分或者是空
else{
oo = o;
xmin = x;
ymin = y;
zmin = z;
length = l;
depth = d;
int num = 0,lentmp = length/2;
Point ptmp;
//考虑构成八叉树的各个立方体的27个顶点
for(int i = 0;i < 3;i++){
for(int j = 0;j < 3;j++){
for(int k = 0;k < 3;k++){
ptmp.setPoint(xmin+i*lentmp,ymin+j*lentmp,zmin+k*lentmp);
inside[num] = oo->isInside(&ptmp);
num++;
}
}
}
//对于每个多变型考虑情况
//1
isempty = true;
if(inside[0] && inside[1] && inside[3] && inside[4]
&& inside[9] && inside[10] && inside[12] && inside[13]){
isempty = false;
isfull = true;
np[0] = NULL;
}
else if(inside[0] || inside[1] || inside[3] || inside[4]
|| inside[9] || inside[10] || inside[12] || inside[13]){
isempty = false;
np[0] = new Node();
np[0]->init(o,xmin,ymin,zmin,length/2,d+1);
}
//2
if(inside[18] && inside[19] && inside[21] && inside[22]
&& inside[9] && inside[10] && inside[12] && inside[13]){
isempty = false;
isfull = true;
np[1] = NULL;
}
else if(inside[18] || inside[19] || inside[21] || inside[22]
|| inside[9] || inside[10] || inside[12] || inside[13]){
isempty = false;
np[1] = new Node();
np[1]->init(o,xmin+length/2,ymin,zmin,length/2,d+1);
}
//3
if(inside[6] && inside[7] && inside[3] && inside[4]
&& inside[15] && inside[16] && inside[12] && inside[13]){
isempty = false;
isfull = true;
np[2] = NULL;
}
else if(inside[6] || inside[7] || inside[3] || inside[4]
|| inside[15] || inside[16] || inside[12] || inside[13]){
isempty = false;
np[2] = new Node();
np[2]->init(o,xmin,ymin+length/2,zmin,length/2,d+1);
}
//4
if(inside[15] && inside[16] && inside[24] && inside[25]
&& inside[21] && inside[22] && inside[12] && inside[13]){
isempty = false;
isfull = true;
np[3] = NULL;
}
else if(inside[15] || inside[16] || inside[24] || inside[25]
|| inside[21] || inside[22] || inside[12] || inside[13]){
isempty = false;
np[3] = new Node();
np[3]->init(o,xmin+length/2,ymin+length/2,zmin,length/2,d+1);
}
//5
if(inside[2] && inside[1] && inside[5] && inside[4]
&& inside[11] && inside[10] && inside[14] && inside[13]){
isempty = false;
isfull = true;
np[4] = NULL;
}
else if(inside[2] || inside[1] || inside[5] || inside[4]
|| inside[11] || inside[10] || inside[14] || inside[13]){
isempty = false;
np[4] = new Node();
np[4]->init(o,xmin,ymin,zmin+length/2,length/2,d+1);
}
//6
if(inside[10] && inside[13] && inside[11] && inside[14]
&& inside[19] && inside[20] && inside[22] && inside[23]){
isempty = false;
isfull = true;
np[5] = NULL;
}
else if(inside[10] || inside[13] || inside[11] || inside[14]
|| inside[19] || inside[20] || inside[22] || inside[23]){
isempty = false;
np[5] = new Node();
np[5]->init(o,xmin+length/2,ymin,zmin+length/2,length/2,d+1);
}
//7
if(inside[4] && inside[5] && inside[7] && inside[8]
&& inside[13] && inside[14] && inside[16] && inside[17]){
isempty = false;
isfull = true;
np[6] = NULL;
}
else if(inside[4] || inside[5] || inside[7] || inside[8]
|| inside[13] || inside[14] || inside[16] || inside[17]){
isempty = false;
np[6] = new Node();
np[6]->init(o,xmin,ymin+length/2,zmin+length/2,length/2,d+1);
}
//8
if(inside[13] && inside[13] && inside[16] && inside[17]
&& inside[22] && inside[23] && inside[25] && inside[26]){
isempty = false;
isfull = true;
np[7] = NULL;
}
else if(inside[13] || inside[13] || inside[16] || inside[17]
|| inside[22] || inside[23] || inside[25] || inside[26]){
isempty = false;
np[7] = new Node();
np[7]->init(o,xmin+length/2,ymin+length/2,zmin+length/2,length/2,d+1);
}
if(isempty == false)isdiv = true;
}
}
/*end of node*/
―――――――――――――――――――
3、main.cpp:
/*
文件名:main.cpp
功能:测试八叉树,单击改变显示模式
*/
#include <iostream>
#include <cstdlib>
#include <stack>
using namespace std;
#include "GL/glut.h"
#include "octtree.h"
enum STATUS {DRAW_ALL=0,DRAW_POINT,DRAW_CUBE};
Point parray[6];
Face face[8];
Object o;
Node top;
int status;
//定义函数
void init();
void display();
void mouse(int button,int state,int x,int y);
void initdata();
void idle();
void destory();
int main(int argc,char ** argv){
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
glutInitWindowSize(800,600);
glutInitWindowPosition(100,100);
glutCreateWindow("octtree");
init();
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutMainLoop();
destory();
return 0;
}
void init(){
initdata();
//opengl
glClearColor(0,0,0,0);
}
void display(){
glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT);
glLoadIdentity ();
gluLookAt(0,0,200,0,0,0,0,1,0);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-100,100,-100,100,50,300);
int i,j;
switch(status){
case DRAW_ALL://只是画线轮廓
glColor3f(1,1,1);
for(i = 0;i < 5;i++){
for(j = i+1;j <6;j++){
glBegin(GL_LINES);
glVertex3f(parray[i].x,parray[i].y,parray[i].z);
glVertex3f(parray[j].x,parray[j].y,parray[j].z);
glEnd();
}
}
break;
case DRAW_POINT://把分成的多边形的每一个顶点都画出来
{
glColor3f(1,1,1);
glBegin(GL_POINTS);
stack<Node*> no;
no.push(&top);
while(!no.empty()){
Node* tmp = no.top();
no.pop();
if(tmp == NULL)continue;
if(tmp->isfull){
glVertex3f(tmp->xmin+tmp->length,tmp->ymin+tmp->length,tmp->zmin+tmp->length);
glVertex3f(tmp->xmin+tmp->length,tmp->ymin+tmp->length,tmp->zmin);
glVertex3f(tmp->xmin+tmp->length,tmp->ymin,tmp->zmin+tmp->length);
glVertex3f(tmp->xmin+tmp->length,tmp->ymin,tmp->zmin);
glVertex3f(tmp->xmin,tmp->ymin+tmp->length,tmp->zmin+tmp->length);
glVertex3f(tmp->xmin,tmp->ymin+tmp->length,tmp->zmin);
glVertex3f(tmp->xmin,tmp->ymin,tmp->zmin+tmp->length);
glVertex3f(tmp->xmin,tmp->ymin,tmp->zmin);
}
else if(tmp->isempty){
}
else{
for(int i = 0;i < 8;i++){
no.push(tmp->np[i]);
}
}
}
glEnd();
}
break;
case DRAW_CUBE://把分成的多边形都画出来
{
glColor3f(1,1,1);
glBegin(GL_QUADS);
stack<Node*> no;
no.push(&top);
while(!no.empty()){
Node* tmp = no.top();
no.pop();
if(tmp == NULL)continue;
if(tmp->isfull){
glVertex3f(tmp->xmin+tmp->length,tmp->ymin+tmp->length,tmp->zmin+tmp->length);
glVertex3f(tmp->xmin+tmp->length,tmp->ymin+tmp->length,tmp->zmin);
glVertex3f(tmp->xmin+tmp->length,tmp->ymin,tmp->zmin+tmp->length);
glVertex3f(tmp->xmin+tmp->length,tmp->ymin,tmp->zmin);
glVertex3f(tmp->xmin,tmp->ymin+tmp->length,tmp->zmin+tmp->length);
glVertex3f(tmp->xmin,tmp->ymin+tmp->length,tmp->zmin);
glVertex3f(tmp->xmin,tmp->ymin,tmp->zmin+tmp->length);
glVertex3f(tmp->xmin,tmp->ymin,tmp->zmin);
}
else if(tmp->isempty){
}
else{
for(int i = 0;i < 8;i++){
no.push(tmp->np[i]);
}
}
}
glEnd();
}
break;
}
glutSwapBuffers();
}
void mouse(int button,int state,int x,int y){
cout << button << ' ' << state << ' ' << x << ' ' << y << endl;
if(state ==0){
status++;
status%=3;
glutPostRedisplay();
}
}
void initdata(){
//point
parray[0].setPoint(50,50,0);
parray[1].setPoint(50,50,100);
parray[2].setPoint(50,0,50);
parray[3].setPoint(50,100,50);
parray[4].setPoint(0,50,50);
parray[5].setPoint(100,50,50);
//~point
//face1
face[0].num = 3;
face[0].vp = new Point*[3];
face[0].vp[0] = parray;
face[0].vp[1] = parray+2;
face[0].vp[2] = parray+5;
face[0].form.setFormula(face[0].vp);
face[1].num = 3;
face[1].vp = new Point*[3];
face[1].vp[0] = parray;
face[1].vp[1] = parray+2;
face[1].vp[2] = parray+4;
face[1].form.setFormula(face[1].vp);
face[2].num = 3;
face[2].vp = new Point*[3];
face[2].vp[0] = parray;
face[2].vp[1] = parray+3;
face[2].vp[2] = parray+4;
face[2].form.setFormula(face[2].vp);
face[3].num = 3;
face[3].vp = new Point*[3];
face[3].vp[0] = parray;
face[3].vp[1] = parray+3;
face[3].vp[2] = parray+5;
face[3].form.setFormula(face[3].vp);
face[4].num = 3;
face[4].vp = new Point*[3];
face[4].vp[0] = parray+1;
face[4].vp[1] = parray+2;
face[4].vp[2] = parray+5;
face[4].form.setFormula(face[4].vp);
face[5].num = 3;
face[5].vp = new Point*[3];
face[5].vp[0] = parray+1;
face[5].vp[1] = parray+2;
face[5].vp[2] = parray+4;
face[5].form.setFormula(face[5].vp);
face[6].num = 3;
face[6].vp = new Point*[3];
face[6].vp[0] = parray+1;
face[6].vp[1] = parray+3;
face[6].vp[2] = parray+5;
face[6].form.setFormula(face[6].vp);
face[7].num = 3;
face[7].vp = new Point*[3];
face[7].vp[0] = parray+1;
face[7].vp[1] = parray+3;
face[7].vp[2] = parray+4;
face[7].form.setFormula(face[7].vp);
//~face init over
int i,j;
//object init begin
o.num = 8;
o.vf = new Face*[8];
for(i = 0;i < 8;i++){
o.vf[i] = &(face[i]);
}
//init frompos
//the 7th face
for(j = 0;j < o.vf[0]->num;j++){
if(o.vf[7]->hasPoint(o.vf[0]->vp[j]))continue;
else{
o.vf[7]->forminsidepos = o.vf[7]->form.formpos(o.vf[0]->vp[j]);
break;
}
}
//计算某个面A的相邻面B的点在A的哪侧,从而可确定内外侧。
for(i = 0;i < 7;i++){
for(j = 0;j < o.vf[i]->num;j++){
if(o.vf[i]->hasPoint(o.vf[i+1]->vp[j]))continue;
else{
o.vf[i]->forminsidepos = o.vf[i]->form.formpos(o.vf[i+1]->vp[j]);
break;
}
}
}
cout << "object init over" << endl;
for(i = 0;i < o.num;i++){
cout << "face" << i << endl;
for(j = 0;j < o.vf[i]->num;j++){
cout << "num of point" << endl;
cout << o.vf[i]->vp[j]->x <<" "<< o.vf[i]->vp[j]->y << " " << o.vf[i]->vp[j]->z << endl;
}
cout << "formulation" << endl;
cout << o.vf[i]->form.a
<<" "<< o.vf[i]->form.b
<<" "<< o.vf[i]->form.c
<<" "<< o.vf[i]->form.d
<<endl;
cout << o.vf[i]->forminsidepos << endl;
}
//~object init over
//ok
//node init
top.init(&o,0,0,0,100,0);
//~node init over
cout << "initover" << endl;
stack<Node*> no;
no.push(&top);
while(!no.empty()){//输出显示子节点
Node* tmp = no.top();
no.pop();
if(tmp == NULL)continue;
if(tmp->isfull){
cout << "full" << endl;
cout << tmp->xmin << ' ' << tmp->ymin << ' ' << tmp->zmin << ' ' << tmp->length << endl;
}
else if(tmp->isempty){
cout << "empty" << endl;
cout << tmp->xmin << ' ' << tmp->ymin << ' ' << tmp->zmin << ' ' << tmp->length << endl;
}
else{
cout << "isdiv" << endl;
cout << tmp->xmin << ' ' << tmp->ymin << ' ' << tmp->zmin << ' ' << tmp->length << endl;
for(int i = 0;i < 8;i++){
no.push(tmp->np[i]);
}
}
}
}
void destory(){
stack<Node*> no;
no.push(&top);
while(!no.empty()){
Node* tmp = no.top();
no.pop();
if(tmp == NULL)continue;
if(tmp->isfull){
delete tmp;
}
else if(tmp->isempty){
delete tmp;
}
else{
for(int i = 0;i < 8;i++){
no.push(tmp->np[i]);
}
delete tmp;
}
}
};