Open Kylsha opened 2 months ago
Hey, yeah I'd avoid mesh boolean operations if you can even though they've gotten a lot better since manifold3d came out. A 2D union works pretty well and you can polygon.buffer(1-e5)
first if that's flaky:
In [1]: import numpy as np
In [2]: from shapely.ops import unary_union
In [3]: from shapely import Polygon
In [4]: pts1 = ((0, 0), (10, 0), (10, 10), (0, 10))
...: pts2 = ((10, 10), (20, 10), (20, 20), (10, 20))
...: pts3 = ((10, 0), (20, 0), (20, 10), (10, 10))
In [5]: p1 = Polygon(pts1, [])
...: p2 = Polygon(pts2, [])
...: p3 = Polygon(pts3, [])
In [7]: import trimesh
In [8]: trimesh.creation.extrude_polygon(unary_union([p1, p2, p3]), 10)
Out[8]: <trimesh.Trimesh(vertices.shape=(16, 3), faces.shape=(28, 3))
In [9]: trimesh.creation.extrude_polygon(unary_union([p1, p2, p3]), 10).is_volume
Out[9]: True
Or if everything is a quad like the example, you can use trimesh methods which merge vertices and find the outline by using trimesh.grouping.group_rows(mesh.edges_sorted, require_count=1)
since edges that aren't on the boundary of a well-constructed mesh occur twice:
In [1]: import numpy as np
In [2]: import trimesh
In [3]: pts1 = ((0, 0), (10, 0), (10, 10), (0, 10))
...: pts2 = ((10, 10), (20, 10), (20, 20), (10, 20))
...: pts3 = ((10, 0), (20, 0), (20, 10), (10, 10))
In [5]: vertices = np.vstack([pts1, pts2, pts3], dtype=np.float64)
In [6]: quads = np.arange(len(vertices), dtype=np.int64).reshape((-1, 4))
In [7]: mesh = trimesh.Trimesh(vertices=vertices, faces=quads)
# quads are triangulated on load and duplicate vertices are merged by default
In [8]: mesh
Out[8]: <trimesh.Trimesh(vertices.shape=(8, 2), faces.shape=(6, 3))>
In [9]: mesh.outline()
Out[9]: <trimesh.Path3D(vertices.shape=(8, 2), len(entities)=1)>
In [11]: mesh.outline().to_planar()[0].extrude(10)
Out[11]: <trimesh.primitives.Extrusion>
In [12]: e = mesh.outline().to_planar()[0].extrude(10)
In [14]: e.is_volume
Out[14]: True
@mikedh thanks for response! Your second code snippet does right thing! My complete code for example:
import numpy as np
import trimesh
import ezdxf
pts1 = ((0, 0), (10, 0), (10, 10), (0, 10))
pts2 = ((10, 10), (20, 10), (20, 20), (10, 20))
pts3 = ((10, 0), (20, 0), (20, 10), (10, 10))
vertices = np.vstack([pts1, pts2, pts3], dtype=np.float64)
quads = np.arange(len(vertices), dtype=np.int64).reshape((-1, 4))
mesh = trimesh.Trimesh(vertices=vertices, faces=quads)
extruded_mesh = mesh.outline().to_planar()[0].extrude(10)
# creating a dxf document with mesh
doc = ezdxf.new("R2000")
msp = doc.modelspace()
new_mesh = msp.add_mesh()
new_mesh.dxf.subdivision_levels = 0
with new_mesh.edit_data() as mesh_data:
mesh_data.vertices = extruded_mesh.vertices.tolist()
mesh_data.faces = extruded_mesh.faces.tolist()
doc.saveas("mesh.dxf")
It does not remove some faces on exterior but it's not a really big deal. Inner rows and faces are gone and it's okay.
And sorry, I forgot to point that extrusion height of polygons may be different because it refers to real building heights given in geojson source file.
It looks like everything is still about filtering faces which are created during polygon extrusion. And method trimesh.grouping.group_rows
returns empty list for concatenated polygon made of three extruded meshed, because each row/face there is unique.
pts1 = ((0, 0), (10, 0), (10, 10), (0, 10))
pts2 = ((10, 10), (20, 10), (20, 20), (10, 20))
pts3 = ((10, 0), (20, 0), (20, 10), (10, 10))
p1 = Polygon(pts1, [])
p2 = Polygon(pts2, [])
p3 = Polygon(pts3, [])
# extruded meshes with different heights
mesh1 = trimesh.creation.extrude_polygon(p1, 10)
mesh2 = trimesh.creation.extrude_polygon(p2, 20)
mesh3 = trimesh.creation.extrude_polygon(p3, 30)
concatenated_mesh = trimesh.util.concatenate([mesh1, mesh2, mesh3])
filtered_faces = trimesh.grouping.group_rows(concatenated_mesh.edges_sorted, require_count=1) #will be empty
@mikedh is there some solution for this case?
Hello! Recently started using trimesh in a purpose of converting geojson polygons into extruded solids for 3d printing. Tested it on some data and found an issue. Due to some demands of 3d printing process all adjacent solids should be combined together. Let's say we got three simple boxes:
I tested two methods to do combine all of them.
united_meshes = mesh1.union(mesh2)
After this error nothing can be further added to this mesh and trimesh throws an error "Not all meshes are volumes!"
concatenated_meshes = trimesh.util.concatenate([mesh1, mesh2, mesh3])
Tried for solutions like:
Is there any way to delete that faces or even more better way to join meshes? It's also would be nice if there is a way to avoid creating triangle faces. Those primitives are simple extrusions of path and if it were extruded manually in AutoCAD, there wouldn't be any of diagonal edge, Thanks in advance!