C++/Qt:最小外接矩形

以凸包的某條邊作爲矩形的一條邊,求包圍所有點的面積最小外接矩形。(感覺是對的)下圖中藍色爲凸包,紅色爲MBR。

           

 

分享給有需要的人,代碼質量勿噴。

一、求凸包,返回 xjListCH

參考:凸包

二、MBR中用到的函數

//返回 點與點的平面距離
double TwoDistancePointAndPoint(const xjPoint &p1, const xjPoint &p2)
{
	double x1 = p1.x, y1 = p1.y;
	double x2 = p2.x, y2 = p2.y;

	double dis = sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2));

	return dis;
}

//返回 點(p0)  到線(p1,p2)的距離
double TwoDistancePointAndLine(const xjPoint &p0, const xjPoint &p1,const xjPoint &p2)
{
	double dis12 = TwoDistancePointAndPoint(p1, p2);//線段長度
	double dis01 = TwoDistancePointAndPoint(p0, p1);//p1與p0的距離
	double dis02 = TwoDistancePointAndPoint(p0, p2);//p2與p0的距離
	double HalfC = (dis12 + dis01 + dis02) / 2;// 半周長
	double s = sqrt(HalfC * (HalfC - dis12) * (HalfC - dis01) * (HalfC - dis02));//海倫公式求面積
	double xj2DisPL = 2 * s / dis12;// 返回點到線的距離(利用三角形面積公式求高)

	return xj2DisPL;
}

三、最小外接矩形

/*返回 最小外接矩形點*/
/* xjListCH 凸包點 */
void xjMinimumBoundingRectangle(QList<xjPoint> &xjListMBRpoint, double &length, double &width, QList<xjPoint> xjListCH)
{
	//外接矩形
	QList<xjPoint> xjListCH2;
	int xjPcount = xjListCH.size();
	for (int i = 0; i < xjPcount; i++)
	{
		xjListCH2.append(xjListCH.at(i));
	}
	qSort(xjListCH2.begin(), xjListCH2.end(), [](const xjPoint &a, const xjPoint &b) {return a.x < b.x; });
	double minX = xjListCH2.at(0).x;
	double maxX = xjListCH2.at(xjPcount - 1).x;
	qSort(xjListCH2.begin(), xjListCH2.end(), [](const xjPoint &a, const xjPoint &b) {return a.y < b.y; });
	double minY = xjListCH2.at(0).y;
	double maxY = xjListCH2.at(xjPcount - 1).y;

	//依次判斷
	double minArea = 99999999;
	xjListCH.push_back(xjListCH.at(0));
	for (int a = 0; a < xjListCH.size() - 1; a++)
	{
		xjPoint p0 = xjListCH.at(a);
		xjPoint p1 = xjListCH.at(a + 1);

		if ((p0.y == p1.y)|| (p0.x == p1.x)) // 水平或垂直
		{
			double side1 = maxY - minY;
			double side0 = maxX - minX;
			double xjArea = side0 * side1;

			if (xjArea <= minArea)
			{
				length = max(side0, side1);
				width = min(side0, side1);
				minArea = xjArea;

				//外接矩形四個點
				xjPoint pLB;
				pLB.x = minX;
				pLB.y = minY;
				pLB.z = 0;
				xjPoint pRB;
				pRB.x = maxX;
				pRB.y = minY;
				pRB.z = 0;
				xjPoint pRT;
				pRT.x = maxX;
				pRT.y = maxY;
				pRT.z = 0;
				xjPoint pLT;
				pLT.x = minX;
				pLT.y = maxY;
				pLT.z = 0;

				xjListMBRpoint.clear();
				xjListMBRpoint.append(pLB);
				xjListMBRpoint.append(pRB);
				xjListMBRpoint.append(pRT);
				xjListMBRpoint.append(pLT);
			}
		}
		else //不水平 不垂直
		{
			double k1 = (p1.y - p0.y) / (p1.x - p0.x);
			double b1 = p0.y - k1 * p0.x;
			double side0 = -3;
			xjPoint Pside0;
			for (int j = 0; j < xjListCH.size(); j++)
			{
				if ((j == a) || (j == (a + 1)))
					continue;

				xjPoint p = xjListCH.at(j);
				double dis = abs(TwoDistancePointAndLine(p, p0, p1));
				if (dis >= side0)
				{
					side0 = dis;
					Pside0.x = p.x;
					Pside0.y = p.y;
					Pside0.z = p.z;
				}
			}
			double b11 = Pside0.y - k1 * Pside0.x;

			//垂直方向
			double k2 = -1.0 / k1;
			double bb = p0.y - k2 * p0.x;
			double side1_positive = -3;
			xjPoint Pside1_positive;
			double side1_negative = 9999999;
			xjPoint Pside1_negative;
			for (int j = 0; j < xjListCH.size(); j++)
			{
				xjPoint p = xjListCH.at(j);
				double dis = (k2*p.x - p.y + bb) / (sqrt(k2*k2 + 1));
				if ((dis>=0)&&(dis >= side1_positive))
				{
					side1_positive = dis;
					Pside1_positive.x = p.x;
					Pside1_positive.y = p.y;
					Pside1_positive.z = p.z;
				}
				if ((dis<0)&&(dis <= side1_negative))
				{
					side1_negative = dis;
					Pside1_negative.x = p.x;
					Pside1_negative.y = p.y;
					Pside1_negative.z = p.z;
				}
			}

			double b2 = Pside1_positive.y - k2 * Pside1_positive.x;
			double b22 = Pside1_negative.y - k2 * Pside1_negative.x;

			//面積和周長
			double side1 = abs(side1_positive)+abs(side1_negative);
			double xjArea = side0 * side1;
			
			if (xjArea <= minArea)
			{
				length = max(side0, side1);
				width = min(side0, side1);
				minArea = xjArea;

				//外接矩形四個點
				xjPoint br0;
				br0.x = (b1 - b22) / (k2 - k1);
				br0.y = k1 * br0.x + b1;
				xjPoint br1;
				br1.x = (b11-b22) / (k2-k1);
				br1.y =  k1* br1.x + b11;
				xjPoint br2;
				br2.x = (b2-b11) / (k1-k2);
				br2.y =  k1* br2.x + b11;
				xjPoint br3;
				br3.x = (b2-b1) / (k1-k2);
				br3.y = k1 * br3.x + b1;

				xjListMBRpoint.clear();
				xjListMBRpoint.append(br0);
				xjListMBRpoint.append(br1);
				xjListMBRpoint.append(br2);
				xjListMBRpoint.append(br3);
			}
		}
	}

	//MBR提示信息
	QString MBRinfo = "chMBR: length = " + QString::number(length, 'f', 4) + ", ";
	MBRinfo += "width = " + QString::number(width, 'f', 4) + ", ";
	MBRinfo += "minimum area = " + QString::number(minArea) + ", ";
	MBRinfo += "circumference = " + QString::number((length + width) * 2);
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章