--- name: cesium-expert description: CesiumJS 3D 지도 전문가. "지도", "Cesium", "3D 맵", "GIS" 관련 질문 시 사용. allowed-tools: Read, Write, Glob, Grep, mcp__plugin_context7_context7__resolve-library-id, mcp__plugin_context7_context7__query-docs --- # Cesium 전문가 $ARGUMENTS CesiumJS 관련 질문에 답변하고 구현을 도와드립니다. --- ## @pf-dev/map 패키지 구조 ``` packages/map/src/ ├── components/ │ ├── MapViewer.tsx # 메인 뷰어 컴포넌트 │ ├── Imagery.tsx # 이미지 레이어 │ ├── Terrain.tsx # 지형 │ └── Tiles3D.tsx # 3D 타일셋 ├── stores/ │ ├── useMapStore.ts # 지도 상태 │ ├── useCameraStore.ts # 카메라 상태 │ └── useFeatureStore.ts # Feature 관리 ├── hooks/ │ └── useCamera.ts # 카메라 제어 └── types/ └── index.ts ``` --- ## 주요 패턴 ### MapViewer 사용 ```tsx import { MapViewer, Imagery, Terrain } from "@pf-dev/map"; function Map() { return ( ); } ``` ### 카메라 제어 ```tsx import { useCameraStore } from "@pf-dev/map"; function Controls() { const { flyTo, lookAt, zoomTo } = useCameraStore(); const handleFlyToSeoul = () => { flyTo({ destination: Cesium.Cartesian3.fromDegrees(126.978, 37.5665, 10000), duration: 2, }); }; return ; } ``` ### Feature 관리 ```tsx import { useFeatureStore } from "@pf-dev/map"; function FeatureManager() { const { addEntity, removeEntity, findByProperty } = useFeatureStore(); const addMarker = (position: Cesium.Cartesian3) => { addEntity({ id: `marker-${Date.now()}`, position, billboard: { image: "/marker.png", scale: 1, }, properties: { type: "cctv", name: "CCTV 1", }, }); }; const findCCTVs = () => { return findByProperty("type", "cctv"); }; } ``` --- ## 자주 묻는 질문 ### Q: 성능이 느려요 **A: 최적화 방법** 1. `requestRenderMode: true` 설정 (필요할 때만 렌더) 2. 3D 타일셋 LOD 설정 3. 엔티티 수 제한 (1000개 이상이면 Primitive 사용) 4. `show: false`로 숨긴 엔티티 정리 ```tsx ``` ### Q: 이미지 레이어 안 보여요 **A: 토큰 확인** ```env VITE_ION_CESIUM_ACCESS_TOKEN=your-token VITE_VWORLD_API_KEY=your-key ``` ### Q: 카메라가 지하로 들어가요 **A: 지형 충돌 설정** ```tsx viewer.scene.globe.depthTestAgainstTerrain = true; viewer.scene.screenSpaceCameraController.enableCollisionDetection = true; ``` ### Q: 클릭 이벤트 처리 ```tsx import { useMapStore } from "@pf-dev/map"; function ClickHandler() { const viewer = useMapStore((state) => state.viewer); useEffect(() => { if (!viewer) return; const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas); handler.setInputAction((click: { position: Cesium.Cartesian2 }) => { const picked = viewer.scene.pick(click.position); if (Cesium.defined(picked)) { console.log("Picked:", picked.id); } }, Cesium.ScreenSpaceEventType.LEFT_CLICK); return () => handler.destroy(); }, [viewer]); } ``` --- ## 좌표 변환 ```tsx // 위경도 → Cartesian3 const position = Cesium.Cartesian3.fromDegrees(126.978, 37.5665, 100); // Cartesian3 → 위경도 const cartographic = Cesium.Cartographic.fromCartesian(position); const lng = Cesium.Math.toDegrees(cartographic.longitude); const lat = Cesium.Math.toDegrees(cartographic.latitude); const height = cartographic.height; // 화면 좌표 → Cartesian3 const cartesian = viewer.camera.pickEllipsoid(screenPosition, viewer.scene.globe.ellipsoid); ``` --- ## 3D 타일셋 로딩 ```tsx import { Tiles3D } from "@pf-dev/map"; { viewer.zoomTo(tileset); }} style={{ color: { conditions: [ ["${height} > 100", "color('red')"], ["true", "color('white')"], ], }, }} />; ``` --- ## Context7 참고 CesiumJS 최신 API가 필요하면 Context7로 조회하세요.