Dynamo Zero Touch Nodeことはじめ

# Zero Touch Node(ZTN)とは
Dyanamoでは、洗練されたビジュアルプログラミングを楽しむことができるのですが、スクリプト環境についていうと、DesignScriptというDSLや、Iron Pythonが使えるのみで、事前に用意されたライブラリ以外は使うことができません。Autodesk Revitと連携させて形状を作るするだけであれば問題ありませんが、システム連携などを考慮すると貧弱に感じます。
Dynamoでは、Zero Touch Node(ZTN)と呼ばれるカスタムノードを開発することが可能です。ちょうどRevitでアドインを開発するように、C#で作ったDLLをDynamoに取り込むことができます。ついでに一般的にはPython Scriptで書くより速いようです。公式のドキュメントは[ここ](https://github.com/DynamoDS/Dynamo/wiki/Zero-Touch-Plugin-Development)です。

**しかし、関連ドキュメント少なすぎやしませんか、、、**

# 準備
## プロジェクト新規作成
Visual Studio Community 2017を使って開発します。新しいプロジェクト（クラスライブラリ .NET Framework）を選択します。.NET Framworkのバージョンは4.8としました。
次にNuGetパッケージマネージャーを使って、以下のようにDynamoの開発に必要なライブラリをインポートします。`DyanamoVisualProgramming.ZeroTouchLibrary`だけで大丈夫です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51703/62056fe5-82c7-71e7-0978-ee27976c3259.png)

`DynamoServices`、`DynamoUnits`、`PhotoGeometry`の3つが追加されています。これらをプロパティを選択して、「ローカルにコピー」をFalseにすると不要なパッケージがパッケージに含まれるのを防ぐことができるそうです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51703/02b33700-fafb-d833-0a39-80a1c2785d2c.png)

## デバッグ環境の整備
開発したZTNをデバッグするためには、毎回出力したDLLを手動でDynamoに読み込ませる必要があります。面倒なので、Visual Studioから起動できるようにしておきます。以下の手順で行います。

1. パッケージ情報(pkg.json)の作成
2. ビルド後に必要ファイルを自動コピーするように設定
3. デバッグ用の外部アプリケーションを指定

pkg.jsonは作成したカスタムノードのメタデータを記述するファイルです。Dynamoで自分でカスタムノードを作る場合は、自動生成されるものです。具体的には、以下のように記述します。

```pkg.json
{
  "license": "",
  "file_hash": null,
  "name": "HelloWorldZeroTouch",
  "version": "1.0.0",
  "description": "Hello world for ZeroTouchNode",
  "group": "",
  "keywords": null,
  "dependencies": [],
  "contents": "",
  "engine_version": "1.0.0",
  "engine": "dynamo",
  "engine_metadata": "",
  "site_url": "",
  "repository_url": "",
  "contains_binaries": true,
  "node_libraries": [
    "HelloWorldZeroTouch, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
  ]
}
```

続いて、ビルドした後のdllなどをDynamoが起動時に読み込むフォルダに自動配置するようにします。自動的に読み込むフォルダは、使っているDynamoによって違います。Dynamoメニューの`設定 -> ノードとパッケージのパスを管理`で当該フォルダを確認してください。プロジェクトの`プロパティ -> ビルドイベント -> ビルド後イベントのコマンドライン`に以下を入力します。以下は、Dynamo Revit 2.0の場合の設定例です。

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

次に、同じくプロジェクトのプロパティから、`デバッグ -> 外部プログラムの開始(X)`に`C:\Program Files\Autodesk\Revit 2019\Revit.exe`と入力します。デバッグに利用するプログラムのパスを書き込むわけですが、ここも環境によって適宜変更してください。

# 開発
## エントリポイントの開発
ここでようやくZTN開発ということですが、特に難しいことはなくて、`public static`なメソッドを定義すればいいだけです。メソッド引数がノードへの入力になります。例えば以下の例では、Nameという文字入力をとって、固定文字を追加して出力とします。


``` HelloDynamo.cs
namespace HelloWorldZeroTouch
{
    public class HelloDynamo
    {
        public static string SayHello(string Name)
        {
            return "Hello " + Name + "!";
        }
    }
}
```

出力を複数にしたい場合は、`Dictionary`をreturnすればよい。この辺は[サンプルコード](https://developer.dynamobim.org/07-Examples/7-0-examples.html)がいくつかあるので、そこから学ぶのが良いと思います。Nodeの中にGUIを作れたりして、実にいろんな拡張が可能です。

ちなみに、Dynamo 2.0で追加になったDictionary型を使うためには、System.Collections.IDictionaryを使います。

## ノードの名称
上記のままでも使えるのですが、Dynamoに表示される名称の階層が深くてかっこ悪いです。これはアセンブリ名とC#のNamespaceから自動生成されています。これを変更する手段としては、パッケージフォルダ内に`bin/アセンブリ名_DynamoCustomization.xml`というファイルを設置することで実現できます。このファイルのコピーもビルド時の挙動に組み込んでおくとよいでしょう。今回の場合は、`HelloWorldZeroTouch_DynamoCustomization.xml`ですね。

```HelloWorldZeroTouch_DynamoCustomization.xml
<?xml version="1.0"?>
<doc>
  <assembly>
    <name>HelloWorldZeroTouch</name>
  </assembly>
  <namespaces>
    <namespace name="HelloWorldZeroTouch">
      <category>HelloWorld</category>
    </namespace>
  </namespaces>
</doc>
```
そうすると以下のように読み込まれるのが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51703/bac32900-ac29-a145-df9c-faa7dbec4683.png)

# 参考
1. [Dynamo Unchained 1: Learn how to develop Zero Touch Nodes in C#](http://teocomi.com/dynamo-unchained-1-learn-how-to-develop-zero-touch-nodes-in-csharp/)
2. [Dynamo Scripting Reference](https://primer.dynamobim.org/13_Best-Practice/13-3_Scripting-Reference.html)
3. [Become a Dynamo Zero Touch C# Node Developer in 75 Minutes](https://bimorph.com/become-a-dynamo-zero-touch-node-developer-in-75-minutes/)
4. [Zero Touch Plugin Development](https://github.com/DynamoDS/Dynamo/wiki/Zero-Touch-Plugin-Development)
5. [Dynamo 2.0 Language Changes Explained](https://github.com/DynamoDS/Dynamo/wiki/Dynamo-2.0-Language-Changes-Explained)