仕事で 3DCADソフトのRhinocerosで作った街のデータを扱うことが出たものの
データのエクスポートでブロックインスタンスで複製してあるオブジェクトが実体化されてしまって
大容量データになってしまっていたので Rhino上でインスタンスの座標を取得する方法を調べたメモ
Rhinocerosの基本操作も把握してない状態で初めたものの
アウトライナのような 全体のオブジェクトを把握できるようなものは見当たらない様子で
オブジェクトの座標を見るにも操作が煩雑な様子なのでスクリプトでできないか調べることに
幸いにもPythonが使えるらしい
rhinoscriptsyntax と Rhino のライブラリを利用するらしいので
軽くdir()で属性を眺めた後に参考のスクリプトを検索してみた
# -*- 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)
な具合。
まずブロックインスタンスの取得を別の書き方で試してみた
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) の部分はこのままで動くからややこしい。
rhobj = doc.Objects.Find(block)
print(rhobj.InstanceDefinition.Name)
といった具合にGUIDからオブジェクトを取得した
冒頭の書き方とどちらがいいのかは不明
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にこのインスタンスのオブジェクトをデータとして書き出した上で
コレクションに収めて コレクションインスタンスとして配置したい場合のスクリプトのメモ
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)