1. 程式人生 > >Cesium 概述 (二) 空間資料視覺化

Cesium 概述 (二) 空間資料視覺化

                                                              空間資料視覺化

Cesium提供Entity API來繪製空間資料,例如點、標記、標籤、線、3D模型、形狀、立體形狀(volume)。

Entity API簡介

Cesium提供兩類API:

  1. (1)面向圖形開發人員的底層API,通常稱為“Primitive API”。該API暴露最小限度的抽象,使用圖形學術語,具有很大的靈活性,需要具有圖形學程式設計的知識
  2. (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. (1)fill:布林型,用於指定目標形狀是否被填充
  2. (2)outline:布林型,用於指定是否繪製形狀的邊緣
  3. (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)