• ABOUT
  • SITE POLICY
  • AGREEMENT
  • JP
  • SIGN IN:
  • SIGN IN:
DrawViewportWires methodのふるまいについて
by Hiroaki Saito Jul 11, 2019

備忘録として記します。
GrasshopperのC#コンポーネント内でDrawViewportWiresを利用する際に、
複数のうまく動かない事象が出てきたのでこれを解決するまでの流れを整理しました。

まずC#コンポーネント内でジオメトリを描画するための簡単なコードをざっくり示します。

private void RunScript(double num, ref object A)
{
_num = num;
}

//

<Custom additional code>
//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);
}
//

</Custom additional code>
}

結果は以下です。
cap01.JPG

次に描画している線データをBakeできるように書き足します。

private void RunScript(double num, bool  bake, ref object A)
{
_num = num;
_bake = bake;
}

//

<Custom additional code>
//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);
}
}
//

</Custom additional code>
}

ここでまず一つ問題が出てきます。
itemアクセスにしているnumに複数のデータが入力された際、最後に入力されたデータでしか描画が反映されません。
cap02.JPG

これを回避するには、以下のように書きます。
一つのデータだけでもあえてListに格納しておく必要があるようです。
(そのことに言及しているフォーラムのリンクを失念してしまいました・・・)

private void RunScript(double num, bool  bake, ref object A)
{
//一つのデータだけでもListに格納する。
numList.Add(num);
_bake = bake;
}

//

<Custom additional code>
//DrawViewportWiresに渡すためのフィールド。
private bool _bake;
private List<double> numList = new List<double>();

/*
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();
}
//

</Custom additional code>
}

これで複数入力でも正常に描画してくれます。
cap03.JPG

しかし、更に問題がありました。
説明が難しいのですが、

「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;
}

//

<Custom additional code>
//DrawViewportWiresに渡すためのフィールド。
private bool _bake;
private List<double> numList = new List<double>();

/*
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();
}
//

</Custom additional code>
}

これでこの問題は解決しましたが、別の問題が更に重なっていました。
上記の操作でBakeはできるようになったのですが、なぜか何重もBakeされる現象が発生しました。
cap04.jpg

どうやら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できる。
}
}

//

<Custom additional code>
//DrawViewportWiresに渡すためのフィールド。
private List<double> numList = new List<double>();
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();
}
//

</Custom additional code>
}

これで今のところ見つかっている問題を回避?解決?できましたが、そもそもC#コンポーネントの挙動についてそんなに詳しい訳ではないのでもっとスマートにやれる、説明できる、という事があればこっそり指摘してもらえたらと思います。

因みに最後のBakeが重複するのは起きる時と起きない時と現象をつかみ切れていないので、鵜呑みしてもらうには注意が必要です。


コメントをするにはログインしてください。

10474 0
Tags
#Grasshopper #C# #bake #DrawViewportWires
License
cc_by_sa
GNU GPL

CONTACT ©2025 NIKKEN SEKKEI LTD.