# 위성 정보를 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](https://github.com/CesiumGS/cesium)
- **특징:** 2012년부터 꾸준히 관리되어 온 가장 성숙한 프로젝트입니다. 핵심 엔진인 CesiumJS 자체는 100% 무료 오픈소스이지만, 고해상도 지형(Terrain)이나 대용량 3D 타일 데이터 호스팅을 위해 **Cesium ion**이라는 유료 클라우드 서비스를 함께 제공하기도 합니다. (자체 서버 데이터 사용 시 비용 없음)

### 2. NASA WebWorldWind

- **라이선스:** **Apache 2.0** (과거 NOSA 라이선스에서 변경됨)
- **저장소:** [GitHub - NASAWorldWind/WebWorldWind](https://github.com/NASAWorldWind/WebWorldWind)
- **특징:** NASA에서 직접 관리하는 프로젝트로, 완전한 오픈소스입니다. 다만, 최근 NASA의 공식적인 직접 지원(Active Maintenance)이 예전만큼 활발하지 않다는 점은 참고해야 합니다. 하지만 코드가 공개되어 있어 커뮤니티나 기업에서 직접 커스텀하여 사용하기에는 문제가 없습니다.

### 3. Deck.gl

- **라이선스:** **MIT** (가장 가볍고 제약이 적은 라이선스)
- **저장소:** [GitHub - visgl/deck.gl](https://github.com/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'로 취급하며, 시간축에 따른 움직임을 구현하기 가장 좋습니다.

```html
<!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` 위에 객체를 올립니다.

```html
<!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)로 표현하는 기본 구조입니다.

```html
<!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에서 실시간으로 받아와야 합니다.)

```javascript
// 국제우주정거장(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`를 이용해 매 프레임마다 위성의 위치를 계산하여 애니메이션처럼 보여주는 방식에 가장 최적화되어 있습니다.

```html
<!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의 위치 속성을 직접 갱신하는 방식을 사용합니다.

```html
<!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`을 이용해 주기적으로 데이터 배열 자체를 새롭게 계산하여 레이어에 넘겨주는 방식을 사용합니다.

```html
<!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 단위로 변환하는 것을 잊지 말아야 합니다.
