在Skyline从6.5版本之后支持以3dml的方式加载模型,3dml的格式相比之前的xpl和xpl2发布的格式渲染的效率更高,在加载海量模型的场景时非常的实用。
在Skyline开发中经常会需要寻找符合条件的场景对象,skyline的模型种类非常繁多,可以根据不同的模型类型来遍历搜索场景。本文主要介绍一下3dml图层在遍历时候的方式。
3dml的图层在Skyline中使用 IMeshLayer66 来表示,当加载3dml的图层之后,遍历场景树的时候,会发现3dml的图层类型是:OT_3D_MESH_LAYER 另外还有一种类型是OT_3D_MESH_FEATURE_LAYER 这个实际上是OT_3D_MESH_LAYER下面真正的图层。
遍历skyline的场景树结构时,可以使用递归的方式进行遍历,类似于下面的代码:
public void IteratorProjectTree(string tParentItemID)
{
string tItemID = _sgWorld.ProjectTree.GetNextItem(tParentItemID, ItemCode.CHILD);
if (tItemID == "") return null;
while (tItemID != "")
{
if (_sgWorld.ProjectTree.IsGroup(tItemID) == true)
{
if (某种条件)
{
//Do your stuff
}
IteratorProjectTree(tItemID);
}
else
{
//do your stuff
tItemID = _sgWorld.ProjectTree.GetNextItem(tItemID, ItemCode.NEXT);
}
}
}
3dml格式的文件从本质上来说是属于Feature类型的(它遍历到最小的单元就是一个IFeature),说到IFeature就不得不提在没有引入3dml格式之前的skyline版本的FeatureLayer,在Skyline中(以skyline6.6为例),FeatureLayer直接可以实现遍历,通过它提供的方法和属性,方式如下:
IFeatureLayer66 ---> IFeatureGroups66 --->IFeatureGroup66--->IFeatures66--->IFeature66
这一条链基本上前一个类中有获取后一个类的方式,前一个类提供了一个数组来保存后一个类的对象。
但是在3dml中并没有这种方式,在接口中
IMeshLayer66提供了获取I3DMLFeatureLayers66的方式,在通过I3DMLFeatureLayers66获取到I3DMLFeatureLayer66,之后I3DMLFeatureLayer66并不提供FeatureGroups的方式进一步向下遍历,它的成员如下:
提供的属性SelectedFeatures仅仅可以获取当前选中的要素,如果没有被选中那么得到的要素节点是空的。在遍历的过程中很显然不会去选中所有的要素。
在详细阅读完文档之后,发现了这个类提供的方法
IFeatures66 ExecuteSpatialQuery(
IGeometry pIGeometry,
[IntersectionType IntersectionType = IntersectionType.IT_INTERSECT])
可以做到这一点,这个方式是在图层中查询满足要求的要素,在skyline中可以设置一个全球的坐标,让场景中所有的要素落入其中,这样就可以获取到所有该图层的要素了,具体实现方式如下:
IMeshLayer66 fl = (IMeshLayer66)3dmloj;
for (int i = 0; i < fl.FeatureLayers.Count; ++i)
{
I3DMLFeatureLayer66 ifl66 = (I3DMLFeatureLayer66)fl.FeatureLayers[i];
IGeometry cPolygonGeometry = null;
double[] cVerticesArray = new double[] {
-180, -90, 10,
180, -90, 10,
180, 90, 10,
-180, 90, 10,
};
ILinearRing cRing = _sgWorld.Creator.GeometryCreator.CreateLinearRingGeometry(cVerticesArray);
cPolygonGeometry = _sgWorld.Creator.GeometryCreator.CreatePolygonGeometry(cRing, null);
IFeatures66 allFeaturesInCurrent3DMLayer = ifl66.ExecuteSpatialQuery(cPolygonGeometry);
因为设置的坐标是经纬度在(-180,180)(-90,90)所以场景中的要素必然落入其中,用这种方法变相的完成了获取到场景中的3dml要素。(补充:在测试过几个场景之后,发现坐标位置使用(-180,180)(-90,90)的时候有时候求交不到,改为比求交区域稍微大一点的多边形之后,每次都可以求交正确【高程的参数无关紧要,可以设置为0】,因此项目中建议使用一个比我们场景区域稍大一点的多边形作求交即可)