diff --git a/src/blenderbim/blenderbim/bim/module/pset/operator.py b/src/blenderbim/blenderbim/bim/module/pset/operator.py index d4b371e670..2fa01640eb 100644 --- a/src/blenderbim/blenderbim/bim/module/pset/operator.py +++ b/src/blenderbim/blenderbim/bim/module/pset/operator.py @@ -381,11 +381,19 @@ class CalculateQuantity(bpy.types.Operator): self.qto_calculator = QtoCalculator() obj = context.active_object prop = obj.PsetProperties.properties.get(self.prop) - prop.metadata.float_value = self.calculate_quantity(obj, context) + quantity = self.calculate_quantity(obj, context) + + if quantity is None: + self.report({"ERROR"}, "Could not calculate quantity") + return {"CANCELLED"} + + prop.metadata.float_value = quantity return {"FINISHED"} def calculate_quantity(self, obj, context): quantity = self.qto_calculator.calculate_quantity(obj.PsetProperties.active_pset_name, self.prop, obj) + if quantity is None: + return return round(quantity, 3) @@ -404,35 +412,7 @@ class GuessQuantity(bpy.types.Operator): def guess_quantity(self, obj, context): quantity = self.qto_calculator.guess_quantity(self.prop, [p.name for p in obj.PsetProperties.properties], obj) - if "area" in self.prop.lower(): - if context.scene.BIMProperties.area_unit: - prefix, name = self.get_prefix_name(context.scene.BIMProperties.area_unit) - quantity = ifcopenshell.util.unit.convert(quantity, None, "SQUARE_METRE", prefix, name) - elif "volume" in self.prop.lower(): - if context.scene.BIMProperties.volume_unit: - prefix, name = self.get_prefix_name(context.scene.BIMProperties.volume_unit) - quantity = ifcopenshell.util.unit.convert(quantity, None, "CUBIC_METRE", prefix, name) - else: - prefix, name = self.get_blender_prefix_name(context) - quantity = ifcopenshell.util.unit.convert(quantity, None, "METRE", prefix, name) - return round(quantity, 3) - - def get_prefix_name(self, value): - if "/" in value: - return value.split("/") - return None, value - - def get_blender_prefix_name(self, context): - unit_settings = context.scene.unit_settings - if unit_settings.system == "IMPERIAL": - if unit_settings.length_unit == "INCHES": - return None, "inch" - elif unit_settings.length_unit == "FEET": - return None, "foot" - elif unit_settings.system == "METRIC": - if unit_settings.length_unit == "METERS": - return None, "METRE" - return unit_settings.length_unit[0 : -len("METERS")], "METRE" + return round(quantity, 3) if quantity is not None else None class CopyPropertyToSelection(bpy.types.Operator, Operator): diff --git a/src/blenderbim/blenderbim/bim/module/pset/qto_calculator.py b/src/blenderbim/blenderbim/bim/module/pset/qto_calculator.py index f08a36006e..2452708fbe 100644 --- a/src/blenderbim/blenderbim/bim/module/pset/qto_calculator.py +++ b/src/blenderbim/blenderbim/bim/module/pset/qto_calculator.py @@ -59,30 +59,48 @@ class QtoCalculator: return tool.Qto.convert_to_project_units(value, qto_name, quantity_name) or value def guess_quantity(self, prop_name, alternative_prop_names, obj): + """guess the value of the quantity by name, returns the value in the project units""" prop_name = prop_name.lower() alternative_prop_names = [p.lower() for p in alternative_prop_names] + value = None if "length" in prop_name and "width" not in alternative_prop_names and "height" not in alternative_prop_names: - return self.get_linear_length(obj) + value = self.get_linear_length(obj) elif "length" in prop_name: - return self.get_length(obj) + value = self.get_length(obj) elif "width" in prop_name and "length" not in alternative_prop_names: - return self.get_length(obj) + value = self.get_length(obj) elif "width" in prop_name: - return self.get_width(obj) + value = self.get_width(obj) elif "height" in prop_name or "depth" in prop_name: - return self.get_height(obj) + value = self.get_height(obj) elif "perimeter" in prop_name: - return self.get_net_perimeter(obj) + value = self.get_net_perimeter(obj) elif "area" in prop_name and ("footprint" in prop_name or "section" in prop_name or "floor" in prop_name): - return self.get_net_footprint_area(obj) + value = self.get_net_footprint_area(obj) elif "area" in prop_name and "side" in prop_name: - return self.get_side_area(obj) + value = self.get_side_area(obj) elif "area" in prop_name: - return self.get_gross_surface_area(obj) + value = self.get_gross_surface_area(obj) elif "volume" in prop_name and "gross" in prop_name: - return self.get_gross_volume(obj) + value = self.get_gross_volume(obj) elif "volume" in prop_name: - return self.get_net_volume(obj) + value = self.get_net_volume(obj) + + if value is None: + return + + unit_type_keywords = { + "length": "Q_LENGTH", + "width": "Q_LENGTH", + "height": "Q_LENGTH", + "depth": "Q_LENGTH", + "perimeter": "Q_LENGTH", + "area": "Q_AREA", + "volume": "Q_VOLUME", + } + + unit_type = next(unit_type_keywords[k] for k in unit_type_keywords if k in prop_name) + return tool.Qto.convert_to_project_units(value, quantity_type=unit_type) or value def get_units(self, o, vg_index): return len([v for v in o.data.vertices if vg_index in [g.group for g in v.groups]]) diff --git a/src/blenderbim/blenderbim/tool/qto.py b/src/blenderbim/blenderbim/tool/qto.py index 762ceb3c5d..60ec399fec 100644 --- a/src/blenderbim/blenderbim/tool/qto.py +++ b/src/blenderbim/blenderbim/tool/qto.py @@ -90,7 +90,8 @@ class Qto(blenderbim.core.tool.Qto): return { quantity_name: cls.get_rounded_value(calculator.calculate_quantity(qto_name, quantity_name, obj)) for quantity_name in cls.get_applicable_quantity_names(qto_name) or [] - if cls.has_calculator(qto_name, quantity_name) and calculator.calculate_quantity(qto_name, quantity_name, obj) is not None + if cls.has_calculator(qto_name, quantity_name) + and calculator.calculate_quantity(qto_name, quantity_name, obj) is not None } @classmethod @@ -98,16 +99,22 @@ class Qto(blenderbim.core.tool.Qto): return bool(mapper.get(qto_name, {}).get(quantity_name, None)) @classmethod - def convert_to_project_units(cls, value, qto_name, quantity_name): + def convert_to_project_units(cls, value, qto_name=None, quantity_name=None, quantity_type=None): + """You can either specify `quantity_type` or provide `qto_name/quantity_name` + to let method figure the `quantity_type` from the templates + + `quantity_type` values are `Q_LENGTH`, `Q_AREA`, `Q_VOLUME` + """ ifc_file = tool.Ifc.get() quantity_to_unit_types = { "Q_LENGTH": ("LENGTHUNIT", "METRE"), "Q_AREA": ("AREAUNIT", "SQUARE_METRE"), "Q_VOLUME": ("VOLUMEUNIT", "CUBIC_METRE"), } + if not quantity_type: + qt = blenderbim.bim.schema.ifc.psetqto.get_by_name(qto_name) + quantity_type = next(q.TemplateType for q in qt.HasPropertyTemplates if q.Name == quantity_name) - qt = blenderbim.bim.schema.ifc.psetqto.get_by_name(qto_name) - quantity_type = next(q.TemplateType for q in qt.HasPropertyTemplates if q.Name == quantity_name) unit_type = quantity_to_unit_types.get(quantity_type, None) if not unit_type: return @@ -125,7 +132,6 @@ class Qto(blenderbim.core.tool.Qto): ) return value - @classmethod def get_guessed_quantities(cls, obj, pset_qto_properties): calculated_quantities = {}