目前,我們還在函數(shù)prepareModel中徘徊,因為這函數(shù)實在是太長了,近乎包含了整個數(shù)據(jù)處理過程。通過前面兩篇,幾何圖形已經(jīng)被導入到內(nèi)存中,并且由一個simplemodel變成了一個optimizedmodel?,F(xiàn)在程序拿起了屠刀,開始了切片過程。
通常來講,在3D打印中所說的slicer過程包含了切割幾何體,連接多邊形,生成Gcode的所有過程,但在此程序中,slicer步僅為生成切片的切割操作。每一個切包含若干個閉合平面多邊形。這些多邊形的產(chǎn)生分兩步。第一,所有的三角形面片被切割成為一條線段;第二,將每層的線段連接起來形成閉合多邊形。前篇所述的點-面對應關系可以幫助這一過程快速進行,因為兩個相鄰的面上的切割線段很有可能就是相鄰線段。這段程序還可以幫助修補幾何圖形中的空洞,因此STL模型不需要那么完美。它也可以處理錯誤的法向量,所以它可以翻轉線段來滿足端點到端點的連接。slicer步驟之后我們得到了一系列閉合多邊形,然后會用到clipper來處理這些多邊形(clipper只可以處理2D閉合多邊形)。這一段來自cura-engine github主頁的介紹。
切割過程代碼在slicer.h和slicer.cpp這兩個文件中。首先我們看其中的class slicer
1 SlicerSegment project2D(Point3& p0, Point3& p1, Point3& p2, int32_t z) const2 {3 SlicerSegment seg;4 seg.start.X = p0.x + int64_t(p1.x - p0.x) * int64_t(z - p0.z) / int64_t(p1.z - p0.z);5 seg.start.Y = p0.y + int64_t(p1.y - p0.y) * int64_t(z - p0.z) / int64_t(p1.z - p0.z);6 seg.end.X = p0.x + int64_t(p2.x - p0.x) * int64_t(z - p0.z) / int64_t(p2.z - p0.z);7 seg.end.Y = p0.y + int64_t(p2.y - p0.y) * int64_t(z - p0.z) / int64_t(p2.z - p0.z);8 return seg;9 }
class slicer中的這段代碼是計算一個三角形p0,p1,p2和平面z的相交線的過程。就算公式也比較簡單粗暴,如下
畫得雖丑,但科學是美麗的,咳咳.。。。函數(shù)project2D所表達的就是上面的公式了,至于六種情況的分類,我們可以在構造函數(shù)slicer()里面找到。沒錯,就是那六排if-else
Slicer(OptimizedVolume* ov, int32_t initial, int32_t thickness, bool keepNoneClosed, bool extensiveStitching) 把優(yōu)化過的幾何體ov按照厚度(thickness)切割成片片即layer。函數(shù)的前大半部分計算了三角面上被切割得到的線段,這些線段只有起點和終點,之間沒有什么聯(lián)系。后小部分使用makepolygon函數(shù)將線段們連接成多邊形。
1 for(unsigned int layerNr=0; layerNr<layers.size(); layerNr++)2 {3 layers[layerNr].makePolygons(ov, keepNoneClosed, extensiveStitching);4 }
那么makepolygon函數(shù)又如何呢,這是一個200多行的大函數(shù)。本篇只能學習一小部分,欲窺其全貌,要等到之后我們學習了class Polygons和class Polygon這些類之后才能領悟。本篇先看這一段:
1 Polygons openPolygonList; 2 3 for(unsigned int startSegment=0; startSegment < segmentList.size(); startSegment++) 4 { 5 if (segmentList[startSegment].addedToPolygon) 6 continue; 7 8 Polygon poly; 9 poly.add(segmentList[startSegment].start);10 11 unsigned int segmentIndex = startSegment;12 bool canClose;13 while(true)14 {15 canClose = false;16 segmentList[segmentIndex].addedToPolygon = true;17 Point p0 = segmentList[segmentIndex].end;18 poly.add(p0);19 int nextIndex = -1;20 OptimizedFace* face = &ov->faces[segmentList[segmentIndex].faceIndex];21 for(unsigned int i=0;i<3;i++)22 {23 if (face->touching[i] > -1 && faceToSegmentIndex.find(face->touching[i]) != faceToSegmentIndex.end())24 {25 Point p1 = segmentList[faceToSegmentIndex[face->touching[i]]].start;26 Point diff = p0 - p1;27 if (shorterThen(diff, MM2INT(0.01)))28 {29 if (faceToSegmentIndex[face->touching[i]] == static_cast<int>(startSegment))30 canClose = true;31 if (segmentList[faceToSegmentIndex[face->touching[i]]].addedToPolygon)32 continue;33 nextIndex = faceToSegmentIndex[face->touching[i]];34 }35 }36 }37 if (nextIndex == -1)38 break;39 segmentIndex = nextIndex;40 }41 if (canClose)42 polygonList.add(poly);43 else44 openPolygonList.add(poly);45 }
這一段講述了把剛才求得的線段們連接成多邊形的故事。可以看到,首先選取一個線段,然后通過它所在的三角面,找到和其相鄰的三角面,在找到相鄰三角面上的線段,查看其是否匹配,依次進行下去,最后會回到最初的那個三角面上,連接結束。
然而這種方法并不能完成所有的情況,比如幾何體有一些缺陷什么的,后面的代碼是針對各種情況所作的處理,這些目前還很難懂,因為在這之前要搞懂Polygon這個基礎類到底是如何構建的。咱們下回分解。