Pregunta

I'm using WinForms to write a visualizer for a simulation. The visualization involves various objects moving around a grid.

So far, I'm using a custom control that extends Panel and doing the custom drawing with the Graphics class during Paint events. However, one irritation is that I'm constantly having to scale things from grid coordinates to the control.DisplayRectangle coordinates (in other words, an object that takes up 2 cells in the grid would take up 2 * (control.DisplayRectangle.Width / horizontalGridWidth) pixels when drawn).

I'm wondering, is there a way to get the Graphics object to do these translations for me so that I can express my drawing in grid coordinates and have it automatically be mapped to the physical coordinates?

It turns out that Matrix was indeed the key (see accepted answer). Here's the code that got it working:

public SimulationPanel() {
    this.DoubleBuffered = true;
    this.SizeChanged += (o, e) => this.Invalidate();
    this.Paint += this.PaintPanel;
}

private void Paint(object sender, PaintEventArgs e) {
                e.Graphics.Clear(Color.Black);

            var fromRectangle = GetSimulationWorldCoordinates();
            var toRectangle = ScaleToFit(fromRectangle, this.DisplayRectangle);

            using (var matrix = new Matrix(
                            fromRectangle, 
                            new[] { 
                                toRectangle.Location, 
                                new Point(toRectangle.Right, toRectangle.Top), 
                                new Point(toRectangle.Left, toRectangle.Bottom), 
                        }))
            {
                                // draw the simulation stuff here using simulation coordinates
                e.Graphics.Transform = matrix;
                e.Graphics.FillRectangle(Brushes.LightBlue, toRectangle);
                e.Graphics.DrawLine(Pens.Red, toRectangle.Location, new Point(toRectangle.Right, toRectangle.Bottom));
            }
}
¿Fue útil?

Solución

How about this code ?

I use Labels instead of grids because I cannot know your grids.

using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        GraphicsPath path = new GraphicsPath();
        RectangleF pathRect;

        public Form1()
        {
            InitializeComponent();

            Location = new Point(0, 0);
            Size = new System.Drawing.Size(500, 500);

            Label lbl1 = new Label();
            lbl1.Location = new Point(100, 100);
            lbl1.Size = new System.Drawing.Size(200, 100);
            lbl1.BorderStyle = BorderStyle.FixedSingle;
            lbl1.Paint += new PaintEventHandler(lbl_Paint);

            Label lbl2 = new Label();
            lbl2.Location = new Point(300, 200);
            lbl2.Size = new System.Drawing.Size(100, 200);
            lbl2.BorderStyle = BorderStyle.FixedSingle;
            lbl2.Paint += new PaintEventHandler(lbl_Paint);

            Controls.Add(lbl1);
            Controls.Add(lbl2);

            path.AddRectangle(new Rectangle(50, 50, 150, 150));
            path.AddEllipse(new Rectangle(25, 50, 25, 50));
            pathRect = path.GetBounds();
        }

        void lbl_Paint(object sender, PaintEventArgs e)
        {
            var rect = ((Control)sender).DisplayRectangle;

            PointF[] plgpts = new PointF[] {
                new PointF(rect.Left, rect.Top),
                new PointF(rect.Right - 1, rect.Top),
                new PointF(rect.Left, rect.Bottom - 1),
            };

            Graphics g = e.Graphics;
            g.Clear(SystemColors.Control);
            using (Matrix matrix = new Matrix(path.GetBounds(), plgpts))
            {
                g.Transform = matrix;
                g.DrawPath(Pens.Red, path);
            }
        }
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top