---
title: Results and legend
source: https://infrared.city/docs/sdk/1.0/api/typescript/results-and-legend/
---

# Results and legend

<a id="areagriddtype"></a>

## AreaGridDtype

Import from `@infrared-city/infrared-sdk-ts`, `@infrared-city/infrared-sdk-ts/tiling`.

> **AreaGridDtype** = `"f16"` \| `"f32"` \| `"i16"` \| `"f64"`

The type of `AreaResult.mergedGrid`: the type the server stored.

- `"f16"`: a `Uint16Array` of raw IEEE half-precision bits (solar radiation, sky view
  factor, thermal comfort statistics, wind speed). Read it with `areaGridValuesF32`.
- `"f32"`: a `Float32Array` (direct sun hours, daylight availability, and the class codes
  of a categorical result).
- `"i16"`: an `Int16Array` of stored integers (thermal comfort index): physical value =
  stored value / `valueDivisor`, and `valid` tells which cells have a value.
- `"f64"`: a `Float64Array` (a run that mixes types).

***

<a id="areagridhasvalue"></a>

## areaGridHasValue

Import from `@infrared-city/infrared-sdk-ts`, `@infrared-city/infrared-sdk-ts/tiling`.

> **areaGridHasValue**(`result`, `cell`): `boolean`

Tells whether a cell of `mergedGrid` has a value. Use it for every `valueDtype`: NaN
(`"f16"` bits, `"f32"`, `"f64"`) or a clear `valid` bit (`"i16"`) means no value.

### Parameters

| Parameter | Type | Description |
| ------ | ------ | ------ |
| `result` | [`AreaResult`](results-and-legend.md#arearesult) | The area result. |
| `cell` | `number` | The cell index, row-major, from `0` to `mergedGrid.length - 1`. |

### Returns

`boolean`

True when the cell has a value.

***

<a id="areagridvaluesf32"></a>

## areaGridValuesF32

Import from `@infrared-city/infrared-sdk-ts`, `@infrared-city/infrared-sdk-ts/tiling`.

> **areaGridValuesF32**(`result`): `Float32Array`

Returns the physical values of `mergedGrid` as 32-bit floats, `NaN` for a cell without a
value: the type and the divisor are applied in one call. **An `"i16"` grid read without
the divisor is 10 times too large for UTCI; use this function.** The result is a new
array; `mergedGrid` does not change. Call `initializeCore()` first.

### Parameters

| Parameter | Type | Description |
| ------ | ------ | ------ |
| `result` | [`AreaResult`](results-and-legend.md#arearesult) | The area result. |

### Returns

`Float32Array`

One value per cell.

***

<a id="arearesult"></a>

## AreaResult

Import from `@infrared-city/infrared-sdk-ts`, `@infrared-city/infrared-sdk-ts/tiling`.

The merged grid of an area run, with its shape, legend range, geographic bounds and the
tiles that did not contribute.

### Properties

| Property | Modifier | Type | Description |
| ------ | ------ | ------ | ------ |
| <a id="arearesult-bounds"></a> `bounds?` | `readonly` | readonly \[`number`, `number`, `number`, `number`\] | Geographic bounds of the grid as four numbers, when known. |
| <a id="arearesult-executiontime"></a> `executionTime` | `readonly` | `number` | Time the merge took, in seconds. |
| <a id="arearesult-failedjobs"></a> `failedJobs` | `readonly` | readonly [`TileFailure`](errors.md#tilefailure)\[\] | The tiles whose job failed. |
| <a id="arearesult-failedtiles"></a> `failedTiles?` | `readonly` | readonly [`TileFailure`](errors.md#tilefailure)\[\] | Every tile that did not contribute. Empty when all tiles did. |
| <a id="arearesult-gridshape"></a> `gridShape` | `readonly` | readonly \[`number`, `number`\] | The grid size as `[rows, columns]`. |
| <a id="arearesult-legend"></a> `legend?` | `readonly` | readonly `string`\[\] | Sorted observed labels indexed by categorical `mergedGrid` ordinals. |
| <a id="arearesult-maxlegend"></a> `maxLegend?` | `readonly` | `number` | Upper end of the colour-scale range; set exactly when `minLegend` is. |
| <a id="arearesult-mergedgrid"></a> `mergedGrid` | `readonly` | `Float32Array`&lt;`ArrayBufferLike`&gt; \| `Float64Array`&lt;`ArrayBufferLike`&gt; \| `Uint16Array`&lt;`ArrayBufferLike`&gt; \| `Int16Array`&lt;`ArrayBufferLike`&gt; | The merged values as one flat row-major array, laid out as described by `gridShape`, in the type the server stored (`valueDtype`): a `Uint16Array` of half-precision bits (`"f16"`), a `Float32Array`, an `Int16Array` of stored integers (`"i16"`, thermal comfort index) or a `Float64Array` (a run that mixes types). Read physical values with `areaGridValuesF32` and test a cell with `areaGridHasValue`. **An `"i16"` UTCI grid read without `valueDivisor` is 10 times too large.** |
| <a id="arearesult-minlegend"></a> `minLegend?` | `readonly` | `number` | Lower end of the colour-scale range: the exact minimum of the finite cells of the finished grid. Absent when no cell is finite, and for a categorical result (`legend`), whose grid holds class codes rather than measurements. Other display ranges (trimmed, fixed, shared across results) are available through `legendRange` and `sharedLegendRange`. |
| <a id="arearesult-skippedjobs"></a> `skippedJobs` | `readonly` | readonly `string`\[\] | Ids of the tiles that were skipped. |
| <a id="arearesult-valid"></a> `valid?` | `readonly` | `Uint8Array`&lt;`ArrayBufferLike`&gt; | `"i16"` only: one bit per cell of `mergedGrid` (least significant bit first), set when the cell has a value. The float types use NaN for no value. |
| <a id="arearesult-valuedivisor"></a> `valueDivisor` | `readonly` | `number` | `"i16"` only: physical value = stored value / `valueDivisor`. `1` for the other types. |
| <a id="arearesult-valuedtype"></a> `valueDtype` | `readonly` | [`AreaGridDtype`](results-and-legend.md#areagriddtype) | The type of `mergedGrid`. |

***

<a id="buildingaggregate"></a>

## BuildingAggregate

Import from `@infrared-city/infrared-sdk-ts`.

Aggregate statistics of the surfaces of one building: area, mean and peak.

### Properties

| Property | Modifier | Type | Description |
| ------ | ------ | ------ | ------ |
| <a id="buildingaggregate-area"></a> `area` | `readonly` | `number` | Total area. |
| <a id="buildingaggregate-mean"></a> `mean` | `readonly` | `number` | Mean value. |
| <a id="buildingaggregate-peak"></a> `peak` | `readonly` | `number` | Peak value. |

***

<a id="clearregistrycache"></a>

## clearRegistryCache

Import from `@infrared-city/infrared-sdk-ts`.

> **clearRegistryCache**(): `void`

Drop the cached registry document, so the next read fetches it again. Useful in tests,
or when you know a new registry release is out.

### Returns

`void`

***

<a id="daylightfactorresult"></a>

## DaylightFactorResult

Import from `@infrared-city/infrared-sdk-ts`.

A daylight-factor result as columns. Sensor `i` of group `g` is element
`groups[g].start + i` of `x`, `y`, `z`, `values` and `room`.

The columns are typed-array views over one binary frame, so no object is created per
sensor. `values` holds the daylight factor as 32-bit floats; `toJson()` gives the same
result as plain JSON numbers (each value rounded to 4 significant digits).

### Constructors

<a id="daylightfactorresult-constructor"></a>

#### Constructor

> **new DaylightFactorResult**(`frame`): `DaylightFactorResult`

Validates `frame` and creates the views over it.

The views share the buffer of `frame` when it starts on an 8-byte boundary; otherwise
it is copied once.

##### Parameters

| Parameter | Type | Description |
| ------ | ------ | ------ |
| `frame` | `Uint8Array` | A binary daylight-factor result. |

##### Returns

`DaylightFactorResult`

##### Throws

When the frame exceeds the result size limit.

##### Throws

When the frame is not a valid daylight-factor result.

### Properties

<a id="daylightfactorresult-buildings"></a>

#### buildings

> `readonly` **buildings**: readonly `string`\[\]

Building names, indexed by `DaylightGroup.building`.

***

<a id="daylightfactorresult-frame"></a>

#### frame

> `readonly` **frame**: `Uint8Array`

The binary frame every view reads. Do not change it.

***

<a id="daylightfactorresult-groups"></a>

#### groups

> `readonly` **groups**: readonly [`DaylightGroup`](results-and-legend.md#daylightgroup)\[\]

The sensor groups, in frame order.

***

<a id="daylightfactorresult-kind"></a>

#### kind

> `readonly` **kind**: `"daylight-points"`

Result discriminator: always `"daylight-points"`.

***

<a id="daylightfactorresult-layout"></a>

#### layout

> `readonly` **layout**: [`DaylightLayout`](results-and-legend.md#daylightlayout)

How the sensors are grouped.

***

<a id="daylightfactorresult-maxlegend"></a>

#### maxLegend

> `readonly` **maxLegend**: `number`

Upper end of the colour legend.

***

<a id="daylightfactorresult-minlegend"></a>

#### minLegend

> `readonly` **minLegend**: `number`

Lower end of the colour legend, as for a grid or facade result.

***

<a id="daylightfactorresult-room"></a>

#### room

> `readonly` **room**: `Uint16Array`

Index into `rooms` per sensor, or `NO_ROOM` for a sensor without a room.

***

<a id="daylightfactorresult-rooms"></a>

#### rooms

> `readonly` **rooms**: readonly [`DaylightRoom`](results-and-legend.md#daylightroom)\[\]

The room rows, which `groups` and `room` index into.

***

<a id="daylightfactorresult-sensorcount"></a>

#### sensorCount

> `readonly` **sensorCount**: `number`

Total number of sensors (the length of every per-sensor column).

***

<a id="daylightfactorresult-validity"></a>

#### validity

> `readonly` **validity**: `Uint8Array`

Bit `i % 8` of byte `i / 8`: `values[i]` is present (as a grid result's `validity`).

***

<a id="daylightfactorresult-values"></a>

#### values

> `readonly` **values**: `Float32Array`

The daylight factor per sensor: the `values` column of the grid and facade results.

***

<a id="daylightfactorresult-version"></a>

#### version

> `readonly` **version**: `number`

The frame's schema version.

***

<a id="daylightfactorresult-warnings"></a>

#### warnings

> `readonly` **warnings**: readonly `string`\[\]

Warnings the analysis reported for the whole result.

***

<a id="daylightfactorresult-x"></a>

#### x

> `readonly` **x**: `Float64Array`

Sensor x coordinates.

***

<a id="daylightfactorresult-y"></a>

#### y

> `readonly` **y**: `Float64Array`

Sensor y coordinates.

***

<a id="daylightfactorresult-z"></a>

#### z

> `readonly` **z**: `Float64Array`

Sensor z coordinates.

### Methods

<a id="daylightfactorresult-tojson"></a>

#### toJson()

> **toJson**(): `unknown`

Returns the result as the parsed JSON value, the same value the `"json"` result
format gives.

##### Returns

`unknown`

The parsed JSON document.

***

<a id="daylightfactorresult-tojsonbytes"></a>

#### toJsonBytes()

> **toJsonBytes**(): `Uint8Array`

Returns the result as the analysis's JSON document, as UTF-8 bytes.

##### Returns

`Uint8Array`

The JSON bytes.

***

<a id="daylightgroup"></a>

## DaylightGroup

Import from `@infrared-city/infrared-sdk-ts`.

One group of sensors in a daylight-factor result: a floor, a building floor, a surface,
or the whole result. It matches one `output` list of the JSON result.

### Properties

| Property | Modifier | Type | Description |
| ------ | ------ | ------ | ------ |
| <a id="daylightgroup-building"></a> `building` | `readonly` | `number` \| `null` | `"buildings"` layout: index into `DaylightFactorResult.buildings`. Otherwise `null`. |
| <a id="daylightgroup-end"></a> `end` | `readonly` | `number` | End of the group's sensor range (exclusive). |
| <a id="daylightgroup-hasrooms"></a> `hasRooms` | `readonly` | `boolean` | True when the sensors carry a room and the group has room rows and mean values. |
| <a id="daylightgroup-key"></a> `key` | `readonly` | `string` | Floor key, surface id, or `""` for the `"single"` layout. |
| <a id="daylightgroup-meandf"></a> `meanDf` | `readonly` | `number` \| `null` | Mean daylight factor of the group (`mean-df` in the JSON result); `null` when absent. |
| <a id="daylightgroup-meandfall"></a> `meanDfAll` | `readonly` | `number` \| `null` | Mean daylight factor over all of the group's sensors (`mean-df-all`); `null` when absent. |
| <a id="daylightgroup-roomend"></a> `roomEnd` | `readonly` | `number` | End of the group's rows in `DaylightFactorResult.rooms` (exclusive). |
| <a id="daylightgroup-roomstart"></a> `roomStart` | `readonly` | `number` | First row of the group in `DaylightFactorResult.rooms`. |
| <a id="daylightgroup-start"></a> `start` | `readonly` | `number` | First sensor of the group: sensors `start` up to (not including) `end` of every column. |

***

<a id="daylightlayout"></a>

## DaylightLayout

Import from `@infrared-city/infrared-sdk-ts`.

> **DaylightLayout** = `"floors"` \| `"buildings"` \| `"surfaces"` \| `"single"`

How the sensors of a daylight-factor result are grouped: `"floors"`, `"buildings"`,
`"surfaces"` or `"single"` (one group for the whole result).

***

<a id="daylightresultformat"></a>

## DaylightResultFormat

Import from `@infrared-city/infrared-sdk-ts`.

> **DaylightResultFormat** = `"irbf"` \| `"json"`

The format of a daylight-factor result.

- `"irbf"`: a `DaylightFactorResult` (typed-array views over one binary frame, with
  `toJson()` on demand). Parts ask the server for binary results when it offers them;
  JSON part results from an older server are converted to the same frame.
- `"json"`: the plain JSON value.

***

<a id="daylightroom"></a>

## DaylightRoom

Import from `@infrared-city/infrared-sdk-ts`.

One room row of a daylight-factor result. A value of `null` is the JSON `null`
(not available).

### Properties

| Property | Modifier | Type | Description |
| ------ | ------ | ------ | ------ |
| <a id="daylightroom-areapctdfge2"></a> `areaPctDfGe2` | `readonly` | `number` \| `null` | Percentage of the room's area with a daylight factor of at least 2, or `null`. |
| <a id="daylightroom-floorarea"></a> `floorArea` | `readonly` | `number` \| `null` | Floor area of the room, or `null`. |
| <a id="daylightroom-id"></a> `id` | `readonly` | `string` | Room id. |
| <a id="daylightroom-irc"></a> `irc` | `readonly` | `number` \| `null` | The room's `irc` value, or `null`. |
| <a id="daylightroom-maxdf"></a> `maxDf` | `readonly` | `number` \| `null` | Highest daylight factor in the room, or `null`. |
| <a id="daylightroom-meandf"></a> `meanDf` | `readonly` | `number` \| `null` | Mean daylight factor of the room, or `null`. |
| <a id="daylightroom-mediandf"></a> `medianDf` | `readonly` | `number` \| `null` | Median daylight factor of the room, or `null`. |
| <a id="daylightroom-mindf"></a> `minDf` | `readonly` | `number` \| `null` | Lowest daylight factor in the room, or `null`. |
| <a id="daylightroom-name"></a> `name` | `readonly` | `string` | Room name. |
| <a id="daylightroom-sensors"></a> `sensors` | `readonly` | `number` | Number of sensors in the room. |
| <a id="daylightroom-windowarea"></a> `windowArea` | `readonly` | `number` \| `null` | Window area of the room, or `null`. |

***

<a id="decompressresultarchive"></a>

## decompressResultArchive

Import from `@infrared-city/infrared-sdk-ts`.

> **decompressResultArchive**(`content`, `options?`): `Uint8Array`

Expands one result archive (ZIP or GZIP) into the result document, with bounded output.
Raw JSON is not accepted: the content must be an archive.

The limits bound the downloaded compressed bytes and the expanded document. They do not
bound the object graph of the JSON parsed from it. Joining the output chunks also needs a
temporary destination buffer.

### Parameters

| Parameter | Type | Description |
| ------ | ------ | ------ |
| `content` | `Uint8Array` | The downloaded archive bytes. |
| `options` | [`DecompressResultArchiveOptions`](results-and-legend.md#decompressresultarchiveoptions) | Size limits; see `DecompressResultArchiveOptions`. |

### Returns

`Uint8Array`

The expanded document (JSON or binary result bytes).

### Throws

When a limit is not a positive safe integer.

### Throws

When the content is not a ZIP or GZIP archive, is truncated, or exceeds a
limit.

***

<a id="decompressresultarchiveoptions"></a>

## DecompressResultArchiveOptions

Import from `@infrared-city/infrared-sdk-ts`.

Size limits for expanding a downloaded result archive.

### Properties

| Property | Modifier | Type | Description |
| ------ | ------ | ------ | ------ |
| <a id="decompressresultarchiveoptions-maxcompressedbytes"></a> `maxCompressedBytes?` | `readonly` | `number` | Maximum downloaded archive size in bytes. The default is 64 MiB. |
| <a id="decompressresultarchiveoptions-maxexpandedbytes"></a> `maxExpandedBytes?` | `readonly` | `number` | Maximum expanded document size in bytes. The default is 512 MiB. |

***

<a id="decompressresultvalue"></a>

## decompressResultValue

Import from `@infrared-city/infrared-sdk-ts`.

> **decompressResultValue**(`jobs`, `content`, `options?`): `unknown`

Decodes a downloaded result archive and returns only the decoded value.

`JobsService.decompress` returns a `ParsedResult` that also says which route
the result took. This function drops that and returns the bare payload, for
code written against the older raw-value contract.

### Parameters

| Parameter | Type | Description |
| ------ | ------ | ------ |
| `jobs` | `Pick`&lt;[`JobsService`](run-an-analysis.md#jobsservice), `"decompress"`&gt; | A `JobsService`, or any object with its `decompress` method. |
| `content` | `Uint8Array` | The downloaded result archive bytes. |
| `options?` | [`ParseResultOptions`](results-and-legend.md#parseresultoptions) | Optional decoding settings. |

### Returns

`unknown`

The decoded payload.

***

<a id="default_daylight_result_format"></a>

## DEFAULT_DAYLIGHT_RESULT_FORMAT

Import from `@infrared-city/infrared-sdk-ts`.

> `const` **DEFAULT\_DAYLIGHT\_RESULT\_FORMAT**: [`DaylightResultFormat`](results-and-legend.md#daylightresultformat) = `"irbf"`

The daylight-factor result format used when none is given: `"irbf"`.

***

<a id="default_max_long_axis_px"></a>

## DEFAULT_MAX_LONG_AXIS_PX

Import from `@infrared-city/infrared-sdk-ts`.

> `const` **DEFAULT\_MAX\_LONG\_AXIS\_PX**: `960` = `960`

The default cap on the long axis of a rendered image, in pixels (960).

A grid at or below the cap renders 1:1, one pixel per cell. A larger grid is
sampled nearest-neighbour on its values, so the aspect ratio and no-data cells
are kept.

***

<a id="deserializetocamelcase"></a>

## deserializeToCamelCase

Import from `@infrared-city/infrared-sdk-ts`.

> **deserializeToCamelCase**(`value`): `unknown`

Converts the keys of an API response to camelCase, recursively, and leaves
the input unchanged.

### Parameters

| Parameter | Type | Description |
| ------ | ------ | ------ |
| `value` | `unknown` | The response object, or any value found inside one. |

### Returns

`unknown`

A converted copy; values that are not plain objects or arrays are returned as they are.

***

<a id="downloadresult"></a>

## DownloadResult

Import from `@infrared-city/infrared-sdk-ts`.

A downloaded result archive.

### Properties

| Property | Modifier | Type | Description |
| ------ | ------ | ------ | ------ |
| <a id="downloadresult-content"></a> `content` | `readonly` | `Uint8Array` | The archive bytes. |
| <a id="downloadresult-contenttype"></a> `contentType` | `readonly` | `string` | Content type reported for the download. |
| <a id="downloadresult-jobid"></a> `jobId` | `readonly` | `string` | Id of the job the results belong to. |
| <a id="downloadresult-presignedurl"></a> `presignedUrl` | `readonly` | `string` | The download URL the archive was fetched from. |

***

<a id="fetchregistryoptions"></a>

## FetchRegistryOptions

Import from `@infrared-city/infrared-sdk-ts`.

Options for `fetchVisualConfigurations`.

### Properties

| Property | Type | Description |
| ------ | ------ | ------ |
| <a id="fetchregistryoptions-fetch"></a> `fetch?` | \{(`input`, `init?`): `Promise`&lt;`Response`&gt;; (`input`, `init?`): `Promise`&lt;`Response`&gt;; \} | Injectable `fetch`, for tests and for hosts with a custom transport. |
| <a id="fetchregistryoptions-signal"></a> `signal?` | `AbortSignal` | The caller's own stop signal. Honoured together with `timeoutMs`. |
| <a id="fetchregistryoptions-timeoutms"></a> `timeoutMs?` | `number` | Total time for the answer AND its body, in ms. Defaults to 30 seconds. |
| <a id="fetchregistryoptions-ttlms"></a> `ttlMs?` | `number` | Cache lifetime in ms. Defaults to 15 minutes. |
| <a id="fetchregistryoptions-url"></a> `url?` | `string` | Defaults to [REGISTRY\_URL](results-and-legend.md#registry_url). A custom URL bypasses the cache. |

***

<a id="fetchvisualconfigurations"></a>

## fetchVisualConfigurations

Import from `@infrared-city/infrared-sdk-ts`.

> **fetchVisualConfigurations**(`options?`): `Promise`&lt;[`RegistryDocument`](results-and-legend.md#registrydocument)&gt;

Fetch the colour configurations from the public registry.

The answer is cached for `ttlMs` (15 minutes by default), and the returned object is
frozen. A custom `url` bypasses the cache, so a pinned document never replaces the
shared entry. No credentials are sent: the registry is public, and the request is a
plain `fetch`, not the SDK's authenticated connection. Redirects are refused.

### Parameters

| Parameter | Type | Description |
| ------ | ------ | ------ |
| `options` | [`FetchRegistryOptions`](results-and-legend.md#fetchregistryoptions) | Optional URL, cache lifetime, `fetch` implementation, abort signal and timeout (30 seconds by default, covering the answer and its body). |

### Returns

`Promise`&lt;[`RegistryDocument`](results-and-legend.md#registrydocument)&gt;

The colour configurations and the registry version.

### Throws

If the URL is not HTTPS on the registry host, the read
  fails, times out or is aborted, or the document is not usable.

***

<a id="flattenvisualconfigs"></a>

## flattenVisualConfigs

Import from `@infrared-city/infrared-sdk-ts`.

> **flattenVisualConfigs**(`configurations`): `Record`&lt;`string`, [`VisualConfig`](results-and-legend.md#visualconfig)&gt;

Flatten `visualConfigurations` to a flat lookup table: a simple type keeps its
process id, and a multi-variant one contributes `process:variant` for each
variant that carries `colors`.

### Parameters

| Parameter | Type | Description |
| ------ | ------ | ------ |
| `configurations` | [`VisualConfigurations`](results-and-legend.md#visualconfigurations) | The registry's `visualConfigurations` document. |

### Returns

`Record`&lt;`string`, [`VisualConfig`](results-and-legend.md#visualconfig)&gt;

Lookup key to colour configuration.

***

<a id="gridcell"></a>

## GridCell

Import from `@infrared-city/infrared-sdk-ts`.

> **GridCell** = `number` \| `string` \| `null` \| `undefined`

A cell as the API returns it: a number, a wind-comfort class label, or no data.

***

<a id="gridexpectedkind"></a>

## GridExpectedKind

Import from `@infrared-city/infrared-sdk-ts`.

> **GridExpectedKind** = `"numeric"` \| `"categorical"`

The kind of grid result a caller expects: `"numeric"` or `"categorical"`.

***

<a id="gridimagesize"></a>

## GridImageSize

Import from `@infrared-city/infrared-sdk-ts`.

The size of a rendered image, and how many pixels it spends per grid cell.

### Properties

| Property | Type | Description |
| ------ | ------ | ------ |
| <a id="gridimagesize-height"></a> `height` | `number` | Image height in pixels. |
| <a id="gridimagesize-scale"></a> `scale` | `number` | Output pixels per grid cell on the long axis: `1` for a 1:1 image. |
| <a id="gridimagesize-width"></a> `width` | `number` | Image width in pixels. |

***

<a id="gridimagesize-2"></a>

## gridImageSize

Import from `@infrared-city/infrared-sdk-ts`.

> **gridImageSize**(`png`, `gridWidth`, `gridHeight`): [`GridImageSize`](results-and-legend.md#gridimagesize)

The rendered size and the scale factor of a PNG from `renderGridPng`, for
aligning an overlay.

The dimensions are read from the PNG itself. A capped image maps output pixel
`(x, y)` to grid cell
`(floor((x + 0.5) * gridWidth / width), floor((y + 0.5) * gridHeight / height))`,
the nearest-neighbour rule.

### Parameters

| Parameter | Type | Description |
| ------ | ------ | ------ |
| `png` | `Uint8Array` | PNG bytes from `renderGridPng`. |
| `gridWidth` | `number` | Width of the rendered grid, in cells. |
| `gridHeight` | `number` | Height of the rendered grid, in cells. |

### Returns

[`GridImageSize`](results-and-legend.md#gridimagesize)

The image `width` and `height` in pixels and the pixels per cell.

### Throws

when `png` is not a PNG or a grid dimension is not positive.

***

<a id="isvertical"></a>

## isVertical

Import from `@infrared-city/infrared-sdk-ts`.

> **isVertical**(`result`, `row`): `boolean`

Tells whether a surface is a wall: its grid normal is at most 30° from horizontal.

### Parameters

| Parameter | Type | Description |
| ------ | ------ | ------ |
| `result` | [`SurfaceColumns`](results-and-legend.md#surfacecolumns) | The surface columns. |
| `row` | `number` | The surface row. |

### Returns

`boolean`

True for a wall.

***

<a id="legendmode"></a>

## LegendMode

Import from `@infrared-city/infrared-sdk-ts`.

> **LegendMode** = `"exact"` \| `"trimmed"` \| `"fixed"`

How a legend range is chosen: `"exact"` (true min/max), `"trimmed"` (2nd to
98th percentile) or `"fixed"` (a caller-supplied scale).

***

<a id="legendrange"></a>

## LegendRange

Import from `@infrared-city/infrared-sdk-ts`.

> **LegendRange** = readonly \[`number`, `number`\]

A legend range as `[min, max]`, in the units of the result.

***

<a id="legendrange-2"></a>

## legendRange

Import from `@infrared-city/infrared-sdk-ts`.

> **legendRange**(`source`, `mode?`, `options?`): [`LegendRange`](results-and-legend.md#legendrange) \| `undefined`

The legend range for one result in the given display mode.

### Parameters

| Parameter | Type | Default value | Description |
| ------ | ------ | ------ | ------ |
| `source` | [`LegendSource`](results-and-legend.md#legendsource) | `undefined` | An area result, or its grid as a typed array (a `Uint16Array` holds half-precision bits; an `Int16Array` needs the area result for its divisor and `valid`). |
| `mode` | [`LegendMode`](results-and-legend.md#legendmode) | `"exact"` | `"exact"` (default), `"trimmed"` or `"fixed"`. |
| `options` | [`LegendRangeOptions`](results-and-legend.md#legendrangeoptions) | `{}` | `fixed` is required for `"fixed"` and refused with any other mode. |

### Returns

[`LegendRange`](results-and-legend.md#legendrange) \| `undefined`

The range, or `undefined` when no cell is finite or, in a measured
  mode, when the result is categorical.

### Throws

on an unknown mode, on `"fixed"` without a valid `fixed` range,
  and on `fixed` with any other mode.

### Throws

when `source` is not an area result or a typed array.

***

<a id="legendrangeoptions"></a>

## LegendRangeOptions

Import from `@infrared-city/infrared-sdk-ts`.

Options for `legendRange` and `sharedLegendRange`.

### Properties

| Property | Modifier | Type | Description |
| ------ | ------ | ------ | ------ |
| <a id="legendrangeoptions-fixed"></a> `fixed?` | `readonly` | [`LegendRange`](results-and-legend.md#legendrange) | Required for mode `"fixed"` (finite, `min < max`); refused with any other mode. |

***

<a id="legendsource"></a>

## LegendSource

Import from `@infrared-city/infrared-sdk-ts`.

> **LegendSource** = `Pick`&lt;[`AreaResult`](results-and-legend.md#arearesult), `"mergedGrid"` \| `"legend"`&gt; & `Partial`&lt;`Pick`&lt;[`AreaResult`](results-and-legend.md#arearesult), `"valueDtype"` \| `"valueDivisor"` \| `"valid"`&gt;&gt; \| `Uint16Array` \| `Float32Array` \| `Int16Array` \| `Float64Array`

A result to range over: an area result, or its grid on its own.

***

<a id="max_registry_bytes"></a>

## MAX_REGISTRY_BYTES

Import from `@infrared-city/infrared-sdk-ts`.

> `const` **MAX\_REGISTRY\_BYTES**: `number`

The largest registry document, in bytes, that the SDK will read (8 MiB). A larger
answer is refused with a `RegistryFetchError`.

***

<a id="no_room"></a>

## NO_ROOM

Import from `@infrared-city/infrared-sdk-ts`.

> `const` **NO\_ROOM**: `65535` = `0xffff`

The `room` value of a sensor that has no room (`"room": null` in the JSON result, or a
group without rooms).

***

<a id="normalizegrid"></a>

## normalizeGrid

Import from `@infrared-city/infrared-sdk-ts`.

> **normalizeGrid**(`grid`): `object`

Convert a grid as returned by the API into a flat `Float32Array` plus its size.

`null` / `undefined` cells become no-data (`NaN`). When the last row holds any
string, the whole grid is read as wind-comfort classes: an unknown label is
no-data and a number stays a number.

### Parameters

| Parameter | Type | Description |
| ------ | ------ | ------ |
| `grid` | readonly readonly [`GridCell`](results-and-legend.md#gridcell)\[\]\[\] | Rows of cells: numbers, class labels, `null` or `undefined`. |

### Returns

`object`

The row-major values and the grid `width` and `height`.

| Name | Type |
| ------ | ------ |
| `height` | `number` |
| `values` | `Float32Array` |
| `width` | `number` |

### Throws

when the grid is empty, ragged, holds a non-numeric cell
or mixes text into a numeric result.

***

<a id="parsedresult"></a>

## ParsedResult

Import from `@infrared-city/infrared-sdk-ts`.

> **ParsedResult** = [`ParsedSurfaceResult`](results-and-legend.md#parsedsurfaceresult) \| \{ `route`: `"json"`; `value`: `unknown`; \} \| \{ `route`: `"daylight-points"`; `value`: [`DaylightFactorResult`](results-and-legend.md#daylightfactorresult); \}

A parsed result document, tagged by `route`: `"surface"` for a surface result,
`"daylight-points"` for a binary daylight-factor result, and `"json"` for any other
result (the decoded JSON value).

***

<a id="parsedsurfaceresult"></a>

## ParsedSurfaceResult

Import from `@infrared-city/infrared-sdk-ts`.

A parsed surface result.

### Properties

| Property | Modifier | Type | Description |
| ------ | ------ | ------ | ------ |
| <a id="parsedsurfaceresult-cellgeometry"></a> `cellGeometry` | `readonly` | `"complete"` \| `"omitted"` | `"complete"` when every surface has cell geometry, `"omitted"` otherwise. |
| <a id="parsedsurfaceresult-route"></a> `route` | `readonly` | `"surface"` | Result discriminator: always `"surface"`. |
| <a id="parsedsurfaceresult-value"></a> `value` | `readonly` | [`SurfaceResultValue`](results-and-legend.md#surfaceresultvalue) | The validated surface result. |

***

<a id="parseresultarchive"></a>

## parseResultArchive

Import from `@infrared-city/infrared-sdk-ts`.

> **parseResultArchive**(`content`, `options?`): [`ParsedResult`](results-and-legend.md#parsedresult)

Expands a downloaded result archive and parses the document inside it.

### Parameters

| Parameter | Type | Description |
| ------ | ------ | ------ |
| `content` | `Uint8Array` | The downloaded archive bytes. |
| `options` | [`ParseResultOptions`](results-and-legend.md#parseresultoptions) | Archive limits, expected grid kind and surface options. |

### Returns

[`ParsedResult`](results-and-legend.md#parsedresult)

The parsed result, tagged by `route`.

### Throws

When the archive cannot be expanded or the result is not valid.

***

<a id="parseresultoptions"></a>

## ParseResultOptions

Import from `@infrared-city/infrared-sdk-ts`.

Options for parsing a result.

### Properties

| Property | Modifier | Type | Description |
| ------ | ------ | ------ | ------ |
| <a id="parseresultoptions-archive"></a> `archive?` | `readonly` | [`DecompressResultArchiveOptions`](results-and-legend.md#decompressresultarchiveoptions) | Size limits for expanding the archive. |
| <a id="parseresultoptions-expectedgridkind"></a> `expectedGridKind?` | `readonly` | [`GridExpectedKind`](results-and-legend.md#gridexpectedkind) | Require a grid result of this kind; a grid of the other kind is rejected. |
| <a id="parseresultoptions-surface"></a> `surface?` | `readonly` | [`ParseSurfaceOptions`](results-and-legend.md#parsesurfaceoptions) | Options for parsing a surface result. |

***

<a id="parsesurfaceoptions"></a>

## ParseSurfaceOptions

Import from `@infrared-city/infrared-sdk-ts`.

Options for parsing a surface result.

### Properties

| Property | Modifier | Type | Description |
| ------ | ------ | ------ | ------ |
| <a id="parsesurfaceoptions-requirecellgeometry"></a> `requireCellGeometry?` | `readonly` | `boolean` | Reject a result whose cell geometry (`cell-tris`) was omitted. The parser does not synthesise geometry. |

***

<a id="parsesurfaceresult"></a>

## parseSurfaceResult

Import from `@infrared-city/infrared-sdk-ts`.

> **parseSurfaceResult**(`document`, `options?`): [`ParsedSurfaceResult`](results-and-legend.md#parsedsurfaceresult)

Parses and validates one JSON surface result.

### Parameters

| Parameter | Type | Description |
| ------ | ------ | ------ |
| `document` | `Uint8Array` | The UTF-8 JSON bytes of the result. |
| `options` | [`ParseSurfaceOptions`](results-and-legend.md#parsesurfaceoptions) | Surface parse options. |

### Returns

[`ParsedSurfaceResult`](results-and-legend.md#parsedsurfaceresult)

The validated result with `route: "surface"`.

### Throws

When the document does not have the shape of a surface result.

### Throws

When `requireCellGeometry` is set and cell geometry is omitted.

***

<a id="registry_url"></a>

## REGISTRY_URL

Import from `@infrared-city/infrared-sdk-ts`.

> `const` **REGISTRY\_URL**: `"https://registry.infrared.city/models/latest.json"` = `"https://registry.infrared.city/models/latest.json"`

The address of the public registry document that colour configurations are read from.
It is served over HTTPS and needs no credentials.

***

<a id="registrydocument"></a>

## RegistryDocument

Import from `@infrared-city/infrared-sdk-ts`.

The public colour registry: the colour configurations used to draw results, and the
registry version they came from.

### Properties

| Property | Type | Description |
| ------ | ------ | ------ |
| <a id="registrydocument-configurations"></a> `configurations` | [`VisualConfigurations`](results-and-legend.md#visualconfigurations) | The colour configurations, keyed by name. The object is frozen. |
| <a id="registrydocument-version"></a> `version` | `string` \| `null` | The registry version, or `null` when the document does not state one. |

***

<a id="registryfixedrange"></a>

## registryFixedRange

Import from `@infrared-city/infrared-sdk-ts`.

> **registryFixedRange**(`analysisType`, `options?`): `Promise`&lt;[`LegendRange`](results-and-legend.md#legendrange) \| `undefined`&gt;

The metric's full scale from the public colour registry, for use as
`legendRange(result, "fixed", { fixed })`.

Reads the same cached `visualConfigurations` document that grid rendering uses.

### Parameters

| Parameter | Type | Description |
| ------ | ------ | ------ |
| `analysisType` | `string` | The analysis whose scale to look up. |
| `options` | [`RegistryFixedRangeOptions`](results-and-legend.md#registryfixedrangeoptions) | Variant selectors (`criteria`, `subtype`), an already-fetched registry document, or fetch overrides. |

### Returns

`Promise`&lt;[`LegendRange`](results-and-legend.md#legendrange) \| `undefined`&gt;

The scale, or `undefined` when the registry has no entry for
  `analysisType`, or its `steps` are class labels or absent (true of many
  analyses today).

***

<a id="registryfixedrangeoptions"></a>

## RegistryFixedRangeOptions

Import from `@infrared-city/infrared-sdk-ts`.

Options for `registryFixedRange`.

### Properties

| Property | Modifier | Type | Description |
| ------ | ------ | ------ | ------ |
| <a id="registryfixedrangeoptions-criteria"></a> `criteria?` | `readonly` | `string` | Variant selector for analyses with several variants; wins over `subtype`. |
| <a id="registryfixedrangeoptions-registry"></a> `registry?` | `readonly` | [`FetchRegistryOptions`](results-and-legend.md#fetchregistryoptions) | Overrides for the registry fetch. |
| <a id="registryfixedrangeoptions-subtype"></a> `subtype?` | `readonly` | `string` | Variant selector, used only when `criteria` is absent. |
| <a id="registryfixedrangeoptions-visualconfigurations"></a> `visualConfigurations?` | `readonly` | [`VisualConfigurations`](results-and-legend.md#visualconfigurations) | Already-fetched `visualConfigurations`; omit it to fetch (and cache). |

***

<a id="rendergridpng"></a>

## renderGridPng

Import from `@infrared-city/infrared-sdk-ts`.

> **renderGridPng**(`grid`, `options?`): `Promise`&lt;`Uint8Array`&lt;`ArrayBufferLike`&gt;&gt;

Render a result grid to PNG bytes with the initialized Infrared core.

The image is 1:1, one pixel per grid cell, up to a 960 px long axis;
`maxLongAxisPx` moves that cap and `0` removes it. Colours come from the registry
`visualConfigurations` entry the options resolve to; without one, a default
`magma_r` ramp applies. Read the result size with `gridImageSize`.
`initializeCore()` must have completed.

The promise only awaits the registry: pass `visualConfigurations` (or omit
`analysisType`) and it resolves without any network request.

### Parameters

| Parameter | Type | Description |
| ------ | ------ | ------ |
| `grid` | readonly readonly [`GridCell`](results-and-legend.md#gridcell)\[\]\[\] | Rows of cells: numbers, class labels, `null` or `undefined`. |
| `options` | [`RenderGridPngOptions`](results-and-legend.md#rendergridpngoptions) | Analysis type, variant selectors, row order and size cap. |

### Returns

`Promise`&lt;`Uint8Array`&lt;`ArrayBufferLike`&gt;&gt;

PNG file bytes.

### Throws

when the grid is invalid or local rendering fails.

### Throws

when the colour registry has to be fetched and the
fetch fails.

***

<a id="rendergridpngoptions"></a>

## RenderGridPngOptions

Import from `@infrared-city/infrared-sdk-ts`.

Options for `renderGridPng`.

### Properties

| Property | Type | Description |
| ------ | ------ | ------ |
| <a id="rendergridpngoptions-analysistype"></a> `analysisType?` | `string` | Analysis process id, e.g. `"pedestrian-wind-comfort"`. |
| <a id="rendergridpngoptions-criteria"></a> `criteria?` | `string` | Variant selector for analyses with several variants; wins over `subtype`. |
| <a id="rendergridpngoptions-maxlongaxispx"></a> `maxLongAxisPx?` | `number` | Cap on the long axis of the image, in pixels. Defaults to `DEFAULT_MAX_LONG_AXIS_PX` (960); `0` renders every cell. Above the cap the grid is sampled nearest-neighbour on its values before it is coloured, so the aspect ratio holds and a no-data cell stays no-data; no blended value appears between two classes. |
| <a id="rendergridpngoptions-registry"></a> `registry?` | [`FetchRegistryOptions`](results-and-legend.md#fetchregistryoptions) | Overrides for the registry fetch. |
| <a id="rendergridpngoptions-reverserows"></a> `reverseRows?` | `boolean` | `true` if the caller's grid is already bottom-up. Defaults to `false`. |
| <a id="rendergridpngoptions-subtype"></a> `subtype?` | `string` | Variant selector, used only when `criteria` is absent. |
| <a id="rendergridpngoptions-visualconfigurations"></a> `visualConfigurations?` | [`VisualConfigurations`](results-and-legend.md#visualconfigurations) | Already-fetched `visualConfigurations`. Supply it to skip the network entirely; omit it and the registry is fetched (and cached) on demand. |

***

<a id="resolvevisualconfig"></a>

## resolveVisualConfig

Import from `@infrared-city/infrared-sdk-ts`.

> **resolveVisualConfig**(`configurations`, `analysisType`, `selectors?`): [`VisualConfig`](results-and-legend.md#visualconfig) \| `undefined`

The colour configuration for one analysis type, or `undefined` when the registry
has none.

The bare `analysisType` wins; only if it is absent does `criteria` (then
`subtype`) select a variant. `undefined` is not an error: the renderer falls
back to its default `magma_r` ramp.

### Parameters

| Parameter | Type | Description |
| ------ | ------ | ------ |
| `configurations` | [`VisualConfigurations`](results-and-legend.md#visualconfigurations) | The registry's `visualConfigurations` document. |
| `analysisType` | `string` | Analysis process id, e.g. `"pedestrian-wind-comfort"`. |
| `selectors` | \{ `criteria?`: `string`; `subtype?`: `string`; \} | Optional variant selectors; `criteria` wins over `subtype`. |
| `selectors.criteria?` | `string` | - |
| `selectors.subtype?` | `string` | - |

### Returns

[`VisualConfig`](results-and-legend.md#visualconfig) \| `undefined`

The matching configuration, or `undefined`.

***

<a id="sharedlegendrange"></a>

## sharedLegendRange

Import from `@infrared-city/infrared-sdk-ts`.

> **sharedLegendRange**(`sources`, `mode?`, `options?`): [`LegendRange`](results-and-legend.md#legendrange) \| `undefined`

One legend range pooled over several results.

Every finite cell of every result is pooled and `mode` is applied once, so
`"trimmed"` is the percentile of the pooled data, never a union of
per-result percentiles. Categorical results are left out in the measured
modes.

### Parameters

| Parameter | Type | Default value | Description |
| ------ | ------ | ------ | ------ |
| `sources` | readonly [`LegendSource`](results-and-legend.md#legendsource)\[\] | `undefined` | Area results, or their grids. |
| `mode` | [`LegendMode`](results-and-legend.md#legendmode) | `"exact"` | `"exact"` (default), `"trimmed"` or `"fixed"`. |
| `options` | [`LegendRangeOptions`](results-and-legend.md#legendrangeoptions) | `{}` | `fixed` is required for `"fixed"` and refused with any other mode. |

### Returns

[`LegendRange`](results-and-legend.md#legendrange) \| `undefined`

The pooled range, or `undefined` when nothing finite remains.

### Throws

when `sources` is not an array, or an entry is not an area
  result or a typed array.

***

<a id="surfaceanalysisresponse"></a>

## SurfaceAnalysisResponse

Import from `@infrared-city/infrared-sdk-ts`.

A surface analysis result: the sensor grid of each surface, per-building aggregates and
the legend range.

### Properties

| Property | Modifier | Type | Description |
| ------ | ------ | ------ | ------ |
| <a id="surfaceanalysisresponse-aggregates"></a> `aggregates` | `readonly` | `Readonly`&lt;`Record`&lt;`string`, `Readonly`&lt;`Record`&lt;`string`, [`BuildingAggregate`](results-and-legend.md#buildingaggregate)&gt;&gt;&gt;&gt; | Aggregates by group (for example `buildings`), then by id within the group. |
| <a id="surfaceanalysisresponse-maxlegend"></a> `maxLegend` | `readonly` | `number` | Upper end of the colour legend. |
| <a id="surfaceanalysisresponse-minlegend"></a> `minLegend` | `readonly` | `number` | Lower end of the colour legend. |
| <a id="surfaceanalysisresponse-sensorcount"></a> `sensorCount` | `readonly` | `number` | Total number of sensors. |
| <a id="surfaceanalysisresponse-surfaces"></a> `surfaces` | `readonly` | `Readonly`&lt;`Record`&lt;`string`, [`SurfaceSensorGrid`](results-and-legend.md#surfacesensorgrid)&gt;&gt; | The sensor grid of each surface, by surface id. |

***

<a id="surfacecolumns"></a>

## SurfaceColumns

Import from `@infrared-city/infrared-sdk-ts`.

The merged surface result of an area run, as columns.

There is one typed array per per-surface field (`S` surfaces), one per per-cell field
(`C` cells in total) and a triangle table, rather than an object per surface. Every array
owns its whole buffer, so the result can be transferred to another thread as it is, and a
renderer can upload `triangles.positions[g]` without a copy.

Surface `i` has the id `ids.slice(idOffsets[i], idOffsets[i + 1])`, its vectors are
`origin[3i..3i+3]` (and likewise the axes), and its cells are
`values[cellOffsets[i]..cellOffsets[i + 1]]`. Look a surface up by id with `surfaceIndex`.
Join two results by surface id and cell index, never by row: the row order follows the
run's entries, not the order the jobs were submitted in.

### Properties

| Property | Modifier | Type | Description |
| ------ | ------ | ------ | ------ |
| <a id="surfacecolumns-aggregates"></a> `aggregates` | `readonly` | `Readonly`&lt;`Record`&lt;`string`, `Readonly`&lt;`Record`&lt;`string`, [`BuildingAggregate`](results-and-legend.md#buildingaggregate)&gt;&gt;&gt;&gt; | Aggregates by group (for example `buildings`), then by id within the group. |
| <a id="surfacecolumns-area"></a> `area` | `readonly` | `Float64Array` | `S`: the area of each surface. |
| <a id="surfacecolumns-cellarea"></a> `cellArea?` | `readonly` | `Float32Array`&lt;`ArrayBufferLike`&gt; | `C`, present when some surface sent an array: NaN for `null` (and for other surfaces' cells). |
| <a id="surfacecolumns-cellareastate"></a> `cellAreaState` | `readonly` | `Uint8Array` | `S`: the wire's `cell-area` for the surface: 0 absent, 1 `null`, 2 an array. |
| <a id="surfacecolumns-celloffsets"></a> `cellOffsets` | `readonly` | `Uint32Array` | `S + 1`: cuts every per-cell column into surfaces. |
| <a id="surfacecolumns-celltrisfallback"></a> `cellTrisFallback?` | `readonly` | readonly `string`\[\] | Absent unless triangles were requested and at least one job fell back: the sorted reasons (for example `"hash_mismatch"`). Each fallback is also logged at `warn`. |
| <a id="surfacecolumns-extra"></a> `extra?` | `readonly` | `Readonly`&lt;`Record`&lt;`number`, `Readonly`&lt;`Record`&lt;`string`, `unknown`&gt;&gt;&gt;&gt; | The fields no column holds, by surface row. Absent when no surface sent one. |
| <a id="surfacecolumns-gridsize"></a> `gridSize` | `readonly` | `Float64Array` | `S`: the cell edge length of each surface. |
| <a id="surfacecolumns-idoffsets"></a> `idOffsets` | `readonly` | `Uint32Array` | `S + 1`: cuts `ids` (string indices). |
| <a id="surfacecolumns-ids"></a> `ids` | `readonly` | `string` | Every surface id, back to back. |
| <a id="surfacecolumns-kind"></a> `kind` | `readonly` | `"surface-columns"` | Result discriminator: always `"surface-columns"`. |
| <a id="surfacecolumns-maxlegend"></a> `maxLegend` | `readonly` | `number` | Upper end of the colour legend. |
| <a id="surfacecolumns-mean"></a> `mean` | `readonly` | `Float64Array` | `S`: the mean value of each surface. |
| <a id="surfacecolumns-minlegend"></a> `minLegend` | `readonly` | `number` | Lower end of the colour legend. |
| <a id="surfacecolumns-nu"></a> `nu` | `readonly` | `Uint32Array` | `S`: the number of cells along the u axis of each surface. |
| <a id="surfacecolumns-nv"></a> `nv` | `readonly` | `Uint32Array` | `S`: the number of cells along the v axis of each surface. |
| <a id="surfacecolumns-origin"></a> `origin` | `readonly` | `Float64Array` | `3S`: each surface grid's origin in the run's frame. |
| <a id="surfacecolumns-outline"></a> `outline?` | `readonly` | `Float32Array`&lt;`ArrayBufferLike`&gt; | `6T`, present on a facade or roof run of this client (the join rebuilds the layout from the kept capture): the outline triangles of all surfaces in row order, in cell units from the corner of cell (0,0), `s0 t0 s1 t1 s2 t2`. `surfaceRenderBuffers` reads it; a saved layout gives the outline through `options.layout` instead. |
| <a id="surfacecolumns-outlineoffsets"></a> `outlineOffsets?` | `readonly` | `Uint32Array`&lt;`ArrayBufferLike`&gt; | `S + 1`, with `outline`: surface row `i` owns outline triangles `outlineOffsets[i]..[i + 1]`. |
| <a id="surfacecolumns-peak"></a> `peak` | `readonly` | `Float64Array` | `S`: the peak value of each surface. |
| <a id="surfacecolumns-sensorcount"></a> `sensorCount` | `readonly` | `number` | Total number of sensors. |
| <a id="surfacecolumns-surfacecount"></a> `surfaceCount` | `readonly` | `number` | `S`, the number of surfaces. |
| <a id="surfacecolumns-triangles"></a> `triangles?` | `readonly` | [`SurfaceTriangles`](results-and-legend.md#surfacetriangles) | Present when triangles were requested (`emitCellTris`) or the server sent some. |
| <a id="surfacecolumns-uaxis"></a> `uAxis` | `readonly` | `Float64Array` | `3S`: the direction of each surface grid's u axis. |
| <a id="surfacecolumns-valid"></a> `valid?` | `readonly` | `Uint8Array`&lt;`ArrayBufferLike`&gt; | Present only when `valueDtype` is `"i16"`: one bit per cell, least significant bit first (cell `c` is bit `c % 8` of byte `c >> 3`), set when the cell has a value. |
| <a id="surfacecolumns-valuedivisor"></a> `valueDivisor` | `readonly` | `number` | `1` unless `valueDtype` is `"i16"`; then physical value = value / `valueDivisor`. |
| <a id="surfacecolumns-valuedtype"></a> `valueDtype` | `readonly` | [`SurfaceValueDtype`](results-and-legend.md#surfacevaluedtype) | The type of `values`. |
| <a id="surfacecolumns-values"></a> `values` | `readonly` | [`SurfaceValues`](results-and-legend.md#surfacevalues) | `C`: the value of each cell, in the type the server stored it (`valueDtype`). This keeps the result at 2 or 4 bytes per cell, not 8. Do not read a number from it directly: use `surfaceHasValue` to test a cell and `surfaceValuesF32` for the physical values. - `"f16"`: a `Uint16Array` of IEEE half-precision BITS (JavaScript has no common 16-bit float array). NaN bits mean no value. - `"f32"`, `"f64"`: NaN means no value. - `"i16"`: scaled integers; physical value = value / `valueDivisor`. An `Int16Array` has no NaN: `valid` tells which cells have a value. |
| <a id="surfacecolumns-vaxis"></a> `vAxis` | `readonly` | `Float64Array` | `3S`: the direction of each surface grid's v axis. |
| <a id="surfacecolumns-version"></a> `version` | `readonly` | `2` | Layout version of this result: always `2` (since 1.0.0 `values` keeps the server's type). |

***

<a id="surfacecolumnsfrombytes"></a>

## surfaceColumnsFromBytes

Import from `@infrared-city/infrared-sdk-ts`.

> **surfaceColumnsFromBytes**(`bytes`): `object`

Loads the blob of `surfaceColumnsToBytes`. The columns have no outline: pass the saved layout
to `surfaceRenderBuffers`. They also have no triangles.

### Parameters

| Parameter | Type | Description |
| ------ | ------ | ------ |
| `bytes` | `Uint8Array` | The blob. |

### Returns

`object`

The `columns` and the `layoutKey` saved with them (`undefined` when none was given).

| Name | Type |
| ------ | ------ |
| `columns` | [`SurfaceColumns`](results-and-legend.md#surfacecolumns) |
| `layoutKey?` | `string` |

### Throws

When the bytes are not a blob, or its version is unknown.

***

<a id="surfacecolumnstobytes"></a>

## surfaceColumnsToBytes

Import from `@infrared-city/infrared-sdk-ts`.

> **surfaceColumnsToBytes**(`columns`, `options?`): `Uint8Array`

Saves the values of one result as one blob: the values in the type the server stored, the
surface ids, the grid placement of each surface, the per-surface numbers, the legend and the
aggregates. It holds no outline and no triangles: the outline comes from the saved layout
(`surfaceRenderBuffers(columns, { layout })`). The blob starts with a version; a reader
refuses a version it does not know.

Store one layout per geometry (`FacadeLayout.toBytes`) and one blob per simulation. Give the
`layoutKey` of the layout the result belongs to; read it back with `surfaceColumnsFromBytes`
and pass it as `expectedLayoutKey` to `attachValues`.

### Parameters

| Parameter | Type | Description |
| ------ | ------ | ------ |
| `columns` | [`SurfaceColumns`](results-and-legend.md#surfacecolumns) | The surface columns of a run. |
| `options` | \{ `layoutKey?`: `string`; \} | `layoutKey`, the key of the layout the result belongs to. |
| `options.layoutKey?` | `string` | - |

### Returns

`Uint8Array`

The blob.

### Throws

When the columns hold a field the blob has no place for (`extra`).

***

<a id="surfaceentry"></a>

## SurfaceEntry

Import from `@infrared-city/infrared-sdk-ts`.

One surface of a surface result, keyed as in the JSON document (`origin`, `u-axis`,
`v-axis`, `grid-size`, `nu`, `nv`, `area`, `mean`, `peak`, `values`, and optionally
`cell-area` and `cell-tris`).

### Extends

- `Record`&lt;`string`, `unknown`&gt;

### Indexable

> \[`key`: `string`\]: `unknown`

### Properties

| Property | Type | Description |
| ------ | ------ | ------ |
| <a id="surfaceentry-cell-tris"></a> `cell-tris?` | (`number`\[\] \| `null`)\[\] \| `null` | Render triangles of each cell (9 numbers per triangle); absent or `null` when omitted. |
| <a id="surfaceentry-values"></a> `values` | `Float64Array`&lt;`ArrayBufferLike`&gt; \| (`number` \| `null`)\[\] | The value of each cell (`nu * nv` entries); `null` or `NaN` marks a cell without a value. |

***

<a id="surfacehasvalue"></a>

## surfaceHasValue

Import from `@infrared-city/infrared-sdk-ts`.

> **surfaceHasValue**(`result`, `cell`): `boolean`

Tells whether a cell has a value. Use it for every type of `values`: NaN (`"f16"` bits,
`"f32"`, `"f64"`) or a clear `valid` bit (`"i16"`) means no value.

### Parameters

| Parameter | Type | Description |
| ------ | ------ | ------ |
| `result` | [`SurfaceColumns`](results-and-legend.md#surfacecolumns) | The surface columns. |
| `cell` | `number` | The cell index, from `0` to `cellOffsets[surfaceCount] - 1`. |

### Returns

`boolean`

True when the cell has a value.

***

<a id="surfaceid"></a>

## surfaceId

Import from `@infrared-city/infrared-sdk-ts`.

> **surfaceId**(`result`, `row`): `string`

Returns the id of a surface.

### Parameters

| Parameter | Type | Description |
| ------ | ------ | ------ |
| `result` | [`SurfaceColumns`](results-and-legend.md#surfacecolumns) | The surface columns. |
| `row` | `number` | The surface row, from `0` to `surfaceCount - 1`. |

### Returns

`string`

The surface id.

***

<a id="surfaceindex"></a>

## surfaceIndex

Import from `@infrared-city/infrared-sdk-ts`.

> **surfaceIndex**(`result`): `ReadonlyMap`&lt;`string`, `number`&gt;

Maps each surface id to its row. The map is built on first use and kept with the result.

### Parameters

| Parameter | Type | Description |
| ------ | ------ | ------ |
| `result` | [`SurfaceColumns`](results-and-legend.md#surfacecolumns) | The surface columns. |

### Returns

`ReadonlyMap`&lt;`string`, `number`&gt;

A map from surface id to row.

***

<a id="surfacerenderbuffers"></a>

## SurfaceRenderBuffers

Import from `@infrared-city/infrared-sdk-ts`.

The buffers a renderer needs to draw a surface result: one record per frame, the outline
triangles of each frame, one value per cell and a validity bit per cell.

A renderer draws each frame as the triangles of its outline. A vertex `(s, t)` of the outline
is at `corner + s * uStep + t * vStep`, where `s` and `t` count cells. The fragment stage
finds the cell of a point and reads its value. Every array owns its buffer: you can transfer
it to another thread, and it stays valid for as long as you keep it.

### Properties

| Property | Modifier | Type | Description |
| ------ | ------ | ------ | ------ |
| <a id="surfacerenderbuffers-anchor"></a> `anchor` | `readonly` | `Float64Array` | `3`: the centroid of the frame corners, in the run's frame. Add it back in 64-bit floats. |
| <a id="surfacerenderbuffers-anyvalid"></a> `anyValid` | `readonly` | `boolean` | `false` when no cell has a value. |
| <a id="surfacerenderbuffers-dims"></a> `dims` | `readonly` | `Uint32Array` | `3S`: for each frame `nu`, `nv` and `cellStart` (the first cell of the frame in `values`). |
| <a id="surfacerenderbuffers-frames"></a> `frames` | `readonly` | `Float32Array` | `9S`: for each frame `corner`, `uStep`, `vStep`, relative to `anchor`. |
| <a id="surfacerenderbuffers-outline"></a> `outline` | `readonly` | `Float32Array` | `6T`: the outline triangles of all frames, `s0 t0 s1 t1 s2 t2`, in cell units. |
| <a id="surfacerenderbuffers-outlineoffsets"></a> `outlineOffsets` | `readonly` | `Uint32Array` | `S + 1`: frame `f` owns outline triangles `outlineOffsets[f]..outlineOffsets[f + 1]`. |
| <a id="surfacerenderbuffers-validity"></a> `validity` | `readonly` | `Uint8Array` | `ceil(C / 8)`: cell `k` is bit `k & 7` of byte `k >> 3`; set when the cell has a value. |
| <a id="surfacerenderbuffers-valuedtype"></a> `valueDtype` | `readonly` | `"f16"` \| `"f32"` | The type of `values`. |
| <a id="surfacerenderbuffers-valuemax"></a> `valueMax` | `readonly` | `number` | The greatest value over the valid cells, `0` when there is none. |
| <a id="surfacerenderbuffers-valuemin"></a> `valueMin` | `readonly` | `number` | The least value over the valid cells, `0` when there is none. |
| <a id="surfacerenderbuffers-values"></a> `values` | `readonly` | `Float32Array`&lt;`ArrayBufferLike`&gt; \| `Uint16Array`&lt;`ArrayBufferLike`&gt; | `C`: the value of a valid cell, `0` for a cell without a value. Half float BITS in a `Uint16Array` when `valueDtype` is `"f16"`, else a `Float32Array`. Never NaN or infinite. |

***

<a id="surfacerenderbuffers-2"></a>

## surfaceRenderBuffers

Import from `@infrared-city/infrared-sdk-ts`.

> **surfaceRenderBuffers**(`columns`, `options?`): [`SurfaceRenderBuffers`](results-and-legend.md#surfacerenderbuffers)

Builds the render buffers of a surface result.

The outline comes from `options.layout` (a saved layout: `FacadeLayout.fromBytes`), or from the
columns themselves: a facade or roof result of this client has one.

### Parameters

| Parameter | Type | Description |
| ------ | ------ | ------ |
| `columns` | [`SurfaceColumns`](results-and-legend.md#surfacecolumns) | The surface columns. |
| `options` | [`SurfaceRenderOptions`](results-and-legend.md#surfacerenderoptions) | `layout`, the layout that holds the outline. |

### Returns

[`SurfaceRenderBuffers`](results-and-legend.md#surfacerenderbuffers)

The render buffers, as owned typed arrays.

### Throws

When there is no outline, when a surface is not in the layout, or when a
  column breaks the contract (for example a frame with cells and no outline triangle, or a
  grid larger than 65,535 cells on a side). The message names the frame.

***

<a id="surfacerenderoptions"></a>

## SurfaceRenderOptions

Import from `@infrared-city/infrared-sdk-ts`.

The options of `surfaceRenderBuffers`.

### Properties

| Property | Modifier | Type | Description |
| ------ | ------ | ------ | ------ |
| <a id="surfacerenderoptions-layout"></a> `layout?` | `readonly` | [`FacadeLayout`](facade-layout.md#facadelayout) | A saved or rebuilt layout that holds the outline of each surface. Each surface of the columns is found in it by id. Check the pair first with `attachValues`. |

***

<a id="surfaceresultvalue"></a>

## SurfaceResultValue

Import from `@infrared-city/infrared-sdk-ts`.

A validated surface result: the surfaces by id, plus any other fields of the document.

### Extends

- `Record`&lt;`string`, `unknown`&gt;

### Indexable

> \[`key`: `string`\]: `unknown`

### Properties

| Property | Type | Description |
| ------ | ------ | ------ |
| <a id="surfaceresultvalue-surfaces"></a> `surfaces` | `Record`&lt;`string`, [`SurfaceEntry`](results-and-legend.md#surfaceentry)&gt; | The surfaces, by surface id. |

***

<a id="surfacesensorgrid"></a>

## SurfaceSensorGrid

Import from `@infrared-city/infrared-sdk-ts`.

The sensor grid of one surface: its placement, cell values and summary statistics.

The surface result of a single job is read as a map of these. An area run's merged
surface result is `SurfaceColumns` instead.

### Extends

- `Readonly`&lt;`Record`&lt;`string`, `unknown`&gt;&gt;

### Indexable

> \[`key`: `string`\]: `unknown`

### Properties

| Property | Modifier | Type | Description |
| ------ | ------ | ------ | ------ |
| <a id="surfacesensorgrid-area"></a> `area` | `readonly` | `number` | Total area of the surface's cells. |
| <a id="surfacesensorgrid-cellarea"></a> `cellArea?` | `readonly` | readonly (`number` \| `null`)\[\] | Area of each cell, when the result carries it. |
| <a id="surfacesensorgrid-celltris"></a> `cellTris?` | `readonly` | readonly (readonly `number`\[\] \| `null`)\[\] | Render triangles of each cell (9 numbers per triangle), when the result carries them. |
| <a id="surfacesensorgrid-gridsize"></a> `gridSize` | `readonly` | `number` | Cell edge length. |
| <a id="surfacesensorgrid-mean"></a> `mean` | `readonly` | `number` | Mean value over the surface. |
| <a id="surfacesensorgrid-nu"></a> `nu` | `readonly` | `number` | Number of cells along the u axis. |
| <a id="surfacesensorgrid-nv"></a> `nv` | `readonly` | `number` | Number of cells along the v axis. |
| <a id="surfacesensorgrid-origin"></a> `origin` | `readonly` | readonly `number`\[\] | Grid origin `[x, y, z]`. |
| <a id="surfacesensorgrid-peak"></a> `peak` | `readonly` | `number` | Peak value over the surface. |
| <a id="surfacesensorgrid-uaxis"></a> `uAxis` | `readonly` | readonly `number`\[\] | Direction of the grid's u axis `[x, y, z]`. |
| <a id="surfacesensorgrid-values"></a> `values` | `readonly` | `Float64Array`&lt;`ArrayBufferLike`&gt; \| readonly (`number` \| `null`)\[\] | The value of each cell (`nu * nv` entries); `null` or `NaN` marks a cell without a value. |
| <a id="surfacesensorgrid-vaxis"></a> `vAxis` | `readonly` | readonly `number`\[\] | Direction of the grid's v axis `[x, y, z]`. |

***

<a id="surfacetriangles"></a>

## SurfaceTriangles

Import from `@infrared-city/infrared-sdk-ts`.

The render triangles of a run, in groups. One group is one job (a tile, or a batch of
one). Positions are 32-bit float metres in the job's tile-local frame, and `anchors[2g]`,
`anchors[2g + 1]` is the tile's south-west offset they still owe to x and y. Keep the
anchor out of the float data and add it as the mesh's position (a 64-bit float in
JavaScript), which keeps city-scale coordinates exact.

### Properties

| Property | Modifier | Type | Description |
| ------ | ------ | ------ | ------ |
| <a id="surfacetriangles-anchors"></a> `anchors` | `readonly` | `Float64Array` | `2G`: each group's tile SW offset, owed to x and y. |
| <a id="surfacetriangles-celloffsets"></a> `cellOffsets` | `readonly` | `Uint32Array` | `C + 1`: cell `c` owns triangles `cellOffsets[c]..cellOffsets[c + 1]` (global index). |
| <a id="surfacetriangles-drawn"></a> `drawn` | `readonly` | `Uint8Array` | `C`: 1 when the cell has geometry, 0 for a cell without a sensor. |
| <a id="surfacetriangles-groupengaged"></a> `groupEngaged` | `readonly` | `Uint8Array` | `G`: 1 when the group has triangles, 0 when its job fell back. |
| <a id="surfacetriangles-groupsurfaces"></a> `groupSurfaces` | `readonly` | `Uint32Array` | `G + 1`: group `g` holds surfaces `groupSurfaces[g]..groupSurfaces[g + 1]`. |
| <a id="surfacetriangles-grouptriangles"></a> `groupTriangles` | `readonly` | `Uint32Array` | `G + 1`: group `g` holds triangles `groupTriangles[g]..groupTriangles[g + 1]`. |
| <a id="surfacetriangles-positions"></a> `positions` | `readonly` | readonly `Float32Array`&lt;`ArrayBufferLike`&gt;\[\] | `G`: 9 floats per triangle; the triangles of group `g` in its cell order. |

***

<a id="surfacevaluedtype"></a>

## SurfaceValueDtype

Import from `@infrared-city/infrared-sdk-ts`.

> **SurfaceValueDtype** = `"f16"` \| `"f32"` \| `"i16"` \| `"f64"`

The type of `SurfaceColumns.values`, as the server stored the values: `"f16"` (raw half
bits in a `Uint16Array`), `"f32"`, `"i16"` (scaled integers: physical value = value /
`valueDivisor`) or `"f64"` (a JSON result, or a run that mixes types).

***

<a id="surfacevalues"></a>

## SurfaceValues

Import from `@infrared-city/infrared-sdk-ts`.

> **SurfaceValues** = `Uint16Array` \| `Float32Array` \| `Int16Array` \| `Float64Array`

The typed array of `SurfaceColumns.values`, one per `SurfaceValueDtype`.

***

<a id="surfacevaluesf32"></a>

## surfaceValuesF32

Import from `@infrared-city/infrared-sdk-ts`.

> **surfaceValuesF32**(`result`, `first?`, `last?`): `Float32Array`

Returns the physical values of cells `first` to `last - 1` as 32-bit floats, `NaN` for a
cell without a value. It applies the type and the divisor in one call for the range. The
result is a new array; `values` does not change. Call `initializeCore()` first.

### Parameters

| Parameter | Type | Default value | Description |
| ------ | ------ | ------ | ------ |
| `result` | [`SurfaceColumns`](results-and-legend.md#surfacecolumns) | `undefined` | The surface columns. |
| `first` | `number` | `0` | The first cell. Default `0`. |
| `last` | `number` | `result.values.length` | One past the last cell. Default: every cell. |

### Returns

`Float32Array`

One value per cell of the range.

***

<a id="vertexvalues"></a>

## vertexValues

Import from `@infrared-city/infrared-sdk-ts`.

> **vertexValues**(`result`, `group`): `Float32Array`

Returns the value of each vertex of a group's triangles (three per triangle, aligned with
`triangles.positions[group]`): the physical value of the cell the triangle draws, `NaN` for
a cell without one. A renderer can upload it as an attribute next to the positions.

### Parameters

| Parameter | Type | Description |
| ------ | ------ | ------ |
| `result` | [`SurfaceColumns`](results-and-legend.md#surfacecolumns) | The surface columns. |
| `group` | `number` | The triangle group (one job). |

### Returns

`Float32Array`

One value per vertex.

### Throws

When the result has no triangles.

***

<a id="visualconfig"></a>

## VisualConfig

Import from `@infrared-city/infrared-sdk-ts`.

One colour configuration from the registry: the colours of a result and how to
step through them.

### Indexable

> \[`key`: `string`\]: `unknown`

### Properties

| Property | Type |
| ------ | ------ |
| <a id="visualconfig-colorinterpolation"></a> `colorInterpolation?` | `string` |
| <a id="visualconfig-colors"></a> `colors` | `number`\[\]\[\] |
| <a id="visualconfig-steps"></a> `steps?` | (`string` \| `number`)\[\] \| `null` |

***

<a id="visualconfigurations"></a>

## VisualConfigurations

Import from `@infrared-city/infrared-sdk-ts`.

> **VisualConfigurations** = `Record`&lt;`string`, `unknown`&gt;

The registry's `visualConfigurations` object, with all variants included, keyed by
configuration name.

***

<a id="windclassordinals"></a>

## windClassOrdinals

Import from `@infrared-city/infrared-sdk-ts`.

> **windClassOrdinals**(): `Record`&lt;`string`, `number`&gt;

The wind-comfort class table, mapping a class label to its ordinal, e.g.
`{A: 0, .., S: 5, S15: 5, S20: 6}`.

A label outside the table is treated as no-data, never as a clamped class.
`initializeCore()` must have completed.

### Returns

`Record`&lt;`string`, `number`&gt;

Class label to ordinal.

***
