目前,我们还在函数prepareModel中徘徊,因为这函数实在是太长了,近乎包含了整个数据处理过程。通过前面两篇,几何图形已经被导入到内存中,并且由一个simplemodel变成了一个optimizedmodel。现在程序拿起了屠刀,开始了切片过程。

  通常来讲,在3D打印中所说的slicer过程包含了切割几何体,连接多边形,生成Gcode的所有过程,但在此程序中,slicer步仅为生成切片的切割操作。每一个切包含若干个闭合平面多边形。这些多边形的产生分两步。第一,所有的三角形面片被切割成为一条线段;第二,将每层的线段连接起来形成闭合多边形。前篇所述的点-面对应关系可以帮助这一过程快速进行,因为两个相邻的面上的切割线段很有可能就是相邻线段。这段程序还可以帮助修补几何图形中的空洞,因此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的相交线的过程。就算公式也比较简单粗暴,如下

 

 

平面设计培训,网页设计培训,美工培训,游戏开发,动画培训

 

  画得虽丑,但科学是美丽的,咳咳.。。。函数project2D所表达的就是上面的公式了,至于六种情况的分类,我们可以在构造函数slicer()里面找到。没错,就是那六排if-else

Slicer(OptimizedVolume* ov, int32_t initial, int32_t thickness, bool keepNoneClosed, bool extensiveStitching)   把优化过的几何体ov按照厚度(thickness)切割成片片即layer。函数的前大半部分计算了三角面上被切割得到的线段,这些线段只有起点和终点,之间没有什么联系。后小部分使用makepolygon函数将线段们连接成多边形。

1  for(unsigned int layerNr=0; layerNr<layers.size(); layerNr++)2     {3         layers[layerNr].makePolygons(ov, keepNoneClosed, extensiveStitching);4     }

  那么makepolygon函数又如何呢,这是一个200多行的大函数。本篇只能学习一小部分,欲窥其全貌,要等到之后我们学习了class Polygonsclass 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这个基础类到底是如何构建的。咱们下回分解。

 


延伸阅读

学习是年轻人改变自己的最好方式-Java培训,做最负责任的教育,学习改变命运,软件学习,再就业,大学生如何就业,帮大学生找到好工作,lphotoshop培训,电脑培训,电脑维修培训,移动软件开发培训,网站设计培训,网站建设培训学习是年轻人改变自己的最好方式