From 2ab5ca9222913be0f26733aecbbfaddebbb4ae3b Mon Sep 17 00:00:00 2001 From: Gorgious56 Date: Tue, 23 Jun 2026 09:46:31 +0200 Subject: [PATCH] ifcpatch: small recipe polish MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ExtractElements: expand the `query` docstring to cover the exclusion syntax (`!` on entity classes, `!=` on attribute / pset / material / classification / location / group facets) and the "seed with a broad include before subtracting" gotcha — entity-class exclusion does not auto-seed from "all elements", so a bare `! IfcSlab` query returns nothing. FixArchiCADToRevitDoorSwings: guard the `IfcIndexedPolyCurve.Segments` loop against the IFC4 case where Segments is absent (a polyline through all coords in declared order). Previously crashed on `None.__iter__`. Generated with the assistance of an AI coding tool. --- src/ifcpatch/ifcpatch/recipes/ExtractElements.py | 15 ++++++++++++++- .../recipes/FixArchiCADToRevitDoorSwings.py | 2 ++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/ifcpatch/ifcpatch/recipes/ExtractElements.py b/src/ifcpatch/ifcpatch/recipes/ExtractElements.py index 10d8b23330..132d86d436 100644 --- a/src/ifcpatch/ifcpatch/recipes/ExtractElements.py +++ b/src/ifcpatch/ifcpatch/recipes/ExtractElements.py @@ -41,7 +41,14 @@ class Patcher(ifcpatch.BasePatcher): to a new IFC file. For example, you might want to extract only the walls in a model and save it as a new model. - :param query: A query to select the subset of IFC elements. + :param query: A query to select the subset of IFC elements, using the + ifcopenshell.util.selector.filter_elements grammar. Supports + exclusion (blacklist) via '!' on entity classes and '!=' on + attribute / pset / material / classification / location / group + facets. Entity-class exclusion does not auto-seed from "all + elements", so a bare '! IfcSlab' query returns nothing — start + with a broad include (e.g. 'IfcProduct', 'IfcElement') and + subtract from it. :param assume_asset_uniqueness_by_name: Avoid adding assets (profiles, materials, styles) with the same name multiple times. Which helps in avoiding duplicated assets. ----- @@ -63,6 +70,12 @@ class Patcher(ifcpatch.BasePatcher): # Extract all walls and slabs ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "ExtractElements", "arguments": ["IfcWall, IfcSlab"]}) + + # Extract everything except slabs (seed with a broad include, then subtract) + ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "ExtractElements", "arguments": ["IfcProduct, ! IfcSlab"]}) + + # Extract walls whose Name is not "Foo" + ifcpatch.execute({"input": "input.ifc", "file": model, "recipe": "ExtractElements", "arguments": ["IfcWall, attribute.Name != \"Foo\""]}) """ super().__init__(file, logger) self.query = query diff --git a/src/ifcpatch/ifcpatch/recipes/FixArchiCADToRevitDoorSwings.py b/src/ifcpatch/ifcpatch/recipes/FixArchiCADToRevitDoorSwings.py index c2523c7e8f..2666b4611f 100644 --- a/src/ifcpatch/ifcpatch/recipes/FixArchiCADToRevitDoorSwings.py +++ b/src/ifcpatch/ifcpatch/recipes/FixArchiCADToRevitDoorSwings.py @@ -190,6 +190,8 @@ class Patcher(ifcpatch.BasePatcher): settings.set("dimensionality", ifcopenshell.ifcopenshell_wrapper.CURVES_SURFACES_AND_SOLIDS) unit_scale = ifcopenshell.util.unit.calculate_unit_scale(self.file) for curve in self.file.by_type("IfcIndexedPolyCurve"): + if curve.Segments is None: + continue if True in [s.is_a("IfcArcIndex") for s in curve.Segments]: shape = ifcopenshell.geom.create_shape(settings, curve) e = shape.edges