【Grasshopper基础2】Grasshopper电池的输入和输出不是那么详的解/进一步了解Params

我们在之前已经介绍过了如何创建自己的第一个电池,其中里面提到了我们制作的大部分电池都需要至少完成下面三个部分的代码

  • RegisterInputParams
  • RegisterOutputParams
  • SolveInstance

其中 RegisterInputParamsRegisterOutputParams 是用来声明电池的输入和输出的两个部分,重要程度不言而喻,本文我们就来看看他们俩到底是什么。


进一步认识RegisterInputParam和RegisterOutputParams

Params是Parameters的简写,即“参数”,这两个函数的名字也十分的直观 “Register Input Parameters” 和 “Register Output Parameters”,就是我们需要把电池需要处理的输入和输出参数进行注册。

不过凡是都有个为什么,我们首先关注的问题是“为什么需要多出来这两个函数?”,直接用 SolveInstance 接收传递参数不是更直观吗?要回答这个问题,我们需要来看看Grasshopper电池是背后的架构是什么样的。前面已经提到过,我们所有的自定义电池都是继承自 GH_Component ,而下图展示了一个它的类图。

GH_ActiveObject GH_Component GH_ComponentParamServer Params int RunCount RegisterInputParams() RegisterOutputParams() SolveInstance()

类图的每一个框代表着一个类,框之间的箭头代表着继承和派生关系,框里面被分割成三个部分,最上面为类名,中间为该类包含的属性,最下面为该类包含的方法。从上面的类图可以看出,GH_Component 是直接继承自 GH_ActiveObject

由于GH所特有的数据树结构(GH_Structure 以及 DataTree)存在,每个GH电池内部对数据的匹配和处理逻辑会变得十分复杂,其中包括一系列问题,例如数据列表与数据树的分支要如何进行数据匹配、数据树与数据树之间要如何匹配等。举个例子,例如下图中,通过两个点构造直线的电池,在输入端分别对应数据列表和数据树的情况下,就会出现不同的结果。

在这里插入图片描述

我们还可以通过把鼠标悬停在电池图标的中间来知道这个电池被运行了几次(SolveInstance被Call了多少次),图中可以看出,靠上方的输入端均为数据列表的电池运行了3次,而靠下方的输入端一个为数据列表另一个为数据树的电池运行了9次。

在这里插入图片描述

GH电池需要一个统一的管理数据匹配的逻辑才能保证所有电池以同一种方式运行,那如果将这种对数据逻辑的管理完全交给我们电池的开发者,那必然会导致两个后果:1)开发者的学习成本变高,我们不但要学习专注于数据处理的逻辑,还要为GH额外学习一部分的数据匹配逻辑;2)GH的用户体验变差,电池的质量参差不齐,每个电池对于数据匹配的逻辑很可能都是不一样的,对于用户来说,这就是一个灾难,在使用电池之前还需要“猜”一下。

因此GH在每个电池内部均内置了一套管理数据的类,即 GH_ComponentParamServer。这样,作为开发者,无需纠结数据树、数据列表的匹配问题,可以专心设计电池的核心部分——SolveInstance,仅需将电池的输入、输出端口在这个数据管理类中注册即可。

此外,GH_ComponentParamServer也会包含一些UI相关的处理,例如输入端和输出端的数量增加会导致电池在画布上显得更大,电池没有输出端则会以锯齿状显示电池的右端(参考 Custom Preview 电池,下图右侧电池)等等情况。

WeChaat

每个电池实例中均包含一个 GH_ComponentParamServer 实例,而每个 GH_ComponentParamServer 包含一个 GH_InputParamManager 实例和一个 GH_OutputParamManager 实例,分别对应管理输入端的参数和输出端的参数。

GH_Component
GH_ComponentParamServer
GH_InputParamManager
GH_OutputParamManager

我们在 RegisterInputParamsRegisterOutputParams 函数中可以看到一个传参为对应的 [Input|Output]ParamManager 。GH主线程在构造我们电池时,会调用这两个函数,并传入对应的实例。我们通过这个实例的一些方法,就可以实现在GH电池上添加输入/输出端了。常用的一些方法包含

  • AddBooleanParameter
  • AddCurveParameter
  • AddIntegerParameter
  • AddLineParameter
  • AddNumberParameter
  • AddTextParameter

大部分的方法都可以通过我们需要添加的输入/输出量的C#类名来确定,例如我们需要处理 Curve(曲线)类的参数,则使用 AddCurveParameter,处理 Line(直线)类的参数则使用 AddLineParameter

有几个特殊的例子值得注意:

  • doublefloat所代表的浮点数,在GH中会统一使用 AddNumberParameter来添加,且此时底层会使用double来保存该值
  • string 字符串类型在GH会使用AddTextParameter来添加,此时底层对数据的存储仍然是string类型,似乎这里只是一个名字的改变

下面就是一个例子,我们在输入端添加了3个输入值,分别是布尔值、直线以及浮点数,而输出端则是一个整数值。而且当我们试图将一个曲线接入电池的直线输入端时,电池会直接报错,并提示错误信息“无法将曲线转换为直线”。

protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager)
{
    pManager.AddBooleanParameter("布尔", "BOOL", "一个布尔值", GH_ParamAccess.item);
    pManager.AddLineParameter("直线", "LINE", "一个直线", GH_ParamAccess.item);
    pManager.AddNumberParameter("浮点数", "NUM", "一个浮点数值", GH_ParamAccess.item);
}
protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager)
{
    pManager.AddIntegerParameter("整数", "INT", "一个整数值", GH_ParamAccess.item);
}

在这里插入图片描述


设置某输入参数为可选

在我们不接入任何数据的时候,电池也会提示我们数据输入口没有数据接入,且电池的 SolveInstance 也不会运行,从而提供某种程度上的数据验证功能,如下图所示。

WeChata

我们当然可以选择不使用这种数据验证,将一个或某个电池的输入端数据为“可选”参数 —— 即该数据端口可不接入数据,电池仍可正常运作。

Grasshopper电池的数据管理类的底层是通过一个列表来存储我们添加的各个参数的,每个参数都是最终继承于 GH_Param 父类。我们可以通过使用列表获取到每个被添加的参数,然后将参数的 Optional 属性设置成 true 就可以实现该参数在不被连入数据时电池也可正常运作。具体看下列代码及结果演示,电池在 直线浮点数 两个输入参数端口即便没有数据连入仍可正常工作:

protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager)
{
    pManager.AddBooleanParameter("布尔", "BOOL", "一个布尔值", GH_ParamAccess.item);
    pManager.AddLineParameter("直线", "LINE", "一个直线", GH_ParamAccess.item);
    pManager.AddNumberParameter("浮点数", "NUM", "一个浮点数值", GH_ParamAccess.item);
    pManager[1].Optional = true;
    pManager[2].Optional = true;
}

在这里插入图片描述


为输入参数设置默认值

除了将参数设为“可选”之外,另一种可以让电池的某些输入端口不需要数据接入就可以工作的方法就是为参数指定默认值。电池在没有数据接入时就会自动采用默认值,Grasshopper原生电池的 Series 电池(生成等距数列)就使用了默认值。

WeChat

值得注意的是,设置参数默认值与设置参数“可选”不同的是,即便电池的参数设置了默认值,用户仍然可以通过右键单击该参数,将默认值删除,此时电池将不会工作。

默认值可以在注册参数时设置,比如下列代码就可以将前文例中的电池的 布尔 参数设置一个默认值为 false

pManager.AddBooleanParameter("布尔", "BOOL", "一个布尔值", GH_ParamAccess.item, false);

或者是添加一个默认值列表,这样可以将默认值设置成一个 list 输入。下例中的代码将默认值设置为一个列表。

IEnumerable<bool> boolList = new List<bool>{ true, false, true };
pManager.AddBooleanParameter("布尔", "BOOL", "一个布尔值", GH_ParamAccess.item, boolList);

其他参数属性

Grasshopper电池中的输入/输出参数对应的基类 GH_Param 除了上一节当中说提到的 Optional 属性之外,还有下列属性是常用到的

  • Name
  • Nickname
  • Description
  • Access
  • DataMapping
  • VolatileData

其中,NameNicknameDescription顾名思义,就是这个参数的一些描述性信息,在注册参数的时候也可以指定,也可以通过直接修改这些属性值进行再定义和修改。

Access属性则决定了电池的SolveInstance被调用时,会以什么样的方式来获取到连入的数据或者传出数据。Access属性也是一个在注册参数时的一个必填项,其值为一个枚举类 GH_ParamAccess,共有3个值,分别是 itemlisttree。它们的具体的区别会在本文最后介绍。

DataMapping属性可以改变参数的数据结构,它提供FlattenGraftNone这三个枚举类值可以赋予,分别对应将参数内的数据进行对应的数据结构改变。这里的改变与我们在正常使用Grasshopper时,在电池的输入/输出端通过右键点击每个参数,改变数据结构时完全相同。

VolatileData属性则是可以直接以数据树形式获取该输入/输出参数的数值,这在某些特定场景十分有用,尤其是当我们不希望使用Grasshopper默认的数据管理模式的时候,通过VolatileData属性可以直接获取到该参数对应的输入值或者输出值。


ParamAccess与数据结构

前文提到,Grasshopper电池中的每个输入/输出都对应有一个Access属性,该属性是一个枚举类型的值,一共有三个值(itemlisttree)可选择,每个值对应的作用如下:

  • item: 每次电池内SolveInstance函数被执行时,从该参数输入/输出端操作数据时,以每个参数的实例来进行操作
  • list: 每次电池内SolveInstance函数被执行时,从该参数输入/输出端操作数据时,以封装参数实例的列表来进行操作
  • tree: 每次电池内SolveInstance函数被执行时,从该参数输入/输出端操作数据时,以封装参数实例的数据树来进行操作

上面的文字描述读起来不是特别直观,下面就来用一个图来说明他们的区别

在这里插入图片描述

图中构造了一个简单的数据树,该数据树一共有三个树枝,第一个树枝中有三个实例,第二个树枝中有两个实例,第三个树枝中有四个实例,共计九个实例存储于该数据树中。此时,如果将该数据树连入某电池的输入端,当电池的输入端的参数具备不同的Access属性时,该电池将由如下不同的执行逻辑:

  • item:电池的SolveInstance将会被执行 9 次,且每次执行时,从该输入端获取数据时,将按实例来获取:第一次执行时,SolveInstance将获得object1,第二次执行时,SolveInstance将获得object2,以此类推
  • list:电池的SolveInstance将会被执行 3 次,因为该数据树一共有3个树枝。每次执行时,将按树枝提取这个树枝上所有的实例,并按照列表方式读入:第一次执行时,SolveInstance将获取到 List<object>{ object0, object1, object2 },第二次执行时,SolveInstance将获取到 List<object>{ object3, object4 },以此类推,直至所有树枝被处理完毕
  • tree:电池的SolveInstance将仅被执行 1 次,且数据树将会被完整地传入。此时,获取的数据与直接使用VolatileData获取得到的数据树相同。

下图就是分别设置输入端为不同的 GH_ParamAccess 值时,电池所对应的不同的表现。

在这里插入图片描述


  • 22
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值