优化GDI +功能的性能性能、功能、GDI

2023-09-04 04:28:59 作者:三分仙女味

在分析我的GDI +项目,我发现下面的 IsLineVisible 函数是一个热门,而绘画和移动我的自定义面板上的对象。

When profiling my GDI+ project I discovered that the following IsLineVisible function is one of the "hottest" while the drawing and moving objects on my custom panel.

是否有可能进行优化呢?

Is there a possibility to optimize it?

  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;
    }

更新时间:以包括厚度/宽度。

UPDATED to include thickness/width.

这是完全未经测试code,但它应该给你的的基本概念的作为没有昂贵的framwork一个超快速的解决方案要求:

This is completely untested code, but it should give you the basic idea for a hyper-fast solution with no expensive framwork calls:

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);
}