vicc blog

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

Rhino8のレイヤー自動色分け機能をRhino7で再現してみた

こんにちは、篠原です。

Rhino8では、レイヤーを新しく作成したときに自動で色が割り当てられる機能が追加されました。
レイヤーを整理するうえで地味に便利なこの機能をつかうと、色の違いで視認性が上がり、ちょっとした手間も省けます。

しかしながら、Rhino7以前にはこの機能はありません。
Rhino7以前を使わざるを得ない環境でも、「このくらいの機能なら、自分でも作れるのでは?」と思ったのが、この記事の出発点です。

本記事では、RhinoCommon*1のイベント処理を使って、Rhino7でも同様の動作を再現する方法を紹介します。
Python に少しでも触れたことがあれば大丈夫で、「自分で Rhino をちょっと便利にしてみたい」という方に向けた内容です。

準備

まずはRhinoを開き、EditPythonScriptコマンドを実行しましょう。Pythonエディターがポップアップします。
理由は後述されますが、バージョンはRhino5からRhino7としましょう。

ここにPythonスクリプトを書き加えていくことになります。

次にスクリプトの大枠を考えます。

機能としては次の3つあります。

  1. ランダムな色を作成する機能
  2. レイヤにその色をあてはめる機能
  3. 上記の機能を、レイヤ新規作成時に割り込ませる機能

では実際に作っていきます。

1. ランダムな色を作成する機能

createRandomColorというメソッドを作成します。実行するたびにランダムな色が生成されます。

from System.Drawing import Color
import random

def createRandomColor():
    return Color.FromArgb(
        random.randint(0, 255),
        random.randint(0, 255),
        random.randint(0, 255)
    )

color = createRandomColor()
print(color)

2. レイヤにその色をあてはめる機能

modifyLayerColorというメソッドを作成します。layerという引数の色をランダムな色にします。

# -*- coding: utf-8 -*-
import random
from System.Drawing import Color
import Rhino.DocObjects

# 1で作成したメソッド
def createRandomColor():
    return Color.FromArgb(
        random.randint(0, 255),
        random.randint(0, 255),
        random.randint(0, 255)
    )

def modifyLayerColor(layer):
    layer.Color = createRandomColor()

3. 上記の機能を、レイヤ新規作成時に割り込ませる機能

RhinoCommonのLayerTableEventというイベント*2を利用します。

LayerTableEventはRhinoがレイヤに関する処理を実行する一連の処理を司るので、その中に自作メソッドを割り込ませることができます。
割り込ませ方:LayerTableEvent += (自作メソッド)

RhinoCommonのリファレンスによると、LayerTableEventはRhino5.0から利用可能とのことです(Available since: 5.0)。

RhinoCommonのリファレンスより
https://developer.rhino3d.com/api/rhinocommon/rhino.rhinodoc/layertableevent

LayerTableEvent周辺の情報で、以下のフローをRhinoCommonの言葉に置き換えましょう。

Before
  1. レイヤ処理が実行された
  2. その処理はレイヤ新規作成である(そうである場合に以下を実行)
  3. その処理の対象レイヤにランダムな色をあてはめる
After
  1. LayerTableEventを購読*3するメソッドでLayerTableEventArgsを取得
  2. LayerTableEventArgsEventTypeを確認し、Addedであれば以下を実行
  3. LayerTableEventArgsNewStateに対してmodifyLayerColorメソッドを実行

RhinoCommonのリファレンスより
https://developer.rhino3d.com/api/rhinocommon/rhino.docobjects.tables.layertableeventargs) (https://developer.rhino3d.com/api/rhinocommon/rhino.docobjects.tables.layertableeventtype

以下、すべてをまとめたスクリプトです。

# -*- coding: utf-8 -*-
import scriptcontext as sc
import Rhino
import random
from System.Drawing import Color
from Rhino.DocObjects.Tables import LayerTableEventType

# 1で作成したメソッド
def createRandomColor():
    return Color.FromArgb(
        random.randint(0, 255),
        random.randint(0, 255),
        random.randint(0, 255)
    )

# 2で作成したmodifyLayerColorにあたるメソッドです(詳しくは後述)
def on_layer_event(sender, e):
    if e.EventType == LayerTableEventType.Added:
        layer = e.NewState
        layer.Color = createRandomColor()

def subscribe_layer_event():
    if sc.sticky.get("layer_event_handler"):
        return
    sc.doc.LayerTableEvent += on_layer_event
    sc.sticky["layer_event_handler"] = on_layer_event

subscribe_layer_event()

2では、modifyLayerColorというメソッドを使っていましたが、このコードではon_layer_eventとしています。
LayerTableEventを購読する*4メソッドとして、EventTypeで条件分岐したうえで対象のレイヤに対するmodifyLayerColor処理を内包しています。

スクリプト実行後、新規レイヤ作成時にRhino7でもレイヤのランダム配色ができました。

おわりに

Rhino 8 で搭載された便利機能も、RhinoCommon を使えば Rhino 7 以前の環境でもある程度再現できます。
今回はレイヤー自動色分けをつくりましたが、オブジェクト追加や削除、ビュー変更など、Rhino 内のさまざまな動作に対して反応できるのがイベント処理の面白いところです。

Python 初学者でも、簡単なコードで Rhino の操作性を向上させることができます。
ちょっとした便利機能を自作してみることで、Rhino との距離がぐっと近づくはずです。

*1:RhinoCommonに関して過去記事があります。blog.vicc.jp

*2:イベントとは、指定の処理を実行する一連の処理です。
UIの設計で頻繁に扱われ、例えば、ボタンをクリックしたときの一連の処理をButtonClickというイベントにまとめます。
イベント処理について詳しく知りたい方は、以下の記事をお勧めします。
Pythonでイベントをわかりやすく解説している記事がなかったので、C#記事になります。 qiita.com

*3:購読はイベントの重要な処理で、イベント処理時に購読するメソッドが実行されます。詳しくはイベントを確認してください。

*4:subscribe_layer_eventメソッドで使用しているscriptcontext (sc) は、メソッドをsticky に保持しないとイベントが発火しないため使用しています。
IronPythonでは登録後すぐに関数が破棄されるためです。 discourse.mcneel.com