diff --git a/src/ifcopenshell-python/ifcopenshell/api/unit/add_context_dependent_unit.py b/src/ifcopenshell-python/ifcopenshell/api/unit/add_context_dependent_unit.py index 3e73b91f9e..9eedfa3570 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/unit/add_context_dependent_unit.py +++ b/src/ifcopenshell-python/ifcopenshell/api/unit/add_context_dependent_unit.py @@ -18,11 +18,40 @@ class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, unit_type="USERDEFINED", name="THINGAMAJIG", dimensions=None): + """Add a new arbitrary unit that can only be interpreted in a project specific context + + Occasionally the construction industry uses arbitrary units to quantify + objects, like "pairs" of door hardware, "palettes" or "boxes" of fixings + or equipment. + + :param unit_type: Typically should be left as USERDEFINED, unless for + some bizarre reason you are redefining something you could use a + sensible normal unit for. In that case, firstly stop whatever you're + doing and have a hard think about your life, and then if life really + is going that badly for you, check out the IFC docs for IfcUnitEnum. + :type unit_type: str + :param name: Give your unit a name. X what? X bananas? + :type name: str + :param dimensions: Units typically measure one of 7 fundamental physical + dimensions: length, mass, time, electric current, temperature, + substance amount, or luminous intensity. These are represented as a + list of 7 integers, representing the exponents of each one of these + dimensions. For example, a length unit is (1, 0, 0, 0, 0, 0, 0), + where as an area unit is (2, 0, 0, 0, 0, 0, 0). A unit of meters per + second is (1, 0, -1, 0, 0, 0, 0). For context dependent units, it is + recommended to leave this as the default of (0, 0, 0, 0, 0, 0, 0). + :type dimensions: list[int] + :return: The new IfcContextDependentUnit + :rtype: ifcopenshell.entity_instance.entity_instance + + Example:: + + # Boxes of things + ifcopenshell.api.run("unit.add_context_dependent_unit", model, name="BOXES") + """ self.file = file - self.settings = {"unit_type": "USERDEFINED", "name": "THINGAMAJIG", "dimensions": (0, 0, 0, 0, 0, 0, 0)} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"unit_type": unit_type, "name": name, "dimensions": dimensions or (0, 0, 0, 0, 0, 0, 0)} def execute(self): return self.file.create_entity( diff --git a/src/ifcopenshell-python/ifcopenshell/api/unit/add_conversion_based_unit.py b/src/ifcopenshell-python/ifcopenshell/api/unit/add_conversion_based_unit.py index e916f450b9..2a854eece2 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/unit/add_conversion_based_unit.py +++ b/src/ifcopenshell-python/ifcopenshell/api/unit/add_conversion_based_unit.py @@ -21,11 +21,42 @@ import ifcopenshell.util.unit class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, name="foot", conversion_offset=None): + """Add a conversion based unit + + If you're in one of those countries who don't use SI units, you're + probably simply using SI units converted into another unit. If you want + to use _those_ units, you can create a conversion based unit with this + function. You can choose from one of: inch, foot, yard, mile, square + inch, square foot, square yard, acre, square mile, cubic inch, cubic + foot, cubic yard, litre, fluid ounce UK, fluid ounce US, pint UK, pint + US, gallon UK, gallon US, degree, ounce, pound, ton UK, ton US, lbf, + kip, psi, ksi, minute, hour, day, btu, and fahrenheit. + + :param name: A converted name chosen from the list above. + :type name: str + :param conversion_offset: If you want to offset the conversion further + by a set number, you may specify it here. For example, fahrenheit is + 1.8 * kelvin - 459.67. The -459.67 is the conversion offset. Note + that this is just an example and you don't actually need to specify + that for fahrenheit as it's built into this API function. For + advanced users only. + :type conversion_offset: float + :return: The new IfcConversionBasedUnit or + IfcConversionBasedUnitWithOffset + :rtype: ifcopenshell.entity_instance.entity_instance + + Example:: + + # Some common imperial measurements + length = ifcopenshell.api.run("unit.add_conversion_based_unit", model, name="inch") + area = ifcopenshell.api.run("unit.add_conversion_based_unit", model, name="square foot") + + # Make it our default units, if we are doing an imperial building + ifcopenshell.api.run("unit.assign_unit", model, units=[length, area]) + """ self.file = file - self.settings = {"name": "foot", "conversion_offset": None} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"name": name, "conversion_offset": conversion_offset} def execute(self): unit_type = ifcopenshell.util.unit.imperial_types.get(self.settings["name"], "USERDEFINED") diff --git a/src/ifcopenshell-python/ifcopenshell/api/unit/add_monetary_unit.py b/src/ifcopenshell-python/ifcopenshell/api/unit/add_monetary_unit.py index d853166c01..924f03c819 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/unit/add_monetary_unit.py +++ b/src/ifcopenshell-python/ifcopenshell/api/unit/add_monetary_unit.py @@ -18,11 +18,29 @@ class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, currency="DOLLARYDOO"): + """Add a new currency + + Currency units are useful in cost plans to know in what currency the + costs are calculated in. The currencies should follow ISO 4217, like + USD, GBP, AUD, MYR, etc. + + :param currency: The currency code + :type currency: str + :return: The newly created IfcMonetaryUnit + :rtype: ifcopenshell.entity_instance.entity_instance + + Example:: + + # If you do all your cost plans in Zimbabwean dollars then nobody + # knows how accurate the numbers are. + zwl = ifcopenshell.api.run("unit.add_monetary_unit", model, currency="ZWL") + + # Make it our default currency + ifcopenshell.api.run("unit.assign_unit", model, units=[zwl]) + """ self.file = file - self.settings = {"currency": "DOLLARYDOO"} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"currency": currency} def execute(self): return self.file.create_entity("IfcMonetaryUnit", self.settings["currency"]) diff --git a/src/ifcopenshell-python/ifcopenshell/api/unit/add_si_unit.py b/src/ifcopenshell-python/ifcopenshell/api/unit/add_si_unit.py index ff8a86670c..1f0aac575a 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/unit/add_si_unit.py +++ b/src/ifcopenshell-python/ifcopenshell/api/unit/add_si_unit.py @@ -16,15 +16,49 @@ # You should have received a copy of the GNU Lesser General Public License # along with IfcOpenShell. If not, see . +import ifcopenshell.util.unit + class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, unit_type="LENGTHUNIT", prefix=None): + """Add a new SI unit + + The supported types are ABSORBEDDOSEUNIT, AMOUNTOFSUBSTANCEUNIT, + AREAUNIT, DOSEEQUIVALENTUNIT, ELECTRICCAPACITANCEUNIT, + ELECTRICCHARGEUNIT, ELECTRICCONDUCTANCEUNIT, ELECTRICCURRENTUNIT, + ELECTRICRESISTANCEUNIT, ELECTRICVOLTAGEUNIT, ENERGYUNIT, FORCEUNIT, + FREQUENCYUNIT, ILLUMINANCEUNIT, INDUCTANCEUNIT, LENGTHUNIT, + LUMINOUSFLUXUNIT, LUMINOUSINTENSITYUNIT, MAGNETICFLUXDENSITYUNIT, + MAGNETICFLUXUNIT, MASSUNIT, PLANEANGLEUNIT, POWERUNIT, PRESSUREUNIT, + RADIOACTIVITYUNIT, SOLIDANGLEUNIT, THERMODYNAMICTEMPERATUREUNIT, + TIMEUNIT, VOLUMEUNIT. + + Prefixes supported are ATTO, CENTI, DECA, DECI, EXA, FEMTO, GIGA, HECTO, + KILO, MEGA, MICRO, MILLI, NANO, PETA, PICO, TERA. + + :param unit_type: A type of unit chosen from the list above. For + example, choosing LENGTHUNIT will give you a metre. + :type unit_type: str + :param prefix: A prefix chosen from the list above, or None for no + prefix. + :type prefix: str,optional + :return: The newly created IfcSIUnit + :rtype: ifcopenshell.entity_instance.entity_instance + + Example:: + + # Millimeters and square meters + length = ifcopenshell.api.run("unit.add_si_unit", model, unit_type="LENGTHUNIT", prefix="MILLI") + area = ifcopenshell.api.run("unit.add_si_unit", model, unit_type="AREAUNIT") + + # Make it our default units, if we are doing a metric building + ifcopenshell.api.run("unit.assign_unit", model, units=[length, area]) + """ self.file = file - self.settings = {"unit_type": "LENGTHUNIT", "name": "METRE", "prefix": None} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"unit_type": unit_type, "prefix": prefix} def execute(self): + name = ifcopenshell.util.unit.si_type_names.get(self.settings["unit_type"], None) return self.file.create_entity( - "IfcSIUnit", UnitType=self.settings["unit_type"], Name=self.settings["name"], Prefix=self.settings["prefix"] + "IfcSIUnit", UnitType=self.settings["unit_type"], Name=name, Prefix=self.settings["prefix"] ) diff --git a/src/ifcopenshell-python/ifcopenshell/api/unit/assign_unit.py b/src/ifcopenshell-python/ifcopenshell/api/unit/assign_unit.py index 86a911088d..1fcad6e839 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/unit/assign_unit.py +++ b/src/ifcopenshell-python/ifcopenshell/api/unit/assign_unit.py @@ -21,7 +21,43 @@ import ifcopenshell.util.unit class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, units=None, length=None, area=None, volume=None): + """Assign default project units + + Whenever a unitised quantity is specified, such as a length, area, + voltage, pressure, etc, these project units are used by default. + + It is also possible to override units for specific properties. For + example, generally you might want square metres for area measurements, + but you might want square millimeters for the measurements of the cross + sectional area of cables in cable trays. However, this function only + deals with the default project units. + + :param units: A list of units to assign as project defaults. See + ifcopenshell.api.unit.add_si_unit, unit.add_conversion_based_unit, + and unit.add_monetary_unit for information on how to create units. + :type units: list[ifcopenshell.entity_instance.entity_instance],optional + :return: The IfcUnitAssignment element + :rtype: ifcopenshell.entity_instance.entity_instance + + Example:: + + # You need a project before you can assign units. + ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcProject") + + # Millimeters and square meters + length = ifcopenshell.api.run("unit.add_si_unit", model, unit_type="LENGTHUNIT", prefix="MILLI") + area = ifcopenshell.api.run("unit.add_si_unit", model, unit_type="AREAUNIT") + + # Make it our default units, if we are doing a metric building + ifcopenshell.api.run("unit.assign_unit", model, units=[length, area]) + + # Alternatively, you may specify without any arguments to + # automatically create millimeters, square meters, and cubic meters + # as a convenience for testing purposes. Sorry imperial folks, we + # prioritise metric here. + ifcopenshell.api.run("unit.assign_unit", model) + """ self.file = file self.settings = { "units": None, @@ -29,8 +65,6 @@ class Usecase: "area": {"is_metric": True, "raw": "METERS"}, "volume": {"is_metric": True, "raw": "METERS"}, } - for key, value in settings.items(): - self.settings[key] = value def execute(self): # We're going to refactor this to split unit creation and assignment diff --git a/src/ifcopenshell-python/ifcopenshell/api/unit/edit_derived_unit.py b/src/ifcopenshell-python/ifcopenshell/api/unit/edit_derived_unit.py index b15bdcd1dd..d3a3c47fe5 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/unit/edit_derived_unit.py +++ b/src/ifcopenshell-python/ifcopenshell/api/unit/edit_derived_unit.py @@ -18,11 +18,21 @@ class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, unit=None, attributes=None): + """Edits the attributes of an IfcDerivedUnit + + For more information about the attributes and data types of an + IfcDerivedUnit, consult the IFC documentation. + + :param unit: The IfcDerivedUnit entity you want to edit + :type unit: ifcopenshell.entity_instance.entity_instance + :param attributes: a dictionary of attribute names and values. + :type attributes: dict, optional + :return: None + :rtype: None + """ self.file = file - self.settings = {"unit": None, "attributes": {}} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"unit": unit, "attributes": attributes or {}} def execute(self): for name, value in self.settings["attributes"].items(): diff --git a/src/ifcopenshell-python/ifcopenshell/api/unit/edit_monetary_unit.py b/src/ifcopenshell-python/ifcopenshell/api/unit/edit_monetary_unit.py index b15bdcd1dd..1862d1322a 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/unit/edit_monetary_unit.py +++ b/src/ifcopenshell-python/ifcopenshell/api/unit/edit_monetary_unit.py @@ -18,11 +18,30 @@ class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, unit=None, attributes=None): + """Edits the attributes of an IfcMonetaryUnit + + For more information about the attributes and data types of an + IfcMonetaryUnit, consult the IFC documentation. + + :param unit: The IfcMonetaryUnit entity you want to edit + :type unit: ifcopenshell.entity_instance.entity_instance + :param attributes: a dictionary of attribute names and values. + :type attributes: dict, optional + :return: None + :rtype: None + + Example:: + + # If you do all your cost plans in Zimbabwean dollars then nobody + # knows how accurate the numbers are. + zwl = ifcopenshell.api.run("unit.add_monetary_unit", model, currency="ZWL") + + # Ah who are we kidding + ifcopenshell.api.run("unit.edit_monetary_unit", model, unit=zwl, attributes={"Currency": "USD"}) + """ self.file = file - self.settings = {"unit": None, "attributes": {}} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"unit": unit, "attributes": attributes or {}} def execute(self): for name, value in self.settings["attributes"].items(): diff --git a/src/ifcopenshell-python/ifcopenshell/api/unit/edit_named_unit.py b/src/ifcopenshell-python/ifcopenshell/api/unit/edit_named_unit.py index f5fd8cbae0..f064ed9280 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/unit/edit_named_unit.py +++ b/src/ifcopenshell-python/ifcopenshell/api/unit/edit_named_unit.py @@ -18,11 +18,32 @@ class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, unit=None, attributes=None): + """Edits the attributes of an IfcNamedUnit + + Named units include SI units, conversion based units (imperial units), + and context dependent units. + + For more information about the attributes and data types of an + IfcNamedUnit, consult the IFC documentation. + + :param unit: The IfcNamedUnit entity you want to edit + :type unit: ifcopenshell.entity_instance.entity_instance + :param attributes: a dictionary of attribute names and values. + :type attributes: dict, optional + :return: None + :rtype: None + + Example:: + + # Boxes of things + unit = ifcopenshell.api.run("unit.add_context_dependent_unit", model, name="BOXES") + + # Uh, crates? Boxes? Whatever. + ifcopenshell.api.run("unit.edit_named_unit", model, unit=unit, attibutes={"Name": "CRATES"}) + """ self.file = file - self.settings = {"unit": None, "attributes": {}} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"unit": unit, "attributes": attributes or {}} def execute(self): for name, value in self.settings["attributes"].items(): diff --git a/src/ifcopenshell-python/ifcopenshell/api/unit/remove_unit.py b/src/ifcopenshell-python/ifcopenshell/api/unit/remove_unit.py index b68176cfc4..03fc0d96da 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/unit/remove_unit.py +++ b/src/ifcopenshell-python/ifcopenshell/api/unit/remove_unit.py @@ -21,11 +21,27 @@ import ifcopenshell.util.element class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, unit=None): + """Remove a unit + + Be very careful when a unit is removed, as it may mean that previously + defined quantities in the model completely lose their meaning. + + :param unit: The unit element to remove + :type unit: ifcopenshell.entity_instance.entity_instance + :return: None + :rtype: None + + Example:: + + # What? + unit = ifcopenshell.api.run("unit.add_context_dependent_unit", model, name="HANDFULS") + + # Yeah maybe not. + ifcopenshell.api.run("unit.remove_unit", model, unit=unit) + """ self.file = file - self.settings = {"unit": None} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"unit": unit} def execute(self): unit_assignment = ifcopenshell.util.unit.get_unit_assignment(self.file) diff --git a/src/ifcopenshell-python/ifcopenshell/api/unit/unassign_unit.py b/src/ifcopenshell-python/ifcopenshell/api/unit/unassign_unit.py index b9ab09491a..3a851ac013 100644 --- a/src/ifcopenshell-python/ifcopenshell/api/unit/unassign_unit.py +++ b/src/ifcopenshell-python/ifcopenshell/api/unit/unassign_unit.py @@ -18,11 +18,31 @@ class Usecase: - def __init__(self, file, **settings): + def __init__(self, file, units=None): + """Unassigns units as default units for the project + + :param units: A list of units to assign as project defaults. + :type units: list[ifcopenshell.entity_instance.entity_instance],optional + :return: None + :rtype: None + + Example:: + + # You need a project before you can assign units. + ifcopenshell.api.run("root.create_entity", model, ifc_class="IfcProject") + + # Millimeters and square meters + length = ifcopenshell.api.run("unit.add_si_unit", model, unit_type="LENGTHUNIT", prefix="MILLI") + area = ifcopenshell.api.run("unit.add_si_unit", model, unit_type="AREAUNIT") + + # Make it our default units, if we are doing a metric building + ifcopenshell.api.run("unit.assign_unit", model, units=[length, area]) + + # Actually, we don't need areas. + ifcopenshell.api.run("unit.unassign_unit", model, units=[area]) + """ self.file = file - self.settings = {"units": None} - for key, value in settings.items(): - self.settings[key] = value + self.settings = {"units": units} def execute(self): unit_assignment = self.file.by_type("IfcUnitAssignment")