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:

NameTypeDescription
job_idstrIdentifier of the job, as recorded by the run.
active_idssequence of str or NoneIds of the buildings that belong to this job. None means every building.
tile_origintuple of float or None(lon, lat) of the tile the job covered. tile_origin_of computes it from a saved AreaSchedule. None for an untiled job.

FacadeLayoutFrame dataclass

One coplanar surface region, with its cells in canonical order.

Attributes:

NameTypeDescription
keystrSurface id. It matches the id of the same surface in a result's SurfaceColumns.
originndarray(x, y, z) of the grid origin.
u_axisndarrayDirection of the grid's u axis.
v_axisndarrayDirection of the grid's v axis.
grid_sizefloatCell size of the grid.
nuintNumber of cells along the u axis.
nvintNumber of cells along the v axis.
cellslist of int or NoneOne entry per grid cell, indexed cells[i * nu + j]: the index of the cell's sensor in the job's flat sensor arrays, or None where the grid cell lies outside the surface.

FacadeLayoutJob dataclass

One job's rebuilt layout.

Attributes:

NameTypeDescription
job_idstrIdentifier of the job.
has_terrainboolWhether the job was built with terrain.
sensor_layout_hashstrHash of the sensor layout. It equals the server's hash for the same inputs and parameters.
entity_hasheslist of strContent hashes of the entities the layout was built from.
warningslist of strNon-fatal notices raised while building the layout.
culled_below_terrainintNumber of sensor cells dropped for lying below the terrain. 0 without terrain.
pointsndarrayFlat sensor positions [x, y, z, ...], float64.
normalsndarrayFlat sensor normals [x, y, z, ...], float64.
cell_areandarray or NonePer-sensor cell coverage fraction, float32. None when partial cells are disabled.
cell_trisndarray or NoneTriangle coordinates of all cells, concatenated in sensor order, float32. None when not built.
cell_tris_offsetsndarray or NoneOffsets into cell_tris that split it per sensor, with one terminal offset, uint32. None when cell_tris is.
frameslist of FacadeLayoutFrameThe 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:

NameTypeDescription
jobslist of FacadeLayoutJobThe rebuilt layout of each job.

layout_key property

Python
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

Python
surfgrid_version: int

Surfgrid version the layout was built at.

core_version property

Python
core_version: str

Version of the bundled geometry core that built the layout.

synth_params property

Python
synth_params: Dict[str, Any]

Synthesis parameters the layout was built with.

to_bytes

Python
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:

TypeDescription
bytesThe exported layout.

from_bytes classmethod

Python
from_bytes(
data: bytes, schedule: Optional["AreaSchedule"] = None
) -> "FacadeLayout"

Load a layout exported by FacadeLayout.to_bytes.

Parameters:

NameTypeDescriptionDefault
databytesThe bytes returned by to_bytes.required
scheduleAreaScheduleThe saved tiled run's AreaSchedule, when the exported layout came from synthesize_facade_layout called with schedule=. Each job's frames are exported in that job's own tile frame, so without the schedule a reloaded tiled layout stays in tile frame and attach_values refuses every tiled surface. With it, the frames are moved into the site frame. Omit for an untiled layout.None

Returns:

TypeDescription
FacadeLayoutThe reloaded layout.

Raises:

TypeDescription
ValueErrorIf schedule has no usable polygon origin or does not contain a job of the layout.

tile_origin_of

Python
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:

NameTypeDescriptionDefault
scheduleAreaScheduleThe saved schedule of a tiled run.required
job_idstrA job id from schedule.jobs.required

Returns:

TypeDescription
tuple of float(lon, lat) of the tile's south-west corner.

Raises:

TypeDescription
ValueErrorIf job_id is not one of the values of schedule.jobs, or if schedule.polygon has no usable origin.

attach_values

Python
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:

  1. columns has that surface;
  2. its origin, axes and grid dimensions agree with the layout's, within float rounding;
  3. its cell layout -- which grid cells actually have a sensor, in canonical row-major order -- matches exactly. columns.has_value is False for a grid cell with no sensor, one entry per cell in the order frame.cells uses, 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:

NameTypeDescriptionDefault
layoutFacadeLayoutThe rebuilt or reloaded layout.required
columnsSurfaceColumnsThe surface columns of the result to verify against.required
expected_layout_keystrThe layout_key stored alongside the result when it first ran.required

Returns:

TypeDescription
SurfaceColumnscolumns, unchanged. This function only verifies.

Raises:

TypeDescription
ValueErrorIf the layout key differs, if frame keys are not unique across the layout, or if a surface of the layout is missing from columns or differs in geometry or cell layout.

synthesize_facade_layout

Python
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:

NameTypeDescriptionDefault
buildingsmappingThe buildings of the run, keyed by building id, as submitted.required
analysis_surfacesstrWhich surfaces to grid: "facades", "roofs" or "all".required
surface_grid_sizefloatGrid cell size, as used by the run.required
groundmappingTerrain geometry of the run, if it had any.None
terrain_alignmentstrTerrain alignment of the run ("to-ground" or "as-is"), if it had one.None
surface_offsetfloatOffset 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_cellsboolIf 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_coveragefloatMinimum in-surface area fraction for a boundary cell to be kept. Used when partial_cells is true.0.05
mesh_cleaningstr"auto" cleans each building before gridding; "off" uses the meshes as drawn."auto"
max_sensors_per_jobintPer-building sensor cap.262144
emit_cell_trisboolWhether the layout holds the clipped triangles of every cell (FacadeLayoutJob.cell_tris). Leave it off for render buffers (columns.render_buffers()) and for the normal case: the outline gives the exact border and no per-cell geometry is needed. Turn it on only to draw the old per-cell mesh or to export the cell geometry. It makes the layout about 3 times larger. The sensors and the hashes do not change.False
surfgrid_versionintSurfgrid version to rebuild at. Omit to use the version of the bundled geometry core; the version used is always available as FacadeLayout.surfgrid_version. A version that cannot be built is refused, never mapped to the nearest one.None
site_origintuple of float(lon, lat) frame in which the coordinates of buildings and ground are expressed. Pass it together with a job's tile_origin to reproduce a tiled job exactly; omit both for an untiled run.None
jobssequence of FacadeLayoutJobSpecReproduces a saved run's job split. Omit for one job over every building.None
scheduleAreaScheduleThe AreaSchedule returned by a tiled run_area call. When given, site_origin and jobs are derived from it: the polygon's own origin, and one FacadeLayoutJobSpec per scheduled job with its tile_origin computed the way run_area computed it. Cannot be combined with site_origin or jobs.None

Returns:

TypeDescription
FacadeLayoutThe rebuilt layout.

Raises:

TypeDescription
ValueErrorIf schedule is combined with site_origin or jobs, or if the inputs are refused (for example an unbuildable surfgrid_version).