From ad7ef0be4f8a50bf6faf1163c7950ed516e1f0bb Mon Sep 17 00:00:00 2001 From: Dion Moult Date: Sun, 24 Nov 2019 21:30:24 +1100 Subject: [PATCH] Implement experimental support for mirror modifier --- src/ifcblenderexport/blenderbim/export_ifc.py | 130 +++++++++++++----- 1 file changed, 95 insertions(+), 35 deletions(-) diff --git a/src/ifcblenderexport/blenderbim/export_ifc.py b/src/ifcblenderexport/blenderbim/export_ifc.py index a3323265d7..db78f5e10a 100644 --- a/src/ifcblenderexport/blenderbim/export_ifc.py +++ b/src/ifcblenderexport/blenderbim/export_ifc.py @@ -219,26 +219,94 @@ class IfcParser(): for product in self.selected_products: obj = product['raw'] self.add_product(self.get_product(product)) - self.resolve_array_modifier(product) + self.resolve_modifiers(product) - def resolve_array_modifier(self, product): + def resolve_modifiers(self, product): obj = product['raw'] - instance_objects = [(obj, obj.matrix_world.translation)] - global_id_index = 0 - for instance in self.get_instances(obj): + instance_objects = [(obj, { + 'location': obj.matrix_world.translation, + 'scale': obj.scale + })] + + for modifier in obj.modifiers: created_instances = [] - for n in range(instance.count - 1): - for o in instance_objects: - location = o[1] + ((n + 1) * instance.offset) - self.add_product( - self.get_product( - {'raw': o[0], 'metadata': product['metadata']}, - {'location': location}, - {'GlobalId': self.get_parametric_global_id(obj, global_id_index)} - ) + if modifier.type == 'ARRAY': + instance_objects.extend( + self.resolve_array_modifier(product, modifier, instance_objects) + ) + elif modifier.type == 'MIRROR': + instance_objects.extend( + self.resolve_mirror_modifier(product, modifier, instance_objects) + ) + + def get_array_modifier(self, product, modifier): + obj = product['raw'] + array = ArrayModifier() + world_rotation = obj.matrix_world.decompose()[1] + array.offset = world_rotation @ Vector( + ( + modifier.constant_offset_displace[0], + modifier.constant_offset_displace[1], + modifier.constant_offset_displace[2] + ) + ) + if modifier.fit_type == 'FIXED_COUNT': + array.count = modifier.count + elif modifier.fit_type == 'FIT_LENGTH': + array.count = int(modifier.fit_length / array.offset.length) + return array + + def resolve_array_modifier(self, product, modifier, instance_objects): + modifier = self.get_array_modifier(product, modifier) + created_instances = [] + for obj in instance_objects: + for n in range(modifier.count - 1): + override = obj[1].copy() + location = override['location'] + ((n + 1) * modifier.offset) + override['location'] = location + self.add_product( + self.get_product( + {'raw': obj[0], 'metadata': product['metadata']}, + metadata_override=override, + attribute_override={'GlobalId': self.get_parametric_global_id( + product['raw'], + len(instance_objects)+len(created_instances)-1 + ) + } ) - created_instances.append((o[0], location)) - instance_objects.extend(created_instances) + ) + created_instances.append((obj[0], override)) + return created_instances + + def resolve_mirror_modifier(self, product, modifier, instance_objects): + return [] # TODO: not yet stable + created_instances = [] + mirrors = [] + for axis in [0, 1, 2]: + if modifier.use_axis[axis]: + mirrors.append(axis) + for mirror in mirrors: + axis_instances = [] + for obj in instance_objects: + override = obj[1].copy() + override['has_scale'] = True + override['has_mirror'] = True + override['scale'][mirror] *= -1 + self.add_product( + self.get_product( + {'raw': obj[0], 'metadata': product['metadata']}, + metadata_override=override, + attribute_override={'GlobalId': self.get_parametric_global_id( + product['raw'], + len(instance_objects)+len(created_instances)-1 + ) + } + ) + ) + created_instances.append((obj[0], override)) + axis_instances.append((obj[0], override)) + instance_objects.extend(axis_instances) + return created_instances def resolve_boolean_modifiers(self): for i, product in enumerate(self.products): @@ -289,6 +357,7 @@ class IfcParser(): 'forward_axis': self.get_axis(obj.matrix_world, 0), 'right_axis': self.get_axis(obj.matrix_world, 1), 'has_scale': obj.scale != Vector((1, 1, 1)), + 'has_mirror': False, 'scale': obj.scale, 'class': self.get_ifc_class(obj.name), 'relating_structure': None, @@ -394,21 +463,6 @@ class IfcParser(): if child.name == child_collection.name: return parent_collection - def get_instances(self, obj): - instances = [] - for m in obj.modifiers: - if m.type == 'ARRAY': - array = ArrayModifier() - world_rotation = obj.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 - def convert_selected_objects_into_products(self, objects_to_sort, metadata=None): if not metadata: metadata = {} @@ -1419,6 +1473,12 @@ class IfcExporter(): mapping_source = self.ifc_parser.representations[representation_name]['ifc'] shape_representation = mapping_source.MappedRepresentation if product['has_scale']: + if not product['has_mirror']: + product['scale'] = Vector(( + abs(product['scale'].x), + abs(product['scale'].y), + abs(product['scale'].z) + )) mapping_target = self.file.createIfcCartesianTransformationOperator3DnonUniform( self.create_direction(product['forward_axis']), self.create_direction(product['right_axis']), @@ -1427,10 +1487,10 @@ class IfcExporter(): product['location'].y, product['location'].z ), - abs(product['scale'].x), + product['scale'].x, self.create_direction(product['up_axis']), - abs(product['scale'].y), - abs(product['scale'].z)) + product['scale'].y, + product['scale'].z) else: mapping_target = self.file.createIfcCartesianTransformationOperator3D( self.create_direction(Vector((1, 0, 0))), @@ -1805,7 +1865,7 @@ class IfcExporter(): self.ifc_parser.products[relating_opening_element]['ifc'], self.ifc_parser.products[related_building_element]['ifc'] ) - + 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(