リストを使用して、データを整理することができます。コンピュータのオペレーティング システム上にはファイルとフォルダがありますが、Dynamo では、項目とリストが、それぞれファイルとフォルダに対応します。オペレーティング システムのように、さまざまな方法でデータの作成、変更、クエリーを実行することができます。この章では、Dynamo でリストを管理する方法を詳しく説明します。
ここでは、階層にもう 1 つの層を追加してみましょう。「リストの操作」の章で例として取り上げたトランプを、ここでも例として使用します。たとえば、複数のデッキ(デッキとは 1 組のトランプのこと)が含まれたボックスを作成したとすると、そのボックスはデッキを格納するリストで、各デッキはカードのリストということになります。これが、「リストのリスト」という考え方です。たとえば次の図では、硬貨の山のリストが入っていて、それぞれの山には硬貨のリストが含まれています。
写真: Dori
リストのリストに関する質問(クエリー)を作成する場合、次のような質問が考えられます。これにより、リストの特性(プロパティ)がわかります。
Q: 硬貨は何種類?A: 2.
Q: 硬貨のタイプ値は? A: $0.01 と $0.25 です。
Q: 25 セント硬貨の材質は?A: 銅 75%、ニッケル 25%
Q: 1 セント硬貨の材質は?A: 亜鉛 97.5%、銅 2.5%
リストのリストに対して実行できる操作(アクション)としては、次のような操作が考えられます。この場合、実行する操作に応じてリストのリストが変化します。
25 セント硬貨または 1 セント硬貨の特定の山を選ぶ。
特定の 25 セント硬貨または 1 セント硬貨を選ぶ。
25 セント硬貨の山と 1 セント硬貨の山の配置を変える。
25 セント硬貨の山と 1 セント硬貨の山をすべて入れ替える。
前の章でも説明したように、Dynamo の各ノードを使用して、上記の操作に似た操作を実行することができます。ここでは、物理的な物体ではなく抽象的なデータを操作するため、データ階層を上下に移動する方法をコントロールするための一連のルールが必要になります。
リストのリストを操作する場合、データは複雑な階層構造になっていますが、この複雑な構造により、非常に高度なパラメータ操作を実行することができます。これ以降の各演習では、基礎的な概念といくつかの操作方法を確認していきます。
下のリンクをクリックして、サンプル ファイルをダウンロードします。
すべてのサンプル ファイルの一覧については、付録を参照してください。
このセクションで説明する基本的な概念は、「Dynamo は、リストをオブジェクトとして処理する」ということです。トップダウン階層は、オブジェクト指向プログラミングをベースとして開発されています。Dynamo は、List.GetItemAtIndex などのコマンドでサブ要素を選択するのではなく、データ構造内でメイン リストのインデックスを選択します。リスト中で選択したその項目が、別のリストである場合もあります。ここからは、サンプルの図を使用して詳しく説明していきます。
Code Block ノードを使用して、
0..2; 0..3;
という 2 つの範囲が定義されています。これらの範囲は、レーシングが「外積」に設定された Point.ByCoordinates ノードに接続されています。これにより、点のグリッドが作成され、リストのリストが出力として返されます。
Watch ノードの各リストで、4 つの項目を持つ 3 つのリストが指定されていることに注意してください。
インデックス値 0 を指定して List.GetItemAtIndex ノードを使用した場合、Dynamo は、最初のリストとそのリスト内のすべてのコンテンツを選択します。他のプログラムでは、データ構造内のすべてのリストの最初の項目だけが選択される場合がありますが、Dynamo は、トップダウン階層を使用してデータの処理を行います。
下のリンクをクリックして、サンプル ファイルをダウンロードします。
すべてのサンプル ファイルの一覧については、付録を参照してください。
フラット化を行うと、データ構造からすべてのデータ層が削除されます。この機能は、操作にデータ階層が必要ない場合に便利ですが、情報が削除される可能性があります。次の図は、データのリストをフラット化した結果を示しています。
Code Block ノードで
-250..-150..#4;
というコード行を挿入して範囲を定義します。Code Block ノードを Point.ByCoordinates ノードの x 入力と y 入力に接続します。これにより、点のグリッドを取得するための「外積」に対するレーシングが設定されます。
Watch ノードに、リストのリストが表示されます。
PolyCurve.ByPoints ノードは、各リストを参照して個別のポリカーブを作成します。Dynamo のプレビューに 4 つのポリカーブが表示されます。それぞれのポリカーブが、グリッド内の各行を表しています。
PolyCurve.ByPoints ノードの前に Flatten ノードを挿入して、すべての点を含む単一のリストを作成します。PolyCurve.ByPoints ノードは、リストを参照して 1 つのカーブを作成しますが、すべての点が 1 つのリスト上に存在しているため、点のリスト全体を通過するジグザクのポリカーブが 1 つだけ作成されます。
独立したデータ層をフラット化する方法も用意されています。List.Flatten ノードを使用すると、データ層の数を定義して、最上位の階層からデータ層をフラット化することができます。このノードは、現在のワークフローに必ずしも関係しない複雑なデータ構造を操作する場合に特に便利です。別の方法として、Flatten ノードを関数として List.Map ノードで使用することもできます。List.Map ノードの詳細については、以下で説明します。
下のリンクをクリックして、サンプル ファイルをダウンロードします。
すべてのサンプル ファイルの一覧については、付録を参照してください。
パラメトリック モデリングを行う際に、既存のリストのデータ構造を修正したい場合があります。その場合、さまざまなノードを使用できますが、List.Chop ノードが最も基本的なノードです。List.Chop ノードで設定された数の項目を使用すると、1 つのリストを複数のサブリストに分割することができます。
Chop コマンドを実行すると、指定されたリストの長さに従ってリストが分割されます。List.Chop ノードは、データ構造を削除するのではなく新しいデータ層をデータ構造に追加するなど、いくつかの点で List.Flatten ノードとは逆の動作を行います。List.Chop ノードは、次の例のようなジオメトリに関する操作を実行する場合に便利です。
下のリンクをクリックして、サンプル ファイルをダウンロードします。
すべてのサンプル ファイルの一覧については、付録を参照してください。
List.Map ノードと List.Combine ノードは、階層内の 1 段階下の層で、設定された関数を入力リストに適用します。リストの組み合わせとリストのマップはほとんど同じ操作ですが、組み合わせの場合は、特定の関数の入力に対応する複数の入力を使用できる点が、マップとは異なっています。
注: この演習は前バージョンの Dynamo を使用して作成されました。 List.Map の機能に関する問題の大半は、 List@Level _機能の追加によって解決されました。詳細については、後述の _ List@Level を参照してください。
簡単な例として、前のセクションで説明した List.Count ノードをもう一度確認してみましょう。
List.Count ノードは、リスト内のすべての項目をカウントします。ここでは、List.Count ノードを使用して、List.Map ノードの仕組みについて説明します。
Code Block ノードで、次の 2 行を挿入します。
-50..50..#Nx; -50..50..#Ny;
このコードを入力すると、Code Block ノードに Nx と Ny という 2 つの入力が作成されます。
2 つの Integer Slider ノードを使用して Nx の値と Ny の値を Code Block ノードに接続すると、これらの値が定義されます。
次に、Code Block ノードの各行を Point.ByCoordinates ノードの x 入力と y 入力に接続します。このノードを右クリックして「レーシング」と「外積」を続けて選択します。この操作により、点のグリッドが作成されます。-50 から 50 までの範囲が定義されているため、ここでは既定の Dynamo グリッド全体を使用しています。
Watch ノードに、作成された点が表示されます。データ構造を確認すると、リストのリストが作成されていることがわかります。それぞれのリストが、グリッドの点の 1 行を表しています。
前の手順の Watch ノードの出力に List.Count ノードを接続します。
Watch ノードを List.Count ノードの出力に接続します。
List.Count ノードによって 5 という値が生成されていることに注意してください。これは、Code Block ノードで定義されている「Nx」変数と同じ値です。こうなる理由は次のとおりです。
まず、Point.ByCoordinates ノードは、リストを作成するための主要な入力として「x」入力を使用します。Nx の値が 5 で Ny の値が 3 の場合、3 つの項目を持つ 5 つのリストが含まれた 1 つのリストが作成されます。
Dynamo は、リストをオブジェクトとして処理するため、List.Count ノードは、階層内のメインのリストに適用されます。その結果、メインのリストに含まれているリストの数である 5 という値が生成されることになります。
List.Map ノードを使用して、階層内の 1 段階下の層で「関数」を実行します。
List.Count ノードには入力がないことに注意してください。List.Count ノードは関数として使用されるため、このノードは階層内の 1 段階下の層にあるすべてのリストに適用されます。List.Count ノードの空の入力は、List.Map ノードの list 入力に対応しています。
List.Count ノードにより、5 つの項目を持つリストが 1 つ作成されます。それぞれの項目の値は 3 になります。この値は、各サブリストの長さを表しています。
注: この演習は前バージョンの Dynamo を使用して作成されました。List.Combine の機能に関する問題の大半は、 List@Level 機能の追加によって解決されました。詳細については、後述の List@Level を参照してください。
この演習では、List.Combine ノードを使用して、個別のオブジェクト リストに関数を適用する方法を説明します。
最初に、2 つの点のリストを設定します。
Sequence ノードを使用して 10 の値を生成し、各値に 10 のステップ増分を指定します。
結果を Point.ByCoordinates ノードの x 入力に接続します。これにより、Dynamo で点のリストが作成されます。
2 番目の Point.ByCoordinates ノードをワークスペースに追加し、x 入力として同じ Sequence 出力を使用し、y 入力として Integer Slider を使用し、その値を 31 (1 番目の点のセットと重ならない限り任意の値)に設定して、2 つの点のセットがお互いに重ならないようにします。
次に、List.Combine ノードを使用して、2 つの異なるリスト内のオブジェクトに関数を適用します。この場合、単純な線描画関数になります。
ワークスペースに List.Combine ノードを追加し、2 つの点のセットを list0 と list1 入力として接続します。
List.Combine ノードの入力関数として Line.ByStartPointEndPoint ノードを使用します。
完了すると、2 つの点のセットが Line.ByStartPointEndPoint 関数を介して一緒に圧縮またはペアリングされ、Dynamo で 10 行が返されます。
List.Combine の別の使用例については、N 次元のリストの演習を参照してください。
下のリンクをクリックして、サンプル ファイルをダウンロードします。
すべてのサンプル ファイルの一覧については、付録を参照してください。
List.Map ではなく List@Level 機能を使用すると、ノードの入力ポートに使用するリストのレベルを直接選択することができます。この機能は、入力ポートに指定されたあらゆる入力値に使用できます。使用すると、もっともすばやく簡単にリストのレベルにアクセスすることができます。ノードの入力として使用するリストのレベルを指定するだけで、後はすべてをノードに任せることができます。
この演習では、List@Level 機能を使用して特定のデータ レベルを分離してみましょう。
点によって構成される単純な 3D グリッドから始めることにします。
X、Y、Z に Range ノードを接続することでグリッドが構成されています。したがって、データの構造は X リスト、Y リスト、Z リストの 3 層から成ることがわかります。
これらの層は、異なるレベルに存在します。レベルは、プレビュー バルーンの下に表示されます。リスト レベルの列はリスト データに対応しています。ここで、作業中のレベルを確認することができます。
リスト レベルは逆順で階層化されているので、最低レベルのデータは常に「L1」にあります。これにより、上流で何かが変更されたとしても、グラフを意図したとおりに動作させることができます。
List@Level 機能を使用するには、[>]をクリックします。このメニュー内部では、2 つのチェックボックスが表示されます。
レベルを使用 - このオプションをオンにすると、List@Level の機能が有効になります。このオプションをクリックした後で、ノードで使用する入力リスト レベルをすべてクリックして選択することができます。このメニューで上矢印か下矢印をクリックすることにより、さまざまなレベル オプションを試すことができます。
リスト構造を保持 - オンにしていると、その入力のレベル構造を保持することができます。意図的にデータを複数のサブリストに整理している場合は、このオプションをオンにしておくと、いかなる情報も失わずにリスト構造をそのまま保持しておくことができます。
リスト レベル全体を切り替えることにより、単純な 3D グリッド上でリスト構造を視覚的に確認することができます。リスト レベルとインデックスの組み合わせを変更すると、元の 3D セットとは異なる点のセットが返されます。
DesignScript で「@L2」を選択すると、レベル 2 のリストのみを選択することができます。index に 0 が入力されているとき、レベル 2 のリストには Y を 0 とする点のセットのみが含まれているので、XZ のグリッド面のみが返されます。
レベル フィルタを「@L1」に変更すると、リスト レベル 1 に含まれるすべての点を確認することができます。index に 0 が入力されているとき、レベル 1 のリストにはフラット リストの 3D ポイントがすべて含まれています。
同様に「@L3」に変更すると、リスト レベル 3 の点のみが表示されます。index に 0 が入力されているとき、レベル 3 のリストには Z を 0 とする点のセットのみが含まれているので、XY のグリッド面のみが返されます。
同様に「@L4」に変更すると、リスト レベル 4 の点のみが表示されます。index に 0 が入力されているとき、レベル 4 のリストには X を 0 とする点のセットのみが含まれているので、YZ のグリッド面のみが返されます。
今回の例は List.Map でも作成できますが、List@Level を使用すると、動作を単純化して簡単にノード データにアクセスできるようになります。次に List.Map と List@Level の比較をご覧ください。
どちらの方法でも同じ点にアクセスすることができますが、List@Level を使用するとたった 1 個のノードだけでデータのレイヤを簡単に切り替えることができます。
List.Map を使用して点構成のグリッドにアクセスするには、List.Map の隣に List.GetItemAtIndex ノードを配置する必要があります。レベルの階層を下りていくたびに、List.Map ノードを追加していく必要があります。リストが複雑になればなるほど、目的の情報レベルにアクセスするには、多数の List.Map ノードをグラフに追加しなければなりません。
この例では、List.GetItemAtIndex ノードを List.Map ノードに接続することにより、List.GetItemAtIndex で「@L3」を選択したときと同じリスト構造を持つ同じ点のセットを取得しています。
下のリンクをクリックして、サンプル ファイルをダウンロードします。
すべてのサンプル ファイルの一覧については、付録を参照してください。
転置は、リストのリストを操作する場合の基本的な機能です。転置を実行すると、スプレッドシート プログラムの場合と同様に、データ構造内の列と行の位置が反転します。次の基本的な行列を使用して、転置の仕組みを説明します。また、次のセクションでは、転置機能を使用して幾何学的な関係を作成する方法について説明します。
最初に、前の演習で使用した List.Count ノードを削除して別のジオメトリに移動し、データ構造がどのようになっているかを確認します。
Point.ByCoordinates ノードから続く Watch ノードの出力に、PolyCurve.ByPoints ノードを接続します。
出力として 5 つのポリカーブが作成され、Dynamo のプレビューにそれらのポリカーブが表示されます。Dynamo ノードは点のリスト(この場合は、点のリストのリスト)を検索し、そのリストから 1 つのポリカーブを作成します。原則として、各リストはデータ構造内で曲線に変換されます。
List.Transpose ノードは、すべての項目をメイン リスト内のすべてのリストと切り替えます。この動作は少し複雑に感じるかもしれませんが、データ構造内の列と行を入れ替える Microsoft Excel と同じ仕組みです。
転置により、リストの構造が変更されていることを確認します。転置前は 3 つの項目を持つ 5 つのリストだったのに対して、転置後は 5 つの項目を持つ 3 つのリストに変わっています。
PolyCurve.ByPoints ノードにより、元の曲線に対して垂直方向に 3 つのポリカーブが作成されます。
Code Block では、「[]」という省略表記を使用してリストを定義します。この方法を使用すると、List.Create ノードを使用するよりも素早く柔軟にリストを作成することができます。Code Block の詳細は、「Code Block と DesignScript」を参照してください。次の図は、Code Block を使用して、複数の式を持つリストを作成する方法を示しています。
Code Block で「[]」という省略表記を使用すると、複雑なデータ構造で特定の項目をすばやく簡単に選択することができます。Code Block の詳細は、「Code Block と DesignScript」の章で説明しています。次の図は、Code Block を使用して、複数のデータ タイプが存在するリストのクエリーを実行する方法を示しています。
下のリンクをクリックして、サンプル ファイルをダウンロードします。
すべてのサンプル ファイルの一覧については、付録を参照してください。
この演習では、前の演習で作成したロジックを使用してサーフェスを編集します。この演習の目的は直感的な操作を行うことですが、データ構造のナビゲーションは少し複雑な操作です。ここでは、制御点を移動することにより、サーフェスの編集を行います。
最初に、上図の各ノードの文字列を操作します。既定の Dynamo グリッド全体にわたる基本的なサーフェスを作成します。
Code Block ノードを使用して次の 2 つのコード行を入力し、Surface.PointAtParameter ノードの u 入力と v 入力にそれぞれのコード行を接続します(
-50..50..#3;
と-50..50..#5;
)。Surface.PointAtParameter ノードのレーシングを「外積」に設定します。
Watch ノードに、5 つの項目を持つ 3 つのリストが含まれた 1 つのリストが表示されます。
この演習では、作成したグリッドの中心点のクエリーを実行します。これを行うには、中央のリストの中心点を選択します。
正しい点を選択するには、Watch ノードの各項目をクリックして、正しい点が選択されているかどうかを確認します。
Code Block ノードを使用して、リストのリストをクエリーするための基礎となるコード行を次の形式で指定します。
points[1][2];
Geometry.Translate ノードを使用して、選択した点を Z の正の向きに 20 単位移動します。
List.GetItemAtIndex ノードを使用して、点の中央の行を選択します。前の手順と同様に、Code Block ノードで
points[1];
というコード行を指定してクエリーを実行することもできます。
ここまでの手順で、中心点のクエリーを実行し、中心点を上方向に移動しました。ここでは、この中心点を元のデータ構造に戻します。
最初に、前の手順で分離したリストの項目を置き換えます。
List.ReplaceItemAtIndex ノードで「2」というインデックス値を使用し、置き換える項目を対象となる点(Geometry.Translate ノードの Geometry 出力)に接続して、中心点を置き換えます。
対象の点がリストの中央の項目に入力されたことが出力として表示されます。
ここでは、前の演習で変更したリストを、元のデータ構造であるリストのリストに戻します。
前の演習と同様に、List.ReplaceItemAtIndex ノードを使用して、中央のリストを変更したリストで置き換えます。
これら 2 つのノードのインデックスを定義する Code Block ノードの値は、それぞれ 1 と 2 であることに注意してください。これらの値は、Code Block ノードで指定した元のクエリー(points[1][2])に対応しています。
インデックス 1 の位置でリストを選択すると、Dynamo のプレビューでデータ構造がハイライト表示されます。これで、対象の点が元のデータ構造に正しく移動されたことになります。
上図の点のセットからサーフェスを作成する方法はいくつかあります。ここでは、複数の曲線をまとめてロフトしてサーフェスを作成してみましょう。
NurbsCurve.ByPoints ノードを作成し、新しいデータ構造を接続して、3 つの NURBS 曲線を作成します。
Surface.ByLoft ノードを NurbsCurve.ByPoints ノードの出力に接続します。これで、サーフェスが変更されました。ジオメトリの元の Z 値を変更することができます。この値を変更して、ジオメトリがどのように変化するかを確認してください。
リストとは、要素(項目)の集合です。例として、1 房のバナナを考えてみましょう。1 本のバナナが、リスト(房)内の 1 つの項目になります。それぞれのバナナをばらばらに取り上げるより、房をまとめて持ち上げる方が簡単です。同じことが、データ構造内のパラメータに基づく関係によって各要素をグループ化する場合についても当てはまります。
写真: Augustus Binu
日用品を購入する場合、購入した商品をすべて買い物カゴに入れます。このカゴも、リストと考えることができます。たとえば、3 房のバナナを使用して 多くの バナナ ブレッドを作るとします。この場合、すべてのバナナが入っている袋がバナナの房のリストで、それぞれの房がバナナのリストになります。この袋は 2 次元の「リストのリスト」で、バナナの房は 1 次元の「リスト」です。
Dynamo では、リスト データには順序が付けられ、各リストの最初の項目にはインデックス「0」が割り当てられます。次のセクションでは、Dynamo におけるリストの定義の仕組みと、複数のリストの相互関係について説明します。
リストのインデックスは、1 ではなく必ず 0 から始まります。これは、最初は不思議に感じるかもしれません。今後、リストの最初の項目と言う場合は、インデックス 0 の付いた項目のことを意味します。
たとえば、右手の指を使って数を数える場合、1 から 5 の順序で数えます。0 から数え始めることはほとんどないはずです。しかし、右手の指を Dynamo のリストだと仮定すると、それぞれの指に 0 から 4 のインデックスが割り当てられることになります。プログラミングの初心者にとっては少し不思議に感じられるかもしれませんが、ほとんどのコンピュータ システムでは、インデックスの値はゼロで始まるのが普通です。
ここでも、引き続きリスト内に 5 つの項目が含まれています。ただし、最初の項目に 0 のインデックス値が割り当てられているものと仮定して説明を続けます。リストに格納できる項目は、数値だけではありません。Dynamo でサポートされているデータ タイプであれば、点、曲線、サーフェス、ファミリなど、任意のデータ タイプをリスト内に格納することができます。
a.インデックス
b.点
c.項目
多くの場合、リストに格納されているデータのタイプを確認する最も簡単な方法は、ノードの出力を Watch ノードに接続する方法です。既定では、Watch ノードにはリストの左側のすべてのインデックスと、右側のすべてのデータ項目が自動的に表示されます。
これらのインデックスは、リストを操作する場合の重要な要素です。
リストの入力と出力は、使用する Dynamo ノードによって異なります。例として、5 つの点を持つリストのノードの出力を PolyCurve.ByPoints ノードと Circle.ByCenterPointRadius ノードに接続してみましょう。
PolyCurve.ByPoints ノードの points 入力には、Point[] が必要です。これは、点のリストを表しています。
PolyCurve.ByPoints ノードの出力は、5 つの点を持つリストから作成された単一のポリカーブです。
Circle.ByCenterPointRadius ノードの centerPoint 入力には、Point が必要です。
Circle.ByCenterPointRadius ノードの出力は、5 つの円を持つリストです。それぞれの円の中心が、元のリスト内の点に対応しています。
PolyCurve.ByPoints と Circle.ByCenterPointRadius の入力データは同じですが、Polycurve.ByPoints ノードは 1 つのポリカーブを返し、Circle.ByCenterPointRadius ノードは各点を中心とする 5 つの円を返します。この場合、5 つの点をつなぐ曲線としてポリカーブが描画され、Circle.ByCenterPointRadius ノードは各点を中心とする個別の円を描画します。これは、直感的に理解することができます。では、データには何が起きているのでしょうか。
Polycurve.ByPoints の points 入力の上にカーソルを置くと、この入力に Point[] が必要であることがわかります。最後の角括弧に注意してください。これは、点のリストであることを表しています。ポリカーブを作成するには、ポリカーブごとにリストを入力する必要があります。入力された各リストは、Polycurve.ByPoints ノードによって 1 つのポリカーブに集約されます。
一方、Circle.ByCenterPointRadius ノードの centerPoint 入力には、Point が必要です。このノードはリストの項目である 1 つの点を取得し、それを円の中心として定義します。入力されたデータから 5 つの円が生成されるのは、このためです。Dynamo の入力に関するこれらの違いを認識しておくと、ノードによるデータ処理の仕組みを正しく理解することができます。
データの一致は、明確に解決することができない問題です。このような問題は、異なるサイズの入力をノードに渡すときに発生します。データ一致アルゴリズムを変更すると、結果が大きく変わってしまうことがあります。
例として、2 点の間に直線セグメントを作成するノード(Line.ByStartPointEndPoint)を考えてみます。このノードは、点の座標を指定する 2 つの入力パラメータを使用します。
最も単純な方法は、一方のリストが終了するまで、入力された点を 1 対 1 で接続していく方法です。これは、「最短リスト」アルゴリズムと呼ばれます。Dynamo ノードの既定の動作です。
「最長リスト」アルゴリズムの場合、すべてのリストの最後の項目に達するまで、同じ要素を繰り返し使用して入力が接続されたままの状態になります。
最後に、「直積」方式について説明します。この方式では、考えられる接続がすべて生成されます。
これらの点の集まりの間に直線を描画する場合、いくつかの方法があります。レーシング オプションを使用するには、ノードの中心を右クリックして[レーシング]メニューを選択します。
下のリンクをクリックして、サンプル ファイルをダウンロードします。
すべてのサンプルファイルの一覧については、付録を参照してください。
次の図を使用して、レーシング操作について説明します。ここでは、上記の基準ファイルを使用して、最短リスト、最長リスト、直積を定義します。
Point.ByCoordinates ノードでレーシングを変更しますが、上図のグラフについては何も変更しません。
レーシング オプション(既定のオプションも同様)として_最短リスト_を選択すると、5 つのポイントで構成される基本的な対角線が得られます。最短リストのレーシングは、2 つのリストのうち短い方のリストの最後の項目に達した場合に動作が終了します。そのためこの例では、5 つの点が含まれているリストの最後に達すると、レーシング動作が停止します。
レーシングを[最長リスト]に変更すると、垂直方向に伸びる対角線が生成されます。上の概念図のように、長い方のリストの最後の項目に達するまで、短い方のリスト(項目数が 5 のリスト)の最後の項目が繰り返し使用されます。
レーシングを[直積]に変更すると、各リスト間で考えられるすべての組み合わせの 5x10 の点のグリッドが生成されます。これは、上の概念図に示す直積に該当するデータ構造です。ただし、ここで使用しているデータは、「リストのリスト」です。ポリカーブを接続すると、各リストは X 値によって定義され、垂直な直線の列が生成されていることがわかります。
ここでは、データ階層にさらに層を追加して、より高度なリストの操作方法について見ていきます。データ構造を拡張して、2 次元を超える多次元のリストのリストを作成することができます。Dynamo のリストは項目として処理されるため、必要な数の次元を持つデータを作成することができます。
多次元のリストの構造は、ロシアのマトリョーシカ人形に似ています。各リストは、複数の項目を格納するコンテナとして考えることができます。各リストには独自のプロパティが存在し、それぞれのリストは独自のオブジェクトとして見なされます。
ロシアのマトリョーシカ人形(写真: Zeta)は、N 次元のリストの構造に似ています。それぞれの層が 1 つのリストを表し、各リスト内に項目が格納されています。Dynamo では、1 つのリストに複数のリストを格納することができます。この場合、格納されているそれぞれのリストが、格納元のリストの項目になります。
N 次元のリストを視覚的に説明するのは難しいため、この章ではいくつかの演習を使用して、2 次元を超える多次元のリストを操作する方法について見ていきます。
Dynamo のデータ管理において最も複雑な概念はマッピングですが、複雑なリスト階層を操作する場合は特に、マッピングが重要になります。この章の演習では、多次元のデータを操作する際に、どのようなケースでマッピングと組み合わせ機能を使用するかについて説明します。
List.Map ノードと List.Combine ノードの概要については、前の章で説明しました。この章の最後の演習でこれらのノードを使用して、複雑なデータ構造の操作を行います。
下のリンクをクリックして、サンプル ファイルをダウンロードします。
すべてのサンプル ファイルの一覧については、付録を参照してください。
この章では、読み込んだジオメトリを操作するための演習を 3 つ見ていきます。この演習はその最初の演習です。演習を進めていくにつれて、より複雑なデータ構造を扱います。
最初に、演習ファイル フォルダ内の .sat ファイルを使用します。このファイルを取得するには、File Path ノードを使用します。
Geometry.ImportFromSAT ノードを使用すると、ジオメトリが 2 つのサーフェスとして Dynamo のプレビューに読み込まれます。
説明を簡単にするため、この演習では 1 つのサーフェスだけを使用します。
インデックス値として 1 を選択して、上部のサーフェスをグラブします。これを行うには、List.GetItemAtIndex ノードを使用します。
Geometry.ImportFromSAT プレビューのジオメトリ プレビューをオフにします。
次に、グラブしたサーフェスを点のグリッドに分割します。
1.Code Block ノードを使用して、次の 2 つのコード行を入力します。
0..1..#10;
0..1..#5;
2.2 つの Code Block 値を、Surface.PointAtParameter ノードの u 入力と v 入力に接続します。次に、このノードの_レーシング_を「外積」に変更します。
3.出力としてデータ構造が表示されます。このデータ構造は、Dynamo のプレビューで表示することもできます。
次に、最後のステップの点を使用して、サーフェスに沿って 10 個のカーブを生成します。
NurbsCurve.ByPoints ノードを Surface.PointAtParameter ノードの出力に接続して、データ構造の内容を確認します。
List.GetItemAtIndex ノードのプレビューをオフにすると、結果が明確になります。
基本的な List.Transpose ノードにより、リストのリストの列と行が反転します。
List.Transpose ノードの出力を NurbsCurve.ByPoints ノードに接続すると、サーフェスに沿って水平方向に 5 本の曲線が作成されます。
前のステップで NurbsCurve.ByPoints ノードのプレビューをオフにしていると、イメージで同じ結果が得られます。
この演習では、少し複雑な操作を実行してみましょう。ここでは、前の演習で作成した曲線に対して操作を実行します。具体的には、これらの曲線を別のサーフェスに関連付けて、2 つのサーフェス間で曲線をロフトします。この操作を実行する場合、データ構造の処理が少し複雑になりますが、基本的な考え方はこれまでと同じです。
最初に、List.GetItemAtIndex ノードを使用して、前の演習で読み込んだジオメトリの上部サーフェスを分離します。
Surface.Offset ノードで 10 という値を指定して、サーフェスをオフセットします。
前の演習と同様に、Code Block ノードで次の 2 つのコード行を入力します。
0..1..#10;
0..1..#5;
上記のコード行を 2 つの Surface.PointAtParameter ノードに接続し、各ノードの レーシング を「外積」に設定します。いずれか一方のノードが元のサーフェスに接続され、もう一方のノードがオフセットされたサーフェスに接続されます。
これらのサーフェスのプレビューをオフにします。
前の演習と同様に、Surface.PointAtParameter ノードの出力を 2 つの NurbsCurve.ByPoints ノードに接続します。結果は、2 つのサーフェスに対応するカーブを示します。
List.Create ノードを使用して、2 組の曲線を 1 つのリストのリストに結合します。
10 個の項目を持つ 2 つのリストが出力として表示されます。各リストが、NURBS 曲線の各接続セットを表しています。
Surface.ByLoft ノードを実行すると、このデータ構造を視覚的に理解することができます。このノードは、各サブリスト内のすべての曲線をロフトします。
前のステップで Surface.ByLoft ノードのプレビューをオフにします。
List.Transpose ノードを使用すると、リスト内のすべての列と行が反転します。このノードにより、10 本の曲線を持つ 2 つのリストが、2 本の曲線を持つ 10 個のリストに変換されます。また、各 NURBS 曲線が、もう一方のサーフェスの隣接する曲線に関連付けられます。
Surface.ByLoft ノードを使用して、リブ形状の構造物を作成します。
次に、この結果を得るための別のプロセスを説明します。
開始する前に、前のステップで Surface.ByLoft プレビューをオフにして、混乱を避けます。
ここでは、List.Transpose ノードの代わりに List.Combine ノードを使用します。このノードは、各サブリスト上で「コンビネータ」を実行します。
この演習では、List.Create ノードを「コンビネータ」として使用します。これにより、サブリスト内の各項目のリストが作成されます。
Surface.ByLoft ノードを使用して、前の手順と同じサーフェスを取得します。この場合は List.Transpose ノードを使用した方が簡単ですが、さらに複雑なデータ構造を操作する場合は、List.Combine ノードを使用することをお勧めします。
リブ形状の構造物内の曲線の方向を切り替える場合は、手順をいくつか戻り、NurbsCurve.ByPoints ノードに接続する前に List.Transpose ノードを使用します。これにより、リスト内の列と行が反転し、水平方向のリブ形状が 5 つ作成されます。
ここからは、さらに高度な操作を実行してみましょう。この演習では、読み込んだ 2 つのサーフェスを両方とも使用して、複雑なデータ階層を作成します。ただし、基本的な考え方はこれまでと同じで、同じ操作を実行することになります。
最初に、前の演習で読み込んだファイルを使用します。
前の演習と同様に Surface.Offset ノードを使用し、サーフェスをオフセットする値として 10 を指定します。
オフセットされたノードによって 2 つのサーフェスが作成されたことが出力として表示されます。
前の演習と同様に、Code Block ノードで次の 2 つのコード行を入力します。
0..1..#20;
0..1..#20;
上記のコード行を 2 つの Surface.PointAtParameter ノードに接続し、各ノードのレーシングを 「外積」 に設定します。いずれか一方のノードが元のサーフェスに接続され、もう一方のノードがオフセットされたサーフェスに接続されます。
前の演習と同様に、Surface.PointAtParameter ノードの出力を 2 つの NurbsCurve.ByPoints ノードに接続します。
NurbsCurve.ByPoints ノードの出力を確認すると、この出力が 2 つのリストを持つリストであることがわかります。これは、前の演習で扱ったリストよりも複雑なデータ構造です。データは基礎となるサーフェスによって分類されるため、構造化されたデータに別の層を追加します。
Surface.PointAtParameter ノードでは、データ構造がさらに複雑になっていることがわかります。このノードでは、「リストのリストのリスト」が作成されます。
続行する前に、既存のサーフェスのプレビューをオフにします。
List.Create ノードを使用して、NURBS 曲線を 1 つのデータ構造にマージします。これにより、「リストのリストのリスト」が作成されます。
Surface.ByLoft ノードを接続すると、元のサーフェスが取得されます。これは、元のデータ構造から作成された独自のリスト内にサーフェスがそのまま残っているためです。
前の演習では、List.Transpose ノードを使用してリブ形状の構造物を作成しましたが、ここでは同じ操作を行うことはできません。List.Transpose ノードを使用できるのは 2 次元のリストの場合ですが、ここでは 3 次元のリストを操作するため、リスト内の列と行を反転する操作を簡単に実行することはできません。これまでに説明したように、リストはオブジェクトとして処理されるため、サブリストが含まれていないリストを List.Transpose ノードを使用して反転することはできますが、階層内の 1 段階下の層でリストの NURBS 曲線を反転することはできません。
ここでは、List.Combine ノードを使用します。さらに複雑なデータ構造を処理する場合は、List.Map ノードと List.Combine ノードを使用します。
List.Create ノードを「コンビネータ」として使用して、この操作に適したデータ構造を作成します。
階層内の 1 段階下の層で、データ構造を転置する必要があります。これを行うには、List.Map ノードを使用します。このノードは List.Combine ノードに似ていますが、複数の入力リストではなく 1 つの入力リストだけを使用する点が異なっています。
List.Map ノードに List.Transpose ノードを適用します。これにより、メイン リスト内のサブリストの列と行が反転します。
これで、適切なデータ階層を持つ NURBS 曲線をまとめてロフトし、リブ形状の構造物を作成できるようになりました。
図に示されている入力設定を持つ Surface.Thicken ノードを使用して、ジオメトリに深さを追加します。
この構造にサーフェスを追加して補強してみましょう。別の Surface.ByLoft ノードを追加し、前のステップの NurbsCurve.ByPoints ノードの最初の出力を入力として使用します。
プレビューが見にくくなってきたので、これらのノードのプレビューをオフにします。ノードを右クリックし、[プレビュー]のチェックを外して結果を見やすくします。
選択したサーフェスに厚みをつければ、操作は完了です。
これで、さまざまなデータを使用したロッキング チェアが完成しました。
最後に、ロッキング チェアの溝の方向を変えてみましょう。前の演習では転置用のノードを使用しましたが、ここでも同じような方法で操作を行います。
データ階層にもう 1 つ深い層があるため、List.Map ノードと List.Tranpose 関数を使用して Nurbs の曲線方向を変更します。
Code Block ノードのコード行を次のように変更して、溝の数を増やします。
0..1..#20;``0..1..#30;
最初に作成したロッキング チェアは滑らかな形状でしたが、このロッキング チェアはまったく異なる形状になりました。
リストとは何かということを理解したところで、ここからは、リストに対して実行できる操作について見ていきます。ここでは、リストをトランプのカードだと考えてください。1 組のトランプがリストで、1 枚 1 枚のカードが 1 つの項目ということになります。
写真: Christian Gidlöf
リストに関する質問(クエリー)を作成する場合、次のような質問が考えられます。これにより、リストの特性(プロパティ)がわかります。
Q: カードの数は?A: 52 枚
Q: スートの数は?A: 4 つ
Q: 素材は?A: 紙
Q: 長さは?A: 89 ミリ
Q: 幅は?A: 64 ミリ
リストに対して実行できる操作(アクション)としては、次のような操作が考えられます。この場合、実行する操作に応じてリストが変化します。
カードをシャッフルする。
数字の順にカードを並べ替える。
スート別にカードを並べ替える。
カード全体をいくつかに分割する。
各プレーヤにカードを配ることにより、カード全体をいくつかに分割する。
デッキから特定のカードを選ぶ。
Dynamo では、これらの操作に似た操作を実行することができます。その場合、Dynamo の各ノードを使用して、一般的なデータのリストを操作することになります。これ以降の各演習では、リストに対して実行できる基本的な操作をいくつか見ていきます。
下のリンクをクリックして、サンプル ファイルをダウンロードします。
すべてのサンプル ファイルの一覧については、付録を参照してください。
下の図は、2 つの円の間に線を引いて基本的なリスト操作を表しているベース グラフです。リスト内のデータを管理する方法を紹介し、次のリスト アクションを使用して視覚的な結果を示します。
最初に、
500;
という値が表示されている Code Block ノードを使用します。上記の Code Block ノードを Point.ByCoordinates ノードの x 入力に接続します。
上記のノードを Plane.ByOriginNormal ノードの origin 入力に接続します。
Plane.ByOriginNormal ノードを Circle.ByPlaneRadius ノードの plane 入力に接続します。
Code Block ノードを使用して、radius の値を
50;
に設定します。これは、最初に作成する円の半径です。Geometry.Translate ノードを使用して、上記の円を Z の正の向きに 100 単位移動します。
Code Block ノードで
0..1..#10;
というコードを指定して、0 から 1 までの範囲で 10 個の数字を定義します。上記の Code Block ノードを 2 つの Curve.PointAtParameter ノードの param 入力に接続します。次に、上部に配置されている方の Curve.PointAtParameter ノードの curve 入力に Circle.ByPlaneRadius ノードを接続し、下部に配置されている方の Curve.PointAtParameter ノードの curve 入力に Geometry.Translate ノードを接続します。
Line.ByStartPointEndPoint ノードを使用して、2 つの Curve.PointAtParameter ノードを接続します。
下のリンクをクリックして、サンプル ファイルをダウンロードします。
すべてのサンプル ファイルの一覧については、付録を参照してください。
List.Count ノードは、リスト内の値の数をカウントしてその数を返すという単純なノードです。「リストのリスト」を操作する場合は、このノードの使用方法も多少複雑になりますが、それについてはこれ以降のセクションで説明します。
**List.Count ****** ノードは、Line.ByStartPointEndPoint ノード内の線分の数を返します。この場合は 10 という値が返されますが、これは、元の Code Block ノードで作成した点の数に対応しています。
下のリンクをクリックして、サンプル ファイルをダウンロードします。
すべてのサンプル ファイルの一覧については、付録を参照してください。
List.GetItemAtIndex ノードは、リスト内の項目のクエリーを実行するための基本的な方法です。
まず、Line.ByStartPointEndPoint ノードを右クリックして、プレビューをオフにします。
List.GetItemAtIndex ノードを使用して、インデックス値「0」を選択するか、線分のリスト内の先頭の項目を選択します。
スライダの値を 0 から 9 の間で変更し、List.GetItemAtIndex ノードを使用して別の項目を選択します。
下のリンクをクリックして、サンプル ファイルをダウンロードします。
すべてのサンプル ファイルの一覧については、付録を参照してください。
List.Reverse ノードは、リスト内のすべての項目の順序を逆にします。
順序が逆になった線分のリストをわかりやすく表示するために、Code Block を
0..1..#50;
に変更して線分の数を増やします。Line.ByStartPointEndPoint ノードを複製し、Curve.PointAtParameter ノードと 2 番目の Line.ByStartPointEndPoint ノードの間に List.Reverse ノードを挿入します。
Watch3D ノードを使用して、2 つの異なる結果をプレビューします。一方のノードには、リストが反転されていない結果が表示されます。それぞれの線分が、対応する点に対して垂直に接続されています。もう一方のノードには、反転していないリストとは逆の順序で、すべての点が接続されます。
下のリンクをクリックして、サンプル ファイルをダウンロードします。
すべてのサンプル ファイルの一覧については、付録を参照してください。
List.ShiftIndices ノードは、ねじれパターンやらせんパターンなどを作成する場合に便利なノードです。このノードは、指定されたインデックス値の分だけ、リスト内の項目を移動します。
List.Reverse ノードの場合と同様に、List.ShiftIndices ノードを Curve.PointAtParameter ノードと Line.ByStartPointEndPoint ノードの間に挿入します。
Code Block ノードを使用して、リストを移動するインデックス値として「1」を指定します。
この場合の変化はわずかですが、下部に表示されている方の Watch3D ノード内のすべての線分が、インデックス 1 つ分だけ横にずれた点に接続されています。
Code Block ノードの値を「30」などの大きな値に変更すると、すべての線分が大きく変化することがわかります。元の円柱形状がこのように変化する動作は、カメラの絞りによく似ています。
下のリンクをクリックして、サンプル ファイルをダウンロードします。
すべてのサンプル ファイルの一覧については、付録を参照してください。
List.FilterByBooleanMask ノードは、ブール値のリストに基づいて、特定の項目を削除します。ブール値とは、「true」または「false」を読み取る値のことです。
「true」または「false」を読み取る値のリストを作成するには、次の手順を実行します。
Code Block ノードを使用して、
0..List.Count(list);
という構文の式を作成します。次に、Curve.PointAtParameter ノードを list 入力に接続します。この設定については、Code Block の章で詳しく説明します。ここでは、上記の構文を使用すると、Curve.PointAtParameter ノードの各インデックス値を表すリストが作成されるということだけを覚えてください。剰余演算を処理する「%」ノードを使用して、Code Block ノードの出力を x 入力に接続し、4 という値を y 入力に接続します。この操作により、インデックス値のリストを 4 で割った場合の余りが取得されます。剰余演算を処理する「%」ノードは、パターンを作成する場合に非常に便利なノードです。たとえば、整数を 4 で割った場合の余りは、0、1、2、3 のいずれかになります。
剰余演算を処理する「%」ノードの値が 0 になっている場合、インデックス値は 4 で割り切れる数値(0、4、8 など)であるということがわかります。「== 」ノードを使用して、インデックス値を「0」という値に対してテストすると、そのインデックス値が割り切れる数値であるかどうかを判断することができます。
Watch ノードには、true,false,false,false... というパターンでテストの結果が表示されます。
この true/false のパターンを使用して、2 つの List.FilterByBooleanMask ノードの mask 入力に接続します。
Curve.PointAtParameter ノードを、2 つの List.FilterByBooleanMask ノードの list 入力に接続します。
List.FilterByBooleanMask の出力が in と out から読み取られます。in は、「true」というマスク値を持つ値を表し、out は、「false」というマスク値を持つ値を表します。in 出力を Line.ByStartPointEndPoint ノードの startPoint 入力と endPoint 入力に接続すると、フィルタされた線分のリストが作成されます。
下部に表示されている方の Watch3D ノードに、線分の数が点の数よりも少ない円柱が表示されます。フィルタ処理で true の値だけに絞り込んだため、ノードの 25% だけが選択されました。