IMDF vs. IndoorGML for Indoor Map Interchange

Part of Indoor Map Data Standards: the two standards that were actually designed for indoor navigation, what each does better, and why the better-designed one is usually not the one to publish.

What Each Standard Is For

How the two standards model the same building differently A two-column comparison of modelling concepts. In IMDF a room is a unit Feature, a doorway is an opening LineString, and the routing graph is derived by the consumer; levels carry an ordinal, features are identified by UUID, and there is one implicit topology. In IndoorGML a room is a CellSpace, a doorway is a CellSpaceBoundary, and the graph is an explicit layer of States and Transitions; levels are layers of a MultiLayeredGraph, features carry gml ids, and multiple graph layers can coexist, one per travel mode or accessibility profile. Same building, two vocabularies, one genuine capability difference Concept IMDF IndoorGML A room is a `unit` Feature a `CellSpace` A doorway is an `opening` LineString a `CellSpaceBoundary` The graph is △ derived by the consumer ● a `State`/`Transition` layer Levels are `level` with an `ordinal` `MultiLayeredGraph` layers Identity UUID per feature gml:id per feature Multiple graphs △ one implicit topology ● one layer per mode or profile IndoorGML's layered graph is the feature no other standard has and few consumers use.

The last row is IndoorGML's real advantage. A step-free graph and a default graph can be separate layers over the same cells — which is exactly the structure an accessibility-aware router wants, and which IMDF leaves to the consumer.

IMDF was designed to get indoor maps into a consumer mapping application. That purpose shows everywhere in it: GeoJSON encoding because every client already parses it, WGS84 because that is what a world map uses, closed category enumerations because a renderer needs to know what to draw, and no explicit graph because Apple’s router builds its own.

IndoorGML was designed to model indoor space for navigation research and analysis. Its central idea is the separation of primal space — cells and their boundaries — from dual space, a graph of State nodes and Transition edges. That separation is genuinely better modelling, and it buys a capability nothing else has: multiple graph layers over the same cells, one per travel mode or accessibility profile, related to each other through the MultiLayeredGraph construct.

If you were designing an internal model from scratch, IndoorGML’s structure is the one to borrow. If you are choosing what to publish, the question is entirely who reads it.

Choosing by Consumer

Choosing an interchange standard by consumer One decision with four outcomes. Consumer applications, including Apple Maps and most map SDKs, want IMDF. Transit operators and research partners want IndoorGML because they want the explicit navigation graph. A tenant's own GIS is best served by IMDF, since GeoJSON is universally readable. Where more than one consumer exists, both are emitted at the publishing boundary from one internal model with two converters. Consumers decide, and two consumers cost one extra converter Which standard should this estate publish? answer by who is reading it, not by which is better designed consumer apps IMDF Apple Maps and most SDKs transit / research IndoorGML explicit navigation graph is wanted tenant GIS IMDF GeoJSON reads everywhere more than one Both, at the edge one internal model, two converters

The fourth branch is cheaper than it looks. Both converters read the same internal envelope, so the second one costs a mapping table and a serialiser rather than a parallel data model.

Published archive size for the same venue in each standard Two curves of published size against the number of levels in a venue. The IMDF archive grows linearly from 0.9 megabytes for a single level to 26 megabytes at 32 levels. The IndoorGML document grows about 3.7 times faster over the same range, from 3.1 megabytes to 98, because GML's XML encoding is considerably more verbose than GeoJSON and because the explicit graph layer adds features the IMDF archive does not carry. Same venue, 3.7x the bytes 0 25 50 75 100 8 16 24 32 levels in the venue published size (MB) IMDF archive (MB) IndoorGML document (MB)

Verbosity is the price of explicitness. Some of the gap is XML overhead and some is real content — the graph layer IMDF makes the consumer rebuild.

Two practical considerations sit alongside the consumer question.

Size. GML is XML and IMDF is GeoJSON, and the ratio is roughly 3.7× for the same venue. For a 32-level tower that is 98 MB against 26 MB, which matters for submission workflows, for storage, and for any consumer fetching it over a network.

Tooling. IMDF has a published validator, a reference implementation and a submission process with feedback. IndoorGML has a schema and considerably less around it, which means more of the validation burden falls on the emitter.

Minimal Working Example

The same three rooms, emitted both ways, is the clearest illustration of the difference.

import json
import logging
import uuid

logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s")
logger = logging.getLogger(__name__)

NS = uuid.UUID("6ba7b810-9dad-11d1-80b4-00c04fd430c8")


def as_imdf_unit(feature: dict, level_id: str) -> dict:
    """One room as an IMDF unit Feature. The graph is left for the consumer to derive."""
    props = feature["properties"]
    try:
        category = {"room": "room", "corridor": "walkway"}[props["space_class"]]
    except KeyError:
        raise ValueError(f"no IMDF category for {props['space_class']!r}")
    return {
        "id": str(uuid.uuid5(NS, f"unit:{props['feature_id']}")),
        "type": "Feature",
        "feature_type": "unit",
        "geometry": feature["geometry"],
        "properties": {"category": category, "level_id": level_id,
                       "name": {"en": props.get("name")} if props.get("name") else None,
                       "display_point": None},
    }


def as_indoorgml_cell(feature: dict) -> dict:
    """One room as an IndoorGML CellSpace, plus the dual State it corresponds to."""
    props = feature["properties"]
    cell_id = f"c-{props['feature_id']}"
    return {
        "CellSpace": {"gml:id": cell_id, "geometry": feature["geometry"]},
        # The dual node exists explicitly and references its cell — this is the part
        # IMDF has no equivalent for.
        "State": {"gml:id": f"s-{props['feature_id']}", "duality": cell_id},
    }

The asymmetry in those two functions is the whole comparison. The IMDF function emits geometry and a category; the IndoorGML function emits geometry, a category and the node in the navigation graph that corresponds to it. A consumer of the first has to reconstruct the graph — the work routing graph construction describes — while a consumer of the second is handed it.

Comparison Reference

Dimension IMDF IndoorGML
Encoding GeoJSON in a zip archive GML 3.2 (XML)
Coordinates WGS84 only any CRS, declared
Room unit Feature CellSpace
Doorway opening LineString CellSpaceBoundary
Graph derived by consumer explicit State / Transition
Multi-modal graphs not expressible MultiLayeredGraph
Levels level with signed ordinal layers with Cell membership
Validator published, maintained schema only
Consumer reach Apple Maps, many SDKs transit, research
Size (8 levels) ~6.6 MB ~24.4 MB
Effort to emit moderate high

The MultiLayeredGraph row is the one worth understanding even if you never emit IndoorGML, because it names a modelling idea most indoor stacks eventually rediscover: the same physical cells can carry more than one navigation graph, and the relationship between those graphs is itself data. That is exactly what accessible routing profiles implements as weight vectors over one topology — a pragmatic version of the same insight.

Common Errors & Fixes

IMDF submission rejected for a category value. The internal space_class was passed through instead of mapped. IMDF’s enumerations are closed; every internal value needs an explicit mapping and an unmapped one must raise at build time.

IndoorGML consumers report a disconnected graph. Transition edges were emitted without their connects references resolving to State ids, usually because the dual nodes were generated after the transitions. Emit states first, then transitions referencing them, and validate that every transition’s endpoints exist.

Coordinates are right in IMDF and wrong in IndoorGML. IndoorGML permits any CRS and requires it to be declared; omitting srsName leaves the consumer guessing, and the usual guess is WGS84 applied to local metres. Declare the CRS explicitly on every geometry container.

Both archives disagree about level ordinals. IMDF ordinals are signed with 0 at the ground floor, which matches the convention level mapping establishes. IndoorGML layers have no inherent ordering, so the ordinal has to be carried as an attribute — and if it is derived independently in the two converters, they will eventually differ. Derive it once, internally, and pass it to both.

Integration Point

Both converters read the same internal envelope and run at the publishing boundary described in Indoor Map Data Standards. Neither is a storage format, and neither should be read back into the pipeline.

The IndoorGML converter has one additional input the IMDF converter does not need: the routing graph itself, from routing graph construction. That is the point of the standard — it publishes the graph rather than making the consumer rebuild it — and it means the IndoorGML publication is downstream of graph construction where the IMDF publication is not.

Frequently Asked Questions

Can one archive satisfy both kinds of consumer?

No, but one internal model can produce both, which is the arrangement that actually works. The formats are incompatible at the encoding level — a zip of GeoJSON files versus a GML document — so there is no single artefact that satisfies an Apple Maps submission and a transit operator’s IndoorGML importer. What is shared is everything upstream: the same envelope, the same reprojection, the same level ordinals and the same stable identifiers feed both converters, so the second target costs a mapping table and a serialiser rather than a parallel pipeline.

Is IndoorGML worth emitting for internal use?

Not as a storage format, and occasionally as an export for analysis. Its verbosity and XML encoding make it a poor working format compared with the internal envelope, and nothing in the pipeline reads GML. Where it earns its keep is when a specialist tool — an evacuation simulator, a pedestrian flow model, an academic collaborator’s software — consumes it natively, because handing over a document that already contains the navigation graph avoids a round of reconstruction and the disagreements that come with it.

Which standard handles accessibility better?

IndoorGML, structurally, and IMDF, practically. IndoorGML can express a step-free graph as a distinct layer over the same cells, which is the cleanest possible model of the problem. IMDF instead carries accessibility as attributes on units and openings, leaving the consumer to apply them — which is less elegant and is what the consumers that exist actually implement. If you publish IMDF, the important thing is to populate those accessibility attributes fully rather than leaving them null, because a consumer cannot infer step-free routing from geometry alone.

This page is a companion to Indoor Map Data Standards, part of the Indoor Mapping Architecture & Standards section.