简体   繁体   中英

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

I have a BIM model in IFC format and I want to add a new property, say cost, to every object in the model using Xbim. I am building a .NET application. The following code works well, except, the property is also added to storeys, buildings and sites - and I only want to add it to the lowest-level objects that nest no other objects.

To begin with, I have tried various methods to print the "related objects" of each object, thinking that I could filter out any objects with non-null related objects. This has led me to look at this:

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.

But I have not managed to implement working code from this documentation.

Here is my code:

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)
        {

        }


        
    }
}

You're starting out by getting too broad a set of elements in the model. Pretty much everything in an IFC model will be classed as (or 'derived from') an instance of IfcObjectDefinition - including Spatial concepts (spaces, levels, zones etc) as well as more abstract concepts of Actors (people), Resources and the like.

You'd be better off filtering down objs to the more specific types such as IfcElement , IfcBuildingElement - or even the more real world elements below (IfcWindow, IfcDoor etc.)

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

You could also filter by more specific clauses more than just their type by using the other IFC relationships.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM