diff --git a/src/ifcblenderexport/blenderbim/bim/__init__.py b/src/ifcblenderexport/blenderbim/bim/__init__.py index 33feb629f2..752f8da2a2 100644 --- a/src/ifcblenderexport/blenderbim/bim/__init__.py +++ b/src/ifcblenderexport/blenderbim/bim/__init__.py @@ -196,6 +196,8 @@ if bpy is not None: operator.SetViewportShadowFromSun, operator.SetNorthOffset, operator.GetNorthOffset, + operator.AddDrawingStyleAttribute, + operator.RemoveDrawingStyleAttribute, prop.StrProperty, prop.Variable, prop.Role, diff --git a/src/ifcblenderexport/blenderbim/bim/cut_ifc.py b/src/ifcblenderexport/blenderbim/bim/cut_ifc.py index 40ee2d24f4..b30cf1596c 100644 --- a/src/ifcblenderexport/blenderbim/bim/cut_ifc.py +++ b/src/ifcblenderexport/blenderbim/bim/cut_ifc.py @@ -1,4 +1,5 @@ import os +import re import math import time import numpy @@ -807,8 +808,17 @@ class IfcCutter: classes = [position, element.is_a()] for association in element.HasAssociations: if association.is_a('IfcRelAssociatesMaterial'): - classes.append('material-{}'.format(self.get_material_name(association.RelatingMaterial))) + classes.append('material-{}'.format( + re.sub('[^0-9a-zA-Z]+', '', self.get_material_name(association.RelatingMaterial)) + )) classes.append('globalid-{}'.format(element.GlobalId)) + for attribute in self.attributes: + result = self.selector.get_element_value(element, attribute) + if result: + classes.append('{}-{}'.format( + re.sub('[^0-9a-zA-Z]+', '', attribute), + re.sub('[^0-9a-zA-Z]+', '', result) + )) return classes def get_material_name(self, element): diff --git a/src/ifcblenderexport/blenderbim/bim/operator.py b/src/ifcblenderexport/blenderbim/bim/operator.py index c30cb533b0..df97bbf790 100644 --- a/src/ifcblenderexport/blenderbim/bim/operator.py +++ b/src/ifcblenderexport/blenderbim/bim/operator.py @@ -2134,7 +2134,8 @@ class CutSection(bpy.types.Operator): import ifccsv ifc_cutter.ifc_filenames = [i.name for i in bpy.context.scene.DocProperties.ifc_files] ifc_cutter.data_dir = bpy.context.scene.BIMProperties.data_dir - ifc_cutter.vector_style = bpy.context.scene.DocProperties.drawing_styles[camera.data.BIMCameraProperties.active_drawing_style_index].vector_style + drawing_style = bpy.context.scene.DocProperties.drawing_styles[camera.data.BIMCameraProperties.active_drawing_style_index] + ifc_cutter.vector_style = drawing_style.vector_style ifc_cutter.diagram_name = self.diagram_name ifc_cutter.background_image = bpy.context.scene.render.filepath if camera.data.BIMCameraProperties.cut_objects == 'CUSTOM': @@ -2153,6 +2154,7 @@ class CutSection(bpy.types.Operator): ifc_cutter.grid_objs = [] ifc_cutter.text_objs = [] ifc_cutter.misc_objs = [] + ifc_cutter.attributes = [a.name for a in drawing_style.attributes] for obj in camera.users_collection[0].objects: if 'IfcGrid' in obj.name: ifc_cutter.grid_objs.append(obj) @@ -3868,3 +3870,24 @@ class GetNorthOffset(bpy.types.Operator): bpy.context.scene.MapConversion.x_axis_abscissa = str(cos(x_angle)) bpy.context.scene.MapConversion.x_axis_ordinate = str(sin(x_angle)) return {'FINISHED'} + + +class AddDrawingStyleAttribute(bpy.types.Operator): + bl_idname = 'bim.add_drawing_style_attribute' + bl_label = 'Add Drawing Style Attribute' + + def execute(self, context): + props = bpy.context.scene.camera.data.BIMCameraProperties + context.scene.DocProperties.drawing_styles[props.active_drawing_style_index].attributes.add() + return {'FINISHED'} + + +class RemoveDrawingStyleAttribute(bpy.types.Operator): + bl_idname = 'bim.remove_drawing_style_attribute' + bl_label = 'Remove Drawing Style Attribute' + index: bpy.props.IntProperty() + + def execute(self, context): + props = bpy.context.scene.camera.data.BIMCameraProperties + context.scene.DocProperties.drawing_styles[props.active_drawing_style_index].attributes.remove(self.index) + return {'FINISHED'} diff --git a/src/ifcblenderexport/blenderbim/bim/prop.py b/src/ifcblenderexport/blenderbim/bim/prop.py index 3ce8c27d64..0a9360f3f2 100644 --- a/src/ifcblenderexport/blenderbim/bim/prop.py +++ b/src/ifcblenderexport/blenderbim/bim/prop.py @@ -521,6 +521,7 @@ class DrawingStyle(PropertyGroup): vector_style: EnumProperty(items=getVectorStyles, name='Vector Style') include_query: StringProperty(name='Include Query') exclude_query: StringProperty(name='Exclude Query') + attributes: CollectionProperty(name='Attributes', type=StrProperty) class DocProperties(PropertyGroup): diff --git a/src/ifcblenderexport/blenderbim/bim/svgwriter.py b/src/ifcblenderexport/blenderbim/bim/svgwriter.py index 0d77b0b584..3663c35379 100644 --- a/src/ifcblenderexport/blenderbim/bim/svgwriter.py +++ b/src/ifcblenderexport/blenderbim/bim/svgwriter.py @@ -1,4 +1,5 @@ import os +import re import bpy import math import pystache @@ -286,6 +287,44 @@ class SvgWriter(): for p in projected_points]) d = 'M{}'.format(d[1:]) path = self.svg.add(self.svg.path(d=d, class_=' '.join(classes))) + + def get_attribute_classes(self, obj): + classes = [] + for attribute in self.ifc_cutter.attributes: + result = self.get_obj_value(obj, attribute) + if result: + classes.append('{}-{}'.format( + re.sub('[^0-9a-zA-Z]+', '', attribute), + re.sub('[^0-9a-zA-Z]+', '', result) + )) + return classes + + def get_obj_value(self, obj, key): + # This is a duplicate implementation of the IFC selector key in Blender + # In the future if all this becomes purely IFC based this can be deleted + if '.' in key \ + and key.split('.')[0] == 'type': + try: + obj = obj.BIMObjectProperties.relating_type + except: + return + key = '.'.join(key.split('.')[1:]) + result = obj.BIMObjectProperties.attributes.get(key) + if result: + return result.string_value + elif key == 'Name': + return obj.name.split('/')[1] + elif '.' in key: + pset_name, prop = key.split('.') + pset = obj.BIMObjectProperties.psets.get(pset_name) + if not pset: + pset = obj.BIMObjectProperties.qtos.get(pset_name) + if not pset: + return + result = pset.properties.get(prop) + if result: + return result.string_value + def draw_line_annotation(self, obj_data, classes): # TODO: properly scope these offsets x_offset = self.raw_width / 2 @@ -306,16 +345,22 @@ class SvgWriter(): d = 'M{}'.format(d[1:]) path = self.svg.add(self.svg.path(d=d, class_=' '.join(classes))) elif isinstance(data, bpy.types.Mesh): - for edge in data.edges: - v0_global = matrix_world @ data.vertices[edge.vertices[0]].co.xyz - v1_global = matrix_world @ data.vertices[edge.vertices[1]].co.xyz - v0 = self.project_point_onto_camera(v0_global) - v1 = self.project_point_onto_camera(v1_global) - start = Vector(((x_offset + v0.x), (y_offset - v0.y))) - end = Vector(((x_offset + v1.x), (y_offset - v1.y))) - vector = end - start - line = self.svg.add(self.svg.line(start=tuple(start * self.scale), - end=tuple(end * self.scale), class_=' '.join(classes))) + self.draw_edge_annotation(obj, classes) + + def draw_edge_annotation(self, obj, classes): + x_offset = self.raw_width / 2 + y_offset = self.raw_height / 2 + matrix_world = obj.matrix_world + for edge in obj.data.edges: + v0_global = matrix_world @ obj.data.vertices[edge.vertices[0]].co.xyz + v1_global = matrix_world @ obj.data.vertices[edge.vertices[1]].co.xyz + v0 = self.project_point_onto_camera(v0_global) + v1 = self.project_point_onto_camera(v1_global) + start = Vector(((x_offset + v0.x), (y_offset - v0.y))) + end = Vector(((x_offset + v1.x), (y_offset - v1.y))) + vector = end - start + line = self.svg.add(self.svg.line(start=tuple(start * self.scale), + end=tuple(end * self.scale), class_=' '.join(classes))) def draw_text_annotations(self): x_offset = self.raw_width / 2 diff --git a/src/ifcblenderexport/blenderbim/bim/ui.py b/src/ifcblenderexport/blenderbim/bim/ui.py index 5ca22e4480..b8dc9bd742 100644 --- a/src/ifcblenderexport/blenderbim/bim/ui.py +++ b/src/ifcblenderexport/blenderbim/bim/ui.py @@ -918,6 +918,14 @@ class BIM_PT_camera(Panel): row = layout.row(align=True) row.prop(drawing_style, 'exclude_query') + row = layout.row() + row.operator('bim.add_drawing_style_attribute') + + for index, attribute in enumerate(drawing_style.attributes): + row = layout.row(align=True) + row.prop(attribute, 'name', text='') + row.operator('bim.remove_drawing_style_attribute', icon='X', text='').index = index + row = layout.row(align=True) row.operator('bim.save_drawing_style') row.operator('bim.activate_drawing_style')