# Geo

These functions can be used when working with and analysing geospatial data.

These functions can be used when working with and analysing geospatial data.

<table>
  <thead>
    <tr>
      <th scope="col">Function</th>
      <th scope="col">Description</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td scope="row" data-label="Function"><a href="#geoarea"><code>geo::area()</code></a></td>
      <td scope="row" data-label="Description">Calculates the area of a geometry</td>
    </tr>
    <tr>
      <td scope="row" data-label="Function"><a href="#geobearing"><code>geo::bearing()</code></a></td>
      <td scope="row" data-label="Description">Calculates the bearing between two geolocation points</td>
    </tr>
    <tr>
      <td scope="row" data-label="Function"><a href="#geocentroid"><code>geo::centroid()</code></a></td>
      <td scope="row" data-label="Description">Calculates the centroid of a geometry</td>
    </tr>
    <tr>
      <td scope="row" data-label="Function"><a href="#geodistance"><code>geo::distance()</code></a></td>
      <td scope="row" data-label="Description">Calculates the distance between two geolocation points</td>
    </tr>
    <tr>
      <td scope="row" data-label="Function"><a href="#geohashdecode"><code>geo::hash::decode()</code></a></td>
      <td scope="row" data-label="Description">Decodes a geohash into a geometry point</td>
    </tr>
    <tr>
      <td scope="row" data-label="Function"><a href="#geohashencode"><code>geo::hash::encode()</code></a></td>
      <td scope="row" data-label="Description">Encodes a geometry point into a geohash</td>
    </tr>
    <tr>
      <td scope="row" data-label="Function"><a href="#geoisvalid"><code>geo::is_valid()</code></a></td>
      <td scope="row" data-label="Description">Determines if a geometry type is a geography type</td>
    </tr>
  </tbody>
</table>

## Point and geometry

* A `point` is composed of two floats that represent the longitude (east/west) and latitude (north/south) of a location.
* A `geometry` is a type of object defined in the [GeoJSON](https://en.wikipedia.org/wiki/GeoJSON) spec, of which Polygon is the most common. They can be passed in to the geo functions as objects that contain a "type" (such as "Polygon") and "coordinates" (an array of points).

## `geo::area`

The `geo::area` function calculates the area of a geometry in square metres.

```surql title="API DEFINITION"
geo::area(geometry) -> number
```

The following example shows this function, and its output, when used in a [`RETURN`](/docs/reference/query-language/statements/return.md) statement for four approximate points found on a map for the US state of Wyoming which has an area of 253,340 km<sup>2</sup> and a mostly rectangular shape. Note: the doubled square brackets are because the function takes an array of an array to allow for more complex types such as MultiPolygon.

<img src="~/assets/img/image/light/geo-wyoming.png" darkSrc="~/assets/img/image/dark/geo-wyoming.png" alt="A map of Wyoming in the United States with four approximate points on each corner used to approximate its total surface area in SurrealDB's geo area function." />

```surql
RETURN geo::area({
  type: "Polygon",
  coordinates: [[
    [-111.0690, 45.0032],
    [-104.0838, 44.9893],
    [-104.0910, 40.9974],
    [-111.0672, 40.9862]
  ]]
});
```

```surql title="Response"
253317731850.3478f
```

If the argument is not a geometry type, then an error will be returned.

```surql
RETURN geo::area(12345);

-- 'Incorrect arguments for function geo::area(). Argument 1 was the wrong type. Expected `geometry` but found `12345`'
```

<br />

## `geo::bearing`

The `geo::bearing` function calculates the bearing between two geolocation points. Bearing begins at 0 degrees to indicate north, increasing clockwise into positive values and decreasing counterclockwise into negative values that converge at 180 degrees.

<img src="~/assets/img/image/light/geo-bearing.png" darkSrc="~/assets/img/image/dark/geo-bearing.png" alt="A circle showing how bearing is defined from 0 degrees to 360 degrees." />

```surql title="API DEFINITION"
geo::bearing($from: point, $to: point) -> number
```

The following example shows this function, and its output, when used in a [`RETURN`](/docs/reference/query-language/statements/return.md) statement:

```surql
-- LET used here for readability
LET $paris = (2.358058597411099, 48.861109346459536);
LET $le_puy_en_velay = (3.883428431947686, 45.04383588468415);
RETURN geo::bearing($paris, $le_puy_en_velay);
RETURN geo::bearing($le_puy_en_velay, $paris);
```

```surql title="Response"
-- Slightly east of directly south
164.18154786094604f
-- Slightly west of directly north
-14.70308114652183f
```

<img src="~/assets/img/image/light/geo-paris.png" darkSrc="~/assets/img/image/dark/geo-paris.png" alt="A map showing the path from Paris, the capital of France, to a French town called Le Puy En Velay. The bearing is south southeast." />

<br />

## `geo::centroid`

The `geo::centroid` function calculates the centroid between multiple geolocation points.

```surql title="API DEFINITION"
geo::centroid(geometry) -> number
```
The following example shows this function, and its output, when used in a [`RETURN`](/docs/reference/query-language/statements/return.md) statement. Note: the doubled square brackets are because the function takes an array of an array to allow for more complex types such as MultiPolygon.

```surql
RETURN geo::centroid({
  type: "Polygon",
  coordinates: [[
    [-0.03921743611083, 51.88106875736589], -- London
    [30.48112752349519, 50.68377089794912], -- Kyiv
    [23.66174524001544, 42.94500782833793], -- Sofia
    [ 1.92481534361859, 41.69698118125476] -- Barcelona
  ]]
});
```

The return value is a mountainous region somewhere in Austria:

```surql title="Response"
(13.483896437936192, 47.07117241195589)
```

<img src="~/assets/img/image/light/geo-centroid.png" darkSrc="~/assets/img/image/dark/geo-centroid.png" alt="A map showing the centroid between four points in Europe: London, Kyiv, Sofia, and Barcelona. The centroid itself is located in Austria." />

<br />

## `geo::distance`

The `geo::distance` function calculates the haversine distance, in metres, between two geolocation points.

```surql title="API DEFINITION"
geo::distance($from: point, $to: point) -> number
```

The following example shows this function, and its output, when used in a [`RETURN`](/docs/reference/query-language/statements/return.md) statement:

```surql
let $london = (-0.04592553673505285, 51.555282574465764);
let $harare = (30.463880214538577, -17.865161568822085);
RETURN geo::distance($london, $harare);
```

```surql title="Response"
8268604.251890703f
```

<img src="~/assets/img/image/light/geo-london.png" darkSrc="~/assets/img/image/dark/geo-london.png" alt="A map showing the distance in a straight line from London, the capital of the United Kingdom, to Harare, the capital of Zimbabwe" />

<br />

## `geo::hash::decode`

The `geo::hash::decode` function converts a geohash into a geolocation point.

```surql title="API DEFINITION"
geo::hash::decode(point) -> string
```
The following example shows this function, and its output, when used in a [`RETURN`](/docs/reference/query-language/statements/return.md) statement:

```surql
RETURN geo::hash::decode("mpuxk4s24f51");
```

```surql title="Response"
(51.50986494496465, -0.11809204705059528)
```

<br />

## `geo::hash::encode`

The `geo::hash::encode` function converts a geolocation point into a geohash.

```surql title="API DEFINITION"
geo::hash::encode(point) -> string
```

The function accepts a second argument, which determines the accuracy and granularity of the geohash.

```surql title="API DEFINITION"
geo::hash::encode(point, $granularity: number) -> string
```

The following example shows this function, and its output, when used in a [`RETURN`](/docs/reference/query-language/statements/return.md) statement:

```surql
RETURN geo::hash::encode( (51.509865, -0.118092) );

-- 'mpuxk4s24f51'
```

The following example shows this function with two arguments, and its output, when used in a select statement:

```surql
RETURN geo::hash::encode( (51.509865, -0.118092), 5 );

-- 'mpuxk'
```

<br />

## `geo::is_valid`

The `geo::is_valid` function determines if a geometry type is a geography type.
Geography types are used to store geolocation data in a [Geographic Coordinate System (GCS)](https://en.wikipedia.org/wiki/Geographic_coordinate_system),
whereas geometry types can store geolocation data in any coordinate system, including GCS, mathematical planes, board game layouts, etc...

A geography type add the following constraint:
each `Point` coordinates are in the range of -180° to 180° for longitude and -90° to 90° for latitude.

```surql title="API DEFINITION"
geo::is_valid(geometry) -> bool
```

The following examples show this function, and its output, when used in a [`RETURN`](/docs/reference/query-language/statements/return.md) statement:

```surql title="A valid geography point"
RETURN geo::is_valid( (51.509865, -0.118092) );

-- true
```

```surql title="Out of range geometry point"
RETURN geo::is_valid( (-181.0, -0.118092) );

-- false
```

<br /><br />
