一、前言
在碰撞检测算法中,最为重要的理论基础都是凸包,在游戏领域也经常用到碰撞的思想,在三维几何算法中也经常用到,凸包可以视为最小最紧凑的包围体,很多碰撞的检测算法中,如a物体与b物体是否发生碰撞,以便做出不同的功能,如子弹是否打中目标等。多种凸包求解算法中,比较经典的两种算法莫过于:Andrew算法和Quickhull算法了。本人在三维几何模型算法处理过程中就需要手写凸包算法,顺便记录下来,本文实现的是Andrew算法。
二、算法原理
算法过程如图所示:
- 先生成随机点
- 将随机点根据x轴排序
- 第一次遍历将上半部分凸包找到
- 第二次遍历将下半部分凸包找到
- 按照瞬时间或者逆时针的方式排列好
- 以上部分凸包为例:
– 最初,将最靠近左侧两点放入集合中,依次对剩余的点进行处理,待确认后逐个加入到集合中。处理过程为,假设A,B为初始点,下一点为C,若C位于AB的右侧,则直接添加到集合中,若C位于AB左侧,则将B弹出,将C放入集合中,如图找到ACDEF,当前点为G,显然G在EF的左侧,F弹出,G在DE的左侧,E弹出,G在CD的右侧,则G添加到集合中,形成ACDG,如果当前集合个数为1时,则直接入集合中,如B,如C(将B弹出后,集合个数为1),直到遍历完最后一个元素,算法停止
凸包的下半部分,也类似,只需要判断相反的方向即可
三、算法实现
- 1、生成随机数,保存到randText.txt文件中,并读入存入vector中
void RandDataLists()
{
srand((unsigned)time(NULL));
int Y = 100;
int X = 0;
int temps[100];
int i = 0;
int temp;
while (i < 100)
{
temp = rand() % (Y - X + 1) + X;
if (temp > 100 || temp < 0)
{
cout << "error" << endl;
}
temps[i] = temp;
i++;
}
using namespace std;
ofstream fout("randText.txt");
cout << "i=" << i << endl;
for (i = 0; i < 100; i++)
{
cout << temps[i] << " ";
fout << temps[i] << endl;
}
}
void GetRandPoints(vector<IntPoint>&ls)
{
vector<IntPoint>&pLists=ls;
using namespace std;
ifstream fin("randText.txt");
for (int i = 0; i < 50; i++)
{
int x, y;
fin >> x >> y;
pLists.push_back(IntPoint(x, y));
//cout << "(" << x << "," << y << ")" << endl;
}
}
- 2、随机点根据x轴排序
void sortLists(set<IntPoint, comp>&ps)
{
vector<IntPoint>lists;
GetRandPoints(lists);
set<IntPoint, comp>&setPoints=ps;
for (auto item : lists)
{
setPoints.insert(item);
}
}
- 遍历获取凸包上半部分点
void UpHullSet(set<IntPoint, comp>& setPoints, stack<IntPoint>&hullStack)
{
for (auto item : setPoints)
{
if (hullStack.size() < 2)
{
hullStack.push(item);
continue;
}
while (true)
{
IntPoint pre, next;
next = hullStack.top();
hullStack.pop();
pre = hullStack.top();
IntPoint AB = next - pre;
IntPoint AC = item - pre;
if ((AB CROSS AC) > 0)
{
if (hullStack.size() == 1)
{
hullStack.push(item);
break;
}
}
else
{
hullStack.push(next);
hullStack.push(item);
break;
}
}
}
}
- 遍历获取凸包下半部分点
void LowHullSet(set<IntPoint,comp>& setPoints,stack<IntPoint>&hullStack)
{
for (auto item : setPoints)
{
if (hullStack.size() < 2)
{
hullStack.push(item);
continue;
}
while (true)
{
IntPoint pre, next;
next = hullStack.top();
hullStack.pop();
pre = hullStack.top();
IntPoint AB = next - pre;
IntPoint AC = item - pre;
if ((AB CROSS AC) < 0)
{
if (hullStack.size() == 1)
{
hullStack.push(item);
break;
}
}
else
{
hullStack.push(next);
hullStack.push(item);
break;
}
}
}
}
- 客户端代码
int main()
{
//offsetTest();
//RandDataLists();
set<IntPoint, comp>setPoints;
sortLists(setPoints);
stack<IntPoint>upStack, lowStack;
UpHullSet(setPoints, upStack);
LowHullSet(setPoints,lowStack);
getchar();
return 0;
}
四、总结
算法过程相对比较简单,在2D空间效果良好,但在3D空间中有短板,计算机图形学中经常用到常规的算法,通过实现这些算法,也给自己打下基础,fighting!