您的位置:首页 > 其它

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

2014-06-30 16:44 295 查看
八叉树判断子长方体的8个点是否在物体内,可判断这8个点是不是在整个物体所有面的内侧。注:(1)但如果物体不是凸壳呢,而是凹体呢???可能某个点在一个面外,但它仍在物体内。??????????(2)每个子长方体里的Object* oo;对象都是该物体的完整模型,该物体的面片并不会被分解。 参考源代码如下:(octtree.h、octtree.cpp、main.cpp)下载地址:http://download.csdn.net/download/gdf420/28747521、 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;
       }
    }
};


http://blog.csdn.net/tmljs1988/article/details/7995088
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: