B4A Library GoogleMapsExtras

M6SOFT

Member
Licensed User
Longtime User
Hi,
First thanks a lot for Your work.
I have a question: is there possibility to serve tiles by myself?
I read this post.
I think about something like getTile where I can return png image to the google map engine. Very usefull if You have tiles in SQLite.
Organizing tiles in database can decrease data size if You have a lot white or blue (water) tiles. You can put one tile and in second table (when are stored x,y,zoom) the same id for all white (blue) tiles.

Greg
 

warwound

Expert
Licensed User
Longtime User
Hi.

That's an interesting idea.

There are already some mapping libraries that store their tiles in a database, MBTiles is one such format.
The OSMDroid library also has it's own OSMDroid SQLite format.

So if you wanted me to create a new TileProvider object in the GoogleMapsExtras library you'd have to decide on a database format to use.
Using an existing format makes more sense than creating your own new format i think.
You could use Mobile Atlas Creator(MOBAC) for example to create both MBTiles and OSMDroid SQLite tile archives.

If offline mapping is important for your app and it's not essential to use the GoogleMaps library then have a read of this thread, look at my post #6.
The link to the apk on my server is no longer valid but you can get the mapsforge demo app and download one or more map database files and give the demo app a go.

The mapsforge library is far from perfect, the GoogleMaps library is much more 'professional' and bug free.
But if you'd like to try using mapsforge in b4a then let me know and i'll let you have a copy of my library.
It'd probably possible to add support for the MBTiles and/or OSMDroid SQLite database tile archives to the OSMDroid library - that's another option.

Otherwise have a read about MBTiles and MOBAC and let me know how you plan to store your tiles using SQLite.

Martin.
 

M6SOFT

Member
Licensed User
Longtime User
Hi.
There are already some mapping libraries that store their tiles in a database, MBTiles is one such format.
The OSMDroid library also has it's own OSMDroid SQLite format.
Martin.
In last weeks i read a lot about tiles and database formats to store it. Your posts are big mine of informations - thanks a lot for this.
But i'm think about idea that we have in b4a function get_tile(x,y,z) which return image to the google maps. What format we use for database is not important in this case.
Maybe i'm wrong and this is not possible.
But in other case, this solution give us possibility to create tile in fly (render from vector data on demand)
PS
Happy to watch how work mapsforge in b4a
 

warwound

Expert
Licensed User
Longtime User
Hi again.

The problem though is that you cannot implement the TileProvider getTile() method in b4a code.
It would have to be implemented in a java class that implements the TileProvider interface.
It'd have to be hardcoded into a b4a library object.

IDEA: Maybe that's not 100% true....
A b4a library object could raise an event each time it requires a tile and a b4a Sub could handle that event and return a tile (actually an array of bytes) to the library.
I think that would suffer from very poor performance, raising an event for each and every offline tile would not be the optimal way to do things.

Anyway after a little coding i have created a new (alpha) library:

CustomTileProvider
Author:
Martin Pearman
Version: 0.01
  • CustomTileProvider
    Events:
    • GetTile (TileX As Int, TileY As Int, Zoom As Int) As Tile
    Fields:
    • NO_TILE As Tile
    Methods:
    • Initialize (EventName As String)
    • IsInitialized As Boolean
  • Tile
    Methods:
    • Initialize (Width As Int, Height As Int, Data() As Byte)
    • IsInitialized As Boolean

The new library contains two new objects: CustomTileProvider and Tile.

Here's a modified version of the UrlTileProvider example:

B4X:
Sub Process_Globals

End Sub

Sub Globals
   Dim CustomTileProvider1 As CustomTileProvider
  Dim GoogleMap1 As GoogleMap
  Dim MapFragment1 As MapFragment
  Dim MapPanel As Panel
End Sub

Sub Activity_Create(FirstTime As Boolean)
   Activity.LoadLayout("Main")
  If MapFragment1.IsGooglePlayServicesAvailable = False Then
  ToastMessageShow("Google Play services not available.", True)
  Else
  MapFragment1.Initialize("MapFragment1", MapPanel)
  End If
End Sub

Sub MapFragment1_Ready
  Log("MapFragment1_Ready")
  GoogleMap1 = MapFragment1.GetMap
  If GoogleMap1.IsInitialized = False Then
  ToastMessageShow("Error initializing map.", True)
  Else
     '   set the map-type to none
     '   the new CustomTileProvider is not transparent and we do not want to load any of the built in tile sources
     GoogleMap1.MapType=GoogleMap1.MAP_TYPE_NONE

     Dim GoogleMapsExtras1 As GoogleMapsExtras
     Dim TileOverlay1 As TileOverlay
     Dim TileOverlayOptions1 As TileOverlayOptions

     CustomTileProvider1.Initialize("CustomTileProvider1")

     TileOverlayOptions1.Initialize
     TileOverlayOptions1.SetTileProvider(CustomTileProvider1)
     TileOverlay1=GoogleMapsExtras1.AddTileOverlay(GoogleMap1, TileOverlayOptions1)

     Dim Marker1 As Marker
  Marker1=GoogleMap1.AddMarker(52.75619, 0.3980, "Home Sweet Home")
  Dim CameraPosition1 As CameraPosition
  CameraPosition1.Initialize(52.75619, 0.3980, 6)
  GoogleMap1.AnimateCamera(CameraPosition1)
  End If
End Sub

Sub CustomTileProvider1_GetTile(TileX As Int, TileY As Int, Zoom As Int) As Tile
   Log("CustomTileProvider1_GetTile X="&TileX&", Y"&TileY&", Zoom="&Zoom)

   '   http://developer.android.com/reference/com/google/android/gms/maps/model/TileProvider.html
   '   return a Tile, Null or CustomTileProvider1.NO_TILE

'   Dim Tile1 As Tile
'   '   M6SOFT you need to modify the next line with the correct width, height and byte array tile data
'   '   the existing 2 byte array will likely cause an exception
'   Tile1.Initialize(256, 256, Array As Byte(0, 255))
'   Return Tile1

   '   If you do not wish to provide a tile for this tile coordinate, return NO_TILE
   Return CustomTileProvider1.NO_TILE

'   '   If the Tile could not be found at this point in time, Return Null and further requests might be made with an exponential backoff
'   Return Null

End Sub

CustomTileProvider1 raises the GetTile event, the Sub that handles this event must return a Tile or Null.
CustomTileProvider1.NO_TILE is a built in Tile object that can be returned to tell the library that no Tile exists or no Tile should be displayed.

So take the attached library files and demo, don't forget you'll need to update the demo private sign key.
Update the Sub CustomTileProvider1_GetTile so that it gets your byte data from your database, creates a Tile object and returns the Tile object to the library.

Do keep this thread updated on your progress - i'm very interested in how well it performs.

Martin.

EDIT This post is no longer current, i have updated the CustomTileProvider and shall make a new post with details.
 
Last edited:

warwound

Expert
Licensed User
Longtime User
Oooops!

Forgot to add that if you test the CustomTileProvider and it performs acceptably then i'll incorporate it into the GoogleMapsExtras library.

Martin.
 

M6SOFT

Member
Licensed User
Longtime User
Do keep this thread updated on your progress - i'm very interested in how well it performs.

Martin.

This solution works PERFECTLY! Attached screenshot with geodetic map layer over the google map. You make me happy today
Working fast and smoothly like a google map. If i make PNG with transparent layer then it is respected on map. As I saw, my tiles are cached and they are reading from database only once.
I will try to paint tile from vector data but this is long way for me - I need to teach B4A how to create PNG by code and paint on its canvas. I will report my progress.
On GetTile we have x, y, and zoom. It's easy to compute tile coordinates in mercator projection used by google (I shall try to make description). But if we want paint vector data given by Lat/Lon (or coordinates in other projection) we need library called pro4j. Do You (or others) have this library wrapped to b4a? It would be very usefull addition for all who working on GIS data

Regards
Greg
 

Attachments

  • map1.jpg
    202.1 KB · Views: 633

warwound

Expert
Licensed User
Longtime User
This solution works PERFECTLY!

Great!
I shall look at integrating the CustomTileProvider and Tile objects into GoogleMapsExtras shortly.

The fact that your generated tiles are cached is good news and must help performance enormously.
The proj4 page states:
Status: Currently this library is still being created, and is not yet ready for download
It's in an alpha stage of development presumably?

Have you any experience of the JTS Topology Suite?
Do you know if it can do the conversion of coordinates from different projections?
It looks to me as if it works with 2d cartesian coordinates only and has no support for different project systems - but i could be wrong.
I did try to wrap the JTS Topology Suite into a b4a library a long while back but never had time to complete the project, and these days i have even less free time so it's unlikely i could complete the wrapper anytime soon.
But it looks to be a very comprehensive and useful library.

b4a has the Geodesic class module available:
The attached class allows you to convert coordinates between Lat Lon coordinates and UTM coordinates.
The conversion is done with WGS84 datum. Note that the class code can handle other datums as well.

By 'other datums' does Erel mean it supports different projection systems?

If you look here you'll see some java methods that can be used to convert tile numbers to latitude/longitude and vice versa - these are WSG84 conversions i'm sure.
Would these be useful to you or do you already have working methods to convert between tile numbers and WSG84 coordinates?

You're working with SQLite and spatial data, have you seen the SpatiaLite update to SQLite?
There's more info HERE.
With SpatiaLite you store spatial features in your tables using spatial geometry types and make queries using spatial geometry clauses.
SpatiaLite also supports many different projection systems.

So you can store points, polylines and polygons (features) using the native SpatiaLite geometry types, and can make queries to get say all features within a bounding box, or within a defined distance of a point.
It's very powerful and makes easy work of storing spatial data in SQLite.

I have a working SpatiaLite b4a library - let me know if you are interested, also let me know if you'd still like to see the mapsforge library.

Martin.
 

M6SOFT

Member
Licensed User
Longtime User
I use this library in windows (delphi) application. Java version is not finished but probably all the major projections are implemented. Working on data without this library will be dificult. Google uses Spherical Mercator projection where coordinates are in meters. GIS or geodetic data can be in various projections. Of course we can reproject it on PC and send to android reprojected. But for users in terrain this is not comfortable. They have all source material in other projection. Very usefull is also showing GPS coordintes in user projection (not Lat/Lon). I found this webpage where is described this library (in comments is advice about remove avt)
I have not enough skill with java and can't rate this sources.

I have no experience but have read about it. This is powerful tool with many functions usefull for manipulating vector data. As i understand (link1, link2) information about projection is only for future use outside JTS.
Have You seen: here is newer version

b4a has the Geodesic class module available:
By 'other datums' does Erel mean it supports different projection systems?
i'm affraid this is much more complicated problem

It's useful but not solve problem if You have data in other projection. In geodesy we do not operate lat/lon. There are much more accurate projections for small scale maps (1:500. 1:1000).

Wow. Bomb at the end. I did not know that spatialite can transform data from one to other projection. I need to read more and test. Probably this is the best solution for storing and retriving vector data.

I have a working SpatiaLite b4a library - let me know if you are interested, also let me know if you'd still like to see the mapsforge library.
Spatialite: Yes, yes, yes
Mapsforge - if it's not problem then yes

greg
PS sorry for my english
 
Last edited:

warwound

Expert
Licensed User
Longtime User
Hi Greg.

I was reading through some docs about SpatiaLite and found that it actually contains a version of the proj4 library.
You should find it very useful!

I'll start a private conversation with you - i'd rather not post links to either SpatiaLite or mapsforge libraries on the forum.

Martin.
 

jota1010

Member
Licensed User
Longtime User
good day, evening or night, I wonder if it is possible with this library to trace or draw a route between two points on the map, also calculate the distance and time from one point to another.
 

warwound

Expert
Licensed User
Longtime User
No there's no routing/directions available with GoogleMapsExtras.
In fact i don't think there is any b4a library that can get routing/directions.

Martin.
 

jcredk

Member
Licensed User
Longtime User
Ok Warwound, as said on the other topic, I will post my questions here:
1) Is the library in 1st page the good one to download and especially with the customeTileProvider ?
2) One thing not clear for me: I am not interested in cartography but only the capacity to zoom over tiles, so I planned to put "GoogleMap1.MapType=GoogleMap1.MAP_TYPE_NONE"
3) But what is unclear is what is the coordinate system?
Is it still lat longs?
What does it mean according to your tiles: does it mean that you have to imagine that level 0 of tiles is a squared tile that represent the full world ?

Thx

Jo
 

warwound

Expert
Licensed User
Longtime User
GoogleMapsExtras updated to version 1.40

  • CustomTileProvider is now part of GoogleMapsExtras, it is no longer a standalone library.
    CustomTileProvider enables you to provide tiles to the map from your b4a code.
    The code sample linked to above is no longer valid, CustomTileProvider no longer raises an event.
    Instead Reflection is used to call a b4a Sub and the b4a Sub returns a Tile object.
    I shall upload a new code example to show how to use the CustomTileProvider.
  • GoogleMapExtras SetPadding is a new method:
  • LatLngBounds has a new property Center.
  • LatLngBoundsBuilder is a new object that enables you to easily create a LatLngBounds object from a number of LatLng objects.
  • MarkerExtras has new methods: GetRotation, IsFlat, SetAnchor, SetFlat, SetInfoWindowAnchor and SetRotation.
    Please read the official documentation for details of these new methods: https://developers.google.com/maps/...ence/com/google/android/gms/maps/model/Marker
    The MarkerOptions object has also been updated to support these same new methods.
  • OnMyLocationButtonClickListener allows you to override the action performed when the MyLocation button is clicked.
    Please read this thread, depending on whether or not you are using the latest version of the Google Play Services library you may find that the MyLocation button is no longer visible.
    Hopefully this will be fixed sooner rather than later.
  • Tile - Contains information about a Tile that is returned by a TileProvider.
    The Tile object is currently only of use if you are using the CustomTileProvider object.

In order to use some of these new features you will need to ensure that you are using the latest version of the Google Play Service library.

Version 1.40 is attached to the first post in this thread.

Martin.
 

warwound

Expert
Licensed User
Longtime User
1) Is the library in 1st page the good one to download and especially with the customeTileProvider ?
See my previous post, i've now uploaded the latest version of GoogleMapsExtras and this new version contains the CustomTileProvider.

2) One thing not clear for me: I am not interested in cartography but only the capacity to zoom over tiles, so I planned to put "GoogleMap1.MapType=GoogleMap1.MAP_TYPE_NONE"
Yes that's exactly what you need to do.

3) But what is unclear is what is the coordinate system?
Is it still lat longs?
What does it mean according to your tiles: does it mean that you have to imagine that level 0 of tiles is a squared tile that represent the full world ?
GoogleMaps uses the WGS84 coordinate system, if you want to reference points on your images you will need to be able to convert pixels to latitude,longitude and vice versa.
Have a read of this page: https://developers.google.com/maps/documentation/javascript/maptypes#MapCoordinates
Event though the page is written for the javascript Google Maps APi it is still relevant.
You might find the Projection object can make these coordinate conversions for you.

Martin.
 

warwound

Expert
Licensed User
Longtime User
@jcredk

Have a look at this example i have put together:

B4X:
Sub Process_Globals
   Dim LastMapCenter As LatLng
   Dim LastMapZoom As Int
End Sub

Sub Globals
  Dim GoogleMap1 As GoogleMap
  Dim MapFragment1 As MapFragment
  Dim MapPanel As Panel
   Dim TileOverlay1 As TileOverlay
End Sub

Sub Activity_Create(FirstTime As Boolean)
   Activity.LoadLayout("Main")
  If MapFragment1.IsGooglePlayServicesAvailable = False Then
  ToastMessageShow("Google Play services not available.", True)
  Else
     If FirstTime Then
       LastMapCenter.Initialize(0, 0)
       LastMapZoom=0
     End If
  MapFragment1.Initialize("MapFragment1", MapPanel)
  End If
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)
   LastMapCenter=MapFragment1.GetMap.CameraPosition.Target
   LastMapZoom=MapFragment1.GetMap.CameraPosition.Zoom
End Sub

Sub MapFragment1_Ready
  Log("MapFragment1_Ready")
  GoogleMap1 = MapFragment1.GetMap
  If GoogleMap1.IsInitialized = False Then
  ToastMessageShow("Error initializing map.", True)
  Else
     '   set the map-type to none
     '   we do not want to load any of the built in tile sources
     GoogleMap1.MapType=GoogleMap1.MAP_TYPE_NONE
    
     Dim GoogleMapsExtras1 As GoogleMapsExtras
     Dim TileOverlayOptions1 As TileOverlayOptions
     Dim UrlTileProvider1 As UrlTileProvider
    
     '   Url parameters are %1$d tileX, %2$d tileY, %3$d zoom
     '   my panorama tiles are all in a single directory and are named: <zoom>_<tileX>x<tileY>.jpg
    
     UrlTileProvider1.Initialize("http://162.221.184.24/tmp/wormegay_river_nar/%3$d_%1$dx%2$d.jpg", 256, 256)
     TileOverlayOptions1.Initialize
     TileOverlayOptions1.SetTileProvider(UrlTileProvider1)
     TileOverlay1=GoogleMapsExtras1.AddTileOverlay(GoogleMap1, TileOverlayOptions1)
    
     Dim Marker1 As Marker
  Marker1=GoogleMap1.AddMarker(0, 0, "(0, 0)")
  Dim CameraPosition1 As CameraPosition
  CameraPosition1.Initialize(LastMapCenter.Latitude, LastMapCenter.Longitude, LastMapZoom)
  GoogleMap1.AnimateCamera(CameraPosition1)
  End If
End Sub

My tiles are cut from a large 360 degree panorama.
The example works well BUT i see some points that you might want to consider:
  • Your images are not 360 degree panoramas, ideally you'd be able to prevent map from wrapping at the meridian longitude. I'm sure there's no way to prevent the GoogleMap from wrapping.
  • Using an old HTC Desire to test my project i see that the GoogleMap doesn't allow me to go to zoom level 0. Looks like zoom level 3 is the most zoomed out level available.
  • I see no way to tell the GoogleMap at which zoom levels tiles exist.
    Keep zooming in on my panorama and at zoom level 8 and higher there are no tiles available.
    Yet you can continue to zoom in but will just see the map background as tiles fail to load.

GoogleMapsExtras has methods:

GetMaxZoomLevel (GoogleMap1 As GoogleMap) As Float
Returns the maximum zoom level for the current camera position. This takes into account what map type is currently being used, e.g., satellite or terrain may have a lower max zoom level than the base map tiles.

GetMinZoomLevel (GoogleMap1 As GoogleMap) As Float
Returns the minimum zoom level. This is the same for every location (unlike the maximum zoom level) but may vary between devices and map sizes.

So minimum zoom level seems to vary from device to device.
But these are read only values, there's no way to set the maximum or minimum zoom levels for which tiles are available.

If you compile my example remember that you'll need to use your own private sign key.
The project is attached as a zip file, i've also attached the already compiled apk if you want to try that instead.

It's worth noting that you can also use the OSMDroid library to display a custom tile set, i can't remember offhand whether or not it's possible to disable map wrapping or set maximum and minimum zoom levels available in OSMDroid - i'll try and find time to have a look.

Martin.
 

Attachments

  • GoogleMapsPanorama.zip
    7.7 KB · Views: 473
  • GoogleMapsPanorama.apk
    318.5 KB · Views: 369

marcick

Well-Known Member
Licensed User
Longtime User
Hi Martin,
with GooglMap library there is the property InfoWindowShown to set the infowindows visible or not.
With your library I can't see this option and the infowindows appears only when I click on the marker.
Am I wrong ? Not possible to have the infowindows always vivible ?
Marco
 

warwound

Expert
Licensed User
Longtime User
GoogleMapsExtras does not contain the methods and properties of the b4a GoogleMaps library.

You need to use the b4a GoogleMaps library to set the InfoWindowShown property, and GoogleMapsExtras to make use of it's additional methods and properties.

Martin.
 

marcick

Well-Known Member
Licensed User
Longtime User
Again: it seems to me that if I place many markers with the property InfoWindowShown=true only the last one has the infowindows visible.
So it is not possible to have some or all infowindows visible sametime ?
Marco
 

warwound

Expert
Licensed User
Longtime User
Again: it seems to me that if I place many markers with the property InfoWindowShown=true only the last one has the infowindows visible.
So it is not possible to have some or all infowindows visible sametime ?
Marco

To be honest i'm not sure.

But from what you describe it definitely sounds as though only one infowindow can be visible at any time.

Martin.
 
Cookies are required to use this site. You must accept them to continue using the site. Learn more…