本文轮廓凸包寻找主要是基于graham算法来实现的,具体的理论知识大家可以网上搜索下一大堆,这里盗用下他人的一张比较好描述该算法的图片:
下面直接上代码:
struct ptInfo
{
point_t* pt;
int size;
};
//符号函数
int signPoint(float x);
//计算叉积
int crossPoint(const point_t a, const point_t b, const point_t c);
//比较两点的位置
int cmpPoint(const point_t a, const point_t b);
//通过两点的叉积来判别两者的相对位置
int compare(const point_t a, const point_t b, const point_t c);
//获取轮廓凸包
void get_convex_hull(point_t* p, point_t* pt, const int num, int* n);
#include "convxhull.h"
static int size = 0;
//计算两点之间的距离
int disPoint(const point_t a, const point_t b)
{
return common_sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y)*(a.y - b.y));
}
//符号函数
int signPoint(int x)
{
return x == 0 ? 0 : (x > 0 ? 1 : -1);
}
//计算叉积
int crossPoint(const point_t a, const point_t b, const point_t c)
{
//int temo = (b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y);
return ((b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y));
}
//比较两点的位置
int cmpPoint(const point_t a, const point_t b)
{
return (a.x < b.x || (signPoint(a.x - b.x) == 0 && a.y < b.y));
}
//通过两点的叉积来判别两者的相对位置
int compare(const point_t a, const point_t b, const point_t c)
{
int sg = signPoint(crossPoint(a, b, c));
if (sg != 0)
return sg > 0; //左转;
else //共线;
return disPoint(a, b) < disPoint(a, c);
}
//入栈
void push(point_t* S, point_t pt)
{
S[size++] = pt;
}
//出栈
void pop(point_t* S)
{
S[--size];
}
//交换两点
void swap(point_t* p, int x, int y)
{
point_t pt = p[x];
p[x] = p[y];
p[y] = pt;
}
void quicksort(point_t *p,int n)
{
int i, j, k = 0;
point_t temp;
for (i = 1; i < n - 1;++i){
k = i;
for (j = i + 1; j < n - 1; ++j){
if (compare(p[0], p[j], p[i])){
temp = p[i];
p[i] = p[j];
p[j] = temp;
}
}
}
}
//获取轮廓凸包
void get_convex_hull(point_t* p, point_t* pt, const int num, int* n)
{
size = 0;//因为是全局变量,所以每次进来要记得清零,不然会导致错误
//寻找x坐标最小的点
int min = -1;
for (int j = 0; j < num; j++)
{
if (min == -1 || cmpPoint(p[j], p[min]))
min = j;
}
//将x最小的点存储在第一个位置
if (min != 0)
swap(p,0,min);
//极角快排
//sort(1,num - 1,p);
quicksort(p,num - 1);
push(pt, p[0]);
push(pt, p[1]);
push(pt, p[2]);
//边缘点寻找
for (int i = 3; i < num; i++)
{
//剔除非左转的点
if (crossPoint(pt[size - 2],pt[size - 1], p[i]) < 0)
pop(pt);
push(pt, p[i]);
}
*n = size;
}
代码运行结果: