上一篇文章中咱們實現了最基本的項目搭建並生成了一個三維地球,這篇文章咱們主要介紹一下地圖中基本的幾大要素、地圖相對應座標系知識的介紹及如何將這幾大元素呈如今咱們的地球上。一樣的,若是文章中有錯誤的話歡迎評論區指出,定當虛心請教並及時修改!javascript
接下來會有部分篇幅用來介紹地圖元素以及座標系及其轉換相關知識,僅做了解。不想看的就直接跳到Viewer相關配置,直接進行實際操做。css
咱們首先來看看百度地圖上大概都有哪些元素(這裏我以路線查詢做爲例子)html
首先,地圖中最重要的,也是最基本的就是底圖,底圖負責將地理的基本信息展示在視區中,沒有底圖,堆多少要素都是無用的。接下來是路線的起點和終點,對應地圖中的點要素Point,兩點之間的路線對應地圖中的線要素LineString。最後就是右下角的面數據了(是否是格格不入,由於是我本身畫的哈哈哈),對應地圖中的面要素Polygon。而咱們的項目中,基本上的信息展現就是由點線面三類要素構成。java
只要涉及到地圖開發,不管如何關於座標系的概念是逃不掉的,誰讓地球它是個球呢🌏(若是向歐文說的地球是方的那就行了)。git
想象中的地球vs實際的地球web
這裏就不列舉國內經常使用的座標系及轉換方法,你們能夠自行百度。關於投影座標系統和地理座標系統,能夠閱讀這兩篇文章加以瞭解。咱們主要介紹Cesium中的經常使用座標系以及對應的轉換方式。編程
地理座標系統canvas
投影座標系統api
Cesium中經常使用的座標有兩種:WGS84座標和笛卡爾空間座標,咱們平時以經緯度來指向一個地點用的就是WGS84座標,笛卡爾空間座標則經常使用來作一些空間位置的變換,如平移、縮放等。兩者關係以下圖:數組
WGS84座標系中包括WGS84經緯度座標系和WGS84弧度座標系(Cartographic
)。
笛卡爾空間座標系包括笛卡爾空間直角座標系(Cartesian3
)、平面座標系(Cartesian2
)和4D笛卡爾座標系(Cartesian4
)。
World Geodetic System 1984,是爲GPS全球定位系統使用而創建的座標系統,座標原點爲地球質心,其地心空間直角座標系的Z軸指向BIH (國際時間服務機構)1984.O定義的協議地球極(CTP)方向,X軸指向BIH 1984.0的零子午面和CTP赤道的交點,Y軸與Z軸、X軸垂直構成右手座標系。咱們日常手機上的指南針顯示的經緯度就是這個座標系下當前的座標,進度範圍[-180,180],緯度範圍[-90,90]。
Cesium目前支持兩種座標系WGS84和WebMercator,可是在Cesium中沒有實際的對象來描述WGS84座標,都是以弧度的方式來進行運用的也就是Cartographic類:
new Cesium.Cartographic(longitude, latitude, height),這裏的參數也叫longitude、latitude,就是經度和緯度,計算方法:弧度= π/180×經緯度角度。
Cartesian3
)笛卡爾空間座標的原點就是橢球的中心,咱們在計算機上進行繪圖時,不方便使用經緯度直接進行繪圖,通常會將座標系轉換爲笛卡爾座標系,使用計算機圖形學中的知識進行繪圖。這裏的Cartesian3,有點相似於三維繫統中的Point3D對象,new Cesium.Cartesian3(x, y, z),裏面三個份量x、y、z。
Cartesian2
)平面座標系也就是平面直角座標系,是一個二維笛卡爾座標系,與Cartesian3相比少了一個z的份量,new Cesium.Cartesian2(x, y)。Cartesian2常常用來描述屏幕座標系,好比鼠標在電腦屏幕上的點擊位置,返回的就是Cartesian2,返回了鼠標點擊位置的xy像素點份量。
var radians=Cesium.Math.toRadians(degrees);//經緯度轉弧度
var degrees=Cesium.Math.toDegrees(radians);//弧度轉經緯度
複製代碼
Cartographic
)的轉換//方法一:
var longitude = Cesium.Math.toRadians(longitude1); //其中 longitude1爲角度
var latitude= Cesium.Math.toRadians(latitude1); //其中 latitude1爲角度
var cartographic = new Cesium.Cartographic(longitude, latitude, height);
//方法二:
var cartographic= Cesium.Cartographic.fromDegrees(longitude, latitude, height);//其中,longitude和latitude爲角度
//方法三:
var cartographic= Cesium.Cartographic.fromRadians(longitude, latitude, height);//其中,longitude和latitude爲弧度
複製代碼
Cartesian3
)的轉換var position = Cesium.Cartesian3.fromDegrees(longitude, latitude, height);//其中,高度默認值爲0,能夠不用填寫;longitude和latitude爲角度
var positions = Cesium.Cartesian3.fromDegreesArray(coordinates);//其中,coordinates格式爲不帶高度的數組。例如:[-115.0, 37.0, -107.0, 33.0]
var positions = Cesium.Cartesian3.fromDegreesArrayHeights(coordinates);//coordinates格式爲帶有高度的數組。例如:[-115.0, 37.0, 100000.0, -107.0, 33.0, 150000.0]
//同理,經過弧度轉換,用法相同,具體有Cesium.Cartesian3.fromRadians,Cesium.Cartesian3.fromRadiansArray,Cesium.Cartesian3.fromRadiansArrayHeights等方法
複製代碼
var cartographic= Cesium.Cartographic.fromCartesian(cartesian3);
複製代碼
Cartesian2
)和笛卡爾空間直角座標系(Cartesian3
)的轉換平面座標系轉笛卡爾空間直角座標系
這裏注意的是當前的點(Cartesian2)必須在三維球上,不然返回的是undefined;經過ScreenSpaceEventHandler回調會取到的座標都是Cartesian2。
屏幕座標轉場景座標-獲取傾斜攝影或模型點擊處的座標 這裏的場景座標是包含了地形、傾斜攝影表面、模型的座標。
經過viewer.scene.pickPosition(movement.position)獲取,根據窗口座標,從場景的深度緩衝區中拾取相應的位置,返回笛卡爾座標。
var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction(function (movement) {
var position = viewer.scene.pickPosition(movement.position);
console.log(position);
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
複製代碼
注:若屏幕座標處沒有傾斜攝影表面、模型時,獲取的笛卡爾座標不許,此時要開啓地形深度檢測(viewer.scene.globe.depthTestAgainstTerrain = true
; //默認爲false)。
屏幕座標轉地表座標-獲取加載地形後對應的經緯度和高程 這裏是地球表面的世界座標,包含地形,不包括模型、傾斜攝影表面。
經過viewer.scene.globe.pick(ray, scene)
獲取,其中ray=viewer.camera.getPickRay(movement.position)
。
var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction(function (movement) {
var ray = viewer.camera.getPickRay(movement.position);
var position = viewer.scene.globe.pick(ray, viewer.scene);
console.log(position);
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
複製代碼
注:經過測試,此處獲得的座標經過轉換成wgs84後,height的爲該點的地形高程值。
屏幕座標轉橢球面座標-獲取鼠標點的對應橢球面位置 這裏的橢球面座標是參考橢球的WGS84座標(Ellipsoid.WGS84),不包含地形、模型、傾斜攝影表面。
經過 viewer.scene.camera.pickEllipsoid(movement.position, ellipsoid)
獲取,能夠獲取當前點擊視線與橢球面相交處的座標,其中ellipsoid是當前地球使用的橢球對象:viewer.scene.globe.ellipsoid
,默認爲Ellipsoid.WGS84。
var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction(function (movement) {
var position = viewer.scene.camera.pickEllipsoid(movement.position, viewer.scene.globe.ellipsoid);
console.log(position);
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
複製代碼
注:經過測試,此處獲得的座標經過轉換成wgs84後,height的爲0(此值應該爲地表座標減去地形的高程)。
咱們在第一篇文章中成功生成了三維球體,可是細心的朋友會發現咱們Viewer
的配置項是一個空對象,接下來我就將基本配置羅列出來,朋友們可根據須要自行添加到本身的Viewer
配置中
這裏的配置對應的是超圖二次封裝過的Viewer,因此有些默認配置可能與原始Ceiusm默認配置不一樣,原始的配置項可參照這篇博客
名稱 | 類型 | 默認 | 描述 |
---|---|---|---|
clock | Clock |
new Clock() |
控制當前時間的時鐘 |
selectedImageryProviderViewModel | ProviderViewModel |
當前基礎圖像圖層的視圖模型,如若未提供,則使用第一個可用基礎圖層。此值僅在 options.baseLayerPicker 設置爲true時有效。 | |
imageryProviderViewModels | Array.<ProviderViewModel> |
createDefaultImageryProviderViewModels() |
ProviderViewModels數組可從BaseLayerPicker中選擇。此值僅在 options.baseLayerPicker 設置爲true時有效。 |
selectedTerrainProviderViewModel | ProviderViewModel |
當前基礎地形圖層的視圖模型,如若未提供,則使用第一個可用基礎圖層。此值僅在 options.baseLayerPicker 設置爲true時有效。 | |
terrainProviderViewModels | Array.<ProviderViewModel> |
createDefaultTerrainProviderViewModels() |
ProviderViewModels數組可從BaseLayerPicker中選擇。此值僅在 options.baseLayerPicker 設置爲true時有效。 |
imageryProvider | ImageryProvider |
new BingMapsImageryProvider() |
使用的影像提供者。此值僅在 options.baseLayerPicker 設置爲 false 時有效。 |
terrainProvider | TerrainProvider |
new EllipsoidTerrainProvider() |
使用的地形提供者。 |
skyBox | SkyBox |
用於渲染星辰的天空盒,未定義時,使用默認星辰效果。 | |
skyAtmosphere | SkyAtmosphere |
環繞地球邊緣的藍天和光暈效果,設置爲false可將其關閉。 | |
useDefaultRenderLoop | Boolean |
true |
若是此部件可以控制渲染循環,設置爲true,反之設置爲false。 |
targetFrameRate | Number |
使用默認渲染循環時的目標幀速率。 | |
showRenderLoopErrors | Boolean |
true |
若是設置爲true,發生渲染循環錯誤時,將自動給用戶顯示一個包含錯誤信息的HTML面板。 |
automaticallyTrackDataSourceClocks | Boolean |
true |
若是設置爲true,將自動跟蹤新添加數據源的時鐘設置,若是數據源的時鐘變動,則更新。如需單獨設置時鐘,請將此項設置爲false。 |
contextOptions | Object |
Context and WebGL 建立屬性與傳遞給Scene匹配的選項。增長硬件反走樣功能,反走樣係數msaalevel使用1到8的整數值,默認是1,值越大反走樣效果越好(由於用到了WebGL2.0的特性,因此requestWebgl2參數設置爲true。由於WebGL2.0還存在一下缺陷,因此須要先把OIT,FXAA,HDR關掉) | |
mapProjection | MapProjection |
new GeographicProjection() |
在二維和Columbus視圖模式下所使用的地圖投影。 |
globe | Globe |
new Globe(mapProjection.ellipsoid) |
場景中的地球,若是此項設置爲false,將不添加球體對象。 |
orderIndependentTranslucency | Boolean |
true |
若是此項設置爲true,而且使用設備支持,將使用與順序無關的半透明。 |
creditContainer | Element \ String |
指定包含CreditDisplay信息的DOM元素或ID。如若未指定,credit信息將添加到部件底部。 | |
dataSources | DataSourceCollection |
new DataSourceCollection() |
指定由viewer部件可視化的數據源集合。若是提供此參數,實例由調用者擁有,而且viewer被銷燬時此實例不被銷燬。 |
terrainExaggeration | Number |
1.0 |
用於誇大地形的標量。請注意,設置地形誇張不會修改其它任何數據。 |
shadows | Boolean |
false |
肯定陰影是否由太陽投射造成。 |
terrainShadows | ShadowMode |
ShadowMode.RECEIVE_ONLY |
肯定地形是否投射或接受來自太陽的陰影。 |
mapMode2D | MapMode2D |
MapMode2D.INFINITE_SCROLL |
肯定二維地圖是可旋轉的或是能夠在在水平方向上無限滾動。 |
navigation | Boolean |
false |
是否顯示導航羅盤控件。如需顯示,需在初始化viewer時此項設置爲true。 |
Adding Imagery
)Imagery
不用說,在Cesium項目中必定是關鍵元素,瓦片圖集合根據不一樣投影方式映射到三維地球表面,經過相機指向地表的方向距離,Cesium會自動請求不一樣層級的圖層信息進行渲染。
Cesium支持多種圖層格式:
默認地,Cesium使用Bing Maps做爲默認的圖層。這個圖層被打包進Viewer中用於演示。
Cesium中基本的添加底圖的方法爲viewer.imageryLayers.addImageryProvider()
咱們在init()
方法中添加下方代碼,嘗試一下。
var layer = viewer.imageryLayers.addImageryProvider(new Cesium.ArcGisMapServerImageryProvider({
url: 'http://cache1.arcgisonline.cn/ArcGIS/rest/services/ChinaOnlineCommunity/MapServer'
}));
複製代碼
對於天地圖WebGL提供了一個天地圖影像服務提供者類TiandituImageryProvider
,具體的使用方法能夠參照示例和api文檔
咱們已經把本身想要的底圖添加到地球上了,可是實際項目中確定不可能一進項目就給人展現整個地球(若是需求是這樣的,那我道歉!)。因此咱們須要在地球生成後定位到咱們須要的位置,這就不得不說一下Camera
了。
Cesium中有不少方法能夠操做Camera,如旋轉(rotate)、縮放(zoom)、平移(pan)和飛到目的地(flyTo)。CesiumJS有鼠標和觸摸事件用來處理與Camrea的交互,還有API來以編程方式操做攝像機。
使用setView
函數可設置Camera的位置和方向。destination
能夠是Cartesian3
或者Rectangle
,orientation
能夠是heading | pitch | roll | direction | up
。航向角、俯仰角和橫滾角以弧度定義。航向角是從正角度向東增長的局部北向旋轉。俯仰角是指從局部的東北平面開始旋轉。正俯仰角在平面上方。負俯仰角在平面如下。
// 初始化場景位置
viewer.scene.camera.setView({
// 初始化相機經緯度(這裏使用了經緯度轉換世界座標的方法)
destination: new Cesium.Cartesian3.fromDegrees(
121.54035,
38.92146,
2000
),
orientation: {
heading: Cesium.Math.toRadians(0.0),
pitch: Cesium.Math.toRadians(-25.0), //從上往下看爲-90
roll: 0,
},
});
複製代碼
flyTo
方法的參數和setView
是基本同樣的。只是setView
是直接將視角根據參數定位,而flyTo
如字面意思,會有一個飛向定位點的動畫效果。
二者效果圖:
<template>
<div class="container"> <div id="cesiumContainer"></div> </div>
</template>
<script> var viewer, camera; export default { data() { return {}; }, mounted() { this.init(); }, methods: { init() { viewer = new Cesium.Viewer("cesiumContainer", {}); var layer = viewer.imageryLayers.addImageryProvider( new Cesium.ArcGisMapServerImageryProvider({ url: "http://cache1.arcgisonline.cn/ArcGIS/rest/services/ChinaOnlineCommunity/MapServer", }) ); // 初始化場景位置 viewer.scene.camera.flyTo({ // 初始化相機經緯度 destination: new Cesium.Cartesian3.fromDegrees( 121.54035, 38.92146, 2000 ), orientation: { heading: Cesium.Math.toRadians(0.0), pitch: Cesium.Math.toRadians(-25.0), //從上往下看爲-90 roll: 0, }, }); }, }, }; </script>
<style lang="scss" scoped> </style>
複製代碼
原本想在這篇文章中把點線面的添加寫進來的,計劃不如變化快,因此這篇暫時就只講一下座標系和Viewer、Camera相關的東西吧。下一篇再實現添加點線面要素吧。頭疼哈哈哈。最後謝謝看過贊過評論過我上一篇文章的兄弟們,寫了文章有了反饋確實是更有動力創做下去!
【三維GIS可視化】基於Vue+Cesium+Supermap實現智慧城市(一)