- 得到凸包
参考上篇文章 - 算法思路
参考这篇文章,链接。依次计算相邻点角度,反向旋转所有凸包点集,计算最小外接正矩形以及面积。往复迭代所有凸包点,得到面积最小的解,反向旋转调整角度即可得到最终解。
- 参考代码
public void MiniBoundingRect(List<MilPoint> Src, ref RectAngle rectAngle)
{
double dArea = 0;
MilPoint ptCnt = new MilPoint();
CalBoundingRect(Src, ref rectAngle, ref dArea);
rectAngle.ptCenter.CopyTo(ref ptCnt);
for (int i = 0; i <= Src.Count; i++)
{
RectAngle rectAngleTmp = new RectAngle();
double dArea_ = 0;
List<MilPoint> ptsTmp = new List<MilPoint>();
double angle = Math.Atan2(Src[i % (Src.Count - 1)].y - Src[(i + 1) % (Src.Count - 1)].y, Src[i % (Src.Count - 1)].x - Src[(i + 1) % (Src.Count - 1)].x);
for (int j = 0; j < Src.Count; j++)
{
MilPoint ptTmp = new MilPoint();
RotatePt(Src[j], ptCnt, ref ptTmp, angle);
ptsTmp.Add(ptTmp);
}
CalBoundingRect(ptsTmp, ref rectAngleTmp, ref dArea_);
if (dArea_ < dArea)
{
RotatePt(rectAngleTmp.ptCenter, ptCnt, ref rectAngle.ptCenter, angle * (-1));
rectAngle.Width = rectAngleTmp.Width;
rectAngle.Height = rectAngleTmp.Height;
rectAngle.Angle = angle / Math.PI * 180 * (-1);
dArea = dArea_;
}
}
}
public double Cross(MilPoint a, MilPoint b, MilPoint c)
{
return (b.x - a.x) * (c.y - a.y) - (c.x - a.x) * (b.y - a.y);
}
public double Dist(MilPoint a, MilPoint b)
{
return Math.Sqrt((a.x - b.x) * (a.x - b.x) * 1.0 + (a.y - b.y) * (a.y - b.y));
}
public void RotatePt(MilPoint nodeSrc, MilPoint nodeCent, ref MilPoint nodeOut, double dangle)
{
double dX = nodeSrc.x - nodeCent.x;
double dY = nodeSrc.y - nodeCent.y;
double dSin = Math.Sin(dangle);
double dCos = Math.Cos(dangle);
nodeOut.x = dCos * dX + dSin * dY + nodeCent.x;
nodeOut.y = dCos * dY - dSin * dX + nodeCent.y;
}
public void CalBoundingRect(List<MilPoint> nodes, ref RectAngle rectAngle, ref double dArea)
{
MilPoint nodeOutTL = new MilPoint();
MilPoint nodeOutBR = new MilPoint();
nodeOutTL.x = nodes[0].x;
nodeOutTL.y = nodes[0].y;
nodeOutBR.x = nodes[0].x;
nodeOutBR.y = nodes[0].y;
for (int i = 0; i < nodes.Count; i++)
{
if (nodes[i].x < nodeOutTL.x)
nodeOutTL.x = nodes[i].x;
if (nodes[i].y < nodeOutTL.y)
nodeOutTL.y = nodes[i].y;
if (nodes[i].x > nodeOutBR.x)
nodeOutBR.x = nodes[i].x;
if (nodes[i].y > nodeOutBR.y)
nodeOutBR.y = nodes[i].y;
}
rectAngle.ptCenter.x = (nodeOutBR.x + nodeOutTL.x) / 2;
rectAngle.ptCenter.y = (nodeOutBR.y + nodeOutTL.y) / 2;
rectAngle.Width = Math.Abs(nodeOutBR.x - nodeOutTL.x);
rectAngle.Height = Math.Abs(nodeOutBR.y - nodeOutTL.y);
rectAngle.Angle = 0;
dArea = rectAngle.Width * rectAngle.Height;
}