你好,这里是BIMBOX。

今天是临时加餐,分享一个很有意思的教程给你,是我们和一位小伙伴两个通宵的成果。

它能解决一个很麻烦的问题,更重要的是它能启发大家的思路:怎样用尽量简单的自动化,帮助我们去做那些重复枯燥的工作。

事情的缘由是这样的。

还记得@Vctcn93吗?那个跟我们一起合作,出了《为所欲为:Dynamo信息可视化脚本实战》的Dynamo小神仙。

最近他一直在琢磨怎么通过Python编程和Dynamo带来更高的生产力,也经常在群里和大家探讨,回答教程问题,已经成了群宠。

上周三,在我们的BIMBOX莱茵河清流群里,小伙伴@Null提问,对于大量形状类似、尺寸不同的族,有没有办法快速的建出来。

一键组网怎么操作 自动批量建族搞起(1)

Vctcn93回答说,生成多个类似的族是有规律的,可以用Dynamo来实现。也有小伙伴提出,可以通过参数化建族来搞定,但用Dynamo能打开更多的思路。

于是,Vctcn93就和Null要来了图纸,答应大家周末抽空把节点和教程给写出来。

一键组网怎么操作 自动批量建族搞起(2)

不过,在叫了对方好几声哥们之后,经@开开提醒,Null是女生,事情的发展又比预想的迅猛很多。

一键组网怎么操作 自动批量建族搞起(3)

周六一早,我就收到了Vctcn93的微信,一看时间是凌晨五点发来的。本来答应周末慢慢搞的事,居然搞了个通宵。

尽管他和我说,主要是因为本来觉得很简单的一个脚本,越琢磨越有意思,好玩的知识点很多,于是越写越兴奋,这才搞了8个小时。

一键组网怎么操作 自动批量建族搞起(4)

我仔细看了一下他的思路,确实很有启发。于是答应下来,拿出时间把他的思路和成果整理成大家更容易阅读的文章,免费分享给所有人看。

这份教程中涉及到一些Dynamo的基础知识,以及几段Python代码,如果你暂时搞不明白原理,也不影响阅读今天的文章,我们会在代码处加入中文说明。

暂时不想做,也可以花十几分钟读一遍,重点看看思路,领略一下Dynamo和Python的自动化之美,以及用自动化解决重复问题时那种灵光乍现的酸爽。

下面正式开始——

一键组网怎么操作 自动批量建族搞起(5)

01 自适应族的拓扑关系

首先你需要掌握一点基础知识。

Revit 中有一个十分强大族类型——自适应构件(Adaptive Component),一般多用于处理幕墙相关的问题。

我们先到 Revit 中制作一个简单的自适应族,来搞清楚自适应构件的原理。

➤ 打开 Revit 2018,新建一个 自适应构件 族。

一键组网怎么操作 自动批量建族搞起(6)

➤ 在面板中找到 点图元 工具,并且添加四个点。

一键组网怎么操作 自动批量建族搞起(7)

一键组网怎么操作 自动批量建族搞起(8)

➤ 全选点,然后点击上部面板下的 使之自适应 按钮。

一键组网怎么操作 自动批量建族搞起(9)

它们就变成了这个样子:

一键组网怎么操作 自动批量建族搞起(10)

➤ 使用线工具,并打开 三维捕捉。

一键组网怎么操作 自动批量建族搞起(11)

➤ 依照 点 上方的序号(index),依次链接各点。

一键组网怎么操作 自动批量建族搞起(12)

➤ 选中全部的线,点击 创建实体形状。

一键组网怎么操作 自动批量建族搞起(13)

这时,我们就成功创建了一个简单的 自适应嵌板。

一键组网怎么操作 自动批量建族搞起(14)

左侧的属性栏可以调整厚度。

一键组网怎么操作 自动批量建族搞起(15)

➤ 保存一下,新建一个项目,把建立的族加载进项目中,只要给定任意的四个点(按顺序点击四下),就能得到依照点生成的嵌板。

一键组网怎么操作 自动批量建族搞起(16)

以上就是制作一个简单自适应族的过程。

想要弄清楚点击四下的时候发生了什么,我们先要了解一个图形学名词 ——拓扑关系(Topological Relation)。

拓扑关系是图形学中的常用概念,本质就是把各种图形,抽象简化为各个点之间的关系。有了这些基本的关系,我们则不需要在乎它绘制出来究竟是什么形状。

比如正方形、梯形、四边形、菱形等等,尽管在形状上有很多不同,但是在拓扑的视角看,这些点都满足依次使点成环的关系,它们是拓扑等价的

我们在制作 自适应族构件的过程中,有一个重点操作叫使之自适应,它的作用是记录各个点的位置、顺序、谁与谁相连等拓扑关系。

这时每个点都会生成一个序号,它将记录自己在这一拓扑关系中的顺序。

当我们使用线将各个点连接起来的时候,这个点就会记录下另外哪两个点和自己相连,而它不会在乎这两个点在空间中的什么位置。

这些顺序和连接关系就是预先保留在族里的默认信息

我们在使用这个族的时候,点击四下,这个操作是告诉Revit预先设定的四个点的空间坐标,它们是我们使用族的输入信息

族在项目里最终呈现什么状态,就是下面的公式:

族的输出状态=预设定默认信息 使用时的输入信息

而我们想要让族「自动化」,就是尽量多的解决默认信息,从而减少输入信息的工作量。

在这个族里,输入信息的重点在于顺序,它决定了点的序号,决定了谁去找谁连线,决定了拓扑关系,从而决定了最终的形状。

想让 Dynamo 来代替我们放正确的 自适应族 的时候,一定要保证输入的点顺序是正确的。

02 Dynamo中的强大节点

在 Dynamo 中,有一个使用自适应族的强大节点:

AdaptiveComponents.ByPoints

一键组网怎么操作 自动批量建族搞起(17)

这个节点有两个输入,第一个是points , 一个二维数组的点。

一键组网怎么操作 自动批量建族搞起(18)

第二个是familyType ,它是自适应族的类别。

一键组网怎么操作 自动批量建族搞起(19)

结合我们刚刚所学的拓扑关系知识,我们来模拟与理解一下这个节点的输入要求。

假设我们有一个需要四个点生成的自适应嵌板,则我们先来模拟建立点的二维数组,下面的代码你不懂python也能大概看懂:

points = [ [ Point.ByCoordinates(0, 0, 0), Point.ByCoordinates(1000, 0, 0), Point.ByCoordinates(1000, 1000, 0), Point.ByCoordinates(0, 1000, 0) ], [ Point.ByCoordinates(1000, 0, 0), Point.ByCoordinates(2000, 0, 0), Point.ByCoordinates(2000, 1000, 0), Point.ByCoordinates(1000, 1000, 0) ], [ Point.ByCoordinates(2000, 0, 0), Point.ByCoordinates(3000, 0, 0), Point.ByCoordinates(3000, 1000, 0), Point.ByCoordinates(2000, 1000, 0) ] ];

这段代码,Dynamo 中的 CodeBlock 与 Python 都可以直读,结果会生成一个 点阵(Points Array)。

一键组网怎么操作 自动批量建族搞起(20)

在上面的 points数组(List)中,每一个元素都是一个小数组,每个小数组里又包含了四个点。

这四个点,就是我们所需要每生成一块嵌板所需要的点,点的顺序则是我们在 Revit 界面中放置嵌板的点击顺序。

我们把数据点阵和族类型Family Types连接到AdaptiveComponents.ByPoints这个节点上。

一键组网怎么操作 自动批量建族搞起(21)

依照上面的点数据,Dynamo 便会依照每一个嵌板的输入点,生成 3个 自适应嵌板。在Dynamo 中看不见族的加载结果,我们得切换回 Revit 界面中才能看到。

一键组网怎么操作 自动批量建族搞起(22)

有多少个 points 数据,将决定我们生成多少块玻璃嵌板,嵌板中的点,即是嵌板的拓扑关系,Dynamo 将根据这四个点的位置与顺序,把嵌板放进去。

这就是在AdaptiveComponents.ByPoints节点中发生的事情,也是 Dynamo 要求输入这种数据结构的原因。

顺序非常关键。

正确地抽象我们要的形状,把抽象所得的点正确地排序与组合,是我们在使用这个节点之前的关键操作。

03 解决问题

@Null在群里的问题是,怎样建出多个形状类似的窗族。

为了降低难度,我将把她的图简化为方方正正的矩形,制作的时候也先暂时忽略尺寸,我们需要根据这个矩形,来运用一下刚刚所学到的东西。

一键组网怎么操作 自动批量建族搞起(23)

➤ 制作Dynamo脚本之前,我们需要先思考一下:

· 我想要那些参数? · 未来能否扩充与异化? · 是否有优化效率的可能?

先来看第一个问题,对于这个简化版的脚本,我需要的参数是:

· 每块面板的长度 · 每块面板的高度 · 面板的数量

➤ 这些参数当然不能一个个手动输入,所以在一开始,我们就把这三个参数做成 Number Slider节点,放置到界面的最左边,把它们重命名,并编组为 参数调节:

一键组网怎么操作 自动批量建族搞起(24)

这里需要注意两点:

· 单位是毫米,所以面板长度与面板高度的间距(step)最好以 100 为基准单位。

· 嵌板的个数必须是整数,所以面板个数的间距(step)一定要是整数。

➤ 下面,我们需要一个原点(origin),作为面板的起始位置,在这里我将使用 (0,0,0)点,你也可以设置其它原点。

一键组网怎么操作 自动批量建族搞起(25)

➤ 接下来,我们要依照给定的面板长度以及面板数量,生成一个以面板长度为间距(step),以面板数量为个数的数组(list),创造需要用到的第一组点。

此处使用 Code Block 代码来完成:

0..#quentity..#step

➤ 然后把面板长度与面板个数分别输入到step与quentity两个输入之中,便可生成第一个数组,也就是未来各点的 x 坐标值:

一键组网怎么操作 自动批量建族搞起(26)

➤ 有了各点的 x 坐标值,我们便可以使用 Geometry.Translate 节点,把原点按照坐标批量生产。

一键组网怎么操作 自动批量建族搞起(27)

➤ x轴方向搞定后,接下来以同样的方法,把这条线上的点,依照嵌板高度,在 y 方向上做条一模一样的出来:

一键组网怎么操作 自动批量建族搞起(28)

到此为止,我们便制作了一个参数化、实时可调的点阵(Points Array)。

➤ 接下来要做的就是要把生成的点阵,处理为一个按照顺序、包含正确拓扑关系的二维数组。

根据我们前面说的拓扑知识,输入进 AdaptiveComponents.ByPoints 节点中的点顺序,一定要正确反应嵌板的拓扑关系。

比如我在使用Revit建立嵌板族的时候,点击的顺序是从左下角开始逆时针旋转:

一键组网怎么操作 自动批量建族搞起(29)

所以,我们的点组顺序,也要按照这样的方式排列:(注意Dynamo第一个点的序号是0而不是1)。

一键组网怎么操作 自动批量建族搞起(30)

我们将刚刚生成的两组点,使用 List.Create 节点打包为一组数据。这样,就可以使用 Python处理我们的点阵了。

➤ 接下来就是Python 数据处理。

当然,到这一步不使用Python也可以使用,但回顾一下我们开始写脚本之前思考的第二个问题:

· 我想要那些参数? · 未来能否扩充与异化? · 是否有优化效率的可能?

虽然目前我们的数据很少、也很具体:两条线,每条线几十个点,我们可以用简单的代码把它写出来。但是,为了日后的扩充与异化,我们一定要把代码进一步处理成代数问题,把它抽象成 m 条线,每条线 n 个点。

在这种思路下,我们来开始写下面的脚本。这里有点烧脑,看不懂代码没关系,可以看看中文代码说明:

# 启用 Python 支持和加载 DesignScript 库 import clr clr.AddReference('ProtoGeometry') from Autodesk.DesignScript.Geometry import * # 该节点的输入内容将存储为 IN 变量中的一个列表。 dataEnteringnode = IN # 将代码放在该行下面 __author__ = 'Vctcn93' __date__ = 20190706 __publisher__ = 'ArchiPython' data = IN[0] # 将刚刚的数据,赋予到变量 data 中 result = list() # 创建一个用以装载结果的空列表 for i in range(len(data) - 1): # 遍历每条线 current_line = data[i] # 当前的线 next_line = data[i 1] # 下一条线 for k in range(len(current_line) - 1): # 拿取线上的每一个点 node = list() # 嵌板点组 node.append(current_line[k]) # 添加第 0 号点 node.append(current_line[k 1]) # 添加第 1 号点 node.append(next_line[k 1]) # 添加第 2 号点 node.append(next_line[k]) # 添加第 3 号点 result.append(node) # 把嵌板点组添加到结果中 # 将输出内容指定给 OUT 变量。 OUT = result # 输出结果

搞定之后,就可以在Dynamo中使用以上代码,把点阵处理清楚了。

一键组网怎么操作 自动批量建族搞起(31)

➤ 最后使用 AdaptiveComponents.ByPoints 节点,在 Revit 中成功生成玻璃嵌板:

一键组网怎么操作 自动批量建族搞起(32)

➤ 再来测试一下参数实时调整,所以依据面板长度、面板高度、面板个数几个参数的不同,可以有很多的结果,并且可实时变化:

一键组网怎么操作 自动批量建族搞起(33)

我们把到此为止的成果储存为「初始版.dyn」,下载链接见文末。

04 异化

到此为止,我们用Dynamo实现的功能还和一个嵌套阵列族差不多。

不过,每次建立一个程序,我们都要思考,能不能再它的基础上,用抽象思维去解决更多的事?

这个操作就叫异化。

比如这个案例,可以思考一下:能不能任意形状都能自动生成?

这里我将把上面这个脚本做一种异化,修改为根据任意 N 条 Revit 中的线,生成自适应异形幕墙。

➤ 首先,在 Revit 中,使用模型线工具绘制 4条 三维曲线:

一键组网怎么操作 自动批量建族搞起(34)

注意:这些线可以足够异型,但不可以在同一标高上,这样才能构成正确的拓扑关系。

一键组网怎么操作 自动批量建族搞起(35)

➤ 下面,我们在 Dynamo 中使用 Select Model Elements 节点,将这四条线由下至上(你看,顺序真的很重要)选进 Dynamo 中。

一键组网怎么操作 自动批量建族搞起(36)

➤ 接下来,再使用 Element.Geometry 的方式让这些线在 Dynamo 中可见,且能被处理。

一键组网怎么操作 自动批量建族搞起(37)

➤ 关于参数的设置,因为目前是弧线且不等长的缘故,再想让嵌板数量与嵌板长度兼得可调是不可能了,所以我们可以仅要嵌板长度这一个可调参数。

一键组网怎么操作 自动批量建族搞起(38)

还没完,嵌板数量也是一个很重要的参数,我们该怎样获取呢?

这时候就要请出高等数学了!

呃,是小学数学,就是取个平均值啦。

➤ 先算出四条线的平均长度,再使用平均长度除以嵌板长度,便是我们的嵌板数量。可是由于这个值除出来之后很有可能是小数,我们可以取最接近这个值的整数,作为每条边的嵌板数量。

一键组网怎么操作 自动批量建族搞起(39)

这一步是怎么来的呢?

你还需要明白一个重要知识点:样条曲线的parameter。

parameter 是把样条曲线的起点值当作 0,终点值当作 1,不管样条曲线多长,多曲折,都具有这样的属性。

比如,任何一条样条曲线中点的 parameter 都为 0.5,三分点无限趋近于 0.333 或 0.666。

知道了这样的一个特性,那么我们想把一条样条曲线均分为 嵌板个数 段,只要把 0 到 1 均分为长度为嵌板个数的数组就好了。

使用 Code Block 代码:

0..1..#steps

➤ 再将嵌板个数输入进 steps 中,就做到了。

一键组网怎么操作 自动批量建族搞起(40)

➤ 然后再使用针对样条曲线的节点 Curve.PointAtParameter 获得在这些值上的点,便得到了我们需要的点阵。

一键组网怎么操作 自动批量建族搞起(41)

➤ 有了这样一个点阵,便可以使用刚刚的 Python 代码,把这些点处理为含有正确拓扑关系的点组。

刚刚编写代码的时候,是用的抽象方法,所以不用改一个字,就能直接让新的脚本用上它,这就是抽象的好处。

一键组网怎么操作 自动批量建族搞起(42)

➤ 最后使用 AdaptiveComponents.ByPoints 节点,就能在 Revit 中找到做好的嵌板了。

一键组网怎么操作 自动批量建族搞起(43)

一键组网怎么操作 自动批量建族搞起(44)

同样,这个结果也是实时可调的,不过由于样条曲线运算复杂,调整起来会有点卡。

一键组网怎么操作 自动批量建族搞起(45)

我们把到此为止的成果储存为「异化版.dyn」,下载链接见文末。

05 小姐姐的需求

写到这儿有点放飞自我了,差点把小姐姐最初的需求给忘了。

之前我们实现的是方方正正的族和奇奇怪怪的族,而这个案例最终还要解决图纸上窗户族两侧的三角形。

一键组网怎么操作 自动批量建族搞起(46)

实现它并不复杂,也就是两端的点有些许偏移而已。

按照我们的顺序,是第一块嵌板的最后一点,与第最后一块嵌板的第二点。

只需要在初始版成果的基础上,加多两个参数:左端偏移与右端偏移就可以解决问题了。

➤ 先打开初始版.dyn,加两个参数:

一键组网怎么操作 自动批量建族搞起(47)

➤ 再回到我们第一次用 Python 处理完成之后的点组位置:

一键组网怎么操作 自动批量建族搞起(48)

➤ 由于 Dynamo 自带的节点更改数据十分麻烦,所以我们再请出 Python 写一个脚本,修改目前点数组中,第一组第4点,以及最后一组第2点的值,给它们做一个偏移。

Python代码如下:(同样,看不懂没关系,看看中文说明了解个大概。)

# 启用 Python 支持和加载 DesignScript 库 import clr clr.AddReference('ProtoGeometry') from Autodesk.DesignScript.Geometry import * # 该节点的输入内容将存储为 IN 变量中的一个列表。 dataEnteringNode = IN # 将代码放在该行下面 __author__ = 'Vctcn93' __date__ = 20190706 __publisher__ = 'ArchiPython' data = IN[0] # 将刚刚的数据,赋予到变量 data 中 left_offset = IN[1] # 左端偏移值 right_offset = IN[2] # 右端偏移值 point1 = data[0][3] # 拿取第一组最后一点的点坐标 point2 = data[-1][1] # 拿取最后一组第二点的点坐标 data[0][3] = Point.ByCoordinates(point1.X - left_offset, point1.Y, point1.Z) # 重新创造偏移后的点,取代原先的点 data[-1][1] = Point.ByCoordinates(point2.X right_offset, point2.Y, point2.Z) # 重新创造偏移后的点,取代原先的点 # 将输出内容指定给 OUT 变量。 OUT = data # 输出结果

在Dynamo里形成这样一个脚本,它有IN[0]、IN[1]、IN[2]三个预留的输入,作用就是「输入一组数,然后修改其中的两个,再输出」。

一键组网怎么操作 自动批量建族搞起(49)

随后将我们原始点阵连接到 IN[0]; 左端偏移连接到 IN[1]; 右端偏移连接到 IN[2]。这样就生成了我们所需要的新点阵。

➤ 新点阵通过 AdaptiveComponents.ByPoints 节点,输入到 Revit 中,我们便得到了左端偏移、右端偏移、嵌板个数、嵌板长度、嵌板高度,这五个数值可调的参数化构件了。

一键组网怎么操作 自动批量建族搞起(50)

我们把最终的成果储存为「小姐姐版.dyn」,下载链接见文末。


Vctcn93的教程结束了,最后来给你总结一下,说说我们的观点。

这个教程主要帮你梳理了三个知识点:

· 拓扑关系与自适应族的概念 · 样条曲线的 Parameter · 如何有效地使用 Python 为自己加速

打通了这几个思路,再遇到类似的幕墙、描述规律等问题,都不再会是难点了,也为今后参数化设计打下坚实的基础。

这也是他为之前在知乎上免费开源写的一系列文章《Dynamo速成大法》填的一个坑。

说起这个系列,Vctcn93已经停止更新了,原因是本来希望做开源分享的事。结果被人抄袭,还申请了原创保护,维权很难,Vctcn93一气之下就把对方还没来得及抄袭的内容全删了。

侵权真的会让人伤心的。

BIMBOX长期以来对版权非常重视,既不抄袭转发,也对抄袭者绝不姑息,加上我们有强大的小伙伴们长期帮忙投诉抄袭者,Vctcn93才愿意把这篇心血之作发布在这里。

大家最终看到的这篇东西,来自于社群里每一个人的高质量提问、不撕逼的交流氛围、对版权的共同维护、还有小伙伴们像朋友一样的彼此信任。

谢谢大家了。

发文多了,我们也会经常收到这样的评论:「你的这个不行,XXX用XXX早就实现了。」

我们一般对这类回复的态度是不抬杠、也不理会。

原因并非因为他说的不对,而是我们觉得,人的表达分为两种:

第一种是告诉你「这件事我知道」;第二种是「我想告诉给你,让你也知道。」

高水平的人,也会有低水平的分享,而我们更关注「分享」的水平。

因此,我们践行的始终是第二种表达方法。这也是从不转发、对投稿审核极严的我们愿意精编和发布这篇文章的原因。

正如Vctcn93自己所说:拒绝嘴遁,从我做起。

学习今天的教程,关于Dynamo部分如果感觉有点吃力,可以知乎搜索(一怒断更的)「Dynamo速成大法」,也可以支持一下Vctcn93与我们共同发布的视频教程《Dynamo信息可视化脚本实战》,里面有大量基础知识给你学习。

如果对Python感兴趣,想深入学习,知乎上搜索「九章Python」,是Vctcn93写的入门学习教程。

最近群里也常聊Python和Dynamo,网上动辄100G的教程资料让人望而却步,我们正在和Vctcn93计划,一起做一系列的好教程,留下最有用的东西,帮大家节省时间。

今天的教程完全免费,建议收藏随时看。Vctcn93做的三个Dynamo成果也免费分享给大家,下载链接:https:///s/1sSEfsQK_VVdFzk88RZgIsw

提取码:z808

有态度,有深度,BIMBOX,咱们下次见!

,