2019-08-29 23:11:12 +10:00
import bpy
2019-09-01 22:03:02 +10:00
import csv
import json
2019-09-03 20:51:58 +10:00
import time
2019-09-01 22:03:02 +10:00
from pathlib import Path
2019-11-06 17:37:51 +11:00
from mathutils import Vector , Matrix
2019-11-07 14:20:54 +11:00
from . helper import SIUnitHelper
2019-09-27 08:43:49 +10:00
from . import ifcopenshell
2019-09-02 19:43:55 +10:00
class ArrayModifier :
count : int
offset : Vector
2019-08-29 23:11:12 +10:00
2019-09-04 16:53:10 +10:00
class QtoCalculator ( ) :
def get_units ( self , o , vg_index ) :
return len ( [ v for v in o . data . vertices if vg_index in [ g . group for g in v . groups ] ] )
2019-09-07 08:04:49 +10:00
2019-09-04 16:53:10 +10:00
def get_length ( self , o , vg_index ) :
length = 0
edges = [ e for e in o . data . edges if (
vg_index in [ g . group for g in o . data . vertices [ e . vertices [ 0 ] ] . groups ] and
vg_index in [ g . group for g in o . data . vertices [ e . vertices [ 1 ] ] . groups ]
) ]
for e in edges :
length + = self . get_edge_distance ( o , e )
return length
2019-09-07 08:04:49 +10:00
2019-09-04 16:53:10 +10:00
def get_edge_distance ( self , object , edge ) :
return ( object . data . vertices [ edge . vertices [ 1 ] ] . co - object . data . vertices [ edge . vertices [ 0 ] ] . co ) . length
2019-09-07 08:04:49 +10:00
2019-09-04 16:53:10 +10:00
def get_area ( self , o , vg_index ) :
area = 0
vertices_in_vg = [ v . index for v in o . data . vertices if vg_index in [ g . group for g in v . groups ] ]
for polygon in o . data . polygons :
if self . is_polygon_in_vg ( polygon , vertices_in_vg ) :
area + = polygon . area
return area
2019-09-07 08:04:49 +10:00
2019-09-04 16:53:10 +10:00
def is_polygon_in_vg ( self , polygon , vertices_in_vg ) :
for v in polygon . vertices :
if v not in vertices_in_vg :
return False
return True
2019-09-07 08:04:49 +10:00
2019-09-04 16:53:10 +10:00
def get_volume ( self , o , vg_index ) :
volume = 0
ob_mat = o . matrix_world
me = o . data
me . calc_loop_triangles ( )
for tf in me . loop_triangles :
tfv = tf . vertices
if len ( tf . vertices ) == 3 :
tf_tris = ( me . vertices [ tfv [ 0 ] ] , me . vertices [ tfv [ 1 ] ] , me . vertices [ tfv [ 2 ] ] ) ,
else :
tf_tris = ( me . vertices [ tfv [ 0 ] ] , me . vertices [ tfv [ 1 ] ] , me . vertices [ tfv [ 2 ] ] ) , \
( me . vertices [ tfv [ 2 ] ] , me . vertices [ tfv [ 3 ] ] , me . vertices [ tfv [ 0 ] ] )
2019-09-07 08:04:49 +10:00
2019-09-04 16:53:10 +10:00
for tf_iter in tf_tris :
v1 = ob_mat @ tf_iter [ 0 ] . co
v2 = ob_mat @ tf_iter [ 1 ] . co
v3 = ob_mat @ tf_iter [ 2 ] . co
2019-09-07 08:04:49 +10:00
2019-09-04 16:53:10 +10:00
volume + = v1 . dot ( v2 . cross ( v3 ) ) / 6.0
return volume
2019-09-08 18:30:16 +10:00
class IfcSchema ( ) :
2019-09-26 21:55:30 +10:00
def __init__ ( self , ifc_export_settings ) :
2019-10-05 21:15:53 +10:00
self . schema_dir = ifc_export_settings . schema_dir
2019-09-08 18:30:16 +10:00
self . property_file = ifcopenshell . open ( self . schema_dir + ' IFC4_ADD2.ifc ' )
self . psets = { }
self . qtos = { }
self . load ( )
with open ( self . schema_dir + ' ifc_types_IFC4.json ' ) as f :
self . type_map = json . load ( f )
2019-11-07 09:11:25 +11:00
with open ( self . schema_dir + ' ifc_elements_IFC4.json ' ) as f :
self . elements = json . load ( f )
2019-09-08 18:30:16 +10:00
def load ( self ) :
for property in self . property_file . by_type ( ' IfcPropertySetTemplate ' ) :
if property . Name [ 0 : 4 ] == ' Qto_ ' :
# self.qtos.append({ })
pass
else :
self . psets [ property . Name ] = {
' HasPropertyTemplates ' : { p . Name : p for p in property . HasPropertyTemplates } }
2019-08-31 23:51:53 +10:00
class IfcParser ( ) :
2019-09-05 17:18:13 +10:00
def __init__ ( self , ifc_export_settings ) :
2019-10-05 21:15:53 +10:00
self . data_dir = ifc_export_settings . data_dir
2019-09-01 22:03:02 +10:00
2019-09-05 17:18:13 +10:00
self . ifc_export_settings = ifc_export_settings
2019-09-01 17:23:48 +10:00
self . selected_products = [ ]
2019-09-05 12:04:34 +10:00
self . product_index = 0
2019-10-03 17:56:45 +10:00
self . product_name_index_map = { }
2019-09-05 12:04:34 +10:00
2019-09-10 17:08:45 +10:00
self . units = { }
2019-11-15 15:44:04 +11:00
self . people = [ ]
self . organisations = [ ]
2019-09-08 19:02:00 +10:00
self . psets = { }
2019-09-11 14:47:53 +10:00
self . documents = { }
self . classifications = [ ]
self . classification_references = { }
2019-09-11 16:50:27 +10:00
self . objectives = { }
2019-09-04 16:53:10 +10:00
self . qtos = { }
2019-09-03 20:52:22 +10:00
self . aggregates = { }
2019-09-28 10:54:10 +10:00
self . materials = { }
2019-08-31 23:51:53 +10:00
self . spatial_structure_elements = [ ]
self . spatial_structure_elements_tree = [ ]
self . rel_contained_in_spatial_structure = { }
2019-09-28 14:08:09 +10:00
self . rel_nests = { }
2019-10-03 17:56:45 +10:00
self . rel_space_boundaries = { }
2019-09-01 18:40:20 +10:00
self . rel_defines_by_type = { }
2019-09-04 16:53:10 +10:00
self . rel_defines_by_qto = { }
2019-09-08 19:02:00 +10:00
self . rel_defines_by_pset = { }
2019-09-11 12:44:36 +10:00
self . rel_associates_document_object = { }
self . rel_associates_document_type = { }
2019-09-11 14:47:53 +10:00
self . rel_associates_classification_object = { }
self . rel_associates_classification_type = { }
2019-09-09 15:11:07 +10:00
self . rel_associates_material = { }
2019-09-28 10:54:10 +10:00
self . rel_associates_material_layer_set = { }
2019-09-28 12:41:51 +10:00
self . rel_associates_material_constituent_set = { }
2019-09-11 16:50:27 +10:00
self . rel_associates_constraint_objective_object = { }
self . rel_associates_constraint_objective_type = { }
2019-09-03 20:52:22 +10:00
self . rel_aggregates = { }
2019-09-08 11:24:41 +10:00
self . representations = { }
2019-09-01 17:23:48 +10:00
self . type_products = [ ]
2019-09-29 22:12:51 +10:00
self . door_attributes = { }
2019-09-29 22:29:06 +10:00
self . window_attributes = { }
2019-09-08 11:07:40 +10:00
self . project = { }
self . libraries = [ ]
2019-08-31 23:51:53 +10:00
self . products = [ ]
def parse ( self ) :
2019-09-10 17:08:45 +10:00
self . units = self . get_units ( )
2019-11-07 16:40:57 +11:00
self . unit_scale = self . get_unit_scale ( )
2019-11-15 15:44:04 +11:00
self . people = self . get_people ( )
self . organisations = self . get_organisations ( )
2019-09-08 11:07:40 +10:00
self . convert_selected_objects_into_products ( bpy . context . selected_objects )
2019-09-01 22:03:02 +10:00
self . psets = self . get_psets ( )
2019-09-11 12:44:36 +10:00
self . documents = self . get_documents ( )
2019-09-11 14:47:53 +10:00
self . classifications = self . get_classifications ( )
self . classification_references = self . get_classification_references ( )
2019-09-11 16:50:27 +10:00
self . objectives = self . get_objectives ( )
2019-09-01 11:45:32 +10:00
self . representations = self . get_representations ( )
2019-09-09 15:11:07 +10:00
self . materials = self . get_materials ( )
2019-10-12 22:20:09 +11:00
self . styled_items = self . get_styled_items ( )
2019-09-04 16:53:10 +10:00
self . qtos = self . get_qtos ( )
2019-09-08 11:07:40 +10:00
self . spatial_structure_elements = self . get_spatial_structure_elements ( )
2019-08-31 23:51:53 +10:00
2019-09-02 19:43:55 +10:00
self . collection_name_filter = [ ]
2019-09-03 20:52:22 +10:00
2019-09-08 11:07:40 +10:00
self . project = self . get_project ( )
self . libraries = self . get_libraries ( )
2019-09-29 22:12:51 +10:00
self . door_attributes = self . get_door_attributes ( )
2019-09-29 22:29:06 +10:00
self . window_attributes = self . get_window_attributes ( )
2019-09-08 11:07:40 +10:00
self . type_products = self . get_type_products ( )
2019-09-08 11:24:41 +10:00
self . get_products ( )
2019-09-07 22:27:52 +10:00
self . map_conversion = self . get_map_conversion ( )
self . target_crs = self . get_target_crs ( )
2019-09-03 20:52:22 +10:00
self . spatial_structure_elements_tree = self . get_spatial_structure_elements_tree (
2019-09-08 11:07:40 +10:00
self . project [ ' raw ' ] . children , self . collection_name_filter )
2019-09-03 20:52:22 +10:00
2019-09-10 17:08:45 +10:00
def get_units ( self ) :
return {
' length ' : {
' ifc ' : None ,
' is_metric ' : bpy . context . scene . unit_settings . system == ' METRIC ' ,
' raw ' : bpy . context . scene . unit_settings . length_unit
} ,
' area ' : {
' ifc ' : None ,
' is_metric ' : bpy . context . scene . unit_settings . system == ' METRIC ' ,
' raw ' : bpy . context . scene . unit_settings . length_unit
} ,
' volume ' : {
' ifc ' : None ,
' is_metric ' : bpy . context . scene . unit_settings . system == ' METRIC ' ,
' raw ' : bpy . context . scene . unit_settings . length_unit
} }
2019-11-07 16:40:57 +11:00
def get_unit_scale ( self ) :
unit_settings = bpy . context . scene . unit_settings
conversions = {
' KILOMETERS ' : 1e3 ,
' CENTIMETERS ' : 1e-2 ,
' MILLIMETERS ' : 1e-3 ,
' MICROMETERS ' : 1e-6 ,
' FEET ' : 0.3048 ,
' INCHES ' : 0.0254 }
if unit_settings . system in { ' METRIC ' , ' IMPERIAL ' } :
scale = unit_settings . scale_length
if unit_settings . length_unit in conversions . keys ( ) :
scale * = conversions [ unit_settings . length_unit ]
return scale
return 1
2019-09-03 20:52:22 +10:00
def get_object_attributes ( self , object ) :
attributes = { ' Name ' : self . get_ifc_name ( object . name ) }
2019-10-21 14:56:40 +11:00
if object . BIMObjectProperties . attributes . find ( ' GlobalId ' ) == - 1 :
global_id = object . BIMObjectProperties . attributes . add ( )
2019-10-16 23:17:48 +11:00
global_id . name = ' GlobalId '
global_id . string_value = ifcopenshell . guid . new ( )
2019-10-21 14:56:40 +11:00
attributes . update ( { a . name : a . string_value for a in object . BIMObjectProperties . attributes } )
2019-09-03 20:52:22 +10:00
return attributes
def get_products ( self ) :
2019-09-08 11:07:40 +10:00
for product in self . selected_products :
object = product [ ' raw ' ]
self . add_product ( self . get_product ( product ) )
self . resolve_array_modifier ( product )
2019-09-05 12:04:34 +10:00
2019-09-08 11:07:40 +10:00
def resolve_array_modifier ( self , product ) :
object = product [ ' raw ' ]
2019-11-16 07:38:21 +11:00
instance_objects = [ ( object , object . matrix_world . translation ) ]
2019-11-08 16:45:39 +11:00
global_id_index = 0
2019-09-05 12:04:34 +10:00
for instance in self . get_instances ( object ) :
created_instances = [ ]
for n in range ( instance . count - 1 ) :
for o in instance_objects :
location = o [ 1 ] + ( ( n + 1 ) * instance . offset )
2019-09-08 11:07:40 +10:00
self . add_product ( self . get_product ( { ' raw ' : o [ 0 ] , ' metadata ' : product [ ' metadata ' ] } ,
2019-11-08 16:45:39 +11:00
{ ' location ' : location } , { ' GlobalId ' : self . get_parametric_global_id ( object , global_id_index ) } ) )
2019-09-05 12:04:34 +10:00
created_instances . append ( ( o [ 0 ] , location ) )
instance_objects . extend ( created_instances )
2019-11-08 16:45:39 +11:00
def get_parametric_global_id ( self , object , index ) :
global_ids = object . BIMObjectProperties . global_ids
total_global_ids = len ( global_ids )
if index < total_global_ids :
return global_ids [ index ] . name
global_id = object . BIMObjectProperties . global_ids . add ( )
global_id . name = ifcopenshell . guid . new ( )
return global_id . name
2019-09-05 12:04:34 +10:00
def add_product ( self , product ) :
self . products . append ( product )
2019-10-03 17:56:45 +10:00
self . product_name_index_map [ product [ ' raw ' ] . name ] = self . product_index
2019-09-05 12:04:34 +10:00
self . product_index + = 1
2019-09-28 14:08:09 +10:00
def get_product_index_from_raw_name ( self , name ) :
for index , product in enumerate ( self . products ) :
if product [ ' raw ' ] . name == name :
return index
2019-09-08 11:07:40 +10:00
def get_product ( self , selected_product , metadata_override = { } , attribute_override = { } ) :
object = selected_product [ ' raw ' ]
2019-09-02 19:43:55 +10:00
product = {
' ifc ' : None ,
' raw ' : object ,
2019-11-16 07:38:21 +11:00
' location ' : object . matrix_world . translation ,
2019-09-02 19:43:55 +10:00
' up_axis ' : object . matrix_world . to_quaternion ( ) @ Vector ( ( 0 , 0 , 1 ) ) ,
' forward_axis ' : object . matrix_world . to_quaternion ( ) @ Vector ( ( 1 , 0 , 0 ) ) ,
2019-11-17 19:08:29 +11:00
' right_axis ' : object . matrix_world . to_quaternion ( ) @ Vector ( ( 0 , 1 , 0 ) ) ,
2019-11-17 20:41:53 +11:00
' has_scale ' : object . scale != Vector ( ( 1 , 1 , 1 ) ) ,
' scale ' : object . scale ,
2019-09-02 19:43:55 +10:00
' class ' : self . get_ifc_class ( object . name ) ,
' relating_structure ' : None ,
2019-09-28 23:43:50 +10:00
' relating_host ' : None ,
2019-09-04 16:53:10 +10:00
' relating_qtos_key ' : None ,
2019-09-16 16:28:26 +10:00
' representations ' : self . get_object_representation_names ( object ) ,
2019-09-02 19:43:55 +10:00
' attributes ' : self . get_object_attributes ( object )
}
2019-09-04 17:46:58 +10:00
product [ ' attributes ' ] . update ( attribute_override )
product . update ( metadata_override )
2019-09-03 20:52:22 +10:00
2019-09-29 22:12:51 +10:00
if object . parent \
and self . is_a_type ( self . get_ifc_class ( object . parent . name ) ) :
reference = self . get_type_product_reference ( object . parent . name )
self . rel_defines_by_type . setdefault ( reference , [ ] ) . append ( self . product_index )
2019-09-29 22:41:26 +10:00
for collection in product [ ' raw ' ] . users_collection :
self . parse_product_collection ( product , collection )
if ' IfcRelNests ' in object . constraints :
parent_product_index = self . get_product_index_from_raw_name (
object . constraints [ ' IfcRelNests ' ] . target . name )
2019-09-28 23:43:50 +10:00
self . rel_nests . setdefault ( parent_product_index , [ ] ) . append ( product )
product [ ' relating_host ' ] = parent_product_index
2019-09-03 20:52:22 +10:00
2019-10-03 17:56:45 +10:00
for name , constraint in object . constraints . items ( ) :
if ' IfcRelSpaceBoundary ' not in name :
continue
self . rel_space_boundaries . setdefault ( self . product_index , [ ] ) . append ( {
' ifc ' : None ,
' class ' : self . get_ifc_class ( name ) ,
' related_building_element_raw_name ' : constraint . target . name ,
' connection_geometry_face_index ' : name . split ( ' / ' ) [ 1 ] ,
' attributes ' : {
' PhysicalOrVirtualBoundary ' : name . split ( ' / ' ) [ 2 ] ,
' InternalOrExternalBoundary ' : name . split ( ' / ' ) [ 3 ]
}
} )
2019-09-03 20:52:22 +10:00
if object . instance_type == ' COLLECTION ' \
and self . is_a_rel_aggregates ( self . get_ifc_class ( object . instance_collection . name ) ) :
2019-09-05 12:04:34 +10:00
self . rel_aggregates [ self . product_index ] = object . name
2019-09-08 11:07:40 +10:00
if ' rel_aggregates_relating_object ' in selected_product [ ' metadata ' ] :
relating_object = selected_product [ ' metadata ' ] [ ' rel_aggregates_relating_object ' ]
2019-09-05 12:04:34 +10:00
product [ ' location ' ] = relating_object . matrix_world @ product [ ' location ' ]
product [ ' up_axis ' ] = ( relating_object . matrix_world . to_quaternion ( ) @ object . matrix_world . to_quaternion ( ) ) @ Vector ( ( 0 , 0 , 1 ) )
product [ ' forward_axis ' ] = ( relating_object . matrix_world . to_quaternion ( ) @ object . matrix_world . to_quaternion ( ) ) @ Vector ( ( 1 , 0 , 0 ) )
self . aggregates . setdefault ( relating_object . name , [ ] ) . append ( self . product_index )
2019-09-03 20:51:39 +10:00
2019-09-04 16:53:10 +10:00
if object . name in self . qtos :
self . rel_defines_by_qto . setdefault ( object . name , [ ] ) . append ( product )
2019-10-21 14:56:40 +11:00
for pset in object . BIMObjectProperties . psets :
2019-10-19 11:36:29 +11:00
self . rel_defines_by_pset . setdefault (
' {} / {} ' . format ( pset . name , pset . file ) , [ ] ) . append ( product )
2019-10-21 15:31:10 +11:00
for document in object . BIMObjectProperties . documents :
self . rel_associates_document_object . setdefault (
document . file , [ ] ) . append ( product )
2019-11-01 17:44:10 +11:00
for classification in object . BIMObjectProperties . classifications :
self . rel_associates_classification_object . setdefault (
classification . identification , [ ] ) . append ( product )
2019-09-08 19:02:00 +10:00
for key in object . keys ( ) :
2019-11-01 17:44:10 +11:00
if key [ 0 : 9 ] == ' Objective ' :
2019-09-11 16:50:27 +10:00
self . rel_associates_constraint_objective_object . setdefault (
object [ key ] , [ ] ) . append ( product )
2019-09-08 19:02:00 +10:00
2019-10-12 22:20:09 +11:00
for slot in object . material_slots :
if slot . link == ' OBJECT ' :
continue
if ' IsMaterialLayerSet ' in object :
2019-09-28 10:54:10 +10:00
self . rel_associates_material_layer_set . setdefault ( self . product_index , [ ] ) . append ( slot . material . name )
2019-10-12 22:20:09 +11:00
elif ' IsMaterialConstituentSet ' in object :
2019-09-28 12:41:51 +10:00
self . rel_associates_material_constituent_set . setdefault ( self . product_index , [ ] ) . append ( slot . material . name )
2019-10-12 22:20:09 +11:00
else :
2019-09-28 10:54:10 +10:00
self . rel_associates_material . setdefault ( slot . material . name , [ ] ) . append ( product )
2019-09-09 15:11:07 +10:00
2019-09-02 19:43:55 +10:00
return product
2019-09-05 12:04:34 +10:00
def parse_product_collection ( self , product , collection ) :
2019-09-29 22:41:26 +10:00
if collection is None :
return
2019-09-03 20:52:22 +10:00
class_name = self . get_ifc_class ( collection . name )
if self . is_a_spatial_structure_element ( class_name ) :
reference = self . get_spatial_structure_element_reference ( collection . name )
2019-09-05 12:04:34 +10:00
self . rel_contained_in_spatial_structure . setdefault ( reference , [ ] ) . append ( self . product_index )
2019-09-03 20:52:22 +10:00
product [ ' relating_structure ' ] = reference
self . collection_name_filter . append ( collection . name )
elif self . is_a_rel_aggregates ( class_name ) :
2019-09-05 12:04:34 +10:00
pass
2019-09-03 20:52:22 +10:00
else :
2019-09-29 22:41:26 +10:00
self . parse_product_collection ( product , self . get_parent_collection ( collection ) )
2019-09-03 20:51:39 +10:00
def get_parent_collection ( self , child_collection ) :
for parent_collection in bpy . data . collections :
for child in parent_collection . children :
if child . name == child_collection . name :
return parent_collection
2019-09-02 19:43:55 +10:00
def get_instances ( self , object ) :
instances = [ ]
for m in object . modifiers :
if m . type == ' ARRAY ' :
array = ArrayModifier ( )
world_rotation = object . matrix_world . decompose ( ) [ 1 ]
array . offset = world_rotation @ Vector (
( m . constant_offset_displace [ 0 ] , m . constant_offset_displace [ 1 ] , m . constant_offset_displace [ 2 ] ) )
if m . fit_type == ' FIXED_COUNT ' :
array . count = m . count
elif m . fit_type == ' FIT_LENGTH ' :
array . count = int ( m . fit_length / array . offset . length )
instances . append ( array )
return instances
2019-09-08 11:07:40 +10:00
def convert_selected_objects_into_products ( self , objects_to_sort , metadata = None ) :
2019-09-05 12:04:34 +10:00
if not metadata :
metadata = { }
2019-09-03 20:52:22 +10:00
for object in objects_to_sort :
2019-09-08 11:07:40 +10:00
if not self . is_a_library ( self . get_ifc_class ( object . users_collection [ 0 ] . name ) ) :
self . selected_products . append ( { ' raw ' : object , ' metadata ' : metadata } )
2019-09-05 12:04:34 +10:00
if object . instance_type == ' COLLECTION ' :
2019-09-08 11:07:40 +10:00
self . convert_selected_objects_into_products ( object . instance_collection . objects ,
2019-09-05 12:04:34 +10:00
{ ' rel_aggregates_relating_object ' : object } )
2019-09-01 17:23:48 +10:00
2019-09-01 22:03:02 +10:00
def get_psets ( self ) :
2019-09-08 19:02:00 +10:00
psets = { }
2019-09-11 12:44:36 +10:00
for filename in Path ( self . data_dir + ' pset/ ' ) . glob ( ' **/*.csv ' ) :
2019-09-01 22:03:02 +10:00
with open ( filename , ' r ' ) as f :
2019-09-08 19:02:00 +10:00
name = filename . parts [ - 2 ]
description = filename . stem
psets [ ' {} / {} ' . format ( name , description ) ] = {
2019-09-01 22:03:02 +10:00
' ifc ' : None ,
2019-09-08 18:30:16 +10:00
' raw ' : { x [ 0 ] : x [ 1 ] for x in list ( csv . reader ( f ) ) } ,
2019-09-01 22:03:02 +10:00
' attributes ' : {
2019-09-08 19:02:00 +10:00
' Name ' : name ,
' Description ' : description }
}
2019-09-01 22:03:02 +10:00
return psets
2019-09-29 22:12:51 +10:00
def get_door_attributes ( self ) :
2019-09-29 22:29:06 +10:00
return self . get_predefined_attributes ( ' door ' )
def get_window_attributes ( self ) :
return self . get_predefined_attributes ( ' window ' )
def get_predefined_attributes ( self , type ) :
2019-09-29 22:12:51 +10:00
results = { }
2019-09-29 22:29:06 +10:00
for filename in Path ( self . data_dir + type + ' / ' ) . glob ( ' **/*.csv ' ) :
2019-09-29 22:12:51 +10:00
with open ( filename , ' r ' ) as f :
type_name = filename . parts [ - 2 ]
pset_name = filename . stem
results . setdefault ( type_name , [ ] ) . append ( {
' ifc ' : None ,
' raw ' : { x [ 0 ] : x [ 1 ] for x in list ( csv . reader ( f ) ) } ,
' pset_name ' : pset_name . split ( ' . ' ) [ 0 ]
} )
return results
2019-09-11 14:47:53 +10:00
def get_classifications ( self ) :
results = [ ]
class_path = self . data_dir + ' class/ '
with open ( class_path + ' classifications.csv ' , ' r ' ) as f :
data = list ( csv . reader ( f ) )
keys = data . pop ( 0 )
for row in data :
row [ - 1 ] = json . loads ( row [ - 1 ] )
results . append ( {
' ifc ' : None ,
' raw ' : row ,
' attributes ' : dict ( zip ( keys , row ) )
} )
return results
def get_classification_references ( self ) :
results = { }
class_path = self . data_dir + ' class/ '
with open ( class_path + ' references.csv ' , ' r ' ) as f :
data = list ( csv . reader ( f ) )
keys = data . pop ( 0 )
for row in data :
results [ row [ 0 ] ] = {
' ifc ' : None ,
' raw ' : row ,
' referenced_source ' : int ( row . pop ( ) ) ,
' attributes ' : dict ( zip ( keys , row ) )
}
return results
2019-09-11 16:50:27 +10:00
def get_objectives ( self ) :
results = { }
class_path = self . data_dir + ' constraint/ '
with open ( class_path + ' objectives.csv ' , ' r ' ) as f :
data = list ( csv . reader ( f ) )
keys = data . pop ( 0 )
for row in data :
results [ row [ 0 ] ] = {
' ifc ' : None ,
' raw ' : row ,
' attributes ' : dict ( zip ( keys , row ) )
}
return results
2019-11-15 15:44:04 +11:00
def get_people ( self ) :
with open ( self . data_dir + ' owner/person.json ' ) as file :
return json . load ( file )
def get_organisations ( self ) :
with open ( self . data_dir + ' owner/organisation.json ' ) as file :
return json . load ( file )
2019-09-11 12:44:36 +10:00
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 ] = {
' ifc ' : None ,
' raw ' : filename ,
' attributes ' : {
' Location ' : uri ,
' Name ' : filename . stem
} }
return documents
2019-09-08 11:07:40 +10:00
def get_project ( self ) :
2019-08-31 23:51:53 +10:00
for collection in bpy . data . collections :
2019-09-08 11:07:40 +10:00
if self . is_a_project ( self . get_ifc_class ( collection . name ) ) :
2019-08-31 23:51:53 +10:00
return {
' ifc ' : None ,
' raw ' : collection ,
2019-09-01 17:23:48 +10:00
' class ' : self . get_ifc_class ( collection . name ) ,
2019-09-08 20:51:59 +10:00
' attributes ' : self . get_object_attributes ( collection )
2019-08-31 23:51:53 +10:00
}
2019-09-08 11:07:40 +10:00
def get_libraries ( self ) :
results = [ ]
for collection in self . project [ ' raw ' ] . children :
if not self . is_a_library ( self . get_ifc_class ( collection . name ) ) :
continue
results . append ( {
' ifc ' : None ,
' raw ' : collection ,
' class ' : self . get_ifc_class ( collection . name ) ,
2019-09-08 14:55:23 +10:00
' rel_declares_type_products ' : [ ] ,
2019-09-08 20:51:59 +10:00
' attributes ' : self . get_object_attributes ( collection )
2019-09-08 11:07:40 +10:00
} )
return results
2019-09-07 22:27:52 +10:00
def get_map_conversion ( self ) :
scene = bpy . context . scene
2019-10-19 15:15:42 +11:00
if not scene . BIMProperties . has_georeferencing :
2019-09-07 22:27:52 +10:00
return { }
return {
' ifc ' : None ,
' attributes ' : {
2019-10-19 15:15:42 +11:00
' Eastings ' : float ( scene . MapConversion . eastings ) ,
' Northings ' : float ( scene . MapConversion . northings ) ,
' OrthogonalHeight ' : float ( scene . MapConversion . orthogonal_height ) ,
' XAxisAbscissa ' : float ( scene . MapConversion . x_axis_abscissa ) ,
' XAxisOrdinate ' : float ( scene . MapConversion . x_axis_ordinate ) ,
' Scale ' : float ( scene . MapConversion . scale )
2019-09-07 22:27:52 +10:00
}
}
def get_target_crs ( self ) :
scene = bpy . context . scene
2019-10-19 15:15:42 +11:00
if not scene . BIMProperties . has_georeferencing :
2019-09-07 22:27:52 +10:00
return { }
return {
' ifc ' : None ,
' attributes ' : {
2019-10-19 15:15:42 +11:00
' Name ' : scene . TargetCRS . name ,
' Description ' : scene . TargetCRS . description ,
' GeodeticDatum ' : scene . TargetCRS . geodetic_datum ,
' VerticalDatum ' : scene . TargetCRS . vertical_datum ,
' MapProjection ' : scene . TargetCRS . map_projection ,
' MapZone ' : str ( scene . TargetCRS . map_zone ) ,
' MapUnit ' : scene . TargetCRS . map_unit
2019-09-07 22:27:52 +10:00
}
}
2019-08-31 23:51:53 +10:00
def get_spatial_structure_elements ( self ) :
elements = [ ]
for collection in bpy . data . collections :
if self . is_a_spatial_structure_element ( self . get_ifc_class ( collection . name ) ) :
elements . append ( {
' ifc ' : None ,
' raw ' : collection ,
2019-09-01 17:23:48 +10:00
' class ' : self . get_ifc_class ( collection . name ) ,
2019-09-08 20:51:59 +10:00
' attributes ' : self . get_object_attributes ( collection )
2019-08-31 23:51:53 +10:00
} )
return elements
2019-09-01 11:45:32 +10:00
def get_representations ( self ) :
2019-09-08 11:24:41 +10:00
results = { }
2019-09-05 17:18:13 +10:00
if not self . ifc_export_settings . has_representations :
return results
2019-09-08 11:07:40 +10:00
for product in self . selected_products + self . type_products :
object = product [ ' raw ' ]
2019-09-08 11:24:41 +10:00
if not object . data \
or object . data . name in results :
2019-09-03 20:52:22 +10:00
continue
2019-09-16 16:28:26 +10:00
2019-09-17 12:56:43 +10:00
self . append_default_representation ( object , results )
self . append_representation_per_context ( object , results )
2019-09-01 11:45:32 +10:00
return results
2019-09-17 12:56:43 +10:00
def append_default_representation ( self , object , results ) :
if not self . is_mesh_context_sensitive ( object . data . name ) :
2019-11-07 21:49:14 +11:00
results [ ' Model/Body/MODEL_VIEW/ {} ' . format ( object . data . name ) ] = self . get_representation (
object . data , object , ' Model ' , ' Body ' , ' MODEL_VIEW ' )
2019-09-17 12:56:43 +10:00
def append_representation_per_context ( self , object , results ) :
name = self . get_ifc_representation_name ( object . data . name )
2019-11-07 21:49:14 +11:00
for context in self . ifc_export_settings . context_tree :
for subcontext in context [ ' subcontexts ' ] :
for target_view in subcontext [ ' target_views ' ] :
mesh_name = ' / ' . join ( [ context [ ' name ' ] , subcontext [ ' name ' ] , target_view , name ] )
try :
mesh = bpy . data . meshes [ mesh_name ]
except :
continue
results [ mesh_name ] = self . get_representation (
mesh , object , context [ ' name ' ] , subcontext [ ' name ' ] , target_view )
def get_representation ( self , mesh , object , context , subcontext , target_view , is_generated = False ) :
2019-09-16 16:28:26 +10:00
return {
' ifc ' : None ,
' raw ' : mesh ,
2019-09-20 09:15:32 +10:00
' raw_object ' : object ,
2019-09-16 16:28:26 +10:00
' context ' : context ,
' subcontext ' : subcontext ,
2019-11-07 21:49:14 +11:00
' target_view ' : target_view ,
2019-11-05 21:49:17 +11:00
' is_curve ' : isinstance ( mesh , bpy . types . Curve ) ,
' is_wireframe ' : mesh . BIMMeshProperties . is_wireframe if hasattr ( mesh , ' BIMMeshProperties ' ) else False ,
' is_swept_solid ' : mesh . BIMMeshProperties . is_swept_solid if hasattr ( mesh , ' BIMMeshProperties ' ) else False ,
2019-09-17 12:56:43 +10:00
' is_generated ' : is_generated ,
2019-09-16 16:28:26 +10:00
' attributes ' : { ' Name ' : mesh . name }
}
def is_mesh_context_sensitive ( self , name ) :
return ' / ' in name
def get_ifc_representation_name ( self , name ) :
if self . is_mesh_context_sensitive ( name ) :
2019-11-07 21:49:14 +11:00
return name . split ( ' / ' ) [ 3 ]
2019-09-16 16:28:26 +10:00
return name
2019-09-09 15:11:07 +10:00
def get_materials ( self ) :
results = { }
if not self . ifc_export_settings . has_representations :
return results
for product in self . selected_products + self . type_products :
object = product [ ' raw ' ]
if not object . data :
continue
for slot in object . material_slots :
2019-10-12 22:20:09 +11:00
if slot . material . name in results \
or slot . link == ' OBJECT ' :
2019-09-09 15:11:07 +10:00
continue
results [ slot . material . name ] = {
' ifc ' : None ,
2019-09-28 10:54:10 +10:00
' layer_ifc ' : None ,
2019-09-28 12:41:51 +10:00
' constituent_ifc ' : None ,
2019-09-09 15:11:07 +10:00
' raw ' : slot . material ,
2019-09-28 10:54:10 +10:00
' is_material_layer_set ' : True if ' IsMaterialLayerSet ' in object . keys ( ) else False ,
2019-09-28 12:41:51 +10:00
' is_material_constituent_set ' : True if ' IsMaterialConstituentSet ' in object . keys ( ) else False ,
2019-09-28 10:54:10 +10:00
' attributes ' : { ' Name ' : slot . material . name } ,
' layer_attributes ' : { key [ 3 : ] : slot . material [ key ] for key in
2019-09-28 12:41:51 +10:00
slot . material . keys ( ) if key [ 0 : 3 ] == ' Ifc ' } ,
' constituent_attributes ' : { key [ 3 : ] : slot . material [ key ] for key in
2019-09-28 10:54:10 +10:00
slot . material . keys ( ) if key [ 0 : 3 ] == ' Ifc ' }
2019-09-09 15:11:07 +10:00
}
return results
2019-10-12 22:20:09 +11:00
def get_styled_items ( self ) :
2019-10-15 18:10:32 +11:00
results = [ ]
2019-10-12 22:20:09 +11:00
if not self . ifc_export_settings . has_representations :
return results
for product in self . selected_products + self . type_products :
object = product [ ' raw ' ]
if not object . data :
continue
for slot in object . material_slots :
2019-11-08 15:10:51 +11:00
if not self . ifc_export_settings . should_export_all_materials_as_styled_items :
if slot . material . name in results \
or slot . link == ' DATA ' :
continue
2019-10-15 18:10:32 +11:00
results . append ( {
2019-10-12 22:20:09 +11:00
' ifc ' : None ,
' raw ' : slot . material ,
' related_product_name ' : product [ ' raw ' ] . name ,
' attributes ' : { ' Name ' : slot . material . name } ,
2019-10-15 18:10:32 +11:00
} )
2019-10-12 22:20:09 +11:00
return results
2019-09-04 16:53:10 +10:00
def get_qtos ( self ) :
2019-09-05 17:18:13 +10:00
if not self . ifc_export_settings . has_quantities :
return { }
2019-09-04 16:53:10 +10:00
results = { }
2019-09-08 11:07:40 +10:00
for product in self . selected_products + self . type_products :
object = product [ ' raw ' ]
2019-09-04 16:53:10 +10:00
if not object . data :
continue
for property in object . keys ( ) :
if property [ 0 : 4 ] != ' Qto_ ' :
continue
results [ object . name ] = {
' ifc ' : None ,
' raw ' : object ,
' class ' : property ,
' attributes ' : {
' Name ' : property ,
' MethodOfMeasurement ' : object [ property ]
}
}
return results
2019-09-01 17:23:48 +10:00
def get_type_products ( self ) :
2019-09-08 11:07:40 +10:00
results = [ ]
2019-09-08 14:55:23 +10:00
index = 0
2019-09-08 11:07:40 +10:00
for library in self . libraries :
for object in library [ ' raw ' ] . objects :
if not self . is_a_type ( self . get_ifc_class ( object . name ) ) :
continue
try :
2019-09-11 12:44:36 +10:00
type = {
2019-09-08 11:07:40 +10:00
' ifc ' : None ,
' raw ' : object ,
2019-11-16 07:38:21 +11:00
' location ' : object . translation ,
2019-09-08 11:07:40 +10:00
' up_axis ' : object . matrix_world . to_quaternion ( ) @ Vector ( ( 0 , 0 , 1 ) ) ,
' forward_axis ' : object . matrix_world . to_quaternion ( ) @ Vector ( ( 1 , 0 , 0 ) ) ,
2019-10-19 11:36:29 +11:00
' psets ' : [ ' {} / {} ' . format ( pset . name , pset . file ) for pset in
2019-10-21 14:56:40 +11:00
object . BIMObjectProperties . psets ] ,
2019-09-08 11:07:40 +10:00
' class ' : self . get_ifc_class ( object . name ) ,
2019-09-16 16:28:26 +10:00
' representations ' : self . get_object_representation_names ( object ) ,
2019-09-08 11:07:40 +10:00
' attributes ' : self . get_object_attributes ( object )
2019-09-11 12:44:36 +10:00
}
results . append ( type )
2019-09-08 14:55:23 +10:00
library [ ' rel_declares_type_products ' ] . append ( index )
2019-09-11 12:44:36 +10:00
for key in object . keys ( ) :
if key [ 0 : 3 ] == ' Doc ' :
self . rel_associates_document_type . setdefault (
object [ key ] , [ ] ) . append ( type )
2019-09-11 14:47:53 +10:00
elif key [ 0 : 5 ] == ' Class ' :
self . rel_associates_classification_type . setdefault (
object [ key ] , [ ] ) . append ( type )
2019-09-11 16:50:27 +10:00
elif key [ 0 : 9 ] == ' Objective ' :
self . rel_associates_constraint_objective_type . setdefault (
object [ key ] , [ ] ) . append ( type )
2019-09-11 12:44:36 +10:00
2019-09-08 14:55:23 +10:00
index + = 1
2019-09-08 11:07:40 +10:00
except Exception as e :
2019-10-07 21:11:11 +11:00
self . ifc_export_settings . logger . error ( ' The type product " {} " could not be parsed: {} ' . format ( object . name , e . args ) )
2019-09-08 11:07:40 +10:00
return results
2019-09-01 17:23:48 +10:00
2019-09-16 16:28:26 +10:00
def get_object_representation_names ( self , object ) :
names = [ ]
if not object . data :
return names
if not self . is_mesh_context_sensitive ( object . data . name ) :
2019-11-07 21:49:14 +11:00
names . append ( ' Model/Body/MODEL_VIEW/ {} ' . format ( object . data . name ) )
name = self . get_ifc_representation_name ( object . data . name )
for context in self . ifc_export_settings . context_tree :
for subcontext in context [ ' subcontexts ' ] :
for target_view in subcontext [ ' target_views ' ] :
mesh_name = ' / ' . join ( [ context [ ' name ' ] , subcontext [ ' name ' ] , target_view , name ] )
try :
mesh = bpy . data . meshes [ mesh_name ]
except :
continue
names . append ( mesh_name )
2019-09-16 16:28:26 +10:00
return names
2019-09-01 11:45:32 +10:00
2019-08-31 23:51:53 +10:00
def get_spatial_structure_elements_tree ( self , collections , name_filter ) :
collection_tree = [ ]
for collection in collections :
if not self . is_a_spatial_structure_element ( self . get_ifc_class ( collection . name ) ) :
continue
children = self . get_spatial_structure_elements_tree (
collection . children , name_filter )
if collection . name in name_filter \
or children :
collection_tree . append ( {
' reference ' : self . get_spatial_structure_element_reference ( collection . name ) ,
' children ' : children
} )
return collection_tree
def get_spatial_structure_element_reference ( self , name ) :
2019-10-12 18:53:40 +11:00
return [ ' {} / {} ' . format ( e [ ' class ' ] , e [ ' attributes ' ] [ ' Name ' ] ) for e in
self . spatial_structure_elements ] . index ( name )
2019-08-31 23:51:53 +10:00
2019-09-01 18:40:20 +10:00
def get_type_product_reference ( self , name ) :
return [ p [ ' attributes ' ] [ ' Name ' ] for p in self . type_products ] . index ( self . get_ifc_name ( name ) )
2019-08-31 23:51:53 +10:00
def get_ifc_class ( self , name ) :
return name . split ( ' / ' ) [ 0 ]
def get_ifc_name ( self , name ) :
2019-09-01 10:32:22 +10:00
try :
return name . split ( ' / ' ) [ 1 ]
except IndexError :
2019-10-07 21:11:11 +11:00
self . ifc_export_settings . logger . error ( ' Name " {} " does not follow the format of " IfcClass/Name " ' . format ( name ) )
2019-08-31 23:51:53 +10:00
def is_a_spatial_structure_element ( self , class_name ) :
2019-09-01 17:23:48 +10:00
# We assume that any collection we can't identify is a spatial structure
return class_name [ 0 : 3 ] == ' Ifc ' \
2019-09-08 11:07:40 +10:00
and not self . is_a_project ( class_name ) \
and not self . is_a_library ( class_name ) \
2019-09-03 20:52:22 +10:00
and not self . is_a_rel_aggregates ( class_name )
def is_a_rel_aggregates ( self , class_name ) :
return class_name == ' IfcRelAggregates '
2019-08-31 23:51:53 +10:00
2019-09-08 11:07:40 +10:00
def is_a_project ( self , class_name ) :
return class_name == ' IfcProject '
def is_a_library ( self , class_name ) :
return class_name == ' IfcProjectLibrary '
2019-08-31 23:51:53 +10:00
2019-09-01 18:40:20 +10:00
def is_a_type ( self , class_name ) :
return class_name [ 0 : 3 ] == ' Ifc ' and class_name [ - 4 : ] == ' Type '
2019-08-31 23:51:53 +10:00
class IfcExporter ( ) :
2019-09-08 18:30:16 +10:00
def __init__ ( self , ifc_export_settings , ifc_schema , ifc_parser , qto_calculator ) :
2019-10-05 21:15:53 +10:00
self . template_file = ' {} template.ifc ' . format ( ifc_export_settings . schema_dir )
2019-09-05 17:18:13 +10:00
self . ifc_export_settings = ifc_export_settings
2019-09-08 18:30:16 +10:00
self . ifc_schema = ifc_schema
2019-08-31 23:51:53 +10:00
self . ifc_parser = ifc_parser
2019-09-04 16:53:10 +10:00
self . qto_calculator = qto_calculator
2019-08-29 23:11:12 +10:00
2019-08-31 17:37:53 +10:00
def export ( self ) :
self . file = ifcopenshell . open ( self . template_file )
self . set_common_definitions ( )
2019-09-01 10:26:54 +10:00
self . ifc_parser . parse ( )
2019-09-10 17:08:45 +10:00
self . create_units ( )
2019-11-15 15:44:04 +11:00
self . create_people ( )
self . create_organisations ( )
2019-09-16 13:16:58 +10:00
self . create_rep_context ( )
self . create_project ( )
2019-09-11 12:44:36 +10:00
self . create_documents ( )
2019-09-11 14:47:53 +10:00
self . create_classifications ( )
self . create_classification_references ( )
2019-09-11 16:50:27 +10:00
self . create_objectives ( )
2019-09-01 22:03:02 +10:00
self . create_psets ( )
2019-09-08 11:07:40 +10:00
self . create_libraries ( )
2019-09-07 22:27:52 +10:00
self . create_map_conversion ( )
2019-09-01 11:45:32 +10:00
self . create_representations ( )
2019-09-09 15:11:07 +10:00
self . create_materials ( )
2019-09-01 17:23:48 +10:00
self . create_type_products ( )
self . create_spatial_structure_elements ( self . ifc_parser . spatial_structure_elements_tree )
2019-09-04 16:53:10 +10:00
self . create_qtos ( )
2019-08-31 17:37:53 +10:00
self . create_products ( )
2019-10-12 22:20:09 +11:00
self . create_styled_items ( )
2019-09-08 14:55:23 +10:00
self . relate_definitions_to_contexts ( )
2019-09-03 20:52:22 +10:00
self . relate_objects_to_objects ( )
2019-08-31 23:51:53 +10:00
self . relate_elements_to_spatial_structures ( )
2019-09-28 14:08:09 +10:00
self . relate_nested_elements_to_hosted_elements ( )
2019-09-01 18:40:20 +10:00
self . relate_objects_to_types ( )
2019-09-04 16:53:10 +10:00
self . relate_objects_to_qtos ( )
2019-09-08 19:02:00 +10:00
self . relate_objects_to_psets ( )
2019-09-09 15:11:07 +10:00
self . relate_objects_to_materials ( )
2019-09-28 10:54:10 +10:00
self . relate_objects_to_material_layer_sets ( )
2019-09-28 12:41:51 +10:00
self . relate_objects_to_material_constituent_sets ( )
2019-10-03 17:56:45 +10:00
self . relate_spaces_to_boundary_elements ( )
2019-09-11 12:44:36 +10:00
self . relate_to_documents ( self . ifc_parser . rel_associates_document_object )
self . relate_to_documents ( self . ifc_parser . rel_associates_document_type )
2019-09-11 14:47:53 +10:00
self . relate_to_classifications ( self . ifc_parser . rel_associates_classification_object )
self . relate_to_classifications ( self . ifc_parser . rel_associates_classification_type )
2019-09-11 16:50:27 +10:00
self . relate_to_objectives ( self . ifc_parser . rel_associates_constraint_objective_object )
self . relate_to_objectives ( self . ifc_parser . rel_associates_constraint_objective_type )
2019-10-08 23:05:27 +11:00
self . file . write ( self . ifc_export_settings . output_file )
2019-08-29 23:11:12 +10:00
2019-08-31 17:37:53 +10:00
def set_common_definitions ( self ) :
# Owner history doesn't actually work like this, but for now, it does :)
2019-09-10 17:08:45 +10:00
self . origin = self . file . by_type ( ' IfcAxis2Placement3D ' ) [ 0 ]
2019-09-10 20:11:58 +10:00
self . owner_history = self . file . by_type ( ' IfcOwnerHistory ' ) [ 0 ]
2019-09-10 17:08:45 +10:00
def create_units ( self ) :
for type , data in self . ifc_parser . units . items ( ) :
if data [ ' is_metric ' ] :
2019-11-07 16:40:57 +11:00
data [ ' ifc ' ] = self . create_metric_unit ( type , data )
2019-09-10 17:08:45 +10:00
else :
2019-11-07 16:40:57 +11:00
data [ ' ifc ' ] = self . create_imperial_unit ( type , data )
2019-09-10 17:08:45 +10:00
self . file . createIfcUnitAssignment ( [ u [ ' ifc ' ] for u in self . ifc_parser . units . values ( ) ] )
2019-11-07 16:40:57 +11:00
def create_metric_unit ( self , type , data ) :
type_prefix = ' '
if type == ' area ' :
type_prefix = ' SQUARE_ '
elif type == ' volume ' :
type_prefix = ' CUBIC_ '
return self . file . createIfcSIUnit ( None ,
' {} UNIT ' . format ( type . upper ( ) ) ,
SIUnitHelper . get_prefix ( data [ ' raw ' ] ) ,
type_prefix + SIUnitHelper . get_unit_name ( data [ ' raw ' ] ) )
2019-09-10 17:08:45 +10:00
def create_imperial_unit ( self , type , data ) :
2019-11-07 16:40:57 +11:00
if type == ' length ' :
dimensional_exponents = self . file . createIfcDimensionalExponents ( 1 , 0 , 0 , 0 , 0 , 0 , 0 )
name_prefix = ' '
elif type == ' area ' :
dimensional_exponents = self . file . createIfcDimensionalExponents ( 2 , 0 , 0 , 0 , 0 , 0 , 0 )
name_prefix = ' square '
elif type == ' volume ' :
dimensional_exponents = self . file . createIfcDimensionalExponents ( 3 , 0 , 0 , 0 , 0 , 0 , 0 )
name_prefix = ' cubic '
si_unit = self . file . createIfcSIUnit ( None , ' {} UNIT ' . format ( type . upper ( ) ) , None ,
' {} METRE ' . format ( name_prefix . upper ( ) + ' _ ' if name_prefix else ' ' ) )
if data [ ' raw ' ] == ' INCHES ' :
name = ' {} inch ' . format ( name_prefix + ' ' if name_prefix else ' ' )
elif data [ ' raw ' ] == ' FEET ' :
name = ' {} foot ' . format ( name_prefix + ' ' if name_prefix else ' ' )
value_component = self . file . create_entity ( ' IfcReal ' ,
* * { ' wrappedValue ' : SIUnitHelper . si_conversions [ name ] } )
conversion_factor = self . file . createIfcMeasureWithUnit ( value_component , si_unit )
return self . file . createIfcConversionBasedUnit (
dimensional_exponents , ' {} UNIT ' . format ( type . upper ( ) ) ,
name , conversion_factor )
2019-08-29 23:11:12 +10:00
2019-11-15 15:44:04 +11:00
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 )
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 )
def create_roles ( self , roles ) :
results = [ ]
for role in roles :
results . append ( self . file . create_entity ( ' IfcActorRole ' , * * role ) )
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 :
results . append ( self . file . create_entity ( ' IfcTelecomAddress ' , * * address ) )
return results
2019-09-11 12:44:36 +10:00
def create_documents ( self ) :
for document in self . ifc_parser . documents . values ( ) :
document [ ' ifc ' ] = self . file . create_entity (
' IfcDocumentReference ' , * * document [ ' attributes ' ] )
2019-09-16 13:16:58 +10:00
self . file . createIfcRelAssociatesDocument (
ifcopenshell . guid . new ( ) , None , None , None ,
[ self . ifc_parser . project [ ' ifc ' ] ] , document [ ' ifc ' ] )
2019-09-11 12:44:36 +10:00
2019-09-11 14:47:53 +10:00
def create_classifications ( self ) :
for classification in self . ifc_parser . classifications :
classification [ ' ifc ' ] = self . file . create_entity (
' IfcClassification ' , * * classification [ ' attributes ' ] )
2019-09-16 13:16:58 +10:00
self . file . createIfcRelAssociatesClassification (
ifcopenshell . guid . new ( ) , None , None , None ,
[ self . ifc_parser . project [ ' ifc ' ] ] , classification [ ' ifc ' ] )
2019-09-11 14:47:53 +10:00
def create_classification_references ( self ) :
for reference in self . ifc_parser . classification_references . values ( ) :
reference [ ' attributes ' ] [ ' ReferencedSource ' ] = self . ifc_parser . classifications [ reference [ ' referenced_source ' ] ] [ ' ifc ' ]
reference [ ' ifc ' ] = self . file . create_entity (
' IfcClassificationReference ' , * * reference [ ' attributes ' ] )
2019-09-11 16:50:27 +10:00
def create_objectives ( self ) :
for objective in self . ifc_parser . objectives . values ( ) :
objective [ ' ifc ' ] = self . file . create_entity (
' IfcObjective ' , * * objective [ ' attributes ' ] )
2019-09-01 22:03:02 +10:00
def create_psets ( self ) :
2019-09-08 19:02:00 +10:00
for pset in self . ifc_parser . psets . values ( ) :
2019-09-01 22:03:02 +10:00
properties = self . create_pset_properties ( pset )
if not properties :
2019-10-07 22:14:52 +11:00
self . ifc_export_settings . logger . error (
' No properties could be detected for the pset {} / {} ' . format (
pset [ ' attributes ' ] [ ' Name ' ] ,
pset [ ' attributes ' ] [ ' Description ' ] ) )
2019-09-01 22:03:02 +10:00
continue
pset [ ' attributes ' ] . update ( {
' GlobalId ' : ifcopenshell . guid . new ( ) ,
' OwnerHistory ' : self . owner_history ,
' HasProperties ' : properties
} )
pset [ ' ifc ' ] = self . file . create_entity ( ' IfcPropertySet ' , * * pset [ ' attributes ' ] )
def create_pset_properties ( self , pset ) :
2019-10-19 14:45:07 +11:00
if pset [ ' attributes ' ] [ ' Name ' ] in self . ifc_schema . psets :
return self . create_templated_pset_properties ( pset )
return self . create_custom_pset_properties ( pset )
def create_custom_pset_properties ( self , pset ) :
properties = [ ]
for key , value in pset [ ' raw ' ] . items ( ) :
properties . append (
self . file . create_entity ( ' IfcPropertySingleValue ' , * * {
' Name ' : key ,
' NominalValue ' : self . file . create_entity ( ' IfcLabel ' , value )
} ) )
return properties
def create_templated_pset_properties ( self , pset ) :
2019-09-01 22:03:02 +10:00
properties = [ ]
2019-09-08 18:30:16 +10:00
templates = self . ifc_schema . psets [ pset [ ' attributes ' ] [ ' Name ' ] ] [ ' HasPropertyTemplates ' ]
for name , data in templates . items ( ) :
if name not in pset [ ' raw ' ] :
continue
if data . TemplateType == ' P_SINGLEVALUE ' :
if data . PrimaryMeasureType :
value_type = data . PrimaryMeasureType
else :
# The IFC spec is missing some, so we provide a fallback
value_type = ' IfcLabel '
nominal_value = self . file . create_entity (
value_type ,
self . cast_to_base_type ( value_type , pset [ ' raw ' ] [ name ] ) )
properties . append (
self . file . create_entity ( ' IfcPropertySingleValue ' , * * {
' Name ' : name ,
' NominalValue ' : nominal_value
} ) )
2019-10-07 22:14:52 +11:00
invalid_pset_keys = [ k for k in pset [ ' raw ' ] . keys ( ) if k not in templates . keys ( ) ]
if invalid_pset_keys :
self . ifc_export_settings . logger . error (
' One or more properties were invalid in the pset {} / {} : {} ' . format (
pset [ ' attributes ' ] [ ' Name ' ] ,
pset [ ' attributes ' ] [ ' Description ' ] ,
invalid_pset_keys ) )
2019-09-01 22:03:02 +10:00
return properties
def cast_to_base_type ( self , type , value ) :
2019-11-07 09:11:25 +11:00
if type not in self . ifc_schema . type_map :
return value
elif self . ifc_schema . type_map [ type ] == ' float ' :
2019-09-01 22:03:02 +10:00
return float ( value )
2019-09-08 18:30:16 +10:00
elif self . ifc_schema . type_map [ type ] == ' integer ' :
2019-09-01 22:03:02 +10:00
return int ( value )
2019-09-08 18:30:16 +10:00
elif self . ifc_schema . type_map [ type ] == ' bool ' :
2019-09-01 22:03:02 +10:00
return True if value . lower ( ) in [ ' 1 ' , ' t ' , ' true ' , ' yes ' , ' y ' , ' uh-huh ' ] else False
return str ( value )
2019-08-31 23:51:53 +10:00
def create_rep_context ( self ) :
2019-09-16 16:28:26 +10:00
self . ifc_rep_context = { }
self . ifc_rep_context [ ' Model ' ] = {
' ifc ' : self . file . createIfcGeometricRepresentationContext (
None , ' Model ' , 3 , 1.0E-05 , self . origin ) }
2019-11-07 21:49:14 +11:00
if ' Plan ' in self . ifc_export_settings . contexts :
self . ifc_rep_context [ ' Plan ' ] = {
' ifc ' : self . file . createIfcGeometricRepresentationContext (
None , ' Plan ' , 2 , 1.0E-05 , self . origin ) }
for context in self . ifc_export_settings . context_tree :
for subcontext in context [ ' subcontexts ' ] :
self . ifc_rep_context [ context [ ' name ' ] ] [ subcontext [ ' name ' ] ] = { }
for target_view in subcontext [ ' target_views ' ] :
self . ifc_rep_context [ context [ ' name ' ] ] [ subcontext [ ' name ' ] ] [ target_view ] = {
' ifc ' : self . file . createIfcGeometricRepresentationSubContext (
subcontext [ ' name ' ] , context [ ' name ' ] , None , None , None , None ,
self . ifc_rep_context [ context [ ' name ' ] ] [ ' ifc ' ] , None , target_view , None ) }
2019-08-29 23:11:12 +10:00
2019-09-08 11:07:40 +10:00
def create_project ( self ) :
self . ifc_parser . project [ ' attributes ' ] . update ( {
2019-09-16 16:28:26 +10:00
' RepresentationContexts ' : [ c [ ' ifc ' ] for c in self . ifc_rep_context . values ( ) ] ,
2019-08-31 23:51:53 +10:00
' UnitsInContext ' : self . file . by_type ( " IfcUnitAssignment " ) [ 0 ]
} )
2019-09-08 11:07:40 +10:00
self . ifc_parser . project [ ' ifc ' ] = self . file . create_entity (
self . ifc_parser . project [ ' class ' ] , * * self . ifc_parser . project [ ' attributes ' ] )
def create_libraries ( self ) :
for library in self . ifc_parser . libraries :
library [ ' ifc ' ] = self . file . create_entity ( library [ ' class ' ] , * * library [ ' attributes ' ] )
self . file . createIfcRelDeclares (
ifcopenshell . guid . new ( ) , self . owner_history ,
2019-09-09 12:48:42 +10:00
None , None ,
2019-09-08 11:07:40 +10:00
self . ifc_parser . project [ ' ifc ' ] , [ l [ ' ifc ' ] for l in self . ifc_parser . libraries ] )
2019-08-29 23:11:12 +10:00
2019-09-07 22:27:52 +10:00
def create_map_conversion ( self ) :
if not self . ifc_parser . map_conversion :
return
self . create_target_crs ( )
2019-09-16 16:28:26 +10:00
# TODO should this be hardcoded?
self . ifc_parser . map_conversion [ ' attributes ' ] [ ' SourceCRS ' ] = self . ifc_rep_context [ ' Model ' ] [ ' ifc ' ]
2019-09-07 22:27:52 +10:00
self . ifc_parser . map_conversion [ ' attributes ' ] [ ' TargetCRS ' ] = self . ifc_parser . target_crs [ ' ifc ' ]
self . ifc_parser . map_conversion [ ' ifc ' ] = self . file . create_entity ( ' IfcMapConversion ' ,
* * self . ifc_parser . map_conversion [ ' attributes ' ] )
def create_target_crs ( self ) :
self . ifc_parser . target_crs [ ' attributes ' ] [ ' MapUnit ' ] = self . file . createIfcSIUnit (
None , ' LENGTHUNIT ' ,
SIUnitHelper . get_prefix ( self . ifc_parser . target_crs [ ' attributes ' ] [ ' MapUnit ' ] ) ,
SIUnitHelper . get_unit_name ( self . ifc_parser . target_crs [ ' attributes ' ] [ ' MapUnit ' ] ) )
self . ifc_parser . target_crs [ ' ifc ' ] = self . file . create_entity (
' IfcProjectedCRS ' , * * self . ifc_parser . target_crs [ ' attributes ' ] )
2019-09-01 17:23:48 +10:00
def create_type_products ( self ) :
for product in self . ifc_parser . type_products :
2019-09-02 19:43:55 +10:00
placement = self . create_ifc_axis_2_placement_3d ( product [ ' location ' ] , product [ ' up_axis ' ] , product [ ' forward_axis ' ] )
2019-09-05 21:38:52 +10:00
2019-09-16 16:28:26 +10:00
if product [ ' representations ' ] :
maps = [ ]
for representation in product [ ' representations ' ] :
maps . append ( self . file . createIfcRepresentationMap (
placement , self . ifc_parser . representations [ representation ] [ ' ifc ' ] ) )
product [ ' attributes ' ] [ ' RepresentationMaps ' ] = maps
2019-09-05 21:38:52 +10:00
2019-09-10 20:11:37 +10:00
if product [ ' psets ' ] :
product [ ' attributes ' ] . update ( { ' HasPropertySets ' :
[ self . ifc_parser . psets [ pset ] [ ' ifc ' ] for pset in
product [ ' psets ' ] ] } )
2019-09-29 22:12:51 +10:00
if product [ ' class ' ] == ' IfcDoorType ' \
and product [ ' attributes ' ] [ ' Name ' ] in self . ifc_parser . door_attributes :
2019-09-29 22:29:06 +10:00
self . add_predefined_attributes_to_type_product ( product ,
self . ifc_parser . door_attributes [ product [ ' attributes ' ] [ ' Name ' ] ] )
elif product [ ' class ' ] == ' IfcWindowType ' \
and product [ ' attributes ' ] [ ' Name ' ] in self . ifc_parser . window_attributes :
self . add_predefined_attributes_to_type_product ( product ,
self . ifc_parser . window_attributes [ product [ ' attributes ' ] [ ' Name ' ] ] )
2019-09-29 22:12:51 +10:00
2019-09-01 17:23:48 +10:00
try :
product [ ' ifc ' ] = self . file . create_entity ( product [ ' class ' ] , * * product [ ' attributes ' ] )
except RuntimeError as e :
2019-10-07 21:11:11 +11:00
self . ifc_export_settings . logger . error ( ' The type product " {} / {} " could not be created: {} ' . format ( product [ ' class ' ] , product [ ' attributes ' ] [ ' Name ' ] , e . args ) )
2019-09-01 17:23:48 +10:00
2019-09-29 22:29:06 +10:00
def add_predefined_attributes_to_type_product ( self , product , attributes ) :
self . create_predefined_attributes ( attributes )
product [ ' attributes ' ] . setdefault ( ' HasPropertySets ' , [ ] )
for attribute in attributes :
product [ ' attributes ' ] [ ' HasPropertySets ' ] . append ( attribute [ ' ifc ' ] )
def create_predefined_attributes ( self , attributes ) :
2019-09-29 22:12:51 +10:00
for attribute in attributes :
attribute [ ' ifc ' ] = self . file . create_entity ( attribute [ ' pset_name ' ] ,
* * { k : float ( v ) if v . replace ( ' . ' , ' ' , 1 ) . isdigit ( ) else v for k , v in attribute [ ' raw ' ] . items ( ) } )
2019-09-08 14:55:23 +10:00
def relate_definitions_to_contexts ( self ) :
for library in self . ifc_parser . libraries :
self . file . createIfcRelDeclares (
ifcopenshell . guid . new ( ) , self . owner_history , None , None ,
library [ ' ifc ' ] ,
[ self . ifc_parser . type_products [ t ] [ ' ifc ' ] for t in library [ ' rel_declares_type_products ' ] ] )
2019-09-03 20:52:22 +10:00
def relate_objects_to_objects ( self ) :
2019-09-05 12:04:34 +10:00
for relating_object , related_objects_reference in self . ifc_parser . rel_aggregates . items ( ) :
2019-09-03 20:52:22 +10:00
relating_object = self . ifc_parser . products [ relating_object ]
2019-09-05 12:04:34 +10:00
related_objects = [ self . ifc_parser . products [ o ] [ ' ifc ' ] for o in self . ifc_parser . aggregates [ related_objects_reference ] ]
2019-09-03 20:52:22 +10:00
self . file . createIfcRelAggregates (
ifcopenshell . guid . new ( ) , self . owner_history , relating_object [ ' attributes ' ] [ ' Name ' ] , None ,
relating_object [ ' ifc ' ] , related_objects )
2019-08-31 23:51:53 +10:00
def create_spatial_structure_elements ( self , element_tree , relating_object = None ) :
if relating_object == None :
2019-09-08 11:07:40 +10:00
relating_object = self . ifc_parser . project [ ' ifc ' ]
2019-08-31 23:51:53 +10:00
placement_rel_to = None
else :
placement_rel_to = relating_object . ObjectPlacement
related_objects = [ ]
for node in element_tree :
element = self . ifc_parser . spatial_structure_elements [ node [ ' reference ' ] ]
element [ ' attributes ' ] . update ( {
' OwnerHistory ' : self . owner_history , # TODO: unhardcode
' ObjectPlacement ' : self . file . createIfcLocalPlacement ( placement_rel_to , self . origin )
} )
element [ ' ifc ' ] = self . file . create_entity ( element [ ' class ' ] , * * element [ ' attributes ' ] )
related_objects . append ( element [ ' ifc ' ] )
self . create_spatial_structure_elements ( node [ ' children ' ] , element [ ' ifc ' ] )
if related_objects :
self . file . createIfcRelAggregates (
ifcopenshell . guid . new ( ) ,
self . owner_history , None , None , relating_object , related_objects )
2019-10-12 22:20:09 +11:00
def create_styled_items ( self ) :
2019-10-15 18:10:32 +11:00
for styled_item in self . ifc_parser . styled_items :
2019-10-12 22:20:09 +11:00
product = self . ifc_parser . products [
self . ifc_parser . get_product_index_from_raw_name (
styled_item [ ' related_product_name ' ] ) ] [ ' ifc ' ]
representation_items = [ ]
if product . Representation :
for representation in product . Representation . Representations :
for item in representation . Items :
representation_items . append ( item )
for representation_item in representation_items :
styled_item [ ' ifc ' ] = self . create_styled_item ( styled_item , representation_item )
def create_styled_item ( self , item , representation_item = None ) :
styles = [ ]
styles . append ( self . create_surface_style_rendering ( item ) )
2019-10-21 14:56:40 +11:00
if item [ ' raw ' ] . BIMMaterialProperties . is_external :
2019-10-12 22:20:09 +11:00
styles . append ( self . file . create_entity ( ' IfcExternallyDefinedSurfaceStyle ' ,
* * self . get_material_external_definition ( item [ ' raw ' ] ) ) )
2019-11-08 15:10:51 +11:00
# Name is filled out because Revit treats this incorrectly as the material name
surface_style = self . file . createIfcSurfaceStyle ( item [ ' attributes ' ] [ ' Name ' ] , ' BOTH ' , styles )
if self . ifc_export_settings . should_use_presentation_style_assignment :
surface_style = self . file . createIfcPresentationStyleAssignment ( [ surface_style ] )
2019-10-12 22:20:09 +11:00
return self . file . createIfcStyledItem ( representation_item , [ surface_style ] , item [ ' attributes ' ] [ ' Name ' ] )
2019-09-09 15:11:07 +10:00
def create_materials ( self ) :
for material in self . ifc_parser . materials . values ( ) :
2019-10-12 22:20:09 +11:00
styled_item = self . create_styled_item ( material )
2019-09-09 15:11:07 +10:00
styled_representation = self . file . createIfcStyledRepresentation (
2019-11-07 21:49:14 +11:00
self . ifc_rep_context [ ' Model ' ] [ ' Body ' ] [ ' MODEL_VIEW ' ] [ ' ifc ' ] , None , None , [ styled_item ] )
2019-09-09 15:11:07 +10:00
material [ ' ifc ' ] = self . file . createIfcMaterial ( material [ ' raw ' ] . name , None , None )
self . file . createIfcMaterialDefinitionRepresentation (
material [ ' raw ' ] . name , None , [ styled_representation ] , material [ ' ifc ' ] )
2019-09-28 10:54:10 +10:00
if material [ ' is_material_layer_set ' ] :
material [ ' layer_attributes ' ] [ ' Material ' ] = material [ ' ifc ' ]
2019-09-28 12:41:51 +10:00
material [ ' layer_ifc ' ] = self . file . create_entity ( ' IfcMaterialLayer ' ,
* * material [ ' layer_attributes ' ] )
elif material [ ' is_material_constituent_set ' ] :
material [ ' constituent_attributes ' ] [ ' Material ' ] = material [ ' ifc ' ]
material [ ' constituent_ifc ' ] = self . file . create_entity ( ' IfcMaterialConstituent ' ,
* * material [ ' constituent_attributes ' ] )
2019-09-09 15:11:07 +10:00
2019-10-12 22:20:09 +11:00
def create_surface_style_rendering ( self , styled_item ) :
surface_colour = self . create_colour_rgb ( styled_item [ ' raw ' ] . diffuse_color )
2019-09-10 14:18:50 +10:00
rendering_attributes = { ' SurfaceColour ' : surface_colour }
2019-10-12 22:20:09 +11:00
rendering_attributes . update ( self . get_rendering_attributes ( styled_item [ ' raw ' ] ) )
2019-09-10 14:18:50 +10:00
return self . file . create_entity ( ' IfcSurfaceStyleRendering ' , * * rendering_attributes )
def get_rendering_attributes ( self , material ) :
2019-09-17 11:20:22 +10:00
if not hasattr ( material . node_tree , ' nodes ' ) \
or ' Principled BSDF ' not in material . node_tree . nodes :
2019-09-10 14:18:50 +10:00
return { }
bsdf = material . node_tree . nodes [ ' Principled BSDF ' ]
return {
' Transparency ' : ( bsdf . inputs [ ' Alpha ' ] . default_value - 1 ) * - 1 ,
' DiffuseColour ' : self . create_colour_rgb ( bsdf . inputs [ ' Base Color ' ] . default_value )
}
def get_material_external_definition ( self , material ) :
return {
2019-10-21 14:56:40 +11:00
' Location ' : material . BIMMaterialProperties . location ,
' Identification ' : material . BIMMaterialProperties . identification if material . BIMMaterialProperties . identification else material . name ,
' Name ' : material . BIMMaterialProperties . name if material . BIMMaterialProperties . name else material . name
2019-09-10 14:18:50 +10:00
}
def create_colour_rgb ( self , colour ) :
return self . file . createIfcColourRgb ( None , colour [ 0 ] , colour [ 1 ] , colour [ 2 ] )
2019-09-01 11:45:32 +10:00
def create_representations ( self ) :
2019-09-08 11:24:41 +10:00
for representation in self . ifc_parser . representations . values ( ) :
2019-09-07 08:05:42 +10:00
representation [ ' ifc ' ] = self . create_representation ( representation )
2019-09-01 11:45:32 +10:00
2019-08-31 23:51:53 +10:00
def create_products ( self ) :
for product in self . ifc_parser . products :
2019-09-02 19:43:55 +10:00
self . create_product ( product )
2019-09-04 16:53:10 +10:00
def create_qtos ( self ) :
for object_name , qto in self . ifc_parser . qtos . items ( ) :
quantities = self . calculate_quantities ( qto [ ' class ' ] , qto [ ' raw ' ] )
qto [ ' attributes ' ] . update ( {
' GlobalId ' : ifcopenshell . guid . new ( ) ,
' OwnerHistory ' : self . owner_history ,
' Quantities ' : quantities
} )
qto [ ' ifc ' ] = self . file . create_entity ( ' IfcElementQuantity ' , * * qto [ ' attributes ' ] )
2019-09-02 19:43:55 +10:00
def create_product ( self , product ) :
2019-09-03 20:52:22 +10:00
if product [ ' relating_structure ' ] :
placement_rel_to = self . ifc_parser . spatial_structure_elements [ product [ ' relating_structure ' ] ] [ ' ifc ' ] . ObjectPlacement
2019-09-28 23:43:50 +10:00
elif product [ ' relating_host ' ] is not None :
placement_rel_to = self . ifc_parser . products [ product [ ' relating_host ' ] ] [ ' ifc ' ] . ObjectPlacement
2019-09-03 20:52:22 +10:00
else :
placement_rel_to = None
2019-11-17 19:08:29 +11:00
if product [ ' has_scale ' ] :
placement = self . file . createIfcLocalPlacement ( placement_rel_to , self . origin )
else :
placement = self . file . createIfcLocalPlacement ( placement_rel_to ,
self . create_ifc_axis_2_placement_3d ( product [ ' location ' ] ,
product [ ' up_axis ' ] ,
product [ ' forward_axis ' ] ) )
2019-09-03 20:52:22 +10:00
product [ ' attributes ' ] . update ( {
' OwnerHistory ' : self . owner_history , # TODO: unhardcode
' ObjectPlacement ' : placement ,
2019-09-16 16:28:26 +10:00
' Representation ' : self . get_product_shape ( product )
2019-09-03 20:52:22 +10:00
} )
2019-11-07 09:11:25 +11:00
for key , value in product [ ' attributes ' ] . items ( ) :
type = self . get_product_attribute_type ( product [ ' class ' ] , key )
if type is None :
continue
product [ ' attributes ' ] [ key ] = self . cast_to_base_type ( type , value )
2019-09-02 19:43:55 +10:00
try :
product [ ' ifc ' ] = self . file . create_entity ( product [ ' class ' ] , * * product [ ' attributes ' ] )
except RuntimeError as e :
2019-10-07 21:11:11 +11:00
self . ifc_export_settings . logger . error ( ' The product " {} / {} " could not be created: {} ' . format ( product [ ' class ' ] , product [ ' attributes ' ] [ ' Name ' ] , e . args ) )
2019-08-31 23:51:53 +10:00
2019-11-07 09:11:25 +11:00
def get_product_attribute_type ( self , product_class , attribute_name ) :
element_schema = self . ifc_schema . elements [ product_class ]
for a in element_schema [ ' attributes ' ] :
if a [ ' name ' ] == attribute_name :
return a [ ' type ' ]
if element_schema [ ' parent ' ] in self . ifc_schema . elements :
return self . get_product_attribute_type ( element_schema [ ' parent ' ] , attribute_name )
return None
2019-09-16 16:28:26 +10:00
def get_product_shape ( self , product ) :
try :
shape = self . file . createIfcProductDefinitionShape ( None , None ,
2019-11-17 19:08:29 +11:00
self . get_product_shape_representations ( product ) )
2019-09-16 16:28:26 +10:00
except :
shape = None
return shape
2019-11-17 19:08:29 +11:00
def get_product_shape_representations ( self , product ) :
results = [ ]
for representation_name in product [ ' representations ' ] :
shape_representation = self . ifc_parser . representations [ representation_name ] [ ' ifc ' ]
if product [ ' has_scale ' ] :
results . append ( self . get_product_mapped_geometry ( product , shape_representation ) )
else :
results . append ( shape_representation )
return results
def get_product_mapped_geometry ( self , product , shape_representation ) :
mapping_source = self . file . createIfcRepresentationMap ( self . origin , shape_representation )
mapping_target = self . file . createIfcCartesianTransformationOperator3DnonUniform (
2019-11-17 20:41:53 +11:00
self . create_direction ( product [ ' forward_axis ' ] ) ,
self . create_direction ( product [ ' right_axis ' ] ) ,
2019-11-17 19:08:29 +11:00
self . create_cartesian_point (
product [ ' location ' ] . x ,
product [ ' location ' ] . y ,
product [ ' location ' ] . z ) ,
product [ ' scale ' ] . x ,
2019-11-17 20:41:53 +11:00
self . create_direction ( product [ ' up_axis ' ] ) ,
2019-11-17 19:08:29 +11:00
product [ ' scale ' ] . y ,
product [ ' scale ' ] . z )
mapped_item = self . file . createIfcMappedItem ( mapping_source , mapping_target )
return self . file . createIfcShapeRepresentation (
shape_representation . ContextOfItems ,
shape_representation . RepresentationIdentifier ,
shape_representation . RepresentationType ,
[ mapped_item ] )
2019-09-04 16:53:10 +10:00
def calculate_quantities ( self , qto_name , object ) :
quantities = [ ]
for index , vg in enumerate ( object . vertex_groups ) :
if qto_name not in vg . name :
continue
if ' length ' in vg . name . lower ( ) :
quantity = float ( self . qto_calculator . get_length ( object , index ) )
quantities . append ( self . file . createIfcQuantityLength (
vg . name . split ( ' / ' ) [ 1 ] , None ,
2019-09-10 17:08:45 +10:00
self . ifc_parser . units [ ' length ' ] [ ' ifc ' ] , quantity ) )
2019-09-04 16:53:10 +10:00
elif ' area ' in vg . name . lower ( ) :
quantity = float ( self . qto_calculator . get_area ( object , index ) )
quantities . append ( self . file . createIfcQuantityArea (
vg . name . split ( ' / ' ) [ 1 ] , None ,
2019-09-10 17:08:45 +10:00
self . ifc_parser . units [ ' area ' ] [ ' ifc ' ] , quantity ) )
2019-09-04 16:53:10 +10:00
elif ' volume ' in vg . name . lower ( ) :
quantity = float ( self . qto_calculator . get_volume ( object , index ) )
quantities . append ( self . file . createIfcQuantityVolume (
vg . name . split ( ' / ' ) [ 1 ] , None ,
2019-09-10 17:08:45 +10:00
self . ifc_parser . units [ ' volume ' ] [ ' ifc ' ] , quantity ) )
2019-09-04 16:53:10 +10:00
if not quantity :
2019-10-07 21:11:11 +11:00
self . ifc_export_settings . logger . warning ( ' The calculated quantity {} for {} is zero. ' . format (
2019-09-04 16:53:10 +10:00
vg . name , object . name ) )
return quantities
2019-09-02 19:43:55 +10:00
def create_ifc_axis_2_placement_3d ( self , point , up , forward ) :
2019-09-01 17:23:48 +10:00
return self . file . createIfcAxis2Placement3D (
2019-11-07 16:40:57 +11:00
self . create_cartesian_point ( point . x , point . y , point . z ) ,
2019-09-02 19:43:55 +10:00
self . file . createIfcDirection ( ( up . x , up . y , up . z ) ) ,
self . file . createIfcDirection ( ( forward . x , forward . y , forward . z ) ) )
2019-09-01 17:23:48 +10:00
2019-09-07 08:05:42 +10:00
def create_representation ( self , representation ) :
self . ifc_vertices = [ ]
self . ifc_edges = [ ]
self . ifc_faces = [ ]
2019-09-18 11:30:07 +10:00
if representation [ ' is_generated ' ] \
and representation [ ' subcontext ' ] == ' Box ' :
return self . create_box_representation ( representation )
elif representation [ ' subcontext ' ] == ' CoG ' :
return self . create_cog_representation ( representation )
2019-09-17 12:56:43 +10:00
elif representation [ ' context ' ] == ' Plan ' \
2019-09-16 16:28:26 +10:00
or representation [ ' subcontext ' ] == ' Axis ' \
or representation [ ' is_wireframe ' ] :
return self . create_wireframe_representation ( representation )
2019-11-07 17:59:37 +11:00
elif representation [ ' subcontext ' ] == ' SurveyPoints ' :
return self . create_geometric_curve_set_representation ( representation )
2019-11-05 21:49:17 +11:00
elif representation [ ' is_curve ' ] :
return self . create_curve_representation ( representation )
2019-09-20 09:15:32 +10:00
elif representation [ ' is_swept_solid ' ] :
return self . create_swept_solid_representation ( representation )
2019-09-17 12:56:43 +10:00
else :
return self . create_solid_representation ( representation )
def create_box_representation ( self , representation ) :
object = representation [ ' raw_object ' ]
bounding_box = self . file . createIfcBoundingBox (
self . create_cartesian_point (
object . bound_box [ 0 ] [ 0 ] , object . bound_box [ 0 ] [ 1 ] , object . bound_box [ 0 ] [ 2 ] ) ,
object . dimensions [ 0 ] , object . dimensions [ 1 ] , object . dimensions [ 2 ] )
return self . file . createIfcShapeRepresentation (
2019-11-07 21:49:14 +11:00
self . ifc_rep_context [ representation [ ' context ' ] ] [ representation [ ' subcontext ' ] ] [ representation [ ' target_view ' ] ] [ ' ifc ' ] ,
2019-09-17 12:56:43 +10:00
representation [ ' subcontext ' ] , ' BoundingBox ' , [ bounding_box ] )
2019-09-16 16:28:26 +10:00
2019-09-18 11:30:07 +10:00
def create_cog_representation ( self , representation ) :
mesh = representation [ ' raw ' ]
cog = self . create_cartesian_point (
mesh . vertices [ 0 ] . co . x , mesh . vertices [ 0 ] . co . y , mesh . vertices [ 0 ] . co . z )
return self . file . createIfcShapeRepresentation (
2019-11-07 21:49:14 +11:00
self . ifc_rep_context [ representation [ ' context ' ] ] [ representation [ ' subcontext ' ] ] [ representation [ ' target_view ' ] ] [ ' ifc ' ] ,
2019-09-18 11:30:07 +10:00
representation [ ' subcontext ' ] , ' BoundingBox ' , [ cog ] )
2019-09-16 16:28:26 +10:00
def create_wireframe_representation ( self , representation ) :
mesh = representation [ ' raw ' ]
2019-09-07 08:05:42 +10:00
self . create_vertices ( mesh . vertices )
for edge in mesh . edges :
self . ifc_edges . append ( self . file . createIfcPolyline ( [
self . ifc_vertices [ v ] for v in edge . vertices ] ) )
return self . file . createIfcShapeRepresentation (
2019-11-07 21:49:14 +11:00
self . ifc_rep_context [ representation [ ' context ' ] ] [ representation [ ' subcontext ' ] ] [ representation [ ' target_view ' ] ] [ ' ifc ' ] ,
2019-09-16 16:28:26 +10:00
representation [ ' subcontext ' ] , ' Curve ' ,
2019-09-07 08:05:42 +10:00
self . ifc_edges )
2019-09-01 09:44:06 +10:00
2019-11-07 17:59:37 +11:00
def create_geometric_curve_set_representation ( self , representation ) :
mesh = representation [ ' raw ' ]
self . create_vertices ( mesh . vertices )
edges = list ( mesh . edges )
loop_vertices = [ ]
loops = [ ]
# Not a fast algorithm, but easy
while edges :
for i , edge in enumerate ( edges ) :
if edge . vertices [ 0 ] in loop_vertices \
and edge . vertices [ 1 ] in loop_vertices :
del edges [ i ]
loop_vertex_indices = self . get_loop_from_edges ( edges )
loop_vertices . extend ( loop_vertex_indices )
loops . append ( self . file . createIfcPolyline ( [
self . ifc_vertices [ i ] for i in loop_vertex_indices ] ) )
geometric_curve_set = self . file . createIfcGeometricCurveSet ( loops )
return self . file . createIfcShapeRepresentation (
2019-11-07 21:49:14 +11:00
self . ifc_rep_context [ representation [ ' context ' ] ] [ representation [ ' subcontext ' ] ] [ representation [ ' target_view ' ] ] [ ' ifc ' ] ,
2019-11-07 17:59:37 +11:00
representation [ ' subcontext ' ] , ' GeometricCurveSet ' , [ geometric_curve_set ] )
2019-11-06 17:37:51 +11:00
# https://medium.com/@behreajj/scripting-curves-in-blender-with-python-c487097efd13
# https://blender.stackexchange.com/questions/30597/python-up-vector-math-for-curve
def bezier_tangent ( self , pt0 = Vector ( ) , pt1 = Vector ( ) , pt2 = Vector ( ) , pt3 = Vector ( ) , step = 0.5 ) :
# Return early if step is out of bounds [0, 1].
if step < = 0.0 :
return pt1 - pt0
if step > = 1.0 :
return pt3 - pt2
# Find coefficients.
u = 1.0 - step
ut6 = u * step * 6.0
tsq3 = step * step * 3.0
usq3 = u * u * 3.0
# Find tangent and return.
return ( pt1 - pt0 ) * usq3 + ( pt2 - pt1 ) * ut6 + ( pt3 - pt2 ) * tsq3
2019-11-05 21:49:17 +11:00
def create_curve_representation ( self , representation ) :
# TODO: support unclosed surfaces
swept_area = self . file . createIfcArbitraryClosedProfileDef ( ' AREA ' , None ,
self . create_curve ( representation [ ' raw ' ] . bevel_object . data ) )
swept_area_solids = [ ]
for spline in representation [ ' raw ' ] . splines :
direction = spline . bezier_points [ 1 ] . co - spline . bezier_points [ 0 ] . co
unit_direction = direction . normalized ( )
2019-11-06 17:37:51 +11:00
# This can be used in the future when dealing with non vector curves
#curr_point = spline.bezier_points[0]
#next_point = spline.bezier_points[1]
#j_percent = 0
#direction = self.bezier_tangent(
# pt0=curr_point.co,
# pt1=curr_point.handle_right,
# pt2=next_point.handle_left,
# pt3=next_point.co,
# step=j_percent)
tilt_matrix = Matrix . Rotation ( - spline . bezier_points [ 0 ] . tilt , 4 , ' Z ' )
x_axis = unit_direction . to_track_quat ( ' -Y ' , ' Z ' ) @ Vector ( ( 1 , 0 , 0 ) ) @ tilt_matrix
position = self . create_ifc_axis_2_placement_3d (
spline . bezier_points [ 0 ] . co , unit_direction , x_axis )
2019-11-05 21:49:17 +11:00
swept_area_solids . append ( self . file . createIfcExtrudedAreaSolid (
2019-11-06 17:37:51 +11:00
swept_area , position ,
self . file . createIfcDirection ( ( 0. , 0. , 1. ) ) ,
2019-11-07 16:40:57 +11:00
self . convert_si_to_unit ( direction . length ) ) )
2019-11-05 21:49:17 +11:00
# TODO: support other types of swept areas
#swept_area_solid = self.file.createIfcFixedReferenceSweptAreaSolid(
# swept_area, self.origin, self.create_curve(representation['raw']),
# 0., 1., self.file.createIfcDirection((0.0, -1.0, 0.0)))
return self . file . createIfcShapeRepresentation (
2019-11-07 21:49:14 +11:00
self . ifc_rep_context [ representation [ ' context ' ] ] [ representation [ ' subcontext ' ] ] [ representation [ ' target_view ' ] ] [ ' ifc ' ] ,
2019-11-05 21:49:17 +11:00
representation [ ' subcontext ' ] , ' AdvancedSweptSolid ' ,
swept_area_solids )
def create_curve ( self , curve ) :
# TODO: support interpolated curves, not just polylines
points = [ ]
for point in curve . splines [ 0 ] . bezier_points :
points . append ( self . create_cartesian_point (
point . co . x , point . co . y , point . co . z ) )
if curve . splines [ 0 ] . use_cyclic_u :
points . append ( points [ 0 ] )
return self . file . createIfcPolyline ( points )
2019-09-20 09:15:32 +10:00
def create_swept_solid_representation ( self , representation ) :
object = representation [ ' raw_object ' ]
mesh = representation [ ' raw ' ]
2019-11-13 18:48:12 +11:00
items = [ ]
for swept_solid in mesh . BIMMeshProperties . swept_solids :
extrusion_edge = self . get_edges_in_v_indices ( object , json . loads ( swept_solid . extrusion ) ) [ 0 ]
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 ) )
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 )
if inner_curves :
curve = self . file . createIfcArbitraryProfileDefWithVoids ( ' AREA ' , None ,
outer_curve , inner_curves )
else :
curve = self . file . createIfcArbitraryClosedProfileDef ( ' AREA ' , None , outer_curve )
2019-11-08 12:39:34 +11:00
2019-11-13 18:48:12 +11:00
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 ' ] )
2019-11-08 12:39:34 +11:00
2019-11-13 18:48:12 +11:00
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 ) ) )
2019-09-20 09:15:32 +10:00
return self . file . createIfcShapeRepresentation (
2019-11-07 21:49:14 +11:00
self . ifc_rep_context [ representation [ ' context ' ] ] [ representation [ ' subcontext ' ] ] [ representation [ ' target_view ' ] ] [ ' ifc ' ] ,
2019-11-13 18:48:12 +11:00
representation [ ' subcontext ' ] , ' SweptSolid ' , items )
2019-09-20 09:15:32 +10:00
def get_start_and_end_of_extrusion ( self , profile_points , extrusion_edge ) :
if extrusion_edge . vertices [ 0 ] in profile_points :
return ( extrusion_edge . vertices [ 0 ] , extrusion_edge . vertices [ 1 ] )
return ( extrusion_edge . vertices [ 1 ] , extrusion_edge . vertices [ 0 ] )
2019-11-12 17:57:59 +11:00
def get_curve_profile_coordinate_system ( self , object , loop ) :
profile_face = bpy . data . meshes . new ( ' profile_face ' )
profile_verts = [ (
object . data . vertices [ p ] . co . x ,
object . data . vertices [ p ] . co . y ,
object . data . vertices [ p ] . co . z
) for p in loop ]
profile_faces = [ tuple ( range ( 0 , len ( profile_verts ) ) ) ]
profile_face . from_pydata ( profile_verts , [ ] , profile_faces )
center = profile_face . polygons [ 0 ] . center
x_axis = ( object . data . vertices [ loop [ 0 ] ] . co - center ) . normalized ( )
z_axis = profile_face . polygons [ 0 ] . normal . normalized ( )
y_axis = z_axis . cross ( x_axis ) . normalized ( )
matrix = Matrix ( ( x_axis , y_axis , z_axis ) )
matrix . normalize ( )
return {
' center ' : center ,
' x_axis ' : x_axis ,
' y_axis ' : y_axis ,
' z_axis ' : z_axis ,
2019-11-14 07:51:47 +11:00
' matrix ' : matrix . to_4x4 ( ) @ Matrix . Translation ( - center )
2019-11-12 17:57:59 +11:00
}
def create_polyline_from_loop ( self , object , loop , curve_ucs ) :
points = [ ]
for point in loop :
transformed_point = curve_ucs [ ' matrix ' ] @ object . data . vertices [ point ] . co
points . append ( self . create_cartesian_point (
transformed_point . x , transformed_point . y ) )
points . append ( points [ 0 ] )
return self . file . createIfcPolyline ( points )
def get_extrusion_direction ( self , object , outer_curve_loop , extrusion_edge , curve_ucs ) :
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 ) )
2019-11-13 18:48:12 +11:00
def get_loop_from_v_indices ( self , object , indices ) :
edges = self . get_edges_in_v_indices ( object , indices )
2019-11-12 17:57:59 +11:00
loop = self . get_loop_from_edges ( edges )
loop . pop ( - 1 )
return loop
2019-09-20 09:15:32 +10:00
2019-11-13 18:48:12 +11:00
def get_edges_in_v_indices ( self , object , indices ) :
2019-09-20 09:15:32 +10:00
return [ e for e in object . data . edges if (
2019-11-13 18:48:12 +11:00
e . vertices [ 0 ] in indices and e . vertices [ 1 ] in indices ) ]
2019-09-20 09:15:32 +10:00
def get_loop_from_edges ( self , edges ) :
while edges :
currentEdge = edges . pop ( )
startVert = currentEdge . vertices [ 0 ]
endVert = currentEdge . vertices [ 1 ]
polyLine = [ startVert , endVert ]
ok = 1
while ok :
ok = 0
i = len ( edges )
while i :
i - = 1
ed = edges [ i ]
if ed . vertices [ 0 ] == endVert :
polyLine . append ( ed . vertices [ 1 ] )
endVert = polyLine [ - 1 ]
ok = 1
del edges [ i ]
elif ed . vertices [ 1 ] == endVert :
polyLine . append ( ed . vertices [ 0 ] )
endVert = polyLine [ - 1 ]
ok = 1
del edges [ i ]
elif ed . vertices [ 0 ] == startVert :
polyLine . insert ( 0 , ed . vertices [ 1 ] )
startVert = polyLine [ 0 ]
ok = 1
del edges [ i ]
elif ed . vertices [ 1 ] == startVert :
polyLine . insert ( 0 , ed . vertices [ 0 ] )
startVert = polyLine [ 0 ]
ok = 1
del edges [ i ]
return polyLine
2019-09-16 16:28:26 +10:00
def create_solid_representation ( self , representation ) :
mesh = representation [ ' raw ' ]
2019-09-07 08:05:42 +10:00
self . create_vertices ( mesh . vertices )
2019-09-01 11:45:32 +10:00
for polygon in mesh . polygons :
2019-09-07 08:05:42 +10:00
self . ifc_faces . append ( self . file . createIfcFace ( [
2019-09-01 09:44:06 +10:00
self . file . createIfcFaceOuterBound (
2019-09-07 08:05:42 +10:00
self . file . createIfcPolyLoop ( [ self . ifc_vertices [ vertice ] for vertice in polygon . vertices ] ) ,
2019-09-01 09:44:06 +10:00
True ) ] ) )
2019-09-01 17:23:48 +10:00
return self . file . createIfcShapeRepresentation (
2019-11-07 21:49:14 +11:00
self . ifc_rep_context [ representation [ ' context ' ] ] [ representation [ ' subcontext ' ] ] [ representation [ ' target_view ' ] ] [ ' ifc ' ] ,
2019-09-16 16:28:26 +10:00
representation [ ' subcontext ' ] , ' Brep ' ,
2019-09-07 08:05:42 +10:00
[ self . file . createIfcFacetedBrep ( self . file . createIfcClosedShell ( self . ifc_faces ) ) ] )
def create_vertices ( self , vertices ) :
for vertice in vertices :
2019-09-17 12:56:43 +10:00
self . ifc_vertices . append ( self . create_cartesian_point (
vertice . co . x , vertice . co . y , vertice . co . z ) )
2019-09-20 09:15:32 +10:00
def create_cartesian_point ( self , x , y , z = None ) :
2019-11-07 16:40:57 +11:00
x = self . convert_si_to_unit ( x )
y = self . convert_si_to_unit ( y )
2019-09-20 09:15:32 +10:00
if z is None :
return self . file . createIfcCartesianPoint ( ( x , y ) )
2019-11-07 16:40:57 +11:00
z = self . convert_si_to_unit ( z )
2019-09-17 12:56:43 +10:00
return self . file . createIfcCartesianPoint ( ( x , y , z ) )
2019-09-01 09:44:06 +10:00
2019-11-17 20:41:53 +11:00
def create_direction ( self , vector ) :
return self . file . createIfcDirection ( ( vector . x , vector . y , vector . z ) )
2019-08-31 23:51:53 +10:00
def relate_elements_to_spatial_structures ( self ) :
for relating_structure , related_elements in self . ifc_parser . rel_contained_in_spatial_structure . items ( ) :
self . file . createIfcRelContainedInSpatialStructure (
ifcopenshell . guid . new ( ) , self . owner_history , None , None ,
[ self . ifc_parser . products [ e ] [ ' ifc ' ] for e in related_elements ] ,
self . ifc_parser . spatial_structure_elements [ relating_structure ] [ ' ifc ' ] )
2019-09-28 14:08:09 +10:00
def relate_nested_elements_to_hosted_elements ( self ) :
for relating_object , related_objects in self . ifc_parser . rel_nests . items ( ) :
self . file . createIfcRelNests (
ifcopenshell . guid . new ( ) , self . owner_history , None , None ,
self . ifc_parser . products [ relating_object ] [ ' ifc ' ] ,
[ o [ ' ifc ' ] for o in related_objects ] )
2019-09-01 18:40:20 +10:00
def relate_objects_to_types ( self ) :
for relating_type , related_objects in self . ifc_parser . rel_defines_by_type . items ( ) :
self . file . createIfcRelDefinesByType (
ifcopenshell . guid . new ( ) , self . owner_history , None , None ,
[ self . ifc_parser . products [ o ] [ ' ifc ' ] for o in related_objects ] ,
self . ifc_parser . type_products [ relating_type ] [ ' ifc ' ] )
2019-09-04 16:53:10 +10:00
def relate_objects_to_qtos ( self ) :
for relating_property_key , related_objects in self . ifc_parser . rel_defines_by_qto . items ( ) :
self . file . createIfcRelDefinesByProperties (
ifcopenshell . guid . new ( ) , self . owner_history , None , None ,
[ o [ ' ifc ' ] for o in related_objects ] ,
2019-09-09 15:11:32 +10:00
self . ifc_parser . qtos [ relating_property_key ] [ ' ifc ' ] )
2019-09-04 16:53:10 +10:00
2019-09-08 19:02:00 +10:00
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 ] ,
2019-09-09 15:11:32 +10:00
self . ifc_parser . psets [ relating_property_key ] [ ' ifc ' ] )
2019-09-08 19:02:00 +10:00
2019-09-09 15:11:07 +10:00
def relate_objects_to_materials ( self ) :
2019-10-07 22:23:31 +11:00
if not self . ifc_export_settings . has_representations :
return
2019-09-09 15:11:07 +10:00
for relating_material_key , related_objects in self . ifc_parser . rel_associates_material . items ( ) :
2019-09-11 12:44:36 +10:00
self . file . createIfcRelAssociatesMaterial (
2019-09-09 15:11:07 +10:00
ifcopenshell . guid . new ( ) , self . owner_history , None , None ,
[ o [ ' ifc ' ] for o in related_objects ] ,
self . ifc_parser . materials [ relating_material_key ] [ ' ifc ' ] )
2019-09-28 10:54:10 +10:00
def relate_objects_to_material_layer_sets ( self ) :
2019-10-07 22:23:31 +11:00
if not self . ifc_export_settings . has_representations :
return
2019-09-28 10:54:10 +10:00
for product_index , related_materials in self . ifc_parser . rel_associates_material_layer_set . items ( ) :
material_layer_set = self . file . create_entity ( ' IfcMaterialLayerSet ' , * * {
' MaterialLayers ' : [ self . ifc_parser . materials [ m ] [ ' layer_ifc ' ] for m in related_materials ]
} )
self . file . createIfcRelAssociatesMaterial (
ifcopenshell . guid . new ( ) , self . owner_history , None , None ,
[ self . ifc_parser . products [ product_index ] [ ' ifc ' ] ] ,
material_layer_set )
2019-09-28 12:41:51 +10:00
def relate_objects_to_material_constituent_sets ( self ) :
2019-10-07 22:23:31 +11:00
if not self . ifc_export_settings . has_representations :
return
2019-09-28 12:41:51 +10:00
for product_index , related_materials in self . ifc_parser . rel_associates_material_constituent_set . items ( ) :
material_constituent_set = self . file . create_entity ( ' IfcMaterialConstituentSet ' , * * {
' MaterialConstituents ' : [ self . ifc_parser . materials [ m ] [ ' constituent_ifc ' ] for m in related_materials ]
} )
self . file . createIfcRelAssociatesMaterial (
ifcopenshell . guid . new ( ) , self . owner_history , None , None ,
[ self . ifc_parser . products [ product_index ] [ ' ifc ' ] ] ,
material_constituent_set )
2019-10-03 17:56:45 +10:00
def relate_spaces_to_boundary_elements ( self ) :
for relating_space_index , relationships , in self . ifc_parser . rel_space_boundaries . items ( ) :
for relationship in relationships :
relationship [ ' attributes ' ] [ ' GlobalId ' ] = ifcopenshell . guid . new ( )
relationship [ ' attributes ' ] [ ' RelatedBuildingElement ' ] = self . ifc_parser . products [
self . ifc_parser . get_product_index_from_raw_name (
relationship [ ' related_building_element_raw_name ' ] ) ] [ ' ifc ' ]
relationship [ ' attributes ' ] [ ' RelatingSpace ' ] = self . ifc_parser . products [ relating_space_index ] [ ' ifc ' ]
relationship [ ' attributes ' ] [ ' ConnectionGeometry ' ] = self . create_connection_geometry (
self . ifc_parser . products [ relating_space_index ] ,
relationship [ ' connection_geometry_face_index ' ] )
self . file . create_entity ( relationship [ ' class ' ] , * * relationship [ ' attributes ' ] )
def create_connection_geometry ( self , product , face_index ) :
mesh = product [ ' raw ' ] . data
polygon = mesh . polygons [ int ( face_index ) ]
vertex_on_polygon = mesh . vertices [ polygon . vertices [ 0 ] ] . co
center = polygon . center
normal = polygon . normal
forward = center - vertex_on_polygon
return self . file . createIfcFaceSurface ( [ self . file . createIfcFaceOuterBound (
self . file . createIfcPolyLoop ( [
self . create_cartesian_point (
mesh . vertices [ vertice ] . co . x ,
mesh . vertices [ vertice ] . co . y ,
mesh . vertices [ vertice ] . co . z )
for vertice in polygon . vertices ] ) ,
True ) ] ,
self . file . createIfcPlane ( self . file . createIfcAxis2Placement3D (
2019-11-07 16:40:57 +11:00
self . create_cartesian_point ( center . x , center . y , center . z ) ,
2019-10-03 17:56:45 +10:00
self . file . createIfcDirection ( ( normal . x , normal . y , normal . z ) ) ,
self . file . createIfcDirection ( ( forward . x , forward . y , forward . z ) ) ) ) ,
True )
2019-09-11 12:44:36 +10:00
def relate_to_documents ( self , relationships ) :
for relating_document_key , related_objects in relationships . items ( ) :
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 ' ] )
2019-09-11 14:47:53 +10:00
def relate_to_classifications ( self , relationships ) :
for relating_key , related_objects in relationships . items ( ) :
self . file . createIfcRelAssociatesClassification (
ifcopenshell . guid . new ( ) , self . owner_history , None , None ,
[ o [ ' ifc ' ] for o in related_objects ] ,
self . ifc_parser . classification_references [ relating_key ] [ ' ifc ' ] )
2019-09-11 16:50:27 +10:00
def relate_to_objectives ( self , relationships ) :
for relating_key , related_objects in relationships . items ( ) :
self . file . createIfcRelAssociatesConstraint (
ifcopenshell . guid . new ( ) , self . owner_history , None , None ,
[ o [ ' ifc ' ] for o in related_objects ] , None ,
self . ifc_parser . objectives [ relating_key ] [ ' ifc ' ] )
2019-11-07 16:40:57 +11:00
def convert_si_to_unit ( self , co ) :
return co / self . ifc_parser . unit_scale
2019-09-05 17:18:13 +10:00
class IfcExportSettings :
def __init__ ( self ) :
2019-10-07 21:11:11 +11:00
self . logger = None
2019-10-05 21:15:53 +10:00
self . schema_dir = None
self . data_dir = None
2019-09-26 21:55:30 +10:00
self . output_file = None
2019-09-05 17:18:13 +10:00
self . has_representations = True
self . has_quantities = True
2019-11-07 21:49:14 +11:00
self . contexts = [ ' Model ' , ' Plan ' ]
2019-11-07 17:59:37 +11:00
self . subcontexts = [ ' Axis ' , ' FootPrint ' , ' Reference ' , ' Body ' , ' Clearance ' , ' CoG ' , ' SurveyPoints ' ]
2019-09-17 12:56:43 +10:00
self . generated_subcontexts = [ ' Box ' ]
2019-11-07 21:49:14 +11:00
self . target_views = [ ' GRAPH_VIEW ' , ' SKETCH_VIEW ' , ' MODEL_VIEW ' , ' PLAN_VIEW ' , ' REFLECTED_PLAN_VIEW ' , ' SECTION_VIEW ' , ' ELEVATION_VIEW ' , ' USERDEFINED ' , ' NOTDEFINED ' ]
2019-11-08 15:10:51 +11:00
self . should_export_all_materials_as_styled_items = False
self . should_use_presentation_style_assignment = False
2019-11-07 21:49:14 +11:00
# TODO make this configurable via UI
self . context_tree = self . build_context_tree ( )
def build_context_tree ( self ) :
tree = [ ]
for context in self . contexts :
subcontexts = [ ]
for subcontext in self . subcontexts + self . generated_subcontexts :
target_views = [ ]
for target_view in self . target_views :
if context == ' Model ' \
and target_view != ' MODEL_VIEW ' :
continue
elif context == ' Plan ' \
and target_view == ' MODEL_VIEW ' :
continue
target_views . append ( target_view )
subcontexts . append ( {
' name ' : subcontext ,
' target_views ' : target_views
} )
tree . append ( {
' name ' : context ,
' subcontexts ' : subcontexts
} )
return tree