Copying parametric geometry from any source now attempts to preserve parametric geometry when possible.

This commit is contained in:
Dion Moult
2021-10-22 18:07:34 +11:00
parent c551275db2
commit 6d817703aa
13 changed files with 326 additions and 103 deletions
@@ -212,7 +212,10 @@ class UpdateRepresentation(bpy.types.Operator):
}
if not self.ifc_representation_class:
self.auto_detect_ifc_representation_class(product, old_representation, representation_data)
representation_data["ifc_representation_class"] = tool.Geometry.get_ifc_representation_class(
product, old_representation
)
representation_data["profile_set_usage"] = tool.Geometry.get_profile_set_usage(product)
new_representation = ifcopenshell.api.run("geometry.add_representation", self.file, **representation_data)
@@ -248,28 +251,6 @@ class UpdateRepresentation(bpy.types.Operator):
if obj.data.BIMMeshProperties.ifc_parameters:
bpy.ops.bim.get_representation_ifc_parameters()
def auto_detect_ifc_representation_class(self, element, representation, data):
material = ifcopenshell.util.element.get_material(element)
if material and material.is_a("IfcMaterialProfileSetUsage"):
data["ifc_representation_class"] = "IfcExtrudedAreaSolid/IfcMaterialProfileSetUsage"
data["profile_set_usage"] = material
return
extruded_areas = [e for e in self.file.traverse(representation) if e.is_a() == "IfcExtrudedAreaSolid"]
if len(extruded_areas) != 1:
return # It's too complex for us to derive topologically right now
profile_def = extruded_areas[0].SweptArea
if profile_def.is_a() == "IfcRectangleProfileDef":
data["ifc_representation_class"] = "IfcExtrudedAreaSolid/IfcRectangleProfileDef"
elif profile_def.is_a() == "IfcCircleProfileDef":
data["ifc_representation_class"] = "IfcExtrudedAreaSolid/IfcCircleProfileDef"
else:
data["ifc_representation_class"] = "IfcExtrudedAreaSolid/IfcArbitraryProfileDefWithVoids"
class UpdateParametricRepresentation(bpy.types.Operator):
bl_idname = "bim.update_parametric_representation"
@@ -337,7 +318,9 @@ class CopyRepresentation(bpy.types.Operator, Operator):
return
bm = bmesh.new()
bm.from_mesh(context.active_object.data)
geometric_context = tool.Root.get_object_context(context.active_object)
geometric_context = tool.Root.get_representation_context(
tool.Root.get_object_representation(context.active_object)
)
for obj in context.selected_objects:
if obj == context.active_object:
continue
@@ -467,7 +450,7 @@ class OverrideDuplicateMove(bpy.types.Operator):
obj.select_set(False)
new_obj.select_set(True)
# This is the only difference
blenderbim.core.root.copy_class(tool.Ifc, tool.Collector, tool.Root, obj=new_obj)
blenderbim.core.root.copy_class(tool.Ifc, tool.Collector, tool.Geometry, tool.Root, obj=new_obj)
bpy.ops.transform.translate("INVOKE_DEFAULT")
blenderbim.bim.handler.purge_module_data()
return {"FINISHED"}
@@ -225,7 +225,7 @@ class DumbWallSplitter:
def duplicate_wall(self):
new = self.wall.copy()
self.wall.users_collection[0].objects.link(new)
blenderbim.core.root.copy_class(tool.Ifc, tool.Collector, tool.Root, obj=new)
blenderbim.core.root.copy_class(tool.Ifc, tool.Collector, tool.Geometry, tool.Root, obj=new)
return new
def snap_end_face_to_point(self, wall, which_end):
@@ -356,5 +356,5 @@ class CopyClass(bpy.types.Operator, Operator):
def _execute(self, context):
objects = [bpy.data.objects.get(self.obj)] if self.obj else context.selected_objects
for obj in objects:
core.copy_class(tool.Ifc, tool.Collector, tool.Root, obj=obj)
core.copy_class(tool.Ifc, tool.Collector, tool.Geometry, tool.Root, obj=obj)
blenderbim.bim.handler.purge_module_data()
+9 -2
View File
@@ -17,7 +17,7 @@
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
def copy_class(ifc, collector, root, obj=None):
def copy_class(ifc, collector, geometry, root, obj=None):
element = ifc.get_entity(obj)
if not element:
return
@@ -27,7 +27,14 @@ def copy_class(ifc, collector, root, obj=None):
if relating_type and root.does_type_have_representations(relating_type):
ifc.run("type.map_type_representations", related_object=element, relating_type=relating_type)
else:
root.run_geometry_add_representation(obj=obj, context=root.get_object_context(obj))
representation = root.get_object_representation(obj)
if representation:
root.run_geometry_add_representation(
obj=obj,
context=root.get_representation_context(representation),
ifc_representation_class=geometry.get_ifc_representation_class(element, representation),
profile_set_usage=geometry.get_profile_set_usage(element),
)
collector.assign(obj)
if root.is_opening_element(element):
root.add_dynamic_opening_voids(element, obj)
+5 -2
View File
@@ -63,8 +63,10 @@ class Geometry:
def does_object_have_mesh_with_faces(cls, obj): pass
def duplicate_object_data(cls, obj): pass
def get_cartesian_point_coordinate_offset(cls, obj): pass
def get_ifc_representation_class(cls, element, representation): pass
def get_object_data(cls, obj): pass
def get_object_materials_without_styles(cls, obj): pass
def get_profile_set_usage(cls, element): pass
def get_representation_data(cls, representation): pass
def get_representation_name(cls, representation): pass
def get_total_representation_items(cls, obj): pass
@@ -148,9 +150,10 @@ class Root:
def add_dynamic_opening_voids(cls, element, obj): pass
def does_type_have_representations(cls, element): pass
def get_element_type(cls, element): pass
def get_object_context(cls, obj): pass
def get_object_representation(cls, obj): pass
def get_representation_context(cls, representation): pass
def is_opening_element(cls, element): pass
def run_geometry_add_representation(cls, obj=None, context=None): pass
def run_geometry_add_representation(cls, obj=None, context=None, ifc_representation_class=None, profile_set_usage=None): pass
@interface
+44 -18
View File
@@ -61,24 +61,6 @@ class Geometry(blenderbim.core.tool.Geometry):
obj.data = obj.data.copy()
return obj.data
@classmethod
def get_object_data(cls, obj):
return obj.data
@classmethod
def get_object_materials_without_styles(cls, obj):
return [
s.material for s in obj.material_slots if s.material and not s.material.BIMMaterialProperties.ifc_style_id
]
@classmethod
def get_representation_data(cls, representation):
return bpy.data.meshes.get(cls.get_representation_name(representation))
@classmethod
def get_representation_name(cls, representation):
return f"{representation.ContextOfItems.id()}/{representation.id()}"
@classmethod
def get_cartesian_point_coordinate_offset(cls, obj):
props = bpy.context.scene.BIMGeoreferenceProperties
@@ -91,6 +73,50 @@ class Geometry(blenderbim.core.tool.Geometry):
)
)
@classmethod
def get_ifc_representation_class(cls, element, representation):
material = ifcopenshell.util.element.get_material(element)
if material and material.is_a("IfcMaterialProfileSetUsage"):
return "IfcExtrudedAreaSolid/IfcMaterialProfileSetUsage"
extruded_areas = [e for e in tool.Ifc.get().traverse(representation) if e.is_a() == "IfcExtrudedAreaSolid"]
if len(extruded_areas) != 1:
return # It's too complex for us to derive topologically right now
profile_def = extruded_areas[0].SweptArea
if profile_def.is_a() == "IfcRectangleProfileDef":
return "IfcExtrudedAreaSolid/IfcRectangleProfileDef"
elif profile_def.is_a() == "IfcCircleProfileDef":
return "IfcExtrudedAreaSolid/IfcCircleProfileDef"
return "IfcExtrudedAreaSolid/IfcArbitraryProfileDefWithVoids"
@classmethod
def get_object_data(cls, obj):
return obj.data
@classmethod
def get_object_materials_without_styles(cls, obj):
return [
s.material for s in obj.material_slots if s.material and not s.material.BIMMaterialProperties.ifc_style_id
]
@classmethod
def get_profile_set_usage(cls, element):
material = ifcopenshell.util.element.get_material(element)
if material:
if material.is_a("IfcMaterialProfileSetUsage"):
return material
@classmethod
def get_representation_data(cls, representation):
return bpy.data.meshes.get(cls.get_representation_name(representation))
@classmethod
def get_representation_name(cls, representation):
return f"{representation.ContextOfItems.id()}/{representation.id()}"
@classmethod
def get_total_representation_items(cls, obj):
return max(1, len(obj.material_slots))
+17 -4
View File
@@ -49,16 +49,29 @@ class Root(blenderbim.core.tool.Root):
return ifcopenshell.util.element.get_type(element)
@classmethod
def get_object_context(cls, obj):
def get_object_representation(cls, obj):
if obj.data and obj.data.BIMMeshProperties.ifc_definition_id:
return tool.Ifc.get().by_id(obj.data.BIMMeshProperties.ifc_definition_id).ContextOfItems
return tool.Ifc.get().by_id(obj.data.BIMMeshProperties.ifc_definition_id)
@classmethod
def get_representation_context(cls, representation):
return representation.ContextOfItems
@classmethod
def is_opening_element(cls, element):
return element.is_a("IfcOpeningElement")
@classmethod
def run_geometry_add_representation(cls, obj=None, context=None):
def run_geometry_add_representation(
cls, obj=None, context=None, ifc_representation_class=None, profile_set_usage=None
):
return blenderbim.core.geometry.add_representation(
tool.Ifc, tool.Geometry, tool.Style, tool.Surveyor, obj=obj, context=context
tool.Ifc,
tool.Geometry,
tool.Style,
tool.Surveyor,
obj=obj,
context=context,
ifc_representation_class=ifc_representation_class,
profile_set_usage=profile_set_usage,
)
+1 -1
View File
@@ -93,7 +93,7 @@ class Spatial(blenderbim.core.tool.Spatial):
@classmethod
def run_root_copy_class(cls, obj=None):
return blenderbim.core.root.copy_class(tool.Ifc, tool.Collector, tool.Root, obj=obj)
return blenderbim.core.root.copy_class(tool.Ifc, tool.Collector, tool.Geometry, tool.Root, obj=obj)
@classmethod
def run_spatial_assign_container(cls, structure_obj=None, element_obj=None):
@@ -44,7 +44,7 @@ Scenario: Switch representation - existing Blender modifiers must be purged
And I press "bim.switch_representation(obj='IfcWall/Cube', ifc_definition_id={representation})"
Then the object "IfcWall/Cube" has no modifiers
Scenario: Update representation
Scenario: Update representation - updating a tessellation
Given an empty IFC project
And I add a cube
And the object "Cube" is selected
@@ -53,6 +53,63 @@ Scenario: Update representation
And I press "bim.update_representation(obj='IfcWall/Cube')"
Then the object "IfcWall/Cube" has a "Tessellation" representation of "Model/Body/MODEL_VIEW"
Scenario: Update representation - updating a layered extrusion
Given an empty IFC project
And I add a cube
And the object "Cube" is selected
And I set "scene.BIMRootProperties.ifc_class" to "IfcWall"
And I press "bim.assign_class"
And I add an empty
And the object "Empty" is selected
And I set "scene.BIMRootProperties.ifc_product" to "IfcElementType"
And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType"
And I press "bim.assign_class"
And I press "bim.add_default_material"
And I set "active_object.BIMObjectMaterialProperties.material_type" to "IfcMaterialLayerSet"
And I press "bim.assign_material"
And I press "bim.enable_editing_assigned_material"
And the variable "layer_set" is "{ifc}.by_type("IfcMaterialLayerSet")[0].id()"
And I press "bim.add_layer(layer_set={layer_set})"
And the variable "layer" is "{ifc}.by_type("IfcMaterialLayer")[0].id()"
And I press "bim.enable_editing_material_set_item(material_set_item={layer})"
And I set "active_object.BIMObjectMaterialProperties.material_set_item_attributes[0].float_value" to "0.1"
And I press "bim.edit_material_set_item(material_set_item={layer})"
And I press "bim.edit_assigned_material(material_set={layer_set})"
And the variable "type" is "{ifc}.by_type('IfcWallType')[0].id()"
And I press "bim.assign_type(relating_type={type}, related_object='IfcWall/Cube')"
When I press "bim.update_representation(obj='IfcWall/Cube')"
Then the object "IfcWall/Cube" has a "SweptSolid" representation of "Model/Body/MODEL_VIEW"
Scenario: Update representation - updating a profiled extrusion
Given an empty IFC project
And I add a cube
And the object "Cube" is selected
And I set "scene.BIMRootProperties.ifc_class" to "IfcWall"
And I press "bim.assign_class"
And I add an empty
And the object "Empty" is selected
And I set "scene.BIMRootProperties.ifc_product" to "IfcElementType"
And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType"
And I press "bim.assign_class"
And I press "bim.add_default_material"
And I set "active_object.BIMObjectMaterialProperties.material_type" to "IfcMaterialProfileSet"
And I press "bim.assign_material"
And I press "bim.enable_editing_assigned_material"
And the variable "profile_set" is "{ifc}.by_type("IfcMaterialProfileSet")[0].id()"
And I press "bim.add_profile(profile_set={profile_set})"
And the variable "profile" is "{ifc}.by_type("IfcMaterialProfile")[0].id()"
And I press "bim.enable_editing_material_set_item(material_set_item={profile})"
And I set "active_object.BIMObjectMaterialProperties.profile_classes" to "IfcParameterizedProfileDef"
And I set "active_object.BIMObjectMaterialProperties.parameterized_profile_classes" to "IfcCircleProfileDef"
And I press "bim.assign_parameterized_profile(ifc_class='IfcCircleProfileDef', material_profile={profile})"
And I set "active_object.BIMObjectMaterialProperties.material_set_item_profile_attributes[2].float_value" to "0.2"
And I press "bim.edit_material_set_item(material_set_item={profile})"
And I press "bim.edit_assigned_material(material_set={profile_set})"
And the variable "type" is "{ifc}.by_type('IfcWallType')[0].id()"
And I press "bim.assign_type(relating_type={type}, related_object='IfcWall/Cube')"
When I press "bim.update_representation(obj='IfcWall/Cube')"
Then the object "IfcWall/Cube" has a "SweptSolid" representation of "Model/Body/MODEL_VIEW"
Scenario: Copy representation
Given an empty IFC project
And I add a cube
@@ -126,3 +183,64 @@ Scenario: Override duplicate move - copying a type instance with a representatio
When I press "object.duplicate_move"
Then the object "IfcWall/Instance.001" exists
And the object "IfcWall/Instance.001" has a "MappedRepresentation" representation of "Model/Body/MODEL_VIEW"
Scenario: Override duplicate move - copying a layered extrusion
Given an empty IFC project
And I add a cube
And the object "Cube" is selected
And I set "scene.BIMRootProperties.ifc_class" to "IfcWall"
And I press "bim.assign_class"
And I add an empty
And the object "Empty" is selected
And I set "scene.BIMRootProperties.ifc_product" to "IfcElementType"
And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType"
And I press "bim.assign_class"
And I press "bim.add_default_material"
And I set "active_object.BIMObjectMaterialProperties.material_type" to "IfcMaterialLayerSet"
And I press "bim.assign_material"
And I press "bim.enable_editing_assigned_material"
And the variable "layer_set" is "{ifc}.by_type("IfcMaterialLayerSet")[0].id()"
And I press "bim.add_layer(layer_set={layer_set})"
And the variable "layer" is "{ifc}.by_type("IfcMaterialLayer")[0].id()"
And I press "bim.enable_editing_material_set_item(material_set_item={layer})"
And I set "active_object.BIMObjectMaterialProperties.material_set_item_attributes[0].float_value" to "0.1"
And I press "bim.edit_material_set_item(material_set_item={layer})"
And I press "bim.edit_assigned_material(material_set={layer_set})"
And the variable "type" is "{ifc}.by_type('IfcWallType')[0].id()"
And I press "bim.assign_type(relating_type={type}, related_object='IfcWall/Cube')"
And the object "IfcWall/Cube" is selected
When I press "object.duplicate_move"
Then the object "IfcWall/Cube.001" exists
Then the object "IfcWall/Cube.001" has a "SweptSolid" representation of "Model/Body/MODEL_VIEW"
Scenario: Override duplicate move - copying a profiled extrusion
Given an empty IFC project
And I add a cube
And the object "Cube" is selected
And I set "scene.BIMRootProperties.ifc_class" to "IfcWall"
And I press "bim.assign_class"
And I add an empty
And the object "Empty" is selected
And I set "scene.BIMRootProperties.ifc_product" to "IfcElementType"
And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType"
And I press "bim.assign_class"
And I press "bim.add_default_material"
And I set "active_object.BIMObjectMaterialProperties.material_type" to "IfcMaterialProfileSet"
And I press "bim.assign_material"
And I press "bim.enable_editing_assigned_material"
And the variable "profile_set" is "{ifc}.by_type("IfcMaterialProfileSet")[0].id()"
And I press "bim.add_profile(profile_set={profile_set})"
And the variable "profile" is "{ifc}.by_type("IfcMaterialProfile")[0].id()"
And I press "bim.enable_editing_material_set_item(material_set_item={profile})"
And I set "active_object.BIMObjectMaterialProperties.profile_classes" to "IfcParameterizedProfileDef"
And I set "active_object.BIMObjectMaterialProperties.parameterized_profile_classes" to "IfcCircleProfileDef"
And I press "bim.assign_parameterized_profile(ifc_class='IfcCircleProfileDef', material_profile={profile})"
And I set "active_object.BIMObjectMaterialProperties.material_set_item_profile_attributes[2].float_value" to "0.2"
And I press "bim.edit_material_set_item(material_set_item={profile})"
And I press "bim.edit_assigned_material(material_set={profile_set})"
And the variable "type" is "{ifc}.by_type('IfcWallType')[0].id()"
And I press "bim.assign_type(relating_type={type}, related_object='IfcWall/Cube')"
And the object "IfcWall/Cube" is selected
When I press "object.duplicate_move"
Then the object "IfcWall/Cube.001" exists
Then the object "IfcWall/Cube.001" has a "SweptSolid" representation of "Model/Body/MODEL_VIEW"
+4 -4
View File
@@ -13,7 +13,7 @@ Scenario: Assign type - assign to an empty type
And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType"
And I press "bim.assign_class"
When the variable "type" is "{ifc}.by_type('IfcWallType')[0].id()"
And I press "bim.assign_type(relating_type={type}, related_object="IfcWall/Cube")"
And I press "bim.assign_type(relating_type={type}, related_object='IfcWall/Cube')"
Then the object "IfcWall/Cube" has a "Tessellation" representation of "Model/Body/MODEL_VIEW"
Scenario: Assign type - assign to a type with representation maps
@@ -28,7 +28,7 @@ Scenario: Assign type - assign to a type with representation maps
And I set "scene.BIMRootProperties.ifc_class" to "IfcWallType"
And I press "bim.assign_class"
When the variable "type" is "{ifc}.by_type('IfcWallType')[0].id()"
And I press "bim.assign_type(relating_type={type}, related_object="IfcWall/Cube")"
And I press "bim.assign_type(relating_type={type}, related_object='IfcWall/Cube')"
Then the object "IfcWall/Cube" has a "MappedRepresentation" representation of "Model/Body/MODEL_VIEW"
Scenario: Assign type - assign to a type with a material layer set
@@ -54,7 +54,7 @@ Scenario: Assign type - assign to a type with a material layer set
And I press "bim.edit_material_set_item(material_set_item={layer})"
And I press "bim.edit_assigned_material(material_set={layer_set})"
When the variable "type" is "{ifc}.by_type('IfcWallType')[0].id()"
And I press "bim.assign_type(relating_type={type}, related_object="IfcWall/Cube")"
And I press "bim.assign_type(relating_type={type}, related_object='IfcWall/Cube')"
Then the object "IfcWall/Cube" has a "SweptSolid" representation of "Model/Body/MODEL_VIEW"
Scenario: Assign type - assign to a type with a material profile set
@@ -83,5 +83,5 @@ Scenario: Assign type - assign to a type with a material profile set
And I press "bim.edit_material_set_item(material_set_item={profile})"
And I press "bim.edit_assigned_material(material_set={profile_set})"
When the variable "type" is "{ifc}.by_type('IfcWallType')[0].id()"
And I press "bim.assign_type(relating_type={type}, related_object="IfcWall/Cube")"
And I press "bim.assign_type(relating_type={type}, related_object='IfcWall/Cube')"
Then the object "IfcWall/Cube" has a "SweptSolid" representation of "Model/Body/MODEL_VIEW"
+31 -19
View File
@@ -18,13 +18,13 @@
import blenderbim.core.root as subject
import test.core.test_geometry
from test.core.bootstrap import ifc, collector, root
from test.core.bootstrap import ifc, collector, geometry, root
class TestCopyClass:
def test_doing_nothing_if_not_an_ifc_element(self, ifc, collector, root):
ifc.get_entity("obj").should_be_called().will_return(None)
subject.copy_class(ifc, collector, root, obj="obj")
subject.copy_class(ifc, collector, geometry, root, obj="obj")
def test_copy_with_new_geometry_derived_from_the_type(self, ifc, collector, root):
ifc.get_entity("obj").should_be_called().will_return("original_element")
@@ -35,31 +35,43 @@ class TestCopyClass:
ifc.run("type.map_type_representations", related_object="element", relating_type="type").should_be_called()
collector.assign("obj").should_be_called()
root.is_opening_element("element").should_be_called().will_return(False)
subject.copy_class(ifc, collector, root, obj="obj")
subject.copy_class(ifc, collector, geometry, root, obj="obj")
def test_copy_with_new_geometry_added_afresh_for_speed(
self,
ifc,
collector,
root,
):
def test_copy_with_new_geometry_added_afresh_for_speed(self, ifc, collector, geometry, root):
ifc.get_entity("obj").should_be_called().will_return("original_element")
ifc.run("root.copy_class", product="original_element").should_be_called().will_return("element")
ifc.link("element", "obj").should_be_called()
root.get_element_type("element").should_be_called().will_return("type")
root.does_type_have_representations("type").should_be_called().will_return(False)
root.get_object_context("obj").should_be_called().will_return("context")
root.run_geometry_add_representation(obj="obj", context="context").should_be_called()
root.get_object_representation("obj").should_be_called().will_return("representation")
root.get_representation_context("representation").should_be_called().will_return("context")
geometry.get_ifc_representation_class("element", "representation").should_be_called().will_return(
"ifc_representation_class"
)
geometry.get_profile_set_usage("element").should_be_called().will_return("profile_set_usage")
root.run_geometry_add_representation(
obj="obj",
context="context",
ifc_representation_class="ifc_representation_class",
profile_set_usage="profile_set_usage",
).should_be_called()
collector.assign("obj").should_be_called()
root.is_opening_element("element").should_be_called().will_return(False)
subject.copy_class(ifc, collector, root, obj="obj")
subject.copy_class(ifc, collector, geometry, root, obj="obj")
def test_copied_openings_have_dynamic_voids_added(
self,
ifc,
collector,
root,
):
def test_copy_with_no_new_geometry(self, ifc, collector, geometry, root):
ifc.get_entity("obj").should_be_called().will_return("original_element")
ifc.run("root.copy_class", product="original_element").should_be_called().will_return("element")
ifc.link("element", "obj").should_be_called()
root.get_element_type("element").should_be_called().will_return("type")
root.does_type_have_representations("type").should_be_called().will_return(False)
root.get_object_representation("obj").should_be_called().will_return(None)
collector.assign("obj").should_be_called()
root.is_opening_element("element").should_be_called().will_return(False)
subject.copy_class(ifc, collector, geometry, root, obj="obj")
def test_copied_openings_have_dynamic_voids_added(self, ifc, collector, root):
ifc.get_entity("obj").should_be_called().will_return("original_element")
ifc.run("root.copy_class", product="original_element").should_be_called().will_return("element")
ifc.link("element", "obj").should_be_called()
@@ -69,4 +81,4 @@ class TestCopyClass:
collector.assign("obj").should_be_called()
root.is_opening_element("element").should_be_called().will_return(True)
root.add_dynamic_opening_voids("element", "obj").should_be_called()
subject.copy_class(ifc, collector, root, obj="obj")
subject.copy_class(ifc, collector, geometry, root, obj="obj")
+74 -21
View File
@@ -20,20 +20,20 @@ import bpy
import math
import numpy
import ifcopenshell
import test.bim.bootstrap
import blenderbim.core.tool
import blenderbim.tool as tool
from mathutils import Vector
from test.bim.bootstrap import NewFile
from blenderbim.tool.geometry import Geometry as subject
from blenderbim.bim.ifc import IfcStore
class TestImplementsTool(test.bim.bootstrap.NewFile):
class TestImplementsTool(NewFile):
def test_run(self):
assert isinstance(subject(), blenderbim.core.tool.Geometry)
class TestChangeObjectData(test.bim.bootstrap.NewFile):
class TestChangeObjectData(NewFile):
def test_change_single_object_data(self):
data1 = bpy.data.meshes.new("Mesh")
data2 = bpy.data.meshes.new("Mesh")
@@ -53,7 +53,7 @@ class TestChangeObjectData(test.bim.bootstrap.NewFile):
assert obj2.data == data2
class TestClearModifiers(test.bim.bootstrap.NewFile):
class TestClearModifiers(NewFile):
def test_run(self):
obj = bpy.data.objects.new("Object", bpy.data.meshes.new("Mesh"))
obj.modifiers.new("IfcOpeningElement", "BOOLEAN")
@@ -61,7 +61,7 @@ class TestClearModifiers(test.bim.bootstrap.NewFile):
assert len(obj.modifiers) == 0
class TestCreateDynamicVoids(test.bim.bootstrap.NewFile):
class TestCreateDynamicVoids(NewFile):
def test_run(self):
ifc = ifcopenshell.file()
tool.Ifc.set(ifc)
@@ -82,7 +82,7 @@ class TestCreateDynamicVoids(test.bim.bootstrap.NewFile):
assert modifier.use_self is True
class TestDoesObjectHaveMeshWithFaces(test.bim.bootstrap.NewFile):
class TestDoesObjectHaveMeshWithFaces(NewFile):
def test_empties_return_false(self):
obj = bpy.data.objects.new("Object", None)
assert subject.does_object_have_mesh_with_faces(obj) is False
@@ -101,7 +101,7 @@ class TestDoesObjectHaveMeshWithFaces(test.bim.bootstrap.NewFile):
assert subject.does_object_have_mesh_with_faces(obj) is True
class TestDuplicateObjectData(test.bim.bootstrap.NewFile):
class TestDuplicateObjectData(NewFile):
def test_run(self):
data = bpy.data.meshes.new("Mesh")
obj = bpy.data.objects.new("Object", data)
@@ -110,14 +110,14 @@ class TestDuplicateObjectData(test.bim.bootstrap.NewFile):
assert isinstance(obj.data, bpy.types.Mesh)
class TestGetObjectData(test.bim.bootstrap.NewFile):
class TestGetObjectData(NewFile):
def test_run(self):
data = bpy.data.meshes.new("Mesh")
obj = bpy.data.objects.new("Object", data)
assert subject.get_object_data(obj) == obj.data
class TestGetObjectMaterialsWithoutStyles(test.bim.bootstrap.NewFile):
class TestGetObjectMaterialsWithoutStyles(NewFile):
def test_run(self):
material1 = bpy.data.materials.new("Material")
material2 = bpy.data.materials.new("Material")
@@ -130,7 +130,7 @@ class TestGetObjectMaterialsWithoutStyles(test.bim.bootstrap.NewFile):
assert subject.get_object_materials_without_styles(obj) == [material1, material2]
class TestGetRepresentationData(test.bim.bootstrap.NewFile):
class TestGetRepresentationData(NewFile):
def test_run(self):
ifc = ifcopenshell.file()
context = ifc.createIfcGeometricRepresentationContext()
@@ -140,7 +140,7 @@ class TestGetRepresentationData(test.bim.bootstrap.NewFile):
assert subject.get_representation_data(representation) == data
class TestGetRepresentationName(test.bim.bootstrap.NewFile):
class TestGetRepresentationName(NewFile):
def test_run(self):
ifc = ifcopenshell.file()
context = ifc.createIfcGeometricRepresentationContext()
@@ -149,7 +149,7 @@ class TestGetRepresentationName(test.bim.bootstrap.NewFile):
assert subject.get_representation_name(representation) == f"{context.id()}/{representation.id()}"
class TestGetCartesianPointCoordinateOffset(test.bim.bootstrap.NewFile):
class TestGetCartesianPointCoordinateOffset(NewFile):
def test_run(self):
obj = bpy.data.objects.new("Object", None)
obj.BIMObjectProperties.blender_offset_type = "CARTESIAN_POINT"
@@ -177,7 +177,7 @@ class TestGetCartesianPointCoordinateOffset(test.bim.bootstrap.NewFile):
assert subject.get_cartesian_point_coordinate_offset(obj) is None
class TestGetTotalRepresentationItems(test.bim.bootstrap.NewFile):
class TestGetTotalRepresentationItems(NewFile):
def test_run(self):
material1 = bpy.data.materials.new("Material")
material2 = bpy.data.materials.new("Material")
@@ -187,7 +187,7 @@ class TestGetTotalRepresentationItems(test.bim.bootstrap.NewFile):
assert subject.get_total_representation_items(obj) == 2
class TestImportRepresentation(test.bim.bootstrap.NewFile):
class TestImportRepresentation(NewFile):
def test_importing_a_normal_shape(self):
ifc = ifcopenshell.open("test/files/basic.ifc")
tool.Ifc.set(ifc)
@@ -213,7 +213,7 @@ class TestImportRepresentation(test.bim.bootstrap.NewFile):
assert len(mesh.edges) == 4
class TestIsBodyRepresentation(test.bim.bootstrap.NewFile):
class TestIsBodyRepresentation(NewFile):
def test_run(self):
ifc = ifcopenshell.file()
context = ifc.createIfcGeometricRepresentationContext()
@@ -225,7 +225,7 @@ class TestIsBodyRepresentation(test.bim.bootstrap.NewFile):
assert subject.is_body_representation(representation) is False
class TestLink(test.bim.bootstrap.NewFile):
class TestLink(NewFile):
def test_run(self):
ifc = ifcopenshell.file()
element = ifc.createIfcShapeRepresentation()
@@ -234,14 +234,14 @@ class TestLink(test.bim.bootstrap.NewFile):
assert obj.BIMMeshProperties.ifc_definition_id == element.id()
class TestRenameObjectData(test.bim.bootstrap.NewFile):
class TestRenameObjectData(NewFile):
def test_run(self):
obj = bpy.data.meshes.new("Mesh")
subject.rename_object(obj, "name")
assert obj.name == "name"
class TestResolveMappedRepresentation(test.bim.bootstrap.NewFile):
class TestResolveMappedRepresentation(NewFile):
def test_run(self):
ifc = ifcopenshell.file()
mapped_representation = ifc.createIfcShapeRepresentation()
@@ -258,19 +258,72 @@ class TestResolveMappedRepresentation(test.bim.bootstrap.NewFile):
assert subject.resolve_mapped_representation(representation) == representation
class TestShouldForceFacetedBrep(test.bim.bootstrap.NewFile):
class TestShouldForceFacetedBrep(NewFile):
def test_run(self):
result = bpy.context.scene.BIMGeometryProperties.should_force_faceted_brep
assert subject.should_force_faceted_brep() is result
class TestShouldForceTriangulation(test.bim.bootstrap.NewFile):
class TestShouldForceTriangulation(NewFile):
def test_run(self):
result = bpy.context.scene.BIMGeometryProperties.should_force_triangulation
assert subject.should_force_triangulation() is result
class TestShouldUsePresentationStyleAssignment(test.bim.bootstrap.NewFile):
class TestShouldUsePresentationStyleAssignment(NewFile):
def test_run(self):
result = bpy.context.scene.BIMGeometryProperties.should_use_presentation_style_assignment
assert subject.should_use_presentation_style_assignment() is result
class TestGetProfileSetUsage(NewFile):
def test_getting_a_profile_set_usage(self):
ifc = ifcopenshell.file()
element = ifc.createIfcColumn()
assert subject.get_profile_set_usage(element) is None
usage = ifc.createIfcMaterialProfileSetUsage()
ifc.createIfcRelAssociatesMaterial(RelatingMaterial=usage, RelatedObjects=[element])
assert subject.get_profile_set_usage(element) == usage
class TestGetIfcRepresentationClass(NewFile):
def test_detecting_profile_set_representations(self):
ifc = ifcopenshell.file()
tool.Ifc.set(ifc)
element = ifc.createIfcColumn()
ifc.createIfcRelAssociatesMaterial(
RelatingMaterial=ifc.createIfcMaterialProfileSetUsage(), RelatedObjects=[element]
)
representation = ifc.createIfcShapeRepresentation()
assert (
subject.get_ifc_representation_class(element, representation)
== "IfcExtrudedAreaSolid/IfcMaterialProfileSetUsage"
)
def test_detecting_rectangular_extrusions(self):
ifc = ifcopenshell.file()
tool.Ifc.set(ifc)
element = ifc.createIfcColumn()
representation = ifc.createIfcShapeRepresentation(
Items=[ifc.createIfcExtrudedAreaSolid(SweptArea=ifc.createIfcRectangleProfileDef())]
)
assert (
subject.get_ifc_representation_class(element, representation)
== "IfcExtrudedAreaSolid/IfcRectangleProfileDef"
)
def test_detecting_circle_extrusions(self):
ifc = ifcopenshell.file()
tool.Ifc.set(ifc)
element = ifc.createIfcColumn()
representation = ifc.createIfcShapeRepresentation(
Items=[ifc.createIfcExtrudedAreaSolid(SweptArea=ifc.createIfcCircleProfileDef())]
)
assert (
subject.get_ifc_representation_class(element, representation) == "IfcExtrudedAreaSolid/IfcCircleProfileDef"
)
def test_returning_null_for_non_parametric_representations(self):
ifc = ifcopenshell.file()
tool.Ifc.set(ifc)
assert subject.get_ifc_representation_class(ifc.createIfcColumn(), ifc.createIfcShapeRepresentation()) is None
+12 -4
View File
@@ -74,15 +74,23 @@ class TestGetElementType(NewFile):
assert subject.get_element_type(element) == type
class TestGetElementType(NewFile):
class TestGetObjectRepresentation(NewFile):
def test_run(self):
ifc = ifcopenshell.file()
tool.Ifc.set(ifc)
representation = ifc.createIfcShapeRepresentation()
obj = bpy.data.objects.new("Object", bpy.data.meshes.new("Mesh"))
obj.data.BIMMeshProperties.ifc_definition_id = representation.id()
assert subject.get_object_representation(obj) == representation
class TestGetRepresentationContext(NewFile):
def test_run(self):
ifc = ifcopenshell.file()
tool.Ifc.set(ifc)
context = ifc.createIfcGeometricRepresentationContext()
representation = ifc.createIfcShapeRepresentation(ContextOfItems=context)
obj = bpy.data.objects.new("Object", bpy.data.meshes.new("Mesh"))
obj.data.BIMMeshProperties.ifc_definition_id = representation.id()
assert subject.get_object_context(obj) == context
assert subject.get_representation_context(representation) == context
class TestIsOpeningElement(NewFile):