diff --git a/src/ifcblenderexport/blenderbim/bim/__init__.py b/src/ifcblenderexport/blenderbim/bim/__init__.py index 71e3ff9f2f..4c306d2aa9 100644 --- a/src/ifcblenderexport/blenderbim/bim/__init__.py +++ b/src/ifcblenderexport/blenderbim/bim/__init__.py @@ -206,8 +206,8 @@ if bpy is not None: operator.SetNorthOffset, operator.GetNorthOffset, operator.AddPresentationLayer, - operator.AddToPresentationLayer, - operator.RemoveFromPresentationLayer, + operator.AssignPresentationLayer, + operator.UnassignPresentationLayer, operator.RemovePresentationLayer, operator.UpdatePresentationLayer, operator.AddDrawingStyleAttribute, @@ -319,7 +319,6 @@ if bpy is not None: ui.BIM_UL_generic, ui.BIM_UL_clash_sets, ui.BIM_UL_constraints, - ui.BIM_UL_presentation_layers, ui.BIM_UL_document_information, ui.BIM_UL_document_references, ui.BIM_UL_topics, diff --git a/src/ifcblenderexport/blenderbim/bim/export_ifc.py b/src/ifcblenderexport/blenderbim/bim/export_ifc.py index c34ffe3f89..38c8fb4f24 100644 --- a/src/ifcblenderexport/blenderbim/bim/export_ifc.py +++ b/src/ifcblenderexport/blenderbim/bim/export_ifc.py @@ -975,10 +975,10 @@ class IfcParser: def load_presentation_layer_assignments(self): for representation in self.representations.values(): if representation["presentation_layer"]: - pl = representation["presentation_layer"] - if pl.name == '': + layer = representation["presentation_layer"] + if layer.name == "": continue - self.presentation_layer_assignments.setdefault(pl.name, []).append(representation) + self.presentation_layer_assignments.setdefault(layer.name, []).append(representation) def load_representations(self): if not self.ifc_export_settings.has_representations: @@ -1110,7 +1110,9 @@ class IfcParser: "is_native": mesh.BIMMeshProperties.is_native if hasattr(mesh, "BIMMeshProperties") else False, "is_swept_solid": mesh.BIMMeshProperties.is_swept_solid if hasattr(mesh, "BIMMeshProperties") else False, "is_generated": False, - "presentation_layer": obj.BIMObjectProperties.presentation_layer if hasattr(obj, "BIMObjectProperties") else None, + "presentation_layer": obj.BIMObjectProperties.presentation_layer + if hasattr(obj, "BIMObjectProperties") + else None, "attributes": {"Name": mesh.name}, } @@ -2034,23 +2036,31 @@ class IfcExporter: def create_presentation_layer_assignments(self): scene_props = bpy.context.scene.BIMProperties for name, assigned_items in self.ifc_parser.presentation_layer_assignments.items(): - if name == '': + if name == "": continue - pl = scene_props.presentation_layers[name] - print("Presentation Export: ", name, pl.identifier, pl.layer_on) + layer = scene_props.presentation_layers[name] with_style = False - if pl.layer_on is False: + if layer.layer_on is False: with_style = True if with_style is False: self.file.createIfcPresentationLayerAssignment( - name, pl.description, [i["ifc"].MappedRepresentation for i in assigned_items], pl.identifier + name, + layer.description or None, + [i["ifc"].MappedRepresentation for i in assigned_items], + layer.identifier or None, ) else: self.file.createIfcPresentationLayerWithStyle( - name, pl.description, [i["ifc"].MappedRepresentation for i in assigned_items], pl.identifier, - pl.layer_on, pl.layer_frozen, pl.layer_blocked, pl.layer_styles + name, + layer.description or None, + [i["ifc"].MappedRepresentation for i in assigned_items], + layer.identifier or None, + layer.layer_on, + layer.layer_frozen, + layer.layer_blocked, + None, ) def create_materials(self): @@ -3245,7 +3255,7 @@ class IfcExporter: "Profile": self.create_material_profile_def(profile), "Priority": profile.priority, "Category": profile.category or None, - } + }, ) ) return results diff --git a/src/ifcblenderexport/blenderbim/bim/import_ifc.py b/src/ifcblenderexport/blenderbim/bim/import_ifc.py index a8909cf076..7703431627 100644 --- a/src/ifcblenderexport/blenderbim/bim/import_ifc.py +++ b/src/ifcblenderexport/blenderbim/bim/import_ifc.py @@ -480,6 +480,7 @@ class IfcImporter: self.add_project_to_scene() self.profile_code("Add project to scene") self.get_presentation_layers() + self.profile_code("Get presentation layers") if self.ifc_import_settings.should_clean_mesh and len(self.file.by_type("IfcElement")) < 10000: self.clean_mesh() self.profile_code("Mesh cleaning") @@ -1328,23 +1329,31 @@ class IfcImporter: ].hide_viewport = True def get_presentation_layers(self): - for f in self.file.by_type("IfcPresentationLayerAssignment"): - pl = bpy.context.scene.BIMProperties.presentation_layers.add() - pl.name = f.Name - pl.description = f.Description - pl.identifier = f.Identifier - if f.is_a() == "IfcPresentationLayerWithStyle": - pl.layer_on = f.LayerOn if f.LayerOn is not None else True - pl.layer_frozen = f.LayerFrozen if f.LayerFrozen is not None else False - pl.layer_blocked = f.LayerBlocked if f.LayerBlocked is not None else False + for assignment in self.file.by_type("IfcPresentationLayerAssignment"): + layer = bpy.context.scene.BIMProperties.presentation_layers.add() + layer.name = assignment.Name + layer.description = assignment.Description or "" + layer.identifier = assignment.Identifier or "" + if assignment.is_a() == "IfcPresentationLayerWithStyle": + layer.layer_on = assignment.LayerOn if assignment.LayerOn is not None else True + layer.layer_frozen = assignment.LayerFrozen if assignment.LayerFrozen is not None else False + layer.layer_blocked = assignment.LayerBlocked if assignment.LayerBlocked is not None else False - for item in f.AssignedItems: - guid = item.OfProductRepresentation[0].ShapeOfProduct[0].GlobalId + for item in assignment.AssignedItems: + # TODO: This is a simplified and incorrect implementation of assigning presentation layers to objects + # themselves, and will need to be rewritten in the future. See bug #1109. This code also does not + # consider mapped representations. + guids = [] + if not hasattr(item, "OfProductRepresentation"): + continue # TODO: At the moment we ignore representation items + for product_representation in item.OfProductRepresentation: + for product in product_representation.ShapeOfProduct: + guids.append(product.GlobalId) for obj in bpy.context.selectable_objects: global_id = obj.BIMObjectProperties.attributes.get("GlobalId") - if global_id and global_id.string_value == guid: - obj.BIMObjectProperties.presentation_layer.name = pl.name - obj.hide_set(not pl.layer_on) + if global_id and global_id.string_value in guids: + obj.BIMObjectProperties.presentation_layer.name = layer.name + obj.hide_set(not layer.layer_on) def clean_mesh(self): obj = None diff --git a/src/ifcblenderexport/blenderbim/bim/operator.py b/src/ifcblenderexport/blenderbim/bim/operator.py index 4159cf4b94..d63df5c993 100644 --- a/src/ifcblenderexport/blenderbim/bim/operator.py +++ b/src/ifcblenderexport/blenderbim/bim/operator.py @@ -2149,8 +2149,6 @@ class UnassignClassification(bpy.types.Operator): index = obj.BIMObjectProperties.classifications.find(key) if index != -1: obj.BIMObjectProperties.classifications.remove(index) - - obj.BIMObjectProperties.classification = "" return {"FINISHED"} @@ -4324,34 +4322,28 @@ class GetNorthOffset(bpy.types.Operator): return {"FINISHED"} -class AddToPresentationLayer(bpy.types.Operator): - bl_idname = "bim.add_to_presentation_layer" - bl_label = "Add To Presentation Layer" +class AssignPresentationLayer(bpy.types.Operator): + bl_idname = "bim.assign_presentation_layer" + bl_label = "Assign Presentation Layer" index: bpy.props.IntProperty() def execute(self, context): presentation_layer = bpy.context.scene.BIMProperties.presentation_layers[self.index] - - # vl = bpy.context.scene.view_layers[presentation_layer.name] - for obj in bpy.context.selected_objects: + # TODO: assign using a different strategy than name association obj.BIMObjectProperties.presentation_layer.name = presentation_layer.name - elem_name = obj.BIMObjectProperties.attributes["Name"].string_value obj.hide_set(not presentation_layer.layer_on) - print(f'Adding "{elem_name}" to View/Presentation Layer "({self.index} - {presentation_layer.name})"') - return {"FINISHED"} -class RemoveFromPresentationLayer(bpy.types.Operator): - bl_idname = "bim.remove_from_presentation_layer" - bl_label = "Remove Selected From Presentation Layer" +class UnassignPresentationLayer(bpy.types.Operator): + bl_idname = "bim.unassign_presentation_layer" + bl_label = "Unassign Presentation Layer" def execute(self, context): for el in bpy.context.selected_objects: if el.BIMObjectProperties.presentation_layer.name != "": el.BIMObjectProperties.presentation_layer.name = "" - return {"FINISHED"} @@ -4361,15 +4353,10 @@ class AddPresentationLayer(bpy.types.Operator): def execute(self, context): new = bpy.context.scene.BIMProperties.presentation_layers.add() - - # Default values of a new presentation layer new.name = "New Presentation Layer" - new.description = "A Description" - new.identifier = "Something" new.layer_on = True new.layer_frozen = False new.layer_blocked = False - return {"FINISHED"} @@ -4380,7 +4367,6 @@ class RemovePresentationLayer(bpy.types.Operator): def execute(self, context): bpy.context.scene.BIMProperties.presentation_layers.remove(self.index) - return {"FINISHED"} diff --git a/src/ifcblenderexport/blenderbim/bim/prop.py b/src/ifcblenderexport/blenderbim/bim/prop.py index 3504cc6ddd..1c72b9c4e8 100644 --- a/src/ifcblenderexport/blenderbim/bim/prop.py +++ b/src/ifcblenderexport/blenderbim/bim/prop.py @@ -799,7 +799,6 @@ class PresentationLayer(PropertyGroup): layer_on: BoolProperty(name="LayerOn", default=True) layer_frozen: BoolProperty(name="LayerFrozen", default=False) layer_blocked: BoolProperty(name="LayerBlocked", default=False) - layer_styles: EnumProperty(items=[], name="LayerStyles") class Constraint(PropertyGroup): @@ -1680,6 +1679,7 @@ class BIMObjectProperties(PropertyGroup): qto_name: EnumProperty(items=getQtoNames, name="Qto Name") has_boundary_condition: BoolProperty(name="Has Boundary Condition") boundary_condition: PointerProperty(name="Boundary Condition", type=BoundaryCondition) + # TODO: presentation layers should belong to a mesh, not an object presentation_layer: PointerProperty(name="Presentation Layer", type=PresentationLayer) structural_member_connection: PointerProperty(name="Structural Member Connection", type=bpy.types.Object) representation_contexts: CollectionProperty(name="Representation Contexts", type=Subcontext) @@ -1724,7 +1724,6 @@ class BIMMeshProperties(PropertyGroup): is_swept_solid: BoolProperty(name="Is Swept Solid") swept_solids: CollectionProperty(name="Swept Solids", type=SweptSolid) is_parametric: BoolProperty(name="Is Parametric", default=False) - presentation_layer: PointerProperty(name="Presentation Layer", type=PresentationLayer) geometry_type: StringProperty(name="Geometry Type") ifc_definition: StringProperty(name="IFC Definition") ifc_definition_id: IntProperty(name="IFC Definition ID") diff --git a/src/ifcblenderexport/blenderbim/bim/qto.py b/src/ifcblenderexport/blenderbim/bim/qto.py index b1fa9f160d..b1a056caeb 100644 --- a/src/ifcblenderexport/blenderbim/bim/qto.py +++ b/src/ifcblenderexport/blenderbim/bim/qto.py @@ -141,10 +141,9 @@ class QtoCalculator: if len(tf.vertices) == 3: tf_tris = ((me.vertices[tfv[0]], me.vertices[tfv[1]], me.vertices[tfv[2]]),) else: - tf_tris = (me.vertices[tfv[0]], me.vertices[tfv[1]], me.vertices[tfv[2]]), ( - me.vertices[tfv[2]], - me.vertices[tfv[3]], - me.vertices[tfv[0]], + tf_tris = ( + (me.vertices[tfv[0]], me.vertices[tfv[1]], me.vertices[tfv[2]]), + (me.vertices[tfv[2]], me.vertices[tfv[3]], me.vertices[tfv[0]],), ) for tf_iter in tf_tris: diff --git a/src/ifcblenderexport/blenderbim/bim/scheduler.py b/src/ifcblenderexport/blenderbim/bim/scheduler.py index 118c85b421..81555cb55c 100644 --- a/src/ifcblenderexport/blenderbim/bim/scheduler.py +++ b/src/ifcblenderexport/blenderbim/bim/scheduler.py @@ -8,11 +8,7 @@ from odf.style import Style class Scheduler: def schedule(self, infile, outfile): - self.svg = svgwrite.Drawing( - outfile, - debug=False, - id="root", - ) + self.svg = svgwrite.Drawing(outfile, debug=False, id="root",) self.padding = 1 self.margin = 1 doc = load(infile) diff --git a/src/ifcblenderexport/blenderbim/bim/svgwriter.py b/src/ifcblenderexport/blenderbim/bim/svgwriter.py index d3cd79438f..1d8968397e 100644 --- a/src/ifcblenderexport/blenderbim/bim/svgwriter.py +++ b/src/ifcblenderexport/blenderbim/bim/svgwriter.py @@ -450,9 +450,7 @@ class SvgWriter: ) transform = "rotate({}, {}, {})".format( - angle, - (text_position * self.scale)[0], - (text_position * self.scale)[1], + angle, (text_position * self.scale)[0], (text_position * self.scale)[1], ) if text_obj.data.BIMTextProperties.symbol != "None": diff --git a/src/ifcblenderexport/blenderbim/bim/ui.py b/src/ifcblenderexport/blenderbim/bim/ui.py index ed252c1796..3fa5ed05ff 100644 --- a/src/ifcblenderexport/blenderbim/bim/ui.py +++ b/src/ifcblenderexport/blenderbim/bim/ui.py @@ -196,12 +196,7 @@ class BIM_PT_object_material(Panel): row.prop(material, "category") elif props.material_type == "IfcMaterialProfileSet": row.template_list( - "MATERIAL_UL_matslots", - "", - set_props, - "material_profiles", - set_props, - "active_material_profile_index", + "MATERIAL_UL_matslots", "", set_props, "material_profiles", set_props, "active_material_profile_index", ) col = row.column(align=True) col.operator("bim.add_material_profile", icon="ADD", text="") @@ -821,29 +816,22 @@ class BIM_PT_presentation_layer_data(Panel): return layout = self.layout elem_props = context.active_object.BIMObjectProperties.presentation_layer - scene_props = context.scene.BIMProperties + props = context.scene.BIMProperties if elem_props.name != "": layout.label(text=f'Object is part of Presentation layer "{elem_props.name}"') - layout.row().operator("bim.remove_from_presentation_layer") + layout.row().operator("bim.unassign_presentation_layer") else: - layout.label(text="Not included in any presentation layer") + if not props.presentation_layers: + layout.label(text=f"No presentation layers are available") + return - if scene_props.presentation_layers: layout.template_list( - "BIM_UL_presentation_layers", - "", - scene_props, - "presentation_layers", - scene_props, - "active_presentation_layer_index", + "BIM_UL_generic", "", props, "presentation_layers", props, "active_presentation_layer_index", ) - pres_layer = scene_props.presentation_layers[scene_props.active_presentation_layer_index] - if pres_layer.name in bpy.context.scene.BIMProperties.presentation_layers: - op = layout.row().operator("bim.add_to_presentation_layer") - op.index = scene_props.active_presentation_layer_index - else: - layout.label(text="Presentation Layer is invalid") + if props.active_presentation_layer_index < len(props.presentation_layers): + op = layout.row().operator("bim.assign_presentation_layer") + op.index = props.active_presentation_layer_index class BIM_PT_material(Panel): @@ -964,41 +952,36 @@ class BIM_PT_presentation_layers(Panel): layout.use_property_split = True props = context.scene.BIMProperties - layout.row().prop(props, "presentation_layers") layout.row().operator("bim.add_presentation_layer") - if props.presentation_layers: - layout.template_list( - "BIM_UL_presentation_layers", "", props, "presentation_layers", props, "active_presentation_layer_index" - ) - pres_layer = props.presentation_layers[props.active_presentation_layer_index] + if not props.presentation_layers: + return + + layout.template_list( + "BIM_UL_generic", "", props, "presentation_layers", props, "active_presentation_layer_index" + ) + + if props.active_presentation_layer_index < len(props.presentation_layers): + layer = props.presentation_layers[props.active_presentation_layer_index] row = layout.row(align=True) - row.prop(pres_layer, "name") - if pres_layer.name in bpy.context.scene.BIMProperties.presentation_layers: - pres_layer = bpy.context.scene.BIMProperties.presentation_layers[pres_layer.name] - row.operator( - "bim.remove_presentation_layer", icon="X", text="" - ).index = props.active_presentation_layer_index - row = layout.row() - row.prop(pres_layer, "description") - row = layout.row() - row.prop(pres_layer, "identifier") - row = layout.row() - row.prop(pres_layer, "layer_on") - row = layout.row() - row.prop(pres_layer, "layer_frozen") - row = layout.row() - row.prop(pres_layer, "layer_blocked") - row = layout.row() - row.prop(pres_layer, "layer_styles") + row.prop(layer, "name") + row.operator( + "bim.remove_presentation_layer", icon="X", text="" + ).index = props.active_presentation_layer_index + row = layout.row() + row.prop(layer, "description") + row = layout.row() + row.prop(layer, "identifier") + row = layout.row() + row.prop(layer, "layer_on") + row = layout.row() + row.prop(layer, "layer_frozen") + row = layout.row() + row.prop(layer, "layer_blocked") - op = layout.row().operator("bim.update_presentation_layer") - op.index = props.active_presentation_layer_index - - - else: - layout.label(text="Presentation Layer is invalid") + op = layout.row().operator("bim.update_presentation_layer") + op.index = props.active_presentation_layer_index class BIM_PT_drawings(Panel): @@ -2073,15 +2056,6 @@ class BIM_UL_constraints(bpy.types.UIList): layout.label(text="", translate=False) -class BIM_UL_presentation_layers(bpy.types.UIList): - def draw_item(self, context, layout, data, item, icon, active_data, active_propname): - ob = data - if item: - layout.prop(item, "name", text="", emboss=False) - else: - layout.label(text="", translate=False) - - class BIM_UL_document_information(bpy.types.UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname): ob = data @@ -2378,7 +2352,9 @@ class BIM_PT_debug(Panel): row.prop(attribute, "name", text="") row.prop(attribute, "string_value", text="") if attribute.int_value: - row.operator("bim.inspect_from_step_id", icon="DISCLOSURE_TRI_RIGHT", text="").step_id = attribute.int_value + row.operator( + "bim.inspect_from_step_id", icon="DISCLOSURE_TRI_RIGHT", text="" + ).step_id = attribute.int_value if props.inverse_attributes: layout.label(text="Inverse attributes:") @@ -2388,7 +2364,9 @@ class BIM_PT_debug(Panel): row.prop(attribute, "name", text="") row.prop(attribute, "string_value", text="") if attribute.int_value: - row.operator("bim.inspect_from_step_id", icon="DISCLOSURE_TRI_RIGHT", text="").step_id = attribute.int_value + row.operator( + "bim.inspect_from_step_id", icon="DISCLOSURE_TRI_RIGHT", text="" + ).step_id = attribute.int_value def ifc_units(self, context): diff --git a/src/ifcblenderexport/blenderbim/libs/site/packages/.gitignore b/src/ifcblenderexport/blenderbim/libs/site/packages/.gitignore deleted file mode 100644 index 808d16c90d..0000000000 --- a/src/ifcblenderexport/blenderbim/libs/site/packages/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -* -!.gitignore -!ifcopenshell.pth -!OCC.pth -!svgwrite.pth \ No newline at end of file