1. 程式人生 > >Revit二次開發_將資料匯入Excel

Revit二次開發_將資料匯入Excel

有時需要將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;
        }
    }
}