mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-06-04 11:14:21 +08:00
commit
817cff9d2f
18
.gitignore
vendored
18
.gitignore
vendored
@ -19,6 +19,7 @@ LC_MESSAGES
|
||||
*~
|
||||
*.qm
|
||||
.idea
|
||||
cura.desktop
|
||||
|
||||
# Eclipse+PyDev
|
||||
.project
|
||||
@ -33,4 +34,21 @@ plugins/Doodle3D-cura-plugin
|
||||
plugins/GodMode
|
||||
plugins/PostProcessingPlugin
|
||||
plugins/X3GWriter
|
||||
plugins/FlatProfileExporter
|
||||
plugins/cura-god-mode-plugin
|
||||
|
||||
#Build stuff
|
||||
CMakeCache.txt
|
||||
CMakeFiles
|
||||
CPackSourceConfig.cmake
|
||||
Testing/
|
||||
CTestTestfile.cmake
|
||||
Makefile*
|
||||
junit-pytest-*
|
||||
CuraVersion.py
|
||||
cmake_install.cmake
|
||||
|
||||
#Debug
|
||||
*.gcode
|
||||
run.sh
|
||||
|
||||
|
@ -22,6 +22,9 @@ set(CURA_BUILDTYPE "" CACHE STRING "Build type of Cura, eg. 'PPA'")
|
||||
configure_file(${CMAKE_SOURCE_DIR}/cura.desktop.in ${CMAKE_BINARY_DIR}/cura.desktop @ONLY)
|
||||
configure_file(cura/CuraVersion.py.in CuraVersion.py @ONLY)
|
||||
|
||||
if(NOT ${URANIUM_DIR} STREQUAL "")
|
||||
set(CMAKE_MODULE_PATH "${URANIUM_DIR}/cmake")
|
||||
endif()
|
||||
if(NOT ${URANIUM_SCRIPTS_DIR} STREQUAL "")
|
||||
list(APPEND CMAKE_MODULE_PATH ${URANIUM_DIR}/cmake)
|
||||
include(UraniumTranslationTools)
|
||||
@ -64,5 +67,3 @@ else()
|
||||
install(FILES ${CMAKE_BINARY_DIR}/CuraVersion.py
|
||||
DESTINATION lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/site-packages/cura)
|
||||
endif()
|
||||
|
||||
include(CPackConfig.cmake)
|
||||
|
@ -1,16 +0,0 @@
|
||||
set(CPACK_PACKAGE_VENDOR "Ultimaker B.V.")
|
||||
set(CPACK_PACKAGE_CONTACT "Arjen Hiemstra <a.hiemstra@ultimaker.com>")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Cura application to drive the CuraEngine")
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR 15)
|
||||
set(CPACK_PACKAGE_VERSION_MINOR 05)
|
||||
set(CPACK_PACKAGE_VERSION_PATCH 90)
|
||||
set(CPACK_PACKAGE_VERSION_REVISION 1)
|
||||
set(CPACK_GENERATOR "DEB")
|
||||
|
||||
set(DEB_DEPENDS
|
||||
"uranium (>= 15.05.93)"
|
||||
)
|
||||
string(REPLACE ";" ", " DEB_DEPENDS "${DEB_DEPENDS}")
|
||||
set(CPACK_DEBIAN_PACKAGE_DEPENDS ${DEB_DEPENDS})
|
||||
|
||||
include(CPack)
|
188
cura/Arrange.py
Executable file
188
cura/Arrange.py
Executable file
@ -0,0 +1,188 @@
|
||||
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
||||
from UM.Logger import Logger
|
||||
from UM.Math.Vector import Vector
|
||||
from cura.ShapeArray import ShapeArray
|
||||
from cura import ZOffsetDecorator
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
import numpy
|
||||
import copy
|
||||
|
||||
|
||||
## Return object for bestSpot
|
||||
LocationSuggestion = namedtuple("LocationSuggestion", ["x", "y", "penalty_points", "priority"])
|
||||
|
||||
|
||||
## The Arrange classed is used together with ShapeArray. Use it to find
|
||||
# good locations for objects that you try to put on a build place.
|
||||
# Different priority schemes can be defined so it alters the behavior while using
|
||||
# the same logic.
|
||||
class Arrange:
|
||||
build_volume = None
|
||||
|
||||
def __init__(self, x, y, offset_x, offset_y, scale= 1.0):
|
||||
self.shape = (y, x)
|
||||
self._priority = numpy.zeros((x, y), dtype=numpy.int32)
|
||||
self._priority_unique_values = []
|
||||
self._occupied = numpy.zeros((x, y), dtype=numpy.int32)
|
||||
self._scale = scale # convert input coordinates to arrange coordinates
|
||||
self._offset_x = offset_x
|
||||
self._offset_y = offset_y
|
||||
self._last_priority = 0
|
||||
|
||||
## Helper to create an Arranger instance
|
||||
#
|
||||
# Either fill in scene_root and create will find all sliceable nodes by itself,
|
||||
# or use fixed_nodes to provide the nodes yourself.
|
||||
# \param scene_root Root for finding all scene nodes
|
||||
# \param fixed_nodes Scene nodes to be placed
|
||||
@classmethod
|
||||
def create(cls, scene_root = None, fixed_nodes = None, scale = 0.5):
|
||||
arranger = Arrange(220, 220, 110, 110, scale = scale)
|
||||
arranger.centerFirst()
|
||||
|
||||
if fixed_nodes is None:
|
||||
fixed_nodes = []
|
||||
for node_ in DepthFirstIterator(scene_root):
|
||||
# Only count sliceable objects
|
||||
if node_.callDecoration("isSliceable"):
|
||||
fixed_nodes.append(node_)
|
||||
|
||||
# Place all objects fixed nodes
|
||||
for fixed_node in fixed_nodes:
|
||||
vertices = fixed_node.callDecoration("getConvexHull")
|
||||
points = copy.deepcopy(vertices._points)
|
||||
shape_arr = ShapeArray.fromPolygon(points, scale = scale)
|
||||
arranger.place(0, 0, shape_arr)
|
||||
|
||||
# If a build volume was set, add the disallowed areas
|
||||
if Arrange.build_volume:
|
||||
disallowed_areas = Arrange.build_volume.getDisallowedAreas()
|
||||
for area in disallowed_areas:
|
||||
points = copy.deepcopy(area._points)
|
||||
shape_arr = ShapeArray.fromPolygon(points, scale = scale)
|
||||
arranger.place(0, 0, shape_arr)
|
||||
return arranger
|
||||
|
||||
## Find placement for a node (using offset shape) and place it (using hull shape)
|
||||
# return the nodes that should be placed
|
||||
# \param node
|
||||
# \param offset_shape_arr ShapeArray with offset, used to find location
|
||||
# \param hull_shape_arr ShapeArray without offset, for placing the shape
|
||||
def findNodePlacement(self, node, offset_shape_arr, hull_shape_arr, step = 1):
|
||||
new_node = copy.deepcopy(node)
|
||||
best_spot = self.bestSpot(
|
||||
offset_shape_arr, start_prio = self._last_priority, step = step)
|
||||
x, y = best_spot.x, best_spot.y
|
||||
|
||||
# Save the last priority.
|
||||
self._last_priority = best_spot.priority
|
||||
|
||||
# Ensure that the object is above the build platform
|
||||
new_node.removeDecorator(ZOffsetDecorator.ZOffsetDecorator)
|
||||
if new_node.getBoundingBox():
|
||||
center_y = new_node.getWorldPosition().y - new_node.getBoundingBox().bottom
|
||||
else:
|
||||
center_y = 0
|
||||
|
||||
if x is not None: # We could find a place
|
||||
new_node.setPosition(Vector(x, center_y, y))
|
||||
found_spot = True
|
||||
self.place(x, y, hull_shape_arr) # place the object in arranger
|
||||
else:
|
||||
Logger.log("d", "Could not find spot!"),
|
||||
found_spot = False
|
||||
new_node.setPosition(Vector(200, center_y, 100))
|
||||
return new_node, found_spot
|
||||
|
||||
## Fill priority, center is best. Lower value is better
|
||||
# This is a strategy for the arranger.
|
||||
def centerFirst(self):
|
||||
# Square distance: creates a more round shape
|
||||
self._priority = numpy.fromfunction(
|
||||
lambda i, j: (self._offset_x - i) ** 2 + (self._offset_y - j) ** 2, self.shape, dtype=numpy.int32)
|
||||
self._priority_unique_values = numpy.unique(self._priority)
|
||||
self._priority_unique_values.sort()
|
||||
|
||||
## Fill priority, back is best. Lower value is better
|
||||
# This is a strategy for the arranger.
|
||||
def backFirst(self):
|
||||
self._priority = numpy.fromfunction(
|
||||
lambda i, j: 10 * j + abs(self._offset_x - i), self.shape, dtype=numpy.int32)
|
||||
self._priority_unique_values = numpy.unique(self._priority)
|
||||
self._priority_unique_values.sort()
|
||||
|
||||
## Return the amount of "penalty points" for polygon, which is the sum of priority
|
||||
# None if occupied
|
||||
# \param x x-coordinate to check shape
|
||||
# \param y y-coordinate
|
||||
# \param shape_arr the ShapeArray object to place
|
||||
def checkShape(self, x, y, shape_arr):
|
||||
x = int(self._scale * x)
|
||||
y = int(self._scale * y)
|
||||
offset_x = x + self._offset_x + shape_arr.offset_x
|
||||
offset_y = y + self._offset_y + shape_arr.offset_y
|
||||
occupied_slice = self._occupied[
|
||||
offset_y:offset_y + shape_arr.arr.shape[0],
|
||||
offset_x:offset_x + shape_arr.arr.shape[1]]
|
||||
try:
|
||||
if numpy.any(occupied_slice[numpy.where(shape_arr.arr == 1)]):
|
||||
return None
|
||||
except IndexError: # out of bounds if you try to place an object outside
|
||||
return None
|
||||
prio_slice = self._priority[
|
||||
offset_y:offset_y + shape_arr.arr.shape[0],
|
||||
offset_x:offset_x + shape_arr.arr.shape[1]]
|
||||
return numpy.sum(prio_slice[numpy.where(shape_arr.arr == 1)])
|
||||
|
||||
## Find "best" spot for ShapeArray
|
||||
# Return namedtuple with properties x, y, penalty_points, priority
|
||||
# \param shape_arr ShapeArray
|
||||
# \param start_prio Start with this priority value (and skip the ones before)
|
||||
# \param step Slicing value, higher = more skips = faster but less accurate
|
||||
def bestSpot(self, shape_arr, start_prio = 0, step = 1):
|
||||
start_idx_list = numpy.where(self._priority_unique_values == start_prio)
|
||||
if start_idx_list:
|
||||
start_idx = start_idx_list[0][0]
|
||||
else:
|
||||
start_idx = 0
|
||||
for priority in self._priority_unique_values[start_idx::step]:
|
||||
tryout_idx = numpy.where(self._priority == priority)
|
||||
for idx in range(len(tryout_idx[0])):
|
||||
x = tryout_idx[0][idx]
|
||||
y = tryout_idx[1][idx]
|
||||
projected_x = x - self._offset_x
|
||||
projected_y = y - self._offset_y
|
||||
|
||||
# array to "world" coordinates
|
||||
penalty_points = self.checkShape(projected_x, projected_y, shape_arr)
|
||||
if penalty_points is not None:
|
||||
return LocationSuggestion(x = projected_x, y = projected_y, penalty_points = penalty_points, priority = priority)
|
||||
return LocationSuggestion(x = None, y = None, penalty_points = None, priority = priority) # No suitable location found :-(
|
||||
|
||||
## Place the object.
|
||||
# Marks the locations in self._occupied and self._priority
|
||||
# \param x x-coordinate
|
||||
# \param y y-coordinate
|
||||
# \param shape_arr ShapeArray object
|
||||
def place(self, x, y, shape_arr):
|
||||
x = int(self._scale * x)
|
||||
y = int(self._scale * y)
|
||||
offset_x = x + self._offset_x + shape_arr.offset_x
|
||||
offset_y = y + self._offset_y + shape_arr.offset_y
|
||||
shape_y, shape_x = self._occupied.shape
|
||||
|
||||
min_x = min(max(offset_x, 0), shape_x - 1)
|
||||
min_y = min(max(offset_y, 0), shape_y - 1)
|
||||
max_x = min(max(offset_x + shape_arr.arr.shape[1], 0), shape_x - 1)
|
||||
max_y = min(max(offset_y + shape_arr.arr.shape[0], 0), shape_y - 1)
|
||||
occupied_slice = self._occupied[min_y:max_y, min_x:max_x]
|
||||
# we use a slice of shape because it can be out of bounds
|
||||
occupied_slice[numpy.where(shape_arr.arr[
|
||||
min_y - offset_y:max_y - offset_y, min_x - offset_x:max_x - offset_x] == 1)] = 1
|
||||
|
||||
# Set priority to low (= high number), so it won't get picked at trying out.
|
||||
prio_slice = self._priority[min_y:max_y, min_x:max_x]
|
||||
prio_slice[numpy.where(shape_arr.arr[
|
||||
min_y - offset_y:max_y - offset_y, min_x - offset_x:max_x - offset_x] == 1)] = 999
|
86
cura/ArrangeObjectsJob.py
Executable file
86
cura/ArrangeObjectsJob.py
Executable file
@ -0,0 +1,86 @@
|
||||
# Copyright (c) 2017 Ultimaker B.V.
|
||||
# Cura is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
from UM.Job import Job
|
||||
from UM.Scene.SceneNode import SceneNode
|
||||
from UM.Math.Vector import Vector
|
||||
from UM.Operations.SetTransformOperation import SetTransformOperation
|
||||
from UM.Operations.TranslateOperation import TranslateOperation
|
||||
from UM.Operations.GroupedOperation import GroupedOperation
|
||||
from UM.Logger import Logger
|
||||
from UM.Message import Message
|
||||
from UM.i18n import i18nCatalog
|
||||
i18n_catalog = i18nCatalog("cura")
|
||||
|
||||
from cura.ZOffsetDecorator import ZOffsetDecorator
|
||||
from cura.Arrange import Arrange
|
||||
from cura.ShapeArray import ShapeArray
|
||||
|
||||
from typing import List
|
||||
|
||||
|
||||
class ArrangeObjectsJob(Job):
|
||||
def __init__(self, nodes: List[SceneNode], fixed_nodes: List[SceneNode], min_offset = 8):
|
||||
super().__init__()
|
||||
self._nodes = nodes
|
||||
self._fixed_nodes = fixed_nodes
|
||||
self._min_offset = min_offset
|
||||
|
||||
def run(self):
|
||||
status_message = Message(i18n_catalog.i18nc("@info:status", "Finding new location for objects"), lifetime = 0, dismissable=False, progress = 0)
|
||||
status_message.show()
|
||||
arranger = Arrange.create(fixed_nodes = self._fixed_nodes)
|
||||
|
||||
# Collect nodes to be placed
|
||||
nodes_arr = [] # fill with (size, node, offset_shape_arr, hull_shape_arr)
|
||||
for node in self._nodes:
|
||||
offset_shape_arr, hull_shape_arr = ShapeArray.fromNode(node, min_offset = self._min_offset)
|
||||
nodes_arr.append((offset_shape_arr.arr.shape[0] * offset_shape_arr.arr.shape[1], node, offset_shape_arr, hull_shape_arr))
|
||||
|
||||
# Sort the nodes with the biggest area first.
|
||||
nodes_arr.sort(key=lambda item: item[0])
|
||||
nodes_arr.reverse()
|
||||
|
||||
# Place nodes one at a time
|
||||
start_priority = 0
|
||||
last_priority = start_priority
|
||||
last_size = None
|
||||
grouped_operation = GroupedOperation()
|
||||
found_solution_for_all = True
|
||||
for idx, (size, node, offset_shape_arr, hull_shape_arr) in enumerate(nodes_arr):
|
||||
# For performance reasons, we assume that when a location does not fit,
|
||||
# it will also not fit for the next object (while what can be untrue).
|
||||
# We also skip possibilities by slicing through the possibilities (step = 10)
|
||||
if last_size == size: # This optimization works if many of the objects have the same size
|
||||
start_priority = last_priority
|
||||
else:
|
||||
start_priority = 0
|
||||
best_spot = arranger.bestSpot(offset_shape_arr, start_prio=start_priority, step=10)
|
||||
x, y = best_spot.x, best_spot.y
|
||||
node.removeDecorator(ZOffsetDecorator)
|
||||
if node.getBoundingBox():
|
||||
center_y = node.getWorldPosition().y - node.getBoundingBox().bottom
|
||||
else:
|
||||
center_y = 0
|
||||
if x is not None: # We could find a place
|
||||
last_size = size
|
||||
last_priority = best_spot.priority
|
||||
|
||||
arranger.place(x, y, hull_shape_arr) # take place before the next one
|
||||
|
||||
grouped_operation.addOperation(TranslateOperation(node, Vector(x, center_y, y), set_position = True))
|
||||
else:
|
||||
Logger.log("d", "Arrange all: could not find spot!")
|
||||
found_solution_for_all = False
|
||||
grouped_operation.addOperation(TranslateOperation(node, Vector(200, center_y, - idx * 20), set_position = True))
|
||||
|
||||
status_message.setProgress((idx + 1) / len(nodes_arr) * 100)
|
||||
Job.yieldThread()
|
||||
|
||||
grouped_operation.push()
|
||||
|
||||
status_message.hide()
|
||||
|
||||
if not found_solution_for_all:
|
||||
no_full_solution_message = Message(i18n_catalog.i18nc("@info:status", "Unable to find a location within the build volume for all objects"))
|
||||
no_full_solution_message.show()
|
@ -23,9 +23,10 @@ from UM.View.GL.OpenGL import OpenGL
|
||||
catalog = i18nCatalog("cura")
|
||||
|
||||
import numpy
|
||||
import copy
|
||||
import math
|
||||
|
||||
from typing import List
|
||||
|
||||
# Setting for clearance around the prime
|
||||
PRIME_CLEARANCE = 6.5
|
||||
|
||||
@ -110,10 +111,11 @@ class BuildVolume(SceneNode):
|
||||
|
||||
def _onChangeTimerFinished(self):
|
||||
root = Application.getInstance().getController().getScene().getRoot()
|
||||
new_scene_objects = set(node for node in BreadthFirstIterator(root) if node.getMeshData() and type(node) is SceneNode)
|
||||
new_scene_objects = set(node for node in BreadthFirstIterator(root) if node.callDecoration("isSliceable"))
|
||||
if new_scene_objects != self._scene_objects:
|
||||
for node in new_scene_objects - self._scene_objects: #Nodes that were added to the scene.
|
||||
node.decoratorsChanged.connect(self._onNodeDecoratorChanged)
|
||||
self._updateNodeListeners(node)
|
||||
node.decoratorsChanged.connect(self._updateNodeListeners) # Make sure that decoration changes afterwards also receive the same treatment
|
||||
for node in self._scene_objects - new_scene_objects: #Nodes that were removed from the scene.
|
||||
per_mesh_stack = node.callDecoration("getStack")
|
||||
if per_mesh_stack:
|
||||
@ -121,7 +123,7 @@ class BuildVolume(SceneNode):
|
||||
active_extruder_changed = node.callDecoration("getActiveExtruderChangedSignal")
|
||||
if active_extruder_changed is not None:
|
||||
node.callDecoration("getActiveExtruderChangedSignal").disconnect(self._updateDisallowedAreasAndRebuild)
|
||||
node.decoratorsChanged.disconnect(self._onNodeDecoratorChanged)
|
||||
node.decoratorsChanged.disconnect(self._updateNodeListeners)
|
||||
|
||||
self._scene_objects = new_scene_objects
|
||||
self._onSettingPropertyChanged("print_sequence", "value") # Create fake event, so right settings are triggered.
|
||||
@ -129,7 +131,7 @@ class BuildVolume(SceneNode):
|
||||
## Updates the listeners that listen for changes in per-mesh stacks.
|
||||
#
|
||||
# \param node The node for which the decorators changed.
|
||||
def _onNodeDecoratorChanged(self, node):
|
||||
def _updateNodeListeners(self, node: SceneNode):
|
||||
per_mesh_stack = node.callDecoration("getStack")
|
||||
if per_mesh_stack:
|
||||
per_mesh_stack.propertyChanged.connect(self._onSettingPropertyChanged)
|
||||
@ -139,21 +141,25 @@ class BuildVolume(SceneNode):
|
||||
self._updateDisallowedAreasAndRebuild()
|
||||
|
||||
def setWidth(self, width):
|
||||
if width: self._width = width
|
||||
if width is not None:
|
||||
self._width = width
|
||||
|
||||
def setHeight(self, height):
|
||||
if height: self._height = height
|
||||
if height is not None:
|
||||
self._height = height
|
||||
|
||||
def setDepth(self, depth):
|
||||
if depth: self._depth = depth
|
||||
if depth is not None:
|
||||
self._depth = depth
|
||||
|
||||
def setShape(self, shape):
|
||||
if shape: self._shape = shape
|
||||
def setShape(self, shape: str):
|
||||
if shape:
|
||||
self._shape = shape
|
||||
|
||||
def getDisallowedAreas(self):
|
||||
def getDisallowedAreas(self) -> List[Polygon]:
|
||||
return self._disallowed_areas
|
||||
|
||||
def setDisallowedAreas(self, areas):
|
||||
def setDisallowedAreas(self, areas: List[Polygon]):
|
||||
self._disallowed_areas = areas
|
||||
|
||||
def render(self, renderer):
|
||||
@ -179,6 +185,53 @@ class BuildVolume(SceneNode):
|
||||
|
||||
return True
|
||||
|
||||
## For every sliceable node, update node._outside_buildarea
|
||||
#
|
||||
def updateNodeBoundaryCheck(self):
|
||||
root = Application.getInstance().getController().getScene().getRoot()
|
||||
nodes = list(BreadthFirstIterator(root))
|
||||
group_nodes = []
|
||||
|
||||
build_volume_bounding_box = self.getBoundingBox()
|
||||
if build_volume_bounding_box:
|
||||
# It's over 9000!
|
||||
build_volume_bounding_box = build_volume_bounding_box.set(bottom=-9001)
|
||||
else:
|
||||
# No bounding box. This is triggered when running Cura from command line with a model for the first time
|
||||
# In that situation there is a model, but no machine (and therefore no build volume.
|
||||
return
|
||||
|
||||
for node in nodes:
|
||||
# Need to check group nodes later
|
||||
if node.callDecoration("isGroup"):
|
||||
group_nodes.append(node) # Keep list of affected group_nodes
|
||||
|
||||
if node.callDecoration("isSliceable") or node.callDecoration("isGroup"):
|
||||
node._outside_buildarea = False
|
||||
bbox = node.getBoundingBox()
|
||||
|
||||
# Mark the node as outside the build volume if the bounding box test fails.
|
||||
if build_volume_bounding_box.intersectsBox(bbox) != AxisAlignedBox.IntersectionResult.FullIntersection:
|
||||
node._outside_buildarea = True
|
||||
continue
|
||||
|
||||
convex_hull = node.callDecoration("getConvexHull")
|
||||
if convex_hull:
|
||||
if not convex_hull.isValid():
|
||||
return
|
||||
# Check for collisions between disallowed areas and the object
|
||||
for area in self.getDisallowedAreas():
|
||||
overlap = convex_hull.intersectsPolygon(area)
|
||||
if overlap is None:
|
||||
continue
|
||||
node._outside_buildarea = True
|
||||
continue
|
||||
|
||||
# Group nodes should override the _outside_buildarea property of their children.
|
||||
for group_node in group_nodes:
|
||||
for child_node in group_node.getAllChildren():
|
||||
child_node._outside_buildarea = group_node._outside_buildarea
|
||||
|
||||
## Recalculates the build volume & disallowed areas.
|
||||
def rebuild(self):
|
||||
if not self._width or not self._height or not self._depth:
|
||||
@ -362,10 +415,12 @@ class BuildVolume(SceneNode):
|
||||
|
||||
Application.getInstance().getController().getScene()._maximum_bounds = scale_to_max_bounds
|
||||
|
||||
def getBoundingBox(self):
|
||||
self.updateNodeBoundaryCheck()
|
||||
|
||||
def getBoundingBox(self) -> AxisAlignedBox:
|
||||
return self._volume_aabb
|
||||
|
||||
def getRaftThickness(self):
|
||||
def getRaftThickness(self) -> float:
|
||||
return self._raft_thickness
|
||||
|
||||
def _updateRaftThickness(self):
|
||||
@ -442,7 +497,7 @@ class BuildVolume(SceneNode):
|
||||
self._engine_ready = True
|
||||
self.rebuild()
|
||||
|
||||
def _onSettingPropertyChanged(self, setting_key, property_name):
|
||||
def _onSettingPropertyChanged(self, setting_key: str, property_name: str):
|
||||
if property_name != "value":
|
||||
return
|
||||
|
||||
@ -475,7 +530,7 @@ class BuildVolume(SceneNode):
|
||||
if rebuild_me:
|
||||
self.rebuild()
|
||||
|
||||
def hasErrors(self):
|
||||
def hasErrors(self) -> bool:
|
||||
return self._has_errors
|
||||
|
||||
## Calls _updateDisallowedAreas and makes sure the changes appear in the
|
||||
|
@ -59,7 +59,8 @@ class ConvexHullDecorator(SceneNodeDecorator):
|
||||
hull = self._compute2DConvexHull()
|
||||
|
||||
if self._global_stack and self._node:
|
||||
if self._global_stack.getProperty("print_sequence", "value") == "one_at_a_time" and not self._node.getParent().callDecoration("isGroup"):
|
||||
# Parent can be None if node is just loaded.
|
||||
if self._global_stack.getProperty("print_sequence", "value") == "one_at_a_time" and (self._node.getParent() is None or not self._node.getParent().callDecoration("isGroup")):
|
||||
hull = hull.getMinkowskiHull(Polygon(numpy.array(self._global_stack.getProperty("machine_head_polygon", "value"), numpy.float32)))
|
||||
hull = self._add2DAdhesionMargin(hull)
|
||||
return hull
|
||||
@ -79,7 +80,7 @@ class ConvexHullDecorator(SceneNodeDecorator):
|
||||
return None
|
||||
|
||||
if self._global_stack:
|
||||
if self._global_stack.getProperty("print_sequence", "value") == "one_at_a_time" and not self._node.getParent().callDecoration("isGroup"):
|
||||
if self._global_stack.getProperty("print_sequence", "value") == "one_at_a_time" and (self._node.getParent() is None or not self._node.getParent().callDecoration("isGroup")):
|
||||
head_with_fans = self._compute2DConvexHeadMin()
|
||||
head_with_fans_with_adhesion_margin = self._add2DAdhesionMargin(head_with_fans)
|
||||
return head_with_fans_with_adhesion_margin
|
||||
@ -93,8 +94,7 @@ class ConvexHullDecorator(SceneNodeDecorator):
|
||||
return None
|
||||
|
||||
if self._global_stack:
|
||||
if self._global_stack.getProperty("print_sequence", "value") == "one_at_a_time" and not self._node.getParent().callDecoration("isGroup"):
|
||||
|
||||
if self._global_stack.getProperty("print_sequence", "value") == "one_at_a_time" and (self._node.getParent() is None or not self._node.getParent().callDecoration("isGroup")):
|
||||
# Printing one at a time and it's not an object in a group
|
||||
return self._compute2DConvexHull()
|
||||
return None
|
||||
@ -258,12 +258,16 @@ class ConvexHullDecorator(SceneNodeDecorator):
|
||||
# influences the collision area.
|
||||
def _offsetHull(self, convex_hull):
|
||||
horizontal_expansion = self._getSettingProperty("xy_offset", "value")
|
||||
if horizontal_expansion != 0:
|
||||
mold_width = 0
|
||||
if self._getSettingProperty("mold_enabled", "value"):
|
||||
mold_width = self._getSettingProperty("mold_width", "value")
|
||||
hull_offset = horizontal_expansion + mold_width
|
||||
if hull_offset != 0:
|
||||
expansion_polygon = Polygon(numpy.array([
|
||||
[-horizontal_expansion, -horizontal_expansion],
|
||||
[-horizontal_expansion, horizontal_expansion],
|
||||
[horizontal_expansion, horizontal_expansion],
|
||||
[horizontal_expansion, -horizontal_expansion]
|
||||
[-hull_offset, -hull_offset],
|
||||
[-hull_offset, hull_offset],
|
||||
[hull_offset, hull_offset],
|
||||
[hull_offset, -hull_offset]
|
||||
], numpy.float32))
|
||||
return convex_hull.getMinkowskiHull(expansion_polygon)
|
||||
else:
|
||||
@ -331,4 +335,4 @@ class ConvexHullDecorator(SceneNodeDecorator):
|
||||
## Settings that change the convex hull.
|
||||
#
|
||||
# If these settings change, the convex hull should be recalculated.
|
||||
_influencing_settings = {"xy_offset"}
|
||||
_influencing_settings = {"xy_offset", "mold_enabled", "mold_width"}
|
||||
|
@ -9,7 +9,10 @@ from UM.Mesh.MeshBuilder import MeshBuilder # To create a mesh to display the c
|
||||
|
||||
from UM.View.GL.OpenGL import OpenGL
|
||||
|
||||
|
||||
class ConvexHullNode(SceneNode):
|
||||
shader = None # To prevent the shader from being re-built over and over again, only load it once.
|
||||
|
||||
## Convex hull node is a special type of scene node that is used to display an area, to indicate the
|
||||
# location an object uses on the buildplate. This area (or area's in case of one at a time printing) is
|
||||
# then displayed as a transparent shadow. If the adhesion type is set to raft, the area is extruded
|
||||
@ -19,8 +22,6 @@ class ConvexHullNode(SceneNode):
|
||||
|
||||
self.setCalculateBoundingBox(False)
|
||||
|
||||
self._shader = None
|
||||
|
||||
self._original_parent = parent
|
||||
|
||||
# Color of the drawn convex hull
|
||||
@ -59,16 +60,16 @@ class ConvexHullNode(SceneNode):
|
||||
return self._node
|
||||
|
||||
def render(self, renderer):
|
||||
if not self._shader:
|
||||
self._shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "transparent_object.shader"))
|
||||
self._shader.setUniformValue("u_diffuseColor", self._color)
|
||||
self._shader.setUniformValue("u_opacity", 0.6)
|
||||
if not ConvexHullNode.shader:
|
||||
ConvexHullNode.shader = OpenGL.getInstance().createShaderProgram(Resources.getPath(Resources.Shaders, "transparent_object.shader"))
|
||||
ConvexHullNode.shader.setUniformValue("u_diffuseColor", self._color)
|
||||
ConvexHullNode.shader.setUniformValue("u_opacity", 0.6)
|
||||
|
||||
if self.getParent():
|
||||
if self.getMeshData():
|
||||
renderer.queueNode(self, transparent = True, shader = self._shader, backface_cull = True, sort = -8)
|
||||
renderer.queueNode(self, transparent = True, shader = ConvexHullNode.shader, backface_cull = True, sort = -8)
|
||||
if self._convex_hull_head_mesh:
|
||||
renderer.queueNode(self, shader = self._shader, transparent = True, mesh = self._convex_hull_head_mesh, backface_cull = True, sort = -8)
|
||||
renderer.queueNode(self, shader = ConvexHullNode.shader, transparent = True, mesh = self._convex_hull_head_mesh, backface_cull = True, sort = -8)
|
||||
|
||||
return True
|
||||
|
||||
|
@ -4,7 +4,6 @@ from PyQt5.QtNetwork import QLocalServer
|
||||
from PyQt5.QtNetwork import QLocalSocket
|
||||
|
||||
from UM.Qt.QtApplication import QtApplication
|
||||
from UM.FileHandler.ReadFileJob import ReadFileJob
|
||||
from UM.Scene.SceneNode import SceneNode
|
||||
from UM.Scene.Camera import Camera
|
||||
from UM.Math.Vector import Vector
|
||||
@ -17,7 +16,6 @@ from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
||||
from UM.Mesh.ReadMeshJob import ReadMeshJob
|
||||
from UM.Logger import Logger
|
||||
from UM.Preferences import Preferences
|
||||
from UM.JobQueue import JobQueue
|
||||
from UM.SaveFile import SaveFile
|
||||
from UM.Scene.Selection import Selection
|
||||
from UM.Scene.GroupDecorator import GroupDecorator
|
||||
@ -33,10 +31,16 @@ from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation
|
||||
from UM.Operations.RemoveSceneNodeOperation import RemoveSceneNodeOperation
|
||||
from UM.Operations.GroupedOperation import GroupedOperation
|
||||
from UM.Operations.SetTransformOperation import SetTransformOperation
|
||||
from cura.Arrange import Arrange
|
||||
from cura.ShapeArray import ShapeArray
|
||||
from cura.ConvexHullDecorator import ConvexHullDecorator
|
||||
from cura.SetParentOperation import SetParentOperation
|
||||
from cura.SliceableObjectDecorator import SliceableObjectDecorator
|
||||
from cura.BlockSlicingDecorator import BlockSlicingDecorator
|
||||
|
||||
from cura.ArrangeObjectsJob import ArrangeObjectsJob
|
||||
from cura.MultiplyObjectsJob import MultiplyObjectsJob
|
||||
|
||||
from UM.Settings.SettingDefinition import SettingDefinition, DefinitionPropertyType
|
||||
from UM.Settings.ContainerRegistry import ContainerRegistry
|
||||
from UM.Settings.SettingFunction import SettingFunction
|
||||
@ -90,6 +94,7 @@ if not MYPY:
|
||||
CuraVersion = "master" # [CodeStyle: Reflecting imported value]
|
||||
CuraBuildType = ""
|
||||
|
||||
|
||||
class CuraApplication(QtApplication):
|
||||
class ResourceTypes:
|
||||
QmlFiles = Resources.UserType + 1
|
||||
@ -104,7 +109,6 @@ class CuraApplication(QtApplication):
|
||||
Q_ENUMS(ResourceTypes)
|
||||
|
||||
def __init__(self):
|
||||
|
||||
Resources.addSearchPath(os.path.join(QtApplication.getInstallPrefix(), "share", "cura", "resources"))
|
||||
if not hasattr(sys, "frozen"):
|
||||
Resources.addSearchPath(os.path.join(os.path.abspath(os.path.dirname(__file__)), "..", "resources"))
|
||||
@ -184,7 +188,10 @@ class CuraApplication(QtApplication):
|
||||
"SelectionTool",
|
||||
"CameraTool",
|
||||
"GCodeWriter",
|
||||
"LocalFileOutputDevice"
|
||||
"LocalFileOutputDevice",
|
||||
"TranslateTool",
|
||||
"FileLogger",
|
||||
"XmlMaterialProfile"
|
||||
])
|
||||
self._physics = None
|
||||
self._volume = None
|
||||
@ -240,7 +247,7 @@ class CuraApplication(QtApplication):
|
||||
ContainerRegistry.getInstance().load()
|
||||
|
||||
Preferences.getInstance().addPreference("cura/active_mode", "simple")
|
||||
Preferences.getInstance().addPreference("cura/recent_files", "")
|
||||
|
||||
Preferences.getInstance().addPreference("cura/categories_expanded", "")
|
||||
Preferences.getInstance().addPreference("cura/jobname_prefix", True)
|
||||
Preferences.getInstance().addPreference("view/center_on_select", False)
|
||||
@ -316,20 +323,11 @@ class CuraApplication(QtApplication):
|
||||
experimental
|
||||
""".replace("\n", ";").replace(" ", ""))
|
||||
|
||||
JobQueue.getInstance().jobFinished.connect(self._onJobFinished)
|
||||
|
||||
self.applicationShuttingDown.connect(self.saveSettings)
|
||||
self.engineCreatedSignal.connect(self._onEngineCreated)
|
||||
|
||||
self.globalContainerStackChanged.connect(self._onGlobalContainerChanged)
|
||||
self._onGlobalContainerChanged()
|
||||
self._recent_files = []
|
||||
files = Preferences.getInstance().getValue("cura/recent_files").split(";")
|
||||
for f in files:
|
||||
if not os.path.isfile(f):
|
||||
continue
|
||||
|
||||
self._recent_files.append(QUrl.fromLocalFile(f))
|
||||
|
||||
def _onEngineCreated(self):
|
||||
self._engine.addImageProvider("camera", CameraImageProvider.CameraImageProvider())
|
||||
@ -594,6 +592,9 @@ class CuraApplication(QtApplication):
|
||||
# The platform is a child of BuildVolume
|
||||
self._volume = BuildVolume.BuildVolume(root)
|
||||
|
||||
# Set the build volume of the arranger to the used build volume
|
||||
Arrange.build_volume = self._volume
|
||||
|
||||
self.getRenderer().setBackgroundColor(QColor(245, 245, 245))
|
||||
|
||||
self._physics = PlatformPhysics.PlatformPhysics(controller, self._volume)
|
||||
@ -668,6 +669,7 @@ class CuraApplication(QtApplication):
|
||||
#
|
||||
# \param engine The QML engine.
|
||||
def registerObjects(self, engine):
|
||||
super().registerObjects(engine)
|
||||
engine.rootContext().setContextProperty("Printer", self)
|
||||
engine.rootContext().setContextProperty("CuraApplication", self)
|
||||
self._print_information = PrintInformation.PrintInformation()
|
||||
@ -701,14 +703,11 @@ class CuraApplication(QtApplication):
|
||||
if type_name in ("Cura", "Actions"):
|
||||
continue
|
||||
|
||||
qmlRegisterType(QUrl.fromLocalFile(path), "Cura", 1, 0, type_name)
|
||||
# Ignore anything that is not a QML file.
|
||||
if not path.endswith(".qml"):
|
||||
continue
|
||||
|
||||
## Get the backend of the application (the program that does the heavy lifting).
|
||||
# The backend is also a QObject, which can be used from qml.
|
||||
# \returns Backend \type{Backend}
|
||||
@pyqtSlot(result = "QObject*")
|
||||
def getBackend(self):
|
||||
return self._backend
|
||||
qmlRegisterType(QUrl.fromLocalFile(path), "Cura", 1, 0, type_name)
|
||||
|
||||
def onSelectionChanged(self):
|
||||
if Selection.hasSelection():
|
||||
@ -847,24 +846,14 @@ class CuraApplication(QtApplication):
|
||||
op.push()
|
||||
|
||||
## Create a number of copies of existing object.
|
||||
# \param object_id
|
||||
# \param count number of copies
|
||||
# \param min_offset minimum offset to other objects.
|
||||
@pyqtSlot("quint64", int)
|
||||
def multiplyObject(self, object_id, count):
|
||||
node = self.getController().getScene().findObject(object_id)
|
||||
|
||||
if not node and object_id != 0: # Workaround for tool handles overlapping the selected object
|
||||
node = Selection.getSelectedObject(0)
|
||||
|
||||
if node:
|
||||
current_node = node
|
||||
# Find the topmost group
|
||||
while current_node.getParent() and current_node.getParent().callDecoration("isGroup"):
|
||||
current_node = current_node.getParent()
|
||||
|
||||
op = GroupedOperation()
|
||||
for _ in range(count):
|
||||
new_node = copy.deepcopy(current_node)
|
||||
op.addOperation(AddSceneNodeOperation(new_node, current_node.getParent()))
|
||||
op.push()
|
||||
def multiplyObject(self, object_id, count, min_offset = 8):
|
||||
job = MultiplyObjectsJob(object_id, count, min_offset)
|
||||
job.start()
|
||||
return
|
||||
|
||||
## Center object on platform.
|
||||
@pyqtSlot("quint64")
|
||||
@ -982,6 +971,52 @@ class CuraApplication(QtApplication):
|
||||
op.addOperation(SetTransformOperation(node, Vector(0, center_y, 0), Quaternion(), Vector(1, 1, 1)))
|
||||
op.push()
|
||||
|
||||
## Arrange all objects.
|
||||
@pyqtSlot()
|
||||
def arrangeAll(self):
|
||||
nodes = []
|
||||
for node in DepthFirstIterator(self.getController().getScene().getRoot()):
|
||||
if type(node) is not SceneNode:
|
||||
continue
|
||||
if not node.getMeshData() and not node.callDecoration("isGroup"):
|
||||
continue # Node that doesnt have a mesh and is not a group.
|
||||
if node.getParent() and node.getParent().callDecoration("isGroup"):
|
||||
continue # Grouped nodes don't need resetting as their parent (the group) is resetted)
|
||||
if not node.isSelectable():
|
||||
continue # i.e. node with layer data
|
||||
# Skip nodes that are too big
|
||||
if node.getBoundingBox().width < self._volume.getBoundingBox().width or node.getBoundingBox().depth < self._volume.getBoundingBox().depth:
|
||||
nodes.append(node)
|
||||
self.arrange(nodes, fixed_nodes = [])
|
||||
|
||||
## Arrange Selection
|
||||
@pyqtSlot()
|
||||
def arrangeSelection(self):
|
||||
nodes = Selection.getAllSelectedObjects()
|
||||
|
||||
# What nodes are on the build plate and are not being moved
|
||||
fixed_nodes = []
|
||||
for node in DepthFirstIterator(self.getController().getScene().getRoot()):
|
||||
if type(node) is not SceneNode:
|
||||
continue
|
||||
if not node.getMeshData() and not node.callDecoration("isGroup"):
|
||||
continue # Node that doesnt have a mesh and is not a group.
|
||||
if node.getParent() and node.getParent().callDecoration("isGroup"):
|
||||
continue # Grouped nodes don't need resetting as their parent (the group) is resetted)
|
||||
if not node.isSelectable():
|
||||
continue # i.e. node with layer data
|
||||
if node in nodes: # exclude selected node from fixed_nodes
|
||||
continue
|
||||
fixed_nodes.append(node)
|
||||
self.arrange(nodes, fixed_nodes)
|
||||
|
||||
## Arrange a set of nodes given a set of fixed nodes
|
||||
# \param nodes nodes that we have to place
|
||||
# \param fixed_nodes nodes that are placed in the arranger before finding spots for nodes
|
||||
def arrange(self, nodes, fixed_nodes):
|
||||
job = ArrangeObjectsJob(nodes, fixed_nodes)
|
||||
job.start()
|
||||
|
||||
## Reload all mesh data on the screen from file.
|
||||
@pyqtSlot()
|
||||
def reloadAll(self):
|
||||
@ -1017,12 +1052,6 @@ class CuraApplication(QtApplication):
|
||||
|
||||
return log
|
||||
|
||||
recentFilesChanged = pyqtSignal()
|
||||
|
||||
@pyqtProperty("QVariantList", notify = recentFilesChanged)
|
||||
def recentFiles(self):
|
||||
return self._recent_files
|
||||
|
||||
@pyqtSlot("QStringList")
|
||||
def setExpandedCategories(self, categories):
|
||||
categories = list(set(categories))
|
||||
@ -1130,25 +1159,6 @@ class CuraApplication(QtApplication):
|
||||
|
||||
fileLoaded = pyqtSignal(str)
|
||||
|
||||
def _onJobFinished(self, job):
|
||||
if (not isinstance(job, ReadMeshJob) and not isinstance(job, ReadFileJob)) or not job.getResult():
|
||||
return
|
||||
|
||||
f = QUrl.fromLocalFile(job.getFileName())
|
||||
if f in self._recent_files:
|
||||
self._recent_files.remove(f)
|
||||
|
||||
self._recent_files.insert(0, f)
|
||||
if len(self._recent_files) > 10:
|
||||
del self._recent_files[10]
|
||||
|
||||
pref = ""
|
||||
for path in self._recent_files:
|
||||
pref += path.toLocalFile() + ";"
|
||||
|
||||
Preferences.getInstance().setValue("cura/recent_files", pref)
|
||||
self.recentFilesChanged.emit()
|
||||
|
||||
def _reloadMeshFinished(self, job):
|
||||
# TODO; This needs to be fixed properly. We now make the assumption that we only load a single mesh!
|
||||
mesh_data = job.getResult()[0].getMeshData()
|
||||
@ -1243,6 +1253,10 @@ class CuraApplication(QtApplication):
|
||||
filename = job.getFileName()
|
||||
self._currently_loading_files.remove(filename)
|
||||
|
||||
root = self.getController().getScene().getRoot()
|
||||
arranger = Arrange.create(scene_root = root)
|
||||
min_offset = 8
|
||||
|
||||
for node in nodes:
|
||||
node.setSelectable(True)
|
||||
node.setName(os.path.basename(filename))
|
||||
@ -1263,9 +1277,24 @@ class CuraApplication(QtApplication):
|
||||
|
||||
scene = self.getController().getScene()
|
||||
|
||||
# If there is no convex hull for the node, start calculating it and continue.
|
||||
if not node.getDecorator(ConvexHullDecorator):
|
||||
node.addDecorator(ConvexHullDecorator())
|
||||
for child in node.getAllChildren():
|
||||
if not child.getDecorator(ConvexHullDecorator):
|
||||
child.addDecorator(ConvexHullDecorator())
|
||||
|
||||
if node.callDecoration("isSliceable"):
|
||||
# Only check position if it's not already blatantly obvious that it won't fit.
|
||||
if node.getBoundingBox().width < self._volume.getBoundingBox().width or node.getBoundingBox().depth < self._volume.getBoundingBox().depth:
|
||||
# Find node location
|
||||
offset_shape_arr, hull_shape_arr = ShapeArray.fromNode(node, min_offset = min_offset)
|
||||
|
||||
# Step is for skipping tests to make it a lot faster. it also makes the outcome somewhat rougher
|
||||
node, _ = arranger.findNodePlacement(node, offset_shape_arr, hull_shape_arr, step = 10)
|
||||
|
||||
op = AddSceneNodeOperation(node, scene.getRoot())
|
||||
op.push()
|
||||
|
||||
scene.sceneChanged.emit(node)
|
||||
|
||||
def addNonSliceableExtension(self, extension):
|
||||
@ -1276,10 +1305,14 @@ class CuraApplication(QtApplication):
|
||||
"""
|
||||
Checks if the given file URL is a valid project file.
|
||||
"""
|
||||
file_path = QUrl(file_url).toLocalFile()
|
||||
workspace_reader = self.getWorkspaceFileHandler().getReaderForFile(file_path)
|
||||
if workspace_reader is None:
|
||||
return False # non-project files won't get a reader
|
||||
try:
|
||||
file_path = QUrl(file_url).toLocalFile()
|
||||
workspace_reader = self.getWorkspaceFileHandler().getReaderForFile(file_path)
|
||||
if workspace_reader is None:
|
||||
return False # non-project files won't get a reader
|
||||
|
||||
result = workspace_reader.preRead(file_path, show_dialog=False)
|
||||
return result == WorkspaceReader.PreReadResult.accepted
|
||||
result = workspace_reader.preRead(file_path, show_dialog=False)
|
||||
return result == WorkspaceReader.PreReadResult.accepted
|
||||
except Exception as e:
|
||||
Logger.log("e", "Could not check file %s: %s", file_url, e)
|
||||
return False
|
||||
|
80
cura/MultiplyObjectsJob.py
Normal file
80
cura/MultiplyObjectsJob.py
Normal file
@ -0,0 +1,80 @@
|
||||
# Copyright (c) 2017 Ultimaker B.V.
|
||||
# Cura is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
from UM.Job import Job
|
||||
from UM.Scene.SceneNode import SceneNode
|
||||
from UM.Math.Vector import Vector
|
||||
from UM.Operations.SetTransformOperation import SetTransformOperation
|
||||
from UM.Operations.TranslateOperation import TranslateOperation
|
||||
from UM.Operations.GroupedOperation import GroupedOperation
|
||||
from UM.Logger import Logger
|
||||
from UM.Message import Message
|
||||
from UM.i18n import i18nCatalog
|
||||
i18n_catalog = i18nCatalog("cura")
|
||||
|
||||
from cura.ZOffsetDecorator import ZOffsetDecorator
|
||||
from cura.Arrange import Arrange
|
||||
from cura.ShapeArray import ShapeArray
|
||||
|
||||
from typing import List
|
||||
|
||||
from UM.Application import Application
|
||||
from UM.Scene.Selection import Selection
|
||||
from UM.Operations.AddSceneNodeOperation import AddSceneNodeOperation
|
||||
|
||||
|
||||
class MultiplyObjectsJob(Job):
|
||||
def __init__(self, object_id, count, min_offset = 8):
|
||||
super().__init__()
|
||||
self._object_id = object_id
|
||||
self._count = count
|
||||
self._min_offset = min_offset
|
||||
|
||||
def run(self):
|
||||
status_message = Message(i18n_catalog.i18nc("@info:status", "Multiplying and placing objects"), lifetime=0,
|
||||
dismissable=False, progress=0)
|
||||
status_message.show()
|
||||
scene = Application.getInstance().getController().getScene()
|
||||
node = scene.findObject(self._object_id)
|
||||
|
||||
if not node and self._object_id != 0: # Workaround for tool handles overlapping the selected object
|
||||
node = Selection.getSelectedObject(0)
|
||||
|
||||
# If object is part of a group, multiply group
|
||||
current_node = node
|
||||
while current_node.getParent() and current_node.getParent().callDecoration("isGroup"):
|
||||
current_node = current_node.getParent()
|
||||
|
||||
root = scene.getRoot()
|
||||
arranger = Arrange.create(scene_root=root)
|
||||
node_too_big = False
|
||||
if node.getBoundingBox().width < 300 or node.getBoundingBox().depth < 300:
|
||||
offset_shape_arr, hull_shape_arr = ShapeArray.fromNode(current_node, min_offset=self._min_offset)
|
||||
else:
|
||||
node_too_big = True
|
||||
nodes = []
|
||||
found_solution_for_all = True
|
||||
for i in range(self._count):
|
||||
# We do place the nodes one by one, as we want to yield in between.
|
||||
if not node_too_big:
|
||||
node, solution_found = arranger.findNodePlacement(current_node, offset_shape_arr, hull_shape_arr)
|
||||
if node_too_big or not solution_found:
|
||||
found_solution_for_all = False
|
||||
new_location = node.getPosition()
|
||||
new_location = new_location.set(z = 100 - i * 20)
|
||||
node.setPosition(new_location)
|
||||
|
||||
nodes.append(node)
|
||||
Job.yieldThread()
|
||||
status_message.setProgress((i + 1) / self._count * 100)
|
||||
|
||||
if nodes:
|
||||
op = GroupedOperation()
|
||||
for new_node in nodes:
|
||||
op.addOperation(AddSceneNodeOperation(new_node, current_node.getParent()))
|
||||
op.push()
|
||||
status_message.hide()
|
||||
|
||||
if not found_solution_for_all:
|
||||
no_full_solution_message = Message(i18n_catalog.i18nc("@info:status", "Unable to find a location within the build volume for all objects"))
|
||||
no_full_solution_message.show()
|
44
cura/PlatformPhysics.py
Normal file → Executable file
44
cura/PlatformPhysics.py
Normal file → Executable file
@ -3,10 +3,10 @@
|
||||
|
||||
from PyQt5.QtCore import QTimer
|
||||
|
||||
from UM.Application import Application
|
||||
from UM.Scene.SceneNode import SceneNode
|
||||
from UM.Scene.Iterator.BreadthFirstIterator import BreadthFirstIterator
|
||||
from UM.Math.Vector import Vector
|
||||
from UM.Math.AxisAlignedBox import AxisAlignedBox
|
||||
from UM.Scene.Selection import Selection
|
||||
from UM.Preferences import Preferences
|
||||
|
||||
@ -51,10 +51,13 @@ class PlatformPhysics:
|
||||
# same direction.
|
||||
transformed_nodes = []
|
||||
|
||||
group_nodes = []
|
||||
# We try to shuffle all the nodes to prevent "locked" situations, where iteration B inverts iteration A.
|
||||
# By shuffling the order of the nodes, this might happen a few times, but at some point it will resolve.
|
||||
nodes = list(BreadthFirstIterator(root))
|
||||
|
||||
# Only check nodes inside build area.
|
||||
nodes = [node for node in nodes if (hasattr(node, "_outside_buildarea") and not node._outside_buildarea)]
|
||||
|
||||
random.shuffle(nodes)
|
||||
for node in nodes:
|
||||
if node is root or type(node) is not SceneNode or node.getBoundingBox() is None:
|
||||
@ -62,24 +65,6 @@ class PlatformPhysics:
|
||||
|
||||
bbox = node.getBoundingBox()
|
||||
|
||||
# Ignore intersections with the bottom
|
||||
build_volume_bounding_box = self._build_volume.getBoundingBox()
|
||||
if build_volume_bounding_box:
|
||||
# It's over 9000!
|
||||
build_volume_bounding_box = build_volume_bounding_box.set(bottom=-9001)
|
||||
else:
|
||||
# No bounding box. This is triggered when running Cura from command line with a model for the first time
|
||||
# In that situation there is a model, but no machine (and therefore no build volume.
|
||||
return
|
||||
node._outside_buildarea = False
|
||||
|
||||
# Mark the node as outside the build volume if the bounding box test fails.
|
||||
if build_volume_bounding_box.intersectsBox(bbox) != AxisAlignedBox.IntersectionResult.FullIntersection:
|
||||
node._outside_buildarea = True
|
||||
|
||||
if node.callDecoration("isGroup"):
|
||||
group_nodes.append(node) # Keep list of affected group_nodes
|
||||
|
||||
# Move it downwards if bottom is above platform
|
||||
move_vector = Vector()
|
||||
if Preferences.getInstance().getValue("physics/automatic_drop_down") and not (node.getParent() and node.getParent().callDecoration("isGroup")) and node.isEnabled(): #If an object is grouped, don't move it down
|
||||
@ -145,27 +130,14 @@ class PlatformPhysics:
|
||||
# Simply waiting for the next tick seems to resolve this correctly.
|
||||
overlap = None
|
||||
|
||||
convex_hull = node.callDecoration("getConvexHull")
|
||||
if convex_hull:
|
||||
if not convex_hull.isValid():
|
||||
return
|
||||
# Check for collisions between disallowed areas and the object
|
||||
for area in self._build_volume.getDisallowedAreas():
|
||||
overlap = convex_hull.intersectsPolygon(area)
|
||||
if overlap is None:
|
||||
continue
|
||||
node._outside_buildarea = True
|
||||
|
||||
if not Vector.Null.equals(move_vector, epsilon=1e-5):
|
||||
transformed_nodes.append(node)
|
||||
op = PlatformPhysicsOperation.PlatformPhysicsOperation(node, move_vector)
|
||||
op.push()
|
||||
|
||||
# Group nodes should override the _outside_buildarea property of their children.
|
||||
for group_node in group_nodes:
|
||||
for child_node in group_node.getAllChildren():
|
||||
child_node._outside_buildarea = group_node._outside_buildarea
|
||||
|
||||
# After moving, we have to evaluate the boundary checks for nodes
|
||||
build_volume = Application.getInstance().getBuildVolume()
|
||||
build_volume.updateNodeBoundaryCheck()
|
||||
|
||||
def _onToolOperationStarted(self, tool):
|
||||
self._enabled = False
|
||||
|
@ -75,6 +75,8 @@ class PrintInformation(QObject):
|
||||
Application.getInstance().getMachineManager().activeMaterialChanged.connect(self._onActiveMaterialChanged)
|
||||
self._onActiveMaterialChanged()
|
||||
|
||||
self._material_amounts = []
|
||||
|
||||
currentPrintTimeChanged = pyqtSignal()
|
||||
|
||||
preSlicedChanged = pyqtSignal()
|
||||
|
@ -16,9 +16,9 @@ class QualityManager:
|
||||
|
||||
## Get the singleton instance for this class.
|
||||
@classmethod
|
||||
def getInstance(cls):
|
||||
def getInstance(cls) -> "QualityManager":
|
||||
# Note: Explicit use of class name to prevent issues with inheritance.
|
||||
if QualityManager.__instance is None:
|
||||
if not QualityManager.__instance:
|
||||
QualityManager.__instance = cls()
|
||||
return QualityManager.__instance
|
||||
|
||||
|
@ -244,7 +244,13 @@ class ExtruderManager(QObject):
|
||||
material = materials[0]
|
||||
preferred_material_id = machine_definition.getMetaDataEntry("preferred_material")
|
||||
if preferred_material_id:
|
||||
search_criteria = { "type": "material", "id": preferred_material_id}
|
||||
global_stack = ContainerRegistry.getInstance().findContainerStacks(id = machine_id)
|
||||
if global_stack:
|
||||
approximate_material_diameter = round(global_stack[0].getProperty("material_diameter", "value"))
|
||||
else:
|
||||
approximate_material_diameter = round(machine_definition.getProperty("material_diameter", "value"))
|
||||
|
||||
search_criteria = { "type": "material", "id": preferred_material_id, "approximate_diameter": approximate_material_diameter}
|
||||
if machine_definition.getMetaDataEntry("has_machine_materials"):
|
||||
search_criteria["definition"] = machine_definition_id
|
||||
|
||||
@ -255,7 +261,12 @@ class ExtruderManager(QObject):
|
||||
|
||||
preferred_materials = container_registry.findInstanceContainers(**search_criteria)
|
||||
if len(preferred_materials) >= 1:
|
||||
material = preferred_materials[0]
|
||||
# In some cases we get multiple materials. In that case, prefer materials that are marked as read only.
|
||||
read_only_preferred_materials = [preferred_material for preferred_material in preferred_materials if preferred_material.isReadOnly()]
|
||||
if len(read_only_preferred_materials) >= 1:
|
||||
material = read_only_preferred_materials[0]
|
||||
else:
|
||||
material = preferred_materials[0]
|
||||
else:
|
||||
Logger.log("w", "The preferred material \"%s\" of machine %s doesn't exist or is not a material profile.", preferred_material_id, machine_id)
|
||||
# And leave it at the default material.
|
||||
|
@ -2,7 +2,7 @@
|
||||
# Cura is released under the terms of the AGPLv3 or higher.
|
||||
from typing import Union
|
||||
|
||||
from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal
|
||||
from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal, QTimer
|
||||
from UM.FlameProfiler import pyqtSlot
|
||||
from PyQt5.QtWidgets import QMessageBox
|
||||
from UM import Util
|
||||
@ -15,9 +15,7 @@ from UM.Message import Message
|
||||
from UM.Settings.ContainerRegistry import ContainerRegistry
|
||||
from UM.Settings.ContainerStack import ContainerStack
|
||||
from UM.Settings.InstanceContainer import InstanceContainer
|
||||
from UM.Settings.SettingDefinition import SettingDefinition
|
||||
from UM.Settings.SettingFunction import SettingFunction
|
||||
from UM.Settings.Validator import ValidatorState
|
||||
from UM.Signal import postponeSignals
|
||||
|
||||
from cura.QualityManager import QualityManager
|
||||
@ -27,6 +25,11 @@ from cura.Settings.ExtruderManager import ExtruderManager
|
||||
from UM.i18n import i18nCatalog
|
||||
catalog = i18nCatalog("cura")
|
||||
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from UM.Settings.DefinitionContainer import DefinitionContainer
|
||||
|
||||
import os
|
||||
|
||||
class MachineManager(QObject):
|
||||
@ -83,6 +86,11 @@ class MachineManager(QObject):
|
||||
self._material_incompatible_message = Message(catalog.i18nc("@info:status",
|
||||
"The selected material is incompatible with the selected machine or configuration."))
|
||||
|
||||
self._error_check_timer = QTimer()
|
||||
self._error_check_timer.setInterval(250)
|
||||
self._error_check_timer.setSingleShot(True)
|
||||
self._error_check_timer.timeout.connect(self._updateStacksHaveErrors)
|
||||
|
||||
globalContainerChanged = pyqtSignal() # Emitted whenever the global stack is changed (ie: when changing between printers, changing a global profile, but not when changing a value)
|
||||
activeMaterialChanged = pyqtSignal()
|
||||
activeVariantChanged = pyqtSignal()
|
||||
@ -306,33 +314,7 @@ class MachineManager(QObject):
|
||||
self.activeStackValueChanged.emit()
|
||||
|
||||
elif property_name == "validationState":
|
||||
if not self._stacks_have_errors:
|
||||
# fast update, we only have to look at the current changed property
|
||||
if self._global_container_stack.getProperty("machine_extruder_count", "value") > 1 and self._active_container_stack.getProperty(key, "settable_per_extruder"):
|
||||
extruder_index = int(self._active_container_stack.getProperty(key, "limit_to_extruder"))
|
||||
if extruder_index >= 0: #We have to look up the value from a different extruder.
|
||||
stack = ExtruderManager.getInstance().getExtruderStack(str(extruder_index))
|
||||
else:
|
||||
stack = self._active_container_stack
|
||||
else:
|
||||
stack = self._global_container_stack
|
||||
changed_validation_state = stack.getProperty(key, property_name)
|
||||
|
||||
if changed_validation_state is None:
|
||||
# Setting is not validated. This can happen if there is only a setting definition.
|
||||
# We do need to validate it, because a setting defintions value can be set by a function, which could
|
||||
# be an invalid setting.
|
||||
definition = self._active_container_stack.getSettingDefinition(key)
|
||||
validator_type = SettingDefinition.getValidatorForType(definition.type)
|
||||
if validator_type:
|
||||
validator = validator_type(key)
|
||||
changed_validation_state = validator(self._active_container_stack)
|
||||
if changed_validation_state in (ValidatorState.Exception, ValidatorState.MaximumError, ValidatorState.MinimumError):
|
||||
self._stacks_have_errors = True
|
||||
self.stacksValidationChanged.emit()
|
||||
else:
|
||||
# Normal check
|
||||
self._updateStacksHaveErrors()
|
||||
self._error_check_timer.start()
|
||||
|
||||
@pyqtSlot(str)
|
||||
def setActiveMachine(self, stack_id: str) -> None:
|
||||
@ -350,10 +332,11 @@ class MachineManager(QObject):
|
||||
name = self._createUniqueName("machine", "", name, definition.getName())
|
||||
new_global_stack = ContainerStack(name)
|
||||
new_global_stack.addMetaDataEntry("type", "machine")
|
||||
new_global_stack.addContainer(definition)
|
||||
container_registry.addContainer(new_global_stack)
|
||||
|
||||
variant_instance_container = self._updateVariantContainer(definition)
|
||||
material_instance_container = self._updateMaterialContainer(definition, variant_instance_container)
|
||||
material_instance_container = self._updateMaterialContainer(definition, new_global_stack, variant_instance_container)
|
||||
quality_instance_container = self._updateQualityContainer(definition, variant_instance_container, material_instance_container)
|
||||
|
||||
current_settings_instance_container = InstanceContainer(name + "_current_settings")
|
||||
@ -362,7 +345,7 @@ class MachineManager(QObject):
|
||||
current_settings_instance_container.setDefinition(definitions[0])
|
||||
container_registry.addContainer(current_settings_instance_container)
|
||||
|
||||
new_global_stack.addContainer(definition)
|
||||
|
||||
if variant_instance_container:
|
||||
new_global_stack.addContainer(variant_instance_container)
|
||||
if material_instance_container:
|
||||
@ -781,7 +764,7 @@ class MachineManager(QObject):
|
||||
if old_material:
|
||||
preferred_material_name = old_material.getName()
|
||||
|
||||
self.setActiveMaterial(self._updateMaterialContainer(self._global_container_stack.getBottom(), containers[0], preferred_material_name).id)
|
||||
self.setActiveMaterial(self._updateMaterialContainer(self._global_container_stack.getBottom(), self._global_container_stack, containers[0], preferred_material_name).id)
|
||||
else:
|
||||
Logger.log("w", "While trying to set the active variant, no variant was found to replace.")
|
||||
|
||||
@ -1115,7 +1098,7 @@ class MachineManager(QObject):
|
||||
def createMachineManager(engine=None, script_engine=None):
|
||||
return MachineManager()
|
||||
|
||||
def _updateVariantContainer(self, definition):
|
||||
def _updateVariantContainer(self, definition: "DefinitionContainer"):
|
||||
if not definition.getMetaDataEntry("has_variants"):
|
||||
return self._empty_variant_container
|
||||
machine_definition_id = Application.getInstance().getMachineManager().getQualityDefinitionId(definition)
|
||||
@ -1131,11 +1114,12 @@ class MachineManager(QObject):
|
||||
|
||||
return self._empty_variant_container
|
||||
|
||||
def _updateMaterialContainer(self, definition, variant_container = None, preferred_material_name = None):
|
||||
def _updateMaterialContainer(self, definition: "DefinitionContainer", stack: "ContainerStack", variant_container: Optional["InstanceContainer"] = None, preferred_material_name: Optional[str] = None):
|
||||
if not definition.getMetaDataEntry("has_materials"):
|
||||
return self._empty_material_container
|
||||
|
||||
search_criteria = { "type": "material" }
|
||||
approximate_material_diameter = round(stack.getProperty("material_diameter", "value"))
|
||||
search_criteria = { "type": "material", "approximate_diameter": approximate_material_diameter }
|
||||
|
||||
if definition.getMetaDataEntry("has_machine_materials"):
|
||||
search_criteria["definition"] = self.getQualityDefinitionId(definition)
|
||||
@ -1167,7 +1151,7 @@ class MachineManager(QObject):
|
||||
Logger.log("w", "Unable to find a material container with provided criteria, returning an empty one instead.")
|
||||
return self._empty_material_container
|
||||
|
||||
def _updateQualityContainer(self, definition, variant_container, material_container = None, preferred_quality_name = None):
|
||||
def _updateQualityContainer(self, definition: "DefinitionContainer", variant_container: "ContainerStack", material_container = None, preferred_quality_name: Optional[str] = None):
|
||||
container_registry = ContainerRegistry.getInstance()
|
||||
search_criteria = { "type": "quality" }
|
||||
|
||||
|
@ -32,9 +32,9 @@ class ProfilesModel(InstanceContainersModel):
|
||||
|
||||
## Get the singleton instance for this class.
|
||||
@classmethod
|
||||
def getInstance(cls):
|
||||
def getInstance(cls) -> "ProfilesModel":
|
||||
# Note: Explicit use of class name to prevent issues with inheritance.
|
||||
if ProfilesModel.__instance is None:
|
||||
if not ProfilesModel.__instance:
|
||||
ProfilesModel.__instance = cls()
|
||||
return ProfilesModel.__instance
|
||||
|
||||
|
113
cura/ShapeArray.py
Executable file
113
cura/ShapeArray.py
Executable file
@ -0,0 +1,113 @@
|
||||
import numpy
|
||||
import copy
|
||||
|
||||
from UM.Math.Polygon import Polygon
|
||||
|
||||
|
||||
## Polygon representation as an array for use with Arrange
|
||||
class ShapeArray:
|
||||
def __init__(self, arr, offset_x, offset_y, scale = 1):
|
||||
self.arr = arr
|
||||
self.offset_x = offset_x
|
||||
self.offset_y = offset_y
|
||||
self.scale = scale
|
||||
|
||||
## Instantiate from a bunch of vertices
|
||||
# \param vertices
|
||||
# \param scale scale the coordinates
|
||||
@classmethod
|
||||
def fromPolygon(cls, vertices, scale = 1):
|
||||
# scale
|
||||
vertices = vertices * scale
|
||||
# flip y, x -> x, y
|
||||
flip_vertices = numpy.zeros((vertices.shape))
|
||||
flip_vertices[:, 0] = vertices[:, 1]
|
||||
flip_vertices[:, 1] = vertices[:, 0]
|
||||
flip_vertices = flip_vertices[::-1]
|
||||
# offset, we want that all coordinates have positive values
|
||||
offset_y = int(numpy.amin(flip_vertices[:, 0]))
|
||||
offset_x = int(numpy.amin(flip_vertices[:, 1]))
|
||||
flip_vertices[:, 0] = numpy.add(flip_vertices[:, 0], -offset_y)
|
||||
flip_vertices[:, 1] = numpy.add(flip_vertices[:, 1], -offset_x)
|
||||
shape = [int(numpy.amax(flip_vertices[:, 0])), int(numpy.amax(flip_vertices[:, 1]))]
|
||||
arr = cls.arrayFromPolygon(shape, flip_vertices)
|
||||
return cls(arr, offset_x, offset_y)
|
||||
|
||||
## Instantiate an offset and hull ShapeArray from a scene node.
|
||||
# \param node source node where the convex hull must be present
|
||||
# \param min_offset offset for the offset ShapeArray
|
||||
# \param scale scale the coordinates
|
||||
@classmethod
|
||||
def fromNode(cls, node, min_offset, scale = 0.5):
|
||||
transform = node._transformation
|
||||
transform_x = transform._data[0][3]
|
||||
transform_y = transform._data[2][3]
|
||||
hull_verts = node.callDecoration("getConvexHull")
|
||||
# For one_at_a_time printing you need the convex hull head.
|
||||
hull_head_verts = node.callDecoration("getConvexHullHead") or hull_verts
|
||||
|
||||
offset_verts = hull_head_verts.getMinkowskiHull(Polygon.approximatedCircle(min_offset))
|
||||
offset_points = copy.deepcopy(offset_verts._points) # x, y
|
||||
offset_points[:, 0] = numpy.add(offset_points[:, 0], -transform_x)
|
||||
offset_points[:, 1] = numpy.add(offset_points[:, 1], -transform_y)
|
||||
offset_shape_arr = ShapeArray.fromPolygon(offset_points, scale = scale)
|
||||
|
||||
hull_points = copy.deepcopy(hull_verts._points)
|
||||
hull_points[:, 0] = numpy.add(hull_points[:, 0], -transform_x)
|
||||
hull_points[:, 1] = numpy.add(hull_points[:, 1], -transform_y)
|
||||
hull_shape_arr = ShapeArray.fromPolygon(hull_points, scale = scale) # x, y
|
||||
|
||||
return offset_shape_arr, hull_shape_arr
|
||||
|
||||
## Create np.array with dimensions defined by shape
|
||||
# Fills polygon defined by vertices with ones, all other values zero
|
||||
# Only works correctly for convex hull vertices
|
||||
# Originally from: http://stackoverflow.com/questions/37117878/generating-a-filled-polygon-inside-a-numpy-array
|
||||
# \param shape numpy format shape, [x-size, y-size]
|
||||
# \param vertices
|
||||
@classmethod
|
||||
def arrayFromPolygon(cls, shape, vertices):
|
||||
base_array = numpy.zeros(shape, dtype=float) # Initialize your array of zeros
|
||||
|
||||
fill = numpy.ones(base_array.shape) * True # Initialize boolean array defining shape fill
|
||||
|
||||
# Create check array for each edge segment, combine into fill array
|
||||
for k in range(vertices.shape[0]):
|
||||
fill = numpy.all([fill, cls._check(vertices[k - 1], vertices[k], base_array)], axis=0)
|
||||
|
||||
# Set all values inside polygon to one
|
||||
base_array[fill] = 1
|
||||
|
||||
return base_array
|
||||
|
||||
## Return indices that mark one side of the line, used by arrayFromPolygon
|
||||
# Uses the line defined by p1 and p2 to check array of
|
||||
# input indices against interpolated value
|
||||
# Returns boolean array, with True inside and False outside of shape
|
||||
# Originally from: http://stackoverflow.com/questions/37117878/generating-a-filled-polygon-inside-a-numpy-array
|
||||
# \param p1 2-tuple with x, y for point 1
|
||||
# \param p2 2-tuple with x, y for point 2
|
||||
# \param base_array boolean array to project the line on
|
||||
@classmethod
|
||||
def _check(cls, p1, p2, base_array):
|
||||
if p1[0] == p2[0] and p1[1] == p2[1]:
|
||||
return
|
||||
idxs = numpy.indices(base_array.shape) # Create 3D array of indices
|
||||
|
||||
p1 = p1.astype(float)
|
||||
p2 = p2.astype(float)
|
||||
|
||||
if p2[0] == p1[0]:
|
||||
sign = numpy.sign(p2[1] - p1[1])
|
||||
return idxs[1] * sign
|
||||
|
||||
if p2[1] == p1[1]:
|
||||
sign = numpy.sign(p2[0] - p1[0])
|
||||
return idxs[1] * sign
|
||||
|
||||
# Calculate max column idx for each row idx based on interpolated line between two points
|
||||
|
||||
max_col_idx = (idxs[0] - p1[0]) / (p2[0] - p1[0]) * (p2[1] - p1[1]) + p1[1]
|
||||
sign = numpy.sign(p2[0] - p1[0])
|
||||
return idxs[1] * sign <= max_col_idx * sign
|
||||
|
@ -12,15 +12,15 @@ UM.Dialog
|
||||
{
|
||||
title: catalog.i18nc("@title:window", "Open Project")
|
||||
|
||||
width: 550
|
||||
minimumWidth: 550
|
||||
maximumWidth: 550
|
||||
width: 550 * Screen.devicePixelRatio
|
||||
minimumWidth: 550 * Screen.devicePixelRatio
|
||||
maximumWidth: minimumWidth
|
||||
|
||||
height: 400
|
||||
minimumHeight: 400
|
||||
maximumHeight: 400
|
||||
property int comboboxHeight: 15
|
||||
property int spacerHeight: 10
|
||||
height: 400 * Screen.devicePixelRatio
|
||||
minimumHeight: 400 * Screen.devicePixelRatio
|
||||
maximumHeight: minimumHeight
|
||||
property int comboboxHeight: 15 * Screen.devicePixelRatio
|
||||
property int spacerHeight: 10 * Screen.devicePixelRatio
|
||||
onClosing: manager.notifyClosed()
|
||||
onVisibleChanged:
|
||||
{
|
||||
@ -33,20 +33,17 @@ UM.Dialog
|
||||
}
|
||||
Item
|
||||
{
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
anchors.topMargin: 20
|
||||
anchors.bottomMargin: 20
|
||||
anchors.leftMargin:20
|
||||
anchors.rightMargin: 20
|
||||
anchors.fill: parent
|
||||
anchors.margins: 20 * Screen.devicePixelRatio
|
||||
|
||||
UM.I18nCatalog
|
||||
{
|
||||
id: catalog;
|
||||
name: "cura";
|
||||
id: catalog
|
||||
name: "cura"
|
||||
}
|
||||
SystemPalette
|
||||
{
|
||||
id: palette
|
||||
}
|
||||
|
||||
ListModel
|
||||
@ -70,12 +67,12 @@ UM.Dialog
|
||||
{
|
||||
id: titleLabel
|
||||
text: catalog.i18nc("@action:title", "Summary - Cura Project")
|
||||
font.pixelSize: 22
|
||||
font.pointSize: 18
|
||||
}
|
||||
Rectangle
|
||||
{
|
||||
id: separator
|
||||
color: "black"
|
||||
color: palette.text
|
||||
width: parent.width
|
||||
height: 1
|
||||
}
|
||||
@ -93,7 +90,7 @@ UM.Dialog
|
||||
{
|
||||
text: catalog.i18nc("@action:label", "Printer settings")
|
||||
font.bold: true
|
||||
width: parent.width /3
|
||||
width: parent.width / 3
|
||||
}
|
||||
Item
|
||||
{
|
||||
@ -360,7 +357,7 @@ UM.Dialog
|
||||
height: width
|
||||
|
||||
source: UM.Theme.getIcon("notice")
|
||||
color: "black"
|
||||
color: palette.text
|
||||
|
||||
}
|
||||
Label
|
||||
@ -392,4 +389,4 @@ UM.Dialog
|
||||
anchors.right: parent.right
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,16 @@
|
||||
# Copyright (c) 2015 Ultimaker B.V.
|
||||
# Cura is released under the terms of the AGPLv3 or higher.
|
||||
from typing import Dict
|
||||
import sys
|
||||
|
||||
from UM.Logger import Logger
|
||||
try:
|
||||
from . import ThreeMFReader
|
||||
except ImportError:
|
||||
Logger.log("w", "Could not import ThreeMFReader; libSavitar may be missing")
|
||||
|
||||
from . import ThreeMFReader
|
||||
from . import ThreeMFWorkspaceReader
|
||||
|
||||
from UM.i18n import i18nCatalog
|
||||
from UM.Platform import Platform
|
||||
catalog = i18nCatalog("cura")
|
||||
@ -14,30 +21,36 @@ def getMetaData() -> Dict:
|
||||
workspace_extension = "3mf"
|
||||
else:
|
||||
workspace_extension = "curaproject.3mf"
|
||||
return {
|
||||
|
||||
metaData = {
|
||||
"plugin": {
|
||||
"name": catalog.i18nc("@label", "3MF Reader"),
|
||||
"author": "Ultimaker",
|
||||
"version": "1.0",
|
||||
"description": catalog.i18nc("@info:whatsthis", "Provides support for reading 3MF files."),
|
||||
"api": 3
|
||||
},
|
||||
"mesh_reader": [
|
||||
}
|
||||
}
|
||||
if "3MFReader.ThreeMFReader" in sys.modules:
|
||||
metaData["mesh_reader"] = [
|
||||
{
|
||||
"extension": "3mf",
|
||||
"description": catalog.i18nc("@item:inlistbox", "3MF File")
|
||||
}
|
||||
],
|
||||
"workspace_reader":
|
||||
[
|
||||
]
|
||||
metaData["workspace_reader"] = [
|
||||
{
|
||||
"extension": workspace_extension,
|
||||
"description": catalog.i18nc("@item:inlistbox", "3MF File")
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
return metaData
|
||||
|
||||
|
||||
def register(app):
|
||||
return {"mesh_reader": ThreeMFReader.ThreeMFReader(),
|
||||
"workspace_reader": ThreeMFWorkspaceReader.ThreeMFWorkspaceReader()}
|
||||
if "3MFReader.ThreeMFReader" in sys.modules:
|
||||
return {"mesh_reader": ThreeMFReader.ThreeMFReader(),
|
||||
"workspace_reader": ThreeMFWorkspaceReader.ThreeMFWorkspaceReader()}
|
||||
else:
|
||||
return {}
|
||||
|
@ -1,30 +1,39 @@
|
||||
# Copyright (c) 2015 Ultimaker B.V.
|
||||
# Uranium is released under the terms of the AGPLv3 or higher.
|
||||
import sys
|
||||
|
||||
from UM.Logger import Logger
|
||||
try:
|
||||
from . import ThreeMFWriter
|
||||
except ImportError:
|
||||
Logger.log("w", "Could not import ThreeMFWriter; libSavitar may be missing")
|
||||
from . import ThreeMFWorkspaceWriter
|
||||
|
||||
from UM.i18n import i18nCatalog
|
||||
from . import ThreeMFWorkspaceWriter
|
||||
from . import ThreeMFWriter
|
||||
|
||||
i18n_catalog = i18nCatalog("uranium")
|
||||
|
||||
def getMetaData():
|
||||
return {
|
||||
metaData = {
|
||||
"plugin": {
|
||||
"name": i18n_catalog.i18nc("@label", "3MF Writer"),
|
||||
"author": "Ultimaker",
|
||||
"version": "1.0",
|
||||
"description": i18n_catalog.i18nc("@info:whatsthis", "Provides support for writing 3MF files."),
|
||||
"api": 3
|
||||
},
|
||||
"mesh_writer": {
|
||||
}
|
||||
}
|
||||
|
||||
if "3MFWriter.ThreeMFWriter" in sys.modules:
|
||||
metaData["mesh_writer"] = {
|
||||
"output": [{
|
||||
"extension": "3mf",
|
||||
"description": i18n_catalog.i18nc("@item:inlistbox", "3MF file"),
|
||||
"mime_type": "application/vnd.ms-package.3dmanufacturing-3dmodel+xml",
|
||||
"mode": ThreeMFWriter.ThreeMFWriter.OutputMode.BinaryMode
|
||||
}]
|
||||
},
|
||||
"workspace_writer": {
|
||||
}
|
||||
metaData["workspace_writer"] = {
|
||||
"output": [{
|
||||
"extension": "curaproject.3mf",
|
||||
"description": i18n_catalog.i18nc("@item:inlistbox", "Cura Project 3MF file"),
|
||||
@ -32,7 +41,12 @@ def getMetaData():
|
||||
"mode": ThreeMFWorkspaceWriter.ThreeMFWorkspaceWriter.OutputMode.BinaryMode
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
return metaData
|
||||
|
||||
def register(app):
|
||||
return {"mesh_writer": ThreeMFWriter.ThreeMFWriter(), "workspace_writer": ThreeMFWorkspaceWriter.ThreeMFWorkspaceWriter()}
|
||||
if "3MFWriter.ThreeMFWriter" in sys.modules:
|
||||
return {"mesh_writer": ThreeMFWriter.ThreeMFWriter(),
|
||||
"workspace_writer": ThreeMFWorkspaceWriter.ThreeMFWorkspaceWriter()}
|
||||
else:
|
||||
return {}
|
||||
|
@ -2,6 +2,7 @@
|
||||
# Cura is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
from UM.Application import Application
|
||||
from UM.Backend import Backend
|
||||
from UM.Job import Job
|
||||
from UM.Logger import Logger
|
||||
from UM.Math.AxisAlignedBox import AxisAlignedBox
|
||||
@ -37,7 +38,6 @@ class GCodeReader(MeshReader):
|
||||
self._message = None
|
||||
self._layer_number = 0
|
||||
self._extruder_number = 0
|
||||
self._layer_type = LayerPolygon.Inset0Type
|
||||
self._clearValues()
|
||||
self._scene_node = None
|
||||
self._position = namedtuple('Position', ['x', 'y', 'z', 'e'])
|
||||
@ -153,7 +153,6 @@ class GCodeReader(MeshReader):
|
||||
self._previous_z = z
|
||||
else:
|
||||
path.append([x, y, z, LayerPolygon.MoveCombingType])
|
||||
|
||||
return self._position(x, y, z, e)
|
||||
|
||||
# G0 and G1 should be handled exactly the same.
|
||||
@ -172,7 +171,6 @@ class GCodeReader(MeshReader):
|
||||
def _gCode92(self, position, params, path):
|
||||
if params.e is not None:
|
||||
position.e[self._extruder_number] = params.e
|
||||
|
||||
return self._position(
|
||||
params.x if params.x is not None else position.x,
|
||||
params.y if params.y is not None else position.y,
|
||||
@ -181,6 +179,7 @@ class GCodeReader(MeshReader):
|
||||
|
||||
def _processGCode(self, G, line, position, path):
|
||||
func = getattr(self, "_gCode%s" % G, None)
|
||||
line = line.split(";", 1)[0] # Remove comments (if any)
|
||||
if func is not None:
|
||||
s = line.upper().split(" ")
|
||||
x, y, z, e = None, None, None, None
|
||||
@ -307,11 +306,11 @@ class GCodeReader(MeshReader):
|
||||
G = self._getInt(line, "G")
|
||||
if G is not None:
|
||||
current_position = self._processGCode(G, line, current_position, current_path)
|
||||
|
||||
# < 2 is a heuristic for a movement only, that should not be counted as a layer
|
||||
if current_position.z > last_z and abs(current_position.z - last_z) < 2:
|
||||
if self._createPolygon(self._current_layer_thickness, current_path, self._extruder_offsets.get(self._extruder_number, [0, 0])):
|
||||
current_path.clear()
|
||||
|
||||
if not self._is_layers_in_file:
|
||||
self._layer_number += 1
|
||||
|
||||
@ -343,6 +342,8 @@ class GCodeReader(MeshReader):
|
||||
gcode_list_decorator.setGCodeList(gcode_list)
|
||||
scene_node.addDecorator(gcode_list_decorator)
|
||||
|
||||
Application.getInstance().getController().getScene().gcode_list = gcode_list
|
||||
|
||||
Logger.log("d", "Finished parsing %s" % file_name)
|
||||
self._message.hide()
|
||||
|
||||
@ -364,4 +365,8 @@ class GCodeReader(MeshReader):
|
||||
"Make sure the g-code is suitable for your printer and printer configuration before sending the file to it. The g-code representation may not be accurate."), lifetime=0)
|
||||
caution_message.show()
|
||||
|
||||
# The "save/print" button's state is bound to the backend state.
|
||||
backend = Application.getInstance().getBackend()
|
||||
backend.backendStateChange.emit(Backend.BackendState.Disabled)
|
||||
|
||||
return scene_node
|
||||
|
@ -1,6 +1,8 @@
|
||||
# Copyright (c) 2015 Ultimaker B.V.
|
||||
# Cura is released under the terms of the AGPLv3 or higher.
|
||||
|
||||
import sys
|
||||
|
||||
from UM.PluginRegistry import PluginRegistry
|
||||
from UM.View.View import View
|
||||
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
||||
@ -253,8 +255,17 @@ class LayerView(View):
|
||||
if not layer_data:
|
||||
continue
|
||||
|
||||
if new_max_layers < len(layer_data.getLayers()):
|
||||
new_max_layers = len(layer_data.getLayers()) - 1
|
||||
min_layer_number = sys.maxsize
|
||||
max_layer_number = -sys.maxsize
|
||||
for layer_id in layer_data.getLayers():
|
||||
if max_layer_number < layer_id:
|
||||
max_layer_number = layer_id
|
||||
if min_layer_number > layer_id:
|
||||
min_layer_number = layer_id
|
||||
layer_count = max_layer_number - min_layer_number
|
||||
|
||||
if new_max_layers < layer_count:
|
||||
new_max_layers = layer_count
|
||||
|
||||
if new_max_layers > 0 and new_max_layers != self._old_max_layers:
|
||||
self._max_layers = new_max_layers
|
||||
|
@ -351,7 +351,7 @@ Item
|
||||
property bool roundValues: true
|
||||
|
||||
property var activeHandle: upperHandle
|
||||
property bool layersVisible: UM.LayerView.layerActivity && Printer.platformActivity ? true : false
|
||||
property bool layersVisible: UM.LayerView.layerActivity && CuraApplication.platformActivity ? true : false
|
||||
|
||||
function getUpperValueFromHandle()
|
||||
{
|
||||
|
49
plugins/UM3NetworkPrinting/NetworkPrinterOutputDevice.py
Normal file → Executable file
49
plugins/UM3NetworkPrinting/NetworkPrinterOutputDevice.py
Normal file → Executable file
@ -200,7 +200,7 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
|
||||
|
||||
def _onAuthenticationRequired(self, reply, authenticator):
|
||||
if self._authentication_id is not None and self._authentication_key is not None:
|
||||
Logger.log("d", "Authentication was required. Setting up authenticator with ID %s and key", self._authentication_id, self._getSafeAuthKey())
|
||||
Logger.log("d", "Authentication was required. Setting up authenticator with ID %s and key %s", self._authentication_id, self._getSafeAuthKey())
|
||||
authenticator.setUser(self._authentication_id)
|
||||
authenticator.setPassword(self._authentication_key)
|
||||
else:
|
||||
@ -625,7 +625,7 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
|
||||
if print_information.materialLengths:
|
||||
# Check if print cores / materials are loaded at all. Any failure in these results in an Error.
|
||||
for index in range(0, self._num_extruders):
|
||||
if print_information.materialLengths[index] != 0:
|
||||
if index < len(print_information.materialLengths) and print_information.materialLengths[index] != 0:
|
||||
if self._json_printer_state["heads"][0]["extruders"][index]["hotend"]["id"] == "":
|
||||
Logger.log("e", "No cartridge loaded in slot %s, unable to start print", index + 1)
|
||||
self._error_message = Message(
|
||||
@ -643,13 +643,13 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
|
||||
for index in range(0, self._num_extruders):
|
||||
# Check if there is enough material. Any failure in these results in a warning.
|
||||
material_length = self._json_printer_state["heads"][0]["extruders"][index]["active_material"]["length_remaining"]
|
||||
if material_length != -1 and print_information.materialLengths[index] > material_length:
|
||||
if material_length != -1 and index < len(print_information.materialLengths) and print_information.materialLengths[index] > material_length:
|
||||
Logger.log("w", "Printer reports that there is not enough material left for extruder %s. We need %s and the printer has %s", index + 1, print_information.materialLengths[index], material_length)
|
||||
warnings.append(i18n_catalog.i18nc("@label", "Not enough material for spool {0}.").format(index+1))
|
||||
|
||||
# Check if the right cartridges are loaded. Any failure in these results in a warning.
|
||||
extruder_manager = cura.Settings.ExtruderManager.ExtruderManager.getInstance()
|
||||
if print_information.materialLengths[index] != 0:
|
||||
if index < len(print_information.materialLengths) and print_information.materialLengths[index] != 0:
|
||||
variant = extruder_manager.getExtruderStack(index).findContainer({"type": "variant"})
|
||||
core_name = self._json_printer_state["heads"][0]["extruders"][index]["hotend"]["id"]
|
||||
if variant:
|
||||
@ -716,7 +716,8 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
|
||||
|
||||
## Start requesting data from printer
|
||||
def connect(self):
|
||||
self.close() # Ensure that previous connection (if any) is killed.
|
||||
if self.isConnected():
|
||||
self.close() # Close previous connection
|
||||
|
||||
self._createNetworkManager()
|
||||
|
||||
@ -796,19 +797,41 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
|
||||
Logger.log("d", "Started sending g-code to remote printer.")
|
||||
self._compressing_print = True
|
||||
## Mash the data into single string
|
||||
|
||||
max_chars_per_line = 1024 * 1024 / 4 # 1 / 4 MB
|
||||
|
||||
byte_array_file_data = b""
|
||||
batched_line = ""
|
||||
|
||||
def _compress_data_and_notify_qt(data_to_append):
|
||||
compressed_data = gzip.compress(data_to_append.encode("utf-8"))
|
||||
QCoreApplication.processEvents() # Ensure that the GUI does not freeze.
|
||||
# Pretend that this is a response, as zipping might take a bit of time.
|
||||
self._last_response_time = time()
|
||||
return compressed_data
|
||||
|
||||
for line in self._gcode:
|
||||
if not self._compressing_print:
|
||||
self._progress_message.hide()
|
||||
return # Stop trying to zip, abort was called.
|
||||
|
||||
if self._use_gzip:
|
||||
byte_array_file_data += gzip.compress(line.encode("utf-8"))
|
||||
QCoreApplication.processEvents() # Ensure that the GUI does not freeze.
|
||||
# Pretend that this is a response, as zipping might take a bit of time.
|
||||
self._last_response_time = time()
|
||||
batched_line += line
|
||||
# if the gcode was read from a gcode file, self._gcode will be a list of all lines in that file.
|
||||
# Compressing line by line in this case is extremely slow, so we need to batch them.
|
||||
if len(batched_line) < max_chars_per_line:
|
||||
continue
|
||||
|
||||
byte_array_file_data += _compress_data_and_notify_qt(batched_line)
|
||||
batched_line = ""
|
||||
else:
|
||||
byte_array_file_data += line.encode("utf-8")
|
||||
|
||||
# don't miss the last batch if it's there
|
||||
if self._use_gzip:
|
||||
if batched_line:
|
||||
byte_array_file_data += _compress_data_and_notify_qt(batched_line)
|
||||
|
||||
if self._use_gzip:
|
||||
file_name = "%s.gcode.gz" % Application.getInstance().getPrintInformation().jobName
|
||||
else:
|
||||
@ -858,7 +881,10 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
|
||||
url = QUrl("http://" + self._address + self._api_prefix + "auth/request")
|
||||
request = QNetworkRequest(url)
|
||||
request.setHeader(QNetworkRequest.ContentTypeHeader, "application/json")
|
||||
self._authentication_key = None
|
||||
self._authentication_id = None
|
||||
self._manager.post(request, json.dumps({"application": "Cura-" + Application.getInstance().getVersion(), "user": self._getUserName()}).encode())
|
||||
self.setAuthenticationState(AuthState.AuthenticationRequested)
|
||||
|
||||
## Send all material profiles to the printer.
|
||||
def sendMaterialProfiles(self):
|
||||
@ -1054,7 +1080,6 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
|
||||
except json.decoder.JSONDecodeError:
|
||||
Logger.log("w", "Received an invalid authentication request reply from printer: Not valid JSON.")
|
||||
return
|
||||
self.setAuthenticationState(AuthState.AuthenticationRequested)
|
||||
global_container_stack = Application.getInstance().getGlobalContainerStack()
|
||||
if global_container_stack: # Remove any old data.
|
||||
Logger.log("d", "Removing old network authentication data as a new one was requested.")
|
||||
@ -1064,7 +1089,7 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
|
||||
|
||||
self._authentication_key = data["key"]
|
||||
self._authentication_id = data["id"]
|
||||
Logger.log("i", "Got a new authentication ID (%s) and KEY (%S). Waiting for authorization.", self._authentication_id, self._getSafeAuthKey())
|
||||
Logger.log("i", "Got a new authentication ID (%s) and KEY (%s). Waiting for authorization.", self._authentication_id, self._getSafeAuthKey())
|
||||
|
||||
# Check if the authentication is accepted.
|
||||
self._checkAuthentication()
|
||||
@ -1142,4 +1167,4 @@ class NetworkPrinterOutputDevice(PrinterOutputDevice):
|
||||
result = self._authentication_key[-5:]
|
||||
result = "********" + result
|
||||
return result
|
||||
return self._authentication_key
|
||||
return self._authentication_key
|
||||
|
@ -157,13 +157,15 @@ class NetworkPrinterOutputDevicePlugin(OutputDevicePlugin):
|
||||
|
||||
for key in self._printers:
|
||||
if key == active_machine.getMetaDataEntry("um_network_key"):
|
||||
Logger.log("d", "Connecting [%s]..." % key)
|
||||
self._printers[key].connect()
|
||||
self._printers[key].connectionStateChanged.connect(self._onPrinterConnectionStateChanged)
|
||||
if not self._printers[key].isConnected():
|
||||
Logger.log("d", "Connecting [%s]..." % key)
|
||||
self._printers[key].connect()
|
||||
self._printers[key].connectionStateChanged.connect(self._onPrinterConnectionStateChanged)
|
||||
else:
|
||||
if self._printers[key].isConnected():
|
||||
Logger.log("d", "Closing connection [%s]..." % key)
|
||||
self._printers[key].close()
|
||||
self._printers[key].connectionStateChanged.disconnect(self._onPrinterConnectionStateChanged)
|
||||
|
||||
## Because the model needs to be created in the same thread as the QMLEngine, we use a signal.
|
||||
def addPrinter(self, name, address, properties):
|
||||
@ -181,9 +183,9 @@ class NetworkPrinterOutputDevicePlugin(OutputDevicePlugin):
|
||||
printer = self._printers.pop(name, None)
|
||||
if printer:
|
||||
if printer.isConnected():
|
||||
printer.disconnect()
|
||||
printer.connectionStateChanged.disconnect(self._onPrinterConnectionStateChanged)
|
||||
Logger.log("d", "removePrinter, disconnecting [%s]..." % name)
|
||||
printer.disconnect()
|
||||
self.printerListChanged.emit()
|
||||
|
||||
## Handler for when the connection state of one of the detected printers changes
|
||||
|
@ -19,8 +19,8 @@ from PyQt5.QtCore import QUrl, pyqtSlot, pyqtSignal, pyqtProperty
|
||||
from UM.i18n import i18nCatalog
|
||||
catalog = i18nCatalog("cura")
|
||||
|
||||
class USBPrinterOutputDevice(PrinterOutputDevice):
|
||||
|
||||
class USBPrinterOutputDevice(PrinterOutputDevice):
|
||||
def __init__(self, serial_port):
|
||||
super().__init__(serial_port)
|
||||
self.setName(catalog.i18nc("@item:inmenu", "USB printing"))
|
||||
@ -148,6 +148,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
||||
## Start a print based on a g-code.
|
||||
# \param gcode_list List with gcode (strings).
|
||||
def printGCode(self, gcode_list):
|
||||
Logger.log("d", "Started printing g-code")
|
||||
if self._progress or self._connection_state != ConnectionState.connected:
|
||||
self._error_message = Message(catalog.i18nc("@info:status", "Unable to start a new job because the printer is busy or not connected."))
|
||||
self._error_message.show()
|
||||
@ -183,6 +184,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
||||
|
||||
## Private function (threaded) that actually uploads the firmware.
|
||||
def _updateFirmware(self):
|
||||
Logger.log("d", "Attempting to update firmware")
|
||||
self._error_code = 0
|
||||
self.setProgress(0, 100)
|
||||
self._firmware_update_finished = False
|
||||
@ -202,6 +204,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
||||
try:
|
||||
programmer.connect(self._serial_port)
|
||||
except Exception:
|
||||
programmer.close()
|
||||
pass
|
||||
|
||||
# Give programmer some time to connect. Might need more in some cases, but this worked in all tested cases.
|
||||
@ -312,8 +315,10 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
||||
programmer.connect(self._serial_port) # Connect with the serial, if this succeeds, it's an arduino based usb device.
|
||||
self._serial = programmer.leaveISP()
|
||||
except ispBase.IspError as e:
|
||||
programmer.close()
|
||||
Logger.log("i", "Could not establish connection on %s: %s. Device is not arduino based." %(self._serial_port,str(e)))
|
||||
except Exception as e:
|
||||
programmer.close()
|
||||
Logger.log("i", "Could not establish connection on %s, unknown reasons. Device is not arduino based." % self._serial_port)
|
||||
|
||||
# If the programmer connected, we know its an atmega based version.
|
||||
@ -533,6 +538,7 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
||||
self._sendNextGcodeLine()
|
||||
elif b"resend" in line.lower() or b"rs" in line: # Because a resend can be asked with "resend" and "rs"
|
||||
try:
|
||||
Logger.log("d", "Got a resend response")
|
||||
self._gcode_position = int(line.replace(b"N:",b" ").replace(b"N",b" ").replace(b":",b" ").split()[-1])
|
||||
except:
|
||||
if b"rs" in line:
|
||||
@ -559,15 +565,20 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
||||
if ";" in line:
|
||||
line = line[:line.find(";")]
|
||||
line = line.strip()
|
||||
|
||||
# Don't send empty lines. But we do have to send something, so send
|
||||
# m105 instead.
|
||||
# Don't send the M0 or M1 to the machine, as M0 and M1 are handled as
|
||||
# an LCD menu pause.
|
||||
if line == "" or line == "M0" or line == "M1":
|
||||
line = "M105"
|
||||
try:
|
||||
if line == "M0" or line == "M1":
|
||||
line = "M105" # Don't send the M0 or M1 to the machine, as M0 and M1 are handled as an LCD menu pause.
|
||||
if ("G0" in line or "G1" in line) and "Z" in line:
|
||||
z = float(re.search("Z([0-9\.]*)", line).group(1))
|
||||
if self._current_z != z:
|
||||
self._current_z = z
|
||||
except Exception as e:
|
||||
Logger.log("e", "Unexpected error with printer connection: %s" % e)
|
||||
Logger.log("e", "Unexpected error with printer connection, could not parse current Z: %s: %s" % (e, line))
|
||||
self._setErrorState("Unexpected error: %s" %e)
|
||||
checksum = functools.reduce(lambda x,y: x^y, map(ord, "N%d%s" % (self._gcode_position, line)))
|
||||
|
||||
@ -666,4 +677,4 @@ class USBPrinterOutputDevice(PrinterOutputDevice):
|
||||
def cancelPreheatBed(self):
|
||||
Logger.log("i", "Cancelling pre-heating of the bed.")
|
||||
self._setTargetBedTemperature(0)
|
||||
self.preheatBedRemainingTimeChanged.emit()
|
||||
self.preheatBedRemainingTimeChanged.emit()
|
||||
|
@ -236,8 +236,7 @@ class USBPrinterOutputDeviceManager(QObject, OutputDevicePlugin, Extension):
|
||||
self.getOutputDeviceManager().removeOutputDevice(serial_port)
|
||||
self.connectionStateChanged.emit()
|
||||
except KeyError:
|
||||
pass # no output device by this device_id found in connection list.
|
||||
|
||||
Logger.log("w", "Connection state of %s changed, but it was not found in the list")
|
||||
|
||||
@pyqtProperty(QObject , notify = connectionStateChanged)
|
||||
def connectedPrinterList(self):
|
||||
|
@ -118,6 +118,7 @@ class XmlMaterialProfile(InstanceContainer):
|
||||
metadata.pop("variant", "")
|
||||
metadata.pop("type", "")
|
||||
metadata.pop("base_file", "")
|
||||
metadata.pop("approximate_diameter", "")
|
||||
|
||||
## Begin Name Block
|
||||
builder.start("name")
|
||||
@ -437,6 +438,7 @@ class XmlMaterialProfile(InstanceContainer):
|
||||
Logger.log("d", "Unsupported material setting %s", key)
|
||||
self._cached_values = global_setting_values
|
||||
|
||||
meta_data["approximate_diameter"] = round(diameter)
|
||||
meta_data["compatible"] = global_compatibility
|
||||
self.setMetaData(meta_data)
|
||||
self._dirty = False
|
||||
|
@ -635,7 +635,7 @@
|
||||
"description": "Width of a single line. Generally, the width of each line should correspond to the width of the nozzle. However, slightly reducing this value could produce better prints.",
|
||||
"unit": "mm",
|
||||
"minimum_value": "0.001",
|
||||
"minimum_value_warning": "0.5 * machine_nozzle_size",
|
||||
"minimum_value_warning": "0.1 + 0.4 * machine_nozzle_size",
|
||||
"maximum_value_warning": "2 * machine_nozzle_size",
|
||||
"default_value": 0.4,
|
||||
"type": "float",
|
||||
@ -649,7 +649,7 @@
|
||||
"description": "Width of a single wall line.",
|
||||
"unit": "mm",
|
||||
"minimum_value": "0.001",
|
||||
"minimum_value_warning": "0.75 * machine_nozzle_size",
|
||||
"minimum_value_warning": "0.1 + 0.4 * machine_nozzle_size",
|
||||
"maximum_value_warning": "2 * machine_nozzle_size",
|
||||
"value": "line_width",
|
||||
"default_value": 0.4,
|
||||
@ -663,7 +663,7 @@
|
||||
"description": "Width of the outermost wall line. By lowering this value, higher levels of detail can be printed.",
|
||||
"unit": "mm",
|
||||
"minimum_value": "0.001",
|
||||
"minimum_value_warning": "0.75 * machine_nozzle_size if outer_inset_first else 0.1 * machine_nozzle_size",
|
||||
"minimum_value_warning": "(0.1 + 0.4 * machine_nozzle_size) if outer_inset_first else 0.1 * machine_nozzle_size",
|
||||
"maximum_value_warning": "2 * machine_nozzle_size",
|
||||
"default_value": 0.4,
|
||||
"value": "wall_line_width",
|
||||
@ -676,7 +676,7 @@
|
||||
"description": "Width of a single wall line for all wall lines except the outermost one.",
|
||||
"unit": "mm",
|
||||
"minimum_value": "0.001",
|
||||
"minimum_value_warning": "0.5 * machine_nozzle_size",
|
||||
"minimum_value_warning": "0.1 + 0.4 * machine_nozzle_size",
|
||||
"maximum_value_warning": "2 * machine_nozzle_size",
|
||||
"default_value": 0.4,
|
||||
"value": "wall_line_width",
|
||||
@ -691,7 +691,7 @@
|
||||
"description": "Width of a single top/bottom line.",
|
||||
"unit": "mm",
|
||||
"minimum_value": "0.001",
|
||||
"minimum_value_warning": "0.1 * machine_nozzle_size",
|
||||
"minimum_value_warning": "0.1 + 0.4 * machine_nozzle_size",
|
||||
"maximum_value_warning": "2 * machine_nozzle_size",
|
||||
"default_value": 0.4,
|
||||
"type": "float",
|
||||
@ -704,7 +704,7 @@
|
||||
"description": "Width of a single infill line.",
|
||||
"unit": "mm",
|
||||
"minimum_value": "0.001",
|
||||
"minimum_value_warning": "0.75 * machine_nozzle_size",
|
||||
"minimum_value_warning": "0.1 + 0.4 * machine_nozzle_size",
|
||||
"maximum_value_warning": "3 * machine_nozzle_size",
|
||||
"default_value": 0.4,
|
||||
"type": "float",
|
||||
@ -718,7 +718,7 @@
|
||||
"description": "Width of a single skirt or brim line.",
|
||||
"unit": "mm",
|
||||
"minimum_value": "0.001",
|
||||
"minimum_value_warning": "0.75 * machine_nozzle_size",
|
||||
"minimum_value_warning": "0.1 + 0.4 * machine_nozzle_size",
|
||||
"maximum_value_warning": "3 * machine_nozzle_size",
|
||||
"default_value": 0.4,
|
||||
"type": "float",
|
||||
@ -733,7 +733,7 @@
|
||||
"description": "Width of a single support structure line.",
|
||||
"unit": "mm",
|
||||
"minimum_value": "0.001",
|
||||
"minimum_value_warning": "0.75 * machine_nozzle_size",
|
||||
"minimum_value_warning": "0.1 + 0.4 * machine_nozzle_size",
|
||||
"maximum_value_warning": "3 * machine_nozzle_size",
|
||||
"default_value": 0.4,
|
||||
"type": "float",
|
||||
@ -750,7 +750,7 @@
|
||||
"unit": "mm",
|
||||
"default_value": 0.4,
|
||||
"minimum_value": "0.001",
|
||||
"minimum_value_warning": "0.4 * machine_nozzle_size",
|
||||
"minimum_value_warning": "0.1 + 0.4 * machine_nozzle_size",
|
||||
"maximum_value_warning": "2 * machine_nozzle_size",
|
||||
"type": "float",
|
||||
"enabled": "support_enable and support_interface_enable",
|
||||
@ -769,7 +769,7 @@
|
||||
"default_value": 0.4,
|
||||
"value": "line_width",
|
||||
"minimum_value": "0.001",
|
||||
"minimum_value_warning": "0.75 * machine_nozzle_size",
|
||||
"minimum_value_warning": "0.1 + 0.4 * machine_nozzle_size",
|
||||
"maximum_value_warning": "2 * machine_nozzle_size",
|
||||
"settable_per_mesh": false,
|
||||
"settable_per_extruder": true
|
||||
@ -845,7 +845,7 @@
|
||||
"unit": "mm",
|
||||
"default_value": 0.8,
|
||||
"minimum_value": "0",
|
||||
"minimum_value_warning": "3 * resolveOrValue('layer_height')",
|
||||
"minimum_value_warning": "0.2 + resolveOrValue('layer_height')",
|
||||
"maximum_value": "machine_height",
|
||||
"type": "float",
|
||||
"value": "top_bottom_thickness",
|
||||
@ -860,7 +860,7 @@
|
||||
"minimum_value": "0",
|
||||
"maximum_value_warning": "100",
|
||||
"type": "int",
|
||||
"minimum_value_warning": "4",
|
||||
"minimum_value_warning": "2",
|
||||
"value": "0 if infill_sparse_density == 100 else math.ceil(round(top_thickness / resolveOrValue('layer_height'), 4))",
|
||||
"settable_per_mesh": true
|
||||
}
|
||||
@ -873,7 +873,7 @@
|
||||
"unit": "mm",
|
||||
"default_value": 0.6,
|
||||
"minimum_value": "0",
|
||||
"minimum_value_warning": "3 * resolveOrValue('layer_height')",
|
||||
"minimum_value_warning": "0.2 + resolveOrValue('layer_height')",
|
||||
"type": "float",
|
||||
"value": "top_bottom_thickness",
|
||||
"maximum_value": "machine_height",
|
||||
@ -885,7 +885,7 @@
|
||||
"label": "Bottom Layers",
|
||||
"description": "The number of bottom layers. When calculated by the bottom thickness, this value is rounded to a whole number.",
|
||||
"minimum_value": "0",
|
||||
"minimum_value_warning": "4",
|
||||
"minimum_value_warning": "2",
|
||||
"default_value": 6,
|
||||
"type": "int",
|
||||
"value": "999999 if infill_sparse_density == 100 else math.ceil(round(bottom_thickness / resolveOrValue('layer_height'), 4))",
|
||||
@ -1121,6 +1121,65 @@
|
||||
"type": "[int]",
|
||||
"default_value": "[ ]",
|
||||
"enabled": "infill_pattern != 'concentric' and infill_pattern != 'concentric_3d' and infill_pattern != 'cubicsubdiv'",
|
||||
"enabled": "infill_sparse_density > 0",
|
||||
"settable_per_mesh": true
|
||||
},
|
||||
"spaghetti_infill_enabled":
|
||||
{
|
||||
"label": "Spaghetti Infill",
|
||||
"description": "Print the infill every so often, so that the filament will curl up chaotically inside the object. This reduces print time, but the behaviour is rather unpredictable.",
|
||||
"type": "bool",
|
||||
"default_value": false,
|
||||
"enabled": "infill_sparse_density > 0",
|
||||
"settable_per_mesh": true
|
||||
},
|
||||
"spaghetti_max_infill_angle":
|
||||
{
|
||||
"label": "Spaghetti Maximum Infill Angle",
|
||||
"description": "The maximum angle w.r.t. the Z axis of the inside of the print for areas which are to be filled with spaghetti infill afterwards. Lowering this value causes more angled parts in your model to be filled on each layer.",
|
||||
"unit": "°",
|
||||
"type": "float",
|
||||
"default_value": 10,
|
||||
"minimum_value": "0",
|
||||
"maximum_value": "90",
|
||||
"maximum_value_warning": "45",
|
||||
"enabled": "infill_sparse_density > 0 and spaghetti_infill_enabled",
|
||||
"settable_per_mesh": true
|
||||
},
|
||||
"spaghetti_max_height":
|
||||
{
|
||||
"label": "Spaghetti Infill Maximum Height",
|
||||
"description": "The maximum height of inside space which can be combined and filled from the top.",
|
||||
"unit": "mm",
|
||||
"type": "float",
|
||||
"default_value": 2.0,
|
||||
"minimum_value": "layer_height",
|
||||
"maximum_value_warning": "10.0",
|
||||
"enabled": "infill_sparse_density > 0 and spaghetti_infill_enabled",
|
||||
"settable_per_mesh": true
|
||||
},
|
||||
"spaghetti_inset":
|
||||
{
|
||||
"label": "Spaghetti Inset",
|
||||
"description": "The offset from the walls from where the spaghetti infill will be printed.",
|
||||
"unit": "mm",
|
||||
"type": "float",
|
||||
"default_value": 0.2,
|
||||
"minimum_value_warning": "0",
|
||||
"maximum_value_warning": "5.0",
|
||||
"enabled": "infill_sparse_density > 0 and spaghetti_infill_enabled",
|
||||
"settable_per_mesh": true
|
||||
},
|
||||
"spaghetti_flow":
|
||||
{
|
||||
"label": "Spaghetti Flow",
|
||||
"description": "Adjusts the density of the spaghetti infill. Note that the Infill Density only controls the line spacing of the filling pattern, not the amount of extrusion for spaghetti infill.",
|
||||
"unit": "%",
|
||||
"type": "float",
|
||||
"default_value": 20,
|
||||
"minimum_value": "0",
|
||||
"maximum_value_warning": "100",
|
||||
"enabled": "infill_sparse_density > 0 and spaghetti_infill_enabled",
|
||||
"settable_per_mesh": true
|
||||
},
|
||||
"sub_div_rad_mult":
|
||||
@ -1229,9 +1288,9 @@
|
||||
"default_value": 0.1,
|
||||
"minimum_value": "resolveOrValue('layer_height')",
|
||||
"maximum_value_warning": "0.75 * machine_nozzle_size",
|
||||
"maximum_value": "resolveOrValue('layer_height') * 8",
|
||||
"maximum_value": "resolveOrValue('layer_height') * (1.45 if spaghetti_infill_enabled else 8)",
|
||||
"value": "resolveOrValue('layer_height')",
|
||||
"enabled": "infill_sparse_density > 0",
|
||||
"enabled": "infill_sparse_density > 0 and not spaghetti_infill_enabled",
|
||||
"settable_per_mesh": true
|
||||
},
|
||||
"gradual_infill_steps":
|
||||
@ -1242,8 +1301,8 @@
|
||||
"type": "int",
|
||||
"minimum_value": "0",
|
||||
"maximum_value_warning": "4",
|
||||
"maximum_value": "(20 - math.log(infill_line_distance) / math.log(2)) if infill_line_distance > 0 else 0",
|
||||
"enabled": "infill_sparse_density > 0 and infill_pattern != 'cubicsubdiv'",
|
||||
"maximum_value": "(20 - math.log(infill_line_distance) / math.log(2)) if infill_line_distance > 0 and not spaghetti_infill_enabled else 0",
|
||||
"enabled": "infill_sparse_density > 0 and infill_pattern != 'cubicsubdiv' and not spaghetti_infill_enabled",
|
||||
"settable_per_mesh": true
|
||||
},
|
||||
"gradual_infill_step_height":
|
||||
@ -2273,7 +2332,6 @@
|
||||
"unit": "mm/s",
|
||||
"type": "float",
|
||||
"minimum_value": "0.1",
|
||||
"minimum_value_warning": "5",
|
||||
"maximum_value_warning": "50",
|
||||
"default_value": 20,
|
||||
"enabled": "resolveOrValue('jerk_enabled')",
|
||||
@ -2287,7 +2345,6 @@
|
||||
"unit": "mm/s",
|
||||
"type": "float",
|
||||
"minimum_value": "0.1",
|
||||
"minimum_value_warning": "5",
|
||||
"maximum_value_warning": "50",
|
||||
"default_value": 20,
|
||||
"value": "jerk_print",
|
||||
@ -2301,7 +2358,6 @@
|
||||
"unit": "mm/s",
|
||||
"type": "float",
|
||||
"minimum_value": "0.1",
|
||||
"minimum_value_warning": "5",
|
||||
"maximum_value_warning": "50",
|
||||
"default_value": 20,
|
||||
"value": "jerk_print",
|
||||
@ -2316,7 +2372,6 @@
|
||||
"unit": "mm/s",
|
||||
"type": "float",
|
||||
"minimum_value": "0.1",
|
||||
"minimum_value_warning": "5",
|
||||
"maximum_value_warning": "50",
|
||||
"default_value": 20,
|
||||
"value": "jerk_wall",
|
||||
@ -2330,7 +2385,6 @@
|
||||
"unit": "mm/s",
|
||||
"type": "float",
|
||||
"minimum_value": "0.1",
|
||||
"minimum_value_warning": "5",
|
||||
"maximum_value_warning": "50",
|
||||
"default_value": 20,
|
||||
"value": "jerk_wall",
|
||||
@ -2346,7 +2400,6 @@
|
||||
"unit": "mm/s",
|
||||
"type": "float",
|
||||
"minimum_value": "0.1",
|
||||
"minimum_value_warning": "5",
|
||||
"maximum_value_warning": "50",
|
||||
"default_value": 20,
|
||||
"value": "jerk_print",
|
||||
@ -2360,7 +2413,6 @@
|
||||
"unit": "mm/s",
|
||||
"type": "float",
|
||||
"minimum_value": "0.1",
|
||||
"minimum_value_warning": "5",
|
||||
"maximum_value_warning": "50",
|
||||
"default_value": 20,
|
||||
"value": "jerk_print",
|
||||
@ -2379,7 +2431,6 @@
|
||||
"default_value": 20,
|
||||
"value": "jerk_support",
|
||||
"minimum_value": "0.1",
|
||||
"minimum_value_warning": "5",
|
||||
"maximum_value_warning": "50",
|
||||
"enabled": "resolveOrValue('jerk_enabled') and support_enable",
|
||||
"limit_to_extruder": "support_infill_extruder_nr",
|
||||
@ -2395,7 +2446,6 @@
|
||||
"default_value": 20,
|
||||
"value": "jerk_support",
|
||||
"minimum_value": "0.1",
|
||||
"minimum_value_warning": "5",
|
||||
"maximum_value_warning": "50",
|
||||
"enabled": "resolveOrValue('jerk_enabled') and extruderValue(support_interface_extruder_nr, 'support_interface_enable') and support_enable",
|
||||
"limit_to_extruder": "support_interface_extruder_nr",
|
||||
@ -2411,7 +2461,6 @@
|
||||
"unit": "mm/s",
|
||||
"type": "float",
|
||||
"minimum_value": "0.1",
|
||||
"minimum_value_warning": "5",
|
||||
"maximum_value_warning": "50",
|
||||
"default_value": 20,
|
||||
"value": "jerk_print",
|
||||
@ -2428,7 +2477,6 @@
|
||||
"type": "float",
|
||||
"default_value": 30,
|
||||
"minimum_value": "0.1",
|
||||
"minimum_value_warning": "5",
|
||||
"maximum_value_warning": "50",
|
||||
"value": "jerk_print if magic_spiralize else 30",
|
||||
"enabled": "resolveOrValue('jerk_enabled')",
|
||||
@ -2443,7 +2491,6 @@
|
||||
"default_value": 20,
|
||||
"value": "jerk_print",
|
||||
"minimum_value": "0.1",
|
||||
"minimum_value_warning": "5",
|
||||
"maximum_value_warning": "50",
|
||||
"enabled": "resolveOrValue('jerk_enabled')",
|
||||
"settable_per_mesh": true,
|
||||
@ -2458,7 +2505,6 @@
|
||||
"default_value": 20,
|
||||
"value": "jerk_layer_0",
|
||||
"minimum_value": "0.1",
|
||||
"minimum_value_warning": "5",
|
||||
"maximum_value_warning": "50",
|
||||
"enabled": "resolveOrValue('jerk_enabled')",
|
||||
"settable_per_mesh": true
|
||||
@ -2472,7 +2518,6 @@
|
||||
"default_value": 20,
|
||||
"value": "jerk_layer_0 * jerk_travel / jerk_print",
|
||||
"minimum_value": "0.1",
|
||||
"minimum_value_warning": "5",
|
||||
"maximum_value_warning": "50",
|
||||
"enabled": "resolveOrValue('jerk_enabled')",
|
||||
"settable_per_extruder": true,
|
||||
@ -2488,7 +2533,6 @@
|
||||
"type": "float",
|
||||
"default_value": 20,
|
||||
"minimum_value": "0.1",
|
||||
"minimum_value_warning": "5",
|
||||
"maximum_value_warning": "50",
|
||||
"value": "jerk_layer_0",
|
||||
"enabled": "resolveOrValue('jerk_enabled')",
|
||||
@ -2792,8 +2836,8 @@
|
||||
{
|
||||
"support_enable":
|
||||
{
|
||||
"label": "Enable Support",
|
||||
"description": "Enable support structures. These structures support parts of the model with severe overhangs.",
|
||||
"label": "Generate Support",
|
||||
"description": "Generate structures to support parts of the model which have overhangs. Without these structures, such parts would collapse during printing.",
|
||||
"type": "bool",
|
||||
"default_value": false,
|
||||
"settable_per_mesh": true,
|
||||
@ -3080,7 +3124,7 @@
|
||||
"type": "float",
|
||||
"default_value": 1,
|
||||
"minimum_value": "0",
|
||||
"minimum_value_warning": "3 * resolveOrValue('layer_height')",
|
||||
"minimum_value_warning": "0.2 + resolveOrValue('layer_height')",
|
||||
"maximum_value_warning": "10",
|
||||
"limit_to_extruder": "support_interface_extruder_nr",
|
||||
"enabled": "extruderValue(support_interface_extruder_nr, 'support_interface_enable') and support_enable",
|
||||
@ -3095,7 +3139,7 @@
|
||||
"type": "float",
|
||||
"default_value": 1,
|
||||
"minimum_value": "0",
|
||||
"minimum_value_warning": "3 * resolveOrValue('layer_height')",
|
||||
"minimum_value_warning": "0.2 + resolveOrValue('layer_height')",
|
||||
"maximum_value_warning": "10",
|
||||
"value": "extruderValue(support_interface_extruder_nr, 'support_interface_height')",
|
||||
"limit_to_extruder": "support_interface_extruder_nr",
|
||||
@ -3111,7 +3155,7 @@
|
||||
"default_value": 1,
|
||||
"value": "extruderValue(support_interface_extruder_nr, 'support_interface_height')",
|
||||
"minimum_value": "0",
|
||||
"minimum_value_warning": "min(3 * resolveOrValue('layer_height'), extruderValue(support_interface_extruder_nr, 'support_bottom_stair_step_height'))",
|
||||
"minimum_value_warning": "min(0.2 + resolveOrValue('layer_height'), extruderValue(support_interface_extruder_nr, 'support_bottom_stair_step_height'))",
|
||||
"maximum_value_warning": "10",
|
||||
"limit_to_extruder": "support_interface_extruder_nr",
|
||||
"enabled": "extruderValue(support_interface_extruder_nr, 'support_interface_enable') and support_enable",
|
||||
@ -3496,7 +3540,7 @@
|
||||
"value": "resolveOrValue('layer_height') * 1.5",
|
||||
"minimum_value": "0.001",
|
||||
"minimum_value_warning": "0.04",
|
||||
"maximum_value_warning": "0.75 * extruderValue(adhesion_extruder_nr, 'raft_interface_line_width')",
|
||||
"maximum_value_warning": "0.75 * extruderValue(adhesion_extruder_nr, 'machine_nozzle_size')",
|
||||
"enabled": "resolveOrValue('adhesion_type') == 'raft'",
|
||||
"settable_per_mesh": false,
|
||||
"settable_per_extruder": true,
|
||||
@ -3898,7 +3942,7 @@
|
||||
"value": "round(max(2 * min(extruderValues('prime_tower_line_width')), 0.5 * (resolveOrValue('prime_tower_size') - math.sqrt(max(0, resolveOrValue('prime_tower_size') ** 2 - max(extruderValues('prime_tower_min_volume')) / resolveOrValue('layer_height'))))), 3)",
|
||||
"resolve": "max(extruderValues('prime_tower_wall_thickness'))",
|
||||
"minimum_value": "0.001",
|
||||
"minimum_value_warning": "2 * min(extruderValues('prime_tower_line_width'))",
|
||||
"minimum_value_warning": "2 * min(extruderValues('prime_tower_line_width')) - 0.0001",
|
||||
"maximum_value_warning": "resolveOrValue('prime_tower_size') / 2",
|
||||
"enabled": "resolveOrValue('prime_tower_enable')",
|
||||
"settable_per_mesh": false,
|
||||
@ -4122,6 +4166,40 @@
|
||||
"settable_per_meshgroup": false,
|
||||
"settable_globally": false
|
||||
},
|
||||
"mold_enabled":
|
||||
{
|
||||
"label": "Mold",
|
||||
"description": "Print models as a mold, which can be cast in order to get a model which resembles the models on the build plate.",
|
||||
"type": "bool",
|
||||
"default_value": false,
|
||||
"settable_per_mesh": true
|
||||
},
|
||||
"mold_width":
|
||||
{
|
||||
"label": "Minimal Mold Width",
|
||||
"description": "The minimal distance between the ouside of the mold and the outside of the model.",
|
||||
"unit": "mm",
|
||||
"type": "float",
|
||||
"minimum_value_warning": "wall_line_width_0 * 2",
|
||||
"maximum_value_warning": "100",
|
||||
"default_value": 5,
|
||||
"settable_per_mesh": true,
|
||||
"enabled": "mold_enabled"
|
||||
},
|
||||
"mold_angle":
|
||||
{
|
||||
"label": "Mold Angle",
|
||||
"description": "The angle of overhang of the outer walls created for the mold. 0° will make the outer shell of the mold vertical, while 90° will make the outside of the model follow the contour of the model.",
|
||||
"unit": "°",
|
||||
"type": "float",
|
||||
"minimum_value": "-89",
|
||||
"minimum_value_warning": "0",
|
||||
"maximum_value_warning": "support_angle",
|
||||
"maximum_value": "90",
|
||||
"default_value": 40,
|
||||
"settable_per_mesh": true,
|
||||
"enabled": "mold_enabled"
|
||||
},
|
||||
"infill_mesh_order":
|
||||
{
|
||||
"label": "Infill Mesh Order",
|
||||
@ -4147,6 +4225,18 @@
|
||||
"settable_per_meshgroup": false,
|
||||
"settable_globally": false
|
||||
},
|
||||
"support_mesh_drop_down":
|
||||
{
|
||||
"label": "Drop Down Support Mesh",
|
||||
"description": "Make support everywhere below the support mesh, so that there's no overhang in the support mesh.",
|
||||
"type": "bool",
|
||||
"default_value": true,
|
||||
"enabled": "support_mesh",
|
||||
"settable_per_mesh": true,
|
||||
"settable_per_extruder": false,
|
||||
"settable_per_meshgroup": false,
|
||||
"settable_globally": false
|
||||
},
|
||||
"anti_overhang_mesh":
|
||||
{
|
||||
"label": "Anti Overhang Mesh",
|
||||
@ -4178,7 +4268,8 @@
|
||||
"description": "Spiralize smooths out the Z move of the outer edge. This will create a steady Z increase over the whole print. This feature turns a solid model into a single walled print with a solid bottom. This feature used to be called Joris in older versions.",
|
||||
"type": "bool",
|
||||
"default_value": false,
|
||||
"settable_per_mesh": true
|
||||
"settable_per_mesh": false,
|
||||
"settable_per_extruder": false
|
||||
}
|
||||
}
|
||||
},
|
||||
|
41
resources/definitions/imade3d_jellybox.def.json
Normal file
41
resources/definitions/imade3d_jellybox.def.json
Normal file
@ -0,0 +1,41 @@
|
||||
{
|
||||
"id": "imade3d_jellybox",
|
||||
"version": 2,
|
||||
"name": "IMADE3D JellyBOX",
|
||||
"inherits": "fdmprinter",
|
||||
"metadata": {
|
||||
"visible": true,
|
||||
"author": "IMADE3D",
|
||||
"manufacturer": "IMADE3D",
|
||||
"category": "Other",
|
||||
"platform": "imade3d_jellybox_platform.stl",
|
||||
"platform_offset": [ 0, -0.3, 0],
|
||||
"file_formats": "text/x-gcode",
|
||||
"preferred_variant": "*0.4*",
|
||||
"preferred_material": "*generic_pla*",
|
||||
"preferred_quality": "*fast*",
|
||||
"has_materials": true,
|
||||
"has_variants": true,
|
||||
"has_machine_materials": true,
|
||||
"has_machine_quality": true
|
||||
},
|
||||
|
||||
"overrides": {
|
||||
"machine_head_with_fans_polygon": { "default_value": [[ 0, 0 ],[ 0, 0 ],[ 0, 0 ],[ 0, 0 ]]},
|
||||
"machine_name": { "default_value": "IMADE3D JellyBOX" },
|
||||
"machine_width": { "default_value": 170 },
|
||||
"machine_height": { "default_value": 145 },
|
||||
"machine_depth": { "default_value": 160 },
|
||||
"machine_nozzle_size": { "default_value": 0.4 },
|
||||
"material_diameter": { "default_value": 1.75 },
|
||||
"machine_heated_bed": { "default_value": true },
|
||||
"machine_center_is_zero": { "default_value": false },
|
||||
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
|
||||
"machine_start_gcode": {
|
||||
"default_value": ";---------------------------------------\n; ; ; Jellybox Start Script Begin ; ; ;\n;_______________________________________\n; M92 E140 ;optionally adjust steps per mm for your filament\n\n; Print Settings Summary\n; (leave these alone: this is only a list of the slicing settings)\n; (overwriting these values will NOT change your printer's behavior)\n; sliced for : {machine_name}\n; nozzle diameter : {machine_nozzle_size}\n; filament diameter : {material_diameter}\n; layer height : {layer_height}\n; 1st layer height : {layer_height_0}\n; line width : {line_width}\n; outer wall wipe dist. : {wall_0_wipe_dist}\n; infill line width : {infill_line_width}\n; wall thickness : {wall_thickness}\n; top thickness : {top_thickness}\n; bottom thickness : {bottom_thickness}\n; infill density : {infill_sparse_density}\n; infill pattern : {infill_pattern}\n; print temperature : {material_print_temperature}\n; 1st layer print temp. : {material_print_temperature_layer_0}\n; heated bed temperature : {material_bed_temperature}\n; 1st layer bed temp. : {material_bed_temperature_layer_0}\n; regular fan speed : {cool_fan_speed_min}\n; max fan speed : {cool_fan_speed_max}\n; retraction amount : {retraction_amount}\n; retr. retract speed : {retraction_retract_speed}\n; retr. prime speed : {retraction_prime_speed}\n; build plate adhesion : {adhesion_type}\n; support ? {support_enable}\n; spiralized ? {magic_spiralize}\n\nM117 Preparing ;write Preparing\nM140 S{material_bed_temperature_layer_0} ;set bed temperature and move on\nM104 S{material_print_temperature_layer_0} ;set extruder temperature and move on\nM206 X10.0 Y0.0 ;set x homing offset for default bed leveling\nG21 ;metric values\nG90 ;absolute positioning\nM107 ;start with the fan off\nM82 ;set extruder to absolute mode\nG28 ;home all axes\nM203 Z4 ;slow Z speed down for greater accuracy when probing\nG29 ;auto bed leveling procedure\nM203 Z7 ;pick up z speed again for printing\nM190 S{material_bed_temperature_layer_0} ;wait for the bed to reach desired temperature\nM109 S{material_print_temperature_layer_0} ;wait for the extruder to reach desired temperature\nG92 E0 ;reset the extruder position\nG1 F1500 E15 ;extrude 15mm of feed stock\nG92 E0 ;reset the extruder position again\nM117 Print starting ;write Print starting\n;---------------------------------------------\n; ; ; Jellybox Printer Start Script End ; ; ;\n;_____________________________________________\n"
|
||||
},
|
||||
"machine_end_gcode": {
|
||||
"default_value": "\n;---------------------------------\n;;; Jellybox End Script Begin ;;;\n;_________________________________\nM117 Finishing Up ;write Finishing Up\n\nM104 S0 ;extruder heater off\nM140 S0 ;bed heater off (if you have it)\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+0.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\nG90 ;absolute positioning\nG28 X ;home x, so the head is out of the way\nG1 Y100 ;move Y forward, so the print is more accessible\nM84 ;steppers off\n\nM117 Print finished ;write Print finished\n;---------------------------------------\n;;; Jellybox End Script End ;;;\n;_______________________________________"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
{
|
||||
"id": "jellybox",
|
||||
"version": 2,
|
||||
"name": "JellyBOX",
|
||||
"inherits": "fdmprinter",
|
||||
"metadata": {
|
||||
"visible": true,
|
||||
"author": "IMADE3D",
|
||||
"manufacturer": "IMADE3D",
|
||||
"category": "Other",
|
||||
"platform": "jellybox_platform.stl",
|
||||
"platform_offset": [ 0, -0.3, 0],
|
||||
"file_formats": "text/x-gcode",
|
||||
"has_materials": true,
|
||||
"has_machine_materials": true
|
||||
},
|
||||
|
||||
"overrides": {
|
||||
"machine_name": { "default_value": "IMADE3D JellyBOX" },
|
||||
"machine_width": { "default_value": 170 },
|
||||
"machine_height": { "default_value": 145 },
|
||||
"machine_depth": { "default_value": 160 },
|
||||
"machine_nozzle_size": { "default_value": 0.4 },
|
||||
"material_diameter": { "default_value": 1.75 },
|
||||
"machine_heated_bed": { "default_value": true },
|
||||
"machine_center_is_zero": { "default_value": false },
|
||||
"machine_gcode_flavor": { "default_value": "RepRap (Marlin/Sprinter)" },
|
||||
"machine_start_gcode": {
|
||||
"default_value": ";---------------------------------------\n; ; ; Jellybox Start Script Begin ; ; ;\n;_______________________________________\n; M92 E140 ;optionally adjust steps per mm for your filament\n\n; Print Settings Summary\n; (overwriting these values will NOT change your printer's behavior)\n; sliced for: {machine_name}\n; nozzle diameter: {machine_nozzle_size}\n; filament diameter: {material_diameter}\n; layer height: {layer_height}\n; 1st layer height: {layer_height_0}\n; line width: {line_width}\n; wall thickness: {wall_thickness}\n; infill density: {infill_sparse_density}\n; infill pattern: {infill_pattern}\n; print temperature: {material_print_temperature}\n; heated bed temperature: {material_bed_temperature}\n; regular fan speed: {cool_fan_speed_min}\n; max fan speed: {cool_fan_speed_max}\n; support? {support_enable}\n; spiralized? {magic_spiralize}\n\nM117 Preparing ;write Preparing\nM140 S{material_bed_temperature} ;set bed temperature and move on\nM104 S{material_print_temperature} ;set extruder temperature and move on\nM206 X10.0 Y0.0 ;set x homing offset for default bed leveling\nG21 ;metric values\nG90 ;absolute positioning\nM107 ;start with the fan off\nM82 ;set extruder to absolute mode\nG28 ;home all axes\nM203 Z5 ;slow Z speed down for greater accuracy when probing\nG29 ;auto bed leveling procedure\nM203 Z7 ;pick up z speed again for printing\nM190 S{material_bed_temperature} ;wait for the bed to reach desired temperature\nM109 S{material_print_temperature} ;wait for the extruder to reach desired temperature\nG92 E0 ;reset the extruder position\nG1 F200 E5 ;extrude 5mm of feed stock\nG92 E0 ;reset the extruder position again\nM117 Print starting ;write Print starting\n;---------------------------------------------\n; ; ; Jellybox Printer Start Script End ; ; ;\n;_____________________________________________"
|
||||
},
|
||||
"machine_end_gcode": {
|
||||
"default_value": "\n;---------------------------------\n;;; Jellybox End Script Begin ;;;\n;_________________________________\nM117 Finishing Up ;write Finishing Up\n\nM104 S0 ;extruder heater off\nM140 S0 ;bed heater off (if you have it)\nG91 ;relative positioning\nG1 E-1 F300 ;retract the filament a bit before lifting the nozzle, to release some of the pressure\nG1 Z+0.5 E-5 X-20 Y-20 F9000 ;move Z up a bit and retract filament even more\nG90 ;absolute positioning\nG28 X ;home x, so the head is out of the way\nG1 Y100 ;move Y forward, so the print is more accessible\nM84 ;steppers off\n\nM117 Print finished ;write Print finished\n;---------------------------------------\n;;; Jellybox End Script End ;;;\n;_______________________________________"
|
||||
}
|
||||
}
|
||||
}
|
70
resources/definitions/makeR_pegasus.def.json
Normal file
70
resources/definitions/makeR_pegasus.def.json
Normal file
@ -0,0 +1,70 @@
|
||||
{
|
||||
"id": "makeR_pegasus",
|
||||
"version": 2,
|
||||
"name": "makeR Pegasus",
|
||||
"inherits": "fdmprinter",
|
||||
"metadata": {
|
||||
"visible": true,
|
||||
"author": "makeR",
|
||||
"manufacturer": "makeR",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"icon": "icon_ultimaker2",
|
||||
"platform": "makeR_pegasus_platform.stl",
|
||||
"platform_offset": [-200,-10,200]
|
||||
},
|
||||
|
||||
"overrides": {
|
||||
"machine_name": { "default_value": " makeR Pegasus" },
|
||||
"machine_heated_bed": {
|
||||
"default_value": true
|
||||
},
|
||||
"machine_width": {
|
||||
"default_value": 400
|
||||
},
|
||||
"machine_height": {
|
||||
"default_value": 400
|
||||
},
|
||||
"machine_depth": {
|
||||
"default_value": 400
|
||||
},
|
||||
"machine_center_is_zero": {
|
||||
"default_value": false
|
||||
},
|
||||
"machine_nozzle_size": {
|
||||
"default_value": 0.4
|
||||
},
|
||||
"material_diameter": {
|
||||
"default_value": 2.85
|
||||
},
|
||||
"machine_nozzle_heat_up_speed": {
|
||||
"default_value": 2
|
||||
},
|
||||
"machine_nozzle_cool_down_speed": {
|
||||
"default_value": 2
|
||||
},
|
||||
"machine_head_polygon": {
|
||||
"default_value": [
|
||||
[-75, -18],
|
||||
[-75, 35],
|
||||
[18, 35],
|
||||
[18, -18]
|
||||
]
|
||||
},
|
||||
"gantry_height": {
|
||||
"default_value": -25
|
||||
},
|
||||
"machine_platform_offset":{
|
||||
"default_value":-25
|
||||
},
|
||||
"machine_gcode_flavor": {
|
||||
"default_value": "RepRap (Marlin/Sprinter)"
|
||||
},
|
||||
"machine_start_gcode": {
|
||||
"default_value": "G1 Z15;\nG28;Home\nG29;Auto Level\nG1 Z5 F5000;Move the platform down 15mm"
|
||||
},
|
||||
"machine_end_gcode": {
|
||||
"default_value": "M104 S0;Turn off temperature\nG28 X0; Home X\nM84; Disable Motors"
|
||||
}
|
||||
}
|
||||
}
|
67
resources/definitions/makeR_prusa_tairona_i3.def.json
Normal file
67
resources/definitions/makeR_prusa_tairona_i3.def.json
Normal file
@ -0,0 +1,67 @@
|
||||
{
|
||||
"id": "makeR_prusa_tairona_i3",
|
||||
"version": 2,
|
||||
"name": "makeR Prusa Tairona i3",
|
||||
"inherits": "fdmprinter",
|
||||
"metadata": {
|
||||
"visible": true,
|
||||
"author": "makeR",
|
||||
"manufacturer": "makeR",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"icon": "icon_ultimaker2",
|
||||
"platform": "makeR_prusa_tairona_i3_platform.stl",
|
||||
"platform_offset": [-2,0,0]
|
||||
},
|
||||
|
||||
"overrides": {
|
||||
"machine_name": { "default_value": "makeR Prusa Tairona I3" },
|
||||
"machine_heated_bed": {
|
||||
"default_value": true
|
||||
},
|
||||
"machine_width": {
|
||||
"default_value": 200
|
||||
},
|
||||
"machine_height": {
|
||||
"default_value": 200
|
||||
},
|
||||
"machine_depth": {
|
||||
"default_value": 200
|
||||
},
|
||||
"machine_center_is_zero": {
|
||||
"default_value": false
|
||||
},
|
||||
"machine_nozzle_size": {
|
||||
"default_value": 0.4
|
||||
},
|
||||
"material_diameter": {
|
||||
"default_value": 1.75
|
||||
},
|
||||
"machine_nozzle_heat_up_speed": {
|
||||
"default_value": 2
|
||||
},
|
||||
"machine_nozzle_cool_down_speed": {
|
||||
"default_value": 2
|
||||
},
|
||||
"machine_head_polygon": {
|
||||
"default_value": [
|
||||
[-75, -18],
|
||||
[-75, 35],
|
||||
[18, 35],
|
||||
[18, -18]
|
||||
]
|
||||
},
|
||||
"gantry_height": {
|
||||
"default_value": 55
|
||||
},
|
||||
"machine_gcode_flavor": {
|
||||
"default_value": "RepRap (Marlin/Sprinter)"
|
||||
},
|
||||
"machine_start_gcode": {
|
||||
"default_value": "G1 Z15;\nG28;Home\nG29;Auto Level\nG1 Z5 F5000;Move the platform down 15mm"
|
||||
},
|
||||
"machine_end_gcode": {
|
||||
"default_value": "M104 S0;Turn off temperature\nG28 X0; Home X\nM84; Disable Motors"
|
||||
}
|
||||
}
|
||||
}
|
162
resources/definitions/peopoly_moai.def.json
Normal file
162
resources/definitions/peopoly_moai.def.json
Normal file
@ -0,0 +1,162 @@
|
||||
{
|
||||
"id": "peopoly_moai",
|
||||
"version": 2,
|
||||
"name": "Peopoly Moai",
|
||||
"inherits": "fdmprinter",
|
||||
"metadata": {
|
||||
"visible": true,
|
||||
"author": "fieldOfView",
|
||||
"manufacturer": "Peopoly",
|
||||
"category": "Other",
|
||||
"file_formats": "text/x-gcode",
|
||||
"has_machine_quality": true,
|
||||
"has_materials": false
|
||||
},
|
||||
|
||||
"overrides": {
|
||||
"machine_name": {
|
||||
"default_value": "Moai"
|
||||
},
|
||||
"machine_width": {
|
||||
"default_value": 130
|
||||
},
|
||||
"machine_height": {
|
||||
"default_value": 180
|
||||
},
|
||||
"machine_depth": {
|
||||
"default_value": 130
|
||||
},
|
||||
"machine_nozzle_size": {
|
||||
"default_value": 0.067
|
||||
},
|
||||
"machine_head_with_fans_polygon":
|
||||
{
|
||||
"default_value": [
|
||||
[ -20, 10 ],
|
||||
[ -20, -10 ],
|
||||
[ 10, 10 ],
|
||||
[ 10, -10 ]
|
||||
]
|
||||
},
|
||||
"machine_gcode_flavor": {
|
||||
"default_value": "RepRap (Marlin/Sprinter)"
|
||||
},
|
||||
"machine_start_gcode": {
|
||||
"default_value": "G28 ;Home"
|
||||
},
|
||||
"machine_end_gcode": {
|
||||
"default_value": "M104 S0\nM140 S0\nG28 X0 Y0\nM84"
|
||||
},
|
||||
|
||||
"line_width": {
|
||||
"minimum_value_warning": "machine_nozzle_size"
|
||||
},
|
||||
"wall_line_width": {
|
||||
"minimum_value_warning": "machine_nozzle_size"
|
||||
},
|
||||
"wall_line_width_x": {
|
||||
"minimum_value_warning": "machine_nozzle_size"
|
||||
},
|
||||
"skin_line_width": {
|
||||
"minimum_value_warning": "machine_nozzle_size"
|
||||
},
|
||||
"infill_line_width": {
|
||||
"minimum_value_warning": "machine_nozzle_size"
|
||||
},
|
||||
"skirt_brim_line_width": {
|
||||
"minimum_value_warning": "machine_nozzle_size"
|
||||
},
|
||||
"layer_height": {
|
||||
"maximum_value_warning": "0.5",
|
||||
"minimum_value_warning": "0.02"
|
||||
},
|
||||
"layer_height_0": {
|
||||
"maximum_value_warning": "0.5",
|
||||
"minimum_value_warning": "0.02",
|
||||
"value": "0.1"
|
||||
},
|
||||
"top_bottom_thickness": {
|
||||
"minimum_value_warning": "0.1"
|
||||
},
|
||||
"infill_sparse_thickness": {
|
||||
"maximum_value_warning": "0.5"
|
||||
},
|
||||
"speed_print": {
|
||||
"maximum_value_warning": "300"
|
||||
},
|
||||
"speed_infill": {
|
||||
"maximum_value_warning": "300"
|
||||
},
|
||||
"speed_wall": {
|
||||
"maximum_value_warning": "300",
|
||||
"value": "speed_print"
|
||||
},
|
||||
"speed_wall_0": {
|
||||
"maximum_value_warning": "300"
|
||||
},
|
||||
"speed_wall_x": {
|
||||
"maximum_value_warning": "300",
|
||||
"value": "speed_print"
|
||||
},
|
||||
"speed_topbottom": {
|
||||
"maximum_value_warning": "300",
|
||||
"value": "speed_print"
|
||||
},
|
||||
"speed_travel": {
|
||||
"value": "300"
|
||||
},
|
||||
"speed_travel_layer_0": {
|
||||
"value": "300"
|
||||
},
|
||||
"speed_layer_0": {
|
||||
"value": "5"
|
||||
},
|
||||
"speed_slowdown_layers": {
|
||||
"value": "2"
|
||||
},
|
||||
|
||||
"acceleration_enabled": {
|
||||
"value": "False"
|
||||
},
|
||||
"print_sequence": {
|
||||
"enabled": false
|
||||
},
|
||||
"support_enable": {
|
||||
"enabled": false
|
||||
},
|
||||
"machine_nozzle_temp_enabled": {
|
||||
"value": "False"
|
||||
},
|
||||
"material_bed_temperature": {
|
||||
"enabled": false
|
||||
},
|
||||
"material_diameter": {
|
||||
"enabled": false,
|
||||
"value": "1.75"
|
||||
},
|
||||
"cool_fan_enabled": {
|
||||
"enabled": false,
|
||||
"value": "False"
|
||||
},
|
||||
"retraction_enable": {
|
||||
"enabled": false,
|
||||
"value": "False"
|
||||
},
|
||||
"retraction_combing": {
|
||||
"enabled": false,
|
||||
"value": "'off'"
|
||||
},
|
||||
"retract_at_layer_change": {
|
||||
"enabled": false
|
||||
},
|
||||
"cool_min_layer_time_fan_speed_max": {
|
||||
"enabled": false
|
||||
},
|
||||
"cool_fan_full_at_height": {
|
||||
"enabled": false
|
||||
},
|
||||
"cool_fan_full_layer": {
|
||||
"enabled": false
|
||||
}
|
||||
}
|
||||
}
|
@ -76,7 +76,7 @@
|
||||
"value": "100"
|
||||
},
|
||||
"material_bed_temperature": {
|
||||
"visible": "False"
|
||||
"enabled": false
|
||||
},
|
||||
"material_diameter": {
|
||||
"value": "1.75"
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,13 +1,18 @@
|
||||
# Cura JSON setting files
|
||||
# Copyright (C) 2017 Ultimaker
|
||||
# This file is distributed under the same license as the Cura package.
|
||||
# Ruben Dulek <r.dulek@ultimaker.com>, 2017.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Uranium json setting files\n"
|
||||
"Report-Msgid-Bugs-To: http://github.com/ultimaker/uranium\n"
|
||||
"POT-Creation-Date: 2016-12-28 10:51+0000\n"
|
||||
"PO-Revision-Date: 2017-01-12 15:51+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE\n"
|
||||
"Language: \n"
|
||||
"Project-Id-Version: Cura 2.5\n"
|
||||
"Report-Msgid-Bugs-To: http://github.com/Ultimaker/Cura\n"
|
||||
"POT-Creation-Date: 2017-03-27 17:27+0000\n"
|
||||
"PO-Revision-Date: 2017-04-04 11:27+0200\n"
|
||||
"Last-Translator: Bothof <info@bothof.nl>\n"
|
||||
"Language-Team: Bothof <info@bothof.nl>\n"
|
||||
"Language: de\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,13 +1,18 @@
|
||||
# Cura JSON setting files
|
||||
# Copyright (C) 2017 Ultimaker
|
||||
# This file is distributed under the same license as the Cura package.
|
||||
# Ruben Dulek <r.dulek@ultimaker.com>, 2017.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Uranium json setting files\n"
|
||||
"Report-Msgid-Bugs-To: http://github.com/ultimaker/uranium\n"
|
||||
"POT-Creation-Date: 2016-12-28 10:51+0000\n"
|
||||
"PO-Revision-Date: 2017-01-12 15:51+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE\n"
|
||||
"Language: \n"
|
||||
"Project-Id-Version: Cura 2.5\n"
|
||||
"Report-Msgid-Bugs-To: http://github.com/Ultimaker/Cura\n"
|
||||
"POT-Creation-Date: 2017-03-27 17:27+0000\n"
|
||||
"PO-Revision-Date: 2017-04-04 11:27+0200\n"
|
||||
"Last-Translator: Bothof <info@bothof.nl>\n"
|
||||
"Language-Team: Bothof <info@bothof.nl>\n"
|
||||
"Language: es\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -3,7 +3,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Uranium json setting files\n"
|
||||
"Report-Msgid-Bugs-To: http://github.com/ultimaker/uranium\n"
|
||||
"POT-Creation-Date: 2016-12-28 10:51+0000\n"
|
||||
"POT-Creation-Date: 2017-03-27 17:27+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE\n"
|
||||
|
@ -3,7 +3,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Uranium json setting files\n"
|
||||
"Report-Msgid-Bugs-To: http://github.com/ultimaker/uranium\n"
|
||||
"POT-Creation-Date: 2016-12-28 10:51+0000\n"
|
||||
"POT-Creation-Date: 2017-03-27 17:27+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE\n"
|
||||
@ -268,6 +268,18 @@ msgid ""
|
||||
"extruder is no longer used."
|
||||
msgstr ""
|
||||
|
||||
#: fdmprinter.def.json
|
||||
msgctxt "machine_nozzle_temp_enabled label"
|
||||
msgid "Enable Nozzle Temperature Control"
|
||||
msgstr ""
|
||||
|
||||
#: fdmprinter.def.json
|
||||
msgctxt "machine_nozzle_temp_enabled description"
|
||||
msgid ""
|
||||
"Whether to control temperature from Cura. Turn this off to control nozzle "
|
||||
"temperature from outside of Cura."
|
||||
msgstr ""
|
||||
|
||||
#: fdmprinter.def.json
|
||||
msgctxt "machine_nozzle_heat_up_speed label"
|
||||
msgid "Heat up speed"
|
||||
@ -856,6 +868,47 @@ msgctxt "top_bottom_pattern option zigzag"
|
||||
msgid "Zig Zag"
|
||||
msgstr ""
|
||||
|
||||
#: fdmprinter.def.json
|
||||
msgctxt "top_bottom_pattern_0 label"
|
||||
msgid "Bottom Pattern Initial Layer"
|
||||
msgstr ""
|
||||
|
||||
#: fdmprinter.def.json
|
||||
msgctxt "top_bottom_pattern_0 description"
|
||||
msgid "The pattern on the bottom of the print on the first layer."
|
||||
msgstr ""
|
||||
|
||||
#: fdmprinter.def.json
|
||||
msgctxt "top_bottom_pattern_0 option lines"
|
||||
msgid "Lines"
|
||||
msgstr ""
|
||||
|
||||
#: fdmprinter.def.json
|
||||
msgctxt "top_bottom_pattern_0 option concentric"
|
||||
msgid "Concentric"
|
||||
msgstr ""
|
||||
|
||||
#: fdmprinter.def.json
|
||||
msgctxt "top_bottom_pattern_0 option zigzag"
|
||||
msgid "Zig Zag"
|
||||
msgstr ""
|
||||
|
||||
#: fdmprinter.def.json
|
||||
msgctxt "skin_angles label"
|
||||
msgid "Top/Bottom Line Directions"
|
||||
msgstr ""
|
||||
|
||||
#: fdmprinter.def.json
|
||||
msgctxt "skin_angles description"
|
||||
msgid ""
|
||||
"A list of integer line directions to use when the top/bottom layers use the "
|
||||
"lines or zig zag pattern. Elements from the list are used sequentially as "
|
||||
"the layers progress and when the end of the list is reached, it starts at "
|
||||
"the beginning again. The list items are separated by commas and the whole "
|
||||
"list is contained in square brackets. Default is an empty list which means "
|
||||
"use the traditional default angles (45 and 135 degrees)."
|
||||
msgstr ""
|
||||
|
||||
#: fdmprinter.def.json
|
||||
msgctxt "wall_0_inset label"
|
||||
msgid "Outer Wall Inset"
|
||||
@ -1124,6 +1177,22 @@ msgctxt "infill_pattern option zigzag"
|
||||
msgid "Zig Zag"
|
||||
msgstr ""
|
||||
|
||||
#: fdmprinter.def.json
|
||||
msgctxt "infill_angles label"
|
||||
msgid "Infill Line Directions"
|
||||
msgstr ""
|
||||
|
||||
#: fdmprinter.def.json
|
||||
msgctxt "infill_angles description"
|
||||
msgid ""
|
||||
"A list of integer line directions to use. Elements from the list are used "
|
||||
"sequentially as the layers progress and when the end of the list is reached, "
|
||||
"it starts at the beginning again. The list items are separated by commas and "
|
||||
"the whole list is contained in square brackets. Default is an empty list "
|
||||
"which means use the traditional default angles (45 and 135 degrees for the "
|
||||
"lines and zig zag patterns and 45 degrees for all other patterns)."
|
||||
msgstr ""
|
||||
|
||||
#: fdmprinter.def.json
|
||||
msgctxt "sub_div_rad_mult label"
|
||||
msgid "Cubic Subdivision Radius"
|
||||
@ -1262,6 +1331,97 @@ msgid ""
|
||||
"through the surface."
|
||||
msgstr ""
|
||||
|
||||
#: fdmprinter.def.json
|
||||
msgctxt "min_infill_area label"
|
||||
msgid "Minimum Infill Area"
|
||||
msgstr ""
|
||||
|
||||
#: fdmprinter.def.json
|
||||
msgctxt "min_infill_area description"
|
||||
msgid "Don't generate areas of infill smaller than this (use skin instead)."
|
||||
msgstr ""
|
||||
|
||||
#: fdmprinter.def.json
|
||||
msgctxt "expand_skins_into_infill label"
|
||||
msgid "Expand Skins Into Infill"
|
||||
msgstr ""
|
||||
|
||||
#: fdmprinter.def.json
|
||||
msgctxt "expand_skins_into_infill description"
|
||||
msgid ""
|
||||
"Expand skin areas of top and/or bottom skin of flat surfaces. By default, "
|
||||
"skins stop under the wall lines that surround infill but this can lead to "
|
||||
"holes appearing when the infill density is low. This setting extends the "
|
||||
"skins beyond the wall lines so that the infill on the next layer rests on "
|
||||
"skin."
|
||||
msgstr ""
|
||||
|
||||
#: fdmprinter.def.json
|
||||
msgctxt "expand_upper_skins label"
|
||||
msgid "Expand Upper Skins"
|
||||
msgstr ""
|
||||
|
||||
#: fdmprinter.def.json
|
||||
msgctxt "expand_upper_skins description"
|
||||
msgid ""
|
||||
"Expand upper skin areas (areas with air above) so that they support infill "
|
||||
"above."
|
||||
msgstr ""
|
||||
|
||||
#: fdmprinter.def.json
|
||||
msgctxt "expand_lower_skins label"
|
||||
msgid "Expand Lower Skins"
|
||||
msgstr ""
|
||||
|
||||
#: fdmprinter.def.json
|
||||
msgctxt "expand_lower_skins description"
|
||||
msgid ""
|
||||
"Expand lower skin areas (areas with air below) so that they are anchored by "
|
||||
"the infill layers above and below."
|
||||
msgstr ""
|
||||
|
||||
#: fdmprinter.def.json
|
||||
msgctxt "expand_skins_expand_distance label"
|
||||
msgid "Skin Expand Distance"
|
||||
msgstr ""
|
||||
|
||||
#: fdmprinter.def.json
|
||||
msgctxt "expand_skins_expand_distance description"
|
||||
msgid ""
|
||||
"The distance the skins are expanded into the infill. The default distance is "
|
||||
"enough to bridge the gap between the infill lines and will stop holes "
|
||||
"appearing in the skin where it meets the wall when the infill density is "
|
||||
"low. A smaller distance will often be sufficient."
|
||||
msgstr ""
|
||||
|
||||
#: fdmprinter.def.json
|
||||
msgctxt "max_skin_angle_for_expansion label"
|
||||
msgid "Maximum Skin Angle for Expansion"
|
||||
msgstr ""
|
||||
|
||||
#: fdmprinter.def.json
|
||||
msgctxt "max_skin_angle_for_expansion description"
|
||||
msgid ""
|
||||
"Top and/or bottom surfaces of your object with an angle larger than this "
|
||||
"setting, won't have their top/bottom skin expanded. This avoids expanding "
|
||||
"the narrow skin areas that are created when the model surface has a near "
|
||||
"vertical slope. An angle of 0° is horizontal, while an angle of 90° is "
|
||||
"vertical."
|
||||
msgstr ""
|
||||
|
||||
#: fdmprinter.def.json
|
||||
msgctxt "min_skin_width_for_expansion label"
|
||||
msgid "Minimum Skin Width for Expansion"
|
||||
msgstr ""
|
||||
|
||||
#: fdmprinter.def.json
|
||||
msgctxt "min_skin_width_for_expansion description"
|
||||
msgid ""
|
||||
"Skin areas narrower than this are not expanded. This avoids expanding the "
|
||||
"narrow skin areas that are created when the model surface has a slope close "
|
||||
"to the vertical."
|
||||
msgstr ""
|
||||
|
||||
#: fdmprinter.def.json
|
||||
msgctxt "material label"
|
||||
msgid "Material"
|
||||
@ -1304,8 +1464,7 @@ msgstr ""
|
||||
|
||||
#: fdmprinter.def.json
|
||||
msgctxt "material_print_temperature description"
|
||||
msgid ""
|
||||
"The temperature used for printing. Set at 0 to pre-heat the printer manually."
|
||||
msgid "The temperature used for printing."
|
||||
msgstr ""
|
||||
|
||||
#: fdmprinter.def.json
|
||||
@ -1376,8 +1535,8 @@ msgstr ""
|
||||
#: fdmprinter.def.json
|
||||
msgctxt "material_bed_temperature description"
|
||||
msgid ""
|
||||
"The temperature used for the heated build plate. Set at 0 to pre-heat the "
|
||||
"printer manually."
|
||||
"The temperature used for the heated build plate. If this is 0, the bed will "
|
||||
"not heat up for this print."
|
||||
msgstr ""
|
||||
|
||||
#: fdmprinter.def.json
|
||||
@ -2216,6 +2375,16 @@ msgctxt "retraction_combing option noskin"
|
||||
msgid "No Skin"
|
||||
msgstr ""
|
||||
|
||||
#: fdmprinter.def.json
|
||||
msgctxt "travel_retract_before_outer_wall label"
|
||||
msgid "Retract Before Outer Wall"
|
||||
msgstr ""
|
||||
|
||||
#: fdmprinter.def.json
|
||||
msgctxt "travel_retract_before_outer_wall description"
|
||||
msgid "Always retract when moving to start an outer wall."
|
||||
msgstr ""
|
||||
|
||||
#: fdmprinter.def.json
|
||||
msgctxt "travel_avoid_other_parts label"
|
||||
msgid "Avoid Printed Parts When Traveling"
|
||||
@ -2671,7 +2840,7 @@ msgctxt "support_z_distance description"
|
||||
msgid ""
|
||||
"Distance from the top/bottom of the support structure to the print. This gap "
|
||||
"provides clearance to remove the supports after the model is printed. This "
|
||||
"value is rounded down to a multiple of the layer height."
|
||||
"value is rounded up to a multiple of the layer height."
|
||||
msgstr ""
|
||||
|
||||
#: fdmprinter.def.json
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,13 +1,18 @@
|
||||
# Cura JSON setting files
|
||||
# Copyright (C) 2017 Ultimaker
|
||||
# This file is distributed under the same license as the Cura package.
|
||||
# Ruben Dulek <r.dulek@ultimaker.com>, 2017.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Uranium json setting files\n"
|
||||
"Report-Msgid-Bugs-To: http://github.com/ultimaker/uranium\n"
|
||||
"POT-Creation-Date: 2016-12-28 10:51+0000\n"
|
||||
"PO-Revision-Date: 2017-01-12 15:51+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE\n"
|
||||
"Language: \n"
|
||||
"Project-Id-Version: Cura 2.5\n"
|
||||
"Report-Msgid-Bugs-To: http://github.com/Ultimaker/Cura\n"
|
||||
"POT-Creation-Date: 2017-03-27 17:27+0000\n"
|
||||
"PO-Revision-Date: 2017-04-04 11:27+0200\n"
|
||||
"Last-Translator: Bothof <info@bothof.nl>\n"
|
||||
"Language-Team: Bothof <info@bothof.nl>\n"
|
||||
"Language: fi\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,13 +1,18 @@
|
||||
# Cura JSON setting files
|
||||
# Copyright (C) 2017 Ultimaker
|
||||
# This file is distributed under the same license as the Cura package.
|
||||
# Ruben Dulek <r.dulek@ultimaker.com>, 2017.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Uranium json setting files\n"
|
||||
"Report-Msgid-Bugs-To: http://github.com/ultimaker/uranium\n"
|
||||
"POT-Creation-Date: 2016-12-28 10:51+0000\n"
|
||||
"PO-Revision-Date: 2017-01-12 15:51+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE\n"
|
||||
"Language: \n"
|
||||
"Project-Id-Version: Cura 2.5\n"
|
||||
"Report-Msgid-Bugs-To: http://github.com/Ultimaker/Cura\n"
|
||||
"POT-Creation-Date: 2017-03-27 17:27+0000\n"
|
||||
"PO-Revision-Date: 2017-04-04 11:27+0200\n"
|
||||
"Last-Translator: Bothof <info@bothof.nl>\n"
|
||||
"Language-Team: Bothof <info@bothof.nl>\n"
|
||||
"Language: fr\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,13 +1,18 @@
|
||||
# Cura JSON setting files
|
||||
# Copyright (C) 2017 Ultimaker
|
||||
# This file is distributed under the same license as the Cura package.
|
||||
# Ruben Dulek <r.dulek@ultimaker.com>, 2017.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Uranium json setting files\n"
|
||||
"Report-Msgid-Bugs-To: http://github.com/ultimaker/uranium\n"
|
||||
"POT-Creation-Date: 2016-12-28 10:51+0000\n"
|
||||
"PO-Revision-Date: 2017-01-12 15:51+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE\n"
|
||||
"Language: \n"
|
||||
"Project-Id-Version: Cura 2.5\n"
|
||||
"Report-Msgid-Bugs-To: http://github.com/Ultimaker/Cura\n"
|
||||
"POT-Creation-Date: 2017-03-27 17:27+0000\n"
|
||||
"PO-Revision-Date: 2017-04-04 11:27+0200\n"
|
||||
"Last-Translator: Bothof <info@bothof.nl>\n"
|
||||
"Language-Team: Bothof <info@bothof.nl>\n"
|
||||
"Language: it\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
File diff suppressed because it is too large
Load Diff
3208
resources/i18n/jp/cura.po
Normal file
3208
resources/i18n/jp/cura.po
Normal file
File diff suppressed because it is too large
Load Diff
3330
resources/i18n/ko/cura.po
Normal file
3330
resources/i18n/ko/cura.po
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,13 +1,18 @@
|
||||
# Cura JSON setting files
|
||||
# Copyright (C) 2017 Ultimaker
|
||||
# This file is distributed under the same license as the Cura package.
|
||||
# Ruben Dulek <r.dulek@ultimaker.com>, 2017.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Uranium json setting files\n"
|
||||
"Report-Msgid-Bugs-To: http://github.com/ultimaker/uranium\n"
|
||||
"POT-Creation-Date: 2016-12-28 10:51+0000\n"
|
||||
"PO-Revision-Date: 2017-01-12 15:51+0100\n"
|
||||
"Last-Translator: Ruben Dulek <r.dulek@ultimaker.com>\n"
|
||||
"Language-Team: Ultimaker\n"
|
||||
"Language: \n"
|
||||
"Project-Id-Version: Cura 2.5\n"
|
||||
"Report-Msgid-Bugs-To: http://github.com/Ultimaker/Cura\n"
|
||||
"POT-Creation-Date: 2017-03-27 17:27+0000\n"
|
||||
"PO-Revision-Date: 2017-04-04 11:27+0200\n"
|
||||
"Last-Translator: Bothof <info@bothof.nl>\n"
|
||||
"Language-Team: Bothof <info@bothof.nl>\n"
|
||||
"Language: nl\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -3,8 +3,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Uranium json setting files\n"
|
||||
"Report-Msgid-Bugs-To: http://github.com/ultimaker/uranium\n"
|
||||
"POT-Creation-Date: 2016-12-28 10:51+0000\n"
|
||||
"PO-Revision-Date: 2016-01-25 05:05-0300\n"
|
||||
"POT-Creation-Date: 2017-03-27 17:27+0000\n"
|
||||
"PO-Revision-Date: 2017-04-10 09:05-0300\n"
|
||||
"Last-Translator: Cláudio Sampaio <patola@makerlinux.com.br>\n"
|
||||
"Language-Team: LANGUAGE\n"
|
||||
"Language: ptbr\n"
|
||||
@ -70,12 +70,8 @@ msgstr "Posição de Início do Extrusor Absoluta"
|
||||
|
||||
#: fdmextruder.def.json
|
||||
msgctxt "machine_extruder_start_pos_abs description"
|
||||
msgid ""
|
||||
"Make the extruder starting position absolute rather than relative to the "
|
||||
"last-known location of the head."
|
||||
msgstr ""
|
||||
"Faz a posição de início do extrusor ser absoluta ao invés de relativa à "
|
||||
"última posição conhecida da cabeça de impressão."
|
||||
msgid "Make the extruder starting position absolute rather than relative to the last-known location of the head."
|
||||
msgstr "Faz a posição de início do extrusor ser absoluta ao invés de relativa à última posição conhecida da cabeça de impressão."
|
||||
|
||||
#: fdmextruder.def.json
|
||||
msgctxt "machine_extruder_start_pos_x label"
|
||||
@ -114,12 +110,8 @@ msgstr "Posição Final do Extrusor Absoluta"
|
||||
|
||||
#: fdmextruder.def.json
|
||||
msgctxt "machine_extruder_end_pos_abs description"
|
||||
msgid ""
|
||||
"Make the extruder ending position absolute rather than relative to the last-"
|
||||
"known location of the head."
|
||||
msgstr ""
|
||||
"Faz a posição final do extrusor ser absoluta ao invés de relativa à última "
|
||||
"posição conhecida da cabeça de impressão."
|
||||
msgid "Make the extruder ending position absolute rather than relative to the last-known location of the head."
|
||||
msgstr "Faz a posição final do extrusor ser absoluta ao invés de relativa à última posição conhecida da cabeça de impressão."
|
||||
|
||||
#: fdmextruder.def.json
|
||||
msgctxt "machine_extruder_end_pos_x label"
|
||||
@ -148,11 +140,8 @@ msgstr "Posição Z de Purga do Extrusor"
|
||||
|
||||
#: fdmextruder.def.json
|
||||
msgctxt "extruder_prime_pos_z description"
|
||||
msgid ""
|
||||
"The Z coordinate of the position where the nozzle primes at the start of "
|
||||
"printing."
|
||||
msgstr ""
|
||||
"A coordenada Z da posição onde o bico faz a purga no início da impressão."
|
||||
msgid "The Z coordinate of the position where the nozzle primes at the start of printing."
|
||||
msgstr "A coordenada Z da posição onde o bico faz a purga no início da impressão."
|
||||
|
||||
#: fdmextruder.def.json
|
||||
msgctxt "platform_adhesion label"
|
||||
@ -171,11 +160,8 @@ msgstr "Posição X de Purga do Extrusor"
|
||||
|
||||
#: fdmextruder.def.json
|
||||
msgctxt "extruder_prime_pos_x description"
|
||||
msgid ""
|
||||
"The X coordinate of the position where the nozzle primes at the start of "
|
||||
"printing."
|
||||
msgstr ""
|
||||
"A coordenada X da posição onde o bico faz a purga no início da impressão."
|
||||
msgid "The X coordinate of the position where the nozzle primes at the start of printing."
|
||||
msgstr "A coordenada X da posição onde o bico faz a purga no início da impressão."
|
||||
|
||||
#: fdmextruder.def.json
|
||||
msgctxt "extruder_prime_pos_y label"
|
||||
@ -184,8 +170,5 @@ msgstr "Posição Y de Purga do Extrusor"
|
||||
|
||||
#: fdmextruder.def.json
|
||||
msgctxt "extruder_prime_pos_y description"
|
||||
msgid ""
|
||||
"The Y coordinate of the position where the nozzle primes at the start of "
|
||||
"printing."
|
||||
msgstr ""
|
||||
"A coordenada Y da posição onde o bico faz a purga no início da impressão."
|
||||
msgid "The Y coordinate of the position where the nozzle primes at the start of printing."
|
||||
msgstr "A coordenada Y da posição onde o bico faz a purga no início da impressão."
|
||||
|
File diff suppressed because it is too large
Load Diff
1573
resources/i18n/ru/cura.po
Normal file → Executable file
1573
resources/i18n/ru/cura.po
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
2539
resources/i18n/ru/fdmprinter.def.json.po
Normal file → Executable file
2539
resources/i18n/ru/fdmprinter.def.json.po
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,13 +1,18 @@
|
||||
# Cura JSON setting files
|
||||
# Copyright (C) 2017 Ultimaker
|
||||
# This file is distributed under the same license as the Cura package.
|
||||
# Ruben Dulek <r.dulek@ultimaker.com>, 2017.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Uranium json setting files\n"
|
||||
"Report-Msgid-Bugs-To: http://github.com/ultimaker/uranium\n"
|
||||
"POT-Creation-Date: 2016-12-28 10:51+0000\n"
|
||||
"PO-Revision-Date: 2017-01-12 15:51+0100\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE\n"
|
||||
"Language: \n"
|
||||
"Project-Id-Version: Cura 2.5\n"
|
||||
"Report-Msgid-Bugs-To: http://github.com/Ultimaker/Cura\n"
|
||||
"POT-Creation-Date: 2017-03-27 17:27+0000\n"
|
||||
"PO-Revision-Date: 2017-04-04 11:27+0200\n"
|
||||
"Last-Translator: Bothof <info@bothof.nl>\n"
|
||||
"Language-Team: Bothof <info@bothof.nl>\n"
|
||||
"Language: tr\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
|
File diff suppressed because it is too large
Load Diff
BIN
resources/meshes/makeR_pegasus_platform.stl
Normal file
BIN
resources/meshes/makeR_pegasus_platform.stl
Normal file
Binary file not shown.
18790
resources/meshes/makeR_prusa_tairona_i3_platform.stl
Normal file
18790
resources/meshes/makeR_prusa_tairona_i3_platform.stl
Normal file
File diff suppressed because it is too large
Load Diff
35
resources/qml/Actions.qml
Normal file → Executable file
35
resources/qml/Actions.qml
Normal file → Executable file
@ -31,6 +31,8 @@ Item
|
||||
property alias selectAll: selectAllAction;
|
||||
property alias deleteAll: deleteAllAction;
|
||||
property alias reloadAll: reloadAllAction;
|
||||
property alias arrangeAll: arrangeAllAction;
|
||||
property alias arrangeSelection: arrangeSelectionAction;
|
||||
property alias resetAllTranslation: resetAllTranslationAction;
|
||||
property alias resetAll: resetAllAction;
|
||||
|
||||
@ -183,7 +185,7 @@ Item
|
||||
enabled: UM.Controller.toolsEnabled;
|
||||
iconName: "edit-delete";
|
||||
shortcut: StandardKey.Delete;
|
||||
onTriggered: Printer.deleteSelection();
|
||||
onTriggered: CuraApplication.deleteSelection();
|
||||
}
|
||||
|
||||
Action
|
||||
@ -207,7 +209,7 @@ Item
|
||||
enabled: UM.Scene.numObjectsSelected > 1 ? true: false
|
||||
iconName: "object-group"
|
||||
shortcut: "Ctrl+G";
|
||||
onTriggered: Printer.groupSelected();
|
||||
onTriggered: CuraApplication.groupSelected();
|
||||
}
|
||||
|
||||
Action
|
||||
@ -217,7 +219,7 @@ Item
|
||||
enabled: UM.Scene.isGroupSelected
|
||||
iconName: "object-ungroup"
|
||||
shortcut: "Ctrl+Shift+G";
|
||||
onTriggered: Printer.ungroupSelected();
|
||||
onTriggered: CuraApplication.ungroupSelected();
|
||||
}
|
||||
|
||||
Action
|
||||
@ -227,7 +229,7 @@ Item
|
||||
enabled: UM.Scene.numObjectsSelected > 1 ? true: false
|
||||
iconName: "merge";
|
||||
shortcut: "Ctrl+Alt+G";
|
||||
onTriggered: Printer.mergeSelected();
|
||||
onTriggered: CuraApplication.mergeSelected();
|
||||
}
|
||||
|
||||
Action
|
||||
@ -244,7 +246,7 @@ Item
|
||||
enabled: UM.Controller.toolsEnabled;
|
||||
iconName: "edit-select-all";
|
||||
shortcut: "Ctrl+A";
|
||||
onTriggered: Printer.selectAll();
|
||||
onTriggered: CuraApplication.selectAll();
|
||||
}
|
||||
|
||||
Action
|
||||
@ -254,7 +256,7 @@ Item
|
||||
enabled: UM.Controller.toolsEnabled;
|
||||
iconName: "edit-delete";
|
||||
shortcut: "Ctrl+D";
|
||||
onTriggered: Printer.deleteAll();
|
||||
onTriggered: CuraApplication.deleteAll();
|
||||
}
|
||||
|
||||
Action
|
||||
@ -263,21 +265,36 @@ Item
|
||||
text: catalog.i18nc("@action:inmenu menubar:file","Re&load All Models");
|
||||
iconName: "document-revert";
|
||||
shortcut: "F5"
|
||||
onTriggered: Printer.reloadAll();
|
||||
onTriggered: CuraApplication.reloadAll();
|
||||
}
|
||||
|
||||
Action
|
||||
{
|
||||
id: arrangeAllAction;
|
||||
text: catalog.i18nc("@action:inmenu menubar:edit","Arrange All Models");
|
||||
onTriggered: Printer.arrangeAll();
|
||||
shortcut: "Ctrl+R";
|
||||
}
|
||||
|
||||
Action
|
||||
{
|
||||
id: arrangeSelectionAction;
|
||||
text: catalog.i18nc("@action:inmenu menubar:edit","Arrange Selection");
|
||||
onTriggered: Printer.arrangeSelection();
|
||||
}
|
||||
|
||||
Action
|
||||
{
|
||||
id: resetAllTranslationAction;
|
||||
text: catalog.i18nc("@action:inmenu menubar:edit","Reset All Model Positions");
|
||||
onTriggered: Printer.resetAllTranslation();
|
||||
onTriggered: CuraApplication.resetAllTranslation();
|
||||
}
|
||||
|
||||
Action
|
||||
{
|
||||
id: resetAllAction;
|
||||
text: catalog.i18nc("@action:inmenu menubar:edit","Reset All Model &Transformations");
|
||||
onTriggered: Printer.resetAll();
|
||||
onTriggered: CuraApplication.resetAll();
|
||||
}
|
||||
|
||||
Action
|
||||
|
@ -6,6 +6,7 @@ import QtQuick.Controls 1.1
|
||||
import QtQuick.Controls.Styles 1.1
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Dialogs 1.1
|
||||
import QtQuick.Window 2.1
|
||||
|
||||
import UM 1.3 as UM
|
||||
import Cura 1.0 as Cura
|
||||
@ -17,13 +18,13 @@ UM.Dialog
|
||||
id: base
|
||||
|
||||
title: catalog.i18nc("@title:window", "Open project file")
|
||||
width: 420
|
||||
height: 140
|
||||
width: 450 * Screen.devicePixelRatio
|
||||
height: 150 * Screen.devicePixelRatio
|
||||
|
||||
maximumHeight: height
|
||||
maximumWidth: width
|
||||
minimumHeight: height
|
||||
minimumWidth: width
|
||||
minimumHeight: maximumHeight
|
||||
minimumWidth: maximumWidth
|
||||
|
||||
modality: UM.Application.platform == "linux" ? Qt.NonModal : Qt.WindowModal;
|
||||
|
||||
@ -40,7 +41,9 @@ UM.Dialog
|
||||
function loadModelFiles(fileUrls)
|
||||
{
|
||||
for (var i in fileUrls)
|
||||
Printer.readLocalFile(fileUrls[i]);
|
||||
{
|
||||
CuraApplication.readLocalFile(fileUrls[i]);
|
||||
}
|
||||
|
||||
var meshName = backgroundItem.getMeshName(fileUrls[0].toString());
|
||||
backgroundItem.hasMesh(decodeURIComponent(meshName));
|
||||
@ -58,15 +61,16 @@ UM.Dialog
|
||||
Column
|
||||
{
|
||||
anchors.fill: parent
|
||||
anchors.margins: UM.Theme.getSize("default_margin").width
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
spacing: UM.Theme.getSize("default_margin").width
|
||||
anchors.leftMargin: 20 * Screen.devicePixelRatio
|
||||
anchors.rightMargin: 20 * Screen.devicePixelRatio
|
||||
anchors.bottomMargin: 20 * Screen.devicePixelRatio
|
||||
spacing: 10 * Screen.devicePixelRatio
|
||||
|
||||
Label
|
||||
{
|
||||
text: catalog.i18nc("@text:window", "This is a Cura project file. Would you like to open it as a project\nor import the models from it?")
|
||||
anchors.margins: UM.Theme.getSize("default_margin").width
|
||||
text: catalog.i18nc("@text:window", "This is a Cura project file. Would you like to open it as a project or import the models from it?")
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
font: UM.Theme.getFont("default")
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
@ -75,7 +79,6 @@ UM.Dialog
|
||||
{
|
||||
id: rememberChoiceCheckBox
|
||||
text: catalog.i18nc("@text:window", "Remember my choice")
|
||||
anchors.margins: UM.Theme.getSize("default_margin").width
|
||||
checked: UM.Preferences.getValue("cura/choice_on_open_project") != "always_ask"
|
||||
}
|
||||
|
||||
@ -91,7 +94,7 @@ UM.Dialog
|
||||
id: openAsProjectButton
|
||||
text: catalog.i18nc("@action:button", "Open as project");
|
||||
anchors.right: importModelsButton.left
|
||||
anchors.rightMargin: UM.Theme.getSize("default_margin").width
|
||||
anchors.rightMargin: UM.Theme.getSize("default_margin").width * Screen.devicePixelRatio
|
||||
isDefault: true
|
||||
onClicked:
|
||||
{
|
||||
|
@ -21,7 +21,7 @@ UM.MainWindow
|
||||
property bool monitoringPrint: false
|
||||
Component.onCompleted:
|
||||
{
|
||||
Printer.setMinimumWindowSize(UM.Theme.getSize("window_minimum_size"))
|
||||
CuraApplication.setMinimumWindowSize(UM.Theme.getSize("window_minimum_size"))
|
||||
// Workaround silly issues with QML Action's shortcut property.
|
||||
//
|
||||
// Currently, there is no way to define shortcuts as "Application Shortcut".
|
||||
@ -131,6 +131,7 @@ UM.MainWindow
|
||||
MenuItem { action: Cura.Actions.redo; }
|
||||
MenuSeparator { }
|
||||
MenuItem { action: Cura.Actions.selectAll; }
|
||||
MenuItem { action: Cura.Actions.arrangeAll; }
|
||||
MenuItem { action: Cura.Actions.deleteSelection; }
|
||||
MenuItem { action: Cura.Actions.deleteAll; }
|
||||
MenuItem { action: Cura.Actions.resetAllTranslation; }
|
||||
@ -259,7 +260,7 @@ UM.MainWindow
|
||||
{
|
||||
if (drop.urls.length > 0)
|
||||
{
|
||||
handleOpenFileUrls(drop.urls);
|
||||
openDialog.handleOpenFileUrls(drop.urls);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -502,7 +503,7 @@ UM.MainWindow
|
||||
icon: StandardIcon.Question
|
||||
onYes:
|
||||
{
|
||||
Printer.deleteAll();
|
||||
CuraApplication.deleteAll();
|
||||
Cura.Actions.resetProfile.trigger();
|
||||
}
|
||||
}
|
||||
@ -603,6 +604,7 @@ UM.MainWindow
|
||||
MenuItem { action: Cura.Actions.multiplyObject; }
|
||||
MenuSeparator { }
|
||||
MenuItem { action: Cura.Actions.selectAll; }
|
||||
MenuItem { action: Cura.Actions.arrangeAll; }
|
||||
MenuItem { action: Cura.Actions.deleteAll; }
|
||||
MenuItem { action: Cura.Actions.reloadAll; }
|
||||
MenuItem { action: Cura.Actions.resetAllTranslation; }
|
||||
@ -619,7 +621,7 @@ UM.MainWindow
|
||||
{
|
||||
if(objectContextMenu.objectId != 0)
|
||||
{
|
||||
Printer.deleteObject(objectContextMenu.objectId);
|
||||
CuraApplication.deleteObject(objectContextMenu.objectId);
|
||||
objectContextMenu.objectId = 0;
|
||||
}
|
||||
}
|
||||
@ -652,7 +654,7 @@ UM.MainWindow
|
||||
{
|
||||
if(objectContextMenu.objectId != 0)
|
||||
{
|
||||
Printer.centerObject(objectContextMenu.objectId);
|
||||
CuraApplication.centerObject(objectContextMenu.objectId);
|
||||
objectContextMenu.objectId = 0;
|
||||
}
|
||||
}
|
||||
@ -663,6 +665,7 @@ UM.MainWindow
|
||||
{
|
||||
id: contextMenu;
|
||||
MenuItem { action: Cura.Actions.selectAll; }
|
||||
MenuItem { action: Cura.Actions.arrangeAll; }
|
||||
MenuItem { action: Cura.Actions.deleteAll; }
|
||||
MenuItem { action: Cura.Actions.reloadAll; }
|
||||
MenuItem { action: Cura.Actions.resetAllTranslation; }
|
||||
@ -722,85 +725,85 @@ UM.MainWindow
|
||||
|
||||
handleOpenFileUrls(fileUrls);
|
||||
}
|
||||
}
|
||||
|
||||
// Yeah... I know... it is a mess to put all those things here.
|
||||
// There are lots of user interactions in this part of the logic, such as showing a warning dialog here and there,
|
||||
// etc. This means it will come back and forth from time to time between QML and Python. So, separating the logic
|
||||
// and view here may require more effort but make things more difficult to understand.
|
||||
function handleOpenFileUrls(fileUrls)
|
||||
{
|
||||
// look for valid project files
|
||||
var projectFileUrlList = [];
|
||||
var hasGcode = false;
|
||||
var nonGcodeFileList = [];
|
||||
for (var i in fileUrls)
|
||||
// Yeah... I know... it is a mess to put all those things here.
|
||||
// There are lots of user interactions in this part of the logic, such as showing a warning dialog here and there,
|
||||
// etc. This means it will come back and forth from time to time between QML and Python. So, separating the logic
|
||||
// and view here may require more effort but make things more difficult to understand.
|
||||
function handleOpenFileUrls(fileUrlList)
|
||||
{
|
||||
var endsWithG = /\.g$/;
|
||||
var endsWithGcode = /\.gcode$/;
|
||||
if (endsWithG.test(fileUrls[i]) || endsWithGcode.test(fileUrls[i]))
|
||||
// look for valid project files
|
||||
var projectFileUrlList = [];
|
||||
var hasGcode = false;
|
||||
var nonGcodeFileList = [];
|
||||
for (var i in fileUrlList)
|
||||
{
|
||||
continue;
|
||||
var endsWithG = /\.g$/;
|
||||
var endsWithGcode = /\.gcode$/;
|
||||
if (endsWithG.test(fileUrlList[i]) || endsWithGcode.test(fileUrlList[i]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (CuraApplication.checkIsValidProjectFile(fileUrlList[i]))
|
||||
{
|
||||
projectFileUrlList.push(fileUrlList[i]);
|
||||
}
|
||||
nonGcodeFileList.push(fileUrlList[i]);
|
||||
}
|
||||
else if (CuraApplication.checkIsValidProjectFile(fileUrls[i]))
|
||||
hasGcode = nonGcodeFileList.length < fileUrlList.length;
|
||||
|
||||
// show a warning if selected multiple files together with Gcode
|
||||
var hasProjectFile = projectFileUrlList.length > 0;
|
||||
var selectedMultipleFiles = fileUrlList.length > 1;
|
||||
if (selectedMultipleFiles && hasGcode)
|
||||
{
|
||||
projectFileUrlList.push(fileUrls[i]);
|
||||
infoMultipleFilesWithGcodeDialog.selectedMultipleFiles = selectedMultipleFiles;
|
||||
infoMultipleFilesWithGcodeDialog.hasProjectFile = hasProjectFile;
|
||||
infoMultipleFilesWithGcodeDialog.fileUrls = nonGcodeFileList.slice();
|
||||
infoMultipleFilesWithGcodeDialog.projectFileUrlList = projectFileUrlList.slice();
|
||||
infoMultipleFilesWithGcodeDialog.open();
|
||||
}
|
||||
nonGcodeFileList.push(fileUrls[i]);
|
||||
}
|
||||
hasGcode = nonGcodeFileList.length < fileUrls.length;
|
||||
|
||||
// show a warning if selected multiple files together with Gcode
|
||||
var hasProjectFile = projectFileUrlList.length > 0;
|
||||
var selectedMultipleFiles = fileUrls.length > 1;
|
||||
if (selectedMultipleFiles && hasGcode)
|
||||
{
|
||||
infoMultipleFilesWithGcodeDialog.selectedMultipleFiles = selectedMultipleFiles;
|
||||
infoMultipleFilesWithGcodeDialog.hasProjectFile = hasProjectFile;
|
||||
infoMultipleFilesWithGcodeDialog.fileUrls = nonGcodeFileList.slice();
|
||||
infoMultipleFilesWithGcodeDialog.projectFileUrlList = projectFileUrlList.slice();
|
||||
infoMultipleFilesWithGcodeDialog.open();
|
||||
}
|
||||
else
|
||||
{
|
||||
handleOpenFiles(selectedMultipleFiles, hasProjectFile, fileUrls, projectFileUrlList);
|
||||
}
|
||||
}
|
||||
|
||||
function handleOpenFiles(selectedMultipleFiles, hasProjectFile, fileUrls, projectFileUrlList)
|
||||
{
|
||||
// we only allow opening one project file
|
||||
if (selectedMultipleFiles && hasProjectFile)
|
||||
{
|
||||
openFilesIncludingProjectsDialog.fileUrls = fileUrls.slice();
|
||||
openFilesIncludingProjectsDialog.show();
|
||||
return;
|
||||
}
|
||||
|
||||
if (hasProjectFile)
|
||||
{
|
||||
var projectFile = projectFileUrlList[0];
|
||||
|
||||
// check preference
|
||||
var choice = UM.Preferences.getValue("cura/choice_on_open_project");
|
||||
if (choice == "open_as_project")
|
||||
else
|
||||
{
|
||||
openFilesIncludingProjectsDialog.loadProjectFile(projectFile);
|
||||
}
|
||||
else if (choice == "open_as_model")
|
||||
{
|
||||
openFilesIncludingProjectsDialog.loadModelFiles([projectFile].slice());
|
||||
}
|
||||
else // always ask
|
||||
{
|
||||
// ask whether to open as project or as models
|
||||
askOpenAsProjectOrModelsDialog.fileUrl = projectFile;
|
||||
askOpenAsProjectOrModelsDialog.show();
|
||||
handleOpenFiles(selectedMultipleFiles, hasProjectFile, fileUrlList, projectFileUrlList);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
function handleOpenFiles(selectedMultipleFiles, hasProjectFile, fileUrlList, projectFileUrlList)
|
||||
{
|
||||
openFilesIncludingProjectsDialog.loadModelFiles(fileUrls.slice());
|
||||
// we only allow opening one project file
|
||||
if (selectedMultipleFiles && hasProjectFile)
|
||||
{
|
||||
openFilesIncludingProjectsDialog.fileUrls = fileUrlList.slice();
|
||||
openFilesIncludingProjectsDialog.show();
|
||||
return;
|
||||
}
|
||||
|
||||
if (hasProjectFile)
|
||||
{
|
||||
var projectFile = projectFileUrlList[0];
|
||||
|
||||
// check preference
|
||||
var choice = UM.Preferences.getValue("cura/choice_on_open_project");
|
||||
if (choice == "open_as_project")
|
||||
{
|
||||
openFilesIncludingProjectsDialog.loadProjectFile(projectFile);
|
||||
}
|
||||
else if (choice == "open_as_model")
|
||||
{
|
||||
openFilesIncludingProjectsDialog.loadModelFiles([projectFile].slice());
|
||||
}
|
||||
else // always ask
|
||||
{
|
||||
// ask whether to open as project or as models
|
||||
askOpenAsProjectOrModelsDialog.fileUrl = projectFile;
|
||||
askOpenAsProjectOrModelsDialog.show();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
openFilesIncludingProjectsDialog.loadModelFiles(fileUrlList.slice());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -818,7 +821,7 @@ UM.MainWindow
|
||||
|
||||
onAccepted:
|
||||
{
|
||||
handleOpenFiles(selectedMultipleFiles, hasProjectFile, fileUrls, projectFileUrlList);
|
||||
openDialog.handleOpenFiles(selectedMultipleFiles, hasProjectFile, fileUrls, projectFileUrlList);
|
||||
}
|
||||
}
|
||||
|
||||
@ -898,14 +901,14 @@ UM.MainWindow
|
||||
{
|
||||
id: messageDialog
|
||||
modality: Qt.ApplicationModal
|
||||
onAccepted: Printer.messageBoxClosed(clickedButton)
|
||||
onApply: Printer.messageBoxClosed(clickedButton)
|
||||
onDiscard: Printer.messageBoxClosed(clickedButton)
|
||||
onHelp: Printer.messageBoxClosed(clickedButton)
|
||||
onNo: Printer.messageBoxClosed(clickedButton)
|
||||
onRejected: Printer.messageBoxClosed(clickedButton)
|
||||
onReset: Printer.messageBoxClosed(clickedButton)
|
||||
onYes: Printer.messageBoxClosed(clickedButton)
|
||||
onAccepted: CuraApplication.messageBoxClosed(clickedButton)
|
||||
onApply: CuraApplication.messageBoxClosed(clickedButton)
|
||||
onDiscard: CuraApplication.messageBoxClosed(clickedButton)
|
||||
onHelp: CuraApplication.messageBoxClosed(clickedButton)
|
||||
onNo: CuraApplication.messageBoxClosed(clickedButton)
|
||||
onRejected: CuraApplication.messageBoxClosed(clickedButton)
|
||||
onReset: CuraApplication.messageBoxClosed(clickedButton)
|
||||
onYes: CuraApplication.messageBoxClosed(clickedButton)
|
||||
}
|
||||
|
||||
Connections
|
||||
|
@ -4,6 +4,7 @@
|
||||
import QtQuick 2.1
|
||||
import QtQuick.Controls 1.1
|
||||
import QtQuick.Dialogs 1.2
|
||||
import QtQuick.Window 2.1
|
||||
|
||||
import UM 1.2 as UM
|
||||
import Cura 1.1 as Cura
|
||||
@ -13,8 +14,8 @@ UM.Dialog
|
||||
id: base
|
||||
title: catalog.i18nc("@title:window", "Discard or Keep changes")
|
||||
|
||||
width: 800
|
||||
height: 400
|
||||
width: 800 * Screen.devicePixelRatio
|
||||
height: 400 * Screen.devicePixelRatio
|
||||
property var changesModel: Cura.UserChangesModel{ id: userChangesModel}
|
||||
onVisibilityChanged:
|
||||
{
|
||||
@ -68,7 +69,7 @@ UM.Dialog
|
||||
anchors.margins: UM.Theme.getSize("default_margin").width
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
height: base.height - 150
|
||||
height: base.height - 150 * Screen.devicePixelRatio
|
||||
id: tableView
|
||||
Component
|
||||
{
|
||||
@ -190,7 +191,7 @@ UM.Dialog
|
||||
anchors.right: parent.right
|
||||
onClicked:
|
||||
{
|
||||
Printer.discardOrKeepProfileChangesClosed("discard")
|
||||
CuraApplication.discardOrKeepProfileChangesClosed("discard")
|
||||
base.hide()
|
||||
}
|
||||
isDefault: true
|
||||
@ -204,7 +205,7 @@ UM.Dialog
|
||||
anchors.rightMargin: UM.Theme.getSize("default_margin").width
|
||||
onClicked:
|
||||
{
|
||||
Printer.discardOrKeepProfileChangesClosed("keep")
|
||||
CuraApplication.discardOrKeepProfileChangesClosed("keep")
|
||||
base.hide()
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ UM.Dialog
|
||||
interval: 1000;
|
||||
running: false;
|
||||
repeat: true;
|
||||
onTriggered: textArea.text = Printer.getEngineLog();
|
||||
onTriggered: textArea.text = CuraApplication.getEngineLog();
|
||||
}
|
||||
UM.I18nCatalog{id: catalog; name:"cura"}
|
||||
}
|
||||
@ -43,7 +43,7 @@ UM.Dialog
|
||||
{
|
||||
if(visible)
|
||||
{
|
||||
textArea.text = Printer.getEngineLog();
|
||||
textArea.text = CuraApplication.getEngineLog();
|
||||
updateTimer.start();
|
||||
} else
|
||||
{
|
||||
|
@ -12,7 +12,7 @@ import Cura 1.0 as Cura
|
||||
Item {
|
||||
id: base
|
||||
|
||||
property bool activity: Printer.platformActivity
|
||||
property bool activity: CuraApplication.platformActivity
|
||||
property string fileBaseName
|
||||
property variant activeMachineName: Cura.MachineManager.activeMachineName
|
||||
|
||||
@ -132,7 +132,7 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
Label
|
||||
Text
|
||||
{
|
||||
id: boundingSpec
|
||||
anchors.top: jobNameRow.bottom
|
||||
@ -141,7 +141,7 @@ Item {
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
font: UM.Theme.getFont("small")
|
||||
color: UM.Theme.getColor("text_subtext")
|
||||
text: Printer.getSceneBoundingBoxString
|
||||
text: CuraApplication.getSceneBoundingBoxString
|
||||
}
|
||||
|
||||
Rectangle
|
||||
@ -169,7 +169,7 @@ Item {
|
||||
color: UM.Theme.getColor("text_subtext")
|
||||
source: UM.Theme.getIcon("print_time")
|
||||
}
|
||||
Label
|
||||
Text
|
||||
{
|
||||
id: timeSpec
|
||||
anchors.right: lengthIcon.left
|
||||
@ -192,7 +192,7 @@ Item {
|
||||
color: UM.Theme.getColor("text_subtext")
|
||||
source: UM.Theme.getIcon("category_material")
|
||||
}
|
||||
Label
|
||||
Text
|
||||
{
|
||||
id: lengthSpec
|
||||
anchors.right: parent.right
|
||||
|
@ -15,6 +15,15 @@ Menu
|
||||
property int extruderIndex: 0
|
||||
property bool printerConnected: Cura.MachineManager.printerOutputDevices.length != 0
|
||||
|
||||
UM.SettingPropertyProvider
|
||||
{
|
||||
id: materialDiameterProvider
|
||||
|
||||
containerStackId: Cura.MachineManager.activeMachineId
|
||||
key: "material_diameter"
|
||||
watchedProperties: [ "value" ]
|
||||
}
|
||||
|
||||
MenuItem
|
||||
{
|
||||
id: automaticMaterial
|
||||
@ -141,7 +150,7 @@ Menu
|
||||
|
||||
function materialFilter()
|
||||
{
|
||||
var result = { "type": "material" };
|
||||
var result = { "type": "material", "approximate_diameter": Math.round(materialDiameterProvider.properties.value) };
|
||||
if(Cura.MachineManager.filterMaterialsByMachine)
|
||||
{
|
||||
result.definition = Cura.MachineManager.activeQualityDefinitionId;
|
||||
|
@ -13,11 +13,11 @@ Menu
|
||||
title: catalog.i18nc("@title:menu menubar:file", "Open &Recent")
|
||||
iconName: "document-open-recent";
|
||||
|
||||
enabled: Printer.recentFiles.length > 0;
|
||||
enabled: CuraApplication.recentFiles.length > 0;
|
||||
|
||||
Instantiator
|
||||
{
|
||||
model: Printer.recentFiles
|
||||
model: CuraApplication.recentFiles
|
||||
MenuItem
|
||||
{
|
||||
text:
|
||||
@ -36,11 +36,13 @@ Menu
|
||||
var choice = UM.Preferences.getValue("cura/choice_on_open_project");
|
||||
|
||||
if (choice == "open_as_project")
|
||||
{
|
||||
toOpenAsProject = true;
|
||||
else if (choice == "open_as_model")
|
||||
}else if (choice == "open_as_model"){
|
||||
toOpenAsModel = true;
|
||||
else
|
||||
}else{
|
||||
toShowDialog = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
toOpenAsModel = true;
|
||||
@ -54,9 +56,13 @@ Menu
|
||||
|
||||
// open file in the prefered way
|
||||
if (toOpenAsProject)
|
||||
{
|
||||
UM.WorkspaceFileHandler.readLocalFile(modelData);
|
||||
}
|
||||
else if (toOpenAsModel)
|
||||
Printer.readLocalFile(modelData);
|
||||
{
|
||||
CuraApplication.readLocalFile(modelData);
|
||||
}
|
||||
var meshName = backgroundItem.getMeshName(modelData.toString())
|
||||
backgroundItem.hasMesh(decodeURIComponent(meshName))
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ Item
|
||||
}
|
||||
}
|
||||
|
||||
property bool activity: Printer.platformActivity;
|
||||
property bool activity: CuraApplication.platformActivity;
|
||||
property int totalHeight: childrenRect.height + UM.Theme.getSize("default_margin").height
|
||||
property string fileBaseName
|
||||
property string statusText:
|
||||
@ -205,8 +205,8 @@ Item
|
||||
onAdditionalComponentsChanged:
|
||||
{
|
||||
if(areaId == "monitorButtons") {
|
||||
for (var component in Printer.additionalComponents["monitorButtons"]) {
|
||||
Printer.additionalComponents["monitorButtons"][component].parent = additionalComponentsRow
|
||||
for (var component in CuraApplication.additionalComponents["monitorButtons"]) {
|
||||
CuraApplication.additionalComponents["monitorButtons"][component].parent = additionalComponentsRow
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ UM.Dialog
|
||||
height: minimumHeight
|
||||
|
||||
property var objectId: 0;
|
||||
onAccepted: Printer.multiplyObject(base.objectId, parseInt(copiesField.text))
|
||||
onAccepted: CuraApplication.multiplyObject(base.objectId, parseInt(copiesField.text))
|
||||
|
||||
property variant catalog: UM.I18nCatalog { name: "cura" }
|
||||
|
||||
|
@ -6,6 +6,7 @@ import QtQuick.Controls 1.1
|
||||
import QtQuick.Controls.Styles 1.1
|
||||
import QtQuick.Layouts 1.1
|
||||
import QtQuick.Dialogs 1.1
|
||||
import QtQuick.Window 2.1
|
||||
|
||||
import UM 1.3 as UM
|
||||
import Cura 1.0 as Cura
|
||||
@ -16,8 +17,8 @@ UM.Dialog
|
||||
id: base
|
||||
|
||||
title: catalog.i18nc("@title:window", "Open file(s)")
|
||||
width: 420
|
||||
height: 170
|
||||
width: 420 * Screen.devicePixelRatio
|
||||
height: 170 * Screen.devicePixelRatio
|
||||
|
||||
maximumHeight: height
|
||||
maximumWidth: width
|
||||
@ -40,7 +41,9 @@ UM.Dialog
|
||||
function loadModelFiles(fileUrls)
|
||||
{
|
||||
for (var i in fileUrls)
|
||||
Printer.readLocalFile(fileUrls[i]);
|
||||
{
|
||||
CuraApplication.readLocalFile(fileUrls[i]);
|
||||
}
|
||||
|
||||
var meshName = backgroundItem.getMeshName(fileUrls[0].toString());
|
||||
backgroundItem.hasMesh(decodeURIComponent(meshName));
|
||||
@ -49,15 +52,18 @@ UM.Dialog
|
||||
Column
|
||||
{
|
||||
anchors.fill: parent
|
||||
anchors.margins: UM.Theme.getSize("default_margin").width
|
||||
anchors.leftMargin: 20 * Screen.devicePixelRatio
|
||||
anchors.rightMargin: 20 * Screen.devicePixelRatio
|
||||
anchors.bottomMargin: 20 * Screen.devicePixelRatio
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
spacing: UM.Theme.getSize("default_margin").width
|
||||
spacing: 10 * Screen.devicePixelRatio
|
||||
|
||||
Text
|
||||
{
|
||||
text: catalog.i18nc("@text:window", "We have found one or more project file(s) within the files you\nhave selected. You can open only one project file at a time. We\nsuggest to only import models from those files. Would you like\nto proceed?")
|
||||
anchors.margins: UM.Theme.getSize("default_margin").width
|
||||
text: catalog.i18nc("@text:window", "We have found one or more project file(s) within the files you have selected. You can open only one project file at a time. We suggest to only import models from those files. Would you like to proceed?")
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
font: UM.Theme.getFont("default")
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
@ -80,7 +86,6 @@ UM.Dialog
|
||||
id: cancelButton
|
||||
text: catalog.i18nc("@action:button", "Cancel");
|
||||
anchors.right: importAllAsModelsButton.left
|
||||
anchors.rightMargin: UM.Theme.getSize("default_margin").width
|
||||
onClicked:
|
||||
{
|
||||
// cancel
|
||||
|
@ -43,7 +43,7 @@ UM.ManagementPage
|
||||
{
|
||||
text: catalog.i18nc("@action:button", "Add");
|
||||
iconName: "list-add";
|
||||
onClicked: Printer.requestAddPrinter()
|
||||
onClicked: CuraApplication.requestAddPrinter()
|
||||
},
|
||||
Button
|
||||
{
|
||||
@ -216,8 +216,8 @@ UM.ManagementPage
|
||||
|
||||
Component.onCompleted:
|
||||
{
|
||||
for (var component in Printer.additionalComponents["machinesDetailPane"]) {
|
||||
Printer.additionalComponents["machinesDetailPane"][component].parent = additionalComponentsColumn
|
||||
for (var component in CuraApplication.additionalComponents["machinesDetailPane"]) {
|
||||
CuraApplication.additionalComponents["machinesDetailPane"][component].parent = additionalComponentsColumn
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -227,8 +227,8 @@ UM.ManagementPage
|
||||
onAdditionalComponentsChanged:
|
||||
{
|
||||
if(areaId == "machinesDetailPane") {
|
||||
for (var component in Printer.additionalComponents["machinesDetailPane"]) {
|
||||
Printer.additionalComponents["machinesDetailPane"][component].parent = additionalComponentsColumn
|
||||
for (var component in CuraApplication.additionalComponents["machinesDetailPane"]) {
|
||||
CuraApplication.additionalComponents["machinesDetailPane"][component].parent = additionalComponentsColumn
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ UM.ManagementPage
|
||||
{
|
||||
filter:
|
||||
{
|
||||
var result = { "type": "material" }
|
||||
var result = { "type": "material", "approximate_diameter": Math.round(materialDiameterProvider.properties.value) }
|
||||
if(Cura.MachineManager.filterMaterialsByMachine)
|
||||
{
|
||||
result.definition = Cura.MachineManager.activeQualityDefinitionId;
|
||||
@ -327,6 +327,15 @@ UM.ManagementPage
|
||||
id: messageDialog
|
||||
}
|
||||
|
||||
UM.SettingPropertyProvider
|
||||
{
|
||||
id: materialDiameterProvider
|
||||
|
||||
containerStackId: Cura.MachineManager.activeMachineId
|
||||
key: "material_diameter"
|
||||
watchedProperties: [ "value" ]
|
||||
}
|
||||
|
||||
UM.I18nCatalog { id: catalog; name: "cura"; }
|
||||
SystemPalette { id: palette }
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ Column
|
||||
height: childrenRect.height + UM.Theme.getSize("default_margin").height * 2
|
||||
color: UM.Theme.getColor("setting_category")
|
||||
|
||||
Label
|
||||
Text
|
||||
{
|
||||
id: connectedPrinterNameLabel
|
||||
text: connectedPrinter != null ? connectedPrinter.name : catalog.i18nc("@info:status", "No printer connected")
|
||||
@ -37,7 +37,7 @@ Column
|
||||
anchors.top: parent.top
|
||||
anchors.margins: UM.Theme.getSize("default_margin").width
|
||||
}
|
||||
Label
|
||||
Text
|
||||
{
|
||||
id: connectedPrinterAddressLabel
|
||||
text: (connectedPrinter != null && connectedPrinter.address != null) ? connectedPrinter.address : ""
|
||||
@ -47,7 +47,7 @@ Column
|
||||
anchors.right: parent.right
|
||||
anchors.margins: UM.Theme.getSize("default_margin").width
|
||||
}
|
||||
Label
|
||||
Text
|
||||
{
|
||||
text: connectedPrinter != null ? connectedPrinter.connectionText : catalog.i18nc("@info:status", "The printer is not connected.")
|
||||
color: connectedPrinter != null && connectedPrinter.acceptsCommands ? UM.Theme.getColor("setting_control_text") : UM.Theme.getColor("setting_control_disabled_text")
|
||||
@ -85,7 +85,7 @@ Column
|
||||
width: index == machineExtruderCount.properties.value - 1 && index % 2 == 0 ? extrudersGrid.width : extrudersGrid.width / 2 - UM.Theme.getSize("sidebar_lining_thin").width / 2
|
||||
height: UM.Theme.getSize("sidebar_extruder_box").height
|
||||
|
||||
Label //Extruder name.
|
||||
Text //Extruder name.
|
||||
{
|
||||
text: ExtruderManager.getExtruderName(index) != "" ? ExtruderManager.getExtruderName(index) : catalog.i18nc("@label", "Hotend")
|
||||
color: UM.Theme.getColor("text")
|
||||
@ -94,7 +94,7 @@ Column
|
||||
anchors.top: parent.top
|
||||
anchors.margins: UM.Theme.getSize("default_margin").width
|
||||
}
|
||||
Label //Temperature indication.
|
||||
Text //Temperature indication.
|
||||
{
|
||||
id: extruderTemperature
|
||||
text: (connectedPrinter != null && connectedPrinter.hotendIds[index] != null && connectedPrinter.hotendTemperatures[index] != null) ? Math.round(connectedPrinter.hotendTemperatures[index]) + "°C" : ""
|
||||
@ -161,7 +161,7 @@ Column
|
||||
}
|
||||
}
|
||||
}
|
||||
Label //Material name.
|
||||
Text //Material name.
|
||||
{
|
||||
id: materialName
|
||||
text: (connectedPrinter != null && connectedPrinter.materialNames[index] != null && connectedPrinter.materialIds[index] != "") ? connectedPrinter.materialNames[index] : ""
|
||||
@ -193,7 +193,7 @@ Column
|
||||
}
|
||||
}
|
||||
}
|
||||
Label //Variant name.
|
||||
Text //Variant name.
|
||||
{
|
||||
id: variantName
|
||||
text: (connectedPrinter != null && connectedPrinter.hotendIds[index] != null) ? connectedPrinter.hotendIds[index] : ""
|
||||
@ -244,7 +244,7 @@ Column
|
||||
height: machineHeatedBed.properties.value == "True" ? UM.Theme.getSize("sidebar_extruder_box").height : 0
|
||||
visible: machineHeatedBed.properties.value == "True"
|
||||
|
||||
Label //Build plate label.
|
||||
Text //Build plate label.
|
||||
{
|
||||
text: catalog.i18nc("@label", "Build plate")
|
||||
font: UM.Theme.getFont("default")
|
||||
@ -253,7 +253,7 @@ Column
|
||||
anchors.top: parent.top
|
||||
anchors.margins: UM.Theme.getSize("default_margin").width
|
||||
}
|
||||
Label //Target temperature.
|
||||
Text //Target temperature.
|
||||
{
|
||||
id: bedTargetTemperature
|
||||
text: connectedPrinter != null ? connectedPrinter.targetBedTemperature + "°C" : ""
|
||||
@ -285,7 +285,7 @@ Column
|
||||
}
|
||||
}
|
||||
}
|
||||
Label //Current temperature.
|
||||
Text //Current temperature.
|
||||
{
|
||||
id: bedCurrentTemperature
|
||||
text: connectedPrinter != null ? connectedPrinter.bedTemperature + "°C" : ""
|
||||
@ -353,7 +353,7 @@ Column
|
||||
color: UM.Theme.getColor("setting_control_highlight")
|
||||
opacity: preheatTemperatureControl.hovered ? 1.0 : 0
|
||||
}
|
||||
Label //Maximum temperature indication.
|
||||
Text //Maximum temperature indication.
|
||||
{
|
||||
text: (bedTemperature.properties.maximum_value != "None" ? bedTemperature.properties.maximum_value : "") + "°C"
|
||||
color: UM.Theme.getColor("setting_unit")
|
||||
@ -452,7 +452,7 @@ Column
|
||||
}
|
||||
}
|
||||
}
|
||||
Label
|
||||
Text
|
||||
{
|
||||
id: preheatCountdown
|
||||
text: connectedPrinter != null ? connectedPrinter.preheatBedRemainingTime : ""
|
||||
@ -546,7 +546,7 @@ Column
|
||||
}
|
||||
}
|
||||
|
||||
Label
|
||||
Text
|
||||
{
|
||||
id: actualLabel
|
||||
anchors.centerIn: parent
|
||||
@ -662,7 +662,7 @@ Column
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: UM.Theme.getSize("default_margin").width
|
||||
|
||||
Label
|
||||
Text
|
||||
{
|
||||
width: parent.width * 0.4
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
@ -671,7 +671,7 @@ Column
|
||||
font: UM.Theme.getFont("default")
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
Label
|
||||
Text
|
||||
{
|
||||
width: parent.width * 0.6
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
@ -692,7 +692,7 @@ Column
|
||||
width: base.width
|
||||
height: UM.Theme.getSize("section").height
|
||||
|
||||
Label
|
||||
Text
|
||||
{
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: parent.left
|
||||
|
@ -16,7 +16,7 @@ Item {
|
||||
property int backendState: UM.Backend.state;
|
||||
|
||||
property var backend: CuraApplication.getBackend();
|
||||
property bool activity: Printer.platformActivity;
|
||||
property bool activity: CuraApplication.platformActivity;
|
||||
|
||||
property int totalHeight: childrenRect.height + UM.Theme.getSize("default_margin").height
|
||||
property string fileBaseName
|
||||
@ -44,7 +44,7 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
Text {
|
||||
id: statusLabel
|
||||
width: parent.width - 2 * UM.Theme.getSize("default_margin").width
|
||||
anchors.top: parent.top
|
||||
@ -110,8 +110,8 @@ Item {
|
||||
onAdditionalComponentsChanged:
|
||||
{
|
||||
if(areaId == "saveButton") {
|
||||
for (var component in Printer.additionalComponents["saveButton"]) {
|
||||
Printer.additionalComponents["saveButton"][component].parent = additionalComponentsRow
|
||||
for (var component in CuraApplication.additionalComponents["saveButton"]) {
|
||||
CuraApplication.additionalComponents["saveButton"][component].parent = additionalComponentsRow
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -95,13 +95,17 @@ SettingItem
|
||||
value:
|
||||
{
|
||||
// FIXME this needs to go away once 'resolve' is combined with 'value' in our data model.
|
||||
var value;
|
||||
if ((base.resolve != "None") && (base.stackLevel != 0) && (base.stackLevel != 1)) {
|
||||
var value = undefined;
|
||||
if ((base.resolve != "None") && (base.stackLevel != 0) && (base.stackLevel != 1))
|
||||
{
|
||||
// We have a resolve function. Indicates that the setting is not settable per extruder and that
|
||||
// we have to choose between the resolved value (default) and the global value
|
||||
// (if user has explicitly set this).
|
||||
value = base.resolve;
|
||||
} else {
|
||||
}
|
||||
|
||||
if (value == undefined)
|
||||
{
|
||||
value = propertyProvider.properties.value;
|
||||
}
|
||||
|
||||
|
@ -98,9 +98,9 @@ SettingItem
|
||||
|
||||
selectByMouse: true;
|
||||
|
||||
maximumLength: (definition.type == "[int]") ? 20 : 10;
|
||||
maximumLength: (definition.type == "[int]") ? 20 : (definition.type == "str") ? -1 : 10;
|
||||
|
||||
validator: RegExpValidator { regExp: (definition.type == "[int]") ? /^\[?(\s*-?[0-9]{0,9}\s*,)*(\s*-?[0-9]{0,9})\s*\]?$/ : (definition.type == "int") ? /^-?[0-9]{0,10}$/ : /^-?[0-9]{0,9}[.,]?[0-9]{0,10}$/ } // definition.type property from parent loader used to disallow fractional number entry
|
||||
validator: RegExpValidator { regExp: (definition.type == "[int]") ? /^\[?(\s*-?[0-9]{0,9}\s*,)*(\s*-?[0-9]{0,9})\s*\]?$/ : (definition.type == "int") ? /^-?[0-9]{0,10}$/ : (definition.type == "float") ? /^-?[0-9]{0,9}[.,]?[0-9]{0,10}$/ : /^.*$/ } // definition.type property from parent loader used to disallow fractional number entry
|
||||
|
||||
Binding
|
||||
{
|
||||
|
@ -155,14 +155,14 @@ Item
|
||||
containerId: Cura.MachineManager.activeDefinitionId
|
||||
visibilityHandler: UM.SettingPreferenceVisibilityHandler { }
|
||||
exclude: ["machine_settings", "command_line_settings", "infill_mesh", "infill_mesh_order", "support_mesh", "anti_overhang_mesh"] // TODO: infill_mesh settigns are excluded hardcoded, but should be based on the fact that settable_globally, settable_per_meshgroup and settable_per_extruder are false.
|
||||
expanded: Printer.expandedCategories
|
||||
expanded: CuraApplication.expandedCategories
|
||||
onExpandedChanged:
|
||||
{
|
||||
if(!findingSettings)
|
||||
{
|
||||
// Do not change expandedCategories preference while filtering settings
|
||||
// because all categories are expanded while filtering
|
||||
Printer.setExpandedCategories(expanded)
|
||||
CuraApplication.setExpandedCategories(expanded)
|
||||
}
|
||||
}
|
||||
onVisibilityChanged: Cura.SettingInheritanceManager.forceUpdate()
|
||||
@ -299,7 +299,7 @@ Item
|
||||
}
|
||||
}
|
||||
|
||||
UM.I18nCatalog { id: catalog; name: "uranium"; }
|
||||
UM.I18nCatalog { id: catalog; name: "cura"; }
|
||||
|
||||
add: Transition {
|
||||
SequentialAnimation {
|
||||
|
@ -332,7 +332,7 @@ Rectangle
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
Text {
|
||||
id: settingsModeLabel
|
||||
text: !hideSettings ? catalog.i18nc("@label:listbox", "Print Setup") : catalog.i18nc("@label:listbox","Print Setup disabled\nG-code files cannot be modified");
|
||||
anchors.left: parent.left
|
||||
|
@ -128,7 +128,7 @@ Column
|
||||
border.color: UM.Theme.getColor("setting_control_border")
|
||||
}
|
||||
|
||||
Label
|
||||
Text
|
||||
{
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.left: swatch.visible ? swatch.right : parent.left
|
||||
@ -174,7 +174,7 @@ Column
|
||||
rightMargin: UM.Theme.getSize("default_margin").width
|
||||
}
|
||||
|
||||
Label
|
||||
Text
|
||||
{
|
||||
id: variantLabel
|
||||
text:
|
||||
@ -272,7 +272,7 @@ Column
|
||||
}
|
||||
|
||||
|
||||
Label
|
||||
Text
|
||||
{
|
||||
id: globalProfileLabel
|
||||
text: catalog.i18nc("@label","Profile:");
|
||||
|
@ -33,7 +33,7 @@ Item
|
||||
width: base.width * .45 - UM.Theme.getSize("default_margin").width
|
||||
height: childrenRect.height
|
||||
|
||||
Label
|
||||
Text
|
||||
{
|
||||
id: infillLabel
|
||||
//: Infill selection label
|
||||
@ -162,7 +162,7 @@ Item
|
||||
}
|
||||
}
|
||||
}
|
||||
Label
|
||||
Text
|
||||
{
|
||||
id: infillLabel
|
||||
font: UM.Theme.getFont("default")
|
||||
@ -225,14 +225,14 @@ Item
|
||||
anchors.right: parent.right
|
||||
height: childrenRect.height
|
||||
|
||||
Label
|
||||
Text
|
||||
{
|
||||
id: enableSupportLabel
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: UM.Theme.getSize("default_margin").width
|
||||
anchors.verticalCenter: enableSupportCheckBox.verticalCenter
|
||||
width: parent.width * .45 - 3 * UM.Theme.getSize("default_margin").width
|
||||
text: catalog.i18nc("@label", "Enable Support");
|
||||
text: catalog.i18nc("@label", "Generate Support");
|
||||
font: UM.Theme.getFont("default");
|
||||
color: UM.Theme.getColor("text");
|
||||
}
|
||||
@ -263,7 +263,7 @@ Item
|
||||
onEntered:
|
||||
{
|
||||
base.showTooltip(enableSupportCheckBox, Qt.point(-enableSupportCheckBox.x, 0),
|
||||
catalog.i18nc("@label", "Enable support structures. These structures support parts of the model with severe overhangs."));
|
||||
catalog.i18nc("@label", "Generate structures to support parts of the model which have overhangs. Without these structures, such parts would collapse during printing."));
|
||||
}
|
||||
onExited:
|
||||
{
|
||||
@ -272,7 +272,7 @@ Item
|
||||
}
|
||||
}
|
||||
|
||||
Label
|
||||
Text
|
||||
{
|
||||
id: supportExtruderLabel
|
||||
visible: (supportEnabled.properties.value == "True") && (machineExtruderCount.properties.value > 1)
|
||||
@ -372,7 +372,7 @@ Item
|
||||
|
||||
}
|
||||
|
||||
Label
|
||||
Text
|
||||
{
|
||||
id: adhesionHelperLabel
|
||||
anchors.left: parent.left
|
||||
@ -470,7 +470,7 @@ Item
|
||||
width: parent.width
|
||||
height: childrenRect.height
|
||||
|
||||
Label
|
||||
Text
|
||||
{
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: UM.Theme.getSize("default_margin").width
|
||||
|
@ -43,7 +43,7 @@ UM.PointingRectangle {
|
||||
base.opacity = 0;
|
||||
}
|
||||
|
||||
Label {
|
||||
Text {
|
||||
id: label;
|
||||
anchors {
|
||||
top: parent.top;
|
||||
|
@ -13,13 +13,13 @@ UM.Dialog
|
||||
{
|
||||
title: catalog.i18nc("@title:window", "Save Project")
|
||||
|
||||
width: 550
|
||||
minimumWidth: 550
|
||||
width: 550 * Screen.devicePixelRatio
|
||||
minimumWidth: 550 * Screen.devicePixelRatio
|
||||
|
||||
height: 350
|
||||
minimumHeight: 350
|
||||
height: 350 * Screen.devicePixelRatio
|
||||
minimumHeight: 350 * Screen.devicePixelRatio
|
||||
|
||||
property int spacerHeight: 10
|
||||
property int spacerHeight: 10 * Screen.devicePixelRatio
|
||||
|
||||
property bool dontShowAgain: true
|
||||
|
||||
@ -41,15 +41,8 @@ UM.Dialog
|
||||
|
||||
Item
|
||||
{
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
|
||||
anchors.topMargin: 20
|
||||
anchors.bottomMargin: 20
|
||||
anchors.leftMargin:20
|
||||
anchors.rightMargin: 20
|
||||
anchors.fill: parent
|
||||
anchors.margins: 20 * Screen.devicePixelRatio
|
||||
|
||||
UM.SettingDefinitionsModel
|
||||
{
|
||||
@ -63,8 +56,12 @@ UM.Dialog
|
||||
}
|
||||
UM.I18nCatalog
|
||||
{
|
||||
id: catalog;
|
||||
name: "cura";
|
||||
id: catalog
|
||||
name: "cura"
|
||||
}
|
||||
SystemPalette
|
||||
{
|
||||
id: palette
|
||||
}
|
||||
|
||||
Column
|
||||
@ -75,12 +72,12 @@ UM.Dialog
|
||||
{
|
||||
id: titleLabel
|
||||
text: catalog.i18nc("@action:title", "Summary - Cura Project")
|
||||
font.pixelSize: 22
|
||||
font.pointSize: 18
|
||||
}
|
||||
Rectangle
|
||||
{
|
||||
id: separator
|
||||
color: "black"
|
||||
color: palette.text
|
||||
width: parent.width
|
||||
height: 1
|
||||
}
|
||||
@ -229,6 +226,13 @@ UM.Dialog
|
||||
width: parent.width / 3
|
||||
}
|
||||
}
|
||||
|
||||
Item // Spacer
|
||||
{
|
||||
height: spacerHeight
|
||||
width: height
|
||||
}
|
||||
|
||||
CheckBox
|
||||
{
|
||||
id: dontShowAgainCheckbox
|
||||
|
@ -0,0 +1,55 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = Coarse
|
||||
definition = imade3d_jellybox
|
||||
|
||||
[metadata]
|
||||
type = quality
|
||||
material = generic_petg_imade3d_jellybox_0.4_mm
|
||||
weight = -1
|
||||
quality_type = fast
|
||||
|
||||
[values]
|
||||
adhesion_type = skirt
|
||||
bottom_thickness = 0.6
|
||||
coasting_enable = True
|
||||
coasting_speed = 95
|
||||
cool_fan_full_at_height = 1.2
|
||||
cool_fan_speed_max = 60
|
||||
cool_fan_speed_min = 20
|
||||
cool_min_layer_time = 5
|
||||
cool_min_layer_time_fan_speed_max = 10
|
||||
cool_min_speed = 10
|
||||
infill_before_walls = False
|
||||
infill_line_width = 0.6
|
||||
infill_overlap = 15
|
||||
infill_pattern = zigzag
|
||||
infill_sparse_density = 20
|
||||
layer_height = 0.3
|
||||
layer_height_0 = 0.3
|
||||
line_width = 0.4
|
||||
material_bed_temperature = 50
|
||||
material_bed_temperature_layer_0 = 55
|
||||
material_flow = 100
|
||||
meshfix_union_all = False
|
||||
retraction_amount = 1.3
|
||||
retraction_combing = all
|
||||
retraction_hop_enabled = 0.1
|
||||
retraction_min_travel = 1.2
|
||||
retraction_prime_speed = 25
|
||||
retraction_retract_speed = 35
|
||||
retraction_speed = 70
|
||||
skin_no_small_gaps_heuristic = False
|
||||
skirt_brim_minimal_length = 100
|
||||
skirt_brim_speed = 25
|
||||
skirt_line_count = 2
|
||||
speed_layer_0 = 14
|
||||
speed_print = 40
|
||||
speed_slowdown_layers = 1
|
||||
speed_topbottom = 20
|
||||
speed_travel = 120
|
||||
speed_travel_layer_0 = 60
|
||||
speed_wall = 25
|
||||
speed_wall_x = 35
|
||||
top_thickness = =top_bottom_thickness
|
||||
wall_thickness = 0.8
|
@ -0,0 +1,55 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = Coarse
|
||||
definition = imade3d_jellybox
|
||||
|
||||
[metadata]
|
||||
type = quality
|
||||
material = generic_petg_imade3d_jellybox_0.4_mm_2-fans
|
||||
weight = -1
|
||||
quality_type = fast
|
||||
|
||||
[values]
|
||||
adhesion_type = skirt
|
||||
bottom_thickness = 0.6
|
||||
coasting_enable = True
|
||||
coasting_speed = 95
|
||||
cool_fan_full_at_height = 1.2
|
||||
cool_fan_speed_max = 40
|
||||
cool_fan_speed_min = 20
|
||||
cool_min_layer_time = 5
|
||||
cool_min_layer_time_fan_speed_max = 10
|
||||
cool_min_speed = 10
|
||||
infill_before_walls = False
|
||||
infill_line_width = 0.6
|
||||
infill_overlap = 15
|
||||
infill_pattern = zigzag
|
||||
infill_sparse_density = 20
|
||||
layer_height = 0.3
|
||||
layer_height_0 = 0.3
|
||||
line_width = 0.4
|
||||
material_bed_temperature = 50
|
||||
material_bed_temperature_layer_0 = 55
|
||||
material_flow = 100
|
||||
meshfix_union_all = False
|
||||
retraction_amount = 1.3
|
||||
retraction_combing = all
|
||||
retraction_hop_enabled = 0.1
|
||||
retraction_min_travel = 1.2
|
||||
retraction_prime_speed = 25
|
||||
retraction_retract_speed = 35
|
||||
retraction_speed = 70
|
||||
skin_no_small_gaps_heuristic = False
|
||||
skirt_brim_minimal_length = 100
|
||||
skirt_brim_speed = 25
|
||||
skirt_line_count = 2
|
||||
speed_layer_0 = 14
|
||||
speed_print = 40
|
||||
speed_slowdown_layers = 1
|
||||
speed_topbottom = 20
|
||||
speed_travel = 120
|
||||
speed_travel_layer_0 = 60
|
||||
speed_wall = 25
|
||||
speed_wall_x = 35
|
||||
top_thickness = =top_bottom_thickness
|
||||
wall_thickness = 0.8
|
@ -0,0 +1,55 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = Medium
|
||||
definition = imade3d_jellybox
|
||||
|
||||
[metadata]
|
||||
type = quality
|
||||
material = generic_petg_imade3d_jellybox_0.4_mm
|
||||
weight = 0
|
||||
quality_type = normal
|
||||
|
||||
[values]
|
||||
adhesion_type = skirt
|
||||
bottom_thickness = 0.6
|
||||
coasting_enable = True
|
||||
coasting_speed = 95
|
||||
cool_fan_full_at_height = 1.2
|
||||
cool_fan_speed_max = 60
|
||||
cool_fan_speed_min = 20
|
||||
cool_min_layer_time = 7
|
||||
cool_min_layer_time_fan_speed_max = 10
|
||||
cool_min_speed = 10
|
||||
infill_before_walls = False
|
||||
infill_line_width = 0.6
|
||||
infill_overlap = 15
|
||||
infill_pattern = zigzag
|
||||
infill_sparse_density = 20
|
||||
layer_height = 0.2
|
||||
layer_height_0 = 0.3
|
||||
line_width = 0.4
|
||||
material_bed_temperature = 50
|
||||
material_bed_temperature_layer_0 = 55
|
||||
material_flow = 100
|
||||
meshfix_union_all = False
|
||||
retraction_amount = 1.3
|
||||
retraction_combing = all
|
||||
retraction_hop_enabled = 0.1
|
||||
retraction_min_travel = 1.2
|
||||
retraction_prime_speed = 25
|
||||
retraction_retract_speed = 35
|
||||
retraction_speed = 70
|
||||
skin_no_small_gaps_heuristic = False
|
||||
skirt_brim_minimal_length = 100
|
||||
skirt_brim_speed = 25
|
||||
skirt_line_count = 2
|
||||
speed_layer_0 = 14
|
||||
speed_print = 40
|
||||
speed_slowdown_layers = 1
|
||||
speed_topbottom = 20
|
||||
speed_travel = 120
|
||||
speed_travel_layer_0 = 60
|
||||
speed_wall = 25
|
||||
speed_wall_x = 35
|
||||
top_thickness = =top_bottom_thickness
|
||||
wall_thickness = 0.8
|
@ -0,0 +1,55 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = Medium
|
||||
definition = imade3d_jellybox
|
||||
|
||||
[metadata]
|
||||
type = quality
|
||||
material = generic_petg_imade3d_jellybox_0.4_mm_2-fans
|
||||
weight = 0
|
||||
quality_type = normal
|
||||
|
||||
[values]
|
||||
adhesion_type = skirt
|
||||
bottom_thickness = 0.6
|
||||
coasting_enable = True
|
||||
coasting_speed = 95
|
||||
cool_fan_full_at_height = 1.2
|
||||
cool_fan_speed_max = 40
|
||||
cool_fan_speed_min = 20
|
||||
cool_min_layer_time = 5
|
||||
cool_min_layer_time_fan_speed_max = 10
|
||||
cool_min_speed = 10
|
||||
infill_before_walls = False
|
||||
infill_line_width = 0.6
|
||||
infill_overlap = 15
|
||||
infill_pattern = zigzag
|
||||
infill_sparse_density = 20
|
||||
layer_height = 0.2
|
||||
layer_height_0 = 0.3
|
||||
line_width = 0.4
|
||||
material_bed_temperature = 50
|
||||
material_bed_temperature_layer_0 = 55
|
||||
material_flow = 100
|
||||
meshfix_union_all = False
|
||||
retraction_amount = 1.3
|
||||
retraction_combing = all
|
||||
retraction_hop_enabled = 0.1
|
||||
retraction_min_travel = 1.2
|
||||
retraction_prime_speed = 25
|
||||
retraction_retract_speed = 35
|
||||
retraction_speed = 70
|
||||
skin_no_small_gaps_heuristic = False
|
||||
skirt_brim_minimal_length = 100
|
||||
skirt_brim_speed = 25
|
||||
skirt_line_count = 2
|
||||
speed_layer_0 = 14
|
||||
speed_print = 40
|
||||
speed_slowdown_layers = 1
|
||||
speed_topbottom = 20
|
||||
speed_travel = 120
|
||||
speed_travel_layer_0 = 60
|
||||
speed_wall = 25
|
||||
speed_wall_x = 35
|
||||
top_thickness = =top_bottom_thickness
|
||||
wall_thickness = 0.8
|
@ -0,0 +1,53 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = Coarse
|
||||
definition = imade3d_jellybox
|
||||
|
||||
[metadata]
|
||||
type = quality
|
||||
material = generic_pla_imade3d_jellybox_0.4_mm
|
||||
weight = -1
|
||||
quality_type = fast
|
||||
|
||||
[values]
|
||||
adhesion_type = skirt
|
||||
bottom_thickness = 0.6
|
||||
coasting_enable = True
|
||||
coasting_speed = 95
|
||||
cool_fan_full_at_height = 0.65
|
||||
cool_fan_speed_max = 100
|
||||
cool_fan_speed_min = 50
|
||||
cool_min_layer_time = 7
|
||||
cool_min_layer_time_fan_speed_max = 10
|
||||
cool_min_speed = 10
|
||||
infill_before_walls = False
|
||||
infill_line_width = 0.6
|
||||
infill_overlap = 15
|
||||
infill_pattern = zigzag
|
||||
infill_sparse_density = 20
|
||||
layer_height = 0.3
|
||||
layer_height_0 = 0.3
|
||||
line_width = 0.4
|
||||
material_flow = 90
|
||||
meshfix_union_all = False
|
||||
retraction_amount = 1.3
|
||||
retraction_combing = all
|
||||
retraction_hop_enabled = 0.1
|
||||
retraction_min_travel = 1.2
|
||||
retraction_prime_speed = 30
|
||||
retraction_retract_speed = 70
|
||||
retraction_speed = 70
|
||||
skin_no_small_gaps_heuristic = False
|
||||
skirt_brim_minimal_length = 100
|
||||
skirt_brim_speed = 20
|
||||
skirt_line_count = 3
|
||||
speed_layer_0 = 20
|
||||
speed_print = 45
|
||||
speed_slowdown_layers = 1
|
||||
speed_topbottom = 25
|
||||
speed_travel = 120
|
||||
speed_travel_layer_0 = 60
|
||||
speed_wall = 25
|
||||
speed_wall_x = 35
|
||||
top_thickness = 0.8
|
||||
wall_thickness = 0.8
|
@ -0,0 +1,53 @@
|
||||
[general]
|
||||
version = 2
|
||||
name = Coarse
|
||||
definition = imade3d_jellybox
|
||||
|
||||
[metadata]
|
||||
type = quality
|
||||
material = generic_pla_imade3d_jellybox_0.4_mm_2-fans
|
||||
weight = -1
|
||||
quality_type = fast
|
||||
|
||||
[values]
|
||||
adhesion_type = skirt
|
||||
bottom_thickness = 0.6
|
||||
coasting_enable = True
|
||||
coasting_speed = 95
|
||||
cool_fan_full_at_height = 0.65
|
||||
cool_fan_speed_max = 100
|
||||
cool_fan_speed_min = 20
|
||||
cool_min_layer_time = 5
|
||||
cool_min_layer_time_fan_speed_max = 10
|
||||
cool_min_speed = 10
|
||||
infill_before_walls = False
|
||||
infill_line_width = 0.6
|
||||
infill_overlap = 15
|
||||
infill_pattern = zigzag
|
||||
infill_sparse_density = 20
|
||||
layer_height = 0.3
|
||||
layer_height_0 = 0.3
|
||||
line_width = 0.4
|
||||
material_flow = 90
|
||||
meshfix_union_all = False
|
||||
retraction_amount = 1.3
|
||||
retraction_combing = all
|
||||
retraction_hop_enabled = 0.1
|
||||
retraction_min_travel = 1.2
|
||||
retraction_prime_speed = 30
|
||||
retraction_retract_speed = 70
|
||||
retraction_speed = 70
|
||||
skin_no_small_gaps_heuristic = False
|
||||
skirt_brim_minimal_length = 100
|
||||
skirt_brim_speed = 20
|
||||
skirt_line_count = 3
|
||||
speed_layer_0 = 20
|
||||
speed_print = 45
|
||||
speed_slowdown_layers = 1
|
||||
speed_topbottom = 25
|
||||
speed_travel = 120
|
||||
speed_travel_layer_0 = 60
|
||||
speed_wall = 25
|
||||
speed_wall_x = 35
|
||||
top_thickness = 0.8
|
||||
wall_thickness = 0.8
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user