B4A Library High performance compass without DrawBitmapRotated

Since the b4a community has helped me greatly in the past, I am again giving something back.

For an astronomy app I've build, I needed a nice compass with good performance. As so many of us I started out with canvasses, bitmaps and DrawBitmapRotated. But I soon ran into performance issues on low end devices. So I decided to approach the whole issue in a different way and here is the result.

This compass does not use any bitmap processing or canvasses, instead it uses animations. The attached example project does use two bitmaps, but only to make the compass look good. You could make the whole compass by just using panels for instance.

Here's the code:

B4X:
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    Dim Orientation As PhoneOrientation
    Dim tmrUpdater As Timer
End Sub

Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.
    Dim pnlRose As Panel
    Dim Rotation As Animation
    Dim dblAngle As Double
    Dim pnlNeedle As Panel
End Sub

Sub Activity_Create(FirstTime As Boolean)

End Sub

Sub Activity_Resume
    dblAngle = 0
    Activity.LoadLayout("Compass")
    pnlRose.SetBackgroundImage(LoadBitmapSample(File.DirAssets, "compass.png", pnlRose.Width, pnlRose.Width))
    pnlNeedle.SetBackgroundImage(LoadBitmapSample(File.DirAssets, "needle.png", pnlRose.Width/9.6, pnlRose.Width))
    Rotation.InitializeRotateCenter("Animation", dblAngle, dblAngle, pnlNeedle)
    Rotation.Duration = 20000
    tmrUpdater.Initialize("tmrUpdater",100)
    Orientation.StartListening("Orientation")
    tmrUpdater.Enabled = True
End Sub

Sub Activity_Pause (UserClosed As Boolean)
    Dim bmpClear As Bitmap
    bmpClear.InitializeMutable(1,1)
    pnlRose.SetBackgroundImage(bmpClear)
    pnlNeedle.SetBackgroundImage(bmpClear)
End Sub

Sub Animation_AnimationEnd
    Try
        Rotation.Start(pnlNeedle)
    Catch
        Log(LastException.Message)
    End Try
End Sub

Sub Orientation_OrientationChanged (Azimuth As Float, Pitch As Float, Roll As Float)
    dblAngle = -Azimuth
End Sub

Sub tmrUpdater_Tick
    Rotation.InitializeRotateCenter("Animation", dblAngle, dblAngle, pnlNeedle)
    Rotation.Duration = 20000
    Rotation.Start(pnlNeedle)
End Sub

So grab it an run with it!
I would really appreciate it if you would post your refined/upgraded/extended versions of this code here in this topic.
That way we can all benefit from our collective effort to build the ultimate b4a compass.
 

Attachments

  • shot1.png
    shot1.png
    128.9 KB · Views: 790
  • HiPerfCompass.zip
    415.3 KB · Views: 1,210

derez

Expert
Licensed User
Longtime User
Thank you very much for this nice compass and the idea.
I found that in my asus TF101 it works fine but on samsung s2 the direction is opposite, so I added a menu item to enable direction change (dblAngle = Azimuth * direction) where direction is 1 or -1. It probably depends on the way you hold your device.
 
Last edited:

bluejay

Active Member
Licensed User
Longtime User
Thank you very much for this nice compass and the idea.
I found that in my asus TF101 it works fine but on samsung s2 the direction is opposite, so I added a menu item to enable direction change (dblAngle = Azimuth * direction) where direction is 1 or -1. It probably depends on the way you hold your device.

The article below might be relevant...
Compass woes on Android by Little Fluffy Toys Ltd
http://www.littlefluffytoys.mobi/?p=190#more-190
http://www.littlefluffytoys.mobi
 

DTB Radio

Member
Licensed User
Longtime User
Relevant, but for those like me who don't know Java or how to translate it to, or use it in, visual basic-ish code, a bit hard to incorporate into this project.
 

Shahid Saeed

Active Member
Licensed User
Longtime User
What is the possibility to integrate this compass with GPS to a specific Latitude & Longitude; for example I want to determine where the user is and point him to a specif direction using compass.
 

Creaky

Member
Licensed User
Longtime User
I'm pretty certain this can be done, instead of using the azimuth data of the Orientation object, you pass it the calculated angle between the azimuth and the target through dblAngle. I haven't done this before, but I'm sure the forums can help you out with the calculations.
 

Shahid Saeed

Active Member
Licensed User
Longtime User
I'm pretty certain this can be done, instead of using the azimuth data of the Orientation object, you pass it the calculated angle between the azimuth and the target through dblAngle. I haven't done this before, but I'm sure the forums can help you out with the calculations.
I am pretty new to GPS & Compass workaround, I'm trying to combine GPS Tutorial by erel with your example; but getting no luck, that would be great if you can show me the correct path to achieve what I am trying to do?
 

Shahid Saeed

Active Member
Licensed User
Longtime User
I'm pretty certain this can be done, instead of using the azimuth data of the Orientation object, you pass it the calculated angle between the azimuth and the target through dblAngle. I haven't done this before, but I'm sure the forums can help you out with the calculations.
After Extensive search on Internet I found some calculations but When I am implementing; it is not accurate can you help me to define where I am wrong? I am using 2 needles, one is to correct the north angle and second is to show the direction accordingly.

B4X:
Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'These variables can be accessed from all modules.
    Dim Orientation As PhoneOrientation
    Dim tmrUpdater As Timer
    Dim GPS1 As GPS
End Sub

Sub Globals
    'These global variables will be redeclared each time the activity is created.
    'These variables can only be accessed from this module.
    Dim pnlRose As Panel
    Dim Rotation As Animation
    Dim RotationQ As Animation
    Dim dblAngle As Double
    Dim dblAngleQ As Double
    Dim pnlNeedle As Panel
    Dim pnlQibla As Panel
    Dim PageTitle As Label   
    Dim lblLat As Label
    Dim lblLon As Label
    Dim DLat, DLon As Float
End Sub

Sub Activity_Create(FirstTime As Boolean)
    'Do not forget to load the layout file created with the visual designer. For example:
    'Activity.LoadLayout("Layout1")
    If FirstTime Then
        GPS1.Initialize("GPS")
    End If   
   
End Sub

Sub Activity_Resume
    If GPS1.GPSEnabled = False Then
    If Msgbox2("Allow Application to use your current location", "GPS", "Yes allow", "", "Don't allow", LoadBitmap(File.DirAssets,"icon.png")) = DialogResponse.POSITIVE Then
    StartActivity(GPS1.LocationSettingsIntent)   
    End If
   
    Else
        GPS1.Start(0,0)
    End If   
   
    dblAngle = 0
    dblAngleQ = 0
    Dim BG As Bitmap = LoadBitmapSample(File.DirAssets, "bg.jpg", Activity.Width, Activity.Height)
    fnc.SetTiledBackground(Activity, BG)
    Activity.LoadLayout("qibla")
    PageTitle.Text = "Qibla Direction"
   
    pnlRose.SetBackgroundImage(LoadBitmapSample(File.DirAssets, "compass.png", pnlRose.Width, pnlRose.Width))
    pnlNeedle.SetBackgroundImage(LoadBitmapSample(File.DirAssets, "needle.png", pnlRose.Width/9.6, pnlRose.Width))
    pnlQibla.SetBackgroundImage(LoadBitmapSample(File.DirAssets, "qibla.png", pnlRose.Width/9.6, pnlRose.Width))
    Rotation.InitializeRotateCenter("Animation", dblAngle, dblAngle, pnlNeedle)
    RotationQ.InitializeRotateCenter("AnimationQ", dblAngleQ, dblAngleQ, pnlQibla)
    Rotation.Duration = 20000
    RotationQ.Duration = 20000
    tmrUpdater.Initialize("tmrUpdater",100)
    Orientation.StartListening("Orientation")
    tmrUpdater.Enabled = True
End Sub

Sub Activity_Pause (UserClosed As Boolean)
    GPS1.Stop
    Dim bmpClear As Bitmap
    bmpClear.InitializeMutable(1,1)
    pnlRose.SetBackgroundImage(bmpClear)
    pnlNeedle.SetBackgroundImage(bmpClear)
    pnlQibla.SetBackgroundImage(bmpClear)
End Sub
Sub Animation_AnimationEnd
    Try
        Rotation.Start(pnlNeedle)
        RotationQ.Start(pnlQibla)
    Catch
        Log(LastException.Message)
    End Try
End Sub

Sub Orientation_OrientationChanged (Azimuth As Float, Pitch As Float, Roll As Float)
    Dim QLat As Double = 21.422497     'Latitude of the destination
    Dim QLon As Double = 39.826179    'Longtitute of the destination
    Dim lonDelta As Float = (DLon - QLon)
    Dim y As Float = Sin(lonDelta) * Cos(DLat)
    Dim x As Float = Cos(QLat) * Sin(DLat) - Sin(QLat) * Cos(DLat) * Cos(lonDelta)
    Dim qibla As Float = Round(ATan2(y, x))
    dblAngle = -Azimuth
    dblAngleQ = Azimuth - qibla
    lblLat.Text = dblAngle
    lblLon.Text = dblAngleQ   
End Sub

Sub tmrUpdater_Tick
    Rotation.InitializeRotateCenter("Animation", dblAngle, dblAngle, pnlNeedle)
    RotationQ.InitializeRotateCenter("AnimationQ", dblAngleQ, dblAngleQ, pnlQibla)
    Rotation.Duration = 20000
    RotationQ.Duration = 20000
    Rotation.Start(pnlNeedle)
    RotationQ.Start(pnlQibla)
End Sub


Sub GPS_LocationChanged (Location1 As Location)
    DLat = Location1.Latitude
    DLon = Location1.Longitude   
End Sub

Sub GPS_UserEnabled (Enabled As Boolean)
    ToastMessageShow("GPS device enabled = " & Enabled, True)
End Sub
 
Top