Convert units to project settings when guessing quantities

This commit is contained in:
Dion Moult
2020-08-08 16:31:27 +10:00
parent 7d976b1bc7
commit 11a66ee181
3 changed files with 102 additions and 2 deletions
@@ -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
@@ -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'
@@ -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