diff --git a/src/ifcblenderexport/blenderbim/bim/__init__.py b/src/ifcblenderexport/blenderbim/bim/__init__.py index f1fc0c50d5..ade06d5ca1 100644 --- a/src/ifcblenderexport/blenderbim/bim/__init__.py +++ b/src/ifcblenderexport/blenderbim/bim/__init__.py @@ -96,6 +96,11 @@ if bpy is not None: operator.OpenView, operator.ActivateView, operator.ExecuteIfcDiff, + operator.AddClashSet, + operator.RemoveClashSet, + operator.AddClashSource, + operator.RemoveClashSource, + operator.SelectClashSource, operator.ExecuteIfcClash, operator.AssignContext, operator.SwitchContext, @@ -138,6 +143,8 @@ if bpy is not None: prop.PropertyTemplate, prop.DocumentInformation, prop.DocumentReference, + prop.ClashSource, + prop.ClashSet, prop.BcfTopic, prop.BcfTopicLabel, prop.BcfTopicFile, @@ -186,6 +193,7 @@ if bpy is not None: ui.BIM_PT_documents, ui.BIM_PT_camera, ui.BIM_PT_text, + ui.BIM_UL_clash_sets, 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 29808647ad..0a2a5db324 100644 --- a/src/ifcblenderexport/blenderbim/bim/operator.py +++ b/src/ifcblenderexport/blenderbim/bim/operator.py @@ -1153,6 +1153,67 @@ class ExecuteIfcDiff(bpy.types.Operator): return {'FINISHED'} +class AddClashSet(bpy.types.Operator): + bl_idname = 'bim.add_clash_set' + bl_label = 'Add Clash Set' + + def execute(self, context): + new = bpy.context.scene.BIMProperties.clash_sets.add() + new.name = 'New Clash Set' + new.tolerance = 0.01 + return {'FINISHED'} + + +class RemoveClashSet(bpy.types.Operator): + bl_idname = 'bim.remove_clash_set' + bl_label = 'Remove Clash Set' + index: bpy.props.IntProperty() + + def execute(self, context): + bpy.context.scene.BIMProperties.clash_sets.remove(self.index) + return {'FINISHED'} + + +class AddClashSource(bpy.types.Operator): + bl_idname = 'bim.add_clash_source' + bl_label = 'Add Clash Source' + group: bpy.props.StringProperty() + + def execute(self, context): + clash_set = bpy.context.scene.BIMProperties.clash_sets[bpy.context.scene.BIMProperties.active_clash_set_index] + source = getattr(clash_set, self.group).add() + return {'FINISHED'} + + +class RemoveClashSource(bpy.types.Operator): + bl_idname = 'bim.remove_clash_source' + bl_label = 'Remove Clash Source' + index: bpy.props.IntProperty() + group: bpy.props.StringProperty() + + def execute(self, context): + clash_set = bpy.context.scene.BIMProperties.clash_sets[bpy.context.scene.BIMProperties.active_clash_set_index] + getattr(clash_set, self.group).remove(self.index) + return {'FINISHED'} + + +class SelectClashSource(bpy.types.Operator): + bl_idname = "bim.select_clash_source" + bl_label = "Select Clash Source" + filepath: bpy.props.StringProperty(subtype="FILE_PATH") + index: bpy.props.IntProperty() + group: bpy.props.StringProperty() + + def execute(self, context): + clash_set = bpy.context.scene.BIMProperties.clash_sets[bpy.context.scene.BIMProperties.active_clash_set_index] + getattr(clash_set, self.group)[self.index].name = self.filepath + return {'FINISHED'} + + def invoke(self, context, event): + context.window_manager.fileselect_add(self) + return {'RUNNING_MODAL'} + + class ExecuteIfcClash(bpy.types.Operator): bl_idname = 'bim.execute_ifc_clash' bl_label = 'Execute IFC Clash' @@ -1172,8 +1233,24 @@ class ExecuteIfcClash(bpy.types.Operator): settings.output = self.filepath settings.logger = logging.getLogger('Clash') settings.logger.setLevel(logging.DEBUG) - ifc_clasher = ifcclash.IfcClasher( - bpy.context.scene.BIMProperties.ifc_clash_a, bpy.context.scene.BIMProperties.ifc_clash_b, settings) + ifc_clasher = ifcclash.IfcClasher(settings) + ifc_clasher.clash_sets = [] + for clash_set in bpy.context.scene.BIMProperties.clash_sets: + self.a = [] + self.b = [] + for ab in ['a', 'b']: + for data in getattr(clash_set, ab): + clash_source = { 'file': data.name } + if data.selector: + clash_source['selector'] = data.selector + clash_source['mode'] = data.mode + getattr(self, ab).append(clash_source) + ifc_clasher.clash_sets.append({ + 'name': clash_set.name, + 'tolerance': clash_set.tolerance, + 'a': self.a, + 'b': self.b + }) ifc_clasher.clash() ifc_clasher.export() return {'FINISHED'} diff --git a/src/ifcblenderexport/blenderbim/bim/prop.py b/src/ifcblenderexport/blenderbim/bim/prop.py index fe89b8702d..84f3173ee7 100644 --- a/src/ifcblenderexport/blenderbim/bim/prop.py +++ b/src/ifcblenderexport/blenderbim/bim/prop.py @@ -467,6 +467,22 @@ class DocumentReference(PropertyGroup): referenced_document: StringProperty(name="Referenced Document") +class ClashSource(PropertyGroup): + name: StringProperty(name='File') + selector: StringProperty(name='Selector') + mode: EnumProperty(items=[ + ('i', 'Include', 'Only the selected objects are included for clashing'), + ('e', 'Exclude', 'All objects except the selected objects are included for clashing') + ], name='Mode') + + +class ClashSet(PropertyGroup): + name: StringProperty(name='Name') + tolerance: FloatProperty(name='Tolerance') + a: CollectionProperty(name='Group A', type=ClashSource) + b: CollectionProperty(name='Group B', type=ClashSource) + + class BcfTopic(PropertyGroup): name: StringProperty(name='Name') @@ -929,8 +945,8 @@ class BIMProperties(PropertyGroup): active_document_information_index: IntProperty(name='Active Document Information Index') document_references: CollectionProperty(name='Document References', type=DocumentReference) active_document_reference_index: IntProperty(name='Active Document Reference Index') - ifc_clash_a: StringProperty(name="IFC Clash A") - ifc_clash_b: StringProperty(name="IFC Clash B") + clash_sets: CollectionProperty(name='Clash Sets', type=ClashSet) + active_clash_set_index: IntProperty(name='Active Clash Set Index') class BCFProperties(PropertyGroup): diff --git a/src/ifcblenderexport/blenderbim/bim/ui.py b/src/ifcblenderexport/blenderbim/bim/ui.py index 00e6f8e80d..97e89e6f88 100644 --- a/src/ifcblenderexport/blenderbim/bim/ui.py +++ b/src/ifcblenderexport/blenderbim/bim/ui.py @@ -1225,6 +1225,15 @@ class BIM_UL_topics(bpy.types.UIList): layout.label(text="", translate=False) +class BIM_UL_clash_sets(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 @@ -1284,16 +1293,64 @@ class BIM_PT_ifcclash(Panel): def draw(self, context): layout = self.layout - layout.use_property_split = True scene = context.scene props = scene.BIMProperties - row = layout.row(align=True) - row.prop(props, 'ifc_clash_a') - - row = layout.row(align=True) - row.prop(props, 'ifc_clash_b') - row = layout.row() - row.operator('bim.execute_ifc_clash') + row.operator('bim.add_clash_set') + + if not props.clash_sets: + return + + layout.template_list('BIM_UL_clash_sets', '', props, 'clash_sets', props, 'active_clash_set_index') + + if props.active_clash_set_index < len(props.clash_sets): + clash_set = props.clash_sets[props.active_clash_set_index] + + row = layout.row(align=True) + row.prop(clash_set, 'name') + row.operator('bim.remove_clash_set', icon='X', text='').index = props.active_clash_set_index + + row = layout.row(align=True) + row.prop(clash_set, 'tolerance') + + layout.label(text="Group A:") + row = layout.row() + row.operator('bim.add_clash_source').group = 'a' + + for index, source in enumerate(clash_set.a): + row = layout.row(align=True) + row.prop(source, 'name', text='') + op = row.operator('bim.select_clash_source', icon='FILE_FOLDER', text='') + op.index = index + op.group = 'a' + op = row.operator('bim.remove_clash_source', icon='X', text='') + op.index = index + op.group = 'a' + + row = layout.row(align=True) + row.prop(source, 'mode', text='') + row.prop(source, 'selector', text='') + + layout.label(text="Group B:") + row = layout.row() + row.operator('bim.add_clash_source').group = 'b' + + for index, source in enumerate(clash_set.b): + row = layout.row(align=True) + row.prop(source, 'name', text='') + op = row.operator('bim.select_clash_source', icon='FILE_FOLDER', text='') + op.index = index + op.group = 'b' + op = row.operator('bim.remove_clash_source', icon='X', text='') + op.index = index + op.group = 'b' + + row = layout.row(align=True) + row.prop(source, 'mode', text='') + row.prop(source, 'selector', text='') + + row = layout.row() + row.operator('bim.execute_ifc_clash') + diff --git a/src/ifcclash/ifcclash.py b/src/ifcclash/ifcclash.py index 810c5080e7..a74d9979ce 100755 --- a/src/ifcclash/ifcclash.py +++ b/src/ifcclash/ifcclash.py @@ -83,14 +83,11 @@ class IfcClasher: for result in results: del result['a_cm'] del result['b_cm'] - for data in result['a']: - del data['ifc'] - del data['meshes'] - for data in result['b']: - del data['ifc'] - del data['meshes'] - print(results) - + for ab in ['a', 'b']: + for data in result[ab]: + for key in ['ifc', 'meshes']: + if key in data: + del data[key] with open(self.settings.output, 'w', encoding='utf-8') as clashes_file: json.dump(results, clashes_file, indent=4)