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
예제 #2
0
    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())