CPythonからGrasshopperを制御する(実践編)
突然ですがGrasshopperを使用しますか? SyntegrateとViccでは使う機会がたくさんあります。前回の記事では、CPythonからGrasshopperを制御する練習として、入力用のコンポーネントに値を入れて、その値が正しく入力されているかを確認するところまで行いました。
今回は実践編として、数式やジオメトリ編集のコンポーネントを用いて計算結果を取得してみようと思います。
前回と同じモジュールを用います。Rhino 7とCPythonをインストールして、以下のCPythonのモジュールをインストールします。
サーフェスを構築するGrasshopperの計算結果を取得する
最初にGrasshopperでサーフェスを構築して、その計算結果を出力します。
### 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
import System
# 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)
# Grasshopperのドキュメントは下のURL
# https://developer.rhino3d.com/api/grasshopper/html/723c01da-9986-4db2-8f53-6f3a7494df75.htm
import Grasshopper
from Grasshopper.Kernel.Types import GH_Brep, GH_Integer, GH_Number #Numberを入れるクラス
from Grasshopper.Kernel.Data import GH_Path
from Grasshopper.Kernel import GH_SolutionMode
# ここまでは同じコード
path_gh = "C:\\Users\\○○\\△△\\Piller.gh"
path_dst_3dm = "C:\\Users\\○○\\△△\\Piller.3dm" # 出力先
# Grasshopper.Kernel.Parameters(int)にセット
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(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
# コンポーネントの結果を3dmで出力
def Export3dm_Extrusion(gh_doc, nname_cmp, path_dst_3dm, name_out="Extrusion"):
List_geom = System.Collections.Generic.List[Rhino.Geometry.GeometryBase]()
for obj in gh_doc.Objects: # IGH_DocumentObject
# 名前でExtrコンポーネントを探す
if obj.NickName != nname_cmp:
continue
for outp in obj.Params.Output:
if outp.Name != name_out:
print("it is not {}...{}".format(name_out, outp.Name))
continue
# 計算
outp.CollectData()
outp.ComputeData()
for branches in outp.VolatileData.Branches:
for item in branches:
# Geometry化してリストに加える
List_geom.Add(item.Value)
# GHの計算結果を3dmで保存
Rhino.FileIO.File3dm.WriteMultipleObjects(path_dst_3dm, List_geom)
def main():
# .ghファイル読み込み
gh_doc_io = Grasshopper.Kernel.GH_DocumentIO()
ret = gh_doc_io.Open(path_gh)
assert ret
# .ghの中身取得
gh_doc = gh_doc_io.Document # GH_Document
# パラメータコンポーネント"Radius"にセット
ret = AssignKernelParameter_Number(gh_doc, "Radius", 4.5)
assert ret
# パラメータコンポーネント"Count"にセット
ret = AssignKernelParameter_Integer(gh_doc, "Count", 3)
assert ret
# パラメータコンポーネント"Radius"にセット
ret = AssignKernelParameter_Integer(gh_doc, "Height", 7)
assert ret
# 計算
gh_doc.NewSolution(True, GH_SolutionMode.Silent)
# 計算結果を保存
Export3dm_Extrusion(gh_doc, "Extr", path_dst_3dm)
if __name__ == '__main__':
main()
出力結果です。サーフェスの3dmファイルができました。
既存のサーフェスを用いるGrasshopperの計算結果を取得する
先の計算結果を用いて、サーフェスにパネルをあてはめるGrasshopperを適用して、そのモデルを保存します。入力コンポーネントのSrfには先に保存した3dmファイルを使います。
### 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
import System
# 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)
# Grasshopperのドキュメントは下のURL
# https://developer.rhino3d.com/api/grasshopper/html/723c01da-9986-4db2-8f53-6f3a7494df75.htm
import Grasshopper
from Grasshopper.Kernel.Types import GH_Brep, GH_Integer, GH_Number #Numberを入れるクラス
from Grasshopper.Kernel.Data import GH_Path
from Grasshopper.Kernel import GH_SolutionMode
# ここまでは同じコード
# Grasshopperのドキュメントは下のURL
# https://developer.rhino3d.com/api/grasshopper/html/723c01da-9986-4db2-8f53-6f3a7494df75.htm
path_gh = "C:\\Users\\○○\\△△\\Panelization.gh"
# 入力元のモデル
path_src_3dm = "C:\\Users\\○○\\△△\\Piller.3dm"
# 出力先
path_dst_3dm = "C:\\Users\\○○\\△△\\Panelization.3dm"
# Grasshopper.Kernel.Parameters(Brep)にセット
def AssignKernelParameter_brep(gh_doc, nname_param, rh_brep):
for obj in gh_doc.Objects: # IGH_DocumentObject
if obj.NickName != nname_param:
continue
# ValatileDataのセット
obj.AddVolatileData(GH_Path(0), 0, GH_Brep(rh_brep))
return True
return False
# 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(Number)にセット
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
#コンポーネントの結果を3dmで出力
def Export3dm_SBox(gh_doc, nname_cmp, path_dst_3dm, name_out="Twisted Box"):
List_geom = System.Collections.Generic.List[Rhino.Geometry.GeometryBase]()
for obj in gh_doc.Objects: # IGH_DocumentObject
# 名前でExtrコンポーネントを探す
if obj.NickName != nname_cmp:
continue
for outp in obj.Params.Output:
if outp.Name != name_out:
print("it is not {}...{}".format(name_out, outp.Name))
continue
# 計算
outp.CollectData()
outp.ComputeData()
for branches in outp.VolatileData.Branches:
for item in branches:
# TwistedBoxからBrepに変換してリストに追加
List_geom.Add(item.ToBRep())
# GHの計算結果を3dmで保存
Rhino.FileIO.File3dm.WriteMultipleObjects(path_dst_3dm, List_geom)
def main():
# 3dmファイルの読み込み(サーフェス一つだけ)
rh_brep = None # セットするメッシュ
f3dm = Rhino.FileIO.File3dm.Read(path_src_3dm)
if f3dm is None:
assert False
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()
assert False
# .ghファイル読み込み
gh_doc_io = Grasshopper.Kernel.GH_DocumentIO()
ret = gh_doc_io.Open(path_gh)
assert ret
# .ghの中身取得
gh_doc = gh_doc_io.Document # GH_Document
# パラメータコンポーネント"Srf"にセット
ret = AssignKernelParameter_brep(gh_doc, "Srf", rh_brep)
assert ret
# パラメータコンポーネント"U Count"にセット
ret = AssignKernelParameter_Integer(gh_doc, "U Count", 10)
assert ret
# パラメータコンポーネント"V Count"にセット
ret = AssignKernelParameter_Integer(gh_doc, "V Count", 10)
assert ret
# パラメータコンポーネント"Height"にセット
ret = AssignKernelParameter_Number(gh_doc, "Height", 0.108)
assert ret
# 計算
gh_doc.NewSolution(True, GH_SolutionMode.Silent)
# 計算結果を保存
Export3dm_SBox(gh_doc, "SBox", path_dst_3dm)
f3dm.Dispose()
if __name__ == '__main__':
main()
出力結果です。パネルの3dmファイルができました。
複数のGHファイルを組み合わせる
先のサーフェスモデルを構築するGrasshopperと、そのサーフェスからパネルを構築するGrasshopperをひとつに組み込んでみます。
### 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を使うだけなら必要ないが、メッシュとかを扱うなら必要
import System
# 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)
# Grasshopperのドキュメントは下のURL
# https://developer.rhino3d.com/api/grasshopper/html/723c01da-9986-4db2-8f53-6f3a7494df75.htm
import Grasshopper
from Grasshopper.Kernel.Types import GH_Brep, GH_Integer, GH_Number #Numberを入れるクラス
from Grasshopper.Kernel.Data import GH_Path
from Grasshopper.Kernel import GH_SolutionMode
# ここまでは同じコード
# Grasshopperのドキュメントは下のURL
# https://developer.rhino3d.com/api/grasshopper/html/723c01da-9986-4db2-8f53-6f3a7494df75.htm
path_gh1 = "C:\\Users\\○○\\△△\\Piller.gh"
path_gh2 = "C:\\Users\\○○\\△△\\Panelization.gh"
# 出力先
path_dst_3dm = "C:\\Users\\○○\\△△\\All.3dm"
# Grasshopper.Kernel.Parameters(Brep)にセット
def AssignKernelParameter_brep(gh_doc, nname_param, rh_brep):
for obj in gh_doc.Objects: # IGH_DocumentObject
if obj.NickName != nname_param:
continue
# ValatileDataのセット
obj.AddVolatileData(GH_Path(0), 0, GH_Brep(rh_brep))
return True
return False
# 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(Number)にセット
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
# ExtrusionコンポーネントからGH_Brepを取得
def GetBrep_Extrusion(gh_doc, nname_cmp, name_out="Extrusion"):
for obj in gh_doc.Objects: # IGH_DocumentObject
# 名前でExtrコンポーネントを探す
if obj.NickName != nname_cmp:
continue
for outp in obj.Params.Output:
if outp.Name != name_out:
print("it is not {}...{}".format(name_out, outp.Name))
continue
# 計算
outp.CollectData()
outp.ComputeData()
for branches in outp.VolatileData.Branches:
for item in branches:
# Geometry化してリストに加える
gh_brep = item.Value
return gh_brep
assert False
# SBoxコンポーネントの結果を3dmで出力
def Export3dm_SBox(gh_doc, nname_cmp, path_dst_3dm, name_out="Twisted Box"):
List_geom = System.Collections.Generic.List[Rhino.Geometry.GeometryBase]()
for obj in gh_doc.Objects: # IGH_DocumentObject
# 名前でExtrコンポーネントを探す
if obj.NickName != nname_cmp:
continue
for outp in obj.Params.Output:
if outp.Name != name_out:
print("it is not {}...{}".format(name_out, outp.Name))
continue
# 計算
outp.CollectData()
outp.ComputeData()
for branches in outp.VolatileData.Branches:
for item in branches:
#for f in dir(item):
# print(f)
# TwistedBoxからBrepに変換してリストに追加
List_geom.Add(item.ToBRep())
# GHの計算結果を3dmで保存
Rhino.FileIO.File3dm.WriteMultipleObjects(path_dst_3dm, List_geom)
def main():
# .ghファイル読み込み(その1)
gh_doc_io1 = Grasshopper.Kernel.GH_DocumentIO()
ret = gh_doc_io1.Open(path_gh1)
assert ret
# .ghの中身取得
gh_doc1 = gh_doc_io1.Document # GH_Document
# パラメータコンポーネント"Radius"にセット
ret = AssignKernelParameter_Number(gh_doc1, "Radius", 4.5)
# パラメータコンポーネント"Count"にセット
ret = AssignKernelParameter_Integer(gh_doc1, "Count", 3)
# パラメータコンポーネント"Radius"にセット
ret = AssignKernelParameter_Integer(gh_doc1, "Height", 7)
# 計算
gh_doc1.NewSolution(True, GH_SolutionMode.Silent)
# 計算結果をGH_Brep形式で取得
rh_brep = GetBrep_Extrusion(gh_doc1, "Extr")
# .ghファイル読み込み(その2)
gh_doc_io2 = Grasshopper.Kernel.GH_DocumentIO()
ret = gh_doc_io2.Open(path_gh2)
assert ret
# .ghの中身取得
gh_doc2 = gh_doc_io2.Document # GH_Document
# パラメータコンポーネント"Srf"にセット
ret = AssignKernelParameter_brep(gh_doc2, "Srf", rh_brep)
assert ret
# パラメータコンポーネント"U Count"にセット
ret = AssignKernelParameter_Integer(gh_doc2, "U Count", 10)
assert ret
# パラメータコンポーネント"V Count"にセット
ret = AssignKernelParameter_Integer(gh_doc2, "V Count", 10)
assert ret
# パラメータコンポーネント"Height"にセット
ret = AssignKernelParameter_Number(gh_doc2, "Height", 0.108)
assert ret
# 計算
gh_doc2.NewSolution(True, GH_SolutionMode.Silent)
# 計算結果を保存
Export3dm_SBox(gh_doc2, "SBox", path_dst_3dm)
if __name__ == '__main__':
main()
出力結果です。2つのGrasshopperを使って、先と同じ3dmファイルができました。
おわりに
以上になります。このようにGrasshopperをCPythonに組み込むことによって様々なことに活用できそうです。例えばサーフェスとパネルのGrasshopperを構築する役割を分担をして開発したり、DjangoやFlaskを使ってサーバーサイドのプログラムにGrasshopperを組み込むといったことができそうです。
最後に、これまで3回にわたってPythonからGrasshopperを扱いました。以前にもあったのですがCPythonからGrasshopperを扱うための情報は少ないので、動作はするが正しい方法なのかは不明であることに注意してください。より正しい方法があればコメントしていただけると助かります。
それでは、ここまでお読みいただきありがとうございました。