B4A Library Google Map library Tile Overlay

Hi Erel.

Would it be possible to add Ground / Tile Overlay to this library at some stage. Need to add a fire line scan image at a Lat/Lon.

Thanks

Richard
 

warwound

Expert
Licensed User
Longtime User
Hi there Richard.

Would you like to test a new library i'm working on?
I saw your request on the main Google Maps tutorial thread and thought i'd see if i could add the TileOverlay, it seems to work ok:

GoogleMapsExtras
Version: 0.01
  • GoogleMapsExtras
    Methods:
    • AddTileOverlay (GoogleMap1 As GoogleMap, TileOverlayOptions1 As TileOverlayOptions) As TileOverlay
      Adds a tile overlay to the map.
    • 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.
  • TileOverlay
    Methods:
    • ClearTileCache
      Clears the tile cache so that all tiles will be requested again from the TileProvider.
    • IsInitialized As Boolean
    • IsVisible As Boolean
      Gets the visibility of this tile overlay.
    • Remove
      Removes this tile overlay from the map.
    Properties:
    • Id As String [read only]
      returns this tile overlay's id.
    • Visible As Boolean [write only]
      Sets the visibility of this tile overlay.
    • ZIndex As Float
      Get or Set the zIndex of this tile overlay.
  • TileOverlayOptions
    Methods:
    • GetZIndex As Float
    • Initialize
      Initializes a new set of tile overlay options.
    • IsInitialized As Boolean
    • IsVisible As Boolean
      Returns the visibility setting for this TileOverlayOptions object.
    • SetTileProvider (TileProvider1 As TileProvider) As TileOverlayOptions
      Specifies the tile provider to use for this tile overlay.
      Currently only an instance of UrlTileProvider can be passed to this method.
    • SetVisible (Visible As Boolean) As TileOverlayOptions
    • SetZIndex (ZIndex As Float) As TileOverlayOptions
  • UrlTileProvider
    Methods:
    • Initialize (UrlTemplate As String, Width As Int, Height As Int)
      Initialize the UrlTileProvider.
      UrlTemplate - a String which is the Url to a tile with X, Y and zoom parameters replaced:
      Here the standard OSM slippy map tilenaming is used.
      http://<my tileserver url>/%3$d/%1$d/%2$d.png
      Url parameters are %1$d tileX, %2$d tileY, %3$d zoom
      Width - tile width in pixels.
      Height - tile height in pixels.
    • IsInitialized As Boolean

I've wrapped the UrlTileProvider class and in the UrlTileProvider Initialize method you specify the tile server URL and the dimensions of your tiles.
In the URL you must replace the X, Y and zoom level parameters with either %1$d, %2$d or %3$d, when the UrlTileProvider requests a tile those arguments are replaced with the X, Y and zoom level of the tile to request.
That should allow a bit of flexibility for tile servers that don't follow the OSM slippy map tile naming convention.

I hope to have time to look at the GroundOverlay probably tomorrow, and then will look at some other useful features to add.
Demo code and library files attached - be sure to change the Google Maps API key and B4A private sign key.

Martin.
 
Last edited:

warwound

Expert
Licensed User
Longtime User
And sooner rather than later i present (drum roll!) GroundOverlay.

GoogleMapsExtras
Version: 0.01
  • GoogleMapsExtras
    Methods:
    • AddGroundOverlay (GoogleMap1 As GoogleMap, GroundOverlayOptions1 As GroundOverlayOptions) As GroundOverlay
    • AddTileOverlay (GoogleMap1 As GoogleMap, TileOverlayOptions1 As TileOverlayOptions) As TileOverlay
      Adds a tile overlay to the map.
    • 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.
  • GroundOverlay
    Methods:
    • IsInitialized As Boolean
    • IsVisible As Boolean
    • Remove
    • SetDimensions (Width As Float)
    Properties:
    • Bearing As Float
    • Bounds As LatLngBounds [read only]
    • Height As Float [read only]
    • Id As String [read only]
    • Position As LatLngWrapper
    • PositionFromBounds As LatLngBounds [write only]
    • Transparency As Float
    • Visible As Boolean [write only]
    • Width As Float [read only]
    • ZIndex As Float
  • GroundOverlayOptions
    Methods:
    • Anchor (U As Float, V As Float) As GroundOverlayOptions
      Specifies the anchor to be at a particular point in the image.
    • GetBearing As Float
    • GetTransparency As Float
    • GetZIndex As Float
    • Image (Bitmap1 As Bitmap) As GroundOverlayOptions
      Specifies the image for this ground overlay.
    • Initialize
    • IsInitialized As Boolean
    • IsVisible As Boolean
    • Position (Position As LatLng, Width As Float, Height As Float) As GroundOverlayOptions
      Specifies the position for this ground overlay using an anchor point (a LatLng), width and height (both in meters).
    • Position2 (Position As LatLng, Width As Float) As GroundOverlayOptions
      Specifies the position for this ground overlay using an anchor point (a LatLng) and the width (in meters).
    • PositionFromBounds (Bounds As LatLngBounds) As GroundOverlayOptions
      Specifies the position for this ground overlay.
    • SetBearing (Bearing As Float) As GroundOverlayOptions
      Specifies the bearing of the ground overlay in degrees clockwise from north.
    • SetTransparency (Transparency As Float) As GroundOverlayOptions
      Specifies the transparency of the ground overlay.
    • SetZIndex (ZIndex As Float) As GroundOverlayOptions
      Specifies the ground overlay's zIndex, i.e., the order in which it will be drawn.
    • Visible (Visible As Boolean) As GroundOverlayOptions
      Specifies the visibility for the ground overlay.
    Properties:
    • AnchorU As Float [read only]
      Returns horizontal distance, normalized to [0, 1], of the anchor from the left edge.
    • AnchorV As Float [read only]
      Returns vertical distance, normalized to [0, 1], of the anchor from the top edge.
    • Bounds As LatLngBounds [read only]
    • Height As Float [read only]
    • Location As LatLngWrapper [read only]
    • Width As Float [read only]
  • LatLngBounds
    Methods:
    • Contains (Point As LatLng) As Boolean
    • Including (Point As LatLng) As LatLngBounds
    • Initialize (SouthWest As LatLng, NorthEast As LatLng)
    • IsInitialized As Boolean

I tested the GroundOverlay by replicating the web based API example at https://developers.google.com/maps/documentation/javascript/overlays#GroundOverlays and it works well.
Demo code for both TileOverlay and GroundOverlay plus the library files are attached - the older attachment in my previous post has been removed and all code is in this new attachment.

I'll await some feedback...

Martin.

GoogleMapsExtras library files can now be found in this thread: http://www.b4x.com/forum/additional...pdates/26277-googlemapsextras.html#post152004
 
Last edited:

RichardHirst

Member
Licensed User
Longtime User
Hi Martin.

You have been busy, looks like what I was looking for..

I have not used ''standard OSM slippy map tilenaming '' before.. do you have any examples at all.

I have a export from the scanning systems which creates KML files and a lot of PNG images, which when opened in Google Earth overlays them on to the map.

I will check to see if it can create OSM files.

thank you for the great work.

Richard
 

warwound

Expert
Licensed User
Longtime User
The slippymap tile naming convention is used by many (many) maps includingOpenStreetMap.
And the wiki link in my previous email explains it:
  • Tiles are 256 × 256 pixel PNG files
  • Each zoom level is a directory, each column is a subdirectory, and each tile in that column is a file
  • Filename(url) format is /zoom/x/y.png
So a typical url to a tile on OpenStreetmap might be: http://b.tile.openstreetmap.org/16/32840/21422.png

Some tileservers swap the x and y parameters so the url is slightly different, and some tileservers use a completely different tile naming scheme.

If you want to get a better idea of how the standard coordinate system works then you'll find a good explanation here: https://developers.google.com/maps/documentation/javascript/maptypes#CustomMapTypes, the section titled Tile coordinates explains it well.

So if you have a tile server or access to a tile server and that tile server serves tiles based on zoom, x and y parameters then you should be able pass a url template to the UrlTileProvider Initialize method that will work.

Take a look at a bit of the relevant source code:

B4X:
private String mUrlTemplate;

@Override
public synchronized URL getTileUrl(int pX, int pY, int pZoom){
   try {
      return new URL(String.format(mUrlTemplate, pX, pY, pZoom));
   } catch (MalformedURLException e) {
      e.printStackTrace();
      return null;
   }
}

mUrlTemplate is the String that you passed to the UrlTileProvider Initialize method.
Each time the map requires a tile it calls the getTileUrl method passing the zoom level and x and y coordinates of the required tile.

return new URL(String.format(mUrlTemplate, pX, pY, pZoom));

This line takes your url template String and replaces %1$d with the tile x coordinate, $2$d with the tile y coordinate and %3$d with the zoom level.

So if the url template is http://b.tile.openstreetmap.org/%3$d/%1$d/%2$d.png then you display tiles from the OpenStreetMap tile server.
If your tile server requires the tile request url to be in a different format then you should be able to create a url template that will work, there's a free tile server at http://www.maps-for-free.com/ but this tile server does not use the slippy map tile naming convention.
A typical url for a tile might be: http://www.maps-for-free.com/layer/relief/z8/row83/8_128-83.jpg
And a url template for this tile server would be:

http://www.maps-for-free.com/layer/relief/z%3$d/row%2$d/%3$d_%1$d-%2$d.jpg

(That's untested by the way).

The GroundOverlay object is passed a single image to display on the map.
You need to tell the GroundOverlay what geographical bounds the image cover and the libray size the image as required and display it.
A GroundOverlay object can display just one image.

So if you currently have a KML file and are using Google Earth to export that KML file and the exports consists of more than one image then a GroundOverlay is of no use.
Is Google Earth exporting a small set of map tiles and naming them with any recognisable convention?
If so then a TileOverlay sounds like it would display those tiles for you.

Can you keep this thread updated with your use of the TileOverlay and GroundOverlay?
if you find it all works well then i'll start a new thread or post on the existing Google Maps Tutorial thread so that others can find and use the library.

Martin.
 
Last edited:

RichardHirst

Member
Licensed User
Longtime User
Martin.

Thanks for the explaination..

I have two ways to use the images.

First is a One File (large) image which had a JGW file (Jpeg World File) which holds details about the position of the image. As this is a large file is can take a while to download to a mobile device.

Second is a KML export file. Looking at the KML file I can see is uses many small PNG files with a KML file to tell GM where to place the bounds.

example

<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.2">
<Document>
<Region>
<Lod>
<minLodPixels>128</minLodPixels>
<maxLodPixels>-1</maxLodPixels>
</Lod>
<LatLonAltBox>
<north>-34.2108645736864500</north>
<south>-34.2203266170205960</south>
<east>150.8445481792831500</east>
<west>150.8331497755447100</west>
</LatLonAltBox>
</Region>
<GroundOverlay>
<Icon>
<href>run1g_pyramid_0_tile_000.png</href>
</Icon>
<LatLonBox>
<north>-34.2108645736864500</north>
<south>-34.2203266170205960</south>
<east>150.8445481792831500</east>
<west>150.8331497755447100</west>
</LatLonBox>
</GroundOverlay>
</Document>
</kml>

If you want to look at the full image see this link

https://dl.dropbox.com/u/12747054/Bulli Tops_13-08-2012_Google Earth.rar

Link to a single file image
https://dl.dropbox.com/u/12747054/Run11_Deans Gap_08-01-2013_2133Hrs.jpg

Looking at your GroundOverlay code I think it would be simple to process each of the KML file for each tile in the directory.

Do you know if there is any KML import code in the google API..?

Thanks again

Richard
 
Last edited:

RichardHirst

Member
Licensed User
Longtime User
Hi Martin.

All seems to be working with the KML file and the small png images. I can place them on the ground layer.

When I try a larger image all I get is a small square, I guess 256x256. Is the 'Ground Tile' image the same size as the 'Tile Overlay' image.

I was using this;

GroundOverlayOptions1.Image(LoadBitmap(File.DirAssets, "run1.png")).Position(LatLng1, 2048, 1024)

Thanks

Richard
 

warwound

Expert
Licensed User
Longtime User
Hi Richard.

There's no documented maximum size for an image to use as a GroundOverlay - not any documentation that i've found so far that is.

I took your image run11_deans gap_08-01-2013_2133hrs.jpg and tried it in the GroundOverlay demo code from post #3.
The only modification to that demo code was:

B4X:
GroundOverlayOptions1.Image(LoadBitmap(File.DirAssets, "run11_deans gap_08-01-2013_2133hrs.jpg")).PositionFromBounds(LatLngBounds1).SetTransparency(0.2)

The app immediately force closed with an out of memory exception - decompressing the JPG to a bitmap required too much memory.

I then edited the project's manifest file adding:

B4X:
SetApplicationAttribute(android:largeHeap,"true")

The demo code now runs perfectly - your image though obviously not correctly aligned to the map.
So i think any limits on the image used for a GroundOverlay will be memory limits not limits to the dimensions of the image.
Note that the android:largeHeap manifest attribute can only be used on version of Android 3 and higher (Honeycomb and later).

If you look at the TileOverlay example you'll see that you can can select a built in map tile layer (such as the road map) and add your custom tile overlay or set the built in map tiles to 'MAP_TYPE_NONE' and add your custom tile overlay.
So you could display a built in map such as road map and display semi-transparent tiles on top of the road map using a TileOverlay.
This would enable you to add your tiles to a very large area with no memory problems.
You'd have to create the necessary tiles, i'm sure Google Earth cannot do this but there are many programs available that can take an image or spatial data file and create correctly named tiles. MapTiler - Map Tile Cutter. Overlay Generator for Google Maps, Google Earth (KML SuperOverlay). looks good, and a search on Google will get links to other software.

There's no way to directly import a KML file into the Android Google Maps API and automatically create a ground overlay or tile layer.
(That's possible with the web based Google Maps API using Fusion Tables).

If you can create a set of tiles for each zoom level - tiles named so that the TileOverlay can request them - then i think you could either serve the tiles from an online tile server OR access them from the device SD card.

Martin.
 
Top