105 lines
3.6 KiB
Python
105 lines
3.6 KiB
Python
import os
|
|
|
|
from fastapi import APIRouter, HTTPException, Query
|
|
from fastapi.responses import FileResponse
|
|
from typing import Optional
|
|
|
|
from app.core.config import settings
|
|
from app.services.terrain_service import terrain_service
|
|
from app.services.los_service import los_service
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.get("/elevation")
|
|
async def get_elevation(
|
|
lat: float = Query(..., ge=-90, le=90, description="Latitude"),
|
|
lon: float = Query(..., ge=-180, le=180, description="Longitude")
|
|
):
|
|
"""Get elevation at a specific point"""
|
|
elevation = await terrain_service.get_elevation(lat, lon)
|
|
return {
|
|
"lat": lat,
|
|
"lon": lon,
|
|
"elevation": elevation,
|
|
"unit": "meters"
|
|
}
|
|
|
|
|
|
@router.get("/profile")
|
|
async def get_elevation_profile(
|
|
lat1: float = Query(..., description="Start latitude"),
|
|
lon1: float = Query(..., description="Start longitude"),
|
|
lat2: float = Query(..., description="End latitude"),
|
|
lon2: float = Query(..., description="End longitude"),
|
|
points: int = Query(100, ge=10, le=500, description="Number of sample points")
|
|
):
|
|
"""Get elevation profile between two points"""
|
|
profile = await terrain_service.get_elevation_profile(lat1, lon1, lat2, lon2, points)
|
|
|
|
return {
|
|
"start": {"lat": lat1, "lon": lon1},
|
|
"end": {"lat": lat2, "lon": lon2},
|
|
"num_points": len(profile),
|
|
"profile": profile
|
|
}
|
|
|
|
|
|
@router.get("/los")
|
|
async def check_line_of_sight(
|
|
tx_lat: float = Query(..., description="Transmitter latitude"),
|
|
tx_lon: float = Query(..., description="Transmitter longitude"),
|
|
tx_height: float = Query(..., ge=0, description="Transmitter height above ground (m)"),
|
|
rx_lat: float = Query(..., description="Receiver latitude"),
|
|
rx_lon: float = Query(..., description="Receiver longitude"),
|
|
rx_height: float = Query(1.5, ge=0, description="Receiver height above ground (m)")
|
|
):
|
|
"""Check line-of-sight between transmitter and receiver"""
|
|
result = await los_service.check_line_of_sight(
|
|
tx_lat, tx_lon, tx_height,
|
|
rx_lat, rx_lon, rx_height
|
|
)
|
|
return result
|
|
|
|
|
|
@router.get("/fresnel")
|
|
async def check_fresnel_clearance(
|
|
tx_lat: float = Query(..., description="Transmitter latitude"),
|
|
tx_lon: float = Query(..., description="Transmitter longitude"),
|
|
tx_height: float = Query(..., ge=0, description="Transmitter height (m)"),
|
|
rx_lat: float = Query(..., description="Receiver latitude"),
|
|
rx_lon: float = Query(..., description="Receiver longitude"),
|
|
rx_height: float = Query(1.5, ge=0, description="Receiver height (m)"),
|
|
frequency: float = Query(1800, ge=100, le=6000, description="Frequency (MHz)")
|
|
):
|
|
"""Calculate Fresnel zone clearance"""
|
|
try:
|
|
result = await los_service.calculate_fresnel_clearance(
|
|
tx_lat, tx_lon, tx_height,
|
|
rx_lat, rx_lon, rx_height,
|
|
frequency
|
|
)
|
|
return result
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=f"Fresnel calculation error: {str(e)}")
|
|
|
|
|
|
@router.get("/tiles")
|
|
async def list_cached_tiles():
|
|
"""List cached SRTM tiles"""
|
|
tiles = list(terrain_service.cache_dir.glob("*.hgt"))
|
|
return {
|
|
"cache_dir": str(terrain_service.cache_dir),
|
|
"tiles": [t.stem for t in tiles],
|
|
"count": len(tiles)
|
|
}
|
|
|
|
|
|
@router.get("/file/{region}")
|
|
async def get_terrain_file(region: str):
|
|
"""Serve raw SRTM terrain .hgt files (legacy compatibility)."""
|
|
terrain_path = os.path.join(settings.TERRAIN_DATA_DIR, f"{region}.hgt")
|
|
if os.path.exists(terrain_path):
|
|
return FileResponse(terrain_path)
|
|
raise HTTPException(status_code=404, detail=f"Region '{region}' not found")
|