iT邦幫忙

第 12 屆 iT 邦幫忙鐵人賽

DAY 28
0
Modern Web

《你的地圖會說話? WebGIS與JavaScript的情感交織》系列 第 28

[3D地圖-CesiumJS系列] 二、建立飛航軌跡及動畫

本篇文章請搭配
[3D地圖-CesiumJS系列] 一、快速上手


不知道大家在飛機上時會不會好奇飛機行進到哪裡?
飛行高度多少?飛行軌跡如何?
身為好奇寶寶的我們,常常會盯著座位螢幕前的3D飛航示意圖呢!
今天就要來介紹怎麼使用CesiumJS來製作一個飛航軌跡圖。

本篇文章使用官方範例來介紹。

初始化3D地圖

複習一下昨天介紹的初始化地圖的方式吧!如果還不會CesiumJS專案建置的人,請參考昨天的文章
在根目錄下建立一個html頁面,取名為Cesium_airplane.html。

↓ 建立一個存放地圖的div

    <div id="cmap"></div>

↓ 引入Cesium.js

    <script src="../Build/Cesium/Cesium.js"></script>

↓ 引入css

    <link rel="stylesheet" href="../Build/Cesium/Widgets/widgets.css" />

↓ css讓地圖滿版

    <style>
        html,
        body,
        #cmap {
            width: 100%;
            height: 100%;
            margin: 0;
            padding: 0;
            overflow: hidden;
        }
    </style>

↓ 設定API Key,如果想要載入自己上傳的圖層或模型,就要載入自己的key,官網註冊連結

        Cesium.Ion.defaultAccessToken = yourAPIKey;

↓ 初始化地圖,新建一個Cesium.Viewer的物件,第一個參數存放地圖的容器Id,第二個參數為設定(選填)。

        const viewer = new Cesium.Viewer('cmap', {
            terrainProvider: Cesium.createWorldTerrain()  // 建立地形
        });

↓ 結果
https://ithelp.ithome.com.tw/upload/images/20201013/20130604mgY1KdXK7D.png

  • terrain

↓ 花東縱谷,未使用Cesium.createWorldTerrain()
https://ithelp.ithome.com.tw/upload/images/20201013/20130604jrGCvFVZmq.jpg

↓ 花東縱谷,使用Cesium.createWorldTerrain()
https://ithelp.ithome.com.tw/upload/images/20201013/20130604bw3SPT4FQR.jpg
明顯較能感受到地形高低起伏。

  • Buildings

↓ 建立3D建物的圖層

    const osmBuildings = viewer.scene.primitives.add(Cesium.createOsmBuildings());

↓ 台北信義區,未使用Cesium.createOsmBuildings()
https://ithelp.ithome.com.tw/upload/images/20201013/20130604pswzuksuRr.jpg
頂多出現高樓層建築物的陰影。

↓ 台北信義區,使用Cesium.createOsmBuildings()
https://ithelp.ithome.com.tw/upload/images/20201013/20130604tidOB0Dzrc.jpg
只要有登記3D建模的建築物都會清楚呈現。

航行路線資料及設定時間

這邊為求方便,直接使用範例航班數據下載

↓ 資料格式

        const data = [{ "longitude": 121.523333, "latitude": 25.15, "height": 3000 }, { "longitude": 120.3508, "latitude": 23, "height": 12000 }]

↓ 把讀取的json資料格式轉為物件/陣列後,即可使用。

        const flightData = JSON.parse(data);

↓ 設定時間區間、起始時間、時間軸動畫

        const timeSpan = 30;
        const totalSeconds = timeSpan * (flightData.length - 1);
        const start = Cesium.JulianDate.fromIso8601("2020-10-13T21:10:00Z");
        const stop = Cesium.JulianDate.addSeconds(start, totalSeconds, new Cesium.JulianDate());
       
        viewer.clock.startTime = start.clone();
        viewer.clock.stopTime = stop.clone();
        viewer.clock.currentTime = start.clone();
        viewer.timeline.zoomTo(start, stop);
        viewer.clock.multiplier = 50;
        viewer.clock.shouldAnimate = true;

↓ 時間軸由設定的時間開始跑
圖片

飛航軌跡點

↓ 剛剛設定的時間區間及每個點座標資訊,用Cesium.SampledPositionProperty()建立的物件來儲存。

        const timeSpan = 30;
        const positionProperty = new Cesium.SampledPositionProperty();

↓ 跑迴圈,設定每個點的時間區間、座標、高度,並把它們加入positionProperty物件中,最後並把點加入地圖(viewer)中。

        flightData.forEach((item, index) => {
            const time = Cesium.JulianDate.addSeconds(start, index * timeSpan, new Cesium.JulianDate());
            const position = Cesium.Cartesian3.fromDegrees(item.longitude, item.latitude, item.height);
            positionProperty.addSample(time, position);

            viewer.entities.add({
                description: `經度: ${item.longitude}, 緯度: ${item.latitude}, 海拔高度: ${item.height})`,
                position: position,
                point: { pixelSize: 10, color: Cesium.Color.ORANGE }
            });
        });

↓ 飛航軌跡
https://ithelp.ithome.com.tw/upload/images/20201013/20130604dce1bKYWTJ.jpg

↓ 從側面看,飛航軌跡橫越大西洋
https://ithelp.ithome.com.tw/upload/images/20201013/20130604jfelMSWMFO.jpg

↓ 把地圖投影成平面後,會發現最短距離在平面地圖上是弧形的
https://ithelp.ithome.com.tw/upload/images/20201013/20130604emdsDtn8UG.jpg

載入飛機模型

可以在Cesium的官方平台上,上傳飛機模型,上傳完畢後會得到一組飛行模型的Id。

↓ 上傳介面
https://ithelp.ithome.com.tw/upload/images/20201013/20130604Rezw3WXpl6.jpg

↓ 選擇GITF格式
https://ithelp.ithome.com.tw/upload/images/20201013/20130604S94l0Xq9pt.jpg

↓ 上傳成功,獲得該飛行模型的Id。
https://ithelp.ithome.com.tw/upload/images/20201013/201306045AuKGGg2Si.jpg

↓ 地圖載入飛機模型,並將它設定至飛航軌跡的實體。

        const airPlaneId = 164161;
        async function LoadAirPlaneModel() {
            const airplaneUri = await Cesium.IonResource.fromAssetId(airPlaneId);
            const airplane = {
                availability: new Cesium.TimeIntervalCollection([new Cesium.TimeInterval({ start: start, stop: stop })]),
                position: positionProperty,
                model: { uri: airplaneUri },
                orientation: new Cesium.VelocityOrientationProperty(positionProperty),
                path: new Cesium.PathGraphics({ width: 3 })
            }

            viewer.trackedEntity = viewer.entities.add(airplane);
        }

↓ airplaneUri也可以直接讀取官網的範例飛機模型連結。

const airplaneUri = 'https://sandcastle.cesium.com/SampleData/models/CesiumAir/Cesium_Air.glb';

↓ 呼叫

         LoadAirPlaneModel();

展示

↓ 機場中滑行
圖片

↓ 空中轉向
圖片

↓ 快速飛越陸地
圖片

↓ 海面上飛行
圖片


看著飛機再飛是不是很療癒呢?
大家趕快也來玩看看吧!

/images/emoticon/emoticon42.gif


上一篇
[3D地圖-CesiumJS系列] 一、快速上手
下一篇
[3D地圖-CesiumJS系列] 三、車輛廢氣排放地圖 - 以粒子系統(Particle system)實作
系列文
《你的地圖會說話? WebGIS與JavaScript的情感交織》30

尚未有邦友留言

立即登入留言