ifcpatch: small recipe polish

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.
This commit is contained in:
Gorgious56
2026-06-23 09:46:31 +02:00
parent f710929e9e
commit 2ab5ca9222
2 changed files with 16 additions and 1 deletions
@@ -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
@@ -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