ZeroTouchNodeを作ってみよう!初級編

公開:2021/02/16
更新:2021/02/20
8 min読了の目安(約7200字TECH技術記事

ZeroTouchNodeとは

ZeroTouchNode(ZTN)は、C# で記述されたカスタムノードです。ZTNは、Dynamo内にDLLをインポートするだけで取得できます。

  • Dynamoカスタムノード 既存のノードをコンテナにネストすることで実行されます。カスタムノードはDYFファイルとして保存され、簡単に共有できます。
  • コードブロック DesignScriptを用いて、スパゲッティのように絡まったグラフを簡潔に書くことが出来ます。
  • Pythonノード Pythonコードを含むカスタムノードであり、モジュールとパッケージをサポートします。
  • ZeroTouchノード C#で記述されたカスタムノードを作成またはインポートします。これはより複雑な選択ですが、.NET Framework、堅牢なIDE、デバッグツール、および多くのライブラリのメリットがあります。
  • デフォルトノード 基本的にはC#で記述されたネイティブDynamoノードであり、NodeModelインターフェイスを実装し、カスタムUIを持ち、グラフの状態に影響を与えることができます

なんでZeroTouchNodeを使うの?

C#を使用してゼロタッチノードを作成する理由は多数あります。

  • IDE(Visual Studio)に完全に統合され、他のどのオプションよりもコーディングを容易にするIntelliSenseとデバッグを提供します
  • 速度–ゼロタッチノードは迅速に実行されるため、大規模プロジェクトの複雑な問題に最適です。Pythonノードよりも処理が速いです。
  • Revit API、Dynamo APIへのフルアクセス、および外部アプリケーションとの通信機能
  • 中身を見ることができないので、知財を守ることが出来ます。

環境

  • Revit2020.2
  • Dynamo2.3.0
  • visual studio 2019

Visual Studioでプロジェクトを作成しよう!

VisualStudioで新しい クラスライブラリプロジェクト(DLL) を作成します。.NETFrameworkのバージョンは、使用するRevitの.NETFrameworkのバージョンに合わせる注意してください。
今回使うRevitのバージョンは2020なので.NET Framworkのバージョンを4.7.2にしました。
プロジェクト名は、DynamoWorkshopとします。

初級編01 カスタムノードを作成してみよう!

環境が整ったので早速カスタムノードを作成していきましょう!
コードはいたって簡単です。プロジェクト内で定義されたメソッドはDynamoのノードとして表示されます。

https://alvpickmans.github.io/DynamoDevelopment-London-Hackathon-2019/03-ZeroTouch/assets/ZT-ExampleMapping.png
  • public staticインスタンスを返すメソッドは、Createノードとして表示されます。
  • publicメソッドは、Actionノードとして表示されます。
  • publicプロパティは、Queryノードとして表示されます。

HelloWorld

ノードのインプットに名前がつながれると、 Hello 名前 ! と出るような簡単なノードを作成してみましょう。Class1.csの名前を、HelloDynamo.csという名前に変更して、以下のコードを書きます。

namespace DynamoWorkshop
{
    public static class HelloDynamo
    {
        public static string SayHello(string Name)
        {
            return "Hello " + Name + "!";
        }
    }
}

デバック

Data-shapesやBimorphNodesパッケージが置かれているフォルダと同じところに自動でZeroTouchNodeパッケージが作成されるようにしていきます。ローカルパッケージとして設定することで、Dynamoが起動するたびに自動的にロードされるようにします。

Dynamoパッケージの構造

  • binフォルダには、C#またはゼロタッチライブラリで作成された.dllファイルが格納されます。これには、Json.NET、RestSharpなどのコードで参照する必要のある外部ライブラリが含まれます。
  • dyfフォルダには、カスタムノードが格納されます。
  • extraフォルダには、すべての追加ファイルが格納されます。これらのファイルは、Dynamo Files (.dyn) または必要な追加ファイル (.svg, .xls, .jpeg, .sat, etc.) である可能性が高いです。
  • pkg.jsonファイルには、パッケージの設定を定義する基本的なテキストファイルです。これはDynamoでも作成できますが、ここでは一から作成します。

プロジェクトを右クリック>追加>新しいアイテム…をクリックした後、Web> JSONファイルで、名前をpkg.jsonとして保存します。コードは以下をコピー&ペーストしてください。

{
  "license": "",
  "file_hash": null,
  "name": "DynamoWorkshop",
  "version": "1.0.0",
  "description": "",
  "group": "",
  "keywords": null,
  "dependencies": [],
  "contents": "",
  "engine_version": "2.3.0.5885",
  "engine": "dynamo",
  "engine_metadata": "",
  "site_url": "",
  "repository_url": "",
  "contains_binaries": true,
  "node_libraries": [
    "DynamoWorkshop, Version=2.3.0.5885, Culture=neutral, PublicKeyToken=null"
  ]
}

Dynamoパッケージフォルダーへのデプロイ

プロジェクトを右クリック> Properties> Build Events> Post-build event command line> 2次の行を貼り付けます。以下の2行はVisualStudioに、dllpkg.jsonをフォルダにコピーするよう指示します。

xcopy /Y "$(TargetDir)*.*" "$(AppData)\Dynamo\Dynamo Revit\2.3\packages\$(ProjectName)\bin\"
xcopy /Y "$(ProjectDir)pkg.json" "$(AppData)\Dynamo\Dynamo Revit\2.3\packages\$(ProjectName)"

ビルドを行い、Dynamoを開いてみると、新しいパッケージがロードされてライブラリに表示されるはずです。

階層

今のままではDynamoに表示される名称の階層が深すぎて見づらいです。bin/アセンブリ名_DynamoCustomization.xmlというファイルを作成することで回避できます。今回の場合は、DynamoWorkshop_DynamoCustomization.xmlですね。

<?xml version="1.0"?>
<doc>
  <assembly>
    <name>DynamoWorkshop</name>
  </assembly>
  <namespaces>
    <namespace name="DynamoWorkshop">
      <category>HelloWorld</category>
    </namespace>
  </namespaces>
</doc>
xcopy /Y "$(ProjectDir)DynamoWorkshop_DynamoCustomization.xml" "$(AppData)\Dynamo\Dynamo Revit\2.3\packages\$(ProjectName)\bin"

初級編02 複数の入力・出力を持つノードを作成しよう!

次は入力と出力が2つあるノードをそれぞれ作成していきましょう!入力が複数になる場合は簡単ですが、出力が複数ある場合は少し注意が必要です。まず入力が複数の時の書き方を見ていきましょう!

・入力を複数にする場合

ここでは2つの入力された値の平均値を出力するノードを作成します!
入力を複数にする書き方は簡単です。引数を複数にするだけです。非常に簡単!!!!!!!!

public static double AverageNumbers(double Number1, double Number2)
 {
     return (Number1 + Number2) / 2;
 }

・出力を複数にする場合

ここでは数値のリストの入力に対して、偶数と奇数に出力を分けるノードを作成していきます!
複数の値を返すのは少し注意が必要です。

  • 最初にusing Autodesk.DesignScript.Runtime;ディレクティブが必要です
  • 次にMultiReturn関数に属性を追加する必要があります
  • 最後に、出力を保存するための辞書を作成します

リファレンスの追加

次にDynamoのジオメトリノードを使えるようにするために、ライブラリを取得します。
プロジェクト名上で右クリックし、NuGetパッケージマネージャーをクリックします。

DynamoVisualProgramming.ZeroTouchLibraryと検索すると下記の画像のように2つ出てくるので片方どちらもインストールしましょう!
バージョンは使っているDynamoのバージョンに合わせます。私はRevit2020.2を使用しているのでDynamのバージョンは2.3.0.5885になります。

インストールされるとDynamoServicesDynamoUnitsProtoGeometryが追加されます。パッケージ内に不要なファイルがコピーされるのを避けるため、それらを選択して、下のプロパティのCopyLocalをFalseにしましょう!

[MultiReturn(new[] { "evens", "odds" })]
        public static Dictionary<string, object> SplitOddEven(List<int> list)
        {
            var odds = new List<int>();
            var evens = new List<int>();

            //check integers in list if even or odd
            foreach (var i in list)
            {
                if (i % 2 == 0)
                {
                    evens.Add(i);
                }
                else
                {
                    odds.Add(i);
                }
            }

            //create a new dictionary and return it
            var d = new Dictionary<string, object>();
            d.Add("evens", evens);
            d.Add("odds", odds);
            return d;

            //the above can be simplified in one line with
            //return new Dictionary<string, object> { { "evens", evens }, { "odds", odds } };       
        }

初級編03 DynamoのGeometryライブラリにアクセスしよう!

using Autodesk.DesignScript.Geometry;をusing ディレクティブに追加すると、DynamoのGeometryライブラリにアクセスできるようになります!

ただし注意が必要です。外部リソースを使用する場合、使い終わったら Dispose()またはusingステートメントを呼び出してリソースを開放する必要があります。関数で作成する各ジオメトリオブジェクトはDynamoリソースを使用するため、破棄する必要があります。

public static Line ByCoordinates(double X1, double Y1, double Z1, double X2, double Y2, double Z2)
{
  var p1 = Point.ByCoordinates(X1, Y1, Z1);
  var p2 = Point.ByCoordinates(X2, Y2, Z2);
  var l = Line.ByStartPointEndPoint(p1, p2);
  p1.Dispose();
  p2.Dispose();
  return l;
}

参考

https://teocomi.com/dynamo-unchained-1-learn-how-to-develop-zero-touch-nodes-in-csharp/

https://qiita.com/Takashi_Kasuya/items/49bd3775443f43fb1796

https://alvpickmans.github.io/DynamoDevelopment-London-Hackathon-2019/