mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-06 22:47:29 -06:00
Merge remote-tracking branch 'origin/main' into optimized-prime-tower
This commit is contained in:
commit
e642d85fcd
478 changed files with 7034 additions and 722 deletions
8
.github/ISSUE_TEMPLATE/SlicingCrash.yaml
vendored
8
.github/ISSUE_TEMPLATE/SlicingCrash.yaml
vendored
|
@ -5,6 +5,13 @@ body:
|
||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
|
### 💥 Slicing Crash Analysis Tool 💥
|
||||||
|
We are taking steps to analyze an increase in reported crashes more systematically. We'll need some help with that. 😇
|
||||||
|
Before filling out the report below, we want you to try a special Cura 5.7 Alpha.
|
||||||
|
This version of Cura has an updated slicing engine that will automatically send a report to the Cura Team for analysis.
|
||||||
|
#### [You can find the downloads here](https://github.com/Ultimaker/Cura/discussions/18080) ####
|
||||||
|
If you still encounter a crash you are still welcome to report the issue so we can use your model as a test case, you can find instructions on how to do that below.
|
||||||
|
|
||||||
### Project File
|
### Project File
|
||||||
**⚠️ Before you continue, we need your project file to troubleshoot a slicing crash.**
|
**⚠️ Before you continue, we need your project file to troubleshoot a slicing crash.**
|
||||||
It contains the printer and settings we need for troubleshooting.
|
It contains the printer and settings we need for troubleshooting.
|
||||||
|
@ -68,4 +75,3 @@ body:
|
||||||
description: You can add the zip file and additional information that is relevant to the issue in the comments below.
|
description: You can add the zip file and additional information that is relevant to the issue in the comments below.
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,8 @@ exe = EXE(
|
||||||
target_arch={{ target_arch }},
|
target_arch={{ target_arch }},
|
||||||
codesign_identity=os.getenv('CODESIGN_IDENTITY', None),
|
codesign_identity=os.getenv('CODESIGN_IDENTITY', None),
|
||||||
entitlements_file={{ entitlements_file }},
|
entitlements_file={{ entitlements_file }},
|
||||||
icon={{ icon }}
|
icon={{ icon }},
|
||||||
|
contents_directory='.'
|
||||||
)
|
)
|
||||||
|
|
||||||
coll = COLLECT(
|
coll = COLLECT(
|
||||||
|
@ -70,188 +71,7 @@ coll = COLLECT(
|
||||||
)
|
)
|
||||||
|
|
||||||
{% if macos == true %}
|
{% if macos == true %}
|
||||||
# PyInstaller seems to copy everything in the resource folder for the MacOS, this causes issues with codesigning and notarizing
|
app = BUNDLE(
|
||||||
# The folder structure should adhere to the one specified in Table 2-5
|
|
||||||
# https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFBundles/BundleTypes/BundleTypes.html#//apple_ref/doc/uid/10000123i-CH101-SW1
|
|
||||||
# The class below is basically ducktyping the BUNDLE class of PyInstaller and using our own `assemble` method for more fine-grain and specific
|
|
||||||
# control. Some code of the method below is copied from:
|
|
||||||
# https://github.com/pyinstaller/pyinstaller/blob/22d1d2a5378228744cc95f14904dae1664df32c4/PyInstaller/building/osx.py#L115
|
|
||||||
#-----------------------------------------------------------------------------
|
|
||||||
# Copyright (c) 2005-2022, PyInstaller Development Team.
|
|
||||||
#
|
|
||||||
# Distributed under the terms of the GNU General Public License (version 2
|
|
||||||
# or later) with exception for distributing the bootloader.
|
|
||||||
#
|
|
||||||
# The full license is in the file COPYING.txt, distributed with this software.
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception)
|
|
||||||
#-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
import plistlib
|
|
||||||
import shutil
|
|
||||||
import PyInstaller.utils.osx as osxutils
|
|
||||||
from pathlib import Path
|
|
||||||
from PyInstaller.building.osx import BUNDLE
|
|
||||||
from PyInstaller.building.utils import (_check_path_overlap, _rmtree, add_suffix_to_extension, checkCache)
|
|
||||||
from PyInstaller.building.datastruct import logger
|
|
||||||
from PyInstaller.building.icon import normalize_icon_type
|
|
||||||
|
|
||||||
|
|
||||||
class UMBUNDLE(BUNDLE):
|
|
||||||
def assemble(self):
|
|
||||||
from PyInstaller.config import CONF
|
|
||||||
|
|
||||||
if _check_path_overlap(self.name) and os.path.isdir(self.name):
|
|
||||||
_rmtree(self.name)
|
|
||||||
logger.info("Building BUNDLE %s", self.tocbasename)
|
|
||||||
|
|
||||||
# Create a minimal Mac bundle structure.
|
|
||||||
macos_path = Path(self.name, "Contents", "MacOS")
|
|
||||||
resources_path = Path(self.name, "Contents", "Resources")
|
|
||||||
frameworks_path = Path(self.name, "Contents", "Frameworks")
|
|
||||||
os.makedirs(macos_path)
|
|
||||||
os.makedirs(resources_path)
|
|
||||||
os.makedirs(frameworks_path)
|
|
||||||
|
|
||||||
# Makes sure the icon exists and attempts to convert to the proper format if applicable
|
|
||||||
self.icon = normalize_icon_type(self.icon, ("icns",), "icns", CONF["workpath"])
|
|
||||||
|
|
||||||
# Ensure icon path is absolute
|
|
||||||
self.icon = os.path.abspath(self.icon)
|
|
||||||
|
|
||||||
# Copy icns icon to Resources directory.
|
|
||||||
shutil.copy(self.icon, os.path.join(self.name, 'Contents', 'Resources'))
|
|
||||||
|
|
||||||
# Key/values for a minimal Info.plist file
|
|
||||||
info_plist_dict = {
|
|
||||||
"CFBundleDisplayName": self.appname,
|
|
||||||
"CFBundleName": self.appname,
|
|
||||||
|
|
||||||
# Required by 'codesign' utility.
|
|
||||||
# The value for CFBundleIdentifier is used as the default unique name of your program for Code Signing
|
|
||||||
# purposes. It even identifies the APP for access to restricted OS X areas like Keychain.
|
|
||||||
#
|
|
||||||
# The identifier used for signing must be globally unique. The usual form for this identifier is a
|
|
||||||
# hierarchical name in reverse DNS notation, starting with the toplevel domain, followed by the company
|
|
||||||
# name, followed by the department within the company, and ending with the product name. Usually in the
|
|
||||||
# form: com.mycompany.department.appname
|
|
||||||
# CLI option --osx-bundle-identifier sets this value.
|
|
||||||
"CFBundleIdentifier": self.bundle_identifier,
|
|
||||||
"CFBundleExecutable": os.path.basename(self.exename),
|
|
||||||
"CFBundleIconFile": os.path.basename(self.icon),
|
|
||||||
"CFBundleInfoDictionaryVersion": "6.0",
|
|
||||||
"CFBundlePackageType": "APPL",
|
|
||||||
"CFBundleVersionString": self.version,
|
|
||||||
"CFBundleShortVersionString": self.version,
|
|
||||||
}
|
|
||||||
|
|
||||||
# Set some default values. But they still can be overwritten by the user.
|
|
||||||
if self.console:
|
|
||||||
# Setting EXE console=True implies LSBackgroundOnly=True.
|
|
||||||
info_plist_dict['LSBackgroundOnly'] = True
|
|
||||||
else:
|
|
||||||
# Let's use high resolution by default.
|
|
||||||
info_plist_dict['NSHighResolutionCapable'] = True
|
|
||||||
|
|
||||||
# Merge info_plist settings from spec file
|
|
||||||
if isinstance(self.info_plist, dict) and self.info_plist:
|
|
||||||
info_plist_dict.update(self.info_plist)
|
|
||||||
|
|
||||||
plist_filename = os.path.join(self.name, "Contents", "Info.plist")
|
|
||||||
with open(plist_filename, "wb") as plist_fh:
|
|
||||||
plistlib.dump(info_plist_dict, plist_fh)
|
|
||||||
|
|
||||||
links = []
|
|
||||||
_QT_BASE_PATH = {'PySide2', 'PySide6', 'PyQt5', 'PyQt6', 'PySide6'}
|
|
||||||
for inm, fnm, typ in self.toc:
|
|
||||||
# Adjust name for extensions, if applicable
|
|
||||||
inm, fnm, typ = add_suffix_to_extension(inm, fnm, typ)
|
|
||||||
inm = Path(inm)
|
|
||||||
fnm = Path(fnm)
|
|
||||||
# Copy files from cache. This ensures that are used files with relative paths to dynamic library
|
|
||||||
# dependencies (@executable_path)
|
|
||||||
if typ in ('EXTENSION', 'BINARY') or (typ == 'DATA' and inm.suffix == '.so'):
|
|
||||||
if any(['.' in p for p in inm.parent.parts]):
|
|
||||||
inm = Path(inm.name)
|
|
||||||
fnm = Path(checkCache(
|
|
||||||
str(fnm),
|
|
||||||
strip = self.strip,
|
|
||||||
upx = self.upx,
|
|
||||||
upx_exclude = self.upx_exclude,
|
|
||||||
dist_nm = str(inm),
|
|
||||||
target_arch = self.target_arch,
|
|
||||||
codesign_identity = self.codesign_identity,
|
|
||||||
entitlements_file = self.entitlements_file,
|
|
||||||
strict_arch_validation = (typ == 'EXTENSION'),
|
|
||||||
))
|
|
||||||
frame_dst = frameworks_path.joinpath(inm)
|
|
||||||
if not frame_dst.exists():
|
|
||||||
if frame_dst.is_dir():
|
|
||||||
os.makedirs(frame_dst, exist_ok = True)
|
|
||||||
else:
|
|
||||||
os.makedirs(frame_dst.parent, exist_ok = True)
|
|
||||||
shutil.copy(fnm, frame_dst, follow_symlinks = True)
|
|
||||||
macos_dst = macos_path.joinpath(inm)
|
|
||||||
if not macos_dst.exists():
|
|
||||||
if macos_dst.is_dir():
|
|
||||||
os.makedirs(macos_dst, exist_ok = True)
|
|
||||||
else:
|
|
||||||
os.makedirs(macos_dst.parent, exist_ok = True)
|
|
||||||
|
|
||||||
# Create relative symlink to the framework
|
|
||||||
symlink_to = Path(*[".." for p in macos_dst.relative_to(macos_path).parts], "Frameworks").joinpath(
|
|
||||||
frame_dst.relative_to(frameworks_path))
|
|
||||||
try:
|
|
||||||
macos_dst.symlink_to(symlink_to)
|
|
||||||
except FileExistsError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
if typ == 'DATA':
|
|
||||||
if any(['.' in p for p in inm.parent.parts]) or inm.suffix == '.so':
|
|
||||||
# Skip info dist egg and some not needed folders in tcl and tk, since they all contain dots in their files
|
|
||||||
logger.warning(f"Skipping DATA file {inm}")
|
|
||||||
continue
|
|
||||||
res_dst = resources_path.joinpath(inm)
|
|
||||||
if not res_dst.exists():
|
|
||||||
if res_dst.is_dir():
|
|
||||||
os.makedirs(res_dst, exist_ok = True)
|
|
||||||
else:
|
|
||||||
os.makedirs(res_dst.parent, exist_ok = True)
|
|
||||||
shutil.copy(fnm, res_dst, follow_symlinks = True)
|
|
||||||
macos_dst = macos_path.joinpath(inm)
|
|
||||||
if not macos_dst.exists():
|
|
||||||
if macos_dst.is_dir():
|
|
||||||
os.makedirs(macos_dst, exist_ok = True)
|
|
||||||
else:
|
|
||||||
os.makedirs(macos_dst.parent, exist_ok = True)
|
|
||||||
|
|
||||||
# Create relative symlink to the resource
|
|
||||||
symlink_to = Path(*[".." for p in macos_dst.relative_to(macos_path).parts], "Resources").joinpath(
|
|
||||||
res_dst.relative_to(resources_path))
|
|
||||||
try:
|
|
||||||
macos_dst.symlink_to(symlink_to)
|
|
||||||
except FileExistsError:
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
macos_dst = macos_path.joinpath(inm)
|
|
||||||
if not macos_dst.exists():
|
|
||||||
if macos_dst.is_dir():
|
|
||||||
os.makedirs(macos_dst, exist_ok = True)
|
|
||||||
else:
|
|
||||||
os.makedirs(macos_dst.parent, exist_ok = True)
|
|
||||||
shutil.copy(fnm, macos_dst, follow_symlinks = True)
|
|
||||||
|
|
||||||
# Sign the bundle
|
|
||||||
logger.info('Signing the BUNDLE...')
|
|
||||||
try:
|
|
||||||
osxutils.sign_binary(self.name, self.codesign_identity, self.entitlements_file, deep = True)
|
|
||||||
except Exception as e:
|
|
||||||
logger.warning(f"Error while signing the bundle: {e}")
|
|
||||||
logger.warning("You will need to sign the bundle manually!")
|
|
||||||
|
|
||||||
logger.info(f"Building BUNDLE {self.tocbasename} completed successfully.")
|
|
||||||
|
|
||||||
app = UMBUNDLE(
|
|
||||||
coll,
|
coll,
|
||||||
name='{{ display_name }}.app',
|
name='{{ display_name }}.app',
|
||||||
icon={{ icon }},
|
icon={{ icon }},
|
||||||
|
@ -272,8 +92,9 @@ app = UMBUNDLE(
|
||||||
}],
|
}],
|
||||||
'CFBundleDocumentTypes': [{
|
'CFBundleDocumentTypes': [{
|
||||||
'CFBundleTypeRole': 'Viewer',
|
'CFBundleTypeRole': 'Viewer',
|
||||||
'CFBundleTypeExtensions': ['*'],
|
'CFBundleTypeExtensions': ['stl', 'obj', '3mf', 'gcode', 'ufp'],
|
||||||
'CFBundleTypeName': 'Model Files',
|
'CFBundleTypeName': 'Model Files',
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
){% endif %}
|
)
|
||||||
|
{% endif %}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
version: "5.7.0-alpha.0"
|
version: "5.7.0-alpha.1"
|
||||||
requirements:
|
requirements:
|
||||||
- "uranium/(latest)@ultimaker/testing"
|
- "uranium/(latest)@ultimaker/testing"
|
||||||
- "curaengine/(latest)@ultimaker/testing"
|
- "curaengine/(latest)@ultimaker/testing"
|
||||||
- "cura_binary_data/(latest)@ultimaker/testing"
|
- "cura_binary_data/(latest)@ultimaker/testing"
|
||||||
- "fdm_materials/(latest)@ultimaker/testing"
|
- "fdm_materials/(latest)@ultimaker/testing"
|
||||||
- "curaengine_plugin_gradual_flow/(latest)@ultimaker/stable"
|
- "curaengine_plugin_gradual_flow/0.1.0-beta.2"
|
||||||
- "dulcificum/latest@ultimaker/testing"
|
- "dulcificum/latest@ultimaker/testing"
|
||||||
- "pysavitar/5.3.0"
|
- "pysavitar/5.3.0"
|
||||||
- "pynest2d/5.3.0"
|
- "pynest2d/5.3.0"
|
||||||
|
@ -118,7 +118,6 @@ pyinstaller:
|
||||||
- "sqlite3"
|
- "sqlite3"
|
||||||
- "trimesh"
|
- "trimesh"
|
||||||
- "win32ctypes"
|
- "win32ctypes"
|
||||||
- "PyQt6"
|
|
||||||
- "PyQt6.QtNetwork"
|
- "PyQt6.QtNetwork"
|
||||||
- "PyQt6.sip"
|
- "PyQt6.sip"
|
||||||
- "stl"
|
- "stl"
|
||||||
|
@ -160,6 +159,10 @@ pycharm_targets:
|
||||||
module_name: Cura
|
module_name: Cura
|
||||||
name: pytest in TestGCodeListDecorator.py
|
name: pytest in TestGCodeListDecorator.py
|
||||||
script_name: tests/TestGCodeListDecorator.py
|
script_name: tests/TestGCodeListDecorator.py
|
||||||
|
- jinja_path: .run_templates/pycharm_cura_test.run.xml.jinja
|
||||||
|
module_name: Cura
|
||||||
|
name: pytest in TestHitChecker.py
|
||||||
|
script_name: tests/TestHitChecker.py
|
||||||
- jinja_path: .run_templates/pycharm_cura_test.run.xml.jinja
|
- jinja_path: .run_templates/pycharm_cura_test.run.xml.jinja
|
||||||
module_name: Cura
|
module_name: Cura
|
||||||
name: pytest in TestIntentManager.py
|
name: pytest in TestIntentManager.py
|
||||||
|
@ -188,6 +191,10 @@ pycharm_targets:
|
||||||
module_name: Cura
|
module_name: Cura
|
||||||
name: pytest in TestPrintInformation.py
|
name: pytest in TestPrintInformation.py
|
||||||
script_name: tests/TestPrintInformation.py
|
script_name: tests/TestPrintInformation.py
|
||||||
|
- jinja_path: .run_templates/pycharm_cura_test.run.xml.jinja
|
||||||
|
module_name: Cura
|
||||||
|
name: pytest in TestPrintOrderManager.py
|
||||||
|
script_name: tests/TestPrintOrderManager.py
|
||||||
- jinja_path: .run_templates/pycharm_cura_test.run.xml.jinja
|
- jinja_path: .run_templates/pycharm_cura_test.run.xml.jinja
|
||||||
module_name: Cura
|
module_name: Cura
|
||||||
name: pytest in TestProfileRequirements.py
|
name: pytest in TestProfileRequirements.py
|
||||||
|
|
22
conanfile.py
22
conanfile.py
|
@ -1,4 +1,5 @@
|
||||||
import os
|
import os
|
||||||
|
from io import StringIO
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from jinja2 import Template
|
from jinja2 import Template
|
||||||
|
@ -150,6 +151,7 @@ class CuraConan(ConanFile):
|
||||||
return "None"
|
return "None"
|
||||||
|
|
||||||
def _conan_installs(self):
|
def _conan_installs(self):
|
||||||
|
self.output.info("Collecting conan installs")
|
||||||
conan_installs = {}
|
conan_installs = {}
|
||||||
|
|
||||||
# list of conan installs
|
# list of conan installs
|
||||||
|
@ -161,13 +163,22 @@ class CuraConan(ConanFile):
|
||||||
return conan_installs
|
return conan_installs
|
||||||
|
|
||||||
def _python_installs(self):
|
def _python_installs(self):
|
||||||
|
self.output.info("Collecting python installs")
|
||||||
python_installs = {}
|
python_installs = {}
|
||||||
|
|
||||||
# list of python installs
|
# list of python installs
|
||||||
python_ins_cmd = f"python -c \"import pkg_resources; print(';'.join([(s.key+','+ s.version) for s in pkg_resources.working_set]))\""
|
run_env = VirtualRunEnv(self)
|
||||||
from six import StringIO
|
env = run_env.environment()
|
||||||
|
env.prepend_path("PYTHONPATH", str(self._site_packages.as_posix()))
|
||||||
|
venv_vars = env.vars(self, scope = "run")
|
||||||
|
|
||||||
|
outer = '"' if self.settings.os == "Windows" else "'"
|
||||||
|
inner = "'" if self.settings.os == "Windows" else '"'
|
||||||
buffer = StringIO()
|
buffer = StringIO()
|
||||||
self.run(python_ins_cmd, run_environment= True, env = "conanrun", output=buffer)
|
with venv_vars.apply():
|
||||||
|
self.run(f"""python -c {outer}import pkg_resources; print({inner};{inner}.join([(s.key+{inner},{inner}+ s.version) for s in pkg_resources.working_set])){outer}""",
|
||||||
|
env = "conanrun",
|
||||||
|
output = buffer)
|
||||||
|
|
||||||
packages = str(buffer.getvalue()).split("-----------------\n")
|
packages = str(buffer.getvalue()).split("-----------------\n")
|
||||||
packages = packages[1].strip('\r\n').split(";")
|
packages = packages[1].strip('\r\n').split(";")
|
||||||
|
@ -420,7 +431,6 @@ class CuraConan(ConanFile):
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.options.get_safe("enable_i18n", False) and self._i18n_options["extract"]:
|
if self.options.get_safe("enable_i18n", False) and self._i18n_options["extract"]:
|
||||||
# Update the po and pot files
|
|
||||||
vb = VirtualBuildEnv(self)
|
vb = VirtualBuildEnv(self)
|
||||||
vb.generate()
|
vb.generate()
|
||||||
|
|
||||||
|
@ -505,10 +515,14 @@ echo "CURA_APP_NAME={{ cura_app_name }}" >> ${{ env_prefix }}GITHUB_ENV
|
||||||
|
|
||||||
if self.in_local_cache:
|
if self.in_local_cache:
|
||||||
self.runenv_info.append_path("PYTHONPATH", os.path.join(self.package_folder, "site-packages"))
|
self.runenv_info.append_path("PYTHONPATH", os.path.join(self.package_folder, "site-packages"))
|
||||||
|
self.env_info.PYTHONPATH.append(os.path.join(self.package_folder, "site-packages"))
|
||||||
self.runenv_info.append_path("PYTHONPATH", os.path.join(self.package_folder, "plugins"))
|
self.runenv_info.append_path("PYTHONPATH", os.path.join(self.package_folder, "plugins"))
|
||||||
|
self.env_info.PYTHONPATH.append(os.path.join(self.package_folder, "plugins"))
|
||||||
else:
|
else:
|
||||||
self.runenv_info.append_path("PYTHONPATH", self.source_folder)
|
self.runenv_info.append_path("PYTHONPATH", self.source_folder)
|
||||||
|
self.env_info.PYTHONPATH.append(self.source_folder)
|
||||||
self.runenv_info.append_path("PYTHONPATH", os.path.join(self.source_folder, "plugins"))
|
self.runenv_info.append_path("PYTHONPATH", os.path.join(self.source_folder, "plugins"))
|
||||||
|
self.env_info.PYTHONPATH.append(os.path.join(self.source_folder, "plugins"))
|
||||||
|
|
||||||
def package_id(self):
|
def package_id(self):
|
||||||
self.info.clear()
|
self.info.clear()
|
||||||
|
|
|
@ -104,7 +104,8 @@ from cura.Settings.SettingInheritanceManager import SettingInheritanceManager
|
||||||
from cura.Settings.SidebarCustomMenuItemsModel import SidebarCustomMenuItemsModel
|
from cura.Settings.SidebarCustomMenuItemsModel import SidebarCustomMenuItemsModel
|
||||||
from cura.Settings.SimpleModeSettingsManager import SimpleModeSettingsManager
|
from cura.Settings.SimpleModeSettingsManager import SimpleModeSettingsManager
|
||||||
from cura.TaskManagement.OnExitCallbackManager import OnExitCallbackManager
|
from cura.TaskManagement.OnExitCallbackManager import OnExitCallbackManager
|
||||||
from cura.UI import CuraSplashScreen, MachineActionManager, PrintInformation
|
from cura.UI import CuraSplashScreen, PrintInformation
|
||||||
|
from cura.UI.MachineActionManager import MachineActionManager
|
||||||
from cura.UI.AddPrinterPagesModel import AddPrinterPagesModel
|
from cura.UI.AddPrinterPagesModel import AddPrinterPagesModel
|
||||||
from cura.UI.MachineSettingsManager import MachineSettingsManager
|
from cura.UI.MachineSettingsManager import MachineSettingsManager
|
||||||
from cura.UI.ObjectsModel import ObjectsModel
|
from cura.UI.ObjectsModel import ObjectsModel
|
||||||
|
@ -125,6 +126,7 @@ from .Machines.Models.CompatibleMachineModel import CompatibleMachineModel
|
||||||
from .Machines.Models.MachineListModel import MachineListModel
|
from .Machines.Models.MachineListModel import MachineListModel
|
||||||
from .Machines.Models.ActiveIntentQualitiesModel import ActiveIntentQualitiesModel
|
from .Machines.Models.ActiveIntentQualitiesModel import ActiveIntentQualitiesModel
|
||||||
from .Machines.Models.IntentSelectionModel import IntentSelectionModel
|
from .Machines.Models.IntentSelectionModel import IntentSelectionModel
|
||||||
|
from .PrintOrderManager import PrintOrderManager
|
||||||
from .SingleInstance import SingleInstance
|
from .SingleInstance import SingleInstance
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
@ -179,6 +181,7 @@ class CuraApplication(QtApplication):
|
||||||
|
|
||||||
# Variables set from CLI
|
# Variables set from CLI
|
||||||
self._files_to_open = []
|
self._files_to_open = []
|
||||||
|
self._urls_to_open = []
|
||||||
self._use_single_instance = False
|
self._use_single_instance = False
|
||||||
|
|
||||||
self._single_instance = None
|
self._single_instance = None
|
||||||
|
@ -186,7 +189,7 @@ class CuraApplication(QtApplication):
|
||||||
|
|
||||||
self._cura_formula_functions = None # type: Optional[CuraFormulaFunctions]
|
self._cura_formula_functions = None # type: Optional[CuraFormulaFunctions]
|
||||||
|
|
||||||
self._machine_action_manager = None # type: Optional[MachineActionManager.MachineActionManager]
|
self._machine_action_manager: Optional[MachineActionManager] = None
|
||||||
|
|
||||||
self.empty_container = None # type: EmptyInstanceContainer
|
self.empty_container = None # type: EmptyInstanceContainer
|
||||||
self.empty_definition_changes_container = None # type: EmptyInstanceContainer
|
self.empty_definition_changes_container = None # type: EmptyInstanceContainer
|
||||||
|
@ -202,6 +205,7 @@ class CuraApplication(QtApplication):
|
||||||
self._container_manager = None
|
self._container_manager = None
|
||||||
|
|
||||||
self._object_manager = None
|
self._object_manager = None
|
||||||
|
self._print_order_manager = None
|
||||||
self._extruders_model = None
|
self._extruders_model = None
|
||||||
self._extruders_model_with_optional = None
|
self._extruders_model_with_optional = None
|
||||||
self._build_plate_model = None
|
self._build_plate_model = None
|
||||||
|
@ -333,7 +337,7 @@ class CuraApplication(QtApplication):
|
||||||
for filename in self._cli_args.file:
|
for filename in self._cli_args.file:
|
||||||
url = QUrl(filename)
|
url = QUrl(filename)
|
||||||
if url.scheme() in self._supported_url_schemes:
|
if url.scheme() in self._supported_url_schemes:
|
||||||
self._open_url_queue.append(url)
|
self._urls_to_open.append(url)
|
||||||
else:
|
else:
|
||||||
self._files_to_open.append(os.path.abspath(filename))
|
self._files_to_open.append(os.path.abspath(filename))
|
||||||
|
|
||||||
|
@ -352,11 +356,11 @@ class CuraApplication(QtApplication):
|
||||||
self.__addAllEmptyContainers()
|
self.__addAllEmptyContainers()
|
||||||
self.__setLatestResouceVersionsForVersionUpgrade()
|
self.__setLatestResouceVersionsForVersionUpgrade()
|
||||||
|
|
||||||
self._machine_action_manager = MachineActionManager.MachineActionManager(self)
|
self._machine_action_manager = MachineActionManager(self)
|
||||||
self._machine_action_manager.initialize()
|
self._machine_action_manager.initialize()
|
||||||
|
|
||||||
def __sendCommandToSingleInstance(self):
|
def __sendCommandToSingleInstance(self):
|
||||||
self._single_instance = SingleInstance(self, self._files_to_open)
|
self._single_instance = SingleInstance(self, self._files_to_open, self._urls_to_open)
|
||||||
|
|
||||||
# If we use single instance, try to connect to the single instance server, send commands, and then exit.
|
# If we use single instance, try to connect to the single instance server, send commands, and then exit.
|
||||||
# If we cannot find an existing single instance server, this is the only instance, so just keep going.
|
# If we cannot find an existing single instance server, this is the only instance, so just keep going.
|
||||||
|
@ -373,9 +377,15 @@ class CuraApplication(QtApplication):
|
||||||
Resources.addExpectedDirNameInData(dir_name)
|
Resources.addExpectedDirNameInData(dir_name)
|
||||||
|
|
||||||
app_root = os.path.abspath(os.path.join(os.path.dirname(sys.executable)))
|
app_root = os.path.abspath(os.path.join(os.path.dirname(sys.executable)))
|
||||||
Resources.addSecureSearchPath(os.path.join(app_root, "share", "cura", "resources"))
|
|
||||||
|
|
||||||
|
if platform.system() == "Darwin":
|
||||||
|
Resources.addSecureSearchPath(os.path.join(app_root, "Resources", "share", "cura", "resources"))
|
||||||
|
Resources.addSecureSearchPath(
|
||||||
|
os.path.join(self._app_install_dir, "Resources", "share", "cura", "resources"))
|
||||||
|
else:
|
||||||
|
Resources.addSecureSearchPath(os.path.join(app_root, "share", "cura", "resources"))
|
||||||
Resources.addSecureSearchPath(os.path.join(self._app_install_dir, "share", "cura", "resources"))
|
Resources.addSecureSearchPath(os.path.join(self._app_install_dir, "share", "cura", "resources"))
|
||||||
|
|
||||||
if not hasattr(sys, "frozen"):
|
if not hasattr(sys, "frozen"):
|
||||||
cura_data_root = os.environ.get('CURA_DATA_ROOT', None)
|
cura_data_root = os.environ.get('CURA_DATA_ROOT', None)
|
||||||
if cura_data_root:
|
if cura_data_root:
|
||||||
|
@ -899,6 +909,7 @@ class CuraApplication(QtApplication):
|
||||||
# initialize info objects
|
# initialize info objects
|
||||||
self._print_information = PrintInformation.PrintInformation(self)
|
self._print_information = PrintInformation.PrintInformation(self)
|
||||||
self._cura_actions = CuraActions.CuraActions(self)
|
self._cura_actions = CuraActions.CuraActions(self)
|
||||||
|
self._print_order_manager = PrintOrderManager(self.getObjectsModel().getNodes)
|
||||||
self.processEvents()
|
self.processEvents()
|
||||||
# Initialize setting visibility presets model.
|
# Initialize setting visibility presets model.
|
||||||
self._setting_visibility_presets_model = SettingVisibilityPresetsModel(self.getPreferences(), parent = self)
|
self._setting_visibility_presets_model = SettingVisibilityPresetsModel(self.getPreferences(), parent = self)
|
||||||
|
@ -956,6 +967,8 @@ class CuraApplication(QtApplication):
|
||||||
self.callLater(self._openFile, file_name)
|
self.callLater(self._openFile, file_name)
|
||||||
for file_name in self._open_file_queue: # Open all the files that were queued up while plug-ins were loading.
|
for file_name in self._open_file_queue: # Open all the files that were queued up while plug-ins were loading.
|
||||||
self.callLater(self._openFile, file_name)
|
self.callLater(self._openFile, file_name)
|
||||||
|
for url in self._urls_to_open:
|
||||||
|
self.callLater(self._openUrl, url)
|
||||||
for url in self._open_url_queue:
|
for url in self._open_url_queue:
|
||||||
self.callLater(self._openUrl, url)
|
self.callLater(self._openUrl, url)
|
||||||
|
|
||||||
|
@ -979,6 +992,7 @@ class CuraApplication(QtApplication):
|
||||||
t.setEnabledAxis([ToolHandle.XAxis, ToolHandle.YAxis, ToolHandle.ZAxis])
|
t.setEnabledAxis([ToolHandle.XAxis, ToolHandle.YAxis, ToolHandle.ZAxis])
|
||||||
|
|
||||||
Selection.selectionChanged.connect(self.onSelectionChanged)
|
Selection.selectionChanged.connect(self.onSelectionChanged)
|
||||||
|
self._print_order_manager.printOrderChanged.connect(self._onPrintOrderChanged)
|
||||||
|
|
||||||
# Set default background color for scene
|
# Set default background color for scene
|
||||||
self.getRenderer().setBackgroundColor(QColor(245, 245, 245))
|
self.getRenderer().setBackgroundColor(QColor(245, 245, 245))
|
||||||
|
@ -1068,6 +1082,10 @@ class CuraApplication(QtApplication):
|
||||||
def getTextManager(self, *args) -> "TextManager":
|
def getTextManager(self, *args) -> "TextManager":
|
||||||
return self._text_manager
|
return self._text_manager
|
||||||
|
|
||||||
|
@pyqtSlot(bool)
|
||||||
|
def getWorkplaceDropToBuildplate(self, drop_to_build_plate: bool) ->None:
|
||||||
|
return self._physics.setAppPerModelDropDown(drop_to_build_plate)
|
||||||
|
|
||||||
def getCuraFormulaFunctions(self, *args) -> "CuraFormulaFunctions":
|
def getCuraFormulaFunctions(self, *args) -> "CuraFormulaFunctions":
|
||||||
if self._cura_formula_functions is None:
|
if self._cura_formula_functions is None:
|
||||||
self._cura_formula_functions = CuraFormulaFunctions(self)
|
self._cura_formula_functions = CuraFormulaFunctions(self)
|
||||||
|
@ -1094,6 +1112,10 @@ class CuraApplication(QtApplication):
|
||||||
self._object_manager = ObjectsModel(self)
|
self._object_manager = ObjectsModel(self)
|
||||||
return self._object_manager
|
return self._object_manager
|
||||||
|
|
||||||
|
@pyqtSlot(str, result = "QVariantList")
|
||||||
|
def getSupportedActionMachineList(self, definition_id: str) -> List["MachineAction"]:
|
||||||
|
return self._machine_action_manager.getSupportedActions(self._machine_manager.getDefinitionByMachineId(definition_id))
|
||||||
|
|
||||||
@pyqtSlot(result = QObject)
|
@pyqtSlot(result = QObject)
|
||||||
def getExtrudersModel(self, *args) -> "ExtrudersModel":
|
def getExtrudersModel(self, *args) -> "ExtrudersModel":
|
||||||
if self._extruders_model is None:
|
if self._extruders_model is None:
|
||||||
|
@ -1129,18 +1151,16 @@ class CuraApplication(QtApplication):
|
||||||
self._setting_inheritance_manager = SettingInheritanceManager.createSettingInheritanceManager()
|
self._setting_inheritance_manager = SettingInheritanceManager.createSettingInheritanceManager()
|
||||||
return self._setting_inheritance_manager
|
return self._setting_inheritance_manager
|
||||||
|
|
||||||
def getMachineActionManager(self, *args: Any) -> MachineActionManager.MachineActionManager:
|
@pyqtSlot(result = QObject)
|
||||||
|
def getMachineActionManager(self, *args: Any) -> MachineActionManager:
|
||||||
"""Get the machine action manager
|
"""Get the machine action manager
|
||||||
|
|
||||||
We ignore any *args given to this, as we also register the machine manager as qml singleton.
|
We ignore any *args given to this, as we also register the machine manager as qml singleton.
|
||||||
It wants to give this function an engine and script engine, but we don't care about that.
|
It wants to give this function an engine and script engine, but we don't care about that.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return cast(MachineActionManager.MachineActionManager, self._machine_action_manager)
|
return self._machine_action_manager
|
||||||
|
|
||||||
@pyqtSlot(result = QObject)
|
|
||||||
def getMachineActionManagerQml(self)-> MachineActionManager.MachineActionManager:
|
|
||||||
return cast(QObject, self._machine_action_manager)
|
|
||||||
|
|
||||||
@pyqtSlot(result = QObject)
|
@pyqtSlot(result = QObject)
|
||||||
def getMaterialManagementModel(self) -> MaterialManagementModel:
|
def getMaterialManagementModel(self) -> MaterialManagementModel:
|
||||||
|
@ -1250,6 +1270,7 @@ class CuraApplication(QtApplication):
|
||||||
self.processEvents()
|
self.processEvents()
|
||||||
engine.rootContext().setContextProperty("Printer", self)
|
engine.rootContext().setContextProperty("Printer", self)
|
||||||
engine.rootContext().setContextProperty("CuraApplication", self)
|
engine.rootContext().setContextProperty("CuraApplication", self)
|
||||||
|
engine.rootContext().setContextProperty("PrintOrderManager", self._print_order_manager)
|
||||||
engine.rootContext().setContextProperty("PrintInformation", self._print_information)
|
engine.rootContext().setContextProperty("PrintInformation", self._print_information)
|
||||||
engine.rootContext().setContextProperty("CuraActions", self._cura_actions)
|
engine.rootContext().setContextProperty("CuraActions", self._cura_actions)
|
||||||
engine.rootContext().setContextProperty("CuraSDKVersion", ApplicationMetadata.CuraSDKVersion)
|
engine.rootContext().setContextProperty("CuraSDKVersion", ApplicationMetadata.CuraSDKVersion)
|
||||||
|
@ -1264,7 +1285,7 @@ class CuraApplication(QtApplication):
|
||||||
qmlRegisterSingletonType(IntentManager, "Cura", 1, 6, self.getIntentManager, "IntentManager")
|
qmlRegisterSingletonType(IntentManager, "Cura", 1, 6, self.getIntentManager, "IntentManager")
|
||||||
qmlRegisterSingletonType(SettingInheritanceManager, "Cura", 1, 0, self.getSettingInheritanceManager, "SettingInheritanceManager")
|
qmlRegisterSingletonType(SettingInheritanceManager, "Cura", 1, 0, self.getSettingInheritanceManager, "SettingInheritanceManager")
|
||||||
qmlRegisterSingletonType(SimpleModeSettingsManager, "Cura", 1, 0, self.getSimpleModeSettingsManagerWrapper, "SimpleModeSettingsManager")
|
qmlRegisterSingletonType(SimpleModeSettingsManager, "Cura", 1, 0, self.getSimpleModeSettingsManagerWrapper, "SimpleModeSettingsManager")
|
||||||
qmlRegisterSingletonType(MachineActionManager.MachineActionManager, "Cura", 1, 0, self.getMachineActionManagerWrapper, "MachineActionManager")
|
qmlRegisterSingletonType(MachineActionManager, "Cura", 1, 0, self.getMachineActionManagerWrapper, "MachineActionManager")
|
||||||
|
|
||||||
self.processEvents()
|
self.processEvents()
|
||||||
qmlRegisterType(NetworkingUtil, "Cura", 1, 5, "NetworkingUtil")
|
qmlRegisterType(NetworkingUtil, "Cura", 1, 5, "NetworkingUtil")
|
||||||
|
@ -1745,8 +1766,12 @@ class CuraApplication(QtApplication):
|
||||||
Selection.remove(node)
|
Selection.remove(node)
|
||||||
Selection.add(group_node)
|
Selection.add(group_node)
|
||||||
|
|
||||||
|
all_nodes = self.getObjectsModel().getNodes()
|
||||||
|
PrintOrderManager.updatePrintOrdersAfterGroupOperation(all_nodes, group_node, selected_nodes)
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def ungroupSelected(self) -> None:
|
def ungroupSelected(self) -> None:
|
||||||
|
all_nodes = self.getObjectsModel().getNodes()
|
||||||
selected_objects = Selection.getAllSelectedObjects().copy()
|
selected_objects = Selection.getAllSelectedObjects().copy()
|
||||||
for node in selected_objects:
|
for node in selected_objects:
|
||||||
if node.callDecoration("isGroup"):
|
if node.callDecoration("isGroup"):
|
||||||
|
@ -1754,21 +1779,30 @@ class CuraApplication(QtApplication):
|
||||||
|
|
||||||
group_parent = node.getParent()
|
group_parent = node.getParent()
|
||||||
children = node.getChildren().copy()
|
children = node.getChildren().copy()
|
||||||
for child in children:
|
|
||||||
# Ungroup only 1 level deep
|
|
||||||
if child.getParent() != node:
|
|
||||||
continue
|
|
||||||
|
|
||||||
|
# Ungroup only 1 level deep
|
||||||
|
children_to_ungroup = list(filter(lambda child: child.getParent() == node, children))
|
||||||
|
for child in children_to_ungroup:
|
||||||
# Set the parent of the children to the parent of the group-node
|
# Set the parent of the children to the parent of the group-node
|
||||||
op.addOperation(SetParentOperation(child, group_parent))
|
op.addOperation(SetParentOperation(child, group_parent))
|
||||||
|
|
||||||
# Add all individual nodes to the selection
|
# Add all individual nodes to the selection
|
||||||
Selection.add(child)
|
Selection.add(child)
|
||||||
|
|
||||||
|
PrintOrderManager.updatePrintOrdersAfterUngroupOperation(all_nodes, node, children_to_ungroup)
|
||||||
op.push()
|
op.push()
|
||||||
# Note: The group removes itself from the scene once all its children have left it,
|
# Note: The group removes itself from the scene once all its children have left it,
|
||||||
# see GroupDecorator._onChildrenChanged
|
# see GroupDecorator._onChildrenChanged
|
||||||
|
|
||||||
|
def _onPrintOrderChanged(self) -> None:
|
||||||
|
# update object list
|
||||||
|
scene = self.getController().getScene()
|
||||||
|
scene.sceneChanged.emit(scene.getRoot())
|
||||||
|
|
||||||
|
# reset if already was sliced
|
||||||
|
Application.getInstance().getBackend().needsSlicing()
|
||||||
|
Application.getInstance().getBackend().tickle()
|
||||||
|
|
||||||
def _createSplashScreen(self) -> Optional[CuraSplashScreen.CuraSplashScreen]:
|
def _createSplashScreen(self) -> Optional[CuraSplashScreen.CuraSplashScreen]:
|
||||||
if self._is_headless:
|
if self._is_headless:
|
||||||
return None
|
return None
|
||||||
|
|
88
cura/HitChecker.py
Normal file
88
cura/HitChecker.py
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
from typing import List, Dict
|
||||||
|
from cura.Scene.CuraSceneNode import CuraSceneNode
|
||||||
|
|
||||||
|
|
||||||
|
class HitChecker:
|
||||||
|
"""Checks if nodes can be printed without causing any collisions and interference"""
|
||||||
|
|
||||||
|
def __init__(self, nodes: List[CuraSceneNode]) -> None:
|
||||||
|
self._hit_map = self._buildHitMap(nodes)
|
||||||
|
|
||||||
|
def anyTwoNodesBlockEachOther(self, nodes: List[CuraSceneNode]) -> bool:
|
||||||
|
"""Returns True if any 2 nodes block each other"""
|
||||||
|
for a in nodes:
|
||||||
|
for b in nodes:
|
||||||
|
if self._hit_map[a][b] and self._hit_map[b][a]:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def canPrintBefore(self, node: CuraSceneNode, other_nodes: List[CuraSceneNode]) -> bool:
|
||||||
|
"""Returns True if node doesn't block other_nodes and can be printed before them"""
|
||||||
|
no_hits = all(not self._hit_map[node][other_node] for other_node in other_nodes)
|
||||||
|
return no_hits
|
||||||
|
|
||||||
|
def canPrintAfter(self, node: CuraSceneNode, other_nodes: List[CuraSceneNode]) -> bool:
|
||||||
|
"""Returns True if node doesn't hit other nodes and can be printed after them"""
|
||||||
|
no_hits = all(not self._hit_map[other_node][node] for other_node in other_nodes)
|
||||||
|
return no_hits
|
||||||
|
|
||||||
|
def calculateScore(self, a: CuraSceneNode, b: CuraSceneNode) -> int:
|
||||||
|
"""Calculate score simply sums the number of other objects it 'blocks'
|
||||||
|
|
||||||
|
:param a: node
|
||||||
|
:param b: node
|
||||||
|
:return: sum of the number of other objects
|
||||||
|
"""
|
||||||
|
|
||||||
|
score_a = sum(self._hit_map[a].values())
|
||||||
|
score_b = sum(self._hit_map[b].values())
|
||||||
|
return score_a - score_b
|
||||||
|
|
||||||
|
def canPrintNodesInProvidedOrder(self, ordered_nodes: List[CuraSceneNode]) -> bool:
|
||||||
|
"""Returns True If nodes don't have any hits in provided order"""
|
||||||
|
for node_index, node in enumerate(ordered_nodes):
|
||||||
|
nodes_before = ordered_nodes[:node_index - 1] if node_index - 1 >= 0 else []
|
||||||
|
nodes_after = ordered_nodes[node_index + 1:] if node_index + 1 < len(ordered_nodes) else []
|
||||||
|
if not self.canPrintBefore(node, nodes_after) or not self.canPrintAfter(node, nodes_before):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _buildHitMap(nodes: List[CuraSceneNode]) -> Dict[CuraSceneNode, CuraSceneNode]:
|
||||||
|
"""Pre-computes all hits between all objects
|
||||||
|
|
||||||
|
:nodes: nodes that need to be checked for collisions
|
||||||
|
:return: dictionary where hit_map[node1][node2] is False if there node1 can be printed before node2
|
||||||
|
"""
|
||||||
|
hit_map = {j: {i: HitChecker._checkHit(j, i) for i in nodes} for j in nodes}
|
||||||
|
return hit_map
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _checkHit(a: CuraSceneNode, b: CuraSceneNode) -> bool:
|
||||||
|
"""Checks if a can be printed before b
|
||||||
|
|
||||||
|
:param a: node
|
||||||
|
:param b: node
|
||||||
|
:return: False if a can be printed before b
|
||||||
|
"""
|
||||||
|
|
||||||
|
if a == b:
|
||||||
|
return False
|
||||||
|
|
||||||
|
a_hit_hull = a.callDecoration("getConvexHullBoundary")
|
||||||
|
b_hit_hull = b.callDecoration("getConvexHullHeadFull")
|
||||||
|
overlap = a_hit_hull.intersectsPolygon(b_hit_hull)
|
||||||
|
|
||||||
|
if overlap:
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Adhesion areas must never overlap, regardless of printing order
|
||||||
|
# This would cause over-extrusion
|
||||||
|
a_hit_hull = a.callDecoration("getAdhesionArea")
|
||||||
|
b_hit_hull = b.callDecoration("getAdhesionArea")
|
||||||
|
overlap = a_hit_hull.intersectsPolygon(b_hit_hull)
|
||||||
|
|
||||||
|
if overlap:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
|
@ -16,6 +16,7 @@ from UM.TaskManagement.HttpRequestManager import HttpRequestManager # To downlo
|
||||||
|
|
||||||
catalog = i18nCatalog("cura")
|
catalog = i18nCatalog("cura")
|
||||||
TOKEN_TIMESTAMP_FORMAT = "%Y-%m-%d %H:%M:%S"
|
TOKEN_TIMESTAMP_FORMAT = "%Y-%m-%d %H:%M:%S"
|
||||||
|
REQUEST_TIMEOUT = 5 # Seconds
|
||||||
|
|
||||||
|
|
||||||
class AuthorizationHelpers:
|
class AuthorizationHelpers:
|
||||||
|
@ -53,7 +54,8 @@ class AuthorizationHelpers:
|
||||||
data = urllib.parse.urlencode(data).encode("UTF-8"),
|
data = urllib.parse.urlencode(data).encode("UTF-8"),
|
||||||
headers_dict = headers,
|
headers_dict = headers,
|
||||||
callback = lambda response: self.parseTokenResponse(response, callback),
|
callback = lambda response: self.parseTokenResponse(response, callback),
|
||||||
error_callback = lambda response, _: self.parseTokenResponse(response, callback)
|
error_callback = lambda response, _: self.parseTokenResponse(response, callback),
|
||||||
|
timeout = REQUEST_TIMEOUT
|
||||||
)
|
)
|
||||||
|
|
||||||
def getAccessTokenUsingRefreshToken(self, refresh_token: str, callback: Callable[[AuthenticationResponse], None]) -> None:
|
def getAccessTokenUsingRefreshToken(self, refresh_token: str, callback: Callable[[AuthenticationResponse], None]) -> None:
|
||||||
|
@ -77,7 +79,9 @@ class AuthorizationHelpers:
|
||||||
data = urllib.parse.urlencode(data).encode("UTF-8"),
|
data = urllib.parse.urlencode(data).encode("UTF-8"),
|
||||||
headers_dict = headers,
|
headers_dict = headers,
|
||||||
callback = lambda response: self.parseTokenResponse(response, callback),
|
callback = lambda response: self.parseTokenResponse(response, callback),
|
||||||
error_callback = lambda response, _: self.parseTokenResponse(response, callback)
|
error_callback = lambda response, _: self.parseTokenResponse(response, callback),
|
||||||
|
urgent = True,
|
||||||
|
timeout = REQUEST_TIMEOUT
|
||||||
)
|
)
|
||||||
|
|
||||||
def parseTokenResponse(self, token_response: QNetworkReply, callback: Callable[[AuthenticationResponse], None]) -> None:
|
def parseTokenResponse(self, token_response: QNetworkReply, callback: Callable[[AuthenticationResponse], None]) -> None:
|
||||||
|
@ -122,7 +126,8 @@ class AuthorizationHelpers:
|
||||||
check_token_url,
|
check_token_url,
|
||||||
headers_dict = headers,
|
headers_dict = headers,
|
||||||
callback = lambda reply: self._parseUserProfile(reply, success_callback, failed_callback),
|
callback = lambda reply: self._parseUserProfile(reply, success_callback, failed_callback),
|
||||||
error_callback = lambda _, _2: failed_callback() if failed_callback is not None else None
|
error_callback = lambda _, _2: failed_callback() if failed_callback is not None else None,
|
||||||
|
timeout = REQUEST_TIMEOUT
|
||||||
)
|
)
|
||||||
|
|
||||||
def _parseUserProfile(self, reply: QNetworkReply, success_callback: Optional[Callable[[UserProfile], None]], failed_callback: Optional[Callable[[], None]] = None) -> None:
|
def _parseUserProfile(self, reply: QNetworkReply, success_callback: Optional[Callable[[UserProfile], None]], failed_callback: Optional[Callable[[], None]] = None) -> None:
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Copyright (c) 2021 Ultimaker B.V.
|
# Copyright (c) 2024 UltiMaker
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
@ -6,13 +6,14 @@ from datetime import datetime, timedelta
|
||||||
from typing import Callable, Dict, Optional, TYPE_CHECKING, Union
|
from typing import Callable, Dict, Optional, TYPE_CHECKING, Union
|
||||||
from urllib.parse import urlencode, quote_plus
|
from urllib.parse import urlencode, quote_plus
|
||||||
|
|
||||||
from PyQt6.QtCore import QUrl
|
from PyQt6.QtCore import QUrl, QTimer
|
||||||
from PyQt6.QtGui import QDesktopServices
|
from PyQt6.QtGui import QDesktopServices
|
||||||
|
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
from UM.Message import Message
|
from UM.Message import Message
|
||||||
from UM.Signal import Signal
|
from UM.Signal import Signal
|
||||||
from UM.i18n import i18nCatalog
|
from UM.i18n import i18nCatalog
|
||||||
|
from UM.TaskManagement.HttpRequestManager import HttpRequestManager # To download log-in tokens.
|
||||||
from cura.OAuth2.AuthorizationHelpers import AuthorizationHelpers, TOKEN_TIMESTAMP_FORMAT
|
from cura.OAuth2.AuthorizationHelpers import AuthorizationHelpers, TOKEN_TIMESTAMP_FORMAT
|
||||||
from cura.OAuth2.LocalAuthorizationServer import LocalAuthorizationServer
|
from cura.OAuth2.LocalAuthorizationServer import LocalAuthorizationServer
|
||||||
from cura.OAuth2.Models import AuthenticationResponse, BaseModel
|
from cura.OAuth2.Models import AuthenticationResponse, BaseModel
|
||||||
|
@ -25,6 +26,8 @@ if TYPE_CHECKING:
|
||||||
|
|
||||||
MYCLOUD_LOGOFF_URL = "https://account.ultimaker.com/logoff?utm_source=cura&utm_medium=software&utm_campaign=change-account-before-adding-printers"
|
MYCLOUD_LOGOFF_URL = "https://account.ultimaker.com/logoff?utm_source=cura&utm_medium=software&utm_campaign=change-account-before-adding-printers"
|
||||||
|
|
||||||
|
REFRESH_TOKEN_MAX_RETRIES = 15
|
||||||
|
REFRESH_TOKEN_RETRY_INTERVAL = 1000
|
||||||
|
|
||||||
class AuthorizationService:
|
class AuthorizationService:
|
||||||
"""The authorization service is responsible for handling the login flow, storing user credentials and providing
|
"""The authorization service is responsible for handling the login flow, storing user credentials and providing
|
||||||
|
@ -57,6 +60,12 @@ class AuthorizationService:
|
||||||
|
|
||||||
self.onAuthStateChanged.connect(self._authChanged)
|
self.onAuthStateChanged.connect(self._authChanged)
|
||||||
|
|
||||||
|
self._refresh_token_retries = 0
|
||||||
|
self._refresh_token_retry_timer = QTimer()
|
||||||
|
self._refresh_token_retry_timer.setInterval(REFRESH_TOKEN_RETRY_INTERVAL)
|
||||||
|
self._refresh_token_retry_timer.setSingleShot(True)
|
||||||
|
self._refresh_token_retry_timer.timeout.connect(self.refreshAccessToken)
|
||||||
|
|
||||||
def _authChanged(self, logged_in):
|
def _authChanged(self, logged_in):
|
||||||
if logged_in and self._unable_to_get_data_message is not None:
|
if logged_in and self._unable_to_get_data_message is not None:
|
||||||
self._unable_to_get_data_message.hide()
|
self._unable_to_get_data_message.hide()
|
||||||
|
@ -167,16 +176,29 @@ class AuthorizationService:
|
||||||
return
|
return
|
||||||
|
|
||||||
def process_auth_data(response: AuthenticationResponse) -> None:
|
def process_auth_data(response: AuthenticationResponse) -> None:
|
||||||
|
self._currently_refreshing_token = False
|
||||||
|
|
||||||
if response.success:
|
if response.success:
|
||||||
|
self._refresh_token_retries = 0
|
||||||
self._storeAuthData(response)
|
self._storeAuthData(response)
|
||||||
|
HttpRequestManager.getInstance().setDelayRequests(False)
|
||||||
self.onAuthStateChanged.emit(logged_in = True)
|
self.onAuthStateChanged.emit(logged_in = True)
|
||||||
else:
|
else:
|
||||||
Logger.warning("Failed to get a new access token from the server.")
|
if self._refresh_token_retries >= REFRESH_TOKEN_MAX_RETRIES:
|
||||||
|
self._refresh_token_retries = 0
|
||||||
|
Logger.warning("Failed to get a new access token from the server, giving up.")
|
||||||
|
HttpRequestManager.getInstance().setDelayRequests(False)
|
||||||
self.onAuthStateChanged.emit(logged_in = False)
|
self.onAuthStateChanged.emit(logged_in = False)
|
||||||
|
else:
|
||||||
|
# Retry a bit later, network may be offline right now and will hopefully be back soon
|
||||||
|
Logger.warning("Failed to get a new access token from the server, retrying later.")
|
||||||
|
self._refresh_token_retries += 1
|
||||||
|
self._refresh_token_retry_timer.start()
|
||||||
|
|
||||||
if self._currently_refreshing_token:
|
if self._currently_refreshing_token:
|
||||||
Logger.debug("Was already busy refreshing token. Do not start a new request.")
|
Logger.debug("Was already busy refreshing token. Do not start a new request.")
|
||||||
return
|
return
|
||||||
|
HttpRequestManager.getInstance().setDelayRequests(True)
|
||||||
self._currently_refreshing_token = True
|
self._currently_refreshing_token = True
|
||||||
self._auth_helpers.getAccessTokenUsingRefreshToken(self._auth_data.refresh_token, process_auth_data)
|
self._auth_helpers.getAccessTokenUsingRefreshToken(self._auth_data.refresh_token, process_auth_data)
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,11 @@ from UM.Scene.Iterator import Iterator
|
||||||
from UM.Scene.SceneNode import SceneNode
|
from UM.Scene.SceneNode import SceneNode
|
||||||
from functools import cmp_to_key
|
from functools import cmp_to_key
|
||||||
|
|
||||||
|
from cura.HitChecker import HitChecker
|
||||||
|
from cura.PrintOrderManager import PrintOrderManager
|
||||||
|
from cura.Scene.CuraSceneNode import CuraSceneNode
|
||||||
|
|
||||||
|
|
||||||
class OneAtATimeIterator(Iterator.Iterator):
|
class OneAtATimeIterator(Iterator.Iterator):
|
||||||
"""Iterator that returns a list of nodes in the order that they need to be printed
|
"""Iterator that returns a list of nodes in the order that they need to be printed
|
||||||
|
|
||||||
|
@ -16,8 +21,6 @@ class OneAtATimeIterator(Iterator.Iterator):
|
||||||
|
|
||||||
def __init__(self, scene_node) -> None:
|
def __init__(self, scene_node) -> None:
|
||||||
super().__init__(scene_node) # Call super to make multiple inheritance work.
|
super().__init__(scene_node) # Call super to make multiple inheritance work.
|
||||||
self._hit_map = [[]] # type: List[List[bool]] # For each node, which other nodes this hits. A grid of booleans on which nodes hit which.
|
|
||||||
self._original_node_list = [] # type: List[SceneNode] # The nodes that need to be checked for collisions.
|
|
||||||
|
|
||||||
def _fillStack(self) -> None:
|
def _fillStack(self) -> None:
|
||||||
"""Fills the ``_node_stack`` with a list of scene nodes that need to be printed in order. """
|
"""Fills the ``_node_stack`` with a list of scene nodes that need to be printed in order. """
|
||||||
|
@ -38,104 +41,50 @@ class OneAtATimeIterator(Iterator.Iterator):
|
||||||
self._node_stack = node_list[:]
|
self._node_stack = node_list[:]
|
||||||
return
|
return
|
||||||
|
|
||||||
# Copy the list
|
hit_checker = HitChecker(node_list)
|
||||||
self._original_node_list = node_list[:]
|
|
||||||
|
|
||||||
# Initialise the hit map (pre-compute all hits between all objects)
|
if PrintOrderManager.isUserDefinedPrintOrderEnabled():
|
||||||
self._hit_map = [[self._checkHit(i, j) for i in node_list] for j in node_list]
|
self._node_stack = self._getNodesOrderedByUser(hit_checker, node_list)
|
||||||
|
else:
|
||||||
|
self._node_stack = self._getNodesOrderedAutomatically(hit_checker, node_list)
|
||||||
|
|
||||||
# Check if we have to files that block each other. If this is the case, there is no solution!
|
# update print orders so that user can try to arrange the nodes automatically first
|
||||||
for a in range(0, len(node_list)):
|
# and if result is not satisfactory he/she can switch to manual mode and change it
|
||||||
for b in range(0, len(node_list)):
|
for index, node in enumerate(self._node_stack):
|
||||||
if a != b and self._hit_map[a][b] and self._hit_map[b][a]:
|
node.printOrder = index + 1
|
||||||
return
|
|
||||||
|
@staticmethod
|
||||||
|
def _getNodesOrderedByUser(hit_checker: HitChecker, node_list: List[CuraSceneNode]) -> List[CuraSceneNode]:
|
||||||
|
nodes_ordered_by_user = sorted(node_list, key=lambda n: n.printOrder)
|
||||||
|
if hit_checker.canPrintNodesInProvidedOrder(nodes_ordered_by_user):
|
||||||
|
return nodes_ordered_by_user
|
||||||
|
return [] # No solution
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _getNodesOrderedAutomatically(hit_checker: HitChecker, node_list: List[CuraSceneNode]) -> List[CuraSceneNode]:
|
||||||
|
# Check if we have two files that block each other. If this is the case, there is no solution!
|
||||||
|
if hit_checker.anyTwoNodesBlockEachOther(node_list):
|
||||||
|
return [] # No solution
|
||||||
|
|
||||||
# Sort the original list so that items that block the most other objects are at the beginning.
|
# Sort the original list so that items that block the most other objects are at the beginning.
|
||||||
# This does not decrease the worst case running time, but should improve it in most cases.
|
# This does not decrease the worst case running time, but should improve it in most cases.
|
||||||
sorted(node_list, key = cmp_to_key(self._calculateScore))
|
node_list = sorted(node_list, key = cmp_to_key(hit_checker.calculateScore))
|
||||||
|
|
||||||
todo_node_list = [_ObjectOrder([], node_list)]
|
todo_node_list = [_ObjectOrder([], node_list)]
|
||||||
while len(todo_node_list) > 0:
|
while len(todo_node_list) > 0:
|
||||||
current = todo_node_list.pop()
|
current = todo_node_list.pop()
|
||||||
for node in current.todo:
|
for node in current.todo:
|
||||||
# Check if the object can be placed with what we have and still allows for a solution in the future
|
# Check if the object can be placed with what we have and still allows for a solution in the future
|
||||||
if not self._checkHitMultiple(node, current.order) and not self._checkBlockMultiple(node, current.todo):
|
if hit_checker.canPrintAfter(node, current.order) and hit_checker.canPrintBefore(node, current.todo):
|
||||||
# We found a possible result. Create new todo & order list.
|
# We found a possible result. Create new todo & order list.
|
||||||
new_todo_list = current.todo[:]
|
new_todo_list = current.todo[:]
|
||||||
new_todo_list.remove(node)
|
new_todo_list.remove(node)
|
||||||
new_order = current.order[:] + [node]
|
new_order = current.order[:] + [node]
|
||||||
if len(new_todo_list) == 0:
|
if len(new_todo_list) == 0:
|
||||||
# We have no more nodes to check, so quit looking.
|
# We have no more nodes to check, so quit looking.
|
||||||
self._node_stack = new_order
|
return new_order # Solution found!
|
||||||
return
|
|
||||||
todo_node_list.append(_ObjectOrder(new_order, new_todo_list))
|
todo_node_list.append(_ObjectOrder(new_order, new_todo_list))
|
||||||
self._node_stack = [] #No result found!
|
return [] # No result found!
|
||||||
|
|
||||||
|
|
||||||
# Check if first object can be printed before the provided list (using the hit map)
|
|
||||||
def _checkHitMultiple(self, node: SceneNode, other_nodes: List[SceneNode]) -> bool:
|
|
||||||
node_index = self._original_node_list.index(node)
|
|
||||||
for other_node in other_nodes:
|
|
||||||
other_node_index = self._original_node_list.index(other_node)
|
|
||||||
if self._hit_map[node_index][other_node_index]:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def _checkBlockMultiple(self, node: SceneNode, other_nodes: List[SceneNode]) -> bool:
|
|
||||||
"""Check for a node whether it hits any of the other nodes.
|
|
||||||
|
|
||||||
:param node: The node to check whether it collides with the other nodes.
|
|
||||||
:param other_nodes: The nodes to check for collisions.
|
|
||||||
:return: returns collision between nodes
|
|
||||||
"""
|
|
||||||
|
|
||||||
node_index = self._original_node_list.index(node)
|
|
||||||
for other_node in other_nodes:
|
|
||||||
other_node_index = self._original_node_list.index(other_node)
|
|
||||||
if self._hit_map[other_node_index][node_index] and node_index != other_node_index:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def _calculateScore(self, a: SceneNode, b: SceneNode) -> int:
|
|
||||||
"""Calculate score simply sums the number of other objects it 'blocks'
|
|
||||||
|
|
||||||
:param a: node
|
|
||||||
:param b: node
|
|
||||||
:return: sum of the number of other objects
|
|
||||||
"""
|
|
||||||
|
|
||||||
score_a = sum(self._hit_map[self._original_node_list.index(a)])
|
|
||||||
score_b = sum(self._hit_map[self._original_node_list.index(b)])
|
|
||||||
return score_a - score_b
|
|
||||||
|
|
||||||
def _checkHit(self, a: SceneNode, b: SceneNode) -> bool:
|
|
||||||
"""Checks if a can be printed before b
|
|
||||||
|
|
||||||
:param a: node
|
|
||||||
:param b: node
|
|
||||||
:return: true if a can be printed before b
|
|
||||||
"""
|
|
||||||
|
|
||||||
if a == b:
|
|
||||||
return False
|
|
||||||
|
|
||||||
a_hit_hull = a.callDecoration("getConvexHullBoundary")
|
|
||||||
b_hit_hull = b.callDecoration("getConvexHullHeadFull")
|
|
||||||
overlap = a_hit_hull.intersectsPolygon(b_hit_hull)
|
|
||||||
|
|
||||||
if overlap:
|
|
||||||
return True
|
|
||||||
|
|
||||||
# Adhesion areas must never overlap, regardless of printing order
|
|
||||||
# This would cause over-extrusion
|
|
||||||
a_hit_hull = a.callDecoration("getAdhesionArea")
|
|
||||||
b_hit_hull = b.callDecoration("getAdhesionArea")
|
|
||||||
overlap = a_hit_hull.intersectsPolygon(b_hit_hull)
|
|
||||||
|
|
||||||
if overlap:
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
class _ObjectOrder:
|
class _ObjectOrder:
|
||||||
|
|
|
@ -38,7 +38,14 @@ class PlatformPhysics:
|
||||||
self._minimum_gap = 2 # It is a minimum distance (in mm) between two models, applicable for small models
|
self._minimum_gap = 2 # It is a minimum distance (in mm) between two models, applicable for small models
|
||||||
|
|
||||||
Application.getInstance().getPreferences().addPreference("physics/automatic_push_free", False)
|
Application.getInstance().getPreferences().addPreference("physics/automatic_push_free", False)
|
||||||
Application.getInstance().getPreferences().addPreference("physics/automatic_drop_down", True)
|
Application.getInstance().getPreferences().addPreference("physics/automatic_drop_down", False)
|
||||||
|
self._app_per_model_drop = Application.getInstance().getPreferences().getValue("physics/automatic_drop_down")
|
||||||
|
|
||||||
|
def getAppPerModelDropDown(self):
|
||||||
|
return self._app_per_model_drop
|
||||||
|
|
||||||
|
def setAppPerModelDropDown(self, drop_to_buildplate):
|
||||||
|
self._app_per_model_drop = drop_to_buildplate
|
||||||
|
|
||||||
def _onSceneChanged(self, source):
|
def _onSceneChanged(self, source):
|
||||||
if not source.callDecoration("isSliceable"):
|
if not source.callDecoration("isSliceable"):
|
||||||
|
@ -71,6 +78,7 @@ class PlatformPhysics:
|
||||||
# We try to shuffle all the nodes to prevent "locked" situations, where iteration B inverts iteration A.
|
# We try to shuffle all the nodes to prevent "locked" situations, where iteration B inverts iteration A.
|
||||||
# By shuffling the order of the nodes, this might happen a few times, but at some point it will resolve.
|
# By shuffling the order of the nodes, this might happen a few times, but at some point it will resolve.
|
||||||
random.shuffle(nodes)
|
random.shuffle(nodes)
|
||||||
|
|
||||||
for node in nodes:
|
for node in nodes:
|
||||||
if node is root or not isinstance(node, SceneNode) or node.getBoundingBox() is None:
|
if node is root or not isinstance(node, SceneNode) or node.getBoundingBox() is None:
|
||||||
continue
|
continue
|
||||||
|
@ -80,7 +88,10 @@ class PlatformPhysics:
|
||||||
# Move it downwards if bottom is above platform
|
# Move it downwards if bottom is above platform
|
||||||
move_vector = Vector()
|
move_vector = Vector()
|
||||||
|
|
||||||
if node.getSetting(SceneNodeSettings.AutoDropDown, app_automatic_drop_down) and not (node.getParent() and node.getParent().callDecoration("isGroup") or node.getParent() != root) and node.isEnabled(): #If an object is grouped, don't move it down
|
# if per model drop is different then app_automatic_drop, in case of 3mf loading when user changes this setting for that model
|
||||||
|
if (self._app_per_model_drop != app_automatic_drop_down):
|
||||||
|
node.setSetting(SceneNodeSettings.AutoDropDown, self._app_per_model_drop)
|
||||||
|
if node.getSetting(SceneNodeSettings.AutoDropDown, self._app_per_model_drop) and not (node.getParent() and node.getParent().callDecoration("isGroup") or node.getParent() != root) and node.isEnabled(): #If an object is grouped, don't move it down
|
||||||
z_offset = node.callDecoration("getZOffset") if node.getDecorator(ZOffsetDecorator.ZOffsetDecorator) else 0
|
z_offset = node.callDecoration("getZOffset") if node.getDecorator(ZOffsetDecorator.ZOffsetDecorator) else 0
|
||||||
move_vector = move_vector.set(y = -bbox.bottom + z_offset)
|
move_vector = move_vector.set(y = -bbox.bottom + z_offset)
|
||||||
|
|
||||||
|
@ -168,6 +179,8 @@ class PlatformPhysics:
|
||||||
op = PlatformPhysicsOperation.PlatformPhysicsOperation(node, move_vector)
|
op = PlatformPhysicsOperation.PlatformPhysicsOperation(node, move_vector)
|
||||||
op.push()
|
op.push()
|
||||||
|
|
||||||
|
# setting this drop to model same as app_automatic_drop_down
|
||||||
|
self._app_per_model_drop = app_automatic_drop_down
|
||||||
# After moving, we have to evaluate the boundary checks for nodes
|
# After moving, we have to evaluate the boundary checks for nodes
|
||||||
build_volume.updateNodeBoundaryCheck()
|
build_volume.updateNodeBoundaryCheck()
|
||||||
|
|
||||||
|
|
171
cura/PrintOrderManager.py
Normal file
171
cura/PrintOrderManager.py
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
from typing import List, Callable, Optional, Any
|
||||||
|
|
||||||
|
from PyQt6.QtCore import pyqtProperty, pyqtSignal, QObject, pyqtSlot
|
||||||
|
from UM.Application import Application
|
||||||
|
from UM.Scene.Selection import Selection
|
||||||
|
|
||||||
|
from cura.Scene.CuraSceneNode import CuraSceneNode
|
||||||
|
|
||||||
|
|
||||||
|
class PrintOrderManager(QObject):
|
||||||
|
"""Allows to order the object list to set the print sequence manually"""
|
||||||
|
|
||||||
|
def __init__(self, get_nodes: Callable[[], List[CuraSceneNode]]) -> None:
|
||||||
|
super().__init__()
|
||||||
|
self._get_nodes = get_nodes
|
||||||
|
self._configureEvents()
|
||||||
|
|
||||||
|
_settingsChanged = pyqtSignal()
|
||||||
|
_uiActionsOutdated = pyqtSignal()
|
||||||
|
printOrderChanged = pyqtSignal()
|
||||||
|
|
||||||
|
@pyqtSlot()
|
||||||
|
def swapSelectedAndPreviousNodes(self) -> None:
|
||||||
|
selected_node, previous_node, next_node = self._getSelectedAndNeighborNodes()
|
||||||
|
self._swapPrintOrders(selected_node, previous_node)
|
||||||
|
|
||||||
|
@pyqtSlot()
|
||||||
|
def swapSelectedAndNextNodes(self) -> None:
|
||||||
|
selected_node, previous_node, next_node = self._getSelectedAndNeighborNodes()
|
||||||
|
self._swapPrintOrders(selected_node, next_node)
|
||||||
|
|
||||||
|
@pyqtProperty(str, notify=_uiActionsOutdated)
|
||||||
|
def previousNodeName(self) -> str:
|
||||||
|
selected_node, previous_node, next_node = self._getSelectedAndNeighborNodes()
|
||||||
|
return self._getNodeName(previous_node)
|
||||||
|
|
||||||
|
@pyqtProperty(str, notify=_uiActionsOutdated)
|
||||||
|
def nextNodeName(self) -> str:
|
||||||
|
selected_node, previous_node, next_node = self._getSelectedAndNeighborNodes()
|
||||||
|
return self._getNodeName(next_node)
|
||||||
|
|
||||||
|
@pyqtProperty(bool, notify=_uiActionsOutdated)
|
||||||
|
def shouldEnablePrintBeforeAction(self) -> bool:
|
||||||
|
selected_node, previous_node, next_node = self._getSelectedAndNeighborNodes()
|
||||||
|
can_swap_with_previous_node = selected_node is not None and previous_node is not None
|
||||||
|
return can_swap_with_previous_node
|
||||||
|
|
||||||
|
@pyqtProperty(bool, notify=_uiActionsOutdated)
|
||||||
|
def shouldEnablePrintAfterAction(self) -> bool:
|
||||||
|
selected_node, previous_node, next_node = self._getSelectedAndNeighborNodes()
|
||||||
|
can_swap_with_next_node = selected_node is not None and next_node is not None
|
||||||
|
return can_swap_with_next_node
|
||||||
|
|
||||||
|
@pyqtProperty(bool, notify=_settingsChanged)
|
||||||
|
def shouldShowEditPrintOrderActions(self) -> bool:
|
||||||
|
return PrintOrderManager.isUserDefinedPrintOrderEnabled()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def isUserDefinedPrintOrderEnabled() -> bool:
|
||||||
|
stack = Application.getInstance().getGlobalContainerStack()
|
||||||
|
is_enabled = stack and \
|
||||||
|
stack.getProperty("print_sequence", "value") == "one_at_a_time" and \
|
||||||
|
stack.getProperty("user_defined_print_order_enabled", "value")
|
||||||
|
return bool(is_enabled)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def initializePrintOrders(nodes: List[CuraSceneNode]) -> None:
|
||||||
|
"""Just created (loaded from file) nodes have print order 0.
|
||||||
|
|
||||||
|
This method initializes print orders with max value to put nodes at the end of object list"""
|
||||||
|
max_print_order = max(map(lambda n: n.printOrder, nodes), default=0)
|
||||||
|
for node in nodes:
|
||||||
|
if node.printOrder == 0:
|
||||||
|
max_print_order += 1
|
||||||
|
node.printOrder = max_print_order
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def updatePrintOrdersAfterGroupOperation(
|
||||||
|
all_nodes: List[CuraSceneNode],
|
||||||
|
group_node: CuraSceneNode,
|
||||||
|
grouped_nodes: List[CuraSceneNode]
|
||||||
|
) -> None:
|
||||||
|
group_node.printOrder = min(map(lambda n: n.printOrder, grouped_nodes))
|
||||||
|
|
||||||
|
all_nodes.append(group_node)
|
||||||
|
for node in grouped_nodes:
|
||||||
|
all_nodes.remove(node)
|
||||||
|
|
||||||
|
# reassign print orders so there won't be gaps like 1 2 5 6 7
|
||||||
|
sorted_nodes = sorted(all_nodes, key=lambda n: n.printOrder)
|
||||||
|
for i, node in enumerate(sorted_nodes):
|
||||||
|
node.printOrder = i + 1
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def updatePrintOrdersAfterUngroupOperation(
|
||||||
|
all_nodes: List[CuraSceneNode],
|
||||||
|
group_node: CuraSceneNode,
|
||||||
|
ungrouped_nodes: List[CuraSceneNode]
|
||||||
|
) -> None:
|
||||||
|
all_nodes.remove(group_node)
|
||||||
|
nodes_to_update_print_order = filter(lambda n: n.printOrder > group_node.printOrder, all_nodes)
|
||||||
|
for node in nodes_to_update_print_order:
|
||||||
|
node.printOrder += len(ungrouped_nodes) - 1
|
||||||
|
|
||||||
|
for i, child in enumerate(ungrouped_nodes):
|
||||||
|
child.printOrder = group_node.printOrder + i
|
||||||
|
all_nodes.append(child)
|
||||||
|
|
||||||
|
def _swapPrintOrders(self, node1: CuraSceneNode, node2: CuraSceneNode) -> None:
|
||||||
|
if node1 and node2:
|
||||||
|
node1.printOrder, node2.printOrder = node2.printOrder, node1.printOrder # swap print orders
|
||||||
|
self.printOrderChanged.emit() # update object list first
|
||||||
|
self._uiActionsOutdated.emit() # then update UI actions
|
||||||
|
|
||||||
|
def _getSelectedAndNeighborNodes(self
|
||||||
|
) -> (Optional[CuraSceneNode], Optional[CuraSceneNode], Optional[CuraSceneNode]):
|
||||||
|
nodes = self._get_nodes()
|
||||||
|
ordered_nodes = sorted(nodes, key=lambda n: n.printOrder)
|
||||||
|
selected_node = PrintOrderManager._getSingleSelectedNode()
|
||||||
|
if selected_node and selected_node in ordered_nodes:
|
||||||
|
selected_node_index = ordered_nodes.index(selected_node)
|
||||||
|
else:
|
||||||
|
selected_node_index = None
|
||||||
|
|
||||||
|
if selected_node_index is not None and selected_node_index - 1 >= 0:
|
||||||
|
previous_node = ordered_nodes[selected_node_index - 1]
|
||||||
|
else:
|
||||||
|
previous_node = None
|
||||||
|
|
||||||
|
if selected_node_index is not None and selected_node_index + 1 < len(ordered_nodes):
|
||||||
|
next_node = ordered_nodes[selected_node_index + 1]
|
||||||
|
else:
|
||||||
|
next_node = None
|
||||||
|
|
||||||
|
return selected_node, previous_node, next_node
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _getNodeName(node: CuraSceneNode, max_length: int = 30) -> str:
|
||||||
|
node_name = node.getName() if node else ""
|
||||||
|
truncated_node_name = node_name[:max_length]
|
||||||
|
return truncated_node_name
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _getSingleSelectedNode() -> Optional[CuraSceneNode]:
|
||||||
|
if len(Selection.getAllSelectedObjects()) == 1:
|
||||||
|
selected_node = Selection.getSelectedObject(0)
|
||||||
|
return selected_node
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _configureEvents(self) -> None:
|
||||||
|
Selection.selectionChanged.connect(self._onSelectionChanged)
|
||||||
|
self._global_stack = None
|
||||||
|
Application.getInstance().globalContainerStackChanged.connect(self._onGlobalStackChanged)
|
||||||
|
self._onGlobalStackChanged()
|
||||||
|
|
||||||
|
def _onGlobalStackChanged(self) -> None:
|
||||||
|
if self._global_stack:
|
||||||
|
self._global_stack.propertyChanged.disconnect(self._onSettingsChanged)
|
||||||
|
self._global_stack.containersChanged.disconnect(self._onSettingsChanged)
|
||||||
|
|
||||||
|
self._global_stack = Application.getInstance().getGlobalContainerStack()
|
||||||
|
|
||||||
|
if self._global_stack:
|
||||||
|
self._global_stack.propertyChanged.connect(self._onSettingsChanged)
|
||||||
|
self._global_stack.containersChanged.connect(self._onSettingsChanged)
|
||||||
|
|
||||||
|
def _onSettingsChanged(self, *args: Any) -> None:
|
||||||
|
self._settingsChanged.emit()
|
||||||
|
|
||||||
|
def _onSelectionChanged(self) -> None:
|
||||||
|
self._uiActionsOutdated.emit()
|
|
@ -25,10 +25,19 @@ class CuraSceneNode(SceneNode):
|
||||||
if not no_setting_override:
|
if not no_setting_override:
|
||||||
self.addDecorator(SettingOverrideDecorator()) # Now we always have a getActiveExtruderPosition, unless explicitly disabled
|
self.addDecorator(SettingOverrideDecorator()) # Now we always have a getActiveExtruderPosition, unless explicitly disabled
|
||||||
self._outside_buildarea = False
|
self._outside_buildarea = False
|
||||||
|
self._print_order = 0
|
||||||
|
|
||||||
def setOutsideBuildArea(self, new_value: bool) -> None:
|
def setOutsideBuildArea(self, new_value: bool) -> None:
|
||||||
self._outside_buildarea = new_value
|
self._outside_buildarea = new_value
|
||||||
|
|
||||||
|
@property
|
||||||
|
def printOrder(self):
|
||||||
|
return self._print_order
|
||||||
|
|
||||||
|
@printOrder.setter
|
||||||
|
def printOrder(self, new_value):
|
||||||
|
self._print_order = new_value
|
||||||
|
|
||||||
def isOutsideBuildArea(self) -> bool:
|
def isOutsideBuildArea(self) -> bool:
|
||||||
return self._outside_buildarea or self.callDecoration("getBuildPlateNumber") < 0
|
return self._outside_buildarea or self.callDecoration("getBuildPlateNumber") < 0
|
||||||
|
|
||||||
|
@ -157,3 +166,6 @@ class CuraSceneNode(SceneNode):
|
||||||
|
|
||||||
def transformChanged(self) -> None:
|
def transformChanged(self) -> None:
|
||||||
self._transformChanged()
|
self._transformChanged()
|
||||||
|
|
||||||
|
def __repr__(self) -> str:
|
||||||
|
return "{print_order}. {name}".format(print_order = self._print_order, name = self.getName())
|
||||||
|
|
|
@ -316,7 +316,13 @@ class ExtruderManager(QObject):
|
||||||
# Starts with the adhesion extruder.
|
# Starts with the adhesion extruder.
|
||||||
adhesion_type = global_stack.getProperty("adhesion_type", "value")
|
adhesion_type = global_stack.getProperty("adhesion_type", "value")
|
||||||
if adhesion_type in {"skirt", "brim"}:
|
if adhesion_type in {"skirt", "brim"}:
|
||||||
return max(0, int(global_stack.getProperty("skirt_brim_extruder_nr", "value"))) # optional skirt/brim extruder defaults to zero
|
skirt_brim_extruder_nr = global_stack.getProperty("skirt_brim_extruder_nr", "value")
|
||||||
|
# if the skirt_brim_extruder_nr is -1, then we use the first used extruder
|
||||||
|
if skirt_brim_extruder_nr == -1:
|
||||||
|
used_extruders = self.getUsedExtruderStacks()
|
||||||
|
return used_extruders[0].position
|
||||||
|
else:
|
||||||
|
return skirt_brim_extruder_nr
|
||||||
if adhesion_type == "raft":
|
if adhesion_type == "raft":
|
||||||
return global_stack.getProperty("raft_base_extruder_nr", "value")
|
return global_stack.getProperty("raft_base_extruder_nr", "value")
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import json
|
||||||
import os
|
import os
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
|
|
||||||
|
from PyQt6.QtCore import QUrl
|
||||||
from PyQt6.QtNetwork import QLocalServer, QLocalSocket
|
from PyQt6.QtNetwork import QLocalServer, QLocalSocket
|
||||||
|
|
||||||
from UM.Qt.QtApplication import QtApplication # For typing.
|
from UM.Qt.QtApplication import QtApplication # For typing.
|
||||||
|
@ -12,9 +13,10 @@ from UM.Logger import Logger
|
||||||
|
|
||||||
|
|
||||||
class SingleInstance:
|
class SingleInstance:
|
||||||
def __init__(self, application: QtApplication, files_to_open: Optional[List[str]]) -> None:
|
def __init__(self, application: QtApplication, files_to_open: Optional[List[str]], url_to_open: Optional[List[str]]) -> None:
|
||||||
self._application = application
|
self._application = application
|
||||||
self._files_to_open = files_to_open
|
self._files_to_open = files_to_open
|
||||||
|
self._url_to_open = url_to_open
|
||||||
|
|
||||||
self._single_instance_server = None
|
self._single_instance_server = None
|
||||||
|
|
||||||
|
@ -33,7 +35,7 @@ class SingleInstance:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# We only send the files that need to be opened.
|
# We only send the files that need to be opened.
|
||||||
if not self._files_to_open:
|
if not self._files_to_open and not self._url_to_open:
|
||||||
Logger.log("i", "No file need to be opened, do nothing.")
|
Logger.log("i", "No file need to be opened, do nothing.")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -55,6 +57,10 @@ class SingleInstance:
|
||||||
payload = {"command": "open", "filePath": os.path.abspath(filename)}
|
payload = {"command": "open", "filePath": os.path.abspath(filename)}
|
||||||
single_instance_socket.write(bytes(json.dumps(payload) + "\n", encoding = "ascii"))
|
single_instance_socket.write(bytes(json.dumps(payload) + "\n", encoding = "ascii"))
|
||||||
|
|
||||||
|
for url in self._url_to_open:
|
||||||
|
payload = {"command": "open-url", "urlPath": url.toString()}
|
||||||
|
single_instance_socket.write(bytes(json.dumps(payload) + "\n", encoding="ascii"))
|
||||||
|
|
||||||
payload = {"command": "close-connection"}
|
payload = {"command": "close-connection"}
|
||||||
single_instance_socket.write(bytes(json.dumps(payload) + "\n", encoding="ascii"))
|
single_instance_socket.write(bytes(json.dumps(payload) + "\n", encoding="ascii"))
|
||||||
|
|
||||||
|
@ -94,6 +100,12 @@ class SingleInstance:
|
||||||
elif command == "open":
|
elif command == "open":
|
||||||
self._application.callLater(lambda f = payload["filePath"]: self._application._openFile(f))
|
self._application.callLater(lambda f = payload["filePath"]: self._application._openFile(f))
|
||||||
|
|
||||||
|
#command: Load a url link in Cura
|
||||||
|
elif command == "open-url":
|
||||||
|
url = QUrl(payload["urlPath"])
|
||||||
|
self._application.callLater(lambda: self._application._openUrl(url))
|
||||||
|
|
||||||
|
|
||||||
# Command: Activate the window and bring it to the top.
|
# Command: Activate the window and bring it to the top.
|
||||||
elif command == "focus":
|
elif command == "focus":
|
||||||
# Operating systems these days prevent windows from moving around by themselves.
|
# Operating systems these days prevent windows from moving around by themselves.
|
||||||
|
|
|
@ -14,6 +14,9 @@ from UM.Scene.SceneNode import SceneNode
|
||||||
from UM.Scene.Selection import Selection
|
from UM.Scene.Selection import Selection
|
||||||
from UM.i18n import i18nCatalog
|
from UM.i18n import i18nCatalog
|
||||||
|
|
||||||
|
from cura.PrintOrderManager import PrintOrderManager
|
||||||
|
from cura.Scene.CuraSceneNode import CuraSceneNode
|
||||||
|
|
||||||
catalog = i18nCatalog("cura")
|
catalog = i18nCatalog("cura")
|
||||||
|
|
||||||
|
|
||||||
|
@ -76,6 +79,9 @@ class ObjectsModel(ListModel):
|
||||||
self._build_plate_number = nr
|
self._build_plate_number = nr
|
||||||
self._update()
|
self._update()
|
||||||
|
|
||||||
|
def getNodes(self) -> List[CuraSceneNode]:
|
||||||
|
return list(map(lambda n: n["node"], self.items))
|
||||||
|
|
||||||
def _updateSceneDelayed(self, source) -> None:
|
def _updateSceneDelayed(self, source) -> None:
|
||||||
if not isinstance(source, Camera):
|
if not isinstance(source, Camera):
|
||||||
self._update_timer.start()
|
self._update_timer.start()
|
||||||
|
@ -175,6 +181,10 @@ class ObjectsModel(ListModel):
|
||||||
|
|
||||||
all_nodes = self._renameNodes(name_to_node_info_dict)
|
all_nodes = self._renameNodes(name_to_node_info_dict)
|
||||||
|
|
||||||
|
user_defined_print_order_enabled = PrintOrderManager.isUserDefinedPrintOrderEnabled()
|
||||||
|
if user_defined_print_order_enabled:
|
||||||
|
PrintOrderManager.initializePrintOrders(all_nodes)
|
||||||
|
|
||||||
for node in all_nodes:
|
for node in all_nodes:
|
||||||
if hasattr(node, "isOutsideBuildArea"):
|
if hasattr(node, "isOutsideBuildArea"):
|
||||||
is_outside_build_area = node.isOutsideBuildArea() # type: ignore
|
is_outside_build_area = node.isOutsideBuildArea() # type: ignore
|
||||||
|
@ -223,8 +233,13 @@ class ObjectsModel(ListModel):
|
||||||
# for anti overhang meshes and groups the extruder nr is irrelevant
|
# for anti overhang meshes and groups the extruder nr is irrelevant
|
||||||
extruder_number = -1
|
extruder_number = -1
|
||||||
|
|
||||||
|
if not user_defined_print_order_enabled:
|
||||||
|
name = node.getName()
|
||||||
|
else:
|
||||||
|
name = "{print_order}. {name}".format(print_order = node.printOrder, name = node.getName())
|
||||||
|
|
||||||
nodes.append({
|
nodes.append({
|
||||||
"name": node.getName(),
|
"name": name,
|
||||||
"selected": Selection.isSelected(node),
|
"selected": Selection.isSelected(node),
|
||||||
"outside_build_area": is_outside_build_area,
|
"outside_build_area": is_outside_build_area,
|
||||||
"buildplate_number": node_build_plate_number,
|
"buildplate_number": node_build_plate_number,
|
||||||
|
@ -234,5 +249,5 @@ class ObjectsModel(ListModel):
|
||||||
"node": node
|
"node": node
|
||||||
})
|
})
|
||||||
|
|
||||||
nodes = sorted(nodes, key=lambda n: n["name"])
|
nodes = sorted(nodes, key=lambda n: n["name"] if not user_defined_print_order_enabled else n["node"].printOrder)
|
||||||
self.setItems(nodes)
|
self.setItems(nodes)
|
||||||
|
|
|
@ -177,6 +177,9 @@ class ThreeMFReader(MeshReader):
|
||||||
else:
|
else:
|
||||||
Logger.log("w", "Unable to find extruder in position %s", setting_value)
|
Logger.log("w", "Unable to find extruder in position %s", setting_value)
|
||||||
continue
|
continue
|
||||||
|
if key == "print_order":
|
||||||
|
um_node.printOrder = int(setting_value)
|
||||||
|
continue
|
||||||
if key in known_setting_keys:
|
if key in known_setting_keys:
|
||||||
setting_container.setProperty(key, "value", setting_value)
|
setting_container.setProperty(key, "value", setting_value)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -299,6 +299,11 @@ class WorkspaceDialog(QObject):
|
||||||
|
|
||||||
Application.getInstance().getBackend().close()
|
Application.getInstance().getBackend().close()
|
||||||
|
|
||||||
|
@pyqtSlot(bool)
|
||||||
|
def setDropToBuildPlateForModel(self, drop_to_buildplate: bool) -> None:
|
||||||
|
CuraApplication.getInstance().getWorkplaceDropToBuildplate(drop_to_buildplate)
|
||||||
|
|
||||||
|
|
||||||
def setMaterialConflict(self, material_conflict: bool) -> None:
|
def setMaterialConflict(self, material_conflict: bool) -> None:
|
||||||
if self._has_material_conflict != material_conflict:
|
if self._has_material_conflict != material_conflict:
|
||||||
self._has_material_conflict = material_conflict
|
self._has_material_conflict = material_conflict
|
||||||
|
|
|
@ -300,6 +300,25 @@ UM.Dialog
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Row
|
||||||
|
{
|
||||||
|
id: dropToBuildPlate
|
||||||
|
width: parent.width
|
||||||
|
height: childrenRect.height
|
||||||
|
spacing: UM.Theme.getSize("default_margin").width
|
||||||
|
UM.CheckBox
|
||||||
|
{
|
||||||
|
id: checkDropModels
|
||||||
|
text: catalog.i18nc("@text:window", "Drop models to buildplate")
|
||||||
|
checked: UM.Preferences.getValue("physics/automatic_drop_down")
|
||||||
|
onCheckedChanged: manager.setDropToBuildPlateForModel(checked)
|
||||||
|
}
|
||||||
|
function reloadValue()
|
||||||
|
{
|
||||||
|
checkDropModels.checked = UM.Preferences.getValue("physics/automatic_drop_down")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Row
|
Row
|
||||||
{
|
{
|
||||||
id: clearBuildPlateWarning
|
id: clearBuildPlateWarning
|
||||||
|
@ -422,6 +441,7 @@ UM.Dialog
|
||||||
materialSection.reloadValues()
|
materialSection.reloadValues()
|
||||||
profileSection.reloadValues()
|
profileSection.reloadValues()
|
||||||
printerSection.reloadValues()
|
printerSection.reloadValues()
|
||||||
|
dropToBuildPlate.reloadValue()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,16 +10,14 @@ from UM.Math.Vector import Vector
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
from UM.Math.Matrix import Matrix
|
from UM.Math.Matrix import Matrix
|
||||||
from UM.Application import Application
|
from UM.Application import Application
|
||||||
from UM.Message import Message
|
|
||||||
from UM.Resources import Resources
|
|
||||||
from UM.Scene.SceneNode import SceneNode
|
from UM.Scene.SceneNode import SceneNode
|
||||||
from UM.Settings.ContainerRegistry import ContainerRegistry
|
from UM.Settings.ContainerRegistry import ContainerRegistry
|
||||||
from UM.Settings.EmptyInstanceContainer import EmptyInstanceContainer
|
|
||||||
|
|
||||||
from cura.CuraApplication import CuraApplication
|
from cura.CuraApplication import CuraApplication
|
||||||
from cura.CuraPackageManager import CuraPackageManager
|
from cura.CuraPackageManager import CuraPackageManager
|
||||||
from cura.Settings import CuraContainerStack
|
from cura.Settings import CuraContainerStack
|
||||||
from cura.Utils.Threading import call_on_qt_thread
|
from cura.Utils.Threading import call_on_qt_thread
|
||||||
|
from cura.Scene.CuraSceneNode import CuraSceneNode
|
||||||
from cura.Snapshot import Snapshot
|
from cura.Snapshot import Snapshot
|
||||||
|
|
||||||
from PyQt6.QtCore import QBuffer
|
from PyQt6.QtCore import QBuffer
|
||||||
|
@ -137,6 +135,9 @@ class ThreeMFWriter(MeshWriter):
|
||||||
for key in changed_setting_keys:
|
for key in changed_setting_keys:
|
||||||
savitar_node.setSetting("cura:" + key, str(stack.getProperty(key, "value")))
|
savitar_node.setSetting("cura:" + key, str(stack.getProperty(key, "value")))
|
||||||
|
|
||||||
|
if isinstance(um_node, CuraSceneNode):
|
||||||
|
savitar_node.setSetting("cura:print_order", str(um_node.printOrder))
|
||||||
|
|
||||||
# Store the metadata.
|
# Store the metadata.
|
||||||
for key, value in um_node.metadata.items():
|
for key, value in um_node.metadata.items():
|
||||||
savitar_node.setSetting(key, value)
|
savitar_node.setSetting(key, value)
|
||||||
|
|
|
@ -76,6 +76,7 @@ class CuraEngineBackend(QObject, Backend):
|
||||||
self._default_engine_location = executable_name
|
self._default_engine_location = executable_name
|
||||||
|
|
||||||
search_path = [
|
search_path = [
|
||||||
|
os.path.abspath(os.path.join(os.path.dirname(sys.executable), "..", "Resources")),
|
||||||
os.path.abspath(os.path.dirname(sys.executable)),
|
os.path.abspath(os.path.dirname(sys.executable)),
|
||||||
os.path.abspath(os.path.join(os.path.dirname(sys.executable), "bin")),
|
os.path.abspath(os.path.join(os.path.dirname(sys.executable), "bin")),
|
||||||
os.path.abspath(os.path.join(os.path.dirname(sys.executable), "..")),
|
os.path.abspath(os.path.join(os.path.dirname(sys.executable), "..")),
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
# Copyright (c) 2021 Ultimaker B.V.
|
# Copyright (c) 2021 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
from UM.MimeTypeDatabase import MimeType, MimeTypeDatabase
|
|
||||||
from .src import DigitalFactoryFileProvider, DigitalFactoryOutputDevicePlugin, DigitalFactoryController
|
from .src import DigitalFactoryFileProvider, DigitalFactoryOutputDevicePlugin, DigitalFactoryController
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
import json
|
import json
|
||||||
from json import JSONDecodeError
|
from json import JSONDecodeError
|
||||||
import re
|
|
||||||
from time import time
|
from time import time
|
||||||
from typing import List, Any, Optional, Union, Type, Tuple, Dict, cast, TypeVar, Callable
|
from typing import List, Any, Optional, Union, Type, Tuple, Dict, cast, TypeVar, Callable
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@ from typing import List, Optional
|
||||||
|
|
||||||
from PyQt6.QtCore import Qt, pyqtSignal
|
from PyQt6.QtCore import Qt, pyqtSignal
|
||||||
|
|
||||||
from UM.Logger import Logger
|
|
||||||
from UM.Qt.ListModel import ListModel
|
from UM.Qt.ListModel import ListModel
|
||||||
from .DigitalFactoryProjectResponse import DigitalFactoryProjectResponse
|
from .DigitalFactoryProjectResponse import DigitalFactoryProjectResponse
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
from UM.i18n import i18nCatalog
|
from UM.i18n import i18nCatalog
|
||||||
from UM.Platform import Platform
|
|
||||||
|
|
||||||
from . import GCodeGzWriter
|
from . import GCodeGzWriter
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,6 @@ from UM.Settings.InstanceContainer import InstanceContainer
|
||||||
from cura.Machines.ContainerTree import ContainerTree
|
from cura.Machines.ContainerTree import ContainerTree
|
||||||
|
|
||||||
from UM.i18n import i18nCatalog
|
from UM.i18n import i18nCatalog
|
||||||
from cura.Settings.CuraStackBuilder import CuraStackBuilder
|
|
||||||
|
|
||||||
catalog = i18nCatalog("cura")
|
catalog = i18nCatalog("cura")
|
||||||
|
|
||||||
|
|
|
@ -3,12 +3,10 @@
|
||||||
|
|
||||||
from typing import Optional, TYPE_CHECKING, Dict, List
|
from typing import Optional, TYPE_CHECKING, Dict, List
|
||||||
|
|
||||||
from .Constants import PACKAGES_URL
|
|
||||||
from .PackageModel import PackageModel
|
from .PackageModel import PackageModel
|
||||||
from .RemotePackageList import RemotePackageList
|
from .RemotePackageList import RemotePackageList
|
||||||
from PyQt6.QtCore import pyqtSignal, QObject, pyqtProperty, QCoreApplication
|
from PyQt6.QtCore import pyqtSignal, QObject, pyqtProperty, QCoreApplication
|
||||||
|
|
||||||
from UM.TaskManagement.HttpRequestManager import HttpRequestManager # To request the package list from the API.
|
|
||||||
from UM.i18n import i18nCatalog
|
from UM.i18n import i18nCatalog
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
import re
|
import re
|
||||||
from enum import Enum
|
|
||||||
from typing import Any, cast, Dict, List, Optional
|
from typing import Any, cast, Dict, List, Optional
|
||||||
|
|
||||||
from PyQt6.QtCore import pyqtProperty, QObject, pyqtSignal, pyqtSlot
|
from PyQt6.QtCore import pyqtProperty, QObject, pyqtSignal, pyqtSlot
|
||||||
|
@ -12,7 +11,6 @@ from cura.CuraApplication import CuraApplication
|
||||||
from cura.CuraPackageManager import CuraPackageManager
|
from cura.CuraPackageManager import CuraPackageManager
|
||||||
from cura.Settings.CuraContainerRegistry import CuraContainerRegistry # To get names of materials we're compatible with.
|
from cura.Settings.CuraContainerRegistry import CuraContainerRegistry # To get names of materials we're compatible with.
|
||||||
from UM.i18n import i18nCatalog # To translate placeholder names if data is not present.
|
from UM.i18n import i18nCatalog # To translate placeholder names if data is not present.
|
||||||
from UM.Logger import Logger
|
|
||||||
from UM.PluginRegistry import PluginRegistry
|
from UM.PluginRegistry import PluginRegistry
|
||||||
|
|
||||||
catalog = i18nCatalog("cura")
|
catalog = i18nCatalog("cura")
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
# Description: This plugin is now an option in 'Display Info on LCD'
|
# Description: This plugin is now an option in 'Display Info on LCD'
|
||||||
|
|
||||||
from ..Script import Script
|
from ..Script import Script
|
||||||
from UM.Application import Application
|
|
||||||
from UM.Message import Message
|
from UM.Message import Message
|
||||||
|
|
||||||
class DisplayFilenameAndLayerOnLCD(Script):
|
class DisplayFilenameAndLayerOnLCD(Script):
|
||||||
|
|
|
@ -30,9 +30,6 @@
|
||||||
from ..Script import Script
|
from ..Script import Script
|
||||||
from UM.Application import Application
|
from UM.Application import Application
|
||||||
from UM.Qt.Duration import DurationFormat
|
from UM.Qt.Duration import DurationFormat
|
||||||
import UM.Util
|
|
||||||
import configparser
|
|
||||||
from UM.Preferences import Preferences
|
|
||||||
import time
|
import time
|
||||||
import datetime
|
import datetime
|
||||||
import math
|
import math
|
||||||
|
|
|
@ -7,8 +7,6 @@
|
||||||
|
|
||||||
from ..Script import Script
|
from ..Script import Script
|
||||||
|
|
||||||
import re
|
|
||||||
import datetime
|
|
||||||
from UM.Message import Message
|
from UM.Message import Message
|
||||||
|
|
||||||
class DisplayProgressOnLCD(Script):
|
class DisplayProgressOnLCD(Script):
|
||||||
|
|
|
@ -372,7 +372,10 @@ class SimulationView(CuraView):
|
||||||
self._minimum_path_num = min(self._minimum_path_num, self._current_path_num)
|
self._minimum_path_num = min(self._minimum_path_num, self._current_path_num)
|
||||||
# update _current time when the path is changed by user
|
# update _current time when the path is changed by user
|
||||||
if self._current_path_num < self._max_paths and round(self._current_path_num)== self._current_path_num:
|
if self._current_path_num < self._max_paths and round(self._current_path_num)== self._current_path_num:
|
||||||
self._current_time = self.cumulativeLineDuration()[int(self._current_path_num)]
|
actual_path_num = int(self._current_path_num)
|
||||||
|
cumulative_line_duration = self.cumulativeLineDuration()
|
||||||
|
if actual_path_num < len(cumulative_line_duration):
|
||||||
|
self._current_time = cumulative_line_duration[actual_path_num]
|
||||||
|
|
||||||
self._startUpdateTopLayers()
|
self._startUpdateTopLayers()
|
||||||
self.currentPathNumChanged.emit()
|
self.currentPathNumChanged.emit()
|
||||||
|
|
|
@ -5,7 +5,7 @@ import json
|
||||||
import os
|
import os
|
||||||
import platform
|
import platform
|
||||||
import time
|
import time
|
||||||
from typing import cast, Optional, Set, TYPE_CHECKING
|
from typing import Optional, Set, TYPE_CHECKING
|
||||||
|
|
||||||
from PyQt6.QtCore import pyqtSlot, QObject
|
from PyQt6.QtCore import pyqtSlot, QObject
|
||||||
from PyQt6.QtNetwork import QNetworkRequest
|
from PyQt6.QtNetwork import QNetworkRequest
|
||||||
|
|
|
@ -16,8 +16,6 @@ from UM.Application import Application
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
from UM.Message import Message
|
from UM.Message import Message
|
||||||
from UM.Math.Color import Color
|
from UM.Math.Color import Color
|
||||||
from UM.PluginRegistry import PluginRegistry
|
|
||||||
from UM.Platform import Platform
|
|
||||||
from UM.Event import Event
|
from UM.Event import Event
|
||||||
|
|
||||||
from UM.View.RenderBatch import RenderBatch
|
from UM.View.RenderBatch import RenderBatch
|
||||||
|
|
|
@ -22,7 +22,6 @@ from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
||||||
from UM.Scene.SceneNode import SceneNode
|
from UM.Scene.SceneNode import SceneNode
|
||||||
from UM.Settings.InstanceContainer import InstanceContainer
|
from UM.Settings.InstanceContainer import InstanceContainer
|
||||||
from cura.CuraApplication import CuraApplication
|
from cura.CuraApplication import CuraApplication
|
||||||
from cura.Settings.CuraStackBuilder import CuraStackBuilder
|
|
||||||
from cura.Settings.GlobalStack import GlobalStack
|
from cura.Settings.GlobalStack import GlobalStack
|
||||||
from cura.Utils.Threading import call_on_qt_thread
|
from cura.Utils.Threading import call_on_qt_thread
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,6 @@
|
||||||
from UM.Job import Job
|
from UM.Job import Job
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
|
|
||||||
from .avr_isp import ispBase
|
|
||||||
from .avr_isp.stk500v2 import Stk500v2
|
|
||||||
|
|
||||||
from time import time, sleep
|
from time import time, sleep
|
||||||
from serial import Serial, SerialException
|
from serial import Serial, SerialException
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ from PyQt6.QtGui import QOpenGLContext, QImage
|
||||||
from UM.Application import Application
|
from UM.Application import Application
|
||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
from UM.Math.Color import Color
|
from UM.Math.Color import Color
|
||||||
from UM.PluginRegistry import PluginRegistry
|
|
||||||
from UM.Resources import Resources
|
from UM.Resources import Resources
|
||||||
from UM.Platform import Platform
|
from UM.Platform import Platform
|
||||||
from UM.Event import Event
|
from UM.Event import Event
|
||||||
|
|
|
@ -5,7 +5,7 @@ import copy
|
||||||
import io
|
import io
|
||||||
import json # To parse the product-to-id mapping file.
|
import json # To parse the product-to-id mapping file.
|
||||||
import os.path # To find the product-to-id mapping.
|
import os.path # To find the product-to-id mapping.
|
||||||
from typing import Any, Dict, List, Optional, Tuple, cast, Set, Union
|
from typing import Any, Dict, List, Optional, Tuple, cast, Set
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
|
|
||||||
from UM.PluginRegistry import PluginRegistry
|
from UM.PluginRegistry import PluginRegistry
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
pytest
|
pytest
|
||||||
pyinstaller==5.8.0
|
pyinstaller==6.3.0
|
||||||
pyinstaller-hooks-contrib
|
pyinstaller-hooks-contrib
|
||||||
pyyaml
|
pyyaml
|
||||||
sip==6.5.1
|
sip==6.5.1
|
||||||
|
|
|
@ -9,16 +9,20 @@
|
||||||
},
|
},
|
||||||
"overrides":
|
"overrides":
|
||||||
{
|
{
|
||||||
"acceleration_layer_0": { "value": 3000 },
|
"acceleration_print":
|
||||||
"acceleration_print": { "value": 3000 },
|
{
|
||||||
"acceleration_travel": { "value": 5000 },
|
"maximum_value_warning": "20000",
|
||||||
|
"value": 10000
|
||||||
|
},
|
||||||
|
"acceleration_wall": { "value": "acceleration_print/2" },
|
||||||
"cool_fan_full_layer": { "value": 2 },
|
"cool_fan_full_layer": { "value": 2 },
|
||||||
"infill_line_width": { "value": "line_width + 0.05" },
|
"infill_line_width": { "value": "line_width + 0.05" },
|
||||||
"infill_overlap": { "value": "0 if infill_sparse_density < 40.01 and infill_pattern != 'concentric' else -5" },
|
"infill_overlap": { "value": "0 if infill_sparse_density < 40.01 and infill_pattern != 'concentric' else -5" },
|
||||||
|
"infill_pattern": { "value": "'lines' if infill_sparse_density > 35 else 'grid'" },
|
||||||
"initial_layer_line_width_factor": { "value": "100.0 if resolveOrValue('adhesion_type') == 'raft' else 125 if line_width < 0.5 else 110" },
|
"initial_layer_line_width_factor": { "value": "100.0 if resolveOrValue('adhesion_type') == 'raft' else 125 if line_width < 0.5 else 110" },
|
||||||
"machine_acceleration": { "value": 3000 },
|
"machine_acceleration": { "value": 5000 },
|
||||||
"machine_depth": { "default_value": 230 },
|
"machine_depth": { "default_value": 230 },
|
||||||
"machine_end_gcode": { "default_value": "G91 ;Relative positionning\nG1 E-2 F2700 ;Retract a bit\nG1 E-2 Z0.2 F2400 ;Retract and raise Z\nG1 X5 Y5 F3000 ;Wipe out\nG1 Z2 ;Raise Z more\nG90 ;Absolute positionning\nG1 X0 Y{machine_depth} ;Present print\nM106 S0 ;Turn-off fan\nM104 S0 ;Turn-off hotend\nM140 S0 ;Turn-off bed\nM84 X Y E ;Disable all steppers but Z" },
|
"machine_end_gcode": { "default_value": "G91 ;Relative positionning\nG1 E-2 F2700 ;Retract a bit\nG1 E-2 Z0.2 F2400 ;Retract and raise Z\nG1 X5 Y5 F3000 ;Wipe out\nG1 Z2 ;Raise Z more\nG90 ;Absolute positionning\nG1 X0 Y{machine_depth - 5} ;Present print\nM106 S0 ;Turn-off fan\nM104 S0 ;Turn-off hotend\nM140 S0 ;Turn-off bed\nM84 X Y E ;Disable all steppers but Z" },
|
||||||
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
|
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
|
||||||
"machine_head_with_fans_polygon":
|
"machine_head_with_fans_polygon":
|
||||||
{
|
{
|
||||||
|
@ -32,12 +36,12 @@
|
||||||
"machine_heated_bed": { "default_value": true },
|
"machine_heated_bed": { "default_value": true },
|
||||||
"machine_height": { "default_value": 270 },
|
"machine_height": { "default_value": 270 },
|
||||||
"machine_max_acceleration_e": { "value": 5000 },
|
"machine_max_acceleration_e": { "value": 5000 },
|
||||||
"machine_max_acceleration_x": { "value": 5000 },
|
"machine_max_acceleration_x": { "value": 20000 },
|
||||||
"machine_max_acceleration_y": { "value": 5000 },
|
"machine_max_acceleration_y": { "value": 20000 },
|
||||||
"machine_name": { "default_value": "ELEGOO NEPTUNE 4" },
|
"machine_name": { "default_value": "ELEGOO NEPTUNE 4" },
|
||||||
"machine_nozzle_cool_down_speed": { "value": 0.75 },
|
"machine_nozzle_cool_down_speed": { "value": 0.75 },
|
||||||
"machine_nozzle_heat_up_speed": { "value": 1.6 },
|
"machine_nozzle_heat_up_speed": { "value": 1.6 },
|
||||||
"machine_start_gcode": { "default_value": "G28 ;home\nG92 E0 ;Reset Extruder\nG1 Z4.0 F3000 ;Move Z Axis up\nG92 E0 ;Reset Extruder\nG1 X1.1 Y20 Z0.28 F5000.0 ;Move to start position\nG1 X1.1 Y80.0 Z0.28 F1500.0 E10 ;Draw the first line\nG1 X1.4 Y80.0 Z0.28 F5000.0 ;Move to side a little\nG1 X1.4 Y20 Z0.28 F1500.0 E20 ;Draw the second line\nG92 E0 ;Reset Extruder\nG1 Z2.0 F3000 ;Move Z Axis up" },
|
"machine_start_gcode": { "default_value": ";ELEGOO NEPTUNE 4 / 4 PRO\nM220 S100 ;Set the feed speed to 100%\nM221 S100 ;Set the flow rate to 100%\nM104 S140 ;Start heating extruder\nM190 S{material_bed_temperature_layer_0} ;Wait for the bed to reach print temp\nG90\nG28 ;home\nG1 Z10 F300\nG1 X67.5 Y0 F6000\nG1 Z0 F300\nM109 S{material_print_temperature_layer_0} ;Wait for extruder to reach print temp\nG92 E0 ;Reset Extruder\nG1 X67.5 Y0 Z0.4 F300 ;Move to start position\nG1 X167.5 E30 F400 ;Draw the first line\nG1 Z0.6 F120.0 ;Move to side a little\nG1 X162.5 F3000\nG92 E0 ;Reset Extruder" },
|
||||||
"machine_width": { "default_value": 235 },
|
"machine_width": { "default_value": 235 },
|
||||||
"retraction_amount": { "default_value": 0.5 },
|
"retraction_amount": { "default_value": 0.5 },
|
||||||
"retraction_count_max": { "value": 80 },
|
"retraction_count_max": { "value": 80 },
|
||||||
|
|
62
resources/definitions/elegoo_neptune_4max.def.json
Normal file
62
resources/definitions/elegoo_neptune_4max.def.json
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "ELEGOO NEPTUNE 4 Max",
|
||||||
|
"inherits": "elegoo_neptune_4",
|
||||||
|
"metadata":
|
||||||
|
{
|
||||||
|
"visible": true,
|
||||||
|
"author": "mastercaution",
|
||||||
|
"platform": "elegoo_platform_max.3mf",
|
||||||
|
"platform_offset": [
|
||||||
|
-2.1,
|
||||||
|
-0.2,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"quality_definition": "elegoo_neptune_4"
|
||||||
|
},
|
||||||
|
"overrides":
|
||||||
|
{
|
||||||
|
"acceleration_print":
|
||||||
|
{
|
||||||
|
"maximum_value_warning": "15000",
|
||||||
|
"value": 2500
|
||||||
|
},
|
||||||
|
"machine_depth": { "default_value": 430 },
|
||||||
|
"machine_height": { "default_value": 482 },
|
||||||
|
"machine_max_acceleration_e": { "value": 5000 },
|
||||||
|
"machine_max_acceleration_x": { "value": 15000 },
|
||||||
|
"machine_max_acceleration_y": { "value": 15000 },
|
||||||
|
"machine_name": { "default_value": "ELEGOO NEPTUNE 4 Max" },
|
||||||
|
"machine_start_gcode": { "default_value": ";ELEGOO NEPTUNE 4 MAX\nM220 S100 ;Set the feed speed to 100%\nM221 S100 ;Set the flow rate to 100%\nM104 S140 ;Start heating extruder\nM190 S{material_bed_temperature_layer_0} ;Wait for the bed to reach print temp\nG90\nG28 ;home\nG1 Z10 F300\nG1 X165 Y0 F6000\nG1 Z0 F300\nM109 S{material_print_temperature_layer_0} ;Wait for extruder to reach print temp\nG92 E0 ;Reset Extruder\nG1 X165 Y0 Z0.4 F300 ;Move to start position\nG1 X265 E30 F400 ;Draw the first line\nG1 Z0.6 F120.0 ;Move to side a little\nG1 X260 F3000\nG92 E0 ;Reset Extruder" },
|
||||||
|
"machine_width": { "default_value": 430 },
|
||||||
|
"nozzle_disallowed_areas":
|
||||||
|
{
|
||||||
|
"default_value": [
|
||||||
|
[
|
||||||
|
[-215, -215],
|
||||||
|
[-215, 215],
|
||||||
|
[-211, 215],
|
||||||
|
[-211, -215]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[215, 215],
|
||||||
|
[215, -215],
|
||||||
|
[211, -215],
|
||||||
|
[211, 215]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[-215, -215],
|
||||||
|
[215, -215],
|
||||||
|
[-215, -211],
|
||||||
|
[215, -211]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[-215, 215],
|
||||||
|
[215, 215],
|
||||||
|
[-215, 211],
|
||||||
|
[215, 211]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
59
resources/definitions/elegoo_neptune_4plus.def.json
Normal file
59
resources/definitions/elegoo_neptune_4plus.def.json
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "ELEGOO NEPTUNE 4 Plus",
|
||||||
|
"inherits": "elegoo_neptune_4",
|
||||||
|
"metadata":
|
||||||
|
{
|
||||||
|
"visible": true,
|
||||||
|
"author": "mastercaution",
|
||||||
|
"platform": "elegoo_platform_max.3mf",
|
||||||
|
"platform_offset": [
|
||||||
|
-2.1,
|
||||||
|
-0.2,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"quality_definition": "elegoo_neptune_4"
|
||||||
|
},
|
||||||
|
"overrides":
|
||||||
|
{
|
||||||
|
"acceleration_print": { "value": 4000 },
|
||||||
|
"machine_acceleration": { "value": 4000 },
|
||||||
|
"machine_depth": { "default_value": 330 },
|
||||||
|
"machine_height": { "default_value": 387 },
|
||||||
|
"machine_max_acceleration_e": { "value": 5000 },
|
||||||
|
"machine_max_acceleration_x": { "value": 20000 },
|
||||||
|
"machine_max_acceleration_y": { "value": 20000 },
|
||||||
|
"machine_name": { "default_value": "ELEGOO NEPTUNE 4 Plus" },
|
||||||
|
"machine_start_gcode": { "default_value": ";ELEGOO NEPTUNE 4 PLUS\nM220 S100 ;Set the feed speed to 100%\nM221 S100 ;Set the flow rate to 100%\nM104 S140 ;Start heating extruder\nM190 S{material_bed_temperature_layer_0} ;Wait for the bed to reach print temp\nG90\nG28 ;home\nG1 Z10 F300\nG1 X115 Y0 F6000\nG1 Z0 F300\nM109 S{material_print_temperature_layer_0} ;Wait for extruder to reach print temp\nG92 E0 ;Reset Extruder\nG1 X115 Y0 Z0.4 F300 ;Move to start position\nG1 X215 E30 F400 ;Draw the first line\nG1 Z0.6 F120.0 ;Move to side a little\nG1 X210 F3000\nG92 E0 ;Reset Extruder" },
|
||||||
|
"machine_width": { "default_value": 330 },
|
||||||
|
"nozzle_disallowed_areas":
|
||||||
|
{
|
||||||
|
"default_value": [
|
||||||
|
[
|
||||||
|
[-165, -165],
|
||||||
|
[-165, 165],
|
||||||
|
[-161, 165],
|
||||||
|
[-161, -165]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[165, 165],
|
||||||
|
[165, -165],
|
||||||
|
[161, -165],
|
||||||
|
[161, 165]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[-165, -165],
|
||||||
|
[165, -165],
|
||||||
|
[-165, -161],
|
||||||
|
[165, -161]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
[-165, 165],
|
||||||
|
[165, 165],
|
||||||
|
[-165, 161],
|
||||||
|
[165, 161]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1684,7 +1684,7 @@
|
||||||
"value": "skin_line_width * 2",
|
"value": "skin_line_width * 2",
|
||||||
"default_value": 1,
|
"default_value": 1,
|
||||||
"minimum_value": "0",
|
"minimum_value": "0",
|
||||||
"maximum_value_warning": "skin_line_width * 3",
|
"maximum_value_warning": "skin_line_width * 10",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"enabled": "(top_layers > 0 or bottom_layers > 0) and top_bottom_pattern != 'concentric'",
|
"enabled": "(top_layers > 0 or bottom_layers > 0) and top_bottom_pattern != 'concentric'",
|
||||||
"limit_to_extruder": "top_bottom_extruder_nr",
|
"limit_to_extruder": "top_bottom_extruder_nr",
|
||||||
|
@ -5151,7 +5151,7 @@
|
||||||
"unit": "mm",
|
"unit": "mm",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"minimum_value": "0",
|
"minimum_value": "0",
|
||||||
"maximum_value_warning": "machine_nozzle_size",
|
"maximum_value_warning": "5*layer_height",
|
||||||
"default_value": 0.1,
|
"default_value": 0.1,
|
||||||
"limit_to_extruder": "support_interface_extruder_nr if support_interface_enable else support_infill_extruder_nr",
|
"limit_to_extruder": "support_interface_extruder_nr if support_interface_enable else support_infill_extruder_nr",
|
||||||
"enabled": "support_enable or support_meshes_present",
|
"enabled": "support_enable or support_meshes_present",
|
||||||
|
@ -6469,6 +6469,18 @@
|
||||||
"settable_per_extruder": true,
|
"settable_per_extruder": true,
|
||||||
"limit_to_extruder": "raft_surface_extruder_nr"
|
"limit_to_extruder": "raft_surface_extruder_nr"
|
||||||
},
|
},
|
||||||
|
"raft_surface_monotonic":
|
||||||
|
{
|
||||||
|
"label": "Monotonic Raft Top Surface Order",
|
||||||
|
"description": "Print raft top surface lines in an ordering that causes them to always overlap with adjacent lines in a single direction. This takes slightly more time to print, but makes the surface look more consistent, which is also visible on the model bottom surface.",
|
||||||
|
"type": "bool",
|
||||||
|
"default_value": false,
|
||||||
|
"value": "skin_monotonic",
|
||||||
|
"enabled": "resolveOrValue('adhesion_type') == 'raft' and raft_surface_layers > 0",
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": true,
|
||||||
|
"limit_to_extruder": "raft_surface_extruder_nr"
|
||||||
|
},
|
||||||
"raft_wall_count":
|
"raft_wall_count":
|
||||||
{
|
{
|
||||||
"label": "Raft Wall Count",
|
"label": "Raft Wall Count",
|
||||||
|
@ -7269,6 +7281,16 @@
|
||||||
"settable_per_extruder": false,
|
"settable_per_extruder": false,
|
||||||
"settable_per_meshgroup": false
|
"settable_per_meshgroup": false
|
||||||
},
|
},
|
||||||
|
"user_defined_print_order_enabled":
|
||||||
|
{
|
||||||
|
"label": "Set Print Sequence Manually",
|
||||||
|
"description": "Allows to order the object list to set the print sequence manually. First object from the list will be printed first.",
|
||||||
|
"type": "bool",
|
||||||
|
"default_value": false,
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": false,
|
||||||
|
"enabled": "print_sequence == 'one_at_a_time'"
|
||||||
|
},
|
||||||
"infill_mesh":
|
"infill_mesh":
|
||||||
{
|
{
|
||||||
"label": "Infill Mesh",
|
"label": "Infill Mesh",
|
||||||
|
|
15
resources/definitions/flashforge_adventurer3.def.json
Normal file
15
resources/definitions/flashforge_adventurer3.def.json
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "Adventurer 3",
|
||||||
|
"inherits": "flashforge_adventurer3c",
|
||||||
|
"metadata":
|
||||||
|
{
|
||||||
|
"visible": true,
|
||||||
|
"author": "Jeremie-C",
|
||||||
|
"supports_network_connection": true
|
||||||
|
},
|
||||||
|
"overrides":
|
||||||
|
{
|
||||||
|
"machine_name": { "default_value": "Adventurer 3" }
|
||||||
|
}
|
||||||
|
}
|
33
resources/definitions/flashforge_adventurer3c.def.json
Normal file
33
resources/definitions/flashforge_adventurer3c.def.json
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "Adventurer 3C",
|
||||||
|
"inherits": "flashforge_adventurer_base",
|
||||||
|
"metadata":
|
||||||
|
{
|
||||||
|
"visible": true,
|
||||||
|
"author": "Jeremie-C",
|
||||||
|
"quality_definition": "flashforge_adventurer3"
|
||||||
|
},
|
||||||
|
"overrides":
|
||||||
|
{
|
||||||
|
"default_material_bed_temperature": { "maximum_value_warning": "100" },
|
||||||
|
"gantry_height": { "value": "150" },
|
||||||
|
"machine_center_is_zero": { "default_value": true },
|
||||||
|
"machine_depth": { "default_value": 150 },
|
||||||
|
"machine_end_gcode": { "default_value": ";end gcode\nM104 S0 T0\nM140 S0 T0\nG162 Z F1800\nG28 X Y\nM132 X Y A B\nM652\nG91\nM18" },
|
||||||
|
"machine_head_with_fans_polygon":
|
||||||
|
{
|
||||||
|
"default_value": [
|
||||||
|
[-20, 10],
|
||||||
|
[-20, -10],
|
||||||
|
[10, 10],
|
||||||
|
[10, -10]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"machine_height": { "default_value": 150 },
|
||||||
|
"machine_name": { "default_value": "Adventurer 3C" },
|
||||||
|
"machine_start_gcode": { "default_value": ";Start Gcode\nG28\nM132 X Y Z A B\nG1 Z50.000 F420\nG161 X Y F3300\nM7 T0\nM6 T0\nM651 S255\n;End Start" },
|
||||||
|
"machine_width": { "default_value": 150 },
|
||||||
|
"speed_print": { "maximum_value_warning": 100 }
|
||||||
|
}
|
||||||
|
}
|
33
resources/definitions/flashforge_adventurer4.def.json
Normal file
33
resources/definitions/flashforge_adventurer4.def.json
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "Adventurer 4",
|
||||||
|
"inherits": "flashforge_adventurer_base",
|
||||||
|
"metadata":
|
||||||
|
{
|
||||||
|
"visible": true,
|
||||||
|
"author": "Jeremie-C",
|
||||||
|
"quality_definition": "flashforge_adventurer4",
|
||||||
|
"supports_network_connection": true
|
||||||
|
},
|
||||||
|
"overrides":
|
||||||
|
{
|
||||||
|
"default_material_bed_temperature": { "maximum_value_warning": "110" },
|
||||||
|
"gantry_height": { "value": "250" },
|
||||||
|
"machine_depth": { "default_value": 200 },
|
||||||
|
"machine_end_gcode": { "default_value": ";End Gcode\nM104 S0 T0\nM140 S0 T0\nG162 Z F1800\nG28 X Y\nM132 X Y A B\nM652\nG91\nM18" },
|
||||||
|
"machine_head_with_fans_polygon":
|
||||||
|
{
|
||||||
|
"default_value": [
|
||||||
|
[-20, 10],
|
||||||
|
[-20, -10],
|
||||||
|
[10, 10],
|
||||||
|
[10, -10]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"machine_height": { "default_value": 250 },
|
||||||
|
"machine_name": { "default_value": "Adventurer 4" },
|
||||||
|
"machine_start_gcode": { "default_value": ";Start Gcode\nG28\nM132 X Y Z A B\nG1 Z50.000 F420\nG161 X Y F3300\nM7 T0\nM6 T0\nM651 S255\n;End Start" },
|
||||||
|
"machine_use_extruder_offset_to_offset_coords": { "default_value": false },
|
||||||
|
"machine_width": { "default_value": 220 }
|
||||||
|
}
|
||||||
|
}
|
14
resources/definitions/flashforge_adventurer4lite.def.json
Normal file
14
resources/definitions/flashforge_adventurer4lite.def.json
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "Adventurer 4 Lite",
|
||||||
|
"inherits": "flashforge_adventurer4",
|
||||||
|
"metadata":
|
||||||
|
{
|
||||||
|
"visible": true,
|
||||||
|
"author": "Jeremie-C"
|
||||||
|
},
|
||||||
|
"overrides":
|
||||||
|
{
|
||||||
|
"machine_name": { "default_value": "Adventurer 4 Lite" }
|
||||||
|
}
|
||||||
|
}
|
34
resources/definitions/flashforge_adventurer_base.def.json
Normal file
34
resources/definitions/flashforge_adventurer_base.def.json
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "Flashforge Adventurer Base",
|
||||||
|
"inherits": "fdmprinter",
|
||||||
|
"metadata":
|
||||||
|
{
|
||||||
|
"visible": false,
|
||||||
|
"author": "Jeremie-C",
|
||||||
|
"manufacturer": "Flashforge",
|
||||||
|
"file_formats": "application/gx;text/x-gcode",
|
||||||
|
"first_start_actions": [ "MachineSettingsAction" ],
|
||||||
|
"has_machine_quality": true,
|
||||||
|
"has_materials": true,
|
||||||
|
"has_variants": true,
|
||||||
|
"machine_extruder_trains": { "0": "flashforge_adventurer_extruder_0" },
|
||||||
|
"preferred_material": "generic_pla",
|
||||||
|
"preferred_quality_type": "normal",
|
||||||
|
"preferred_variant_name": "0.4mm Nozzle",
|
||||||
|
"variants_name": "Nozzle Size"
|
||||||
|
},
|
||||||
|
"overrides":
|
||||||
|
{
|
||||||
|
"adhesion_type": { "default_value": "skirt" },
|
||||||
|
"default_material_print_temperature": { "maximum_value_warning": "265" },
|
||||||
|
"layer_height":
|
||||||
|
{
|
||||||
|
"maximum_value_warning": "0.4",
|
||||||
|
"minimum_value_warning": "0.1"
|
||||||
|
},
|
||||||
|
"machine_center_is_zero": { "default_value": true },
|
||||||
|
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
|
||||||
|
"machine_heated_bed": { "default_value": true }
|
||||||
|
}
|
||||||
|
}
|
20
resources/definitions/ratrig_base.def.json
Normal file
20
resources/definitions/ratrig_base.def.json
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "RatRig Printer",
|
||||||
|
"inherits": "fdmprinter",
|
||||||
|
"metadata":
|
||||||
|
{
|
||||||
|
"visible": false,
|
||||||
|
"author": "nu-hin",
|
||||||
|
"manufacturer": "RatRig",
|
||||||
|
"file_formats": "text/x-gcode",
|
||||||
|
"exclude_materials": [],
|
||||||
|
"first_start_actions": [ "MachineSettingsAction" ],
|
||||||
|
"has_materials": true,
|
||||||
|
"machine_extruder_trains": { "0": "ratrig_base_extruder_0" },
|
||||||
|
"preferred_material": "generic_pla",
|
||||||
|
"preferred_quality_type": "standard",
|
||||||
|
"quality_definition": "ratrig_base",
|
||||||
|
"supported_actions": [ "MachineSettingsAction" ]
|
||||||
|
}
|
||||||
|
}
|
23
resources/definitions/ratrig_vcore3_200.def.json
Normal file
23
resources/definitions/ratrig_vcore3_200.def.json
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "RatRig V-Core 3 200mm",
|
||||||
|
"inherits": "ratrig_vcore3_base",
|
||||||
|
"metadata":
|
||||||
|
{
|
||||||
|
"visible": true,
|
||||||
|
"platform": "ratrig_vcore3_200.stl",
|
||||||
|
"platform_offset": [
|
||||||
|
0,
|
||||||
|
5,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"weight": 16
|
||||||
|
},
|
||||||
|
"overrides":
|
||||||
|
{
|
||||||
|
"machine_depth": { "default_value": 200 },
|
||||||
|
"machine_height": { "default_value": 200 },
|
||||||
|
"machine_name": { "default_value": "RatRig V-Core 3 200mm" },
|
||||||
|
"machine_width": { "default_value": 200 }
|
||||||
|
}
|
||||||
|
}
|
23
resources/definitions/ratrig_vcore3_300.def.json
Normal file
23
resources/definitions/ratrig_vcore3_300.def.json
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "RatRig V-Core 3 300mm",
|
||||||
|
"inherits": "ratrig_vcore3_base",
|
||||||
|
"metadata":
|
||||||
|
{
|
||||||
|
"visible": true,
|
||||||
|
"platform": "ratrig_vcore3_300.stl",
|
||||||
|
"platform_offset": [
|
||||||
|
0,
|
||||||
|
5,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"weight": 16
|
||||||
|
},
|
||||||
|
"overrides":
|
||||||
|
{
|
||||||
|
"machine_depth": { "default_value": 300 },
|
||||||
|
"machine_height": { "default_value": 300 },
|
||||||
|
"machine_name": { "default_value": "RatRig V-Core 3 300mm" },
|
||||||
|
"machine_width": { "default_value": 300 }
|
||||||
|
}
|
||||||
|
}
|
23
resources/definitions/ratrig_vcore3_400.def.json
Normal file
23
resources/definitions/ratrig_vcore3_400.def.json
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "RatRig V-Core 3 400mm",
|
||||||
|
"inherits": "ratrig_vcore3_base",
|
||||||
|
"metadata":
|
||||||
|
{
|
||||||
|
"visible": true,
|
||||||
|
"platform": "ratrig_vcore3_400.stl",
|
||||||
|
"platform_offset": [
|
||||||
|
0,
|
||||||
|
3,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"weight": 16
|
||||||
|
},
|
||||||
|
"overrides":
|
||||||
|
{
|
||||||
|
"machine_depth": { "default_value": 400 },
|
||||||
|
"machine_height": { "default_value": 400 },
|
||||||
|
"machine_name": { "default_value": "RatRig V-Core 3 400mm" },
|
||||||
|
"machine_width": { "default_value": 400 }
|
||||||
|
}
|
||||||
|
}
|
23
resources/definitions/ratrig_vcore3_500.def.json
Normal file
23
resources/definitions/ratrig_vcore3_500.def.json
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "RatRig V-Core 3 500mm",
|
||||||
|
"inherits": "ratrig_vcore3_base",
|
||||||
|
"metadata":
|
||||||
|
{
|
||||||
|
"visible": true,
|
||||||
|
"platform": "ratrig_vcore3_500.stl",
|
||||||
|
"platform_offset": [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"weight": 16
|
||||||
|
},
|
||||||
|
"overrides":
|
||||||
|
{
|
||||||
|
"machine_depth": { "default_value": 500 },
|
||||||
|
"machine_height": { "default_value": 500 },
|
||||||
|
"machine_name": { "default_value": "RatRig V-Core 3 500mm" },
|
||||||
|
"machine_width": { "default_value": 500 }
|
||||||
|
}
|
||||||
|
}
|
116
resources/definitions/ratrig_vcore3_base.def.json
Normal file
116
resources/definitions/ratrig_vcore3_base.def.json
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "RatRig V-Core 3",
|
||||||
|
"inherits": "ratrig_base",
|
||||||
|
"metadata":
|
||||||
|
{
|
||||||
|
"visible": false,
|
||||||
|
"has_machine_quality": true,
|
||||||
|
"has_variants": true,
|
||||||
|
"machine_extruder_trains": { "0": "ratrig_base_extruder_0" },
|
||||||
|
"preferred_variant_name": "0.4mm Nozzle",
|
||||||
|
"variants_name": "Nozzle Size"
|
||||||
|
},
|
||||||
|
"overrides":
|
||||||
|
{
|
||||||
|
"acceleration_enabled": { "value": true },
|
||||||
|
"acceleration_layer_0": { "value": "acceleration_topbottom" },
|
||||||
|
"acceleration_roofing": { "enabled": "acceleration_enabled and roofing_layer_count > 0 and top_layers > 0" },
|
||||||
|
"acceleration_topbottom": { "value": "acceleration_print / 3" },
|
||||||
|
"acceleration_travel": { "value": 3000 },
|
||||||
|
"acceleration_travel_layer_0": { "value": "acceleration_travel / 3" },
|
||||||
|
"adaptive_layer_height_variation": { "value": 0.04 },
|
||||||
|
"adaptive_layer_height_variation_step": { "value": 0.04 },
|
||||||
|
"adhesion_type": { "value": "'skirt'" },
|
||||||
|
"brim_replaces_support": { "value": false },
|
||||||
|
"brim_width": { "value": "3" },
|
||||||
|
"cool_fan_full_at_height": { "value": "layer_height_0 + 2 * layer_height" },
|
||||||
|
"cool_min_layer_time": { "value": 2 },
|
||||||
|
"fill_outline_gaps": { "value": false },
|
||||||
|
"gantry_height": { "value": 30 },
|
||||||
|
"infill_before_walls": { "value": false },
|
||||||
|
"infill_overlap": { "value": 30 },
|
||||||
|
"infill_pattern": { "value": "'lines' if infill_sparse_density > 50 else 'cubic'" },
|
||||||
|
"infill_wipe_dist": { "value": 0 },
|
||||||
|
"layer_height": { "default_value": 0.2 },
|
||||||
|
"layer_height_0": { "default_value": 0.2 },
|
||||||
|
"machine_acceleration": { "value": 3000 },
|
||||||
|
"machine_end_gcode": { "default_value": "END_PRINT" },
|
||||||
|
"machine_extruder_count": { "default_value": 1 },
|
||||||
|
"machine_head_with_fans_polygon":
|
||||||
|
{
|
||||||
|
"default_value": [
|
||||||
|
[-40, 90],
|
||||||
|
[-40, -30],
|
||||||
|
[40, -30],
|
||||||
|
[40, 90]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"machine_heated_bed": { "default_value": true },
|
||||||
|
"machine_max_acceleration_e": { "value": 5000 },
|
||||||
|
"machine_max_acceleration_x": { "value": 9000 },
|
||||||
|
"machine_max_acceleration_y": { "value": 9000 },
|
||||||
|
"machine_max_acceleration_z": { "value": 100 },
|
||||||
|
"machine_max_feedrate_e": { "value": 60 },
|
||||||
|
"machine_max_feedrate_x": { "value": 500 },
|
||||||
|
"machine_max_feedrate_y": { "value": 500 },
|
||||||
|
"machine_max_feedrate_z": { "value": 10 },
|
||||||
|
"machine_max_jerk_e": { "value": 5 },
|
||||||
|
"machine_max_jerk_xy": { "value": 5 },
|
||||||
|
"machine_max_jerk_z": { "value": 0.4 },
|
||||||
|
"machine_name": { "default_value": "RatRig V-Core 3" },
|
||||||
|
"machine_shape": { "default_value": "rectangular" },
|
||||||
|
"machine_show_variants": { "default_value": true },
|
||||||
|
"machine_start_gcode": { "default_value": "START_PRINT EXTRUDER_TEMP={material_print_temperature_layer_0} BED_TEMP={material_bed_temperature_layer_0}" },
|
||||||
|
"material_diameter": { "default_value": 1.75 },
|
||||||
|
"material_final_print_temperature": { "value": "material_print_temperature" },
|
||||||
|
"material_initial_print_temperature": { "value": "material_print_temperature" },
|
||||||
|
"meshfix_maximum_resolution": { "value": "0.25" },
|
||||||
|
"meshfix_maximum_travel_resolution": { "value": "meshfix_maximum_resolution" },
|
||||||
|
"minimum_interface_area": { "value": 10 },
|
||||||
|
"minimum_support_area": { "value": 2 },
|
||||||
|
"optimize_wall_printing_order": { "value": true },
|
||||||
|
"retraction_amount": { "value": "machine_nozzle_size * 2" },
|
||||||
|
"retraction_combing": { "value": "'off' if retraction_hop_enabled else 'noskin'" },
|
||||||
|
"retraction_combing_max_distance": { "value": 30 },
|
||||||
|
"retraction_count_max": { "value": 100 },
|
||||||
|
"retraction_extrusion_window": { "value": 10 },
|
||||||
|
"retraction_speed": { "value": 40 },
|
||||||
|
"roofing_layer_count": { "value": 1 },
|
||||||
|
"skin_overlap": { "value": 18 },
|
||||||
|
"skirt_brim_minimal_length": { "default_value": 30 },
|
||||||
|
"skirt_gap": { "value": 10 },
|
||||||
|
"skirt_line_count": { "value": 3 },
|
||||||
|
"speed_layer_0": { "value": "math.floor(speed_print * 3 / 10)" },
|
||||||
|
"speed_print": { "value": 100 },
|
||||||
|
"speed_roofing": { "value": "math.floor(speed_print * 3 / 10)" },
|
||||||
|
"speed_support": { "value": "math.floor(speed_print * 3 / 10)" },
|
||||||
|
"speed_support_interface": { "value": "speed_topbottom" },
|
||||||
|
"speed_topbottom": { "value": "math.floor(speed_print / 2)" },
|
||||||
|
"speed_travel": { "value": 250 },
|
||||||
|
"speed_travel_layer_0": { "value": "100 if speed_layer_0 < 20 else 150 if speed_layer_0 > 30 else speed_layer_0 * 5" },
|
||||||
|
"speed_wall_x": { "value": "speed_wall" },
|
||||||
|
"speed_z_hop": { "value": 5 },
|
||||||
|
"support_angle": { "value": "math.floor(math.degrees(math.atan(line_width/2.0/layer_height)))" },
|
||||||
|
"support_brim_width": { "value": 4 },
|
||||||
|
"support_infill_rate": { "value": "0 if support_enable and support_structure == 'tree' else 20" },
|
||||||
|
"support_interface_density": { "value": 33.333 },
|
||||||
|
"support_interface_enable": { "value": true },
|
||||||
|
"support_interface_height": { "value": "layer_height * 4" },
|
||||||
|
"support_interface_pattern": { "value": "'grid'" },
|
||||||
|
"support_pattern": { "value": "'zigzag'" },
|
||||||
|
"support_use_towers": { "value": false },
|
||||||
|
"support_xy_distance": { "value": "wall_line_width_0 * 2" },
|
||||||
|
"support_xy_distance_overhang": { "value": "wall_line_width_0" },
|
||||||
|
"support_xy_overrides_z": { "value": "'xy_overrides_z'" },
|
||||||
|
"support_z_distance": { "value": "layer_height if layer_height >= 0.16 else layer_height * 2" },
|
||||||
|
"top_bottom_pattern": { "value": "'lines'" },
|
||||||
|
"top_bottom_thickness": { "value": "layer_height_0 + layer_height * 3" },
|
||||||
|
"travel_avoid_supports": { "value": true },
|
||||||
|
"travel_retract_before_outer_wall": { "value": true },
|
||||||
|
"wall_0_wipe_dist": { "value": 0 },
|
||||||
|
"wall_thickness": { "value": "line_width * 2" },
|
||||||
|
"z_seam_corner": { "value": "'z_seam_corner_weighted'" },
|
||||||
|
"z_seam_type": { "value": "'back'" }
|
||||||
|
}
|
||||||
|
}
|
127
resources/definitions/ratrig_vminion.def.json
Normal file
127
resources/definitions/ratrig_vminion.def.json
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "RatRig V-Minion",
|
||||||
|
"inherits": "ratrig_base",
|
||||||
|
"metadata":
|
||||||
|
{
|
||||||
|
"visible": true,
|
||||||
|
"platform": "ratrig_vminion.stl",
|
||||||
|
"has_machine_quality": true,
|
||||||
|
"has_variants": true,
|
||||||
|
"machine_extruder_trains": { "0": "ratrig_base_extruder_0" },
|
||||||
|
"platform_offset": [
|
||||||
|
0,
|
||||||
|
5,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"preferred_variant_name": "0.4mm Nozzle",
|
||||||
|
"variants_name": "Nozzle Size",
|
||||||
|
"weight": 8
|
||||||
|
},
|
||||||
|
"overrides":
|
||||||
|
{
|
||||||
|
"acceleration_enabled": { "value": true },
|
||||||
|
"acceleration_layer_0": { "value": "acceleration_topbottom" },
|
||||||
|
"acceleration_roofing": { "enabled": "acceleration_enabled and roofing_layer_count > 0 and top_layers > 0" },
|
||||||
|
"acceleration_topbottom": { "value": "acceleration_print / 3" },
|
||||||
|
"acceleration_travel": { "value": 3000 },
|
||||||
|
"acceleration_travel_layer_0": { "value": "acceleration_travel / 3" },
|
||||||
|
"adaptive_layer_height_variation": { "value": 0.04 },
|
||||||
|
"adaptive_layer_height_variation_step": { "value": 0.04 },
|
||||||
|
"adhesion_type": { "value": "'skirt'" },
|
||||||
|
"brim_replaces_support": { "value": false },
|
||||||
|
"brim_width": { "value": "3" },
|
||||||
|
"cool_fan_full_at_height": { "value": "layer_height_0 + 2 * layer_height" },
|
||||||
|
"cool_min_layer_time": { "value": 2 },
|
||||||
|
"fill_outline_gaps": { "value": false },
|
||||||
|
"gantry_height": { "value": 30 },
|
||||||
|
"infill_before_walls": { "value": false },
|
||||||
|
"infill_overlap": { "value": 30 },
|
||||||
|
"infill_pattern": { "value": "'lines' if infill_sparse_density > 50 else 'cubic'" },
|
||||||
|
"infill_wipe_dist": { "value": 0 },
|
||||||
|
"layer_height": { "default_value": 0.2 },
|
||||||
|
"layer_height_0": { "default_value": 0.2 },
|
||||||
|
"machine_acceleration": { "value": 3000 },
|
||||||
|
"machine_depth": { "default_value": 180 },
|
||||||
|
"machine_end_gcode": { "default_value": "END_PRINT" },
|
||||||
|
"machine_extruder_count": { "default_value": 1 },
|
||||||
|
"machine_head_with_fans_polygon":
|
||||||
|
{
|
||||||
|
"default_value": [
|
||||||
|
[-40, 90],
|
||||||
|
[-40, -30],
|
||||||
|
[40, -30],
|
||||||
|
[40, 90]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"machine_heated_bed": { "default_value": true },
|
||||||
|
"machine_height": { "default_value": 180 },
|
||||||
|
"machine_max_acceleration_e": { "value": 5000 },
|
||||||
|
"machine_max_acceleration_x": { "value": 9000 },
|
||||||
|
"machine_max_acceleration_y": { "value": 9000 },
|
||||||
|
"machine_max_acceleration_z": { "value": 100 },
|
||||||
|
"machine_max_feedrate_e": { "value": 60 },
|
||||||
|
"machine_max_feedrate_x": { "value": 500 },
|
||||||
|
"machine_max_feedrate_y": { "value": 500 },
|
||||||
|
"machine_max_feedrate_z": { "value": 10 },
|
||||||
|
"machine_max_jerk_e": { "value": 5 },
|
||||||
|
"machine_max_jerk_xy": { "value": 5 },
|
||||||
|
"machine_max_jerk_z": { "value": 0.4 },
|
||||||
|
"machine_name": { "default_value": "RatRig V-Minion" },
|
||||||
|
"machine_shape": { "default_value": "rectangular" },
|
||||||
|
"machine_show_variants": { "default_value": true },
|
||||||
|
"machine_start_gcode": { "default_value": "START_PRINT EXTRUDER_TEMP={material_print_temperature_layer_0} BED_TEMP={material_bed_temperature_layer_0}" },
|
||||||
|
"machine_width": { "default_value": 180 },
|
||||||
|
"material_diameter": { "default_value": 1.75 },
|
||||||
|
"material_final_print_temperature": { "value": "material_print_temperature" },
|
||||||
|
"material_initial_print_temperature": { "value": "material_print_temperature" },
|
||||||
|
"meshfix_maximum_resolution": { "value": "0.25" },
|
||||||
|
"meshfix_maximum_travel_resolution": { "value": "meshfix_maximum_resolution" },
|
||||||
|
"minimum_interface_area": { "value": 10 },
|
||||||
|
"minimum_support_area": { "value": 2 },
|
||||||
|
"optimize_wall_printing_order": { "value": true },
|
||||||
|
"retraction_amount": { "value": "machine_nozzle_size * 2" },
|
||||||
|
"retraction_combing": { "value": "'off' if retraction_hop_enabled else 'noskin'" },
|
||||||
|
"retraction_combing_max_distance": { "value": 30 },
|
||||||
|
"retraction_count_max": { "value": 100 },
|
||||||
|
"retraction_extrusion_window": { "value": 10 },
|
||||||
|
"retraction_speed": { "value": 40 },
|
||||||
|
"roofing_layer_count": { "value": 1 },
|
||||||
|
"skin_overlap": { "value": 18 },
|
||||||
|
"skirt_brim_minimal_length": { "default_value": 30 },
|
||||||
|
"skirt_gap": { "value": 10 },
|
||||||
|
"skirt_line_count": { "value": 3 },
|
||||||
|
"speed_layer_0": { "value": "math.floor(speed_print * 3 / 10)" },
|
||||||
|
"speed_print": { "value": 100 },
|
||||||
|
"speed_roofing": { "value": "math.floor(speed_print * 3 / 10)" },
|
||||||
|
"speed_support": { "value": "math.floor(speed_print * 3 / 10)" },
|
||||||
|
"speed_support_interface": { "value": "speed_topbottom" },
|
||||||
|
"speed_topbottom": { "value": "math.floor(speed_print / 2)" },
|
||||||
|
"speed_travel": { "value": 250 },
|
||||||
|
"speed_travel_layer_0": { "value": "100 if speed_layer_0 < 20 else 150 if speed_layer_0 > 30 else speed_layer_0 * 5" },
|
||||||
|
"speed_wall": { "value": "math.floor(speed_print / 2)" },
|
||||||
|
"speed_wall_x": { "value": "speed_wall" },
|
||||||
|
"speed_z_hop": { "value": 5 },
|
||||||
|
"support_angle": { "value": "math.floor(math.degrees(math.atan(line_width/2.0/layer_height)))" },
|
||||||
|
"support_brim_width": { "value": 4 },
|
||||||
|
"support_infill_rate": { "value": "0 if support_enable and support_structure == 'tree' else 20" },
|
||||||
|
"support_interface_density": { "value": 33.333 },
|
||||||
|
"support_interface_enable": { "value": true },
|
||||||
|
"support_interface_height": { "value": "layer_height * 4" },
|
||||||
|
"support_interface_pattern": { "value": "'grid'" },
|
||||||
|
"support_pattern": { "value": "'zigzag'" },
|
||||||
|
"support_use_towers": { "value": false },
|
||||||
|
"support_xy_distance": { "value": "wall_line_width_0 * 2" },
|
||||||
|
"support_xy_distance_overhang": { "value": "wall_line_width_0" },
|
||||||
|
"support_xy_overrides_z": { "value": "'xy_overrides_z'" },
|
||||||
|
"support_z_distance": { "value": "layer_height if layer_height >= 0.16 else layer_height * 2" },
|
||||||
|
"top_bottom_pattern": { "value": "'lines'" },
|
||||||
|
"top_bottom_thickness": { "value": "layer_height_0 + layer_height * 3" },
|
||||||
|
"travel_avoid_supports": { "value": true },
|
||||||
|
"travel_retract_before_outer_wall": { "value": true },
|
||||||
|
"wall_0_wipe_dist": { "value": 0 },
|
||||||
|
"wall_thickness": { "value": "line_width * 2" },
|
||||||
|
"z_seam_corner": { "value": "'z_seam_corner_weighted'" },
|
||||||
|
"z_seam_type": { "value": "'back'" }
|
||||||
|
}
|
||||||
|
}
|
|
@ -106,6 +106,7 @@
|
||||||
"retraction_combing_max_distance": { "value": 15 },
|
"retraction_combing_max_distance": { "value": 15 },
|
||||||
"retraction_count_max": { "value": 25 },
|
"retraction_count_max": { "value": 25 },
|
||||||
"retraction_extrusion_window": { "value": 1 },
|
"retraction_extrusion_window": { "value": 1 },
|
||||||
|
"retraction_min_travel": { "value": 5 },
|
||||||
"roofing_layer_count": { "value": "1" },
|
"roofing_layer_count": { "value": "1" },
|
||||||
"roofing_material_flow": { "value": "material_flow" },
|
"roofing_material_flow": { "value": "material_flow" },
|
||||||
"skin_angles": { "value": "[] if infill_pattern not in ['cross', 'cross_3d'] else [20, 110]" },
|
"skin_angles": { "value": "[] if infill_pattern not in ['cross', 'cross_3d'] else [20, 110]" },
|
||||||
|
|
|
@ -156,7 +156,6 @@
|
||||||
"retraction_hop": { "value": "2" },
|
"retraction_hop": { "value": "2" },
|
||||||
"retraction_hop_enabled": { "value": "extruders_enabled_count > 1" },
|
"retraction_hop_enabled": { "value": "extruders_enabled_count > 1" },
|
||||||
"retraction_hop_only_when_collides": { "value": "True" },
|
"retraction_hop_only_when_collides": { "value": "True" },
|
||||||
"retraction_min_travel": { "value": "5" },
|
|
||||||
"retraction_prime_speed": { "value": "15" },
|
"retraction_prime_speed": { "value": "15" },
|
||||||
"skin_overlap": { "value": "10" },
|
"skin_overlap": { "value": "10" },
|
||||||
"speed_prime_tower": { "value": "speed_topbottom" },
|
"speed_prime_tower": { "value": "speed_topbottom" },
|
||||||
|
|
|
@ -373,7 +373,6 @@
|
||||||
"retraction_hop": { "value": 0.4 },
|
"retraction_hop": { "value": 0.4 },
|
||||||
"retraction_hop_enabled": { "value": true },
|
"retraction_hop_enabled": { "value": true },
|
||||||
"retraction_hop_only_when_collides": { "value": false },
|
"retraction_hop_only_when_collides": { "value": false },
|
||||||
"retraction_min_travel": { "value": "line_width * 4" },
|
|
||||||
"retraction_prime_speed": { "value": "retraction_speed" },
|
"retraction_prime_speed": { "value": "retraction_speed" },
|
||||||
"retraction_speed": { "value": 5 },
|
"retraction_speed": { "value": 5 },
|
||||||
"roofing_layer_count": { "value": 2 },
|
"roofing_layer_count": { "value": 2 },
|
||||||
|
@ -386,6 +385,7 @@
|
||||||
"skin_preshrink": { "value": 0 },
|
"skin_preshrink": { "value": 0 },
|
||||||
"skirt_brim_material_flow": { "value": "material_flow" },
|
"skirt_brim_material_flow": { "value": "material_flow" },
|
||||||
"skirt_brim_minimal_length": { "value": 500 },
|
"skirt_brim_minimal_length": { "value": 500 },
|
||||||
|
"small_skin_width": { "value": 4 },
|
||||||
"speed_equalize_flow_width_factor": { "value": 0 },
|
"speed_equalize_flow_width_factor": { "value": 0 },
|
||||||
"speed_prime_tower": { "value": "speed_topbottom" },
|
"speed_prime_tower": { "value": "speed_topbottom" },
|
||||||
"speed_print": { "value": 50 },
|
"speed_print": { "value": 50 },
|
||||||
|
@ -426,7 +426,7 @@
|
||||||
"travel_avoid_other_parts": { "value": false },
|
"travel_avoid_other_parts": { "value": false },
|
||||||
"wall_0_inset": { "value": 0 },
|
"wall_0_inset": { "value": 0 },
|
||||||
"wall_0_material_flow": { "value": "material_flow" },
|
"wall_0_material_flow": { "value": "material_flow" },
|
||||||
"wall_0_wipe_dist": { "value": 0 },
|
"wall_0_wipe_dist": { "value": 0.8 },
|
||||||
"wall_material_flow": { "value": "material_flow" },
|
"wall_material_flow": { "value": "material_flow" },
|
||||||
"wall_x_material_flow": { "value": "material_flow" },
|
"wall_x_material_flow": { "value": "material_flow" },
|
||||||
"xy_offset": { "value": 0 },
|
"xy_offset": { "value": 0 },
|
||||||
|
|
|
@ -108,7 +108,6 @@
|
||||||
"retraction_hop": { "value": "2" },
|
"retraction_hop": { "value": "2" },
|
||||||
"retraction_hop_enabled": { "value": "extruders_enabled_count > 1" },
|
"retraction_hop_enabled": { "value": "extruders_enabled_count > 1" },
|
||||||
"retraction_hop_only_when_collides": { "value": "True" },
|
"retraction_hop_only_when_collides": { "value": "True" },
|
||||||
"retraction_min_travel": { "value": "5" },
|
|
||||||
"retraction_prime_speed": { "value": "15" },
|
"retraction_prime_speed": { "value": "15" },
|
||||||
"retraction_speed": { "value": "45" },
|
"retraction_speed": { "value": "45" },
|
||||||
"speed_prime_tower": { "value": "speed_topbottom" },
|
"speed_prime_tower": { "value": "speed_topbottom" },
|
||||||
|
|
|
@ -110,7 +110,6 @@
|
||||||
"retraction_hop": { "value": "2" },
|
"retraction_hop": { "value": "2" },
|
||||||
"retraction_hop_enabled": { "value": "extruders_enabled_count > 1" },
|
"retraction_hop_enabled": { "value": "extruders_enabled_count > 1" },
|
||||||
"retraction_hop_only_when_collides": { "value": "True" },
|
"retraction_hop_only_when_collides": { "value": "True" },
|
||||||
"retraction_min_travel": { "value": "5" },
|
|
||||||
"retraction_prime_speed": { "value": "15" },
|
"retraction_prime_speed": { "value": "15" },
|
||||||
"retraction_speed": { "value": "45" },
|
"retraction_speed": { "value": "45" },
|
||||||
"speed_prime_tower": { "value": "speed_topbottom" },
|
"speed_prime_tower": { "value": "speed_topbottom" },
|
||||||
|
|
|
@ -55,7 +55,7 @@
|
||||||
"machine_endstop_positive_direction_y": { "default_value": true },
|
"machine_endstop_positive_direction_y": { "default_value": true },
|
||||||
"machine_endstop_positive_direction_z": { "default_value": false },
|
"machine_endstop_positive_direction_z": { "default_value": false },
|
||||||
"machine_feeder_wheel_diameter": { "default_value": 7.5 },
|
"machine_feeder_wheel_diameter": { "default_value": 7.5 },
|
||||||
"machine_gcode_flavor": { "default_value": "RepRap (RepRap)" },
|
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
|
||||||
"machine_head_with_fans_polygon":
|
"machine_head_with_fans_polygon":
|
||||||
{
|
{
|
||||||
"default_value": [
|
"default_value": [
|
||||||
|
@ -76,7 +76,7 @@
|
||||||
"machine_max_jerk_xy": { "default_value": 20 },
|
"machine_max_jerk_xy": { "default_value": 20 },
|
||||||
"machine_max_jerk_z": { "default_value": 1 },
|
"machine_max_jerk_z": { "default_value": 1 },
|
||||||
"machine_name": { "default_value": "VORON2" },
|
"machine_name": { "default_value": "VORON2" },
|
||||||
"machine_start_gcode": { "default_value": "print_start" },
|
"machine_start_gcode": { "default_value": ";Nozzle diameter = {machine_nozzle_size}\n;Filament type = {material_type}\n;Filament name = {material_name}\n;Filament weight = {filament_weight}\n; M190 S{material_bed_temperature_layer_0}\n; M109 S{material_print_temperature_layer_0}\nprint_start EXTRUDER={material_print_temperature_layer_0} BED={material_bed_temperature_layer_0} CHAMBER={build_volume_temperature}" },
|
||||||
"machine_steps_per_mm_x": { "default_value": 80 },
|
"machine_steps_per_mm_x": { "default_value": 80 },
|
||||||
"machine_steps_per_mm_y": { "default_value": 80 },
|
"machine_steps_per_mm_y": { "default_value": 80 },
|
||||||
"machine_steps_per_mm_z": { "default_value": 400 },
|
"machine_steps_per_mm_z": { "default_value": 400 },
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "Extruder",
|
||||||
|
"inherits": "fdmextruder",
|
||||||
|
"metadata":
|
||||||
|
{
|
||||||
|
"machine": "flashforge_adventurer_base",
|
||||||
|
"position": "0"
|
||||||
|
},
|
||||||
|
"overrides":
|
||||||
|
{
|
||||||
|
"extruder_nr": { "default_value": 0 },
|
||||||
|
"machine_nozzle_size": { "default_value": 0.4 },
|
||||||
|
"material_diameter": { "default_value": 1.75 }
|
||||||
|
}
|
||||||
|
}
|
16
resources/extruders/ratrig_base_extruder_0.def.json
Normal file
16
resources/extruders/ratrig_base_extruder_0.def.json
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"name": "Extruder 1",
|
||||||
|
"inherits": "fdmextruder",
|
||||||
|
"metadata":
|
||||||
|
{
|
||||||
|
"machine": "ratrig_base",
|
||||||
|
"position": "0"
|
||||||
|
},
|
||||||
|
"overrides":
|
||||||
|
{
|
||||||
|
"extruder_nr": { "default_value": 0 },
|
||||||
|
"machine_nozzle_size": { "default_value": 0.4 },
|
||||||
|
"material_diameter": { "default_value": 1.75 }
|
||||||
|
}
|
||||||
|
}
|
|
@ -4946,6 +4946,14 @@ msgctxt "@action:inmenu menubar:edit"
|
||||||
msgid "Ungroup Models"
|
msgid "Ungroup Models"
|
||||||
msgstr "Rozdělit modely"
|
msgstr "Rozdělit modely"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print Before"
|
||||||
|
msgstr "Tisknout před"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print After"
|
||||||
|
msgstr "Tisknout po"
|
||||||
|
|
||||||
msgctxt "@button"
|
msgctxt "@button"
|
||||||
msgid "Uninstall"
|
msgid "Uninstall"
|
||||||
msgstr "Odinstalovat"
|
msgstr "Odinstalovat"
|
||||||
|
|
|
@ -2583,6 +2583,14 @@ msgctxt "print_sequence label"
|
||||||
msgid "Print Sequence"
|
msgid "Print Sequence"
|
||||||
msgstr "Tisková sekvence"
|
msgstr "Tisková sekvence"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled label"
|
||||||
|
msgid "Set Print Sequence Manually"
|
||||||
|
msgstr "Nastavit tiskovou sekvenci ručně"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled description"
|
||||||
|
msgid "Allows to order the object list to set the print sequence manually. First object from the list will be printed first."
|
||||||
|
msgstr "Umožňuje řadit seznam objektů pro ruční nastavení tiskové sekvence. První objekt ze seznamu bude vytisknut jako první."
|
||||||
|
|
||||||
msgctxt "speed_print label"
|
msgctxt "speed_print label"
|
||||||
msgid "Print Speed"
|
msgid "Print Speed"
|
||||||
msgstr "Rychlost tisku"
|
msgstr "Rychlost tisku"
|
||||||
|
|
|
@ -4565,6 +4565,14 @@ msgctxt "@action:inmenu menubar:edit"
|
||||||
msgid "Ungroup Models"
|
msgid "Ungroup Models"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print Before"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print After"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgctxt "@button"
|
msgctxt "@button"
|
||||||
msgid "Uninstall"
|
msgid "Uninstall"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -4930,6 +4930,14 @@ msgctxt "@action:inmenu menubar:edit"
|
||||||
msgid "Ungroup Models"
|
msgid "Ungroup Models"
|
||||||
msgstr "Gruppierung für Modelle aufheben"
|
msgstr "Gruppierung für Modelle aufheben"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print Before"
|
||||||
|
msgstr "Vor dem Drucken"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print After"
|
||||||
|
msgstr "Nach dem Drucken"
|
||||||
|
|
||||||
msgctxt "@button"
|
msgctxt "@button"
|
||||||
msgid "Uninstall"
|
msgid "Uninstall"
|
||||||
msgstr "Deinstallieren"
|
msgstr "Deinstallieren"
|
||||||
|
|
|
@ -2580,6 +2580,14 @@ msgctxt "print_sequence label"
|
||||||
msgid "Print Sequence"
|
msgid "Print Sequence"
|
||||||
msgstr "Druckreihenfolge"
|
msgstr "Druckreihenfolge"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled label"
|
||||||
|
msgid "Set Print Sequence Manually"
|
||||||
|
msgstr "Druckreihenfolge manuell einstellen"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled description"
|
||||||
|
msgid "Allows to order the object list to set the print sequence manually. First object from the list will be printed first."
|
||||||
|
msgstr "Ermöglicht das Ordnen der Objektliste, um die Druckreihenfolge manuell festzulegen. Das erste Objekt aus der Liste wird zuerst gedruckt."
|
||||||
|
|
||||||
msgctxt "speed_print label"
|
msgctxt "speed_print label"
|
||||||
msgid "Print Speed"
|
msgid "Print Speed"
|
||||||
msgstr "Druckgeschwindigkeit"
|
msgstr "Druckgeschwindigkeit"
|
||||||
|
|
|
@ -4931,6 +4931,14 @@ msgctxt "@action:inmenu menubar:edit"
|
||||||
msgid "Ungroup Models"
|
msgid "Ungroup Models"
|
||||||
msgstr "Desagrupar modelos"
|
msgstr "Desagrupar modelos"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print Before"
|
||||||
|
msgstr "Imprimir antes"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print After"
|
||||||
|
msgstr "Imprimir después"
|
||||||
|
|
||||||
msgctxt "@button"
|
msgctxt "@button"
|
||||||
msgid "Uninstall"
|
msgid "Uninstall"
|
||||||
msgstr "Desinstalar"
|
msgstr "Desinstalar"
|
||||||
|
|
|
@ -2580,6 +2580,14 @@ msgctxt "print_sequence label"
|
||||||
msgid "Print Sequence"
|
msgid "Print Sequence"
|
||||||
msgstr "Secuencia de impresión"
|
msgstr "Secuencia de impresión"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled label"
|
||||||
|
msgid "Set Print Sequence Manually"
|
||||||
|
msgstr "Establecer secuencia de impresión manualmente"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled description"
|
||||||
|
msgid "Allows to order the object list to set the print sequence manually. First object from the list will be printed first."
|
||||||
|
msgstr "Permite ordenar la lista de objetos para establecer la secuencia de impresión manualmente. El primer objeto de la lista se imprimirá primero."
|
||||||
|
|
||||||
msgctxt "speed_print label"
|
msgctxt "speed_print label"
|
||||||
msgid "Print Speed"
|
msgid "Print Speed"
|
||||||
msgstr "Velocidad de impresión"
|
msgstr "Velocidad de impresión"
|
||||||
|
|
|
@ -4588,6 +4588,14 @@ msgctxt "print_sequence option one_at_a_time"
|
||||||
msgid "One at a Time"
|
msgid "One at a Time"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled label"
|
||||||
|
msgid "Set Print Sequence Manually"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled description"
|
||||||
|
msgid "Allows to order the object list to set the print sequence manually. First object from the list will be printed first."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgctxt "infill_mesh label"
|
msgctxt "infill_mesh label"
|
||||||
msgid "Infill Mesh"
|
msgid "Infill Mesh"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -4899,6 +4899,14 @@ msgctxt "@action:inmenu menubar:edit"
|
||||||
msgid "Ungroup Models"
|
msgid "Ungroup Models"
|
||||||
msgstr "Poista mallien ryhmitys"
|
msgstr "Poista mallien ryhmitys"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print Before"
|
||||||
|
msgstr "Tulosta ennen"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print After"
|
||||||
|
msgstr "Tulosta jälkeen"
|
||||||
|
|
||||||
msgctxt "@button"
|
msgctxt "@button"
|
||||||
msgid "Uninstall"
|
msgid "Uninstall"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -2578,6 +2578,14 @@ msgctxt "print_sequence label"
|
||||||
msgid "Print Sequence"
|
msgid "Print Sequence"
|
||||||
msgstr "Tulostusjärjestys"
|
msgstr "Tulostusjärjestys"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled label"
|
||||||
|
msgid "Set Print Sequence Manually"
|
||||||
|
msgstr "Aseta tulostusjärjestys manuaalisesti"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled description"
|
||||||
|
msgid "Allows to order the object list to set the print sequence manually. First object from the list will be printed first."
|
||||||
|
msgstr "Mahdollistaa kohteiden järjestämisen tulostusjärjestyksen manuaaliseen asettamiseen. Listan ensimmäinen kohde tulostetaan ensin."
|
||||||
|
|
||||||
msgctxt "speed_print label"
|
msgctxt "speed_print label"
|
||||||
msgid "Print Speed"
|
msgid "Print Speed"
|
||||||
msgstr "Tulostusnopeus"
|
msgstr "Tulostusnopeus"
|
||||||
|
|
|
@ -4928,6 +4928,14 @@ msgctxt "@action:inmenu menubar:edit"
|
||||||
msgid "Ungroup Models"
|
msgid "Ungroup Models"
|
||||||
msgstr "Dégrouper les modèles"
|
msgstr "Dégrouper les modèles"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print Before"
|
||||||
|
msgstr "Imprimer avant"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print After"
|
||||||
|
msgstr "Imprimer après"
|
||||||
|
|
||||||
msgctxt "@button"
|
msgctxt "@button"
|
||||||
msgid "Uninstall"
|
msgid "Uninstall"
|
||||||
msgstr "Désinstaller"
|
msgstr "Désinstaller"
|
||||||
|
|
|
@ -2580,6 +2580,14 @@ msgctxt "print_sequence label"
|
||||||
msgid "Print Sequence"
|
msgid "Print Sequence"
|
||||||
msgstr "Séquence d'impression"
|
msgstr "Séquence d'impression"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled label"
|
||||||
|
msgid "Set Print Sequence Manually"
|
||||||
|
msgstr "Définir la séquence d'impression manuellement"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled description"
|
||||||
|
msgid "Allows to order the object list to set the print sequence manually. First object from the list will be printed first."
|
||||||
|
msgstr "Permet de classer la liste des objets pour définir manuellement la séquence d'impression. Le premier objet de la liste sera imprimé en premier."
|
||||||
|
|
||||||
msgctxt "speed_print label"
|
msgctxt "speed_print label"
|
||||||
msgid "Print Speed"
|
msgid "Print Speed"
|
||||||
msgstr "Vitesse d’impression"
|
msgstr "Vitesse d’impression"
|
||||||
|
|
|
@ -4913,6 +4913,14 @@ msgctxt "@action:inmenu menubar:edit"
|
||||||
msgid "Ungroup Models"
|
msgid "Ungroup Models"
|
||||||
msgstr "Csoport bontása"
|
msgstr "Csoport bontása"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print Before"
|
||||||
|
msgstr "Nyomtatás előtt"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print After"
|
||||||
|
msgstr "Nyomtatás után"
|
||||||
|
|
||||||
msgctxt "@button"
|
msgctxt "@button"
|
||||||
msgid "Uninstall"
|
msgid "Uninstall"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -2585,6 +2585,14 @@ msgctxt "print_sequence label"
|
||||||
msgid "Print Sequence"
|
msgid "Print Sequence"
|
||||||
msgstr "Nyomtatási sorrend"
|
msgstr "Nyomtatási sorrend"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled label"
|
||||||
|
msgid "Set Print Sequence Manually"
|
||||||
|
msgstr "Nyomtatási sorrend kézi beállítása"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled description"
|
||||||
|
msgid "Allows to order the object list to set the print sequence manually. First object from the list will be printed first."
|
||||||
|
msgstr "Lehetővé teszi az objektumlista rendezését a nyomtatási sorrend kézi beállításához. A lista első objektuma lesz először nyomtatva."
|
||||||
|
|
||||||
msgctxt "speed_print label"
|
msgctxt "speed_print label"
|
||||||
msgid "Print Speed"
|
msgid "Print Speed"
|
||||||
msgstr "Nyomtatási sebesség"
|
msgstr "Nyomtatási sebesség"
|
||||||
|
|
|
@ -4931,6 +4931,14 @@ msgctxt "@action:inmenu menubar:edit"
|
||||||
msgid "Ungroup Models"
|
msgid "Ungroup Models"
|
||||||
msgstr "Separa modelli"
|
msgstr "Separa modelli"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print Before"
|
||||||
|
msgstr "Stampa prima"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print After"
|
||||||
|
msgstr "Stampa dopo"
|
||||||
|
|
||||||
msgctxt "@button"
|
msgctxt "@button"
|
||||||
msgid "Uninstall"
|
msgid "Uninstall"
|
||||||
msgstr "Disinstalla"
|
msgstr "Disinstalla"
|
||||||
|
|
|
@ -2580,6 +2580,14 @@ msgctxt "print_sequence label"
|
||||||
msgid "Print Sequence"
|
msgid "Print Sequence"
|
||||||
msgstr "Sequenza di stampa"
|
msgstr "Sequenza di stampa"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled label"
|
||||||
|
msgid "Set Print Sequence Manually"
|
||||||
|
msgstr "Imposta manualmente la sequenza di stampa"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled description"
|
||||||
|
msgid "Allows to order the object list to set the print sequence manually. First object from the list will be printed first."
|
||||||
|
msgstr "Consente di ordinare l'elenco degli oggetti per impostare manualmente la sequenza di stampa. Il primo oggetto dell'elenco sarà stampato per primo."
|
||||||
|
|
||||||
msgctxt "speed_print label"
|
msgctxt "speed_print label"
|
||||||
msgid "Print Speed"
|
msgid "Print Speed"
|
||||||
msgstr "Velocità di stampa"
|
msgstr "Velocità di stampa"
|
||||||
|
|
|
@ -4914,6 +4914,14 @@ msgctxt "@action:inmenu menubar:edit"
|
||||||
msgid "Ungroup Models"
|
msgid "Ungroup Models"
|
||||||
msgstr "モデルを非グループ化"
|
msgstr "モデルを非グループ化"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print Before"
|
||||||
|
msgstr "印刷前"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print After"
|
||||||
|
msgstr "印刷後"
|
||||||
|
|
||||||
msgctxt "@button"
|
msgctxt "@button"
|
||||||
msgid "Uninstall"
|
msgid "Uninstall"
|
||||||
msgstr "アンインストール"
|
msgstr "アンインストール"
|
||||||
|
|
|
@ -2580,6 +2580,14 @@ msgctxt "print_sequence label"
|
||||||
msgid "Print Sequence"
|
msgid "Print Sequence"
|
||||||
msgstr "印刷頻度"
|
msgstr "印刷頻度"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled label"
|
||||||
|
msgid "Set Print Sequence Manually"
|
||||||
|
msgstr "手動で印刷順序を設定する"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled description"
|
||||||
|
msgid "Allows to order the object list to set the print sequence manually. First object from the list will be printed first."
|
||||||
|
msgstr "オブジェクトリストを並べ替えて、手動で印刷順序を設定することができます。リストの最初のオブジェクトが最初に印刷されます。"
|
||||||
|
|
||||||
msgctxt "speed_print label"
|
msgctxt "speed_print label"
|
||||||
msgid "Print Speed"
|
msgid "Print Speed"
|
||||||
msgstr "印刷速度"
|
msgstr "印刷速度"
|
||||||
|
|
|
@ -4917,6 +4917,14 @@ msgctxt "@action:inmenu menubar:edit"
|
||||||
msgid "Ungroup Models"
|
msgid "Ungroup Models"
|
||||||
msgstr "모델 그룹 해제"
|
msgstr "모델 그룹 해제"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print Before"
|
||||||
|
msgstr "인쇄 전"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print After"
|
||||||
|
msgstr "인쇄 후"
|
||||||
|
|
||||||
msgctxt "@button"
|
msgctxt "@button"
|
||||||
msgid "Uninstall"
|
msgid "Uninstall"
|
||||||
msgstr "설치 제거"
|
msgstr "설치 제거"
|
||||||
|
|
|
@ -2580,6 +2580,14 @@ msgctxt "print_sequence label"
|
||||||
msgid "Print Sequence"
|
msgid "Print Sequence"
|
||||||
msgstr "프린팅 순서"
|
msgstr "프린팅 순서"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled label"
|
||||||
|
msgid "Set Print Sequence Manually"
|
||||||
|
msgstr "수동으로 인쇄 순서 설정"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled description"
|
||||||
|
msgid "Allows to order the object list to set the print sequence manually. First object from the list will be printed first."
|
||||||
|
msgstr "객체 목록을 정렬하여 수동으로 인쇄 순서를 설정할 수 있습니다. 목록의 첫 번째 객체가 먼저 인쇄됩니다."
|
||||||
|
|
||||||
msgctxt "speed_print label"
|
msgctxt "speed_print label"
|
||||||
msgid "Print Speed"
|
msgid "Print Speed"
|
||||||
msgstr "프린팅 속도"
|
msgstr "프린팅 속도"
|
||||||
|
|
|
@ -4925,6 +4925,14 @@ msgctxt "@action:inmenu menubar:edit"
|
||||||
msgid "Ungroup Models"
|
msgid "Ungroup Models"
|
||||||
msgstr "Groeperen van Modellen Opheffen"
|
msgstr "Groeperen van Modellen Opheffen"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print Before"
|
||||||
|
msgstr "Afdrukken voor"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print After"
|
||||||
|
msgstr "Afdrukken na"
|
||||||
|
|
||||||
msgctxt "@button"
|
msgctxt "@button"
|
||||||
msgid "Uninstall"
|
msgid "Uninstall"
|
||||||
msgstr "De-installeren"
|
msgstr "De-installeren"
|
||||||
|
|
|
@ -2580,6 +2580,14 @@ msgctxt "print_sequence label"
|
||||||
msgid "Print Sequence"
|
msgid "Print Sequence"
|
||||||
msgstr "Printvolgorde"
|
msgstr "Printvolgorde"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled label"
|
||||||
|
msgid "Set Print Sequence Manually"
|
||||||
|
msgstr "Handmatig afdrukvolgorde instellen"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled description"
|
||||||
|
msgid "Allows to order the object list to set the print sequence manually. First object from the list will be printed first."
|
||||||
|
msgstr "Maakt het mogelijk de objectlijst te ordenen om de afdrukvolgorde handmatig in te stellen. Het eerste object van de lijst wordt als eerste afgedrukt."
|
||||||
|
|
||||||
msgctxt "speed_print label"
|
msgctxt "speed_print label"
|
||||||
msgid "Print Speed"
|
msgid "Print Speed"
|
||||||
msgstr "Printsnelheid"
|
msgstr "Printsnelheid"
|
||||||
|
|
|
@ -4916,6 +4916,14 @@ msgctxt "@action:inmenu menubar:edit"
|
||||||
msgid "Ungroup Models"
|
msgid "Ungroup Models"
|
||||||
msgstr "Rozgrupuj modele"
|
msgstr "Rozgrupuj modele"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print Before"
|
||||||
|
msgstr "Drukuj przed"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print After"
|
||||||
|
msgstr "Drukuj po"
|
||||||
|
|
||||||
msgctxt "@button"
|
msgctxt "@button"
|
||||||
msgid "Uninstall"
|
msgid "Uninstall"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -2584,6 +2584,14 @@ msgctxt "print_sequence label"
|
||||||
msgid "Print Sequence"
|
msgid "Print Sequence"
|
||||||
msgstr "Sekwencja Wydruku"
|
msgstr "Sekwencja Wydruku"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled label"
|
||||||
|
msgid "Set Print Sequence Manually"
|
||||||
|
msgstr "Ręczne ustawienie kolejności drukowania"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled description"
|
||||||
|
msgid "Allows to order the object list to set the print sequence manually. First object from the list will be printed first."
|
||||||
|
msgstr "Umożliwia ręczne ustawienie kolejności drukowania na liście obiektów. Pierwszy obiekt z listy zostanie wydrukowany jako pierwszy."
|
||||||
|
|
||||||
msgctxt "speed_print label"
|
msgctxt "speed_print label"
|
||||||
msgid "Print Speed"
|
msgid "Print Speed"
|
||||||
msgstr "Prędkość Druku"
|
msgstr "Prędkość Druku"
|
||||||
|
|
|
@ -4942,6 +4942,14 @@ msgctxt "@action:inmenu menubar:edit"
|
||||||
msgid "Ungroup Models"
|
msgid "Ungroup Models"
|
||||||
msgstr "Desagrupar Modelos"
|
msgstr "Desagrupar Modelos"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print Before"
|
||||||
|
msgstr "Imprimir antes"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print After"
|
||||||
|
msgstr "Imprimir depois"
|
||||||
|
|
||||||
msgctxt "@button"
|
msgctxt "@button"
|
||||||
msgid "Uninstall"
|
msgid "Uninstall"
|
||||||
msgstr "Desinstalar"
|
msgstr "Desinstalar"
|
||||||
|
|
|
@ -2585,6 +2585,14 @@ msgctxt "print_sequence label"
|
||||||
msgid "Print Sequence"
|
msgid "Print Sequence"
|
||||||
msgstr "Sequência de Impressão"
|
msgstr "Sequência de Impressão"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled label"
|
||||||
|
msgid "Set Print Sequence Manually"
|
||||||
|
msgstr "Definir sequência de impressão manualmente"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled description"
|
||||||
|
msgid "Allows to order the object list to set the print sequence manually. First object from the list will be printed first."
|
||||||
|
msgstr "Permite ordenar a lista de objetos para definir a sequência de impressão manualmente. O primeiro objeto da lista será impresso primeiro."
|
||||||
|
|
||||||
msgctxt "speed_print label"
|
msgctxt "speed_print label"
|
||||||
msgid "Print Speed"
|
msgid "Print Speed"
|
||||||
msgstr "Velocidade de Impressão"
|
msgstr "Velocidade de Impressão"
|
||||||
|
|
|
@ -4932,6 +4932,14 @@ msgctxt "@action:inmenu menubar:edit"
|
||||||
msgid "Ungroup Models"
|
msgid "Ungroup Models"
|
||||||
msgstr "Desagrupar Modelos"
|
msgstr "Desagrupar Modelos"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print Before"
|
||||||
|
msgstr "Imprimir antes"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print After"
|
||||||
|
msgstr "Imprimir depois"
|
||||||
|
|
||||||
msgctxt "@button"
|
msgctxt "@button"
|
||||||
msgid "Uninstall"
|
msgid "Uninstall"
|
||||||
msgstr "Desinstalar"
|
msgstr "Desinstalar"
|
||||||
|
|
|
@ -2580,6 +2580,14 @@ msgctxt "print_sequence label"
|
||||||
msgid "Print Sequence"
|
msgid "Print Sequence"
|
||||||
msgstr "Sequência de impressão"
|
msgstr "Sequência de impressão"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled label"
|
||||||
|
msgid "Set Print Sequence Manually"
|
||||||
|
msgstr "Definir sequência de impressão manualmente"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled description"
|
||||||
|
msgid "Allows to order the object list to set the print sequence manually. First object from the list will be printed first."
|
||||||
|
msgstr "Permite ordenar a lista de objetos para definir a sequência de impressão manualmente. O primeiro objeto da lista será impresso primeiro."
|
||||||
|
|
||||||
msgctxt "speed_print label"
|
msgctxt "speed_print label"
|
||||||
msgid "Print Speed"
|
msgid "Print Speed"
|
||||||
msgstr "Velocidade de Impressão"
|
msgstr "Velocidade de Impressão"
|
||||||
|
|
|
@ -4955,6 +4955,14 @@ msgctxt "@action:inmenu menubar:edit"
|
||||||
msgid "Ungroup Models"
|
msgid "Ungroup Models"
|
||||||
msgstr "Разгруппировать модели"
|
msgstr "Разгруппировать модели"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print Before"
|
||||||
|
msgstr "Печатать до"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print After"
|
||||||
|
msgstr "Печатать после"
|
||||||
|
|
||||||
msgctxt "@button"
|
msgctxt "@button"
|
||||||
msgid "Uninstall"
|
msgid "Uninstall"
|
||||||
msgstr "Удалить"
|
msgstr "Удалить"
|
||||||
|
|
|
@ -2580,6 +2580,14 @@ msgctxt "print_sequence label"
|
||||||
msgid "Print Sequence"
|
msgid "Print Sequence"
|
||||||
msgstr "Последовательная печать"
|
msgstr "Последовательная печать"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled label"
|
||||||
|
msgid "Set Print Sequence Manually"
|
||||||
|
msgstr "Установить последовательность печати вручную"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled description"
|
||||||
|
msgid "Allows to order the object list to set the print sequence manually. First object from the list will be printed first."
|
||||||
|
msgstr "Позволяет упорядочить список объектов для ручной настройки последовательности печати. Первый объект из списка будет напечатан первым."
|
||||||
|
|
||||||
msgctxt "speed_print label"
|
msgctxt "speed_print label"
|
||||||
msgid "Print Speed"
|
msgid "Print Speed"
|
||||||
msgstr "Скорость печати"
|
msgstr "Скорость печати"
|
||||||
|
|
|
@ -4931,6 +4931,14 @@ msgctxt "@action:inmenu menubar:edit"
|
||||||
msgid "Ungroup Models"
|
msgid "Ungroup Models"
|
||||||
msgstr "Model Grubunu Çöz"
|
msgstr "Model Grubunu Çöz"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print Before"
|
||||||
|
msgstr "Önce Yazdır"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print After"
|
||||||
|
msgstr "Sonra Yazdır"
|
||||||
|
|
||||||
msgctxt "@button"
|
msgctxt "@button"
|
||||||
msgid "Uninstall"
|
msgid "Uninstall"
|
||||||
msgstr "Kaldır"
|
msgstr "Kaldır"
|
||||||
|
|
|
@ -2580,6 +2580,14 @@ msgctxt "print_sequence label"
|
||||||
msgid "Print Sequence"
|
msgid "Print Sequence"
|
||||||
msgstr "Yazdırma Dizisi"
|
msgstr "Yazdırma Dizisi"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled label"
|
||||||
|
msgid "Set Print Sequence Manually"
|
||||||
|
msgstr "Baskı Sırasını Manuel Olarak Ayarla"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled description"
|
||||||
|
msgid "Allows to order the object list to set the print sequence manually. First object from the list will be printed first."
|
||||||
|
msgstr "Nesne listesini sıralayarak baskı sırasını manuel olarak ayarlamayı sağlar. Listeden ilk nesne ilk olarak basılacak."
|
||||||
|
|
||||||
msgctxt "speed_print label"
|
msgctxt "speed_print label"
|
||||||
msgid "Print Speed"
|
msgid "Print Speed"
|
||||||
msgstr "Yazdırma Hızı"
|
msgstr "Yazdırma Hızı"
|
||||||
|
|
|
@ -4919,6 +4919,14 @@ msgctxt "@action:inmenu menubar:edit"
|
||||||
msgid "Ungroup Models"
|
msgid "Ungroup Models"
|
||||||
msgstr "拆分模型"
|
msgstr "拆分模型"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print Before"
|
||||||
|
msgstr "打印前"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print After"
|
||||||
|
msgstr "打印后"
|
||||||
|
|
||||||
msgctxt "@button"
|
msgctxt "@button"
|
||||||
msgid "Uninstall"
|
msgid "Uninstall"
|
||||||
msgstr "卸载"
|
msgstr "卸载"
|
||||||
|
|
|
@ -2580,6 +2580,14 @@ msgctxt "print_sequence label"
|
||||||
msgid "Print Sequence"
|
msgid "Print Sequence"
|
||||||
msgstr "打印序列"
|
msgstr "打印序列"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled label"
|
||||||
|
msgid "Set Print Sequence Manually"
|
||||||
|
msgstr "手动设置打印顺序"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled description"
|
||||||
|
msgid "Allows to order the object list to set the print sequence manually. First object from the list will be printed first."
|
||||||
|
msgstr "允许对对象列表进行排序,以手动设置打印顺序。列表中的第一个对象将首先被打印。"
|
||||||
|
|
||||||
msgctxt "speed_print label"
|
msgctxt "speed_print label"
|
||||||
msgid "Print Speed"
|
msgid "Print Speed"
|
||||||
msgstr "打印速度"
|
msgstr "打印速度"
|
||||||
|
|
|
@ -4911,6 +4911,14 @@ msgctxt "@action:inmenu menubar:edit"
|
||||||
msgid "Ungroup Models"
|
msgid "Ungroup Models"
|
||||||
msgstr "取消模型群組"
|
msgstr "取消模型群組"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print Before"
|
||||||
|
msgstr "列印前"
|
||||||
|
|
||||||
|
msgctxt "@action:inmenu menubar:edit"
|
||||||
|
msgid "Print After"
|
||||||
|
msgstr "列印後"
|
||||||
|
|
||||||
msgctxt "@button"
|
msgctxt "@button"
|
||||||
msgid "Uninstall"
|
msgid "Uninstall"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -2585,6 +2585,14 @@ msgctxt "print_sequence label"
|
||||||
msgid "Print Sequence"
|
msgid "Print Sequence"
|
||||||
msgstr "列印順序"
|
msgstr "列印順序"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled label"
|
||||||
|
msgid "Set Print Sequence Manually"
|
||||||
|
msgstr "手動設置列印順序"
|
||||||
|
|
||||||
|
msgctxt "user_defined_print_order_enabled description"
|
||||||
|
msgid "Allows to order the object list to set the print sequence manually. First object from the list will be printed first."
|
||||||
|
msgstr "允許手動設置物件列表以設定列印順序。列表中的第一個物件將首先被列印。"
|
||||||
|
|
||||||
msgctxt "speed_print label"
|
msgctxt "speed_print label"
|
||||||
msgid "Print Speed"
|
msgid "Print Speed"
|
||||||
msgstr "列印速度"
|
msgstr "列印速度"
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
[general]
|
||||||
|
definition = elegoo_neptune_4
|
||||||
|
name = Accurate
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[metadata]
|
||||||
|
intent_category = engineering
|
||||||
|
is_experimental = True
|
||||||
|
material = generic_pla
|
||||||
|
quality_type = Elegoo_layer_020
|
||||||
|
setting_version = 22
|
||||||
|
type = intent
|
||||||
|
variant = 0.40mm_Elegoo_Nozzle
|
||||||
|
|
||||||
|
[values]
|
||||||
|
speed_infill = =speed_print
|
||||||
|
speed_print = 150
|
||||||
|
speed_topbottom = =speed_print * 2 / 3
|
||||||
|
speed_travel = =min(speed_print * 4 / 3, 250) if speed_print <= 250 else speed_print
|
||||||
|
speed_wall = =speed_print * 2 / 3
|
||||||
|
speed_wall_0 = =speed_wall
|
||||||
|
speed_wall_x = =speed_wall
|
||||||
|
top_bottom_thickness = =wall_thickness
|
||||||
|
wall_thickness = =line_width * 3
|
||||||
|
|
|
@ -12,6 +12,14 @@ type = intent
|
||||||
variant = AA 0.4
|
variant = AA 0.4
|
||||||
|
|
||||||
[values]
|
[values]
|
||||||
speed_infill = 50
|
_plugin__curaenginegradualflow__0_1_0__max_flow_acceleration = 0.5
|
||||||
top_bottom_thickness = 1.05
|
acceleration_print = 2500
|
||||||
|
acceleration_wall_0 = 1000
|
||||||
|
inset_direction = inside_out
|
||||||
|
jerk_wall_0 = 20
|
||||||
|
speed_print = 50
|
||||||
|
speed_roofing = =math.ceil(speed_wall*(35/50))
|
||||||
|
speed_wall_0 = =math.ceil(speed_wall*(20/50))
|
||||||
|
speed_wall_x = =math.ceil(speed_wall*(35/50))
|
||||||
|
top_bottom_thickness = =max(1.2 , layer_height * 6)
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue