mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-09 17:31:45 +00:00
Assigning a parametric layer type (for walls for now) now attempts to switch from non parametric to parametric geometry.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user