追加二:
怎么理解 Rhino、scriptcontext、 rhinoscriptsyntax, 什么时候该用什么
后来我发现这个问题属于年更问题,不止我一个人问,我就释然了
Rhino:
一切都是以Rhino为基础(也就是官方说的RhinoCommon,注意与Command做区分,后者是命令行,也就是指令巨集)。调用方法为
import Rhino
由于它对学习C#的更友好,所以我还得再次单方面强调C#在这个应用场景中秒杀python。纵然官方使用了IronPython就是为了方便调用RhinoCommon降低了上手成本,然而就以我的体验而言,降低的相当有限,不如新手直接学C#(忽略python中庞大的第三方库数量而言)。
rhinoscriptsyntax:
官方对于常用的一些功能把RhinoCommon直接封装了一下,易于理解,说明文档更全面,也更容易使用。
但不是封装了所有的RhinoCommon。
萌新的福音,进阶的拦路虎,给rhinopython披上了易于使用的伪装。
scriptcontext:
不是很好理解的东西,个人建议忽略这个东西。
有且只有在ghpython中想和rhino中的物件做互动时候,使用一次即可。
这是我在论坛提问时候官方的一个说明:请问关于scriptcontext的帮助文档哪里可以找到? - #11,来自 Jorin 。
如果你能看明白这里就不用看下面我个人的理解翻译出来的废话。
之所以存在这个是因为gh的特殊性与rhinoscriptsyntax运行的特性。
首先我们回到单纯的使用gh的场景,很多电池创建了物件,但是在rhino中并不存在(只可以显示),无法选取也无法操作,只有通过 bake 指令才可以在rhino中实际存在。
这是因为rhino有一个doc(文档?)的概念存在(不要问我更深层次的东西,我也不明白意义何在),我们平时在rhino中创建的物件,从程序的角度看信息保存在 Rhino.RhinoDoc.ActiveDoc。
官方相关文档:
https://developer.rhino3d.com/guides/rhinopython/python-rhinoscriptsyntax-objects/ #简单
Rhino - 8 Geometry #极难且必要
而GH中也参考了这种设计,存在一个它自己的doc,名字就是 ghdoc ,与Rhino.RhinoDoc.ActiveDoc在程序的概念上看大部分时候都仅仅只有名字不同。
在gh中创建的物体,虽然并没有在rhino中存在,但是实际上存储在ghdoc中。而 gh 中的 bake 指令做的事也就可以理解为把对应的物件信息从ghdoc中复制到 Rhino.RhinoDoc.ActiveDoc 中一份。
ghpython中的bake官方范例:Rhino - Custom GhPython Baking Component
而需要注意的是,ghdoc 和 Rhino.RhinoDoc.ActiveDoc 是相互独立的。
那么由于这种相互独立,也就造成了如果在 gh 的 python 电池中运行,默认情况应该是对 ghdoc 中的物体进行处理,如果要对 rhino 中的物件进行处理,就必须把程序所操作的 doc 切换为 Rhino.RhinoDoc.ActiveDoc 。
scriptcontext就是为了做这件事。(当然实际上能做得更多)
在忽略掉ghdoc和Rhino.RhinoDoc.ActiveDoc时候,scriptcontext.doc 存储的的就是 rhinoscriptsyntax 操作的对象所在的doc,当需要对rhino中的物件信息进行操作时候,就把 scriptcontext.doc 指向 Rhino.RhinoDoc.ActiveDoc。
scriptcontext.doc = Rhino.RhinoDoc.ActiveDoc
加入上一行代码以后,就可以在 gh 的 python 中对rhino中物体信息进行互动(创建、拾取、读取信息、修改等)。
如果要对ghdoc中的物体信息进行互动,就得切换为 ghdoc :
scriptcontext.doc = ghdoc
# 普通情况下,gh中的python默认运行就是在ghdoc中,不需要手动加这一行代码。
扩展一:
由于前面强调过的 ghdoc 和 Rhino.RhinoDoc.ActiveDoc 相互独立"的特性,也就意味着切换doc时候需要注意 其中保存的物体信息不通用。
记得吗,前面的 “易用的RhinoScriptSyntax” 中有关物体的函数中,主要的输入物件信息是guid,主要的返回信息也是guid。而guid只是物体的一个属性,只是相当于物体对于程序的名字,并没有保存物体的实际信息。
也就是在程序中的信息层级可以(不准确的)表述为:
—doc
------物体1…
-----------guid(自动生成且唯一)
-----------属性
-----------几何信息
-----------……
------物体2…
------物体3…
也就意味着,如果使用的是 “易用的RhinoScriptSyntax” ,保存到变量中了一个guid,在切换了文档(doc)以后,再使用“易用的RhinoScriptSyntax” ,就会发现查无此物,因为按照一个doc中的guid是不可能查得到另一个doc中的信息的,它没这个物件。
也就是说如果要保障切换doc时候的顺利进行,就得把要传递的具体信息保存到变量中,而不能只是仅仅记录guid。需要几何信息就把几何信息(geometry)记录下来,需要其他信息就把其他信息记录下来。
上面是说的理论上
然而不同于理论上,ghpython做了一个优化——为了保障RhinoScriptSyntax的易用性,在ghpython中的guid并不仅仅是一串字符串(string),是一个(Guid),是的,这就是一个格式。
可以用python内置的 type() 来校验,输出结果为:
36228887-86a2-4c6f-a60a-c11f4d7518b4
<type 'Guid'>
虽然官方的说明是:“RhinoScriptSyntax 以字符串的形式返回对象标识符”。
但是这个 Guid 的格式在实测中是包含了物体信息的(也就会造成在一些特殊情况下会产生奇怪的问题)。
换而言之,即使是在ghpython中用RhinoScriptSyntax返回的Guid作为输出,gh也会自动把物体信息(Object信息含有attributes、geometry等)从 Rhino.RhinoDoc.ActiveDoc 复制到了 ghdoc 中去,那么其中的几何信息(geometry)也可以作为后续电池的输入。
但这样产生了几个需要注意的问题:
- Guid格式中似乎没有保存所有的物体信息,只包含了几何信息。
- 输出的Guid如果接入到 gh 的 panel 中,有的时候传递的是 Rhino.RhinoDoc.ActiveDoc 中字符串格式的guid,有的时候是ghdoc中物件的几何信息。
- 输出的Guid如果接入到 gh 的 id 中,有时候可以成功转为 id,有时候则会报错:“Data conversion failed from geometry to Guid ”。
- 输出的 Guid 如果接入到下一个ghpython的输入端,如果输入端属性为默认(ghdoc Object when geometry ),则输入信息为ghdoc中的物件 Guid,也就意味着明明上一个电池输出的是Rhino.RhinoDoc.ActiveDoc ,但是到了下一个电池中信息自动变成了ghdoc。如果输入端属性限定为 str 或者 Guid,那么接第二条,panel显示为字符串的guid时候运行正常,如果panel显示为几何信息(point、surface、brep……),那么则会报错:“Data conversion failed from geometry to Guid ”。
总之,在需要切换doc时候,不要信任 “易用的RhinoScriptSyntax” 与它使用的 Guid 机制。