Skip to content

Floorplan YAML Construction

YAML serialisation of indoor building geometry.

This module provides utilities for converting labelled room polygons into a structured, human-readable YAML representation of a building floorplan. It operates on GeoDataFrame-derived polygon geometries and produces a schema focused on architectural topology rather than geospatial metadata.

Responsibilities of this module include: - Converting polygon exteriors into ordered wall segments. - Mapping labelled polygons and canonical door segments to room definitions. - Assembling building- and floor-level metadata into a serialisable form. - Writing the resulting structure to disk as YAML.

The module assumes: - One polygon corresponds to one room. - Polygon geometries are valid, closed, and planar. - Coordinates exist in a local Cartesian space with no CRS. - Room labels have already been attached upstream.

DXF parsing, spatial joins, and geometry construction are explicitly out of scope and must be handled before using this module.

FlowList

Bases: list

List subtype used to force YAML flow-style serialisation.

Source code in src/floorplan_extractor/yaml_construction.py
37
38
class FlowList(list):
    """List subtype used to force YAML flow-style serialisation."""

build_yaml_structure(*, building_name, building_address, floor_level, rooms)

Construct a YAML-ready building data structure from room definitions.

This function assembles building metadata and a collection of room definitions into a nested dictionary matching the expected output schema. The resulting structure is suitable for serialisation using yaml.safe_dump without further transformation.

The function does not perform validation of room geometry or schema completeness. It assumes that each room dictionary contains, at a minimum, the keys: - "name" - "walls" - "doors"

Parameters:

Name Type Description Default
building_name str

Name of the building.

required
building_address str

Address of the building.

required
floor_level int

Floor identifier to associate with the provided rooms.

required
rooms list[dict]

List of room definitions produced by polygons_to_rooms.

required

Returns:

Type Description
dict

Nested dictionary structured as:

{ "building": { "name": str, "address": str, "floors": [ { "level": int, "rooms": list[dict], } ], } }

Source code in src/floorplan_extractor/yaml_construction.py
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
def build_yaml_structure(
    *,
    building_name: str,
    building_address: str,
    floor_level: int,
    rooms: list[dict],
) -> dict:
    """
    Construct a YAML-ready building data structure from room definitions.

    This function assembles building metadata and a collection of room
    definitions into a nested dictionary matching the expected output
    schema. The resulting structure is suitable for serialisation using
    `yaml.safe_dump` without further transformation.

    The function does not perform validation of room geometry or schema
    completeness. It assumes that each room dictionary contains, at a
    minimum, the keys:
        - "name"
        - "walls"
        - "doors"

    Parameters
    ----------
    building_name : str
        Name of the building.
    building_address : str
        Address of the building.
    floor_level : int
        Floor identifier to associate with the provided rooms.
    rooms : list[dict]
        List of room definitions produced by `polygons_to_rooms`.

    Returns
    -------
    dict
        Nested dictionary structured as:

        {
            "building": {
                "name": str,
                "address": str,
                "floors": [
                    {
                        "level": int,
                        "rooms": list[dict],
                    }
                ],
            }
        }

    """
    return {
        "building": {
            "name": building_name,
            "address": building_address,
            "floors": [
                {
                    "level": floor_level,
                    "rooms": rooms,
                }
            ],
        }
    }

polygons_to_rooms(gdf, room_name_column, door_column=None, opening_column=None, opening_tolerance=1e-06)

Convert labelled polygons into room definitions.

Parameters:

Name Type Description Default
gdf GeoDataFrame

GeoDataFrame containing polygon geometries.

required
room_name_column str

Column containing room names.

required
door_column str or None

Optional column containing lists of canonical door segments represented as [x1, y1, x2, y2]. These spans are emitted as doors and removed from the physical wall list.

None
opening_column str or None

Optional column containing lists of non-operable opening segments. When provided, those segments are emitted as openings and removed from the room's physical wall list.

None
opening_tolerance float

Maximum boundary distance accepted when removing an opening from the physical wall list.

1e-6

Returns:

Type Description
list[dict]

Room definitions containing name, walls, and doors values suitable for YAML serialisation.

Source code in src/floorplan_extractor/yaml_construction.py
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
def polygons_to_rooms(
    gdf: gpd.GeoDataFrame,
    room_name_column: str,
    door_column: str | None = None,
    opening_column: str | None = None,
    opening_tolerance: float = 1.0e-6,
) -> list[dict]:
    """
    Convert labelled polygons into room definitions.

    Parameters
    ----------
    gdf : geopandas.GeoDataFrame
        GeoDataFrame containing polygon geometries.
    room_name_column : str
        Column containing room names.
    door_column : str or None
        Optional column containing lists of canonical door segments represented
        as ``[x1, y1, x2, y2]``. These spans are emitted as doors and removed
        from the physical wall list.
    opening_column : str or None
        Optional column containing lists of non-operable opening segments. When
        provided, those segments are emitted as ``openings`` and removed from
        the room's physical wall list.
    opening_tolerance : float, default 1e-6
        Maximum boundary distance accepted when removing an opening from the
        physical wall list.

    Returns
    -------
    list[dict]
        Room definitions containing ``name``, ``walls``, and ``doors`` values
        suitable for YAML serialisation.

    """
    rooms = []

    for _, row in gdf.iterrows():
        door_values = []
        if door_column and door_column in row and row[door_column]:
            door_values = [FlowList(d) for d in row[door_column]]

        opening_values = []
        if opening_column and opening_column in row and row[opening_column]:
            opening_values = [FlowList(opening) for opening in row[opening_column]]
        opening_lines = [
            LineString([(opening[0], opening[1]), (opening[2], opening[3])])
            for opening in opening_values
        ]
        door_lines = [
            LineString([(door[0], door[1]), (door[2], door[3])]) for door in door_values
        ]

        d = {
            "name": row[room_name_column],
            "walls": _polygon_to_walls(
                row.geometry,
                [*opening_lines, *door_lines],
                opening_tolerance=opening_tolerance,
            ),
            "doors": door_values,
        }
        if opening_column is not None:
            d["openings"] = opening_values
        rooms.append(d)

    return rooms

register_yaml_representers()

Register custom YAML representers used by the building serialisation module.

This function registers a representer for the FlowList type with PyYAML's SafeDumper, ensuring that wall segment coordinate lists are emitted in flow style (e.g. [x1, y1, x2, y2]) when using yaml.safe_dump.

The registration mutates PyYAML's global dumper state and therefore must be called exactly once, before any YAML serialisation occurs. It is intentionally explicit to avoid hidden import-time side effects.

Returns:

Type Description
None
Source code in src/floorplan_extractor/yaml_construction.py
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
def register_yaml_representers() -> None:
    """
    Register custom YAML representers used by the building serialisation module.

    This function registers a representer for the `FlowList` type with
    PyYAML's `SafeDumper`, ensuring that wall segment coordinate lists are
    emitted in flow style (e.g. `[x1, y1, x2, y2]`) when using
    `yaml.safe_dump`.

    The registration mutates PyYAML's global dumper state and therefore
    must be called exactly once, before any YAML serialisation occurs.
    It is intentionally explicit to avoid hidden import-time side effects.

    Returns
    -------
    None

    """
    yaml.SafeDumper.add_representer(FlowList, _represent_flow_list)