【问题标题】:How to determine when Rectangles overlap or intersect?如何确定矩形何时重叠或相交?
【发布时间】:2020-07-16 23:37:12
【问题描述】:

我发现了如何绘制矩形和一些代码来查找两个矩形何时重叠,但我无法连接这些程序。

我有两个我想要的矩形,但无法确定它们是否相交,然后将此信息添加到 ListBox。

这是我的代码:

public partial class Form1 : Form
{
    Graphics g;
    Pen p;
    Point cursor;

    int k = 0;
    Point[] tocke = new Point[2];
    public Form1()
    {
        InitializeComponent();
        g = this.CreateGraphics();
        p = new Pen(Color.Black, 3);
    }

    private void Form1_MouseMove(object sender, MouseEventArgs e)
    {
        cursor = this.PointToClient(Cursor.Position);
        statusMisa.Text = "X: " + cursor.X + " Y: " + cursor.Y;
    }

    private void Form1_Click(object sender, EventArgs e)
    {
        bool Preklapanje(int l1x, int l1y, int l2x, int l2y, int r1x, int r1y, int r2x, int r2y)
        {
            if (l1x >= r2x || l2x >= r1x)
            {
                return false;
            }

            if (l1y <= r2y || l2y <= r1y)
            {
                return false;
            }
            return true;
        }

        List<int> pozX = new List<int>();
        List<int> pozY = new List<int>();
        if (checkCrtanje.Checked == true)
        {
            Rectangle rect = new Rectangle(cursor.X - 50, cursor.Y - 50, 100, 100);
            if (k < 2)
            {
                g.DrawRectangle(p, rect);
                tocke[k++] = new Point(cursor.X, cursor.Y);
                listBox1.Items.Add("X: " + cursor.X + " Y: " + cursor.Y);
                pozX.Add(cursor.X);
                pozY.Add(cursor.Y);
            }
            else
            {
                MessageBox.Show("Možeš nacrtati samo dva kvadrata!");
            }
        }

        if (k == 3)
        {
            if (Preklapanje(pozX[0] - 50, pozY[0] - 50, pozX[0] + 50, pozY[0] + 50, pozX[1] - 50, pozY[1] - 50, pozX[1] + 50, pozY[1] + 50))
            {
                listBox1.Items.Add("Preklapaju se.");
            }
            else
            {
                listBox1.Items.Add("Ne preklapaju se.");
            }
        }
    }
}

【问题讨论】:

  • 有一个内置函数:Rectangle.Intersects(Rectangle) - 另外:通常不推荐使用 this.CreateGraphics() .. - 修复你的代码,你最好的朋友,@987654321 @,应该有帮助!

标签: c# .net winforms graphics intersection


【解决方案1】:

► 如前所述,您不应使用CreateGraphics() 在 Control 的表面上绘图:一旦执行绘图的 Control 被执行,此对象就会变为无效(属于 过去)无效(被重新绘制)。

所有具有可绘制表面的控件,引发Paint 事件并具有OnPaint 方法,我们可以重写该方法以执行自定义绘画(OnPaint 方法负责引发Paint 事件,所以我们只需要处理一个)。

事件和方法的参数,代表一个PaintEventArgs对象,它提供了一个新鲜 Graphics对象,我们可以用它来绘画。

我们可以在需要时调用Invalidate() 方法来重绘一个控件。此方法导致生成一个新的PaintEventArgs 对象(因此,一个新的 Graphics 对象)。之后,调用 OnPaint 方法,进而引发 Paint 事件。

► 要确定一个矩形是否与另一个(或多个)相交,我们可以使用Rectangle.IntersetWith() 方法(它返回truefalse)和Rectangle.Interset() 方法→ 这用于生成一个表示其他两个矩形相交的矩形。

另见:
Rectangle.Contains([Rectangle])
Rectangle.Union([Rectangle a], [Rectangle b]).

在这里,我使用了一些集合来存储当前绘制的形状及其交叉点(只是矩形,但您可以使用GraphicsPath 对象构建更复杂的形状):

  • 一个List&lt;Rectangle&gt; (rects) 存储已创建的矩形。
  • 一个List&lt;Rectangle&gt; (intersections),用于存储属于过去的路口(已绘制的路口)。
  • 一个List&lt;Rectangle&gt;(currentIntersects),用于临时存储绘制新矩形时产生的交集,这样我们就可以使用不同的颜色(只要我们松开鼠标按钮,此集合已修复并添加到 intersections 集合中)。
  • 一个 Rectangle 结构 (currentRect),表示当前在表面上绘制的 Rectangle(当释放鼠标按钮时,此对象被添加到 rects 收藏)。
  • 一个Point结构(startPosition),用于存储当前绘制的Rectangle的初始位置。调用 OnMouseDown 方法时(生成新的 Rectangle 形状时)将其重置。

► 要使用此代码,请创建一个新表单并将您在此处找到的代码粘贴到其代码文件中。无需订阅任何事件:由于我们正在绘制表单,因此我将覆盖其方法(OnPaintOnMouseDownOnMouseUpOnMouseMove),不使用任何事件。
您可以对自定义控件或用户控件执行相同操作。

要将这些集合或仅将交集集合添加到例如 ListBox 以直观地处理集合,请参见此处(currentIntersectsintersections 集合已包含信息):

How to call a method that uses PaintEventArgs and coordinates variables

注意
► 这里,在OnPaint 方法覆盖中,我没有调用base.OnPaint(),因此不会生成事件。这稍微加快了进程,但请记住,订阅 Form 的 Paint 事件是没有用的。

► 你需要开启双缓冲:(设置DoubleBuffered = true),否则你会注意到很多闪烁(这是很正常的)。

这就是它的工作原理:


public partial class FormDrawings : Form
{
    private List<Rectangle> rects = new List<Rectangle>();
    private List<Rectangle> intersections = new List<Rectangle>();
    private List<Rectangle> currentIntersects = new List<Rectangle>();

    private Rectangle currentRect = Rectangle.Empty;
    private Point startPosition = Point.Empty;
    private float penSize = 2.0f;

    protected override void OnMouseDown(MouseEventArgs e)
    {
        base.OnMouseDown(e);
        if (e.Button == MouseButtons.Left) {
            startPosition = e.Location;
            currentRect = new Rectangle(startPosition, Size.Empty);
        }
    }

    protected override void OnMouseMove(MouseEventArgs e)
    {
        base.OnMouseMove(e);
        if (e.Button == MouseButtons.Left) {
            if (e.Y < startPosition.Y) { currentRect.Location = new Point(currentRect.X, e.Y); }
            if (e.X < startPosition.X) { currentRect.Location = new Point(e.X, currentRect.Y); }

            currentRect.Size = new Size(Math.Abs(startPosition.X - e.X), Math.Abs(startPosition.Y - e.Y));

            currentIntersects.Clear();
            foreach (var rect in rects) {
                if (currentRect.IntersectsWith(rect)) {
                    currentIntersects.Add(Rectangle.Intersect(currentRect, rect));
                }
            }
            this.Invalidate();
        }
    }

    protected override void OnMouseUp(MouseEventArgs e)
    {
        base.OnMouseUp(e);
        if (currentRect.Size != Size.Empty) rects.Add(currentRect);
        if (currentIntersects.Count > 0) {
            intersections.AddRange(currentIntersects);
        }
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        using (var borderPen = new Pen(Color.LightGreen, penSize))
        using (var iBrush = new SolidBrush(Color.FromArgb(128, Color.Orange)))
        using (var crBrush = new SolidBrush(Color.FromArgb(128, Color.DeepSkyBlue))) {

            intersections.ForEach(r => e.Graphics.FillRectangle(iBrush, r));
            currentIntersects.ForEach(r => e.Graphics.FillRectangle(crBrush, r));

            e.Graphics.DrawRectangle(borderPen, currentRect);
            rects.ForEach(r => e.Graphics.DrawRectangle(borderPen, r));
        }
    }
}

【讨论】:

  • 谢谢。我会尝试这种方式。唯一的问题是我必须使用算法来绘制形状,而不是我们已有的方法。我很好奇是否有其他方法可以执行这种重叠算法,以便比较它们的执行速度?
  • 当您看到某处(甚至是 MSDN 文档)代码在使用 CreateGraphics() 的画布上绘制形状时,这只是一个示例,而不是真正的代码:它缩短了代码,您应该来全面实施。 CreateGraphics() 当然可以使用,但只是为了绘制一些不应该持续存在的东西(如果你最小化或最大化表单,或者以其他方式导致它重新绘制,一切都消失了)。它也用于测量文本,因为你只需要它一瞬间,然后你处理它(顺便说一句,这是强制性的)。
  • 我很好奇如何获取矩形的左上角和右下角坐标,以便我可以在算法中实现它们以查找矩形的交点?
  • ??它已经在这里实现了:if (currentRect.IntersectsWith(rect)) { currentIntersects.Add(Rectangle.Intersect(currentRect, rect)); }。所以,Rectangle.Intersect(currentRect, rect) 返回一个 Rectangle,表示其他两个矩形的交集。
  • 是的,但我需要使用您可以在我的代码中看到的算法。不是 VS 中已经存在的东西。
猜你喜欢
  • 1970-01-01
  • 2010-09-23
  • 2012-11-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多