diff --git a/src/ifcblenderexport/io_export_ifc/__init__.py b/src/ifcblenderexport/io_export_ifc/__init__.py index 1e4b1008f3..b023d640b1 100644 --- a/src/ifcblenderexport/io_export_ifc/__init__.py +++ b/src/ifcblenderexport/io_export_ifc/__init__.py @@ -31,9 +31,14 @@ classes = ( operator.SelectAudited, operator.RejectElement, operator.SelectExternalMaterialDir, + operator.AddSweptSolid, + operator.RemoveSweptSolid, operator.AssignSweptSolidOuterCurve, + operator.SelectSweptSolidOuterCurve, operator.AddSweptSolidInnerCurve, + operator.SelectSweptSolidInnerCurves, operator.AssignSweptSolidExtrusion, + operator.SelectSweptSolidExtrusion, operator.AssignPset, operator.UnassignPset, operator.AddPset, @@ -61,6 +66,7 @@ classes = ( ui.GlobalId, ui.BIMObjectProperties, ui.BIMMaterialProperties, + ui.SweptSolid, ui.BIMMeshProperties, ui.GISPanel, ui.BIMPanel, diff --git a/src/ifcblenderexport/io_export_ifc/export_ifc.py b/src/ifcblenderexport/io_export_ifc/export_ifc.py index 1ba1c10132..0070213c26 100644 --- a/src/ifcblenderexport/io_export_ifc/export_ifc.py +++ b/src/ifcblenderexport/io_export_ifc/export_ifc.py @@ -1397,50 +1397,40 @@ class IfcExporter(): def create_swept_solid_representation(self, representation): object = representation['raw_object'] mesh = representation['raw'] - outer_curve_index = None - inner_curve_indices = [] - extrusion_index = None + items = [] + for swept_solid in mesh.BIMMeshProperties.swept_solids: + extrusion_edge = self.get_edges_in_v_indices(object, json.loads(swept_solid.extrusion))[0] - for index, vg in enumerate(object.vertex_groups): - if vg.name == 'outer-curve': - outer_curve_index = index - elif 'inner-curve' in vg.name: - inner_curve_indices.append(index) - elif vg.name == 'extrusion': - extrusion_index = index + inner_curves = [] + if swept_solid.inner_curves: + for indices in json.loads(swept_solid.inner_curves): + loop = self.get_loop_from_v_indices(object, indices) + curve_ucs = self.get_curve_profile_coordinate_system(object, loop) + inner_curves.append( + self.create_polyline_from_loop(object, loop, curve_ucs)) - extrusion_edge = self.get_edges_in_vg_index(object, extrusion_index)[0] + outer_curve_loop = self.get_loop_from_v_indices(object, json.loads(swept_solid.outer_curve)) + curve_ucs = self.get_curve_profile_coordinate_system(object, outer_curve_loop) + outer_curve = self.create_polyline_from_loop(object, outer_curve_loop, curve_ucs) - inner_curves = [] - for index in inner_curve_indices: - loop = self.get_loop_from_vg_index(object, index) - curve_ucs = self.get_curve_profile_coordinate_system(object, loop) - inner_curves.append( - self.create_polyline_from_loop(object, loop, curve_ucs)) + if inner_curves: + curve = self.file.createIfcArbitraryProfileDefWithVoids('AREA', None, + outer_curve, inner_curves) + else: + curve = self.file.createIfcArbitraryClosedProfileDef('AREA', None, outer_curve) - outer_curve_loop = self.get_loop_from_vg_index(object, outer_curve_index) - curve_ucs = self.get_curve_profile_coordinate_system(object, outer_curve_loop) - outer_curve = self.create_polyline_from_loop(object, outer_curve_loop, curve_ucs) + direction = self.get_extrusion_direction(object, outer_curve_loop, extrusion_edge, curve_ucs) + unit_direction = direction.normalized() + position = self.create_ifc_axis_2_placement_3d( + curve_ucs['center'], curve_ucs['z_axis'], curve_ucs['x_axis']) - if inner_curves: - curve = self.file.createIfcArbitraryProfileDefWithVoids('AREA', None, - outer_curve, inner_curves) - else: - curve = self.file.createIfcArbitraryClosedProfileDef('AREA', None, outer_curve) - - direction = self.get_extrusion_direction(object, outer_curve_loop, extrusion_edge, curve_ucs) - unit_direction = direction.normalized() - position = self.create_ifc_axis_2_placement_3d( - curve_ucs['center'], curve_ucs['z_axis'], curve_ucs['x_axis']) - - extruded_area_solid = self.file.createIfcExtrudedAreaSolid( - curve, position, self.file.createIfcDirection(( - unit_direction.x, unit_direction.y, unit_direction.z)), - self.convert_si_to_unit(direction.length)) + items.append(self.file.createIfcExtrudedAreaSolid( + curve, position, self.file.createIfcDirection(( + unit_direction.x, unit_direction.y, unit_direction.z)), + self.convert_si_to_unit(direction.length))) return self.file.createIfcShapeRepresentation( self.ifc_rep_context[representation['context']][representation['subcontext']][representation['target_view']]['ifc'], - representation['subcontext'], 'SweptSolid', - [extruded_area_solid]) + representation['subcontext'], 'SweptSolid', items) def get_start_and_end_of_extrusion(self, profile_points, extrusion_edge): if extrusion_edge.vertices[0] in profile_points: @@ -1483,17 +1473,15 @@ class IfcExporter(): start, end = self.get_start_and_end_of_extrusion(outer_curve_loop, extrusion_edge) return curve_ucs['matrix'] @ (curve_ucs['center'] + (object.data.vertices[end].co - object.data.vertices[start].co)) - def get_loop_from_vg_index(self, object, vg_index): - edges = self.get_edges_in_vg_index(object, vg_index) + def get_loop_from_v_indices(self, object, indices): + edges = self.get_edges_in_v_indices(object, indices) loop = self.get_loop_from_edges(edges) loop.pop(-1) return loop - def get_edges_in_vg_index(self, object, index): + def get_edges_in_v_indices(self, object, indices): return [ e for e in object.data.edges if ( - index in [ g.group for g in object.data.vertices[e.vertices[0]].groups ] and - index in [ g.group for g in object.data.vertices[e.vertices[1]].groups ] - ) ] + e.vertices[0] in indices and e.vertices[1] in indices) ] def get_loop_from_edges(self, edges): while edges: diff --git a/src/ifcblenderexport/io_export_ifc/operator.py b/src/ifcblenderexport/io_export_ifc/operator.py index 1fa1edfa70..56ad699411 100644 --- a/src/ifcblenderexport/io_export_ifc/operator.py +++ b/src/ifcblenderexport/io_export_ifc/operator.py @@ -1,5 +1,6 @@ import bpy import time +import json import logging from . import ifcopenshell from . import export_ifc @@ -343,47 +344,127 @@ class RemoveAttribute(bpy.types.Operator): bpy.context.active_object.BIMObjectProperties.attributes.remove(self.attribute_index) return {'FINISHED'} +class AddSweptSolid(bpy.types.Operator): + bl_idname = 'bim.add_swept_solid' + bl_label = 'Add Swept Solid' + + def execute(self, context): + swept_solids = bpy.context.active_object.data.BIMMeshProperties.swept_solids + swept_solid = swept_solids.add() + swept_solid.name = 'Swept Solid {}'.format(len(swept_solids)) + return {'FINISHED'} + +class RemoveSweptSolid(bpy.types.Operator): + bl_idname = 'bim.remove_swept_solid' + bl_label = 'Remove Swept Solid' + index: bpy.props.IntProperty() + + def execute(self, context): + bpy.context.active_object.data.BIMMeshProperties.swept_solids.remove(self.index) + return {'FINISHED'} + class AssignSweptSolidOuterCurve(bpy.types.Operator): bl_idname = 'bim.assign_swept_solid_outer_curve' bl_label = 'Assign Outer Curve' + index: bpy.props.IntProperty() def execute(self, context): if bpy.context.mode != 'EDIT_MESH': return {'FINISHED'} - for vg in bpy.context.active_object.vertex_groups: - if vg.name == 'outer-curve': - bpy.ops.object.vertex_group_set_active(group=vg.name) - bpy.ops.object.vertex_group_remove() - break - bpy.ops.object.vertex_group_assign_new() - bpy.context.active_object.vertex_groups[bpy.context.active_object.vertex_groups[-1].name].name = 'outer-curve' + bpy.ops.object.mode_set(mode='OBJECT') + bpy.ops.object.mode_set(mode='EDIT') + vertices = [v.index for v in bpy.context.active_object.data.vertices if v.select == True] + print(vertices) + bpy.context.active_object.data.BIMMeshProperties.swept_solids[self.index].outer_curve = json.dumps(vertices) + return {'FINISHED'} + +class SelectSweptSolidOuterCurve(bpy.types.Operator): + bl_idname = 'bim.select_swept_solid_outer_curve' + bl_label = 'Select Outer Curve' + index: bpy.props.IntProperty() + + def execute(self, context): + if bpy.context.mode != 'EDIT_MESH': + return {'FINISHED'} + bpy.ops.object.mode_set(mode='OBJECT') + outer_curve = bpy.context.active_object.data.BIMMeshProperties.swept_solids[self.index].outer_curve + if not outer_curve: + return {'FINISHED'} + indices = json.loads(outer_curve) + for index in indices: + bpy.context.active_object.data.vertices[index].select = True + bpy.ops.object.mode_set(mode='EDIT') return {'FINISHED'} class AddSweptSolidInnerCurve(bpy.types.Operator): bl_idname = 'bim.add_swept_solid_inner_curve' bl_label = 'Add Inner Curve' + index: bpy.props.IntProperty() def execute(self, context): if bpy.context.mode != 'EDIT_MESH': return {'FINISHED'} - bpy.ops.object.vertex_group_assign_new() - bpy.context.active_object.vertex_groups[bpy.context.active_object.vertex_groups[-1].name].name = 'inner-curve' + bpy.ops.object.mode_set(mode='OBJECT') + bpy.ops.object.mode_set(mode='EDIT') + vertices = [v.index for v in bpy.context.active_object.data.vertices if v.select == True] + swept_solid = bpy.context.active_object.data.BIMMeshProperties.swept_solids[self.index] + if swept_solid.inner_curves: + curves = json.loads(swept_solid.inner_curves) + else: + curves = [] + curves.append(vertices) + swept_solid.inner_curves = json.dumps(curves) + return {'FINISHED'} + +class SelectSweptSolidInnerCurves(bpy.types.Operator): + bl_idname = 'bim.select_swept_solid_inner_curves' + bl_label = 'Select Inner Curves' + index: bpy.props.IntProperty() + + def execute(self, context): + if bpy.context.mode != 'EDIT_MESH': + return {'FINISHED'} + bpy.ops.object.mode_set(mode='OBJECT') + inner_curves = bpy.context.active_object.data.BIMMeshProperties.swept_solids[self.index].inner_curves + if not inner_curves: + return {'FINISHED'} + curves = json.loads(inner_curves) + for curve in curves: + for index in curve: + bpy.context.active_object.data.vertices[index].select = True + bpy.ops.object.mode_set(mode='EDIT') return {'FINISHED'} class AssignSweptSolidExtrusion(bpy.types.Operator): bl_idname = 'bim.assign_swept_solid_extrusion' bl_label = 'Assign Extrusion' + index: bpy.props.IntProperty() def execute(self, context): if bpy.context.mode != 'EDIT_MESH': return {'FINISHED'} - for vg in bpy.context.active_object.vertex_groups: - if vg.name == 'extrusion': - bpy.ops.object.vertex_group_set_active(group=vg.name) - bpy.ops.object.vertex_group_remove() - break - bpy.ops.object.vertex_group_assign_new() - bpy.context.active_object.vertex_groups[bpy.context.active_object.vertex_groups[-1].name].name = 'extrusion' + bpy.ops.object.mode_set(mode='OBJECT') + bpy.ops.object.mode_set(mode='EDIT') + vertices = [v.index for v in bpy.context.active_object.data.vertices if v.select == True] + bpy.context.active_object.data.BIMMeshProperties.swept_solids[self.index].extrusion = json.dumps(vertices) + return {'FINISHED'} + +class SelectSweptSolidExtrusion(bpy.types.Operator): + bl_idname = 'bim.select_swept_solid_extrusion' + bl_label = 'Select Extrusion' + index: bpy.props.IntProperty() + + def execute(self, context): + if bpy.context.mode != 'EDIT_MESH': + return {'FINISHED'} + bpy.ops.object.mode_set(mode='OBJECT') + extrusion = bpy.context.active_object.data.BIMMeshProperties.swept_solids[self.index].extrusion + if not extrusion: + return {'FINISHED'} + indices = json.loads(extrusion) + for index in indices: + bpy.context.active_object.data.vertices[index].select = True + bpy.ops.object.mode_set(mode='EDIT') return {'FINISHED'} class SelectExternalMaterialDir(bpy.types.Operator): diff --git a/src/ifcblenderexport/io_export_ifc/ui.py b/src/ifcblenderexport/io_export_ifc/ui.py index 751e41a71a..ea51fc9049 100644 --- a/src/ifcblenderexport/io_export_ifc/ui.py +++ b/src/ifcblenderexport/io_export_ifc/ui.py @@ -147,9 +147,16 @@ class BIMMaterialProperties(bpy.types.PropertyGroup): identification: bpy.props.StringProperty(name="Identification") name: bpy.props.StringProperty(name="Name") +class SweptSolid(bpy.types.PropertyGroup): + name: bpy.props.StringProperty(name="Name") + outer_curve: bpy.props.StringProperty(name="Outer Curve") + inner_curves: bpy.props.StringProperty(name="Inner Curves") + extrusion: bpy.props.StringProperty(name="Extrusion") + class BIMMeshProperties(bpy.types.PropertyGroup): is_wireframe: bpy.props.BoolProperty(name="Is Wireframe") is_swept_solid: bpy.props.BoolProperty(name="Is Swept Solid") + swept_solids: bpy.props.CollectionProperty(name="Swept Solids", type=SweptSolid) class ObjectPanel(bpy.types.Panel): bl_label = 'IFC Object' @@ -175,7 +182,7 @@ class ObjectPanel(bpy.types.Panel): row = layout.row(align=True) row.prop(attribute, 'name', text='') row.prop(attribute, 'string_value', text='') - row.operator('bim.remove_attribute', icon='CANCEL', text='').attribute_index = index + row.operator('bim.remove_attribute', icon='X', text='').attribute_index = index row = layout.row() row.prop(bpy.context.active_object.BIMObjectProperties, 'attributes') @@ -188,7 +195,7 @@ class ObjectPanel(bpy.types.Panel): row = layout.row(align=True) row.prop(pset, 'name', text='') row.prop(pset, 'file', text='') - row.operator('bim.remove_pset', icon='CANCEL', text='').pset_index = index + row.operator('bim.remove_pset', icon='X', text='').pset_index = index row = layout.row() row.prop(bpy.context.active_object.BIMObjectProperties, 'psets') @@ -201,7 +208,7 @@ class ObjectPanel(bpy.types.Panel): for index, document in enumerate(bpy.context.active_object.BIMObjectProperties.documents): row = layout.row(align=True) row.prop(document, 'file', text='') - row.operator('bim.remove_document', icon='CANCEL', text='').document_index = index + row.operator('bim.remove_document', icon='X', text='').document_index = index row = layout.row() row.prop(bpy.context.active_object.BIMObjectProperties, 'documents') @@ -212,7 +219,7 @@ class ObjectPanel(bpy.types.Panel): row = layout.row(align=True) row.prop(classification, 'identification', text='') row.prop(classification, 'name', text='') - row.operator('bim.remove_classification', icon='CANCEL', text='').classification_index = index + row.operator('bim.remove_classification', icon='X', text='').classification_index = index row = layout.row() row.prop(bpy.context.active_object.BIMObjectProperties, 'classifications') @@ -233,11 +240,25 @@ class MeshPanel(bpy.types.Panel): row.prop(bpy.context.active_object.data.BIMMeshProperties, 'is_wireframe') row = layout.row() row.prop(bpy.context.active_object.data.BIMMeshProperties, 'is_swept_solid') - row = layout.row(align=True) - row.operator('bim.assign_swept_solid_outer_curve') - row.operator('bim.add_swept_solid_inner_curve') + row = layout.row() - row.operator('bim.assign_swept_solid_extrusion') + row.operator('bim.add_swept_solid') + for index, swept_solid in enumerate(bpy.context.active_object.data.BIMMeshProperties.swept_solids): + row = layout.row(align=True) + row.prop(swept_solid, 'name', text='') + row.operator('bim.remove_swept_solid', icon='X', text='').index = index + row = layout.row() + sub = row.row(align=True) + sub.operator('bim.assign_swept_solid_outer_curve').index = index + sub.operator('bim.select_swept_solid_outer_curve', icon='RESTRICT_SELECT_OFF', text='').index = index + sub = row.row(align=True) + sub.operator('bim.add_swept_solid_inner_curve').index = index + sub.operator('bim.select_swept_solid_inner_curves', icon='RESTRICT_SELECT_OFF', text='').index = index + row = layout.row(align=True) + row.operator('bim.assign_swept_solid_extrusion').index = index + row.operator('bim.select_swept_solid_extrusion', icon='RESTRICT_SELECT_OFF', text='').index = index + row = layout.row() + row.prop(bpy.context.active_object.data.BIMMeshProperties, 'swept_solids') class MaterialPanel(bpy.types.Panel): bl_label = 'IFC Materials'