diff --git a/src/ifcblenderexport/blenderbim/bim/__init__.py b/src/ifcblenderexport/blenderbim/bim/__init__.py index 96b8bf7bbd..ef9e00d2ff 100644 --- a/src/ifcblenderexport/blenderbim/bim/__init__.py +++ b/src/ifcblenderexport/blenderbim/bim/__init__.py @@ -199,6 +199,9 @@ if bpy is not None: operator.SetViewportShadowFromSun, operator.SetNorthOffset, operator.GetNorthOffset, + operator.AddPresentationLayer, + operator.AddToPresentationLayer, + operator.RemovePresentationLayer, operator.AddDrawingStyleAttribute, operator.RemoveDrawingStyleAttribute, operator.CopyPropertyToSelection, @@ -235,6 +238,7 @@ if bpy is not None: prop.BcfTopicDocumentReference, prop.BcfTopicRelatedTopic, prop.Subcontext, + prop.PresentationLayer, prop.BIMProperties, prop.BIMDebugProperties, prop.BCFProperties, @@ -245,7 +249,6 @@ if bpy is not None: prop.Attribute, prop.IfcParameter, prop.BoundaryCondition, - prop.PresentationLayer, prop.PsetQto, prop.GlobalId, prop.RepresentationItem, @@ -275,6 +278,7 @@ if bpy is not None: ui.BIM_PT_qa, ui.BIM_PT_library, ui.BIM_PT_gis, + ui.BIM_PT_presentation_layers, ui.BIM_PT_diff, ui.BIM_PT_cobie, ui.BIM_PT_patch, @@ -282,7 +286,7 @@ if bpy is not None: ui.BIM_PT_debug, ui.BIM_PT_material, ui.BIM_PT_mesh, - ui.BIM_PT_presentation, + ui.BIM_PT_presentation_layer_data, ui.BIM_PT_object, ui.BIM_PT_object_material, ui.BIM_PT_object_psets, @@ -301,6 +305,7 @@ 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/operator.py b/src/ifcblenderexport/blenderbim/bim/operator.py index c4d60a6711..a35953fa27 100644 --- a/src/ifcblenderexport/blenderbim/bim/operator.py +++ b/src/ifcblenderexport/blenderbim/bim/operator.py @@ -55,8 +55,8 @@ def set_active_camera_resolution(scene): if not scene.camera or "/" not in scene.camera.name or not scene.DocProperties.drawings: return if ( - scene.render.resolution_x != scene.camera.data.BIMCameraProperties.raster_x - or scene.render.resolution_y != scene.camera.data.BIMCameraProperties.raster_y + scene.render.resolution_x != scene.camera.data.BIMCameraProperties.raster_x + or scene.render.resolution_y != scene.camera.data.BIMCameraProperties.raster_y ): scene.render.resolution_x = scene.camera.data.BIMCameraProperties.raster_x scene.render.resolution_y = scene.camera.data.BIMCameraProperties.raster_y @@ -145,8 +145,9 @@ class SelectGlobalId(bpy.types.Operator): for obj in bpy.context.visible_objects: index = obj.BIMObjectProperties.attributes.find("GlobalId") if ( - index != -1 - and obj.BIMObjectProperties.attributes[index].string_value == bpy.context.scene.BIMProperties.global_id + index != -1 + and obj.BIMObjectProperties.attributes[ + index].string_value == bpy.context.scene.BIMProperties.global_id ): obj.select_set(True) break @@ -167,9 +168,9 @@ class SelectAttribute(bpy.types.Operator): continue value = object.BIMObjectProperties.attributes[index].string_value if ( - bpy.context.scene.BIMProperties.search_regex - and bpy.context.scene.BIMProperties.search_ignorecase - and re.search(search_value, value, flags=re.IGNORECASE) + bpy.context.scene.BIMProperties.search_regex + and bpy.context.scene.BIMProperties.search_ignorecase + and re.search(search_value, value, flags=re.IGNORECASE) ): object.select_set(True) elif bpy.context.scene.BIMProperties.search_regex and re.search(search_value, value): @@ -200,9 +201,9 @@ class SelectPset(bpy.types.Operator): continue value = object.BIMObjectProperties.psets[pset_index].properties[prop_index].string_value if ( - bpy.context.scene.BIMProperties.search_regex - and bpy.context.scene.BIMProperties.search_ignorecase - and re.search(search_value, value, flags=re.IGNORECASE) + bpy.context.scene.BIMProperties.search_regex + and bpy.context.scene.BIMProperties.search_ignorecase + and re.search(search_value, value, flags=re.IGNORECASE) ): object.select_set(True) elif bpy.context.scene.BIMProperties.search_regex and re.search(search_value, value): @@ -301,9 +302,9 @@ class SelectClass(bpy.types.Operator): def execute(self, context): for object in bpy.context.visible_objects: if ( - "/" in object.name - and object.name[0:3] == "Ifc" - and object.name.split("/")[0] == bpy.context.scene.BIMProperties.ifc_class + "/" in object.name + and object.name[0:3] == "Ifc" + and object.name.split("/")[0] == bpy.context.scene.BIMProperties.ifc_class ): object.select_set(True) return {"FINISHED"} @@ -316,19 +317,19 @@ class SelectType(bpy.types.Operator): def execute(self, context): for object in bpy.context.visible_objects: if ( - "/" in object.name - and object.name[0:3] == "Ifc" - and object.name.split("/")[0] == bpy.context.scene.BIMProperties.ifc_class - and "PredefinedType" in object.BIMObjectProperties.attributes - and object.BIMObjectProperties.attributes["PredefinedType"].string_value - == bpy.context.scene.BIMProperties.ifc_predefined_type + "/" in object.name + and object.name[0:3] == "Ifc" + and object.name.split("/")[0] == bpy.context.scene.BIMProperties.ifc_class + and "PredefinedType" in object.BIMObjectProperties.attributes + and object.BIMObjectProperties.attributes["PredefinedType"].string_value + == bpy.context.scene.BIMProperties.ifc_predefined_type ): if bpy.context.scene.BIMProperties.ifc_predefined_type != "USERDEFINED": object.select_set(True) elif ( - "ObjectType" in object.BIMObjectProperties.attributes - and object.BIMObjectProperties.attributes["ObjectType"].string_value - == bpy.context.scene.BIMProperties.ifc_userdefined_type + "ObjectType" in object.BIMObjectProperties.attributes + and object.BIMObjectProperties.attributes["ObjectType"].string_value + == bpy.context.scene.BIMProperties.ifc_userdefined_type ): object.select_set(True) return {"FINISHED"} @@ -423,8 +424,8 @@ class QAHelper: is_in_scenario = False for source_line in source: if ( - "Scenario: " in source_line - and bpy.context.scene.BIMProperties.scenario == source_line.strip()[len("Scenario: ") :] + "Scenario: " in source_line + and bpy.context.scene.BIMProperties.scenario == source_line.strip()[len("Scenario: "):] ): is_in_scenario = True elif is_in_scenario: @@ -715,7 +716,7 @@ class ActivateBcfViewpoint(bpy.types.Operator): def hex_to_rgb(self, value): value = value.lstrip("#") lv = len(value) - t = tuple(int(value[i : i + lv // 3], 16) for i in range(0, lv, lv // 3)) + t = tuple(int(value[i: i + lv // 3], 16) for i in range(0, lv, lv // 3)) return [t[0] / 255.0, t[1] / 255.0, t[2] / 255.0, 1] @@ -2394,12 +2395,12 @@ class CutSection(bpy.types.Operator): obj.hide_set(True) for obj in bpy.context.visible_objects: if ( - not obj.data - or isinstance(obj.data, bpy.types.Camera) - or "IfcGrid/" in obj.name - or "IfcGridAxis/" in obj.name - or "IfcOpeningElement/" in obj.name - or self.does_obj_have_target_view_representation(obj, camera) + not obj.data + or isinstance(obj.data, bpy.types.Camera) + or "IfcGrid/" in obj.name + or "IfcGridAxis/" in obj.name + or "IfcOpeningElement/" in obj.name + or self.does_obj_have_target_view_representation(obj, camera) ): previous_visibility[obj.name] = obj.hide_get() obj.hide_set(True) @@ -2544,8 +2545,8 @@ class ActivateView(bpy.types.Operator): # We assume a convention that the 'Views' collection is directly # in the project collection if ( - "Views" in project_collection.children - and collection.name in project_collection.children["Views"].children + "Views" in project_collection.children + and collection.name in project_collection.children["Views"].children ): project_collection.children["Views"].children[collection.name].hide_viewport = True bpy.data.collections.get(collection.name).hide_render = True @@ -2604,9 +2605,9 @@ class SwitchContext(bpy.types.Operator): has_context = False for context in self.obj.BIMObjectProperties.representation_contexts: if ( - context.context == self.context - and context.name == self.subcontext - and context.target_view == self.target_view + context.context == self.context + and context.name == self.subcontext + and context.target_view == self.target_view ): has_context = True break @@ -2633,16 +2634,16 @@ class SwitchContext(bpy.types.Operator): for rep in element.Representation.Representations: if ( - rep.ContextOfItems.is_a("IfcGeometricRepresentationSubContext") - and rep.ContextOfItems.ContextType == self.context - and rep.ContextOfItems.ContextIdentifier == self.subcontext - and rep.ContextOfItems.TargetView == self.target_view + rep.ContextOfItems.is_a("IfcGeometricRepresentationSubContext") + and rep.ContextOfItems.ContextType == self.context + and rep.ContextOfItems.ContextIdentifier == self.subcontext + and rep.ContextOfItems.TargetView == self.target_view ): break elif ( - rep.ContextOfItems.is_a("IfcGeometricRepresentationContext") - and rep.ContextOfItems.ContextType == self.context - and rep.ContextOfItems.ContextIdentifier == self.subcontext + rep.ContextOfItems.is_a("IfcGeometricRepresentationContext") + and rep.ContextOfItems.ContextType == self.context + and rep.ContextOfItems.ContextIdentifier == self.subcontext ): break @@ -2977,7 +2978,8 @@ class AddSectionPlane(bpy.types.Operator): section.show_in_front = True if bpy.context.active_object.select_get() and isinstance(bpy.context.active_object.data, bpy.types.Camera): section.matrix_world = ( - bpy.context.active_object.matrix_world @ Euler((radians(180.0), 0.0, 0.0), "XYZ").to_matrix().to_4x4() + bpy.context.active_object.matrix_world @ Euler((radians(180.0), 0.0, 0.0), + "XYZ").to_matrix().to_4x4() ) else: section.rotation_euler = Euler((radians(180.0), 0.0, 0.0), "XYZ") @@ -3394,12 +3396,12 @@ class GenerateReferences(bpy.types.Operator): if self.camera.data.BIMCameraProperties.raster_x > self.camera.data.BIMCameraProperties.raster_y: width = self.camera.data.ortho_scale height = ( - width / self.camera.data.BIMCameraProperties.raster_x * self.camera.data.BIMCameraProperties.raster_y + width / self.camera.data.BIMCameraProperties.raster_x * self.camera.data.BIMCameraProperties.raster_y ) else: height = self.camera.data.ortho_scale width = ( - height / self.camera.data.BIMCameraProperties.raster_y * self.camera.data.BIMCameraProperties.raster_x + height / self.camera.data.BIMCameraProperties.raster_y * self.camera.data.BIMCameraProperties.raster_x ) level_obj = annotation.Annotator.get_annotation_obj("Section Level", "curve") @@ -3585,9 +3587,9 @@ class PushRepresentation(bpy.types.Operator): def is_current_context(self, element): return ( - element.ContextType == self.context - and element.ContextIdentifier == self.subcontext - and element.TargetView == self.target_view + element.ContextType == self.context + and element.ContextIdentifier == self.subcontext + and element.TargetView == self.target_view ) @@ -3678,7 +3680,7 @@ class GuessQuantity(bpy.types.Operator): elif bpy.context.scene.unit_settings.system == "METRIC": if bpy.context.scene.unit_settings.length_unit == "METERS": return None, "METRE" - return bpy.context.scene.unit_settings.length_unit[0 : -len("METERS")], "METRE" + return bpy.context.scene.unit_settings.length_unit[0: -len("METERS")], "METRE" class ExecuteBIMTester(bpy.types.Operator): @@ -3909,7 +3911,7 @@ class ActivateDrawingStyle(bpy.types.Operator): def execute(self, context): if context.scene.camera.data.BIMCameraProperties.active_drawing_style_index < len( - bpy.context.scene.DocProperties.drawing_styles + bpy.context.scene.DocProperties.drawing_styles ): self.drawing_style = bpy.context.scene.DocProperties.drawing_styles[ context.scene.camera.data.BIMCameraProperties.active_drawing_style_index @@ -4187,7 +4189,7 @@ class SetViewportShadowFromSun(bpy.types.Operator): # The vector used for the light direction is a bit funny mat = Matrix(((-1.0, 0.0, 0.0, 0.0), (0.0, 0, 1.0, 0.0), (-0.0, -1.0, 0, 0.0), (0.0, 0.0, 0.0, 1.0))) context.scene.display.light_direction = mat.inverted() @ ( - context.active_object.matrix_world.to_quaternion() @ Vector((0, 0, -1)) + context.active_object.matrix_world.to_quaternion() @ Vector((0, 0, -1)) ) return {"FINISHED"} @@ -4217,6 +4219,57 @@ 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" + index: bpy.props.IntProperty() + guid: bpy.props.StringProperty() + + def execute(self, context): + presentation_layers = bpy.context.scene.BIMProperties.presentation_layers + new = presentation_layers[self.index] + new.assigned_items.items.append(self.guid) + + return {"FINISHED"} + + +class AddPresentationLayer(bpy.types.Operator): + bl_idname = "bim.add_presentation_layer" + bl_label = "Add Presentation Layer" + + _name = 'New Presentation Layer' + descript = 'A Description' + identifier = 'Something' + assigned_items = bpy.props.EnumProperty(items=[]) + layer_on = True + layer_frozen = False + layer_blocked = False + layer_styles = bpy.props.EnumProperty(items=[]) + + def execute(self, context): + new = bpy.context.scene.BIMProperties.presentation_layers.add() + new.name = self._name + new.description = self.descript + new.identifier = self.identifier + new.layer_on = self.layer_on + new.layer_frozen = self.layer_frozen + new.layer_blocked = self.layer_blocked + # new.assigned_items = self.assigned_items + # new.layer_styles = self.layer_styles + + return {"FINISHED"} + + +class RemovePresentationLayer(bpy.types.Operator): + bl_idname = "bim.remove_presentation_layer" + bl_label = "Remove Presentation Layer" + index: bpy.props.IntProperty() + + def execute(self, context): + bpy.context.scene.BIMProperties.presentation_layers.remove(self.index) + return {"FINISHED"} + + class AddDrawingStyleAttribute(bpy.types.Operator): bl_idname = "bim.add_drawing_style_attribute" bl_label = "Add Drawing Style Attribute" @@ -4266,7 +4319,7 @@ class SelectHighPolygonMeshes(bpy.types.Operator): results = {} for obj in bpy.data.objects: if not isinstance(obj.data, bpy.types.Mesh) or len(obj.data.polygons) < int( - bpy.context.scene.BIMDebugProperties.number_of_polygons + bpy.context.scene.BIMDebugProperties.number_of_polygons ): continue try: diff --git a/src/ifcblenderexport/blenderbim/bim/prop.py b/src/ifcblenderexport/blenderbim/bim/prop.py index 7b3740b069..a61c1ac813 100644 --- a/src/ifcblenderexport/blenderbim/bim/prop.py +++ b/src/ifcblenderexport/blenderbim/bim/prop.py @@ -1555,6 +1555,7 @@ class BIMProperties(PropertyGroup): override_colour: FloatVectorProperty( name="Override Colour", subtype="COLOR", default=(1, 0, 0, 1), min=0.0, max=1.0, size=4 ) + active_presentation_layer_index: IntProperty(name="Active Presentation Layer Index") presentation_layers: CollectionProperty(name="Presentation Layers", type=PresentationLayer) @@ -1671,6 +1672,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) + active_presentation_layer_index: IntProperty(name="Active Presentation Layer Index") 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) diff --git a/src/ifcblenderexport/blenderbim/bim/ui.py b/src/ifcblenderexport/blenderbim/bim/ui.py index 7253ce1e6a..fe452b55ad 100644 --- a/src/ifcblenderexport/blenderbim/bim/ui.py +++ b/src/ifcblenderexport/blenderbim/bim/ui.py @@ -219,11 +219,11 @@ class BIM_PT_object_qto(Panel): row.prop(prop, "name", text="") row.prop(prop, "string_value", text="") if ( - "length" in prop.name.lower() - or "width" in prop.name.lower() - or "height" in prop.name.lower() - or "depth" in prop.name.lower() - or "perimeter" in prop.name.lower() + "length" in prop.name.lower() + or "width" in prop.name.lower() + or "height" in prop.name.lower() + or "depth" in prop.name.lower() + or "perimeter" in prop.name.lower() ): op = row.operator("bim.guess_quantity", icon="IPO_EASE_IN_OUT", text="") op.qto_index = index @@ -670,9 +670,9 @@ class BIM_PT_mesh(Panel): @classmethod def poll(cls, context): return ( - context.active_object is not None - and context.active_object.type == "MESH" - and hasattr(context.active_object.data, "BIMMeshProperties") + context.active_object is not None + and context.active_object.type == "MESH" + and hasattr(context.active_object.data, "BIMMeshProperties") ) def draw(self, context): @@ -726,7 +726,7 @@ class BIM_PT_mesh(Panel): row.prop(props, "swept_solids") -class BIM_PT_presentation(Panel): +class BIM_PT_presentation_layer_data(Panel): bl_label = "IFC Presentation Layers" bl_idname = "BIM_PT_presentation" bl_space_type = "PROPERTIES" @@ -736,25 +736,39 @@ class BIM_PT_presentation(Panel): @classmethod def poll(cls, context): return ( - context.active_object is not None - and context.active_object.type == "MESH" - and hasattr(context.active_object.data, "BIMMeshProperties") + context.active_object is not None + and context.active_object.type == "MESH" + and hasattr(context.active_object.data, "BIMMeshProperties") ) def draw(self, context): if not context.active_object.data: return layout = self.layout - props = context.active_object.data.BIMMeshProperties + curr_props = context.active_object.data.BIMMeshProperties.presentation_layer - row = layout.row(align=True) - row.prop(props.presentation_layer, "name") - row = layout.row() - row.prop(props.presentation_layer, "description") - row = layout.row() - row.prop(props.presentation_layer, "identifier") - row = layout.row() - row.prop(props.presentation_layer, "layer_on") + # if len(curr_props.values()) > 0: + + layout.row(align=True).prop(curr_props, "name") + layout.row().prop(curr_props, "description") + layout.row().prop(curr_props, "identifier") + layout.row().prop(curr_props, "layer_on") + layout.row().prop(curr_props, "layer_frozen") + layout.row().prop(curr_props, "layer_blocked") + layout.row().prop(curr_props, "layer_styles") + + props = context.scene.BIMProperties + cur_elem = bpy.context.active_object.BIMObjectProperties + 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 pres_layer.name in bpy.context.scene.BIMProperties.presentation_layers: + op = layout.row().operator("bim.add_to_presentation_layer") + op.index = props.active_presentation_layer_index + op.guid = cur_elem.attributes['GlobalId'].string_value + else: + layout.label(text="Presentation Layer is invalid") class BIM_PT_material(Panel): @@ -873,6 +887,52 @@ class BIM_PT_gis(Panel): row.operator("bim.set_north_offset") +class BIM_PT_presentation_layers(Panel): + bl_label = "IFC Presentation Layers" + bl_idname = "BIM_PT_presentation_layer" + bl_options = {"DEFAULT_CLOSED"} + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "scene" + + def draw(self, context): + layout = self.layout + 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] + + 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, "assigned_items") + 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") + else: + layout.label(text="Presentation Layer is invalid") + + class BIM_PT_drawings(Panel): bl_label = "SVG Drawings" bl_idname = "BIM_PT_drawings" @@ -1576,7 +1636,7 @@ class BIM_PT_bcf(Panel): layout.label(text="Document References:") for index, doc in enumerate(props.topic_document_references): row = layout.row(align=True) - row.prop(doc, "name", text=f"File {index+1} URI") + row.prop(doc, "name", text=f"File {index + 1} URI") if doc.is_external: row.operator("bim.open_bcf_document_reference", icon="URL", text="").data = "{}/{}".format( props.topic_guid, index @@ -1586,7 +1646,7 @@ class BIM_PT_bcf(Panel): props.topic_guid, index ) row = layout.row(align=True) - row.prop(doc, "description", text=f"File {index+1} Description:") + row.prop(doc, "description", text=f"File {index + 1} Description:") layout.label(text="Related Topics:") for topic in props.topic_related_topics: @@ -1933,6 +1993,15 @@ 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