Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Visual Basic - Compass Gauge... how can I? 1

Status
Not open for further replies.

Varga

Technical User
Mar 28, 2003
43
CA
Hello,

I'm trying to make a VB form that has a compass display on it.
I want to display the reading from a digital compass sensor on a form and I am using Visual Basic 6.0.

I can't find any built-in compass gauges, except for expensive downloads in Aviation packs, and wondered how I could do it.

I thought of using a pic of a compass and changing the rotation as the signal changed, but I only found the options to rotate by 90degree increments with xy flipping.

Is there no way to rotate an image in small increments?

Or to simulate a compass reading?

I would like to set the desired direction of the robot with another compass dial, or preferably a combo compass dial/indicator.


Any help would be appreciated.
Thanks
Varga
 
I only found the options to rotate by 90degree increments with xy flipping.

Is there no way to rotate an image in small increments?

Yes, that 90º increment limitation is a problem. And, whilst there are plenty of VB solutions to samll incremental rotations they all predominantly involve a point by point scanning of the source image and applying a mathematical transform to each point - so they are slow and cumbersome (well, actually some are quite elegant, but they are still slow)

However, over in the VB5&6 forum I illustrated a technique some 7 years ago in thread222-535523 which is dramatically faster and a more powerful (it can scale, and mirror quite happily as well for example)

thread222-1459552 contains a more recent version of the example, illustrating rotation about a specific point
 
Hey,
Thanks for the help strongm.

I messed around with some of those methods, but the redraw "raster" was slow and low quality, and I couldn't get the transformworld one to work.

The solution I cam up with was to use a compass face image, and save 18 versions of the gif at 5degree rotation increments from 0 - 85 degrees. (I'm testing it with a trackbar 0-360 range.) I use Mod to figure out which image, and then a division to determine the quadrant and set the proper RotateFlipType.

I'm updating the picture every timer tick, and have it set to 200ms
Do you have any suggestions to speedup or improve on my idea?

See the code below.

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

Public Class Form1
Dim bmp As Bitmap

Private Sub TrackBar1_Change(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TrackBar1.Scroll
CompassAngle.Text = TrackBar1.Value
End Sub

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
CompassAngle.Text = 0
Timer1.Enabled = True
End Sub

Private Sub UpdateCompass()
Dim pic As String
Dim quadrant As Double
Dim tempInt As Integer
Dim tempMod As Integer

'5 degree increments
tempInt = Int(TrackBar1.Value / 5)

'18 increments per quadrant
tempMod = tempInt Mod 18

If tempMod = 0 Then
pic = "C:\Images\Compass_0degrees.gif"
ElseIf tempMod = 1 Then
pic = "B:\Images\Compass_5degrees.gif"
ElseIf tempMod = 2 Then
pic = "B:\Images\Compass_10degrees.gif"
ElseIf tempMod = 3 Then
pic = "B:\Images\Compass_15degrees.gif"
ElseIf tempMod = 4 Then
...

ElseIf tempMod = 16 Then
pic = "B:\Images\Compass_80degrees.gif"
ElseIf tempMod = 17 Then
pic = "B:\Images\Compass_85degrees.gif"
End If

'quadrant has 18 increments
quadrant = tempInt / 18

bmp = System.Drawing.Bitmap.FromFile(pic)
PictureBox1.Image = bmp

If quadrant < 1 Then
PictureBox1.Image.RotateFlip(RotateFlipType.RotateNoneFlipNone)
ElseIf quadrant < 2 Then
PictureBox1.Image.RotateFlip(RotateFlipType.Rotate270FlipNone)
ElseIf quadrant < 3 Then
PictureBox1.Image.RotateFlip(RotateFlipType.Rotate180FlipNone)
ElseIf quadrant < 4 Then
PictureBox1.Image.RotateFlip(RotateFlipType.Rotate90FlipNone)
Else '= 360
PictureBox1.Image.RotateFlip(RotateFlipType.RotateNoneFlipNone)
End If
End Sub

Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
Call UpdateCompass()
End Sub
End Class

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

Thanx again for the help,
Varga
 
What problem are you having with the SetWorldTransform method?

I'm guessing that you can't get t working as written in my examples because you are, it now appears, actually using VB.NET, and not as you said "I am using Visual Basic 6.0"
 
Hey strongm,

Sorry I forgot I upgraded to, and am now using, Visual Basic 2008 Express.

That's the main reason why the SetWorldTransform wouldn't work as certain commands were not recognized...

My method works, crude as it is, but would the SetWorldTransform be better/faster/more efficient?


I am willing to take another stab at SetWorldTransform if you think it would be better...

Please let me know,
Thanks
Varga
 
If you've switched to VB 2008, then you are using .NET which means you can use the Graphics class of the System.Drawing namespace, which has transform methods built-in that do the same thing as SetWorldTransform (e.g. MultiplyTransform, ResetTransform, RotateTransform, ScaleTransform, TransformPoints and TranslateTransform) and a Transform property.

Here's the MSDN page that documents these
 
Hey strongm,
I'm trying all that stuff, but so frustrated I'm ready to give up.

I finally got the e.Graphics.Drawing stuff to draw something. (Thanks to ...but I couldn't get anything more than a circle and square, and need to rotate an image.
(So that led me to 'Drawing.Graphics.FromImage')

I don't understand the "e" PaintEvent args...
I can get the code below to run, but how do I call the main function? What do I put as an "e" argument in the call line?

If I get my image into a drawing, then get the drawing output to output on the form, then transform/rotate it (about it's center point), then I'll be happy.

(And do I just put the 'Compass.jpg' file in the bin or root folder? Or do I need the full path?)

Imports graphics
Public Class Form1
Public Shared Function FromImage( _
ByVal image As Image _
) As Drawing.Graphics

End Function

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'FromImageImage2(???)
End Sub
Private Sub FromImageImage2(ByVal e As PaintEventArgs)

' Create image.
Dim imageFile As Image = Image.FromFile("Compass.bmp")

' Create graphics object for alteration.
Dim newGraphics As Drawing.Graphics = Drawing.Graphics.FromImage(imageFile)

' Alter image.
newGraphics.FillRectangle(New SolidBrush(Color.Black), _
100, 50, 100, 100)

' Draw image to screen.
e.Graphics.DrawImage(imageFile, New PointF(0.0F, 0.0F))

' Dispose of graphics object.
newGraphics.Dispose()
End Sub

End Class


Your help IS appreciated.
Thanks
Varga
 
Here's what I hope is a pretty straightforward example. You simply need a form with a timer, and then paste in the following code. Note that I am deliberately using a relatively large image (500 * 472 pixels) to show that applying the transforms is quick.
Code:
[blue]Public Class Form1
    ' Lazily use some form-wide variables for this example
    Private myImage As Image 'to contain our source image
    Private myGraphics As Drawing.Graphics 'represents our drawing canvas that we can manipulate

    ' Each tick increases the rotation 
    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        Static Angle As Long

        PictureBox1.Refresh()
        myGraphics.ResetTransform()

        '' calculated centre for general images that we want to rotate around their centre point
        'myGraphics.TranslateTransform(myImage.Width / 2, myImage.Height / 2) ' move drawing origin
        'myGraphics.RotateTransform(Angle) ' apply a rotation transform of Angle degrees
        '' Now draw our source image with the above two transforms applied
        'myGraphics.DrawImage(myImage, New Rectangle(-myImage.Width / 2, -myImage.Height / 2, myImage.Width, myImage.Height)) ' CInt(-myImage.Width / 2), CInt(-myImage.Height / 2))

        ' if using the compass picture referenced above the actual centre of the compass
        ' is not quite in the centre of the image, so we use a hard-coded point for the centre
        ' rather than calculated centre
        myGraphics.TranslateTransform(247, 239)  ' move drawing origin
        myGraphics.RotateTransform(Angle) ' apply a rotation transform of Angle degrees
        ' Now draw our source image with the above two transforms applied
        myGraphics.DrawImage(myImage, New Rectangle(-247, -239, myImage.Width, myImage.Height)) ' CInt(-myImage.Width / 2), CInt(-myImage.Height / 2))

        myGraphics.RotateTransform(-Angle)
        Dim point0 As New Point(0, 5)
        Dim point1 As New Point(-5, 0)
        Dim point3 As New Point(5, 0)
        Dim point2 As New Point(0, -myImage.Height / 2.5)
        Dim Pointer As Point() = {point0, point1, point2, point3}
        myGraphics.FillPolygon(Brushes.Red, Pointer)

        Angle = (Angle + 3) Mod 360
    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim filename As String

        ' Initialise variables ready for example
        filename = "c:\transair_compass_rose.jpg" 'sourced for this example from [URL unfurl="true"]http://www.transair.co.uk/images/2007images/transair_compass_rose.jpg[/URL]
        myImage = Image.FromFile(filename)

        PictureBox1.Width = myImage.Width
        PictureBox1.Height = myImage.Height
        myGraphics = PictureBox1.CreateGraphics
        ' Uncommenting the below line will slow the drawing of the rotated image down but increase its visual quality
        ' Note that you can select a different InterpolationMode settings to balance speed against quality
        ' myGraphics.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic 
        myGraphics.SmoothingMode = Drawing2D.SmoothingMode.HighQuality ' high quality antialiasing will be applied to line drawing 
        Timer1.Interval = 250
        Timer1.Enabled = True
    End Sub
End Class[/blue]
 
Hey strongm,

Awesome. I tries it out and it works.
And I understand it enough that I should be able to modify it for my purposes.

You've been a great help!

Thanks
Varga
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top