C++/Qt:凸包

 分享给有需要的人,代码质量勿喷。

首先是需要用到的结构体和函数

//自定义结构体
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;
 }
发布了63 篇原创文章 · 获赞 58 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/xinjiang666/article/details/103444866
今日推荐