備忘録として記します。
GrasshopperのC#コンポーネント内でDrawViewportWiresを利用する際に、
複数のうまく動かない事象が出てきたのでこれを解決するまでの流れを整理しました。
まずC#コンポーネント内でジオメトリを描画するための簡単なコードをざっくり示します。
private void RunScript(double num, ref object A)
{
_num = num;
}//
//DrawViewportWiresに渡すためのフィールド。
private double _num;public override void DrawViewportWires(IGH_PreviewArgs args)
{
//Lineを作成。
Point3d ptStart = new Point3d(0, 0, 0);
Point3d ptEnd = new Point3d(_num, _num, 0);
Line ln = new Line(ptStart, ptEnd);//Draw
args.Display.DrawLine(ln, Color.Magenta);
}
//
}
次に描画している線データをBakeできるように書き足します。
private void RunScript(double num, bool bake, ref object A)
{
_num = num;
_bake = bake;
}//
//DrawViewportWiresに渡すためのフィールド。
private double _num;
private bool _bake;/*
Rhino.RhinoDoc.ActiveDoc.Objectsはdoc.Objectsと同じ。
後述しますが、ここに書くのは問題がある。
*/
private Rhino.DocObjects.Tables.ObjectTable oTable =
Rhino.RhinoDoc.ActiveDoc.Objects;public override void DrawViewportWires(IGH_PreviewArgs args)
{
//Lineを作成。
Point3d ptStart = new Point3d(0, 0, 0);
Point3d ptEnd = new Point3d(_num, _num, 0);
Line ln = new Line(ptStart, ptEnd);//Draw
args.Display.DrawLine(ln, Color.Magenta);//Bake
if(_bake)
{
oTable.AddLine(ln);
}
}
//
}
ここでまず一つ問題が出てきます。
itemアクセスにしているnumに複数のデータが入力された際、最後に入力されたデータでしか描画が反映されません。
これを回避するには、以下のように書きます。
一つのデータだけでもあえてListに格納しておく必要があるようです。
(そのことに言及しているフォーラムのリンクを失念してしまいました・・・)
private void RunScript(double num, bool bake, ref object A)
{
//一つのデータだけでもListに格納する。
numList.Add(num);
_bake = bake;
}//
//DrawViewportWiresに渡すためのフィールド。
private bool _bake;
private ListnumList = new List (); /*
Rhino.RhinoDoc.ActiveDoc.Objectsはdoc.Objectsと同じ。
後述しますが、ここに書くのは問題がある。
*/
private Rhino.DocObjects.Tables.ObjectTable oTable =
Rhino.RhinoDoc.ActiveDoc.Objects;public override void DrawViewportWires(IGH_PreviewArgs args)
{
foreach(double item in numList)
{
//Lineを作成。
Point3d ptStart = new Point3d(0, 0, 0);
Point3d ptEnd = new Point3d(item, item, 0);
Line ln = new Line(ptStart, ptEnd);//Draw
args.Display.DrawLine(ln, Color.Magenta);//Bake
if(_bake)
{
oTable.AddLine(ln);
}
}
}/*
ListをRunScriptの外で宣言した場合、
これを書かないとBakeを押すたびに線の数が増えていきます。
*/
public override void BeforeRunScript()
{
numList.Clear();
}
//
}
しかし、更に問題がありました。
説明が難しいのですが、
「Rhinoを起動、Grasshopperを起動、ghファイルを開き、Bakeする。」
これは、問題なくできます。しかし更にそこから、
「ghファイルは開いたまま、Rhinoのファイルを新規作成し直し、Bakeする。」
と、なぜかBakeできません。色々調べているとScript_Instanceのフィールドとして、ObjectTableを宣言する事でその事象が生まれているようでしたので、以下のように書き直しました。
private void RunScript(double num, bool bake, ref object A)
{
//一つのデータだけでもListに格納する。
numList.Add(num);
_bake = bake;
}//
//DrawViewportWiresに渡すためのフィールド。
private bool _bake;
private ListnumList = new List (); /*
Script_Instanceクラスのフィールドとして以下を宣言すると、
このファイルをを開いたままRhinoファイルを新規作成して、
もう一度Bakeを押すとBakeできない現象が発生する。
*/
//Rhino.DocObjects.Tables.ObjectTable oTable = Rhino.RhinoDoc.ActiveDoc.Objects;public override void DrawViewportWires(IGH_PreviewArgs args)
{
foreach(double item in numList)
{
//こっちに書く。
Rhino.DocObjects.Tables.ObjectTable oTable =
Rhino.RhinoDoc.ActiveDoc.Objects;//Lineを作成。
Point3d ptStart = new Point3d(0, 0, 0);
Point3d ptEnd = new Point3d(item, item, 0);
Line ln = new Line(ptStart, ptEnd);//Draw
args.Display.DrawLine(ln, Color.Magenta);//Bake
if(_bake)
{
oTable.AddLine(ln);
//doc.Objects.AddLine(ln); //これでも同様にBakeできる。
}
}
}/*
ListをRunScriptの外で宣言した場合、
これを書かないとBakeを押すたびに線の数が増えていきます。
*/
public override void BeforeRunScript()
{
numList.Clear();
}
//
}
これでこの問題は解決しましたが、別の問題が更に重なっていました。
上記の操作でBakeはできるようになったのですが、なぜか何重もBakeされる現象が発生しました。
どうやらDrawViewportWiresメソッドが何かあるたびに2回以上計算が回される時があるようです。
詳しい仕様はわかりませんが、そういうものだという理解で以下のようにRunScript内に書き換えることにしました。
private void RunScript(double num, bool bake, ref object A)
{
Rhino.DocObjects.Tables.ObjectTable oTable =
Rhino.RhinoDoc.ActiveDoc.Objects;//DrawViewportWiresメソッドのために一つのデータだけでもListに格納する。
numList.Add(num);//Lineを作成
Point3d ptStart = new Point3d(0, 0, 0);
Point3d ptEnd = new Point3d(num, num, 0);
Line ln = new Line(ptStart, ptEnd);
_ln = ln;//Bake
if(bake)
{
oTable.AddLine(ln);
//doc.Objects.AddLine(ln); //これでも同様にBakeできる。
}
}//
//DrawViewportWiresに渡すためのフィールド。
private ListnumList = new List ();
private Line _ln;public override void DrawViewportWires(IGH_PreviewArgs args)
{
foreach(double item in numList)
{
//Draw
args.Display.DrawLine(_ln, Color.Magenta);
}
}public override void BeforeRunScript()
{
numList.Clear();
}
//
}
これで今のところ見つかっている問題を回避?解決?できましたが、そもそもC#コンポーネントの挙動についてそんなに詳しい訳ではないのでもっとスマートにやれる、説明できる、という事があればこっそり指摘してもらえたらと思います。
因みに最後のBakeが重複するのは起きる時と起きない時と現象をつかみ切れていないので、鵜呑みしてもらうには注意が必要です。
コメントをするにはログインしてください。