How to determine when Rectangles overlap or intersect?

Deadly 提交于 2021-02-19 07:18:31

问题


I found out how to draw Rectangles and some code to find when two rectangles overlap but I can't connect these procedures.

I have the two rectangles that I wanted but then a cannot determine whether these intersect, to then add this information to a ListBox.

Here is my code:

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

回答1:


► As noted, you shouldn't use CreateGraphics() to draw on a Control's surface: this object becomes invalid (belongs to the past) as soon as the Control where the drawing is performed is invalidated (is repainted).

All Controls that have a drawable surface, raise a Paint event and have an OnPaint method that we can override to perform custom painting (the OnPaint method is responsible to raise the Paint event, so we need to handle just one).

The argument of both the event and the method, represents a PaintEventArgs object, which provides a fresh Graphics object that we can use to paint.

We can call the Invalidate() method to repaint a Control when needed. This method causes the generation of a new PaintEventArgs object (thus, a new Graphics object). After, the OnPaint method is called, which - in turn - raises the Paint event.

► To determine whether a Rectangle intersects another (or more than one), we can use the Rectangle.IntersetWith() method (it returns true or false) and the Rectangle.Interset() method → this is used to generate a Rectangle that represents the intersection of two other rectangles.

See also:
→ Rectangle.Contains([Rectangle])
→ Rectangle.Union([Rectangle a], [Rectangle b]).

Here, I'm using a few collections to store the shapes currently drawn and their intersections (just rectangles, but you can build more complex shapes using GraphicsPath objects):

  • A List<Rectangle> (rects) which stores the Rectangles already created.
  • A List<Rectangle> (intersections), to store the intersections which belong to the past (intersections already drawn).
  • A List<Rectangle> (currentIntersects), used to temporarily store the intersection generated when a new Rectangle shaped is being drawn, so we can use different colors (as soon as we release the Mouse Button, this collection is fixed and added to the intersections collection).
  • A Rectangle structure (currentRect) which represents the Rectangle that is currently being drawn on the surface (when the Mouse Button is released, this object is added to the rects collection).
  • A Point structure (startPosition), used to store the initial position of the Rectangle currently drawn. It's reset when the OnMouseDown method is called (when a new Rectangle shape is generated).

► To use this code, create a new Form and paste the code you find here in its Code file. No need to subscribe to any event: since we're drawing on a Form, I'm overriding its methods (OnPaint, OnMouseDown, OnMouseUp, OnMouseMove), no event is used.
You can do the same with a Custom Control or a UserControl.

To add these collection, or just the intersections collection, to e.g., a ListBox, to handle the collections visually, see here (the currentIntersects and intersections collections already contain the information):

How to call a method that uses PaintEventArgs and coordinates variables

NOTE:
► Here, in the OnPaint method override, I'm not calling base.OnPaint(), so the event is not generated. This speeds up the process a bit, but keep in mind that subscribing to the Form's Paint event is useless.

► You need to activate double-buffering: (set DoubleBuffered = true), otherwise you'll notice a lot of flickering (this is quite normal).

This is how it works:


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


来源:https://stackoverflow.com/questions/62945025/how-to-determine-when-rectangles-overlap-or-intersect

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!