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
vertices

List of vertices as Vec3 or (x, y, z) tuple

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 or Vec3 object. The new vertex indices are stored as face in the faces 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 or Mesh object or requires the attributes vertices and faces.

Parameters:
  • vertices – list of vertices, a vertex is a (x, y, z) tuple or Vec3 object

  • faces – 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 a Vec3 object, returns the indices of the vertices added to the vertices 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).

Parameters:

vertices – list of vertices, vertex as (x, y, z) tuple or Vec3 objects

Returns:

indices of the vertices added to the vertices list

Return type:

tuple

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.

faces_as_vertices() Iterator[list[Vec3]]

Yields all faces as list of vertices.

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 only MeshBuilder and inherited classes.

classmethod from_mesh(other: MeshBuilder | Mesh) T

Create new mesh from other mesh as class method.

Parameters:

othermesh of type MeshBuilder and inherited or DXF Mesh entity or any object providing attributes vertices, edges and faces.

classmethod from_polyface(other: Polymesh | Polyface) T

Create new mesh from a Polyface or Polymesh object.

get_face_vertices(index: int) Sequence[Vec3]

Returns the face index as sequence of Vec3 objects.

get_face_normal(index: int) Vec3

Returns the normal vector of the face index as Vec3, returns the NULLVEC 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:
  • layoutBaseLayout object

  • dxfattribs – dict of DXF attributes e.g. {'layer': 'mesh', 'color': 7}

  • matrix – transformation matrix of type Matrix44

  • ucs – transform vertices by UCS to WCS

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 method mesh_tesselation() can help to break down the faces into triangles.

Requires a valid DXF document for layout and DXF version R2000 or newer.

Parameters:
  • layoutBaseLayout object

  • dxfattribs – dict of DXF attributes e.g. {'layer': 'mesh', 'color': 7}

Raises:

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:
  • layoutBaseLayout object

  • dxfattribs – dict of DXF attributes e.g. {'layer': 'mesh', 'color': 7}

  • matrix – transformation matrix of type Matrix44

  • ucs – transform vertices by UCS to WCS

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:
  • layoutBaseLayout object

  • length – 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:
  • layoutBaseLayout object

  • dxfattribs – dict of DXF attributes e.g. {'layer': 'mesh', 'color': 7}

  • matrix – transformation matrix of type Matrix44

  • ucs – transform vertices by UCS to WCS

separate_meshes() list[MeshTransformer]

A single MeshBuilder instance can store multiple separated meshes. This function returns this separated meshes as multiple MeshTransformer 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 the tessellation() 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 single MeshBuilder 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 single MeshBuilder 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!

  • fodFaceOrientationDetector 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

rotate_axis(axis: UVec, angle: float)

Rotate mesh around an arbitrary axis located in the origin (0, 0, 0) about angle.

Parameters:
  • axis – rotation axis as Vec3

  • 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 Python round() 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 the MeshAverageVertexMerger 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 Python round() 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 the MeshVertexMerger 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 an EdgeStat tuple of edge count and edge balance, see EdgeStat 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 only True 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.

property vertices: Sequence[Vec3]

Sequence of mesh vertices as Vec3 instances

centroid() Vec3

Returns the centroid of all vertices. (center of mass)

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:

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 than MeshDiagnose.

Parameters:
  • mesh – source mesh as MeshBuilder object

  • reference – 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 property is_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 only True 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 property all_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!