xBIM 基础15 IFC导出Excel报表

  • 2019 年 10 月 4 日
  • 笔记

  IFC导出Excel空间报表文件

  本篇将向您展示从IFC文件读取数据所需的一些概念。它使用IFC4接口,适用于IFC2x3和IFC4型号。要创建Excel文件,我们使用NPOI。在这个例子中你只需要 xBIM Essentials 组件。包含样本数据的所有代码均可在此处获得

此示例的结果如下所示:

您将需要以下using声明:

using NPOI.SS.UserModel;  using NPOI.XSSF.UserModel;  using System.Diagnostics;  using System.IO;  using System.Linq;  using Xbim.Ifc;  using Xbim.Ifc4.Interfaces;

主要功能如下:

//从模板初始化NPOI工作簿  var workbook = new XSSFWorkbook("template.xlsx");  var sheet = workbook.GetSheet("Spaces");//用单位创建漂亮的数字格式。 现实中需要更多的关心的是单位。    //我们只知道我们现在的模型有空间面积以立方米和空间体积为单位  //请注意从Revit导出的原始数据是错误的,因为数据量比应该大1000倍。  //在这个例子中,数据是使用xBIM修复的。  var areaFormat = workbook.CreateDataFormat();  var areaFormatId = areaFormat.GetFormat("# ##0.00 [$m²]");  var areaStyle = workbook.CreateCellStyle();  areaStyle.DataFormat = areaFormatId;  var volumeFormat = workbook.CreateDataFormat();  var volumeFormatId = volumeFormat.GetFormat("# ##0.00 [$m³]");  var volumeStyle = workbook.CreateCellStyle();  volumeStyle.DataFormat = volumeFormatId;  //打开IFC模型。 不会改变模型中的任何东西,所以我们可以把编辑器的信息保留下来。  using (var model = IfcStore.Open("SampleHouse.ifc"))  {      //获取模型中的所有空间.      //需要 ToList() 方便使用 Foreach      var spaces = model.Instances.OfType<IIfcSpace>().ToList();      //设置报表标题      sheet.GetRow(0).GetCell(0)          .SetCellValue($"Space Report ({spaces.Count} spaces)");      foreach (var space in spaces)      {          //写报表数据          WriteSpaceRow(space, sheet, areaStyle, volumeStyle);      }  }  //保存 报表  using (var stream = File.Create("spaces.xlsx"))  {      workbook.Write(stream);      stream.Close();  }  //打开保存的EXCEL 文件  Process.Start("spaces.xlsx");

此代码使用以下函数从IFC读取数据并为每个空间写入一行

private static void WriteSpaceRow(IIfcSpace space, ISheet sheet, ICellStyle areaStyle, ICellStyle volumeStyle)  {      var row = sheet.CreateRow(sheet.LastRowNum + 1);        var name = space.Name;      row.CreateCell(0).SetCellValue(name);        var floor = GetFloor(space);      row.CreateCell(1).SetCellValue(floor?.Name);        var area = GetArea(space);      if (area != null)      {          var cell = row.CreateCell(2);          cell.CellStyle = areaStyle;            // 如果来自属性而不是数量,那么僵不能保证它是数字          if (area.UnderlyingSystemType == typeof(double))              cell.SetCellValue((double)(area.Value));          else              cell.SetCellValue(area.ToString());      }        var volume = GetVolume(space);      if (volume != null)      {          var cell = row.CreateCell(3);          cell.CellStyle = volumeStyle;            // 如果来自属性而不是数量,那么将不能保证它是数字          if (volume.UnderlyingSystemType == typeof(double))              cell.SetCellValue((double)(volume.Value));          else              cell.SetCellValue(volume.ToString());      }  }

要获得包含空间的楼层,您需要执行此操作:

private static IIfcBuildingStorey GetFloor(IIfcSpace space)  {      return          //获取所有对象化的关系,这些关系将按此空间进行分解          space.Decomposes            //选择分解的对象(这些对象可能是其他空间或建筑楼层)          .Select(r => r.RelatingObject)            //仅获取楼层          .OfType<IIfcBuildingStorey>()            //获取第一个          .FirstOrDefault();  }

IFC包含数据基础结构,用于存储与产品及其类型相关的任意数据。这种基础设施相当复杂。存储数据的两种主要方式是数量或属性。数量是明确的,它们包含的值的类型,其中属性可以包含许多不同的数据类型作为值。对于面积和体积,如果定义了数量,则最好从数量中获取值

private static IIfcValue GetArea(IIfcProduct product)  {      //尝试先从数量中获取      var area =          //获取可以定义属性和数量集的所有关系          product.IsDefinedBy          //在所有属性和数量集之间搜索。          //您可能还希望按名称搜索特定数量          .SelectMany(r => r.RelatingPropertyDefinition.PropertySetDefinitions)          //数量集合          .OfType<IIfcElementQuantity>()          //从数量集获取所有数量          .SelectMany(qset => qset.Quantities)          //我们只对面积感兴趣          .OfType<IIfcQuantityArea>()          //我们将采取第一个。显然有一个以上的面积属性          //所以, 要检查的名称。但是,我们将保持它简单的这个例子。          .FirstOrDefault()?          .AreaValue;      if (area != null)          return area;      //从属性中获取值      return GetProperty(product, "Area");  }    private static IIfcValue GetVolume(IIfcProduct product)  {      var volume = product.IsDefinedBy          .SelectMany(r => r.RelatingPropertyDefinition.PropertySetDefinitions)          .OfType<IIfcElementQuantity>()          .SelectMany(qset => qset.Quantities)          .OfType<IIfcQuantityVolume>()          .FirstOrDefault()?.VolumeValue;      if (volume != null)          return volume;      return GetProperty(product, "Volume");  }

更常见的属性在属性集中搜索

private static IIfcValue GetProperty(IIfcProduct product, string name)  {      return          //获取可以定义属性和数量集的所有关系          product.IsDefinedBy          //在所有属性和数量集之间搜索。您可能还希望在特定属性集中搜索          .SelectMany(r => r.RelatingPropertyDefinition.PropertySetDefinitions)          //在这种情况下, 只考虑属性集。          .OfType<IIfcPropertySet>()          //从所有属性集中获取所有属性          .SelectMany(pset => pset.HasProperties)          //只允许考虑单个值属性。还有枚举属性,          //表属性、引用属性、复杂属性和其他          .OfType<IIfcPropertySingleValue>()          .Where(p =>              string.Equals(p.Name, name, System.StringComparison.OrdinalIgnoreCase) ||              p.Name.ToString().ToLower().Contains(name.ToLower()))          .FirstOrDefault()?.NominalValue;  }