Skip to content

Commit

Permalink
exclude MESH without vertices or faces from DXF export #1219
Browse files Browse the repository at this point in the history
MESH entities without vertices or faces create an invalid
DXF file for AutoCAD and BricsCAD.

And Mesh.audit() now also destroys such entities.
  • Loading branch information
mozman committed Dec 25, 2024
1 parent 4b5e6d7 commit 3f59f0e
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 6 deletions.
6 changes: 5 additions & 1 deletion notes/pages/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
## Version 1.3.5 - 2024-12-15
## Version 1.3.6 - dev
- NEW: `Mesh.audit()` removes `MESH` entities without vertices or faces
- BUGFIX: Exported `MESH` entities without vertices or faces create invalid DXF files
- {{issue 1219}}
- ## Version 1.3.5 - 2024-12-15
- ((65ed4f6c-edc8-4390-880c-c604a3fa5ec0))
- NEW: `ezdxf.blkrefs.find_unreferenced_blocks()` function returns the names of unused block definitions
- NEW: `Auditor` checks if modelspace and active paperspace exists
Expand Down
1 change: 1 addition & 0 deletions src/ezdxf/audit.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ class AuditError(IntEnum):
INVALID_ELLIPSE_RATIO = 225
INVALID_HATCH_BOUNDARY_PATH = 226
TAG_ATTRIBUTE_MISSING = 227
INVALID_MESH_DATA = 228


REQUIRED_ROOT_DICT_ENTRIES = ("ACAD_GROUP", "ACAD_PLOTSTYLENAME")
Expand Down
22 changes: 22 additions & 0 deletions src/ezdxf/entities/mesh.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,20 @@ def process_creases():
self._edges = process_edges()
self._creases = process_creases()

def preprocess_export(self, tagwriter: AbstractTagWriter) -> bool:
"""Pre requirement check and pre-processing for export.
Returns ``False`` if entity should not be exported at all.
- MESH without vertices creates an invalid DXF file for AutoCAD and BricsCAD.
- MESH without faces creates an invalid DXF file for AutoCAD and BricsCAD.
(internal API)
"""
if len(self.vertices) == 0 or len(self.faces) == 0:
return False
return True

def export_entity(self, tagwriter: AbstractTagWriter) -> None:
"""Export entity specific data as DXF tags."""
super().export_entity(tagwriter)
Expand Down Expand Up @@ -410,6 +424,14 @@ def audit(self, auditor: Auditor) -> None:
message=f"fixed invalid count of crease values in {str(self)}",
dxf_entity=self,
)
if len(self.vertices) == 0 or len(self.faces) == 0:
# A MESH without vertices or vertices creates an invalid DXF file for
# AutoCAD and BricsCAD
auditor.fixed_error(
code=AuditError.INVALID_VERTEX_COUNT,
message=f"removed {str(self)} without vertices or faces",
)
auditor.trash(self)


class MeshData:
Expand Down
4 changes: 2 additions & 2 deletions src/ezdxf/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,5 @@
# 1. bug fix release beta0: VERSION = "0.9.1b0"; version = (0, 9, 1, 'b0')
# 2. bug fix release: VERSION = "0.9.2"; version = (0, 9, 2, 'release')

version = (1, 3, 5, "release")
__version__ = "1.3.5"
version = (1, 3, 6, "b0")
__version__ = "1.3.6b0"
19 changes: 16 additions & 3 deletions tests/test_02_dxf_graphics/test_228_mesh.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,12 @@ def test_load_from_text(entity):
assert entity.dxf.subdivision_levels == 0


def test_write_dxf():
def test_export_without_vertices_or_faces():
# MESH without vertices creates an invalid DXF file for AutoCAD and BricsCAD.
# MESH without faces creates an invalid DXF file for AutoCAD and BricsCAD.
entity = Mesh.from_text(MESH)
result = TagCollector.dxftags(entity)
expected = basic_tags_from_text(MESH)
assert result == expected
assert len(result) == 0


@pytest.fixture(scope="module")
Expand Down Expand Up @@ -200,6 +201,18 @@ def test_auditor_fixes_invalid_crease_count(msp: Modelspace):
assert list(mesh.creases) == [0.0]


def test_auditor_destroys_invalid_meshes_without_vertices_or_faces():
# new document required
doc = ezdxf.new()
msp = doc.modelspace()
# add a mesh without vertices or faces
mesh = msp.add_mesh()

auditor = msp.doc.audit()
assert len(auditor.fixes) == 1
assert mesh.is_alive is False


def test_vertex_format(msp: Modelspace):
mesh = msp.add_mesh()
with mesh.edit_data() as mesh_data:
Expand Down

0 comments on commit 3f59f0e

Please sign in to comment.