> ## Documentation Index
> Fetch the complete documentation index at: https://clickhouse.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> 地理坐标文档

# 处理地理坐标的函数

<div id="greatcircledistance">
  ## greatCircleDistance
</div>

使用[大圆距离公式](https://en.wikipedia.org/wiki/Great-circle_distance)计算地球表面上两点之间的距离。

```sql theme={null}
greatCircleDistance(lon1Deg, lat1Deg, lon2Deg, lat2Deg)
```

**输入参数**

* `lon1Deg` — 第一个点的经度 (以度为单位) 。范围：`[-180°, 180°]`。
* `lat1Deg` — 第一个点的纬度 (以度为单位) 。范围：`[-90°, 90°]`。
* `lon2Deg` — 第二个点的经度 (以度为单位) 。范围：`[-180°, 180°]`。
* `lat2Deg` — 第二个点的纬度 (以度为单位) 。范围：`[-90°, 90°]`。

正值表示北纬和东经，负值表示南纬和西经。

**返回值**

地球表面两点之间的距离，单位为米。

当输入参数值超出范围时，会抛出异常。

**示例**

```sql theme={null}
SELECT greatCircleDistance(55.755831, 37.617673, -55.755831, -37.617673) AS greatCircleDistance
```

```text theme={null}
┌─greatCircleDistance─┐
│            14128352 │
└─────────────────────┘
```

<div id="geodistance">
  ## geoDistance
</div>

与 `greatCircleDistance` 类似，但它计算的是 WGS-84 椭球体上的距离，而不是球面上的距离。这种方法对地球大地水准面的近似更精确。
其性能与 `greatCircleDistance` 相同 (没有性能损失) 。建议使用 `geoDistance` 来计算地球表面的距离。

技术说明：对于彼此足够接近的点，我们使用平面近似来计算距离，并采用坐标中点处切平面上的度量。

```sql theme={null}
geoDistance(lon1Deg, lat1Deg, lon2Deg, lat2Deg)
```

**输入参数**

* `lon1Deg` — 第一个点的经度 (单位：度) 。范围：`[-180°, 180°]`。
* `lat1Deg` — 第一个点的纬度 (单位：度) 。范围：`[-90°, 90°]`。
* `lon2Deg` — 第二个点的经度 (单位：度) 。范围：`[-180°, 180°]`。
* `lat2Deg` — 第二个点的纬度 (单位：度) 。范围：`[-90°, 90°]`。

正值表示北纬和东经，负值表示南纬和西经。

**返回值**

地球表面两点之间的距离，单位为米。

当输入参数的值超出上述范围时，会引发异常。

**示例**

```sql theme={null}
SELECT geoDistance(38.8976, -77.0366, 39.9496, -75.1503) AS geoDistance
```

```text theme={null}
┌─geoDistance─┐
│   212458.73 │
└─────────────┘
```

<div id="greatcircleangle">
  ## greatCircleAngle
</div>

使用[大圆距离公式](https://en.wikipedia.org/wiki/Great-circle_distance)计算地球表面两点之间的中心角。

```sql theme={null}
greatCircleAngle(lon1Deg, lat1Deg, lon2Deg, lat2Deg)
```

**输入参数**

* `lon1Deg` — 第一个点的经度，单位为度。
* `lat1Deg` — 第一个点的纬度，单位为度。
* `lon2Deg` — 第二个点的经度，单位为度。
* `lat2Deg` — 第二个点的纬度，单位为度。

**返回值**

两点之间的中心角，单位为度。

**示例**

```sql theme={null}
SELECT greatCircleAngle(0, 0, 45, 0) AS arc
```

```text theme={null}
┌─arc─┐
│  45 │
└─────┘
```

<div id="geotoutm">
  ## geoToUTM
</div>

将 WGS84 地理坐标 `(longitude, latitude)` 转换为 [Universal Transverse Mercator (UTM)](https://en.wikipedia.org/wiki/Universal_Transverse_Mercator_coordinate_system) 坐标。

UTM 是一组由 60 个横轴墨卡托投影构成的坐标系统，每个投影覆盖一个宽 6° 的经度带，用于将地理坐标映射到以米为单位的平面网格。除非显式指定 `zone`，否则会根据经度自动选择分区，并应用针对挪威和斯瓦尔巴的标准例外规则。UTM 仅定义于纬度范围 `[-80°, 84°]`；极地区域使用单独的 UPS 系统。

```sql theme={null}
geoToUTM(longitude, latitude[, zone])
```

**参数**

* `longitude` — 以度为单位的经度。范围：`[-180°, 180°]`。[`Float32`](/docs/zh/reference/data-types/float)/[`Float64`](/docs/zh/reference/data-types/float)。
* `latitude` — 以度为单位的纬度。范围：`[-80°, 84°]`。[`Float32`](/docs/zh/reference/data-types/float)/[`Float64`](/docs/zh/reference/data-types/float)。
* `zone` — 可选。将投影强制指定到此 UTM 分区，而不是自动选择。范围：`[1, 60]`。[`(U)Int*`](/docs/zh/reference/data-types/int-uint)。

**返回值**

一个命名元组 `(easting, northing, zone, band)`：`easting` 和 `northing` 以米为单位 ([`Float64`](/docs/zh/reference/data-types/float)) ，UTM `zone` 编号 ([`UInt8`](/docs/zh/reference/data-types/int-uint)) ，以及 MGRS 纬度 `band` 字母 ([`FixedString(1)`](/docs/zh/reference/data-types/fixedstring)) 。`band` 为 `'N'` 或其后字母时，表示北半球。

当纬度超出 `[-80°, 84°]` 或经度超出 `[-180°, 180°]` 时，会抛出异常。

**示例**

```sql theme={null}
SELECT geoToUTM(2.294497, 48.858222) AS utm; -- Eiffel Tower
```

```text theme={null}
(448251.5978370684,5411935.125629659,31,'U')
```

<div id="utmtogeo">
  ## UTMToGeo
</div>

将 [UTM](https://en.wikipedia.org/wiki/Universal_Transverse_Mercator_coordinate_system) 坐标还原为 WGS84 地理坐标 `(longitude, latitude)`。这是 [`geoToUTM`](#geotoutm) 的逆运算。

```sql theme={null}
UTMToGeo(easting, northing, zone, is_north)
```

**参数**

* `easting` — 以米为单位的东向坐标 (包含 500000 m 的假东向偏移) 。[`(U)Int*`](/docs/zh/reference/data-types/int-uint)/[`Float*`](/docs/zh/reference/data-types/float)。
* `northing` — 以米为单位的北向坐标 (包含南半球 10000000 m 的假北向偏移) 。[`(U)Int*`](/docs/zh/reference/data-types/int-uint)/[`Float*`](/docs/zh/reference/data-types/float)。
* `zone` — UTM 分区编号。范围：`[1, 60]`。[`(U)Int*`](/docs/zh/reference/data-types/int-uint)。
* `is_north` — 半球：`1` 表示北半球，`0` 表示南半球。[`(U)Int*`](/docs/zh/reference/data-types/int-uint)。

**返回值**

以度为单位的命名元组 `(longitude, latitude)`。[`Tuple(Float64, Float64)`](/docs/zh/reference/data-types/tuple)。

**示例**

```sql theme={null}
SELECT UTMToGeo(448251.6, 5411935.13, 31, 1) AS coord;
```

```text theme={null}
(2.2944970289079203,48.85822204127082)
```

<div id="geotomgrs">
  ## geoToMGRS
</div>

将 WGS84 地理坐标 `(longitude, latitude)` 编码为 [Military Grid Reference System (MGRS)](https://en.wikipedia.org/wiki/Military_Grid_Reference_System) 字符串。

该字符串的格式为 `<zone><band><100km square><easting><northing>`，例如 `31UDQ4825111935`。`precision` 参数控制 easting 和 northing 各自使用的位数：`5` (默认) 表示 1 m，`4` 表示 10 m，`3` 表示 100 m，`2` 表示 1 km，`1` 表示 10 km，`0` 则仅表示 100 km 网格方块。MGRS 仅对纬度范围在 `[-80°, 84°]` 内的坐标有定义。

```sql theme={null}
geoToMGRS(longitude, latitude[, precision])
```

**参数**

* `longitude` — 以度为单位的经度。范围：`[-180°, 180°]`。[`Float32`](/docs/zh/reference/data-types/float)/[`Float64`](/docs/zh/reference/data-types/float)。
* `latitude` — 以度为单位的纬度。范围：`[-80°, 84°]`。[`Float32`](/docs/zh/reference/data-types/float)/[`Float64`](/docs/zh/reference/data-types/float)。
* `precision` — 可选。东向坐标和北向坐标各自保留的位数。默认值：`5`。范围：`[0, 5]`。[`(U)Int*`](/docs/zh/reference/data-types/int-uint)。

**返回值**

MGRS 坐标字符串。[`String`](/docs/zh/reference/data-types/string)。

**示例**

```sql theme={null}
SELECT geoToMGRS(2.294497, 48.858222) AS mgrs, geoToMGRS(2.294497, 48.858222, 3) AS mgrs_100m;
```

```text theme={null}
┌─mgrs────────────┬─mgrs_100m───┐
│ 31UDQ4825111935 │ 31UDQ482119 │
└─────────────────┴─────────────┘
```

<div id="mgrstogeo">
  ## MGRSToGeo
</div>

将 [MGRS](https://en.wikipedia.org/wiki/Military_Grid_Reference_System) 字符串解码为 WGS84 地理坐标 `(longitude, latitude)`。这是 [`geoToMGRS`](#geotomgrs) 的逆运算。

返回的 Point 是所指网格方格的中心点，因此结果的精度与字符串中编码的精度一致。输入中的空白字符会被忽略，字母不区分大小写。

```sql theme={null}
MGRSToGeo(mgrs)
```

**参数**

* `mgrs` — 要解码的 MGRS 参考字符串。[`String`](/docs/zh/reference/data-types/string)/[`FixedString`](/docs/zh/reference/data-types/fixedstring)。

**返回值**

以度为单位的命名元组 `(longitude, latitude)`。[`Tuple(Float64, Float64)`](/docs/zh/reference/data-types/tuple)。

**示例**

```sql theme={null}
SELECT MGRSToGeo('31UDQ4825111935') AS coord;
```

```text theme={null}
(2.294495618908297,48.85822536113692)
```

<div id="pointinellipses">
  ## pointInEllipses
</div>

判断该点是否位于至少一个椭圆内。
坐标采用笛卡尔坐标系中的几何坐标。

```sql theme={null}
pointInEllipses(x, y, x₀, y₀, a₀, b₀,...,xₙ, yₙ, aₙ, bₙ)
```

**输入参数**

* `x, y` — 平面上一点的坐标。
* `xᵢ, yᵢ` — 第 `i` 个椭圆中心的坐标。
* `aᵢ, bᵢ` — 第 `i` 个椭圆的轴长，以 x、y 坐标单位表示。

输入参数的总数必须为 `2+4⋅n`，其中 `n` 是椭圆的数量。

**返回值**

如果该点位于至少一个椭圆内，则返回 `1`；否则返回 `0`。

**示例**

```sql theme={null}
SELECT pointInEllipses(10., 10., 10., 9.1, 1., 0.9999)
```

```text theme={null}
┌─pointInEllipses(10., 10., 10., 9.1, 1., 0.9999)─┐
│                                               1 │
└─────────────────────────────────────────────────┘
```

<div id="pointinpolygon">
  ## pointInPolygon
</div>

检查该点是否位于平面上的多边形内。

```sql theme={null}
pointInPolygon((x, y), [(a, b), (c, d) ...], ...)
```

**输入值**

* `(x, y)` — 平面上某一点的坐标。数据类型 — [Tuple](/docs/zh/reference/data-types/tuple) — 由两个数字组成的元组，或 [Point](/docs/zh/reference/data-types/geo#point)。
* `[(a, b), (c, d) ...]` — 多边形顶点。数据类型 — [Array](/docs/zh/reference/data-types/array) 或 [Ring](/docs/zh/reference/data-types/geo#ring)。每个顶点用一对坐标 `(a, b)` 表示。顶点应按顺时针或逆时针顺序指定。顶点最少为 3 个。
* 该函数支持带孔的多边形 (镂空区域) 。数据类型 — [Polygon](/docs/zh/reference/data-types/geo#polygon)。可以将整个 `Polygon` 作为第二个参数传入，也可以先传入外环，再将每个孔分别作为额外参数传入。
* 该函数也支持 `MultiPolygon`。数据类型 — [MultiPolygon](/docs/zh/reference/data-types/geo#multipolygon)。可以将整个 `MultiPolygon` 作为第二个参数传入，也可以将其中的每个组成多边形分别作为独立参数传入。
* 多边形参数也可以是包含多边形形态值 (`Ring`、`Polygon` 或 `MultiPolygon`) 的 [Geometry](/docs/zh/reference/data-types/geo#geometry) 列。

这些多边形形态类型 ([Ring](/docs/zh/reference/data-types/geo#ring)、[Polygon](/docs/zh/reference/data-types/geo#polygon)、[MultiPolygon](/docs/zh/reference/data-types/geo#multipolygon) 和 [Geometry](/docs/zh/reference/data-types/geo#geometry)) 既可以作为常量传入，也可以作为普通 (非常量) 表列传入。当多边形通过多个独立参数提供时 (先传外环再传孔，或传入一个 MultiPolygon 中的多个多边形) ，所有这些参数都必须是常量。

**返回值**

如果点位于多边形内部，则返回 `1`；否则返回 `0`。
如果点位于多边形边界上，函数可能返回 `0` 或 `1`。

**示例**

```sql theme={null}
SELECT pointInPolygon((3., 3.), [(6, 0), (8, 4), (5, 8), (0, 2)]) AS res
```

```text theme={null}
┌─res─┐
│   1 │
└─────┘
```

多边形也可以使用具名几何数据类型来指定，包括作为表列：

```sql theme={null}
CREATE TABLE poly (id UInt32, shape Polygon) ENGINE = Memory;
INSERT INTO poly VALUES (1, [[(0, 0), (10, 0), (10, 10), (0, 10)], [(4, 4), (6, 4), (6, 6), (4, 6)]]);
SELECT id, pointInPolygon((2., 2.), shape) AS res FROM poly;
```

```text theme={null}
┌─id─┬─res─┐
│  1 │   1 │
└────┴─────┘
```

> **注意**
> • 你可以设置 `validate_polygons = 0` 以跳过几何校验。
> • `pointInPolygon` 假定每个多边形都是合法的。如果输入存在自相交、环顺序错误或边重叠，结果就会变得不可靠——尤其是对于恰好位于边上、顶点上，或位于自相交区域内且“内部”与“外部”的概念未定义的点。
> • 当多边形参数是常量，且点是用已建立索引的键列表示时 (例如，在 `x, y` 是 `PRIMARY KEY` 的一部分或被 `minmax` 索引覆盖的表上使用 `pointInPolygon((x, y), constant_polygon)`) ，ClickHouse 可以同时使用主键和 `minmax` 数据跳过索引来跳过无关粒度。
