はじめに
AMDlab BIMソフトウェアエンジニアの河野(twitter@tatsukikouno)です。
アイキャッチ画像は、リモートワークを手伝ってくれている愛猫のユズです。
今回は、RevitアドインからRhino.Inside.Revitの機能を利用するためのセットアップ手順を紹介します。
サンプルコードでは、ユーザーが選択した2つのRevit要素の交差部分を計算し、デスクトップに3dmファイルとして保存する機能を実装します。
Revit APIにもブーリアン演算の機能はありますが、Rhinoの強力なジオメトリエンジンを活用できるに越したことはありません。
なお、本プログラムを動作させるには、Rhino.Inside.Revitのインストールと適切なライセンスが必要です。
ご利用は自己責任でお願いいたします。
手順1:Rhino.Inside.Revitのインストール
https://www.rhino3d.com/jp/features/rhino-inside-revit/
手順2:プロジェクトのセットアップと参照の追加
Revitアドインプロジェクトを作成したら、必要なDLLへの参照を追加します。
- プロジェクトの参照を右クリックし、[参照の追加] → [参照]を選択します。
C:\ProgramData\Autodesk\Revit\Addins\2024\RhinoInside.Revit\R7
に移動し、下記のDLLを参照に追加します。
–RhinoInside.Revit.AddIn.dll
–RhinoInside.Revit.dll
–RhinoInside.Revit.External.dll
- 再度、プロジェクトの参照から[参照の追加]を行い、C:\Program Files\Rhino 7\System\RhinoCommon.dllを追加します
- 参照に追加したすべてのDLLを選択し、プロパティウィンドウで「ローカルにコピー」を
True
に設定します。
※RhinoとRhino.Inside.Revitのバージョンは合わせてください。
手順3:ヘルパー関数の実装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
/// <summary> /// Elementから最初のSolidを取得するヘルパーメソッド /// </summary> /// <param name="element"></param> /// <returns></returns> private static Solid GetSolidFromGeometry(Element element) { var options = new Options { DetailLevel = ViewDetailLevel.Fine }; var geometry = element.get_Geometry(options); foreach (GeometryObject geoObj in geometry) { if (geoObj is Solid solid && solid.Volume > 0.1) { return solid; } } return null; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
/// <summary> /// 2つのSolidをRhinoのBrepに変換し、交差を計算してRhinoファイルにエクスポートするヘルパーメソッド /// </summary> /// <param name="solidA"></param> /// <param name="solidB"></param> /// <param name="tolerance"></param> /// <param name="fileName"></param> /// <returns></returns> /// <exception cref="InvalidOperationException"></exception> private static Solid PerformBooleanIntersection(Solid solidA, Solid solidB, double tolerance, string fileName = null) { try { if (!Rhino.Runtime.HostUtils.RunningInRhino) _ = new Rhino.Runtime.InProcess.RhinoCore( new[] { "/NOSPLASH" }, // 任意パラメータ Rhino.Runtime.InProcess.WindowStyle.Hidden); var brepA = solidA.ToBrep(); var brepB = solidB.ToBrep(); var results = Brep.CreateBooleanIntersection(brepA, brepB, tolerance); // デバッグ用に、交差が見つからなかった場合でも元の形状を保存する if (results == null || results.Length == 0) { if (fileName != null && brepA != null && brepB != null) CreateRhinoDocumentWithBreps(new[] { brepA, brepB }, tolerance, Environment.GetFolderPath(Environment.SpecialFolder.Desktop), fileName + "_debug"); return null; } var result = results[0]; // デバッグ用に、元の形状と交差結果を保存する if (fileName != null && brepA != null && brepB != null) CreateRhinoDocumentWithBreps(new[] { brepA, brepB, result }, tolerance, Environment.GetFolderPath(Environment.SpecialFolder.Desktop), fileName); return results[0].ToSolid(); } catch (Rhino.Runtime.NotLicensedException ex) { throw new InvalidOperationException($"Rhinoライセンスエラー: {ex.Message}。Rhino.Insideのライセンスを確認してください。", ex); } catch (Exception ex) { throw new InvalidOperationException($"ブーリアン演算中にエラーが発生しました: {ex.Message}", ex); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
/// <summary> /// 複数のBrepを1つの.3dmファイルに書き出すヘルパーメソッド /// </summary> /// <param name="breps">書き出すBrepの配列</param> /// <param name="tolerance">Brepの検証・修復用の許容誤差</param> /// <param name="saveFolder">保存先フォルダ</param> /// <param name="fileName">ファイル名(拡張子なし)</param> private static void CreateRhinoDocumentWithBreps( Brep[] breps, double tolerance, string saveFolder, string fileName) { using (var doc = RhinoDoc.CreateHeadless(null)) // null: デフォルトテンプレート { foreach (var brep in breps) { if (brep == null) continue; if (!brep.IsValid) brep.Repair(tolerance); doc.Objects.AddBrep(brep); } var savePath = Path.Combine(saveFolder, $"{fileName}.3dm"); if (!doc.SaveAs(savePath)) throw new InvalidOperationException("3dmファイルの保存に失敗しました。"); } } |
手順4:Commandの実装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) { try { var uidoc = commandData.Application.ActiveUIDocument; var doc = uidoc.Document; // 1つ目の要素を選択 var firstRef = uidoc.Selection.PickObject(ObjectType.Element, "1つ目の要素を選択してください"); var firstElement = doc.GetElement(firstRef.ElementId); var firstSolid = GetSolidFromGeometry(firstElement); if (firstSolid == null) { message = "1つ目の要素からソリッドが見つかりませんでした。"; return Result.Cancelled; } // 2つ目の要素を選択 var secondRef = uidoc.Selection.PickObject(ObjectType.Element, "2つ目の要素を選択してください"); var secondElement = doc.GetElement(secondRef.ElementId); var secondSolid = GetSolidFromGeometry(secondElement); if (secondSolid == null) { message = "2つ目の要素からソリッドが見つかりませんでした。"; return Result.Cancelled; } // ブーリアン演算を実行し、結果をファイルに保存 var resultSolid = PerformBooleanIntersection(firstSolid, secondSolid, 0.001, "intersection_result"); if (resultSolid == null) { message = "要素の交差が見つかりませんでした。デバッグ用のファイル(intersection_result_debug.3dm)を確認してください。"; return Result.Cancelled; } TaskDialog.Show("成功", "交差部分の計算に成功し、デスクトップに'intersection_result.3dm'として保存しました。"); return Result.Succeeded; } catch (Autodesk.Revit.Exceptions.OperationCanceledException) { // ユーザーが選択をキャンセルした場合 return Result.Cancelled; } catch (Exception ex) { message = ex.Message; return Result.Failed; } } |
エクスポートしたファイルを確認する
例として2枚の壁を配置し、結合を解除したうえでコマンドを実行してみました。(壁が結合されていると、意図した交差部分が生成されない場合があるためです)
コマンド実行後、デスクトップに保存された “intersection_result.3dm” をRhinoで開くと、壁の交差部分の形状(Brep)が正しく保存されていることが確認できます。
おわりに
今回は、RevitアドインからRhino.Inside.Revitの機能を活用する方法を紹介しました。
この方法を使えば、Rhinoの強力なジオメトリ機能をRevitアドインに組み込むことが可能になります。
AMDlabでは、開発に力を貸していただけるエンジニアを募集しています。ご興味をお持ちいただけましたら、カジュアルな面談も可能ですので、お気軽にご連絡ください。
中途求人ページ: https://www.amd-lab.com/recruit-list/mid-career
カジュアル面談はエントリーフォームからお申し込みいただけます。
採用種別で「カジュアル面談(オンライン)」を選択し、必要事項をご記入の上、送信してください。
エントリーフォーム: https://www.amd-lab.com/entry
AMDlabのSNSアカウントです。ぜひフォローをお願いします!
■ X(旧Twitter):https://x.com/amdlabinc
■ Instagram:https://www.instagram.com/amdlabinc/
■ Facebook:https://www.facebook.com/amdlab.lnc/
COMMENTS