A basic & complete cartography example #
Situm provides a complete cartography manager that allows you to:
- Create buildings & uploading their floorplans.
- Manage different cartography elements such as Points of Interest, Geofences, navigation routes (and more).
- Retrieve and operate these cartography elements from within your application: you will be able to download their information & display it to your users easily and with a few lines of code.
Before you start
Before you start:
- Make sure you have a good understanding of our Quickstart guides: Android, iOS, Cordova, React Native.
- Take a deep look at the CommunicationManager, which retrieves all the cartography information from the Situm Platform. Under the hood, the CommunicationManager calls the Situm REST API to retrieve all the information.
Ready? Let’s go!
The following snippet shows you how to retrieve and inspect the most important cartography information: buildings, floors, points of interest and geofences.
package com.example.situmsdkbasicapp; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import java.util.Collection; import es.situm.sdk.SitumSdk; import es.situm.sdk.model.cartography.Building; import es.situm.sdk.model.cartography.BuildingInfo; import es.situm.sdk.model.cartography.Floor; import es.situm.sdk.model.cartography.Geofence; import es.situm.sdk.model.cartography.Poi; import es.situm.sdk.error.Error; import es.situm.sdk.utils.Handler; public class MainActivity extends AppCompatActivity { private static final String TAG = MainActivity.class.getSimpleName(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //Initialize Situm SDK SitumSdk.init(this); //Call the communicationManager to fetch all the buildings from Situm REST API SitumSdk.communicationManager().fetchBuildings(new Handler<Collection<Building>>() { //The onSuccess method receives the Collection of buildings from Situm REST API @Override public void onSuccess(Collection<Building> buildings) { // First, we print the basic info of all the buildings Log.i(TAG, "BuildingsBasicInfo = [" + buildings + "]"); Log.i(TAG, "********************************************"); //We can go further an loop over all the buildings... for (Building building : buildings) { //...and fetch this additional info: floors, indoorPOIs, outdoorPOIs and geofences SitumSdk.communicationManager().fetchBuildingInfo(building.getIdentifier(), new Handler<BuildingInfo>() { //The onSuccess method receives the BuildingInfo data object ... @Override public void onSuccess(BuildingInfo buildingInfo) { //... which contains all the relevant cartography entities associated with the building Building buildingBasicInfo = buildingInfo.getBuilding(); Collection<Floor> floors = buildingInfo.getFloors(); Collection<Poi> indoorPOIs = buildingInfo.getIndoorPOIs(); Collection<Poi> outdoorPOIs = buildingInfo.getOutdoorPOIs(); Collection<Geofence> geofences = buildingInfo.getGeofences(); Log.i(TAG, "BuildingBasicInfo = [" + buildingBasicInfo + "]"); for (Floor floor : floors) Log.i(TAG, "floor = [" + floor + "]"); for (Poi indoorPOI : indoorPOIs) Log.i(TAG, "indoorPoi = [" + indoorPOI + "]"); for (Poi outdoorPOI : outdoorPOIs) Log.i(TAG, "outdoorPoi = [" + outdoorPOI + "]"); for (Geofence geofence : geofences) Log.i(TAG, "geofence = [" + geofence + "]"); Log.i(TAG, "------------------------------------------------"); } //This onFailure method receives errors that happen during the fetchBuildingInfo network request @Override public void onFailure(Error error) { Log.e(TAG, "Error with msg = [" + error.getMessage() + "]" + " and code = [" + error.getCode() + "]"); } }); } } //This onFailure method receives errors that happen during the fetchBuildings network request @Override public void onFailure(Error error) { Log.e(TAG, "FAILURE " + error); } }); } }
The previous code snippets shows us how to retrieve the basic information of all the buildings in our account using the fetchBuildings method (Android, iOS, Cordova, ReactNative). We receive a collection of Building data objects (Android, iOS), each of which contains what we called the basic information of the building: name, rotation, bounds, location, etc.
Most times, we will need more information, such as the floorplans or the Points of Interest. Although these are separate entities from the building, in a way they belong to it (after all, a floor only exists if the building exists). Therefore, Situm SDK provides the utility method fetchBuildingInfo (Android, iOS, Cordova, ReactNative), which retrieves for us the building floors, indoor & outdoor POIs, and the geofences.
Buildings #
The building is the most important cartographic entity in Situm. Buildings can represent any venue and contain all other cartographic elements, such as floors (with floorplans), points of interest, geofences, etc.
For detailed information on buildings, you may read their introductory description and how to create them in Situm Dashboard. You may also find interesting their data models as provided by Situm REST API Building methods and Situm SDK Building data model (Android, iOS).
Fetching all the buildings of your account #
The following Android code snippet shows how to retrieve the buildings of your account and output their information on the application Log. It uses the fetchBuildings method, available for Android, iOS, Cordova and ReactNative.
//Fetches all the buildings in your account SitumSdk.communicationManager().fetchBuildings(new Handler<Collection<Building>>() { @Override public void onSuccess(Collection<Building> buildings) { //Receives all the buildings and loops over them for (Building building: buildings){ Log.i(TAG, "Building ID: " + building.getIdentifier()); Log.i(TAG, "Name: " + building.getName()+ "\n"); Log.i(TAG, "Address: " + building.getAddress()); Log.i(TAG, "InfoHTML: " + building.getInfoHtml()); Log.i(TAG, "BuildingPictureURL: " + building.getPictureUrl()); Log.i(TAG, "BuildingPictureThumbnailURL " + building.getPictureThumbUrl()); Log.i(TAG, "CustomFields: " + building.getCustomFields()); Log.i(TAG, "Center. Lat=" + building.getCenter().getLatitude() + " Lng=" + building.getCenter().getLongitude()); Log.i(TAG, "Dimensions. Height: " + building.getDimensions().getHeight() + ". Width: " + building.getDimensions().getWidth()); Log.i(TAG, "Rotation. Degrees=" + building.getRotation().degrees() + " Radians=" + building.getRotation().radians()); Log.i(TAG, "Bounds:"); Log.i(TAG, " NW (TopLeft [1]): Lat=" + building.getBounds().getNorthWest().getLatitude() + " Lng=" + building.getBounds().getNorthWest().getLongitude()); Log.i(TAG, " NE (TopRight [2]): Lat=" + building.getBounds().getNorthEast().getLatitude() + " Lng=" + building.getBounds().getNorthEast().getLongitude()); Log.i(TAG, " SE (BottomRight [3]): Lat=" + building.getBounds().getSouthEast().getLatitude() + " Lng=" + building.getBounds().getSouthEast().getLongitude()); Log.i(TAG, " SW (BottomLeft [4]): Lat=" + building.getBounds().getSouthWest().getLatitude() + " Lng=" + building.getBounds().getSouthWest().getLongitude()); Log.i(TAG, "BoundsRotated:"); Log.i(TAG, " NW (TopLeft [1]): Lat=" + building.getBoundsRotated().getNorthWest().getLatitude() + " Lng=" + building.getBoundsRotated().getNorthWest().getLongitude()); Log.i(TAG, " NE (TopRight [2]): Lat=" + building.getBoundsRotated().getNorthEast().getLatitude() + " Lng=" + building.getBoundsRotated().getNorthEast().getLongitude()); Log.i(TAG, " SE (BottomRight [3]): Lat=" + building.getBoundsRotated().getSouthEast().getLatitude() + " Lng=" + building.getBoundsRotated().getSouthEast().getLongitude()); Log.i(TAG, " SW (BottomLeft [4]): Lat=" + building.getBoundsRotated().getSouthWest().getLatitude() + " Lng=" + building.getBoundsRotated().getSouthWest().getLongitude()+ "\n"); } } @Override public void onFailure(Error error) { Log.e(TAG, "Error: " + error ); } });
In the previous code snippet, we are receiving a Collection of Building objects (Android, iOS). These are the buildings in the user account, and we loop over them to print their properties. Your application logs should be something like this:
... Building ID: 8377 Name: Situm HQ Address: Rúa do Restollal, nº 32 Edificio Paxonal, Planta 4, Of. 401 15702, Santiago de Compostela, A Coruña, Spain InfoHTML: <p><strong>Welcome to Situm!</strong></p><p><br></p> BuildingPictureURL: URL{value='/uploads/building/8377/6d8423b9-61b5-4015-a0aa-0faf3c9c66cc.png', isAbsolute=false} BuildingPictureThumbnailURL URL{value='/uploads/building/8377/6d8423b9-61b5-4015-a0aa-0faf3c9c66cc.png', isAbsolute=false} CustomFields: {external_cms_id=102301, show_in_app=true} Center. Lat=42.872352462867 Lng=-8.56324909758796 Dimensions. Height: 43.9411738292689. Width: 73.273936306327 Rotation. Degrees=170.58184697387247 Radians=2.9772148738272 Bounds: NW (TopLeft [1]): Lat=42.87255023533293 Lng=-8.56369747820446 NE (TopRight [2]): Lat=42.87255023533293 Lng=-8.562800717024437 SE (BottomRight [3]): Lat=42.87215469039859 Lng=-8.562800717024437 SW (BottomLeft [4]): Lat=42.87215469039859 Lng=-8.56369747820446 BoundsRotated: NW (TopLeft [1]): Lat=42.872211323414874 Lng=-8.562762760777817 NE (TopRight [2]): Lat=42.87210338912287 Lng=-8.56364743390568 SE (BottomRight [3]): Lat=42.872493602247964 Lng=-8.563735434357707 SW (BottomLeft [4]): Lat=42.87260153653997 Lng=-8.562850761229845 ...
Let’s examine them in detail.
Building Details: Identifier, Name, Address…
The first information you will notice in the log is the Building Identifier. This is the identifier that Situm Platform automatically assigns automatically to your building when you create it. You may also know the identifier of a particular building by taking a look at the building URL in Situm Dashboard. Another way to know the identifier of a venue is to edit that venue in Situm Dashboard.
Building ID: 8377
Following, a number of lines contain other basic building information: the building’s name, address, free HTML information (introduced using our Rich Text HTML editor), a picture of the building (both at full resolution and its thumbnail version), and all the custom-field key-value pairs that you may have created.
Name: Situm HQ Address: Rúa do Restollal, nº 32 Edificio Paxonal, Planta 4, Of. 401 15702, Santiago de Compostela, A Coruña, Spain InfoHTML: <p><strong>Welcome to Situm!</strong></p><p><br></p> BuildingPictureURL: URL{value='/uploads/building/8377/6d8423b9-61b5-4015-a0aa-0faf3c9c66cc.png', isAbsolute=false} BuildingPictureThumbnailURL URL{value='/uploads/building/8377/6d8423b9-61b5-4015-a0aa-0faf3c9c66cc.png', isAbsolute=false} CustomFields: {external_cms_id=102301, show_in_app=true}
All this information can be edited from the building editor of Situm Dashboard, as shown in the following picture:
Building Cartography information: center (location), rotation, corners
Finally, the most important building information: where it is, how is it oriented and where are its bounds (corners).
The following image will help to clarify the previous information. On the left, we see a floorplan whose dimensions have been adjusted to the building’s dimensions, but that has not been rotated yet. On the right, we see the same floorplan after it has been rotated to fit with the building’s silhouette.
First, take a look at the left image. Notice that the building’s margins (blue lines) form a rectangle defined by the margins of the floorplan. Since all floorplans have the same size, the width & height of the building are exactly the width & height of this rectangle before it has been rotated. Likewise, the location of the building (center) is exactly the location of the center point of this rectangle.
Center. Lat=42.872352462867 Lng=-8.56324909758796 Dimensions. Height: 43.9411738292689. Width: 73.273936306327
The location of the building’s corners (bounds) also matches the location of the corners of this rectangle. Now, take a look at the right image. The floorplan has been rotated 170.58 degrees counter-clockwise. This does not change the center of the building, nor its width or height, but it does change the location of the building’s bounds. For convenience, Situm SDK provides their location before and after rotation.
Rotation. Degrees=170.58184697387247 Radians=2.9772148738272 Bounds: NW (TopLeft [1]): Lat=42.87255023533293 Lng=-8.56369747820446 NE (TopRight [2]): Lat=42.87255023533293 Lng=-8.562800717024437 SE (BottomRight [3]): Lat=42.87215469039859 Lng=-8.562800717024437 SW (BottomLeft [4]): Lat=42.87215469039859 Lng=-8.56369747820446 BoundsRotated: NW (TopLeft [1]): Lat=42.872211323414874 Lng=-8.562762760777817 NE (TopRight [2]): Lat=42.87210338912287 Lng=-8.56364743390568 SE (BottomRight [3]): Lat=42.872493602247964 Lng=-8.563735434357707 SW (BottomLeft [4]): Lat=42.87260153653997 Lng=-8.562850761229845
Floors and floorplans #
In Situm Platform, a building can have a number of floors, each associated with a floorplan image.
For detailed information on floors & floorplans, you may read their introductory description and how to create them in Situm Dashboard. You may also find interesting their data models as provided by Situm REST API Floor methods and Situm SDK Floor data model (Android, iOS).
Fetching all the floors of a building #
The following Android code snippet shows how to retrieve the floors of a certain building and output their information on the application Log. For this example, we will use building 8377, which we know from a previous example. Remember to change the building id 8377 for your building id.
The example uses the method fetchFloorsFromBuilding for Android (also available on iOS, Cordova and ReactNative), but you may also retrieve the floors as shown in the Basic cartography example.
//Fetches all the floors of building 8377 SitumSdk.communicationManager().fetchFloorsFromBuilding("8377", new Handler<Collection<Floor>>() { @Override public void onSuccess(Collection<Floor> floors) { //Receives all the buildings and loops over them for (Floor floor: floors){ Log.i(TAG, "BuildingID: " + floor.getBuildingIdentifier()); Log.i(TAG, "FloorID: " + floor.getIdentifier()); Log.i(TAG, "Name: " + floor.getName()); Log.i(TAG, "Floor (Order): " + floor.getFloor()); Log.i(TAG, "Altitude: " + floor.getAltitude()); Log.i(TAG, "CustomFields: " + floor.getCustomFields()); Log.i(TAG, "MapURL: " + floor.getMapUrl()); Log.i(TAG, "Scale (pixels / meter): " + floor.getScale()); } } @Override public void onFailure(Error error) { Log.e(TAG, "Error: " + error ); } });
In the previous code snippet, we are receiving a Collection of Floor objects (Android, iOS), which are the floors in Building 8377. We loop over them to print their properties. Your application logs should be something like this:
... BuildingID: 8377 FloorID: 20541 Name: F0 Floor (Order): 0 Altitude: 0.0 CustomFields: {} MapURL: URL{value='https://dashboard.situm.es/uploads/floor/20541/51b985cf-4c2b-4327-bbab-a53b9c50b916.png', isAbsolute=true} Scale (pixels / meter): 17.25033570894508 ... BuildingID: 8377 FloorID: 20542 Name: F1 Floor (Order): 1 Altitude: 15.0 CustomFields: {show_in_app=true} MapURL: URL{value='https://dashboard.situm.es/uploads/floor/20542/aa275ada-5ca2-4d51-be61-71fec14f29be.png', isAbsolute=true} Scale (pixels / meter): 17.25033570894508 ...
Let’s examine them in detail.
Building Identifier
First, you will notice that the Floor data object allows you to retrieve the identifier of the building to which the floor belongs. This is handy if you need this information later in your code. For more information about this identifier, please check this Section.
BuildingID: 8377
Floor Identifier
Then, we output the floor identifier.
FloorID: 20542
The floor identifier is automatically generated by Situm Platform when the floor is created. Another way to know the identifier of a floor is to edit that floor in Situm Dashboard.
Floor Name, Floor (order), Altitude and Custom Fields
After that, we see the floor name, the floor order, the altitude of that particular floor (in meters) and any user-defined custom-fields.
Name: F1 Floor (Order): 1 Altitude: 0.0 CustomFields: {show_in_app=true}
All this information can be configured when creating a floor:
Floorplan
The previous image shows how we can upload the floorplan image of a floor. Once we do that, we can retrieve this information with Situm SDK and output its information as shown in this section.
MapURL: URL{value='https://dashboard.situm.es/uploads/floor/20542/aa275ada-5ca2-4d51-be61-71fec14f29be.png', isAbsolute=true}Scale (pixels / meter): 17.25033570894508
The floorplan is provided as a URL object (Android, iOS). You may download the content from this URL (e.g. “https://dashboard.situm.es/uploads/floor/20541/51b985cf-4c2b-4327-bbab-a53b9c50b916.png” in this example) in order to download the floorplan image.
The scale of the floorplan is also provided in pixels per meter. This way, you may know how many meters are contained within each pixel. This can be handy, for instance, to compute distances within the floorplan image. Note that all floorplans have the same scale, since all floorplans must have the same size (width & height) in pixels.
Downloading all the floorplans of a building #
As explained in the previous section, you may retrieve the floorplan of each building by downloading it from its URL. Additionally, Situm SDK provides the method fetchMapFromFloor (Android, iOS) which handles the download for you. The Android following snippet shows an example.
//First, we need to fetch all the floors of the building (e.g. building 8377) SitumSdk.communicationManager().fetchFloorsFromBuilding("8377", new Handler<Collection<Floor>>() { @Override public void onSuccess(Collection<Floor> floors) { for (final Floor floor: floors) { //Then, we may download all the floorplans SitumSdk.communicationManager().fetchMapFromFloor(floor, new Handler<Bitmap>() { @Override public void onSuccess(Bitmap bitmap) { Log.i(TAG, "FloorId: " + floor.getIdentifier()); Log.i(TAG, " Size in pixels. Height: " + bitmap.getHeight() + " Width: " + bitmap.getWidth()); Log.i(TAG, " Size in meters. Height: " + bitmap.getHeight()/floor.getScale() + " Width: " + bitmap.getWidth()/floor.getScale()); } @Override public void onFailure(Error error) { Log.e(TAG, "Error: " + error); } }); } } @Override public void onFailure(Error error) { Log.e(TAG, "Error: " + error ); } });
Note that the floorplan is provided as an Android Bitmap object (or NSData in iOS, map image in Base64 in React Native, bitmap in Cordova). As an example, the previous snippet shows for each building the size of the image in pixels and in meters (using the Floor.getScale method).
FloorId: 20541 Size in pixels. Height: 758 Width: 1264 Size in meters. Height: 43.941173829268884 Width: 73.273936306327 FloorId: 20542 Size in pixels. Height: 758 Width: 1264 Size in meters. Height: 43.941173829268884 Width: 73.273936306327
Points of Interest (POIs) #
In Situm Platform, a building can have a number of Points of Interest that represent significative locations inside or outside of the building. For detailed information on points of interest, you may read their introductory description and how to create them in Situm Dashboard. You may also find interesting their data models as provided by Situm REST API Floor methods and Situm SDK Poi model (Android, iOS).
Fetching all the Indoor POIs of a building #
Situm allows both indoor POIs (within the floorplan limits) & outdoor POIs (outside the floorplan). The following Android code snippet shows how to retrieve the indoor POIs of a certain building and output their information on the application Log. For this example, we will use building 8377, which we know from a previous example.
The example uses the method fetchIndoorPOIsFromBuilding, available for Android, iOS, Cordova and ReactNative.
//Fetches all the indoor POIs from the building 8377 SitumSdk.communicationManager().fetchIndoorPOIsFromBuilding("8377", new Handler<Collection<Poi>>() { @Override public void onSuccess(Collection<Poi> pois) { //Receives all the buildings and loops over them for (Poi poi: pois){ Log.i(TAG, "BuildingID: " + poi.getBuildingIdentifier()); Log.i(TAG, "FloorID: " + poi.getFloorIdentifier()); Log.i(TAG, "PoiID: " + poi.getIdentifier()); Log.i(TAG, "Name: " + poi.getName()); Log.i(TAG, "InfoHTML: " + poi.getInfoHtml()); Log.i(TAG, "CustomFields: " + poi.getCustomFields()); Log.i(TAG, "Category:"); Log.i(TAG, " CategoryID: " + poi.getCategory().getIdentifier()); Log.i(TAG, " Code: " + poi.getCategory().getCode()); Log.i(TAG, " NameInLocale: " + poi.getCategory().getName()); Log.i(TAG, " NameInAllLanguages: " + poi.getCategory().getNameAsI18n()); Log.i(TAG, " IconURL (when selected): " + poi.getCategory().getSelectedIconUrl()); Log.i(TAG, " IconURL (when unselected): " + poi.getCategory().getUnselectedIconUrl()); Log.i(TAG, "Position:"); Log.i(TAG, " BuildingID: " + poi.getPosition().getBuildingIdentifier()); Log.i(TAG, " FloorID: " + poi.getPosition().getFloorIdentifier()); Log.i(TAG, " WSG84 Coordinate. Lat=" + poi.getPosition().getCoordinate().getLatitude() + " Lng="+poi.getPosition().getCoordinate().getLongitude()); Log.i(TAG, " Cartesian Coordinate (meters). X= " + poi.getPosition().getCartesianCoordinate().getX() + " Y="+ poi.getPosition().getCartesianCoordinate().getY()); Log.i(TAG, " IsIndoor? " + poi.getPosition().isIndoor()); } } @Override public void onFailure(Error error) { Log.e(TAG, "Error: " + error ); } });
In the previous code snippet, we are receiving a Collection of POI objects (Android, iOS). In this case, the POIs in Building 8377, over which we loop to print their properties. Your application logs should be something like this:
... BuildingID: 8377 FloorID: 20541 PoiID: 64478 Name: Shop InfoHTML: <p><b>Welcome to the shop!</b></p> CustomFields: {show_in_app=true} Category: CategoryID: 1206 Code: MC NameInLocale: My Category NameInAllLanguages: I18nString{values={spa=Mi categoría, eng=My Category}} IconURL (when selected): URL{value='/uploads/poicategoryselected/1206/b7bac260-f68d-4554-9054-d8a9be992618.png', isAbsolute=false} IconURL (when unselected): URL{value='/uploads/poicategory/1206/a04cf2b3-5c09-40d1-8dca-3f3d9ae3adde.png', isAbsolute=false} Position: BuildingID: 8377 FloorID: 20541 WSG84 Coordinate. Lat=42.8722187941717 Lng=-8.56361387801399 Cartesian Coordinate (meters). X=68.521411474978 Y=31.7456405070183 IsIndoor? true ... BuildingID: 8377 FloorID: 20541 PoiID: 64479 Name: Entrance InfoHTML: <p>Entrance</p>; CustomFields: {} Category: CategoryID: 148 Code: situm-default NameInLocale: No category NameInAllLanguages: I18nString{values={spa=Sin categoría, eng=No category}} IconURL (when selected): URL{value='/uploads/poicategoryselected/148/4c85ebd0-6ff2-4c1d-bad5-1f9f9eedc847.png', isAbsolute=false} IconURL (when unselected): URL{value='/uploads/poicategory/148/8ac8e04f-a6a0-4da5-a08d-02ec33ffdcfb.png', isAbsolute=false} Position: BuildingID: 8377 FloorID: 20541 WSG84 Coordinate. Lat=42.8724016056969 Lng=-8.56283871960868 Cartesian Coordinate (meters). X= 2.72343394626029 Lng=22.0525554105088 IsIndoor? true ...
Let’s examine them in detail.
Building and floor Identifier
First, you will notice that the POI data object allows you to retrieve the identifier of the building & floor to which the POI belongs. This is handy if you need this information later in your code.
BuildingID: 8377 FloorID: 20541
POI Identifier
Then, we output the POI identifier.
PoiID: 64478
The POI identifier is automatically generated by Situm Platform when the POI is created. Another way to know the identifier of a POI is to edit that POI in Situm Dashboard.
POI Name, free HTML information and custom fields
After that, we see the POI name, it free HTML info (filled using our Rich Text Editor) and the POI’s custom fields.
Name: Shop InfoHTML: <p><b>Welcome to the shop!</b></p> CustomFields: {show_in_app=true}
All this information can be configured when creating/editing the POI:
POI Category
The previous image shows that each POI can be assigned to a different category. For instance, a POI may be a shop, while other may be a restroom or an information point. Situm Dashboard comes with a predefined set of categories but also allows you to define your own. Categories are specially useful if you want to assign different icons to your POIs when showing them in your app, or if you want to build advanced search/filter utilities.
The POI data object contains a full PoiCategory data object instance, therefore we have access to all the details of the POI’s category. This can be seen in the log output:
Category: CategoryID: 1206 Code: MC NameInLocale: My Category NameInAllLanguages: I18nString{values={spa=Mi categoría, eng=My Category}} IconURL (when selected): URL{value='/uploads/poicategoryselected/1206/b7bac260-f68d-4554-9054-d8a9be992618.png', isAbsolute=false} IconURL (when unselected): URL{value='/uploads/poicategory/1206/a04cf2b3-5c09-40d1-8dca-3f3d9ae3adde.png', isAbsolute=false}
The category data includes the identifier of the category, its code, the name of the category (shown in the locale of the smartphone), the name of the category in all the supported languages, and the 2 URLs that will allow you to download the icons of the category (usually, one of them will be shown when the POI icon is selected, and the other when it is unselected).
POI Position
Last but not least, each POI will have a certain location. This location will be provided as an standard Situm Point data object whose info is shown on the log:
Position: BuildingID: 8377 FloorID: 20541 WSG84 Coordinate. Lat=42.8724016056969 Lng=-8.56283871960868 Cartesian Coordinate (meters). X=2.72343394626029 Y=22.0525554105088 IsIndoor? true
Fetching all the Outdoor POIs of a building #
Fetching the outdoor POIs of a building is similar to fetching the indoor ones: instead of using the CommunicationManager.fetchIndoorPOIsFromBuilding method, you may use the CommunicationManager.fetchOutdoorPOIsFromBuilding one. The snippet would be like this:
//Fetches all the outdoor POIs from the building 8377 SitumSdk.communicationManager().fetchOutdoorPOIsFromBuilding("8377", new Handler<Collection<Poi>>() { @Override public void onSuccess(Collection<Poi> pois) { //Receives all the buildings and loops over them for (Poi poi: pois){ Log.i(TAG, "BuildingID: " + poi.getBuildingIdentifier()); ... } } @Override public void onFailure(Error error) { Log.e(TAG, "Error: " + error ); } });
You may print all the POI information as in the Indoor POIs example to see a log output like the following one.
BuildingID: 8377 FloorID: -1 PoiID: 64480 Name: OutdoorPOI InfoHTML: CustomFields: {} Category: CategoryID: 148 Code: situm-default NameInLocale: No category NameInAllLanguages: I18nString{values={spa=Sin categoría, eng=No category}} IconURL (when selected): URL{value='/uploads/poicategoryselected/148/4c85ebd0-6ff2-4c1d-bad5-1f9f9eedc847.png', isAbsolute=false} IconURL (when unselected): URL{value='/uploads/poicategory/148/8ac8e04f-a6a0-4da5-a08d-02ec33ffdcfb.png', isAbsolute=false} Position: BuildingID: 8377 FloorID: -1 WSG84 Coordinate. Lat=42.872388178306 Lng=-8.56437136391785 Cartesian Coordinate (meters). X= 0.0 Y=0.0 IsIndoor? false
Notice that since this is an Outdoor POI, the floor identifier is “-1” (since the POI does not belong to any floor) and the POI.getPosition.isIndoor method returns false.
Fetching all the POIs of the user account #
Finally, you may be interested on fetching all the POIs of the user account, irregardless of the building where they have been created. You may do it by using the method CommunicationManager.fetchAllPOIsFromUser. This can be useful, for example, if you want to build an utility that is able to search across all the POIs of all the buildings.
//Fetches all the POIs from the user account SitumSdk.communicationManager().fetchAllPOIsFromUser( new Handler<Collection<Poi>>() { @Override public void onSuccess(Collection<Poi> pois) { //Receives all the buildings and loops over them for (Poi poi: pois){ Log.i(TAG, "BuildingID: " + poi.getBuildingIdentifier()); ... } } @Override public void onFailure(Error error) { Log.e(TAG, "Error: " + error ); } });
POI Categories #
We have seen that each POI has a POI category associated with it. Situm Platform has a set of default/predefined categories such as “Coffee”, “Elevator”, “Entrance”… or “No category”, which is a special category reserved for POIs that are not associated with any particular POI Category. Additionally, the user may also define its own category in Situm Dashboard.
For detailed information on POI Categories, you may also read their introductory description. You may also find interesting their data models as provided by Situm REST API Get POI Categories method and Situm SDK POI Category model.
Fetching all the POI Categories of the user #
The following code snippet shows how to retrieve the POIs categories of the user’s account and output their information on the application Log.
//Fetches all the POI Categories of the user's account SitumSdk.communicationManager().fetchPoiCategories(new Handler<Collection>() { @Override public void onSuccess(Collection poiCategories) { //We loop over all the POI categories to log their information for (PoiCategory poiCategory: poiCategories){ Log.i(TAG, "POICategoryID: "+ poiCategory.getIdentifier()); Log.i(TAG, " POICategoryName: "+ poiCategory.getName()); Log.i(TAG, " POICategoryNameI18n: "+ poiCategory.getNameAsI18n()); Log.i(TAG, " POICategoryCode: "+ poiCategory.getCode()); Log.i(TAG, " POICategoryCustomFields: "+ poiCategory.getCustomFields()); Log.i(TAG, " POICategorySelectedIconURL: "+ poiCategory.getSelectedIconUrl()); Log.i(TAG, " POICategorySelectedIconURL: "+ poiCategory.getUnselectedIconUrl()); } } @Override public void onFailure(Error error) { Log.e(TAG, "Error " + error); } });
The resulting log will be something like:
POICategoryID: 1 POICategoryName: Coffee POICategoryNameI18n: I18nString{values={spa=Cafetería, eng=Coffee}} POICategoryCode: situm-coffee POICategoryCustomFields: {} POICategorySelectedIconURL: URL{value='/uploads/poicategoryselected/1/fcfb13c6-44e7-4b58-b568-780ef41628f1.png', isAbsolute=false} POICategorySelectedIconURL: URL{value='/uploads/poicategory/1/b3d4b884-ed86-4ab5-929d-3e5a40502e56.png', isAbsolute=fals POICategoryID: 2 POICategoryName: Elevator POICategoryNameI18n: I18nString{values={spa=Ascensor, eng=Elevator}} POICategoryCode: situm-elevator POICategoryCustomFields: {} POICategorySelectedIconURL: URL{value='/uploads/poicategoryselected/2/f43bbdb4-4844-4147-9a1f-e7db307bc439.png', isAbsolute=false} POICategorySelectedIconURL: URL{value='/uploads/poicategory/2/9b3247fd-148d-4098-82a3-3e4d6e4deb33.png', isAbsolute=false} POICategoryID: 3 POICategoryName: Entrance POICategoryNameI18n: I18nString{values={spa=Acceso, eng=Entrance}} POICategoryCode: situm-entrance POICategoryCustomFields: {} POICategorySelectedIconURL: URL{value='/uploads/poicategoryselected/3/4618b474-efb3-4152-b5c2-1ba2c2dabcc0.png', isAbsolute=false} POICategorySelectedIconURL: URL{value='/uploads/poicategory/3/1999aa2f-c137-469d-83cd-4c3624bec39d.png', isAbsolute=false} POICategoryID: 4 POICategoryName: Information POICategoryNameI18n: I18nString{values={spa=Información, eng=Information}} POICategoryCode: situm-info POICategoryCustomFields: {} POICategorySelectedIconURL: URL{value='/uploads/poicategoryselected/4/331a12fc-bef3-4b78-b5aa-6b2e98fc2b16.png', isAbsolute=false} POICategorySelectedIconURL: URL{value='/uploads/poicategory/4/91f3a501-5f71-4a67-8ea3-b8e1a63eb911.png', isAbsolute=false} POICategoryID: 5 POICategoryName: Parking POICategoryNameI18n: I18nString{values={spa=Aparcamiento, eng=Parking}} POICategoryCode: situm-parking POICategoryCustomFields: {} POICategorySelectedIconURL: URL{value='/uploads/poicategoryselected/5/77719daa-4e0e-468c-9ca6-05516053304d.png', isAbsolute=false} POICategorySelectedIconURL: URL{value='/uploads/poicategory/5/c9858e94-c49a-4d3a-be3d-278168fa611a.png', isAbsolute=false} POICategoryID: 6 POICategoryName: Ramp POICategoryNameI18n: I18nString{values={spa=Rampa, eng=Ramp}} POICategoryCode: situm-ramp POICategoryCustomFields: {} POICategorySelectedIconURL: URL{value='/uploads/poicategoryselected/6/8b1efad0-9e3c-4e47-941a-18ed88aecab4.png', isAbsolute=false} POICategorySelectedIconURL: URL{value='/uploads/poicategory/6/e3c0d140-f2e9-4088-ab9f-77fa54c4adc7.png', isAbsolute=false} POICategoryID: 7 POICategoryName: Shop POICategoryNameI18n: I18nString{values={spa=Tienda, eng=Shop}} POICategoryCode: situm-shop POICategoryCustomFields: {} POICategorySelectedIconURL: URL{value='/uploads/poicategoryselected/7/2038ed3a-d5c3-4aee-9ca5-2e994b717bcc.png', isAbsolute=false} POICategorySelectedIconURL: URL{value='/uploads/poicategory/7/76bfcad9-5df2-4331-85a7-b51e03379883.png', isAbsolute=false} POICategoryID: 8 POICategoryName: Stairs POICategoryNameI18n: I18nString{values={spa=Escaleras, eng=Stairs}} POICategoryCode: situm-stairs POICategoryCustomFields: {} POICategorySelectedIconURL: URL{value='/uploads/poicategoryselected/8/2c7aaeba-8695-4272-a35d-222675b9f788.png', isAbsolute=false} POICategorySelectedIconURL: URL{value='/uploads/poicategory/8/5e81ef12-d5e4-4213-ad24-25db43ac2911.png', isAbsolute=false} POICategoryID: 9 POICategoryName: Toilets POICategoryNameI18n: I18nString{values={spa=Aseos, eng=Toilets}} POICategoryCode: situm-toilets POICategoryCustomFields: {} POICategorySelectedIconURL: URL{value='/uploads/poicategoryselected/9/95a7f721-3a00-481e-8786-6126e8d6533e.png', isAbsolute=false} POICategorySelectedIconURL: URL{value='/uploads/poicategory/9/5a6a82df-1b47-4afa-bf91-5c06427fb0a7.png', isAbsolute=false} POICategoryID: 148 POICategoryName: No category POICategoryNameI18n: I18nString{values={spa=Sin categoría, eng=No category}} POICategoryCode: situm-default POICategoryCustomFields: {} POICategorySelectedIconURL: URL{value='/uploads/poicategoryselected/148/4c85ebd0-6ff2-4c1d-bad5-1f9f9eedc847.png', isAbsolute=false} POICategorySelectedIconURL: URL{value='/uploads/poicategory/148/8ac8e04f-a6a0-4da5-a08d-02ec33ffdcfb.png', isAbsolute=false} POICategoryID: 1206 POICategoryName: My Category POICategoryNameI18n: I18nString{values={spa=Mi categoría, eng=My Category}} POICategoryCode: MC POICategoryCustomFields: {} POICategorySelectedIconURL: URL{value='/uploads/poicategoryselected/1206/b7bac260-f68d-4554-9054-d8a9be992618.png', isAbsolute=false} POICategorySelectedIconURL: URL{value='/uploads/poicategory/1206/a04cf2b3-5c09-40d1-8dca-3f3d9ae3adde.png', isAbsolute=false}
Notice that the POICategories with IDs 1 to 9 are Situm’s predefined categories and ID 148 belongs to the reserved category “No Category”, which will be associated to POIs that should not belong to any category. Finally, in this particular example, category with ID 1206 is an user-defined one. Let’s examine this category in detail.
POICategoryID: 1206 POICategoryName: My Category POICategoryNameI18n: I18nString{values={spa=Mi categoría, eng=My Category}} POICategoryCode: MC POICategoryCustomFields: {} POICategorySelectedIconURL: URL{value='/uploads/poicategoryselected/1206/b7bac260-f68d-4554-9054-d8a9be992618.png', isAbsolute=false} POICategorySelectedIconURL: URL{value='/uploads/poicategory/1206/a04cf2b3-5c09-40d1-8dca-3f3d9ae3adde.png', isAbsolute=false}
We can see that the application log shows the main information of the POICategory data object, which includes:
- The identifier of the category.
- Its code
- The name of the category (shown in the locale of the smartphone).
- The name of the category in all the supported languages (english & spanish).
- The URL to download the main icon (called Selected Icon because it is usually shown when a POI has not been selected by the user yet).
- The URL to download the secondary icon (called Unselected Icon because it is usually shown when a POI has been selected by the user).
Fetching all the POI Categories Icons #
In addition to retrieving all the POI Categories, you will probably want to download their icons. The following snippet shows you how to do it.
//Fetches all the POI Categories of the user's account SitumSdk.communicationManager().fetchPoiCategories(new Handler<Collection<PoiCategory>>() { @Override public void onSuccess(Collection<PoiCategory> poiCategories) { //We loop over all the POI categories to download their icons for (final PoiCategory poiCategory: poiCategories){ //Downloading the Main Icons (Selected Icons) SitumSdk.communicationManager().fetchPoiCategoryIcon(poiCategory, true, new Handler<Bitmap>() { @Override public void onSuccess(Bitmap bitmap) { Log.i(TAG, "POICategoryID: " + poiCategory.getIdentifier()); Log.i(TAG, " SelectedIcon hashcode: " + bitmap.hashCode()); } @Override public void onFailure(Error error) { Log.e(TAG, "Error " + error); } }); //Downloading the Secondary Icons (Unselected Icons) SitumSdk.communicationManager().fetchPoiCategoryIcon(poiCategory, false, new Handler<Bitmap>() { @Override public void onSuccess(Bitmap bitmap) { Log.i(TAG, "POICategoryID: " + poiCategory.getIdentifier()); Log.i(TAG, " UnselectedIcon hashcode: " + bitmap.hashCode()); } @Override public void onFailure(Error error) { Log.e(TAG, "Error " + error); } }); } } @Override public void onFailure(Error error) { Log.e(TAG, "Error " + error); } });
Note that the icons are provided as Android Bitmap objects. As an example, the previous snippet shows the hash code of each icon.
POICategoryID: 1 SelectedIcon hashcode: 27274630 POICategoryID: 1 UnselectedIcon hashcode: 179725895 POICategoryID: 2 SelectedIcon hashcode: 79519348 POICategoryID: 2 UnselectedIcon hashcode: 153141149 POICategoryID: 3 SelectedIcon hashcode: 230792210 POICategoryID: 3 UnselectedIcon hashcode: 15278051 POICategoryID: 4 SelectedIcon hashcode: 126610912 POICategoryID: 4 UnselectedIcon hashcode: 72267929 POICategoryID: 5 SelectedIcon hashcode: 18442078 POICategoryID: 5 UnselectedIcon hashcode: 100915007 POICategoryID: 6 SelectedIcon hashcode: 82970636 POICategoryID: 6 UnselectedIcon hashcode: 248071509 POICategoryID: 7 SelectedIcon hashcode: 59808618 POICategoryID: 7 UnselectedIcon hashcode: 32024667 POICategoryID: 8 SelectedIcon hashcode: 79534328 POICategoryID: 8 UnselectedIcon hashcode: 19259857 POICategoryID: 9 SelectedIcon hashcode: 9765942 POICategoryID: 9 UnselectedIcon hashcode: 243232567 POICategoryID: 148 SelectedIcon hashcode: 196037796 POICategoryID: 148 UnselectedIcon hashcode: 232114701 POICategoryID: 1206 SelectedIcon hashcode: 178597314 POICategoryID: 1206 UnselectedIcon hashcode: 38914003
Geofences #
In Situm Platform, a building can have a number of Geofences. Geofences are polygonal areas that are delimited for a number of purposes: showing a message to the user when she enters, triggering an alarm if an area is too crowded, analysing the time the users spend in each area, etc.
For detailed information on geofences, you may read their introductory description and how to create them in Situm Dashboard. You may also find interesting their data models as provided by Situm REST API Geofence methods and Situm SDK Geofence model.
Fetching all the Geofences of a building #
The following code snippet shows how to retrieve the geofences of a certain building and output their information on the application Log. For this example, we will use building 8377, which we know from a previous example.
//Fetches all the geofences from the building 8377 Building building = new Building.Builder().identifier("8377").build(); SitumSdk.communicationManager().fetchGeofencesFromBuilding(building, new Handler<List<Geofence>>() { @Override public void onSuccess(List<Geofence> geofences) { for (Geofence geofence: geofences){ Log.i(TAG, "BuildingID: "+ geofence.getBuildingIdentifier()); Log.i(TAG, "FloorID: "+ geofence.getFloorIdentifier()); Log.i(TAG, "GeofenceID: "+ geofence.getIdentifier()); Log.i(TAG, "Name: "+ geofence.getName()); Log.i(TAG, "InfoHTML: "+ geofence.getInfoHtml()); Log.i(TAG, "CustomFields: "+ geofence.getCustomFields()); Log.i(TAG, "PolygonPoints: "); for (Point p: geofence.getPolygonPoints()){ Log.i(TAG, " Point:"); Log.i(TAG, " BuildingID: " + p.getBuildingIdentifier()); Log.i(TAG, " FloorID: " + p.getFloorIdentifier()); Log.i(TAG, " WSG84 Coordinate. Lat=" + p.getCoordinate().getLatitude() + " Lng="+p.getCoordinate().getLongitude()); Log.i(TAG, " IsIndoor? " + p.isIndoor()); } } } @Override public void onFailure(Error error) { Log.e(TAG, "Error: " + error ); } });
In the previous code snippet, we are receiving a List of Geofence objects (the geofences in Building 8377), and we loop over them to print their properties. Your application logs should be something like this:
... BuildingID: 8377 FloorID: 20541 GeofenceUUID: dc7a83da-cb3b-4476-9f0c-9c75e97bc98e Name: Entrance InfoHTML: <p><strong>Welcome!</strong></p> CustomFields: {show_in_app=true} PolygonPoints: Point: BuildingID: 8377 FloorID: 20541 WSG84 Coordinate. Lat=42.87247616887151 Lng=-8.562831151227792 IsIndoor? true Point: BuildingID: 8377 FloorID: 20541 WSG84 Coordinate. Lat=42.87246158665294 Lng=-8.56293384594478 IsIndoor? true Point: BuildingID: 8377 FloorID: 20541 WSG84 Coordinate. Lat=42.872350236963406 Lng=-8.562851147272264 IsIndoor? true Point: BuildingID: 8377 FloorID: 20541 WSG84 Coordinate. Lat=42.87247616887151 Lng=-8.562831151227792 IsIndoor? true ...
Let’s examine them in detail.
Building and floor Identifier
First, you will notice that the Geofence data object allows you to retrieve the identifier of the building & floor to which the geofence belongs. This is handy if you need this information later in your code.
BuildingID: 8377 FloorID: 20541
Geofence Identifier (UUID)
Then, we output the geofence identifier. Unlike other cartography identifiers (such as building, floor or POI identifiers), the geofence identifier comes in UUID format. UUID format that all new entities introduced in Situm (such as geofences) follow. Other identifier formats are considered legacy and will eventually be deprecated.
GeofenceUUID: dc7a83da-cb3b-4476-9f0c-9c75e97bc98e
The geofence identifier is automatically generated by Situm Platform when the geofence is created. Another way to know the identifier of a geofence is to edit that geofence in Situm Dashboard.
Geofence Name, free HTML information and custom fields
After that, we see the geofence name, its free HTML info (filled using our Rich Text Editor) and the POI’s custom fields.
Name: Entrance InfoHTML: <p><strong>Welcome!</strong></p> CustomFields: {show_in_app=true}
All this information can be configured when creating/editing the geofence:
Geofence Polygon
Last but not least, each geofence will have occupy a certain area defined as a polygon. This polygon is defined as a List of Situm Points, where:
- Each point represents a vertex of the polygon.
- The first & last points are the same point. Therefore, a triangle will have 4 points (1 repeated), a rectangle 5 points, and so on. This is to ensure that the list of points represents a closed surface.
PolygonPoints: Point: BuildingID: 8377 FloorID: 20541 WSG84 Coordinate. Lat=42.87247616887151 Lng=-8.562831151227792 IsIndoor? true Point: BuildingID: 8377 FloorID: 20541 WSG84 Coordinate. Lat=42.87246158665294 Lng=-8.56293384594478 IsIndoor? true Point: BuildingID: 8377 FloorID: 20541 WSG84 Coordinate. Lat=42.872350236963406 Lng=-8.562851147272264 IsIndoor? true Point: BuildingID: 8377 FloorID: 20541 WSG84 Coordinate. Lat=42.87247616887151 Lng=-8.562831151227792 IsIndoor? true
In this example, this is the geofence that has been output in the log.
Building Info: Floors, POIs and geofences all together #
In previous sections, we have seen how to fetch Buildings, Floors, POIs and Geofences from Situm Platform using Situm SDK. Instead of having to fetch each resource separately, Situm SDK also allows you to retrieve all this information with a single network call.
The following code snippet shows how to retrieve all the information of building 8377 ( which we know from a previous example) and output its information on the application Log.
//Fetches all the information (basic building info, floors, POIs, genfences) from building 8377 Building building = new Building.Builder().identifier("8377").build(); SitumSdk.communicationManager().fetchBuildingInfo(building.getIdentifier(), new Handler<BuildingInfo>() { //The onSuccess method receives the BuildingInfo data object ... @Override public void onSuccess(BuildingInfo buildingInfo) { //... which contains all the relevant cartography entities associated with the building Building buildingBasicInfo = buildingInfo.getBuilding(); Collection<Floor> floors = buildingInfo.getFloors(); Collection<Poi> indoorPOIs = buildingInfo.getIndoorPOIs(); Collection<Poi> outdoorPOIs = buildingInfo.getOutdoorPOIs(); Collection<Geofence> geofences = buildingInfo.getGeofences(); Log.i(TAG, "BuildingBasicInfo = [" + buildingBasicInfo + "]"); Log.i(TAG, "Floors = [" + floors + "]"); Log.i(TAG, "IndoorPOIs = [" + indoorPOIs + "]"); Log.i(TAG, "OutdoorPOIs = [" + outdoorPOIs + "]"); Log.i(TAG, "Geofences = [" + geofences + "]"); } @Override public void onFailure(Error error) { Log.e(TAG, "Error " + error); } });
In the previous code snippet, we are receiving a BuildingInfo data object, which contains:
- A Building data object with the basic building information. See this example to know how to treat this information.
- A Collection of Floor objects with the floor’s information. See this example to know how to treat this information.
- A Collection of POI objects with the indoor POI’s information. See this example to know how to treat this information.
- A Collection of POI objects with the outdoor POI’s information. See this example to know how to treat this information.
- A Collection of Geofence objects with the geofences information. See this example to know how to treat this information.
BuildingBasicInfo = [Building{userIdentifier='-1', name='Situm HQ', address='Rúa do Restollal, nº 32 Edificio Paxonal, Planta 4, Of. 401 15702, Santiago de Compostela, A Coruña, Spain', infoHtml='<p><strong>Welcome to Situm!</strong></p><p><br></p>', center=Coordinate{latitude=42.872352, longitude=-8.563249}, rotation=Angle{radians=2.95, degrees=169.23}, dimensions=Dimensions{width=73.273936306327, height=43.9411738292689}, pictureUrl=URL{value='/uploads/building/8377/6d8423b9-61b5-4015-a0aa-0faf3c9c66cc.png', isAbsolute=false}, pictureThumbUrl=URL{value='/uploads/building/8377/6d8423b9-61b5-4015-a0aa-0faf3c9c66cc.png', isAbsolute=false}} Resource{identifier='8377', updatedAt=1617296565984, createdAt=1617268218730, customFields={external_cms_id=102301, show_in_app=true}}] Floors = [[Floor{buildingIdentifier='8377', name='F0', floor=0, scale=17.25033570894508, altitude=0.0, mapUrl=URL{value='https://dashboard.situm.es/uploads/floor/20541/51b985cf-4c2b-4327-bbab-a53b9c50b916.png', isAbsolute=true}}, Floor{buildingIdentifier='8377', name='F1', floor=1, scale=17.25033570894508, altitude=15.0, mapUrl=URL{value='https://dashboard.situm.es/uploads/floor/20542/aa275ada-5ca2-4d51-be61-71fec14f29be.png', isAbsolute=true}}]] IndoorPOIs = [[Poi{name='Shop', infoHtml='<p><b>Welcome to the shop!</b></p>', category=PoiCategory{code='MC', name=I18nString{values={spa=Mi categoría, eng=My Category}}, unselectedIconUrl=URL{value='/uploads/poicategory/1206/a04cf2b3-5c09-40d1-8dca-3f3d9ae3adde.png', isAbsolute=false}, selectedIconUrl=URL{value='/uploads/poicategoryselected/1206/b7bac260-f68d-4554-9054-d8a9be992618.png', isAbsolute=false}, isPublic=false} Resource{identifier='1206', updatedAt=0, createdAt=0, customFields={}}, position=Point{buildingIdentifier='8377', floorIdentifier='20541', cartesianCoordinate=CartesianCoordinate{x=71.66, y=1.71}, coordinate=Coordinate{latitude=42.872473, longitude=-8.563716}, isOutdoor=false}} Resource{identifier='64478', updatedAt=0, createdAt=0, customFields={show_in_app=true}}, Poi{name='Entrance', infoHtml='<p>Entrance</p>', category=PoiCategory{code='situm-default', name=I18nString{values={spa=Sin categoría, eng=No category}}, unselectedIconUrl=URL{value='/uploads/poicategory/148/8ac8e04f-a6a0-4da5-a08d-02ec33ffdcfb.png', isAbsolute=false}, selectedIconUrl=URL{value='/uploads/poicategoryselected/148/4c85ebd0-6ff2-4c1d-bad5-1f9f9eedc847.png', isAbsolute=false}, isPublic=true} Resource{identifier='148', updatedAt=0, createdAt=0, customFields={}}, position=Point{buildingIdentifier='8377', floorIdentifier='20541', cartesianCoordinate=CartesianCoordinate{x=2.69, y=22.18}, coordinate=Coordinate{latitude=42.872408, longitude=-8.562840}, isOutdoor=false}} Resource{identifier='64479', updatedAt=0, createdAt=0, customFields={}}]] OutdoorPOIs = [[Poi{name='OutdoorPOI', infoHtml='', category=PoiCategory{code='situm-default', name=I18nString{values={spa=Sin categoría, eng=No category}}, unselectedIconUrl=URL{value='/uploads/poicategory/148/8ac8e04f-a6a0-4da5-a08d-02ec33ffdcfb.png', isAbsolute=false}, selectedIconUrl=URL{value='/uploads/poicategoryselected/148/4c85ebd0-6ff2-4c1d-bad5-1f9f9eedc847.png', isAbsolute=false}, isPublic=true} Resource{identifier='148', updatedAt=0, createdAt=0, customFields={}}, position=Point{buildingIdentifier='8377', floorIdentifier='-1', cartesianCoordinate=CartesianCoordinate{x=0.00, y=0.00}, coordinate=Coordinate{latitude=42.872474, longitude=-8.562138}, isOutdoor=true}} Resource{identifier='64480', updatedAt=0, createdAt=0, customFields={}}]] Geofences = [[Geofence{name='Entrance', code='G0', infoHtml='<p><strong>Welcome!</strong></p>', floorIdentifier='20541', buildingIdentifier='8377', polygonPoints=[Point{buildingIdentifier='8377', floorIdentifier='20541', cartesianCoordinate=CartesianCoordinate{x=0.52, y=14.85}, coordinate=Coordinate{latitude=42.872476, longitude=-8.562831}, isOutdoor=false}, Point{buildingIdentifier='8377', floorIdentifier='20541', cartesianCoordinate=CartesianCoordinate{x=9.07, y=14.88}, coordinate=Coordinate{latitude=42.872462, longitude=-8.562934}, isOutdoor=false}, Point{buildingIdentifier='8377', floorIdentifier='20541', cartesianCoordinate=CartesianCoordinate{x=4.74, y=28.29}, coordinate=Coordinate{latitude=42.872350, longitude=-8.562851}, isOutdoor=false}, Point{buildingIdentifier='8377', floorIdentifier='20541', cartesianCoordinate=CartesianCoordinate{x=0.52, y=14.85}, coordinate=Coordinate{latitude=42.872476, longitude=-8.562831}, isOutdoor=false}]}]]