"""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, }, }