9.

外部ツールから Revit Document を取得する完全ガイド — IExternalCommand / .addin / Dynamo

編集
この記事の要点
  • 原則: Revit Document は Revit プロセス内でのみ取得可能。スタンドアロン .exe からは直接アクセス不可
  • 基本パターンは IExternalCommand を実装した DLL を .addin マニフェストで Revit に登録
  • commandData.Application.ActiveUIDocument.Document で現在開かれている Document を取得
  • Application.OpenDocumentFile() で .rvt を開いて Document を得る(バッチ処理向け)
  • Dynamo / pyRevit / RevitLookup なども内部的に IExternalCommand と同じ仕組みを利用

大前提: Revit プロセス内でしか触れない

Revit API の Autodesk.Revit.DB.Document は、Revit.exe プロセス内でロードされた DLL からのみアクセスできます。スタンドアロン .exe を作って「外部から .rvt を開いて要素を読みたい」という直接アクセスはサポートされていません(ライセンス的にも技術的にも)。

したがって「外部ツール」とは正確には「Revit にロードされる外部 DLL(アドイン)」を指します。

方法 1: IExternalCommand を実装

最も基本的なアドイン作成パターン:

using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;

[Transaction(TransactionMode.Manual)]
[Regeneration(RegenerationOption.Manual)]
public class HelloRevit : IExternalCommand
{
    public Result Execute(
        ExternalCommandData commandData,
        ref string message,
        ElementSet elements)
    {
        // ★ Document 取得の基本形
        UIApplication uiApp = commandData.Application;
        UIDocument uiDoc = uiApp.ActiveUIDocument;
        Document doc = uiDoc.Document;

        TaskDialog.Show("Revit", $"ファイル: {doc.Title}");

        // 壁の数を数える
        int wallCount = new FilteredElementCollector(doc)
            .OfCategory(BuiltInCategory.OST_Walls)
            .WhereElementIsNotElementType()
            .Count();

        TaskDialog.Show("Revit", $"壁の数: {wallCount}");

        return Result.Succeeded;
    }
}

方法 2: .addin マニフェストで登録

DLL を Revit にロードさせるための XML を %ProgramData%\Autodesk\Revit\Addins\2024\ に配置します:



  
    HelloRevit
    C:\Tools\MyRevitAddin.dll
    12345678-1234-1234-1234-123456789012
    MyNamespace.HelloRevit
    ABCD
    My Company
  

ファイル拡張子は .addin。Revit 起動時に自動でロードされ、「アドイン」タブにコマンドが追加されます。

方法 3: IExternalApplication でリボン登録

毎回コマンドメニューから選ばせるのが面倒なら、リボン UI にボタンを追加:

public class MyApp : IExternalApplication
{
    public Result OnStartup(UIControlledApplication app)
    {
        string tabName = "MyTab";
        app.CreateRibbonTab(tabName);
        var panel = app.CreateRibbonPanel(tabName, "Tools");

        var btn = new PushButtonData(
            "HelloBtn",
            "Hello",
            Assembly.GetExecutingAssembly().Location,
            "MyNamespace.HelloRevit");

        panel.AddItem(btn);
        return Result.Succeeded;
    }

    public Result OnShutdown(UIControlledApplication app)
    {
        return Result.Succeeded;
    }
}

方法 4: バッチ処理(OpenDocumentFile)

ユーザー操作なしで複数 .rvt を処理する場合は Application.OpenDocumentFile():

public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
    Application app = commandData.Application.Application;

    string[] files = Directory.GetFiles(@"C:\Projects", "*.rvt");
    foreach (var file in files)
    {
        Document doc = app.OpenDocumentFile(file);
        try
        {
            int walls = new FilteredElementCollector(doc)
                .OfCategory(BuiltInCategory.OST_Walls)
                .Count();
            File.AppendAllText(@"C:\report.txt", $"{file}: {walls}\n");
        }
        finally
        {
            doc.Close(false);
        }
    }
    return Result.Succeeded;
}

Document 取得パターン比較

取得方法シーン注意
commandData.Application.ActiveUIDocument.Documentユーザー操作時の現在開いてる .rvtもっとも一般的
app.Application.OpenDocumentFile(path)バッチ処理で複数 .rvt処理後 Close 必須
app.Application.Documents開かれている全 Document を列挙Family Document も含む
RevitLinkInstance.GetLinkDocument()リンクされた .rvt の Document編集不可(読み取り専用)
doc.IsFamilyDocument.rfa か .rvt かの判定

Dynamo からのアクセス

Dynamo はビジュアルプログラミング環境ですが、内部的に Revit API を呼び出しています:

# Dynamo の Python Script ノード
import clr
clr.AddReference('RevitAPI')
clr.AddReference('RevitServices')

from Autodesk.Revit.DB import FilteredElementCollector, BuiltInCategory
from RevitServices.Persistence import DocumentManager

doc = DocumentManager.Instance.CurrentDBDocument

walls = FilteredElementCollector(doc) \
    .OfCategory(BuiltInCategory.OST_Walls) \
    .WhereElementIsNotElementType() \
    .ToElements()

OUT = len(walls)

pyRevit からのアクセス

pyRevit は Python で書ける軽量アドインフレームワーク:

# pyRevit の Python スクリプト
from pyrevit import revit, DB

doc = revit.doc
uidoc = revit.uidoc

walls = DB.FilteredElementCollector(doc) \
    .OfCategory(DB.BuiltInCategory.OST_Walls) \
    .WhereElementIsNotElementType() \
    .ToElements()

for w in walls:
    print(w.Name)

RevitLookup ツール

RevitLookup(オープンソース)は要素のプロパティをツリービューで覗き見できる必須デバッグツールです:

  • GitHub: jeremytammik/RevitLookup
  • 要素を選択して「Snoop Current Selection」
  • 全プロパティと値、関連要素を再帰的にブラウズ可能
  • BuiltInCategory・パラメータ名・型 ID 等の確認に最適

注意事項とベストプラクティス

  • Transaction: ドキュメントを変更する場合は new Transaction(doc, "name") で囲む
  • Disposable: 多くの Revit API オブジェクトは IDisposable → using で囲む
  • UI スレッド: Document 操作は UI スレッドからのみ。バックグラウンドスレッド NG
  • API バージョン: Revit 2024 用 DLL は 2023 では動かない(多くの場合)→ バージョン別ビルド
  • テスト: 開発中はデバッガをアタッチして F5、または RevitAddInUtility で自動再ロード

FAQ

Q: PowerShell や Python から外部プロセスとして Revit を操作したい
A: 公式には不可能です。Revit ServerForge / Autodesk Platform Services(APS)を使ったクラウド API なら外部から .rvt を扱えます。

Q: Revit を起動せずに .rvt を読みたい
A: 公式 API では不可。サードパーティの ODA BimRv SDK(Open Design Alliance)が独自に .rvt を解析できますが、別ライセンスが必要。

Q: .addin が読み込まれない
A: 配置先パスと FullClassName のスペル、Assembly のパス、AddInId の GUID 重複を確認。Revit のログ journal ファイルにエラーが出ます。

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. RevitAPI.dll と RevitAPIUI.dll の参照
  2. マニフェストファイルの書き方
  3. アドインの追加/設置方法
  4. アドインの作成サンプル(外部ツール編)
  5. アドインの作成サンプル(外部アプリケーション編)
  6. 要素の取得と情報の表示
  7. 要素のカテゴリとマテリアルの取得と表示
  8. よく使うBuiltInCategoryの一覧
  9. 外部ツールでAutodesk.Revit.Documentを取得する方法
  10. エラーメッセージの設定方法
  11. 「はい」、「いいえ」、「キャンセル」ボタンの設置と処理分岐
  12. 要素(カテゴリ、ファミリ、タイプ)とは
  13. ElementIdとUniqueIdの違い
  14. 要素フィルターの使い方
  15. 要素のパラメータ一覧の取得
  16. pyRevitの導入と簡単なアプリケーションの作成
  17. Revit SDKのサンプルの場所とビルド方法
  18. FamilySymbol(タイプ)の取得とパラメータの変更
  19. 相対パスでdllにアイコン画像を埋め込む方法
  20. 「グループ」について