ここでは、さまざまなベスト プラクティスを紹介します。これらのベスト プラクティスは、これまでの経験と調査によって得たいくつかの方策が、品質の高いパラメトリック ワークフローを構築するために最も効果的であることを明らかにしています。設計者やプログラマ同様、オートデスクが評価する品質の基準は、主にツールの保守性、信頼性、利便性、効率性です。ここで紹介するベスト プラクティスでは、ビジュアルベースまたはテキストベースのスクリプト作成における具体的な例を挙げていますが、これらの原則は、すべてのプログラミング環境に適用でき、さまざまな計算ワークフローを示すことができます。
この章に入る前に、Dynamo の強力なビジュアル スクリプト機能の実装方法について説明しました。これらの機能を正しく理解することが、堅固なビジュアル プログラムを開発するための基礎となり、第一歩となります。実際の現場でビジュアル プログラムを使用する場合、チーム メンバーとビジュアル プログラムを共有する場合、エラーのトラブルシューティングを行う場合、制限値のテストを行う場合などは、新たな問題が発生します。自分が作成したプログラムを他のメンバーが使用する場合や、今から 6 ヵ月後にプログラムを起動するような場合は、外観的な面でも論理的な面でも、すぐに理解できるようなプログラムを作成する必要があります。Dynamo には、複雑なプログラムを管理するためのさまざまなツールが用意されています。この章では、そうしたツールを使用する場合のガイドラインについて説明します。
Dynamo でプログラムを作成したり、アイデアをテストする場合、そのサイズと複雑さが急激に増大することがあります。正しく機能するプログラムを作成することはもちろん重要なことですが、可能な限り簡潔なプログラムを作成することも同様に重要です。簡潔なプログラムを作成することにより、プログラムの処理速度と精度が上がるだけでなく、後で他のメンバーとともにコードを解析する場合も、ロジックを簡単に追うことができるようになります。ここでは、プログラムのロジックを分かりやすく記述するための方法をいくつか紹介します。
プログラムの作成時にグループを使用して、機能別に異なるパーツを作成することができます。
グループを使用すると、各モジュールとその配置を維持しながら、プログラム内の大きなパーツを移動することができます。
グループの色を変えて、各グループの用途(入力や関数など)を区別することができます。
グループを使用してプログラムを整理し、カスタム ノードの作成を簡素化することができます。
このプログラムでは、各グループの用途を色で示しています。この方法により、開発するプログラムの標準やテンプレート内で階層を作成することができます。
関数グループ(青)
入力グループ(オレンジ色)
スクリプト グループ(緑)
グループの使用方法については、「プログラムを管理する」を参照してください。
必要に応じてコード ブロックを使用すると、検索するよりも速く、数値メソッドやノード メソッドを入力することができます(Point.ByCoordinates、Number、String、Formula)。
DesignScript でカスタム関数を定義してプログラム内のノードの数を減らす場合は、コード ブロックを使用すると便利です。
1 と 2 は、どちらも同じ関数を実行します。各ノードを個別に検索して追加するよりも、コードを何行か入力する方が、ずっと速く作業を進めることができます。また、コード ブロックのサイズもずっと小さくなります。
コード ブロックを使用して記述した設計スクリプト
ノードを使用して同じスクリプトを記述した場合
コード ブロックの使用方法については、「コード ブロックとは」を参照してください。
[ノードをコード化]機能を使用して、画面上の煩雑さを軽減することができます。この機能では、複数の単純なノードを 1 つにまとめることにより、それらのノードに対応する DesignScript が 1 つのコード ブロック内で記述されます。
[ノードをコード化]機能を使用すると、プログラムの明確性を損なうことなく、コードをまとめることができます。
[ノードをコード化]機能を使用するメリットには、次のようなものがあります。
コードを編集可能な 1 つのコンポーネントとして簡単に集約できる
画面上の大部分を簡素化できる
小さなプログラムを頻繁に編集する必要がない場合に便利である
関数など、他のコード ブロック機能を組み込む場合に便利である
[ノードをコード化]機能を使用するデメリットには、次のようなものがあります。
一般的な命名規則が使用されるため、コードの内容が多少わかりにくくなる
他のユーザにとって、コードの理解が難しくなる
元のビジュアル プログラムに簡単に戻すことができない
既存のプログラム
[ノードをコード化]機能によって作成されたコード ブロック
[ノードをコード化]機能の使用方法については、「DesignScript 構文」を参照してください。
List.Map ノードと List.Combine ノードはキャンバス上で大きなスペースを占有する場合がありますが、List@Level 機能を使用してこれらのノードを置き換えることにより、画面上の煩雑さを軽減することができます。
List@Level 機能を使用すると、ノードの入力ポートからリスト内の任意のレベルに直接アクセスできるため、List.Map ノードや List.Combine ノードを使用するよりも速くノード ロジックを記述できます。
CountTrue ノードの list 入力で List@Level 機能を有効にすると、BoundingBox.Contains ノードから返される True 値の数と、その True 値を返すリストを確認できます。List@Level 機能により、入力データの取得元となるレベルを特定することができます。List.Map ノードと List.Combine ノードを使用する場合、List@Level 機能は、他の方法よりも柔軟で効率的な方法です。これらのノードで作業を行う場合は、List@Level 機能を使用することを強くお勧めします。
リスト レベル 2 で True 値の数をカウント
リスト レベル 3 で True 値の数をカウント
List@Level 機能の使用方法については、「リストのリスト」を参照してください。
可能な限り簡潔で効率的なプログラムを作成するには、見やすいプログラムを作成するということに重点を置く必要があります。論理的にグループ化された直感的なプログラムを作成した場合であっても、データ間の関係性が分かりにくくなることがあります。グループ内に簡単な注記を記載したり、スライダー名を分かりやすい名前に変更すると、自分だけでなく他のメンバーも、名前などで混乱したり、画面上を無駄に移動することがなくなります。ここでは、プログラム全体で一貫した外観を保つための方法をいくつか紹介します。
プログラム作成後の作業量を減らすには、プログラムの作成時に頻繁にノードの配置を調整して、ノードのレイアウトを見やすく整える必要があります。
自分が作成したプログラムで他のメンバーが作業を行う場合は、ワイヤが自然な方向に流れるように各ノードを配置する必要があります。
ノードを配置するには、[ノードのレイアウトをクリーンアップ]機能を使用してノードの配置を自動的に調整します。ただし、手動で調整する場合と比べて、多少精度が下がることに注意してください。
ノードが整理されていない画面
ノードが整理されている画面
ノードの配置を調整する方法については、「プログラムを管理する」を参照してください。
入力の名前を変更することにより、自分が作成したプログラムを他のメンバーが使用する場合でも、内容を簡単に理解できるようになります。特に、入力の接続先ノードが画面からはみ出してしまうような場合は、入力名からそのノードの内容を推測できるため、 分かりやすい名前を付けておくと便利です。
入力以外のノード名を変更する場合は、注意が必要です。 その場合は、別の方法として、ノード クラスタからカスタム ノードを作成し、そのカスタム ノードの名前を変更します。こうすることにより、そのノードの内容は、他のノードとは異なっているということを示すことができます。
サーフェスを操作するための入力
建築設計パラメータ用の入力
排水シミュレーション スクリプト用の入力
ノード名を変更するには、変更するノード名を右クリックして[ノードの名前を変更...]を選択します。
ノードでは表現できないような分かりやすい説明をプログラムに挿入する必要がある場合は、ノートと呼ばれる注記を追加します。
ノードの集合やグループのサイズが大きすぎて(または複雑すぎて)簡単には理解できない場合は、ノートを追加することをお勧めします。
行の移動距離を返すプログラムの特定の箇所を説明するためのノート
上記の移動距離の値を正弦波にマッピングするコードを説明するためのノート
ノートの追加方法については、「プログラムを管理する」を参照してください。
ビジュアル スクリプトを作成する場合、正しい値がスクリプトから返されるかどうかを確認することが重要になります。すべてのエラーが、プログラムの即時停止につながるエラーというわけではありません。特に、Null 値やゼロの値に関するエラーは、プログラムの下流部分に影響する場合があるため、注意が必要です。この方法は、「スクリプト作成のガイドライン」の章でも、テキスト スクリプトに関連する形で記載されています。次の演習では、正しい結果を得る方法について確認していきます。
プログラムの作成時にウォッチ バルーンまたはプレビュー バルーンを使用すると、重要な出力データが正しく返されるかどうかを確認することができます。
この例では、Watch ノードを使用して、次のデータを比較しています。
行の移動距離
正弦式から渡された値
Watch ノードの使用方法については、「ライブラリ」を参照してください。
自分が他のメンバーとは別の作業を行っている場合であっても、自分が作成したプログラムを後で他のメンバーが使用するというのは非常によくあることです。そうした場合に備えて、入力データと出力データから、プログラムの内容と結果を短時間で把握できるようにしておく必要があります。これは特に、カスタム ノードを開発して Dynamo コミュニティで共有し、他のメンバーが作成したプログラム内でそのカスタム ノードを使用する場合に重要になります。こうすることにより、簡単に再利用できる堅固なプログラムとノードを作成することができます。
プログラムの読みやすさと拡張性を確保するため、入力と出力は可能な限り少なくすることをお勧めします。
キャンバス上でノードを追加する前に、ロジックの概要を組み立ててから、そのロジックをどのように作成していくかを検討するようにしてください。概要を組み立てる際に、スクリプト内で使用する入力と出力を検討する必要があります。
特定のオプションや条件をプログラム内に組み込む場合は、プリセットを使用すると、迅速に作業を進めることができます。
また、長期間実行されるプログラム内でプリセットを使用して特定のスライダ値をキャッシュすると、プログラムの複雑さを軽減することができます。
プリセットの使用方法については、「プリセットを使用してデータを管理する」を参照してください。
プログラムを構成する各ノードを 1 つのコンテナ内に収集できる場合は、カスタム ノードを使用することをお勧めします。
他のプログラム内で一部のコードを頻繁に再利用する場合は、カスタム ノードを使用することをお勧めします。
Dynamo コミュニティ内で特定の機能を共有する場合は、カスタム ノードを使用することをお勧めします。
点の移動プログラムを構成する各ノードをカスタム ノード内に収集すると、移植可能で堅固な一意のプログラムを作成することができます。また、プログラムの内容も簡単に理解できるようになります。入力ポートに分かりやすい名前を付けると、他のメンバーがそのプログラムを使用する際に、ノードの使用方法を簡単に理解できるようになります。すべての入力について、説明と必要なデータ タイプを追加してください。
既存のアトラクタ プログラム
上記のプログラムを構成する各ノードを収集するためのカスタム ノード「PointGrid」
カスタム ノードの使用方法については、「カスタム ノードの概要」を参照してください。
テンプレートを作成してビジュアル プログラム全体の外観的な標準を定義することにより、すべてのチーム メンバーが標準化された方法でプログラムを理解できるようになります。
テンプレートを作成する際に、グループの色とフォント サイズを標準化して、ワークフローやデータ操作のタイプを分類することができます。
テンプレートを作成する際に、プログラム内のワークフローのフロントエンドとバックエンドとの差異について、ラベルを付けたり、色を付けたり、スタイルを設定することもできます。
プログラムの UI (フロントエンド)。プロジェクト名、入力スライダ、読み込みジオメトリが表示されます。
プログラムのバックエンド。
グループ(一般的な設計、入力、Python スクリプト、読み込まれたジオメトリ)を区別するための色分け。
下のリンクをクリックして、サンプル ファイルをダウンロードします。
すべてのサンプルファイルの一覧については、付録を参照してください。
この演習では、上で説明したベスト プラクティスを構造化されていないプログラムに適用してみましょう。このプログラムでは、屋根を正しく作成することができますが、計画的に作成されたものではないため、構造化されていない状態になっています。各ノードの配置は整理されておらず、ノードの用途を示す説明も入力されていません。このプログラムの作成者以外のユーザもこのプログラムの内容を理解できるように、ノード配置の整理、説明の追加、プログラムの解析について、ベスト プラクティスを適用する手順を順に見ていきましょう。
このプログラムは正しく機能しますが、ノードが乱雑に配置されているため、見にくくなっています。
最初に、プログラムから返されるデータとジオメトリを確認しましょう。
論理的な単位であるモジュールを作成する場合、データが大きく変更されるタイミングを把握することが非常に重要になります。Watch ノードを使用してプログラムを検査し、ノードのグループ化を検討してから、次のステップに進むようにしてください。
このコード ブロックには数式が記述されているため、プログラムの重要な部分を構成していると考えられます。Watch ノードを使用すると、プログラムから返される移動距離のリストを表示することができます。
これらのノードの用途については、一見しただけではよくわかりません。BoundingBox.Contains ノードのリスト レベル L2 の True 値の配置と、List.FilterByBoolMask ノードが使用されていることから考えると、点構成グリッドの一部をサンプリングしていることが推測できます。
プログラム内の各要素の内容が理解できたら、それらの要素をグループ化します。
ノードをグループ化することにより、プログラムを構成するパーツを視覚的に区別できるようになります。
3D サイト モデルを読み込むグループ
正弦式に基づいて点構成グリッドを移動するグループ
点構成グリッドの一部をサンプリングするグループ
建築設計で使用する屋根のサーフェスを作成するグループ
ガラス カーテン ウォールを作成するグループ
グループ化が完了したら、ノードの配置を調整して、プログラム全体の流れを見やすく整理します。
プログラムの流れを見やすく整理することにより、プログラムの構造と各ノード間の暗黙的な関係を把握できるようになります。
プログラムをさらに見やすくするため、外観的な情報を追加してみましょう。ここでは、プログラムの特定の領域がどのように機能するかを示すためのノートを追加し、入力のカスタム名を設定し、グループのタイプを区別するための色を割り当てます。
これらの外観的な情報を追加することにより、プログラムの内容がさらに分かりやすくなります。グループを色分けすると、関数から渡される入力を簡単に区別することができます。
ノート
分かりやすい名前が設定された入力
プログラムの集約を開始する前に、プログラムのどの位置に Python スクリプトの排水シミュレータを組み込むかについて確認しましょう。スケーリングされた最初の屋根のサーフェスの出力を、それぞれのスクリプト入力に接続します。
ここでは、上図の位置にスクリプトを組み込みます。これにより、元の屋根のサーフェス上で排水シミュレーションを実行できるようになります。このサーフェスはプレビュー表示されていませんが、このサーフェスにより、面取りされたポリサーフェスの上部サーフェスを選択する必要がなくなります。
スクリプト入力のソース ジオメトリ
Python ノード
入力スライダ
オン/オフ スイッチ
これですべての準備が整ったので、プログラムを集約してみましょう。
[ノードをコード化]と[カスタム ノード]を使用してプラグラムを集約すると、プログラムのサイズが大幅に削減されます。屋根のサーフェスと壁を作成するグループは、このプログラムにとって非常に重要な機能を実行するグループであるため、コードに変換されています。点を移動するグループは、他のプログラムでも使用できるように、カスタム ノード内に集約されています。このサンプル ファイルで、点を移動するグループを使用して、独自のカスタム ノードを作成してみてください。
点構成グリッドを移動するグループを格納するためのカスタム ノード
建築設計で使用する屋根のサーフェスとカーテン ウォールを作成するグループを集約するための[ノードをコード化]機能
最後に、サンプルの屋根形状用のプリセットを作成します。
上図の各入力が、屋根形状の主要な駆動要素になります。これらの入力を確認することにより、プログラムの概要を把握することができます。
2 つのプリセットは、次のようなビューとして表示されます。
屋根の排水パターンを指定することにより、それぞれのプリセットをさまざまな角度から解析することができます。
このリファレンス ページでは、「スクリプト作成のガイドライン」のページで紹介したベスト プラクティスを、コード ライブラリ、ラベル付け、スタイル設定によってさらに拡張する方法について説明します。ここでは、Python を使用して次に示す概念を説明しますが、Python だけでなく C#(Zerotouch)についても、同じ概念が異なる構文で適用されます。
標準ライブラリは Dynamo の外部に存在し、プログラミング言語の Python や C# (Zerotouch)の内部で使用されます。Dynamo には、ノード階層に直接対応する専用のライブラリ セットも用意されています。これらの専用ライブラリにより、ノードとワイヤを使用して作成したコード内で、あらゆる処理を記述することができます。ここからは、各 Dynamo ライブラリの内容と、どのような場合に標準ライブラリを使用するかについて説明します。
標準ライブラリと Dynamo ライブラリ
Dynamo 環境内で Python と C# の標準ライブラリを使用すると、高度なデータ構造とフロー構造を定義できます。
Dynamo ライブラリは、ジオメトリなどの Dynamo オブジェクトを作成するためのノード階層に直接対応しています。
Dynamo ライブラリ
ProtoGeometry*
機能: 円弧、境界ボックス、円、円錐、座標系、立方体、曲線、円柱、エッジ、楕円、楕円弧、面、ジオメトリ、らせん、インデックス グループ、線分、メッシュ、NURBS 曲線、NURBS サーフェス、平面、点、ポリゴン、長方形、ソリッド、球体、サーフェス、トポロジ、T スプライン、UV、ベクトル、頂点。
読み込み方法: import Autodesk.DesignScript.Geometry
``
DSCoreNodes
機能: 色、色範囲(2D)、日時、期間、I/O、式、ロジック、リスト、数式、クアッドツリー、文字列、スレッド。
読み込み方法: import DSCore
モザイク模様
機能: 凸型ハル、ドローネー、ボロノイ図。
読み込み方法: import Tessellation
DSOffice
機能: Excel。
読み込み方法: import DSOffice
*注: Python または C# で ProtoGeometry を使用すると、非管理オブジェクト(メモリを手動で管理する必要があるオブジェクト)が作成されることに注意してください。詳細については、「非管理オブジェクト」のセクションを参照してください。
スクリプトを作成する際には、頻繁に識別子を使用して、変数、タイプ、関数などのエンティティを区別する必要があります。アルゴリズムの作成時に、文字列から構成されるラベルを付けることにより、アルゴリズムの内容が分かりやすくなります。コードを記述する際に分かりやすい名前を付けると、他のメンバーがそのコードの内容を簡単に理解できるようになるだけでなく、後から自分でコードを読む場合にも役立ちます。スクリプト内でエンティティに名前を付ける場合のヒントをいくつか紹介します。
略語を使用する場合は、その略語の意味をコメントで記述する:
冗長な名前は付けない:
If 文で変数名を記述する場合は、If not 文を使用しない:
単語を連結した変数を使用する場合は、「主語_形容詞」という順にする:
このように形式を統一すると、意味がさらに分かりやすくなります。
長い名前を繰り返し使用する場合は、エイリアスを使用する:
ただし、頻繁にエイリアスを使用すると、非常に混乱した分かりにくいプログラムになる場合があります。
必要な単語だけを使用する:
「ものごとはできるかぎりシンプルにすべきだ。しかし、シンプルすぎてもいけない」 - アルバート・アインシュタイン
プログラムを作成する方法は 1 つだけではないため、スクリプトを記述する場合は「個人的なスタイル」を基準として、さまざまなことを判断しながらスクリプトを記述していくことになります。そのため、コード内のスタイルが統一されているかどうか、一般的な形式のスタイルに準拠しているかどうかが、コードの読みやすさと保守作業の容易さに直接影響することになります。一般的に、同じコードが 2 箇所で記述されている場合、それらのコードは同じように機能すると考えられます。ここで、スタイルが統一された分かりやすいコードを記述するためのヒントをいくつか紹介します。
命名規則: (次に示すいずれかの命名規則に従って、コード内の各種タイプのエンティティに名前を付けてください)
変数、関数、メソッド、パッケージ、モジュール:
lower_case_with_underscores
クラス、例外:
CapWords
保護されているメソッド、内部関数:
_single_leading_underscore(self, ...)
プライベート メソッド:
__double_leading_underscore(self, ...)
定数:
ALL_CAPS_WITH_UNDERSCORES
ヒント: 非常に短いコード ブロック内で、明確な文脈で意味がはっきりと理解できる場合を除き、1 文字だけの変数は使用しないでください(特に、l、O、I の使用は避けてください)。
空白行を使用する:
最上位関数とクラス定義の前後に、2 行の空白行を挿入してください。
クラス内に記述されているメソッド定義の場合は、その前後に空白行を 1 行挿入します。
空白行を挿入して、関連する関数グループを区別してもかまいません(ただし、あまり多くの空白行を挿入しないようにしてください)。
余分な空白を挿入しない:
丸括弧、角括弧、中括弧の内側に、空白を挿入しないでください。
カンマ、セミコロン、コロンの直前に、空白を挿入しないでください。
関数呼び出しの引数リストが記述されている括弧の直前に、空白を挿入しないでください。
インデックスまたはスライシングが記述された括弧の直前に、空白を挿入しないでください。
次に示すバイナリ演算子については、必ず前後に空白を 1 つずつ挿入してください。
行の長さに注意する:
1 行の長さは 79 文字以内にしてください。
使用するエディタ ウィンドウの幅を制限することにより、複数のファイルを並べて表示できるようになるため、2 つのバージョンを並べて表示するコード レビュー ツールを使用して作業を行う場合に便利です。
複数の式が記述されている長い行の場合は、式を丸括弧で囲んで改行すると、1 行を複数の行に分割することができます。
余分なコメントや冗長なコメントを記述しない:
コメントを少なくした方が、コードが読みやすくなる場合があります。特に、コメントの代わりに分かりやすい名前を使用すると効果的です。
適切な方法でコードを記述することにより、必要以上にコメントを入力することがなくなります。
ヒント: コードの内容が簡単に理解できるようなコメントを入力し、処理内容が明確に理解できるようなコードを記述することが重要です。
オープン ソース コードを確認する:
オープン ソース プロジェクトというプロジェクトがありますが、これは、多くの開発者が協力して立ち上げたプロジェクトです。これらのプロジェクトでは、チーム内で可能な限り効率的に作業を進めることができるように、読みやすいコードを記述することが求められます。そのため、これらのプロジェクトで使用されているソース コードを参照すると、開発者がどのようなコードを記述しているのかを確認することができます。
次の項目を確認することにより、命名規則を改善することができます。
ニーズに適した命名規則になっているかどうか。
命名規則が原因で、機能や効率性に影響していないかどうか。
次に示す各 Wiki ページで、Dynamo で C# (Zerotouch)を記述する場合のガイド情報を参照できます。
この Wiki ページには、コードのドキュメント化とテストを行う場合の一般的なコーディング標準が記載されています: https://github.com/DynamoDS/Dynamo/wiki/Coding-Standards
この Wiki ページには、ライブラリ、カテゴリ、ノード、ポート、略称に関する命名規則の標準が記載されています: https://github.com/DynamoDS/Dynamo/wiki/Naming-Standards
非管理オブジェクト:
Python または C# で Dynamo のジオメトリ ライブラリ (ProtoGeometry) を使用してジオメトリ オブジェクトを作成した場合、それらのオブジェクトは仮想マシンによって管理されないため、それらの多くのオブジェクトについて、メモリを手動でクリーンアップする必要があります。ネイティブ オブジェクトと非管理オブジェクトは、いずれも、Dispose メソッドまたは using キーワードを使用してクリーンアップできます。概要については、次の Wiki エントリを参照してください: https://github.com/DynamoDS/Dynamo/wiki/Zero-Touch-Plugin-Development#dispose--using-statement
破棄する必要があるのは、プログラム内に返されることがない非管理オブジェクト、または参照情報が格納されない非管理オブジェクトだけです。ここからは、こうしたオブジェクトのことを「中間ジオメトリ」と呼ぶことにします。次のサンプル コードでは、例として、このようなオブジェクトのクラスが記述されています。このコードに記述されている Zero Touch の C# 関数である singleCube は、立方体を 1 つだけ返しますが、この関数の実行中に 10000 個の立方体が作成されます。この処理は、他のジオメトリが一部の中間構築ジオメトリとして使用されたものと想定することができます。
この Zero Touch 関数を実行すると、かなりの確率で Dynamo がクラッシュします。 このコードでは 10000 個の立方体が作成されますが、格納されてプログラムに返されるのは、そのうちの 1 つのみです。代わりに、プログラムに返す 1 つを除いて、残りの中間立方体をすべて破棄する必要があります。プログラムに返す立方体は、プログラム内に伝播されて他のノードで使用されるため、ここでは破棄しません。
修正後のコードは次のようになります。
通常、破棄する必要があるジオメトリは、Surfaces
、Curves
、Solids
のみです。ただし、念のため、すべてのタイプのジオメトリ(Vectors
、Points
、CoordinateSystems
)を破棄することをお勧めします。
ビジュアル プログラミングは非常にクリエイティブな作業ですが、ワークスペースの複雑性やレイアウトの関係で、プログラム フローや主要なユーザ入力がすぐにわかりにくくなる場合があります。ここでは、プログラムの管理に関するベスト プラクティスをいくつか確認してみましょう。
ワークスペースにある程度の数のノードを追加した場合は、画面を見やすくするためにノードのレイアウトを再編成することをお勧めします。複数のノードを選択してワークスペースを右クリックすると、X と Y で位置合わせオプションや分配オプションを指定するための [選択を位置合わせ] メニューがポップアップ ウィンドウに表示されます。
複数のノードを選択します。
ワークスペースを右クリックします。
[選択を位置合わせ] オプションを使用します。
Dynamo の操作に慣れてくると、ノード名とプログラム フローを確認することにより、ビジュアル プログラムを「読む」ことができるようになります。経験のレベルを問わず、すべてのユーザにとって、わかりやすい名前と説明を入力することが重要になります。そのため、Dynamo には、編集可能なテキスト フィールドが含まれているノート ノードが用意されています。ノートをワークスペースに追加する方法は 2 つあります。
[編集] > [ノートを作成]メニューを参照します。
キーボード ショートカット[Ctrl]+[W]を使用します。
ワークスペースにノートが追加されると、ノート内のテキストを編集するためのテキスト フィールドがポップアップ表示されます。ノートが作成されると、ノート ノードをダブルクリックするか右クリックしてノートを編集できるようになります。
ビジュアル プログラムのサイズが大きい場合、大まかな実行手順が特定できると便利です。グループを使用してノードの集合をハイライト表示し、色付きの長方形にタイトルが表示されたラベルを付けることができます。複数のノードを選択してグループを作成する方法は 3 つあります。
[編集] > [グループを作成]メニューを参照します。
キーボード ショートカット[Ctrl]+[G]を使用します。
ワークスペースを右クリックし、[グループを作成]を選択します。
作成したグループについては、タイトルやカラーなどの設定を編集できます。
ヒント: ノードとグループの両方を使用すると、わかりやすい注釈をファイルに簡単に追加することができます。
ここで、ノートとグループを追加したプログラムの例を示します。
ノート: 「Grid Parameters」
ノート: 「Grid Points」
グループ:「Create a Grid of Points」
グループ:「Create an Attractor Point」
ノート: 「Calibrate Distance Values」
ノート: 「Variable Grid of Circles」
ビジュアル スクリプト環境内で、DesignScript、Python、ZeroTouch (C#)を使用してテキストベースのスクリプトを作成すると、機能性の高い視覚的な関係を構築することができます。同じワークスペース内で Python や C# を使用して、入力スライダなどの要素を画面上に表示したり、大規模な操作を DesignScript 内に集約したり、便利なツールやライブラリにアクセスすることができます。こうした方法を組み合わせて効率的に管理することにより、プログラム全体のカスタマイズ性、明確性、効率性が大幅に向上します。ここでは、テキスト スクリプトを使用してビジュアル スクリプトを拡張するための一連のガイドラインを紹介します。
テキスト スクリプトを使用すると、ビジュアル スクリプトよりも複雑な関係を記述することができます。ただし、テキスト スクリプトとビジュアル スクリプトの機能は多くの点で重複しています。事前にパッケージ化された便利なコードがビジュアル スクリプトのノードであるため、ビジュアル スクリプトで多くの機能が重複するのは避けられないことです。ビジュアル スクリプトを使用すると、Dynamo プログラム全体を DesignScript または Python で作成することができます。ただし、ノードとワイヤのインタフェースを使用すると、グラフィカルな情報を直感的なフローで作成できるため、Dynamo ではビジュアル スクリプトを使用しています。テキスト スクリプトの機能がビジュアル スクリプトの機能よりも優れている点について理解しておくと、ノードやワイヤの直感的な機能の代わりにテキスト スクリプトの機能を使用した方が効率的な場合を特定できるようになります。どのような場合にどの言語を使用してスクリプトを作成するかについては、次に示すガイドラインを参照してください。
テキスト スクリプトを使用するケース:
ループ
反復処理を記述する場合
外部ライブラリへのアクセス処理を記述する場合
言語の選択
各 Dynamo ライブラリでアクセスできるコンテンツのリストについては、「スクリプトの参照情報」を参照してください。
Dynamo でスクリプトを作成する場合は必ずパラメトリック環境で作業を行うことになるため、使用するノードとワイヤのフレームワークに関連する形で、構造化されたコードを記述することをお勧めします。例として、テキスト スクリプトが記述されているノードを考えてみます。このノードは、複数の入力、1 つの関数、予想される 1 つの出力が指定されている、プログラム内の他のノードと同じように構成されているとします。この場合、ノード内のコードにいくつかの作業用変数が即時に設定されます。これらの変数が、クリーンなパラメトリック システムの重要な要素になります。コードをビジュアル プログラムに統合するための適切な方法については、次のガイドラインを参照してください。
外部変数を特定する
設計内で使用するパラメータを特定します。これにより、対象のデータから直接作成されるモデルを構築できるようになります。
コードを記述する前に、次の変数を特定します。
入力の最小セット
目的の出力
定数
一部の変数については、コードを記述する前に既に定義されています。
降雨のシミュレーションを実行するサーフェス。
必要な雨粒の数(エージェント)。
雨粒の移動距離。
最も急なパスの下降とサーフェス横断との切り替え。
各入力の番号が指定された Python Script ノード。
返された曲線が青で表示されるコード ブロック。
内部的な関係を設計する
パラメトリシズム機能で特定のパラメータや変数を編集することにより、計算式やシステムの最終結果を操作または変更できます。
スクリプト内のエンティティが論理的に関連付けられている場合は、常にそれらのエンティティを相互の関数として定義します。この場合、一方の関数を変更すると、その変更内容に応じてもう一方の関数が更新されます。
重要なパラメータだけを表示し、入力の数を最小限に抑えます。
追加の親パラーメータから一連のパラメータを継承できる場合は、それらの親パラメータだけをスクリプトの入力として表示してください。こうすることにより、インタフェースの複雑さが軽減されるため、スクリプトが使いやすくなります。
上記のコードは、Python Script ノードの「modules」というサンプル コードです。
入力。
スクリプト内で使用される変数。
上記の入力と変数を使用して関数を実行するループ。
ヒント: スクリプトの結果だけでなく、途中のプロセスも非常に重要です。どちらにも同じように重点を置いてください。
スクリプト内で同じ処理を複数の方法で記述すると、いずれかのタイミングで、重複するコード記述間における整合性が取れなくなることがあります。その結果、保守作業に時間がかかったり、コードの解析効率が落ちたり、システム内部の不整合が発生する可能性があります。
DRY 原則は、「すべての情報は、システム内において、ただ 1 つの明確な信頼できる表現を持っている」ということを表す原則です。
この原則を正しく適用することにより、スクリプト内の関連要素が予期したとおりに統一して変更されます。関連しない要素については、相互に論理的な影響が及ぶことはありません。
ヒント: 上記の「BAD」の例では定数を記述していますが、スクリプト内でエンティティを複製する前に、ソースにリンクさせることができないかどうかを検討することをお勧めします。
コードが長くなってより複雑になるにつれて、スクリプトの目的や全体的なアルゴリズムが分かりにくくなります。また、特定の処理の内容や、特定の処理が記述されている箇所を簡単に追跡できなくなり、エラーが発生した場合も、その原因となるバグを見つけることが難しくなります。さらに、他のコードへの統合や開発作業の割り当てについても、困難になります。こうした困難を避けるため、モジュール単位でコードを記述することをお勧めします。この方法では、コードで実行する処理に基づいて、コードを組織的に分割して記述します。ここでは、モジュール化の手法を使用して、スクリプトを簡単に管理するためのヒントをいくつか紹介します。
モジュール単位でコードを記述する
「モジュール」とは、特定の処理を実行するコードの集まりで、ワークスペース内の Dynamo ノードに似ています。
モジュールは、隣接するコードから視覚的に離れた位置に記述します(関数、クラス、入力のグループ、読み込むライブラリなどがモジュールになります)。
モジュール単位でコードを記述すると、視覚的で直感的なノードの利点を活用できるだけなく、テキスト スクリプトでしか記述できない複雑な関係を使用することもできます。
上記のループ処理では、「agent」というクラスを呼び出しています。このクラスは、次の演習で作成します。
各エージェントの開始点を定義するコード モジュール。
エージェントを更新するコード モジュール。
エージェントのパスの基準線を描画するコード モジュール。
複数の箇所に記述されている同じコードを関数としてまとめる
同じ処理(または非常に類似した処理)を実行するコードが複数の箇所に記述されている場合は、呼び出し可能な関数としてそれらのコードをまとめます。
「Manager」関数は、プログラム フローをコントロールします。この関数には主に、構造間でのデータ移動などの低レベル詳細の動作を処理する「Worker」関数に対する呼び出しが格納されます。
上記の例では、中心点の Z 値に基づき、半径と色を指定して球体を作成しています。
中心線の Z 値に基づき、半径と表示色を指定して球体を作成する 2 つの「Worker」親関数。
2 つの Worker 関数を組み合わせる「Manager」親関数。この関数を呼び出すと、この関数に含まれている 2 つの Worker 関数が呼び出されることになります。
必要な要素だけを表示する
モジュールのインタフェースには、そのモジュールで指定されている必要な要素が表示されます。
ユニット間のインタフェースを定義すると、各ユニットの詳細設計を個別に進めることができるようになります。
モジュールの分離や置き換え
モジュール間には相互の関係はないため、必要に応じて分離や置き換えを行うことができます。
モジュール化の一般的な形式
コードをグループ化する場合は、次のように記述します。
関数は、次のように記述します。
クラスは、次のように記述します。
Dynamo でテキスト スクリプトを開発する場合は、目的とする結果と、実際に作成される結果を頻繁に確認することをお勧めします。こうすることにより、構文エラー、論理的な矛盾点、不正確な値、正しくない出力など、予期しない状況をすばやく検出し、そのたびに修正することができます。最後にまとめて修正するよりも、効率的に作業を進めることができます。テキスト スクリプトは、キャンバス上のノード内でアクティブになっているため、ビジュアル プログラムのデータ フローに既に統合された状態になっています。そのため、出力データを割り当ててプログラムを実行し、Watch ノードを使用してスクリプトからのフローを評価するだけで、スクリプトを継続的にモニタリングすることができます。ここでは、スクリプトを作成しながら、そのスクリプトを継続的に検査する場合のヒントをいくつか紹介します。
スクリプトを開発しながらテストを行う
機能を実行するためのコードの記述が完了するたびに、次の点を確認します。
コードの内容を客観的に確認します。
コードの内容を批判的に確認します。たとえば、共同作業を行っている他のメンバーがこのコードの内容を理解できるかどうか、この処理は本当に必要なのかどうか、この機能をさらに効率的に記述することができないかどうか、不要な重複コードや依存コードが記述されていないかどうか、などを確認します。
正しいデータが返されるかどうかを簡単にテストします。
スクリプト内で使用する最新のデータを出力として割り当てます。これにより、スクリプトを更新するたびに、関連するデータがノードによって常に出力されるようになります。
ソリッドのすべてのエッジが、境界ボックスを作成するための曲線として返されるかどうかを確認します。
Count 入力が正しく Range に変換されるかどうかを確認します。
座標系が適切に変換され、ループ内で回転するかどうかを確認します。
極端な条件を想定してテストを行う
スクリプトの作成中に、割り当てられているドメインの最小値と最大値に入力パラメータを設定すると、極端な条件下でもプログラムが正常に機能するかどうかを確認することができます。
最小値や最大値を指定して正常にプログラムが機能する場合であっても、予期しない Null 値、空の値、ゼロが返されることがないかどうかを確認する必要があります。
こうした極端な条件を設定しないと、スクリプト内に存在する問題を示すバグやエラーが見つからないことがあります。
エラーの原因を特定し、エラーを内部的に修正する必要があるのかどうか、またはパラメータ ドメインを調整してエラーを回避する必要があるのかどうかを判断します。
ヒント: ユーザは、使用可能なすべての入力値のあらゆる組み合わせを使用するということを常に想定しておく必要があります。これにより、予期しない問題が発生するのを防ぐことができます。
デバッグとは、スクリプトからバグをなくすためのプロセスのことです。エラー、非効率な処理、不正確な値、予期しない結果などをまとめて「バグ」と呼びます。バグの修正は、変数名のスペルミスを修正するような単純なものもあれば、スクリプトの構成に関する問題のように、広範囲にわたるものもあります。スクリプトを作成しながら、早い段階で潜在的な問題を検出して修正するのが理想的な方法ですが、この方法でも、バグのまったくないスクリプトを作成できるという保証はありません。ここでは、バグを系統的な方法で修正するためのベスト プラクティスをいくつか紹介します。これらのベスト プラクティスは、優先度の高い順に記載されています。
ウォッチ バルーンを使用する
返されるデータを OUT 変数に割り当てて、コード内の複数の場所でそのデータを確認します。これは、スクリプトを作成しながらバグを修正する方法に似ています。
分かりやすいコメントを書く
コードをモジュール化して、目的とする結果をコメントとして明確に記述すると、デバッグが簡単になります。
通常、コメント行と空白行は余分な情報ですが、デバッグを行う場合は、コードを細分化して内容を追跡できるため、便利です。
モジュール化されたコードの利点を活用する
分離された特定のモジュール内に問題の原因が存在している場合があります。
問題のあるモジュールを特定できれば、問題の修正が非常に簡単になります。
プログラムを修正する必要がある場合、コードがモジュール化されていれば、非常に簡単に修正を行うことができます。
プログラムの他の部分を変更することなく、新しいモジュールやデバッグ済みのモジュールを既存のプログラムに挿入することができます。
Python Script ノードのサンプル ファイルをデバックすると、次のようになります。
自分よりも大きな境界ボックスを返す入力ジオメトリ(これを確認するには、xDist と yDist の値を OUT 変数に割り当てます)。
xDist と yDist の正しい距離が設定された適切な境界ボックスを返す入力ジオメトリのエッジ曲線。
xDist と yDist の値に関する問題に対応するための「module」コード(これは、これまでの説明で挿入したコードです)。
下のリンクをクリックして、サンプル ファイルをダウンロードします。
すべてのサンプル ファイルの一覧については、付録を参照してください。
上で説明したテキスト スクリプトのベスト プラクティスを意識しながら、降雨シミュレーション スクリプトを作成してみましょう。「見やすいプログラムを作成するためのガイドライン」の演習では、ベスト プラクティスに従い、構造化されていないビジュアル プログラムを見やすく整理することができましたが、テキスト スクリプトの場合、それは非常に難しくなります。テキスト スクリプトで記述された論理的な関係は、視覚的に把握するのが難しいため、複雑なコードになると、関係を解読するのがほとんど不可能になる場合もあります。そのため、テキスト スクリプトの高度な機能を使用する場合は、組織的に記述する必要性が高くなります。この演習では、ステップごとに操作を確認しながら、ベスト プラクティスについて説明していきます。
アトラクタが変形しているサーフェスに適用されるスクリプト
最初に、必要な Dynamo ライブラリを読み込みます。これにより、Python 内で Dynamo の機能にグローバルにアクセスできるようになります。
この段階で、必要なライブラリをすべて読み込む必要があります。
次に、スクリプトの入力と出力を定義する必要があります。定義した入力は、ノード上で入力ポートとして表示されます。これらの外部入力が、このスクリプトの基礎となり、パラメトリック環境を構築するための重要なデータになります。
Python スクリプト内の変数に対応する入力を定義する必要があります。これらの入力により、目的とする出力が設定されます。
ベースとなるサーフェス。
使用するエージェントの数。
エージェントが進むことができるステップの最大数。
サーフェスからの最短距離のパスを取得するためのオプション(または、サーフェスを横断するためのオプション)。
スクリプト IN[0] とスクリプト IN[1] の入力に対応する入力 ID が設定された Python ノード。
異なる色で表示可能な出力曲線。
では、モジュール化の手法を使用して、スクリプトの本文を作成してみましょう。複数の始点に対して、サーフェスからの最短パスのシミュレーションを実行するのは、複数の関数が必要になる複雑な作業です。そのため、スクリプト内の異なる場所で異なる関数を呼び出すのではなく、それらの関数をエージェントの 1 つのクラスとしてまとめることにより、コードをモジュール化します。このクラス(モジュール)の各関数は、それぞれ異なる変数を使用して呼び出すことができます。また、別のスクリプト内で再利用することもできます。
サーフェス上を下降するエージェントに対して、その動作を指示するクラスを定義する必要があります。このクラスを使用して、エージェントがステップを進むたびに、最も急な方向へ移動することを選択します。
名前。
すべてのエージェントが共有するグローバル属性。
各エージェント固有のインスタンス属性。
ステップを進むための関数。
各ステップの位置を基準線リストにカタログ化するための関数。
ここで、エージェントの開始位置を指定して、エージェントを初期化しましょう。それに合わせて、スクリプトの調整を行い、エージェント クラスが正しく機能するかどうかを確認します。
サーフェスを下降するすべてのエージェントをインスタンス化し、それらのエージェントの初期属性を定義する必要があります。
新しい空の基準線リスト。
サーフェス上での下降の開始を指定するためのコード。
エージェント リストを出力として割り当て、スクリプトから返される情報を確認するための Watch ノード。エージェントの正確な数が返されていますが、後でスクリプトをもう一度編集して、スクリプトから返されるジオメトリを確認します。
ステップごとにそれぞれのエージェントを更新します。次に、エージェントとステップごとに、ネストされたループ処理を記述し、エージェントとステップの位置を更新してそれぞれの基準線リストに記録します。また、各ステップで、エージェントがサーフェス上の最終的な位置(それ以上は下降できない位置)にまだ到達していないことを確認します。エージェントがサーフェス上の最終的な位置に到達したら、エージェントの移動を停止します。
これで、各エージェントが完全に更新されました。次に、これらのエージェントを表すジオメトリを返してみましょう。すべてのエージェントが、それ以上は下降できない位置にまで達したことを確認した後で(または、ステップの最大数に達したことを確認した後で)、各エージェントの基準線リスト内の点を通過するポリカーブを作成し、そのポリカーブの基準線を出力します。
最も急なパスを探すためのスクリプト。
ベースとなるサーフェス上の降雨をシミュレーションするためのプリセット。
最も急なパスを探す代わりに、エージェントを切り替えて、ベースとなるサーフェスを横断することもできます。
最終的な Python のテキスト スクリプトはこのようになります。
ループ
反復
ノードの集約
外部ライブラリへのアクセス
省略表記
DesignScript
可
可
可
不可
可
Python
可
可
一部可
可
不可
ZeroTouch (C#)
不可
不可
不可
可
不可