mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 09:48:32 +00:00
Fix #2981. Standard case windows can now have different materials and implement shape aspects.
This commit is contained in:
@@ -521,6 +521,11 @@ class BIMWindowProperties(PropertyGroup):
|
|||||||
name="Frame Thickness", size=3, default=[0.035] * 3, subtype="TRANSLATION"
|
name="Frame Thickness", size=3, default=[0.035] * 3, subtype="TRANSLATION"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Material properties
|
||||||
|
lining_material: bpy.props.EnumProperty(name="Lining Material", items=get_materials, options=set())
|
||||||
|
framing_material: bpy.props.EnumProperty(name="Framing Material", items=get_materials, options=set())
|
||||||
|
glazing_material: bpy.props.EnumProperty(name="Glazing Material", items=get_materials, options=set())
|
||||||
|
|
||||||
def get_general_kwargs(self, convert_to_project_units=False):
|
def get_general_kwargs(self, convert_to_project_units=False):
|
||||||
kwargs = {
|
kwargs = {
|
||||||
"window_type": self.window_type,
|
"window_type": self.window_type,
|
||||||
|
|||||||
@@ -448,8 +448,13 @@ class BIM_PT_window(bpy.types.Panel):
|
|||||||
for panel_i in range(number_of_panels):
|
for panel_i in range(number_of_panels):
|
||||||
cols[panel_i + 1].prop(props, prop, index=panel_i, text="")
|
cols[panel_i + 1].prop(props, prop, index=panel_i, text="")
|
||||||
|
|
||||||
update_window_modifier_bmesh(context)
|
self.layout.use_property_split = True
|
||||||
|
self.layout.label(text="Material Properties")
|
||||||
|
self.layout.prop(props, "lining_material")
|
||||||
|
self.layout.prop(props, "framing_material", text="Panel Material")
|
||||||
|
self.layout.prop(props, "glazing_material")
|
||||||
|
|
||||||
|
update_window_modifier_bmesh(context)
|
||||||
else:
|
else:
|
||||||
row.operator("bim.enable_editing_window", icon="GREASEPENCIL", text="")
|
row.operator("bim.enable_editing_window", icon="GREASEPENCIL", text="")
|
||||||
row.operator("bim.remove_window", icon="X", text="")
|
row.operator("bim.remove_window", icon="X", text="")
|
||||||
@@ -492,7 +497,6 @@ class BIM_PT_window(bpy.types.Panel):
|
|||||||
prop_value = panel_props[prop_name][panel_i]
|
prop_value = panel_props[prop_name][panel_i]
|
||||||
r.label(text=str(prop_value))
|
r.label(text=str(prop_value))
|
||||||
r = cols[panel_i + 1].row()
|
r = cols[panel_i + 1].row()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
row = self.layout.row()
|
row = self.layout.row()
|
||||||
row.label(text="No Window Found")
|
row.label(text="No Window Found")
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ def update_window_modifier_representation(context: bpy.types.Context) -> None:
|
|||||||
}
|
}
|
||||||
representation_data["panel_properties"].append(panel_data)
|
representation_data["panel_properties"].append(panel_data)
|
||||||
|
|
||||||
previously_active_context = tool.Geometry.get_active_representation_context(obj)
|
active_context = tool.Geometry.get_active_representation_context(obj)
|
||||||
|
|
||||||
# ELEVATION_VIEW representation
|
# ELEVATION_VIEW representation
|
||||||
profile = ifcopenshell.util.representation.get_context(ifc_file, "Model", "Profile", "ELEVATION_VIEW")
|
profile = ifcopenshell.util.representation.get_context(ifc_file, "Model", "Profile", "ELEVATION_VIEW")
|
||||||
@@ -88,8 +88,25 @@ def update_window_modifier_representation(context: bpy.types.Context) -> None:
|
|||||||
# (Model/Body defined only BEFORE Plan/Body to prevent #2744)
|
# (Model/Body defined only BEFORE Plan/Body to prevent #2744)
|
||||||
body = ifcopenshell.util.representation.get_context(ifc_file, "Model", "Body", "MODEL_VIEW")
|
body = ifcopenshell.util.representation.get_context(ifc_file, "Model", "Body", "MODEL_VIEW")
|
||||||
representation_data["context"] = body
|
representation_data["context"] = body
|
||||||
|
representation_data["part_of_product"] = ifcopenshell.util.representation.get_part_of_product(element, body)
|
||||||
model_representation = ifcopenshell.api.run("geometry.add_window_representation", ifc_file, **representation_data)
|
model_representation = ifcopenshell.api.run("geometry.add_window_representation", ifc_file, **representation_data)
|
||||||
|
representation_data["part_of_product"] = None
|
||||||
tool.Model.replace_object_ifc_representation(body, obj, model_representation)
|
tool.Model.replace_object_ifc_representation(body, obj, model_representation)
|
||||||
|
if fallback_material := (int(props.lining_material) or int(props.framing_material) or int(props.glazing_material)):
|
||||||
|
ifcopenshell.api.material.set_shape_aspect_constituents(
|
||||||
|
ifc_file,
|
||||||
|
element=element,
|
||||||
|
context=body,
|
||||||
|
materials={
|
||||||
|
"Lining": tool.Ifc.get().by_id(int(props.lining_material) or fallback_material),
|
||||||
|
"Framing": tool.Ifc.get().by_id(int(props.framing_material) or fallback_material),
|
||||||
|
"Glazing": tool.Ifc.get().by_id(int(props.glazing_material) or fallback_material),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
elif material := ifcopenshell.util.element.get_material(element):
|
||||||
|
ifcopenshell.api.material.unassign_material(ifc_file, products=[element])
|
||||||
|
if not material.is_a("IfcMaterial") and not ifc_file.get_total_inverses(material):
|
||||||
|
ifcopenshell.api.material.remove_material_set(ifc_file, material=material)
|
||||||
|
|
||||||
# PLAN_VIEW representation
|
# PLAN_VIEW representation
|
||||||
plan = ifcopenshell.util.representation.get_context(ifc_file, "Plan", "Body", "PLAN_VIEW")
|
plan = ifcopenshell.util.representation.get_context(ifc_file, "Plan", "Body", "PLAN_VIEW")
|
||||||
@@ -100,24 +117,15 @@ def update_window_modifier_representation(context: bpy.types.Context) -> None:
|
|||||||
)
|
)
|
||||||
tool.Model.replace_object_ifc_representation(plan, obj, plan_representation)
|
tool.Model.replace_object_ifc_representation(plan, obj, plan_representation)
|
||||||
|
|
||||||
# adding switch representation at the end instead of changing order of representations
|
bonsai.core.geometry.switch_representation(
|
||||||
# to prevent #2744
|
tool.Ifc,
|
||||||
if tool.Geometry.get_active_representation_context(obj) != previously_active_context:
|
tool.Geometry,
|
||||||
previously_active_representation = ifcopenshell.util.representation.get_representation(
|
obj=obj,
|
||||||
element,
|
representation=ifcopenshell.util.representation.get_representation(element, active_context),
|
||||||
previously_active_context.ContextType,
|
should_reload=True,
|
||||||
previously_active_context.ContextIdentifier,
|
is_global=True,
|
||||||
previously_active_context.TargetView,
|
should_sync_changes_first=True,
|
||||||
)
|
)
|
||||||
bonsai.core.geometry.switch_representation(
|
|
||||||
tool.Ifc,
|
|
||||||
tool.Geometry,
|
|
||||||
obj=obj,
|
|
||||||
representation=previously_active_representation,
|
|
||||||
should_reload=True,
|
|
||||||
is_global=True,
|
|
||||||
should_sync_changes_first=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
# type attributes
|
# type attributes
|
||||||
if tool.Ifc.get_schema() != "IFC2X3":
|
if tool.Ifc.get_schema() != "IFC2X3":
|
||||||
|
|||||||
@@ -232,7 +232,7 @@ def create_ifc_window(
|
|||||||
output_items = (lining_items, frame_extruded_items, [glass])
|
output_items = (lining_items, frame_extruded_items, [glass])
|
||||||
builder.translate(chain(*output_items), position)
|
builder.translate(chain(*output_items), position)
|
||||||
|
|
||||||
return output_items
|
return {"Lining": lining_items, "Framing": frame_extruded_items, "Glazing": [glass]}
|
||||||
|
|
||||||
|
|
||||||
# we use dataclass as we need default values for arguments
|
# we use dataclass as we need default values for arguments
|
||||||
@@ -363,6 +363,7 @@ def add_window_representation(
|
|||||||
partition_type: WINDOW_TYPE = "SINGLE_PANEL",
|
partition_type: WINDOW_TYPE = "SINGLE_PANEL",
|
||||||
lining_properties: Optional[Union[WindowLiningProperties, dict[str, Any]]] = None,
|
lining_properties: Optional[Union[WindowLiningProperties, dict[str, Any]]] = None,
|
||||||
panel_properties: Optional[list[Union[WindowPanelProperties, dict[str, Any]]]] = None,
|
panel_properties: Optional[list[Union[WindowPanelProperties, dict[str, Any]]]] = None,
|
||||||
|
part_of_product: Optional[ifcopenshell.entity_instance] = None,
|
||||||
unit_scale: Optional[float] = None,
|
unit_scale: Optional[float] = None,
|
||||||
) -> ifcopenshell.entity_instance:
|
) -> ifcopenshell.entity_instance:
|
||||||
"""units in usecase_settings expected to be in ifc project units
|
"""units in usecase_settings expected to be in ifc project units
|
||||||
@@ -415,6 +416,7 @@ def add_window_representation(
|
|||||||
"partition_type": partition_type,
|
"partition_type": partition_type,
|
||||||
"lining_properties": lining_properties,
|
"lining_properties": lining_properties,
|
||||||
"panel_properties": panel_properties,
|
"panel_properties": panel_properties,
|
||||||
|
"part_of_product": part_of_product,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -440,6 +442,9 @@ class Usecase:
|
|||||||
accumulated_height = [0] * len(panel_schema[0])
|
accumulated_height = [0] * len(panel_schema[0])
|
||||||
built_panels: list[int] = []
|
built_panels: list[int] = []
|
||||||
window_items: list[ifcopenshell.entity_instance] = []
|
window_items: list[ifcopenshell.entity_instance] = []
|
||||||
|
lining_items: list[ifcopenshell.entity_instance] = []
|
||||||
|
framing_items: list[ifcopenshell.entity_instance] = []
|
||||||
|
glazing_items: list[ifcopenshell.entity_instance] = []
|
||||||
|
|
||||||
lining_props: dict[str, Any] = self.settings["lining_properties"]
|
lining_props: dict[str, Any] = self.settings["lining_properties"]
|
||||||
lining_thickness: float = lining_props["LiningThickness"]
|
lining_thickness: float = lining_props["LiningThickness"]
|
||||||
@@ -728,13 +733,39 @@ class Usecase:
|
|||||||
x_offsets,
|
x_offsets,
|
||||||
)
|
)
|
||||||
built_panels.append(panel_i)
|
built_panels.append(panel_i)
|
||||||
window_items.extend(chain(*current_window_items))
|
window_items.extend(chain(*current_window_items.values()))
|
||||||
|
lining_items.extend(current_window_items["Lining"])
|
||||||
|
framing_items.extend(current_window_items["Framing"])
|
||||||
|
glazing_items.extend(current_window_items["Glazing"])
|
||||||
|
|
||||||
accumulated_height[column_i] += panel_height
|
accumulated_height[column_i] += panel_height
|
||||||
accumulated_width += panel_width
|
accumulated_width += panel_width
|
||||||
|
|
||||||
builder.translate(window_items, (0, lining_offset, 0)) # wall offset
|
builder.translate(window_items, (0, lining_offset, 0)) # wall offset
|
||||||
representation = builder.get_representation(self.settings["context"], window_items)
|
representation = builder.get_representation(self.settings["context"], window_items)
|
||||||
|
if self.settings["part_of_product"]:
|
||||||
|
ifcopenshell.api.geometry.add_shape_aspect(
|
||||||
|
self.file,
|
||||||
|
"Lining",
|
||||||
|
items=lining_items,
|
||||||
|
representation=representation,
|
||||||
|
part_of_product=self.settings["part_of_product"],
|
||||||
|
)
|
||||||
|
ifcopenshell.api.geometry.add_shape_aspect(
|
||||||
|
self.file,
|
||||||
|
"Framing",
|
||||||
|
items=framing_items,
|
||||||
|
representation=representation,
|
||||||
|
part_of_product=self.settings["part_of_product"],
|
||||||
|
)
|
||||||
|
ifcopenshell.api.geometry.add_shape_aspect(
|
||||||
|
self.file,
|
||||||
|
"Glazing",
|
||||||
|
items=glazing_items,
|
||||||
|
representation=representation,
|
||||||
|
part_of_product=self.settings["part_of_product"],
|
||||||
|
)
|
||||||
|
|
||||||
return representation
|
return representation
|
||||||
|
|
||||||
@overload
|
@overload
|
||||||
|
|||||||
Reference in New Issue
Block a user