我们之前已经讨论过利用Document.Delete()的几个重载方法来发现对象之间关系的几个应用实例。比方说:标签和其标注元素的关系、墙及其墙基脚的关系、宿主及其内嵌元素的关系、Sheet的标题块、或者宿主元素及其门洞(针对粗略的材质量化计算)之间的关系。另外一种使用的场景是获取没有修改的元素几何数据。
感谢Saikat Bhattacharya提供的一个小巧的例子:ObjRel。它展示了在一个建筑模型中如何利用Document.Delete()来获取对象关系,并且将这些关系用一颗树体现出来。这棵树用.NET中的TreeView控件实现,这棵树所在的窗体(Windows Form)命名为Result。
Saikat的例子中使用一个函数GetDependentsElementIds来实现整体功能,如下所示,这个函数十分简洁,只有3行:
ElementIdSet GetDependentsElementIds(
Element e )
{
Document doc = _app.ActiveDocument;
doc.BeginTransaction();
ElementIdSet ids = doc.Delete( e );
doc.AbortTransaction();
return ids;
}
这个函数被树控件的两个函数(DisplayNode 和CreateRelationships )所调用。最终的结果是建筑模型中所有和其它元素有关系的BIM 元素都被填充到树控件中。
DisplayNode(): 这个递归函数根据相互依赖的元素ID 创建树节点。每个节点显示其对应元素的名称(Element Name )、类别(Category )和ID (Element ID )。
CreateRelationships(): 根据初始节点创建树节点,填充它,并且维护一个已经创建的节点列表以避免重复创建对应统一元素的树节点。
下面是这两个方法的实现,以及树所在窗体的构造函数是如何调用它们的:
void DisplayNode( Element e, TreeNode node )
{
string cat = (null == e.Category)
? "<category unknown>"
: e.Category.Name;
string label = string.Format( "{0}: {1} {2}",
e.Name, cat, e.Id.Value );
TreeNode father = node.Nodes.Add( label );
// save element id to handle select event,
// cf. treeView1_AfterSelect:
father.ImageKey = e.Id.Value.ToString();
ElementIdSet ids = GetDependentsElementIds( e );
try
{
if( null != ids && 1 < ids.Size )
{
Document doc = _app.ActiveDocument;
foreach( ElementId id1 in ids )
{
ElementId id = id1;
Element e2 = doc.get_Element( ref id );
if( e2 != null )
{
if( !e2.Id.Equals( e.Id )
&& !_displayedElems.Contains( e2 ) )
{
_displayedElems.Insert( e2 );
DisplayNode( e2, father );
}
}
}
}
}
catch( Exception ex )
{
MessageBox.Show( ex.Message.ToString() );
}
}
void CreateRelationships()
{
rootNode = new TreeNode( _app.ActiveDocument.Title );
this.treeView1.Nodes.Add( rootNode );
_displayedElems = new ElementSet();
foreach( Element e in _elems )
{
if( !_displayedElems.Contains( e ) )
{
DisplayNode( e, rootNode );
}
}
}
public Result( ElementSet elems, Autodesk.Revit.Application app )
{
_elems = elems;
_app = app;
InitializeComponent();
CreateRelationships();
treeView1.AfterSelect
+= new TreeViewEventHandler(
treeView1_AfterSelect );
}
接下来您将看到一个 Revit 外部命令( External Command )的 Execute() 方法。这个外部命令创建一系列可见的模型元素,然后将一个
包含这些模型元素的集合作为参数创建一个 Result 窗体。之后正如你在上面 Result 窗体的构造函数中看见的那样,窗体通过调用
CreateRelationships() 方法来填充那颗关系树。
Application app = commandData.Application;
Document doc = app.ActiveDocument;
Autodesk.Revit.Geometry.Options opt
= app.Create.NewGeometryOptions();
BuiltInCategory bicPreviewLegendComponent
= BuiltInCategory.OST_PreviewLegendComponents;
int iBic = ( int ) bicPreviewLegendComponent;
try
{
// select all model elements:
ElementSet a = app.Create.NewElementSet();
ElementIterator it = app.ActiveDocument.Elements;
while( it.MoveNext() )
{
Element e = it.Current as Element;
if( !( e is Symbol )
&& !( e is FamilyBase )
&& ( null != e.Category )
&& ( iBic != e.Category.Id.Value )
&& ( null != e.get_Geometry( opt ) ) )
{
a.Insert( e );
}
}
// show the object relationship dialog
Result res = new Result( a, app );
res.ShowDialog();
}
catch( Exception ex )
{
message = ex.Message;
}
return IExternalCommand.Result.Failed;
我们可以使用一个简单的模型文件SimpleHouse.rvt来测试ObjRel的运行结果。您可以在原文链接的附件中找到这个模型文件。