
こんにちは。
今日はC#を使ったGrasshopper コンポーネントの作り方を考えていこうと思います。
参考にしたサイトはDesignalyze:Scripting in GHです。
このサイトは、たまに、アイフォンが当たりました!!とかいう詐欺サイトに飛ばされるので気を付けてください。
正確には、参考にしたというよりかは、このサイトに沿って学習を進めていきました。
実はC#をgrasshopperで使うのはとても簡単なんです!
これから詳しく解説していこうと思います。
最後までよろしくお付き合いください!
応用編はこちら↓
目次
grasshopperでC#を使う基本編
まずはMathのタブからC#コンポーネントを選んで配置します。

それから、Panelを出して、outに繋ぎます。
このパネルはコンソールのような働きをするらしく、エラーログなど文法ミスが出たりします。

コンポーネントをダブルクリックすると、エディタが起動します。

現在の状態ではobjectxとobject yがインプットでAがアウトプットになっていますよということが書いてあります。
例えば、Aに0,0,0座標が吐き出されるコードを書いてみます。
Point3d pt = new Point3d(); でポイントの宣言をした後に、pt.と打つと使えるメソッドが出てきます。
これによって入力の予測が出てくるので楽ですね。

下記のようにポイントを原点にするように書きます。

パネルを確認するとエラーログは出ていませんね。
そして、原点に点が現れました。

しかし、これではインプットのxとyが無駄ですね。
今度はx y z のインプットを利用して点を作りたいと思います。
コンポーネントに十分に寄ると、zをプラスボタンで足すことができます。

そして、下記のようにスクリプトを書き換えます。
プルダウンメニューでPoint3dの予測入力候補が出てきますね。

入力し終えると、エラーログが出ます。x、y、zがオブジェクト型を参照しているのに対し、スクリプトではDoubleの数値になっているためです。

これを治すためにはコンポーネントの入力部分を右クリックしType Hint をDoubleにします。

x、y、zそれぞれをdouble を選択してあげることで、実際のスクリプト内の文字も変わっているのが確認できます。
そして、エラーログが消える事が確認できます。

そして、x、y、zに好きな値を入れると、パラメトリックにポイントが作成されました。

grasshopperでC#のLineコンポーネントを作成する
それでは、ポイントの時と同様にLineの宣言を行って変数を代入するようにしてみます。
下記のように書きます。

この時、Point やLineのクラスって全部覚えてないといけないの?という疑問が出てきます。
このLineというクラスは実はRhino.Geometryという名前空間から来ています。
一行目のUsingというところをクリックして開くと、使ってる名前空間が出てきますね。

では、Rhino.Geometryと打ってみましょう。予測入力の使用可能なクラスがプルダウンメニューに出てきます。
これによって使用できるクラスが選べるようになっています。
クラス名が分かっているのであれば、Rhino.Geometry.は名前空間に追加されているのでもちろんタイプする必要はありません。

下記のようにタイプすると、お決まりのエラーログが出てきます。

もちろんx、y、にPoint 3dが入力として求められているのに対し、x、y、zがobjectになっているからですね。

前の章と同様にType HintからPoint3dを選んであげるとエラーログは消えます。
x、yにポイントを突っ込むと、ラインができる事が確認できます。

grasshopperでC#のリストとFor文を使ってみる
今度はリストの宣言を行い、For文をグラスホッパーで使ってみましょう。
下記のようにタイプします。

これによって0~9までの整数をリスト化することができます。

これは結局のところSeriesを使うのとあまり大差がありませんね。
しかし、スクリプト内でfor文やリストを実装できることで、様々な所で応用が利きそうな気がします。
例えば、下記のように書くことで点をy=2xの線に並べる事ができます。
List<Point3d> pts = new List<Point3d>();
for (int i = 0; i < 10; i++) {
Point3d tempPt = new Point3d(i, i*2, 0);
pts.Add(tempPt);
}
A = pts;
for 文が回るたびにAddでtempPtをリストに追加しているということです。

C#のforeachを使って点に〇をつけてみる
foreachの構文を使って点を中心とした円を描いてみます。
適当に点を打って、Pointコンポーネントで拾います。

C#コンポーネントには下記のように記述します。
private void RunScript(List<Point3d> x, object y, ref object A)
{
List<Circle> circles = new List<Circle>();
foreach(Point3d pt in x)
{
Circle tempCircle = new Circle(pt, 1);
circles.Add(tempCircle);
}
A = circles;
}
foreach によってListxのなかの各ptについて{}内の作業を行います。
この時の、ptは中心点で、もう1つの値は半径です。

記述を終えるとエラーが出ます。
これは、リストを拾う場合は、Item AccessをList Accessにする必要があるようです。

点の周りに半径1の丸が描けました。

C#とwhileを使ってSeriesを実装してみる
while を使うことでSeriesコンポーネントを自作することができます。
やり方はとても簡単で、C#コンポーネントに下のように記載します。
iがcount以下である場合、start 足すstep*iを計算しリストに加え、iをインクリメントします。
できたリストを吐き出すようになっています。
List<int> numbers = new List<int>();
int i = 0;
while (i < count) {
numbers.Add((i * step) + start);
i++;
}
A = numbers;
この時、Slider をリネームするだけではだめで、エラーが出ます。
コンポーネントのx、y、z全てをリネームしてあげる必要があります。

C#コンポーネントのインプットを右クリックしてそれぞれを、C#の変数に合わせてリネームしていきます。

あれ、おかしいですね。リネームし終わると、エラーログが出ています。
これは型の問題のようですね、恐らくobject型として認識されているのが問題のようです。
整数に変更してあげましょう。

前のエクササイズ同様にC#コンポーネントのインプットを右クリックし、TypeHintを整数型にそれぞれ変更します。

うまく、Seriesと同様の結果が得られました。
C#とネストされたfor文でグリッドを作ってみる
簡単なグリッドの作り方を試してみましょう。
xSizeとySizeがグリッドの領域で、numDivsXとnumDivsYがグリッドの数です。
C#コンポーネントには下記のように記載します。
for文の中にfor文を入れることでグリッドを作成しています。
一つ目のfor文では原点のx座標にグリッド間隔を足してあげる事で点を作成し、それを二つ目のfor文でy方向にコピーしてあげています。
List<Point3d> pts = new List<Point3d>();//リストの宣言
if (x == null) {
x = new Point3d(0, 0, 0);//ポイントが与えられなかった場合原点とする。
}
double spacingX = xSize / numDivsX;//グリッド間隔の計算
double spacingY = ySize / numDivsY;//グリッド間隔の計算
Point3d tempPt = x;//グリッド原点の宣言
for (int i = 0; i < numDivsX; i++) {
tempPt.X = x.X + (spacingX * i);
for (int j = 0; j < numDivsY; j++) {
tempPt.Y = x.Y + (spacingY * j);
pts.Add(tempPt);
}
}
A = pts;
エラーが出る場合には下の画像の冒頭の部分の型に注意してください、Point3dとdoubleとintと使い分けが必要です。

とても簡単にグリッドの作成ができる事が分かると思います。
C#でif文を使ってみる
今度はif文を使ってみましょう。トグルをtrueにすると、”It's true"と返すコンポーネントを組んでみます。
トグルがTrueの時は下記のようにパネルに表示されます。

トグルがFalseの時は下記のようにパネルに表示されます。
うまく、機能していることが判ります。

それでは、コンポーネントの中身を見てみましょう。
コンポーネントには簡潔に下記のように書いてあります。
if (x == true) {
A = "It's True!";
} else {
A = "It's False";
}
もし、xがtrueと等しい時、AにIt's trueを代入します。
それ以外の場合はAにIt's Falseを代入します。
たったこれだけです。
とても簡単ですよね。
そこで、もう少しだけ複雑な処理をしてみます。
X座標が3の約数もしくは5の約数の時だけ点をうつコンポーネントを考えます。
0,3,5,6,9,10,12,15、、、という風に3もしくは5で割り切れる場合は点を打ち、そうでない場合は点を打たないという書き方をしたいと思います。

コンポーネントの中身は下記のようになります。
まずはListの定義をし、for文で1~99回処理を繰り返すようにします。
そして、もし、iを3で割った時の余り(%)が0であるならば、または(||)、5で割った時の余りが0であるならば、下記の処理を行うと書いてあります。
下記の処理とは、iをⅹ座標とする点に点を打つという事です。
これによってiが3もしくは5の約数の時に点を打つということができるようになりました。
List<Point3d> pts = new List<Point3d>();
for (int i = 0; i < 100; i++) {
if (i % 3 == 0 || i % 5 == 0) {
Point3d ptTemp = new Point3d(i, 0, 0);
pts.Add(ptTemp);
}
}
A = pts;
C#でDivideCurveを作ってみる
今度はDivideCurve、カーブをいくつかの点で割ってあげるスクリプトを組んでみたいと思います。
下記のようにC#コンポーネントに記載します。
この時のxとはカーブです。そして、tは曲線の長さを1にnormalizeした場合のt値(0~1)です。
tの値に対するカーブ上のxの座標を取得するコンポーネントです。
Point3d pt = new Point3d(); pt = x.PointAtNormalizedLength(t); A = pt;
コンポーネントにエラーがあるようです。これはCrvがobject型で参照されているせいですね。

C#コンポーネントのinputを左クリックし、Type HintをCurveに変更します。

エラーが消え上手く動いているのが確認できると思います。
これを基礎として、DivideCurveコンポーネントの作成に挑戦してみましょう。
まずはポイントを格納するリストの宣言と、ポイントの宣言をしておきます。
次に、spacingという変数に1をnumDivsで割った数を代入します。
このspacingが各点のt値の差になります。
最後に、t値にi*spacingを代入し、t値に対する点を作成して、リストに追加します。
List<Point3d> pts = new List<Point3d>();
Point3d pt = new Point3d();
double spacing = 1.0 / numDivs;
double t;
for (int i = 0; i <= numDivs; i++) {
t = i * spacing;
pt = x.PointAtNormalizedLength(t);
pts.Add(pt);
}
A = pts;
曲線が等間隔にnumDivs個に分割されたのが確認できます。

C#でrandomクラスを使ってみる
今度はrandomクラスを利用したコンポーネントを作成します。
まずはリストと、ランダムクラスの使用宣言(初期化)を行います。
次にfor文でendに達するまで2ずつインクリメントしていく条件で、下の処理を行うようにします。
処理の中では0~100の間のランダム値を取得し、iをⅹ座標とした点と、ランダム値をⅹ座標とした点を繋ぐ直線をリストに追加します。
詳細は下記のスクリプトのようになります。
List<Line> lines = new List<Line>();//リストの宣言
Random random = new Random();//ランダムクラスを使いますよという宣言
for(int i = start; i <= end; i = i+2){ //2ずつインクリメントしてendに達するまで繰り返すfor文
int randint = random.Next(0, 100);//0~100の値をrandintに返すランダムメソッド
Line ln = new Line(i, 10, 0, randint, 50, 0); //点1から点2へと座標を代入すると線を引く(x1, y1, z1, x2, y2, z2)
lines.Add(ln); //リストにラインを加える。
}
A = lines;
実行してみると下記のようなランダムな線が得られます。
下のY座標が10の点がiを用いた一点目で、xが2ずつインクリメントしているのが確認できます。
それに対し、上のY座標が50の点はランダムに並んでいるのが分かると思います。

さて、これを利用して、今度はランダムに正方形を作成するスクリプトを書いてみましょう。
先ほどのスクリプトとほぼ一緒のやり方で書いてあります。
追加で必要だったのは四角形を定義するための平面ですね。
平面を定義するには点と、z方向のベクトルが必要です。
よって、ベクトルを作成し代入しています。
点はx,y,z,の順番で、i(1~100),ランダム(0~100)、ランダム(0~10)が代入されています。
詳細は下記のスクリプトの注釈をご参照ください。
List<Point3d> pts = new List<Point3d>();
List<Plane> plns = new List<Plane>();//平面の宣言
List<Rectangle3d> rects = new List<Rectangle3d>();//四角形の宣言
Random random = new Random();
Vector3d unitZ = new Vector3d(0,0,1);//unitZ単位ベクトルの作成
for(int i = start; i <= end; i = i + 2) {
//Create random values
int randint = random.Next(0,100);//y座標
int randint2 = random.Next(0,10);//Z座標
int randint3 = random.Next(0,5);//四角形の辺の長さ
Point3d pt = new Point3d(i, randint, randint2);//点の作成
Plane pln = new Plane(pt, unitZ);//平面の作成
Rectangle3d rect = new Rectangle3d(pln, randint3, randint3);//四角形の作成
//リストの作成(点と平面はリストを最終的に使用してないので要らないです。)
pts.Add(pt);
plns.Add(pln);
rects.Add(rect);
}
A = rects;
うまく、正方形がランダムに配置されました。
これを利用すれば色々なランダムなパターンが作れそうですね。

grasshopperでC#を使う基本編まとめ
今回はgrasshopperのC#コンポーネントの基礎的な使い方を学びました。
for, foreach, whileなどの基本的なC#のプログラムで使える機能がgrasshopperでも使えるということが確認できました。
型を揃えることも必要で、TypeHintから正しい型を選べるという事も重要なポイントでしたね。
今後は、より実践的なC#の応用の仕方を考えていきたいと思います。
最後まで読んでいただきありがとうございます。
もし、興味があれば応用編もありますのでこちらからどうぞ。
それでは、また!












