坐标转换工具为 GIS 和测绘应用提供了一套完整的坐标系统转换功能，涵盖角度格式转换、坐标系统转换、几何变换等核心能力。本模块通过 PySSMath 提供高性能的坐标转换算法，支持从基础的角度格式互转到复杂的坐标系统映射变换。本文档面向高级开发者，详细说明各类坐标转换工具的 API 使用方法和应用场景。

Sources: [PySSMath.py](PySSMath.py#L2700-L2787)

## 角度格式转换

PySSMath 提供了多种角度表示形式之间的转换功能，支持弧度制、十进制度数、度分秒（DMS）格式之间的灵活互转，满足测绘应用中不同角度表示需求。

### 基础角度转换

| 函数名 | 功能描述 | 参数 | 返回值 |
|--------|----------|------|--------|
| `degToRadian(deg)` | 十进制度数转弧度 | deg: float | 弧度值 |
| `radianToDeg(dRadian)` | 弧度转十进制度数 | dRadian: float | 度数值 |
| `degToDms(deg)` | 十进制度数转度分秒 | deg: float | DMS 值 |
| `dmsToDeg(dms)` | 度分秒转十进制度数 | dms: float | 度数值 |
| `dmsToRadian(dDms)` | 度分秒转弧度 | dDms: float | 弧度值 |
| `radianToDms(dRadian)` | 弧度转度分秒 | dRadian: float | DMS 值 |
| `dmsToSec(dms)` | 度分秒转秒数 | dms: float | 秒数 |
| `secToDms(sec)` | 秒数转度分秒 | sec: float | DMS 值 |

### 角度调整函数

| 函数名 | 功能描述 | 参数说明 |
|--------|----------|----------|
| `adjustAngle(dRadian)` | 调整弧度值到 [-π, π] 范围 | dRadian: 待调整的弧度值 |
| `adjustDmsAngle(dAngle)` | 调整 DMS 角度值 | dAngle: 待调整的 DMS 角度值 |
| `adjustDegAngle(dAngle)` | 调整度数值到 [0, 360] 范围 | dAngle: 待调整的度数值 |

### 角度转换示例

```python
import sunvpy.PySSMath as ssMath

# 十进制度数转弧度
deg_value = 45.5
rad_value = ssMath.degToRadian(deg_value)
print(f"{deg_value}° = {rad_value:.6f} rad")

# 弧度转度分秒
dms_value = ssMath.radianToDms(1.5708)
print(f"1.5708 rad = {dms_value:.4f} (DMS格式)")

# 角度调整到标准范围
adjusted_angle = ssMath.adjustAngle(7.0)  # 超出范围的角度
print(f"调整后角度: {adjusted_angle:.6f} rad")
```

Sources: [PySSMath.py](PySSMath.py#L2752-L2767)

## 极坐标与直角坐标转换

极坐标和直角坐标是两种常用的坐标表示方式，适用于不同的应用场景。PySSMath 提供了两者之间的双向转换功能。

### 坐标转换函数

| 函数名 | 功能描述 | 参数说明 |
|--------|----------|----------|
| `rightToPolar(x, y)` | 直角坐标转极坐标 | x, y: 直角坐标值，返回 (距离, 方位角) |
| `polarToRight(r, angle)` | 极坐标转直角坐标 | r: 距离；angle: 方位角（弧度） |
| `getPolar(p1, p2, dist, dRadian)` | 从基点按距离和方位角获取点 | p1: 基点；p2: 参考点；dist: 距离；dRadian: 方位角 |
| `getPoint(p1, p2, dist, dRadian)` | 同 getPolar | 参数同 getPolar |

### 极坐标转换示例

```python
import sunvpy.PySSMath as ssMath

# 直角坐标转极坐标
x, y = 100.0, 100.0
distance, angle = ssMath.rightToPolar(x, y)
print(f"直角坐标 ({x}, {y}) -> 极坐标: 距离={distance:.2f}, 方位角={angle:.6f} rad")

# 极坐标转直角坐标
r = 141.42
angle_rad = 0.785398
x_new, y_new = ssMath.polarToRight(r, angle_rad)
print(f"极坐标 (r={r}, angle={angle_rad}) -> 直角坐标: ({x_new:.2f}, {y_new:.2f})")

# 从基点获取极坐标点
import sunvpy.PySSMath.Point3D as Point3D
p1 = Point3D(0, 0, 0)
p2 = Point3D(1, 0, 0)
new_point = ssMath.getPolar(p1, p2, 100, ssMath.degToRadian(45))
print(f"从原点向东45°方向100米处的点: ({new_point.x():.2f}, {new_point.y():.2f})")
```

Sources: [PySSMath.py](PySSMath.py#L2808-L2815)

## 方位角计算

方位角计算是测绘和导航应用中的核心功能，PySSMath 提供了多种方位角计算方法，支持点对点方位角、角度平分等场景。

### 方位角计算函数

| 函数名 | 功能描述 | 参数说明 |
|--------|----------|----------|
| `bearing(x1, y1, x0, y0)` | 计算从点 (x0, y0) 到点 (x1, y1) 的方位角 | 返回弧度值 |
| `bearing(p0, p1)` | 计算方位角（使用 Point3D 对象） | p0: 起始点；p1: 目标点 |
| `jiaoPingfenFangWei(x1, y1, x0, y0, x2, y2)` | 计算两线段的夹角平分方位角 | (x1,y1)-(x0,y0) 和 (x2,y2)-(x0,y0) 的平分方向 |

### 角度计算函数

| 函数名 | 功能描述 | 返回值 |
|--------|----------|--------|
| `openAngle(p1, p0, p2)` | 计算 ∠p1p0p2 的夹角 | 弧度值 |
| `openAngleDeg(p1, p0, p2)` | 计算夹角（度数） | 度数 |

### 方位角计算示例

```python
import sunvpy.PySSMath as ssMath
import sunvpy.PySSMath.Point3D as Point3D

# 计算两点间的方位角
x0, y0 = 100.0, 100.0  # 起点
x1, y1 = 200.0, 150.0  # 终点
azimuth_rad = ssMath.bearing(x1, y1, x0, y0)
azimuth_deg = ssMath.radianToDeg(azimuth_rad)
print(f"从 ({x0}, {y0}) 到 ({x1}, {y1}) 的方位角: {azimuth_deg:.2f}°")

# 使用 Point3D 对象计算方位角
p0 = Point3D(100.0, 100.0, 0)
p1 = Point3D(200.0, 150.0, 0)
azimuth_rad2 = ssMath.bearing(p0, p1)
print(f"方位角（弧度）: {azimuth_rad2:.6f}")

# 计算角度平分方向
# 从 (0,0) 到 (100,0) 和 (0,100) 的夹角平分方向
bisect_angle = ssMath.jiaoPingfenFangWei(100, 0, 0, 0, 0, 100)
bisect_deg = ssMath.radianToDeg(bisect_angle)
print(f"90°角的平分方位角: {bisect_deg:.2f}°")

# 计算三点夹角
p1 = Point3D(0, 100, 0)
p_center = Point3D(0, 0, 0)
p2 = Point3D(100, 0, 0)
angle_rad = ssMath.openAngle(p1, p_center, p2)
angle_deg = ssMath.radianToDeg(angle_rad)
print(f"夹角 ∠p1-center-p2: {angle_deg:.2f}°")
```

Sources: [PySSMath.py](PySSMath.py#L2789-L2797)

## 几何变换操作

几何变换是坐标转换的重要应用场景，包括旋转、平移、缩放、镜像等基本变换，以及系统坐标旋转、映射变换等高级变换。

### 二维几何变换

| 函数名 | 功能描述 | 参数说明 |
|--------|----------|----------|
| `rotate2DList(Points, angle, basePoint)` | 二维点集旋转 | angle: 旋转角（弧度）；basePoint: 旋转基点 |
| `offset2DList(Points, dx, dy)` | 二维点集平移 | dx, dy: X和Y方向的平移量 |

### 三维几何变换

| 函数名 | 功能描述 | 参数说明 |
|--------|----------|----------|
| `rotate3DList(*args)` | 三维点集旋转 | 支持多种参数形式（绕轴旋转、绕任意轴旋转） |
| `offset3DList(*args)` | 三维点集偏移 | 支持偏移向量或分量形式 |
| `zoom3DList(*args)` | 三维点集缩放 | 支持缩放中心和缩放因子 |
| `mirror3DList(baseP0, baseP1, Ps)` | 三维点集镜像 | baseP0, baseP1: 镜像轴上的两点；Ps: 待变换点集 |
| `extend3DList(Points, dist, bTail)` | 点集延伸 | dist: 延伸距离；bTail: true=尾部延伸，false=头部延伸 |
| `smooth3DList(Ps0, fScale, nFlag)` | 点集平滑 | fScale: 平滑系数；nFlag: 平滑方式 |
| `mapping3DList(Points, ctrlPoints_old, ctrlPoints_new)` | 点集映射变换 | 基于控制点的仿射变换 |

### 系统坐标变换

| 函数名 | 功能描述 | 参数说明 |
|--------|----------|----------|
| `sysRotate(Xold, Yold, Xnew, Ynew, X0, Y0, dRadian)` | 系统旋转 | 将旧坐标系旋转至新坐标系 |
| `grdbodyRotate(*args)` | 网格体旋转 | 支持多种参数形式 |

### 几何变换示例

```python
import sunvpy.PySSMath as ssMath
import sunvpy.PySSMath.POINT3DLIST as POINT3DLIST
import sunvpy.PySSMath.Point3D as Point3D

# 创建点集
points = POINT3DLIST()
points.push_back(Point3D(10, 10, 0))
points.push_back(Point3D(20, 10, 0))
points.push_back(Point3D(20, 20, 0))

# 二维旋转（绕原点旋转90度）
basePoint = Point3D(0, 0, 0)
angle = ssMath.degToRadian(90)
ssMath.rotate2DList(points, angle, basePoint)
print("旋转后的点集:")
for i in range(points.size()):
    pt = points.at(i)
    print(f"  点{i+1}: ({pt.x():.2f}, {pt.y():.2f}, {pt.z():.2f})")

# 二维平移
ssMath.offset2DList(points, 5.0, 5.0)
print("平移后的点集:")
for i in range(points.size()):
    pt = points.at(i)
    print(f"  点{i+1}: ({pt.x():.2f}, {pt.y():.2f}, {pt.z():.2f})")

# 镜像变换
points2 = POINT3DLIST()
points2.push_back(Point3D(10, 10, 0))
points2.push_back(Point3D(30, 10, 0))
points2.push_back(Point3D(30, 30, 0))

baseP0 = Point3D(0, 0, 0)  # 镜像轴起点
baseP1 = Point3D(1, 0, 0)  # 镜像轴终点（X轴）
ssMath.mirror3DList(baseP0, baseP1, points2)
print("镜像后的点集:")
for i in range(points2.size()):
    pt = points2.at(i)
    print(f"  点{i+1}: ({pt.x():.2f}, {pt.y():.2f}, {pt.z():.2f})")
```

Sources: [PySSMath.py](PySSMath.py#L2819-L2840)

## 坐标转换应用场景

### 测绘坐标转换

```python
import sunvpy.PySSMath as ssMath

# 场景1：测量角度转换
# 将测量得到的度分秒格式转换为十进制度数
dms_angle = 30.3045  # 30°30'45" 表示为 30.3045
deg_angle = ssMath.dmsToDeg(dms_angle)
rad_angle = ssMath.degToRadian(deg_angle)
print(f"测量角度 {dms_angle:.4f} (DMS) = {deg_angle:.6f}° = {rad_angle:.6f} rad")

# 场景2：方位角归一化
# 确保方位角在 [0, 2π) 范围内
azimuth = 450.0  # 超出范围的方位角
normalized_deg = ssMath.adjustDegAngle(azimuth)
normalized_rad = ssMath.degToRadian(normalized_deg)
print(f"归一化方位角: {azimuth}° -> {normalized_deg:.2f}° = {normalized_rad:.6f} rad")

# 场景3：极坐标测量转直角坐标
# 从测站向东偏北45°方向测量距离100米
dist = 100.0
azimuth_from_north = ssMath.degToRadian(45)  # 从北方向向东
# 注意：测量通常以北方为0°，顺时针为正
# PySSMath的bearing函数可能以东方为0°，需要根据实际情况调整
```

### GIS 坐标变换

```python
import sunvpy.PySSMath as ssMath
import sunvpy.PySSMath.POINT3DLIST as POINT3DLIST
import sunvpy.PySSMath.Point3D as Point3D

# 场景1：地图旋转校正
# 将倾斜的地图元素旋转到标准方向
polygon = POINT3DLIST()
polygon.push_back(Point3D(100, 100, 0))
polygon.push_back(Point3D(110, 95, 0))
polygon.push_back(Point3D(105, 105, 0))

# 计算需要旋转的角度
angle_correction = ssMath.degToRadian(5)  # 逆时针旋转5度
rotation_center = Point3D(100, 100, 0)
ssMath.rotate2DList(polygon, angle_correction, rotation_center)

# 场景2：坐标系平移
# 将局部坐标系下的坐标转换到全局坐标系
offset_x = 500000.0  # 全局坐标系X偏移量
offset_y = 3000000.0  # 全局坐标系Y偏移量
ssMath.offset2DList(polygon, offset_x, offset_y)

# 场景3：比例尺变换
# 应用地图比例尺变换
scale_factor = 1000.0  # 1:1000比例尺
zoom_center = Point3D(500000, 3000000, 0)
ssMath.zoom3DList(polygon, scale_factor, scale_factor, scale_factor, zoom_center)
```

### 工程应用变换

```python
import sunvpy.PySSMath as ssMath
import sunvpy.PySSMath.POINT3DLIST as POINT3DLIST
import sunvpy.PySSMath.Point3D as Point3D

# 场景：基于控制点的坐标映射
# 已知旧坐标系和新坐标系中的控制点对
control_points_old = POINT3DLIST()
control_points_old.push_back(Point3D(0, 0, 0))
control_points_old.push_back(Point3D(100, 0, 0))
control_points_old.push_back(Point3D(0, 100, 0))

control_points_new = POINT3DLIST()
control_points_new.push_back(Point3D(500000, 3000000, 0))
control_points_new.push_back(Point3D(500100, 3000000, 0))
control_points_new.push_back(Point3D(500000, 3000100, 0))

# 待变换的点集
points_to_transform = POINT3DLIST()
points_to_transform.push_back(Point3D(50, 50, 0))
points_to_transform.push_back(Point3D(75, 25, 0))

# 执行映射变换
ssMath.mapping3DList(points_to_transform, control_points_old, control_points_new)

print("变换后的点:")
for i in range(points_to_transform.size()):
    pt = points_to_transform.at(i)
    print(f"  点{i+1}: ({pt.x():.2f}, {pt.y():.2f}, {pt.z():.2f})")
```

Sources: [PySSMath.py](PySSMath.py#L2700-L2900)

## 最佳实践与注意事项

### 角度单位处理

在进行角度计算时，务必注意角度单位的统一性。PySSMath 的函数默认使用弧度制进行内部计算，但提供了多种角度格式的转换函数。

```python
import sunvpy.PySSMath as ssMath

# 推荐：在计算开始时统一转换为弧度制
def calculate_with_angles(deg_angle):
    rad_angle = ssMath.degToRadian(deg_angle)
    # 执行计算
    result = rad_angle * 2  # 示例计算
    # 将结果转换回需要的格式
    return ssMath.radianToDeg(result)
```

### 坐标变换顺序

多个几何变换的执行顺序会影响最终结果。通常建议的顺序为：平移 → 旋转 → 缩放。

```python
import sunvpy.PySSMath as ssMath
import sunvpy.PySSMath.POINT3DLIST as POINT3DLIST
import sunvpy.PySSMath.Point3D as Point3D

points = POINT3DLIST()
# ... 添加点 ...

# 推荐的变换顺序
ssMath.offset3DList(points, dx, dy, dz)    # 1. 先平移
ssMath.rotate3DList(points, angle, axis)    # 2. 再旋转
ssMath.zoom3DList(points, sx, sy, sz, center)  # 3. 最后缩放
```

### 精度控制

在比较坐标和角度时，使用容差而非精确相等。

```python
import sunvpy.PySSMath as ssMath
import sunvpy.PySSMath.Point3D as Point3D

p1 = Point3D(100.0, 100.0, 0.0)
p2 = Point3D(100.0001, 100.0001, 0.0)

# 使用带容差的比较
epsilon = 0.001
is_same = ssMath.isSamePoint(p1, p2, epsilon)
```

## 相关页面

- [数学计算工具](43-shu-xue-ji-suan-gong-ju) - 了解更多数学计算相关的 API
- [地理对象类型定义](42-di-li-dui-xiang-lei-xing-ding-yi) - 了解 Point3D 等基础数据结构
- [库概述](1-ku-gai-shu) - 了解 sunvpy 模块的整体架构