Title: Easily map drawing coordinates in C#
The example Map points between coordinate systems in C# shows several ways you can map drawing coordinates to screen coordinates. They all work, but these sorts of coordinate conversions are really common if you're doing more advanced graphics, so I wanted to make this as easy as possible.
This example uses the following SetTransformation method to make using these kinds of transformations easier.
// Map from world coordinates to device coordinates.
private void SetTransformation(Graphics gr,
RectangleF world_rect, RectangleF device_rect,
bool invert_x, bool invert_y)
{
PointF[] device_points =
{
// Upper left.
new PointF(device_rect.Left, device_rect.Top),
// Upper right.
new PointF(device_rect.Right, device_rect.Top),
// Lower left.
new PointF(device_rect.Left, device_rect.Bottom),
};
if (invert_x) for (int i = 0; i < 3; i++)
{
device_points[0].X = device_rect.Right;
device_points[1].X = device_rect.Left;
device_points[2].X = device_rect.Right;
}
if (invert_y)
{
device_points[0].Y = device_rect.Bottom;
device_points[1].Y = device_rect.Bottom;
device_points[2].Y = device_rect.Top;
}
gr.Transform = new Matrix(world_rect, device_points);
}
The method takes as input parameters the Graphics object that will be used for drawing and two rectangles, one that defines the drawing coordinates and one that tells where those coordinates should be displayed on the screen. It also takes two additional parameters that indicate whether you want to flip the drawing horizontally or vertically.
The method creates three points that determine where the graphics system should map the upper left, upper right, and lower left corners of the drawing coordinates. Initially the points map the drawing coordinates to the device coordinates without changing the orientation. The code then checks the invert_x and invert_y parameters to see if it should flip the drawing horizontally or vertically and it adjusts the points' X and Y coordinates accordingly.
The code then uses the drawing coordinate rectangle and the device coordinate points to define a Matrix to transform points from drawing coordinates to the device coordinates and sets the Graphics object's Transform property to the Matrix.
The following code shows how the example uses the SetTransformation method.
// Draw the smiley face with a box around it.
private void picCanvas_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
// Set the transformation. Flip vertically.
RectangleF drawing_rect = new RectangleF(-1, -1, 2, 2);
Rectangle device_rect = new Rectangle(10, 10, 250, 150);
SetTransformation(e.Graphics,
drawing_rect, device_rect, false, true);
// Draw the smiley.
DrawSmiley(e.Graphics);
// Reset the transformation and draw a box around it.
e.Graphics.ResetTransform();
e.Graphics.DrawRectangle(Pens.Red, device_rect);
}
This code sets the Graphics object's SmoothingMode property. It then uses SetTransformation to map the drawing coordinates -1 ≤ X ≤ 1, -1 ≤ Y ≤ 1 to the device rectangle 10 ≤ X ≤ 260, 10 ≤ Y ≤ 160. The DrawSmiley method uses coordinates with X increasing to the right and Y increasing upward (as they normally do when you graph mathematical equations). Screen coordinates increase to the right and down so the call to SetTransformation makes the method flip the result vertically.
The code then calls the DrawSmiley method to draw a smiley face. That method draws the face right side up within the bounds -1 ≤ X ≤ 1, -1 ≤ Y ≤ 1 as shown in Figure 1. The transformation automatically maps the drawing to the desired part of the PictureBox and flips it so it remains right side up despite the fact that Y screen coordinates increase downward. (Change the invert_y parameter to false to see what happens.)
Note that the thicknesses of lines are scaled by transformations. This example scales a drawing rectangle with width 2 to a device rectangle with width 250, which is 125 times wider. If you draw a vertical line 1 pixel wide, it would be scaled by a factor of 125 so it would appear 125 pixels wide in the final drawing. The scaling in the Y direction can be different and is in this example.
You can avoid line scaling by using a pen with thickness 0. That special value tells the drawing system not to scale the line's thickness and always draw it 1 pixel wide even if a transformation is in use.
The DrawSmiley method uses this kind of pen with thickness 0. Otherwise the method isn't very interesting so it isn't shown here. Download the example to see how it works.
The Paint event handler finishes by resetting the Graphics object's transformation and then drawing a box around the device coordinate rectangle.
Download the example to experiment with it and to see additional details.
|