Merge pull request #13209 from Ultimaker/CURA-9224_approver_settings_json

[CURA-9224] Approver settings json
This commit is contained in:
Jaime van Kessel 2022-09-13 14:07:42 +02:00 committed by GitHub
commit ce71cbb57b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 81 additions and 34 deletions

View File

@ -1,6 +1,8 @@
# Copyright (c) 2019 Ultimaker B.V. # Copyright (c) 2022 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.
import copy
from typing import Optional, cast from typing import Optional, cast
from UM.ConfigurationErrorMessage import ConfigurationErrorMessage from UM.ConfigurationErrorMessage import ConfigurationErrorMessage

View File

@ -1,9 +1,8 @@
# Copyright (c) 2019 Ultimaker B.V. # Copyright (c) 2022 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.
import re # For escaping characters in the settings. import re # For escaping characters in the settings.
import json import json
import copy
from UM.Mesh.MeshWriter import MeshWriter from UM.Mesh.MeshWriter import MeshWriter
from UM.Logger import Logger from UM.Logger import Logger
@ -12,6 +11,8 @@ from UM.Settings.InstanceContainer import InstanceContainer
from cura.Machines.ContainerTree import ContainerTree from cura.Machines.ContainerTree import ContainerTree
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
from cura.Settings.CuraStackBuilder import CuraStackBuilder
catalog = i18nCatalog("cura") catalog = i18nCatalog("cura")
@ -96,25 +97,6 @@ class GCodeWriter(MeshWriter):
self.setInformation(catalog.i18nc("@warning:status", "Please prepare G-code before exporting.")) self.setInformation(catalog.i18nc("@warning:status", "Please prepare G-code before exporting."))
return False return False
def _createFlattenedContainerInstance(self, instance_container1, instance_container2):
"""Create a new container with container 2 as base and container 1 written over it."""
flat_container = InstanceContainer(instance_container2.getName())
# The metadata includes id, name and definition
flat_container.setMetaData(copy.deepcopy(instance_container2.getMetaData()))
if instance_container1.getDefinition():
flat_container.setDefinition(instance_container1.getDefinition().getId())
for key in instance_container2.getAllKeys():
flat_container.setProperty(key, "value", instance_container2.getProperty(key, "value"))
for key in instance_container1.getAllKeys():
flat_container.setProperty(key, "value", instance_container1.getProperty(key, "value"))
return flat_container
def _serialiseSettings(self, stack): def _serialiseSettings(self, stack):
"""Serialises a container stack to prepare it for writing at the end of the g-code. """Serialises a container stack to prepare it for writing at the end of the g-code.
@ -145,22 +127,22 @@ class GCodeWriter(MeshWriter):
container_with_profile.setDefinition(machine_definition_id_for_quality) container_with_profile.setDefinition(machine_definition_id_for_quality)
container_with_profile.setMetaDataEntry("setting_version", stack.quality.getMetaDataEntry("setting_version")) container_with_profile.setMetaDataEntry("setting_version", stack.quality.getMetaDataEntry("setting_version"))
flat_global_container = self._createFlattenedContainerInstance(stack.userChanges, container_with_profile) merged_global_instance_container = InstanceContainer.createMergedInstanceContainer(stack.userChanges, container_with_profile)
# If the quality changes is not set, we need to set type manually # If the quality changes is not set, we need to set type manually
if flat_global_container.getMetaDataEntry("type", None) is None: if merged_global_instance_container.getMetaDataEntry("type", None) is None:
flat_global_container.setMetaDataEntry("type", "quality_changes") merged_global_instance_container.setMetaDataEntry("type", "quality_changes")
# Ensure that quality_type is set. (Can happen if we have empty quality changes). # Ensure that quality_type is set. (Can happen if we have empty quality changes).
if flat_global_container.getMetaDataEntry("quality_type", None) is None: if merged_global_instance_container.getMetaDataEntry("quality_type", None) is None:
flat_global_container.setMetaDataEntry("quality_type", stack.quality.getMetaDataEntry("quality_type", "normal")) merged_global_instance_container.setMetaDataEntry("quality_type", stack.quality.getMetaDataEntry("quality_type", "normal"))
# Get the machine definition ID for quality profiles # Get the machine definition ID for quality profiles
flat_global_container.setMetaDataEntry("definition", machine_definition_id_for_quality) merged_global_instance_container.setMetaDataEntry("definition", machine_definition_id_for_quality)
serialized = flat_global_container.serialize() serialized = merged_global_instance_container.serialize()
data = {"global_quality": serialized} data = {"global_quality": serialized}
all_setting_keys = flat_global_container.getAllKeys() all_setting_keys = merged_global_instance_container.getAllKeys()
for extruder in stack.extruderList: for extruder in stack.extruderList:
extruder_quality = extruder.qualityChanges extruder_quality = extruder.qualityChanges
if extruder_quality.getId() == "empty_quality_changes": if extruder_quality.getId() == "empty_quality_changes":
@ -174,7 +156,7 @@ class GCodeWriter(MeshWriter):
extruder_quality.setDefinition(machine_definition_id_for_quality) extruder_quality.setDefinition(machine_definition_id_for_quality)
extruder_quality.setMetaDataEntry("setting_version", stack.quality.getMetaDataEntry("setting_version")) extruder_quality.setMetaDataEntry("setting_version", stack.quality.getMetaDataEntry("setting_version"))
flat_extruder_quality = self._createFlattenedContainerInstance(extruder.userChanges, extruder_quality) flat_extruder_quality = InstanceContainer.createMergedInstanceContainer(extruder.userChanges, extruder_quality)
# If the quality changes is not set, we need to set type manually # If the quality changes is not set, we need to set type manually
if flat_extruder_quality.getMetaDataEntry("type", None) is None: if flat_extruder_quality.getMetaDataEntry("type", None) is None:
flat_extruder_quality.setMetaDataEntry("type", "quality_changes") flat_extruder_quality.setMetaDataEntry("type", "quality_changes")

View File

@ -1,6 +1,6 @@
# Copyright (c) 2021 Ultimaker B.V. # Copyright (c) 2022 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.
import json
from typing import cast, List, Dict from typing import cast, List, Dict
from Charon.VirtualFile import VirtualFile # To open UFP files. from Charon.VirtualFile import VirtualFile # To open UFP files.
@ -10,6 +10,7 @@ from io import StringIO # For converting g-code to bytes.
from PyQt6.QtCore import QBuffer from PyQt6.QtCore import QBuffer
from UM.Application import Application
from UM.Logger import Logger from UM.Logger import Logger
from UM.Mesh.MeshWriter import MeshWriter # The writer we need to implement. from UM.Mesh.MeshWriter import MeshWriter # The writer we need to implement.
from UM.MimeTypeDatabase import MimeTypeDatabase, MimeType from UM.MimeTypeDatabase import MimeTypeDatabase, MimeType
@ -17,12 +18,16 @@ from UM.PluginRegistry import PluginRegistry # To get the g-code writer.
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
from UM.Scene.SceneNode import SceneNode from UM.Scene.SceneNode import SceneNode
from UM.Settings.InstanceContainer import InstanceContainer
from cura.CuraApplication import CuraApplication from cura.CuraApplication import CuraApplication
from cura.Settings.CuraStackBuilder import CuraStackBuilder
from cura.Settings.GlobalStack import GlobalStack
from cura.Utils.Threading import call_on_qt_thread from cura.Utils.Threading import call_on_qt_thread
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
METADATA_OBJECTS_PATH = "metadata/objects" METADATA_OBJECTS_PATH = "metadata/objects"
SLICE_METADATA_PATH = "Cura/slicemetadata.json"
catalog = i18nCatalog("cura") catalog = i18nCatalog("cura")
@ -67,7 +72,21 @@ class UFPWriter(MeshWriter):
try: try:
gcode = archive.getStream("/3D/model.gcode") gcode = archive.getStream("/3D/model.gcode")
gcode.write(gcode_textio.getvalue().encode("UTF-8")) gcode.write(gcode_textio.getvalue().encode("UTF-8"))
archive.addRelation(virtual_path = "/3D/model.gcode", relation_type = "http://schemas.ultimaker.org/package/2018/relationships/gcode") archive.addRelation(virtual_path = "/3D/model.gcode",
relation_type = "http://schemas.ultimaker.org/package/2018/relationships/gcode")
except EnvironmentError as e:
error_msg = catalog.i18nc("@info:error", "Can't write to UFP file:") + " " + str(e)
self.setInformation(error_msg)
Logger.error(error_msg)
return False
# Write settings
try:
archive.addContentType(extension="json", mime_type="application/json")
setting_textio = StringIO()
json.dump(self._getSliceMetadata(), setting_textio, separators=(", ", ": "), indent=4)
steam = archive.getStream(SLICE_METADATA_PATH)
steam.write(setting_textio.getvalue().encode("UTF-8"))
except EnvironmentError as e: except EnvironmentError as e:
error_msg = catalog.i18nc("@info:error", "Can't write to UFP file:") + " " + str(e) error_msg = catalog.i18nc("@info:error", "Can't write to UFP file:") + " " + str(e)
self.setInformation(error_msg) self.setInformation(error_msg)
@ -190,3 +209,47 @@ class UFPWriter(MeshWriter):
return [{"name": item.getName()} return [{"name": item.getName()}
for item in DepthFirstIterator(node) for item in DepthFirstIterator(node)
if item.getMeshData() is not None and not item.callDecoration("isNonPrintingMesh")] if item.getMeshData() is not None and not item.callDecoration("isNonPrintingMesh")]
def _getSliceMetadata(self) -> Dict[str, Dict[str, Dict[str, str]]]:
"""Get all changed settings and all settings. For each extruder and the global stack"""
print_information = CuraApplication.getInstance().getPrintInformation()
settings = {
"material": {
"length": print_information.materialLengths,
"weight": print_information.materialWeights,
"cost": print_information.materialCosts,
},
"global": {
"changes": {},
"all_settings": {},
}
}
global_stack = cast(GlobalStack, Application.getInstance().getGlobalContainerStack())
# Add global user or quality changes
global_flattened_changes = InstanceContainer.createMergedInstanceContainer(global_stack.userChanges, global_stack.qualityChanges)
for setting in global_flattened_changes.getAllKeys():
settings["global"]["changes"][setting] = global_flattened_changes.getProperty(setting, "value")
# Get global all settings values without user or quality changes
for setting in global_stack.getAllKeys():
settings["global"]["all_settings"][setting] = global_stack.getProperty(setting, "value")
for i, extruder in enumerate(global_stack.extruderList):
# Add extruder fields to settings dictionary
settings[f"extruder_{i}"] = {
"changes": {},
"all_settings": {},
}
# Add extruder user or quality changes
extruder_flattened_changes = InstanceContainer.createMergedInstanceContainer(extruder.userChanges, extruder.qualityChanges)
for setting in extruder_flattened_changes.getAllKeys():
settings[f"extruder_{i}"]["changes"][setting] = extruder_flattened_changes.getProperty(setting, "value")
# Get extruder all settings values without user or quality changes
for setting in extruder.getAllKeys():
settings[f"extruder_{i}"]["all_settings"][setting] = extruder.getProperty(setting, "value")
return settings