mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-21 14:23:53 +00:00
#2104. Support for adding conversion based units to the project.
This commit is contained in:
@@ -156,7 +156,9 @@ class UpdateRepresentation(bpy.types.Operator):
|
|||||||
|
|
||||||
def update_obj_mesh_representation(self, context, obj):
|
def update_obj_mesh_representation(self, context, obj):
|
||||||
product = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
product = self.file.by_id(obj.BIMObjectProperties.ifc_definition_id)
|
||||||
tool.Geometry.clear_cache(product)
|
|
||||||
|
if not product.is_a("IfcGridAxis"):
|
||||||
|
tool.Geometry.clear_cache(product)
|
||||||
|
|
||||||
if product.is_a("IfcGridAxis"):
|
if product.is_a("IfcGridAxis"):
|
||||||
ifcopenshell.api.run("grid.create_axis_curve", self.file, **{"axis_curve": obj, "grid_axis": product})
|
ifcopenshell.api.run("grid.create_axis_curve", self.file, **{"axis_curve": obj, "grid_axis": product})
|
||||||
|
|||||||
@@ -20,18 +20,19 @@ import bpy
|
|||||||
from . import ui, prop, operator
|
from . import ui, prop, operator
|
||||||
|
|
||||||
classes = (
|
classes = (
|
||||||
operator.AssignSceneUnits,
|
operator.AddContextDependentUnit,
|
||||||
operator.AssignUnit,
|
operator.AddConversionBasedUnit,
|
||||||
operator.UnassignUnit,
|
|
||||||
operator.LoadUnits,
|
|
||||||
operator.DisableUnitEditingUI,
|
|
||||||
operator.RemoveUnit,
|
|
||||||
operator.AddMonetaryUnit,
|
operator.AddMonetaryUnit,
|
||||||
operator.AddSIUnit,
|
operator.AddSIUnit,
|
||||||
operator.AddContextDependentUnit,
|
operator.AssignSceneUnits,
|
||||||
operator.EnableEditingUnit,
|
operator.AssignUnit,
|
||||||
operator.DisableEditingUnit,
|
operator.DisableEditingUnit,
|
||||||
|
operator.DisableUnitEditingUI,
|
||||||
operator.EditUnit,
|
operator.EditUnit,
|
||||||
|
operator.EnableEditingUnit,
|
||||||
|
operator.LoadUnits,
|
||||||
|
operator.RemoveUnit,
|
||||||
|
operator.UnassignUnit,
|
||||||
prop.Unit,
|
prop.Unit,
|
||||||
prop.BIMUnitProperties,
|
prop.BIMUnitProperties,
|
||||||
ui.BIM_PT_units,
|
ui.BIM_PT_units,
|
||||||
|
|||||||
@@ -16,6 +16,10 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# 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/>.
|
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import ifcopenshell
|
||||||
|
import ifcopenshell.util.unit
|
||||||
|
import ifcopenshell.util.schema
|
||||||
|
import ifcopenshell.util.attribute
|
||||||
import blenderbim.tool as tool
|
import blenderbim.tool as tool
|
||||||
|
|
||||||
|
|
||||||
@@ -29,9 +33,32 @@ class UnitsData:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load(cls):
|
def load(cls):
|
||||||
cls.data = {"total_units": cls.get_total_units()}
|
cls.data = {
|
||||||
|
"unit_classes": cls.unit_classes(),
|
||||||
|
"named_unit_types": cls.named_unit_types(),
|
||||||
|
"conversion_unit_types": cls.conversion_unit_types(),
|
||||||
|
"total_units": cls.get_total_units()
|
||||||
|
}
|
||||||
cls.is_loaded = True
|
cls.is_loaded = True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def unit_classes(cls):
|
||||||
|
declarations = ifcopenshell.util.schema.get_subtypes(tool.Ifc.schema().declaration_by_name("IfcNamedUnit"))
|
||||||
|
results = [(c, c, "") for c in sorted([d.name() for d in declarations])]
|
||||||
|
results.extend([("IfcDerivedUnit", "IfcDerivedUnit", ""), ("IfcMonetaryUnit", "IfcMonetaryUnit", "")])
|
||||||
|
return results
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def named_unit_types(cls):
|
||||||
|
values = ifcopenshell.util.attribute.get_enum_items(
|
||||||
|
tool.Ifc.schema().declaration_by_name("IfcNamedUnit").all_attributes()[1]
|
||||||
|
)
|
||||||
|
return [(c, c, "") for c in sorted(values)]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def conversion_unit_types(cls):
|
||||||
|
return [(u, u, "") for u in ifcopenshell.util.unit.si_conversions.keys()]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_total_units(cls):
|
def get_total_units(cls):
|
||||||
ifc = tool.Ifc.get()
|
ifc = tool.Ifc.get()
|
||||||
|
|||||||
@@ -94,6 +94,16 @@ class RemoveUnit(bpy.types.Operator, Operator):
|
|||||||
core.remove_unit(tool.Ifc, tool.Unit, unit=tool.Ifc.get().by_id(self.unit))
|
core.remove_unit(tool.Ifc, tool.Unit, unit=tool.Ifc.get().by_id(self.unit))
|
||||||
|
|
||||||
|
|
||||||
|
class AddConversionBasedUnit(bpy.types.Operator, Operator):
|
||||||
|
bl_idname = "bim.add_conversion_based_unit"
|
||||||
|
bl_label = "Add Conversion Based Unit"
|
||||||
|
bl_options = {"REGISTER", "UNDO"}
|
||||||
|
name: bpy.props.StringProperty()
|
||||||
|
|
||||||
|
def _execute(self, context):
|
||||||
|
core.add_conversion_based_unit(tool.Ifc, tool.Unit, name=self.name)
|
||||||
|
|
||||||
|
|
||||||
class AddMonetaryUnit(bpy.types.Operator, 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"
|
||||||
|
|||||||
@@ -17,11 +17,9 @@
|
|||||||
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
import ifcopenshell
|
|
||||||
import ifcopenshell.util.schema
|
|
||||||
import ifcopenshell.util.attribute
|
|
||||||
from blenderbim.bim.ifc import IfcStore
|
from blenderbim.bim.ifc import IfcStore
|
||||||
from blenderbim.bim.prop import StrProperty, Attribute
|
from blenderbim.bim.prop import StrProperty, Attribute
|
||||||
|
from blenderbim.bim.module.unit.data import UnitsData
|
||||||
from bpy.types import PropertyGroup
|
from bpy.types import PropertyGroup
|
||||||
from bpy.props import (
|
from bpy.props import (
|
||||||
PointerProperty,
|
PointerProperty,
|
||||||
@@ -35,34 +33,22 @@ from bpy.props import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
unitclasses_enum = []
|
def get_unit_classes(self, context):
|
||||||
namedunittypes_enum = []
|
if not UnitsData.is_loaded:
|
||||||
|
UnitsData.load()
|
||||||
|
return UnitsData.data["unit_classes"]
|
||||||
|
|
||||||
|
|
||||||
def purge():
|
def get_conversion_unit_types(self, context):
|
||||||
global unitclasses_enum
|
if not UnitsData.is_loaded:
|
||||||
global namedunittypes_enum
|
UnitsData.load()
|
||||||
unitclasses_enum = []
|
return UnitsData.data["conversion_unit_types"]
|
||||||
namedunittypes_enum = []
|
|
||||||
|
|
||||||
|
|
||||||
def getUnitClasses(self, context):
|
def get_named_unit_types(self, context):
|
||||||
global unitclasses_enum
|
if not UnitsData.is_loaded:
|
||||||
if not len(unitclasses_enum) and IfcStore.get_file():
|
UnitsData.load()
|
||||||
declarations = ifcopenshell.util.schema.get_subtypes(IfcStore.get_schema().declaration_by_name("IfcNamedUnit"))
|
return UnitsData.data["named_unit_types"]
|
||||||
unitclasses_enum.extend([(c, c, "") for c in sorted([d.name() for d in declarations])])
|
|
||||||
unitclasses_enum.extend([("IfcDerivedUnit", "IfcDerivedUnit", ""), ("IfcMonetaryUnit", "IfcMonetaryUnit", "")])
|
|
||||||
return unitclasses_enum
|
|
||||||
|
|
||||||
|
|
||||||
def getNamedUnitTypes(self, context):
|
|
||||||
global namedunittypes_enum
|
|
||||||
if not len(namedunittypes_enum) and IfcStore.get_file():
|
|
||||||
values = ifcopenshell.util.attribute.get_enum_items(
|
|
||||||
IfcStore.get_schema().declaration_by_name("IfcNamedUnit").all_attributes()[1]
|
|
||||||
)
|
|
||||||
namedunittypes_enum.extend([(c, c, "") for c in sorted(values)])
|
|
||||||
return namedunittypes_enum
|
|
||||||
|
|
||||||
|
|
||||||
class Unit(PropertyGroup):
|
class Unit(PropertyGroup):
|
||||||
@@ -78,6 +64,7 @@ class BIMUnitProperties(PropertyGroup):
|
|||||||
units: CollectionProperty(name="Units", type=Unit)
|
units: CollectionProperty(name="Units", type=Unit)
|
||||||
active_unit_index: IntProperty(name="Active Unit Index")
|
active_unit_index: IntProperty(name="Active Unit Index")
|
||||||
active_unit_id: IntProperty(name="Active Unit Id")
|
active_unit_id: IntProperty(name="Active Unit Id")
|
||||||
unit_classes: EnumProperty(items=getUnitClasses, name="Unit Classes")
|
unit_classes: EnumProperty(items=get_unit_classes, name="Unit Classes")
|
||||||
named_unit_types: EnumProperty(items=getNamedUnitTypes, name="Named Unit Types")
|
conversion_unit_types: EnumProperty(items=get_conversion_unit_types, name="Conversion Unit Types")
|
||||||
|
named_unit_types: EnumProperty(items=get_named_unit_types, name="Named Unit Types")
|
||||||
unit_attributes: CollectionProperty(name="Unit Attributes", type=Attribute)
|
unit_attributes: CollectionProperty(name="Unit Attributes", type=Attribute)
|
||||||
|
|||||||
@@ -57,6 +57,10 @@ class BIM_PT_units(Panel):
|
|||||||
|
|
||||||
if self.props.unit_classes == "IfcMonetaryUnit":
|
if self.props.unit_classes == "IfcMonetaryUnit":
|
||||||
row.operator("bim.add_monetary_unit", text="", icon="ADD")
|
row.operator("bim.add_monetary_unit", text="", icon="ADD")
|
||||||
|
elif self.props.unit_classes in ("IfcConversionBasedUnit", "IfcConversionBasedUnitWithOffset"):
|
||||||
|
row.prop(self.props, "conversion_unit_types", text="")
|
||||||
|
op = row.operator("bim.add_conversion_based_unit", text="", icon="ADD")
|
||||||
|
op.name = self.props.conversion_unit_types
|
||||||
elif self.props.unit_classes == "IfcDerivedUnit":
|
elif self.props.unit_classes == "IfcDerivedUnit":
|
||||||
pass # TODO
|
pass # TODO
|
||||||
elif self.props.unit_classes == "IfcSIUnit":
|
elif self.props.unit_classes == "IfcSIUnit":
|
||||||
|
|||||||
@@ -32,7 +32,9 @@ def assign_scene_units(ifc, unit):
|
|||||||
areaunit = ifc.run("unit.add_conversion_based_unit", name=area_name)
|
areaunit = ifc.run("unit.add_conversion_based_unit", name=area_name)
|
||||||
volumeunit = ifc.run("unit.add_conversion_based_unit", name=volume_name)
|
volumeunit = ifc.run("unit.add_conversion_based_unit", name=volume_name)
|
||||||
|
|
||||||
ifc.run("unit.assign_unit", units=[lengthunit, areaunit, volumeunit])
|
planeangleunit = ifc.run("unit.add_conversion_based_unit", name="degree")
|
||||||
|
|
||||||
|
ifc.run("unit.assign_unit", units=[lengthunit, areaunit, volumeunit, planeangleunit])
|
||||||
|
|
||||||
|
|
||||||
def assign_unit(ifc, unit_tool, unit=None):
|
def assign_unit(ifc, unit_tool, unit=None):
|
||||||
@@ -77,6 +79,12 @@ def add_context_dependent_unit(ifc, unit, unit_type=None, name=None):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def add_conversion_based_unit(ifc, unit, name=None):
|
||||||
|
result = ifc.run("unit.add_conversion_based_unit", name=name)
|
||||||
|
unit.import_units()
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
def enable_editing_unit(unit_tool, unit=None):
|
def enable_editing_unit(unit_tool, unit=None):
|
||||||
unit_tool.set_active_unit(unit)
|
unit_tool.set_active_unit(unit)
|
||||||
unit_tool.import_unit_attributes(unit)
|
unit_tool.import_unit_attributes(unit)
|
||||||
|
|||||||
@@ -50,6 +50,16 @@ Scenario: Add context dependent unit
|
|||||||
When I press "bim.add_context_dependent_unit(name='THINGAMAJIGS', unit_type='LENGTHUNIT')"
|
When I press "bim.add_context_dependent_unit(name='THINGAMAJIGS', unit_type='LENGTHUNIT')"
|
||||||
Then nothing happens
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Add conversion based unit
|
||||||
|
Given an empty IFC project
|
||||||
|
When I press "bim.add_conversion_based_unit(name='inch')"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
|
Scenario: Add conversion based unit with offset
|
||||||
|
Given an empty IFC project
|
||||||
|
When I press "bim.add_conversion_based_unit(name='fahrenheit')"
|
||||||
|
Then nothing happens
|
||||||
|
|
||||||
Scenario: Enable editing unit
|
Scenario: Enable editing unit
|
||||||
Given an empty IFC project
|
Given an empty IFC project
|
||||||
And the variable "unit" is "{ifc}.by_type('IfcSIUnit')[0].id()"
|
And the variable "unit" is "{ifc}.by_type('IfcSIUnit')[0].id()"
|
||||||
|
|||||||
@@ -39,7 +39,9 @@ class TestAssignSceneUnits:
|
|||||||
"unit.add_si_unit", unit_type="VOLUMEUNIT", name="name", prefix="prefix"
|
"unit.add_si_unit", unit_type="VOLUMEUNIT", name="name", prefix="prefix"
|
||||||
).should_be_called().will_return("volumeunit")
|
).should_be_called().will_return("volumeunit")
|
||||||
|
|
||||||
ifc.run("unit.assign_unit", units=["lengthunit", "areaunit", "volumeunit"]).should_be_called()
|
ifc.run("unit.add_conversion_based_unit", name="degree").should_be_called().will_return("planeangleunit")
|
||||||
|
|
||||||
|
ifc.run("unit.assign_unit", units=["lengthunit", "areaunit", "volumeunit", "planeangleunit"]).should_be_called()
|
||||||
subject.assign_scene_units(ifc, unit)
|
subject.assign_scene_units(ifc, unit)
|
||||||
|
|
||||||
def test_creating_and_assigning_imperial_units(self, ifc, unit):
|
def test_creating_and_assigning_imperial_units(self, ifc, unit):
|
||||||
@@ -53,7 +55,9 @@ class TestAssignSceneUnits:
|
|||||||
unit.get_scene_unit_name("volume").should_be_called().will_return("volumename")
|
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.add_conversion_based_unit", name="volumename").should_be_called().will_return("volumeunit")
|
||||||
|
|
||||||
ifc.run("unit.assign_unit", units=["lengthunit", "areaunit", "volumeunit"]).should_be_called()
|
ifc.run("unit.add_conversion_based_unit", name="degree").should_be_called().will_return("planeangleunit")
|
||||||
|
|
||||||
|
ifc.run("unit.assign_unit", units=["lengthunit", "areaunit", "volumeunit", "planeangleunit"]).should_be_called()
|
||||||
subject.assign_scene_units(ifc, unit)
|
subject.assign_scene_units(ifc, unit)
|
||||||
|
|
||||||
|
|
||||||
@@ -115,6 +119,13 @@ class TestAddContextDependentUnit:
|
|||||||
assert subject.add_context_dependent_unit(ifc, unit, unit_type="unit_type", name="name") == "unit"
|
assert subject.add_context_dependent_unit(ifc, unit, unit_type="unit_type", name="name") == "unit"
|
||||||
|
|
||||||
|
|
||||||
|
class TestAddConversionBasedUnit:
|
||||||
|
def test_run(self, ifc, unit):
|
||||||
|
ifc.run("unit.add_conversion_based_unit", name="name").should_be_called().will_return("unit")
|
||||||
|
unit.import_units().should_be_called()
|
||||||
|
assert subject.add_conversion_based_unit(ifc, unit, name="name") == "unit"
|
||||||
|
|
||||||
|
|
||||||
class TestEnableEditingUnit:
|
class TestEnableEditingUnit:
|
||||||
def test_run(self, unit):
|
def test_run(self, unit):
|
||||||
unit.set_active_unit("unit").should_be_called()
|
unit.set_active_unit("unit").should_be_called()
|
||||||
|
|||||||
Reference in New Issue
Block a user