CuraEngine工作流程及代码详解

FffProcessor类:线材热熔制造处理最初阶段,对网面进行切片,分层处理。
FffPolygonGenerator类:线材热熔制造的初期阶段,生成多边形。
FffGcodeWriter类:线材热熔制造处理第二阶段,已经生成的多边形轮廓将用于Gcode的生成。

libarcus库
libarcus库包含了c++和python的类(这里没用到python),用来创建一个socket。这个socket基于protobuf,用来发送和接收信息。就是在Cura(图形界面,前端)和CuraEngine(后端)传递信息。
protobuf库
Google Protocol Buffer(简称 Protobuf) 是Google公司内部的混合语言数据标准,用于结构化数据串行化,有如XML,不过它更小、更快、也更简单,可用于通讯协议、数据存储等领域。
目前提供了 C++、Java、Python 三种语言的 API。(因此可以将protobuf代码转换成c++代码)
commandSocket类
commandsocket类主要是为了与前端通信用的。
commandsocket.h中包含了utils/socket.h和utils/socket.cpp文件
只有CommandSocket类用到了Arcus库。
CommandSocket(fffProcessor* processor)新加数据处理器
void connect(const std::string& ip, int port)连接并且注册消息类型
void handleObjectList(Cura::ObjectList* list)添加数据
void handleSettingList(Cura::SettingList* list)为处理器配置参数
void sendPolygons(cura::PolygonType type, int layer_nr, cura::Polygons& polygons)发送某层的多边形信息。
void sendProgress(float amount)发送打印进度
void sendPrintTime()向接收端发送打印信息
void beginSendSlicedObject()发送开始切片
void endSendSlicedObject()发送结束切片
void beginGCode()生成gcode之前,设置gcodewriter输出流
void sendGCodeLayer()发送一层的gcode
void sendGCodePrefix(std::string prefix)发送gcode前缀代码
切片流程概述
从总体上讲,CuraEngine 的切片分为五个步骤:
步骤一:模型载入
计算机中的 3D 模型大多是以三角形面组合成的表面所包裹的空间来表示的。三角形作为 3D 模型的基本单元,有结构简单,通用性强,可组合成任意面的特点;空间坐标中只要三个点就可以表示一个唯一的三角形,两点只能表示一条直线,而再多的直线也无法组成一个平面;空间中的任意三个不共线的点都可以组成一个三角形,而四个点所组成的四边形就必需要求四点共面;任意的表面都可以拆解成三角形,一个四边形可以拆解成两个三角形,但一个三角形确没有办法用四边形组合而成。计算机所擅长的事情就是把简单的事情不断重复,而三角形正是因为这些特性,成为了计算机 3D 世界的基石。
CuraEngine 内部也是用三角形组合来表示模型的,不过同样一个三角形组合,确有无穷多种数据结构来进行存储,CuraEngine 切片的第一步,就是从外部读入模型数据,转换成以 CuraEngine 内部的数据结构所表示的三角形组合。
有了三角形组合还不够,CuraEngine 在载入模型阶段还要对三角形进行关联。两个三角形共有一条边的,就可以判断它们为相邻三角形,一个三角形有三条边,所以最多可以有三个相邻三角形,一般而言,如果模型是封闭的,那它的每一个三角形都会有三个相邻三角形。
有了三角形的相邻关系,就可以大幅提高下一个步骤分层过程的处理速度。Cura 之所以成为当前市场切片速度最快的软件,这是其中最显著的优化之一。
步骤二:分层
如果把模型放在 XY 平面上,Z 轴对应的就是模型高度。把 XY 平面抬高一定高度再与模型的表面相交,就可以得到模型在这个高度上层切片。所谓的分层就是每隔一定高度就用一个 XY 平面去和模型相交作层切片,全部切完后就可以得到模型在每一个高度上的轮廓线。就像是切土豆片一样,把一个圆的或不圆异或不管什么奇形怪状的土豆用菜刀一刀一刀切开,最后就能得到一盘薄如纸片的土豆片。
分层本质上就是一个把 3D 模型转化为一系列 2D 平面的过程,自此之后的所有操作就都是在 2D 图形的基础上进行了。
在前面模型载入阶段说到了 CuraEngine 埋了一个三角形关联的伏笔,现在知道,两个平面相交,得到的是一条直线,一个平面和一个三角形相交,就得到一条线段。当然也有可能什么也得不到,平台平行啦,三角形的三个点都在平面的同一面之类,这些可以不管,现在只关心和平面有交集的那些三角形即可。把一个平面和所有的三角形都相交了一遍,得到了许许多多的线段,但需要的是 2D 图形,三角形是 2D 图形,四边形,任意多边形都是 2D 图形,但线段不是。所以就要把这些线段试着连成一个多边形,那么问题来了,要把这些线段连起来,只能两个两个地去试,看看它们是不是共端点了,粗算一下,每一层都是平方级的复杂度,再算上层数,那就是三次方级了。但现在,我们知道了三角形的关联关系,两个关联的三角形,如果都与一个平面相交,那它们的交线一定也是关联的,这一下,每一条线段只需要判断三它与它相邻三角形,看看与这个平面有没有交线即可,一下子就把问题的复杂度降了一个次元。速度自然可以有质的提升。
步骤三:划分组件
经过分层之后,我们得到了一叠 2D 平面图形。接下来需要做的事情就是对每一层的平面图形进行划分,标记出哪里是外墻、内墙、填充、上下表面、支撑等等。
3D 打印在每一层是以组件单位,所谓组件指的就是每一层 2D 平面图形里可以连通的区域。而打印的顺序就每打印完一个组件,接着会挑选一个离上一个组件最近的组件作为下一个进行打印,如此循环直至一层的组件全部打印完成;接着会 Z 轴上升,重复上述步骤打印下一层的所有组件。
每一个组件的打印,先打边线再对边线内部填充。边线可以打印多层,最外层的边线称为外墙,其它的统称为内墙,CuraEngine 之所以要对内外墙进行区分,是为了可以为它们定制不同的打印参数:外墙会被人观察到,所以可以采用低速以提高表面质量,内墙只是起增加强度的作用,可以稍稍加快打印速度以节省时间。这些都可以在 Cura 界面的高级选项里进行配置。
内外墙标记完之后就是填充和上下表面的标记了,填充有一个填充率,0%填充率就是无填充,100%就是打成一个密实的平面,所以上下表面就是填充率为 100%的填充。中间的填充率自然介于两者之间,就像一张渔网,填充率越高网眼越细。
软件会先把内墙里面的部分统统标记成填充,之后再进一步判断其中有哪些部分要转换成为上下表面。至于是哪些部分,在设置里会有一个上下表面层数的设置,它代表了模型的上下与空气接触的表面有几层,这里就会用到这个参数,CuraEngine 会把当前层上下 n 层(上下表面层数)取出来与当前层进行比较,凡是当前层有而上下 n 层没有的部分就会被划归到表皮。而原来的填充区域在割除被划到表皮的部分后剩下的部分就是最终的填充区域。
CuraEngine 在处理过程中大量用到了 2D 图形运算操作,有关 2D 图形的运算,有很多人研究,也被做成许多成熟的库可以调用。CuraEngine 的作者拿来主义,选取了一个他认为比较好用的库,叫 ClipperLib 的库直接内嵌到软件之中,ClipperLib 所使用的 2D 图形算法也很著名,叫 Vatti’s clipping algorithm,很复杂。
CuraEngine 所用到的几种 2D 图形的运算,都是由 ClipperLib 实现的:交、并、差、偏移。
• 图形相交 二元图形操作,最终结果为两个图形共同包含的区域。记作:A * B
• 图形相并 二元图形操作,最终结果为两个图形其中的一个或两者所包含的区域。记作:A + B
• 图形相减 二元图形操作,最终结果为属于前者但不属于后者的区域。记作:A – B
• 图形偏移(外扩) 一元图形操作,最终结果为图形区域的边界向外扩展指定的距离。
• 图形偏移(内缩)
• 一元图形操作,最终结果为图形区域的边界向内收缩指定的距离。内缩与外扩互为逆运算。
这些就是 CuraEngine 所用到的 2D 图形操作,运算不多,确可以做许许多多的事情,比如上面所说的上下表面计算,就可以用数学公式来表示:
• 表面(i) = [填充(i) – 层(i + n)] + [填充(i) – 层(i – n)]
• 填充(i) = 填充(i) – 表面(i)
• 其中,i 为当前层号,n 为上下表面层数(可以不一样)。
• 同样的,组件里面内外墙,填充怎么划分,只用一个内缩运算就可以搞定:
• 外墙 = 组件.offset(-线宽)
• 内墙 1 = 组件.offset(-线宽 * 2)
• …
• 内墙 n = 组件.offset(-线宽 * (n + 1))
• 填充 = 组件.offset(-线宽 * (n + 2))
如果模型无需支撑,那组件划分到这里就可以收工。否则,接下就是计算支撑的时间了。
CuraEngine 最大的不足就是在支撑上,CuraEngine 所用的支撑算法:
CuraEngine 首先把整个打印空间在 XY 平台上划分成为 50um*50um 的网格,每个网格的中心点再延 Z 轴向上作一条直线,这条直线可能会与组成 3D 模型的三角形相交,三角形与直线的交点以及这个三角形的倾斜度会被记录到网格里面。
现在每个网格里会记录下一串被称为支撑点的列表,每个支撑点包含一个高度和一个倾斜度信息。接下来会对每个网格的支撑点列表按照高度从低到高排序。根据这些信息就可以判断模型上任意一个点是否需要支撑了,怎么判断:
从底面开始延着一条网格中心往上走,起始是在模型外部,当遇到第一个支撑点的时候,就从模型外部进行了模型内部,称这个支撑点为进点。
继续向上,遇到了第二个支撑点,从模型内部又退到了模型外部,称这个支撑点为出点。
接着向上,可以发现,进点与出点总是交替出现的。
利用这个规律,对于模型上任何一个点,只要找到这个点所对应的网格,再找到这个网格里在这个点以上最近的一个支撑点,就可以得到两个信息:这个点之上是否有模型悬空;这个点上面的悬空点的面的倾斜度是多少。
Cura 界面的专家设置里面有支撑角度的设置,如果一个点处于模型悬空部分以下,并且悬空点倾斜度大于支撑角度,那这个点就是需要支撑的。所一个平台上所有的需要支撑的点连接起来围成的 2D 图形就是支撑区域。
CuraEngine 所使用的支撑算法比较粗糙,但胜在速度很快。先不说网格化后失去了精度,通过倾斜角度来判断,模型下方一旦倾斜角发生了突变,像左图这种从负 45 度一下突变成正 45 度,倾斜角判断无能为力,除非把它改大到 60 度,这样的话,整个模型都会被过度支撑。这样矫枉过正,既不科学,也浪费材料和打印时间,还会对模型表面质量带来不好的影响。
科学的支撑算法应该是找到模型局部最低点进行支撑,最低点以上不一定需要支撑。因为 FDM 材料本身的粘性,使得材料的走线可以有一部分悬空而不坍塌,这个效果被称为 Overhang,只要上层材料的悬空距离小于一定的值,它就不需要支撑,这个距离应该在 1/4 到 1/2 线宽之间。
支撑范围确定之后,也和组件一样,可以有外墙、内墙、填充、表面。依样画葫芦即可。CuraEngine 对于支撑,只会生成外墙和填充。
组件和支撑就是 CuraEngine 在这一步所生成的结果,这一步可以说是整个切片过程的核心。
步骤四:路径生成
这一步路径生成就要开始规划喷头在不同的组件中怎么运动。路径按大类来分,有轮廓和填充两种。
轮廓很简单,沿着 2D 图形的边线走一圈即可。前一步所生成的外墙、内墙都属于轮廓,可以直接把它们的图形以设置里的线宽转换为轮廓路径。
填充稍微要复杂一些,2D 图形指定的只是填充的边界,而生成的路径则是在边界的范围内的条纹或网格结构,就像窗帘或者渔网。这两种就最基本的结构, 当然也许还可以想出其它花式的填充,比如蜂窝状或者 S 型等。 CuraEngine 在专家设置里可以对填充类型进行选择,里面除了条纹和网格外还 有一个自动选项,默认就是自动。自动模式会根据当前的填充率进行切换,当填充率小于 20%就用条纹填充,否则使用网格填充。因为网格结构虽然更为合理,但它有一个问题,就是交点的地方会打两次。填充率越高,交点越密,对打印质量的影响会越大。表面就是 100%的填充,如果表面用网格打,不但无法打密实,表面还会坑坑洼洼,所以 100%填充只能用条纹打,这就是 CuraEngine 推荐自动模式的原因。
至于填充率,就反映在线与线的间距上。100%填充率间距为 0;0%填充率间距无限大,一根线条也不会有。
每个组件独立的路径生成好了,还要确定打印的先后顺序。顺序先好了可以少走弯路,打印速度和质量都会有提升。路径的顺序以先近后远为基本原则:每打印完一条路径,当前位置是上一条路径的终点;在当前层里剩下还没打印的路径中挑选一条起点离当前位置最近的一条路径开打。路径的起点可以是路径中的任意一个点,程序会自行判断。而路径的终点有两种可能:对于直线,图形只有两个点,终点就是除起点之外的那个点;对于轮廓,终点就是起点,因为轮廓是一个封闭图形,从它的起点开始沿任意方向走一圈,最后还会回到起点。CuraEngine 对路径选择做了一个估值,除了考虑到先近后远外,还顺便参考了下一个点相对于当前点的方向,它的物理意义就是减少喷头转弯。
路径的顺序也确定了,还有一个问题需要考虑:如果前后两条路径首尾相连,那直接走就是了,但大多数情况并非如此,前一条路径的终点往往和后一条路径起点之间有一段距离。这时候去往下一点的路上要小心了,肯定不能继续挤出材料,否则轻则拉丝,重则模型面目全非。这段路喷头就需要空走,即喷头只移动,不吐丝,那只要把挤出机停下来不转就行了吗?也不行,因为前面分析过,挤出机的速度要传导到喷嘴,有一个延迟,不是你说停它就立即停下来的。这是 FDM 打印的通病,解决办法就是回抽。所谓回抽,就是在空走之前先让挤出机高速反转一段材料,这样就可以瞬间把加热腔里的材料抽光,再移动过去,中间就不会挤出材料,到了下一个点,在打印之前,先把刚才抽回去的丝再按一样的长度放回来,继续打印。回抽可以很好地解决空走拉丝的问题,但是它很慢,以抽一次 0.5 秒来算的话,如果打印一个表面,0.4 线宽,10 厘米的距离至少回抽 25 下,10 几秒钟的时间一层,几百上千层打下来,光回抽所用的时间就是几个小时,是可忍孰不可忍!
CuraEngine 给我们提供了解决方案就是 Comb,也就是绕路。是不是所有的回抽都是必需的呢?不回抽会拉丝是肯定的,但如果需要空走的路径本来就要打印的,那拉丝又有何妨。按这个思路,就可以给每个组件设定一个边界,只要路径的起点和终点都在这个边界之内的,空走都不回抽。这样可以解决 80%的问题。
红色是起点,绿色是终点,直接走过去会走出边界的范围。这时我们就要绕一点路,走一条曲线到达目的地。这就是 Comb 所做的事情,在 Cura 专家设置里面可以对 Comb 进行设置,选择开启、关闭还有表面不 Comb。Comb 可以大幅节省打印时间,但是同一个地方打印多次对模型质量还是会有细微的影响,个中利弊,交给用户自己判断。
步骤五:gcode 生成
路径都生成好了,还需要翻译对打印机可以实别的 gcode 代码才行。这一步花样不多,按部就班即可。
先让打印机做一些准备工作:归零、加热喷头和平台、抬高喷头、挤一小段丝、风扇设置。
从下到上一层一层打印,每层打印之前先用 G0 抬高 Z 坐标到相应位置。
按照路径,每个点生成一条 gcode。其中空走 G0;边挤边走用 G1,Cura 的设置里有丝材的直径、线宽,可以算出走这些距离需要挤出多少材料;G0 和 G1 的速度也都在设置里可以调整。
若需回抽,用 G1 生成一条 E 轴倒退的代码。在下一条 G1 执行之前,再用 G1 生成一条相应的 E 轴前进的代码。
所有层都打完后让打印机做一些收尾工作:关闭加热、XY 归零、电机释放。
生成 gcode 的过程中,CuraEngine 也会模拟一遍打印过程,用来计算出打印所需要的时间和材料长度。
切片程序的主要过程如下:
• 导入 3D 模型(STL,OBJ 等等)。
• 分析并修复 3D 模型。
• 将 3D 模型切割成 2D 层。
• 用上一步得到的 2D 图层形成 LayerParts,因为一层里面,很有可能有很多个不同的多边形,比如桌子,他的四个角,切出来后是四个圆形,上一步中只是得到了四个圆形,而没有确定这四个圆形是属于同一层的。
• 进一步确定 LayerParts 中,各个 part 间的关系,比如得到了两个圆,大圆套小圆,我们就需要确认,小圆是空心的,而大圆和小圆形成的圆环是实心的。
• 将需要实心打印的部分标记出来(100%填充)。
• 将需要空心打印的地方打印出来(部分填充)。
• 根据生成的 LayerParts 生成每一层的 G-code。
上述的每一步都有更多的逻辑关系在里面,但这只是一个工作的大概流程。切割引擎所有的数据都存放在一个叫 SliceDataStorage 的类里面。上述的每一步都是基于前一步的数据来进行的。这里严格按照上述的流程来处理 3D 模型生成 G-code。另外,在代码里面,坐标是用 64 位整数的形式存在的,代码中看到的 1000,他实际代表了 1mm。这样做是因为 Clipper 使用了 64 为整数来表示距离。
源码中的几个类:
Mesh类 (之前版本称为OptimizedModel类)
Mesh(OptimizedModel )也是一个 3D 模型,只是他是对一开始导入的模型进行的优化,去除了 3D 模型中多余的数据,同时确立了 3D 模型中每个三角面之间的拓扑关系。这是整个软件最为核心的一部分之一。他为后面一步进行切割做好了准备,没有他 slice 无法进行。
MeshGroup类 网面组是一个或多个3D网面的集合
void MeshGroup::finalize finalize 对网面组的偏移进行最终定位应用
bool loadMeshSTL_ascii加载ascii形式的stl模型
bool loadMeshIntoMeshGroup从文件中加载一个网面模型并存储打到网面组中
Slicer类
我们通常都把由 3D 模型生成 G-code 的过程叫做 slicing.在 CuraEngine 中,Slicer 只是数量很小的一部分代码,用于生成 layers。每个 layer 都有闭合的 2D 多边形。这些多边形的形成有两步。
第一步,用一个切割平面同所有三角形做相交运算,得到和这个平面相交的线段就是属于这个 layer 的,这些切割后得到的线段称之为”linesegment”。此时,layer 里面只是有一些零散的线段。
第二步,将这些 linesegment 连起来,形成封闭的多边形。
由于 Mesh(OptimizedModel) 已经将各个相邻三角形之间的关系确立好了,这里的 slice 速度变得很快。在进行完 slice 之后,就得到了封闭的多边形曲线,这些曲线,要交给 Clipper 库来进行下一步的处理。Clipper 库只能用于处理 2D 的封闭多边形模型。
LayerParts
LayerParts 是需要掌握的一个重要概念。LayerParts 是一个单独的 layer 中的一部分。比如,切割一个正方体,只会得到一个 LayerPart,但是,如果切割一个桌子,这个桌子有四个脚,就会得到四个切面,也就是四个 LayerPart,把这在同一平面的四个 LayerPart 称为 LayerParts。在生成 G-code 的过程中,都是对每个 LayerPart 单独操作,避免了打印机在两个 LayerPart 之间打印多余的东西。同时也减少了喷头运动的距离。为了生成 LayerPart,要使用到 Clipper 库。
Skin类
这部分的功能是确定模型中,需要完全被填充的部位,这里大量使用了 Clipper 库里面的布尔运算。看 Cura 的代码会发现,这里的 skin(完全填充)和 sparse fill(稀疏填充)的代码是几乎一样的,只是设置了不同的填充比例而已。注意,这一步只是标记了需要填充的区域,真正的填充操作是在下面一步生成 G-code 的过程中进行。
G-code 生成器
G-code 生成器有非常多的代码,这里给出他主要的几个点:
PathOrderOptimizer:这部分代码是路径优化代码,计算最优路径。提供很多边形,然后找到最好的顺序和最好的路径来走完他们。比如,打印完这一个 LayerPart 后,需要找到下一个离他最近的 LayerPart 多边形来打印
Infill:这部分代码会在一个区域里生成一组线。
Comb:这部分的代码,是为了避免在打印机不喷丝时移动喷头而不会同打印好的层发生接触从而产生一些不好的洞。
GCodeExport:导出 G-code 分为两个步骤,首先,他将需要打印的那一层(layer,不是 LayerPart)的所有路径收集起来,包括移动,打印,挤出宽度等。然后生成最终的 G-code。只有这一部分的代码是和 G-code 直接相关的。要生成不同的 G-code,只需要在这里做少量的调整即可。另外,对模型体积的计算,也是在这一步中计算出来的。
Insets:有时又叫做”Perimeters”(围墙)或者 “Loops”(环圈)。处理这个 clipper 做了大部分的工作。

Clipper 类
clipper 是一个提供图形切片(clipping)和偏移(offse)的二维图形库。切片类型包括交(intersection)、和(Union)、差(difference)、异或(xor)运算。
preserveCollinear 对在同一条线段上的点是否进行简化处理。
reverseSolution 跟切片后路径的方向相关。
StrictlySimple
• simple polygon 是不自交的。
• weakly simple polygon 包括了重合的顶点或者接触的边线。
• strictly simple polygon 不包括重合或者接触的顶点、边线。
PolyFillType 指定了对路径的填充方法
ArcTolerance: 圆角的精度。
MiterLimit: 为了防止尖角处延伸过大,这个参数指定最大的延伸量
joinType 路径偏移后的形状类

path(contour)指的是一组有序的顶点,组成了未封闭路径(open path)或者闭合路径。Polygon在平面内一个闭合的不自交的轨迹。不自交指的是路径轨迹上的任意线段不相交。
polygon类polygon 等类对 clipper 进行了封装,使其更好得满足二维平面上的运算操作。
class ConstPolygonRef多边形的常引用,外轮廓应该逆时针,内轮廓应该顺时针
PolygonRef 类
int64_t polygonLength() const;多边形的周长
void translate(Point translation)多边形在平面上根据 translation 矢量偏移量。
bool inside(Point p, bool border_result=false)点 p 是否在区域内。返回是否、或者 border_result(即在边界上)
void smooth(int remove_length, PolygonRef result) 当小于 remove_length 时将点从多边形中移除。
void simplify(int allowed_error_distance_squared, PolygonRef result) 如果三点几乎呈一条直线,将中间点移除
Polygons 类
包含了一个 ClipperLib::Paths 类的成员 ploygons。
交、和、差、异或、偏移运算的封装。
对一组 polygon 的 smooth、simplify。
根据 even-odd 填充原则分组,所得每个 polygons 中的第一个 polygon 为 outline,其他都是 holes。
PolygonsPart类
包含 holes 的区域。第一个 polygon 是 outline,其他的都是 holes 在 outline 内。hole是封闭的轨迹。内部不标记填充。
Polygon filling rule对任意一组闭合多边形,指定哪些需要进行填充。
AABB 类 一个多边形在平面区域内范围的矩形。
intpoint类:
vSize2离原点距离的平方 vSize离原点距离
testLength 顶点距离原点值不能大于lenth
angle与x正半轴夹角,角度制
crossZ绕原点逆时针旋转90度
Point apply(const Point p) const //点p左乘矩阵
Point unapply(const Point p) const //点p右乘矩阵

  1. Point3 类(定义在 intpoint.h)
    该类定义了点得三维坐标,坐标值是三个 int32 类型,x y z
    定义加、减、数乘、数除 d、点积、相等、不等 方法,
    IntPoint 类(intpoint.h) 和 Point
    这个类是用在 ClipperLib 中的。Clipperlib 处理二维封闭图形。
    因此有两个变量 x 和 y。
    PointMatrix 类(intpoint.h)
    成员变量 matrix[ 4].是一个二维矩阵。
    FPoint3 类(floatpoint.h)
    基本与 Point3 完全一样,用 float 类型
    FMatrix3x3 类(floatpoint.h)
    跟 PointMatrix 一样。
    时间类
    Timekeeper(gettime.h)
    只有 starttime 这个变量,
    restart()方法重启定时器,返回所用时间。
    TimeEstimatecalculator 类(timeEstimate.h)
    这个类估算打印所需的时间。
    成员变量:
    Position 类
    定义打印点所处位置
    Block 类
    记录打印机参数。
    方法
    setPosition(Position newPos) 设置打印位置
    reset() 清空打印位置
    void plan(Position newPos, double feedRate) 对新位置点,新的进料速度进行配置
    double TimeEstimateCalculator::calculate() 返回运动时间
    配置类
    SettingConfig
    直接从 json 文件 json 读取配置的类,Single setting data.有以下成员变量,跟 json 文件项一一对应。
  2. std::string label;
  3. std::string key;
  4. std::string type;
  5. std::string default_value;
  6. std::string unit;
  7. SettingConfig* parent;
  8. std::list children;
    各种 get,set 方法,
    addchild 方法递归添加一个键值。
    CettingCategory
    包含多个子配置 Contains one or more children settings.
    基本与 SettingConfig 一样。
    SettingRegistry
    注册类。包含所有的配置设定 This registry contains all known setting keys.
    Mesh 类
    mesh 即网状物,是 stl 转换成的数据结构。
    MeshVertex 类
    记录 mesh 中 vertex 顶点,相邻面片索引(face)。
    MeshFace 类
    meshFace 是有三个顶点的面片模型,一个面片因为是三角形,所以邻接了三个其他的面片。
    PrintObject 类(modelFile.h)
    该类是多个 mesh 的集合(成员变量 meshes)。由于可能一次有多个 STL 文件会被打印。

fffProcessor 类
getMeshgroupN获取当前正在处理的网面组编号
FffPolygonGenerator polygon_generator多边形生成器,它会切片所有模型,然后生成所有打印区域的多边形
FffGcodeWriter gcode_writer Gcode输出器,为层规划生成路径到缓冲,然后转换这些路径到gcode命令
meshgroup_number当前正在被处理的网面组编号
getAllSettingsString获取当前正在处理的网面组的设置
string profile_string = ""一个包含了所有引擎设置参数的字符串,外部传入
processMeshGroup(MeshGroup* meshgroup) 处理网面组,开始切片
polygon_generator.setParent(meshgroup)初始化多边形生成器
gcode_writer.setParent(meshgroup)初始化G代码生成器
SliceDataStorage storage(meshgroup) 切片数据存储器
FffPolygonGenerator 类线材热熔制造的初期阶段:生成多边形
生成多边形,模型已经切片,切片的产生的多边形就是外轮廓内轮廓,两者之间的就是打印对象,切片结束后,层已经处理好了;例如外壁填充生成了,所有的支撑和填充区域生成了。在这个阶段,除了区域和循环路径(用多边形表示)之外,没有其他的东西生成。没有填充线和支撑样式生成。在这里生成了多边形。 模型被切片,每片由代表轮廓的多边形组成,——轮廓包括模型的内部和外部的边界。切片后,layers 产生。比如 wall insets 围墙 ,要填充为 support 的区域,稀疏填充的区域。这里都由 polygon 表示了。
bool generateAreas由 outline 生成 polygons,包括 inset,support 等
getDraftShieldLayerCount设置限制实际打印高度
sliceModel切片生成 outline给模型(\p object)切片,并将外轮廓存储在(\p storage)中。模型进行切片。调用了slicr类
slices2polygons处理外轮廓信息并存储在(\p storage):生成 填充路径 支撑路径,操作生成的 inset ,support 多边形。
processBasicWallsSkinInfill处理外轮廓信息并存储在(\p storage):生成 绕边 皮肤 填充
processOutlineGaps最外圈墙和次外圈墙之间并不贴合的间隙区域,这些区域应该被类似于皮肤的东西填充,这些东西是是一根变宽的皮肤线
processPerimeterGaps除最外圈墙外,剩下的墙之间不贴合的区域
processInfillMesh处理 填充选择网面:限制所有在这外轮廓中的普通网面的填充,并且将这一部分从普通网面的区域中移除
processDerivedWallsSkinInfill处理由基础外墙,皮肤,填充等推导出来的特性: 模糊皮肤 结合填充
isEmptyLayer检查层是否是空的
removeEmptyFirstLayers移除所有的空底层
computePrintHeightStatistics计算打印的高度统计
processInsets生成墙壁的填充多边形操作由 wall 外墙 outline 生成的 inset 多边形
processOozeShield生成渗出保护
processSkinsAndInfill产生皮肤区域操作某层的 skin(即需要被完全填充的部分)
processDraftShield生成应在草图屏幕所在的多边形。
processPlatformAdhesion生成平台附着
processFuzzyWalls使外壁(皮肤)模糊(抖动)
FffGcodeWriter类热熔线材堆叠的第二个步骤: 已经生成的多边形轮廓将用于Gcode 的生成,在SliceDataStorage中一些多边形轮廓代表的特殊区域会被平行线填充,其他多边形代表的轮廓会被打印出来,这个类的主要函数是 FffGcodeWriter::writeGCode()
gcode.preSetup(storage.meshgroup); 初始化Gcode相关的参数
gcode.resetTotalPrintTimeAndFilament();重置所有的时间计数
gcode.setInitialTemps(*storage.meshgroup, getStartExtruder(storage));设置喷头和热床的初始温度
setTargetFile设置要将gcode写入文件的目标。
setTargetStream设置要将gcode写入的目标:输出流。
getTotalFilamentUsed获取特定挤出机的总挤出体积,单位为mm^3
getTotalPrintTimePerFeature获取每个功能的估计总打印时间(秒)
setConfigFanSpeedLayerTime(storage); 设置喷嘴风扇的速度和层的最小冷却时间
setConfigCoasting(storage); 设置每个喷嘴的惯性泄露参数
setConfigRetraction(storage); 设置每个喷头的回抽参数
layer_plan_buffer.setPreheatConfig设置每个喷嘴的材料温度
getStartExtruder获得最先开始打印的挤出机,一般这里是打印附着增强物的挤出机,但是可能存在没有平台附着的情况,此时,打印层号越低的挤出机就是初始挤出机
setInfillAndSkinAngles设置填充角度和皮肤角度到SliceDataStorage中,这些角度列表被循环利用到特定的层中
processStartingCode设置温度和初始线材装填,写入一个副头部如果引擎的是命令行模式
processNextMeshGroupCode从已经打印过的网面组上移动到下一个网面组
processRaft将raft层计划添加到FffGcodeWriter::layer_plan_缓冲区
processLayer将图层的多边形数据转换为FffGcodeWriter::layer_plan_缓冲区上的图层平面,如果层号为负数,则只创建包含辅助部件(支撑等)数据的层,以填补筏板和模型之间的间隙。
getExtruderNeedPrimeBlobDuringFirstLayer此函数用于检查第一层上的任何挤出机是否应发生质点。启动总是会发生,但实际启动可能包括或不包括一个主块。从技术上讲,此功能检查是否有任何挤出机需要在使用前单独启动(带有主块)。
ensureAllExtrudersArePrimed所有未涂底漆的旧挤出机的计划底漆
processSkirtBrim如果尚未添加裙子或帽檐,请将其添加到层平面图gcodeLayer中。应仅对一个层调用此函数;对多个层调用此函数将导致裙子/帽檐打印在多个层上。
processOozeShield将软泥屏蔽添加到层平面图gcodeLayer。
processDraftShield将草稿保护屏幕添加到层计划gcodeLayer。
calculateExtruderOrderPerLayer计算出每一层喷嘴的打印顺序,在extruder_order_per_layer 为普通层存储挤出机的顺序,在extruder_order_per_layer_negative_layers中存储 raft/filler 的喷嘴打印顺序,只有会被用到的挤出机才会被加入计划,在规划阶段,我们只有区域信息,并不知道他们是如何填充的,如果一个区域太小而不能被填充,它就会被特殊对待
getUsedExtrudersOnLayerExcludingStartingExtruder获取在给定层上使用的挤出机列表,但不包括给定的启动挤出机。当它位于第一层时,也将考虑基本blob。请注意,在规划阶段,我们仅提供有关区域的信息,不是如何填充的。如果一个区域太小,无法填充任何东西,它仍然会被指定为与挤出机一起用于该区域。
calculateMeshOrder 计算出使用指定挤出机打印网面的顺序情况,每一个网面有些特征需要被此喷嘴打印就会被包含在顺序中能够,一个网面会出现在多个挤出机的网面顺序列表种
addMeshLayerToGCode_meshSurfaceMode在“网格曲面”模式下,将单个网格体积中的单个层添加到“层平面”gcodeLayer。
addMeshOpenPolyLinesToGCode将打开的多段线从单个网格体积中的单个图层添加到图层平面模式中,以便对曲面模式进行网格划分。
addMeshLayerToGCode将给定挤出机的所有功能从单个网格体积的单层添加到层平面图gcode层。这会将此网格的所有特征(如墙、蒙皮等)添加到使用挤压机打印的gcode中
addMeshPartToGCode将给定挤出机的所有特征从给定网格体积层的单个零件添加到层平面图gcode层。这只会添加使用挤压机打印的功能。
processInfill为图层平面中的给定零件添加内嵌。
processMultiLayerInfill为图层平面中的给定零件添加较厚(多层)的稀疏内嵌。
processSingleLayerInfill为层中的给定部分添加标准稀疏填充。
processInsets为给定图层零件的墙生成插入。
processSpiralizedWall为给定的层零件生成螺旋墙。
processOutlineGaps添加轮廓间隙的gcode:单个perimter不适合的薄零件区域。
processSkinAndPerimeterGaps添加给定零件顶部/底部蒙皮和周长间隙的gcode。周长间隙用于处理蒙皮轮廓,并在通过调用processSkinPart打印蒙皮部分的蒙皮填充后打印。墙之间的周长间隙随后添加到gcode。
processSkinPart添加给定蒙皮部分的顶部/底部蒙皮和周长间隙的gcode。如果当前挤出机打印了以下特性,则周长间隙由当前挤出机处理。
*-皮肤轮廓
*-屋顶(如果同心)
*-顶部/底部(如果同心)
它们都是在使用该挤出机打印的蒙皮零件特征打印结束时打印的。请注意,正常的周长间隙是用外壁挤出机打印的,而新生成的周长间隙是用打印特征并生成间隙的挤出机打印的。
processSkinInsets添加额外的蒙皮墙
processRoofing加上屋顶,这是最里面的皮肤插入区域,它有空气“直接”在周长间隙之上,当图案同心时,这些间隙就产生在这里,但此处不打印,因为同时打印所有周长间隙更有效。皮肤轮廓墙已经有一些周长间隙。此功能为屋顶同心图案添加更多周长间隙。间隙将填充为同心周长间隙,这样我们可以在所有间隙之间选择最快的路径此蒙皮部分的周长间隙。
processTopBottom加上正常的皮肤填充,这是最里面的皮肤插入没有空气直接在上面,如果我们打印屋顶周长间隙产生时,图案是同心的。这些间隙在此处生成,但在此处不打印,因为同时打印所有周长间隙更有效。皮肤轮廓墙已经有一些周边间隙。此函数为蒙皮同心图案添加更多周长间隙。这些间隙将填充在同心周长间隙中,这样我们可以在该蒙皮零件的所有周长间隙之间选择最快的路径。
processSkinPrintFeature处理密集的蒙皮特征,如屋顶或顶部/底部
processPerimeterGaps使用给定的挤出机添加网格的周长间隙。
getSeamAvoidingLocation查看是否可以通过移动到一个起点来避免在多个分段中打印线条或锯齿样式的蒙皮部分,该起点将增加在单个分段中打印蒙皮的机会。显然,如果蒙皮部分包含孔,则无论如何都必须将其打印成多个部分,但这样做可能仍然会产生较少的蒙皮接缝,或将穿过零件中间的接缝移动到不太明显的位置
processIroning添加熨烫顶部表面的g代码。这会产生额外的低挤压移动,覆盖上表面,以便更平滑的表面。
addSupportToGCode将支持添加到当前层的层计划gcodeLayer
processSupportInfill将支撑线/墙添加到当前图层的图层平面图图层。
addSupportRoofsToGCode将支撑屋顶添加到当前图层的图层平面图gcodeLayer。
addSupportBottomsToGCode将支持底部添加到当前层的层平面图gcodeLayer。
supportInterfaceFillAngle简要给出了支撑界面填充的角度,该角度取决于它使用的是哪种模式,在某些模式下,它在层之间交替。
setExtruder_addPrime更换新的挤出机,如果新的挤出机与上一个不同,则添加主塔说明。在第0层上,此功能为其切换到的喷嘴添加裙板,而不是主塔。
addPrimeTower为当前层添加基本塔gcode。
finalize添加结束gcode并将所有温度设置为零。
findLayerSeamsForSpiralize为每一层计算被认为是接缝的顶点的索引
findSpiralizedLayerSeamVertexIndex计算被认为是给定层接缝的顶点的索引
layer_plan_buffer.setPreheatConfig(*storage.meshgroup);设置每个喷嘴的材料温度
processStartingCode(storage, start_extruder_nr); 输出打印起始命令 准备起始喷嘴
processNextMeshGroupCode(storage);为下一个网面的打印避让和准备热床
setInfillAndSkinAngles(mesh); 设置网面不同的填充的角度
gcode.writeLayerCountComment(total_layers);输出总打印层数
calculateExtruderOrderPerLayer(storage); 计算出每一层喷嘴的打印顺序
calculateMeshOrder计算出使用指定挤出机打印网面的顺序情况

sliceModel 函数
在 sliceModel 函数中,首先对用 Slicer 对 meshes 进行切片。输出切片层数 layer count,切片时间 sliced model in … 。之后,meshes 中数据就存在 slicerlist 中。由于此时 meshes 已经没用了,可以 clear 掉。
再通过 createLayerParts 方法将 sliceList 中数据转变成 meshStorage 中的 layParts。(说明:layer-part 是生成实际数据的第一步。它用到了 slicer 之后的一堆没有顺序的多边形数据,把他们组成有序的组(即 part),parts 则代表在 2D 层中可能有孔洞的孤立区域。
LayerParts 是需要掌握的一个重要概念。LayerParts 是一个单独的 layer 中的一部分。比如,切割一个正方体,我们只会得到一个 LayerPart,但是,如果切割一个桌子,这个桌子有四个脚,我们就会得到四个切面,也就是四个 LayerPart,我们把这在同一平面的四个 LayerPart 称为 layer。在生成 G-code 的过程中,都是对每个 LayerPart 单独操作,避免了打印机在两个 LayerPart 之间打印多余的东西。同时也减少了喷头运动的距离。为了生成 LayerPart,我们要使用到 Clipper 库。
• 由于此步骤产生的数据量较大,对没有再用的数据要及时清除。
• 根据有无 raft 基座类型对模型进行 z 方向的偏移。
• 最后输出产生 layer parts 所用时间
slices2polygons 函数
• 先将为空的开头几层移除-> 处理 insets(processOozeShield)-> 处理 support(generateSupportAreas) ->处理 skins(processSkins,combineSparseLayers 合并稀疏层)-> 处理 wipeTower(processWipeTower) -> 处理平台附着(processPlatformAdhesion)
sliceDataStorage 类
class SkinPart皮肤部件 层中的上下表面
PolygonsPart outline;外轮廓
std::vector insets; 绕周填充
Polygons perimeter_gaps;绕线间隙
Polygons inner_infill; 内部填充区域
Polygons roofing_fill; 上表面区域
class SliceLayerPart切片层部件 是单个闭合的孤立打印区域,他会在(FffProcessor.processSliceData(.))时被填充,最后被(FffProcessor.writeGCode(.))转换成gcode
AABB boundaryBox; 边界框
PolygonsPart outline; 部件的原始外轮廓
Polygons print_outline; 实际的打印外轮廓(考虑到线宽,会偏置,造成小细节丢失)
std::vector insets; 内墙绕周填充部件
Polygons perimeter_gaps内墙间隙
Polygons outline_gaps; 皮肤与外墙的间隙
std::vector skin_parts;皮肤部件
Polygons infill_area原始的填充区域(非墙壁,表面部分
std::optional infill_area_own自己的填充区域,需要被(0-99%)密度填充
class SliceLayer切片层类包含了所有的切片数据数据
printZ; 层的打印高度(考虑到喷嘴挤出间隙)
thickness; 层厚
Polygons openPolyLines;层中的开多段线
TopSurface top_surface; 层的顶面部分
class SupportLayer支撑作用的层
class SupportStorage支撑信息存储类
class SliceMeshStorage : public SettingsMessenger网面的切片信息,可代理使用网面的设置参数
SubDivCube* base_subdiv_cube; 基本的区分立方体
RetractionConfig类 回抽丝的配置类,
GcodePathConfig 类 打印过程和移动过程的参数配置类
Weaver 类 主要的 编织器 线打印 线框打印 类,用于计算基础的打印路径
void weave(MeshGroup* objects); 为薄壁打印规划路径
void connect连接两个多边形,链化第二个多边形同时从它生成连接器,支撑多边形是第一个
void chainify_polygons转换(链化)多边形列表,最后它们将由统一长度(\p nozzle_top_diameter)的线段或者链接组成,函数的大概作用就是 将不等长的线段全部等长化
void connect_polygons主要的编织函数,在两个多边形中间生成连接器,连接器有由纵横交错的之字线组成,横之字线是从多边形(\p supported)上的一个点(a)朝某个方向到自身最近的一个点(b)之间的连线(大距离),纵之字线是对角连接线,从横线的点(b)出发,沿着多边形(\p supported)的轮廓方向走一段距离(Weaver::nozzle_top_diameter)到自身点©(小距离)
void createHorizontalFill创建水平的顶部和底部或平面的填充
void fillRoofs用(\p supporting)填充顶部轮廓,被填充的区域是( \p to_be_supported , \p supporting )的差集,大致步骤就是:首先计算出顶面的轮廓,再将这个轮廓生成一圈一圈(偏置)的填充路径。
void fillFloors用(\p supporting)填充层平台轮廓,被填充的区域是(\p floors)等于( \p to_be_supported , \p supporting )的差集
void connections2moves过滤掉小距离的连接,用移动代替

• FffPolygonGenerator 类中 ,
• sliceModel 方法调用了 Slicer 切片,调用了 CreateLayParts 转换成 平面封闭多边形(此时的多边形只是孤立的,相互没有关系)。
• 用 createLayerParts 方法将平面封闭多边形转换成 LayerParts。
• 再通过 slicers2polygons 方法,先将为空的开头几层移除-> 处理 insets(processInsets)->处理溢出保护层(processOozeShield)-> 处理 support(generateSupportAreas) ->处理 skins(processSkins,combineSparseLayers 合并稀疏层)-> 处理 wipeTower(processWipeTower) -> 处理平台附着(processPlatformAdhesion)
• processInsets 调用了 generateInsets
• processSkins 调用了 generateSkins,generateSpares,generatePerimeterGaps
• processPlatformAdhesion 调用了 generateSkirt,generateRaft
Slicer 类 生成的多边形是没有顺序和结构的。
class SlicerSegment切片的线段
class ClosePolygonResult 闭合多边形结果,表示找到闭合多边形上的一个点
class GapCloserResult间隙闭合结果
class SlicerLayer切片层
void makePolygons将层里面的切线段连接成多边形
void makeBasicPolygonLoops将不需要缝合的多边形闭合成圈(不做线段缝合操作)
void makeBasicPolygonLoop把线段连接成一个闭合圈,从tart_segment_idx 的线段开始
int getNextSegmentIdx得到将现在这条线段结束点作为起点的线段,以便于构建闭合多边形,如果线段连接着切片层的起始线段则返回 ASAP。
void connectOpenPolylines连接非闭合的折线,因为模型并不总是完美的网面结构,我们需要一些连接补充以便于得到正确的多边形组。首先连接缝隙不超过2微米的折线,这一步将会处理完所有的非闭合折线。
void stitch衔接所有丢失终点,首先闭合间隙最小的.这是一个低效率的实现,它的时间复杂度是 O(N* N* N)
void stitch_extensive尝试闭合多段线到多边形中,即使他们的间隙很大
class Terminus brief 界点类表示多边形的起点或终点
bool operator<(const PossibleStitch &other) const; 重载排序运算符,通过缝合可能性的好坏决定顺序
static Index endIndexFromPolylineEndIndex从多段线的终点(索引号)计算界点 的终点(索引号)
findPossibleStitches按好坏程度找到可以闭合的折线
struct PossibleStitch表示两个多段线缝合的可能性大小
struct StitchGridVal缝合网格的数据元 表示折线的终点。
struct StitchGridValLocator缝合网格定位器 返回折线的结束点
planPolylineStitch计划多段线缝合的最佳方法。
joinPolylines将polyline_1连接到polyline_0。
connectOpenPolylinesImpl连接尚未封闭的折线,任何被这个函数处理后闭合的多边形会被加入到层的多边形组,所有满足 distance 和 reversal 标准的折线都会被处理. 该功能将不会引入相同折线段的任何副本。
TerminusTrackingMap跟踪折线终点位置(终点)的移动
findPolygonGapCloser找到最接近的多边形
findPolygonPointClosestTo找到靠近给定顶点的多段线的起点或终点
int tryFaceNextSegmentIdx从与面A的相邻面B中找到线段的相连切片线段
getNextSegmentIdx找到相邻的下一条切线段
class Slicer切片器类
SlicingTolerance切片公差
三种切片模式:Middle Exclusive Inclusive其中Middle 就是按照层的中心位置切片,Exclusive,Inclusive 按照层的起始位置切片,最终的切片结果需要结合下一层做分别做 交,并运算
LayerPart类
layer-part 产生的步骤是实际产生 3D 打印数据的第一步。把 slice 得到的无序的多边形变成一组“part”,不过仍然有可能有孔洞。part 中所有的 element 在移动到下一层之前都会被打印。
createLayerWithParts将一层的的切片 layer 的数据整合到 storage 中。
createLayerParts创建层部件,对每层调用 createLayerWithParts 方法,得到有序的 layer。并且每层整合完成后显示 layerparts +层数
InsetOrderOptimizer类 插入顺序优化器的构造函数
findAdjacentEnclosingPoly给定一个插图,搜索一个插图集合以查找相邻的封闭插图
processHoleInsets 优化排序后,为给定层零件的孔生成插图。
processOuterWallInsets优化排序后,生成给定层零件外壁的插图。
moveInside生成从当前位置到零件内部的行程。这是在生成外壁之后使用的,这样如果紧随其后发生缩回,则挤出机将不会在外壁上。
processInsetsWithOptimizedOrdering优化排序后,为给定层零件的所有壁生成插图。
optimizingInsetsIsWorthwhile测试优化给定图层零件的插入顺序是否值得。
Mold类 模具,为模型生成为一个模具,使得模型可以被铸造,转换(\p storage)中的闭合或者非闭合多边形为模具网面,以便于 使用外轮廓的形状来 制作一个模具。这些模型的非闭合多边形也被用来勾勒外轮廓形状并放到模具中。
MultipleVolumes类 这个文件包含着辅助修复多模型打印的方法
carveMultipleVolumes移除重叠的体积,遍历所有的打印体,将先前打印体于现在打印体重合的轮廓移除,这样就没有重叠区域了,让打印体两两求交,再切除一份重叠的区域。
generateMultipleVolumesOverlap每层扩展一点点,然后保持额外的重叠部件与其他体交接,这会在双喷头生成一些重叠,让接触的部件结合的更好
carveCuttingMeshes函数的作用就是,移除普通模型中的被选中部分,存储到区域选择模型中。排除所有的重叠体积,多模型打印在体积重叠的地方,删除一个模型的重叠区域。
ConicalOverhang类 改变模型的形状使它变得可打印,或者使用更少的支撑,改变模型的切片数据,使得模型更加适合打印
ExtruderTrain类 挤出机设定参数
FanSpeedLayerTimeSettings 关于风扇速度以及层冷却时间的设置
GCodeExport类Gcode输出类,这是唯一知道gcode长啥样的类,任何自定义Gcode风格的修改都在这个类里操作
GCodePathConfig类GCodePathConfig是移动/挤压动作的配置。 这定义了打印线的宽度和速度。
LayerPlanBuffer类类用于缓冲多个层中的层规划(\ref LayerPlan) / 挤出机规划 ,因此温度命令可以在早期的层规划中使用。这个类可以处理的温度命令: 初始层温度、流动依赖的温度、从待机温度开始加热、初始打印温度 | 打印中温度 | 最终打印温度
PathOrderOptimizer类 实用程序类,用于通过最小化打印层中不同部分之间的移动距离来优化路径顺序。优化多边形的顺序,选择每个多边形内的起始点。
Preheat类 用于计算加热和冷却的时间的类, 参与打印时间评估计算
PrimeTower类所有有关于擦料塔的类,生成区域,检查擦料塔应该打印的高度,生成路径,并添加到层规划中
Skin类 主要用来划分皮肤和填充区域的
class SkinInfillAreaComputation皮肤 和 填充 区域的计算函数
getSkinLineWidth计算皮肤线宽
getWallLineWidth0计算最外层壁线宽
getWallLineWidthX计算墙壁线宽
getInfillSkinOverlap计算皮肤和填充的重叠
getWalls得到所有与多边形(\p part_here)相交的层中部件外轮廓
getReferenceWallIdx获取顶部或底部蒙皮的参考墙的墙索引。用户指定的预收缩越大,参考墙索引越低。
generateSkinsAndInfill生成皮肤区域和填充
generateSkinInsetsAndInnerSkinInfill(&part);生成皮肤绕周填充线,与内部填充去区域
generateRoofing(part);生成上表面区域
calculateBottomSkin计算下表面皮肤
calculateTopSkin计算上表面皮肤
applySkinExpansion应用皮肤层扩展,将皮肤融合进填充区域
generateInfill生成填充区域,没有生成填充线
generateRoofing计算“直接”在空气中的面积。
generateSkinInsets为皮肤部件生成皮肤填充
generateInnerSkinInfill为皮肤的内部填充区域生成填充
combineInfillLayers为指定网格合并多个层的填充。
generateGradualInfill生成填充区域,从上到下导致填充结构的密度逐渐降低。
SkirtBrim类 用于生成裙边
WallsComputation类 计算外壁填充
Wireframe2gcode类 为线框打印做gcode输出

Infill类 对区域进行填充,生成填充线。
EFillMethod //填充方法选项
EPlatformAdhesion //最底层与工作台的粘合形态
ESupportType //支撑类型
Polygons difference求轮廓差集
Polygons unionPolygons轮廓求合运算 联合所有的多边形
Polygons intersection轮廓求交运算
Polygons offset轮廓线偏置
start_segment此填充线的起点所属的多边形线段。
start_polygon填充线的起点属于哪个多边形。
computeScanSegmentIdx函数,返回给定x坐标的扫描线
void generate产生填充
class SierpinskiFillProvider谢尔宾斯基填充提供器 生成支撑的填充样式,这个类决定最大递归深度,初始三角形和通用的填充配置 后面会在生成填充时用到
void generateConcentricInfill(Polygons& result, int inset_value);生成稀疏同心填充。
inset_value每个连续的两个多边形之间的偏移量
void generateConcentricInfill(Polygons& first_wall, Polygons& result, int inset_value);从特定外墙开始生成稀疏的同心填充
void generateConcentric3DInfill(Polygons& result); 生成稀疏同心填充。
generateGridInfill生成填充线的矩形网格
generateCubicInfill生成填充线的移动三角形网格,该网格与连续的层组合成一个立方体图案
generateTetrahedralInfill生成填充线的双移动正方形网格,该网格与连续的层组合成四面体图案
generateQuarterCubicInfill生成填充线的双移动正方形网格,该网格与连续的层组合为四分之一立方图案
generateHalfTetrahedralInfill生成填充线的单个移动方形网格。这用于四面体填充(八进制填充)和四分之一立方填充。
generateTriangleInfill生成填充线的三角形网格
generateTrihexagonInfill生成填充线的三角形网格
generateCubicSubDivInfill在其点上生成细分立方体的三维图案
generateCrossInfill在其点上生成细分立方体的三维图案
addLineInfill使用奇偶规则将扫描线到线段的映射-扫描线交点(\p剪切列表)转换为线段
addLineSegmentsInfill用裁剪器按填充多边形裁剪线段
generateLineInfill在轮廓中的区域内以固定的直线距离间隔生成直线
generateLinearBasedInfill用于创建基于线性的内嵌类型(直线、锯齿形)的函数,会调用一个ZigzagConnectorProcessor函数,它处理每一个线段-扫描线相交的操作
generateZigZagInfill在[in_outline]区域内以[line_distance]的固定间隔生成线
getShiftOffsetFromInfillOriginAndRotation根据infll_origin和infll_rotation的值确定填充样式应移动多远
connectLines将内嵌线连接在一起,以便它们形成多段线。在大多数情况下,它最终只得到一条或多或少是最优的长线。这些线的末端通过沿填充区域的边界拉伸而连接,类似于锯齿形图案。

ZigzagConnectorProcessor类 处理行之间的连接的处理器类,使填充成为锯齿形图案。
registerVertex 处理外部边界上的下一个顶点。
registerScanlineSegmentIntersection处理扫描线与外部边界之间的下一个交点。
registerPolyFinished处理多边形的末端并准备下一个。此函数应重置所有成员变量。
reset重置状态,以便它可以用于处理另一个多边形。
addLine将一条线添加到结果bu,又乘旋转矩阵。
shouldAddCurrentConnector检查是否应添加当前连接器。
checkAndAddZagConnectorLine检查两个点是否至少被“阈值”微米隔开。如果它们彼此距离足够远,则将添加由这两个点表示的线;如果它们很近,则将第二个点设置为第一个相同点,而不添加此线。
addZagConnector添加由给定点表示的Zag连接器。如果给定的连接器是端件并且未启用“已连接的端件”,则不会添加连接器的最后一行。

CuraEngine工作流程及代码详解相关推荐

  1. MeanTeacher文章解读+算法流程+核心代码详解

    MeanTeacher 本博客仅做算法流程疏导,具体细节请参见原文 原文 原文链接点这里 Github 代码 Github代码点这里 解读 论文解读点这里 算法流程 代码详解 train_transf ...

  2. SLAM学习笔记(二十)LIO-SAM流程及代码详解(最全)

    写在前面 关于安装配置,博客LIO_SAM实测运行,论文学习及代码注释[附对应google driver数据] 我觉得已经写的比较完善了.但是我觉得在注释方面,这位博主写的还不够完善,因此在学习以后, ...

  3. FixMatch文章解读+算法流程+核心代码详解

    FixMatch 本博客仅做算法流程疏导,具体细节请参见原文 原文 查看原文点这里 Github代码 Github代码点这里 解读 FixMatch算法抓住了半监督算法的两个重要观点,第一个是一致性正 ...

  4. optee的RPC流程的代码详解

    文章目录 1.在optee中发起RPC调用 (1).rpc_load (2).thread_rpc_cmd (3).thread_rpc 2.ATF code 3.tee driver中的switch ...

  5. 域名系统的工作流程——DNS服务详解

    DNS是什么? 简单说是:DNS把难记的IP地址转换为好记的域名帮助记忆. DNS(Domain Name System 域名系统):是一项互联网服务,存储域名和IP地址相互映射关系的一个分布式数据库 ...

  6. yii mysql 事务处理_Yii2中事务的使用实例代码详解

    前言 一般我们做业务逻辑,都不会仅仅关联一个数据表,所以,会面临事务问题. 数据库事务(Database Transaction) ,是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全 ...

  7. 来FAL学风控|风控策略分析师的日常是怎样的?(案例+代码详解篇)

    风控策略分析师的日常是怎样的?(案例+代码详解篇) FAL金科应用研究院 做了5年的金融,3年的数据分析工作,从17年6月才真正接触代码,算不到熟练,但在不断的学习和工作实践中目前是可以解决任何问题的 ...

  8. 从PointNet到PointNet++理论及代码详解

    从PointNet到PointNet++理论及代码详解 1. 点云是什么 1.1 三维数据的表现形式 1.2 为什么使用点云 1.3 点云上以往的相关工作 2. PointNet 2.1 基于点云的置 ...

  9. 《STM32从零开始学习历程》——CAN通讯代码详解

    <STM32从零开始学习历程>@EnzoReventon CAN通讯代码详解 相关链接: <STM32从零开始学习历程>--CAN通讯协议物理层 CAN-bus规范 V2.0版 ...

  10. 常见字典用法集锦及代码详解

    目录 前言 字典的简介 1. 字典对象 1.1 Add 方法 1.2 Exists 方法 1.3 Keys 方法 1.4 Items 方法 1.5 Remove 方法 1.6 RemoveAll 方法 ...

最新文章

  1. Struts2框架执行流程
  2. 物理学上最厉害的54个男人!2400年来难以超越,没想到聚在一起后这么震撼......
  3. java三目运算_Java中的三目运算符 详解
  4. 企业数字化新战场:低代码究竟是“毒瘤”还是“良药”?
  5. 在内存中动态生成缩略图
  6. error: couldn't connect to server 127.0.0.1:27017 src/mongo/shell/mongo.js
  7. java3D反恐精英3_统一5.3.0f4错误CS0029;不能隐式转换'UnityEngine.Vector3'类型为'float'...
  8. SAP License:年度结算的步骤
  9. LeetCode 104.二叉树的最大深度(递归)
  10. java多线程写数据到数据库6_java多线程向数据库写入数据
  11. java中的ioc和aop_IOC和AOP分别是什么?如何理解?
  12. 我的世界服务器显示红心,我的世界手机版红心怎么恢复 | 手游网游页游攻略大全...
  13. J2EE框架技术(SpringMVC) 知识点笔记(1)
  14. 安装ie11提示计算机安装了更新的版本,离线安装IE11浏览器提示quot;获取更新quot;解决方法 - 191路由网...
  15. 麻辣香锅(Spicy Hot Pot)浏览器劫持病毒应急方法
  16. 【思想总结】关于最近思想滑坡的反省
  17. oracle查询时间段差,关于oracle数据库中进行查询的时候出现效率特别差的一种情况...
  18. 上周回顾:DNS漏洞被泄 华为辞职门再起风波
  19. request.setattribute详解
  20. 区块链技术方向的就业前景

热门文章

  1. 阿里云短信服务 手机验证码
  2. PCB的安装与元器件的绘制
  3. 9、recoil库的基本使用
  4. Zabbix proxy
  5. 在win7下面安装ubuntu 16.04.4双系统
  6. 在Google Chrome WebRTC中分层蛋糕式的VP9 SVC
  7. 号称超越ETH、吊打EOS,技术流IOST的底气到底在哪里?
  8. 华硕路由域名访问_“618” WiFi6 路由器选购推荐清单_路由器
  9. 分布式专题(1)- 计算机网络
  10. 响应式布局的实现方式