Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Close an extruded mesh with a cover #1155

Open
FPerezHernandez92 opened this issue Jul 10, 2024 · 4 comments
Open

Close an extruded mesh with a cover #1155

FPerezHernandez92 opened this issue Jul 10, 2024 · 4 comments

Comments

@FPerezHernandez92
Copy link

I am working with a kind of mesh that is a bit complicated. At the edges they might have intersections. Therefore, when it comes to extruding and putting a cover, I have problems. For example, I can't generate the cover with "Delaney". Or if I paste a slice the mesh is not closed (I use the is_closed method and it returns False).

example_lower.stl.zip

# Python 3.11.9
import vedo  # 2024.5.2
import time


def close_with_cover_reply(mesh, value_z):
    extrude_mesh = mesh.extrude(zshift=value_z, rotation=0, cap=False, dr=0, res=10)
    cut_mesh = extrude_mesh.cut_with_plane(origin=(0, 0, value_z), normal=(0, 0, 1))

    extrude_cut_mesh = vedo.merge(mesh, cut_mesh)
    extrude_cut_mesh.clean()

    cover_mesh = extrude_cut_mesh.copy()
    cover_mesh.vertices[:, 2:] = value_z

    closed_mesh = vedo.merge(extrude_cut_mesh, cover_mesh)
    closed_mesh.clean()
    return closed_mesh


def close_with_delaney(mesh, value_z):
    extrude_mesh = mesh.extrude(zshift=value_z, rotation=0, cap=False, dr=0, res=10)
    cut_mesh = extrude_mesh.cut_with_plane(origin=(0, 0, value_z), normal=(0, 0, 1))

    extrude_cut_mesh = vedo.merge(mesh, cut_mesh)
    extrude_cut_mesh.clean()

    boundarie = extrude_cut_mesh.boundaries()
    cover_delaney = boundarie.generate_delaunay2d()

    closed_mesh = vedo.merge(extrude_cut_mesh, cover_delaney)
    closed_mesh.clean()
    return closed_mesh


name_mesh = "example_lower.stl"
mesh = vedo.Mesh(name_mesh)
value_z: int = -20
# vedo.show(mesh, new=True)

st_time = time.time()
closed_mesh = close_with_cover_reply(mesh, value_z)
print(time.time() - st_time, closed_mesh.is_closed())  # 0.58 seconds and closed

st_time = time.time()
closed_mesh = close_with_delaney(mesh, value_z)
print(time.time() - st_time, closed_mesh.is_closed())  # 0.71 seconds but not closed

I have extruded the mesh and then cut the extrusion to have a plane surface.

Captura de pantalla 2024-07-10 a las 16 02 30

My problem comes to generate the cover.
Option 1. Function "close_with_cover_reply".
I have tried to replicate the mesh at the desired Z coordinate. This way I get a closed mesh, but at the cost of obtaining a mesh with twice the number of points, which is not very elegant.

Captura de pantalla 2024-07-10 a las 16 04 24

Option 2. Function "close_with_delaney".
I tried to get the boundary of the extracted mesh. Then I generate the cover with Delaney, but, apart from the fact that it generates triangles where it does not correspond, the mesh would not be closed.

Captura de pantalla 2024-07-10 a las 16 05 10

I wouldn't mind modifying the morphology of the edge, so I could make a smooth of the edge and join it as it is done in @#1019 and then extrude to simplify it, but it is not enough.

I have used the "cap" parameter of the extrude function but it generates a copy of the mesh points, which I am trying to avoid.

My goal would be to have something similar to this and also, the is_closed function would return True:

Captura de pantalla 2024-07-10 a las 16 15 07

Thanks for the help and congratulations for the work, I love vedo.

@marcomusy
Copy link
Owner

Hi Francisco, I think it is very difficult problem because the original mesh is very irregular and even at the very first step you run into the problem of having the extrusion of the boundary to intersect your mesh mesh:

import vedo 

def cap(mesh, value_z):
    msh = mesh.boundaries().join().extrude(zshift=value_z).lw(0)
    msh.cut_with_plane(origin=(0, 0, value_z), normal=(0, 0, 1))
    return msh

name_mesh = "data/example_lower.stl"
mesh = vedo.Mesh(name_mesh)
value_z: int = -20

closed_mesh = cap(mesh, value_z)
vedo.show(mesh, closed_mesh).close()

Screenshot from 2024-07-10 22-06-31
(note how the purple on the bottom right hits the yellow mesh)

I'm afraid you will need an extra step of cleaning up the mesh before proceeding to close it.

@marcomusy
Copy link
Owner

Or you can try with pymeshfix but it takes a LONG time to process it (1 min):

pip install pymeshfix

then

import vedo  # 2024.5.2
import time
import pymeshfix


def close_with_cover_reply(mesh, value_z):
    extrude_mesh = mesh.extrude(zshift=value_z, cap=False, res=10)
    cut_mesh = extrude_mesh.cut_with_plane(origin=(0, 0, value_z), normal=(0, 0, 1))

    extrude_cut_mesh = vedo.merge(mesh, cut_mesh)
    extrude_cut_mesh.clean()

    cover_mesh = extrude_cut_mesh.copy()
    cover_mesh.vertices[:, 2:] = value_z

    closed_mesh = vedo.merge(extrude_cut_mesh, cover_mesh)
    closed_mesh.clean()
    meshfix = pymeshfix.MeshFix(closed_mesh.vertices, closed_mesh.cells)
    meshfix.repair()
    return vedo.Mesh(meshfix.mesh)


name_mesh = "data/example_lower.stl"
mesh = vedo.Mesh(name_mesh)
value_z: int = -20

st_time = time.time()
closed_mesh = close_with_cover_reply(mesh, value_z)
print(time.time() - st_time, closed_mesh.is_closed(), closed_mesh.is_manifold()) 

vedo.show(closed_mesh, axes=1)

image

@FPerezHernandez92
Copy link
Author

Thank you very much for your answers. Unfortunately I can't use pymeshfix because it takes too long. I need to solve the problem in a very small amount of time.

Indeed the type of meshes present many difficulties.
I have thought of an alternative that could be the one that was done here #1019 (comment)

But my idea would be to make smooth to the edge or to take a subsampling of the edge to lose a little its morphology. The problem would be that with the subsampling I would not be able to use the to_strips function because the number of lines is different. Perhaps in this way I could clean the edge that apparently is the biggest impediment. Would it be an option?

@marcomusy
Copy link
Owner

Sorry I overlooked your question..
SInce the main issue seems to be the self-intersecting vertices in the extrusion, you may try to detect them before extrusion with intersect_with_line() described here
If positive you can delete the face .delete_cells() and then call .clean() to remove the point too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants