# Geospatial Metrics

> NumKong for C

The native SDK exposes both the fast spherical approximation and the more accurate ellipsoidal solver, each between every row and every column of two packed point sets.
Inputs are in radians.
Outputs are in meters.

```c
// Statue of Liberty (40.6892°N, 74.0445°W) and Big Ben (51.5007°N, 0.1246°W)
nk_f64_t latitudes[] = {0.7101605100, 0.8988567821}, longitudes[] = {-1.2923203180, -0.0021746802};

// A pack is built once per point set, on an `nk_default_alignment_k` boundary
nk_size_t bytes = 0;
nk_vincentys_pack_size_f64_best(2, capabilities, &bytes);
void *vincentys_pack = aligned_alloc(nk_default_alignment_k, bytes);
nk_vincentys_pack_f64_best(latitudes, longitudes, 2, vincentys_pack, capabilities, NULL);

// Every row against every column, so the diagonal is zero
nk_f64_t distances[2][2];
nk_vincentys_packed_f64_best(vincentys_pack, vincentys_pack, &distances[0][0], 2 * sizeof(nk_f64_t), capabilities,
                             NULL); // distances[0][1] ≈ 5,589,857 m on WGS-84

nk_haversines_pack_size_f64_best(2, capabilities, &bytes);
void *haversines_pack = aligned_alloc(nk_default_alignment_k, bytes);
nk_haversines_pack_f64_best(latitudes, longitudes, 2, haversines_pack, capabilities, NULL);
nk_haversines_packed_f64_best(haversines_pack, haversines_pack, &distances[0][0], 2 * sizeof(nk_f64_t),
                              capabilities, NULL); // distances[0][1] ≈ 5,574,848 m on the mean sphere, 15 km less
```

`#include <numkong/capabilities.h>`

`#include <numkong/geospatial.h>`

## nk_geospatial_pack_size_punned_t

Pack sizes are host arithmetic, so they take no stream.

```c
typedef nk_status_t(*) nk_geospatial_pack_size_punned_t(nk_size_t points, nk_size_t *bytes);
```

## nk_sqeuclideans3d_*_best

Squared Euclidean distances between every row point and every column point in 3D.

```c
nk_status_t nk_sqeuclideans3d_i32_best(
    nk_i32_t const *a,
    nk_size_t rows,
    nk_i32_t const *b,
    nk_size_t columns,
    nk_u64_t *results,
    nk_size_t results_stride,
    nk_capability_t capabilities,
    nk_stream_t stream);
```

- `nk_sqeuclideans3d_i32_best`: a, b `nk_i32_t`, results `nk_u64_t`
- `nk_sqeuclideans3d_f64_best`: a, b `nk_f64_t`, results `nk_f64_t`

- `nk_sqeuclideans3d_i32` backends: serial, neon, haswell, skylake, v128relaxed, rvv
- `nk_sqeuclideans3d_f64` backends: serial, neon, haswell, skylake, v128relaxed, rvv

Integer results are exact whenever every axis difference fits 32 bits, which Earth-fixed centimetres below 4,359 km of altitude always satisfy. F64 inputs sum their squares in Dot2.

- `a` (in): The rows, `rows` × 3 interleaved [x0,y0,z0, x1,y1,z1, ...].
- `rows` (in): The number of row points.
- `b` (in): The columns, `columns` × 3 interleaved.
- `columns` (in): The number of column points.
- `results` (out): The ____[rows,columns] squared distances.
- `results_stride` (in): The bytes between consecutive rows of `results`.
- `capabilities` (in): One device's capabilities, like [`nk_cpu_capabilities_enabled`](https://www.unum.cloud/docs/numkong/c/runtime-dispatch.md#nk_cpu_capabilities_enabled) reports.
- `stream` (in): Null on the CPU, or the GPU stream of that device to queue on.

Statuses: - [`nk_missing_kernel_k`](https://www.unum.cloud/docs/numkong/c/quickstart.md#nk_missing_kernel_k) No capability in `capabilities` has it.

## nk_*_pack_size_f64_best

Returns the bytes a Haversine or Vincenty pack of `points` points takes.

```c
nk_status_t nk_haversines_pack_size_f64_best(
    nk_size_t points,
    nk_capability_t capabilities,
    nk_size_t *bytes);
```

- `nk_haversines_pack_size_f64_best`
- `nk_vincentys_pack_size_f64_best`

- `nk_haversines_pack_size_f64` backends: serial, cuda
- `nk_vincentys_pack_size_f64` backends: serial, cuda

- `points` (in): The number of points.
- `capabilities` (in): One device's capabilities, like [`nk_cpu_capabilities_enabled`](https://www.unum.cloud/docs/numkong/c/runtime-dispatch.md#nk_cpu_capabilities_enabled) reports.
- `bytes` (out): The size of the pack.

Statuses: - [`nk_missing_kernel_k`](https://www.unum.cloud/docs/numkong/c/quickstart.md#nk_missing_kernel_k) No capability in `capabilities` has it.

## nk_haversines_pack_f64_best

Packs points as unit vectors on the mean sphere, for [`nk_haversines_packed_f64_best`](#nk_haversines_packed_f64_best).

```c
nk_status_t nk_haversines_pack_f64_best(
    nk_f64_t const *latitudes,
    nk_f64_t const *longitudes,
    nk_size_t count,
    void *packed,
    nk_capability_t capabilities,
    nk_stream_t stream);
```

- `nk_haversines_pack_f64` backends: serial, cuda

- `latitudes` (in): Latitudes, in radians.
- `longitudes` (in): Longitudes, in radians.
- `count` (in): The number of points.
- `packed` (out): The pack, on an `nk_default_alignment_k` boundary.
- `capabilities` (in): One device's capabilities, like [`nk_cpu_capabilities_enabled`](https://www.unum.cloud/docs/numkong/c/runtime-dispatch.md#nk_cpu_capabilities_enabled) reports.
- `stream` (in): Null on the CPU, or the GPU stream of that device to queue on.

Statuses: - [`nk_missing_kernel_k`](https://www.unum.cloud/docs/numkong/c/quickstart.md#nk_missing_kernel_k) No capability in `capabilities` has it.

## nk_vincentys_pack_f64_best

Packs points as their longitudes and the sines and cosines of their reduced latitudes on the ellipsoid, for [`nk_vincentys_packed_f64_best`](#nk_vincentys_packed_f64_best); parameters as [`nk_haversines_pack_f64_best`](#nk_haversines_pack_f64_best).

```c
nk_status_t nk_vincentys_pack_f64_best(
    nk_f64_t const *latitudes,
    nk_f64_t const *longitudes,
    nk_size_t count,
    void *packed,
    nk_capability_t capabilities,
    nk_stream_t stream);
```

- `nk_vincentys_pack_f64` backends: serial, cuda

## nk_haversines_packed_f64_best

Great-circle metres between every row and every column point on the mean sphere.

```c
nk_status_t nk_haversines_packed_f64_best(
    void const *a_packed,
    void const *b_packed,
    nk_f64_t *results,
    nk_size_t results_stride,
    nk_capability_t capabilities,
    nk_stream_t stream);
```

- `nk_haversines_packed_f64` backends: serial, neon, haswell, skylake, v128relaxed, rvv, cuda

- `a_packed` (in): The row points, as [`nk_haversines_pack_f64_best`](#nk_haversines_pack_f64_best) packed them.
- `b_packed` (in): The column points, packed the same way.
- `results` (out): The ____[rows,columns] distances.
- `results_stride` (in): The bytes between consecutive rows of `results`.
- `capabilities` (in): One device's capabilities, like [`nk_cpu_capabilities_enabled`](https://www.unum.cloud/docs/numkong/c/runtime-dispatch.md#nk_cpu_capabilities_enabled) reports.
- `stream` (in): Null on the CPU, or the GPU stream of that device to queue on.

Statuses: - [`nk_missing_kernel_k`](https://www.unum.cloud/docs/numkong/c/quickstart.md#nk_missing_kernel_k) No capability in `capabilities` has it.

## nk_vincentys_packed_f64_best

Geodesic metres on the WGS-84 ellipsoid between every row and every column point, from packs of [`nk_vincentys_pack_f64_best`](#nk_vincentys_pack_f64_best); parameters as [`nk_haversines_packed_f64_best`](#nk_haversines_packed_f64_best).

```c
nk_status_t nk_vincentys_packed_f64_best(
    void const *a_packed,
    void const *b_packed,
    nk_f64_t *results,
    nk_size_t results_stride,
    nk_capability_t capabilities,
    nk_stream_t stream);
```

- `nk_vincentys_packed_f64` backends: serial, neon, haswell, skylake, v128relaxed, rvv, cuda

## nk_terrain_pack_size_f32_best

Returns the bytes the terrain pack of a `rows` × `columns` grid takes.

```c
nk_status_t nk_terrain_pack_size_f32_best(
    nk_size_t rows,
    nk_size_t columns,
    nk_capability_t capabilities,
    nk_size_t *bytes);
```

- `nk_terrain_pack_size_f32` backends: serial, cuda

- `rows` (in): The grid rows.
- `columns` (in): The grid columns.
- `capabilities` (in): One device's capabilities, like [`nk_cpu_capabilities_enabled`](https://www.unum.cloud/docs/numkong/c/runtime-dispatch.md#nk_cpu_capabilities_enabled) reports.
- `bytes` (out): The size of the pack.

Statuses: - [`nk_missing_kernel_k`](https://www.unum.cloud/docs/numkong/c/quickstart.md#nk_missing_kernel_k) No capability in `capabilities` has it.

## nk_terrain_pack_f32_best

Packs the maxima of every 2ᵏ × 2ᵏ block of a north-up grid, its shape and scale.

```c
nk_status_t nk_terrain_pack_f32_best(
    nk_f32_t const *heights,
    nk_size_t rows,
    nk_size_t columns,
    nk_size_t heights_stride,
    nk_f64_t row_metres,
    nk_f64_t column_metres,
    void *packed,
    nk_capability_t capabilities,
    nk_stream_t stream);
```

- `nk_terrain_pack_f32` backends: serial, cuda

- `heights` (in): The ____[rows,columns] heights in metres, row 0 at the north edge; NaN marks a missing cell. Every later call names the same buffer again.
- `rows` (in): The grid rows.
- `columns` (in): The grid columns.
- `heights_stride` (in): The bytes between consecutive rows of `heights`.
- `row_metres` (in): The ground length of one row step, constant over the grid.
- `column_metres` (in): The ground length of one column step, constant over the grid.
- `packed` (out): The pack, on an `nk_default_alignment_k` boundary.
- `capabilities` (in): One device's capabilities, like [`nk_cpu_capabilities_enabled`](https://www.unum.cloud/docs/numkong/c/runtime-dispatch.md#nk_cpu_capabilities_enabled) reports.
- `stream` (in): Null on the CPU, or the GPU stream of that device to queue on.

Statuses: - [`nk_missing_kernel_k`](https://www.unum.cloud/docs/numkong/c/quickstart.md#nk_missing_kernel_k) No capability in `capabilities` has it.

## nk_terrain_heights_packed_f32_best

Bilinear terrain heights under `count` points.

```c
nk_status_t nk_terrain_heights_packed_f32_best(
    nk_f32_t const *heights,
    void const *packed,
    nk_f32_t const *points,
    nk_size_t count,
    nk_f32_t *results,
    nk_capability_t capabilities,
    nk_stream_t stream);
```

- `nk_terrain_heights_packed_f32` backends: serial, cuda

- `heights` (in): The grid `packed` was built from.
- `packed` (in): The grid's terrain pack.
- `points` (in): The `count` × 2 interleaved [column,row] cell coordinates of the points.
- `count` (in): The number of points.
- `results` (out): The `count` heights in metres, NaN off the grid or beside a missing cell.
- `capabilities` (in): One device's capabilities, like [`nk_cpu_capabilities_enabled`](https://www.unum.cloud/docs/numkong/c/runtime-dispatch.md#nk_cpu_capabilities_enabled) reports.
- `stream` (in): Null on the CPU, or the GPU stream of that device to queue on.

Statuses: - [`nk_missing_kernel_k`](https://www.unum.cloud/docs/numkong/c/quickstart.md#nk_missing_kernel_k) No capability in `capabilities` has it.

## nk_clearances_packed_f32_best

Clearances in metres from every row viewpoint to every column target over one terrain, as Clearance defines them.

```c
nk_status_t nk_clearances_packed_f32_best(
    nk_f32_t const *heights,
    void const *packed,
    nk_f32_t const *viewpoints,
    nk_f32_t const *views,
    nk_size_t rows,
    nk_f32_t const *targets,
    nk_size_t columns,
    nk_f64_t refraction,
    nk_f32_t *results,
    nk_size_t results_stride,
    nk_capability_t capabilities,
    nk_stream_t stream);
```

- `nk_clearances_packed_f32` backends: serial, cuda

- `heights` (in): The grid `packed` was built from.
- `packed` (in): The grid's terrain pack.
- `viewpoints` (in): The rows, `rows` × 3 interleaved [column, row, height].
- `views` (in): Null, seeing everywhere without limit, or `rows` × 4 interleaved [azimuth, elevation, field, range]: radians clockwise from the grid's north and above the horizon, the full cone angle in radians, and metres.
- `rows` (in): The number of viewpoints.
- `targets` (in): The columns, `columns` × 3 interleaved [column, row, height].
- `columns` (in): The number of targets.
- `refraction` (in): The refraction coefficient: 1/7 for light, 0.25 for radio, 0 for none.
- `results` (out): The ____[rows,columns] clearances.
- `results_stride` (in): The bytes between consecutive rows of `results`.
- `capabilities` (in): One device's capabilities, like [`nk_cpu_capabilities_enabled`](https://www.unum.cloud/docs/numkong/c/runtime-dispatch.md#nk_cpu_capabilities_enabled) reports.
- `stream` (in): Null on the CPU, or the GPU stream of that device to queue on.

Statuses: - [`nk_missing_kernel_k`](https://www.unum.cloud/docs/numkong/c/quickstart.md#nk_missing_kernel_k) No capability in `capabilities` has it.

## nk_sqeuclideans3d_output_dtype

Returns the output dtype of `sqeuclideans3d:` exact `u64` for `i32`, `f64` for `f64`.

```c
nk_dtype_t nk_sqeuclideans3d_output_dtype(nk_dtype_t dtype);
```

## nk_geodesics_output_dtype

Returns the output dtype of `haversines` and `vincentys`.

```c
nk_dtype_t nk_geodesics_output_dtype(nk_dtype_t dtype);
```

## nk_clearances_output_dtype

Returns the output dtype of `clearances`.

```c
nk_dtype_t nk_clearances_output_dtype(nk_dtype_t dtype);
```

## nk_haversines_error_bound

Returns the error bound of a Haversine central angle in radians, relative to one plus the angle: 3 sines and cosines per unit vector at 3.5 ULP, the Dot2 norms, 2 roots and the arctangent.

```c
nk_f64_t nk_haversines_error_bound(nk_dtype_t dtype);
```

## nk_vincentys_error_bound

Returns the error bound of a Vincenty angular distance, in radians: the longitude the iteration stops within, and 20 roundings on the longest path from the reduced latitudes through one iteration and the series.

```c
nk_f64_t nk_vincentys_error_bound(nk_dtype_t dtype);
```

## nk_geospatial_find_kernel

Finds the geospatial kernel of `kind` for `dtype`, from the best of `capabilities`.

```c
nk_status_t nk_geospatial_find_kernel(
    nk_kernel_kind_t kind,
    nk_dtype_t dtype,
    nk_capability_t capabilities,
    nk_kernel_punned_t *kernel,
    nk_capability_t *capability);
```

- `kind` (in): The verb whose kernel to find.
- `dtype` (in): The input type the kernel reads.
- `capabilities` (in): The mask to pick the best capability from.
- `kernel` (out): The kernel, or null when no capability in `capabilities` has it.
- `capability` (out): The capability the kernel belongs to, or zero.

Statuses: - [`nk_missing_kernel_k`](https://www.unum.cloud/docs/numkong/c/quickstart.md#nk_missing_kernel_k)
- [`nk_missing_library_k`](https://www.unum.cloud/docs/numkong/c/quickstart.md#nk_missing_library_k) Header-only.

## NUMKONG_EARTH_MEAN_RADIUS

The IUGG mean radius R₁, in metres, of the Haversine sphere and the terrain curvature.

```c
#define NUMKONG_EARTH_MEAN_RADIUS (6371008.8)
```

## NUMKONG_EARTH_ELLIPSOID_EQUATORIAL_RADIUS

The WGS-84 semi-major axis, in metres; the polar radius derives as a × (1 − f).

```c
#define NUMKONG_EARTH_ELLIPSOID_EQUATORIAL_RADIUS (6378137.0)
```

## NUMKONG_EARTH_ELLIPSOID_INVERSE_FLATTENING

The WGS-84 inverse flattening.

```c
#define NUMKONG_EARTH_ELLIPSOID_INVERSE_FLATTENING (298.257223563)
```

