Skip to main content

Paths and area aggregation

/L5/A/ldk is not a name but an address. And the hierarchy cut by / is itself the unit of aggregation. A path plays two roles at once.

Those two roles dissolve a problem that has been awkward in architectural data for years — where to cut granularity. At rooms? At dwelling units? At storeys? koyu's answer is "at all of them; the path makes them hold simultaneously".

As an address​

A path is human-readable. The outside world can point at a space without a table of UUIDs.

space /L5/A/ldk ldk X1..X3 Y1..Y2 name:リビングダイニング

Sensor readings, a booking system and a BEMS can all use the string /L5/A/ldk as a foreign key. The path is the meaning.

The leading segment of a path becomes a level only when a level of that name is declared. Writing /L1/ does not conjure a level into existence.

grid X 0 3600
grid Y 0 4000
space /L1/x room X1..X2 Y1..Y2
✖ p3.muro:line 3: /L1/x has a region, but its level cannot be determined (give it at the head of the path or with level:)

An error, not a warning; the exit code is 1. Without a level no form can be made, so this counts as missing sufficiency.

The head of a path can express only one level, so groupings that cross storeys (maisonettes and the like) are stated with the level: attribute.

As an aggregation hierarchy​

A space with a region may not have child spaces with regions, because parent and child would overlap.

grid X 0 3600 7200
grid Y 0 4000
level L1 0 h:2400 slab:150
space /L1/home unit X1..X3 Y1..Y2
space /L1/home/a room X1..X2 Y1..Y2
space /L1/home/b room X2..X3 Y1..Y2
space /out outside:1
boundary /L1/home /out
boundary /L1/home/a /out
boundary /L1/home/b /out
✖ p1.muro:line 4: Space regions overlap: /L1/home and /L1/home/a
✖ p1.muro:line 4: Space regions overlap: /L1/home and /L1/home/b

To split a dwelling into rooms, make the parent a zone, not a space. A zone has no geometry; it is a counted aggregation that gathers whatever sits under its path prefix.

grid X 0 3600 7200
grid Y 0 4000
level L1 0 h:2400 slab:150
zone /L1/home name:住戸
space /L1/home/a room X1..X2 Y1..Y2
space /L1/home/b room X2..X3 Y1..Y2
space /out outside:1
boundary /L1/home/a /out
boundary /L1/home/b /out
L1
  /L1/home/a	a	room	14.40 m2
  /L1/home/b	b	room	14.40 m2
  Subtotal 28.80 m2
Total 28.80 m2 (indoor floor area)
By zone (counted aggregation):
  /L1/home	住戸	28.80 m2

The individual rooms come out, and the dwelling total survives. You can split into a layout without losing the language of the dwelling — that is what the double role buys.

From which one design guideline follows: put the unit you want to aggregate by nearer the head of the path.

The bundled examples use two idioms.

IdiomExamplesWhat you want to aggregate by
/L1/room — level firsttwo-rooms, office, mansion, tower, complexarea per storey, checks per storey
/home/room + level:L1 — dwelling firsthousearea per dwelling, maisonettes

Neither is better. It is a difference in what you want to group by. When to reach for zone rather than space is covered in zone.

Paths change, which is why uid exists​

Rename or restructure and the path changes, and any sensor or register that used it as a foreign key loses its join.

When a reference must outlive the path, use uid:. It is an opaque token, unique across the model, and not derived from the path.

space /L5/A/ldk ldk X1..X3 Y1..Y2 uid:u-7f3k9m2qx4b8dhtv

Not derived from the path is the crux. Derive it and a rename changes the token, and the whole point of a uid — pointing at the same thing across a rename — evaporates. When a machine makes one, it is random.

The division of labour is clean.

PurposeWhat to use
references inside the repository (boundary, doors, zone totals)the path
aggregation hierarchythe path
long-lived identity across renames (sensors, survey, registers)uid

uid may be written on space and zone and nothing else. It cannot go on a relation because a relation's identity is derived from its two ends (Walls as boundaries). The details are in Identity.

It also works as a namespace​

When composing several files, no per-layer namespace prefix is needed — the path hierarchy is already a namespace. Let L5.muro write /L5/... and core.muro write /B2..L19/core/... and nothing collides.

This is the result of borrowing from USD only the mechanism of a path namespace (Splitting and layering files).

Next​