05 – How to use Tiles with Situm

What are Tile Overlays? #

Tile Overlays consist of a grid of tiles that increase in number for each zoom level. The entire map of earth is split into a 2×2 grid (4 images) at zoom level 1, and at zoom level 2, it will be split into a 4×4 grid (16 images).

This image represents what the tiles would be for zoom 2

Google has very good documentation on how Tile Overlays work and how to implement them in Google Maps. We will be basing our examples on their documentation and applying it to our use case.

We have an entry on Tiles in our blog, in which we go into more detail on the benefits of using tiles to represent floorplans.

Why use Tile Overlays instead of regular images? #

Some of the buildings were Situm is deployed are very large which can make rendering the floorplans in a map quite a challenge due to the large quantity of resources needed to load s a single very large image.

Some known issues of using a large image to render a floor in a map are:

  • Large memory usage that may cause lag in certain interactions.
  • Possible crashes if the device’s memory can’t handle the amount of resources needed.
  • Low quality when zooming into the image, specially perceptible during calibration where precision is most important.

To solve these issue we recommend rendering large floor plans as Tile Overlays as these are much more optimised. Tiles offer better quality at higher zoom levels, and a much more optimised usage of resources.

Situm’s use case #

A normal usecase for tiles would be adding a new map provider so we do not have to use Google’s proprietary maps or overlaying analytics data over a map. This implies having a single overlay in a specific area.

In our particular usecase we are trying to render buildings which, in most cases, have multiple floors. This complicates the implementation because each floor requires it’s own overlay.

Implementing Tile Overlays #

Tile source URL #

To render our own tiles, we need a Tile Source. This is basically a server to store our tiles and a URL which will serve us the tiles we need on demand. Situm’s paltform already has this infrstructure in place and serves tiles through the following URL:

https://dashboard.situm.com/api/v1/tiles/{floorId}/{z}/{x}/{y}.png 
  • {floorId} – The identifier of the Situm Floor in our building.
  • {z} – The tile’s zoom level. At zoom level 0, each tile covers the entire world map; at zoom level 1, it covers ¼ of the world; at zoom level 2, 116 of the world, and so on.
  • {x} – The index of the tile along the map’s x axis according to Spherical Mercator projection. If the value is 0, the tile’s left edge corresponds to the 180th meridian west. If the value is 2z−1, the tile’s right edge corresponds to the 180th meridian east.
  • {y} – The index of the tile along the map’s y axis according to Spherical Mercator projection. If the value is 0, the tile’s tile edge corresponds to arctan(sinh(π)), or approximately 85.0511 degrees north. If the value is 2z−1, the tile’s bottom edge corresponds to −arctan(sinh(π)), or approximately 85.0511 degrees south

If you want to enable Tiles in your buildings, please contact our support team

Sample Code #

To start off we need a class dedicated to handling the tile logic for each floor. For rendering tiles we are going to need the following:

  • The tile size (TILE_WIDTH and TILE_LENGTH) – This defines the individual tile’s resolution. This resolution is specified when creating the tile and will normally be 256.
  • The tile source URL.

We are also interested in showing one tile overlay at a time for the floor we are currently viewing. To achieve this we add a variable to store the TileOverlay that is currently loaded so we can remove it before loading a new one.

The TILE_INDEX is the value we will give ther tileOverlay’s z index. The z index is a common parameter to every object rendered in google maps and will define the order in which they are rendered.

A note on Z indexes: Every object rendered in the map will have a z index. Items with a lower z index will be drawn underneath items with higher z indexes. We highly recommend you keep track of all the objects that are being rendered and their z indexes so you can easily adjust them and avoid covering important information. Example: We always want to render the position marker over the tile overlay, therefore we would set the tile overlay’s z index to 0 and the position marker’s z index to 1.

Example: We always want to render the position marker over the tile overlay, therefore we would set the tile overlay’s z index to 0 and the position marker’s z index to 1.

class FloorTileOverlayController {

    companion object {
        //Base URL of the Tile provider.
        private const val BASE_URL = "https://dashboard.situm.com/api/v1/tiles/"
        private const val TILE_WIDTH = 256
        private const val TILE_HEIGHT = 256
        private const val TILE_INDEX = 1
    }

    //This variable will store any TileOverlay we add to the map so we can remove 
    //it before adding a new one.
    private var tileOverlay: TileOverlay? = null
}

Now the method that will handle the TileOverlay rendering.

This method receives the Google Map instance, where we will be adding the tile overlay, and the ID of the floor we want to show.

We first remove any previous TileOverlay because we want to load a new one for the specific floor. Then we declare a new UrlTileProvider and override it’s getTileUrl method as seen bellow. Here we must complete the tile URL with the floor identifier, x, y and z parameters. Finally we can add a new TileOverlay that uses this new UrlTileProvider.

fun showLevelTileOverlay(googleMap: GoogleMap, floorIdentifier: String) {
        // Remove the tileOverlay of the preious floor if it is not null.
        tileOverlay?.remove()

        //Declare a new UrlTileProvider and override it's getTileUrl method.
        val tileProvider: UrlTileProvider = object : UrlTileProvider(TILE_WIDTH, TILE_HEIGHT) {
            override fun getTileUrl(x: Int, y: Int, z: Int): URL? {
                //Return the complete URL with the floor identifier of the floor we want to 
                //render and the tile position given to us by the method
                return try {
                    URL("${BASE_URL}$floorIdentifier/$z/$x/$y.png")
                } catch (e: MalformedURLException) {
                    e.printStackTrace()
                    throw AssertionError(e)
                }
            }
        }
        
        //Add a TileOverlay that uses our UrlTileProvder to the googleMap instance.
        //Save it in the variable tileOverlay so we can remove it when necessary
        tileOverlay = googleMap.addTileOverlay(TileOverlayOptions().zIndex(TILE_INDEX)
                .tileProvider(tileProvider))
    }

This method should be called whenever a floor change is detected, or whenever we want to show a specific floor so the map can render the correct tiles.

//We get this google map instance in the onMapReady method when loading the map.
val gMapsInstance : GoogleMap
val floorTileOverlaycontroller = FloorTileOverlayController()

fun onFloorChanged(floor: Floor){
  floorTileOverlaycontroller.showLevelTileOverlay(gMapsInstance, floor.getIdentifier())
}

Suscríbete a nuestro boletín

INFORMACIÓN BÁSICA SOBRE PROTECCIÓN DE DATOS

Responsable del tratamiento: SITUM TECHNOLOGIES, S.L.
Contacto: Responsable del tratamiento: situm@situm.es
Responsable de protección: dpo@situm.es
Finalidad y base legal: Gestionar el envío de newsletter de SITUM sólo con consentimiento.
Legitimación: Consentimiento expreso del interesado.
Destinatarios: Los datos no serán cedidos a terceros salvo obligación legal.
Plazo de conservación: Mientras la parte interesada permanezca suscrita al newsletter (en cada newsletter enviado por Situm estará disponible un link para darse de baja).
Derechos: El interesado podrá revocar en cualquier momento su consentimiento, así como ejercitar los derechos de oposición, acceso, conservación, rectificación, limitación, supresión de datos y no ser objeto de una decisión basada únicamente en el tratamiento automatizado de datos, dirigiéndose por escrito a SITUM en las direcciones indicadas.
Información Adicional: Puede consultar la información adicional y detallada sobre Protección de Datos en nuestra política de privacidad.

Por favor, descarga tu copia aquí.

Muchas gracias por descargar nuestro whitepaper. No dudes en contactar con nosotros si quieres saber más sobre cómo nuestras soluciones pueden ayudar a tu negocio.


Cerrar ventana