Ejemplo n.º 1
0
def makeLaplacianMatrixSolverIGLHard(VPos, ITris, anchorsIdx):
    VPosE = igl.eigen.MatrixXd(VPos)
    ITrisE = igl.eigen.MatrixXi(ITris)
    L = igl.eigen.SparseMatrixd()
    M = igl.eigen.SparseMatrixd()
    M_inv = igl.eigen.SparseMatrixd()
    igl.cotmatrix(VPosE,ITrisE,L)
    igl.massmatrix(VPosE,ITrisE,igl.MASSMATRIX_TYPE_VORONOI,M)
    igl.invert_diag(M,M_inv)
    L = M_inv*L
    deltaCoords = L*VPosE
    deltaCoords = np.array(deltaCoords)
    
    #Bi-laplacian
    Q = L.transpose()*L
Ejemplo n.º 2
0
def conformal_flow(vertices, faces):
    vertices = normalize(np.copy(vertices))

    L = igl.cotmatrix(vertices, faces)

    itrs = 20
    time_step = .1

    for i in range(itrs):
        vertices = normalize(vertices)

        # this is a lumped mass matrix
        M = igl.massmatrix(vertices, faces, igl.MASSMATRIX_TYPE_BARYCENTRIC)
        S = (M - time_step * L)
        b = M.dot(vertices)
        vertices = spsolve(S, b)

    vertices = normalize(vertices)

    print("flow error: " + str(get_error(vertices)))

    vertices = project_sphere(vertices)

    print("percentage of flipped faces: " +
          str(100 * get_flipped_normals(vertices, faces)))
    return vertices
Ejemplo n.º 3
0
def get_mesh_cotmatrix_igl(mesh, fix_boundaries=True):
    """
    Gets the laplace operator of the mesh

    Parameters
    ----------
    mesh: :class: 'compas.datastructures.Mesh'
    fix_boundaries : bool

    Returns
    ----------
    :class: 'scipy.sparse.csr_matrix'
        sparse matrix (dimensions: #V x #V), laplace operator, each row i corresponding to v(i, :)
    """
    check_package_is_installed('igl')
    import igl
    v, f = mesh.to_vertices_and_faces()
    C = igl.cotmatrix(np.array(v), np.array(f))

    if fix_boundaries:
        # fix boundaries by putting the corresponding columns of the sparse matrix to 0
        C_dense = C.toarray()
        for i, (vkey, data) in enumerate(mesh.vertices(data=True)):
            if data['boundary'] > 0:
                C_dense[i][:] = np.zeros(len(v))
        C = scipy.sparse.csr_matrix(C_dense)
    return C
Ejemplo n.º 4
0
def get_lbo(vertices, faces, area_type):
    """
    Return the Laplace-Beltrami Operator for the surface.

    Parameters
    ----------
    vertices : np.array
        (N x 3) array of vertex coordinates.
    faces : np.array
        (N x 3) array of faces making up the surface.
    area_type : str
        Which definition of vertex area to use for the mass matrix 
        computation.
    
    Returns
    -------
    L : scipy sparse array
        (N x N) sparse weighting matrix constituting the Laplace-
        Beltrami Operator for this surface.
    """
    l = igl.cotmatrix(vertices, faces)
    m = get_mass_matrix(vertices, faces, area_type)
    minv = m.power(-1)
    L = -minv.dot(l)
    return L
Ejemplo n.º 5
0
 def test_harmonic(self):
     l = igl.cotmatrix(self.v1, self.f1)
     m = igl.massmatrix(self.v1, self.f1, igl.MASSMATRIX_TYPE_VORONOI)
     b = np.array([1, 2, 10, 7])
     bc = self.v1[b, :]
     k = 1
     w = igl.harmonic_weights_from_laplacian_and_mass(l, m, b, bc, k)
     self.assertTrue(w.flags.c_contiguous)
Ejemplo n.º 6
0
 def set_parameters(self, V, F):
     # reset
     self.reset()
     # compute property given V and F
     self.N = igl.per_vertex_normals(V, F)
     self.L = igl.cotmatrix(V, F)
     VA = igl.massmatrix(V, F, 0)
     self.VA = VA.diagonal()
     # get face adjacency list
     VF, NI = igl.vertex_triangle_adjacency(F, V.shape[0])
     adjFList = construct_adjacency_list(VF, NI)
     # arap
     self.K = igl.arap_rhs(V, F, d=3, energy=1)
     # they are all list since length can be different
     self.hEList = [None] * V.shape[0]
     self.WVecList = [None] * V.shape[0]
     self.dVList = [None] * V.shape[0]
     for i in range(0, V.shape[0]):
         adjF = adjFList[i]
         len_adjF = adjF.shape[0]
         self.hEList[i] = np.zeros((len_adjF * 3, 2), dtype=int)
         self.WVecList[i] = np.zeros(len_adjF * 3)
         self.dVList[i] = np.zeros((3, 3 * len_adjF))
         for j in range(0, len_adjF):
             vIdx = adjF[j]
             v0 = F[vIdx, 0]
             v1 = F[vIdx, 1]
             v2 = F[vIdx, 2]
             # half edge indices
             # hE = np.array([[v0, v1], [v1, v2], [v2, v0]])
             # self.hEList[i] = hE
             self.hEList[i][3 * j, 0] = v0
             self.hEList[i][3 * j, 1] = v1
             self.hEList[i][3 * j + 1, 0] = v1
             self.hEList[i][3 * j + 1, 1] = v2
             self.hEList[i][3 * j + 2, 0] = v2
             self.hEList[i][3 * j + 2, 1] = v0
             # weight vec
             self.WVecList[i][3 * j] = self.L[v0, v1]
             self.WVecList[i][3 * j + 1] = self.L[v1, v2]
             self.WVecList[i][3 * j + 2] = self.L[v2, v0]
         V_hE0 = V[self.hEList[i][:, 0], :]
         V_hE1 = V[self.hEList[i][:, 1], :]
         self.dVList[i] = np.transpose(V_hE1 - V_hE0)
         self.WVecList[i] = np.diag(self.WVecList[i])
     # other var
     numV = V.shape[0]
     self.zAll = np.random.rand(3, numV) * 2.0 - 1.0
     self.uAll = np.random.rand(3, numV) * 2.0 - 1.0
     self.zAll = np.zeros((3, numV))
     self.uAll = np.zeros((3, numV))
     self.rhoAll = np.full(numV, self.param.rhoInit)
Ejemplo n.º 7
0
    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
Ejemplo n.º 8
0
def compute_cotan_laplacian(df):
    """
    compute mass matrix and cotan laplacian matrix
    :param df: pandas data frame
    :return L, M, in that order, CSR-sparse matrix
    """
    points = df2points(df).T
    assert points.shape[-1] == 3
    ch = ConvexHull(points)
    assert points.shape[0] == ch.points.shape[0]
    L = -csr_matrix(igl.cotmatrix(ch.points, ch.simplices))  # positive semidefiniteness
    # ISSUE: some areas are way too small such that igl ends up considering it exactly zero.
    # as a result, it's not even stored in the sparse matrix. coarsening needed
    M = csr_matrix(igl.massmatrix(ch.points, ch.simplices, igl.MASSMATRIX_TYPE_VORONOI))
    return L, M
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}
Ejemplo n.º 10
0
    def __init__(self, mesh, OUTPUT_PATH):
        utils.check_package_is_installed('igl')
        import igl

        logger.info('GeodesicsSolver')
        self.mesh = mesh
        self.OUTPUT_PATH = OUTPUT_PATH

        self.use_forwards_euler = True

        v, f = mesh.to_vertices_and_faces()
        v = np.array(v)
        f = np.array(f)

        # compute necessary data
        self.cotans = igl.cotmatrix_entries(v, f)  # compute_cotan_field(self.mesh)
        self.L = igl.cotmatrix(v, f)  # assemble_laplacian_matrix(self.mesh, self.cotans)
        self.M = igl.massmatrix(v, f)  # create_mass_matrix(mesh)
Ejemplo n.º 11
0
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 features_extractor(classes,DNA_size=50):
    """Extract the features from the samples in the dataset. The type of features is the ShapeDNA.

    :param classes: list
        list of the classes
    :param DNA_size: int
        size of the feature vector
    """
    print("\nFeature extraction")
    
    for c in classes:
        print(c)
        for file in os.listdir(os.path.join('.', 'Dataset', c)):
            if file.endswith(".off"):
                print("\t", file, end=" ... ")
                # Load mesh
                v, f = igl.read_triangle_mesh(os.path.join('.', 'Dataset',c, file))
                M = igl.massmatrix(v, f, igl.MASSMATRIX_TYPE_VORONOI)
                v = v / np.sqrt(M.sum())

                # Compute Laplacian
                L = -igl.cotmatrix(v, f)
                M = igl.massmatrix(v, f, igl.MASSMATRIX_TYPE_VORONOI)
                # Compute EigenDecomposition
                try:
                    evals, evecs = sp.sparse.linalg.eigsh(L, DNA_size+2, M, sigma=0.0, which='LM', maxiter=1e9, tol=1.e-15)
                except:
                    evals, evecs = sp.sparse.linalg.eigsh(L + 1e-8 * sp.sparse.identity(v.shape[0]), DNA_size+2,
                                                          M, sigma=0.0, which='LM', maxiter=1e9, tol=1.e-15)
                # Shape DNA
                descriptors = evals[2:] / evals[1]
                # Save descriptor
                np.save(os.path.join('.', 'Dataset', c, file[:-4] + "_DNA"), descriptors, allow_pickle=False)

                print("done.")
    print("Finished")
# Plot the mesh
viewer = igl.viewer.Viewer()
viewer.data.set_mesh(V, F)
viewer.core.show_lines = False
viewer.callback_key_down = key_down

# One fixed point on belly
b = igl.eigen.MatrixXi([[2556]])
bc = igl.eigen.MatrixXd([[1]])

# Construct Laplacian and mass matrix
L = igl.eigen.SparseMatrixd()
M = igl.eigen.SparseMatrixd()
Minv = igl.eigen.SparseMatrixd()

igl.cotmatrix(V, F, L)
igl.massmatrix(V, F, igl.MASSMATRIX_TYPE_VORONOI, M)
igl.invert_diag(M, Minv)

# Bi-Laplacian
Q = L.transpose() * (Minv * L)

# Zero linear term
B = igl.eigen.MatrixXd.Zero(V.rows(), 1)

# Lower and upper bound
lx = igl.eigen.MatrixXd.Zero(V.rows(), 1)
ux = igl.eigen.MatrixXd.Ones(V.rows(), 1)

# Equality constraint constrain solution to sum to 1
Beq = igl.eigen.MatrixXd([[0.08]])
Ejemplo n.º 14
0
# import gc_bindings

import polyscope
import igl
import numpy as np
import polyscope as ps
import scipy

# https://www.cs.cmu.edu/~kmcrane/Projects/ModelRepository/spot.zip
path = "/Users/cbabraham/data/mesh/spot/spot_triangulated.obj"

# verts and faces
V,F = igl.read_triangle_mesh(path)

# cotan laplacian and mass matrix
L = igl.cotmatrix(V,F)
M = igl.massmatrix(V,F)

# eigenvectors of the laplacian
_, E = scipy.sparse.linalg.eigsh(L, 1000, M, which='BE')

C = V.T.dot(E) # inner product of each eigenvector and the mesh
R = np.einsum('km,nm->nk',C,E)

# V: n x k verts (k = 3)
# E: n x m eigenvectors, to use as bases
# C: k x m basis weights
# R: n x k synthesized vertices from weighted bases

ps.init()
original = ps.register_surface_mesh("mesh", V,F)
Ejemplo n.º 15
0
# Plot the mesh
viewer = igl.viewer.Viewer()
viewer.data.set_mesh(V, F)
viewer.core.show_lines = False
viewer.callback_key_down = key_down

# One fixed point on belly
b  = igl.eigen.MatrixXi([[2556]])
bc = igl.eigen.MatrixXd([[1]])

# Construct Laplacian and mass matrix
L = igl.eigen.SparseMatrixd()
M = igl.eigen.SparseMatrixd()
Minv = igl.eigen.SparseMatrixd()

igl.cotmatrix(V,F,L)
igl.massmatrix(V,F,igl.MASSMATRIX_TYPE_VORONOI,M);
igl.invert_diag(M,Minv)

# Bi-Laplacian
Q = L.transpose() * (Minv * L)

# Zero linear term
B = igl.eigen.MatrixXd.Zero(V.rows(),1)

# Lower and upper bound
lx = igl.eigen.MatrixXd.Zero(V.rows(),1)
ux = igl.eigen.MatrixXd.Ones(V.rows(),1)

# Equality constraint constrain solution to sum to 1
Beq = igl.eigen.MatrixXd([[0.08]])
Ejemplo n.º 16
0
def laplacian_editing(path, anchors, anchors_id, tetra=False,
                      custom_weight=None):
    """
    Applies laplacian mesh editing to a mesh using igl's cotangent weights
    ----
    input:
        path: str -> path to the triangle mesh
        anchors: float array of shape (n, 3) -> position of the anchors
        anchors_id: float array of shape (n,) -> index of each anchor vertex
        tetra: bool -> if the mesh is tetraedral. If False, it should be with
            triangular faces
        custom_weight: float list of length n. If None, every weight is
            considered to be 1
    ----
    output:
        v_res: float array of shape (N, 3) -> the new vertices
        f: float array of shape (P, 3) -> the faces (same as before)
    """
    nb_anchors = len(anchors)
    assert nb_anchors == len(anchors_id), "anchors and anchors_id have \
different size"

    extension = path.split('.')[-1]

    weight_anchors = 1.0

    if extension == "mesh":
        v, vo, f = igl.read_mesh(path)
        f = f - 1
        # When using read_mesh, vertex indices start at 1 instead of 0
        # We could use read_triangle_mesh which returns vertices with indices
        # starting at 0
    elif extension == "obj":
        v, f = igl.read_triangle_mesh(path)
    else:
        raise ValueError("Currently, only .obj and .mesh files are supported")

    if tetra:
        assert extension == "mesh", "Laplacian editing for tetraedral mesh is\
 currently only supported for .mesh files"
        L = igl.cotmatrix(v, vo)
    else:
        L = igl.cotmatrix(v, f)

    M, N = L._shape  # M should be equal to N

    delta = np.array(L.dot(v))

    # The lines that will be appened to L and delta
    anchors_L = sparse.csc_matrix((nb_anchors, N))
    anchors_delta = np.zeros((nb_anchors, 3), dtype=np.double)
    for k in range(nb_anchors):
        if custom_weight is None:
            anchors_L[k, anchors_id[k]] = weight_anchors
            anchors_delta[k] = weight_anchors * anchors[k]
        else:
            anchors_L[k, anchors_id[k]] = custom_weight[k]
            anchors_delta[k] = custom_weight[k] * anchors[k]

    L = sparse.vstack((L, anchors_L), format="coo")
    delta = np.vstack((delta, anchors_delta))

    # Solving for least squares
    v_res = np.zeros((M, 3), dtype=np.double)
    for k in range(3):
        v_res[:, k] = lsqr(L, delta[:, k], x0=v[:, k])[0]

    return v_res, f
Ejemplo n.º 17
0
def torch_laplacian_cot(verts_np, faces_np):
    L_np = -1 * igl.cotmatrix(verts_np, faces_np)
    return coo_to_sparse_torch(L_np.tocoo())
Ejemplo n.º 18
0
def makeLaplacianMatrixSolverIGLSoft(VPos, ITris, anchorsIdx, anchorWeights, makeSolver = True):
    VPosE = igl.eigen.MatrixXd(VPos)
    ITrisE = igl.eigen.MatrixXi(ITris)
    '''
    #Doing this check slows things down by more than a factor of 2 (convert to numpy to make faster?)
    for f in range(ITrisE.rows()):
        v_list = ITrisE.row(f)
        v1 = VPosE.row(v_list[0])
        v2 = VPosE.row(v_list[1])
        v3 = VPosE.row(v_list[2])
        if (v1-v2).norm() < 1e-10 and (v1-v3).norm() < 1e-10 and (v2-v3).norm() < 1e-10:
            print 'zero area triangle!',f
    '''
    L = igl.eigen.SparseMatrixd()
    M = igl.eigen.SparseMatrixd()
    M_inv = igl.eigen.SparseMatrixd()
    igl.cotmatrix(VPosE,ITrisE,L)
    igl.massmatrix(VPosE,ITrisE,igl.MASSMATRIX_TYPE_VORONOI,M)
    #np.set_printoptions(threshold='nan')
    #print 'what is M?',M.diagonal()
    igl.invert_diag(M,M_inv)
    #L = M_inv*L
    deltaCoords = (M_inv*L)*VPosE

    #TODO: What to do with decaying_anchor_weights?
    '''
    anchor_dists = []
    for i in range(VPosE.rows()):
        anchor_dists.append(min([ (VPosE.row(i)-VPosE.row(j)).norm() for j in anchorsIdx ]))
    max_anchor_dist = max(anchor_dists)
    # assume linear weighting for anchor weights -> we are 0 at the anchors, anchorWeights at max_anchor_dist
    decaying_anchor_weights = []
    for anchor_dist in anchor_dists:
        decaying_anchor_weights.append(anchorWeights*(anchor_dist/max_anchor_dist))
    '''
    
    solver = None
    if makeSolver:
        Q = L*(M_inv*M_inv)*L
        #Now add in sparse constraints
        diagTerms = igl.eigen.SparseMatrixd(VPos.shape[0], VPos.shape[0])
        # anchor points
        for a in anchorsIdx:
            diagTerms.insert(a, a, anchorWeights)
        # off points
        '''
        for adx,decay_weight in enumerate(decaying_anchor_weights):
            if decay_weight == 0:
                diagTerms.insert(adx, adx, anchorWeights)
            else:
                diagTerms.insert(adx, adx, decay_weight)
        '''
        Q = Q + diagTerms
        Q.makeCompressed()
        start_time = time.time()
        solver = igl.eigen.SimplicialLLTsparse(Q)
        #solver = igl.eigen.CholmodSupernodalLLT(Q)
        end_time = time.time()
        print 'factorization elapsed time:',end_time-start_time,'seconds'
    

    return (L, M_inv, solver, np.array(deltaCoords))
Ejemplo n.º 19
0
 def test_cotmatrix(self):
     l = igl.cotmatrix(self.v, self.f)
     self.assertTrue(l.shape == (self.v.shape[0], self.v.shape[0]))
     self.assertTrue(l.dtype == self.v.dtype)
     self.assertTrue(type(l) == csc.csc_matrix)
Ejemplo n.º 20
0
 def cot_matrix(self):
     if ('cot_matrix' not in self.cache):
         self.cache['cot_matrix'] = igl.cotmatrix(self.vertices, self.faces)
     return self.cache['cot_matrix']
Ejemplo n.º 21
0
    # tensor flow sparse
    values = mat.data
    indices = np.vstack((mat.row, mat.col))

    i = torch.LongTensor(indices)
    v = torch.FloatTensor(values)
    shape = mat.shape
    return torch.sparse_coo_tensor(i, v, dtype=dtype)


if __name__ == '__main__':

    # A set of sanity checks (invariant to translation) for the cotan laplacian
    target_mesh = Mesh(filename='../Results/imgHQ00039.obj')
    v, f = target_mesh.v, np.int32(target_mesh.f)
    L = -1 * igl.cotmatrix(v, f).tocoo()

    x = np.expand_dims(v[:, 0], axis=1)

    def smooth_np(L, x):
        return x.transpose().dot(L.dot(x))

    def smooth_diff_np(L, x1, x2):
        return smooth_np(L, x1 - x2)

    print('smooth_np(L,v[:,0]) = ', smooth_np(L, x))
    print('smooth_diff_np(L,x,x) = ', smooth_diff_np(L, x, x))
    x_translated = x + 100000
    print('smooth_diff_np(L,x,x) = ', smooth_diff_np(L, x, x_translated))

    # now sanity checks on tensors