diff --git a/src/ifcblenderexport/blenderbim/scripts/addons/bim/import_ifc.py b/src/ifcblenderexport/blenderbim/scripts/addons/bim/import_ifc.py index 5471fb9a83..2864c8fb7a 100644 --- a/src/ifcblenderexport/blenderbim/scripts/addons/bim/import_ifc.py +++ b/src/ifcblenderexport/blenderbim/scripts/addons/bim/import_ifc.py @@ -5,6 +5,7 @@ import os import json import time import mathutils +import math import multiprocessing from .helper import SIUnitHelper from . import schema @@ -193,6 +194,7 @@ class IfcImporter(): self.time = 0 self.unit_scale = 1 self.added_data = {} + self.native_data = {} self.material_creator = MaterialCreator(ifc_import_settings) @@ -210,6 +212,7 @@ class IfcImporter(): if self.ifc_import_settings.should_import_opening_elements: self.create_openings_collection() self.purge_diff() + self.parse_native_products() self.filter_ifc() self.patch_ifc() self.create_type_products() @@ -258,6 +261,52 @@ class IfcImporter(): or abs(point.Coordinates[1]) > 1000000 \ or abs(point.Coordinates[2]) > 1000000 + def parse_native_products(self): + # TODO: simple code for now as we only treat rebar specially + for element in self.file.by_type('IfcReinforcingBar'): + for representation in element.Representation.Representations: + self.replace_with_directrix(representation, element) + for item in representation.Items: + if item.is_a('IfcMappedItem'): + self.replace_with_directrix(item.MappingSource.MappedRepresentation, element) + for global_id, data in self.native_data.items(): + bevel_object = bpy.data.objects.new('rebar-profile', self.create_bezier_circle(data['radius'])) + bpy.context.scene.collection.objects.link(bevel_object) + data['bevel_object'] = bevel_object + + def create_bezier_circle(self, radius): + curve = bpy.data.curves.new('circle-profile', type='CURVE') + spline = curve.splines.new('BEZIER') + spline.use_cyclic_u = True + spline.bezier_points.add(3) + approx_distance = (4/3)*math.tan(math.pi/(2*4)) + for i in range(0, 4): + spline.bezier_points[i].handle_left_type = 'AUTO' + spline.bezier_points[i].handle_right_type = 'AUTO' + spline.bezier_points[0].co = mathutils.Vector((-radius, 0, 0)) + spline.bezier_points[0].handle_left = mathutils.Vector((-radius, -approx_distance, 0)) + spline.bezier_points[0].handle_right = mathutils.Vector((-radius, approx_distance, 0)) + spline.bezier_points[1].co = mathutils.Vector((0, radius, 0)) + spline.bezier_points[1].handle_left = mathutils.Vector((-approx_distance, radius, 0)) + spline.bezier_points[1].handle_right = mathutils.Vector((approx_distance, radius, 0)) + spline.bezier_points[2].co = mathutils.Vector((radius, 0, 0)) + spline.bezier_points[2].handle_left = mathutils.Vector((radius, approx_distance, 0)) + spline.bezier_points[2].handle_right = mathutils.Vector((radius, -approx_distance, 0)) + spline.bezier_points[3].co = mathutils.Vector((0, -radius, 0)) + spline.bezier_points[3].handle_left = mathutils.Vector((approx_distance, -radius, 0)) + spline.bezier_points[3].handle_right = mathutils.Vector((-approx_distance, -radius, 0)) + return curve + + def replace_with_directrix(self, representation, element): + new_items = [] + for item in representation.Items: + if item.is_a('IfcSweptDiskSolid'): + new_items.append(item.Directrix) + self.native_data[element.GlobalId] = { 'radius': item.Radius } + else: + new_items.append(item) + representation.Items = new_items + def filter_ifc(self): for element in self.file.by_type('IfcElement'): if self.diff \ @@ -387,7 +436,13 @@ class IfcImporter(): mesh_name = f'mesh-{shape.geometry.id}' mesh = self.meshes.get(mesh_name) if mesh is None: - mesh = self.create_mesh(element, shape) + # TODO: figure out a design pattern for native objects + if element.is_a('IfcReinforcingBar'): + mesh = self.create_mesh(element, shape, is_curve=True) + mesh.bevel_object = self.native_data[element.GlobalId]['bevel_object'] + mesh.use_fill_caps = True + else: + mesh = self.create_mesh(element, shape) self.meshes[mesh_name] = mesh else: mesh = None @@ -790,12 +845,16 @@ class IfcImporter(): and representation.RepresentationType == 'MappedRepresentation': return representation.Items[0].MappingTarget - def create_mesh(self, element, shape): + def create_mesh(self, element, shape, is_curve=False): try: if hasattr(shape, 'geometry'): geometry = shape.geometry else: geometry = shape + + if is_curve: + return self.create_curve(geometry) + mesh = bpy.data.meshes.new(geometry.id) f = geometry.faces e = geometry.edges @@ -822,6 +881,28 @@ class IfcImporter(): except: self.ifc_import_settings.logger.error('Could not create mesh for {}: {}/{}'.format(element.GlobalId, self.get_name(element))) + def create_curve(self, geometry): + curve = bpy.data.curves.new(geometry.id, type='CURVE') + curve.dimensions = '3D' + curve.resolution_u = 2 + polyline = curve.splines.new('POLY') + e = geometry.edges + v = geometry.verts + vertices = [[v[i], v[i + 1], v[i + 2], 1] + for i in range(0, len(v), 3)] + edges = [[e[i], e[i + 1]] + for i in range(0, len(e), 2)] + v2 = None + for edge in edges: + v1 = vertices[edge[0]] + if v1 != v2: + polyline = curve.splines.new('POLY') + polyline.points[-1].co = v1 + v2 = vertices[edge[1]] + polyline.points.add(1) + polyline.points[-1].co = v2 + return curve + def a2p(self, o, z, x): y = z.cross(x) r = mathutils.Matrix((x, y, z, o))