原理:凸包算法(Graham扫描法)_よろしくお願いします-CSDN博客_graham扫描法
/**
* @brief :获取平面点集的凸包,采用GrahamScan计算凸包
* @param[in] :points:输入的点集,
* @param[out] :
* @return :返回凸包的点集,点集是逆时针排序。
*/
CUBECOM_API vector<iCoord2d> GetConvexHullByGrahamScan(vector<iCoord2d>& points);
//获取平面向量叉积
double GetTwoVectorMulti(const iCoord2d &fpt, const iCoord2d &spt, const iCoord2d &oriPt)
{
return (fpt[0] - oriPt[0]) * (spt[1] - oriPt[1]) - (spt[0] - oriPt[0]) * (fpt[1]-oriPt[1]);
}
CUBECOM_API vector<iCoord2d> CubeHelper::GetConvexHullByGrahamScan(vector<iCoord2d>& points)
{
vector<iCoord2d> pointArray;
size_t ptSize = points.size();
size_t temp = 0;
//获取最下而且偏左的点
for (size_t i = 1; i < ptSize; ++i)
{
if (points[i][1] < points[temp][1] || ((points[i][1] == points[temp][1]) && (points[i][0] < points[temp][0])))
{
temp = i;
}
}
//将得到的点作为第一个点
std::swap(points[0], points[temp]);
//按极角从小到大排列,极角相同则距离偏短的进行排序
iCoord2d tempPt = points[0];
std::sort(points.begin()+1, points.end(), [&tempPt](const iCoord2d &fpt, const iCoord2d &spt)
{
iVec2d fvec(fpt[0] - tempPt[0], fpt[1] - tempPt[1]);
iVec2d svec(spt[0] - tempPt[0], spt[1] - tempPt[1]);
//判断哪一条向量极角更大
if (fvec.SignZCross(svec) > 0) return true;
//共线
if (fvec.SignZCross(svec) == 0 && fpt.DistPtPt(tempPt) < spt.DistPtPt(tempPt)) return true;
return false;
});
//存前三个点入栈
for (int i = 0; i < 3; ++i)
pointArray.emplace_back(points[i]);
//获取点集合
size_t top = 2;
for (size_t i = 3; i < ptSize;++i)
{
//判断
while (top > 1 && CubeHelper::GetTwoVectorMulti(pointArray[top], points[i], pointArray[top - 1]) < 0)
top--;
//如果top变化,说明points[i]这个点才是凸点,栈最后的几个点要出栈。
if (top != (pointArray.size() - 1))
{
size_t j = pointArray.size() - 1;
for (; j > top; --j)
pointArray.pop_back();
}
//将当前点入栈,因为极角排序的原因,过程中会将不符合的点去掉,所以当前的点一定会入栈(注意是极角排序关系)。
pointArray.emplace_back(points[i]);
top = pointArray.size()-1;
}
return pointArray;
}