几种空间分割算法研究之bsp

BSP:

二叉分割树,是一种分割场景的方法,下面代码是BSP树一种实现可运行:

运行例子中,将定义的16个空间面,分割为一个深度是3的BSP树,上图显示的是运行结果:

#include "stdafx.h"

#include <map>

#include <vector>

#include <iostream>

using namespace std;

//定义空间的点结构

struct point

{

float x,y,z;

point():x(0.0f),y(0.0f),z(0.0f){};

point(float a,float b,float
c):x(a),y(b),z(c){}

void operator += (int n)

{

x += n;

y += n;

z += n;

}

void operator = (point& p)

{

memcpy(this,(void*)&p,sizeof(*this));

}

};

//定义空间的面结构

struct face

{

point P[3];

void operator +=(int n)

{

P[0] += n;

P[1] += n;

P[2] += n;

}

};

//定义包围盒结构

struct BBox

{

point Min;

point Max;

BBox():Min(),Max(){}

};

enum EAxis

{//沿的轴枚举

Axis_X,

Axis_Y,

Axis_Z,

};

//树节点的定义

struct TreeNode

{

TreeNode():box(),nDepth(0),pLChild(NULL),pRChild(NULL),Axis(Axis_X),Split(0.0f){vFaceId.reserve(16);}

int nDepth;

TreeNode* pLChild;

TreeNode* pRChild;

std::vector<int> vFaceId;

int Axis;

BBox box;

float Split;

};

//存储空间的面

std::map<int,face> m_mFace;

//通过面ID获取面的地址

face* GetFaceByID(int nID)

{

std::map<int,face>::iterator itr
= m_mFace.find(nID);

if (itr != m_mFace.end() )

{

return
&(m_mFace[nID]);

}

return NULL;

}

//BSP类的定义实现

class BspTree

{

public:

BspTree():m_pRoot(NULL){};

~BspTree()

{

if
(m_pRoot)

{

DeleteNode(m_pRoot);

}

}

//初始化树根

void InitTreeRoot(TreeNode *pNode);

//释放整个树的资源

void DeleteNode(TreeNode * pNode);

//生成AABB包围盒

void BuildAABB(TreeNode * pNode);

//切分整个空间

void SplitSpace(TreeNode* pRoot,int
nAxis,int ndepth);

//切分面

void SplitFace( int nFaceId, float
fSplit, int nAxis, int* pLeftNum, int* pRightNum, int* pBothNum );

//遍历整个树

void ErgodicTree(TreeNode * pNode);

protected:

private:

TreeNode *m_pRoot;

};

void BspTree::InitTreeRoot(TreeNode *pNode)

{

if (pNode == NULL)

return;

m_pRoot = pNode;

}

void BspTree::DeleteNode(TreeNode * pNode)

{

if (pNode == NULL)

return;

DeleteNode(pNode->pLChild);

DeleteNode(pNode->pRChild);

delete pNode;

}

//遍历整个树

void BspTree::ErgodicTree(TreeNode * pNode)

{

if (pNode == NULL)

return;

ErgodicTree(pNode->pLChild);

cout<<"节点深度:
"<<pNode->nDepth<<"含有多少个面: "<<pNode->vFaceId.size();

switch (pNode->Axis)

{

case Axis_X:

{

cout<<" 沿X轴分割"<<"分割点是: x ="<<pNode->Split<<endl;

break;

}

case Axis_Y:

{

cout<<" 沿Y轴分割"<<"分割点是: y ="<<pNode->Split<<endl;

break;

}

case Axis_Z:

{

cout<<" 沿Z轴分割"<<"分割点是: z ="<<pNode->Split<<endl;

break;

}

}

ErgodicTree(pNode->pRChild);

}

void BspTree::BuildAABB(TreeNode * pNode)

{

if(!pNode)

return;

point Min(1000000,1000000,1000000);

point
Max(-1000000,-1000000,-1000000);

for(int n = 0; n <
pNode->vFaceId.size(); ++n)

{

face *pFa =
GetFaceByID(n);

if (pFa ==
NULL)

continue;

for(int m = 0;
m < 3; ++m)

{

if (pFa->P[m].x > Max.x)

Max.x = pFa->P[m].x;

if (pFa->P[m].y > Max.y)

Max.y = pFa->P[m].y;

if (pFa->P[m].z > Max.z)

Max.z = pFa->P[m].z;

if (pFa->P[m].x < Min.x)

Min.x = pFa->P[m].x;

if (pFa->P[m].y < Min.y)

Min.y = pFa->P[m].y;

if (pFa->P[m].z < Min.z)

Min.z = pFa->P[m].z;

}

}

pNode->box.Max = Max;

pNode->box.Min = Min;

}

int CompareFloat(float a,float b,float fOff)

{

if (abs(a - b) < fOff)

return 0;

if ( a > b)

return 1;

else

return -1;

}

void BspTree::SplitFace( int nFaceId, float fSplit, int nAxis,
int* pLeftNum, int* pRightNum, int* pBothNum )

{

face* pFace = GetFaceByID(nFaceId);

int nLeftCount = 0;

int nRightCount = 0;

int nBothCount = 0;

float t[3];

switch( nAxis )

{

case Axis_X:

t[0] =
pFace->P[0].x;

t[1] =
pFace->P[1].x;

t[2] =
pFace->P[2].x;

break;

case Axis_Y:

t[0] =
pFace->P[0].y;

t[1] =
pFace->P[1].y;

t[2] =
pFace->P[2].y;

break;

case Axis_Z:

t[0] =
pFace->P[0].z;

t[1] =
pFace->P[1].z;

t[2] =
pFace->P[2].z;

break;

}

for( int i = 0; i < 3; i++ )

{

int c =
CompareFloat( t[i], fSplit ,0.001f);

if( c < 0
)            // 左边

nLeftCount++;

else if( c >
0 )   // 右边

nRightCount++;

else              
// 正中间

nBothCount++;

}

*pLeftNum = nLeftCount;

*pRightNum = nRightCount;

*pBothNum = nBothCount;

}

void BspTree::SplitSpace(TreeNode* pRoot,int nAxis,int
ndepth)

{

if(!pRoot)

return;

pRoot->nDepth = ndepth;

pRoot->Axis = nAxis;

if (pRoot->vFaceId.size() < 3 ||
ndepth > 2)

{

pRoot->pLChild = NULL;

pRoot->pRChild = NULL;

return;

}

pRoot->pLChild = new TreeNode;

pRoot->pRChild = new TreeNode;

pRoot->pLChild->box.Max =
pRoot->box.Max;

pRoot->pLChild->box.Min =
pRoot->box.Min;

pRoot->pRChild->box.Max =
pRoot->box.Max;

pRoot->pRChild->box.Min =
pRoot->box.Min;

nAxis = (int)Axis_X;

float XLength = pRoot->box.Max.x -
pRoot->box.Min.x;

float YLength = pRoot->box.Max.y -
pRoot->box.Min.y;

float ZLength = pRoot->box.Max.z -
pRoot->box.Min.z;

if (YLength > XLength)

{

nAxis =
Axis_Y;

XLength =
YLength;

}

if (ZLength > XLength)

{

nAxis =
Axis_Z;

}

float fslit = 0.0f;

switch (nAxis)

{

case Axis_X:

{

fslit = (pRoot->box.Max.x + pRoot->box.Min.x)/2.0;

pRoot->pLChild->box.Max.x = fslit;

pRoot->pRChild->box.Min.x = fslit;

}break;

case Axis_Y:

{

fslit = (pRoot->box.Max.y + pRoot->box.Min.y)/2.0;

pRoot->pLChild->box.Max.y = fslit;

pRoot->pRChild->box.Min.y = fslit;

}break;

case Axis_Z:

{

fslit = (pRoot->box.Max.z + pRoot->box.Min.z)/2.0;

pRoot->pLChild->box.Max.z = fslit;

pRoot->pRChild->box.Min.z = fslit;

}break;

}

pRoot->Split = fslit;

int nSize =
pRoot->vFaceId.size();

int
nLeftCount,nRightCount,nBothCount;

for (int n = 0; n < nSize; ++n)

{

SplitFace(pRoot->vFaceId.at(n),fslit,nAxis,&nLeftCount,&nRightCount,&nBothCount);

// 如果左边有

if( nLeftCount
> 0 || nBothCount > 0 )

pRoot->pLChild->vFaceId.push_back( pRoot->vFaceId.at(n) );

if( nRightCount
> 0 || nBothCount > 0 )

pRoot->pRChild->vFaceId.push_back( pRoot->vFaceId.at(n) );

}

pRoot->vFaceId.clear();

// 递归

SplitSpace( pRoot->pLChild, nAxis ,
ndepth+1);

SplitSpace( pRoot->pRChild, nAxis ,
ndepth+1);

}

int _tmain(int argc, _TCHAR* argv[])

{

BspTree bspTree;

TreeNode *pRoot = new TreeNode;

face fa;

fa.P[0].x = -10;fa.P[0].y =
-10;fa.P[0].z = -10;

fa.P[1].x = 2;fa.P[1].y = 2;fa.P[1].z =
2;

fa.P[2].x = 5;fa.P[2].y = 5;fa.P[2].z =
5;

for (int n = 0; n < 16; ++n)

{

if (n % 5 ==
0)

fa += 2*(-n);

else

fa += 2*n;

m_mFace[n] =
fa;

pRoot->vFaceId.push_back(n);

}

bspTree.InitTreeRoot(pRoot);

bspTree.BuildAABB(pRoot);

bspTree.SplitSpace(pRoot,0,0);

bspTree.ErgodicTree(pRoot);

getchar();

return 0;}

几种空间分割算法研究之bsp,布布扣,bubuko.com

时间: 2024-08-05 06:42:17

几种空间分割算法研究之bsp的相关文章

几种搜索引擎算法研究

http://www.cnblogs.com/zxjyuan/archive/2010/01/06/1640136.html 1.引言 万维网WWW(World Wide Web)是一个巨大的,分布全球的信息服务中心,正在以飞快的速度扩展.1998年WWW上拥有约3.5亿个文档[14],每天增加约1百万的文档[6],不到9个月的时间文档总数就会翻一番[14].WEB上的文档和传统的文档比较,有很多新的特点,它们是分布的,异构的,无结构或者半结构的,这就对传统信息检索技术提出了新的挑战. 传统的W

八种排序算法

最近一段时间自己在研究各种排序算法,于是自己写了一个八种排序算法的集合: /************************************************************************* > Copyright (c)2014 stay hungry,stay foolish !!! > File Name: sort.cpp > Author: kanty > Mail: [email protected] > Created Time:

基本算法研究1-冒泡排序算法测试

基本算法研究1-冒泡排序算法测试 1.经典冒泡排序法基本原理 先看一个动态图,感觉比较形象: 冒泡排序(Bubble Sort)是一种简单的排序算法.默认是从小到大排序,即把最大的数据排在最后,相当于每次把最大数据像气泡一样浮到水面一样.它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.走访数列的工作是重复地进行直到没有再需要交换. 基本步骤: 1.比较相邻的元素.如果第一个比第二个大,就交换他们两个.        2.对每一对相邻元素作同样的工作,从开始第一对

HTML5游戏开发-扫雷及其算法研究

吕蒙曰:士隔三月[1],当刮目相看.所以,在下在这三月中发奋图强,花了约莫8节信息课的时间研究扫雷.呜呼,由于在下才能尚且不足,所以也就只能勉强打过中级难度的吧.不过,一边玩的同时,我还一边对扫雷这个游戏的制做方法构思了一下.所以说,本文中的算法完全是凭借自己对扫雷游戏规则的总结而自行研发出来的,倘若和MS的扫雷玩法有些出入,还望各位看官见谅. [1]出自<孙权劝学>,原文为"士别三日",由于在下这三个月来都不曾发表博客,所以引申到"士隔三月",各位看官

通用高校排课算法研究----3.基于时间片优先级排课算法

通用高校排课算法研究----3.基于时间片优先级排课算法 3   基于时间片优先级排课算法描述与分析 排课问题实质上是时间.教师.班级.教室.课程这五维关系的冲突问题,要合理的解决这个问题首先要了解排课中的一些基本原则以及排课的一些基本要求. 3.1排课中的基本原则 在课程的编排中应遵循一定的规则, 只有按照基本规则来进行课程的编排才能够减少冲突的发生, 这些基本规则主要有以下几条: 1) 同一班级的学生在同一时间(某些特定的选修课时间除外) 不能安排两门课程 2) 同一教师在同一时间不能安排两

通用高校排课算法研究----前言

1   绪 论 1.1课题背景与研究意义 1.2课题的应用领域 1.3 课题的现状 1.4解决NP问题的几种算法及其比较 2   目前流行的几种排课算法的介绍 2.1. 自动排课算法 2.2 基于优先级的排课算法 3   基于时间片优先级排课算法描述与分析 3.1排课中的基本原则 3.2排课的基本要求 3.3基于时间片优先级排课算法描述 3.4算法分析 参 考 资 料 1   绪 论 1课题背景与研究意义 排课问题早在70年代就证明是一个NP完全问题,即算法的计算时间是呈指数增长的,这一论断确立

基础典型算法研究:合并有序数组

做leetcode第二题的时候,发现合并有序数组是一个很有意思的问题,于是,总结如下,部分内容来源于网络各位大神. 第一种方法: 合并调用sort. 即是将两个数组合并在一个数组里面,然后对合并后的数组调用sort函数即可. class Solution: def getArray(self, A, B) : for item in B : A.append(item) A.sort() 第二种方法: 极值插入法. #include <stdio.h> void insert(int *arr

NLTK学习笔记(四):自然语言处理的一些算法研究

自然语言处理中算法设计有两大部分:分而治之 和 转化 思想.一个是将大问题简化为小问题,另一个是将问题抽象化,向向已知转化.前者的例子:归并排序:后者的例子:判断相邻元素是否相同(与排序). 这次总结的自然语言中常用的一些基本算法,算是入个门了. 递归 使用递归速度上会受影响,但是便于理解算法深层嵌套对象.而一些函数式编程语言会将尾递归优化为迭代. 如果要计算n个词有多少种组合方式?按照阶乘定义:n! = n*(n-1)*...*1 def func(wordlist): length = le

图像连通域标记算法研究

把之前一篇记录过的日志贴过来 图像连通域标记算法研究 ConnectedComponent Labeling 最近在研究一篇复杂下背景文字检测的论文. “Detecting Text in Natural Scenes with Stroke Width Transform ” CPVR 2010的文章,它主要探讨利用文字内部笔画宽度一致作为主要线索来检测文字的一个新奇的算法,当然,我不是想讨论文字检测,论文算法实施的过程中有一步涉及到图像连通域标记算法,在这里我遇到了一些问题,查阅了一些相关文