mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 01:41:57 +00:00
Merge branch 'v0.6.0' of https://github.com/IfcOpenShell/IfcOpenShell into v0.6.0
This commit is contained in:
@@ -65,10 +65,14 @@ if bpy is not None:
|
||||
operator.RemoveObjectConstraint,
|
||||
operator.AddPerson,
|
||||
operator.RemovePerson,
|
||||
operator.AddPersonRole,
|
||||
operator.RemovePersonRole,
|
||||
operator.AddPersonAddress,
|
||||
operator.RemovePersonAddress,
|
||||
operator.AddOrganisation,
|
||||
operator.RemoveOrganisation,
|
||||
operator.AddOrganisationRole,
|
||||
operator.RemoveOrganisationRole,
|
||||
operator.AddOrganisationAddress,
|
||||
operator.RemoveOrganisationAddress,
|
||||
operator.AddDocumentInformation,
|
||||
@@ -158,6 +162,7 @@ if bpy is not None:
|
||||
operator.ConvertLocalToGlobal,
|
||||
prop.StrProperty,
|
||||
prop.Variable,
|
||||
prop.Role,
|
||||
prop.Address,
|
||||
prop.Person,
|
||||
prop.Organisation,
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
[
|
||||
{
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -1,35 +0,0 @@
|
||||
[
|
||||
{
|
||||
"Identification": "Moult",
|
||||
"FamilyName": "Moult",
|
||||
"GivenName": "Dion",
|
||||
"MiddleNames": ["Sebastian", "Isan", "Tan"],
|
||||
"PrefixTitles": ["Mr"],
|
||||
"SuffixTitles": ["UE"],
|
||||
"Roles": [{
|
||||
"Role": "ARCHITECT",
|
||||
"UserDefinedRole": null,
|
||||
"Description": "Draws the pretty pictures"
|
||||
}],
|
||||
"Addresses": [{
|
||||
"Purpose": "OFFICE",
|
||||
"Description": "Headquarters",
|
||||
"UserDefinedPurpose": null,
|
||||
"InternalLocation": "Cupboard under the stairs",
|
||||
"AddressLines": [ "221B Baker Street" ],
|
||||
"PostalBox": null,
|
||||
"Town": "MyTown",
|
||||
"Region": "Middle-Earth",
|
||||
"PostalCode": "42",
|
||||
"Country": "Narnia"
|
||||
}, {
|
||||
"Purpose": "OFFICE",
|
||||
"Description": "Headquarters",
|
||||
"UserDefinedPurpose": null,
|
||||
"TelephoneNumbers": ["0123456789"],
|
||||
"ElectronicMailAddresses": ["dion@thinkmoult.com"],
|
||||
"WWWHomePageURL": "https://thinkmoult.com",
|
||||
"MessagingIDs": ["irc://irc.freenode.net##architect"]
|
||||
}]
|
||||
}
|
||||
]
|
||||
@@ -697,12 +697,120 @@ class IfcParser():
|
||||
return results
|
||||
|
||||
def get_people(self):
|
||||
with open(self.data_dir + 'owner/person.json') as file:
|
||||
return [{'raw': p} for p in json.load(file)]
|
||||
data_map = {
|
||||
'name': 'Identification',
|
||||
'family_name': 'FamilyName',
|
||||
'given_name': 'GivenName',
|
||||
}
|
||||
list_data_map = {
|
||||
'middle_names': 'MiddleNames',
|
||||
'prefix_titles': 'PrefixTitles',
|
||||
'suffix_titles': 'SuffixTitles',
|
||||
}
|
||||
results = []
|
||||
for person in bpy.context.scene.BIMProperties.people:
|
||||
attributes = {}
|
||||
for key, value in data_map.items():
|
||||
if getattr(person, key):
|
||||
attributes[value] = getattr(person, key)
|
||||
for key, value in list_data_map.items():
|
||||
if getattr(person, key):
|
||||
attributes[value] = getattr(person, key).split(',')
|
||||
results.append({
|
||||
'ifc': None,
|
||||
'raw': person,
|
||||
'attributes': attributes,
|
||||
'roles': self.get_roles(person.roles),
|
||||
'addresses': self.get_addresses(person.addresses)
|
||||
})
|
||||
return results
|
||||
|
||||
def get_organisations(self):
|
||||
with open(self.data_dir + 'owner/organisation.json') as file:
|
||||
return [{'raw': o} for o in json.load(file)]
|
||||
data_map = {
|
||||
'name': 'Name',
|
||||
'description': 'Description',
|
||||
}
|
||||
results = []
|
||||
for organisation in bpy.context.scene.BIMProperties.organisations:
|
||||
attributes = {}
|
||||
for key, value in data_map.items():
|
||||
if getattr(organisation, key):
|
||||
attributes[value] = getattr(organisation, key)
|
||||
results.append({
|
||||
'ifc': None,
|
||||
'raw': organisation,
|
||||
'attributes': attributes,
|
||||
'roles': self.get_roles(organisation.roles),
|
||||
'addresses': self.get_addresses(organisation.addresses)
|
||||
})
|
||||
return results
|
||||
|
||||
def get_roles(self, roles):
|
||||
data_map = {
|
||||
'name': 'Role',
|
||||
'user_defined_role': 'UserDefinedRole',
|
||||
'description': 'Description',
|
||||
}
|
||||
results = []
|
||||
for role in roles:
|
||||
attributes = {}
|
||||
for key, value in data_map.items():
|
||||
if getattr(role, key):
|
||||
attributes[value] = getattr(role, key)
|
||||
results.append({
|
||||
'ifc': None,
|
||||
'raw': role,
|
||||
'attributes': attributes
|
||||
})
|
||||
return results
|
||||
|
||||
def get_addresses(self, addresses):
|
||||
results = []
|
||||
address_data_map = {
|
||||
'purpose': 'Purpose',
|
||||
'description': 'Description',
|
||||
'user_defined_purpose': 'UserDefinedPurpose',
|
||||
}
|
||||
postal_data_map = {
|
||||
'internal_location': 'InternalLocation',
|
||||
'postal_box': 'PostalBox',
|
||||
'town': 'Town',
|
||||
'region': 'Region',
|
||||
'postal_code': 'PostalCode',
|
||||
'country': 'Country',
|
||||
}
|
||||
telecom_data_map = {
|
||||
'pager_number': 'PagerNumber',
|
||||
'www_home_page_url': 'WWWHomePageURL',
|
||||
}
|
||||
telecom_list_data_map = {
|
||||
'telephone_numbers': 'TelephoneNumbers',
|
||||
'fascimile_numbers': 'FascimileNumbers',
|
||||
'electronic_mail_addresses': 'ElectronicMailAddresses',
|
||||
'messaging_ids': 'MessagingIDs',
|
||||
}
|
||||
for address in addresses:
|
||||
attributes = {}
|
||||
if 'IfcPostalAddress' in address.name:
|
||||
merged_data_map = {**address_data_map, **postal_data_map}
|
||||
if address.address_lines:
|
||||
attributes['AddressLines'] = address.address_lines.split('/')
|
||||
elif 'IfcTelecomAddress' in address.name:
|
||||
merged_data_map = {**address_data_map, **telecom_data_map}
|
||||
for key, value in telecom_list_data_map.items():
|
||||
if getattr(address, key):
|
||||
attributes[value] = getattr(address, key).split(',')
|
||||
for key, value in merged_data_map.items():
|
||||
if getattr(address, key):
|
||||
attributes[value] = getattr(address, key)
|
||||
results.append({
|
||||
'ifc': None,
|
||||
'raw': address,
|
||||
'is_postal': 'IfcPostalAddress' in address.name,
|
||||
'is_telecom': 'IfcTelecomAddress' in address.name,
|
||||
'attributes': attributes
|
||||
})
|
||||
return results
|
||||
|
||||
def get_document_references(self):
|
||||
results = {}
|
||||
@@ -1221,15 +1329,55 @@ class IfcExporter():
|
||||
self.file.wrapped_data.header.file_name.time_stamp = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).astimezone().replace(microsecond=0).isoformat()
|
||||
self.file.wrapped_data.header.file_name.preprocessor_version = 'IfcOpenShell {}'.format(ifcopenshell.version)
|
||||
self.file.wrapped_data.header.file_name.originating_system = '{} {}'.format(
|
||||
self.owner_history.OwningApplication.ApplicationFullName,
|
||||
self.owner_history.OwningApplication.Version,
|
||||
)
|
||||
if self.schema == 'IFC2X3':
|
||||
self.file.wrapped_data.header.file_name.authorization = self.owner_history.OwningUser.ThePerson.Id
|
||||
self.get_application_name(), self.get_application_version())
|
||||
if self.owner_history:
|
||||
if self.schema == 'IFC2X3':
|
||||
self.file.wrapped_data.header.file_name.authorization = self.owner_history.OwningUser.ThePerson.Id
|
||||
else:
|
||||
self.file.wrapped_data.header.file_name.authorization = self.owner_history.OwningUser.ThePerson.Identification
|
||||
else:
|
||||
self.file.wrapped_data.header.file_name.authorization = self.owner_history.OwningUser.ThePerson.Identification
|
||||
self.file.wrapped_data.header.file_name.authorization = 'Nobody'
|
||||
|
||||
def get_application_name(self):
|
||||
return 'BlenderBIM'
|
||||
|
||||
def get_application_version(self):
|
||||
return '.'.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]])
|
||||
|
||||
def get_application_organisation(self):
|
||||
self.application_organisation = self.file.create_entity('IfcOrganization', **{
|
||||
"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": [self.file.create_entity('IfcActorRole', **{
|
||||
"Role": "USERDEFINED",
|
||||
"UserDefinedRole": "CONTRIBUTOR"
|
||||
})],
|
||||
"Addresses": [
|
||||
self.file.create_entity('IfcTelecomAddress', **{
|
||||
"Purpose": "USERDEFINED",
|
||||
"UserDefinedPurpose": "WEBPAGE",
|
||||
"Description": "The main webpage of the software collection.",
|
||||
"WWWHomePageURL": "https://ifcopenshell.org"
|
||||
}),
|
||||
self.file.create_entity('IfcTelecomAddress', **{
|
||||
"Purpose": "USERDEFINED",
|
||||
"UserDefinedPurpose": "WEBPAGE",
|
||||
"Description": "The BlenderBIM Add-on webpage of the software collection.",
|
||||
"WWWHomePageURL": "https://blenderbim.org"
|
||||
}),
|
||||
self.file.create_entity('IfcTelecomAddress', **{
|
||||
"Purpose": "USERDEFINED",
|
||||
"UserDefinedPurpose": "REPOSITORY",
|
||||
"Description": "The source code repository of the software collection.",
|
||||
"WWWHomePageURL": "https://github.com/IfcOpenShell/IfcOpenShell.git"
|
||||
})
|
||||
]
|
||||
})
|
||||
return self.application_organisation
|
||||
|
||||
def create_owner_history(self):
|
||||
person = None
|
||||
organisation = None
|
||||
for person in self.ifc_parser.people:
|
||||
if self.schema == 'IFC2X3' and person['ifc'].Id == bpy.context.scene.BIMProperties.person:
|
||||
break
|
||||
@@ -1238,18 +1386,20 @@ class IfcExporter():
|
||||
for organisation in self.ifc_parser.organisations:
|
||||
if organisation['ifc'].Name == bpy.context.scene.BIMProperties.organisation:
|
||||
break
|
||||
if not person or not organisation:
|
||||
self.owner_history = None
|
||||
return
|
||||
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']
|
||||
developer_organisation = self.get_application_organisation()
|
||||
application = self.file.create_entity('IfcApplication', **{
|
||||
'ApplicationDeveloper': developer_organisation,
|
||||
'Version': version,
|
||||
'ApplicationFullName': 'BlenderBIM',
|
||||
'ApplicationIdentifier': 'BlenderBIM'
|
||||
'Version': self.get_application_version(),
|
||||
'ApplicationFullName': self.get_application_name(),
|
||||
'ApplicationIdentifier': self.get_application_name()
|
||||
})
|
||||
self.owner_history = self.file.create_entity('IfcOwnerHistory', **{
|
||||
'OwningUser': person_and_organisation,
|
||||
@@ -1317,45 +1467,36 @@ class IfcExporter():
|
||||
|
||||
def create_people(self):
|
||||
for person in self.ifc_parser.people:
|
||||
data = person['raw'].copy()
|
||||
if data['Roles']:
|
||||
data['Roles'] = self.create_roles(data['Roles'])
|
||||
if data['Addresses']:
|
||||
data['Addresses'] = self.create_addresses(data['Addresses'])
|
||||
if self.schema == 'IFC2X3' and 'Identification' in data:
|
||||
data['Id'] = data['Identification']
|
||||
del data['Identification']
|
||||
person['ifc'] = self.file.create_entity('IfcPerson', **data)
|
||||
if person['roles']:
|
||||
person['attributes']['Roles'] = self.create_roles(person['roles'])
|
||||
if person['addresses']:
|
||||
person['attributes']['Addresses'] = self.create_addresses(person['addresses'])
|
||||
if self.schema == 'IFC2X3' and 'Identification' in person['attributes']:
|
||||
person['attributes']['Id'] = person['attributes']['Identification']
|
||||
del person['attributes']['Identification']
|
||||
person['ifc'] = self.file.create_entity('IfcPerson', **person['attributes'])
|
||||
|
||||
def create_organisations(self):
|
||||
for organisation in self.ifc_parser.organisations:
|
||||
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)
|
||||
if organisation['roles']:
|
||||
organisation['attributes']['Roles'] = self.create_roles(organisation['roles'])
|
||||
if organisation['addresses']:
|
||||
organisation['attributes']['Addresses'] = self.create_addresses(organisation['addresses'])
|
||||
organisation['ifc'] = self.file.create_entity('IfcOrganization', **organisation['attributes'])
|
||||
|
||||
def create_roles(self, roles):
|
||||
results = []
|
||||
for role in roles:
|
||||
results.append(self.file.create_entity('IfcActorRole', **role))
|
||||
results.append(self.file.create_entity('IfcActorRole', **role['attributes']))
|
||||
return results
|
||||
|
||||
def create_addresses(self, addresses):
|
||||
results = []
|
||||
for address in addresses:
|
||||
is_postal_address = False
|
||||
for key in ['InternalLocation', 'AddressLines', 'PostalBox', 'Town',
|
||||
'Region', 'PostalCode', 'Country']:
|
||||
if key in address:
|
||||
is_postal_address = True
|
||||
if is_postal_address:
|
||||
results.append(self.file.create_entity('IfcPostalAddress', **address))
|
||||
else:
|
||||
if self.schema == 'IFC2X3' and 'MessagingIDs' in address:
|
||||
del address['MessagingIDs']
|
||||
results.append(self.file.create_entity('IfcTelecomAddress', **address))
|
||||
if self.schema == 'IFC2X3' and 'MessagingIDs' in address['attributes']:
|
||||
del address['attributes']['MessagingIDs']
|
||||
results.append(self.file.create_entity('IfcPostalAddress' if
|
||||
address['is_postal'] else 'IfcTelecomAddress', **address['attributes']))
|
||||
return results
|
||||
|
||||
def create_library_information(self):
|
||||
@@ -2627,10 +2768,11 @@ class IfcExporter():
|
||||
|
||||
def relate_objects_to_psets(self):
|
||||
for relating_property_key, related_objects in self.ifc_parser.rel_defines_by_pset.items():
|
||||
self.file.createIfcRelDefinesByProperties(
|
||||
ifcopenshell.guid.new(), self.owner_history, None, None,
|
||||
[o['ifc'] for o in related_objects],
|
||||
self.ifc_parser.psets[relating_property_key]['ifc'])
|
||||
if self.ifc_parser.psets[relating_property_key]['ifc']:
|
||||
self.file.createIfcRelDefinesByProperties(
|
||||
ifcopenshell.guid.new(), self.owner_history, None, None,
|
||||
[o['ifc'] for o in related_objects],
|
||||
self.ifc_parser.psets[relating_property_key]['ifc'])
|
||||
|
||||
def relate_objects_to_materials(self):
|
||||
if not self.ifc_export_settings.has_representations:
|
||||
|
||||
@@ -5,6 +5,7 @@ import ifcopenshell.util.selector
|
||||
import bpy
|
||||
import bmesh
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import threading
|
||||
import json
|
||||
@@ -105,7 +106,7 @@ class MaterialCreator():
|
||||
return
|
||||
if len(obj.material_slots) == 1:
|
||||
return
|
||||
slots = [s.name for s in obj.material_slots]
|
||||
slots = [self.canonicalise_material_name(s.name) for s in obj.material_slots]
|
||||
material_to_slot = {}
|
||||
for i, material in enumerate(mesh['ios_materials']):
|
||||
if material == 'NULLMAT':
|
||||
@@ -119,6 +120,9 @@ class MaterialCreator():
|
||||
else 0) for mat_id in mesh['ios_material_ids']]
|
||||
mesh.polygons.foreach_set('material_index', material_index)
|
||||
|
||||
def canonicalise_material_name(self, name):
|
||||
return re.sub(r'\.[0-9]{3}', '', name)
|
||||
|
||||
def parse_material(self, element):
|
||||
for association in element.HasAssociations:
|
||||
if association.is_a('IfcRelAssociatesMaterial'):
|
||||
@@ -266,57 +270,101 @@ class IfcImporter():
|
||||
|
||||
self.material_creator = MaterialCreator(ifc_import_settings)
|
||||
|
||||
def profile_code(self, message):
|
||||
if not self.ifc_import_settings.should_import_with_profiling:
|
||||
return
|
||||
if not self.time:
|
||||
self.time = time.time()
|
||||
print('{} :: {:.2f}'.format(message, time.time() - self.time))
|
||||
self.time = time.time()
|
||||
|
||||
def execute(self):
|
||||
self.profile_code('Starting import process')
|
||||
self.load_existing_rooted_elements()
|
||||
self.profile_code('Load existing rooted elements')
|
||||
self.load_diff()
|
||||
self.profile_code('Load diff')
|
||||
self.cache_file()
|
||||
self.profile_code('Caching file')
|
||||
self.load_file()
|
||||
self.profile_code('Loading file')
|
||||
self.set_ifc_file()
|
||||
self.profile_code('Setting file')
|
||||
if self.ifc_import_settings.should_auto_set_workarounds:
|
||||
self.auto_set_workarounds()
|
||||
self.profile_code('Set vendor worksarounds')
|
||||
self.calculate_unit_scale()
|
||||
self.profile_code('Calculate unit scale')
|
||||
self.set_units()
|
||||
self.profile_code('Set units')
|
||||
self.create_geometric_representation_contexts()
|
||||
self.profile_code('Create contexts')
|
||||
self.create_project()
|
||||
self.profile_code('Create project')
|
||||
self.create_classifications()
|
||||
self.profile_code('Create classifications')
|
||||
self.create_document_information()
|
||||
self.profile_code('Create doc info')
|
||||
self.create_document_references()
|
||||
self.profile_code('Create doc refs')
|
||||
self.create_spatial_hierarchy()
|
||||
self.profile_code('Create spatial hierarchy')
|
||||
self.purge_diff()
|
||||
self.profile_code('Purge diffs')
|
||||
self.create_type_products()
|
||||
self.profile_code('Create type products')
|
||||
if self.ifc_import_settings.should_import_aggregates:
|
||||
self.create_aggregates()
|
||||
self.profile_code('Create aggregates')
|
||||
self.create_openings_collection()
|
||||
self.profile_code('Create opening collection')
|
||||
self.process_element_filter()
|
||||
self.profile_code('Process element filter')
|
||||
if self.ifc_import_settings.should_import_native:
|
||||
self.parse_native_elements()
|
||||
self.profile_code('Parsing native elements')
|
||||
self.filter_ifc()
|
||||
self.profile_code('Filtering ifc')
|
||||
self.patch_ifc()
|
||||
self.profile_code('Patching ifc')
|
||||
self.create_georeferencing()
|
||||
self.profile_code('Georeferencing ifc')
|
||||
self.create_groups()
|
||||
self.profile_code('Creating groups')
|
||||
self.create_grids()
|
||||
self.profile_code('Creating grids')
|
||||
if self.ifc_import_settings.should_import_native:
|
||||
self.create_native_products()
|
||||
self.profile_code('Creating native products')
|
||||
# TODO: Deprecate after bug #682 is fixed and the new importer is stable
|
||||
if self.ifc_import_settings.should_use_legacy:
|
||||
self.create_products_legacy()
|
||||
else:
|
||||
self.create_products()
|
||||
self.profile_code('Creating meshified products')
|
||||
self.relate_openings()
|
||||
self.profile_code('Relating openings')
|
||||
self.place_objects_in_spatial_tree()
|
||||
self.profile_code('Placing objects in spatial tree')
|
||||
if self.ifc_import_settings.should_merge_aggregates:
|
||||
self.merge_aggregates()
|
||||
self.profile_code('Merging aggregates')
|
||||
if self.ifc_import_settings.should_merge_by_class:
|
||||
self.merge_by_class()
|
||||
self.profile_code('Merging by class')
|
||||
elif self.ifc_import_settings.should_merge_by_material:
|
||||
self.merge_by_material()
|
||||
self.profile_code('Merging by material')
|
||||
if self.ifc_import_settings.should_merge_materials_by_colour \
|
||||
or (self.ifc_import_settings.should_auto_set_workarounds \
|
||||
and len(self.material_creator.materials) > 300):
|
||||
self.merge_materials_by_colour()
|
||||
self.profile_code('Merging by colour')
|
||||
self.add_project_to_scene()
|
||||
self.profile_code('Add project to scene')
|
||||
if self.ifc_import_settings.should_clean_mesh and len(self.file.by_type('IfcElement')) < 10000:
|
||||
self.clean_mesh()
|
||||
self.profile_code('Mesh cleaning')
|
||||
|
||||
def auto_set_workarounds(self):
|
||||
if 'DDS-CAD' in self.file.wrapped_data.header.file_name.originating_system \
|
||||
@@ -1875,6 +1923,7 @@ class IfcImportSettings:
|
||||
self.should_import_spaces = False
|
||||
self.should_treat_styled_item_as_material = False
|
||||
self.should_use_cpu_multiprocessing = False
|
||||
self.should_import_with_profiling = False
|
||||
self.should_import_native = False
|
||||
self.should_use_legacy = False
|
||||
self.should_merge_aggregates = False
|
||||
@@ -1903,6 +1952,7 @@ class IfcImportSettings:
|
||||
settings.should_auto_set_workarounds = scene_bim.import_should_auto_set_workarounds
|
||||
settings.should_treat_styled_item_as_material = scene_bim.import_should_treat_styled_item_as_material
|
||||
settings.should_use_cpu_multiprocessing = scene_bim.import_should_use_cpu_multiprocessing
|
||||
settings.should_import_with_profiling = scene_bim.import_should_import_with_profiling
|
||||
settings.should_import_native = scene_bim.import_should_import_native
|
||||
settings.should_use_legacy = scene_bim.import_should_use_legacy
|
||||
settings.should_import_aggregates = scene_bim.import_should_import_aggregates
|
||||
|
||||
@@ -87,6 +87,7 @@ class ImportIFC(bpy.types.Operator, ImportHelper):
|
||||
ifc_importer = import_ifc.IfcImporter(ifc_import_settings)
|
||||
ifc_importer.execute()
|
||||
ifc_import_settings.logger.info('Import finished in {:.2f} seconds'.format(time.time() - start))
|
||||
print('Import finished in {:.2f} seconds'.format(time.time() - start))
|
||||
return {'FINISHED'}
|
||||
|
||||
class SelectGlobalId(bpy.types.Operator):
|
||||
@@ -917,6 +918,25 @@ class RemovePersonAddress(bpy.types.Operator):
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class AddPersonRole(bpy.types.Operator):
|
||||
bl_idname = 'bim.add_person_role'
|
||||
bl_label = 'Add Person Role'
|
||||
|
||||
def execute(self, context):
|
||||
new = bpy.context.scene.BIMProperties.people[bpy.context.scene.BIMProperties.active_person_index].roles.add()
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class RemovePersonRole(bpy.types.Operator):
|
||||
bl_idname = 'bim.remove_person_role'
|
||||
bl_label = 'Remove Person Role'
|
||||
index: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
bpy.context.scene.BIMProperties.people[bpy.context.scene.BIMProperties.active_person_index].roles.remove(self.index)
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class AddOrganisation(bpy.types.Operator):
|
||||
bl_idname = 'bim.add_organisation'
|
||||
bl_label = 'Add Organisation'
|
||||
@@ -957,6 +977,25 @@ class RemoveOrganisationAddress(bpy.types.Operator):
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class AddOrganisationRole(bpy.types.Operator):
|
||||
bl_idname = 'bim.add_organisation_role'
|
||||
bl_label = 'Add Organisation Role'
|
||||
|
||||
def execute(self, context):
|
||||
new = bpy.context.scene.BIMProperties.organisations[bpy.context.scene.BIMProperties.active_organisation_index].roles.add()
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class RemoveOrganisationRole(bpy.types.Operator):
|
||||
bl_idname = 'bim.remove_organisation_role'
|
||||
bl_label = 'Remove Organisation Role'
|
||||
index: bpy.props.IntProperty()
|
||||
|
||||
def execute(self, context):
|
||||
bpy.context.scene.BIMProperties.organisations[bpy.context.scene.BIMProperties.active_organisation_index].roles.remove(self.index)
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class AddDocumentInformation(bpy.types.Operator):
|
||||
bl_idname = 'bim.add_document_information'
|
||||
bl_label = 'Add Document Information'
|
||||
|
||||
@@ -130,6 +130,7 @@ def getIfcProducts(self, context):
|
||||
'IfcSpatialElement',
|
||||
'IfcGroup',
|
||||
'IfcStructural',
|
||||
'IfcPositioningElement',
|
||||
'IfcContext',
|
||||
'IfcAnnotation']])
|
||||
return products_enum
|
||||
@@ -151,21 +152,15 @@ def getProfileDef(self, context):
|
||||
|
||||
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])
|
||||
persons_enum.clear()
|
||||
persons_enum.extend([(p.name, p.name, '') for p in bpy.context.scene.BIMProperties.people])
|
||||
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])
|
||||
organisations_enum.clear()
|
||||
organisations_enum.extend([(o.name, o.name, '') for o in bpy.context.scene.BIMProperties.organisations])
|
||||
return organisations_enum
|
||||
|
||||
|
||||
@@ -831,13 +826,19 @@ class PropertyTemplate(PropertyGroup):
|
||||
|
||||
class Address(PropertyGroup):
|
||||
name: StringProperty(name="Name") # Stores IfcPostalAddress or IfcTelecomAddress
|
||||
purpose: StringProperty(name="Purpose")
|
||||
purpose: EnumProperty(items=[
|
||||
('OFFICE', 'OFFICE', 'An office address.'),
|
||||
('SITE', 'SITE', 'A site address.'),
|
||||
('HOME', 'HOME', 'A home address.'),
|
||||
('DISTRIBUTIONPOINT', 'DISTRIBUTIONPOINT', 'A postal distribution point address.'),
|
||||
('USERDEFINED', 'USERDEFINED', 'A user defined address type to be provided.'),
|
||||
], name='Purpose')
|
||||
description: StringProperty(name="Description")
|
||||
user_defined_purpose: StringProperty(name="Custom Purpose")
|
||||
|
||||
internal_location: StringProperty(name="Internal Location")
|
||||
address_lines: StringProperty(name="Address")
|
||||
postal_box: StringProperty(name="PO Box")
|
||||
postal_box: StringProperty(name="Postal Box")
|
||||
town: StringProperty(name="Town")
|
||||
region: StringProperty(name="Region")
|
||||
postal_code: StringProperty(name="Postal Code")
|
||||
@@ -851,10 +852,41 @@ class Address(PropertyGroup):
|
||||
messaging_ids: StringProperty(name="IMs")
|
||||
|
||||
|
||||
class Role(PropertyGroup):
|
||||
name: EnumProperty(items=[
|
||||
('SUPPLIER', 'SUPPLIER', ''),
|
||||
('MANUFACTURER', 'MANUFACTURER', ''),
|
||||
('CONTRACTOR', 'CONTRACTOR', ''),
|
||||
('SUBCONTRACTOR', 'SUBCONTRACTOR', ''),
|
||||
('ARCHITECT', 'ARCHITECT', ''),
|
||||
('STRUCTURALENGINEER', 'STRUCTURALENGINEER', ''),
|
||||
('COSTENGINEER', 'COSTENGINEER', ''),
|
||||
('CLIENT', 'CLIENT', ''),
|
||||
('BUILDINGOWNER', 'BUILDINGOWNER', ''),
|
||||
('BUILDINGOPERATOR', 'BUILDINGOPERATOR', ''),
|
||||
('MECHANICALENGINEER', 'MECHANICALENGINEER', ''),
|
||||
('ELECTRICALENGINEER', 'ELECTRICALENGINEER', ''),
|
||||
('PROJECTMANAGER', 'PROJECTMANAGER', ''),
|
||||
('FACILITIESMANAGER', 'FACILITIESMANAGER', ''),
|
||||
('CIVILENGINEER', 'CIVILENGINEER', ''),
|
||||
('COMMISSIONINGENGINEER', 'COMMISSIONINGENGINEER', ''),
|
||||
('ENGINEER', 'ENGINEER', ''),
|
||||
('OWNER', 'OWNER', ''),
|
||||
('CONSULTANT', 'CONSULTANT', ''),
|
||||
('CONSTRUCTIONMANAGER', 'CONSTRUCTIONMANAGER', ''),
|
||||
('FIELDCONSTRUCTIONMANAGER', 'FIELDCONSTRUCTIONMANAGER', ''),
|
||||
('RESELLER', 'RESELLER', ''),
|
||||
('USERDEFINED', 'USERDEFINED', ''),
|
||||
], name='Name')
|
||||
user_defined_role: StringProperty(name="Custom Role")
|
||||
description: StringProperty(name="Description")
|
||||
|
||||
|
||||
class Organisation(PropertyGroup):
|
||||
name: StringProperty(name="Name")
|
||||
description: StringProperty(name="Description")
|
||||
roles: StringProperty(name="Roles")
|
||||
roles: CollectionProperty(name="Roles", type=Role)
|
||||
active_role_index: bpy.props.IntProperty()
|
||||
addresses: CollectionProperty(name="Addresses", type=Address)
|
||||
active_address_index: bpy.props.IntProperty()
|
||||
|
||||
@@ -866,7 +898,8 @@ class Person(PropertyGroup):
|
||||
middle_names: StringProperty(name="Middle Names")
|
||||
prefix_titles: StringProperty(name="Prefixes")
|
||||
suffix_titles: StringProperty(name="Suffixes")
|
||||
roles: StringProperty(name="Roles")
|
||||
roles: CollectionProperty(name="Roles", type=Role)
|
||||
active_role_index: bpy.props.IntProperty()
|
||||
addresses: CollectionProperty(name="Addresses", type=Address)
|
||||
active_address_index: bpy.props.IntProperty()
|
||||
|
||||
@@ -971,6 +1004,7 @@ class BIMProperties(PropertyGroup):
|
||||
import_should_use_legacy: BoolProperty(name="Import with Legacy Importer", default=False)
|
||||
import_should_import_native: BoolProperty(name="Import Native Representations", default=False)
|
||||
import_should_use_cpu_multiprocessing: BoolProperty(name="Import with CPU Multiprocessing", default=False)
|
||||
import_should_import_with_profiling: BoolProperty(name="Import with Profiling", default=True)
|
||||
import_should_import_aggregates: BoolProperty(name="Import Aggregates", default=True)
|
||||
import_should_merge_aggregates: BoolProperty(name="Import and Merge Aggregates", default=False)
|
||||
import_should_merge_by_class: BoolProperty(name="Import and Merge by Class", default=False)
|
||||
|
||||
@@ -17,6 +17,7 @@ class IfcSchema():
|
||||
'IfcSpatialElement',
|
||||
'IfcGroup',
|
||||
'IfcStructural',
|
||||
'IfcPositioningElement',
|
||||
'IfcMaterialDefinition',
|
||||
'IfcParameterizedProfileDef',
|
||||
'IfcBoundaryCondition',
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
{
|
||||
"IfcGrid": {
|
||||
"is_abstract": false,
|
||||
"parent": "IfcProduct",
|
||||
"attributes": [
|
||||
{
|
||||
"name": "GlobalId",
|
||||
"type": "IfcGloballyUniqueId",
|
||||
"is_enum": false,
|
||||
"enum_values": []
|
||||
},
|
||||
{
|
||||
"name": "Name",
|
||||
"type": "IfcLabel",
|
||||
"is_enum": false,
|
||||
"enum_values": []
|
||||
},
|
||||
{
|
||||
"name": "Description",
|
||||
"type": "IfcText",
|
||||
"is_enum": false,
|
||||
"enum_values": []
|
||||
},
|
||||
{
|
||||
"name": "ObjectType",
|
||||
"type": "IfcLabel",
|
||||
"is_enum": false,
|
||||
"enum_values": []
|
||||
},
|
||||
{
|
||||
"name": "PredefinedType",
|
||||
"type": "IfcGridTypeEnum",
|
||||
"is_enum": true,
|
||||
"enum_values": [
|
||||
"RECTANGULAR",
|
||||
"RADIAL",
|
||||
"TRIANGULAR",
|
||||
"IRREGULAR",
|
||||
"USERDEFINED",
|
||||
"NOTDEFINED"
|
||||
]
|
||||
}
|
||||
],
|
||||
"complex_attributes": [
|
||||
{
|
||||
"name": "OwnerHistory",
|
||||
"type": "IfcOwnerHistory",
|
||||
"is_select": false,
|
||||
"select_types": []
|
||||
},
|
||||
{
|
||||
"name": "IsDeclaredBy",
|
||||
"type": "IfcRelDefinesByObject",
|
||||
"is_select": false,
|
||||
"select_types": []
|
||||
},
|
||||
{
|
||||
"name": "IsTypedBy",
|
||||
"type": "IfcRelDefinesByType",
|
||||
"is_select": false,
|
||||
"select_types": []
|
||||
},
|
||||
{
|
||||
"name": "ObjectPlacement",
|
||||
"type": "IfcObjectPlacement",
|
||||
"is_select": false,
|
||||
"select_types": []
|
||||
},
|
||||
{
|
||||
"name": "Representation",
|
||||
"type": "IfcProductRepresentation",
|
||||
"is_select": false,
|
||||
"select_types": []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -854,11 +854,17 @@ class BIM_PT_owner(Panel):
|
||||
scene = context.scene
|
||||
props = scene.BIMProperties
|
||||
|
||||
row = layout.row()
|
||||
row.prop(props, 'person')
|
||||
if not props.person:
|
||||
layout.label(text="No people found.")
|
||||
else:
|
||||
row = layout.row()
|
||||
row.prop(props, 'person')
|
||||
|
||||
row = layout.row()
|
||||
row.prop(props, 'organisation')
|
||||
if not props.organisation:
|
||||
layout.label(text="No organisations found.")
|
||||
else:
|
||||
row = layout.row()
|
||||
row.prop(props, 'organisation')
|
||||
|
||||
|
||||
class BIM_PT_people(Panel):
|
||||
@@ -879,7 +885,7 @@ class BIM_PT_people(Panel):
|
||||
row.operator('bim.add_person')
|
||||
|
||||
if props.people:
|
||||
layout.template_list('BIM_UL_topics', '',
|
||||
layout.template_list('BIM_UL_generic', '',
|
||||
props, 'people', props, 'active_person_index')
|
||||
|
||||
if props.active_person_index < len(props.people):
|
||||
@@ -897,11 +903,9 @@ class BIM_PT_people(Panel):
|
||||
row.prop(person, 'prefix_titles')
|
||||
row = layout.row()
|
||||
row.prop(person, 'suffix_titles')
|
||||
row = layout.row()
|
||||
row.prop(person, 'roles')
|
||||
|
||||
layout.label(text="Roles:")
|
||||
draw_roles_ui(layout, person, 'person')
|
||||
layout.label(text="Addresses:")
|
||||
|
||||
draw_addresses_ui(layout, person, 'person')
|
||||
|
||||
|
||||
@@ -923,7 +927,7 @@ class BIM_PT_organisations(Panel):
|
||||
row.operator('bim.add_organisation')
|
||||
|
||||
if props.organisations:
|
||||
layout.template_list('BIM_UL_topics', '',
|
||||
layout.template_list('BIM_UL_generic', '',
|
||||
props, 'organisations', props, 'active_organisation_index')
|
||||
|
||||
if props.active_organisation_index < len(props.organisations):
|
||||
@@ -933,20 +937,38 @@ class BIM_PT_organisations(Panel):
|
||||
row.operator('bim.remove_organisation', icon='X', text='').index = props.active_organisation_index
|
||||
row = layout.row()
|
||||
row.prop(organisation, 'description')
|
||||
row = layout.row()
|
||||
row.prop(organisation, 'roles')
|
||||
|
||||
layout.label(text="Roles:")
|
||||
draw_roles_ui(layout, organisation, 'organisation')
|
||||
layout.label(text="Addresses:")
|
||||
|
||||
draw_addresses_ui(layout, organisation, 'organisation')
|
||||
|
||||
|
||||
def draw_roles_ui(layout, parent, parent_type):
|
||||
row = layout.row()
|
||||
row.operator(f'bim.add_{parent_type}_role')
|
||||
|
||||
if parent.roles:
|
||||
layout.template_list('BIM_UL_generic', '',
|
||||
parent, 'roles', parent, 'active_role_index')
|
||||
|
||||
if parent.active_role_index < len(parent.roles):
|
||||
role = parent.roles[parent.active_role_index]
|
||||
row = layout.row()
|
||||
row.prop(role, 'name')
|
||||
row.operator(f'bim.remove_{parent_type}_role', icon='X', text='').index = parent.active_role_index
|
||||
if role.name == 'USERDEFINED':
|
||||
row = layout.row()
|
||||
row.prop(role, 'user_defined_role')
|
||||
row = layout.row()
|
||||
row.prop(role, 'description')
|
||||
|
||||
|
||||
def draw_addresses_ui(layout, parent, parent_type):
|
||||
row = layout.row()
|
||||
row.operator(f'bim.add_{parent_type}_address')
|
||||
|
||||
if parent.addresses:
|
||||
layout.template_list('BIM_UL_topics', '',
|
||||
layout.template_list('BIM_UL_generic', '',
|
||||
parent, 'addresses', parent, 'active_address_index')
|
||||
|
||||
if parent.active_address_index < len(parent.addresses):
|
||||
@@ -1437,6 +1459,8 @@ class BIM_PT_mvd(Panel):
|
||||
row.prop(bim_properties, 'import_should_import_native')
|
||||
row = layout.row()
|
||||
row.prop(bim_properties, 'import_should_use_cpu_multiprocessing')
|
||||
row = layout.row()
|
||||
row.prop(bim_properties, 'import_should_import_with_profiling')
|
||||
|
||||
layout.label(text='Simplifications:')
|
||||
|
||||
|
||||
@@ -157,7 +157,8 @@ filename_filters = {
|
||||
'IfcParameterizedProfileDef_IFC4.json': ['IfcParameterizedProfileDef'],
|
||||
'IfcBoundaryCondition_IFC4.json': ['IfcBoundaryCondition'],
|
||||
'IfcElementType_IFC4.json': ['IfcElementType', 'IfcSpatialElementType'],
|
||||
'IfcAnnotation_IFC4.json': ['IfcAnnotation']
|
||||
'IfcAnnotation_IFC4.json': ['IfcAnnotation'],
|
||||
'IfcPositioningElement_IFC4.json': ['IfcGrid'] # IfcPositioningElement in the future
|
||||
}
|
||||
|
||||
for filename, filters in filename_filters.items():
|
||||
|
||||
Reference in New Issue
Block a user