Download as pdf or txt
Download as pdf or txt
You are on page 1of 8

28/9/21 19:27 Map device coordinates to world coordinates in C# - C# HelperC# Helper

C# Helper
Tips, tricks, and example programs for
C# programmers.

Map device coordinates to world coordinates in C#


Posted on January 17, 2018 by Rod Stephens

Sometimes it’s convenient to draw in one coordinate system (called world


coordinates) and map those coordinates to the screen’s device
coordinates. The example Map points between coordinate systems in C#
shows how to do this in C#.

For example, the picture shown here draws ellipses. The axes show the X
and Y coordinate systems used. For example, the blue ellipse is about 1
unit wide and 3 units tall.

The program uses a transformation to scale and translate the drawing so


the ellipses are centered and drawn at a reasonable size. Without the
transformation, the ellipses would be tiny little marks just a few pixels in size in the PictureBox control’s upper left
corner.

That much is described by the earlier example. The new feature here is that the program allows the user to click
and drag to define new ellipses. The reason this is not trivial is that the picture is drawn with the transformation

csharphelper.com/blog/2018/01/map-device-coordinates-to-world-coordinates-in-c/ 1/8
28/9/21 19:27 Map device coordinates to world coordinates in C# - C# HelperC# Helper

but the PictureBox control’s mouse events use normal device coordinates. If you use those coordinates, then any
new ellipses would be huge and not centered property after they were transformed.

The solution to this problem is to transform the mouse coordinates by using the inverse of the transformation
used to draw the ellipses. For example, the drawing transformation enlarges the ellipses so they have a reasonable
size. The inverse transformation reduces the mouse coordinates during a click and drag so the resulting ellipse is
small enough to draw correctly when modified by the drawing transformation.

That’s the theory. Here’s the code.

The following shows how the program stores information about the ellipses.

// The user's ellipses.

private List<RectangleF> Ellipses = new List<RectangleF>();

private List<Color> Colors = new List<Color>();

// Used while drawing a new ellipse.

private bool Drawing = false;

private PointF StartPoint, EndPoint;

// The transformations.

private Matrix Transform = null, InverseTransform = null;

private const float DrawingScale = 50;

// The world coordinate bounds.

private float Wxmin, Wxmax, Wymin, Wymax;

csharphelper.com/blog/2018/01/map-device-coordinates-to-world-coordinates-in-c/ 2/8
28/9/21 19:27 Map device coordinates to world coordinates in C# - C# HelperC# Helper

This code defines lists to hold the ellipses and their colors. The Drawing, StartPoint, and EndPoint variables are used
to let the user click and drag to create a new ellipse.

The Transform and InverseTransform variables are the matrices used to transform the drawing and to find the
inverse points for mouse coordinates.

Finally Wxmin, Wxmax, Wymin, and Wymax store the world coordinates used to draw the ellipses.

When the form resizes, the following code executes.

// Create new transformations to center the drawing.

private void Form1_Resize(object sender, EventArgs e)

CreateTransforms();

picCanvas.Refresh();

This code calls the following CreateTransforms method and then refreshes the PictureBox.

// Create the transforms.

private void CreateTransforms()

// Make the draw transformation. (World --> Device)

Transform = new Matrix();

Transform.Scale(DrawingScale, DrawingScale);

float cx = picCanvas.ClientSize.Width / 2;

float cy = picCanvas.ClientSize.Height / 2;

csharphelper.com/blog/2018/01/map-device-coordinates-to-world-coordinates-in-c/ 3/8
28/9/21 19:27 Map device coordinates to world coordinates in C# - C# HelperC# Helper

Transform.Translate(cx, cy, MatrixOrder.Append);

// Make the inverse transformation. (Device --> World)

InverseTransform = Transform.Clone();

InverseTransform.Invert();

// Calculate the world coordinate bounds.

Wxmin = -cx / DrawingScale;

Wxmax = cx / DrawingScale;

Wymin = -cy / DrawingScale;

Wymax = cy / DrawingScale;

This method makes a new Matrix object named Transform. It uses the object’s Scale method to apply a scaling
transformation to enlarge the drawing. The code then uses the object’s Translate method to add another
transformation to the Matrix to center the drawing in the PictureBox.

That completes the drawing transformation. It first scales and then translates the drawing.

Now the code makes a clone of the drawing transformation and calls the new Matrix object’s Invert method to
invert it. This is the transformation that maps from device (mouse) coordinates into world coordinates. (Basically
it does the opposite of whatever the drawing transformation does.)

The method finishes by calculating the minimum and maximum X and Y coordinates that will appear in the
drawing area. (It uses them to decide how long to draw the axes.)

The following code shows how the program uses the drawing transformation.

csharphelper.com/blog/2018/01/map-device-coordinates-to-world-coordinates-in-c/ 4/8
28/9/21 19:27 Map device coordinates to world coordinates in C# - C# HelperC# Helper

// Draw.

private void picCanvas_Paint(object sender, PaintEventArgs e)

// If we don't have the transforms yet, get them.

if (Transform == null) CreateTransforms();

e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;

e.Graphics.Transform = Transform;

// Use a pen that isn't scaled.

using (Pen thin_pen = new Pen(Color.Black, 0))

// Draw the axes.

float tic = 0.25f;

thin_pen.Width = 2 / DrawingScale;

e.Graphics.DrawLine(thin_pen, Wxmin, 0, Wxmax, 0);

for (int x = (int)Wxmin; x <= Wxmax; x++)

e.Graphics.DrawLine(thin_pen, x, -tic, x, tic);

e.Graphics.DrawLine(thin_pen, 0, Wymin, 0, Wymax);

for (int y = (int)Wymin; y <= Wymax; y++)

e.Graphics.DrawLine(thin_pen, -tic, y, tic, y);

// Draw the ellipses.

thin_pen.Width = 0;

for (int i = 0; i < Ellipses.Count; i++)

using (Brush brush =

new SolidBrush(Color.FromArgb(128, Colors[i])))

e.Graphics.FillEllipse(brush, Ellipses[i]);

thin_pen.Color = Colors[i];

csharphelper.com/blog/2018/01/map-device-coordinates-to-world-coordinates-in-c/ 5/8
28/9/21 19:27 Map device coordinates to world coordinates in C# - C# HelperC# Helper

e.Graphics.DrawEllipse(thin_pen, Ellipses[i]);

// Draw the new ellipse.

if (Drawing)

thin_pen.Color = Color.Black;

e.Graphics.DrawEllipse(thin_pen,

Math.Min(StartPoint.X, EndPoint.X),

Math.Min(StartPoint.Y, EndPoint.Y),

Math.Abs(StartPoint.X - EndPoint.X),

Math.Abs(StartPoint.Y - EndPoint.Y));

If the program hasn’t created the transformations yet, it calls CreateTransforms to do so now.

Next, the program sets the Graphics object’s SmoothingMode property to get a smooth picture. It also sets the object’s
Transform property to the drawing transformation matrix.

The code then creates a Pen with width 0. That width tells the program to draw with one-pixel-wide lines no matter
what transformations are in effect. (If you don’t do this, then the pen is scaled by the drawing transformation so
the ellipses are drawn with huge edges.)

The rest of the method is reasonably straightforward. It draws the axes and then loops through the ellipses
drawing them. If the program is in the middle of drawing a new ellipse because the mouse is down, the method
finishes by drawing it.

csharphelper.com/blog/2018/01/map-device-coordinates-to-world-coordinates-in-c/ 6/8
28/9/21 19:27 Map device coordinates to world coordinates in C# - C# HelperC# Helper

The following code shows how the program uses the inverse transformation to map from mouse (device)
coordinates to world coordinates.

// Convert from device coordinates to world coordinates.

private PointF DeviceToWorld(PointF point)

PointF[] points = { point };

InverseTransform.TransformPoints(points);

return points[0];

The Matrix class provides a TransformPoints method that transforms an array of points by applying its
transformation. The DeviceToWorld method takes a point in device coordinates as a parameter. It creates an array
holding that point and calls the inverse transformation matrix’s TransformPoints method to transform the point
into world coordinates. It then returns the converted point.

The rest of the program’s code is fairly straightforward. The mouse events that let the user click and drag use the
DeviceToWorld method to convert mouse coordinates into device coordinates. For example, the following code
shows the PictureBox control’s MouseDown event handler.

// Let the user draw a new ellipse.

private void picCanvas_MouseDown(object sender, MouseEventArgs e)

Drawing = true;

// Get the start and end points.

StartPoint = DeviceToWorld(e.Location);

csharphelper.com/blog/2018/01/map-device-coordinates-to-world-coordinates-in-c/ 7/8
28/9/21 19:27 Map device coordinates to world coordinates in C# - C# HelperC# Helper

EndPoint = StartPoint;

This is just like any other click and drag mouse event except it calls DeviceToWorld.

Download the example to see the rest of the code.

     

This entry was posted in drawing, graphics, transformations and tagged C#, C# programming, coordinates, device coordinates, drawing, example, example program, graphics,
transformations, Windows Forms programming, world coordinates. Bookmark the permalink.

C# Helper
Proudly powered by WordPress.

csharphelper.com/blog/2018/01/map-device-coordinates-to-world-coordinates-in-c/ 8/8

You might also like