Use floor aware maps

The term floor-aware refers to maps and scenes with indoor features that can be queried for their level inside a facility. Apps and APIs that support floor-awareness provide tools to visualize and interact with floor-aware indoor data. Once created and saved using ArcGIS Pro, a floor-aware map can be consumed inside your ArcGIS Runtime app.

Refer to the Floor-aware maps topic in the ArcGIS Pro documentation for details about creating floor-aware maps and scenes.

Filter display by floor

Some common use cases for working with floor-aware maps include:

  • Filter the display to only show features on a specified level (floor) of a facility.
  • Evaluate the availability and distribution of critical assets for a facility, such as fire extinguishers or defibrillators.
  • Apply a floor filter based on an indoor positioning system (IPS) location.
  • Track assets, such as mobile devices, that may move between facilities and levels.

Use ArcGIS Runtime to:

Floor-aware data model

The floor-aware data model is organized into a hierarchy of layers that describe relevant indoor features and their relationships. Features are associated with a specific level (floor, in other words). Levels are contained within a facility (such as a building), and facilities can belong to a site (for example, a shopping center, industrial complex, or college campus).

A floor-aware map must include, at a minimum, a layer representing facilities and a layer representing levels. These layers must include specific fields that identify the features and define their hierarchical relationships, such as which levels are contained by a given facility. Indoor features can then be assigned the appropriate level within a facility.

Read floor-aware metadata

Floor filtering requires floor-awareness settings defined for the map. When a floor-aware map is loaded, ArcGIS Runtime reads floor-aware metadata and populates the following classes.

These classes describe which layers and fields are used to support floor-aware mapping. While you could use this information to build queries to explore floor-aware relationships (facilities within a site, levels within a facility, and so on), ArcGIS Runtime provides additional API to read floor-aware metadata and to implement floor filtering that abstracts these details.

  • GeoModelFloorDefinition: exposes classes that define the sites, facilities, and levels configured in the map's floor-aware settings. This is null for maps that are not floor-aware.

  • SiteLayerDefinition: defines the layer and field properties for the (optional) site layer. A site layer defines the boundaries of managed sites (such as college campuses) that each contain one or more facilities.

  • FacilityLayerDefinition: defines the layer and field properties for the facility layer, which describes the footprints of managed facilities containing one or more levels.

  • LevelLayerDefinition: defines the layer and field properties for the level layer, which describes the footprint of each occupiable floor within a facility.

Floor-aware layers

Layers that contain features associated with a specific level within a facility expose floor-aware settings through a IFloorAware interface. Layers that support floor-awareness, such as FeatureLayer, implement this interface.

IFloorAware defines a read-write FloorDefinition property of type LayerFloorDefinition that contains the properties that allow a layer to be floor-aware (such as the level at which a feature exists). Changing this property on-the-fly updates the floor filtering behavior. Setting or clearing this property toggles the floor filter rendering for the layer.

Iterate the floor-aware data model

You can iterate the floor-aware data model for a Map to find all available sites, facilities, and levels. You can also find all the facilities for a given site or all levels for a specific facility.

The FloorManager class exposes the sites, facilities, and levels of the floor-aware data model. You can get the FloorManager using the read-only FloorManager property of a map. This property returns null for maps that are not floor-aware. FloorManager inherits from ILoadable and must be loaded before sites, facilities, and levels are available.

                                                                            
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// Fix blank line
using Esri.ArcGISRuntime.Mapping;
using Esri.ArcGISRuntime.UI.Controls;

Esri.ArcGISRuntime.ArcGISRuntimeEnvironment.ApiKey = "YOUR_API_KEY";

var map = new Map(BasemapStyle.ArcGISNavigation);



Map webMap = new Map(new Uri("https://www.arcgis.com/home/item.html?id=acc027394bc84c2fb04d1ed317aac674"));



MapView mapView = new MapView();
mapView.Map = map;
mapView.SetViewpointCenterAsync(latitude: 34.027,
                                longitude: -118.805,
                                scale: 72223.819286);


// --- Floor-aware maps ---
private async void SetVisibleFloorForFacility(int selectedLevelNum, string selectedFacilityId)
{
    Map map = MainMapView.Map;

    // FloorManager is null until the Map is loaded.
    await map.LoadAsync();

    FloorManager floorManager = map.FloorManager;
    if (floorManager == null)
    {
        // The map is not floor aware, exit.
        return;
    }

    // FloorManager properties are not instantiated until loaded.
    await floorManager.LoadAsync();


    // Get the chosen site from the FloorManager (using its unique site ID).
    FloorSite selectedSite = floorManager.Sites.FirstOrDefault(s => s.SiteId == selectedSiteId);

    // Get the chosen facility within the selected site (using its unique facility ID).
    FloorFacility building = selectedSite.Facilities.FirstOrDefault(f => f.FacilityId == selectedFacilityId);
    if (building == null) { return; }

    // Set the viewpoint to center on this facility (to better see the levels).
    var facilityViewpoint = new Viewpoint(building.Geometry);
    MainMapView.SetViewpoint(facilityViewpoint);

    // Get all levels for this facility.
    IReadOnlyList<FloorLevel> facilityLevels = building.Levels;

    // Iterate all levels in the collection.
    foreach (FloorLevel lvl in facilityLevels)
    {
        // Set levels with the selected level number visible.
        lvl.IsVisible = lvl.LevelNumber == selectedLevelNum;
    }

}


// Get all sites, facilities, and levels
IReadOnlyList<FloorSite> allSites = floorManager.Sites;
IReadOnlyList<FloorFacility> allFacilities = floorManager.Facilities;
IReadOnlyList<FloorLevel> allLevels = floorManager.Levels;

// Get all facilities for a particular site.
FloorSite mainCampus = floorManager.Sites.FirstOrDefault(s => s.SiteId == "ESRI.RED.MAIN");
IReadOnlyList<FloorFacility> mainCampusBuildings = mainCampus.Facilities;

// Get all levels for a particular facility.
FloorFacility buildingQ = floorManager.Facilities.FirstOrDefault(f => f.FacilityId == "ESRI.RED.MAIN.Q");
IReadOnlyList<FloorLevel> buildingQLevels = buildingQ.Levels;

You can use the FloorManager to build a UI that allows your user to explore available sites, facilities, and levels in the map. For example, you can provide a tree view or set of list controls so the user can filter facilities by site, and then see all levels within a chosen facility.

See the ArcGIS API for JavaScript FloorFilter widget for an example of such a control. This control is also used in the ArcGIS Online Map Viewer for floor-aware maps.

Floor control in the ArcGIS Online Map Viewer

Filter features by floor

FloorManager exposes a collection of FloorLevel, which includes properties that describe the following aspects of a level.

  • Associated facility: the facility that contains this level.
  • Visibility: whether or not the level is currently visible in the map.
  • Level ID: a string that uniquely identifies the level (across all levels in all facilities).
  • Level number: the number assigned to this level. This can differ from the actual order of the level. Some facilities, for example, don't designate a 13th floor. Instead, this level may be given a level number of 14.
  • Long name: a descriptive name of the level. A good convention for creating a clear description of the level is to use the facility name and level number for the long name.
  • Short name: a more succinct version of the long name. This is useful for showing a compact name in a UI element, such as a drop down list.
  • Vertical order: the actual position of the level in the collection of levels, sorted from low to high. The level order is zero-based. The ground floor is level 0, levels below it are negative, floors above positive.
  • Shape: a polygon geometry that describes the level.

Levels can be shown or hidden to filter the display for a specified level or levels in the map, either for a specific facility, multiple facilities, or across all facilities. The display of all floor-aware features is filtered according to the visibility of their associated level.

To display a single level for all facilities:

  1. Make sure the map is loaded.
  2. Get the map's FloorManager.
    • If the map is not floor-aware, the FloorManager will be null.
  3. Load the FloorManager to read the floor-aware data.
  4. Get the FloorLevel collection from the map's FloorManager.
    • This returns all levels for all facilities in the map.
  5. Iterate all FloorLevel objects in the collection.
    • Set the chosen level as visible.
    • Set all other levels as not visible.
                                      
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
using Esri.ArcGISRuntime.Data;
using Esri.ArcGISRuntime.Mapping;
using Esri.ArcGISRuntime.Mapping.Floor;
using System;
using System.Collections.Generic;
using System.Linq;

public class FloorFilter
{
    private async void SetVisibleFloor(int selectedVerticalPosition)
    {
        Map map = MainMapView.Map;

        // FloorManager is null until the Map is loaded.
        await map.LoadAsync();

        FloorManager floorManager = map.FloorManager;
        if (floorManager == null)
        {
            // The map is not floor aware, exit.
            return;
        }

        // FloorManager properties are not instantiated until loaded.
        await floorManager.LoadAsync();

        // Get all levels from FloorManager.
        IReadOnlyList<FloorLevel> allLevels = floorManager.Levels;

        // Iterate all levels in the collection.
        foreach (FloorLevel lvl in allLevels)
        {
            // Set levels with the selected vertical order visible.
            lvl.IsVisible = lvl.VerticalOrder == selectedVerticalPosition;
        }

    }
}

To display a single level in a chosen facility:

  1. Make sure the map is loaded.
  2. Get the map's FloorManager.
    • If the map is not floor-aware, the FloorManager will be null.
  3. Load the FloorManager to read the floor-aware data.
  4. Get the chosen site, represented by a FloorSite object.
  5. Get the chosen facility from the collection of facilities for the site, represented by a FloorFacility object.
  6. Set the map view's viewpoint using the facility's geometry.
  7. Get the FloorLevel collection for the facility (exposed as a property on FloorFacility).
  8. Iterate all FloorLevel objects in the collection.
    • Set the chosen level as visible.
    • Set all other levels as not visible.
                                                                            
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
// Fix blank line
using Esri.ArcGISRuntime.Mapping;
using Esri.ArcGISRuntime.UI.Controls;

Esri.ArcGISRuntime.ArcGISRuntimeEnvironment.ApiKey = "YOUR_API_KEY";

var map = new Map(BasemapStyle.ArcGISNavigation);



Map webMap = new Map(new Uri("https://www.arcgis.com/home/item.html?id=acc027394bc84c2fb04d1ed317aac674"));



MapView mapView = new MapView();
mapView.Map = map;
mapView.SetViewpointCenterAsync(latitude: 34.027,
                                longitude: -118.805,
                                scale: 72223.819286);


// --- Floor-aware maps ---
private async void SetVisibleFloorForFacility(int selectedLevelNum, string selectedFacilityId)
{
    Map map = MainMapView.Map;

    // FloorManager is null until the Map is loaded.
    await map.LoadAsync();

    FloorManager floorManager = map.FloorManager;
    if (floorManager == null)
    {
        // The map is not floor aware, exit.
        return;
    }

    // FloorManager properties are not instantiated until loaded.
    await floorManager.LoadAsync();


    // Get the chosen site from the FloorManager (using its unique site ID).
    FloorSite selectedSite = floorManager.Sites.FirstOrDefault(s => s.SiteId == selectedSiteId);

    // Get the chosen facility within the selected site (using its unique facility ID).
    FloorFacility building = selectedSite.Facilities.FirstOrDefault(f => f.FacilityId == selectedFacilityId);
    if (building == null) { return; }

    // Set the viewpoint to center on this facility (to better see the levels).
    var facilityViewpoint = new Viewpoint(building.Geometry);
    MainMapView.SetViewpoint(facilityViewpoint);

    // Get all levels for this facility.
    IReadOnlyList<FloorLevel> facilityLevels = building.Levels;

    // Iterate all levels in the collection.
    foreach (FloorLevel lvl in facilityLevels)
    {
        // Set levels with the selected level number visible.
        lvl.IsVisible = lvl.LevelNumber == selectedLevelNum;
    }

}


// Get all sites, facilities, and levels
IReadOnlyList<FloorSite> allSites = floorManager.Sites;
IReadOnlyList<FloorFacility> allFacilities = floorManager.Facilities;
IReadOnlyList<FloorLevel> allLevels = floorManager.Levels;

// Get all facilities for a particular site.
FloorSite mainCampus = floorManager.Sites.FirstOrDefault(s => s.SiteId == "ESRI.RED.MAIN");
IReadOnlyList<FloorFacility> mainCampusBuildings = mainCampus.Facilities;

// Get all levels for a particular facility.
FloorFacility buildingQ = floorManager.Facilities.FirstOrDefault(f => f.FacilityId == "ESRI.RED.MAIN.Q");
IReadOnlyList<FloorLevel> buildingQLevels = buildingQ.Levels;

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.