diff --git a/src/ifcopenshell-python/ifcopenshell/api/aggregate/assign_object.py b/src/ifcopenshell-python/ifcopenshell/api/aggregate/assign_object.py index 632d286ff3..685b680a95 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/aggregate/assign_object.py +++ b/src/ifcopenshell-python/ifcopenshell/api/aggregate/assign_object.py @@ -26,16 +26,31 @@ class Usecase: def __init__(self, file, product=None, relating_object=None): """Assigns an object as an aggregate to a product + All physical IFC model elements must be part of a hierarchical tree + called the "spatial decomposition", where large things are made up of + smaller things. This tree always begins at an "IfcProject" and is then + broken down using "decomposition" relationships, of which aggregation is + the first relationship you will use. + Typically used when you want to describe how large spaces are made up of smaller spaces. For example large spatial elements (e.g. sites, buidings) can be made out of smaller spatial elements (e.g. storeys, spaces). + The largest space (typically the IfcSite) can then be aggregated in a + project. It is requirement for all spatial structures to be directly or + indirectly aggregated back to the IfcProject to create a hierarchy of + spaces. + The other common usecase is when larger physical products are made up of smaller physical products. For example, a stair might be made out of a flight, a landing, a railing and so on. Or a wall might be made out of stud members, and coverings. + As a product may only have a single locaion in the "spatial + decomposition" tree, assigning an aggregate relationship will remove any + previous aggregation, containment, or nesting relationships it may have. + IFC placements follow a convention where the placement is relative to its parent in the spatial hierarchy. If your product has a placement, its placement will be recalculated to follow this convention. @@ -51,8 +66,12 @@ class Usecase: Example:: + project = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcProject") element = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcSite") subelement = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcBuilding") + # The project contains a site (note that project aggregation is a special case in IFC) + ifcopenshell.api.run("aggregate.assign_object", model, product=element, relating_object=project) + # The site has a building ifcopenshell.api.run("aggregate.assign_object", model, product=subelement, relating_object=element) """ self.file = file diff --git a/src/ifcopenshell-python/ifcopenshell/api/aggregate/unassign_object.py b/src/ifcopenshell-python/ifcopenshell/api/aggregate/unassign_object.py index f2f6bbd189..23f3d91311 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/aggregate/unassign_object.py +++ b/src/ifcopenshell-python/ifcopenshell/api/aggregate/unassign_object.py @@ -21,13 +21,42 @@ import ifcopenshell.api class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, product=None): + """Unassigns a product from its aggregate + + A product (i.e. a smaller part of a whole) may be aggregated into zero + or one larger space or element. This function will remove that + aggregation relationship. + + As all physical IFC model elements must be part of a hierarchical tree + called the "spatial decomposition", using this function will remove the + product from that tree. This is a dangerous operation and may result in + the product no longer being visible in IFC applications. + + If the product is not part of an aggregation relationship, nothing will + happen. + + :param product: The part of the aggregate, typically an IfcElement or + IfcSpatialStructureElement subclass + :type product: ifcopenshell.entity_instance + :return: The IfcRelAggregate relationship instance, only returned if the + whole still contains any other parts. + :rtype: ifcopenshell.entity_instance.entity_instance, None + + Example:: + + element = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcSite") + subelement1 = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcBuilding") + subelement2 = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcBuilding") + ifcopenshell.api.run("aggregate.assign_object", model, product=subelement1, relating_object=element) + ifcopenshell.api.run("aggregate.assign_object", model, product=subelement2, relating_object=element) + # The relationship is returned as element still has subelement2 + rel = ifcopenshell.api.run("aggregate.unassign_object", model, product=subelement1) + # Nothing is returned, as element is now empty + ifcopenshell.api.run("aggregate.unassign_object", model, product=subelement2) + """ self.file = file - self.settings = { - "product": None, - } - for key, value in settings.items(): - self.settings[key] = value + self.settings = { "product": product } def execute(self): for rel in self.settings["product"].Decomposes or []: