JSOn fix: spaghetti infill enabled function bug (CURA-3238)

This commit is contained in:
Tim Kuipers 2017-03-13 16:22:21 +01:00
commit fe56c105e9
76 changed files with 2219 additions and 869 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)
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_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.
* [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.
* [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
----------------------------------

12
cura/BuildVolume.py Normal file → Executable file
View File

@ -385,15 +385,19 @@ class BuildVolume(SceneNode):
self.setPosition(Vector(0, -self._raft_thickness, 0), SceneNode.TransformSpace.World)
self.raftThicknessChanged.emit()
def _updateExtraZClearance(self):
extra_z = None
def _updateExtraZClearance(self) -> None:
extra_z = 0.0
extruders = ExtruderManager.getInstance().getMachineExtruders(self._global_container_stack.getId())
use_extruders = False
for extruder in extruders:
if extruder.getProperty("retraction_hop_enabled", "value"):
retraction_hop = extruder.getProperty("retraction_hop", "value")
if extra_z is None or retraction_hop > extra_z:
extra_z = retraction_hop
if extra_z is None:
use_extruders = True
if not use_extruders:
# If no extruders, take global 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:
self._extra_z_clearance = extra_z
@ -890,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"]
_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"]
_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"]

View File

@ -253,14 +253,12 @@ class ConvexHullDecorator(SceneNodeDecorator):
## Offset the convex hull with settings that influence the collision area.
#
# This also applies a minimum offset of 0.5mm, because of edge cases due
# to the rounding we apply.
#
# \param convex_hull Polygon of the original convex hull.
# \return New Polygon instance that is offset with everything that
# influences the collision area.
def _offsetHull(self, convex_hull):
horizontal_expansion = max(0.5, self._getSettingProperty("xy_offset", "value"))
horizontal_expansion = self._getSettingProperty("xy_offset", "value")
if horizontal_expansion != 0:
expansion_polygon = Polygon(numpy.array([
[-horizontal_expansion, -horizontal_expansion],
[-horizontal_expansion, horizontal_expansion],
@ -268,6 +266,8 @@ class ConvexHullDecorator(SceneNodeDecorator):
[horizontal_expansion, -horizontal_expansion]
], numpy.float32))
return convex_hull.getMinkowskiHull(expansion_polygon)
else:
return convex_hull
def _onChanged(self, *args):
self._raft_thickness = self._build_volume.getRaftThickness()

65
cura/CuraApplication.py Normal file → Executable file
View File

@ -55,7 +55,7 @@ from . import MachineActionManager
from cura.Settings.MachineManager import MachineManager
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.ContainerSettingsModel import ContainerSettingsModel
from cura.Settings.MaterialSettingsVisibilityHandler import MaterialSettingsVisibilityHandler
@ -126,6 +126,8 @@ class CuraApplication(QtApplication):
SettingDefinition.addSettingType("extruder", None, str, Validator)
SettingDefinition.addSettingType("[int]", None, str, None)
SettingFunction.registerOperator("extruderValues", ExtruderManager.getExtruderValues)
SettingFunction.registerOperator("extruderValue", ExtruderManager.getExtruderValue)
SettingFunction.registerOperator("resolveOrValue", ExtruderManager.getResolveOrValue)
@ -243,6 +245,7 @@ class CuraApplication(QtApplication):
Preferences.getInstance().addPreference("mesh/scale_tiny_meshes", True)
Preferences.getInstance().addPreference("cura/dialog_on_project_save", True)
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/material_settings", "{}")
@ -325,11 +328,35 @@ class CuraApplication(QtApplication):
## A reusable dialogbox
#
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 = []):
self._message_box_callback = callback
self._message_box_callback_arguments = callback_arguments
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)
def messageBoxClosed(self, button):
if self._message_box_callback:
@ -339,11 +366,6 @@ class CuraApplication(QtApplication):
showPrintMonitor = pyqtSignal(bool, arguments = ["show"])
def setViewLegendItems(self, items):
self.viewLegendItemsChanged.emit(items)
viewLegendItemsChanged = pyqtSignal("QVariantList", arguments = ["items"])
## Cura has multiple locations where instance containers need to be saved, so we need to handle this differently.
#
# Note that the AutoSave plugin also calls this method.
@ -655,6 +677,7 @@ class CuraApplication(QtApplication):
qmlRegisterType(MaterialSettingsVisibilityHandler, "Cura", 1, 0, "MaterialSettingsVisibilityHandler")
qmlRegisterType(QualitySettingsModel, "Cura", 1, 0, "QualitySettingsModel")
qmlRegisterType(MachineNameValidator, "Cura", 1, 0, "MachineNameValidator")
qmlRegisterType(UserChangesModel, "Cura", 1, 1, "UserChangesModel")
qmlRegisterSingletonType(ContainerManager, "Cura", 1, 0, "ContainerManager", ContainerManager.createContainerManager)
@ -1078,18 +1101,6 @@ class CuraApplication(QtApplication):
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):
if type(job) is not ReadMeshJob or not job.getResult():
return
@ -1117,10 +1128,8 @@ class CuraApplication(QtApplication):
else:
Logger.log("w", "Could not find a mesh in reloaded node.")
def _openFile(self, file):
job = ReadMeshJob(os.path.abspath(file))
job.finished.connect(self._onFileLoaded)
job.start()
def _openFile(self, filename):
self.readLocalFile(QUrl.fromLocalFile(filename))
def _addProfileReader(self, profile_reader):
# TODO: Add the profile reader to the list of plug-ins that can be used when importing profiles.
@ -1232,15 +1241,3 @@ class CuraApplication(QtApplication):
def addNonSliceableExtension(self, extension):
self._non_sliceable_extensions.append(extension)
@pyqtSlot("QVector3D")
def testQVector3D(self, vect):
Logger.log("d", "got QVector3D: %s : %s %s %s" % (vect, vect.x(), vect.y(), vect.z()))
@pyqtProperty("QVector3D")
def getQVector3D(self):
from PyQt5.QtGui import QVector3D
vect = QVector3D(1.0, 2.0, 3.0)
Logger.log("d", "get QVector3D: %s" % vect)
return vect

View File

@ -3,4 +3,4 @@
CuraVersion = "@CURA_VERSION@"
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)
colors = numpy.empty((vertex_count, 4), numpy.float32)
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)
vertex_offset = 0

View File

@ -105,7 +105,7 @@ class MachineActionManager(QObject):
if definition_id in self._supported_actions:
return list(self._supported_actions[definition_id])
else:
return set()
return list()
## Get all actions required by given machine
# \param definition_id The ID of the definition you want the required actions of

View File

@ -177,7 +177,7 @@ class PrintInformation(QObject):
self._active_material_container = active_material_containers[0]
self._active_material_container.metaDataChanged.connect(self._onMaterialMetaDataChanged)
def _onMaterialMetaDataChanged(self):
def _onMaterialMetaDataChanged(self, *args, **kwargs):
self._calculateInformation()
@pyqtSlot(str)

View File

@ -47,8 +47,8 @@ class PrinterOutputDevice(QObject, OutputDevice):
self._job_name = ""
self._error_text = ""
self._accepts_commands = True
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_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.setSingleShot(True)
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.
@pyqtProperty(str, notify = preheatBedRemainingTimeChanged)
def preheatBedRemainingTime(self):
if not self._preheat_bed_timer.isActive():
return ""
period = self._preheat_bed_timer.remainingTime()
if period <= 0:
return ""
minutes, period = divmod(period, 60000) #60000 milliseconds in a minute.
seconds, _ = divmod(period, 1000) #1000 milliseconds in a second.
if minutes <= 0 and seconds <= 0:
return ""
return "%d:%02d" % (minutes, seconds)
## Time the print has been printing.

View File

@ -823,7 +823,7 @@ class ContainerManager(QObject):
#
# \param QVariant<QUrl>, essentially a list with QUrl objects.
# \return Dict with keys status, text
@pyqtSlot(QVariant, result="QVariantMap")
@pyqtSlot("QVariantList", result="QVariantMap")
def importProfiles(self, file_urls):
status = "ok"
results = {"ok": [], "error": []}
@ -856,7 +856,7 @@ class ContainerManager(QObject):
return self._container_registry.importProfile(path)
@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():
return
path = file_url.toLocalFile()

View File

@ -939,48 +939,7 @@ class MachineManager(QObject):
container.nameChanged.connect(self._onQualityNameChanged)
def _askUserToKeepOrClearCurrentSettings(self):
# Ask the user if the user profile should be cleared or not (discarding the current settings)
# 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()
Application.getInstance().discardOrKeepProfileChanges()
@pyqtProperty(str, notify = activeVariantChanged)
def activeVariantName(self):

View File

@ -0,0 +1,122 @@
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
from collections import OrderedDict
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):
item_dict = OrderedDict()
item_list = []
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()
if category_label not in item_dict:
item_dict[category_label] = []
item_dict[category_label].append(item_to_add)
for each_item_list in item_dict.values():
item_list += each_item_list
self.setItems(item_list)

View File

@ -17,6 +17,12 @@ if Platform.isLinux(): # Needed for platform.linux_distribution, which is not av
libGL = find_library("GL")
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
# It looks like setuptools creates a .pth file in
# 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
MYPY = False
import Savitar
import numpy
try:
if not MYPY:
import xml.etree.cElementTree as ET
@ -38,98 +42,10 @@ class ThreeMFReader(MeshReader):
self._base_name = ""
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):
if transformation == "":
return Matrix()
splitted_transformation = transformation.split()
## Transformation is saved as:
## M00 M01 M02 0.0
@ -156,51 +72,103 @@ class ThreeMFReader(MeshReader):
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():
child_node = self._convertSavitarNodeToUMNode(child)
if child_node:
um_node.addChild(child_node)
if um_node.getMeshData() is None and len(um_node.getChildren()) == 0:
return None
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):
result = []
# The base object of 3mf is a zipped archive.
try:
archive = zipfile.ZipFile(file_name, "r")
self._base_name = os.path.basename(file_name)
try:
self._root = ET.parse(archive.open("3D/3dmodel.model"))
self._unit = self._root.getroot().get("unit")
build_items = self._root.findall("./3mf:build/3mf:item", self._namespaces)
for build_item in build_items:
id = build_item.get("objectid")
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"])
parser = Savitar.ThreeMFParser()
scene_3mf = parser.parse(archive.open("3D/3dmodel.model").read())
self._unit = scene_3mf.getUnit()
for node in scene_3mf.getSceneNodes():
um_node = self._convertSavitarNodeToUMNode(node)
if um_node is None:
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
transform_matrix = Matrix()
mesh_data = build_item_node.getMeshData()
mesh_data = um_node.getMeshData()
if mesh_data is not None:
extents = mesh_data.getExtents()
center_vector = Vector(extents.center.x, extents.center.y, extents.center.z)
transform_matrix.setByTranslation(center_vector)
# offset with transform from 3mf
transform = build_item.get("transform")
if transform is not None:
transform_matrix.multiply(self._createMatrixFromTransformationString(transform))
build_item_node.setTransformation(transform_matrix)
transform_matrix.multiply(um_node.getLocalTransformation())
um_node.setTransformation(transform_matrix)
global_container_stack = Application.getInstance().getGlobalContainerStack()
@ -215,9 +183,9 @@ class ThreeMFReader(MeshReader):
# Second step: 3MF defines the left corner of the machine as center, whereas cura uses the center of the
# build volume.
if global_container_stack:
translation_vector = Vector(x = -global_container_stack.getProperty("machine_width", "value") / 2,
y = -global_container_stack.getProperty("machine_depth", "value") / 2,
z = 0)
translation_vector = Vector(x=-global_container_stack.getProperty("machine_width", "value") / 2,
y=-global_container_stack.getProperty("machine_depth", "value") / 2,
z=0)
translation_matrix = Matrix()
translation_matrix.setByTranslation(translation_vector)
transformation_matrix.multiply(translation_matrix)
@ -228,12 +196,13 @@ class ThreeMFReader(MeshReader):
transformation_matrix.multiply(scale_matrix)
# 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:
Logger.log("e", "An exception occurred in 3mf reader: %s", e)
except Exception:
Logger.logException("e", "An exception occurred in 3mf reader.")
return []
return result

View File

@ -476,7 +476,9 @@ class ThreeMFWorkspaceReader(WorkspaceReader):
return nodes
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):
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.Math.Matrix import Matrix
from UM.Application import Application
import UM.Scene.SceneNode
import Savitar
import numpy
MYPY = False
try:
@ -35,18 +40,18 @@ class ThreeMFWriter(MeshWriter):
def _convertMatrixToString(self, matrix):
result = ""
result += str(matrix._data[0,0]) + " "
result += str(matrix._data[1,0]) + " "
result += str(matrix._data[2,0]) + " "
result += str(matrix._data[0,1]) + " "
result += str(matrix._data[1,1]) + " "
result += str(matrix._data[2,1]) + " "
result += str(matrix._data[0,2]) + " "
result += str(matrix._data[1,2]) + " "
result += str(matrix._data[2,2]) + " "
result += str(matrix._data[0,3]) + " "
result += str(matrix._data[1,3]) + " "
result += str(matrix._data[2,3])
result += str(matrix._data[0, 0]) + " "
result += str(matrix._data[1, 0]) + " "
result += str(matrix._data[2, 0]) + " "
result += str(matrix._data[0, 1]) + " "
result += str(matrix._data[1, 1]) + " "
result += str(matrix._data[2, 1]) + " "
result += str(matrix._data[0, 2]) + " "
result += str(matrix._data[1, 2]) + " "
result += str(matrix._data[2, 2]) + " "
result += str(matrix._data[0, 3]) + " "
result += str(matrix._data[1, 3]) + " "
result += str(matrix._data[2, 3])
return result
## Should we store the archive
@ -55,6 +60,48 @@ class ThreeMFWriter(MeshWriter):
def setStoreArchive(self, 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):
return self._archive
@ -79,98 +126,7 @@ class ThreeMFWriter(MeshWriter):
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 = ET.Element("model", unit = "millimeter", xmlns = self._namespaces["3mf"])
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.
savitar_scene = Savitar.Scene()
transformation_matrix = Matrix()
transformation_matrix._data[1, 1] = 0
transformation_matrix._data[1, 2] = -1
@ -188,14 +144,22 @@ class ThreeMFWriter(MeshWriter):
translation_matrix.setByTranslation(translation_vector)
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()
root_node = UM.Application.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)
ET.SubElement(build, "item", objectid = str(added_nodes.index(node) + 1), transform = self._convertMatrixToString(node_matrix.preMultiply(transformation_matrix)))
parser = Savitar.ThreeMFParser()
scene_string = parser.sceneToString(savitar_scene)
archive.writestr(model_file, b'<?xml version="1.0" encoding="UTF-8"?> \n' + ET.tostring(model))
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(relations_file, b'<?xml version="1.0" encoding="UTF-8"?> \n' + ET.tostring(relations_element))
except Exception as e:

6
plugins/ChangeLogPlugin/ChangeLog.txt Normal file → Executable file
View File

@ -1,5 +1,9 @@
[2.5.0]
*Included PauseBackendPlugin. This enables pausing the backend and manually start the backend. Thanks to community member Aldo Hoeben for this feature.
*Layerview double slider.
The layerview now has a nice slider with double handles where you can drag maximum layer, minimum layer and the layer range. Thansk to community member Aldo Hoeben for this feature.
*Included PauseBackendPlugin.
This enables pausing the backend and manually start the backend. Thanks to community member Aldo Hoeben for this feature.
[2.4.0]
*Project saving & opening

33
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._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.backendConnected.connect(self._onBackendConnected)
@ -340,23 +342,34 @@ class CuraEngineBackend(QObject, Backend):
#
# \param source The scene node that was changed.
def _onSceneChanged(self, source):
if self._tool_active:
return
if type(source) is not SceneNode:
return
if source is self._scene.getRoot():
root_scene_nodes_changed = False
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 self._tool_active:
# do it later, each source only has to be done once
if source not in self._postponed_scene_change_sources:
self._postponed_scene_change_sources.append(source)
return
self.needsSlicing()
self.stopSlicing()
self._onChanged()
@ -501,7 +514,11 @@ class CuraEngineBackend(QObject, Backend):
# \param tool The tool that the user was using.
def _onToolOperationStopped(self, tool):
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.
def _onActiveViewChanged(self):

8
plugins/LayerView/LayerPass.py Normal file → Executable file
View File

@ -97,11 +97,11 @@ class LayerPass(RenderPass):
# Create a new batch that is not range-limited
batch = RenderBatch(self._layer_shader, type = RenderBatch.RenderType.Solid)
if self._layer_view._current_layer_mesh:
batch.addItem(node.getWorldTransformation(), self._layer_view._current_layer_mesh)
if self._layer_view.getCurrentLayerMesh():
batch.addItem(node.getWorldTransformation(), self._layer_view.getCurrentLayerMesh())
if self._layer_view._current_layer_jumps:
batch.addItem(node.getWorldTransformation(), self._layer_view._current_layer_jumps)
if self._layer_view.getCurrentLayerJumps():
batch.addItem(node.getWorldTransformation(), self._layer_view.getCurrentLayerJumps())
if len(batch.items) > 0:
batch.render(self._scene.getActiveCamera())

70
plugins/LayerView/LayerView.py Normal file → Executable file
View File

@ -67,16 +67,14 @@ class LayerView(View):
self._resetSettings()
self._legend_items = None
self._show_travel_moves = False
Preferences.getInstance().addPreference("view/top_layer_count", 5)
Preferences.getInstance().addPreference("view/only_show_top_layers", False)
Preferences.getInstance().addPreference("view/force_layer_view_compatibility_mode", False)
Preferences.getInstance().addPreference("layerview/layer_view_type", 0)
Preferences.getInstance().addPreference("layerview/extruder0_opacity", 1.0)
Preferences.getInstance().addPreference("layerview/extruder1_opacity", 1.0)
Preferences.getInstance().addPreference("layerview/extruder2_opacity", 1.0)
Preferences.getInstance().addPreference("layerview/extruder3_opacity", 1.0)
Preferences.getInstance().addPreference("layerview/extruder_opacities", "")
Preferences.getInstance().addPreference("layerview/show_travel_moves", False)
Preferences.getInstance().addPreference("layerview/show_helpers", True)
@ -165,6 +163,8 @@ class LayerView(View):
self._current_layer_num = 0
if self._current_layer_num > self._max_layers:
self._current_layer_num = self._max_layers
if self._current_layer_num < self._minimum_layer_num:
self._minimum_layer_num = self._current_layer_num
self._startUpdateTopLayers()
@ -175,6 +175,10 @@ class LayerView(View):
self._minimum_layer_num = value
if self._minimum_layer_num < 0:
self._minimum_layer_num = 0
if self._minimum_layer_num > self._max_layers:
self._minimum_layer_num = self._max_layers
if self._minimum_layer_num > self._current_layer_num:
self._current_layer_num = self._minimum_layer_num
self._startUpdateTopLayers()
@ -196,6 +200,7 @@ class LayerView(View):
# \param extruder_nr 0..3
# \param opacity 0.0 .. 1.0
def setExtruderOpacity(self, extruder_nr, opacity):
if 0 <= extruder_nr <= 3:
self._extruder_opacity[extruder_nr] = opacity
self.currentLayerNumChanged.emit()
@ -278,21 +283,17 @@ class LayerView(View):
def endRendering(self):
pass
def enableLegend(self):
Application.getInstance().setViewLegendItems(self._getLegendItems())
def disableLegend(self):
Application.getInstance().setViewLegendItems([])
def event(self, event):
modifiers = QApplication.keyboardModifiers()
ctrl_is_active = modifiers == Qt.ControlModifier
ctrl_is_active = modifiers & Qt.ControlModifier
shift_is_active = modifiers & Qt.ShiftModifier
if event.type == Event.KeyPressEvent and ctrl_is_active:
amount = 10 if shift_is_active else 1
if event.key == KeyEvent.UpKey:
self.setLayer(self._current_layer_num + 1)
self.setLayer(self._current_layer_num + amount)
return True
if event.key == KeyEvent.DownKey:
self.setLayer(self._current_layer_num - 1)
self.setLayer(self._current_layer_num - amount)
return True
if event.type == Event.ViewActivateEvent:
@ -316,9 +317,6 @@ class LayerView(View):
self._old_composite_shader = self._composite_pass.getCompositeShader()
self._composite_pass.setCompositeShader(self._layerview_composite_shader)
if self.getLayerViewType() == self.LAYER_VIEW_TYPE_LINE_TYPE or self._compatibility_mode:
self.enableLegend()
elif event.type == Event.ViewDeactivateEvent:
self._wireprint_warning_message.hide()
Application.getInstance().globalContainerStackChanged.disconnect(self._onGlobalStackChanged)
@ -328,7 +326,11 @@ class LayerView(View):
self._composite_pass.setLayerBindings(self._old_layer_bindings)
self._composite_pass.setCompositeShader(self._old_composite_shader)
self.disableLegend()
def getCurrentLayerMesh(self):
return self._current_layer_mesh
def getCurrentLayerJumps(self):
return self._current_layer_jumps
def _onGlobalStackChanged(self):
if self._global_container_stack:
@ -370,6 +372,7 @@ class LayerView(View):
return
self.resetLayerData() # Reset the layer data only when job is done. Doing it now prevents "blinking" data.
self._current_layer_mesh = job.getResult().get("layers")
if self._show_travel_moves:
self._current_layer_jumps = job.getResult().get("jumps")
self._controller.getScene().sceneChanged.emit(self._controller.getScene().getRoot())
@ -383,10 +386,12 @@ class LayerView(View):
self.setLayerViewType(int(float(Preferences.getInstance().getValue("layerview/layer_view_type"))));
self.setExtruderOpacity(0, float(Preferences.getInstance().getValue("layerview/extruder0_opacity")))
self.setExtruderOpacity(1, float(Preferences.getInstance().getValue("layerview/extruder1_opacity")))
self.setExtruderOpacity(2, float(Preferences.getInstance().getValue("layerview/extruder2_opacity")))
self.setExtruderOpacity(3, float(Preferences.getInstance().getValue("layerview/extruder3_opacity")))
for extruder_nr, extruder_opacity in enumerate(Preferences.getInstance().getValue("layerview/extruder_opacities").split("|")):
try:
opacity = float(extruder_opacity)
except ValueError:
opacity = 1.0
self.setExtruderOpacity(extruder_nr, opacity)
self.setShowTravelMoves(bool(Preferences.getInstance().getValue("layerview/show_travel_moves")))
self.setShowHelpers(bool(Preferences.getInstance().getValue("layerview/show_helpers")))
@ -402,10 +407,7 @@ class LayerView(View):
"view/only_show_top_layers",
"view/force_layer_view_compatibility_mode",
"layerview/layer_view_type",
"layerview/extruder0_opacity",
"layerview/extruder1_opacity",
"layerview/extruder2_opacity",
"layerview/extruder3_opacity",
"layerview/extruder_opacities",
"layerview/show_travel_moves",
"layerview/show_helpers",
"layerview/show_skin",
@ -415,24 +417,6 @@ class LayerView(View):
self._updateWithPreferences()
def _getLegendItems(self):
if self._legend_items is None:
theme = Application.getInstance().getTheme()
self._legend_items = [
{"color": theme.getColor("layerview_inset_0").name(), "title": catalog.i18nc("@label:layerview polygon type", "Outer Wall")}, # Inset0Type
{"color": theme.getColor("layerview_inset_x").name(), "title": catalog.i18nc("@label:layerview polygon type", "Inner Wall")}, # InsetXType
{"color": theme.getColor("layerview_skin").name(), "title": catalog.i18nc("@label:layerview polygon type", "Top / Bottom")}, # SkinType
{"color": theme.getColor("layerview_infill").name(), "title": catalog.i18nc("@label:layerview polygon type", "Infill")}, # InfillType
{"color": theme.getColor("layerview_support").name(), "title": catalog.i18nc("@label:layerview polygon type", "Support Skin")}, # SupportType
{"color": theme.getColor("layerview_support_infill").name(), "title": catalog.i18nc("@label:layerview polygon type", "Support Infill")}, # SupportInfillType
{"color": theme.getColor("layerview_support_interface").name(), "title": catalog.i18nc("@label:layerview polygon type", "Support Interface")}, # SupportInterfaceType
{"color": theme.getColor("layerview_skirt").name(), "title": catalog.i18nc("@label:layerview polygon type", "Build Plate Adhesion")}, # SkirtType
{"color": theme.getColor("layerview_move_combing").name(), "title": catalog.i18nc("@label:layerview polygon type", "Travel Move")}, # MoveCombingType
{"color": theme.getColor("layerview_move_retraction").name(), "title": catalog.i18nc("@label:layerview polygon type", "Retraction Move")}, # MoveRetractionType
#{"color": theme.getColor("layerview_none").name(), "title": catalog.i18nc("@label:layerview polygon type", "Unknown")} # NoneType
]
return self._legend_items
class _CreateTopLayersJob(Job):
def __init__(self, scene, layer_number, solid_layers):

View File

@ -10,78 +10,567 @@ import UM 1.0 as UM
Item
{
width: UM.Theme.getSize("button").width
height: UM.Theme.getSize("slider_layerview_size").height
width: {
if (UM.LayerView.compatibilityMode) {
return UM.Theme.getSize("layerview_menu_size_compatibility").width;
} else {
return UM.Theme.getSize("layerview_menu_size").width;
}
}
height: {
if (UM.LayerView.compatibilityMode) {
return UM.Theme.getSize("layerview_menu_size_compatibility").height;
} else {
return UM.Theme.getSize("layerview_menu_size").height + UM.LayerView.extruderCount * (UM.Theme.getSize("layerview_row").height + UM.Theme.getSize("layerview_row_spacing").height)
}
}
Slider
{
id: sliderMinimumLayer
width: UM.Theme.getSize("slider_layerview_size").width
height: UM.Theme.getSize("slider_layerview_size").height
Rectangle {
id: layerViewMenu
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("slider_layerview_margin").width * 0.2
orientation: Qt.Vertical
minimumValue: 0;
maximumValue: UM.LayerView.numLayers-1;
stepSize: 1
anchors.top: parent.top
width: parent.width
height: parent.height
z: slider.z - 1
color: UM.Theme.getColor("tool_panel_background")
property real pixelsPerStep: ((height - UM.Theme.getSize("slider_handle").height) / (maximumValue - minimumValue)) * stepSize;
ColumnLayout {
id: view_settings
value: UM.LayerView.minimumLayer
onValueChanged: {
UM.LayerView.setMinimumLayer(value)
if (value > UM.LayerView.currentLayer) {
UM.LayerView.setCurrentLayer(value);
property var extruder_opacities: UM.Preferences.getValue("layerview/extruder_opacities").split("|")
property bool show_travel_moves: UM.Preferences.getValue("layerview/show_travel_moves")
property bool show_helpers: UM.Preferences.getValue("layerview/show_helpers")
property bool show_skin: UM.Preferences.getValue("layerview/show_skin")
property bool show_infill: UM.Preferences.getValue("layerview/show_infill")
property bool show_legend: UM.LayerView.compatibilityMode || UM.Preferences.getValue("layerview/layer_view_type") == 1
property bool only_show_top_layers: UM.Preferences.getValue("view/only_show_top_layers")
property int top_layer_count: UM.Preferences.getValue("view/top_layer_count")
anchors.top: parent.top
anchors.topMargin: UM.Theme.getSize("default_margin").height
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_margin").width
spacing: UM.Theme.getSize("layerview_row_spacing").height
Label
{
id: layersLabel
anchors.left: parent.left
text: catalog.i18nc("@label","View Mode: Layers")
font.bold: true
}
Label
{
id: spaceLabel
anchors.left: parent.left
text: " "
font.pointSize: 0.5
}
Label
{
id: layerViewTypesLabel
anchors.left: parent.left
text: catalog.i18nc("@label","Color scheme")
visible: !UM.LayerView.compatibilityMode
Layout.fillWidth: true
}
ListModel // matches LayerView.py
{
id: layerViewTypes
}
Component.onCompleted:
{
layerViewTypes.append({
text: catalog.i18nc("@label:listbox", "Material Color"),
type_id: 0
})
layerViewTypes.append({
text: catalog.i18nc("@label:listbox", "Line Type"),
type_id: 1 // these ids match the switching in the shader
})
}
ComboBox
{
id: layerTypeCombobox
anchors.left: parent.left
Layout.fillWidth: true
Layout.preferredWidth: UM.Theme.getSize("layerview_row").width
model: layerViewTypes
visible: !UM.LayerView.compatibilityMode
property int layer_view_type: UM.Preferences.getValue("layerview/layer_view_type")
currentIndex: layer_view_type // index matches type_id
onActivated: {
// Combobox selection
var type_id = index;
UM.Preferences.setValue("layerview/layer_view_type", type_id);
updateLegend(type_id);
}
onModelChanged: {
updateLegend(UM.Preferences.getValue("layerview/layer_view_type"));
}
// Update visibility of legend.
function updateLegend(type_id) {
if (UM.LayerView.compatibilityMode || (type_id == 1)) {
// Line type
view_settings.show_legend = true;
} else {
view_settings.show_legend = false;
}
}
}
style: UM.Theme.styles.slider;
Label
{
id: compatibilityModeLabel
anchors.left: parent.left
text: catalog.i18nc("@label","Compatibility Mode")
visible: UM.LayerView.compatibilityMode
Layout.fillWidth: true
Layout.preferredHeight: UM.Theme.getSize("layerview_row").height
Layout.preferredWidth: UM.Theme.getSize("layerview_row").width
}
Slider
Label
{
id: space2Label
anchors.left: parent.left
text: " "
font.pointSize: 0.5
}
Connections {
target: UM.Preferences
onPreferenceChanged:
{
layerTypeCombobox.layer_view_type = UM.Preferences.getValue("layerview/layer_view_type");
view_settings.extruder_opacities = UM.Preferences.getValue("layerview/extruder_opacities").split("|");
view_settings.show_travel_moves = UM.Preferences.getValue("layerview/show_travel_moves");
view_settings.show_helpers = UM.Preferences.getValue("layerview/show_helpers");
view_settings.show_skin = UM.Preferences.getValue("layerview/show_skin");
view_settings.show_infill = UM.Preferences.getValue("layerview/show_infill");
view_settings.only_show_top_layers = UM.Preferences.getValue("view/only_show_top_layers");
view_settings.top_layer_count = UM.Preferences.getValue("view/top_layer_count");
}
}
Repeater {
model: UM.LayerView.extruderCount
CheckBox {
checked: view_settings.extruder_opacities[index] > 0.5 || view_settings.extruder_opacities[index] == undefined || view_settings.extruder_opacities[index] == ""
onClicked: {
view_settings.extruder_opacities[index] = checked ? 1.0 : 0.0
UM.Preferences.setValue("layerview/extruder_opacities", view_settings.extruder_opacities.join("|"));
}
text: catalog.i18nc("@label", "Extruder %1").arg(index + 1)
visible: !UM.LayerView.compatibilityMode
enabled: index + 1 <= 4
Layout.fillWidth: true
Layout.preferredHeight: UM.Theme.getSize("layerview_row").height
Layout.preferredWidth: UM.Theme.getSize("layerview_row").width
}
}
CheckBox {
checked: view_settings.show_travel_moves
onClicked: {
UM.Preferences.setValue("layerview/show_travel_moves", checked);
}
text: catalog.i18nc("@label", "Show Travels")
Rectangle {
anchors.top: parent.top
anchors.topMargin: 2
anchors.right: parent.right
width: UM.Theme.getSize("layerview_legend_size").width
height: UM.Theme.getSize("layerview_legend_size").height
color: UM.Theme.getColor("layerview_move_combing")
border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("lining")
visible: view_settings.show_legend
}
Layout.fillWidth: true
Layout.preferredHeight: UM.Theme.getSize("layerview_row").height
Layout.preferredWidth: UM.Theme.getSize("layerview_row").width
}
CheckBox {
checked: view_settings.show_helpers
onClicked: {
UM.Preferences.setValue("layerview/show_helpers", checked);
}
text: catalog.i18nc("@label", "Show Helpers")
Rectangle {
anchors.top: parent.top
anchors.topMargin: 2
anchors.right: parent.right
width: UM.Theme.getSize("layerview_legend_size").width
height: UM.Theme.getSize("layerview_legend_size").height
color: UM.Theme.getColor("layerview_support")
border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("lining")
visible: view_settings.show_legend
}
Layout.fillWidth: true
Layout.preferredHeight: UM.Theme.getSize("layerview_row").height
Layout.preferredWidth: UM.Theme.getSize("layerview_row").width
}
CheckBox {
checked: view_settings.show_skin
onClicked: {
UM.Preferences.setValue("layerview/show_skin", checked);
}
text: catalog.i18nc("@label", "Show Shell")
Rectangle {
anchors.top: parent.top
anchors.topMargin: 2
anchors.right: parent.right
width: UM.Theme.getSize("layerview_legend_size").width
height: UM.Theme.getSize("layerview_legend_size").height
color: UM.Theme.getColor("layerview_inset_0")
border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("lining")
visible: view_settings.show_legend
}
Layout.fillWidth: true
Layout.preferredHeight: UM.Theme.getSize("layerview_row").height
Layout.preferredWidth: UM.Theme.getSize("layerview_row").width
}
CheckBox {
checked: view_settings.show_infill
onClicked: {
UM.Preferences.setValue("layerview/show_infill", checked);
}
text: catalog.i18nc("@label", "Show Infill")
Rectangle {
anchors.top: parent.top
anchors.topMargin: 2
anchors.right: parent.right
width: UM.Theme.getSize("layerview_legend_size").width
height: UM.Theme.getSize("layerview_legend_size").height
color: UM.Theme.getColor("layerview_infill")
border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("lining")
visible: view_settings.show_legend
}
Layout.fillWidth: true
Layout.preferredHeight: UM.Theme.getSize("layerview_row").height
Layout.preferredWidth: UM.Theme.getSize("layerview_row").width
}
CheckBox {
checked: view_settings.only_show_top_layers
onClicked: {
UM.Preferences.setValue("view/only_show_top_layers", checked ? 1.0 : 0.0);
}
text: catalog.i18nc("@label", "Only Show Top Layers")
visible: UM.LayerView.compatibilityMode
}
CheckBox {
checked: view_settings.top_layer_count == 5
onClicked: {
UM.Preferences.setValue("view/top_layer_count", checked ? 5 : 1);
}
text: catalog.i18nc("@label", "Show 5 Detailed Layers On Top")
visible: UM.LayerView.compatibilityMode
}
Label
{
id: topBottomLabel
anchors.left: parent.left
text: catalog.i18nc("@label","Top / Bottom")
Rectangle {
anchors.top: parent.top
anchors.topMargin: 2
anchors.right: parent.right
width: UM.Theme.getSize("layerview_legend_size").width
height: UM.Theme.getSize("layerview_legend_size").height
color: UM.Theme.getColor("layerview_skin")
border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("lining")
}
Layout.fillWidth: true
Layout.preferredHeight: UM.Theme.getSize("layerview_row").height
Layout.preferredWidth: UM.Theme.getSize("layerview_row").width
visible: view_settings.show_legend
}
Label
{
id: innerWallLabel
anchors.left: parent.left
text: catalog.i18nc("@label","Inner Wall")
Rectangle {
anchors.top: parent.top
anchors.topMargin: 2
anchors.right: parent.right
width: UM.Theme.getSize("layerview_legend_size").width
height: UM.Theme.getSize("layerview_legend_size").height
color: UM.Theme.getColor("layerview_inset_x")
border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("lining")
visible: view_settings.show_legend
}
Layout.fillWidth: true
Layout.preferredHeight: UM.Theme.getSize("layerview_row").height
Layout.preferredWidth: UM.Theme.getSize("layerview_row").width
visible: view_settings.show_legend
}
}
Item
{
id: slider
width: UM.Theme.getSize("slider_layerview_size").width
height: UM.Theme.getSize("slider_layerview_size").height
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("slider_layerview_margin").width * 0.8
orientation: Qt.Vertical
minimumValue: 0;
maximumValue: UM.LayerView.numLayers;
stepSize: 1
width: handleSize
height: parent.height - 2*UM.Theme.getSize("slider_layerview_margin").height
anchors.top: parent.top
anchors.topMargin: UM.Theme.getSize("slider_layerview_margin").height
anchors.right: layerViewMenu.right
anchors.rightMargin: UM.Theme.getSize("slider_layerview_margin").width
property real pixelsPerStep: ((height - UM.Theme.getSize("slider_handle").height) / (maximumValue - minimumValue)) * stepSize;
property real handleSize: UM.Theme.getSize("slider_handle").width
property real handleRadius: handleSize / 2
property real minimumRangeHandleSize: UM.Theme.getSize("slider_handle").width / 2
property real trackThickness: UM.Theme.getSize("slider_groove").width
property real trackRadius: trackThickness / 2
property real trackBorderWidth: UM.Theme.getSize("default_lining").width
property color upperHandleColor: UM.Theme.getColor("slider_handle")
property color lowerHandleColor: UM.Theme.getColor("slider_handle")
property color rangeHandleColor: UM.Theme.getColor("slider_groove_fill")
property color trackColor: UM.Theme.getColor("slider_groove")
property color trackBorderColor: UM.Theme.getColor("slider_groove_border")
value: UM.LayerView.currentLayer
onValueChanged: {
property real maximumValue: UM.LayerView.numLayers
property real minimumValue: 0
property real minimumRange: 0
property bool roundValues: true
property var activeHandle: upperHandle
property bool layersVisible: UM.LayerView.layerActivity && Printer.platformActivity ? true : false
function getUpperValueFromHandle()
{
var result = upperHandle.y / (height - (2 * handleSize + minimumRangeHandleSize));
result = maximumValue + result * (minimumValue - (maximumValue - minimumRange));
result = roundValues ? Math.round(result) | 0 : result;
return result;
}
function getLowerValueFromHandle()
{
var result = (lowerHandle.y - (handleSize + minimumRangeHandleSize)) / (height - (2 * handleSize + minimumRangeHandleSize));
result = maximumValue - minimumRange + result * (minimumValue - (maximumValue - minimumRange));
result = roundValues ? Math.round(result) : result;
return result;
}
function setUpperValue(value)
{
var value = (value - maximumValue) / (minimumValue - maximumValue);
var new_upper_y = Math.round(value * (height - (2 * handleSize + minimumRangeHandleSize)));
if(new_upper_y != upperHandle.y)
{
upperHandle.y = new_upper_y;
}
rangeHandle.height = lowerHandle.y - (upperHandle.y + upperHandle.height);
}
function setLowerValue(value)
{
var value = (value - maximumValue) / (minimumValue - maximumValue);
var new_lower_y = Math.round((handleSize + minimumRangeHandleSize) + value * (height - (2 * handleSize + minimumRangeHandleSize)));
if(new_lower_y != lowerHandle.y)
{
lowerHandle.y = new_lower_y;
}
rangeHandle.height = lowerHandle.y - (upperHandle.y + upperHandle.height);
}
Connections
{
target: UM.LayerView
onMinimumLayerChanged: slider.setLowerValue(UM.LayerView.minimumLayer)
onCurrentLayerChanged: slider.setUpperValue(UM.LayerView.currentLayer)
}
Rectangle {
width: parent.trackThickness
height: parent.height - parent.handleSize
radius: parent.trackRadius
anchors.centerIn: parent
color: parent.trackColor
border.width: parent.trackBorderWidth;
border.color: parent.trackBorderColor;
}
Item {
id: rangeHandle
y: upperHandle.y + upperHandle.height
width: parent.handleSize
height: parent.minimumRangeHandleSize
anchors.horizontalCenter: parent.horizontalCenter
visible: slider.layersVisible
property real value: UM.LayerView.currentLayer
function setValue(value)
{
var range = upperHandle.value - lowerHandle.value;
value = Math.min(value, slider.maximumValue);
value = Math.max(value, slider.minimumValue + range);
UM.LayerView.setCurrentLayer(value);
if (value < UM.LayerView.minimumLayer) {
UM.LayerView.setMinimumLayer(value - range);
}
Rectangle {
anchors.centerIn: parent
width: parent.parent.trackThickness - 2 * parent.parent.trackBorderWidth
height: parent.height + parent.parent.handleSize
color: parent.parent.rangeHandleColor
}
MouseArea {
anchors.fill: parent
drag.target: parent
drag.axis: Drag.YAxis
drag.minimumY: upperHandle.height
drag.maximumY: parent.parent.height - (parent.height + lowerHandle.height)
onPressed: parent.parent.activeHandle = rangeHandle
onPositionChanged:
{
upperHandle.y = parent.y - upperHandle.height
lowerHandle.y = parent.y + parent.height
var upper_value = slider.getUpperValueFromHandle();
var lower_value = upper_value - (upperHandle.value - lowerHandle.value);
UM.LayerView.setCurrentLayer(upper_value);
UM.LayerView.setMinimumLayer(lower_value);
}
}
}
Rectangle {
id: upperHandle
y: parent.height - (parent.minimumRangeHandleSize + 2 * parent.handleSize)
width: parent.handleSize
height: parent.handleSize
anchors.horizontalCenter: parent.horizontalCenter
radius: parent.handleRadius
color: parent.upperHandleColor
visible: slider.layersVisible
property real value: UM.LayerView.currentLayer
function setValue(value)
{
UM.LayerView.setCurrentLayer(value);
}
MouseArea {
anchors.fill: parent
drag.target: parent
drag.axis: Drag.YAxis
drag.minimumY: 0
drag.maximumY: parent.parent.height - (2 * parent.parent.handleSize + parent.parent.minimumRangeHandleSize)
onPressed: parent.parent.activeHandle = upperHandle
onPositionChanged:
{
if(lowerHandle.y - (upperHandle.y + upperHandle.height) < parent.parent.minimumRangeHandleSize)
{
lowerHandle.y = upperHandle.y + upperHandle.height + parent.parent.minimumRangeHandleSize;
}
rangeHandle.height = lowerHandle.y - (upperHandle.y + upperHandle.height);
UM.LayerView.setCurrentLayer(slider.getUpperValueFromHandle());
}
}
}
Rectangle {
id: lowerHandle
y: parent.height - parent.handleSize
width: parent.handleSize
height: parent.handleSize
anchors.horizontalCenter: parent.horizontalCenter
radius: parent.handleRadius
color: parent.lowerHandleColor
visible: slider.layersVisible
property real value: UM.LayerView.minimumLayer
function setValue(value)
{
UM.LayerView.setMinimumLayer(value);
}
MouseArea {
anchors.fill: parent
drag.target: parent
drag.axis: Drag.YAxis
drag.minimumY: upperHandle.height + parent.parent.minimumRangeHandleSize
drag.maximumY: parent.parent.height - parent.height
onPressed: parent.parent.activeHandle = lowerHandle
onPositionChanged:
{
if(lowerHandle.y - (upperHandle.y + upperHandle.height) < parent.parent.minimumRangeHandleSize)
{
upperHandle.y = lowerHandle.y - (upperHandle.height + parent.parent.minimumRangeHandleSize);
}
rangeHandle.height = lowerHandle.y - (upperHandle.y + upperHandle.height)
UM.LayerView.setMinimumLayer(slider.getLowerValueFromHandle());
}
}
}
style: UM.Theme.styles.slider;
Rectangle
UM.PointingRectangle
{
x: parent.width + UM.Theme.getSize("slider_layerview_background").width / 2;
y: parent.height - (parent.value * parent.pixelsPerStep) - UM.Theme.getSize("slider_handle").height * 1.25;
y: Math.floor(slider.activeHandle.y + slider.activeHandle.height / 2 - height / 2);
height: UM.Theme.getSize("slider_handle").height + UM.Theme.getSize("default_margin").height
target: Qt.point(0, slider.activeHandle.y + slider.activeHandle.height / 2)
arrowSize: UM.Theme.getSize("default_arrow").width
height: (Math.floor(UM.Theme.getSize("slider_handle").height + UM.Theme.getSize("default_margin").height) / 2) * 2 // Make sure height has an integer middle so drawing a pointy border is easier
width: valueLabel.width + UM.Theme.getSize("default_margin").width
Behavior on height { NumberAnimation { duration: 50; } }
border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("slider_groove_border")
color: UM.Theme.getColor("tool_panel_background")
color: UM.Theme.getColor("lining");
visible: UM.LayerView.layerActivity && Printer.platformActivity ? true : false
visible: slider.layersVisible
UM.PointingRectangle
{
color: UM.Theme.getColor("tool_panel_background")
target: Qt.point(0, height / 2 + UM.Theme.getSize("default_lining").width)
arrowSize: UM.Theme.getSize("default_arrow").width
anchors.fill: parent
anchors.margins: UM.Theme.getSize("default_lining").width
MouseArea //Catch all mouse events (so scene doesnt handle them)
{
anchors.fill: parent
}
}
TextField
{
id: valueLabel
property string maxValue: slider.maximumValue + 1
text: slider.value + 1
text: slider.activeHandle.value + 1
horizontalAlignment: TextInput.AlignRight;
onEditingFinished:
{
@ -91,7 +580,7 @@ Item
cursorPosition = 0;
if(valueLabel.text != '')
{
slider.value = valueLabel.text - 1;
slider.activeHandle.setValue(valueLabel.text - 1);
}
}
validator: IntValidator { bottom: 1; top: slider.maximumValue + 1; }
@ -107,6 +596,9 @@ Item
font: UM.Theme.getFont("default");
background: Item { }
}
Keys.onUpPressed: slider.activeHandle.setValue(slider.activeHandle.value + ((event.modifiers & Qt.ShiftModifier) ? 10 : 1))
Keys.onDownPressed: slider.activeHandle.setValue(slider.activeHandle.value - ((event.modifiers & Qt.ShiftModifier) ? 10 : 1))
}
BusyIndicator
@ -124,198 +616,5 @@ Item
}
}
}
Rectangle {
id: slider_background
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
z: slider.z - 1
width: UM.Theme.getSize("slider_layerview_background").width
height: slider.height + UM.Theme.getSize("default_margin").height * 2
color: UM.Theme.getColor("tool_panel_background");
border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("lining")
MouseArea {
id: sliderMouseArea
property double manualStepSize: slider.maximumValue / 11
anchors.fill: parent
onWheel: {
slider.value = wheel.angleDelta.y < 0 ? slider.value - sliderMouseArea.manualStepSize : slider.value + sliderMouseArea.manualStepSize
}
}
}
Rectangle {
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
anchors.top: slider_background.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height
width: UM.Theme.getSize("slider_layerview_background").width * 3
height: slider.height + UM.Theme.getSize("default_margin").height * 2
color: UM.Theme.getColor("tool_panel_background");
border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("lining")
ListModel // matches LayerView.py
{
id: layerViewTypes
ListElement {
text: "Material Color"
type_id: 0
}
ListElement {
text: "Line Type"
type_id: 1 // these ids match the switching in the shader
}
}
ComboBox
{
id: layerTypeCombobox
anchors.top: parent.top
anchors.left: parent.left
model: layerViewTypes
visible: !UM.LayerView.compatibilityMode
property int layer_view_type: UM.Preferences.getValue("layerview/layer_view_type")
currentIndex: layer_view_type // index matches type_id
onActivated: {
// Combobox selection
var type_id = layerViewTypes.get(index).type_id;
UM.Preferences.setValue("layerview/layer_view_type", type_id);
updateLegend();
}
onModelChanged: {
updateLegend();
}
// Update visibility of legend.
function updateLegend() {
var type_id = layerViewTypes.get(currentIndex).type_id;
if (UM.LayerView.compatibilityMode || (type_id == 1)) {
// Line type
UM.LayerView.enableLegend();
} else {
UM.LayerView.disableLegend();
}
}
}
Label
{
id: compatibilityModeLabel
anchors.top: parent.top
anchors.left: parent.left
text: catalog.i18nc("@label","Compatibility Mode")
visible: UM.LayerView.compatibilityMode
}
Connections {
target: UM.Preferences
onPreferenceChanged:
{
layerTypeCombobox.layer_view_type = UM.Preferences.getValue("layerview/layer_view_type");
view_settings.extruder0_checked = UM.Preferences.getValue("layerview/extruder0_opacity") > 0.5;
view_settings.extruder1_checked = UM.Preferences.getValue("layerview/extruder1_opacity") > 0.5;
view_settings.extruder2_checked = UM.Preferences.getValue("layerview/extruder2_opacity") > 0.5;
view_settings.extruder3_checked = UM.Preferences.getValue("layerview/extruder3_opacity") > 0.5;
view_settings.show_travel_moves = UM.Preferences.getValue("layerview/show_travel_moves");
view_settings.show_helpers = UM.Preferences.getValue("layerview/show_helpers");
view_settings.show_skin = UM.Preferences.getValue("layerview/show_skin");
view_settings.show_infill = UM.Preferences.getValue("layerview/show_infill");
}
}
ColumnLayout {
id: view_settings
property bool extruder0_checked: UM.Preferences.getValue("layerview/extruder0_opacity") > 0.5
property bool extruder1_checked: UM.Preferences.getValue("layerview/extruder1_opacity") > 0.5
property bool extruder2_checked: UM.Preferences.getValue("layerview/extruder2_opacity") > 0.5
property bool extruder3_checked: UM.Preferences.getValue("layerview/extruder3_opacity") > 0.5
property bool show_travel_moves: UM.Preferences.getValue("layerview/show_travel_moves")
property bool show_helpers: UM.Preferences.getValue("layerview/show_helpers")
property bool show_skin: UM.Preferences.getValue("layerview/show_skin")
property bool show_infill: UM.Preferences.getValue("layerview/show_infill")
anchors.top: UM.LayerView.compatibilityMode ? compatibilityModeLabel.bottom : layerTypeCombobox.bottom
anchors.topMargin: UM.Theme.getSize("default_margin").height
anchors.left: parent.left
anchors.leftMargin: UM.Theme.getSize("default_margin").width
CheckBox {
checked: view_settings.extruder0_checked
onClicked: {
UM.Preferences.setValue("layerview/extruder0_opacity", checked ? 1.0 : 0.0);
}
text: "Extruder 1"
visible: !UM.LayerView.compatibilityMode && (UM.LayerView.extruderCount >= 1)
}
CheckBox {
checked: view_settings.extruder1_checked
onClicked: {
UM.Preferences.setValue("layerview/extruder1_opacity", checked ? 1.0 : 0.0);
}
text: "Extruder 2"
visible: !UM.LayerView.compatibilityMode && (UM.LayerView.extruderCount >= 2)
}
CheckBox {
checked: view_settings.extruder2_checked
onClicked: {
UM.Preferences.setValue("layerview/extruder2_opacity", checked ? 1.0 : 0.0);
}
text: "Extruder 3"
visible: !UM.LayerView.compatibilityMode && (UM.LayerView.etruderCount >= 3)
}
CheckBox {
checked: view_settings.extruder3_checked
onClicked: {
UM.Preferences.setValue("layerview/extruder3_opacity", checked ? 1.0 : 0.0);
}
text: "Extruder 4"
visible: !UM.LayerView.compatibilityMode && (UM.LayerView.extruderCount >= 4)
}
Label {
text: "Other extruders always visible"
visible: !UM.LayerView.compatibilityMode && (UM.LayerView.extruderCount >= 5)
}
CheckBox {
checked: view_settings.show_travel_moves
onClicked: {
UM.Preferences.setValue("layerview/show_travel_moves", checked);
}
text: catalog.i18nc("@label", "Show Travel Moves")
}
CheckBox {
checked: view_settings.show_helpers
onClicked: {
UM.Preferences.setValue("layerview/show_helpers", checked);
}
text: catalog.i18nc("@label", "Show Helpers")
}
CheckBox {
checked: view_settings.show_skin
onClicked: {
UM.Preferences.setValue("layerview/show_skin", checked);
}
text: catalog.i18nc("@label", "Show Shell")
}
CheckBox {
checked: view_settings.show_infill
onClicked: {
UM.Preferences.setValue("layerview/show_infill", checked);
}
text: catalog.i18nc("@label", "Show Infill")
}
CheckBox {
checked: true
onClicked: {
CuraApplication.log("getting QVector3D");
var v = CuraApplication.getQVector3D;
CuraApplication.log("getting QVector3D");
CuraApplication.testQVector3D(v);
}
text: catalog.i18nc("@label", "test")
}
}
}
}

View File

@ -30,7 +30,6 @@ class LayerViewProxy(QObject):
active_view = self._controller.getActiveView()
if type(active_view) == LayerView.LayerView.LayerView:
return active_view.getMaxLayers()
#return 100
@pyqtProperty(int, notify = currentLayerChanged)
def currentLayer(self):
@ -124,18 +123,6 @@ class LayerViewProxy(QObject):
return active_view.getExtruderCount()
return 0
@pyqtSlot()
def enableLegend(self):
active_view = self._controller.getActiveView()
if type(active_view) == LayerView.LayerView.LayerView:
active_view.enableLegend()
@pyqtSlot()
def disableLegend(self):
active_view = self._controller.getActiveView()
if type(active_view) == LayerView.LayerView.LayerView:
active_view.disableLegend()
def _layerActivityChanged(self):
self.activityChanged.emit()

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

6
plugins/LayerView/layers3d.shader Normal file → Executable file
View File

@ -16,7 +16,7 @@ vertex41core =
in lowp vec4 a_material_color;
in highp vec4 a_normal;
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;
out lowp vec4 v_color;
@ -53,7 +53,7 @@ vertex41core =
v_vertex = world_space_vert.xyz;
v_normal = (u_normalMatrix * normalize(a_normal)).xyz;
v_line_dim = a_line_dim;
v_extruder = a_extruder;
v_extruder = int(a_extruder);
v_line_type = a_line_type;
v_extruder_opacity = u_extruder_opacity;
@ -128,7 +128,7 @@ geometry41core =
if ((v_line_type[0] == 8) || (v_line_type[0] == 9)) {
// fixed size for movements
size_x = 0.2;
size_x = 0.05;
} else {
size_x = v_line_dim[0].x / 2 + 0.01; // radius, and make it nicely overlapping
}

View File

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

3
plugins/SliceInfoPlugin/SliceInfo.py Normal file → Executable file
View File

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

View File

@ -327,6 +327,9 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
## Set the authentication state.
# \param auth_state \type{AuthState} Enum value representing the new auth state
def setAuthenticationState(self, auth_state):
if auth_state == self._authentication_state:
return # Nothing to do here.
if auth_state == AuthState.AuthenticationRequested:
Logger.log("d", "Authentication state changed to authentication requested.")
self.setAcceptsCommands(False)
@ -367,7 +370,6 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
self._authentication_timer.stop()
self._authentication_counter = 0
if auth_state != self._authentication_state:
self._authentication_state = auth_state
self.authenticationStateChanged.emit()
@ -558,7 +560,6 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
self._preheat_bed_timer.stop()
self.preheatBedRemainingTimeChanged.emit()
def close(self):
Logger.log("d", "Closing connection of printer %s with ip %s", self._key, self._address)
self._updateJobState("")
@ -601,10 +602,6 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
# \param filter_by_machine Whether to filter MIME types by machine. This
# is ignored.
def requestWrite(self, nodes, file_name = None, filter_by_machine = False, file_handler = None):
if self._progress != 0:
self._error_message = Message(i18n_catalog.i18nc("@info:status", "Unable to start a new print job because the printer is busy. Please check the printer."))
self._error_message.show()
return
if self._printer_state != "idle":
self._error_message = Message(
i18n_catalog.i18nc("@info:status", "Unable to start a new print job, printer is busy. Current printer status is %s.") % self._printer_state)
@ -1064,17 +1061,7 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
if status_code in [200, 201, 202, 204]:
pass # Request was successful!
else:
operation_type = "Unknown"
if reply.operation() == QNetworkAccessManager.GetOperation:
operation_type = "Get"
elif reply.operation() == QNetworkAccessManager.PutOperation:
operation_type = "Put"
elif reply.operation() == QNetworkAccessManager.PostOperation:
operation_type = "Post"
elif reply.operation() == QNetworkAccessManager.DeleteOperation:
operation_type = "Delete"
Logger.log("d", "Something went wrong when trying to update data of API (%s). Message: %s Statuscode: %s, operation: %s", reply_url, reply.readAll(), status_code, operation_type)
Logger.log("d", "Something went wrong when trying to update data of API (%s). Message: %s Statuscode: %s", reply_url, reply.readAll(), status_code)
else:
Logger.log("d", "NetworkPrinterOutputDevice got an unhandled operation %s", reply.operation())

View File

@ -45,7 +45,7 @@ class UMOUpgradeSelection(MachineAction):
def _createDefinitionChangesContainer(self, global_container_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_changes_container.setDefinition(definition)
definition_changes_container.addMetaDataEntry("type", "definition_changes")

View File

@ -93,6 +93,7 @@
"description": "Whether to wait until the nozzle temperature is reached at the start.",
"default_value": true,
"type": "bool",
"enabled": "machine_nozzle_temp_enabled",
"settable_per_mesh": false,
"settable_per_extruder": 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.",
"default_value": true,
"type": "bool",
"enabled": "machine_nozzle_temp_enabled",
"settable_per_mesh": false,
"settable_per_extruder": false,
"settable_per_meshgroup": false
@ -249,6 +251,17 @@
"settable_per_extruder": true,
"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":
{
"label": "Heat up speed",
@ -256,6 +269,7 @@
"default_value": 2.0,
"unit": "°C/s",
"type": "float",
"enabled": "machine_nozzle_temp_enabled",
"settable_per_mesh": false,
"settable_per_extruder": true
},
@ -266,6 +280,7 @@
"default_value": 2.0,
"unit": "°C/s",
"type": "float",
"enabled": "machine_nozzle_temp_enabled",
"settable_per_mesh": false,
"settable_per_extruder": true
},
@ -276,6 +291,7 @@
"default_value": 50.0,
"unit": "s",
"type": "float",
"enabled": "machine_nozzle_temp_enabled",
"settable_per_mesh": false,
"settable_per_extruder": true
},
@ -908,6 +924,15 @@
"value": "top_bottom_pattern",
"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":
{
"label": "Outer Wall Inset",
@ -1089,6 +1114,16 @@
"value": "'lines' if infill_sparse_density > 25 else 'grid'",
"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'",
"enabled": "infill_sparse_density > 0",
"settable_per_mesh": true
},
"spaghetti_infill_enabled":
{
"label": "Spaghetti Infill",
@ -1267,7 +1302,7 @@
"minimum_value": "0",
"maximum_value_warning": "4",
"maximum_value": "(20 - math.log(infill_line_distance) / math.log(2)) if infill_line_distance > 0 and not spaghetti_infill_enabled else 0",
"enabled": "infill_sparse_density > 0 and infill_pattern != 'cubicsubdiv' not spaghetti_infill_enabled",
"enabled": "infill_sparse_density > 0 and infill_pattern != 'cubicsubdiv' and not spaghetti_infill_enabled",
"settable_per_mesh": true
},
"gradual_infill_step_height":
@ -1301,6 +1336,75 @@
"minimum_value": "0",
"default_value": 0,
"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
},
"max_skin_angle_for_expansion":
{
"label": "Maximum 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. An angle of 0° is horizontal, while an angle of 90° is vertical.",
"unit": "°",
"type": "float",
"minimum_value": "0",
"minimum_value_warning": "2",
"maximum_value_warning": "45",
"maximum_value": "90",
"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(max_skin_angle_for_expansion))",
"minimum_value": "0",
"enabled": "expand_upper_skins or expand_lower_skins",
"settable_per_mesh": true
}
}
}
}
},
@ -1318,7 +1422,7 @@
"description": "Change the temperature for each layer automatically with the average flow speed of that layer.",
"type": "bool",
"default_value": false,
"enabled": "False",
"enabled": "machine_nozzle_temp_enabled and False",
"settable_per_mesh": false,
"settable_per_extruder": true
},
@ -1329,22 +1433,24 @@
"unit": "°C",
"type": "float",
"default_value": 210,
"enabled": false,
"minimum_value_warning": "0",
"maximum_value_warning": "285",
"enabled": "machine_nozzle_temp_enabled",
"settable_per_extruder": true,
"minimum_value": "-273.15"
},
"material_print_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",
"type": "float",
"default_value": 210,
"value": "default_material_print_temperature",
"minimum_value": "-273.15",
"minimum_value_warning": "0",
"maximum_value_warning": "270",
"enabled": "not (material_flow_dependent_temperature) and machine_gcode_flavor != \"UltiGCode\"",
"maximum_value_warning": "285",
"enabled": "machine_nozzle_temp_enabled and not (material_flow_dependent_temperature)",
"settable_per_mesh": false,
"settable_per_extruder": true
},
@ -1355,11 +1461,11 @@
"unit": "°C",
"type": "float",
"default_value": 215,
"value": "material_print_temperature + 5",
"value": "material_print_temperature",
"minimum_value": "-273.15",
"minimum_value_warning": "0",
"maximum_value_warning": "260",
"enabled": "machine_gcode_flavor != \"UltiGCode\"",
"maximum_value_warning": "285",
"enabled": "machine_nozzle_temp_enabled",
"settable_per_mesh": false,
"settable_per_extruder": true
},
@ -1374,7 +1480,7 @@
"minimum_value": "-273.15",
"minimum_value_warning": "material_standby_temperature",
"maximum_value_warning": "material_print_temperature",
"enabled": "machine_gcode_flavor != \"UltiGCode\"",
"enabled": "machine_nozzle_temp_enabled",
"settable_per_mesh": false,
"settable_per_extruder": true
},
@ -1389,7 +1495,7 @@
"minimum_value": "-273.15",
"minimum_value_warning": "material_standby_temperature",
"maximum_value_warning": "material_print_temperature",
"enabled": "machine_gcode_flavor != \"UltiGCode\"",
"enabled": "machine_nozzle_temp_enabled",
"settable_per_mesh": false,
"settable_per_extruder": true
},
@ -1400,8 +1506,7 @@
"unit": "[[mm³,°C]]",
"type": "str",
"default_value": "[[3.5,200],[7.0,240]]",
"enabled": "False",
"comments": "old enabled function: material_flow_dependent_temperature",
"enabled": "False and machine_nozzle_temp_enabled and material_flow_dependent_temperature",
"settable_per_mesh": false,
"settable_per_extruder": true
},
@ -1415,8 +1520,7 @@
"minimum_value": "0",
"maximum_value_warning": "10.0",
"maximum_value": "machine_nozzle_heat_up_speed",
"enabled": "False",
"comments": "old enabled function: material_flow_dependent_temperature or machine_extruder_count > 1",
"enabled": "material_flow_dependent_temperature or (machine_extruder_count > 1 and material_final_print_temperature != material_print_temperature)",
"settable_per_mesh": false,
"settable_per_extruder": true
},
@ -1430,7 +1534,7 @@
"default_value": 60,
"minimum_value": "-273.15",
"minimum_value_warning": "0",
"maximum_value_warning": "260",
"maximum_value_warning": "130",
"enabled": "machine_heated_bed and machine_gcode_flavor != \"UltiGCode\"",
"settable_per_mesh": false,
"settable_per_extruder": false,
@ -1447,7 +1551,7 @@
"value": "resolveOrValue('material_bed_temperature')",
"minimum_value": "-273.15",
"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\"",
"settable_per_mesh": false,
"settable_per_extruder": false,
@ -1623,7 +1727,7 @@
"minimum_value": "-273.15",
"minimum_value_warning": "0",
"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_extruder": true
},
@ -2476,6 +2580,16 @@
"settable_per_mesh": false,
"settable_per_extruder": false
},
"travel_retract_before_outer_wall":
{
"label": "Retract Before Outer Wall",
"description": "Always retract when moving to start an outer wall.",
"type": "bool",
"default_value": false,
"enabled": "retraction_enable",
"settable_per_mesh": false,
"settable_per_extruder": false
},
"travel_avoid_other_parts":
{
"label": "Avoid Printed Parts When Traveling",
@ -3841,7 +3955,7 @@
"unit": "mm",
"type": "float",
"default_value": 2,
"value": "max(2 * min(extruderValues('prime_tower_line_width')), 0.5 * (resolveOrValue('prime_tower_size') - math.sqrt(max(0, resolveOrValue('prime_tower_size') ** 2 - max(extruderValues('prime_tower_min_volume')) / resolveOrValue('layer_height')))))",
"value": "round(max(2 * min(extruderValues('prime_tower_line_width')), 0.5 * (resolveOrValue('prime_tower_size') - math.sqrt(max(0, resolveOrValue('prime_tower_size') ** 2 - max(extruderValues('prime_tower_min_volume')) / resolveOrValue('layer_height'))))), 3)",
"resolve": "max(extruderValues('prime_tower_wall_thickness'))",
"minimum_value": "0.001",
"minimum_value_warning": "2 * min(extruderValues('prime_tower_line_width'))",

View File

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

View File

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

View File

@ -106,6 +106,7 @@
"line_width": { "value": "machine_nozzle_size * 0.875" },
"machine_min_cool_heat_time_window": { "value": "15" },
"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_layer_0": { "maximum_value": "115" },
"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..."
},
"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

@ -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;
text: catalog.i18nc("@action:inmenu menubar:file","Re&load All Models");
iconName: "document-revert";
shortcut: "F5"
onTriggered: Printer.reloadAll();
}

33
resources/qml/Cura.qml Normal file → Executable file
View File

@ -266,11 +266,11 @@ UM.MainWindow
anchors.fill: parent;
onDropped:
{
if(drop.urls.length > 0)
if (drop.urls.length > 0)
{
// Import models
var imported_model = -1;
for(var i in drop.urls)
for (var i in drop.urls)
{
// There is no endsWith in this version of JS...
if ((drop.urls[i].length <= 12) || (drop.urls[i].substring(drop.urls[i].length-12) !== ".curaprofile")) {
@ -287,7 +287,7 @@ UM.MainWindow
var import_result = Cura.ContainerManager.importProfiles(drop.urls);
if (import_result.message !== "") {
messageDialog.text = import_result.message
if(import_result.status == "ok")
if (import_result.status == "ok")
{
messageDialog.icon = StandardIcon.Information
}
@ -306,18 +306,6 @@ UM.MainWindow
}
}
Legend
{
id: legend
anchors
{
top: parent.top
topMargin: UM.Theme.getSize("default_margin").height
right: sidebar.left
rightMargin: UM.Theme.getSize("default_margin").width
}
}
JobSpecs
{
id: jobSpecs
@ -882,6 +870,21 @@ UM.MainWindow
}
}
DiscardOrKeepProfileChangesDialog
{
id: discardOrKeepProfileChangesDialog
}
Connections
{
target: Printer
onShowDiscardOrKeepProfileChanges:
{
discardOrKeepProfileChangesDialog.show()
}
}
Connections
{
target: Cura.Actions.addMachine

View File

@ -0,0 +1,208 @@
// 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: 800
height: 400
property var changesModel: Cura.UserChangesModel{ id: userChangesModel}
onVisibilityChanged:
{
if(visible)
{
changesModel.forceUpdate()
}
discardOrKeepProfileChangesDropDownButton.currentIndex = UM.Preferences.getValue("cura/choice_on_profile_override")
}
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
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")
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("system")
text:
{
var result = styleData.value
if (extruder_name != "")
{
result += " (" + extruder_name + ")"
}
return result
}
}
}
Component
{
id: defaultDelegate
Label
{
text: styleData.value
font: UM.Theme.getFont("system")
color: UM.Theme.getColor("setting_control_disabled_text")
}
}
TableViewColumn
{
role: "label"
title: catalog.i18nc("@title:column", "Profile settings")
delegate: labelDelegate
width: tableView.width * 0.4
}
TableViewColumn
{
role: "original_value"
title: catalog.i18nc("@title:column", "Default")
width: tableView.width * 0.3
delegate: defaultDelegate
}
TableViewColumn
{
role: "user_value"
title: catalog.i18nc("@title:column", "Customized")
width: tableView.width * 0.3 - 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()
}
}
}
}

View File

@ -1,65 +0,0 @@
// Copyright (c) 2015 Ultimaker B.V.
// Cura is released under the terms of the AGPLv3 or higher.
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
import QtQuick.Layouts 1.1
import UM 1.1 as UM
import Cura 1.0 as Cura
Item {
id: base
UM.I18nCatalog { id: catalog; name:"cura"}
width: childrenRect.width
height: childrenRect.height
Connections
{
target: Printer
onViewLegendItemsChanged:
{
legendItemRepeater.model = items
}
}
Column
{
Repeater
{
id: legendItemRepeater
Item {
anchors.right: parent.right
height: childrenRect.height
width: childrenRect.width
Rectangle {
id: swatch
anchors.right: parent.right
anchors.verticalCenter: label.verticalCenter
height: UM.Theme.getSize("setting_control").height / 2
width: height
color: modelData.color
border.width: UM.Theme.getSize("default_lining").width
border.color: UM.Theme.getColor("text_subtext")
}
Label {
id: label
text: modelData.title
font: UM.Theme.getFont("small")
color: UM.Theme.getColor("text_subtext")
anchors.right: swatch.left
anchors.rightMargin: UM.Theme.getSize("default_margin").width / 2
}
}
}
}
}

74
resources/qml/Preferences/GeneralPage.qml Normal file → Executable file
View File

@ -47,6 +47,8 @@ UM.PreferencesPage
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) {
UM.Preferences.resetPreference("info/send_slice_info")
@ -257,44 +259,6 @@ UM.PreferencesPage
}
}
UM.TooltipArea {
width: childrenRect.width;
height: childrenRect.height;
text: catalog.i18nc("@info:tooltip","Display 5 top layers in layer view or only the top-most layer. Rendering 5 layers takes longer, but may show more information.")
CheckBox
{
id: topLayerCountCheckbox
text: catalog.i18nc("@action:button","Display five top layers in layer view compatibility mode");
checked: UM.Preferences.getValue("view/top_layer_count") == 5
onClicked:
{
if(UM.Preferences.getValue("view/top_layer_count") == 5)
{
UM.Preferences.setValue("view/top_layer_count", 1)
}
else
{
UM.Preferences.setValue("view/top_layer_count", 5)
}
}
}
}
UM.TooltipArea {
width: childrenRect.width
height: childrenRect.height
text: catalog.i18nc("@info:tooltip", "Should only the top layers be displayed in layerview?")
CheckBox
{
id: topLayersOnlyCheckbox
text: catalog.i18nc("@option:check", "Only display top layer(s) in layer view compatibility mode")
checked: boolCheck(UM.Preferences.getValue("view/only_show_top_layers"))
onCheckedChanged: UM.Preferences.setValue("view/only_show_top_layers", checked)
}
}
UM.TooltipArea {
width: childrenRect.width
height: childrenRect.height
@ -377,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
{

View File

@ -89,6 +89,10 @@ UM.ManagementPage
id: machineActionRepeater
model: base.currentItem ? Cura.MachineActionManager.getSupportedActions(Cura.MachineManager.getDefinitionByMachineId(base.currentItem.id)) : null
Item
{
width: childrenRect.width + 2
height: childrenRect.height
Button
{
text: machineActionRepeater.model[index].label
@ -102,6 +106,7 @@ UM.ManagementPage
}
}
}
}
UM.Dialog
{

View File

@ -155,8 +155,10 @@ TabView
decimals: 2
maximumValue: 1000
onEditingFinished: base.setMaterialPreferenceValue(properties.guid, "spool_cost", parseFloat(value))
onValueChanged: updateCostPerMeter()
onValueChanged: {
base.setMaterialPreferenceValue(properties.guid, "spool_cost", parseFloat(value))
updateCostPerMeter()
}
}
Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Filament weight") }
@ -170,8 +172,10 @@ TabView
decimals: 0
maximumValue: 10000
onEditingFinished: base.setMaterialPreferenceValue(properties.guid, "spool_weight", parseFloat(value))
onValueChanged: updateCostPerMeter()
onValueChanged: {
base.setMaterialPreferenceValue(properties.guid, "spool_weight", parseFloat(value))
updateCostPerMeter()
}
}
Label { width: base.firstColumnWidth; height: parent.rowHeight; verticalAlignment: Qt.AlignVCenter; text: catalog.i18nc("@label", "Filament length") }

View File

@ -98,9 +98,9 @@ SettingItem
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
{

View File

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

View File

@ -17,6 +17,9 @@ infill_wipe_dist = 0
layer_height = 0.2
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

View File

@ -17,6 +17,9 @@ infill_wipe_dist = 0
layer_height = 0.15
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

View File

@ -14,7 +14,9 @@ brim_width = 7
cool_min_speed = 5
infill_wipe_dist = 0
layer_height = 0.06
material_print_temperature = =default_material_print_temperature + 2
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

View File

@ -13,7 +13,9 @@ weight = 0
brim_width = 7
cool_min_speed = 7
infill_wipe_dist = 0
material_print_temperature = =default_material_print_temperature + 5
material_initial_print_temperature = =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

View File

@ -18,6 +18,9 @@ cool_min_speed = 6
infill_line_width = =round(line_width * 0.4 / 0.35, 2)
infill_overlap_mm = 0.05
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

View File

@ -19,6 +19,9 @@ infill_line_width = =round(line_width * 0.4 / 0.35, 2)
infill_overlap = =0
infill_overlap_mm = 0.05
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

View File

@ -17,6 +17,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_layer_0 = =material_print_temperature + 5
ooze_shield_angle = 40

View File

@ -16,6 +16,8 @@ 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_layer_0 = =material_print_temperature + 5
ooze_shield_angle = 40

View File

@ -20,8 +20,11 @@ infill_pattern = tetrahedral
infill_sparse_density = 96
layer_height = 0.2
line_width = =machine_nozzle_size * 0.95
material_final_print_temperature = =material_print_temperature - 10
material_flow = 106
material_print_temperature_layer_0 = =default_material_print_temperature + 2
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

View File

@ -20,8 +20,11 @@ infill_pattern = tetrahedral
infill_sparse_density = 96
layer_height = 0.15
line_width = =machine_nozzle_size * 0.95
material_final_print_temperature = =material_print_temperature - 10
material_flow = 106
material_print_temperature_layer_0 = =default_material_print_temperature + 2
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_count_max = 12
retraction_extra_prime_amount = 0.8

View File

@ -19,10 +19,11 @@ 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_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

View File

@ -0,0 +1,26 @@
[general]
version = 2
name = Draft Print
definition = ultimaker3
[metadata]
type = quality
quality_type = draft
material = generic_nylon_ultimaker3_AA_0.8
weight = -2
[values]
brim_width = 8.0
cool_fan_full_at_height = =layer_height_0 + 4 * layer_height
cool_min_layer_time_fan_speed_max = 20
infill_before_walls = True
infill_pattern = triangles
machine_nozzle_cool_down_speed = 0.9
material_standby_temperature = 100
raft_airgap = =round(layer_height_0 * 0.85, 2)
raft_interface_thickness = =round(machine_nozzle_size * 0.3 / 0.4, 2)
raft_surface_thickness = =round(machine_nozzle_size * 0.2 / 0.4, 2)
switch_extruder_retraction_amount = 30
switch_extruder_retraction_speeds = 40
wall_line_width_x = =wall_line_width

View File

@ -0,0 +1,27 @@
[general]
version = 2
name = Superdraft Print
definition = ultimaker3
[metadata]
type = quality
quality_type = superdraft
material = generic_nylon_ultimaker3_AA_0.8
weight = -2
[values]
brim_width = 8.0
cool_fan_full_at_height = =layer_height_0 + 4 * layer_height
cool_min_layer_time_fan_speed_max = 20
infill_before_walls = True
infill_pattern = triangles
layer_height = 0.4
machine_nozzle_cool_down_speed = 0.9
material_standby_temperature = 100
raft_airgap = =round(layer_height_0 * 0.85, 2)
raft_interface_thickness = =round(machine_nozzle_size * 0.3 / 0.4, 2)
raft_surface_thickness = =round(machine_nozzle_size * 0.2 / 0.4, 2)
switch_extruder_retraction_amount = 30
switch_extruder_retraction_speeds = 40
wall_line_width_x = =wall_line_width

View File

@ -0,0 +1,27 @@
[general]
version = 2
name = Verydraft Print
definition = ultimaker3
[metadata]
type = quality
quality_type = verydraft
material = generic_nylon_ultimaker3_AA_0.8
weight = -2
[values]
brim_width = 8.0
cool_fan_full_at_height = =layer_height_0 + 4 * layer_height
cool_min_layer_time_fan_speed_max = 20
infill_before_walls = True
infill_pattern = triangles
layer_height = 0.3
machine_nozzle_cool_down_speed = 0.9
material_standby_temperature = 100
raft_airgap = =round(layer_height_0 * 0.85, 2)
raft_interface_thickness = =round(machine_nozzle_size * 0.3 / 0.4, 2)
raft_surface_thickness = =round(machine_nozzle_size * 0.2 / 0.4, 2)
switch_extruder_retraction_amount = 30
switch_extruder_retraction_speeds = 40
wall_line_width_x = =wall_line_width

View File

@ -0,0 +1,34 @@
[general]
version = 2
name = Draft Print
definition = ultimaker3
[metadata]
type = quality
quality_type = draft
material = generic_pla_ultimaker3_AA_0.8
weight = 0
[values]
brim_line_count = =math.ceil(brim_width / skirt_brim_line_width)
cool_fan_speed_max = =cool_fan_speed
cool_min_speed = 2
gradual_infill_step_height = =3 * layer_height
gradual_infill_steps = 4
infill_line_width = =round(line_width * 0.535 / 0.75, 2)
infill_sparse_density = 80
line_width = =machine_nozzle_size * 0.9375
machine_nozzle_heat_up_speed = 1.6
material_final_print_temperature = =max(-273.15, material_print_temperature - 15)
material_initial_print_temperature = =max(-273.15, material_print_temperature - 10)
material_print_temperature = =default_material_print_temperature + 10
material_standby_temperature = 100
ooze_shield_angle = 60
raft_acceleration = =acceleration_print
raft_jerk = =jerk_print
raft_margin = 15
switch_extruder_prime_speed = =switch_extruder_retraction_speeds
top_bottom_thickness = =layer_height * 4
wall_line_width = =round(line_width * 0.75 / 0.75, 2)
wall_thickness = =wall_line_width_0 + wall_line_width_x

View File

@ -0,0 +1,35 @@
[general]
version = 2
name = Superdraft Print
definition = ultimaker3
[metadata]
type = quality
quality_type = superdraft
material = generic_pla_ultimaker3_AA_0.8
weight = 1
[values]
brim_line_count = =math.ceil(brim_width / skirt_brim_line_width)
cool_fan_speed_max = =cool_fan_speed
cool_min_speed = 2
gradual_infill_step_height = =3 * layer_height
gradual_infill_steps = 4
infill_line_width = =round(line_width * 0.535 / 0.75, 2)
infill_sparse_density = 80
layer_height = 0.4
line_width = =machine_nozzle_size * 0.9375
machine_nozzle_heat_up_speed = 1.6
material_final_print_temperature = =max(-273.15, material_print_temperature - 15)
material_initial_print_temperature = =max(-273.15, material_print_temperature - 10)
material_print_temperature = =default_material_print_temperature + 15
material_standby_temperature = 100
ooze_shield_angle = 60
raft_acceleration = =acceleration_print
raft_jerk = =jerk_print
raft_margin = 15
switch_extruder_prime_speed = =switch_extruder_retraction_speeds
top_bottom_thickness = =layer_height * 4
wall_line_width = =round(line_width * 0.75 / 0.75, 2)
wall_thickness = =wall_line_width_0 + wall_line_width_x

View File

@ -0,0 +1,35 @@
[general]
version = 2
name = Verydraft Print
definition = ultimaker3
[metadata]
type = quality
quality_type = verydraft
material = generic_pla_ultimaker3_AA_0.8
weight = 1
[values]
brim_line_count = =math.ceil(brim_width / skirt_brim_line_width)
cool_fan_speed_max = =cool_fan_speed
cool_min_speed = 2
gradual_infill_step_height = =3 * layer_height
gradual_infill_steps = 4
infill_line_width = =round(line_width * 0.535 / 0.75, 2)
infill_sparse_density = 80
layer_height = 0.3
line_width = =machine_nozzle_size * 0.9375
machine_nozzle_heat_up_speed = 1.6
material_final_print_temperature = =max(-273.15, material_print_temperature - 15)
material_initial_print_temperature = =max(-273.15, material_print_temperature - 10)
material_print_temperature = =default_material_print_temperature + 10
material_standby_temperature = 100
ooze_shield_angle = 60
raft_acceleration = =acceleration_print
raft_jerk = =jerk_print
raft_margin = 15
switch_extruder_prime_speed = =switch_extruder_retraction_speeds
top_bottom_thickness = =layer_height * 4
wall_line_width = =round(line_width * 0.75 / 0.75, 2)
wall_thickness = =wall_line_width_0 + wall_line_width_x

View File

@ -0,0 +1,14 @@
[general]
version = 2
name = Draft Print
definition = ultimaker3
[metadata]
type = quality
quality_type = draft
weight = -2
material = generic_pva_ultimaker3_BB_0.8
[values]
material_print_temperature = =default_material_print_temperature + 5

View File

@ -0,0 +1,14 @@
[general]
version = 2
name = Superdraft Print
definition = ultimaker3
[metadata]
type = quality
quality_type = superdraft
weight = -2
material = generic_pva_ultimaker3_BB_0.8
[values]
layer_height = 0.4

View File

@ -0,0 +1,14 @@
[general]
version = 2
name = Verydraft Print
definition = ultimaker3
[metadata]
type = quality
quality_type = verydraft
weight = -2
material = generic_pva_ultimaker3_BB_0.8
[values]
layer_height = 0.3

View File

@ -290,9 +290,15 @@
"slider_groove": [0.5, 0.5],
"slider_handle": [1.5, 1.5],
"slider_layerview_size": [1.0, 16.0],
"slider_layerview_size": [1.0, 22.0],
"slider_layerview_background": [4.0, 0.0],
"slider_layerview_margin": [3.0, 3.0],
"slider_layerview_margin": [1.0, 1.0],
"layerview_menu_size": [16.5, 21.0],
"layerview_menu_size_compatibility": [22, 23.0],
"layerview_legend_size": [1.0, 1.0],
"layerview_row": [11.0, 1.5],
"layerview_row_spacing": [0.0, 0.5],
"checkbox": [2.0, 2.0],

View File

@ -45,19 +45,19 @@ speed_travel_layer_0 = =round(speed_travel)
speed_support_interface = =round(speed_topbottom)
retraction_combing = off
retraction_hop_enabled = true
retraction_hop_enabled = True
retraction_hop = 1
support_z_distance = 0
support_xy_distance = 0.5
support_join_distance = 10
support_interface_enable = true
support_interface_enable = True
adhesion_type = skirt
skirt_gap = 0.5
skirt_brim_minimal_length = 50
coasting_enable = true
coasting_enable = True
coasting_volume = 0.1
coasting_min_volume = 0.17
coasting_speed = 90

View File

@ -45,19 +45,19 @@ speed_travel_layer_0 = =round(speed_travel)
speed_support_interface = =round(speed_topbottom)
retraction_combing = off
retraction_hop_enabled = true
retraction_hop_enabled = True
retraction_hop = 1
support_z_distance = 0
support_xy_distance = 0.5
support_join_distance = 10
support_interface_enable = true
support_interface_enable = True
adhesion_type = skirt
skirt_gap = 0.5
skirt_brim_minimal_length = 50
coasting_enable = true
coasting_enable = True
coasting_volume = 0.1
coasting_min_volume = 0.17
coasting_speed = 90

View File

@ -46,19 +46,19 @@ speed_travel_layer_0 = =round(speed_travel)
speed_support_interface = =round(speed_topbottom)
retraction_combing = off
retraction_hop_enabled = true
retraction_hop_enabled = True
retraction_hop = 1
support_z_distance = 0
support_xy_distance = 0.5
support_join_distance = 10
support_interface_enable = true
support_interface_enable = True
adhesion_type = skirt
skirt_gap = 0.5
skirt_brim_minimal_length = 50
coasting_enable = true
coasting_enable = True
coasting_volume = 0.1
coasting_min_volume = 0.17
coasting_speed = 90

View File

@ -0,0 +1,64 @@
[general]
name = AA 0.8
version = 2
definition = ultimaker3
[metadata]
author = ultimaker
type = variant
[values]
acceleration_enabled = True
acceleration_print = 4000
brim_line_count = 7
brim_width = 7
cool_fan_full_at_height = =layer_height_0 + 2 * layer_height
cool_fan_speed = 100
cool_fan_speed_max = 100
default_material_print_temperature = 200
infill_before_walls = False
infill_overlap = 0
infill_pattern = cubic
infill_wipe_dist = 0
jerk_enabled = True
jerk_print = 25
jerk_topbottom = =math.ceil(jerk_print * 25 / 25)
jerk_wall = =math.ceil(jerk_print * 25 / 25)
jerk_wall_0 = =math.ceil(jerk_wall * 25 / 25)
layer_height = 0.2
machine_min_cool_heat_time_window = 15
machine_nozzle_cool_down_speed = 0.75
machine_nozzle_size = 0.8
material_final_print_temperature = =material_print_temperature - 10
material_initial_print_temperature = =material_print_temperature - 5
material_standby_temperature = 100
multiple_mesh_overlap = 0
ooze_shield_angle = 40
raft_acceleration = =acceleration_layer_0
raft_margin = 10
retract_at_layer_change = True
retraction_count_max = 25
retraction_extrusion_window = 1
retraction_hop = 2
retraction_hop_enabled = True
retraction_hop_only_when_collides = True
skin_overlap = 5
speed_equalize_flow_enabled = True
speed_layer_0 = 20
speed_print = 35
speed_topbottom = =math.ceil(speed_print * 25 / 35)
speed_wall_0 = =math.ceil(speed_wall * 25 / 30)
support_angle = 70
support_bottom_distance = =support_z_distance / 2
support_line_width = =line_width * 0.75
support_top_distance = =support_z_distance
support_xy_distance = =wall_line_width_0 * 1.5
support_z_distance = =layer_height * 2
switch_extruder_prime_speed = 30
switch_extruder_retraction_amount = 16.5
top_bottom_thickness = 1.4
travel_avoid_distance = 3
wall_0_inset = 0
wall_line_width_x = =round(wall_line_width * 0.625 / 0.75, 2)
wall_thickness = 2

View File

@ -0,0 +1,74 @@
[general]
name = BB 0.8
version = 2
definition = ultimaker3
[metadata]
author = ultimaker
type = variant
[values]
acceleration_enabled = True
acceleration_print = 4000
acceleration_support_interface = =math.ceil(acceleration_topbottom * 100 / 500)
brim_width = 3
cool_fan_speed = 50
cool_min_speed = 5
infill_line_width = =round(line_width * 0.8 / 0.7, 2)
infill_overlap = 0
infill_pattern = triangles
infill_wipe_dist = 0
jerk_enabled = True
jerk_print = 25
jerk_support_interface = =math.ceil(jerk_topbottom * 1 / 5)
layer_height = 0.2
machine_min_cool_heat_time_window = 15
machine_nozzle_heat_up_speed = 1.5
machine_nozzle_size = 0.8
material_print_temperature = =default_material_print_temperature + 10
material_standby_temperature = 100
multiple_mesh_overlap = 0
raft_acceleration = =acceleration_layer_0
raft_airgap = 0
raft_base_speed = 20
raft_base_thickness = 0.3
raft_interface_line_spacing = 0.5
raft_interface_line_width = 0.5
raft_interface_speed = 20
raft_interface_thickness = 0.2
raft_margin = 10
raft_speed = 25
raft_surface_layers = 1
retraction_amount = 4.5
retraction_count_max = 15
retraction_hop = 2
retraction_hop_enabled = True
retraction_hop_only_when_collides = True
retraction_min_travel = 5
retraction_prime_speed = 15
skin_overlap = 5
speed_layer_0 = 20
speed_print = 35
speed_support_interface = =math.ceil(speed_topbottom * 15 / 20)
speed_wall_0 = =math.ceil(speed_wall * 25 / 30)
support_angle = 60
support_bottom_height = =layer_height * 2
support_bottom_stair_step_height = =layer_height
support_infill_rate = 25
support_interface_enable = True
support_interface_height = =layer_height * 5
support_join_distance = 3
support_line_width = =round(line_width * 0.4 / 0.35, 2)
support_offset = 1.5
support_pattern = triangles
support_use_towers = False
support_xy_distance = =wall_line_width_0 / 2
support_xy_distance_overhang = =wall_line_width_0 / 4
support_z_distance = 0
switch_extruder_prime_speed = 15
switch_extruder_retraction_amount = 12
top_bottom_thickness = 1
travel_avoid_distance = 3
wall_0_inset = 0
wall_thickness = 1

View File

@ -0,0 +1,64 @@
[general]
name = AA 0.8
version = 2
definition = ultimaker3_extended
[metadata]
author = ultimaker
type = variant
[values]
acceleration_enabled = True
acceleration_print = 4000
brim_line_count = 7
brim_width = 7
cool_fan_full_at_height = =layer_height_0 + 2 * layer_height
cool_fan_speed = 100
cool_fan_speed_max = 100
default_material_print_temperature = 200
infill_before_walls = False
infill_overlap = 0
infill_pattern = cubic
infill_wipe_dist = 0
jerk_enabled = True
jerk_print = 25
jerk_topbottom = =math.ceil(jerk_print * 25 / 25)
jerk_wall = =math.ceil(jerk_print * 25 / 25)
jerk_wall_0 = =math.ceil(jerk_wall * 25 / 25)
layer_height = 0.2
machine_min_cool_heat_time_window = 15
machine_nozzle_cool_down_speed = 0.75
machine_nozzle_size = 0.8
material_final_print_temperature = =material_print_temperature - 10
material_initial_print_temperature = =material_print_temperature - 5
material_standby_temperature = 100
multiple_mesh_overlap = 0
ooze_shield_angle = 40
raft_acceleration = =acceleration_layer_0
raft_margin = 10
retract_at_layer_change = True
retraction_count_max = 25
retraction_extrusion_window = 1
retraction_hop = 2
retraction_hop_enabled = True
retraction_hop_only_when_collides = True
skin_overlap = 5
speed_equalize_flow_enabled = True
speed_layer_0 = 20
speed_print = 35
speed_topbottom = =math.ceil(speed_print * 25 / 35)
speed_wall_0 = =math.ceil(speed_wall * 25 / 30)
support_angle = 70
support_bottom_distance = =support_z_distance / 2
support_line_width = =line_width * 0.75
support_top_distance = =support_z_distance
support_xy_distance = =wall_line_width_0 * 1.5
support_z_distance = =layer_height * 2
switch_extruder_prime_speed = 30
switch_extruder_retraction_amount = 16.5
top_bottom_thickness = 1.4
travel_avoid_distance = 3
wall_0_inset = 0
wall_line_width_x = =round(wall_line_width * 0.625 / 0.75, 2)
wall_thickness = 2

View File

@ -0,0 +1,74 @@
[general]
name = BB 0.8
version = 2
definition = ultimaker3_extended
[metadata]
author = ultimaker
type = variant
[values]
acceleration_enabled = True
acceleration_print = 4000
acceleration_support_interface = =math.ceil(acceleration_topbottom * 100 / 500)
brim_width = 3
cool_fan_speed = 50
cool_min_speed = 5
infill_line_width = =round(line_width * 0.8 / 0.7, 2)
infill_overlap = 0
infill_pattern = triangles
infill_wipe_dist = 0
jerk_enabled = True
jerk_print = 25
jerk_support_interface = =math.ceil(jerk_topbottom * 1 / 5)
layer_height = 0.2
machine_min_cool_heat_time_window = 15
machine_nozzle_heat_up_speed = 1.5
machine_nozzle_size = 0.8
material_print_temperature = =default_material_print_temperature + 10
material_standby_temperature = 100
multiple_mesh_overlap = 0
raft_acceleration = =acceleration_layer_0
raft_airgap = 0
raft_base_speed = 20
raft_base_thickness = 0.3
raft_interface_line_spacing = 0.5
raft_interface_line_width = 0.5
raft_interface_speed = 20
raft_interface_thickness = 0.2
raft_margin = 10
raft_speed = 25
raft_surface_layers = 1
retraction_amount = 4.5
retraction_count_max = 15
retraction_hop = 2
retraction_hop_enabled = True
retraction_hop_only_when_collides = True
retraction_min_travel = 5
retraction_prime_speed = 15
skin_overlap = 5
speed_layer_0 = 20
speed_print = 35
speed_support_interface = =math.ceil(speed_topbottom * 15 / 20)
speed_wall_0 = =math.ceil(speed_wall * 25 / 30)
support_angle = 60
support_bottom_height = =layer_height * 2
support_bottom_stair_step_height = =layer_height
support_infill_rate = 25
support_interface_enable = True
support_interface_height = =layer_height * 5
support_join_distance = 3
support_line_width = =round(line_width * 0.4 / 0.35, 2)
support_offset = 1.5
support_pattern = triangles
support_use_towers = False
support_xy_distance = =wall_line_width_0 / 2
support_xy_distance_overhang = =wall_line_width_0 / 4
support_z_distance = 0
switch_extruder_prime_speed = 15
switch_extruder_retraction_amount = 12
top_bottom_thickness = 1
travel_avoid_distance = 3
wall_0_inset = 0
wall_thickness = 1