Browse Source

Merge branch '5.7' into add_cad_plugin

Saumya Jain 1 year ago
parent
commit
b920c7934b

+ 2 - 1
cura/OAuth2/AuthorizationService.py

@@ -305,7 +305,8 @@ class AuthorizationService:
                                                                        message_type = Message.MessageType.ERROR)
                             Logger.warning("Unable to get user profile using auth data from preferences.")
                             self._unable_to_get_data_message.show()
-                self.getUserProfile(callback)
+                if self._get_user_profile:
+                    self.getUserProfile(callback)
         except (ValueError, TypeError):
             Logger.logException("w", "Could not load auth data from preferences")
 

+ 18 - 19
cura/PrinterOutput/Models/MaterialOutputModel.py

@@ -10,8 +10,8 @@ class MaterialOutputModel(QObject):
     def __init__(self, guid: Optional[str], type: str, color: str, brand: str, name: str, parent = None) -> None:
         super().__init__(parent)
 
-        name, guid = MaterialOutputModel.getMaterialFromDefinition(guid,type, brand, name)
-        self._guid =guid
+        name, guid = MaterialOutputModel.getMaterialFromDefinition(guid, type, brand, name)
+        self._guid = guid
         self._type = type
         self._color = color
         self._brand = brand
@@ -24,23 +24,22 @@ class MaterialOutputModel(QObject):
     @staticmethod
     def getMaterialFromDefinition(guid, type, brand, name):
 
-        _MATERIAL_MAP = {	"abs" 		:{"name" :"abs_175"       ,"guid": "2780b345-577b-4a24-a2c5-12e6aad3e690"},
-                            "abs-wss1"	:{"name" :"absr_175"      ,"guid": "88c8919c-6a09-471a-b7b6-e801263d862d"},
-                            "asa" 		:{"name" :"asa_175"       ,"guid": "416eead4-0d8e-4f0b-8bfc-a91a519befa5"},
-                            "nylon-cf" 	:{"name" :"cffpa_175"     ,"guid": "85bbae0e-938d-46fb-989f-c9b3689dc4f0"},
-                             "nylon12-cf": {"name": "nylon12-cf_175", "guid": "3c6f2877-71cc-4760-84e6-4b89ab243e3b"},
-                            "nylon"		:{"name" :"nylon_175"     ,"guid": "283d439a-3490-4481-920c-c51d8cdecf9c"},
-                            "pc"		:{"name" :"pc_175"        ,"guid": "62414577-94d1-490d-b1e4-7ef3ec40db02"},
-                            "petg"		:{"name" :"petg_175"      ,"guid": "69386c85-5b6c-421a-bec5-aeb1fb33f060"},
-                            "pla" 		:{"name" :"pla_175"       ,"guid": "0ff92885-617b-4144-a03c-9989872454bc"},
-                            "pva"		:{"name" :"pva_175"       ,"guid": "a4255da2-cb2a-4042-be49-4a83957a2f9a"},
-                            "wss1"		:{"name" :"rapidrinse_175","guid": "a140ef8f-4f26-4e73-abe0-cfc29d6d1024"},
-                            "sr30"		:{"name" :"sr30_175"      ,"guid": "77873465-83a9-4283-bc44-4e542b8eb3eb"},
-                            "im-pla"    :{"name" :"tough_pla_175" ,"guid": "96fca5d9-0371-4516-9e96-8e8182677f3c"},
-                            "bvoh"		:{"name" :"bvoh_175"      ,"guid": "923e604c-8432-4b09-96aa-9bbbd42207f4"},
-                            "cpe"		:{"name" :"cpe_175"       ,"guid": "da1872c1-b991-4795-80ad-bdac0f131726"},
-                            "hips"		:{"name" :"hips_175"      ,"guid": "a468d86a-220c-47eb-99a5-bbb47e514eb0"},
-                            "tpu"		:{"name" :"tpu_175"       ,"guid": "19baa6a9-94ff-478b-b4a1-8157b74358d2"}
+        _MATERIAL_MAP = {	"abs"       :{"name" :"ABS"           ,"guid": "2780b345-577b-4a24-a2c5-12e6aad3e690"},
+                             "abs-cf10": {"name": "ABS-CF", "guid": "495a0ce5-9daf-4a16-b7b2-06856d82394d"},
+                            "abs-wss1"  :{"name" :"ABS-R"         ,"guid": "88c8919c-6a09-471a-b7b6-e801263d862d"},
+                            "asa"       :{"name" :"ASA"           ,"guid": "416eead4-0d8e-4f0b-8bfc-a91a519befa5"},
+                            "nylon12-cf":{"name": "Nylon 12 CF"   ,"guid": "3c6f2877-71cc-4760-84e6-4b89ab243e3b"},
+                            "nylon"     :{"name" :"Nylon"         ,"guid": "283d439a-3490-4481-920c-c51d8cdecf9c"},
+                            "pc"        :{"name" :"PC"            ,"guid": "62414577-94d1-490d-b1e4-7ef3ec40db02"},
+                            "petg"      :{"name" :"PETG"          ,"guid": "69386c85-5b6c-421a-bec5-aeb1fb33f060"},
+                            "pla"       :{"name" :"PLA"           ,"guid": "0ff92885-617b-4144-a03c-9989872454bc"},
+                            "pva"       :{"name" :"PVA"           ,"guid": "a4255da2-cb2a-4042-be49-4a83957a2f9a"},
+                            "wss1"      :{"name" :"RapidRinse"    ,"guid": "a140ef8f-4f26-4e73-abe0-cfc29d6d1024"},
+                            "sr30"      :{"name" :"SR-30"         ,"guid": "77873465-83a9-4283-bc44-4e542b8eb3eb"},
+                            "bvoh"      :{"name" :"BVOH"          ,"guid": "923e604c-8432-4b09-96aa-9bbbd42207f4"},
+                            "cpe"       :{"name" :"CPE"           ,"guid": "da1872c1-b991-4795-80ad-bdac0f131726"},
+                            "hips"      :{"name" :"HIPS"          ,"guid": "a468d86a-220c-47eb-99a5-bbb47e514eb0"},
+                            "tpu"       :{"name" :"TPU 95A"       ,"guid": "19baa6a9-94ff-478b-b4a1-8157b74358d2"}
                         }
 
 

+ 38 - 22
cura/Snapshot.py

@@ -21,23 +21,31 @@ from UM.Scene.SceneNode import SceneNode
 from UM.Qt.QtRenderer import QtRenderer
 
 class Snapshot:
+
+    DEFAULT_WIDTH_HEIGHT = 300
+    MAX_RENDER_DISTANCE = 10000
+    BOUND_BOX_FACTOR = 1.75
+    CAMERA_FOVY = 30
+    ATTEMPTS_FOR_SNAPSHOT = 10
+
     @staticmethod
-    def getImageBoundaries(image: QImage):
-        # Look at the resulting image to get a good crop.
-        # Get the pixels as byte array
+    def getNonZeroPixels(image: QImage):
         pixel_array = image.bits().asarray(image.sizeInBytes())
         width, height = image.width(), image.height()
-        # Convert to numpy array, assume it's 32 bit (it should always be)
         pixels = numpy.frombuffer(pixel_array, dtype=numpy.uint8).reshape([height, width, 4])
         # Find indices of non zero pixels
-        nonzero_pixels = numpy.nonzero(pixels)
+        return numpy.nonzero(pixels)
+
+    @staticmethod
+    def getImageBoundaries(image: QImage):
+        nonzero_pixels = Snapshot.getNonZeroPixels(image)
         min_y, min_x, min_a_ = numpy.amin(nonzero_pixels, axis=1)  # type: ignore
         max_y, max_x, max_a_ = numpy.amax(nonzero_pixels, axis=1)  # type: ignore
 
         return min_x, max_x, min_y, max_y
 
     @staticmethod
-    def isometricSnapshot(width: int = 300, height: int = 300, *, node: Optional[SceneNode] = None) -> Optional[QImage]:
+    def isometricSnapshot(width: int = DEFAULT_WIDTH_HEIGHT, height: int = DEFAULT_WIDTH_HEIGHT, *, node: Optional[SceneNode] = None) -> Optional[QImage]:
         """
         Create an isometric snapshot of the scene.
 
@@ -92,8 +100,8 @@ class Snapshot:
             camera_width / 2,
             -camera_height / 2,
             camera_height / 2,
-            -10000,
-            10000
+            -Snapshot.MAX_RENDER_DISTANCE,
+            Snapshot.MAX_RENDER_DISTANCE
         )
         camera.setPerspective(False)
         camera.setProjectionMatrix(ortho_matrix)
@@ -112,22 +120,25 @@ class Snapshot:
 
         return render_pass.getOutput()
 
+    @staticmethod
+    def isNodeRenderable(node):
+        return not getattr(node, "_outside_buildarea", False) and node.callDecoration(
+            "isSliceable") and node.getMeshData() and node.isVisible() and not node.callDecoration(
+            "isNonThumbnailVisibleMesh")
+
     @staticmethod
     def nodeBounds(root_node: SceneNode) -> Optional[AxisAlignedBox]:
         axis_aligned_box = None
         for node in DepthFirstIterator(root_node):
-            if not getattr(node, "_outside_buildarea", False):
-                if node.callDecoration(
-                        "isSliceable") and node.getMeshData() and node.isVisible() and not node.callDecoration(
-                        "isNonThumbnailVisibleMesh"):
-                    if axis_aligned_box is None:
-                        axis_aligned_box = node.getBoundingBox()
-                    else:
-                        axis_aligned_box = axis_aligned_box + node.getBoundingBox()
+            if Snapshot.isNodeRenderable(node):
+                if axis_aligned_box is None:
+                    axis_aligned_box = node.getBoundingBox()
+                else:
+                    axis_aligned_box = axis_aligned_box + node.getBoundingBox()
         return axis_aligned_box
 
     @staticmethod
-    def snapshot(width = 300, height = 300):
+    def snapshot(width = DEFAULT_WIDTH_HEIGHT, height = DEFAULT_WIDTH_HEIGHT, number_of_attempts = ATTEMPTS_FOR_SNAPSHOT):
         """Return a QImage of the scene
 
         Uses PreviewPass that leaves out some elements Aspect ratio assumes a square
@@ -163,13 +174,13 @@ class Snapshot:
         looking_from_offset = Vector(-1, 1, 2)
         if size > 0:
             # determine the watch distance depending on the size
-            looking_from_offset = looking_from_offset * size * 1.75
+            looking_from_offset = looking_from_offset * size * Snapshot.BOUND_BOX_FACTOR
         camera.setPosition(look_at + looking_from_offset)
         camera.lookAt(look_at)
 
         satisfied = False
         size = None
-        fovy = 30
+        fovy = Snapshot.CAMERA_FOVY
 
         while not satisfied:
             if size is not None:
@@ -184,9 +195,14 @@ class Snapshot:
             pixel_output = preview_pass.getOutput()
             try:
                 min_x, max_x, min_y, max_y = Snapshot.getImageBoundaries(pixel_output)
-            except (ValueError, AttributeError):
-                Logger.logException("w", "Failed to crop the snapshot!")
-                return None
+            except (ValueError, AttributeError) as e:
+                if number_of_attempts == 0:
+                    Logger.warning( f"Failed to crop the snapshot even after {Snapshot.ATTEMPTS_FOR_SNAPSHOT} attempts!")
+                    return None
+                else:
+                    number_of_attempts = number_of_attempts - 1
+                    Logger.info("Trying to get the snapshot again.")
+                    return Snapshot.snapshot(width, height, number_of_attempts)
 
             size = max((max_x - min_x) / render_width, (max_y - min_y) / render_height)
             if size > 0.5 or satisfied:

+ 0 - 4
plugins/3MFReader/ThreeMFWorkspaceReader.py

@@ -915,10 +915,6 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
 
                 # Prepare the machine
                 self._applyChangesToMachine(global_stack, extruder_stack_dict)
-            else:
-                # Just clear the settings now, so that we can change the active machine without conflicts
-                self._clearMachineSettings(global_stack, {})
-
 
             Logger.log("d", "Workspace loading is notifying rest of the code of changes...")
             # Actually change the active machine.

+ 43 - 42
plugins/3MFReader/WorkspaceDialog.qml

@@ -12,7 +12,7 @@ import Cura 1.1 as Cura
 UM.Dialog
 {
     id: workspaceDialog
-    title: manager.isUcp? catalog.i18nc("@title:window", "Open Universal Cura Project (UCP)"): catalog.i18nc("@title:window", "Open Project")
+    title: manager.isUcp? catalog.i18nc("@title:window Don't translate 'Universal Cura Project'", "Open Universal Cura Project (UCP)"): catalog.i18nc("@title:window", "Open Project")
 
     margin: UM.Theme.getSize("default_margin").width
     minimumWidth: UM.Theme.getSize("modal_window_minimum").width
@@ -28,7 +28,7 @@ UM.Dialog
         UM.Label
         {
             id: titleLabel
-            text: manager.isUcp? catalog.i18nc("@action:title", "Summary - Open Universal Cura Project (UCP)"): catalog.i18nc("@action:title", "Summary - Cura Project")
+            text: manager.isUcp? catalog.i18nc("@action:title Don't translate 'Universal Cura Project'", "Summary - Open Universal Cura Project (UCP)"): catalog.i18nc("@action:title", "Summary - Cura Project")
             font: UM.Theme.getFont("large")
             anchors.top: parent.top
             anchors.left: parent.left
@@ -156,46 +156,6 @@ UM.Dialog
                     }
                 }
 
-                WorkspaceSection
-                {
-                    id: profileSection
-                    title: manager.isUcp? catalog.i18nc("@action:label", "Suggested Profile settings"):catalog.i18nc("@action:label", "Profile settings")
-                    iconSource: UM.Theme.getIcon("Sliders")
-                    content: Column
-                    {
-                        id: profileSettingsValuesTable
-                        spacing: UM.Theme.getSize("default_margin").height
-                        leftPadding: UM.Theme.getSize("medium_button_icon").width + UM.Theme.getSize("default_margin").width
-
-                        WorkspaceRow
-                        {
-                            leftLabelText: catalog.i18nc("@action:label", "Name")
-                            rightLabelText: manager.qualityName
-                            visible: manager.isCompatibleMachine
-                        }
-
-                        WorkspaceRow
-                        {
-                            leftLabelText: catalog.i18nc("@action:label", "Intent")
-                            rightLabelText: manager.intentName
-                            visible: manager.isCompatibleMachine
-                        }
-
-                        WorkspaceRow
-                        {
-                            leftLabelText: catalog.i18nc("@action:label", "Not in profile")
-                            rightLabelText: catalog.i18ncp("@action:label", "%1 override", "%1 overrides", manager.numUserSettings).arg(manager.numUserSettings)
-                            visible: manager.numUserSettings != 0 && manager.isCompatibleMachine
-                        }
-
-                        WorkspaceRow
-                        {
-                            leftLabelText: catalog.i18nc("@action:label", "Derivative from")
-                            rightLabelText: catalog.i18ncp("@action:label", "%1, %2 override", "%1, %2 overrides", manager.numSettingsOverridenByQualityChanges).arg(manager.qualityType).arg(manager.numSettingsOverridenByQualityChanges)
-                            visible: manager.numSettingsOverridenByQualityChanges != 0 && manager.isCompatibleMachine
-                        }
-                    }
-                }
                 WorkspaceSection
                 {
                     id: ucpProfileSection
@@ -279,6 +239,47 @@ UM.Dialog
                     }
                 }
 
+                WorkspaceSection
+                {
+                    id: profileSection
+                    title: manager.isUcp? catalog.i18nc("@action:label", "Suggested Profile settings"):catalog.i18nc("@action:label", "Profile settings")
+                    iconSource: UM.Theme.getIcon("Sliders")
+                    content: Column
+                    {
+                        id: profileSettingsValuesTable
+                        spacing: UM.Theme.getSize("default_margin").height
+                        leftPadding: UM.Theme.getSize("medium_button_icon").width + UM.Theme.getSize("default_margin").width
+
+                        WorkspaceRow
+                        {
+                            leftLabelText: catalog.i18nc("@action:label", "Name")
+                            rightLabelText: manager.qualityName
+                            visible: manager.isCompatibleMachine
+                        }
+
+                        WorkspaceRow
+                        {
+                            leftLabelText: catalog.i18nc("@action:label", "Intent")
+                            rightLabelText: manager.intentName
+                            visible: manager.isCompatibleMachine
+                        }
+
+                        WorkspaceRow
+                        {
+                            leftLabelText: catalog.i18nc("@action:label", "Not in profile")
+                            rightLabelText: catalog.i18ncp("@action:label", "%1 override", "%1 overrides", manager.numUserSettings).arg(manager.numUserSettings)
+                            visible: manager.numUserSettings != 0 && !manager.isUcp
+                        }
+
+                        WorkspaceRow
+                        {
+                            leftLabelText: catalog.i18nc("@action:label", "Derivative from")
+                            rightLabelText: catalog.i18ncp("@action:label", "%1, %2 override", "%1, %2 overrides", manager.numSettingsOverridenByQualityChanges).arg(manager.qualityType).arg(manager.numSettingsOverridenByQualityChanges)
+                            visible: manager.numSettingsOverridenByQualityChanges != 0 && manager.isCompatibleMachine
+                        }
+                    }
+                }
+
                 WorkspaceSection
                 {
                     id: materialSection

+ 3 - 3
plugins/3MFWriter/SettingSelection.qml

@@ -19,7 +19,7 @@ RowLayout
         Layout.preferredWidth: UM.Theme.getSize("setting").width
         checked: modelData.selected
         onClicked: modelData.selected = checked
-        tooltip: modelData.selectable ? "" :catalog.i18nc("@tooltip", "This setting may not perform well while exporting to UCP. Users are asked to add it at their own risk.")
+        tooltip: modelData.selectable ? "" :catalog.i18nc("@tooltip Don't translate 'Universal Cura Project'", "This setting may not perform well while exporting to Universal Cura Project. Users are asked to add it at their own risk.")
     }
 
     UM.Label
@@ -30,8 +30,8 @@ RowLayout
     UM.HelpIcon
     {
         UM.I18nCatalog { id: catalog; name: "cura" }
-        text: catalog.i18nc("@tooltip",
-                            "This setting may not perform well while exporting to UCP, Users are asked to add it at their own risk.")
+        text: catalog.i18nc("@tooltip Don't translate 'Universal Cura Project'",
+                            "This setting may not perform well while exporting to Universal Cura Project, Users are asked to add it at their own risk.")
         visible: !modelData.selectable
     }
 

+ 4 - 0
plugins/3MFWriter/ThreeMFWriter.py

@@ -2,6 +2,7 @@
 #  Cura is released under the terms of the LGPLv3 or higher.
 import json
 import re
+import threading
 
 from typing import Optional, cast, List, Dict, Pattern, Set
 
@@ -65,6 +66,7 @@ class ThreeMFWriter(MeshWriter):
         self._unit_matrix_string = ThreeMFWriter._convertMatrixToString(Matrix())
         self._archive: Optional[zipfile.ZipFile] = None
         self._store_archive = False
+        self._lock = threading.Lock()
 
     @staticmethod
     def _convertMatrixToString(matrix):
@@ -423,6 +425,7 @@ class ThreeMFWriter(MeshWriter):
     @call_on_qt_thread  # must be called from the main thread because of OpenGL
     def _createSnapshot(self):
         Logger.log("d", "Creating thumbnail image...")
+        self._lock.acquire()
         if not CuraApplication.getInstance().isVisible:
             Logger.log("w", "Can't create snapshot when renderer not initialized.")
             return None
@@ -431,6 +434,7 @@ class ThreeMFWriter(MeshWriter):
         except:
             Logger.logException("w", "Failed to create snapshot image")
             return None
+        finally: self._lock.release()
 
         return snapshot
 

+ 2 - 2
plugins/3MFWriter/UCPDialog.py

@@ -75,9 +75,9 @@ class UCPDialog(QObject):
             device.requestWrite(
                 nodes,
                 file_name,
-                ["application/vnd.ms-package.3dmanufacturing-3dmodel+xml"],
+                ["application/x-ucp"],
                 workspace_handler,
-                preferred_mimetype_list="application/vnd.ms-package.3dmanufacturing-3dmodel+xml"
+                preferred_mimetype_list="application/x-ucp"
             )
         except OutputDeviceError.UserCanceledError:
             self._onRejected()

+ 3 - 3
plugins/3MFWriter/UCPDialog.qml

@@ -12,7 +12,7 @@ import Cura 1.1 as Cura
 UM.Dialog
 {
     id: exportDialog
-    title: catalog.i18nc("@title:window", "Export Universal Cura Project")
+    title: catalog.i18nc("@title:window Don't translate 'Universal Cura Project'", "Export Universal Cura Project")
 
     margin: UM.Theme.getSize("default_margin").width
     minimumWidth: UM.Theme.getSize("modal_window_minimum").width
@@ -39,14 +39,14 @@ UM.Dialog
             UM.Label
             {
                 id: titleLabel
-                text: catalog.i18nc("@action:title", "Summary - Universal Cura Project")
+                text: catalog.i18nc("@action:title Don't translate 'Universal Cura Project'", "Summary - Universal Cura Project")
                 font: UM.Theme.getFont("large")
             }
 
             UM.Label
             {
                 id: descriptionLabel
-                text: catalog.i18nc("@action:description", "Universal Cura Project files can be printed on different 3D printers while retaining positional data and selected settings. When exported, all models present on the build plate will be included along with their current position, orientation, and scale. You can also select which per-extruder or per-model settings should be included to ensure proper printing.")
+                text: catalog.i18nc("@action:description Don't translate 'Universal Cura Project'", "Universal Cura Project files can be printed on different 3D printers while retaining positional data and selected settings. When exported, all models present on the build plate will be included along with their current position, orientation, and scale. You can also select which per-extruder or per-model settings should be included to ensure proper printing.")
                 font: UM.Theme.getFont("default")
                 wrapMode: Text.Wrap
                 Layout.maximumWidth: headerColumn.width

+ 7 - 1
plugins/3MFWriter/__init__.py

@@ -32,7 +32,7 @@ def getMetaData():
                     "description": i18n_catalog.i18nc("@item:inlistbox", "3MF file"),
                     "mime_type": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml",
                     "mode": ThreeMFWriter.ThreeMFWriter.OutputMode.BinaryMode
-                }
+                },
             ]
         }
         metaData["workspace_writer"] = {
@@ -42,6 +42,12 @@ def getMetaData():
                     "description": i18n_catalog.i18nc("@item:inlistbox", "Cura Project 3MF file"),
                     "mime_type": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml",
                     "mode": ThreeMFWorkspaceWriter.ThreeMFWorkspaceWriter.OutputMode.BinaryMode
+                },
+                {
+                    "extension": "3mf",
+                    "description": i18n_catalog.i18nc("@item:inlistbox", "Universal Cura Project"),
+                    "mime_type": "application/x-ucp",
+                    "mode": ThreeMFWorkspaceWriter.ThreeMFWorkspaceWriter.OutputMode.BinaryMode
                 }
             ]
         }

Some files were not shown because too many files changed in this diff