mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-25 17:57:02 +00:00
New usecase for adding conversion based units
This commit is contained in:
@@ -27,6 +27,8 @@ import addon_utils
|
|||||||
import ifcopenshell
|
import ifcopenshell
|
||||||
import ifcopenshell.api
|
import ifcopenshell.api
|
||||||
import ifcopenshell.util.placement
|
import ifcopenshell.util.placement
|
||||||
|
import blenderbim.tool as tool
|
||||||
|
import blenderbim.core.style
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
|
|
||||||
|
|
||||||
@@ -105,7 +107,7 @@ class IfcExporter:
|
|||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
if isinstance(obj, bpy.types.Material):
|
if isinstance(obj, bpy.types.Material):
|
||||||
bpy.ops.bim.update_style_colours(material=obj.name)
|
blenderbim.core.style.update_style_colours(tool.Ifc, tool.Style, obj=obj)
|
||||||
else:
|
else:
|
||||||
bpy.ops.bim.update_representation(obj=obj.name)
|
bpy.ops.bim.update_representation(obj=obj.name)
|
||||||
except ReferenceError:
|
except ReferenceError:
|
||||||
|
|||||||
@@ -97,5 +97,5 @@ class AddAggregate(bpy.types.Operator):
|
|||||||
aggregate = bpy.data.objects.new("Assembly", None)
|
aggregate = bpy.data.objects.new("Assembly", None)
|
||||||
aggregate_collection.objects.link(aggregate)
|
aggregate_collection.objects.link(aggregate)
|
||||||
bpy.ops.bim.assign_class(obj=aggregate.name, ifc_class="IfcElementAssembly")
|
bpy.ops.bim.assign_class(obj=aggregate.name, ifc_class="IfcElementAssembly")
|
||||||
bpy.ops.bim.assign_object(related_object=obj.name, relating_object=aggregate.name)
|
core.assign_object(tool.Ifc, tool.Aggregate, tool.Collector, relating_obj=aggregate, related_obj=obj)
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import ifcopenshell.util.representation
|
|||||||
import logging
|
import logging
|
||||||
import ifcopenshell.api
|
import ifcopenshell.api
|
||||||
import blenderbim.core.geometry as core
|
import blenderbim.core.geometry as core
|
||||||
|
import blenderbim.core.style
|
||||||
import blenderbim.tool as tool
|
import blenderbim.tool as tool
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from blenderbim.bim import import_ifc
|
from blenderbim.bim import import_ifc
|
||||||
@@ -108,7 +109,7 @@ class AddRepresentation(bpy.types.Operator):
|
|||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
[
|
[
|
||||||
bpy.ops.bim.add_style(material=s.material.name)
|
blenderbim.core.style.add_style(tool.Ifc, tool.Style, obj=s.material)
|
||||||
for s in obj.material_slots
|
for s in obj.material_slots
|
||||||
if s.material and not s.material.BIMMaterialProperties.ifc_style_id
|
if s.material and not s.material.BIMMaterialProperties.ifc_style_id
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ class CreateProject(bpy.types.Operator):
|
|||||||
building_storey = bpy.data.objects.new(self.get_name("IfcBuildingStorey", "My Storey"), None)
|
building_storey = bpy.data.objects.new(self.get_name("IfcBuildingStorey", "My Storey"), None)
|
||||||
|
|
||||||
bpy.ops.bim.assign_class(obj=project.name, ifc_class="IfcProject")
|
bpy.ops.bim.assign_class(obj=project.name, ifc_class="IfcProject")
|
||||||
bpy.ops.bim.assign_unit()
|
blenderbim.core.unit.assign_scene_units(tool.Ifc, tool.Unit)
|
||||||
|
|
||||||
model = blenderbim.core.context.add_context(
|
model = blenderbim.core.context.add_context(
|
||||||
tool.Ifc, context_type="Model", context_identifier="", target_view="", parent=0
|
tool.Ifc, context_type="Model", context_identifier="", target_view="", parent=0
|
||||||
|
|||||||
@@ -64,4 +64,4 @@ class SpatialData:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def is_directly_contained(cls):
|
def is_directly_contained(cls):
|
||||||
return bool(getattr(tool.Ifc.get_entity(bpy.context.active_object), "ContainedInStructure"))
|
return bool(getattr(tool.Ifc.get_entity(bpy.context.active_object), "ContainedInStructure", False))
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import bpy
|
|||||||
from . import ui, prop, operator
|
from . import ui, prop, operator
|
||||||
|
|
||||||
classes = (
|
classes = (
|
||||||
|
operator.AssignSceneUnits,
|
||||||
operator.AssignUnit,
|
operator.AssignUnit,
|
||||||
operator.UnassignUnit,
|
operator.UnassignUnit,
|
||||||
operator.LoadUnits,
|
operator.LoadUnits,
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||||
|
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
|
||||||
|
#
|
||||||
|
# This file is part of BlenderBIM Add-on.
|
||||||
|
#
|
||||||
|
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import blenderbim.tool as tool
|
||||||
|
|
||||||
|
|
||||||
|
def refresh():
|
||||||
|
UnitsData.is_loaded = False
|
||||||
|
|
||||||
|
|
||||||
|
class UnitsData:
|
||||||
|
data = {}
|
||||||
|
is_loaded = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load(cls):
|
||||||
|
cls.data = {"total_units": cls.get_total_units()}
|
||||||
|
cls.is_loaded = True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_total_units(cls):
|
||||||
|
ifc = tool.Ifc.get()
|
||||||
|
return len(ifc.by_type("IfcDerivedUnit") + ifc.by_type("IfcNamedUnit") + ifc.by_type("IfcMonetaryUnit"))
|
||||||
@@ -21,274 +21,131 @@ import json
|
|||||||
import ifcopenshell.api
|
import ifcopenshell.api
|
||||||
import ifcopenshell.util.unit
|
import ifcopenshell.util.unit
|
||||||
import blenderbim.bim.helper
|
import blenderbim.bim.helper
|
||||||
|
import blenderbim.bim.handler
|
||||||
|
import blenderbim.tool as tool
|
||||||
|
import blenderbim.core.unit as core
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from ifcopenshell.api.unit.data import Data
|
from ifcopenshell.api.unit.data import Data
|
||||||
|
|
||||||
|
|
||||||
class AssignUnit(bpy.types.Operator):
|
class Operator:
|
||||||
|
def execute(self, context):
|
||||||
|
IfcStore.execute_ifc_operator(self, context)
|
||||||
|
blenderbim.bim.handler.refresh_ui_data
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
|
||||||
|
class AssignSceneUnits(bpy.types.Operator, Operator):
|
||||||
|
bl_idname = "bim.assign_scene_units"
|
||||||
|
bl_label = "Assign Scene Units"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
|
core.assign_scene_units(tool.Ifc, tool.Unit)
|
||||||
|
|
||||||
|
|
||||||
|
class AssignUnit(bpy.types.Operator, Operator):
|
||||||
bl_idname = "bim.assign_unit"
|
bl_idname = "bim.assign_unit"
|
||||||
bl_label = "Assign Unit"
|
bl_label = "Assign Unit"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
unit: bpy.props.IntProperty()
|
unit: bpy.props.IntProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
|
||||||
return IfcStore.execute_ifc_operator(self, context)
|
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
self.file = IfcStore.get_file()
|
core.assign_unit(tool.Ifc, tool.Unit, unit=tool.Ifc.get().by_id(self.unit))
|
||||||
if self.unit:
|
|
||||||
ifcopenshell.api.run("unit.assign_unit", self.file, units=[self.file.by_id(self.unit)])
|
|
||||||
else:
|
|
||||||
ifcopenshell.api.run("unit.assign_unit", self.file, **self.get_units(context))
|
|
||||||
Data.load(self.file)
|
|
||||||
if self.unit:
|
|
||||||
bpy.ops.bim.load_units()
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
def get_units(self, context):
|
|
||||||
scene = context.scene
|
|
||||||
units = {
|
|
||||||
"length": {
|
|
||||||
"ifc": None,
|
|
||||||
"is_metric": scene.unit_settings.system != "IMPERIAL",
|
|
||||||
"raw": scene.unit_settings.length_unit,
|
|
||||||
},
|
|
||||||
"area": {
|
|
||||||
"ifc": None,
|
|
||||||
"is_metric": scene.unit_settings.system != "IMPERIAL",
|
|
||||||
"raw": scene.unit_settings.length_unit,
|
|
||||||
},
|
|
||||||
"volume": {
|
|
||||||
"ifc": None,
|
|
||||||
"is_metric": scene.unit_settings.system != "IMPERIAL",
|
|
||||||
"raw": scene.unit_settings.length_unit,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for data in units.values():
|
|
||||||
if data["raw"] == "ADAPTIVE":
|
|
||||||
if data["is_metric"]:
|
|
||||||
data["raw"] = "METERS"
|
|
||||||
else:
|
|
||||||
data["raw"] = "FEET"
|
|
||||||
return units
|
|
||||||
|
|
||||||
|
|
||||||
class UnassignUnit(bpy.types.Operator):
|
class UnassignUnit(bpy.types.Operator, Operator):
|
||||||
bl_idname = "bim.unassign_unit"
|
bl_idname = "bim.unassign_unit"
|
||||||
bl_label = "Unassign Unit"
|
bl_label = "Unassign Unit"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
unit: bpy.props.IntProperty()
|
unit: bpy.props.IntProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
|
||||||
return IfcStore.execute_ifc_operator(self, context)
|
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
self.file = IfcStore.get_file()
|
core.unassign_unit(tool.Ifc, tool.Unit, unit=tool.Ifc.get().by_id(self.unit))
|
||||||
ifcopenshell.api.run("unit.unassign_unit", IfcStore.get_file(), units=[self.file.by_id(self.unit)])
|
|
||||||
Data.load(self.file)
|
|
||||||
bpy.ops.bim.load_units()
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
|
|
||||||
class LoadUnits(bpy.types.Operator):
|
class LoadUnits(bpy.types.Operator, Operator):
|
||||||
bl_idname = "bim.load_units"
|
bl_idname = "bim.load_units"
|
||||||
bl_label = "Load Units"
|
bl_label = "Load Units"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
def execute(self, context):
|
def _execute(self, context):
|
||||||
props = context.scene.BIMUnitProperties
|
core.load_units(tool.Unit)
|
||||||
props.units.clear()
|
|
||||||
|
|
||||||
for ifc_definition_id, unit in Data.units.items():
|
|
||||||
name = unit.get("Name", "")
|
|
||||||
|
|
||||||
if unit["type"] == "IfcMonetaryUnit":
|
|
||||||
name = unit["Currency"]
|
|
||||||
|
|
||||||
if unit["type"] == "IfcSIUnit" and unit["Prefix"]:
|
|
||||||
if "_" in name:
|
|
||||||
name_components = name.split("_")
|
|
||||||
name = f"{name_components[0]} {unit['Prefix']}{name_components[1]}"
|
|
||||||
else:
|
|
||||||
name = f"{unit['Prefix']}{name}"
|
|
||||||
|
|
||||||
icon = "MOD_MESHDEFORM"
|
|
||||||
if unit["type"] == "IfcSIUnit":
|
|
||||||
icon = "SNAP_GRID"
|
|
||||||
elif unit["type"] == "IfcMonetaryUnit":
|
|
||||||
icon = "COPY_ID"
|
|
||||||
|
|
||||||
unit_type = unit.get("UserDefinedType", None)
|
|
||||||
if not unit_type:
|
|
||||||
unit_type = unit.get("UnitType", None)
|
|
||||||
if unit["type"] == "IfcMonetaryUnit":
|
|
||||||
unit_type = "CURRENCY"
|
|
||||||
|
|
||||||
new = props.units.add()
|
|
||||||
new.ifc_definition_id = ifc_definition_id
|
|
||||||
new.name = name
|
|
||||||
new.unit_type = unit_type
|
|
||||||
new.is_assigned = ifc_definition_id in Data.unit_assignment
|
|
||||||
new.icon = icon
|
|
||||||
|
|
||||||
props.is_editing = True
|
|
||||||
bpy.ops.bim.disable_editing_unit()
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
|
|
||||||
class DisableUnitEditingUI(bpy.types.Operator):
|
class DisableUnitEditingUI(bpy.types.Operator, Operator):
|
||||||
bl_idname = "bim.disable_unit_editing_ui"
|
bl_idname = "bim.disable_unit_editing_ui"
|
||||||
bl_label = "Disable Unit Editing UI"
|
bl_label = "Disable Unit Editing UI"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
def execute(self, context):
|
def _execute(self, context):
|
||||||
context.scene.BIMUnitProperties.is_editing = False
|
core.disable_unit_editing_ui(tool.Unit)
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
|
|
||||||
class RemoveUnit(bpy.types.Operator):
|
class RemoveUnit(bpy.types.Operator, Operator):
|
||||||
bl_idname = "bim.remove_unit"
|
bl_idname = "bim.remove_unit"
|
||||||
bl_label = "Remove Unit"
|
bl_label = "Remove Unit"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
unit: bpy.props.IntProperty()
|
unit: bpy.props.IntProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
|
||||||
return IfcStore.execute_ifc_operator(self, context)
|
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
props = context.scene.BIMUnitProperties
|
core.remove_unit(tool.Ifc, tool.Unit, unit=tool.Ifc.get().by_id(self.unit))
|
||||||
self.file = IfcStore.get_file()
|
|
||||||
ifcopenshell.api.run("unit.remove_unit", self.file, **{"unit": self.file.by_id(self.unit)})
|
|
||||||
Data.load(self.file)
|
|
||||||
bpy.ops.bim.load_units()
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
|
|
||||||
class AddMonetaryUnit(bpy.types.Operator):
|
class AddMonetaryUnit(bpy.types.Operator, Operator):
|
||||||
bl_idname = "bim.add_monetary_unit"
|
bl_idname = "bim.add_monetary_unit"
|
||||||
bl_label = "Add Monetary Unit"
|
bl_label = "Add Monetary Unit"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
def execute(self, context):
|
|
||||||
return IfcStore.execute_ifc_operator(self, context)
|
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
props = context.scene.BIMUnitProperties
|
core.add_monetary_unit(tool.Ifc, tool.Unit)
|
||||||
self.file = IfcStore.get_file()
|
|
||||||
ifcopenshell.api.run("unit.add_monetary_unit", self.file)
|
|
||||||
Data.load(self.file)
|
|
||||||
bpy.ops.bim.load_units()
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
|
|
||||||
class AddSIUnit(bpy.types.Operator):
|
class AddSIUnit(bpy.types.Operator, Operator):
|
||||||
bl_idname = "bim.add_si_unit"
|
bl_idname = "bim.add_si_unit"
|
||||||
bl_label = "Add SI Unit"
|
bl_label = "Add SI Unit"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
unit_type: bpy.props.StringProperty()
|
||||||
def execute(self, context):
|
|
||||||
return IfcStore.execute_ifc_operator(self, context)
|
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
props = context.scene.BIMUnitProperties
|
core.add_si_unit(tool.Ifc, tool.Unit, unit_type=self.unit_type)
|
||||||
self.file = IfcStore.get_file()
|
|
||||||
ifcopenshell.api.run(
|
|
||||||
"unit.add_si_unit",
|
|
||||||
self.file,
|
|
||||||
unit_type=props.named_unit_types,
|
|
||||||
name=ifcopenshell.util.unit.si_type_names[props.named_unit_types],
|
|
||||||
)
|
|
||||||
Data.load(self.file)
|
|
||||||
bpy.ops.bim.load_units()
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
|
|
||||||
class AddContextDependentUnit(bpy.types.Operator):
|
class AddContextDependentUnit(bpy.types.Operator, Operator):
|
||||||
bl_idname = "bim.add_context_dependent_unit"
|
bl_idname = "bim.add_context_dependent_unit"
|
||||||
bl_label = "Add Context Dependent Unit"
|
bl_label = "Add Context Dependent Unit"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
name: bpy.props.StringProperty()
|
||||||
def execute(self, context):
|
unit_type: bpy.props.StringProperty()
|
||||||
return IfcStore.execute_ifc_operator(self, context)
|
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
props = context.scene.BIMUnitProperties
|
core.add_context_dependent_unit(tool.Ifc, tool.Unit, unit_type=self.unit_type, name=self.name)
|
||||||
self.file = IfcStore.get_file()
|
|
||||||
ifcopenshell.api.run(
|
|
||||||
"unit.add_context_dependent_unit", self.file, unit_type=props.named_unit_types, name="THINGAMAJIG"
|
|
||||||
)
|
|
||||||
Data.load(self.file)
|
|
||||||
bpy.ops.bim.load_units()
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
|
|
||||||
class EnableEditingUnit(bpy.types.Operator):
|
class EnableEditingUnit(bpy.types.Operator, Operator):
|
||||||
bl_idname = "bim.enable_editing_unit"
|
bl_idname = "bim.enable_editing_unit"
|
||||||
bl_label = "Enable Editing Unit"
|
bl_label = "Enable Editing Unit"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
unit: bpy.props.IntProperty()
|
unit: bpy.props.IntProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
def _execute(self, context):
|
||||||
props = context.scene.BIMUnitProperties
|
core.enable_editing_unit(tool.Unit, unit=tool.Ifc.get().by_id(self.unit))
|
||||||
props.unit_attributes.clear()
|
|
||||||
data = Data.units[self.unit]
|
|
||||||
blenderbim.bim.helper.import_attributes(
|
|
||||||
data["type"],
|
|
||||||
props.unit_attributes,
|
|
||||||
data,
|
|
||||||
lambda name, prop, data: self.import_attributes(name, prop, data, context),
|
|
||||||
)
|
|
||||||
props.active_unit_id = self.unit
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
def import_attributes(self, name, prop, data, context):
|
|
||||||
if name == "Dimensions" and data["type"] != "IfcSIUnit":
|
|
||||||
new = context.scene.BIMUnitProperties.unit_attributes.add()
|
|
||||||
new.name = name
|
|
||||||
new.is_null = data[name] is None
|
|
||||||
new.is_optional = False
|
|
||||||
new.data_type = "string"
|
|
||||||
new.string_value = json.dumps([e for e in IfcStore.get_file().by_id(data["id"]).Dimensions])
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
class DisableEditingUnit(bpy.types.Operator):
|
class DisableEditingUnit(bpy.types.Operator, Operator):
|
||||||
bl_idname = "bim.disable_editing_unit"
|
bl_idname = "bim.disable_editing_unit"
|
||||||
bl_label = "Disable Editing Unit"
|
bl_label = "Disable Editing Unit"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
|
||||||
def execute(self, context):
|
def _execute(self, context):
|
||||||
context.scene.BIMUnitProperties.active_unit_id = 0
|
core.disable_editing_unit(tool.Unit)
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
|
|
||||||
class EditUnit(bpy.types.Operator):
|
class EditUnit(bpy.types.Operator, Operator):
|
||||||
bl_idname = "bim.edit_unit"
|
bl_idname = "bim.edit_unit"
|
||||||
bl_label = "Edit Unit"
|
bl_label = "Edit Unit"
|
||||||
bl_options = {"REGISTER", "UNDO"}
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
unit: bpy.props.IntProperty()
|
||||||
def execute(self, context):
|
|
||||||
return IfcStore.execute_ifc_operator(self, context)
|
|
||||||
|
|
||||||
def _execute(self, context):
|
def _execute(self, context):
|
||||||
props = context.scene.BIMUnitProperties
|
core.edit_unit(tool.Ifc, tool.Unit, unit=tool.Ifc.get().by_id(self.unit))
|
||||||
attributes = blenderbim.bim.helper.export_attributes(props.unit_attributes, self.export_attributes)
|
|
||||||
self.file = IfcStore.get_file()
|
|
||||||
unit = self.file.by_id(props.active_unit_id)
|
|
||||||
if unit.is_a("IfcMonetaryUnit"):
|
|
||||||
ifcopenshell.api.run("unit.edit_monetary_unit", self.file, **{"unit": unit, "attributes": attributes})
|
|
||||||
elif unit.is_a("IfcDerivedUnit"):
|
|
||||||
ifcopenshell.api.run("unit.edit_derived_unit", self.file, **{"unit": unit, "attributes": attributes})
|
|
||||||
elif unit.is_a("IfcNamedUnit"):
|
|
||||||
ifcopenshell.api.run("unit.edit_named_unit", self.file, **{"unit": unit, "attributes": attributes})
|
|
||||||
Data.load(IfcStore.get_file())
|
|
||||||
bpy.ops.bim.load_units()
|
|
||||||
return {"FINISHED"}
|
|
||||||
|
|
||||||
def export_attributes(self, attributes, prop):
|
|
||||||
if prop.name == "Dimensions":
|
|
||||||
try:
|
|
||||||
attributes[prop.name] = json.loads(prop.get_value())
|
|
||||||
except:
|
|
||||||
attributes[prop.name] = (0, 0, 0, 0, 0, 0, 0)
|
|
||||||
return True
|
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ class Unit(PropertyGroup):
|
|||||||
name: StringProperty(name="Name")
|
name: StringProperty(name="Name")
|
||||||
unit_type: StringProperty(name="Unit Type")
|
unit_type: StringProperty(name="Unit Type")
|
||||||
is_assigned: BoolProperty(name="Is Assigned")
|
is_assigned: BoolProperty(name="Is Assigned")
|
||||||
icon: StringProperty(name="Icon")
|
ifc_class: StringProperty(name="IFC Class")
|
||||||
ifc_definition_id: IntProperty(name="IFC Definition ID")
|
ifc_definition_id: IntProperty(name="IFC Definition ID")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
import blenderbim.bim.helper
|
import blenderbim.bim.helper
|
||||||
from bpy.types import Panel, UIList
|
from bpy.types import Panel, UIList
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from ifcopenshell.api.unit.data import Data
|
from blenderbim.bim.module.unit.data import UnitsData
|
||||||
|
|
||||||
|
|
||||||
class BIM_PT_units(Panel):
|
class BIM_PT_units(Panel):
|
||||||
@@ -36,13 +36,13 @@ class BIM_PT_units(Panel):
|
|||||||
return file
|
return file
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
self.file = IfcStore.get_file()
|
if not UnitsData.is_loaded:
|
||||||
if not Data.is_loaded:
|
UnitsData.load()
|
||||||
Data.load(self.file)
|
|
||||||
self.props = context.scene.BIMUnitProperties
|
self.props = context.scene.BIMUnitProperties
|
||||||
|
|
||||||
row = self.layout.row(align=True)
|
row = self.layout.row(align=True)
|
||||||
row.label(text="{} Units Found".format(len(Data.units)), icon="SNAP_GRID")
|
row.label(text="{} Units Found".format(UnitsData.data["total_units"]), icon="SNAP_GRID")
|
||||||
if self.props.is_editing:
|
if self.props.is_editing:
|
||||||
row.operator("bim.disable_unit_editing_ui", text="", icon="CANCEL")
|
row.operator("bim.disable_unit_editing_ui", text="", icon="CANCEL")
|
||||||
else:
|
else:
|
||||||
@@ -60,10 +60,13 @@ class BIM_PT_units(Panel):
|
|||||||
pass # TODO
|
pass # TODO
|
||||||
elif self.props.unit_classes == "IfcSIUnit":
|
elif self.props.unit_classes == "IfcSIUnit":
|
||||||
row.prop(self.props, "named_unit_types", text="")
|
row.prop(self.props, "named_unit_types", text="")
|
||||||
row.operator("bim.add_si_unit", text="", icon="ADD")
|
op = row.operator("bim.add_si_unit", text="", icon="ADD")
|
||||||
|
op.unit_type = self.props.named_unit_types
|
||||||
elif self.props.unit_classes == "IfcContextDependentUnit":
|
elif self.props.unit_classes == "IfcContextDependentUnit":
|
||||||
row.prop(self.props, "named_unit_types", text="")
|
row.prop(self.props, "named_unit_types", text="")
|
||||||
row.operator("bim.add_context_dependent_unit", text="", icon="ADD")
|
op = row.operator("bim.add_context_dependent_unit", text="", icon="ADD")
|
||||||
|
op.name = "THINGAMAJIG"
|
||||||
|
op.unit_type = self.props.named_unit_types
|
||||||
|
|
||||||
self.layout.template_list(
|
self.layout.template_list(
|
||||||
"BIM_UL_units",
|
"BIM_UL_units",
|
||||||
@@ -85,8 +88,14 @@ class BIM_UL_units(UIList):
|
|||||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
|
||||||
props = context.scene.BIMUnitProperties
|
props = context.scene.BIMUnitProperties
|
||||||
if item:
|
if item:
|
||||||
|
icon = "MOD_MESHDEFORM"
|
||||||
|
if item.ifc_class == "IfcSIUnit":
|
||||||
|
icon = "SNAP_GRID"
|
||||||
|
elif item.ifc_class == "IfcMonetaryUnit":
|
||||||
|
icon = "COPY_ID"
|
||||||
|
|
||||||
row = layout.row(align=True)
|
row = layout.row(align=True)
|
||||||
row.label(text=item.unit_type or "No Type", icon=item.icon)
|
row.label(text=item.unit_type or "No Type", icon=icon)
|
||||||
row.label(text=item.name or "Unnamed")
|
row.label(text=item.name or "Unnamed")
|
||||||
|
|
||||||
if item.is_assigned:
|
if item.is_assigned:
|
||||||
|
|||||||
@@ -130,6 +130,22 @@ class Surveyor:
|
|||||||
def get_absolute_matrix(cls, obj): pass
|
def get_absolute_matrix(cls, obj): pass
|
||||||
|
|
||||||
|
|
||||||
|
@interface
|
||||||
|
class Unit:
|
||||||
|
def clear_active_unit(cls): pass
|
||||||
|
def disable_editing_units(cls): pass
|
||||||
|
def enable_editing_units(cls): pass
|
||||||
|
def export_unit_attributes(cls): pass
|
||||||
|
def get_scene_unit_name(cls, unit_type): pass
|
||||||
|
def get_scene_unit_si_prefix(cls): pass
|
||||||
|
def get_si_name_from_unit_type(cls, unit_type): pass
|
||||||
|
def get_unit_class(cls, unit): pass
|
||||||
|
def import_unit_attributes(cls, unit): pass
|
||||||
|
def import_units(cls): pass
|
||||||
|
def is_scene_unit_metric(cls): pass
|
||||||
|
def set_active_unit(cls, unit): pass
|
||||||
|
|
||||||
|
|
||||||
@interface
|
@interface
|
||||||
class Voider:
|
class Voider:
|
||||||
def can_void(cls, opening, element): pass
|
def can_void(cls, opening, element): pass
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||||
|
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
|
||||||
|
#
|
||||||
|
# This file is part of BlenderBIM Add-on.
|
||||||
|
#
|
||||||
|
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
def assign_scene_units(ifc, unit):
|
||||||
|
length_name = unit.get_scene_unit_name("length")
|
||||||
|
area_name = unit.get_scene_unit_name("area")
|
||||||
|
volume_name = unit.get_scene_unit_name("volume")
|
||||||
|
|
||||||
|
if unit.is_scene_unit_metric():
|
||||||
|
prefix = unit.get_scene_unit_si_prefix()
|
||||||
|
lengthunit = ifc.run("unit.add_si_unit", unit_type="LENGTHUNIT", name=length_name, prefix=prefix)
|
||||||
|
areaunit = ifc.run("unit.add_si_unit", unit_type="AREAUNIT", name=area_name, prefix=prefix)
|
||||||
|
volumeunit = ifc.run("unit.add_si_unit", unit_type="VOLUMEUNIT", name=volume_name, prefix=prefix)
|
||||||
|
else:
|
||||||
|
lengthunit = ifc.run("unit.add_conversion_based_unit", name=length_name)
|
||||||
|
areaunit = ifc.run("unit.add_conversion_based_unit", name=area_name)
|
||||||
|
volumeunit = ifc.run("unit.add_conversion_based_unit", name=volume_name)
|
||||||
|
|
||||||
|
ifc.run("unit.assign_unit", units=[lengthunit, areaunit, volumeunit])
|
||||||
|
|
||||||
|
|
||||||
|
def assign_unit(ifc, unit_tool, unit=None):
|
||||||
|
ifc.run("unit.assign_unit", units=[unit])
|
||||||
|
unit_tool.import_units()
|
||||||
|
|
||||||
|
|
||||||
|
def unassign_unit(ifc, unit_tool, unit=None):
|
||||||
|
ifc.run("unit.unassign_unit", units=[unit])
|
||||||
|
unit_tool.import_units()
|
||||||
|
|
||||||
|
|
||||||
|
def load_units(unit):
|
||||||
|
unit.import_units()
|
||||||
|
unit.enable_editing_units()
|
||||||
|
|
||||||
|
|
||||||
|
def disable_unit_editing_ui(unit):
|
||||||
|
unit.disable_editing_units()
|
||||||
|
|
||||||
|
|
||||||
|
def remove_unit(ifc, unit_tool, unit=None):
|
||||||
|
ifc.run("unit.remove_unit", unit=unit)
|
||||||
|
unit_tool.import_units()
|
||||||
|
|
||||||
|
|
||||||
|
def add_monetary_unit(ifc, unit):
|
||||||
|
result = ifc.run("unit.add_monetary_unit")
|
||||||
|
unit.import_units()
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def add_si_unit(ifc, unit, unit_type=None):
|
||||||
|
result = ifc.run("unit.add_si_unit", unit_type=unit_type, name=unit.get_si_name_from_unit_type(unit_type))
|
||||||
|
unit.import_units()
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def add_context_dependent_unit(ifc, unit, unit_type=None, name=None):
|
||||||
|
result = ifc.run("unit.add_context_dependent_unit", unit_type=unit_type, name=name)
|
||||||
|
unit.import_units()
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def enable_editing_unit(unit_tool, unit=None):
|
||||||
|
unit_tool.set_active_unit(unit)
|
||||||
|
unit_tool.import_unit_attributes(unit)
|
||||||
|
|
||||||
|
|
||||||
|
def disable_editing_unit(unit):
|
||||||
|
unit.clear_active_unit()
|
||||||
|
|
||||||
|
|
||||||
|
def edit_unit(ifc, unit_tool, unit=None):
|
||||||
|
attributes = unit_tool.export_unit_attributes()
|
||||||
|
unit_class = unit_tool.get_unit_class(unit)
|
||||||
|
if unit_class == "IfcMonetaryUnit":
|
||||||
|
ifc.run("unit.edit_monetary_unit", unit=unit, attributes=attributes)
|
||||||
|
elif unit_class == "IfcDerivedUnit":
|
||||||
|
ifc.run("unit.edit_derived_unit", unit=unit, attributes=attributes)
|
||||||
|
elif unit_class == "IfcNamedUnit":
|
||||||
|
ifc.run("unit.edit_named_unit", unit=unit, attributes=attributes)
|
||||||
|
unit_tool.import_units()
|
||||||
|
unit_tool.clear_active_unit()
|
||||||
@@ -25,3 +25,4 @@ from blenderbim.tool.ifc import Ifc
|
|||||||
from blenderbim.tool.owner import Owner
|
from blenderbim.tool.owner import Owner
|
||||||
from blenderbim.tool.style import Style
|
from blenderbim.tool.style import Style
|
||||||
from blenderbim.tool.surveyor import Surveyor
|
from blenderbim.tool.surveyor import Surveyor
|
||||||
|
from blenderbim.tool.unit import Unit
|
||||||
|
|||||||
@@ -0,0 +1,157 @@
|
|||||||
|
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||||
|
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
|
||||||
|
#
|
||||||
|
# This file is part of BlenderBIM Add-on.
|
||||||
|
#
|
||||||
|
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import bpy
|
||||||
|
import json
|
||||||
|
import ifcopenshell
|
||||||
|
import blenderbim.core.tool
|
||||||
|
import blenderbim.tool as tool
|
||||||
|
|
||||||
|
|
||||||
|
class Unit(blenderbim.core.tool.Unit):
|
||||||
|
@classmethod
|
||||||
|
def clear_active_unit(cls):
|
||||||
|
bpy.context.scene.BIMUnitProperties.active_unit_id = 0
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def disable_editing_units(cls):
|
||||||
|
bpy.context.scene.BIMUnitProperties.is_editing = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def enable_editing_units(cls):
|
||||||
|
bpy.context.scene.BIMUnitProperties.is_editing = True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def export_unit_attributes(cls):
|
||||||
|
def callback(attributes, prop):
|
||||||
|
if prop.name == "Dimensions":
|
||||||
|
try:
|
||||||
|
attributes[prop.name] = json.loads(prop.get_value())
|
||||||
|
except:
|
||||||
|
attributes[prop.name] = (0, 0, 0, 0, 0, 0, 0)
|
||||||
|
return True
|
||||||
|
|
||||||
|
props = bpy.context.scene.BIMUnitProperties
|
||||||
|
return blenderbim.bim.helper.export_attributes(props.unit_attributes, callback=callback)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_scene_unit_name(cls, unit_type):
|
||||||
|
props = bpy.context.scene.unit_settings
|
||||||
|
is_metric = props.system == "METRIC" or props.system == "NONE"
|
||||||
|
|
||||||
|
if is_metric:
|
||||||
|
name = "METRE"
|
||||||
|
elif props.length_unit == "MILES":
|
||||||
|
name = "mile"
|
||||||
|
elif props.length_unit == "FEET" or props.length_unit == "ADAPTIVE":
|
||||||
|
name = "foot"
|
||||||
|
elif props.length_unit == "INCHES":
|
||||||
|
name = "inch"
|
||||||
|
elif props.length_unit == "THOU":
|
||||||
|
name = "thou"
|
||||||
|
|
||||||
|
if unit_type == "length":
|
||||||
|
return name
|
||||||
|
elif unit_type == "area":
|
||||||
|
if is_metric:
|
||||||
|
return f"SQUARE_{name}"
|
||||||
|
return f"square {name}"
|
||||||
|
elif unit_type == "volume":
|
||||||
|
if is_metric:
|
||||||
|
return f"CUBIC_{name}"
|
||||||
|
return f"cubic {name}"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_scene_unit_si_prefix(cls):
|
||||||
|
props = bpy.context.scene.unit_settings
|
||||||
|
if props.length_unit == "ADAPTIVE" or props.length_unit == "METERS":
|
||||||
|
return
|
||||||
|
return props.length_unit.replace("METERS", "")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_si_name_from_unit_type(cls, unit_type):
|
||||||
|
return ifcopenshell.util.unit.si_type_names.get(unit_type, None)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_unit_class(cls, unit):
|
||||||
|
return unit.is_a()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def import_unit_attributes(cls, unit):
|
||||||
|
def callback(name, prop, data):
|
||||||
|
if name == "Dimensions" and data["type"] != "IfcSIUnit":
|
||||||
|
new = bpy.context.scene.BIMUnitProperties.unit_attributes.add()
|
||||||
|
new.name = name
|
||||||
|
new.is_null = data[name] is None
|
||||||
|
new.is_optional = False
|
||||||
|
new.data_type = "string"
|
||||||
|
new.string_value = json.dumps([e for e in tool.Ifc.get().by_id(data["id"]).Dimensions])
|
||||||
|
return True
|
||||||
|
|
||||||
|
props = bpy.context.scene.BIMUnitProperties
|
||||||
|
props.unit_attributes.clear()
|
||||||
|
blenderbim.bim.helper.import_attributes2(unit, props.unit_attributes, callback=callback)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def import_units(cls):
|
||||||
|
props = bpy.context.scene.BIMUnitProperties
|
||||||
|
props.units.clear()
|
||||||
|
|
||||||
|
units = []
|
||||||
|
for unit_class in ["IfcDerivedUnit", "IfcMonetaryUnit", "IfcNamedUnit"]:
|
||||||
|
units += tool.Ifc.get().by_type(unit_class)
|
||||||
|
|
||||||
|
assigned_units = tool.Ifc.get().by_type("IfcUnitAssignment")
|
||||||
|
if assigned_units:
|
||||||
|
assigned_units = assigned_units[0].Units
|
||||||
|
|
||||||
|
for unit in units:
|
||||||
|
name = ""
|
||||||
|
if unit.is_a("IfcMonetaryUnit"):
|
||||||
|
name = unit.Currency
|
||||||
|
elif not unit.is_a("IfcDerivedUnit"):
|
||||||
|
name = unit.Name or ""
|
||||||
|
|
||||||
|
if unit.is_a("IfcSIUnit") and unit.Prefix:
|
||||||
|
if "_" in name:
|
||||||
|
name_components = name.split("_")
|
||||||
|
name = f"{name_components[0]} {unit.Prefix}{name_components[1]}"
|
||||||
|
else:
|
||||||
|
name = f"{unit.Prefix}{name}"
|
||||||
|
|
||||||
|
if unit.is_a("IfcMonetaryUnit"):
|
||||||
|
unit_type = "CURRENCY"
|
||||||
|
else:
|
||||||
|
unit_type = getattr(unit, "UserDefinedType", None)
|
||||||
|
if not unit_type:
|
||||||
|
unit_type = getattr(unit, "UnitType", None)
|
||||||
|
|
||||||
|
new = props.units.add()
|
||||||
|
new.ifc_definition_id = unit.id()
|
||||||
|
new.name = name
|
||||||
|
new.unit_type = unit_type
|
||||||
|
new.is_assigned = unit in assigned_units
|
||||||
|
new.ifc_class = unit.is_a()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def is_scene_unit_metric(cls):
|
||||||
|
return bpy.context.scene.unit_settings.system in ["METRIC", "NONE"]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def set_active_unit(cls, unit):
|
||||||
|
bpy.context.scene.BIMUnitProperties.active_unit_id = unit.id()
|
||||||
@@ -4,6 +4,8 @@ markers =
|
|||||||
context
|
context
|
||||||
geometry
|
geometry
|
||||||
owner
|
owner
|
||||||
void
|
|
||||||
pset_template
|
pset_template
|
||||||
spatial
|
spatial
|
||||||
|
style
|
||||||
|
unit
|
||||||
|
void
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
@unit
|
||||||
|
Feature: Unit
|
||||||
|
|
||||||
|
Scenario: Assign scene units
|
||||||
|
Given an empty IFC project
|
||||||
|
When I press "bim.assign_scene_units"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Assign unit
|
||||||
|
Given an empty IFC project
|
||||||
|
And the variable "unit" is "{ifc}.by_type('IfcSIUnit')[0].id()"
|
||||||
|
When I press "bim.assign_unit(unit={unit})"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Unassign unit
|
||||||
|
Given an empty IFC project
|
||||||
|
And the variable "unit" is "{ifc}.by_type('IfcSIUnit')[0].id()"
|
||||||
|
When I press "bim.unassign_unit(unit={unit})"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Load units
|
||||||
|
Given an empty IFC project
|
||||||
|
When I press "bim.load_units"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Disable unit editing UI
|
||||||
|
Given an empty IFC project
|
||||||
|
And I press "bim.load_units"
|
||||||
|
When I press "bim.disable_unit_editing_ui"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Remove unit
|
||||||
|
Given an empty IFC project
|
||||||
|
And the variable "unit" is "{ifc}.by_type('IfcSIUnit')[0].id()"
|
||||||
|
When I press "bim.remove_unit(unit={unit})"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Add monetary unit
|
||||||
|
Given an empty IFC project
|
||||||
|
When I press "bim.add_monetary_unit"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Add SI unit
|
||||||
|
Given an empty IFC project
|
||||||
|
When I press "bim.add_si_unit(unit_type='LENGTHUNIT')"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Add context dependent unit
|
||||||
|
Given an empty IFC project
|
||||||
|
When I press "bim.add_context_dependent_unit(name='THINGAMAJIGS', unit_type='LENGTHUNIT')"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Enable editing unit
|
||||||
|
Given an empty IFC project
|
||||||
|
And the variable "unit" is "{ifc}.by_type('IfcSIUnit')[0].id()"
|
||||||
|
When I press "bim.enable_editing_unit(unit={unit})"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Disable editing unit
|
||||||
|
Given an empty IFC project
|
||||||
|
And the variable "unit" is "{ifc}.by_type('IfcSIUnit')[0].id()"
|
||||||
|
And I press "bim.enable_editing_unit(unit={unit})"
|
||||||
|
When I press "bim.disable_editing_unit"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Edit unit
|
||||||
|
Given an empty IFC project
|
||||||
|
And the variable "unit" is "{ifc}.by_type('IfcSIUnit')[0].id()"
|
||||||
|
And I press "bim.enable_editing_unit(unit={unit})"
|
||||||
|
When I press "bim.edit_unit(unit={unit})"
|
||||||
|
Then nothing happens
|
||||||
@@ -98,6 +98,13 @@ def container():
|
|||||||
prophet.verify()
|
prophet.verify()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def unit():
|
||||||
|
prophet = Prophecy(blenderbim.core.tool.Unit)
|
||||||
|
yield prophet
|
||||||
|
prophet.verify()
|
||||||
|
|
||||||
|
|
||||||
class Prophecy:
|
class Prophecy:
|
||||||
def __init__(self, cls):
|
def __init__(self, cls):
|
||||||
self.subject = cls
|
self.subject = cls
|
||||||
|
|||||||
@@ -0,0 +1,154 @@
|
|||||||
|
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||||
|
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
|
||||||
|
#
|
||||||
|
# This file is part of BlenderBIM Add-on.
|
||||||
|
#
|
||||||
|
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import blenderbim.core.unit as subject
|
||||||
|
from test.core.bootstrap import ifc, unit
|
||||||
|
|
||||||
|
|
||||||
|
class TestAssignSceneUnits:
|
||||||
|
def test_creating_and_assigning_metric_units(self, ifc, unit):
|
||||||
|
unit.is_scene_unit_metric().should_be_called().will_return(True)
|
||||||
|
unit.get_scene_unit_name("length").should_be_called().will_return("name")
|
||||||
|
unit.get_scene_unit_si_prefix().should_be_called().will_return("prefix")
|
||||||
|
ifc.run(
|
||||||
|
"unit.add_si_unit", unit_type="LENGTHUNIT", name="name", prefix="prefix"
|
||||||
|
).should_be_called().will_return("lengthunit")
|
||||||
|
|
||||||
|
unit.get_scene_unit_name("area").should_be_called().will_return("name")
|
||||||
|
ifc.run("unit.add_si_unit", unit_type="AREAUNIT", name="name", prefix="prefix").should_be_called().will_return(
|
||||||
|
"areaunit"
|
||||||
|
)
|
||||||
|
|
||||||
|
unit.get_scene_unit_name("volume").should_be_called().will_return("name")
|
||||||
|
ifc.run(
|
||||||
|
"unit.add_si_unit", unit_type="VOLUMEUNIT", name="name", prefix="prefix"
|
||||||
|
).should_be_called().will_return("volumeunit")
|
||||||
|
|
||||||
|
ifc.run("unit.assign_unit", units=["lengthunit", "areaunit", "volumeunit"]).should_be_called()
|
||||||
|
subject.assign_scene_units(ifc, unit)
|
||||||
|
|
||||||
|
def test_creating_and_assigning_imperial_units(self, ifc, unit):
|
||||||
|
unit.is_scene_unit_metric().should_be_called().will_return(False)
|
||||||
|
unit.get_scene_unit_name("length").should_be_called().will_return("lengthname")
|
||||||
|
ifc.run("unit.add_conversion_based_unit", name="lengthname").should_be_called().will_return("lengthunit")
|
||||||
|
|
||||||
|
unit.get_scene_unit_name("area").should_be_called().will_return("areaname")
|
||||||
|
ifc.run("unit.add_conversion_based_unit", name="areaname").should_be_called().will_return("areaunit")
|
||||||
|
|
||||||
|
unit.get_scene_unit_name("volume").should_be_called().will_return("volumename")
|
||||||
|
ifc.run("unit.add_conversion_based_unit", name="volumename").should_be_called().will_return("volumeunit")
|
||||||
|
|
||||||
|
ifc.run("unit.assign_unit", units=["lengthunit", "areaunit", "volumeunit"]).should_be_called()
|
||||||
|
subject.assign_scene_units(ifc, unit)
|
||||||
|
|
||||||
|
|
||||||
|
class TestAssignUnit:
|
||||||
|
def test_run(self, ifc, unit):
|
||||||
|
ifc.run("unit.assign_unit", units=["unit"]).should_be_called()
|
||||||
|
unit.import_units().should_be_called()
|
||||||
|
subject.assign_unit(ifc, unit, unit="unit")
|
||||||
|
|
||||||
|
|
||||||
|
class TestUnassignUnit:
|
||||||
|
def test_run(self, ifc, unit):
|
||||||
|
ifc.run("unit.unassign_unit", units=["unit"]).should_be_called()
|
||||||
|
unit.import_units().should_be_called()
|
||||||
|
subject.unassign_unit(ifc, unit, unit="unit")
|
||||||
|
|
||||||
|
|
||||||
|
class TestLoadUnits:
|
||||||
|
def test_run(self, unit):
|
||||||
|
unit.import_units().should_be_called()
|
||||||
|
unit.enable_editing_units().should_be_called()
|
||||||
|
subject.load_units(unit)
|
||||||
|
|
||||||
|
|
||||||
|
class TestDisableUnitEditingUI:
|
||||||
|
def test_run(self, unit):
|
||||||
|
unit.disable_editing_units().should_be_called()
|
||||||
|
subject.disable_unit_editing_ui(unit)
|
||||||
|
|
||||||
|
|
||||||
|
class TestRemoveUnit:
|
||||||
|
def test_run(self, ifc, unit):
|
||||||
|
ifc.run("unit.remove_unit", unit="unit").should_be_called()
|
||||||
|
unit.import_units().should_be_called()
|
||||||
|
subject.remove_unit(ifc, unit, unit="unit")
|
||||||
|
|
||||||
|
|
||||||
|
class TestAddMonetaryUnit:
|
||||||
|
def test_run(self, ifc, unit):
|
||||||
|
ifc.run("unit.add_monetary_unit").should_be_called().will_return("unit")
|
||||||
|
unit.import_units().should_be_called()
|
||||||
|
assert subject.add_monetary_unit(ifc, unit) == "unit"
|
||||||
|
|
||||||
|
|
||||||
|
class TestAddSIUnit:
|
||||||
|
def test_run(self, ifc, unit):
|
||||||
|
unit.get_si_name_from_unit_type("unit_type").should_be_called().will_return("name")
|
||||||
|
ifc.run("unit.add_si_unit", unit_type="unit_type", name="name").should_be_called().will_return("unit")
|
||||||
|
unit.import_units().should_be_called()
|
||||||
|
assert subject.add_si_unit(ifc, unit, unit_type="unit_type") == "unit"
|
||||||
|
|
||||||
|
|
||||||
|
class TestAddContextDependentUnit:
|
||||||
|
def test_run(self, ifc, unit):
|
||||||
|
ifc.run("unit.add_context_dependent_unit", unit_type="unit_type", name="name").should_be_called().will_return(
|
||||||
|
"unit"
|
||||||
|
)
|
||||||
|
unit.import_units().should_be_called()
|
||||||
|
assert subject.add_context_dependent_unit(ifc, unit, unit_type="unit_type", name="name") == "unit"
|
||||||
|
|
||||||
|
|
||||||
|
class TestEnableEditingUnit:
|
||||||
|
def test_run(self, unit):
|
||||||
|
unit.set_active_unit("unit").should_be_called()
|
||||||
|
unit.import_unit_attributes("unit").should_be_called()
|
||||||
|
subject.enable_editing_unit(unit, unit="unit")
|
||||||
|
|
||||||
|
|
||||||
|
class TestDisableEditingUnit:
|
||||||
|
def test_run(self, unit):
|
||||||
|
unit.clear_active_unit().should_be_called()
|
||||||
|
subject.disable_editing_unit(unit)
|
||||||
|
|
||||||
|
|
||||||
|
class TestEditUnit:
|
||||||
|
def test_editing_monetary_units(self, ifc, unit):
|
||||||
|
unit.export_unit_attributes().should_be_called().will_return("attributes")
|
||||||
|
unit.get_unit_class("unit").should_be_called().will_return("IfcMonetaryUnit")
|
||||||
|
ifc.run("unit.edit_monetary_unit", unit="unit", attributes="attributes").should_be_called()
|
||||||
|
unit.import_units().should_be_called()
|
||||||
|
unit.clear_active_unit().should_be_called()
|
||||||
|
subject.edit_unit(ifc, unit, unit="unit")
|
||||||
|
|
||||||
|
def test_editing_derived_units(self, ifc, unit):
|
||||||
|
unit.export_unit_attributes().should_be_called().will_return("attributes")
|
||||||
|
unit.get_unit_class("unit").should_be_called().will_return("IfcDerivedUnit")
|
||||||
|
ifc.run("unit.edit_derived_unit", unit="unit", attributes="attributes").should_be_called()
|
||||||
|
unit.import_units().should_be_called()
|
||||||
|
unit.clear_active_unit().should_be_called()
|
||||||
|
subject.edit_unit(ifc, unit, unit="unit")
|
||||||
|
|
||||||
|
def test_editing_named_units(self, ifc, unit):
|
||||||
|
unit.export_unit_attributes().should_be_called().will_return("attributes")
|
||||||
|
unit.get_unit_class("unit").should_be_called().will_return("IfcNamedUnit")
|
||||||
|
ifc.run("unit.edit_named_unit", unit="unit", attributes="attributes").should_be_called()
|
||||||
|
unit.import_units().should_be_called()
|
||||||
|
unit.clear_active_unit().should_be_called()
|
||||||
|
subject.edit_unit(ifc, unit, unit="unit")
|
||||||
@@ -0,0 +1,315 @@
|
|||||||
|
# BlenderBIM Add-on - OpenBIM Blender Add-on
|
||||||
|
# Copyright (C) 2021 Dion Moult <dion@thinkmoult.com>
|
||||||
|
#
|
||||||
|
# This file is part of BlenderBIM Add-on.
|
||||||
|
#
|
||||||
|
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# BlenderBIM Add-on is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import bpy
|
||||||
|
import ifcopenshell
|
||||||
|
import blenderbim.core.tool
|
||||||
|
import blenderbim.tool as tool
|
||||||
|
from test.bim.bootstrap import NewFile
|
||||||
|
from blenderbim.tool.unit import Unit as subject
|
||||||
|
|
||||||
|
|
||||||
|
class TestImplementsTool(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
assert isinstance(subject(), blenderbim.core.tool.Unit)
|
||||||
|
|
||||||
|
|
||||||
|
class TestClearActiveUnit(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
bpy.context.scene.BIMUnitProperties.active_unit_id = 1
|
||||||
|
subject.clear_active_unit()
|
||||||
|
assert bpy.context.scene.BIMUnitProperties.active_unit_id == 0
|
||||||
|
|
||||||
|
|
||||||
|
class TestDisableEditingUnits(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
bpy.context.scene.BIMUnitProperties.is_editing = True
|
||||||
|
subject.disable_editing_units()
|
||||||
|
assert bpy.context.scene.BIMUnitProperties.is_editing == False
|
||||||
|
|
||||||
|
|
||||||
|
class TestEnableEditingUnits(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
bpy.context.scene.BIMUnitProperties.is_editing = False
|
||||||
|
subject.enable_editing_units()
|
||||||
|
assert bpy.context.scene.BIMUnitProperties.is_editing == True
|
||||||
|
|
||||||
|
|
||||||
|
class TestExportUnitAttributes(NewFile):
|
||||||
|
def test_exporting_derived_units(self):
|
||||||
|
TestImportUnitAttributes().test_importing_derived_units()
|
||||||
|
assert subject.export_unit_attributes() == {
|
||||||
|
"UnitType": "ANGULARVELOCITYUNIT",
|
||||||
|
"UserDefinedType": "UserDefinedType",
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_exporting_monetary_units(self):
|
||||||
|
TestImportUnitAttributes().test_importing_monetary_units()
|
||||||
|
assert subject.export_unit_attributes() == {"Currency": "Currency"}
|
||||||
|
|
||||||
|
def test_exporting_monetary_units_ifc2x3(self):
|
||||||
|
TestImportUnitAttributes().test_importing_monetary_units_ifc2x3()
|
||||||
|
assert subject.export_unit_attributes() == {"Currency": "USD"}
|
||||||
|
|
||||||
|
def test_exporting_context_dependent_units(self):
|
||||||
|
TestImportUnitAttributes().test_importing_context_dependent_units()
|
||||||
|
assert subject.export_unit_attributes() == {
|
||||||
|
"UnitType": "ABSORBEDDOSEUNIT",
|
||||||
|
"Name": "Name",
|
||||||
|
"Dimensions": [1, 2, 3, 4, 5, 6, 7],
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_exporting_conversion_based_units(self):
|
||||||
|
TestImportUnitAttributes().test_importing_conversion_based_units()
|
||||||
|
assert subject.export_unit_attributes() == {
|
||||||
|
"UnitType": "ABSORBEDDOSEUNIT",
|
||||||
|
"Name": "Name",
|
||||||
|
"Dimensions": [1, 2, 3, 4, 5, 6, 7],
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_exporting_conversion_based_with_offset_units(self):
|
||||||
|
TestImportUnitAttributes().test_importing_conversion_based_with_offset_units()
|
||||||
|
assert subject.export_unit_attributes() == {
|
||||||
|
"UnitType": "ABSORBEDDOSEUNIT",
|
||||||
|
"Name": "Name",
|
||||||
|
"Dimensions": [1, 2, 3, 4, 5, 6, 7],
|
||||||
|
"ConversionOffset": 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_exporting_si_units(self):
|
||||||
|
TestImportUnitAttributes().test_importing_si_units()
|
||||||
|
assert subject.export_unit_attributes() == {"UnitType": "ABSORBEDDOSEUNIT", "Prefix": "EXA", "Name": "AMPERE"}
|
||||||
|
|
||||||
|
|
||||||
|
class TestGetSceneUnitName(NewFile):
|
||||||
|
def test_getting_a_metric_name(self):
|
||||||
|
bpy.context.scene.unit_settings.system = "METRIC"
|
||||||
|
assert subject.get_scene_unit_name("length") == "METRE"
|
||||||
|
assert subject.get_scene_unit_name("area") == "SQUARE_METRE"
|
||||||
|
assert subject.get_scene_unit_name("volume") == "CUBIC_METRE"
|
||||||
|
|
||||||
|
def test_getting_an_imperial_name(self):
|
||||||
|
bpy.context.scene.unit_settings.system = "IMPERIAL"
|
||||||
|
bpy.context.scene.unit_settings.length_unit = "MILES"
|
||||||
|
assert subject.get_scene_unit_name("length") == "mile"
|
||||||
|
assert subject.get_scene_unit_name("area") == "square mile"
|
||||||
|
assert subject.get_scene_unit_name("volume") == "cubic mile"
|
||||||
|
bpy.context.scene.unit_settings.length_unit = "FEET"
|
||||||
|
assert subject.get_scene_unit_name("length") == "foot"
|
||||||
|
assert subject.get_scene_unit_name("area") == "square foot"
|
||||||
|
assert subject.get_scene_unit_name("volume") == "cubic foot"
|
||||||
|
bpy.context.scene.unit_settings.length_unit = "INCHES"
|
||||||
|
assert subject.get_scene_unit_name("length") == "inch"
|
||||||
|
assert subject.get_scene_unit_name("area") == "square inch"
|
||||||
|
assert subject.get_scene_unit_name("volume") == "cubic inch"
|
||||||
|
bpy.context.scene.unit_settings.length_unit = "THOU"
|
||||||
|
assert subject.get_scene_unit_name("length") == "thou"
|
||||||
|
assert subject.get_scene_unit_name("area") == "square thou"
|
||||||
|
assert subject.get_scene_unit_name("volume") == "cubic thou"
|
||||||
|
bpy.context.scene.unit_settings.length_unit = "ADAPTIVE"
|
||||||
|
assert subject.get_scene_unit_name("length") == "foot"
|
||||||
|
assert subject.get_scene_unit_name("area") == "square foot"
|
||||||
|
assert subject.get_scene_unit_name("volume") == "cubic foot"
|
||||||
|
|
||||||
|
def test_getting_a_name_with_no_unit_system(self):
|
||||||
|
bpy.context.scene.unit_settings.system = "NONE"
|
||||||
|
assert subject.get_scene_unit_name("length") == "METRE"
|
||||||
|
|
||||||
|
|
||||||
|
class TestGetSceneUnitSIPrefix:
|
||||||
|
def test_run(self):
|
||||||
|
bpy.context.scene.unit_settings.system = "METRIC"
|
||||||
|
bpy.context.scene.unit_settings.length_unit = "METERS"
|
||||||
|
assert subject.get_scene_unit_si_prefix() is None
|
||||||
|
bpy.context.scene.unit_settings.length_unit = "MICROMETERS"
|
||||||
|
assert subject.get_scene_unit_si_prefix() == "MICRO"
|
||||||
|
bpy.context.scene.unit_settings.length_unit = "MILLIMETERS"
|
||||||
|
assert subject.get_scene_unit_si_prefix() == "MILLI"
|
||||||
|
bpy.context.scene.unit_settings.length_unit = "CENTIMETERS"
|
||||||
|
assert subject.get_scene_unit_si_prefix() == "CENTI"
|
||||||
|
bpy.context.scene.unit_settings.length_unit = "KILOMETERS"
|
||||||
|
assert subject.get_scene_unit_si_prefix() == "KILO"
|
||||||
|
bpy.context.scene.unit_settings.length_unit = "ADAPTIVE"
|
||||||
|
assert subject.get_scene_unit_si_prefix() is None
|
||||||
|
|
||||||
|
|
||||||
|
class TestGetSINameFromUnitType:
|
||||||
|
def test_run(self):
|
||||||
|
for key, value in ifcopenshell.util.unit.si_type_names.items():
|
||||||
|
assert subject.get_si_name_from_unit_type(key) == value
|
||||||
|
|
||||||
|
|
||||||
|
class TestGetUnitClass:
|
||||||
|
def test_run(self):
|
||||||
|
ifc = ifcopenshell.file()
|
||||||
|
assert subject.get_unit_class(ifc.createIfcSIUnit()) == "IfcSIUnit"
|
||||||
|
assert subject.get_unit_class(ifc.createIfcNamedUnit()) == "IfcNamedUnit"
|
||||||
|
|
||||||
|
|
||||||
|
class TestImportUnitAttributes(NewFile):
|
||||||
|
def test_importing_derived_units(self):
|
||||||
|
ifc = ifcopenshell.file()
|
||||||
|
unit = ifc.createIfcDerivedUnit()
|
||||||
|
unit.UnitType = "ANGULARVELOCITYUNIT"
|
||||||
|
unit.UserDefinedType = "UserDefinedType"
|
||||||
|
subject.import_unit_attributes(unit)
|
||||||
|
props = bpy.context.scene.BIMUnitProperties
|
||||||
|
assert props.unit_attributes.get("UnitType").enum_value == "ANGULARVELOCITYUNIT"
|
||||||
|
assert props.unit_attributes.get("UserDefinedType").string_value == "UserDefinedType"
|
||||||
|
|
||||||
|
def test_importing_monetary_units(self):
|
||||||
|
ifc = ifcopenshell.file()
|
||||||
|
unit = ifc.createIfcMonetaryUnit()
|
||||||
|
unit.Currency = "Currency"
|
||||||
|
subject.import_unit_attributes(unit)
|
||||||
|
props = bpy.context.scene.BIMUnitProperties
|
||||||
|
assert props.unit_attributes.get("Currency").string_value == "Currency"
|
||||||
|
|
||||||
|
def test_importing_monetary_units_ifc2x3(self):
|
||||||
|
ifc = ifcopenshell.file(schema="IFC2X3")
|
||||||
|
unit = ifc.createIfcMonetaryUnit()
|
||||||
|
unit.Currency = "USD"
|
||||||
|
subject.import_unit_attributes(unit)
|
||||||
|
props = bpy.context.scene.BIMUnitProperties
|
||||||
|
assert props.unit_attributes.get("Currency").enum_value == "USD"
|
||||||
|
|
||||||
|
def test_importing_context_dependent_units(self):
|
||||||
|
ifc = ifcopenshell.file()
|
||||||
|
tool.Ifc.set(ifc)
|
||||||
|
unit = ifc.createIfcContextDependentUnit()
|
||||||
|
unit.UnitType = "ABSORBEDDOSEUNIT"
|
||||||
|
unit.Name = "Name"
|
||||||
|
unit.Dimensions = ifc.createIfcDimensionalExponents(1, 2, 3, 4, 5, 6, 7)
|
||||||
|
subject.import_unit_attributes(unit)
|
||||||
|
props = bpy.context.scene.BIMUnitProperties
|
||||||
|
assert props.unit_attributes.get("UnitType").enum_value == "ABSORBEDDOSEUNIT"
|
||||||
|
assert props.unit_attributes.get("Name").string_value == "Name"
|
||||||
|
assert props.unit_attributes.get("Dimensions").string_value == "[1, 2, 3, 4, 5, 6, 7]"
|
||||||
|
|
||||||
|
def test_importing_conversion_based_units(self):
|
||||||
|
ifc = ifcopenshell.file()
|
||||||
|
tool.Ifc.set(ifc)
|
||||||
|
unit = ifc.createIfcConversionBasedUnit()
|
||||||
|
unit.UnitType = "ABSORBEDDOSEUNIT"
|
||||||
|
unit.Name = "Name"
|
||||||
|
unit.Dimensions = ifc.createIfcDimensionalExponents(1, 2, 3, 4, 5, 6, 7)
|
||||||
|
subject.import_unit_attributes(unit)
|
||||||
|
props = bpy.context.scene.BIMUnitProperties
|
||||||
|
assert props.unit_attributes.get("UnitType").enum_value == "ABSORBEDDOSEUNIT"
|
||||||
|
assert props.unit_attributes.get("Name").string_value == "Name"
|
||||||
|
assert props.unit_attributes.get("Dimensions").string_value == "[1, 2, 3, 4, 5, 6, 7]"
|
||||||
|
|
||||||
|
def test_importing_conversion_based_with_offset_units(self):
|
||||||
|
ifc = ifcopenshell.file()
|
||||||
|
tool.Ifc.set(ifc)
|
||||||
|
unit = ifc.createIfcConversionBasedUnitWithOffset()
|
||||||
|
unit.UnitType = "ABSORBEDDOSEUNIT"
|
||||||
|
unit.Name = "Name"
|
||||||
|
unit.Dimensions = ifc.createIfcDimensionalExponents(1, 2, 3, 4, 5, 6, 7)
|
||||||
|
unit.ConversionOffset = 1
|
||||||
|
subject.import_unit_attributes(unit)
|
||||||
|
props = bpy.context.scene.BIMUnitProperties
|
||||||
|
assert props.unit_attributes.get("UnitType").enum_value == "ABSORBEDDOSEUNIT"
|
||||||
|
assert props.unit_attributes.get("Name").string_value == "Name"
|
||||||
|
assert props.unit_attributes.get("Dimensions").string_value == "[1, 2, 3, 4, 5, 6, 7]"
|
||||||
|
assert props.unit_attributes.get("ConversionOffset").float_value == 1
|
||||||
|
|
||||||
|
def test_importing_si_units(self):
|
||||||
|
ifc = ifcopenshell.file()
|
||||||
|
tool.Ifc.set(ifc)
|
||||||
|
unit = ifc.createIfcSIUnit()
|
||||||
|
unit.UnitType = "ABSORBEDDOSEUNIT"
|
||||||
|
unit.Prefix = "EXA"
|
||||||
|
unit.Name = "AMPERE"
|
||||||
|
subject.import_unit_attributes(unit)
|
||||||
|
props = bpy.context.scene.BIMUnitProperties
|
||||||
|
assert props.unit_attributes.get("UnitType").enum_value == "ABSORBEDDOSEUNIT"
|
||||||
|
assert props.unit_attributes.get("Prefix").enum_value == "EXA"
|
||||||
|
assert props.unit_attributes.get("Name").enum_value == "AMPERE"
|
||||||
|
assert props.unit_attributes.get("Dimensions") is None
|
||||||
|
|
||||||
|
|
||||||
|
class TestImportUnits(NewFile):
|
||||||
|
def test_importing_multiple_units(self):
|
||||||
|
ifc = ifcopenshell.file()
|
||||||
|
tool.Ifc.set(ifc)
|
||||||
|
unit1 = ifc.createIfcDerivedUnit(UnitType="ANGULARVELOCITYUNIT")
|
||||||
|
unit2 = ifc.createIfcMonetaryUnit(Currency="Currency")
|
||||||
|
unit3 = ifc.createIfcContextDependentUnit(Name="Name", UnitType="ABSORBEDDOSEUNIT")
|
||||||
|
unit4 = ifc.createIfcConversionBasedUnit(Name="Name", UnitType="ABSORBEDDOSEUNIT")
|
||||||
|
unit5 = ifc.createIfcSIUnit(Name="AMPERE", Prefix="MILLI", UnitType="ABSORBEDDOSEUNIT")
|
||||||
|
unit6 = ifc.createIfcSIUnit(Name="CUBIC_METRE", Prefix="CENTI", UnitType="ABSORBEDDOSEUNIT")
|
||||||
|
ifc.createIfcUnitAssignment(Units=[unit2])
|
||||||
|
subject.import_units()
|
||||||
|
props = bpy.context.scene.BIMUnitProperties
|
||||||
|
assert len(props.units) == 6
|
||||||
|
|
||||||
|
assert props.units[0].ifc_definition_id == unit1.id()
|
||||||
|
assert props.units[0].name == ""
|
||||||
|
assert props.units[0].is_assigned is False
|
||||||
|
assert props.units[0].unit_type == unit1.UnitType
|
||||||
|
assert props.units[0].ifc_class == unit1.is_a()
|
||||||
|
|
||||||
|
assert props.units[1].ifc_definition_id == unit2.id()
|
||||||
|
assert props.units[1].name == "Currency"
|
||||||
|
assert props.units[1].is_assigned is True
|
||||||
|
assert props.units[1].unit_type == "CURRENCY"
|
||||||
|
assert props.units[1].ifc_class == unit2.is_a()
|
||||||
|
|
||||||
|
assert props.units[2].ifc_definition_id == unit3.id()
|
||||||
|
assert props.units[2].name == "Name"
|
||||||
|
assert props.units[2].is_assigned is False
|
||||||
|
assert props.units[2].unit_type == unit3.UnitType
|
||||||
|
assert props.units[2].ifc_class == unit3.is_a()
|
||||||
|
|
||||||
|
assert props.units[3].ifc_definition_id == unit4.id()
|
||||||
|
assert props.units[3].name == "Name"
|
||||||
|
assert props.units[3].is_assigned is False
|
||||||
|
assert props.units[3].unit_type == unit4.UnitType
|
||||||
|
assert props.units[3].ifc_class == unit4.is_a()
|
||||||
|
|
||||||
|
assert props.units[4].ifc_definition_id == unit5.id()
|
||||||
|
assert props.units[4].name == "MILLIAMPERE"
|
||||||
|
assert props.units[4].is_assigned is False
|
||||||
|
assert props.units[4].unit_type == unit5.UnitType
|
||||||
|
assert props.units[4].ifc_class == unit5.is_a()
|
||||||
|
|
||||||
|
assert props.units[5].ifc_definition_id == unit6.id()
|
||||||
|
assert props.units[5].name == "CUBIC CENTIMETRE"
|
||||||
|
assert props.units[5].is_assigned is False
|
||||||
|
assert props.units[5].unit_type == unit6.UnitType
|
||||||
|
assert props.units[5].ifc_class == unit6.is_a()
|
||||||
|
|
||||||
|
|
||||||
|
class TestIsSceneUnitMetric(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
props = bpy.context.scene.unit_settings
|
||||||
|
props.system = "METRIC"
|
||||||
|
assert subject.is_scene_unit_metric() is True
|
||||||
|
props.system = "IMPERIAL"
|
||||||
|
assert subject.is_scene_unit_metric() is False
|
||||||
|
props.system = "NONE"
|
||||||
|
assert subject.is_scene_unit_metric() is True
|
||||||
|
|
||||||
|
|
||||||
|
class TestSetActiveUnit(NewFile):
|
||||||
|
def test_run(self):
|
||||||
|
ifc = ifcopenshell.file()
|
||||||
|
unit = ifc.createIfcSIUnit()
|
||||||
|
subject.set_active_unit(unit)
|
||||||
|
assert bpy.context.scene.BIMUnitProperties.active_unit_id == unit.id()
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import ifcopenshell
|
||||||
|
import ifcopenshell.util.unit
|
||||||
|
|
||||||
|
|
||||||
|
class Usecase:
|
||||||
|
def __init__(self, file, **settings):
|
||||||
|
self.file = file
|
||||||
|
self.settings = {"unit_type": "LENGTHUNIT", "name": "METRE", "prefix": None, "conversion_offset": None}
|
||||||
|
for key, value in settings.items():
|
||||||
|
self.settings[key] = value
|
||||||
|
|
||||||
|
def execute(self):
|
||||||
|
if self.settings["unit_type"] == "LENGTHUNIT":
|
||||||
|
dimensional_exponents = self.file.createIfcDimensionalExponents(1, 0, 0, 0, 0, 0, 0)
|
||||||
|
si_unit = self.file.createIfcSIUnit(UnitType=self.settings["unit_type"], Name="METRE")
|
||||||
|
elif self.settings["unit_type"] == "AREAUNIT":
|
||||||
|
dimensional_exponents = self.file.createIfcDimensionalExponents(2, 0, 0, 0, 0, 0, 0)
|
||||||
|
si_unit = self.file.createIfcSIUnit(UnitType=self.settings["unit_type"], Name="SQUARE_METRE")
|
||||||
|
elif self.settings["unit_type"] == "VOLUMEUNIT":
|
||||||
|
dimensional_exponents = self.file.createIfcDimensionalExponents(3, 0, 0, 0, 0, 0, 0)
|
||||||
|
si_unit = self.file.createIfcSIUnit(UnitType=self.settings["unit_type"], Name="CUBIC_METRE")
|
||||||
|
|
||||||
|
conversion_real = ifcopenshell.util.unit.si_conversions.get(self.settings["name"], 1)
|
||||||
|
value_component = self.file.create_entity("IfcReal", **{"wrappedValue": conversion_real})
|
||||||
|
conversion_factor = self.file.createIfcMeasureWithUnit(value_component, si_unit)
|
||||||
|
|
||||||
|
if self.settings["conversion_offset"]:
|
||||||
|
return self.file.createIfcConversionBasedUnit(
|
||||||
|
dimensional_exponents,
|
||||||
|
self.settings["unit_type"],
|
||||||
|
self.settings["name"],
|
||||||
|
conversion_factor,
|
||||||
|
self.settings["conversion_offset"],
|
||||||
|
)
|
||||||
|
return self.file.createIfcConversionBasedUnit(
|
||||||
|
dimensional_exponents, self.settings["unit_type"], self.settings["name"], conversion_factor
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user