优化GDI +功能的性能
在分析我的GDI +项目时,我发现以下IsLineVisible
函数是在我的自定义面板上绘制和移动对象时“最热”的函数之一。优化GDI +功能的性能
有没有可能优化它?
Private Function IsLineVisible(ByVal detectorRectangle As Rectangle,
ByVal pen As Pen,
ByVal ParamArray points() As Point) As Boolean
Using path As New GraphicsPath()
path.AddLines(points)
Return IsPathVisible(detectorRectangle, path, pen)
End Using
End Function
' Helper functions '''''''''''''''''''''''''''''''''''''
Private Function IsPathVisible(ByVal detectorRectangle As Rectangle,
ByVal path As GraphicsPath,
ByVal pen As Pen) As Boolean
If Not path.IsPoint Then
path.Widen(pen)
End If
Return IsPathVisible(detectorRectangle, path)
End Function
Private Function IsPathVisible(ByVal detectorRectangle As Rectangle,
ByVal path As GraphicsPath) As Boolean
Using r As New Region(path)
If r.IsVisible(detectorRectangle) Then
Return True
Else
Return False
End If
End Using
End Function
更新2:
public bool AreLinesVisible(Point[] p, int width, Rectangle rect)
{
for (var i = 1; i < p.Length; i++)
if (IsLineVisible(p[i - 1], p[i], width, rect))
return true;
return false;
}
修订包括厚度/宽度。
这是完全未经测试的代码,但它应该给你基本思路对于没有昂贵的framwork一个超快速的解决方案要求:
public bool IsLineVisible(Point p1, Point p2, int width, Rectangle rect)
{
var a = Math.Atan2(p1.Y - p2.Y, p1.X - p2.X) + Math.PI/2;
var whalf = (width + 1)*0.5;
var dx = (int) Math.Round(whalf*Math.Sin(a));
var dy = (int) Math.Round(whalf*Math.Cos(a));
return IsLineVisible(new Point(p1.X - dx, p1.Y - dy), new Point(p2.X - dx, p2.Y - dy), rect)
|| IsLineVisible(new Point(p1.X + dx, p1.Y + dy), new Point(p2.X + dx, p2.Y + dy), rect);
}
public bool IsLineVisible(Point p1, Point p2, Rectangle rect)
{
if (p1.X > p2.X) // make sure p1 is the leftmost point
return IsLineVisible(p2, p1, rect);
if (rect.Contains(p1) || rect.Contains(p2))
return true; // one or both end-points within the rect -> line is visible
//if both points are simultaneously left or right or above or below -> line is NOT visible
if (p1.X < rect.X && p2.X < rect.X)
return false;
if (p1.X >= rect.Right && p2.X >= rect.Right)
return false;
if (p1.Y < rect.Y && p2.Y < rect.Y)
return false;
if (p1.Y >= rect.Bottom && p2.Y >= rect.Bottom)
return false;
// now recursivley break down the line in two part and see what happens
// (this is an approximation...)
var pMiddle = new Point((p1.X + p2.X)/2, (p1.Y + p2.Y)/2);
return IsLineVisible(p1, new Point(pMiddle.X - 1, pMiddle.Y), rect)
|| IsLineVisible(new Point(pMiddle.X + 1, pMiddle.Y), p2, rect);
}
我能看到的唯一的事情是可能使用更宽/更厚Pen
。
这样可以减少方法,减少对Widen
的调用,而不会失去太多的效果(我希望在最后一个)。
我使用其他笔,我通过作为参数...这是所有的重点。我有一些宽线,其他粗线,所以我应该检测不同类型的线... – serhio
而不是创建一个路径,这是一个非常昂贵的GDI构造,如何循环你的点,将该点与前一点连接,并检查该线是否与矩形相交?
它应该在计算上花费较少,并且能够停止第一个段上的循环与矩形相交。
这篇文章应该有助于交集测试。 How to find the intersection point between a line and a rectangle?
这个想法是笔,可以是不同的。不只是一行像素的故事。 – serhio
有没有必要建立一个区域; GraphicsPath.IsVisible可以用来代替。我会扩大GraphicsPath并将其缓存以供每个需要命中测试的对象重用。
谢谢。但是你“忘记”了笔的宽度**(厚度)。 – serhio
是的,但我说的基本思想 - 你只需要计算两条轮廓线,组成你的粗线并通过它们。如果其中一个是可见的 - 那么你的粗线是可见的! –
这条线也可以有一个样式:虚线,虚线... – serhio