Solved merge conflict. CURA-3321

This commit is contained in:
Jack Ha 2017-03-07 10:34:53 +01:00
commit 42d939b34e
65 changed files with 1358 additions and 418 deletions

View file

@ -11,6 +11,9 @@ add_custom_target(tests)
add_custom_command(TARGET tests POST_BUILD COMMAND "PYTHONPATH=${CMAKE_SOURCE_DIR}/../Uranium/:${CMAKE_SOURCE_DIR}" ${PYTHON_EXECUTABLE} -m pytest -r a --junitxml=${CMAKE_BINARY_DIR}/junit.xml ${CMAKE_SOURCE_DIR} || exit 0) add_custom_command(TARGET tests POST_BUILD COMMAND "PYTHONPATH=${CMAKE_SOURCE_DIR}/../Uranium/:${CMAKE_SOURCE_DIR}" ${PYTHON_EXECUTABLE} -m pytest -r a --junitxml=${CMAKE_BINARY_DIR}/junit.xml ${CMAKE_SOURCE_DIR} || exit 0)
option(CURA_DEBUGMODE "Enable debug dialog and other debug features" OFF) option(CURA_DEBUGMODE "Enable debug dialog and other debug features" OFF)
if(CURA_DEBUGMODE)
set(_cura_debugmode "ON")
endif()
set(CURA_VERSION "master" CACHE STRING "Version name of Cura") set(CURA_VERSION "master" CACHE STRING "Version name of Cura")
set(CURA_BUILDTYPE "" CACHE STRING "Build type of Cura, eg. 'PPA'") set(CURA_BUILDTYPE "" CACHE STRING "Build type of Cura, eg. 'PPA'")

View file

@ -50,6 +50,7 @@ Third party plugins
* [X3G Writer](https://github.com/Ghostkeeper/X3GWriter): Adds support for exporting X3G files. * [X3G Writer](https://github.com/Ghostkeeper/X3GWriter): Adds support for exporting X3G files.
* [Auto orientation](https://github.com/nallath/CuraOrientationPlugin): Calculate the optimal orientation for a model. * [Auto orientation](https://github.com/nallath/CuraOrientationPlugin): Calculate the optimal orientation for a model.
* [OctoPrint Plugin](https://github.com/fieldofview/OctoPrintPlugin): Send printjobs directly to OctoPrint and monitor their progress in Cura. * [OctoPrint Plugin](https://github.com/fieldofview/OctoPrintPlugin): Send printjobs directly to OctoPrint and monitor their progress in Cura.
* [WirelessPrinting Plugin](https://github.com/probonopd/WirelessPrinting): Print wirelessly from Cura to your 3D printer connected to an ESP8266 module.
Making profiles for other printers Making profiles for other printers
---------------------------------- ----------------------------------

22
cura/BuildVolume.py Normal file → Executable file
View file

@ -385,20 +385,22 @@ class BuildVolume(SceneNode):
self.setPosition(Vector(0, -self._raft_thickness, 0), SceneNode.TransformSpace.World) self.setPosition(Vector(0, -self._raft_thickness, 0), SceneNode.TransformSpace.World)
self.raftThicknessChanged.emit() self.raftThicknessChanged.emit()
def _updateExtraZClearance(self): def _updateExtraZClearance(self) -> None:
extra_z = None extra_z = 0.0
extruders = ExtruderManager.getInstance().getMachineExtruders(self._global_container_stack.getId()) extruders = ExtruderManager.getInstance().getMachineExtruders(self._global_container_stack.getId())
use_extruders = False
for extruder in extruders: for extruder in extruders:
retraction_hop = extruder.getProperty("retraction_hop", "value") if extruder.getProperty("retraction_hop_enabled", "value"):
if extra_z is None or retraction_hop > extra_z: retraction_hop = extruder.getProperty("retraction_hop", "value")
extra_z = retraction_hop if extra_z is None or retraction_hop > extra_z:
if extra_z is None: extra_z = retraction_hop
use_extruders = True
if not use_extruders:
# If no extruders, take global value. # If no extruders, take global value.
extra_z = self._global_container_stack.getProperty("retraction_hop", "value") if self._global_container_stack.getProperty("retraction_hop_enabled", "value"):
extra_z = self._global_container_stack.getProperty("retraction_hop", "value")
if extra_z != self._extra_z_clearance: if extra_z != self._extra_z_clearance:
self._extra_z_clearance = extra_z self._extra_z_clearance = extra_z
from UM.Logger import Logger
Logger.log("d", " ### Extra z clearance changed: %s" % extra_z)
## Update the build volume visualization ## Update the build volume visualization
def _onStackChanged(self): def _onStackChanged(self):
@ -892,7 +894,7 @@ class BuildVolume(SceneNode):
_skirt_settings = ["adhesion_type", "skirt_gap", "skirt_line_count", "skirt_brim_line_width", "brim_width", "brim_line_count", "raft_margin", "draft_shield_enabled", "draft_shield_dist"] _skirt_settings = ["adhesion_type", "skirt_gap", "skirt_line_count", "skirt_brim_line_width", "brim_width", "brim_line_count", "raft_margin", "draft_shield_enabled", "draft_shield_dist"]
_raft_settings = ["adhesion_type", "raft_base_thickness", "raft_interface_thickness", "raft_surface_layers", "raft_surface_thickness", "raft_airgap"] _raft_settings = ["adhesion_type", "raft_base_thickness", "raft_interface_thickness", "raft_surface_layers", "raft_surface_thickness", "raft_airgap"]
_extra_z_settings = ["retraction_hop"] _extra_z_settings = ["retraction_hop_enabled", "retraction_hop"]
_prime_settings = ["extruder_prime_pos_x", "extruder_prime_pos_y", "extruder_prime_pos_z"] _prime_settings = ["extruder_prime_pos_x", "extruder_prime_pos_y", "extruder_prime_pos_z"]
_tower_settings = ["prime_tower_enable", "prime_tower_size", "prime_tower_position_x", "prime_tower_position_y"] _tower_settings = ["prime_tower_enable", "prime_tower_size", "prime_tower_position_x", "prime_tower_position_y"]
_ooze_shield_settings = ["ooze_shield_enabled", "ooze_shield_dist"] _ooze_shield_settings = ["ooze_shield_enabled", "ooze_shield_dist"]

View file

@ -6,7 +6,6 @@ from PyQt5.QtCore import QVariantAnimation, QEasingCurve
from PyQt5.QtGui import QVector3D from PyQt5.QtGui import QVector3D
from UM.Math.Vector import Vector from UM.Math.Vector import Vector
from UM.Logger import Logger
class CameraAnimation(QVariantAnimation): class CameraAnimation(QVariantAnimation):

58
cura/CuraApplication.py Normal file → Executable file
View file

@ -20,6 +20,8 @@ from UM.JobQueue import JobQueue
from UM.SaveFile import SaveFile from UM.SaveFile import SaveFile
from UM.Scene.Selection import Selection from UM.Scene.Selection import Selection
from UM.Scene.GroupDecorator import GroupDecorator from UM.Scene.GroupDecorator import GroupDecorator
from UM.Settings.ContainerStack import ContainerStack
from UM.Settings.InstanceContainer import InstanceContainer
from UM.Settings.Validator import Validator from UM.Settings.Validator import Validator
from UM.Message import Message from UM.Message import Message
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
@ -53,7 +55,7 @@ from . import MachineActionManager
from cura.Settings.MachineManager import MachineManager from cura.Settings.MachineManager import MachineManager
from cura.Settings.ExtruderManager import ExtruderManager from cura.Settings.ExtruderManager import ExtruderManager
from cura.Settings.CuraContainerRegistry import CuraContainerRegistry from cura.Settings.UserChangesModel import UserChangesModel
from cura.Settings.ExtrudersModel import ExtrudersModel from cura.Settings.ExtrudersModel import ExtrudersModel
from cura.Settings.ContainerSettingsModel import ContainerSettingsModel from cura.Settings.ContainerSettingsModel import ContainerSettingsModel
from cura.Settings.MaterialSettingsVisibilityHandler import MaterialSettingsVisibilityHandler from cura.Settings.MaterialSettingsVisibilityHandler import MaterialSettingsVisibilityHandler
@ -124,6 +126,8 @@ class CuraApplication(QtApplication):
SettingDefinition.addSettingType("extruder", None, str, Validator) SettingDefinition.addSettingType("extruder", None, str, Validator)
SettingDefinition.addSettingType("[int]", None, str, None)
SettingFunction.registerOperator("extruderValues", ExtruderManager.getExtruderValues) SettingFunction.registerOperator("extruderValues", ExtruderManager.getExtruderValues)
SettingFunction.registerOperator("extruderValue", ExtruderManager.getExtruderValue) SettingFunction.registerOperator("extruderValue", ExtruderManager.getExtruderValue)
SettingFunction.registerOperator("resolveOrValue", ExtruderManager.getResolveOrValue) SettingFunction.registerOperator("resolveOrValue", ExtruderManager.getResolveOrValue)
@ -148,11 +152,11 @@ class CuraApplication(QtApplication):
UM.VersionUpgradeManager.VersionUpgradeManager.getInstance().setCurrentVersions( UM.VersionUpgradeManager.VersionUpgradeManager.getInstance().setCurrentVersions(
{ {
("quality", UM.Settings.InstanceContainer.InstanceContainer.Version): (self.ResourceTypes.QualityInstanceContainer, "application/x-uranium-instancecontainer"), ("quality", InstanceContainer.Version): (self.ResourceTypes.QualityInstanceContainer, "application/x-uranium-instancecontainer"),
("machine_stack", UM.Settings.ContainerStack.ContainerStack.Version): (self.ResourceTypes.MachineStack, "application/x-uranium-containerstack"), ("machine_stack", ContainerStack.Version): (self.ResourceTypes.MachineStack, "application/x-uranium-containerstack"),
("extruder_train", UM.Settings.ContainerStack.ContainerStack.Version): (self.ResourceTypes.ExtruderStack, "application/x-uranium-extruderstack"), ("extruder_train", ContainerStack.Version): (self.ResourceTypes.ExtruderStack, "application/x-uranium-extruderstack"),
("preferences", Preferences.Version): (Resources.Preferences, "application/x-uranium-preferences"), ("preferences", Preferences.Version): (Resources.Preferences, "application/x-uranium-preferences"),
("user", UM.Settings.InstanceContainer.InstanceContainer.Version): (self.ResourceTypes.UserInstanceContainer, "application/x-uranium-instancecontainer") ("user", InstanceContainer.Version): (self.ResourceTypes.UserInstanceContainer, "application/x-uranium-instancecontainer")
} }
) )
@ -241,6 +245,7 @@ class CuraApplication(QtApplication):
Preferences.getInstance().addPreference("mesh/scale_tiny_meshes", True) Preferences.getInstance().addPreference("mesh/scale_tiny_meshes", True)
Preferences.getInstance().addPreference("cura/dialog_on_project_save", True) Preferences.getInstance().addPreference("cura/dialog_on_project_save", True)
Preferences.getInstance().addPreference("cura/asked_dialog_on_project_save", False) Preferences.getInstance().addPreference("cura/asked_dialog_on_project_save", False)
Preferences.getInstance().addPreference("cura/choice_on_profile_override", 0)
Preferences.getInstance().addPreference("cura/currency", "") Preferences.getInstance().addPreference("cura/currency", "")
Preferences.getInstance().addPreference("cura/material_settings", "{}") Preferences.getInstance().addPreference("cura/material_settings", "{}")
@ -323,11 +328,35 @@ class CuraApplication(QtApplication):
## A reusable dialogbox ## A reusable dialogbox
# #
showMessageBox = pyqtSignal(str, str, str, str, int, int, arguments = ["title", "text", "informativeText", "detailedText", "buttons", "icon"]) showMessageBox = pyqtSignal(str, str, str, str, int, int, arguments = ["title", "text", "informativeText", "detailedText", "buttons", "icon"])
def messageBox(self, title, text, informativeText = "", detailedText = "", buttons = QMessageBox.Ok, icon = QMessageBox.NoIcon, callback = None, callback_arguments = []): def messageBox(self, title, text, informativeText = "", detailedText = "", buttons = QMessageBox.Ok, icon = QMessageBox.NoIcon, callback = None, callback_arguments = []):
self._message_box_callback = callback self._message_box_callback = callback
self._message_box_callback_arguments = callback_arguments self._message_box_callback_arguments = callback_arguments
self.showMessageBox.emit(title, text, informativeText, detailedText, buttons, icon) self.showMessageBox.emit(title, text, informativeText, detailedText, buttons, icon)
showDiscardOrKeepProfileChanges = pyqtSignal()
def discardOrKeepProfileChanges(self):
choice = Preferences.getInstance().getValue("cura/choice_on_profile_override")
if choice == 1:
# don't show dialog and DISCARD the profile
self.discardOrKeepProfileChangesClosed("discard")
elif choice == 2:
# don't show dialog and KEEP the profile
self.discardOrKeepProfileChangesClosed("keep")
else:
# ALWAYS ask whether to keep or discard the profile
self.showDiscardOrKeepProfileChanges.emit()
@pyqtSlot(str)
def discardOrKeepProfileChangesClosed(self, option):
if option == "discard":
global_stack = self.getGlobalContainerStack()
for extruder in ExtruderManager.getInstance().getMachineExtruders(global_stack.getId()):
extruder.getTop().clear()
global_stack.getTop().clear()
@pyqtSlot(int) @pyqtSlot(int)
def messageBoxClosed(self, button): def messageBoxClosed(self, button):
if self._message_box_callback: if self._message_box_callback:
@ -648,6 +677,7 @@ class CuraApplication(QtApplication):
qmlRegisterType(MaterialSettingsVisibilityHandler, "Cura", 1, 0, "MaterialSettingsVisibilityHandler") qmlRegisterType(MaterialSettingsVisibilityHandler, "Cura", 1, 0, "MaterialSettingsVisibilityHandler")
qmlRegisterType(QualitySettingsModel, "Cura", 1, 0, "QualitySettingsModel") qmlRegisterType(QualitySettingsModel, "Cura", 1, 0, "QualitySettingsModel")
qmlRegisterType(MachineNameValidator, "Cura", 1, 0, "MachineNameValidator") qmlRegisterType(MachineNameValidator, "Cura", 1, 0, "MachineNameValidator")
qmlRegisterType(UserChangesModel, "Cura", 1, 1, "UserChangesModel")
qmlRegisterSingletonType(ContainerManager, "Cura", 1, 0, "ContainerManager", ContainerManager.createContainerManager) qmlRegisterSingletonType(ContainerManager, "Cura", 1, 0, "ContainerManager", ContainerManager.createContainerManager)
@ -1071,18 +1101,6 @@ class CuraApplication(QtApplication):
fileLoaded = pyqtSignal(str) fileLoaded = pyqtSignal(str)
def _onFileLoaded(self, job):
nodes = job.getResult()
for node in nodes:
if node is not None:
self.fileLoaded.emit(job.getFileName())
node.setSelectable(True)
node.setName(os.path.basename(job.getFileName()))
op = AddSceneNodeOperation(node, self.getController().getScene().getRoot())
op.push()
self.getController().getScene().sceneChanged.emit(node) #Force scene change.
def _onJobFinished(self, job): def _onJobFinished(self, job):
if type(job) is not ReadMeshJob or not job.getResult(): if type(job) is not ReadMeshJob or not job.getResult():
return return
@ -1110,10 +1128,8 @@ class CuraApplication(QtApplication):
else: else:
Logger.log("w", "Could not find a mesh in reloaded node.") Logger.log("w", "Could not find a mesh in reloaded node.")
def _openFile(self, file): def _openFile(self, filename):
job = ReadMeshJob(os.path.abspath(file)) self.readLocalFile(QUrl.fromLocalFile(filename))
job.finished.connect(self._onFileLoaded)
job.start()
def _addProfileReader(self, profile_reader): def _addProfileReader(self, profile_reader):
# TODO: Add the profile reader to the list of plug-ins that can be used when importing profiles. # TODO: Add the profile reader to the list of plug-ins that can be used when importing profiles.

View file

@ -3,4 +3,4 @@
CuraVersion = "@CURA_VERSION@" CuraVersion = "@CURA_VERSION@"
CuraBuildType = "@CURA_BUILDTYPE@" CuraBuildType = "@CURA_BUILDTYPE@"
CuraDebugMode = True if "@CURA_DEBUGMODE@" == "ON" else False CuraDebugMode = True if "@_cura_debugmode@" == "ON" else False

2
cura/LayerDataBuilder.py Normal file → Executable file
View file

@ -63,7 +63,7 @@ class LayerDataBuilder(MeshBuilder):
line_dimensions = numpy.empty((vertex_count, 2), numpy.float32) line_dimensions = numpy.empty((vertex_count, 2), numpy.float32)
colors = numpy.empty((vertex_count, 4), numpy.float32) colors = numpy.empty((vertex_count, 4), numpy.float32)
indices = numpy.empty((index_count, 2), numpy.int32) indices = numpy.empty((index_count, 2), numpy.int32)
extruders = numpy.empty((vertex_count), numpy.int32) # Only usable for newer OpenGL versions extruders = numpy.empty((vertex_count), numpy.float32)
line_types = numpy.empty((vertex_count), numpy.float32) line_types = numpy.empty((vertex_count), numpy.float32)
vertex_offset = 0 vertex_offset = 0

View file

@ -47,8 +47,8 @@ class PrinterOutputDevice(QObject, OutputDevice):
self._job_name = "" self._job_name = ""
self._error_text = "" self._error_text = ""
self._accepts_commands = True self._accepts_commands = True
self._preheat_bed_timeout = 900 #Default time-out for pre-heating the bed, in seconds. self._preheat_bed_timeout = 900 # Default time-out for pre-heating the bed, in seconds.
self._preheat_bed_timer = QTimer() #Timer that tracks how long to preheat still. self._preheat_bed_timer = QTimer() # Timer that tracks how long to preheat still.
self._preheat_bed_timer.setSingleShot(True) self._preheat_bed_timer.setSingleShot(True)
self._preheat_bed_timer.timeout.connect(self.cancelPreheatBed) self._preheat_bed_timer.timeout.connect(self.cancelPreheatBed)
@ -232,11 +232,15 @@ class PrinterOutputDevice(QObject, OutputDevice):
# \return The duration of the time-out to pre-heat the bed, formatted. # \return The duration of the time-out to pre-heat the bed, formatted.
@pyqtProperty(str, notify = preheatBedRemainingTimeChanged) @pyqtProperty(str, notify = preheatBedRemainingTimeChanged)
def preheatBedRemainingTime(self): def preheatBedRemainingTime(self):
if not self._preheat_bed_timer.isActive():
return ""
period = self._preheat_bed_timer.remainingTime() period = self._preheat_bed_timer.remainingTime()
if period <= 0: if period <= 0:
return "" return ""
minutes, period = divmod(period, 60000) #60000 milliseconds in a minute. minutes, period = divmod(period, 60000) #60000 milliseconds in a minute.
seconds, _ = divmod(period, 1000) #1000 milliseconds in a second. seconds, _ = divmod(period, 1000) #1000 milliseconds in a second.
if minutes <= 0 and seconds <= 0:
return ""
return "%d:%02d" % (minutes, seconds) return "%d:%02d" % (minutes, seconds)
## Time the print has been printing. ## Time the print has been printing.

View file

@ -3,15 +3,15 @@
import os.path import os.path
import urllib import urllib
from typing import Dict, Union
from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal, QUrl, QVariant from PyQt5.QtCore import QObject, QUrl, QVariant
from UM.FlameProfiler import pyqtSlot from UM.FlameProfiler import pyqtSlot
from PyQt5.QtWidgets import QMessageBox from PyQt5.QtWidgets import QMessageBox
from UM.PluginRegistry import PluginRegistry from UM.PluginRegistry import PluginRegistry
from UM.Platform import Platform
from UM.SaveFile import SaveFile from UM.SaveFile import SaveFile
from UM.Platform import Platform
from UM.MimeTypeDatabase import MimeTypeDatabase from UM.MimeTypeDatabase import MimeTypeDatabase
from UM.Logger import Logger from UM.Logger import Logger
@ -307,18 +307,20 @@ class ContainerManager(QObject):
# #
# \param container_id The ID of the container to export # \param container_id The ID of the container to export
# \param file_type The type of file to save as. Should be in the form of "description (*.extension, *.ext)" # \param file_type The type of file to save as. Should be in the form of "description (*.extension, *.ext)"
# \param file_url The URL where to save the file. # \param file_url_or_string The URL where to save the file.
# #
# \return A dictionary containing a key "status" with a status code and a key "message" with a message # \return A dictionary containing a key "status" with a status code and a key "message" with a message
# explaining the status. # explaining the status.
# The status code can be one of "error", "cancelled", "success" # The status code can be one of "error", "cancelled", "success"
@pyqtSlot(str, str, QUrl, result = "QVariantMap") @pyqtSlot(str, str, QUrl, result = "QVariantMap")
def exportContainer(self, container_id, file_type, file_url): def exportContainer(self, container_id: str, file_type: str, file_url_or_string: Union[QUrl, str]) -> Dict[str, str]:
if not container_id or not file_type or not file_url: if not container_id or not file_type or not file_url_or_string:
return { "status": "error", "message": "Invalid arguments"} return { "status": "error", "message": "Invalid arguments"}
if isinstance(file_url, QUrl): if isinstance(file_url_or_string, QUrl):
file_url = file_url.toLocalFile() file_url = file_url_or_string.toLocalFile()
else:
file_url = file_url_or_string
if not file_url: if not file_url:
return { "status": "error", "message": "Invalid path"} return { "status": "error", "message": "Invalid path"}
@ -373,12 +375,14 @@ class ContainerManager(QObject):
# \return \type{Dict} dict with a 'status' key containing the string 'success' or 'error', and a 'message' key # \return \type{Dict} dict with a 'status' key containing the string 'success' or 'error', and a 'message' key
# containing a message for the user # containing a message for the user
@pyqtSlot(QUrl, result = "QVariantMap") @pyqtSlot(QUrl, result = "QVariantMap")
def importContainer(self, file_url): def importContainer(self, file_url_or_string: Union[QUrl, str]) -> Dict[str, str]:
if not file_url: if not file_url_or_string:
return { "status": "error", "message": "Invalid path"} return { "status": "error", "message": "Invalid path"}
if isinstance(file_url, QUrl): if isinstance(file_url_or_string, QUrl):
file_url = file_url.toLocalFile() file_url = file_url_or_string.toLocalFile()
else:
file_url = file_url_or_string
if not file_url or not os.path.exists(file_url): if not file_url or not os.path.exists(file_url):
return { "status": "error", "message": "Invalid path" } return { "status": "error", "message": "Invalid path" }
@ -438,7 +442,7 @@ class ContainerManager(QObject):
## Clear the top-most (user) containers of the active stacks. ## Clear the top-most (user) containers of the active stacks.
@pyqtSlot() @pyqtSlot()
def clearUserContainers(self): def clearUserContainers(self) -> None:
self._machine_manager.blurSettings.emit() self._machine_manager.blurSettings.emit()
send_emits_containers = [] send_emits_containers = []
@ -668,7 +672,7 @@ class ContainerManager(QObject):
return new_change_instances return new_change_instances
@pyqtSlot(str, result = str) @pyqtSlot(str, result = str)
def duplicateMaterial(self, material_id): def duplicateMaterial(self, material_id: str) -> str:
containers = self._container_registry.findInstanceContainers(id=material_id) containers = self._container_registry.findInstanceContainers(id=material_id)
if not containers: if not containers:
Logger.log("d", "Unable to duplicate the material with id %s, because it doesn't exist.", material_id) Logger.log("d", "Unable to duplicate the material with id %s, because it doesn't exist.", material_id)
@ -692,7 +696,7 @@ class ContainerManager(QObject):
## Get the singleton instance for this class. ## Get the singleton instance for this class.
@classmethod @classmethod
def getInstance(cls): def getInstance(cls) -> "ContainerManager":
# Note: Explicit use of class name to prevent issues with inheritance. # Note: Explicit use of class name to prevent issues with inheritance.
if ContainerManager.__instance is None: if ContainerManager.__instance is None:
ContainerManager.__instance = cls() ContainerManager.__instance = cls()
@ -717,7 +721,7 @@ class ContainerManager(QObject):
if clear_settings: if clear_settings:
merge.clear() merge.clear()
def _updateContainerNameFilters(self): def _updateContainerNameFilters(self) -> None:
self._container_name_filters = {} self._container_name_filters = {}
for plugin_id, container_type in self._container_registry.getContainerTypes(): for plugin_id, container_type in self._container_registry.getContainerTypes():
# Ignore default container types since those are not plugins # Ignore default container types since those are not plugins
@ -852,10 +856,10 @@ class ContainerManager(QObject):
return self._container_registry.importProfile(path) return self._container_registry.importProfile(path)
@pyqtSlot("QVariantList", QUrl, str) @pyqtSlot("QVariantList", QUrl, str)
def exportProfile(self, instance_id, file_url, file_type): def exportProfile(self, instance_id: str, file_url: QUrl, file_type: str) -> None:
if not file_url.isValid(): if not file_url.isValid():
return return
path = file_url.toLocalFile() path = file_url.toLocalFile()
if not path: if not path:
return return
self._container_registry.exportProfile(instance_id, path, file_type) self._container_registry.exportProfile(instance_id, path, file_type)

View file

@ -939,48 +939,7 @@ class MachineManager(QObject):
container.nameChanged.connect(self._onQualityNameChanged) container.nameChanged.connect(self._onQualityNameChanged)
def _askUserToKeepOrClearCurrentSettings(self): def _askUserToKeepOrClearCurrentSettings(self):
# Ask the user if the user profile should be cleared or not (discarding the current settings) Application.getInstance().discardOrKeepProfileChanges()
# In Simple Mode we assume the user always wants to keep the (limited) current settings
details_text = catalog.i18nc("@label", "You made changes to the following setting(s)/override(s):")
# user changes in global stack
details_list = [setting.definition.label for setting in self._global_container_stack.getTop().findInstances(**{})]
# user changes in extruder stacks
stacks = list(ExtruderManager.getInstance().getMachineExtruders(self._global_container_stack.getId()))
for stack in stacks:
details_list.extend([
"%s (%s)" % (setting.definition.label, stack.getName())
for setting in stack.getTop().findInstances(**{})])
# Format to output string
details = "\n ".join([details_text, ] + details_list)
num_changed_settings = len(details_list)
Application.getInstance().messageBox(
catalog.i18nc("@window:title", "Switched profiles"),
catalog.i18nc(
"@label",
"Do you want to transfer your %d changed setting(s)/override(s) to this profile?") % num_changed_settings,
catalog.i18nc(
"@label",
"If you transfer your settings they will override settings in the profile. If you don't transfer these settings, they will be lost."),
details,
buttons=QMessageBox.Yes + QMessageBox.No,
icon=QMessageBox.Question,
callback=self._keepUserSettingsDialogCallback)
def _keepUserSettingsDialogCallback(self, button):
if button == QMessageBox.Yes:
# Yes, keep the settings in the user profile with this profile
pass
elif button == QMessageBox.No:
# No, discard the settings in the user profile
global_stack = Application.getInstance().getGlobalContainerStack()
for extruder in ExtruderManager.getInstance().getMachineExtruders(global_stack.getId()):
extruder.getTop().clear()
global_stack.getTop().clear()
@pyqtProperty(str, notify = activeVariantChanged) @pyqtProperty(str, notify = activeVariantChanged)
def activeVariantName(self): def activeVariantName(self):

View file

@ -6,7 +6,7 @@ from PyQt5.QtGui import QValidator
import os #For statvfs. import os #For statvfs.
import urllib #To escape machine names for how they're saved to file. import urllib #To escape machine names for how they're saved to file.
import UM.Resources from UM.Resources import Resources
from UM.Settings.ContainerRegistry import ContainerRegistry from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.Settings.InstanceContainer import InstanceContainer from UM.Settings.InstanceContainer import InstanceContainer
@ -19,7 +19,7 @@ class MachineNameValidator(QObject):
#Compute the validation regex for printer names. This is limited by the maximum file name length. #Compute the validation regex for printer names. This is limited by the maximum file name length.
try: try:
filename_max_length = os.statvfs(UM.Resources.getDataStoragePath()).f_namemax filename_max_length = os.statvfs(Resources.getDataStoragePath()).f_namemax
except AttributeError: #Doesn't support statvfs. Probably because it's not a Unix system. except AttributeError: #Doesn't support statvfs. Probably because it's not a Unix system.
filename_max_length = 255 #Assume it's Windows on NTFS. filename_max_length = 255 #Assume it's Windows on NTFS.
machine_name_max_length = filename_max_length - len("_current_settings.") - len(ContainerRegistry.getMimeTypeForContainer(InstanceContainer).preferredSuffix) machine_name_max_length = filename_max_length - len("_current_settings.") - len(ContainerRegistry.getMimeTypeForContainer(InstanceContainer).preferredSuffix)
@ -41,7 +41,7 @@ class MachineNameValidator(QObject):
def validate(self, name, position): def validate(self, name, position):
#Check for file name length of the current settings container (which is the longest file we're saving with the name). #Check for file name length of the current settings container (which is the longest file we're saving with the name).
try: try:
filename_max_length = os.statvfs(UM.Resources.getDataStoragePath()).f_namemax filename_max_length = os.statvfs(Resources.getDataStoragePath()).f_namemax
except AttributeError: #Doesn't support statvfs. Probably because it's not a Unix system. except AttributeError: #Doesn't support statvfs. Probably because it's not a Unix system.
filename_max_length = 255 #Assume it's Windows on NTFS. filename_max_length = 255 #Assume it's Windows on NTFS.
escaped_name = urllib.parse.quote_plus(name) escaped_name = urllib.parse.quote_plus(name)

View file

@ -8,7 +8,7 @@ from UM.Signal import Signal, signalemitter
from UM.Settings.ContainerStack import ContainerStack from UM.Settings.ContainerStack import ContainerStack
from UM.Settings.InstanceContainer import InstanceContainer from UM.Settings.InstanceContainer import InstanceContainer
from UM.Settings.ContainerRegistry import ContainerRegistry from UM.Settings.ContainerRegistry import ContainerRegistry
import UM.Logger from UM.Logger import Logger
from UM.Application import Application from UM.Application import Application
@ -99,7 +99,7 @@ class SettingOverrideDecorator(SceneNodeDecorator):
Application.getInstance().getBackend().needsSlicing() Application.getInstance().getBackend().needsSlicing()
Application.getInstance().getBackend().tickle() Application.getInstance().getBackend().tickle()
else: else:
UM.Logger.log("e", "Extruder stack %s below per-object settings does not exist.", self._extruder_stack) Logger.log("e", "Extruder stack %s below per-object settings does not exist.", self._extruder_stack)
else: else:
self._stack.setNextStack(Application.getInstance().getGlobalContainerStack()) self._stack.setNextStack(Application.getInstance().getGlobalContainerStack())

View file

@ -0,0 +1,115 @@
from UM.Qt.ListModel import ListModel
from PyQt5.QtCore import pyqtSlot, Qt
from UM.Application import Application
from cura.Settings.ExtruderManager import ExtruderManager
from UM.Settings.ContainerRegistry import ContainerRegistry
from UM.i18n import i18nCatalog
from UM.Settings.SettingFunction import SettingFunction
import os
class UserChangesModel(ListModel):
KeyRole = Qt.UserRole + 1
LabelRole = Qt.UserRole + 2
ExtruderRole = Qt.UserRole +3
OriginalValueRole = Qt.UserRole + 4
UserValueRole = Qt.UserRole + 6
CategoryRole = Qt.UserRole + 7
def __init__(self, parent = None):
super().__init__(parent = parent)
self.addRoleName(self.KeyRole, "key")
self.addRoleName(self.LabelRole, "label")
self.addRoleName(self.ExtruderRole, "extruder")
self.addRoleName(self.OriginalValueRole, "original_value")
self.addRoleName(self.UserValueRole, "user_value")
self.addRoleName(self.CategoryRole, "category")
self._i18n_catalog = None
self._update()
@pyqtSlot()
def forceUpdate(self):
self._update()
def _update(self):
items = []
global_stack = Application.getInstance().getGlobalContainerStack()
if not global_stack:
return
stacks = ExtruderManager.getInstance().getActiveGlobalAndExtruderStacks()
# Check if the definition container has a translation file and ensure it's loaded.
definition = global_stack.getBottom()
definition_suffix = ContainerRegistry.getMimeTypeForContainer(type(definition)).preferredSuffix
catalog = i18nCatalog(os.path.basename(definition.getId() + "." + definition_suffix))
if catalog.hasTranslationLoaded():
self._i18n_catalog = catalog
for file_name in definition.getInheritedFiles():
catalog = i18nCatalog(os.path.basename(file_name))
if catalog.hasTranslationLoaded():
self._i18n_catalog = catalog
for stack in stacks:
# Make a list of all containers in the stack.
containers = []
latest_stack = stack
while latest_stack:
containers.extend(latest_stack.getContainers())
latest_stack = latest_stack.getNextStack()
# Drop the user container.
user_changes = containers.pop(0)
for setting_key in user_changes.getAllKeys():
original_value = None
# Find the category of the instance by moving up until we find a category.
category = user_changes.getInstance(setting_key).definition
while category.type != "category":
category = category.parent
# Handle translation (and fallback if we weren't able to find any translation files.
if self._i18n_catalog:
category_label = self._i18n_catalog.i18nc(category.key + " label", category.label)
else:
category_label = category.label
if self._i18n_catalog:
label = self._i18n_catalog.i18nc(setting_key + " label", stack.getProperty(setting_key, "label"))
else:
label = stack.getProperty(setting_key, "label")
for container in containers:
if stack == global_stack:
resolve = global_stack.getProperty(setting_key, "resolve")
if resolve is not None:
original_value = resolve
break
original_value = container.getProperty(setting_key, "value")
# If a value is a function, ensure it's called with the stack it's in.
if isinstance(original_value, SettingFunction):
original_value = original_value(stack)
if original_value is not None:
break
item_to_add = {"key": setting_key,
"label": label,
"user_value": str(user_changes.getProperty(setting_key, "value")),
"original_value": str(original_value),
"extruder": "",
"category": category_label}
if stack != global_stack:
item_to_add["extruder"] = stack.getName()
items.append(item_to_add)
self.setItems(items)

View file

@ -17,6 +17,12 @@ if Platform.isLinux(): # Needed for platform.linux_distribution, which is not av
libGL = find_library("GL") libGL = find_library("GL")
ctypes.CDLL(libGL, ctypes.RTLD_GLOBAL) ctypes.CDLL(libGL, ctypes.RTLD_GLOBAL)
# When frozen, i.e. installer version, don't let PYTHONPATH mess up the search path for DLLs.
if Platform.isWindows() and hasattr(sys, "frozen"):
try:
del os.environ["PYTHONPATH"]
except KeyError: pass
#WORKAROUND: GITHUB-704 GITHUB-708 #WORKAROUND: GITHUB-704 GITHUB-708
# It looks like setuptools creates a .pth file in # It looks like setuptools creates a .pth file in
# the default /usr/lib which causes the default site-packages # the default /usr/lib which causes the default site-packages

View file

@ -18,6 +18,10 @@ from cura.QualityManager import QualityManager
from UM.Scene.SceneNode import SceneNode from UM.Scene.SceneNode import SceneNode
MYPY = False MYPY = False
import Savitar
import numpy
try: try:
if not MYPY: if not MYPY:
import xml.etree.cElementTree as ET import xml.etree.cElementTree as ET
@ -38,98 +42,10 @@ class ThreeMFReader(MeshReader):
self._base_name = "" self._base_name = ""
self._unit = None self._unit = None
def _createNodeFromObject(self, object, name = ""):
node = SceneNode()
node.setName(name)
mesh_builder = MeshBuilder()
vertex_list = []
components = object.find(".//3mf:components", self._namespaces)
if components:
for component in components:
id = component.get("objectid")
new_object = self._root.find("./3mf:resources/3mf:object[@id='{0}']".format(id), self._namespaces)
new_node = self._createNodeFromObject(new_object, self._base_name + "_" + str(id))
node.addChild(new_node)
transform = component.get("transform")
if transform is not None:
new_node.setTransformation(self._createMatrixFromTransformationString(transform))
# for vertex in entry.mesh.vertices.vertex:
for vertex in object.findall(".//3mf:vertex", self._namespaces):
vertex_list.append([vertex.get("x"), vertex.get("y"), vertex.get("z")])
Job.yieldThread()
xml_settings = list(object.findall(".//cura:setting", self._namespaces))
# Add the setting override decorator, so we can add settings to this node.
if xml_settings:
node.addDecorator(SettingOverrideDecorator())
global_container_stack = Application.getInstance().getGlobalContainerStack()
# Ensure the correct next container for the SettingOverride decorator is set.
if global_container_stack:
multi_extrusion = global_container_stack.getProperty("machine_extruder_count", "value") > 1
# Ensure that all extruder data is reset
if not multi_extrusion:
default_stack_id = global_container_stack.getId()
else:
default_stack = ExtruderManager.getInstance().getExtruderStack(0)
if default_stack:
default_stack_id = default_stack.getId()
else:
default_stack_id = global_container_stack.getId()
node.callDecoration("setActiveExtruder", default_stack_id)
# Get the definition & set it
definition = QualityManager.getInstance().getParentMachineDefinition(global_container_stack.getBottom())
node.callDecoration("getStack").getTop().setDefinition(definition)
setting_container = node.callDecoration("getStack").getTop()
for setting in xml_settings:
setting_key = setting.get("key")
setting_value = setting.text
# Extruder_nr is a special case.
if setting_key == "extruder_nr":
extruder_stack = ExtruderManager.getInstance().getExtruderStack(int(setting_value))
if extruder_stack:
node.callDecoration("setActiveExtruder", extruder_stack.getId())
else:
Logger.log("w", "Unable to find extruder in position %s", setting_value)
continue
setting_container.setProperty(setting_key,"value", setting_value)
if len(node.getChildren()) > 0:
group_decorator = GroupDecorator()
node.addDecorator(group_decorator)
triangles = object.findall(".//3mf:triangle", self._namespaces)
mesh_builder.reserveFaceCount(len(triangles))
for triangle in triangles:
v1 = int(triangle.get("v1"))
v2 = int(triangle.get("v2"))
v3 = int(triangle.get("v3"))
mesh_builder.addFaceByPoints(vertex_list[v1][0], vertex_list[v1][1], vertex_list[v1][2],
vertex_list[v2][0], vertex_list[v2][1], vertex_list[v2][2],
vertex_list[v3][0], vertex_list[v3][1], vertex_list[v3][2])
Job.yieldThread()
# TODO: We currently do not check for normals and simply recalculate them.
mesh_builder.calculateNormals(fast=True)
mesh_builder.setFileName(name)
mesh_data = mesh_builder.build()
if len(mesh_data.getVertices()):
node.setMeshData(mesh_data)
node.setSelectable(True)
return node
def _createMatrixFromTransformationString(self, transformation): def _createMatrixFromTransformationString(self, transformation):
if transformation == "":
return Matrix()
splitted_transformation = transformation.split() splitted_transformation = transformation.split()
## Transformation is saved as: ## Transformation is saved as:
## M00 M01 M02 0.0 ## M00 M01 M02 0.0
@ -156,51 +72,96 @@ class ThreeMFReader(MeshReader):
return temp_mat return temp_mat
## Convenience function that converts a SceneNode object (as obtained from libSavitar) to a Uranium scenenode.
# \returns Uranium Scenen node.
def _convertSavitarNodeToUMNode(self, savitar_node):
um_node = SceneNode()
transformation = self._createMatrixFromTransformationString(savitar_node.getTransformation())
um_node.setTransformation(transformation)
mesh_builder = MeshBuilder()
data = numpy.fromstring(savitar_node.getMeshData().getFlatVerticesAsBytes(), dtype=numpy.float32)
vertices = numpy.resize(data, (int(data.size / 3), 3))
mesh_builder.setVertices(vertices)
mesh_builder.calculateNormals(fast=True)
mesh_data = mesh_builder.build()
if len(mesh_data.getVertices()):
um_node.setMeshData(mesh_data)
for child in savitar_node.getChildren():
um_node.addChild(self._convertSavitarNodeToUMNode(child))
settings = savitar_node.getSettings()
# Add the setting override decorator, so we can add settings to this node.
if settings:
um_node.addDecorator(SettingOverrideDecorator())
global_container_stack = Application.getInstance().getGlobalContainerStack()
# Ensure the correct next container for the SettingOverride decorator is set.
if global_container_stack:
multi_extrusion = global_container_stack.getProperty("machine_extruder_count", "value") > 1
# Ensure that all extruder data is reset
if not multi_extrusion:
default_stack_id = global_container_stack.getId()
else:
default_stack = ExtruderManager.getInstance().getExtruderStack(0)
if default_stack:
default_stack_id = default_stack.getId()
else:
default_stack_id = global_container_stack.getId()
um_node.callDecoration("setActiveExtruder", default_stack_id)
# Get the definition & set it
definition = QualityManager.getInstance().getParentMachineDefinition(global_container_stack.getBottom())
um_node.callDecoration("getStack").getTop().setDefinition(definition)
setting_container = um_node.callDecoration("getStack").getTop()
for key in settings:
setting_value = settings[key]
# Extruder_nr is a special case.
if key == "extruder_nr":
extruder_stack = ExtruderManager.getInstance().getExtruderStack(int(setting_value))
if extruder_stack:
um_node.callDecoration("setActiveExtruder", extruder_stack.getId())
else:
Logger.log("w", "Unable to find extruder in position %s", setting_value)
continue
setting_container.setProperty(key,"value", setting_value)
if len(um_node.getChildren()) > 0:
group_decorator = GroupDecorator()
um_node.addDecorator(group_decorator)
um_node.setSelectable(True)
return um_node
def read(self, file_name): def read(self, file_name):
result = [] result = []
# The base object of 3mf is a zipped archive. # The base object of 3mf is a zipped archive.
archive = zipfile.ZipFile(file_name, "r")
self._base_name = os.path.basename(file_name)
try: try:
self._root = ET.parse(archive.open("3D/3dmodel.model")) archive = zipfile.ZipFile(file_name, "r")
self._unit = self._root.getroot().get("unit") self._base_name = os.path.basename(file_name)
parser = Savitar.ThreeMFParser()
build_items = self._root.findall("./3mf:build/3mf:item", self._namespaces) scene_3mf = parser.parse(archive.open("3D/3dmodel.model").read())
self._unit = scene_3mf.getUnit()
for build_item in build_items: for node in scene_3mf.getSceneNodes():
id = build_item.get("objectid") um_node = self._convertSavitarNodeToUMNode(node)
object = self._root.find("./3mf:resources/3mf:object[@id='{0}']".format(id), self._namespaces)
if "type" in object.attrib:
if object.attrib["type"] == "support" or object.attrib["type"] == "other":
# Ignore support objects, as cura does not support these.
# We can't guarantee that they wont be made solid.
# We also ignore "other", as I have no idea what to do with them.
Logger.log("w", "3MF file contained an object of type %s which is not supported by Cura", object.attrib["type"])
continue
elif object.attrib["type"] == "solidsupport" or object.attrib["type"] == "model":
pass # Load these as normal
else:
# We should technically fail at this point because it's an invalid 3MF, but try to continue anyway.
Logger.log("e", "3MF file contained an object of type %s which is not supported by the 3mf spec",
object.attrib["type"])
continue
build_item_node = self._createNodeFromObject(object, self._base_name + "_" + str(id))
# compensate for original center position, if object(s) is/are not around its zero position # compensate for original center position, if object(s) is/are not around its zero position
transform_matrix = Matrix() transform_matrix = Matrix()
mesh_data = build_item_node.getMeshData() mesh_data = um_node.getMeshData()
if mesh_data is not None: if mesh_data is not None:
extents = mesh_data.getExtents() extents = mesh_data.getExtents()
center_vector = Vector(extents.center.x, extents.center.y, extents.center.z) center_vector = Vector(extents.center.x, extents.center.y, extents.center.z)
transform_matrix.setByTranslation(center_vector) transform_matrix.setByTranslation(center_vector)
transform_matrix.multiply(um_node.getLocalTransformation())
# offset with transform from 3mf um_node.setTransformation(transform_matrix)
transform = build_item.get("transform")
if transform is not None:
transform_matrix.multiply(self._createMatrixFromTransformationString(transform))
build_item_node.setTransformation(transform_matrix)
global_container_stack = Application.getInstance().getGlobalContainerStack() global_container_stack = Application.getInstance().getGlobalContainerStack()
@ -215,9 +176,9 @@ class ThreeMFReader(MeshReader):
# Second step: 3MF defines the left corner of the machine as center, whereas cura uses the center of the # Second step: 3MF defines the left corner of the machine as center, whereas cura uses the center of the
# build volume. # build volume.
if global_container_stack: if global_container_stack:
translation_vector = Vector(x = -global_container_stack.getProperty("machine_width", "value") / 2, translation_vector = Vector(x=-global_container_stack.getProperty("machine_width", "value") / 2,
y = -global_container_stack.getProperty("machine_depth", "value") / 2, y=-global_container_stack.getProperty("machine_depth", "value") / 2,
z = 0) z=0)
translation_matrix = Matrix() translation_matrix = Matrix()
translation_matrix.setByTranslation(translation_vector) translation_matrix.setByTranslation(translation_vector)
transformation_matrix.multiply(translation_matrix) transformation_matrix.multiply(translation_matrix)
@ -228,12 +189,13 @@ class ThreeMFReader(MeshReader):
transformation_matrix.multiply(scale_matrix) transformation_matrix.multiply(scale_matrix)
# Pre multiply the transformation with the loaded transformation, so the data is handled correctly. # Pre multiply the transformation with the loaded transformation, so the data is handled correctly.
build_item_node.setTransformation(build_item_node.getLocalTransformation().preMultiply(transformation_matrix)) um_node.setTransformation(um_node.getLocalTransformation().preMultiply(transformation_matrix))
result.append(build_item_node) result.append(um_node)
except Exception as e: except Exception:
Logger.log("e", "An exception occurred in 3mf reader: %s", e) Logger.logException("e", "An exception occurred in 3mf reader.")
return []
return result return result

View file

@ -476,7 +476,9 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
return nodes return nodes
def _stripFileToId(self, file): def _stripFileToId(self, file):
return file.replace("Cura/", "").split(".")[0] mime_type = MimeTypeDatabase.getMimeTypeForFile(file)
file = mime_type.stripExtension(file)
return file.replace("Cura/", "")
def _getXmlProfileClass(self): def _getXmlProfileClass(self):
return self._container_registry.getContainerForMimeType(MimeTypeDatabase.getMimeType("application/x-ultimaker-material-profile")) return self._container_registry.getContainerForMimeType(MimeTypeDatabase.getMimeType("application/x-ultimaker-material-profile"))

View file

@ -6,6 +6,11 @@ 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
import UM.Scene.SceneNode
import Savitar
import numpy
MYPY = False MYPY = False
try: try:
@ -35,18 +40,18 @@ class ThreeMFWriter(MeshWriter):
def _convertMatrixToString(self, matrix): def _convertMatrixToString(self, matrix):
result = "" result = ""
result += str(matrix._data[0,0]) + " " result += str(matrix._data[0, 0]) + " "
result += str(matrix._data[1,0]) + " " result += str(matrix._data[1, 0]) + " "
result += str(matrix._data[2,0]) + " " result += str(matrix._data[2, 0]) + " "
result += str(matrix._data[0,1]) + " " result += str(matrix._data[0, 1]) + " "
result += str(matrix._data[1,1]) + " " result += str(matrix._data[1, 1]) + " "
result += str(matrix._data[2,1]) + " " result += str(matrix._data[2, 1]) + " "
result += str(matrix._data[0,2]) + " " result += str(matrix._data[0, 2]) + " "
result += str(matrix._data[1,2]) + " " result += str(matrix._data[1, 2]) + " "
result += str(matrix._data[2,2]) + " " result += str(matrix._data[2, 2]) + " "
result += str(matrix._data[0,3]) + " " result += str(matrix._data[0, 3]) + " "
result += str(matrix._data[1,3]) + " " result += str(matrix._data[1, 3]) + " "
result += str(matrix._data[2,3]) result += str(matrix._data[2, 3])
return result return result
## Should we store the archive ## Should we store the archive
@ -55,6 +60,48 @@ class ThreeMFWriter(MeshWriter):
def setStoreArchive(self, store_archive): def setStoreArchive(self, store_archive):
self._store_archive = store_archive self._store_archive = store_archive
## Convenience function that converts an Uranium SceneNode object to a SavitarSceneNode
# \returns Uranium Scenen node.
def _convertUMNodeToSavitarNode(self, um_node, transformation = Matrix()):
if type(um_node) is not UM.Scene.SceneNode.SceneNode:
return None
savitar_node = Savitar.SceneNode()
node_matrix = um_node.getLocalTransformation()
matrix_string = self._convertMatrixToString(node_matrix.preMultiply(transformation))
savitar_node.setTransformation(matrix_string)
mesh_data = um_node.getMeshData()
if mesh_data is not None:
savitar_node.getMeshData().setVerticesFromBytes(mesh_data.getVerticesAsByteArray())
indices_array = mesh_data.getIndicesAsByteArray()
if indices_array is not None:
savitar_node.getMeshData().setFacesFromBytes(indices_array)
else:
savitar_node.getMeshData().setFacesFromBytes(numpy.arange(mesh_data.getVertices().size / 3, dtype=numpy.int32).tostring())
# Handle per object settings (if any)
stack = um_node.callDecoration("getStack")
if stack is not None:
changed_setting_keys = set(stack.getTop().getAllKeys())
# Ensure that we save the extruder used for this object.
if stack.getProperty("machine_extruder_count", "value") > 1:
changed_setting_keys.add("extruder_nr")
# Get values for all changed settings & save them.
for key in changed_setting_keys:
savitar_node.setSetting(key, str(stack.getProperty(key, "value")))
for child_node in um_node.getChildren():
savitar_child_node = self._convertUMNodeToSavitarNode(child_node)
if savitar_child_node is not None:
savitar_node.addChild(savitar_child_node)
return savitar_node
def getArchive(self): def getArchive(self):
return self._archive return self._archive
@ -79,98 +126,7 @@ class ThreeMFWriter(MeshWriter):
relations_element = ET.Element("Relationships", xmlns = self._namespaces["relationships"]) relations_element = ET.Element("Relationships", xmlns = self._namespaces["relationships"])
model_relation_element = ET.SubElement(relations_element, "Relationship", Target = "/3D/3dmodel.model", Id = "rel0", Type = "http://schemas.microsoft.com/3dmanufacturing/2013/01/3dmodel") model_relation_element = ET.SubElement(relations_element, "Relationship", Target = "/3D/3dmodel.model", Id = "rel0", Type = "http://schemas.microsoft.com/3dmanufacturing/2013/01/3dmodel")
model = ET.Element("model", unit = "millimeter", xmlns = self._namespaces["3mf"]) savitar_scene = Savitar.Scene()
model.set("xmlns:cura", self._namespaces["cura"])
# Add the version of Cura this was created with. Since there is no "version" or similar metadata name we need
# to prefix it with the cura namespace, as specified by the 3MF specification.
version_metadata = ET.SubElement(model, "metadata", name = "cura:version")
version_metadata.text = Application.getInstance().getVersion()
resources = ET.SubElement(model, "resources")
build = ET.SubElement(model, "build")
added_nodes = []
index = 0 # Ensure index always exists (even if there are no nodes to write)
# Write all nodes with meshData to the file as objects inside the resource tag
for index, n in enumerate(MeshWriter._meshNodes(nodes)):
added_nodes.append(n) # Save the nodes that have mesh data
object = ET.SubElement(resources, "object", id = str(index+1), type = "model")
mesh = ET.SubElement(object, "mesh")
mesh_data = n.getMeshData()
vertices = ET.SubElement(mesh, "vertices")
verts = mesh_data.getVertices()
if verts is None:
Logger.log("d", "3mf writer can't write nodes without mesh data. Skipping this node.")
continue # No mesh data, nothing to do.
if mesh_data.hasIndices():
for face in mesh_data.getIndices():
v1 = verts[face[0]]
v2 = verts[face[1]]
v3 = verts[face[2]]
xml_vertex1 = ET.SubElement(vertices, "vertex", x = str(v1[0]), y = str(v1[1]), z = str(v1[2]))
xml_vertex2 = ET.SubElement(vertices, "vertex", x = str(v2[0]), y = str(v2[1]), z = str(v2[2]))
xml_vertex3 = ET.SubElement(vertices, "vertex", x = str(v3[0]), y = str(v3[1]), z = str(v3[2]))
triangles = ET.SubElement(mesh, "triangles")
for face in mesh_data.getIndices():
triangle = ET.SubElement(triangles, "triangle", v1 = str(face[0]) , v2 = str(face[1]), v3 = str(face[2]))
else:
triangles = ET.SubElement(mesh, "triangles")
for idx, vert in enumerate(verts):
xml_vertex = ET.SubElement(vertices, "vertex", x = str(vert[0]), y = str(vert[1]), z = str(vert[2]))
# If we have no faces defined, assume that every three subsequent vertices form a face.
if idx % 3 == 0:
triangle = ET.SubElement(triangles, "triangle", v1 = str(idx), v2 = str(idx + 1), v3 = str(idx + 2))
# Handle per object settings
stack = n.callDecoration("getStack")
if stack is not None:
changed_setting_keys = set(stack.getTop().getAllKeys())
# Ensure that we save the extruder used for this object.
if stack.getProperty("machine_extruder_count", "value") > 1:
changed_setting_keys.add("extruder_nr")
settings_xml = ET.SubElement(object, "settings", xmlns=self._namespaces["cura"])
# Get values for all changed settings & save them.
for key in changed_setting_keys:
setting_xml = ET.SubElement(settings_xml, "setting", key = key)
setting_xml.text = str(stack.getProperty(key, "value"))
# Add one to the index as we haven't incremented the last iteration.
index += 1
nodes_to_add = set()
for node in added_nodes:
# Check the parents of the nodes with mesh_data and ensure that they are also added.
parent_node = node.getParent()
while parent_node is not None:
if parent_node.callDecoration("isGroup"):
nodes_to_add.add(parent_node)
parent_node = parent_node.getParent()
else:
parent_node = None
# Sort all the nodes by depth (so nodes with the highest depth are done first)
sorted_nodes_to_add = sorted(nodes_to_add, key=lambda node: node.getDepth(), reverse = True)
# We have already saved the nodes with mesh data, but now we also want to save nodes required for the scene
for node in sorted_nodes_to_add:
object = ET.SubElement(resources, "object", id=str(index + 1), type="model")
components = ET.SubElement(object, "components")
for child in node.getChildren():
if child in added_nodes:
component = ET.SubElement(components, "component", objectid = str(added_nodes.index(child) + 1), transform = self._convertMatrixToString(child.getLocalTransformation()))
index += 1
added_nodes.append(node)
# Create a transformation Matrix to convert from our worldspace into 3MF.
# First step: flip the y and z axis.
transformation_matrix = Matrix() transformation_matrix = Matrix()
transformation_matrix._data[1, 1] = 0 transformation_matrix._data[1, 1] = 0
transformation_matrix._data[1, 2] = -1 transformation_matrix._data[1, 2] = -1
@ -188,14 +144,23 @@ class ThreeMFWriter(MeshWriter):
translation_matrix.setByTranslation(translation_vector) translation_matrix.setByTranslation(translation_vector)
transformation_matrix.preMultiply(translation_matrix) transformation_matrix.preMultiply(translation_matrix)
# Find out what the final build items are and add them.
for node in added_nodes:
if node.getParent().callDecoration("isGroup") is None:
node_matrix = node.getLocalTransformation()
ET.SubElement(build, "item", objectid = str(added_nodes.index(node) + 1), transform = self._convertMatrixToString(node_matrix.preMultiply(transformation_matrix))) root_node = UM.Application.getInstance().getController().getScene().getRoot()
for node in nodes:
if node == root_node:
for root_child in node.getChildren():
savitar_node = self._convertUMNodeToSavitarNode(root_child, transformation_matrix)
if savitar_node:
savitar_scene.addSceneNode(savitar_node)
else:
savitar_node = self._convertUMNodeToSavitarNode(node, transformation_matrix)
if savitar_node:
savitar_scene.addSceneNode(savitar_node)
archive.writestr(model_file, b'<?xml version="1.0" encoding="UTF-8"?> \n' + ET.tostring(model)) parser = Savitar.ThreeMFParser()
scene_string = parser.sceneToString(savitar_scene)
archive.writestr(model_file, scene_string)
archive.writestr(content_types_file, b'<?xml version="1.0" encoding="UTF-8"?> \n' + ET.tostring(content_types)) archive.writestr(content_types_file, b'<?xml version="1.0" encoding="UTF-8"?> \n' + ET.tostring(content_types))
archive.writestr(relations_file, b'<?xml version="1.0" encoding="UTF-8"?> \n' + ET.tostring(relations_element)) archive.writestr(relations_file, b'<?xml version="1.0" encoding="UTF-8"?> \n' + ET.tostring(relations_element))
except Exception as e: except Exception as e:

39
plugins/CuraEngineBackend/CuraEngineBackend.py Normal file → Executable file
View file

@ -105,6 +105,8 @@ class CuraEngineBackend(QObject, Backend):
self._backend_log_max_lines = 20000 # Maximum number of lines to buffer self._backend_log_max_lines = 20000 # Maximum number of lines to buffer
self._error_message = None # Pop-up message that shows errors. self._error_message = None # Pop-up message that shows errors.
self._last_num_objects = 0 # Count number of objects to see if there is something changed
self._postponed_scene_change_sources = [] # scene change is postponed (by a tool)
self.backendQuit.connect(self._onBackendQuit) self.backendQuit.connect(self._onBackendQuit)
self.backendConnected.connect(self._onBackendConnected) self.backendConnected.connect(self._onBackendConnected)
@ -340,21 +342,32 @@ class CuraEngineBackend(QObject, Backend):
# #
# \param source The scene node that was changed. # \param source The scene node that was changed.
def _onSceneChanged(self, source): def _onSceneChanged(self, source):
if self._tool_active:
return
if type(source) is not SceneNode: if type(source) is not SceneNode:
return return
if source is self._scene.getRoot(): root_scene_nodes_changed = False
return if source == self._scene.getRoot():
num_objects = 0
for node in DepthFirstIterator(self._scene.getRoot()):
# Only count sliceable objects
if node.callDecoration("isSliceable"):
num_objects += 1
if num_objects != self._last_num_objects:
self._last_num_objects = num_objects
root_scene_nodes_changed = True
else:
return
self.determineAutoSlicing() if not source.callDecoration("isGroup") and not root_scene_nodes_changed:
if source.getMeshData() is None:
return
if source.getMeshData().getVertices() is None:
return
if source.getMeshData() is None: if self._tool_active:
return # do it later, each source only has to be done once
if source not in self._postponed_scene_change_sources:
if source.getMeshData().getVertices() is None: self._postponed_scene_change_sources.append(source)
return return
self.needsSlicing() self.needsSlicing()
@ -501,7 +514,11 @@ class CuraEngineBackend(QObject, Backend):
# \param tool The tool that the user was using. # \param tool The tool that the user was using.
def _onToolOperationStopped(self, tool): def _onToolOperationStopped(self, tool):
self._tool_active = False # React on scene change again self._tool_active = False # React on scene change again
self.determineAutoSlicing() self.determineAutoSlicing() # Switch timer on if appropriate
# Process all the postponed scene changes
while self._postponed_scene_change_sources:
source = self._postponed_scene_change_sources.pop(0)
self._onSceneChanged(source)
## Called when the user changes the active view mode. ## Called when the user changes the active view mode.
def _onActiveViewChanged(self): def _onActiveViewChanged(self):

View file

@ -2,7 +2,7 @@
# Cura is released under the terms of the AGPLv3 or higher. # Cura is released under the terms of the AGPLv3 or higher.
import configparser import configparser
from UM import PluginRegistry from UM.PluginRegistry import PluginRegistry
from UM.Logger import Logger from UM.Logger import Logger
from UM.Settings.InstanceContainer import InstanceContainer # The new profile to make. from UM.Settings.InstanceContainer import InstanceContainer # The new profile to make.
from cura.ProfileReader import ProfileReader from cura.ProfileReader import ProfileReader

0
plugins/LayerView/LayerPass.py Normal file → Executable file
View file

0
plugins/LayerView/layers.shader Normal file → Executable file
View file

4
plugins/LayerView/layers3d.shader Normal file → Executable file
View file

@ -16,7 +16,7 @@ vertex41core =
in lowp vec4 a_material_color; in lowp vec4 a_material_color;
in highp vec4 a_normal; in highp vec4 a_normal;
in highp vec2 a_line_dim; // line width and thickness in highp vec2 a_line_dim; // line width and thickness
in highp int a_extruder; // Note: cannot use this in compatibility, int is only available in newer OpenGL. in highp float a_extruder;
in highp float a_line_type; in highp float a_line_type;
out lowp vec4 v_color; out lowp vec4 v_color;
@ -53,7 +53,7 @@ vertex41core =
v_vertex = world_space_vert.xyz; v_vertex = world_space_vert.xyz;
v_normal = (u_normalMatrix * normalize(a_normal)).xyz; v_normal = (u_normalMatrix * normalize(a_normal)).xyz;
v_line_dim = a_line_dim; v_line_dim = a_line_dim;
v_extruder = a_extruder; v_extruder = int(a_extruder);
v_line_type = a_line_type; v_line_type = a_line_type;
v_extruder_opacity = u_extruder_opacity; v_extruder_opacity = u_extruder_opacity;

View file

@ -209,6 +209,8 @@ Item {
{ {
case "int": case "int":
return settingTextField return settingTextField
case "[int]":
return settingTextField
case "float": case "float":
return settingTextField return settingTextField
case "enum": case "enum":

View file

@ -2,7 +2,7 @@
# Cura is released under the terms of the AGPLv3 or higher. # Cura is released under the terms of the AGPLv3 or higher.
from UM.Platform import Platform from UM.Platform import Platform
from UM.Logger import Logger
from UM.i18n import i18nCatalog from UM.i18n import i18nCatalog
catalog = i18nCatalog("cura") catalog = i18nCatalog("cura")

5
plugins/SliceInfoPlugin/SliceInfo.py Normal file → Executable file
View file

@ -90,9 +90,8 @@ class SliceInfo(Extension):
# Listing all files placed on the buildplate # Listing all files placed on the buildplate
modelhashes = [] modelhashes = []
for node in DepthFirstIterator(CuraApplication.getInstance().getController().getScene().getRoot()): for node in DepthFirstIterator(CuraApplication.getInstance().getController().getScene().getRoot()):
if type(node) is not SceneNode or not node.getMeshData(): if node.callDecoration("isSliceable"):
continue modelhashes.append(node.getMeshData().getHash())
modelhashes.append(node.getMeshData().getHash())
# Creating md5sums and formatting them as discussed on JIRA # Creating md5sums and formatting them as discussed on JIRA
modelhash_formatted = ",".join(modelhashes) modelhash_formatted = ",".join(modelhashes)

View file

@ -99,6 +99,7 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
self._material_ids = [""] * self._num_extruders self._material_ids = [""] * self._num_extruders
self._hotend_ids = [""] * self._num_extruders self._hotend_ids = [""] * self._num_extruders
self._target_bed_temperature = 0 self._target_bed_temperature = 0
self._processing_preheat_requests = True
self.setPriority(2) # Make sure the output device gets selected above local file output self.setPriority(2) # Make sure the output device gets selected above local file output
self.setName(key) self.setName(key)
@ -262,6 +263,7 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
Logger.log("i", "Pre-heating bed to %i degrees.", temperature) Logger.log("i", "Pre-heating bed to %i degrees.", temperature)
put_request = QNetworkRequest(url) put_request = QNetworkRequest(url)
put_request.setHeader(QNetworkRequest.ContentTypeHeader, "application/json") put_request.setHeader(QNetworkRequest.ContentTypeHeader, "application/json")
self._processing_preheat_requests = False
self._manager.put(put_request, data.encode()) self._manager.put(put_request, data.encode())
self._preheat_bed_timer.start(self._preheat_bed_timeout * 1000) #Times 1000 because it needs to be provided as milliseconds. self._preheat_bed_timer.start(self._preheat_bed_timeout * 1000) #Times 1000 because it needs to be provided as milliseconds.
self.preheatBedRemainingTimeChanged.emit() self.preheatBedRemainingTimeChanged.emit()
@ -532,6 +534,29 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
self._updateHeadPosition(head_x, head_y, head_z) self._updateHeadPosition(head_x, head_y, head_z)
self._updatePrinterState(self._json_printer_state["status"]) self._updatePrinterState(self._json_printer_state["status"])
if self._processing_preheat_requests:
try:
is_preheating = self._json_printer_state["bed"]["pre_heat"]["active"]
except KeyError: #Old firmware doesn't support that.
pass #Don't update the pre-heat remaining time.
else:
if is_preheating:
try:
remaining_preheat_time = self._json_printer_state["bed"]["pre_heat"]["remaining"]
except KeyError: #Error in firmware. If "active" is supported, "remaining" should also be supported.
pass #Anyway, don't update.
else:
#Only update if time estimate is significantly off (>5000ms).
#Otherwise we get issues with latency causing the timer to count inconsistently.
if abs(self._preheat_bed_timer.remainingTime() - remaining_preheat_time * 1000) > 5000:
self._preheat_bed_timer.setInterval(remaining_preheat_time * 1000)
self._preheat_bed_timer.start()
self.preheatBedRemainingTimeChanged.emit()
else: #Not pre-heating. Must've cancelled.
if self._preheat_bed_timer.isActive():
self._preheat_bed_timer.setInterval(0)
self._preheat_bed_timer.stop()
self.preheatBedRemainingTimeChanged.emit()
def close(self): def close(self):
Logger.log("d", "Closing connection of printer %s with ip %s", self._key, self._address) Logger.log("d", "Closing connection of printer %s with ip %s", self._key, self._address)
@ -1033,6 +1058,8 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
self._progress_message.hide() self._progress_message.hide()
elif reply.operation() == QNetworkAccessManager.PutOperation: elif reply.operation() == QNetworkAccessManager.PutOperation:
if "printer/bed/pre_heat" in reply_url: #Pre-heat command has completed. Re-enable syncing pre-heating.
self._processing_preheat_requests = True
if status_code in [200, 201, 202, 204]: if status_code in [200, 201, 202, 204]:
pass # Request was successful! pass # Request was successful!
else: else:

View file

@ -45,7 +45,7 @@ class UMOUpgradeSelection(MachineAction):
def _createDefinitionChangesContainer(self, global_container_stack): def _createDefinitionChangesContainer(self, global_container_stack):
# Create a definition_changes container to store the settings in and add it to the stack # Create a definition_changes container to store the settings in and add it to the stack
definition_changes_container = UM.Settings.InstanceContainer(global_container_stack.getName() + "_settings") definition_changes_container = UM.Settings.InstanceContainer.InstanceContainer(global_container_stack.getName() + "_settings")
definition = global_container_stack.getBottom() definition = global_container_stack.getBottom()
definition_changes_container.setDefinition(definition) definition_changes_container.setDefinition(definition)
definition_changes_container.addMetaDataEntry("type", "definition_changes") definition_changes_container.addMetaDataEntry("type", "definition_changes")

View file

@ -3,7 +3,7 @@
import UM.VersionUpgrade #To indicate that a file is of incorrect format. import UM.VersionUpgrade #To indicate that a file is of incorrect format.
import UM.VersionUpgradeManager #To schedule more files to be upgraded. import UM.VersionUpgradeManager #To schedule more files to be upgraded.
import UM.Resources #To get the config storage path. from UM.Resources import Resources #To get the config storage path.
import configparser #To read config files. import configparser #To read config files.
import io #To write config files to strings as if they were files. import io #To write config files to strings as if they were files.
@ -107,7 +107,7 @@ class MachineInstance:
user_profile["values"] = {} user_profile["values"] = {}
version_upgrade_manager = UM.VersionUpgradeManager.VersionUpgradeManager.getInstance() version_upgrade_manager = UM.VersionUpgradeManager.VersionUpgradeManager.getInstance()
user_storage = os.path.join(UM.Resources.getDataStoragePath(), next(iter(version_upgrade_manager.getStoragePaths("user")))) user_storage = os.path.join(Resources.getDataStoragePath(), next(iter(version_upgrade_manager.getStoragePaths("user"))))
user_profile_file = os.path.join(user_storage, urllib.parse.quote_plus(self._name) + "_current_settings.inst.cfg") user_profile_file = os.path.join(user_storage, urllib.parse.quote_plus(self._name) + "_current_settings.inst.cfg")
if not os.path.exists(user_storage): if not os.path.exists(user_storage):
os.makedirs(user_storage) os.makedirs(user_storage)

View file

@ -3,6 +3,8 @@
import configparser #To read config files. import configparser #To read config files.
import io #To write config files to strings as if they were files. import io #To write config files to strings as if they were files.
from typing import Dict
from typing import List
import UM.VersionUpgrade import UM.VersionUpgrade
from UM.Logger import Logger from UM.Logger import Logger

View file

@ -9,7 +9,6 @@
"manufacturer": "Cartesio bv", "manufacturer": "Cartesio bv",
"category": "Other", "category": "Other",
"file_formats": "text/x-gcode", "file_formats": "text/x-gcode",
"has_materials": true,
"has_machine_materials": true, "has_machine_materials": true,
"has_variants": true, "has_variants": true,
"variants_name": "Nozzle size", "variants_name": "Nozzle size",
@ -31,12 +30,11 @@
"machine_heated_bed": { "default_value": true }, "machine_heated_bed": { "default_value": true },
"machine_center_is_zero": { "default_value": false }, "machine_center_is_zero": { "default_value": false },
"machine_height": { "default_value": 400 }, "machine_height": { "default_value": 400 },
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
"machine_depth": { "default_value": 270 }, "machine_depth": { "default_value": 270 },
"machine_width": { "default_value": 430 }, "machine_width": { "default_value": 430 },
"machine_name": { "default_value": "Cartesio" }, "machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
"machine_start_gcode": { "machine_start_gcode": {
"default_value": "M92 E162\nG21\nG90\nM42 S255 P13;chamber lights\nM42 S255 P12;fume extraction\nM140 S{material_bed_temperature}\n\nM117 Homing Y ......\nG28 Y\nM117 Homing X ......\nG28 X\nM117 Homing Z ......\nG28 Z F100\nG1 Z10 F600\nG1 X70 Y20 F9000;go to wipe point\n\nM190 S{material_bed_temperature}\nM104 S120 T1\nM109 S{material_print_temperature} T0\nM104 S21 T1\n\nM117 purging nozzle....\n\nT0\nG92 E0;set E\nG1 E10 F100\nG92 E0\nG1 E-{retraction_amount} F600\nG92 E0\n\nM117 wiping nozzle....\n\nG1 X1 Y24 F3000\nG1 X70 F9000\n\nM117 Printing .....\n\nG1 E1 F100\nG92 E-1\n" "default_value": "M92 E159\nG21\nG90\nM42 S255 P13;chamber lights\nM42 S255 P12;fume extraction\nM140 S{material_bed_temperature}\n\nM117 Homing Y ......\nG28 Y\nM117 Homing X ......\nG28 X\nM117 Homing Z ......\nG28 Z F100\nG1 Z10 F600\nG1 X70 Y20 F9000;go to wipe point\n\nM190 S{material_bed_temperature}\nM104 S120 T1\nM109 S{material_print_temperature} T0\nM104 S21 T1\n\nM117 purging nozzle....\n\nT0\nG92 E0;set E\nG1 E10 F100\nG92 E0\nG1 E-{retraction_amount} F600\nG92 E0\n\nM117 wiping nozzle....\n\nG1 X1 Y24 F3000\nG1 X70 F9000\n\nM117 Printing .....\n\nG1 E1 F100\nG92 E-1\n"
}, },
"machine_end_gcode": { "machine_end_gcode": {
"default_value": "; -- END GCODE --\nM106 S255\nM140 S5\nM104 S5 T0\nM104 S5 T1\nG1 X20.0 Y260.0 F6000\nG4 S7\nM84\nG4 S90\nM107\nM42 P12 S0\nM42 P13 S0\nM84\n; -- end of END GCODE --" "default_value": "; -- END GCODE --\nM106 S255\nM140 S5\nM104 S5 T0\nM104 S5 T1\nG1 X20.0 Y260.0 F6000\nG4 S7\nM84\nG4 S90\nM107\nM42 P12 S0\nM42 P13 S0\nM84\n; -- end of END GCODE --"

View file

@ -93,6 +93,7 @@
"description": "Whether to wait until the nozzle temperature is reached at the start.", "description": "Whether to wait until the nozzle temperature is reached at the start.",
"default_value": true, "default_value": true,
"type": "bool", "type": "bool",
"enabled": "machine_nozzle_temp_enabled",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": false, "settable_per_extruder": false,
"settable_per_meshgroup": false "settable_per_meshgroup": false
@ -103,6 +104,7 @@
"description": "Whether to include nozzle temperature commands at the start of the gcode. When the start_gcode already contains nozzle temperature commands Cura frontend will automatically disable this setting.", "description": "Whether to include nozzle temperature commands at the start of the gcode. When the start_gcode already contains nozzle temperature commands Cura frontend will automatically disable this setting.",
"default_value": true, "default_value": true,
"type": "bool", "type": "bool",
"enabled": "machine_nozzle_temp_enabled",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": false, "settable_per_extruder": false,
"settable_per_meshgroup": false "settable_per_meshgroup": false
@ -249,6 +251,17 @@
"settable_per_extruder": true, "settable_per_extruder": true,
"settable_per_meshgroup": false "settable_per_meshgroup": false
}, },
"machine_nozzle_temp_enabled":
{
"label": "Enable Nozzle Temperature Control",
"description": "Whether to control temperature from Cura. Turn this off to control nozzle temperature from outside of Cura.",
"default_value": true,
"value": "machine_gcode_flavor != \"UltiGCode\"",
"type": "bool",
"settable_per_mesh": false,
"settable_per_extruder": true,
"settable_per_meshgroup": false
},
"machine_nozzle_heat_up_speed": "machine_nozzle_heat_up_speed":
{ {
"label": "Heat up speed", "label": "Heat up speed",
@ -256,6 +269,7 @@
"default_value": 2.0, "default_value": 2.0,
"unit": "°C/s", "unit": "°C/s",
"type": "float", "type": "float",
"enabled": "machine_nozzle_temp_enabled",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": true "settable_per_extruder": true
}, },
@ -266,6 +280,7 @@
"default_value": 2.0, "default_value": 2.0,
"unit": "°C/s", "unit": "°C/s",
"type": "float", "type": "float",
"enabled": "machine_nozzle_temp_enabled",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": true "settable_per_extruder": true
}, },
@ -276,6 +291,7 @@
"default_value": 50.0, "default_value": 50.0,
"unit": "s", "unit": "s",
"type": "float", "type": "float",
"enabled": "machine_nozzle_temp_enabled",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": true "settable_per_extruder": true
}, },
@ -908,6 +924,15 @@
"value": "top_bottom_pattern", "value": "top_bottom_pattern",
"settable_per_mesh": true "settable_per_mesh": true
}, },
"skin_angles":
{
"label": "Top/Bottom Line Directions",
"description": "A list of integer line directions to use when the top/bottom layers use the lines or zig zag pattern. Elements from the list are used sequentially as the layers progress and when the end of the list is reached, it starts at the beginning again. The list items are separated by commas and the whole list is contained in square brackets. Default is an empty list which means use the traditional default angles (45 and 135 degrees).",
"type": "[int]",
"default_value": "[ ]",
"enabled": "top_bottom_pattern != 'concentric'",
"settable_per_mesh": true
},
"wall_0_inset": "wall_0_inset":
{ {
"label": "Outer Wall Inset", "label": "Outer Wall Inset",
@ -1089,6 +1114,15 @@
"value": "'lines' if infill_sparse_density > 25 else 'grid'", "value": "'lines' if infill_sparse_density > 25 else 'grid'",
"settable_per_mesh": true "settable_per_mesh": true
}, },
"infill_angles":
{
"label": "Infill Line Directions",
"description": "A list of integer line directions to use. Elements from the list are used sequentially as the layers progress and when the end of the list is reached, it starts at the beginning again. The list items are separated by commas and the whole list is contained in square brackets. Default is an empty list which means use the traditional default angles (45 and 135 degrees for the lines and zig zag patterns and 45 degrees for all other patterns).",
"type": "[int]",
"default_value": "[ ]",
"enabled": "infill_pattern != 'concentric' and infill_pattern != 'concentric_3d' and infill_pattern != 'cubicsubdiv'",
"settable_per_mesh": true
},
"sub_div_rad_mult": "sub_div_rad_mult":
{ {
"label": "Cubic Subdivision Radius", "label": "Cubic Subdivision Radius",
@ -1243,6 +1277,74 @@
"minimum_value": "0", "minimum_value": "0",
"default_value": 0, "default_value": 0,
"settable_per_mesh": true "settable_per_mesh": true
},
"expand_skins_into_infill":
{
"label": "Expand Skins Into Infill",
"description": "Expand skin areas of top and/or bottom skin of flat surfaces. By default, skins stop under the wall lines that surround infill but this can lead to holes appearing when the infill density is low. This setting extends the skins beyond the wall lines so that the infill on the next layer rests on skin.",
"type": "bool",
"default_value": false,
"settable_per_mesh": true,
"children":
{
"expand_upper_skins":
{
"label": "Expand Upper Skins",
"description": "Expand upper skin areas (areas with air above) so that they support infill above.",
"type": "bool",
"default_value": false,
"value": "expand_skins_into_infill",
"settable_per_mesh": true
},
"expand_lower_skins":
{
"label": "Expand Lower Skins",
"description": "Expand lower skin areas (areas with air below) so that they are anchored by the infill layers above and below.",
"type": "bool",
"default_value": false,
"settable_per_mesh": true
}
}
},
"expand_skins_expand_distance":
{
"label": "Skin Expand Distance",
"description": "The distance the skins are expanded into the infill. The default distance is enough to bridge the gap between the infill lines and will stop holes appearing in the skin where it meets the wall when the infill density is low. A smaller distance will often be sufficient.",
"unit": "mm",
"type": "float",
"default_value": 2.8,
"value": "infill_line_distance * 1.4",
"minimum_value": "0",
"enabled": "expand_upper_skins or expand_lower_skins",
"settable_per_mesh": true
},
"min_skin_angle_for_expansion":
{
"label": "Minimum Skin Angle for Expansion",
"description": "Top and or bottom surfaces of your object with an angle larger than this setting, won't have their top/bottom skin expanded. This avoids expanding the narrow skin areas that are created when the model surface has a near vertical slope.",
"unit": "°",
"type": "float",
"minimum_value": "0",
"maximum_value": "90",
"maximum_value_warning": "45",
"default_value": 20,
"enabled": "expand_upper_skins or expand_lower_skins",
"settable_per_mesh": true,
"children":
{
"min_skin_width_for_expansion":
{
"label": "Minimum Skin Width for Expansion",
"description": "Skin areas narrower than this are not expanded. This avoids expanding the narrow skin areas that are created when the model surface has a slope close to the vertical.",
"unit": "mm",
"type": "float",
"default_value": 2.24,
"value": "top_layers * layer_height / math.tan(math.radians(min_skin_angle_for_expansion))",
"minimum_value": "0",
"enabled": "expand_upper_skins or expand_lower_skins",
"settable_per_mesh": true
}
}
} }
} }
}, },
@ -1260,7 +1362,7 @@
"description": "Change the temperature for each layer automatically with the average flow speed of that layer.", "description": "Change the temperature for each layer automatically with the average flow speed of that layer.",
"type": "bool", "type": "bool",
"default_value": false, "default_value": false,
"enabled": "False", "enabled": "machine_nozzle_temp_enabled and False",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": true "settable_per_extruder": true
}, },
@ -1271,22 +1373,24 @@
"unit": "°C", "unit": "°C",
"type": "float", "type": "float",
"default_value": 210, "default_value": 210,
"enabled": false, "minimum_value_warning": "0",
"maximum_value_warning": "285",
"enabled": "machine_nozzle_temp_enabled",
"settable_per_extruder": true, "settable_per_extruder": true,
"minimum_value": "-273.15" "minimum_value": "-273.15"
}, },
"material_print_temperature": "material_print_temperature":
{ {
"label": "Printing Temperature", "label": "Printing Temperature",
"description": "The temperature used for printing. If this is 0, the extruder will not heat up for this print.", "description": "The temperature used for printing.",
"unit": "°C", "unit": "°C",
"type": "float", "type": "float",
"default_value": 210, "default_value": 210,
"value": "default_material_print_temperature", "value": "default_material_print_temperature",
"minimum_value": "-273.15", "minimum_value": "-273.15",
"minimum_value_warning": "0", "minimum_value_warning": "0",
"maximum_value_warning": "270", "maximum_value_warning": "285",
"enabled": "not (material_flow_dependent_temperature) and machine_gcode_flavor != \"UltiGCode\"", "enabled": "machine_nozzle_temp_enabled and not (material_flow_dependent_temperature)",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": true "settable_per_extruder": true
}, },
@ -1297,11 +1401,11 @@
"unit": "°C", "unit": "°C",
"type": "float", "type": "float",
"default_value": 215, "default_value": 215,
"value": "material_print_temperature + 5", "value": "material_print_temperature",
"minimum_value": "-273.15", "minimum_value": "-273.15",
"minimum_value_warning": "0", "minimum_value_warning": "0",
"maximum_value_warning": "260", "maximum_value_warning": "285",
"enabled": "machine_gcode_flavor != \"UltiGCode\"", "enabled": "machine_nozzle_temp_enabled",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": true "settable_per_extruder": true
}, },
@ -1316,7 +1420,7 @@
"minimum_value": "-273.15", "minimum_value": "-273.15",
"minimum_value_warning": "material_standby_temperature", "minimum_value_warning": "material_standby_temperature",
"maximum_value_warning": "material_print_temperature", "maximum_value_warning": "material_print_temperature",
"enabled": "machine_gcode_flavor != \"UltiGCode\"", "enabled": "machine_nozzle_temp_enabled",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": true "settable_per_extruder": true
}, },
@ -1331,7 +1435,7 @@
"minimum_value": "-273.15", "minimum_value": "-273.15",
"minimum_value_warning": "material_standby_temperature", "minimum_value_warning": "material_standby_temperature",
"maximum_value_warning": "material_print_temperature", "maximum_value_warning": "material_print_temperature",
"enabled": "machine_gcode_flavor != \"UltiGCode\"", "enabled": "machine_nozzle_temp_enabled",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": true "settable_per_extruder": true
}, },
@ -1342,8 +1446,7 @@
"unit": "[[mm³,°C]]", "unit": "[[mm³,°C]]",
"type": "str", "type": "str",
"default_value": "[[3.5,200],[7.0,240]]", "default_value": "[[3.5,200],[7.0,240]]",
"enabled": "False", "enabled": "False and machine_nozzle_temp_enabled and material_flow_dependent_temperature",
"comments": "old enabled function: material_flow_dependent_temperature",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": true "settable_per_extruder": true
}, },
@ -1357,8 +1460,7 @@
"minimum_value": "0", "minimum_value": "0",
"maximum_value_warning": "10.0", "maximum_value_warning": "10.0",
"maximum_value": "machine_nozzle_heat_up_speed", "maximum_value": "machine_nozzle_heat_up_speed",
"enabled": "False", "enabled": "material_flow_dependent_temperature or (machine_extruder_count > 1 and material_final_print_temperature != material_print_temperature)",
"comments": "old enabled function: material_flow_dependent_temperature or machine_extruder_count > 1",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": true "settable_per_extruder": true
}, },
@ -1372,7 +1474,7 @@
"default_value": 60, "default_value": 60,
"minimum_value": "-273.15", "minimum_value": "-273.15",
"minimum_value_warning": "0", "minimum_value_warning": "0",
"maximum_value_warning": "260", "maximum_value_warning": "130",
"enabled": "machine_heated_bed and machine_gcode_flavor != \"UltiGCode\"", "enabled": "machine_heated_bed and machine_gcode_flavor != \"UltiGCode\"",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": false, "settable_per_extruder": false,
@ -1389,7 +1491,7 @@
"value": "resolveOrValue('material_bed_temperature')", "value": "resolveOrValue('material_bed_temperature')",
"minimum_value": "-273.15", "minimum_value": "-273.15",
"minimum_value_warning": "max(extruderValues('material_bed_temperature'))", "minimum_value_warning": "max(extruderValues('material_bed_temperature'))",
"maximum_value_warning": "260", "maximum_value_warning": "130",
"enabled": "machine_heated_bed and machine_gcode_flavor != \"UltiGCode\"", "enabled": "machine_heated_bed and machine_gcode_flavor != \"UltiGCode\"",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": false, "settable_per_extruder": false,
@ -1565,7 +1667,7 @@
"minimum_value": "-273.15", "minimum_value": "-273.15",
"minimum_value_warning": "0", "minimum_value_warning": "0",
"maximum_value_warning": "260", "maximum_value_warning": "260",
"enabled": "machine_extruder_count > 1 and machine_gcode_flavor != \"UltiGCode\"", "enabled": "machine_extruder_count > 1 and machine_nozzle_temp_enabled",
"settable_per_mesh": false, "settable_per_mesh": false,
"settable_per_extruder": true "settable_per_extruder": true
}, },

View file

@ -18,8 +18,8 @@
"bottom_thickness": { "bottom_thickness": {
"value": "0.5" "value": "0.5"
}, },
"brim_line_count": { "brim_width": {
"value": "20.0" "value": "2.0"
}, },
"cool_fan_enabled": { "cool_fan_enabled": {
"value": "True" "value": "True"
@ -81,6 +81,9 @@
"material_diameter": { "material_diameter": {
"value": "1.75" "value": "1.75"
}, },
"material_flow": {
"value": "110"
},
"material_print_temperature": { "material_print_temperature": {
"value": "210.0" "value": "210.0"
}, },
@ -151,13 +154,13 @@
"value": "3.0" "value": "3.0"
}, },
"skirt_line_count": { "skirt_line_count": {
"value": "1.0" "value": "3"
}, },
"speed_infill": { "speed_infill": {
"value": "50.0" "value": "50.0"
}, },
"speed_layer_0": { "speed_layer_0": {
"value": "30.0" "value": "15.0"
}, },
"speed_print": { "speed_print": {
"value": "50.0" "value": "50.0"

View file

@ -100,6 +100,9 @@
}, },
"machine_acceleration": { "machine_acceleration": {
"default_value": 3000 "default_value": 3000
},
"machine_nozzle_temp_enabled": {
"default_value": false
} }
} }
} }

View file

@ -106,6 +106,7 @@
"line_width": { "value": "machine_nozzle_size * 0.875" }, "line_width": { "value": "machine_nozzle_size * 0.875" },
"machine_min_cool_heat_time_window": { "value": "15" }, "machine_min_cool_heat_time_window": { "value": "15" },
"default_material_print_temperature": { "value": "200" }, "default_material_print_temperature": { "value": "200" },
"material_print_temperature_layer_0": { "value": "material_print_temperature + 5" },
"material_bed_temperature": { "maximum_value": "115" }, "material_bed_temperature": { "maximum_value": "115" },
"material_bed_temperature_layer_0": { "maximum_value": "115" }, "material_bed_temperature_layer_0": { "maximum_value": "115" },
"material_standby_temperature": { "value": "100" }, "material_standby_temperature": { "value": "100" },

View file

@ -62,7 +62,7 @@
"default_value": "G21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstops\nG1 Z15.0 F9000 ;move the platform down 15mm\nG92 E0 ;zero the extruded length\nG1 F200 E6 ;extrude 6 mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F9000\n;Put printing message on LCD screen\nM117 Printing..." "default_value": "G21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstops\nG1 Z15.0 F9000 ;move the platform down 15mm\nG92 E0 ;zero the extruded length\nG1 F200 E6 ;extrude 6 mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F9000\n;Put printing message on LCD screen\nM117 Printing..."
}, },
"machine_end_gcode": { "machine_end_gcode": {
"default_value": "M104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+0.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\nG28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\nM84 ;steppers off\nG90 ;absolute positioning" "value": "'M104 S0 ;extruder heater off' + ('\\nM140 S0 ;heated bed heater off' if machine_heated_bed else '') + '\\nG91 ;relative positioning\\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\\nG1 Z+0.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\\nG28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\\nM84 ;steppers off\\nG90 ;absolute positioning'"
} }
} }
} }

View file

@ -0,0 +1,84 @@
{
"id": "vertex_k8400",
"version": 2,
"name": "Vertex K8400",
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"manufacturer": "Velleman",
"category": "Other",
"file_formats": "text/x-gcode",
"icon": "icon_ultimaker2",
"platform": "Vertex_build_panel.stl",
"platform_offset": [0, -2, 0],
"supports_usb_connection": true,
"supported_actions": ["MachineSettingsAction"]
},
"overrides": {
"machine_name": { "default_value": "Vertex K8400" },
"machine_heated_bed": {
"default_value": true
},
"material_bed_temperature": {
"default_value": 0
},
"material_bed_temperature_layer_0": {
"default_value": 0
},
"machine_width": {
"default_value": 200
},
"machine_height": {
"default_value": 190
},
"machine_depth": {
"default_value": 200
},
"machine_disallowed_areas": { "default_value": [
[[-100,100],[-100,80],[100,80],[100,100]]
]},
"machine_center_is_zero": {
"default_value": false
},
"machine_nozzle_size": {
"default_value": 0.35
},
"material_diameter": {
"default_value": 1.75
},
"machine_head_polygon": {
"default_value": [
[-60, -18],
[-60, 40],
[18, 40],
[18, -18]
]
},
"machine_head_with_fans_polygon": {
"default_value": [
[-60, -40],
[-60, 40],
[18, 40],
[18, -40]
]
},
"gantry_height": {
"default_value": 18
},
"machine_nozzle_heat_up_speed": {
"default_value": 2
},
"machine_nozzle_cool_down_speed": {
"default_value": 2
},
"machine_gcode_flavor": {
"default_value": "RepRap (Marlin/Sprinter)"
},
"machine_start_gcode": {
"default_value": "G21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstops\nG1 Z15.0 F9000 ;move the platform down 15mm\nG92 E0 ;zero the extruded length\nG1 F200 E3 ;extrude 3mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F9000\n;Put printing message on LCD screen\nM117 Printing..."
},
"machine_end_gcode": {
"default_value": "M104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+0.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\nG28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\nM84 ;steppers off\nG90 ;absolute positioning"
}
}
}

View file

@ -0,0 +1,92 @@
{
"id": "vertex_k8400_dual",
"version": 2,
"name": "Vertex K8400 Dual",
"inherits": "fdmprinter",
"metadata": {
"visible": true,
"manufacturer": "Velleman",
"category": "Other",
"file_formats": "text/x-gcode",
"icon": "icon_ultimaker2",
"platform": "Vertex_build_panel.stl",
"platform_offset": [0, -2, 0],
"machine_extruder_trains": {
"0": "vertex_k8400_dual_1st",
"1": "vertex_k8400_dual_2nd"
}
},
"overrides": {
"machine_name": { "default_value": "Vertex K8400 Dual" },
"machine_heated_bed": {
"default_value": true
},
"material_bed_temperature": {
"default_value": 0
},
"material_bed_temperature_layer_0": {
"default_value": 0
},
"machine_width": {
"default_value": 223.7
},
"machine_height": {
"default_value": 190
},
"machine_depth": {
"default_value": 200
},
"machine_disallowed_areas": { "default_value": [
[[-111.85,100],[111.85,100],[-111.85,80],[111.85,80]]
]},
"machine_center_is_zero": {
"default_value": false
},
"machine_use_extruder_offset_to_offset_coords": {
"default_value": true
},
"machine_nozzle_size": {
"default_value": 0.35
},
"material_diameter": {
"default_value": 1.75
},
"machine_head_polygon": {
"default_value": [
[-60, -18],
[-60, 40],
[18, 40],
[18, -18]
]
},
"machine_head_with_fans_polygon": {
"default_value": [
[-60, -40],
[-60, 40],
[18, 40],
[18, -40]
]
},
"gantry_height": {
"default_value": 18
},
"machine_nozzle_heat_up_speed": {
"default_value": 2
},
"machine_nozzle_cool_down_speed": {
"default_value": 2
},
"machine_extruder_count": {
"default_value": 2
},
"machine_gcode_flavor": {
"default_value": "RepRap (Marlin/Sprinter)"
},
"machine_start_gcode": {
"default_value": "G21 ;metric values\nG90 ;absolute positioning\nM82 ;set extruder to absolute mode\nM107 ;start with the fan off\nG28 X0 Y0 ;move X/Y to min endstops\nG28 Z0 ;move Z to min endstops\nG1 Z15.0 F9000 ;move the platform down 15mm\nG92 E0 ;zero the extruded length\nG1 F200 E3 ;extrude 3mm of feed stock\nG92 E0 ;zero the extruded length again\nG1 F9000\n;Put printing message on LCD screen\nM117 Printing..."
},
"machine_end_gcode": {
"default_value": "M104 S0 ;extruder heater off\nM140 S0 ;heated bed heater off (if you have it)\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+0.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\nG28 X0 Y0 ;move X/Y to min endstops, so the head is out of the way\nM84 ;steppers off\nG90 ;absolute positioning"
}
}
}

View file

@ -16,10 +16,10 @@
"machine_nozzle_offset_x": { "default_value": 0.0 }, "machine_nozzle_offset_x": { "default_value": 0.0 },
"machine_nozzle_offset_y": { "default_value": 0.0 }, "machine_nozzle_offset_y": { "default_value": 0.0 },
"machine_extruder_start_code": { "machine_extruder_start_code": {
"default_value": "M117 Heating nozzles....\nM104 S190 T0\nG1 X70 Y20 F9000\nM109 S270 T0 ;wait for nozzle to heat up\nT0\n\nM117 purging nozzle\nG92 E0\nG1 E6 F90\nG92 E0\nG1 E-2 F300\nG92 E0\nM117 wiping nozzle\nG1 X1 Y28 F3000\nG1 X70 F6000\n\nM117 printing\n" "default_value": "\n;start extruder_0\nM117 Heating nozzles....\nM104 S190 T0\nG1 X70 Y20 F9000\nM109 S190 T0\n\nM117 purging nozzle\nG92 E0\nG1 E6 F90\nG92 E0\nG1 E-2 F300\nG92 E0\nM117 wiping nozzle\nG1 X1 Y28 F3000\nG1 X70 F6000\n\nM117 printing\n"
}, },
"machine_extruder_end_code": { "machine_extruder_end_code": {
"default_value": "\nM104 S160 T0\n;end extruder_0\nM117 temp is {material_print_temp}" "default_value": "\nM104 T0 S155\n;end extruder_0\nM117 temp is {material_print_temp}"
} }
} }
} }

View file

@ -16,10 +16,10 @@
"machine_nozzle_offset_x": { "default_value": 24.0 }, "machine_nozzle_offset_x": { "default_value": 24.0 },
"machine_nozzle_offset_y": { "default_value": 0.0 }, "machine_nozzle_offset_y": { "default_value": 0.0 },
"machine_extruder_start_code": { "machine_extruder_start_code": {
"default_value": "\n;start extruder_1\nM117 Heating nozzles....\nM104 S190 T1\nG1 X70 Y20 F9000\nM109 S190 T1 ;wait for nozzle to heat up\n\nM117 purging nozzle\nG92 E0\nG1 E6 F90\nG92 E0\nG1 E-2 F300\nG92 E0\n\nM117 wiping nozzle\nG1 X1 Y28 F3000\nG1 X70 F6000\n\nM117 printing\n" "default_value": "\n;start extruder_1\nM117 Heating nozzles....\nM104 S190 T1\nG1 X70 Y20 F9000\nM109 S190 T1\n\nM117 purging nozzle\nG92 E0\nG1 E6 F90\nG92 E0\nG1 E-2 F300\nG92 E0\n\nM117 wiping nozzle\nG1 X1 Y28 F3000\nG1 X70 F6000\n\nM117 printing\n"
}, },
"machine_extruder_end_code": { "machine_extruder_end_code": {
"default_value": "\nM104 T0 S120\n;end extruder_1\n" "default_value": "\nM104 T1 S155\n;end extruder_1\n"
} }
} }
} }

View file

@ -19,7 +19,7 @@
"default_value": "\n;start extruder_2\nM117 Heating nozzles....\nM104 S190 T2\nG1 X70 Y20 F9000\nM109 S190 T2\n\nM117 purging nozzle\nG92 E0\nG1 E6 F90\nG92 E0\nG1 E-2 F300\nG92 E0\n\nM117 wiping nozzle\nG1 X1 Y28 F3000\nG1 X70 F6000\n\nM117 printing\n" "default_value": "\n;start extruder_2\nM117 Heating nozzles....\nM104 S190 T2\nG1 X70 Y20 F9000\nM109 S190 T2\n\nM117 purging nozzle\nG92 E0\nG1 E6 F90\nG92 E0\nG1 E-2 F300\nG92 E0\n\nM117 wiping nozzle\nG1 X1 Y28 F3000\nG1 X70 F6000\n\nM117 printing\n"
}, },
"machine_extruder_end_code": { "machine_extruder_end_code": {
"default_value": "\nM104 T2 S120\n;end extruder_2\n" "default_value": "\nM104 T2 S155\n;end extruder_2\n"
} }
} }
} }

View file

@ -19,7 +19,7 @@
"default_value": "\n;start extruder_3\nM117 Heating nozzles....\nM104 S190 T3\nG1 X70 Y20 F9000\nM109 S190 T3\n\nM117 purging nozzle\nG92 E0\nG1 E6 F90\nG92 E0\nG1 E-2 F300\nG92 E0\n\nM117 wiping nozzle\nG1 X1 Y28 F3000\nG1 X70 F6000\n\nM117 printing\n" "default_value": "\n;start extruder_3\nM117 Heating nozzles....\nM104 S190 T3\nG1 X70 Y20 F9000\nM109 S190 T3\n\nM117 purging nozzle\nG92 E0\nG1 E6 F90\nG92 E0\nG1 E-2 F300\nG92 E0\n\nM117 wiping nozzle\nG1 X1 Y28 F3000\nG1 X70 F6000\n\nM117 printing\n"
}, },
"machine_extruder_end_code": { "machine_extruder_end_code": {
"default_value": "\nM104 T3 S120\n;end extruder_3\n" "default_value": "\nM104 T3 S155\n;end extruder_3\n"
} }
} }
} }

View file

@ -0,0 +1,26 @@
{
"id": "vertex_k8400_dual_1st",
"version": 2,
"name": "Extruder 1",
"inherits": "fdmextruder",
"metadata": {
"machine": "vertex_k8400_dual",
"position": "0"
},
"overrides": {
"extruder_nr": {
"default_value": 0,
"maximum_value": "1"
},
"machine_nozzle_offset_x": { "default_value": 23.7 },
"machine_nozzle_offset_y": { "default_value": 0.0 },
"machine_extruder_start_pos_abs": { "default_value": true },
"machine_extruder_start_pos_x": { "value": "prime_tower_position_x" },
"machine_extruder_start_pos_y": { "value": "prime_tower_position_y" },
"machine_extruder_end_pos_abs": { "default_value": true },
"machine_extruder_end_pos_x": { "value": "prime_tower_position_x" },
"machine_extruder_end_pos_y": { "value": "prime_tower_position_y" }
}
}

View file

@ -0,0 +1,26 @@
{
"id": "vertex_k8400_dual_2nd",
"version": 2,
"name": "Extruder 2",
"inherits": "fdmextruder",
"metadata": {
"machine": "vertex_k8400_dual",
"position": "1"
},
"overrides": {
"extruder_nr": {
"default_value": 1,
"maximum_value": "1"
},
"machine_nozzle_offset_x": { "default_value": 0.0 },
"machine_nozzle_offset_y": { "default_value": 0.0 },
"machine_extruder_start_pos_abs": { "default_value": true },
"machine_extruder_start_pos_x": { "value": "prime_tower_position_x" },
"machine_extruder_start_pos_y": { "value": "prime_tower_position_y" },
"machine_extruder_end_pos_abs": { "default_value": true },
"machine_extruder_end_pos_x": { "value": "prime_tower_position_x" },
"machine_extruder_end_pos_y": { "value": "prime_tower_position_y" }
}
}

Binary file not shown.

View file

@ -262,6 +262,7 @@ Item
id: reloadAllAction; id: reloadAllAction;
text: catalog.i18nc("@action:inmenu menubar:file","Re&load All Models"); text: catalog.i18nc("@action:inmenu menubar:file","Re&load All Models");
iconName: "document-revert"; iconName: "document-revert";
shortcut: "F5"
onTriggered: Printer.reloadAll(); onTriggered: Printer.reloadAll();
} }

15
resources/qml/Cura.qml Normal file → Executable file
View file

@ -870,6 +870,21 @@ UM.MainWindow
} }
} }
DiscardOrKeepProfileChangesDialog
{
id: discardOrKeepProfileChangesDialog
}
Connections
{
target: Printer
onShowDiscardOrKeepProfileChanges:
{
discardOrKeepProfileChangesDialog.show()
}
}
Connections Connections
{ {
target: Cura.Actions.addMachine target: Cura.Actions.addMachine

View file

@ -0,0 +1,214 @@
// Copyright (c) 2017 Ultimaker B.V.
// Cura is released under the terms of the AGPLv3 or higher.
import QtQuick 2.1
import QtQuick.Controls 1.1
import QtQuick.Dialogs 1.2
import UM 1.2 as UM
import Cura 1.1 as Cura
UM.Dialog
{
id: base
title: catalog.i18nc("@title:window", "Discard or Keep changes")
width: 500
height: 300
property var changesModel: Cura.UserChangesModel{ id: userChangesModel}
onVisibilityChanged:
{
if(visible)
{
changesModel.forceUpdate()
}
}
Column
{
anchors.fill: parent
spacing: UM.Theme.getSize("default_margin").width
UM.I18nCatalog
{
id: catalog;
name:"cura"
}
Row
{
height: childrenRect.height
anchors.margins: UM.Theme.getSize("default_margin").width
anchors.left: parent.left
anchors.right: parent.right
spacing: UM.Theme.getSize("default_margin").width
UM.RecolorImage
{
source: UM.Theme.getIcon("star")
width : 30
height: width
color: UM.Theme.getColor("setting_control_button")
}
Label
{
text: "You have customized some profile settings.\nWould you like to keep or discard those settings?"
anchors.margins: UM.Theme.getSize("default_margin").width
font: UM.Theme.getFont("default_bold")
wrapMode: Text.WordWrap
}
}
TableView
{
anchors.margins: UM.Theme.getSize("default_margin").width
anchors.left: parent.left
anchors.right: parent.right
height: base.height - 200
id: tableView
Component
{
id: labelDelegate
Label
{
property var extruder_name: userChangesModel.getItem(styleData.row).extruder
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_margin").width
font: UM.Theme.getFont("default")
text:
{
var result = styleData.value
if (extruder_name!= "")
{
result += " (" + extruder_name + ")"
}
return result
}
}
}
Component
{
id: defaultDelegate
Label
{
text: styleData.value
font: UM.Theme.getFont("default")
color: UM.Theme.getColor("setting_control_disabled_text")
}
}
TableViewColumn
{
role: "label"
title: catalog.i18nc("@title:column", "Profile settings")
delegate: labelDelegate
width: tableView.width * 0.5
}
TableViewColumn
{
role: "original_value"
title: "Default"
width: tableView.width * 0.25
delegate: defaultDelegate
}
TableViewColumn
{
role: "user_value"
title: catalog.i18nc("@title:column", "Customized")
width: tableView.width * 0.25 - 1
}
section.property: "category"
section.delegate: Label
{
text: section
font.bold: true
}
model: base.changesModel
}
Item
{
anchors.right: parent.right
anchors.left: parent.left
anchors.margins: UM.Theme.getSize("default_margin").width
height:childrenRect.height
ComboBox
{
id: discardOrKeepProfileChangesDropDownButton
model: [
catalog.i18nc("@option:discardOrKeep", "Always ask me this"),
catalog.i18nc("@option:discardOrKeep", "Discard and never ask again"),
catalog.i18nc("@option:discardOrKeep", "Keep and never ask again")
]
width: 300
currentIndex: UM.Preferences.getValue("cura/choice_on_profile_override")
onCurrentIndexChanged:
{
UM.Preferences.setValue("cura/choice_on_profile_override", currentIndex)
if (currentIndex == 1) {
// 1 == "Discard and never ask again", so only enable the "Discard" button
discardButton.enabled = true
keepButton.enabled = false
}
else if (currentIndex == 2) {
// 2 == "Keep and never ask again", so only enable the "Keep" button
keepButton.enabled = true
discardButton.enabled = false
}
else {
// 0 == "Always ask me this", so show both
keepButton.enabled = true
discardButton.enabled = true
}
}
}
}
Item
{
anchors.right: parent.right
anchors.left: parent.left
anchors.margins: UM.Theme.getSize("default_margin").width
height:childrenRect.height
Button
{
id: discardButton
text: catalog.i18nc("@action:button", "Discard");
anchors.right: parent.right
onClicked:
{
Printer.discardOrKeepProfileChangesClosed("discard")
base.hide()
}
isDefault: true
}
Button
{
id: keepButton
text: catalog.i18nc("@action:button", "Keep");
anchors.right: discardButton.left
anchors.rightMargin: UM.Theme.getSize("default_margin").width
onClicked:
{
Printer.discardOrKeepProfileChangesClosed("keep")
base.hide()
}
}
Button
{
id: createNewProfileButton
text: catalog.i18nc("@action:button", "Create New Profile");
anchors.left: parent.left
action: Cura.Actions.addProfile
onClicked: base.hide()
}
}
}
}

38
resources/qml/Preferences/GeneralPage.qml Normal file → Executable file
View file

@ -45,6 +45,10 @@ UM.PreferencesPage
showOverhangCheckbox.checked = boolCheck(UM.Preferences.getValue("view/show_overhang")) showOverhangCheckbox.checked = boolCheck(UM.Preferences.getValue("view/show_overhang"))
UM.Preferences.resetPreference("view/center_on_select"); UM.Preferences.resetPreference("view/center_on_select");
centerOnSelectCheckbox.checked = boolCheck(UM.Preferences.getValue("view/center_on_select")) centerOnSelectCheckbox.checked = boolCheck(UM.Preferences.getValue("view/center_on_select"))
UM.Preferences.resetPreference("view/top_layer_count");
topLayerCountCheckbox.checked = boolCheck(UM.Preferences.getValue("view/top_layer_count"))
UM.Preferences.resetPreference("cura/choice_on_profile_override")
choiceOnProfileOverrideDropDownButton.currentIndex = UM.Preferences.getValue("cura/choice_on_profile_override")
if (plugins.find("id", "SliceInfoPlugin") > -1) { if (plugins.find("id", "SliceInfoPlugin") > -1) {
UM.Preferences.resetPreference("info/send_slice_info") UM.Preferences.resetPreference("info/send_slice_info")
@ -337,6 +341,40 @@ UM.PreferencesPage
} }
} }
Item
{
//: Spacer
height: UM.Theme.getSize("default_margin").height
width: UM.Theme.getSize("default_margin").width
}
Label
{
font.bold: true
text: catalog.i18nc("@label", "Override Profile")
}
UM.TooltipArea
{
width: childrenRect.width;
height: childrenRect.height;
text: catalog.i18nc("@info:tooltip", "When you have made changes to a profile and switched to a different one, a dialog will be shown asking whether you want to keep your modifications or not, or you can choose a default behaviour and never show that dialog again.")
ComboBox
{
id: choiceOnProfileOverrideDropDownButton
model: [
catalog.i18nc("@option:discardOrKeep", "Always ask me this"),
catalog.i18nc("@option:discardOrKeep", "Discard and never ask again"),
catalog.i18nc("@option:discardOrKeep", "Keep and never ask again")
]
width: 300
currentIndex: UM.Preferences.getValue("cura/choice_on_profile_override")
onCurrentIndexChanged: UM.Preferences.setValue("cura/choice_on_profile_override", currentIndex)
}
}
Item Item
{ {

View file

@ -89,15 +89,20 @@ UM.ManagementPage
id: machineActionRepeater id: machineActionRepeater
model: base.currentItem ? Cura.MachineActionManager.getSupportedActions(Cura.MachineManager.getDefinitionByMachineId(base.currentItem.id)) : null model: base.currentItem ? Cura.MachineActionManager.getSupportedActions(Cura.MachineManager.getDefinitionByMachineId(base.currentItem.id)) : null
Button Item
{ {
text: machineActionRepeater.model[index].label width: childrenRect.width + 2
onClicked: height: childrenRect.height
Button
{ {
actionDialog.content = machineActionRepeater.model[index].displayItem; text: machineActionRepeater.model[index].label
machineActionRepeater.model[index].displayItem.reset(); onClicked:
actionDialog.title = machineActionRepeater.model[index].label; {
actionDialog.show(); actionDialog.content = machineActionRepeater.model[index].displayItem;
machineActionRepeater.model[index].displayItem.reset();
actionDialog.title = machineActionRepeater.model[index].label;
actionDialog.show();
}
} }
} }
} }

View file

@ -98,9 +98,9 @@ SettingItem
selectByMouse: true; selectByMouse: true;
maximumLength: 10; maximumLength: (definition.type == "[int]") ? 20 : 10;
validator: RegExpValidator { regExp: (definition.type == "int") ? /^-?[0-9]{0,10}$/ : /^-?[0-9]{0,9}[.,]?[0-9]{0,10}$/ } // definition.type property from parent loader used to disallow fractional number entry validator: RegExpValidator { regExp: (definition.type == "[int]") ? /^\[?(\s*-?[0-9]{0,9}\s*,)*(\s*-?[0-9]{0,9})\s*\]?$/ : (definition.type == "int") ? /^-?[0-9]{0,10}$/ : /^-?[0-9]{0,9}[.,]?[0-9]{0,10}$/ } // definition.type property from parent loader used to disallow fractional number entry
Binding Binding
{ {

View file

@ -217,6 +217,8 @@ Item
{ {
case "int": case "int":
return "SettingTextField.qml" return "SettingTextField.qml"
case "[int]":
return "SettingTextField.qml"
case "float": case "float":
return "SettingTextField.qml" return "SettingTextField.qml"
case "enum": case "enum":

View file

@ -10,12 +10,28 @@ material = generic_cpe_plus_ultimaker3_AA_0.4
weight = -2 weight = -2
[values] [values]
brim_width = 7
cool_fan_speed_max = 80 cool_fan_speed_max = 80
cool_min_speed = 5
infill_wipe_dist = 0
layer_height = 0.2 layer_height = 0.2
machine_nozzle_cool_down_speed = 0.9 machine_nozzle_cool_down_speed = 0.9
speed_print = 50 machine_nozzle_heat_up_speed = 1.4
material_initial_print_temperature = =material_print_temperature - 5
material_final_print_temperature = =material_print_temperature - 10
material_print_temperature = =default_material_print_temperature + 5
prime_tower_size = 17
retraction_combing = off
retraction_hop = 0.2
retraction_hop_enabled = False
retraction_min_travel = =5
retraction_prime_speed = =15
speed_topbottom = =math.ceil(speed_print * 65 / 50) speed_topbottom = =math.ceil(speed_print * 65 / 50)
speed_wall = =math.ceil(speed_print * 50 / 50) speed_wall = =math.ceil(speed_print * 50 / 50)
speed_wall_0 = =math.ceil(speed_wall * 40 / 50) speed_wall_0 = =math.ceil(speed_wall * 40 / 50)
support_z_distance = =layer_height
switch_extruder_prime_speed = =15
switch_extruder_retraction_amount = =8
switch_extruder_retraction_speeds = 20
wall_thickness = 1 wall_thickness = 1

View file

@ -10,12 +10,29 @@ material = generic_cpe_plus_ultimaker3_AA_0.4
weight = -1 weight = -1
[values] [values]
brim_width = 7
cool_fan_speed_max = 80 cool_fan_speed_max = 80
cool_min_speed = 6 cool_min_speed = 6
infill_wipe_dist = 0
layer_height = 0.15 layer_height = 0.15
machine_nozzle_cool_down_speed = 0.9 machine_nozzle_cool_down_speed = 0.9
machine_nozzle_heat_up_speed = 1.4
material_initial_print_temperature = =material_print_temperature - 5
material_final_print_temperature = =material_print_temperature - 10
material_print_temperature = =default_material_print_temperature + 5
prime_tower_size = 17
retraction_combing = off
retraction_hop = 0.2
retraction_hop_enabled = False
retraction_min_travel = =5
retraction_prime_speed = =15
speed_print = 45 speed_print = 45
speed_topbottom = =math.ceil(speed_print * 55 / 45) speed_topbottom = =math.ceil(speed_print * 55 / 45)
speed_wall = =math.ceil(speed_print * 45 / 45) speed_wall = =math.ceil(speed_print * 45 / 45)
speed_wall_0 = =math.ceil(speed_wall * 35 / 45) speed_wall_0 = =math.ceil(speed_wall * 35 / 45)
support_z_distance = =layer_height
switch_extruder_prime_speed = =15
switch_extruder_retraction_amount = =8
switch_extruder_retraction_speeds = 20
wall_thickness = 1.3

View file

@ -10,6 +10,26 @@ material = generic_cpe_plus_ultimaker3_AA_0.4
weight = 1 weight = 1
[values] [values]
machine_nozzle_heat_up_speed = 1.5 brim_width = 7
material_print_temperature = =default_material_print_temperature + 2 cool_min_speed = 5
infill_wipe_dist = 0
layer_height = 0.06
material_initial_print_temperature = =material_print_temperature - 5
material_final_print_temperature = =material_print_temperature - 10
material_print_temperature = =default_material_print_temperature - 3
prime_tower_size = 17
retraction_combing = off
retraction_hop = 0.2
retraction_hop_enabled = False
retraction_min_travel = =5
retraction_prime_speed = =15
speed_print = 40
speed_topbottom = =math.ceil(speed_print * 30 / 35)
speed_wall = =math.ceil(speed_print * 35 / 40)
speed_wall_0 = =math.ceil(speed_wall * 30 / 35)
support_z_distance = =layer_height
switch_extruder_prime_speed = =15
switch_extruder_retraction_amount = =8
switch_extruder_retraction_speeds = 20
wall_thickness = 1.3

View file

@ -10,8 +10,25 @@ material = generic_cpe_plus_ultimaker3_AA_0.4
weight = 0 weight = 0
[values] [values]
brim_width = 7
cool_min_speed = 7 cool_min_speed = 7
layer_height = 0.1 infill_wipe_dist = 0
machine_nozzle_heat_up_speed = 1.5 material_initial_print_temperature = =material_print_temperature - 5
material_print_temperature = =default_material_print_temperature + 5 material_final_print_temperature = =material_print_temperature - 10
material_print_temperature = =default_material_print_temperature
prime_tower_size = 17
retraction_combing = off
retraction_hop = 0.2
retraction_hop_enabled = False
retraction_min_travel = =5
retraction_prime_speed = =15
speed_print = 40
speed_topbottom = =math.ceil(speed_print * 30 / 35)
speed_wall = =math.ceil(speed_print * 35 / 40)
speed_wall_0 = =math.ceil(speed_wall * 30 / 35)
support_z_distance = =layer_height
switch_extruder_prime_speed = =15
switch_extruder_retraction_amount = =8
switch_extruder_retraction_speeds = 20
wall_thickness = 1.3

View file

@ -10,7 +10,27 @@ material = generic_pc_ultimaker3_AA_0.4
weight = -2 weight = -2
[values] [values]
adhesion_type = raft
cool_fan_full_at_height = =layer_height_0 + layer_height
cool_fan_speed_max = 90 cool_fan_speed_max = 90
cool_min_layer_time_fan_speed_max = 5
cool_min_speed = 6 cool_min_speed = 6
infill_line_width = =round(line_width * 0.4 / 0.35, 2)
infill_overlap_mm = 0.05
layer_height = 0.2 layer_height = 0.2
material_final_print_temperature = =material_print_temperature - 10
material_initial_print_temperature = =material_print_temperature - 5
material_print_temperature = =default_material_print_temperature + 10
material_print_temperature_layer_0 = =material_print_temperature + 5
ooze_shield_angle = 40
raft_airgap = 0.25
raft_margin = 15
retraction_count_max = 80
skin_overlap = 30
speed_layer_0 = 25
support_interface_line_distance = 0.4
support_interface_pattern = lines
support_pattern = zigzag
wall_line_width_x = =round(line_width * 0.4 / 0.35, 2)
xy_offset = -0.15

View file

@ -10,8 +10,28 @@ material = generic_pc_ultimaker3_AA_0.4
weight = -1 weight = -1
[values] [values]
adhesion_type = raft
cool_fan_full_at_height = =layer_height_0 + layer_height
cool_fan_speed_max = 85 cool_fan_speed_max = 85
cool_min_layer_time_fan_speed_max = 5
cool_min_speed = 7 cool_min_speed = 7
infill_line_width = =round(line_width * 0.4 / 0.35, 2)
infill_overlap = =0 infill_overlap = =0
infill_overlap_mm = 0.05
layer_height = 0.15 layer_height = 0.15
material_initial_print_temperature = =material_print_temperature - 5
material_final_print_temperature = =material_print_temperature - 10
material_print_temperature = =default_material_print_temperature + 10
material_print_temperature_layer_0 = =material_print_temperature + 5
ooze_shield_angle = 40
raft_airgap = 0.25
raft_margin = 15
retraction_count_max = 80
skin_overlap = 30
speed_layer_0 = 25
support_interface_line_distance = 0.4
support_interface_pattern = lines
support_pattern = zigzag
wall_line_width_x = =round(line_width * 0.4 / 0.35, 2)
xy_offset = -0.15

View file

@ -10,6 +10,26 @@ material = generic_pc_ultimaker3_AA_0.4
weight = 1 weight = 1
[values] [values]
adhesion_type = raft
cool_fan_full_at_height = =layer_height_0 + layer_height
cool_min_layer_time_fan_speed_max = 5
cool_min_speed = 8 cool_min_speed = 8
infill_line_width = =round(line_width * 0.4 / 0.35, 2)
infill_overlap_mm = 0.05
layer_height = 0.06
material_initial_print_temperature = =material_print_temperature - 5
material_final_print_temperature = =material_print_temperature - 10
material_print_temperature = =default_material_print_temperature - 10 material_print_temperature = =default_material_print_temperature - 10
material_print_temperature_layer_0 = =material_print_temperature + 5
ooze_shield_angle = 40
raft_airgap = 0.25
raft_margin = 15
retraction_count_max = 80
skin_overlap = 30
speed_layer_0 = 25
support_interface_line_distance = 0.4
support_interface_pattern = lines
support_pattern = zigzag
wall_line_width_x = =round(line_width * 0.4 / 0.35, 2)
xy_offset = -0.15

View file

@ -10,6 +10,25 @@ material = generic_pc_ultimaker3_AA_0.4
weight = 0 weight = 0
[values] [values]
layer_height = 0.1 adhesion_type = raft
cool_fan_full_at_height = =layer_height_0 + layer_height
cool_min_layer_time_fan_speed_max = 5
cool_min_speed = 5
infill_line_width = =round(line_width * 0.4 / 0.35, 2)
infill_overlap_mm = 0.05
material_initial_print_temperature = =material_print_temperature - 5
material_final_print_temperature = =material_print_temperature - 10
material_print_temperature = =default_material_print_temperature material_print_temperature = =default_material_print_temperature
material_print_temperature_layer_0 = =material_print_temperature + 5
ooze_shield_angle = 40
raft_airgap = 0.25
raft_margin = 15
retraction_count_max = 80
skin_overlap = 30
speed_layer_0 = 25
support_interface_line_distance = 0.4
support_interface_pattern = lines
support_pattern = zigzag
wall_line_width_x = =round(line_width * 0.4 / 0.35, 2)
xy_offset = -0.15

View file

@ -10,5 +10,34 @@ material = generic_tpu_ultimaker3_AA_0.4
weight = -2 weight = -2
[values] [values]
brim_width = 8.75
cool_fan_speed_max = 100
cool_min_layer_time_fan_speed_max = 6
gradual_infill_step_height = =5 * layer_height
gradual_infill_steps = 4
infill_line_width = =round(line_width * 0.38 / 0.38, 2)
infill_pattern = tetrahedral
infill_sparse_density = 96
layer_height = 0.2 layer_height = 0.2
line_width = =machine_nozzle_size * 0.95
material_final_print_temperature = =material_print_temperature - 10
material_flow = 106
material_initial_print_temperature = =material_print_temperature - 5
material_print_temperature = =default_material_print_temperature + 2
material_print_temperature_layer_0 = =material_print_temperature
retraction_count_max = 12
retraction_extra_prime_amount = 0.8
skin_overlap = 15
speed_equalize_flow_enabled = True
speed_layer_0 = 18
speed_print = 25
speed_topbottom = =math.ceil(speed_print * 25 / 25)
speed_travel = 300
speed_wall = =math.ceil(speed_print * 25 / 25)
speed_wall_0 = =math.ceil(speed_wall * 25 / 25)
support_angle = 50
support_bottom_distance = =support_z_distance / 2
top_bottom_thickness = 0.7
wall_line_width_x = =line_width
wall_thickness = 0.76

View file

@ -10,6 +10,35 @@ material = generic_tpu_ultimaker3_AA_0.4
weight = -1 weight = -1
[values] [values]
brim_width = 8.75
cool_fan_speed_max = 100
cool_min_layer_time_fan_speed_max = 6
gradual_infill_step_height = =5 * layer_height
gradual_infill_steps = 4
infill_line_width = =round(line_width * 0.38 / 0.38, 2)
infill_pattern = tetrahedral
infill_sparse_density = 96
layer_height = 0.15 layer_height = 0.15
line_width = =machine_nozzle_size * 0.95
material_final_print_temperature = =material_print_temperature - 10
material_flow = 106
material_initial_print_temperature = =material_print_temperature - 5
material_print_temperature = =default_material_print_temperature + 2
material_print_temperature_layer_0 = =material_print_temperature
retraction_amount = 7 retraction_amount = 7
retraction_count_max = 12
retraction_extra_prime_amount = 0.8
skin_overlap = 15
speed_equalize_flow_enabled = True
speed_layer_0 = 18
speed_print = 25
speed_topbottom = =math.ceil(speed_print * 25 / 25)
speed_travel = 300
speed_wall = =math.ceil(speed_print * 25 / 25)
speed_wall_0 = =math.ceil(speed_wall * 25 / 25)
support_angle = 50
support_bottom_distance = =support_z_distance / 2
top_bottom_thickness = 0.7
wall_line_width_x = =line_width
wall_thickness = 0.76

View file

@ -10,7 +10,33 @@ material = generic_tpu_ultimaker3_AA_0.4
weight = 0 weight = 0
[values] [values]
brim_width = 8.75
cool_fan_speed_max = 100
cool_min_layer_time_fan_speed_max = 6
gradual_infill_step_height = =5 * layer_height
gradual_infill_steps = 4
infill_line_width = =round(line_width * 0.38 / 0.38, 2)
infill_pattern = tetrahedral
infill_sparse_density = 96
line_width = =machine_nozzle_size * 0.95
material_final_print_temperature = =material_print_temperature - 10
material_flow = 106
material_initial_print_temperature = =material_print_temperature - 10 material_initial_print_temperature = =material_print_temperature - 10
material_print_temperature = =default_material_print_temperature material_print_temperature = =default_material_print_temperature
material_print_temperature_layer_0 = =default_material_print_temperature material_print_temperature_layer_0 = =material_print_temperature
retraction_count_max = 12
retraction_extra_prime_amount = 0.8
skin_overlap = 15
speed_equalize_flow_enabled = True
speed_layer_0 = 18
speed_print = 25
speed_topbottom = =math.ceil(speed_print * 25 / 25)
speed_travel = 300
speed_wall = =math.ceil(speed_print * 25 / 25)
speed_wall_0 = =math.ceil(speed_wall * 25 / 25)
support_angle = 50
support_bottom_distance = =support_z_distance / 2
top_bottom_thickness = 0.7
wall_line_width_x = =line_width
wall_thickness = 0.76

View file

@ -11,6 +11,9 @@ type = variant
machine_nozzle_size = 0.25 machine_nozzle_size = 0.25
machine_nozzle_tip_outer_diameter = 1.05 machine_nozzle_tip_outer_diameter = 1.05
infill_line_width = 0.3
wall_thickness = 1
wall_0_inset = -0.05 wall_0_inset = -0.05
fill_perimeter_gaps = nowhere fill_perimeter_gaps = nowhere
travel_compensate_overlapping_walls_enabled = travel_compensate_overlapping_walls_enabled =
@ -43,6 +46,7 @@ speed_support_interface = =round(speed_topbottom)
retraction_combing = off retraction_combing = off
retraction_hop_enabled = true retraction_hop_enabled = true
retraction_hop = 1
support_z_distance = 0 support_z_distance = 0
support_xy_distance = 0.5 support_xy_distance = 0.5

View file

@ -12,6 +12,9 @@ type = variant
machine_nozzle_size = 0.4 machine_nozzle_size = 0.4
machine_nozzle_tip_outer_diameter = 0.8 machine_nozzle_tip_outer_diameter = 0.8
infill_line_width = 0.5
wall_thickness = 1.2
wall_0_inset = -0.05 wall_0_inset = -0.05
fill_perimeter_gaps = nowhere fill_perimeter_gaps = nowhere
travel_compensate_overlapping_walls_enabled = travel_compensate_overlapping_walls_enabled =
@ -20,7 +23,6 @@ infill_sparse_density = 25
infill_overlap = -50 infill_overlap = -50
skin_overlap = -40 skin_overlap = -40
material_print_temperature_layer_0 = =round(material_print_temperature) material_print_temperature_layer_0 = =round(material_print_temperature)
material_initial_print_temperature = =round(material_print_temperature) material_initial_print_temperature = =round(material_print_temperature)
material_diameter = 1.75 material_diameter = 1.75
@ -44,6 +46,7 @@ speed_support_interface = =round(speed_topbottom)
retraction_combing = off retraction_combing = off
retraction_hop_enabled = true retraction_hop_enabled = true
retraction_hop = 1
support_z_distance = 0 support_z_distance = 0
support_xy_distance = 0.5 support_xy_distance = 0.5

View file

@ -11,18 +11,22 @@ type = variant
machine_nozzle_size = 0.8 machine_nozzle_size = 0.8
machine_nozzle_tip_outer_diameter = 1.05 machine_nozzle_tip_outer_diameter = 1.05
infill_line_width = 0.9
wall_thickness = 2.4
top_bottom_thickness = =0.8 if layer_height < 0.3 else (layer_height * 3)
wall_0_inset = -0.05 wall_0_inset = -0.05
fill_perimeter_gaps = nowhere fill_perimeter_gaps = nowhere
travel_compensate_overlapping_walls_enabled = travel_compensate_overlapping_walls_enabled =
infill_sparse_density = 25 infill_sparse_density = 15
infill_overlap = -50 infill_overlap = -50
skin_overlap = -40 skin_overlap = -40
material_print_temperature_layer_0 = =round(material_print_temperature) material_print_temperature_layer_0 = =round(material_print_temperature)
material_initial_print_temperature = =round(material_print_temperature) material_initial_print_temperature = =round(material_print_temperature)
material_diameter = 1.75 material_diameter = 1.75
retraction_amount = 2 retraction_amount = 1.5
retraction_speed = 40 retraction_speed = 40
retraction_prime_speed = =round(retraction_speed / 4) retraction_prime_speed = =round(retraction_speed / 4)
retraction_min_travel = =round(line_width * 10) retraction_min_travel = =round(line_width * 10)
@ -43,6 +47,7 @@ speed_support_interface = =round(speed_topbottom)
retraction_combing = off retraction_combing = off
retraction_hop_enabled = true retraction_hop_enabled = true
retraction_hop = 1
support_z_distance = 0 support_z_distance = 0
support_xy_distance = 0.5 support_xy_distance = 0.5