Transformation of World coordinates to screen coordinates

  • Thread starter Bruce Schechter
  • Start date
B

Bruce Schechter

I am creating a custom control, "Graph", which will draw a set of graphs of
data on a normal Cartesian (x,y) coordinate system. The max and min values
of both x and y and determined on the fly based on the specific range of
data being plotted.
I am (for my first time) using GDI+ to do the World coordinates to screen
coordinates transformation using the Graphics.Transform method via a Matrix
class object I built via one of the Matrix class constructors.
(Specifically, I'm using the constructor of the form: Matrix(RectangleF,
PointF[]); )

When I first mocked up the code, I got no points drawn in my control. Ater
hours of debugging, I discovered that the control is trying to plot points
which are basically correct, except that each y coordinate is the negative
of what it should be. Thus, no points were displayed in the custom control
but rather were off-scale in the negative direction.

As a "work around", I found that I can just scale the transformation matrix
by -1 in the y direction, and then plotted points are correct. But I really
want to get to the bottom of my problem so that I can prevent other related
problems in the future.

Specifically, I would appreciate a pointer to where is the problem in my
code below.

Thanks,
Bruce

----------------------------------------------------------------
// Per the online documentation of the Matrix class constructor....
// PointF[] below is an array of three PointF structures that represents the
points
// of a parallelogram to which the upper-left, upper-right, and lower-left
corners
// of the rectangle (rectFWorld) is to be transformed. The lower-right
// corner of the parallelogram is implied by the first three corners.....

// W == world coordinates.
// These four variables determine the range of data to be plotted on each
axis.
float XWMin, YWMin, XWMax, YWMax;
XWMin = bizLayer.XMin;
XWMax = bizLayer.XMax;
YWMin = bizLayer.YMin;
YWMax = bizLayer.YMax;
rectFWorld = new RectangleF( XWMin, YWMax, XWMax-XWMin, YWMax-YWMin );

// Coordinates in pixels, which define the boundary of
// this Graph control instance.... These will construct a PointF[] below...
float XMin, YMin, XMax, YMax;
XMin = 0;
XMax = this.Width;
YMin = this.Height; // Since (0,0) is in upper left on a control.
YMax = 0;

Matrix matrix = new Matrix( rectFWorld,
new PointF[] { new PointF( XMin, YMax ),
new PointF( XMax, YMax ), new PointF( XMin, YMin ) } );

e.Graphics.Transform = matrix;
float penWidth = (YWMax-YWMin)/this.Height;
pen = new Pen( System.Drawing.Brushes.Gray, penWidth );

// Draw X axis...
path = new GraphicsPath();
path.AddLine( XWMin, 0f, XWMax, 0f );
e.Graphics.DrawPath( pen, path );

// Draw Y axis...
path.Reset();
path.AddLine( 0f, YWMin, 0f, YWMax );
e.Graphics.DrawPath( pen, path );
pen.Dispose();

etc...
 
Y

Ying-Shen Yu[MSFT]

Hi Bruce,

Looking at your code, it seems we should define the world coordinate
rectangle as below:
RectangleF rectFWorld = new RectangleF( XWMin, YWMin, XWMax-XWMin,
YWMax-YWMin );
or we will get the rectangle area below the area we needed.
For further information , please refer to :
<Coordinate Systems and Transformations >
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdicpp/GDIP
lus/AboutGDIPlus/CoordinateSystemsandTransformations.asp

Does it solve your problem?
Please feel free to reply this thread, if you have anything unclear on this
issue.
Thanks!

Best regards,

Ying-Shen Yu [MSFT]
Microsoft community Support
Get Secure! - www.microsoft.com/security

This posting is provided "AS IS" with no warranties and confers no rights.
This mail should not be replied directly, please remove the word "online"
before sending mail.
 
B

Bruce Schechter

Hi Ying-Shen,

I made the change you suggested, and it helped. This time I actually had my
graph on the custom control. However, the graph was reversed (upside-down)
in the y direction. So I switched my values of YMin and YMax (even though I
wouldn't have expected this to work!) and now the graph diplays exactly like
it should. My new version of the code is below, in case it can be of help
to anyone else trying to do the same thing.

Hopefully, the documentation for the Matrix(RectangleF, PointF[])
constructor will be much better in the next release of the dotnet
documentation.

Thanks for your help!

cheers, Bruce

----------------------------------------------

private Matrix GetTransformMatrix()
{
Matrix matrix;
// W == world coordinates
float XWMin, YWMin, XWMax, YWMax;
XWMin = m_bizLayer.XMin;
XWMax = m_bizLayer.XMax;
YWMin = m_bizLayer.YMin;
YWMax = m_bizLayer.YMax;

// Per the online documentation of the Matrix class constructor....
// PointF[] below is an array of three PointF structures that represents
the points
// of a parallelogram to which the upper-left, upper-right, and
lower-left corners
// of the rectangle (rectFWorld) is to be transformed. The lower-right
corner of
// the parallelogram is implied by the first three corners.

RectangleF rectFWorld = new RectangleF( XWMin, YWMin,
XWMax-XWMin, YWMax-YWMin );

// Coordinates in pixels, which define the boundary of
// this Graph control instance. These will construct a PointF[] below...
float XMin, YMin, XMax, YMax;
XMin = 0;
XMax = this.ClientRectangle.Width;
YMin = 0;
YMax = this.ClientRectangle.Height;

matrix = new Matrix( rectFWorld,
new PointF[] { new PointF( XMin, YMax ), new PointF( XMax, YMax ),
new PointF( XMin, YMin ) } );
return matrix;
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top