mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-06 22:47:29 -06:00
Convert doxygen to rst for 3MFReader/Writer and AMFReader
This commit is contained in:
parent
679739d09d
commit
8f3827d5ae
6 changed files with 95 additions and 64 deletions
|
@ -32,8 +32,9 @@ except ImportError:
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
|
|
||||||
## Base implementation for reading 3MF files. Has no support for textures. Only loads meshes!
|
|
||||||
class ThreeMFReader(MeshReader):
|
class ThreeMFReader(MeshReader):
|
||||||
|
"""Base implementation for reading 3MF files. Has no support for textures. Only loads meshes!"""
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
|
@ -55,13 +56,17 @@ class ThreeMFReader(MeshReader):
|
||||||
return Matrix()
|
return Matrix()
|
||||||
|
|
||||||
split_transformation = transformation.split()
|
split_transformation = transformation.split()
|
||||||
## Transformation is saved as:
|
|
||||||
## M00 M01 M02 0.0
|
|
||||||
## M10 M11 M12 0.0
|
|
||||||
## M20 M21 M22 0.0
|
|
||||||
## M30 M31 M32 1.0
|
|
||||||
## We switch the row & cols as that is how everyone else uses matrices!
|
|
||||||
temp_mat = Matrix()
|
temp_mat = Matrix()
|
||||||
|
"""Transformation is saved as:
|
||||||
|
M00 M01 M02 0.0
|
||||||
|
|
||||||
|
M10 M11 M12 0.0
|
||||||
|
|
||||||
|
M20 M21 M22 0.0
|
||||||
|
|
||||||
|
M30 M31 M32 1.0
|
||||||
|
We switch the row & cols as that is how everyone else uses matrices!
|
||||||
|
"""
|
||||||
# Rotation & Scale
|
# Rotation & Scale
|
||||||
temp_mat._data[0, 0] = split_transformation[0]
|
temp_mat._data[0, 0] = split_transformation[0]
|
||||||
temp_mat._data[1, 0] = split_transformation[1]
|
temp_mat._data[1, 0] = split_transformation[1]
|
||||||
|
@ -80,9 +85,11 @@ class ThreeMFReader(MeshReader):
|
||||||
|
|
||||||
return temp_mat
|
return temp_mat
|
||||||
|
|
||||||
## Convenience function that converts a SceneNode object (as obtained from libSavitar) to a 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]:
|
||||||
|
"""Convenience function that converts a SceneNode object (as obtained from libSavitar) to a scene node.
|
||||||
|
|
||||||
|
:returns: Scene node.
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
node_name = savitar_node.getName()
|
node_name = savitar_node.getName()
|
||||||
node_id = savitar_node.getId()
|
node_id = savitar_node.getId()
|
||||||
|
@ -243,15 +250,17 @@ class ThreeMFReader(MeshReader):
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
## Create a scale vector based on a unit string.
|
|
||||||
# The core spec defines the following:
|
|
||||||
# * micron
|
|
||||||
# * millimeter (default)
|
|
||||||
# * centimeter
|
|
||||||
# * inch
|
|
||||||
# * foot
|
|
||||||
# * meter
|
|
||||||
def _getScaleFromUnit(self, unit: Optional[str]) -> Vector:
|
def _getScaleFromUnit(self, unit: Optional[str]) -> Vector:
|
||||||
|
"""Create a scale vector based on a unit string.
|
||||||
|
|
||||||
|
.. The core spec defines the following:
|
||||||
|
* micron
|
||||||
|
* millimeter (default)
|
||||||
|
* centimeter
|
||||||
|
* inch
|
||||||
|
* foot
|
||||||
|
* meter
|
||||||
|
"""
|
||||||
conversion_to_mm = {
|
conversion_to_mm = {
|
||||||
"micron": 0.001,
|
"micron": 0.001,
|
||||||
"millimeter": 1,
|
"millimeter": 1,
|
||||||
|
|
|
@ -89,8 +89,9 @@ class ExtruderInfo:
|
||||||
self.intent_info = None
|
self.intent_info = None
|
||||||
|
|
||||||
|
|
||||||
## Base implementation for reading 3MF workspace files.
|
|
||||||
class ThreeMFWorkspaceReader(WorkspaceReader):
|
class ThreeMFWorkspaceReader(WorkspaceReader):
|
||||||
|
"""Base implementation for reading 3MF workspace files."""
|
||||||
|
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
|
@ -130,18 +131,21 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
||||||
self._old_new_materials = {}
|
self._old_new_materials = {}
|
||||||
self._machine_info = None
|
self._machine_info = None
|
||||||
|
|
||||||
## Get a unique name based on the old_id. This is different from directly calling the registry in that it caches results.
|
|
||||||
# This has nothing to do with speed, but with getting consistent new naming for instances & objects.
|
|
||||||
def getNewId(self, old_id: str):
|
def getNewId(self, old_id: str):
|
||||||
|
"""Get a unique name based on the old_id. This is different from directly calling the registry in that it caches results.
|
||||||
|
|
||||||
|
This has nothing to do with speed, but with getting consistent new naming for instances & objects.
|
||||||
|
"""
|
||||||
if old_id not in self._id_mapping:
|
if old_id not in self._id_mapping:
|
||||||
self._id_mapping[old_id] = self._container_registry.uniqueName(old_id)
|
self._id_mapping[old_id] = self._container_registry.uniqueName(old_id)
|
||||||
return self._id_mapping[old_id]
|
return self._id_mapping[old_id]
|
||||||
|
|
||||||
## Separates the given file list into a list of GlobalStack files and a list of ExtruderStack files.
|
|
||||||
#
|
|
||||||
# In old versions, extruder stack files have the same suffix as container stack files ".stack.cfg".
|
|
||||||
#
|
|
||||||
def _determineGlobalAndExtruderStackFiles(self, project_file_name: str, file_list: List[str]) -> Tuple[str, List[str]]:
|
def _determineGlobalAndExtruderStackFiles(self, project_file_name: str, file_list: List[str]) -> Tuple[str, List[str]]:
|
||||||
|
"""Separates the given file list into a list of GlobalStack files and a list of ExtruderStack files.
|
||||||
|
|
||||||
|
In old versions, extruder stack files have the same suffix as container stack files ".stack.cfg".
|
||||||
|
"""
|
||||||
|
|
||||||
archive = zipfile.ZipFile(project_file_name, "r")
|
archive = zipfile.ZipFile(project_file_name, "r")
|
||||||
|
|
||||||
global_stack_file_list = [name for name in file_list if name.endswith(self._global_stack_suffix)]
|
global_stack_file_list = [name for name in file_list if name.endswith(self._global_stack_suffix)]
|
||||||
|
@ -181,10 +185,13 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
||||||
|
|
||||||
return global_stack_file_list[0], extruder_stack_file_list
|
return global_stack_file_list[0], extruder_stack_file_list
|
||||||
|
|
||||||
## read some info so we can make decisions
|
|
||||||
# \param file_name
|
|
||||||
# \param show_dialog In case we use preRead() to check if a file is a valid project file, we don't want to show a dialog.
|
|
||||||
def preRead(self, file_name, show_dialog=True, *args, **kwargs):
|
def preRead(self, file_name, show_dialog=True, *args, **kwargs):
|
||||||
|
"""Read some info so we can make decisions
|
||||||
|
|
||||||
|
:param file_name:
|
||||||
|
:param show_dialog: In case we use preRead() to check if a file is a valid project file,
|
||||||
|
we don't want to show a dialog.
|
||||||
|
"""
|
||||||
self._clearState()
|
self._clearState()
|
||||||
|
|
||||||
self._3mf_mesh_reader = Application.getInstance().getMeshFileHandler().getReaderForFile(file_name)
|
self._3mf_mesh_reader = Application.getInstance().getMeshFileHandler().getReaderForFile(file_name)
|
||||||
|
@ -578,15 +585,17 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
||||||
|
|
||||||
return WorkspaceReader.PreReadResult.accepted
|
return WorkspaceReader.PreReadResult.accepted
|
||||||
|
|
||||||
## Read the project file
|
|
||||||
# Add all the definitions / materials / quality changes that do not exist yet. Then it loads
|
|
||||||
# all the stacks into the container registry. In some cases it will reuse the container for the global stack.
|
|
||||||
# It handles old style project files containing .stack.cfg as well as new style project files
|
|
||||||
# containing global.cfg / extruder.cfg
|
|
||||||
#
|
|
||||||
# \param file_name
|
|
||||||
@call_on_qt_thread
|
@call_on_qt_thread
|
||||||
def read(self, file_name):
|
def read(self, file_name):
|
||||||
|
"""Read the project file
|
||||||
|
|
||||||
|
Add all the definitions / materials / quality changes that do not exist yet. Then it loads
|
||||||
|
all the stacks into the container registry. In some cases it will reuse the container for the global stack.
|
||||||
|
It handles old style project files containing .stack.cfg as well as new style project files
|
||||||
|
containing global.cfg / extruder.cfg
|
||||||
|
|
||||||
|
:param file_name:
|
||||||
|
"""
|
||||||
application = CuraApplication.getInstance()
|
application = CuraApplication.getInstance()
|
||||||
|
|
||||||
archive = zipfile.ZipFile(file_name, "r")
|
archive = zipfile.ZipFile(file_name, "r")
|
||||||
|
@ -856,19 +865,22 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
||||||
|
|
||||||
self._machine_info.quality_changes_info.name = quality_changes_name
|
self._machine_info.quality_changes_info.name = quality_changes_name
|
||||||
|
|
||||||
## Helper class to create a new quality changes profile.
|
|
||||||
#
|
|
||||||
# This will then later be filled with the appropriate data.
|
|
||||||
# \param quality_type The quality type of the new profile.
|
|
||||||
# \param intent_category The intent category of the new profile.
|
|
||||||
# \param name The name for the profile. This will later be made unique so
|
|
||||||
# it doesn't need to be unique yet.
|
|
||||||
# \param global_stack The global stack showing the configuration that the
|
|
||||||
# profile should be created for.
|
|
||||||
# \param extruder_stack The extruder stack showing the configuration that
|
|
||||||
# the profile should be created for. If this is None, it will be created
|
|
||||||
# for the global stack.
|
|
||||||
def _createNewQualityChanges(self, quality_type: str, intent_category: Optional[str], name: str, global_stack: GlobalStack, extruder_stack: Optional[ExtruderStack]) -> InstanceContainer:
|
def _createNewQualityChanges(self, quality_type: str, intent_category: Optional[str], name: str, global_stack: GlobalStack, extruder_stack: Optional[ExtruderStack]) -> InstanceContainer:
|
||||||
|
"""Helper class to create a new quality changes profile.
|
||||||
|
|
||||||
|
This will then later be filled with the appropriate data.
|
||||||
|
|
||||||
|
:param quality_type: The quality type of the new profile.
|
||||||
|
:param intent_category: The intent category of the new profile.
|
||||||
|
:param name: The name for the profile. This will later be made unique so
|
||||||
|
it doesn't need to be unique yet.
|
||||||
|
:param global_stack: The global stack showing the configuration that the
|
||||||
|
profile should be created for.
|
||||||
|
:param extruder_stack: The extruder stack showing the configuration that
|
||||||
|
the profile should be created for. If this is None, it will be created
|
||||||
|
for the global stack.
|
||||||
|
"""
|
||||||
|
|
||||||
container_registry = CuraApplication.getInstance().getContainerRegistry()
|
container_registry = CuraApplication.getInstance().getContainerRegistry()
|
||||||
base_id = global_stack.definition.getId() if extruder_stack is None else extruder_stack.getId()
|
base_id = global_stack.definition.getId() if extruder_stack is None else extruder_stack.getId()
|
||||||
new_id = base_id + "_" + name
|
new_id = base_id + "_" + name
|
||||||
|
@ -1077,9 +1089,10 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
|
||||||
def _getXmlProfileClass(self):
|
def _getXmlProfileClass(self):
|
||||||
return self._container_registry.getContainerForMimeType(MimeTypeDatabase.getMimeType("application/x-ultimaker-material-profile"))
|
return self._container_registry.getContainerForMimeType(MimeTypeDatabase.getMimeType("application/x-ultimaker-material-profile"))
|
||||||
|
|
||||||
## Get the list of ID's of all containers in a container stack by partially parsing it's serialized data.
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _getContainerIdListFromSerialized(serialized):
|
def _getContainerIdListFromSerialized(serialized):
|
||||||
|
"""Get the list of ID's of all containers in a container stack by partially parsing it's serialized data."""
|
||||||
|
|
||||||
parser = ConfigParser(interpolation = None, empty_lines_in_values = False)
|
parser = ConfigParser(interpolation = None, empty_lines_in_values = False)
|
||||||
parser.read_string(serialized)
|
parser.read_string(serialized)
|
||||||
|
|
||||||
|
|
|
@ -229,9 +229,10 @@ class WorkspaceDialog(QObject):
|
||||||
if key in self._result:
|
if key in self._result:
|
||||||
self._result[key] = strategy
|
self._result[key] = strategy
|
||||||
|
|
||||||
## Close the backend: otherwise one could end up with "Slicing..."
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def closeBackend(self):
|
def closeBackend(self):
|
||||||
|
"""Close the backend: otherwise one could end up with "Slicing..."""
|
||||||
|
|
||||||
Application.getInstance().getBackend().close()
|
Application.getInstance().getBackend().close()
|
||||||
|
|
||||||
def setMaterialConflict(self, material_conflict):
|
def setMaterialConflict(self, material_conflict):
|
||||||
|
@ -283,8 +284,9 @@ class WorkspaceDialog(QObject):
|
||||||
self.showDialogSignal.emit()
|
self.showDialogSignal.emit()
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
## Used to notify the dialog so the lock can be released.
|
|
||||||
def notifyClosed(self):
|
def notifyClosed(self):
|
||||||
|
"""Used to notify the dialog so the lock can be released."""
|
||||||
|
|
||||||
self._result = {} # The result should be cleared before hide, because after it is released the main thread lock
|
self._result = {} # The result should be cleared before hide, because after it is released the main thread lock
|
||||||
self._visible = False
|
self._visible = False
|
||||||
try:
|
try:
|
||||||
|
@ -319,8 +321,9 @@ class WorkspaceDialog(QObject):
|
||||||
self._view.hide()
|
self._view.hide()
|
||||||
self.hide()
|
self.hide()
|
||||||
|
|
||||||
## Block thread until the dialog is closed.
|
|
||||||
def waitForClose(self):
|
def waitForClose(self):
|
||||||
|
"""Block thread until the dialog is closed."""
|
||||||
|
|
||||||
if self._visible:
|
if self._visible:
|
||||||
if threading.current_thread() != threading.main_thread():
|
if threading.current_thread() != threading.main_thread():
|
||||||
self._lock.acquire()
|
self._lock.acquire()
|
||||||
|
|
|
@ -107,11 +107,13 @@ class ThreeMFWorkspaceWriter(WorkspaceWriter):
|
||||||
import json
|
import json
|
||||||
archive.writestr(file_in_archive, json.dumps(metadata, separators = (", ", ": "), indent = 4, skipkeys = True))
|
archive.writestr(file_in_archive, json.dumps(metadata, separators = (", ", ": "), indent = 4, skipkeys = True))
|
||||||
|
|
||||||
## Helper function that writes ContainerStacks, InstanceContainers and DefinitionContainers to the archive.
|
|
||||||
# \param container That follows the \type{ContainerInterface} to archive.
|
|
||||||
# \param archive The archive to write to.
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _writeContainerToArchive(container, archive):
|
def _writeContainerToArchive(container, archive):
|
||||||
|
"""Helper function that writes ContainerStacks, InstanceContainers and DefinitionContainers to the archive.
|
||||||
|
|
||||||
|
:param container: That follows the :type{ContainerInterface} to archive.
|
||||||
|
:param archive: The archive to write to.
|
||||||
|
"""
|
||||||
if isinstance(container, type(ContainerRegistry.getInstance().getEmptyInstanceContainer())):
|
if isinstance(container, type(ContainerRegistry.getInstance().getEmptyInstanceContainer())):
|
||||||
return # Empty file, do nothing.
|
return # Empty file, do nothing.
|
||||||
|
|
||||||
|
|
|
@ -60,15 +60,19 @@ class ThreeMFWriter(MeshWriter):
|
||||||
result += str(matrix._data[2, 3])
|
result += str(matrix._data[2, 3])
|
||||||
return result
|
return result
|
||||||
|
|
||||||
## Should we store the archive
|
|
||||||
# Note that if this is true, the archive will not be closed.
|
|
||||||
# The object that set this parameter is then responsible for closing it correctly!
|
|
||||||
def setStoreArchive(self, store_archive):
|
def setStoreArchive(self, store_archive):
|
||||||
|
"""Should we store the archive
|
||||||
|
|
||||||
|
Note that if this is true, the archive will not be closed.
|
||||||
|
The object that set this parameter is then responsible for closing it correctly!
|
||||||
|
"""
|
||||||
self._store_archive = store_archive
|
self._store_archive = store_archive
|
||||||
|
|
||||||
## Convenience function that converts an Uranium SceneNode object to a SavitarSceneNode
|
|
||||||
# \returns Uranium Scene node.
|
|
||||||
def _convertUMNodeToSavitarNode(self, um_node, transformation = Matrix()):
|
def _convertUMNodeToSavitarNode(self, um_node, transformation = Matrix()):
|
||||||
|
"""Convenience function that converts an Uranium SceneNode object to a SavitarSceneNode
|
||||||
|
|
||||||
|
:returns: Uranium Scene node.
|
||||||
|
"""
|
||||||
if not isinstance(um_node, SceneNode):
|
if not isinstance(um_node, SceneNode):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
|
@ -147,13 +147,13 @@ class AMFReader(MeshReader):
|
||||||
|
|
||||||
return group_node
|
return group_node
|
||||||
|
|
||||||
## Converts a Trimesh to Uranium's MeshData.
|
|
||||||
# \param tri_node A Trimesh containing the contents of a file that was
|
|
||||||
# just read.
|
|
||||||
# \param file_name The full original filename used to watch for changes
|
|
||||||
# \return Mesh data from the Trimesh in a way that Uranium can understand
|
|
||||||
# it.
|
|
||||||
def _toMeshData(self, tri_node: trimesh.base.Trimesh, file_name: str = "") -> MeshData:
|
def _toMeshData(self, tri_node: trimesh.base.Trimesh, file_name: str = "") -> MeshData:
|
||||||
|
"""Converts a Trimesh to Uranium's MeshData.
|
||||||
|
|
||||||
|
:param tri_node: A Trimesh containing the contents of a file that was just read.
|
||||||
|
:param file_name: The full original filename used to watch for changes
|
||||||
|
:return: Mesh data from the Trimesh in a way that Uranium can understand it.
|
||||||
|
"""
|
||||||
tri_faces = tri_node.faces
|
tri_faces = tri_node.faces
|
||||||
tri_vertices = tri_node.vertices
|
tri_vertices = tri_node.vertices
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue