mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 09:48:32 +00:00
Copying parametric geometry from any source now attempts to preserve parametric geometry when possible.
This commit is contained in:
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user