Metadata-Version: 2.4
Name: horn_dem
Version: 1.0.5
Summary: 用 Horn 算法计算 DEM 坡度与坡向(可分别计算其一, 支持基线跨步与区域裁切)
Author-email: ghx <guohengxi.dennis@gmail.com>
License: MIT
Project-URL: Homepage, https://github.com/DennisGuo/horn_dem
Project-URL: Repository, https://github.com/DennisGuo/horn_dem
Project-URL: Issues, https://github.com/DennisGuo/horn_dem/issues
Keywords: DEM,slope,aspect,Horn,GIS,raster,terrain,geo
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Topic :: Scientific/Engineering :: GIS
Classifier: Intended Audience :: Science/Research
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: rasterio>=1.3
Requires-Dist: numpy>=1.24
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: build; extra == "dev"
Requires-Dist: twine; extra == "dev"
Dynamic: license-file

# horn_dem

用 **Horn 算法**计算 DEM（数字高程模型）的**坡度**、**坡向**与**粗糙度**，输出为 GeoTIFF。三种产物**各自独立计算**，支持**基线跨步**与**区域裁切**。

> 术语与决策见 [CONTEXT.md](CONTEXT.md) 与 [docs/adr/](docs/adr/)。

## 约定

| 项 | 约定 |
|---|---|
| 基线 baseline | 3×3 窗口的跨步，单位为**原生像素数**；`baseline=N` → 邻域取中心 ±N 像素，`cellsize = N × 像素分辨率`（默认 1） |
| 坡度 | 度，0–90° |
| 坡向 | 栅格相对方位角，0–360°，0°=+Y/上方（北）、顺时针，**平坦记 -1** |
| 粗糙度 | 3×3 跨步窗口内高程 **max−min**（米，≥0），对齐 GDAL `gdaldem roughness` |
| NoData | 窗口内任一无效（含中心）或凑不齐 3×3 → 输出 NoData（严格传播）；输入/输出统一 `-9999` |
| region | 可选；GeoJSON `Polygon`/`MultiPolygon`，坐标须为**与 DEM 同 CRS**（不重投影），裁切窗口（外扩 baseline）并按精确多边形掩膜 |

> **约定**：坡向以栅格 +Y 轴（上方）为 0° 基准；该方向是否等于地理正北取决于 DEM 的投影 CRS。

## 安装

```bash
python3 -m venv .venv
.venv/bin/pip install -e ".[dev]"
```

## 命令行

```bash
.venv/bin/python -m horn_dem {slope|aspect|roughness} <输入DEM.tif> -o <输出.tif> [选项]

子命令:
  slope      计算坡度（度，0–90）
  aspect     计算坡向（度，0–360，平坦=-1）
  roughness  计算粗糙度（3×3 窗口 max−min，米）

选项:
  -o, --out PATH      输出 GeoTIFF 文件路径（必填）
  -b, --baseline N    3×3 跨步/像元尺寸，原生像素数（默认 1）
  --region GEOJSON    计算区域：GeoJSON 文件路径或内联 JSON 字符串（坐标与 DEM 同 CRS，不重投影）；省略则计算整图
  --no-compress       不压缩输出（默认 DEFLATE + PREDICTOR=3）
```

每次只算一种产物，输出单个 GeoTIFF（Float32，保留输入 CRS / 地理变换 / 范围，输出 NoData=-9999）。

### 示例

```bash
# 坡度
.venv/bin/python -m horn_dem slope /path/to/DEM.tif -o out_slope.tif --baseline 1

# 坡向
.venv/bin/python -m horn_dem aspect /path/to/DEM.tif -o out_aspect.tif

# 某区域的粗糙度
.venv/bin/python -m horn_dem roughness /path/to/DEM.tif -o out_roughness.tif --region region.geojson
```

## 作为库调用

```python
import horn_dem

# 三种产物各自独立计算，写到指定文件路径，返回该 Path
slope_path     = horn_dem.compute_slope("DEM.tif", "out_slope.tif")
aspect_path    = horn_dem.compute_aspect("DEM.tif", "out_aspect.tif")
roughness_path = horn_dem.compute_roughness(
    "DEM.tif", "out_roughness.tif",
    region={"type": "Polygon", "coordinates": [[...]]},
)

# 公开 API 仅此三个函数（+ NODATA 常量）；底层算法不从顶层导出。
# baseline / region / compress 关键字参数三者一致：
#   horn_dem.compute_slope("DEM.tif", "out.tif", baseline=2, region=..., compress=False)
```

## 测试

```bash
.venv/bin/python -m pytest tests/ -v
```

## 实现要点

- **rasterio + numpy 手写 Horn**：对自定义 baseline 跨步最忠实（详见 [ADR-0001](docs/adr/0001-slope-aspect-via-rasterio-numpy.md)）。
- **三种独立产物**：`compute_slope` / `compute_aspect` / `compute_roughness`，各只读一次 DEM、只派生所需产物；底层梯度/极值函数为内部实现，不从顶层导出（详见 [ADR-0003](docs/adr/0003-single-product-functions.md)）。
- **粗糙度**：3×3 跨步窗口高程 `max−min`，对齐 GDAL `gdaldem roughness`，与坡度/坡向共享 baseline/region/NoData 约定。
- **NoData 用 `np.nan` 自然传播**：3×3 邻域任一为 nan 即结果 nan，边缘凑不齐亦为 nan。
- **region**：坐标须与 DEM 同 CRS（不重投影）→ 求外接像素窗口（外扩 baseline 保证边缘 3×3）→ 计算 → 裁回真实窗口 → 精确多边形掩膜（详见 [ADR-0004](docs/adr/0004-region-uses-dem-crs-no-reproject.md)）。
- **校验**：坡度与 `gdaldem slope`（同 Horn）逐位吻合；坡向与 `gdaldem aspect` 同约定、环形差近 0；粗糙度与 `gdaldem roughness` 同定义。
