From cd8199d3c41c32a4684ec413be4890b1609fb18d Mon Sep 17 00:00:00 2001 From: Bruno Postle Date: Tue, 10 Mar 2026 07:30:16 +0000 Subject: [PATCH] ifcquery: diagnose empty drawings and fix test fixture Generated with the assistance of an AI coding tool. --- src/ifcquery/ifcquery/plot.py | 32 +++++++++++++++++++++++++++++++- src/ifcquery/tests/test_plot.py | 1 + 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/ifcquery/ifcquery/plot.py b/src/ifcquery/ifcquery/plot.py index 0deee7baca..4327384b63 100644 --- a/src/ifcquery/ifcquery/plot.py +++ b/src/ifcquery/ifcquery/plot.py @@ -117,6 +117,36 @@ def _make_filtered_iterator(model: ifcopenshell.file, include_elements: list[Any return ifcopenshell.geom.iterator(geom_settings, model, n_threads, include=include_elements) +def _diagnose_empty_drawing(model: ifcopenshell.file, view: str) -> str: + """Return a helpful error message when ifcopenshell.draw produces no geometry groups.""" + hints = [] + + if view in ("floorplan", "auto"): + storeys = model.by_type("IfcBuildingStorey") + if not storeys: + hints.append("the model has no IfcBuildingStorey entities (required for auto_floorplan)") + else: + null_elevation = [s for s in storeys if getattr(s, "Elevation", None) is None] + if null_elevation: + names = ", ".join(f'"{s.Name or s.GlobalId}"' for s in null_elevation) + hints.append( + f"storey Elevation is None for: {names} — " + "set IfcBuildingStorey.Elevation (e.g. 0.0) so the section cut height can be determined" + ) + + has_geom = any( + getattr(e, "Representation", None) is not None + for e in model.by_type("IfcProduct") + ) + if not has_geom: + hints.append("no IfcProduct entities have geometric representations") + + base = f"No plan geometry found for view={view!r}." + if hints: + return base + " Possible causes: " + "; ".join(hints) + "." + return base + " The model may lack geometry visible in this view." + + def plot( model: ifcopenshell.file, *, @@ -225,7 +255,7 @@ def plot( svgs = list(svg_split(BytesIO(svg_bytes))) if not svgs: - raise ValueError("No plan geometry found; the model may lack 2D annotation representations for the requested view.") + raise ValueError(_diagnose_empty_drawing(model, view)) composite = None png_bytes = None diff --git a/src/ifcquery/tests/test_plot.py b/src/ifcquery/tests/test_plot.py index 1794546fab..142be30bdc 100644 --- a/src/ifcquery/tests/test_plot.py +++ b/src/ifcquery/tests/test_plot.py @@ -52,6 +52,7 @@ def model_with_annotations(): site = ifcopenshell.api.root.create_entity(f, ifc_class="IfcSite", name="TestSite") building = ifcopenshell.api.root.create_entity(f, ifc_class="IfcBuilding", name="TestBuilding") storey = ifcopenshell.api.root.create_entity(f, ifc_class="IfcBuildingStorey", name="Ground Floor") + storey.Elevation = 0.0 # required for setSectionHeightsFromStoreys() to create a cut plane ifcopenshell.api.aggregate.assign_object(f, products=[site], relating_object=project) ifcopenshell.api.aggregate.assign_object(f, products=[building], relating_object=site) ifcopenshell.api.aggregate.assign_object(f, products=[storey], relating_object=building)