.net 优化GDI和x2B的性能;作用

.net 优化GDI和x2B的性能;作用,.net,winforms,gdi+,.net,Winforms,Gdi+,在分析我的GDI+项目时,我发现以下IsLineVisible函数是在我的自定义面板上绘制和移动对象时最“热门”的函数之一 是否有可能对其进行优化 Private Function IsLineVisible(ByVal detectorRectangle As Rectangle, ByVal pen As Pen, ByVal ParamArray po

在分析我的GDI+项目时,我发现以下
IsLineVisible
函数是在我的自定义面板上绘制和移动对象时最“热门”的函数之一

是否有可能对其进行优化

  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

我唯一能看到的可能是使用一支更宽/更厚的


这将减少该方法的递归次数,并减少对
加宽
的调用,而不会失去太多的效果(我希望是在最后一个上)。

与其创建路径(这是一个非常昂贵的GDI构造),不如在点之间循环,将该点与前一点连接起来,检查那条线是否与你的矩形相交

它的计算成本应该较低,并且能够在第一个与矩形相交的线段上停止循环

这篇文章应该有助于交叉测试。

更新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;
    }
public bool AreLinesVisible(点[]p,int-width,矩形rect)
{
对于(变量i=1;i
更新了以包括厚度/宽度

这是完全未经测试的代码,但它应该为您提供超快速解决方案的基本思想,而不需要昂贵的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);
}
public bool IsLineVisible(点p1、点p2、int-width、矩形rect)
{
var a=Math.Atan2(p1.Y-p2.Y,p1.X-p2.X)+Math.PI/2;
var whalf=(宽度+1)*0.5;
var dx=(int)Math.Round(whalf*Math.Sin(a));
var dy=(int)Math.Round(whalf*Math.Cos(a));
返回IsLineVisible(新点(p1.X-dx,p1.Y-dy),新点(p2.X-dx,p2.Y-dy),rect)
||IsLineVisible(新点(p1.X+dx,p1.Y+dy),新点(p2.X+dx,p2.Y+dy),rect);
}
公共布尔线可见(点p1、点p2、矩形矩形)
{
if(p1.X>p2.X)//确保p1是最左边的点
返回IsLineVisible(p2、p1、rect);
if(矩形包含(p1)| |矩形包含(p2))
return true;//rect->line中的一个或两个端点可见
//如果两个点同时位于左侧或右侧或上方或下方->直线不可见
if(p1.X=rect.Right&&p2.X>=rect.Right)
返回false;
if(p1.Y=rect.Bottom&&p2.Y>=rect.Bottom)
返回false;
//现在recursivley把这条线分成两部分,看看会发生什么
//(这是一个近似值…)
var pmidle=新点((p1.X+p2.X)/2,(p1.Y+p2.Y)/2);
返回IsLineVisible(p1,新点(pmidle.X-1,pmidle.Y),rect)
||IsLineVisible(新点(pmidle.X+1,pmidle.Y),p2,rect);
}

无需创建区域;可以改用GraphicsPath.IsVisible。我会扩展GraphicsPath并缓存它,以便根据需要命中测试的对象重复使用。

想法是笔,可以不同。不仅仅是一行像素的故事。我可以用另一支笔作为论据。。。这就是重点。我有一些宽的线,其他粗的线,所以我应该检测不同类型的线…是的,但我说了基本的想法-你只需要计算出组成粗线的两条等高线,然后将它们都传递出去。如果其中一条是可见的,那么你的粗线就是可见的!一条虚线在一个矩形内是否或多或少可见???当虚线刚好接触到矩形的角点时,你是在追求精确的像素重叠吗?好的,我可以承认离开了样式限制。。。但我的方法接受了一系列点,而不仅仅是2…)什么我不知道这是一个“请给我发密码”的问题。我刚刚向您展示了如何使代码运行速度提高100倍,而您甚至不必编写最简单的循环-(C#和VB.Net在此有所不同。整数除以整数不会导致C#中的双精度。在VB.Net中,我想您可以使用“\”进行整数除法。至少在普通的旧VB中可以。