vicc blog

株式会社ヴィックの技術ブログです。

rhino3dm ライブラリを触ってみた(前編)

諸般の事情があり、Rhinoceros のローカルのアプリケーションだけではなく、様々な環境で 3D モデルやファイルを弄る方法を調べています。その中で rhino3dm というライブラリをちょっと触ってみたので記録として記事を書いてみます。

rhino3dm ライブラリとは

公式サイトによると下記のように紹介されています。

rhino3dmは、RhinoCommonスタイルのopenNURBSジオメトリライブラリを基にしたライブラリのセットです

www.rhino3d.com

このライブラリは、Rhino のアプリケーションと完全に切り離されており、Rhino のアプリやライセンスが要りません。Rhino のアプリと切り離されているのでおそらく Linux 環境でも動作します(筆者は未検証)。 また、リモートサーバに問い合わせる必要もありません。 rhino3dm ライブラリ単独でちょっとした Rhino のモデルやファイルの操作が可能です。

Rhino そのものの開発思想と、提供されているこちらのライブラリにより、通常は 3D CAD のみで操作できるネイティブファイルを、3D CAD 関与なしの自前のプログラムから簡単に触ることができるという環境が提供されておりに非常に面白いです。

自由にどこでも動かしやすい反面、ブーリアン演算のようなリッチな処理はほぼできません。そのあたりが Rhino.insideRhino Compute といった技術とは明確に異なるようです。

今回の記事では、しばらく取り組んでいた rhino3dm の実験からいくつか簡単な作例を紹介します。

ちょっとした作例

rhino3dm は、JavaScript / Python / .Net の環境で、MIT ライセンスとしてライブラリが提供されています。

筆者は Python を使うことが多いので、今回も Python で触ってみます。 詳細は下記のページを参照してください。

rhino3dm PyPI
https://pypi.org/project/rhino3dm/

rhino3dm.py API Documentation
mcneel.github.io

注)Rhino のアプリケーションに含まれる IronPython ではなく、CPython が必要です。必要に応じてセットアップしてください。

環境は下記の通りです。

  • Windwos11
  • Python 3.12.2
  • rhino3dm 8.9.0

また、下記の作例はすべて MIT ライセンスとします。

ボックスを作り、新規 3dm ファイルとして保存する

Hello, World! 的な気持ちで、ボックスを作って保存してみます。

# -*- coding: utf-8 -*-
import rhino3dm

def create_box_and_save(file_path):
    
    # Rhino3dm のモデルを作成
    my_file = rhino3dm.File3dm()
    
    # ボックスのコーナーポイントを定義
    min_corner = rhino3dm.Point3d(0, 0, 0)
    max_corner = rhino3dm.Point3d(10, 10, 10)
    
    # ボックスの作成
    box = rhino3dm.Box(rhino3dm.BoundingBox(min_corner, max_corner))

    # ボックスを Brep に変換
    brep = rhino3dm.Brep.CreateFromBox(box)

    # モデルにボックスを追加
    my_file.Objects.AddBrep(brep)

    # ファイルを保存
    my_file.Write(file_path, 7)
    print(f"*** File Saved: {file_path}")

# 保存するファイル名
output_file = "C:\\Users\\naoki yoshioka\\Desktop\\box_v1.3dm"
create_box_and_save(output_file)
   

実行すると、ライノファイルが作成されます。

powershell の画面。print() の結果が1行表示される。

Rhino で開いて見るとこんな感じ。

ライノで開いた変哲の無いボックス。

ボックスを作り、レイヤーを指定し属性情報を入れて保存する

ボックスを作って保存するだけだと意味がないので、レイヤーの設定や属性情報を設定してみます。

# -*- coding: utf-8 -*-
import rhino3dm

def create_box_and_save(file_path):
    
    # Rhino3dm のモデルを作成
    my_file = rhino3dm.File3dm()
    
    # ボックスのコーナーポイントを定義
    min_corner = rhino3dm.Point3d(0, 0, 0)
    max_corner = rhino3dm.Point3d(10, 10, 10)
    
    # ボックスの作成
    box = rhino3dm.Box(rhino3dm.BoundingBox(min_corner, max_corner))

    # ボックスを Brep に変換
    brep = rhino3dm.Brep.CreateFromBox(box)

    # レイヤーを作成
    layer = rhino3dm.Layer()
    layer.Name = "New Layer 1"
    layer.Color = (255, 0, 0, 255)
    my_file.Layers.Add(layer)

    # レイヤーを作成(2)
    layer = rhino3dm.Layer()
    layer.Name = "New Layer 2"
    layer.Color = (0, 255, 0, 255)
    my_file.Layers.Add(layer)

    # 属性情報を作成
    attribute = rhino3dm.ObjectAttributes()
    attribute.SetUserString("Create", "Yoshioka")
    
    # レイヤーを指定
    # ここでは 0 = "New Layer 1", 1 = "New Layer 2"
    attribute.LayerIndex = 1

    # モデルにボックスを追加
    my_file.Objects.Add(brep, attribute)

    # ファイルを保存
    my_file.Write(file_path, 7)
    print(f"*** File Saved: {file_path}")

# 保存するファイル名
output_file = "C:\\Users\\naoki yoshioka\\Desktop\\box_v2.3dm"
create_box_and_save(output_file)

実行すると、ライノファイルが作成されます。PowerShell の画像はほぼ同じなので割愛します。

Rhino で開いて見るとこんな感じ。

ライノで開いたボックス。レイヤーを指定し、属性情報も記入済み。

ボックスを作り、レイヤーを指定し属性情報を入れて保存する(複数)

後編の記事でファイルを読み込み属性情報を変更するということを紹介する予定です。その下準備としてオブジェクトが複数入ったライノファイルを作成します。

# -*- coding: utf-8 -*-
import rhino3dm

def create_layers(my_file, count):

    # 複数のレイヤーを作成する
    # レイヤーカラーはグラデーションになるようにする

    # 色のグラデーション作成用
    step_color = int(255 / (count+1))
    # print(step_color)

    for i in range(count):

        # レイヤーを作成
        layer = rhino3dm.Layer()
        layer.Name = "New Layer {}".format(str(i).zfill(2))

        layer.Color = ((i * step_color), 0, 255 - (i * step_color), 255)
        my_file.Layers.Add(layer)


def create_boxes(my_file, count):
    
    # ボックスのサイズ
    step_box_size = 5

    for i in range(count):

        pt = step_box_size * 2 * i

        # ボックスのコーナーポイントを定義
        min_corner = rhino3dm.Point3d(pt, 0, 0)
        max_corner = rhino3dm.Point3d(pt + step_box_size, step_box_size, step_box_size)
    
        # ボックスの作成
        box = rhino3dm.Box(rhino3dm.BoundingBox(min_corner, max_corner))

        # ボックスを Brep に変換
        brep = rhino3dm.Brep.CreateFromBox(box)


        # 属性情報を作成
        attribute = rhino3dm.ObjectAttributes()
        attribute.SetUserString("Create", "Yoshioka")

        # 属性情報としてインデックスを追加
        attribute.SetUserString("Index", str(i))
    
        # レイヤーを指定
        attribute.LayerIndex = i

        # モデルにボックスを追加
        my_file.Objects.Add(brep, attribute)


# Rhino3dm のモデルを作成
my_file = rhino3dm.File3dm()

# ボックスの個数
count = 10

# レイヤーを作成
create_layers(my_file, count)

# レイヤーを確認
layers = my_file.Layers
for l in layers:
    print("{} : {} : {}".format(l.Index, l.Name, l.Color))

# ボックスを作る
create_boxes(my_file, count)

# 保存するファイル名
output_file = "C:\\Users\\naoki yoshioka\\Desktop\\box_v3.3dm"

# ファイルを保存
my_file.Write(output_file, 7)
print(f"*** File Saved: {output_file}")

実行すると、ライノファイルが作成されます。PowerShell の画像はほぼ同じなので割愛します。

ライノで開いて見るとこんな感じ。

ライノで開いたボックス。レイヤーを指定し、属性情報も記入済み。(複数)

ここまで Python + rhino3dm の紹介として、オブジェクトを作り、属性情報を追加し、ファイルを新規保存をするということをやってみました。

冒頭で書いたような、通常は 3D CAD のみで操作できるネイティブファイルを、3D CAD 関与なしの自前のプログラムから簡単に触ることができるという面白ポイントについて少しでも伝わりましたでしょうか。

今回はここまでで後編へ続きます。後編ではファイルを開いて属性情報の更新を行うなどを紹介する予定です。

(補足)

属性情報という言葉を紹介なく使っていますが、詳しくはこちらを確認ください。
blog.vicc.jp

(参考)

hiron さんをはじめとした先人が書き残したものを辿って様々な情報を得ることができました。偉大な先人に感謝します。

hiron.dev