目前,我們還在函數(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

平面設計培訓,網(wǎng)頁設計培訓,美工培訓,游戲開發(fā),動畫培訓

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     }

平面設計培訓,網(wǎng)頁設計培訓,美工培訓,游戲開發(fā),動畫培訓

  class slicer中的這段代碼是計算一個三角形p0,p1,p2和平面z的相交線的過程。就算公式也比較簡單粗暴,如下

 

 

平面設計培訓,網(wǎng)頁設計培訓,美工培訓,游戲開發(fā),動畫培訓

 

  畫得雖丑,但科學是美麗的,咳咳.。。。函數(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 Polygonsclass Polygon這些類之后才能領悟。本篇先看這一段:

平面設計培訓,網(wǎng)頁設計培訓,美工培訓,游戲開發(fā),動畫培訓

 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     }

平面設計培訓,網(wǎng)頁設計培訓,美工培訓,游戲開發(fā),動畫培訓

  這一段講述了把剛才求得的線段們連接成多邊形的故事。可以看到,首先選取一個線段,然后通過它所在的三角面,找到和其相鄰的三角面,在找到相鄰三角面上的線段,查看其是否匹配,依次進行下去,最后會回到最初的那個三角面上,連接結束。

平面設計培訓,網(wǎng)頁設計培訓,美工培訓,游戲開發(fā),動畫培訓

  然而這種方法并不能完成所有的情況,比如幾何體有一些缺陷什么的,后面的代碼是針對各種情況所作的處理,這些目前還很難懂,因為在這之前要搞懂Polygon這個基礎類到底是如何構建的。咱們下回分解。