MeshBuilder¶
The MeshBuilder
classes are helper tools to manage meshes buildup by
vertices and faces.
The vertices are stored in a vertices list as Vec3
instances.
The faces are stored as a sequence of vertex indices which is the location of
the vertex in the vertex list. A single MeshBuilder
class can contain
multiple separated meshes at the same time.
The method MeshBuilder.render_mesh()
renders the content as a single DXF
Mesh
entity, which supports ngons, ngons are polygons
with more than 4 vertices. This entity requires at least DXF R2000.
The method MeshBuilder.render_polyface()
renders the content as a single
DXF Polyface
entity, which supports only triangles and
quadrilaterals. This entity is supported by DXF R12.
The method MeshBuilder.render_3dfaces()
renders each face of the mesh as
a single DXF Face3d
entity, which supports only
triangles and quadrilaterals. This entity is supported by DXF R12.
The MeshTransformer
class is often used as an interface object to
transfer mesh data between functions and moduls, like for the mesh exchange
add-on meshex
.
The basic MeshBuilder
class does not support transformations.
- class ezdxf.render.MeshBuilder¶
-
- faces¶
List of faces as list of vertex indices, where a vertex index is the index of the vertex in the
vertices
list. A face requires at least three vertices,Mesh
supports ngons, so the count of vertices is not limited.
- add_face(vertices: Iterable[UVec]) None ¶
Add a face as vertices list to the mesh. A face requires at least 3 vertices, each vertex is a
(x, y, z)
tuple orVec3
object. The new vertex indices are stored as face in thefaces
list.- Parameters:
vertices – list of at least 3 vertices
[(x1, y1, z1), (x2, y2, z2), (x3, y3, y3), ...]
- add_mesh(vertices: list[Vec3] | None = None, faces: list[Sequence[int]] | None = None, mesh=None) None ¶
Add another mesh to this mesh.
A mesh can be a
MeshBuilder
,MeshVertexMerger
orMesh
object or requires the attributesvertices
andfaces
.- Parameters:
vertices – list of vertices, a vertex is a
(x, y, z)
tuple orVec3
objectfaces – list of faces, a face is a list of vertex indices
mesh – another mesh entity
- add_vertices(vertices: Iterable[UVec]) Sequence[int] ¶
Add new vertices to the mesh, each vertex is a
(x, y, z)
tuple or aVec3
object, returns the indices of the vertices added to thevertices
list.e.g. adding 4 vertices to an empty mesh, returns the indices
(0, 1, 2, 3)
, adding additional 4 vertices returns the indices(4, 5, 6, 7)
.
- bbox() BoundingBox ¶
Returns the
BoundingBox
of the mesh.
- copy()¶
Returns a copy of mesh.
- diagnose() MeshDiagnose ¶
Returns the
MeshDiagnose
object for this mesh.
- face_normals() Iterator[Vec3] ¶
Yields all face normals, yields the
NULLVEC
instance for degenerated faces.
- face_orientation_detector(reference: int = 0) FaceOrientationDetector ¶
Returns a
FaceOrientationDetector
or short fod instance. The forward orientation is defined by the reference face which is 0 by default.The fod can check if all faces are reachable from the reference face and if all faces have the same orientation. The fod can be reused to unify the face orientation of the mesh.
- flip_normals() None ¶
Flips the normals of all faces by reversing the vertex order inplace.
- classmethod from_builder(other: MeshBuilder)¶
Create new mesh from other mesh builder, faster than
from_mesh()
but supports onlyMeshBuilder
and inherited classes.
- classmethod from_mesh(other: MeshBuilder | Mesh) T ¶
Create new mesh from other mesh as class method.
- Parameters:
other – mesh of type
MeshBuilder
and inherited or DXFMesh
entity or any object providing attributesvertices
,edges
andfaces
.
- get_face_normal(index: int) Vec3 ¶
Returns the normal vector of the face index as
Vec3
, returns theNULLVEC
instance for degenerated faces.
- merge_coplanar_faces(passes: int = 1) MeshTransformer ¶
Returns a new
MeshBuilder
object with merged adjacent coplanar faces.The faces have to share at least two vertices and have to have the same clockwise or counter-clockwise vertex order.
The current implementation is not very capable!
- mesh_tessellation(max_vertex_count: int = 4) MeshTransformer ¶
Returns a new
MeshTransformer
instance, where each face has no more vertices than the given max_vertex_count.The fast mode uses a shortcut for faces with less than 6 vertices which may not work for concave faces!
- normalize_faces() None ¶
Removes duplicated vertex indices from faces and stores all faces as open faces, where the last vertex is not coincident with the first vertex.
- open_faces() Iterator[Sequence[int]] ¶
Yields all faces as sequence of integers where the first vertex is not coincident with the last vertex.
- optimize_vertices(precision: int = 6) MeshTransformer ¶
Returns a new mesh with optimized vertices. Coincident vertices are merged together and all faces are open faces (first vertex != last vertex). Uses internally the
MeshVertexMerger
class to merge vertices.
- render_3dfaces(layout: GenericLayoutType, dxfattribs=None, matrix: Matrix44 | None = None, ucs: UCS | None = None)¶
Render mesh as
Face3d
entities into layout.- Parameters:
layout –
BaseLayout
objectdxfattribs – dict of DXF attributes e.g.
{'layer': 'mesh', 'color': 7}
matrix – transformation matrix of type
Matrix44
- render_3dsolid(layout: GenericLayoutType, dxfattribs=None) Solid3d ¶
Render mesh as
Solid3d
entity into layout.This is an experimental feature to create simple 3DSOLID entities from polyhedrons.
The method supports closed and open shells. A 3DSOLID entity can contain multiple shells. Separate the meshes beforehand by the method
separate_meshes()
if required. The normals vectors of all faces should point outwards. Faces can have more than 3 vertices (ngons) but non-planar faces and concave faces will cause problems in some CAD applications. The methodmesh_tesselation()
can help to break down the faces into triangles.Requires a valid DXF document for layout and DXF version R2000 or newer.
- Parameters:
layout –
BaseLayout
objectdxfattribs – dict of DXF attributes e.g.
{'layer': 'mesh', 'color': 7}
- Raises:
DXFValueError – valid DXF document required, if
layout.doc
isNone
DXFVersionError – invalid DXF version
Added in version 1.2.0.
- render_mesh(layout: GenericLayoutType, dxfattribs=None, matrix: Matrix44 | None = None, ucs: UCS | None = None)¶
Render mesh as
Mesh
entity into layout.- Parameters:
layout –
BaseLayout
objectdxfattribs – dict of DXF attributes e.g.
{'layer': 'mesh', 'color': 7}
matrix – transformation matrix of type
Matrix44
- render_normals(layout: GenericLayoutType, length: float = 1, relative=True, dxfattribs=None)¶
Render face normals as
Line
entities into layout, useful to check orientation of mesh faces.- Parameters:
layout –
BaseLayout
objectlength – visual length of normal, use length < 0 to point normals in opposite direction
relative – scale length relative to face size if
True
dxfattribs – dict of DXF attributes e.g.
{'layer': 'normals', 'color': 6}
- render_polyface(layout: GenericLayoutType, dxfattribs=None, matrix: Matrix44 | None = None, ucs: UCS | None = None)¶
Render mesh as
Polyface
entity into layout.- Parameters:
layout –
BaseLayout
objectdxfattribs – dict of DXF attributes e.g.
{'layer': 'mesh', 'color': 7}
matrix – transformation matrix of type
Matrix44
- separate_meshes() list[MeshTransformer] ¶
A single
MeshBuilder
instance can store multiple separated meshes. This function returns this separated meshes as multipleMeshTransformer
instances.
- subdivide(level: int = 1, quads=True) MeshTransformer ¶
Returns a new
MeshTransformer
object with all faces subdivided.- Parameters:
level – subdivide levels from 1 to max of 5
quads – create quad faces if
True
else create triangles
- subdivide_ngons(max_vertex_count=4) Iterator[Sequence[Vec3]] ¶
Yields all faces as sequence of
Vec3
instances, where all ngons which have more than max_vertex_count vertices gets subdivided. In contrast to thetessellation()
method, creates this method a new vertex in the centroid of the face. This can create a more regular tessellation but only works reliable for convex faces!
- tessellation(max_vertex_count: int = 4) Iterator[Sequence[Vec3]] ¶
Yields all faces as sequence of
Vec3
instances, each face has no more vertices than the given max_vertex_count. This method uses the “ear clipping” algorithm which works with concave faces too and does not create any additional vertices.
- unify_face_normals(*, fod: FaceOrientationDetector | None = None) MeshTransformer ¶
Returns a new
MeshTransformer
object with unified face normal vectors of all faces. The forward direction (not necessarily outwards) is defined by the face-normals of the majority of the faces. This function can not process non-manifold meshes (more than two faces are connected by a single edge) or multiple disconnected meshes in a singleMeshBuilder
object.It is possible to pass in an existing
FaceOrientationDetector
instance as argument fod.- Raises:
NonManifoldError – non-manifold mesh
MultipleMeshesError – the
MeshBuilder
object contains multiple disconnected meshes
- unify_face_normals_by_reference(reference: int = 0, *, force_outwards=False, fod: FaceOrientationDetector | None = None) MeshTransformer ¶
Returns a new
MeshTransformer
object with unified face normal vectors of all faces. The forward direction (not necessarily outwards) is defined by the reference face, which is the first face of the mesh by default. This function can not process non-manifold meshes (more than two faces are connected by a single edge) or multiple disconnected meshes in a singleMeshBuilder
object.The outward direction of all face normals can be forced by stetting the argument force_outwards to
True
but this works only for closed surfaces, and it’s time-consuming!It is not possible to check for a closed surface as long the face normal vectors are not unified. But it can be done afterward by the attribute
MeshDiagnose.is_closed_surface()
to see if the result is trustworthy.It is possible to pass in an existing
FaceOrientationDetector
instance as argument fod.- Parameters:
reference – index of the reference face
force_outwards – forces face-normals to point outwards, this works only for closed surfaces, and it’s time-consuming!
fod –
FaceOrientationDetector
instance
- Raises:
ValueError – non-manifold mesh or the
MeshBuilder
object contains multiple disconnected meshes
MeshTransformer¶
Same functionality as MeshBuilder
but supports inplace transformation.
- class ezdxf.render.MeshTransformer¶
Subclass of
MeshBuilder
- transform(matrix: Matrix44)¶
Transform mesh inplace by applying the transformation matrix.
- Parameters:
matrix – 4x4 transformation matrix as
Matrix44
object
- translate(dx: float | UVec = 0, dy: float = 0, dz: float = 0)¶
Translate mesh inplace.
- Parameters:
dx – translation in x-axis or translation vector
dy – translation in y-axis
dz – translation in z-axis
- scale(sx: float = 1, sy: float = 1, sz: float = 1)¶
Scale mesh inplace.
- Parameters:
sx – scale factor for x-axis
sy – scale factor for y-axis
sz – scale factor for z-axis
- scale_uniform(s: float)¶
Scale mesh uniform inplace.
- Parameters:
s – scale factor for x-, y- and z-axis
- rotate_x(angle: float)¶
Rotate mesh around x-axis about angle inplace.
- Parameters:
angle – rotation angle in radians
- rotate_y(angle: float)¶
Rotate mesh around y-axis about angle inplace.
- Parameters:
angle – rotation angle in radians
- rotate_z(angle: float)¶
Rotate mesh around z-axis about angle inplace.
- Parameters:
angle – rotation angle in radians
MeshVertexMerger¶
Same functionality as MeshBuilder
, but created meshes with unique
vertices and no doublets, but MeshVertexMerger
needs extra memory for
bookkeeping and also does not support transformations.
The location of the merged vertices is the location of the first vertex with the
same key.
This class is intended as intermediate object to create compact meshes and
convert them to MeshTransformer
objects to apply transformations:
mesh = MeshVertexMerger()
# create your mesh
mesh.add_face(...)
# convert mesh to MeshTransformer object
return MeshTransformer.from_builder(mesh)
- class ezdxf.render.MeshVertexMerger(precision: int = 6)¶
Subclass of
MeshBuilder
Mesh with unique vertices and no doublets, but needs extra memory for bookkeeping.
MeshVertexMerger
creates a key for every vertex by rounding its components by the Pythonround()
function and a given precision value. Each vertex with the same key gets the same vertex index, which is the index of first vertex with this key, so all vertices with the same key will be located at the location of this first vertex. If you want an average location of all vertices with the same key use theMeshAverageVertexMerger
class.- Parameters:
precision – floating point precision for vertex rounding
MeshAverageVertexMerger¶
This is an extended version of MeshVertexMerger
.
The location of the merged vertices is the average location of all vertices with
the same key, this needs extra memory and runtime in comparison to
MeshVertexMerger
and this class also does not support
transformations.
- class ezdxf.render.MeshAverageVertexMerger(precision: int = 6)¶
Subclass of
MeshBuilder
Mesh with unique vertices and no doublets, but needs extra memory for bookkeeping and runtime for calculation of average vertex location.
MeshAverageVertexMerger
creates a key for every vertex by rounding its components by the Pythonround()
function and a given precision value. Each vertex with the same key gets the same vertex index, which is the index of first vertex with this key, the difference to theMeshVertexMerger
class is the calculation of the average location for all vertices with the same key, this needs extra memory to keep track of the count of vertices for each key and extra runtime for updating the vertex location each time a vertex with an existing key is added.- Parameters:
precision – floating point precision for vertex rounding
- class ezdxf.render.mesh.EdgeStat(count: int, balance: int)¶
Named tuple of edge statistics.
- count¶
how often the edge (a, b) is used in faces as (a, b) or (b, a)
- balance¶
count of edges (a, b) - count of edges (b, a) and should be 0 in “healthy” closed surfaces, if the balance is not 0, maybe doubled coincident faces exist or faces may have mixed clockwise and counter-clockwise vertex orders
MeshBuilder Helper Classes¶
- class ezdxf.render.MeshDiagnose¶
Diagnose tool which can be used to analyze and detect errors of
MeshBuilder
objects like topology errors for closed surfaces. The object contains cached values, which do not get updated if the source mesh will be changed!Note
There exist no tools in ezdxf to repair broken surfaces, but you can use the
ezdxf.addons.meshex
addon to exchange meshes with the open source tool MeshLab.Create an instance of this tool by the
MeshBuilder.diagnose()
method.- property bbox: BoundingBox¶
Returns the
BoundingBox
of the mesh. (cached data)
- property edge_stats: Dict[Tuple[int, int], EdgeStat]¶
Returns the edge statistics as a
dict
. The dict-key is the edge as tuple of two vertex indices (a, b) where a is always smaller than b. The dict-value is anEdgeStat
tuple of edge count and edge balance, seeEdgeStat
for the definition of edge count and edge balance. (cached data)
- property euler_characteristic: int¶
Returns the Euler characteristic: https://en.wikipedia.org/wiki/Euler_characteristic
This number is always 2 for convex polyhedra.
- property face_normals: Sequence[Vec3]¶
Returns all face normal vectors as sequence. The
NULLVEC
instance is used as normal vector for degenerated faces. (cached data)
- property faces: Sequence[Sequence[int]]¶
Sequence of faces as
Sequence[int]
- property is_closed_surface: bool¶
Returns
True
if the mesh has a closed surface. This method does not require a unified face orientation. If multiple separated meshes are present the state is onlyTrue
if all meshes have a closed surface. (cached data)Returns
False
for non-manifold meshes.
- property is_edge_balance_broken: bool¶
Returns
True
if the edge balance is broken, this indicates a topology error for closed surfaces. A non-broken edge balance reflects that each edge connects two faces, where the edge is clockwise oriented in the first face and counter-clockwise oriented in the second face. A broken edge balance indicates possible topology errors like mixed face vertex orientations or a non-manifold mesh where an edge connects more than two faces. (cached data)
- property is_manifold: bool¶
Returns
True
if all edges have an edge count < 3. (cached data)A non-manifold mesh has edges with 3 or more connected faces.
- property n_edges: int¶
Returns the unique edge count. (cached data)
- property n_faces: int¶
Returns the face count.
- property n_vertices: int¶
Returns the vertex count.
- estimate_face_normals_direction() float ¶
Returns the estimated face-normals direction as
float
value in the range [-1.0, 1.0] for a closed surface.This heuristic works well for simple convex hulls but struggles with more complex structures like a torus (doughnut).
A counter-clockwise (ccw) vertex arrangement for outward pointing faces is assumed but a clockwise (cw) arrangement works too but the return values are reversed.
The closer the value to 1.0 (-1.0 for cw) the more likely all normals pointing outwards from the surface.
The closer the value to -1.0 (1.0 for cw) the more likely all normals pointing inwards from the surface.
There are no exact confidence values if all faces pointing outwards, here some examples for surfaces created by
ezdxf.render.forms
functions:cube()
returns 1.0cylinder()
returns 0.9992sphere()
returns 0.9994cone()
returns 0.9162cylinder()
with all hull faces pointing outwards but caps pointing inwards returns 0.7785 but the propertyis_edge_balance_broken
returnsTrue
which indicates the mixed vertex orientationand the estimation of 0.0469 for a
torus()
is barely usable
- has_non_planar_faces() bool ¶
Returns
True
if any face is non-planar.
- surface_area() float ¶
Returns the surface area.
- total_edge_count() int ¶
Returns the total edge count of all faces, shared edges are counted separately for each face. In closed surfaces this count should be 2x the unique edge count
n_edges
. (cached data)
- unique_edges() Iterable[Tuple[int, int]] ¶
Yields the unique edges of the mesh as int 2-tuples. (cached data)
- volume() float ¶
Returns the volume of a closed surface or 0 otherwise.
Warning
The face vertices have to be in counter-clockwise order, this requirement is not checked by this method.
The result is not correct for multiple separated meshes in a single MeshBuilder object!!!
- class ezdxf.render.FaceOrientationDetector(mesh: MeshBuilder, reference: int = 0)¶
Helper class for face orientation and face normal vector detection. Use the method
MeshBuilder.face_orientation_detector()
to create an instance.The face orientation detector classifies the faces of a mesh by their forward or backward orientation. The forward orientation is defined by a reference face, which is the first face of the mesh by default and this orientation is not necessarily outwards.
This class has some overlapping features with
MeshDiagnose
but it has a longer setup time and needs more memory thanMeshDiagnose
.- Parameters:
mesh – source mesh as
MeshBuilder
objectreference – index of the reference face
- is_manifold¶
True
if all edges have an edge count < 3. A non-manifold mesh has edges with 3 or more connected faces.
- property all_reachable: bool¶
Returns
True
if all faces are reachable from the reference face same as propertyis_single_mesh
.
- property count: tuple[int, int]¶
Returns the count of forward and backward oriented faces.
- property backward_faces: Iterator[Sequence[int]]¶
Yields all backward oriented faces.
- property forward_faces: Iterator[Sequence[int]]¶
Yields all forward oriented faces.
- property has_uniform_face_normals: bool¶
Returns
True
if all reachable faces are forward oriented according to the reference face.
- property is_closed_surface: bool¶
Returns
True
if the mesh has a closed surface. This method does not require a unified face orientation. If multiple separated meshes are present the state is onlyTrue
if all meshes have a closed surface.Returns
False
for non-manifold meshes.
- property is_single_mesh: bool¶
Returns
True
if only a single mesh is present same as propertyall_reachable
.
- classify_faces(reference: int = 0) None ¶
Detect the forward and backward oriented faces.
The forward and backward orientation has to be defined by a reference face.
- is_reference_face_pointing_outwards() bool ¶
Returns
True
if the normal vector of the reference face is pointing outwards. This works only for meshes with unified faces which represent a closed surfaces, and it’s a time-consuming calculation!