Facade layout
Rebuild a facade or roof sensor layout offline from the original inputs.
synthesize_facade_layout gives the same frames and canonical cell order
that the merge of a live area run attaches. With emit_cell_tris=True it
also gives the per-cell triangles. surfgrid_version is pinned by the caller. It is
pure: no HTTP and no billing.
FacadeLayout.to_bytes and FacadeLayout.from_bytes save and reload a
layout without the geometry, for the case where the model was edited after the
run. The triangles of a full (unclipped) cell are not stored, because they
follow from its frame, so the export is far smaller than the triangle geometry
an emit_cell_tris=True merge carries.
Rebuilding and exporting are separate calls, so a caller that only wants to
show a recomputed layout never pays for compression: synthesize_facade_layout
only rebuilds, and FacadeLayout.to_bytes runs the compact export only when
it is called. Bulk numeric data stays in numpy buffers throughout.
One job covering every building in buildings is the common, untiled case. A
caller that tiled its own run either names each job's building ids and
tile_origin by hand in jobs, or passes that run's saved
AreaSchedule as schedule= and lets the SDK derive both from it.
FacadeLayoutJobSpec
dataclass
One job to synthesize.
tile_origin reproduces one tile of a tiled run. Pass it together with
synthesize_facade_layout's site_origin; omit both for an untiled run.
Warnings
A tiled submission projects each tile's geometry around that tile's own
reference point, so omitting tile_origin for a tiled job re-synthesizes in
the site frame instead and drifts every frame by the tile row's
cos(latitude) term.
Attributes:
| Name | Type | Description |
|---|---|---|
job_id |
str
|
Identifier of the job, as recorded by the run. |
active_ids |
sequence of str or None
|
Ids of the buildings that belong to this job. |
tile_origin |
tuple of float or None
|
|
FacadeLayoutFrame
dataclass
One coplanar surface region, with its cells in canonical order.
Attributes:
| Name | Type | Description |
|---|---|---|
key |
str
|
Surface id. It matches the id of the same surface in a result's
|
origin |
ndarray
|
|
u_axis |
ndarray
|
Direction of the grid's u axis. |
v_axis |
ndarray
|
Direction of the grid's v axis. |
grid_size |
float
|
Cell size of the grid. |
nu |
int
|
Number of cells along the u axis. |
nv |
int
|
Number of cells along the v axis. |
cells |
list of int or None
|
One entry per grid cell, indexed |
FacadeLayoutJob
dataclass
One job's rebuilt layout.
Attributes:
| Name | Type | Description |
|---|---|---|
job_id |
str
|
Identifier of the job. |
has_terrain |
bool
|
Whether the job was built with terrain. |
sensor_layout_hash |
str
|
Hash of the sensor layout. It equals the server's hash for the same inputs and parameters. |
entity_hashes |
list of str
|
Content hashes of the entities the layout was built from. |
warnings |
list of str
|
Non-fatal notices raised while building the layout. |
culled_below_terrain |
int
|
Number of sensor cells dropped for lying below the terrain. |
points |
ndarray
|
Flat sensor positions |
normals |
ndarray
|
Flat sensor normals |
cell_area |
ndarray or None
|
Per-sensor cell coverage fraction, |
cell_tris |
ndarray or None
|
Triangle coordinates of all cells, concatenated in sensor order,
|
cell_tris_offsets |
ndarray or None
|
Offsets into |
frames |
list of FacadeLayoutFrame
|
The surface regions of the job. |
FacadeLayout
A rebuilt or reloaded facade layout.
Create one with synthesize_facade_layout or FacadeLayout.from_bytes;
do not call the constructor directly.
Attributes:
| Name | Type | Description |
|---|---|---|
jobs |
list of FacadeLayoutJob
|
The rebuilt layout of each job. |
layout_key
property
layout_key: str
Key that identifies this layout.
It covers the geometry, the synthesis parameters, the surfgrid version and the core version, so two layouts with the same key are the same layout. Store it with each result you may want to show again later.
surfgrid_version
property
surfgrid_version: int
Surfgrid version the layout was built at.
core_version
property
core_version: str
Version of the bundled geometry core that built the layout.
synth_params
property
synth_params: Dict[str, Any]
Synthesis parameters the layout was built with.
to_bytes
to_bytes() -> bytes
Export this layout in a compact form.
The export leaves out the triangles of full cells and is
zlib-compressed. Reload it with FacadeLayout.from_bytes. It is
computed once and cached.
Returns:
| Type | Description |
|---|---|
bytes
|
The exported layout. |
from_bytes
classmethod
from_bytes(
data: bytes, schedule: Optional["AreaSchedule"] = None
) -> "FacadeLayout"
Load a layout exported by FacadeLayout.to_bytes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
bytes
|
The bytes returned by |
required |
schedule
|
AreaSchedule
|
The saved tiled run's |
None
|
Returns:
| Type | Description |
|---|---|
FacadeLayout
|
The reloaded layout. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
tile_origin_of
tile_origin_of(schedule: 'AreaSchedule', job_id: str) -> Tuple[float, float]
Return the (lon, lat) of a job's tile south-west corner.
This is the same computation run_area used to anchor that tile when it
submitted it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
schedule
|
AreaSchedule
|
The saved schedule of a tiled run. |
required |
job_id
|
str
|
A job id from |
required |
Returns:
| Type | Description |
|---|---|
tuple of float
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
attach_values
attach_values(
layout: "FacadeLayout", columns: Any, *, expected_layout_key: str
) -> Any
Verify a layout against a live or reloaded SurfaceColumns.
The check refuses a mismatch. It first compares layout.layout_key with
expected_layout_key, which covers the geometry, the synthesis
parameters, the surfgrid version and the core version, so a rebuild whose
geometry drifted gets a different key. This catches even a change too small
to move a frame's origin, axes or grid, such as a small hole inside a cell
that is still present.
Two further checks guard against a columns mismatch the key alone
cannot catch, such as the wrong surface entirely. They join by surface id,
never by row, so the row order of columns does not have to match the
job and frame order of layout. For every frame the layout names, this
checks that:
columnshas that surface;- its origin, axes and grid dimensions agree with the layout's, within float rounding;
- its cell layout -- which grid cells actually have a sensor, in canonical
row-major order -- matches exactly.
columns.has_valueis False for a grid cell with no sensor, one entry per cell in the orderframe.cellsuses, so presence is compared exactly.
Store layout_key with every result so you can pass it back here later.
Warnings
Never read expected_layout_key off layout itself: that checks nothing,
because a layout always agrees with its own key.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
layout
|
FacadeLayout
|
The rebuilt or reloaded layout. |
required |
columns
|
SurfaceColumns
|
The surface columns of the result to verify against. |
required |
expected_layout_key
|
str
|
The |
required |
Returns:
| Type | Description |
|---|---|
SurfaceColumns
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If the layout key differs, if frame keys are not unique across the
layout, or if a surface of the layout is missing from |
synthesize_facade_layout
synthesize_facade_layout(
buildings: Mapping[str, Mapping[str, Any]],
*,
analysis_surfaces: str,
surface_grid_size: float,
ground: Optional[Mapping[str, Mapping[str, Any]]] = None,
terrain_alignment: Optional[str] = None,
surface_offset: float = 0.1,
partial_cells: bool = True,
min_coverage: float = 0.05,
mesh_cleaning: str = "auto",
max_sensors_per_job: int = 262144,
emit_cell_tris: bool = False,
surfgrid_version: Optional[int] = None,
site_origin: Optional[Tuple[float, float]] = None,
jobs: Optional[Sequence[FacadeLayoutJobSpec]] = None,
schedule: Optional["AreaSchedule"] = None,
) -> FacadeLayout
Rebuild a facade or roof layout offline from the original inputs.
This only rebuilds the layout; call FacadeLayout.to_bytes on the result
to export it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
buildings
|
mapping
|
The buildings of the run, keyed by building id, as submitted. |
required |
analysis_surfaces
|
str
|
Which surfaces to grid: |
required |
surface_grid_size
|
float
|
Grid cell size, as used by the run. |
required |
ground
|
mapping
|
Terrain geometry of the run, if it had any. |
None
|
terrain_alignment
|
str
|
Terrain alignment of the run ( |
None
|
surface_offset
|
float
|
Offset of the sensors from the surface, in metres. This is the default a live run uses when the field is absent; set it only to rebuild a layout that used a different, explicit value. |
0.1
|
partial_cells
|
bool
|
If true, boundary cells are clipped to the surface and kept when enough of them lies inside. If false, a cell is kept when its centre lies inside the surface. |
True
|
min_coverage
|
float
|
Minimum in-surface area fraction for a boundary cell to be kept. Used
when |
0.05
|
mesh_cleaning
|
str
|
|
"auto"
|
max_sensors_per_job
|
int
|
Per-building sensor cap. |
262144
|
emit_cell_tris
|
bool
|
Whether the layout holds the clipped triangles of every cell
( |
False
|
surfgrid_version
|
int
|
Surfgrid version to rebuild at. Omit to use the version of the
bundled geometry core; the version used is always available as
|
None
|
site_origin
|
tuple of float
|
|
None
|
jobs
|
sequence of FacadeLayoutJobSpec
|
Reproduces a saved run's job split. Omit for one job over every building. |
None
|
schedule
|
AreaSchedule
|
The |
None
|
Returns:
| Type | Description |
|---|---|
FacadeLayout
|
The rebuilt layout. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |