Setting a custom coordinate system like VB picturebox.Scale

  • Thread starter Thread starter Randy Vande Hei
  • Start date Start date
R

Randy Vande Hei

Does anyone know how to change the the GDI+ coordinate system like you used
to be able to do in VB6 with the picturebox.scale method. The
picturebox.scale method took an x,y point defining the upper left corner and
a second x,y point defining the lower right corner.

In VB6 the 0,0 location was the upper left like in GDI+, but I could at
least reset it so I could use it with lat/lons. Basically all I want to do
is be able to use the USA lat/lon coordinates to put a circle at a
particular lat/lon.

I've looked at Graphics.RotateTransform and graphics.TranslateTransform, but
they don't seem to do it for me.

-Randy
 
Hi there,

Have you thought about a simple scaling algorithm to turn your values
into the pixel equivilents? This might be the simplest approach. I wish I
could quote one for you now but I never have been good at maths and it would
require me hunting through zip disks. But I hope the concept helps you as
their isn;t a "scale" method in .NET (That I know of).

Nick.

--
/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
"No matter. Whatever the outcome, you are changed."

Fergus - September 5th 2003
/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
 
Randy,
I've looked at Graphics.RotateTransform and graphics.TranslateTransform, but
they don't seem to do it for me.
You were close ;-)

You need to use Graphics.TranslateTransform along with
Graphics.ScaleTransform.

The trick is to call them in the correct order with the correct parameters.

You need to call TranslateTransform to move the origin to the lower left.
You can use 0 & me.ClientRectangle.Height.

Then you need to call ScaleTransform with 1 & -1 as parameters to flip the y
axis.

Hope this helps
Jay
 
Oops, I stand corrected :-)

Nick.

--
/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
"No matter. Whatever the outcome, you are changed."

Fergus - September 5th 2003
/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
 
Randy Vande Hei said:
Does anyone know how to change the the GDI+ coordinate system like you used
to be able to do in VB6 with the picturebox.scale method. The
picturebox.scale method took an x,y point defining the upper left corner and
a second x,y point defining the lower right corner.

Well, I sorta missed the old Scale method too so I decided to roll my own
once and for all. IIRC, if you wanted to (predictably) draw arcs in VB.OLD
you
really needed to have "square" canvases so this method always uses the
same scaling factor horizontally and vertically. If you don't want/need that
you
need to slightly change the code so that it calculates and uses 2
scalingfactors:
one for the horizontal scaling and one for the vertical scaling.

Private mWorld2DeviceXfm As New System.Drawing.Drawing2D.Matrix()
Private mDevice2WorldXfm As New System.Drawing.Drawing2D.Matrix()

Public Sub SetScale( _

ByVal xupperleft As Integer, ByVal yupperleft As Integer, _

ByVal xlowerright As Integer, ByVal ylowerright As Integer)

Dim XMirrorFactor As Single = CSng(Sign(xlowerright - xupperleft))

Dim ScaleFactor As Single

If Me.Size.Width < Me.Size.Height Then 'remember to compensate for
non-square canvas !

ScaleFactor = CSng(Me.Size.Width) / Abs(xlowerright - xupperleft)

Else

ScaleFactor = CSng(Me.Size.Height) / Abs(yupperleft - ylowerright)

End If

'construct forward matrix (world coord -> device coord)

mWorld2DeviceXfm.Reset()

mWorld2DeviceXfm.Translate( CSng(-xupperleft), CSng(-yupperleft))

mWorld2DeviceXfm.Scale( XMirrorFactor * ScaleFactor, -1! * ScaleFactor,
MatrixOrder.Append)

'also store inverse matrix (device coord -> world coord) for convenience
when hit-testing

If mWorld2DeviceXfm.IsInvertible() Then

mDevice2WorldXfm = mWorld2DeviceXfm.Clone()

mDevice2WorldXfm.Invert()

End If

End Sub



Please note that this method is taken from a custom control that derives
from

System.Windows.Forms.ScrollableControl. That's why Me.Size is used to
determine the

physical size of the canvas we're drawing on. Your situation may be slightly
different so

take care. Also, try to understand what's going on, it will help you to use
it better.



You can use this method in OnPaint like this:



Protected Overrides Sub OnPaint(ByVal e As
System.Windows.Forms.PaintEventArgs)

Dim xlowleft As Integer, ylowleft As Integer

Dim xupright As Integer, yupright As Integer

MyBase.OnPaint(e)

'calculate your xlowleft, ylowleft, xupright, yupright

......

Me.SetScale( xlowleft, ylowleft, xupright, yupright)

e.Graphics.Transform = mWorld2DeviceXfm

'Draw your stuff on the gr object here

........

End Sub



HTH

eltwo
 
Randy Vande Hei said:
Does anyone know how to change the the GDI+ coordinate system like you used
to be able to do in VB6 with the picturebox.scale method. The
picturebox.scale method took an x,y point defining the upper left corner and
a second x,y point defining the lower right corner.

Well, I sorta missed the old Scale method too so I decided to roll my own
once and for all. IIRC, if you wanted to (predictably) draw arcs in VB.OLD
you really needed to have "square" canvases so this method always uses the
same scaling factor horizontally and vertically. If you don't want/need that
you need to slightly change the code so that it calculates and uses 2
scalingfactors: one for the horizontal scaling and one for the vertical
scaling.

Private mWorld2DeviceXfm As New System.Drawing.Drawing2D.Matrix()
Private mDevice2WorldXfm As New System.Drawing.Drawing2D.Matrix()

Public Sub SetScale( _
ByVal xupperleft As Integer, ByVal yupperleft As Integer, _
ByVal xlowerright As Integer, ByVal ylowerright As Integer)

Dim XMirrorFactor As Single = CSng(Sign(xlowerright - xupperleft))
Dim ScaleFactor As Single

' compensate for non-square canvas
If Me.Size.Width < Me.Size.Height Then
ScaleFactor = CSng(Me.Size.Width) / Abs(xlowerright - xupperleft)
Else
ScaleFactor = CSng(Me.Size.Height) / Abs(yupperleft - ylowerright)
End If

' construct forward matrix (world coord -> device coord)
mWorld2DeviceXfm.Reset()
mWorld2DeviceXfm.Translate( CSng(-xupperleft), CSng(-yupperleft))
mWorld2DeviceXfm.Scale( XMirrorFactor * ScaleFactor, -1! * ScaleFactor, _
MatrixOrder.Append)

' also store inverse matrix (device coord -> world coord) for
' convenience when hit-testing
If mWorld2DeviceXfm.IsInvertible() Then
mDevice2WorldXfm = mWorld2DeviceXfm.Clone()
mDevice2WorldXfm.Invert()
End If

End Sub


Please note that this method is taken from a custom control that derives
from System.Windows.Forms.ScrollableControl. That's why Me.Size
is used to determine the physical size of the canvas. Your situation may be
different so take care. So now you can use this method in OnPaint like
this:

Protected Overrides Sub OnPaint( ByVal _
e As System.Windows.Forms.PaintEventArgs)

Dim xupleft As Integer, yupleft As Integer
Dim xloright As Integer, yloright As Integer

MyBase.OnPaint(e)

' calculate your xupleft, yupleft, xloright, yloright
.............................
Me.SetScale( xupleft, yupleft, xloright, yloright)
e.Graphics.Transform = mWorld2DeviceXfm

' draw your stuff on the e.Graphics here
..............................

End Sub



HTH

eltwo
 
That is exactly what I was looking for. Thanks.

I used e.graphics.TranslateTransform (this.ClientRectangle.Width,
this.ClientRectangle.Height) to get the origin over to the bottom right.
So I now have 0,0 a the bottom right. What I need next is to set the upper
limit of x and y so that my plotting can have the affect of zooming.
Again, the vb scale method used to allow this.

i.e. I'd like to be able to fill the window with my plotting regardless of
what size the window is sized to.

-Randy
 
Randy,
You use ScaleTransform to 'zoom' also.

I normally use a ratio of this.ClientSize (which is the same as
this.ClientRectangle.Size) to the size of my drawing. To get the drawing to
fit in the window itself.

You can call ScaleTransform twice, once to flip the drawing, then a second
time to zoom the drawing. Order should not matter.

Hope this helps
Jay
 
Back
Top