Cesium中文网:http://cesiumcn.org/ | 国内快速访问:http://cesium.coinidea.com/javascript
如今咱们已经为咱们的应用程序设置了Viewer配置、imagery和terrain的阶段,咱们能够添加咱们的应用程序的主要焦点——geocache数据。html
为了便于可视化,Cesium支持流行的矢量格式GeoJson和KML,以及一种咱们团队本身开源的格式,咱们专门开发用于描述Cesium场景的[]CZML](https://github.com/AnalyticalGraphicsInc/czml-writer/wiki/CZML-Guide)。java
不管初始格式如何,Cesium中的全部空间数据都使用Entity API来表示。Entity API以一种有效提供灵活的可视化的方式,以便对Cesium进行渲染。Cesium Entity是能够与样式化图形表示配对并定位在空间和时间上的数据对象。测试沙盒中提供了许多简单Entity的例子。为了在Entity API的基础上加快速度,从这个应用程序中休息一下,而后阅读可视化的空间数据教程 Visualizing Spatial Data tutorial。git
如下有一些关于不一样entity类型的例子:github
一旦你掌握了一个Entity的样子,用Cesium装载数据集将是变得容易理解。要读取数据文件,须要建立适合于数据格式的数据源DataSource,该数据源将解析在指定URL中承载的数据文件,并为数据集中的每一个地理空间对象建立包含Entity的EntityCollection。DataSource只是定义了一个接口——您须要的数据源的确切类型将取决于数据格式。例如,KML使用KmlDataSource源代码。好比:json
var kmlOptions = { camera : viewer.scene.camera, canvas : viewer.scene.canvas, clampToGround : true }; // Load geocache points of interest from a KML file // Data from : http://catalog.opendata.city/dataset/pediacities-nyc-neighborhoods/resource/91778048-3c58-449c-a3f9-365ed203e914 var geocachePromise = Cesium.KmlDataSource.load('./Source/SampleData/sampleGeocacheLocations.kml', kmlOptions);
上述代码读取咱们样例的geocahce点,从一个KML文件中,调用KmlDataSource.load(optinos)带一些配置。针对一个KmlDataSource,相机和Canvas配置项是必须的。clamptoGround选项激活了ground clamping**,一种流行的描述配置用因而地面的几何entities好比多边形和椭圆符合地形并且听从WGS84椭圆面。canvas
因为这些数据是异步加载的,所以针对KmlDataSource返回一个的Promise,它将包含咱们全部新建立的entities。promise
若是您不熟悉使用异步函数的PromiseAPI,这里的“异步”基本上意味着您应该在所提供的回调函数中完成所需的数据**.then.为了实际地将这些实体集合添加到场景中,咱们必须等待直到promise完成,而后将KmlDataSource添加viewer.datasrouces**。取消如下几行注释:浏览器
// Add geocache billboard entities to scene and style them geocachePromise.then(function(dataSource) { // Add the new data as entities to the viewer viewer.dataSources.add(dataSource); });
默认状况下,这些新建立的实体具备有用的功能。单击将显示与实体相关的元数据的信息框Infobox,并双击缩放并查看实体。若要中止查看该实体,请单击“home”按钮,或单击“信息框”上的“划出”相机图标。接下来,咱们将添加自定义样式来改善咱们的应用程序的外观style。dom
对于KML和CZML文件,能够在文件中创建声明式样式。然而,对于这个应用,让咱们练习手动设计咱们的实体。要作到这一点,咱们将采起相似的方法来处理这个样式示例,等待咱们的数据源加载,而后迭代数据源集合中的全部实体,修改和添加属性。默认状况下,咱们的geocache点标记被建立为Billboards和Labels,因此为了修改这些实体的外观,咱们这样作:
// Add geocache billboard entities to scene and style them geocachePromise.then(function(dataSource) { // Add the new data as entities to the viewer viewer.dataSources.add(dataSource); // Get the array of entities var geocacheEntities = dataSource.entities.values; for (var i = 0; i < geocacheEntities.length; i++) { var entity = geocacheEntities[i]; if (Cesium.defined(entity.billboard)) { // Entity styling code here } } });
咱们能够经过调整它们的锚点、去除标签来减小clutter和设置isplayDistanceCondition来改善标记的外观,使得只有在距相机的必定距离内的点是可见的。
// Add geocache billboard entities to scene and style them if (Cesium.defined(entity.billboard)) { // Adjust the vertical origin so pins sit on terrain entity.billboard.verticalOrigin = Cesium.VerticalOrigin.BOTTOM; // Disable the labels to reduce clutter entity.label = undefined; // Add distance display condition entity.billboard.distanceDisplayCondition = new Cesium.DistanceDisplayCondition(10.0, 20000.0); }
有关distanceDisplayCondition的更多帮助,请参见sandcastle example。
接下来,让咱们为每一个geocache实体改进信息框Infobox。信息框的标题是实体名称,内容是实体描述,显示为HTML。
你会发现默认的描述并非颇有帮助。因为咱们正在显示geocache 位置,让咱们更新它们来显示点的经度和纬度。
首先,咱们将实体的位置转换成地图,而后从Cartographic中读取经度和纬度,并将其添加到HTML表中的描述中。
在单击时,咱们的geocache 实体如今将显示一个格式良好的信息框Infobox,只须要咱们所须要的数据。
// Add geocache billboard entities to scene and style them if (Cesium.defined(entity.billboard)) { // Adjust the vertical origin so pins sit on terrain entity.billboard.verticalOrigin = Cesium.VerticalOrigin.BOTTOM; // Disable the labels to reduce clutter entity.label = undefined; // Add distance display condition entity.billboard.distanceDisplayCondition = new Cesium.DistanceDisplayCondition(10.0, 20000.0); // Compute longitude and latitude in degrees var cartographicPosition = Cesium.Cartographic.fromCartesian(entity.position.getValue(Cesium.JulianDate.now())); var longitude = Cesium.Math.toDegrees(cartographicPosition.longitude); var latitude = Cesium.Math.toDegrees(cartographicPosition.latitude); // Modify description // Modify description var description = '<table class="cesium-infoBox-defaultTable cesium-infoBox-defaultTable-lighter"><tbody>' + '<tr><th>' + "Longitude" + '</th><td>' + longitude.toFixed(5) + '</td></tr>' + '<tr><th>' + "Latitude" + '</th><td>' + latitude.toFixed(5) + '</td></tr>' + '</tbody></table>'; entity.description = description; }
咱们的geocache标记如今应该看起来像这样:
对于咱们的地理应用程序来讲,可视化特定点的邻域也会有帮助。让咱们试着为每一个纽约街区记载一个包含多边形的GeoJson文件。加载GeoJson文件最终很是相似于咱们刚刚用于KML的加载过程。可是在这种状况下,咱们使用GeoJsonDataSource。与前一个数据源同样,咱们须要将它添加到viewer.datasources中,以便实际添加数据到场景中。
var geojsonOptions = { clampToGround : true }; // Load neighborhood boundaries from KML file var neighborhoodsPromise = Cesium.GeoJsonDataSource.load('./Source/SampleData/neighborhoods.geojson', geojsonOptions); // Save an new entity collection of neighborhood data var neighborhoods; neighborhoodsPromise.then(function(dataSource) { // Add the new data as entities to the viewer viewer.dataSources.add(dataSource); });
让咱们来调整咱们加载的neighborhood多边形。就像咱们刚才作的billboard样式同样,咱们首先在数据源加载后迭代遍历neighborhood 数据源实体,此次检查每一个实体的多边形被定义:
// Save an new entity collection of neighborhood data var neighborhoods; neighborhoodsPromise.then(function(dataSource) { // Add the new data as entities to the viewer viewer.dataSources.add(dataSource); neighborhoods = dataSource.entities; // Get the array of entities var neighborhoodEntities = dataSource.entities.values; for (var i = 0; i < neighborhoodEntities.length; i++) { var entity = neighborhoodEntities[i]; if (Cesium.defined(entity.polygon)) { // entity styling code here } } });
既然咱们正在显示neighborhood,让咱们重命名每一个实体使用neighborhood做为它的名字。咱们所读的neighborhood中原始GeoJson文件做为属性。Cesium将GeoJson属性存储在enty.properties中,这样咱们就能够设置这样的neighborhood名称:
// entity styling code here // Use geojson neighborhood value as entity name entity.name = entity.properties.neighborhood;
咱们能够把每个多边形分配给一个新的颜色材料属性,经过ColorMaterialProperty设置随机颜色Color,而不是把全部的区域都设置成同样的颜色。
// entity styling code here // Set the polygon material to a random, translucent color. entity.polygon.material = Cesium.Color.fromRandom({ red : 0.1, maximumGreen : 0.5, minimumBlue : 0.5, alpha : 0.6 }); // Tells the polygon to color the terrain. ClassificationType.CESIUM_3D_TILE will color the 3D tileset, and ClassificationType.BOTH will color both the 3d tiles and terrain (BOTH is the default) entity.polygon.classificationType = Cesium.ClassificationType.TERRAIN;
最后,让咱们为每一个实体生成一个带有一些基本样式选项的标签Label。为了保持整洁,咱们可使用disableDepthTestDistance让Cesium老是把标签放在任何3D物体可能遮挡的地方。
然而,请注意,标签老是位于entity.position。多边形Polygon是由一个未定义的位置建立的,由于它有一个定义多边形边界的位置列表。咱们能够经过取多边形位置的中心来生成一个位置:
// entity styling code here // Generate Polygon position var polyPositions = entity.polygon.hierarchy.getValue(Cesium.JulianDate.now()).positions; var polyCenter = Cesium.BoundingSphere.fromPoints(polyPositions).center; polyCenter = Cesium.Ellipsoid.WGS84.scaleToGeodeticSurface(polyCenter); entity.position = polyCenter; // Generate labels entity.label = { text : entity.name, showBackground : true, scale : 0.6, horizontalOrigin : Cesium.HorizontalOrigin.CENTER, verticalOrigin : Cesium.VerticalOrigin.BOTTOM, distanceDisplayCondition : new Cesium.DistanceDisplayCondition(10.0, 8000.0), disableDepthTestDistance : 100.0 };
这给咱们标出了看起来像这样的多边形:
最后,让咱们经过在城市上空添加无人机飞行来增长咱们的NYC geocaches 的高科技视角。
因为飞行路径只是一系列随时间变化的位置,因此咱们能够从CZML文件中添加这些数据。CZML是一种用于描述时间动态图形场景的格式,主要用于在运行Cesium的Web浏览器中显示。它描述了线、点、billboards、模型和其余图形原语,并指定它们如何随时间变化。CZML之于Cesium,至关于KML之于谷歌地球的标准格式,它容许大多数Cesium功能特性经过声明式样式语言(在这种状况下是JSON模式)使用。
咱们的CZML文件定义了一个实体(默认为可视化的一个点),其位置被定义为在不一样时间点的一系列位置。实体API中有几种属性类型可用于处理时间动态数据。参见下面的演示示例:
// Load a drone flight path from a CZML file var dronePromise = Cesium.CzmlDataSource.load('./Source/SampleData/SampleFlight.czml'); dronePromise.then(function(dataSource) { viewer.dataSources.add(dataSource); });
CZML文件使用Cesium来显示无人机飞行,该路径是实体随时间显示其位置的属性。一条路径用插值法将离散点链接到一条连续的直线上进行可视化。 最后,让咱们改善无人机飞行的外观。首先,而不是简单地解决问题,咱们能够加载一个3D模型来表示咱们的无人机并将其附加到实体上。
Cesium支持基于glTF(GL传输格式)加载3D模型,这是Cesium团队与Khronos group一块儿开发的开放规范,用于经过最小化文件大小和运行时间处理来有效地加载应用程序的3D模型。没有gLTF模型吗?咱们提供了一个在线转换器,将COLLADA和OBJ文件转换为glTF格式。
让咱们加载一个无人机模型Model,具备良好的基于物理的阴影和一些动画:
var drone; dronePromise.then(function(dataSource) { viewer.dataSources.add(dataSource); // Get the entity using the id defined in the CZML data drone = dataSource.entities.getById('Aircraft/Aircraft1'); // Attach a 3D model drone.model = { uri : './Source/SampleData/Models/CesiumDrone.gltf', minimumPixelSize : 128, maximumScale : 1000, silhouetteColor : Cesium.Color.WHITE, silhouetteSize : 2 }; });
如今咱们的模型看起来不错,但与原来的点不一样,无人机模型具备方向性,当无人驾驶飞机向前移动时,它看起来很奇怪。幸运的是,Cesium提供了一种VelocityOrientationProperty,它将根据一个实体向前和向后采样的位置自动计算方向:
// Add computed orientation based on sampled positions drone.orientation = new Cesium.VelocityOrientationProperty(drone.position);
如今咱们的无人驾驶飞机模型将如期进行。
还有一件事咱们能够作的是改善咱们的无人机飞行的外观。从远处看,它可能并不明显,但无人机的路径是由看起来不天然的线段组成的,这是由于Cesium使用线性插值来构建从默认采样点的路径。然而,能够配置插值选项。
为了得到更平滑的飞行路径,咱们能够改变这样的插值选项:
// Smooth path interpolation drone.position.setInterpolationOptions({ interpolationDegree : 3, interpolationAlgorithm : Cesium.HermitePolynomialApproximation });
Cesium中文网交流QQ群:807482793
Cesium中文网:http://cesiumcn.org/ | 国内快速访问:http://cesium.coinidea.com/