欢迎光临散文网 会员登陆 & 注册

Grasshopper 中树形数据的实际应用

2023-09-14 22:58 作者:Rhino3D原厂中国  | 我要投稿

本文以设计一座桥梁的钢缆的连接方式为例,详细分析了在使用GH的实现过程中,如何利用GH既有的数据规则来解决实际设计中遇到的复杂问题。过程着重于介绍分析思路,反映设计过程中遇到的数据处理及如何解决问题的思维过程。内容属于较为深入的GH部分,要求学员对Grasshopper有较久的使用经验,且对数据结构的规则较为清楚。

 

在过去十年的Grasshopper技术推广过程中,我们注意到:由于大部分设计专业的学员之前并没有接受过系统编程课程的逻辑思维训练,因此在使用Grasshopper的过程中涉及到逻辑思维的部分通常都会感觉较为吃力。

这个问题的另一个具体的表象就是:很多学员在遇到Grasshopper的树形数据结构时,对它的概念理解以及实际运用层面感到困难。这通常是所有学习GH的用户到了某个阶段都需要跨过的一道坎。

与其他的参数化设计软件和编程软件不同,GH采用的树形据结构的数据管理是很特别的,它可以让用户“分层级”的“多维度”的管理和控制大量的数据。但前提是使用者必须对这种数据管理和控制的原理有对应的了解,才能对其进行合理和灵活的控制。这部分是很多使用者依靠自己琢磨难以深入到的部分。在此我们将用一个实际的设计案例的过程分析帮助用户思考树形数据的组织关系。


 

设计一座悬挂结构的桥

这是一个悬挂结构的桥,如图是整个桥的侧面结构。黑色矩形方框是桥体。桥体上10个红色点桥体的固定点,用钢丝悬挂固定。顶上的两个蓝色矩形代表悬挂桥的两个立柱,每个立柱上各有3个钢丝固定点。我们需要解决的问题就是如何在桥体和柱子的固定点之间拉钢丝。


这个设计中遇到的实际问题可以被简化为点连线的问题,即:如何在下面10个点和上面6个点(2*3结构)之间做各种连线方式的设计。为了理清设计思路,我们先看两种最极端的连线方式:

  1. 最稳固的方式(连线最复杂)

  2. 最省材料的方式(连线最简单)


 

1. 最稳固的方式(连线最复杂)

所谓最稳固的方式(并且是合理的),也即是:桥体的每个点(底下的10个点)都和柱子上的每个点(顶上的6个点)都做连线。

这个连线方式可以概括为:10个点和6个点之间的所有可能的连线,是交叉的数据对应的方式,因此会有60条线(10乘以6)。

虽说是最复杂的连线方式,但是在编程逻辑中却是最简单的,程序如下图:

连接效果如图:

虽然这是最稳固的连接方式,逻辑上来讲很简单,程序处理也很容易。但连接的视觉效果却不够好,因为桥体上的每个点都挂了6根连线,很明显连线过于密集(10*6=60根连线),并且造价也较贵。

2. 最省材料的连接方式

所谓最省材料的连接方式,也即是:桥体上的每个点(10个点)只使用一根钢丝做固定。

从连接的角度可以理解为:底部的10个点中,每个点都和上面的6个点的其中之一做连接。

思考:那么具体和顶部的哪一个点做连接呢?通常与最近的一个点连接是最合理的,因为最省材料而且钢缆牵引的角度也更趋近于垂直向上,力学上来说较为合理。

所以,整个连线的逻辑就是:底部的10个点中,每个点与顶上的6个点中最近的一个点做连线。

这个逻辑就稍微复杂一点了,从编程逻辑来考虑,实现这个效果可以分两个步骤实现:

  1. 首先做出桥体上每个点与柱体上6个点的连线。

  2. 然后从每个桥体上点的6个连线中挑选出最短的一根。

在这个编程逻辑中要特别注意:第一步的程序输出的数据虽然仍然是得到60根线,但是如果这60根线是在同一个列表中的,那么从数据管理的角度来说是有缺陷的,因为这样的数据结构无法反映出桥体上的某一个点上连接的6根连线是哪6根。因此无法进行长度的比对和挑选,因此到了第二步也就也无法完成最短线的挑选。

因此在第一步中,这60跟线必须是依据底部的10个点分别处理的,也即是:第一步输出的数据结构应该有10个分支(列表)对应底部的10个点,而每个分支里面有6个数据(6根线)。这种数据结构可以清楚的反映出60根线中,哪些线是连接哪个点的。这实际上就是Grasshopper的树形数据的基本用途。数据结构图和GH中的Param Viewer观察输出结构应该如下图所示:


提示:Param Viewer是用于检查树形结构常用的工具,用户应该熟悉如何去阅读它。

 

2.1 桥体上每个点与柱体上6个点的连线

第一个步骤的程序如下图所示:

程序处理细节:为了保证输出结果是想要的树形结构,因此根据GH的数据对应法则,必须把B端的数据做Graft处理,这样数据的对应方式就变成桥体上的每个点与顶部的六个点做数据对应连接线。

思考:做Graft之后数据产生什么样的结构变化?为什么要把B端做Graft,而不是把A端做Graft?如果对A端做Graft数据会变成什么样的数据结构?为什么需要这样的数据结构?


2.2 每个桥体点的6个连线中挑选最短一根

这个功能从编程逻辑角度思考可以这样解决:首先对每个点的六条线的长度做从小到大的排序,然后从中挑第一条线,因为第一条线必定是每个点的六条线中最短的一根。这部分并不涉及数据结构的处理,理解工具运作的原理就可以做出来,程序如下:

效果如下图,每条线都是底部的每个点与顶部6个点中最近的一个点的连线:

在这个例子中,如何控制程序将输出的60根线使用树形结构做正确的归属管理,是程序实现正确连线效果的关键。

总结:以上两种方案都是最极端的:例如第一个方案安全性自然是最好,但是因为连线最多意味着实际项目中钢缆也必须使用很多,因此造价很贵。而第二种方案虽然造价最便宜,但是因为每个桥体上的固定点只有一根钢缆固定,因此安全性也是最差的。可以试想如果其中有一根柱子断了,那么整个桥就有一半的区域完全没有支撑,因此很可能整个桥立马就垮了。所以有时候我们会综合造价、成本等因素来考虑解决方案。

3. 较合理的方式

上述两个极端方案都有各自的明显的问题,因此从加强安全性角度考虑可以做些改进:让桥体上的每个固定点都有2根钢缆拉住它,且两根钢缆分别连接到两个不同的立柱上。再从造价和力学角度考虑让每根钢缆连接对应的立柱中最短的一个点,这样可以在安全性和造价方面获得一个不错的平衡。

因此这个设计的具体要求就是:对于桥体上的10个点,每个点分别跟两个立柱连接的3根线中挑选出最短的一根。

这个设计从逻辑上来讲其实和第二个方案比较接近,区别在于第二个设计仅仅要求找出每个点的6个连线中最短的一个,而这个设计要求还需将每个点的6根线按照立柱的归属分成2组,然后再找出每一组中的最短的线。因此输出的60根线应该是按照如下的树形结构管理和数据结构的程序为:

首先需要注意:立柱点输入端输入的数据,必须按照立柱归属做树形结构的管理,两个分支对应两个立柱,每个分支里面3个数据对应每个立柱的三个固定点。

立柱的树形数据结构依赖于前端的程序对应生成。

在接下来的连线程序部分会遇到数据对应方面的控制问题,当前程序部分结构如下:

现在A和B组数据的结构与之前不同,按照GH的数据对规则来看,事实上这里无论怎么调整都不可能直接得到我们要的数据结构。<想想为什么>

因此我们的考虑就是退而求其次:如果没有办法直接得到60根线(10个点—2个立柱—3根线) 的树形结构方式,那么我也可以接受其他的树形结构管理方式,只要60跟线的数据没有混淆在一起,我们就可以在后面做树形结构的调整。

因此在这里我们可以考虑让得到的60根线的树形结构可以体现出:分别属于桥体10个点,分别属于2个立柱,分别属于立柱的3个固定点的结构?也即是树形结构中必须体现出:10,3,2的结构,无论顺序如何。<这里根据排列原则有六种树形结构是符合要求的>

当前的程序从输入数据的树形结构来分析唯一可以做到这个效果的方法就是:将A组的数据做Graft,如下图所示。<思考为什么其他方式都不可以?>

输出的数据接结构如下,尝试理解每个层级代表的含义是什么。

上面的树形数据,结构是<2,3,10>的结构,是符合我们的预期的。但我们希望树形结构管理是这样:底部10个点的每个点分别与两个立柱各自的3三个点连线。因此数据结构应该是:

因此接下来我们需要在GH中把当前的树形结构做对应调整:


调整树形结构的组织顺序,使到的工具是Path Mapper,Path Mapper在调整树形结构方面有非常多的用途,但是要做到灵活运用,用户首先要能看懂树形结构代表的含义,进一步必须清楚自己需要的树形结构是什么样的,才能配合Path Mapper做对应的调整。如果对Path Mapper工具用法不清楚,建议系统学习Rhino原厂的发布的一套视频工具课程:

Grasshopper 工具视频课程

🔗 https://pezzs.xet.tech/s/3uvetF

 

一旦树形结构调整正确了,后面的部分就很容处理了,跟之前的部分完全一样:对每个分支中的三条线的长度做从小到大的排序,根据排序把对应第一条线跳出来即可。完整程序如下:

可以看到,虽然整个程序编写过程中涉及的树形数据的理解和控制需要非常多的思考,但是写出来的程序却是很简单的。

最终效果如下图所示,其设计的连线逻辑就是:桥体上的每个点都有两根线拉住它,并且这两根线分别连接到两个不同的立柱上(分散风险),并且每根线都是立柱上3个点中距离最短的点的连线(造价低,力学效果好)。

因为程序本身可以处理立柱点输入端的多分枝数据结构,因此对于更加复杂的设计,例如我们需要将立柱数量变成5个,仅仅需要从输入端将对应的5个分支的数据输入即可,程序不需要做任何修改,仍然是简单的结构但是可以处理复杂的数据,如下图所示:

思考:文章的后面部分中,我们将介绍一种不太好的编程思路。也是很多对Grasshopper数据结构缺乏理解的用户很常见的做法。


4. 用户常见分析方式

例如刚才我们提到的第三种方案:找出底部10个点的每个点分别跟两个立柱连接的3根线中最短的一根。

遇到这种需要处理复杂的树形结构的程序的时候,我们经常见到用户会使用下面这种做法。

程序仅考虑处理单个柱子连接的情况,程序如下:

这个程序几乎可以沿用最简化方案的程序,但输入仅仅是3个点(第一根柱子里的)。

当需要处理多根立柱的数据的时候,将整个程序复制一个出来,输入端更换为另一根柱子的3个点,最后再把数据合并在一起如下图所示。

这种做法虽然也可以做到本例中的效果,但是其的本质是用多个一模一样的程序并排分别处理不同立柱中的数据,然后再把每个程序得到的数据合并在一起。

这种做法如果要说好处,应该是可以少费一点脑力,不用去组织多层的树形数据结构。但是缺点也是很明显的:如果柱子数量较多,就需要手工复制出这部分的程序并每个都做修改来实现分别的处理,程序会因此变得很复杂,不利于修改和管理程序,程序执行效率也会变得比较低。例如前例中最后提到的:如果设计变动成5跟立柱,那么程序就必须复制出5个一模一样的部分,分别改动每个立柱的数据,如下图所示:

这种方式还有一个严重的缺点:如果柱子数量本身是一个设计中考虑的变量,那么如果柱子数量发生变动,每次使用者都必须手动更改每一个程序部分:重新连接每个程序部分的输入数据,重新连线,更改每一个程序的参数,否则程序运行就会出错。

也即是说,这种方法是因为程序无法处理输入端的树形结构数据,因此把数据结构拆开让多个程序分别处理,因此这种程序往往显得“呆板”,它不能适应输入的数据分支结构发生变化的情况。

提示:通过这个案例的过程解释,希望学员可以掌握能够处理复杂的树形结构的程序的方法,写出高效而聪明的程序辅助设计。

 


本次分享结束,欢迎分享这篇文章给你身边的小伙伴。

如果你在使用 Rhino Grasshopper 时遇到问题,可以前往 Rhino 中文讨论区发帖提问哦~


Grasshopper 中树形数据的实际应用的评论 (共 条)

分享到微博请遵守国家法律