From 308ee7f7a94e40cfecf6fa998bd37f4c9e083f4d Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Tue, 15 Nov 2022 16:11:47 +0900 Subject: [PATCH] Add API documentation for classification module --- .../api/classification/add_classification.py | 57 ++++++++++- .../api/classification/add_reference.py | 99 +++++++++++++++++-- .../api/classification/edit_classification.py | 25 ++++- .../api/classification/edit_reference.py | 25 ++++- .../classification/remove_classification.py | 24 ++++- .../api/classification/remove_reference.py | 31 +++++- 6 files changed, 232 insertions(+), 29 deletions(-) diff --git a/src/ifcopenshell-python/ifcopenshell/api/classification/add_classification.py b/src/ifcopenshell-python/ifcopenshell/api/classification/add_classification.py index 57e8fe5c4a..c344f03e1f 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/classification/add_classification.py +++ b/src/ifcopenshell-python/ifcopenshell/api/classification/add_classification.py @@ -22,13 +22,62 @@ import ifcopenshell.util.date class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, classification=None): + """Adds a new classification system to the project + + External classification systems such as Uniclass or Omniclass are + ways of categorising elements in the AEC industry, typically + standardised or nominated by governments or companies. A system + typically contains a series of hierarchical reference codes and labels + like Pr_12_23_34. + + Classifications may be applied to many things, not just physical + elements, such as doors and windows, spatial elements, tasks, cost + items, or even resources. + + Prior to assigning classificaion references, you need to add the name + and metadata of the classification system that you will use in your + project. Classification systems may be revised over time, so this + metadata includes the edition date. + + Common classification systems are provided as an IFC library which may + be downloaded from https://github.com/Moult/IfcClassification for your + convenience. It is advised to use these to ensure that the + classification metadata is standardised. + + Adding a classification system will not add the entire hierarchy of + references available in the classification. References need to be added + separately. Typically, you'd only add the references that you use in + your project, see ifcopenshell.api.classification.add_reference for more + information. + + :param classification: If a string is provided, it is assumed to be the + name of your classification system. This is necessary if you are + creating your own custom classification system. Alternatively, you + may provide an entity_instance of an IfcClassification from an IFC + classification library. The latter approach is preferred if you are + using a commonly known system such as Uniclass, as this will ensure + all metadata is added correctly. + :type classification: str,ifcopenshell.entity_instance.entity_instance + :return: The added IfcClassification element + :rtype: ifcopenshell.entity_instance.entity_instance + + Example:: + + # Option 1: adding a custom clasification from scratch + ifcopenshell.api.run("classification.add_classification", model, + classification="MyCustomClassification") + + # Option 2: adding a popular classification from a library + library = ifcopenshell.open("/path/to/Uniclass.ifc") + classification = library.by_type("IfcClassification")[0] + ifcopenshell.api.run("classification.add_classification", model, + classification=classification) + """ self.file = file self.settings = { - "classification": None, + "classification": classification, } - for key, value in settings.items(): - self.settings[key] = value def execute(self): if isinstance(self.settings["classification"], str): diff --git a/src/ifcopenshell-python/ifcopenshell/api/classification/add_reference.py b/src/ifcopenshell-python/ifcopenshell/api/classification/add_reference.py index 1f34ac4dc1..55fd2ee5de 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/classification/add_reference.py +++ b/src/ifcopenshell-python/ifcopenshell/api/classification/add_reference.py @@ -21,18 +21,99 @@ import ifcopenshell.util.schema class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, product=None, reference=None, identification=None, name=None, classification=None, is_lightweight=True): + """Adds a new classification reference and assigns it to a product + + A classification reference is a single entry such as "Pr_12_23_34" that + is part of an external classification system (such as Uniclass or + Omniclass). + + References can be added to almost any object in IFC, including physical + objects, object types, properties, tasks, costs, resources, or even + resources such as profiles, documents, libraries, and so on. + + Classification references can be added in two ways. Option 1) specify a + custom arbitrary reference, where you have the manually specify the + identification (e.g. "Pr_12_23_45") and name (e.g. "Door Products"). + Option 2) add a reference from an IFC classification library. The latter + is preferred if you are using a common classification system such as + Uniclass, as the library will be prepopulated with all the valid + classifications already. + + Objects are allowed to have multiple classification references from + multiple classification systems. This means that adding a new reference + will not remove existing references. + + References can be inherited from types. This means that if an + IfcWallType has a classification reference of Pr_12_23_34, then all + IfcWall occurrences of that type automatically get the same + classification of Pr_12_23_34. This means that it is more efficient to + assign to types where possible. If a classification reference is + assigned to both the type and an occurrence, then the assignment at the + occurrence will override the type classification. + + :param product: The IFC object, property, or resource you want to + associate the classification reference to. + :type product: ifcopenshell.entity_instance.entity_instance + :param reference: The classification reference entity taken from an + IFC classification library. If you supply this parameter, you will + use option 2. + :type product: ifcopenshell.entity_instance.entity_instance, optional + :param identification: If you choose option 1 and do not specify a + reference, you may manually specify an identification code. The code + is typically a short identifier and may have punctuation to separate + the levels of hierarchy in the classificaion (e.g. Pr_12_23_34). + :type identification: str, optional + :param name: If you choose option 1 and do not specify a reference, you + may manually specify a name. The name is typically human readable. + :type name: str, optional + :param classification: The IfcClassification entity in your IFC model + (not the library, if you are doing option 2) that the reference is + part of. + :type product: ifcopenshell.entity_instance.entity_instance + :param is_lightweight: If you are doing option 2, choose whether or not + to only add that particular reference (lighweight) or also add all + of its parent references in the classification hierarchy (not + lighweight). For example, adding a lightweight reference to + Pr_12_23_34 will only add Pr_12_23_34, but adding a heavy reference + to Pr_12_23_34 will also add Pr_12_23 and Pr_12. These parent + references merely help describe the "tree" of classifications, but + is generally unnecessary. Using lightweight classifications are + recommended and is the default. + :type is_lightweight: bool, optional + :return: The newly added IfcClassificationReference + :rtype: ifcopenshell.entity_instance.entity_instance + + Example:: + + # Option 1: adding and assigning a new reference from scratch + wall_type = model.by_type("IfcWallType")[0] + classification = ifcopenshell.api.run("classification.add_classification", + model, classification="MyCustomClassification") + ifcopenshell.api.run("classification.add_reference", model, + product=wall_type, classification=classification, + identification="W_01", name="Interior Walls") + + # Option 2: adding a popular classification from a library + library = ifcopenshell.open("/path/to/Uniclass.ifc") + lib_classification = library.by_type("IfcClassification")[0] + classification = ifcopenshell.api.run("classification.add_classification", + model, classification=lib_classification) + reference = [r for r in library.by_type("IfcClassificationReference") + if r.Identification == "XYZ"][0] + ifcopenshell.api.run("classification.add_reference", model, + product=wall_type, classification=classification, + reference=reference) + """ self.file = file self.settings = { - "product": None, - "reference": None, - "identification": None, - "name": None, - "classification": None, - "is_lightweight": True, + "product": product, + "reference": reference, + "identification": identification, + "name": name, + "classification": classification, + "is_lightweight": is_lightweight, } - for key, value in settings.items(): - self.settings[key] = value def execute(self): self.is_rooted = self.settings["product"].is_a("IfcRoot") diff --git a/src/ifcopenshell-python/ifcopenshell/api/classification/edit_classification.py b/src/ifcopenshell-python/ifcopenshell/api/classification/edit_classification.py index 812b35df92..2e8ad38ae9 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/classification/edit_classification.py +++ b/src/ifcopenshell-python/ifcopenshell/api/classification/edit_classification.py @@ -18,11 +18,28 @@ class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, classification=None, attributes=None): + """Edits the attributes of an IfcClassification + + For more information about the attributes and data types of an + IfcClassification, consult the IFC documentation. + + :param classification: The IfcClassification entity you want to edit + :type classification: ifcopenshell.entity_instance.entity_instance + :param attributes: a dictionary of attribute names and values. + :type attributes: dict, optional + :return: None + :rtype: None + + Example:: + + classification = model.by_type("IfcClassification")[0] + # Change the name of the classification system to "Foo" + ifcopenshell.api.run("classification.edit_classification", model, + classification=classification, attributes={"Name": "Foo"}) + """ self.file = file - self.settings = {"classification": None, "attributes": {}} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"classification": classification, "attributes": attributes or {}} def execute(self): for name, value in self.settings["attributes"].items(): diff --git a/src/ifcopenshell-python/ifcopenshell/api/classification/edit_reference.py b/src/ifcopenshell-python/ifcopenshell/api/classification/edit_reference.py index 342b1fbad2..a483c0c6a8 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/classification/edit_reference.py +++ b/src/ifcopenshell-python/ifcopenshell/api/classification/edit_reference.py @@ -18,11 +18,28 @@ class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, reference=None, attributes=None): + """Edits the attributes of an IfcClassificationReference + + For more information about the attributes and data types of an + IfcClassificationReference, consult the IFC documentation. + + :param reference: The IfcClassificationReference entity you want to edit + :type reference: ifcopenshell.entity_instance.entity_instance + :param attributes: a dictionary of attribute names and values. + :type attributes: dict, optional + :return: None + :rtype: None + + Example:: + + reference = model.by_type("IfcClassification")[0] + # Change the name of the reference to "Foo" + ifcopenshell.api.run("classification.edit_reference", model, + reference=reference, attributes={"Name": "Foo"}) + """ self.file = file - self.settings = {"reference": None, "attributes": {}} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"reference": reference, "attributes": attributes or {}} def execute(self): for name, value in self.settings["attributes"].items(): diff --git a/src/ifcopenshell-python/ifcopenshell/api/classification/remove_classification.py b/src/ifcopenshell-python/ifcopenshell/api/classification/remove_classification.py index cc49343318..1eae029413 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/classification/remove_classification.py +++ b/src/ifcopenshell-python/ifcopenshell/api/classification/remove_classification.py @@ -18,11 +18,27 @@ class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, classifcation=None): + """Removes an IfcClassification from the project and all references + + The classification and all of its relationships, children references, + and relationships between objectse and child references are completely + removed from a project. + + :param classification: The IfcClassification entity you want to remove + :type classification: ifcopenshell.entity_instance.entity_instance + :return: None + :rtype: None + + Example:: + + classification = model.by_type("IfcClassification")[0] + ifcopenshell.api.run("classification.remove_classification", model, + classification=classification) + """ + self.file = file - self.settings = {"classification": None} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"classification": classification} def execute(self): references = self.get_references(self.settings["classification"]) diff --git a/src/ifcopenshell-python/ifcopenshell/api/classification/remove_reference.py b/src/ifcopenshell-python/ifcopenshell/api/classification/remove_reference.py index 9d80660a12..9ff9cd22a9 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/classification/remove_reference.py +++ b/src/ifcopenshell-python/ifcopenshell/api/classification/remove_reference.py @@ -18,11 +18,34 @@ class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, reference=None, product=None): + """Removes a classification reference from a product + + If the classification reference is no longer associated to any products, + the classification reference itself is also removed. + + :param reference: The IfcClassificationReference entity of the + relationship you want to remove. + :type reference: ifcopenshell.entity_instance.entity_instance + :param product: The object entity of the relationship you want to + remove. + :type reference: ifcopenshell.entity_instance.entity_instance + :return: None + :rtype: None + + Example:: + + wall_type = model.by_type("IfcWallType")[0] + classification = ifcopenshell.api.run("classification.add_classification", + model, classification="MyCustomClassification") + reference = ifcopenshell.api.run("classification.add_reference", model, + product=wall_type, classification=classification, + identification="W_01", name="Interior Walls") + ifcopenshell.api.run("classification.remove_reference", model, + reference=reference, product=wall_type) + """ self.file = file - self.settings = {"reference": None, "product": None} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"reference": reference, "product": product} def execute(self): if self.settings["product"].is_a("IfcRoot"):