// Load a mesh using the assimp library, and calculate its mesh saliency bool load_mesh (const char* file_name, GLuint* vao, int* point_count) { const aiScene* scene = aiImportFile (file_name, aiProcess_Triangulate); if (!scene) { fprintf (stderr, "ERROR: reading mesh %s\n", file_name); return false; } // Get first mesh in file only const aiMesh* mesh = scene->mMeshes[0]; printf (" %i vertices in mesh[0]\n", mesh->mNumVertices); printf (" %i faces in mesh[0]\n", mesh->mNumFaces); // Pass back number of vertex points in mesh *point_count = mesh->mNumVertices; vertexCnt = *point_count; // Generate a VAO, using the pass-by-reference parameter that we give to the function glGenVertexArrays (1, vao); glBindVertexArray (*vao); points = NULL; // array of vertex points if (!mesh->HasPositions()) { fprintf(stderr, "ERROR: mesh %s don't have vertex data!\n", file_name); return false; } float xMin = oo, yMin = oo, zMin = oo; float xMax = -oo, yMax = -oo, zMax = -oo; // Get the mesh's vertecies points = (GLfloat*)malloc (vertexCnt * 3 * sizeof (GLfloat)); for (int i = 0; i < vertexCnt; i++) { const aiVector3D* vp = &(mesh->mVertices[i]); points[i * 3] = (GLfloat)vp->x; points[i * 3 + 1] = (GLfloat)vp->y; points[i * 3 + 2] = (GLfloat)vp->z; xMin = fMin(xMin, vp->x), xMax = fMax(xMax, vp->x); yMin = fMin(yMin, vp->y), yMax = fMax(yMax, vp->y); zMin = fMin(zMin, vp->z), zMax = fMax(zMax, vp->z); } // Calculate the mesh's normal normals = (GLfloat*)malloc(vertexCnt * 3 * sizeof(GLfloat)); for(int i = 0; i < mesh->mNumFaces; i++) { int idx[3]; for(int k = 0; k < 3; k++) idx[k] = mesh->mFaces[i].mIndices[k]; // get all vertecies' location const aiVector3D* v1 = &(mesh->mVertices[idx[0]]); const aiVector3D* v2 = &(mesh->mVertices[idx[1]]); const aiVector3D* v3 = &(mesh->mVertices[idx[2]]); // vectors vec3 faceVec1 = vec3(v2->x - v1->x, v2->y - v1->y, v2->z - v1->z); vec3 faceVec2 = vec3(v3->x - v2->x, v3->y - v2->y, v3->z - v2->z); vec3 crossProd = cross(faceVec1, faceVec2); for(int k = 0; k < 3; k++) { normals[idx[k]*3+0] += (GLfloat)crossProd.v[0], normals[idx[k]*3+1] += (GLfloat)crossProd.v[1], normals[idx[k]*3+2] += (GLfloat)crossProd.v[2]; } } for(int i = 0; i < vertexCnt; i++) { float norm = 0.0f; for(int k = 0; k < 3; k++) norm += normals[i*3+k]*normals[i*3+k]; for(int k = 0; k < 3; k++) normals[i*3+k] /= sqrt(norm); } // Calculate each vertecies' shape operator mat3* shapeOperators = NULL; float* vertexArea = NULL; shapeOperators = (mat3*)malloc(vertexCnt * sizeof(mat3)); vertexArea = (float*)malloc(vertexCnt * sizeof(float)); for(int i = 0; i < vertexCnt ; i++) { vertexArea[i] = 0.0f; for(int j = 0; j < 9; j++) shapeOperators[i].m[j] = 0.0f; } for(int k = 0; k < mesh->mNumFaces; k++) { // Calculate the face's area aiVector3D* aiVec[3]; for(int idx = 0; idx < 3; idx++) aiVec[idx] = &(mesh->mVertices[mesh->mFaces[k].mIndices[idx]]); vec3 faceVec1 = vec3(aiVec[1]->x - aiVec[0]->x, aiVec[1]->y - aiVec[0]->y, aiVec[1]->z - aiVec[0]->z); vec3 faceVec2 = vec3(aiVec[2]->x - aiVec[1]->x, aiVec[2]->y - aiVec[1]->y, aiVec[2]->z - aiVec[1]->z); vec3 vecArea = cross(faceVec1, faceVec2); float faceArea = sqrt(vecArea.v[0]*vecArea.v[0] + vecArea.v[1]*vecArea.v[1] + vecArea.v[2]*vecArea.v[2]); for(int idx = 0; idx < 3; idx++) { int i = mesh->mFaces[k].mIndices[idx]; int j = mesh->mFaces[k].mIndices[(idx+1)%3]; // Get vertex i and j's normal vectors. vec3 Ni = vec3(normals[i*3], normals[i*3+1], normals[i*3+2]); vec3 Nj = vec3(normals[j*3], normals[j*3+1], normals[j*3+2]); // Get vertex i and j's location. const aiVector3D* aiVi = &(mesh->mVertices[i]); const aiVector3D* aiVj = &(mesh->mVertices[j]); vec3 Vi = vec3(aiVi->x, aiVi->y, aiVi->z); vec3 Vj = vec3(aiVj->x, aiVj->y, aiVj->z); // For vertex i, update the relative part of its shape operator vec3 Tij = (identity_mat3() - wedge(Ni, Ni))*(Vi-Vj); Tij = normalise(Tij); float kappa_ij = 2*dot(Ni, Vj-Vi); kappa_ij /= get_squared_dist(Vi, Vj); // Maintain vi's shape operator shapeOperators[i] = shapeOperators[i] + (wedge(Tij, Tij) * (kappa_ij * faceArea)); vertexArea[i] += faceArea; // For vertex j, update the relative part of its shape operator vec3 Tji = (identity_mat3() - wedge(Nj, Nj))*(Vj-Vi); Tji = normalise(Tji); float kappa_ji = 2*dot(Nj, Vi-Vj); kappa_ji /= get_squared_dist(Vi, Vj); // Maintain vj's shape operator shapeOperators[j] = shapeOperators[j] + (wedge(Tji, Tji) * (kappa_ji * faceArea)); vertexArea[j] += faceArea; } } for(int i = 0; i < vertexCnt; i++) { shapeOperators[i] = shapeOperators[i] * (1.0f/vertexArea[i]);// * 10000000.0f; //print(shapeOperators[i]); } free(vertexArea); // Diagonalize the shape operator, and get the mean curvature meanCurvature = (float*)malloc(vertexCnt * sizeof(float)); for(int k = 0; k < vertexCnt; k++) { vec3 E1 = vec3(1.0f, 0.0f, 0.0f); vec3 Nk = vec3(normals[k*3], normals[k*3+1], normals[k*3+2]); bool isMinus = get_squared_dist(E1, Nk) > get_squared_dist(E1 * (-1.0f), Nk); vec3 Wk; // Diagnoalization by the Householder transform if (!isMinus) Wk = E1 + Nk; else Wk = E1 - Nk; Wk = normalise(Wk); mat3 Qk = identity_mat3() - (wedge(Wk, Wk) * 2.0f); mat3 Mk = transpose(Qk) * shapeOperators[k] * Qk; // Calculate the mean curvature by M_k's trace; meanCurvature[k] = (GLfloat)(Mk.m[4] + Mk.m[8]); } free(shapeOperators); // Calculate the incident matrix ( as linked list ) int* first = NULL; int* next = NULL; int* incidentVertex = NULL; first = (int*)malloc(vertexCnt * sizeof(int)); for(int i = 0; i < vertexCnt; i++) first[i] = -1; next = (int*)malloc(mesh->mNumFaces * 6 * sizeof(int)); incidentVertex = (int*)malloc(mesh->mNumFaces * 6 * sizeof(int)); int edgeCnt = 0; for(int k = 0; k < mesh->mNumFaces; k++) { int idx[3]; for(int i = 0; i < 3; i++) idx[i] = mesh->mFaces[k].mIndices[i]; for(int i = 0; i < 3; i++) { int j1 = idx[(i+1)%3], j2 = idx[(i+2)%3]; incidentVertex[++edgeCnt] = j1; next[edgeCnt] = first[idx[i]]; first[idx[i]] = edgeCnt; incidentVertex[++edgeCnt] = j2; next[edgeCnt] = first[idx[i]]; first[idx[i]] = edgeCnt; } } printf("BFS 1\n"); // Calculate the mesh saliency by BFS float diagonalLength = sqrt((xMax-xMin)*(xMax-xMin) + (yMax-yMin)*(yMax-yMin) + (zMax-zMin)*(zMax-zMin)); float sigma = 0.003 * diagonalLength; float* saliency[7]; float maxSaliency[7]; for(int i = 2; i <= 6; i++) { saliency[i] = NULL;; saliency[i] = (float*)malloc(vertexCnt * sizeof(float)); maxSaliency[i] = -oo; } // Labeled the vertecies whether covered or not. bool* used = NULL; used = (bool*)malloc(vertexCnt * sizeof(bool)); for(int k = 0; k < vertexCnt; k++) { if(k%1000 == 0) printf("#%d#\n", k); // Initialize the saliency and its local counter. for(int i = 2; i <= 6; i++) saliency[i][k] = 0.0f; // Initialize the saliency's Gaussian filter. float gaussianSigma1[7], gaussianSigma2[7], sumSigma1[7], sumSigma2[7]; for(int i = 2; i <= 6; i++) gaussianSigma1[i] = gaussianSigma2[i] = 0.0f, sumSigma1[i] = sumSigma2[i] = 0.0f; // Get the current vertex's information. aiVector3D* aiVec = &(mesh->mVertices[k]); vec3 vVec = vec3(aiVec->x, aiVec->y, aiVec->z); // Initialize the queue to find neighbourhood. for(int i = 0; i < vertexCnt; i++) used[i] = false; queue<int> Q; Q.push(k); used[k] = true; // Frsit BFS while(!Q.empty()) { // Get the front element in the queue. int idx = Q.front(); Q.pop(); aiVec = &(mesh->mVertices[idx]); vec3 idxVec = vec3(aiVec->x, aiVec->y, aiVec->z); // Put the next level vertecies into the queue. for(int e = first[idx]; e != -1; e = next[e]) { int idxNext = incidentVertex[e]; // Expand the next level vertecies. if(!used[idxNext]) { aiVec = &(mesh->mVertices[idxNext]); vec3 idxNextVec = vec3(aiVec->x, aiVec->y, aiVec->z); if(get_squared_dist(vVec, idxNextVec) <= 36*sigma*sigma) Q.push(incidentVertex[e]), used[incidentVertex[e]] = 1; } } // Update Gaussian filter float dist = get_squared_dist(vVec, idxVec); for(int i = 2; i <= 6; i++) { float sigmaHere = i*i*sigma*sigma; if(dist <= sigmaHere) { float factor = exp(-dist/(2*sigmaHere)); gaussianSigma1[i] += meanCurvature[idx] * factor; sumSigma1[i] += factor; } if(dist <= 2*sigmaHere) { float factor = exp(-dist/(8*sigma*sigma)); gaussianSigma2[i] += meanCurvature[idx] * factor; sumSigma2[i] += factor; } } } for(int i = 2; i <= 6; i++) { saliency[i][k] = fabs(gaussianSigma1[i]/sumSigma1[i] - gaussianSigma2[i]/sumSigma2[i]); maxSaliency[i] = fMax(maxSaliency[i], saliency[i][k]); } } printf("BFS 2\n"); // Second BFS and get the non-linear normailization of suppressian's saliency. smoothSaliency = (float*)malloc(vertexCnt * sizeof(float)); for(int k = 0; k < vertexCnt; k++) { if(k%1000 == 0) printf("[%d]\n", k); smoothSaliency[k] = 0.0f; float localMaxSaliency[7];//, localCntSaliency[7]; for(int i = 2; i <= 6; i++) localMaxSaliency[i] = -oo; // Get the current vertex's information. aiVector3D* aiVec = &(mesh->mVertices[k]); vec3 vVec = vec3(aiVec->x, aiVec->y, aiVec->z); // Initialize the queue to find neighbourhood. for(int i = 0; i < vertexCnt; i++) used[i] = false; queue<int> Q; Q.push(k); used[k] = true; while(!Q.empty()) { // Get the front element in the queue. int idx = Q.front(); Q.pop(); //aiVec = &(mesh->mVertices[idx]); //vec3 idxVec = vec3(aiVec->x, aiVec->y, aiVec->z); // Put the next level vertecies into the queue. for(int e = first[idx]; e != -1; e = next[e]) { int idxNext = incidentVertex[e]; // Expand the next level vertecies. if(!used[idxNext]) { aiVec = &(mesh->mVertices[idxNext]); vec3 idxNextVec = vec3(aiVec->x, aiVec->y, aiVec->z); if(get_squared_dist(vVec, idxNextVec) <= 36*sigma*sigma) Q.push(incidentVertex[ e]), used[incidentVertex[e]] = 1; } } // Update Gaussian filter for(int i = 2; i <= 6; i++) localMaxSaliency[i] = fMax(localMaxSaliency[i], saliency[i][idx]); } // Calculate the weighted saliency float saliencySum = 0.0f; for(int i = 2; i <= 6; i++) { float factor = (maxSaliency[i]-localMaxSaliency[i])*(maxSaliency[i]-localMaxSaliency[i]); smoothSaliency[k] += (GLfloat)saliency[i][k] * factor; saliencySum += factor; } smoothSaliency[k] /= (GLfloat)saliencySum; } // Clean up resources free(first); free(next); free(incidentVertex); for(int i = 2; i <= 6; i++) free(saliency[i]); // Copy all vertecies and normal vertors in mesh data into VBOs /* { GLuint vbo; glGenBuffers (1, &vbo); glBindBuffer (GL_ARRAY_BUFFER, vbo); glBufferData ( GL_ARRAY_BUFFER, 3 * vertexCnt * sizeof (GLfloat), points, GL_STATIC_DRAW ); glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, 0, NULL); glEnableVertexAttribArray (0); free (points); } */ // Copy all normal vectors in mesh data into VBOs updateDisplayType(1); aiReleaseImport (scene); printf ("mesh loaded\n"); return true; }
/* * return the minimum on the projective line * */ int lp_base_case(FLOAT halves[][2], /* halves --- half lines */ int m, /* m --- terminal marker */ FLOAT n_vec[2], /* n_vec --- numerator funciton */ FLOAT d_vec[2], /* d_vec --- denominator function */ FLOAT opt[2], /* opt --- optimum */ int next[], int prev[]) /* next, prev --- double linked list of indices */ { FLOAT cw_vec[2], ccw_vec[2]; #ifdef CHECK FLOAT d_cw; int i; #endif int status, degen; FLOAT ab; /* find the feasible region of the line */ status = wedge(halves,m,next,prev,cw_vec,ccw_vec,°en); if(status==INFEASIBLE) return(status); /* no non-trivial constraints one the plane: return the unconstrained ** optimum */ if(status==UNBOUNDED) { return(lp_no_constraints(1,n_vec,d_vec,opt)); } ab = ABS(cross2(n_vec,d_vec)); if(ab < 2*EPS*EPS) { if(dot2(n_vec,n_vec) < 2*EPS*EPS || dot2(d_vec,d_vec) > 2*EPS*EPS) { /* numerator is zero or numerator and denominator are linearly dependent */ opt[0] = cw_vec[0]; opt[1] = cw_vec[1]; status = AMBIGUOUS; } else { /* numerator is non-zero and denominator is zero ** minimize linear functional on circle */ if(!degen && cross2(cw_vec,n_vec) <= 0.0 && cross2(n_vec,ccw_vec) <= 0.0 ) { /* optimum is in interior of feasible region */ opt[0] = -n_vec[0]; opt[1] = -n_vec[1]; } else if(dot2(n_vec,cw_vec) > dot2(n_vec,ccw_vec) ) { /* optimum is at counter-clockwise boundary */ opt[0] = ccw_vec[0]; opt[1] = ccw_vec[1]; } else { /* optimum is at clockwise boundary */ opt[0] = cw_vec[0]; opt[1] = cw_vec[1]; } status = MINIMUM; } } else { /* niether numerator nor denominator is zero */ lp_min_lin_rat(degen,cw_vec,ccw_vec,n_vec,d_vec,opt); status = MINIMUM; } #ifdef CHECK for(i=0; i!=m; i=next[i]) { d_cw = dot2(opt,halves[i]); if(d_cw < -2*EPS) { printf("error at base level\n"); exit(1); } } #endif return(status); }