Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change Assembly definition for memory usage optimization and performance #994

Draft
wants to merge 9 commits into
base: dev
Choose a base branch
from
Draft
97 changes: 97 additions & 0 deletions volmdlr/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -1296,6 +1296,103 @@ def to_step(self, current_id):
return step_content, current_id, [brep_id, product_definition_id]


class Assembly(Compound):
"""
Represents the structure of an assembly.

This class is similar to a Compound, capable of containing multiple sub-shapes. The key distinction is the
association of a frame with the Assembly. This frame is utilized for exporting into a STEP file.

:param primitives: A list of volmdlr objects representing sub-shapes.
:type primitives: List[:class:`volmdlr.core.Primitive3D`]
:param frame: The associated frame for the assembly. It's the frame where all the first level assembly's shapes
where defined. Default is volmdlr.OXYZ.
:type frame: :class:`volmdlr.core.Frame3D`
:param name: The name of the Assembly. Default is an empty string.
:type name: str
"""
_standalone_in_db = True
_eq_is_data_eq = True
_non_serializable_attributes = ['bounding_box', "primitives"]
_non_data_eq_attributes = ['name', 'bounding_box']
_non_data_hash_attributes = ['name', 'bounding_box']

def __init__(self, primitives: List[Primitive3D],
frame: volmdlr.Frame3D = volmdlr.OXYZ, name: str = ''):
self.frame = frame
self._bbox = None
Compound.__init__(self, primitives=primitives, name=name)

def frame_mapping(self, frame: volmdlr.Frame3D, side: str):
"""
Changes frame_mapping and return a new Compound.

side = 'old' or 'new'
"""
new_primitives = [primitive.frame_mapping(frame, side)
for primitive in self.primitives]
new_frame = self.frame.frame_mapping(frame, side)
return Assembly(new_primitives, new_frame, self.name)

def to_step(self, current_id):
"""
Creates step file entities from volmdlr objects.
"""
step_content = ''

product_content, current_id, assembly_data = self.to_step_product(current_id)
step_content += product_content
assembly_frames = assembly_data[-1]
for i, primitive in enumerate(self.primitives):
if primitive.__class__.__name__ in ('OpenShell3D', 'ClosedShell3D') or hasattr(primitive, "shell_faces"):
primitive_content, current_id, primitive_data = primitive.to_step_product(current_id)
assembly_frame_id = assembly_frames[0]
component_frame_id = assembly_frames[i + 1]
assembly_content, current_id = assembly_definition_writer(current_id, assembly_data[:-1],
primitive_data, assembly_frame_id,
component_frame_id)

else:
primitive_content, current_id, primitive_data = primitive.to_step(current_id)
step_content += primitive_content
assembly_frame_id = assembly_frames[0]
component_frame_id = assembly_frames[i + 1]
assembly_content, current_id = assembly_definition_writer(current_id, assembly_data[:-1],
primitive_data, assembly_frame_id,
component_frame_id)
step_content += primitive_content
step_content += assembly_content

return step_content, current_id, assembly_data[:-1]


def to_step_product(self, current_id):
"""
Returns step product entities from volmdlr objects.
"""
step_content = ''
product_content, shape_definition_repr_id = product_writer(current_id, self.name)
product_definition_id = shape_definition_repr_id - 2
step_content += product_content
shape_representation_id = shape_definition_repr_id + 1
current_id = shape_representation_id

frame_content, current_id = self.frame.to_step(current_id + 1)
frame_ids = [current_id] * (len(self.primitives) + 1)

geometric_context_content, geometric_representation_context_id = geometric_context_writer(current_id)

step_content += f"#{shape_representation_id} = SHAPE_REPRESENTATION('',({step_ids_to_str(frame_ids)})," \
f"#{geometric_representation_context_id});\n"

step_content += frame_content

step_content += geometric_context_content

return step_content, geometric_representation_context_id, \
[shape_representation_id, product_definition_id, frame_ids]


class VolumeModel(dc.PhysicalObject):
"""
A class containing one or several :class:`volmdlr.core.Primitive3D`.
Expand Down
8 changes: 6 additions & 2 deletions volmdlr/step.py
Original file line number Diff line number Diff line change
Expand Up @@ -726,8 +726,12 @@ def instatiate_assembly(self, object_dict):

if not list_primitives:
none_primitives.add(instantiate_id)

volmdlr_object = volmdlr.core.Assembly(list_primitives, assembly_positions, assembly_frame,
instantiate_ids.pop()
continue
list_primitives = [step_reader.map_primitive(primitive, assembly_frame, frame_primitive)
if frame_primitive != assembly_frame else primitive
for primitive, frame_primitive in zip(list_primitives, assembly_positions)]
volmdlr_object = volmdlr.core.Assembly(list_primitives, assembly_frame,
name=name)
object_dict[instantiate_id] = volmdlr_object
last_error = None
Expand Down
66 changes: 33 additions & 33 deletions volmdlr/utils/step_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -687,6 +687,39 @@ def geometrically_bounded_surface_shape_representation(arguments, object_dict, *
return primitives[0]


def map_primitive(primitive, global_frame, transformed_frame):
"""
Frame maps a primitive in an assembly to its good position.

:param primitive: primitive to map
:type primitive: Primitive3D
:param global_frame: Assembly frame
:type global_frame: volmdlr.Frame3D
:param transformed_frame: position of the primitive on the assembly
:type transformed_frame: volmdlr.Frame3D
:return: A new positioned primitive
:rtype: Primitive3D

"""
basis_a = global_frame.basis()
basis_b = transformed_frame.basis()
matrix_a = npy.array([[basis_a.vectors[0].x, basis_a.vectors[0].y, basis_a.vectors[0].z],
[basis_a.vectors[1].x, basis_a.vectors[1].y, basis_a.vectors[1].z],
[basis_a.vectors[2].x, basis_a.vectors[2].y, basis_a.vectors[2].z]])
matrix_b = npy.array([[basis_b.vectors[0].x, basis_b.vectors[0].y, basis_b.vectors[0].z],
[basis_b.vectors[1].x, basis_b.vectors[1].y, basis_b.vectors[1].z],
[basis_b.vectors[2].x, basis_b.vectors[2].y, basis_b.vectors[2].z]])
transfer_matrix = npy.linalg.solve(matrix_a, matrix_b)
u_vector = volmdlr.Vector3D(*transfer_matrix[0])
v_vector = volmdlr.Vector3D(*transfer_matrix[1])
w_vector = volmdlr.Vector3D(*transfer_matrix[2])
new_frame = volmdlr.Frame3D(transformed_frame.origin, u_vector, v_vector, w_vector)
if new_frame == volmdlr.OXYZ:
return primitive
new_primitive = primitive.frame_mapping(new_frame, 'old')
return new_primitive


def geometrically_bounded_wireframe_shape_representation(arguments, object_dict, *args, **kwargs):
"""
Returns xx.
Expand All @@ -711,39 +744,6 @@ def geometrically_bounded_wireframe_shape_representation(arguments, object_dict,
return primitives[0]


def frame_map_closed_shell(closed_shells, item_defined_transformation_frames, shape_representation_frames):
"""
Frame maps a closed shell in an assembly to its good position.

:param closed_shells: DESCRIPTION
:type closed_shells: vmshells.OpenShell3D
:param item_defined_transformation_frames: DESCRIPTION
:type item_defined_transformation_frames: TYPE
:param shape_representation_frames: DESCRIPTION
:type shape_representation_frames: TYPE
:return: DESCRIPTION
:rtype: TYPE

"""
if item_defined_transformation_frames[0] == item_defined_transformation_frames[1]:
return closed_shells
if shape_representation_frames[0].origin.is_close(volmdlr.O3D):
global_frame = shape_representation_frames[0]
else:
global_frame = [frame for frame in item_defined_transformation_frames if frame.origin.is_close(volmdlr.O3D)][0]
transformed_frame = [frame for frame in item_defined_transformation_frames if frame != global_frame][0]
new_closedshells = []

for shell3d in closed_shells:
basis_a = global_frame.basis()
basis_b = transformed_frame.basis()
transfer_matrix = get_transfer_matrix_from_basis(basis_a, basis_b)
new_frame = volmdlr.Frame3D(transformed_frame.origin, volmdlr.Vector3D(*transfer_matrix[0]),
volmdlr.Vector3D(*transfer_matrix[1]), volmdlr.Vector3D(*transfer_matrix[2]))
new_closedshells.append(shell3d.frame_mapping(new_frame, 'old'))
return new_closedshells


def representation_relationship_representation_relationship_with_transformation_shape_representation_relationship(
arguments, object_dict, *args, **kwargs):
"""
Expand Down