mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-13 01:37:51 -06:00
Merge remote-tracking branch 'origin/master' into libArachne_rebased
This commit is contained in:
commit
55e3b858d6
207 changed files with 3493 additions and 183 deletions
|
@ -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 == "":
|
||||
|
@ -193,6 +197,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:
|
||||
|
@ -257,6 +262,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 []
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -69,7 +69,7 @@ Item
|
|||
BackupListFooter
|
||||
{
|
||||
id: backupListFooter
|
||||
showInfoButton: backupList.model.length > 4
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Copyright (c) 2018 Ultimaker B.V.
|
||||
# Copyright (c) 2021 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import argparse #To run the engine in debug mode if the front-end is in debug mode.
|
||||
|
@ -9,6 +9,8 @@ import sys
|
|||
from time import time
|
||||
from typing import Any, cast, Dict, List, Optional, Set, TYPE_CHECKING
|
||||
|
||||
from PyQt5.QtGui import QImage
|
||||
|
||||
from UM.Backend.Backend import Backend, BackendState
|
||||
from UM.Scene.SceneNode import SceneNode
|
||||
from UM.Signal import Signal
|
||||
|
@ -24,6 +26,8 @@ from UM.Tool import Tool #For typing.
|
|||
|
||||
from cura.CuraApplication import CuraApplication
|
||||
from cura.Settings.ExtruderManager import ExtruderManager
|
||||
from cura.Snapshot import Snapshot
|
||||
from cura.Utils.Threading import call_on_qt_thread
|
||||
from .ProcessSlicedLayersJob import ProcessSlicedLayersJob
|
||||
from .StartSliceJob import StartSliceJob, StartJobResult
|
||||
|
||||
|
@ -153,6 +157,8 @@ class CuraEngineBackend(QObject, Backend):
|
|||
self.determineAutoSlicing()
|
||||
application.getPreferences().preferenceChanged.connect(self._onPreferencesChanged)
|
||||
|
||||
self._snapshot = None #type: Optional[QImage]
|
||||
|
||||
application.initializationFinished.connect(self.initialize)
|
||||
|
||||
def initialize(self) -> None:
|
||||
|
@ -241,9 +247,27 @@ class CuraEngineBackend(QObject, Backend):
|
|||
self.markSliceAll()
|
||||
self.slice()
|
||||
|
||||
@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)
|
||||
except:
|
||||
Logger.logException("w", "Failed to create snapshot image")
|
||||
self._snapshot = None # Failing to create thumbnail should not fail creation of UFP
|
||||
|
||||
def getLatestSnapshot(self) -> Optional[QImage]:
|
||||
return self._snapshot
|
||||
|
||||
def slice(self) -> None:
|
||||
"""Perform a slice of the scene."""
|
||||
|
||||
self._createSnapshot()
|
||||
|
||||
Logger.log("i", "Starting to slice...")
|
||||
self._slice_start_time = time()
|
||||
if not self._build_plates_to_be_sliced:
|
||||
|
@ -331,7 +355,6 @@ class CuraEngineBackend(QObject, Backend):
|
|||
|
||||
def _onStartSliceCompleted(self, job: StartSliceJob) -> None:
|
||||
"""Event handler to call when the job to initiate the slicing process is
|
||||
|
||||
completed.
|
||||
|
||||
When the start slice job is successfully completed, it will be happily
|
||||
|
|
|
@ -43,7 +43,7 @@ UM.Dialog
|
|||
TextField {
|
||||
id: peak_height
|
||||
objectName: "Peak_Height"
|
||||
validator: RegExpValidator {regExp: /^\d{1,3}([\,|\.]\d*)?$/}
|
||||
validator: RegExpValidator {regExp: /^\d{0,3}([\,|\.]\d*)?$/}
|
||||
width: 180 * screenScaleFactor
|
||||
onTextChanged: { manager.onPeakHeightChanged(text) }
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ UM.Dialog
|
|||
TextField {
|
||||
id: base_height
|
||||
objectName: "Base_Height"
|
||||
validator: RegExpValidator {regExp: /^\d{1,3}([\,|\.]\d*)?$/}
|
||||
validator: RegExpValidator {regExp: /^\d{0,3}([\,|\.]\d*)?$/}
|
||||
width: 180 * screenScaleFactor
|
||||
onTextChanged: { manager.onBaseHeightChanged(text) }
|
||||
}
|
||||
|
|
|
@ -52,11 +52,8 @@ class ImageReader(MeshReader):
|
|||
|
||||
def _generateSceneNode(self, file_name, xz_size, height_from_base, base_height, blur_iterations, max_size, lighter_is_higher, use_transparency_model, transmittance_1mm):
|
||||
scene_node = SceneNode()
|
||||
|
||||
mesh = MeshBuilder()
|
||||
|
||||
img = QImage(file_name)
|
||||
|
||||
if img.isNull():
|
||||
Logger.log("e", "Image is corrupt.")
|
||||
return None
|
||||
|
@ -70,11 +67,10 @@ class ImageReader(MeshReader):
|
|||
|
||||
height_from_base = max(height_from_base, 0)
|
||||
base_height = max(base_height, 0)
|
||||
peak_height = base_height + height_from_base
|
||||
|
||||
|
||||
xz_size = max(xz_size, 1)
|
||||
scale_vector = Vector(xz_size, peak_height, xz_size)
|
||||
scale_vector = Vector(xz_size, height_from_base, xz_size)
|
||||
|
||||
if width > height:
|
||||
scale_vector = scale_vector.set(z=scale_vector.z * aspect)
|
||||
|
@ -132,7 +128,7 @@ class ImageReader(MeshReader):
|
|||
|
||||
if use_transparency_model:
|
||||
divisor = 1.0 / math.log(transmittance_1mm / 100.0) # log-base doesn't matter here. Precompute this value for faster computation of each pixel.
|
||||
min_luminance = (transmittance_1mm / 100.0) ** (peak_height - base_height)
|
||||
min_luminance = (transmittance_1mm / 100.0) ** height_from_base
|
||||
for (y, x) in numpy.ndindex(height_data.shape):
|
||||
mapped_luminance = min_luminance + (1.0 - min_luminance) * height_data[y, x]
|
||||
height_data[y, x] = base_height + divisor * math.log(mapped_luminance) # use same base as a couple lines above this
|
||||
|
|
|
@ -137,6 +137,7 @@ Item
|
|||
labelWidth: base.labelWidth
|
||||
controlWidth: base.controlWidth
|
||||
unitText: ""
|
||||
decimals: 0
|
||||
forceUpdateOnChangeFunction: forceUpdateFunction
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -237,7 +237,7 @@ Item
|
|||
id: settingLoader
|
||||
width: UM.Theme.getSize("setting").width
|
||||
height: UM.Theme.getSize("section").height
|
||||
|
||||
enabled: provider.properties.enabled === "True"
|
||||
property var definition: model
|
||||
property var settingDefinitionsModel: addedSettingsModel
|
||||
property var propertyProvider: provider
|
||||
|
|
|
@ -774,15 +774,15 @@ class ChangeAtZProcessor:
|
|||
|
||||
# looking for wait for bed temp
|
||||
if "bedTemp" in values:
|
||||
codes.append("BedTemp: " + str(values["bedTemp"]))
|
||||
codes.append("BedTemp: " + str(round(values["bedTemp"])))
|
||||
|
||||
# set our extruder one temp (if specified)
|
||||
if "extruderOne" in values:
|
||||
codes.append("Extruder 1 Temp: " + str(values["extruderOne"]))
|
||||
codes.append("Extruder 1 Temp: " + str(round(values["extruderOne"])))
|
||||
|
||||
# set our extruder two temp (if specified)
|
||||
if "extruderTwo" in values:
|
||||
codes.append("Extruder 2 Temp: " + str(values["extruderTwo"]))
|
||||
codes.append("Extruder 2 Temp: " + str(round(values["extruderTwo"])))
|
||||
|
||||
# set global flow rate
|
||||
if "flowrate" in values:
|
||||
|
|
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
|
|
@ -182,8 +182,7 @@ class PauseAtHeight(Script):
|
|||
"Repetier": "Repetier"
|
||||
},
|
||||
"default_value": "RepRap (Marlin/Sprinter)",
|
||||
"enabled": false,
|
||||
"default_value": ""
|
||||
"enabled": false
|
||||
},
|
||||
"custom_gcode_before_pause":
|
||||
{
|
||||
|
|
|
@ -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,6 +61,9 @@ 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())
|
||||
|
@ -71,6 +75,7 @@ class SimulationPass(RenderPass):
|
|||
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)
|
||||
|
@ -83,6 +88,7 @@ class SimulationPass(RenderPass):
|
|||
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 +167,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())
|
||||
|
|
|
@ -104,13 +104,14 @@ class SimulationView(CuraView):
|
|||
Application.getInstance().getPreferences().addPreference("view/only_show_top_layers", False)
|
||||
Application.getInstance().getPreferences().addPreference("view/force_layer_view_compatibility_mode", False)
|
||||
|
||||
Application.getInstance().getPreferences().addPreference("layerview/layer_view_type", 0)
|
||||
Application.getInstance().getPreferences().addPreference("layerview/layer_view_type", 1) # Default to "Line Type".
|
||||
Application.getInstance().getPreferences().addPreference("layerview/extruder_opacities", "")
|
||||
|
||||
Application.getInstance().getPreferences().addPreference("layerview/show_travel_moves", False)
|
||||
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 +147,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:
|
||||
|
@ -355,6 +357,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
|
||||
|
||||
|
@ -638,6 +647,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 +663,7 @@ class SimulationView(CuraView):
|
|||
"layerview/show_helpers",
|
||||
"layerview/show_skin",
|
||||
"layerview/show_infill",
|
||||
"layerview/show_starts",
|
||||
}:
|
||||
return
|
||||
|
||||
|
|
|
@ -82,6 +82,7 @@ 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
|
||||
|
@ -250,6 +251,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"
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,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 +33,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;
|
||||
|
@ -92,6 +94,7 @@ vertex41core =
|
|||
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 +111,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 +128,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 +275,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 +342,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 +370,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,3 +1,6 @@
|
|||
# Copyright (c) 2021 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
import os
|
||||
from typing import List, Dict, Any, cast
|
||||
|
||||
|
@ -96,7 +99,10 @@ class SyncOrchestrator(Extension):
|
|||
else:
|
||||
self._cloud_api.unsubscribe(item["package_id"])
|
||||
# delete temp file
|
||||
os.remove(item["package_path"])
|
||||
try:
|
||||
os.remove(item["package_path"])
|
||||
except EnvironmentError as e: # File was already removed, no access rights, etc.
|
||||
Logger.error("Can't delete temporary package file: {err}".format(err = str(e)))
|
||||
|
||||
if has_changes:
|
||||
self._restart_presenter.present()
|
||||
|
|
|
@ -46,8 +46,6 @@ class Toolbox(QObject, Extension):
|
|||
|
||||
self._application = application # type: CuraApplication
|
||||
|
||||
self._sdk_version = ApplicationMetadata.CuraSDKVersion # type: Union[str, int]
|
||||
|
||||
# Network:
|
||||
self._download_request_data = None # type: Optional[HttpRequestData]
|
||||
self._download_progress = 0 # type: float
|
||||
|
|
|
@ -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 cast, List, Dict
|
||||
|
@ -7,16 +7,16 @@ from Charon.VirtualFile import VirtualFile # To open UFP files.
|
|||
from Charon.OpenMode import OpenMode # To indicate that we want to write to UFP files.
|
||||
from io import StringIO # For converting g-code to bytes.
|
||||
|
||||
from PyQt5.QtCore import QBuffer
|
||||
|
||||
from UM.Logger import Logger
|
||||
from UM.Mesh.MeshWriter import MeshWriter # The writer we need to implement.
|
||||
from UM.MimeTypeDatabase import MimeTypeDatabase, MimeType
|
||||
from UM.PluginRegistry import PluginRegistry # To get the g-code writer.
|
||||
from PyQt5.QtCore import QBuffer
|
||||
|
||||
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
||||
from UM.Scene.SceneNode import SceneNode
|
||||
from cura.CuraApplication import CuraApplication
|
||||
from cura.Snapshot import Snapshot
|
||||
from cura.Utils.Threading import call_on_qt_thread
|
||||
|
||||
from UM.i18n import i18nCatalog
|
||||
|
@ -38,17 +38,6 @@ class UFPWriter(MeshWriter):
|
|||
)
|
||||
)
|
||||
|
||||
self._snapshot = None
|
||||
|
||||
def _createSnapshot(self, *args):
|
||||
# must be called from the main thread because of OpenGL
|
||||
Logger.log("d", "Creating thumbnail image...")
|
||||
try:
|
||||
self._snapshot = Snapshot.snapshot(width = 300, height = 300)
|
||||
except Exception:
|
||||
Logger.logException("w", "Failed to create snapshot image")
|
||||
self._snapshot = None # Failing to create thumbnail should not fail creation of UFP
|
||||
|
||||
# This needs to be called on the main thread (Qt thread) because the serialization of material containers can
|
||||
# trigger loading other containers. Because those loaded containers are QtObjects, they must be created on the
|
||||
# Qt thread. The File read/write operations right now are executed on separated threads because they are scheduled
|
||||
|
@ -72,24 +61,23 @@ class UFPWriter(MeshWriter):
|
|||
gcode.write(gcode_textio.getvalue().encode("UTF-8"))
|
||||
archive.addRelation(virtual_path = "/3D/model.gcode", relation_type = "http://schemas.ultimaker.org/package/2018/relationships/gcode")
|
||||
|
||||
self._createSnapshot()
|
||||
|
||||
# Store the thumbnail.
|
||||
if self._snapshot:
|
||||
# Attempt to store the thumbnail, if any:
|
||||
backend = CuraApplication.getInstance().getBackend()
|
||||
snapshot = None if getattr(backend, "getLatestSnapshot", None) is None else backend.getLatestSnapshot()
|
||||
if snapshot:
|
||||
archive.addContentType(extension = "png", mime_type = "image/png")
|
||||
thumbnail = archive.getStream("/Metadata/thumbnail.png")
|
||||
|
||||
thumbnail_buffer = QBuffer()
|
||||
thumbnail_buffer.open(QBuffer.ReadWrite)
|
||||
thumbnail_image = self._snapshot
|
||||
thumbnail_image.save(thumbnail_buffer, "PNG")
|
||||
snapshot.save(thumbnail_buffer, "PNG")
|
||||
|
||||
thumbnail.write(thumbnail_buffer.data())
|
||||
archive.addRelation(virtual_path = "/Metadata/thumbnail.png",
|
||||
relation_type = "http://schemas.openxmlformats.org/package/2006/relationships/metadata/thumbnail",
|
||||
origin = "/3D/model.gcode")
|
||||
else:
|
||||
Logger.log("d", "Thumbnail not created, cannot save it")
|
||||
Logger.log("w", "Thumbnail not created, cannot save it")
|
||||
|
||||
# Store the material.
|
||||
application = CuraApplication.getInstance()
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
# Copyright (c) 2021 Ultimaker B.V.
|
||||
# Cura is released under the terms of the LGPLv3 or higher.
|
||||
|
||||
from typing import List, Optional
|
||||
|
||||
from UM.FileHandler.FileHandler import FileHandler
|
||||
|
|
|
@ -151,7 +151,7 @@ class XmlMaterialProfile(InstanceContainer):
|
|||
"version": self.CurrentFdmMaterialVersion})
|
||||
|
||||
## Begin Metadata Block
|
||||
builder.start("metadata") # type: ignore
|
||||
builder.start("metadata", {}) # type: ignore
|
||||
|
||||
metadata = copy.deepcopy(self.getMetaData())
|
||||
# setting_version is derived from the "version" tag in the schema, so don't serialize it into a file
|
||||
|
@ -165,21 +165,21 @@ class XmlMaterialProfile(InstanceContainer):
|
|||
properties = metadata.pop("properties", {})
|
||||
|
||||
## Begin Name Block
|
||||
builder.start("name") # type: ignore
|
||||
builder.start("name", {}) # type: ignore
|
||||
|
||||
builder.start("brand") # type: ignore
|
||||
builder.start("brand", {}) # type: ignore
|
||||
builder.data(metadata.pop("brand", ""))
|
||||
builder.end("brand")
|
||||
|
||||
builder.start("material") # type: ignore
|
||||
builder.start("material", {}) # type: ignore
|
||||
builder.data(metadata.pop("material", ""))
|
||||
builder.end("material")
|
||||
|
||||
builder.start("color") # type: ignore
|
||||
builder.start("color", {}) # type: ignore
|
||||
builder.data(metadata.pop("color_name", ""))
|
||||
builder.end("color")
|
||||
|
||||
builder.start("label") # type: ignore
|
||||
builder.start("label", {}) # type: ignore
|
||||
builder.data(self.getName())
|
||||
builder.end("label")
|
||||
|
||||
|
@ -190,7 +190,7 @@ class XmlMaterialProfile(InstanceContainer):
|
|||
key_to_use = key
|
||||
if key in self._metadata_tags_that_have_cura_namespace:
|
||||
key_to_use = "cura:" + key_to_use
|
||||
builder.start(key_to_use) # type: ignore
|
||||
builder.start(key_to_use, {}) # type: ignore
|
||||
if value is not None: #Nones get handled well by the builder.
|
||||
#Otherwise the builder always expects a string.
|
||||
#Deserialize expects the stringified version.
|
||||
|
@ -202,10 +202,10 @@ class XmlMaterialProfile(InstanceContainer):
|
|||
## End Metadata Block
|
||||
|
||||
## Begin Properties Block
|
||||
builder.start("properties") # type: ignore
|
||||
builder.start("properties", {}) # type: ignore
|
||||
|
||||
for key, value in properties.items():
|
||||
builder.start(key) # type: ignore
|
||||
builder.start(key, {}) # type: ignore
|
||||
builder.data(value)
|
||||
builder.end(key)
|
||||
|
||||
|
@ -213,7 +213,7 @@ class XmlMaterialProfile(InstanceContainer):
|
|||
## End Properties Block
|
||||
|
||||
## Begin Settings Block
|
||||
builder.start("settings") # type: ignore
|
||||
builder.start("settings", {}) # type: ignore
|
||||
|
||||
if self.getMetaDataEntry("definition") == "fdmprinter":
|
||||
for instance in self.findInstances():
|
||||
|
@ -258,7 +258,7 @@ class XmlMaterialProfile(InstanceContainer):
|
|||
product = product_name
|
||||
break
|
||||
|
||||
builder.start("machine") # type: ignore
|
||||
builder.start("machine", {}) # type: ignore
|
||||
builder.start("machine_identifier", {
|
||||
"manufacturer": container.getMetaDataEntry("machine_manufacturer",
|
||||
definition_metadata.get("manufacturer", "Unknown")),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue