空间数据可视化之Entity
Cesium在空间数据可视化方面提供了两种类型的API,一种是面向图形开发人员的低级(原始)API,通过Primitive类实现,对于那些对计算机图形学知识很了解的同学可以采用Primitive API;另一种是用于数据驱动的高级(实体)API,通过Entity类实现,相对于Primitive API,Entity API实现起来更简单一些,特别建议初学者使用。Entity API 实际上是对Primitive API的二次封装,底层调用的仍然是Primitive API,目的就是为我们提供灵活的、易学、易用的高性能可视化界面。使用Cesium的Entity API我们可以去绘制空间数据,如点,图标,文字标注,折线,模型,图形和立体图形。
Entity支持的图形类型
通过在Cesium API文档中查看Entity类的构造函数,我们发现Entity支持的图形类型都是以Graphics结尾的,一共有17种类型:
billboard 广告牌
var entity = viewer.entities.add({
name: "billboard",
position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883),
billboard: {
show: true,
image: "./images/Cesium_Logo_overlay.png",
scale: 2.0,
pixelOffset: new Cesium.Cartesian2(0, -50),
eyeOffset: new Cesium.Cartesian3(0.0, 0.0, 0.0),
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
color: Cesium.Color.LIME,
rotation: Cesium.Math.PI_OVER_FOUR,
alignedAxis: Cesium.Cartesian3.ZERO,
width: 100,
height: 25,
scaleByDistance: new Cesium.NearFarScalar(1.0e3, 2.0, 2.0e3, 1.0),
translucencyByDistance: new Cesium.NearFarScalar(
1.0e3,
1.0,
1.5e6,
0.5
),
pixelOffsetScaleByDistance: new Cesium.NearFarScalar(
1.0e3,
1.0,
1.5e6,
0.0
),
disableDepthTestDistance: Number.POSITIVE_INFINITY,
},
});
viewer.zoomTo(entity);
var billboard = entity.billboard;
billboard.scale = 3.0;
billboard.color = Cesium.Color.WHITE.withAlpha(0.25);
box 盒子
var entity = viewer.entities.add({
name: "box",
position: Cesium.Cartesian3.fromDegrees(-107.0, 40.0, 300000.0),
box: {
show: true,
dimensions: new Cesium.Cartesian3(400000.0, 300000.0, 500000.0),
heightReference: Cesium.HeightReference.NONE,
fill: true,
material: Cesium.Color.RED.withAlpha(0.5),
outline: true,
outlineColor: Cesium.Color.BLACK,
outlineWidth: 1.0,
shadows: Cesium.ShadowMode.DISABLED,
},
});
viewer.zoomTo(entity);
corridor 走廊
var entity = viewer.entities.add({
name: "corridor",
corridor: {
// 指定定义走廊中心线的 Cartesian3 位置的数组 type: Cartesian3
positions: Cesium.Cartesian3.fromDegreesArray([
-80.0,
40.0,
-85.0,
40.0,
-85.0,
35.0,
]),
width: 200000.0,
height: 200000.0,
heightReference: Cesium.HeightReference.NONE,
extrudedHeight: 100000.0,
extrudedHeightReference: Cesium.HeightReference.NONE,
// 拐角的样式 type:CornerType default:CornerType.ROUNDED
// ROUNDED 角有光滑的边缘;MITERED 拐角点是相邻边的交点;BEVELED 角被修剪
cornerType: Cesium.CornerType.ROUNDED,
// 每个纬度和经度之间的距离
granularity: Cesium.Math.RADIANS_PER_DEGREE,
fill: true,
// 材质 type:MaterialProperty|Color default:Color.WHITE
material: Cesium.Color.BLUE.withAlpha(0.5),
outline: true,
outlineColor: Cesium.Color.WHITE,
outlineWidth: 1.0,
shadows: Cesium.ShadowMode.DISABLED,
// 走廊在地面上时将对地形,3D tiles还是对两者进行分类 type:ClassificationType default:ClassificationType.BOTH
// TERRAIN 将仅对地形进行分类;CESIUM_3D_TILE 将仅对3D Tiles进行分类;BOTH 将同时对Terrain和3D Tiles进行分类。
classificationType: Cesium.ClassificationType.BOTH,
},
});
cylinder 圆柱、圆锥
var entity = viewer.entities.add({
name: "cylinder",
position: Cesium.Cartesian3.fromDegrees(-105.0, 40.0, 200000.0),
cylinder: {
length: 400000.0,
topRadius: 200000.0,
bottomRadius: 200000.0,
heightReference: Cesium.HeightReference.NONE,
fill: true,
material: Cesium.Color.GREEN.withAlpha(0.5),
outline: true,
outlineColor: Cesium.Color.DARK_GREEN,
outlineWidth: 1.0,
// 沿轮廓的周长绘制的垂直线的数量
numberOfVerticalLines: 16,
shadows: Cesium.ShadowMode.DISABLED,
// 圆柱周围的边缘数量
slices: 128,
},
});
ellipsoid 椭球体
var entity = viewer.entities.add({
name: "Spheres and Ellipsoids",
position: Cesium.Cartesian3.fromDegrees(-100.0, 40.0, 300000.0),
ellipsoid: {
show: true,
radii: new Cesium.Cartesian3(200000.0, 200000.0, 300000.0),
minimumClock: 0.0,
maximumClock: 2 * Math.PI,
minimumCone: 0.0,
maximumCone: Math.PI,
heightReference: Cesium.HeightReference.NONE,
fill: true,
material: Cesium.Color.BLUE.withAlpha(0.5),
outline: true,
outlineColor: Cesium.Color.YELLOW,
outlineWidth: 1.0,
stackPartitions: 64,
slicePartitions: 64,
subdivisions: 128,
shadows: Cesium.ShadowMode.DISABLED,
},
});
label 标签
var citizensBankPark = viewer.entities.add({ name : 'Citizens Bank Park', position : Cesium.Cartesian3.fromDegrees(-75.166493, 39.9060534), 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) } });
model 模型
var position = Cesium.Cartesian3.fromDegrees(
-123.0744619,
44.0503706,
5000.0
);
var heading = Cesium.Math.toRadians(135);
var pitch = 0;
var roll = 0;
var hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
var orientation = Cesium.Transforms.headingPitchRollQuaternion(
position,
hpr
);
var url = "./data/models/CesiumAir/Cesium_Air.glb";
var entity = viewer.entities.add({
name: "model",
position: position,
orientation: orientation,
model: {
show: true,
uri: url,
scale: 1.0,
minimumPixelSize: 128,
maximumScale: 20000,
incrementallyLoadTextures: true,
runAnimations: true,
clampAnimations: true,
shadows: Cesium.ShadowMode.DISABLED,
heightReference: Cesium.HeightReference.NONE,
silhouetteColor: Cesium.Color.RED,
silhouetteSize: 0.0,
color: Cesium.Color.WHITE,
colorBlendMode: Cesium.ColorBlendMode.HIGHLIGHT,
colorBlendAmount: 0.5,
imageBasedLightingFactor: new Cesium.Cartesian2(1.0, 1.0),
lightColor: undefined,
},
});
tileset 3D Tiles瓦片集
var entity = viewer.entities.add({ name: "3D Tiles", position: Cesium.Cartesian3.fromDegrees(-114.0, 40.0, 300000.0), tileset: { show: true, uri: "./data/Cesium3DTiles/Tilesets/Tileset/tileset.json", }, });
plane 平面
var entity= viewer.entities.add({
name: "Blue plane",
position: Cesium.Cartesian3.fromDegrees(-114.0, 40.0, 300000.0),
plane: {
show: true,
plane: new Cesium.Plane(Cesium.Cartesian3.UNIT_X, 0.0),
dimensions: new Cesium.Cartesian2(400000.0, 300000.0),
fill: true,
material: Cesium.Color.BLUE,
outline: false,
outlineColor: Cesium.Color.BLACK,
outlineWidth: 1.0,
shadows: Cesium.ShadowMode.DISABLED,
},
});
point 点
var entity = viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883), point: { show: true, pixelSize: 10, // 像素大小 heightReference: Cesium.HeightReference.NONE, color: Cesium.Color.YELLOW, outlineColor: Cesium.Color.BLACK, outlineWidth: 0, scaleByDistance: new Cesium.NearFarScalar(1.0e3, 10.0, 2.0e3, 1.0), translucencyByDistance: new Cesium.NearFarScalar( 1.0e3, 1.0, 1.5e6, 0.5 ), // distanceDisplayCondition: new Cesium.DistanceDisplayCondition( // 1.0e3, // 2.0e3 // ), // 获取或设置与相机的距离,在深度处禁用深度测试,例如,以防止剪切地形。 // 设置为零时,将始终应用深度测试。设置为Number.POSITIVE_INFINITY时,永远不会应用深度测试。 disableDepthTestDistance: Number.POSITIVE_INFINITY, }, });
polygon 多边形
var entity = viewer.entities.add({ name: "Red polygon on surface", polygon: { show: true, hierarchy: Cesium.Cartesian3.fromDegreesArray([ -115.0, 37.0, -115.0, 32.0, -107.0, 33.0, -102.0, 31.0, -102.0, 35.0, ]), height: 0, heightReference: Cesium.HeightReference.NONE, stRotation: 0.0, granularity: Cesium.Math.RADIANS_PER_DEGREE, fill: true, material: Cesium.Color.RED, outline: false, outlineColor: Cesium.Color.BLACK, outlineWidth: 1.0, perPositionHeight: false, closeTop: true, closeBottom: true, arcType: Cesium.ArcType.GEODESIC, shadows: Cesium.ShadowMode.DISABLED, classificationType: Cesium.ClassificationType.BOTH, zIndex: 0, }, });
polyline 多线段
var entity= viewer.entities.add({ name: "Red line on terrain", polyline: { show: true, positions: Cesium.Cartesian3.fromDegreesArray([-75, 35, -125, 35]), width: 5, material: Cesium.Color.RED, clampToGround: true, shadows: Cesium.ShadowMode.DISABLED, classificationType: Cesium.ClassificationType.BOTH, }, });
polylineVolume 多线段柱体
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; } var entity= viewer.entities.add({ name: "Red tube with rounded corners", polylineVolume: { show: true, positions: Cesium.Cartesian3.fromDegreesArray([ -85.0, 32.0, -85.0, 36.0, -89.0, 36.0, ]), shape: computeCircle(60000.0), cornerType: Cesium.CornerType.ROUNDED, fill: true, material: Cesium.Color.RED, outline: false, outlineColor: Cesium.Color.BLACK, outlineWidth: 1.0, shadows: Cesium.ShadowMode.DISABLED, }, });
rectangle 矩形
var entity= viewer.entities.add({ name: "Red translucent rectangle", rectangle: { show: true, coordinates: Cesium.Rectangle.fromDegrees(-110.0, 20.0, -80.0, 25.0), rotation: 0.0, stRotation: 0.0, granularity: Cesium.Math.RADIANS_PER_DEGREE, fill: true, material: Cesium.Color.RED.withAlpha(0.5), outline: false, outlineColor: Cesium.Color.BLACK, outlineWidth: 1.0, shadows: Cesium.ShadowMode.DISABLED, classificationType: Cesium.ClassificationType.BOTH, zIndex: 0, }, });
wall 墙
var entity= viewer.entities.add({ name: "Red wall at height", wall: { show: true, positions: Cesium.Cartesian3.fromDegreesArrayHeights([ -115.0, 44.0, 200000.0, -90.0, 44.0, 200000.0, ]), minimumHeights: [100000.0, 100000.0], granularity: Cesium.Math.RADIANS_PER_DEGREE, fill: true, material: Cesium.Color.RED, outline: false, outlineColor: Cesium.Color.BLACK, outlineWidth: 1.0, shadows: Cesium.ShadowMode.DISABLED, }, });
材质和边线
无论各种几何体有什么不同,所有形状和体都有一系列相同的属性来控制它们的外观。fill
为boolean类型,控制表面是否填充。 outline
属性控制是否有外边界。当 fill
=true
,material
属性决定了用什么材质填充表面。
当设置颜色或者url之后Cesium会自动创建 ColorMaterialProperty 或者ImageMaterialProperty对象。 对于更复杂的材质, 需要手动创建 MaterialProperty对象。 当前, Entity 面和体支持 颜色(colors),纹理图片( images),棋盘 (checkerboard), 条纹(stripe), 网格(grid)等材质
半透明
var entity = viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(-103.0, 40.0), ellipse : { semiMinorAxis : 250000.0, semiMajorAxis : 400000.0, material : Cesium.Color.BLUE.withAlpha(0.5) } }); viewer.zoomTo(entity);
图片
var entity = viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(-103.0, 40.0), ellipse : { semiMinorAxis : 250000.0, semiMajorAxis : 400000.0, material : './images/Cesium_Logo_overlay.png' } }); viewer.zoomTo(entity);
网格
var entity = viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(-103.0, 40.0), ellipse: { semiMinorAxis: 250000.0, semiMajorAxis: 400000.0, material: new Cesium.CheckerboardMaterialProperty({ evenColor: Cesium.Color.WHITE, oddColor: Cesium.Color.BLACK, repeat: new Cesium.Cartesian2(4, 4), }), }, }); viewer.zoomTo(entity);
条纹
var entity = viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(-103.0, 40.0), ellipse: { semiMinorAxis: 250000.0, semiMajorAxis: 400000.0, material: new Cesium.StripeMaterialProperty({ evenColor: Cesium.Color.WHITE, oddColor: Cesium.Color.BLACK, repeat: 32, }), }, }); viewer.zoomTo(entity);
网格
var entity = viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(-103.0, 40.0), ellipse: { semiMinorAxis: 250000.0, semiMajorAxis: 400000.0, material: new Cesium.GridMaterialProperty({ color: Cesium.Color.YELLOW, cellAlpha: 0.2, lineCount: new Cesium.Cartesian2(8, 8), lineThickness: new Cesium.Cartesian2(2.0, 2.0), }), }, }); viewer.zoomTo(entity);
边线
和
注意
fill
属性不太一样,outline
没有对应的材质配置,而是用两个独立的属性outlineColor
和outlineWidth
。注意
outlineWidth
属性仅仅在非windows系统上有效,比如Android, iOS, Linux, 和OS X。Windows系统上边线宽度永远为1var entity = viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(-103.0, 40.0), ellipse: { semiMinorAxis: 250000.0, semiMajorAxis: 400000.0, fill:false, outlineColor:Cesium.Color.RED, outlineWidth:2.0, outline:true, }, }); viewer.zoomTo(entity);
折线
ar entity = viewer.entities.add({ polyline: { positions: Cesium.Cartesian3.fromDegreesArray([77, 35, 75, 34, 60, 30]), width: 5, material: new Cesium.PolylineOutlineMaterialProperty({ color: Cesium.Color.ORANGE, outlineWidth: 3, outlineColor: Cesium.Color.BLUE, }), }, }); viewer.
高度和垂直挤压
所有的面形状都是平铺在地球上,当前 圆(circles)、椭圆(ellipses)、多边形(polygons)、矩形(rectangles)可以有一个高程属性 或者 垂直挤压变成体。这两种情况种,这些面或者体仍然会贴合地球曲率。
上面我们列出的所有图形,都是只需要在图形对象(graphics )上设置一个高度属性即可。这里顺便说明下,除非在函数上明确说明,否则Cesium总是使用米、弧度、秒做为标准单位。如Cartesian3.fromDegrees.
View Code
上面我们列出的所有图形,都是只需要在图形对象(graphics )上设置一个高度属性即可。这里顺便说明下,除非在函数上明确说明,否则Cesium总是使用米、弧度、秒做为标准单位。如Cartesian3.fromDegrees.
把图形挤压为体,也非常简单。仅仅需要设置
extrudedHeight
属性。将会创建一个在height
和extrudedHeight
之间的体块。如果 height
没有定义, 体块从 0高程开始。下面代码创建一个从200,000米到 250,000米的体 。也就是说这个体的高度是50000米。var entity = viewer.entities.add({ polygon: { hierarchy: Cesium.Cartesian3.fromDegreesArray([ -109.080842, 45.002073, -105.91517, 45.002073, -111.047063, 42.000709, -111.047063, 44.476286, -111.05254, 45.002073, ]), height: 200000, extrudedHeight: 250000, material: Cesium.Color.RED.withAlpha(0.5), outline: true, outlineColor: Cesium.Color.BLACK, }, }); viewer.zoomTo(viewer.entities);
管理Entity集合
EntityCollection类是一个Entity数组集合,用来它管理和控制一组entity非常方便。我们已经见过它的一个实例 viewer.entities 属性。EntityCollection 提供了基本的数组方法 add, remove, 和 removeAll;同时还有下面我们要讨论的一些特有方法或者属性。
很多项目的数据实际都是存在服务端的,只有客户端需要的时候才会加载。有时候需要更改一个我们已经创建的entity。所有entity对象都有一个独一无二的 id 属性,这种情况情况下就非常有用。前面的示例里,我们并没有指定这个id,Cesium会自动生成一个 GUID 类似
很多项目的数据实际都是存在服务端的,只有客户端需要的时候才会加载。有时候需要更改一个我们已经创建的entity。所有entity对象都有一个独一无二的 id 属性,这种情况情况下就非常有用。前面的示例里,我们并没有指定这个id,Cesium会自动生成一个 GUID 类似
182bdba4-2b3e-47ae-bf0b-83f6fde285fd
填充到id属性里。服务端的数据一般都有自己主键id属性,所以可以在enity创建的时候指定这个id。随后,可以通过 getById来获取Entity对象。如果没有找到对应的id,那么该方法返回 undefined
。
另一个常见的应用,是如果id不存在就新建,如果id存在就更新。 getOrCreateEntity 总会返回以传入的参数为id的对象实例, 如果id不存在,那么会新建一个,并且增加到entity集合里,然后返回。
最后,简单的通过 add就可以新建一个Entity实例。这种情况下,add函数会检测如果传入了一个已经存在的id,那么会报异常。
EntityCollection 最强大的功能其实是collectionChanged Event,我们用它来接收集合里entity被添加、删除甚至更新的通知。当项目里的用户界面或者某个功能需要监控集合里的对象改变的时候,这个功能非常有用。
var viewer = new Cesium.Viewer("cesiumContainer"); function onChanged(collection, added, removed, changed) { var msg = "Added ids"; for (var i = 0; i < added.length; i++) { msg += "\n" + added[i].id; } console.log(msg); } viewer.entities.collectionChanged.addEventListener(onChanged); var entity = viewer.entities.add({ id: "test", polygon: { hierarchy: Cesium.Cartesian3.fromDegreesArray([ -109.080842, 45.002073, -105.91517, 45.002073, -111.047063, 42.000709, -111.047063, 44.476286, -111.05254, 45.002073, ]), height: 200000, extrudedHeight: 250000, material: Cesium.Color.RED.withAlpha(0.5), outline: true, outlineColor: Cesium.Color.BLACK, }, }); viewer.zoomTo(viewer.entities);