Android Code Snippet Addition to B4XMap (OSM viewer)

Using this very nice OSM map viewer:

I didn't like the blue diagonals that will show for the area outside the map, so added some code that will prevent that
and also avoids trips to the map DB, looking for tiles that are not there:

In clsMapTileManager:

B4X:
'open db, create it if necessary
Private Sub dbInit
    
    Dim strSQL As String
    
    strSQL = "CREATE TABLE tiles(" & _
             "zoom_level INTEGER NOT NULL, " & _
             "tile_column INTEGER Not Null, " & _
             "tile_row INTEGER Not Null, " & _
             "tile_data BLOB Not Null, primary key (zoom_level, tile_column, tile_row))"

    fXUI.SetDataFolder("")
    If Not(File.Exists(fXUI.DefaultFolder,"tiles.db3")) Then
        #if B4A or B4i
        fDB.Initialize(fXUI.DefaultFolder,"tiles.db3",True)
        #else if B4J
            fDB.InitializeSQLite(fXUI.DefaultFolder,"tiles.db3",True)
        #end if
        fDB.ExecNonQuery(strSQL)
    Else
        
        Dim strSQL As String
        Dim RS1 As ResultSet

        #if B4A or B4i
        fDB.Initialize(fXUI.DefaultFolder, "tiles.db3", False)
        
        strSQL = "select zoom_level, min(tile_column), max(tile_column), min(tile_row), max(tile_row) from tiles group by zoom_level"
        RS1 = fDB.ExecQuery(strSQL)
        MapUtilities.SetupMapDBRowsColumns(RS1)
        
        #else if B4J
            fDB.InitializeSQLite(fXUI.DefaultFolder,"tiles.db3",False)
        #End If
    End If
End Sub

In

In code module MapUtilities:

B4X:
Sub Process_Globals

    Private mapDBRowsColumns As Map


Sub SetupMapDBRowsColumns(RS1 As ResultSet)
    
    Dim c As Int
    
    mapDBRowsColumns.Initialize
    
    Do While RS1.NextRow
        Dim arrInt(4) As Int
        For c = 0 To 3
            arrInt(c) = RS1.GetInt2(c + 1)
        Next
        mapDBRowsColumns.Put(RS1.GetInt2(0), arrInt)
    Loop
    
End Sub

Public Sub TileInDB(iZoom As Int, iColumn As Int, iRow As Int) As Boolean
    
    Dim arrInt() As Int
    
    arrInt = mapDBRowsColumns.Get(iZoom)
    Return iColumn >= arrInt(0) And iColumn <= arrInt(1) And iRow >= arrInt(2) And iRow <= arrInt(3)
    
End Sub

In cvMap:

B4X:
'add tile to the mapview
private Sub addTile(aLeft As Int,aTop As Int,aTileX As Long,aTileY As Long,aZ As Int)
    
    aTileX=checkTile(aTileX,fTilesCount)
    aTileY=checkTile(aTileY,fTilesCount)
    
    'view for the tile
    Dim xpt As B4XView = fxui.CreatePanel("tile")
    xpt.Tag=MapUtilities.initTileXY(aTileX,aTileY)
    fViewTiles.AddView(xpt,aLeft,aTop,MapUtilities.cTileSize,MapUtilities.cTileSize)
    
    'view for the tile's image
    'only put image on tile panel if that tile is in the DB
    '------------------------------------------------------
    If MapUtilities.TileInDB(aZ,aTileX,aTileY) Then '<<<< added RBS 14/03/2022
        Dim iv As ImageView
        iv.Initialize("itile")
        xpt.AddView(iv,0,0,MapUtilities.cTileSize,MapUtilities.cTileSize)
        drawTile(iv,aZ,aTileX,aTileY)
    End If
    
    'view for the grid
    Dim pg As B4XView = fxui.CreatePanel("gtile")
    xpt.AddView(pg,0,0,MapUtilities.cTileSize,MapUtilities.cTileSize)
    drawGridOnTile(pg)
    pg.Visible=fMap.fShowGrid
    
End Sub

RBS
 

roberto64

Active Member
Licensed User
Longtime User
Hi, the changes you made don't work, the 1 in the "sub TileInDB" arrInt = mapDBRowsColumns.Get (iZoom) returns null and gives an error. and every time you put or offline GPs always error
greeting
 

RB Smissaert

Well-Known Member
Licensed User
Longtime User
Hi, the changes you made don't work, the 1 in the "sub TileInDB" arrInt = mapDBRowsColumns.Get (iZoom) returns null and gives an error. and every time you put or offline GPs always error
greeting
All working fine with me. Is the iZoom within the zoom range?

RBS
 

RB Smissaert

Well-Known Member
Licensed User
Longtime User
Using this very nice OSM map viewer:

I didn't like the blue diagonals that will show for the area outside the map, so added some code that will prevent that
and also avoids trips to the map DB, looking for tiles that are not there:

In clsMapTileManager:

B4X:
'open db, create it if necessary
Private Sub dbInit
   
    Dim strSQL As String
   
    strSQL = "CREATE TABLE tiles(" & _
             "zoom_level INTEGER NOT NULL, " & _
             "tile_column INTEGER Not Null, " & _
             "tile_row INTEGER Not Null, " & _
             "tile_data BLOB Not Null, primary key (zoom_level, tile_column, tile_row))"

    fXUI.SetDataFolder("")
    If Not(File.Exists(fXUI.DefaultFolder,"tiles.db3")) Then
        #if B4A or B4i
        fDB.Initialize(fXUI.DefaultFolder,"tiles.db3",True)
        #else if B4J
            fDB.InitializeSQLite(fXUI.DefaultFolder,"tiles.db3",True)
        #end if
        fDB.ExecNonQuery(strSQL)
    Else
       
        Dim strSQL As String
        Dim RS1 As ResultSet

        #if B4A or B4i
        fDB.Initialize(fXUI.DefaultFolder, "tiles.db3", False)
       
        strSQL = "select zoom_level, min(tile_column), max(tile_column), min(tile_row), max(tile_row) from tiles group by zoom_level"
        RS1 = fDB.ExecQuery(strSQL)
        MapUtilities.SetupMapDBRowsColumns(RS1)
       
        #else if B4J
            fDB.InitializeSQLite(fXUI.DefaultFolder,"tiles.db3",False)
        #End If
    End If
End Sub

In

In code module MapUtilities:

B4X:
Sub Process_Globals

    Private mapDBRowsColumns As Map


Sub SetupMapDBRowsColumns(RS1 As ResultSet)
   
    Dim c As Int
   
    mapDBRowsColumns.Initialize
   
    Do While RS1.NextRow
        Dim arrInt(4) As Int
        For c = 0 To 3
            arrInt(c) = RS1.GetInt2(c + 1)
        Next
        mapDBRowsColumns.Put(RS1.GetInt2(0), arrInt)
    Loop
   
End Sub

Public Sub TileInDB(iZoom As Int, iColumn As Int, iRow As Int) As Boolean
   
    Dim arrInt() As Int
   
    arrInt = mapDBRowsColumns.Get(iZoom)
    Return iColumn >= arrInt(0) And iColumn <= arrInt(1) And iRow >= arrInt(2) And iRow <= arrInt(3)
   
End Sub

In cvMap:

B4X:
'add tile to the mapview
private Sub addTile(aLeft As Int,aTop As Int,aTileX As Long,aTileY As Long,aZ As Int)
   
    aTileX=checkTile(aTileX,fTilesCount)
    aTileY=checkTile(aTileY,fTilesCount)
   
    'view for the tile
    Dim xpt As B4XView = fxui.CreatePanel("tile")
    xpt.Tag=MapUtilities.initTileXY(aTileX,aTileY)
    fViewTiles.AddView(xpt,aLeft,aTop,MapUtilities.cTileSize,MapUtilities.cTileSize)
   
    'view for the tile's image
    'only put image on tile panel if that tile is in the DB
    '------------------------------------------------------
    If MapUtilities.TileInDB(aZ,aTileX,aTileY) Then '<<<< added RBS 14/03/2022
        Dim iv As ImageView
        iv.Initialize("itile")
        xpt.AddView(iv,0,0,MapUtilities.cTileSize,MapUtilities.cTileSize)
        drawTile(iv,aZ,aTileX,aTileY)
    End If
   
    'view for the grid
    Dim pg As B4XView = fxui.CreatePanel("gtile")
    xpt.AddView(pg,0,0,MapUtilities.cTileSize,MapUtilities.cTileSize)
    drawGridOnTile(pg)
    pg.Visible=fMap.fShowGrid
   
End Sub

RBS
Just a little alteration to this, needed in case you had non-continuous tile DB, that is there are area's in the map rectangle where there are no tiles.
This will be unusual, but I added a small area to my tile DB, away from the main map area and then noticed the diagonal blue lines.

These are the alterations needed:

In MapUtilities:

B4X:
Sub SetupMapDBRowsColumns(RS1 As ResultSet)
    
    Dim c As Int
    
    mapDBRowsColumns.Initialize
    
    'RS1 is produced by this SQL:
    'select zoom_level || '|' || tile_column as zx, min(tile_row), max(tile_row) from tiles group by zx
    Do While RS1.NextRow
        Dim arrInt(2) As Int
        For c = 0 To 1
            arrInt(c) = RS1.GetInt2(c + 1)
        Next
        mapDBRowsColumns.Put(RS1.GetString2(0), arrInt)
    Loop
    
End Sub

'checks if a tile is in the DB, directly from a map
Public Sub TileInDB(iZoom As Int, iColumn As Int, iRow As Int) As Boolean
    
    Dim arrDefault(1) As Int
    
    Dim arrInt() As Int = mapDBRowsColumns.GetDefault(iZoom & "|" & iColumn, arrDefault)
    
    If arrInt(0) = 0 Then Return False
    
    '              min(tile_row)         max(tile_row)
    Return iRow >= arrInt(0) And iRow <= arrInt(1)
    
End Sub

In clsMapTileManager:

B4X:
'open db, create it if necessary
Private Sub DBInit
    
    Dim strSQL As String
    
    strSQL = "CREATE TABLE tiles(" & _
             "zoom_level INTEGER NOT NULL, " & _
             "tile_column INTEGER Not Null, " & _
             "tile_row INTEGER Not Null, " & _
             "tile_data BLOB Not Null, primary key (zoom_level, tile_column, tile_row))"

    fXUI.SetDataFolder("")
    If Not(File.Exists(fXUI.DefaultFolder,"tiles.db3")) Then
        cMP.cConn.SQL_MapnikOSM2.ExecNonQuery(strSQL)
        bConnected = True
    Else
        
        Dim strSQL As String
        Dim RS1 As ResultSet

        #if B4A or B4i
        'fDB.Initialize(fXUI.DefaultFolder, "tiles.db3", False)
  
        If MapUtilities.mapDBRowsColumns.IsInitialized = False Then
             strSQL = "select zoom_level || '|' || tile_column as zx, min(tile_row), max(tile_row) from tiles group by zx"
            RS1 = cMP.cConn.SQL_MapnikOSM2.ExecQuery(strSQL)
            MapUtilities.SetupMapDBRowsColumns(RS1)
            RS1.Close
        End If
        #else if B4J
            fDB.InitializeSQLite(fXUI.DefaultFolder,"tiles.db3",False)
        #End If
        
        bConnected = True
    End If
    
End Sub

This works fine in my situation where in the UK my main area is around Wolverhampton and I added a small area in North Wales.
Not tested for the situation where there are multiple area's at the same longitude.

RBS
 
Top