Graphic transformations
I'm working with data (stuff like Sin/Cosin waves, etc) that repeat with frequency M. I've written a simple display control where it takes the data and paints connected lines to represent the data in a pretty picture.
My question is, the data is given where if painted onto a bitmap, quadrant 1 data is in quadrant 3 and quadrant 2 data is in quadrant 4 (and vice versa).
The bitmap is of width M and hight array.Max - array.Min
.
Is there a simple transform for changing the data so it will display in the appropriate quadrants?
A good way of thinking about it is that (0,0) in world coordinates is divided between
(0,0), (width, 0), (0,height), (width, height)
which would (width/2, height/2) in image coordinates.
From there, the transform would be:
Data(x,y) => x = ABS(x - (width/2)), y = ABS(y - (Height/2))
Graphics.ScaleTransform is not a good idea because it will affect not only layout but also drawing itself (thickness of strokes, texts and so on).
I suggest you to prepare points list and then perform a transformation to them using the Matrix class. This is a small example I made for you, hope it will be helpful.
private PointF[] sourcePoints = GenerateFunctionPoints();
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.Clear(Color.Black);
// Wee need to perform transformation on a copy of a points array.
PointF[] points = (PointF[])sourcePoints.Clone();
// The way to calculate width and height of our drawing.
// Of course this operation may be performed outside this method for better performance.
float drawingWidth = points.Max(p => p.X) - points.Min(p => p.X);
float drawingHeight = points.Max(p => p.Y) - points.Min(p => p.Y);
// Calculate the scale aspect we need to apply to points.
float scaleAspect = Math.Min(ClientSize.Width / drawingWidth, ClientSize.Height / drawingHeight);
// This matrix transofrmation allow us to scale and translate points so the (0,0) point will be
// in the center of the screen. X and Y axis will be scaled to fit the drawing on the screen.
// Also the Y axis will be inverted.
Matrix matrix = new Matrix();
matrix.Scale(scaleAspect, -scaleAspect);
matrix.Translate(drawingWidth / 2, -drawingHeight / 2);
// Perform a transformation and draw curve using out points.
matrix.TransformPoints(points);
e.Graphics.DrawCurve(Pens.Green, points);
}
private static PointF[] GenerateFunctionPoints()
{
List<PointF> result = new List<PointF>();
for (double x = -Math.PI; x < Math.PI; x = x + 0.1)
{
double y = Math.Sin(x);
result.Add(new PointF((float)x, (float)y));
}
return result.ToArray();
}
protected override void OnSizeChanged(EventArgs e)
{
base.OnSizeChanged(e);
Invalidate();
}
Try to invert the y-axis using
g.ScaleTransform(1, -1);
Also remember that for drawing in a scaled context, if you have to, Pen for example takes width as Single in some of its constructors, meaning inversely proportional fractional values can be used to make an invariant compensation for the effect of ScaleTransform.
UPDATE: forget that, Pen has its own local ScaleTransform, so both x an y can be compensated for.
精彩评论