mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-11-02 20:52:20 -07:00
Merge branch 'master' into CURA-7871_lowest_print_height
This commit is contained in:
commit
2c55c4a562
171 changed files with 58890 additions and 418 deletions
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright (c) 2019 Ultimaker B.V.
|
||||
# Copyright (c) 2021 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import os.path
|
||||
|
|
@ -51,6 +51,10 @@ class ThreeMFReader(MeshReader):
|
|||
self._root = None
|
||||
self._base_name = ""
|
||||
self._unit = None
|
||||
self._empty_project = False
|
||||
|
||||
def emptyFileHintSet(self) -> bool:
|
||||
return self._empty_project
|
||||
|
||||
def _createMatrixFromTransformationString(self, transformation: str) -> Matrix:
|
||||
if transformation == "":
|
||||
|
|
@ -159,9 +163,9 @@ class ThreeMFReader(MeshReader):
|
|||
um_node.callDecoration("getStack").getTop().setDefinition(definition_id)
|
||||
|
||||
setting_container = um_node.callDecoration("getStack").getTop()
|
||||
|
||||
known_setting_keys = um_node.callDecoration("getStack").getAllKeys()
|
||||
for key in settings:
|
||||
setting_value = settings[key]
|
||||
setting_value = settings[key].value
|
||||
|
||||
# Extruder_nr is a special case.
|
||||
if key == "extruder_nr":
|
||||
|
|
@ -171,7 +175,10 @@ class ThreeMFReader(MeshReader):
|
|||
else:
|
||||
Logger.log("w", "Unable to find extruder in position %s", setting_value)
|
||||
continue
|
||||
setting_container.setProperty(key, "value", setting_value)
|
||||
if key in known_setting_keys:
|
||||
setting_container.setProperty(key, "value", setting_value)
|
||||
else:
|
||||
um_node.metadata[key] = settings[key]
|
||||
|
||||
if len(um_node.getChildren()) > 0 and um_node.getMeshData() is None:
|
||||
if len(um_node.getAllChildren()) == 1:
|
||||
|
|
@ -193,6 +200,7 @@ class ThreeMFReader(MeshReader):
|
|||
return um_node
|
||||
|
||||
def _read(self, file_name: str) -> Union[SceneNode, List[SceneNode]]:
|
||||
self._empty_project = False
|
||||
result = []
|
||||
# The base object of 3mf is a zipped archive.
|
||||
try:
|
||||
|
|
@ -201,6 +209,10 @@ class ThreeMFReader(MeshReader):
|
|||
parser = Savitar.ThreeMFParser()
|
||||
scene_3mf = parser.parse(archive.open("3D/3dmodel.model").read())
|
||||
self._unit = scene_3mf.getUnit()
|
||||
|
||||
for key, value in scene_3mf.getMetadata().items():
|
||||
CuraApplication.getInstance().getController().getScene().setMetaDataEntry(key, value)
|
||||
|
||||
for node in scene_3mf.getSceneNodes():
|
||||
um_node = self._convertSavitarNodeToUMNode(node, file_name)
|
||||
if um_node is None:
|
||||
|
|
@ -257,6 +269,9 @@ class ThreeMFReader(MeshReader):
|
|||
|
||||
result.append(um_node)
|
||||
|
||||
if len(result) == 0:
|
||||
self._empty_project = True
|
||||
|
||||
except Exception:
|
||||
Logger.logException("e", "An exception occurred in 3mf reader.")
|
||||
return []
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ from cura.CuraApplication import CuraApplication
|
|||
import Savitar
|
||||
|
||||
import numpy
|
||||
import datetime
|
||||
|
||||
MYPY = False
|
||||
try:
|
||||
|
|
@ -108,7 +109,11 @@ class ThreeMFWriter(MeshWriter):
|
|||
|
||||
# Get values for all changed settings & save them.
|
||||
for key in changed_setting_keys:
|
||||
savitar_node.setSetting(key, str(stack.getProperty(key, "value")))
|
||||
savitar_node.setSetting("cura:" + key, str(stack.getProperty(key, "value")))
|
||||
|
||||
# Store the metadata.
|
||||
for key, value in um_node.metadata.items():
|
||||
savitar_node.setSetting(key, value)
|
||||
|
||||
for child_node in um_node.getChildren():
|
||||
# only save the nodes on the active build plate
|
||||
|
|
@ -145,6 +150,22 @@ class ThreeMFWriter(MeshWriter):
|
|||
model_relation_element = ET.SubElement(relations_element, "Relationship", Target = "/3D/3dmodel.model", Id = "rel0", Type = "http://schemas.microsoft.com/3dmanufacturing/2013/01/3dmodel")
|
||||
|
||||
savitar_scene = Savitar.Scene()
|
||||
|
||||
metadata_to_store = CuraApplication.getInstance().getController().getScene().getMetaData()
|
||||
|
||||
for key, value in metadata_to_store.items():
|
||||
savitar_scene.setMetaDataEntry(key, value)
|
||||
|
||||
current_time_string = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
if "Application" not in metadata_to_store:
|
||||
# This might sound a bit strange, but this field should store the original application that created
|
||||
# the 3mf. So if it was already set, leave it to whatever it was.
|
||||
savitar_scene.setMetaDataEntry("Application", CuraApplication.getInstance().getApplicationDisplayName())
|
||||
if "CreationDate" not in metadata_to_store:
|
||||
savitar_scene.setMetaDataEntry("CreationDate", current_time_string)
|
||||
|
||||
savitar_scene.setMetaDataEntry("ModificationDate", current_time_string)
|
||||
|
||||
transformation_matrix = Matrix()
|
||||
transformation_matrix._data[1, 1] = 0
|
||||
transformation_matrix._data[1, 2] = -1
|
||||
|
|
|
|||
|
|
@ -43,6 +43,10 @@ class DriveApiService:
|
|||
return
|
||||
|
||||
backup_list_response = HttpRequestManager.readJSON(reply)
|
||||
if backup_list_response is None:
|
||||
Logger.error("List of back-ups can't be parsed.")
|
||||
changed([])
|
||||
return
|
||||
if "data" not in backup_list_response:
|
||||
Logger.log("w", "Could not get backups from remote, actual response body was: %s",
|
||||
str(backup_list_response))
|
||||
|
|
|
|||
|
|
@ -250,6 +250,9 @@ class CuraEngineBackend(QObject, Backend):
|
|||
@call_on_qt_thread # must be called from the main thread because of OpenGL
|
||||
def _createSnapshot(self) -> None:
|
||||
self._snapshot = None
|
||||
if not CuraApplication.getInstance().isVisible:
|
||||
Logger.log("w", "Can't create snapshot when renderer not initialized.")
|
||||
return
|
||||
Logger.log("i", "Creating thumbnail image (just before slice)...")
|
||||
try:
|
||||
self._snapshot = Snapshot.snapshot(width = 300, height = 300)
|
||||
|
|
|
|||
|
|
@ -330,6 +330,25 @@ Item
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
- Fix for this issue: https://github.com/Ultimaker/Cura/issues/9167
|
||||
- Allows user to toggle if GCODE coordinates are affected by the extruder offset.
|
||||
- Machine wide setting. CuraEngine/src/gcodeExport.cpp is not set up to evaluate per extruder currently.
|
||||
- If it is moved to per-extruder (unlikely), then this should be moved to the extruder tab.
|
||||
*/
|
||||
Cura.SimpleCheckBox // "GCode Affected By Extruder Offsets"
|
||||
{
|
||||
id: applyExtruderOffsetsCheckbox
|
||||
containerStackId: machineStackId
|
||||
settingKey: "machine_use_extruder_offset_to_offset_coords"
|
||||
settingStoreIndex: propertyStoreIndex
|
||||
labelText: catalog.i18nc("@label", "Apply Extruder offsets to GCode")
|
||||
labelFont: base.labelFont
|
||||
labelWidth: base.labelWidth
|
||||
forceUpdateOnChangeFunction: forceUpdateFunction
|
||||
}
|
||||
|
||||
|
||||
/* The "Shared Heater" feature is temporarily disabled because its
|
||||
implementation is incomplete. Printers with multiple filaments going
|
||||
into one nozzle will keep the inactive filaments retracted at the
|
||||
|
|
|
|||
|
|
@ -142,7 +142,9 @@ class PostProcessingPlugin(QObject, Extension):
|
|||
# The PostProcessingPlugin path is for built-in scripts.
|
||||
# The Resources path is where the user should store custom scripts.
|
||||
# The Preferences path is legacy, where the user may previously have stored scripts.
|
||||
for root in [PluginRegistry.getInstance().getPluginPath("PostProcessingPlugin"), Resources.getStoragePath(Resources.Resources), Resources.getStoragePath(Resources.Preferences)]:
|
||||
resource_folders = [PluginRegistry.getInstance().getPluginPath("PostProcessingPlugin"), Resources.getStoragePath(Resources.Preferences)]
|
||||
resource_folders.extend(Resources.getAllPathsForType(Resources.Resources))
|
||||
for root in resource_folders:
|
||||
if root is None:
|
||||
continue
|
||||
path = os.path.join(root, "scripts")
|
||||
|
|
|
|||
109
plugins/PostProcessingPlugin/scripts/CreateThumbnail.py
Normal file
109
plugins/PostProcessingPlugin/scripts/CreateThumbnail.py
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
import base64
|
||||
|
||||
from UM.Logger import Logger
|
||||
from cura.Snapshot import Snapshot
|
||||
from PyQt5.QtCore import QByteArray, QIODevice, QBuffer
|
||||
|
||||
from ..Script import Script
|
||||
|
||||
|
||||
class CreateThumbnail(Script):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
def _createSnapshot(self, width, height):
|
||||
Logger.log("d", "Creating thumbnail image...")
|
||||
try:
|
||||
return Snapshot.snapshot(width, height)
|
||||
except Exception:
|
||||
Logger.logException("w", "Failed to create snapshot image")
|
||||
|
||||
def _encodeSnapshot(self, snapshot):
|
||||
Logger.log("d", "Encoding thumbnail image...")
|
||||
try:
|
||||
thumbnail_buffer = QBuffer()
|
||||
thumbnail_buffer.open(QBuffer.ReadWrite)
|
||||
thumbnail_image = snapshot
|
||||
thumbnail_image.save(thumbnail_buffer, "PNG")
|
||||
base64_bytes = base64.b64encode(thumbnail_buffer.data())
|
||||
base64_message = base64_bytes.decode('ascii')
|
||||
thumbnail_buffer.close()
|
||||
return base64_message
|
||||
except Exception:
|
||||
Logger.logException("w", "Failed to encode snapshot image")
|
||||
|
||||
def _convertSnapshotToGcode(self, encoded_snapshot, width, height, chunk_size=78):
|
||||
gcode = []
|
||||
|
||||
encoded_snapshot_length = len(encoded_snapshot)
|
||||
gcode.append(";")
|
||||
gcode.append("; thumbnail begin {} {} {}".format(
|
||||
width, height, encoded_snapshot_length))
|
||||
|
||||
chunks = ["; {}".format(encoded_snapshot[i:i+chunk_size])
|
||||
for i in range(0, len(encoded_snapshot), chunk_size)]
|
||||
gcode.extend(chunks)
|
||||
|
||||
gcode.append("; thumbnail end")
|
||||
gcode.append(";")
|
||||
gcode.append("")
|
||||
|
||||
return gcode
|
||||
|
||||
def getSettingDataString(self):
|
||||
return """{
|
||||
"name": "Create Thumbnail",
|
||||
"key": "CreateThumbnail",
|
||||
"metadata": {},
|
||||
"version": 2,
|
||||
"settings":
|
||||
{
|
||||
"width":
|
||||
{
|
||||
"label": "Width",
|
||||
"description": "Width of the generated thumbnail",
|
||||
"unit": "px",
|
||||
"type": "int",
|
||||
"default_value": 32,
|
||||
"minimum_value": "0",
|
||||
"minimum_value_warning": "12",
|
||||
"maximum_value_warning": "800"
|
||||
},
|
||||
"height":
|
||||
{
|
||||
"label": "Height",
|
||||
"description": "Height of the generated thumbnail",
|
||||
"unit": "px",
|
||||
"type": "int",
|
||||
"default_value": 32,
|
||||
"minimum_value": "0",
|
||||
"minimum_value_warning": "12",
|
||||
"maximum_value_warning": "600"
|
||||
}
|
||||
}
|
||||
}"""
|
||||
|
||||
def execute(self, data):
|
||||
width = self.getSettingValueByKey("width")
|
||||
height = self.getSettingValueByKey("height")
|
||||
|
||||
snapshot = self._createSnapshot(width, height)
|
||||
if snapshot:
|
||||
encoded_snapshot = self._encodeSnapshot(snapshot)
|
||||
snapshot_gcode = self._convertSnapshotToGcode(
|
||||
encoded_snapshot, width, height)
|
||||
|
||||
for layer in data:
|
||||
layer_index = data.index(layer)
|
||||
lines = data[layer_index].split("\n")
|
||||
for line in lines:
|
||||
if line.startswith(";Generated with Cura"):
|
||||
line_index = lines.index(line)
|
||||
insert_index = line_index + 1
|
||||
lines[insert_index:insert_index] = snapshot_gcode
|
||||
break
|
||||
|
||||
final_lines = "\n".join(lines)
|
||||
data[layer_index] = final_lines
|
||||
|
||||
return data
|
||||
|
|
@ -15,9 +15,10 @@ from UM.View.RenderBatch import RenderBatch
|
|||
from UM.View.GL.OpenGL import OpenGL
|
||||
|
||||
from cura.Settings.ExtruderManager import ExtruderManager
|
||||
|
||||
from cura.LayerPolygon import LayerPolygon
|
||||
|
||||
import os.path
|
||||
import numpy
|
||||
|
||||
## RenderPass used to display g-code paths.
|
||||
from .NozzleNode import NozzleNode
|
||||
|
|
@ -60,29 +61,38 @@ class SimulationPass(RenderPass):
|
|||
self._current_shader = self._layer_shader
|
||||
# Use extruder 0 if the extruder manager reports extruder index -1 (for single extrusion printers)
|
||||
self._layer_shader.setUniformValue("u_active_extruder", float(max(0, self._extruder_manager.activeExtruderIndex)))
|
||||
if not self._compatibility_mode:
|
||||
self._layer_shader.setUniformValue("u_starts_color", Color(*Application.getInstance().getTheme().getColor("layerview_starts").getRgb()))
|
||||
|
||||
if self._layer_view:
|
||||
self._layer_shader.setUniformValue("u_max_feedrate", self._layer_view.getMaxFeedrate())
|
||||
self._layer_shader.setUniformValue("u_min_feedrate", self._layer_view.getMinFeedrate())
|
||||
self._layer_shader.setUniformValue("u_max_thickness", self._layer_view.getMaxThickness())
|
||||
self._layer_shader.setUniformValue("u_min_thickness", self._layer_view.getMinThickness())
|
||||
self._layer_shader.setUniformValue("u_max_line_width", self._layer_view.getMaxLineWidth())
|
||||
self._layer_shader.setUniformValue("u_min_line_width", self._layer_view.getMinLineWidth())
|
||||
self._layer_shader.setUniformValue("u_layer_view_type", self._layer_view.getSimulationViewType())
|
||||
self._layer_shader.setUniformValue("u_extruder_opacity", self._layer_view.getExtruderOpacities())
|
||||
self._layer_shader.setUniformValue("u_show_travel_moves", self._layer_view.getShowTravelMoves())
|
||||
self._layer_shader.setUniformValue("u_show_helpers", self._layer_view.getShowHelpers())
|
||||
self._layer_shader.setUniformValue("u_show_skin", self._layer_view.getShowSkin())
|
||||
self._layer_shader.setUniformValue("u_show_infill", self._layer_view.getShowInfill())
|
||||
self._layer_shader.setUniformValue("u_show_starts", self._layer_view.getShowStarts())
|
||||
else:
|
||||
#defaults
|
||||
self._layer_shader.setUniformValue("u_max_feedrate", 1)
|
||||
self._layer_shader.setUniformValue("u_min_feedrate", 0)
|
||||
self._layer_shader.setUniformValue("u_max_thickness", 1)
|
||||
self._layer_shader.setUniformValue("u_min_thickness", 0)
|
||||
self._layer_shader.setUniformValue("u_max_line_width", 1)
|
||||
self._layer_shader.setUniformValue("u_min_line_width", 0)
|
||||
self._layer_shader.setUniformValue("u_layer_view_type", 1)
|
||||
self._layer_shader.setUniformValue("u_extruder_opacity", [[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]])
|
||||
self._layer_shader.setUniformValue("u_show_travel_moves", 0)
|
||||
self._layer_shader.setUniformValue("u_show_helpers", 1)
|
||||
self._layer_shader.setUniformValue("u_show_skin", 1)
|
||||
self._layer_shader.setUniformValue("u_show_infill", 1)
|
||||
self._layer_shader.setUniformValue("u_show_starts", 1)
|
||||
|
||||
if not self._tool_handle_shader:
|
||||
self._tool_handle_shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "toolhandle.shader"))
|
||||
|
|
@ -161,6 +171,13 @@ class SimulationPass(RenderPass):
|
|||
self._current_shader = self._layer_shader
|
||||
self._switching_layers = True
|
||||
|
||||
# The first line does not have a previous line: add a MoveCombingType in front for start detection
|
||||
# this way the first start of the layer can also be drawn
|
||||
prev_line_types = numpy.concatenate([numpy.asarray([LayerPolygon.MoveCombingType], dtype = numpy.float32), layer_data._attributes["line_types"]["value"]])
|
||||
# Remove the last element
|
||||
prev_line_types = prev_line_types[0:layer_data._attributes["line_types"]["value"].size]
|
||||
layer_data._attributes["prev_line_types"] = {'opengl_type': 'float', 'value': prev_line_types, 'opengl_name': 'a_prev_line_type'}
|
||||
|
||||
layers_batch = RenderBatch(self._current_shader, type = RenderBatch.RenderType.Solid, mode = RenderBatch.RenderMode.Lines, range = (start, end), backface_cull = True)
|
||||
layers_batch.addItem(node.getWorldTransformation(), layer_data)
|
||||
layers_batch.render(self._scene.getActiveCamera())
|
||||
|
|
|
|||
|
|
@ -91,6 +91,8 @@ class SimulationView(CuraView):
|
|||
self._min_feedrate = sys.float_info.max
|
||||
self._max_thickness = sys.float_info.min
|
||||
self._min_thickness = sys.float_info.max
|
||||
self._max_line_width = sys.float_info.min
|
||||
self._min_line_width = sys.float_info.max
|
||||
|
||||
self._global_container_stack = None # type: Optional[ContainerStack]
|
||||
self._proxy = None
|
||||
|
|
@ -111,6 +113,7 @@ class SimulationView(CuraView):
|
|||
Application.getInstance().getPreferences().addPreference("layerview/show_helpers", True)
|
||||
Application.getInstance().getPreferences().addPreference("layerview/show_skin", True)
|
||||
Application.getInstance().getPreferences().addPreference("layerview/show_infill", True)
|
||||
Application.getInstance().getPreferences().addPreference("layerview/show_starts", True)
|
||||
|
||||
self._updateWithPreferences()
|
||||
|
||||
|
|
@ -146,6 +149,7 @@ class SimulationView(CuraView):
|
|||
self._show_helpers = True
|
||||
self._show_skin = True
|
||||
self._show_infill = True
|
||||
self._show_starts = True
|
||||
self.resetLayerData()
|
||||
|
||||
def getActivity(self) -> bool:
|
||||
|
|
@ -218,6 +222,8 @@ class SimulationView(CuraView):
|
|||
self._min_feedrate = sys.float_info.max
|
||||
self._max_thickness = sys.float_info.min
|
||||
self._min_thickness = sys.float_info.max
|
||||
self._max_line_width = sys.float_info.min
|
||||
self._min_line_width = sys.float_info.max
|
||||
|
||||
def beginRendering(self) -> None:
|
||||
scene = self.getController().getScene()
|
||||
|
|
@ -355,6 +361,13 @@ class SimulationView(CuraView):
|
|||
def getShowInfill(self) -> bool:
|
||||
return self._show_infill
|
||||
|
||||
def setShowStarts(self, show: bool) -> None:
|
||||
self._show_starts = show
|
||||
self.currentLayerNumChanged.emit()
|
||||
|
||||
def getShowStarts(self) -> bool:
|
||||
return self._show_starts
|
||||
|
||||
def getCompatibilityMode(self) -> bool:
|
||||
return self._compatibility_mode
|
||||
|
||||
|
|
@ -377,6 +390,14 @@ class SimulationView(CuraView):
|
|||
def getMaxThickness(self) -> float:
|
||||
return self._max_thickness
|
||||
|
||||
def getMaxLineWidth(self) -> float:
|
||||
return self._max_line_width
|
||||
|
||||
def getMinLineWidth(self) -> float:
|
||||
if abs(self._min_line_width - sys.float_info.max) < 10: # Some lenience due to floating point rounding.
|
||||
return 0.0 # If it's still max-float, there are no measurements. Use 0 then.
|
||||
return self._min_line_width
|
||||
|
||||
def calculateMaxLayers(self) -> None:
|
||||
scene = self.getController().getScene()
|
||||
|
||||
|
|
@ -401,6 +422,8 @@ class SimulationView(CuraView):
|
|||
for p in layer_data.getLayer(layer_id).polygons:
|
||||
self._max_feedrate = max(float(p.lineFeedrates.max()), self._max_feedrate)
|
||||
self._min_feedrate = min(float(p.lineFeedrates.min()), self._min_feedrate)
|
||||
self._max_line_width = max(float(p.lineWidths.max()), self._max_line_width)
|
||||
self._min_line_width = min(float(p.lineWidths.min()), self._min_line_width)
|
||||
self._max_thickness = max(float(p.lineThicknesses.max()), self._max_thickness)
|
||||
try:
|
||||
self._min_thickness = min(float(p.lineThicknesses[numpy.nonzero(p.lineThicknesses)].min()), self._min_thickness)
|
||||
|
|
@ -638,6 +661,7 @@ class SimulationView(CuraView):
|
|||
self.setShowHelpers(bool(Application.getInstance().getPreferences().getValue("layerview/show_helpers")))
|
||||
self.setShowSkin(bool(Application.getInstance().getPreferences().getValue("layerview/show_skin")))
|
||||
self.setShowInfill(bool(Application.getInstance().getPreferences().getValue("layerview/show_infill")))
|
||||
self.setShowStarts(bool(Application.getInstance().getPreferences().getValue("layerview/show_starts")))
|
||||
|
||||
self._startUpdateTopLayers()
|
||||
self.preferencesChanged.emit()
|
||||
|
|
@ -653,6 +677,7 @@ class SimulationView(CuraView):
|
|||
"layerview/show_helpers",
|
||||
"layerview/show_skin",
|
||||
"layerview/show_infill",
|
||||
"layerview/show_starts",
|
||||
}:
|
||||
return
|
||||
|
||||
|
|
|
|||
|
|
@ -82,12 +82,14 @@ Cura.ExpandableComponent
|
|||
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_starts: UM.Preferences.getValue("layerview/show_starts")
|
||||
|
||||
// If we are in compatibility mode, we only show the "line type"
|
||||
property bool show_legend: UM.SimulationView.compatibilityMode ? true : UM.Preferences.getValue("layerview/layer_view_type") == 1
|
||||
property bool show_gradient: UM.SimulationView.compatibilityMode ? false : UM.Preferences.getValue("layerview/layer_view_type") == 2 || UM.Preferences.getValue("layerview/layer_view_type") == 3
|
||||
property bool show_feedrate_gradient: show_gradient && UM.Preferences.getValue("layerview/layer_view_type") == 2
|
||||
property bool show_thickness_gradient: show_gradient && UM.Preferences.getValue("layerview/layer_view_type") == 3
|
||||
property bool show_line_width_gradient: show_gradient && UM.Preferences.getValue("layerview/layer_view_type") == 4
|
||||
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")
|
||||
|
||||
|
|
@ -116,9 +118,13 @@ Cura.ExpandableComponent
|
|||
type_id: 2
|
||||
})
|
||||
layerViewTypes.append({
|
||||
text: catalog.i18nc("@label:listbox", "Layer thickness"),
|
||||
text: catalog.i18nc("@label:listbox", "Layer Thickness"),
|
||||
type_id: 3 // these ids match the switching in the shader
|
||||
})
|
||||
layerViewTypes.append({
|
||||
text: catalog.i18nc("@label:listbox", "Line Width"),
|
||||
type_id: 4
|
||||
})
|
||||
}
|
||||
|
||||
ComboBox
|
||||
|
|
@ -144,9 +150,10 @@ Cura.ExpandableComponent
|
|||
{
|
||||
// Update the visibility of the legends.
|
||||
viewSettings.show_legend = UM.SimulationView.compatibilityMode || (type_id == 1);
|
||||
viewSettings.show_gradient = !UM.SimulationView.compatibilityMode && (type_id == 2 || type_id == 3);
|
||||
viewSettings.show_gradient = !UM.SimulationView.compatibilityMode && (type_id == 2 || type_id == 3 || type_id == 4);
|
||||
viewSettings.show_feedrate_gradient = viewSettings.show_gradient && (type_id == 2);
|
||||
viewSettings.show_thickness_gradient = viewSettings.show_gradient && (type_id == 3);
|
||||
viewSettings.show_line_width_gradient = viewSettings.show_gradient && (type_id == 4);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -250,6 +257,15 @@ Cura.ExpandableComponent
|
|||
preference: "layerview/show_infill",
|
||||
colorId: "layerview_infill"
|
||||
});
|
||||
if (! UM.SimulationView.compatibilityMode)
|
||||
{
|
||||
typesLegendModel.append({
|
||||
label: catalog.i18nc("@label", "Starts"),
|
||||
initialValue: viewSettings.show_starts,
|
||||
preference: "layerview/show_starts",
|
||||
colorId: "layerview_starts"
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -380,6 +396,11 @@ Cura.ExpandableComponent
|
|||
{
|
||||
return parseFloat(UM.SimulationView.getMinThickness()).toFixed(2)
|
||||
}
|
||||
//Line width selected
|
||||
if(UM.Preferences.getValue("layerview/layer_view_type") == 4)
|
||||
{
|
||||
return parseFloat(UM.SimulationView.getMinLineWidth()).toFixed(2);
|
||||
}
|
||||
}
|
||||
return catalog.i18nc("@label","min")
|
||||
}
|
||||
|
|
@ -405,6 +426,11 @@ Cura.ExpandableComponent
|
|||
{
|
||||
return "mm"
|
||||
}
|
||||
//Line width selected
|
||||
if(UM.Preferences.getValue("layerview/layer_view_type") == 4)
|
||||
{
|
||||
return "mm"
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
|
@ -429,6 +455,11 @@ Cura.ExpandableComponent
|
|||
{
|
||||
return parseFloat(UM.SimulationView.getMaxThickness()).toFixed(2)
|
||||
}
|
||||
//Line width selected
|
||||
if(UM.Preferences.getValue("layerview/layer_view_type") == 4)
|
||||
{
|
||||
return parseFloat(UM.SimulationView.getMaxLineWidth()).toFixed(2);
|
||||
}
|
||||
}
|
||||
return catalog.i18nc("@label","max")
|
||||
}
|
||||
|
|
@ -443,7 +474,7 @@ Cura.ExpandableComponent
|
|||
Rectangle
|
||||
{
|
||||
id: feedrateGradient
|
||||
visible: viewSettings.show_feedrate_gradient
|
||||
visible: viewSettings.show_feedrate_gradient || viewSettings.show_line_width_gradient
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: Math.round(UM.Theme.getSize("layerview_row").height * 1.5)
|
||||
|
|
|
|||
|
|
@ -117,6 +117,14 @@ class SimulationViewProxy(QObject):
|
|||
def getMaxThickness(self):
|
||||
return self._simulation_view.getMaxThickness()
|
||||
|
||||
@pyqtSlot(result=float)
|
||||
def getMaxLineWidth(self):
|
||||
return self._simulation_view.getMaxLineWidth()
|
||||
|
||||
@pyqtSlot(result=float)
|
||||
def getMinLineWidth(self):
|
||||
return self._simulation_view.getMinLineWidth()
|
||||
|
||||
# Opacity 0..1
|
||||
@pyqtSlot(int, float)
|
||||
def setExtruderOpacity(self, extruder_nr, opacity):
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ vertex41core =
|
|||
uniform lowp float u_min_feedrate;
|
||||
uniform lowp float u_max_thickness;
|
||||
uniform lowp float u_min_thickness;
|
||||
uniform lowp float u_max_line_width;
|
||||
uniform lowp float u_min_line_width;
|
||||
uniform lowp int u_layer_view_type;
|
||||
uniform lowp mat4 u_extruder_opacity; // currently only for max 16 extruders, others always visible
|
||||
|
||||
|
|
@ -21,6 +23,7 @@ vertex41core =
|
|||
in highp vec4 a_normal;
|
||||
in highp vec2 a_line_dim; // line width and thickness
|
||||
in highp float a_extruder;
|
||||
in highp float a_prev_line_type;
|
||||
in highp float a_line_type;
|
||||
in highp float a_feedrate;
|
||||
in highp float a_thickness;
|
||||
|
|
@ -32,6 +35,7 @@ vertex41core =
|
|||
out lowp vec2 v_line_dim;
|
||||
out highp int v_extruder;
|
||||
out highp mat4 v_extruder_opacity;
|
||||
out float v_prev_line_type;
|
||||
out float v_line_type;
|
||||
|
||||
out lowp vec4 f_color;
|
||||
|
|
@ -64,6 +68,19 @@ vertex41core =
|
|||
return vec4(red, green, blue, 1.0);
|
||||
}
|
||||
|
||||
vec4 lineWidthGradientColor(float abs_value, float min_value, float max_value)
|
||||
{
|
||||
float value = (abs_value - min_value) / (max_value - min_value);
|
||||
float red = value;
|
||||
float green = 1 - abs(1 - 4 * value);
|
||||
if(value > 0.375)
|
||||
{
|
||||
green = 0.5;
|
||||
}
|
||||
float blue = max(1 - 4 * value, 0);
|
||||
return vec4(red, green, blue, 1.0);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 v1_vertex = a_vertex;
|
||||
|
|
@ -86,12 +103,16 @@ vertex41core =
|
|||
case 3: // "Layer thickness"
|
||||
v_color = layerThicknessGradientColor(a_line_dim.y, u_min_thickness, u_max_thickness);
|
||||
break;
|
||||
case 4: // "Line width"
|
||||
v_color = lineWidthGradientColor(a_line_dim.x, u_min_line_width, u_max_line_width);
|
||||
break;
|
||||
}
|
||||
|
||||
v_vertex = world_space_vert.xyz;
|
||||
v_normal = (u_normalMatrix * normalize(a_normal)).xyz;
|
||||
v_line_dim = a_line_dim;
|
||||
v_extruder = int(a_extruder);
|
||||
v_prev_line_type = a_prev_line_type;
|
||||
v_line_type = a_line_type;
|
||||
v_extruder_opacity = u_extruder_opacity;
|
||||
|
||||
|
|
@ -108,13 +129,16 @@ geometry41core =
|
|||
uniform highp mat4 u_viewMatrix;
|
||||
uniform highp mat4 u_projectionMatrix;
|
||||
|
||||
uniform lowp vec4 u_starts_color;
|
||||
|
||||
uniform int u_show_travel_moves;
|
||||
uniform int u_show_helpers;
|
||||
uniform int u_show_skin;
|
||||
uniform int u_show_infill;
|
||||
uniform int u_show_starts;
|
||||
|
||||
layout(lines) in;
|
||||
layout(triangle_strip, max_vertices = 26) out;
|
||||
layout(triangle_strip, max_vertices = 40) out;
|
||||
|
||||
in vec4 v_color[];
|
||||
in vec3 v_vertex[];
|
||||
|
|
@ -122,6 +146,7 @@ geometry41core =
|
|||
in vec2 v_line_dim[];
|
||||
in int v_extruder[];
|
||||
in mat4 v_extruder_opacity[];
|
||||
in float v_prev_line_type[];
|
||||
in float v_line_type[];
|
||||
|
||||
out vec4 f_color;
|
||||
|
|
@ -268,6 +293,29 @@ geometry41core =
|
|||
|
||||
EndPrimitive();
|
||||
}
|
||||
|
||||
|
||||
if ((u_show_starts == 1) && (v_prev_line_type[0] != 1) && (v_line_type[0] == 1)) {
|
||||
float w = v_line_dim[0].x / 2;
|
||||
float h = v_line_dim[0].y / 2;
|
||||
|
||||
myEmitVertex(v_vertex[0] + vec3( w, h, w), u_starts_color, normalize(vec3( 1.0, 1.0, 1.0)), viewProjectionMatrix * (gl_in[0].gl_Position + vec4( w, h, w, 0.0))); // Front-top-left
|
||||
myEmitVertex(v_vertex[0] + vec3(-w, h, w), u_starts_color, normalize(vec3(-1.0, 1.0, 1.0)), viewProjectionMatrix * (gl_in[0].gl_Position + vec4(-w, h, w, 0.0))); // Front-top-right
|
||||
myEmitVertex(v_vertex[0] + vec3( w, -h, w), u_starts_color, normalize(vec3( 1.0, -1.0, 1.0)), viewProjectionMatrix * (gl_in[0].gl_Position + vec4( w, -h, w, 0.0))); // Front-bottom-left
|
||||
myEmitVertex(v_vertex[0] + vec3(-w, -h, w), u_starts_color, normalize(vec3(-1.0, -1.0, 1.0)), viewProjectionMatrix * (gl_in[0].gl_Position + vec4(-w, -h, w, 0.0))); // Front-bottom-right
|
||||
myEmitVertex(v_vertex[0] + vec3(-w, -h, -w), u_starts_color, normalize(vec3(-1.0, -1.0, -1.0)), viewProjectionMatrix * (gl_in[0].gl_Position + vec4(-w, -h, -w, 0.0))); // Back-bottom-right
|
||||
myEmitVertex(v_vertex[0] + vec3(-w, h, w), u_starts_color, normalize(vec3(-1.0, 1.0, 1.0)), viewProjectionMatrix * (gl_in[0].gl_Position + vec4(-w, h, w, 0.0))); // Front-top-right
|
||||
myEmitVertex(v_vertex[0] + vec3(-w, h, -w), u_starts_color, normalize(vec3(-1.0, 1.0, -1.0)), viewProjectionMatrix * (gl_in[0].gl_Position + vec4(-w, h, -w, 0.0))); // Back-top-right
|
||||
myEmitVertex(v_vertex[0] + vec3( w, h, w), u_starts_color, normalize(vec3( 1.0, 1.0, 1.0)), viewProjectionMatrix * (gl_in[0].gl_Position + vec4( w, h, w, 0.0))); // Front-top-left
|
||||
myEmitVertex(v_vertex[0] + vec3( w, h, -w), u_starts_color, normalize(vec3( 1.0, 1.0, -1.0)), viewProjectionMatrix * (gl_in[0].gl_Position + vec4( w, h, -w, 0.0))); // Back-top-left
|
||||
myEmitVertex(v_vertex[0] + vec3( w, -h, w), u_starts_color, normalize(vec3( 1.0, -1.0, 1.0)), viewProjectionMatrix * (gl_in[0].gl_Position + vec4( w, -h, w, 0.0))); // Front-bottom-left
|
||||
myEmitVertex(v_vertex[0] + vec3( w, -h, -w), u_starts_color, normalize(vec3( 1.0, -1.0, -1.0)), viewProjectionMatrix * (gl_in[0].gl_Position + vec4( w, -h, -w, 0.0))); // Back-bottom-left
|
||||
myEmitVertex(v_vertex[0] + vec3(-w, -h, -w), u_starts_color, normalize(vec3(-1.0, -1.0, -1.0)), viewProjectionMatrix * (gl_in[0].gl_Position + vec4(-w, -h, -w, 0.0))); // Back-bottom-right
|
||||
myEmitVertex(v_vertex[0] + vec3( w, h, -w), u_starts_color, normalize(vec3( 1.0, 1.0, -1.0)), viewProjectionMatrix * (gl_in[0].gl_Position + vec4( w, h, -w, 0.0))); // Back-top-left
|
||||
myEmitVertex(v_vertex[0] + vec3(-w, h, -w), u_starts_color, normalize(vec3(-1.0, 1.0, -1.0)), viewProjectionMatrix * (gl_in[0].gl_Position + vec4(-w, h, -w, 0.0))); // Back-top-right
|
||||
|
||||
EndPrimitive();
|
||||
}
|
||||
}
|
||||
|
||||
fragment41core =
|
||||
|
|
@ -312,10 +360,13 @@ u_diffuseColor = [1.0, 0.79, 0.14, 1.0]
|
|||
u_minimumAlbedo = [0.1, 0.1, 0.1, 1.0]
|
||||
u_shininess = 20.0
|
||||
|
||||
u_starts_color = [1.0, 1.0, 1.0, 1.0]
|
||||
|
||||
u_show_travel_moves = 0
|
||||
u_show_helpers = 1
|
||||
u_show_skin = 1
|
||||
u_show_infill = 1
|
||||
u_show_starts = 1
|
||||
|
||||
u_min_feedrate = 0
|
||||
u_max_feedrate = 1
|
||||
|
|
@ -337,6 +388,7 @@ a_normal = normal
|
|||
a_line_dim = line_dim
|
||||
a_extruder = extruder
|
||||
a_material_color = material_color
|
||||
a_prev_line_type = prev_line_type
|
||||
a_line_type = line_type
|
||||
a_feedrate = feedrate
|
||||
a_thickness = thickness
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright (c) 2019 Ultimaker B.V.
|
||||
# Copyright (c) 2021 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
from typing import Optional
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright (c) 2020 Ultimaker B.V.
|
||||
# Copyright (c) 2021 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
from typing import List, Optional, Union, Dict, Any
|
||||
|
||||
|
|
@ -8,7 +8,7 @@ from .ClusterBuildPlate import ClusterBuildPlate
|
|||
from .ClusterPrintJobConfigurationChange import ClusterPrintJobConfigurationChange
|
||||
from .ClusterPrintJobImpediment import ClusterPrintJobImpediment
|
||||
from .ClusterPrintCoreConfiguration import ClusterPrintCoreConfiguration
|
||||
from .ClusterPrintJobConstraint import ClusterPrintJobConstraints
|
||||
from .ClusterPrintJobConstraints import ClusterPrintJobConstraints
|
||||
from ..UM3PrintJobOutputModel import UM3PrintJobOutputModel
|
||||
from ..ConfigurationChangeModel import ConfigurationChangeModel
|
||||
from ..BaseModel import BaseModel
|
||||
|
|
@ -18,13 +18,24 @@ from ...ClusterOutputController import ClusterOutputController
|
|||
class ClusterPrintJobStatus(BaseModel):
|
||||
"""Model for the status of a single print job in a cluster."""
|
||||
|
||||
def __init__(self, created_at: str, force: bool, machine_variant: str, name: str, started: bool, status: str,
|
||||
time_total: int, uuid: str,
|
||||
def __init__(self,
|
||||
created_at: str,
|
||||
force: bool,
|
||||
machine_variant: str,
|
||||
name: str,
|
||||
started: bool,
|
||||
status: str,
|
||||
time_total: int,
|
||||
uuid: str,
|
||||
configuration: List[Union[Dict[str, Any], ClusterPrintCoreConfiguration]],
|
||||
constraints: List[Union[Dict[str, Any], ClusterPrintJobConstraints]],
|
||||
last_seen: Optional[float] = None, network_error_count: Optional[int] = None,
|
||||
owner: Optional[str] = None, printer_uuid: Optional[str] = None, time_elapsed: Optional[int] = None,
|
||||
assigned_to: Optional[str] = None, deleted_at: Optional[str] = None,
|
||||
constraints: Optional[Union[Dict[str, Any], ClusterPrintJobConstraints]] = None,
|
||||
last_seen: Optional[float] = None,
|
||||
network_error_count: Optional[int] = None,
|
||||
owner: Optional[str] = None,
|
||||
printer_uuid: Optional[str] = None,
|
||||
time_elapsed: Optional[int] = None,
|
||||
assigned_to: Optional[str] = None,
|
||||
deleted_at: Optional[str] = None,
|
||||
printed_on_uuid: Optional[str] = None,
|
||||
configuration_changes_required: List[
|
||||
Union[Dict[str, Any], ClusterPrintJobConfigurationChange]] = None,
|
||||
|
|
@ -63,10 +74,9 @@ class ClusterPrintJobStatus(BaseModel):
|
|||
printer
|
||||
:param preview_url: URL to the preview image (same as wou;d've been included in the ufp).
|
||||
"""
|
||||
|
||||
self.assigned_to = assigned_to
|
||||
self.configuration = self.parseModels(ClusterPrintCoreConfiguration, configuration)
|
||||
self.constraints = self.parseModels(ClusterPrintJobConstraints, constraints)
|
||||
self.constraints = self.parseModel(ClusterPrintJobConstraints, constraints) if constraints else None
|
||||
self.created_at = created_at
|
||||
self.force = force
|
||||
self.last_seen = last_seen
|
||||
|
|
@ -83,7 +93,6 @@ class ClusterPrintJobStatus(BaseModel):
|
|||
self.deleted_at = deleted_at
|
||||
self.printed_on_uuid = printed_on_uuid
|
||||
self.preview_url = preview_url
|
||||
|
||||
self.configuration_changes_required = self.parseModels(ClusterPrintJobConfigurationChange,
|
||||
configuration_changes_required) \
|
||||
if configuration_changes_required else []
|
||||
|
|
|
|||
|
|
@ -129,16 +129,16 @@ class ZeroConfClient:
|
|||
|
||||
for record in zero_conf.cache.entries_with_name(info.server):
|
||||
info.update_record(zero_conf, time(), record)
|
||||
if info.addresses:
|
||||
if hasattr(info, "addresses") and info.addresses:
|
||||
break
|
||||
|
||||
# Request more data if info is not complete
|
||||
if not info.addresses:
|
||||
if not hasattr(info, "addresses") or not info.addresses:
|
||||
new_info = zero_conf.get_service_info(service_type, name)
|
||||
if new_info is not None:
|
||||
info = new_info
|
||||
|
||||
if info and info.addresses:
|
||||
if info and hasattr(info, "addresses") and info.addresses:
|
||||
type_of_device = info.properties.get(b"type", None)
|
||||
if type_of_device:
|
||||
if type_of_device == b"printer":
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue