Groups | Blog | Home
all groups > dotnet drawing api > august 2006 >

dotnet drawing api : Scale transforms, again


James Parsly
8/2/2006 10:45:35 AM
Here is an example of drawing a simple sine curve plot using VB 6 code.
The code for the rotated label is pretty ugly, but it works (I've been doing
it
in a similar fashion all the way back to GWBASIC). I'm sure that part will
be a lot simpler in .net.

What I'd like to see is VB.NET code that accomplishes the same thing
using its scale transformation, text, and line drawing methods.

'
' set data ranges for the plot axes
'
xmin = 90
xmax = 270
xstep = 30
ymin = -1
ymax = 1
ystep = 0.5
'
' compute range for the coordinate system, providing
' margins for axis labels
'
xmin2 = xmin - 0.2 * (xmax - xmin)
xmax2 = xmax + 0.2 * (xmax - xmin)
ymin2 = ymin - 0.2 * (ymax - ymin)
ymax2 = ymax + 0.2 * (ymax - ymin)
'
' set up the scale
'
Picture1.Scale (xmin2, ymax2)-(xmax2, ymin2)
'
' make a box
'
Picture1.ForeColor = QBColor(0)
Picture1.Line (xmin, ymin)-(xmax, ymax), QBColor(0), B
'
' label y axis
'
For i = ymin To ymax Step ystep
Picture1.CurrentX = xmin
Picture1.CurrentY = i
Picture1.ScaleMode = 3 'switch to pixels
Picture1.Line -(Picture1.CurrentX - 5, Picture1.CurrentY) 'draw tic mark
t$ = Format$(i, "#0.0")
'
' set location for text, so that it is centered around the tic mark
'
Picture1.CurrentX = Picture1.CurrentX - Picture1.TextWidth(t$ + " ")
Picture1.CurrentY = Picture1.CurrentY - Picture1.TextHeight(t$) / 2
Picture1.Print t$;
Picture1.Scale (xmin2, ymax2)-(xmax2, ymin2) 'restore coordinate system
Next i
'
' label x axis
'
For i = xmin To xmax Step xstep
Picture1.CurrentY = ymin
Picture1.CurrentX = i
Picture1.ScaleMode = 3 'switch to pixels
Picture1.Line -(Picture1.CurrentX, Picture1.CurrentY + 5) 'draw tic mark
t$ = Format$(i, "##0")
'
' set location for text, so that it is centered around the tic mark
'
Picture1.CurrentX = Picture1.CurrentX - Picture1.TextWidth(t$) / 2
Picture1.CurrentY = Picture1.CurrentY + Picture1.TextHeight(t$) / 4
Picture1.Print t$;
Picture1.Scale (xmin2, ymax2)-(xmax2, ymin2)
Next i
Picture1.DrawWidth = 2 'draw a line 2 pixels wide
For x = 90 To 270
y = Sin(x * 3.14159265 / 180)
If x = 90 Then Picture1.CurrentX = x: Picture1.CurrentY = y
Picture1.Line -(x, y), QBColor(12) 'qbcolor(12) is red
Next x
Picture1.DrawWidth = 1
'
' draw Y axis title (it's ugly, but it works; for printer an api call would
be
' used)
'
' set location to middle of y axis, and offset enough to the left to
' avoid y axis labels
'
Picture1.CurrentX = xmin - Picture1.TextWidth("XXXXXXX")
Picture1.CurrentY = (ymax + ymin) / 2
Picture1.ScaleMode = 3 'switch to pixels
x = Picture1.CurrentX
y = Picture1.CurrentY
'
' got to top left corner and print label, to use as a pattern
'
Picture1.CurrentX = 0
Picture1.CurrentY = 0
t$ = "Amplitude"
Picture1.Print t$;
'
' loop through the pattern. if a pixel is black, erase it
' and draw a corresponding pixel with X and Y switched at the
' label location
'
For i = 0 To Picture1.TextWidth(t$) - 1
For j = 0 To Picture1.TextHeight(t$) - 1
If Picture1.Point(i, j) = QBColor(0) Then
Picture1.PSet (i, j), Picture1.BackColor
Picture1.PSet (x + j - 1, y + Picture1.TextWidth(t$) / 2 - i),
QBColor(0)
End If
Next j
Next i

James Parsly
8/7/2006 12:23:01 PM
No takers?
[quoted text, click to view]

Bob Powell [MVP]
8/7/2006 9:35:33 PM
[quoted text, click to view]
using its scale transformation, text, and line drawing methods.

That's called consulting. Now, if you have a question you'd like
answered.....

--
Bob Powell [MVP]
Visual C#, System.Drawing

Ramuseco Limited .NET consulting
http://www.ramuseco.com

Find great Windows Forms articles in Windows Forms Tips and Tricks
http://www.bobpowell.net/tipstricks.htm

Answer those GDI+ questions with the GDI+ FAQ
http://www.bobpowell.net/faqmain.htm

All new articles provide code in C# and VB.NET.
Subscribe to the RSS feeds provided and never miss a new article.



[quoted text, click to view]

James Parsly
8/9/2006 2:26:33 PM
The example was intended to answer several questions at once. At the
moment,
I've got both VB6 and VB.NET installed, but I generally prefer VB 6, because
I already know how to do everthing. The example I included, I was able to
toss together in 15 minutes, because I write a lot of this sort of charting
code .

Every time I think about trying .NET, I am stumped by how different
everything is.

But if you want questions, I can do that too:

1. In VB 6, a user coordinate system is set up using the SCALE method:

picture1.scale (xmin,ymax)-(xmax,ymin)

create a coordinate system with (xmin,ymin) is at the lower left-hand
corner
of picture1, and (xmax,ymax) is at the upper right-hand corner.

Given (xmin,ymin) and (xmax,ymax) what commands are required to do the
same thing in VB.NET? From what I have read, it will require a
translatetranform, a scaletransform, and a rotation.

I think this is getting close, but it doesn't have the rotation to put
ymin at the bottom:
xs = PictureBox1.Width / (xmax - xmin)

ys = PictureBox1.Height / (ymax - ymin)

g.TranslateTransform(-xmin, -ymin, Drawing2D.MatrixOrder.Append)

g.ScaleTransform(xs, ys, Drawing2D.MatrixOrder.Append)

2. Having created my coordinate system, I want to move to a spot and
print some text. This scrap of code makes tics mark the width of the
letter "x", Then attempts
to print some text close to the tic marks. As shown, the code produces
text that is
the wrong size. I greatly suspect that if I had flipped the Y axis, it
would also be upside down.

yy = e.Graphics.MeasureString("x", PictureBox1.Font)

For i = ymin2 To ymax2 Step 5

g.DrawLine(mypen, xmin2, i, xmin2 - yy.Width / xs, i)

g.DrawString(Str(i), PictureBox1.Font, Brushes.Black, xmin2, i)

Next

What would I add to the code to make the text show up normally?
What would I do if I wanted the text size to be normal, but I wanted the
text rotated 90 degrees?






[quoted text, click to view]

Bob Powell [MVP]
8/9/2006 9:30:58 PM
See the GDI+ FAQ for how to define a transform that enables you to flip the
Y axis AND how to draw the text the right way up.

--
Bob Powell [MVP]
Visual C#, System.Drawing

Ramuseco Limited .NET consulting
http://www.ramuseco.com

Find great Windows Forms articles in Windows Forms Tips and Tricks
http://www.bobpowell.net/tipstricks.htm

Answer those GDI+ questions with the GDI+ FAQ
http://www.bobpowell.net/faqmain.htm

All new articles provide code in C# and VB.NET.
Subscribe to the RSS feeds provided and never miss a new article.



[quoted text, click to view]
Bob Powell [MVP]
8/9/2006 9:31:56 PM
And see the GDI+ FAQ for how to rotate text..

--
Bob Powell [MVP]
Visual C#, System.Drawing

Ramuseco Limited .NET consulting
http://www.ramuseco.com

Find great Windows Forms articles in Windows Forms Tips and Tricks
http://www.bobpowell.net/tipstricks.htm

Answer those GDI+ questions with the GDI+ FAQ
http://www.bobpowell.net/faqmain.htm

All new articles provide code in C# and VB.NET.
Subscribe to the RSS feeds provided and never miss a new article.



[quoted text, click to view]
James Parsly
8/10/2006 12:07:15 PM
OK.Using the info from the GDI+ FAQ, I think I've got it working. The main
sticking point was
figuring out what I had to add to the example to account for scaling. Here's
the code I came up
with:

Dim g As Graphics = e.Graphics

Dim xmin As Single, xmax As Single, ymin As Single, ymax As Single

Dim xmin2 As Single, xmax2 As Single, ymin2 As Single, ymax2 As Single

Dim i As Single

Dim yy As SizeF

Dim xx As SizeF

Dim y As Single, y2 As Single

'

' set up the coordinate system

'

xmin2 = 30

xmax2 = 270

ymin2 = -1

ymax2 = 1

xmin = xmin2 - 0.2 * (xmax2 - xmin2)

xmax = xmax2 + 0.2 * (xmax2 - xmin2)

ymin = ymin2 - 0.2 * (ymax2 - ymin2)

ymax = ymax2 + 0.2 * (ymax2 - ymin2)

Dim mypen As New Pen(Color.Red, 2) 'make a pen with drawing width 2

Dim mypen2 As New Pen(Color.Red, 2)

Dim xs As Single, ys As Single

xs = PictureBox1.Width / (xmax - xmin)

ys = PictureBox1.Height / (ymax - ymin)

'

'

Dim mx As New Drawing2D.Matrix(1, 0, 0, -1, 0, PictureBox1.Height)

g.Transform = mx

g.ScaleTransform(xs, ys, Drawing2D.MatrixOrder.Prepend)

g.TranslateTransform(-xmin, -ymin, Drawing2D.MatrixOrder.Prepend)

'

' scale the pen so that it will draw correctly

'

mypen.ScaleTransform(1 / (xs), 1 / (ys))

'

' make a box

'

g.DrawLine(mypen, xmin2, ymin2, xmin2, ymax2)

g.DrawLine(mypen, xmin2, ymax2, xmax2, ymax2)

g.DrawLine(mypen, xmax2, ymax2, xmax2, ymin2)

g.DrawLine(mypen, xmax2, ymin2, xmin2, ymin2)

'

' label the y axis

'

Dim gs As Drawing2D.GraphicsState

Dim mx1 As Drawing2D.Matrix

For i = ymin2 To ymax2 Step 0.25

gs = g.Save

Dim mx2 As New Drawing2D.Matrix(1, 0, 0, -1, (xmin2 - xmin) * xs, (i - ymin)
* ys)

mx1 = mx.Clone

mx1.Multiply(mx2)

g.Transform = mx1

g.DrawLine(mypen2, 0, 0, -5, 0)

xx = g.MeasureString("XXXX", PictureBox1.Font)

g.DrawString(Str(i), PictureBox1.Font,
Brushes.Black, -xx.Width, -Font.Height / 2)

g.Restore(gs)

Next i

'

' label the x axis

'

For i = xmin2 To xmax2 Step 30

gs = g.Save

Dim mx2 As New Drawing2D.Matrix(1, 0, 0, -1, (i - xmin) * xs, (ymin2 - ymin)
* ys)

mx1 = mx.Clone

mx1.Multiply(mx2)

g.Transform = mx1

g.DrawLine(mypen2, 0, 0, 0, 5)

xx = g.MeasureString(Trim(Str(i)), PictureBox1.Font)

g.DrawString(Trim(Str(i)), PictureBox1.Font, Brushes.Black, -xx.Width / 2,
Font.Height / 2)

g.Restore(gs)

Next i

'

' put a rotated title on the y axis

'

gs = g.Save

xx = g.MeasureString("XXXX", PictureBox1.Font)

Dim mx3 As New Drawing2D.Matrix(1, 0, 0, -1, (xmin2 - xx.Width - xmin) * xs,
((ymax2 + ymin2) / 2 - ymin) * ys)

mx1 = mx.Clone

mx1.Multiply(mx3)

g.Transform = mx1

g.RotateTransform(270)

yy = g.MeasureString("Amplitude", PictureBox1.Font)

g.DrawString("Amplitude", PictureBox1.Font, Brushes.Black, -yy.Width / 2, 0)

g.Restore(gs)

'

' make a sine curve

'

For i = 30 To 269

y = Math.Sin(i * 3.14159265 / 180)

y2 = Math.Sin((i + 1) * 3.14159265 / 180)

g.DrawLine(mypen, i, y, i + 1, y2)

Next i



[quoted text, click to view]
AddThis Social Bookmark Button