xBIM 基本的模型操作
目录
本次案例我们主要查看xBIM 一些简单的基本操作,我们将介绍被称为CRUD(创建,检索,更新和删除)的持久性存储的四个基本功能 。以下示例通常适用于IFC4,但您也可以对IFC2x3执行相同的操作。实际上,大部分代码都是IFC版本不可知的,因为它使用IFC4接口,它也适用于IFC2x3。用于开发这些示例的示例数据可以在这里下载 。
一、创建
以下示例将创建没有任何几何图形的简单IFC模型。你可以看到IfcStore
一个XbimEditorCredentials
代表当前应用程序和用户的配置对象,并用它来维护OwnerHistory
根实体。这是一个要求,可以更轻松地处理创建兼容IFC模型所需的众多方面之一。IFC没有定义任何模型视图定义(MVD), 所以除了WHERE
规则和所需的属性之外没有其他限制。您应该始终设置编辑器凭据并填写您的应用程序的首字母和您当前的用户。
var editor = new XbimEditorCredentials { ApplicationDevelopersName = "xBIM Team", ApplicationFullName = "xBIM Toolkit", ApplicationIdentifier = "xBIM", ApplicationVersion = "4.0", EditorsFamilyName = "Santini Aichel", EditorsGivenName = "Johann Blasius", EditorsOrganisationName = "Independent Architecture" };
IModel
在xBIM中的所有实现都是IDisposable
这样的,建议在开发时应用 using
:
using (var model = IfcStore.Create(editor, IfcSchemaVersion.Ifc4, XbimStoreType.InMemoryModel)) { //...do something with the model }
如果要在模型中创建或修改任何内容,则必须使用事务。这些也应该在using
语句中使用,以便在事件发生的时候有适当的回滚操作范围。您必须明确提交事务以保持更改。事务不能嵌套,所以当时总是只有一个事务。
using (var txn = model.BeginTransaction("Hello Wall")) { //....do something in the scope of this transaction txn.Commit() }
所有与实体有关的操作都可以通过IModel.Instances
。这是您在模型中获取,更改和创建新实体的访问点。要创建任何新的对象,请使用此模板化函数。您始终必须指定一个非抽象类型来创建。这是建立在xBIM的方式,如果你没有得到一个编译时错误。每个模型都是模式特定的,因此它是IFC2x3或IFC4或其他特定模式。IfcStore
使它更容易,因为它可以打开两个IFC的版本,并会告诉你它是什么,但是当你想创建数据,确保你不会搞砸你的using
陈述。如果您尝试创建模型初始化为IFC2x3的IFC4实体,则会引发运行时异常。
var newWall = mode.Instances.New<IfcWall>();
除了使用这个函数之外,不可能以任何其他方式创建新的实体。你会在上面的代码中看到,这个函数使用可选的类型化对象初始化器来设置对象的值。没有必要使用它们,但我个人喜欢它,因为我可以看到结果实体的结构。使用所有这些基本的部分,我们可以建造第一堵墙。这面墙没有任何几何图形,所以IFC的大部分观众不会告诉你任何东西。但这只是一个基本的例子。这里是完整的代码:
var editor = new XbimEditorCredentials { ApplicationDevelopersName = "xBIM Team", ApplicationFullName = "xBIM Toolkit", ApplicationIdentifier = "xBIM", ApplicationVersion = "4.0", EditorsFamilyName = "Santini Aichel", EditorsGivenName = "Johann Blasius", EditorsOrganisationName = "Independent Architecture" }; using (var model = IfcStore.Create(editor, IfcSchemaVersion.Ifc4, XbimStoreType.InMemoryModel)) { using (var txn = model.BeginTransaction("Hello Wall")) { //创建模型前应该先创建项目 var project = model.Instances.New<IfcProject>(p => p.Name = "Basic Creation"); //定义基本的单位 SIUnitsUK 为英制单位 project.Initialize(ProjectUnits.SIUnitsUK); //创建简单的对象并使用lambda初始值设定名称 var wall = model.Instances.New<IfcWall>(w => w.Name = "The very first wall"); //设置一些基本的属性 model.Instances.New<IfcRelDefinesByProperties>(rel => { rel.RelatedObjects.Add(wall); rel.RelatingPropertyDefinition = model.Instances.New<IfcPropertySet>(pset => { pset.Name = "Basic set of properties"; pset.HasProperties.AddRange(new[] { model.Instances.New<IfcPropertySingleValue>(p => { p.Name = "Text property"; p.NominalValue = new IfcText("Any arbitrary text you like"); }), model.Instances.New<IfcPropertySingleValue>(p => { p.Name = "Length property"; p.NominalValue = new IfcLengthMeasure(56.0); }), model.Instances.New<IfcPropertySingleValue>(p => { p.Name = "Number property"; p.NominalValue = new IfcNumericMeasure(789.2); }), model.Instances.New<IfcPropertySingleValue>(p => { p.Name = "Logical property"; p.NominalValue = new IfcLogical(true); }) }); }); }); txn.Commit(); } model.SaveAs("BasicWall.ifc"); }
IFC 文件格式如下
ISO-10303-21; HEADER; FILE_DESCRIPTION ((''), '2;1'); FILE_NAME ('', '2016-10-27T13:14:43', (''), (''), 'Xbim File Processor version 3.2.0.0', 'Xbim version 3.2.0.0', ''); FILE_SCHEMA (('IFC4')); ENDSEC; DATA; #1=IFCPROJECT('2t0OftVsP8UBH3rtAB$yJv',#2,'Basic Creation',$,$,$,$,(#20,#23),#8); #2=IFCOWNERHISTORY(#5,#6,$,.ADDED.,$,$,$,0); #3=IFCPERSON($,'Santini Aichel','Johann Blasius',$,$,$,$,$); #4=IFCORGANIZATION($,'Independent Architecture',$,$,$); #5=IFCPERSONANDORGANIZATION(#3,#4,$); #7=IFCORGANIZATION($,'xBIM Team',$,$,$); #6=IFCAPPLICATION(#7,$,'xBIM Toolkit','xBIM'); #8=IFCUNITASSIGNMENT((#9,#10,#11,#12,#13,#14,#15,#16,#17)); #9=IFCSIUNIT(*,.LENGTHUNIT.,.MILLI.,.METRE.); #10=IFCSIUNIT(*,.AREAUNIT.,$,.SQUARE_METRE.); #11=IFCSIUNIT(*,.VOLUMEUNIT.,$,.CUBIC_METRE.); #12=IFCSIUNIT(*,.SOLIDANGLEUNIT.,$,.STERADIAN.); #13=IFCSIUNIT(*,.PLANEANGLEUNIT.,$,.RADIAN.); #14=IFCSIUNIT(*,.MASSUNIT.,$,.GRAM.); #15=IFCSIUNIT(*,.TIMEUNIT.,$,.SECOND.); #16=IFCSIUNIT(*,.THERMODYNAMICTEMPERATUREUNIT.,$,.DEGREE_CELSIUS.); #17=IFCSIUNIT(*,.LUMINOUSINTENSITYUNIT.,$,.LUMEN.); #18=IFCCARTESIANPOINT((0.,0.,0.)); #19=IFCAXIS2PLACEMENT3D(#18,$,$); #20=IFCGEOMETRICREPRESENTATIONCONTEXT('Building Model','Model',3,1.E-05,#19,$); #21=IFCCARTESIANPOINT((0.,0.)); #22=IFCAXIS2PLACEMENT2D(#21,$); #23=IFCGEOMETRICREPRESENTATIONCONTEXT('Building Plan View','Plan',2,1.E-05,#22,$); #24=IFCWALL('1YTVCro6L0$OJQL2X7wICY',#2,'The very first wall',$,$,$,$,$,$); #27=IFCPROPERTYSINGLEVALUE('Text property',$,IFCTEXT('Any arbitrary text you like'),$); #28=IFCPROPERTYSINGLEVALUE('Length property',$,IFCLENGTHMEASURE(56.),$); #29=IFCPROPERTYSINGLEVALUE('Number property',$,IFCNUMERICMEASURE(789.2),$); #30=IFCPROPERTYSINGLEVALUE('Logical property',$,IFCLOGICAL(.T.),$); #26=IFCPROPERTYSET('2u_olyjv13oRt0GvSVSxHS',#2,'Basic set of properties',$,(#27,#28,#29,#30)); #25=IFCRELDEFINESBYPROPERTIES('3I5GuvWn95PRXcxoFGfJAL',#2,$,$,(#24),#26); ENDSEC; END-ISO-10303-21;
二、查询
从模型中检索数据非常简单,它IModel.Instances
再次用于访问我们需要的所有实体。
var firstWall = mode.Instances.FirtsOrDefault<IfcWall>(); var allWalls = model.Instances.OfType<IfcWall>(); var specificWall = model.Instances.Where<IfcWall>(w => w.Name == "Brick wall");
您可以看到,所有这些函数都是模板化的,所以它们使用对象的类型作为第一级过滤器。如果你知道你想要的类型,你应该总是指定它来提高性能。对于所有的搜索查询,您也可以使用接口来检索实体。我们在IFC2x3实体上实现了IFC4接口,这意味着您可以用一个代码库查询IFC2x3和IFC4 。
以下示例只需要这些使用:
using System; using System.Linq; using Xbim.Ifc; using Xbim.Ifc4.Interfaces;
如果您对实体的结构感兴趣,建议浏览 buildingSMART的前身是IFC数据互用联盟(IAI-International Alliance of Interoperability) 教程网站。
const string fileName = "SampleHouse.ifc"; using (var model = IfcStore.Open(fileName)) { // 获得IFC 文件中的所有门(使用IfcDoor的IFC4接口,这将对IFC2x3和IFC4都有效) var allDoors = model.Instances.OfType<IIfcDoor>(); //只获得具有定义的IIfcTypeObject的门 var someDoors = model.Instances.Where<IIfcDoor>(d => d.IsTypedBy.Any()); //获取单个门 以Id 查询 var id = "2AswZfru1AdAiKfEdrNPnu"; var theDoor = model.Instances.FirstOrDefault<IIfcDoor>(d => d.GlobalId == id); Console.WriteLine($"Door ID: {theDoor.GlobalId}, Name: {theDoor.Name}"); //获取这个门的所有属性 var properties = theDoor.IsDefinedBy .Where(r => r.RelatingPropertyDefinition is IIfcPropertySet) .SelectMany(r => ((IIfcPropertySet)r.RelatingPropertyDefinition).HasProperties) .OfType<IIfcPropertySingleValue>(); foreach (var property in properties) Console.WriteLine($"Property: {property.Name}, Value: {property.NominalValue}"); }
控制台输出属性信息
Door ID: 3cUkl32yn9qRSPvBJVyWYp, Name: Doors_ExtDbl_Flush:1810x2110mm:285860 Property: IsExternal, Value: true Property: Reference, Value: 1810x2110mm Property: Level, Value: Level: Ground Floor Property: Sill Height, Value: 0 Property: Area, Value: 4.9462127188431 Property: Volume, Value: 0.193819981582386 Property: Mark, Value: 1 Property: Category, Value: Doors Property: Family, Value: Doors_ExtDbl_Flush: 1810x2110mm Property: Family and Type, Value: Doors_ExtDbl_Flush: 1810x2110mm Property: Head Height, Value: 2110 Property: Host Id, Value: Basic Wall: Wall-Ext_102Bwk-75Ins-100LBlk-12P Property: Type, Value: Doors_ExtDbl_Flush: 1810x2110mm Property: Type Id, Value: Doors_ExtDbl_Flush: 1810x2110mm Property: Phase Created, Value: New Construction
三、修改
修改与新增、查询比较类似。注意事务必须是开放的,并且应该被包含在using
语句中,否则模型将在您创建或更改任何对象时抛出异常。
const string fileName = "SampleHouse.ifc"; var editor = new XbimEditorCredentials { ApplicationDevelopersName = "xBIM Team", ApplicationFullName = "xBIM Toolkit", ApplicationIdentifier = "xBIM", ApplicationVersion = "4.0", EditorsFamilyName = "Santini Aichel", EditorsGivenName = "Johann Blasius", EditorsOrganisationName = "Independent Architecture" }; using (var model = IfcStore.Open(fileName, editor, true)) { //根据ID 在模型中查询对应的门 var id = "3cUkl32yn9qRSPvBJVyWYp"; var theDoor = model.Instances.FirstOrDefault<IfcDoor>(d => d.GlobalId == id); //修改事务 using (var txn = model.BeginTransaction("Doors modification")) { //创建具有两个属性的新属性集 var pSetRel = model.Instances.New<IfcRelDefinesByProperties>(r => { r.GlobalId = Guid.NewGuid(); r.RelatingPropertyDefinition = model.Instances.New<IfcPropertySet>(pSet => { pSet.Name = "New property set"; //所有的集合被初始化
pSet.HasProperties.Add(model.Instances.New<IfcPropertySingleValue>(p => { p.Name = "First property"; p.NominalValue = new IfcLabel("First value"); })); pSet.HasProperties.Add(model.Instances.New<IfcPropertySingleValue>(p => { p.Name = "Second property"; p.NominalValue = new IfcLengthMeasure(156.5); })); }); }); //修改门的名称 theDoor.Name += "_checked"; //添加属性 pSetRel.RelatedObjects.Add(theDoor); //提交修改事务 txn.Commit(); } }
四、删除
那么删除也是模型中最复杂的操作,首先要知道的是,它只能在MemoryModel (内存模式)(2016年10月)中完全实现。之所以这么复杂,是因为IFC 格式的数据模型非常复杂,并不是层次结构或方向图。所以我们的delete实现只能确保模型中没有对象引用你删除的对象,所以模型保持一致。但它不会自动删除任何引用它的对象或引用它。有程序员或用户可以选择。但是,用于删除的底层基础设施可以非常简单地使用:
using (var model = IfcStore.Open(fileName)) { //获取模型中得一个门 var id = "3cUkl32yn9qRSPvBJVyWYp"; //使用模型ID var theDoor = model.Instances.FirstOrDefault<IIfcDoor>(d => d.GlobalId == id); //打开事务 using (var txn = model.BeginTransaction("Delete the door")) { //删除门 model.Delete(theDoor); //提交修改 txn.Commit(); } }