mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-27 18:57:17 +00:00
Parse array modifiers and create instances. Take into account local vs global rotation.
This commit is contained in:
@@ -3,6 +3,11 @@ import bpy
|
|||||||
import csv
|
import csv
|
||||||
import json
|
import json
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from mathutils import Vector
|
||||||
|
|
||||||
|
class ArrayModifier:
|
||||||
|
count: int
|
||||||
|
offset: Vector
|
||||||
|
|
||||||
class IfcParser():
|
class IfcParser():
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -32,37 +37,73 @@ class IfcParser():
|
|||||||
self.representations = self.get_representations()
|
self.representations = self.get_representations()
|
||||||
self.type_products = self.get_type_products()
|
self.type_products = self.get_type_products()
|
||||||
|
|
||||||
collection_name_filter = []
|
self.collection_name_filter = []
|
||||||
for index, object in enumerate(self.selected_products):
|
index = 0
|
||||||
product_data = {
|
for object in self.selected_products:
|
||||||
'ifc': None,
|
self.products.append(self.get_product(object, index))
|
||||||
'raw': object,
|
index += 1
|
||||||
'class': self.get_ifc_class(object.name),
|
|
||||||
'relating_structure': None,
|
instance_objects = [(object, object.location)]
|
||||||
'representation': self.get_representation_reference(object.data.name),
|
for instance in self.get_instances(object):
|
||||||
'attributes': self.get_object_attributes(object)
|
created_instances = []
|
||||||
}
|
for n in range(instance.count-1):
|
||||||
for collection in object.users_collection:
|
for o in instance_objects:
|
||||||
if self.is_a_spatial_structure_element(self.get_ifc_class(collection.name)):
|
location = o[1] + ((n+1) * instance.offset)
|
||||||
reference = self.get_spatial_structure_element_reference(collection.name)
|
self.products.append(self.get_product(o[0], index,
|
||||||
self.rel_contained_in_spatial_structure.setdefault(reference, []).append(index)
|
{'location': location}))
|
||||||
product_data['relating_structure'] = reference
|
index += 1
|
||||||
collection_name_filter.append(collection.name)
|
created_instances.append((o[0], location))
|
||||||
if object.parent \
|
instance_objects.extend(created_instances)
|
||||||
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(index)
|
|
||||||
self.products.append(product_data)
|
|
||||||
|
|
||||||
self.context = self.get_context()
|
self.context = self.get_context()
|
||||||
self.spatial_structure_elements_tree = self.get_spatial_structure_elements_tree(
|
self.spatial_structure_elements_tree = self.get_spatial_structure_elements_tree(
|
||||||
self.context['raw'].children, collection_name_filter)
|
self.context['raw'].children, self.collection_name_filter)
|
||||||
|
|
||||||
def get_object_attributes(self, object):
|
def get_object_attributes(self, object):
|
||||||
attributes = { 'Name': self.get_ifc_name(object.name) }
|
attributes = { 'Name': self.get_ifc_name(object.name) }
|
||||||
attributes.update({ key[3:]: object[key] for key in object.keys() if key[0:3] == 'Ifc'})
|
attributes.update({ key[3:]: object[key] for key in object.keys() if key[0:3] == 'Ifc'})
|
||||||
return attributes
|
return attributes
|
||||||
|
|
||||||
|
def get_product(self, object, index, attribute_override={}):
|
||||||
|
product = {
|
||||||
|
'ifc': None,
|
||||||
|
'raw': object,
|
||||||
|
'location': object.location,
|
||||||
|
'up_axis': object.matrix_world.to_quaternion() @ Vector((0, 0, 1)),
|
||||||
|
'forward_axis': object.matrix_world.to_quaternion() @ Vector((1, 0, 0)),
|
||||||
|
'class': self.get_ifc_class(object.name),
|
||||||
|
'relating_structure': None,
|
||||||
|
'representation': self.get_representation_reference(object.data.name),
|
||||||
|
'attributes': self.get_object_attributes(object)
|
||||||
|
}
|
||||||
|
product.update(attribute_override)
|
||||||
|
for collection in object.users_collection:
|
||||||
|
if self.is_a_spatial_structure_element(self.get_ifc_class(collection.name)):
|
||||||
|
reference = self.get_spatial_structure_element_reference(collection.name)
|
||||||
|
self.rel_contained_in_spatial_structure.setdefault(reference, []).append(index)
|
||||||
|
product['relating_structure'] = reference
|
||||||
|
self.collection_name_filter.append(collection.name)
|
||||||
|
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(index)
|
||||||
|
return product
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
def sort_selected_into_products_and_types(self):
|
def sort_selected_into_products_and_types(self):
|
||||||
for object in bpy.context.selected_objects:
|
for object in bpy.context.selected_objects:
|
||||||
if self.is_object_in_types_collection(object):
|
if self.is_object_in_types_collection(object):
|
||||||
@@ -269,7 +310,7 @@ class IfcExporter():
|
|||||||
def create_type_products(self):
|
def create_type_products(self):
|
||||||
for product in self.ifc_parser.type_products:
|
for product in self.ifc_parser.type_products:
|
||||||
representation = self.ifc_parser.representations[product['representation']]['ifc']
|
representation = self.ifc_parser.representations[product['representation']]['ifc']
|
||||||
placement = self.create_ifc_axis_2_placement_3d(product['raw'].location)
|
placement = self.create_ifc_axis_2_placement_3d(product['location'], product['up_axis'], product['forward_axis'])
|
||||||
representation_map = self.file.createIfcRepresentationMap(placement, representation)
|
representation_map = self.file.createIfcRepresentationMap(placement, representation)
|
||||||
product['attributes'].update({
|
product['attributes'].update({
|
||||||
'GlobalId': ifcopenshell.guid.new(),
|
'GlobalId': ifcopenshell.guid.new(),
|
||||||
@@ -314,24 +355,31 @@ class IfcExporter():
|
|||||||
print('The product "{}/{}" could not be placed on a spatial structure {}'.format(product['class'], product['attributes']['Name'], e.args))
|
print('The product "{}/{}" could not be placed on a spatial structure {}'.format(product['class'], product['attributes']['Name'], e.args))
|
||||||
continue
|
continue
|
||||||
placement = self.file.createIfcLocalPlacement(placement_rel_to,
|
placement = self.file.createIfcLocalPlacement(placement_rel_to,
|
||||||
self.create_ifc_axis_2_placement_3d(product['raw'].location))
|
self.create_ifc_axis_2_placement_3d(product['location'],
|
||||||
representation = self.file.createIfcProductDefinitionShape(
|
product['up_axis'],
|
||||||
None, None,
|
product['forward_axis']))
|
||||||
[self.ifc_parser.representations[product['representation']]['ifc']])
|
shape = self.file.createIfcProductDefinitionShape(
|
||||||
|
None, None,
|
||||||
|
[self.ifc_parser.representations[product['representation']]['ifc']])
|
||||||
product['attributes'].update({
|
product['attributes'].update({
|
||||||
'GlobalId': ifcopenshell.guid.new(), # TODO: unhardcode
|
'GlobalId': ifcopenshell.guid.new(), # TODO: unhardcode
|
||||||
'OwnerHistory': self.owner_history, # TODO: unhardcode
|
'OwnerHistory': self.owner_history, # TODO: unhardcode
|
||||||
'ObjectPlacement': placement,
|
'ObjectPlacement': placement,
|
||||||
'Representation': representation
|
'Representation': shape
|
||||||
})
|
})
|
||||||
try:
|
self.create_product(product)
|
||||||
product['ifc'] = self.file.create_entity(product['class'], **product['attributes'])
|
|
||||||
except RuntimeError as e:
|
|
||||||
print('The product "{}/{}" could not be created: {}'.format(product['class'], product['attributes']['Name'], e.args))
|
|
||||||
|
|
||||||
def create_ifc_axis_2_placement_3d(self, point):
|
def create_product(self, product):
|
||||||
|
try:
|
||||||
|
product['ifc'] = self.file.create_entity(product['class'], **product['attributes'])
|
||||||
|
except RuntimeError as e:
|
||||||
|
print('The product "{}/{}" could not be created: {}'.format(product['class'], product['attributes']['Name'], e.args))
|
||||||
|
|
||||||
|
def create_ifc_axis_2_placement_3d(self, point, up, forward):
|
||||||
return self.file.createIfcAxis2Placement3D(
|
return self.file.createIfcAxis2Placement3D(
|
||||||
self.file.createIfcCartesianPoint((point.x, point.y, point.z)))
|
self.file.createIfcCartesianPoint((point.x, point.y, point.z)),
|
||||||
|
self.file.createIfcDirection((up.x, up.y, up.z)),
|
||||||
|
self.file.createIfcDirection((forward.x, forward.y, forward.z)))
|
||||||
|
|
||||||
def create_representation(self, mesh):
|
def create_representation(self, mesh):
|
||||||
ifc_vertices = []
|
ifc_vertices = []
|
||||||
|
|||||||
Reference in New Issue
Block a user