Fix wrong placement of objects children when saving to 3MF

We now ignore the auto-centering of meshes for children objects, because it messes up with their relative position with their parent. Only the top-level objects needs to be centered, the children will follow.

CURA-11902
This commit is contained in:
Erwan MATHIEU 2024-05-14 14:54:00 +02:00
parent 22c17c68ac
commit b75f168c55

View file

@ -96,7 +96,8 @@ class ThreeMFWriter(MeshWriter):
@staticmethod @staticmethod
def _convertUMNodeToSavitarNode(um_node, def _convertUMNodeToSavitarNode(um_node,
transformation = Matrix(), transformation = Matrix(),
exported_settings: Optional[Dict[str, Set[str]]] = None): exported_settings: Optional[Dict[str, Set[str]]] = None,
center_mesh = False):
"""Convenience function that converts an Uranium SceneNode object to a SavitarSceneNode """Convenience function that converts an Uranium SceneNode object to a SavitarSceneNode
:returns: Uranium Scene node. :returns: Uranium Scene node.
@ -111,16 +112,21 @@ class ThreeMFWriter(MeshWriter):
savitar_node = Savitar.SceneNode() savitar_node = Savitar.SceneNode()
savitar_node.setName(um_node.getName()) savitar_node.setName(um_node.getName())
node_matrix = Matrix() node_matrix = um_node.getLocalTransformation()
mesh_data = um_node.getMeshData() mesh_data = um_node.getMeshData()
# compensate for original center position, if object(s) is/are not around its zero position
if mesh_data is not None: if center_mesh:
extents = mesh_data.getExtents() node_matrix = Matrix()
if extents is not None: # compensate for original center position, if object(s) is/are not around its zero position
# We use a different coordinate space while writing, so flip Z and Y if mesh_data is not None:
center_vector = Vector(extents.center.x, extents.center.z, extents.center.y) extents = mesh_data.getExtents()
node_matrix.setByTranslation(center_vector) if extents is not None:
node_matrix.multiply(um_node.getLocalTransformation()) # We use a different coordinate space while writing, so flip Z and Y
center_vector = Vector(extents.center.x, extents.center.y, extents.center.z)
node_matrix.setByTranslation(center_vector)
node_matrix.multiply(um_node.getLocalTransformation())
else:
node_matrix = um_node.getLocalTransformation()
matrix_string = ThreeMFWriter._convertMatrixToString(node_matrix.preMultiply(transformation)) matrix_string = ThreeMFWriter._convertMatrixToString(node_matrix.preMultiply(transformation))
@ -147,7 +153,7 @@ class ThreeMFWriter(MeshWriter):
for key in changed_setting_keys: for key in changed_setting_keys:
savitar_node.setSetting("cura:" + key, str(stack.getProperty(key, "value"))) savitar_node.setSetting("cura:" + key, str(stack.getProperty(key, "value")))
else: else:
# We want to export only the specified settings # We want to export only the specified settings
if um_node.getName() in exported_settings: if um_node.getName() in exported_settings:
model_exported_settings = exported_settings[um_node.getName()] model_exported_settings = exported_settings[um_node.getName()]
@ -283,7 +289,8 @@ class ThreeMFWriter(MeshWriter):
for root_child in node.getChildren(): for root_child in node.getChildren():
savitar_node = ThreeMFWriter._convertUMNodeToSavitarNode(root_child, savitar_node = ThreeMFWriter._convertUMNodeToSavitarNode(root_child,
transformation_matrix, transformation_matrix,
exported_model_settings) exported_model_settings,
center_mesh = True)
if savitar_node: if savitar_node:
savitar_scene.addSceneNode(savitar_node) savitar_scene.addSceneNode(savitar_node)
else: else:
@ -442,7 +449,7 @@ class ThreeMFWriter(MeshWriter):
def sceneNodesToString(scene_nodes: [SceneNode]) -> str: def sceneNodesToString(scene_nodes: [SceneNode]) -> str:
savitar_scene = Savitar.Scene() savitar_scene = Savitar.Scene()
for scene_node in scene_nodes: for scene_node in scene_nodes:
savitar_node = ThreeMFWriter._convertUMNodeToSavitarNode(scene_node) savitar_node = ThreeMFWriter._convertUMNodeToSavitarNode(scene_node, center_mesh = True)
savitar_scene.addSceneNode(savitar_node) savitar_scene.addSceneNode(savitar_node)
parser = Savitar.ThreeMFParser() parser = Savitar.ThreeMFParser()
scene_string = parser.sceneToString(savitar_scene) scene_string = parser.sceneToString(savitar_scene)