创建另一个具有不同坐标的图形?

Creating another Graphics with different coordinates?

是否可以使用不同的坐标系从现有 Graphics 中创建另一个 Graphics?例如,假设黑色矩形是我在 OnPaint() 中得到的 Graphics 对象的 ClipRectangle。如果我只想在蓝色矩形内部绘制,我将不得不不断计算偏移量。也就是说,要在蓝色矩形中的逻辑点 (0,0) 处绘制,我必须添加 x 和 y 偏移量。这使得绘图代码变得复杂。

有没有一种方法可以使用上面的 Graphics 但使用不同的坐标系来创建某种虚拟 Graphics?如下所示

//not actual code
var virtualG = Graphics.FromExistingGraphics(e.Graphics, 200/*x1*/, 200/*y1*/, 1000/*x2*/, 600/*y2*/);

//Doing the same thing as e.Graphics.DrawLine(pen, 200, 200, 400, 400) 
virtualG.DrawLine(pen, 0, 0, 200, 200); 

//Draws nothing, NOT the same as e.Graphics.DrawLine(pen, 1100, 200, 1200, 400)
//, because its outside of the virtualG's bounds.
virtualG.DrawLine(pen, 900, 0, 1000, 200); 

我考虑过使用位图创建一个新的 Graphics,在那里绘制,然后将位图从 OnPaint 复制到 Graphics 的指定位置,但这可能会很慢。

如果您不想进行任何缩放,而只想将原点移动到 (200, 200),则使用 TranslateTransform as suggested previously. If you want to clip any drawings outside that rectangle, then use SetClip

这是一个示例,显示了在平移和剪裁之前和之后绘制的同一组线条。黑线在之前,蓝线在之后(第二条蓝线被剪掉了,因此不可见)。红色矩形表示裁剪区域:

代码:

public partial class Form1 : Form
{

    public Form1()
    {
        InitializeComponent();
    }

    public class Line
    {
        public Point ptA;
        public Point ptB;
        public void Draw(Graphics G, Color color)
        {
            using (Pen P = new Pen(color))
            {
                G.DrawLine(P, ptA, ptB);
            }
        }
    }

    private List<Line> Lines = new List<Line>();

    private void Form1_Load(object sender, EventArgs e)
    {
        Lines.Add(new Line() { ptA = new Point(0,0), ptB = new Point(200, 200)});
        Lines.Add(new Line() { ptA = new Point(900, 0), ptB = new Point(1000, 200) });
    }        

    private void pictureBox1_Paint(object sender, PaintEventArgs e)
    {
        Graphics G = e.Graphics;
        G.Clear(Color.DarkGray);

        foreach(Line line in Lines)
        {
            line.Draw(G, Color.Black);
        }

        Rectangle rc = new Rectangle(new Point(200, 200), new Size(800, 400));
        G.DrawRectangle(Pens.Red, rc);
        G.SetClip(rc);

        G.TranslateTransform(rc.Left, rc.Top); // origin is now at (200, 200)

        foreach (Line line in Lines)
        {
            line.Draw(G, Color.Blue);
        }
    }

}