Skyline Globe中3dml圖層的遍歷
在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】,因此專案中建議使用一個比我們場景區域稍大一點的多邊形作求交即可)