# Feature: Tile Coordinate Operations

## Description
Handles all tile coordinate calculations including GPS-to-tile conversion, tile grid computation, and grid expansion for progressive search. Delegates core Web Mercator projection math to H06 Web Mercator Utils to maintain single source of truth.

## Component APIs Implemented
- `compute_tile_coords(lat: float, lon: float, zoom: int) -> TileCoords`
- `compute_tile_bounds(tile_coords: TileCoords) -> TileBounds`
- `get_tile_grid(center: TileCoords, grid_size: int) -> List[TileCoords]`
- `expand_search_grid(center: TileCoords, current_size: int, new_size: int) -> List[TileCoords]`

## External Tools and Services
None (pure computation, delegates to H06)

## Internal Dependencies
- **H06 Web Mercator Utils**: Core projection calculations
  - `H06.latlon_to_tile()` for coordinate conversion
  - `H06.compute_tile_bounds()` for bounding box calculation

## Internal Methods
- `_compute_grid_offset(grid_size: int) -> int`: Calculates offset from center for symmetric grid (e.g., 3×3 → offset 1)
- `_grid_size_to_dimensions(grid_size: int) -> Tuple[int, int]`: Maps grid_size (1,4,9,16,25) to (rows, cols)
- `_generate_grid_tiles(center: TileCoords, rows: int, cols: int) -> List[TileCoords]`: Generates all tile coords in grid

## Unit Tests
1. **compute_tile_coords_ukraine**: Ukraine GPS coords at zoom 19 → valid tile coords
2. **compute_tile_coords_origin**: lat=0, lon=0 → correct center tile
3. **compute_tile_coords_edge_cases**: lat=90, lon=180, lon=-180 → handled correctly
4. **compute_tile_bounds_zoom19**: Zoom 19 tile → GSD ≈ 0.3 m/pixel
5. **compute_tile_bounds_corners**: Returns valid GPS for all 4 corners
6. **get_tile_grid_1**: grid_size=1 → returns [center]
7. **get_tile_grid_4**: grid_size=4 → returns 4 tiles (2×2)
8. **get_tile_grid_9**: grid_size=9 → returns 9 tiles (3×3) centered
9. **get_tile_grid_25**: grid_size=25 → returns 25 tiles (5×5)
10. **expand_search_grid_1_to_4**: Returns 3 new tiles only
11. **expand_search_grid_4_to_9**: Returns 5 new tiles only
12. **expand_search_grid_9_to_16**: Returns 7 new tiles only
13. **expand_search_grid_no_duplicates**: Expanded tiles not in original set

## Integration Tests
1. **h06_delegation_verify**: compute_tile_coords() result matches direct H06.latlon_to_tile()
2. **grid_bounds_coverage**: get_tile_grid(9) → all 9 tile bounds form contiguous area
3. **expand_completes_grid**: get_tile_grid(4) + expand_search_grid(4,9) == get_tile_grid(9)

