Cesium 概述 (二) 空間資料視覺化
空間資料視覺化
Cesium提供Entity API來繪製空間資料,例如點、標記、標籤、線、3D模型、形狀、立體形狀(volume)。
Entity API簡介
Cesium提供兩類API:
- (1)面向圖形開發人員的底層API,通常稱為“Primitive API”。該API暴露最小限度的抽象,使用圖形學術語,具有很大的靈活性,需要具有圖形學程式設計的知識
- (2)高級別的資料驅動的API,稱為“Entity API”。該API使用一致性設計的、高級別的物件來管理一組相關性的視覺化物件,其底層使用Primitive API
下面是Entity API的簡單例子,用紅色半透明區域標記出美國懷俄明州:
var viewer = new Cesium.Viewer('cesiumContainer'); //建立一個檢視器(Viewer widget) var wyoming = viewer.entities.add({ //新增一個實體,僅需要傳遞一個簡單JSON物件,返回值是一個Entity物件 name : 'Wyoming', polygon : { hierarchy : Cesium.Cartesian3.fromDegreesArray([//一組地理座標 -109.080842,45.002073, -105.91517,45.002073, -104.058488,44.996596, -104.053011,43.002989, -104.053011,41.003906, -105.728954,40.998429, -107.919731,41.003906, -109.04798,40.998429, -111.047063,40.998429, -111.047063,42.000709, -111.047063,44.476286, -111.05254,45.002073]), material : Cesium.Color.RED.withAlpha(0.5), //材質 outline : true, //是否顯示輪廓 outlineColor : Cesium.Color.BLACK //輪廓的顏色 } }); viewer.zoomTo(wyoming);//縮放、平移檢視使實體可見
形狀與立體(Shapes and Volumes)
支援的形狀與立體列表
(1) 立方體(Boxes):
var blueBox = viewer.entities.add({ name : 'Blue box', //中心的位置 position: Cesium.Cartesian3.fromDegrees(-114.0, 40.0, 300000.0), box : { //長寬高 dimensions : new Cesium.Cartesian3(400000.0, 300000.0, 500000.0), material : Cesium.Color.BLUE } }); var redBox = viewer.entities.add({ name : 'Red box with black outline', position: Cesium.Cartesian3.fromDegrees(-107.0, 40.0, 300000.0), box : { dimensions : new Cesium.Cartesian3(400000.0, 300000.0, 500000.0), material : Cesium.Color.RED, outline : true, //顯示輪廓 outlineColor : Cesium.Color.BLACK } }); var outlineOnly = viewer.entities.add({ name : 'Yellow box outline', position: Cesium.Cartesian3.fromDegrees(-100.0, 40.0, 300000.0), box : { dimensions : new Cesium.Cartesian3(400000.0, 300000.0, 500000.0), fill : false, //不顯示填充 outline : true, outlineColor : Cesium.Color.YELLOW } });
(2)圓和橢圓(Circles Ellipses)
var viewer = new Cesium.Viewer('cesiumContainer');
//浮空的綠色圓形
var greenCircle = viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(-111.0, 40.0, 150000.0),
name : 'Green circle at height',
ellipse : {
semiMinorAxis : 300000.0,
semiMajorAxis : 300000.0,
height: 200000.0, //浮空
material : Cesium.Color.GREEN
}
});
//紅色橢圓形,位於地表,帶輪廓
var redEllipse = viewer.entities.add({
//不帶高度
position: Cesium.Cartesian3.fromDegrees(-103.0, 40.0),
name : 'Red ellipse on surface with outline',
ellipse : {
semiMinorAxis : 250000.0,
semiMajorAxis : 400000.0,
material : Cesium.Color.RED.withAlpha(0.5),
outline : true,
outlineColor : Cesium.Color.RED
}
});
//藍色橢圓柱,旋轉了角度
var blueEllipse = viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(-95.0, 40.0, 100000.0),
name : 'Blue translucent, rotated, and extruded ellipse',
ellipse : {
semiMinorAxis : 150000.0,
semiMajorAxis : 300000.0,
extrudedHeight : 200000.0, //拉伸
rotation : Cesium.Math.toRadians(45), //旋轉
material : Cesium.Color.BLUE.withAlpha(0.7),
outline : true
}
});
viewer.zoomTo(viewer.entities);
(3)走廊(Corridor)
var redCorridor = viewer.entities.add({
name : 'Red corridor on surface with rounded corners and outline',
corridor : {
positions : Cesium.Cartesian3.fromDegreesArray([
-100.0, 40.0,
-105.0, 40.0,
-105.0, 35.0
]),
width : 200000.0,
material : Cesium.Color.RED.withAlpha(0.5),
outline : true,
outlineColor : Cesium.Color.RED
}
});
var greenCorridor = viewer.entities.add({
name : 'Green corridor at height with mitered corners',
corridor : {
positions : Cesium.Cartesian3.fromDegreesArray(
[ -90.0, 40.0,
-95.0, 40.0,
-95.0, 35.0
]),
height: 100000.0,
width : 200000.0,
cornerType: Cesium.CornerType.MITERED,
material : Cesium.Color.GREEN
}
});
var blueCorridor = viewer.entities.add({
name : 'Blue extruded corridor with beveled corners and outline',
corridor : {
positions : Cesium.Cartesian3.fromDegreesArray(
[ 80.0, 40.0,
-85.0, 40.0,
-85.0, 35.0
]),
height : 200000.0,
extrudedHeight : 100000.0,
width : 200000.0,
cornerType: Cesium.CornerType.BEVELED,
material : Cesium.Color.BLUE.withAlpha(0.5),
outline : true,
outlineColor : Cesium.Color.BLUE
}
});
(4)圓柱和圓錐(Cylinder Cones)
var greenCylinder = viewer.entities.add({
name : 'Green cylinder with black outline',
position: Cesium.Cartesian3.fromDegrees(-100.0, 40.0, 200000.0),
cylinder : { //圓柱
length : 400000.0,
topRadius : 200000.0,
bottomRadius : 200000.0,
material : Cesium.Color.GREEN,
outline : true,
outlineColor : Cesium.Color.DARK_GREEN
}
});
var redCone = viewer.entities.add({
name : 'Red cone',
position: Cesium.Cartesian3.fromDegrees(-105.0, 40.0, 200000.0),
cylinder : {//圓錐
length : 400000.0,
topRadius : 0.0,
bottomRadius : 200000.0,
material : Cesium.Color.RED
}
});
(5) 多邊形(Polygons)
var redPolygon = viewer.entities.add({
name : '貼著地表的多邊形',
polygon : {
hierarchy : Cesium.Cartesian3.fromDegreesArray([-115.0, 37.0,
-115.0, 32.0,
-107.0, 33.0,
-102.0, 31.0,
-102.0, 35.0]),
material : Cesium.Color.RED
}
});
var greenPolygon = viewer.entities.add({
name : '綠色拉伸多邊形',
polygon : {
hierarchy : Cesium.Cartesian3.fromDegreesArray([-108.0, 42.0,
-100.0, 42.0,
-104.0, 40.0]),
extrudedHeight: 500000.0,
material : Cesium.Color.GREEN
}
});
var orangePolygon = viewer.entities.add({
name : '每個頂點具有不同拉伸高度的橘色多邊形',
polygon : {
hierarchy : Cesium.Cartesian3.fromDegreesArrayHeights(
[-108.0, 25.0, 100000,
-100.0, 25.0, 100000,
-100.0, 30.0, 100000,
-108.0, 30.0, 300000]),
extrudedHeight: 0,
perPositionHeight : true,
material : Cesium.Color.ORANGE,
outline : true,
outlineColor : Cesium.Color.BLACK
}
});
var bluePolygon = viewer.entities.add({
name : '具有挖空效果的藍色多邊形',
polygon : {
hierarchy : {
positions : Cesium.Cartesian3.fromDegreesArray(
[-99.0, 30.0,
-85.0, 30.0,
-85.0, 40.0,
-99.0, 40.0]),
holes : [{
positions : Cesium.Cartesian3.fromDegreesArray([
-97.0, 31.0,
-97.0, 39.0,
-87.0, 39.0,
-87.0, 31.0
]),
holes : [{
positions : Cesium.Cartesian3.fromDegreesArray([
-95.0, 33.0,
-89.0, 33.0,
-89.0, 37.0,
-95.0, 37.0
]),
holes : [{
positions : Cesium.Cartesian3.fromDegreesArray([
-93.0, 34.0,
-91.0, 34.0,
-91.0, 36.0,
-93.0, 36.0
])
}]
}]
}]
},
material : Cesium.Color.BLUE,
outline : true,
outlineColor : Cesium.Color.BLACK
}
});
(6)多段線(Polylines)
var redLine = viewer.entities.add({
name : '沿著地球表面的紅線',
polyline : {
positions : Cesium.Cartesian3.fromDegreesArray(
[-75, 35,
-125, 35]),
width : 5,
material : Cesium.Color.RED
}
});
var glowingLine = viewer.entities.add({
name : '具有發光效果的線',
polyline : {
positions : Cesium.Cartesian3.fromDegreesArray(
[-75, 37, -125, 37]
),
width : 10,
material : new Cesium.PolylineGlowMaterialProperty({
glowPower : 0.2,
color : Cesium.Color.BLUE
})
}
});
var orangeOutlined = viewer.entities.add({
name : '具有一定高度的線',
polyline : {
positions : Cesium.Cartesian3.fromDegreesArrayHeights(
[-75, 39, 250000,-125, 39, 250000]
),
width : 5,
material : new Cesium.PolylineOutlineMaterialProperty({
color : Cesium.Color.ORANGE,
outlineWidth : 2,
outlineColor : Cesium.Color.BLACK
})
}
});
var yellowLine = viewer.entities.add({
name : '不貼著地表的線',
polyline : {
positions : Cesium.Cartesian3.fromDegreesArrayHeights(
[-75, 43, 500000,-125, 43, 500000]
),
width : 3,
followSurface : false, //是否貼著地表
material : Cesium.Color.PURPLE
}
});
(7)多段線體(Polyline
Volumes)var viewer = new Cesium.Viewer('cesiumContainer');
function computeCircle(radius) {
var positions = [];
for (var i = 0; i < 360; i++) {
var radians = Cesium.Math.toRadians(i);
positions.push(new Cesium.Cartesian2(
radius * Math.cos(radians), radius * Math.sin(radians)));
}
return positions;
}
function computeStar(arms, rOuter, rInner) {
var angle = Math.PI / arms;
var length = 2 * arms;
var positions = new Array(length);
for (var i = 0; i < length; i++) {
var r = (i % 2) === 0 ? rOuter : rInner;
positions[i] = new Cesium.Cartesian2(
Math.cos(i * angle) * r, Math.sin(i * angle) * r);
}
return positions;
}
var redTube = viewer.entities.add({
name : 'Red tube with rounded corners',
polylineVolume : {
positions : Cesium.Cartesian3.fromDegreesArray(
[-85.0, 32.0,
-85.0, 36.0,
-89.0, 36.0]),
shape : computeCircle(60000.0),
material : Cesium.Color.RED
}
});
var greenBox = viewer.entities.add({
name : 'Green box with beveled corners and outline',
polylineVolume : {
positions : Cesium.Cartesian3.fromDegreesArrayHeights(
[-90.0, 32.0, 0.0,
-90.0, 36.0, 100000.0,
-94.0, 36.0, 0.0]),
shape :[new Cesium.Cartesian2(-50000, -50000),
new Cesium.Cartesian2(50000, -50000),
new Cesium.Cartesian2(50000, 50000),
new Cesium.Cartesian2(-50000, 50000)],
cornerType : Cesium.CornerType.BEVELED,
material : Cesium.Color.GREEN,
outline : true,
outlineColor : Cesium.Color.BLACK
}
});
var blueStar = viewer.entities.add({
name : 'Blue star with mitered corners and outline',
polylineVolume : {
positions : Cesium.Cartesian3.fromDegreesArrayHeights(
[-95.0, 32.0, 0.0,
-95.0, 36.0, 100000.0,
-99.0, 36.0, 200000.0]),
shape : computeStar(7, 70000, 50000),
cornerType : Cesium.CornerType.MITERED,
material : Cesium.Color.BLUE,
outline : true,
outlineColor : Cesium.Color.BLACK
}
});
viewer.zoomTo(viewer.entities);
(8)矩形(Rectangles)
<strong>//紅色矩形
var redRectangle = viewer.entities.add({
name : 'Red translucent rectangle with outline',
rectangle : {
coordinates : Cesium.Rectangle.fromDegrees(-110.0, 20.0, -80.0, 25.0),
material : Cesium.Color.RED.withAlpha(0.5),
outline : true,
outlineColor : Cesium.Color.RED
}
});
//綠色旋轉、拉伸的矩形
var greenRectangle = viewer.entities.add({
name : 'Green translucent, rotated, and extruded rectangle',
rectangle : {
coordinates : Cesium.Rectangle.fromDegrees(-100.0, 30.0, -90.0, 40.0),
material : Cesium.Color.GREEN.withAlpha(0.5),
rotation : Cesium.Math.toRadians(45),
extrudedHeight : 300000.0,
height : 100000.0,
outline : true,
outlineColor : Cesium.Color.GREEN
}
});</strong>
(9)球和橢球(Spheres Ellipsoids)
<pre name="code" class="javascript">var blueEllipsoid = viewer.entities.add({
name : 'Blue ellipsoid',
position: Cesium.Cartesian3.fromDegrees(-114.0, 40.0, 300000.0),
ellipsoid : {
//可以指定三個軸的半徑
radii : new Cesium.Cartesian3(200000.0, 200000.0, 300000.0),
material : Cesium.Color.BLUE
}
});
var redSphere = viewer.entities.add({
name : 'Red sphere with black outline',
position: Cesium.Cartesian3.fromDegrees(-107.0, 40.0, 300000.0),
ellipsoid : {
//正球體
radii : new Cesium.Cartesian3(300000.0, 300000.0, 300000.0),
material : Cesium.Color.RED,
outline : true,
outlineColor : Cesium.Color.BLACK
}
});
var outlineOnly = viewer.entities.add({
name : 'Yellow ellipsoid outline',
position: Cesium.Cartesian3.fromDegrees(-100.0, 40.0, 300000.0),
ellipsoid : {
radii : new Cesium.Cartesian3(200000.0, 200000.0, 300000.0),
fill : false,
outline : true,
outlineColor : Cesium.Color.YELLOW,
slicePartitions : 24, //橫向切割線
stackPartitions : 36 //縱向切割線
}
});
(10) 牆(Walls)
//東西方向的橫牆
var redWall = viewer.entities.add({
name : 'Red wall at height',
wall : {
positions : Cesium.Cartesian3.fromDegreesArrayHeights(
[-115.0, 44.0, 200000.0,//座標點
-90.0, 44.0, 200000.0]
),
minimumHeights : [100000.0, 100000.0], //按座標點的最小高度陣列
material : Cesium.Color.RED
}
});
//四邊圍牆
var greenWall = viewer.entities.add({
name : 'Green wall from surface with outline',
wall : {
positions : Cesium.Cartesian3.fromDegreesArrayHeights(
[-107.0, 43.0, 100000.0,
-97.0, 43.0, 100000.0,
-97.0, 40.0, 100000.0,
-107.0, 40.0, 100000.0,
-107.0, 43.0, 100000.0]),
material : Cesium.Color.GREEN,
outline : true,
outlineColor : Cesium.Color.BLACK
}
});
//曲折的牆
var blueWall = viewer.entities.add({
name : 'Blue wall with sawtooth heights and outline',
wall : {
//座標點,不指定高度
positions : Cesium.Cartesian3.fromDegreesArray(
[-115.0, 50.0,
-112.5, 50.0,
-110.0, 50.0,
-107.5, 50.0,
-105.0, 50.0,
-102.5, 50.0,
-100.0, 50.0,
-97.5, 50.0,
-95.0, 50.0,
-92.5, 50.0,
-90.0, 50.0]),
maximumHeights : [ //上高
100000, 200000, 100000, 200000, 100000, 200000,
100000, 200000, 100000, 200000, 100000],
minimumHeights : [ //下高
0, 100000, 0, 100000, 0, 100000, 0, 100000, 0,
100000, 0],
material : Cesium.Color.BLUE,
outline : true,
outlineColor : Cesium.Color.BLACK
}
});
材質(Material)與輪廓(Outline)
多數形狀均支援通過一致的方式來設定屬性、控制外觀:
- (1)fill:布林型,用於指定目標形狀是否被填充
- (2)outline:布林型,用於指定是否繪製形狀的邊緣
- (3)material:如果fill為true,該屬性可以控制填充的材質型別
一個例外是多段線,可以設定outlineWidth 、outlineColor、glowPower 等屬性。
高度與拉伸(Extrusion)所有的形狀均預設均是沿著地表的,目前圓形、橢圓、矩形可以在一定高度浮空顯示,或者拉伸為Volume。
需要注意:Cesium總是使用米、弧度、秒為度量單位。下面是一個例子:
wyoming.polygon.height = 200000; //設定高度
wyoming.polygon.extrudedHeight = 250000; //設定拉伸高度
在Viewer中可用的Entity特性
除非顯式禁用,點選實體後會顯示SelectionIndicator小器件,以及一個資訊框。通過設定Entity.description,可以在資訊框中顯示任何HTML內容。
鏡頭控制zoomTo方法可以立即定位到某個位置,而flyTo則是通過動畫方式轉移到某個位置,這兩個方法均可以傳遞EntityCollection物件,並且均是非同步方法,返回一個Promises物件
預設情況下,鏡頭是朝北、45度傾斜檢視地球。下面的程式碼可以讓鏡頭朝東、傾斜三十度檢視:
//鏡頭順時針旋轉九十度,即東向
var heading = Cesium.Math.toRadians(90);
//鏡頭傾斜30度俯視
var pitch = Cesium.Math.toRadians(-30);
viewer.zoomTo(wyoming, new Cesium.HeadingPitchRange(heading, pitch)).then(function(result){
//執行完畢後,進行的動作
if (result) { //如果鏡頭切換成功,則result=true
viewer.selectedEntity = wyoming;
}
});
有時需要鏡頭跟蹤某個實體(使居中)而不是地球,可以使用如下程式碼:
wyoming.position = Cesium.Cartesian3.fromDegrees(-107.724, 42.68);
viewer.trackedEntity = wyoming; //跟蹤某個實體。如果呼叫zoomTo、flyTo自動取消跟蹤
管理Entity
EntityCollection物件是一個從Entity Id到Entity的關聯陣列,其提供例如add、remove、removeAll之類的常規函式,用於新增或者刪除某個Entity:
//新增一個實體,並且提供ID
viewer.entities.add({
id : '182bdba4-2b3e-47ae-bf0b-83f6fde285fd'
});
//獲取一個實體
var entity = viewer.entities.getById('uniqueId')
//獲取一個實體,如果不存在則建立之
var entity = viewer.entities.getOrCreateEntity('uniqueId');
//當新增、刪除、修改EntityCollection中的Entity時,可以獲得事件通知
function onChanged(collection, added, removed, changed){
//add、removed、changed是增刪改的Entity陣列
for(var i = 0; i < added.length; i++) {
}
}
viewer.entities.collectionChanged.addEventListener(onChanged);
//大批量操作時,臨時禁用事件可以提高效能
viewer.entities.suspendEvents();
//執行各種Entity操作
viewer.entities.resumeEvents();
點、圖示和標籤
新增一個點、標籤或者圖示很簡單:
var viewer = new Cesium.Viewer( 'cesiumContainer' );
var citizensBankPark = viewer.entities.add( {
name : 'Citizens Bank Park',
position : Cesium.Cartesian3.fromDegrees( -75.166493, 39.9060534 ),
point : { //點
pixelSize : 5,
color : Cesium.Color.RED,
outlineColor : Cesium.Color.WHITE,
outlineWidth : 2
},
label : { //文字標籤
text : 'Citizens Bank Park',
font : '14pt monospace',
style : Cesium.LabelStyle.FILL_AND_OUTLINE,
outlineWidth : 2,
verticalOrigin : Cesium.VerticalOrigin.BOTTOM, //垂直方向以底部來計算標籤的位置
pixelOffset : new Cesium.Cartesian2( 0, -9 ) //偏移量
}
billboard : { //圖示
image : 'http://localhost:81/images/2015/02-02/Philadelphia_Phillies.png',
width : 64,
height : 64
},
} );
viewer.zoomTo( viewer.entities );
3D模型
Cesium支援glTF格式的3D模型,glTF是WebGL、 OpenGL ES、 OpenGL的一種執行時模型格式,在Cesium中建立3D模型很簡單:
var viewer = new Cesium.Viewer('cesiumContainer');
var entity = viewer.entities.add({
position : Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706),
model : {
uri : '../../SampleData/models/CesiumGround/Cesium_Ground.gltf'
},
scale : 1,//和原始大小相比的縮放比例
minimumPixelSize :100 //最小尺寸,防止太小而看不見
});
viewer.trackedEntity = entity;
預設情況下,模型豎直放置、並且面向東面。可以指定四元組(Quaternion)給Entity.orientation屬性,以改變放置的方向:
var viewer = new Cesium.Viewer('cesiumContainer');
var position = Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706); //位置
var heading = Cesium.Math.toRadians(45.0);//繞垂直於地心的軸旋轉
var pitch = Cesium.Math.toRadians(15.0); //繞緯度線旋轉
var roll = Cesium.Math.toRadians(0.0); //繞經度線旋轉
var orientation = Cesium.Transforms.headingPitchRollQuaternion(position, heading, pitch, roll);
var entity = viewer.entities.add({
position : position,
orientation : orientation,
model : {
uri : '../../SampleData/models/CesiumGround/Cesium_Ground.gltf'
}
});
viewer.trackedEntity = entity;
例子中的heading(yaw)、pitch、roll對應了繞Z(垂直軸)、Y(維度方向)、X(經度方向)進行旋轉,正數表示順時針旋轉(由於相對運動,在瀏覽器上看起來是地球在逆時針旋轉),可以參考下圖理解(人面向北面,搖頭heading、點頭pitch、歪頭roll):
Cesium提供了一些快捷方式來設定屬性,例如outline:true,但是嘗試使用e.polygon.outline這樣的形式來獲取輪廓時,會得到一個ConstantProperty物件,如果不使用快捷方式,則需要編寫更多的程式碼,例如:
polygon.outline = new Cesium.ConstantProperty(true);
polygon.outlineColor = new Cesium.ConstantProperty(Cesium.Color.BLACK);
所有屬性的例項均是Property的子型別,引入屬性類層次而不是使用基本型別的原因是,某些屬性是隨著時間而變化的。
要得到屬性的原始值,需要呼叫Property.getValue()方法,例如:
//獲取當前時間點,多邊形輪廓是否存在
polygon.outline.getValue(viewer.clock.currentTime)