def key_pressed(viewer, key, modifier): global V global U global F global L if key == ord('r') or key == ord('R'): U = V; elif key == ord(' '): # Recompute just mass matrix on each step M = igl.eigen.SparseMatrixd() igl.massmatrix(U,F,igl.MASSMATRIX_TYPE_BARYCENTRIC,M); # Solve (M-delta*L) U = M*U S = (M - 0.001*L) solver = igl.eigen.SimplicialLLTsparse(S) U = solver.solve(M*U) # Compute centroid and subtract (also important for numerics) dblA = igl.eigen.MatrixXd() igl.doublearea(U,F,dblA) print(dblA.sum()) area = 0.5*dblA.sum() BC = igl.eigen.MatrixXd() igl.barycenter(U,F,BC) centroid = igl.eigen.MatrixXd([[0.0,0.0,0.0]]) for i in range(0,BC.rows()): centroid += 0.5*dblA[i,0]/area*BC.row(i) U -= centroid.replicate(U.rows(),1) # Normalize to unit surface area (important for numerics) U = U / math.sqrt(area) else: return False # Send new positions, update normals, recenter viewer.data.set_vertices(U) viewer.data.compute_normals() viewer.core.align_camera_center(U,F) return True
def construct_matrices(self): """ Construct FEM matrices """ V = self.vertices F = self.faces # Compute gradient operator: #F*3 by #V G = igl.grad(V, F).tocoo() L = igl.cotmatrix(V, F).tocoo() N = igl.per_face_normals(V, F, np.array([0., 0., 0.])) A = igl.doublearea(V, F) A = A[:, np.newaxis] M = igl.massmatrix(V, F, igl.MASSMATRIX_TYPE_VORONOI).tocoo() M = M.data # Compute latitude and longitude directional vector fields NS = np.reshape(G.dot(self.lat), [self.nf, 3], order='F') EW = np.cross(NS, N) # Compute F2V matrix (weigh by area) # adjacency i = self.faces.ravel() j = np.arange(self.nf).repeat(3) one = np.ones(self.nf * 3) adj = sparse.csc_matrix((one, (i, j)), shape=(self.nv, self.nf)) tot_area = adj.dot(A) norm_area = A.ravel().repeat(3) / np.squeeze(tot_area[i]) F2V = sparse.csc_matrix((norm_area, (i, j)), shape=(self.nv, self.nf)) # Compute interpolation matrix if self.level > 0: intp = self.intp[self.nv_prev:] i = np.concatenate( (np.arange(self.nv), np.arange(self.nv_prev, self.nv))) j = np.concatenate((np.arange(self.nv_prev), intp[:, 0], intp[:, 1])) ratio = np.concatenate( (np.ones(self.nv_prev), 0.5 * np.ones(2 * intp.shape[0]))) intp = sparse.csc_matrix((ratio, (i, j)), shape=(self.nv, self.nv_prev)) else: intp = sparse.csc_matrix(np.eye(self.nv)) # Compute vertex mean matrix self.G = G # gradient matrix self.L = L # laplacian matrix self.N = N # normal vectors (per-triangle) self.NS = NS # north-south vectors (per-triangle) self.EW = EW # east-west vectors (per-triangle) self.F2V = F2V # map face quantities to vertices self.M = M # mass matrix (area of voronoi cell around node. for integration) self.Seq = self._rotseq(self.vertices) self.Intp = intp
def construct_mesh_matrices_de(vertices, faces): v_num, f_num = vertices.shape[0], faces.shape[0] G = igl.grad(vertices, faces) L = igl.cotmatrix(vertices, faces) A = igl.doublearea(vertices, faces) XN = np.array([1, 0, 0], dtype=np.float32) YN = np.array([0, 1, 0], dtype=np.float32) i = faces.ravel() j = np.arange(f_num).repeat(3) one = np.ones(f_num * 3) adj = sparse.csc_matrix((one, (i, j)), shape=(v_num, f_num)) tot_area = adj.dot(A) norm_area = A.ravel().repeat(3) / np.squeeze(tot_area[i]) F2V = sparse.csc_matrix((norm_area, (i, j)), shape=(v_num, f_num)) return {'G': G, 'L': L, 'A': A, 'XN': XN, 'YN': YN, 'F2V': F2V}
def construct_mesh_matrices(vertices, faces): v_num, f_num = vertices.shape[0], faces.shape[0] G = igl.grad(vertices, faces) # L = igl.cotmatrix(vertices, faces) L = cotmatrix_firstvonly(vertices, faces) A = igl.doublearea(vertices, faces) XN = np.array([1, 0, 0], dtype=np.float32) YN = np.array([0, 1, 0], dtype=np.float32) i = faces[:, 0].ravel() # each triangle only belongs to the first vertex! j = np.arange(f_num) one = np.ones(f_num) adj = sparse.csc_matrix((one, (i, j)), shape=(v_num, f_num)) tot_area = adj.dot(A) norm_area = A.ravel() / np.squeeze(tot_area[i] + 1e-6) F2V = sparse.csc_matrix((norm_area, (i, j)), shape=(v_num, f_num)) return {'G': G, 'L': L, 'A': A, 'XN': XN, 'YN': YN, 'F2V': F2V}
def construct_mesh_matrices_de(vertices, faces, lat): v_num, f_num = vertices.shape[0], faces.shape[0] G = igl.grad(vertices, faces) L = igl.cotmatrix(vertices, faces) A = igl.doublearea(vertices, faces) N = igl.per_face_normals(vertices, faces, vertices) YN = np.reshape(G.dot(lat), [f_num, 3], order='F') YN = YN / (np.linalg.norm(YN, axis=1)[:, np.newaxis]+1e-6) XN = np.cross(YN, N) i = faces.ravel() j = np.arange(f_num).repeat(3) one = np.ones(f_num * 3) adj = sparse.csc_matrix((one, (i, j)), shape=(v_num, f_num)) tot_area = adj.dot(A) norm_area = A.ravel().repeat(3) / np.squeeze(tot_area[i] + 1e-6) F2V = sparse.csc_matrix((norm_area, (i, j)), shape=(v_num, f_num)) return { 'G': G, 'L': L, 'A': A, 'XN': XN, 'YN': YN, 'F2V': F2V }
def run(self): if not self.copyData(): return if self.geo.getNumFaces() == 0 or self.geo.getNumVertexes() == 0: return mt = self.get_property("Method") if mt == "FaceCent": self.geo.meshFuncs.facePos(True) elif mt == "Area": area = igl.doublearea(self.geo.getVertexes(), self.geo.mesh.face_vertex_indices()) / 2.0 self.geo.setFaceAttribData("area", area, attribType='float', defaultValue=0.0) elif mt == "Edge Length": self.geo.meshFuncs.edgeLength(True)
def construct_mesh_matrices(vertices, faces, lat): v_num, f_num = vertices.shape[0], faces.shape[0] G = igl.grad(vertices, faces) # L = igl.cotmatrix(vertices, faces) L = cotmatrix_firstvonly(vertices, faces) A = igl.doublearea(vertices, faces) N = igl.per_face_normals(vertices, faces, vertices) # XN = np.array([1, 0, 0], dtype=np.float32) # YN = np.array([0, 1, 0], dtype=np.float32) YN = np.reshape(G.dot(lat), [f_num, 3], order='F') YN = YN / (np.linalg.norm(YN, axis=1)[:, np.newaxis]+1e-6) XN = np.cross(YN, N) i = faces[:, 0].ravel() # each triangle only belongs to the first vertex! j = np.arange(f_num) one = np.ones(f_num) adj = sparse.csc_matrix((one, (i, j)), shape=(v_num, f_num)) tot_area = adj.dot(A) norm_area = A.ravel() / np.squeeze(tot_area[i] + 1e-6) F2V = sparse.csc_matrix((norm_area, (i, j)), shape=(v_num, f_num)) return { 'G': G, 'L': L, 'A': A, 'XN': XN, 'YN': YN, 'F2V': F2V, 'N': N }
# Load a mesh in OFF format igl.readOFF("../../tutorial/shared/cow.off", V, F) # Compute Laplace-Beltrami operator: #V by #V igl.cotmatrix(V,F,L) # Alternative construction of same Laplacian G = igl.eigen.SparseMatrixd() K = igl.eigen.SparseMatrixd() # Gradient/Divergence igl.grad(V,F,G); # Diagonal per-triangle "mass matrix" dblA = igl.eigen.MatrixXd() igl.doublearea(V,F,dblA) # Place areas along diagonal #dim times T = (dblA.replicate(3,1)*0.5).asDiagonal() * 1 # Laplacian K built as discrete divergence of gradient or equivalently # discrete Dirichelet energy Hessian temp = -G.transpose() K = -G.transpose() * T * G print("|K-L|: ",(K-L).norm()) def key_pressed(viewer, key, modifier): global V global U
def test_doublearea(self): a = igl.doublearea(self.v1, self.f1) self.assertEqual(a.shape[0], self.f1.shape[0]) self.assertEqual(a.dtype, self.v1.dtype) self.assertTrue(a.flags.c_contiguous)
def test_doublearea(self): a = igl.doublearea(self.v1, self.f1) self.assertEqual(a.shape[0], self.f1.shape[0]) self.assertEqual(a.dtype, self.v1.dtype)