위성 정보를 3D 지구(Digital Globe)에 시각화
가장 추천하는 방식 3가지를 정리해 드립니다.
카테고리: uploads | 읽기시간: 10분 | 원문: 다운로드
위성 정보를 3D 지구(Digital Globe)에 시각화
가장 추천하는 방식 3가지를 정리해 드립니다.
1. CesiumJS (가장 추천하는 표준 방식)
웹 기반 3D 지구 시각화에서 업계 표준에 가깝습니다. 위성 궤도 시각화, 지형 렌더링, 시계열 데이터 처리에 특화되어 있습니다.
- 특징: 높은 성능의 3D 렌더링, 시간축(Timeline) 기반의 데이터 애니메이션 지원.
- 활용: 위성의 실시간 위치(TLE 데이터), 위성 이미지 오버레이, 센서 범위 시각화.
- 기술 스택: JavaScript / TypeScript.
- 장점: NASA 등 주요 우주 기관에서도 사용할 만큼 신뢰도가 높고 문서화가 잘 되어 있습니다.
2. NASA WebWorldWind
NASA에서 관리하는 오픈소스 가상 지구 SDK입니다. CesiumJS와 유사하지만, 좀 더 학술적이고 공공 데이터 연동에 친화적입니다.
- 특징: 다양한 지도 투영법(Projection) 지원, 고해상도 지형 데이터 처리.
- 활용: 기상 위성 데이터, 대기 오염 농도 등 대용량 래스터(Raster) 데이터 시각화.
- 기술 스택: JavaScript (Web), Java (Android), iOS.
3. Deck.gl + Mapbox/MapLibre
데이터 분석가나 데이터 사이언티스트들이 선호하는 방식입니다. Uber에서 만든 대용량 데이터 시각화 라이브러리인 Deck.gl을 사용합니다.
- 특징: 수만 개의 점(Point)이나 선(Arc) 데이터를 웹브라우저에서 끊김 없이 처리.
- 활용: 위성 간의 통신 경로(Arc Layer), 특정 지역의 위성 신호 강도 히트맵.
- 기술 스택: React, JavaScript.
💡 어떤 것을 선택해야 할까요?
| 목적 | 추천 도구 |
|---|---|
| 위성 궤도 및 이동 경로 시각화 | CesiumJS |
| 대규모 데이터 분석 및 히트맵 | Deck.gl |
| 모바일 앱(네이티브) 개발 | WebWorldWind |
구현 팁: 데이터 형식
위성 위치 정보를 다루신다면 보통 TLE(Two-Line Element) 형식을 사용하게 됩니다. 이를 위도/경도/고도로 변환하기 위해 satellite.js 같은 라이브러리를 함께 사용하시는 것을 권장합니다.
위성 정보를 3D 지구(Digital Globe)에 시각화하는 것은 데이터의 직관적인 이해를 돕는 아주 멋진 프로젝트가 될 것 같네요! 오픈소스 생태계에는 이 분야를 꽉 잡고 있는 강력한 도구들이 있습니다.
가장 추천하는 방식 3가지를 정리해 드립니다.
1. CesiumJS (가장 추천하는 표준 방식)
웹 기반 3D 지구 시각화에서 업계 표준에 가깝습니다. 위성 궤도 시각화, 지형 렌더링, 시계열 데이터 처리에 특화되어 있습니다.
- 특징: 높은 성능의 3D 렌더링, 시간축(Timeline) 기반의 데이터 애니메이션 지원.
- 활용: 위성의 실시간 위치(TLE 데이터), 위성 이미지 오버레이, 센서 범위 시각화.
- 기술 스택: JavaScript / TypeScript.
- 장점: NASA 등 주요 우주 기관에서도 사용할 만큼 신뢰도가 높고 문서화가 잘 되어 있습니다.
2. NASA WebWorldWind
NASA에서 관리하는 오픈소스 가상 지구 SDK입니다. CesiumJS와 유사하지만, 좀 더 학술적이고 공공 데이터 연동에 친화적입니다.
- 특징: 다양한 지도 투영법(Projection) 지원, 고해상도 지형 데이터 처리.
- 활용: 기상 위성 데이터, 대기 오염 농도 등 대용량 래스터(Raster) 데이터 시각화.
- 기술 스택: JavaScript (Web), Java (Android), iOS.
3. Deck.gl + Mapbox/MapLibre
데이터 분석가나 데이터 사이언티스트들이 선호하는 방식입니다. Uber에서 만든 대용량 데이터 시각화 라이브러리인 Deck.gl을 사용합니다.
- 특징: 수만 개의 점(Point)이나 선(Arc) 데이터를 웹브라우저에서 끊김 없이 처리.
- 활용: 위성 간의 통신 경로(Arc Layer), 특정 지역의 위성 신호 강도 히트맵.
- 기술 스택: React, JavaScript.
💡 어떤 것을 선택해야 할까요?
| 목적 | 추천 도구 |
|---|---|
| 위성 궤도 및 이동 경로 시각화 | CesiumJS |
| 대규모 데이터 분석 및 히트맵 | Deck.gl |
| 모바일 앱(네이티브) 개발 | WebWorldWind |
구현 팁: 데이터 형식
위성 위치 정보를 다루신다면 보통 TLE(Two-Line Element) 형식을 사용하게 됩니다. 이를 위도/경도/고도로 변환하기 위해 satellite.js 같은 라이브러리를 함께 사용하시는 것을 권장합니다.
--
추천해 드린 세 가지 오픈소스 라이브러리의 실제 구현 예시 이미지들을 찾아보았습니다. 각 도구가 위성 데이터를 어떤 느낌으로 표현하는지 확인해 보세요.
1. CesiumJS: 정밀한 위성 궤도 시각화
가장 전문적인 느낌을 주며, 실제 위성의 고도와 궤적(Orbit)을 3D 공간상에 매우 정확하게 투영합니다. 시간 흐름에 따른 위성의 움직임을 부드럽게 보여주는 것이 강점입니다.
https://cesium.com/industries/aerospace/
2. NASA WebWorldWind: 학술적 데이터 시각화
NASA에서 제공하는 만큼 지형 데이터나 대기 데이터(Heatmap)를 지구본 위에 겹쳐서(Overlay) 보여주는 데 강점이 있습니다. 분석용 대시보드 형태의 프로젝트에 자주 활용됩니다.
https://worldwind.arc.nasa.gov/spacebirds/index.html
3. Deck.gl: 대용량 데이터 및 연결 시각화
수많은 위성 노드(Node)나 지상국과의 연결선(Arc)을 화려하고 현대적인 그래픽으로 표현하고 싶을 때 적합합니다. 웹 브라우저에서도 매우 빠르고 세련된 효과를 낼 수 있습니다.
https://codepen.io/AdriSolid/pen/RwoQeeR
--
세 가지 모두 오픈소스로 공개되어 있으며, 상업적 이용이 가능한 라이선스를 채택하고 있습니다. 각 프레임워크의 오픈소스 현황과 특징을 정리해 드릴게요.
1. CesiumJS
- 라이선스: Apache 2.0 (매우 관대한 라이선스, 상업적 이용 및 수정 가능)
- 저장소: GitHub - CesiumGS/cesium
- 특징: 2012년부터 꾸준히 관리되어 온 가장 성숙한 프로젝트입니다. 핵심 엔진인 CesiumJS 자체는 100% 무료 오픈소스이지만, 고해상도 지형(Terrain)이나 대용량 3D 타일 데이터 호스팅을 위해 Cesium ion이라는 유료 클라우드 서비스를 함께 제공하기도 합니다. (자체 서버 데이터 사용 시 비용 없음)
2. NASA WebWorldWind
- 라이선스: Apache 2.0 (과거 NOSA 라이선스에서 변경됨)
- 저장소: GitHub - NASAWorldWind/WebWorldWind
- 특징: NASA에서 직접 관리하는 프로젝트로, 완전한 오픈소스입니다. 다만, 최근 NASA의 공식적인 직접 지원(Active Maintenance)이 예전만큼 활발하지 않다는 점은 참고해야 합니다. 하지만 코드가 공개되어 있어 커뮤니티나 기업에서 직접 커스텀하여 사용하기에는 문제가 없습니다.
3. Deck.gl
- 라이선스: MIT (가장 가볍고 제약이 적은 라이선스)
- 저장소: GitHub - visgl/deck.gl
- 특징: Uber에서 시작하여 현재는 vis.gl 프레임워크 그룹(OpenJS Foundation 소속)에서 관리하는 프로젝트입니다. 최신 웹 기술(WebGL2, WebGPU)을 가장 적극적으로 활용하며, 다른 React 라이브러리들과 결합성이 매우 좋습니다.
📊 요약 및 추천
| 프레임워크 | 라이선스 | 관리 주체 | 추천 용도 |
|---|---|---|---|
| CesiumJS | Apache 2.0 | Cesium GS | 실시간 위성 궤도, 전문적인 3D GIS 구축 |
| WebWorldWind | Apache 2.0 | NASA | 학술용, 기상/해양 데이터 시각화 |
| Deck.gl | MIT | vis.gl (OpenJS) | 대시보드 내 데이터 인포그래픽, 고성능 렌더링 |
현재 가장 활발하게 쓰이고 커뮤니티 지원이 좋은 것은 CesiumJS와 Deck.gl입니다. 특히 위성의 물리적 궤적과 시간 흐름을 다루신다면 CesiumJS가 압도적인 편의성을 제공할 것입니다.
--
각 프레임워크의 특성에 맞춰 위성 위치(위도, 경도, 고도)를 3D 지구에 배치하는 가장 기초적인 스켈레톤(Skeleton) 코드입니다. 모든 예제는 별도의 빌드 도구 없이 HTML 파일 하나로 실행해 볼 수 있도록 CDN 방식을 사용했습니다.
1. CesiumJS: 위성 엔티티 배치 (Entity API)
Cesium은 위성을 'Entity'로 취급하며, 시간축에 따른 움직임을 구현하기 가장 좋습니다.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="utf-8" />
<script src="https://cesium.com/downloads/cesiumjs/releases/1.114/Build/Cesium/Cesium.js"></script>
<link
href="https://cesium.com/downloads/cesiumjs/releases/1.114/Build/Cesium/Widgets/widgets.css"
rel="stylesheet"
/>
</head>
<body>
<div id="cesiumContainer" style="width: 100%; height: 100vh;"></div>
<script>
// Cesium.Ion.defaultAccessToken = 'YOUR_ACCESS_TOKEN'; // 지형 데이터를 쓰려면 토큰 필요
const viewer = new Cesium.Viewer("cesiumContainer", {
terrainProvider: Cesium.createWorldTerrain(),
});
// 위성 엔티티 추가
const satellite = viewer.entities.add({
name: "K-Sattie-01",
position: Cesium.Cartesian3.fromDegrees(127.0, 37.5, 500000), // 경도, 위도, 고도(m)
point: { pixelSize: 10, color: Cesium.Color.RED },
label: {
text: "Satellite A",
font: "14pt monospace",
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
pixelOffset: new Cesium.Cartesian2(0, -9),
},
});
viewer.zoomTo(satellite);
</script>
</body>
</html>
2. NASA WebWorldWind: 레이어 기반 배치
WorldWind는 전통적인 GIS 레이어 방식을 따르며, RenderableLayer 위에 객체를 올립니다.
<!DOCTYPE html>
<html>
<head>
<script src="https://files.worldwind.arc.nasa.gov/artifactory/web/0.9.0/worldwind.min.js"></script>
</head>
<body>
<canvas id="canvasOne" style="width: 100%; height: 100vh;"></canvas>
<script>
const wwd = new WorldWind.WorldWindow("canvasOne");
// 기본 지도 레이어 추가
wwd.addLayer(new WorldWind.BMNGOneImageLayer());
wwd.addLayer(new WorldWind.CoordinatesDisplayLayer(wwd));
// 위성 표시 레이어 생성
const satelliteLayer = new WorldWind.RenderableLayer("Satellites");
wwd.addLayer(satelliteLayer);
// 위성 지점(Placemark) 설정
const position = new WorldWind.Position(37.5, 127.0, 500000); // 위도, 경도, 고도
const placemark = new WorldWind.Placemark(position, false, null);
placemark.label = "Satellite B";
const attributes = new WorldWind.PlacemarkAttributes(null);
attributes.imageSource =
"https://worldwind.arc.nasa.gov/web/examples/images/white-dot.png";
placemark.attributes = attributes;
satelliteLayer.addRenderable(placemark);
</script>
</body>
</html>
3. Deck.gl: 대용량 데이터 시각화 (ScenegraphLayer)
Deck.gl은 대량의 점 데이터를 GPU로 렌더링하는 데 최적화되어 있습니다. 아래는 위성을 구체(Point)로 표현하는 기본 구조입니다.
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/deck.gl@latest/dist.min.js"></script>
<script src="https://unpkg.com/maplibre-gl@latest/dist/maplibre-gl.js"></script>
<link
href="https://unpkg.com/maplibre-gl@latest/dist/maplibre-gl.css"
rel="stylesheet"
/>
</head>
<body style="margin: 0;">
<div id="container" style="width: 100vw; height: 100vh;"></div>
<script>
const { DeckGL, GeoJsonLayer, ScatterplotLayer } = deck;
new DeckGL({
container: "container",
initialViewState: {
longitude: 127.0,
latitude: 37.5,
zoom: 2,
pitch: 45,
},
controller: true,
layers: [
new ScatterplotLayer({
id: "satellite-layer",
data: [{ position: [127.0, 37.5, 5000], name: "Sat-C" }], // [경도, 위도, 고도]
getPosition: (d) => d.position,
getFillColor: [0, 255, 128],
getRadius: 100000,
pickable: true,
}),
],
views: new deck.GlobeView(), // 지구본 형태로 보기
});
</script>
</body>
</html>
💡 팁: 무엇부터 시작할까요?
- 정밀한 위성 관제 느낌을 원하시면 CesiumJS 코드를 먼저 돌려보시는 것을 강력히 추천합니다. 위성 궤도(Orbit)를 그리는
PathGraphics기능이 매우 강력하기 때문입니다. - 위 코드를
.html파일로 저장해서 브라우저로 열면 바로 작동을 확인할 수 있습니다.
3가지 프레임워크 모두에서 실제 위성 데이터를 다루는 핵심은 TLE (Two-Line Element) 데이터를 웹 브라우저가 이해할 수 있는 위도, 경도, 고도로 변환하는 것입니다.
이 변환을 위해 전용 자바스크립트 라이브러리인 **satellite.js**를 필수적으로 함께 사용해야 합니다.
각 프레임워크별로 TLE 데이터를 활용하여 실시간으로 위성 위치를 갱신하는 구현 스켈레톤을 소개합니다. 이 코드를 복사하여 .html로 저장하면 즉시 ISS(국제우주정거장)의 실시간 위치를 확인할 수 있습니다.
필수 공통 데이터: ISS의 TLE
모든 예제는 현재 시점의 ISS TLE 데이터를 사용합니다. (실제 서비스에서는 이 데이터를 백엔드 API에서 실시간으로 받아와야 합니다.)
// 국제우주정거장(ISS)의 TLE 데이터 (실시간 갱신 필요)
const tleLine1 =
"1 25544U 98067A 24089.15582236 .00015692 00000-0 27889-3 0 9999";
const tleLine2 =
"2 25544 51.6416 195.1432 0004558 102.7711 319.2483 15.49534708445775";
1. CesiumJS + satellite.js (가장 권장됨)
Cesium은 CallbackProperty를 이용해 매 프레임마다 위성의 위치를 계산하여 애니메이션처럼 보여주는 방식에 가장 최적화되어 있습니다.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="utf-8" />
<script src="https://cesium.com/downloads/cesiumjs/releases/1.114/Build/Cesium/Cesium.js"></script>
<link
href="https://cesium.com/downloads/cesiumjs/releases/1.114/Build/Cesium/Widgets/widgets.css"
rel="stylesheet"
/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/satellite.js/4.1.3/satellite.min.js"></script>
</head>
<body>
<div id="cesiumContainer" style="width: 100%; height: 100vh;"></div>
<script>
// Cesium.Ion.defaultAccessToken = 'YOUR_ACCESS_TOKEN';
const viewer = new Cesium.Viewer("cesiumContainer");
// ISS TLE
const tleLine1 =
"1 25544U 98067A 24089.15582236 .00015692 00000-0 27889-3 0 9999";
const tleLine2 =
"2 25544 51.6416 195.1432 0004558 102.7711 319.2483 15.49534708445775";
const satrec = satellite.twoline2satrec(tleLine1, tleLine2);
// [핵심] 실시간 위치 계산 함수
function getSatellitePosition(time) {
const date = Cesium.JulianDate.toDate(time);
const positionAndVelocity = satellite.propagate(satrec, date);
const gmst = satellite.gstime(date);
const positionGd = satellite.eciToGeodetic(
positionAndVelocity.position,
gmst,
);
// Cesium 전용 좌표계(Cartesian3)로 변환
return Cesium.Cartesian3.fromRadians(
positionGd.longitude,
positionGd.latitude,
positionGd.height * 1000, // satellite.js는 km, Cesium은 m 단위 사용
);
}
// 위성 엔티티 추가 (위치를 CallbackProperty로 지정)
const issEntity = viewer.entities.add({
id: "ISS",
name: "ISS (Real-time)",
position: new Cesium.CallbackProperty(getSatellitePosition, false), // 매 프레임마다 계산
point: { pixelSize: 15, color: Cesium.Color.RED },
label: {
text: "ISS",
font: "12pt sans-serif",
pixelOffset: new Cesium.Cartesian2(0, -15),
},
// 궤적 표현 추가
path: {
leadTime: 3600,
trailTime: 3600,
width: 2,
material: Cesium.Color.YELLOW,
},
});
// 위성으로 카메라 이동 및 추적
viewer.trackedEntity = issEntity;
</script>
</body>
</html>
2. NASA WebWorldWind + satellite.js
WorldWind는 setInterval을 이용해 주기적으로 placemark의 위치 속성을 직접 갱신하는 방식을 사용합니다.
<!DOCTYPE html>
<html>
<head>
<script src="https://files.worldwind.arc.nasa.gov/artifactory/web/0.9.0/worldwind.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/satellite.js/4.1.3/satellite.min.js"></script>
</head>
<body>
<canvas id="canvasOne" style="width: 100%; height: 100vh;"></canvas>
<script>
const wwd = new WorldWind.WorldWindow("canvasOne");
wwd.addLayer(new WorldWind.BMNGOneImageLayer());
const satelliteLayer = new WorldWind.RenderableLayer("ISS Layer");
wwd.addLayer(satelliteLayer);
// ISS TLE & 초기화
const tleLine1 =
"1 25544U 98067A 24089.15582236 .00015692 00000-0 27889-3 0 9999";
const tleLine2 =
"2 25544 51.6416 195.1432 0004558 102.7711 319.2483 15.49534708445775";
const satrec = satellite.twoline2satrec(tleLine1, tleLine2);
// Placemark 생성 (초기 위치 임시 설정)
const placemark = new WorldWind.Placemark(
new WorldWind.Position(0, 0, 0),
);
placemark.label = "ISS";
const attributes = new WorldWind.PlacemarkAttributes(null);
attributes.imageSource =
"https://worldwind.arc.nasa.gov/web/examples/images/white-dot.png";
attributes.imageScale = 1.5;
placemark.attributes = attributes;
satelliteLayer.addRenderable(placemark);
// [핵심] 1초마다 위치를 계산하여 업데이트
setInterval(function () {
const now = new Date();
const positionAndVelocity = satellite.propagate(satrec, now);
const gmst = satellite.gstime(now);
const positionGd = satellite.eciToGeodetic(
positionAndVelocity.position,
gmst,
);
// WorldWind 좌표계(Position) 갱신
placemark.position = new WorldWind.Position(
satellite.degreesLat(positionGd.latitude), // 라디안 -> 도(degree) 변환
satellite.degreesLong(positionGd.longitude),
positionGd.height * 1000, // m 단위
);
wwd.redraw(); // 화면 재생성
}, 1000);
</script>
</body>
</html>
3. Deck.gl + satellite.js
Deck.gl은 상태(State) 기반으로 작동하므로, 자바스크립트의 requestAnimationFrame을 이용해 주기적으로 데이터 배열 자체를 새롭게 계산하여 레이어에 넘겨주는 방식을 사용합니다.
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/deck.gl@latest/dist.min.js"></script>
<script src="https://unpkg.com/maplibre-gl@latest/dist/maplibre-gl.js"></script>
<link
href="https://unpkg.com/maplibre-gl@latest/dist/maplibre-gl.css"
rel="stylesheet"
/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/satellite.js/4.1.3/satellite.min.js"></script>
</head>
<body style="margin: 0;">
<div id="container" style="width: 100vw; height: 100vh;"></div>
<script>
const { DeckGL, ScatterplotLayer, GlobeView } = deck;
// ISS TLE
const tleLine1 =
"1 25544U 98067A 24089.15582236 .00015692 00000-0 27889-3 0 9999";
const tleLine2 =
"2 25544 51.6416 195.1432 0004558 102.7711 319.2483 15.49534708445775";
const satrec = satellite.twoline2satrec(tleLine1, tleLine2);
let deckInstance;
// [핵심] 현재 위치 데이터를 가진 레이어 스냅샷 생성
function renderLayer() {
const now = new Date();
const positionAndVelocity = satellite.propagate(satrec, now);
const gmst = satellite.gstime(now);
const positionGd = satellite.eciToGeodetic(
positionAndVelocity.position,
gmst,
);
const issData = [
{
// Deck.gl GlobeView는 [경도, 위도, 고도] 순서 사용
position: [
satellite.degreesLong(positionGd.longitude),
satellite.degreesLat(positionGd.latitude),
positionGd.height * 1000,
],
name: "ISS",
},
];
const layer = new ScatterplotLayer({
id: "iss-layer",
data: issData,
getPosition: (d) => d.position,
getFillColor: [255, 50, 50],
getRadius: 200000, // m 단위 (크게 설정)
stroked: true,
getLineColor: [255, 255, 255],
lineWidthMinPixels: 2,
});
// 기존 DeckGL 인스턴스가 있다면 레이어만 갱신
if (deckInstance) {
deckInstance.setProps({ layers: [layer] });
}
return layer;
}
// 초기 인스턴스 생성
deckInstance = new DeckGL({
container: "container",
views: new GlobeView(), // 지구본 모드
initialViewState: { longitude: 0, latitude: 0, zoom: 1 },
controller: true,
layers: [renderLayer()],
});
// 주기적 업데이트 애니메이션 루프
function animationLoop() {
renderLayer();
requestAnimationFrame(animationLoop); // 매 프레임 업데이트 (성능 주의)
}
animationLoop();
</script>
</body>
</html>
요약
데이터 연동 관점에서 CesiumJS는 CallbackProperty라는 빌트인 메커니즘을 제공하여 코드가 가장 간결하고 성능이 좋습니다. satellite.js 라이브러리는 공통으로 사용되며 km 단위 좌표를 m 단위로 변환하는 것을 잊지 말아야 합니다.