diff --git a/src/ifcblenderexport/blenderbim/bim/helper.py b/src/ifcblenderexport/blenderbim/bim/helper.py index aa00fc0273..a58f66c019 100644 --- a/src/ifcblenderexport/blenderbim/bim/helper.py +++ b/src/ifcblenderexport/blenderbim/bim/helper.py @@ -1,5 +1,7 @@ import math +# TODO: Deprecate this in favour of ifcopenshell.util.unit + class SIUnitHelper: prefixes = {"EXA": 1e18, "PETA": 1e15, "TERA": 1e12, "GIGA": 1e9, "MEGA": 1e6, "KILO": 1e3, "HECTO": 1e2, "DECA": 1e1, "DECI": 1e-1, "CENTI": @@ -64,3 +66,38 @@ class SIUnitHelper: for name in SIUnitHelper.unit_names: if name in text.upper().replace('METER', 'METRE'): return name + + @staticmethod + def convert(value, from_prefix, from_unit, to_prefix, to_unit): + """Converts between length, area, and volume units + + :param value: The numeric value you want to convert + :type value: float + :param from_prefix: A prefix from IfcSIPrefix. Can be None. + :type from_prefix: string + :param from_unit: IfcSIUnitName or IfcConversionBasedUnit.Name + :type from_unit: string + :param to_prefix: A prefix from IfcSIPrefix. Can be None. + :type to_prefix: string + :param to_unit: IfcSIUnitName or IfcConversionBasedUnit.Name + :type to_unit: string + """ + if from_unit in SIUnitHelper.si_conversions: + value *= SIUnitHelper.si_conversions[from_unit] + elif from_prefix: + value *= SIUnitHelper.get_prefix_multiplier(from_prefix) + if 'SQUARE' in from_unit: + value *= SIUnitHelper.get_prefix_multiplier(from_prefix) + elif 'CUBIC' in from_unit: + value *= SIUnitHelper.get_prefix_multiplier(from_prefix) + value *= SIUnitHelper.get_prefix_multiplier(from_prefix) + if to_unit in SIUnitHelper.si_conversions: + return value * (1 / SIUnitHelper.si_conversions[to_unit]) + elif to_prefix: + value *= (1 / SIUnitHelper.get_prefix_multiplier(to_prefix)) + if 'SQUARE' in from_unit: + value *= (1 / SIUnitHelper.get_prefix_multiplier(to_prefix)) + elif 'CUBIC' in from_unit: + value *= (1 / SIUnitHelper.get_prefix_multiplier(to_prefix)) + value *= (1 / SIUnitHelper.get_prefix_multiplier(to_prefix)) + return value diff --git a/src/ifcblenderexport/blenderbim/bim/operator.py b/src/ifcblenderexport/blenderbim/bim/operator.py index 457943f5d1..5fbab67e31 100644 --- a/src/ifcblenderexport/blenderbim/bim/operator.py +++ b/src/ifcblenderexport/blenderbim/bim/operator.py @@ -16,6 +16,7 @@ from . import schema from . import bcf from . import ifc from . import annotation +from . import helper from bpy_extras.io_utils import ImportHelper from itertools import cycle from mathutils import Vector, Matrix, Euler @@ -3245,10 +3246,38 @@ class GuessQuantity(bpy.types.Operator): qto_calculator = qto.QtoCalculator() props = bpy.context.active_object.BIMObjectProperties.qtos[self.qto_index].properties prop = props[self.prop_index] - prop.string_value = str(round(qto_calculator.guess_quantity( - prop.name, [p.name for p in props], bpy.context.active_object), 3)) + quantity = qto_calculator.guess_quantity( + prop.name, [p.name for p in props], bpy.context.active_object) + if 'area' in prop.name.lower(): + if bpy.context.scene.BIMProperties.area_unit: + prefix, name = self.get_prefix_name(bpy.context.scene.BIMProperties.area_unit) + quantity = helper.SIUnitHelper.convert(quantity, None, 'SQUARE_METRE', prefix, name) + elif 'volume' in prop.name.lower(): + if bpy.context.scene.BIMProperties.volume_unit: + prefix, name = self.get_prefix_name(bpy.context.scene.BIMProperties.volume_unit) + quantity = helper.SIUnitHelper.convert(quantity, None, 'CUBIC_METRE', prefix, name) + else: + prefix, name = self.get_blender_prefix_name() + quantity = helper.SIUnitHelper.convert(quantity, None, 'METRE', prefix, name) + prop.string_value = str(round(quantity, 3)) return {'FINISHED'} + def get_prefix_name(self, value): + if '/' in value: + return value.split('/') + return None, bpy.context.scene.BIMProperties.area_unit + + def get_blender_prefix_name(self): + if bpy.context.scene.unit_settings.system == 'IMPERIAL': + if bpy.context.scene.unit_settings.length_unit == 'INCHES': + return None, 'inch' + elif bpy.context.scene.unit_settings.length_unit == 'FEET': + return None, 'foot' + elif bpy.context.scene.unit_settings.system == 'METRIC': + if bpy.context.scene.unit_settings.length_unit == 'METERS': + return None, 'METRE' + return bpy.context.scene.unit_settings.length_unit[0:-len('METERS')], 'METRE' + class ExecuteBIMTester(bpy.types.Operator): bl_idname = 'bim.execute_bim_tester' diff --git a/src/ifcopenshell-python/ifcopenshell/util/unit.py b/src/ifcopenshell-python/ifcopenshell/util/unit.py index 42687afdee..a001b085d5 100644 --- a/src/ifcopenshell-python/ifcopenshell/util/unit.py +++ b/src/ifcopenshell-python/ifcopenshell/util/unit.py @@ -62,3 +62,37 @@ def get_unit_name(text): for name in unit_names: if name in text.upper().replace('METER', 'METRE'): return name + +def convert(value, from_prefix, from_unit, to_prefix, to_unit): + """Converts between length, area, and volume units + + :param value: The numeric value you want to convert + :type value: float + :param from_prefix: A prefix from IfcSIPrefix. Can be None. + :type from_prefix: string + :param from_unit: IfcSIUnitName or IfcConversionBasedUnit.Name + :type from_unit: string + :param to_prefix: A prefix from IfcSIPrefix. Can be None. + :type to_prefix: string + :param to_unit: IfcSIUnitName or IfcConversionBasedUnit.Name + :type to_unit: string + """ + if from_unit in si_conversions: + value *= si_conversions[from_unit] + elif from_prefix: + value *= get_prefix_multiplier(from_prefix) + if 'SQUARE' in from_unit: + value *= get_prefix_multiplier(from_prefix) + elif 'CUBIC' in from_unit: + value *= get_prefix_multiplier(from_prefix) + value *= get_prefix_multiplier(from_prefix) + if to_unit in si_conversions: + return value * (1 / si_conversions[to_unit]) + elif to_prefix: + value *= (1 / get_prefix_multiplier(to_prefix)) + if 'SQUARE' in from_unit: + value *= (1 / get_prefix_multiplier(to_prefix)) + elif 'CUBIC' in from_unit: + value *= (1 / get_prefix_multiplier(to_prefix)) + value *= (1 / get_prefix_multiplier(to_prefix)) + return value