RegisterInputParamsRegisterOutputParames中添加数据的输入端/输出端之后的下一步就是我们如何在电池的SolveInstance中拿到我们的数据并进一步处理了。

我们先来看看SolveInstance方法重写(override)时的方法定义

protected override void SolveInstance(IGH_DataAccess DA) { }

方法的传入参数为IGH_DataAccess接口类,返回类型void。当看到返回类型是void时我们就想到了,电池的计算结果肯定不是直接通过这个方法本身返回的,而是在方法内通过某种方式将数据传递出去。那么,这个传入的IGH_DataAccess接口类就应该是实现电池内部逻辑与数据的交互的核心了。


认识IGH_DataAccess

正如它的名字一般,IGH_DataAccess是一个用来从GH_Structure中获取数据的一个接口类。

回忆一下我们在C#中创建自定义类的时候如果要创建一个属性,我们常常会定义一个非公开变量用来存储这个属性值,并实现一个setter方法和getter方法来提供对这个私有变量的值的设置和获取,如下例所示

class MyCustomizedClass
{private string _name;public string Name => _name;public void SetName(string name) => _name = name;
}

相较于直接把属于类实例的变量 _name 直接设置成为公开,上面的处理方式可以在设置变量值的时候对该变量的值进行验证,比如上述方法中就可以直接对字符串的长度进行一个简单的验证:

public void SetName(string name)
{if (name.Length > 0) _name = name;else throw new ArgumentException("名字不能为空");
}

在Grasshopper中也是类似的,每个继承自GH_Component的电池都将内部的数据都是交由注册在电池上的参数实例 GH_Params 来管理的。参数实例把数据封包起来(底层对数据封装的实例为GH_Structure<T>),并将自己挂载在电池数据管理类GH_ComponentParamServer中,由电池内部的一个迭代器继承IGH_DataAccess接口类提供数据的setter方法和getter方法,并提供一些包含数据验证、迭代器、隐式类型转换等等功能。下面是上面各个类的关系图

于是,观察这个接口类会发现如下的一些方法

  • GetData
  • GetDataList
  • GetDataTree
  • SetData
  • SetDataList
  • SetDataTree

这些函数分别对应的就是以不同的方式获取电池输入/输出参数中的数据。值得注意点是,使用的获取数据以及给参数赋值的方法必须与之前参数的Access属性一致,否则会出错或出现异常现象,即:

  • 参数注册时Access属性设置为 item 时,需要使用 GetDataSetData
  • 参数注册时Access属性设置为 list 时,需要使用 GetDataListSetDataList
  • 参数注册时Access属性设置为 tree 时,需要使用 GetDataTreeSetDataTree

下面就是一个简单的例子,在SolveInstance中获取数据时,分别对具备不同的Access属性的参数进行数据获取。

protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager)
{// “布尔”参数的Access属性设置为 itempManager.AddBooleanParameter("布尔", "BOOL", "一个布尔值", GH_ParamAccess.item);// “直线”参数的Access属性设置为 listpManager.AddLineParameter("直线", "LINE", "一个直线", GH_ParamAccess.list);// “浮点数”参数的Access属性设置为 treepManager.AddNumberParameter("浮点数", "NUM", "一个浮点数值", GH_ParamAccess.tree);
}
protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager)
{// “整数”参数的Access属性设置为 listpManager.AddIntegerParameter("整数", "INT", "一个整数值", GH_ParamAccess.list);
}
protected override void SolveInstance(IGH_DataAccess DA)
{// 对变量进行初始化var bValue = false;var lineList = new List<Line>();var numberTree = new GH_Structure<GH_Number>();// 使用IGH_DataAccess获取数据,并保存至相应变量DA.GetData(0, ref bValue);DA.GetDataList(1, lineList);DA.GetDataTree(2, out numberTree);// .... .... // 处理数据、运算// .... ....var resultIntegerList = new List<int>();// .... .... // 处理数据、运算// .... ....// 使用IGH_DataAccess将结果数据赋值到输出参数中DA.SetDataList(0, resultIntegerList);
}

隐式类型转换

我们都知道任何一个编程语言都会或多或少地存在隐式数据转换,比如在学C/C++中大家都会遇到的经典问题 —— 5 / 3 的结果与 5 / 3.0 的结果不一样,就是因为后者在进行计算时,整型5会被隐式地转换成了浮点数类型。

隐式类型转换可以认为是程序(编译器也是一种程序)在最大程度上揣测用户的用意。这种隐式地转换类型发生地悄然无声,如果我们对其不够了解的话,那么对于程序运行的过程也会存在一定程度上的危险,导致一些奇怪的结果出现。

在GH中,隐式转换无处不在,可以说GH的易用性不光是靠各种快速的集合运算,更是因为这种“自然”的数据隐式转换。字符串转整数和浮点型、字符串转GH_Path、曲线转浮点型、直线转字符串,等等。

这些隐式类型转换虽然不是保证数据的双向完整传递(比如曲线转浮点型就默认只有长度,没法直接逆操作),但从用户体验的角度来说的确是省去了使用大量额外的电池来完成简单类型转换的操作。

GH中的隐式数据类型转换发生于两个层面:

  1. 输入/输出参数层面
  2. 参数拆箱层面

上图中的靠左侧虚线处会发生输入参数层面的隐式类型转换,靠中间虚线处会发生参数拆箱层面的隐式类型转换。

输入/输出参数层面的隐式类型转换

首先需要明确的一点是,仅有 GH自有类型 可以被作为数据传递与各个电池之间。于是,所有 非GH自有类型 的数据在GH画布中传递时都会被转换为GH自有的类型。所谓GH自有类型是实现了IGH_Goo接口的类。“数据传递”可以认为是从GH画布上电池的一端通过线输送到另一端的过程.

GH封装了许多常用的类,做成了自己的数据类型体系,均是以 “GH_” 开头,很多常见的Rhino几何类型都包含在内,例如 GH_LineGH_CurveGH_Surface 是封装的Rhino几何类LineCurveSurface。对于代码层面的基础类,比如 stringinteger ,也有对应的 GH_StringGH_Integer 与它们对应。所有其他未涵盖的类都通过GH_ObjectWrapper<T>泛型进行简单装箱。

假设我们现在将一个字符串类型(GH_String)输入到另一个电池的一个注册为GH_Number的参数中。当我们在使用 RegisterInputParameter 或者 RegisterOutputParameter 时,已经声明了这个参数的类型,于是所对应的GH_Param就固定了是字符串类型。当这个声明类型为GH_Number的参数接收到来自GH_String类型的数据时,会发现类型不匹配,于是乎,它就会调用GH_Convert的函数帮忙转换一下,转换成功则电池继续运行,如果无法转换,则直接报错,如下图所示

参数拆箱层面的隐式类型转换

在GH_Param成功获取到数据后,数据即可确认成为相对应的GH自有类型(以“GH_”开头的类型)。

当我们真正开始在SolveInstance中使用GetData系列函数获取该参数内部的值时,我们需要将GH自有类型进行拆箱,才能正常进行操作。例如,如果我们直接对两个GH_Integer实例进行相加的操作会直接报错(可以在C# Script电池中尝试下面一段代码)

GH_Integer a = new GH_Integer(1);
GH_Integer b = new GH_Integer(2);
var c = a + b; // 报错

函数内部值可以直接通过IGH_Goo接口中的属性Value获取,即

GH_Integer packed = new GH_Integer(1);
int unpacked = packed.Value;

但我们如果在代码中每次都要手动拆箱这的确十分麻烦,所以GH提供了参数拆箱层面上的隐式类型转换,即我们使用GetData系列函数获取参数的值时,可以自动实现对应类型的拆箱。也就是说,如果IGH_Goo.Value的返回值类型与GetData需要赋予的变量的值类型相同,可实现自动拆箱。

protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager)
{pManager.AddLineParameter("直线", "", "", GH_ParamAccess.item);
}
// ... ...
protected override void SolveInstance(IGH_DataAccess DA)
{Line line = default(Line);GH_Line ghLine = new GH_LineDA.Getdata(0, ref GH_Line); // 不拆箱直接获取DA.GetData(0, ref line);    // 隐式类型转换拆箱
}

值得注意的是,这个“拆箱”的类型转换必须类型完全相同,将浮点型double转换为整型int也是不允许的(GH_Number->int直接报错)。下列代码就会直接报错

protected override void RegisterInputParams(GH_Component.GH_InputParamManager pManager)
{pManager.AddIntegerParameter("整型", "", "", GH_ParamAccess.item);
}
// ... ...
protected override void SolveInstance(IGH_DataAccess DA)
{double d = 0.0;DA.GetData(0, ref d);   // 报错,无法将装箱的整型拆箱成浮点型
}


以上就是本次关于在SolveInstance中有关数据I/O的一些小细节的内容了,欢迎关注下期

【Grasshopper基础3】在SolveInstance中获取数据和传出数据相关推荐

  1. 【Python基础】在pandas中利用hdf5高效存储数据

    1 简介 HDF5(Hierarchical Data Formal)是用于存储大规模数值数据的较为理想的存储格式. 其文件后缀名为h5,存储读取速度非常快,且可在文件内部按照明确的层次存储数据,同一 ...

  2. PowerShell_零基础自学课程_6_PS中获取帮助信息详解、管道、格式化输

    前些文章陆续的说了一些关于这些主题,但是讨论的都不够深入,今天我们深入的了解一下获取帮助信息.管道以及格式化输出的内容. 一.获取帮助信息 在PS中获取帮助信息,最常用的有: -? .get-comm ...

  3. PowerShell_6_零基础自学课程__6_PS中获取帮助信息详解、管道、格式化输

    前些文章陆续的说了一些关于这些主题,但是讨论的都不够深入,今天我们深入的了解一下获取帮助信息.管道以及格式化输出的内容. 一.获取帮助信息 在PS中获取帮助信息,最常用的有: -? .get-comm ...

  4. Servlet中获取请求体的数据

    package priv.lwx.javaex.servlet_demo.web.servlet.request;/*** 获取请求体的数据** @author liaowenxiong* @date ...

  5. Servlet中获取请求头的数据

    package priv.lwx.javaex.servlet_demo.web.servlet.request;/*** 获取请求头的数据** @author liaowenxiong* @date ...

  6. Servlet中获取请求行的数据

    package priv.lwx.javaex.servlet_demo.web.servlet.request; /*** 获取请求行的数据** @author liaowenxiong* @dat ...

  7. 关于Android中获取Intent里的数据

    Intent获取数据和发送数据的办法: //直接通过Intent发送 intent.putExtra("name","wytings"); //直接通过Inte ...

  8. 用springboot编写RestController之——详解RestController中获取请求的各种数据

    参考资料:老葛课堂 https://study.163.com/course/courseLearn.htm?courseId=1005213034#/learn/video?lessonId=105 ...

  9. 【Rust】从同质形式的 variants 中获取同类型的数据

    本文内容整理自:https://users.rust-lang.org/t/generic-referencing-enum-inner-data/66342 同质形式的 variants 如果你定义 ...

最新文章

  1. Apache2.2+tomcat7 负载均衡配置
  2. 8GB内存的树莓派4来啦!国内售价589元,官方还推出配套64位系统
  3. mysql数据库性别男用1存储那性别女用什么呢?
  4. mysql only_full_group_by报错的问题(转)
  5. react-native 集成极光推送jpush-react-native时的小问题
  6. sourceinsight如何显示完整文件路径
  7. 降低数据中心功耗的 4 大方法
  8. 【干货】女性社区应该如何抵御垃圾男
  9. 设计模式(面向对象)设计的七大原则
  10. 使用SpringTask定时获取传感器设备信息并缓存到Redis
  11. React的Element的创建和render
  12. 两个字符串的最长公共子序列长度_算法学习笔记(58): 最长公共子序列
  13. SSM返回中文乱码问题,SpringMVC返回中文乱码,SSM返回String字符串乱码问题
  14. 开发前奏曲之添加Android SDK平台工具
  15. python中index什么意思_index在python中是什么意思
  16. windows创建bat文件进行截图
  17. java:窗体里的标签(图片标签)
  18. python storm连接mysql_Python ORM Storm 源码修改
  19. 计算机视觉系列(七)——迁移学习
  20. iframe父页面与子页面如何传值

热门文章

  1. 为什么计算机的性能和价格千差万别,电脑性能怎么看_怎么看电脑配置好坏 从参数中看...
  2. 地图可视化技术的应用现状
  3. 20160329中艺收盘总结
  4. 数据库导入Excel中的数据
  5. Linux运维容器篇 k8s单节点二进制部署(1) ECTD部署+CA证书制作
  6. html 对象元素如何获取div 里的data值 原生和jq对象两种获取
  7. 《PHP攻城狮面试宝典》
  8. 判断ajax获取是否为空,使用paginate方法分页无法判断获取的数据是否为空
  9. 多级复选框实现vue
  10. Linux桌面环境(桌面系统)比较优缺点