今回は、任意のポリラインを元に配管を生成し、配管の長さ・数量・エルボの数などを取得していこうと思います。初学者の方にとってはややこしいかもしれません、データツリーをしっかり理解している必要があります。また、今回はプラグインやPython・C#などを使用せず実装していますが、所々スクリプトを書けば楽な箇所はあります。より効率の良い方法はいくらでもあると思いますので、自分なりに修正してみてください。
目次
概要

上画像がプログラムの全体像となっております。各ブロックごとに説明していこうと思います。
ベースとなるポリラインを生成

- まずはRhinocerosでPolylineを生成します。今回は75Φの配管を実装していこうと思いますので、各辺400mm以上はあるかなといった感じです。小さすぎるスケールにしないようご注意ください(※例えば1辺10mmとかだと、そもそも75Φの配管できませんので・・・)上画像ではX・Y・Z方向に垂直なポリラインになっておりますが、斜めも対応できるようにプログラムは組んでいきます。
- Grasshopperに移動し、Curveコンポーネントにセットします。
コーナー位置を取得

- コーナー部分にはコーナー材(エルボ)が来ますので、その位置を取得していきます。
- Explodeコンポーネントでポリラインを直線に分解していきます。
- Lengthコンポーネントで直線の長さを取得します。
- 今回はコーナー位置からそれぞれ100mm返った箇所でジョイントしたいので、100mm ÷ (直線の長さ)と、(直線の長さ-100mm)÷直線の長さの2つの値を取得します。この2つの値は、直線の始点・終点を0~1とした際に、始点・終点から100mm返った位置となります。
- Evaluate Curveコンポーネントを2つ用意し、Reparametrizeして分割したポリラインを接続します。先ほど取得した、直線の始点から100mm返った位置と終点から100mm返った位置を接続し、実際のポイントを取得します。
- Weaveコンポーネントで取得した点を1つのリストにしていきます。Patternは右クリックでSet Multiple Integerで「0,1,2」と入力します。0にExplodeコンポーネントから始点を、1には始点から100mm返った位置を、2には終点から100mm返った位置を接続します。
配管の中心線を取得

- 先ほど作成した点のリストから配管の中心線を生成します。Polylineコンポーネントで再度最初の状態に戻します。
- Filletコンポーネントでコーナー部分を曲げていきます。角から100mm返った位置を取得したので、100mmを半径としています。
- ここで問題が起きてきます。最初に設定する曲線が直線だった場合、Filletコンポーネントは機能せずエラーを吐いてしまいます。なので、Stream Filterコンポーネントを使って工夫します。
- 最初に設定する曲線が直線だった場合、当たり前ですが、PolylineコンポーネントからはPolylineCurveではなくLinear Curveが取得できます。とりあえずPolylineコンポーネントの出力端子をReplace Textコンポ―テントで「Linear Curve」⇒「This is Linear Curve」とでも置き換えましょう。
- Member Indexコンポーネントで「This is Linear Curve」のテキストがList内にいくつあるか取得します。この値がPolylineだったら0だし、直線だったら1になりますね。この値を利用していきます。
- Stream FilterコンポーネントのGateにMember IndexコンポーネントのNを接続します。0の場合はFilletされたポリラインが出力されます。次の項で1の時に出力される直線を生成していきます。
直線だった場合

- 最初に設定する曲線が直線だった場合、Stream Filterコンポーネントにそのまま最初のCurvesコンポーネントを接続すればいいじゃんと思った方もいるかもしれませんが、今回はそうしません。後々わかってくると思いますが、今回はパイプの長さが一定以上の場合、継手を設けるようなプログラムを書いていこうと思います。もし設定された直線の頂点が、始点と終点のみのではなく、中間にも頂点があってしまった場合に都合が悪くなるので、その場合でも頂点が始点・終点のみの直線となるようなプログラムを書いていこうと思います。
- End Pointsコンポーネントで始点と終点を取得し、Lineコンポーネントで直線を初期化します。これをStream Filterコンポーネントの1の端子に接続します。
- これで、最初の曲線が直線の時は、配管の中心線は直線が返され、そうでない場合はフィレットされた曲線が返されます。
一定以上の長さより長い箇所を取得

- 配管にも定尺がありますよね。今回は一定以上の長さの場合に継ぎ手を設けたいので、指定した長さ以上の直線を取得していきます。
- Explodeコンポーネントで直線と円弧に分割します。
- Lengthコンポーネントで分割した直線・円弧の長さを取得します。
- Larger Thanコンポーネントで取得した長さが1000mmより大きいかどうかをBool値で取得します。この1000mmは目的とする材料の定尺など入れてみてください。
- Member IndexコンポーネントでTrueの場合のIndex番号を取得します。Construct Pathコンポーネントで取得したインデックス番号でPathを生成します。入力値はGraftして出力値はSimplifyしておきましょう。
- ExplodeコンポーネントにEntwineコンポーネントを接続します。EntwineコンポーネントはGraftで使用し{0;x}にGraft・simplifyした分割した曲線を、{1;x}にはPanelコンポーネントで適当にdummy dataを生成しときます。これをする理由は後ほど説明します。
- 出力値をFlattenし、Graftコンポーネントで再度Graftします。これをする理由はブランチの番号をきれいにしたいからです。
- Split Treeコンポーネントで接続したデータツリーから一定以上の長さの直線が格納されているブランチを取得します。出力端子Pからは一定以上の長さの直線が格納されているブランチが、Nからはそうでない直線・円弧が取得できます。
- 先ほどdummy dataを設けたのは、最初に設定するが直線だった場合にSplit Treeコンポーネントが機能しないためです。直線だった場合、Explodeしても直線なので値は1つです。それをSplit Treeコンポーネントで検索を掛けても検索がかかりません。なのであえてダミーデータを設けてブランチが最低でも2つになるようにしています。
継手位置取得

- Divide Curveコンポーネントで先ほど取得した1000mm以上の直線を分割していきます。
- Lengthコンポーネントで長さを取得します。
- Divisionコンポーネントで取得した長さを、1000mm(先ほど指定した材料の定尺などの値)で割り、Roundコンポーネントで切り上げた数値で分割していきます。
- Shatterコンポーネントで一定以上の長さの直線をDivide Curveコンポーネントで取得した分割点位置のパラメーターで切断します。出力端子はSimplifyします。
- Mergeコンポーネントで一定以上の長さではない曲線と一定以上の長さを分割した直線をマージし、Flattenしておきます。
- 前項で作成したdummy dataが邪魔なので、Cull Indexコンポーネントで‐1番目を削除し、dummy dataを消します。
- Join Curvesコンポーネントで曲線を結合します。
配管の生成

- Join Curvesコンポーネントで結合する前の分割状態の曲線に対して、Perp Framesコンポーネントを使用し、Countに1を指定することで、始点と終点に曲線に直行する平面を取得します。
- Circleコンポーネントで取得した平面に円を生成します。半径は配管の半径としたいので、75Φの半分で37.5mmとしています。出力端子はFlattenしてSimplifyしておきます。
- List Itemコンポーネントで0番目の値を取得し、全体の曲線の始点位置にある円を取得します。
- Sweep1コンポーネントでJoin Curvesコンポーネントから出力される、配管の中心線をレールにして円を押し出します。とりあえず配管部分の完成です。
継手・仕口部作成

- Offset Curveコンポーネントで先ほど生成した円をオフセットします。7.5mm外側にオフセットしています。
- Entwineコンポーネントでオフセット前と後の円をそれぞれブランチに格納しています。
- Flip Matrixコンポーネントで行列を反転させることで、それぞれ対応する円同士でブランチに格納します。
- Boundary Surfaceコンポーネントでオフセット前と後との間にサーフェイスを張ります。
- Offset Surfaceコンポーネントで生成したサーフェイスを今度はパイプの方向にオフセットします。今回は適当に5mmオフセットします。
- Brep Edgesコンポーネントでオフセット前と後のサーフェイスそれぞれのエッジを取得します。
- Ruled Surfaceコンポーネントでエッジ同士の間にサーフェイスを張ります。
- Mergeコンポーネントで仕口・継手部のサーフェイスをまとめます。
- 最後にMergeコンポーネントで配管部と継手・仕口部をまとめて完成です。
配管データ取得①(径)

- それではデータを取得していきます。まずは配管の直径を取得します。これは簡単ですね。
- 配管の半径を使用しているので、それを2倍するだけです。
- 私はサムネイルをつくる都合上、Rhinocerosに情報をBakeしたかったので、テキスト化して、Concatenateコンポーネントで「"Pipe_Size=>" + "75" + "Φ"」として「Pipe_Size=>75Φ」という文字列を取得しています。
配管データ取得②(長さ・コーナーの数)

- 結合する前の配管の中心線をDataコンポ―ネントで持ってきます。Flattenしておきます。
- Replace TextコンポーネントでDataのListのうちコーナー部分(Arc-Like Curve)を適当に「This is Pipe corner」というテキストに置き換えておきましょう。
- Member Indexコンポーネントで「This is Pipe corner」に置き換わったリストのIndex番号を取得します。
- Cull Indexコンポーネントで取得したIndex番号のデータを削除すれば、直線部分のみが残るります。Lengthコンポーネントで長さを取得することで、各配管の長さが取得できます。
- 私はサムネの都合上、「Pipe_Length:○○mm」
- List ItemコンポーネントでArc部分を取得すれば、コーナー部分のみのリストになります。List Lengthコンポーネントで数量を取得します。
- 私はサムネの都合上、「Num_of_Pipe_Corner => ○○」という文字列で取得しています。
完成

最後はText Tag 3Dコンポーネントで取得した文字列をテクストオブジェクトに変換してRhinoceros上に張っているだけです。途中のごちゃごちゃしているのは単純に、どの位置に張り付けるかを書いているだけなので割愛します。

いかがだったでしょうか。たぶん意味不明な箇所が多々あったかと思います。とりあえずベタ打ちしながらPanelコンポーネントでリストの中身を確認しながら進めることをお勧めします。また、もっと簡単な実装方法はいくらでもあると思います。スクリプトを書けば楽になる箇所もあります。是非自分なりに修正してみてください。