new branch
This commit is contained in:
81
backend/app/api/v1/visualization.py
Normal file
81
backend/app/api/v1/visualization.py
Normal file
@@ -0,0 +1,81 @@
|
||||
"""Visualization API - GeoJSON endpoints for 3D Earth display"""
|
||||
|
||||
from fastapi import APIRouter, HTTPException
|
||||
import httpx
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
CABLE_DATA_URL = "https://services.arcgis.com/6DIQcwlPy8knb6sg/arcgis/rest/services/SubmarineCables/FeatureServer/2/query?where=1%3D1&outFields=*&returnGeometry=true&f=geojson"
|
||||
LANDING_POINT_CSV_URL = "https://data.apps.fao.org/catalog/dataset/1b75ff21-92f2-4b96-9b7b-98e8aa65ad5d/resource/b6071077-d1d4-4e97-aa00-42e902847c87/download/landing-point-geo.csv"
|
||||
|
||||
|
||||
@router.get("/geo/cables")
|
||||
async def get_cables_geojson():
|
||||
"""获取海底电缆 GeoJSON 数据 (LineString)"""
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=60.0) as client:
|
||||
response = await client.get(CABLE_DATA_URL)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
except httpx.HTTPError as e:
|
||||
raise HTTPException(status_code=502, detail=f"Failed to fetch cable data: {str(e)}")
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Internal error: {str(e)}")
|
||||
|
||||
|
||||
@router.get("/geo/landing-points")
|
||||
async def get_landing_points_geojson():
|
||||
"""获取登陆点 GeoJSON 数据 (Point)"""
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=60.0) as client:
|
||||
response = await client.get(LANDING_POINT_CSV_URL)
|
||||
response.raise_for_status()
|
||||
|
||||
lines = response.text.strip().split("\n")
|
||||
if not lines:
|
||||
raise HTTPException(status_code=500, detail="Empty CSV data")
|
||||
|
||||
features = []
|
||||
for line in lines[1:]:
|
||||
if not line.strip():
|
||||
continue
|
||||
parts = line.split(",")
|
||||
if len(parts) >= 4:
|
||||
try:
|
||||
lon = float(parts[0])
|
||||
lat = float(parts[1])
|
||||
feature_id = parts[2]
|
||||
name = parts[3].strip('"')
|
||||
is_tbd = parts[4].strip() == "true" if len(parts) > 4 else False
|
||||
|
||||
features.append(
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": {"type": "Point", "coordinates": [lon, lat]},
|
||||
"properties": {"id": feature_id, "name": name, "is_tbd": is_tbd},
|
||||
}
|
||||
)
|
||||
except (ValueError, IndexError):
|
||||
continue
|
||||
|
||||
return {"type": "FeatureCollection", "features": features}
|
||||
except httpx.HTTPError as e:
|
||||
raise HTTPException(status_code=502, detail=f"Failed to fetch landing point data: {str(e)}")
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=500, detail=f"Internal error: {str(e)}")
|
||||
|
||||
|
||||
@router.get("/geo/all")
|
||||
async def get_all_geojson():
|
||||
"""获取所有可视化数据 (电缆 + 登陆点)"""
|
||||
cables = await get_cables_geojson()
|
||||
points = await get_landing_points_geojson()
|
||||
|
||||
return {
|
||||
"cables": cables,
|
||||
"landing_points": points,
|
||||
"stats": {
|
||||
"cable_count": len(cables.get("features", [])) if cables else 0,
|
||||
"landing_point_count": len(points.get("features", [])) if points else 0,
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user