B4A Class Open Street Map viewer - GPS

Hi,

This b4Xlib contains a custom view (cvMap) which can display Open Street Map.


screenshot.png
View attachment 109081



The tiles are retrieved from the internet and cached in a database. You can add shapes and images on the map.

UI :
- Lat/lng Center of the map
- Zoom Level
- Compass Direction with rotation
- Scale
- Button Menu
- Grid
- Center
- GPS position and bearing

Event :
- ready
- Lat/lng changed
- Zoom Level Changed
- Compass Direction Changed
- Shape Clicked
- Map Clicked
- Center Lat/lng clicked
- Button Menu clicked
- Scale clicked
- Compass Clicked
- GPS Clicked

Tile Server
2 new properties :
This 2 properties are available in the designer or with setter/getter from the cvmap : userAgent, tileServer

Dependencies :
- Core
- SQL
- OKHttpUtils2
- XUI
- XUI views

Other files in the b4xlib :
- coMapUtilities : code module with Types, functions, helpers
- clTileManager : standard class module to load tile from database and/or internet and save them into the database
- clMapShapeCirgle : standard class to draw circle on the map
- clMapShapeLine : standard class to draw line on the map
- clMapShapePolygon : standard class to draw polygon on the map
- clMapShapeImage : standard class to draw image on the map
- layout cvmap.bal and cvmap.bjl
- images for the compass and gps



How to use it :
- Just add the cvMap custom view with the designer
- create sub to handle events if necessary
- set options (lat/lng, zoom.....)

B4A example and B4J example included



spsp
 

Attachments

  • Screenshot_2021-02-21-11-49-10-222_map.b4A.com.jpg
    Screenshot_2021-02-21-11-49-10-222_map.b4A.com.jpg
    258.3 KB · Views: 1,909
  • B4Xmap.zip
    23 KB · Views: 1,959
  • B4Xmap.b4xlib
    23.7 KB · Views: 845
Last edited:

Domrich_FR

New Member
Hello UDG
Sorry for late answer. Thanks a lot UDG. Work fine now. Most exactly was working fine. I get now a problem downloading tiles. OSM seem to limit seriously the quantity of tiles freely downloaded. (I red 250 of maw zoom). Its a pity as I am still developping my soft. Has somebody experienced that ? Solution?
Dominique
 

Indy

Active Member
Licensed User
Longtime User
Hi,

In cvMap , when the property followGPS is set to true, the map is centered and oriented according the GPS. when this property is set to false, you can move the map.

You can set to false/true this property with a button
Not a bad idea, I never thought of doing it that way. But is there still a way of getting the GPS co-ordinates? I do need them for storing against a record in a database.

Thanks
 

spsp

Active Member
Licensed User
Longtime User
Not a bad idea, I never thought of doing it that way. But is there still a way of getting the GPS co-ordinates? I do need them for storing against a record in a database.

Thanks

The GPS variable is declared in the starter service. You can access it to retrieve the coords.

Other method : If followGPS is set to true the GPS position is in the center of the map, so the CenterLatLng property gives you the GPS position
 
Last edited:

udg

Expert
Licensed User
Longtime User
Hi @spsp ,
in an eventually forthcoming release, do you mind to add a mapLongClicked event? I'd like to use it this way:
mapClicked : add a POI (point of interest) / Show details about POI (eventually on a superimposed panel or somewhere outside the map)
mapLongClicked: remove a POI (if any and following a confirmation)

Due to differences between B4A and B4J, I will name this second kind of click something like mapAltClick ("Alt" for alternative) masking a LongClick (B4A) and a RightClik or a DoubleClick (B4J).

udg
 

spsp

Active Member
Licensed User
Longtime User
Hi,
in cvMap.pas, line 816 in the 'fViewTouch_Touch ' sub you can check if it is a click or longclik (perhaps store a timestamp in the touch dovn) and raise the right event.

spsp


Hi @spsp ,
in an eventually forthcoming release, do you mind to add a mapLongClicked event? I'd like to use it this way:
mapClicked : add a POI (point of interest) / Show details about POI (eventually on a superimposed panel or somewhere outside the map)
mapLongClicked: remove a POI (if any and following a confirmation)

Due to differences between B4A and B4J, I will name this second kind of click something like mapAltClick ("Alt" for alternative) masking a LongClick (B4A) and a RightClik or a DoubleClick (B4J).

udg
 

udg

Expert
Licensed User
Longtime User
Sure. I could derive a lib's version for my own use, but posted here to keep a single official version of it.
Giving it a second thought, we may even have two possible couples of events:
Double click (B4J) - double tap (B4A)
Right button (B4J) - long click (B4A)

Tomorrow I will have a look at it then post here.
 
Last edited:

udg

Expert
Licensed User
Longtime User
A quick test before lunch..
This B4XPages demo manages click, longclick and doubleclick for a panel, both B4J and B4A.
Modify the Sensitivity value for a quicker or slower response.

Note: beware it's just a quick test; I don't know yet if I'll use it to modify cvMap to rise additional events.

Edit 26.04: read post below. I changed my mind and tried a more traditional approach based on click counts.
 

Attachments

  • TestClick.zip
    14.6 KB · Views: 386
Last edited:

udg

Expert
Licensed User
Longtime User
Hi @spsp
Just an update and a hint I hope you may find useful.
Hint: I noted that in cvMap you use CallSub(mCallBack,mEventName & "_<function here>"); I find it safer to precede it with a "if SubExists() then ..", so if the called function is missing in the calling code, no error is raised.
Update: please find attached a modified version of your lib sporting a first attempt to integrate Click-LongClick-DoubleClick actions. It seems to somewhat work.
I set Sensitivity to 500ms and 1500ms for my desktop and phone respectively. This is the time a click action has to be completed in (otherwise is ignored)
In demo's B4xMain I disabled function ShapesClicked so to intercept the click actions generated by the added events. In other words, when using the lib, one has to choose whether to use ShapesClicked or mapDoubleClicked/mapLongClicked.
ps: since on my phone circles where too small and difficult to click on, I lengthened their radius and I also increased the zoom level to 18.

To avoid confusion I named the attached lib dgOSM, but it's still totally your code. Where I added/modified something I placed a comment like "UDG <date>"

Note: as said above, the modified lib works, but it's still a preliminary version.
Note2: I didn't start a new thread because I hope we can have a single lib to grow and update. Eventually PM me.

Edit 26.04: I changed my mind and rewrote my click-actions code using the more traditional click count approach. It seems to work very well. I will upload here the lib after a few more tests. Meanwhile I removed the version based on the state machine technique.

udg
 
Last edited:

udg

Expert
Licensed User
Longtime User
Hi all,
this is the exact code published by @spsp where I added a way to optionally raise a few types of click events both on B4J and B4A platforms. To avoid confusion I renamed it to dgOSM. My contribution is marked by comments starting with "UDG" in the original code.
The events managed are: Click, DoubleClick, LongClick

There are two new properties to set in the Designer for a cvMap: Use touch, Click max interval.
Use touch defaults to False so the lib works as the original one (i.e. you have mapClicked and ShapesClicked events). Set it to True in order to raise events for the above mentioned click actions (mapClicked, mapDoubleClicked, mapLongClicked).
Click max interval (defaults to 500ms) is the total time alloted to complete any of the click actions above. Exceeding it leads to a discarded action (i.e. no event is raised)

On my PC and phone I found that a value of 1000ms (1 second) is enough to correctly work with all three events. You can shorten it for desktop use and may need to increase it for your phone (this is because often phones have a different level of touch sensitivity)

As noted on the previous post, on my phone circles were too small and difficult to click on so I modified the demo available on post#1 increasing the radius to 10-15dpi
dgOSM has maximum zoom level set to 18 (original was 17) . You can change it back modifying its value in coMapUtilities.

udg
 

Attachments

  • dgOSM.b4xlib
    24.5 KB · Views: 398
Last edited:

spsp

Active Member
Licensed User
Longtime User
Hi all,
this is the exact code published by @spsp where I added a way to optionally raise a few types of click events both on B4J and B4A platforms. To avoid confusion I renamed it to dgOSM. My contribution is marked by comments starting with "UDG" in the original code.
The events managed are: Click, DoubleClick, LongClick

There are two new properties to set in the Designer for a cvMap: Use touch, Click max interval.
Use touch defaults to False so the lib works as the original one (i.e. you have mapClicked and ShapesClicked events). Set it to True in order to raise events for the above mentioned click actions (mapClicked, mapDoubleClicked, mapLongClicked).
Click max interval (defaults to 500ms) is the total time alloted to complete any of the click actions above. Exceeding it leads to a discarded action (i.e. no event is raised)

On my PC and phone I found that a value of 1000ms (1 second) is enough to correctly work with all three events. You can shorten it for desktop use and may need to increase it for your phone (this is because often phones have a different level of touch sensitivity)

As noted on the previous post, on my phone circles were too small and difficult to click on so I modified the demo available on post#1 increasing the radius to 10-15dpi
dgOSM has maximum zoom level set to 18 (original was 17) . You can change it back modifying its value in coMapUtilities.

udg

Hello @udg,

Thank you for your contribution.

spsp
 
  • Like
Reactions: udg

udg

Expert
Licensed User
Longtime User
Hi @spsp
may I suggest an additional innovation? To lighten the clutter due to too many visible shapes/markers when the zoom level is low, you could modify sub update_shapes (module cvMap) as below:
B4X:
private Sub update_shapes
    fShapeCanvas.ClearRect(fShapeCanvas.TargetRect)
    If fMap.fZoomLevel > 16 Then
        For Each o As Object In fMap.fShapes
            CallSub(o,"draw")
        Next
    End If
    fShapeCanvas.Invalidate
End Sub
Even better would be to set the zoom level at which shapes begin to be drawn as a Property (instead of setting it at a fixed value as above).

A different approach could be to make shapes/markers dimensions proportional to the zoom level. Even in this case, drawing shapes at a zoom level below 10 would probabily be wothless.

udg
 

spsp

Active Member
Licensed User
Longtime User
Hi @spsp
may I suggest an additional innovation? To lighten the clutter due to too many visible shapes/markers when the zoom level is low, you could modify sub update_shapes (module cvMap) as below:
B4X:
private Sub update_shapes
    fShapeCanvas.ClearRect(fShapeCanvas.TargetRect)
    If fMap.fZoomLevel > 16 Then
        For Each o As Object In fMap.fShapes
            CallSub(o,"draw")
        Next
    End If
    fShapeCanvas.Invalidate
End Sub
Even better would be to set the zoom level at which shapes begin to be drawn as a Property (instead of setting it at a fixed value as above).

A different approach could be to make shapes/markers dimensions proportional to the zoom level. Even in this case, drawing shapes at a zoom level below 10 would probabily be wothless.

udg
Hello @udg,

Don't hesitate to do modification on the source code and publish it with your account.

I've written this lib for an application and I will not update it until I need it. So use it as you want.

spsp
 
  • Like
Reactions: udg

udg

Expert
Licensed User
Longtime User
What do you think is best: starting a new thread for dgOSM where I add/modify to you original work or me further posting in this same thread any additional modifications?
I like to keep everything in a single place, but in the long run it could generate some confusion.
Anyway, since you are the original author I leave to you the last word.

udg

ps: thanks again for your great lib
 

spsp

Active Member
Licensed User
Longtime User
What do you think is best: starting a new thread for dgOSM where I add/modify to you original work or me further posting in this same thread any additional modifications?
I like to keep everything in a single place, but in the long run it could generate some confusion.
Anyway, since you are the original author I leave to you the last word.

udg

ps: thanks again for your great lib
HI @udg start a new thread with your modified version. You can post in this thread a link to point it if you want.

spsp
 

udg

Expert
Licensed User
Longtime User
Hi, sorry to bother you again. I've just downloaded from post #1 and found that the published lib is probabily an older version. In fact I can't see the two new properties ( tileServer, userAgent). Version as set in manifest is 2. Class cvMap is datet March 7th. Class cvTilemanager has date March 16th.
Reading through this thread's posts it looks you modified the lib the following day (but eventually forgot to update the attachments on post #1).

Anyway, I'll add those props to my version of the lib. This message is just to make you aware about my findings.

udg
 

MbedAndroid

Well-Known Member
Licensed User
Longtime User
just a question: there isnt a headup/northup switch?. With northup mode the map stays north, and only the gps symbol turns.
The Gps marker has to be adapted/translated?
<edit>
solution is easy. (
Screen Shot 05-30-21 at 04.52 PM.PNG
A extra switch is inserted in the menu)
change this code
B4X:
public Sub update_GPS
    #if b4a
        Dim pt As TMapPoint=LatLngToPoint(fMap.fGPS.fLatLng)
        fViewGPSImage.SetLayoutAnimated(0,pt.fX-fViewGPSImage.Width/2,pt.fy-fViewGPSImage.Height/2,fViewGPSImage.Width,fViewGPSImage.Height)
        Log(fMap.fNorthUp)
        fViewGPSImage.Rotation=fMap.fGPS.fBearing
        If fMap.fFollowGPS Then
            fMap.fCenterLatLng=fMap.fgps.fLatLng
            If fMap.fNorthUp Then
                fMap.fCompassDirection=0
            Else
            fMap.fCompassDirection=360-fMap.fGPS.fBearing
            End If
            createTiles(fMap.fCenterLatLng,fMap.fZoomLevel)
            update_Scale
            update_CompassDirection
            update_CenterLatLng
            update_shapes
        End If
    #Else
        fViewGPSImage.Visible=False
    #end if
End Sub
 
Last edited:

zava

Member
Hello,
totally new here, so excuse if I am asking something stupid.
After struggling with Android Studio + OSMDroid (with hardly a success and much frustration...), this B4X environment seems refreshingly simple! (Can you really write an Android App by writing YOUR code and not spending 99% ot time trying to understand and manage lifecycle issues?! Great!)
I'd now need to check if cvMap can replace OSMDroid for all my need (possibly using some other available lib); specifically:
- any chance to use offline maps made from georeferenced images (such as produced with Maptiles or similar?
- any chance to display gpx (or other similar format) tracks and waypoints?
- any specific tutorial or literature or book to learn to use this lib?
Or, maybe: any BETTER way to do this, maybe using some more appropriate tool or lib?
Or, maybe, use (import? wrap?) OSMdroid directly? (but with it's gazillion undocumented methods, something simpler, b4X-style woule make me breathe more lightly! ;)

Thank you for any help!
 

zava

Member
Thank you DonManfred,
thought the question was in a fairly related thread, but will definitely do as you suggested.
Thank you!
 
Top