diff --git a/src/ifcblenderexport/blenderbim/bim/__init__.py b/src/ifcblenderexport/blenderbim/bim/__init__.py index a97648852a..09f4605c05 100644 --- a/src/ifcblenderexport/blenderbim/bim/__init__.py +++ b/src/ifcblenderexport/blenderbim/bim/__init__.py @@ -55,8 +55,11 @@ if bpy is not None: operator.RemoveMaterialPset, operator.AddDocumentInformation, operator.RemoveDocumentInformation, - operator.AddDocument, - operator.RemoveDocument, + operator.AddDocumentReference, + operator.RemoveDocumentReference, + operator.AssignDocumentReference, + operator.UnassignDocumentReference, + operator.RemoveObjectDocumentReference, operator.GenerateGlobalId, operator.AddAttribute, operator.RemoveAttribute, @@ -119,6 +122,7 @@ if bpy is not None: prop.PropertySetTemplate, prop.PropertyTemplate, prop.DocumentInformation, + prop.DocumentReference, prop.BcfTopic, prop.BcfTopicLabel, prop.BcfTopicFile, @@ -135,7 +139,6 @@ if bpy is not None: prop.Attribute, prop.BoundaryCondition, prop.PsetQto, - prop.Document, prop.GlobalId, prop.BIMObjectProperties, prop.BIMMaterialProperties, @@ -165,6 +168,7 @@ if bpy is not None: ui.BIM_PT_documents, ui.BIM_PT_camera, ui.BIM_UL_document_information, + ui.BIM_UL_document_references, ui.BIM_UL_topics, ui.BIM_UL_classifications, ui.BIM_ADDON_preferences, diff --git a/src/ifcblenderexport/blenderbim/bim/data/doc/foo/bar.pdf b/src/ifcblenderexport/blenderbim/bim/data/doc/foo/bar.pdf deleted file mode 100644 index 774c2ea70c..0000000000 Binary files a/src/ifcblenderexport/blenderbim/bim/data/doc/foo/bar.pdf and /dev/null differ diff --git a/src/ifcblenderexport/blenderbim/bim/data/doc/proxy.opass b/src/ifcblenderexport/blenderbim/bim/data/doc/proxy.opass deleted file mode 100644 index c2dcd24e5f..0000000000 --- a/src/ifcblenderexport/blenderbim/bim/data/doc/proxy.opass +++ /dev/null @@ -1,6 +0,0 @@ -{ - "blender": { - "uri": "high-res.blend", - "identification": "high-res" - } -} diff --git a/src/ifcblenderexport/blenderbim/bim/data/doc/test.pdf b/src/ifcblenderexport/blenderbim/bim/data/doc/test.pdf deleted file mode 100644 index 774c2ea70c..0000000000 Binary files a/src/ifcblenderexport/blenderbim/bim/data/doc/test.pdf and /dev/null differ diff --git a/src/ifcblenderexport/blenderbim/bim/export_ifc.py b/src/ifcblenderexport/blenderbim/bim/export_ifc.py index af436a28c9..17682cb0d3 100644 --- a/src/ifcblenderexport/blenderbim/bim/export_ifc.py +++ b/src/ifcblenderexport/blenderbim/bim/export_ifc.py @@ -88,7 +88,7 @@ class IfcParser(): self.people = [] self.organisations = [] self.psets = {} - self.documents = {} + self.document_references = {} self.classifications = [] self.classification_references = {} self.objectives = {} @@ -138,7 +138,7 @@ class IfcParser(): self.categorise_selected_objects(unique_objects) self.material_psets = self.get_material_psets() self.document_information = self.get_document_information() - self.documents = self.get_documents() + self.document_references = self.get_document_references() self.classifications = self.get_classifications() self.classification_references = self.get_classification_references() self.objectives = self.get_objectives() @@ -453,9 +453,9 @@ class IfcParser(): self.get_product_psets_qtos(product, obj, is_pset=True) self.get_product_psets_qtos(product, obj, is_qto=True) - for document in obj.BIMObjectProperties.documents: + for reference in obj.BIMObjectProperties.document_references: self.rel_associates_document_object.setdefault( - document.file, []).append(product) + reference.name, []).append(product) for classification in obj.BIMObjectProperties.classifications: self.rel_associates_classification_object.setdefault( @@ -673,19 +673,25 @@ class IfcParser(): with open(self.data_dir + 'owner/organisation.json') as file: return [{'raw': o} for o in json.load(file)] - def get_documents(self): - documents = {} - doc_path = self.data_dir + 'doc/' - for filename in Path(doc_path).glob('**/*'): - uri = str(filename.relative_to(doc_path).as_posix()) - documents[uri] = { + def get_document_references(self): + results = {} + for reference in bpy.context.scene.BIMProperties.document_references: + data_map = { + 'name': 'Identification', + 'human_name': 'Name', + 'description': 'Description', + 'location': 'Location' + } + attributes = {} + for key, value in data_map.items(): + if getattr(reference, key): + attributes[value] = getattr(reference, key) + results[reference.name] = { 'ifc': None, - 'raw': filename, - 'attributes': { - 'Location': uri, - 'Name': filename.stem - }} - return documents + 'raw': reference, + 'attributes': attributes + } + return results def get_document_information(self): results = {} @@ -1140,7 +1146,7 @@ class IfcExporter(): self.create_project() self.create_library_information() self.create_document_information() - self.create_documents() + self.create_document_references() self.create_classifications() self.create_classification_references() self.create_objectives() @@ -1339,13 +1345,13 @@ class IfcExporter(): information['ifc'] = self.file.create_entity( 'IfcDocumentInformation', **information['attributes']) - def create_documents(self): - for document in self.ifc_parser.documents.values(): - document['ifc'] = self.file.create_entity( - 'IfcDocumentReference', **document['attributes']) + def create_document_references(self): + for reference in self.ifc_parser.document_references.values(): + reference['ifc'] = self.file.create_entity( + 'IfcDocumentReference', **reference['attributes']) self.file.createIfcRelAssociatesDocument( ifcopenshell.guid.new(), None, None, None, - [self.ifc_parser.project['ifc']], document['ifc']) + [self.ifc_parser.project['ifc']], reference['ifc']) def create_classifications(self): for classification in self.ifc_parser.classifications.values(): @@ -2431,7 +2437,7 @@ class IfcExporter(): self.file.createIfcRelAssociatesDocument( ifcopenshell.guid.new(), self.owner_history, None, None, [o['ifc'] for o in related_objects], - self.ifc_parser.documents[relating_document_key]['ifc']) + self.ifc_parser.document_references[relating_document_key]['ifc']) def relate_to_classifications(self, relationships): for relating_key, related_objects in relationships.items(): diff --git a/src/ifcblenderexport/blenderbim/bim/import_ifc.py b/src/ifcblenderexport/blenderbim/bim/import_ifc.py index 2a779e583c..432d02f98b 100644 --- a/src/ifcblenderexport/blenderbim/bim/import_ifc.py +++ b/src/ifcblenderexport/blenderbim/bim/import_ifc.py @@ -224,6 +224,7 @@ class IfcImporter(): self.calculate_unit_scale() self.create_project() self.create_classifications() + self.create_document_references() self.create_spatial_hierarchy() self.purge_diff() self.create_type_products() @@ -749,6 +750,19 @@ class IfcImporter(): results.extend(self.file.get_inverse(reference)) return results + def create_document_references(self): + for data in self.file.by_type('IfcDocumentReference'): + reference = bpy.context.scene.BIMProperties.document_references.add() + data_map = { + 'location': 'Location', + 'name': 'Identification', + 'human_name': 'Name', + 'description': 'Description' + } + for key, value in data_map.items(): + if hasattr(data, value) and getattr(data, value): + setattr(reference, key, getattr(data, value)) + def create_spatial_hierarchy(self): if self.project['ifc'].IsDecomposedBy: for rel_aggregate in self.project['ifc'].IsDecomposedBy: @@ -857,18 +871,8 @@ class IfcImporter(): def add_element_document_relations(self, element, obj): for association in element.HasAssociations: if association.is_a('IfcRelAssociatesDocument'): - data = association.RelatingDocument - document = obj.BIMObjectProperties.documents.add() - data_map = { - 'file': 'Location', - 'location': 'Location', - 'identification': 'Identification', - 'name': 'Name', - 'description': 'Description' - } - for key, value in data_map.items(): - if hasattr(data, value) and getattr(data, value): - setattr(document, key, getattr(data, value)) + reference = obj.BIMObjectProperties.document_references.add() + reference.name = association.RelatingDocument.Identification def place_objects_in_spatial_tree(self): for global_id, obj in self.added_data.items(): diff --git a/src/ifcblenderexport/blenderbim/bim/operator.py b/src/ifcblenderexport/blenderbim/bim/operator.py index 508401d110..4f59b2ad5a 100644 --- a/src/ifcblenderexport/blenderbim/bim/operator.py +++ b/src/ifcblenderexport/blenderbim/bim/operator.py @@ -792,22 +792,90 @@ class RemoveMaterialPset(bpy.types.Operator): return {'FINISHED'} -class AddDocument(bpy.types.Operator): - bl_idname = 'bim.add_document' - bl_label = 'Add Document' +class AddDocumentInformation(bpy.types.Operator): + bl_idname = 'bim.add_document_information' + bl_label = 'Add Document Information' def execute(self, context): - document = bpy.context.active_object.BIMObjectProperties.documents.add() - document.file = bpy.context.active_object.BIMObjectProperties.applicable_documents + info = bpy.context.scene.BIMProperties.document_information.add() + info.name = 'New Document ID' return {'FINISHED'} -class RemoveDocument(bpy.types.Operator): - bl_idname = 'bim.remove_document' - bl_label = 'Remove Document' - document_index: bpy.props.IntProperty() + +class RemoveDocumentInformation(bpy.types.Operator): + bl_idname = 'bim.remove_document_information' + bl_label = 'Remove Document Information' + index: bpy.props.IntProperty() def execute(self, context): - bpy.context.active_object.BIMObjectProperties.documents.remove(self.document_index) + bpy.context.scene.BIMProperties.document_information.remove(self.index) + return {'FINISHED'} + + +class AddDocumentReference(bpy.types.Operator): + bl_idname = 'bim.add_document_reference' + bl_label = 'Add Document Reference' + + def execute(self, context): + document = bpy.context.scene.BIMProperties.document_references.add() + document.name = 'New Document Reference ID' + return {'FINISHED'} + + +class RemoveDocumentReference(bpy.types.Operator): + bl_idname = 'bim.remove_document_reference' + bl_label = 'Remove Document Reference' + index: bpy.props.IntProperty() + + def execute(self, context): + bpy.context.scene.BIMProperties.document_references.remove(self.index) + return {'FINISHED'} + + +class RemoveObjectDocumentReference(bpy.types.Operator): + bl_idname = 'bim.remove_object_document_reference' + bl_label = 'Remove Object Document Reference' + index: bpy.props.IntProperty() + + def execute(self, context): + bpy.context.active_object.BIMObjectProperties.document_references.remove(self.index) + return {'FINISHED'} + + +class AssignDocumentReference(bpy.types.Operator): + bl_idname = 'bim.assign_document_reference' + bl_label = 'Assign Document Reference' + + def execute(self, context): + identification = bpy.context.scene.BIMProperties.document_references[bpy.context.scene.BIMProperties.active_document_reference_index].name + for obj in bpy.context.selected_objects: + if obj.BIMObjectProperties.document_references.get(identification): + continue + reference = obj.BIMObjectProperties.document_references.add() + reference.name = identification + return {'FINISHED'} + + +class UnassignDocumentReference(bpy.types.Operator): + bl_idname = 'bim.unassign_document_reference' + bl_label = 'Unassign Document Reference' + + def execute(self, context): + identification = bpy.context.scene.BIMProperties.document_references[bpy.context.scene.BIMProperties.active_document_reference_index].name + for obj in bpy.context.selected_objects: + index = obj.BIMObjectProperties.document_references.find(identification) + if index >= 0: + obj.BIMObjectProperties.document_references.remove(index) + return {'FINISHED'} + + +class RemoveObjectDocumentReference(bpy.types.Operator): + bl_idname = 'bim.remove_object_document_reference' + bl_label = 'Remove Object Document Reference' + index: bpy.props.IntProperty() + + def execute(self, context): + bpy.context.active_object.BIMObjectProperties.document_references.remove(self.index) return {'FINISHED'} class GenerateGlobalId(bpy.types.Operator): @@ -2236,22 +2304,3 @@ class SelectSimilarType(bpy.types.Operator): if obj.BIMObjectProperties.relating_type == relating_type: obj.select_set(True) return {'FINISHED'} - - -class AddDocumentInformation(bpy.types.Operator): - bl_idname = 'bim.add_document_information' - bl_label = 'Add Document Information' - - def execute(self, context): - info = bpy.context.scene.BIMProperties.document_information.add() - info.name = 'New Document ID' - return {'FINISHED'} - -class RemoveDocumentInformation(bpy.types.Operator): - bl_idname = 'bim.remove_document_information' - bl_label = 'Remove Document Information' - index: bpy.props.IntProperty() - - def execute(self, context): - bpy.context.scene.BIMProperties.document_information.remove(self.index) - return {'FINISHED'} diff --git a/src/ifcblenderexport/blenderbim/bim/prop.py b/src/ifcblenderexport/blenderbim/bim/prop.py index c940c648a7..521530052c 100644 --- a/src/ifcblenderexport/blenderbim/bim/prop.py +++ b/src/ifcblenderexport/blenderbim/bim/prop.py @@ -40,7 +40,6 @@ attributes_enum = [] psetnames_enum = [] qtonames_enum = [] materialattributes_enum = [] -documents_enum = [] materialtypes_enum = [] contexts_enum = [] subcontexts_enum = [] @@ -309,16 +308,6 @@ def refreshProfileAttributes(self, context): profile_attribute.name = attribute['name'] -def getApplicableDocuments(self, context): - global documents_enum - documents_enum.clear() - doc_path = os.path.join(context.scene.BIMProperties.data_dir, 'doc') - for filename in Path(doc_path).glob('**/*'): - uri = str(filename.relative_to(doc_path).as_posix()) - documents_enum.append((uri, uri, '')) - return documents_enum - - def getMaterialTypes(self, context): global materialtypes_enum materialtypes_enum.clear() @@ -433,6 +422,13 @@ class DocumentInformation(PropertyGroup): ], name='Status') +class DocumentReference(PropertyGroup): + location: StringProperty(name="Location") + name: StringProperty(name="Identification") + human_name: StringProperty(name="Name") + description: StringProperty(name="Description") + + class BcfTopic(PropertyGroup): name: StringProperty(name='Name') @@ -892,6 +888,8 @@ class BIMProperties(PropertyGroup): csv_attributes: CollectionProperty(name='CSV Attributes', type=StrProperty) document_information: CollectionProperty(name='Document Information', type=DocumentInformation) 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') class BCFProperties(PropertyGroup): @@ -959,18 +957,9 @@ class Attribute(PropertyGroup): class PsetQto(PropertyGroup): name: StringProperty(name="Name") - file: StringProperty(name="File") properties: CollectionProperty(name="Properties", type=Attribute) -class Document(PropertyGroup): - file: StringProperty(name="File") - location: StringProperty(name="Location") - identification: StringProperty(name="Identification") - name: StringProperty(name="Name") - description: StringProperty(name="Description") - - class GlobalId(PropertyGroup): name: StringProperty(name="Name") @@ -988,8 +977,8 @@ class BIMObjectProperties(PropertyGroup): psets: CollectionProperty(name="Psets", type=PsetQto) qtos: CollectionProperty(name="Qtos", type=PsetQto) applicable_attributes: EnumProperty(items=getApplicableAttributes, name="Attribute Names") - documents: CollectionProperty(name="Documents", type=Document) - applicable_documents: EnumProperty(items=getApplicableDocuments, name="Available Documents") + document_references: CollectionProperty(name="Document References", type=DocumentReference) + active_document_reference_index: IntProperty(name='Active Document Reference Index') classifications: CollectionProperty(name="Classifications", type=ClassificationReference) material_type: EnumProperty(items=getMaterialTypes, name="Material Type") pset_name: EnumProperty(items=getPsetNames, name='Pset Name') diff --git a/src/ifcblenderexport/blenderbim/bim/ui.py b/src/ifcblenderexport/blenderbim/bim/ui.py index 932ba13556..e2d06400d7 100644 --- a/src/ifcblenderexport/blenderbim/bim/ui.py +++ b/src/ifcblenderexport/blenderbim/bim/ui.py @@ -102,7 +102,7 @@ class BIM_PT_object(Panel): class BIM_PT_document_information(Panel): - bl_label = 'Document Information' + bl_label = 'Documents' bl_idname = 'BIM_PT_document_information' bl_options = {'DEFAULT_CLOSED'} bl_space_type = 'PROPERTIES' @@ -117,9 +117,7 @@ class BIM_PT_document_information(Panel): row = layout.row() row.operator('bim.add_document_information') - if not props.document_information: - layout.label(text="No document information found") - else: + if props.document_information: layout.template_list('BIM_UL_document_information', '', props, 'document_information', props, 'active_document_information_index') if props.active_document_information_index < len(props.document_information): @@ -156,6 +154,28 @@ class BIM_PT_document_information(Panel): row = layout.row() row.prop(information, 'status') + row = layout.row() + row.operator('bim.add_document_reference') + + if props.document_references: + layout.template_list('BIM_UL_document_references', '', props, 'document_references', props, 'active_document_reference_index') + + if props.active_document_reference_index < len(props.document_references): + reference = props.document_references[props.active_document_reference_index] + row = layout.row(align=True) + row.prop(reference, 'name') + row.operator('bim.remove_document_reference', icon='X', text='').index = props.active_document_reference_index + row = layout.row() + row.prop(reference, 'human_name') + row = layout.row() + row.prop(reference, 'location') + row = layout.row() + row.prop(reference, 'description') + + row = layout.row(align=True) + row.operator('bim.assign_document_reference', text='Assign Reference') + row.operator('bim.unassign_document_reference', text='Unassign Reference') + class BIM_PT_documents(Panel): bl_label = 'Documents' @@ -167,30 +187,33 @@ class BIM_PT_documents(Panel): def draw(self, context): layout = self.layout + layout.use_property_split = True props = context.active_object.BIMObjectProperties - if not props.documents: + if not props.document_references: layout.label(text="No documents found") - row = layout.row(align=True) - row.prop(props, 'applicable_documents', text='') - row.operator('bim.add_document') - row = layout.row() row.operator('bim.fetch_object_passport') - for index, document in enumerate(props.documents): - row = layout.row(align=True) - row.prop(document, 'identification') - row.operator('bim.remove_document', icon='X', text='').document_index = index - row = layout.row(align=True) - row.prop(document, 'file') - row = layout.row(align=True) - row.prop(document, 'location') - row = layout.row(align=True) - row.prop(document, 'name') - row = layout.row(align=True) - row.prop(document, 'description') + if props.document_references: + layout.template_list('BIM_UL_document_references', '', props, 'document_references', props, 'active_document_reference_index') + + if props.active_document_reference_index < len(props.document_references): + reference = props.document_references[props.active_document_reference_index] + row = layout.row(align=True) + row.prop(reference, 'name') + if reference.name in bpy.context.scene.BIMProperties.document_references: + reference = bpy.context.scene.BIMProperties.document_references[reference.name] + row.operator('bim.remove_object_document_reference', icon='X', text='').index = props.active_document_reference_index + row = layout.row() + row.prop(reference, 'human_name') + row = layout.row() + row.prop(reference, 'location') + row = layout.row() + row.prop(reference, 'description') + else: + layout.label(text="Reference is invalid") class BIM_PT_classification_references(Panel): @@ -1081,6 +1104,15 @@ class BIM_UL_document_information(bpy.types.UIList): layout.label(text="", translate=False) +class BIM_UL_document_references(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_classifications(bpy.types.UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname): if self.layout_type in {'DEFAULT', 'COMPACT'}: