Blockview
#region polyline围合区域转solid集合
/// <summary>
/// 使用内存 Solid 模拟多边形灰色填充
/// </summary>
/// <param name="poly">闭合多边形 Polyline(直边,bulge = 0)</param>
/// <returns>List<Solid> 临时实体集合</returns>
public static List<Solid> Fill(Polyline poly)
{
if (poly == null) throw new ArgumentNullException(nameof(poly));
if (!poly.Closed) throw new ArgumentException("Polyline 必须闭合");
var verts = new List<Point2d>();
for (int i = 0; i < poly.NumberOfVertices; i++)
verts.Add(poly.GetPoint2dAt(i));
// 三角剖分
var triangles = Triangulate(verts);
// 生成 Solid
var solids = new List<Solid>();
foreach (var tri in triangles)
{
var p0 = new Point3d(tri[0].X, tri[0].Y, 0);
var p1 = new Point3d(tri[1].X, tri[1].Y, 0);
var p2 = new Point3d(tri[2].X, tri[2].Y, 0);
solids.Add(new Solid(p0, p1, p2));
}
return solids;
}
/// <summary>
/// 简单耳切法三角剖分
/// </summary>
private static List<Point2d[]> Triangulate(List<Point2d> polyVerts)
{
var triangles = new List<Point2d[]>();
var verts = new List<Point2d>(polyVerts);
while (verts.Count > 3)
{
bool earFound = false;
for (int i = 0; i < verts.Count; i++)
{
var prev = verts[(i - 1 + verts.Count) % verts.Count];
var curr = verts[i];
var next = verts[(i + 1) % verts.Count];
if (IsConvex(prev, curr, next))
{
// 检查三角形内有没有其他点
bool hasPointInside = false;
for (int j = 0; j < verts.Count; j++)
{
if (j == (i - 1 + verts.Count) % verts.Count || j == i || j == (i + 1) % verts.Count)
continue;
if (PointInTriangle(verts[j], prev, curr, next))
{
hasPointInside = true;
break;
}
}
if (!hasPointInside)
{
// 找到一个耳朵
triangles.Add(new Point2d[] { prev, curr, next });
verts.RemoveAt(i);
earFound = true;
break;
}
}
}
if (!earFound)
throw new Exception("三角剖分失败,可能多边形顶点顺序不对");
}
// 剩下最后一个三角形
triangles.Add(new Point2d[] { verts[0], verts[1], verts[2] });
return triangles;
}
private static bool IsConvex(Point2d a, Point2d b, Point2d c)
{
return (b.X - a.X) * (c.Y - a.Y) - (b.Y - a.Y) * (c.X - a.X) > 0;
}
private static bool PointInTriangle(Point2d p, Point2d a, Point2d b, Point2d c)
{
double dX = p.X - c.X;
double dY = p.Y - c.Y;
double dX21 = c.X - b.X;
double dY12 = b.Y - c.Y;
double D = dY12 * (a.X - c.X) + dX21 * (a.Y - c.Y);
double s = dY12 * dX + dX21 * dY;
double t = (c.Y - a.Y) * dX + (a.X - c.X) * dY;
if (D < 0) return s <= 0 && t <= 0 && s + t >= D;
return s >= 0 && t >= 0 && s + t <= D;
}
#endregion