皆様こんにちは。
AMDlabの秋山です。
前回に引き続き、Dynamo×Pythonやっていきましょう。
前回から日が空いてしまい申し訳ありません。
前回の記事は導入編になりますので、まだの方はこちらから読んでいただけると理解が深まると思います。
この記事では、Dynamo×Pythonを使用するうえで重要なことをまとめています。
- DynamoUIの説明
- Pythonスクリプトの中身を確認する
- Revitの構成を知る
- RevitAPIドキュメントを活用する
- RevitアプリケーションとRevitドキュメントの違いを知る
- Revit要素をアンラップするとは
- Revit要素にフィルターをかける
- ジオメトリとは
- Dynamo上で長さを出力する
- Dynamo上で長さを変換する
DynamoUIの説明
Dynamoを使用するのでまず初めにDynamoのUIを確認しておきましょう。
Pythonスクリプトの中身を確認する
Pythonスクリプトを記述するには、ライブラリ上で検索し、PythonScriptノードをワークスペースに配置します。
CodeBlockノードとWatchノードも追加し、CodeBlockには添付写真のように配列を入力します。実行をクリックしてもPythonスクリプトにはまだ何も記述していないので、nullが出ています。
Pythonノードをクリックするとエディタ画面が表示されます。あらかじめ今回記述するコードを書いてます。
pythonスクリプトの中身を説明していきます。
1.外部からライブラリと.dllデータ(注.1)を読み込むため、ボイラープレートコードを記述します。ボイラープレートコードは、頻繁に使用するテンプレートのようなものになります。
以下をコピペして貼り付けてください。
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 |
import clr import sys sys.path.append('C:\Program Files (x86)\IronPython 2.7\Lib') import System from System import Array from System.Collections.Generic import * clr.AddReference('ProtoGeometry') from Autodesk.DesignScript.Geometry import * clr.AddReference("RevitNodes") import Revit clr.ImportExtensions(Revit.Elements) clr.ImportExtensions(Revit.GeometryConversion) clr.AddReference("RevitServices") import RevitServices from RevitServices.Persistence import DocumentManager from RevitServices.Transactions import TransactionManager clr.AddReference("RevitAPI") clr.AddReference("RevitAPIUI") import Autodesk from Autodesk.Revit.DB import * from Autodesk.Revit.UI import * doc = DocumentManager.Instance.CurrentDBDocument uiapp = DocumentManager.Instance.CurrentUIApplication app = uiapp.Application uidoc = uiapp.ActiveUIDocument |
IronPython(注.2)を使用することで、.NET Frameworkライブラリにアクセスすることが可能になります。
作成するプログラム次第ですが、ここに乗せたボイラープレートコードは全てインポートする必要はありません。
ただ、それぞれどのライブラリから何をインポートしているかを理解しておく必要はあるので、次回こちらのインポートの仕方や参照先について詳しく解説していこうと思います。
今回は、とりあえず全てコピペしてインポートします。
2.Dynamo上の入力ポートに1~5の数字のリストを作成し、inputlistに代入します。
3.出力用の空リストを作成しています。
作成したリストをコードの最後でOUTに代入しています。
4.入力された数字のリストをfor文で繰り返し、入力数字に1を足した数字を出力リストに追加します。
5.最後にwatchノードで出力を確認します。入力の数字に+1された数字のリストが確認できます。
(注.1)ダイナミックリンクライブラリとよばれ、プログラムを動かすために必要なデータが集まった部品
(注.2).NET Frameworkのライブラリを使用することのできるC#で実装されたPython
Revitの構成を知る
Revitは要素ID、カテゴリ、場所などのコンテンツが常に変更、更新されるデータベースのソフトウェアになります。
アプリケーション自体は、3Dジオメトリの編集・操作を可能にしています。
そして、Revitはアプリ内だけでは完結せず、BIM360やAutodeskForgeのようなネットワークをつなげたワークシェアリングも可能にしています。
この一連の作業をGUIのような一般的なユーザー向けのインターフェース上や、APIのようなエンジニア向けのインターフェース上でデータベースの更新を行っています。
RevitAPIドキュメントを活用する
このような建築の複合的なソフトのGUI上のコマンドは数が多いため、APIもデータが膨大になります。
RevitAPIドキュメントを見てみると、約1700のクラスに50のインターフェース、500以上の列挙型が含まれています。
さらにクラスは数百の名前空間に分かれていることも見て取れます。
そのため、RevitAPIドキュメントの見方や、実際に作成したいプログラムにどのように落とし込むか考えていく必要があります。
まず初めに、RevitAPIドキュメントの見方を説明します。
- Revitバージョン
Revitは1年に1度バージョンが更新されます。その都度、APIの内容も更新されていきます。 - 名前空間
類似または機能的に関連したクラスをグループにまとめた単位の1つです。 - クラス
- クラスの説明
- 構文
Pythonの構文はありませんが、このメソッドは何を引数に取るかなど確認することができます。 - 備考
ここではAreaクラスを例に説明していきます。
- メンバー
クラスのメンバーページには、メソッド、プロパティなどクラスがどのような機能を持つか把握できるページが1つにまとまっています。 - メソッド
メソッドはクラス内の関数のことです。関数は動作によく例えられ、このAreaクラスは何ができるかになります。1つのクラスにメソッドの数は1~複数存在します。例えば、このAreaクラスのCanBeLocked()メソッドはエリアがロックされているか確認することができます。 - プロパティ
メソッドは動作を表しますが、プロパティは形容詞的に使用します。クラスのインスタンスに形容詞を追加することで、インスタンスの性質が変更されます。
RevitアプリケーションとRevitドキュメントの違いを知る
次にRevitアプリケーションとRevitドキュメントとの違いをみていきましょう。
こちらの違いを理解することも重要です。
RevitAPIの最上位に位置するオブジェクトはアプリケーションとドキュメントになります。
またこれらは、さらに4つにわけて考えます。
Revitは一度にドキュメントを複数開いて作業することができるので、クラスを選択する前に、現在開いているドキュメントを指定する必要があります。
ここでいうドキュメントとは、
建物モデルが保存されているプロジェクトファイル(.rvt)や、ファミリが保存されている(.rfa)などのDBドキュメント
ドキュメント操作に関するUIドキュメントに分けられます。
Revitは一度にアプリケーションも複数開いて作業することもできるので、クラスを選択する前に、現在開いているアプリケーションを指定する必要があります。
ここでいうアプリケーションとは、
リボンや、ワークスペース、メインウィンドウなどのUIアプリケーション
ドキュメントの新規作成、プロジェクトの新規作成、ドキュメントの管理などのDBアプリケーション
に分けられます。
Revit要素をアンラップするとは
Pythonスクリプトにも入力ポート、出力ポートが存在しています。
数字のリストだけではなく、{Revit要素、文字列、リスト、ジオメトリ}などなど、あらゆる種類のデータを入力、出力することができます。
しかし、Revit上のモデル要素を入力する際には、Revit要素のラップを解除するという注意点がでてきます。
APIというものは、アプリケーションが存在すれば、どのソフトウェアにも存在します。
RevitAPIがあれば、DynamoAPIも存在します。DynamoはRevitと統合するように開発されていたのですが、Revit上の要素とDynamo上の要素が同じものをさしていてもクラス名に違いがありました。
そのため、Revit要素のラップを解除するには、RevitAPIのクラスをDynamoAPIのクラスに変換し、Dynamo上でRevit要素を使用することができるようにすることなのです。
またアンラップする必要があるときとは、Pythonスクリプトの入力側にRevit要素を持ってくるときです。
↓がラップ解除化の方法です。
1 |
revit_elements = UnwrapElement(IN[0]) |
revit_elements(Revit要素リスト)がUnwraElement()メソッドでラップ解除されました。
これでDynamo上でも使用することができるようになりました。
しかしRevit要素を取得するときにアンラップせずとも取得できる方法があります。
フィルターを使用してRevitAPIから、アンラップせずに直接Revit要素を取得する方法です。
Revit要素にフィルターをかける
Elementを取得する際にエレメントの名前を表すエレメントタイプとプロジェクトファイルの中で唯一の数字要素を取得できます。
Revitの FilteredElementCollectorクラスを使用することで、RevitドキュメントのデータベースからRevitの要素をフィルターをかけ、取得することができます。
欲しい要素をフィルタリングせずに取得すると、Revitは多数の要素で構成されているため、処理が重くなってしまいます。
フィルターを使用してパフォーマンス向上を図ります。
FilteredElementCollectorsクラスはElement、ElementIdのどちらかを返します。
1 2 3 4 5 |
all_furniture = FilteredElementCollector(doc) all_furniture.OfCategory(BuiltInCategory.OST_Furniture) all_furniture.WhereElementIsNotElementType() all_furniture.ToElements() OUT = all_furniture |
まずコンストラクタ―の引数としてRevitドキュメントを取得します。
次に、カテゴリーから要素にフィルターをかけます。家具カテゴリーを取得し、BuiltlnCategory列挙型を取得します。
次に、タイプを取得せずにインスタンスのみを取得します。
最後にRevit要素を返します。
これらのスクリプトはよく1行で表されます。
1 2 |
all_furniture = FilteredElementCollector(doc).OfCategory(BuiltInCategory.OST_Furniture).WhereElementIsNotElementType().ToElements() OUT = all_furniture |
他にも、いろいろな方法で、要素にフィルターをかけるクラスはたくさんあります。
こちらの記事にとても詳しく載っていますので、ぜひお読みください。
https://thebuildingcoder.typepad.com/blog/2010/10/filtered-element-collectors.html
今回は基本的なフィルター、FilteredElementCollectorクラスを使って、任意のRevit要素を取得する方法をお伝えしました。
ジオメトリとは
Revit要素のアンラップと同様に、変換が必要です。
まず、CGの世界で頻繁に目にするジオメトリとは、広意義では3D形状をもつもののことと理解していただいて問題ありません。
ジオメトリは、FacesやEdgesやVerticalsのような細かい要素で構成しています。
これらに加えてLineなどもジオメトリです。
実はこのジオメトリ、DynamoジオメトリとRevitジオメトリで異なるため、
数種類のAPIの変換メソッドを使用して変換していきます。
ToProtoType()
ToDSType()
ToLine()
ToPoint()
ToVector()
ToXyz()
簡単な例を使用します。寸法要素が含まれない点(ポイント)を使用します。
Dynamo上でポイントを作成するには、Designscript Libraryを使用します。
1 2 |
dynamo_point = Autodesk.DesignScript.Geometry.Point.ByCoordinates(0,0,0) OUT = dynamo_point |
Revitには2種類のポイントが存在します。
Autodesk.Revit.DB.XYZ
こちらはRevitのポイントとベクトルを表します。
Autodesk.Revit.DB.Point
こちらは、Revitのポイントのみ表します。
まずはPythonスクリプト上でRevitポイントを表示してみましょう。
1 2 3 |
revit_xyz = XYZ(0,0,0) revit_point = Point.Create(revit_xyz) OUT = revit_xyz, revit_point |
しかしこのままだと、Dynamo上にはジオメトリが表示されません。
Dynamoタイプに変更する必要があります。
1 2 3 |
revit_xyz = XYZ(0,0,0) revit_point = Point.Create(revit_xyz) OUT = revit_xyz.ToPoint(), revit_point.ToProtoType() |
これでDynamo上に表示されました。
次に先ほど作成したポイントを原点ではなく、xy座標を持たせます。そして点を結び直線や曲線を作成します。
線も2つ種類があります。
Autodesk.DesignScript.Geometry.Line
始点と終点をもつ直線を作成します。
Autodesk.DesignScript.Geometry.Curve
複数点を持つ曲線を作成します。
Revit上の直線の作成の仕方
1 2 3 4 |
revit_xyz_1 = XYZ ( 0 , 0 , 0 ) revit_xyz_2 = XYZ ( 10 , 10 , 0 ) revit_line = line. CreateBound ( revit_xyz_1 , revit_xyz_2 ) OUT = revit_line |
Dynamo上の直線の作成の仕方
1 2 3 4 |
revit_xyz_1 = XYZ ( 0 , 0 , 0 ) revit_xyz_2 = XYZ ( 10 , 10 , 0 ) revit_line = line. CreateBound ( revit_xyz_1 , revit_xyz_2 ) OUT = revit_line . ToProtoType () |
これでDynamoジオメトリプレビュー上に線が表示されました。
Dynamo上で長さを出力する
RevitAPIを使用していると、Revit標準の長さの単位はフィートで取得されていることに気づくと思います。
フィートは日本人にはなじみのない長さの単位になりますので、こちらを標準のミリメートルに変更する必要が出てきます。
まず、初めにRevit上の線分長さをDynamo上で確認してみましょう。
Revitで詳細線分を作成します。(長さは1000mmで作成しています。)
下記のスクリプトをPythonノード上に記述します。
1 2 3 |
detail_line = UnwrapElement(IN[0]) decimal_feet_length = detail_line.GeometryCurve.Length OUT = decimal_feet_length |
Revitから取得するモデルに関しては、アンラップをする必要があると前回の記事(リンク)でお伝えしました。
線分の長さを取得するメソッドを使用して、長さを出力します。
1フィート304.8mmですので出力に出てくる値は、3.2808…フィートになります。十進法のフィートで値が表示されています。
Dynamo上で長さを変換する方法
このままでは、使用できないので、こちらを、RevitAPIのUnitiUtilsクラスを使用して、単位をミリメートルに変換してみようと思います。
UnitiUtilsクラスにはたくさんのメソッドが存在していますが、今回は赤枠のメソッドを使用します。
引数は3つ必要で、その内2つはDisplayUnitType列挙型を選択する必要があります。
フィートをミリメートルに変換するため、下の赤枠を選択して下さい。
1 2 3 4 |
detail_line = UnwrapElement(IN[0]) decimal_feet_length = detail_line.GeometryCurve.Length metric_length = UnitUtils.Convert(decimal_feet_length, DisplayUnitType.DUT_DECIMAL_FEET, DisplayUnitType.DUT_MILLIMETERS) OUT = metric_length |
以上がDynamo×Pythonを使用するうえで重要なことになります。
COMMENTS