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;  }