diff --git a/src/ifcopenshell-python/ifcopenshell/api/root/copy_class.py b/src/ifcopenshell-python/ifcopenshell/api/root/copy_class.py index 708855b938..55a2093004 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/root/copy_class.py +++ b/src/ifcopenshell-python/ifcopenshell/api/root/copy_class.py @@ -22,11 +22,47 @@ import ifcopenshell.util.element class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, product=None): + """Copies a product + + The following relationships are also duplicated: + + * The copy will have the same object placement coordinates as the + original. + * The copy will have duplicated property sets, properties, and quantities + * The copy will have all nested distribution ports copied too + * The copy will be part of the same aggregate + * The copy will be contained in the same spatial structure + * The copy, if it is an occurrence, will have the same type + * Voids are duplicated too + * The copy will have the same material as the original. Parametric + material set usages will be copied. + + Be warned that: + + * Representations are _not_ copied. Copying representations is an + expensive operation so for now the user is responsible for handling + representations. + * Filled voids are not copied, as there is no guarantee that the filling + will also be copied. + * Path connectivity is not copied, as there is no guarantee that the + connections are still valid. + + :param product: The IfcProduct to copy. + :type param: ifcopenshell.entity_instance.entity_instance + :return: The copied product + :rtype: ifcopenshell.entity_instance.entity_instance + + Example:: + + # We have a wall + wall = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcWall") + + # And now we have two + wall_copy = ifcopenshell.api.run("root.copy_class", model, product=wall) + """ self.file = file - self.settings = {"product": None} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"product": product} def execute(self): result = ifcopenshell.util.element.copy(self.file, self.settings["product"]) diff --git a/src/ifcopenshell-python/ifcopenshell/api/root/create_entity.py b/src/ifcopenshell-python/ifcopenshell/api/root/create_entity.py index 7abeb59502..ae94b5ef47 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/root/create_entity.py +++ b/src/ifcopenshell-python/ifcopenshell/api/root/create_entity.py @@ -21,15 +21,52 @@ import ifcopenshell.api class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, ifc_class="IfcBuildingElementProxy", predefined_type=None, name=None): + """Create a new rooted product + + This is a critical function used to create almost any rooted product or + product type. If you want to create walls, spaces, buildings, wall + types, and so on, use this function. + + Just specify the class you want to create, as well as the predefined + type and name. It will handle the storage of the predefined type and + check whether the predefined type is built-in or custom. It will also + generate a valid GlobalId and store ownership history. It will also + handle some edge cases for default validity where users might forget to + populate some mandatory attributes. For example, doors must define an + operation type but many people forget. + + :param ifc_class: Any rooted IFC class. + :type ifc_class: str,optional + :param predefined_type: Any built-in or user-defined predefined type that + is applicable to that IFC class. For user-defined predefined types + just enter in any value and the API will handle it automatically. + :type predefined_type: str,optional + :param name: The name of the new element. + :type name: str,optional + :return: The newly created element based on the specified IFC class. + :rtype: ifcopenshell.entity_instance.entity_instance + + Example:: + + # We have a project. + ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcProject") + + # We have a building. + ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcBuilding") + + # We have a wall. + ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcWall") + + # We have a wall type. + ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcWallType") + """ self.file = file self.settings = { - "ifc_class": "IfcBuildingElementProxy", - "predefined_type": None, - "name": None, + "ifc_class": ifc_class, + "predefined_type": predefined_type, + "name": name, } - for key, value in settings.items(): - self.settings[key] = value def execute(self): element = self.file.create_entity( diff --git a/src/ifcopenshell-python/ifcopenshell/api/root/reassign_class.py b/src/ifcopenshell-python/ifcopenshell/api/root/reassign_class.py index 403e49fc34..0726092121 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/root/reassign_class.py +++ b/src/ifcopenshell-python/ifcopenshell/api/root/reassign_class.py @@ -21,15 +21,43 @@ import ifcopenshell.util.schema class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, product=None, ifc_class="IfcBuildingElementProxy", predefined_type=None): + """Changes the class of a product + + If you ever created a wall then realised it's meant to be something + else, this function lets you change the IFC class whilst retaining all + other geometry and relationships. + + This is especially useful when dealing with poorly classified data from + proprietary software with limited IFC capabilities. + + :param product: The IfcProduct that you want to change the class of. + :type product: ifcopenshell.entity_instance.entity_instance + :param ifc_class: The new IFC class you want to change it to. + :type ifc_class: str,optional + :param predefined_type: In case you want to change the predefined type + too. User defined types are also allowed, just type what you want. + :type predefined_type: str,optional + :return: The newly modified product. + :rtype: ifcopenshell.entity_instance.entity_instance + + Example:: + + # We have a wall. + wall = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcWall") + + # Oh, did I say wall? I meant slab. + slab = ifcopenshell.api.run("root.reassign_class", model, product=wall, ifc_class="IfcSlab") + + # Warning: this will crash since wall doesn't exist any more. + print(wall) # Kaboom. + """ self.file = file self.settings = { - "product": None, - "ifc_class": "IfcBuildingElementProxy", - "predefined_type": None, + "product": product, + "ifc_class": ifc_class, + "predefined_type": predefined_type, } - for key, value in settings.items(): - self.settings[key] = value def execute(self): element = ifcopenshell.util.schema.reassign_class( diff --git a/src/ifcopenshell-python/ifcopenshell/api/root/remove_product.py b/src/ifcopenshell-python/ifcopenshell/api/root/remove_product.py index 38973f973b..23eae1b3b4 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/root/remove_product.py +++ b/src/ifcopenshell-python/ifcopenshell/api/root/remove_product.py @@ -20,11 +20,33 @@ import ifcopenshell.api class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, product=None): + """Removes a product + + This is effectively a smart delete function that not only removes a + product, but also all of its relationships. It is always recommended to + use this function to prevent orphaned data in your IFC model. + + For example, geometric representations are removed. Placement + coordinates are also removed. Properties are removed. Material, type, + containment, aggregation, and nesting relationships are removed (but + naturally, the materials, types, containers, etc themselves remain). + + :param product: The IfcProduct to remove. + :type product: ifcopenshell.entity_instance.entity_instance + :return: None + :rtype: None + + Example:: + + # We have a wall. + wall = ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcWall") + + # No we don't. + ifcopenshell.api.run("root.remove_product", model, product=wall) + """ self.file = file - self.settings = {"product": None} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"product": product} def execute(self): representations = []