请教个RhinoCommon 插件问题

我用Rhino.DocObjects.Custom.CustomCurveObject创建一条曲线,并写入一些UserData数据,把这个3DM文件保存。我想问下,当rhino打开这个3dm文件时,怎么可以自动调用我的插件命令来处理这些UserData数据。就象TS插件一样,有装TS插件,TS物件就能正常显示。没有装TS插件,TS物件就会被转为rhino物件。
英文太差,表达不清楚所以只能发这里问问大家了。
@KelvinC

@Jorin 這個問題你可以用英文描述嗎?

@KelvinC
我英文太菜 :sweat:
不过这个问题先不急,先把另一个问题解决了再说。 :smile:

@mdjcad,

請儘管用英文在英文論壇發問,Dale 看不懂就會來找我。

好的,谢谢!

要在打开一个含有插件数据的 Rhino 文件时,不需要人为干涉的情况下自动处理文件,这个功能的实现思路是这样:

1.首先要为我们插件所使用的 Rhino 文件用户数据中加入一个特有的标记,有这个标记,就表示这是需要我们的插件来处理的。

2.文件中有了插件信息标记,我们在打开这个文件时若能读到这个标记,就判断此文件为我们的插件要处理的,若没有读到,就不做任何操作。

然后我们来看看如何具体操作,第一步在 Rhino 的 3dm 文件中加入标记,这个你已经做到了。难点在第二步,要如何在每次打开文件时判断这个文件有没有标记呢?你这里提到了 TS,为什么在打开含有 TS 数据的 Rhino 文档时,不用我们执行任何操作 TS 就可以处理其数据?那我们先分析一下 TS 插件的属性。

在“选项”/“插件程序”中找到 TS 打开他的插件程序属性,从这个对话框中我们就可以发现这个插件程序和大多数插件的载入时间是不同的,从下图可以看到,TS 的载入时间是“启动时载入”

而大多数插件都如下图所示,是“需要时启动”

来想想为什么 TS 需要在启动 Rhino 的时候就载入呢,结合前面我们提出的问题,不难发现,TS 启动以后就等在后台,如果打开了含有 TS 数据的问题, TS 介入处理。所以这里得出第一个必要条件,我们要写的插件载入时间必须是启动时载入。查阅 RhinoCommon 说明文件,可以在 Rhino.PlugIns 下的 PlugIn 类中找到 LoadTime 属性。要修改这个属性,必须要重写。重写的语句如下:

public override PlugInLoadTime LoadTime
{
       get { return Rhino.PlugIns.PlugInLoadTime.AtStartup; }
}

有了上面这句,程序就可以在 Rhino 起点时加载了,当然仅加载是不够的,还需要在 3dm 文件打开时做出判断,所以程序需要“监听”打开的文件,当然“监听”只是表象,.NET编程并非监听机制,而是通过事件订阅。

继续查阅 RhinoCommon 文档,在 Rhino.RhinoDoc 类下面可以找到 EndOpenDocument 事件,如果我们订阅了这个事件,在文件打开完成以后就可以做一些操作了(比如你对你的模型进行一些处理)。

订阅打开文件结束事件代码示例:

Rhino.RhinoDoc.EndOpenDocument += new System.EventHandler<Rhino.DocumentOpenEventArgs>(WriteSomething);

上面代码中 WriteSomething 是这个事件传递来以后要执行的函数,可以自由定义。

我用上面的方法写了一个非常简单的插件LoadTest.rhp (6 KB) 来测试以上思路是否正确,提前准备好了一个3dm 文件 test.3dm (220.2 KB) ,在文档层面包含了一个字符串,通过"Plugin", "Name"索引可以查找到"LoadTest"字符串。这个程序写好以后要检查的有两个方面,第一,插件是否随 Rhino 启动,第二,是否能正确读出我藏在 3dm 文件中的字符串。

通过实际运行,下图验证了以上方法:

范例源码如下:LoadTest.zip (22.5 KB)

@KelvinC 中文已解答。

很詳細,謝謝。

@Jorin
回答很详细,非常有用,谢谢你。
另外有两个新问题。
1、我的3DM文件中,经常有上千个物件,如果每个都由插件判断有没有含有用户数据,是不是太浪费资源了,有没有事件驱动,当犀牛程序发现某个物件需要某个插件时,再调用指定插件?我在打开matrix资源文件(3DM文件)时就看到类似,你打开的文件需要matrix插件。这是怎么实现的呢。
2、有没有监控物件被修改的事件?例如,一曲线控制点被移动。我的插件怎么才能监控到这个修改呢?

1.用户数据分为两种,一种是储存在文档层面的,一种是储存在物件上的,我给出的示例中的那个3dm文件的用户数据就放在文档层,而不是在物件层。所以只需要判断这个3dm文件是不是需要插件来处理的,和这个文件中有多少个物件毫无关系。
2.请参考 Rhino.Input.Custom 命名空间 GetTransform 类下的 GetTransform Events

@Jorin,感谢你的及时回复。
1、我想自己写一种曲线和曲面,每个曲线或曲面附加的内容不同,所以数据是存储在物件层面的。
2、晚上回去试试。