簡化測試程式碼
阿新 • • 發佈:2019-01-05
#include "stdafx.h" #include <gtest/gtest.h> #include <fstream> #include <math.h> #include <algorithm> #include <iostream> #include "..\TestServer\FileHelper.h" #include "Algorithm/algsimplifier.h" #include "algqemsimplifier.h" #include "Geometry/Plane.h" #include "Algorithm/algTriMeshSegm.h" #include "gmath/GBox3.h" // coe = 4*1.732*w/(a*a + b*b + c*c) :其中w代表面積,a,b,c代表邊長,coe 的結果1表示等邊三角形,0表示邊重合 // 狹長三角形係數 coe 的邊界值 #define COE_MIN_LONG_TRIANGLE 0.1 // 兩個面片法線夾角的最大值 #define MAX_ANGLE 3.1415926 // 簡化比允許的上下波動 #define FLUCT_RATIO 0.02 // 計算兩個網格模型距離平均值時選取的頂點數的比率 #define DIS_NUM_RATIO 0.1 // 計算兩個網格模型距離平均值的邊界值 #define DIS_MAX 1.0 typedef CVec3<double> point; typedef CBox3<double> ptrBox; // 簡化後網格模型檔名標識 string SimSign("_simply"); class mesh_vertex; class mesh_face; class tri_mesh; typedef set<mesh_face*, ggp::dereference_functor_less> FaceSet; // 類表示網格模型的點 class mesh_vertex { public: // 預設建構函式 mesh_vertex(bool inisPatch = false):isPatch(inisPatch){} // 座標 point pt; // 頂點是否加入了分割 bool isPatch; // 與頂點相連的面 FaceSet p_face; friend class tri_mesh; }; // 類表示網格模型的面 class mesh_face { public: // 對應的頂點號 size_t vertices[3]; // 頂點的紋理座標 CVector2d textcoord[3]; //過載“<”操作符,自定義排序規則 bool operator < (const mesh_face &f) const { //按vertices從小到大排列 return (vertices[0] < f.vertices[0]) || (vertices[0] == f.vertices[0] && vertices[1] < f.vertices[1]) || (vertices[0] == f.vertices[0] && vertices[1] == f.vertices[1] && vertices[2] < f.vertices[2]); } friend class tri_mesh; }; // 類表示三角網格 class tri_mesh { public: // 獲得pos位置的面 mesh_face getFace(size_t pos); vector<mesh_vertex*> VertexList; FaceSet FaceList; }; // 獲得 tri_mesh 中某個位置的面 mesh_face tri_mesh::getFace(size_t pos) { FaceSet::iterator it = FaceList.begin(); int i = 0; while(i < pos) { it ++; i ++; } return **it; } // 讀取網格檔案中的面和點,網格檔案型別為 .ply ,成功返回 true bool ReadMeshFromFilePly(string mesh_path, tri_mesh & mesh) { ifstream infile(mesh_path); string line, str; int num_vertex = -1, num_face = -1; //讀取點和麵的數量 while(getline(infile, line)) { stringstream s_line(line); if(s_line >> str ) { if(str == "element" && s_line >> str) { if(str == "vertex" && s_line >> str) num_vertex = stoi(str); if(str == "face" && s_line >> str) { num_face = stoi(str); break; } } } } if(num_vertex == -1 || num_face == -1) return false; while(getline(infile, line)) { if(line == "end_header") break; } int i = 0; // 讀取點和麵 while(i < num_vertex && getline(infile, line)) { mesh_vertex * mem = new mesh_vertex; stringstream s_line(line); // 讀取頂點座標,如果有方向的話,讀取方向 if(! (s_line >> mem->pt.X >> mem->pt.Y >> mem->pt.Z)) return false; mesh.VertexList.push_back(mem); i ++; } i = 0; while(i < num_face && getline(infile, line)) { mesh_face * mem = new mesh_face; std::stringstream s_line(line); // 面中頂點個數 size_t num_v; s_line >> num_v; // 讀取面的頂點號 for(int j = 0; j < 3; j++) { if(! (s_line >> mem->vertices[j])) return false; } // 面的紋理座標個數 size_t num_vt; s_line >> num_vt; // 讀取面的頂點的紋理座標(假如含有紋理座標) for(int j = 0; j < 3; j++) s_line >> mem->textcoord[j][0] >> mem->textcoord[j][1]; mesh.FaceList.insert(mem); i ++; } int m1 = mesh.VertexList.size(), m2 = mesh.FaceList.size(); if(m1 != num_vertex) { for(size_t i = 0; i < m1; i ++) delete mesh.VertexList[i]; for(FaceSet::iterator it = mesh.FaceList.begin(); it != mesh.FaceList.end(); it ++) delete *it; return false; } infile.close(); size_t pos = 0; for(FaceSet::iterator it = mesh.FaceList.begin(); it != mesh.FaceList.end(); it ++) { for(int j = 0; j < 3; j++) mesh.VertexList[(*it)->vertices[j]]->p_face.insert(*it); // 將面號儲存在頂點資訊中 pos ++; } return true; } // 讀取網格檔案中的面和點,網格檔案型別為 .obj ,成功返回 true bool ReadMeshFromFileObj(string mesh_path, tri_mesh & mesh) { // 為方便計算,使vec_vertex從第二個元素開始有效 mesh_vertex * temp = new mesh_vertex; mesh.VertexList.push_back(temp); vector<CVector2d> vec_text; // 臨時儲存紋理座標 ifstream infile(mesh_path); string line; // 讀取點的資料 while(getline(infile, line)) { string str; stringstream s_line(line); s_line >> str; if(str == "v") { // 讀取頂點座標 mesh_vertex * mem = new mesh_vertex; if( ! (s_line >> mem->pt.X >> mem->pt.Y >> mem->pt.Z)) return false; mesh.VertexList.push_back(mem); } if(str == "vt") { CVector2d textcoord; s_line >> textcoord[0] >> textcoord[1]; vec_text.push_back(textcoord); } if(str == "f") { mesh_face * mem = new mesh_face; for(int j = 0; j < 3; j++) { string str_f; if( ! (s_line >> str_f)) return false; string str_v, str_vt; // 讀取面的頂點號 if(str_f.find("/") != string::npos) { str_vt = str_f.substr(str_f.find_first_of("/") + 1, str_f.find_last_of("/")); str_v = str_f.substr(0, str_f.find_first_of("/")); } else str_v = str_f; size_t v = stoi(str_v); mem->vertices[j] = v; // 讀取面的頂點的紋理座標 if(str_vt != "") { size_t n_vt = stoi(str_vt); mem->textcoord[j] = vec_text[n_vt - 1]; } } mesh.FaceList.insert(mem); } } int m1 = mesh.VertexList.size(), m2 = mesh.FaceList.size(); infile.close(); size_t pos = 0; for(FaceSet::iterator it = mesh.FaceList.begin(); it != mesh.FaceList.end(); it ++) { for(int j = 0; j < 3; j++) mesh.VertexList[(*it)->vertices[j]]->p_face.insert(*it); // 將面號儲存在頂點資訊中 pos ++; } return true; } // 讀取網格檔案中的面和點,成功返回 true bool ReadMeshFromFile(string mesh_path, tri_mesh & mesh) { string type = mesh_path.substr(mesh_path.find_last_of("."), mesh_path.size() - mesh_path.find_last_of(".")); if(type == ".obj") return ReadMeshFromFileObj(mesh_path, mesh); if(type == ".ply") return ReadMeshFromFilePly(mesh_path, mesh); return true; } // 判斷兩個網格模型空間之間的距離屬性,mesh1:簡化前,mesh2:簡化後。返回 num 個點距離平方的平均值 double GetDisSquareOfTwoMesh(tri_mesh & mesh1, tri_mesh & mesh2, size_t num) { double dissquare = 0.0; if(num == 0) return dissquare; // 每隔per個點取 mesh2 中的一個點 size_t per; if(num > mesh2.VertexList.size()) per = 1; else per = mesh2.VertexList.size()/num; // 找到對應的距離最小的點 int i = 0, pos = 0; while(pos < mesh2.VertexList.size()) { i ++; if(i == per + 1) i = 0; if(i != per) { pos ++; continue; } // 迴圈找到 vec_vertex1 中距離該點最近距離的點(為簡化計算,用x+y+z的值來找最近點) double dis = mesh1.VertexList[0]->pt.SqrDistanceTo(mesh2.VertexList[pos]->pt); for(size_t j = 1; j < mesh1.VertexList.size(); j++) { double new_dis = mesh1.VertexList[j]->pt.SqrDistanceTo(mesh2.VertexList[pos]->pt); if(dis > new_dis) { if(new_dis < 1e-6) int o = 10; dis = new_dis; } } // 將距離平方加入到 dissquare 中 dissquare += dis; pos ++; } cout<<"兩個網格模型距離:"<<dissquare/num<<endl; return dissquare/num; } // 獲得三角形的面積(海倫-秦九公式),已知一個面的三個頂點,a,b,c分別為邊長 double GetTriangleArea(tri_mesh & mesh, const mesh_face & face, double & a, double & b, double &c) { point pt1, pt2, pt3; pt1 = mesh.VertexList[face.vertices[0]]->pt; pt2 = mesh.VertexList[face.vertices[1]]->pt; pt3 = mesh.VertexList[face.vertices[2]]->pt; double p, s; // 求三邊長度 a = pt1.DistanceTo(pt2); b = pt1.DistanceTo(pt3); c = pt2.DistanceTo(pt3); p = (a + b + c) / 2; // 求面積 s = sqrt(p*(p - a)*(p - b)*(p - c)); return s; } // 計算兩個向量的夾角 static double GetAngleOfTwoDir(const point& v1, const point & v2) { double mult = v1.Dot(v2); double longth1 = v1.Length(); double longth2 = v2.Length(); return acos(mult / (longth1 * longth2)); } // 通過兩個點獲得一個向量,vectex1 表示起點,vertex2 表示終點 static void GetVecFromVertex(const point & vertex1, const point & vertex2, point & vect) { vect[0] = vertex2[0] - vertex1[0]; vect[1] = vertex2[1] - vertex1[1]; vect[2] = vertex2[2] - vertex1[2]; } // 由三角面片的三個點獲得三角面片的方向 static void GetDirectOfFace(const point & vertex1, const point & vertex2, const point & vertex3, point & dir) { // 兩個點組成的向量 point vector1, vector2; GetVecFromVertex(vertex1, vertex2, vector1); GetVecFromVertex(vertex2, vertex3, vector2); // 獲得兩個向量的叉乘,即面片的方向 dir = vector1.Cross(vector2); } // 使用公式 coe = 4*1.732*w/(a*a + b*b + c*c) :其中w代表面積,a,b,c代表邊長,coe 的結果1表示等邊三角形,0表示邊重合 int GetLongTriangleNum(tri_mesh & mesh) { int num = 0; for(FaceSet::iterator it = mesh.FaceList.begin(); it != mesh.FaceList.end(); it ++) { double coe, a, b, c, s; s = GetTriangleArea(mesh, **it, a, b, c); coe = 4 * 1.732 * s /(pow(a, 2) + pow(b, 2) + pow(c, 2)); if(coe <= COE_MIN_LONG_TRIANGLE) { //cout<<"狹長三角形:"<<i<<" 係數是:"<<coe<<endl; num ++; } } cout<<"狹長三角形個數:"<<num<<endl; return num; } // 獲得兩個 mesh_face 的公共頂點個數 size_t GetCommenVertexNum(const mesh_face & face1, const mesh_face & face2, tri_mesh & mesh) { size_t num = 0; for(size_t i = 0; i < 3; i ++) { for(size_t j = 0; j < 3; j++) { if(face1.vertices[i] == face2.vertices[j]) num ++; } } return num; } // 找到三角面片 n_pos 周圍相鄰的面片 void FindAdjTriangle(mesh_face face, tri_mesh & mesh, FaceSet & adj_triangle) { for(size_t i = 0; i < 3; i ++) { size_t vertex_pos = face.vertices[i]; // 找到面的第i個頂點的頂點號 FaceSet & pFace = mesh.VertexList[vertex_pos]->p_face; // 第i個頂點周圍的面號 for(FaceSet::iterator it = pFace.begin(); it != pFace.end(); it ++) { if(GetCommenVertexNum(face, **it, mesh) == 2) adj_triangle.insert(*it); } } } // 獲得面的法線 void GetUnitOfFace(mesh_face face, tri_mesh & mesh, point & dir) { point vertex[3]; for(size_t i = 0; i < 3; i ++) vertex[i] = mesh.VertexList[face.vertices[i]]->pt; GetDirectOfFace(vertex[0], vertex[1], vertex[2], dir); } // 判斷褶皺,即判斷網格模型中的三角形是否有兩個三角形角度小於等於120度的情況,即兩個三角形法線點乘大於0 int GetCoincideTriangleNum(tri_mesh & mesh) { int num = 0; for(FaceSet::iterator it = mesh.FaceList.begin(); it != mesh.FaceList.end(); it ++) { point dir1, dir2; GetUnitOfFace(**it, mesh, dir1); // 找到相鄰的面 FaceSet adj_triangle; FindAdjTriangle(**it, mesh, adj_triangle); // 查詢跟 vec_face[i] 有公共邊的面 for(FaceSet::iterator it2 = adj_triangle.begin(); it2 != adj_triangle.end(); it2 ++) { GetUnitOfFace(**it2, mesh, dir2); // 如果兩個面片的方向向量點乘小於等於0.0,證明兩個面片夾角小於等於180度 double angle = GetAngleOfTwoDir(dir1, dir2); if(angle >= MAX_ANGLE) { num ++; } } } cout<<"褶皺面個數:"<<num<<endl; return num; } // 獲得擬合平面的距離誤差 double GetFitPlaneCoef(ggp::UVPatch::UVPatchGeom & goems, tri_mesh & mesh, string fileType) { vector<CVector3d> pPtsVec; CPlaneCoef plane_coe; double coe; for(size_t i = 0; i < goems.faceVertexIdxs.size(); i ++) { size_t vertex_id = goems.faceVertexIdxs[i]; if(fileType == ".obj") vertex_id ++; mesh.VertexList[vertex_id]->isPatch = true; // 點標記為加入到分割中 point & re_vetex = mesh.VertexList[vertex_id]->pt; pPtsVec.push_back(re_vetex); } plane_coe.CalPlaneCoef(pPtsVec, pPtsVec.size(), coe); return coe; } // 獲得平均網格模型的平均邊長 double GetAverSqrSideLenth(tri_mesh & mesh) { double sqrlength = 0.0; int num = 0; for(FaceSet::iterator it = mesh.FaceList.begin(); it != mesh.FaceList.end(); it ++) { point pts[3]; for(size_t j = 0; j < 3; j ++) { size_t ver_id = (*it)->vertices[j]; pts[j] = mesh.VertexList[ver_id]->pt; } sqrlength += pts[0].SqrDistanceTo(pts[1]) + pts[0].SqrDistanceTo(pts[2]) + pts[1].SqrDistanceTo(pts[2]); num += 3; } return sqrlength/num; } // 驗證是否所有的平面加入了分割 bool IsAllInPatch(tri_mesh & mesh) { bool isAllPath = true; for(size_t i = 0; i < mesh.VertexList.size(); i ++) { if(mesh.VertexList[i]->p_face.size() > 0 && ! mesh.VertexList[i]->isPatch) return false; } return isAllPath; } // 釋放記憶體 void FreeMesh(tri_mesh & mesh) { // 釋放頂點 for(size_t i = 0; i < mesh.VertexList.size(); i ++) if(mesh.VertexList[i]) delete mesh.VertexList[i]; // 釋放面 for(FaceSet::iterator it = mesh.FaceList.begin(); it != mesh.FaceList.end(); it ++) if(*it) delete *it; } // 驗證三角網格簡化:是否能夠正確獲得簡化模型 void SimplifyResultTest_1(string fileName, double ratio) { string meshPath = CFileHelper::GetFilePath(fileName, g_WhiteboxCaseSimplifyMetrics); string fileType = fileName.substr(fileName.find_last_of("."), fileName.size() - fileName.find_last_of(".")); // 讀取網格模型,並將簡化的模型寫入新的檔案 SimConfig simSign(false, COE_MIN_LONG_TRIANGLE, cos(MAX_ANGLE)); ggp::SimMesh* simedMesh = ggp::Simplify(meshPath, ratio, simSign); EXPECT_TRUE(simedMesh != nullptr); // 將簡化後網格模型寫入檔案 string sub1 = meshPath.substr(0, meshPath.find_last_of(".")); string sub2 = meshPath.substr(meshPath.find_last_of("."), meshPath.size() - meshPath.find_last_of(".")); string simplydMeshPath = sub1 + SimSign + sub2; bool isWriteOk = ggp::EdgeCollapsor::writeTriMesh(*simedMesh, simplydMeshPath); EXPECT_TRUE(isWriteOk); // 讀取簡化前後 tri_mesh mesh1, mesh2; ReadMeshFromFile(meshPath, mesh1); ReadMeshFromFile(simplydMeshPath, mesh2); // 重新計算簡化比,使簡化比在0.0 - 1.0 if(ratio > 1.0 + g_DistEpsilon) { int temp = ratio; ratio = (double)temp/mesh1.FaceList.size(); } if(ratio > 1.0 && ratio <= 1.0 + g_DistEpsilon) ratio = 1.0; EXPECT_TRUE(ratio >= 0.0 && ratio <= 1.0); // 驗證實際簡化比是否正確 double f1, f2; f1 = mesh1.FaceList.size(); f2 = mesh2.FaceList.size(); double real_ratio = f2/f1; if(ratio < 1.0/f1) EXPECT_TRUE(real_ratio == 0.0); else EXPECT_TRUE(fabs(ratio - real_ratio) <= FLUCT_RATIO); // 驗證兩個網格模型距離是否正確 //-----------------------------------------------------------待修正--------------------------------- double dis = GetDisSquareOfTwoMesh(mesh1, mesh2, DIS_NUM_RATIO * mesh2.VertexList.size()); EXPECT_TRUE(dis < DIS_MAX); //-----------------------------------------------------------待修正--------------------------------- // 摺疊三角形 int CoinNum = GetCoincideTriangleNum(mesh1); int CoinNum_Simplify = GetCoincideTriangleNum(mesh2); EXPECT_TRUE(CoinNum_Simplify <= CoinNum); // 狹長三角形 int LongNum = GetLongTriangleNum(mesh1); int LongNum_Simplify = GetLongTriangleNum(mesh2); EXPECT_TRUE(LongNum_Simplify <= LongNum); // 驗證簡化後的網格模型——網格分割是否正確 double sqrLength = GetAverSqrSideLenth(mesh2); ggp::TriMeshSegm meshSegm; double dDistEpsilon = 0.0; meshSegm.PartitionMesh(*simedMesh); std::vector<ggp::UVPatch::UVPatchGeom> patchGeoms = meshSegm.ExportPatchs(); for(int i = 0; i < patchGeoms.size(); i ++) { dDistEpsilon = GetFitPlaneCoef(patchGeoms[i], mesh2, fileType); // 擬合平面距離誤差 //cout<<dDistEpsilon<<" "; // 驗證擬合平面的距離誤差是否正確 double coe_patch = dDistEpsilon /(sqrt(sqrLength) * 2); EXPECT_TRUE(coe_patch < 10.0)<<coe_patch; } EXPECT_TRUE(IsAllInPatch(mesh2)); // 驗證是否所有面參與了分割 // 釋放記憶體 delete simedMesh; FreeMesh(mesh1); FreeMesh(mesh2); // 刪除建立的簡化後網格模型檔案 string delFile = (string)"del" + " " + simplydMeshPath; system(delFile.data()); } // 驗證三角網格簡化:不能正確獲得簡化模型 void SimplifyResultTest_2(string fileName, double ratio) { string meshPath = CFileHelper::GetFilePath(fileName, g_WhiteboxCaseSimplifyMetrics); // 讀取網格模型,並將簡化的模型寫入新的檔案 ggp::SimMesh* simedMesh = ggp::Simplify(meshPath, ratio); EXPECT_TRUE(simedMesh == nullptr); string sub1 = meshPath.substr(0, meshPath.find_last_of(".")); string sub2 = meshPath.substr(meshPath.find_last_of("."), meshPath.size() - meshPath.find_last_of(".")); string simplydMeshPath = sub1 + "_simply" + sub2; bool isWriteOk = ggp::EdgeCollapsor::writeTriMesh(*simedMesh, simplydMeshPath); EXPECT_FALSE(isWriteOk); } //表示 檔名 和 簡化比的類 struct FilenameAndRatio { FilenameAndRatio(string f, double r) : fileName(f), ratio(r){} string fileName; // 檔名 double ratio; // 簡化比 }; // 測試用例引數化類:獲得正確的簡化模型 class MeshSimplifyTest_1 : public ::testing::TestWithParam<FilenameAndRatio> { }; // 測試用例引數化類:不能獲得正確的簡化模型 class MeshSimplifyTest_2 : public ::testing::TestWithParam<FilenameAndRatio> { }; // 時間超長的測試用例 class LongTime_MeshSimplifyTest : public ::testing::TestWithParam<FilenameAndRatio> { }; // 引數化:正確簡化 TEST_P(MeshSimplifyTest_1, GGP_22144) { FilenameAndRatio Data = GetParam(); string fileName = Data.fileName; double ratio = Data.ratio; SimplifyResultTest_1(fileName, ratio); } // 引數化:不能正確簡化 TEST_P(MeshSimplifyTest_2, GGP_22144) { FilenameAndRatio Data = GetParam(); string fileName = Data.fileName; double ratio = Data.ratio; SimplifyResultTest_2(fileName, ratio); } // 引數化:不能正確簡化 TEST_P(LongTime_MeshSimplifyTest, GGP_22144) { FilenameAndRatio Data = GetParam(); string fileName = Data.fileName; double ratio = Data.ratio; SimplifyResultTest_1(fileName, ratio); } // 測試用例:正確簡化 INSTANTIATE_TEST_CASE_P(TrueReturn, MeshSimplifyTest_1, testing::Values(// 經典網格模型 FilenameAndRatio("bunny.obj", 0.0), // /0 //v: 3508 f: 6944 FilenameAndRatio("bunny.ply", 0.5), // /1 //v: 35947 f: 69451 FilenameAndRatio("horse.ply", 1.0), // /2 //v: 48485 f: 96966 FilenameAndRatio("bunny.obj", 0.00001), // /3 //v: 3508 f: 6944 FilenameAndRatio("bunny.ply", 0.99999), // /4 //v: 35947 f: 69451 FilenameAndRatio("bunny.obj", 1.00001), // /5 //v: 3508 f: 6944 FilenameAndRatio("horse.ply", 96966 - 3), // /6 //v: 48485 f: 96966 FilenameAndRatio("horse.ply", 5), // /7 //v: 48485 f: 96966 // 離散獲得的網格模型 FilenameAndRatio("annulus.ply", 0.5), // /8 //v: 64 f: 64 FilenameAndRatio("cone.ply", 0.00001), // /9 //v: 74 f: 144 FilenameAndRatio("sphere.ply", 0.99999), // /10 //v: 642 f: 1280 FilenameAndRatio("ModifyFile.obj", 0.5), // /11 //v: 642 f: 1280 // 存在往復邊 FilenameAndRatio("ReciproEdge.ply", 0.5), // /12 //v: 75 f: 145 // 存在退化三角形 FilenameAndRatio("DegeTriangle.ply", 0.5), // /13 //v: 74 f: 144 // 存在重合的三角形 FilenameAndRatio("CoinTriangle.ply", 0.1), // /14 //v: 642 f: 1281 // 非流行網格模型 FilenameAndRatio("NonManifold.ply", 0.5), // /15 //v: 38 f: 67 // 存在遊離的點 FilenameAndRatio("FreeVertex.obj", 0.5), // /16 //v: 3511 f: 6944 // 驗證三角網分割的特殊用例 FilenameAndRatio("DesignChair.obj", 0.5), // /17 //v: 16034 f: 32064 FilenameAndRatio("Medalballfootball.obj", 0.5), // /18 //v: 23778 f: 47492 FilenameAndRatio("MedBottles.obj", 0.5), // /19 //v: 2214 f: 4396 FilenameAndRatio("StingSword.obj", 0.5) )); // /20 //v: 1329 f: 2596 // 測試用例:不能正確簡化 INSTANTIATE_TEST_CASE_P(FalseReturn, MeshSimplifyTest_2, testing::Values(// 錯誤的簡化比 FilenameAndRatio("bunny.obj", -1.0), // /0 //v: 3508 f: 6944 FilenameAndRatio("bunny.ply", -0.5), // /1 //v: 35947 f: 69451 FilenameAndRatio("horse.ply", -0.00001), // /2 //v: 48485 f: 96966 FilenameAndRatio("bunny.ply", 69451 + 3), // /3 //v: 35947 f: 69451 // 錯誤的模型 // 含有錯誤的識別符號 //FilenameAndRatio("ErrorIdentifier.ply", 0.5), // /4 //v: 64 f: 64 // 卡住了 // 三角形有些點不存在 //FilenameAndRatio("InvalidVertex.ply", 0.5), // /5 //v: 642 f: 1280 // 生成了簡化後網格模型,沒有報錯 // 0個點,0個面 FilenameAndRatio("NoVertexFace.ply", 0.5), // /6 //v: 0 f: 0 // 錯誤的路徑 FilenameAndRatio("bunny", 0.5), // /7 FilenameAndRatio("12345543", 0.5), // /8 FilenameAndRatio("bunny\\bunny.obj", 0.5) )); // /9 // 執行超長時間的測試用例 //INSTANTIATE_TEST_CASE_P(LongTime, LongTime_MeshSimplifyTest, testing::Values(// 執行時間較長的用例 // // FilenameAndRatio("Armadillo.ply", 0.9), // /0 //v: 172974 f: 345944 // FilenameAndRatio("blade.ply", 441477), // /1 //v: 882954 f: 1765388 // FilenameAndRatio("dragon_vrip.ply", 0.9), // /2 //v: 437645 f: 871414 // FilenameAndRatio("hand.ply", 0.9), // /3 //v: 327323 f: 654666 // FilenameAndRatio("happy_vrip.ply", 0.9), // /4 //v: 543652 f: 1087716 // FilenameAndRatio("sofa.obj", 0.9) )); // /5 //v: 189637 f: 379234