项目里有这样一个需求,需要把一组矩形合并成一个多边形,这个多边形正好把所有矩形包在里面,而且是最小多边形。这里面尝试了好几种方案,不过每一种方案里都有这样一个步骤,判断给定的点在不在给定的矩形区域内。因为这是一个被频繁调用的方法,所以需要找出最优的实现。
- 最先尝试的是使用内角和法,将这个在网上有详细说明和C++代码,改成C#代码如下:
Line[] lineArray = new Line[vertexArray.Length];
for (int index = 0; index < vertexArray.Length; index++)
{
if (vertexArray[index] == point) //判断点与顶点重合
{
return true;
}
lineArray[index] = new Line(point, vertexArray[index]);
}
Array.Sort(lineArray);
for (int index = 0; index < lineArray.Length - 1; index++)
{
if (lineArray[index].IncludedAngleWith(lineArray[index + 1]) >= 180)
{
return false;
}
}
if (lineArray[lineArray.Length - 1].IncludedAngleWith(lineArray[0]) >= 180)
{
return false;
}
return true;
- 使用DotTrace监测,发现因为调用次数非常多,总的消耗的时间太多,鉴于项目里只需要判断是否在矩形内,于是改用叉积法:
PointF[] vertexArray = beanRect.apexPoints; // 矩形的四个顶点
float cross1, cross2;
float pointX = grid.CenterPoint.X + offsetX; // 点的X坐标
float pointY = grid.CenterPoint.Y + offsetY; // 点的Y坐标
// 判是否在v[0]v[1]和v[2]v[3]两边的同侧
cross1 = (pointX - vertexArray[0].X) * (vertexArray[1].Y - vertexArray[0].Y) - (pointY - vertexArray[0].Y) * (vertexArray[1].X - vertexArray[0].X);
cross2 = (pointX - vertexArray[3].X) * (vertexArray[2].Y - vertexArray[3].Y) - (pointY - vertexArray[3].Y) * (vertexArray[2].X - vertexArray[3].X);
if ((cross1 * cross2) > 0 || (cross1 == 0 && cross2 > 0) || (cross2 == 0 && cross1 > 0))
return false;
// 判是否在v[0]v[3]和v[1]v[2]两边的同侧
cross1 = (pointX - vertexArray[0].X) * (vertexArray[3].Y - vertexArray[0].Y) - (pointY - vertexArray[0].Y) * (vertexArray[3].X - vertexArray[0].X);
cross2 = (pointX - vertexArray[1].X) * (vertexArray[2].Y - vertexArray[1].Y) - (pointY - vertexArray[1].Y) * (vertexArray[2].X - vertexArray[1].X);
if ((cross1 * cross2 > 0) || (cross1 == 0 && cross2 > 0) || (cross2 == 0 && cross1 > 0))
return false;
return true;
再使用DotTrace监测,果然时间消耗瓶颈已经不在这里。