CPythonからGrasshopperを制御する(練習編)
突然ですがGrasshopperを使用しますか? SyntegrateとViccでは使う機会がたくさんあります。前回のブログ記事では、Rhino PythonからGrasshopperの制御を行いました。
今回はRhinoInsideを用いて、CPythonからGrasshopperを制御してみようと思います。これによってRhino Python(IronPython)の制限がなくなり、CPythonからインストールできるモジュールを利用することができます。また、複数のGrasshopperを制御することができるようになり、Grasshopperの用途を拡張することができます。
では本記事の流れとして、まずCPythonからGrasshopperを扱えるかの確認を行います。そして、練習としてghファイルを開いてコンポーネントに値やオブジェクトをセットします。今回はそこまでやってみます。
あらかじめRhino 7とCPythonをインストールして、以下のCPythonのモジュールをインストールします。
CPythonからGrasshopperのモジュールを扱う準備
Rhino 7が以下のフォルダにあるかを確認します。
C:\Program Files\Rhino 7\Plug-ins\Grasshopper
もしフォルダが存在していれば、以下のCPythonコードを実行してみます。Grasshopperのバージョンが出力されていれば成功です。
もしなければ、Rhino 7をインストールした時に別の場所に入れた可能性があるので、dir_plugins=”C:\\Program Files\\Rhino 7\\Plug-ins\\Grasshopper”の箇所をRhino 7がインストールしてあるディレクトリパスに修正してください。
### Copyright (c) 2021 Syntegrate
###
### This software is released under the MIT License.
### https://opensource.org/licenses/MIT
import os
import rhinoinside #pip install rhinoinside
import clr #pip install pythonnet
#Rhino.insideのimport
rhinoinside.load() #これがないとimport Rhinoができない → import Grasshopperができない
import Rhino
#pythonnetを用いて、GlasshopperのDLLを読み込んでimport
dir_plugins = "C:\\Program Files\\Rhino 7\\Plug-ins\\Grasshopper"
path_dll_Grasshopper = os.path.join(dir_plugins, "Grasshopper.dll")
path_dll_GHIO = os.path.join(dir_plugins, "GH_IO.dll")
path_dll_GHUtil = os.path.join(dir_plugins, "GH_Util.dll")
clr.AddReference(path_dll_Grasshopper)
clr.AddReference(path_dll_GHIO)
clr.AddReference(path_dll_GHUtil)
#試しにimport, バージョン出力
import Grasshopper
print(Grasshopper.Versioning.Version)
CPythonを実行させて、以下のようなGrasshopperのバージョンが出力されたら準備完了です。
1.0.0007
CPythonからghファイルを開いてGrasshopperに値をセットする
では、前回の投稿と同じように各コンポーネントに値を入力していくところからやってみましょう。パラメータのコンポーネントに入力できたかを確認するために、Pythonコンポーネントの出力”a”から値を取得しています。Panelコンポーネントは確認用であり、特になくても構いません。
Numberコンポーネントに値をセット
### Copyright (c) 2021 Syntegrate
###
### This software is released under the MIT License.
### https://opensource.org/licenses/MIT
import os
import rhinoinside #pip install rhinoinside
import clr #pip install pythonnet
#Rhino.insideのimport
rhinoinside.load() #これがないとimport Rhinoができない → import Grasshopperができない
import Rhino #Grasshopperを使うだけなら必要ないが、メッシュとかを扱うなら必要
#pythonnetを用いて、GlasshopperのDLLを読み込んでimport
dir_plugins = "C:\\Program Files\\Rhino 7\\Plug-ins\\Grasshopper"
path_dll_Grasshopper = os.path.join(dir_plugins, "Grasshopper.dll")
path_dll_GHIO = os.path.join(dir_plugins, "GH_IO.dll")
path_dll_GHUtil = os.path.join(dir_plugins, "GH_Util.dll")
clr.AddReference(path_dll_Grasshopper)
clr.AddReference(path_dll_GHIO)
clr.AddReference(path_dll_GHUtil)
#ここまでは同じコード
import Grasshopper
from Grasshopper.Kernel.Types import GH_Integer #Integerを入れるクラス
from Grasshopper.Kernel.Data import GH_Path
from Grasshopper.Kernel import GH_SolutionMode
path_gh = "○○\\△△\\test01.gh" #Grasshopperファイルへのパス
#--- Grasshopper.Kernel.Parameters(Integer)にセット
def AssignKernelParameter_Integer(gh_doc, nname_param, val):
for obj in gh_doc.Objects: #IGH_DocumentObject
if obj.NickName != nname_param:
continue
obj.AddVolatileData(GH_Path(0), 0, GH_Integer(int(val))) #ValatileDataのセット
return True
return False
#--- Grasshopper.Kernel.Parametersにセットされている値を出力
def PrintParameterInput(gh_doc, nname_param):
for obj in gh_doc.Objects: #IGH_DocumentObject
if obj.NickName != nname_param:
continue
#出力
print("input : {}".format(nname_param))
for branches in obj.VolatileData.Branches:
for item in branches:
print(" {}".format(item))
return True
return False
#---コンポーネントの出力結果を出力
def PrintComponentOutput(gh_doc, nname_cmp):
for obj in gh_doc.Objects: #IGH_DocumentObject
if obj.NickName != nname_cmp:
continue
for outp in obj.Params.Output:
print("output : {} ({})".format(nname_cmp, type(outp)))
#謎の処理
outp.CollectData()
#計算(いらない?)
outp.ComputeData()
for branches in outp.VolatileData.Branches:
for item in branches:
print(" {}".format(item.Value))
return True
return False
def main():
#.ghファイル読み込み
gh_doc_io = Grasshopper.Kernel.GH_DocumentIO()
ret = gh_doc_io.Open(path_gh)
if not ret:
return
#GH_Documentの取得
gh_doc = gh_doc_io.Document
#Integerコンポーネントにセット
ret_assign_A = AssignKernelParameter_Integer(gh_doc, "Int", 108)
#入力コンポーネント(Int)をチェック
ret_input_A = PrintParameterInput(gh_doc, "Int")
#計算
gh_doc.NewSolution(True, GH_SolutionMode.Silent)
#Pythonコンポーネントから結果を出力
ret_out_Py = PrintComponentOutput(gh_doc, "Python")
if __name__ == '__main__':
main()
出力結果です。Pythonコンポーネントの”a”から108が出てきています。
input : Int
108
output : Python (<class 'Grasshopper.Kernel.Parameters.Param_String'>)
output : Python (<class 'Grasshopper.Kernel.Parameters.Param_GenericObject'>)
108
Sliderコンポーネントに値をセット
### Copyright (c) 2021 Syntegrate
###
### This software is released under the MIT License.
### https://opensource.org/licenses/MIT
import os
import rhinoinside #pip install rhinoinside
import clr #pip install pythonnet
#Rhino.insideのimport
rhinoinside.load() #これがないとimport Rhinoができない → import Grasshopperができない
import Rhino #Grasshopperを使うだけなら必要ないが、メッシュとかを扱うなら必要
#pythonnetを用いて、GlasshopperのDLLを読み込んでimport
dir_plugins = "C:\\Program Files\\Rhino 7\\Plug-ins\\Grasshopper"
path_dll_Grasshopper = os.path.join(dir_plugins, "Grasshopper.dll")
path_dll_GHIO = os.path.join(dir_plugins, "GH_IO.dll")
path_dll_GHUtil = os.path.join(dir_plugins, "GH_Util.dll")
clr.AddReference(path_dll_Grasshopper)
clr.AddReference(path_dll_GHIO)
clr.AddReference(path_dll_GHUtil)
#ここまでは同じコード
import Grasshopper
from Grasshopper.Kernel.Types import GH_Number #Numberを入れるクラス
from Grasshopper.Kernel.Data import GH_Path
from Grasshopper.Kernel import GH_SolutionMode
path_gh = "○○\\△△\\test02.gh" #Grasshopperファイルへのパス
#--- Grasshopper.Kernel.Parameters(Numというやつ)にセット
def AssignKernelParameter_Number(gh_doc, nname_param, val):
for obj in gh_doc.Objects: #IGH_DocumentObject
if obj.NickName != nname_param:
continue
obj.AddVolatileData(GH_Path(0), 0, GH_Number(float(val))) #ValatileDataのセット
return True
return False
#--- Grasshopper.Kernel.Parametersにセットされている値を出力
def PrintParameterInput(gh_doc, nname_param):
for obj in gh_doc.Objects: #IGH_DocumentObject
if obj.NickName != nname_param:
continue
#出力
print("input : {}".format(nname_param))
for branches in obj.VolatileData.Branches:
for item in branches:
print(" {}".format(item))
return True
return False
#---コンポーネントの出力結果を出力
def PrintComponentOutput(gh_doc, nname_cmp):
for obj in gh_doc.Objects: #IGH_DocumentObject
if obj.NickName != nname_cmp:
continue
for outp in obj.Params.Output:
print("output : {} ({})".format(nname_cmp, type(outp)))
#謎の処理
outp.CollectData()
#計算(いらない?)
outp.ComputeData()
for branches in outp.VolatileData.Branches:
for item in branches:
print(" {}".format(item.Value))
return True
return False
def main():
#.ghファイル読み込み
gh_doc_io = Grasshopper.Kernel.GH_DocumentIO()
ret = gh_doc_io.Open(path_gh)
if not ret:
return
#.ghの中身取得
gh_doc = gh_doc_io.Document #GH_Document
#パラメータコンポーネントxにセット
ret_assign_X = AssignKernelParameter_Number(gh_doc, "x", 0.108)
#入力コンポーネントの値チェック
ret_input_X = PrintParameterInput(gh_doc, "x")
#計算
gh_doc.NewSolution(True, GH_SolutionMode.Silent)
#結果を出力
ret_out_Py = PrintComponentOutput(gh_doc, "Python")
if __name__ == '__main__':
main()
出力結果です。Pythonコンポーネントの”a”から0.108が出てきています。
input : x
0.108
output : Python (<class 'Grasshopper.Kernel.Parameters.Param_String'>)
output : Python (<class 'Grasshopper.Kernel.Parameters.Param_GenericObject'>)
0.108
Brepコンポーネントにオブジェクトをセット
### Copyright (c) 2021 Syntegrate
###
### This software is released under the MIT License.
### https://opensource.org/licenses/MIT
import os
import rhinoinside #pip install rhinoinside
import clr #pip install pythonnet
#Rhino.insideのimport
rhinoinside.load() #これがないとimport Rhinoができない → import Grasshopperができない
import Rhino #Grasshopperを使うだけなら必要ないが、メッシュとかを扱うなら必要
#pythonnetを用いて、GlasshopperのDLLを読み込んでimport
dir_plugins = "C:\\Program Files\\Rhino 7\\Plug-ins\\Grasshopper"
path_dll_Grasshopper = os.path.join(dir_plugins, "Grasshopper.dll")
path_dll_GHIO = os.path.join(dir_plugins, "GH_IO.dll")
path_dll_GHUtil = os.path.join(dir_plugins, "GH_Util.dll")
clr.AddReference(path_dll_Grasshopper)
clr.AddReference(path_dll_GHIO)
clr.AddReference(path_dll_GHUtil)
#ここまでは同じコード
import Grasshopper
from Grasshopper.Kernel.Types import GH_Brep #Numberを入れるクラス
from Grasshopper.Kernel.Data import GH_Path
from Grasshopper.Kernel import GH_SolutionMode
path_gh = "○○\\△△\\test03.gh" #Grasshopperファイルへのパス
path_3dm = "○○\\△△\\tmp.3dm" #サーフェスが入っているパス
#--- Grasshopper.Kernel.Parameters(Numというやつ)にセット
def AssignKernelParameter_brep(gh_doc, nname_param, rh_brep):
for obj in gh_doc.Objects: #IGH_DocumentObject
if obj.NickName != nname_param:
continue
obj.AddVolatileData(GH_Path(0), 0, GH_Brep(rh_brep)) #ValatileDataのセット
return True
return False
#--- Grasshopper.Kernel.Parametersにセットされている値を出力
def PrintParameterInput(gh_doc, nname_param):
for obj in gh_doc.Objects: #IGH_DocumentObject
if obj.NickName != nname_param:
continue
#出力
print("input : {}".format(nname_param))
for branches in obj.VolatileData.Branches:
for item in branches:
print(" {}".format(item))
return True
return False
#---コンポーネントの出力結果を出力
def PrintComponentOutput(gh_doc, nname_cmp):
for obj in gh_doc.Objects: #IGH_DocumentObject
if obj.NickName != nname_cmp:
continue
for outp in obj.Params.Output:
print("output : {} ({})".format(nname_cmp, type(outp)))
#謎の処理
outp.CollectData()
#計算(いらない?)
outp.ComputeData()
for branches in outp.VolatileData.Branches:
for item in branches:
print(" {}".format(item.Value))
return True
return False
def main():
#3dmファイルの読み込み
rh_brep = None #セットするbrep
f3dm = Rhino.FileIO.File3dm.Read(path_3dm)
if f3dm is None:
return
for obj in f3dm.Objects:
if obj.Geometry.ObjectType == 16: #Brepの番号
rh_brep = obj.Geometry
break
if rh_brep is None:
print("can not extract brep...")
f3dm.Dispose()
return
#.ghファイル読み込み
gh_doc_io = Grasshopper.Kernel.GH_DocumentIO()
ret = gh_doc_io.Open(path_gh)
if not ret:
return
#.ghの中身取得
gh_doc = gh_doc_io.Document #GH_Document
#パラメータコンポーネントxにセット
ret_assign_Brep = AssignKernelParameter_brep(gh_doc, "Brep", rh_brep)
#入力コンポーネントの値チェック
ret_input_Brep = PrintParameterInput(gh_doc, "Brep")
#計算
gh_doc.NewSolution(True, GH_SolutionMode.Silent)
#結果を出力
ret_out_Py = PrintComponentOutput(gh_doc, "Python")
#3dmを閉じる
f3dm.Dispose()
if __name__ == '__main__':
main()
出力結果です。Pythonコンポーネントの”a”からBrepオブジェクトのGUIDが出力されています。
input : Brep
Untrimmed Surface
output : Python (<class 'Grasshopper.Kernel.Parameters.Param_String'>)
output : Python (<class 'Grasshopper.Kernel.Parameters.Param_GenericObject'>)
8b2ffb7c-9357-46d2-9a15-c14d52885480
次回
今回は以上になります。前回とは扱うクラスが異なる上に、ソースコードが冗長になっています。また、CPythonでGrasshopperを扱うための情報が少ないので、動作はするが正しい方法なのか不明であることに注意です。より正しい方法があればコメントしていただけると助かります。
次回は実践編として、数式コンポーネントの利用や、前回と同様にサーフェスモデルにGrasshopperを適用して別のオブジェクトを作るということをしてみます。
それでは、ここまでお読みいただきありがとうございました。