From 0477910fc066d3d3cc3067d3566b3ecc62d4ef30 Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Thu, 7 Nov 2019 16:40:57 +1100 Subject: [PATCH] Add support for export of imperial units --- .../io_export_ifc/export_ifc.py | 81 ++++++++++++++----- 1 file changed, 62 insertions(+), 19 deletions(-) diff --git a/src/ifcblenderexport/io_export_ifc/export_ifc.py b/src/ifcblenderexport/io_export_ifc/export_ifc.py index c2e932b80f..aa59bb627a 100644 --- a/src/ifcblenderexport/io_export_ifc/export_ifc.py +++ b/src/ifcblenderexport/io_export_ifc/export_ifc.py @@ -134,6 +134,7 @@ class IfcParser(): def parse(self): self.units = self.get_units() + self.unit_scale = self.get_unit_scale() self.convert_selected_objects_into_products(bpy.context.selected_objects) self.psets = self.get_psets() self.documents = self.get_documents() @@ -177,6 +178,22 @@ class IfcParser(): 'raw': bpy.context.scene.unit_settings.length_unit }} + 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 + def get_object_attributes(self, object): attributes = { 'Name': self.get_ifc_name(object.name) } if object.BIMObjectProperties.attributes.find('GlobalId') == -1: @@ -811,21 +828,44 @@ class IfcExporter(): def create_units(self): for type, data in self.ifc_parser.units.items(): if data['is_metric']: - type_prefix = '' - if type == 'area': - type_prefix = 'SQUARE_' - elif type == 'volume': - type_prefix = 'CUBIC_' - data['ifc'] = self.file.createIfcSIUnit(None, - '{}UNIT'.format(type.upper()), - SIUnitHelper.get_prefix(data['raw']), - type_prefix + SIUnitHelper.get_unit_name(data['raw'])) + data['ifc'] = self.create_metric_unit(type, data) else: - self.create_imperial_unit(type, data) + data['ifc'] = self.create_imperial_unit(type, data) self.file.createIfcUnitAssignment([u['ifc'] for u in self.ifc_parser.units.values()]) + 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'])) + def create_imperial_unit(self, type, data): - pass # TODO + 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) def create_documents(self): for document in self.ifc_parser.documents.values(): @@ -1210,7 +1250,7 @@ class IfcExporter(): def create_ifc_axis_2_placement_3d(self, point, up, forward): return self.file.createIfcAxis2Placement3D( - self.file.createIfcCartesianPoint((point.x, point.y, point.z)), + self.create_cartesian_point(point.x, point.y, point.z), self.file.createIfcDirection((up.x, up.y, up.z)), self.file.createIfcDirection((forward.x, forward.y, forward.z))) @@ -1301,18 +1341,14 @@ class IfcExporter(): # pt3=next_point.co, # step=j_percent) tilt_matrix = Matrix.Rotation(-spline.bezier_points[0].tilt, 4, 'Z') - print(spline.bezier_points[0].tilt) - print(tilt_matrix) x_axis = unit_direction.to_track_quat('-Y', 'Z') @ Vector((1, 0, 0)) @ tilt_matrix - print((tilt_matrix @ Vector((1, 0, 0)))) - print(x_axis) position = self.create_ifc_axis_2_placement_3d( spline.bezier_points[0].co, unit_direction, x_axis) swept_area_solids.append(self.file.createIfcExtrudedAreaSolid( swept_area, position, self.file.createIfcDirection((0., 0., 1.)), - direction.length)) + self.convert_si_to_unit(direction.length))) # TODO: support other types of swept areas #swept_area_solid = self.file.createIfcFixedReferenceSweptAreaSolid( # swept_area, self.origin, self.create_curve(representation['raw']), @@ -1358,7 +1394,8 @@ class IfcExporter(): direction = self.get_extrusion_direction(mesh, start, end) unit_direction = direction.normalized() extruded_area_solid = self.file.createIfcExtrudedAreaSolid(curve, self.origin, - self.file.createIfcDirection((unit_direction.x, unit_direction.y, unit_direction.z)), direction.length) + self.file.createIfcDirection((unit_direction.x, unit_direction.y, unit_direction.z)), + self.convert_si_to_unit(direction.length)) return self.file.createIfcShapeRepresentation( self.ifc_rep_context[representation['context']][representation['subcontext']]['ifc'], representation['subcontext'], 'SweptSolid', @@ -1432,8 +1469,11 @@ class IfcExporter(): vertice.co.x, vertice.co.y, vertice.co.z)) def create_cartesian_point(self, x, y, z=None): + x = self.convert_si_to_unit(x) + y = self.convert_si_to_unit(y) if z is None: return self.file.createIfcCartesianPoint((x, y)) + z = self.convert_si_to_unit(z) return self.file.createIfcCartesianPoint((x, y, z)) def relate_elements_to_spatial_structures(self): @@ -1533,7 +1573,7 @@ class IfcExporter(): for vertice in polygon.vertices]), True)], self.file.createIfcPlane(self.file.createIfcAxis2Placement3D( - self.file.createIfcCartesianPoint((center.x, center.y, center.z)), + self.create_cartesian_point(center.x, center.y, center.z), self.file.createIfcDirection((normal.x, normal.y, normal.z)), self.file.createIfcDirection((forward.x, forward.y, forward.z)))), True) @@ -1559,6 +1599,9 @@ class IfcExporter(): [o['ifc'] for o in related_objects], None, self.ifc_parser.objectives[relating_key]['ifc']) + def convert_si_to_unit(self, co): + return co / self.ifc_parser.unit_scale + class IfcExportSettings: def __init__(self): self.logger = None