127 lines
3.9 KiB
Markdown
127 lines
3.9 KiB
Markdown
# CLAUDE.md
|
||
|
||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||
|
||
## Project Overview
|
||
|
||
This is a collection of FastAPI-based tile servers that use rio-tiler to serve COG (Cloud Optimized GeoTIFF) files as dynamic map tiles. The project serves imagery from different planetary bodies:
|
||
|
||
- **app.py** - NJ 2020 aerial imagery (I7D16.tif) - UInt16 data with per-band rescaling
|
||
- **app_world.py** - Natural Earth global basemap (HYP_HR_SR_OB_DR_cog.tif) - uint8 RGB
|
||
- **app_mars.py** - Mars MGS MOLA global basemap - Uses custom Mars CRS in equidistant cylindrical projection
|
||
|
||
## Running the Servers
|
||
|
||
Each app is an independent FastAPI application. Run with uvicorn:
|
||
|
||
```bash
|
||
# Run NJ imagery server (default port 8000)
|
||
uvicorn app:app --reload
|
||
|
||
# Run world basemap server
|
||
uvicorn app_world:app --port 8001 --reload
|
||
|
||
# Run Mars basemap server
|
||
uvicorn app_mars:app --port 8002 --reload
|
||
```
|
||
|
||
## Architecture
|
||
|
||
### Common Pattern (app.py, app_world.py)
|
||
|
||
All apps follow the same pattern using `rio_tiler.io.Reader`:
|
||
|
||
1. **Tile endpoint** (`/tiles/{z}/{x}/{y}.png`) - Reads COG tiles and returns PNG
|
||
2. **TileJSON endpoint** (`/tilejson.json`) - Returns TileJSON 2.2.0 metadata
|
||
3. **Optional viewer** (`/`) - app.py includes a Leaflet.js viewer
|
||
|
||
Key rio-tiler concepts:
|
||
- `Reader(DATA_PATH)` context manager for reading COGs
|
||
- `cog.tile(x, y, z)` to extract tiles
|
||
- `img.render()` with `img_profiles` for output formatting
|
||
- `cog.get_geographic_bounds()` for bounds in geographic CRS
|
||
- `cog.minzoom`/`cog.maxzoom` for zoom levels
|
||
|
||
### Mars CRS (app_mars.py)
|
||
|
||
The Mars server uses a **custom TileMatrixSet** to handle Mars-specific coordinate system:
|
||
|
||
- **CRS**: Simple Cylindrical Mars (equidistant cylindrical, meters)
|
||
- **Sphere radius**: 3,396,190 m (vs Earth's ~6,378,137 m)
|
||
- **Extent**: ±πR in x, ±πR/2 in y (calculated from Mars radius)
|
||
- **matrix_scale=[2, 1]**: 2×1 tiles at zoom 0, matching Cesium's GeographicTilingScheme
|
||
|
||
**Critical design decision**: TMS and TIF both use the same Mars CRS (eqc meters). Avoid using longlat (degrees) because PROJ would attempt datum transformation through WGS84, causing "PROJ: eqc: Invalid latitude" errors due to the large sphere radius difference.
|
||
|
||
```python
|
||
MARS_CRS = CRS.from_proj4(
|
||
"+proj=eqc +lat_ts=0 +lat_0=0 +lon_0=0 +x_0=0 +y_0=0 +a=3396190 +b=3396190 +units=m +no_defs"
|
||
)
|
||
|
||
MARS_TMS = TileMatrixSet.custom(
|
||
crs=MARS_CRS,
|
||
extent=(-_MAX_X, -_MAX_Y, _MAX_X, _MAX_Y),
|
||
matrix_scale=[2, 1],
|
||
)
|
||
```
|
||
|
||
Pass custom TMS to Reader: `Reader(DATA_PATH, tms=MARS_TMS)`
|
||
|
||
## Data Handling
|
||
|
||
### Rescaling (app.py)
|
||
|
||
For UInt16 imagery, use per-band rescaling based on p2/p98 statistics:
|
||
|
||
```python
|
||
RESCALE = [
|
||
(6130, 40453), # Red
|
||
(10641, 41211), # Green
|
||
(12482, 36323), # Blue
|
||
]
|
||
|
||
img.render(img_format="PNG", rescale=RESCALE, **img_profiles.get("png", {}))
|
||
```
|
||
|
||
### uint8 Data (app_world.py, app_mars.py)
|
||
|
||
No rescaling needed for pre-scaled uint8 imagery:
|
||
|
||
```python
|
||
img.render(img_format="PNG", **img_profiles.get("png", {}))
|
||
```
|
||
|
||
## Dependencies
|
||
|
||
Managed via uv with `pyproject.toml`:
|
||
- fastapi - Web framework
|
||
- rio-tiler - COG tiling engine
|
||
- rasterio - GeoTIFF I/O
|
||
- uvicorn - ASGI server
|
||
- pyproj, morecantile - CRS and TMS handling (for Mars app)
|
||
|
||
## Adding New Tile Servers
|
||
|
||
To add a new COG tile server:
|
||
|
||
1. Copy the appropriate template (app.py for UInt16, app_world.py/app_mars.py for uint8)
|
||
2. Update `DATA_PATH` to point to your COG file in `data/`
|
||
3. For non-Earth data, create a custom CRS/TMS following app_mars.py pattern
|
||
4. Adjust rescaling if needed for UInt16 data
|
||
5. Update app metadata (title, description)
|
||
6. Run with uvicorn on a unique port
|
||
|
||
## File Structure
|
||
|
||
```
|
||
data/ # COG files (gitignored)
|
||
├── I7D16.tif
|
||
├── HYP_HR_SR_OB_DR_cog.tif
|
||
└── Mars_MGS_MOLA_...tif
|
||
|
||
app.py # NJ imagery server
|
||
app_world.py # World basemap server
|
||
app_mars.py # Mars basemap server
|
||
pyproject.toml # uv dependencies
|
||
```
|