Cesium隨筆:鷹眼功能

0.前言

leaf2vue.png

本文記錄一下Cesium引擎鷹眼功能的實(shí)現(xiàn)過程岁疼,項(xiàng)目采用vue框架(修改自cesiumlab的開源項(xiàng)目)赤炒,小地圖采用leaflet蟹略。閱讀本文需要Cesium和Vue相關(guān)知識(shí)缓淹。

gifeditor_20190516_232158.gif

1.基本思路

鷹眼的基本需求是:在三維地圖中鑲嵌一個(gè)迷你二維地圖哈打,在迷你地圖中繪制三維地圖中用戶的可視域、鼠標(biāo)的位置等讯壶,并且隨著三維地圖畫面的更新二維地圖也跟著實(shí)時(shí)變化料仗。
首先是二三維地圖的實(shí)時(shí)聯(lián)動(dòng)問題,通過監(jiān)聽Cesium的postRender或者鼠標(biāo)移動(dòng)事件伏蚊,將數(shù)據(jù)變化實(shí)時(shí)更新到二維地圖即可立轧。
然后是二維地圖的選擇,需求只需要繪制簡單的幾何圖形躏吊,因此這里選擇簡單好用的leaflet地圖氛改。
最后是二維地圖繪制邏輯,經(jīng)過試驗(yàn)比伏,筆者采用二維地圖實(shí)時(shí)聚焦在三維地圖鼠標(biāo)坐標(biāo)的方式胜卤,并且在二維地圖中繪制出三維攝像頭的可見范圍,二維地圖的縮放級(jí)別隨著三維攝像機(jī)的離地高度改變赁项。

2.leaflet2vue

項(xiàng)目使用leaflet2vue葛躏。
組件安裝:
npm install vue2-leaflet leaflet --save
在小地圖組件中使用leaflet:

<template>
    <div class="vue-leaflet">
        <l-map style="position: absolute; top: 110px; right: 10px; padding: 0px; width: 250px; height: 250px" :zoom="zoom"
         :center="center">
            <l-tile-layer :url="url" :attribution="attribution"></l-tile-layer>
            <l-marker :lat-lng="marker">
                <l-popup :content="text"></l-popup>
            </l-marker>
            <l-polygon :lat-lngs="viewRect" :color="viewRectColor">
            </l-polygon>
        </l-map>
    </div>
</template>

<script>
    import {
        LMap,
        LTileLayer,
        LMarker,
        LPopup,
        LPolygon
    } from 'vue2-leaflet'

    export default {
        name: 'leafletMini',
        components: {
            LMap,
            LTileLayer,
            LMarker,
            LPopup,
            LPolygon
        },
        data() {
            return {
                url: 'http://{s}.tile.osm.org/{z}/{x}/{y}.png',
                attribution: '&copy; <a >OpenStreetMap</a> contributors',
                text: '光標(biāo)的位置',
                viewRectColor: 'orange'
            }
        },
        props: ['center', 'marker', 'zoom', 'viewRect']
    }
</script>

在本例中幾乎不需要對(duì)leaflet進(jìn)行任何編程澈段,只需要把地圖中心、大頭針舰攒、視域多邊形的數(shù)據(jù)綁定給相應(yīng)的組件即實(shí)現(xiàn)了leaflet負(fù)責(zé)的功能败富。

3.Cesium與leaflet聯(lián)動(dòng)

在Cesium窗口中添加小地圖組件

<template>
    <div style="width: 100%; height: 100%">
        <div style="position: relative; width: 100%; height: 100%" ref="coreViewer">
            <div ref="viewer" style="width: 100%; height: 100%" id="viewer"></div>
     
            <leafletMini :center="minimapCenter" :marker="minimapCrusor" :zoom="minimapZoom" :viewRect="minimapViewRect"/>
        </div>
    </div>
</template>

<script>
import bindMinimap from '../scripts/eagleEye';
import leafletMini from '../components/leafletMini.vue';
import {
        LMap,
        LTileLayer,
        LMarker,
        LPopup
    } from 'vue2-leaflet'
export default {
    name: "CesiumView",
    components: {
        'leafletMini': leafletMini
    },
    mounted() {
        this.$nextTick(() => {
            const viewer = initViewer(this.$refs.viewer);

            this.freezedViewer = Object.freeze({viewer});

            var that = this;
            document.addEventListener(Cesium.Fullscreen.changeEventName, () => {
                that.isFullscreen = Cesium.Fullscreen.fullscreen;
            });
        });
    },
    data() {
        return {
            freezedViewer: undefined,
            minimapCenter: undefined,
            minimapZoom: 2,
            minimapCrusor: L.latLng(0.0, 0.0),
            minimapViewRect:[]
        };
    },
    methods: {
        
        bindEagleEyeOnMinimap(){
            let h=parseInt(window.getComputedStyle(this.$refs.coreViewer).height);
            let w=parseInt(window.getComputedStyle(this.$refs.coreViewer).width);
            bindMinimap(this.freezedViewer && this.freezedViewer.viewer,(x,y,zoom,viewRectCoords)=>{
                this.minimapCenter=L.latLng(y, x);
                this.minimapZoom=zoom;
                this.minimapCrusor=L.latLng(y, x);
                this.minimapViewRect=viewRectCoords;
            },w,h);
        }
    }
};
</script>

實(shí)現(xiàn)聯(lián)動(dòng)的代碼:eagleEye.js

import Cesium from 'Cesium';
//啟動(dòng)鷹眼功能
function bindMinimap(cesiumViewer, funcWithCursorPos,windowWidth,windowHeight) {
    var handler = new Cesium.ScreenSpaceEventHandler(cesiumViewer.scene.canvas);
    handler.setInputAction(function(movement) {
        let dynamicPosition = undefined;
        let ray = cesiumViewer.camera.getPickRay(movement.endPosition);
        dynamicPosition = cesiumViewer.scene.globe.pick(ray, cesiumViewer.scene);
        let corners=getViewRect(cesiumViewer,cesiumViewer.scene.camera,windowWidth,windowHeight);
        if (Cesium.defined(dynamicPosition)) {
            funcWithCursorPos(Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(dynamicPosition).longitude),
                Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(dynamicPosition).latitude),
                getZoomLevel(cesiumViewer.scene.camera),
                corners
            );
        }
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
}
//計(jì)算相機(jī)視域
function getViewRect(cesiumViewer,camera,windowWidth,windowHeight){
    let cornerPos = undefined;
    let ray=undefined;
    let positions=[];
    
    ray = cesiumViewer.camera.getPickRay(new Cesium.Cartesian2(0,0));
    cornerPos = cesiumViewer.scene.globe.pick(ray, cesiumViewer.scene);
    if (!Cesium.defined(cornerPos)){
        return [];
    }
    positions.push([Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(cornerPos).latitude),
    Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(cornerPos).longitude)]);
    
    ray = cesiumViewer.camera.getPickRay(new Cesium.Cartesian2(0,windowHeight));
    cornerPos = cesiumViewer.scene.globe.pick(ray, cesiumViewer.scene);
    if (!Cesium.defined(cornerPos)){
        return [];
    }
    positions.push([Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(cornerPos).latitude),
    Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(cornerPos).longitude)]);
    
    ray = cesiumViewer.camera.getPickRay(new Cesium.Cartesian2(windowWidth,windowHeight));
    cornerPos = cesiumViewer.scene.globe.pick(ray, cesiumViewer.scene);
    if (!Cesium.defined(cornerPos)){
        return [];
    }
    positions.push([Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(cornerPos).latitude),
    Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(cornerPos).longitude)]);
    
    ray = cesiumViewer.camera.getPickRay(new Cesium.Cartesian2(windowWidth,0));
    cornerPos = cesiumViewer.scene.globe.pick(ray, cesiumViewer.scene);
    if (!Cesium.defined(cornerPos)){
        return [];
    }
    positions.push([Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(cornerPos).latitude),
    Cesium.Math.toDegrees(Cesium.Cartographic.fromCartesian(cornerPos).longitude)]);
    
    return positions
}
//計(jì)算地圖縮放等級(jí)
function getZoomLevel(camera) {
    let h = camera.positionCartographic.height;
    if (h <= 100) { //0.01
        return 19;
    } else if (h <= 300) { //0.02
        return 18;
    } else if (h <= 660) { //0.05
        return 17;
    } else if (h <= 1300) { //0.1
        return 16;
    } else if (h <= 2600) { //0.2
        return 15;
    } else if (h <= 6400) { //0.5
        return 14;
    } else if (h <= 13200) { //1
        return 13;
    } else if (h <= 26000) { //2
        return 12;
    } else if (h <= 67985) { //5
        return 11;
    } else if (h <= 139780) { //10
        return 10;
    } else if (h <= 250600) { //20
        return 9;
    } else if (h <= 380000) { //30
        return 8;
    } else if (h <= 640000) { //50
        return 7;
    } else if (h <= 1280000) { //100
        return 6;
    } else if (h <= 2600000) { //200
        return 5;
    } else if (h <= 6100000) { //500
        return 4;
    } else if (h <= 11900000) { //1000
        return 3;
    } else {
        return 2;
    }
}
export default bindMinimap;

4.總結(jié)

Vue綁定數(shù)據(jù)很方便,通過Props就能把Cesium主窗口的數(shù)據(jù)綁定給miniMap子窗口摩窃,不需要寫多余的代碼兽叮。包括小地圖的中心位置、鼠標(biāo)坐標(biāo)偶芍、視域范圍都是這樣同步過來的充择,且感受不到任何延遲德玫。
具體綁定過程:
1.在Cesium組件聲明小地圖數(shù)據(jù)

image.png

2.在小地圖組件中聲明Props
image.png

3.在Cesium窗口中向Minimap綁定Props和自己的data
image.png

4.在miniMap組件把數(shù)據(jù)綁定到leaflet
image.png

經(jīng)過一番折騰匪蟀,在Cesium窗口中改變綁定的這些data,leaflet小地圖就能實(shí)時(shí)變化了宰僧。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末材彪,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子琴儿,更是在濱河造成了極大的恐慌段化,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件造成,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)篮绰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門钉鸯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人鼓鲁,你說我怎么就攤上這事蕴轨。” “怎么了骇吭?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵橙弱,是天一觀的道長。 經(jīng)常有香客問我燥狰,道長棘脐,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任龙致,我火速辦了婚禮蛀缝,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘净当。我一直安慰自己内斯,他們只是感情好蕴潦,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著俘闯,像睡著了一般潭苞。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上真朗,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天此疹,我揣著相機(jī)與錄音,去河邊找鬼遮婶。 笑死蝗碎,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的旗扑。 我是一名探鬼主播蹦骑,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼臀防!你這毒婦竟也來了眠菇?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤袱衷,失蹤者是張志新(化名)和其女友劉穎捎废,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體致燥,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡登疗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了嫌蚤。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片辐益。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖搬葬,靈堂內(nèi)的尸體忽然破棺而出荷腊,到底是詐尸還是另有隱情,我是刑警寧澤急凰,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布女仰,位于F島的核電站,受9級(jí)特大地震影響抡锈,放射性物質(zhì)發(fā)生泄漏疾忍。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一床三、第九天 我趴在偏房一處隱蔽的房頂上張望一罩。 院中可真熱鬧,春花似錦撇簿、人聲如沸聂渊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽汉嗽。三九已至欲逃,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間饼暑,已是汗流浹背稳析。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留弓叛,地道東北人彰居。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像撰筷,于是被迫代替她去往敵國和親陈惰。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容