Revert "Revert "Merge pull request #7384 from Ultimaker/CURA-7333_Fix_reloading_3mf_files_with_many_objects""

This reverts commit 4f55c8d8
This commit is contained in:
Nino van Hooff 2020-04-08 11:06:31 +02:00
parent be8f8a308e
commit e43768ebde
2 changed files with 49 additions and 27 deletions

View file

@ -4,7 +4,7 @@
import os import os
import sys import sys
import time import time
from typing import cast, TYPE_CHECKING, Optional, Callable, List, Any from typing import cast, TYPE_CHECKING, Optional, Callable, List, Any, Dict
import numpy import numpy
from PyQt5.QtCore import QObject, QTimer, QUrl, pyqtSignal, pyqtProperty, QEvent, Q_ENUMS from PyQt5.QtCore import QObject, QTimer, QUrl, pyqtSignal, pyqtProperty, QEvent, Q_ENUMS
@ -1382,22 +1382,29 @@ class CuraApplication(QtApplication):
if not nodes: if not nodes:
return return
objects_in_filename = {} # type: Dict[str, List[CuraSceneNode]]
for node in nodes: for node in nodes:
mesh_data = node.getMeshData() mesh_data = node.getMeshData()
if mesh_data: if mesh_data:
file_name = mesh_data.getFileName() file_name = mesh_data.getFileName()
if file_name: if file_name:
job = ReadMeshJob(file_name) if file_name not in objects_in_filename:
job._node = node # type: ignore objects_in_filename[file_name] = []
job.finished.connect(self._reloadMeshFinished) if file_name in objects_in_filename:
if has_merged_nodes: objects_in_filename[file_name].append(node)
job.finished.connect(self.updateOriginOfMergedMeshes)
job.start()
else: else:
Logger.log("w", "Unable to reload data because we don't have a filename.") Logger.log("w", "Unable to reload data because we don't have a filename.")
for file_name, nodes in objects_in_filename.items():
for node in nodes:
job = ReadMeshJob(file_name)
job._node = node # type: ignore
job.finished.connect(self._reloadMeshFinished)
if has_merged_nodes:
job.finished.connect(self.updateOriginOfMergedMeshes)
job.start()
@pyqtSlot("QStringList") @pyqtSlot("QStringList")
def setExpandedCategories(self, categories: List[str]) -> None: def setExpandedCategories(self, categories: List[str]) -> None:
categories = list(set(categories)) categories = list(set(categories))
@ -1572,13 +1579,30 @@ class CuraApplication(QtApplication):
fileLoaded = pyqtSignal(str) fileLoaded = pyqtSignal(str)
fileCompleted = pyqtSignal(str) fileCompleted = pyqtSignal(str)
def _reloadMeshFinished(self, job): def _reloadMeshFinished(self, job) -> None:
# TODO; This needs to be fixed properly. We now make the assumption that we only load a single mesh! """
job_result = job.getResult() Function called whenever a ReadMeshJob finishes in the background. It reloads a specific node object in the
scene from its source file. The function gets all the nodes that exist in the file through the job result, and
then finds the scene node that it wants to refresh by its object id. Each job refreshes only one node.
:param job: The ReadMeshJob running in the background that reads all the meshes in a file
:return: None
"""
job_result = job.getResult() # nodes that exist inside the file read by this job
if len(job_result) == 0: if len(job_result) == 0:
Logger.log("e", "Reloading the mesh failed.") Logger.log("e", "Reloading the mesh failed.")
return return
mesh_data = job_result[0].getMeshData() object_found = False
mesh_data = None
# Find the node to be refreshed based on its id
for job_result_node in job_result:
if job_result_node.getId() == job._node.getId():
mesh_data = job_result_node.getMeshData()
object_found = True
break
if not object_found:
Logger.warning("The object with id {} no longer exists! Keeping the old version in the scene.".format(job_result_node.getId()))
return
if not mesh_data: if not mesh_data:
Logger.log("w", "Could not find a mesh in reloaded node.") Logger.log("w", "Could not find a mesh in reloaded node.")
return return

View file

@ -1,31 +1,28 @@
# Copyright (c) 2019 Ultimaker B.V. # Copyright (c) 2019 Ultimaker B.V.
# Cura is released under the terms of the LGPLv3 or higher. # Cura is released under the terms of the LGPLv3 or higher.
from typing import List, Optional, Union, TYPE_CHECKING
import os.path import os.path
import zipfile import zipfile
from typing import List, Optional, Union, TYPE_CHECKING
import numpy
import Savitar import Savitar
import numpy
from UM.Logger import Logger from UM.Logger import Logger
from UM.Math.Matrix import Matrix from UM.Math.Matrix import Matrix
from UM.Math.Vector import Vector from UM.Math.Vector import Vector
from UM.Mesh.MeshBuilder import MeshBuilder from UM.Mesh.MeshBuilder import MeshBuilder
from UM.Mesh.MeshReader import MeshReader from UM.Mesh.MeshReader import MeshReader
from UM.Scene.GroupDecorator import GroupDecorator
from UM.Scene.SceneNode import SceneNode #For typing.
from UM.MimeTypeDatabase import MimeTypeDatabase, MimeType from UM.MimeTypeDatabase import MimeTypeDatabase, MimeType
from UM.Scene.GroupDecorator import GroupDecorator
from UM.Scene.SceneNode import SceneNode # For typing.
from cura.CuraApplication import CuraApplication from cura.CuraApplication import CuraApplication
from cura.Machines.ContainerTree import ContainerTree from cura.Machines.ContainerTree import ContainerTree
from cura.Settings.ExtruderManager import ExtruderManager
from cura.Scene.CuraSceneNode import CuraSceneNode
from cura.Scene.BuildPlateDecorator import BuildPlateDecorator from cura.Scene.BuildPlateDecorator import BuildPlateDecorator
from cura.Scene.CuraSceneNode import CuraSceneNode
from cura.Scene.SliceableObjectDecorator import SliceableObjectDecorator from cura.Scene.SliceableObjectDecorator import SliceableObjectDecorator
from cura.Scene.ZOffsetDecorator import ZOffsetDecorator from cura.Scene.ZOffsetDecorator import ZOffsetDecorator
from cura.Settings.ExtruderManager import ExtruderManager
try: try:
if not TYPE_CHECKING: if not TYPE_CHECKING:
@ -52,7 +49,6 @@ class ThreeMFReader(MeshReader):
self._root = None self._root = None
self._base_name = "" self._base_name = ""
self._unit = None self._unit = None
self._object_count = 0 # Used to name objects as there is no node name yet.
def _createMatrixFromTransformationString(self, transformation: str) -> Matrix: def _createMatrixFromTransformationString(self, transformation: str) -> Matrix:
if transformation == "": if transformation == "":
@ -87,17 +83,20 @@ class ThreeMFReader(MeshReader):
## Convenience function that converts a SceneNode object (as obtained from libSavitar) to a scene node. ## Convenience function that converts a SceneNode object (as obtained from libSavitar) to a scene node.
# \returns Scene node. # \returns Scene node.
def _convertSavitarNodeToUMNode(self, savitar_node: Savitar.SceneNode, file_name: str = "") -> Optional[SceneNode]: def _convertSavitarNodeToUMNode(self, savitar_node: Savitar.SceneNode, file_name: str = "") -> Optional[SceneNode]:
self._object_count += 1
node_name = savitar_node.getName() node_name = savitar_node.getName()
node_id = savitar_node.getId()
if node_name == "": if node_name == "":
node_name = "Object %s" % self._object_count if file_name != "":
node_name = os.path.basename(file_name)
else:
node_name = "Object {}".format(node_id)
active_build_plate = CuraApplication.getInstance().getMultiBuildPlateModel().activeBuildPlate active_build_plate = CuraApplication.getInstance().getMultiBuildPlateModel().activeBuildPlate
um_node = CuraSceneNode() # This adds a SettingOverrideDecorator um_node = CuraSceneNode() # This adds a SettingOverrideDecorator
um_node.addDecorator(BuildPlateDecorator(active_build_plate)) um_node.addDecorator(BuildPlateDecorator(active_build_plate))
um_node.setName(node_name) um_node.setName(node_name)
um_node.setId(node_id)
transformation = self._createMatrixFromTransformationString(savitar_node.getTransformation()) transformation = self._createMatrixFromTransformationString(savitar_node.getTransformation())
um_node.setTransformation(transformation) um_node.setTransformation(transformation)
mesh_builder = MeshBuilder() mesh_builder = MeshBuilder()
@ -169,7 +168,6 @@ class ThreeMFReader(MeshReader):
def _read(self, file_name: str) -> Union[SceneNode, List[SceneNode]]: def _read(self, file_name: str) -> Union[SceneNode, List[SceneNode]]:
result = [] result = []
self._object_count = 0 # Used to name objects as there is no node name yet.
# The base object of 3mf is a zipped archive. # The base object of 3mf is a zipped archive.
try: try:
archive = zipfile.ZipFile(file_name, "r") archive = zipfile.ZipFile(file_name, "r")