分享给有需要的人,代码质量勿喷。
首先是需要用到的结构体和函数
//自定义结构体
struct xjPoint
{
double x;
double y;
double z;
};
/*返回 两点的平面距离*/
double xjGet2DistancePP(xjPoint p1, xjPoint p2)
{
return (sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)));
}
/*返回 两个向量的叉积(p0是公共点)*/
double xjGetCrossProduct(xjPoint p1, xjPoint p2, xjPoint p0)
{
return ((p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y));
}
---------------第一种写法------------
/*方式一、返回 凸包点集,通过 Graham Scan 方法*/
QList<xjPoint> xjGetConvexHullByGrahamScan(QList<xjPoint> listPoint)
{
QList<xjPoint> xjListResult;
int i = 0, j = 0, k = 0;
xjPoint tmP = listPoint[0];
//排序 找到最下且偏左的点
for (i = 1; i < listPoint.size(); i++)
{
if ((listPoint[i].y < tmP.y) || ((listPoint[i].y == tmP.y) && (listPoint[i].x < tmP.x)))
{
tmP = listPoint[i];
k = i;
}
}
listPoint[k] = listPoint[0];
listPoint[0] = tmP;
//排序 按极角从小到大,距离从近到远
for (i = 1; i < listPoint.size(); i++)
{
k = i;
for (j = i + 1; j < listPoint.size(); j++)
{
double cross = xjGetCrossProduct(listPoint[j], listPoint[k], listPoint[0]);
double disance_j = xjGet2DistancePP(listPoint[0], listPoint[j]);
double disance_k = xjGet2DistancePP(listPoint[0], listPoint[k]);
if ((cross > 0) || ((cross == 0) && (disance_j < disance_k)))
{
k = j;//k保存极角最小的那个点,或者相同距离原点最近
}
}
tmP = listPoint[i];
listPoint[i] = listPoint[k];
listPoint[k] = tmP;
}
//添加第一、二个凸包点
xjListResult.append(listPoint[0]);
xjListResult.append(listPoint[1]);
////遍历
for (i = 2; i < listPoint.size(); ++i)
{
for (j = i + 1; j < listPoint.size(); ++j)
{
if (xjGetCrossProduct(listPoint[i], listPoint[j], xjListResult[xjListResult.size() - 1]) < 0)
{
i = j;
}
}
xjListResult.append(listPoint[i]);
}
return xjListResult;
}
-----------第二种写法-----------
/*方式二:返回 凸包点集,通过 Graham Scan 方法*/
QList<xjPoint> xjGetConvexHull(QList<xjPoint> list)
{
QList<xjPoint> newList;
/*最下偏左的点 肯定是凸包点*/
qSort(list.begin(), list.end(), [](const xjPoint &a, const xjPoint &b)
{
if (a.y == b.y)
return a.x < b.x;
else
return a.y < b.y;
});
xjPoint p0 = list.at(0);
//临时点集 坐标偏移
QList<xjPoint> tempList;
for (int i = 0; i < list.size(); i++)
{
xjPoint p;
p.x = list.at(i).x - p0.x;
p.y = list.at(i).y - p0.y;
p.z = list.at(i).z - p0.z;
tempList.append(p);
}
newList.append(tempList.at(0));
//按极角从小到大,距离偏短进行排序
qSort(tempList.begin(), tempList.end(), [](const xjPoint &a, const xjPoint &b)
{
if (atan2(a.y, a.x) != atan2(b.y, b.x))
return (atan2(a.y, a.x)) < (atan2(b.y, b.x));
return a.x < b.x;
});
xjPoint p1 = tempList.at(1);
newList.append(p1);
//获取凸包点
for (int j = 2; j < tempList.size(); j++)
{
for (int k = j + 1; k < tempList.size(); k++)
{
double xjCross = xjGetCrossProduct(tempList.at(j), tempList.at(k), newList.at(newList.size() - 1));
if (xjCross < 0)
{
j = k;
}
}
newList.append(tempList.at(j));
}
//回复坐标
for (int i = 0; i < newList.size(); i++)
{
xjPoint p = newList.at(i);
p.x += p0.x;
p.y += p0.y;
p.z += p0.z;
newList.replace(i, p);
}
return newList;
}