我有以下
private bool IsPathVisible(Rectangle detectorRectangle, GraphicsPath path, Pen pen)
{
path.Widen(pen);
return IsPathVisible(detectorRectangle, path);
}
当path
点相同时,我收到OutOfMemoryException(使用Widen
函数)。
我该如何管理?
答案 0 :(得分:6)
这是笔和扩大方法的错误。确保路径的起点和路径的终点不相同。
这是一个示范:
private void panel1_Paint(object sender, PaintEventArgs e)
{
//This works:
using (GraphicsPath path = new GraphicsPath())
{
path.AddLine(new Point(16, 16), new Point(20, 20));
path.Widen(Pens.Black);
e.Graphics.DrawPath(Pens.Black, path);
}
//This does not:
using (GraphicsPath path = new GraphicsPath())
{
path.AddLine(new Point(20, 20), new Point(20, 20));
path.Widen(Pens.Black);
e.Graphics.DrawPath(Pens.Black, path);
}
}
以下是向Microsoft报告的地方:GraphicsPath.Widen throw OutOfMemoryException if the path has a single point
答案 1 :(得分:1)
我也遭受过这种例外。建议如下:
在加宽之前保存点以查看导致OutOfMemoryException的确切点:
private bool IsPathVisible(Rectangle detectorRectangle, GraphicsPath path, Pen pen)
{
var points = path.PathPoints.Clone() as PointF[];
path.Widen(pen);
return IsPathVisible(detectorRectangle, path);
}
您可能会看到,可能有后续点具有相同的坐标。他们实际上是造成了这个问题。
此外,GraphicsPath可以包含多个子路径。为了进行可靠的命中测试,我建议如下:
public Region[] CreateRegionFromGraphicsPath(GraphicsPath path, Pen wideningPen)
{
var regions = new List<Region>();
var itPath = new GraphicsPathIterator(path);
itPath.Rewind();
var curSubPath = new GraphicsPath();
for (int i = 0; i < itPath.SubpathCount; i++)
{
bool isClosed;
itPath.NextSubpath(curSubPath, out isClosed);
if (!isClosed && CanWiden(curSubPath)) curSubPath.Widen(wideningPen); // widen not closed paths
int regionIndex = i / 100; // max region scan rectangles count
if (regions.Count < regionIndex + 1)
{
regions.Add(new Region(curSubPath));
}
else
{
regions[regionIndex].Union(curSubPath);
}
}
curSubPath.Dispose();
itPath.Dispose();
return regions.ToArray();
}
/// <summary>
/// Determines whether widening this graphics path will not lead to an exception
/// </summary>
public static bool CanWiden(GraphicsPath gp)
{
const float regionPointsTolerance = 1e-8f;
var pts = gp.PathPoints;
if (pts.Length < 2) return false;
for (int i = 1; i < pts.Length; i++)
{
if (Math.Abs(pts[i-1].X - pts[i].X) < regionPointsTolerance && Math.Abs(pts[i-1].Y - pts[i].Y) < regionPointsTolerance) return false;
}
return true;
}
然后你只需为区域调用IsVisible来查找是否有任何一个被击中
答案 2 :(得分:0)
如果路径为IsPoint
,则不要执行加宽。
<System.Runtime.CompilerServices.Extension()> _
Public Function IsPoint(ByVal path As System.Drawing.Drawing2D.GraphicsPath) As Boolean
If path Is Nothing Then Throw New ArgumentNullException("path")
If path.PathPoints.Count < 2 Then Return True
If path.PathPoints(0) <> path.PathPoints(path.PathPoints.Count - 1) Then Return False
For i = 1 To path.PathPoints.Count - 1
If path.PathPoints(i - 1) <> path.PathPoints(i) Then Return False
Next i
' if all the points are the same
Return True
End Function
答案 3 :(得分:0)
以下代码导致.Net 4.0中的DrawPath中的OutOfMemory(可能更高)。 我设法绕过它使用LineCap.Flat而不是LineCap.NoAnchor:
public void TestDrawPath()
{
PointF[] points = new PointF[13]
{
new PointF(0.491141558f, 1.53909028f),
new PointF(0.491141558f, 1.55148673f),
new PointF(0.4808829f, 1.56153619f),
new PointF(0.468228281f, 1.56153619f),
new PointF(0.4555736f, 1.56153619f),
new PointF(0.445314974f, 1.55148673f),
new PointF(0.445314974f, 1.53909028f),
new PointF(0.445314974f, 1.52669382f),
new PointF(0.4555736f, 1.51664436f),
new PointF(0.468228281f, 1.51664436f),
new PointF(0.4808829f, 1.51664436f),
new PointF(0.491141558f, 1.52669382f),
new PointF(0.491141558f, 1.53909028f)
};
byte[] types = new byte[13] { 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 131 };
using (Bitmap bitmap = new Bitmap(2, 2))
using (Graphics g = Graphics.FromImage(bitmap))
{
using (Pen pen = new Pen(Color.Black))
using (GraphicsPath path = new GraphicsPath(points, types))
{
pen.StartCap = LineCap.NoAnchor;
pen.EndCap = LineCap.NoAnchor;
g.DrawPath(pen, path);
}
}
}