nmwsharp / potpourri3d

An invigorating blend of 3D geometry tools in Python.
MIT License
414 stars 31 forks source link

Randomly generated mesh test fails #1

Closed mhr closed 3 years ago

mhr commented 3 years ago

Hello!

I've been trying to figure out how to generate a 2D circle mesh for use with potpourri3d, but I keep getting this error: self-edge in face list [x] -- [x]. While investigating, I came across your test functions, generate_verts() and generate_faces(). When I tried to load a mesh using those two, I also got self-edge in face list. However, puzzlingly, I could use the bunny mesh without any errors.

Other errors I got while trying to make my circle mesh work include vertex [x] appears in more than one boundary loop and duplicate edge in list [i] -- [j].

I'm confused because polyscope renders the meshes correctly, but potpourri3d has a hard time with the same meshes.

Thank you!

image

import numpy as np
import polyscope as ps
import potpourri3d as pp3d

# Initialize polyscope
ps.init()

def generate_verts(n_pts=999):
    np.random.seed(777)        
    return np.random.rand(n_pts, 3)

def generate_faces(n_pts=999):
    # n_pts should be a multiple of 3 for indexing to work out
    np.random.seed(777)        
    rand_faces = np.random.randint(0, n_pts, size=(2*n_pts,3))
    coverage_faces = np.arange(n_pts).reshape(-1, 3)
    faces = np.vstack((rand_faces, coverage_faces))
    return faces

verts = generate_verts()
faces = generate_faces()
solver = pp3d.MeshVectorHeatSolver(verts, faces)
ps.register_surface_mesh("random mesh", verts, faces, smooth_shade=True)

verts, faces = pp3d.read_mesh("bunny_small.ply")
solver = pp3d.MeshVectorHeatSolver(verts, faces)
ps.register_surface_mesh("bunny mesh", verts, faces, smooth_shade=True)

radians = np.linspace(0, 2*np.pi-(2*np.pi/40), 40)
unit_circle = np.stack((np.cos(radians), np.sin(radians), radians*0), axis=1)
verts = unit_circle
faces = []
for i in range(0, verts.shape[0]):
    if i == verts.shape[0]-1:
        faces.append([i, 0, 0])
    else:
        faces.append([i, i+1, 0])
faces = np.array(faces)
solver = pp3d.MeshVectorHeatSolver(verts, faces)
ps.register_surface_mesh("unit circle mesh", verts, faces, smooth_shade=True)

ps.show()
nmwsharp commented 3 years ago

Hi!

The issue here is meshes which contain degenerate faces, or have nonmanifold connectivity. The error you're seeing is the underlying library detecting bad connectivity in the mesh.

For instance, if I'm reading your code correctly, the line faces.append([i, 0, 0]) generates a degenerate "face" where two vertices are actually the same vertex. I think this also happens on the first loop iteration. Generally we would expect no repeat vertices in a face; I suspect if you remove those lines the mesh will work fine.

Similarly, the genreate_faces() function, which just creates a bunch of random faces, ensures there are no duplicate face indices like that, but can still create nonmanifold meshes (imagine an hourglass configuration with a single vertex at the center). This is why it's not used in the unit tests for MeshVectorHeatSolver, which requires a manifold triangle mesh.

Since Polyscope just does visualization, it don't check any of these conditions and just happily renders the mesh. A face which contains a duplicate vertex will just be an invisible sliver which you can't even see.

Hope that helps!

mhr commented 3 years ago

Skipping the first and last vertex in my faces loop was the answer, thank you so much!