cesium系列篇:Entity vs Primitive 源码解析(从Entity到Primitive)01

Entity 和 Primitive的关系

官方教材中提到,Primitive API主要适用于图形渲染开发者,Entity API则适用于数据驱动的可视化,而Entity API的底层则使用了Primitive API。下面我们将通过cesium的源码探究当添加entity对象时,是如何在底层调用对应的Primitive API,创建相应的primitive对象。

这篇文章中,我们将先从viewer初始化开始,探究各个对象之间的关系以及其相互之间的相应关系。

这是下文中涉及到的类的类图,从中可以清晰的了解各个对象之间的关系,接下来我们结合代码来仔细讲解。

在这里插入图片描述

地球伊始

  1. 通过viewer.entities我们定位到下面三个目标_dataSourceDisplaydefaultDataSourceentities
  entities: {get: function () {return this._dataSourceDisplay.defaultDataSource.entities;},},
  1. 看一下他们分别是如何创建的
  • 在对象viewer中创建对象_dataSourceDisplay
 // 创建dataSourceDisplay对象const dataSourceDisplay = new DataSourceDisplay({scene: scene,dataSourceCollection: dataSourceCollection,});this._dataSourceDisplay = dataSourceDisplay;
  • 创建defaultDataSource
const defaultDataSource = new CustomDataSource();
  • 创建对象_entityCollection
    • 结合下面的代码我们知道entities其实对应的是属性_entityCollection
  /*** Gets the collection of {@link Entity} instances.* @memberof CustomDataSource.prototype* @type {EntityCollection}*/entities: {get: function () {return this._entityCollection;},},
    • 创建_entityCollection
this._entityCollection = new EntityCollection(this);

事件发出

  1. 可以发现在调用_entityCollection对象的add函数时,其内部调用了fireChangedEvent函数
EntityCollection.prototype.add = function (entity) {// 创建entity对象if (!(entity instanceof Entity)) {entity = new Entity(entity);}// 发出信号fireChangedEvent(this);return entity;
};
  1. fireChangedEvent则对外发出了一个信号,其中包含了当前添加的对象、移除的对象以及发生变化的对象
function fireChangedEvent(collection) {// evnet 对象发出信号collection._collectionChanged.raiseEvent(collection,addedArray,removedArray,changedArray);
}
  • 其中_collectionChanged_entityCollection初始化时创建的一个Event对象
this._collectionChanged = new Event();

事件监听

既然有信号被发出,那就需要找到监听的一方,查看源码可以发现

  1. _dataSourceDisplay中创建defaultDataSource之后,调用了函数
this._onDataSourceAdded(undefined, defaultDataSource);
  1. 其中对defaultDataSource_visualizers进行赋值
DataSourceDisplay.prototype._onDataSourceAdded = function (dataSourceCollection,dataSource
) {dataSource._visualizers = this._visualizersCallback(scene,entityCluster,dataSource);
};
  1. 我们看下this._visualizersCallback都返回了什么
  this._visualizersCallback = defaultValue(options.visualizersCallback,DataSourceDisplay.defaultVisualizersCallback);DataSourceDisplay.defaultVisualizersCallback = function (scene,entityCluster,dataSource
) {const entities = dataSource.entities;return [new BillboardVisualizer(entityCluster, entities),new GeometryVisualizer(scene,entities,dataSource._primitives,dataSource._groundPrimitives),new LabelVisualizer(entityCluster, entities),new ModelVisualizer(scene, entities),new Cesium3DTilesetVisualizer(scene, entities),new PointVisualizer(entityCluster, entities),new PathVisualizer(scene, entities),new PolylineVisualizer(scene,entities,dataSource._primitives,dataSource._groundPrimitives),];
};

这段代码比较长,但还是可以看出是返回了一个包含了各类Visualizer的列表,其中将entities也就是我们上面的_entityCollection作为参数传递进去。
4. 以GeometryVisualizer为例,看看在构造函数阶段都做了什么

function GeometryVisualizer(scene,entityCollection,primitives,groundPrimitives
) {this._entityCollection = entityCollection;entityCollection.collectionChanged.addEventListener(GeometryVisualizer.prototype._onCollectionChanged,this);
}
  1. 通过_onCollectionChanged函数,可以看见其将添加到entity添加到了this._addedObjects属性中
/*** @private*/
GeometryVisualizer.prototype._onCollectionChanged = function (entityCollection,added,removed
) {const addedObjects = this._addedObjects;for (i = added.length - 1; i > -1; i--) {entity = added[i];id = entity.id;if (removedObjects.remove(id)) {changedObjects.set(id, entity);} else {addedObjects.set(id, entity);}}
};

于是我们找到了监听collectionChanged事件的对象,以及如何将被添加的entity传递到GeometryVisualizer,从而完成了事件发出到监听的闭环。

在这之后又是如何根据GeometryVisualizer中的_addedObjects创建primitive呢,这我们将在下一篇文章中进行详细的描述。