自动批量建族?nèng它!

 

你好,这里是BIMBOX。

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

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

事情的缘由是这样的。

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

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

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

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

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

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

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

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

但我还是不相信,这和对方是个妹子没关系。

咳咳。Anyway,Vctcn93找到我,说他觉得挖出来的知识点很有趣,单独发群里有点浪费,问我是否愿意发文分享给大家。

我问他,这个教程你想收费吗?

他不好意思地说:「等我出大点的教程吧,毕竟我也穷。不过这个教程挺小的,等我异化出更牛逼的东西来,再做成视频教程。」

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

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

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

如果你希望彻底搞明白背后的原理,我们会在文末给出更详细的学习链接,以及我们与Vctcn93的分享计划。还有,我们送出的三瓶红酒。

下面正式开始——

01 自适应族的拓扑关系

 

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

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

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

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

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

 

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

它们就变成了这个样子:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

02 Dynamo中的强大节点

 

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

AdaptiveComponents.ByPoints

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

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

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

假设我们有一个需要四个点生成的自适应嵌板,则我们先来模拟建立点的二维数组,下面的代码你不懂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 中的 CodeBlockPython 都可以直读,结果会生成一个 点阵(Points Array)

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

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

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

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

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

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

顺序非常关键。

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

03 解决问题

 

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

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

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

· 我想要那些参数?

· 未来能否扩充与异化?

· 是否有优化效率的可能?

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

· 每块面板的长度

· 每块面板的高度

· 面板的数量

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

这里需要注意两点:

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

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

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

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

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

0..#quentity..#step

 

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

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

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

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

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

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

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

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

我们将刚刚生成的两组点,使用 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中使用以上代码,把点阵处理清楚了。

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

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

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

03 异化

 

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

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

这个操作就叫异化

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

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

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

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

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

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

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

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

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

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

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

这一步是怎么来的呢?

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

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

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

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

使用 Code Block 代码:

0..1..#steps


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

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

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

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

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

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

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

04 小姐姐的需求

 

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

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

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

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

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

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

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

由于 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]三个预留的输入,作用就是「输入一组数,然后修改其中的两个,再输出」。

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

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

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

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

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

· 拓扑关系与自适应族的概念

· 样条曲线的 Parameter

· 如何有效地使用 Python 为自己加速


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

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

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

截图隐掉部分不代表BOX观点的内容

侵权真的会让人伤心的。

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

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

谢谢大家了。

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

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

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

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

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

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

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

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

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

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

当然,也会收点费,毕竟——

今天的教程完全免费,建议收藏随时看。Vctcn93做的三个Dynamo成果也免费分享给大家,下载地址:https://pan.baidu.com/s/1sSEfsQK_VVdFzk88RZgIsw
提取码:z808 

 


注:

· 本文章已经Vctcn93授权,对原稿中的文本、图片做了精排和修改,在BIMBOX公众号、知乎专栏、腾讯开放平台、今日头条等平台发布。如需转载,请联系BIMBOX小编。

· 但请大家知悉主要原创工作为Vctcn93做出,本篇原创已授权Vctcn93在其个人名下的平台号转发。

· 所有经过我们授权的平台转发,会在文章底部显示本文「转发自公众号BIM清流BIMBOX」的链接,各位小伙伴们看到善意转载的不要投诉啦~

2 条评论

  1. mahuagou

    我也想入群 怎么加入呢?

    • BIMBOX

      加小编微信 BIM_BOX

相关推荐

微信扫一扫

微信扫一扫

微信扫一扫,分享到朋友圈

自动批量建族?nèng它!