Metadata-Version: 2.1
Name: alcesium-terrain-maker
Version: 0.1.0
Summary: High-performance GeoTIFF to Cesium quantized-mesh terrain tile generator
Requires-Python: >=3.11
Requires-Dist: numpy>=1.26
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: numpy>=1.26; extra == "dev"
Description-Content-Type: text/markdown

# alcesium-terrain-maker

High-performance **GeoTIFF → Cesium quantized-mesh-1.0** terrain tile generator.

Python API + Cython/AVX512 native core（默认开启 AVX512，需 CPU 支持）。GDAL is required at runtime (not bundled in the wheel).

## Requirements

- Python >= 3.11
- CMake >= 3.22, C++17 compiler, Ninja
- **GDAL >= 3.4** with Python bindings (`osgeo`)
- NumPy (build + runtime for tests)

### Installing GDAL

**Conda (recommended on Windows):**

```bash
conda install -c conda-forge gdal
```

**Linux:**

```bash
sudo apt install gdal-bin libgdal-dev python3-gdal
```

## Build & Install

```bash
# 安装到当前环境（开发）
uv sync --extra dev
uv pip install -e ".[dev]"

# 打一个 wheel（当前 Python 版本）→ dist/
uv build --wheel --out-dir dist

# Windows：注入 MSVC 后构建（推荐）
.\scripts\build_wheel.ps1

# 全量：Windows 3.11–3.14 + Linux manylinux（需 Docker）
.\scripts\build_local_wheels.ps1

# 上传 PyPI
.\scripts\upload_wheels.ps1
```

详见 [scripts/README.md](scripts/README.md)。

默认 wheel **开启 AVX512**（性能优先）。在不支持 AVX512 的老 CPU 上需关闭后重编：

```bash
uv build --wheel -Ccmake.define.ATM_USE_AVX512=OFF
# 或仅 AVX2：
uv build --wheel -Ccmake.define.ATM_USE_AVX512=OFF -Ccmake.define.ATM_USE_AVX2=ON
# 或完全可移植（无 SIMD 指令集要求）：
uv build --wheel -Ccmake.define.ATM_USE_AVX512=OFF -Ccmake.define.ATM_USE_AVX2=OFF
```

PowerShell 脚本可加 `-Portable`：`.\scripts\build_wheel.ps1 -Portable`

## Python API

```python
from pathlib import Path
from alcesium_terrain_maker import TerrainBuilder, TerrainConfig

config = TerrainConfig(
    profile="geodetic",       # or "mercator"
    overlap_mode="MEAN",      # LAST | FIRST | MEAN | MIN | MAX
    buffer_m=500.0,
    buffer_mode="FADE",       # EXTEND | FADE
    max_zoom=14,
    thread_count=16,
)

builder = TerrainBuilder(config)
result = builder.build(
    inputs=[Path("dem_a.tif"), Path("dem_b.tif")],
    output_dir=Path("terrain_out"),
)

print(result.tiles_written, result.layer_json_path)
```

### Multi-GeoTIFF overlap

Each source is sampled independently per tile. Overlap pixels are merged using `overlap_mode`:

| Mode | Behavior |
|------|----------|
| `LAST` | Later inputs overwrite earlier |
| `FIRST` | Earlier values kept where present |
| `MEAN` | Average of valid values |
| `MIN` / `MAX` | Minimum / maximum elevation |

### Boundary buffer

`buffer_m` extends each source outward. Applied per-source during tile sampling (not by merging rasters):

- **EXTEND**: outer ring height copied from nearest valid edge pixel
- **FADE**: linear decay toward 0; pixels originally below 0 stay frozen in the buffer zone

## Output layout

```
terrain_out/
├── layer.json
└── {z}/{x}/{y}.terrain   # gzip-compressed quantized-mesh-1.0
```

## Load in CesiumJS

```javascript
const viewer = new Cesium.Viewer("cesiumContainer", {
  terrainProvider: await Cesium.CesiumTerrainProvider.fromUrl("./terrain_out/"),
});
```

## Project layout

```
src/alcesium_terrain_maker/   # Python + Cython sources
extern/zlib/                  # zlib (FetchContent at build time)
extern/mesh_simplify/         # Chunked LOD grid simplification (C++)
```

## Tests

```bash
pytest tests/
```

## Performance tips

- Use COG / tiled GeoTIFF (`gdal_translate -co TILED=YES -co BLOCKXSIZE=65`)
- Set `thread_count` to CPU core count
- Input elevation should be ellipsoidal heights in meters (WGS84)
