はじめに
AMDlab BIMエンジニアの河野(twitter@tatsukikouno)です。
RevitAPIで学ぶC#シリーズ、第5弾です。
今回はRevitの機能の一つである「拡張ストレージ」を取り上げます。
拡張ストレージについて
拡張ストレージは、API経由でのみ利用可能なRevitの標準機能です。
RevitはGUIで操作するソフトウェアなので、馴染みが無い方も多いと思います。
Revit公式の開発者ガイドには、Revitにデータを格納する手段は1つ目が共有パラメータ、2つ目が拡張ストレージと紹介されています。
共有パラメータは、あるカテゴリに対してパラメータの名前や型を定義し、そこに値を格納していくものでした。
拡張ストレージは、スキーマ(C#でいうクラス)を定義し、スキーマから作成したエンティティ(C#でいうインスタンス)を任意のElementのプロパティとして持たせることのできる機能です。
Revitのオブジェクトデータベースに定義を追加できるようなイメージですね。
拡張ストレージを使うと、共有パラメータでは出来なかったり不便だったり非効率だった処理を、シンプルに解決できることがあります。
その分、複数アドインが拡張ストレージを利用しているとなかなかにカオスな状況が生まれるのですが・・・
【RevitAPIで学ぶC#】にはぴったりな題材なので、これを機に使いこなせるようになりましょう。
拡張ストレージの利用で出てくるクラス一覧
最初は混乱すると思うので、ここにまとめておきます。
Schema・・・C#でいうクラスで、各種Fieldが定義可能
SchemaBuilder・・・Schemaを設定・作成するためのオブジェクト
Entity・・・C#でいうインスタンスで、Schemaに定義されているFieldに値を持たせることができる
Field・・・C#でいうフィールド(プロパティ)
FieldBuilder・・・Fieldに単位や説明を追加することのできるオブジェクト
Schemaを作成しよう
まずは、Revitのデータベースを変更する=トランザクションが必要なので、トランザクションを貼っておきます。
1 2 3 |
Document doc = commandData.Application.ActiveUIDocument.Document; Transaction trans = new Transaction(doc, "拡張ストレージを追加"); trans.Start(); |
次に、Schemaを作る必要があるかチェックします。
2回目以降の実行では、Schema.Lookupで以前に作成したSchemaが返ってくるので、SchemaBuilderによる処理は実行不要です。
1 2 |
Guid schemaGuid = new Guid("5B2A2D42-4BE6-4B3C-8A03-F73387C229C1") Schema schema = Schema.Lookup(schemaGuid); |
Schema.Lookupでnullが返ってきたときの処理を作成します。
Schemaを作るためのSchemaBuilderを作成します。
1 |
SchemaBuilder schemaBuilder = new SchemaBuilder(schemaGuid ); |
次に、Schemaのアクセスレベルを設定します。
読み取り権限・書き込み権限を変更可能です。
なお、アクセスレベルをAccessLevel.VendorやAccessLevel.Applicationとした場合は、実行中のアドインマニフェストの情報を見に行ってアクセスの可否を判断しているみたいです。
暗号化されるわけではないので、認証情報などを扱う場合は注意しましょう、
1 2 3 |
schemaBuilder.SetReadAccessLevel(AccessLevel.Public); schemaBuilder.SetWriteAccessLevel(AccessLevel.Vendor); schemaBuilder.SetVendorId("AMDlab"); |
次に、Schemaの名前を設定します。
今回は、設計者のデータを格納するためのスキーマにしてみます。
1 |
schemaBuilder.SetSchemaName("DesignersInformation"); |
次に、Schema に Field を定義します。定義する Field は以下のとおりです。
- 設計者の名前(文字列)
- 年齢(整数)
- 保有資格のリスト(文字列のリスト)
- 好きなものの辞書(文字列をキーとした文字列の辞書)
1 2 3 4 5 6 7 8 9 10 11 |
FieldBuilder nameFieldBuilder = schemaBuilder.AddSimpleField("DesignerName", typeof(string)); nameFieldBuilder.SetDocumentation("設計者の名前を格納します。"); FieldBuilder ageFieldBuilder = schemaBuilder.AddSimpleField("Age", typeof(int)); ageFieldBuilder.SetDocumentation("設計者の年齢を格納します。"); FieldBuilder qualificationsFieldBuilder = schemaBuilder.AddArrayField("Qualifications", typeof(string)); qualificationsFieldBuilder.SetDocumentation("設計者の保有資格をリストで格納します。"); FieldBuilder favoritesFieldBuilder = schemaBuilder.AddMapField("Favorites", typeof(string), typeof(string)); favoritesFieldBuilder.SetDocumentation("設計者の好きなものをキーと値のペアで格納します。"); |
これでSchemaBuilderを用いた設定が完了なので、Schemaを作成します。
1 |
Schema schema = schemaBuilder.Finish(); |
Schemaが確定したらFieldを取得しておきます。
1 2 3 4 |
nameField = schema.GetField("DesignerName"); ageField = schema.GetField("Age"); qualificationsField = schema.GetField("Qualifications"); favoritesField = schema.GetField("Favorites"); |
Schemaから拡張ストレージを作成しよう
定義したスキーマからエンティティを作成し、データを設定します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
Entity entity = new Entity(schema); // 設計者の名前と年齢を設定 entity.Set(nameField, "河野達己"); entity.Set(ageField, 35); // 保有資格のリストを設定 IList<string> qualifications = new List<string> { "特級建築士", "構造設計特級建築士" }; entity.Set(qualificationsField, qualifications); // 好きなものの辞書を設定 IDictionary<string, string> favorites = new Dictionary<string, string> { { "色", "青" }, { "食べ物", "魚" }, { "生き物", "猫" } }; entity.Set(favoritesField, favorites); |
作成したエンティティを任意のElementに設定します。
今回は、最もポピュラーなElementの1つであるProjectInformationをターゲットとします。
1 2 |
ProjectInfo projectInfo = doc.ProjectInformation; projectInfo.SetEntity(entity); |
1 |
trans.Commit(); |
拡張ストレージのチェック!
コードを実行したら、Revit Lookupで確認してみましょう
ただし、Revit Lookupでは各Fieldに入っている値までは確認できないようでした。
フィールドまで確認するには、以下のようなコードを書くしか無いみたいですね。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
Entity retrievedEntity = projectInfo.GetEntity(schema); string designerName = retrievedEntity.Get<string>(nameFieldBuilder); int age = retrievedEntity.Get<int>(ageFieldBuilder); IList<string> retrievedQualifications = retrievedEntity.Get<IList<string>>(qualificationsFieldBuilder); IDictionary<string, string> retrievedFavorites = retrievedEntity.Get<IDictionary<string, string>>(favoritesFieldBuilder); TaskDialog.Show("設計者情報", $"名前: {designerName}\n" + $"年齢: {age}\n" + $"保有資格: {string.Join(", ", retrievedQualifications)}\n" + $"好きなもの:\n" + $"{string.Join("\n", retrievedFavorites.Select(kv => $"{kv.Key}: {kv.Value}"))}"); |
おわりに
お疲れ様でした。
パラメータによる値の保持はRevitを操作する人からどうしても見えてしまうので、機械的に値を記憶したい場合は拡張ストレージをぜひ使ってみてください。
なお、今回は紹介しきれませんでしたが、FieldにはEntity型を定義することも可能です。
自分はあまり活用したことが無いのですが、複雑なオブジェクトでも(ある程度は)そのまま保存できるので、案件によっては便利に使えそうです。
弊社では随時BIMエンジニア、コンピュテーショナルデザイナーを募集しています。
ご興味のある方は、DMかContactからご連絡ください。
コード全文
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 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
[Transaction(TransactionMode.Manual)] public class AddExtensibleStorage : IExternalCommand { public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) { // Document の取得 Document doc = commandData.Application.ActiveUIDocument.Document; // トランザクションの開始 Transaction trans = new Transaction(doc, "拡張ストレージを追加"); trans.Start(); // Schema の GUID を定義 Guid schemaGuid = new Guid("5B2A2D42-4BE6-4B3C-8A03-F73387C229C1"); // Schema の存在をチェック Schema schema = Schema.Lookup(schemaGuid); if (schema == null) { // Schema が存在しない場合、新規作成 SchemaBuilder schemaBuilder = new SchemaBuilder(schemaGuid); // アクセスレベルの設定 schemaBuilder.SetReadAccessLevel(AccessLevel.Public); schemaBuilder.SetWriteAccessLevel(AccessLevel.Vendor); schemaBuilder.SetVendorId("com.amd-lab"); // Schema の名前を設定 schemaBuilder.SetSchemaName("DesignersInformation"); // 設計者の名前フィールドを定義 FieldBuilder nameFieldBuilder = schemaBuilder.AddSimpleField("DesignerName", typeof(string)); nameFieldBuilder.SetDocumentation("設計者の名前を格納します。"); // 年齢フィールドを定義 FieldBuilder ageFieldBuilder = schemaBuilder.AddSimpleField("Age", typeof(int)); ageFieldBuilder.SetDocumentation("設計者の年齢を格納します。"); // 保有資格リストフィールドを定義 FieldBuilder qualificationsFieldBuilder = schemaBuilder.AddArrayField("Qualifications", typeof(string)); qualificationsFieldBuilder.SetDocumentation("設計者の保有資格をリストで格納します。"); // 好きなものの辞書フィールドを定義 FieldBuilder favoritesFieldBuilder = schemaBuilder.AddMapField("Favorites", typeof(string), typeof(string)); favoritesFieldBuilder.SetDocumentation("設計者の好きなものをキーと値のペアで格納します。"); // Schema の作成 schema = schemaBuilder.Finish(); } // Field を取得 Field nameField = schema.GetField("DesignerName"); Field ageField = schema.GetField("Age"); Field qualificationsField = schema.GetField("Qualifications"); Field favoritesField = schema.GetField("Favorites"); // エンティティの作成 Entity entity = new Entity(schema); // 設計者の名前と年齢を設定 entity.Set(nameField, "河野達己"); entity.Set(ageField, 35); // 保有資格のリストを設定 IList<string> qualifications = new List<string> { "特級建築士", "構造設計特級建築士" }; entity.Set(qualificationsField, qualifications); // 好きなものの辞書を設定 IDictionary<string, string> favorites = new Dictionary<string, string> { { "色", "青" }, { "食べ物", "魚" }, { "生き物", "猫" } }; entity.Set(favoritesField, favorites); // ProjectInfo エレメントを取得 ProjectInfo projectInfo = doc.ProjectInformation; // エンティティをエレメントに設定 projectInfo.SetEntity(entity); // トランザクションのコミット trans.Commit(); // 処理完了のメッセージを表示 TaskDialog.Show("完了", "設計者の情報を拡張ストレージに保存しました。"); Entity retrievedEntity = projectInfo.GetEntity(schema); string designerName = retrievedEntity.Get<string>(nameField); int age = retrievedEntity.Get<int>(ageField); IList<string> retrievedQualifications = retrievedEntity.Get<IList<string>>(qualificationsField); IDictionary<string, string> retrievedFavorites = retrievedEntity.Get<IDictionary<string, string>>(favoritesField); TaskDialog.Show("設計者情報", $"名前: {designerName}\n" + $"年齢: {age}\n" + $"保有資格: {string.Join(", ", retrievedQualifications)}\n" + $"好きなもの:\n" + $"{string.Join("\n", retrievedFavorites.Select(kv => $"{kv.Key}: {kv.Value}"))}"); return Result.Succeeded; } } |
COMMENTS