def getMarkerType(context, mesh, landmark): indices = np.array([vid for vid in landmark.v_indices], dtype=int); ratios = np.array([r for r in landmark.v_ratios]); c_nz = np.count_nonzero(ratios); arg_sorted = np.argsort(ratios)[::-1]; v_indices = None; bm = getBMMesh(context, mesh, useeditmode=False); ensurelookuptable(bm); if(c_nz == 1): v_indices = indices[arg_sorted[[0]]]; location = bm.verts[v_indices[0]].co.to_tuple(); bm.free(); return 'VERTEX', v_indices[0], location, [location]; elif (c_nz == 2): v_indices = indices[arg_sorted[[0, 1]]]; edges_1 = np.array([e.index for e in bm.verts[v_indices[0]].link_edges]); edges_2 = np.array([e.index for e in bm.verts[v_indices[1]].link_edges]); edge_common = np.intersect1d(edges_1, edges_2); location = tuple([val for val in landmark.location]); edge_locations = [bm.verts[v_indices[0]].co.to_tuple(), bm.verts[v_indices[1]].co.to_tuple()]; bm.free(); return 'EDGE', edge_common.tolist()[0], location, edge_locations; elif(c_nz == 3): v_indices = indices[arg_sorted[[0, 1, 2]]]; faces_1 = np.array([f.index for f in bm.verts[v_indices[0]].link_faces]); faces_2 = np.array([f.index for f in bm.verts[v_indices[1]].link_faces]); faces_3 = np.array([f.index for f in bm.verts[v_indices[2]].link_faces]); face_common = reduce(np.intersect1d, (faces_1, faces_2, faces_3)); location = tuple([val for val in landmark.location]); face_locations = [bm.verts[v_indices[0]].co.to_tuple(), bm.verts[v_indices[1]].co.to_tuple(), bm.verts[v_indices[2]].co.to_tuple()]; bm.free(); return 'FACE', face_common.tolist()[0], location, face_locations; return None, None, None;
def applyVertexColors(context, mesh, colors,*, v_group_name = "lap_errors", for_vertices = True): if(None == mesh.data.vertex_colors.get(v_group_name)): mesh.data.vertex_colors.new(v_group_name); vertex_colors = mesh.data.vertex_colors[v_group_name]; vertex_colors.active = True; try: material = bpy.data.materials[mesh.name+'_'+v_group_name]; except KeyError: material = bpy.data.materials.new(mesh.name+'_'+v_group_name); try: mesh.data.materials[mesh.name+'_'+v_group_name]; except KeyError: mesh.data.materials.append(material); if(for_vertices): bm = getBMMesh(context, mesh, False); ensurelookuptable(bm); for v in mesh.data.vertices: b_vert = bm.verts[v.index]; for l in b_vert.link_loops: vertex_colors.data[l.index].color = colors[v.index]; bm.free(); else: for f in mesh.data.polygons: for lid in f.loop_indices: vertex_colors.data[lid].color = colors[f.index]; material.use_vertex_color_paint = True; return vertex_colors, material;
def autoCorrectLandmarksData(context, mesh): print('AUTOCORRECT: CONSTRUCT KDTREE'); kd = getKDTree(context, mesh); print('AUTOCORRECT: CONSTRUCT BMESH DATA'); bm = getBMMesh(context, mesh, False); print('AUTOCORRECT: CONSTRUCT BMESH DATA ENSURETABLE'); ensurelookuptable(bm); print('AUTOCORRECT: ITERATE LANDMARKS AND FIX POSITION'); for gm in mesh.generic_landmarks: loc = [dim for dim in gm.location]; mco = Vector((loc[0], loc[1], loc[2])); co, index, dist = kd.find(mco); v = bm.verts[index]; f = v.link_faces[0]; a = f.loops[0].vert; b = f.loops[1].vert; c = f.loops[2].vert; u,v,w,ratio,isinside = getBarycentricCoordinate(co, a.co, b.co, c.co); gm.v_ratios = [u, v, w]; gm.v_indices = [a.index, b.index, c.index]; print('AUTOCORRECT: FREE THE BMESH DATA'); bm.free();
def deformWithMapping(context, owner_mesh, map_to, apply_on_mesh, mapped_points): print('DEFORM WITH MAPPING (UPLIFTING)'); c = context; constraint_positions = []; constraint_ids = []; invalid_indices = []; for vid, mapped_point in enumerate(mapped_points): if(mapped_point.is_valid): co = getGeneralCartesianFromBarycentre(mapped_point.bary_ratios, [map_to.data.vertices[m_vid].co for m_vid in mapped_point.bary_indices]); constraint_ids.append(vid); constraint_positions.append(co.to_tuple()); else: invalid_indices.append(vid); constraint_positions = np.array(constraint_positions, dtype=np.float); constraint_ids = np.array(constraint_ids, dtype=np.int); invalid_indices = np.array(invalid_indices, dtype=np.int); vpos = getMeshVPos(apply_on_mesh); print('TOTAL VERTICES : #%s, INVALID INDICES : #%s'%(vpos.shape[0], invalid_indices.shape[0], )); if(invalid_indices.shape[0] > 0 and invalid_indices.shape[0] != vpos.shape[0]): print('SOLVE WITH LSE FOR INVALID MAPPING INDICES'); v_group_name='Mapping-LSE-deformer'; if(None == apply_on_mesh.vertex_groups.get(v_group_name)): apply_on_mesh.vertex_groups.new(name=v_group_name); group_ind = apply_on_mesh.vertex_groups[v_group_name].index; vertex_group = apply_on_mesh.vertex_groups[group_ind]; vertex_group.remove([v.index for v in apply_on_mesh.data.vertices]); apply_on_mesh.modifiers.clear(); vertex_group.add(constraint_ids.tolist(), 1.0, 'REPLACE'); lap_mod = apply_on_mesh.modifiers.new(name=vertex_group.name, type='LAPLACIANDEFORM'); lap_mod.vertex_group = vertex_group.name; lap_mod.iterations = 3;#its was 1 before bpy.ops.object.select_all(action="DESELECT"); apply_on_mesh.select = True; c.scene.objects.active = apply_on_mesh; bpy.ops.object.laplaciandeform_bind(modifier=lap_mod.name); bm = getBMMesh(c, apply_on_mesh, useeditmode=False); ensurelookuptable(bm); for i in range(constraint_ids.shape[0]): vid = constraint_ids[i]; bm.verts[vid].co = constraint_positions[i]; bm.to_mesh(apply_on_mesh.data); bm.free(); bpy.ops.object.modifier_apply(modifier=v_group_name); elif(invalid_indices.shape[0] == vpos.shape[0]): print('NO SOLUTION AVAILABLE FROM THIS MAPPING'); else: setMeshVPOS(apply_on_mesh, constraint_positions); return getMeshVPos(apply_on_mesh);
def applyVertexWeights(context, mesh, weights,*, v_group_name = "lap_errors"): if(None == mesh.vertex_groups.get(v_group_name)): mesh.vertex_groups.new(name=v_group_name); group_ind = mesh.vertex_groups[v_group_name].index; vertex_group = mesh.vertex_groups[group_ind]; bm = getBMMesh(context, mesh, False); ensurelookuptable(bm); for v in mesh.data.vertices: n = v.index; vertex_group.add([n], weights[v.index], 'REPLACE'); b_vert = bm.verts[v.index]; bm.free(); return vertex_group;
def createBonesMesh(self, context, mesh, bone_vertices, edge_indices): iso_name = mesh.name + "_geodesics_bones" try: existing = context.scene.objects[iso_name] existing.name = "READY_FOR_DELETE" bpy.ops.object.select_all(action="DESELECT") existing.select = True context.scene.objects.active = existing bpy.ops.object.delete() except KeyError: pass iso_mesh = bpy.data.meshes.new(iso_name) vertex_cos = getMeshVPos(mesh) # Make a new BMesh bm = bmesh.new() for vid in bone_vertices: x, y, z = vertex_cos[vid] v = bm.verts.new() v.co = (x, y, z) ensurelookuptable(bm) for (id_1, id_2) in edge_indices: v1, v2 = bm.verts[id_1], bm.verts[id_2] e = bm.edges.new([v1, v2]) print(id_1, id_2) bm.to_mesh(iso_mesh) iso_mesh_obj = bpy.data.objects.new(iso_name, iso_mesh) iso_mesh_obj.data = iso_mesh context.scene.objects.link(iso_mesh_obj) iso_mesh_obj.location = mesh.location.copy() return iso_mesh_obj
def remeshMarkersAsVertices(context, mesh): edge_indices = [] edge_locations = [] face_indices = [] face_locations = [] print('GET ALL LANDMARKS ON EDGE OR FACE') for gm in mesh.generic_landmarks: gm_on_type, gm_on_type_index, gm_location, gm_locations = getMarkerType( context, mesh, gm) if (gm_on_type == 'EDGE'): edge_locations.append(gm_location) edge_indices.append(gm_on_type_index) elif (gm_on_type == 'FACE'): face_locations.append(gm_location) face_indices.append(gm_on_type_index) verts_and_locations = [] bm = getBMMesh(context, mesh, useeditmode=False) print('POKE THE FACES FIRST') ensurelookuptable(bm) faces = [bm.faces[ind] for ind in face_indices] returned_geometry_faces = bmesh.ops.poke(bm, faces=faces) for i, vert in enumerate(returned_geometry_faces['verts']): verts_and_locations.append((vert.index, face_locations[i])) print('CUT THE EDGES NOW') ensurelookuptable(bm) edges = [bm.edges[ind] for ind in edge_indices] returned_geometry_edges = bmesh.ops.bisect_edges(bm, edges=edges, cuts=1) returned_vertices = [ vert for vert in returned_geometry_edges['geom_split'] if isinstance(vert, bmesh.types.BMVert) ] for i, vert in enumerate(returned_vertices): verts_and_locations.append((vert.index, edge_locations[i])) ensurelookuptable(bm) print('TRIANGULATING THE MESH AS THE LAST STEP FOR MESH') bmesh.ops.triangulate(bm, faces=bm.faces[:], quad_method=0, ngon_method=0) print('NOW MAKE THIS NEW TOPOLOGY TO BE THE MESH') bm.to_mesh(mesh.data) bm.free() for vid, co in verts_and_locations: mesh.data.vertices[vid].co = co print('AUTOCORRECT THE MESH LANDMARKS WITH NEW TOPOLOGY') autoCorrectLandmarksData(context, mesh)
def need_curvatures(mesh): loops = mesh.data.loops; faces = mesh.data.polygons; vertices = mesh.data.vertices; n = len(mesh.data.vertices); f_n = len(mesh.data.polygons); #get the normals and pointareas associated with each vertices normals, normals_np = need_normals(mesh); pointareas, cornerareas = need_pointareas(mesh); curv1, curv2, curv12 = [0.0] * n, [0.0] * n, [0.0] * n; pdir1, pdir2 = [Vector((0,0,0))] * n, [Vector((0,0,0))] * n; principalvalues = []; for f in faces: p0 = vertices[loops[f.loop_indices[0]].vertex_index]; p1 = vertices[loops[f.loop_indices[1]].vertex_index]; p2 = vertices[loops[f.loop_indices[2]].vertex_index]; pdir1[p0.index] = p1.co - p0.co; pdir1[p1.index] = p2.co - p1.co; pdir1[p2.index] = p0.co - p2.co; for v in vertices: pdir1[v.index] = pdir1[v.index].cross(normals[v.index]); pdir1[v.index].normalize(); pdir2[v.index] = normals[v.index].cross(pdir1[v.index]); for f in faces: #Creating reference to all the vertices in this face 'f' p0 = vertices[loops[f.loop_indices[0]].vertex_index]; p1 = vertices[loops[f.loop_indices[1]].vertex_index]; p2 = vertices[loops[f.loop_indices[2]].vertex_index]; verts = [p0, p1, p2]; e = [p2.co - p1.co, p0.co - p2.co, p1.co - p0.co]; #Normal-Tangent-Basis coordinate system per face t = e[0].copy(); t.normalize(); n = e[0].cross(e[1]); b = n.cross(t); b.normalize(); #Estimating curvatures based on the variation of normals along the edges m = [0.0, 0.0, 0.0]; w = [[0.0,0.0,0.0], [0.0,0.0,0.0], [0.0,0.0,0.0]]; for j in range(3): prev_ii = (j + 3 - 1) % 3; next_ii = (j + 1) % 3; u = e[j].dot(t); v = e[j].dot(b); w[0][0] = w[0][0] + (u * u); w[0][1] = w[0][1] + (u * v); w[2][2] = w[2][2] + (v * v); #Find the normal between the "normals of vertices" connected to this #vertex on this face 'f' dn = normals[verts[prev_ii].index] - normals[verts[next_ii].index]; #Find their angular deviation (cosine theta) w.r.to tangent t and basis b dnu = dn.dot(t); dnv = dn.dot(b); m[0] = m[0] + (dnu * u); m[1] = m[1] + ((dnu * v) + (dnv * u)); m[2] = m[2] + (dnv * v); w[1][1] = (w[0][0] + w[2][2]); w[1][2] = (w[0][1]); diag = [0.0, 0.0, 0.0]; solvable, A, rdiag = ldltdc(w, diag); if(not solvable): continue; x, A, B, rdiag = ldltsl(A, rdiag, m, m); for index, v in enumerate(verts): new_ku, newkuv, newkv = proj_curv(t, b, m[0], m[1], m[2], pdir1[v.index], pdir2[v.index]); wt = (cornerareas[f.index][v.index] / pointareas[v.index]); curv1[v.index] = curv1[v.index] + (wt * new_ku); curv12[v.index] = curv12[v.index]+ (wt * newkuv); curv2[v.index] = curv2[v.index] + (wt * newkv); k1_list, k2_list, p1_list, p2_list, mean_list, gaussian_list = [], [], [], [], [], []; bm = getBMMesh(bpy.context, mesh, useeditmode=False); ensurelookuptable(bm); for v in bm.verts: averagelength = sum([e.calc_length() for e in v.link_edges]) * (1.0 / len(v.link_edges));# * 0.4; k1, k2, p1, p2 = diagonalize_curv(pdir1[v.index], pdir2[v.index], curv1[v.index], curv12[v.index], curv2[v.index], normals[v.index]); principalvalues.append(((k1+k2)*0.5,k1*k2 ,k1, k2, p1, p2)); p1 = p1 * averagelength; p2 = p2 * averagelength; o_values = np.array([k1, k2]); p_values = [p1, p2]; abs_values = np.abs(o_values); indices_max = np.argmax(abs_values); indices_min = np.argmin(abs_values); k1_list.append(o_values[indices_max]); k2_list.append(o_values[indices_min]); # k1_list.append(k1); # k2_list.append(k2); p1_list.append(p_values[indices_max]); p2_list.append(p_values[indices_min]); mean_list.append((k1+k2)*0.5); gaussian_list.append(k1*k2); sx = np.abs(k1_list) - np.abs(k2_list); bm.free(); return np.array(k1_list), np.array(k2_list), sx, np.array(p1_list), np.array(p2_list), np.array(mean_list), np.array(gaussian_list), normals_np;
def constructFromFile(self, mapping_file_path, owner_mesh, map_to): n_count = len(owner_mesh.data.vertices) self.mapped_points.clear() # np_file = np.loadtxt(mapping_file_path, dtype={'names':['index','u','v','w'], 'formats':[int, float, float, float]}); # np_file = np.loadtxt(mapping_file_path, dtype={'names':['index','u','v','w'], 'formats':[int, float, float, float]}); try: np_file = np.loadtxt(mapping_file_path, dtype=None) except ValueError: np_file = np.loadtxt( mapping_file_path, dtype=None, delimiter=",", ) isTriangleMapped = False isVertexMapped = False isVertexToVertexMapped = False try: isTriangleMapped = (np_file.shape[1] == 4) isVertexMapped = (np_file.shape[1] == 6) except IndexError: isVertexToVertexMapped = True ids = np_file bm = getBMMesh(bpy.context, map_to, useeditmode=False) ensurelookuptable(bm) if (isTriangleMapped): ids = np_file[:, 0].astype(int) ratios = np_file[:, -3:].astype(float) elif (isVertexMapped): ids = np_file[:, :3].astype('int') ratios = np_file[:, -3:].astype(float) print(ids.shape, ids[0]) loops = map_to.data.loops vertices = map_to.data.vertices for vid, v in enumerate(owner_mesh.data.vertices): mapped_point = self.mapped_points.add() if (isTriangleMapped): fid = ids[vid] u, v, w = ratios[vid] if (fid == -1): mapped_point.is_valid = False else: face = map_to.data.polygons[fid] vids = [ loops[lid].vertex_index for lid in face.loop_indices ] vid1, vid2, vid3 = vids elif (isVertexMapped): vid1, vid2, vid3 = [int(ii) for ii in ids[vid]] u, v, w = ratios[vid] if (vid1 == -1 and vid2 == -1 and vid3 == -1): mapped_point.is_valid = False elif (isVertexToVertexMapped): useVertexTargetId = int(ids[vid]) if (useVertexTargetId != -1): bmface = bm.verts[useVertexTargetId].link_faces[0] t_verts = [l.vert.index for l in bmface.loops] t_ratios = [0.0, 0.0, 0.0] t_ratios[t_verts.index(useVertexTargetId)] = 1.0 vid1, vid2, vid3 = t_verts u, v, w = t_ratios else: mapped_point.is_valid = False if (mapped_point.is_valid): mapped_point.bary_ratios = [u, v, w] mapped_point.bary_indices = [vid1, vid2, vid3] self.mapping_is_valid = True try: bm.free() except NameError: pass return True