Assigning a parametric layer type (for walls for now) now attempts to switch from non parametric to parametric geometry.

This commit is contained in:
Dion Moult
2021-10-22 15:43:04 +11:00
parent f19e334cd5
commit 9ffe92eae5
9 changed files with 108 additions and 65 deletions
@@ -200,9 +200,6 @@ class UpdateRepresentation(bpy.types.Operator):
)
)
if not self.ifc_representation_class:
self.ifc_representation_class = self.auto_detect_ifc_representation_class(product, old_representation) or ""
representation_data = {
"context": context_of_items,
"blender_object": obj,
@@ -214,6 +211,9 @@ class UpdateRepresentation(bpy.types.Operator):
"ifc_representation_class": self.ifc_representation_class,
}
if not self.ifc_representation_class:
self.auto_detect_ifc_representation_class(product, old_representation, representation_data)
new_representation = ifcopenshell.api.run("geometry.add_representation", self.file, **representation_data)
[
@@ -248,24 +248,27 @@ 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):
def auto_detect_ifc_representation_class(self, element, representation, data):
material = ifcopenshell.util.element.get_material(element)
if material.is_a("IfcMaterialProfileSetUsage"):
return "IfcExtrudedAreaSolid/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 None # It's too complex for us to derive topologically right now
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"
data["ifc_representation_class"] = "IfcExtrudedAreaSolid/IfcRectangleProfileDef"
elif profile_def.is_a() == "IfcCircleProfileDef":
return "IfcExtrudedAreaSolid/IfcCircleProfileDef"
return "IfcExtrudedAreaSolid/IfcArbitraryProfileDefWithVoids"
data["ifc_representation_class"] = "IfcExtrudedAreaSolid/IfcCircleProfileDef"
else:
data["ifc_representation_class"] = "IfcExtrudedAreaSolid/IfcArbitraryProfileDefWithVoids"
class UpdateParametricRepresentation(bpy.types.Operator):
@@ -69,10 +69,10 @@ def load_post(*args):
ifcopenshell.api.add_post_listener(
"geometry.add_representation", "BlenderBIM.DumbWall.CalculateQuantities", wall.calculate_quantities
)
ifcopenshell.api.add_pre_listener(
ifcopenshell.api.add_post_listener(
"material.edit_layer", "BlenderBIM.DumbWall.RegenerateFromLayer", wall.DumbWallPlaner().regenerate_from_layer
)
ifcopenshell.api.add_pre_listener(
ifcopenshell.api.add_post_listener(
"type.assign_type", "BlenderBIM.DumbWall.RegenerateFromType", wall.DumbWallPlaner().regenerate_from_type
)
@@ -85,10 +85,10 @@ def load_post(*args):
ifcopenshell.api.add_post_listener(
"geometry.add_representation", "BlenderBIM.DumbSlab.CalculateQuantities", slab.calculate_quantities
)
ifcopenshell.api.add_pre_listener(
ifcopenshell.api.add_post_listener(
"material.edit_layer", "BlenderBIM.DumbSlab.RegenerateFromLayer", slab.DumbSlabPlaner().regenerate_from_layer
)
ifcopenshell.api.add_pre_listener(
ifcopenshell.api.add_post_listener(
"type.assign_type", "BlenderBIM.DumbSlab.RegenerateFromType", slab.DumbSlabPlaner().regenerate_from_type
)
@@ -328,7 +328,7 @@ class DumbSlabPlaner:
if not total_thickness:
continue
for inverse in ifc_file.get_inverse(layer_set):
if not inverse.is_a("IfcMaterialLayerSetUsage"):
if not inverse.is_a("IfcMaterialLayerSetUsage") or inverse.LayerSetDirection != "AXIS3":
continue
if ifc_file.schema == "IFC2X3":
for rel in ifc_file.get_inverse(inverse):
@@ -347,13 +347,11 @@ class DumbSlabPlaner:
if not new_material or not new_material.is_a("IfcMaterialLayerSet"):
return
new_thickness = sum([l.LayerThickness for l in new_material.MaterialLayers])
self.change_thickness(settings["related_object"], new_thickness)
material = ifcopenshell.util.element.get_material(settings["related_object"])
if material and material.is_a("IfcMaterialLayerSetUsage") and material.LayerSetDirection == "AXIS3":
self.change_thickness(settings["related_object"], new_thickness)
def change_thickness(self, element, thickness):
parametric = ifcopenshell.util.element.get_psets(element).get("EPset_Parametric")
if not parametric or parametric["Engine"] != "BlenderBIM.DumbLayer3":
return
obj = IfcStore.get_element(element.id())
if not obj:
return
@@ -925,7 +925,7 @@ class DumbWallPlaner:
if not total_thickness:
continue
for inverse in ifc_file.get_inverse(layer_set):
if not inverse.is_a("IfcMaterialLayerSetUsage"):
if not inverse.is_a("IfcMaterialLayerSetUsage") or inverse.LayerSetDirection != "AXIS2":
continue
if ifc_file.schema == "IFC2X3":
for rel in ifc_file.get_inverse(inverse):
@@ -944,13 +944,11 @@ class DumbWallPlaner:
if not new_material or not new_material.is_a("IfcMaterialLayerSet"):
return
new_thickness = sum([l.LayerThickness for l in new_material.MaterialLayers])
self.change_thickness(settings["related_object"], new_thickness)
material = ifcopenshell.util.element.get_material(settings["related_object"])
if material and material.is_a("IfcMaterialLayerSetUsage") and material.LayerSetDirection == "AXIS2":
self.change_thickness(settings["related_object"], new_thickness)
def change_thickness(self, element, thickness):
parametric = ifcopenshell.util.element.get_psets(element).get("EPset_Parametric")
if not parametric or parametric["Engine"] != "BlenderBIM.DumbLayer2":
return
obj = IfcStore.get_element(element.id())
if not obj:
return
@@ -998,7 +996,7 @@ class DumbWallPlaner:
if not slide_vector:
continue
slide_vector *= slide_magnitude / abs(slide_vector.y)
results.append({"vert":vert, "vector":slide_vector})
results.append({"vert": vert, "vector": slide_vector})
return results
# An end face is a quad that is on one end of the wall or the other. It must
+1 -1
View File
@@ -57,7 +57,7 @@ class Type(blenderbim.core.tool.Type):
if material.is_a("IfcMaterialProfileSetUsage"):
return "IfcExtrudedAreaSolid/IfcMaterialProfileSetUsage"
elif material.is_a("IfcMaterialLayerSetUsage"):
return "IfcExtrudedAreaSolid/IfcExtrudedAreaSolid/IfcArbitraryProfileDefWithVoids"
return "IfcExtrudedAreaSolid/IfcArbitraryProfileDefWithVoids"
@classmethod
def get_profile_set_usage(cls, element):
@@ -87,6 +87,7 @@ Scenario: Override duplicate move - with active IFC data
And the object "IfcWall/Cube" is an "IfcWall"
And the object "IfcWall/Cube.001" exists
And the object "IfcWall/Cube.001" is an "IfcWall"
And the object "IfcWall/Cube.001" has a "Tessellation" representation of "Model/Body/MODEL_VIEW"
And the object "IfcBuildingStorey/My Storey.001" exists
And the object "IfcBuildingStorey/My Storey.001" is an "IfcBuildingStorey"
+72 -2
View File
@@ -1,7 +1,7 @@
@type
Feature: Type
Scenario: Assign type
Scenario: Assign type - assign to an empty type
Given an empty IFC project
And I add a cube
And the object "Cube" is selected
@@ -14,4 +14,74 @@ Scenario: Assign type
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")"
Then nothing happens
Then the object "IfcWall/Cube" has a "Tessellation" representation of "Model/Body/MODEL_VIEW"
Scenario: Assign type - assign to a type with representation maps
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 a cube
And the object "Cube" 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"
When the variable "type" is "{ifc}.by_type('IfcWallType')[0].id()"
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
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})"
When the variable "type" is "{ifc}.by_type('IfcWallType')[0].id()"
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
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})"
When the variable "type" is "{ifc}.by_type('IfcWallType')[0].id()"
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"
+2 -5
View File
@@ -103,12 +103,9 @@ class TestGetIfcRepresentationClass(NewFile):
ifc.createIfcRelAssociatesMaterial(
RelatingMaterial=ifc.createIfcMaterialLayerSetUsage(), RelatedObjects=[element]
)
assert (
subject.get_ifc_representation_class(element)
== "IfcExtrudedAreaSolid/IfcExtrudedAreaSolid/IfcArbitraryProfileDefWithVoids"
)
assert subject.get_ifc_representation_class(element) == "IfcExtrudedAreaSolid/IfcArbitraryProfileDefWithVoids"
def test_returning_null_for_non_parametric_represntations(self):
def test_returning_null_for_non_parametric_representations(self):
ifc = ifcopenshell.file()
assert subject.get_ifc_representation_class(ifc.createIfcColumn()) is None
@@ -54,40 +54,16 @@ class Usecase:
}
)
ifcopenshell.api.run(
"type.map_type_representations",
self.file,
related_object=self.settings["related_object"],
relating_type=self.settings["relating_type"],
)
if self.settings["relating_type"].RepresentationMaps:
ifcopenshell.api.run(
"type.map_type_representations",
self.file,
related_object=self.settings["related_object"],
relating_type=self.settings["relating_type"],
)
self.map_material_usages()
return types
def map_representations(self):
if not self.settings["relating_type"].RepresentationMaps:
return
representations = []
if self.settings["related_object"].Representation:
representations = self.settings["related_object"].Representation.Representations
for representation in representations:
# TODO: check if this is right? Surely this can be a single usecase?
ifcopenshell.api.run(
"geometry.unassign_representation",
self.file,
**{"product": self.settings["related_object"], "representation": representation}
)
ifcopenshell.api.run("geometry.remove_representation", self.file, **{"representation": representation})
for representation_map in self.settings["relating_type"].RepresentationMaps:
representation = representation_map.MappedRepresentation
mapped_representation = ifcopenshell.api.run(
"geometry.map_representation", self.file, **{"representation": representation}
)
ifcopenshell.api.run(
"geometry.assign_representation",
self.file,
**{"product": self.settings["related_object"], "representation": mapped_representation}
)
def map_material_usages(self):
type_material = ifcopenshell.util.element.get_material(self.settings["relating_type"])
if not type_material: