Rhinocerosの ブロックインスタンスの座標を取得する

仕事で 3DCADソフトのRhinocerosで作った街のデータを扱うことが出たものの
データのエクスポートでブロックインスタンスで複製してあるオブジェクトが実体化されてしまって
大容量データになってしまっていたので Rhino上でインスタンスの座標を取得する方法を調べたメモ


Rhinocerosの基本操作も把握してない状態で初めたものの
アウトライナのような　全体のオブジェクトを把握できるようなものは見当たらない様子で
オブジェクトの座標を見るにも操作が煩雑な様子なのでスクリプトでできないか調べることに
幸いにもPythonが使えるらしい

rhinoscriptsyntax　と　Rhino　のライブラリを利用するらしいので
軽くdir()で属性を眺めた後に参考のスクリプトを検索してみた


``` py:blockinstance_position.py
# -*- coding: utf-8 -*-
import rhinoscriptsyntax as rs
import Rhino
blocks = Rhino.RhinoDoc.ActiveDoc.Objects.FindByObjectType(Rhino.DocObjects.ObjectType.InstanceReference)
for block in blocks:
    print(block.InstanceDefinition.Name) #インスタンス元の識別名
    print(block.InsertionPoint) #ブロックインスタンスのある座標
    print(rs.BlockInstanceXform(block)) #インスタンスの変換マトリクス
```
rhinoscriptsyntax はrsとして読み込むのが伝統になってるらしい？
とりあえず必要なデータは取得できたのだけれど
オブジェクトの種類でフィルタして一覧取得できるのはいいけど　参考にしたこの取得法では煩雑

また、BlockInstanceXformで取得できる変換マトリクス
>R0=(1,0,0,2043.06350946135), R1=(0,1,0,-829.999999999735), R2=(0,0,1,294.919991230696), R3=(0,0,0,1)
な具合。

まずブロックインスタンスの取得を別の書き方で試してみた
``` py:
blocks=rs.ObjectsByType(4096)
for block in blocks:
    print(block.InstanceDefinition.Name)
    print(rs.BlockInstanceXform(block))
```
オブジェクトタイプにはIDが割り振られているらしい。　一見これで動くかと思いきや
>Message: 'Guid' object has no attribute 'InstanceDefinition'

のエラーが出る　ObjectsByTypeで取得できるのはオブジェクトそのものでなくて　オブジェクトのGUIDらしい。
参考にしたスクリプトにもあった　rs.BlockInstanceXform(block)　の部分はこのままで動くからややこしい。
``` py:
rhobj = doc.Objects.Find(block)
print(rhobj.InstanceDefinition.Name)
```
といった具合にGUIDからオブジェクトを取得した
冒頭の書き方とどちらがいいのかは不明


```py:rhino_blockinstance_data.py
import rhinoscriptsyntax as rs
import Rhino
doc = Rhino.RhinoDoc.ActiveDoc
block_IDs=rs.ObjectsByType(4096)

for block_ID in block_IDs:
    rhobj = doc.Objects.Find(block_ID)
    obj_name = rhobj.InstanceDefinition.Name
    mat = rhobj.InstanceXform
    objdata = [obj_name, 
        mat.M00, mat.M01, mat.M02, mat.M03, 
        mat.M10, mat.M11, mat.M12, mat.M13, 
        mat.M20, mat.M21, mat.M22, mat.M23, 
        mat.M30, mat.M31, mat.M32, mat.M33]
    print (objdata)
```
InstanceXformでは先の　rs.BlockInstanceXform()同様　変換マトリクスの情報がテキストとして取得できるのだけれど
リストやタプルで取得する方法は不明　M00といった具合で個々の要素は取得できるし
今回欲しかったのはこのデータ自体なので　コードとしては美しくないけど　ここまで。

補足：
Blenderにこのインスタンスのオブジェクトをデータとして書き出した上で
コレクションに収めて　コレクションインスタンスとして配置したい場合のスクリプトのメモ
```py
import bpy
from mathutils import Matrix

def set_collection_instance(instance_data):
    for D_ in instance_data:
        bpy.ops.object.collection_instance_add(collection='collevtion_name', align='WORLD', location=(0, 0, 0), scale=(1, 1, 1))
        matrix_ = Matrix(((D_[1], D_[2], D_[3], D_[4]),(D_[5], D_[6], D_[7], D_[8]),(D_[9], D_[10], D_[11], D_[12]),(D_[13], D_[14], D_[15], D_[16])))
        bpy.context.active_object.matrix_basis = matrix_
        
"""#参考　コレクションインスタンスの作成
source_collection = bpy.data.collections["the_name_of_the_collection_to_use"]
instance_obj = bpy.data.objects.new(
    name="my_new__obj_instance_name", 
    object_data=None
)
instance_obj.instance_collection = source_collection
instance_obj.instance_type = 'COLLECTION'
parent_collection = bpy.context.view_layer.active_layer_collection
parent_collection.collection.objects.link(instance_obj)
"""
instance_data = []
set_collection_instance(instance_data)
```