Rhinoceros x Pythonで3Dデータの分析をしよう（環境構築編）

# はじめに
仕事を通じてRhinocerosとPythonを使って3Dデータを分析する機会がありました。色々面白いことができるのですが、ネット上に情報が少なく苦労した割に今後同じような分析をする機会も少なそうなので、学んだことを記事にして多くの人に参考にしてもらえればと思ってこの記事を書きました。Plateauというオープンな日本の都市の3Dデータを題材に分析のための環境構築と分析の事例を紹介します。
この記事ではまず環境構築とRhinoceros上でのPythonの動作確認までをご紹介します。

# Rhinocerosとは
Rhinocerosについての詳細については[公式サイト](https://www.rhino3d.co.jp/)や各種専門書を参考にしてもらえればと思いますが、[NURBS](https://ja.wikipedia.org/wiki/NURBS)というモデルの表現が得意なタイプの3DCADソフトで、工業デザインや機械設計、建築などに使用されています。

Rhinocerosでは基本的にはGUIを使用して3Dモデリングを行うことが想定されていますが、C#やPythonのAPIが公開されておりプログラミングで3Dモデリングをすることもできます。Rhinocerosは3Dデータのオブジェクトの位置関係や大きさなどを捉えることが得意なので、本記事はそこから3Dデータの分析をしようというものです。

# 環境構築 

## Rhinocerosのインストール
[公式サイト](https://www.rhino3d.com/jp/download/)からRhinocerosのインストールをしましょう。筆者は仕事では商用版を使用しましたが、この手の3DCADツールはそれなりにお値段するのでとりあえず触ってみようという方はまずは評価版を使用すると良いと思います。

自分の環境に合わせたRhinocerosを選択すると次のような画面になるので、ボタンをクリックしてRhinoアカウントを作成します。

![ダウンロード画面1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178986/232d1d71-3676-1aeb-92bb-2fc25c4af4c1.png)

プライバシーポリシーに同意するにチェックしてソフトをダウンロードしながらライセンスキーをメモしておきましょう。

![ダウンロード画面2](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178986/bed13c73-8a57-67c5-49cf-7ab0f548df93.png)

ダウンロード完了後はRhinoアカウントのメールアドレスを入力してアカウントの認証します。

![ログイン画面1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178986/8cfbed48-2c83-3911-f4fa-dd85e61aa385.png)

その後先程のライセンスキーを入力します。複数PCで使用する場合やバリデーション画面が出てきます。これらについては使用PCに限定と登録スキップで問題ないです。
こちらのトップ画面までたどり着けばOKです。

![トップ画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178986/2e394e43-5d5a-6fc7-1713-17d081a3ed57.png)

## Rhinoceros x Pythonの開発環境

### Rhinoceros上で開発する
Rhinoceros x Pythonの開発を進めるときにRhinoceros上でPythonコードを書いて実行することができます。
[タブ] > [ツール] > [スクリプト] > [編集]
からスクリプトエディタを開きます。

![スクリプトエディタ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178986/218c8b16-6a2a-0104-7bd7-a2c6345f9c2b.png)

デフォルトではIronPython(Python2系)の環境になっていますが、[ファイル] > [新規作成]から新しいスクリプトの種類を選ぶことができ、C#、Python3、IronPythonから選ぶことができます。
ブレークポイントの設定など簡易的なデバッグ機能もついています。

### VSCodeで開発する
Rhino8のエディタはコード補完などやUIの見た目的にもかなり使いやすくなっていますが、（個人的には）Rhino7のエディタは使いづらかったです。
しかしRhinoceros上でないとRhinocerosのAPIを利用できません。そこでVSCodeにはRhinoPythonという拡張機能があり、それを使うと
VSCode上でRhinocerosのコードを動かすことができます。

![RhinoPython](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178986/e983edd2-a713-8eb7-1ef8-64030f54c25c.png)

セットアップ方法は拡張機能のページの[Installation]の通りですが、[food4rhino](https://www.food4rhino.com/en/app/code-listener)のページからCodeListnerという機能をダウンロードする必要があります。無料です。

簡単な使い方は以下の通りです。
1. Rhinocerosを起動しCommandからCodeListnerと入力
2. VSCodeにRhinoceros上で動かしたいスクリプトを作成
3. ファイルを選択した状態でF2を実行する

これでスクリプトエディタで実行した状態と同じ結果が画面上に得られます。
Rhinocerosの3Dモデルの処理だけであればスクリプトエディタ上でも良いですが、その他Rhinocerosと関係ないスクリプトやシステムなどと組み合わせたい場合はすべてをRhinoceros上で開発するのは大変なのでこちらを使ってみると良いと思います。

※RhinoPythonはRhino5/6に対応と書かれており、Rhino7でも動作します。また筆者が試した限りでは同じ設定でRhino8でも動作するようですが、厳密な動作保証はできかねますのでご了承ください。

## 動作確認

### 簡単なモデルを作成するスクリプトの実行
各エディタが使えるようになったら、簡単な3Dモデルを作成するスクリプトを実行してみましょう。

今回はRhinocerosのスクリプトエディタを使ってみます。
ファイル・新規作成からExample1.pyを新規作成をするとサンプルコードが作られた状態でファイルが用意されます。

```python:Example1.py
#! python 3
import rhinoscriptsyntax as rs

rs.MessageBox("Hello World")

centerpoint = [1.0, 2.0, 4.0]
rs.AddCircle(centerpoint, 5.0)

startPoint = [1.0, 2.0, 0.0]
endPoint = [4.0, 5.0, 0.0]
line1 = [startPoint, endPoint]

line1ID = rs.AddLine(line1[0], line1[1])

startPoint2 = [1.0, 4.0, 0.0]
endPoint2 = [4.0, 2.0, 0.0]
line2 = [startPoint2, endPoint2]

line2ID = rs.AddLine(line2[0], line2[1])

llinter = rs.LineLineIntersection(line1ID, line2ID)

print(llinter)
```

上記のスクリプトを実行すると画像のようなモデルが作成されると思います。

![実行結果](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/178986/b0315c7a-8bf2-bcb6-0162-76f1bef902a6.png)

### スクリプトの説明

前提知識を踏まえながら上記のスクリプトの説明をします。

#### RhinocerosのPythonAPIについて

PythonからRhinocerosを操作するにはRhinocerosのPython用APIを使用する必要があります。主に2つをよく使います。
- [RhinoCommonAPI](https://developer.rhino3d.com/api/rhinocommon/?version=8.x)
  - Rhinoについて基本的な操作ができるもので、どのような操作でもできます。ただし中身のクラスの役割や仕組みを理解する必要があり、少し難しいです。
- [RhinoScriptSyntax](https://developer.rhino3d.com/api/RhinoScriptSyntax/)
  - RhinocerosのGUIで操作できるような処理がメソッドとして呼び出せるようになっています。GUIDというオブジェクトのユニークなIDを使用して、モデルファイルを編集していく特徴があります。都度描画されるため若干処理が遅くなる特徴があります。

基本的にはRhinoScriptSyntaxで目的の処理を実装し、極端に処理が遅いとかやりたい操作ができない場合にRhinoCommonを使うというのが良いと思います。
Example1.pyではこちらのrhinoscriptsyntaxが使われています。

#### 各メソッドについて

上記のスクリプトでは以下のメソッドが使われています。

- `rs.MessageBox("Hello World")`
  - Hello Worldと書かれたメッセージボックスを表示します。
- `rs.AddCircle(centerpoint,5.0)`
  - centerpointを中心に半径5.0の円のカーブを作成します。
- `rs.AddLine(line1[0],line1[1])`,`rs.AddLine(line2[0],line2[1])`,
  - 始点と終点に向かってそれぞれ線を書きます。また返り値にguidというオブジェクトのIDが返ってきています。
- `rs.LineLineIntersection(line1ID,line2ID)`
  - 線の描画時に取得したIDを用いて、それぞれの線を取得し、もしそれらが交差する場合は交差する点を作成しています。
  - 返り値は(1本目の線上の交差した点、2本目の線上の交差した点)のtuple形式です。
  - こちらの点はRhino.Geometry.Point3dのオブジェクトとして作成されており、描画したい場合ばrs.AddPointなどを実行する必要があります。

以上のようなメソッドを使うことでモデルを作成したり、あるいはオブジェクト同士が干渉しているか？という情報を得ることができます。


# まとめ

本記事の内容でRhinocerosをインストールしPythonコードをRhinoceros上で実行して動作を確認するということはできたかと思います。ここからRhinocerosの3DモデリングをPythonでやってみたい方は以下の参考資料に上げたようなものを読んでいただくとより理解が深まると思います。
次回の記事はPlateauのデータを使用し、Pythonを用いた3Dデータの簡単な分析事例をご紹介します。

# 参考資料

- 書籍
  - [Rhinoceros×Python コンピュテーショナル・デザイン入門](https://www.amazon.co.jp/Rhinoceros%C3%97Python-%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%86%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%8A%E3%83%AB%E3%83%BB%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E5%85%A5%E9%96%80-%E4%B8%89%E4%BA%95%E5%92%8C%E7%94%B7/dp/439532083X)
  - [建築設計者のためのRhinoceros](https://www.amazon.co.jp/%E5%BB%BA%E7%AF%89%E8%A8%AD%E8%A8%88%E8%80%85%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AERhinoceros-%E3%80%90Rhino7%E5%AF%BE%E5%BF%9C%E3%80%91-%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%83%A9%E3%83%9C/dp/4296110845)
    - 建築ドメイン向けではありますが、Rhinocerosの各GUIのコマンドについてオブジェクト付きで説明されています。実際にモデリングや分析を行う際にはRhinocerosのコマンドを直接呼び出すこともあるので、Rhinoceros自体の操作を理解しておくと良いと思います。
- サイト
  - [RhinoScriptSyntaxAPI Documentation](https://developer.rhino3d.com/api/RhinoScriptSyntax/)
  - [RhinoCommonAPI Documentation](https://developer.rhino3d.com/api/rhinocommon/?version=8.x)
  - [Mcneel Forum](https://discourse.mcneel.com/)
    - 英語のコミュニティですが、システム仕様の質問などに答えてくれたりバグの修正を対応してもらえたりします。