在知道 CuraEngine 的工作原理之前,需要先知道 STL 格式的含義。.stl 文件是在計(jì)算機(jī)圖形應(yīng)用系統(tǒng)中,用于表示三角形網(wǎng)格的一種文件格式。 它的文件格式非常簡單, 應(yīng)用很廣泛。STL 是最多快速原型系統(tǒng)所應(yīng)用的標(biāo)準(zhǔn)文件類型。STL 是用三角網(wǎng)格來表現(xiàn) 3D CAD 模型。
Stl 文件中存放的是無數(shù)個(gè)空間三角面的位置信息(空間中,每個(gè)三角面的確定是通過它
三個(gè)定點(diǎn)的坐標(biāo)來的)。所以,我們?nèi)绻獙?duì)一個(gè) 3D 模型進(jìn)行切割,實(shí)際上就是用一個(gè)平面
來和無數(shù)小三角形做相交,得到很多條交線,我們把這些交線連接起來就得到了切平面了。
.CuraEngine 基本工作流程
筆者一開始就選擇了 Cura 作為研究對(duì)象,有兩個(gè)原因:一是 slice3R 的切片速度明顯不如 Cura,
二是,Cura 的切片引擎使用的是 C++…這是筆者所鐘愛的開發(fā)語言。雖然 Cura 的界面是用
Python 語言寫的,但這不影響底層切片軟件引擎的使用。
下面是 CuraEngine 的 github 上關(guān)于 Cura 項(xiàng)目的介紹和描述。
(
https://github.com/Ultimaker/CuraEngine)
1.1 總流程
The Cura Engine is structured as mainly .h files. This is not standard for an C++ project. However,
using less cpp files makes the optimizer work harder and removes linking error issues. It's partialy
a result of lazyness but also for optimalizations.
The .h files contain different steps called from the main.cpp file. The main.cpp file contains the
global slicing logic.
The slicing process follows the following global steps:
Load 3D model
Analize and fix 3D model
Slice 3D model into 2D layers
Build LayerParts from sliced layers
Generate Insets
Generate up/down skins areas
Generate sparse infill areas
Generate GCode for each layer
Each step has more logic in it. But this is a general overview. All data for the engine is stored in
the "SliceDataStorage". It's important to remember that only the data from the previous step is
valid.
Coordinates are stored in 64bit integers as microns in the code. So if you see a value of 1000 then
this mean 1mm of distance. This is because Clipper works on 64bit integers and microns give a
high enough resolution without limiting the size too much. Note that there are some bits and
pieces of code that need to be careful about 64bit overflows, especially calculating lengths
sqrt(x*x+y*y) can cause overflows.
下面我把自己理解的意思說一下,英文爛,勿噴。
首先,Cura 不是一個(gè)標(biāo)準(zhǔn)的 C++工程,他大部分的函數(shù)都是在.h 文件中實(shí)現(xiàn)的,這樣做,使
得在編譯過程中優(yōu)化出現(xiàn)了很多的錯(cuò)誤,這主要是由于懶的原因….(..請(qǐng)?zhí)^)。
切片程序的主要過程如下:
i.導(dǎo)入 3D 模型(STL,OBJ 等等)。
ii.分析并修復(fù) 3D 模型(源碼里面貌似木有這一步…)。
iii.將 3D 模型切割成 2D 層。
iv.用上一步得到的 2D 圖層形成 LayerParts(他們自己的叫法),因?yàn)橐粚永锩?,很有?br />
能有很多個(gè)不同的多邊形,比如桌子,他的四個(gè)角,切出來后是四個(gè)圓形,上一步
中只是得到了四個(gè)圓形,而沒有確定這四個(gè)圓形是屬于同一層的。
v.進(jìn)一步確定 LayerParts 中,各個(gè) part 間的關(guān)系,比如得到了兩個(gè)圓,大圓套小圓,
我們就需要確認(rèn),小圓是空心的,而大圓和小圓形成的圓環(huán)是實(shí)心的。
vi.將需要實(shí)心打印的部分標(biāo)記出來(100%填充)。
vii.將需要空心打印的地方打印出來(部分填充)。
viii.根據(jù)生成的 LayerParts 生成每一層的 G-code。
上述的每一步都有更多的邏輯關(guān)系在里面,但這只是一個(gè)工作的大概流程。切割引擎所有的
數(shù)據(jù)都存放在一個(gè)叫 SliceDataStorage 的類里面。記住,上述的每一步都是基于前一步的數(shù)
據(jù)來進(jìn)行的。這里嚴(yán)格按照上述的流程來處理 3D 模型生成 G-code。另外,在代碼里面,坐
標(biāo)是用 64 位整數(shù)的形式存在的,比如,你在代碼中看到的 1000,他實(shí)際代表了 1mm。這
樣做是因?yàn)?Clipper 使用了 64 為整數(shù)來表示距離。
1.2 源碼中幾個(gè)重要的類
1. OptimizedModel
The OptimizedModel is a 3D model stored with vertex<->face relations. This gives touching face
relations which are used later on to slice into layers faster.
OptimizedModel 也是一個(gè) 3D 模型,只是他是對(duì)一開始導(dǎo)入的模型進(jìn)行的優(yōu)化,去除了 3D
模型中多余的數(shù)據(jù),同時(shí)確立了 3D 模型中每個(gè)三角面之間的拓?fù)潢P(guān)系。這是整個(gè)軟件最為
核心的一部分之一。他為后面一步進(jìn)行切割做好了準(zhǔn)備,沒有他 slice 無法進(jìn)行。
2.Slicer
While usually the whole GCode generation process is called Slicing. The slicer in the CuraEngine is
the piece of code that generates layers. Each layer has closed 2D polygons. These polygons are
generated in a 2 step process. First all triangles are cut into lines per layer, for each layer a "line
segment" is added to that layer. Next all these line-segments are connected to eachother to make
Polygons. The vertex<->face relations of the OptimizedModel help to make this process fast, as
there is a huge chance that 2 connecting faces also make 2 connecting line-segments. This code
also fixes up small holes in the 3D model, so your model doesn't need to be perfect Manifold. It
also accounts for incorrect normals, so it can flip around line-segments to fit end-to-end.
After the Slicer we have closed Polygons which can be used in Clipper, as Clipper can only
opperate on closed 2D polygons.
我們通常都把由 3D 模型生成 G-code 的過程叫做 slicing.在 CuraEngine 中,Slicer 只是數(shù)量很
小的一部分代碼,用于生成 layers。每個(gè) layer 都有閉合的 2D 多邊形。這些多邊形的形成有
兩步。
第一步,用一個(gè)切割平面同所有三角形做相交運(yùn)算,得到和這個(gè)平面相交的線段就是屬
于這個(gè) layer 的,這些切割后得到的線段稱之為”linesegment”。此時(shí),layer 里面只是有
一些零散的線段。
第二步,將這些 linesegment 連起來,形成封閉的多邊形。
由于 OptimizedModel 已經(jīng)將各個(gè)相鄰三角形之間的關(guān)系確立好了,這里的 slice 速度變得很
快。在進(jìn)行完 slice 之后,我們就得到了封閉的多邊形曲線,這些曲線,要交給 Clipper 庫來
進(jìn)行下一步的處理。Clipper 庫只能用于處理 2D 的封閉多邊形模型。(Clipper 的用途請(qǐng) google)。
3. LayerParts
An important concept to grasp is the LayerParts. LayerParts are seperate parts inside a single layer.
For example, if you have a cube. Then each layer has a single LayerPart. However, if you have a
table, then the layers which build the legs have a LayerPart per leg, and thus there will be 4
LayerParts. A LayerPart is a seperated area inside a single layer which does not touch any other
LayerParts. Most operations run on LayerParts as it reduces the amount of data to process.
During GCode generation handling each LayerPart as an own step makes sure you never travel
between LayerParts and thus reducing the amount of external travel. LayerParts are generated
after the Slicer step.
To generate the LayerParts Clipper is used. A Clipper union with extended results gives a list of
Polygons with holes in them. Each polygon is a LayerPart, and the holes are added to this
LayerPart.
LayerParts 是需要掌握的一個(gè)重要概念。LayerParts 是一個(gè)單獨(dú)的 layer 中的一部分。比如,
切割一個(gè)正方體,我們只會(huì)得到一個(gè) LayerPart,但是,如果切割一個(gè)桌子,這個(gè)桌子有四
個(gè)腳,我們就會(huì)得到四個(gè)切面,也就是四個(gè) LayerPart,我們把這在同一平面的四個(gè) LayerPart
稱為 layer。在生成 G-code 的過程中,都是對(duì)每個(gè) LayerPart 單獨(dú)操作,避免了打印機(jī)在兩個(gè)
LayerPart 之間打印多余的東西。同時(shí)也減少了噴頭運(yùn)動(dòng)的距離。為了生成 LayerPart,我們
要使用到 Clipper 庫。
4 Up/Down skin
The skin code generates the fully filled areas, it does this with some heavy boolean Clipper action.
The skin step uses data from different layers to get the job done. Check the code for details. The
sparse infill area code is almost the same as the skin code. With the difference that it keeps the
other areas and uses different offsets.
Note that these steps generate the areas, not the actual infill lines. The infill line paths are
generated later on. So the result of this step are list of Polygons which are the areas that need to
be filled.
這部分的功能是確定模型中,需要完全被填充的部位,這里大量使用了 Clipper 庫里面的布
爾運(yùn)算。如果自己看 Cura 的代碼會(huì)發(fā)現(xiàn),這里的 skin(完全填充)和 sparse fill(稀疏填充)的代
碼是幾乎一樣的,只是設(shè)置了不同的填充比例而已。注意,這一步只是標(biāo)記了需要填充的區(qū)
域,真正的填充操作是在下面一步生成 G-code 的過程中進(jìn)行。
5 G-code 生成器
The GCode generation is quite a large bit of code. As a lot is going on here. Important bits here
are:
PathOrderOptimizer: This piece of code needs to solve a TravelingSalesmanProblem. Given a list
of polygons/lines it tries to find the best order in which to print them. It currently does this by
finding the closest next polygon to print.
Infill: This code generates a group of lines from an area. This is the code that generates the
actuall infill pattern. There is also a concentric infill function, which is currently not used.
Comb: The combing code is the code that tries to avoid holes when moving around the head
without printing. This code also detects when it fails. The final GCode generator uses the
combing code while generating the final GCode. So they interact closely.
GCodeExport: The GCode export is a 2 step process. First it collects all the paths for a layer that it
needs to print, this includes all moves, prints, extrusion widths. And then it generates the final
GCode. This is the only piece of code that has knowledge about GCode, and to generate a
different flavor of GCode it will be the only piece that needs adjustment. All volumatric
calculations also happen here.
G-code 生成器有非常多的代碼,這里給出他主要的幾個(gè)點(diǎn):
PathOrderOptimizer:這部分代碼是路徑優(yōu)化代碼,計(jì)算最優(yōu)路徑。提供很多歌多邊形,
然后找到最好的順序和最好的路徑來走完他們。比如,你打印完這一個(gè) LayerPart 后,
你需要找到下一個(gè)離他最近的 LayerPart 多邊形來打印
Infill :這部分代碼會(huì)在一個(gè)區(qū)域里生成一組線。
Comb:這部分的代碼,是為了避免在打印機(jī)不噴絲時(shí)移動(dòng)噴頭而不會(huì)同打印好的層發(fā)
生接觸從而產(chǎn)生一些不好的洞。
GCodeExport:導(dǎo)出 G-code 分為兩個(gè)步驟,首先,他將需要打印的那一層(layer,不是
LayerPart)的所有路徑收集起來,包括移動(dòng),打印,擠出寬度等。然后生成最終的 G-code。
只有這一部分的代碼是和 G-code 直接相關(guān)的。要生成不同的 G-code,只需要在這里做
少量的調(diào)整即可。另外,對(duì)模型體積的計(jì)算,也是在這一步中計(jì)算出來的。
你可能喜歡
拓竹Bambu Lab A1 mini測評(píng):這臺(tái)3D打印機(jī)
變廢為寶:通過固相制造將鋁廢料轉(zhuǎn)化為3D打
新突破:基于聲波的3D打印技術(shù)——全息直聲
一篇帶你讀懂:金屬3D打印在航空航天領(lǐng)域的
推薦課程
神奇的3D打印
SLA3D打印工藝全套培訓(xùn)課程 - 軟件篇
3D打印月球燈視頻教程 包括完整貼圖建模流
【原創(chuàng)發(fā)布】Cura軟件修改二次開發(fā)定制視頻