# 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/geospatial.hpp>`

## haversines

Great-circle metres between every row and every column point on the mean sphere, through the haversine 2R · atan2(√h, √(1 − h)) evaluated in `precision_type_`, where h = sin²(Δφ / 2) + cos φ₁ · cos φ₂ · sin²(Δλ / 2).

```cpp
template <numeric_dtype precision_type_>
void haversines(
    f64_t const *a_latitudes,
    f64_t const *a_longitudes,
    std::size_t rows,
    f64_t const *b_latitudes,
    f64_t const *b_longitudes,
    std::size_t columns,
    f64_t *results,
    std::size_t results_stride) noexcept;
```

- `a_latitudes` (in): The [`rows`](https://www.unum.cloud/docs/numkong/cpp/matrix-kernels.md#rows) row latitudes, in radians.
- `a_longitudes` (in): The [`rows`](https://www.unum.cloud/docs/numkong/cpp/matrix-kernels.md#rows) row longitudes, in radians.
- `rows` (in): Number of row points.
- `b_latitudes` (in): The [`columns`](https://www.unum.cloud/docs/numkong/cpp/tensors-and-views.md#columns) column latitudes, in radians.
- `b_longitudes` (in): The [`columns`](https://www.unum.cloud/docs/numkong/cpp/tensors-and-views.md#columns) column longitudes, in radians.
- `columns` (in): Number of column points.
- `results` (out): The ____[rows,columns] distances, `results_stride` bytes apart.
- `results_stride` (in): Bytes between the rows of `results`.

## vincentys

Geodesic metres on the WGS-84 ellipsoid between every row and every column point, through Vincenty's inverse formula in `precision_type_`, with the reduced latitudes taken through atan2 to stay finite at the poles; parameters as [`haversines`](#haversines).

```cpp
template <numeric_dtype precision_type_>
void vincentys(
    f64_t const *a_latitudes,
    f64_t const *a_longitudes,
    std::size_t rows,
    f64_t const *b_latitudes,
    f64_t const *b_longitudes,
    std::size_t columns,
    f64_t *results,
    std::size_t results_stride) noexcept;
```

## sqeuclideans3d

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

```cpp
template <numeric_dtype in_type_, numeric_dtype result_type_ = std::conditional_t<std::is_same_v<in_type_, i32_t>, u64_t, f64_t>>
requires (std::is_same_v<in_type_, i32_t> || std::is_same_v<in_type_, f64_t>)
status_t sqeuclideans3d(
    in_type_ const *a,
    std::size_t rows,
    in_type_ const *b,
    std::size_t columns,
    result_type_ *results,
    std::size_t results_stride,
    nk_capability_t capabilities = default_capabilities(),
    nk_stream_t stream = nullptr) noexcept;
```

- `a` (in): The [`rows`](https://www.unum.cloud/docs/numkong/cpp/matrix-kernels.md#rows) points, 3 interleaved coordinates each.
- `rows` (in): Number of row points.
- `b` (in): The [`columns`](https://www.unum.cloud/docs/numkong/cpp/tensors-and-views.md#columns) points, 3 interleaved coordinates each.
- `columns` (in): Number of column points.
- `results` (out): The ____[rows,columns] squares, `results_stride` bytes apart.
- `results_stride` (in): Bytes between the rows of `results`.
- `capabilities` (in): Capabilities to pick from, or zero for the reference in `result_type_`.
- `stream` (in): Null on the CPU, or the stream of the device `capabilities` describes.

## haversines_pack_size

Returns the bytes a Haversine pack of [`points`](https://www.unum.cloud/docs/numkong/cpp/mesh-alignment.md#points) takes.

```cpp
expected<std::size_t> haversines_pack_size(
    std::size_t points,
    nk_capability_t capabilities = default_capabilities()) noexcept;
```

- `points` (in): Number of points in the pack.
- `capabilities` (in): Capabilities to pick from, or zero for the serial layout.

## haversines_pack

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

```cpp
status_t haversines_pack(
    f64_t const *latitudes,
    f64_t const *longitudes,
    std::size_t count,
    void *packed,
    nk_capability_t capabilities = default_capabilities(),
    nk_stream_t stream = nullptr) noexcept;
```

- `latitudes` (in): The [`count`](https://www.unum.cloud/docs/numkong/cpp/runtime-dispatch.md#count) latitudes, in radians.
- `longitudes` (in): The [`count`](https://www.unum.cloud/docs/numkong/cpp/runtime-dispatch.md#count) longitudes, in radians.
- `count` (in): Number of points.
- `packed` (out): At least [`haversines_pack_size`](#haversines_pack_size) bytes, aligned to `nk_default_alignment_k`.
- `capabilities` (in): Capabilities to pick from, or zero for the serial kernel.
- `stream` (in): Null on the CPU, or the stream of the device `capabilities` describes.

## haversines_packed

Great-circle metres between every row and every column point of two Haversine packs.

```cpp
status_t haversines_packed(
    void const *a_packed,
    void const *b_packed,
    f64_t *results,
    std::size_t results_stride,
    nk_capability_t capabilities = default_capabilities(),
    nk_stream_t stream = nullptr) noexcept;
```

- `a_packed` (in): The row points' Haversine pack.
- `b_packed` (in): The column points' Haversine pack.
- `results` (out): The ____[rows,columns] distances, `results_stride` bytes apart.
- `results_stride` (in): Bytes between the rows of `results`.
- `capabilities` (in): Capabilities to pick from, or zero for the serial kernel.
- `stream` (in): Null on the CPU, or the stream of the device `capabilities` describes.

## vincentys_pack_size

Returns the bytes a Vincenty pack of [`points`](https://www.unum.cloud/docs/numkong/cpp/mesh-alignment.md#points) takes, as [`haversines_pack_size`](#haversines_pack_size) does.

```cpp
expected<std::size_t> vincentys_pack_size(
    std::size_t points,
    nk_capability_t capabilities = default_capabilities()) noexcept;
```

## vincentys_pack

Packs points as their longitudes and the sines and cosines of their reduced latitudes, for [`vincentys_packed`](#vincentys_packed), taking what [`haversines_pack`](#haversines_pack) takes.

```cpp
status_t vincentys_pack(
    f64_t const *latitudes,
    f64_t const *longitudes,
    std::size_t count,
    void *packed,
    nk_capability_t capabilities = default_capabilities(),
    nk_stream_t stream = nullptr) noexcept;
```

## vincentys_packed

Geodesic metres on the WGS-84 ellipsoid between every row and every column point of two Vincenty packs, taking what [`haversines_packed`](#haversines_packed) takes.

```cpp
status_t vincentys_packed(
    void const *a_packed,
    void const *b_packed,
    f64_t *results,
    std::size_t results_stride,
    nk_capability_t capabilities = default_capabilities(),
    nk_stream_t stream = nullptr) noexcept;
```

## terrain_pack_size

Returns the bytes the terrain pack of a [`rows`](https://www.unum.cloud/docs/numkong/cpp/matrix-kernels.md#rows) × [`columns`](https://www.unum.cloud/docs/numkong/cpp/tensors-and-views.md#columns) grid takes.

```cpp
expected<std::size_t> terrain_pack_size(
    std::size_t rows,
    std::size_t columns,
    nk_capability_t capabilities = default_capabilities()) noexcept;
```

- `rows` (in): Number of grid rows.
- `columns` (in): Number of grid columns.
- `capabilities` (in): Capabilities to pick from, or zero for the serial layout.

## terrain_pack

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

```cpp
status_t terrain_pack(
    f32_t const *heights,
    std::size_t rows,
    std::size_t columns,
    std::size_t heights_stride,
    f64_t row_metres,
    f64_t column_metres,
    void *packed,
    nk_capability_t capabilities = default_capabilities(),
    nk_stream_t stream = nullptr) noexcept;
```

- `heights` (in): The ____[rows,columns] heights in metres, `heights_stride` bytes apart.
- `rows` (in): Number of grid rows.
- `columns` (in): Number of grid columns.
- `heights_stride` (in): Bytes between the rows of `heights`.
- `row_metres` (in): Metres between adjacent rows.
- `column_metres` (in): Metres between adjacent columns.
- `packed` (out): At least [`terrain_pack_size`](#terrain_pack_size) bytes, aligned to `nk_default_alignment_k`.
- `capabilities` (in): Capabilities to pick from, or zero for the serial kernel.
- `stream` (in): Null on the CPU, or the stream of the device `capabilities` describes.

## terrain_heights_packed

Bilinear terrain heights under [`count`](https://www.unum.cloud/docs/numkong/cpp/runtime-dispatch.md#count) interleaved [column, row] points, NaN off the grid, dispatched as [`terrain_pack`](#terrain_pack) is.

```cpp
status_t terrain_heights_packed(
    f32_t const *heights,
    void const *packed,
    f32_t const *points,
    std::size_t count,
    f32_t *results,
    nk_capability_t capabilities = default_capabilities(),
    nk_stream_t stream = nullptr) noexcept;
```

## clearances_packed

Clearances in metres from every row viewpoint to every column target over one terrain, as [`nk_clearances_packed_f32_best`](https://www.unum.cloud/docs/numkong/c/geospatial-metrics.md#nk_clearances_packed_f32_best) defines them, dispatched as [`terrain_pack`](#terrain_pack) is.

```cpp
status_t clearances_packed(
    f32_t const *heights,
    void const *packed,
    f32_t const *viewpoints,
    f32_t const *views,
    std::size_t rows,
    f32_t const *targets,
    std::size_t columns,
    f64_t refraction,
    f32_t *results,
    std::size_t results_stride,
    nk_capability_t capabilities = default_capabilities(),
    nk_stream_t stream = nullptr) noexcept;
```

