mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-04-23 06:09:38 +08:00
Merge branch 'master' of github.com:Ultimaker/Cura into feature_intent
This commit is contained in:
commit
0cb83d2c92
6
.github/ISSUE_TEMPLATE/bug-report.md
vendored
6
.github/ISSUE_TEMPLATE/bug-report.md
vendored
@ -8,11 +8,11 @@ assignees: ''
|
|||||||
---
|
---
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
The following template is useful for filing new issues. Processing an issue will go much faster when this is filled out, and issues which do not use this template WILL BE REMOVED.
|
Processing an issue will go much faster when this is filled out, and issues which do not use this template WILL BE REMOVED and no fix will be considered!
|
||||||
|
|
||||||
Before filing, PLEASE check if the issue already exists (either open or closed) by using the search bar on the issues page. If it does, comment there. Even if it's closed, we can reopen it based on your comment.
|
Before filing, PLEASE check if the issue already exists (either open or closed) by using the search bar on the issues page. If it does, comment there. Even if it's closed, we can reopen it based on your comment.
|
||||||
|
|
||||||
Also, please note the application version in the title of the issue. For example: "[3.2.1] Cannot connect to 3rd-party printer". Please do not write things like "Request:" or "[BUG]" in the title; this is what labels are for.
|
Also, please note the application version in the title of the issue. For example: "[3.2.1] Cannot connect to 3rd-party printer". Please do NOT write things like "Request:" or "[BUG]" in the title; this is what labels are for.
|
||||||
|
|
||||||
It is also helpful to attach a project (.3mf or .curaproject) file and Cura log file so we can debug issues quicker. Information about how to find the log file can be found at https://github.com/Ultimaker/Cura#logging-issues
|
It is also helpful to attach a project (.3mf or .curaproject) file and Cura log file so we can debug issues quicker. Information about how to find the log file can be found at https://github.com/Ultimaker/Cura#logging-issues
|
||||||
|
|
||||||
@ -40,4 +40,4 @@ Thank you for using Cura!
|
|||||||
<!-- What should happen after the above steps have been followed -->
|
<!-- What should happen after the above steps have been followed -->
|
||||||
|
|
||||||
**Additional information**
|
**Additional information**
|
||||||
<!-- Extra information relevant to the issue, like screenshots -->
|
<!-- Extra information relevant to the issue, like screenshots. Don't forget to attach the log files with this issue report. -->
|
||||||
|
@ -20,7 +20,6 @@ set(CURA_APP_NAME "cura" CACHE STRING "Short name of Cura, used for configuratio
|
|||||||
set(CURA_APP_DISPLAY_NAME "Ultimaker Cura" CACHE STRING "Display name of Cura")
|
set(CURA_APP_DISPLAY_NAME "Ultimaker Cura" CACHE STRING "Display name of Cura")
|
||||||
set(CURA_VERSION "master" CACHE STRING "Version name of Cura")
|
set(CURA_VERSION "master" CACHE STRING "Version name of Cura")
|
||||||
set(CURA_BUILDTYPE "" CACHE STRING "Build type of Cura, eg. 'PPA'")
|
set(CURA_BUILDTYPE "" CACHE STRING "Build type of Cura, eg. 'PPA'")
|
||||||
set(CURA_SDK_VERSION "" CACHE STRING "SDK version of Cura")
|
|
||||||
set(CURA_CLOUD_API_ROOT "" CACHE STRING "Alternative Cura cloud API root")
|
set(CURA_CLOUD_API_ROOT "" CACHE STRING "Alternative Cura cloud API root")
|
||||||
set(CURA_CLOUD_API_VERSION "" CACHE STRING "Alternative Cura cloud API version")
|
set(CURA_CLOUD_API_VERSION "" CACHE STRING "Alternative Cura cloud API version")
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@ DEFAULT_CURA_DISPLAY_NAME = "Ultimaker Cura"
|
|||||||
DEFAULT_CURA_VERSION = "master"
|
DEFAULT_CURA_VERSION = "master"
|
||||||
DEFAULT_CURA_BUILD_TYPE = ""
|
DEFAULT_CURA_BUILD_TYPE = ""
|
||||||
DEFAULT_CURA_DEBUG_MODE = False
|
DEFAULT_CURA_DEBUG_MODE = False
|
||||||
DEFAULT_CURA_SDK_VERSION = "6.1.0"
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from cura.CuraVersion import CuraAppName # type: ignore
|
from cura.CuraVersion import CuraAppName # type: ignore
|
||||||
@ -42,9 +41,4 @@ try:
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
CuraDebugMode = DEFAULT_CURA_DEBUG_MODE
|
CuraDebugMode = DEFAULT_CURA_DEBUG_MODE
|
||||||
|
|
||||||
try:
|
from cura.CuraVersion import CuraSDKVersion # type: ignore
|
||||||
from cura.CuraVersion import CuraSDKVersion # type: ignore
|
|
||||||
if CuraSDKVersion == "":
|
|
||||||
CuraSDKVersion = DEFAULT_CURA_SDK_VERSION
|
|
||||||
except ImportError:
|
|
||||||
CuraSDKVersion = DEFAULT_CURA_SDK_VERSION
|
|
||||||
|
@ -1,12 +1,18 @@
|
|||||||
|
#Copyright (c) 2019 Ultimaker B.V.
|
||||||
|
#Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
|
||||||
import numpy
|
import numpy
|
||||||
import copy
|
import copy
|
||||||
|
from typing import Optional, Tuple, TYPE_CHECKING
|
||||||
|
|
||||||
from UM.Math.Polygon import Polygon
|
from UM.Math.Polygon import Polygon
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from UM.Scene.SceneNode import SceneNode
|
||||||
|
|
||||||
## Polygon representation as an array for use with Arrange
|
## Polygon representation as an array for use with Arrange
|
||||||
class ShapeArray:
|
class ShapeArray:
|
||||||
def __init__(self, arr, offset_x, offset_y, scale = 1):
|
def __init__(self, arr: numpy.array, offset_x: float, offset_y: float, scale: float = 1) -> None:
|
||||||
self.arr = arr
|
self.arr = arr
|
||||||
self.offset_x = offset_x
|
self.offset_x = offset_x
|
||||||
self.offset_y = offset_y
|
self.offset_y = offset_y
|
||||||
@ -16,7 +22,7 @@ class ShapeArray:
|
|||||||
# \param vertices
|
# \param vertices
|
||||||
# \param scale scale the coordinates
|
# \param scale scale the coordinates
|
||||||
@classmethod
|
@classmethod
|
||||||
def fromPolygon(cls, vertices, scale = 1):
|
def fromPolygon(cls, vertices: numpy.array, scale: float = 1) -> "ShapeArray":
|
||||||
# scale
|
# scale
|
||||||
vertices = vertices * scale
|
vertices = vertices * scale
|
||||||
# flip y, x -> x, y
|
# flip y, x -> x, y
|
||||||
@ -42,7 +48,7 @@ class ShapeArray:
|
|||||||
# \param min_offset offset for the offset ShapeArray
|
# \param min_offset offset for the offset ShapeArray
|
||||||
# \param scale scale the coordinates
|
# \param scale scale the coordinates
|
||||||
@classmethod
|
@classmethod
|
||||||
def fromNode(cls, node, min_offset, scale = 0.5, include_children = False):
|
def fromNode(cls, node: "SceneNode", min_offset: float, scale: float = 0.5, include_children: bool = False) -> Tuple[Optional["ShapeArray"], Optional["ShapeArray"]]:
|
||||||
transform = node._transformation
|
transform = node._transformation
|
||||||
transform_x = transform._data[0][3]
|
transform_x = transform._data[0][3]
|
||||||
transform_y = transform._data[2][3]
|
transform_y = transform._data[2][3]
|
||||||
@ -88,7 +94,7 @@ class ShapeArray:
|
|||||||
# \param shape numpy format shape, [x-size, y-size]
|
# \param shape numpy format shape, [x-size, y-size]
|
||||||
# \param vertices
|
# \param vertices
|
||||||
@classmethod
|
@classmethod
|
||||||
def arrayFromPolygon(cls, shape, vertices):
|
def arrayFromPolygon(cls, shape: Tuple[int, int], vertices: numpy.array) -> numpy.array:
|
||||||
base_array = numpy.zeros(shape, dtype = numpy.int32) # Initialize your array of zeros
|
base_array = numpy.zeros(shape, dtype = numpy.int32) # Initialize your array of zeros
|
||||||
|
|
||||||
fill = numpy.ones(base_array.shape) * True # Initialize boolean array defining shape fill
|
fill = numpy.ones(base_array.shape) * True # Initialize boolean array defining shape fill
|
||||||
@ -111,9 +117,9 @@ class ShapeArray:
|
|||||||
# \param p2 2-tuple with x, y for point 2
|
# \param p2 2-tuple with x, y for point 2
|
||||||
# \param base_array boolean array to project the line on
|
# \param base_array boolean array to project the line on
|
||||||
@classmethod
|
@classmethod
|
||||||
def _check(cls, p1, p2, base_array):
|
def _check(cls, p1: numpy.array, p2: numpy.array, base_array: numpy.array) -> bool:
|
||||||
if p1[0] == p2[0] and p1[1] == p2[1]:
|
if p1[0] == p2[0] and p1[1] == p2[1]:
|
||||||
return
|
return False
|
||||||
idxs = numpy.indices(base_array.shape) # Create 3D array of indices
|
idxs = numpy.indices(base_array.shape) # Create 3D array of indices
|
||||||
|
|
||||||
p1 = p1.astype(float)
|
p1 = p1.astype(float)
|
||||||
@ -132,4 +138,3 @@ class ShapeArray:
|
|||||||
max_col_idx = (idxs[0] - p1[0]) / (p2[0] - p1[0]) * (p2[1] - p1[1]) + p1[1]
|
max_col_idx = (idxs[0] - p1[0]) / (p2[0] - p1[0]) * (p2[1] - p1[1]) + p1[1]
|
||||||
sign = numpy.sign(p2[0] - p1[0])
|
sign = numpy.sign(p2[0] - p1[0])
|
||||||
return idxs[1] * sign <= max_col_idx * sign
|
return idxs[1] * sign <= max_col_idx * sign
|
||||||
|
|
||||||
|
@ -727,48 +727,17 @@ class BuildVolume(SceneNode):
|
|||||||
|
|
||||||
self._error_areas = []
|
self._error_areas = []
|
||||||
|
|
||||||
extruder_manager = ExtruderManager.getInstance()
|
used_extruders = ExtruderManager.getInstance().getUsedExtruderStacks()
|
||||||
used_extruders = extruder_manager.getUsedExtruderStacks()
|
|
||||||
disallowed_border_size = self.getEdgeDisallowedSize()
|
disallowed_border_size = self.getEdgeDisallowedSize()
|
||||||
|
|
||||||
if not used_extruders:
|
result_areas = self._computeDisallowedAreasStatic(disallowed_border_size, used_extruders) # Normal machine disallowed areas can always be added.
|
||||||
# If no extruder is used, assume that the active extruder is used (else nothing is drawn)
|
|
||||||
if extruder_manager.getActiveExtruderStack():
|
|
||||||
used_extruders = [extruder_manager.getActiveExtruderStack()]
|
|
||||||
else:
|
|
||||||
used_extruders = [self._global_container_stack]
|
|
||||||
|
|
||||||
result_areas = self._computeDisallowedAreasStatic(disallowed_border_size, used_extruders) #Normal machine disallowed areas can always be added.
|
|
||||||
prime_areas = self._computeDisallowedAreasPrimeBlob(disallowed_border_size, used_extruders)
|
prime_areas = self._computeDisallowedAreasPrimeBlob(disallowed_border_size, used_extruders)
|
||||||
result_areas_no_brim = self._computeDisallowedAreasStatic(0, used_extruders) #Where the priming is not allowed to happen. This is not added to the result, just for collision checking.
|
result_areas_no_brim = self._computeDisallowedAreasStatic(0, used_extruders) # Where the priming is not allowed to happen. This is not added to the result, just for collision checking.
|
||||||
prime_disallowed_areas = copy.deepcopy(result_areas_no_brim)
|
|
||||||
|
|
||||||
#Check if prime positions intersect with disallowed areas.
|
# Check if prime positions intersect with disallowed areas.
|
||||||
for extruder in used_extruders:
|
for extruder in used_extruders:
|
||||||
extruder_id = extruder.getId()
|
extruder_id = extruder.getId()
|
||||||
|
|
||||||
collision = False
|
|
||||||
for prime_polygon in prime_areas[extruder_id]:
|
|
||||||
for disallowed_polygon in prime_disallowed_areas[extruder_id]:
|
|
||||||
if prime_polygon.intersectsPolygon(disallowed_polygon) is not None:
|
|
||||||
collision = True
|
|
||||||
break
|
|
||||||
if collision:
|
|
||||||
break
|
|
||||||
|
|
||||||
#Also check other prime positions (without additional offset).
|
|
||||||
for other_extruder_id in prime_areas:
|
|
||||||
if extruder_id == other_extruder_id: #It is allowed to collide with itself.
|
|
||||||
continue
|
|
||||||
for other_prime_polygon in prime_areas[other_extruder_id]:
|
|
||||||
if prime_polygon.intersectsPolygon(other_prime_polygon):
|
|
||||||
collision = True
|
|
||||||
break
|
|
||||||
if collision:
|
|
||||||
break
|
|
||||||
if collision:
|
|
||||||
break
|
|
||||||
|
|
||||||
result_areas[extruder_id].extend(prime_areas[extruder_id])
|
result_areas[extruder_id].extend(prime_areas[extruder_id])
|
||||||
result_areas_no_brim[extruder_id].extend(prime_areas[extruder_id])
|
result_areas_no_brim[extruder_id].extend(prime_areas[extruder_id])
|
||||||
|
|
||||||
@ -776,37 +745,32 @@ class BuildVolume(SceneNode):
|
|||||||
for area in nozzle_disallowed_areas:
|
for area in nozzle_disallowed_areas:
|
||||||
polygon = Polygon(numpy.array(area, numpy.float32))
|
polygon = Polygon(numpy.array(area, numpy.float32))
|
||||||
polygon_disallowed_border = polygon.getMinkowskiHull(Polygon.approximatedCircle(disallowed_border_size))
|
polygon_disallowed_border = polygon.getMinkowskiHull(Polygon.approximatedCircle(disallowed_border_size))
|
||||||
result_areas[extruder_id].append(polygon_disallowed_border) #Don't perform the offset on these.
|
result_areas[extruder_id].append(polygon_disallowed_border) # Don't perform the offset on these.
|
||||||
#polygon_minimal_border = polygon.getMinkowskiHull(5)
|
result_areas_no_brim[extruder_id].append(polygon) # No brim
|
||||||
result_areas_no_brim[extruder_id].append(polygon) # no brim
|
|
||||||
|
|
||||||
# Add prime tower location as disallowed area.
|
# Add prime tower location as disallowed area.
|
||||||
if len(used_extruders) > 1: #No prime tower in single-extrusion.
|
if len([x for x in used_extruders if x.isEnabled]) > 1: # No prime tower if only one extruder is enabled
|
||||||
|
prime_tower_collision = False
|
||||||
if len([x for x in used_extruders if x.isEnabled]) > 1: #No prime tower if only one extruder is enabled
|
prime_tower_areas = self._computeDisallowedAreasPrinted(used_extruders)
|
||||||
prime_tower_collision = False
|
for extruder_id in prime_tower_areas:
|
||||||
prime_tower_areas = self._computeDisallowedAreasPrinted(used_extruders)
|
for area_index, prime_tower_area in enumerate(prime_tower_areas[extruder_id]):
|
||||||
for extruder_id in prime_tower_areas:
|
for area in result_areas[extruder_id]:
|
||||||
for i_area, prime_tower_area in enumerate(prime_tower_areas[extruder_id]):
|
if prime_tower_area.intersectsPolygon(area) is not None:
|
||||||
for area in result_areas[extruder_id]:
|
prime_tower_collision = True
|
||||||
if prime_tower_area.intersectsPolygon(area) is not None:
|
|
||||||
prime_tower_collision = True
|
|
||||||
break
|
|
||||||
if prime_tower_collision: #Already found a collision.
|
|
||||||
break
|
break
|
||||||
if (ExtruderManager.getInstance().getResolveOrValue("prime_tower_brim_enable") and
|
if prime_tower_collision: # Already found a collision.
|
||||||
ExtruderManager.getInstance().getResolveOrValue("adhesion_type") != "raft"):
|
break
|
||||||
prime_tower_areas[extruder_id][i_area] = prime_tower_area.getMinkowskiHull(
|
if self._global_container_stack.getProperty("prime_tower_brim_enable", "value") and self._global_container_stack.getProperty("adhesion_type", "value") != "raft":
|
||||||
Polygon.approximatedCircle(disallowed_border_size))
|
prime_tower_areas[extruder_id][area_index] = prime_tower_area.getMinkowskiHull(Polygon.approximatedCircle(disallowed_border_size))
|
||||||
if not prime_tower_collision:
|
if not prime_tower_collision:
|
||||||
result_areas[extruder_id].extend(prime_tower_areas[extruder_id])
|
result_areas[extruder_id].extend(prime_tower_areas[extruder_id])
|
||||||
result_areas_no_brim[extruder_id].extend(prime_tower_areas[extruder_id])
|
result_areas_no_brim[extruder_id].extend(prime_tower_areas[extruder_id])
|
||||||
else:
|
else:
|
||||||
self._error_areas.extend(prime_tower_areas[extruder_id])
|
self._error_areas.extend(prime_tower_areas[extruder_id])
|
||||||
|
|
||||||
self._has_errors = len(self._error_areas) > 0
|
self._has_errors = len(self._error_areas) > 0
|
||||||
|
|
||||||
self._disallowed_areas = []
|
self._disallowed_areas = [] # type: List[Polygon]
|
||||||
for extruder_id in result_areas:
|
for extruder_id in result_areas:
|
||||||
self._disallowed_areas.extend(result_areas[extruder_id])
|
self._disallowed_areas.extend(result_areas[extruder_id])
|
||||||
self._disallowed_areas_no_brim = []
|
self._disallowed_areas_no_brim = []
|
||||||
@ -823,11 +787,14 @@ class BuildVolume(SceneNode):
|
|||||||
# where that extruder may not print.
|
# where that extruder may not print.
|
||||||
def _computeDisallowedAreasPrinted(self, used_extruders):
|
def _computeDisallowedAreasPrinted(self, used_extruders):
|
||||||
result = {}
|
result = {}
|
||||||
|
adhesion_extruder = None #type: ExtruderStack
|
||||||
for extruder in used_extruders:
|
for extruder in used_extruders:
|
||||||
|
if int(extruder.getProperty("extruder_nr", "value")) == int(self._global_container_stack.getProperty("adhesion_extruder_nr", "value")):
|
||||||
|
adhesion_extruder = extruder
|
||||||
result[extruder.getId()] = []
|
result[extruder.getId()] = []
|
||||||
|
|
||||||
#Currently, the only normally printed object is the prime tower.
|
# Currently, the only normally printed object is the prime tower.
|
||||||
if ExtruderManager.getInstance().getResolveOrValue("prime_tower_enable"):
|
if self._global_container_stack.getProperty("prime_tower_enable", "value"):
|
||||||
prime_tower_size = self._global_container_stack.getProperty("prime_tower_size", "value")
|
prime_tower_size = self._global_container_stack.getProperty("prime_tower_size", "value")
|
||||||
machine_width = self._global_container_stack.getProperty("machine_width", "value")
|
machine_width = self._global_container_stack.getProperty("machine_width", "value")
|
||||||
machine_depth = self._global_container_stack.getProperty("machine_depth", "value")
|
machine_depth = self._global_container_stack.getProperty("machine_depth", "value")
|
||||||
@ -837,12 +804,11 @@ class BuildVolume(SceneNode):
|
|||||||
prime_tower_x = prime_tower_x - machine_width / 2 #Offset by half machine_width and _depth to put the origin in the front-left.
|
prime_tower_x = prime_tower_x - machine_width / 2 #Offset by half machine_width and _depth to put the origin in the front-left.
|
||||||
prime_tower_y = prime_tower_y + machine_depth / 2
|
prime_tower_y = prime_tower_y + machine_depth / 2
|
||||||
|
|
||||||
if (ExtruderManager.getInstance().getResolveOrValue("prime_tower_brim_enable") and
|
if adhesion_extruder is not None and self._global_container_stack.getProperty("prime_tower_brim_enable", "value") and self._global_container_stack.getProperty("adhesion_type", "value") != "raft":
|
||||||
ExtruderManager.getInstance().getResolveOrValue("adhesion_type") != "raft"):
|
|
||||||
brim_size = (
|
brim_size = (
|
||||||
extruder.getProperty("brim_line_count", "value") *
|
adhesion_extruder.getProperty("brim_line_count", "value") *
|
||||||
extruder.getProperty("skirt_brim_line_width", "value") / 100.0 *
|
adhesion_extruder.getProperty("skirt_brim_line_width", "value") / 100.0 *
|
||||||
extruder.getProperty("initial_layer_line_width_factor", "value")
|
adhesion_extruder.getProperty("initial_layer_line_width_factor", "value")
|
||||||
)
|
)
|
||||||
prime_tower_x -= brim_size
|
prime_tower_x -= brim_size
|
||||||
prime_tower_y += brim_size
|
prime_tower_y += brim_size
|
||||||
@ -908,9 +874,12 @@ class BuildVolume(SceneNode):
|
|||||||
# for.
|
# for.
|
||||||
# \return A dictionary with for each used extruder ID the disallowed areas
|
# \return A dictionary with for each used extruder ID the disallowed areas
|
||||||
# where that extruder may not print.
|
# where that extruder may not print.
|
||||||
def _computeDisallowedAreasStatic(self, border_size, used_extruders):
|
def _computeDisallowedAreasStatic(self, border_size:float, used_extruders: List["ExtruderStack"]) -> Dict[str, List[Polygon]]:
|
||||||
#Convert disallowed areas to polygons and dilate them.
|
# Convert disallowed areas to polygons and dilate them.
|
||||||
machine_disallowed_polygons = []
|
machine_disallowed_polygons = []
|
||||||
|
if self._global_container_stack is None:
|
||||||
|
return {}
|
||||||
|
|
||||||
for area in self._global_container_stack.getProperty("machine_disallowed_areas", "value"):
|
for area in self._global_container_stack.getProperty("machine_disallowed_areas", "value"):
|
||||||
polygon = Polygon(numpy.array(area, numpy.float32))
|
polygon = Polygon(numpy.array(area, numpy.float32))
|
||||||
polygon = polygon.getMinkowskiHull(Polygon.approximatedCircle(border_size))
|
polygon = polygon.getMinkowskiHull(Polygon.approximatedCircle(border_size))
|
||||||
@ -921,7 +890,7 @@ class BuildVolume(SceneNode):
|
|||||||
nozzle_offsetting_for_disallowed_areas = self._global_container_stack.getMetaDataEntry(
|
nozzle_offsetting_for_disallowed_areas = self._global_container_stack.getMetaDataEntry(
|
||||||
"nozzle_offsetting_for_disallowed_areas", True)
|
"nozzle_offsetting_for_disallowed_areas", True)
|
||||||
|
|
||||||
result = {}
|
result = {} # type: Dict[str, List[Polygon]]
|
||||||
for extruder in used_extruders:
|
for extruder in used_extruders:
|
||||||
extruder_id = extruder.getId()
|
extruder_id = extruder.getId()
|
||||||
offset_x = extruder.getProperty("machine_nozzle_offset_x", "value")
|
offset_x = extruder.getProperty("machine_nozzle_offset_x", "value")
|
||||||
@ -930,13 +899,13 @@ class BuildVolume(SceneNode):
|
|||||||
offset_y = extruder.getProperty("machine_nozzle_offset_y", "value")
|
offset_y = extruder.getProperty("machine_nozzle_offset_y", "value")
|
||||||
if offset_y is None:
|
if offset_y is None:
|
||||||
offset_y = 0
|
offset_y = 0
|
||||||
offset_y = -offset_y #Y direction of g-code is the inverse of Y direction of Cura's scene space.
|
offset_y = -offset_y # Y direction of g-code is the inverse of Y direction of Cura's scene space.
|
||||||
result[extruder_id] = []
|
result[extruder_id] = []
|
||||||
|
|
||||||
for polygon in machine_disallowed_polygons:
|
for polygon in machine_disallowed_polygons:
|
||||||
result[extruder_id].append(polygon.translate(offset_x, offset_y)) #Compensate for the nozzle offset of this extruder.
|
result[extruder_id].append(polygon.translate(offset_x, offset_y)) # Compensate for the nozzle offset of this extruder.
|
||||||
|
|
||||||
#Add the border around the edge of the build volume.
|
# Add the border around the edge of the build volume.
|
||||||
left_unreachable_border = 0
|
left_unreachable_border = 0
|
||||||
right_unreachable_border = 0
|
right_unreachable_border = 0
|
||||||
top_unreachable_border = 0
|
top_unreachable_border = 0
|
||||||
@ -944,7 +913,8 @@ class BuildVolume(SceneNode):
|
|||||||
|
|
||||||
# Only do nozzle offsetting if needed
|
# Only do nozzle offsetting if needed
|
||||||
if nozzle_offsetting_for_disallowed_areas:
|
if nozzle_offsetting_for_disallowed_areas:
|
||||||
#The build volume is defined as the union of the area that all extruders can reach, so we need to know the relative offset to all extruders.
|
# The build volume is defined as the union of the area that all extruders can reach, so we need to know
|
||||||
|
# the relative offset to all extruders.
|
||||||
for other_extruder in ExtruderManager.getInstance().getActiveExtruderStacks():
|
for other_extruder in ExtruderManager.getInstance().getActiveExtruderStacks():
|
||||||
other_offset_x = other_extruder.getProperty("machine_nozzle_offset_x", "value")
|
other_offset_x = other_extruder.getProperty("machine_nozzle_offset_x", "value")
|
||||||
if other_offset_x is None:
|
if other_offset_x is None:
|
||||||
@ -1028,8 +998,8 @@ class BuildVolume(SceneNode):
|
|||||||
[ half_machine_width - border_size, 0]
|
[ half_machine_width - border_size, 0]
|
||||||
], numpy.float32)))
|
], numpy.float32)))
|
||||||
result[extruder_id].append(Polygon(numpy.array([
|
result[extruder_id].append(Polygon(numpy.array([
|
||||||
[ half_machine_width,-half_machine_depth],
|
[ half_machine_width, -half_machine_depth],
|
||||||
[-half_machine_width,-half_machine_depth],
|
[-half_machine_width, -half_machine_depth],
|
||||||
[ 0, -half_machine_depth + border_size]
|
[ 0, -half_machine_depth + border_size]
|
||||||
], numpy.float32)))
|
], numpy.float32)))
|
||||||
|
|
||||||
|
@ -6,7 +6,9 @@ CuraAppDisplayName = "@CURA_APP_DISPLAY_NAME@"
|
|||||||
CuraVersion = "@CURA_VERSION@"
|
CuraVersion = "@CURA_VERSION@"
|
||||||
CuraBuildType = "@CURA_BUILDTYPE@"
|
CuraBuildType = "@CURA_BUILDTYPE@"
|
||||||
CuraDebugMode = True if "@_cura_debugmode@" == "ON" else False
|
CuraDebugMode = True if "@_cura_debugmode@" == "ON" else False
|
||||||
CuraSDKVersion = "@CURA_SDK_VERSION@"
|
|
||||||
|
CuraSDKVersion = "6.1.0"
|
||||||
|
|
||||||
CuraCloudAPIRoot = "@CURA_CLOUD_API_ROOT@"
|
CuraCloudAPIRoot = "@CURA_CLOUD_API_ROOT@"
|
||||||
CuraCloudAPIVersion = "@CURA_CLOUD_API_VERSION@"
|
CuraCloudAPIVersion = "@CURA_CLOUD_API_VERSION@"
|
||||||
CuraCloudAccountAPIRoot = "@CURA_CLOUD_ACCOUNT_API_ROOT@"
|
CuraCloudAccountAPIRoot = "@CURA_CLOUD_ACCOUNT_API_ROOT@"
|
||||||
|
@ -205,7 +205,7 @@ class ExtruderManager(QObject):
|
|||||||
# list.
|
# list.
|
||||||
#
|
#
|
||||||
# \return A list of extruder stacks.
|
# \return A list of extruder stacks.
|
||||||
def getUsedExtruderStacks(self) -> List["ContainerStack"]:
|
def getUsedExtruderStacks(self) -> List["ExtruderStack"]:
|
||||||
global_stack = self._application.getGlobalContainerStack()
|
global_stack = self._application.getGlobalContainerStack()
|
||||||
container_registry = ContainerRegistry.getInstance()
|
container_registry = ContainerRegistry.getInstance()
|
||||||
|
|
||||||
|
@ -986,8 +986,9 @@ class MachineManager(QObject):
|
|||||||
self._application.globalContainerStackChanged.emit()
|
self._application.globalContainerStackChanged.emit()
|
||||||
self.forceUpdateAllSettings()
|
self.forceUpdateAllSettings()
|
||||||
|
|
||||||
|
# Note that this function is deprecated, but the decorators for this don't play well together!
|
||||||
|
# @deprecated("use Cura.MachineManager.activeMachine.extruders instead", "4.2")
|
||||||
@pyqtSlot(int, result = QObject)
|
@pyqtSlot(int, result = QObject)
|
||||||
@deprecated("use Cura.MachineManager.activeMachine.extruders instead", "4.2")
|
|
||||||
def getExtruder(self, position: int) -> Optional[ExtruderStack]:
|
def getExtruder(self, position: int) -> Optional[ExtruderStack]:
|
||||||
if self._global_container_stack:
|
if self._global_container_stack:
|
||||||
return self._global_container_stack.extruders.get(str(position))
|
return self._global_container_stack.extruders.get(str(position))
|
||||||
|
@ -8,7 +8,6 @@ from UM.PluginRegistry import PluginRegistry
|
|||||||
from UM.Logger import Logger
|
from UM.Logger import Logger
|
||||||
from UM.Settings.ContainerFormatError import ContainerFormatError
|
from UM.Settings.ContainerFormatError import ContainerFormatError
|
||||||
from UM.Settings.InstanceContainer import InstanceContainer # The new profile to make.
|
from UM.Settings.InstanceContainer import InstanceContainer # The new profile to make.
|
||||||
from cura.CuraApplication import CuraApplication #To get the current setting version.
|
|
||||||
from cura.ReaderWriters.ProfileReader import ProfileReader
|
from cura.ReaderWriters.ProfileReader import ProfileReader
|
||||||
|
|
||||||
import zipfile
|
import zipfile
|
||||||
@ -32,7 +31,7 @@ class CuraProfileReader(ProfileReader):
|
|||||||
def read(self, file_name: str) -> List[Optional[InstanceContainer]]:
|
def read(self, file_name: str) -> List[Optional[InstanceContainer]]:
|
||||||
try:
|
try:
|
||||||
with zipfile.ZipFile(file_name, "r") as archive:
|
with zipfile.ZipFile(file_name, "r") as archive:
|
||||||
results = [] #type: List[Optional[InstanceContainer]]
|
results = [] # type: List[Optional[InstanceContainer]]
|
||||||
for profile_id in archive.namelist():
|
for profile_id in archive.namelist():
|
||||||
with archive.open(profile_id) as f:
|
with archive.open(profile_id) as f:
|
||||||
serialized = f.read()
|
serialized = f.read()
|
||||||
@ -68,7 +67,7 @@ class CuraProfileReader(ProfileReader):
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
version = int(parser["general"]["version"])
|
version = int(parser["general"]["version"])
|
||||||
if InstanceContainer.Version != version or "metadata" not in parser or "setting_version" not in parser["metadata"] or parser["metadata"]["setting_version"] != str(CuraApplication.SettingVersion):
|
if InstanceContainer.Version != version:
|
||||||
name = parser["general"]["name"]
|
name = parser["general"]["name"]
|
||||||
return self._upgradeProfileVersion(serialized, name, version)
|
return self._upgradeProfileVersion(serialized, name, version)
|
||||||
else:
|
else:
|
||||||
@ -107,9 +106,11 @@ class CuraProfileReader(ProfileReader):
|
|||||||
if source_format in plugin["version_upgrade"] and plugin["version_upgrade"][source_format][1] == InstanceContainer.Version]
|
if source_format in plugin["version_upgrade"] and plugin["version_upgrade"][source_format][1] == InstanceContainer.Version]
|
||||||
|
|
||||||
if not profile_convert_funcs:
|
if not profile_convert_funcs:
|
||||||
|
Logger.log("w", "Unable to find an upgrade path for the profile [%s]", profile_id)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
filenames, outputs = profile_convert_funcs[0](serialized, profile_id)
|
filenames, outputs = profile_convert_funcs[0](serialized, profile_id)
|
||||||
if filenames is None and outputs is None:
|
if filenames is None and outputs is None:
|
||||||
|
Logger.log("w", "The conversion failed to return any usable data for [%s]", profile_id)
|
||||||
return []
|
return []
|
||||||
return list(zip(outputs, filenames))
|
return list(zip(outputs, filenames))
|
||||||
|
@ -81,7 +81,7 @@ Item
|
|||||||
enabled: visible && !(printJob.state == "pausing" || printJob.state == "resuming");
|
enabled: visible && !(printJob.state == "pausing" || printJob.state == "resuming");
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (printJob.state == "paused") {
|
if (printJob.state == "paused") {
|
||||||
printJob.setState("print");
|
printJob.setState("resume");
|
||||||
popUp.close();
|
popUp.close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -22,10 +22,6 @@ Item
|
|||||||
// The print job which all other data is derived from
|
// The print job which all other data is derived from
|
||||||
property var printJob: null
|
property var printJob: null
|
||||||
|
|
||||||
// If the printer is a cloud printer or not. Other items base their enabled state off of this boolean. In the future
|
|
||||||
// they might not need to though.
|
|
||||||
property bool cloudConnection: Cura.MachineManager.activeMachineIsUsingCloudConnection
|
|
||||||
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: childrenRect.height
|
height: childrenRect.height
|
||||||
|
|
||||||
@ -217,7 +213,7 @@ Item
|
|||||||
}
|
}
|
||||||
width: 32 * screenScaleFactor // TODO: Theme!
|
width: 32 * screenScaleFactor // TODO: Theme!
|
||||||
height: 32 * screenScaleFactor // TODO: Theme!
|
height: 32 * screenScaleFactor // TODO: Theme!
|
||||||
enabled: !cloudConnection
|
enabled: OutputDevice.supportsPrintJobActions
|
||||||
onClicked: enabled ? contextMenu.switchPopupState() : {}
|
onClicked: enabled ? contextMenu.switchPopupState() : {}
|
||||||
visible:
|
visible:
|
||||||
{
|
{
|
||||||
@ -250,7 +246,7 @@ Item
|
|||||||
MonitorInfoBlurb
|
MonitorInfoBlurb
|
||||||
{
|
{
|
||||||
id: contextMenuDisabledInfo
|
id: contextMenuDisabledInfo
|
||||||
text: catalog.i18nc("@info", "These options are not available because you are monitoring a cloud printer.")
|
text: catalog.i18nc("@info", "Please update your printer's firmware to manage the queue remotely.")
|
||||||
target: contextMenuButton
|
target: contextMenuButton
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -172,8 +172,7 @@ Item
|
|||||||
}
|
}
|
||||||
width: 36 * screenScaleFactor // TODO: Theme!
|
width: 36 * screenScaleFactor // TODO: Theme!
|
||||||
height: 36 * screenScaleFactor // TODO: Theme!
|
height: 36 * screenScaleFactor // TODO: Theme!
|
||||||
enabled: !cloudConnection
|
enabled: OutputDevice.supportsPrintJobActions
|
||||||
|
|
||||||
onClicked: enabled ? contextMenu.switchPopupState() : {}
|
onClicked: enabled ? contextMenu.switchPopupState() : {}
|
||||||
visible:
|
visible:
|
||||||
{
|
{
|
||||||
@ -206,7 +205,7 @@ Item
|
|||||||
MonitorInfoBlurb
|
MonitorInfoBlurb
|
||||||
{
|
{
|
||||||
id: contextMenuDisabledInfo
|
id: contextMenuDisabledInfo
|
||||||
text: catalog.i18nc("@info", "These options are not available because you are monitoring a cloud printer.")
|
text: catalog.i18nc("@info", "Please update your printer's firmware to manage the queue remotely.")
|
||||||
target: contextMenuButton
|
target: contextMenuButton
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,7 +243,6 @@ Item
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Divider
|
// Divider
|
||||||
Rectangle
|
Rectangle
|
||||||
{
|
{
|
||||||
|
@ -42,7 +42,6 @@ Item
|
|||||||
}
|
}
|
||||||
height: 18 * screenScaleFactor // TODO: Theme!
|
height: 18 * screenScaleFactor // TODO: Theme!
|
||||||
width: childrenRect.width
|
width: childrenRect.width
|
||||||
visible: !cloudConnection
|
|
||||||
|
|
||||||
UM.RecolorImage
|
UM.RecolorImage
|
||||||
{
|
{
|
||||||
@ -65,7 +64,7 @@ Item
|
|||||||
color: UM.Theme.getColor("monitor_text_link")
|
color: UM.Theme.getColor("monitor_text_link")
|
||||||
font: UM.Theme.getFont("medium") // 14pt, regular
|
font: UM.Theme.getFont("medium") // 14pt, regular
|
||||||
linkColor: UM.Theme.getColor("monitor_text_link")
|
linkColor: UM.Theme.getColor("monitor_text_link")
|
||||||
text: catalog.i18nc("@label link to connect manager", "Go to Cura Connect")
|
text: catalog.i18nc("@label link to connect manager", "Manage in browser")
|
||||||
renderType: Text.NativeRendering
|
renderType: Text.NativeRendering
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -73,9 +72,7 @@ Item
|
|||||||
MouseArea
|
MouseArea
|
||||||
{
|
{
|
||||||
anchors.fill: manageQueueLabel
|
anchors.fill: manageQueueLabel
|
||||||
enabled: !cloudConnection
|
onClicked: OutputDevice.openPrintJobControlPanel()
|
||||||
hoverEnabled: !cloudConnection
|
|
||||||
onClicked: Cura.MachineManager.printerOutputDevices[0].openPrintJobControlPanel()
|
|
||||||
onEntered:
|
onEntered:
|
||||||
{
|
{
|
||||||
manageQueueText.font.underline = true
|
manageQueueText.font.underline = true
|
||||||
@ -198,8 +195,7 @@ Item
|
|||||||
color: UM.Theme.getColor("monitor_card_background")
|
color: UM.Theme.getColor("monitor_card_background")
|
||||||
border.color: UM.Theme.getColor("monitor_card_border")
|
border.color: UM.Theme.getColor("monitor_card_border")
|
||||||
radius: 2 * screenScaleFactor // TODO: Theme!
|
radius: 2 * screenScaleFactor // TODO: Theme!
|
||||||
|
visible: OutputDevice.printJobs.length == 0
|
||||||
visible: printJobList.model.length == 0
|
|
||||||
|
|
||||||
Row
|
Row
|
||||||
{
|
{
|
||||||
@ -249,14 +245,14 @@ Item
|
|||||||
color: UM.Theme.getColor("monitor_text_link")
|
color: UM.Theme.getColor("monitor_text_link")
|
||||||
font: UM.Theme.getFont("medium") // 14pt, regular
|
font: UM.Theme.getFont("medium") // 14pt, regular
|
||||||
linkColor: UM.Theme.getColor("monitor_text_link")
|
linkColor: UM.Theme.getColor("monitor_text_link")
|
||||||
text: catalog.i18nc("@label link to connect manager", "View print history")
|
text: catalog.i18nc("@label link to connect manager", "Manage in browser")
|
||||||
renderType: Text.NativeRendering
|
renderType: Text.NativeRendering
|
||||||
}
|
}
|
||||||
MouseArea
|
MouseArea
|
||||||
{
|
{
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
onClicked: Cura.MachineManager.printerOutputDevices[0].openPrintJobControlPanel()
|
onClicked: OutputDevice.openPrintJobControlPanel()
|
||||||
onEntered:
|
onEntered:
|
||||||
{
|
{
|
||||||
viewPrintHistoryText.font.underline = true
|
viewPrintHistoryText.font.underline = true
|
||||||
|
@ -96,6 +96,21 @@ class CloudApiClient:
|
|||||||
reply = self._manager.post(self._createEmptyRequest(url), b"")
|
reply = self._manager.post(self._createEmptyRequest(url), b"")
|
||||||
self._addCallback(reply, on_finished, CloudPrintResponse)
|
self._addCallback(reply, on_finished, CloudPrintResponse)
|
||||||
|
|
||||||
|
## Send a print job action to the cluster for the given print job.
|
||||||
|
# \param cluster_id: The ID of the cluster.
|
||||||
|
# \param cluster_job_id: The ID of the print job within the cluster.
|
||||||
|
# \param action: The name of the action to execute.
|
||||||
|
def doPrintJobAction(self, cluster_id: str, cluster_job_id: str, action: str, data: Optional[Dict[str, Any]] = None) -> None:
|
||||||
|
body = b""
|
||||||
|
if data:
|
||||||
|
try:
|
||||||
|
body = json.dumps({"data": data}).encode()
|
||||||
|
except JSONDecodeError as err:
|
||||||
|
Logger.log("w", "Could not encode body: %s", err)
|
||||||
|
return
|
||||||
|
url = "{}/clusters/{}/print_jobs/{}/action/{}".format(self.CLUSTER_API_ROOT, cluster_id, cluster_job_id, action)
|
||||||
|
self._manager.post(self._createEmptyRequest(url), body)
|
||||||
|
|
||||||
## We override _createEmptyRequest in order to add the user credentials.
|
## We override _createEmptyRequest in order to add the user credentials.
|
||||||
# \param url: The URL to request
|
# \param url: The URL to request
|
||||||
# \param content_type: The type of the body contents.
|
# \param content_type: The type of the body contents.
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
# Copyright (c) 2018 Ultimaker B.V.
|
# Copyright (c) 2018 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the LGPLv3 or higher.
|
# Cura is released under the terms of the LGPLv3 or higher.
|
||||||
|
from cura.PrinterOutput.Models.PrintJobOutputModel import PrintJobOutputModel
|
||||||
from cura.PrinterOutput.PrinterOutputController import PrinterOutputController
|
from cura.PrinterOutput.PrinterOutputController import PrinterOutputController
|
||||||
|
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING
|
||||||
@ -13,10 +14,13 @@ class CloudOutputController(PrinterOutputController):
|
|||||||
|
|
||||||
# The cloud connection only supports fetching the printer and queue status and adding a job to the queue.
|
# The cloud connection only supports fetching the printer and queue status and adding a job to the queue.
|
||||||
# To let the UI know this we mark all features below as False.
|
# To let the UI know this we mark all features below as False.
|
||||||
self.can_pause = False
|
self.can_pause = True
|
||||||
self.can_abort = False
|
self.can_abort = True
|
||||||
self.can_pre_heat_bed = False
|
self.can_pre_heat_bed = False
|
||||||
self.can_pre_heat_hotends = False
|
self.can_pre_heat_hotends = False
|
||||||
self.can_send_raw_gcode = False
|
self.can_send_raw_gcode = False
|
||||||
self.can_control_manually = False
|
self.can_control_manually = False
|
||||||
self.can_update_firmware = False
|
self.can_update_firmware = False
|
||||||
|
|
||||||
|
def setJobState(self, job: "PrintJobOutputModel", state: str):
|
||||||
|
self._output_device.setJobState(job.key, state)
|
||||||
|
@ -6,6 +6,7 @@ from time import time
|
|||||||
from typing import Dict, List, Optional, Set, cast
|
from typing import Dict, List, Optional, Set, cast
|
||||||
|
|
||||||
from PyQt5.QtCore import QObject, QUrl, pyqtProperty, pyqtSignal, pyqtSlot
|
from PyQt5.QtCore import QObject, QUrl, pyqtProperty, pyqtSignal, pyqtSlot
|
||||||
|
from PyQt5.QtGui import QDesktopServices
|
||||||
|
|
||||||
from UM import i18nCatalog
|
from UM import i18nCatalog
|
||||||
from UM.Backend.Backend import BackendState
|
from UM.Backend.Backend import BackendState
|
||||||
@ -15,6 +16,7 @@ from UM.Message import Message
|
|||||||
from UM.PluginRegistry import PluginRegistry
|
from UM.PluginRegistry import PluginRegistry
|
||||||
from UM.Qt.Duration import Duration, DurationFormat
|
from UM.Qt.Duration import Duration, DurationFormat
|
||||||
from UM.Scene.SceneNode import SceneNode
|
from UM.Scene.SceneNode import SceneNode
|
||||||
|
from UM.Version import Version
|
||||||
|
|
||||||
from cura.CuraApplication import CuraApplication
|
from cura.CuraApplication import CuraApplication
|
||||||
from cura.PrinterOutput.NetworkedPrinterOutputDevice import AuthState, NetworkedPrinterOutputDevice
|
from cura.PrinterOutput.NetworkedPrinterOutputDevice import AuthState, NetworkedPrinterOutputDevice
|
||||||
@ -48,6 +50,9 @@ class CloudOutputDevice(NetworkedPrinterOutputDevice):
|
|||||||
# The interval with which the remote clusters are checked
|
# The interval with which the remote clusters are checked
|
||||||
CHECK_CLUSTER_INTERVAL = 10.0 # seconds
|
CHECK_CLUSTER_INTERVAL = 10.0 # seconds
|
||||||
|
|
||||||
|
# The minimum version of firmware that support print job actions over cloud.
|
||||||
|
PRINT_JOB_ACTIONS_MIN_VERSION = Version("5.3.0")
|
||||||
|
|
||||||
# Signal triggered when the print jobs in the queue were changed.
|
# Signal triggered when the print jobs in the queue were changed.
|
||||||
printJobsChanged = pyqtSignal()
|
printJobsChanged = pyqtSignal()
|
||||||
|
|
||||||
@ -359,6 +364,13 @@ class CloudOutputDevice(NetworkedPrinterOutputDevice):
|
|||||||
).show()
|
).show()
|
||||||
self.writeFinished.emit()
|
self.writeFinished.emit()
|
||||||
|
|
||||||
|
## Whether the printer that this output device represents supports print job actions via the cloud.
|
||||||
|
@pyqtProperty(bool, notify = _clusterPrintersChanged)
|
||||||
|
def supportsPrintJobActions(self) -> bool:
|
||||||
|
version_number = self.printers[0].firmwareVersion.split(".")
|
||||||
|
firmware_version = Version([version_number[0], version_number[1], version_number[2]])
|
||||||
|
return firmware_version >= self.PRINT_JOB_ACTIONS_MIN_VERSION
|
||||||
|
|
||||||
## Gets the number of printers in the cluster.
|
## Gets the number of printers in the cluster.
|
||||||
# We use a minimum of 1 because cloud devices are always a cluster and printer discovery needs it.
|
# We use a minimum of 1 because cloud devices are always a cluster and printer discovery needs it.
|
||||||
@pyqtProperty(int, notify = _clusterPrintersChanged)
|
@pyqtProperty(int, notify = _clusterPrintersChanged)
|
||||||
@ -399,6 +411,22 @@ class CloudOutputDevice(NetworkedPrinterOutputDevice):
|
|||||||
return [print_job for print_job in self._print_jobs if
|
return [print_job for print_job in self._print_jobs if
|
||||||
print_job.assignedPrinter is not None and print_job.state != "queued"]
|
print_job.assignedPrinter is not None and print_job.state != "queued"]
|
||||||
|
|
||||||
|
def setJobState(self, print_job_uuid: str, state: str) -> None:
|
||||||
|
self._api.doPrintJobAction(self._cluster.cluster_id, print_job_uuid, state)
|
||||||
|
|
||||||
|
@pyqtSlot(str)
|
||||||
|
def sendJobToTop(self, print_job_uuid: str) -> None:
|
||||||
|
self._api.doPrintJobAction(self._cluster.cluster_id, print_job_uuid, "move",
|
||||||
|
{"list": "queued", "to_position": 0})
|
||||||
|
|
||||||
|
@pyqtSlot(str)
|
||||||
|
def deleteJobFromQueue(self, print_job_uuid: str) -> None:
|
||||||
|
self._api.doPrintJobAction(self._cluster.cluster_id, print_job_uuid, "remove")
|
||||||
|
|
||||||
|
@pyqtSlot(str)
|
||||||
|
def forceSendJob(self, print_job_uuid: str) -> None:
|
||||||
|
self._api.doPrintJobAction(self._cluster.cluster_id, print_job_uuid, "force")
|
||||||
|
|
||||||
@pyqtSlot(int, result = str)
|
@pyqtSlot(int, result = str)
|
||||||
def formatDuration(self, seconds: int) -> str:
|
def formatDuration(self, seconds: int) -> str:
|
||||||
return Duration(seconds).getDisplayString(DurationFormat.Format.Short)
|
return Duration(seconds).getDisplayString(DurationFormat.Format.Short)
|
||||||
@ -411,6 +439,18 @@ class CloudOutputDevice(NetworkedPrinterOutputDevice):
|
|||||||
def getDateCompleted(self, time_remaining: int) -> str:
|
def getDateCompleted(self, time_remaining: int) -> str:
|
||||||
return formatDateCompleted(time_remaining)
|
return formatDateCompleted(time_remaining)
|
||||||
|
|
||||||
|
@pyqtProperty(bool, notify=printJobsChanged)
|
||||||
|
def receivedPrintJobs(self) -> bool:
|
||||||
|
return bool(self._print_jobs)
|
||||||
|
|
||||||
|
@pyqtSlot()
|
||||||
|
def openPrintJobControlPanel(self) -> None:
|
||||||
|
QDesktopServices.openUrl(QUrl("https://mycloud.ultimaker.com"))
|
||||||
|
|
||||||
|
@pyqtSlot()
|
||||||
|
def openPrinterControlPanel(self) -> None:
|
||||||
|
QDesktopServices.openUrl(QUrl("https://mycloud.ultimaker.com"))
|
||||||
|
|
||||||
## TODO: The following methods are required by the monitor page QML, but are not actually available using cloud.
|
## TODO: The following methods are required by the monitor page QML, but are not actually available using cloud.
|
||||||
# TODO: We fake the methods here to not break the monitor page.
|
# TODO: We fake the methods here to not break the monitor page.
|
||||||
|
|
||||||
@ -422,30 +462,6 @@ class CloudOutputDevice(NetworkedPrinterOutputDevice):
|
|||||||
def setActiveCameraUrl(self, camera_url: "QUrl") -> None:
|
def setActiveCameraUrl(self, camera_url: "QUrl") -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@pyqtProperty(bool, notify = printJobsChanged)
|
|
||||||
def receivedPrintJobs(self) -> bool:
|
|
||||||
return bool(self._print_jobs)
|
|
||||||
|
|
||||||
@pyqtSlot()
|
|
||||||
def openPrintJobControlPanel(self) -> None:
|
|
||||||
pass
|
|
||||||
|
|
||||||
@pyqtSlot()
|
|
||||||
def openPrinterControlPanel(self) -> None:
|
|
||||||
pass
|
|
||||||
|
|
||||||
@pyqtSlot(str)
|
|
||||||
def sendJobToTop(self, print_job_uuid: str) -> None:
|
|
||||||
pass
|
|
||||||
|
|
||||||
@pyqtSlot(str)
|
|
||||||
def deleteJobFromQueue(self, print_job_uuid: str) -> None:
|
|
||||||
pass
|
|
||||||
|
|
||||||
@pyqtSlot(str)
|
|
||||||
def forceSendJob(self, print_job_uuid: str) -> None:
|
|
||||||
pass
|
|
||||||
|
|
||||||
@pyqtProperty("QVariantList", notify = _clusterPrintersChanged)
|
@pyqtProperty("QVariantList", notify = _clusterPrintersChanged)
|
||||||
def connectedPrintersTypeCount(self) -> List[Dict[str, str]]:
|
def connectedPrintersTypeCount(self) -> List[Dict[str, str]]:
|
||||||
return []
|
return []
|
||||||
|
@ -91,7 +91,6 @@ class CloudClusterPrintJobStatus(BaseCloudModel):
|
|||||||
def createOutputModel(self, controller: CloudOutputController) -> UM3PrintJobOutputModel:
|
def createOutputModel(self, controller: CloudOutputController) -> UM3PrintJobOutputModel:
|
||||||
model = UM3PrintJobOutputModel(controller, self.uuid, self.name)
|
model = UM3PrintJobOutputModel(controller, self.uuid, self.name)
|
||||||
self.updateOutputModel(model)
|
self.updateOutputModel(model)
|
||||||
|
|
||||||
return model
|
return model
|
||||||
|
|
||||||
## Creates a new configuration model
|
## Creates a new configuration model
|
||||||
|
@ -140,6 +140,11 @@ class ClusterUM3OutputDevice(NetworkedPrinterOutputDevice):
|
|||||||
if self._printer_selection_dialog is not None:
|
if self._printer_selection_dialog is not None:
|
||||||
self._printer_selection_dialog.show()
|
self._printer_selection_dialog.show()
|
||||||
|
|
||||||
|
## Whether the printer that this output device represents supports print job actions via the local network.
|
||||||
|
@pyqtProperty(bool, constant=True)
|
||||||
|
def supportsPrintJobActions(self) -> bool:
|
||||||
|
return True
|
||||||
|
|
||||||
@pyqtProperty(int, constant=True)
|
@pyqtProperty(int, constant=True)
|
||||||
def clusterSize(self) -> int:
|
def clusterSize(self) -> int:
|
||||||
return self._cluster_size
|
return self._cluster_size
|
||||||
|
@ -27,7 +27,7 @@ from UM.Version import Version
|
|||||||
|
|
||||||
from . import ClusterUM3OutputDevice, LegacyUM3OutputDevice
|
from . import ClusterUM3OutputDevice, LegacyUM3OutputDevice
|
||||||
from .Cloud.CloudOutputDeviceManager import CloudOutputDeviceManager
|
from .Cloud.CloudOutputDeviceManager import CloudOutputDeviceManager
|
||||||
from .Cloud.CloudOutputDevice import CloudOutputDevice # typing
|
from .Cloud.CloudOutputDevice import CloudOutputDevice # typing
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from PyQt5.QtNetwork import QNetworkReply
|
from PyQt5.QtNetwork import QNetworkReply
|
||||||
|
@ -72,9 +72,9 @@ class TestCloudOutputDevice(TestCase):
|
|||||||
|
|
||||||
controller_fields = {
|
controller_fields = {
|
||||||
"_output_device": self.device,
|
"_output_device": self.device,
|
||||||
"can_abort": False,
|
"can_abort": True,
|
||||||
"can_control_manually": False,
|
"can_control_manually": False,
|
||||||
"can_pause": False,
|
"can_pause": True,
|
||||||
"can_pre_heat_bed": False,
|
"can_pre_heat_bed": False,
|
||||||
"can_pre_heat_hotends": False,
|
"can_pre_heat_hotends": False,
|
||||||
"can_send_raw_gcode": False,
|
"can_send_raw_gcode": False,
|
||||||
|
@ -1196,6 +1196,13 @@ class XmlMaterialProfile(InstanceContainer):
|
|||||||
"surface energy": "material_surface_energy",
|
"surface energy": "material_surface_energy",
|
||||||
"shrinkage percentage": "material_shrinkage_percentage",
|
"shrinkage percentage": "material_shrinkage_percentage",
|
||||||
"build volume temperature": "build_volume_temperature",
|
"build volume temperature": "build_volume_temperature",
|
||||||
|
"anti ooze retracted position": "material_anti_ooze_retracted_position",
|
||||||
|
"anti ooze retract speed": "material_anti_ooze_retraction_speed",
|
||||||
|
"break preparation retracted position": "material_break_preparation_retracted_position",
|
||||||
|
"break preparation speed": "material_break_preparation_speed",
|
||||||
|
"break retracted position": "material_break_retracted_position",
|
||||||
|
"break speed": "material_break_speed",
|
||||||
|
"break temperature": "material_break_temperature"
|
||||||
}
|
}
|
||||||
__unmapped_settings = [
|
__unmapped_settings = [
|
||||||
"hardware compatible",
|
"hardware compatible",
|
||||||
|
@ -66,7 +66,7 @@
|
|||||||
"material_print_temperature_layer_0": { "default_value": 220 },
|
"material_print_temperature_layer_0": { "default_value": 220 },
|
||||||
"material_initial_print_temperature": { "default_value": 220 },
|
"material_initial_print_temperature": { "default_value": 220 },
|
||||||
"material_final_print_temperature": { "default_value": 220 },
|
"material_final_print_temperature": { "default_value": 220 },
|
||||||
"retraction_amount": { "default_value": 4 },
|
"retraction_amount": { "default_value": 6.5 },
|
||||||
|
|
||||||
"speed_print": { "default_value": 40 },
|
"speed_print": { "default_value": 40 },
|
||||||
"speed_infill": { "default_value": 60 },
|
"speed_infill": { "default_value": 60 },
|
||||||
|
@ -963,20 +963,20 @@
|
|||||||
"maximum_value_warning": "2 * machine_nozzle_size",
|
"maximum_value_warning": "2 * machine_nozzle_size",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": true
|
"settable_per_extruder": true
|
||||||
},
|
|
||||||
"initial_layer_line_width_factor":
|
|
||||||
{
|
|
||||||
"label": "Initial Layer Line Width",
|
|
||||||
"description": "Multiplier of the line width on the first layer. Increasing this could improve bed adhesion.",
|
|
||||||
"type": "float",
|
|
||||||
"unit": "%",
|
|
||||||
"default_value": 100.0,
|
|
||||||
"minimum_value": "0.001",
|
|
||||||
"maximum_value_warning": "150",
|
|
||||||
"settable_per_mesh": false,
|
|
||||||
"settable_per_extruder": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"initial_layer_line_width_factor":
|
||||||
|
{
|
||||||
|
"label": "Initial Layer Line Width",
|
||||||
|
"description": "Multiplier of the line width on the first layer. Increasing this could improve bed adhesion.",
|
||||||
|
"type": "float",
|
||||||
|
"unit": "%",
|
||||||
|
"default_value": 100.0,
|
||||||
|
"minimum_value": "0.001",
|
||||||
|
"maximum_value_warning": "150",
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -2234,6 +2234,107 @@
|
|||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": true
|
"settable_per_extruder": true
|
||||||
},
|
},
|
||||||
|
"material_crystallinity":
|
||||||
|
{
|
||||||
|
"label": "Crystalline Material",
|
||||||
|
"description": "Is this material the type that breaks off cleanly when heated (crystalline), or is it the type that produces long intertwined polymer chains (non-crystalline)?",
|
||||||
|
"type": "bool",
|
||||||
|
"default_value": false,
|
||||||
|
"enabled": false,
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": true
|
||||||
|
},
|
||||||
|
"material_anti_ooze_retracted_position":
|
||||||
|
{
|
||||||
|
"label": "Anti-ooze Retracted Position",
|
||||||
|
"description": "How far the material needs to be retracted before it stops oozing.",
|
||||||
|
"type": "float",
|
||||||
|
"unit": "mm",
|
||||||
|
"default_value": 4,
|
||||||
|
"enabled": false,
|
||||||
|
"minimum_value_warning": "0",
|
||||||
|
"maximum_value_warning": "retraction_amount",
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": true
|
||||||
|
},
|
||||||
|
"material_anti_ooze_retraction_speed":
|
||||||
|
{
|
||||||
|
"label": "Anti-ooze Retraction Speed",
|
||||||
|
"description": "How fast the material needs to be retracted during a filament switch to prevent oozing.",
|
||||||
|
"type": "float",
|
||||||
|
"unit": "mm/s",
|
||||||
|
"default_value": 5,
|
||||||
|
"enabled": false,
|
||||||
|
"minimum_value": "0",
|
||||||
|
"maximum_value": "machine_max_feedrate_e",
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": true
|
||||||
|
},
|
||||||
|
"material_break_preparation_retracted_position":
|
||||||
|
{
|
||||||
|
"label": "Break Preparation Retracted Position",
|
||||||
|
"description": "How far the filament can be stretched before it breaks, while heated.",
|
||||||
|
"type": "float",
|
||||||
|
"unit": "mm",
|
||||||
|
"default_value": 16,
|
||||||
|
"enabled": false,
|
||||||
|
"minimum_value_warning": "0",
|
||||||
|
"maximum_value_warning": "retraction_amount * 4",
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": true
|
||||||
|
},
|
||||||
|
"material_break_preparation_speed":
|
||||||
|
{
|
||||||
|
"label": "Break Preparation Retraction Speed",
|
||||||
|
"description": "How fast the filament needs to be retracted just before breaking it off in a retraction.",
|
||||||
|
"type": "float",
|
||||||
|
"unit": "mm/s",
|
||||||
|
"default_value": 2,
|
||||||
|
"enabled": false,
|
||||||
|
"minimum_value": "0",
|
||||||
|
"maximum_value": "machine_max_feedrate_e",
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": true
|
||||||
|
},
|
||||||
|
"material_break_retracted_position":
|
||||||
|
{
|
||||||
|
"label": "Break Retracted Position",
|
||||||
|
"description": "How far to retract the filament in order to break it cleanly.",
|
||||||
|
"type": "float",
|
||||||
|
"unit": "mm",
|
||||||
|
"default_value": 50,
|
||||||
|
"enabled": false,
|
||||||
|
"minimum_value_warning": "0",
|
||||||
|
"maximum_value_warning": "100",
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": true
|
||||||
|
},
|
||||||
|
"material_break_speed":
|
||||||
|
{
|
||||||
|
"label": "Break Retraction Speed",
|
||||||
|
"description": "The speed at which to retract the filament in order to break it cleanly.",
|
||||||
|
"type": "float",
|
||||||
|
"unit": "mm/s",
|
||||||
|
"default_value": 25,
|
||||||
|
"enabled": false,
|
||||||
|
"minimum_value": "0",
|
||||||
|
"maximum_value": "machine_max_feedrate_e",
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": true
|
||||||
|
},
|
||||||
|
"material_break_temperature":
|
||||||
|
{
|
||||||
|
"label": "Break Temperature",
|
||||||
|
"description": "The temperature at which the filament is broken for a clean break.",
|
||||||
|
"type": "float",
|
||||||
|
"unit": "°C",
|
||||||
|
"default_value": 50,
|
||||||
|
"enabled": false,
|
||||||
|
"minimum_value": "-273.15",
|
||||||
|
"maximum_value_warning": "300",
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": true
|
||||||
|
},
|
||||||
"material_flow":
|
"material_flow":
|
||||||
{
|
{
|
||||||
"label": "Flow",
|
"label": "Flow",
|
||||||
@ -2245,7 +2346,195 @@
|
|||||||
"minimum_value_warning": "50",
|
"minimum_value_warning": "50",
|
||||||
"maximum_value_warning": "150",
|
"maximum_value_warning": "150",
|
||||||
"enabled": "machine_gcode_flavor != \"UltiGCode\"",
|
"enabled": "machine_gcode_flavor != \"UltiGCode\"",
|
||||||
"settable_per_mesh": true
|
"settable_per_mesh": true,
|
||||||
|
"children":
|
||||||
|
{
|
||||||
|
"wall_material_flow":
|
||||||
|
{
|
||||||
|
"label": "Wall Flow",
|
||||||
|
"description": "Flow compensation on wall lines.",
|
||||||
|
"unit": "%",
|
||||||
|
"type": "float",
|
||||||
|
"default_value": 100,
|
||||||
|
"value": "material_flow",
|
||||||
|
"minimum_value": "5",
|
||||||
|
"minimum_value_warning": "50",
|
||||||
|
"maximum_value_warning": "150",
|
||||||
|
"limit_to_extruder": "wall_0_extruder_nr if wall_x_extruder_nr == wall_0_extruder_nr else -1",
|
||||||
|
"settable_per_mesh": true,
|
||||||
|
"children":
|
||||||
|
{
|
||||||
|
"wall_0_material_flow":
|
||||||
|
{
|
||||||
|
"label": "Outer Wall Flow",
|
||||||
|
"description": "Flow compensation on the outermost wall line.",
|
||||||
|
"unit": "%",
|
||||||
|
"type": "float",
|
||||||
|
"default_value": 100,
|
||||||
|
"value": "wall_material_flow",
|
||||||
|
"minimum_value": "5",
|
||||||
|
"minimum_value_warning": "50",
|
||||||
|
"maximum_value_warning": "150",
|
||||||
|
"limit_to_extruder": "wall_0_extruder_nr",
|
||||||
|
"settable_per_mesh": true
|
||||||
|
},
|
||||||
|
"wall_x_material_flow":
|
||||||
|
{
|
||||||
|
"label": "Inner Wall(s) Flow",
|
||||||
|
"description": "Flow compensation on wall lines for all wall lines except the outermost one.",
|
||||||
|
"unit": "%",
|
||||||
|
"type": "float",
|
||||||
|
"default_value": 100,
|
||||||
|
"value": "wall_material_flow",
|
||||||
|
"minimum_value": "5",
|
||||||
|
"minimum_value_warning": "50",
|
||||||
|
"maximum_value_warning": "150",
|
||||||
|
"limit_to_extruder": "wall_x_extruder_nr",
|
||||||
|
"settable_per_mesh": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"skin_material_flow":
|
||||||
|
{
|
||||||
|
"label": "Top/Bottom Flow",
|
||||||
|
"description": "Flow compensation on top/bottom lines.",
|
||||||
|
"unit": "%",
|
||||||
|
"type": "float",
|
||||||
|
"default_value": 100,
|
||||||
|
"value": "material_flow",
|
||||||
|
"minimum_value": "5",
|
||||||
|
"minimum_value_warning": "50",
|
||||||
|
"maximum_value_warning": "150",
|
||||||
|
"enabled": "top_layers > 0 or bottom_layers > 0",
|
||||||
|
"limit_to_extruder": "top_bottom_extruder_nr",
|
||||||
|
"settable_per_mesh": true
|
||||||
|
},
|
||||||
|
"roofing_material_flow":
|
||||||
|
{
|
||||||
|
"label": "Top Surface Skin Flow",
|
||||||
|
"description": "Flow compensation on lines of the areas at the top of the print.",
|
||||||
|
"unit": "%",
|
||||||
|
"type": "float",
|
||||||
|
"default_value": 100,
|
||||||
|
"value": "skin_material_flow",
|
||||||
|
"minimum_value": "5",
|
||||||
|
"minimum_value_warning": "50",
|
||||||
|
"maximum_value_warning": "150",
|
||||||
|
"limit_to_extruder": "roofing_extruder_nr",
|
||||||
|
"settable_per_mesh": true,
|
||||||
|
"enabled": "roofing_layer_count > 0 and top_layers > 0"
|
||||||
|
},
|
||||||
|
"infill_material_flow":
|
||||||
|
{
|
||||||
|
"label": "Infill Flow",
|
||||||
|
"description": "Flow compensation on infill lines.",
|
||||||
|
"unit": "%",
|
||||||
|
"type": "float",
|
||||||
|
"default_value": 100,
|
||||||
|
"value": "material_flow",
|
||||||
|
"minimum_value": "5",
|
||||||
|
"minimum_value_warning": "50",
|
||||||
|
"maximum_value_warning": "150",
|
||||||
|
"enabled": "infill_sparse_density > 0",
|
||||||
|
"limit_to_extruder": "infill_extruder_nr",
|
||||||
|
"settable_per_mesh": true
|
||||||
|
},
|
||||||
|
"skirt_brim_material_flow":
|
||||||
|
{
|
||||||
|
"label": "Skirt/Brim Flow",
|
||||||
|
"description": "Flow compensation on skirt or brim lines.",
|
||||||
|
"unit": "%",
|
||||||
|
"type": "float",
|
||||||
|
"default_value": 100,
|
||||||
|
"value": "material_flow",
|
||||||
|
"minimum_value": "5",
|
||||||
|
"minimum_value_warning": "50",
|
||||||
|
"maximum_value_warning": "150",
|
||||||
|
"enabled": "resolveOrValue('adhesion_type') == 'skirt' or resolveOrValue('adhesion_type') == 'brim'",
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": true
|
||||||
|
},
|
||||||
|
"support_material_flow":
|
||||||
|
{
|
||||||
|
"label": "Support Flow",
|
||||||
|
"description": "Flow compensation on support structure lines.",
|
||||||
|
"unit": "%",
|
||||||
|
"type": "float",
|
||||||
|
"default_value": 100,
|
||||||
|
"value": "material_flow",
|
||||||
|
"minimum_value": "5",
|
||||||
|
"minimum_value_warning": "50",
|
||||||
|
"maximum_value_warning": "150",
|
||||||
|
"limit_to_extruder": "support_infill_extruder_nr",
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": true
|
||||||
|
},
|
||||||
|
"support_interface_material_flow":
|
||||||
|
{
|
||||||
|
"label": "Support Interface Flow",
|
||||||
|
"description": "Flow compensation on lines of support roof or floor.",
|
||||||
|
"unit": "%",
|
||||||
|
"type": "float",
|
||||||
|
"default_value": 100,
|
||||||
|
"value": "material_flow",
|
||||||
|
"minimum_value": "5",
|
||||||
|
"minimum_value_warning": "50",
|
||||||
|
"maximum_value_warning": "150",
|
||||||
|
"enabled": "support_enable and support_interface_enable",
|
||||||
|
"limit_to_extruder": "support_interface_extruder_nr",
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": true,
|
||||||
|
"children":
|
||||||
|
{
|
||||||
|
"support_roof_material_flow":
|
||||||
|
{
|
||||||
|
"label": "Support Roof Flow",
|
||||||
|
"description": "Flow compensation on support roof lines.",
|
||||||
|
"unit": "%",
|
||||||
|
"type": "float",
|
||||||
|
"default_value": 100,
|
||||||
|
"value": "extruderValue(support_roof_extruder_nr, 'support_interface_material_flow')",
|
||||||
|
"minimum_value": "5",
|
||||||
|
"minimum_value_warning": "50",
|
||||||
|
"maximum_value_warning": "150",
|
||||||
|
"enabled": "support_enable and support_roof_enable",
|
||||||
|
"limit_to_extruder": "support_roof_extruder_nr",
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": true
|
||||||
|
},
|
||||||
|
"support_bottom_material_flow":
|
||||||
|
{
|
||||||
|
"label": "Support Floor Flow",
|
||||||
|
"description": "Flow compensation on support floor lines.",
|
||||||
|
"unit": "%",
|
||||||
|
"type": "float",
|
||||||
|
"default_value": 100,
|
||||||
|
"value": "extruderValue(support_bottom_extruder_nr, 'support_interface_material_flow')",
|
||||||
|
"minimum_value": "5",
|
||||||
|
"minimum_value_warning": "50",
|
||||||
|
"maximum_value_warning": "150",
|
||||||
|
"enabled": "support_enable and support_bottom_enable",
|
||||||
|
"limit_to_extruder": "support_bottom_extruder_nr",
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"prime_tower_flow":
|
||||||
|
{
|
||||||
|
"label": "Prime Tower Flow",
|
||||||
|
"description": "Flow compensation on prime tower lines.",
|
||||||
|
"unit": "%",
|
||||||
|
"type": "float",
|
||||||
|
"default_value": 100,
|
||||||
|
"value": "material_flow",
|
||||||
|
"minimum_value": "5",
|
||||||
|
"minimum_value_warning": "50",
|
||||||
|
"maximum_value_warning": "150",
|
||||||
|
"settable_per_mesh": false,
|
||||||
|
"settable_per_extruder": true
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"material_flow_layer_0":
|
"material_flow_layer_0":
|
||||||
{
|
{
|
||||||
@ -2253,7 +2542,6 @@
|
|||||||
"description": "Flow compensation for the first layer: the amount of material extruded on the initial layer is multiplied by this value.",
|
"description": "Flow compensation for the first layer: the amount of material extruded on the initial layer is multiplied by this value.",
|
||||||
"unit": "%",
|
"unit": "%",
|
||||||
"default_value": 100,
|
"default_value": 100,
|
||||||
"value": "material_flow",
|
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"minimum_value": "0.0001",
|
"minimum_value": "0.0001",
|
||||||
"minimum_value_warning": "50",
|
"minimum_value_warning": "50",
|
||||||
@ -4635,11 +4923,11 @@
|
|||||||
"label": "Enable Prime Blob",
|
"label": "Enable Prime Blob",
|
||||||
"description": "Whether to prime the filament with a blob before printing. Turning this setting on will ensure that the extruder will have material ready at the nozzle before printing. Printing Brim or Skirt can act like priming too, in which case turning this setting off saves some time.",
|
"description": "Whether to prime the filament with a blob before printing. Turning this setting on will ensure that the extruder will have material ready at the nozzle before printing. Printing Brim or Skirt can act like priming too, in which case turning this setting off saves some time.",
|
||||||
"type": "bool",
|
"type": "bool",
|
||||||
"resolve": "any(extruderValues('prime_blob_enable'))",
|
|
||||||
"default_value": false,
|
"default_value": false,
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": true,
|
"settable_per_extruder": true,
|
||||||
"enabled": false
|
"enabled": false,
|
||||||
|
"warning_value": "True if resolveOrValue('print_sequence') == 'one_at_a_time' else None"
|
||||||
},
|
},
|
||||||
"extruder_prime_pos_x":
|
"extruder_prime_pos_x":
|
||||||
{
|
{
|
||||||
@ -5305,7 +5593,7 @@
|
|||||||
"type": "float",
|
"type": "float",
|
||||||
"default_value": 6,
|
"default_value": 6,
|
||||||
"minimum_value": "0",
|
"minimum_value": "0",
|
||||||
"maximum_value_warning": "((resolveOrValue('prime_tower_size') * 0.5) ** 2 * 3.14159 * resolveOrValue('layer_height')",
|
"maximum_value_warning": "(resolveOrValue('prime_tower_size') * 0.5) ** 2 * 3.14159 * resolveOrValue('layer_height')",
|
||||||
"enabled": "resolveOrValue('prime_tower_enable')",
|
"enabled": "resolveOrValue('prime_tower_enable')",
|
||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": true
|
"settable_per_extruder": true
|
||||||
@ -5338,21 +5626,6 @@
|
|||||||
"settable_per_mesh": false,
|
"settable_per_mesh": false,
|
||||||
"settable_per_extruder": false
|
"settable_per_extruder": false
|
||||||
},
|
},
|
||||||
"prime_tower_flow":
|
|
||||||
{
|
|
||||||
"label": "Prime Tower Flow",
|
|
||||||
"description": "Flow compensation: the amount of material extruded is multiplied by this value.",
|
|
||||||
"type": "float",
|
|
||||||
"unit": "%",
|
|
||||||
"enabled": "resolveOrValue('prime_tower_enable')",
|
|
||||||
"default_value": 100,
|
|
||||||
"value": "material_flow",
|
|
||||||
"minimum_value": "0.0001",
|
|
||||||
"minimum_value_warning": "50",
|
|
||||||
"maximum_value_warning": "150",
|
|
||||||
"settable_per_mesh": false,
|
|
||||||
"settable_per_extruder": true
|
|
||||||
},
|
|
||||||
"prime_tower_wipe_enabled":
|
"prime_tower_wipe_enabled":
|
||||||
{
|
{
|
||||||
"label": "Wipe Inactive Nozzle on Prime Tower",
|
"label": "Wipe Inactive Nozzle on Prime Tower",
|
||||||
|
78
resources/definitions/flsun_qq_s.def.json
Normal file
78
resources/definitions/flsun_qq_s.def.json
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
{
|
||||||
|
"id": "flsun_qq_s",
|
||||||
|
"version": 2,
|
||||||
|
"name": "FLSUN QQ-S",
|
||||||
|
"inherits": "fdmprinter",
|
||||||
|
"metadata": {
|
||||||
|
"visible": true,
|
||||||
|
"author": "Cataldo URSO",
|
||||||
|
"manufacturer": "FLSUN",
|
||||||
|
"file_formats": "text/x-gcode",
|
||||||
|
"has_materials": true,
|
||||||
|
"preferred_quality_type": "draft",
|
||||||
|
"machine_extruder_trains": {
|
||||||
|
"0": "flsun_qq_s_extruder_0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"overrides": {
|
||||||
|
"machine_center_is_zero": {
|
||||||
|
"default_value": true
|
||||||
|
},
|
||||||
|
"machine_shape": {
|
||||||
|
"default_value": "elliptic"
|
||||||
|
},
|
||||||
|
"machine_width": {
|
||||||
|
"default_value": 260
|
||||||
|
},
|
||||||
|
"machine_depth": {
|
||||||
|
"default_value": 260
|
||||||
|
},
|
||||||
|
"machine_height": {
|
||||||
|
"default_value": 370
|
||||||
|
},
|
||||||
|
"z_seam_type": {
|
||||||
|
"default_value": "back"
|
||||||
|
},
|
||||||
|
"top_thickness": {
|
||||||
|
"default_value": 5
|
||||||
|
},
|
||||||
|
"bottom_layers": {
|
||||||
|
"default_value": 4
|
||||||
|
},
|
||||||
|
"gantry_height": {
|
||||||
|
"default_value": 0
|
||||||
|
},
|
||||||
|
"machine_nozzle_size": {
|
||||||
|
"default_value": 0.4
|
||||||
|
},
|
||||||
|
"material_diameter": {
|
||||||
|
"default_value": 1.75
|
||||||
|
},
|
||||||
|
"machine_start_gcode": {
|
||||||
|
"default_value": "G21\nG90\nM82\nM107 T0\nM190 S{material_bed_temperature}\nM109 S{material_print_temperature} T0\nG28\nG92 E0\nG0 E3 F200\nG92 E0\n"
|
||||||
|
},
|
||||||
|
"machine_end_gcode": {
|
||||||
|
"default_value": "M107 T0\nM104 S0\nM104 S0 T1\nM140 S0\nG92 E0\nG91\nG1 E-1 F300 \nG1 Z+0.5 E-5 X-20 Y-20 F9000\nG28 X0 Y0\nM84 ;steppers off\nG90 ;absolute positioning\n"
|
||||||
|
},
|
||||||
|
"infill_sparse_density": {
|
||||||
|
"default_value": 10
|
||||||
|
},
|
||||||
|
"machine_head_with_fans_polygon": {
|
||||||
|
"default_value": [
|
||||||
|
[0, 0],
|
||||||
|
[0, 0],
|
||||||
|
[0, 0],
|
||||||
|
[0, 0]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"retraction_enable": {
|
||||||
|
"default_value": true
|
||||||
|
},
|
||||||
|
"machine_heated_bed": {
|
||||||
|
"default_value": true
|
||||||
|
},
|
||||||
|
"machine_gcode_flavor": {
|
||||||
|
"default_value": "Repetier"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
132
resources/definitions/geeetech_a30.def.json
Normal file
132
resources/definitions/geeetech_a30.def.json
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
{
|
||||||
|
"id": "geeetech_a30",
|
||||||
|
"version": 2,
|
||||||
|
"name": "Geeetech A30",
|
||||||
|
"inherits": "fdmprinter",
|
||||||
|
"metadata": {
|
||||||
|
"author": "William & Cataldo URSO",
|
||||||
|
"manufacturer": "Shenzhen Geeetech Technology",
|
||||||
|
"setting_version": 8,
|
||||||
|
"file_formats": "text/x-gcode",
|
||||||
|
"visible": true,
|
||||||
|
"has_materials": true,
|
||||||
|
"preferred_quality_type": "draft",
|
||||||
|
"machine_extruder_trains": {
|
||||||
|
"0": "geeetech_a30_extruder_0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"overrides": {
|
||||||
|
"machine_name": {
|
||||||
|
"default_value": "Geeetech A30"
|
||||||
|
},
|
||||||
|
"machine_start_gcode": {
|
||||||
|
"default_value": "G28 ;Home\nM190 S{material_bed_temperature}\nM109 S{material_print_temperature} T0\nG1 Z15.0 F6000 ;Move the platform down 15mm\nG92 E0\nG1 F200 E3\nG92 E0"
|
||||||
|
},
|
||||||
|
"machine_end_gcode": {
|
||||||
|
"default_value": "M104 S0;Cooling the heat end\nM140 S0;Cooling the heat bed\nG92 E1\nG1 E-1 F300\nG28 X0 Y0;Home X axis and Y axis\nM84"
|
||||||
|
},
|
||||||
|
"machine_width": {
|
||||||
|
"default_value": 320
|
||||||
|
},
|
||||||
|
"machine_height": {
|
||||||
|
"default_value": 420
|
||||||
|
},
|
||||||
|
"machine_depth": {
|
||||||
|
"default_value": 320
|
||||||
|
},
|
||||||
|
"machine_heated_bed": {
|
||||||
|
"default_value": true
|
||||||
|
},
|
||||||
|
"machine_center_is_zero": {
|
||||||
|
"default_value": false
|
||||||
|
},
|
||||||
|
"material_diameter": {
|
||||||
|
"default_value": 1.75
|
||||||
|
},
|
||||||
|
"material_bed_temperature": {
|
||||||
|
"default_value": 60
|
||||||
|
},
|
||||||
|
"machine_nozzle_size": {
|
||||||
|
"default_value": 0.4
|
||||||
|
},
|
||||||
|
"layer_height": {
|
||||||
|
"default_value": 0.1
|
||||||
|
},
|
||||||
|
"layer_height_0": {
|
||||||
|
"default_value": 0.3
|
||||||
|
},
|
||||||
|
"retraction_amount": {
|
||||||
|
"default_value": 2
|
||||||
|
},
|
||||||
|
"retraction_speed": {
|
||||||
|
"default_value": 25
|
||||||
|
},
|
||||||
|
"retraction_retract_speed": {
|
||||||
|
"default_value": 25
|
||||||
|
},
|
||||||
|
"retraction_prime_speed": {
|
||||||
|
"default_value": 25
|
||||||
|
},
|
||||||
|
"adhesion_type": {
|
||||||
|
"default_value": "skirt"
|
||||||
|
},
|
||||||
|
"machine_head_polygon": {
|
||||||
|
"default_value": [
|
||||||
|
[-75, 35],
|
||||||
|
[18, 35],
|
||||||
|
[18, -18],
|
||||||
|
[-75, -18]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"machine_head_with_fans_polygon": {
|
||||||
|
"default_value": [
|
||||||
|
[-75, 35],
|
||||||
|
[18, 35],
|
||||||
|
[18, -18],
|
||||||
|
[-75, -18]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"gantry_height": {
|
||||||
|
"default_value": 55
|
||||||
|
},
|
||||||
|
"machine_max_feedrate_x": {
|
||||||
|
"default_value": 300
|
||||||
|
},
|
||||||
|
"machine_max_feedrate_y": {
|
||||||
|
"default_value": 300
|
||||||
|
},
|
||||||
|
"machine_max_feedrate_z": {
|
||||||
|
"default_value": 7
|
||||||
|
},
|
||||||
|
"machine_max_feedrate_e": {
|
||||||
|
"default_value": 50
|
||||||
|
},
|
||||||
|
"machine_max_acceleration_x": {
|
||||||
|
"default_value": 2000
|
||||||
|
},
|
||||||
|
"machine_max_acceleration_y": {
|
||||||
|
"default_value": 2000
|
||||||
|
},
|
||||||
|
"machine_max_acceleration_z": {
|
||||||
|
"default_value": 100
|
||||||
|
},
|
||||||
|
"machine_max_acceleration_e": {
|
||||||
|
"default_value": 10000
|
||||||
|
},
|
||||||
|
"machine_acceleration": {
|
||||||
|
"default_value": 2000
|
||||||
|
},
|
||||||
|
"machine_max_jerk_xy": {
|
||||||
|
"default_value": 10
|
||||||
|
},
|
||||||
|
"machine_max_jerk_z": {
|
||||||
|
"default_value": 1
|
||||||
|
},
|
||||||
|
"machine_max_jerk_e": {
|
||||||
|
"default_value": 5
|
||||||
|
},
|
||||||
|
"machine_gcode_flavor": {
|
||||||
|
"default_value": "Repetier"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -56,7 +56,7 @@
|
|||||||
"prime_tower_position_y": {"value": 70 },
|
"prime_tower_position_y": {"value": 70 },
|
||||||
"prime_blob_enable": {"default_value": false },
|
"prime_blob_enable": {"default_value": false },
|
||||||
"machine_max_feedrate_z": {"default_value": 1200 },
|
"machine_max_feedrate_z": {"default_value": 1200 },
|
||||||
"machine_start_gcode": {"default_value": "\n;Neither MaukCC nor any of MaukCC representatives has any liabilities or gives any warranties on this .gcode file, or on any or all objects made with this .gcode file.\n\nM117 Homing Y ......\nG28 Y\nM117 Homing X ......\nG28 X\nM117 Homing Z ......\nG28 Z F100\n\nG1 X150 Y10 F9000\nG30 H0\nM340 P0 S1500\n\nG1 X-20 Y-100 F9000;go to wipe point\nG1 Z0 F900\nG1 Z0.2 F900\nG1 Y-50 F9000\nG1 X150 Y10 F9000\nM117 HMS434 Printing ...\n\n" },
|
"machine_start_gcode": {"default_value": "\n;Neither MaukCC nor any of MaukCC representatives has any liabilities or gives any warranties on this .gcode file, or on any or all objects made with this .gcode file.\n\nM117 Homing Y ......\nG28 Y\nM117 Homing X ......\nG28 X\nM117 Homing Z ......\nG28 Z F100\n\nG1 X-44 Y-100 F9000;go to wipe point\nG1 Z0 F900\nG1 Z0.2 F900\nM117 HMS434 Printing ...\n\n" },
|
||||||
"machine_end_gcode": {"default_value": "" },
|
"machine_end_gcode": {"default_value": "" },
|
||||||
|
|
||||||
"retraction_extra_prime_amount": {"minimum_value_warning": "-2.0" },
|
"retraction_extra_prime_amount": {"minimum_value_warning": "-2.0" },
|
||||||
@ -94,7 +94,7 @@
|
|||||||
"maximum_value_warning": "material_print_temperature + 15"},
|
"maximum_value_warning": "material_print_temperature + 15"},
|
||||||
"material_final_print_temperature": {"value": "material_print_temperature"},
|
"material_final_print_temperature": {"value": "material_print_temperature"},
|
||||||
"material_bed_temperature_layer_0": {"value": "material_bed_temperature + 1"},
|
"material_bed_temperature_layer_0": {"value": "material_bed_temperature + 1"},
|
||||||
"material_flow": {"value": "120 if infill_sparse_density < 95 else 115"},
|
"material_flow": {"value": "100"},
|
||||||
"retraction_amount": {"value": "1"},
|
"retraction_amount": {"value": "1"},
|
||||||
"retraction_speed": {"value": "20"},
|
"retraction_speed": {"value": "20"},
|
||||||
"retraction_prime_speed": {"value": "8"},
|
"retraction_prime_speed": {"value": "8"},
|
||||||
|
@ -79,7 +79,7 @@
|
|||||||
"prime_tower_position_x": { "value": "machine_depth - max(extruderValue(adhesion_extruder_nr, 'brim_width') * extruderValue(adhesion_extruder_nr, 'initial_layer_line_width_factor') / 100 if adhesion_type == 'brim' else (extruderValue(adhesion_extruder_nr, 'raft_margin') if adhesion_type == 'raft' else (extruderValue(adhesion_extruder_nr, 'skirt_gap') if adhesion_type == 'skirt' else 0)), max(extruderValues('travel_avoid_distance'))) - max(extruderValues('support_offset')) - sum(extruderValues('skirt_brim_line_width')) - 30" },
|
"prime_tower_position_x": { "value": "machine_depth - max(extruderValue(adhesion_extruder_nr, 'brim_width') * extruderValue(adhesion_extruder_nr, 'initial_layer_line_width_factor') / 100 if adhesion_type == 'brim' else (extruderValue(adhesion_extruder_nr, 'raft_margin') if adhesion_type == 'raft' else (extruderValue(adhesion_extruder_nr, 'skirt_gap') if adhesion_type == 'skirt' else 0)), max(extruderValues('travel_avoid_distance'))) - max(extruderValues('support_offset')) - sum(extruderValues('skirt_brim_line_width')) - 30" },
|
||||||
"prime_tower_wipe_enabled": { "default_value": false },
|
"prime_tower_wipe_enabled": { "default_value": false },
|
||||||
|
|
||||||
"prime_blob_enable": { "enabled": true, "default_value": true },
|
"prime_blob_enable": { "enabled": true, "default_value": true, "value": "resolveOrValue('print_sequence') != 'one_at_a_time'" },
|
||||||
|
|
||||||
"acceleration_enabled": { "value": "True" },
|
"acceleration_enabled": { "value": "True" },
|
||||||
"acceleration_layer_0": { "value": "acceleration_topbottom" },
|
"acceleration_layer_0": { "value": "acceleration_topbottom" },
|
||||||
|
16
resources/extruders/flsun_qq_s_extruder_0.def.json
Normal file
16
resources/extruders/flsun_qq_s_extruder_0.def.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"id": "flsun_qq_s_extruder_0",
|
||||||
|
"version": 2,
|
||||||
|
"name": "Extruder 1",
|
||||||
|
"inherits": "fdmextruder",
|
||||||
|
"metadata": {
|
||||||
|
"machine": "flsun_qq_s",
|
||||||
|
"position": "0"
|
||||||
|
},
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"extruder_nr": { "default_value": 0 },
|
||||||
|
"machine_nozzle_size": { "default_value": 0.4 },
|
||||||
|
"material_diameter": { "default_value": 1.75 }
|
||||||
|
}
|
||||||
|
}
|
16
resources/extruders/geeetech_a30_extruder_0.def.json
Normal file
16
resources/extruders/geeetech_a30_extruder_0.def.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"id": "geeetech_a30_extruder_0",
|
||||||
|
"version": 2,
|
||||||
|
"name": "Extruder 1",
|
||||||
|
"inherits": "fdmextruder",
|
||||||
|
"metadata": {
|
||||||
|
"machine": "geeetech_a30",
|
||||||
|
"position": "0"
|
||||||
|
},
|
||||||
|
|
||||||
|
"overrides": {
|
||||||
|
"extruder_nr": { "default_value": 0 },
|
||||||
|
"machine_nozzle_size": { "default_value": 0.4 },
|
||||||
|
"material_diameter": { "default_value": 1.75 }
|
||||||
|
}
|
||||||
|
}
|
@ -17,10 +17,10 @@
|
|||||||
"machine_nozzle_offset_y": { "default_value": 0.0 },
|
"machine_nozzle_offset_y": { "default_value": 0.0 },
|
||||||
"material_diameter": { "default_value": 1.75 },
|
"material_diameter": { "default_value": 1.75 },
|
||||||
"machine_extruder_start_code": {
|
"machine_extruder_start_code": {
|
||||||
"default_value": "\nM109 T0 S{material_print_temperature}\nG1 X-18 Y-50 F9000\nG1 X150 Y10 F9000\n\n"
|
"default_value": "\n;changing to tool1\nM109 T0 S{material_print_temperature}\nG1 X-18 Y-50 F9000\nG1 X150 Y10 F9000\n\n"
|
||||||
},
|
},
|
||||||
"machine_extruder_end_code": {
|
"machine_extruder_end_code": {
|
||||||
"default_value": "\nG1 X150 Y10 F9000\nG1 X-20 Y-50 F9000\nG1 Y-100 F3000\n\n"
|
"default_value": "\nG1 X150 Y10 F9000\nG1 X-20 Y-50 F9000\nG1 Y-100 F3000\n; ending tool1\n\n"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,10 +17,10 @@
|
|||||||
"machine_nozzle_offset_y": { "default_value": 0.0 },
|
"machine_nozzle_offset_y": { "default_value": 0.0 },
|
||||||
"material_diameter": { "default_value": 1.75 },
|
"material_diameter": { "default_value": 1.75 },
|
||||||
"machine_extruder_start_code": {
|
"machine_extruder_start_code": {
|
||||||
"default_value": "\nM109 T1 S{material_print_temperature}\nG1 X-18 Y-50 F9000\nG1 X150 Y10 F9000\n\n"
|
"default_value": "\n;changing to tool2\nM109 T1 S{material_print_temperature}\nG1 X-18 Y-50 F9000\nG1 X150 Y10 F9000\n\n"
|
||||||
},
|
},
|
||||||
"machine_extruder_end_code": {
|
"machine_extruder_end_code": {
|
||||||
"default_value": "\nG1 X150 Y10 F9000\nG1 X-20 Y-50 F9000\nG1 Y-100 F3000\n\n"
|
"default_value": "\nG1 X150 Y10 F9000\nG1 X-20 Y-50 F9000\nG1 Y-100 F3000\n; ending tool2\n\n"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,10 +17,10 @@
|
|||||||
"machine_nozzle_offset_y": { "default_value": 0.0 },
|
"machine_nozzle_offset_y": { "default_value": 0.0 },
|
||||||
"material_diameter": { "default_value": 1.75 },
|
"material_diameter": { "default_value": 1.75 },
|
||||||
"machine_extruder_start_code": {
|
"machine_extruder_start_code": {
|
||||||
"default_value": ""
|
"default_value": "\n;changing to tool3"
|
||||||
},
|
},
|
||||||
"machine_extruder_end_code": {
|
"machine_extruder_end_code": {
|
||||||
"default_value": ""
|
"default_value": "\n;ending tool3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,10 +17,10 @@
|
|||||||
"machine_nozzle_offset_y": { "default_value": 0.0 },
|
"machine_nozzle_offset_y": { "default_value": 0.0 },
|
||||||
"material_diameter": { "default_value": 1.75 },
|
"material_diameter": { "default_value": 1.75 },
|
||||||
"machine_extruder_start_code": {
|
"machine_extruder_start_code": {
|
||||||
"default_value": ""
|
"default_value": "\n;changing to tool4"
|
||||||
},
|
},
|
||||||
"machine_extruder_end_code": {
|
"machine_extruder_end_code": {
|
||||||
"default_value": ""
|
"default_value": "\n;ending tool4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,10 +17,10 @@
|
|||||||
"machine_nozzle_offset_y": { "default_value": 0.0 },
|
"machine_nozzle_offset_y": { "default_value": 0.0 },
|
||||||
"material_diameter": { "default_value": 1.75 },
|
"material_diameter": { "default_value": 1.75 },
|
||||||
"machine_extruder_start_code": {
|
"machine_extruder_start_code": {
|
||||||
"default_value": ""
|
"default_value": "\n;changing to tool5"
|
||||||
},
|
},
|
||||||
"machine_extruder_end_code": {
|
"machine_extruder_end_code": {
|
||||||
"default_value": ""
|
"default_value": "\n;ending tool5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,10 +17,10 @@
|
|||||||
"machine_nozzle_offset_y": { "default_value": 0.0 },
|
"machine_nozzle_offset_y": { "default_value": 0.0 },
|
||||||
"material_diameter": { "default_value": 1.75 },
|
"material_diameter": { "default_value": 1.75 },
|
||||||
"machine_extruder_start_code": {
|
"machine_extruder_start_code": {
|
||||||
"default_value": ""
|
"default_value": "\n;changing to tool6"
|
||||||
},
|
},
|
||||||
"machine_extruder_end_code": {
|
"machine_extruder_end_code": {
|
||||||
"default_value": ""
|
"default_value": "\n;ending tool6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,10 +17,10 @@
|
|||||||
"machine_nozzle_offset_y": { "default_value": 0.0 },
|
"machine_nozzle_offset_y": { "default_value": 0.0 },
|
||||||
"material_diameter": { "default_value": 1.75 },
|
"material_diameter": { "default_value": 1.75 },
|
||||||
"machine_extruder_start_code": {
|
"machine_extruder_start_code": {
|
||||||
"default_value": ""
|
"default_value": "\n;changing to tool7"
|
||||||
},
|
},
|
||||||
"machine_extruder_end_code": {
|
"machine_extruder_end_code": {
|
||||||
"default_value": ""
|
"default_value": "\n;ending tool7"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,10 +17,10 @@
|
|||||||
"machine_nozzle_offset_y": { "default_value": 0.0 },
|
"machine_nozzle_offset_y": { "default_value": 0.0 },
|
||||||
"material_diameter": { "default_value": 1.75 },
|
"material_diameter": { "default_value": 1.75 },
|
||||||
"machine_extruder_start_code": {
|
"machine_extruder_start_code": {
|
||||||
"default_value": ""
|
"default_value": "\n;changing to tool8"
|
||||||
},
|
},
|
||||||
"machine_extruder_end_code": {
|
"machine_extruder_end_code": {
|
||||||
"default_value": ""
|
"default_value": "\n;ending tool8"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,51 @@ Menu
|
|||||||
MenuItem { action: Cura.Actions.viewRightSideCamera; }
|
MenuItem { action: Cura.Actions.viewRightSideCamera; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Menu
|
||||||
|
{
|
||||||
|
id: cameraViewMenu
|
||||||
|
property string cameraMode: UM.Preferences.getValue("general/camera_perspective_mode")
|
||||||
|
Connections
|
||||||
|
{
|
||||||
|
target: UM.Preferences
|
||||||
|
onPreferenceChanged:
|
||||||
|
{
|
||||||
|
if (preference !== "general/camera_perspective_mode")
|
||||||
|
{
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cameraViewMenu.cameraMode = UM.Preferences.getValue("general/camera_perspective_mode")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
title: catalog.i18nc("@action:inmenu menubar:view","Camera view")
|
||||||
|
MenuItem
|
||||||
|
{
|
||||||
|
text: catalog.i18nc("@action:inmenu menubar:view", "Perspective")
|
||||||
|
checkable: true
|
||||||
|
checked: cameraViewMenu.cameraMode == "perspective"
|
||||||
|
onTriggered:
|
||||||
|
{
|
||||||
|
UM.Preferences.setValue("general/camera_perspective_mode", "perspective")
|
||||||
|
checked = cameraViewMenu.cameraMode == "perspective"
|
||||||
|
}
|
||||||
|
exclusiveGroup: group
|
||||||
|
}
|
||||||
|
MenuItem
|
||||||
|
{
|
||||||
|
text: catalog.i18nc("@action:inmenu menubar:view", "Orthographic")
|
||||||
|
checkable: true
|
||||||
|
checked: cameraViewMenu.cameraMode == "orthogonal"
|
||||||
|
onTriggered:
|
||||||
|
{
|
||||||
|
UM.Preferences.setValue("general/camera_perspective_mode", "orthogonal")
|
||||||
|
checked = cameraViewMenu.cameraMode == "orthogonal"
|
||||||
|
}
|
||||||
|
exclusiveGroup: group
|
||||||
|
}
|
||||||
|
ExclusiveGroup { id: group }
|
||||||
|
}
|
||||||
|
|
||||||
MenuSeparator
|
MenuSeparator
|
||||||
{
|
{
|
||||||
visible: UM.Preferences.getValue("cura/use_multi_build_plate")
|
visible: UM.Preferences.getValue("cura/use_multi_build_plate")
|
||||||
|
@ -91,27 +91,27 @@ SettingItem
|
|||||||
}
|
}
|
||||||
width: height
|
width: height
|
||||||
|
|
||||||
color:
|
|
||||||
{
|
|
||||||
if (!enabled)
|
|
||||||
{
|
|
||||||
return UM.Theme.getColor("setting_control_disabled")
|
|
||||||
}
|
|
||||||
if (control.containsMouse || control.activeFocus)
|
|
||||||
{
|
|
||||||
return UM.Theme.getColor("setting_control_highlight")
|
|
||||||
}
|
|
||||||
return UM.Theme.getColor("setting_control")
|
|
||||||
}
|
|
||||||
|
|
||||||
radius: UM.Theme.getSize("setting_control_radius").width
|
radius: UM.Theme.getSize("setting_control_radius").width
|
||||||
border.width: UM.Theme.getSize("default_lining").width
|
border.width: UM.Theme.getSize("default_lining").width
|
||||||
|
|
||||||
border.color:
|
border.color:
|
||||||
{
|
{
|
||||||
if (!enabled)
|
if(!enabled)
|
||||||
{
|
{
|
||||||
return UM.Theme.getColor("setting_control_disabled_border")
|
return UM.Theme.getColor("setting_control_disabled_border")
|
||||||
}
|
}
|
||||||
|
switch (propertyProvider.properties.validationState)
|
||||||
|
{
|
||||||
|
case "ValidatorState.Invalid":
|
||||||
|
case "ValidatorState.Exception":
|
||||||
|
case "ValidatorState.MinimumError":
|
||||||
|
case "ValidatorState.MaximumError":
|
||||||
|
return UM.Theme.getColor("setting_validation_error");
|
||||||
|
case "ValidatorState.MinimumWarning":
|
||||||
|
case "ValidatorState.MaximumWarning":
|
||||||
|
return UM.Theme.getColor("setting_validation_warning");
|
||||||
|
}
|
||||||
|
// Validation is OK.
|
||||||
if (control.containsMouse || control.activeFocus)
|
if (control.containsMouse || control.activeFocus)
|
||||||
{
|
{
|
||||||
return UM.Theme.getColor("setting_control_border_highlight")
|
return UM.Theme.getColor("setting_control_border_highlight")
|
||||||
@ -119,6 +119,30 @@ SettingItem
|
|||||||
return UM.Theme.getColor("setting_control_border")
|
return UM.Theme.getColor("setting_control_border")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
color: {
|
||||||
|
if (!enabled)
|
||||||
|
{
|
||||||
|
return UM.Theme.getColor("setting_control_disabled")
|
||||||
|
}
|
||||||
|
switch (propertyProvider.properties.validationState)
|
||||||
|
{
|
||||||
|
case "ValidatorState.Invalid":
|
||||||
|
case "ValidatorState.Exception":
|
||||||
|
case "ValidatorState.MinimumError":
|
||||||
|
case "ValidatorState.MaximumError":
|
||||||
|
return UM.Theme.getColor("setting_validation_error_background")
|
||||||
|
case "ValidatorState.MinimumWarning":
|
||||||
|
case "ValidatorState.MaximumWarning":
|
||||||
|
return UM.Theme.getColor("setting_validation_warning_background")
|
||||||
|
}
|
||||||
|
// Validation is OK.
|
||||||
|
if (control.containsMouse || control.activeFocus)
|
||||||
|
{
|
||||||
|
return UM.Theme.getColor("setting_control_highlight")
|
||||||
|
}
|
||||||
|
return UM.Theme.getColor("setting_control")
|
||||||
|
}
|
||||||
|
|
||||||
UM.RecolorImage
|
UM.RecolorImage
|
||||||
{
|
{
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
@ -113,6 +113,18 @@ material_bed_temperature_layer_0
|
|||||||
material_adhesion_tendency
|
material_adhesion_tendency
|
||||||
material_surface_energy
|
material_surface_energy
|
||||||
material_flow
|
material_flow
|
||||||
|
wall_material_flow
|
||||||
|
wall_0_material_flow
|
||||||
|
wall_x_material_flow
|
||||||
|
skin_material_flow
|
||||||
|
roofing_material_flow
|
||||||
|
infill_material_flow
|
||||||
|
skirt_brim_material_flow
|
||||||
|
support_material_flow
|
||||||
|
support_interface_material_flow
|
||||||
|
support_roof_material_flow
|
||||||
|
support_bottom_material_flow
|
||||||
|
prime_tower_flow
|
||||||
material_flow_layer_0
|
material_flow_layer_0
|
||||||
retraction_enable
|
retraction_enable
|
||||||
retract_at_layer_change
|
retract_at_layer_change
|
||||||
@ -297,7 +309,6 @@ prime_tower_size
|
|||||||
prime_tower_min_volume
|
prime_tower_min_volume
|
||||||
prime_tower_position_x
|
prime_tower_position_x
|
||||||
prime_tower_position_y
|
prime_tower_position_y
|
||||||
prime_tower_flow
|
|
||||||
prime_tower_wipe_enabled
|
prime_tower_wipe_enabled
|
||||||
prime_tower_brim_enable
|
prime_tower_brim_enable
|
||||||
ooze_shield_enabled
|
ooze_shield_enabled
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock, patch
|
||||||
|
from UM.Math.AxisAlignedBox import AxisAlignedBox
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from UM.Math.Polygon import Polygon
|
from UM.Math.Polygon import Polygon
|
||||||
from UM.Settings.SettingInstance import InstanceState
|
from UM.Math.Vector import Vector
|
||||||
from cura.BuildVolume import BuildVolume, PRIME_CLEARANCE
|
from cura.BuildVolume import BuildVolume, PRIME_CLEARANCE
|
||||||
import numpy
|
import numpy
|
||||||
|
|
||||||
@ -43,6 +43,109 @@ def test_buildGridMesh(build_volume):
|
|||||||
assert numpy.array_equal(result_vertices, mesh.getVertices())
|
assert numpy.array_equal(result_vertices, mesh.getVertices())
|
||||||
|
|
||||||
|
|
||||||
|
def test_clamp(build_volume):
|
||||||
|
assert build_volume._clamp(0, 0, 200) == 0
|
||||||
|
assert build_volume._clamp(0, -200, 200) == 0
|
||||||
|
assert build_volume._clamp(300, -200, 200) == 200
|
||||||
|
|
||||||
|
|
||||||
|
class TestCalculateBedAdhesionSize:
|
||||||
|
setting_property_dict = {"adhesion_type": {"value": "brim"},
|
||||||
|
"skirt_brim_line_width": {"value": 0},
|
||||||
|
"initial_layer_line_width_factor": {"value": 0},
|
||||||
|
"brim_line_count": {"value": 0},
|
||||||
|
"machine_width": {"value": 200},
|
||||||
|
"machine_depth": {"value": 200},
|
||||||
|
"skirt_line_count": {"value": 0},
|
||||||
|
"skirt_gap": {"value": 0},
|
||||||
|
"raft_margin": {"value": 0}
|
||||||
|
}
|
||||||
|
|
||||||
|
def getPropertySideEffect(*args, **kwargs):
|
||||||
|
properties = TestCalculateBedAdhesionSize.setting_property_dict.get(args[1])
|
||||||
|
if properties:
|
||||||
|
return properties.get(args[2])
|
||||||
|
|
||||||
|
def createAndSetGlobalStack(self, build_volume):
|
||||||
|
mocked_stack = MagicMock()
|
||||||
|
mocked_stack.getProperty = MagicMock(side_effect=self.getPropertySideEffect)
|
||||||
|
|
||||||
|
build_volume._global_container_stack = mocked_stack
|
||||||
|
|
||||||
|
def test_noGlobalStack(self, build_volume: BuildVolume):
|
||||||
|
assert build_volume._calculateBedAdhesionSize([]) is None
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("setting_dict, result", [
|
||||||
|
({}, 0),
|
||||||
|
({"adhesion_type": {"value": "skirt"}}, 0),
|
||||||
|
({"adhesion_type": {"value": "raft"}}, 0),
|
||||||
|
({"adhesion_type": {"value": "none"}}, 0),
|
||||||
|
({"adhesion_type": {"value": "skirt"}, "skirt_line_count": {"value": 2}, "initial_layer_line_width_factor": {"value": 1}, "skirt_brim_line_width": {"value": 2}}, 0.02),
|
||||||
|
# Even though it's marked as skirt, it should behave as a brim as the prime tower has a brim (skirt line count is still at 0!)
|
||||||
|
({"adhesion_type": {"value": "skirt"}, "prime_tower_brim_enable": {"value": True}, "skirt_brim_line_width": {"value": 2}, "initial_layer_line_width_factor": {"value": 3}}, -0.06),
|
||||||
|
({"brim_line_count": {"value": 1}, "skirt_brim_line_width": {"value": 2}, "initial_layer_line_width_factor": {"value": 3}}, 0),
|
||||||
|
({"brim_line_count": {"value": 2}, "skirt_brim_line_width": {"value": 2}, "initial_layer_line_width_factor": {"value": 3}}, 0.06),
|
||||||
|
({"brim_line_count": {"value": 9000000}, "skirt_brim_line_width": {"value": 90000}, "initial_layer_line_width_factor": {"value": 9000}}, 100), # Clamped at half the max size of buildplate
|
||||||
|
])
|
||||||
|
def test_singleExtruder(self, build_volume: BuildVolume, setting_dict, result):
|
||||||
|
self.createAndSetGlobalStack(build_volume)
|
||||||
|
patched_dictionary = self.setting_property_dict.copy()
|
||||||
|
patched_dictionary.update(setting_dict)
|
||||||
|
with patch.dict(self.setting_property_dict, patched_dictionary):
|
||||||
|
assert build_volume._calculateBedAdhesionSize([]) == result
|
||||||
|
|
||||||
|
def test_unknownBedAdhesion(self, build_volume: BuildVolume):
|
||||||
|
self.createAndSetGlobalStack(build_volume)
|
||||||
|
patched_dictionary = self.setting_property_dict.copy()
|
||||||
|
patched_dictionary.update({"adhesion_type": {"value": "OMGZOMGBBQ"}})
|
||||||
|
with patch.dict(self.setting_property_dict, patched_dictionary):
|
||||||
|
with pytest.raises(Exception):
|
||||||
|
build_volume._calculateBedAdhesionSize([])
|
||||||
|
|
||||||
|
class TestComputeDisallowedAreasStatic:
|
||||||
|
setting_property_dict = {"machine_disallowed_areas": {"value": [[[-200, 112.5], [ -82, 112.5], [ -84, 102.5], [-115, 102.5]]]},
|
||||||
|
"machine_width": {"value": 200},
|
||||||
|
"machine_depth": {"value": 200},
|
||||||
|
}
|
||||||
|
|
||||||
|
def getPropertySideEffect(*args, **kwargs):
|
||||||
|
properties = TestComputeDisallowedAreasStatic.setting_property_dict.get(args[1])
|
||||||
|
if properties:
|
||||||
|
return properties.get(args[2])
|
||||||
|
|
||||||
|
def test_computeDisallowedAreasStaticNoExtruder(self, build_volume: BuildVolume):
|
||||||
|
mocked_stack = MagicMock()
|
||||||
|
mocked_stack.getProperty = MagicMock(side_effect=self.getPropertySideEffect)
|
||||||
|
|
||||||
|
build_volume._global_container_stack = mocked_stack
|
||||||
|
assert build_volume._computeDisallowedAreasStatic(0, []) == {}
|
||||||
|
|
||||||
|
def test_computeDisalowedAreasStaticSingleExtruder(self, build_volume: BuildVolume):
|
||||||
|
mocked_stack = MagicMock()
|
||||||
|
mocked_stack.getProperty = MagicMock(side_effect=self.getPropertySideEffect)
|
||||||
|
|
||||||
|
mocked_extruder = MagicMock()
|
||||||
|
mocked_extruder.getProperty = MagicMock(side_effect=self.getPropertySideEffect)
|
||||||
|
mocked_extruder.getId = MagicMock(return_value = "zomg")
|
||||||
|
|
||||||
|
build_volume._global_container_stack = mocked_stack
|
||||||
|
with patch("cura.Settings.ExtruderManager.ExtruderManager.getInstance"):
|
||||||
|
result = build_volume._computeDisallowedAreasStatic(0, [mocked_extruder])
|
||||||
|
assert result == {"zomg": [Polygon([[-84.0, 102.5], [-115.0, 102.5], [-200.0, 112.5], [-82.0, 112.5]])]}
|
||||||
|
|
||||||
|
def test_computeDisalowedAreasMutliExtruder(self, build_volume):
|
||||||
|
mocked_stack = MagicMock()
|
||||||
|
mocked_stack.getProperty = MagicMock(side_effect=self.getPropertySideEffect)
|
||||||
|
|
||||||
|
mocked_extruder = MagicMock()
|
||||||
|
mocked_extruder.getProperty = MagicMock(side_effect=self.getPropertySideEffect)
|
||||||
|
mocked_extruder.getId = MagicMock(return_value="zomg")
|
||||||
|
extruder_manager = MagicMock()
|
||||||
|
extruder_manager.getActiveExtruderStacks = MagicMock(return_value = [mocked_stack])
|
||||||
|
build_volume._global_container_stack = mocked_stack
|
||||||
|
with patch("cura.Settings.ExtruderManager.ExtruderManager.getInstance", MagicMock(return_value = extruder_manager)):
|
||||||
|
result = build_volume._computeDisallowedAreasStatic(0, [mocked_extruder])
|
||||||
|
assert result == {"zomg": [Polygon([[-84.0, 102.5], [-115.0, 102.5], [-200.0, 112.5], [-82.0, 112.5]])]}
|
||||||
|
|
||||||
class TestUpdateRaftThickness:
|
class TestUpdateRaftThickness:
|
||||||
setting_property_dict = {"raft_base_thickness": {"value": 1},
|
setting_property_dict = {"raft_base_thickness": {"value": 1},
|
||||||
@ -201,6 +304,25 @@ class TestRebuild:
|
|||||||
build_volume.rebuild()
|
build_volume.rebuild()
|
||||||
assert build_volume.getMeshData() is None
|
assert build_volume.getMeshData() is None
|
||||||
|
|
||||||
|
def test_updateBoundingBox(self, build_volume: BuildVolume):
|
||||||
|
build_volume.setWidth(10)
|
||||||
|
build_volume.setHeight(10)
|
||||||
|
build_volume.setDepth(10)
|
||||||
|
|
||||||
|
mocked_global_stack = MagicMock()
|
||||||
|
build_volume._global_container_stack = mocked_global_stack
|
||||||
|
build_volume.getEdgeDisallowedSize = MagicMock(return_value = 0)
|
||||||
|
build_volume.updateNodeBoundaryCheck = MagicMock()
|
||||||
|
|
||||||
|
# Fake the the "engine is created callback"
|
||||||
|
build_volume._onEngineCreated()
|
||||||
|
build_volume.rebuild()
|
||||||
|
|
||||||
|
bounding_box = build_volume.getBoundingBox()
|
||||||
|
assert bounding_box.minimum == Vector(-5.0, -1.0, -5.0)
|
||||||
|
assert bounding_box.maximum == Vector(5.0, 10.0, 5.0)
|
||||||
|
|
||||||
|
|
||||||
class TestUpdateMachineSizeProperties:
|
class TestUpdateMachineSizeProperties:
|
||||||
setting_property_dict = {"machine_width": {"value": 50},
|
setting_property_dict = {"machine_width": {"value": 50},
|
||||||
"machine_depth": {"value": 100},
|
"machine_depth": {"value": 100},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user