C#中如何将GraphicsPath转换为单个多边形以适配FillPolygon?
解决SVG路径转FillPolygon的异常问题
问题根源
直接使用GraphicsPath.PathPoints调用FillPolygon异常的核心原因有两个:
- 曲线点干扰:SVG路径常包含贝塞尔曲线、圆弧等曲线段,
PathPoints会包含这些曲线的控制点,而非构成多边形的直线顶点,直接使用会导致形状错误或参数异常。 - 多子路径冲突:单个SVG路径可能包含多个独立的子路径(比如多个闭合图形),
FillPolygon仅支持单一闭合直线多边形的点集,混合多个子路径的点会引发逻辑错误。
解决方案
需要先将路径曲线转成直线段,再拆分每个子路径的点集,分别调用FillPolygon:
步骤1:展平曲线为直线段
使用GraphicsPath.Flatten()方法,将所有曲线段近似转换为连续的直线段,此时PathPoints中的点都是直线顶点。
步骤2:拆分独立子路径
通过PathTypes标记,拆分出每个子路径的点集,确保每个点集对应一个独立的多边形。
完整代码示例
if (obj is SvgPath o) { var graphicsPath = new GraphicsPath(); var start = PointF.Empty; foreach (var segment in o.PathData) { start = segment.AddToPath(graphicsPath, start, o.PathData); } // 1. 将曲线展平为直线段,消除控制点干扰 graphicsPath.Flatten(); // 2. 拆分每个子路径的点集 List<List<PointF>> subPathPoints = new List<List<PointF>>(); List<PointF> currentPoints = new List<PointF>(); for (int i = 0; i < graphicsPath.PathPoints.Length; i++) { currentPoints.Add(graphicsPath.PathPoints[i]); // 判断当前点是否为子路径结束点 bool isEndOfSubpath = ((graphicsPath.PathTypes[i] & PathPointType.CloseSubpath) != 0) || (i == graphicsPath.PathPoints.Length - 1) || (i + 1 < graphicsPath.PathPoints.Length && (graphicsPath.PathTypes[i + 1] & PathPointType.Start) != 0); if (isEndOfSubpath) { // 确保子路径闭合(FillPolygon需要闭合多边形) if (currentPoints.Count > 1 && !currentPoints.First().Equals(currentPoints.Last())) { currentPoints.Add(currentPoints.First()); } // 仅保留有效多边形(至少3个点) if (currentPoints.Count >= 3) { subPathPoints.Add(currentPoints); } currentPoints = new List<PointF>(); } } // 3. 逐个填充每个子路径对应的多边形 foreach (var points in subPathPoints) { g.FillPolygon(Brushes.Black, points.ToArray()); } }
关键细节说明
- Flatten参数:
Flatten()可传入精度参数(比如graphicsPath.Flatten(new Matrix(), 0.1f)),数值越小近似精度越高,但生成的点越多。 - 子路径闭合:如果原SVG路径是开放的,手动添加起点到末尾可确保
FillPolygon填充符合预期(FillPolygon默认会自动闭合,但手动闭合更可控)。 - 点数量校验:多边形至少需要3个顶点,否则
FillPolygon会抛出异常,代码中加入了判断避免报错。
内容的提问来源于stack exchange,提问作者Suresh Mandala
相关产品推荐
相关产品推荐

