def get_nearest_points_and_normals(vert, base_verts, base_faces): """ inspired from frankengeist.body.ch.mesh_distance.MeshDistanceSquared """ fn = TriNormals(v=base_verts, f=base_faces).reshape((-1, 3)) vn = VertNormals(v=base_verts, f=base_faces).reshape((-1, 3)) tree = AabbTree(Mesh(v=base_verts, f=base_faces)) nearest_tri, nearest_part, nearest_point = tree.nearest( vert, nearest_part=True) nearest_tri = nearest_tri.ravel().astype(np.long) nearest_part = nearest_part.ravel().astype(np.long) nearest_normals = np.zeros_like(vert) # nearest_part tells you whether the closest point in triangle abc is in the interior (0), on an edge (ab:1,bc:2,ca:3), or a vertex (a:4,b:5,c:6) cl_tri_idxs = np.nonzero(nearest_part == 0)[0].astype(np.int) cl_vrt_idxs = np.nonzero(nearest_part > 3)[0].astype(np.int) cl_edg_idxs = np.nonzero((nearest_part <= 3) & (nearest_part > 0))[0].astype(np.int) nt = nearest_tri[cl_tri_idxs] nearest_normals[cl_tri_idxs] = fn[nt] nt = nearest_tri[cl_vrt_idxs] npp = nearest_part[cl_vrt_idxs] - 4 nearest_normals[cl_vrt_idxs] = vn[base_faces[nt, npp]] nt = nearest_tri[cl_edg_idxs] npp = nearest_part[cl_edg_idxs] - 1 nearest_normals[cl_edg_idxs] += vn[base_faces[nt, npp]] npp = np.mod(nearest_part[cl_edg_idxs], 3) nearest_normals[cl_edg_idxs] += vn[base_faces[nt, npp]] nearest_normals = nearest_normals / ( np.linalg.norm(nearest_normals, axis=-1, keepdims=True) + 1.e-10) return nearest_point, nearest_normals
def test_trinormal(self): from psbody.mesh.mesh import Mesh from psbody.mesh.geometry.tri_normals import TriNormals, TriToScaledNormal, TriNormalsScaled, NormalizeRows m = Mesh( filename=os.path.join(test_data_folder, 'female_template.ply')) # Raffi: I do not know what this thing is supposed to test, maybe stability over some noise... tn = TriNormals(m.v, m.f) tn2 = NormalizeRows(TriToScaledNormal(m.v, m.f)) eps = 1e-8 mvc = m.v.copy() mvc[0] += eps tn_b = TriNormals(mvc, m.f) tn2_b = NormalizeRows(TriToScaledNormal(mvc, m.f)) # our TriNormals empirical: sp.csc_matrix(tn_b.flatten() - tn.flatten()) / eps # old TriToScaledNormals empirical': sp.csc_matrix(tn2_b.flatten() - tn2.flatten()) / eps # apparently just for printing sparsly # import scipy.sparse as sp # print sp.csc_matrix(tn_b.flatten() - tn.flatten()) / eps np.testing.assert_almost_equal(tn_b.flatten() - tn.flatten(), tn2_b.flatten() - tn2.flatten()) tn = TriNormalsScaled(m.v, m.f) tn2 = TriToScaledNormal(m.v, m.f) eps = 1e-8 mvc = m.v.copy() mvc[0] += eps tn_b = TriNormalsScaled(mvc, m.f) tn2_b = TriToScaledNormal(mvc, m.f) np.testing.assert_almost_equal(tn_b.flatten() - tn.flatten(), tn2_b.flatten() - tn2.flatten())