Last active
February 1, 2021 13:15
-
-
Save yuancu/d1b08bf3384e28dfb72988ba670f869c to your computer and use it in GitHub Desktop.
Implementation of some helper functions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Return a list of vertices | |
def get_vertices(context): | |
selected_object = context.active_object | |
if selected_object is None: | |
raise Exception('No object selected: please select the object to deform') | |
return selected_object.data.vertices | |
# Returns a list of triangles of vertex indices (you need to perform simple triangulation) | |
def get_faces(context): | |
selected_object = context.active_object | |
if selected_object is None: | |
raise Exception('No object selected: please select the object to deform') | |
return selected_object.data.polygons | |
# EFFICIENTLY returns the 1-ring (a list of vertex indices) for a vertex index | |
def neighbor_indices(vertex_index, vertices, faces): | |
neighbors = [] | |
obj = bpy.context.active_object | |
me = obj.data | |
bm = bmesh.new() | |
bm.from_mesh(me) | |
# make bm.verts indexable | |
if hasattr(bm.verts, "ensure_lookup_table"): | |
bm.verts.ensure_lookup_table() | |
v = bm.verts[vertex_index] | |
for e in v.link_edges: | |
neighbors.append(e.other_vert(v).index) | |
bm.free() | |
return neighbors | |
# Return the sparse diagonal weight matrix W | |
def weights(vertices, faces): | |
""" | |
Compute weights by iterating through faces. | |
for every edge in every face: | |
if weights[edge] isn't assigned: | |
assign cot of respective angle as its weight (i.e, cot(A) for edge a) | |
else, this means its weight is assgined in another face as cot: | |
assign weights[edge] * 0.5 + new cot as its weight | |
""" | |
vert_num = len(vertices) | |
w = dict() # use a dict to store weights in {(i, j): w} | |
for face in faces: | |
for i, j in face.edge_keys: | |
other = (set(face.vertices) ^ set((i, j))).pop() | |
# make i always be the smaller index | |
i, j = i, j if i < j else j, i | |
if w.get((i, j), 0) == 0: | |
w[(i, j)] = compute_cot(vertices[i].co - vertices[other].co, | |
vertices[j].co -vertices[other].co ) | |
else: | |
w[(i, j)] = w[(i, j)] * 0.5 + compute_cot(vertices[i].co - vertices[other].co, | |
vertices[j].co - vertices[other].co) * 0.5 | |
# convert dict to list | |
w_list = [] | |
for k,v in w: | |
w_list.append((k[0], k[1], v)) | |
# force an ascending edge order | |
w_list = sorted(w_list, key = lambda w_list: (w_list[0], w_list[1])) | |
return ddm.Sparse_Matrix(w_list, vert_num, vert_num) | |
def compute_cot(v1, v2): | |
dotprod = v1 * v2 | |
cos_v1v2 = dotprod / (v1.length * v2.length) | |
cot_v1v2 = cos_v1v2 / np.sqrt(1 - cos_v1v2**2) | |
return cot_v1v2 | |
# Returns g matrix of shape |E| × 3 | |
# Note: E here represents all edges | |
# Order of edges is: acend, first by vertex index, second by neighbor index | |
def compute_g(vertices, R_list): | |
g = [] | |
for v_i, R_i in zip(vertices, R_list): | |
neighbors = neighbor_indices(v_i.index, None, None) | |
# force an order of edges connected to a vertex | |
neighbors.sort() | |
for n in neighbors: | |
# force an order where only records g_ij that i < j | |
if v_i.index >= n: | |
continue | |
v_j = vertices[n] | |
R_j = R_list[n] | |
g_ij = (v_i.co - v_j.co) * R_i | |
g_ji = (v_j.co - v_i.co) * R_j | |
g.append((g_ij - g_ji) / 2) | |
if bpy.context.active_object is not None: | |
assert len(g) == len(bpy.context.active_object.data.edges), 'length of g should be equal to number of edges' | |
return Matrix(np.array(g)) | |
# Returns a sparse diagonal matrix of type scipy.sparse.coo_matrix where indices in index list is set to one | |
# if flip is set, it's a diagonal matrix where indices not set in index_list are one | |
def convert_to_mask(index_list, length, flip=False): | |
if flip: | |
mask1D = np.zeros(length, dtype=np.int) | |
mask1D[index_list] = 1 | |
index_list = np.where(mask1D == 0)[0].tolist() | |
len_index = len(index_list) | |
mask = sp.coo_matrix((np.ones(len_index), (index_list, index_list)), shape=(length, length)) | |
return mask |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment