Petit Phoenix
Petit Phoenix

Reputation: 1

Manifold 3D mesh of text in python

I'm trying to get to the end on a code that will help me scripting the generation of customized stl files.

The general needs I have are to :

and specifically to :

So far, I cannot find the right library to perform those operations.

I found the library sdf which is really awesome but generate large models.

Trimesh is great. I managed to generate the meshes of the structure, export to HTML and STL but cannot perform boolean operations without back-end.

I looked a bit into Pymesh but the librairy seems not beeing developped anymore and has a large number of dependencies.

I'm now trying with looked quickly into PyVista but currently can't get into issues with non manifold models.

here is the code that I want manifold

import numpy as np
import pyvista as pv
RES = 20

vertices = np.array([
        [20.5, -17.5, 0.0],
        [24.39711432, -8.75, 0.0],
        [24.39711432, 8.75, 0.0],
        [20.5, 17.5, 0.0],
        [19.20096189, 8.75, 0.0],
        [19.20096189, -8.75, 0.0],
        [20.5, -17.5, 0.0]])
profile = pv.MultipleLines(vertices)
profile.plot(color='tan')
extruded = profile.extrude_rotate(resolution=RES**2, rotation_axis=(0, 1, 0))#, capping=False)
print(extruded.is_all_triangles)
print(extruded.is_manifold)
print(extruded.extract_geometry().n_open_edges)
extruded.plot_normals()

# Check if all triangles :
extruded = extruded.fill_holes(4*RES)
print(extruded.is_all_triangles)
print(extruded.is_manifold)
print(extruded.extract_geometry().n_open_edges)
extruded.plot_normals()

extruded.plot(color='tan')

Step 2 is add text around it.

Upvotes: 0

Views: 972

Answers (2)

jimy byerley
jimy byerley

Reputation: 159

It looks like pymadcad should be suited for your need (disclamer: I am the author of pymadcad)

  • it is in pure python (well there is some cython but is is part of the ecosystem)
  • has dependencies to scipy and qt but not more
  • produce lightweight models with only the necessary triangles for describing the geometry

for your application specificities:

  • it can generate a 3D mesh for regular shapes with functions in madcad.generation
  • it can generate a 3D mesh from text with functions in madcad.text
  • for wraping the text mesh around a cylinder, I will detail below
  • it can perform boolean operations with functions from madcad.boolean

Wraping a mesh around a cylinder is somewhat more specific, but can be coded by yourself I guess since text is only flat. Here is how I would proceed:

from madcad import *

r = 1
h = 0.6
e = 0.1

# generate the shape to write on
shape = cylinder(vec3(0,0,-h), vec3(0,0,h), r)

# generate flat text as a Web (wireframe mesh)
label = text.text("foo bar", fill=False)
# wrap the mesh points around the cylinder
label.points = typedlist(vec3(cos(p.x/r), sin(p.x/r), p.y-0.5)*r  
                      for p in label.points)
# extrude the mesh and give it a cylindric filling
label = intersection(
        extrusion(scale(vec3(1-e-0.1*r, 1-e-0.1*r, 1)), label.transform(scale(vec3(1+e*1.1, 1+e*1.1, 1)))), 
        inflate(shape, e),
        )
# merge it onto the cylinder
result = union(shape, label)

print(repr(result))
show([result], display_wire=True)

Here is the result:

<Mesh with 1486 points at 0x7efdaeb10ef0, 2966 faces>

resulting mesh

Upvotes: 0

I don't fully understand what you want to end up with (especially about the text part), but your cylinder is almost manifold and can be made manifold.

There are a few issues:

  1. Your fill_holes call adds a "bottom" to your cylinder. This will mess up manifoldness, because the edge of this "bottom" belongs to three faces each (one inside wall, one outside wall, and one "bottom" face). I recommend forgetting about the bottom as long as you need a manifold mesh, and only adding that bottom at the very end if you need it.
  2. Your MultipleLines call creates 7 points, so the polygonal cross-section is not actually closed. You could either create the polyline with a different approach, or just call .clean() on your profile to make it closed.
  3. You also need to remove capping from the extrusion, because that could lead to two internal faces inside the cylinder, again messing with manifoldness.
  4. If you fix the above, you end up with an extruded cylinder that has 12 open edges still: two times 6. This indicates that VTK fails to identify the two ends of the rotational extrusion as identical, and calling .clean() doesn't help either. It turns out that we have to bump up the default tolerance value to fix this. A choice of tolerance=1e-10 works nicely for your example, but you could go much higher to be on the safe side if your model's parameters can vary.

Here's the fixed snippet:

import numpy as np
import pyvista as pv

RES = 20

vertices = np.array([
        [20.5, -17.5, 0.0],
        [24.39711432, -8.75, 0.0],
        [24.39711432, 8.75, 0.0],
        [20.5, 17.5, 0.0],
        [19.20096189, 8.75, 0.0],
        [19.20096189, -8.75, 0.0],
        [20.5, -17.5, 0.0]])
profile = pv.MultipleLines(vertices).clean()
extruded = profile.extrude_rotate(resolution=RES**2, rotation_axis=(0, 1, 0), capping=False)
cleaned = extruded.clean(tolerance=1e-10)
print(cleaned.is_manifold)  # True

All that being said, boolean operations with VTK ca be finnicky. You might find that the end result still doesn't fit your use case. But you'll only know once you try.

Upvotes: 0

Related Questions