diff --git a/src/ifcblenderexport/gbxml.py b/src/ifcblenderexport/gbxml.py new file mode 100644 index 0000000000..3fcf3ccc8c --- /dev/null +++ b/src/ifcblenderexport/gbxml.py @@ -0,0 +1,130 @@ +import bpy +import uuid +import math +import sys +#sys.path.append('C:\Program Files\Python37\Lib\site-packages') +import bspy +from bspy import Gbxml + +class GbxmlExporter(): + def __init__(self): + self.gbxml = Gbxml() + self.campus = None + + def export(self): + print('# Start export') + self.campus = self.gbxml.add_element(self.gbxml.root(), 'Campus') + self.campus.set('id', 'campus-1') + name = self.gbxml.add_element(self.campus, 'Name', 'My project') + + location = self.gbxml.add_element(self.campus, 'Location') + self.gbxml.add_element(location, 'ZipcodeOrPostalCode', 'G20 0SP') + self.gbxml.add_element(location, 'Name', 'London/Heathrow') + self.gbxml.add_element(location, 'Latitude', '51.480000') + self.gbxml.add_element(location, 'Longitude', '-0.450000') + self.gbxml.add_element(location, 'Elevation', '24.000000') + + building = self.gbxml.add_element(self.campus, 'Building') + building.set('id', str(uuid.uuid4())) + building.set('buildingType', 'Office') + + for object in bpy.context.selected_objects: + self.create_space(object, building) + + # hardcoded test + construction = self.gbxml.add_element(self.gbxml.root(), 'Construction') + construction.set('id', 'defaultconstruction') + self.gbxml.add_element(construction, 'Name', 'test construction name') + u_value = self.gbxml.add_element(construction, 'U-value', '0.42') + u_value.set('unit', 'WPerSquareMeterK') + layer = self.gbxml.add_element(construction, 'LayerId') + layer.set('layerIdRef', 'defaultlayer') + + layer = self.gbxml.add_element(self.gbxml.root(), 'Layer') + layer.set('id', 'defaultlayer') + material = self.gbxml.add_element(layer, 'MaterialId') + material.set('materialIdRef', 'defaultmaterial') + + material = self.gbxml.add_element(self.gbxml.root(), 'Material') + material.set('id', 'defaultmaterial') + thickness = self.gbxml.add_element(material, 'Thickness', '0.2') + thickness.set('unit', 'Meters') + self.gbxml.add_element(material, 'Name', 'test material name') + r_value = self.gbxml.add_element(material, 'R-value', '0.13') + r_value.set('unit', 'SquareMeterKPerW') + + self.gbxml.write('C:/cygwin64/home/moud308/Projects/New Folder/out.xml') + print('# Validation results: {}'.format(self.gbxml.validate())) + print('# Finish export') + + def create_space(self, object, building): + space = self.gbxml.add_element(building, 'Space') + space.set('id', object.name) + calculated_area = 0 + + shell_geometry = self.gbxml.add_element(space, 'ShellGeometry') + shell_geometry.set('id', 'shellid') + closed_shell = self.gbxml.add_element(shell_geometry, 'ClosedShell') + for polygon in object.data.polygons: + calculated_area += polygon.area + self.create_poly_loop(object, polygon, closed_shell) + self.create_space_boundary(object, polygon, space) + self.create_surface(object, polygon) + self.gbxml.add_element(space, 'Area', str(calculated_area)) + self.gbxml.add_element(space, 'Volume', str(self.get_volume(object))) + + def create_space_boundary(self, object, polygon, parent): + space_boundary = self.gbxml.add_element(parent, 'SpaceBoundary') + space_boundary.set('isSecondLevelBoundary', 'true') + space_boundary.set('surfaceIdRef', 'surface-{}-{}'.format(object.name, polygon.index)) + planar_geometry = self.gbxml.add_element(space_boundary, 'PlanarGeometry') + self.create_poly_loop(object, polygon, planar_geometry) + + def create_surface(self, object, polygon): + surface = self.gbxml.add_element(self.campus, 'Surface') + surface.set('id', 'surface-{}-{}'.format(object.name, polygon.index)) + surface.set('surfaceType', 'ExteriorWall') + surface.set('constructionIdRef', 'defaultconstruction') + adjacent_space_id = self.gbxml.add_element(surface, 'AdjacentSpaceId') + adjacent_space_id.set('spaceIdRef', object.name) + rectangular_geometry = self.gbxml.add_element(surface, 'RectangularGeometry') + self.gbxml.add_element( + rectangular_geometry, 'Azimuth', + str(math.degrees(math.atan2(polygon.normal[0], polygon.normal[1])))) + self.gbxml.add_element( + rectangular_geometry, 'Tilt', + str(math.degrees(math.atan2(polygon.normal[2], polygon.normal[1])) - 90)) + planar_geometry = self.gbxml.add_element(surface, 'PlanarGeometry') + self.create_poly_loop(object, polygon, planar_geometry) + + def create_poly_loop(self, object, polygon, parent): + poly_loop = self.gbxml.add_element(parent, 'PolyLoop') + for vertice in polygon.vertices: + cartesian_point = self.gbxml.add_element(poly_loop, 'CartesianPoint') + for coord in [0, 1, 2]: + coordinate = self.gbxml.add_element(cartesian_point, 'Coordinate') + coordinate.text = str(object.data.vertices[vertice].co[coord]) + + def get_volume(self, o): + 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]]) + + 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 + + volume += v1.dot(v2.cross(v3)) / 6.0 + return volume + +gbxml_exporter = GbxmlExporter() +gbxml_exporter.export() diff --git a/src/ifcblenderexport/import.py b/src/ifcblenderexport/import.py index 0e9f7cef27..e9e4282491 100644 --- a/src/ifcblenderexport/import.py +++ b/src/ifcblenderexport/import.py @@ -15,7 +15,7 @@ class ImportIFC(): def execute(self): self.load_file() n = 0 - elements = self.file.by_type('IfcElement') + elements = self.file.by_type('IfcElement') + self.file.by_type('IfcSpace') for element in elements: self.create_object(element) n += 1