【Grasshopper基础14】创建可在画布上自由传递的自定义类型数据(下)—— 电池与自定义IGH_Goo的交互
2022年3月至今,这段日子真是一段令人印象深刻的时光。
总之,居家这么久了,忙了一阵终于可以来写点东西了。首先要对上一期【基础13】内的两个小错误进行一个勘误:
在
class Pudge
中对IGH_Goo
接口的实现方法中,CastFrom(object source)
和CastTo<T>(out T target)
函数体内对于目标类型的判断有错误。不应该直接判断int
、double
或者Circle
类型,而是应该判断其GH_xxxx
类型,故依次应为GH_Integer
、GH_Number
和GH_Circle
。
仅当 需要转换的数据类型不存在Grasshopper自由类型对应时,才可以直接使用该类型作为判断依据。对应代码已经在【基础13】中更正,同时,也添加了一些对于序列化期间的异常处理的逻辑,详见原文代码。
接下来,就是本期的正文了:在【基础13】中我们已经建立了一个自己的数据类,实现了IGH_Goo
接口,向Grasshopper表明了我们对于该数据类型支持Grasshopper画布上流转表明了意愿,那么,怎么才能真正地实现Grasshopper的精髓 —— 自动数据隐式转换?
制作属于自己数据类型的电池出/入口
相信大家在【基础2】中就已经知道,如何向我们的自定义Component
中添加出入口了,那么我们现在回过头来看一段熟悉的不能再熟悉的代码:
protected override void RegisterOutputParams(GH_Component.GH_OutputParamManager pManager)
{pManager.AddIntegerParameter("整数", "INT", "一个整数值", GH_ParamAccess.item);
}
在这个往电池添加出口的函数里,调用 AddIntegerParameter
函数就是向出口添加了一个 Parameter
,类型为 Integer
。所有的出/入口都需要是Parameter
类型,我们要创建一个属于自己数据类型的Parameter
才可以把它作为出口添加到电池上去。
相信熟悉Grasshopper开发的读者已经想到了,是的,我们创建自定义Parameter
类,那在Grasshopper对应也是有一个基类需要继承,它就是GH_PersistentParam<T>
.
不多谈,直接上代码
using Grasshopper.Kernel;
// ... ...public class Param_Pudge : GH_PersistentParam<Pudge>
{public Param_Pudge() : base("Pudge", "Pud", "Contains a collection of pudges", "Params", "Geometry") { }public override Guid ComponentGuid=> Guid.Parse("{2737B093-AE35-40BE-B0BE-6E2D401C8E78}");protected override GH_GetterResult Prompt_Plural(ref List<Pudge> values){return GH_GetterResult.cancel;}protected override GH_GetterResult Prompt_Singular(ref Pudge value){return GH_GetterResult.cancel;}
}
看起来挺不错的,其实大部分工作已经是由基类GH_PersistentParam<T>
完成了,我们需要做的只是把这个基类里的具体泛型改成我们自己需要的自定义数据类型即可。
乍看之下,还挺像个电池的,有熟悉的base(...)
方法,熟悉的ComponentGuid
属性,但是有两个函数Prompt_Plural
和Prompt_Singular
,我们一会儿再讲它是干什么的。
直接对它进行一个编译,启动Grasshopper,我们发现,去Param
分类的Geometry
子分类,还真能找到我们刚刚的这个Param_Pudge
!
好家伙,拖出来看看,是熟悉的感觉哇。
点击它看看右键菜单:
这两个选项居然默认就有 “Set one Pudge” 和 “Set Multiple Pudges”,还贴心的加了复数形式s
。细节把控,极度舒适!
好了,上面提到的两个函数Prompt_Plural
和Prompt_Singular
就是这俩菜单项的回调函数,里面决定了这俩菜单项被用户点击之后,怎么样去生成一个Pudge
数据,和多个Pudge
数据。具体怎么写嘛… 今天就不多提及了,直接一个return GH_GetterResult.cancel
。期待后面的章节吧,嘿嘿。
制作“创作Pudge”、“分解Pudge”的电池
有了这个Pudge
类的Parameter
,我们在写自己的电池的时候,就可以将它加到我们的出入口里啦。作为演示,我们需要一对电池来创作能够在画布上游动的Pudge
数据类(创作Pudge和分解Pudge),显然,做电池这种【基础1】里就讲了的东西我就不说没用的了,直接上代码:
public class CreatePudge : GH_Component
{public CreatePudge() : base("CreatePudge", "CPud", "Make a Pudge", "Params", "DigitalCrab"){}public override Guid ComponentGuid => Guid.Parse("{7E5CEC1E-DAB1-4605-B310-CA23A965AD43}");protected override void RegisterInputParams(GH_InputParamManager pManager){pManager.AddIntegerParameter("Int", "i", "integer", GH_ParamAccess.item);pManager.AddNumberParameter("DoubleList", "d", "double list", GH_ParamAccess.list);pManager.AddTextParameter("CurveDictKeys", "k", "curve dictionaray, keys", GH_ParamAccess.list);pManager.AddCurveParameter("CurveDictVals", "cr", "curve dictionaray, values", GH_ParamAccess.list);pManager.AddCircleParameter("Circle", "ci", "circle", GH_ParamAccess.item);pManager.AddGenericParameter("TextEntity", "t", "text entity", GH_ParamAccess.item);for (int i = 0; i < 6; i++){pManager[i].Optional = true;}}protected override void RegisterOutputParams(GH_OutputParamManager pManager){pManager.AddParameter(new Param_Pudge(), "Pudge", "Pud", "The created Pudge", GH_ParamAccess.item);}protected override void SolveInstance(IGH_DataAccess DA){int i = 0;List<double> dl = new List<double>();List<string> sl = new List<string>();List<Curve> cl = new List<Curve>();Circle cir = default;TextEntity te = default;Pudge p = new Pudge();if (DA.GetData(0, ref i))p.PudgeInt = i;if (DA.GetDataList(1, dl))p.PudgeDoubleList = dl;if (DA.GetDataList(2, sl) && DA.GetDataList(3, cl)){var guids = new List<Guid>();foreach (var item in sl){guids.Add(Guid.Parse(item));}if (guids.Count == cl.Count)p.PudgeCurveDictionary = guids.Zip(cl, (s, c) => new { k = s, v = c }).ToDictionary(k => k.k, v => v.v);elsethrow new Exception("Number of Guids does not match number of Curves.");}if (DA.GetData(4, ref cir))p.PudgeCircle = cir;if (DA.GetData(5, ref te))p.PudgeTextEntity = te;DA.SetData(0, p);}
}public class DeconstructPudge : GH_Component
{public DeconstructPudge() : base("DeconstructPudge", "DPud", "Deconstruct a Pudge", "Params", "DigitalCrab"){}public override Guid ComponentGuid => Guid.Parse("{5F2C82C5-7E05-4A03-A7B5-0CA8E6284E2A}");protected override void RegisterInputParams(GH_InputParamManager pManager){pManager.AddParameter(new Param_Pudge(), "Pudge", "Pud", "The created Pudge", GH_ParamAccess.item);}protected override void RegisterOutputParams(GH_OutputParamManager pManager){pManager.AddIntegerParameter("Int", "i", "integer", GH_ParamAccess.item);pManager.AddNumberParameter("DoubleList", "d", "double list", GH_ParamAccess.list);pManager.AddTextParameter("CurveDictKeys", "k", "curve dictionaray, keys", GH_ParamAccess.list);pManager.AddCurveParameter("CurveDictVals", "cr", "curve dictionaray, values", GH_ParamAccess.list);pManager.AddCircleParameter("Circle", "ci", "circle", GH_ParamAccess.item);pManager.AddGenericParameter("TextEntity", "t", "text entity", GH_ParamAccess.item);}protected override void SolveInstance(IGH_DataAccess DA){Pudge p = null;if (!DA.GetData(0, ref p)) return;DA.SetData(0, p.PudgeInt);DA.SetDataList(1, p.PudgeDoubleList ?? Enumerable.Empty<double>());DA.SetDataList(2, p.PudgeCurveDictionary?.Keys.Select(k => k.ToString()) ?? Enumerable.Empty<string>());DA.SetDataList(3, p.PudgeCurveDictionary?.Values ?? Enumerable.Empty<Curve>());DA.SetData(4, p.PudgeCircle);DA.SetData(5, p.PudgeTextEntity);}
}
注释我也省了,毕竟电池都写这么多了,读者肯定一看就懂啦,最终看最后结果就好了:)
Ok, everything’s ready, let’s ROCK!
最终结果已经上图了,点开大图食用。Pudge
实现了CastFrom
和CastTo<T>
,因此可以对实现的几种数据类型进行隐式数据转换啦(Pudge
至 GH_Integer
, GH_Integer
至 Pudge
, GH_Circle
至 Pudge
)。
我们可以看到隐式数据转换会存在数据转换后,数据不完整的情况(由Pudge
类转换为int
之后,再往回转换则会出现其他数据丢失的问题),这其实是隐式转换的一个弊端。在设计自有数据类型的时候,不光是考虑隐式数据转换对用户的便利性,也需要考虑到数据如果出现丢失,避免对用户造成困惑才可以更好地设计出好用的工具。
另外,由于 Parameter Pudge 本身其实也是一个类电池,它也是可以实现自定义右键菜单、自定义数据后处理等高级功能(比如,“曲线”类的出入口会有“Reparameterize”菜单项,用来实现归一化功能,还能出现一个额外的小图标)。这些,大概笔者会在后续的 【Grasshopper进阶】 系列慢慢为大家带来吧。
祝大家开心地传递自定义类型,Enjoy!
【Grasshopper基础14】创建可在画布上自由传递的自定义类型数据(下)—— 电池与自定义IGH_Goo的交互相关推荐
- 【Grasshopper基础13】创建可在画布上自由传递的自定义类型数据(上)—— IGH_Goo接口的重要性及其实现
接下来的两章,我们来介绍一下在之前章节尚未介绍到的,但却在Grasshopper中占据极其重要地位的另一批我们早就虎视眈眈但却还没想到理由要去触碰的电池们(左侧红色框指示): 是的,就是这一些带黑底的 ...
- 【Grasshopper基础11】如何在GH电池上增加一个自己的按钮
作者:"咕咕咕?下一篇马上就写好了" 通过上一篇[基础10]的文章,大家已经了解到一个GH电池在画布上的样式是由其背后的 GH_Attribute 类实例来决定的,而大部分的GH电 ...
- 【Grasshopper进阶】在Grasshopper画布上实现动画效果
最近笔者为了能够做到对用户友好,深入地学习了一些前端的知识,等回过神来,发现已经好久没有在CSDN上更过东西了- 结合最近看到的某些前端框架的底层,突然想到为什么不在Grasshopper上玩动画呢? ...
- python怎么在画布上写字_Python3 tkinter基础 Canvas create_text 在画布上添加文字
Python : 3.7.0 OS : Ubuntu 18.04.1 LTS IDE : PyCharm 2018.2.4 Conda : 4.5.11 typesetting : Markdown ...
- python创建画布与子图_python实现在一个画布上画多个子图
今天小编就为大家分享一篇python实现在一个画布上画多个子图,具有很好的参考价值,希望对大家有所帮助.一起跟随小编过来看看吧 matplotlib 是可以组合许多的小图, 放在一张大图里面显示的. ...
- canvas在画布上创建向上下左右3D影子文字
canvas在画布上创建向上下左右3D影子文字 简单实现canvas中的文字3D影子;如有代码问题请留言,谢谢; <!DOCTYPE html> <html><head& ...
- 技术图文:02 创建型设计模式(上)
创建型设计模式(上) 知识结构: 图1 知识结构 简单工厂模式 Sunny 软件公司欲基于 C# 语言开发一套图表库,该图表库可以为应用系统提供各种不同外观的图表,如: 柱状图(histogram) ...
- 【Grasshopper基础8】电池的序列化与反序列化 Serilization of Grasshopper Component
这篇文章的内容是介绍GH_Component中另外一对可以被 override 的函数: Read Write 当我们在自己的电池中直接 override 时,Visual Studio会帮我们添加基 ...
- 【Grasshopper基础10】GH_Attribute简介 —— 自定义电池样式的终极后台
距离上次的[基础9]已经过去了又有差不多1个月了,工作上的事情越来越多,能抽出空来(主要是要找到"有空并且有舒适的心情来写"的时间挺难的-)的时间也变少了.笔者最近在做的工作跟Gr ...
最新文章
- Android ListView 删除 item
- 虚拟机 硬盘容量不够 增大的方法
- 惠普:利用大数据创造更智能的IT服务台
- java处理Excel(POI包)
- maven依赖 spark sql_window环境运行spark-xgboost 8.1踩到的坑
- Flink官网自学笔记
- Python稳基修炼的经典案例5(计算机二级、初学者必须掌握的例题)
- Excel .net读取
- python sorted下标_初学者掌握python 列表需要知道的操作
- Android studio java.lang.UnsatisfiedLinkError加载.so文件失败解决办法
- 中兴c语言 面试题,华为,英飞凌,中兴硬件工程师面试题
- [SPDK/NVMe存储技术分析]015 - 理解内存注册(Memory Registration)
- 一文看懂抢注域名的相关问题解答
- 微信小程序-贪吃蛇开发4 wxml和wxss学习
- 再见PanDownload ,下一个已经来了。
- 社交返利APP正在被返利机器人,普通返利APP集体围攻绞杀
- setproxy_SetProxy:一个设置IE代理的命令行小工具
- Python实现Excel拆分操作
- 使用LVM动态管理4T以上硬盘
- DEFCON CTF 2017圆满收关,三支中国战队闯入全球前五