八叉树 判断长立方体是否在物体内???????

八叉树

判断子长方体的8个点是否在物体内,可判断这8个点是不是在整个物体所有面的内侧。

 

注:

1但如果物体不是凸壳呢,而是凹体呢???可能某个点在一个面外,但它仍在物体内。??????????

2)每个子长方体里的Object* oo;对象都是该物体的完整模型,该物体的面片并不会被分解。

 

参考源代码如下:(octtree.hocttree.cppmain.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

―――――――――――――――

2octtree.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*/

―――――――――――――――――――

3main.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;

       }

    }

};

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值