Revitアドインで建築を自動化!床・壁・柱の配置が簡単に #001

ここではRevitアドインがどのような素晴らしい可能性をもっているか一例を紹介します。

Revitアドインとは

  • Revitにユーザーが独自の機能を追加できるプログラム
  • できること
    • インスタンスを配置位置変更する(インスタンスとは床壁天井、設備機器などのファミリを使って実際にモデル内で利用するもの)
    • インスタンスから情報を取得する
    • インスタンスの情報を変更する(ファミリ変更、タイプ変更、パラメータ変更等)
  • プログラミング言語はC#またはVB.NETを使う。以降C#を使用
  • 開発ツールはマイクロソフトのVisualStudioがよい
  • Autodeskが提供しているRevit APIを利用する。正式ドキュメントはRevit API Docs

 

このアドインの機能

Revitの建築モデルにおいて床、壁、柱を指定した内容で自動的に入力します。これによってRevitモデリング作業を限られた範囲ですが自動化することができます。

 

設計プロセスでどこが効率化できるでしょうか

従来の設計では、設計者が顧客の条件に合うプランをいくつも検討し、最終的にマウスを使ってRevitに入力します。ただし、現在はRevit以外のCADソフトを使うことが多いと思います。

このプロセスで人が「Revitに入力する」作業は、創造や思考といった人間ならではの部分は少なく、ほとんどが機械的な作業です。しかし、この作業には多くの時間がかかります。そこで、Revitアドインを使ってこの部分を自動化することで、効率を大幅に向上させることができると思います。

 

人間の考えをどうRevitに伝えるかがむずかしい

ここで、人間が考えるプランをどのようにRevitに伝えるかは難しい問題です。

将来的には、生成AIが顧客の条件を読み取り、おすすめのプランを提示してくれるようになると思います。しかし、現時点では手間をかけずに中間的な方法で表現するのが現実的だと思います。私の知る限り、この中間的な方法はまだ提案されていません。ここで紹介する方法が最善だとは思いませんが、常により良いアイデアを探しています。

 

この試みでの私の提案

ここではプランをExcelシートで表現してみます。現実の設計業務にすぐに使える詳細度ではありませんがひとつのチャレンジです。

実務ではDXFファイルを使って、そこからプランを読み取る方法のほうが現実的でしょう。こちらに可能性を示します

Excel案に戻ります。外壁は赤、内壁は緑でセルを塗りつぶすことによって壁を指定します。この例では外壁、内壁、窓、ドアはそれぞれ1種類しか指定できませんが壁の種類をW1, W2, W3など複数に拡張することも可能でしょう。使用するRevitファミリ、タイプは使用しているテンプレート等によって異なりますので注意してください。

外壁・内壁の表現
外壁接続点には番号(床作成用の形状を決める要素)
Wは窓の位置、Dはドアの位置
外壁や窓などRevitファミリとタイプの指定(一例)
選択できるファミリとタイプの設定その1(一例)
選択できるファミリとタイプの設定その2(一例)

この情報をRevitアドインで読み込んで、要素の位置、ファミリ、タイプを使ってプログラムで自動的にモデリングします。

 

完成Revitモデル!

プログラミングテクニックはこの後概要を説明しますが、結果として完成したモデルは次のとおりです。細かい部分の完成度はとても低いものですがブラッシュアップしていけば完成度も上がり、設計初期段階でのモデリングに役に立つと思います。この例ではExcelデータが用意されていれば実行時間は1秒から3秒程度です。Excel入力データを複数用意しておけば即座に複数案が作れます。

 

 

Revitアドインプログラムの中身の説明

アドインのタイプは複数あります

作成したアドインのメニューは配置の選択肢3つあります。どれにするかによってコードも変わります。一番上のものが最もシンプルなので、ここではそのタイプでアドインを作成します。

  • 「外部ツール」の中にコマンドを配置(下図の一番左の丸印の配下)
  • 「アドイン」タブの中に独自パネル、独自アイコン(リボン)を配置(下図の左から二番目の丸印)
  • 独自タブの作成(下図の右側3つの丸印の配下)

 

アドインの基本的な構成

開発システムVisualStudioを使用しますが、そのファイルの構成は次の通りです。ここでプロジェクト名はCreateWakksAndFloorsとします。中心となるファイルはCommand.csとKUtil.csです。前者はメインのファイル、後者はよく使うメソッドを私がまとめたユーティリティファイルです。CreateWakksAndFloors.addinは設定ファイルです。なおアドインはRevitのバージョンによって参照すべきファイルが異なりますので注意が必要です。

このタイプのアドインでは、ユーザーが実行アクションをしたときに初めに実行されるのは下のコードでCommand.csのExecuteメソッドです。その内部に実行したい機能をプログラミングしていきます。

#region Namespaces
using Autodesk.Revit.ApplicationServices;
(一部省略)

#endregion
//当ソフトにはEPPlus4.5.3.3を使用しています。これはLGPLライセンスです。著作権はEPPlus Software社です。
namespace CreateWallsAndFloors
{
    [Transaction(TransactionMode.Manual)]
    public class Command : IExternalCommand
    {
        public Result Execute(
          ExternalCommandData commandData,
          ref string message,
          ElementSet elements)
        {
            //この部分に実行したい内容を書く
            return Result.Succeeded;
        }
    }
}

 

処理の大まかな流れ

  • STEP1:Excelファイルから設定情報の読み込み
  • STEP2:ファミリとタイプの読み込み
  • STEP3:インスタンスの配置

 

STEP1:Excelファイルから設定情報の読み込み

まずExcelファイルを読むためのダイアログをユーザーに表示します。そのためにOpenFileDialogを作成して諸々設定しopenFileDialog.ShowDialog()を実行すると私たちがよく見かけるファイルオープンの画面が出ます。OKボタンが押されるとファイル名がfileNameに代入されます。

public static string OpenExcel()
{
    string fileName = string.Empty;

    //OpenFileDialog
    using (OpenFileDialog openFileDialog = new OpenFileDialog())
    {
        openFileDialog.Title = "ファイル選択";
        openFileDialog.Filter = "ExcelFiles | *.xls;*.xlsx;*.xlsm";
        //初期表示フォルダはデスクトップ
        openFileDialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
        //ファイル選択ダイアログを開く
        if (openFileDialog.ShowDialog() == DialogResult.OK)
        {
            fileName = openFileDialog.FileName;
        }
    }
    return fileName;
}

次のコードでExcelの最初のシートを読みます。ここには次のような情報があるのでこれらを取り込みます。最初にあるKUtil.OpenExcel()は上で説明したコードのことです。変数excelFileにはExcelのファイル名が入っています。Excelファイルを読んでいく中で設定項目が欠落している場合にはerrorItemにエラーメッセージを代入して後で表示し、処理はそこで終了します。

//設定とモデリング情報が入っているExcelファイルを読む
string excelFile = KUtil.OpenExcel();
using (var excel = new ExcelPackage(new FileInfo(excelFile)))
{
    //独自のModelSettingクラス
    modelsetting = new ModelSetting();

    //設定をExcelシートから読む---------------------------------------------
    int sheetPage = 1;//SPECシート, 企業のExcelは0から始まる模様だがmicrosoft365では1から開始。確認要
    //シートを取得
    var sheet = excel.Workbook.Worksheets[sheetPage];
    //エラー項目
    string errorItem = "";
    //階高設定を取得。内部単位に変換
    var temp = sheet.Cells[1, 2].Value;
    if (temp != null)
    {
        modelsetting.kaidaka = KUtil.CVmmToInt(Convert.ToDouble(temp.ToString()));
    }
    else
    {
        errorItem = "Excel入力情報のエラー:\n階高設定がない" + "\n";
    }
   ・・・・・・・・
  (途中略)
   ・・・・・・・・
    if (!errorItem.Equals(""))
    {
        TaskDialog.Show("Error", errorItem);

        return false;
    }

次に3番目のシートにある色塗りで作ったプラン案を読みます。下の図は前に説明したものですが、赤が外壁、緑が内壁、柱はC、窓はW、ドアはDでマークしてあります。

これを読み取って次の2つの配列を作ります。colorArray配列は色を識別して壁の種類と位置を記憶する配列。この配列の中身は赤の外壁の1、緑の内壁は2を代入します。下の図はExcelで表現していますが、実際はC#のプログラムの中の配列colorArray = new int[cellsRange.End.Row, cellsRange.End.Column];のことです

colorArrayの一部

外壁の接続点の数字、柱を表すC、窓を表すW、ドアを表すDの情報を記憶するvalueArray配列を作ります。これもC#の中の配列valueArray = new string[cellsRange.End.Row, cellsRange.End.Column];のことです。

valueArrayの一部
valueArrayの一部
using (var excel = new ExcelPackage(new FileInfo(excelFile)))
{
  ・・・・・・
  (途中略)
    //モデリングに必要な情報をExcelシートから読む--------------------------
    //Excelシート番号。番号は0から始まる
    sheetPage = 3;//level1の情報
    //シートを取得
    sheet = excel.Workbook.Worksheets[sheetPage];
    var cellsRange = sheet.Dimension;

    //外壁、内壁の位置を解析するためのデータ配列------------
    //データ配列(壁の色用。外壁の赤は1を代入、内壁の青は2を代入)
    colorArray = new int[cellsRange.End.Row, cellsRange.End.Column];

    //床を作成するための座標を検出するための配列。外壁で数値が入っているものだけを拾った配列
    //窓のW、ドアのDも入っている
    //データ配列(文字用)
    valueArray = new string[cellsRange.End.Row, cellsRange.End.Column];

    //データが存在する最大の行番号
    int maxI = colorArray.GetLength(0);
    //Excelを読んで解析用のモデルに数値を入れる
    //行をスキャンする
    for (int i = cellsRange.Start.Row; i <= cellsRange.End.Row; i++)//セルの行、列番号は1から始まる
    {
        //列をスキャンする
        for (int j = cellsRange.Start.Column; j <= cellsRange.End.Column; j++)
        {
            //セルの色を取得
            string color = sheet.Cells[i, j].Style.Fill.BackgroundColor.Rgb ?? "xxxxxxxx";
            //セルの値を取得
            string val = (sheet.Cells[i, j].Value ?? "").ToString();
            //セルの文字をvalueArray配列に代入(数値、W、D、C等)
            if (val != null)
            {
                valueArray[i - 1, j - 1] = val;
            }

            //色を抽出する
            color = color.Substring(2, 6);
            switch (color)
            {
                case @"FF0000"://赤 外壁
                    colorArray[i - 1, j - 1] = 1;
                    break;
                case @"00FF00"://緑 内壁
                    colorArray[i - 1, j - 1] = 2;
                    break;
            }
        }
    }
}

これで壁、柱、窓、床の位置が配列で表現できました。これらの情報は「インスタンスの配置」で、どの位置に、何を配置するかに利用します。

 

STEP2:ファミリとタイプの読み込み

壁などを配置する前に、どのタイプを使用するか選ばなければいけません。それは人間がRevitを操作するときと同じですね。

タイプ情報はExcelファイルから読み込みこみます。詳細は省略しますが外壁のタイプ名は変数outWallTypeName、内壁のタイプ名は変数innerWallTypeName、床のタイプ名は変数floorTypeNameに現段階でセットされていると思って下さい。そして次のコードの命令が実行されると外壁、内壁、床のタイプがoutWallType、innerWallType、floorTypeに選択されて入ります。

タイプを選択する過程を少し詳しく説明します。FilteredElementCollector(doc)というのはよく使う命令で、その後に続く条件でモデルに用意されている要素をフィルタリングして選ぶための最初の命令です。条件というのはOfClass(typeof(WallType))、つまり登録されている「壁のタイプを選んでください」ということです。FirstOrDefault(q => q.Name == outWallTypeName)というのは、壁のタイプを複数ピックアップしたのちに、「それらを変数qに一個ずつ取り出してその名前が指定した壁タイプの名前と一致するかどうか、つまりq.Name == outWallTypeNameかどうか調べて、それが成り立つもので最初のものを壁タイプをして選んでください」という命令です。

//外壁、内壁、床タイプの検索
WallType outWallType = new FilteredElementCollector(doc).OfClass(typeof(WallType)).Cast<WallType>().FirstOrDefault(q => q.Name == outWallTypeName);
WallType innerWallType = new FilteredElementCollector(doc).OfClass(typeof(WallType)).Cast<WallType>().FirstOrDefault(q => q.Name == innerWallTypeName);
FloorType floorType = new FilteredElementCollector(doc).OfClass(typeof(FloorType)).Cast<FloorType>().FirstOrDefault(q => q.Name == floorTypeName);

STEP3:インスタンスの配置

Revitアドインでモノを配置したり変更するときには慎重な手続きが求められます。単に情報を読み出すだけなら簡単です。手続きは次のようにTransactionというものを作成し、それをStartで開始し、正常に終わればCommitで変更を確定します。もし途中で何かエラーが出た場合にはトランザクションをRollBackで元に戻してキャンセルします。Revitはこれらの手続きによってモデルに不整合が生じないように守っています。

「トランザクション」とは元々は商取引のことです。IT業界では複数の処理を一つの処理として一貫性を持たせて実行・管理する仕組みです。データの整合性を保つために重要なメカニズムです。

using (Transaction tx = new Transaction(doc))
{
    tx.Start("TransactionWallFloor");
    try
    {
   ・・・・・
   この部分でモデルに変更を加える
   ・・・・・
    }
    catch (Exception e)
    {
        message = e.Message;
        tx.RollBack();
        return Result.Failed;
    }
    tx.Commit();
}

インスタンスの配置というのは実際に、壁、床、柱、窓、ドアをモデルに入力して配置することを言います。例えば壁を作る命令の文法は次のコードのとおりです。必要な引数をCreateメソッドに渡して実行すれば壁ができます。

ここでcurveは壁の平面的な設置ラインのことです。これは前に説明した配列colorArrayを読み込んで、横や縦で連続している部分を検出してその両端の座標が壁の両端であるとしてcurveを作成しています。KUtil.csのFindContinuousOnesメソッドで行っています。

public static Wall Create(
	Document document, ・・・・開いているRevitファイル
	Curve curve, ・・・・・・・平面上で壁を立てる位置の線分(直線、曲線可能)
	ElementId wallTypeId,・・・壁のタイプ
	ElementId levelId,・・・・・配置するレベル(階)
	double height,・・・・・・・壁の高さ
	double offset,・・・・・・・壁の下端はレベルからどれだけ高さ方向にオフセットするか
	bool flip,・・・・・・・・・壁の面を反転させるかどうか
	bool structural・・・・・・構造壁かどうか
)

次のコードはこのサンプルの全てのインスタンス配置部分です。どのインスタンスも複数あるのでforeachでループ処理しています。柱を作るCreateColumn、窓やドアを作るCreateWindowAndDoorは、そのメソッドの内部でファミリとタイプを検索して決定しているので外部にその部分が出ていません。ちょっとやり方が統一されていません

//モデルの生成
using (Transaction tx = new Transaction(doc))
{
    tx.Start("TransactionWallFloor");
    try
    {
        // レベル2の高さを設定
        level2.Elevation = level2HeightFeet;

        //通芯
        KUtil.CreateGrids(doc);

        //外壁を作成
        foreach (Curve curve in modelsetting.gaihekiCurves)
        {
            Wall wall = Wall.Create(doc, curve, outWallType.Id, level.Id, wallHeight, offset, false, false);
        }
        //内壁を作成
        foreach (Curve curve in modelsetting.naihekiCurves)
        {
            Wall wall = Wall.Create(doc, curve, innerWallType.Id, level.Id, wallHeight, offset, false, false);
        }
        //床を作成
        Floor floor = Floor.Create(doc, new List<CurveLoop> { floorLoop }, floorType.Id, level.Id);
        //柱の作成
        foreach (XYZ point in modelsetting.columnsPoints)
        {
            KUtil.CreateColumn(doc, levelName, levelName2, columnFamilyName, columnSymbolName, point.X, point.Y);//シンボルを探すこともメソッド内で実行
        }
        //窓の作成
        foreach (XYZ point in modelsetting.windowsPoints)
        {
            KUtil.CreateWindowAndDoor(uidoc, doc, windowFamilyName, windowSymbolName, levelName, point.X, point.Y, windowOffset);//シンボルを探すこともメソッド内で実行
        }
        //ドアの作成
        
        foreach (XYZ point in modelsetting.doorsPoints)
        {
            KUtil.CreateWindowAndDoor(uidoc, doc, doorFamilyName, doorSymbolName, levelName, point.X, point.Y, 0);//シンボルを探すこともメソッド内で実行
        }
        
    }
    catch (Exception e)
    {
        message = e.Message;
        tx.RollBack();
        return Result.Failed;
    }
    tx.Commit();
}

return Result.Succeeded;

 

アドインの設定ファイル.addin

Revitがアドインについての情報を得て適切なdllを読み込んで実行するためには.addinの拡張子をもった設定ファイルが必要です。アドインの実行形式のタイプで説明したように外部コマンド型のアドインですから、下記マークアップで<AddIn Type=”Application”>という部分は実際には何も機能しないので、このマークアップ部分は有っても無くても問題ありません。

<?xml version="1.0" encoding="utf-8"?>
<RevitAddIns>
  <AddIn Type="Command">
    <Text>Command 壁床の作成</Text>
    <Description>壁と床を作成するサンプルです</Description>
    <Assembly>CreateWallsAndFloors.dll</Assembly>
    <FullClassName>CreateWallsAndFloors.Command</FullClassName>
    <ClientId>168d2797-1a27-407d-9ace-cfbf328d4aa6</ClientId>
    <VendorId>com.kawasaki.katsumi</VendorId>
    <VendorDescription>Katsumi kawasaki</VendorDescription>
  </AddIn>
  <AddIn Type="Application">
    <Name>Application CreateWallsAndFloors</Name>
    <Assembly>CreateWallsAndFloors.dll</Assembly>
    <FullClassName>CreateWallsAndFloors.App</FullClassName>
    <ClientId>c8e567e5-1ead-4a93-aedc-1c11085092e2</ClientId>
    <VendorId>com.kawasaki.katsumi</VendorId>
    <VendorDescription>Katsumi kawasaki</VendorDescription>
  </AddIn>
</RevitAddIns>

 

アドインを使用する前のインストール

VisualStudioで開発したアドインの中で次の2つのファイルをインストール先にコピーします。そのあとにRevitを起動するとアドインが有効になります。最初に起動したときに署名がないアドインが見つかった旨の警告が出ますが「常にロード」ボタンを押してください。なおこの方法によるインストールはWindowsの管理者権限を必要としません。
[インストールするファイル]・・●●部分はあなたのログオン名
C:\Users\●●\source\repos\CreateWallsAndFloors\CreateWallsAndFloorsの中のCreateWallsAndFloors.addin
C:\Users\●●\source\repos\CreateWallsAndFloors\CreateWallsAndFloors\bin\Debugの中のCreateWallsAndFloors.dll
[インストール先のディレクトリ]
C:\Users\katsu\AppData\Roaming\Autodesk\Revit\Addins\2022

 

まとめ

この例でアドインの可能性を感じることができたしょうか。

こんなシンプルな例でもプログラミングになじみの無い方には複雑で難しく感じたと思います。しかし手間がかかっても一度作成すれば、何度も使う業務ならば効果は相当大きくなります。

この例では非常に大雑把なモデリングでしたが設計者の要求をよく反映して細かいところまで作りこんでいくことは可能でしょう。

しかしながら自動化ツールだけでは設計はできないことも事実です。旅行に例えれば自動化は新幹線のようなもので途中で止まることもできず決まった地点まで高速でしか行けません。最後は各駅停車やバス、タクシー、徒歩も組み合わせないと目的は達成できませんね。これと同じです。アドインを設計のどの場面で利用したら便利になるか今後も提案していきたいと思います。

詳しいコードの説明までは説明する時間がありませんが、ご興味のある方はこのリンクからコードを参照できます。

githubはこちらhttps://github.com/katsumikawasaki/CreateWallsAndFloors.git

(ご注意)ここに掲載したコードはひとつの技術的な解法を示すサンプルです。実践的な用途に耐えうる堅牢性や品質等は備えていません。コードの実行結果について当組織は一切責任を負いませんので、参照、利用はご自身の責任でお願いします。

書籍もぜひご覧ください


コメント

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です