From 403cda5bc8842ed434f8d64deb5f9b24ce0fdc4f Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Fri, 3 Jan 2020 15:53:57 +1100 Subject: [PATCH] Allow you to select person and organisation when exporting owner history metadata --- src/ifcblenderexport/blenderbim/__init__.py | 1 + .../blenderbim/data/owner/organisation.json | 35 ++++++++--- src/ifcblenderexport/blenderbim/export_ifc.py | 62 ++++++++++++++----- src/ifcblenderexport/blenderbim/prop.py | 24 +++++++ .../blenderbim/schema/template.ifc | 17 ++--- src/ifcblenderexport/blenderbim/ui.py | 21 +++++++ 6 files changed, 126 insertions(+), 34 deletions(-) diff --git a/src/ifcblenderexport/blenderbim/__init__.py b/src/ifcblenderexport/blenderbim/__init__.py index b000037c75..e07360572e 100644 --- a/src/ifcblenderexport/blenderbim/__init__.py +++ b/src/ifcblenderexport/blenderbim/__init__.py @@ -97,6 +97,7 @@ if bpy is not None: prop.BIMMeshProperties, ui.BIM_PT_documentation, ui.BIM_PT_bim, + ui.BIM_PT_owner, ui.BIM_PT_context, ui.BIM_PT_qa, ui.BIM_PT_library, diff --git a/src/ifcblenderexport/blenderbim/data/owner/organisation.json b/src/ifcblenderexport/blenderbim/data/owner/organisation.json index b9420dc4d3..75f9d2d261 100644 --- a/src/ifcblenderexport/blenderbim/data/owner/organisation.json +++ b/src/ifcblenderexport/blenderbim/data/owner/organisation.json @@ -1,13 +1,30 @@ [ { - "Name": "ACME", - "Description": "Does everything", - "Roles": [ { "Role": "ARCHITECT" } ], - "Addresses": [{ - "Purpose": "OFFICE", - "Description": "Headquarters", - "ElectronicMailAddresses": ["acme@example.com"], - "WWWHomePageURL": "https://example.com" - }] + "Name": "IfcOpenShell", + "Description": "IfcOpenShell is an open source (LGPL) software library that helps users and software developers to work with the IFC file format.", + "Roles": [{ + "Role": "USERDEFINED", + "UserDefinedRole": "CONTRIBUTOR" + }], + "Addresses": [ + { + "Purpose": "USERDEFINED", + "UserDefinedPurpose": "WEBPAGE", + "Description": "The main webpage of the software collection.", + "WWWHomePageURL": "https://ifcopenshell.org" + }, + { + "Purpose": "USERDEFINED", + "UserDefinedPurpose": "WEBPAGE", + "Description": "The BlenderBIM webpage of the software collection.", + "WWWHomePageURL": "https://blenderbim.org" + }, + { + "Purpose": "USERDEFINED", + "UserDefinedPurpose": "REPOSITORY", + "Description": "The source code repository of the software collection.", + "WWWHomePageURL": "https://github.com/IfcOpenShell/IfcOpenShell.git" + } + ] } ] diff --git a/src/ifcblenderexport/blenderbim/export_ifc.py b/src/ifcblenderexport/blenderbim/export_ifc.py index d7500b5154..ca854f42f8 100644 --- a/src/ifcblenderexport/blenderbim/export_ifc.py +++ b/src/ifcblenderexport/blenderbim/export_ifc.py @@ -6,6 +6,7 @@ from pathlib import Path from mathutils import Vector, Matrix from .helper import SIUnitHelper import ifcopenshell +import addon_utils class ArrayModifier: count: int @@ -567,11 +568,11 @@ class IfcParser(): def get_people(self): with open(self.data_dir + 'owner/person.json') as file: - return json.load(file) + return [{'raw': p} for p in json.load(file)] def get_organisations(self): with open(self.data_dir + 'owner/organisation.json') as file: - return json.load(file) + return [{'raw': o} for o in json.load(file)] def get_documents(self): documents = {} @@ -930,11 +931,11 @@ class IfcExporter(): def export(self): self.file = ifcopenshell.open(self.template_file) - self.set_common_definitions() self.ifc_parser.parse() self.create_units() self.create_people() self.create_organisations() + self.set_common_definitions() self.create_rep_context() self.create_project() self.create_library_information() @@ -976,7 +977,38 @@ class IfcExporter(): def set_common_definitions(self): # Owner history doesn't actually work like this, but for now, it does :) self.origin = self.file.by_type('IfcAxis2Placement3D')[0] - self.owner_history = self.file.by_type('IfcOwnerHistory')[0] + self.create_owner_history() + + def create_owner_history(self): + for person in self.ifc_parser.people: + if person['ifc'].Identification == bpy.context.scene.BIMProperties.person: + break + for organisation in self.ifc_parser.organisations: + if organisation['ifc'].Name == bpy.context.scene.BIMProperties.organisation: + break + person_and_organisation = self.file.create_entity('IfcPersonAndOrganization', **{ + 'ThePerson': person['ifc'], + 'TheOrganization': organisation['ifc'], + 'Roles': None # TODO + }) + version = '.'.join([str(x) for x in [addon.bl_info.get('version', (-1,-1,-1)) for addon in addon_utils.modules() if addon.bl_info['name'] == 'BlenderBIM'][0]]) + developer_organisation = [o for o in self.ifc_parser.organisations if o['ifc'].Name == 'IfcOpenShell'][0]['ifc'] + application = self.file.create_entity('IfcApplication', **{ + 'ApplicationDeveloper': developer_organisation, + 'Version': version, + 'ApplicationFullName': 'BlenderBIM', + 'ApplicationIdentifier': 'BlenderBIM' + }) + self.owner_history = self.file.create_entity('IfcOwnerHistory', **{ + 'OwningUser': person_and_organisation, + 'OwningApplication': application, + 'State': 'READWRITE', + 'ChangeAction': 'NOTDEFINED', + 'LastModifiedDate': int(time.time()), + 'LastModifyingUser': person_and_organisation, + 'LastModifyingApplication': application, + 'CreationDate': int(time.time()) # illegal, but better than nothing ... + }) def create_units(self): for unit_type, data in self.ifc_parser.units.items(): @@ -1033,19 +1065,21 @@ class IfcExporter(): def create_people(self): for person in self.ifc_parser.people: - if person['Roles']: - person['Roles'] = self.create_roles(person['Roles']) - if person['Addresses']: - person['Addresses'] = self.create_addresses(person['Addresses']) - self.file.create_entity('IfcPerson', **person) + data = person['raw'].copy() + if data['Roles']: + data['Roles'] = self.create_roles(data['Roles']) + if data['Addresses']: + data['Addresses'] = self.create_addresses(data['Addresses']) + person['ifc'] = self.file.create_entity('IfcPerson', **data) def create_organisations(self): for organisation in self.ifc_parser.organisations: - if organisation['Roles']: - organisation['Roles'] = self.create_roles(organisation['Roles']) - if organisation['Addresses']: - organisation['Addresses'] = self.create_addresses(organisation['Addresses']) - self.file.create_entity('IfcOrganization', **organisation) + data = organisation['raw'].copy() + if data['Roles']: + data['Roles'] = self.create_roles(data['Roles']) + if data['Addresses']: + data['Addresses'] = self.create_addresses(data['Addresses']) + organisation['ifc'] = self.file.create_entity('IfcOrganization', **data) def create_roles(self, roles): results = [] diff --git a/src/ifcblenderexport/blenderbim/prop.py b/src/ifcblenderexport/blenderbim/prop.py index 810bd77a25..26e2bcf7c7 100644 --- a/src/ifcblenderexport/blenderbim/prop.py +++ b/src/ifcblenderexport/blenderbim/prop.py @@ -36,6 +36,8 @@ documents_enum = [] contexts_enum = [] subcontexts_enum = [] target_views_enum = [] +persons_enum = [] +organisations_enum = [] @persistent def setDefaultProperties(scene): @@ -92,6 +94,26 @@ def getIfcClasses(self, context): return classes_enum +def getPersons(self, context): + global persons_enum + if len(persons_enum) < 1: + persons_enum.clear() + with open(os.path.join(self.data_dir, 'owner', 'person.json'), 'r') as f: + persons = json.load(f) + persons_enum.extend([(p['Identification'], p['Identification'], '') for p in persons]) + return persons_enum + + +def getOrganisations(self, context): + global organisations_enum + if len(organisations_enum) < 1: + organisations_enum.clear() + with open(os.path.join(self.data_dir, 'owner', 'organisation.json'), 'r') as f: + organisations = json.load(f) + organisations_enum.extend([(o['Name'], o['Name'], '') for o in organisations]) + return organisations_enum + + def getPsetNames(self, context): global psetnames_enum if len(psetnames_enum) < 1: @@ -215,6 +237,8 @@ class BIMProperties(PropertyGroup): import_should_use_legacy: BoolProperty(name="Import with Legacy Importer", default=False) import_should_use_cpu_multiprocessing: BoolProperty(name="Import with CPU Multiprocessing", default=False) qa_reject_element_reason: StringProperty(name="Element Rejection Reason") + person: EnumProperty(items=getPersons, name="Person") + organisation: EnumProperty(items=getOrganisations, name="Organisation") pset_name: EnumProperty(items=getPsetNames, name="Pset Name", update=refreshPsetFiles) pset_file: EnumProperty(items=getPsetFiles, name="Pset File") has_georeferencing: BoolProperty(name="Has Georeferencing", default=False) diff --git a/src/ifcblenderexport/blenderbim/schema/template.ifc b/src/ifcblenderexport/blenderbim/schema/template.ifc index db780c963a..5db8ff403d 100644 --- a/src/ifcblenderexport/blenderbim/schema/template.ifc +++ b/src/ifcblenderexport/blenderbim/schema/template.ifc @@ -5,16 +5,11 @@ FILE_NAME('$filename','2019-05-12T12:33:45',('$owner','$email'),('$company'),'If FILE_SCHEMA(('IFC4')); ENDSEC; DATA; -#1=IFCPERSON($,$,'$owner',$,$,$,$,$); -#2=IFCORGANIZATION($,'$company',$,$,$); -#3=IFCPERSONANDORGANIZATION(#1,#2,$); -#4=IFCAPPLICATION(#2,'0.0.1','Blender BIM IFC','118df2cf_ed21_438e_a41'); -#5=IFCOWNERHISTORY(#3,#4,$,.ADDED.,$,#3,#4,1557664425); -#6=IFCDIRECTION((1.,0.,0.)); -#7=IFCDIRECTION((0.,0.,1.)); -#8=IFCCARTESIANPOINT((0.,0.,0.)); -#9=IFCAXIS2PLACEMENT3D(#8,#7,#6); -#10=IFCDIRECTION((0.,1.,0.)); -#12=IFCDIMENSIONALEXPONENTS(0,0,0,0,0,0,0); +#1=IFCDIRECTION((1.,0.,0.)); +#2=IFCDIRECTION((0.,0.,1.)); +#3=IFCCARTESIANPOINT((0.,0.,0.)); +#4=IFCAXIS2PLACEMENT3D(#3,#2,#1); +#5=IFCDIRECTION((0.,1.,0.)); +#6=IFCDIMENSIONALEXPONENTS(0,0,0,0,0,0,0); ENDSEC; END-ISO-10303-21; diff --git a/src/ifcblenderexport/blenderbim/ui.py b/src/ifcblenderexport/blenderbim/ui.py index e1ac4db726..4e1b9e8168 100644 --- a/src/ifcblenderexport/blenderbim/ui.py +++ b/src/ifcblenderexport/blenderbim/ui.py @@ -206,6 +206,27 @@ class BIM_PT_documentation(Panel): row = layout.row() row.operator('bim.generate_digital_twin') + +class BIM_PT_owner(Panel): + bl_label = "Owner History" + bl_idname = "BIM_PT_owner" + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "scene" + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + + scene = context.scene + props = scene.BIMProperties + + row = layout.row() + row.prop(props, 'person') + + row = layout.row() + row.prop(props, 'organisation') + class BIM_PT_context(Panel): bl_label = "Geometric Representation Contexts" bl_idname = "BIM_PT_context"