Revit二次開發_將資料匯入Excel
阿新 • • 發佈:2018-12-14
有時需要將Revit模型的一些資訊提取到Excel中進行處理或者是作為記錄進行儲存,但也許是因為Revit的資料結構相對複雜,並不支援直接將資料匯出Excel,所以平時通過二次開發將資訊輸出到Excel中。
常使用的輸出方法有三個,分別是com元件;NPOI庫;Epplus庫。
com元件需要電腦安裝Excel軟體,由於Excel版本比較多,匯出的時候要注意版本的問題。下面的程式碼通過com元件的方法匯出模型中的一張明細表。
//使用Excel2013,引用Microsoft Excel 15.0 Object Library using Autodesk.Revit.DB; using Autodesk.Revit.UI; using Autodesk.Revit.Attributes; using System.IO; using System.Reflection; using EXCEL = Microsoft.Office.Interop.Excel; namespace RevitAddinTestClass { [Transaction(TransactionMode.Manual)] class ViewScheduleExport : IExternalCommand { public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) { Document document = commandData.Application.ActiveUIDocument.Document; //獲取專案中的一張門明細表 FilteredElementCollector collector = new FilteredElementCollector(document); foreach (ViewSchedule vs in collector.OfClass(typeof(ViewSchedule))) { if (vs.Name == "門明細表") { //Excel檔案路徑 string path = @"D:\LST\Test\ViewSchedule.xlsx"; //如檔案已存在則刪除 if (File.Exists(path)) File.Delete(path); //建立Excel檔案 object nothing = Missing.Value; EXCEL.Application excelApplication = new EXCEL.ApplicationClass(); EXCEL.Workbook excelWorkBook = excelApplication.Workbooks.Add(nothing); EXCEL.Worksheet excelWorkSheet = excelWorkBook.Sheets[1] as EXCEL.Worksheet; //獲取表格的行列數 int rows, cols; TableSectionData data = vs.GetTableData().GetSectionData(SectionType.Body); rows = data.NumberOfRows; cols = data.NumberOfColumns; //匯入資料 for (int i = 0; i < rows; i++) { for(int j = 0; j < cols; j++) { EXCEL.Range cell = excelWorkSheet.Cells[i + 1, j + 1] as EXCEL.Range; //獲取明細表中的字串 cell.Value = vs.GetCellText(SectionType.Body, i, j); //表頭字型設定為粗體 if (cell.Row == 1) { cell.Font.Bold = true; } //新增邊框線 cell.BorderAround2(); } } //儲存檔案 excelWorkBook.Close(true, path); excelApplication.Quit(); excelApplication = null; continue; } } return Result.Succeeded; } } }
NPOI與Epplus都是開源免費的,NPOI庫用的比較少,因為它只支援03和07版的Excel,但它不需要電腦安裝有Excel軟體。下面的程式碼讀取模型中的建築標高,然後通過NPOI庫在Excel中製作一個層高表。
using System; using System.Collections.Generic; using System.IO; using Autodesk.Revit.DB; using Autodesk.Revit.UI; using Autodesk.Revit.Attributes; using NPOI.HSSF.UserModel; using NPOI.SS.UserModel; namespace RevitAddinTestClass { [Transaction(TransactionMode.Manual)] class LevelsScheduleExport : IExternalCommand { public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) { Document document = commandData.Application.ActiveUIDocument.Document; //獲取所有建築標高 Dictionary<double, string> levelDic = new Dictionary<double, string>(); List<double> elevationList = new List<double>(); FilteredElementCollector collector = new FilteredElementCollector(document); foreach(Level l in collector.OfCategory(BuiltInCategory.OST_Levels).WhereElementIsNotElementType()) { if (l.get_Parameter(BuiltInParameter.LEVEL_IS_BUILDING_STORY).AsInteger() == 1) { double elevation = Math.Round(UnitUtils.ConvertFromInternalUnits(l.Elevation, DisplayUnitType.DUT_METERS), 2); string levelName = l.Name; try { if (l.GetParameters("避難層")[0].AsInteger() == 1) levelName += "(避難層)"; } catch { //to do } levelDic.Add(elevation, levelName); elevationList.Add(elevation); } } //按標高的高度排序 elevationList.Sort(); //Excel檔案路徑 string path = @"D:\LST\Test\LevelSchedule.xls"; //如檔案已存在則刪除 if (File.Exists(path)) File.Delete(path); //建立Excel檔案 HSSFWorkbook excelWorkBook = new HSSFWorkbook(); ISheet excelWorkSheet = excelWorkBook.CreateSheet("層高表"); //格式 ICellStyle cellStyle = excelWorkBook.CreateCellStyle(); cellStyle.BorderLeft = BorderStyle.Thin; cellStyle.BorderTop = BorderStyle.Thin; cellStyle.BorderRight = BorderStyle.Thin; cellStyle.BorderBottom = BorderStyle.Thin; cellStyle.DataFormat = HSSFDataFormat.GetBuiltinFormat("0.00"); //表頭 IRow hRow = excelWorkSheet.CreateRow(0); ICell hCell0 = hRow.CreateCell(0); hCell0.SetCellValue("樓層"); hCell0.CellStyle = cellStyle; ICell hCell1 = hRow.CreateCell(1); hCell1.SetCellValue("層高"); hCell1.CellStyle = cellStyle; ICell hCell2 = hRow.CreateCell(2); hCell2.SetCellValue("標高(m)"); hCell2.CellStyle = cellStyle; //計算高差並寫入資料 for (int i = 0; i < elevationList.Count; i++) { double currentElve, upElve, height; string currentLevel; currentElve = elevationList[i]; currentLevel = levelDic[currentElve]; if (i == elevationList.Count - 1) { upElve = 0; height = 0; } else { upElve = elevationList[i + 1]; height = upElve - currentElve; } //寫入資料 IRow dRow = excelWorkSheet.CreateRow(i + 1); ICell dCell0 = dRow.CreateCell(0); dCell0.SetCellValue(currentLevel); dCell0.CellStyle = cellStyle; ICell dCell1 = dRow.CreateCell(1); if (height == 0) { dCell1.SetCellValue(""); } else { dCell1.SetCellValue(height); } dCell1.CellStyle = cellStyle; ICell dCell2 = dRow.CreateCell(2); dCell2.SetCellValue(currentElve); dCell2.CellStyle = cellStyle; } //儲存檔案 using (FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write)) { excelWorkBook.Write(fs); } return Result.Succeeded; } } }
Epplus庫也不需要電腦安裝Excel,但只支援xlsx格式的excel檔案,網上的一些評論是匯出的效率及穩定性都比NPOI好,但由於沒進行過非常大資料量的匯出,所以暫時沒有體現出來。 下面程式碼將模型中的管道資訊按照一定的規則處理後匯出到Excel中,然後在Excel中簡單的做個數據透視即可獲得對應的工程量。
using System.IO; using Autodesk.Revit.DB; using Autodesk.Revit.UI; using Autodesk.Revit.Attributes; using Autodesk.Revit.DB.Plumbing; using OfficeOpenXml; using OfficeOpenXml.Style; namespace RevitAddinTestClass { [Transaction(TransactionMode.Manual)] class PipeSchedule : IExternalCommand { public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) { Document document = commandData.Application.ActiveUIDocument.Document; //Excel檔案路徑 string path = @"D:\LST\Test\PipeSchedule.xlsx"; //如檔案已存在則刪除 if (File.Exists(path)) File.Delete(path); //建立Excel檔案 ExcelPackage package = new ExcelPackage(new FileInfo(path)); ExcelWorksheet excelWorkSheet = package.Workbook.Worksheets.Add("管道資料"); //表頭 string[] hearName = { "Id", "系統", "專案名稱", "材質", "規格", "連線方式", "單位", "工程量" }; for(int i = 0; i< hearName.Length; i++) { ExcelRange hCell = excelWorkSheet.Cells[1, i + 1]; hCell.Value = hearName[i]; //格式 hCell.Style.Font.Bold = true; hCell.Style.Border.BorderAround(ExcelBorderStyle.Thin); } //獲得所有管道資料 List<object[]> pipeDataList = new List<object[]>(); FilteredElementCollector collector = new FilteredElementCollector(document); foreach(Pipe p in collector.OfClass(typeof(Pipe)).WhereElementIsNotElementType()) { string pipeId, pipeSys, pipeItemName, pipeSize, pipeMaterial, pipeConnect, pipeUnit; double pipeQuantity; //系統縮寫 string abbr = p.get_Parameter(BuiltInParameter.RBS_DUCT_PIPE_SYSTEM_ABBREVIATION_PARAM).AsString(); //讀取資料 pipeId = p.Id.ToString(); pipeSys = GetPipeSys(abbr); pipeItemName = p.get_Parameter(BuiltInParameter.RBS_PIPING_SYSTEM_TYPE_PARAM).AsValueString().Split('_')[1]; pipeSize = p.get_Parameter(BuiltInParameter.RBS_CALCULATED_SIZE).AsString().Split(' ')[0]; pipeMaterial = GetPipeMaterial(Convert.ToDouble(pipeSize), abbr); pipeConnect=GetPipeConnect(Convert.ToDouble(pipeSize),pipeMaterial); pipeUnit = "m"; pipeQuantity = UnitUtils.ConvertFromInternalUnits(p.get_Parameter(BuiltInParameter.CURVE_ELEM_LENGTH).AsDouble(), DisplayUnitType.DUT_METERS); object[] pipeData = { pipeId, pipeSys, pipeItemName, pipeMaterial, "DN" + pipeSize, pipeConnect, pipeUnit, pipeQuantity }; pipeDataList.Add(pipeData); } //寫入資料 for(int i = 0; i < pipeDataList.Count; i++) { object[] pipeData = pipeDataList[i]; for(int j = 0; j < pipeData.Length; j++) { ExcelRange dCell = excelWorkSheet.Cells[i + 2, j + 1]; dCell.Value = pipeData[j]; dCell.Style.Border.BorderAround(ExcelBorderStyle.Thin); } } //儲存 package.Save(); package.Dispose(); return Result.Succeeded; } string GetPipeSys(string abbreviation) { Dictionary<string, string> sysDic = new Dictionary<string, string>(); sysDic.Add("ZP", "消防系統"); sysDic.Add("X", "消防系統"); sysDic.Add("J", "給水系統"); sysDic.Add("F", "排水系統"); sysDic.Add("W", "排水系統"); return sysDic[abbreviation]; } string GetPipeMaterial(double pipeSize,string abbreviation) { string material = "未定義"; switch (abbreviation) { case "ZP": material = "鍍鋅鋼管"; break; case "X": material = "鍍鋅鋼管"; break; case "J": if (pipeSize > 50) { material = "鋼塑複合管"; } else { material = "PP-R管"; } break; case "F": material = "PVC-U管"; break; case "W": material = "PVC-U管"; break; } return material; } string GetPipeConnect(double pipeSize,string material) { string connect = "未定義"; switch (material) { case "PVC-U管": connect = "粘接"; break; case "PP-R管": connect = "熱熔"; break; case "鋼塑複合管": if (pipeSize > 65) { connect = "卡箍"; } else { connect = "螺紋"; } break; case "鍍鋅鋼管": if (pipeSize > 65) { connect = "卡箍"; } else { connect = "螺紋"; } break; } return connect; } } }