cura-engine為開源3D打印軟件cura的核心引擎代碼,詳細介紹參看github主頁。現在學習的是一個簡單版的https://github.com/repetier/CuraEngine,最新版https://github.com/Ultimaker/CuraEngine添加了很多功能,尤其通信部分有點難懂。本系列文章主要是為了保存本人閱讀記憶,一面吃過就忘,所以完全按照閱讀順序編寫,故稍有凌亂。下面直接進入學習。
首先看fffProcessor.h中的讀取STL文件部分:
函數ProsessFile:功能:STL文件讀取prepareModel、生成切片數據processSliceData、生成Gcode writeGcode。(log函數現在濾去,單獨研究)
函數prepareModel:功能:STL文件讀取、優化STL文件、生成LayerParts。涉及到的類:class SimpleModel、class SimpleVolume、class OptimizedModel、cura class Slicer、cura class SupportStorage。
文件讀取的實現:
1 if (files.size() == 1 && files[0][0] == '$') 2 { 3 const char *input_filename = files[0].c_str(); 4 model = new SimpleModel(); 5 for(unsigned int n=0; input_filename[n]; n++) 6 { 7 model->volumes.push_back(SimpleVolume()); 8 SimpleVolume* volume = &model->volumes[model->volumes.size()-1]; 9 guiSocket.sendNr(GUI_CMD_REQUEST_MESH); 10 11 int32_t vertexCount = guiSocket.recvNr(); 12 int pNr = 0; 13 cura::log("Reading mesh from socket with %i vertexes\n", vertexCount); 14 Point3 v[3]; 15 while(vertexCount) 16 { 17 float f[3]; 18 guiSocket.recvAll(f, 3 * sizeof(float)); 19 FPoint3 fp(f[0], f[1], f[2]); 20 v[pNr++] = config.matrix.apply(fp); 21 if (pNr == 3) 22 { 23 volume->addFace(v[0], v[1], v[2]); 24 pNr = 0; 25 } 26 vertexCount--; 27 } 28 } 29 }else{ 30 model = new SimpleModel(); 31 for(unsigned int i=0;i < files.size(); i++) { 32 if(files[i] == "-") 33 model->volumes.push_back(SimpleVolume()); 34 else { 35 cura::log("Loading %s from disk...\n", files[i].c_str()); 36 SimpleModel *test = loadModelFromFile(model,files[i].c_str(), config.matrix); 37 if(test == nullptr) { // error while reading occurred 38 cura::logError("Failed to load model: %s\n", files[i].c_str()); 39 return false; 40 } 41 } 42 } 43 }
此處讀入文件來源有兩種,一是通過guiSocket從通信中接收的數據,二是從硬盤中讀取STL文件,通信部分暫且不提,先學習后者。這就到了loadModelFromFile函數,此函數名字就已透露其作用-讀文件。代碼在文件modelFile.cpp中,如下:
1 SimpleModel* loadModelFromFile(SimpleModel *m,const char* filename, FMatrix3x3& matrix) 2 { 3 const char* ext = strrchr(filename, '.'); 4 if (ext && stringcasecompare(ext, ".stl") == 0) 5 { 6 return loadModelSTL(m,filename, matrix); 7 } 8 if (filename[0] == '#' && binaryMeshBlob != nullptr) 9 { 10 while(*filename == '#') 11 { 12 filename++; 13 14 m->volumes.push_back(SimpleVolume()); 15 SimpleVolume* vol = &m->volumes[m->volumes.size()-1]; 16 int32_t n, pNr = 0; 17 if (fread(&n, 1, sizeof(int32_t), binaryMeshBlob) < 1) 18 return nullptr; 19 cura::log("Reading mesh from binary blob with %i vertexes\n", n); 20 Point3 v[3]; 21 while(n) 22 { 23 float f[3]; 24 if (fread(f, 3, sizeof(float), binaryMeshBlob) < 1) 25 return nullptr; 26 FPoint3 fp(f[0], f[1], f[2]); 27 v[pNr++] = matrix.apply(fp); 28 if (pNr == 3) 29 { 30 vol->addFace(v[0], v[1], v[2]); 31 pNr = 0; 32 } 33 n--; 34 } 35 } 36 return m; 37 } 38 return nullptr; 39 }
此處可以看出分兩種情況,一是讀取.stl后綴的STL文件,二是讀取blob(binary large object)二進制大對象,blob同樣來源與硬盤數據文件,至於到底是神馬,還不知道。
1 m->volumes.push_back(SimpleVolume()); 2 SimpleVolume* vol = &m->volumes[m->volumes.size()-1];
代碼作者超級喜歡這種先推入一個初始的幾何體,然后在通過引用取出到vol,再賦值,貌似我一般都是相反的順序,不知這種有何優勢。下面還是看一看函數LoadModelSTL()吧,就在正上方。
1 SimpleModel* loadModelSTL(SimpleModel *m,const char* filename, FMatrix3x3& matrix) 2 { 3 FILE* f = fopen(filename, "r"); 4 char buffer[6]; 5 if (f == nullptr) 6 return nullptr; 7 8 if (fread(buffer, 5, 1, f) != 1) 9 { 10 fclose(f); 11 return nullptr; 12 } 13 fclose(f); 14 15 buffer[5] = '\0'; 16 if (stringcasecompare(buffer, "solid") == 0) 17 { 18 SimpleModel* asciiModel = loadModelSTL_ascii(m, filename, matrix); 19 if (!asciiModel) 20 return nullptr; 21 22 // This logic is used to handle the case where the file starts with 23 // "solid" but is a binary file. 24 if (m->volumes[m->volumes.size()-1].faces.size() < 1) 25 { 26 m->volumes.erase(m->volumes.end() - 1); 27 return loadModelSTL_binary(m, filename, matrix); 28 } 29 return asciiModel; 30 } 31 return loadModelSTL_binary(m, filename, matrix); 32 }
此函數同樣分兩種情況(看來碼農都喜歡二分)。很簡單,讀入開頭5個字母,如果是solid,則按Ascii讀入,否則按照二進制讀入。然而作者心思謹慎,開頭是solid時也有二進制情況,所以檢查一下讀入最后一個幾何體如果一個面都沒有,那就錯了唄,滾回用二進制重新讀。
函數loadModelSTL_ascii(SimpleModel *m,const char* filename, FMatrix3x3& matrix)
和loadModelSTL_binary(SimpleModel *m,const char* filename, FMatrix3x3& matrix)是我們這部分的最后一站,代碼不是很難,但有個小小的問題,matrix到底是干什么用的。這個matrix來自最初的函數loadModelFromFile(model,files[i].c_str(), config.matrix);config據我目前所知是整個系統一些參數設置的一個匯總類class ConfigSettings。這里面保存了大量的參數設置。這個matrix是的用途就是每個讀入的坐標與其相乘,結果再存入model->volume.faces,就是將幾何體坐標根據需要做了個變換,至於變換的作用,現在還不清楚。
至此,文件讀入功能結束,文中還有一些問題沒有解決,主要有log相關函數,socket相關函數和config相關,這些都是貫穿整個程序的,以后詳細學習。
哦也。