如何在 Xbim 中只提取最低级别的对象?

How to I extract only the lowest-level objects in Xbim?

我有一个 IFC 格式的 BIM 模型,我想使用 Xbim 向模型中的每个对象添加一个新的 属性,比如成本。我正在构建一个 .NET 应用程序。下面的代码运行良好,除了 属性 也被添加到楼层、建筑物和站点 - 我只想将它添加到没有嵌套其他对象的最低级别对象。

首先,我尝试了各种方法来打印每个对象的“相关对象”,认为我可以过滤掉任何具有非空相关对象的对象。这让我看到了这个:

IfcRelDefinesByType.RelatedObjects (http://docs.xbim.net/XbimDocs/html/7fb93e55-dcf7-f6da-0e08-f8b5a70accf2.htm) from thinking that RelatedObjects (https://standards.buildingsmart.org/IFC/RELEASE/IFC2x3/FINAL/HTML/ifckernel/lexical/ifcreldecomposes.htm) would contain this information.

但我还没有设法实现此文档中的工作代码。

这是我的代码:

using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Xbim.Ifc;
using Xbim.Ifc2x3.Interfaces;
using Xbim.Ifc4.Kernel;
using Xbim.Ifc4.MeasureResource;
using Xbim.Ifc4.PropertyResource;
using Xbim.Ifc4.Interfaces;
using IIfcProject = Xbim.Ifc4.Interfaces.IIfcProject;

namespace MyPlugin0._1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            outputBox.AppendText("Plugin launched successfully");
        }


        private void button1_Click(object sender, EventArgs e)
        {
            // Setup the editor
            var editor = new XbimEditorCredentials
            {
                ApplicationDevelopersName = "O",
                ApplicationFullName = "MyPlugin",
                ApplicationIdentifier = "99990100",
                ApplicationVersion = "0.1",
                EditorsFamilyName = "B",
                EditorsGivenName = "O",
                EditorsOrganisationName = "MyWorkplace"
            };

            // Choose an IFC file to work with        
            OpenFileDialog dialog = new OpenFileDialog();
            dialog.ShowDialog();
            string filename = dialog.FileName;
            string newLine = Environment.NewLine;
            
            // Check if the file is valid and continue
            if (!filename.ToLower().EndsWith(".ifc"))
            {
                // Output error if the file is the wrong format
                outputBox.AppendText(newLine + "Error: select an .ifc-file");
            }
            else
            {
                // Open the selected file (## Not sure what the response is to a corrupt/invalid .ifc-file)
                using (var model = IfcStore.Open(filename, editor, 1.0))
                {
                    // Output success when the file has been opened
                    string reversedName = Form1.ReversedString(filename);
                    int filenameShortLength = reversedName.IndexOf("\");
                    string filenameShort = filename.Substring(filename.Length - filenameShortLength, filenameShortLength);
                    outputBox.AppendText(newLine + filenameShort + " opened successfully for editing");

                    

                    ////////////////////////////////////////////////////////////////////
                    // Get all the objects in the model ( ### lowest level only??? ###)
                    var objs = model.Instances.OfType<IfcObjectDefinition>();
                    ////////////////////////////////////////////////////////////////////



                    // Create and store a new property
                    using (var txn = model.BeginTransaction("Store Costs"))
                    {
                        // Iterate over all the walls to initiate the Point Source property
                        foreach (var obj in objs)
                        {

                            // Create new property set to host properties
                            var pSetRel = model.Instances.New<IfcRelDefinesByProperties>(r =>
                            {
                                r.GlobalId = Guid.NewGuid();
                                r.RelatingPropertyDefinition = model.Instances.New<IfcPropertySet>(pSet =>
                                {
                                    pSet.Name = "Economy";
                                    pSet.HasProperties.Add(model.Instances.New<IfcPropertySingleValue>(p =>
                                    {
                                        p.Name = "Cost";
                                        p.NominalValue = new IfcMonetaryMeasure(200.00); // Default Currency set on IfcProject
                                    }));
                                });
                            });

                            // Add property to the object
                            pSetRel.RelatedObjects.Add(obj);

                            // Rename the object
                            outputBox.AppendText(newLine + "Cost property added to " + obj.Name);
                            obj.Name += "_withCost";

                            
                            //outputBox.AppendText(newLine + obj.OwnerHistory.ToString());
                            
                        }

                        // Commit changes to this model
                        txn.Commit();
                    };

                    // Save the changed model with a new name. Does not overwrite existing files but generates a unique name
                    string newFilename = filenameShort.Substring(0, filenameShort.Length - 4) + "_Modified.IFC";
                    int i = 1;
                    while (File.Exists(newFilename))
                    {
                        newFilename = filenameShort.Substring(0, filenameShort.Length - 4) + "_Modified(" + i.ToString() + ").IFC";
                        i += 1;
                    }
                    model.SaveAs(newFilename); // (!) Gets stored in the project folder > bin > Debug
                    outputBox.AppendText(newLine + newFilename + " has been saved");
                       
                };
            }
            
        }



        // Reverse string-function
        static string ReversedString(string text)
        {
            if (text == null) return null;
            char[] array = text.ToCharArray();
            Array.Reverse(array);
            return new String(array);
        }


        private void Form1_Load(object sender, EventArgs e)
        {

        }


        
    }
}

您一开始就在模型中获取了过于宽泛的一组元素。 IFC 模型中的几乎所有内容都将被归类为(或 'derived from')IfcObjectDefinition 的实例 - 包括空间概念(空间、级别、区域等)以及更抽象的参与者概念(人) , 资源之类的

您最好过滤 objs 到更具体的类型,例如 IfcElement, IfcBuildingElement - 甚至是下面更真实的元素(IfcWindow、IfcDoor 等)

// Get all the building elements in the model 
var objs = model.Instances.OfType<IfcBuildingElement>();

您还可以通过使用其他 IFC 关系按更具体的子句进行过滤,而不仅仅是它们的类型。