测试矩形线相交

时间:2018-07-06 21:01:12

标签: c# winforms intersection

我正在尝试查看图像框是否与e图形线交互。 我当前的代码:

e.Graphics.DrawLine(SystemPens.ButtonShadow, a, b);

if (pictureBox1.Bounds.IntersectsWith(e.GraphicsLine.Bounds))
{
    dead();
}

我不确定该怎么做。

2 个答案:

答案 0 :(得分:2)

要测试矩形和直线的交点,您可以使用Wikipedia文章中的许多方法之一,也可以使用涉及GraphicsPathsRegions的GDI +技巧..:

using System.Drawing.Drawing2D;
..

bool Intersects(Point a, Point b, Rectangle r)
{
    if (Math.Min(a.X, b.X) > r.Right)  return false;   // *
    if (Math.Max(a.X, b.X) < r.Left)   return false;   // *
    if (Math.Min(a.Y, b.Y) > r.Bottom) return false;   // *
    if (Math.Max(a.Y, b.Y) < r.Top)    return false;   // *

    if (r.Contains(a)) return true;   // **
    if (r.Contains(b)) return true;   // **

    using (GraphicsPath gp = new GraphicsPath())
    using (Pen pen = new Pen(Color.Empty, 0.5f))
    using (Region reg = new Region(r))
    using (Graphics g = CreateGraphics())
    {
        gp.AddLine(a,b);
        gp.Widen(pen);   // we need to widen the line path just a little
        reg.Intersect(gp);
        if (reg.IsEmpty(g)) return false;
    }
    return true;
}

这是一个小的测试结果:

enter image description here

由于Region.IsEmpty可能不是很快,所以我在通话前进行了一些琐碎的测试,以提高速度。有关区域see here的性能问题的讨论。从这一点上,我猜可以得出一个结论,即用一个简单的矩形进行测试实际上仍然会相当快。

对于真正快速的测试,您可能需要实现真正的限幅方法。 This looks nice ..

但是与该分析方法相比,该地区的GDI +技巧有一个很大的优势:我将处理可以放入GraphicsPath的任何形状,包括圆形,椭圆形,多边形,各种组合以及复杂的形状跟踪路径。并且由于Region支持所有设置操作,因此您的想象力是极限。

这使您可以测试飞船或怪物的复杂形状;还有一些其他技巧,您甚至可以测试旋转的形状。

请注意,如果您要测试复杂的形状,则需要:

  • 传递GraphicsPath
  • 在前四个测试(*)中使用其边界矩形(gp.GetBounds()
  • 删除其他两个测试(**),因为边界矩形现在不起作用;实际上,它们仅适用于矩形。在下面的椭圆演示中,我不得不将其删除。

这里是相同的示例,只是用椭圆代替矩形:

enter image description here

答案 1 :(得分:2)

您在这里。原始代码在C中,我翻译为vb.net。该代码适用于直线和矩形。

enter image description here

'//min_clip_x is the distance of the left side of rect
'//min_clip_y is the distance of the upper side of rect
'//max_clip_x is the distance of the right side of rect
'//min_clip_y is the distance of the down side of rect

Private Function Clip_Line(ByVal x1 As Integer, ByVal y1 As Integer, ByVal x2 As Integer, ByVal y2 As Integer,
                             ByVal min_clip_x As Integer, ByVal max_clip_x As Integer, ByVal min_clip_y As Integer,
                             ByVal max_clip_y As Integer) As Boolean

    Const CLIP_CODE_C As Integer = 0
    Const CLIP_CODE_N As Integer = 8
    Const CLIP_CODE_S As Integer = 4
    Const CLIP_CODE_E As Integer = 2
    Const CLIP_CODE_W As Integer = 1
    Const CLIP_CODE_NE As Integer = 10
    Const CLIP_CODE_SE As Integer = 6
    Const CLIP_CODE_NW As Integer = 9
    Const CLIP_CODE_SW As Integer = 5

    Dim p1_code As Integer = 0
    Dim p2_code As Integer = 0
    Dim xc1, yc1, xc2, yc2 As Integer

    xc1 = x1
    yc1 = y1
    xc2 = x2
    yc2 = y2

    '//determine codes for p1 And p2
    If y1 < min_clip_y Then
        p1_code = p1_code Or CLIP_CODE_N
    Else
        If y1 > max_clip_y Then
            p1_code = p1_code Or CLIP_CODE_S
        End If
    End If

    If (x1 < min_clip_x) Then
        p1_code = p1_code Or CLIP_CODE_W
    Else
        If (x1 > max_clip_x) Then
            p1_code = p1_code Or CLIP_CODE_E
        End If
    End If

    If (y2 < min_clip_y) Then
        p2_code = p2_code Or CLIP_CODE_N
    Else
        If (y2 > max_clip_y) Then
            p2_code = p2_code Or CLIP_CODE_S
        End If
    End If

    If (x2 < min_clip_x) Then
        p2_code = p2_code Or CLIP_CODE_W
    Else
        If (x2 > max_clip_x) Then
            p2_code = p2_code Or CLIP_CODE_E
        End If
    End If

    '//try And trivially reject
    If CBool(p1_code And p2_code) Then
        Return False
    End If

    '//test for totally visible, if so leave points untouched
    If (p1_code = 0 And p2_code = 0) Then
        Return True
    End If

    '//determine end clip point for p1
    Select Case p1_code
        Case CLIP_CODE_C
            Exit Select
        Case CLIP_CODE_N
            yc1 = min_clip_y
            xc1 = CInt(x1 + 0.5 + (min_clip_y - y1) * (x2 - x1) / (y2 - y1))

            Exit Select
        Case CLIP_CODE_S
            yc1 = max_clip_y
            xc1 = CInt(x1 + 0.5 + (max_clip_y - y1) * (x2 - x1) / (y2 - y1))

            Exit Select
        Case CLIP_CODE_W
            xc1 = min_clip_x
            yc1 = CInt(y1 + 0.5 + (min_clip_x - x1) * (y2 - y1) / (x2 - x1))

            Exit Select
        Case CLIP_CODE_E
            xc1 = max_clip_x
            yc1 = CInt(y1 + 0.5 + (max_clip_x - x1) * (y2 - y1) / (x2 - x1))

            Exit Select
        Case CLIP_CODE_NE
            '//north hline intersection
            yc1 = min_clip_y
            xc1 = CInt(x1 + 0.5 + (min_clip_y - y1) * (x2 - x1) / (y2 - y1))
            '//test if intersection Is valid,
            '//if so then done, else compute next
            If (xc1 < min_clip_x) Or (xc1 > max_clip_x) Then
                '//east vline intersection
                xc1 = max_clip_x
                yc1 = CInt(y1 + 0.5 + (max_clip_x - x1) * (y2 - y1) / (x2 - x1))
            End If

            Exit Select
        Case CLIP_CODE_SE
            '//south hline intersection
            yc1 = max_clip_y
            xc1 = CInt(x1 + 0.5 + (max_clip_y - y1) * (x2 - x1) / (y2 - y1))
            '//test if intersection Is valid,
            '//if so then done, else compute next
            If (xc1 < min_clip_x) Or (xc1 > max_clip_x) Then
                '//east vline intersection
                xc1 = max_clip_x
                yc1 = CInt(y1 + 0.5 + (max_clip_x - x1) * (y2 - y1) / (x2 - x1))
            End If

            Exit Select
        Case CLIP_CODE_NW
            '//north hline intersection
            yc1 = min_clip_y
            xc1 = CInt(x1 + 0.5 + (min_clip_y - y1) * (x2 - x1) / (y2 - y1))
            '//test if intersection Is valid,
            '//if so then done, else compute next
            If (xc1 < min_clip_x) Or (xc1 > max_clip_x) Then
                xc1 = min_clip_x
                yc1 = CInt(y1 + 0.5 + (min_clip_x - x1) * (y2 - y1) / (x2 - x1))
            End If

            Exit Select
        Case CLIP_CODE_SW
            '//south hline intersection
            yc1 = max_clip_y
            xc1 = CInt(x1 + 0.5 + (max_clip_y - y1) * (x2 - x1) / (y2 - y1))
            '//test if intersection Is valid,
            '//if so then done, else compute next
            If (xc1 < min_clip_x) Or (xc1 > max_clip_x) Then
                xc1 = min_clip_x
                yc1 = CInt(CDbl(y1) + 0.5 + CDbl(min_clip_x - x1) * CDbl(y2 - y1) / CDbl(x2 - x1))
            End If

            Exit Select
        Case Else
            Exit Select
    End Select

    '//determine end clip point for p2
    Select Case p2_code
        Case CLIP_CODE_C
            Exit Select
        Case CLIP_CODE_N
            yc2 = min_clip_y
            xc2 = CInt(x2 + (min_clip_y - y2) * (x1 - x2) / (y1 - y2))

            Exit Select
        Case CLIP_CODE_S
            yc2 = max_clip_y
            xc2 = CInt(x2 + (max_clip_y - y2) * (x1 - x2) / (y1 - y2))

            Exit Select
        Case CLIP_CODE_W
            xc2 = min_clip_x
            yc2 = CInt(y2 + (min_clip_x - x2) * (y1 - y2) / (x1 - x2))

            Exit Select
        Case CLIP_CODE_E
            xc2 = max_clip_x
            yc2 = CInt(y2 + (max_clip_x - x2) * (y1 - y2) / (x1 - x2))

            Exit Select
        Case CLIP_CODE_NE
            '//north hline intersection
            yc2 = min_clip_y
            xc2 = CInt(x2 + 0.5 + (min_clip_y - y2) * (x1 - x2) / (y1 - y2))
            '//test if intersection Is valid,
            '//if so then done, else compute next
            If (xc2 < min_clip_x) Or (xc2 > max_clip_x) Then
                '//east vline intersection
                xc2 = max_clip_x
                yc2 = CInt(y2 + 0.5 + (max_clip_x - x2) * (y1 - y2) / (x1 - x2))
            End If

            Exit Select
        Case CLIP_CODE_SE
            '//south hline intersection
            yc2 = max_clip_y
            xc2 = CInt(x2 + 0.5 + (max_clip_y - y2) * (x1 - x2) / (y1 - y2))
            '//test if intersection Is valid,
            '//if so then done, else compute next
            If (xc2 < min_clip_x) Or (xc2 > max_clip_x) Then
                '//east vline intersection
                xc2 = max_clip_x
                yc2 = CInt(y2 + 0.5 + (max_clip_x - x2) * (y1 - y2) / (x1 - x2))
            End If

            Exit Select
        Case CLIP_CODE_NW
            '//north hline intersection
            yc2 = min_clip_y
            xc2 = CInt(x2 + 0.5 + (min_clip_y - y2) * (x1 - x2) / (y1 - y2))
            '//test if intersection Is valid,
            '//if so then done, else compute next
            If (xc2 < min_clip_x) Or (xc2 > max_clip_x) Then
                xc2 = min_clip_x
                yc2 = CInt(y2 + 0.5 + (min_clip_x - x2) * (y1 - y2) / (x1 - x2))
            End If

            Exit Select
        Case CLIP_CODE_SW
            '//south hline intersection
            yc2 = max_clip_y
            xc2 = CInt(x2 + 0.5 + (max_clip_y - y2) * (x1 - x2) / (y1 - y2))
            '//test if intersection Is valid,
            '//if so then done, else compute next
            If (xc2 < min_clip_x) Or (xc2 > max_clip_x) Then
                xc2 = min_clip_x
                yc2 = CInt(y2 + 0.5 + (min_clip_x - x2) * (y1 - y2) / (x1 - x2))
            End If

            Exit Select
        Case Else
            Exit Select
    End Select

    '//do bounds check
    If (xc1 < min_clip_x) Or (xc1 > max_clip_x) Or (yc1 < min_clip_y) Or (yc1 > max_clip_y) Or
        (xc2 < min_clip_x) Or (xc2 > max_clip_x) Or (yc2 < min_clip_y) Or (yc2 > max_clip_y) Then

        Return False '//no collision
    End If

    Return True '//collision
End Function