From 4f9d041ae84206c4ad3f7d2c6f01912965d57890 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Thu, 11 May 2023 16:14:38 +0200 Subject: [PATCH 01/25] Add rotation lock in arrange and multiply objects Add rotation lock in - context menu item arrange and - checkbox in multiply objects dialog CURA-7951 --- cura/Arranging/ArrangeObjectsJob.py | 7 +++-- cura/Arranging/Nest2DArrange.py | 36 ++++++++++++++++------- cura/CuraActions.py | 10 ++++--- cura/CuraApplication.py | 11 ++++---- cura/MultiplyObjectsJob.py | 14 +++++---- resources/qml/Actions.qml | 20 +++++++++++-- resources/qml/Menus/ContextMenu.qml | 44 ++++++++++++++++++----------- 7 files changed, 97 insertions(+), 45 deletions(-) diff --git a/cura/Arranging/ArrangeObjectsJob.py b/cura/Arranging/ArrangeObjectsJob.py index 6ba6717191..f938b44d1f 100644 --- a/cura/Arranging/ArrangeObjectsJob.py +++ b/cura/Arranging/ArrangeObjectsJob.py @@ -14,11 +14,13 @@ i18n_catalog = i18nCatalog("cura") class ArrangeObjectsJob(Job): - def __init__(self, nodes: List[SceneNode], fixed_nodes: List[SceneNode], min_offset = 8) -> None: + def __init__(self, nodes: List[SceneNode], fixed_nodes: List[SceneNode], min_offset=8, + lock_rotation: bool = False) -> None: super().__init__() self._nodes = nodes self._fixed_nodes = fixed_nodes self._min_offset = min_offset + self._lock_rotation = lock_rotation def run(self): found_solution_for_all = False @@ -30,7 +32,8 @@ class ArrangeObjectsJob(Job): status_message.show() try: - found_solution_for_all = arrange(self._nodes, Application.getInstance().getBuildVolume(), self._fixed_nodes) + found_solution_for_all = arrange(self._nodes, Application.getInstance().getBuildVolume(), self._fixed_nodes, + lock_rotation=self._lock_rotation) except: # If the thread crashes, the message should still close Logger.logException("e", "Unable to arrange the objects on the buildplate. The arrange algorithm has crashed.") diff --git a/cura/Arranging/Nest2DArrange.py b/cura/Arranging/Nest2DArrange.py index 21427f1194..8921c9ede2 100644 --- a/cura/Arranging/Nest2DArrange.py +++ b/cura/Arranging/Nest2DArrange.py @@ -22,7 +22,13 @@ if TYPE_CHECKING: from cura.BuildVolume import BuildVolume -def findNodePlacement(nodes_to_arrange: List["SceneNode"], build_volume: "BuildVolume", fixed_nodes: Optional[List["SceneNode"]] = None, factor = 10000) -> Tuple[bool, List[Item]]: +def findNodePlacement( + nodes_to_arrange: List["SceneNode"], + build_volume: "BuildVolume", + fixed_nodes: Optional[List["SceneNode"]] = None, + factor: int = 10000, + lock_rotation: bool = False +) -> Tuple[bool, List[Item]]: """ Find placement for a set of scene nodes, but don't actually move them just yet. :param nodes_to_arrange: The list of nodes that need to be moved. @@ -30,6 +36,7 @@ def findNodePlacement(nodes_to_arrange: List["SceneNode"], build_volume: "BuildV :param fixed_nodes: List of nods that should not be moved, but should be used when deciding where the others nodes are placed. :param factor: The library that we use is int based. This factor defines how accurate we want it to be. + :param lock_rotation: If set to true the orientation of the object will remain the same :return: tuple (found_solution_for_all, node_items) WHERE @@ -100,6 +107,8 @@ def findNodePlacement(nodes_to_arrange: List["SceneNode"], build_volume: "BuildV config = NfpConfig() config.accuracy = 1.0 config.alignment = NfpConfig.Alignment.DONT_ALIGN + if lock_rotation: + config.rotations = [0.0] num_bins = nest(node_items, build_plate_bounding_box, spacing, config) @@ -114,10 +123,12 @@ def findNodePlacement(nodes_to_arrange: List["SceneNode"], build_volume: "BuildV def createGroupOperationForArrange(nodes_to_arrange: List["SceneNode"], build_volume: "BuildVolume", fixed_nodes: Optional[List["SceneNode"]] = None, - factor = 10000, - add_new_nodes_in_scene: bool = False) -> Tuple[GroupedOperation, int]: + factor: int = 10000, + add_new_nodes_in_scene: bool = False, + lock_rotation: bool = False) -> Tuple[GroupedOperation, int]: scene_root = Application.getInstance().getController().getScene().getRoot() - found_solution_for_all, node_items = findNodePlacement(nodes_to_arrange, build_volume, fixed_nodes, factor) + found_solution_for_all, node_items = findNodePlacement(nodes_to_arrange, build_volume, fixed_nodes, factor, + lock_rotation) not_fit_count = 0 grouped_operation = GroupedOperation() @@ -141,11 +152,14 @@ def createGroupOperationForArrange(nodes_to_arrange: List["SceneNode"], return grouped_operation, not_fit_count -def arrange(nodes_to_arrange: List["SceneNode"], - build_volume: "BuildVolume", - fixed_nodes: Optional[List["SceneNode"]] = None, - factor = 10000, - add_new_nodes_in_scene: bool = False) -> bool: +def arrange( + nodes_to_arrange: List["SceneNode"], + build_volume: "BuildVolume", + fixed_nodes: Optional[List["SceneNode"]] = None, + factor=10000, + add_new_nodes_in_scene: bool = False, + lock_rotation: bool = False +) -> bool: """ Find placement for a set of scene nodes, and move them by using a single grouped operation. :param nodes_to_arrange: The list of nodes that need to be moved. @@ -154,10 +168,12 @@ def arrange(nodes_to_arrange: List["SceneNode"], are placed. :param factor: The library that we use is int based. This factor defines how accuracte we want it to be. :param add_new_nodes_in_scene: Whether to create new scene nodes before applying the transformations and rotations + :param lock_rotation: If set to true the orientation of the object will remain the same :return: found_solution_for_all: Whether the algorithm found a place on the buildplate for all the objects """ - grouped_operation, not_fit_count = createGroupOperationForArrange(nodes_to_arrange, build_volume, fixed_nodes, factor, add_new_nodes_in_scene) + grouped_operation, not_fit_count = createGroupOperationForArrange(nodes_to_arrange, build_volume, fixed_nodes, + factor, add_new_nodes_in_scene, lock_rotation) grouped_operation.push() return not_fit_count == 0 diff --git a/cura/CuraActions.py b/cura/CuraActions.py index 193803325f..fed57c8500 100644 --- a/cura/CuraActions.py +++ b/cura/CuraActions.py @@ -75,19 +75,21 @@ class CuraActions(QObject): center_y = 0 # Move the object so that it's bottom is on to of the buildplate - center_operation = TranslateOperation(current_node, Vector(0, center_y, 0), set_position = True) + center_operation = TranslateOperation(current_node, Vector(0, center_y, 0), set_position=True) operation.addOperation(center_operation) operation.push() - @pyqtSlot(int) - def multiplySelection(self, count: int) -> None: + @pyqtSlot(int, bool) + def multiplySelection(self, count: int, lock_rotation: bool) -> None: """Multiply all objects in the selection :param count: The number of times to multiply the selection. + :param lock_rotation: If set to true the orientation of the object will remain the same """ min_offset = cura.CuraApplication.CuraApplication.getInstance().getBuildVolume().getEdgeDisallowedSize() + 2 # Allow for some rounding errors - job = MultiplyObjectsJob(Selection.getAllSelectedObjects(), count, min_offset = max(min_offset, 8)) + job = MultiplyObjectsJob(Selection.getAllSelectedObjects(), count, min_offset=max(min_offset, 8), + lock_rotation=lock_rotation) job.start() @pyqtSlot() diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 113e7b3ff4..15e7a60fcb 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -1421,8 +1421,8 @@ class CuraApplication(QtApplication): op.push() # Single build plate - @pyqtSlot() - def arrangeAll(self) -> None: + @pyqtSlot(bool) + def arrangeAll(self, lock_rotation: bool) -> None: nodes_to_arrange = [] active_build_plate = self.getMultiBuildPlateModel().activeBuildPlate locked_nodes = [] @@ -1452,17 +1452,18 @@ class CuraApplication(QtApplication): locked_nodes.append(node) else: nodes_to_arrange.append(node) - self.arrange(nodes_to_arrange, locked_nodes) + self.arrange(nodes_to_arrange, locked_nodes, lock_rotation) - def arrange(self, nodes: List[SceneNode], fixed_nodes: List[SceneNode]) -> None: + def arrange(self, nodes: List[SceneNode], fixed_nodes: List[SceneNode], lock_rotation: bool = False) -> None: """Arrange a set of nodes given a set of fixed nodes :param nodes: nodes that we have to place :param fixed_nodes: nodes that are placed in the arranger before finding spots for nodes + :param lock_rotation: If set to true the orientation of the object will remain the same """ min_offset = self.getBuildVolume().getEdgeDisallowedSize() + 2 # Allow for some rounding errors - job = ArrangeObjectsJob(nodes, fixed_nodes, min_offset = max(min_offset, 8)) + job = ArrangeObjectsJob(nodes, fixed_nodes, min_offset=max(min_offset, 8), lock_rotation=lock_rotation) job.start() @pyqtSlot() diff --git a/cura/MultiplyObjectsJob.py b/cura/MultiplyObjectsJob.py index 1446ae687e..ff4f362b4c 100644 --- a/cura/MultiplyObjectsJob.py +++ b/cura/MultiplyObjectsJob.py @@ -20,11 +20,12 @@ i18n_catalog = i18nCatalog("cura") class MultiplyObjectsJob(Job): - def __init__(self, objects, count, min_offset = 8): + def __init__(self, objects, count: int, min_offset: int = 8, lock_rotation: bool = False): super().__init__() self._objects = objects - self._count = count - self._min_offset = min_offset + self._count: int = count + self._min_offset: int = min_offset + self._lock_rotation: bool = lock_rotation def run(self) -> None: status_message = Message(i18n_catalog.i18nc("@info:status", "Multiplying and placing objects"), lifetime = 0, @@ -39,7 +40,7 @@ class MultiplyObjectsJob(Job): root = scene.getRoot() - processed_nodes = [] # type: List[SceneNode] + processed_nodes: List[SceneNode] = [] nodes = [] fixed_nodes = [] @@ -79,8 +80,9 @@ class MultiplyObjectsJob(Job): group_operation, not_fit_count = createGroupOperationForArrange(nodes, Application.getInstance().getBuildVolume(), fixed_nodes, - factor = 10000, - add_new_nodes_in_scene = True) + factor=10000, + add_new_nodes_in_scene=True, + lock_rotation=self._lock_rotation) found_solution_for_all = not_fit_count == 0 if nodes_to_add_without_arrange: diff --git a/resources/qml/Actions.qml b/resources/qml/Actions.qml index 6cd75b51ac..eb9f1c7f21 100644 --- a/resources/qml/Actions.qml +++ b/resources/qml/Actions.qml @@ -41,7 +41,9 @@ Item property alias deleteAll: deleteAllAction property alias reloadAll: reloadAllAction property alias arrangeAll: arrangeAllAction + property alias arrangeAllLock: arrangeAllLockAction property alias arrangeSelection: arrangeSelectionAction + property alias arrangeSelectionLock: arrangeSelectionLockAction property alias resetAllTranslation: resetAllTranslationAction property alias resetAll: resetAllAction @@ -412,15 +414,29 @@ Item { id: arrangeAllAction text: catalog.i18nc("@action:inmenu menubar:edit","Arrange All Models") - onTriggered: Printer.arrangeAll() + onTriggered: Printer.arrangeAll(false) shortcut: "Ctrl+R" } + Action + { + id: arrangeAllLockAction + text: catalog.i18nc("@action:inmenu menubar:edit","Arrange All Models Without Rotation") + onTriggered: Printer.arrangeAll(true) + } + Action { id: arrangeSelectionAction text: catalog.i18nc("@action:inmenu menubar:edit","Arrange Selection") - onTriggered: Printer.arrangeSelection() + onTriggered: Printer.arrangeSelection(false) + } + + Action + { + id: arrangeSelectionLockAction + text: catalog.i18nc("@action:inmenu menubar:edit","Arrange Selection Without Rotation") + onTriggered: Printer.arrangeSelection(true) } Action diff --git a/resources/qml/Menus/ContextMenu.qml b/resources/qml/Menus/ContextMenu.qml index 65f3409c8a..c327a37a2b 100644 --- a/resources/qml/Menus/ContextMenu.qml +++ b/resources/qml/Menus/ContextMenu.qml @@ -53,6 +53,7 @@ Cura.Menu Cura.MenuSeparator {} Cura.MenuItem { action: Cura.Actions.selectAll } Cura.MenuItem { action: Cura.Actions.arrangeAll } + Cura.MenuItem { action: Cura.Actions.arrangeAllLock } Cura.MenuItem { action: Cura.Actions.deleteAll } Cura.MenuItem { action: Cura.Actions.reloadAll } Cura.MenuItem { action: Cura.Actions.resetAllTranslation } @@ -96,7 +97,7 @@ Cura.Menu minimumWidth: UM.Theme.getSize("small_popup_dialog").width minimumHeight: UM.Theme.getSize("small_popup_dialog").height - onAccepted: CuraActions.multiplySelection(copiesField.value) + onAccepted: CuraActions.multiplySelection(copiesField.value, lockRotationField.checked) buttonSpacing: UM.Theme.getSize("thin_margin").width @@ -114,27 +115,38 @@ Cura.Menu } ] - Row + Column { - spacing: UM.Theme.getSize("default_margin").width + spacing: UM.Theme.getSize("default_margin").height - UM.Label + Row { - text: catalog.i18nc("@label", "Number of Copies") - anchors.verticalCenter: copiesField.verticalCenter - width: contentWidth - wrapMode: Text.NoWrap + spacing: UM.Theme.getSize("default_margin").width + + UM.Label + { + text: catalog.i18nc("@label", "Number of Copies") + anchors.verticalCenter: copiesField.verticalCenter + width: contentWidth + wrapMode: Text.NoWrap + } + + Cura.SpinBox + { + id: copiesField + editable: true + focus: true + from: 1 + to: 99 + width: 2 * UM.Theme.getSize("button").width + value: 1 + } } - Cura.SpinBox + UM.CheckBox { - id: copiesField - editable: true - focus: true - from: 1 - to: 99 - width: 2 * UM.Theme.getSize("button").width - value: 1 + id: lockRotationField + text: catalog.i18nc("@label", "Lock Rotation") } } } From d4c0f81719fae2af2117cb05b5c7aeab371f6654 Mon Sep 17 00:00:00 2001 From: casperlamboo Date: Thu, 11 May 2023 14:20:25 +0000 Subject: [PATCH 02/25] update translations --- resources/i18n/cs_CZ/cura.po | 139 +++-- resources/i18n/cura.pot | 1065 +++++++++++++++++----------------- resources/i18n/de_DE/cura.po | 139 +++-- resources/i18n/es_ES/cura.po | 139 +++-- resources/i18n/fi_FI/cura.po | 139 +++-- resources/i18n/fr_FR/cura.po | 139 +++-- resources/i18n/hu_HU/cura.po | 139 +++-- resources/i18n/it_IT/cura.po | 139 +++-- resources/i18n/ja_JP/cura.po | 139 +++-- resources/i18n/ko_KR/cura.po | 139 +++-- resources/i18n/nl_NL/cura.po | 139 +++-- resources/i18n/pl_PL/cura.po | 139 +++-- resources/i18n/pt_BR/cura.po | 139 +++-- resources/i18n/pt_PT/cura.po | 139 +++-- resources/i18n/ru_RU/cura.po | 139 +++-- resources/i18n/tr_TR/cura.po | 139 +++-- resources/i18n/zh_CN/cura.po | 139 +++-- resources/i18n/zh_TW/cura.po | 139 +++-- 18 files changed, 1849 insertions(+), 1579 deletions(-) diff --git a/resources/i18n/cs_CZ/cura.po b/resources/i18n/cs_CZ/cura.po index f20c8c2949..29109ae325 100644 --- a/resources/i18n/cs_CZ/cura.po +++ b/resources/i18n/cs_CZ/cura.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Cura 5.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-04-27 12:22+0000\n" +"POT-Creation-Date: 2023-05-11 14:19+0000\n" "PO-Revision-Date: 2023-02-16 20:28+0100\n" "Last-Translator: Miroslav Šustek \n" "Language-Team: DenyCZ \n" @@ -23,22 +23,22 @@ msgctxt "@info:title" msgid "Login failed" msgstr "Přihlášení selhalo" -#: cura/Arranging/ArrangeObjectsJob.py:25 +#: cura/Arranging/ArrangeObjectsJob.py:27 msgctxt "@info:status" msgid "Finding new location for objects" msgstr "Hledám nové umístění pro objekt" -#: cura/Arranging/ArrangeObjectsJob.py:29 +#: cura/Arranging/ArrangeObjectsJob.py:31 msgctxt "@info:title" msgid "Finding Location" msgstr "Hledám umístění" -#: cura/Arranging/ArrangeObjectsJob.py:42 cura/MultiplyObjectsJob.py:99 +#: cura/Arranging/ArrangeObjectsJob.py:45 cura/MultiplyObjectsJob.py:101 msgctxt "@info:status" msgid "Unable to find a location within the build volume for all objects" msgstr "Nemohu najít lokaci na podložce pro všechny objekty" -#: cura/Arranging/ArrangeObjectsJob.py:43 +#: cura/Arranging/ArrangeObjectsJob.py:46 msgctxt "@info:title" msgid "Can't Find Location" msgstr "Nemohu najít umístění" @@ -265,25 +265,25 @@ msgctxt "@info 'width', 'depth' and 'height' are variable names that must NOT be msgid "%(width).1f x %(depth).1f x %(height).1f mm" msgstr "%(width).1f x %(depth).1f x %(height).1f mm" -#: cura/CuraApplication.py:1816 +#: cura/CuraApplication.py:1817 #, python-brace-format msgctxt "@info:status" msgid "Only one G-code file can be loaded at a time. Skipped importing {0}" msgstr "Současně lze načíst pouze jeden soubor G-kódu. Přeskočen import {0}" -#: cura/CuraApplication.py:1818 cura/OAuth2/AuthorizationService.py:217 +#: cura/CuraApplication.py:1819 cura/OAuth2/AuthorizationService.py:217 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:189 msgctxt "@info:title" msgid "Warning" msgstr "Varování" -#: cura/CuraApplication.py:1828 +#: cura/CuraApplication.py:1829 #, python-brace-format msgctxt "@info:status" msgid "Can't open any other file if G-code is loading. Skipped importing {0}" msgstr "Nelze otevřít žádný jiný soubor, když se načítá G kód. Přeskočen import {0}" -#: cura/CuraApplication.py:1830 cura/Settings/CuraContainerRegistry.py:156 +#: cura/CuraApplication.py:1831 cura/Settings/CuraContainerRegistry.py:156 #: cura/Settings/CuraContainerRegistry.py:166 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:153 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:173 @@ -410,17 +410,17 @@ msgctxt "@info:status" msgid "Calculated" msgstr "Vypočítáno" -#: cura/MultiplyObjectsJob.py:30 +#: cura/MultiplyObjectsJob.py:31 msgctxt "@info:status" msgid "Multiplying and placing objects" msgstr "Násobím a rozmisťuji objekty" -#: cura/MultiplyObjectsJob.py:32 +#: cura/MultiplyObjectsJob.py:33 msgctxt "@info:title" msgid "Placing Objects" msgstr "Umisťuji objekty" -#: cura/MultiplyObjectsJob.py:100 +#: cura/MultiplyObjectsJob.py:102 msgctxt "@info:title" msgid "Placing Object" msgstr "Umisťuji objekt" @@ -3689,17 +3689,17 @@ msgctxt "@action:button" msgid "Remove printers" msgstr "Odstranit tiskárnu" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:62 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:63 msgctxt "@action:button Preceded by 'Ready to'." msgid "Print over network" msgstr "Tisk přes síť" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:63 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:64 msgctxt "@properties:tooltip" msgid "Print over network" msgstr "Tisk přes síť" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:64 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:65 msgctxt "@info:status" msgid "Connected over the network" msgstr "Připojeno přes síť" @@ -4241,227 +4241,237 @@ msgctxt "@button" msgid "Cancel" msgstr "Zrušit" -#: resources/qml/Actions.qml:81 +#: resources/qml/Actions.qml:83 msgctxt "@action:inmenu" msgid "Show Online Troubleshooting" msgstr "Zobrazit online řešení problémů" -#: resources/qml/Actions.qml:88 +#: resources/qml/Actions.qml:90 msgctxt "@action:inmenu" msgid "Toggle Full Screen" msgstr "Přepnout zobrazení na celou obrazovku" -#: resources/qml/Actions.qml:96 +#: resources/qml/Actions.qml:98 msgctxt "@action:inmenu" msgid "Exit Full Screen" msgstr "Ukončit zobrazení na celou obrazovku" -#: resources/qml/Actions.qml:103 +#: resources/qml/Actions.qml:105 msgctxt "@action:inmenu menubar:edit" msgid "&Undo" msgstr "&Vrátit" -#: resources/qml/Actions.qml:113 +#: resources/qml/Actions.qml:115 msgctxt "@action:inmenu menubar:edit" msgid "&Redo" msgstr "&Znovu" -#: resources/qml/Actions.qml:131 +#: resources/qml/Actions.qml:133 msgctxt "@action:inmenu menubar:file" msgid "&Quit" msgstr "&Ukončit" -#: resources/qml/Actions.qml:139 +#: resources/qml/Actions.qml:141 msgctxt "@action:inmenu menubar:view" msgid "3D View" msgstr "3D Pohled" -#: resources/qml/Actions.qml:146 +#: resources/qml/Actions.qml:148 msgctxt "@action:inmenu menubar:view" msgid "Front View" msgstr "Přední pohled" -#: resources/qml/Actions.qml:153 +#: resources/qml/Actions.qml:155 msgctxt "@action:inmenu menubar:view" msgid "Top View" msgstr "Pohled seshora" -#: resources/qml/Actions.qml:160 +#: resources/qml/Actions.qml:162 msgctxt "@action:inmenu menubar:view" msgid "Bottom View" msgstr "Pohled zezdola" -#: resources/qml/Actions.qml:167 +#: resources/qml/Actions.qml:169 msgctxt "@action:inmenu menubar:view" msgid "Left Side View" msgstr "Pohled z pravé strany" -#: resources/qml/Actions.qml:174 +#: resources/qml/Actions.qml:176 msgctxt "@action:inmenu menubar:view" msgid "Right Side View" msgstr "Pohled z pravé strany" -#: resources/qml/Actions.qml:188 +#: resources/qml/Actions.qml:190 msgctxt "@action:inmenu" msgid "Configure Cura..." msgstr "Konfigurovat Cura..." -#: resources/qml/Actions.qml:197 +#: resources/qml/Actions.qml:199 msgctxt "@action:inmenu menubar:printer" msgid "&Add Printer..." msgstr "Přidat t&iskárnu..." -#: resources/qml/Actions.qml:203 +#: resources/qml/Actions.qml:205 msgctxt "@action:inmenu menubar:printer" msgid "Manage Pr&inters..." msgstr "Spravovat &tiskárny..." -#: resources/qml/Actions.qml:210 +#: resources/qml/Actions.qml:212 msgctxt "@action:inmenu" msgid "Manage Materials..." msgstr "Spravovat materiály..." -#: resources/qml/Actions.qml:218 +#: resources/qml/Actions.qml:220 msgctxt "@action:inmenu Marketplace is a brand name of UltiMaker's, so don't translate." msgid "Add more materials from Marketplace" msgstr "Přidat více materiálů z Marketplace" -#: resources/qml/Actions.qml:225 +#: resources/qml/Actions.qml:227 msgctxt "@action:inmenu menubar:profile" msgid "&Update profile with current settings/overrides" msgstr "&Aktualizovat profil s aktuálními nastaveními/přepsáními" -#: resources/qml/Actions.qml:233 +#: resources/qml/Actions.qml:235 msgctxt "@action:inmenu menubar:profile" msgid "&Discard current changes" msgstr "Smazat aktuální &změny" -#: resources/qml/Actions.qml:245 +#: resources/qml/Actions.qml:247 msgctxt "@action:inmenu menubar:profile" msgid "&Create profile from current settings/overrides..." msgstr "&Vytvořit profil z aktuálního nastavení/přepsání." -#: resources/qml/Actions.qml:251 +#: resources/qml/Actions.qml:253 msgctxt "@action:inmenu menubar:profile" msgid "Manage Profiles..." msgstr "Spravovat profily..." -#: resources/qml/Actions.qml:259 +#: resources/qml/Actions.qml:261 msgctxt "@action:inmenu menubar:help" msgid "Show Online &Documentation" msgstr "Zobrazit online &dokumentaci" -#: resources/qml/Actions.qml:267 +#: resources/qml/Actions.qml:269 msgctxt "@action:inmenu menubar:help" msgid "Report a &Bug" msgstr "Nahlásit &chybu" -#: resources/qml/Actions.qml:275 +#: resources/qml/Actions.qml:277 msgctxt "@action:inmenu menubar:help" msgid "What's New" msgstr "Co je nového" -#: resources/qml/Actions.qml:289 +#: resources/qml/Actions.qml:291 msgctxt "@action:inmenu menubar:help" msgid "About..." msgstr "Více..." -#: resources/qml/Actions.qml:296 +#: resources/qml/Actions.qml:298 msgctxt "@action:inmenu menubar:edit" msgid "Delete Selected" msgstr "Smazat vybrané" -#: resources/qml/Actions.qml:306 +#: resources/qml/Actions.qml:308 msgctxt "@action:inmenu menubar:edit" msgid "Center Selected" msgstr "Centrovat vybrané" -#: resources/qml/Actions.qml:315 +#: resources/qml/Actions.qml:317 msgctxt "@action:inmenu menubar:edit" msgid "Multiply Selected" msgstr "Násobit vybrané" -#: resources/qml/Actions.qml:324 +#: resources/qml/Actions.qml:326 msgctxt "@action:inmenu" msgid "Delete Model" msgstr "Odstranit model" -#: resources/qml/Actions.qml:332 +#: resources/qml/Actions.qml:334 msgctxt "@action:inmenu" msgid "Ce&nter Model on Platform" msgstr "&Centerovat model na podložce" -#: resources/qml/Actions.qml:338 +#: resources/qml/Actions.qml:340 msgctxt "@action:inmenu menubar:edit" msgid "&Group Models" msgstr "Sesk&upit modely" -#: resources/qml/Actions.qml:358 +#: resources/qml/Actions.qml:360 msgctxt "@action:inmenu menubar:edit" msgid "Ungroup Models" msgstr "Rozdělit modely" -#: resources/qml/Actions.qml:368 +#: resources/qml/Actions.qml:370 msgctxt "@action:inmenu menubar:edit" msgid "&Merge Models" msgstr "Spo&jit modely" -#: resources/qml/Actions.qml:378 +#: resources/qml/Actions.qml:380 msgctxt "@action:inmenu" msgid "&Multiply Model..." msgstr "Náso&bení modelu..." -#: resources/qml/Actions.qml:385 +#: resources/qml/Actions.qml:387 msgctxt "@action:inmenu menubar:edit" msgid "Select All Models" msgstr "Vybrat všechny modely" -#: resources/qml/Actions.qml:395 +#: resources/qml/Actions.qml:397 msgctxt "@action:inmenu menubar:edit" msgid "Clear Build Plate" msgstr "Vyčistit podložku" -#: resources/qml/Actions.qml:405 +#: resources/qml/Actions.qml:407 msgctxt "@action:inmenu menubar:file" msgid "Reload All Models" msgstr "Znovu načíst všechny modely" -#: resources/qml/Actions.qml:414 +#: resources/qml/Actions.qml:416 msgctxt "@action:inmenu menubar:edit" msgid "Arrange All Models" msgstr "Uspořádat všechny modely" -#: resources/qml/Actions.qml:422 +#: resources/qml/Actions.qml:424 +msgctxt "@action:inmenu menubar:edit" +msgid "Arrange All Models Without Rotation" +msgstr "" + +#: resources/qml/Actions.qml:431 msgctxt "@action:inmenu menubar:edit" msgid "Arrange Selection" msgstr "Uspořádat selekci" -#: resources/qml/Actions.qml:429 +#: resources/qml/Actions.qml:438 +msgctxt "@action:inmenu menubar:edit" +msgid "Arrange Selection Without Rotation" +msgstr "" + +#: resources/qml/Actions.qml:445 msgctxt "@action:inmenu menubar:edit" msgid "Reset All Model Positions" msgstr "Resetovat všechny pozice modelů" -#: resources/qml/Actions.qml:436 +#: resources/qml/Actions.qml:452 msgctxt "@action:inmenu menubar:edit" msgid "Reset All Model Transformations" msgstr "Resetovat všechny transformace modelů" -#: resources/qml/Actions.qml:445 +#: resources/qml/Actions.qml:461 msgctxt "@action:inmenu menubar:file" msgid "&Open File(s)..." msgstr "&Otevřít soubor(y)..." -#: resources/qml/Actions.qml:455 +#: resources/qml/Actions.qml:471 msgctxt "@action:inmenu menubar:file" msgid "&New Project..." msgstr "&Nový projekt..." -#: resources/qml/Actions.qml:462 +#: resources/qml/Actions.qml:478 msgctxt "@action:inmenu menubar:help" msgid "Show Configuration Folder" msgstr "Zobrazit složku s konfigurací" -#: resources/qml/Actions.qml:469 resources/qml/Settings/SettingView.qml:476 +#: resources/qml/Actions.qml:485 resources/qml/Settings/SettingView.qml:476 msgctxt "@action:menu" msgid "Configure setting visibility..." msgstr "Konfigurovat viditelnost nastavení..." @@ -5083,7 +5093,7 @@ msgstr[0] "Tisknout vybraný model pomocí:" msgstr[1] "Tisknout vybrané modely pomocí:" msgstr[2] "Tisknout vybrané modely pomocí:" -#: resources/qml/Menus/ContextMenu.qml:92 +#: resources/qml/Menus/ContextMenu.qml:93 msgctxt "@title:window" msgid "Multiply Selected Model" msgid_plural "Multiply Selected Models" @@ -5091,11 +5101,16 @@ msgstr[0] "Násobit vybraný model" msgstr[1] "Násobit vybrané modele" msgstr[2] "Násobit vybrané modele" -#: resources/qml/Menus/ContextMenu.qml:123 +#: resources/qml/Menus/ContextMenu.qml:128 msgctxt "@label" msgid "Number of Copies" msgstr "Počet kopií" +#: resources/qml/Menus/ContextMenu.qml:149 +msgctxt "@label" +msgid "Lock Rotation" +msgstr "" + #: resources/qml/Menus/EditMenu.qml:12 msgctxt "@title:menu menubar:toplevel" msgid "&Edit" diff --git a/resources/i18n/cura.pot b/resources/i18n/cura.pot index 9321ffa72b..3dc901e8e0 100644 --- a/resources/i18n/cura.pot +++ b/resources/i18n/cura.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-04-27 12:22+0000\n" +"POT-Creation-Date: 2023-05-11 14:19+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -23,23 +23,23 @@ msgctxt "@info:title" msgid "Login failed" msgstr "" -#: cura/Arranging/ArrangeObjectsJob.py:25 +#: cura/Arranging/ArrangeObjectsJob.py:27 msgctxt "@info:status" msgid "Finding new location for objects" msgstr "" -#: cura/Arranging/ArrangeObjectsJob.py:29 +#: cura/Arranging/ArrangeObjectsJob.py:31 msgctxt "@info:title" msgid "Finding Location" msgstr "" -#: cura/Arranging/ArrangeObjectsJob.py:42 -#: cura/MultiplyObjectsJob.py:99 +#: cura/Arranging/ArrangeObjectsJob.py:45 +#: cura/MultiplyObjectsJob.py:101 msgctxt "@info:status" msgid "Unable to find a location within the build volume for all objects" msgstr "" -#: cura/Arranging/ArrangeObjectsJob.py:43 +#: cura/Arranging/ArrangeObjectsJob.py:46 msgctxt "@info:title" msgid "Can't Find Location" msgstr "" @@ -259,26 +259,26 @@ msgctxt "@info 'width', 'depth' and 'height' are variable names that must NOT be msgid "%(width).1f x %(depth).1f x %(height).1f mm" msgstr "" -#: cura/CuraApplication.py:1816 +#: cura/CuraApplication.py:1817 #, python-brace-format msgctxt "@info:status" msgid "Only one G-code file can be loaded at a time. Skipped importing {0}" msgstr "" -#: cura/CuraApplication.py:1818 +#: cura/CuraApplication.py:1819 #: cura/OAuth2/AuthorizationService.py:217 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:189 msgctxt "@info:title" msgid "Warning" msgstr "" -#: cura/CuraApplication.py:1828 +#: cura/CuraApplication.py:1829 #, python-brace-format msgctxt "@info:status" msgid "Can't open any other file if G-code is loading. Skipped importing {0}" msgstr "" -#: cura/CuraApplication.py:1830 +#: cura/CuraApplication.py:1831 #: cura/Settings/CuraContainerRegistry.py:156 #: cura/Settings/CuraContainerRegistry.py:166 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:153 @@ -406,17 +406,17 @@ msgctxt "@info:status" msgid "Calculated" msgstr "" -#: cura/MultiplyObjectsJob.py:30 +#: cura/MultiplyObjectsJob.py:31 msgctxt "@info:status" msgid "Multiplying and placing objects" msgstr "" -#: cura/MultiplyObjectsJob.py:32 +#: cura/MultiplyObjectsJob.py:33 msgctxt "@info:title" msgid "Placing Objects" msgstr "" -#: cura/MultiplyObjectsJob.py:100 +#: cura/MultiplyObjectsJob.py:102 msgctxt "@info:title" msgid "Placing Object" msgstr "" @@ -3321,17 +3321,17 @@ msgctxt "@action:button" msgid "Remove printers" msgstr "" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:62 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:63 msgctxt "@action:button Preceded by 'Ready to'." msgid "Print over network" msgstr "" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:63 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:64 msgctxt "@properties:tooltip" msgid "Print over network" msgstr "" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:64 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:65 msgctxt "@info:status" msgid "Connected over the network" msgstr "" @@ -3570,227 +3570,237 @@ msgctxt "@button" msgid "Cancel" msgstr "" -#: resources/qml/Actions.qml:81 +#: resources/qml/Actions.qml:83 msgctxt "@action:inmenu" msgid "Show Online Troubleshooting" msgstr "" -#: resources/qml/Actions.qml:88 +#: resources/qml/Actions.qml:90 msgctxt "@action:inmenu" msgid "Toggle Full Screen" msgstr "" -#: resources/qml/Actions.qml:96 +#: resources/qml/Actions.qml:98 msgctxt "@action:inmenu" msgid "Exit Full Screen" msgstr "" -#: resources/qml/Actions.qml:103 +#: resources/qml/Actions.qml:105 msgctxt "@action:inmenu menubar:edit" msgid "&Undo" msgstr "" -#: resources/qml/Actions.qml:113 +#: resources/qml/Actions.qml:115 msgctxt "@action:inmenu menubar:edit" msgid "&Redo" msgstr "" -#: resources/qml/Actions.qml:131 +#: resources/qml/Actions.qml:133 msgctxt "@action:inmenu menubar:file" msgid "&Quit" msgstr "" -#: resources/qml/Actions.qml:139 +#: resources/qml/Actions.qml:141 msgctxt "@action:inmenu menubar:view" msgid "3D View" msgstr "" -#: resources/qml/Actions.qml:146 +#: resources/qml/Actions.qml:148 msgctxt "@action:inmenu menubar:view" msgid "Front View" msgstr "" -#: resources/qml/Actions.qml:153 +#: resources/qml/Actions.qml:155 msgctxt "@action:inmenu menubar:view" msgid "Top View" msgstr "" -#: resources/qml/Actions.qml:160 +#: resources/qml/Actions.qml:162 msgctxt "@action:inmenu menubar:view" msgid "Bottom View" msgstr "" -#: resources/qml/Actions.qml:167 +#: resources/qml/Actions.qml:169 msgctxt "@action:inmenu menubar:view" msgid "Left Side View" msgstr "" -#: resources/qml/Actions.qml:174 +#: resources/qml/Actions.qml:176 msgctxt "@action:inmenu menubar:view" msgid "Right Side View" msgstr "" -#: resources/qml/Actions.qml:188 +#: resources/qml/Actions.qml:190 msgctxt "@action:inmenu" msgid "Configure Cura..." msgstr "" -#: resources/qml/Actions.qml:197 +#: resources/qml/Actions.qml:199 msgctxt "@action:inmenu menubar:printer" msgid "&Add Printer..." msgstr "" -#: resources/qml/Actions.qml:203 +#: resources/qml/Actions.qml:205 msgctxt "@action:inmenu menubar:printer" msgid "Manage Pr&inters..." msgstr "" -#: resources/qml/Actions.qml:210 +#: resources/qml/Actions.qml:212 msgctxt "@action:inmenu" msgid "Manage Materials..." msgstr "" -#: resources/qml/Actions.qml:218 +#: resources/qml/Actions.qml:220 msgctxt "@action:inmenu Marketplace is a brand name of UltiMaker's, so don't translate." msgid "Add more materials from Marketplace" msgstr "" -#: resources/qml/Actions.qml:225 +#: resources/qml/Actions.qml:227 msgctxt "@action:inmenu menubar:profile" msgid "&Update profile with current settings/overrides" msgstr "" -#: resources/qml/Actions.qml:233 +#: resources/qml/Actions.qml:235 msgctxt "@action:inmenu menubar:profile" msgid "&Discard current changes" msgstr "" -#: resources/qml/Actions.qml:245 +#: resources/qml/Actions.qml:247 msgctxt "@action:inmenu menubar:profile" msgid "&Create profile from current settings/overrides..." msgstr "" -#: resources/qml/Actions.qml:251 +#: resources/qml/Actions.qml:253 msgctxt "@action:inmenu menubar:profile" msgid "Manage Profiles..." msgstr "" -#: resources/qml/Actions.qml:259 +#: resources/qml/Actions.qml:261 msgctxt "@action:inmenu menubar:help" msgid "Show Online &Documentation" msgstr "" -#: resources/qml/Actions.qml:267 +#: resources/qml/Actions.qml:269 msgctxt "@action:inmenu menubar:help" msgid "Report a &Bug" msgstr "" -#: resources/qml/Actions.qml:275 +#: resources/qml/Actions.qml:277 msgctxt "@action:inmenu menubar:help" msgid "What's New" msgstr "" -#: resources/qml/Actions.qml:289 +#: resources/qml/Actions.qml:291 msgctxt "@action:inmenu menubar:help" msgid "About..." msgstr "" -#: resources/qml/Actions.qml:296 +#: resources/qml/Actions.qml:298 msgctxt "@action:inmenu menubar:edit" msgid "Delete Selected" msgstr "" -#: resources/qml/Actions.qml:306 +#: resources/qml/Actions.qml:308 msgctxt "@action:inmenu menubar:edit" msgid "Center Selected" msgstr "" -#: resources/qml/Actions.qml:315 +#: resources/qml/Actions.qml:317 msgctxt "@action:inmenu menubar:edit" msgid "Multiply Selected" msgstr "" -#: resources/qml/Actions.qml:324 +#: resources/qml/Actions.qml:326 msgctxt "@action:inmenu" msgid "Delete Model" msgstr "" -#: resources/qml/Actions.qml:332 +#: resources/qml/Actions.qml:334 msgctxt "@action:inmenu" msgid "Ce&nter Model on Platform" msgstr "" -#: resources/qml/Actions.qml:338 +#: resources/qml/Actions.qml:340 msgctxt "@action:inmenu menubar:edit" msgid "&Group Models" msgstr "" -#: resources/qml/Actions.qml:358 +#: resources/qml/Actions.qml:360 msgctxt "@action:inmenu menubar:edit" msgid "Ungroup Models" msgstr "" -#: resources/qml/Actions.qml:368 +#: resources/qml/Actions.qml:370 msgctxt "@action:inmenu menubar:edit" msgid "&Merge Models" msgstr "" -#: resources/qml/Actions.qml:378 +#: resources/qml/Actions.qml:380 msgctxt "@action:inmenu" msgid "&Multiply Model..." msgstr "" -#: resources/qml/Actions.qml:385 +#: resources/qml/Actions.qml:387 msgctxt "@action:inmenu menubar:edit" msgid "Select All Models" msgstr "" -#: resources/qml/Actions.qml:395 +#: resources/qml/Actions.qml:397 msgctxt "@action:inmenu menubar:edit" msgid "Clear Build Plate" msgstr "" -#: resources/qml/Actions.qml:405 +#: resources/qml/Actions.qml:407 msgctxt "@action:inmenu menubar:file" msgid "Reload All Models" msgstr "" -#: resources/qml/Actions.qml:414 +#: resources/qml/Actions.qml:416 msgctxt "@action:inmenu menubar:edit" msgid "Arrange All Models" msgstr "" -#: resources/qml/Actions.qml:422 +#: resources/qml/Actions.qml:424 +msgctxt "@action:inmenu menubar:edit" +msgid "Arrange All Models Without Rotation" +msgstr "" + +#: resources/qml/Actions.qml:431 msgctxt "@action:inmenu menubar:edit" msgid "Arrange Selection" msgstr "" -#: resources/qml/Actions.qml:429 +#: resources/qml/Actions.qml:438 +msgctxt "@action:inmenu menubar:edit" +msgid "Arrange Selection Without Rotation" +msgstr "" + +#: resources/qml/Actions.qml:445 msgctxt "@action:inmenu menubar:edit" msgid "Reset All Model Positions" msgstr "" -#: resources/qml/Actions.qml:436 +#: resources/qml/Actions.qml:452 msgctxt "@action:inmenu menubar:edit" msgid "Reset All Model Transformations" msgstr "" -#: resources/qml/Actions.qml:445 +#: resources/qml/Actions.qml:461 msgctxt "@action:inmenu menubar:file" msgid "&Open File(s)..." msgstr "" -#: resources/qml/Actions.qml:455 +#: resources/qml/Actions.qml:471 msgctxt "@action:inmenu menubar:file" msgid "&New Project..." msgstr "" -#: resources/qml/Actions.qml:462 +#: resources/qml/Actions.qml:478 msgctxt "@action:inmenu menubar:help" msgid "Show Configuration Folder" msgstr "" -#: resources/qml/Actions.qml:469 +#: resources/qml/Actions.qml:485 #: resources/qml/Settings/SettingView.qml:476 msgctxt "@action:menu" msgid "Configure setting visibility..." @@ -4414,18 +4424,23 @@ msgid_plural "Print Selected Models With:" msgstr[0] "" msgstr[1] "" -#: resources/qml/Menus/ContextMenu.qml:92 +#: resources/qml/Menus/ContextMenu.qml:93 msgctxt "@title:window" msgid "Multiply Selected Model" msgid_plural "Multiply Selected Models" msgstr[0] "" msgstr[1] "" -#: resources/qml/Menus/ContextMenu.qml:123 +#: resources/qml/Menus/ContextMenu.qml:128 msgctxt "@label" msgid "Number of Copies" msgstr "" +#: resources/qml/Menus/ContextMenu.qml:149 +msgctxt "@label" +msgid "Lock Rotation" +msgstr "" + #: resources/qml/Menus/EditMenu.qml:12 msgctxt "@title:menu menubar:toplevel" msgid "&Edit" @@ -6244,6 +6259,106 @@ msgstr "" msgctxt "@label" msgid "No items to select from" msgstr "" +#: plugins/UltimakerMachineActions/plugin.json +msgctxt "description" +msgid "Provides machine actions for Ultimaker machines (such as bed leveling wizard, selecting upgrades, etc.)." +msgstr "" + +#: plugins/UltimakerMachineActions/plugin.json +msgctxt "name" +msgid "UltiMaker machine actions" +msgstr "" + +#: plugins/SupportEraser/plugin.json +msgctxt "description" +msgid "Creates an eraser mesh to block the printing of support in certain places" +msgstr "" + +#: plugins/SupportEraser/plugin.json +msgctxt "name" +msgid "Support Eraser" +msgstr "" + +#: plugins/GCodeGzReader/plugin.json +msgctxt "description" +msgid "Reads g-code from a compressed archive." +msgstr "" + +#: plugins/GCodeGzReader/plugin.json +msgctxt "name" +msgid "Compressed G-code Reader" +msgstr "" + +#: plugins/SentryLogger/plugin.json +msgctxt "description" +msgid "Logs certain events so that they can be used by the crash reporter" +msgstr "" + +#: plugins/SentryLogger/plugin.json +msgctxt "name" +msgid "Sentry Logger" +msgstr "" + +#: plugins/CuraProfileReader/plugin.json +msgctxt "description" +msgid "Provides support for importing Cura profiles." +msgstr "" + +#: plugins/CuraProfileReader/plugin.json +msgctxt "name" +msgid "Cura Profile Reader" +msgstr "" + +#: plugins/3MFWriter/plugin.json +msgctxt "description" +msgid "Provides support for writing 3MF files." +msgstr "" + +#: plugins/3MFWriter/plugin.json +msgctxt "name" +msgid "3MF Writer" +msgstr "" + +#: plugins/PerObjectSettingsTool/plugin.json +msgctxt "description" +msgid "Provides the Per Model Settings." +msgstr "" + +#: plugins/PerObjectSettingsTool/plugin.json +msgctxt "name" +msgid "Per Model Settings Tool" +msgstr "" + +#: plugins/PrepareStage/plugin.json +msgctxt "description" +msgid "Provides a prepare stage in Cura." +msgstr "" + +#: plugins/PrepareStage/plugin.json +msgctxt "name" +msgid "Prepare Stage" +msgstr "" + +#: plugins/TrimeshReader/plugin.json +msgctxt "description" +msgid "Provides support for reading model files." +msgstr "" + +#: plugins/TrimeshReader/plugin.json +msgctxt "name" +msgid "Trimesh Reader" +msgstr "" + +#: plugins/Marketplace/plugin.json +msgctxt "description" +msgid "Manages extensions to the application and allows browsing extensions from the UltiMaker website." +msgstr "" + +#: plugins/Marketplace/plugin.json +msgctxt "name" +msgid "Marketplace" +msgstr "" + #: plugins/LegacyProfileReader/plugin.json msgctxt "description" msgid "Provides support for importing profiles from legacy Cura versions." @@ -6254,34 +6369,294 @@ msgctxt "name" msgid "Legacy Cura Profile Reader" msgstr "" -#: plugins/VersionUpgrade/VersionUpgrade22to24/plugin.json +#: plugins/GCodeProfileReader/plugin.json msgctxt "description" -msgid "Upgrades configurations from Cura 2.2 to Cura 2.4." +msgid "Provides support for importing profiles from g-code files." msgstr "" -#: plugins/VersionUpgrade/VersionUpgrade22to24/plugin.json +#: plugins/GCodeProfileReader/plugin.json msgctxt "name" -msgid "Version Upgrade 2.2 to 2.4" +msgid "G-code Profile Reader" msgstr "" -#: plugins/VersionUpgrade/VersionUpgrade411to412/plugin.json +#: plugins/CuraDrive/plugin.json msgctxt "description" -msgid "Upgrades configurations from Cura 4.11 to Cura 4.12." +msgid "Backup and restore your configuration." msgstr "" -#: plugins/VersionUpgrade/VersionUpgrade411to412/plugin.json +#: plugins/CuraDrive/plugin.json msgctxt "name" -msgid "Version Upgrade 4.11 to 4.12" +msgid "Cura Backups" msgstr "" -#: plugins/VersionUpgrade/VersionUpgrade41to42/plugin.json +#: plugins/3MFReader/plugin.json msgctxt "description" -msgid "Upgrades configurations from Cura 4.1 to Cura 4.2." +msgid "Provides support for reading 3MF files." msgstr "" -#: plugins/VersionUpgrade/VersionUpgrade41to42/plugin.json +#: plugins/3MFReader/plugin.json msgctxt "name" -msgid "Version Upgrade 4.1 to 4.2" +msgid "3MF Reader" +msgstr "" + +#: plugins/X3DReader/plugin.json +msgctxt "description" +msgid "Provides support for reading X3D files." +msgstr "" + +#: plugins/X3DReader/plugin.json +msgctxt "name" +msgid "X3D Reader" +msgstr "" + +#: plugins/RemovableDriveOutputDevice/plugin.json +msgctxt "description" +msgid "Provides removable drive hotplugging and writing support." +msgstr "" + +#: plugins/RemovableDriveOutputDevice/plugin.json +msgctxt "name" +msgid "Removable Drive Output Device Plugin" +msgstr "" + +#: plugins/FirmwareUpdateChecker/plugin.json +msgctxt "description" +msgid "Checks for firmware updates." +msgstr "" + +#: plugins/FirmwareUpdateChecker/plugin.json +msgctxt "name" +msgid "Firmware Update Checker" +msgstr "" + +#: plugins/MachineSettingsAction/plugin.json +msgctxt "description" +msgid "Provides a way to change machine settings (such as build volume, nozzle size, etc.)." +msgstr "" + +#: plugins/MachineSettingsAction/plugin.json +msgctxt "name" +msgid "Machine Settings Action" +msgstr "" + +#: plugins/XmlMaterialProfile/plugin.json +msgctxt "description" +msgid "Provides capabilities to read and write XML-based material profiles." +msgstr "" + +#: plugins/XmlMaterialProfile/plugin.json +msgctxt "name" +msgid "Material Profiles" +msgstr "" + +#: plugins/UFPReader/plugin.json +msgctxt "description" +msgid "Provides support for reading Ultimaker Format Packages." +msgstr "" + +#: plugins/UFPReader/plugin.json +msgctxt "name" +msgid "UFP Reader" +msgstr "" + +#: plugins/CuraEngineBackend/plugin.json +msgctxt "description" +msgid "Provides the link to the CuraEngine slicing backend." +msgstr "" + +#: plugins/CuraEngineBackend/plugin.json +msgctxt "name" +msgid "CuraEngine Backend" +msgstr "" + +#: plugins/GCodeReader/plugin.json +msgctxt "description" +msgid "Allows loading and displaying G-code files." +msgstr "" + +#: plugins/GCodeReader/plugin.json +msgctxt "name" +msgid "G-code Reader" +msgstr "" + +#: plugins/CuraProfileWriter/plugin.json +msgctxt "description" +msgid "Provides support for exporting Cura profiles." +msgstr "" + +#: plugins/CuraProfileWriter/plugin.json +msgctxt "name" +msgid "Cura Profile Writer" +msgstr "" + +#: plugins/SimulationView/plugin.json +msgctxt "description" +msgid "Provides the preview of sliced layerdata." +msgstr "" + +#: plugins/SimulationView/plugin.json +msgctxt "name" +msgid "Simulation View" +msgstr "" + +#: plugins/UM3NetworkPrinting/plugin.json +msgctxt "description" +msgid "Manages network connections to UltiMaker networked printers." +msgstr "" + +#: plugins/UM3NetworkPrinting/plugin.json +msgctxt "name" +msgid "UltiMaker Network Connection" +msgstr "" + +#: plugins/XRayView/plugin.json +msgctxt "description" +msgid "Provides the X-Ray view." +msgstr "" + +#: plugins/XRayView/plugin.json +msgctxt "name" +msgid "X-Ray View" +msgstr "" + +#: plugins/UFPWriter/plugin.json +msgctxt "description" +msgid "Provides support for writing Ultimaker Format Packages." +msgstr "" + +#: plugins/UFPWriter/plugin.json +msgctxt "name" +msgid "UFP Writer" +msgstr "" + +#: plugins/GCodeWriter/plugin.json +msgctxt "description" +msgid "Writes g-code to a file." +msgstr "" + +#: plugins/GCodeWriter/plugin.json +msgctxt "name" +msgid "G-code Writer" +msgstr "" + +#: plugins/MonitorStage/plugin.json +msgctxt "description" +msgid "Provides a monitor stage in Cura." +msgstr "" + +#: plugins/MonitorStage/plugin.json +msgctxt "name" +msgid "Monitor Stage" +msgstr "" + +#: plugins/FirmwareUpdater/plugin.json +msgctxt "description" +msgid "Provides a machine actions for updating firmware." +msgstr "" + +#: plugins/FirmwareUpdater/plugin.json +msgctxt "name" +msgid "Firmware Updater" +msgstr "" + +#: plugins/SolidView/plugin.json +msgctxt "description" +msgid "Provides a normal solid mesh view." +msgstr "" + +#: plugins/SolidView/plugin.json +msgctxt "name" +msgid "Solid View" +msgstr "" + +#: plugins/SliceInfoPlugin/plugin.json +msgctxt "description" +msgid "Submits anonymous slice info. Can be disabled through preferences." +msgstr "" + +#: plugins/SliceInfoPlugin/plugin.json +msgctxt "name" +msgid "Slice info" +msgstr "" + +#: plugins/ImageReader/plugin.json +msgctxt "description" +msgid "Enables ability to generate printable geometry from 2D image files." +msgstr "" + +#: plugins/ImageReader/plugin.json +msgctxt "name" +msgid "Image Reader" +msgstr "" + +#: plugins/PostProcessingPlugin/plugin.json +msgctxt "description" +msgid "Extension that allows for user created scripts for post processing" +msgstr "" + +#: plugins/PostProcessingPlugin/plugin.json +msgctxt "name" +msgid "Post Processing" +msgstr "" + +#: plugins/AMFReader/plugin.json +msgctxt "description" +msgid "Provides support for reading AMF files." +msgstr "" + +#: plugins/AMFReader/plugin.json +msgctxt "name" +msgid "AMF Reader" +msgstr "" + +#: plugins/VersionUpgrade/VersionUpgrade53to54/plugin.json +msgctxt "description" +msgid "Upgrades configurations from Cura 5.3 to Cura 5.4." +msgstr "" + +#: plugins/VersionUpgrade/VersionUpgrade53to54/plugin.json +msgctxt "name" +msgid "Version Upgrade 5.3 to 5.4" +msgstr "" + +#: plugins/VersionUpgrade/VersionUpgrade460to462/plugin.json +msgctxt "description" +msgid "Upgrades configurations from Cura 4.6.0 to Cura 4.6.2." +msgstr "" + +#: plugins/VersionUpgrade/VersionUpgrade460to462/plugin.json +msgctxt "name" +msgid "Version Upgrade 4.6.0 to 4.6.2" +msgstr "" + +#: plugins/VersionUpgrade/VersionUpgrade47to48/plugin.json +msgctxt "description" +msgid "Upgrades configurations from Cura 4.7 to Cura 4.8." +msgstr "" + +#: plugins/VersionUpgrade/VersionUpgrade47to48/plugin.json +msgctxt "name" +msgid "Version Upgrade 4.7 to 4.8" +msgstr "" + +#: plugins/VersionUpgrade/VersionUpgrade42to43/plugin.json +msgctxt "description" +msgid "Upgrades configurations from Cura 4.2 to Cura 4.3." +msgstr "" + +#: plugins/VersionUpgrade/VersionUpgrade42to43/plugin.json +msgctxt "name" +msgid "Version Upgrade 4.2 to 4.3" +msgstr "" + +#: plugins/VersionUpgrade/VersionUpgrade32to33/plugin.json +msgctxt "description" +msgid "Upgrades configurations from Cura 3.2 to Cura 3.3." +msgstr "" + +#: plugins/VersionUpgrade/VersionUpgrade32to33/plugin.json +msgctxt "name" +msgid "Version Upgrade 3.2 to 3.3" msgstr "" #: plugins/VersionUpgrade/VersionUpgrade35to40/plugin.json @@ -6304,136 +6679,6 @@ msgctxt "name" msgid "Version Upgrade 2.7 to 3.0" msgstr "" -#: plugins/VersionUpgrade/VersionUpgrade44to45/plugin.json -msgctxt "description" -msgid "Upgrades configurations from Cura 4.4 to Cura 4.5." -msgstr "" - -#: plugins/VersionUpgrade/VersionUpgrade44to45/plugin.json -msgctxt "name" -msgid "Version Upgrade 4.4 to 4.5" -msgstr "" - -#: plugins/VersionUpgrade/VersionUpgrade30to31/plugin.json -msgctxt "description" -msgid "Upgrades configurations from Cura 3.0 to Cura 3.1." -msgstr "" - -#: plugins/VersionUpgrade/VersionUpgrade30to31/plugin.json -msgctxt "name" -msgid "Version Upgrade 3.0 to 3.1" -msgstr "" - -#: plugins/VersionUpgrade/VersionUpgrade21to22/plugin.json -msgctxt "description" -msgid "Upgrades configurations from Cura 2.1 to Cura 2.2." -msgstr "" - -#: plugins/VersionUpgrade/VersionUpgrade21to22/plugin.json -msgctxt "name" -msgid "Version Upgrade 2.1 to 2.2" -msgstr "" - -#: plugins/VersionUpgrade/VersionUpgrade413to50/plugin.json -msgctxt "description" -msgid "Upgrades configurations from Cura 4.13 to Cura 5.0." -msgstr "" - -#: plugins/VersionUpgrade/VersionUpgrade413to50/plugin.json -msgctxt "name" -msgid "Version Upgrade 4.13 to 5.0" -msgstr "" - -#: plugins/VersionUpgrade/VersionUpgrade53to54/plugin.json -msgctxt "description" -msgid "Upgrades configurations from Cura 5.3 to Cura 5.4." -msgstr "" - -#: plugins/VersionUpgrade/VersionUpgrade53to54/plugin.json -msgctxt "name" -msgid "Version Upgrade 5.3 to 5.4" -msgstr "" - -#: plugins/VersionUpgrade/VersionUpgrade32to33/plugin.json -msgctxt "description" -msgid "Upgrades configurations from Cura 3.2 to Cura 3.3." -msgstr "" - -#: plugins/VersionUpgrade/VersionUpgrade32to33/plugin.json -msgctxt "name" -msgid "Version Upgrade 3.2 to 3.3" -msgstr "" - -#: plugins/VersionUpgrade/VersionUpgrade40to41/plugin.json -msgctxt "description" -msgid "Upgrades configurations from Cura 4.0 to Cura 4.1." -msgstr "" - -#: plugins/VersionUpgrade/VersionUpgrade40to41/plugin.json -msgctxt "name" -msgid "Version Upgrade 4.0 to 4.1" -msgstr "" - -#: plugins/VersionUpgrade/VersionUpgrade42to43/plugin.json -msgctxt "description" -msgid "Upgrades configurations from Cura 4.2 to Cura 4.3." -msgstr "" - -#: plugins/VersionUpgrade/VersionUpgrade42to43/plugin.json -msgctxt "name" -msgid "Version Upgrade 4.2 to 4.3" -msgstr "" - -#: plugins/VersionUpgrade/VersionUpgrade47to48/plugin.json -msgctxt "description" -msgid "Upgrades configurations from Cura 4.7 to Cura 4.8." -msgstr "" - -#: plugins/VersionUpgrade/VersionUpgrade47to48/plugin.json -msgctxt "name" -msgid "Version Upgrade 4.7 to 4.8" -msgstr "" - -#: plugins/VersionUpgrade/VersionUpgrade34to35/plugin.json -msgctxt "description" -msgid "Upgrades configurations from Cura 3.4 to Cura 3.5." -msgstr "" - -#: plugins/VersionUpgrade/VersionUpgrade34to35/plugin.json -msgctxt "name" -msgid "Version Upgrade 3.4 to 3.5" -msgstr "" - -#: plugins/VersionUpgrade/VersionUpgrade48to49/plugin.json -msgctxt "description" -msgid "Upgrades configurations from Cura 4.8 to Cura 4.9." -msgstr "" - -#: plugins/VersionUpgrade/VersionUpgrade48to49/plugin.json -msgctxt "name" -msgid "Version Upgrade 4.8 to 4.9" -msgstr "" - -#: plugins/VersionUpgrade/VersionUpgrade43to44/plugin.json -msgctxt "description" -msgid "Upgrades configurations from Cura 4.3 to Cura 4.4." -msgstr "" - -#: plugins/VersionUpgrade/VersionUpgrade43to44/plugin.json -msgctxt "name" -msgid "Version Upgrade 4.3 to 4.4" -msgstr "" - -#: plugins/VersionUpgrade/VersionUpgrade25to26/plugin.json -msgctxt "description" -msgid "Upgrades configurations from Cura 2.5 to Cura 2.6." -msgstr "" - -#: plugins/VersionUpgrade/VersionUpgrade25to26/plugin.json -msgctxt "name" -msgid "Version Upgrade 2.5 to 2.6" -msgstr "" - #: plugins/VersionUpgrade/VersionUpgrade462to47/plugin.json msgctxt "description" msgid "Upgrades configurations from Cura 4.6.2 to Cura 4.7." @@ -6444,34 +6689,14 @@ msgctxt "name" msgid "Version Upgrade 4.6.2 to 4.7" msgstr "" -#: plugins/VersionUpgrade/VersionUpgrade26to27/plugin.json +#: plugins/VersionUpgrade/VersionUpgrade22to24/plugin.json msgctxt "description" -msgid "Upgrades configurations from Cura 2.6 to Cura 2.7." +msgid "Upgrades configurations from Cura 2.2 to Cura 2.4." msgstr "" -#: plugins/VersionUpgrade/VersionUpgrade26to27/plugin.json +#: plugins/VersionUpgrade/VersionUpgrade22to24/plugin.json msgctxt "name" -msgid "Version Upgrade 2.6 to 2.7" -msgstr "" - -#: plugins/VersionUpgrade/VersionUpgrade45to46/plugin.json -msgctxt "description" -msgid "Upgrades configurations from Cura 4.5 to Cura 4.6." -msgstr "" - -#: plugins/VersionUpgrade/VersionUpgrade45to46/plugin.json -msgctxt "name" -msgid "Version Upgrade 4.5 to 4.6" -msgstr "" - -#: plugins/VersionUpgrade/VersionUpgrade33to34/plugin.json -msgctxt "description" -msgid "Upgrades configurations from Cura 3.3 to Cura 3.4." -msgstr "" - -#: plugins/VersionUpgrade/VersionUpgrade33to34/plugin.json -msgctxt "name" -msgid "Version Upgrade 3.3 to 3.4" +msgid "Version Upgrade 2.2 to 2.4" msgstr "" #: plugins/VersionUpgrade/VersionUpgrade52to53/plugin.json @@ -6484,16 +6709,6 @@ msgctxt "name" msgid "Version Upgrade 5.2 to 5.3" msgstr "" -#: plugins/VersionUpgrade/VersionUpgrade460to462/plugin.json -msgctxt "description" -msgid "Upgrades configurations from Cura 4.6.0 to Cura 4.6.2." -msgstr "" - -#: plugins/VersionUpgrade/VersionUpgrade460to462/plugin.json -msgctxt "name" -msgid "Version Upgrade 4.6.0 to 4.6.2" -msgstr "" - #: plugins/VersionUpgrade/VersionUpgrade49to410/plugin.json msgctxt "description" msgid "Upgrades configurations from Cura 4.9 to Cura 4.10." @@ -6504,114 +6719,144 @@ msgctxt "name" msgid "Version Upgrade 4.9 to 4.10" msgstr "" -#: plugins/CuraProfileWriter/plugin.json +#: plugins/VersionUpgrade/VersionUpgrade48to49/plugin.json msgctxt "description" -msgid "Provides support for exporting Cura profiles." +msgid "Upgrades configurations from Cura 4.8 to Cura 4.9." msgstr "" -#: plugins/CuraProfileWriter/plugin.json +#: plugins/VersionUpgrade/VersionUpgrade48to49/plugin.json msgctxt "name" -msgid "Cura Profile Writer" +msgid "Version Upgrade 4.8 to 4.9" msgstr "" -#: plugins/FirmwareUpdateChecker/plugin.json +#: plugins/VersionUpgrade/VersionUpgrade30to31/plugin.json msgctxt "description" -msgid "Checks for firmware updates." +msgid "Upgrades configurations from Cura 3.0 to Cura 3.1." msgstr "" -#: plugins/FirmwareUpdateChecker/plugin.json +#: plugins/VersionUpgrade/VersionUpgrade30to31/plugin.json msgctxt "name" -msgid "Firmware Update Checker" +msgid "Version Upgrade 3.0 to 3.1" msgstr "" -#: plugins/PostProcessingPlugin/plugin.json +#: plugins/VersionUpgrade/VersionUpgrade34to35/plugin.json msgctxt "description" -msgid "Extension that allows for user created scripts for post processing" +msgid "Upgrades configurations from Cura 3.4 to Cura 3.5." msgstr "" -#: plugins/PostProcessingPlugin/plugin.json +#: plugins/VersionUpgrade/VersionUpgrade34to35/plugin.json msgctxt "name" -msgid "Post Processing" +msgid "Version Upgrade 3.4 to 3.5" msgstr "" -#: plugins/USBPrinting/plugin.json +#: plugins/VersionUpgrade/VersionUpgrade43to44/plugin.json msgctxt "description" -msgid "Accepts G-Code and sends them to a printer. Plugin can also update firmware." +msgid "Upgrades configurations from Cura 4.3 to Cura 4.4." msgstr "" -#: plugins/USBPrinting/plugin.json +#: plugins/VersionUpgrade/VersionUpgrade43to44/plugin.json msgctxt "name" -msgid "USB printing" +msgid "Version Upgrade 4.3 to 4.4" msgstr "" -#: plugins/CuraDrive/plugin.json +#: plugins/VersionUpgrade/VersionUpgrade41to42/plugin.json msgctxt "description" -msgid "Backup and restore your configuration." +msgid "Upgrades configurations from Cura 4.1 to Cura 4.2." msgstr "" -#: plugins/CuraDrive/plugin.json +#: plugins/VersionUpgrade/VersionUpgrade41to42/plugin.json msgctxt "name" -msgid "Cura Backups" +msgid "Version Upgrade 4.1 to 4.2" msgstr "" -#: plugins/GCodeGzWriter/plugin.json +#: plugins/VersionUpgrade/VersionUpgrade44to45/plugin.json msgctxt "description" -msgid "Writes g-code to a compressed archive." +msgid "Upgrades configurations from Cura 4.4 to Cura 4.5." msgstr "" -#: plugins/GCodeGzWriter/plugin.json +#: plugins/VersionUpgrade/VersionUpgrade44to45/plugin.json msgctxt "name" -msgid "Compressed G-code Writer" +msgid "Version Upgrade 4.4 to 4.5" msgstr "" -#: plugins/GCodeWriter/plugin.json +#: plugins/VersionUpgrade/VersionUpgrade33to34/plugin.json msgctxt "description" -msgid "Writes g-code to a file." +msgid "Upgrades configurations from Cura 3.3 to Cura 3.4." msgstr "" -#: plugins/GCodeWriter/plugin.json +#: plugins/VersionUpgrade/VersionUpgrade33to34/plugin.json msgctxt "name" -msgid "G-code Writer" +msgid "Version Upgrade 3.3 to 3.4" msgstr "" -#: plugins/3MFWriter/plugin.json +#: plugins/VersionUpgrade/VersionUpgrade411to412/plugin.json msgctxt "description" -msgid "Provides support for writing 3MF files." +msgid "Upgrades configurations from Cura 4.11 to Cura 4.12." msgstr "" -#: plugins/3MFWriter/plugin.json +#: plugins/VersionUpgrade/VersionUpgrade411to412/plugin.json msgctxt "name" -msgid "3MF Writer" +msgid "Version Upgrade 4.11 to 4.12" msgstr "" -#: plugins/ModelChecker/plugin.json +#: plugins/VersionUpgrade/VersionUpgrade413to50/plugin.json msgctxt "description" -msgid "Checks models and print configuration for possible printing issues and give suggestions." +msgid "Upgrades configurations from Cura 4.13 to Cura 5.0." msgstr "" -#: plugins/ModelChecker/plugin.json +#: plugins/VersionUpgrade/VersionUpgrade413to50/plugin.json msgctxt "name" -msgid "Model Checker" +msgid "Version Upgrade 4.13 to 5.0" msgstr "" -#: plugins/GCodeReader/plugin.json +#: plugins/VersionUpgrade/VersionUpgrade45to46/plugin.json msgctxt "description" -msgid "Allows loading and displaying G-code files." +msgid "Upgrades configurations from Cura 4.5 to Cura 4.6." msgstr "" -#: plugins/GCodeReader/plugin.json +#: plugins/VersionUpgrade/VersionUpgrade45to46/plugin.json msgctxt "name" -msgid "G-code Reader" +msgid "Version Upgrade 4.5 to 4.6" msgstr "" -#: plugins/GCodeGzReader/plugin.json +#: plugins/VersionUpgrade/VersionUpgrade21to22/plugin.json msgctxt "description" -msgid "Reads g-code from a compressed archive." +msgid "Upgrades configurations from Cura 2.1 to Cura 2.2." msgstr "" -#: plugins/GCodeGzReader/plugin.json +#: plugins/VersionUpgrade/VersionUpgrade21to22/plugin.json msgctxt "name" -msgid "Compressed G-code Reader" +msgid "Version Upgrade 2.1 to 2.2" +msgstr "" + +#: plugins/VersionUpgrade/VersionUpgrade40to41/plugin.json +msgctxt "description" +msgid "Upgrades configurations from Cura 4.0 to Cura 4.1." +msgstr "" + +#: plugins/VersionUpgrade/VersionUpgrade40to41/plugin.json +msgctxt "name" +msgid "Version Upgrade 4.0 to 4.1" +msgstr "" + +#: plugins/VersionUpgrade/VersionUpgrade25to26/plugin.json +msgctxt "description" +msgid "Upgrades configurations from Cura 2.5 to Cura 2.6." +msgstr "" + +#: plugins/VersionUpgrade/VersionUpgrade25to26/plugin.json +msgctxt "name" +msgid "Version Upgrade 2.5 to 2.6" +msgstr "" + +#: plugins/VersionUpgrade/VersionUpgrade26to27/plugin.json +msgctxt "description" +msgid "Upgrades configurations from Cura 2.6 to Cura 2.7." +msgstr "" + +#: plugins/VersionUpgrade/VersionUpgrade26to27/plugin.json +msgctxt "name" +msgid "Version Upgrade 2.6 to 2.7" msgstr "" #: plugins/DigitalLibrary/plugin.json @@ -6624,234 +6869,34 @@ msgctxt "name" msgid "Ultimaker Digital Library" msgstr "" -#: plugins/SupportEraser/plugin.json +#: plugins/ModelChecker/plugin.json msgctxt "description" -msgid "Creates an eraser mesh to block the printing of support in certain places" +msgid "Checks models and print configuration for possible printing issues and give suggestions." msgstr "" -#: plugins/SupportEraser/plugin.json +#: plugins/ModelChecker/plugin.json msgctxt "name" -msgid "Support Eraser" +msgid "Model Checker" msgstr "" -#: plugins/RemovableDriveOutputDevice/plugin.json +#: plugins/USBPrinting/plugin.json msgctxt "description" -msgid "Provides removable drive hotplugging and writing support." +msgid "Accepts G-Code and sends them to a printer. Plugin can also update firmware." msgstr "" -#: plugins/RemovableDriveOutputDevice/plugin.json +#: plugins/USBPrinting/plugin.json msgctxt "name" -msgid "Removable Drive Output Device Plugin" +msgid "USB printing" msgstr "" -#: plugins/SolidView/plugin.json +#: plugins/GCodeGzWriter/plugin.json msgctxt "description" -msgid "Provides a normal solid mesh view." +msgid "Writes g-code to a compressed archive." msgstr "" -#: plugins/SolidView/plugin.json +#: plugins/GCodeGzWriter/plugin.json msgctxt "name" -msgid "Solid View" -msgstr "" - -#: plugins/SentryLogger/plugin.json -msgctxt "description" -msgid "Logs certain events so that they can be used by the crash reporter" -msgstr "" - -#: plugins/SentryLogger/plugin.json -msgctxt "name" -msgid "Sentry Logger" -msgstr "" - -#: plugins/PerObjectSettingsTool/plugin.json -msgctxt "description" -msgid "Provides the Per Model Settings." -msgstr "" - -#: plugins/PerObjectSettingsTool/plugin.json -msgctxt "name" -msgid "Per Model Settings Tool" -msgstr "" - -#: plugins/3MFReader/plugin.json -msgctxt "description" -msgid "Provides support for reading 3MF files." -msgstr "" - -#: plugins/3MFReader/plugin.json -msgctxt "name" -msgid "3MF Reader" -msgstr "" - -#: plugins/AMFReader/plugin.json -msgctxt "description" -msgid "Provides support for reading AMF files." -msgstr "" - -#: plugins/AMFReader/plugin.json -msgctxt "name" -msgid "AMF Reader" -msgstr "" - -#: plugins/X3DReader/plugin.json -msgctxt "description" -msgid "Provides support for reading X3D files." -msgstr "" - -#: plugins/X3DReader/plugin.json -msgctxt "name" -msgid "X3D Reader" -msgstr "" - -#: plugins/SimulationView/plugin.json -msgctxt "description" -msgid "Provides the preview of sliced layerdata." -msgstr "" - -#: plugins/SimulationView/plugin.json -msgctxt "name" -msgid "Simulation View" -msgstr "" - -#: plugins/TrimeshReader/plugin.json -msgctxt "description" -msgid "Provides support for reading model files." -msgstr "" - -#: plugins/TrimeshReader/plugin.json -msgctxt "name" -msgid "Trimesh Reader" -msgstr "" - -#: plugins/CuraEngineBackend/plugin.json -msgctxt "description" -msgid "Provides the link to the CuraEngine slicing backend." -msgstr "" - -#: plugins/CuraEngineBackend/plugin.json -msgctxt "name" -msgid "CuraEngine Backend" -msgstr "" - -#: plugins/ImageReader/plugin.json -msgctxt "description" -msgid "Enables ability to generate printable geometry from 2D image files." -msgstr "" - -#: plugins/ImageReader/plugin.json -msgctxt "name" -msgid "Image Reader" -msgstr "" - -#: plugins/GCodeProfileReader/plugin.json -msgctxt "description" -msgid "Provides support for importing profiles from g-code files." -msgstr "" - -#: plugins/GCodeProfileReader/plugin.json -msgctxt "name" -msgid "G-code Profile Reader" -msgstr "" - -#: plugins/XmlMaterialProfile/plugin.json -msgctxt "description" -msgid "Provides capabilities to read and write XML-based material profiles." -msgstr "" - -#: plugins/XmlMaterialProfile/plugin.json -msgctxt "name" -msgid "Material Profiles" -msgstr "" - -#: plugins/MonitorStage/plugin.json -msgctxt "description" -msgid "Provides a monitor stage in Cura." -msgstr "" - -#: plugins/MonitorStage/plugin.json -msgctxt "name" -msgid "Monitor Stage" -msgstr "" - -#: plugins/CuraProfileReader/plugin.json -msgctxt "description" -msgid "Provides support for importing Cura profiles." -msgstr "" - -#: plugins/CuraProfileReader/plugin.json -msgctxt "name" -msgid "Cura Profile Reader" -msgstr "" - -#: plugins/UM3NetworkPrinting/plugin.json -msgctxt "description" -msgid "Manages network connections to UltiMaker networked printers." -msgstr "" - -#: plugins/UM3NetworkPrinting/plugin.json -msgctxt "name" -msgid "UltiMaker Network Connection" -msgstr "" - -#: plugins/PrepareStage/plugin.json -msgctxt "description" -msgid "Provides a prepare stage in Cura." -msgstr "" - -#: plugins/PrepareStage/plugin.json -msgctxt "name" -msgid "Prepare Stage" -msgstr "" - -#: plugins/UFPWriter/plugin.json -msgctxt "description" -msgid "Provides support for writing Ultimaker Format Packages." -msgstr "" - -#: plugins/UFPWriter/plugin.json -msgctxt "name" -msgid "UFP Writer" -msgstr "" - -#: plugins/UltimakerMachineActions/plugin.json -msgctxt "description" -msgid "Provides machine actions for Ultimaker machines (such as bed leveling wizard, selecting upgrades, etc.)." -msgstr "" - -#: plugins/UltimakerMachineActions/plugin.json -msgctxt "name" -msgid "UltiMaker machine actions" -msgstr "" - -#: plugins/UFPReader/plugin.json -msgctxt "description" -msgid "Provides support for reading Ultimaker Format Packages." -msgstr "" - -#: plugins/UFPReader/plugin.json -msgctxt "name" -msgid "UFP Reader" -msgstr "" - -#: plugins/XRayView/plugin.json -msgctxt "description" -msgid "Provides the X-Ray view." -msgstr "" - -#: plugins/XRayView/plugin.json -msgctxt "name" -msgid "X-Ray View" -msgstr "" - -#: plugins/MachineSettingsAction/plugin.json -msgctxt "description" -msgid "Provides a way to change machine settings (such as build volume, nozzle size, etc.)." -msgstr "" - -#: plugins/MachineSettingsAction/plugin.json -msgctxt "name" -msgid "Machine Settings Action" +msgid "Compressed G-code Writer" msgstr "" #: plugins/PreviewStage/plugin.json @@ -6864,33 +6909,3 @@ msgctxt "name" msgid "Preview Stage" msgstr "" -#: plugins/SliceInfoPlugin/plugin.json -msgctxt "description" -msgid "Submits anonymous slice info. Can be disabled through preferences." -msgstr "" - -#: plugins/SliceInfoPlugin/plugin.json -msgctxt "name" -msgid "Slice info" -msgstr "" - -#: plugins/Marketplace/plugin.json -msgctxt "description" -msgid "Manages extensions to the application and allows browsing extensions from the UltiMaker website." -msgstr "" - -#: plugins/Marketplace/plugin.json -msgctxt "name" -msgid "Marketplace" -msgstr "" - -#: plugins/FirmwareUpdater/plugin.json -msgctxt "description" -msgid "Provides a machine actions for updating firmware." -msgstr "" - -#: plugins/FirmwareUpdater/plugin.json -msgctxt "name" -msgid "Firmware Updater" -msgstr "" - diff --git a/resources/i18n/de_DE/cura.po b/resources/i18n/de_DE/cura.po index 32d5befcda..c326cca9fd 100644 --- a/resources/i18n/de_DE/cura.po +++ b/resources/i18n/de_DE/cura.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-04-27 12:22+0000\n" +"POT-Creation-Date: 2023-05-11 14:19+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -23,22 +23,22 @@ msgctxt "@info:title" msgid "Login failed" msgstr "Login fehlgeschlagen" -#: cura/Arranging/ArrangeObjectsJob.py:25 +#: cura/Arranging/ArrangeObjectsJob.py:27 msgctxt "@info:status" msgid "Finding new location for objects" msgstr "Neue Position für Objekte finden" -#: cura/Arranging/ArrangeObjectsJob.py:29 +#: cura/Arranging/ArrangeObjectsJob.py:31 msgctxt "@info:title" msgid "Finding Location" msgstr "Position finden" -#: cura/Arranging/ArrangeObjectsJob.py:42 cura/MultiplyObjectsJob.py:99 +#: cura/Arranging/ArrangeObjectsJob.py:45 cura/MultiplyObjectsJob.py:101 msgctxt "@info:status" msgid "Unable to find a location within the build volume for all objects" msgstr "Innerhalb der Druckabmessung für alle Objekte konnte keine Position gefunden werden" -#: cura/Arranging/ArrangeObjectsJob.py:43 +#: cura/Arranging/ArrangeObjectsJob.py:46 msgctxt "@info:title" msgid "Can't Find Location" msgstr "Kann Position nicht finden" @@ -265,25 +265,25 @@ msgctxt "@info 'width', 'depth' and 'height' are variable names that must NOT be msgid "%(width).1f x %(depth).1f x %(height).1f mm" msgstr "%(width).1f x %(depth).1f x %(height).1f mm" -#: cura/CuraApplication.py:1816 +#: cura/CuraApplication.py:1817 #, python-brace-format msgctxt "@info:status" msgid "Only one G-code file can be loaded at a time. Skipped importing {0}" msgstr "Es kann nur jeweils ein G-Code gleichzeitig geladen werden. Wichtige {0} werden übersprungen." -#: cura/CuraApplication.py:1818 cura/OAuth2/AuthorizationService.py:217 +#: cura/CuraApplication.py:1819 cura/OAuth2/AuthorizationService.py:217 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:189 msgctxt "@info:title" msgid "Warning" msgstr "Warnhinweis" -#: cura/CuraApplication.py:1828 +#: cura/CuraApplication.py:1829 #, python-brace-format msgctxt "@info:status" msgid "Can't open any other file if G-code is loading. Skipped importing {0}" msgstr "Wenn G-Code geladen wird, kann keine weitere Datei geöffnet werden. Wichtige {0} werden übersprungen." -#: cura/CuraApplication.py:1830 cura/Settings/CuraContainerRegistry.py:156 +#: cura/CuraApplication.py:1831 cura/Settings/CuraContainerRegistry.py:156 #: cura/Settings/CuraContainerRegistry.py:166 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:153 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:173 @@ -410,17 +410,17 @@ msgctxt "@info:status" msgid "Calculated" msgstr "Berechnet" -#: cura/MultiplyObjectsJob.py:30 +#: cura/MultiplyObjectsJob.py:31 msgctxt "@info:status" msgid "Multiplying and placing objects" msgstr "Objekte vervielfältigen und platzieren" -#: cura/MultiplyObjectsJob.py:32 +#: cura/MultiplyObjectsJob.py:33 msgctxt "@info:title" msgid "Placing Objects" msgstr "Objekte platzieren" -#: cura/MultiplyObjectsJob.py:100 +#: cura/MultiplyObjectsJob.py:102 msgctxt "@info:title" msgid "Placing Object" msgstr "Objekt-Platzierung" @@ -3675,17 +3675,17 @@ msgctxt "@action:button" msgid "Remove printers" msgstr "Drucker entfernen" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:62 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:63 msgctxt "@action:button Preceded by 'Ready to'." msgid "Print over network" msgstr "Drucken über Netzwerk" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:63 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:64 msgctxt "@properties:tooltip" msgid "Print over network" msgstr "Drücken über Netzwerk" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:64 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:65 msgctxt "@info:status" msgid "Connected over the network" msgstr "Über Netzwerk verbunden" @@ -4227,227 +4227,237 @@ msgctxt "@button" msgid "Cancel" msgstr "Abbrechen" -#: resources/qml/Actions.qml:81 +#: resources/qml/Actions.qml:83 msgctxt "@action:inmenu" msgid "Show Online Troubleshooting" msgstr "Online-Fehlerbehebung anzeigen" -#: resources/qml/Actions.qml:88 +#: resources/qml/Actions.qml:90 msgctxt "@action:inmenu" msgid "Toggle Full Screen" msgstr "Umschalten auf Vollbild-Modus" -#: resources/qml/Actions.qml:96 +#: resources/qml/Actions.qml:98 msgctxt "@action:inmenu" msgid "Exit Full Screen" msgstr "Vollbildmodus beenden" -#: resources/qml/Actions.qml:103 +#: resources/qml/Actions.qml:105 msgctxt "@action:inmenu menubar:edit" msgid "&Undo" msgstr "&Rückgängig machen" -#: resources/qml/Actions.qml:113 +#: resources/qml/Actions.qml:115 msgctxt "@action:inmenu menubar:edit" msgid "&Redo" msgstr "&Wiederholen" -#: resources/qml/Actions.qml:131 +#: resources/qml/Actions.qml:133 msgctxt "@action:inmenu menubar:file" msgid "&Quit" msgstr "&Beenden" -#: resources/qml/Actions.qml:139 +#: resources/qml/Actions.qml:141 msgctxt "@action:inmenu menubar:view" msgid "3D View" msgstr "3D-Ansicht" -#: resources/qml/Actions.qml:146 +#: resources/qml/Actions.qml:148 msgctxt "@action:inmenu menubar:view" msgid "Front View" msgstr "Vorderansicht" -#: resources/qml/Actions.qml:153 +#: resources/qml/Actions.qml:155 msgctxt "@action:inmenu menubar:view" msgid "Top View" msgstr "Draufsicht" -#: resources/qml/Actions.qml:160 +#: resources/qml/Actions.qml:162 msgctxt "@action:inmenu menubar:view" msgid "Bottom View" msgstr "Ansicht von unten" -#: resources/qml/Actions.qml:167 +#: resources/qml/Actions.qml:169 msgctxt "@action:inmenu menubar:view" msgid "Left Side View" msgstr "Ansicht von links" -#: resources/qml/Actions.qml:174 +#: resources/qml/Actions.qml:176 msgctxt "@action:inmenu menubar:view" msgid "Right Side View" msgstr "Ansicht von rechts" -#: resources/qml/Actions.qml:188 +#: resources/qml/Actions.qml:190 msgctxt "@action:inmenu" msgid "Configure Cura..." msgstr "Cura konfigurieren..." -#: resources/qml/Actions.qml:197 +#: resources/qml/Actions.qml:199 msgctxt "@action:inmenu menubar:printer" msgid "&Add Printer..." msgstr "&Drucker hinzufügen..." -#: resources/qml/Actions.qml:203 +#: resources/qml/Actions.qml:205 msgctxt "@action:inmenu menubar:printer" msgid "Manage Pr&inters..." msgstr "Dr&ucker verwalten..." -#: resources/qml/Actions.qml:210 +#: resources/qml/Actions.qml:212 msgctxt "@action:inmenu" msgid "Manage Materials..." msgstr "Materialien werden verwaltet..." -#: resources/qml/Actions.qml:218 +#: resources/qml/Actions.qml:220 msgctxt "@action:inmenu Marketplace is a brand name of UltiMaker's, so don't translate." msgid "Add more materials from Marketplace" msgstr "Weiteres Material aus Marketplace hinzufügen" -#: resources/qml/Actions.qml:225 +#: resources/qml/Actions.qml:227 msgctxt "@action:inmenu menubar:profile" msgid "&Update profile with current settings/overrides" msgstr "&Profil mit aktuellen Einstellungen/Überschreibungen aktualisieren" -#: resources/qml/Actions.qml:233 +#: resources/qml/Actions.qml:235 msgctxt "@action:inmenu menubar:profile" msgid "&Discard current changes" msgstr "&Aktuelle Änderungen verwerfen" -#: resources/qml/Actions.qml:245 +#: resources/qml/Actions.qml:247 msgctxt "@action:inmenu menubar:profile" msgid "&Create profile from current settings/overrides..." msgstr "P&rofil von aktuellen Einstellungen/Überschreibungen erstellen..." -#: resources/qml/Actions.qml:251 +#: resources/qml/Actions.qml:253 msgctxt "@action:inmenu menubar:profile" msgid "Manage Profiles..." msgstr "Profile verwalten..." -#: resources/qml/Actions.qml:259 +#: resources/qml/Actions.qml:261 msgctxt "@action:inmenu menubar:help" msgid "Show Online &Documentation" msgstr "Online-&Dokumentation anzeigen" -#: resources/qml/Actions.qml:267 +#: resources/qml/Actions.qml:269 msgctxt "@action:inmenu menubar:help" msgid "Report a &Bug" msgstr "&Fehler melden" -#: resources/qml/Actions.qml:275 +#: resources/qml/Actions.qml:277 msgctxt "@action:inmenu menubar:help" msgid "What's New" msgstr "Neuheiten" -#: resources/qml/Actions.qml:289 +#: resources/qml/Actions.qml:291 msgctxt "@action:inmenu menubar:help" msgid "About..." msgstr "Über..." -#: resources/qml/Actions.qml:296 +#: resources/qml/Actions.qml:298 msgctxt "@action:inmenu menubar:edit" msgid "Delete Selected" msgstr "Ausgewählte löschen" -#: resources/qml/Actions.qml:306 +#: resources/qml/Actions.qml:308 msgctxt "@action:inmenu menubar:edit" msgid "Center Selected" msgstr "Ausgewählte zentrieren" -#: resources/qml/Actions.qml:315 +#: resources/qml/Actions.qml:317 msgctxt "@action:inmenu menubar:edit" msgid "Multiply Selected" msgstr "Ausgewählte vervielfachen" -#: resources/qml/Actions.qml:324 +#: resources/qml/Actions.qml:326 msgctxt "@action:inmenu" msgid "Delete Model" msgstr "Modell löschen" -#: resources/qml/Actions.qml:332 +#: resources/qml/Actions.qml:334 msgctxt "@action:inmenu" msgid "Ce&nter Model on Platform" msgstr "Modell auf Druckplatte ze&ntrieren" -#: resources/qml/Actions.qml:338 +#: resources/qml/Actions.qml:340 msgctxt "@action:inmenu menubar:edit" msgid "&Group Models" msgstr "Modelle &gruppieren" -#: resources/qml/Actions.qml:358 +#: resources/qml/Actions.qml:360 msgctxt "@action:inmenu menubar:edit" msgid "Ungroup Models" msgstr "Gruppierung für Modelle aufheben" -#: resources/qml/Actions.qml:368 +#: resources/qml/Actions.qml:370 msgctxt "@action:inmenu menubar:edit" msgid "&Merge Models" msgstr "Modelle &zusammenführen" -#: resources/qml/Actions.qml:378 +#: resources/qml/Actions.qml:380 msgctxt "@action:inmenu" msgid "&Multiply Model..." msgstr "Modell &multiplizieren..." -#: resources/qml/Actions.qml:385 +#: resources/qml/Actions.qml:387 msgctxt "@action:inmenu menubar:edit" msgid "Select All Models" msgstr "Alle Modelle wählen" -#: resources/qml/Actions.qml:395 +#: resources/qml/Actions.qml:397 msgctxt "@action:inmenu menubar:edit" msgid "Clear Build Plate" msgstr "Druckplatte reinigen" -#: resources/qml/Actions.qml:405 +#: resources/qml/Actions.qml:407 msgctxt "@action:inmenu menubar:file" msgid "Reload All Models" msgstr "Alle Modelle neu laden" -#: resources/qml/Actions.qml:414 +#: resources/qml/Actions.qml:416 msgctxt "@action:inmenu menubar:edit" msgid "Arrange All Models" msgstr "Alle Modelle anordnen" -#: resources/qml/Actions.qml:422 +#: resources/qml/Actions.qml:424 +msgctxt "@action:inmenu menubar:edit" +msgid "Arrange All Models Without Rotation" +msgstr "" + +#: resources/qml/Actions.qml:431 msgctxt "@action:inmenu menubar:edit" msgid "Arrange Selection" msgstr "Anordnung auswählen" -#: resources/qml/Actions.qml:429 +#: resources/qml/Actions.qml:438 +msgctxt "@action:inmenu menubar:edit" +msgid "Arrange Selection Without Rotation" +msgstr "" + +#: resources/qml/Actions.qml:445 msgctxt "@action:inmenu menubar:edit" msgid "Reset All Model Positions" msgstr "Alle Modellpositionen zurücksetzen" -#: resources/qml/Actions.qml:436 +#: resources/qml/Actions.qml:452 msgctxt "@action:inmenu menubar:edit" msgid "Reset All Model Transformations" msgstr "Alle Modelltransformationen zurücksetzen" -#: resources/qml/Actions.qml:445 +#: resources/qml/Actions.qml:461 msgctxt "@action:inmenu menubar:file" msgid "&Open File(s)..." msgstr "&Datei(en) öffnen..." -#: resources/qml/Actions.qml:455 +#: resources/qml/Actions.qml:471 msgctxt "@action:inmenu menubar:file" msgid "&New Project..." msgstr "&Neues Projekt..." -#: resources/qml/Actions.qml:462 +#: resources/qml/Actions.qml:478 msgctxt "@action:inmenu menubar:help" msgid "Show Configuration Folder" msgstr "Konfigurationsordner anzeigen" -#: resources/qml/Actions.qml:469 resources/qml/Settings/SettingView.qml:476 +#: resources/qml/Actions.qml:485 resources/qml/Settings/SettingView.qml:476 msgctxt "@action:menu" msgid "Configure setting visibility..." msgstr "Sichtbarkeit einstellen wird konfiguriert..." @@ -5071,18 +5081,23 @@ msgid_plural "Print Selected Models With:" msgstr[0] "Ausgewähltes Modell drucken mit:" msgstr[1] "Ausgewählte Modelle drucken mit:" -#: resources/qml/Menus/ContextMenu.qml:92 +#: resources/qml/Menus/ContextMenu.qml:93 msgctxt "@title:window" msgid "Multiply Selected Model" msgid_plural "Multiply Selected Models" msgstr[0] "Ausgewähltes Modell multiplizieren" msgstr[1] "Ausgewählte Modelle multiplizieren" -#: resources/qml/Menus/ContextMenu.qml:123 +#: resources/qml/Menus/ContextMenu.qml:128 msgctxt "@label" msgid "Number of Copies" msgstr "Anzahl Kopien" +#: resources/qml/Menus/ContextMenu.qml:149 +msgctxt "@label" +msgid "Lock Rotation" +msgstr "" + #: resources/qml/Menus/EditMenu.qml:12 msgctxt "@title:menu menubar:toplevel" msgid "&Edit" diff --git a/resources/i18n/es_ES/cura.po b/resources/i18n/es_ES/cura.po index 991ce49f1e..f8f3eddb49 100644 --- a/resources/i18n/es_ES/cura.po +++ b/resources/i18n/es_ES/cura.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Cura 5.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-04-27 12:22+0000\n" +"POT-Creation-Date: 2023-05-11 14:19+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -22,22 +22,22 @@ msgctxt "@info:title" msgid "Login failed" msgstr "Fallo de inicio de sesión" -#: cura/Arranging/ArrangeObjectsJob.py:25 +#: cura/Arranging/ArrangeObjectsJob.py:27 msgctxt "@info:status" msgid "Finding new location for objects" msgstr "Buscando nueva ubicación para los objetos" -#: cura/Arranging/ArrangeObjectsJob.py:29 +#: cura/Arranging/ArrangeObjectsJob.py:31 msgctxt "@info:title" msgid "Finding Location" msgstr "Buscando ubicación" -#: cura/Arranging/ArrangeObjectsJob.py:42 cura/MultiplyObjectsJob.py:99 +#: cura/Arranging/ArrangeObjectsJob.py:45 cura/MultiplyObjectsJob.py:101 msgctxt "@info:status" msgid "Unable to find a location within the build volume for all objects" msgstr "No se puede encontrar una ubicación dentro del volumen de impresión para todos los objetos" -#: cura/Arranging/ArrangeObjectsJob.py:43 +#: cura/Arranging/ArrangeObjectsJob.py:46 msgctxt "@info:title" msgid "Can't Find Location" msgstr "No se puede encontrar la ubicación" @@ -264,25 +264,25 @@ msgctxt "@info 'width', 'depth' and 'height' are variable names that must NOT be msgid "%(width).1f x %(depth).1f x %(height).1f mm" msgstr "%(width).1f x %(depth).1f x %(height).1f mm" -#: cura/CuraApplication.py:1816 +#: cura/CuraApplication.py:1817 #, python-brace-format msgctxt "@info:status" msgid "Only one G-code file can be loaded at a time. Skipped importing {0}" msgstr "Solo se puede cargar un archivo GCode a la vez. Se omitió la importación de {0}" -#: cura/CuraApplication.py:1818 cura/OAuth2/AuthorizationService.py:217 +#: cura/CuraApplication.py:1819 cura/OAuth2/AuthorizationService.py:217 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:189 msgctxt "@info:title" msgid "Warning" msgstr "Advertencia" -#: cura/CuraApplication.py:1828 +#: cura/CuraApplication.py:1829 #, python-brace-format msgctxt "@info:status" msgid "Can't open any other file if G-code is loading. Skipped importing {0}" msgstr "No se puede abrir ningún archivo si se está cargando un archivo GCode. Se omitió la importación de {0}" -#: cura/CuraApplication.py:1830 cura/Settings/CuraContainerRegistry.py:156 +#: cura/CuraApplication.py:1831 cura/Settings/CuraContainerRegistry.py:156 #: cura/Settings/CuraContainerRegistry.py:166 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:153 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:173 @@ -409,17 +409,17 @@ msgctxt "@info:status" msgid "Calculated" msgstr "Calculado" -#: cura/MultiplyObjectsJob.py:30 +#: cura/MultiplyObjectsJob.py:31 msgctxt "@info:status" msgid "Multiplying and placing objects" msgstr "Multiplicar y colocar objetos" -#: cura/MultiplyObjectsJob.py:32 +#: cura/MultiplyObjectsJob.py:33 msgctxt "@info:title" msgid "Placing Objects" msgstr "Colocando objetos" -#: cura/MultiplyObjectsJob.py:100 +#: cura/MultiplyObjectsJob.py:102 msgctxt "@info:title" msgid "Placing Object" msgstr "Colocando objeto" @@ -3675,17 +3675,17 @@ msgctxt "@action:button" msgid "Remove printers" msgstr "Eliminar impresoras" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:62 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:63 msgctxt "@action:button Preceded by 'Ready to'." msgid "Print over network" msgstr "Imprimir a través de la red" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:63 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:64 msgctxt "@properties:tooltip" msgid "Print over network" msgstr "Imprime a través de la red" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:64 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:65 msgctxt "@info:status" msgid "Connected over the network" msgstr "Conectado a través de la red" @@ -4227,227 +4227,237 @@ msgctxt "@button" msgid "Cancel" msgstr "Cancelar" -#: resources/qml/Actions.qml:81 +#: resources/qml/Actions.qml:83 msgctxt "@action:inmenu" msgid "Show Online Troubleshooting" msgstr "Mostrar resolución de problemas online" -#: resources/qml/Actions.qml:88 +#: resources/qml/Actions.qml:90 msgctxt "@action:inmenu" msgid "Toggle Full Screen" msgstr "Alternar pantalla completa" -#: resources/qml/Actions.qml:96 +#: resources/qml/Actions.qml:98 msgctxt "@action:inmenu" msgid "Exit Full Screen" msgstr "Salir de modo de pantalla completa" -#: resources/qml/Actions.qml:103 +#: resources/qml/Actions.qml:105 msgctxt "@action:inmenu menubar:edit" msgid "&Undo" msgstr "Des&hacer" -#: resources/qml/Actions.qml:113 +#: resources/qml/Actions.qml:115 msgctxt "@action:inmenu menubar:edit" msgid "&Redo" msgstr "&Rehacer" -#: resources/qml/Actions.qml:131 +#: resources/qml/Actions.qml:133 msgctxt "@action:inmenu menubar:file" msgid "&Quit" msgstr "&Salir" -#: resources/qml/Actions.qml:139 +#: resources/qml/Actions.qml:141 msgctxt "@action:inmenu menubar:view" msgid "3D View" msgstr "Vista en 3D" -#: resources/qml/Actions.qml:146 +#: resources/qml/Actions.qml:148 msgctxt "@action:inmenu menubar:view" msgid "Front View" msgstr "Vista frontal" -#: resources/qml/Actions.qml:153 +#: resources/qml/Actions.qml:155 msgctxt "@action:inmenu menubar:view" msgid "Top View" msgstr "Vista superior" -#: resources/qml/Actions.qml:160 +#: resources/qml/Actions.qml:162 msgctxt "@action:inmenu menubar:view" msgid "Bottom View" msgstr "Vista inferior" -#: resources/qml/Actions.qml:167 +#: resources/qml/Actions.qml:169 msgctxt "@action:inmenu menubar:view" msgid "Left Side View" msgstr "Vista del lado izquierdo" -#: resources/qml/Actions.qml:174 +#: resources/qml/Actions.qml:176 msgctxt "@action:inmenu menubar:view" msgid "Right Side View" msgstr "Vista del lado derecho" -#: resources/qml/Actions.qml:188 +#: resources/qml/Actions.qml:190 msgctxt "@action:inmenu" msgid "Configure Cura..." msgstr "Configurar Cura..." -#: resources/qml/Actions.qml:197 +#: resources/qml/Actions.qml:199 msgctxt "@action:inmenu menubar:printer" msgid "&Add Printer..." msgstr "&Agregar impresora..." -#: resources/qml/Actions.qml:203 +#: resources/qml/Actions.qml:205 msgctxt "@action:inmenu menubar:printer" msgid "Manage Pr&inters..." msgstr "Adm&inistrar impresoras ..." -#: resources/qml/Actions.qml:210 +#: resources/qml/Actions.qml:212 msgctxt "@action:inmenu" msgid "Manage Materials..." msgstr "Administrar materiales..." -#: resources/qml/Actions.qml:218 +#: resources/qml/Actions.qml:220 msgctxt "@action:inmenu Marketplace is a brand name of UltiMaker's, so don't translate." msgid "Add more materials from Marketplace" msgstr "Añadir más materiales de Marketplace" -#: resources/qml/Actions.qml:225 +#: resources/qml/Actions.qml:227 msgctxt "@action:inmenu menubar:profile" msgid "&Update profile with current settings/overrides" msgstr "&Actualizar perfil con ajustes o sobrescrituras actuales" -#: resources/qml/Actions.qml:233 +#: resources/qml/Actions.qml:235 msgctxt "@action:inmenu menubar:profile" msgid "&Discard current changes" msgstr "&Descartar cambios actuales" -#: resources/qml/Actions.qml:245 +#: resources/qml/Actions.qml:247 msgctxt "@action:inmenu menubar:profile" msgid "&Create profile from current settings/overrides..." msgstr "&Crear perfil a partir de ajustes o sobrescrituras actuales..." -#: resources/qml/Actions.qml:251 +#: resources/qml/Actions.qml:253 msgctxt "@action:inmenu menubar:profile" msgid "Manage Profiles..." msgstr "Administrar perfiles..." -#: resources/qml/Actions.qml:259 +#: resources/qml/Actions.qml:261 msgctxt "@action:inmenu menubar:help" msgid "Show Online &Documentation" msgstr "Mostrar &documentación en línea" -#: resources/qml/Actions.qml:267 +#: resources/qml/Actions.qml:269 msgctxt "@action:inmenu menubar:help" msgid "Report a &Bug" msgstr "Informar de un &error" -#: resources/qml/Actions.qml:275 +#: resources/qml/Actions.qml:277 msgctxt "@action:inmenu menubar:help" msgid "What's New" msgstr "Novedades" -#: resources/qml/Actions.qml:289 +#: resources/qml/Actions.qml:291 msgctxt "@action:inmenu menubar:help" msgid "About..." msgstr "Acerca de..." -#: resources/qml/Actions.qml:296 +#: resources/qml/Actions.qml:298 msgctxt "@action:inmenu menubar:edit" msgid "Delete Selected" msgstr "Eliminar selección" -#: resources/qml/Actions.qml:306 +#: resources/qml/Actions.qml:308 msgctxt "@action:inmenu menubar:edit" msgid "Center Selected" msgstr "Centrar selección" -#: resources/qml/Actions.qml:315 +#: resources/qml/Actions.qml:317 msgctxt "@action:inmenu menubar:edit" msgid "Multiply Selected" msgstr "Multiplicar selección" -#: resources/qml/Actions.qml:324 +#: resources/qml/Actions.qml:326 msgctxt "@action:inmenu" msgid "Delete Model" msgstr "Eliminar modelo" -#: resources/qml/Actions.qml:332 +#: resources/qml/Actions.qml:334 msgctxt "@action:inmenu" msgid "Ce&nter Model on Platform" msgstr "Ce&ntrar modelo en plataforma" -#: resources/qml/Actions.qml:338 +#: resources/qml/Actions.qml:340 msgctxt "@action:inmenu menubar:edit" msgid "&Group Models" msgstr "A&grupar modelos" -#: resources/qml/Actions.qml:358 +#: resources/qml/Actions.qml:360 msgctxt "@action:inmenu menubar:edit" msgid "Ungroup Models" msgstr "Desagrupar modelos" -#: resources/qml/Actions.qml:368 +#: resources/qml/Actions.qml:370 msgctxt "@action:inmenu menubar:edit" msgid "&Merge Models" msgstr "Co&mbinar modelos" -#: resources/qml/Actions.qml:378 +#: resources/qml/Actions.qml:380 msgctxt "@action:inmenu" msgid "&Multiply Model..." msgstr "&Multiplicar modelo..." -#: resources/qml/Actions.qml:385 +#: resources/qml/Actions.qml:387 msgctxt "@action:inmenu menubar:edit" msgid "Select All Models" msgstr "Seleccionar todos los modelos" -#: resources/qml/Actions.qml:395 +#: resources/qml/Actions.qml:397 msgctxt "@action:inmenu menubar:edit" msgid "Clear Build Plate" msgstr "Borrar placa de impresión" -#: resources/qml/Actions.qml:405 +#: resources/qml/Actions.qml:407 msgctxt "@action:inmenu menubar:file" msgid "Reload All Models" msgstr "Recargar todos los modelos" -#: resources/qml/Actions.qml:414 +#: resources/qml/Actions.qml:416 msgctxt "@action:inmenu menubar:edit" msgid "Arrange All Models" msgstr "Organizar todos los modelos" -#: resources/qml/Actions.qml:422 +#: resources/qml/Actions.qml:424 +msgctxt "@action:inmenu menubar:edit" +msgid "Arrange All Models Without Rotation" +msgstr "" + +#: resources/qml/Actions.qml:431 msgctxt "@action:inmenu menubar:edit" msgid "Arrange Selection" msgstr "Organizar selección" -#: resources/qml/Actions.qml:429 +#: resources/qml/Actions.qml:438 +msgctxt "@action:inmenu menubar:edit" +msgid "Arrange Selection Without Rotation" +msgstr "" + +#: resources/qml/Actions.qml:445 msgctxt "@action:inmenu menubar:edit" msgid "Reset All Model Positions" msgstr "Restablecer las posiciones de todos los modelos" -#: resources/qml/Actions.qml:436 +#: resources/qml/Actions.qml:452 msgctxt "@action:inmenu menubar:edit" msgid "Reset All Model Transformations" msgstr "Restablecer las transformaciones de todos los modelos" -#: resources/qml/Actions.qml:445 +#: resources/qml/Actions.qml:461 msgctxt "@action:inmenu menubar:file" msgid "&Open File(s)..." msgstr "&Abrir archivo(s)..." -#: resources/qml/Actions.qml:455 +#: resources/qml/Actions.qml:471 msgctxt "@action:inmenu menubar:file" msgid "&New Project..." msgstr "&Nuevo proyecto..." -#: resources/qml/Actions.qml:462 +#: resources/qml/Actions.qml:478 msgctxt "@action:inmenu menubar:help" msgid "Show Configuration Folder" msgstr "Mostrar carpeta de configuración" -#: resources/qml/Actions.qml:469 resources/qml/Settings/SettingView.qml:476 +#: resources/qml/Actions.qml:485 resources/qml/Settings/SettingView.qml:476 msgctxt "@action:menu" msgid "Configure setting visibility..." msgstr "Configurar visibilidad de los ajustes..." @@ -5071,18 +5081,23 @@ msgid_plural "Print Selected Models With:" msgstr[0] "Imprimir modelo seleccionado con:" msgstr[1] "Imprimir modelos seleccionados con:" -#: resources/qml/Menus/ContextMenu.qml:92 +#: resources/qml/Menus/ContextMenu.qml:93 msgctxt "@title:window" msgid "Multiply Selected Model" msgid_plural "Multiply Selected Models" msgstr[0] "Multiplicar modelo seleccionado" msgstr[1] "Multiplicar modelos seleccionados" -#: resources/qml/Menus/ContextMenu.qml:123 +#: resources/qml/Menus/ContextMenu.qml:128 msgctxt "@label" msgid "Number of Copies" msgstr "Número de copias" +#: resources/qml/Menus/ContextMenu.qml:149 +msgctxt "@label" +msgid "Lock Rotation" +msgstr "" + #: resources/qml/Menus/EditMenu.qml:12 msgctxt "@title:menu menubar:toplevel" msgid "&Edit" diff --git a/resources/i18n/fi_FI/cura.po b/resources/i18n/fi_FI/cura.po index f2b4e4cbcb..95c45c0ea1 100644 --- a/resources/i18n/fi_FI/cura.po +++ b/resources/i18n/fi_FI/cura.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Cura 5.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-04-27 12:22+0000\n" +"POT-Creation-Date: 2023-05-11 14:19+0000\n" "PO-Revision-Date: 2022-07-15 10:53+0200\n" "Last-Translator: Bothof \n" "Language-Team: Finnish\n" @@ -23,22 +23,22 @@ msgctxt "@info:title" msgid "Login failed" msgstr "" -#: cura/Arranging/ArrangeObjectsJob.py:25 +#: cura/Arranging/ArrangeObjectsJob.py:27 msgctxt "@info:status" msgid "Finding new location for objects" msgstr "Uusien paikkojen etsiminen kappaleille" -#: cura/Arranging/ArrangeObjectsJob.py:29 +#: cura/Arranging/ArrangeObjectsJob.py:31 msgctxt "@info:title" msgid "Finding Location" msgstr "Etsitään paikkaa" -#: cura/Arranging/ArrangeObjectsJob.py:42 cura/MultiplyObjectsJob.py:99 +#: cura/Arranging/ArrangeObjectsJob.py:45 cura/MultiplyObjectsJob.py:101 msgctxt "@info:status" msgid "Unable to find a location within the build volume for all objects" msgstr "Kaikille kappaleille ei löydy paikkaa tulostustilavuudessa" -#: cura/Arranging/ArrangeObjectsJob.py:43 +#: cura/Arranging/ArrangeObjectsJob.py:46 msgctxt "@info:title" msgid "Can't Find Location" msgstr "Paikkaa ei löydy" @@ -257,25 +257,25 @@ msgctxt "@info 'width', 'depth' and 'height' are variable names that must NOT be msgid "%(width).1f x %(depth).1f x %(height).1f mm" msgstr "%(width).1f x %(depth).1f x %(height).1f mm" -#: cura/CuraApplication.py:1816 +#: cura/CuraApplication.py:1817 #, python-brace-format msgctxt "@info:status" msgid "Only one G-code file can be loaded at a time. Skipped importing {0}" msgstr "Vain yksi G-code-tiedosto voidaan ladata kerralla. Tiedoston {0} tuonti ohitettiin." -#: cura/CuraApplication.py:1818 cura/OAuth2/AuthorizationService.py:217 +#: cura/CuraApplication.py:1819 cura/OAuth2/AuthorizationService.py:217 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:189 msgctxt "@info:title" msgid "Warning" msgstr "Varoitus" -#: cura/CuraApplication.py:1828 +#: cura/CuraApplication.py:1829 #, python-brace-format msgctxt "@info:status" msgid "Can't open any other file if G-code is loading. Skipped importing {0}" msgstr "Muita tiedostoja ei voida ladata, kun G-code latautuu. Tiedoston {0} tuonti ohitettiin." -#: cura/CuraApplication.py:1830 cura/Settings/CuraContainerRegistry.py:156 +#: cura/CuraApplication.py:1831 cura/Settings/CuraContainerRegistry.py:156 #: cura/Settings/CuraContainerRegistry.py:166 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:153 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:173 @@ -402,17 +402,17 @@ msgctxt "@info:status" msgid "Calculated" msgstr "Laskettu" -#: cura/MultiplyObjectsJob.py:30 +#: cura/MultiplyObjectsJob.py:31 msgctxt "@info:status" msgid "Multiplying and placing objects" msgstr "Kappaleiden kertominen ja sijoittelu" -#: cura/MultiplyObjectsJob.py:32 +#: cura/MultiplyObjectsJob.py:33 msgctxt "@info:title" msgid "Placing Objects" msgstr "" -#: cura/MultiplyObjectsJob.py:100 +#: cura/MultiplyObjectsJob.py:102 msgctxt "@info:title" msgid "Placing Object" msgstr "Sijoitetaan kappaletta" @@ -3650,17 +3650,17 @@ msgctxt "@action:button" msgid "Remove printers" msgstr "" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:62 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:63 msgctxt "@action:button Preceded by 'Ready to'." msgid "Print over network" msgstr "Tulosta verkon kautta" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:63 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:64 msgctxt "@properties:tooltip" msgid "Print over network" msgstr "Tulosta verkon kautta" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:64 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:65 msgctxt "@info:status" msgid "Connected over the network" msgstr "" @@ -4199,227 +4199,237 @@ msgctxt "@button" msgid "Cancel" msgstr "" -#: resources/qml/Actions.qml:81 +#: resources/qml/Actions.qml:83 msgctxt "@action:inmenu" msgid "Show Online Troubleshooting" msgstr "" -#: resources/qml/Actions.qml:88 +#: resources/qml/Actions.qml:90 msgctxt "@action:inmenu" msgid "Toggle Full Screen" msgstr "Vaihda koko näyttöön" -#: resources/qml/Actions.qml:96 +#: resources/qml/Actions.qml:98 msgctxt "@action:inmenu" msgid "Exit Full Screen" msgstr "" -#: resources/qml/Actions.qml:103 +#: resources/qml/Actions.qml:105 msgctxt "@action:inmenu menubar:edit" msgid "&Undo" msgstr "&Kumoa" -#: resources/qml/Actions.qml:113 +#: resources/qml/Actions.qml:115 msgctxt "@action:inmenu menubar:edit" msgid "&Redo" msgstr "Tee &uudelleen" -#: resources/qml/Actions.qml:131 +#: resources/qml/Actions.qml:133 msgctxt "@action:inmenu menubar:file" msgid "&Quit" msgstr "&Lopeta" -#: resources/qml/Actions.qml:139 +#: resources/qml/Actions.qml:141 msgctxt "@action:inmenu menubar:view" msgid "3D View" msgstr "" -#: resources/qml/Actions.qml:146 +#: resources/qml/Actions.qml:148 msgctxt "@action:inmenu menubar:view" msgid "Front View" msgstr "" -#: resources/qml/Actions.qml:153 +#: resources/qml/Actions.qml:155 msgctxt "@action:inmenu menubar:view" msgid "Top View" msgstr "" -#: resources/qml/Actions.qml:160 +#: resources/qml/Actions.qml:162 msgctxt "@action:inmenu menubar:view" msgid "Bottom View" msgstr "" -#: resources/qml/Actions.qml:167 +#: resources/qml/Actions.qml:169 msgctxt "@action:inmenu menubar:view" msgid "Left Side View" msgstr "" -#: resources/qml/Actions.qml:174 +#: resources/qml/Actions.qml:176 msgctxt "@action:inmenu menubar:view" msgid "Right Side View" msgstr "" -#: resources/qml/Actions.qml:188 +#: resources/qml/Actions.qml:190 msgctxt "@action:inmenu" msgid "Configure Cura..." msgstr "Määritä Curan asetukset..." -#: resources/qml/Actions.qml:197 +#: resources/qml/Actions.qml:199 msgctxt "@action:inmenu menubar:printer" msgid "&Add Printer..." msgstr "L&isää tulostin..." -#: resources/qml/Actions.qml:203 +#: resources/qml/Actions.qml:205 msgctxt "@action:inmenu menubar:printer" msgid "Manage Pr&inters..." msgstr "Tulostinten &hallinta..." -#: resources/qml/Actions.qml:210 +#: resources/qml/Actions.qml:212 msgctxt "@action:inmenu" msgid "Manage Materials..." msgstr "Hallitse materiaaleja..." -#: resources/qml/Actions.qml:218 +#: resources/qml/Actions.qml:220 msgctxt "@action:inmenu Marketplace is a brand name of UltiMaker's, so don't translate." msgid "Add more materials from Marketplace" msgstr "" -#: resources/qml/Actions.qml:225 +#: resources/qml/Actions.qml:227 msgctxt "@action:inmenu menubar:profile" msgid "&Update profile with current settings/overrides" msgstr "&Päivitä nykyiset asetukset tai ohitukset profiiliin" -#: resources/qml/Actions.qml:233 +#: resources/qml/Actions.qml:235 msgctxt "@action:inmenu menubar:profile" msgid "&Discard current changes" msgstr "&Hylkää tehdyt muutokset" -#: resources/qml/Actions.qml:245 +#: resources/qml/Actions.qml:247 msgctxt "@action:inmenu menubar:profile" msgid "&Create profile from current settings/overrides..." msgstr "&Luo profiili nykyisten asetusten tai ohitusten perusteella..." -#: resources/qml/Actions.qml:251 +#: resources/qml/Actions.qml:253 msgctxt "@action:inmenu menubar:profile" msgid "Manage Profiles..." msgstr "Profiilien hallinta..." -#: resources/qml/Actions.qml:259 +#: resources/qml/Actions.qml:261 msgctxt "@action:inmenu menubar:help" msgid "Show Online &Documentation" msgstr "Näytä sähköinen &dokumentaatio" -#: resources/qml/Actions.qml:267 +#: resources/qml/Actions.qml:269 msgctxt "@action:inmenu menubar:help" msgid "Report a &Bug" msgstr "Ilmoita &virheestä" -#: resources/qml/Actions.qml:275 +#: resources/qml/Actions.qml:277 msgctxt "@action:inmenu menubar:help" msgid "What's New" msgstr "" -#: resources/qml/Actions.qml:289 +#: resources/qml/Actions.qml:291 msgctxt "@action:inmenu menubar:help" msgid "About..." msgstr "Tietoja..." -#: resources/qml/Actions.qml:296 +#: resources/qml/Actions.qml:298 msgctxt "@action:inmenu menubar:edit" msgid "Delete Selected" msgstr "" -#: resources/qml/Actions.qml:306 +#: resources/qml/Actions.qml:308 msgctxt "@action:inmenu menubar:edit" msgid "Center Selected" msgstr "" -#: resources/qml/Actions.qml:315 +#: resources/qml/Actions.qml:317 msgctxt "@action:inmenu menubar:edit" msgid "Multiply Selected" msgstr "" -#: resources/qml/Actions.qml:324 +#: resources/qml/Actions.qml:326 msgctxt "@action:inmenu" msgid "Delete Model" msgstr "Poista malli" -#: resources/qml/Actions.qml:332 +#: resources/qml/Actions.qml:334 msgctxt "@action:inmenu" msgid "Ce&nter Model on Platform" msgstr "Ke&skitä malli alustalle" -#: resources/qml/Actions.qml:338 +#: resources/qml/Actions.qml:340 msgctxt "@action:inmenu menubar:edit" msgid "&Group Models" msgstr "&Ryhmittele mallit" -#: resources/qml/Actions.qml:358 +#: resources/qml/Actions.qml:360 msgctxt "@action:inmenu menubar:edit" msgid "Ungroup Models" msgstr "Poista mallien ryhmitys" -#: resources/qml/Actions.qml:368 +#: resources/qml/Actions.qml:370 msgctxt "@action:inmenu menubar:edit" msgid "&Merge Models" msgstr "&Yhdistä mallit" -#: resources/qml/Actions.qml:378 +#: resources/qml/Actions.qml:380 msgctxt "@action:inmenu" msgid "&Multiply Model..." msgstr "&Kerro malli..." -#: resources/qml/Actions.qml:385 +#: resources/qml/Actions.qml:387 msgctxt "@action:inmenu menubar:edit" msgid "Select All Models" msgstr "Valitse kaikki mallit" -#: resources/qml/Actions.qml:395 +#: resources/qml/Actions.qml:397 msgctxt "@action:inmenu menubar:edit" msgid "Clear Build Plate" msgstr "Tyhjennä tulostusalusta" -#: resources/qml/Actions.qml:405 +#: resources/qml/Actions.qml:407 msgctxt "@action:inmenu menubar:file" msgid "Reload All Models" msgstr "Lataa kaikki mallit uudelleen" -#: resources/qml/Actions.qml:414 +#: resources/qml/Actions.qml:416 msgctxt "@action:inmenu menubar:edit" msgid "Arrange All Models" msgstr "Järjestä kaikki mallit" -#: resources/qml/Actions.qml:422 +#: resources/qml/Actions.qml:424 +msgctxt "@action:inmenu menubar:edit" +msgid "Arrange All Models Without Rotation" +msgstr "" + +#: resources/qml/Actions.qml:431 msgctxt "@action:inmenu menubar:edit" msgid "Arrange Selection" msgstr "Järjestä valinta" -#: resources/qml/Actions.qml:429 +#: resources/qml/Actions.qml:438 +msgctxt "@action:inmenu menubar:edit" +msgid "Arrange Selection Without Rotation" +msgstr "" + +#: resources/qml/Actions.qml:445 msgctxt "@action:inmenu menubar:edit" msgid "Reset All Model Positions" msgstr "Määritä kaikkien mallien positiot uudelleen" -#: resources/qml/Actions.qml:436 +#: resources/qml/Actions.qml:452 msgctxt "@action:inmenu menubar:edit" msgid "Reset All Model Transformations" msgstr "Määritä kaikkien mallien muutokset uudelleen" -#: resources/qml/Actions.qml:445 +#: resources/qml/Actions.qml:461 msgctxt "@action:inmenu menubar:file" msgid "&Open File(s)..." msgstr "&Avaa tiedosto(t)..." -#: resources/qml/Actions.qml:455 +#: resources/qml/Actions.qml:471 msgctxt "@action:inmenu menubar:file" msgid "&New Project..." msgstr "&Uusi projekti..." -#: resources/qml/Actions.qml:462 +#: resources/qml/Actions.qml:478 msgctxt "@action:inmenu menubar:help" msgid "Show Configuration Folder" msgstr "Näytä määrityskansio" -#: resources/qml/Actions.qml:469 resources/qml/Settings/SettingView.qml:476 +#: resources/qml/Actions.qml:485 resources/qml/Settings/SettingView.qml:476 msgctxt "@action:menu" msgid "Configure setting visibility..." msgstr "Määritä asetusten näkyvyys..." @@ -5040,18 +5050,23 @@ msgid_plural "Print Selected Models With:" msgstr[0] "Tulosta valittu malli asetuksella:" msgstr[1] "Tulosta valitut mallit asetuksella:" -#: resources/qml/Menus/ContextMenu.qml:92 +#: resources/qml/Menus/ContextMenu.qml:93 msgctxt "@title:window" msgid "Multiply Selected Model" msgid_plural "Multiply Selected Models" msgstr[0] "Kerro valittu malli" msgstr[1] "Kerro valitut mallit" -#: resources/qml/Menus/ContextMenu.qml:123 +#: resources/qml/Menus/ContextMenu.qml:128 msgctxt "@label" msgid "Number of Copies" msgstr "Kopioiden määrä" +#: resources/qml/Menus/ContextMenu.qml:149 +msgctxt "@label" +msgid "Lock Rotation" +msgstr "" + #: resources/qml/Menus/EditMenu.qml:12 msgctxt "@title:menu menubar:toplevel" msgid "&Edit" diff --git a/resources/i18n/fr_FR/cura.po b/resources/i18n/fr_FR/cura.po index ea1d51cd5a..e496faed64 100644 --- a/resources/i18n/fr_FR/cura.po +++ b/resources/i18n/fr_FR/cura.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-04-27 12:22+0000\n" +"POT-Creation-Date: 2023-05-11 14:19+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -23,22 +23,22 @@ msgctxt "@info:title" msgid "Login failed" msgstr "La connexion a échoué" -#: cura/Arranging/ArrangeObjectsJob.py:25 +#: cura/Arranging/ArrangeObjectsJob.py:27 msgctxt "@info:status" msgid "Finding new location for objects" msgstr "Recherche d'un nouvel emplacement pour les objets" -#: cura/Arranging/ArrangeObjectsJob.py:29 +#: cura/Arranging/ArrangeObjectsJob.py:31 msgctxt "@info:title" msgid "Finding Location" msgstr "Recherche d'emplacement" -#: cura/Arranging/ArrangeObjectsJob.py:42 cura/MultiplyObjectsJob.py:99 +#: cura/Arranging/ArrangeObjectsJob.py:45 cura/MultiplyObjectsJob.py:101 msgctxt "@info:status" msgid "Unable to find a location within the build volume for all objects" msgstr "Impossible de trouver un emplacement dans le volume d'impression pour tous les objets" -#: cura/Arranging/ArrangeObjectsJob.py:43 +#: cura/Arranging/ArrangeObjectsJob.py:46 msgctxt "@info:title" msgid "Can't Find Location" msgstr "Impossible de trouver un emplacement" @@ -265,25 +265,25 @@ msgctxt "@info 'width', 'depth' and 'height' are variable names that must NOT be msgid "%(width).1f x %(depth).1f x %(height).1f mm" msgstr "%(width).1f x %(depth).1f x %(height).1f mm" -#: cura/CuraApplication.py:1816 +#: cura/CuraApplication.py:1817 #, python-brace-format msgctxt "@info:status" msgid "Only one G-code file can be loaded at a time. Skipped importing {0}" msgstr "Un seul fichier G-Code peut être chargé à la fois. Importation de {0} sautée" -#: cura/CuraApplication.py:1818 cura/OAuth2/AuthorizationService.py:217 +#: cura/CuraApplication.py:1819 cura/OAuth2/AuthorizationService.py:217 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:189 msgctxt "@info:title" msgid "Warning" msgstr "Avertissement" -#: cura/CuraApplication.py:1828 +#: cura/CuraApplication.py:1829 #, python-brace-format msgctxt "@info:status" msgid "Can't open any other file if G-code is loading. Skipped importing {0}" msgstr "Impossible d'ouvrir un autre fichier si le G-Code est en cours de chargement. Importation de {0} sautée" -#: cura/CuraApplication.py:1830 cura/Settings/CuraContainerRegistry.py:156 +#: cura/CuraApplication.py:1831 cura/Settings/CuraContainerRegistry.py:156 #: cura/Settings/CuraContainerRegistry.py:166 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:153 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:173 @@ -410,17 +410,17 @@ msgctxt "@info:status" msgid "Calculated" msgstr "Calculer" -#: cura/MultiplyObjectsJob.py:30 +#: cura/MultiplyObjectsJob.py:31 msgctxt "@info:status" msgid "Multiplying and placing objects" msgstr "Multiplication et placement d'objets" -#: cura/MultiplyObjectsJob.py:32 +#: cura/MultiplyObjectsJob.py:33 msgctxt "@info:title" msgid "Placing Objects" msgstr "Placement des objets" -#: cura/MultiplyObjectsJob.py:100 +#: cura/MultiplyObjectsJob.py:102 msgctxt "@info:title" msgid "Placing Object" msgstr "Placement de l'objet" @@ -3678,17 +3678,17 @@ msgctxt "@action:button" msgid "Remove printers" msgstr "Supprimer des imprimantes" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:62 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:63 msgctxt "@action:button Preceded by 'Ready to'." msgid "Print over network" msgstr "Imprimer sur le réseau" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:63 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:64 msgctxt "@properties:tooltip" msgid "Print over network" msgstr "Imprimer sur le réseau" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:64 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:65 msgctxt "@info:status" msgid "Connected over the network" msgstr "Connecté sur le réseau" @@ -4227,227 +4227,237 @@ msgctxt "@button" msgid "Cancel" msgstr "Annuler" -#: resources/qml/Actions.qml:81 +#: resources/qml/Actions.qml:83 msgctxt "@action:inmenu" msgid "Show Online Troubleshooting" msgstr "Afficher le dépannage en ligne" -#: resources/qml/Actions.qml:88 +#: resources/qml/Actions.qml:90 msgctxt "@action:inmenu" msgid "Toggle Full Screen" msgstr "Passer en Plein écran" -#: resources/qml/Actions.qml:96 +#: resources/qml/Actions.qml:98 msgctxt "@action:inmenu" msgid "Exit Full Screen" msgstr "Quitter le mode plein écran" -#: resources/qml/Actions.qml:103 +#: resources/qml/Actions.qml:105 msgctxt "@action:inmenu menubar:edit" msgid "&Undo" msgstr "&Annuler" -#: resources/qml/Actions.qml:113 +#: resources/qml/Actions.qml:115 msgctxt "@action:inmenu menubar:edit" msgid "&Redo" msgstr "&Rétablir" -#: resources/qml/Actions.qml:131 +#: resources/qml/Actions.qml:133 msgctxt "@action:inmenu menubar:file" msgid "&Quit" msgstr "&Quitter" -#: resources/qml/Actions.qml:139 +#: resources/qml/Actions.qml:141 msgctxt "@action:inmenu menubar:view" msgid "3D View" msgstr "Vue 3D" -#: resources/qml/Actions.qml:146 +#: resources/qml/Actions.qml:148 msgctxt "@action:inmenu menubar:view" msgid "Front View" msgstr "Vue de face" -#: resources/qml/Actions.qml:153 +#: resources/qml/Actions.qml:155 msgctxt "@action:inmenu menubar:view" msgid "Top View" msgstr "Vue du dessus" -#: resources/qml/Actions.qml:160 +#: resources/qml/Actions.qml:162 msgctxt "@action:inmenu menubar:view" msgid "Bottom View" msgstr "Vue de dessous" -#: resources/qml/Actions.qml:167 +#: resources/qml/Actions.qml:169 msgctxt "@action:inmenu menubar:view" msgid "Left Side View" msgstr "Vue latérale gauche" -#: resources/qml/Actions.qml:174 +#: resources/qml/Actions.qml:176 msgctxt "@action:inmenu menubar:view" msgid "Right Side View" msgstr "Vue latérale droite" -#: resources/qml/Actions.qml:188 +#: resources/qml/Actions.qml:190 msgctxt "@action:inmenu" msgid "Configure Cura..." msgstr "Configurer Cura..." -#: resources/qml/Actions.qml:197 +#: resources/qml/Actions.qml:199 msgctxt "@action:inmenu menubar:printer" msgid "&Add Printer..." msgstr "&Ajouter une imprimante..." -#: resources/qml/Actions.qml:203 +#: resources/qml/Actions.qml:205 msgctxt "@action:inmenu menubar:printer" msgid "Manage Pr&inters..." msgstr "Gérer les &imprimantes..." -#: resources/qml/Actions.qml:210 +#: resources/qml/Actions.qml:212 msgctxt "@action:inmenu" msgid "Manage Materials..." msgstr "Gérer les matériaux..." -#: resources/qml/Actions.qml:218 +#: resources/qml/Actions.qml:220 msgctxt "@action:inmenu Marketplace is a brand name of UltiMaker's, so don't translate." msgid "Add more materials from Marketplace" msgstr "Ajouter d'autres matériaux depuis la Marketplace" -#: resources/qml/Actions.qml:225 +#: resources/qml/Actions.qml:227 msgctxt "@action:inmenu menubar:profile" msgid "&Update profile with current settings/overrides" msgstr "&Mettre à jour le profil à l'aide des paramètres / forçages actuels" -#: resources/qml/Actions.qml:233 +#: resources/qml/Actions.qml:235 msgctxt "@action:inmenu menubar:profile" msgid "&Discard current changes" msgstr "&Ignorer les modifications actuelles" -#: resources/qml/Actions.qml:245 +#: resources/qml/Actions.qml:247 msgctxt "@action:inmenu menubar:profile" msgid "&Create profile from current settings/overrides..." msgstr "&Créer un profil à partir des paramètres / forçages actuels..." -#: resources/qml/Actions.qml:251 +#: resources/qml/Actions.qml:253 msgctxt "@action:inmenu menubar:profile" msgid "Manage Profiles..." msgstr "Gérer les profils..." -#: resources/qml/Actions.qml:259 +#: resources/qml/Actions.qml:261 msgctxt "@action:inmenu menubar:help" msgid "Show Online &Documentation" msgstr "Afficher la &documentation en ligne" -#: resources/qml/Actions.qml:267 +#: resources/qml/Actions.qml:269 msgctxt "@action:inmenu menubar:help" msgid "Report a &Bug" msgstr "Notifier un &bug" -#: resources/qml/Actions.qml:275 +#: resources/qml/Actions.qml:277 msgctxt "@action:inmenu menubar:help" msgid "What's New" msgstr "Quoi de neuf" -#: resources/qml/Actions.qml:289 +#: resources/qml/Actions.qml:291 msgctxt "@action:inmenu menubar:help" msgid "About..." msgstr "À propos de..." -#: resources/qml/Actions.qml:296 +#: resources/qml/Actions.qml:298 msgctxt "@action:inmenu menubar:edit" msgid "Delete Selected" msgstr "Supprimer la sélection" -#: resources/qml/Actions.qml:306 +#: resources/qml/Actions.qml:308 msgctxt "@action:inmenu menubar:edit" msgid "Center Selected" msgstr "Centrer la sélection" -#: resources/qml/Actions.qml:315 +#: resources/qml/Actions.qml:317 msgctxt "@action:inmenu menubar:edit" msgid "Multiply Selected" msgstr "Multiplier la sélection" -#: resources/qml/Actions.qml:324 +#: resources/qml/Actions.qml:326 msgctxt "@action:inmenu" msgid "Delete Model" msgstr "Supprimer le modèle" -#: resources/qml/Actions.qml:332 +#: resources/qml/Actions.qml:334 msgctxt "@action:inmenu" msgid "Ce&nter Model on Platform" msgstr "Ce&ntrer le modèle sur le plateau" -#: resources/qml/Actions.qml:338 +#: resources/qml/Actions.qml:340 msgctxt "@action:inmenu menubar:edit" msgid "&Group Models" msgstr "&Grouper les modèles" -#: resources/qml/Actions.qml:358 +#: resources/qml/Actions.qml:360 msgctxt "@action:inmenu menubar:edit" msgid "Ungroup Models" msgstr "Dégrouper les modèles" -#: resources/qml/Actions.qml:368 +#: resources/qml/Actions.qml:370 msgctxt "@action:inmenu menubar:edit" msgid "&Merge Models" msgstr "&Fusionner les modèles" -#: resources/qml/Actions.qml:378 +#: resources/qml/Actions.qml:380 msgctxt "@action:inmenu" msgid "&Multiply Model..." msgstr "&Multiplier le modèle..." -#: resources/qml/Actions.qml:385 +#: resources/qml/Actions.qml:387 msgctxt "@action:inmenu menubar:edit" msgid "Select All Models" msgstr "Sélectionner tous les modèles" -#: resources/qml/Actions.qml:395 +#: resources/qml/Actions.qml:397 msgctxt "@action:inmenu menubar:edit" msgid "Clear Build Plate" msgstr "Supprimer les modèles du plateau" -#: resources/qml/Actions.qml:405 +#: resources/qml/Actions.qml:407 msgctxt "@action:inmenu menubar:file" msgid "Reload All Models" msgstr "Recharger tous les modèles" -#: resources/qml/Actions.qml:414 +#: resources/qml/Actions.qml:416 msgctxt "@action:inmenu menubar:edit" msgid "Arrange All Models" msgstr "Réorganiser tous les modèles" -#: resources/qml/Actions.qml:422 +#: resources/qml/Actions.qml:424 +msgctxt "@action:inmenu menubar:edit" +msgid "Arrange All Models Without Rotation" +msgstr "" + +#: resources/qml/Actions.qml:431 msgctxt "@action:inmenu menubar:edit" msgid "Arrange Selection" msgstr "Réorganiser la sélection" -#: resources/qml/Actions.qml:429 +#: resources/qml/Actions.qml:438 +msgctxt "@action:inmenu menubar:edit" +msgid "Arrange Selection Without Rotation" +msgstr "" + +#: resources/qml/Actions.qml:445 msgctxt "@action:inmenu menubar:edit" msgid "Reset All Model Positions" msgstr "Réinitialiser toutes les positions des modèles" -#: resources/qml/Actions.qml:436 +#: resources/qml/Actions.qml:452 msgctxt "@action:inmenu menubar:edit" msgid "Reset All Model Transformations" msgstr "Réinitialiser tous les modèles et transformations" -#: resources/qml/Actions.qml:445 +#: resources/qml/Actions.qml:461 msgctxt "@action:inmenu menubar:file" msgid "&Open File(s)..." msgstr "&Ouvrir le(s) fichier(s)..." -#: resources/qml/Actions.qml:455 +#: resources/qml/Actions.qml:471 msgctxt "@action:inmenu menubar:file" msgid "&New Project..." msgstr "&Nouveau projet..." -#: resources/qml/Actions.qml:462 +#: resources/qml/Actions.qml:478 msgctxt "@action:inmenu menubar:help" msgid "Show Configuration Folder" msgstr "Afficher le dossier de configuration" -#: resources/qml/Actions.qml:469 resources/qml/Settings/SettingView.qml:476 +#: resources/qml/Actions.qml:485 resources/qml/Settings/SettingView.qml:476 msgctxt "@action:menu" msgid "Configure setting visibility..." msgstr "Configurer la visibilité des paramètres..." @@ -5071,18 +5081,23 @@ msgid_plural "Print Selected Models With:" msgstr[0] "Imprimer le modèle sélectionné avec :" msgstr[1] "Imprimer les modèles sélectionnés avec :" -#: resources/qml/Menus/ContextMenu.qml:92 +#: resources/qml/Menus/ContextMenu.qml:93 msgctxt "@title:window" msgid "Multiply Selected Model" msgid_plural "Multiply Selected Models" msgstr[0] "Multiplier le modèle sélectionné" msgstr[1] "Multiplier les modèles sélectionnés" -#: resources/qml/Menus/ContextMenu.qml:123 +#: resources/qml/Menus/ContextMenu.qml:128 msgctxt "@label" msgid "Number of Copies" msgstr "Nombre de copies" +#: resources/qml/Menus/ContextMenu.qml:149 +msgctxt "@label" +msgid "Lock Rotation" +msgstr "" + #: resources/qml/Menus/EditMenu.qml:12 msgctxt "@title:menu menubar:toplevel" msgid "&Edit" diff --git a/resources/i18n/hu_HU/cura.po b/resources/i18n/hu_HU/cura.po index 9ea5ca5aea..06e99060f7 100644 --- a/resources/i18n/hu_HU/cura.po +++ b/resources/i18n/hu_HU/cura.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Cura 5.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-04-27 12:22+0000\n" +"POT-Creation-Date: 2023-05-11 14:19+0000\n" "PO-Revision-Date: 2020-03-24 09:36+0100\n" "Last-Translator: Nagy Attila \n" "Language-Team: ATI-SZOFT\n" @@ -23,22 +23,22 @@ msgctxt "@info:title" msgid "Login failed" msgstr "Sikertelen bejelentkezés" -#: cura/Arranging/ArrangeObjectsJob.py:25 +#: cura/Arranging/ArrangeObjectsJob.py:27 msgctxt "@info:status" msgid "Finding new location for objects" msgstr "Új hely keresése az objektumokhoz" -#: cura/Arranging/ArrangeObjectsJob.py:29 +#: cura/Arranging/ArrangeObjectsJob.py:31 msgctxt "@info:title" msgid "Finding Location" msgstr "Hely keresés" -#: cura/Arranging/ArrangeObjectsJob.py:42 cura/MultiplyObjectsJob.py:99 +#: cura/Arranging/ArrangeObjectsJob.py:45 cura/MultiplyObjectsJob.py:101 msgctxt "@info:status" msgid "Unable to find a location within the build volume for all objects" msgstr "Nincs elég hely az összes objektum építési térfogatához" -#: cura/Arranging/ArrangeObjectsJob.py:43 +#: cura/Arranging/ArrangeObjectsJob.py:46 msgctxt "@info:title" msgid "Can't Find Location" msgstr "Nem találok helyet" @@ -265,25 +265,25 @@ msgctxt "@info 'width', 'depth' and 'height' are variable names that must NOT be msgid "%(width).1f x %(depth).1f x %(height).1f mm" msgstr "%(width).1f x %(depth).1f x %(height).1f mm" -#: cura/CuraApplication.py:1816 +#: cura/CuraApplication.py:1817 #, python-brace-format msgctxt "@info:status" msgid "Only one G-code file can be loaded at a time. Skipped importing {0}" msgstr "Egyszerre csak egy G-kód fájlt lehet betölteni. Az importálás kihagyva {0}" -#: cura/CuraApplication.py:1818 cura/OAuth2/AuthorizationService.py:217 +#: cura/CuraApplication.py:1819 cura/OAuth2/AuthorizationService.py:217 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:189 msgctxt "@info:title" msgid "Warning" msgstr "Figyelem" -#: cura/CuraApplication.py:1828 +#: cura/CuraApplication.py:1829 #, python-brace-format msgctxt "@info:status" msgid "Can't open any other file if G-code is loading. Skipped importing {0}" msgstr "Nem nyitható meg más fájl, ha a G-kód betöltődik. Az importálás kihagyva {0}" -#: cura/CuraApplication.py:1830 cura/Settings/CuraContainerRegistry.py:156 +#: cura/CuraApplication.py:1831 cura/Settings/CuraContainerRegistry.py:156 #: cura/Settings/CuraContainerRegistry.py:166 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:153 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:173 @@ -410,17 +410,17 @@ msgctxt "@info:status" msgid "Calculated" msgstr "Számított" -#: cura/MultiplyObjectsJob.py:30 +#: cura/MultiplyObjectsJob.py:31 msgctxt "@info:status" msgid "Multiplying and placing objects" msgstr "Tárgyak többszörözése és elhelyezése" -#: cura/MultiplyObjectsJob.py:32 +#: cura/MultiplyObjectsJob.py:33 msgctxt "@info:title" msgid "Placing Objects" msgstr "Tárgyak elhelyezése" -#: cura/MultiplyObjectsJob.py:100 +#: cura/MultiplyObjectsJob.py:102 msgctxt "@info:title" msgid "Placing Object" msgstr "Tárgy elhelyezése" @@ -3666,17 +3666,17 @@ msgctxt "@action:button" msgid "Remove printers" msgstr "" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:62 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:63 msgctxt "@action:button Preceded by 'Ready to'." msgid "Print over network" msgstr "Hálózati nyomtatás" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:63 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:64 msgctxt "@properties:tooltip" msgid "Print over network" msgstr "Hálózati nyomtatás" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:64 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:65 msgctxt "@info:status" msgid "Connected over the network" msgstr "Csatlakozva hálózaton keresztül" @@ -4215,227 +4215,237 @@ msgctxt "@button" msgid "Cancel" msgstr "Elvet" -#: resources/qml/Actions.qml:81 +#: resources/qml/Actions.qml:83 msgctxt "@action:inmenu" msgid "Show Online Troubleshooting" msgstr "" -#: resources/qml/Actions.qml:88 +#: resources/qml/Actions.qml:90 msgctxt "@action:inmenu" msgid "Toggle Full Screen" msgstr "Teljes képernyőre váltás" -#: resources/qml/Actions.qml:96 +#: resources/qml/Actions.qml:98 msgctxt "@action:inmenu" msgid "Exit Full Screen" msgstr "Kilépés a teljes képernyőn" -#: resources/qml/Actions.qml:103 +#: resources/qml/Actions.qml:105 msgctxt "@action:inmenu menubar:edit" msgid "&Undo" msgstr "&Visszavon" -#: resources/qml/Actions.qml:113 +#: resources/qml/Actions.qml:115 msgctxt "@action:inmenu menubar:edit" msgid "&Redo" msgstr "&Újra" -#: resources/qml/Actions.qml:131 +#: resources/qml/Actions.qml:133 msgctxt "@action:inmenu menubar:file" msgid "&Quit" msgstr "Kilép" -#: resources/qml/Actions.qml:139 +#: resources/qml/Actions.qml:141 msgctxt "@action:inmenu menubar:view" msgid "3D View" msgstr "3D nézet" -#: resources/qml/Actions.qml:146 +#: resources/qml/Actions.qml:148 msgctxt "@action:inmenu menubar:view" msgid "Front View" msgstr "Előlnézet" -#: resources/qml/Actions.qml:153 +#: resources/qml/Actions.qml:155 msgctxt "@action:inmenu menubar:view" msgid "Top View" msgstr "Felülnézet" -#: resources/qml/Actions.qml:160 +#: resources/qml/Actions.qml:162 msgctxt "@action:inmenu menubar:view" msgid "Bottom View" msgstr "" -#: resources/qml/Actions.qml:167 +#: resources/qml/Actions.qml:169 msgctxt "@action:inmenu menubar:view" msgid "Left Side View" msgstr "Bal oldalnézet" -#: resources/qml/Actions.qml:174 +#: resources/qml/Actions.qml:176 msgctxt "@action:inmenu menubar:view" msgid "Right Side View" msgstr "Jobb oldalnézet" -#: resources/qml/Actions.qml:188 +#: resources/qml/Actions.qml:190 msgctxt "@action:inmenu" msgid "Configure Cura..." msgstr "Cura beállítása..." -#: resources/qml/Actions.qml:197 +#: resources/qml/Actions.qml:199 msgctxt "@action:inmenu menubar:printer" msgid "&Add Printer..." msgstr "&Nyomtató hozzáadása..." -#: resources/qml/Actions.qml:203 +#: resources/qml/Actions.qml:205 msgctxt "@action:inmenu menubar:printer" msgid "Manage Pr&inters..." msgstr "Nyomtatók kezelése..." -#: resources/qml/Actions.qml:210 +#: resources/qml/Actions.qml:212 msgctxt "@action:inmenu" msgid "Manage Materials..." msgstr "Anyagok kezelése..." -#: resources/qml/Actions.qml:218 +#: resources/qml/Actions.qml:220 msgctxt "@action:inmenu Marketplace is a brand name of UltiMaker's, so don't translate." msgid "Add more materials from Marketplace" msgstr "" -#: resources/qml/Actions.qml:225 +#: resources/qml/Actions.qml:227 msgctxt "@action:inmenu menubar:profile" msgid "&Update profile with current settings/overrides" msgstr "Profil &frissítése a jelenlegi beállításokkal/felülírásokkal" -#: resources/qml/Actions.qml:233 +#: resources/qml/Actions.qml:235 msgctxt "@action:inmenu menubar:profile" msgid "&Discard current changes" msgstr "&Jelenlegi változtatások eldobása" -#: resources/qml/Actions.qml:245 +#: resources/qml/Actions.qml:247 msgctxt "@action:inmenu menubar:profile" msgid "&Create profile from current settings/overrides..." msgstr "Profil &létrehozása a jelenlegi beállításokkal/felülírásokkal..." -#: resources/qml/Actions.qml:251 +#: resources/qml/Actions.qml:253 msgctxt "@action:inmenu menubar:profile" msgid "Manage Profiles..." msgstr "Profilok kezelése..." -#: resources/qml/Actions.qml:259 +#: resources/qml/Actions.qml:261 msgctxt "@action:inmenu menubar:help" msgid "Show Online &Documentation" msgstr "Online &Dokumentumok megjelenítése" -#: resources/qml/Actions.qml:267 +#: resources/qml/Actions.qml:269 msgctxt "@action:inmenu menubar:help" msgid "Report a &Bug" msgstr "Hibajelentés" -#: resources/qml/Actions.qml:275 +#: resources/qml/Actions.qml:277 msgctxt "@action:inmenu menubar:help" msgid "What's New" msgstr "Újdonságok" -#: resources/qml/Actions.qml:289 +#: resources/qml/Actions.qml:291 msgctxt "@action:inmenu menubar:help" msgid "About..." msgstr "Rólunk..." -#: resources/qml/Actions.qml:296 +#: resources/qml/Actions.qml:298 msgctxt "@action:inmenu menubar:edit" msgid "Delete Selected" msgstr "" -#: resources/qml/Actions.qml:306 +#: resources/qml/Actions.qml:308 msgctxt "@action:inmenu menubar:edit" msgid "Center Selected" msgstr "" -#: resources/qml/Actions.qml:315 +#: resources/qml/Actions.qml:317 msgctxt "@action:inmenu menubar:edit" msgid "Multiply Selected" msgstr "" -#: resources/qml/Actions.qml:324 +#: resources/qml/Actions.qml:326 msgctxt "@action:inmenu" msgid "Delete Model" msgstr "Modell törlés" -#: resources/qml/Actions.qml:332 +#: resources/qml/Actions.qml:334 msgctxt "@action:inmenu" msgid "Ce&nter Model on Platform" msgstr "&Középső modell a platformon" -#: resources/qml/Actions.qml:338 +#: resources/qml/Actions.qml:340 msgctxt "@action:inmenu menubar:edit" msgid "&Group Models" msgstr "&Csoportosítás" -#: resources/qml/Actions.qml:358 +#: resources/qml/Actions.qml:360 msgctxt "@action:inmenu menubar:edit" msgid "Ungroup Models" msgstr "Csoport bontása" -#: resources/qml/Actions.qml:368 +#: resources/qml/Actions.qml:370 msgctxt "@action:inmenu menubar:edit" msgid "&Merge Models" msgstr "&Modellek keverése" -#: resources/qml/Actions.qml:378 +#: resources/qml/Actions.qml:380 msgctxt "@action:inmenu" msgid "&Multiply Model..." msgstr "&Modell többszörözés..." -#: resources/qml/Actions.qml:385 +#: resources/qml/Actions.qml:387 msgctxt "@action:inmenu menubar:edit" msgid "Select All Models" msgstr "Mindent kijelöl" -#: resources/qml/Actions.qml:395 +#: resources/qml/Actions.qml:397 msgctxt "@action:inmenu menubar:edit" msgid "Clear Build Plate" msgstr "Tárgyasztal törlése" -#: resources/qml/Actions.qml:405 +#: resources/qml/Actions.qml:407 msgctxt "@action:inmenu menubar:file" msgid "Reload All Models" msgstr "Mindent újratölt" -#: resources/qml/Actions.qml:414 +#: resources/qml/Actions.qml:416 msgctxt "@action:inmenu menubar:edit" msgid "Arrange All Models" msgstr "Minden modell rendezése" -#: resources/qml/Actions.qml:422 +#: resources/qml/Actions.qml:424 +msgctxt "@action:inmenu menubar:edit" +msgid "Arrange All Models Without Rotation" +msgstr "" + +#: resources/qml/Actions.qml:431 msgctxt "@action:inmenu menubar:edit" msgid "Arrange Selection" msgstr "Kijelöltek rendezése" -#: resources/qml/Actions.qml:429 +#: resources/qml/Actions.qml:438 +msgctxt "@action:inmenu menubar:edit" +msgid "Arrange Selection Without Rotation" +msgstr "" + +#: resources/qml/Actions.qml:445 msgctxt "@action:inmenu menubar:edit" msgid "Reset All Model Positions" msgstr "Minden modellpozíció visszaállítása" -#: resources/qml/Actions.qml:436 +#: resources/qml/Actions.qml:452 msgctxt "@action:inmenu menubar:edit" msgid "Reset All Model Transformations" msgstr "Minden modelltranszformáció visszaállítása" -#: resources/qml/Actions.qml:445 +#: resources/qml/Actions.qml:461 msgctxt "@action:inmenu menubar:file" msgid "&Open File(s)..." msgstr "Fájl(ok) megnyitása..." -#: resources/qml/Actions.qml:455 +#: resources/qml/Actions.qml:471 msgctxt "@action:inmenu menubar:file" msgid "&New Project..." msgstr "Új projekt..." -#: resources/qml/Actions.qml:462 +#: resources/qml/Actions.qml:478 msgctxt "@action:inmenu menubar:help" msgid "Show Configuration Folder" msgstr "Konfigurációs mappa megjelenítése" -#: resources/qml/Actions.qml:469 resources/qml/Settings/SettingView.qml:476 +#: resources/qml/Actions.qml:485 resources/qml/Settings/SettingView.qml:476 msgctxt "@action:menu" msgid "Configure setting visibility..." msgstr "Beállítások láthatóságának beállítása..." @@ -5054,18 +5064,23 @@ msgid_plural "Print Selected Models With:" msgstr[0] "Kiválasztott modell nyomtatása:" msgstr[1] "Kiválasztott modellek nyomtatása:" -#: resources/qml/Menus/ContextMenu.qml:92 +#: resources/qml/Menus/ContextMenu.qml:93 msgctxt "@title:window" msgid "Multiply Selected Model" msgid_plural "Multiply Selected Models" msgstr[0] "Kiválasztott modell sokszorozása" msgstr[1] "Kiválasztott modellek sokszorozása" -#: resources/qml/Menus/ContextMenu.qml:123 +#: resources/qml/Menus/ContextMenu.qml:128 msgctxt "@label" msgid "Number of Copies" msgstr "Másolatok száma" +#: resources/qml/Menus/ContextMenu.qml:149 +msgctxt "@label" +msgid "Lock Rotation" +msgstr "" + #: resources/qml/Menus/EditMenu.qml:12 msgctxt "@title:menu menubar:toplevel" msgid "&Edit" diff --git a/resources/i18n/it_IT/cura.po b/resources/i18n/it_IT/cura.po index ea4fc72cff..8151bb48c9 100644 --- a/resources/i18n/it_IT/cura.po +++ b/resources/i18n/it_IT/cura.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-04-27 12:22+0000\n" +"POT-Creation-Date: 2023-05-11 14:19+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -23,22 +23,22 @@ msgctxt "@info:title" msgid "Login failed" msgstr "Login non riuscito" -#: cura/Arranging/ArrangeObjectsJob.py:25 +#: cura/Arranging/ArrangeObjectsJob.py:27 msgctxt "@info:status" msgid "Finding new location for objects" msgstr "Ricerca nuova posizione per gli oggetti" -#: cura/Arranging/ArrangeObjectsJob.py:29 +#: cura/Arranging/ArrangeObjectsJob.py:31 msgctxt "@info:title" msgid "Finding Location" msgstr "Ricerca posizione" -#: cura/Arranging/ArrangeObjectsJob.py:42 cura/MultiplyObjectsJob.py:99 +#: cura/Arranging/ArrangeObjectsJob.py:45 cura/MultiplyObjectsJob.py:101 msgctxt "@info:status" msgid "Unable to find a location within the build volume for all objects" msgstr "Impossibile individuare una posizione nel volume di stampa per tutti gli oggetti" -#: cura/Arranging/ArrangeObjectsJob.py:43 +#: cura/Arranging/ArrangeObjectsJob.py:46 msgctxt "@info:title" msgid "Can't Find Location" msgstr "Impossibile individuare posizione" @@ -265,25 +265,25 @@ msgctxt "@info 'width', 'depth' and 'height' are variable names that must NOT be msgid "%(width).1f x %(depth).1f x %(height).1f mm" msgstr "%(width).1f x %(depth).1f x %(height).1f mm" -#: cura/CuraApplication.py:1816 +#: cura/CuraApplication.py:1817 #, python-brace-format msgctxt "@info:status" msgid "Only one G-code file can be loaded at a time. Skipped importing {0}" msgstr "È possibile caricare un solo file codice G per volta. Importazione saltata {0}" -#: cura/CuraApplication.py:1818 cura/OAuth2/AuthorizationService.py:217 +#: cura/CuraApplication.py:1819 cura/OAuth2/AuthorizationService.py:217 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:189 msgctxt "@info:title" msgid "Warning" msgstr "Avvertenza" -#: cura/CuraApplication.py:1828 +#: cura/CuraApplication.py:1829 #, python-brace-format msgctxt "@info:status" msgid "Can't open any other file if G-code is loading. Skipped importing {0}" msgstr "Impossibile aprire altri file durante il caricamento del codice G. Importazione saltata {0}" -#: cura/CuraApplication.py:1830 cura/Settings/CuraContainerRegistry.py:156 +#: cura/CuraApplication.py:1831 cura/Settings/CuraContainerRegistry.py:156 #: cura/Settings/CuraContainerRegistry.py:166 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:153 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:173 @@ -410,17 +410,17 @@ msgctxt "@info:status" msgid "Calculated" msgstr "Calcolato" -#: cura/MultiplyObjectsJob.py:30 +#: cura/MultiplyObjectsJob.py:31 msgctxt "@info:status" msgid "Multiplying and placing objects" msgstr "Moltiplicazione e collocazione degli oggetti" -#: cura/MultiplyObjectsJob.py:32 +#: cura/MultiplyObjectsJob.py:33 msgctxt "@info:title" msgid "Placing Objects" msgstr "Sistemazione oggetti" -#: cura/MultiplyObjectsJob.py:100 +#: cura/MultiplyObjectsJob.py:102 msgctxt "@info:title" msgid "Placing Object" msgstr "Sistemazione oggetto" @@ -3678,17 +3678,17 @@ msgctxt "@action:button" msgid "Remove printers" msgstr "Rimuovere le stampanti" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:62 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:63 msgctxt "@action:button Preceded by 'Ready to'." msgid "Print over network" msgstr "Stampa sulla rete" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:63 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:64 msgctxt "@properties:tooltip" msgid "Print over network" msgstr "Stampa sulla rete" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:64 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:65 msgctxt "@info:status" msgid "Connected over the network" msgstr "Collegato alla rete" @@ -4230,227 +4230,237 @@ msgctxt "@button" msgid "Cancel" msgstr "Annulla" -#: resources/qml/Actions.qml:81 +#: resources/qml/Actions.qml:83 msgctxt "@action:inmenu" msgid "Show Online Troubleshooting" msgstr "Mostra ricerca e riparazione dei guasti online" -#: resources/qml/Actions.qml:88 +#: resources/qml/Actions.qml:90 msgctxt "@action:inmenu" msgid "Toggle Full Screen" msgstr "Attiva/disattiva schermo intero" -#: resources/qml/Actions.qml:96 +#: resources/qml/Actions.qml:98 msgctxt "@action:inmenu" msgid "Exit Full Screen" msgstr "Esci da schermo intero" -#: resources/qml/Actions.qml:103 +#: resources/qml/Actions.qml:105 msgctxt "@action:inmenu menubar:edit" msgid "&Undo" msgstr "&Annulla" -#: resources/qml/Actions.qml:113 +#: resources/qml/Actions.qml:115 msgctxt "@action:inmenu menubar:edit" msgid "&Redo" msgstr "Ri&peti" -#: resources/qml/Actions.qml:131 +#: resources/qml/Actions.qml:133 msgctxt "@action:inmenu menubar:file" msgid "&Quit" msgstr "&Esci" -#: resources/qml/Actions.qml:139 +#: resources/qml/Actions.qml:141 msgctxt "@action:inmenu menubar:view" msgid "3D View" msgstr "Visualizzazione 3D" -#: resources/qml/Actions.qml:146 +#: resources/qml/Actions.qml:148 msgctxt "@action:inmenu menubar:view" msgid "Front View" msgstr "Visualizzazione frontale" -#: resources/qml/Actions.qml:153 +#: resources/qml/Actions.qml:155 msgctxt "@action:inmenu menubar:view" msgid "Top View" msgstr "Visualizzazione superiore" -#: resources/qml/Actions.qml:160 +#: resources/qml/Actions.qml:162 msgctxt "@action:inmenu menubar:view" msgid "Bottom View" msgstr "Vista inferiore" -#: resources/qml/Actions.qml:167 +#: resources/qml/Actions.qml:169 msgctxt "@action:inmenu menubar:view" msgid "Left Side View" msgstr "Visualizzazione lato sinistro" -#: resources/qml/Actions.qml:174 +#: resources/qml/Actions.qml:176 msgctxt "@action:inmenu menubar:view" msgid "Right Side View" msgstr "Visualizzazione lato destro" -#: resources/qml/Actions.qml:188 +#: resources/qml/Actions.qml:190 msgctxt "@action:inmenu" msgid "Configure Cura..." msgstr "Configura Cura..." -#: resources/qml/Actions.qml:197 +#: resources/qml/Actions.qml:199 msgctxt "@action:inmenu menubar:printer" msgid "&Add Printer..." msgstr "&Aggiungi stampante..." -#: resources/qml/Actions.qml:203 +#: resources/qml/Actions.qml:205 msgctxt "@action:inmenu menubar:printer" msgid "Manage Pr&inters..." msgstr "Gestione stampanti..." -#: resources/qml/Actions.qml:210 +#: resources/qml/Actions.qml:212 msgctxt "@action:inmenu" msgid "Manage Materials..." msgstr "Gestione materiali..." -#: resources/qml/Actions.qml:218 +#: resources/qml/Actions.qml:220 msgctxt "@action:inmenu Marketplace is a brand name of UltiMaker's, so don't translate." msgid "Add more materials from Marketplace" msgstr "Aggiungere altri materiali da Marketplace" -#: resources/qml/Actions.qml:225 +#: resources/qml/Actions.qml:227 msgctxt "@action:inmenu menubar:profile" msgid "&Update profile with current settings/overrides" msgstr "&Aggiorna il profilo con le impostazioni/esclusioni correnti" -#: resources/qml/Actions.qml:233 +#: resources/qml/Actions.qml:235 msgctxt "@action:inmenu menubar:profile" msgid "&Discard current changes" msgstr "&Elimina le modifiche correnti" -#: resources/qml/Actions.qml:245 +#: resources/qml/Actions.qml:247 msgctxt "@action:inmenu menubar:profile" msgid "&Create profile from current settings/overrides..." msgstr "&Crea profilo dalle impostazioni/esclusioni correnti..." -#: resources/qml/Actions.qml:251 +#: resources/qml/Actions.qml:253 msgctxt "@action:inmenu menubar:profile" msgid "Manage Profiles..." msgstr "Gestione profili..." -#: resources/qml/Actions.qml:259 +#: resources/qml/Actions.qml:261 msgctxt "@action:inmenu menubar:help" msgid "Show Online &Documentation" msgstr "Mostra documentazione &online" -#: resources/qml/Actions.qml:267 +#: resources/qml/Actions.qml:269 msgctxt "@action:inmenu menubar:help" msgid "Report a &Bug" msgstr "Se&gnala un errore" -#: resources/qml/Actions.qml:275 +#: resources/qml/Actions.qml:277 msgctxt "@action:inmenu menubar:help" msgid "What's New" msgstr "Scopri le novità" -#: resources/qml/Actions.qml:289 +#: resources/qml/Actions.qml:291 msgctxt "@action:inmenu menubar:help" msgid "About..." msgstr "Informazioni..." -#: resources/qml/Actions.qml:296 +#: resources/qml/Actions.qml:298 msgctxt "@action:inmenu menubar:edit" msgid "Delete Selected" msgstr "Cancella selezionati" -#: resources/qml/Actions.qml:306 +#: resources/qml/Actions.qml:308 msgctxt "@action:inmenu menubar:edit" msgid "Center Selected" msgstr "Centra selezionati" -#: resources/qml/Actions.qml:315 +#: resources/qml/Actions.qml:317 msgctxt "@action:inmenu menubar:edit" msgid "Multiply Selected" msgstr "Moltiplica selezionati" -#: resources/qml/Actions.qml:324 +#: resources/qml/Actions.qml:326 msgctxt "@action:inmenu" msgid "Delete Model" msgstr "Elimina modello" -#: resources/qml/Actions.qml:332 +#: resources/qml/Actions.qml:334 msgctxt "@action:inmenu" msgid "Ce&nter Model on Platform" msgstr "C&entra modello su piattaforma" -#: resources/qml/Actions.qml:338 +#: resources/qml/Actions.qml:340 msgctxt "@action:inmenu menubar:edit" msgid "&Group Models" msgstr "&Raggruppa modelli" -#: resources/qml/Actions.qml:358 +#: resources/qml/Actions.qml:360 msgctxt "@action:inmenu menubar:edit" msgid "Ungroup Models" msgstr "Separa modelli" -#: resources/qml/Actions.qml:368 +#: resources/qml/Actions.qml:370 msgctxt "@action:inmenu menubar:edit" msgid "&Merge Models" msgstr "&Unisci modelli" -#: resources/qml/Actions.qml:378 +#: resources/qml/Actions.qml:380 msgctxt "@action:inmenu" msgid "&Multiply Model..." msgstr "Mo<iplica modello..." -#: resources/qml/Actions.qml:385 +#: resources/qml/Actions.qml:387 msgctxt "@action:inmenu menubar:edit" msgid "Select All Models" msgstr "Seleziona tutti i modelli" -#: resources/qml/Actions.qml:395 +#: resources/qml/Actions.qml:397 msgctxt "@action:inmenu menubar:edit" msgid "Clear Build Plate" msgstr "Cancellare piano di stampa" -#: resources/qml/Actions.qml:405 +#: resources/qml/Actions.qml:407 msgctxt "@action:inmenu menubar:file" msgid "Reload All Models" msgstr "Ricarica tutti i modelli" -#: resources/qml/Actions.qml:414 +#: resources/qml/Actions.qml:416 msgctxt "@action:inmenu menubar:edit" msgid "Arrange All Models" msgstr "Sistema tutti i modelli" -#: resources/qml/Actions.qml:422 +#: resources/qml/Actions.qml:424 +msgctxt "@action:inmenu menubar:edit" +msgid "Arrange All Models Without Rotation" +msgstr "" + +#: resources/qml/Actions.qml:431 msgctxt "@action:inmenu menubar:edit" msgid "Arrange Selection" msgstr "Sistema selezione" -#: resources/qml/Actions.qml:429 +#: resources/qml/Actions.qml:438 +msgctxt "@action:inmenu menubar:edit" +msgid "Arrange Selection Without Rotation" +msgstr "" + +#: resources/qml/Actions.qml:445 msgctxt "@action:inmenu menubar:edit" msgid "Reset All Model Positions" msgstr "Reimposta tutte le posizioni dei modelli" -#: resources/qml/Actions.qml:436 +#: resources/qml/Actions.qml:452 msgctxt "@action:inmenu menubar:edit" msgid "Reset All Model Transformations" msgstr "Reimposta tutte le trasformazioni dei modelli" -#: resources/qml/Actions.qml:445 +#: resources/qml/Actions.qml:461 msgctxt "@action:inmenu menubar:file" msgid "&Open File(s)..." msgstr "&Apri file..." -#: resources/qml/Actions.qml:455 +#: resources/qml/Actions.qml:471 msgctxt "@action:inmenu menubar:file" msgid "&New Project..." msgstr "&Nuovo Progetto..." -#: resources/qml/Actions.qml:462 +#: resources/qml/Actions.qml:478 msgctxt "@action:inmenu menubar:help" msgid "Show Configuration Folder" msgstr "Mostra cartella di configurazione" -#: resources/qml/Actions.qml:469 resources/qml/Settings/SettingView.qml:476 +#: resources/qml/Actions.qml:485 resources/qml/Settings/SettingView.qml:476 msgctxt "@action:menu" msgid "Configure setting visibility..." msgstr "Configura visibilità delle impostazioni..." @@ -5074,18 +5084,23 @@ msgid_plural "Print Selected Models With:" msgstr[0] "Stampa modello selezionato con:" msgstr[1] "Stampa modelli selezionati con:" -#: resources/qml/Menus/ContextMenu.qml:92 +#: resources/qml/Menus/ContextMenu.qml:93 msgctxt "@title:window" msgid "Multiply Selected Model" msgid_plural "Multiply Selected Models" msgstr[0] "Moltiplica modello selezionato" msgstr[1] "Moltiplica modelli selezionati" -#: resources/qml/Menus/ContextMenu.qml:123 +#: resources/qml/Menus/ContextMenu.qml:128 msgctxt "@label" msgid "Number of Copies" msgstr "Numero di copie" +#: resources/qml/Menus/ContextMenu.qml:149 +msgctxt "@label" +msgid "Lock Rotation" +msgstr "" + #: resources/qml/Menus/EditMenu.qml:12 msgctxt "@title:menu menubar:toplevel" msgid "&Edit" diff --git a/resources/i18n/ja_JP/cura.po b/resources/i18n/ja_JP/cura.po index 3a896394a5..7609c93e0f 100644 --- a/resources/i18n/ja_JP/cura.po +++ b/resources/i18n/ja_JP/cura.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-04-27 12:22+0000\n" +"POT-Creation-Date: 2023-05-11 14:19+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -23,22 +23,22 @@ msgctxt "@info:title" msgid "Login failed" msgstr "ログインに失敗しました" -#: cura/Arranging/ArrangeObjectsJob.py:25 +#: cura/Arranging/ArrangeObjectsJob.py:27 msgctxt "@info:status" msgid "Finding new location for objects" msgstr "造形物のために新しい位置を探索中" -#: cura/Arranging/ArrangeObjectsJob.py:29 +#: cura/Arranging/ArrangeObjectsJob.py:31 msgctxt "@info:title" msgid "Finding Location" msgstr "位置確認" -#: cura/Arranging/ArrangeObjectsJob.py:42 cura/MultiplyObjectsJob.py:99 +#: cura/Arranging/ArrangeObjectsJob.py:45 cura/MultiplyObjectsJob.py:101 msgctxt "@info:status" msgid "Unable to find a location within the build volume for all objects" msgstr "全ての造形物の造形サイズに対し、適切な位置が確認できません" -#: cura/Arranging/ArrangeObjectsJob.py:43 +#: cura/Arranging/ArrangeObjectsJob.py:46 msgctxt "@info:title" msgid "Can't Find Location" msgstr "位置を確保できません" @@ -265,25 +265,25 @@ msgctxt "@info 'width', 'depth' and 'height' are variable names that must NOT be msgid "%(width).1f x %(depth).1f x %(height).1f mm" msgstr "%(width).1f x %(depth).1f x %(height).1f mm" -#: cura/CuraApplication.py:1816 +#: cura/CuraApplication.py:1817 #, python-brace-format msgctxt "@info:status" msgid "Only one G-code file can be loaded at a time. Skipped importing {0}" msgstr "一度に一つのG-codeしか読み取れません。{0}の取り込みをスキップしました。" -#: cura/CuraApplication.py:1818 cura/OAuth2/AuthorizationService.py:217 +#: cura/CuraApplication.py:1819 cura/OAuth2/AuthorizationService.py:217 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:189 msgctxt "@info:title" msgid "Warning" msgstr "警告" -#: cura/CuraApplication.py:1828 +#: cura/CuraApplication.py:1829 #, python-brace-format msgctxt "@info:status" msgid "Can't open any other file if G-code is loading. Skipped importing {0}" msgstr "G-codeを読み込み中は他のファイルを開くことができません。{0}の取り込みをスキップしました。" -#: cura/CuraApplication.py:1830 cura/Settings/CuraContainerRegistry.py:156 +#: cura/CuraApplication.py:1831 cura/Settings/CuraContainerRegistry.py:156 #: cura/Settings/CuraContainerRegistry.py:166 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:153 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:173 @@ -410,17 +410,17 @@ msgctxt "@info:status" msgid "Calculated" msgstr "計算された" -#: cura/MultiplyObjectsJob.py:30 +#: cura/MultiplyObjectsJob.py:31 msgctxt "@info:status" msgid "Multiplying and placing objects" msgstr "造形データを増やす、配置する" -#: cura/MultiplyObjectsJob.py:32 +#: cura/MultiplyObjectsJob.py:33 msgctxt "@info:title" msgid "Placing Objects" msgstr "造形データを配置" -#: cura/MultiplyObjectsJob.py:100 +#: cura/MultiplyObjectsJob.py:102 msgctxt "@info:title" msgid "Placing Object" msgstr "造形データを配置" @@ -3666,17 +3666,17 @@ msgctxt "@action:button" msgid "Remove printers" msgstr "プリンターを取り除く" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:62 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:63 msgctxt "@action:button Preceded by 'Ready to'." msgid "Print over network" msgstr "ネットワーク上のプリント" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:63 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:64 msgctxt "@properties:tooltip" msgid "Print over network" msgstr "ネットワークのプリント" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:64 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:65 msgctxt "@info:status" msgid "Connected over the network" msgstr "ネットワーク上で接続" @@ -4218,227 +4218,237 @@ msgctxt "@button" msgid "Cancel" msgstr "キャンセル" -#: resources/qml/Actions.qml:81 +#: resources/qml/Actions.qml:83 msgctxt "@action:inmenu" msgid "Show Online Troubleshooting" msgstr "オンライントラブルシューティングを表示" -#: resources/qml/Actions.qml:88 +#: resources/qml/Actions.qml:90 msgctxt "@action:inmenu" msgid "Toggle Full Screen" msgstr "留め金 フルスクリーン" -#: resources/qml/Actions.qml:96 +#: resources/qml/Actions.qml:98 msgctxt "@action:inmenu" msgid "Exit Full Screen" msgstr "全画面表示を終了する" -#: resources/qml/Actions.qml:103 +#: resources/qml/Actions.qml:105 msgctxt "@action:inmenu menubar:edit" msgid "&Undo" msgstr "&取り消す" -#: resources/qml/Actions.qml:113 +#: resources/qml/Actions.qml:115 msgctxt "@action:inmenu menubar:edit" msgid "&Redo" msgstr "&やりなおす" -#: resources/qml/Actions.qml:131 +#: resources/qml/Actions.qml:133 msgctxt "@action:inmenu menubar:file" msgid "&Quit" msgstr "&やめる" -#: resources/qml/Actions.qml:139 +#: resources/qml/Actions.qml:141 msgctxt "@action:inmenu menubar:view" msgid "3D View" msgstr "3Dビュー" -#: resources/qml/Actions.qml:146 +#: resources/qml/Actions.qml:148 msgctxt "@action:inmenu menubar:view" msgid "Front View" msgstr "フロントビュー" -#: resources/qml/Actions.qml:153 +#: resources/qml/Actions.qml:155 msgctxt "@action:inmenu menubar:view" msgid "Top View" msgstr "トップビュー" -#: resources/qml/Actions.qml:160 +#: resources/qml/Actions.qml:162 msgctxt "@action:inmenu menubar:view" msgid "Bottom View" msgstr "底面図" -#: resources/qml/Actions.qml:167 +#: resources/qml/Actions.qml:169 msgctxt "@action:inmenu menubar:view" msgid "Left Side View" msgstr "左サイドビュー" -#: resources/qml/Actions.qml:174 +#: resources/qml/Actions.qml:176 msgctxt "@action:inmenu menubar:view" msgid "Right Side View" msgstr "右サイドビュー" -#: resources/qml/Actions.qml:188 +#: resources/qml/Actions.qml:190 msgctxt "@action:inmenu" msgid "Configure Cura..." msgstr "Curaを構成する..." -#: resources/qml/Actions.qml:197 +#: resources/qml/Actions.qml:199 msgctxt "@action:inmenu menubar:printer" msgid "&Add Printer..." msgstr "&プリンターを追加する..." -#: resources/qml/Actions.qml:203 +#: resources/qml/Actions.qml:205 msgctxt "@action:inmenu menubar:printer" msgid "Manage Pr&inters..." msgstr "プリンターを管理する..." -#: resources/qml/Actions.qml:210 +#: resources/qml/Actions.qml:212 msgctxt "@action:inmenu" msgid "Manage Materials..." msgstr "フィラメントを管理する..." -#: resources/qml/Actions.qml:218 +#: resources/qml/Actions.qml:220 msgctxt "@action:inmenu Marketplace is a brand name of UltiMaker's, so don't translate." msgid "Add more materials from Marketplace" msgstr "Add more materials from Marketplace" -#: resources/qml/Actions.qml:225 +#: resources/qml/Actions.qml:227 msgctxt "@action:inmenu menubar:profile" msgid "&Update profile with current settings/overrides" msgstr "&現在の設定/無効にプロファイルをアップデートする" -#: resources/qml/Actions.qml:233 +#: resources/qml/Actions.qml:235 msgctxt "@action:inmenu menubar:profile" msgid "&Discard current changes" msgstr "&変更を破棄する" -#: resources/qml/Actions.qml:245 +#: resources/qml/Actions.qml:247 msgctxt "@action:inmenu menubar:profile" msgid "&Create profile from current settings/overrides..." msgstr "&今の設定/無効からプロファイルを作成する..." -#: resources/qml/Actions.qml:251 +#: resources/qml/Actions.qml:253 msgctxt "@action:inmenu menubar:profile" msgid "Manage Profiles..." msgstr "プロファイルを管理する..." -#: resources/qml/Actions.qml:259 +#: resources/qml/Actions.qml:261 msgctxt "@action:inmenu menubar:help" msgid "Show Online &Documentation" msgstr "オンラインドキュメントを表示する" -#: resources/qml/Actions.qml:267 +#: resources/qml/Actions.qml:269 msgctxt "@action:inmenu menubar:help" msgid "Report a &Bug" msgstr "報告&バグ" -#: resources/qml/Actions.qml:275 +#: resources/qml/Actions.qml:277 msgctxt "@action:inmenu menubar:help" msgid "What's New" msgstr "新情報" -#: resources/qml/Actions.qml:289 +#: resources/qml/Actions.qml:291 msgctxt "@action:inmenu menubar:help" msgid "About..." msgstr "アバウト..." -#: resources/qml/Actions.qml:296 +#: resources/qml/Actions.qml:298 msgctxt "@action:inmenu menubar:edit" msgid "Delete Selected" msgstr "選択内容を削除" -#: resources/qml/Actions.qml:306 +#: resources/qml/Actions.qml:308 msgctxt "@action:inmenu menubar:edit" msgid "Center Selected" msgstr "選択内容を中央に移動" -#: resources/qml/Actions.qml:315 +#: resources/qml/Actions.qml:317 msgctxt "@action:inmenu menubar:edit" msgid "Multiply Selected" msgstr "選択内容を増倍" -#: resources/qml/Actions.qml:324 +#: resources/qml/Actions.qml:326 msgctxt "@action:inmenu" msgid "Delete Model" msgstr "モデルを消去する" -#: resources/qml/Actions.qml:332 +#: resources/qml/Actions.qml:334 msgctxt "@action:inmenu" msgid "Ce&nter Model on Platform" msgstr "プラットホームの中心にモデルを配置" -#: resources/qml/Actions.qml:338 +#: resources/qml/Actions.qml:340 msgctxt "@action:inmenu menubar:edit" msgid "&Group Models" msgstr "&モデルグループ" -#: resources/qml/Actions.qml:358 +#: resources/qml/Actions.qml:360 msgctxt "@action:inmenu menubar:edit" msgid "Ungroup Models" msgstr "モデルを非グループ化" -#: resources/qml/Actions.qml:368 +#: resources/qml/Actions.qml:370 msgctxt "@action:inmenu menubar:edit" msgid "&Merge Models" msgstr "モ&デルの合体" -#: resources/qml/Actions.qml:378 +#: resources/qml/Actions.qml:380 msgctxt "@action:inmenu" msgid "&Multiply Model..." msgstr "&モデルを増倍する..." -#: resources/qml/Actions.qml:385 +#: resources/qml/Actions.qml:387 msgctxt "@action:inmenu menubar:edit" msgid "Select All Models" msgstr "すべてのモデル選択" -#: resources/qml/Actions.qml:395 +#: resources/qml/Actions.qml:397 msgctxt "@action:inmenu menubar:edit" msgid "Clear Build Plate" msgstr "ビルドプレート上のクリア" -#: resources/qml/Actions.qml:405 +#: resources/qml/Actions.qml:407 msgctxt "@action:inmenu menubar:file" msgid "Reload All Models" msgstr "すべてのモデルを読み込む" -#: resources/qml/Actions.qml:414 +#: resources/qml/Actions.qml:416 msgctxt "@action:inmenu menubar:edit" msgid "Arrange All Models" msgstr "すべてのモデルをアレンジする" -#: resources/qml/Actions.qml:422 +#: resources/qml/Actions.qml:424 +msgctxt "@action:inmenu menubar:edit" +msgid "Arrange All Models Without Rotation" +msgstr "" + +#: resources/qml/Actions.qml:431 msgctxt "@action:inmenu menubar:edit" msgid "Arrange Selection" msgstr "選択をアレンジする" -#: resources/qml/Actions.qml:429 +#: resources/qml/Actions.qml:438 +msgctxt "@action:inmenu menubar:edit" +msgid "Arrange Selection Without Rotation" +msgstr "" + +#: resources/qml/Actions.qml:445 msgctxt "@action:inmenu menubar:edit" msgid "Reset All Model Positions" msgstr "すべてのモデルのポジションをリセットする" -#: resources/qml/Actions.qml:436 +#: resources/qml/Actions.qml:452 msgctxt "@action:inmenu menubar:edit" msgid "Reset All Model Transformations" msgstr "すべてのモデル&変更点をリセットする" -#: resources/qml/Actions.qml:445 +#: resources/qml/Actions.qml:461 msgctxt "@action:inmenu menubar:file" msgid "&Open File(s)..." msgstr "&ファイルを開く(s)..." -#: resources/qml/Actions.qml:455 +#: resources/qml/Actions.qml:471 msgctxt "@action:inmenu menubar:file" msgid "&New Project..." msgstr "&新しいプロジェクト..." -#: resources/qml/Actions.qml:462 +#: resources/qml/Actions.qml:478 msgctxt "@action:inmenu menubar:help" msgid "Show Configuration Folder" msgstr "コンフィグレーションのフォルダーを表示する" -#: resources/qml/Actions.qml:469 resources/qml/Settings/SettingView.qml:476 +#: resources/qml/Actions.qml:485 resources/qml/Settings/SettingView.qml:476 msgctxt "@action:menu" msgid "Configure setting visibility..." msgstr "視野のセッティングを構成する..." @@ -5061,17 +5071,22 @@ msgid "Print Selected Model With:" msgid_plural "Print Selected Models With:" msgstr[0] "選択したモデルで印刷:" -#: resources/qml/Menus/ContextMenu.qml:92 +#: resources/qml/Menus/ContextMenu.qml:93 msgctxt "@title:window" msgid "Multiply Selected Model" msgid_plural "Multiply Selected Models" msgstr[0] "選択した複数のモデル" -#: resources/qml/Menus/ContextMenu.qml:123 +#: resources/qml/Menus/ContextMenu.qml:128 msgctxt "@label" msgid "Number of Copies" msgstr "コピーの数" +#: resources/qml/Menus/ContextMenu.qml:149 +msgctxt "@label" +msgid "Lock Rotation" +msgstr "" + #: resources/qml/Menus/EditMenu.qml:12 msgctxt "@title:menu menubar:toplevel" msgid "&Edit" diff --git a/resources/i18n/ko_KR/cura.po b/resources/i18n/ko_KR/cura.po index f7a5f47e0a..45af01145e 100644 --- a/resources/i18n/ko_KR/cura.po +++ b/resources/i18n/ko_KR/cura.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-04-27 12:22+0000\n" +"POT-Creation-Date: 2023-05-11 14:19+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -23,22 +23,22 @@ msgctxt "@info:title" msgid "Login failed" msgstr "로그인 실패" -#: cura/Arranging/ArrangeObjectsJob.py:25 +#: cura/Arranging/ArrangeObjectsJob.py:27 msgctxt "@info:status" msgid "Finding new location for objects" msgstr "객체의 새 위치 찾기" -#: cura/Arranging/ArrangeObjectsJob.py:29 +#: cura/Arranging/ArrangeObjectsJob.py:31 msgctxt "@info:title" msgid "Finding Location" msgstr "위치 찾기" -#: cura/Arranging/ArrangeObjectsJob.py:42 cura/MultiplyObjectsJob.py:99 +#: cura/Arranging/ArrangeObjectsJob.py:45 cura/MultiplyObjectsJob.py:101 msgctxt "@info:status" msgid "Unable to find a location within the build volume for all objects" msgstr "모든 개체가 출력할 수 있는 최대 사이즈 내에 위치할 수 없습니다" -#: cura/Arranging/ArrangeObjectsJob.py:43 +#: cura/Arranging/ArrangeObjectsJob.py:46 msgctxt "@info:title" msgid "Can't Find Location" msgstr "위치를 찾을 수 없음" @@ -265,25 +265,25 @@ msgctxt "@info 'width', 'depth' and 'height' are variable names that must NOT be msgid "%(width).1f x %(depth).1f x %(height).1f mm" msgstr "%(width).1f x %(depth).1f x %(height).1f mm" -#: cura/CuraApplication.py:1816 +#: cura/CuraApplication.py:1817 #, python-brace-format msgctxt "@info:status" msgid "Only one G-code file can be loaded at a time. Skipped importing {0}" msgstr "한 번에 하나의 G-코드 파일만 로드 할 수 있습니다. {0} 가져 오기를 건너 뛰었습니다." -#: cura/CuraApplication.py:1818 cura/OAuth2/AuthorizationService.py:217 +#: cura/CuraApplication.py:1819 cura/OAuth2/AuthorizationService.py:217 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:189 msgctxt "@info:title" msgid "Warning" msgstr "경고" -#: cura/CuraApplication.py:1828 +#: cura/CuraApplication.py:1829 #, python-brace-format msgctxt "@info:status" msgid "Can't open any other file if G-code is loading. Skipped importing {0}" msgstr "G-코드가 로드되어 있으면 다른 파일을 열 수 없습니다. {0} 가져 오기를 건너 뛰었습니다." -#: cura/CuraApplication.py:1830 cura/Settings/CuraContainerRegistry.py:156 +#: cura/CuraApplication.py:1831 cura/Settings/CuraContainerRegistry.py:156 #: cura/Settings/CuraContainerRegistry.py:166 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:153 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:173 @@ -410,17 +410,17 @@ msgctxt "@info:status" msgid "Calculated" msgstr "계산된" -#: cura/MultiplyObjectsJob.py:30 +#: cura/MultiplyObjectsJob.py:31 msgctxt "@info:status" msgid "Multiplying and placing objects" msgstr "객체를 증가시키고 배치" -#: cura/MultiplyObjectsJob.py:32 +#: cura/MultiplyObjectsJob.py:33 msgctxt "@info:title" msgid "Placing Objects" msgstr "개체 배치 중" -#: cura/MultiplyObjectsJob.py:100 +#: cura/MultiplyObjectsJob.py:102 msgctxt "@info:title" msgid "Placing Object" msgstr "개체 배치 중" @@ -3665,17 +3665,17 @@ msgctxt "@action:button" msgid "Remove printers" msgstr "프린터 제거" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:62 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:63 msgctxt "@action:button Preceded by 'Ready to'." msgid "Print over network" msgstr "네트워크를 통해 프린팅" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:63 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:64 msgctxt "@properties:tooltip" msgid "Print over network" msgstr "네트워크를 통해 프린팅" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:64 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:65 msgctxt "@info:status" msgid "Connected over the network" msgstr "네트워크를 통해 연결됨" @@ -4217,227 +4217,237 @@ msgctxt "@button" msgid "Cancel" msgstr "취소" -#: resources/qml/Actions.qml:81 +#: resources/qml/Actions.qml:83 msgctxt "@action:inmenu" msgid "Show Online Troubleshooting" msgstr "온라인 문제 해결 표시" -#: resources/qml/Actions.qml:88 +#: resources/qml/Actions.qml:90 msgctxt "@action:inmenu" msgid "Toggle Full Screen" msgstr "전채 화면 전환" -#: resources/qml/Actions.qml:96 +#: resources/qml/Actions.qml:98 msgctxt "@action:inmenu" msgid "Exit Full Screen" msgstr "전체 화면 종료" -#: resources/qml/Actions.qml:103 +#: resources/qml/Actions.qml:105 msgctxt "@action:inmenu menubar:edit" msgid "&Undo" msgstr "되돌리기(&U)" -#: resources/qml/Actions.qml:113 +#: resources/qml/Actions.qml:115 msgctxt "@action:inmenu menubar:edit" msgid "&Redo" msgstr "다시하기(&R)" -#: resources/qml/Actions.qml:131 +#: resources/qml/Actions.qml:133 msgctxt "@action:inmenu menubar:file" msgid "&Quit" msgstr "종료(&Q)" -#: resources/qml/Actions.qml:139 +#: resources/qml/Actions.qml:141 msgctxt "@action:inmenu menubar:view" msgid "3D View" msgstr "3D 보기" -#: resources/qml/Actions.qml:146 +#: resources/qml/Actions.qml:148 msgctxt "@action:inmenu menubar:view" msgid "Front View" msgstr "앞에서 보기" -#: resources/qml/Actions.qml:153 +#: resources/qml/Actions.qml:155 msgctxt "@action:inmenu menubar:view" msgid "Top View" msgstr "위에서 보기" -#: resources/qml/Actions.qml:160 +#: resources/qml/Actions.qml:162 msgctxt "@action:inmenu menubar:view" msgid "Bottom View" msgstr "하단 뷰" -#: resources/qml/Actions.qml:167 +#: resources/qml/Actions.qml:169 msgctxt "@action:inmenu menubar:view" msgid "Left Side View" msgstr "왼쪽에서 보기" -#: resources/qml/Actions.qml:174 +#: resources/qml/Actions.qml:176 msgctxt "@action:inmenu menubar:view" msgid "Right Side View" msgstr "오른쪽에서 보기" -#: resources/qml/Actions.qml:188 +#: resources/qml/Actions.qml:190 msgctxt "@action:inmenu" msgid "Configure Cura..." msgstr "Cura 구성 ..." -#: resources/qml/Actions.qml:197 +#: resources/qml/Actions.qml:199 msgctxt "@action:inmenu menubar:printer" msgid "&Add Printer..." msgstr "프린터 추가..." -#: resources/qml/Actions.qml:203 +#: resources/qml/Actions.qml:205 msgctxt "@action:inmenu menubar:printer" msgid "Manage Pr&inters..." msgstr "프린터 관리 ..." -#: resources/qml/Actions.qml:210 +#: resources/qml/Actions.qml:212 msgctxt "@action:inmenu" msgid "Manage Materials..." msgstr "재료 관리..." -#: resources/qml/Actions.qml:218 +#: resources/qml/Actions.qml:220 msgctxt "@action:inmenu Marketplace is a brand name of UltiMaker's, so don't translate." msgid "Add more materials from Marketplace" msgstr "마켓플레이스에서 더 많은 재료 추가" -#: resources/qml/Actions.qml:225 +#: resources/qml/Actions.qml:227 msgctxt "@action:inmenu menubar:profile" msgid "&Update profile with current settings/overrides" msgstr "현재 설정으로로 프로파일 업데이트" -#: resources/qml/Actions.qml:233 +#: resources/qml/Actions.qml:235 msgctxt "@action:inmenu menubar:profile" msgid "&Discard current changes" msgstr "현재 변경 사항 무시" -#: resources/qml/Actions.qml:245 +#: resources/qml/Actions.qml:247 msgctxt "@action:inmenu menubar:profile" msgid "&Create profile from current settings/overrides..." msgstr "현재 설정으로 프로파일 생성..." -#: resources/qml/Actions.qml:251 +#: resources/qml/Actions.qml:253 msgctxt "@action:inmenu menubar:profile" msgid "Manage Profiles..." msgstr "프로파일 관리..." -#: resources/qml/Actions.qml:259 +#: resources/qml/Actions.qml:261 msgctxt "@action:inmenu menubar:help" msgid "Show Online &Documentation" msgstr "온라인 문서 표시" -#: resources/qml/Actions.qml:267 +#: resources/qml/Actions.qml:269 msgctxt "@action:inmenu menubar:help" msgid "Report a &Bug" msgstr "버그 리포트" -#: resources/qml/Actions.qml:275 +#: resources/qml/Actions.qml:277 msgctxt "@action:inmenu menubar:help" msgid "What's New" msgstr "새로운 기능" -#: resources/qml/Actions.qml:289 +#: resources/qml/Actions.qml:291 msgctxt "@action:inmenu menubar:help" msgid "About..." msgstr "소개..." -#: resources/qml/Actions.qml:296 +#: resources/qml/Actions.qml:298 msgctxt "@action:inmenu menubar:edit" msgid "Delete Selected" msgstr "선택 항목 삭제" -#: resources/qml/Actions.qml:306 +#: resources/qml/Actions.qml:308 msgctxt "@action:inmenu menubar:edit" msgid "Center Selected" msgstr "선택 항목 가운데 정렬" -#: resources/qml/Actions.qml:315 +#: resources/qml/Actions.qml:317 msgctxt "@action:inmenu menubar:edit" msgid "Multiply Selected" msgstr "선택 항목 복제" -#: resources/qml/Actions.qml:324 +#: resources/qml/Actions.qml:326 msgctxt "@action:inmenu" msgid "Delete Model" msgstr "모델 삭제" -#: resources/qml/Actions.qml:332 +#: resources/qml/Actions.qml:334 msgctxt "@action:inmenu" msgid "Ce&nter Model on Platform" msgstr "플랫폼중심에 모델 위치하기" -#: resources/qml/Actions.qml:338 +#: resources/qml/Actions.qml:340 msgctxt "@action:inmenu menubar:edit" msgid "&Group Models" msgstr "모델 그룹화" -#: resources/qml/Actions.qml:358 +#: resources/qml/Actions.qml:360 msgctxt "@action:inmenu menubar:edit" msgid "Ungroup Models" msgstr "모델 그룹 해제" -#: resources/qml/Actions.qml:368 +#: resources/qml/Actions.qml:370 msgctxt "@action:inmenu menubar:edit" msgid "&Merge Models" msgstr "모델 합치기" -#: resources/qml/Actions.qml:378 +#: resources/qml/Actions.qml:380 msgctxt "@action:inmenu" msgid "&Multiply Model..." msgstr "모델 복제..." -#: resources/qml/Actions.qml:385 +#: resources/qml/Actions.qml:387 msgctxt "@action:inmenu menubar:edit" msgid "Select All Models" msgstr "모든 모델 선택" -#: resources/qml/Actions.qml:395 +#: resources/qml/Actions.qml:397 msgctxt "@action:inmenu menubar:edit" msgid "Clear Build Plate" msgstr "빌드 플레이트 지우기" -#: resources/qml/Actions.qml:405 +#: resources/qml/Actions.qml:407 msgctxt "@action:inmenu menubar:file" msgid "Reload All Models" msgstr "모든 모델 다시 로드" -#: resources/qml/Actions.qml:414 +#: resources/qml/Actions.qml:416 msgctxt "@action:inmenu menubar:edit" msgid "Arrange All Models" msgstr "모든 모델 정렬" -#: resources/qml/Actions.qml:422 +#: resources/qml/Actions.qml:424 +msgctxt "@action:inmenu menubar:edit" +msgid "Arrange All Models Without Rotation" +msgstr "" + +#: resources/qml/Actions.qml:431 msgctxt "@action:inmenu menubar:edit" msgid "Arrange Selection" msgstr "선택한 모델 정렬" -#: resources/qml/Actions.qml:429 +#: resources/qml/Actions.qml:438 +msgctxt "@action:inmenu menubar:edit" +msgid "Arrange Selection Without Rotation" +msgstr "" + +#: resources/qml/Actions.qml:445 msgctxt "@action:inmenu menubar:edit" msgid "Reset All Model Positions" msgstr "모든 모델의 위치 재설정" -#: resources/qml/Actions.qml:436 +#: resources/qml/Actions.qml:452 msgctxt "@action:inmenu menubar:edit" msgid "Reset All Model Transformations" msgstr "모든 모델의 변환 재설정" -#: resources/qml/Actions.qml:445 +#: resources/qml/Actions.qml:461 msgctxt "@action:inmenu menubar:file" msgid "&Open File(s)..." msgstr "파일 열기..." -#: resources/qml/Actions.qml:455 +#: resources/qml/Actions.qml:471 msgctxt "@action:inmenu menubar:file" msgid "&New Project..." msgstr "새로운 프로젝트..." -#: resources/qml/Actions.qml:462 +#: resources/qml/Actions.qml:478 msgctxt "@action:inmenu menubar:help" msgid "Show Configuration Folder" msgstr "설정 폴더 표시" -#: resources/qml/Actions.qml:469 resources/qml/Settings/SettingView.qml:476 +#: resources/qml/Actions.qml:485 resources/qml/Settings/SettingView.qml:476 msgctxt "@action:menu" msgid "Configure setting visibility..." msgstr "설정 보기..." @@ -5060,17 +5070,22 @@ msgid "Print Selected Model With:" msgid_plural "Print Selected Models With:" msgstr[0] "선택된 모델 프린팅 :" -#: resources/qml/Menus/ContextMenu.qml:92 +#: resources/qml/Menus/ContextMenu.qml:93 msgctxt "@title:window" msgid "Multiply Selected Model" msgid_plural "Multiply Selected Models" msgstr[0] "선택한 모델 복" -#: resources/qml/Menus/ContextMenu.qml:123 +#: resources/qml/Menus/ContextMenu.qml:128 msgctxt "@label" msgid "Number of Copies" msgstr "복제할 수" +#: resources/qml/Menus/ContextMenu.qml:149 +msgctxt "@label" +msgid "Lock Rotation" +msgstr "" + #: resources/qml/Menus/EditMenu.qml:12 msgctxt "@title:menu menubar:toplevel" msgid "&Edit" diff --git a/resources/i18n/nl_NL/cura.po b/resources/i18n/nl_NL/cura.po index 6c903dd42c..6a3bb768c4 100644 --- a/resources/i18n/nl_NL/cura.po +++ b/resources/i18n/nl_NL/cura.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-04-27 12:22+0000\n" +"POT-Creation-Date: 2023-05-11 14:19+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -23,22 +23,22 @@ msgctxt "@info:title" msgid "Login failed" msgstr "Inloggen mislukt" -#: cura/Arranging/ArrangeObjectsJob.py:25 +#: cura/Arranging/ArrangeObjectsJob.py:27 msgctxt "@info:status" msgid "Finding new location for objects" msgstr "Nieuwe locatie vinden voor objecten" -#: cura/Arranging/ArrangeObjectsJob.py:29 +#: cura/Arranging/ArrangeObjectsJob.py:31 msgctxt "@info:title" msgid "Finding Location" msgstr "Locatie vinden" -#: cura/Arranging/ArrangeObjectsJob.py:42 cura/MultiplyObjectsJob.py:99 +#: cura/Arranging/ArrangeObjectsJob.py:45 cura/MultiplyObjectsJob.py:101 msgctxt "@info:status" msgid "Unable to find a location within the build volume for all objects" msgstr "Kan binnen het werkvolume niet voor alle objecten een locatie vinden" -#: cura/Arranging/ArrangeObjectsJob.py:43 +#: cura/Arranging/ArrangeObjectsJob.py:46 msgctxt "@info:title" msgid "Can't Find Location" msgstr "Kan locatie niet vinden" @@ -265,25 +265,25 @@ msgctxt "@info 'width', 'depth' and 'height' are variable names that must NOT be msgid "%(width).1f x %(depth).1f x %(height).1f mm" msgstr "%(width).1f x %(depth).1f x %(height).1f mm" -#: cura/CuraApplication.py:1816 +#: cura/CuraApplication.py:1817 #, python-brace-format msgctxt "@info:status" msgid "Only one G-code file can be loaded at a time. Skipped importing {0}" msgstr "Er kan slechts één G-code-bestand tegelijkertijd worden geladen. Het importeren van {0} is overgeslagen" -#: cura/CuraApplication.py:1818 cura/OAuth2/AuthorizationService.py:217 +#: cura/CuraApplication.py:1819 cura/OAuth2/AuthorizationService.py:217 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:189 msgctxt "@info:title" msgid "Warning" msgstr "Waarschuwing" -#: cura/CuraApplication.py:1828 +#: cura/CuraApplication.py:1829 #, python-brace-format msgctxt "@info:status" msgid "Can't open any other file if G-code is loading. Skipped importing {0}" msgstr "Kan geen ander bestand openen als G-code wordt geladen. Het importeren van {0} is overgeslagen" -#: cura/CuraApplication.py:1830 cura/Settings/CuraContainerRegistry.py:156 +#: cura/CuraApplication.py:1831 cura/Settings/CuraContainerRegistry.py:156 #: cura/Settings/CuraContainerRegistry.py:166 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:153 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:173 @@ -410,17 +410,17 @@ msgctxt "@info:status" msgid "Calculated" msgstr "Berekend" -#: cura/MultiplyObjectsJob.py:30 +#: cura/MultiplyObjectsJob.py:31 msgctxt "@info:status" msgid "Multiplying and placing objects" msgstr "Objecten verveelvoudigen en plaatsen" -#: cura/MultiplyObjectsJob.py:32 +#: cura/MultiplyObjectsJob.py:33 msgctxt "@info:title" msgid "Placing Objects" msgstr "Objecten plaatsen" -#: cura/MultiplyObjectsJob.py:100 +#: cura/MultiplyObjectsJob.py:102 msgctxt "@info:title" msgid "Placing Object" msgstr "Object plaatsen" @@ -3678,17 +3678,17 @@ msgctxt "@action:button" msgid "Remove printers" msgstr "Printers verwijderen" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:62 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:63 msgctxt "@action:button Preceded by 'Ready to'." msgid "Print over network" msgstr "Printen via netwerk" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:63 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:64 msgctxt "@properties:tooltip" msgid "Print over network" msgstr "Printen via netwerk" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:64 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:65 msgctxt "@info:status" msgid "Connected over the network" msgstr "Via het netwerk verbonden" @@ -4230,227 +4230,237 @@ msgctxt "@button" msgid "Cancel" msgstr "Annuleren" -#: resources/qml/Actions.qml:81 +#: resources/qml/Actions.qml:83 msgctxt "@action:inmenu" msgid "Show Online Troubleshooting" msgstr "Online probleemoplossing weergeven" -#: resources/qml/Actions.qml:88 +#: resources/qml/Actions.qml:90 msgctxt "@action:inmenu" msgid "Toggle Full Screen" msgstr "Volledig Scherm In-/Uitschakelen" -#: resources/qml/Actions.qml:96 +#: resources/qml/Actions.qml:98 msgctxt "@action:inmenu" msgid "Exit Full Screen" msgstr "Volledig scherm sluiten" -#: resources/qml/Actions.qml:103 +#: resources/qml/Actions.qml:105 msgctxt "@action:inmenu menubar:edit" msgid "&Undo" msgstr "Ongedaan &Maken" -#: resources/qml/Actions.qml:113 +#: resources/qml/Actions.qml:115 msgctxt "@action:inmenu menubar:edit" msgid "&Redo" msgstr "&Opnieuw" -#: resources/qml/Actions.qml:131 +#: resources/qml/Actions.qml:133 msgctxt "@action:inmenu menubar:file" msgid "&Quit" msgstr "&Afsluiten" -#: resources/qml/Actions.qml:139 +#: resources/qml/Actions.qml:141 msgctxt "@action:inmenu menubar:view" msgid "3D View" msgstr "3D-weergave" -#: resources/qml/Actions.qml:146 +#: resources/qml/Actions.qml:148 msgctxt "@action:inmenu menubar:view" msgid "Front View" msgstr "Weergave voorzijde" -#: resources/qml/Actions.qml:153 +#: resources/qml/Actions.qml:155 msgctxt "@action:inmenu menubar:view" msgid "Top View" msgstr "Weergave bovenzijde" -#: resources/qml/Actions.qml:160 +#: resources/qml/Actions.qml:162 msgctxt "@action:inmenu menubar:view" msgid "Bottom View" msgstr "Aanzicht onderzijde" -#: resources/qml/Actions.qml:167 +#: resources/qml/Actions.qml:169 msgctxt "@action:inmenu menubar:view" msgid "Left Side View" msgstr "Weergave linkerzijde" -#: resources/qml/Actions.qml:174 +#: resources/qml/Actions.qml:176 msgctxt "@action:inmenu menubar:view" msgid "Right Side View" msgstr "Weergave rechterzijde" -#: resources/qml/Actions.qml:188 +#: resources/qml/Actions.qml:190 msgctxt "@action:inmenu" msgid "Configure Cura..." msgstr "Cura Configureren..." -#: resources/qml/Actions.qml:197 +#: resources/qml/Actions.qml:199 msgctxt "@action:inmenu menubar:printer" msgid "&Add Printer..." msgstr "&Printer Toevoegen..." -#: resources/qml/Actions.qml:203 +#: resources/qml/Actions.qml:205 msgctxt "@action:inmenu menubar:printer" msgid "Manage Pr&inters..." msgstr "Pr&inters Beheren..." -#: resources/qml/Actions.qml:210 +#: resources/qml/Actions.qml:212 msgctxt "@action:inmenu" msgid "Manage Materials..." msgstr "Materialen Beheren..." -#: resources/qml/Actions.qml:218 +#: resources/qml/Actions.qml:220 msgctxt "@action:inmenu Marketplace is a brand name of UltiMaker's, so don't translate." msgid "Add more materials from Marketplace" msgstr "Meer materialen toevoegen van Marketplace" -#: resources/qml/Actions.qml:225 +#: resources/qml/Actions.qml:227 msgctxt "@action:inmenu menubar:profile" msgid "&Update profile with current settings/overrides" msgstr "Profiel bijwerken met h&uidige instellingen/overschrijvingen" -#: resources/qml/Actions.qml:233 +#: resources/qml/Actions.qml:235 msgctxt "@action:inmenu menubar:profile" msgid "&Discard current changes" msgstr "Hui&dige wijzigingen verwijderen" -#: resources/qml/Actions.qml:245 +#: resources/qml/Actions.qml:247 msgctxt "@action:inmenu menubar:profile" msgid "&Create profile from current settings/overrides..." msgstr "Profiel maken op basis van huidige instellingen/overs&chrijvingen..." -#: resources/qml/Actions.qml:251 +#: resources/qml/Actions.qml:253 msgctxt "@action:inmenu menubar:profile" msgid "Manage Profiles..." msgstr "Profielen Beheren..." -#: resources/qml/Actions.qml:259 +#: resources/qml/Actions.qml:261 msgctxt "@action:inmenu menubar:help" msgid "Show Online &Documentation" msgstr "Online &Documentatie Weergeven" -#: resources/qml/Actions.qml:267 +#: resources/qml/Actions.qml:269 msgctxt "@action:inmenu menubar:help" msgid "Report a &Bug" msgstr "Een &Bug Rapporteren" -#: resources/qml/Actions.qml:275 +#: resources/qml/Actions.qml:277 msgctxt "@action:inmenu menubar:help" msgid "What's New" msgstr "Nieuwe functies" -#: resources/qml/Actions.qml:289 +#: resources/qml/Actions.qml:291 msgctxt "@action:inmenu menubar:help" msgid "About..." msgstr "Over..." -#: resources/qml/Actions.qml:296 +#: resources/qml/Actions.qml:298 msgctxt "@action:inmenu menubar:edit" msgid "Delete Selected" msgstr "Verwijder geselecteerde items" -#: resources/qml/Actions.qml:306 +#: resources/qml/Actions.qml:308 msgctxt "@action:inmenu menubar:edit" msgid "Center Selected" msgstr "Centreer geselecteerde items" -#: resources/qml/Actions.qml:315 +#: resources/qml/Actions.qml:317 msgctxt "@action:inmenu menubar:edit" msgid "Multiply Selected" msgstr "Verveelvoudig geselecteerde items" -#: resources/qml/Actions.qml:324 +#: resources/qml/Actions.qml:326 msgctxt "@action:inmenu" msgid "Delete Model" msgstr "Model Verwijderen" -#: resources/qml/Actions.qml:332 +#: resources/qml/Actions.qml:334 msgctxt "@action:inmenu" msgid "Ce&nter Model on Platform" msgstr "Model op Platform Ce&ntreren" -#: resources/qml/Actions.qml:338 +#: resources/qml/Actions.qml:340 msgctxt "@action:inmenu menubar:edit" msgid "&Group Models" msgstr "Modellen &Groeperen" -#: resources/qml/Actions.qml:358 +#: resources/qml/Actions.qml:360 msgctxt "@action:inmenu menubar:edit" msgid "Ungroup Models" msgstr "Groeperen van Modellen Opheffen" -#: resources/qml/Actions.qml:368 +#: resources/qml/Actions.qml:370 msgctxt "@action:inmenu menubar:edit" msgid "&Merge Models" msgstr "Modellen Samen&voegen" -#: resources/qml/Actions.qml:378 +#: resources/qml/Actions.qml:380 msgctxt "@action:inmenu" msgid "&Multiply Model..." msgstr "&Model verveelvoudigen..." -#: resources/qml/Actions.qml:385 +#: resources/qml/Actions.qml:387 msgctxt "@action:inmenu menubar:edit" msgid "Select All Models" msgstr "Alle Modellen Selecteren" -#: resources/qml/Actions.qml:395 +#: resources/qml/Actions.qml:397 msgctxt "@action:inmenu menubar:edit" msgid "Clear Build Plate" msgstr "Platform Leegmaken" -#: resources/qml/Actions.qml:405 +#: resources/qml/Actions.qml:407 msgctxt "@action:inmenu menubar:file" msgid "Reload All Models" msgstr "Alle Modellen Opnieuw Laden" -#: resources/qml/Actions.qml:414 +#: resources/qml/Actions.qml:416 msgctxt "@action:inmenu menubar:edit" msgid "Arrange All Models" msgstr "Alle modellen schikken" -#: resources/qml/Actions.qml:422 +#: resources/qml/Actions.qml:424 +msgctxt "@action:inmenu menubar:edit" +msgid "Arrange All Models Without Rotation" +msgstr "" + +#: resources/qml/Actions.qml:431 msgctxt "@action:inmenu menubar:edit" msgid "Arrange Selection" msgstr "Selectie schikken" -#: resources/qml/Actions.qml:429 +#: resources/qml/Actions.qml:438 +msgctxt "@action:inmenu menubar:edit" +msgid "Arrange Selection Without Rotation" +msgstr "" + +#: resources/qml/Actions.qml:445 msgctxt "@action:inmenu menubar:edit" msgid "Reset All Model Positions" msgstr "Alle Modelposities Herstellen" -#: resources/qml/Actions.qml:436 +#: resources/qml/Actions.qml:452 msgctxt "@action:inmenu menubar:edit" msgid "Reset All Model Transformations" msgstr "Alle Modeltransformaties Herstellen" -#: resources/qml/Actions.qml:445 +#: resources/qml/Actions.qml:461 msgctxt "@action:inmenu menubar:file" msgid "&Open File(s)..." msgstr "Bestand(en) &openen..." -#: resources/qml/Actions.qml:455 +#: resources/qml/Actions.qml:471 msgctxt "@action:inmenu menubar:file" msgid "&New Project..." msgstr "&Nieuw project..." -#: resources/qml/Actions.qml:462 +#: resources/qml/Actions.qml:478 msgctxt "@action:inmenu menubar:help" msgid "Show Configuration Folder" msgstr "Open Configuratiemap" -#: resources/qml/Actions.qml:469 resources/qml/Settings/SettingView.qml:476 +#: resources/qml/Actions.qml:485 resources/qml/Settings/SettingView.qml:476 msgctxt "@action:menu" msgid "Configure setting visibility..." msgstr "Zichtbaarheid Instelling Configureren..." @@ -5074,18 +5084,23 @@ msgid_plural "Print Selected Models With:" msgstr[0] "Geselecteerd model printen met:" msgstr[1] "Geselecteerde modellen printen met:" -#: resources/qml/Menus/ContextMenu.qml:92 +#: resources/qml/Menus/ContextMenu.qml:93 msgctxt "@title:window" msgid "Multiply Selected Model" msgid_plural "Multiply Selected Models" msgstr[0] "Geselecteerd model verveelvoudigen" msgstr[1] "Geselecteerde modellen verveelvoudigen" -#: resources/qml/Menus/ContextMenu.qml:123 +#: resources/qml/Menus/ContextMenu.qml:128 msgctxt "@label" msgid "Number of Copies" msgstr "Aantal exemplaren" +#: resources/qml/Menus/ContextMenu.qml:149 +msgctxt "@label" +msgid "Lock Rotation" +msgstr "" + #: resources/qml/Menus/EditMenu.qml:12 msgctxt "@title:menu menubar:toplevel" msgid "&Edit" diff --git a/resources/i18n/pl_PL/cura.po b/resources/i18n/pl_PL/cura.po index 6bdef88ffd..27734220ad 100644 --- a/resources/i18n/pl_PL/cura.po +++ b/resources/i18n/pl_PL/cura.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Cura 5.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-04-27 12:22+0000\n" +"POT-Creation-Date: 2023-05-11 14:19+0000\n" "PO-Revision-Date: 2021-09-07 08:02+0200\n" "Last-Translator: Mariusz Matłosz \n" "Language-Team: Mariusz Matłosz , reprapy.pl\n" @@ -24,22 +24,22 @@ msgctxt "@info:title" msgid "Login failed" msgstr "Logowanie nie powiodło się" -#: cura/Arranging/ArrangeObjectsJob.py:25 +#: cura/Arranging/ArrangeObjectsJob.py:27 msgctxt "@info:status" msgid "Finding new location for objects" msgstr "Znajdowanie nowej lokalizacji obiektów" -#: cura/Arranging/ArrangeObjectsJob.py:29 +#: cura/Arranging/ArrangeObjectsJob.py:31 msgctxt "@info:title" msgid "Finding Location" msgstr "Szukanie Lokalizacji" -#: cura/Arranging/ArrangeObjectsJob.py:42 cura/MultiplyObjectsJob.py:99 +#: cura/Arranging/ArrangeObjectsJob.py:45 cura/MultiplyObjectsJob.py:101 msgctxt "@info:status" msgid "Unable to find a location within the build volume for all objects" msgstr "Nie można znaleźć lokalizacji w obrębie obszaru roboczego dla wszystkich obiektów" -#: cura/Arranging/ArrangeObjectsJob.py:43 +#: cura/Arranging/ArrangeObjectsJob.py:46 msgctxt "@info:title" msgid "Can't Find Location" msgstr "Nie można Znaleźć Lokalizacji" @@ -266,25 +266,25 @@ msgctxt "@info 'width', 'depth' and 'height' are variable names that must NOT be msgid "%(width).1f x %(depth).1f x %(height).1f mm" msgstr "%(width).1f x %(depth).1f x %(height).1f mm" -#: cura/CuraApplication.py:1816 +#: cura/CuraApplication.py:1817 #, python-brace-format msgctxt "@info:status" msgid "Only one G-code file can be loaded at a time. Skipped importing {0}" msgstr "Jednocześnie można załadować tylko jeden plik G-code. Pominięto importowanie {0}" -#: cura/CuraApplication.py:1818 cura/OAuth2/AuthorizationService.py:217 +#: cura/CuraApplication.py:1819 cura/OAuth2/AuthorizationService.py:217 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:189 msgctxt "@info:title" msgid "Warning" msgstr "Ostrzeżenie" -#: cura/CuraApplication.py:1828 +#: cura/CuraApplication.py:1829 #, python-brace-format msgctxt "@info:status" msgid "Can't open any other file if G-code is loading. Skipped importing {0}" msgstr "Nie można otworzyć żadnego innego pliku, jeśli ładuje się G-code. Pominięto importowanie {0}" -#: cura/CuraApplication.py:1830 cura/Settings/CuraContainerRegistry.py:156 +#: cura/CuraApplication.py:1831 cura/Settings/CuraContainerRegistry.py:156 #: cura/Settings/CuraContainerRegistry.py:166 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:153 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:173 @@ -411,17 +411,17 @@ msgctxt "@info:status" msgid "Calculated" msgstr "Przeliczone" -#: cura/MultiplyObjectsJob.py:30 +#: cura/MultiplyObjectsJob.py:31 msgctxt "@info:status" msgid "Multiplying and placing objects" msgstr "Zwielokrotnienie i umieszczanie przedmiotów" -#: cura/MultiplyObjectsJob.py:32 +#: cura/MultiplyObjectsJob.py:33 msgctxt "@info:title" msgid "Placing Objects" msgstr "Umieść Obiekty" -#: cura/MultiplyObjectsJob.py:100 +#: cura/MultiplyObjectsJob.py:102 msgctxt "@info:title" msgid "Placing Object" msgstr "Rozmieszczenie Obiektów" @@ -3667,17 +3667,17 @@ msgctxt "@action:button" msgid "Remove printers" msgstr "" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:62 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:63 msgctxt "@action:button Preceded by 'Ready to'." msgid "Print over network" msgstr "Drukuj przez sieć" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:63 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:64 msgctxt "@properties:tooltip" msgid "Print over network" msgstr "Drukuj przez sieć" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:64 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:65 msgctxt "@info:status" msgid "Connected over the network" msgstr "Połączone przez sieć" @@ -4216,227 +4216,237 @@ msgctxt "@button" msgid "Cancel" msgstr "Anuluj" -#: resources/qml/Actions.qml:81 +#: resources/qml/Actions.qml:83 msgctxt "@action:inmenu" msgid "Show Online Troubleshooting" msgstr "" -#: resources/qml/Actions.qml:88 +#: resources/qml/Actions.qml:90 msgctxt "@action:inmenu" msgid "Toggle Full Screen" msgstr "Przełącz tryb pełnoekranowy" -#: resources/qml/Actions.qml:96 +#: resources/qml/Actions.qml:98 msgctxt "@action:inmenu" msgid "Exit Full Screen" msgstr "Wyłącz tryb pełnoekranowy" -#: resources/qml/Actions.qml:103 +#: resources/qml/Actions.qml:105 msgctxt "@action:inmenu menubar:edit" msgid "&Undo" msgstr "&Cofnij" -#: resources/qml/Actions.qml:113 +#: resources/qml/Actions.qml:115 msgctxt "@action:inmenu menubar:edit" msgid "&Redo" msgstr "&Ponów" -#: resources/qml/Actions.qml:131 +#: resources/qml/Actions.qml:133 msgctxt "@action:inmenu menubar:file" msgid "&Quit" msgstr "&Zamknij" -#: resources/qml/Actions.qml:139 +#: resources/qml/Actions.qml:141 msgctxt "@action:inmenu menubar:view" msgid "3D View" msgstr "Widok 3D" -#: resources/qml/Actions.qml:146 +#: resources/qml/Actions.qml:148 msgctxt "@action:inmenu menubar:view" msgid "Front View" msgstr "Widok z przodu" -#: resources/qml/Actions.qml:153 +#: resources/qml/Actions.qml:155 msgctxt "@action:inmenu menubar:view" msgid "Top View" msgstr "Widok z góry" -#: resources/qml/Actions.qml:160 +#: resources/qml/Actions.qml:162 msgctxt "@action:inmenu menubar:view" msgid "Bottom View" msgstr "" -#: resources/qml/Actions.qml:167 +#: resources/qml/Actions.qml:169 msgctxt "@action:inmenu menubar:view" msgid "Left Side View" msgstr "Widok z lewej strony" -#: resources/qml/Actions.qml:174 +#: resources/qml/Actions.qml:176 msgctxt "@action:inmenu menubar:view" msgid "Right Side View" msgstr "Widok z prawej strony" -#: resources/qml/Actions.qml:188 +#: resources/qml/Actions.qml:190 msgctxt "@action:inmenu" msgid "Configure Cura..." msgstr "Konfiguruj Cura..." -#: resources/qml/Actions.qml:197 +#: resources/qml/Actions.qml:199 msgctxt "@action:inmenu menubar:printer" msgid "&Add Printer..." msgstr "&Dodaj drukarkę..." -#: resources/qml/Actions.qml:203 +#: resources/qml/Actions.qml:205 msgctxt "@action:inmenu menubar:printer" msgid "Manage Pr&inters..." msgstr "Zarządzaj drukarkami..." -#: resources/qml/Actions.qml:210 +#: resources/qml/Actions.qml:212 msgctxt "@action:inmenu" msgid "Manage Materials..." msgstr "Zarządzaj materiałami..." -#: resources/qml/Actions.qml:218 +#: resources/qml/Actions.qml:220 msgctxt "@action:inmenu Marketplace is a brand name of UltiMaker's, so don't translate." msgid "Add more materials from Marketplace" msgstr "" -#: resources/qml/Actions.qml:225 +#: resources/qml/Actions.qml:227 msgctxt "@action:inmenu menubar:profile" msgid "&Update profile with current settings/overrides" msgstr "&Aktualizuj profil z bieżącymi ustawieniami" -#: resources/qml/Actions.qml:233 +#: resources/qml/Actions.qml:235 msgctxt "@action:inmenu menubar:profile" msgid "&Discard current changes" msgstr "&Odrzuć bieżące zmiany" -#: resources/qml/Actions.qml:245 +#: resources/qml/Actions.qml:247 msgctxt "@action:inmenu menubar:profile" msgid "&Create profile from current settings/overrides..." msgstr "&Utwórz profil z bieżących ustawień..." -#: resources/qml/Actions.qml:251 +#: resources/qml/Actions.qml:253 msgctxt "@action:inmenu menubar:profile" msgid "Manage Profiles..." msgstr "Zarządzaj profilami..." -#: resources/qml/Actions.qml:259 +#: resources/qml/Actions.qml:261 msgctxt "@action:inmenu menubar:help" msgid "Show Online &Documentation" msgstr "Pokaż dokumentację internetową" -#: resources/qml/Actions.qml:267 +#: resources/qml/Actions.qml:269 msgctxt "@action:inmenu menubar:help" msgid "Report a &Bug" msgstr "Zgłoś błąd" -#: resources/qml/Actions.qml:275 +#: resources/qml/Actions.qml:277 msgctxt "@action:inmenu menubar:help" msgid "What's New" msgstr "Co nowego" -#: resources/qml/Actions.qml:289 +#: resources/qml/Actions.qml:291 msgctxt "@action:inmenu menubar:help" msgid "About..." msgstr "O..." -#: resources/qml/Actions.qml:296 +#: resources/qml/Actions.qml:298 msgctxt "@action:inmenu menubar:edit" msgid "Delete Selected" msgstr "" -#: resources/qml/Actions.qml:306 +#: resources/qml/Actions.qml:308 msgctxt "@action:inmenu menubar:edit" msgid "Center Selected" msgstr "" -#: resources/qml/Actions.qml:315 +#: resources/qml/Actions.qml:317 msgctxt "@action:inmenu menubar:edit" msgid "Multiply Selected" msgstr "" -#: resources/qml/Actions.qml:324 +#: resources/qml/Actions.qml:326 msgctxt "@action:inmenu" msgid "Delete Model" msgstr "Usuń model" -#: resources/qml/Actions.qml:332 +#: resources/qml/Actions.qml:334 msgctxt "@action:inmenu" msgid "Ce&nter Model on Platform" msgstr "Wyśrodkuj model na platformie" -#: resources/qml/Actions.qml:338 +#: resources/qml/Actions.qml:340 msgctxt "@action:inmenu menubar:edit" msgid "&Group Models" msgstr "&Grupuj modele" -#: resources/qml/Actions.qml:358 +#: resources/qml/Actions.qml:360 msgctxt "@action:inmenu menubar:edit" msgid "Ungroup Models" msgstr "Rozgrupuj modele" -#: resources/qml/Actions.qml:368 +#: resources/qml/Actions.qml:370 msgctxt "@action:inmenu menubar:edit" msgid "&Merge Models" msgstr "Połącz modele" -#: resources/qml/Actions.qml:378 +#: resources/qml/Actions.qml:380 msgctxt "@action:inmenu" msgid "&Multiply Model..." msgstr "&Powiel model..." -#: resources/qml/Actions.qml:385 +#: resources/qml/Actions.qml:387 msgctxt "@action:inmenu menubar:edit" msgid "Select All Models" msgstr "Wybierz wszystkie modele" -#: resources/qml/Actions.qml:395 +#: resources/qml/Actions.qml:397 msgctxt "@action:inmenu menubar:edit" msgid "Clear Build Plate" msgstr "Wyczyść stół" -#: resources/qml/Actions.qml:405 +#: resources/qml/Actions.qml:407 msgctxt "@action:inmenu menubar:file" msgid "Reload All Models" msgstr "Przeładuj wszystkie modele" -#: resources/qml/Actions.qml:414 +#: resources/qml/Actions.qml:416 msgctxt "@action:inmenu menubar:edit" msgid "Arrange All Models" msgstr "Ułóż wszystkie modele" -#: resources/qml/Actions.qml:422 +#: resources/qml/Actions.qml:424 +msgctxt "@action:inmenu menubar:edit" +msgid "Arrange All Models Without Rotation" +msgstr "" + +#: resources/qml/Actions.qml:431 msgctxt "@action:inmenu menubar:edit" msgid "Arrange Selection" msgstr "Wybór ułożenia" -#: resources/qml/Actions.qml:429 +#: resources/qml/Actions.qml:438 +msgctxt "@action:inmenu menubar:edit" +msgid "Arrange Selection Without Rotation" +msgstr "" + +#: resources/qml/Actions.qml:445 msgctxt "@action:inmenu menubar:edit" msgid "Reset All Model Positions" msgstr "Zresetuj wszystkie pozycje modelu" -#: resources/qml/Actions.qml:436 +#: resources/qml/Actions.qml:452 msgctxt "@action:inmenu menubar:edit" msgid "Reset All Model Transformations" msgstr "Zresetuj wszystkie przekształcenia modelu" -#: resources/qml/Actions.qml:445 +#: resources/qml/Actions.qml:461 msgctxt "@action:inmenu menubar:file" msgid "&Open File(s)..." msgstr "&Otwórz plik(i)..." -#: resources/qml/Actions.qml:455 +#: resources/qml/Actions.qml:471 msgctxt "@action:inmenu menubar:file" msgid "&New Project..." msgstr "&Nowy projekt..." -#: resources/qml/Actions.qml:462 +#: resources/qml/Actions.qml:478 msgctxt "@action:inmenu menubar:help" msgid "Show Configuration Folder" msgstr "Pokaż folder konfiguracji" -#: resources/qml/Actions.qml:469 resources/qml/Settings/SettingView.qml:476 +#: resources/qml/Actions.qml:485 resources/qml/Settings/SettingView.qml:476 msgctxt "@action:menu" msgid "Configure setting visibility..." msgstr "Skonfiguruj widoczność ustawień ..." @@ -5057,18 +5067,23 @@ msgid_plural "Print Selected Models With:" msgstr[0] "Wydrukuj wybrany model z:" msgstr[1] "Wydrukuj wybrane modele z:" -#: resources/qml/Menus/ContextMenu.qml:92 +#: resources/qml/Menus/ContextMenu.qml:93 msgctxt "@title:window" msgid "Multiply Selected Model" msgid_plural "Multiply Selected Models" msgstr[0] "Zduplikuj wybrany model" msgstr[1] "Zduplikuj wybrane modele" -#: resources/qml/Menus/ContextMenu.qml:123 +#: resources/qml/Menus/ContextMenu.qml:128 msgctxt "@label" msgid "Number of Copies" msgstr "Liczba kopii" +#: resources/qml/Menus/ContextMenu.qml:149 +msgctxt "@label" +msgid "Lock Rotation" +msgstr "" + #: resources/qml/Menus/EditMenu.qml:12 msgctxt "@title:menu menubar:toplevel" msgid "&Edit" diff --git a/resources/i18n/pt_BR/cura.po b/resources/i18n/pt_BR/cura.po index 4242a852d5..1973e9e3ed 100644 --- a/resources/i18n/pt_BR/cura.po +++ b/resources/i18n/pt_BR/cura.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Cura 5.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-04-27 12:22+0000\n" +"POT-Creation-Date: 2023-05-11 14:19+0000\n" "PO-Revision-Date: 2023-02-17 17:37+0100\n" "Last-Translator: Cláudio Sampaio \n" "Language-Team: Cláudio Sampaio \n" @@ -23,22 +23,22 @@ msgctxt "@info:title" msgid "Login failed" msgstr "Login falhou" -#: cura/Arranging/ArrangeObjectsJob.py:25 +#: cura/Arranging/ArrangeObjectsJob.py:27 msgctxt "@info:status" msgid "Finding new location for objects" msgstr "Achando novos lugares para objetos" -#: cura/Arranging/ArrangeObjectsJob.py:29 +#: cura/Arranging/ArrangeObjectsJob.py:31 msgctxt "@info:title" msgid "Finding Location" msgstr "Buscando Localização" -#: cura/Arranging/ArrangeObjectsJob.py:42 cura/MultiplyObjectsJob.py:99 +#: cura/Arranging/ArrangeObjectsJob.py:45 cura/MultiplyObjectsJob.py:101 msgctxt "@info:status" msgid "Unable to find a location within the build volume for all objects" msgstr "Não foi possível achar um lugar dentro do volume de construção para todos os objetos" -#: cura/Arranging/ArrangeObjectsJob.py:43 +#: cura/Arranging/ArrangeObjectsJob.py:46 msgctxt "@info:title" msgid "Can't Find Location" msgstr "Não Foi Encontrada Localização" @@ -265,25 +265,25 @@ msgctxt "@info 'width', 'depth' and 'height' are variable names that must NOT be msgid "%(width).1f x %(depth).1f x %(height).1f mm" msgstr "%(width).1f x %(depth).1f x %(height).1f mm" -#: cura/CuraApplication.py:1816 +#: cura/CuraApplication.py:1817 #, python-brace-format msgctxt "@info:status" msgid "Only one G-code file can be loaded at a time. Skipped importing {0}" msgstr "Somente um arquivo G-Code pode ser carregado por vez. Pulando importação de {0}" -#: cura/CuraApplication.py:1818 cura/OAuth2/AuthorizationService.py:217 +#: cura/CuraApplication.py:1819 cura/OAuth2/AuthorizationService.py:217 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:189 msgctxt "@info:title" msgid "Warning" msgstr "Aviso" -#: cura/CuraApplication.py:1828 +#: cura/CuraApplication.py:1829 #, python-brace-format msgctxt "@info:status" msgid "Can't open any other file if G-code is loading. Skipped importing {0}" msgstr "Não é possível abrir nenhum outro arquivo se G-Code estiver sendo carregado. Pulando importação de {0}" -#: cura/CuraApplication.py:1830 cura/Settings/CuraContainerRegistry.py:156 +#: cura/CuraApplication.py:1831 cura/Settings/CuraContainerRegistry.py:156 #: cura/Settings/CuraContainerRegistry.py:166 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:153 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:173 @@ -410,17 +410,17 @@ msgctxt "@info:status" msgid "Calculated" msgstr "Calculado" -#: cura/MultiplyObjectsJob.py:30 +#: cura/MultiplyObjectsJob.py:31 msgctxt "@info:status" msgid "Multiplying and placing objects" msgstr "Multiplicando e colocando objetos" -#: cura/MultiplyObjectsJob.py:32 +#: cura/MultiplyObjectsJob.py:33 msgctxt "@info:title" msgid "Placing Objects" msgstr "Colocando Objetos" -#: cura/MultiplyObjectsJob.py:100 +#: cura/MultiplyObjectsJob.py:102 msgctxt "@info:title" msgid "Placing Object" msgstr "Colocando Objeto" @@ -3678,17 +3678,17 @@ msgctxt "@action:button" msgid "Remove printers" msgstr "Remover impressoras" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:62 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:63 msgctxt "@action:button Preceded by 'Ready to'." msgid "Print over network" msgstr "Imprimir pela rede" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:63 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:64 msgctxt "@properties:tooltip" msgid "Print over network" msgstr "Imprime pela rede" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:64 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:65 msgctxt "@info:status" msgid "Connected over the network" msgstr "Conectado pela rede" @@ -4230,227 +4230,237 @@ msgctxt "@button" msgid "Cancel" msgstr "Cancelar" -#: resources/qml/Actions.qml:81 +#: resources/qml/Actions.qml:83 msgctxt "@action:inmenu" msgid "Show Online Troubleshooting" msgstr "Mostrar Resolução de Problemas Online" -#: resources/qml/Actions.qml:88 +#: resources/qml/Actions.qml:90 msgctxt "@action:inmenu" msgid "Toggle Full Screen" msgstr "Alternar Tela Cheia" -#: resources/qml/Actions.qml:96 +#: resources/qml/Actions.qml:98 msgctxt "@action:inmenu" msgid "Exit Full Screen" msgstr "Sair da Tela Cheia" -#: resources/qml/Actions.qml:103 +#: resources/qml/Actions.qml:105 msgctxt "@action:inmenu menubar:edit" msgid "&Undo" msgstr "Desfazer (&U)" -#: resources/qml/Actions.qml:113 +#: resources/qml/Actions.qml:115 msgctxt "@action:inmenu menubar:edit" msgid "&Redo" msgstr "&Refazer" -#: resources/qml/Actions.qml:131 +#: resources/qml/Actions.qml:133 msgctxt "@action:inmenu menubar:file" msgid "&Quit" msgstr "Sair (&Q)" -#: resources/qml/Actions.qml:139 +#: resources/qml/Actions.qml:141 msgctxt "@action:inmenu menubar:view" msgid "3D View" msgstr "Visão &3D" -#: resources/qml/Actions.qml:146 +#: resources/qml/Actions.qml:148 msgctxt "@action:inmenu menubar:view" msgid "Front View" msgstr "Visão Frontal" -#: resources/qml/Actions.qml:153 +#: resources/qml/Actions.qml:155 msgctxt "@action:inmenu menubar:view" msgid "Top View" msgstr "Visão Superior" -#: resources/qml/Actions.qml:160 +#: resources/qml/Actions.qml:162 msgctxt "@action:inmenu menubar:view" msgid "Bottom View" msgstr "Visão de Baixo" -#: resources/qml/Actions.qml:167 +#: resources/qml/Actions.qml:169 msgctxt "@action:inmenu menubar:view" msgid "Left Side View" msgstr "Visão do Lado Esquerdo" -#: resources/qml/Actions.qml:174 +#: resources/qml/Actions.qml:176 msgctxt "@action:inmenu menubar:view" msgid "Right Side View" msgstr "Visão do Lado Direito" -#: resources/qml/Actions.qml:188 +#: resources/qml/Actions.qml:190 msgctxt "@action:inmenu" msgid "Configure Cura..." msgstr "Configurar Cura..." -#: resources/qml/Actions.qml:197 +#: resources/qml/Actions.qml:199 msgctxt "@action:inmenu menubar:printer" msgid "&Add Printer..." msgstr "&Adicionar Impressora..." -#: resources/qml/Actions.qml:203 +#: resources/qml/Actions.qml:205 msgctxt "@action:inmenu menubar:printer" msgid "Manage Pr&inters..." msgstr "Adm&inistrar Impressoras..." -#: resources/qml/Actions.qml:210 +#: resources/qml/Actions.qml:212 msgctxt "@action:inmenu" msgid "Manage Materials..." msgstr "Administrar Materiais..." -#: resources/qml/Actions.qml:218 +#: resources/qml/Actions.qml:220 msgctxt "@action:inmenu Marketplace is a brand name of UltiMaker's, so don't translate." msgid "Add more materials from Marketplace" msgstr "Adicionar mais materiais ao Marketplace" -#: resources/qml/Actions.qml:225 +#: resources/qml/Actions.qml:227 msgctxt "@action:inmenu menubar:profile" msgid "&Update profile with current settings/overrides" msgstr "At&ualizar perfil com valores e sobreposições atuais" -#: resources/qml/Actions.qml:233 +#: resources/qml/Actions.qml:235 msgctxt "@action:inmenu menubar:profile" msgid "&Discard current changes" msgstr "&Descartar ajustes atuais" -#: resources/qml/Actions.qml:245 +#: resources/qml/Actions.qml:247 msgctxt "@action:inmenu menubar:profile" msgid "&Create profile from current settings/overrides..." msgstr "&Criar perfil a partir de ajustes/sobreposições atuais..." -#: resources/qml/Actions.qml:251 +#: resources/qml/Actions.qml:253 msgctxt "@action:inmenu menubar:profile" msgid "Manage Profiles..." msgstr "Administrar perfis..." -#: resources/qml/Actions.qml:259 +#: resources/qml/Actions.qml:261 msgctxt "@action:inmenu menubar:help" msgid "Show Online &Documentation" msgstr "Exibir &Documentação Online" -#: resources/qml/Actions.qml:267 +#: resources/qml/Actions.qml:269 msgctxt "@action:inmenu menubar:help" msgid "Report a &Bug" msgstr "Relatar um &Bug" -#: resources/qml/Actions.qml:275 +#: resources/qml/Actions.qml:277 msgctxt "@action:inmenu menubar:help" msgid "What's New" msgstr "Novidades" -#: resources/qml/Actions.qml:289 +#: resources/qml/Actions.qml:291 msgctxt "@action:inmenu menubar:help" msgid "About..." msgstr "Sobre..." -#: resources/qml/Actions.qml:296 +#: resources/qml/Actions.qml:298 msgctxt "@action:inmenu menubar:edit" msgid "Delete Selected" msgstr "Remover Selecionados" -#: resources/qml/Actions.qml:306 +#: resources/qml/Actions.qml:308 msgctxt "@action:inmenu menubar:edit" msgid "Center Selected" msgstr "Centralizar Selecionados" -#: resources/qml/Actions.qml:315 +#: resources/qml/Actions.qml:317 msgctxt "@action:inmenu menubar:edit" msgid "Multiply Selected" msgstr "Multiplicar Selecionados" -#: resources/qml/Actions.qml:324 +#: resources/qml/Actions.qml:326 msgctxt "@action:inmenu" msgid "Delete Model" msgstr "Remover Modelo" -#: resources/qml/Actions.qml:332 +#: resources/qml/Actions.qml:334 msgctxt "@action:inmenu" msgid "Ce&nter Model on Platform" msgstr "Ce&ntralizar Modelo na Mesa" -#: resources/qml/Actions.qml:338 +#: resources/qml/Actions.qml:340 msgctxt "@action:inmenu menubar:edit" msgid "&Group Models" msgstr "A&grupar Modelos" -#: resources/qml/Actions.qml:358 +#: resources/qml/Actions.qml:360 msgctxt "@action:inmenu menubar:edit" msgid "Ungroup Models" msgstr "Desagrupar Modelos" -#: resources/qml/Actions.qml:368 +#: resources/qml/Actions.qml:370 msgctxt "@action:inmenu menubar:edit" msgid "&Merge Models" msgstr "Co&mbinar Modelos" -#: resources/qml/Actions.qml:378 +#: resources/qml/Actions.qml:380 msgctxt "@action:inmenu" msgid "&Multiply Model..." msgstr "&Multiplicar Modelo..." -#: resources/qml/Actions.qml:385 +#: resources/qml/Actions.qml:387 msgctxt "@action:inmenu menubar:edit" msgid "Select All Models" msgstr "Selecionar Todos Os Modelos" -#: resources/qml/Actions.qml:395 +#: resources/qml/Actions.qml:397 msgctxt "@action:inmenu menubar:edit" msgid "Clear Build Plate" msgstr "Esvaziar a Mesa de Impressão" -#: resources/qml/Actions.qml:405 +#: resources/qml/Actions.qml:407 msgctxt "@action:inmenu menubar:file" msgid "Reload All Models" msgstr "Recarregar Todos Os Modelos" -#: resources/qml/Actions.qml:414 +#: resources/qml/Actions.qml:416 msgctxt "@action:inmenu menubar:edit" msgid "Arrange All Models" msgstr "Posicionar Todos os Modelos" -#: resources/qml/Actions.qml:422 +#: resources/qml/Actions.qml:424 +msgctxt "@action:inmenu menubar:edit" +msgid "Arrange All Models Without Rotation" +msgstr "" + +#: resources/qml/Actions.qml:431 msgctxt "@action:inmenu menubar:edit" msgid "Arrange Selection" msgstr "Posicionar Seleção" -#: resources/qml/Actions.qml:429 +#: resources/qml/Actions.qml:438 +msgctxt "@action:inmenu menubar:edit" +msgid "Arrange Selection Without Rotation" +msgstr "" + +#: resources/qml/Actions.qml:445 msgctxt "@action:inmenu menubar:edit" msgid "Reset All Model Positions" msgstr "Reestabelecer as Posições de Todos Os Modelos" -#: resources/qml/Actions.qml:436 +#: resources/qml/Actions.qml:452 msgctxt "@action:inmenu menubar:edit" msgid "Reset All Model Transformations" msgstr "Remover as Transformações de Todos Os Modelos" -#: resources/qml/Actions.qml:445 +#: resources/qml/Actions.qml:461 msgctxt "@action:inmenu menubar:file" msgid "&Open File(s)..." msgstr "Abrir Arquiv&o(s)..." -#: resources/qml/Actions.qml:455 +#: resources/qml/Actions.qml:471 msgctxt "@action:inmenu menubar:file" msgid "&New Project..." msgstr "&Novo Projeto..." -#: resources/qml/Actions.qml:462 +#: resources/qml/Actions.qml:478 msgctxt "@action:inmenu menubar:help" msgid "Show Configuration Folder" msgstr "Exibir Pasta de Configuração" -#: resources/qml/Actions.qml:469 resources/qml/Settings/SettingView.qml:476 +#: resources/qml/Actions.qml:485 resources/qml/Settings/SettingView.qml:476 msgctxt "@action:menu" msgid "Configure setting visibility..." msgstr "Configurar a visibilidade dos ajustes..." @@ -5071,18 +5081,23 @@ msgid_plural "Print Selected Models With:" msgstr[0] "Imprimir Modelo Selecionado Com:" msgstr[1] "Imprimir Modelos Selecionados Com:" -#: resources/qml/Menus/ContextMenu.qml:92 +#: resources/qml/Menus/ContextMenu.qml:93 msgctxt "@title:window" msgid "Multiply Selected Model" msgid_plural "Multiply Selected Models" msgstr[0] "Multiplicar Modelo Selecionado" msgstr[1] "Multiplicar Modelos Selecionados" -#: resources/qml/Menus/ContextMenu.qml:123 +#: resources/qml/Menus/ContextMenu.qml:128 msgctxt "@label" msgid "Number of Copies" msgstr "Número de Cópias" +#: resources/qml/Menus/ContextMenu.qml:149 +msgctxt "@label" +msgid "Lock Rotation" +msgstr "" + #: resources/qml/Menus/EditMenu.qml:12 msgctxt "@title:menu menubar:toplevel" msgid "&Edit" diff --git a/resources/i18n/pt_PT/cura.po b/resources/i18n/pt_PT/cura.po index 21eace1a53..2f683461e6 100644 --- a/resources/i18n/pt_PT/cura.po +++ b/resources/i18n/pt_PT/cura.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-04-27 12:22+0000\n" +"POT-Creation-Date: 2023-05-11 14:19+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -23,22 +23,22 @@ msgctxt "@info:title" msgid "Login failed" msgstr "Falha no início de sessão" -#: cura/Arranging/ArrangeObjectsJob.py:25 +#: cura/Arranging/ArrangeObjectsJob.py:27 msgctxt "@info:status" msgid "Finding new location for objects" msgstr "A procurar nova posição para os objetos" -#: cura/Arranging/ArrangeObjectsJob.py:29 +#: cura/Arranging/ArrangeObjectsJob.py:31 msgctxt "@info:title" msgid "Finding Location" msgstr "A Procurar Posição" -#: cura/Arranging/ArrangeObjectsJob.py:42 cura/MultiplyObjectsJob.py:99 +#: cura/Arranging/ArrangeObjectsJob.py:45 cura/MultiplyObjectsJob.py:101 msgctxt "@info:status" msgid "Unable to find a location within the build volume for all objects" msgstr "Não é possível posicionar todos os objetos dentro do volume de construção" -#: cura/Arranging/ArrangeObjectsJob.py:43 +#: cura/Arranging/ArrangeObjectsJob.py:46 msgctxt "@info:title" msgid "Can't Find Location" msgstr "Não é Possível Posicionar" @@ -265,25 +265,25 @@ msgctxt "@info 'width', 'depth' and 'height' are variable names that must NOT be msgid "%(width).1f x %(depth).1f x %(height).1f mm" msgstr "%(width).1f x %(depth).1f x %(height).1f mm" -#: cura/CuraApplication.py:1816 +#: cura/CuraApplication.py:1817 #, python-brace-format msgctxt "@info:status" msgid "Only one G-code file can be loaded at a time. Skipped importing {0}" msgstr "Apenas pode ser carregado um ficheiro G-code de cada vez. Importação {0} ignorada" -#: cura/CuraApplication.py:1818 cura/OAuth2/AuthorizationService.py:217 +#: cura/CuraApplication.py:1819 cura/OAuth2/AuthorizationService.py:217 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:189 msgctxt "@info:title" msgid "Warning" msgstr "Aviso" -#: cura/CuraApplication.py:1828 +#: cura/CuraApplication.py:1829 #, python-brace-format msgctxt "@info:status" msgid "Can't open any other file if G-code is loading. Skipped importing {0}" msgstr "Não é possível abrir outro ficheiro enquanto o G-code estiver a carregar. Importação {0} ignorada" -#: cura/CuraApplication.py:1830 cura/Settings/CuraContainerRegistry.py:156 +#: cura/CuraApplication.py:1831 cura/Settings/CuraContainerRegistry.py:156 #: cura/Settings/CuraContainerRegistry.py:166 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:153 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:173 @@ -410,17 +410,17 @@ msgctxt "@info:status" msgid "Calculated" msgstr "Calculado" -#: cura/MultiplyObjectsJob.py:30 +#: cura/MultiplyObjectsJob.py:31 msgctxt "@info:status" msgid "Multiplying and placing objects" msgstr "Multiplicar e posicionar objetos" -#: cura/MultiplyObjectsJob.py:32 +#: cura/MultiplyObjectsJob.py:33 msgctxt "@info:title" msgid "Placing Objects" msgstr "A posicionar objetos" -#: cura/MultiplyObjectsJob.py:100 +#: cura/MultiplyObjectsJob.py:102 msgctxt "@info:title" msgid "Placing Object" msgstr "A Posicionar Objeto" @@ -3676,17 +3676,17 @@ msgctxt "@action:button" msgid "Remove printers" msgstr "Remover impressoras" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:62 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:63 msgctxt "@action:button Preceded by 'Ready to'." msgid "Print over network" msgstr "Imprimir através da rede" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:63 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:64 msgctxt "@properties:tooltip" msgid "Print over network" msgstr "Imprimir através da rede" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:64 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:65 msgctxt "@info:status" msgid "Connected over the network" msgstr "Ligado através da rede" @@ -4228,227 +4228,237 @@ msgctxt "@button" msgid "Cancel" msgstr "Cancelar" -#: resources/qml/Actions.qml:81 +#: resources/qml/Actions.qml:83 msgctxt "@action:inmenu" msgid "Show Online Troubleshooting" msgstr "Ver online o guia de resolução de problemas" -#: resources/qml/Actions.qml:88 +#: resources/qml/Actions.qml:90 msgctxt "@action:inmenu" msgid "Toggle Full Screen" msgstr "Alternar para ecrã inteiro" -#: resources/qml/Actions.qml:96 +#: resources/qml/Actions.qml:98 msgctxt "@action:inmenu" msgid "Exit Full Screen" msgstr "Sair do Ecrã Inteiro" -#: resources/qml/Actions.qml:103 +#: resources/qml/Actions.qml:105 msgctxt "@action:inmenu menubar:edit" msgid "&Undo" msgstr "&Desfazer" -#: resources/qml/Actions.qml:113 +#: resources/qml/Actions.qml:115 msgctxt "@action:inmenu menubar:edit" msgid "&Redo" msgstr "&Refazer" -#: resources/qml/Actions.qml:131 +#: resources/qml/Actions.qml:133 msgctxt "@action:inmenu menubar:file" msgid "&Quit" msgstr "&Sair" -#: resources/qml/Actions.qml:139 +#: resources/qml/Actions.qml:141 msgctxt "@action:inmenu menubar:view" msgid "3D View" msgstr "Vista 3D" -#: resources/qml/Actions.qml:146 +#: resources/qml/Actions.qml:148 msgctxt "@action:inmenu menubar:view" msgid "Front View" msgstr "Vista Frente" -#: resources/qml/Actions.qml:153 +#: resources/qml/Actions.qml:155 msgctxt "@action:inmenu menubar:view" msgid "Top View" msgstr "Vista Cima" -#: resources/qml/Actions.qml:160 +#: resources/qml/Actions.qml:162 msgctxt "@action:inmenu menubar:view" msgid "Bottom View" msgstr "Vista Inferior" -#: resources/qml/Actions.qml:167 +#: resources/qml/Actions.qml:169 msgctxt "@action:inmenu menubar:view" msgid "Left Side View" msgstr "Vista Lado Esquerdo" -#: resources/qml/Actions.qml:174 +#: resources/qml/Actions.qml:176 msgctxt "@action:inmenu menubar:view" msgid "Right Side View" msgstr "Vista Lado Direito" -#: resources/qml/Actions.qml:188 +#: resources/qml/Actions.qml:190 msgctxt "@action:inmenu" msgid "Configure Cura..." msgstr "Configurar Cura..." -#: resources/qml/Actions.qml:197 +#: resources/qml/Actions.qml:199 msgctxt "@action:inmenu menubar:printer" msgid "&Add Printer..." msgstr "&Adicionar Impressora..." -#: resources/qml/Actions.qml:203 +#: resources/qml/Actions.qml:205 msgctxt "@action:inmenu menubar:printer" msgid "Manage Pr&inters..." msgstr "Gerir Im&pressoras..." -#: resources/qml/Actions.qml:210 +#: resources/qml/Actions.qml:212 msgctxt "@action:inmenu" msgid "Manage Materials..." msgstr "Gerir Materiais..." -#: resources/qml/Actions.qml:218 +#: resources/qml/Actions.qml:220 msgctxt "@action:inmenu Marketplace is a brand name of UltiMaker's, so don't translate." msgid "Add more materials from Marketplace" msgstr "Adicionar mais materiais disponíveis no Marketplace" -#: resources/qml/Actions.qml:225 +#: resources/qml/Actions.qml:227 msgctxt "@action:inmenu menubar:profile" msgid "&Update profile with current settings/overrides" msgstr "&Atualizar perfil com as definições/substituições atuais" -#: resources/qml/Actions.qml:233 +#: resources/qml/Actions.qml:235 msgctxt "@action:inmenu menubar:profile" msgid "&Discard current changes" msgstr "&Descartar alterações atuais" -#: resources/qml/Actions.qml:245 +#: resources/qml/Actions.qml:247 msgctxt "@action:inmenu menubar:profile" msgid "&Create profile from current settings/overrides..." msgstr "&Criar perfil a partir das definições/substituições atuais..." -#: resources/qml/Actions.qml:251 +#: resources/qml/Actions.qml:253 msgctxt "@action:inmenu menubar:profile" msgid "Manage Profiles..." msgstr "Gerir Perfis..." -#: resources/qml/Actions.qml:259 +#: resources/qml/Actions.qml:261 msgctxt "@action:inmenu menubar:help" msgid "Show Online &Documentation" msgstr "Mostrar &documentação online" -#: resources/qml/Actions.qml:267 +#: resources/qml/Actions.qml:269 msgctxt "@action:inmenu menubar:help" msgid "Report a &Bug" msgstr "Reportar um &erro" -#: resources/qml/Actions.qml:275 +#: resources/qml/Actions.qml:277 msgctxt "@action:inmenu menubar:help" msgid "What's New" msgstr "Novidades" -#: resources/qml/Actions.qml:289 +#: resources/qml/Actions.qml:291 msgctxt "@action:inmenu menubar:help" msgid "About..." msgstr "Sobre..." -#: resources/qml/Actions.qml:296 +#: resources/qml/Actions.qml:298 msgctxt "@action:inmenu menubar:edit" msgid "Delete Selected" msgstr "Apagar seleção" -#: resources/qml/Actions.qml:306 +#: resources/qml/Actions.qml:308 msgctxt "@action:inmenu menubar:edit" msgid "Center Selected" msgstr "Centrar seleção" -#: resources/qml/Actions.qml:315 +#: resources/qml/Actions.qml:317 msgctxt "@action:inmenu menubar:edit" msgid "Multiply Selected" msgstr "Multiplicar seleção" -#: resources/qml/Actions.qml:324 +#: resources/qml/Actions.qml:326 msgctxt "@action:inmenu" msgid "Delete Model" msgstr "Apagar Modelo" -#: resources/qml/Actions.qml:332 +#: resources/qml/Actions.qml:334 msgctxt "@action:inmenu" msgid "Ce&nter Model on Platform" msgstr "Ce&ntrar Modelo na Base" -#: resources/qml/Actions.qml:338 +#: resources/qml/Actions.qml:340 msgctxt "@action:inmenu menubar:edit" msgid "&Group Models" msgstr "&Agrupar Modelos" -#: resources/qml/Actions.qml:358 +#: resources/qml/Actions.qml:360 msgctxt "@action:inmenu menubar:edit" msgid "Ungroup Models" msgstr "Desagrupar Modelos" -#: resources/qml/Actions.qml:368 +#: resources/qml/Actions.qml:370 msgctxt "@action:inmenu menubar:edit" msgid "&Merge Models" msgstr "&Combinar Modelos" -#: resources/qml/Actions.qml:378 +#: resources/qml/Actions.qml:380 msgctxt "@action:inmenu" msgid "&Multiply Model..." msgstr "&Multiplicar Modelo..." -#: resources/qml/Actions.qml:385 +#: resources/qml/Actions.qml:387 msgctxt "@action:inmenu menubar:edit" msgid "Select All Models" msgstr "Selecionar todos os modelos" -#: resources/qml/Actions.qml:395 +#: resources/qml/Actions.qml:397 msgctxt "@action:inmenu menubar:edit" msgid "Clear Build Plate" msgstr "Limpar base de construção" -#: resources/qml/Actions.qml:405 +#: resources/qml/Actions.qml:407 msgctxt "@action:inmenu menubar:file" msgid "Reload All Models" msgstr "Recarregar todos os modelos" -#: resources/qml/Actions.qml:414 +#: resources/qml/Actions.qml:416 msgctxt "@action:inmenu menubar:edit" msgid "Arrange All Models" msgstr "Dispor todos os modelos" -#: resources/qml/Actions.qml:422 +#: resources/qml/Actions.qml:424 +msgctxt "@action:inmenu menubar:edit" +msgid "Arrange All Models Without Rotation" +msgstr "" + +#: resources/qml/Actions.qml:431 msgctxt "@action:inmenu menubar:edit" msgid "Arrange Selection" msgstr "Dispor seleção" -#: resources/qml/Actions.qml:429 +#: resources/qml/Actions.qml:438 +msgctxt "@action:inmenu menubar:edit" +msgid "Arrange Selection Without Rotation" +msgstr "" + +#: resources/qml/Actions.qml:445 msgctxt "@action:inmenu menubar:edit" msgid "Reset All Model Positions" msgstr "Repor todas as posições de modelos" -#: resources/qml/Actions.qml:436 +#: resources/qml/Actions.qml:452 msgctxt "@action:inmenu menubar:edit" msgid "Reset All Model Transformations" msgstr "Repor Todas as Transformações do Modelo" -#: resources/qml/Actions.qml:445 +#: resources/qml/Actions.qml:461 msgctxt "@action:inmenu menubar:file" msgid "&Open File(s)..." msgstr "&Abrir Ficheiro(s)..." -#: resources/qml/Actions.qml:455 +#: resources/qml/Actions.qml:471 msgctxt "@action:inmenu menubar:file" msgid "&New Project..." msgstr "&Novo Projeto..." -#: resources/qml/Actions.qml:462 +#: resources/qml/Actions.qml:478 msgctxt "@action:inmenu menubar:help" msgid "Show Configuration Folder" msgstr "Mostrar pasta de configuração" -#: resources/qml/Actions.qml:469 resources/qml/Settings/SettingView.qml:476 +#: resources/qml/Actions.qml:485 resources/qml/Settings/SettingView.qml:476 msgctxt "@action:menu" msgid "Configure setting visibility..." msgstr "Configurar visibilidade das definições..." @@ -5072,18 +5082,23 @@ msgid_plural "Print Selected Models With:" msgstr[0] "Imprimir Modelo Selecionado Com:" msgstr[1] "Imprimir modelos selecionados com:" -#: resources/qml/Menus/ContextMenu.qml:92 +#: resources/qml/Menus/ContextMenu.qml:93 msgctxt "@title:window" msgid "Multiply Selected Model" msgid_plural "Multiply Selected Models" msgstr[0] "Multiplicar Modelo Selecionado" msgstr[1] "Multiplicar modelos selecionados" -#: resources/qml/Menus/ContextMenu.qml:123 +#: resources/qml/Menus/ContextMenu.qml:128 msgctxt "@label" msgid "Number of Copies" msgstr "Número de Cópias" +#: resources/qml/Menus/ContextMenu.qml:149 +msgctxt "@label" +msgid "Lock Rotation" +msgstr "" + #: resources/qml/Menus/EditMenu.qml:12 msgctxt "@title:menu menubar:toplevel" msgid "&Edit" diff --git a/resources/i18n/ru_RU/cura.po b/resources/i18n/ru_RU/cura.po index a43df3e590..15431cabc9 100644 --- a/resources/i18n/ru_RU/cura.po +++ b/resources/i18n/ru_RU/cura.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-04-27 12:22+0000\n" +"POT-Creation-Date: 2023-05-11 14:19+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -23,22 +23,22 @@ msgctxt "@info:title" msgid "Login failed" msgstr "Вход не выполнен" -#: cura/Arranging/ArrangeObjectsJob.py:25 +#: cura/Arranging/ArrangeObjectsJob.py:27 msgctxt "@info:status" msgid "Finding new location for objects" msgstr "Поиск места для новых объектов" -#: cura/Arranging/ArrangeObjectsJob.py:29 +#: cura/Arranging/ArrangeObjectsJob.py:31 msgctxt "@info:title" msgid "Finding Location" msgstr "Поиск места" -#: cura/Arranging/ArrangeObjectsJob.py:42 cura/MultiplyObjectsJob.py:99 +#: cura/Arranging/ArrangeObjectsJob.py:45 cura/MultiplyObjectsJob.py:101 msgctxt "@info:status" msgid "Unable to find a location within the build volume for all objects" msgstr "Невозможно разместить все объекты внутри печатаемого объёма" -#: cura/Arranging/ArrangeObjectsJob.py:43 +#: cura/Arranging/ArrangeObjectsJob.py:46 msgctxt "@info:title" msgid "Can't Find Location" msgstr "Не могу найти место" @@ -265,25 +265,25 @@ msgctxt "@info 'width', 'depth' and 'height' are variable names that must NOT be msgid "%(width).1f x %(depth).1f x %(height).1f mm" msgstr "%(width).1f x %(depth).1f x %(height).1f мм" -#: cura/CuraApplication.py:1816 +#: cura/CuraApplication.py:1817 #, python-brace-format msgctxt "@info:status" msgid "Only one G-code file can be loaded at a time. Skipped importing {0}" msgstr "Только один G-code файла может быть загружен в момент времени. Пропускаю импортирование {0}" -#: cura/CuraApplication.py:1818 cura/OAuth2/AuthorizationService.py:217 +#: cura/CuraApplication.py:1819 cura/OAuth2/AuthorizationService.py:217 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:189 msgctxt "@info:title" msgid "Warning" msgstr "Внимание" -#: cura/CuraApplication.py:1828 +#: cura/CuraApplication.py:1829 #, python-brace-format msgctxt "@info:status" msgid "Can't open any other file if G-code is loading. Skipped importing {0}" msgstr "Невозможно открыть любой другой файл, если G-code файл уже загружен. Пропускаю импортирование {0}" -#: cura/CuraApplication.py:1830 cura/Settings/CuraContainerRegistry.py:156 +#: cura/CuraApplication.py:1831 cura/Settings/CuraContainerRegistry.py:156 #: cura/Settings/CuraContainerRegistry.py:166 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:153 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:173 @@ -410,17 +410,17 @@ msgctxt "@info:status" msgid "Calculated" msgstr "Вычислено" -#: cura/MultiplyObjectsJob.py:30 +#: cura/MultiplyObjectsJob.py:31 msgctxt "@info:status" msgid "Multiplying and placing objects" msgstr "Размножение и размещение объектов" -#: cura/MultiplyObjectsJob.py:32 +#: cura/MultiplyObjectsJob.py:33 msgctxt "@info:title" msgid "Placing Objects" msgstr "Размещение объектов" -#: cura/MultiplyObjectsJob.py:100 +#: cura/MultiplyObjectsJob.py:102 msgctxt "@info:title" msgid "Placing Object" msgstr "Размещение объекта" @@ -3687,17 +3687,17 @@ msgctxt "@action:button" msgid "Remove printers" msgstr "Удалить принтеры" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:62 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:63 msgctxt "@action:button Preceded by 'Ready to'." msgid "Print over network" msgstr "Печать через сеть" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:63 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:64 msgctxt "@properties:tooltip" msgid "Print over network" msgstr "Печать через сеть" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:64 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:65 msgctxt "@info:status" msgid "Connected over the network" msgstr "Подключен по сети" @@ -4239,227 +4239,237 @@ msgctxt "@button" msgid "Cancel" msgstr "Отмена" -#: resources/qml/Actions.qml:81 +#: resources/qml/Actions.qml:83 msgctxt "@action:inmenu" msgid "Show Online Troubleshooting" msgstr "Показать сетевое руководство по устранению неполадок" -#: resources/qml/Actions.qml:88 +#: resources/qml/Actions.qml:90 msgctxt "@action:inmenu" msgid "Toggle Full Screen" msgstr "Полный экран" -#: resources/qml/Actions.qml:96 +#: resources/qml/Actions.qml:98 msgctxt "@action:inmenu" msgid "Exit Full Screen" msgstr "Выйти из полноэкранного режима" -#: resources/qml/Actions.qml:103 +#: resources/qml/Actions.qml:105 msgctxt "@action:inmenu menubar:edit" msgid "&Undo" msgstr "Отмена" -#: resources/qml/Actions.qml:113 +#: resources/qml/Actions.qml:115 msgctxt "@action:inmenu menubar:edit" msgid "&Redo" msgstr "Возврат" -#: resources/qml/Actions.qml:131 +#: resources/qml/Actions.qml:133 msgctxt "@action:inmenu menubar:file" msgid "&Quit" msgstr "Выход" -#: resources/qml/Actions.qml:139 +#: resources/qml/Actions.qml:141 msgctxt "@action:inmenu menubar:view" msgid "3D View" msgstr "Трехмерный вид" -#: resources/qml/Actions.qml:146 +#: resources/qml/Actions.qml:148 msgctxt "@action:inmenu menubar:view" msgid "Front View" msgstr "Вид спереди" -#: resources/qml/Actions.qml:153 +#: resources/qml/Actions.qml:155 msgctxt "@action:inmenu menubar:view" msgid "Top View" msgstr "Вид сверху" -#: resources/qml/Actions.qml:160 +#: resources/qml/Actions.qml:162 msgctxt "@action:inmenu menubar:view" msgid "Bottom View" msgstr "Вид снизу" -#: resources/qml/Actions.qml:167 +#: resources/qml/Actions.qml:169 msgctxt "@action:inmenu menubar:view" msgid "Left Side View" msgstr "Вид слева" -#: resources/qml/Actions.qml:174 +#: resources/qml/Actions.qml:176 msgctxt "@action:inmenu menubar:view" msgid "Right Side View" msgstr "Вид справа" -#: resources/qml/Actions.qml:188 +#: resources/qml/Actions.qml:190 msgctxt "@action:inmenu" msgid "Configure Cura..." msgstr "Настроить Cura..." -#: resources/qml/Actions.qml:197 +#: resources/qml/Actions.qml:199 msgctxt "@action:inmenu menubar:printer" msgid "&Add Printer..." msgstr "Добавить принтер..." -#: resources/qml/Actions.qml:203 +#: resources/qml/Actions.qml:205 msgctxt "@action:inmenu menubar:printer" msgid "Manage Pr&inters..." msgstr "Управление принтерами..." -#: resources/qml/Actions.qml:210 +#: resources/qml/Actions.qml:212 msgctxt "@action:inmenu" msgid "Manage Materials..." msgstr "Управление материалами..." -#: resources/qml/Actions.qml:218 +#: resources/qml/Actions.qml:220 msgctxt "@action:inmenu Marketplace is a brand name of UltiMaker's, so don't translate." msgid "Add more materials from Marketplace" msgstr "Добавить больше материалов из Магазина" -#: resources/qml/Actions.qml:225 +#: resources/qml/Actions.qml:227 msgctxt "@action:inmenu menubar:profile" msgid "&Update profile with current settings/overrides" msgstr "Обновить профиль текущими параметрами" -#: resources/qml/Actions.qml:233 +#: resources/qml/Actions.qml:235 msgctxt "@action:inmenu menubar:profile" msgid "&Discard current changes" msgstr "Сбросить текущие параметры" -#: resources/qml/Actions.qml:245 +#: resources/qml/Actions.qml:247 msgctxt "@action:inmenu menubar:profile" msgid "&Create profile from current settings/overrides..." msgstr "Создать профиль из текущих параметров..." -#: resources/qml/Actions.qml:251 +#: resources/qml/Actions.qml:253 msgctxt "@action:inmenu menubar:profile" msgid "Manage Profiles..." msgstr "Управление профилями..." -#: resources/qml/Actions.qml:259 +#: resources/qml/Actions.qml:261 msgctxt "@action:inmenu menubar:help" msgid "Show Online &Documentation" msgstr "Показать онлайн документацию" -#: resources/qml/Actions.qml:267 +#: resources/qml/Actions.qml:269 msgctxt "@action:inmenu menubar:help" msgid "Report a &Bug" msgstr "Отправить отчёт об ошибке" -#: resources/qml/Actions.qml:275 +#: resources/qml/Actions.qml:277 msgctxt "@action:inmenu menubar:help" msgid "What's New" msgstr "Что нового" -#: resources/qml/Actions.qml:289 +#: resources/qml/Actions.qml:291 msgctxt "@action:inmenu menubar:help" msgid "About..." msgstr "О Cura..." -#: resources/qml/Actions.qml:296 +#: resources/qml/Actions.qml:298 msgctxt "@action:inmenu menubar:edit" msgid "Delete Selected" msgstr "Удалить выбранное" -#: resources/qml/Actions.qml:306 +#: resources/qml/Actions.qml:308 msgctxt "@action:inmenu menubar:edit" msgid "Center Selected" msgstr "Центрировать выбранное" -#: resources/qml/Actions.qml:315 +#: resources/qml/Actions.qml:317 msgctxt "@action:inmenu menubar:edit" msgid "Multiply Selected" msgstr "Размножить выбранное" -#: resources/qml/Actions.qml:324 +#: resources/qml/Actions.qml:326 msgctxt "@action:inmenu" msgid "Delete Model" msgstr "Удалить модель" -#: resources/qml/Actions.qml:332 +#: resources/qml/Actions.qml:334 msgctxt "@action:inmenu" msgid "Ce&nter Model on Platform" msgstr "Поместить модель по центру" -#: resources/qml/Actions.qml:338 +#: resources/qml/Actions.qml:340 msgctxt "@action:inmenu menubar:edit" msgid "&Group Models" msgstr "Сгруппировать модели" -#: resources/qml/Actions.qml:358 +#: resources/qml/Actions.qml:360 msgctxt "@action:inmenu menubar:edit" msgid "Ungroup Models" msgstr "Разгруппировать модели" -#: resources/qml/Actions.qml:368 +#: resources/qml/Actions.qml:370 msgctxt "@action:inmenu menubar:edit" msgid "&Merge Models" msgstr "Объединить модели" -#: resources/qml/Actions.qml:378 +#: resources/qml/Actions.qml:380 msgctxt "@action:inmenu" msgid "&Multiply Model..." msgstr "Дублировать модель..." -#: resources/qml/Actions.qml:385 +#: resources/qml/Actions.qml:387 msgctxt "@action:inmenu menubar:edit" msgid "Select All Models" msgstr "Выбрать все модели" -#: resources/qml/Actions.qml:395 +#: resources/qml/Actions.qml:397 msgctxt "@action:inmenu menubar:edit" msgid "Clear Build Plate" msgstr "Очистить стол" -#: resources/qml/Actions.qml:405 +#: resources/qml/Actions.qml:407 msgctxt "@action:inmenu menubar:file" msgid "Reload All Models" msgstr "Перезагрузить все модели" -#: resources/qml/Actions.qml:414 +#: resources/qml/Actions.qml:416 msgctxt "@action:inmenu menubar:edit" msgid "Arrange All Models" msgstr "Выровнять все модели" -#: resources/qml/Actions.qml:422 +#: resources/qml/Actions.qml:424 +msgctxt "@action:inmenu menubar:edit" +msgid "Arrange All Models Without Rotation" +msgstr "" + +#: resources/qml/Actions.qml:431 msgctxt "@action:inmenu menubar:edit" msgid "Arrange Selection" msgstr "Выровнять выбранные" -#: resources/qml/Actions.qml:429 +#: resources/qml/Actions.qml:438 +msgctxt "@action:inmenu menubar:edit" +msgid "Arrange Selection Without Rotation" +msgstr "" + +#: resources/qml/Actions.qml:445 msgctxt "@action:inmenu menubar:edit" msgid "Reset All Model Positions" msgstr "Сбросить позиции всех моделей" -#: resources/qml/Actions.qml:436 +#: resources/qml/Actions.qml:452 msgctxt "@action:inmenu menubar:edit" msgid "Reset All Model Transformations" msgstr "Сбросить преобразования всех моделей" -#: resources/qml/Actions.qml:445 +#: resources/qml/Actions.qml:461 msgctxt "@action:inmenu menubar:file" msgid "&Open File(s)..." msgstr "Открыть файл(ы)..." -#: resources/qml/Actions.qml:455 +#: resources/qml/Actions.qml:471 msgctxt "@action:inmenu menubar:file" msgid "&New Project..." msgstr "Новый проект..." -#: resources/qml/Actions.qml:462 +#: resources/qml/Actions.qml:478 msgctxt "@action:inmenu menubar:help" msgid "Show Configuration Folder" msgstr "Показать конфигурационный каталог" -#: resources/qml/Actions.qml:469 resources/qml/Settings/SettingView.qml:476 +#: resources/qml/Actions.qml:485 resources/qml/Settings/SettingView.qml:476 msgctxt "@action:menu" msgid "Configure setting visibility..." msgstr "Видимость параметров..." @@ -5084,7 +5094,7 @@ msgstr[0] "Печать выбранной модели:" msgstr[1] "Печать выбранных моделей:" msgstr[2] "Печать выбранных моделей:" -#: resources/qml/Menus/ContextMenu.qml:92 +#: resources/qml/Menus/ContextMenu.qml:93 msgctxt "@title:window" msgid "Multiply Selected Model" msgid_plural "Multiply Selected Models" @@ -5092,11 +5102,16 @@ msgstr[0] "Размножить выбранную модель" msgstr[1] "Размножить выбранные модели" msgstr[2] "Размножить выбранные модели" -#: resources/qml/Menus/ContextMenu.qml:123 +#: resources/qml/Menus/ContextMenu.qml:128 msgctxt "@label" msgid "Number of Copies" msgstr "Количество копий" +#: resources/qml/Menus/ContextMenu.qml:149 +msgctxt "@label" +msgid "Lock Rotation" +msgstr "" + #: resources/qml/Menus/EditMenu.qml:12 msgctxt "@title:menu menubar:toplevel" msgid "&Edit" diff --git a/resources/i18n/tr_TR/cura.po b/resources/i18n/tr_TR/cura.po index 7731155049..f607ed1c83 100644 --- a/resources/i18n/tr_TR/cura.po +++ b/resources/i18n/tr_TR/cura.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-04-27 12:22+0000\n" +"POT-Creation-Date: 2023-05-11 14:19+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -23,22 +23,22 @@ msgctxt "@info:title" msgid "Login failed" msgstr "Giriş başarısız" -#: cura/Arranging/ArrangeObjectsJob.py:25 +#: cura/Arranging/ArrangeObjectsJob.py:27 msgctxt "@info:status" msgid "Finding new location for objects" msgstr "Nesneler için yeni konum bulunuyor" -#: cura/Arranging/ArrangeObjectsJob.py:29 +#: cura/Arranging/ArrangeObjectsJob.py:31 msgctxt "@info:title" msgid "Finding Location" msgstr "Konumu Buluyor" -#: cura/Arranging/ArrangeObjectsJob.py:42 cura/MultiplyObjectsJob.py:99 +#: cura/Arranging/ArrangeObjectsJob.py:45 cura/MultiplyObjectsJob.py:101 msgctxt "@info:status" msgid "Unable to find a location within the build volume for all objects" msgstr "Yapılan hacim içinde tüm nesneler için konum bulunamadı" -#: cura/Arranging/ArrangeObjectsJob.py:43 +#: cura/Arranging/ArrangeObjectsJob.py:46 msgctxt "@info:title" msgid "Can't Find Location" msgstr "Konum Bulunamıyor" @@ -265,25 +265,25 @@ msgctxt "@info 'width', 'depth' and 'height' are variable names that must NOT be msgid "%(width).1f x %(depth).1f x %(height).1f mm" msgstr "%(width).1f x %(depth).1f x %(height).1f mm" -#: cura/CuraApplication.py:1816 +#: cura/CuraApplication.py:1817 #, python-brace-format msgctxt "@info:status" msgid "Only one G-code file can be loaded at a time. Skipped importing {0}" msgstr "Aynı anda yalnızca bir G-code dosyası yüklenebilir. {0} içe aktarma atlandı" -#: cura/CuraApplication.py:1818 cura/OAuth2/AuthorizationService.py:217 +#: cura/CuraApplication.py:1819 cura/OAuth2/AuthorizationService.py:217 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:189 msgctxt "@info:title" msgid "Warning" msgstr "Uyarı" -#: cura/CuraApplication.py:1828 +#: cura/CuraApplication.py:1829 #, python-brace-format msgctxt "@info:status" msgid "Can't open any other file if G-code is loading. Skipped importing {0}" msgstr "G-code yüklenirken başka bir dosya açılamaz. {0} içe aktarma atlandı" -#: cura/CuraApplication.py:1830 cura/Settings/CuraContainerRegistry.py:156 +#: cura/CuraApplication.py:1831 cura/Settings/CuraContainerRegistry.py:156 #: cura/Settings/CuraContainerRegistry.py:166 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:153 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:173 @@ -410,17 +410,17 @@ msgctxt "@info:status" msgid "Calculated" msgstr "Hesaplanmış" -#: cura/MultiplyObjectsJob.py:30 +#: cura/MultiplyObjectsJob.py:31 msgctxt "@info:status" msgid "Multiplying and placing objects" msgstr "Nesneler çoğaltılıyor ve yerleştiriliyor" -#: cura/MultiplyObjectsJob.py:32 +#: cura/MultiplyObjectsJob.py:33 msgctxt "@info:title" msgid "Placing Objects" msgstr "Nesneler Yerleştiriliyor" -#: cura/MultiplyObjectsJob.py:100 +#: cura/MultiplyObjectsJob.py:102 msgctxt "@info:title" msgid "Placing Object" msgstr "Nesne Yerleştiriliyor" @@ -3678,17 +3678,17 @@ msgctxt "@action:button" msgid "Remove printers" msgstr "Yazıcıları kaldır" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:62 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:63 msgctxt "@action:button Preceded by 'Ready to'." msgid "Print over network" msgstr "Ağ üzerinden yazdır" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:63 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:64 msgctxt "@properties:tooltip" msgid "Print over network" msgstr "Ağ üzerinden yazdır" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:64 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:65 msgctxt "@info:status" msgid "Connected over the network" msgstr "Ağ üzerinden bağlandı" @@ -4230,227 +4230,237 @@ msgctxt "@button" msgid "Cancel" msgstr "İptal" -#: resources/qml/Actions.qml:81 +#: resources/qml/Actions.qml:83 msgctxt "@action:inmenu" msgid "Show Online Troubleshooting" msgstr "Çevrimiçi Sorun Giderme Kılavuzunu Göster" -#: resources/qml/Actions.qml:88 +#: resources/qml/Actions.qml:90 msgctxt "@action:inmenu" msgid "Toggle Full Screen" msgstr "Tam Ekrana Geç" -#: resources/qml/Actions.qml:96 +#: resources/qml/Actions.qml:98 msgctxt "@action:inmenu" msgid "Exit Full Screen" msgstr "Tam Ekrandan Çık" -#: resources/qml/Actions.qml:103 +#: resources/qml/Actions.qml:105 msgctxt "@action:inmenu menubar:edit" msgid "&Undo" msgstr "&Geri Al" -#: resources/qml/Actions.qml:113 +#: resources/qml/Actions.qml:115 msgctxt "@action:inmenu menubar:edit" msgid "&Redo" msgstr "&Yinele" -#: resources/qml/Actions.qml:131 +#: resources/qml/Actions.qml:133 msgctxt "@action:inmenu menubar:file" msgid "&Quit" msgstr "&Çıkış" -#: resources/qml/Actions.qml:139 +#: resources/qml/Actions.qml:141 msgctxt "@action:inmenu menubar:view" msgid "3D View" msgstr "3 Boyutlu Görünüm" -#: resources/qml/Actions.qml:146 +#: resources/qml/Actions.qml:148 msgctxt "@action:inmenu menubar:view" msgid "Front View" msgstr "Önden Görünüm" -#: resources/qml/Actions.qml:153 +#: resources/qml/Actions.qml:155 msgctxt "@action:inmenu menubar:view" msgid "Top View" msgstr "Yukarıdan Görünüm" -#: resources/qml/Actions.qml:160 +#: resources/qml/Actions.qml:162 msgctxt "@action:inmenu menubar:view" msgid "Bottom View" msgstr "Alttan Görünüm" -#: resources/qml/Actions.qml:167 +#: resources/qml/Actions.qml:169 msgctxt "@action:inmenu menubar:view" msgid "Left Side View" msgstr "Sol Taraftan Görünüm" -#: resources/qml/Actions.qml:174 +#: resources/qml/Actions.qml:176 msgctxt "@action:inmenu menubar:view" msgid "Right Side View" msgstr "Sağ Taraftan Görünüm" -#: resources/qml/Actions.qml:188 +#: resources/qml/Actions.qml:190 msgctxt "@action:inmenu" msgid "Configure Cura..." msgstr "Cura’yı yapılandır..." -#: resources/qml/Actions.qml:197 +#: resources/qml/Actions.qml:199 msgctxt "@action:inmenu menubar:printer" msgid "&Add Printer..." msgstr "&Yazıcı Ekle..." -#: resources/qml/Actions.qml:203 +#: resources/qml/Actions.qml:205 msgctxt "@action:inmenu menubar:printer" msgid "Manage Pr&inters..." msgstr "Yazıcıları Yönet..." -#: resources/qml/Actions.qml:210 +#: resources/qml/Actions.qml:212 msgctxt "@action:inmenu" msgid "Manage Materials..." msgstr "Malzemeleri Yönet..." -#: resources/qml/Actions.qml:218 +#: resources/qml/Actions.qml:220 msgctxt "@action:inmenu Marketplace is a brand name of UltiMaker's, so don't translate." msgid "Add more materials from Marketplace" msgstr "Mağazadan daha fazla malzeme ekle" -#: resources/qml/Actions.qml:225 +#: resources/qml/Actions.qml:227 msgctxt "@action:inmenu menubar:profile" msgid "&Update profile with current settings/overrides" msgstr "&Profili geçerli ayarlar/geçersiz kılmalar ile güncelle" -#: resources/qml/Actions.qml:233 +#: resources/qml/Actions.qml:235 msgctxt "@action:inmenu menubar:profile" msgid "&Discard current changes" msgstr "&Geçerli değişiklikleri iptal et" -#: resources/qml/Actions.qml:245 +#: resources/qml/Actions.qml:247 msgctxt "@action:inmenu menubar:profile" msgid "&Create profile from current settings/overrides..." msgstr "G&eçerli ayarlardan/geçersiz kılmalardan profil oluştur..." -#: resources/qml/Actions.qml:251 +#: resources/qml/Actions.qml:253 msgctxt "@action:inmenu menubar:profile" msgid "Manage Profiles..." msgstr "Profilleri Yönet..." -#: resources/qml/Actions.qml:259 +#: resources/qml/Actions.qml:261 msgctxt "@action:inmenu menubar:help" msgid "Show Online &Documentation" msgstr "Çevrimiçi Belgeleri Göster" -#: resources/qml/Actions.qml:267 +#: resources/qml/Actions.qml:269 msgctxt "@action:inmenu menubar:help" msgid "Report a &Bug" msgstr "Hata Bildir" -#: resources/qml/Actions.qml:275 +#: resources/qml/Actions.qml:277 msgctxt "@action:inmenu menubar:help" msgid "What's New" msgstr "Yenilikler" -#: resources/qml/Actions.qml:289 +#: resources/qml/Actions.qml:291 msgctxt "@action:inmenu menubar:help" msgid "About..." msgstr "Hakkında..." -#: resources/qml/Actions.qml:296 +#: resources/qml/Actions.qml:298 msgctxt "@action:inmenu menubar:edit" msgid "Delete Selected" msgstr "Seçileni Sil" -#: resources/qml/Actions.qml:306 +#: resources/qml/Actions.qml:308 msgctxt "@action:inmenu menubar:edit" msgid "Center Selected" msgstr "Seçileni Ortala" -#: resources/qml/Actions.qml:315 +#: resources/qml/Actions.qml:317 msgctxt "@action:inmenu menubar:edit" msgid "Multiply Selected" msgstr "Seçileni Çoğalt" -#: resources/qml/Actions.qml:324 +#: resources/qml/Actions.qml:326 msgctxt "@action:inmenu" msgid "Delete Model" msgstr "Modeli Sil" -#: resources/qml/Actions.qml:332 +#: resources/qml/Actions.qml:334 msgctxt "@action:inmenu" msgid "Ce&nter Model on Platform" msgstr "Modeli Platformda Ortala" -#: resources/qml/Actions.qml:338 +#: resources/qml/Actions.qml:340 msgctxt "@action:inmenu menubar:edit" msgid "&Group Models" msgstr "Modelleri Gruplandır" -#: resources/qml/Actions.qml:358 +#: resources/qml/Actions.qml:360 msgctxt "@action:inmenu menubar:edit" msgid "Ungroup Models" msgstr "Model Grubunu Çöz" -#: resources/qml/Actions.qml:368 +#: resources/qml/Actions.qml:370 msgctxt "@action:inmenu menubar:edit" msgid "&Merge Models" msgstr "&Modelleri Birleştir" -#: resources/qml/Actions.qml:378 +#: resources/qml/Actions.qml:380 msgctxt "@action:inmenu" msgid "&Multiply Model..." msgstr "&Modeli Çoğalt..." -#: resources/qml/Actions.qml:385 +#: resources/qml/Actions.qml:387 msgctxt "@action:inmenu menubar:edit" msgid "Select All Models" msgstr "Tüm modelleri Seç" -#: resources/qml/Actions.qml:395 +#: resources/qml/Actions.qml:397 msgctxt "@action:inmenu menubar:edit" msgid "Clear Build Plate" msgstr "Yapı Levhasını Temizle" -#: resources/qml/Actions.qml:405 +#: resources/qml/Actions.qml:407 msgctxt "@action:inmenu menubar:file" msgid "Reload All Models" msgstr "Tüm Modelleri Yeniden Yükle" -#: resources/qml/Actions.qml:414 +#: resources/qml/Actions.qml:416 msgctxt "@action:inmenu menubar:edit" msgid "Arrange All Models" msgstr "Tüm Modelleri Düzenle" -#: resources/qml/Actions.qml:422 +#: resources/qml/Actions.qml:424 +msgctxt "@action:inmenu menubar:edit" +msgid "Arrange All Models Without Rotation" +msgstr "" + +#: resources/qml/Actions.qml:431 msgctxt "@action:inmenu menubar:edit" msgid "Arrange Selection" msgstr "Seçimi Düzenle" -#: resources/qml/Actions.qml:429 +#: resources/qml/Actions.qml:438 +msgctxt "@action:inmenu menubar:edit" +msgid "Arrange Selection Without Rotation" +msgstr "" + +#: resources/qml/Actions.qml:445 msgctxt "@action:inmenu menubar:edit" msgid "Reset All Model Positions" msgstr "Tüm Model Konumlarını Sıfırla" -#: resources/qml/Actions.qml:436 +#: resources/qml/Actions.qml:452 msgctxt "@action:inmenu menubar:edit" msgid "Reset All Model Transformations" msgstr "Tüm Model ve Dönüşümleri Sıfırla" -#: resources/qml/Actions.qml:445 +#: resources/qml/Actions.qml:461 msgctxt "@action:inmenu menubar:file" msgid "&Open File(s)..." msgstr "&Dosya Aç..." -#: resources/qml/Actions.qml:455 +#: resources/qml/Actions.qml:471 msgctxt "@action:inmenu menubar:file" msgid "&New Project..." msgstr "&Yeni Proje..." -#: resources/qml/Actions.qml:462 +#: resources/qml/Actions.qml:478 msgctxt "@action:inmenu menubar:help" msgid "Show Configuration Folder" msgstr "Yapılandırma Klasörünü Göster" -#: resources/qml/Actions.qml:469 resources/qml/Settings/SettingView.qml:476 +#: resources/qml/Actions.qml:485 resources/qml/Settings/SettingView.qml:476 msgctxt "@action:menu" msgid "Configure setting visibility..." msgstr "Görünürlük ayarını yapılandır..." @@ -5074,18 +5084,23 @@ msgid_plural "Print Selected Models With:" msgstr[0] "Seçili Modeli Şununla Yazdır:" msgstr[1] "Seçili Modelleri Şununla Yazdır:" -#: resources/qml/Menus/ContextMenu.qml:92 +#: resources/qml/Menus/ContextMenu.qml:93 msgctxt "@title:window" msgid "Multiply Selected Model" msgid_plural "Multiply Selected Models" msgstr[0] "Seçili Modeli Çoğalt" msgstr[1] "Seçili Modelleri Çoğalt" -#: resources/qml/Menus/ContextMenu.qml:123 +#: resources/qml/Menus/ContextMenu.qml:128 msgctxt "@label" msgid "Number of Copies" msgstr "Kopya Sayısı" +#: resources/qml/Menus/ContextMenu.qml:149 +msgctxt "@label" +msgid "Lock Rotation" +msgstr "" + #: resources/qml/Menus/EditMenu.qml:12 msgctxt "@title:menu menubar:toplevel" msgid "&Edit" diff --git a/resources/i18n/zh_CN/cura.po b/resources/i18n/zh_CN/cura.po index 5d63f8552b..a2e4fd3d24 100644 --- a/resources/i18n/zh_CN/cura.po +++ b/resources/i18n/zh_CN/cura.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Cura 5.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-04-27 12:22+0000\n" +"POT-Creation-Date: 2023-05-11 14:19+0000\n" "PO-Revision-Date: 2022-07-15 11:06+0200\n" "Last-Translator: \n" "Language-Team: \n" @@ -23,22 +23,22 @@ msgctxt "@info:title" msgid "Login failed" msgstr "登录失败" -#: cura/Arranging/ArrangeObjectsJob.py:25 +#: cura/Arranging/ArrangeObjectsJob.py:27 msgctxt "@info:status" msgid "Finding new location for objects" msgstr "正在为模型寻找新位置" -#: cura/Arranging/ArrangeObjectsJob.py:29 +#: cura/Arranging/ArrangeObjectsJob.py:31 msgctxt "@info:title" msgid "Finding Location" msgstr "正在寻找位置" -#: cura/Arranging/ArrangeObjectsJob.py:42 cura/MultiplyObjectsJob.py:99 +#: cura/Arranging/ArrangeObjectsJob.py:45 cura/MultiplyObjectsJob.py:101 msgctxt "@info:status" msgid "Unable to find a location within the build volume for all objects" msgstr "无法在成形空间体积内放下全部模型" -#: cura/Arranging/ArrangeObjectsJob.py:43 +#: cura/Arranging/ArrangeObjectsJob.py:46 msgctxt "@info:title" msgid "Can't Find Location" msgstr "找不到位置" @@ -265,25 +265,25 @@ msgctxt "@info 'width', 'depth' and 'height' are variable names that must NOT be msgid "%(width).1f x %(depth).1f x %(height).1f mm" msgstr "%(width).1f x %(depth).1f x %(height).1f mm" -#: cura/CuraApplication.py:1816 +#: cura/CuraApplication.py:1817 #, python-brace-format msgctxt "@info:status" msgid "Only one G-code file can be loaded at a time. Skipped importing {0}" msgstr "一次只能加载一个 G-code 文件。{0} 已跳过导入" -#: cura/CuraApplication.py:1818 cura/OAuth2/AuthorizationService.py:217 +#: cura/CuraApplication.py:1819 cura/OAuth2/AuthorizationService.py:217 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:189 msgctxt "@info:title" msgid "Warning" msgstr "警告" -#: cura/CuraApplication.py:1828 +#: cura/CuraApplication.py:1829 #, python-brace-format msgctxt "@info:status" msgid "Can't open any other file if G-code is loading. Skipped importing {0}" msgstr "如果加载 G-code,则无法打开其他任何文件。{0} 已跳过导入" -#: cura/CuraApplication.py:1830 cura/Settings/CuraContainerRegistry.py:156 +#: cura/CuraApplication.py:1831 cura/Settings/CuraContainerRegistry.py:156 #: cura/Settings/CuraContainerRegistry.py:166 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:153 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:173 @@ -410,17 +410,17 @@ msgctxt "@info:status" msgid "Calculated" msgstr "已计算" -#: cura/MultiplyObjectsJob.py:30 +#: cura/MultiplyObjectsJob.py:31 msgctxt "@info:status" msgid "Multiplying and placing objects" msgstr "复制并放置模型" -#: cura/MultiplyObjectsJob.py:32 +#: cura/MultiplyObjectsJob.py:33 msgctxt "@info:title" msgid "Placing Objects" msgstr "放置模型" -#: cura/MultiplyObjectsJob.py:100 +#: cura/MultiplyObjectsJob.py:102 msgctxt "@info:title" msgid "Placing Object" msgstr "放置模型" @@ -3667,17 +3667,17 @@ msgctxt "@action:button" msgid "Remove printers" msgstr "删除打印机" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:62 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:63 msgctxt "@action:button Preceded by 'Ready to'." msgid "Print over network" msgstr "通过网络打印" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:63 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:64 msgctxt "@properties:tooltip" msgid "Print over network" msgstr "通过网络打印" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:64 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:65 msgctxt "@info:status" msgid "Connected over the network" msgstr "已通过网络连接" @@ -4219,227 +4219,237 @@ msgctxt "@button" msgid "Cancel" msgstr "取消" -#: resources/qml/Actions.qml:81 +#: resources/qml/Actions.qml:83 msgctxt "@action:inmenu" msgid "Show Online Troubleshooting" msgstr "显示联机故障排除" -#: resources/qml/Actions.qml:88 +#: resources/qml/Actions.qml:90 msgctxt "@action:inmenu" msgid "Toggle Full Screen" msgstr "切换全屏" -#: resources/qml/Actions.qml:96 +#: resources/qml/Actions.qml:98 msgctxt "@action:inmenu" msgid "Exit Full Screen" msgstr "退出全屏" -#: resources/qml/Actions.qml:103 +#: resources/qml/Actions.qml:105 msgctxt "@action:inmenu menubar:edit" msgid "&Undo" msgstr "撤销(&U)" -#: resources/qml/Actions.qml:113 +#: resources/qml/Actions.qml:115 msgctxt "@action:inmenu menubar:edit" msgid "&Redo" msgstr "重做(&R)" -#: resources/qml/Actions.qml:131 +#: resources/qml/Actions.qml:133 msgctxt "@action:inmenu menubar:file" msgid "&Quit" msgstr "退出(&Q)" -#: resources/qml/Actions.qml:139 +#: resources/qml/Actions.qml:141 msgctxt "@action:inmenu menubar:view" msgid "3D View" msgstr "3D 视图" -#: resources/qml/Actions.qml:146 +#: resources/qml/Actions.qml:148 msgctxt "@action:inmenu menubar:view" msgid "Front View" msgstr "正视图" -#: resources/qml/Actions.qml:153 +#: resources/qml/Actions.qml:155 msgctxt "@action:inmenu menubar:view" msgid "Top View" msgstr "顶视图" -#: resources/qml/Actions.qml:160 +#: resources/qml/Actions.qml:162 msgctxt "@action:inmenu menubar:view" msgid "Bottom View" msgstr "仰视图" -#: resources/qml/Actions.qml:167 +#: resources/qml/Actions.qml:169 msgctxt "@action:inmenu menubar:view" msgid "Left Side View" msgstr "左视图" -#: resources/qml/Actions.qml:174 +#: resources/qml/Actions.qml:176 msgctxt "@action:inmenu menubar:view" msgid "Right Side View" msgstr "右视图" -#: resources/qml/Actions.qml:188 +#: resources/qml/Actions.qml:190 msgctxt "@action:inmenu" msgid "Configure Cura..." msgstr "配置 Cura..." -#: resources/qml/Actions.qml:197 +#: resources/qml/Actions.qml:199 msgctxt "@action:inmenu menubar:printer" msgid "&Add Printer..." msgstr "新增打印机(&A)..." -#: resources/qml/Actions.qml:203 +#: resources/qml/Actions.qml:205 msgctxt "@action:inmenu menubar:printer" msgid "Manage Pr&inters..." msgstr "管理打印机(&I)..." -#: resources/qml/Actions.qml:210 +#: resources/qml/Actions.qml:212 msgctxt "@action:inmenu" msgid "Manage Materials..." msgstr "管理材料..." -#: resources/qml/Actions.qml:218 +#: resources/qml/Actions.qml:220 msgctxt "@action:inmenu Marketplace is a brand name of UltiMaker's, so don't translate." msgid "Add more materials from Marketplace" msgstr "从市场添加更多材料" -#: resources/qml/Actions.qml:225 +#: resources/qml/Actions.qml:227 msgctxt "@action:inmenu menubar:profile" msgid "&Update profile with current settings/overrides" msgstr "使用当前设置 / 重写值更新配置文件(&U)" -#: resources/qml/Actions.qml:233 +#: resources/qml/Actions.qml:235 msgctxt "@action:inmenu menubar:profile" msgid "&Discard current changes" msgstr "舍弃当前更改(&D)" -#: resources/qml/Actions.qml:245 +#: resources/qml/Actions.qml:247 msgctxt "@action:inmenu menubar:profile" msgid "&Create profile from current settings/overrides..." msgstr "从当前设置 / 重写值创建配置文件(&C)..." -#: resources/qml/Actions.qml:251 +#: resources/qml/Actions.qml:253 msgctxt "@action:inmenu menubar:profile" msgid "Manage Profiles..." msgstr "管理配置文件.." -#: resources/qml/Actions.qml:259 +#: resources/qml/Actions.qml:261 msgctxt "@action:inmenu menubar:help" msgid "Show Online &Documentation" msgstr "显示在线文档(&D)" -#: resources/qml/Actions.qml:267 +#: resources/qml/Actions.qml:269 msgctxt "@action:inmenu menubar:help" msgid "Report a &Bug" msgstr "BUG 反馈(&B)" -#: resources/qml/Actions.qml:275 +#: resources/qml/Actions.qml:277 msgctxt "@action:inmenu menubar:help" msgid "What's New" msgstr "新增功能" -#: resources/qml/Actions.qml:289 +#: resources/qml/Actions.qml:291 msgctxt "@action:inmenu menubar:help" msgid "About..." msgstr "关于..." -#: resources/qml/Actions.qml:296 +#: resources/qml/Actions.qml:298 msgctxt "@action:inmenu menubar:edit" msgid "Delete Selected" msgstr "删除所选项" -#: resources/qml/Actions.qml:306 +#: resources/qml/Actions.qml:308 msgctxt "@action:inmenu menubar:edit" msgid "Center Selected" msgstr "居中所选项" -#: resources/qml/Actions.qml:315 +#: resources/qml/Actions.qml:317 msgctxt "@action:inmenu menubar:edit" msgid "Multiply Selected" msgstr "复制所选项" -#: resources/qml/Actions.qml:324 +#: resources/qml/Actions.qml:326 msgctxt "@action:inmenu" msgid "Delete Model" msgstr "删除模型" -#: resources/qml/Actions.qml:332 +#: resources/qml/Actions.qml:334 msgctxt "@action:inmenu" msgid "Ce&nter Model on Platform" msgstr "使模型居于平台中央(&N)" -#: resources/qml/Actions.qml:338 +#: resources/qml/Actions.qml:340 msgctxt "@action:inmenu menubar:edit" msgid "&Group Models" msgstr "绑定模型(&G)" -#: resources/qml/Actions.qml:358 +#: resources/qml/Actions.qml:360 msgctxt "@action:inmenu menubar:edit" msgid "Ungroup Models" msgstr "拆分模型" -#: resources/qml/Actions.qml:368 +#: resources/qml/Actions.qml:370 msgctxt "@action:inmenu menubar:edit" msgid "&Merge Models" msgstr "合并模型(&M)" -#: resources/qml/Actions.qml:378 +#: resources/qml/Actions.qml:380 msgctxt "@action:inmenu" msgid "&Multiply Model..." msgstr "复制模型(&M)…" -#: resources/qml/Actions.qml:385 +#: resources/qml/Actions.qml:387 msgctxt "@action:inmenu menubar:edit" msgid "Select All Models" msgstr "选择所有模型" -#: resources/qml/Actions.qml:395 +#: resources/qml/Actions.qml:397 msgctxt "@action:inmenu menubar:edit" msgid "Clear Build Plate" msgstr "清空打印平台" -#: resources/qml/Actions.qml:405 +#: resources/qml/Actions.qml:407 msgctxt "@action:inmenu menubar:file" msgid "Reload All Models" msgstr "重新载入所有模型" -#: resources/qml/Actions.qml:414 +#: resources/qml/Actions.qml:416 msgctxt "@action:inmenu menubar:edit" msgid "Arrange All Models" msgstr "编位所有的模型" -#: resources/qml/Actions.qml:422 +#: resources/qml/Actions.qml:424 +msgctxt "@action:inmenu menubar:edit" +msgid "Arrange All Models Without Rotation" +msgstr "" + +#: resources/qml/Actions.qml:431 msgctxt "@action:inmenu menubar:edit" msgid "Arrange Selection" msgstr "为所选模型编位" -#: resources/qml/Actions.qml:429 +#: resources/qml/Actions.qml:438 +msgctxt "@action:inmenu menubar:edit" +msgid "Arrange Selection Without Rotation" +msgstr "" + +#: resources/qml/Actions.qml:445 msgctxt "@action:inmenu menubar:edit" msgid "Reset All Model Positions" msgstr "复位所有模型的位置" -#: resources/qml/Actions.qml:436 +#: resources/qml/Actions.qml:452 msgctxt "@action:inmenu menubar:edit" msgid "Reset All Model Transformations" msgstr "复位所有模型的变动" -#: resources/qml/Actions.qml:445 +#: resources/qml/Actions.qml:461 msgctxt "@action:inmenu menubar:file" msgid "&Open File(s)..." msgstr "打开文件(&O)..." -#: resources/qml/Actions.qml:455 +#: resources/qml/Actions.qml:471 msgctxt "@action:inmenu menubar:file" msgid "&New Project..." msgstr "新建项目(&N)..." -#: resources/qml/Actions.qml:462 +#: resources/qml/Actions.qml:478 msgctxt "@action:inmenu menubar:help" msgid "Show Configuration Folder" msgstr "显示配置文件夹" -#: resources/qml/Actions.qml:469 resources/qml/Settings/SettingView.qml:476 +#: resources/qml/Actions.qml:485 resources/qml/Settings/SettingView.qml:476 msgctxt "@action:menu" msgid "Configure setting visibility..." msgstr "配置设定可见性..." @@ -5062,17 +5072,22 @@ msgid "Print Selected Model With:" msgid_plural "Print Selected Models With:" msgstr[0] "打印所选模型:" -#: resources/qml/Menus/ContextMenu.qml:92 +#: resources/qml/Menus/ContextMenu.qml:93 msgctxt "@title:window" msgid "Multiply Selected Model" msgid_plural "Multiply Selected Models" msgstr[0] "复制所选模型" -#: resources/qml/Menus/ContextMenu.qml:123 +#: resources/qml/Menus/ContextMenu.qml:128 msgctxt "@label" msgid "Number of Copies" msgstr "复制个数" +#: resources/qml/Menus/ContextMenu.qml:149 +msgctxt "@label" +msgid "Lock Rotation" +msgstr "" + #: resources/qml/Menus/EditMenu.qml:12 msgctxt "@title:menu menubar:toplevel" msgid "&Edit" diff --git a/resources/i18n/zh_TW/cura.po b/resources/i18n/zh_TW/cura.po index 0a4522c657..f4eb2ebf6e 100644 --- a/resources/i18n/zh_TW/cura.po +++ b/resources/i18n/zh_TW/cura.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: Cura 5.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-04-27 12:22+0000\n" +"POT-Creation-Date: 2023-05-11 14:19+0000\n" "PO-Revision-Date: 2022-01-02 19:59+0800\n" "Last-Translator: Valen Chang \n" "Language-Team: Valen Chang \n" @@ -23,22 +23,22 @@ msgctxt "@info:title" msgid "Login failed" msgstr "登入失敗" -#: cura/Arranging/ArrangeObjectsJob.py:25 +#: cura/Arranging/ArrangeObjectsJob.py:27 msgctxt "@info:status" msgid "Finding new location for objects" msgstr "正在為物件尋找新位置" -#: cura/Arranging/ArrangeObjectsJob.py:29 +#: cura/Arranging/ArrangeObjectsJob.py:31 msgctxt "@info:title" msgid "Finding Location" msgstr "尋找位置中" -#: cura/Arranging/ArrangeObjectsJob.py:42 cura/MultiplyObjectsJob.py:99 +#: cura/Arranging/ArrangeObjectsJob.py:45 cura/MultiplyObjectsJob.py:101 msgctxt "@info:status" msgid "Unable to find a location within the build volume for all objects" msgstr "無法在列印範圍內放下全部物件" -#: cura/Arranging/ArrangeObjectsJob.py:43 +#: cura/Arranging/ArrangeObjectsJob.py:46 msgctxt "@info:title" msgid "Can't Find Location" msgstr "無法找到位置" @@ -265,25 +265,25 @@ msgctxt "@info 'width', 'depth' and 'height' are variable names that must NOT be msgid "%(width).1f x %(depth).1f x %(height).1f mm" msgstr "%(width).1f x %(depth).1f x %(height).1f mm" -#: cura/CuraApplication.py:1816 +#: cura/CuraApplication.py:1817 #, python-brace-format msgctxt "@info:status" msgid "Only one G-code file can be loaded at a time. Skipped importing {0}" msgstr "一次只能載入一個 G-code 檔案。{0} 已跳過匯入" -#: cura/CuraApplication.py:1818 cura/OAuth2/AuthorizationService.py:217 +#: cura/CuraApplication.py:1819 cura/OAuth2/AuthorizationService.py:217 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:189 msgctxt "@info:title" msgid "Warning" msgstr "警告" -#: cura/CuraApplication.py:1828 +#: cura/CuraApplication.py:1829 #, python-brace-format msgctxt "@info:status" msgid "Can't open any other file if G-code is loading. Skipped importing {0}" msgstr "如果載入 G-code,則無法開啟其他任何檔案。{0} 已跳過匯入" -#: cura/CuraApplication.py:1830 cura/Settings/CuraContainerRegistry.py:156 +#: cura/CuraApplication.py:1831 cura/Settings/CuraContainerRegistry.py:156 #: cura/Settings/CuraContainerRegistry.py:166 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:153 #: plugins/RemovableDriveOutputDevice/RemovableDriveOutputDevice.py:173 @@ -410,17 +410,17 @@ msgctxt "@info:status" msgid "Calculated" msgstr "已計算" -#: cura/MultiplyObjectsJob.py:30 +#: cura/MultiplyObjectsJob.py:31 msgctxt "@info:status" msgid "Multiplying and placing objects" msgstr "正在複製並放置模型" -#: cura/MultiplyObjectsJob.py:32 +#: cura/MultiplyObjectsJob.py:33 msgctxt "@info:title" msgid "Placing Objects" msgstr "正在放置模型" -#: cura/MultiplyObjectsJob.py:100 +#: cura/MultiplyObjectsJob.py:102 msgctxt "@info:title" msgid "Placing Object" msgstr "擺放物件中" @@ -3668,17 +3668,17 @@ msgctxt "@action:button" msgid "Remove printers" msgstr "移除印表機" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:62 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:63 msgctxt "@action:button Preceded by 'Ready to'." msgid "Print over network" msgstr "網路連線列印" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:63 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:64 msgctxt "@properties:tooltip" msgid "Print over network" msgstr "網路連線列印" -#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:64 +#: plugins/UM3NetworkPrinting/src/Network/LocalClusterOutputDevice.py:65 msgctxt "@info:status" msgid "Connected over the network" msgstr "透過網路連接" @@ -4220,227 +4220,237 @@ msgctxt "@button" msgid "Cancel" msgstr "取消" -#: resources/qml/Actions.qml:81 +#: resources/qml/Actions.qml:83 msgctxt "@action:inmenu" msgid "Show Online Troubleshooting" msgstr "" -#: resources/qml/Actions.qml:88 +#: resources/qml/Actions.qml:90 msgctxt "@action:inmenu" msgid "Toggle Full Screen" msgstr "切換全螢幕" -#: resources/qml/Actions.qml:96 +#: resources/qml/Actions.qml:98 msgctxt "@action:inmenu" msgid "Exit Full Screen" msgstr "離開全螢幕" -#: resources/qml/Actions.qml:103 +#: resources/qml/Actions.qml:105 msgctxt "@action:inmenu menubar:edit" msgid "&Undo" msgstr "復原(&U)" -#: resources/qml/Actions.qml:113 +#: resources/qml/Actions.qml:115 msgctxt "@action:inmenu menubar:edit" msgid "&Redo" msgstr "取消復原(&R)" -#: resources/qml/Actions.qml:131 +#: resources/qml/Actions.qml:133 msgctxt "@action:inmenu menubar:file" msgid "&Quit" msgstr "退出(&Q)" -#: resources/qml/Actions.qml:139 +#: resources/qml/Actions.qml:141 msgctxt "@action:inmenu menubar:view" msgid "3D View" msgstr "立體圖" -#: resources/qml/Actions.qml:146 +#: resources/qml/Actions.qml:148 msgctxt "@action:inmenu menubar:view" msgid "Front View" msgstr "前視圖" -#: resources/qml/Actions.qml:153 +#: resources/qml/Actions.qml:155 msgctxt "@action:inmenu menubar:view" msgid "Top View" msgstr "上視圖" -#: resources/qml/Actions.qml:160 +#: resources/qml/Actions.qml:162 msgctxt "@action:inmenu menubar:view" msgid "Bottom View" msgstr "下視圖" -#: resources/qml/Actions.qml:167 +#: resources/qml/Actions.qml:169 msgctxt "@action:inmenu menubar:view" msgid "Left Side View" msgstr "左視圖" -#: resources/qml/Actions.qml:174 +#: resources/qml/Actions.qml:176 msgctxt "@action:inmenu menubar:view" msgid "Right Side View" msgstr "右視圖" -#: resources/qml/Actions.qml:188 +#: resources/qml/Actions.qml:190 msgctxt "@action:inmenu" msgid "Configure Cura..." msgstr "設定 Cura..." -#: resources/qml/Actions.qml:197 +#: resources/qml/Actions.qml:199 msgctxt "@action:inmenu menubar:printer" msgid "&Add Printer..." msgstr "新增印表機(&A)..." -#: resources/qml/Actions.qml:203 +#: resources/qml/Actions.qml:205 msgctxt "@action:inmenu menubar:printer" msgid "Manage Pr&inters..." msgstr "管理印表機(&I)..." -#: resources/qml/Actions.qml:210 +#: resources/qml/Actions.qml:212 msgctxt "@action:inmenu" msgid "Manage Materials..." msgstr "管理線材..." -#: resources/qml/Actions.qml:218 +#: resources/qml/Actions.qml:220 msgctxt "@action:inmenu Marketplace is a brand name of UltiMaker's, so don't translate." msgid "Add more materials from Marketplace" msgstr "從市集增加更多線材" -#: resources/qml/Actions.qml:225 +#: resources/qml/Actions.qml:227 msgctxt "@action:inmenu menubar:profile" msgid "&Update profile with current settings/overrides" msgstr "使用目前設定 / 覆寫更新列印參數(&U)" -#: resources/qml/Actions.qml:233 +#: resources/qml/Actions.qml:235 msgctxt "@action:inmenu menubar:profile" msgid "&Discard current changes" msgstr "捨棄目前更改(&D)" -#: resources/qml/Actions.qml:245 +#: resources/qml/Actions.qml:247 msgctxt "@action:inmenu menubar:profile" msgid "&Create profile from current settings/overrides..." msgstr "從目前設定 / 覆寫值建立列印參數(&C)..." -#: resources/qml/Actions.qml:251 +#: resources/qml/Actions.qml:253 msgctxt "@action:inmenu menubar:profile" msgid "Manage Profiles..." msgstr "管理列印參數.." -#: resources/qml/Actions.qml:259 +#: resources/qml/Actions.qml:261 msgctxt "@action:inmenu menubar:help" msgid "Show Online &Documentation" msgstr "顯示線上說明文件(&D)" -#: resources/qml/Actions.qml:267 +#: resources/qml/Actions.qml:269 msgctxt "@action:inmenu menubar:help" msgid "Report a &Bug" msgstr "BUG 回報(&B)" -#: resources/qml/Actions.qml:275 +#: resources/qml/Actions.qml:277 msgctxt "@action:inmenu menubar:help" msgid "What's New" msgstr "新功能" -#: resources/qml/Actions.qml:289 +#: resources/qml/Actions.qml:291 msgctxt "@action:inmenu menubar:help" msgid "About..." msgstr "關於..." -#: resources/qml/Actions.qml:296 +#: resources/qml/Actions.qml:298 msgctxt "@action:inmenu menubar:edit" msgid "Delete Selected" msgstr "刪除選取" -#: resources/qml/Actions.qml:306 +#: resources/qml/Actions.qml:308 msgctxt "@action:inmenu menubar:edit" msgid "Center Selected" msgstr "置中選取" -#: resources/qml/Actions.qml:315 +#: resources/qml/Actions.qml:317 msgctxt "@action:inmenu menubar:edit" msgid "Multiply Selected" msgstr "複製選取" -#: resources/qml/Actions.qml:324 +#: resources/qml/Actions.qml:326 msgctxt "@action:inmenu" msgid "Delete Model" msgstr "刪除模型" -#: resources/qml/Actions.qml:332 +#: resources/qml/Actions.qml:334 msgctxt "@action:inmenu" msgid "Ce&nter Model on Platform" msgstr "將模型置中(&N)" -#: resources/qml/Actions.qml:338 +#: resources/qml/Actions.qml:340 msgctxt "@action:inmenu menubar:edit" msgid "&Group Models" msgstr "群組模型(&G)" -#: resources/qml/Actions.qml:358 +#: resources/qml/Actions.qml:360 msgctxt "@action:inmenu menubar:edit" msgid "Ungroup Models" msgstr "取消模型群組" -#: resources/qml/Actions.qml:368 +#: resources/qml/Actions.qml:370 msgctxt "@action:inmenu menubar:edit" msgid "&Merge Models" msgstr "結合模型(&M)" -#: resources/qml/Actions.qml:378 +#: resources/qml/Actions.qml:380 msgctxt "@action:inmenu" msgid "&Multiply Model..." msgstr "複製模型...(&M)" -#: resources/qml/Actions.qml:385 +#: resources/qml/Actions.qml:387 msgctxt "@action:inmenu menubar:edit" msgid "Select All Models" msgstr "選擇所有模型" -#: resources/qml/Actions.qml:395 +#: resources/qml/Actions.qml:397 msgctxt "@action:inmenu menubar:edit" msgid "Clear Build Plate" msgstr "清空列印平台" -#: resources/qml/Actions.qml:405 +#: resources/qml/Actions.qml:407 msgctxt "@action:inmenu menubar:file" msgid "Reload All Models" msgstr "重新載入所有模型" -#: resources/qml/Actions.qml:414 +#: resources/qml/Actions.qml:416 msgctxt "@action:inmenu menubar:edit" msgid "Arrange All Models" msgstr "排列所有模型" -#: resources/qml/Actions.qml:422 +#: resources/qml/Actions.qml:424 +msgctxt "@action:inmenu menubar:edit" +msgid "Arrange All Models Without Rotation" +msgstr "" + +#: resources/qml/Actions.qml:431 msgctxt "@action:inmenu menubar:edit" msgid "Arrange Selection" msgstr "排列所選模型" -#: resources/qml/Actions.qml:429 +#: resources/qml/Actions.qml:438 +msgctxt "@action:inmenu menubar:edit" +msgid "Arrange Selection Without Rotation" +msgstr "" + +#: resources/qml/Actions.qml:445 msgctxt "@action:inmenu menubar:edit" msgid "Reset All Model Positions" msgstr "重置所有模型位置" -#: resources/qml/Actions.qml:436 +#: resources/qml/Actions.qml:452 msgctxt "@action:inmenu menubar:edit" msgid "Reset All Model Transformations" msgstr "重置所有模型旋轉" -#: resources/qml/Actions.qml:445 +#: resources/qml/Actions.qml:461 msgctxt "@action:inmenu menubar:file" msgid "&Open File(s)..." msgstr "開啟檔案(&O)..." -#: resources/qml/Actions.qml:455 +#: resources/qml/Actions.qml:471 msgctxt "@action:inmenu menubar:file" msgid "&New Project..." msgstr "新建專案(&N)..." -#: resources/qml/Actions.qml:462 +#: resources/qml/Actions.qml:478 msgctxt "@action:inmenu menubar:help" msgid "Show Configuration Folder" msgstr "顯示設定資料夾" -#: resources/qml/Actions.qml:469 resources/qml/Settings/SettingView.qml:476 +#: resources/qml/Actions.qml:485 resources/qml/Settings/SettingView.qml:476 msgctxt "@action:menu" msgid "Configure setting visibility..." msgstr "參數顯示設定..." @@ -5060,17 +5070,22 @@ msgid "Print Selected Model With:" msgid_plural "Print Selected Models With:" msgstr[0] "列印所選模型:" -#: resources/qml/Menus/ContextMenu.qml:92 +#: resources/qml/Menus/ContextMenu.qml:93 msgctxt "@title:window" msgid "Multiply Selected Model" msgid_plural "Multiply Selected Models" msgstr[0] "複製所選模型" -#: resources/qml/Menus/ContextMenu.qml:123 +#: resources/qml/Menus/ContextMenu.qml:128 msgctxt "@label" msgid "Number of Copies" msgstr "複製個數" +#: resources/qml/Menus/ContextMenu.qml:149 +msgctxt "@label" +msgid "Lock Rotation" +msgstr "" + #: resources/qml/Menus/EditMenu.qml:12 msgctxt "@title:menu menubar:toplevel" msgid "&Edit" From 1c07ba81f4f9ddfb5509729dc6da02f256c88c8f Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Fri, 12 May 2023 09:23:03 +0200 Subject: [PATCH 03/25] Add shortcut for "arrange without rotation" action CURA-7951 --- resources/qml/Actions.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/resources/qml/Actions.qml b/resources/qml/Actions.qml index eb9f1c7f21..8a4826e149 100644 --- a/resources/qml/Actions.qml +++ b/resources/qml/Actions.qml @@ -423,6 +423,7 @@ Item id: arrangeAllLockAction text: catalog.i18nc("@action:inmenu menubar:edit","Arrange All Models Without Rotation") onTriggered: Printer.arrangeAll(true) + shortcut: "Shift+Ctrl+R" } Action From 209162fbce5dc0e5b2ff934900623691c46df233 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Mon, 21 Aug 2023 17:31:29 +0200 Subject: [PATCH 04/25] multiplying objects place them in a grid CURA-7951 --- cura/Arranging/GridArrange.py | 185 ++++++++++++++++++++++++++++++++++ cura/MultiplyObjectsJob.py | 18 ++-- 2 files changed, 197 insertions(+), 6 deletions(-) create mode 100644 cura/Arranging/GridArrange.py diff --git a/cura/Arranging/GridArrange.py b/cura/Arranging/GridArrange.py new file mode 100644 index 0000000000..543971c5b2 --- /dev/null +++ b/cura/Arranging/GridArrange.py @@ -0,0 +1,185 @@ +import math +from typing import List, TYPE_CHECKING, Optional, Tuple, Set + +from UM.Application import Application +from UM.Math import AxisAlignedBox +from UM.Math.Vector import Vector +from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation +from UM.Operations.GroupedOperation import GroupedOperation +from UM.Operations.TranslateOperation import TranslateOperation + + +class GridArrange: + offset_x: float = 10 + offset_y: float = 10 + + _grid_width: float + _grid_height: float + + _nodes_to_arrange: List["SceneNode"] + _fixed_nodes: List["SceneNode"] + _build_volume_bounding_box = AxisAlignedBox + + def __init__(self, nodes_to_arrange: List["SceneNode"], build_volume: "BuildVolume", fixed_nodes: List["SceneNode"] = []): + print("len(nodes_to_arrange)", len(nodes_to_arrange)) + self._nodes_to_arrange = nodes_to_arrange + self._build_volume_bounding_box = build_volume.getBoundingBox() + self._fixed_nodes = fixed_nodes + + def arrange(self) -> Tuple[GroupedOperation, int]: + self._grid_width = 0 + self._grid_height = 0 + for node in self._nodes_to_arrange: + bounding_box = node.getBoundingBox() + self._grid_width = max(self._grid_width, bounding_box.width) + self._grid_height = max(self._grid_height, bounding_box.depth) + + # Find grid indexes that intersect with fixed objects + fixed_nodes_grid_ids = set() + for node in self._fixed_nodes: + fixed_nodes_grid_ids = fixed_nodes_grid_ids.union(self.intersectingGridIdxInclusive(node.getBoundingBox())) + + build_plate_grid_ids = self.intersectingGridIdxExclusive(self._build_volume_bounding_box) + allowed_grid_idx = build_plate_grid_ids.difference(fixed_nodes_grid_ids) + + # Find the sequence in which items are placed + coord_build_plate_center_x = self._build_volume_bounding_box.width * 0.5 + self._build_volume_bounding_box.left + coord_build_plate_center_y = self._build_volume_bounding_box.depth * 0.5 + self._build_volume_bounding_box.back + grid_build_plate_center_x, grid_build_plate_center_y = self.coordSpaceToGridSpace(coord_build_plate_center_x, coord_build_plate_center_y) + + def distToCenter(grid_id: Tuple[int, int]) -> float: + grid_x, grid_y = grid_id + distance_squared = (grid_build_plate_center_x - grid_x) ** 2 + (grid_build_plate_center_y - grid_y) ** 2 + return distance_squared + + sequence: List[Tuple[int, int]] = list(allowed_grid_idx) + sequence.sort(key=distToCenter) + scene_root = Application.getInstance().getController().getScene().getRoot() + grouped_operation = GroupedOperation() + + for grid_id, node in zip(sequence, self._nodes_to_arrange): + grouped_operation.addOperation(AddSceneNodeOperation(node, scene_root)) + grid_x, grid_y = grid_id + + coord_grid_x, coord_grid_y = self.gridSpaceToCoordSpace(grid_x, grid_y) + center_grid_x = coord_grid_x+(0.5 * self._grid_width) + center_grid_y = coord_grid_y+(0.5 * self._grid_height) + + bounding_box = node.getBoundingBox() + center_node_x = (bounding_box.left + bounding_box.right) * 0.5 + center_node_y = (bounding_box.back + bounding_box.front) * 0.5 + + delta_x = center_grid_x - center_node_x + delta_y = center_grid_y - center_node_y + grouped_operation.addOperation(TranslateOperation(node, Vector(delta_x, 0, delta_y))) + + self.drawDebugSvg() + + return grouped_operation, 0 + + def getGridCornerPoints(self, bounding_box: "BoundingVolume") -> Tuple[float, float, float, float]: + coord_x1 = bounding_box.left + coord_x2 = bounding_box.right + coord_y1 = bounding_box.back + coord_y2 = bounding_box.front + grid_x1, grid_y1 = self.coordSpaceToGridSpace(coord_x1, coord_y1) + grid_x2, grid_y2 = self.coordSpaceToGridSpace(coord_x2, coord_y2) + return grid_x1, grid_y1, grid_x2, grid_y2 + + def intersectingGridIdxInclusive(self, bounding_box: "BoundingVolume") -> Set[Tuple[int, int]]: + grid_x1, grid_y1, grid_x2, grid_y2 = self.getGridCornerPoints(bounding_box) + grid_idx = set() + for grid_x in range(math.floor(grid_x1), math.ceil(grid_x2)): + for grid_y in range(math.floor(grid_y1), math.ceil(grid_y2)): + grid_idx.add((grid_x, grid_y)) + return grid_idx + + def intersectingGridIdxExclusive(self, bounding_box: "BoundingVolume") -> Set[Tuple[int, int]]: + grid_x1, grid_y1, grid_x2, grid_y2 = self.getGridCornerPoints(bounding_box) + grid_idx = set() + for grid_x in range(math.ceil(grid_x1), math.floor(grid_x2)): + for grid_y in range(math.ceil(grid_y1), math.floor(grid_y2)): + grid_idx.add((grid_x, grid_y)) + return grid_idx + + def gridSpaceToCoordSpace(self, x: float, y: float) -> Tuple[float, float]: + grid_x = x * (self._grid_width + self.offset_x) + self._build_volume_bounding_box.left + grid_y = y * (self._grid_height + self.offset_y) + self._build_volume_bounding_box.back + return grid_x, grid_y + + def coordSpaceToGridSpace(self, grid_x: float, grid_y: float) -> Tuple[float, float]: + coord_x = (grid_x - self._build_volume_bounding_box.left) / (self._grid_width + self.offset_x) + coord_y = (grid_y - self._build_volume_bounding_box.back) / (self._grid_height + self.offset_y) + return coord_x, coord_y + + def drawDebugSvg(self): + with open("Builvolume_test.svg", "w") as f: + build_volume_bounding_box = self._build_volume_bounding_box + + f.write( + f"\n") + + f.write( + f""" + + """) + + for grid_x in range(-10, 10): + for grid_y in range(-10, 10): + # if (grid_x, grid_y) in intersecting_grid_idx: + # fill_color = "red" + # elif (grid_x, grid_y) in build_plate_grid_idx: + # fill_color = "green" + # else: + # fill_color = "orange" + coord_grid_x, coord_grid_y = self.gridSpaceToCoordSpace(grid_x, grid_y) + f.write( + f""" + + """) + f.write(f""" + + {grid_x},{grid_y} + + """) + for node in self._fixed_nodes: + bounding_box = node.getBoundingBox() + f.write(f""" + + """) + for node in self._nodes_to_arrange: + bounding_box = node.getBoundingBox() + f.write(f""" + + """) + f.write(f"") diff --git a/cura/MultiplyObjectsJob.py b/cura/MultiplyObjectsJob.py index ff4f362b4c..e1cead7557 100644 --- a/cura/MultiplyObjectsJob.py +++ b/cura/MultiplyObjectsJob.py @@ -14,6 +14,7 @@ from UM.Operations.TranslateOperation import TranslateOperation from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator from UM.Scene.SceneNode import SceneNode from UM.i18n import i18nCatalog +from cura.Arranging.GridArrange import GridArrange from cura.Arranging.Nest2DArrange import arrange, createGroupOperationForArrange i18n_catalog = i18nCatalog("cura") @@ -77,12 +78,17 @@ class MultiplyObjectsJob(Job): found_solution_for_all = True group_operation = GroupedOperation() if nodes: - group_operation, not_fit_count = createGroupOperationForArrange(nodes, - Application.getInstance().getBuildVolume(), - fixed_nodes, - factor=10000, - add_new_nodes_in_scene=True, - lock_rotation=self._lock_rotation) + grid_arrange = GridArrange(nodes,Application.getInstance().getBuildVolume(), + fixed_nodes) + + group_operation, not_fit_count = grid_arrange.arrange() + print("group_operation", group_operation) + # group_operation, not_fit_count = createGroupOperationForArrange(nodes, + # Application.getInstance().getBuildVolume(), + # fixed_nodes, + # factor=10000, + # add_new_nodes_in_scene=True, + # lock_rotation=self._lock_rotation) found_solution_for_all = not_fit_count == 0 if nodes_to_add_without_arrange: From df69ccadb585fb86291861b1dfd3015dadfd0182 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Mon, 21 Aug 2023 18:45:40 +0200 Subject: [PATCH 05/25] Revert "multiplying objects place them in a grid" This reverts commit 209162fbce5dc0e5b2ff934900623691c46df233. --- cura/Arranging/GridArrange.py | 185 ---------------------------------- cura/MultiplyObjectsJob.py | 18 ++-- 2 files changed, 6 insertions(+), 197 deletions(-) delete mode 100644 cura/Arranging/GridArrange.py diff --git a/cura/Arranging/GridArrange.py b/cura/Arranging/GridArrange.py deleted file mode 100644 index 543971c5b2..0000000000 --- a/cura/Arranging/GridArrange.py +++ /dev/null @@ -1,185 +0,0 @@ -import math -from typing import List, TYPE_CHECKING, Optional, Tuple, Set - -from UM.Application import Application -from UM.Math import AxisAlignedBox -from UM.Math.Vector import Vector -from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation -from UM.Operations.GroupedOperation import GroupedOperation -from UM.Operations.TranslateOperation import TranslateOperation - - -class GridArrange: - offset_x: float = 10 - offset_y: float = 10 - - _grid_width: float - _grid_height: float - - _nodes_to_arrange: List["SceneNode"] - _fixed_nodes: List["SceneNode"] - _build_volume_bounding_box = AxisAlignedBox - - def __init__(self, nodes_to_arrange: List["SceneNode"], build_volume: "BuildVolume", fixed_nodes: List["SceneNode"] = []): - print("len(nodes_to_arrange)", len(nodes_to_arrange)) - self._nodes_to_arrange = nodes_to_arrange - self._build_volume_bounding_box = build_volume.getBoundingBox() - self._fixed_nodes = fixed_nodes - - def arrange(self) -> Tuple[GroupedOperation, int]: - self._grid_width = 0 - self._grid_height = 0 - for node in self._nodes_to_arrange: - bounding_box = node.getBoundingBox() - self._grid_width = max(self._grid_width, bounding_box.width) - self._grid_height = max(self._grid_height, bounding_box.depth) - - # Find grid indexes that intersect with fixed objects - fixed_nodes_grid_ids = set() - for node in self._fixed_nodes: - fixed_nodes_grid_ids = fixed_nodes_grid_ids.union(self.intersectingGridIdxInclusive(node.getBoundingBox())) - - build_plate_grid_ids = self.intersectingGridIdxExclusive(self._build_volume_bounding_box) - allowed_grid_idx = build_plate_grid_ids.difference(fixed_nodes_grid_ids) - - # Find the sequence in which items are placed - coord_build_plate_center_x = self._build_volume_bounding_box.width * 0.5 + self._build_volume_bounding_box.left - coord_build_plate_center_y = self._build_volume_bounding_box.depth * 0.5 + self._build_volume_bounding_box.back - grid_build_plate_center_x, grid_build_plate_center_y = self.coordSpaceToGridSpace(coord_build_plate_center_x, coord_build_plate_center_y) - - def distToCenter(grid_id: Tuple[int, int]) -> float: - grid_x, grid_y = grid_id - distance_squared = (grid_build_plate_center_x - grid_x) ** 2 + (grid_build_plate_center_y - grid_y) ** 2 - return distance_squared - - sequence: List[Tuple[int, int]] = list(allowed_grid_idx) - sequence.sort(key=distToCenter) - scene_root = Application.getInstance().getController().getScene().getRoot() - grouped_operation = GroupedOperation() - - for grid_id, node in zip(sequence, self._nodes_to_arrange): - grouped_operation.addOperation(AddSceneNodeOperation(node, scene_root)) - grid_x, grid_y = grid_id - - coord_grid_x, coord_grid_y = self.gridSpaceToCoordSpace(grid_x, grid_y) - center_grid_x = coord_grid_x+(0.5 * self._grid_width) - center_grid_y = coord_grid_y+(0.5 * self._grid_height) - - bounding_box = node.getBoundingBox() - center_node_x = (bounding_box.left + bounding_box.right) * 0.5 - center_node_y = (bounding_box.back + bounding_box.front) * 0.5 - - delta_x = center_grid_x - center_node_x - delta_y = center_grid_y - center_node_y - grouped_operation.addOperation(TranslateOperation(node, Vector(delta_x, 0, delta_y))) - - self.drawDebugSvg() - - return grouped_operation, 0 - - def getGridCornerPoints(self, bounding_box: "BoundingVolume") -> Tuple[float, float, float, float]: - coord_x1 = bounding_box.left - coord_x2 = bounding_box.right - coord_y1 = bounding_box.back - coord_y2 = bounding_box.front - grid_x1, grid_y1 = self.coordSpaceToGridSpace(coord_x1, coord_y1) - grid_x2, grid_y2 = self.coordSpaceToGridSpace(coord_x2, coord_y2) - return grid_x1, grid_y1, grid_x2, grid_y2 - - def intersectingGridIdxInclusive(self, bounding_box: "BoundingVolume") -> Set[Tuple[int, int]]: - grid_x1, grid_y1, grid_x2, grid_y2 = self.getGridCornerPoints(bounding_box) - grid_idx = set() - for grid_x in range(math.floor(grid_x1), math.ceil(grid_x2)): - for grid_y in range(math.floor(grid_y1), math.ceil(grid_y2)): - grid_idx.add((grid_x, grid_y)) - return grid_idx - - def intersectingGridIdxExclusive(self, bounding_box: "BoundingVolume") -> Set[Tuple[int, int]]: - grid_x1, grid_y1, grid_x2, grid_y2 = self.getGridCornerPoints(bounding_box) - grid_idx = set() - for grid_x in range(math.ceil(grid_x1), math.floor(grid_x2)): - for grid_y in range(math.ceil(grid_y1), math.floor(grid_y2)): - grid_idx.add((grid_x, grid_y)) - return grid_idx - - def gridSpaceToCoordSpace(self, x: float, y: float) -> Tuple[float, float]: - grid_x = x * (self._grid_width + self.offset_x) + self._build_volume_bounding_box.left - grid_y = y * (self._grid_height + self.offset_y) + self._build_volume_bounding_box.back - return grid_x, grid_y - - def coordSpaceToGridSpace(self, grid_x: float, grid_y: float) -> Tuple[float, float]: - coord_x = (grid_x - self._build_volume_bounding_box.left) / (self._grid_width + self.offset_x) - coord_y = (grid_y - self._build_volume_bounding_box.back) / (self._grid_height + self.offset_y) - return coord_x, coord_y - - def drawDebugSvg(self): - with open("Builvolume_test.svg", "w") as f: - build_volume_bounding_box = self._build_volume_bounding_box - - f.write( - f"\n") - - f.write( - f""" - - """) - - for grid_x in range(-10, 10): - for grid_y in range(-10, 10): - # if (grid_x, grid_y) in intersecting_grid_idx: - # fill_color = "red" - # elif (grid_x, grid_y) in build_plate_grid_idx: - # fill_color = "green" - # else: - # fill_color = "orange" - coord_grid_x, coord_grid_y = self.gridSpaceToCoordSpace(grid_x, grid_y) - f.write( - f""" - - """) - f.write(f""" - - {grid_x},{grid_y} - - """) - for node in self._fixed_nodes: - bounding_box = node.getBoundingBox() - f.write(f""" - - """) - for node in self._nodes_to_arrange: - bounding_box = node.getBoundingBox() - f.write(f""" - - """) - f.write(f"") diff --git a/cura/MultiplyObjectsJob.py b/cura/MultiplyObjectsJob.py index e1cead7557..ff4f362b4c 100644 --- a/cura/MultiplyObjectsJob.py +++ b/cura/MultiplyObjectsJob.py @@ -14,7 +14,6 @@ from UM.Operations.TranslateOperation import TranslateOperation from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator from UM.Scene.SceneNode import SceneNode from UM.i18n import i18nCatalog -from cura.Arranging.GridArrange import GridArrange from cura.Arranging.Nest2DArrange import arrange, createGroupOperationForArrange i18n_catalog = i18nCatalog("cura") @@ -78,17 +77,12 @@ class MultiplyObjectsJob(Job): found_solution_for_all = True group_operation = GroupedOperation() if nodes: - grid_arrange = GridArrange(nodes,Application.getInstance().getBuildVolume(), - fixed_nodes) - - group_operation, not_fit_count = grid_arrange.arrange() - print("group_operation", group_operation) - # group_operation, not_fit_count = createGroupOperationForArrange(nodes, - # Application.getInstance().getBuildVolume(), - # fixed_nodes, - # factor=10000, - # add_new_nodes_in_scene=True, - # lock_rotation=self._lock_rotation) + group_operation, not_fit_count = createGroupOperationForArrange(nodes, + Application.getInstance().getBuildVolume(), + fixed_nodes, + factor=10000, + add_new_nodes_in_scene=True, + lock_rotation=self._lock_rotation) found_solution_for_all = not_fit_count == 0 if nodes_to_add_without_arrange: From b91ebcbb364b14d2aa6a8d894fcbc27a2bb06538 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Mon, 21 Aug 2023 18:51:08 +0200 Subject: [PATCH 06/25] multiplying objects place them in a grid Co-authored-by: Casper Lamboo CURA-7951 --- cura/Arranging/GridArrange.py | 185 ++++++++++++++++++++++++++++++++++ cura/MultiplyObjectsJob.py | 18 ++-- 2 files changed, 197 insertions(+), 6 deletions(-) create mode 100644 cura/Arranging/GridArrange.py diff --git a/cura/Arranging/GridArrange.py b/cura/Arranging/GridArrange.py new file mode 100644 index 0000000000..543971c5b2 --- /dev/null +++ b/cura/Arranging/GridArrange.py @@ -0,0 +1,185 @@ +import math +from typing import List, TYPE_CHECKING, Optional, Tuple, Set + +from UM.Application import Application +from UM.Math import AxisAlignedBox +from UM.Math.Vector import Vector +from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation +from UM.Operations.GroupedOperation import GroupedOperation +from UM.Operations.TranslateOperation import TranslateOperation + + +class GridArrange: + offset_x: float = 10 + offset_y: float = 10 + + _grid_width: float + _grid_height: float + + _nodes_to_arrange: List["SceneNode"] + _fixed_nodes: List["SceneNode"] + _build_volume_bounding_box = AxisAlignedBox + + def __init__(self, nodes_to_arrange: List["SceneNode"], build_volume: "BuildVolume", fixed_nodes: List["SceneNode"] = []): + print("len(nodes_to_arrange)", len(nodes_to_arrange)) + self._nodes_to_arrange = nodes_to_arrange + self._build_volume_bounding_box = build_volume.getBoundingBox() + self._fixed_nodes = fixed_nodes + + def arrange(self) -> Tuple[GroupedOperation, int]: + self._grid_width = 0 + self._grid_height = 0 + for node in self._nodes_to_arrange: + bounding_box = node.getBoundingBox() + self._grid_width = max(self._grid_width, bounding_box.width) + self._grid_height = max(self._grid_height, bounding_box.depth) + + # Find grid indexes that intersect with fixed objects + fixed_nodes_grid_ids = set() + for node in self._fixed_nodes: + fixed_nodes_grid_ids = fixed_nodes_grid_ids.union(self.intersectingGridIdxInclusive(node.getBoundingBox())) + + build_plate_grid_ids = self.intersectingGridIdxExclusive(self._build_volume_bounding_box) + allowed_grid_idx = build_plate_grid_ids.difference(fixed_nodes_grid_ids) + + # Find the sequence in which items are placed + coord_build_plate_center_x = self._build_volume_bounding_box.width * 0.5 + self._build_volume_bounding_box.left + coord_build_plate_center_y = self._build_volume_bounding_box.depth * 0.5 + self._build_volume_bounding_box.back + grid_build_plate_center_x, grid_build_plate_center_y = self.coordSpaceToGridSpace(coord_build_plate_center_x, coord_build_plate_center_y) + + def distToCenter(grid_id: Tuple[int, int]) -> float: + grid_x, grid_y = grid_id + distance_squared = (grid_build_plate_center_x - grid_x) ** 2 + (grid_build_plate_center_y - grid_y) ** 2 + return distance_squared + + sequence: List[Tuple[int, int]] = list(allowed_grid_idx) + sequence.sort(key=distToCenter) + scene_root = Application.getInstance().getController().getScene().getRoot() + grouped_operation = GroupedOperation() + + for grid_id, node in zip(sequence, self._nodes_to_arrange): + grouped_operation.addOperation(AddSceneNodeOperation(node, scene_root)) + grid_x, grid_y = grid_id + + coord_grid_x, coord_grid_y = self.gridSpaceToCoordSpace(grid_x, grid_y) + center_grid_x = coord_grid_x+(0.5 * self._grid_width) + center_grid_y = coord_grid_y+(0.5 * self._grid_height) + + bounding_box = node.getBoundingBox() + center_node_x = (bounding_box.left + bounding_box.right) * 0.5 + center_node_y = (bounding_box.back + bounding_box.front) * 0.5 + + delta_x = center_grid_x - center_node_x + delta_y = center_grid_y - center_node_y + grouped_operation.addOperation(TranslateOperation(node, Vector(delta_x, 0, delta_y))) + + self.drawDebugSvg() + + return grouped_operation, 0 + + def getGridCornerPoints(self, bounding_box: "BoundingVolume") -> Tuple[float, float, float, float]: + coord_x1 = bounding_box.left + coord_x2 = bounding_box.right + coord_y1 = bounding_box.back + coord_y2 = bounding_box.front + grid_x1, grid_y1 = self.coordSpaceToGridSpace(coord_x1, coord_y1) + grid_x2, grid_y2 = self.coordSpaceToGridSpace(coord_x2, coord_y2) + return grid_x1, grid_y1, grid_x2, grid_y2 + + def intersectingGridIdxInclusive(self, bounding_box: "BoundingVolume") -> Set[Tuple[int, int]]: + grid_x1, grid_y1, grid_x2, grid_y2 = self.getGridCornerPoints(bounding_box) + grid_idx = set() + for grid_x in range(math.floor(grid_x1), math.ceil(grid_x2)): + for grid_y in range(math.floor(grid_y1), math.ceil(grid_y2)): + grid_idx.add((grid_x, grid_y)) + return grid_idx + + def intersectingGridIdxExclusive(self, bounding_box: "BoundingVolume") -> Set[Tuple[int, int]]: + grid_x1, grid_y1, grid_x2, grid_y2 = self.getGridCornerPoints(bounding_box) + grid_idx = set() + for grid_x in range(math.ceil(grid_x1), math.floor(grid_x2)): + for grid_y in range(math.ceil(grid_y1), math.floor(grid_y2)): + grid_idx.add((grid_x, grid_y)) + return grid_idx + + def gridSpaceToCoordSpace(self, x: float, y: float) -> Tuple[float, float]: + grid_x = x * (self._grid_width + self.offset_x) + self._build_volume_bounding_box.left + grid_y = y * (self._grid_height + self.offset_y) + self._build_volume_bounding_box.back + return grid_x, grid_y + + def coordSpaceToGridSpace(self, grid_x: float, grid_y: float) -> Tuple[float, float]: + coord_x = (grid_x - self._build_volume_bounding_box.left) / (self._grid_width + self.offset_x) + coord_y = (grid_y - self._build_volume_bounding_box.back) / (self._grid_height + self.offset_y) + return coord_x, coord_y + + def drawDebugSvg(self): + with open("Builvolume_test.svg", "w") as f: + build_volume_bounding_box = self._build_volume_bounding_box + + f.write( + f"\n") + + f.write( + f""" + + """) + + for grid_x in range(-10, 10): + for grid_y in range(-10, 10): + # if (grid_x, grid_y) in intersecting_grid_idx: + # fill_color = "red" + # elif (grid_x, grid_y) in build_plate_grid_idx: + # fill_color = "green" + # else: + # fill_color = "orange" + coord_grid_x, coord_grid_y = self.gridSpaceToCoordSpace(grid_x, grid_y) + f.write( + f""" + + """) + f.write(f""" + + {grid_x},{grid_y} + + """) + for node in self._fixed_nodes: + bounding_box = node.getBoundingBox() + f.write(f""" + + """) + for node in self._nodes_to_arrange: + bounding_box = node.getBoundingBox() + f.write(f""" + + """) + f.write(f"") diff --git a/cura/MultiplyObjectsJob.py b/cura/MultiplyObjectsJob.py index ff4f362b4c..e1cead7557 100644 --- a/cura/MultiplyObjectsJob.py +++ b/cura/MultiplyObjectsJob.py @@ -14,6 +14,7 @@ from UM.Operations.TranslateOperation import TranslateOperation from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator from UM.Scene.SceneNode import SceneNode from UM.i18n import i18nCatalog +from cura.Arranging.GridArrange import GridArrange from cura.Arranging.Nest2DArrange import arrange, createGroupOperationForArrange i18n_catalog = i18nCatalog("cura") @@ -77,12 +78,17 @@ class MultiplyObjectsJob(Job): found_solution_for_all = True group_operation = GroupedOperation() if nodes: - group_operation, not_fit_count = createGroupOperationForArrange(nodes, - Application.getInstance().getBuildVolume(), - fixed_nodes, - factor=10000, - add_new_nodes_in_scene=True, - lock_rotation=self._lock_rotation) + grid_arrange = GridArrange(nodes,Application.getInstance().getBuildVolume(), + fixed_nodes) + + group_operation, not_fit_count = grid_arrange.arrange() + print("group_operation", group_operation) + # group_operation, not_fit_count = createGroupOperationForArrange(nodes, + # Application.getInstance().getBuildVolume(), + # fixed_nodes, + # factor=10000, + # add_new_nodes_in_scene=True, + # lock_rotation=self._lock_rotation) found_solution_for_all = not_fit_count == 0 if nodes_to_add_without_arrange: From b62725b4f0289ed672281d4b913d708f4de3234a Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Tue, 22 Aug 2023 10:30:51 +0200 Subject: [PATCH 07/25] copy_paste in a grid arrange all objects in grid place in grid Co-authored-by: Casper Lamboo CURA-7951 --- cura/Arranging/ArrangeObjectsJob.py | 15 +++++++++++---- cura/Arranging/GridArrange.py | 8 +++++++- cura/CuraActions.py | 12 ++++++------ cura/CuraApplication.py | 10 +++++----- cura/MultiplyObjectsJob.py | 24 +++++++++++------------- resources/qml/Actions.qml | 6 +++--- resources/qml/Menus/ContextMenu.qml | 8 ++++---- 7 files changed, 47 insertions(+), 36 deletions(-) diff --git a/cura/Arranging/ArrangeObjectsJob.py b/cura/Arranging/ArrangeObjectsJob.py index f938b44d1f..d122098565 100644 --- a/cura/Arranging/ArrangeObjectsJob.py +++ b/cura/Arranging/ArrangeObjectsJob.py @@ -8,6 +8,7 @@ from UM.Logger import Logger from UM.Message import Message from UM.Scene.SceneNode import SceneNode from UM.i18n import i18nCatalog +from cura.Arranging.GridArrange import GridArrange from cura.Arranging.Nest2DArrange import arrange i18n_catalog = i18nCatalog("cura") @@ -15,12 +16,12 @@ i18n_catalog = i18nCatalog("cura") class ArrangeObjectsJob(Job): def __init__(self, nodes: List[SceneNode], fixed_nodes: List[SceneNode], min_offset=8, - lock_rotation: bool = False) -> None: + grid_arrange: bool = False) -> None: super().__init__() self._nodes = nodes self._fixed_nodes = fixed_nodes self._min_offset = min_offset - self._lock_rotation = lock_rotation + self._grid_arrange = grid_arrange def run(self): found_solution_for_all = False @@ -32,8 +33,14 @@ class ArrangeObjectsJob(Job): status_message.show() try: - found_solution_for_all = arrange(self._nodes, Application.getInstance().getBuildVolume(), self._fixed_nodes, - lock_rotation=self._lock_rotation) + + if self._grid_arrange: + grid_arrange = GridArrange(self._nodes, Application.getInstance().getBuildVolume(), self._fixed_nodes) + found_solution_for_all = grid_arrange.arrange() + + else: + found_solution_for_all = arrange(self._nodes, Application.getInstance().getBuildVolume(), self._fixed_nodes) + except: # If the thread crashes, the message should still close Logger.logException("e", "Unable to arrange the objects on the buildplate. The arrange algorithm has crashed.") diff --git a/cura/Arranging/GridArrange.py b/cura/Arranging/GridArrange.py index 543971c5b2..0d76ecff52 100644 --- a/cura/Arranging/GridArrange.py +++ b/cura/Arranging/GridArrange.py @@ -26,7 +26,13 @@ class GridArrange: self._build_volume_bounding_box = build_volume.getBoundingBox() self._fixed_nodes = fixed_nodes - def arrange(self) -> Tuple[GroupedOperation, int]: + def arrange(self)-> bool: + + grouped_operation, not_fit_count = self.createGroupOperationForArrange() + grouped_operation.push() + return not_fit_count == 0 + + def createGroupOperationForArrange(self) -> Tuple[GroupedOperation, int]: self._grid_width = 0 self._grid_height = 0 for node in self._nodes_to_arrange: diff --git a/cura/CuraActions.py b/cura/CuraActions.py index 3567c1532f..1b98bdddd8 100644 --- a/cura/CuraActions.py +++ b/cura/CuraActions.py @@ -18,6 +18,7 @@ from UM.Operations.RemoveSceneNodeOperation import RemoveSceneNodeOperation from UM.Operations.TranslateOperation import TranslateOperation import cura.CuraApplication +from cura.Arranging.GridArrange import GridArrange from cura.Operations.SetParentOperation import SetParentOperation from cura.MultiplyObjectsJob import MultiplyObjectsJob from cura.Settings.SetObjectExtruderOperation import SetObjectExtruderOperation @@ -84,16 +85,16 @@ class CuraActions(QObject): operation.push() @pyqtSlot(int, bool) - def multiplySelection(self, count: int, lock_rotation: bool) -> None: + def multiplySelection(self, count: int, grid_placement: bool) -> None: """Multiply all objects in the selection :param count: The number of times to multiply the selection. - :param lock_rotation: If set to true the orientation of the object will remain the same + :param grid_placement: If set to true objects are placed in a grid """ min_offset = cura.CuraApplication.CuraApplication.getInstance().getBuildVolume().getEdgeDisallowedSize() + 2 # Allow for some rounding errors job = MultiplyObjectsJob(Selection.getAllSelectedObjects(), count, min_offset=max(min_offset, 8), - lock_rotation=lock_rotation) + grid_arrange=grid_placement) job.start() @pyqtSlot() @@ -231,9 +232,8 @@ class CuraActions(QObject): if node.callDecoration("isSliceable"): fixed_nodes.append(node) # Add the new nodes to the scene, and arrange them - group_operation, not_fit_count = createGroupOperationForArrange(nodes, application.getBuildVolume(), - fixed_nodes, factor=10000, - add_new_nodes_in_scene=True) + grid_arrange = GridArrange(nodes, application.getBuildVolume(), fixed_nodes) + group_operation, not_fit_count = grid_arrange.createGroupOperationForArrange() group_operation.push() # deselect currently selected nodes, and select the new nodes diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 82d009e436..c6c0ed3cd2 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -1441,7 +1441,7 @@ class CuraApplication(QtApplication): # Single build plate @pyqtSlot(bool) - def arrangeAll(self, lock_rotation: bool) -> None: + def arrangeAll(self, grid_arrangement: bool) -> None: nodes_to_arrange = [] active_build_plate = self.getMultiBuildPlateModel().activeBuildPlate locked_nodes = [] @@ -1471,18 +1471,18 @@ class CuraApplication(QtApplication): locked_nodes.append(node) else: nodes_to_arrange.append(node) - self.arrange(nodes_to_arrange, locked_nodes, lock_rotation) + self.arrange(nodes_to_arrange, locked_nodes, grid_arrangement) - def arrange(self, nodes: List[SceneNode], fixed_nodes: List[SceneNode], lock_rotation: bool = False) -> None: + def arrange(self, nodes: List[SceneNode], fixed_nodes: List[SceneNode], grid_arrangement: bool = False) -> None: """Arrange a set of nodes given a set of fixed nodes :param nodes: nodes that we have to place :param fixed_nodes: nodes that are placed in the arranger before finding spots for nodes - :param lock_rotation: If set to true the orientation of the object will remain the same + :param grid_arrangement: If set to true if objects are to be placed in a grid """ min_offset = self.getBuildVolume().getEdgeDisallowedSize() + 2 # Allow for some rounding errors - job = ArrangeObjectsJob(nodes, fixed_nodes, min_offset=max(min_offset, 8), lock_rotation=lock_rotation) + job = ArrangeObjectsJob(nodes, fixed_nodes, min_offset=max(min_offset, 8), grid_arrange =grid_arrangement) job.start() @pyqtSlot() diff --git a/cura/MultiplyObjectsJob.py b/cura/MultiplyObjectsJob.py index e1cead7557..6df80eb01c 100644 --- a/cura/MultiplyObjectsJob.py +++ b/cura/MultiplyObjectsJob.py @@ -21,12 +21,12 @@ i18n_catalog = i18nCatalog("cura") class MultiplyObjectsJob(Job): - def __init__(self, objects, count: int, min_offset: int = 8, lock_rotation: bool = False): + def __init__(self, objects, count: int, min_offset: int = 8, grid_arrange: bool = False): super().__init__() self._objects = objects self._count: int = count self._min_offset: int = min_offset - self._lock_rotation: bool = lock_rotation + self._grid_arrange: bool = grid_arrange def run(self) -> None: status_message = Message(i18n_catalog.i18nc("@info:status", "Multiplying and placing objects"), lifetime = 0, @@ -78,18 +78,16 @@ class MultiplyObjectsJob(Job): found_solution_for_all = True group_operation = GroupedOperation() if nodes: - grid_arrange = GridArrange(nodes,Application.getInstance().getBuildVolume(), - fixed_nodes) + if(self._grid_arrange): + grid_arrange = GridArrange(nodes,Application.getInstance().getBuildVolume(),fixed_nodes) + group_operation, not_fit_count = grid_arrange.createGroupOperationForArrange() - group_operation, not_fit_count = grid_arrange.arrange() - print("group_operation", group_operation) - # group_operation, not_fit_count = createGroupOperationForArrange(nodes, - # Application.getInstance().getBuildVolume(), - # fixed_nodes, - # factor=10000, - # add_new_nodes_in_scene=True, - # lock_rotation=self._lock_rotation) - found_solution_for_all = not_fit_count == 0 + else: + group_operation, not_fit_count = createGroupOperationForArrange(nodes, + Application.getInstance().getBuildVolume(), + fixed_nodes, + factor=10000, + add_new_nodes_in_scene=True) if nodes_to_add_without_arrange: for nested_node in nodes_to_add_without_arrange: diff --git a/resources/qml/Actions.qml b/resources/qml/Actions.qml index e47f797195..1c84ec66b7 100644 --- a/resources/qml/Actions.qml +++ b/resources/qml/Actions.qml @@ -41,7 +41,7 @@ Item property alias deleteAll: deleteAllAction property alias reloadAll: reloadAllAction property alias arrangeAll: arrangeAllAction - property alias arrangeAllLock: arrangeAllLockAction + property alias arrangeAllGrid: arrangeAllGridAction property alias arrangeSelection: arrangeSelectionAction property alias arrangeSelectionLock: arrangeSelectionLockAction property alias resetAllTranslation: resetAllTranslationAction @@ -464,8 +464,8 @@ Item Action { - id: arrangeAllLockAction - text: catalog.i18nc("@action:inmenu menubar:edit","Arrange All Models Without Rotation") + id: arrangeAllGridAction + text: catalog.i18nc("@action:inmenu menubar:edit","Arrange All Models in a grid") onTriggered: Printer.arrangeAll(true) shortcut: "Shift+Ctrl+R" } diff --git a/resources/qml/Menus/ContextMenu.qml b/resources/qml/Menus/ContextMenu.qml index f07b4d9571..75d366e5db 100644 --- a/resources/qml/Menus/ContextMenu.qml +++ b/resources/qml/Menus/ContextMenu.qml @@ -66,7 +66,7 @@ Cura.Menu Cura.MenuSeparator {} Cura.MenuItem { action: Cura.Actions.selectAll } Cura.MenuItem { action: Cura.Actions.arrangeAll } - Cura.MenuItem { action: Cura.Actions.arrangeAllLock } + Cura.MenuItem { action: Cura.Actions.arrangeAllGrid } Cura.MenuItem { action: Cura.Actions.deleteAll } Cura.MenuItem { action: Cura.Actions.reloadAll } Cura.MenuItem { action: Cura.Actions.resetAllTranslation } @@ -110,7 +110,7 @@ Cura.Menu minimumWidth: UM.Theme.getSize("small_popup_dialog").width minimumHeight: UM.Theme.getSize("small_popup_dialog").height - onAccepted: CuraActions.multiplySelection(copiesField.value, lockRotationField.checked) + onAccepted: CuraActions.multiplySelection(copiesField.value, gridPlacementSelected.checked) buttonSpacing: UM.Theme.getSize("thin_margin").width @@ -158,8 +158,8 @@ Cura.Menu UM.CheckBox { - id: lockRotationField - text: catalog.i18nc("@label", "Lock Rotation") + id: gridPlacementSelected + text: catalog.i18nc("@label", "Grid Placement") } } } From 2089462cd8121fe0e220e38c9909a13f688d8b9b Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Tue, 22 Aug 2023 11:16:02 +0200 Subject: [PATCH 08/25] place objects outside grid Co-authored-by: Casper Lamboo CURA-7951 --- cura/Arranging/GridArrange.py | 60 +++++++++++++++++++++++++---------- 1 file changed, 43 insertions(+), 17 deletions(-) diff --git a/cura/Arranging/GridArrange.py b/cura/Arranging/GridArrange.py index 0d76ecff52..212f7b8e51 100644 --- a/cura/Arranging/GridArrange.py +++ b/cura/Arranging/GridArrange.py @@ -26,13 +26,6 @@ class GridArrange: self._build_volume_bounding_box = build_volume.getBoundingBox() self._fixed_nodes = fixed_nodes - def arrange(self)-> bool: - - grouped_operation, not_fit_count = self.createGroupOperationForArrange() - grouped_operation.push() - return not_fit_count == 0 - - def createGroupOperationForArrange(self) -> Tuple[GroupedOperation, int]: self._grid_width = 0 self._grid_height = 0 for node in self._nodes_to_arrange: @@ -40,6 +33,19 @@ class GridArrange: self._grid_width = max(self._grid_width, bounding_box.width) self._grid_height = max(self._grid_height, bounding_box.depth) + coord_initial_leftover_x = self._build_volume_bounding_box.right + 2 * self._grid_width + coord_initial_leftover_y = (self._build_volume_bounding_box.back + self._build_volume_bounding_box.front) * 0.5 + self._initial_leftover_grid_x, self._initial_leftover_grid_y = self.coordSpaceToGridSpace(coord_initial_leftover_x, coord_initial_leftover_y) + self._initial_leftover_grid_x = math.floor(self._initial_leftover_grid_x) + self._initial_leftover_grid_y = math.floor(self._initial_leftover_grid_y) + + def arrange(self)-> bool: + + grouped_operation, not_fit_count = self.createGroupOperationForArrange() + grouped_operation.push() + return not_fit_count == 0 + + def createGroupOperationForArrange(self) -> Tuple[GroupedOperation, int]: # Find grid indexes that intersect with fixed objects fixed_nodes_grid_ids = set() for node in self._fixed_nodes: @@ -67,21 +73,41 @@ class GridArrange: grouped_operation.addOperation(AddSceneNodeOperation(node, scene_root)) grid_x, grid_y = grid_id - coord_grid_x, coord_grid_y = self.gridSpaceToCoordSpace(grid_x, grid_y) - center_grid_x = coord_grid_x+(0.5 * self._grid_width) - center_grid_y = coord_grid_y+(0.5 * self._grid_height) + operation = self.moveNodeOnGrid(node, grid_x, grid_y) + grouped_operation.addOperation(operation) - bounding_box = node.getBoundingBox() - center_node_x = (bounding_box.left + bounding_box.right) * 0.5 - center_node_y = (bounding_box.back + bounding_box.front) * 0.5 + leftover_nodes = self._nodes_to_arrange[len(sequence):] - delta_x = center_grid_x - center_node_x - delta_y = center_grid_y - center_node_y - grouped_operation.addOperation(TranslateOperation(node, Vector(delta_x, 0, delta_y))) + left_over_grid_y = self._initial_leftover_grid_y + for node in leftover_nodes: + grouped_operation.addOperation(AddSceneNodeOperation(node, scene_root)) + + # find the first next grid position that isn't occupied by a fixed node + while (self._initial_leftover_grid_x, left_over_grid_y) in fixed_nodes_grid_ids: + left_over_grid_y = left_over_grid_y - 1 + + operation = self.moveNodeOnGrid(node, self._initial_leftover_grid_x, left_over_grid_y) + grouped_operation.addOperation(operation) + + left_over_grid_y = left_over_grid_y - 1 self.drawDebugSvg() - return grouped_operation, 0 + return grouped_operation, len(leftover_nodes) + + def moveNodeOnGrid(self, node: "SceneNode", grid_x: int, grid_y: int) -> "Operation.Operation": + coord_grid_x, coord_grid_y = self.gridSpaceToCoordSpace(grid_x, grid_y) + center_grid_x = coord_grid_x + (0.5 * self._grid_width) + center_grid_y = coord_grid_y + (0.5 * self._grid_height) + + bounding_box = node.getBoundingBox() + center_node_x = (bounding_box.left + bounding_box.right) * 0.5 + center_node_y = (bounding_box.back + bounding_box.front) * 0.5 + + delta_x = center_grid_x - center_node_x + delta_y = center_grid_y - center_node_y + + return TranslateOperation(node, Vector(delta_x, 0, delta_y)) def getGridCornerPoints(self, bounding_box: "BoundingVolume") -> Tuple[float, float, float, float]: coord_x1 = bounding_box.left From 7449e2137c979b49ccf9a4f423344ed887070bb9 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Tue, 22 Aug 2023 11:26:43 +0200 Subject: [PATCH 09/25] objects placed with an offset to the grid Co-authored-by: Casper Lamboo CURA-7951 --- cura/Arranging/GridArrange.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cura/Arranging/GridArrange.py b/cura/Arranging/GridArrange.py index 212f7b8e51..fbfaa7f40e 100644 --- a/cura/Arranging/GridArrange.py +++ b/cura/Arranging/GridArrange.py @@ -97,8 +97,8 @@ class GridArrange: def moveNodeOnGrid(self, node: "SceneNode", grid_x: int, grid_y: int) -> "Operation.Operation": coord_grid_x, coord_grid_y = self.gridSpaceToCoordSpace(grid_x, grid_y) - center_grid_x = coord_grid_x + (0.5 * self._grid_width) - center_grid_y = coord_grid_y + (0.5 * self._grid_height) + center_grid_x = coord_grid_x + (0.5 * (self._grid_width + self.offset_x)) + center_grid_y = coord_grid_y + (0.5 * (self._grid_height + self.offset_y)) bounding_box = node.getBoundingBox() center_node_x = (bounding_box.left + bounding_box.right) * 0.5 From b662da732eeb5c310db4ab07e748624e12441c1d Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Tue, 22 Aug 2023 11:51:30 +0200 Subject: [PATCH 10/25] review comments fixed Co-authored-by: Casper Lamboo CURA-7951 --- cura/Arranging/GridArrange.py | 6 ------ cura/CuraActions.py | 15 +++++++++++---- cura/CuraApplication.py | 11 +++++++++-- resources/qml/Actions.qml | 4 ++-- resources/qml/Menus/ContextMenu.qml | 11 ++++++++++- 5 files changed, 32 insertions(+), 15 deletions(-) diff --git a/cura/Arranging/GridArrange.py b/cura/Arranging/GridArrange.py index fbfaa7f40e..6d4db360f7 100644 --- a/cura/Arranging/GridArrange.py +++ b/cura/Arranging/GridArrange.py @@ -21,7 +21,6 @@ class GridArrange: _build_volume_bounding_box = AxisAlignedBox def __init__(self, nodes_to_arrange: List["SceneNode"], build_volume: "BuildVolume", fixed_nodes: List["SceneNode"] = []): - print("len(nodes_to_arrange)", len(nodes_to_arrange)) self._nodes_to_arrange = nodes_to_arrange self._build_volume_bounding_box = build_volume.getBoundingBox() self._fixed_nodes = fixed_nodes @@ -72,7 +71,6 @@ class GridArrange: for grid_id, node in zip(sequence, self._nodes_to_arrange): grouped_operation.addOperation(AddSceneNodeOperation(node, scene_root)) grid_x, grid_y = grid_id - operation = self.moveNodeOnGrid(node, grid_x, grid_y) grouped_operation.addOperation(operation) @@ -81,18 +79,14 @@ class GridArrange: left_over_grid_y = self._initial_leftover_grid_y for node in leftover_nodes: grouped_operation.addOperation(AddSceneNodeOperation(node, scene_root)) - # find the first next grid position that isn't occupied by a fixed node while (self._initial_leftover_grid_x, left_over_grid_y) in fixed_nodes_grid_ids: left_over_grid_y = left_over_grid_y - 1 operation = self.moveNodeOnGrid(node, self._initial_leftover_grid_x, left_over_grid_y) grouped_operation.addOperation(operation) - left_over_grid_y = left_over_grid_y - 1 - self.drawDebugSvg() - return grouped_operation, len(leftover_nodes) def moveNodeOnGrid(self, node: "SceneNode", grid_x: int, grid_y: int) -> "Operation.Operation": diff --git a/cura/CuraActions.py b/cura/CuraActions.py index 1b98bdddd8..bd5787de42 100644 --- a/cura/CuraActions.py +++ b/cura/CuraActions.py @@ -83,18 +83,25 @@ class CuraActions(QObject): center_operation = TranslateOperation(current_node, Vector(0, center_y, 0), set_position=True) operation.addOperation(center_operation) operation.push() + @pyqtSlot(int) + def multiplySelection(self, count: int) -> None: + """Multiply all objects in the selection + :param count: The number of times to multiply the selection. + """ + min_offset = cura.CuraApplication.CuraApplication.getInstance().getBuildVolume().getEdgeDisallowedSize() + 2 # Allow for some rounding errors + job = MultiplyObjectsJob(Selection.getAllSelectedObjects(), count, min_offset = max(min_offset, 8)) + job.start() - @pyqtSlot(int, bool) - def multiplySelection(self, count: int, grid_placement: bool) -> None: + @pyqtSlot(int) + def multiplySelectionToGrid(self, count: int) -> None: """Multiply all objects in the selection :param count: The number of times to multiply the selection. - :param grid_placement: If set to true objects are placed in a grid """ min_offset = cura.CuraApplication.CuraApplication.getInstance().getBuildVolume().getEdgeDisallowedSize() + 2 # Allow for some rounding errors job = MultiplyObjectsJob(Selection.getAllSelectedObjects(), count, min_offset=max(min_offset, 8), - grid_arrange=grid_placement) + grid_arrange=True) job.start() @pyqtSlot() diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index c6c0ed3cd2..a9517c966c 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -1440,8 +1440,15 @@ class CuraApplication(QtApplication): op.push() # Single build plate - @pyqtSlot(bool) - def arrangeAll(self, grid_arrangement: bool) -> None: + @pyqtSlot() + def arrangeAll(self) -> None: + self._arrangeAll(False) + + @pyqtSlot() + def arrangeAllInGrid(self) -> None: + self._arrangeAll(True) + + def _arrangeAll(self, grid_arrangement: bool) -> None: nodes_to_arrange = [] active_build_plate = self.getMultiBuildPlateModel().activeBuildPlate locked_nodes = [] diff --git a/resources/qml/Actions.qml b/resources/qml/Actions.qml index 1c84ec66b7..0701ba48ce 100644 --- a/resources/qml/Actions.qml +++ b/resources/qml/Actions.qml @@ -458,7 +458,7 @@ Item { id: arrangeAllAction text: catalog.i18nc("@action:inmenu menubar:edit","Arrange All Models") - onTriggered: Printer.arrangeAll(false) + onTriggered: Printer.arrangeAll() shortcut: "Ctrl+R" } @@ -466,7 +466,7 @@ Item { id: arrangeAllGridAction text: catalog.i18nc("@action:inmenu menubar:edit","Arrange All Models in a grid") - onTriggered: Printer.arrangeAll(true) + onTriggered: Printer.arrangeAllInGrid() shortcut: "Shift+Ctrl+R" } diff --git a/resources/qml/Menus/ContextMenu.qml b/resources/qml/Menus/ContextMenu.qml index 75d366e5db..a095fb6e1a 100644 --- a/resources/qml/Menus/ContextMenu.qml +++ b/resources/qml/Menus/ContextMenu.qml @@ -110,7 +110,16 @@ Cura.Menu minimumWidth: UM.Theme.getSize("small_popup_dialog").width minimumHeight: UM.Theme.getSize("small_popup_dialog").height - onAccepted: CuraActions.multiplySelection(copiesField.value, gridPlacementSelected.checked) + onAccepted: { + if (gridPlacementSelected.checked) + { + CuraActions.multiplySelectionToGrid(copiesField.value) + } + else + { + CuraActions.multiplySelection(copiesField.value) + } + } buttonSpacing: UM.Theme.getSize("thin_margin").width From 4096fc864b524db6d3da45526abfc08e6c9604d2 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Tue, 22 Aug 2023 15:06:17 +0200 Subject: [PATCH 11/25] grid placement available for elliptical buildplates Co-authored-by: Casper Lamboo CURA-7951 --- cura/Arranging/ArrangeObjectsJob.py | 2 +- cura/Arranging/GridArrange.py | 90 +++++++++++++++++++++++------ cura/BuildVolume.py | 3 + cura/CuraActions.py | 2 +- resources/qml/Actions.qml | 16 ----- 5 files changed, 78 insertions(+), 35 deletions(-) diff --git a/cura/Arranging/ArrangeObjectsJob.py b/cura/Arranging/ArrangeObjectsJob.py index d122098565..4bb55bf660 100644 --- a/cura/Arranging/ArrangeObjectsJob.py +++ b/cura/Arranging/ArrangeObjectsJob.py @@ -15,7 +15,7 @@ i18n_catalog = i18nCatalog("cura") class ArrangeObjectsJob(Job): - def __init__(self, nodes: List[SceneNode], fixed_nodes: List[SceneNode], min_offset=8, + def __init__(self, nodes: List[SceneNode], fixed_nodes: List[SceneNode], min_offset = 8, grid_arrange: bool = False) -> None: super().__init__() self._nodes = nodes diff --git a/cura/Arranging/GridArrange.py b/cura/Arranging/GridArrange.py index 6d4db360f7..5280843bd3 100644 --- a/cura/Arranging/GridArrange.py +++ b/cura/Arranging/GridArrange.py @@ -18,10 +18,12 @@ class GridArrange: _nodes_to_arrange: List["SceneNode"] _fixed_nodes: List["SceneNode"] - _build_volume_bounding_box = AxisAlignedBox + _build_volume: "BuildVolume" + _build_volume_bounding_box: AxisAlignedBox def __init__(self, nodes_to_arrange: List["SceneNode"], build_volume: "BuildVolume", fixed_nodes: List["SceneNode"] = []): self._nodes_to_arrange = nodes_to_arrange + self._build_volume = build_volume self._build_volume_bounding_box = build_volume.getBoundingBox() self._fixed_nodes = fixed_nodes @@ -39,7 +41,6 @@ class GridArrange: self._initial_leftover_grid_y = math.floor(self._initial_leftover_grid_y) def arrange(self)-> bool: - grouped_operation, not_fit_count = self.createGroupOperationForArrange() grouped_operation.push() return not_fit_count == 0 @@ -51,6 +52,11 @@ class GridArrange: fixed_nodes_grid_ids = fixed_nodes_grid_ids.union(self.intersectingGridIdxInclusive(node.getBoundingBox())) build_plate_grid_ids = self.intersectingGridIdxExclusive(self._build_volume_bounding_box) + + # Filter out the corner grid squares if the build plate shape is elliptic + if self._build_volume.getShape() == "elliptic": + build_plate_grid_ids = set(filter(lambda grid_id: self.checkGridUnderDiscSpace(grid_id[0], grid_id[1]), build_plate_grid_ids)) + allowed_grid_idx = build_plate_grid_ids.difference(fixed_nodes_grid_ids) # Find the sequence in which items are placed @@ -86,7 +92,6 @@ class GridArrange: operation = self.moveNodeOnGrid(node, self._initial_leftover_grid_x, left_over_grid_y) grouped_operation.addOperation(operation) left_over_grid_y = left_over_grid_y - 1 - return grouped_operation, len(leftover_nodes) def moveNodeOnGrid(self, node: "SceneNode", grid_x: int, grid_y: int) -> "Operation.Operation": @@ -138,6 +143,35 @@ class GridArrange: coord_y = (grid_y - self._build_volume_bounding_box.back) / (self._grid_height + self.offset_y) return coord_x, coord_y + def checkGridUnderDiscSpace(self, grid_x: int, grid_y: int) -> bool: + left, back = self.gridSpaceToCoordSpace(grid_x, grid_y) + right, front = self.gridSpaceToCoordSpace(grid_x + 1, grid_y + 1) + corners = [(left, back), (right, back), (right, front), (left, front)] + return all([self.checkPointUnderDiscSpace(x, y) for x, y in corners]) + + def checkPointUnderDiscSpace(self, x: float, y: float) -> bool: + disc_x, disc_y = self.coordSpaceToDiscSpace(x, y) + distance_to_center_squared = disc_x ** 2 + disc_y ** 2 + return distance_to_center_squared <= 1.0 + + def coordSpaceToDiscSpace(self, x: float, y: float) -> Tuple[float, float]: + # Transform coordinate system to + # + # coord_build_plate_left = -1 + # | coord_build_plate_right = 1 + # v (0,1) v + # ┌───────┬───────┐ < coord_build_plate_back = -1 + # │ │ │ + # │ │(0,0) │ + # (-1,0)│───────o───────┤(1,0) + # │ │ │ + # │ │ │ + # └───────┴───────┘ < coord_build_plate_front = +1 + # (0,-1) + disc_x = ((x - self._build_volume_bounding_box.left) / self._build_volume_bounding_box.width) * 2.0 - 1.0 + disc_y = ((y - self._build_volume_bounding_box.back) / self._build_volume_bounding_box.depth) * 2.0 - 1.0 + return disc_x, disc_y + def drawDebugSvg(self): with open("Builvolume_test.svg", "w") as f: build_volume_bounding_box = self._build_volume_bounding_box @@ -145,25 +179,39 @@ class GridArrange: f.write( f"\n") - f.write( - f""" - - """) + ellipse = True + if ellipse: + f.write( + f""" + + """) + else: + f.write( + f""" + + """) - for grid_x in range(-10, 10): - for grid_y in range(-10, 10): + for grid_x in range(0, 100): + for grid_y in range(0, 100): # if (grid_x, grid_y) in intersecting_grid_idx: # fill_color = "red" # elif (grid_x, grid_y) in build_plate_grid_idx: # fill_color = "green" # else: # fill_color = "orange" + coord_grid_x, coord_grid_y = self.gridSpaceToCoordSpace(grid_x, grid_y) f.write( f""" @@ -172,12 +220,13 @@ class GridArrange: y="{coord_grid_y}" width="{self._grid_width}" height="{self._grid_height}" - fill="green" + fill="#ff00ff88" stroke="black" /> """) f.write(f""" @@ -208,4 +257,11 @@ class GridArrange: stroke-width="3" /> """) - f.write(f"") + + for x in range(math.floor(self._build_volume_bounding_box.left), math.floor(self._build_volume_bounding_box.right), 50): + for y in range(math.floor(self._build_volume_bounding_box.back), math.floor(self._build_volume_bounding_box.front), 50): + color = "green" if self.checkPointUnderDiscSpace(x, y) else "red" + f.write(f""" + + """) + f.write(f"") \ No newline at end of file diff --git a/cura/BuildVolume.py b/cura/BuildVolume.py index 0d6ecf5810..045156dcce 100755 --- a/cura/BuildVolume.py +++ b/cura/BuildVolume.py @@ -203,6 +203,9 @@ class BuildVolume(SceneNode): if shape: self._shape = shape + def getShape(self) -> str: + return self._shape + def getDiagonalSize(self) -> float: """Get the length of the 3D diagonal through the build volume. diff --git a/cura/CuraActions.py b/cura/CuraActions.py index bd5787de42..6e6e93e3ad 100644 --- a/cura/CuraActions.py +++ b/cura/CuraActions.py @@ -80,7 +80,7 @@ class CuraActions(QObject): center_y = 0 # Move the object so that it's bottom is on to of the buildplate - center_operation = TranslateOperation(current_node, Vector(0, center_y, 0), set_position=True) + center_operation = TranslateOperation(current_node, Vector(0, center_y, 0), set_position = True) operation.addOperation(center_operation) operation.push() @pyqtSlot(int) diff --git a/resources/qml/Actions.qml b/resources/qml/Actions.qml index 0701ba48ce..65888b3493 100644 --- a/resources/qml/Actions.qml +++ b/resources/qml/Actions.qml @@ -42,8 +42,6 @@ Item property alias reloadAll: reloadAllAction property alias arrangeAll: arrangeAllAction property alias arrangeAllGrid: arrangeAllGridAction - property alias arrangeSelection: arrangeSelectionAction - property alias arrangeSelectionLock: arrangeSelectionLockAction property alias resetAllTranslation: resetAllTranslationAction property alias resetAll: resetAllAction @@ -470,20 +468,6 @@ Item shortcut: "Shift+Ctrl+R" } - Action - { - id: arrangeSelectionAction - text: catalog.i18nc("@action:inmenu menubar:edit","Arrange Selection") - onTriggered: Printer.arrangeSelection(false) - } - - Action - { - id: arrangeSelectionLockAction - text: catalog.i18nc("@action:inmenu menubar:edit","Arrange Selection Without Rotation") - onTriggered: Printer.arrangeSelection(true) - } - Action { id: resetAllTranslationAction From 118f49a0520bdd1a3983bbf33b49c3ed8a645fb1 Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Wed, 23 Aug 2023 15:39:23 +0200 Subject: [PATCH 12/25] review comments fixed Co-authored-by: Casper Lamboo CURA-7951 --- cura/Arranging/ArrangeObjectsJob.py | 10 ++---- cura/Arranging/GridArrange.py | 39 +++++++++----------- cura/Arranging/Nest2DArrange.py | 56 ++++++++++++++++------------- cura/CuraActions.py | 4 +-- cura/CuraApplication.py | 13 ++++--- cura/MultiplyObjectsJob.py | 21 +++++------ resources/qml/Menus/ContextMenu.qml | 23 ++++++------ 7 files changed, 76 insertions(+), 90 deletions(-) diff --git a/cura/Arranging/ArrangeObjectsJob.py b/cura/Arranging/ArrangeObjectsJob.py index 4bb55bf660..0f8c576995 100644 --- a/cura/Arranging/ArrangeObjectsJob.py +++ b/cura/Arranging/ArrangeObjectsJob.py @@ -16,7 +16,7 @@ i18n_catalog = i18nCatalog("cura") class ArrangeObjectsJob(Job): def __init__(self, nodes: List[SceneNode], fixed_nodes: List[SceneNode], min_offset = 8, - grid_arrange: bool = False) -> None: + *, grid_arrange: bool = False) -> None: super().__init__() self._nodes = nodes self._fixed_nodes = fixed_nodes @@ -33,13 +33,7 @@ class ArrangeObjectsJob(Job): status_message.show() try: - - if self._grid_arrange: - grid_arrange = GridArrange(self._nodes, Application.getInstance().getBuildVolume(), self._fixed_nodes) - found_solution_for_all = grid_arrange.arrange() - - else: - found_solution_for_all = arrange(self._nodes, Application.getInstance().getBuildVolume(), self._fixed_nodes) + found_solution_for_all = arrange(self._nodes, Application.getInstance().getBuildVolume(), self._fixed_nodes, grid_arrange= self._grid_arrange) except: # If the thread crashes, the message should still close Logger.logException("e", "Unable to arrange the objects on the buildplate. The arrange algorithm has crashed.") diff --git a/cura/Arranging/GridArrange.py b/cura/Arranging/GridArrange.py index 5280843bd3..d8b7ba9db8 100644 --- a/cura/Arranging/GridArrange.py +++ b/cura/Arranging/GridArrange.py @@ -1,6 +1,11 @@ import math from typing import List, TYPE_CHECKING, Optional, Tuple, Set + + +if TYPE_CHECKING: + from UM.Scene.SceneNode import SceneNode + from UM.Application import Application from UM.Math import AxisAlignedBox from UM.Math.Vector import Vector @@ -10,23 +15,16 @@ from UM.Operations.TranslateOperation import TranslateOperation class GridArrange: - offset_x: float = 10 - offset_y: float = 10 - - _grid_width: float - _grid_height: float - - _nodes_to_arrange: List["SceneNode"] - _fixed_nodes: List["SceneNode"] - _build_volume: "BuildVolume" - _build_volume_bounding_box: AxisAlignedBox - - def __init__(self, nodes_to_arrange: List["SceneNode"], build_volume: "BuildVolume", fixed_nodes: List["SceneNode"] = []): + def __init__(self, nodes_to_arrange: List["SceneNode"], build_volume: "BuildVolume", fixed_nodes: List["SceneNode"] = None): + if fixed_nodes is None: + fixed_nodes = [] self._nodes_to_arrange = nodes_to_arrange self._build_volume = build_volume self._build_volume_bounding_box = build_volume.getBoundingBox() self._fixed_nodes = fixed_nodes + self._offset_x: float = 10 + self._offset_y: float = 10 self._grid_width = 0 self._grid_height = 0 for node in self._nodes_to_arrange: @@ -40,11 +38,6 @@ class GridArrange: self._initial_leftover_grid_x = math.floor(self._initial_leftover_grid_x) self._initial_leftover_grid_y = math.floor(self._initial_leftover_grid_y) - def arrange(self)-> bool: - grouped_operation, not_fit_count = self.createGroupOperationForArrange() - grouped_operation.push() - return not_fit_count == 0 - def createGroupOperationForArrange(self) -> Tuple[GroupedOperation, int]: # Find grid indexes that intersect with fixed objects fixed_nodes_grid_ids = set() @@ -96,8 +89,8 @@ class GridArrange: def moveNodeOnGrid(self, node: "SceneNode", grid_x: int, grid_y: int) -> "Operation.Operation": coord_grid_x, coord_grid_y = self.gridSpaceToCoordSpace(grid_x, grid_y) - center_grid_x = coord_grid_x + (0.5 * (self._grid_width + self.offset_x)) - center_grid_y = coord_grid_y + (0.5 * (self._grid_height + self.offset_y)) + center_grid_x = coord_grid_x + (0.5 * (self._grid_width + self._offset_x)) + center_grid_y = coord_grid_y + (0.5 * (self._grid_height + self._offset_y)) bounding_box = node.getBoundingBox() center_node_x = (bounding_box.left + bounding_box.right) * 0.5 @@ -134,13 +127,13 @@ class GridArrange: return grid_idx def gridSpaceToCoordSpace(self, x: float, y: float) -> Tuple[float, float]: - grid_x = x * (self._grid_width + self.offset_x) + self._build_volume_bounding_box.left - grid_y = y * (self._grid_height + self.offset_y) + self._build_volume_bounding_box.back + grid_x = x * (self._grid_width + self._offset_x) + self._build_volume_bounding_box.left + grid_y = y * (self._grid_height + self._offset_y) + self._build_volume_bounding_box.back return grid_x, grid_y def coordSpaceToGridSpace(self, grid_x: float, grid_y: float) -> Tuple[float, float]: - coord_x = (grid_x - self._build_volume_bounding_box.left) / (self._grid_width + self.offset_x) - coord_y = (grid_y - self._build_volume_bounding_box.back) / (self._grid_height + self.offset_y) + coord_x = (grid_x - self._build_volume_bounding_box.left) / (self._grid_width + self._offset_x) + coord_y = (grid_y - self._build_volume_bounding_box.back) / (self._grid_height + self._offset_y) return coord_x, coord_y def checkGridUnderDiscSpace(self, grid_x: int, grid_y: int) -> bool: diff --git a/cura/Arranging/Nest2DArrange.py b/cura/Arranging/Nest2DArrange.py index 8921c9ede2..b7422e3943 100644 --- a/cura/Arranging/Nest2DArrange.py +++ b/cura/Arranging/Nest2DArrange.py @@ -15,7 +15,7 @@ from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation from UM.Operations.GroupedOperation import GroupedOperation from UM.Operations.RotateOperation import RotateOperation from UM.Operations.TranslateOperation import TranslateOperation - +from cura.Arranging.GridArrange import GridArrange if TYPE_CHECKING: from UM.Scene.SceneNode import SceneNode @@ -27,6 +27,7 @@ def findNodePlacement( build_volume: "BuildVolume", fixed_nodes: Optional[List["SceneNode"]] = None, factor: int = 10000, + *, lock_rotation: bool = False ) -> Tuple[bool, List[Item]]: """ @@ -124,30 +125,36 @@ def createGroupOperationForArrange(nodes_to_arrange: List["SceneNode"], build_volume: "BuildVolume", fixed_nodes: Optional[List["SceneNode"]] = None, factor: int = 10000, + *, add_new_nodes_in_scene: bool = False, - lock_rotation: bool = False) -> Tuple[GroupedOperation, int]: - scene_root = Application.getInstance().getController().getScene().getRoot() - found_solution_for_all, node_items = findNodePlacement(nodes_to_arrange, build_volume, fixed_nodes, factor, - lock_rotation) + lock_rotation: bool = False, + grid_arrange: bool = False) -> Tuple[GroupedOperation, int]: + if grid_arrange: + grid = GridArrange(nodes_to_arrange, build_volume, fixed_nodes) + return grid.createGroupOperationForArrange() + else: + scene_root = Application.getInstance().getController().getScene().getRoot() + found_solution_for_all, node_items = findNodePlacement(nodes_to_arrange, build_volume, fixed_nodes, factor, + lock_rotation = lock_rotation) - not_fit_count = 0 - grouped_operation = GroupedOperation() - for node, node_item in zip(nodes_to_arrange, node_items): - if add_new_nodes_in_scene: - grouped_operation.addOperation(AddSceneNodeOperation(node, scene_root)) + not_fit_count = 0 + grouped_operation = GroupedOperation() + for node, node_item in zip(nodes_to_arrange, node_items): + if add_new_nodes_in_scene: + grouped_operation.addOperation(AddSceneNodeOperation(node, scene_root)) - if node_item.binId() == 0: - # We found a spot for it - rotation_matrix = Matrix() - rotation_matrix.setByRotationAxis(node_item.rotation(), Vector(0, -1, 0)) - grouped_operation.addOperation(RotateOperation(node, Quaternion.fromMatrix(rotation_matrix))) - grouped_operation.addOperation(TranslateOperation(node, Vector(node_item.translation().x() / factor, 0, - node_item.translation().y() / factor))) - else: - # We didn't find a spot - grouped_operation.addOperation( - TranslateOperation(node, Vector(200, node.getWorldPosition().y, -not_fit_count * 20), set_position = True)) - not_fit_count += 1 + if node_item.binId() == 0: + # We found a spot for it + rotation_matrix = Matrix() + rotation_matrix.setByRotationAxis(node_item.rotation(), Vector(0, -1, 0)) + grouped_operation.addOperation(RotateOperation(node, Quaternion.fromMatrix(rotation_matrix))) + grouped_operation.addOperation(TranslateOperation(node, Vector(node_item.translation().x() / factor, 0, + node_item.translation().y() / factor))) + else: + # We didn't find a spot + grouped_operation.addOperation( + TranslateOperation(node, Vector(200, node.getWorldPosition().y, -not_fit_count * 20), set_position = True)) + not_fit_count += 1 return grouped_operation, not_fit_count @@ -158,7 +165,8 @@ def arrange( fixed_nodes: Optional[List["SceneNode"]] = None, factor=10000, add_new_nodes_in_scene: bool = False, - lock_rotation: bool = False + lock_rotation: bool = False, + grid_arrange: bool = False ) -> bool: """ Find placement for a set of scene nodes, and move them by using a single grouped operation. @@ -174,6 +182,6 @@ def arrange( """ grouped_operation, not_fit_count = createGroupOperationForArrange(nodes_to_arrange, build_volume, fixed_nodes, - factor, add_new_nodes_in_scene, lock_rotation) + factor, add_new_nodes_in_scene = add_new_nodes_in_scene, lock_rotation = lock_rotation, grid_arrange = grid_arrange) grouped_operation.push() return not_fit_count == 0 diff --git a/cura/CuraActions.py b/cura/CuraActions.py index 6e6e93e3ad..dc18497191 100644 --- a/cura/CuraActions.py +++ b/cura/CuraActions.py @@ -18,7 +18,6 @@ from UM.Operations.RemoveSceneNodeOperation import RemoveSceneNodeOperation from UM.Operations.TranslateOperation import TranslateOperation import cura.CuraApplication -from cura.Arranging.GridArrange import GridArrange from cura.Operations.SetParentOperation import SetParentOperation from cura.MultiplyObjectsJob import MultiplyObjectsJob from cura.Settings.SetObjectExtruderOperation import SetObjectExtruderOperation @@ -239,8 +238,7 @@ class CuraActions(QObject): if node.callDecoration("isSliceable"): fixed_nodes.append(node) # Add the new nodes to the scene, and arrange them - grid_arrange = GridArrange(nodes, application.getBuildVolume(), fixed_nodes) - group_operation, not_fit_count = grid_arrange.createGroupOperationForArrange() + group_operation, not_fit_count = createGroupOperationForArrange(nodes, application.getBuildVolume(), fixed_nodes, grid_arrange = True) group_operation.push() # deselect currently selected nodes, and select the new nodes diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index a9517c966c..fb4b4cc5d6 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -1442,13 +1442,13 @@ class CuraApplication(QtApplication): # Single build plate @pyqtSlot() def arrangeAll(self) -> None: - self._arrangeAll(False) + self._arrangeAll(grid_arrangement = False) @pyqtSlot() def arrangeAllInGrid(self) -> None: - self._arrangeAll(True) + self._arrangeAll(grid_arrangement = True) - def _arrangeAll(self, grid_arrangement: bool) -> None: + def _arrangeAll(self, *, grid_arrangement: bool) -> None: nodes_to_arrange = [] active_build_plate = self.getMultiBuildPlateModel().activeBuildPlate locked_nodes = [] @@ -1478,18 +1478,17 @@ class CuraApplication(QtApplication): locked_nodes.append(node) else: nodes_to_arrange.append(node) - self.arrange(nodes_to_arrange, locked_nodes, grid_arrangement) + self.arrange(nodes_to_arrange, locked_nodes, grid_arrangement = grid_arrangement) - def arrange(self, nodes: List[SceneNode], fixed_nodes: List[SceneNode], grid_arrangement: bool = False) -> None: + def arrange(self, nodes: List[SceneNode], fixed_nodes: List[SceneNode], *, grid_arrangement: bool = False) -> None: """Arrange a set of nodes given a set of fixed nodes :param nodes: nodes that we have to place :param fixed_nodes: nodes that are placed in the arranger before finding spots for nodes :param grid_arrangement: If set to true if objects are to be placed in a grid """ - min_offset = self.getBuildVolume().getEdgeDisallowedSize() + 2 # Allow for some rounding errors - job = ArrangeObjectsJob(nodes, fixed_nodes, min_offset=max(min_offset, 8), grid_arrange =grid_arrangement) + job = ArrangeObjectsJob(nodes, fixed_nodes, min_offset = max(min_offset, 8), grid_arrange = grid_arrangement) job.start() @pyqtSlot() diff --git a/cura/MultiplyObjectsJob.py b/cura/MultiplyObjectsJob.py index 6df80eb01c..3864b94427 100644 --- a/cura/MultiplyObjectsJob.py +++ b/cura/MultiplyObjectsJob.py @@ -14,14 +14,13 @@ from UM.Operations.TranslateOperation import TranslateOperation from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator from UM.Scene.SceneNode import SceneNode from UM.i18n import i18nCatalog -from cura.Arranging.GridArrange import GridArrange -from cura.Arranging.Nest2DArrange import arrange, createGroupOperationForArrange +from cura.Arranging.Nest2DArrange import createGroupOperationForArrange i18n_catalog = i18nCatalog("cura") class MultiplyObjectsJob(Job): - def __init__(self, objects, count: int, min_offset: int = 8, grid_arrange: bool = False): + def __init__(self, objects, count: int, min_offset: int = 8 ,* , grid_arrange: bool = False): super().__init__() self._objects = objects self._count: int = count @@ -78,16 +77,12 @@ class MultiplyObjectsJob(Job): found_solution_for_all = True group_operation = GroupedOperation() if nodes: - if(self._grid_arrange): - grid_arrange = GridArrange(nodes,Application.getInstance().getBuildVolume(),fixed_nodes) - group_operation, not_fit_count = grid_arrange.createGroupOperationForArrange() - - else: - group_operation, not_fit_count = createGroupOperationForArrange(nodes, - Application.getInstance().getBuildVolume(), - fixed_nodes, - factor=10000, - add_new_nodes_in_scene=True) + group_operation, not_fit_count = createGroupOperationForArrange(nodes, + Application.getInstance().getBuildVolume(), + fixed_nodes, + factor=10000, + add_new_nodes_in_scene=True, + grid_arrange=self._grid_arrange) if nodes_to_add_without_arrange: for nested_node in nodes_to_add_without_arrange: diff --git a/resources/qml/Menus/ContextMenu.qml b/resources/qml/Menus/ContextMenu.qml index a095fb6e1a..2de2795a74 100644 --- a/resources/qml/Menus/ContextMenu.qml +++ b/resources/qml/Menus/ContextMenu.qml @@ -109,18 +109,7 @@ Cura.Menu height: UM.Theme.getSize("small_popup_dialog").height minimumWidth: UM.Theme.getSize("small_popup_dialog").width minimumHeight: UM.Theme.getSize("small_popup_dialog").height - - onAccepted: { - if (gridPlacementSelected.checked) - { - CuraActions.multiplySelectionToGrid(copiesField.value) - } - else - { - CuraActions.multiplySelection(copiesField.value) - } - } - + onAccepted: gridPlacementSelected.checked? CuraActions.multiplySelectionToGrid(copiesField.value) : CuraActions.multiplySelection(copiesField.value) buttonSpacing: UM.Theme.getSize("thin_margin").width rightButtons: @@ -169,7 +158,17 @@ Cura.Menu { id: gridPlacementSelected text: catalog.i18nc("@label", "Grid Placement") + + UM.ToolTip + { + visible: parent.hovered + targetPoint: Qt.point(parent.x + Math.round(parent.width / 2), parent.y) + x: 0 + y: parent.y + parent.height + UM.Theme.getSize("default_margin").height + tooltipText: catalog.i18nc("@info", "Multiply selected item and place them in a grid of build plate.") + } } + } } } From 668038c59f420843b166690486c698d79c957da6 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Wed, 23 Aug 2023 17:58:00 +0200 Subject: [PATCH 13/25] Implement factory for Arrange CURA-7951 --- cura/Arranging/ArrangeObjectsJob.py | 10 +- cura/Arranging/Arranger.py | 27 ++++ cura/Arranging/GridArrange.py | 12 +- cura/Arranging/Nest2DArrange.py | 228 ++++++++++++---------------- cura/CuraActions.py | 9 +- cura/CuraApplication.py | 1 - cura/MultiplyObjectsJob.py | 15 +- 7 files changed, 152 insertions(+), 150 deletions(-) create mode 100644 cura/Arranging/Arranger.py diff --git a/cura/Arranging/ArrangeObjectsJob.py b/cura/Arranging/ArrangeObjectsJob.py index 0f8c576995..b1e0432786 100644 --- a/cura/Arranging/ArrangeObjectsJob.py +++ b/cura/Arranging/ArrangeObjectsJob.py @@ -9,7 +9,7 @@ from UM.Message import Message from UM.Scene.SceneNode import SceneNode from UM.i18n import i18nCatalog from cura.Arranging.GridArrange import GridArrange -from cura.Arranging.Nest2DArrange import arrange +from cura.Arranging.Nest2DArrange import Nest2DArrange i18n_catalog = i18nCatalog("cura") @@ -33,7 +33,13 @@ class ArrangeObjectsJob(Job): status_message.show() try: - found_solution_for_all = arrange(self._nodes, Application.getInstance().getBuildVolume(), self._fixed_nodes, grid_arrange= self._grid_arrange) + if self._grid_arrange: + arranger = GridArrange(self._nodes, Application.getInstance().getBuildVolume(), self._fixed_nodes) + else: + arranger = Nest2DArrange(self._nodes, Application.getInstance().getBuildVolume(), self._fixed_nodes, + factor=1000) + + found_solution_for_all = arranger.arrange() except: # If the thread crashes, the message should still close Logger.logException("e", "Unable to arrange the objects on the buildplate. The arrange algorithm has crashed.") diff --git a/cura/Arranging/Arranger.py b/cura/Arranging/Arranger.py new file mode 100644 index 0000000000..684fa1258b --- /dev/null +++ b/cura/Arranging/Arranger.py @@ -0,0 +1,27 @@ +from typing import List, TYPE_CHECKING, Optional, Tuple, Set + +if TYPE_CHECKING: + from UM.Operations.GroupedOperation import GroupedOperation + + +class Arranger: + def createGroupOperationForArrange(self, add_new_nodes_in_scene: bool = True) -> Tuple["GroupedOperation", int]: + """ + Find placement for a set of scene nodes, but don't actually move them just yet. + :param add_new_nodes_in_scene: Whether to create new scene nodes before applying the transformations and rotations + :return: tuple (found_solution_for_all, node_items) + WHERE + found_solution_for_all: Whether the algorithm found a place on the buildplate for all the objects + node_items: A list of the nodes return by libnest2d, which contain the new positions on the buildplate + """ + raise NotImplementedError + + def arrange(self, add_new_nodes_in_scene: bool = True) -> bool: + """ + Find placement for a set of scene nodes, and move them by using a single grouped operation. + :param add_new_nodes_in_scene: Whether to create new scene nodes before applying the transformations and rotations + :return: found_solution_for_all: Whether the algorithm found a place on the buildplate for all the objects + """ + grouped_operation, not_fit_count = self.createGroupOperationForArrange(add_new_nodes_in_scene) + grouped_operation.push() + return not_fit_count == 0 diff --git a/cura/Arranging/GridArrange.py b/cura/Arranging/GridArrange.py index d8b7ba9db8..4866e99b69 100644 --- a/cura/Arranging/GridArrange.py +++ b/cura/Arranging/GridArrange.py @@ -1,8 +1,6 @@ import math from typing import List, TYPE_CHECKING, Optional, Tuple, Set - - if TYPE_CHECKING: from UM.Scene.SceneNode import SceneNode @@ -12,9 +10,10 @@ from UM.Math.Vector import Vector from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation from UM.Operations.GroupedOperation import GroupedOperation from UM.Operations.TranslateOperation import TranslateOperation +from cura.Arranging.Arranger import Arranger -class GridArrange: +class GridArrange(Arranger): def __init__(self, nodes_to_arrange: List["SceneNode"], build_volume: "BuildVolume", fixed_nodes: List["SceneNode"] = None): if fixed_nodes is None: fixed_nodes = [] @@ -38,7 +37,7 @@ class GridArrange: self._initial_leftover_grid_x = math.floor(self._initial_leftover_grid_x) self._initial_leftover_grid_y = math.floor(self._initial_leftover_grid_y) - def createGroupOperationForArrange(self) -> Tuple[GroupedOperation, int]: + def createGroupOperationForArrange(self, add_new_nodes_in_scene: bool = True) -> Tuple[GroupedOperation, int]: # Find grid indexes that intersect with fixed objects fixed_nodes_grid_ids = set() for node in self._fixed_nodes: @@ -77,7 +76,8 @@ class GridArrange: left_over_grid_y = self._initial_leftover_grid_y for node in leftover_nodes: - grouped_operation.addOperation(AddSceneNodeOperation(node, scene_root)) + if add_new_nodes_in_scene: + grouped_operation.addOperation(AddSceneNodeOperation(node, scene_root)) # find the first next grid position that isn't occupied by a fixed node while (self._initial_leftover_grid_x, left_over_grid_y) in fixed_nodes_grid_ids: left_over_grid_y = left_over_grid_y - 1 @@ -156,7 +156,7 @@ class GridArrange: # ┌───────┬───────┐ < coord_build_plate_back = -1 # │ │ │ # │ │(0,0) │ - # (-1,0)│───────o───────┤(1,0) + # (-1,0)├───────o───────┤(1,0) # │ │ │ # │ │ │ # └───────┴───────┘ < coord_build_plate_front = +1 diff --git a/cura/Arranging/Nest2DArrange.py b/cura/Arranging/Nest2DArrange.py index b7422e3943..ea45fe0b8e 100644 --- a/cura/Arranging/Nest2DArrange.py +++ b/cura/Arranging/Nest2DArrange.py @@ -15,131 +15,122 @@ from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation from UM.Operations.GroupedOperation import GroupedOperation from UM.Operations.RotateOperation import RotateOperation from UM.Operations.TranslateOperation import TranslateOperation -from cura.Arranging.GridArrange import GridArrange +from cura.Arranging.Arranger import Arranger if TYPE_CHECKING: from UM.Scene.SceneNode import SceneNode from cura.BuildVolume import BuildVolume -def findNodePlacement( - nodes_to_arrange: List["SceneNode"], - build_volume: "BuildVolume", - fixed_nodes: Optional[List["SceneNode"]] = None, - factor: int = 10000, - *, - lock_rotation: bool = False -) -> Tuple[bool, List[Item]]: - """ - Find placement for a set of scene nodes, but don't actually move them just yet. - :param nodes_to_arrange: The list of nodes that need to be moved. - :param build_volume: The build volume that we want to place the nodes in. It gets size & disallowed areas from this. - :param fixed_nodes: List of nods that should not be moved, but should be used when deciding where the others nodes - are placed. - :param factor: The library that we use is int based. This factor defines how accurate we want it to be. - :param lock_rotation: If set to true the orientation of the object will remain the same +class Nest2DArrange(Arranger): + def __init__(self, + nodes_to_arrange: List["SceneNode"], + build_volume: "BuildVolume", + fixed_nodes: Optional[List["SceneNode"]] = None, + *, + factor: int = 10000, + lock_rotation: bool = False): + """ + :param nodes_to_arrange: The list of nodes that need to be moved. + :param build_volume: The build volume that we want to place the nodes in. It gets size & disallowed areas from this. + :param fixed_nodes: List of nods that should not be moved, but should be used when deciding where the others nodes + are placed. + :param factor: The library that we use is int based. This factor defines how accuracte we want it to be. + :param lock_rotation: If set to true the orientation of the object will remain the same + """ + super().__init__() + self._nodes_to_arrange = nodes_to_arrange + self._build_volume = build_volume + self._fixed_nodes = fixed_nodes + self._factor = factor + self._lock_rotation = lock_rotation - :return: tuple (found_solution_for_all, node_items) - WHERE - found_solution_for_all: Whether the algorithm found a place on the buildplate for all the objects - node_items: A list of the nodes return by libnest2d, which contain the new positions on the buildplate - """ - spacing = int(1.5 * factor) # 1.5mm spacing. + def findNodePlacement(self) -> Tuple[bool, List[Item]]: + spacing = int(1.5 * self._factor) # 1.5mm spacing. - machine_width = build_volume.getWidth() - machine_depth = build_volume.getDepth() - build_plate_bounding_box = Box(int(machine_width * factor), int(machine_depth * factor)) + machine_width = self._build_volume.getWidth() + machine_depth = self._build_volume.getDepth() + build_plate_bounding_box = Box(int(machine_width * self._factor), int(machine_depth * self._factor)) - if fixed_nodes is None: - fixed_nodes = [] + if self._fixed_nodes is None: + self._fixed_nodes = [] - # Add all the items we want to arrange - node_items = [] - for node in nodes_to_arrange: - hull_polygon = node.callDecoration("getConvexHull") - if not hull_polygon or hull_polygon.getPoints is None: - Logger.log("w", "Object {} cannot be arranged because it has no convex hull.".format(node.getName())) - continue - converted_points = [] - for point in hull_polygon.getPoints(): - converted_points.append(Point(int(point[0] * factor), int(point[1] * factor))) - item = Item(converted_points) - node_items.append(item) - - # Use a tiny margin for the build_plate_polygon (the nesting doesn't like overlapping disallowed areas) - half_machine_width = 0.5 * machine_width - 1 - half_machine_depth = 0.5 * machine_depth - 1 - build_plate_polygon = Polygon(numpy.array([ - [half_machine_width, -half_machine_depth], - [-half_machine_width, -half_machine_depth], - [-half_machine_width, half_machine_depth], - [half_machine_width, half_machine_depth] - ], numpy.float32)) - - disallowed_areas = build_volume.getDisallowedAreas() - num_disallowed_areas_added = 0 - for area in disallowed_areas: - converted_points = [] - - # Clip the disallowed areas so that they don't overlap the bounding box (The arranger chokes otherwise) - clipped_area = area.intersectionConvexHulls(build_plate_polygon) - - if clipped_area.getPoints() is not None and len(clipped_area.getPoints()) > 2: # numpy array has to be explicitly checked against None - for point in clipped_area.getPoints(): - converted_points.append(Point(int(point[0] * factor), int(point[1] * factor))) - - disallowed_area = Item(converted_points) - disallowed_area.markAsDisallowedAreaInBin(0) - node_items.append(disallowed_area) - num_disallowed_areas_added += 1 - - for node in fixed_nodes: - converted_points = [] - hull_polygon = node.callDecoration("getConvexHull") - - if hull_polygon is not None and hull_polygon.getPoints() is not None and len(hull_polygon.getPoints()) > 2: # numpy array has to be explicitly checked against None + # Add all the items we want to arrange + node_items = [] + for node in self._nodes_to_arrange: + hull_polygon = node.callDecoration("getConvexHull") + if not hull_polygon or hull_polygon.getPoints is None: + Logger.log("w", "Object {} cannot be arranged because it has no convex hull.".format(node.getName())) + continue + converted_points = [] for point in hull_polygon.getPoints(): - converted_points.append(Point(int(point[0] * factor), int(point[1] * factor))) + converted_points.append(Point(int(point[0] * self._factor), int(point[1] * self._factor))) item = Item(converted_points) - item.markAsFixedInBin(0) node_items.append(item) - num_disallowed_areas_added += 1 - config = NfpConfig() - config.accuracy = 1.0 - config.alignment = NfpConfig.Alignment.DONT_ALIGN - if lock_rotation: - config.rotations = [0.0] + # Use a tiny margin for the build_plate_polygon (the nesting doesn't like overlapping disallowed areas) + half_machine_width = 0.5 * machine_width - 1 + half_machine_depth = 0.5 * machine_depth - 1 + build_plate_polygon = Polygon(numpy.array([ + [half_machine_width, -half_machine_depth], + [-half_machine_width, -half_machine_depth], + [-half_machine_width, half_machine_depth], + [half_machine_width, half_machine_depth] + ], numpy.float32)) - num_bins = nest(node_items, build_plate_bounding_box, spacing, config) + disallowed_areas = self._build_volume.getDisallowedAreas() + num_disallowed_areas_added = 0 + for area in disallowed_areas: + converted_points = [] - # Strip the fixed items (previously placed) and the disallowed areas from the results again. - node_items = list(filter(lambda item: not item.isFixed(), node_items)) + # Clip the disallowed areas so that they don't overlap the bounding box (The arranger chokes otherwise) + clipped_area = area.intersectionConvexHulls(build_plate_polygon) - found_solution_for_all = num_bins == 1 + if clipped_area.getPoints() is not None and len( + clipped_area.getPoints()) > 2: # numpy array has to be explicitly checked against None + for point in clipped_area.getPoints(): + converted_points.append(Point(int(point[0] * self._factor), int(point[1] * self._factor))) - return found_solution_for_all, node_items + disallowed_area = Item(converted_points) + disallowed_area.markAsDisallowedAreaInBin(0) + node_items.append(disallowed_area) + num_disallowed_areas_added += 1 + for node in self._fixed_nodes: + converted_points = [] + hull_polygon = node.callDecoration("getConvexHull") -def createGroupOperationForArrange(nodes_to_arrange: List["SceneNode"], - build_volume: "BuildVolume", - fixed_nodes: Optional[List["SceneNode"]] = None, - factor: int = 10000, - *, - add_new_nodes_in_scene: bool = False, - lock_rotation: bool = False, - grid_arrange: bool = False) -> Tuple[GroupedOperation, int]: - if grid_arrange: - grid = GridArrange(nodes_to_arrange, build_volume, fixed_nodes) - return grid.createGroupOperationForArrange() - else: + if hull_polygon is not None and hull_polygon.getPoints() is not None and len( + hull_polygon.getPoints()) > 2: # numpy array has to be explicitly checked against None + for point in hull_polygon.getPoints(): + converted_points.append(Point(int(point[0] * self._factor), int(point[1] * self._factor))) + item = Item(converted_points) + item.markAsFixedInBin(0) + node_items.append(item) + num_disallowed_areas_added += 1 + + config = NfpConfig() + config.accuracy = 1.0 + config.alignment = NfpConfig.Alignment.DONT_ALIGN + if self._lock_rotation: + config.rotations = [0.0] + + num_bins = nest(node_items, build_plate_bounding_box, spacing, config) + + # Strip the fixed items (previously placed) and the disallowed areas from the results again. + node_items = list(filter(lambda item: not item.isFixed(), node_items)) + + found_solution_for_all = num_bins == 1 + + return found_solution_for_all, node_items + + def createGroupOperationForArrange(self, add_new_nodes_in_scene: bool = True) -> Tuple[GroupedOperation, int]: scene_root = Application.getInstance().getController().getScene().getRoot() - found_solution_for_all, node_items = findNodePlacement(nodes_to_arrange, build_volume, fixed_nodes, factor, - lock_rotation = lock_rotation) + found_solution_for_all, node_items = self.findNodePlacement() not_fit_count = 0 grouped_operation = GroupedOperation() - for node, node_item in zip(nodes_to_arrange, node_items): + for node, node_item in zip(self._nodes_to_arrange, node_items): if add_new_nodes_in_scene: grouped_operation.addOperation(AddSceneNodeOperation(node, scene_root)) @@ -148,40 +139,13 @@ def createGroupOperationForArrange(nodes_to_arrange: List["SceneNode"], rotation_matrix = Matrix() rotation_matrix.setByRotationAxis(node_item.rotation(), Vector(0, -1, 0)) grouped_operation.addOperation(RotateOperation(node, Quaternion.fromMatrix(rotation_matrix))) - grouped_operation.addOperation(TranslateOperation(node, Vector(node_item.translation().x() / factor, 0, - node_item.translation().y() / factor))) + grouped_operation.addOperation( + TranslateOperation(node, Vector(node_item.translation().x() / self._factor, 0, + node_item.translation().y() / self._factor))) else: # We didn't find a spot grouped_operation.addOperation( TranslateOperation(node, Vector(200, node.getWorldPosition().y, -not_fit_count * 20), set_position = True)) not_fit_count += 1 - return grouped_operation, not_fit_count - - -def arrange( - nodes_to_arrange: List["SceneNode"], - build_volume: "BuildVolume", - fixed_nodes: Optional[List["SceneNode"]] = None, - factor=10000, - add_new_nodes_in_scene: bool = False, - lock_rotation: bool = False, - grid_arrange: bool = False -) -> bool: - """ - Find placement for a set of scene nodes, and move them by using a single grouped operation. - :param nodes_to_arrange: The list of nodes that need to be moved. - :param build_volume: The build volume that we want to place the nodes in. It gets size & disallowed areas from this. - :param fixed_nodes: List of nods that should not be moved, but should be used when deciding where the others nodes - are placed. - :param factor: The library that we use is int based. This factor defines how accuracte we want it to be. - :param add_new_nodes_in_scene: Whether to create new scene nodes before applying the transformations and rotations - :param lock_rotation: If set to true the orientation of the object will remain the same - - :return: found_solution_for_all: Whether the algorithm found a place on the buildplate for all the objects - """ - - grouped_operation, not_fit_count = createGroupOperationForArrange(nodes_to_arrange, build_volume, fixed_nodes, - factor, add_new_nodes_in_scene = add_new_nodes_in_scene, lock_rotation = lock_rotation, grid_arrange = grid_arrange) - grouped_operation.push() - return not_fit_count == 0 + return grouped_operation, not_fit_count diff --git a/cura/CuraActions.py b/cura/CuraActions.py index dc18497191..29f50d88b2 100644 --- a/cura/CuraActions.py +++ b/cura/CuraActions.py @@ -22,7 +22,10 @@ from cura.Operations.SetParentOperation import SetParentOperation from cura.MultiplyObjectsJob import MultiplyObjectsJob from cura.Settings.SetObjectExtruderOperation import SetObjectExtruderOperation from cura.Settings.ExtruderManager import ExtruderManager -from cura.Arranging.Nest2DArrange import createGroupOperationForArrange + +from cura.Arranging.GridArrange import GridArrange +from cura.Arranging.Nest2DArrange import Nest2DArrange + from cura.Operations.SetBuildPlateNumberOperation import SetBuildPlateNumberOperation @@ -238,7 +241,9 @@ class CuraActions(QObject): if node.callDecoration("isSliceable"): fixed_nodes.append(node) # Add the new nodes to the scene, and arrange them - group_operation, not_fit_count = createGroupOperationForArrange(nodes, application.getBuildVolume(), fixed_nodes, grid_arrange = True) + + arranger = GridArrange(nodes, application.getBuildVolume(), fixed_nodes) + group_operation, not_fit_count = arranger.createGroupOperationForArrange() group_operation.push() # deselect currently selected nodes, and select the new nodes diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index fb4b4cc5d6..54b717b3d0 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -54,7 +54,6 @@ from cura import ApplicationMetadata from cura.API import CuraAPI from cura.API.Account import Account from cura.Arranging.ArrangeObjectsJob import ArrangeObjectsJob -from cura.Arranging.Nest2DArrange import arrange from cura.Machines.MachineErrorChecker import MachineErrorChecker from cura.Machines.Models.BuildPlateModel import BuildPlateModel from cura.Machines.Models.CustomQualityProfilesDropDownMenuModel import CustomQualityProfilesDropDownMenuModel diff --git a/cura/MultiplyObjectsJob.py b/cura/MultiplyObjectsJob.py index 3864b94427..889b6f5d1a 100644 --- a/cura/MultiplyObjectsJob.py +++ b/cura/MultiplyObjectsJob.py @@ -14,7 +14,8 @@ from UM.Operations.TranslateOperation import TranslateOperation from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator from UM.Scene.SceneNode import SceneNode from UM.i18n import i18nCatalog -from cura.Arranging.Nest2DArrange import createGroupOperationForArrange +from cura.Arranging.GridArrange import GridArrange +from cura.Arranging.Nest2DArrange import Nest2DArrange i18n_catalog = i18nCatalog("cura") @@ -77,12 +78,12 @@ class MultiplyObjectsJob(Job): found_solution_for_all = True group_operation = GroupedOperation() if nodes: - group_operation, not_fit_count = createGroupOperationForArrange(nodes, - Application.getInstance().getBuildVolume(), - fixed_nodes, - factor=10000, - add_new_nodes_in_scene=True, - grid_arrange=self._grid_arrange) + if self._grid_arrange: + arranger = GridArrange(nodes, Application.getInstance().getBuildVolume(), fixed_nodes) + else: + arranger = Nest2DArrange(nodes, Application.getInstance().getBuildVolume(), fixed_nodes, factor=1000) + + group_operation, not_fit_count = arranger.createGroupOperationForArrange(add_new_nodes_in_scene=True) if nodes_to_add_without_arrange: for nested_node in nodes_to_add_without_arrange: From f67a6970ddd5a189f148fbf45377d56ba3af89e9 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Thu, 24 Aug 2023 08:33:59 +0200 Subject: [PATCH 14/25] Find optimal offset for grid arrange CURA-7951 --- cura/Arranging/GridArrange.py | 243 ++++++++++++++++++++++++---------- 1 file changed, 170 insertions(+), 73 deletions(-) diff --git a/cura/Arranging/GridArrange.py b/cura/Arranging/GridArrange.py index 4866e99b69..82ce7bc224 100644 --- a/cura/Arranging/GridArrange.py +++ b/cura/Arranging/GridArrange.py @@ -1,11 +1,11 @@ import math -from typing import List, TYPE_CHECKING, Optional, Tuple, Set +from typing import List, TYPE_CHECKING, Tuple, Set if TYPE_CHECKING: from UM.Scene.SceneNode import SceneNode + from cura.BuildVolume import BuildVolume from UM.Application import Application -from UM.Math import AxisAlignedBox from UM.Math.Vector import Vector from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation from UM.Operations.GroupedOperation import GroupedOperation @@ -22,14 +22,25 @@ class GridArrange(Arranger): self._build_volume_bounding_box = build_volume.getBoundingBox() self._fixed_nodes = fixed_nodes - self._offset_x: float = 10 - self._offset_y: float = 10 + self._margin_x: float = 1 + self._margin_y: float = 1 + self._grid_width = 0 self._grid_height = 0 for node in self._nodes_to_arrange: bounding_box = node.getBoundingBox() self._grid_width = max(self._grid_width, bounding_box.width) self._grid_height = max(self._grid_height, bounding_box.depth) + self._grid_width += self._margin_x + self._grid_height += self._margin_y + + # Round up the grid size to the nearest cm + self._grid_width = math.ceil(self._grid_width / 10) * 10 + self._grid_height = math.ceil(self._grid_height / 10) * 10 + + self._offset_x = 0 + self._offset_y = 0 + self._findOptimalGridOffset() coord_initial_leftover_x = self._build_volume_bounding_box.right + 2 * self._grid_width coord_initial_leftover_y = (self._build_volume_bounding_box.back + self._build_volume_bounding_box.front) * 0.5 @@ -37,39 +48,38 @@ class GridArrange(Arranger): self._initial_leftover_grid_x = math.floor(self._initial_leftover_grid_x) self._initial_leftover_grid_y = math.floor(self._initial_leftover_grid_y) - def createGroupOperationForArrange(self, add_new_nodes_in_scene: bool = True) -> Tuple[GroupedOperation, int]: # Find grid indexes that intersect with fixed objects - fixed_nodes_grid_ids = set() + self._fixed_nodes_grid_ids = set() for node in self._fixed_nodes: - fixed_nodes_grid_ids = fixed_nodes_grid_ids.union(self.intersectingGridIdxInclusive(node.getBoundingBox())) + self._fixed_nodes_grid_ids = self._fixed_nodes_grid_ids.union( + self.intersectingGridIdxInclusive(node.getBoundingBox())) - build_plate_grid_ids = self.intersectingGridIdxExclusive(self._build_volume_bounding_box) + self._build_plate_grid_ids = self.intersectingGridIdxExclusive(self._build_volume_bounding_box) # Filter out the corner grid squares if the build plate shape is elliptic if self._build_volume.getShape() == "elliptic": - build_plate_grid_ids = set(filter(lambda grid_id: self.checkGridUnderDiscSpace(grid_id[0], grid_id[1]), build_plate_grid_ids)) + self._build_plate_grid_ids = set( + filter(lambda grid_id: self.checkGridUnderDiscSpace(grid_id[0], grid_id[1]), + self._build_plate_grid_ids)) - allowed_grid_idx = build_plate_grid_ids.difference(fixed_nodes_grid_ids) + self._allowed_grid_idx = self._build_plate_grid_ids.difference(self._fixed_nodes_grid_ids) + def createGroupOperationForArrange(self, add_new_nodes_in_scene: bool = True) -> Tuple[GroupedOperation, int]: # Find the sequence in which items are placed coord_build_plate_center_x = self._build_volume_bounding_box.width * 0.5 + self._build_volume_bounding_box.left coord_build_plate_center_y = self._build_volume_bounding_box.depth * 0.5 + self._build_volume_bounding_box.back grid_build_plate_center_x, grid_build_plate_center_y = self.coordSpaceToGridSpace(coord_build_plate_center_x, coord_build_plate_center_y) - def distToCenter(grid_id: Tuple[int, int]) -> float: - grid_x, grid_y = grid_id - distance_squared = (grid_build_plate_center_x - grid_x) ** 2 + (grid_build_plate_center_y - grid_y) ** 2 - return distance_squared - - sequence: List[Tuple[int, int]] = list(allowed_grid_idx) - sequence.sort(key=distToCenter) + sequence: List[Tuple[int, int]] = list(self._allowed_grid_idx) + sequence.sort(key=lambda grid_id: (grid_build_plate_center_x - grid_id[0]) ** 2 + ( + grid_build_plate_center_y - grid_id[1]) ** 2) scene_root = Application.getInstance().getController().getScene().getRoot() grouped_operation = GroupedOperation() for grid_id, node in zip(sequence, self._nodes_to_arrange): grouped_operation.addOperation(AddSceneNodeOperation(node, scene_root)) grid_x, grid_y = grid_id - operation = self.moveNodeOnGrid(node, grid_x, grid_y) + operation = self._moveNodeOnGrid(node, grid_x, grid_y) grouped_operation.addOperation(operation) leftover_nodes = self._nodes_to_arrange[len(sequence):] @@ -79,18 +89,103 @@ class GridArrange(Arranger): if add_new_nodes_in_scene: grouped_operation.addOperation(AddSceneNodeOperation(node, scene_root)) # find the first next grid position that isn't occupied by a fixed node - while (self._initial_leftover_grid_x, left_over_grid_y) in fixed_nodes_grid_ids: + while (self._initial_leftover_grid_x, left_over_grid_y) in self._fixed_nodes_grid_ids: left_over_grid_y = left_over_grid_y - 1 - operation = self.moveNodeOnGrid(node, self._initial_leftover_grid_x, left_over_grid_y) + operation = self._moveNodeOnGrid(node, self._initial_leftover_grid_x, left_over_grid_y) grouped_operation.addOperation(operation) left_over_grid_y = left_over_grid_y - 1 + return grouped_operation, len(leftover_nodes) - def moveNodeOnGrid(self, node: "SceneNode", grid_x: int, grid_y: int) -> "Operation.Operation": - coord_grid_x, coord_grid_y = self.gridSpaceToCoordSpace(grid_x, grid_y) - center_grid_x = coord_grid_x + (0.5 * (self._grid_width + self._offset_x)) - center_grid_y = coord_grid_y + (0.5 * (self._grid_height + self._offset_y)) + def _findOptimalGridOffset(self): + if len(self._fixed_nodes) == 0: + self._offset_x = 0 + self._offset_y = 0 + return + + if len(self._fixed_nodes) == 1: + center_grid_x = 0.5 * self._grid_width + self._build_volume_bounding_box.left + center_grid_y = 0.5 * self._grid_height + self._build_volume_bounding_box.back + + bounding_box = self._fixed_nodes[0].getBoundingBox() + center_node_x = (bounding_box.left + bounding_box.right) * 0.5 + center_node_y = (bounding_box.back + bounding_box.front) * 0.5 + + self._offset_x = center_node_x - center_grid_x + self._offset_y = center_node_y - center_grid_y + + return + + class Event: + def __init__(self, coord: float, change: float): + self.coord = coord + self.change = change + + events_horizontal: List[Event] = [] + events_vertical: List[Event] = [] + + for node in self._fixed_nodes: + bounding_box = node.getBoundingBox() + + left = bounding_box.left - self._build_volume_bounding_box.left + right = bounding_box.right - self._build_volume_bounding_box.left + back = bounding_box.back - self._build_volume_bounding_box.back + front = bounding_box.front - self._build_volume_bounding_box.back + + value_left = math.ceil(left / self._grid_width) * self._grid_width - left + value_right = math.ceil(right / self._grid_width) * self._grid_width - right + value_back = math.ceil(back / self._grid_height) * self._grid_height - back + value_front = math.ceil(front / self._grid_height) * self._grid_height - front + + # give nodes a weight according to their size. This + # weight is heuristically chosen to be proportional to + # the number of grid squares the node-boundary occupies + weight = bounding_box.width + bounding_box.depth + + events_horizontal.append(Event(value_left, weight)) + events_horizontal.append(Event(value_right, -weight)) + events_vertical.append(Event(value_back, weight)) + events_vertical.append(Event(value_front, -weight)) + + events_horizontal.sort(key=lambda event: event.coord) + events_vertical.sort(key=lambda event: event.coord) + + def findOptimalOffsetAxis(events: List[Event], interval: float) -> float: + prev_coord = events[-1].coord - interval + + current_offset = 0 + + best_offset = float('inf') + best_coord_length = float('-inf') + best_coord = 0.0 + + for event in events: + coord_length = event.coord - prev_coord + + if current_offset < best_offset or (current_offset == best_offset and coord_length > best_coord_length): + best_offset = current_offset + best_coord_length = coord_length + best_coord = event.coord + + current_offset += event.change + prev_coord = event.coord + + return best_coord - best_coord_length * 0.5 + + center_grid_x = 0.5 * self._grid_width + center_grid_y = 0.5 * self._grid_height + + optimal_center_x = self._grid_width - findOptimalOffsetAxis(events_horizontal, self._grid_width) + optimal_center_y = self._grid_height - findOptimalOffsetAxis(events_vertical, self._grid_height) + + self._offset_x = optimal_center_x - center_grid_x + self._offset_y = optimal_center_y - center_grid_y + + def _moveNodeOnGrid(self, node: "SceneNode", grid_x: int, grid_y: int) -> "Operation.Operation": + coord_grid_x, coord_grid_y = self._gridSpaceToCoordSpace(grid_x, grid_y) + center_grid_x = coord_grid_x + (0.5 * self._grid_width) + center_grid_y = coord_grid_y + (0.5 * self._grid_height) bounding_box = node.getBoundingBox() center_node_x = (bounding_box.left + bounding_box.right) * 0.5 @@ -101,7 +196,7 @@ class GridArrange(Arranger): return TranslateOperation(node, Vector(delta_x, 0, delta_y)) - def getGridCornerPoints(self, bounding_box: "BoundingVolume") -> Tuple[float, float, float, float]: + def _getGridCornerPoints(self, bounding_box: "BoundingVolume") -> Tuple[float, float, float, float]: coord_x1 = bounding_box.left coord_x2 = bounding_box.right coord_y1 = bounding_box.back @@ -111,7 +206,7 @@ class GridArrange(Arranger): return grid_x1, grid_y1, grid_x2, grid_y2 def intersectingGridIdxInclusive(self, bounding_box: "BoundingVolume") -> Set[Tuple[int, int]]: - grid_x1, grid_y1, grid_x2, grid_y2 = self.getGridCornerPoints(bounding_box) + grid_x1, grid_y1, grid_x2, grid_y2 = self._getGridCornerPoints(bounding_box) grid_idx = set() for grid_x in range(math.floor(grid_x1), math.ceil(grid_x2)): for grid_y in range(math.floor(grid_y1), math.ceil(grid_y2)): @@ -119,26 +214,26 @@ class GridArrange(Arranger): return grid_idx def intersectingGridIdxExclusive(self, bounding_box: "BoundingVolume") -> Set[Tuple[int, int]]: - grid_x1, grid_y1, grid_x2, grid_y2 = self.getGridCornerPoints(bounding_box) + grid_x1, grid_y1, grid_x2, grid_y2 = self._getGridCornerPoints(bounding_box) grid_idx = set() for grid_x in range(math.ceil(grid_x1), math.floor(grid_x2)): for grid_y in range(math.ceil(grid_y1), math.floor(grid_y2)): grid_idx.add((grid_x, grid_y)) return grid_idx - def gridSpaceToCoordSpace(self, x: float, y: float) -> Tuple[float, float]: - grid_x = x * (self._grid_width + self._offset_x) + self._build_volume_bounding_box.left - grid_y = y * (self._grid_height + self._offset_y) + self._build_volume_bounding_box.back + def _gridSpaceToCoordSpace(self, x: float, y: float) -> Tuple[float, float]: + grid_x = x * self._grid_width + self._build_volume_bounding_box.left + self._offset_x + grid_y = y * self._grid_height + self._build_volume_bounding_box.back + self._offset_y return grid_x, grid_y def coordSpaceToGridSpace(self, grid_x: float, grid_y: float) -> Tuple[float, float]: - coord_x = (grid_x - self._build_volume_bounding_box.left) / (self._grid_width + self._offset_x) - coord_y = (grid_y - self._build_volume_bounding_box.back) / (self._grid_height + self._offset_y) + coord_x = (grid_x - self._build_volume_bounding_box.left - self._offset_x) / self._grid_width + coord_y = (grid_y - self._build_volume_bounding_box.back - self._offset_y) / self._grid_height return coord_x, coord_y def checkGridUnderDiscSpace(self, grid_x: int, grid_y: int) -> bool: - left, back = self.gridSpaceToCoordSpace(grid_x, grid_y) - right, front = self.gridSpaceToCoordSpace(grid_x + 1, grid_y + 1) + left, back = self._gridSpaceToCoordSpace(grid_x, grid_y) + right, front = self._gridSpaceToCoordSpace(grid_x + 1, grid_y + 1) corners = [(left, back), (right, back), (right, front), (left, front)] return all([self.checkPointUnderDiscSpace(x, y) for x, y in corners]) @@ -165,15 +260,14 @@ class GridArrange(Arranger): disc_y = ((y - self._build_volume_bounding_box.back) / self._build_volume_bounding_box.depth) * 2.0 - 1.0 return disc_x, disc_y - def drawDebugSvg(self): + def _drawDebugSvg(self): with open("Builvolume_test.svg", "w") as f: build_volume_bounding_box = self._build_volume_bounding_box f.write( f"\n") - ellipse = True - if ellipse: + if self._build_volume.getShape() == "elliptic": f.write( f""" """) else: @@ -196,30 +290,32 @@ class GridArrange(Arranger): /> """) - for grid_x in range(0, 100): - for grid_y in range(0, 100): - # if (grid_x, grid_y) in intersecting_grid_idx: - # fill_color = "red" - # elif (grid_x, grid_y) in build_plate_grid_idx: - # fill_color = "green" - # else: - # fill_color = "orange" + for grid_x in range(-10, 10): + for grid_y in range(-10, 10): + if (grid_x, grid_y) in self._allowed_grid_idx: + fill_color = "rgba(0, 255, 0, 0.5)" + elif (grid_x, grid_y) in self._build_plate_grid_ids: + fill_color = "rgba(255, 165, 0, 0.5)" + else: + fill_color = "rgba(255, 0, 0, 0.5)" - coord_grid_x, coord_grid_y = self.gridSpaceToCoordSpace(grid_x, grid_y) + coord_grid_x, coord_grid_y = self._gridSpaceToCoordSpace(grid_x, grid_y) f.write( f""" """) f.write(f""" @@ -237,24 +333,25 @@ class GridArrange(Arranger): fill="red" /> """) - for node in self._nodes_to_arrange: - bounding_box = node.getBoundingBox() - f.write(f""" - - """) - for x in range(math.floor(self._build_volume_bounding_box.left), math.floor(self._build_volume_bounding_box.right), 50): - for y in range(math.floor(self._build_volume_bounding_box.back), math.floor(self._build_volume_bounding_box.front), 50): - color = "green" if self.checkPointUnderDiscSpace(x, y) else "red" - f.write(f""" - - """) - f.write(f"") \ No newline at end of file + f.write(f""" + """) + + # coord_build_plate_center_x = self._build_volume_bounding_box.width * 0.5 + self._build_volume_bounding_box.left + # coord_build_plate_center_y = self._build_volume_bounding_box.depth * 0.5 + self._build_volume_bounding_box.back + # f.write(f""" + # """) + + f.write(f"") From 719b11655ce3e002f04b065439ae3e80ab4e5d73 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Thu, 24 Aug 2023 11:24:21 +0200 Subject: [PATCH 15/25] Fix ctrl+z issues CURA-7951` --- cura/Arranging/Arranger.py | 4 ++-- cura/Arranging/GridArrange.py | 2 +- cura/Arranging/Nest2DArrange.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cura/Arranging/Arranger.py b/cura/Arranging/Arranger.py index 684fa1258b..fd93ab1846 100644 --- a/cura/Arranging/Arranger.py +++ b/cura/Arranging/Arranger.py @@ -5,7 +5,7 @@ if TYPE_CHECKING: class Arranger: - def createGroupOperationForArrange(self, add_new_nodes_in_scene: bool = True) -> Tuple["GroupedOperation", int]: + def createGroupOperationForArrange(self, add_new_nodes_in_scene: bool = False) -> Tuple["GroupedOperation", int]: """ Find placement for a set of scene nodes, but don't actually move them just yet. :param add_new_nodes_in_scene: Whether to create new scene nodes before applying the transformations and rotations @@ -16,7 +16,7 @@ class Arranger: """ raise NotImplementedError - def arrange(self, add_new_nodes_in_scene: bool = True) -> bool: + def arrange(self, add_new_nodes_in_scene: bool = False) -> bool: """ Find placement for a set of scene nodes, and move them by using a single grouped operation. :param add_new_nodes_in_scene: Whether to create new scene nodes before applying the transformations and rotations diff --git a/cura/Arranging/GridArrange.py b/cura/Arranging/GridArrange.py index 4866e99b69..9c7f0d31fb 100644 --- a/cura/Arranging/GridArrange.py +++ b/cura/Arranging/GridArrange.py @@ -37,7 +37,7 @@ class GridArrange(Arranger): self._initial_leftover_grid_x = math.floor(self._initial_leftover_grid_x) self._initial_leftover_grid_y = math.floor(self._initial_leftover_grid_y) - def createGroupOperationForArrange(self, add_new_nodes_in_scene: bool = True) -> Tuple[GroupedOperation, int]: + def createGroupOperationForArrange(self, add_new_nodes_in_scene: bool = False) -> Tuple[GroupedOperation, int]: # Find grid indexes that intersect with fixed objects fixed_nodes_grid_ids = set() for node in self._fixed_nodes: diff --git a/cura/Arranging/Nest2DArrange.py b/cura/Arranging/Nest2DArrange.py index ea45fe0b8e..bad57c5045 100644 --- a/cura/Arranging/Nest2DArrange.py +++ b/cura/Arranging/Nest2DArrange.py @@ -124,7 +124,7 @@ class Nest2DArrange(Arranger): return found_solution_for_all, node_items - def createGroupOperationForArrange(self, add_new_nodes_in_scene: bool = True) -> Tuple[GroupedOperation, int]: + def createGroupOperationForArrange(self, add_new_nodes_in_scene: bool = False) -> Tuple[GroupedOperation, int]: scene_root = Application.getInstance().getController().getScene().getRoot() found_solution_for_all, node_items = self.findNodePlacement() From 1591a2a0c37cd8dc7a443a6f14101ddbf6e605af Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Thu, 24 Aug 2023 11:48:43 +0200 Subject: [PATCH 16/25] ctrl+z for grid CURA-7951 --- cura/Arranging/GridArrange.py | 3 ++- cura/CuraActions.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cura/Arranging/GridArrange.py b/cura/Arranging/GridArrange.py index 9c7f0d31fb..c430de4d73 100644 --- a/cura/Arranging/GridArrange.py +++ b/cura/Arranging/GridArrange.py @@ -67,7 +67,8 @@ class GridArrange(Arranger): grouped_operation = GroupedOperation() for grid_id, node in zip(sequence, self._nodes_to_arrange): - grouped_operation.addOperation(AddSceneNodeOperation(node, scene_root)) + if add_new_nodes_in_scene: + grouped_operation.addOperation(AddSceneNodeOperation(node, scene_root)) grid_x, grid_y = grid_id operation = self.moveNodeOnGrid(node, grid_x, grid_y) grouped_operation.addOperation(operation) diff --git a/cura/CuraActions.py b/cura/CuraActions.py index 29f50d88b2..9a61a1c4f0 100644 --- a/cura/CuraActions.py +++ b/cura/CuraActions.py @@ -243,7 +243,7 @@ class CuraActions(QObject): # Add the new nodes to the scene, and arrange them arranger = GridArrange(nodes, application.getBuildVolume(), fixed_nodes) - group_operation, not_fit_count = arranger.createGroupOperationForArrange() + group_operation, not_fit_count = arranger.createGroupOperationForArrange(add_new_nodes_in_scene = True) group_operation.push() # deselect currently selected nodes, and select the new nodes From ac78de1227329a35b259cf76a391012cc0699ffc Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Thu, 24 Aug 2023 11:55:07 +0200 Subject: [PATCH 17/25] Updated comments CURA-7951 --- cura/Arranging/GridArrange.py | 69 ++++++++++++++++++++++++++--------- 1 file changed, 52 insertions(+), 17 deletions(-) diff --git a/cura/Arranging/GridArrange.py b/cura/Arranging/GridArrange.py index 23c14e248b..3b00f44ddc 100644 --- a/cura/Arranging/GridArrange.py +++ b/cura/Arranging/GridArrange.py @@ -118,11 +118,40 @@ class GridArrange(Arranger): return + # If there are multiple fixed nodes, an optimal solution is not always possible + # We will try to find an offset that minimizes the number of grid intersections + # with fixed nodes. The algorithm below achieves this by utilizing a scanline + # algorithm. In this algorithm each axis is solved separately as offsetting + # is completely independent in each axis. The comments explaining the algorithm + # below are for the x-axis, but the same applies for the y-axis. + # + # Each node either occupies ceil((node.right - node.right) / grid_width) or + # ceil((node.right - node.right) / grid_width) + 1 grid squares. We will call + # these the node's "footprint". + # + # ┌────────────────┐ + # minimum food print │ NODE │ + # └────────────────┘ + # │ grid 1 │ grid 2 │ grid 3 │ grid 4 | grid 5 | + # ┌────────────────┐ + # maximum food print │ NODE │ + # └────────────────┘ + # + # The algorithm will find the grid offset such that the number of nodes with + # a _minimal_ footprint is _maximized_. + + # The scanline algorithm works as follows, we create events for both end points + # of each node's footprint. The event have two properties, + # - the coordinate: the amount the endpoint can move to the + # left before it crosses a grid line + # - the change: either +1 or -1, indicating whether crossing the grid line + # would result in a minimal footprint node becoming a maximal footprint class Event: def __init__(self, coord: float, change: float): self.coord = coord self.change = change + # create events for both the horizontal and vertical axis events_horizontal: List[Event] = [] events_vertical: List[Event] = [] @@ -152,33 +181,39 @@ class GridArrange(Arranger): events_horizontal.sort(key=lambda event: event.coord) events_vertical.sort(key=lambda event: event.coord) - def findOptimalOffsetAxis(events: List[Event], interval: float) -> float: - prev_coord = events[-1].coord - interval + def findOptimalShiftAxis(events: List[Event], interval: float) -> float: + # executing the actual scanline algorithm + # iteratively go through events (left to right) and keep track of the + # current footprint. The optimal location is the one with the minimal + # footprint. If there are multiple locations with the same minimal + # footprint, the optimal location is the one with the largest range + # between the left and right endpoint of the footprint. + prev_offset = events[-1].coord - interval + current_minimal_footprint_count = 0 - current_offset = 0 - - best_offset = float('inf') - best_coord_length = float('-inf') - best_coord = 0.0 + best_minimal_footprint_count = float('inf') + best_offset_span = float('-inf') + best_offset = 0.0 for event in events: - coord_length = event.coord - prev_coord + offset_span = event.coord - prev_offset - if current_offset < best_offset or (current_offset == best_offset and coord_length > best_coord_length): - best_offset = current_offset - best_coord_length = coord_length - best_coord = event.coord + if current_minimal_footprint_count < best_minimal_footprint_count or ( + current_minimal_footprint_count == best_minimal_footprint_count and offset_span > best_offset_span): + best_minimal_footprint_count = current_minimal_footprint_count + best_offset_span = offset_span + best_offset = event.coord - current_offset += event.change - prev_coord = event.coord + current_minimal_footprint_count += event.change + prev_offset = event.coord - return best_coord - best_coord_length * 0.5 + return best_offset - best_offset_span * 0.5 center_grid_x = 0.5 * self._grid_width center_grid_y = 0.5 * self._grid_height - optimal_center_x = self._grid_width - findOptimalOffsetAxis(events_horizontal, self._grid_width) - optimal_center_y = self._grid_height - findOptimalOffsetAxis(events_vertical, self._grid_height) + optimal_center_x = self._grid_width - findOptimalShiftAxis(events_horizontal, self._grid_width) + optimal_center_y = self._grid_height - findOptimalShiftAxis(events_vertical, self._grid_height) self._offset_x = optimal_center_x - center_grid_x self._offset_y = optimal_center_y - center_grid_y From 34aa631531c55bf2e3b24e9ddb6bead061011f19 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Thu, 24 Aug 2023 16:13:39 +0200 Subject: [PATCH 18/25] Re-add arrange to CuraApplication CURA-7951 --- cura/CuraApplication.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cura/CuraApplication.py b/cura/CuraApplication.py index 54b717b3d0..5f2770c3a2 100755 --- a/cura/CuraApplication.py +++ b/cura/CuraApplication.py @@ -114,6 +114,7 @@ from . import CameraAnimation from . import CuraActions from . import PlatformPhysics from . import PrintJobPreviewImageProvider +from .Arranging.Nest2DArrange import Nest2DArrange from .AutoSave import AutoSave from .Machines.Models.CompatibleMachineModel import CompatibleMachineModel from .Machines.Models.MachineListModel import MachineListModel @@ -1974,7 +1975,8 @@ class CuraApplication(QtApplication): if select_models_on_load: Selection.add(node) try: - arrange(nodes_to_arrange, self.getBuildVolume(), fixed_nodes) + arranger = Nest2DArrange(nodes_to_arrange, self.getBuildVolume(), fixed_nodes) + arranger.arrange() except: Logger.logException("e", "Failed to arrange the models") From e8c06ec7838efc89c0c17f30c67be6c02700d7ae Mon Sep 17 00:00:00 2001 From: "saumya.jain" Date: Thu, 24 Aug 2023 16:34:34 +0200 Subject: [PATCH 19/25] grid arrange adjusted for disallowed area CURA-7951 --- cura/Arranging/GridArrange.py | 52 +++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/cura/Arranging/GridArrange.py b/cura/Arranging/GridArrange.py index 3b00f44ddc..a049c20c82 100644 --- a/cura/Arranging/GridArrange.py +++ b/cura/Arranging/GridArrange.py @@ -54,6 +54,11 @@ class GridArrange(Arranger): self._fixed_nodes_grid_ids = self._fixed_nodes_grid_ids.union( self.intersectingGridIdxInclusive(node.getBoundingBox())) + #grid indexes that are in disallowed area + for polygon in self._build_volume.getDisallowedAreas(): + self._fixed_nodes_grid_ids = self._fixed_nodes_grid_ids.union( + self._getIntersectingGridIdForPolygon(polygon)) + self._build_plate_grid_ids = self.intersectingGridIdxExclusive(self._build_volume_bounding_box) # Filter out the corner grid squares if the build plate shape is elliptic @@ -241,6 +246,32 @@ class GridArrange(Arranger): grid_x2, grid_y2 = self.coordSpaceToGridSpace(coord_x2, coord_y2) return grid_x1, grid_y1, grid_x2, grid_y2 + def _getIntersectingGridIdForPolygon(self, polygon)-> Set[Tuple[int, int]]: + # (x0, y0) + # | + # v + # ┌─────────────┐ + # │ │ + # │ │ + # └─────────────┘ < (x1, y1) + x0 = float('inf') + y0 = float('inf') + x1 = float('-inf') + y1 = float('-inf') + grid_idx = set() + for [x, y] in polygon.getPoints(): + x0 = min(x0, x) + y0 = min(y0, y) + x1 = max(x1, x) + y1 = max(y1, y) + grid_x1, grid_y1 = self.coordSpaceToGridSpace(x0, y0) + grid_x2, grid_y2 = self.coordSpaceToGridSpace(x1, y1) + + for grid_x in range(math.floor(grid_x1), math.ceil(grid_x2)): + for grid_y in range(math.floor(grid_y1), math.ceil(grid_y2)): + grid_idx.add((grid_x, grid_y)) + return grid_idx + def intersectingGridIdxInclusive(self, bounding_box: "BoundingVolume") -> Set[Tuple[int, int]]: grid_x1, grid_y1, grid_x2, grid_y2 = self._getGridCornerPoints(bounding_box) grid_idx = set() @@ -326,8 +357,25 @@ class GridArrange(Arranger): /> """) - for grid_x in range(-10, 10): - for grid_y in range(-10, 10): + for polygon in self._build_volume.getDisallowedAreas(): + # Extract individual points and convert them to tuples + + path_data = "" + for [x,y] in polygon.getPoints(): + path_data += f"{x},{y} " + + f.write( + f""" + + """) + + for grid_x in range(-10, 100): + for grid_y in range(-10, 100): if (grid_x, grid_y) in self._allowed_grid_idx: fill_color = "rgba(0, 255, 0, 0.5)" elif (grid_x, grid_y) in self._build_plate_grid_ids: From cfc4db00a533dafd5237e26de488e58c192e4482 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Wed, 30 Aug 2023 12:41:53 +0200 Subject: [PATCH 20/25] Use descriptive variable name instead of magic number CURA-7951 --- cura/Arranging/GridArrange.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cura/Arranging/GridArrange.py b/cura/Arranging/GridArrange.py index a049c20c82..d046114fab 100644 --- a/cura/Arranging/GridArrange.py +++ b/cura/Arranging/GridArrange.py @@ -35,8 +35,9 @@ class GridArrange(Arranger): self._grid_height += self._margin_y # Round up the grid size to the nearest cm - self._grid_width = math.ceil(self._grid_width / 10) * 10 - self._grid_height = math.ceil(self._grid_height / 10) * 10 + grid_precision = 10 # 1cm + self._grid_width = math.ceil(self._grid_width / grid_precision) * grid_precision + self._grid_height = math.ceil(self._grid_height / grid_precision) * grid_precision self._offset_x = 0 self._offset_y = 0 From b3b5ffbf5530ed21b351aaf2ea0e70234d0c0148 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Wed, 30 Aug 2023 12:45:34 +0200 Subject: [PATCH 21/25] Put try catch around actual arranging `arrange` is the function that _could_ fail CURA-7951 --- cura/Arranging/ArrangeObjectsJob.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/cura/Arranging/ArrangeObjectsJob.py b/cura/Arranging/ArrangeObjectsJob.py index b1e0432786..48d2436482 100644 --- a/cura/Arranging/ArrangeObjectsJob.py +++ b/cura/Arranging/ArrangeObjectsJob.py @@ -32,17 +32,18 @@ class ArrangeObjectsJob(Job): title = i18n_catalog.i18nc("@info:title", "Finding Location")) status_message.show() + if self._grid_arrange: + arranger = GridArrange(self._nodes, Application.getInstance().getBuildVolume(), self._fixed_nodes) + else: + arranger = Nest2DArrange(self._nodes, Application.getInstance().getBuildVolume(), self._fixed_nodes, + factor=1000) + + found_solution_for_all = False try: - if self._grid_arrange: - arranger = GridArrange(self._nodes, Application.getInstance().getBuildVolume(), self._fixed_nodes) - else: - arranger = Nest2DArrange(self._nodes, Application.getInstance().getBuildVolume(), self._fixed_nodes, - factor=1000) - found_solution_for_all = arranger.arrange() - except: # If the thread crashes, the message should still close - Logger.logException("e", "Unable to arrange the objects on the buildplate. The arrange algorithm has crashed.") + Logger.logException("e", + "Unable to arrange the objects on the buildplate. The arrange algorithm has crashed.") status_message.hide() From 38a5754c6fd9b32a5fe080eb225367eac51b5452 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Wed, 30 Aug 2023 12:47:56 +0200 Subject: [PATCH 22/25] Mark method functions as private CURA-7951 --- cura/Arranging/GridArrange.py | 36 ++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/cura/Arranging/GridArrange.py b/cura/Arranging/GridArrange.py index d046114fab..d2eace3c26 100644 --- a/cura/Arranging/GridArrange.py +++ b/cura/Arranging/GridArrange.py @@ -45,7 +45,8 @@ class GridArrange(Arranger): coord_initial_leftover_x = self._build_volume_bounding_box.right + 2 * self._grid_width coord_initial_leftover_y = (self._build_volume_bounding_box.back + self._build_volume_bounding_box.front) * 0.5 - self._initial_leftover_grid_x, self._initial_leftover_grid_y = self.coordSpaceToGridSpace(coord_initial_leftover_x, coord_initial_leftover_y) + self._initial_leftover_grid_x, self._initial_leftover_grid_y = self._coordSpaceToGridSpace( + coord_initial_leftover_x, coord_initial_leftover_y) self._initial_leftover_grid_x = math.floor(self._initial_leftover_grid_x) self._initial_leftover_grid_y = math.floor(self._initial_leftover_grid_y) @@ -53,19 +54,19 @@ class GridArrange(Arranger): self._fixed_nodes_grid_ids = set() for node in self._fixed_nodes: self._fixed_nodes_grid_ids = self._fixed_nodes_grid_ids.union( - self.intersectingGridIdxInclusive(node.getBoundingBox())) + self._intersectingGridIdxInclusive(node.getBoundingBox())) #grid indexes that are in disallowed area for polygon in self._build_volume.getDisallowedAreas(): self._fixed_nodes_grid_ids = self._fixed_nodes_grid_ids.union( self._getIntersectingGridIdForPolygon(polygon)) - self._build_plate_grid_ids = self.intersectingGridIdxExclusive(self._build_volume_bounding_box) + self._build_plate_grid_ids = self._intersectingGridIdxExclusive(self._build_volume_bounding_box) # Filter out the corner grid squares if the build plate shape is elliptic if self._build_volume.getShape() == "elliptic": self._build_plate_grid_ids = set( - filter(lambda grid_id: self.checkGridUnderDiscSpace(grid_id[0], grid_id[1]), + filter(lambda grid_id: self._checkGridUnderDiscSpace(grid_id[0], grid_id[1]), self._build_plate_grid_ids)) self._allowed_grid_idx = self._build_plate_grid_ids.difference(self._fixed_nodes_grid_ids) @@ -74,7 +75,8 @@ class GridArrange(Arranger): # Find the sequence in which items are placed coord_build_plate_center_x = self._build_volume_bounding_box.width * 0.5 + self._build_volume_bounding_box.left coord_build_plate_center_y = self._build_volume_bounding_box.depth * 0.5 + self._build_volume_bounding_box.back - grid_build_plate_center_x, grid_build_plate_center_y = self.coordSpaceToGridSpace(coord_build_plate_center_x, coord_build_plate_center_y) + grid_build_plate_center_x, grid_build_plate_center_y = self._coordSpaceToGridSpace(coord_build_plate_center_x, + coord_build_plate_center_y) sequence: List[Tuple[int, int]] = list(self._allowed_grid_idx) sequence.sort(key=lambda grid_id: (grid_build_plate_center_x - grid_id[0]) ** 2 + ( @@ -243,8 +245,8 @@ class GridArrange(Arranger): coord_x2 = bounding_box.right coord_y1 = bounding_box.back coord_y2 = bounding_box.front - grid_x1, grid_y1 = self.coordSpaceToGridSpace(coord_x1, coord_y1) - grid_x2, grid_y2 = self.coordSpaceToGridSpace(coord_x2, coord_y2) + grid_x1, grid_y1 = self._coordSpaceToGridSpace(coord_x1, coord_y1) + grid_x2, grid_y2 = self._coordSpaceToGridSpace(coord_x2, coord_y2) return grid_x1, grid_y1, grid_x2, grid_y2 def _getIntersectingGridIdForPolygon(self, polygon)-> Set[Tuple[int, int]]: @@ -265,15 +267,15 @@ class GridArrange(Arranger): y0 = min(y0, y) x1 = max(x1, x) y1 = max(y1, y) - grid_x1, grid_y1 = self.coordSpaceToGridSpace(x0, y0) - grid_x2, grid_y2 = self.coordSpaceToGridSpace(x1, y1) + grid_x1, grid_y1 = self._coordSpaceToGridSpace(x0, y0) + grid_x2, grid_y2 = self._coordSpaceToGridSpace(x1, y1) for grid_x in range(math.floor(grid_x1), math.ceil(grid_x2)): for grid_y in range(math.floor(grid_y1), math.ceil(grid_y2)): grid_idx.add((grid_x, grid_y)) return grid_idx - def intersectingGridIdxInclusive(self, bounding_box: "BoundingVolume") -> Set[Tuple[int, int]]: + def _intersectingGridIdxInclusive(self, bounding_box: "BoundingVolume") -> Set[Tuple[int, int]]: grid_x1, grid_y1, grid_x2, grid_y2 = self._getGridCornerPoints(bounding_box) grid_idx = set() for grid_x in range(math.floor(grid_x1), math.ceil(grid_x2)): @@ -281,7 +283,7 @@ class GridArrange(Arranger): grid_idx.add((grid_x, grid_y)) return grid_idx - def intersectingGridIdxExclusive(self, bounding_box: "BoundingVolume") -> Set[Tuple[int, int]]: + def _intersectingGridIdxExclusive(self, bounding_box: "BoundingVolume") -> Set[Tuple[int, int]]: grid_x1, grid_y1, grid_x2, grid_y2 = self._getGridCornerPoints(bounding_box) grid_idx = set() for grid_x in range(math.ceil(grid_x1), math.floor(grid_x2)): @@ -294,23 +296,23 @@ class GridArrange(Arranger): grid_y = y * self._grid_height + self._build_volume_bounding_box.back + self._offset_y return grid_x, grid_y - def coordSpaceToGridSpace(self, grid_x: float, grid_y: float) -> Tuple[float, float]: + def _coordSpaceToGridSpace(self, grid_x: float, grid_y: float) -> Tuple[float, float]: coord_x = (grid_x - self._build_volume_bounding_box.left - self._offset_x) / self._grid_width coord_y = (grid_y - self._build_volume_bounding_box.back - self._offset_y) / self._grid_height return coord_x, coord_y - def checkGridUnderDiscSpace(self, grid_x: int, grid_y: int) -> bool: + def _checkGridUnderDiscSpace(self, grid_x: int, grid_y: int) -> bool: left, back = self._gridSpaceToCoordSpace(grid_x, grid_y) right, front = self._gridSpaceToCoordSpace(grid_x + 1, grid_y + 1) corners = [(left, back), (right, back), (right, front), (left, front)] - return all([self.checkPointUnderDiscSpace(x, y) for x, y in corners]) + return all([self._checkPointUnderDiscSpace(x, y) for x, y in corners]) - def checkPointUnderDiscSpace(self, x: float, y: float) -> bool: - disc_x, disc_y = self.coordSpaceToDiscSpace(x, y) + def _checkPointUnderDiscSpace(self, x: float, y: float) -> bool: + disc_x, disc_y = self._coordSpaceToDiscSpace(x, y) distance_to_center_squared = disc_x ** 2 + disc_y ** 2 return distance_to_center_squared <= 1.0 - def coordSpaceToDiscSpace(self, x: float, y: float) -> Tuple[float, float]: + def _coordSpaceToDiscSpace(self, x: float, y: float) -> Tuple[float, float]: # Transform coordinate system to # # coord_build_plate_left = -1 From 3e39bbdabd9f154dc6754d23c01006ad5a6cfd08 Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Wed, 30 Aug 2023 12:51:03 +0200 Subject: [PATCH 23/25] Typo CURA-7951 --- cura/Arranging/GridArrange.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cura/Arranging/GridArrange.py b/cura/Arranging/GridArrange.py index d2eace3c26..8a4606e3f3 100644 --- a/cura/Arranging/GridArrange.py +++ b/cura/Arranging/GridArrange.py @@ -138,11 +138,11 @@ class GridArrange(Arranger): # these the node's "footprint". # # ┌────────────────┐ - # minimum food print │ NODE │ + # minimum foot-print │ NODE │ # └────────────────┘ # │ grid 1 │ grid 2 │ grid 3 │ grid 4 | grid 5 | # ┌────────────────┐ - # maximum food print │ NODE │ + # maximum foot-print │ NODE │ # └────────────────┘ # # The algorithm will find the grid offset such that the number of nodes with From afc1ba78f5cf239a035a85ea25aff7efd63de7bf Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Wed, 30 Aug 2023 12:52:27 +0200 Subject: [PATCH 24/25] Remove debugging utility function CURA-7951 --- cura/Arranging/GridArrange.py | 113 ---------------------------------- 1 file changed, 113 deletions(-) diff --git a/cura/Arranging/GridArrange.py b/cura/Arranging/GridArrange.py index 8a4606e3f3..95ce2c7190 100644 --- a/cura/Arranging/GridArrange.py +++ b/cura/Arranging/GridArrange.py @@ -329,116 +329,3 @@ class GridArrange(Arranger): disc_x = ((x - self._build_volume_bounding_box.left) / self._build_volume_bounding_box.width) * 2.0 - 1.0 disc_y = ((y - self._build_volume_bounding_box.back) / self._build_volume_bounding_box.depth) * 2.0 - 1.0 return disc_x, disc_y - - def _drawDebugSvg(self): - with open("Builvolume_test.svg", "w") as f: - build_volume_bounding_box = self._build_volume_bounding_box - - f.write( - f"\n") - - if self._build_volume.getShape() == "elliptic": - f.write( - f""" - - """) - else: - f.write( - f""" - - """) - - for polygon in self._build_volume.getDisallowedAreas(): - # Extract individual points and convert them to tuples - - path_data = "" - for [x,y] in polygon.getPoints(): - path_data += f"{x},{y} " - - f.write( - f""" - - """) - - for grid_x in range(-10, 100): - for grid_y in range(-10, 100): - if (grid_x, grid_y) in self._allowed_grid_idx: - fill_color = "rgba(0, 255, 0, 0.5)" - elif (grid_x, grid_y) in self._build_plate_grid_ids: - fill_color = "rgba(255, 165, 0, 0.5)" - else: - fill_color = "rgba(255, 0, 0, 0.5)" - - coord_grid_x, coord_grid_y = self._gridSpaceToCoordSpace(grid_x, grid_y) - f.write( - f""" - - """) - f.write(f""" - - {grid_x},{grid_y} - - """) - for node in self._fixed_nodes: - bounding_box = node.getBoundingBox() - f.write(f""" - - """) - - f.write(f""" - """) - - # coord_build_plate_center_x = self._build_volume_bounding_box.width * 0.5 + self._build_volume_bounding_box.left - # coord_build_plate_center_y = self._build_volume_bounding_box.depth * 0.5 + self._build_volume_bounding_box.back - # f.write(f""" - # """) - - f.write(f"") From 586739c5479c0363b98468b7fb679294870b3d0c Mon Sep 17 00:00:00 2001 From: "c.lamboo" Date: Wed, 30 Aug 2023 13:06:19 +0200 Subject: [PATCH 25/25] Avoid bool-trap CURA-7951 --- cura/Arranging/Arranger.py | 7 ++++--- cura/Arranging/GridArrange.py | 2 +- cura/Arranging/Nest2DArrange.py | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/cura/Arranging/Arranger.py b/cura/Arranging/Arranger.py index fd93ab1846..f7f9870cf9 100644 --- a/cura/Arranging/Arranger.py +++ b/cura/Arranging/Arranger.py @@ -5,7 +5,7 @@ if TYPE_CHECKING: class Arranger: - def createGroupOperationForArrange(self, add_new_nodes_in_scene: bool = False) -> Tuple["GroupedOperation", int]: + def createGroupOperationForArrange(self, *, add_new_nodes_in_scene: bool = False) -> Tuple["GroupedOperation", int]: """ Find placement for a set of scene nodes, but don't actually move them just yet. :param add_new_nodes_in_scene: Whether to create new scene nodes before applying the transformations and rotations @@ -16,12 +16,13 @@ class Arranger: """ raise NotImplementedError - def arrange(self, add_new_nodes_in_scene: bool = False) -> bool: + def arrange(self, *, add_new_nodes_in_scene: bool = False) -> bool: """ Find placement for a set of scene nodes, and move them by using a single grouped operation. :param add_new_nodes_in_scene: Whether to create new scene nodes before applying the transformations and rotations :return: found_solution_for_all: Whether the algorithm found a place on the buildplate for all the objects """ - grouped_operation, not_fit_count = self.createGroupOperationForArrange(add_new_nodes_in_scene) + grouped_operation, not_fit_count = self.createGroupOperationForArrange( + add_new_nodes_in_scene=add_new_nodes_in_scene) grouped_operation.push() return not_fit_count == 0 diff --git a/cura/Arranging/GridArrange.py b/cura/Arranging/GridArrange.py index 95ce2c7190..493c81b27c 100644 --- a/cura/Arranging/GridArrange.py +++ b/cura/Arranging/GridArrange.py @@ -71,7 +71,7 @@ class GridArrange(Arranger): self._allowed_grid_idx = self._build_plate_grid_ids.difference(self._fixed_nodes_grid_ids) - def createGroupOperationForArrange(self, add_new_nodes_in_scene: bool = False) -> Tuple[GroupedOperation, int]: + def createGroupOperationForArrange(self, *, add_new_nodes_in_scene: bool = False) -> Tuple[GroupedOperation, int]: # Find the sequence in which items are placed coord_build_plate_center_x = self._build_volume_bounding_box.width * 0.5 + self._build_volume_bounding_box.left coord_build_plate_center_y = self._build_volume_bounding_box.depth * 0.5 + self._build_volume_bounding_box.back diff --git a/cura/Arranging/Nest2DArrange.py b/cura/Arranging/Nest2DArrange.py index bad57c5045..5fcd36c1a3 100644 --- a/cura/Arranging/Nest2DArrange.py +++ b/cura/Arranging/Nest2DArrange.py @@ -124,7 +124,7 @@ class Nest2DArrange(Arranger): return found_solution_for_all, node_items - def createGroupOperationForArrange(self, add_new_nodes_in_scene: bool = False) -> Tuple[GroupedOperation, int]: + def createGroupOperationForArrange(self, *, add_new_nodes_in_scene: bool = False) -> Tuple[GroupedOperation, int]: scene_root = Application.getInstance().getController().getScene().getRoot() found_solution_for_all, node_items = self.findNodePlacement()