mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-06 22:47:29 -06:00
Merge branch '15.10'
* 15.10: (39 commits) Remove unused import in StartSliceJob conforming to code style fix typo's.. Adjust initial view to be slightly from the side uses a different method to check whether a machine name excists Sets the languageComboBox to the default language Remove per-group settings for now Make sure to send all settings when an object overrides the profile Properly emit writeStarted in RemovableDriveOutputDevice Add xy_offset setting to list of settings that trigger a disallowed area update Properly trigger a reslice when the active instance is changed Wizardpages without hack Only hides the window when there are no more pages Only add layer data node after all processing Also account for "xy_offset" setting for the disallowed areas JSON: workaround for stutter in spiralize vase: set travel speed to printing speed Adds a color for the error-messages Shows an error message when a user tries to add a printer with a name that already excists. JSON: support bottom stair step height defaults changed so that the bottom distance to the model isn't violated too much Try to use Protobuf CPP implementation if it is available ...
This commit is contained in:
commit
751f58fb02
24 changed files with 593 additions and 263 deletions
|
@ -6,6 +6,9 @@ include(GNUInstallDirs)
|
||||||
|
|
||||||
set(URANIUM_SCRIPTS_DIR "${CMAKE_SOURCE_DIR}/../uranium/scripts" CACHE DIRECTORY "The location of the scripts directory of the Uranium repository")
|
set(URANIUM_SCRIPTS_DIR "${CMAKE_SOURCE_DIR}/../uranium/scripts" CACHE DIRECTORY "The location of the scripts directory of the Uranium repository")
|
||||||
|
|
||||||
|
set(CURA_VERSION "master" CACHE STRING "Version name of Cura")
|
||||||
|
configure_file(cura/CuraVersion.py.in CuraVersion.py @ONLY)
|
||||||
|
|
||||||
if(NOT ${URANIUM_SCRIPTS_DIR} STREQUAL "")
|
if(NOT ${URANIUM_SCRIPTS_DIR} STREQUAL "")
|
||||||
# Extract Strings
|
# Extract Strings
|
||||||
add_custom_target(extract-messages ${URANIUM_SCRIPTS_DIR}/extract-messages ${CMAKE_SOURCE_DIR} cura)
|
add_custom_target(extract-messages ${URANIUM_SCRIPTS_DIR}/extract-messages ${CMAKE_SOURCE_DIR} cura)
|
||||||
|
@ -60,10 +63,12 @@ install(DIRECTORY resources DESTINATION ${CMAKE_INSTALL_DATADIR}/cura)
|
||||||
install(DIRECTORY plugins DESTINATION lib/cura)
|
install(DIRECTORY plugins DESTINATION lib/cura)
|
||||||
install(FILES cura_app.py DESTINATION ${CMAKE_INSTALL_BINDIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
install(FILES cura_app.py DESTINATION ${CMAKE_INSTALL_BINDIR} PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||||
if(NOT APPLE AND NOT WIN32)
|
if(NOT APPLE AND NOT WIN32)
|
||||||
install(DIRECTORY cura DESTINATION lib/python${PYTHON_VERSION_MAJOR}/dist-packages)
|
install(DIRECTORY cura DESTINATION lib/python${PYTHON_VERSION_MAJOR}/dist-packages FILES_MATCHING PATTERN *.py)
|
||||||
|
install(FILES ${CMAKE_BINARY_DIR}/CuraVersion.py DESTINATION lib/python${PYTHON_VERSION_MAJOR}/dist-packages/cura)
|
||||||
install(FILES cura.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications)
|
install(FILES cura.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications)
|
||||||
else()
|
else()
|
||||||
install(DIRECTORY cura DESTINATION lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/site-packages)
|
install(DIRECTORY cura DESTINATION lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/site-packages FILES_MATCHING PATTERN *.py)
|
||||||
|
install(FILES ${CMAKE_BINARY_DIR}/CuraVersion.py DESTINATION lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/site-packages/cura)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
include(CPackConfig.cmake)
|
include(CPackConfig.cmake)
|
||||||
|
|
|
@ -34,10 +34,14 @@ class BuildVolume(SceneNode):
|
||||||
|
|
||||||
self.setCalculateBoundingBox(False)
|
self.setCalculateBoundingBox(False)
|
||||||
|
|
||||||
|
self._active_profile = None
|
||||||
self._active_instance = None
|
self._active_instance = None
|
||||||
Application.getInstance().getMachineManager().activeMachineInstanceChanged.connect(self._onActiveInstanceChanged)
|
Application.getInstance().getMachineManager().activeMachineInstanceChanged.connect(self._onActiveInstanceChanged)
|
||||||
self._onActiveInstanceChanged()
|
self._onActiveInstanceChanged()
|
||||||
|
|
||||||
|
Application.getInstance().getMachineManager().activeProfileChanged.connect(self._onActiveProfileChanged)
|
||||||
|
self._onActiveProfileChanged()
|
||||||
|
|
||||||
def setWidth(self, width):
|
def setWidth(self, width):
|
||||||
if width: self._width = width
|
if width: self._width = width
|
||||||
|
|
||||||
|
@ -72,7 +76,7 @@ class BuildVolume(SceneNode):
|
||||||
renderer.queueNode(self, material = self._material, mode = Renderer.RenderLines)
|
renderer.queueNode(self, material = self._material, mode = Renderer.RenderLines)
|
||||||
renderer.queueNode(self, mesh = self._grid_mesh, material = self._grid_material, force_single_sided = True)
|
renderer.queueNode(self, mesh = self._grid_mesh, material = self._grid_material, force_single_sided = True)
|
||||||
if self._disallowed_area_mesh:
|
if self._disallowed_area_mesh:
|
||||||
renderer.queueNode(self, mesh = self._disallowed_area_mesh, material = self._material)
|
renderer.queueNode(self, mesh = self._disallowed_area_mesh, material = self._material, transparent = True)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def rebuild(self):
|
def rebuild(self):
|
||||||
|
@ -117,18 +121,20 @@ class BuildVolume(SceneNode):
|
||||||
v = self._grid_mesh.getVertex(n)
|
v = self._grid_mesh.getVertex(n)
|
||||||
self._grid_mesh.setVertexUVCoordinates(n, v[0], v[2])
|
self._grid_mesh.setVertexUVCoordinates(n, v[0], v[2])
|
||||||
|
|
||||||
|
disallowed_area_height = 0.2
|
||||||
disallowed_area_size = 0
|
disallowed_area_size = 0
|
||||||
if self._disallowed_areas:
|
if self._disallowed_areas:
|
||||||
mb = MeshBuilder()
|
mb = MeshBuilder()
|
||||||
|
color = Color(0.0, 0.0, 0.0, 0.15)
|
||||||
for polygon in self._disallowed_areas:
|
for polygon in self._disallowed_areas:
|
||||||
points = polygon.getPoints()
|
points = polygon.getPoints()
|
||||||
mb.addQuad(
|
first = Vector(self._clamp(points[0][0], minW, maxW), disallowed_area_height, self._clamp(points[0][1], minD, maxD))
|
||||||
Vector(points[0, 0], 0.1, points[0, 1]),
|
previous_point = Vector(self._clamp(points[0][0], minW, maxW), disallowed_area_height, self._clamp(points[0][1], minD, maxD))
|
||||||
Vector(points[1, 0], 0.1, points[1, 1]),
|
for point in points:
|
||||||
Vector(points[2, 0], 0.1, points[2, 1]),
|
new_point = Vector(self._clamp(point[0], minW, maxW), disallowed_area_height, self._clamp(point[1], minD, maxD))
|
||||||
Vector(points[3, 0], 0.1, points[3, 1]),
|
mb.addFace(first, previous_point, new_point, color = color)
|
||||||
color = Color(174, 174, 174, 255)
|
previous_point = new_point
|
||||||
)
|
|
||||||
# Find the largest disallowed area to exclude it from the maximum scale bounds
|
# Find the largest disallowed area to exclude it from the maximum scale bounds
|
||||||
size = abs(numpy.max(points[:, 1]) - numpy.min(points[:, 1]))
|
size = abs(numpy.max(points[:, 1]) - numpy.min(points[:, 1]))
|
||||||
disallowed_area_size = max(size, disallowed_area_size)
|
disallowed_area_size = max(size, disallowed_area_size)
|
||||||
|
@ -141,16 +147,9 @@ class BuildVolume(SceneNode):
|
||||||
|
|
||||||
skirt_size = 0.0
|
skirt_size = 0.0
|
||||||
|
|
||||||
#profile = Application.getInstance().getMachineManager().getActiveProfile()
|
profile = Application.getInstance().getMachineManager().getActiveProfile()
|
||||||
#if profile:
|
if profile:
|
||||||
#if profile.getSettingValue("adhesion_type") == "skirt":
|
skirt_size = self._getSkirtSize(profile)
|
||||||
#skirt_size = profile.getSettingValue("skirt_line_count") * profile.getSettingValue("skirt_line_width") + profile.getSettingValue("skirt_gap")
|
|
||||||
#elif profile.getSettingValue("adhesion_type") == "brim":
|
|
||||||
#skirt_size = profile.getSettingValue("brim_line_count") * profile.getSettingValue("skirt_line_width")
|
|
||||||
#else:
|
|
||||||
#skirt_size = profile.getSettingValue("skirt_line_width")
|
|
||||||
|
|
||||||
#skirt_size += profile.getSettingValue("skirt_line_width")
|
|
||||||
|
|
||||||
scale_to_max_bounds = AxisAlignedBox(
|
scale_to_max_bounds = AxisAlignedBox(
|
||||||
minimum = Vector(minW + skirt_size, minH, minD + skirt_size + disallowed_area_size),
|
minimum = Vector(minW + skirt_size, minH, minD + skirt_size + disallowed_area_size),
|
||||||
|
@ -167,12 +166,108 @@ class BuildVolume(SceneNode):
|
||||||
self._height = self._active_instance.getMachineSettingValue("machine_height")
|
self._height = self._active_instance.getMachineSettingValue("machine_height")
|
||||||
self._depth = self._active_instance.getMachineSettingValue("machine_depth")
|
self._depth = self._active_instance.getMachineSettingValue("machine_depth")
|
||||||
|
|
||||||
|
self._updateDisallowedAreas()
|
||||||
|
|
||||||
|
self.rebuild()
|
||||||
|
|
||||||
|
def _onActiveProfileChanged(self):
|
||||||
|
if self._active_profile:
|
||||||
|
self._active_profile.settingValueChanged.disconnect(self._onSettingValueChanged)
|
||||||
|
|
||||||
|
self._active_profile = Application.getInstance().getMachineManager().getActiveProfile()
|
||||||
|
if self._active_profile:
|
||||||
|
self._active_profile.settingValueChanged.connect(self._onSettingValueChanged)
|
||||||
|
self._updateDisallowedAreas()
|
||||||
|
self.rebuild()
|
||||||
|
|
||||||
|
def _onSettingValueChanged(self, setting):
|
||||||
|
if setting in self._skirt_settings:
|
||||||
|
self._updateDisallowedAreas()
|
||||||
|
self.rebuild()
|
||||||
|
|
||||||
|
def _updateDisallowedAreas(self):
|
||||||
|
if not self._active_instance or not self._active_profile:
|
||||||
|
return
|
||||||
|
|
||||||
disallowed_areas = self._active_instance.getMachineSettingValue("machine_disallowed_areas")
|
disallowed_areas = self._active_instance.getMachineSettingValue("machine_disallowed_areas")
|
||||||
areas = []
|
areas = []
|
||||||
|
|
||||||
|
skirt_size = 0.0
|
||||||
|
if self._active_profile:
|
||||||
|
skirt_size = self._getSkirtSize(self._active_profile)
|
||||||
|
|
||||||
if disallowed_areas:
|
if disallowed_areas:
|
||||||
for area in disallowed_areas:
|
for area in disallowed_areas:
|
||||||
areas.append(Polygon(numpy.array(area, numpy.float32)))
|
poly = Polygon(numpy.array(area, numpy.float32))
|
||||||
|
poly = poly.getMinkowskiHull(Polygon(numpy.array([
|
||||||
|
[-skirt_size, 0],
|
||||||
|
[-skirt_size * 0.707, skirt_size * 0.707],
|
||||||
|
[0, skirt_size],
|
||||||
|
[skirt_size * 0.707, skirt_size * 0.707],
|
||||||
|
[skirt_size, 0],
|
||||||
|
[skirt_size * 0.707, -skirt_size * 0.707],
|
||||||
|
[0, -skirt_size],
|
||||||
|
[-skirt_size * 0.707, -skirt_size * 0.707]
|
||||||
|
], numpy.float32)))
|
||||||
|
|
||||||
|
areas.append(poly)
|
||||||
|
|
||||||
|
if skirt_size > 0:
|
||||||
|
half_machine_width = self._active_instance.getMachineSettingValue("machine_width") / 2
|
||||||
|
half_machine_depth = self._active_instance.getMachineSettingValue("machine_depth") / 2
|
||||||
|
|
||||||
|
areas.append(Polygon(numpy.array([
|
||||||
|
[-half_machine_width, -half_machine_depth],
|
||||||
|
[-half_machine_width, half_machine_depth],
|
||||||
|
[-half_machine_width + skirt_size, half_machine_depth - skirt_size],
|
||||||
|
[-half_machine_width + skirt_size, -half_machine_depth + skirt_size]
|
||||||
|
], numpy.float32)))
|
||||||
|
|
||||||
|
areas.append(Polygon(numpy.array([
|
||||||
|
[half_machine_width, half_machine_depth],
|
||||||
|
[half_machine_width, -half_machine_depth],
|
||||||
|
[half_machine_width - skirt_size, -half_machine_depth + skirt_size],
|
||||||
|
[half_machine_width - skirt_size, half_machine_depth - skirt_size]
|
||||||
|
], numpy.float32)))
|
||||||
|
|
||||||
|
areas.append(Polygon(numpy.array([
|
||||||
|
[-half_machine_width, half_machine_depth],
|
||||||
|
[half_machine_width, half_machine_depth],
|
||||||
|
[half_machine_width - skirt_size, half_machine_depth - skirt_size],
|
||||||
|
[-half_machine_width + skirt_size, half_machine_depth - skirt_size]
|
||||||
|
], numpy.float32)))
|
||||||
|
|
||||||
|
areas.append(Polygon(numpy.array([
|
||||||
|
[half_machine_width, -half_machine_depth],
|
||||||
|
[-half_machine_width, -half_machine_depth],
|
||||||
|
[-half_machine_width + skirt_size, -half_machine_depth + skirt_size],
|
||||||
|
[half_machine_width - skirt_size, -half_machine_depth + skirt_size]
|
||||||
|
], numpy.float32)))
|
||||||
|
|
||||||
self._disallowed_areas = areas
|
self._disallowed_areas = areas
|
||||||
|
|
||||||
self.rebuild()
|
def _getSkirtSize(self, profile):
|
||||||
|
skirt_size = 0.0
|
||||||
|
|
||||||
|
adhesion_type = profile.getSettingValue("adhesion_type")
|
||||||
|
if adhesion_type == "skirt":
|
||||||
|
skirt_distance = profile.getSettingValue("skirt_gap")
|
||||||
|
skirt_line_count = profile.getSettingValue("skirt_line_count")
|
||||||
|
skirt_size = skirt_distance + (skirt_line_count * profile.getSettingValue("skirt_line_width"))
|
||||||
|
elif adhesion_type == "brim":
|
||||||
|
brim_line_count = profile.getSettingValue("brim_line_count")
|
||||||
|
skirt_size = brim_line_count * profile.getSettingValue("skirt_line_width")
|
||||||
|
elif adhesion_type == "raft":
|
||||||
|
skirt_size = profile.getSettingValue("raft_margin")
|
||||||
|
|
||||||
|
if profile.getSettingValue("draft_shield_enabled"):
|
||||||
|
skirt_size += profile.getSettingValue("draft_shield_dist")
|
||||||
|
|
||||||
|
skirt_size += profile.getSettingValue("xy_offset")
|
||||||
|
|
||||||
|
return skirt_size
|
||||||
|
|
||||||
|
def _clamp(self, value, min_value, max_value):
|
||||||
|
return max(min(value, max_value), min_value)
|
||||||
|
|
||||||
|
_skirt_settings = ["adhesion_type", "skirt_gap", "skirt_line_count", "skirt_line_width", "brim_line_count", "raft_margin", "draft_shield_enabled", "draft_shield_dist", "xy_offset"]
|
||||||
|
|
|
@ -31,6 +31,8 @@ class ConvexHullJob(Job):
|
||||||
self._node.callDecoration("setConvexHullJob", None)
|
self._node.callDecoration("setConvexHullJob", None)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
Job.yieldThread()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if not self._node.getMeshData():
|
if not self._node.getMeshData():
|
||||||
return
|
return
|
||||||
|
|
|
@ -58,6 +58,11 @@ import numpy
|
||||||
import copy
|
import copy
|
||||||
numpy.seterr(all="ignore")
|
numpy.seterr(all="ignore")
|
||||||
|
|
||||||
|
try:
|
||||||
|
from cura.CuraVersion import CuraVersion
|
||||||
|
except ImportError:
|
||||||
|
CuraVersion = "master"
|
||||||
|
|
||||||
class CuraApplication(QtApplication):
|
class CuraApplication(QtApplication):
|
||||||
class ResourceTypes:
|
class ResourceTypes:
|
||||||
QmlFiles = Resources.UserType + 1
|
QmlFiles = Resources.UserType + 1
|
||||||
|
@ -69,7 +74,7 @@ class CuraApplication(QtApplication):
|
||||||
if not hasattr(sys, "frozen"):
|
if not hasattr(sys, "frozen"):
|
||||||
Resources.addSearchPath(os.path.join(os.path.abspath(os.path.dirname(__file__)), ".."))
|
Resources.addSearchPath(os.path.join(os.path.abspath(os.path.dirname(__file__)), ".."))
|
||||||
|
|
||||||
super().__init__(name = "cura", version = "master")
|
super().__init__(name = "cura", version = CuraVersion)
|
||||||
|
|
||||||
self.setWindowIcon(QIcon(Resources.getPath(Resources.Images, "cura-icon.png")))
|
self.setWindowIcon(QIcon(Resources.getPath(Resources.Images, "cura-icon.png")))
|
||||||
|
|
||||||
|
@ -136,6 +141,9 @@ class CuraApplication(QtApplication):
|
||||||
parser.add_argument("--debug", dest="debug-mode", action="store_true", default=False, help="Enable detailed crash reports.")
|
parser.add_argument("--debug", dest="debug-mode", action="store_true", default=False, help="Enable detailed crash reports.")
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
if not "PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION" in os.environ or os.environ["PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION"] != "cpp":
|
||||||
|
Logger.log("w", "Using Python implementation of Protobuf, expect bad performance!")
|
||||||
|
|
||||||
self._i18n_catalog = i18nCatalog("cura");
|
self._i18n_catalog = i18nCatalog("cura");
|
||||||
|
|
||||||
i18nCatalog.setTagReplacements({
|
i18nCatalog.setTagReplacements({
|
||||||
|
@ -168,7 +176,7 @@ class CuraApplication(QtApplication):
|
||||||
self._physics = PlatformPhysics.PlatformPhysics(controller, self._volume)
|
self._physics = PlatformPhysics.PlatformPhysics(controller, self._volume)
|
||||||
|
|
||||||
camera = Camera("3d", root)
|
camera = Camera("3d", root)
|
||||||
camera.setPosition(Vector(0, 250, 900))
|
camera.setPosition(Vector(-80, 250, 700))
|
||||||
camera.setPerspective(True)
|
camera.setPerspective(True)
|
||||||
camera.lookAt(Vector(0, 0, 0))
|
camera.lookAt(Vector(0, 0, 0))
|
||||||
controller.getScene().setActiveCamera("3d")
|
controller.getScene().setActiveCamera("3d")
|
||||||
|
|
4
cura/CuraVersion.py.in
Normal file
4
cura/CuraVersion.py.in
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
# Copyright (c) 2015 Ultimaker B.V.
|
||||||
|
# Cura is released under the terms of the AGPLv3 or higher.
|
||||||
|
|
||||||
|
CuraVersion = "@CURA_VERSION@"
|
|
@ -63,6 +63,7 @@ class LayerData(MeshData):
|
||||||
offset = data.build(offset, vertices, colors, indices)
|
offset = data.build(offset, vertices, colors, indices)
|
||||||
self._element_counts[layer] = data.elementCount
|
self._element_counts[layer] = data.elementCount
|
||||||
|
|
||||||
|
self.clear()
|
||||||
self.addVertices(vertices)
|
self.addVertices(vertices)
|
||||||
self.addColors(colors)
|
self.addColors(colors)
|
||||||
self.addIndices(indices.flatten())
|
self.addIndices(indices.flatten())
|
||||||
|
@ -200,18 +201,14 @@ class Polygon():
|
||||||
|
|
||||||
def build(self, offset, vertices, colors, indices):
|
def build(self, offset, vertices, colors, indices):
|
||||||
self._begin = offset
|
self._begin = offset
|
||||||
|
self._end = self._begin + len(self._data) - 1
|
||||||
|
|
||||||
color = self.getColor()
|
color = self.getColor()
|
||||||
color.setValues(color.r * 0.5, color.g * 0.5, color.b * 0.5, color.a)
|
color.setValues(color.r * 0.5, color.g * 0.5, color.b * 0.5, color.a)
|
||||||
|
color = numpy.array([color.r, color.g, color.b, color.a], numpy.float32)
|
||||||
|
|
||||||
for i in range(len(self._data)):
|
vertices[self._begin:self._end + 1, :] = self._data[:, :]
|
||||||
vertices[offset + i, :] = self._data[i, :]
|
colors[self._begin:self._end + 1, :] = color
|
||||||
colors[offset + i, 0] = color.r
|
|
||||||
colors[offset + i, 1] = color.g
|
|
||||||
colors[offset + i, 2] = color.b
|
|
||||||
colors[offset + i, 3] = color.a
|
|
||||||
|
|
||||||
self._end = self._begin + len(self._data) - 1
|
|
||||||
|
|
||||||
for i in range(self._begin, self._end):
|
for i in range(self._begin, self._end):
|
||||||
indices[i, 0] = i
|
indices[i, 0] = i
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
# Cura is released under the terms of the AGPLv3 or higher.
|
# Cura is released under the terms of the AGPLv3 or higher.
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
def exceptHook(type, value, traceback):
|
def exceptHook(type, value, traceback):
|
||||||
import cura.CrashHandler
|
import cura.CrashHandler
|
||||||
|
@ -11,6 +12,13 @@ def exceptHook(type, value, traceback):
|
||||||
|
|
||||||
sys.excepthook = exceptHook
|
sys.excepthook = exceptHook
|
||||||
|
|
||||||
|
try:
|
||||||
|
from google.protobuf.pyext import _message
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
os.environ["PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION"] = "cpp"
|
||||||
|
|
||||||
import cura.CuraApplication
|
import cura.CuraApplication
|
||||||
|
|
||||||
if sys.platform == "win32" and hasattr(sys, "frozen"):
|
if sys.platform == "win32" and hasattr(sys, "frozen"):
|
||||||
|
|
|
@ -10,6 +10,7 @@ from UM.Scene.SceneNode import SceneNode
|
||||||
from UM.Scene.GroupDecorator import GroupDecorator
|
from UM.Scene.GroupDecorator import GroupDecorator
|
||||||
from UM.Math.Quaternion import Quaternion
|
from UM.Math.Quaternion import Quaternion
|
||||||
|
|
||||||
|
from UM.Job import Job
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import struct
|
import struct
|
||||||
|
@ -53,6 +54,7 @@ class ThreeMFReader(MeshReader):
|
||||||
#for vertex in object.mesh.vertices.vertex:
|
#for vertex in object.mesh.vertices.vertex:
|
||||||
for vertex in object.findall(".//3mf:vertex", self._namespaces):
|
for vertex in object.findall(".//3mf:vertex", self._namespaces):
|
||||||
vertex_list.append([vertex.get("x"), vertex.get("y"), vertex.get("z")])
|
vertex_list.append([vertex.get("x"), vertex.get("y"), vertex.get("z")])
|
||||||
|
Job.yieldThread()
|
||||||
|
|
||||||
triangles = object.findall(".//3mf:triangle", self._namespaces)
|
triangles = object.findall(".//3mf:triangle", self._namespaces)
|
||||||
|
|
||||||
|
@ -64,6 +66,8 @@ class ThreeMFReader(MeshReader):
|
||||||
v2 = int(triangle.get("v2"))
|
v2 = int(triangle.get("v2"))
|
||||||
v3 = int(triangle.get("v3"))
|
v3 = int(triangle.get("v3"))
|
||||||
mesh.addFace(vertex_list[v1][0],vertex_list[v1][1],vertex_list[v1][2],vertex_list[v2][0],vertex_list[v2][1],vertex_list[v2][2],vertex_list[v3][0],vertex_list[v3][1],vertex_list[v3][2])
|
mesh.addFace(vertex_list[v1][0],vertex_list[v1][1],vertex_list[v1][2],vertex_list[v2][0],vertex_list[v2][1],vertex_list[v2][2],vertex_list[v3][0],vertex_list[v3][1],vertex_list[v3][2])
|
||||||
|
Job.yieldThread()
|
||||||
|
|
||||||
#TODO: We currently do not check for normals and simply recalculate them.
|
#TODO: We currently do not check for normals and simply recalculate them.
|
||||||
mesh.calculateNormals()
|
mesh.calculateNormals()
|
||||||
node.setMeshData(mesh)
|
node.setMeshData(mesh)
|
||||||
|
@ -116,6 +120,8 @@ class ThreeMFReader(MeshReader):
|
||||||
#node.rotate(rotation)
|
#node.rotate(rotation)
|
||||||
result.addChild(node)
|
result.addChild(node)
|
||||||
|
|
||||||
|
Job.yieldThread()
|
||||||
|
|
||||||
#If there is more then one object, group them.
|
#If there is more then one object, group them.
|
||||||
try:
|
try:
|
||||||
if len(objects) > 1:
|
if len(objects) > 1:
|
||||||
|
|
|
@ -17,6 +17,7 @@ from cura.OneAtATimeIterator import OneAtATimeIterator
|
||||||
from . import Cura_pb2
|
from . import Cura_pb2
|
||||||
from . import ProcessSlicedObjectListJob
|
from . import ProcessSlicedObjectListJob
|
||||||
from . import ProcessGCodeJob
|
from . import ProcessGCodeJob
|
||||||
|
from . import StartSliceJob
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
@ -49,6 +50,7 @@ class CuraEngineBackend(Backend):
|
||||||
self._onActiveViewChanged()
|
self._onActiveViewChanged()
|
||||||
self._stored_layer_data = None
|
self._stored_layer_data = None
|
||||||
|
|
||||||
|
Application.getInstance().getMachineManager().activeMachineInstanceChanged.connect(self._onChanged)
|
||||||
|
|
||||||
self._profile = None
|
self._profile = None
|
||||||
Application.getInstance().getMachineManager().activeProfileChanged.connect(self._onActiveProfileChanged)
|
Application.getInstance().getMachineManager().activeProfileChanged.connect(self._onActiveProfileChanged)
|
||||||
|
@ -67,12 +69,8 @@ class CuraEngineBackend(Backend):
|
||||||
|
|
||||||
self._slicing = False
|
self._slicing = False
|
||||||
self._restart = False
|
self._restart = False
|
||||||
|
|
||||||
self._save_gcode = True
|
|
||||||
self._save_polygons = True
|
|
||||||
self._report_progress = True
|
|
||||||
|
|
||||||
self._enabled = True
|
self._enabled = True
|
||||||
|
self._always_restart = True
|
||||||
|
|
||||||
self._message = None
|
self._message = None
|
||||||
|
|
||||||
|
@ -103,24 +101,12 @@ class CuraEngineBackend(Backend):
|
||||||
## Emitted whne the slicing process is aborted forcefully.
|
## Emitted whne the slicing process is aborted forcefully.
|
||||||
slicingCancelled = Signal()
|
slicingCancelled = Signal()
|
||||||
|
|
||||||
## Perform a slice of the scene with the given set of settings.
|
## Perform a slice of the scene.
|
||||||
#
|
def slice(self):
|
||||||
# \param kwargs Keyword arguments.
|
|
||||||
# Valid values are:
|
|
||||||
# - settings: The settings to use for the slice. The default is the active machine.
|
|
||||||
# - save_gcode: True if the generated gcode should be saved, False if not. True by default.
|
|
||||||
# - save_polygons: True if the generated polygon data should be saved, False if not. True by default.
|
|
||||||
# - force_restart: True if the slicing process should be forcefully restarted if it is already slicing.
|
|
||||||
# If False, this method will do nothing when already slicing. True by default.
|
|
||||||
# - report_progress: True if the slicing progress should be reported, False if not. Default is True.
|
|
||||||
def slice(self, **kwargs):
|
|
||||||
if not self._enabled:
|
if not self._enabled:
|
||||||
return
|
return
|
||||||
|
|
||||||
if self._slicing:
|
if self._slicing:
|
||||||
if not kwargs.get("force_restart", True):
|
|
||||||
return
|
|
||||||
|
|
||||||
self._slicing = False
|
self._slicing = False
|
||||||
self._restart = True
|
self._restart = True
|
||||||
if self._process is not None:
|
if self._process is not None:
|
||||||
|
@ -129,42 +115,16 @@ class CuraEngineBackend(Backend):
|
||||||
self._process.terminate()
|
self._process.terminate()
|
||||||
except: # terminating a process that is already terminating causes an exception, silently ignore this.
|
except: # terminating a process that is already terminating causes an exception, silently ignore this.
|
||||||
pass
|
pass
|
||||||
self.slicingCancelled.emit()
|
|
||||||
return
|
|
||||||
|
|
||||||
Logger.log("d", "Preparing to send slice data to engine.")
|
|
||||||
object_groups = []
|
|
||||||
if self._profile.getSettingValue("print_sequence") == "one_at_a_time":
|
|
||||||
for node in OneAtATimeIterator(self._scene.getRoot()):
|
|
||||||
temp_list = []
|
|
||||||
children = node.getAllChildren()
|
|
||||||
children.append(node)
|
|
||||||
for child_node in children:
|
|
||||||
if type(child_node) is SceneNode and child_node.getMeshData() and child_node.getMeshData().getVertices() is not None:
|
|
||||||
temp_list.append(child_node)
|
|
||||||
object_groups.append(temp_list)
|
|
||||||
else:
|
|
||||||
temp_list = []
|
|
||||||
for node in DepthFirstIterator(self._scene.getRoot()):
|
|
||||||
if type(node) is SceneNode and node.getMeshData() and node.getMeshData().getVertices() is not None:
|
|
||||||
if not getattr(node, "_outside_buildarea", False):
|
|
||||||
temp_list.append(node)
|
|
||||||
if len(temp_list) == 0:
|
|
||||||
self.processingProgress.emit(0.0)
|
|
||||||
return
|
|
||||||
object_groups.append(temp_list)
|
|
||||||
#for node in DepthFirstIterator(self._scene.getRoot()):
|
|
||||||
# if type(node) is SceneNode and node.getMeshData() and node.getMeshData().getVertices() is not None:
|
|
||||||
# if not getattr(node, "_outside_buildarea", False):
|
|
||||||
# objects.append(node)
|
|
||||||
|
|
||||||
if len(object_groups) == 0:
|
|
||||||
if self._message:
|
if self._message:
|
||||||
self._message.hide()
|
self._message.hide()
|
||||||
self._message = None
|
self._message = None
|
||||||
return #No point in slicing an empty build plate
|
|
||||||
|
|
||||||
if kwargs.get("profile", self._profile).hasErrorValue():
|
self.slicingCancelled.emit()
|
||||||
|
return
|
||||||
|
|
||||||
|
if self._profile.hasErrorValue():
|
||||||
Logger.log('w', "Profile has error values. Aborting slicing")
|
Logger.log('w', "Profile has error values. Aborting slicing")
|
||||||
if self._message:
|
if self._message:
|
||||||
self._message.hide()
|
self._message.hide()
|
||||||
|
@ -172,18 +132,7 @@ class CuraEngineBackend(Backend):
|
||||||
self._message = Message(catalog.i18nc("@info:status", "Unable to slice. Please check your setting values for errors."))
|
self._message = Message(catalog.i18nc("@info:status", "Unable to slice. Please check your setting values for errors."))
|
||||||
self._message.show()
|
self._message.show()
|
||||||
return #No slicing if we have error values since those are by definition illegal values.
|
return #No slicing if we have error values since those are by definition illegal values.
|
||||||
# Remove existing layer data (if any)
|
|
||||||
for node in DepthFirstIterator(self._scene.getRoot()):
|
|
||||||
if type(node) is SceneNode and node.getMeshData():
|
|
||||||
if node.callDecoration("getLayerData"):
|
|
||||||
Application.getInstance().getController().getScene().getRoot().removeChild(node)
|
|
||||||
break
|
|
||||||
Application.getInstance().getController().getScene().gcode_list = None
|
|
||||||
self._slicing = True
|
|
||||||
self.slicingStarted.emit()
|
|
||||||
|
|
||||||
self._report_progress = kwargs.get("report_progress", True)
|
|
||||||
if self._report_progress:
|
|
||||||
self.processingProgress.emit(0.0)
|
self.processingProgress.emit(0.0)
|
||||||
if not self._message:
|
if not self._message:
|
||||||
self._message = Message(catalog.i18nc("@info:status", "Slicing..."), 0, False, -1)
|
self._message = Message(catalog.i18nc("@info:status", "Slicing..."), 0, False, -1)
|
||||||
|
@ -191,43 +140,19 @@ class CuraEngineBackend(Backend):
|
||||||
else:
|
else:
|
||||||
self._message.setProgress(-1)
|
self._message.setProgress(-1)
|
||||||
|
|
||||||
self._sendSettings(kwargs.get("profile", self._profile))
|
self._scene.gcode_list = []
|
||||||
|
self._slicing = True
|
||||||
|
|
||||||
self._scene.acquireLock()
|
job = StartSliceJob.StartSliceJob(self._profile, self._socket)
|
||||||
|
job.start()
|
||||||
|
job.finished.connect(self._onStartSliceCompleted)
|
||||||
|
|
||||||
# Set the gcode as an empty list. This will be filled with strings by GCodeLayer messages.
|
def _onStartSliceCompleted(self, job):
|
||||||
# This is done so the gcode can be fragmented in memory and does not need a continues memory space.
|
if job.getError() or job.getResult() != True:
|
||||||
# (AKA. This prevents MemoryErrors)
|
if self._message:
|
||||||
self._save_gcode = kwargs.get("save_gcode", True)
|
self._message.hide()
|
||||||
if self._save_gcode:
|
self._message = None
|
||||||
setattr(self._scene, "gcode_list", [])
|
return
|
||||||
|
|
||||||
self._save_polygons = kwargs.get("save_polygons", True)
|
|
||||||
|
|
||||||
slice_message = Cura_pb2.Slice()
|
|
||||||
|
|
||||||
for group in object_groups:
|
|
||||||
group_message = slice_message.object_lists.add()
|
|
||||||
for object in group:
|
|
||||||
mesh_data = object.getMeshData().getTransformed(object.getWorldTransformation())
|
|
||||||
|
|
||||||
obj = group_message.objects.add()
|
|
||||||
obj.id = id(object)
|
|
||||||
|
|
||||||
verts = numpy.array(mesh_data.getVertices())
|
|
||||||
verts[:,[1,2]] = verts[:,[2,1]]
|
|
||||||
verts[:,1] *= -1
|
|
||||||
obj.vertices = verts.tostring()
|
|
||||||
|
|
||||||
self._handlePerObjectSettings(object, obj)
|
|
||||||
|
|
||||||
# Hack to add per-object settings also to the "MeshGroup" in CuraEngine
|
|
||||||
# We really should come up with a better solution for this.
|
|
||||||
self._handlePerObjectSettings(group[0], group_message)
|
|
||||||
|
|
||||||
self._scene.releaseLock()
|
|
||||||
Logger.log("d", "Sending data to engine for slicing.")
|
|
||||||
self._socket.sendMessage(slice_message)
|
|
||||||
|
|
||||||
def _onSceneChanged(self, source):
|
def _onSceneChanged(self, source):
|
||||||
if type(source) is not SceneNode:
|
if type(source) is not SceneNode:
|
||||||
|
@ -257,7 +182,6 @@ class CuraEngineBackend(Backend):
|
||||||
self._onChanged()
|
self._onChanged()
|
||||||
|
|
||||||
def _onSlicedObjectListMessage(self, message):
|
def _onSlicedObjectListMessage(self, message):
|
||||||
if self._save_polygons:
|
|
||||||
if self._layer_view_active:
|
if self._layer_view_active:
|
||||||
job = ProcessSlicedObjectListJob.ProcessSlicedObjectListJob(message)
|
job = ProcessSlicedObjectListJob.ProcessSlicedObjectListJob(message)
|
||||||
job.start()
|
job.start()
|
||||||
|
@ -265,7 +189,21 @@ class CuraEngineBackend(Backend):
|
||||||
self._stored_layer_data = message
|
self._stored_layer_data = message
|
||||||
|
|
||||||
def _onProgressMessage(self, message):
|
def _onProgressMessage(self, message):
|
||||||
if message.amount >= 0.99:
|
if self._message:
|
||||||
|
self._message.setProgress(round(message.amount * 100))
|
||||||
|
|
||||||
|
self.processingProgress.emit(message.amount)
|
||||||
|
|
||||||
|
def _onGCodeLayerMessage(self, message):
|
||||||
|
self._scene.gcode_list.append(message.data.decode("utf-8", "replace"))
|
||||||
|
|
||||||
|
def _onGCodePrefixMessage(self, message):
|
||||||
|
self._scene.gcode_list.insert(0, message.data.decode("utf-8", "replace"))
|
||||||
|
|
||||||
|
def _onObjectPrintTimeMessage(self, message):
|
||||||
|
self.printDurationMessage.emit(message.time, message.material_amount)
|
||||||
|
self.processingProgress.emit(1.0)
|
||||||
|
|
||||||
self._slicing = False
|
self._slicing = False
|
||||||
|
|
||||||
if self._message:
|
if self._message:
|
||||||
|
@ -273,24 +211,12 @@ class CuraEngineBackend(Backend):
|
||||||
self._message.hide()
|
self._message.hide()
|
||||||
self._message = None
|
self._message = None
|
||||||
|
|
||||||
if self._message:
|
if self._always_restart:
|
||||||
self._message.setProgress(round(message.amount * 100))
|
try:
|
||||||
|
self._process.terminate()
|
||||||
if self._report_progress:
|
self._createSocket()
|
||||||
self.processingProgress.emit(message.amount)
|
except: # terminating a process that is already terminating causes an exception, silently ignore this.
|
||||||
|
pass
|
||||||
def _onGCodeLayerMessage(self, message):
|
|
||||||
if self._save_gcode:
|
|
||||||
job = ProcessGCodeJob.ProcessGCodeLayerJob(message)
|
|
||||||
job.start()
|
|
||||||
|
|
||||||
def _onGCodePrefixMessage(self, message):
|
|
||||||
if self._save_gcode:
|
|
||||||
self._scene.gcode_list.insert(0, message.data.decode("utf-8", "replace"))
|
|
||||||
|
|
||||||
def _onObjectPrintTimeMessage(self, message):
|
|
||||||
self.printDurationMessage.emit(message.time, message.material_amount)
|
|
||||||
self.processingProgress.emit(1.0)
|
|
||||||
|
|
||||||
def _createSocket(self):
|
def _createSocket(self):
|
||||||
super()._createSocket()
|
super()._createSocket()
|
||||||
|
@ -313,15 +239,6 @@ class CuraEngineBackend(Backend):
|
||||||
|
|
||||||
self._change_timer.start()
|
self._change_timer.start()
|
||||||
|
|
||||||
def _sendSettings(self, profile):
|
|
||||||
msg = Cura_pb2.SettingList()
|
|
||||||
for key, value in profile.getAllSettingValues(include_machine = True).items():
|
|
||||||
s = msg.settings.add()
|
|
||||||
s.name = key
|
|
||||||
s.value = str(value).encode("utf-8")
|
|
||||||
|
|
||||||
self._socket.sendMessage(msg)
|
|
||||||
|
|
||||||
def _onBackendConnected(self):
|
def _onBackendConnected(self):
|
||||||
if self._restart:
|
if self._restart:
|
||||||
self._onChanged()
|
self._onChanged()
|
||||||
|
@ -346,22 +263,6 @@ class CuraEngineBackend(Backend):
|
||||||
else:
|
else:
|
||||||
self._layer_view_active = False
|
self._layer_view_active = False
|
||||||
|
|
||||||
def _handlePerObjectSettings(self, node, message):
|
|
||||||
profile = node.callDecoration("getProfile")
|
|
||||||
if profile:
|
|
||||||
for key, value in profile.getChangedSettingValues().items():
|
|
||||||
setting = message.settings.add()
|
|
||||||
setting.name = key
|
|
||||||
setting.value = str(value).encode()
|
|
||||||
|
|
||||||
object_settings = node.callDecoration("getAllSettingValues")
|
|
||||||
if not object_settings:
|
|
||||||
return
|
|
||||||
|
|
||||||
for key, value in object_settings.items():
|
|
||||||
setting = message.settings.add()
|
|
||||||
setting.name = key
|
|
||||||
setting.value = str(value).encode()
|
|
||||||
|
|
||||||
def _onInstanceChanged(self):
|
def _onInstanceChanged(self):
|
||||||
self._slicing = False
|
self._slicing = False
|
||||||
|
|
|
@ -38,10 +38,10 @@ class ProcessSlicedObjectListJob(Job):
|
||||||
for node in DepthFirstIterator(self._scene.getRoot()):
|
for node in DepthFirstIterator(self._scene.getRoot()):
|
||||||
if type(node) is SceneNode and node.getMeshData():
|
if type(node) is SceneNode and node.getMeshData():
|
||||||
if node.callDecoration("getLayerData"):
|
if node.callDecoration("getLayerData"):
|
||||||
#if hasattr(node.getMeshData(), "layerData"):
|
|
||||||
self._scene.getRoot().removeChild(node)
|
self._scene.getRoot().removeChild(node)
|
||||||
else:
|
else:
|
||||||
objectIdMap[id(node)] = node
|
objectIdMap[id(node)] = node
|
||||||
|
Job.yieldThread()
|
||||||
|
|
||||||
settings = Application.getInstance().getMachineManager().getActiveProfile()
|
settings = Application.getInstance().getMachineManager().getActiveProfile()
|
||||||
layerHeight = settings.getSettingValue("layer_height")
|
layerHeight = settings.getSettingValue("layer_height")
|
||||||
|
@ -54,6 +54,12 @@ class ProcessSlicedObjectListJob(Job):
|
||||||
|
|
||||||
mesh = MeshData()
|
mesh = MeshData()
|
||||||
layer_data = LayerData.LayerData()
|
layer_data = LayerData.LayerData()
|
||||||
|
|
||||||
|
layer_count = 0
|
||||||
|
for object in self._message.objects:
|
||||||
|
layer_count += len(object.layers)
|
||||||
|
|
||||||
|
current_layer = 0
|
||||||
for object in self._message.objects:
|
for object in self._message.objects:
|
||||||
try:
|
try:
|
||||||
node = objectIdMap[object.id]
|
node = objectIdMap[object.id]
|
||||||
|
@ -73,15 +79,23 @@ class ProcessSlicedObjectListJob(Job):
|
||||||
|
|
||||||
points[:,2] *= -1
|
points[:,2] *= -1
|
||||||
|
|
||||||
points -= numpy.array(center)
|
points -= center
|
||||||
|
|
||||||
layer_data.addPolygon(layer.id, polygon.type, points, polygon.line_width)
|
layer_data.addPolygon(layer.id, polygon.type, points, polygon.line_width)
|
||||||
|
|
||||||
|
Job.yieldThread()
|
||||||
|
|
||||||
|
current_layer += 1
|
||||||
|
progress = (current_layer / layer_count) * 100
|
||||||
|
# TODO: Rebuild the layer data mesh once the layer has been processed.
|
||||||
|
# This needs some work in LayerData so we can add the new layers instead of recreating the entire mesh.
|
||||||
|
|
||||||
|
if self._progress:
|
||||||
|
self._progress.setProgress(progress)
|
||||||
|
|
||||||
# We are done processing all the layers we got from the engine, now create a mesh out of the data
|
# We are done processing all the layers we got from the engine, now create a mesh out of the data
|
||||||
layer_data.build()
|
layer_data.build()
|
||||||
|
|
||||||
|
|
||||||
#Add layerdata decorator to scene node to indicate that the node has layerdata
|
#Add layerdata decorator to scene node to indicate that the node has layerdata
|
||||||
decorator = LayerDataDecorator.LayerDataDecorator()
|
decorator = LayerDataDecorator.LayerDataDecorator()
|
||||||
decorator.setLayerData(layer_data)
|
decorator.setLayerData(layer_data)
|
||||||
|
@ -90,6 +104,9 @@ class ProcessSlicedObjectListJob(Job):
|
||||||
new_node.setMeshData(mesh)
|
new_node.setMeshData(mesh)
|
||||||
new_node.setParent(self._scene.getRoot())
|
new_node.setParent(self._scene.getRoot())
|
||||||
|
|
||||||
|
if self._progress:
|
||||||
|
self._progress.setProgress(100)
|
||||||
|
|
||||||
view = Application.getInstance().getController().getActiveView()
|
view = Application.getInstance().getController().getActiveView()
|
||||||
if view.getPluginId() == "LayerView":
|
if view.getPluginId() == "LayerView":
|
||||||
view.resetLayerData()
|
view.resetLayerData()
|
||||||
|
|
121
plugins/CuraEngineBackend/StartSliceJob.py
Normal file
121
plugins/CuraEngineBackend/StartSliceJob.py
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
# Copyright (c) 2015 Ultimaker B.V.
|
||||||
|
# Cura is released under the terms of the AGPLv3 or higher.
|
||||||
|
|
||||||
|
import numpy
|
||||||
|
|
||||||
|
from UM.Job import Job
|
||||||
|
from UM.Application import Application
|
||||||
|
from UM.Logger import Logger
|
||||||
|
|
||||||
|
from UM.Scene.SceneNode import SceneNode
|
||||||
|
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
|
||||||
|
|
||||||
|
from cura.OneAtATimeIterator import OneAtATimeIterator
|
||||||
|
|
||||||
|
from . import Cura_pb2
|
||||||
|
|
||||||
|
## Job class that handles sending the current scene data to CuraEngine
|
||||||
|
class StartSliceJob(Job):
|
||||||
|
def __init__(self, profile, socket):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self._scene = Application.getInstance().getController().getScene()
|
||||||
|
self._profile = profile
|
||||||
|
self._socket = socket
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self._scene.acquireLock()
|
||||||
|
|
||||||
|
for node in DepthFirstIterator(self._scene.getRoot()):
|
||||||
|
if node.callDecoration("getLayerData"):
|
||||||
|
node.getParent().removeChild(node)
|
||||||
|
break
|
||||||
|
|
||||||
|
object_groups = []
|
||||||
|
if self._profile.getSettingValue("print_sequence") == "one_at_a_time":
|
||||||
|
for node in OneAtATimeIterator(self._scene.getRoot()):
|
||||||
|
temp_list = []
|
||||||
|
|
||||||
|
if getattr(node, "_outside_buildarea", False):
|
||||||
|
continue
|
||||||
|
|
||||||
|
children = node.getAllChildren()
|
||||||
|
children.append(node)
|
||||||
|
for child_node in children:
|
||||||
|
if type(child_node) is SceneNode and child_node.getMeshData() and child_node.getMeshData().getVertices() is not None:
|
||||||
|
temp_list.append(child_node)
|
||||||
|
|
||||||
|
if temp_list:
|
||||||
|
object_groups.append(temp_list)
|
||||||
|
Job.yieldThread()
|
||||||
|
else:
|
||||||
|
temp_list = []
|
||||||
|
for node in DepthFirstIterator(self._scene.getRoot()):
|
||||||
|
if type(node) is SceneNode and node.getMeshData() and node.getMeshData().getVertices() is not None:
|
||||||
|
if not getattr(node, "_outside_buildarea", False):
|
||||||
|
temp_list.append(node)
|
||||||
|
Job.yieldThread()
|
||||||
|
|
||||||
|
if temp_list:
|
||||||
|
object_groups.append(temp_list)
|
||||||
|
|
||||||
|
self._scene.releaseLock()
|
||||||
|
|
||||||
|
if not object_groups:
|
||||||
|
return
|
||||||
|
|
||||||
|
self._sendSettings(self._profile)
|
||||||
|
|
||||||
|
slice_message = Cura_pb2.Slice()
|
||||||
|
|
||||||
|
for group in object_groups:
|
||||||
|
group_message = slice_message.object_lists.add()
|
||||||
|
for object in group:
|
||||||
|
mesh_data = object.getMeshData().getTransformed(object.getWorldTransformation())
|
||||||
|
|
||||||
|
obj = group_message.objects.add()
|
||||||
|
obj.id = id(object)
|
||||||
|
|
||||||
|
verts = numpy.array(mesh_data.getVertices())
|
||||||
|
verts[:,[1,2]] = verts[:,[2,1]]
|
||||||
|
verts[:,1] *= -1
|
||||||
|
obj.vertices = verts.tostring()
|
||||||
|
|
||||||
|
self._handlePerObjectSettings(object, obj)
|
||||||
|
|
||||||
|
Job.yieldThread()
|
||||||
|
|
||||||
|
Logger.log("d", "Sending data to engine for slicing.")
|
||||||
|
self._socket.sendMessage(slice_message)
|
||||||
|
|
||||||
|
self.setResult(True)
|
||||||
|
|
||||||
|
def _sendSettings(self, profile):
|
||||||
|
msg = Cura_pb2.SettingList()
|
||||||
|
for key, value in profile.getAllSettingValues(include_machine = True).items():
|
||||||
|
s = msg.settings.add()
|
||||||
|
s.name = key
|
||||||
|
s.value = str(value).encode("utf-8")
|
||||||
|
|
||||||
|
self._socket.sendMessage(msg)
|
||||||
|
|
||||||
|
def _handlePerObjectSettings(self, node, message):
|
||||||
|
profile = node.callDecoration("getProfile")
|
||||||
|
if profile:
|
||||||
|
for key, value in profile.getAllSettingValues().items():
|
||||||
|
setting = message.settings.add()
|
||||||
|
setting.name = key
|
||||||
|
setting.value = str(value).encode()
|
||||||
|
|
||||||
|
Job.yieldThread()
|
||||||
|
|
||||||
|
object_settings = node.callDecoration("getAllSettingValues")
|
||||||
|
if not object_settings:
|
||||||
|
return
|
||||||
|
|
||||||
|
for key, value in object_settings.items():
|
||||||
|
setting = message.settings.add()
|
||||||
|
setting.name = key
|
||||||
|
setting.value = str(value).encode()
|
||||||
|
|
||||||
|
Job.yieldThread()
|
|
@ -52,6 +52,8 @@ class RemovableDriveOutputDevice(OutputDevice):
|
||||||
message = Message(catalog.i18nc("@info:progress", "Saving to Removable Drive <filename>{0}</filename>").format(self.getName()), 0, False, -1)
|
message = Message(catalog.i18nc("@info:progress", "Saving to Removable Drive <filename>{0}</filename>").format(self.getName()), 0, False, -1)
|
||||||
message.show()
|
message.show()
|
||||||
|
|
||||||
|
self.writeStarted.emit(self)
|
||||||
|
|
||||||
job._message = message
|
job._message = message
|
||||||
job.start()
|
job.start()
|
||||||
except PermissionError as e:
|
except PermissionError as e:
|
||||||
|
|
|
@ -45,7 +45,7 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
|
||||||
self._connect_thread.daemon = True
|
self._connect_thread.daemon = True
|
||||||
|
|
||||||
self._end_stop_thread = threading.Thread(target = self._pollEndStop)
|
self._end_stop_thread = threading.Thread(target = self._pollEndStop)
|
||||||
self._end_stop_thread.deamon = True
|
self._end_stop_thread.daemon = True
|
||||||
self._poll_endstop = -1
|
self._poll_endstop = -1
|
||||||
|
|
||||||
# Printer is connected
|
# Printer is connected
|
||||||
|
@ -65,6 +65,7 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
|
||||||
|
|
||||||
self._update_firmware_thread = threading.Thread(target= self._updateFirmware)
|
self._update_firmware_thread = threading.Thread(target= self._updateFirmware)
|
||||||
self._update_firmware_thread.daemon = True
|
self._update_firmware_thread.daemon = True
|
||||||
|
self.firmwareUpdateComplete.connect(self._onFirmwareUpdateComplete)
|
||||||
|
|
||||||
self._heatup_wait_start_time = time.time()
|
self._heatup_wait_start_time = time.time()
|
||||||
|
|
||||||
|
@ -197,6 +198,8 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
|
||||||
|
|
||||||
## Private fuction (threaded) that actually uploads the firmware.
|
## Private fuction (threaded) that actually uploads the firmware.
|
||||||
def _updateFirmware(self):
|
def _updateFirmware(self):
|
||||||
|
self.setProgress(0, 100)
|
||||||
|
|
||||||
if self._is_connecting or self._is_connected:
|
if self._is_connecting or self._is_connected:
|
||||||
self.close()
|
self.close()
|
||||||
hex_file = intelHex.readHex(self._firmware_file_name)
|
hex_file = intelHex.readHex(self._firmware_file_name)
|
||||||
|
@ -207,7 +210,11 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
|
||||||
|
|
||||||
programmer = stk500v2.Stk500v2()
|
programmer = stk500v2.Stk500v2()
|
||||||
programmer.progressCallback = self.setProgress
|
programmer.progressCallback = self.setProgress
|
||||||
|
|
||||||
|
try:
|
||||||
programmer.connect(self._serial_port)
|
programmer.connect(self._serial_port)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
time.sleep(1) # Give programmer some time to connect. Might need more in some cases, but this worked in all tested cases.
|
time.sleep(1) # Give programmer some time to connect. Might need more in some cases, but this worked in all tested cases.
|
||||||
|
|
||||||
|
@ -336,8 +343,8 @@ class PrinterConnection(OutputDevice, QObject, SignalEmitter):
|
||||||
self._connect_thread = threading.Thread(target=self._connect)
|
self._connect_thread = threading.Thread(target=self._connect)
|
||||||
self._connect_thread.daemon = True
|
self._connect_thread.daemon = True
|
||||||
|
|
||||||
if self._serial is not None:
|
|
||||||
self.setIsConnected(False)
|
self.setIsConnected(False)
|
||||||
|
if self._serial is not None:
|
||||||
try:
|
try:
|
||||||
self._listen_thread.join()
|
self._listen_thread.join()
|
||||||
except:
|
except:
|
||||||
|
|
|
@ -11,6 +11,7 @@ from UM.Logger import Logger
|
||||||
from UM.PluginRegistry import PluginRegistry
|
from UM.PluginRegistry import PluginRegistry
|
||||||
from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin
|
from UM.OutputDevice.OutputDevicePlugin import OutputDevicePlugin
|
||||||
from UM.Qt.ListModel import ListModel
|
from UM.Qt.ListModel import ListModel
|
||||||
|
from UM.Message import Message
|
||||||
|
|
||||||
from cura.CuraApplication import CuraApplication
|
from cura.CuraApplication import CuraApplication
|
||||||
|
|
||||||
|
@ -95,6 +96,10 @@ class USBPrinterManager(QObject, SignalEmitter, OutputDevicePlugin, Extension):
|
||||||
|
|
||||||
@pyqtSlot()
|
@pyqtSlot()
|
||||||
def updateAllFirmware(self):
|
def updateAllFirmware(self):
|
||||||
|
if not self._printer_connections:
|
||||||
|
Message("Cannot update firmware, there were no connected printers found.").show()
|
||||||
|
return
|
||||||
|
|
||||||
self.spawnFirmwareInterface("")
|
self.spawnFirmwareInterface("")
|
||||||
for printer_connection in self._printer_connections:
|
for printer_connection in self._printer_connections:
|
||||||
try:
|
try:
|
||||||
|
@ -159,6 +164,16 @@ class USBPrinterManager(QObject, SignalEmitter, OutputDevicePlugin, Extension):
|
||||||
continue
|
continue
|
||||||
self._serial_port_list = list(serial_ports)
|
self._serial_port_list = list(serial_ports)
|
||||||
|
|
||||||
|
connections_to_remove = []
|
||||||
|
for port, connection in self._printer_connections.items():
|
||||||
|
if port not in self._serial_port_list:
|
||||||
|
connection.close()
|
||||||
|
connections_to_remove.append(port)
|
||||||
|
|
||||||
|
for port in connections_to_remove:
|
||||||
|
del self._printer_connections[port]
|
||||||
|
|
||||||
|
|
||||||
## Because the model needs to be created in the same thread as the QMLEngine, we use a signal.
|
## Because the model needs to be created in the same thread as the QMLEngine, we use a signal.
|
||||||
def addConnection(self, serial_port):
|
def addConnection(self, serial_port):
|
||||||
connection = PrinterConnection.PrinterConnection(serial_port)
|
connection = PrinterConnection.PrinterConnection(serial_port)
|
||||||
|
|
|
@ -58,7 +58,7 @@ class IspBase():
|
||||||
raise IspError("Called undefined verifyFlash")
|
raise IspError("Called undefined verifyFlash")
|
||||||
|
|
||||||
|
|
||||||
class IspError(BaseException):
|
class IspError(Exception):
|
||||||
def __init__(self, value):
|
def __init__(self, value):
|
||||||
self.value = value
|
self.value = value
|
||||||
|
|
||||||
|
|
|
@ -140,7 +140,7 @@
|
||||||
"unit": "mm",
|
"unit": "mm",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"default": 0.1,
|
"default": 0.1,
|
||||||
"min_value": "0.0001",
|
"min_value": "0.001",
|
||||||
"min_value_warning": "0.04",
|
"min_value_warning": "0.04",
|
||||||
"max_value_warning": "0.32"
|
"max_value_warning": "0.32"
|
||||||
},
|
},
|
||||||
|
@ -150,7 +150,7 @@
|
||||||
"unit": "mm",
|
"unit": "mm",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"default": 0.3,
|
"default": 0.3,
|
||||||
"min_value": "0.0001",
|
"min_value": "0.001",
|
||||||
"min_value_warning": "0.04",
|
"min_value_warning": "0.04",
|
||||||
"max_value_warning": "0.32",
|
"max_value_warning": "0.32",
|
||||||
"visible": false
|
"visible": false
|
||||||
|
@ -821,7 +821,8 @@
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"min_value": "0.1",
|
"min_value": "0.1",
|
||||||
"max_value_warning": "300",
|
"max_value_warning": "300",
|
||||||
"default": 150
|
"default": 150,
|
||||||
|
"inherit_function": "speed_print if magic_spiralize else 150"
|
||||||
},
|
},
|
||||||
"speed_layer_0": {
|
"speed_layer_0": {
|
||||||
"label": "Bottom Layer Speed",
|
"label": "Bottom Layer Speed",
|
||||||
|
|
|
@ -567,7 +567,7 @@ UM.MainWindow
|
||||||
|
|
||||||
addMachine.onTriggered: addMachineWizard.visible = true;
|
addMachine.onTriggered: addMachineWizard.visible = true;
|
||||||
|
|
||||||
preferences.onTriggered: { preferences.visible = true; }
|
preferences.onTriggered: { preferences.visible = true; preferences.setPage(0); }
|
||||||
configureMachines.onTriggered: { preferences.visible = true; preferences.setPage(3); }
|
configureMachines.onTriggered: { preferences.visible = true; preferences.setPage(3); }
|
||||||
manageProfiles.onTriggered: { preferences.visible = true; preferences.setPage(4); }
|
manageProfiles.onTriggered: { preferences.visible = true; preferences.setPage(4); }
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,18 @@ UM.PreferencesPage
|
||||||
//: General configuration page title
|
//: General configuration page title
|
||||||
title: catalog.i18nc("@title:tab","General");
|
title: catalog.i18nc("@title:tab","General");
|
||||||
|
|
||||||
|
function setDefaultLanguage(languageCode)
|
||||||
|
{
|
||||||
|
//loops trough the languageList and sets the language using the languageCode
|
||||||
|
for(var i = 0; i < languageList.count; i++)
|
||||||
|
{
|
||||||
|
if (languageComboBox.model.get(i).code == languageCode)
|
||||||
|
{
|
||||||
|
languageComboBox.currentIndex = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function reset()
|
function reset()
|
||||||
{
|
{
|
||||||
UM.Preferences.resetPreference("general/language")
|
UM.Preferences.resetPreference("general/language")
|
||||||
|
@ -22,7 +34,8 @@ UM.PreferencesPage
|
||||||
pushFreeCheckbox.checked = boolCheck(UM.Preferences.getValue("physics/automatic_push_free"))
|
pushFreeCheckbox.checked = boolCheck(UM.Preferences.getValue("physics/automatic_push_free"))
|
||||||
sendDataCheckbox.checked = boolCheck(UM.Preferences.getValue("info/send_slice_info"))
|
sendDataCheckbox.checked = boolCheck(UM.Preferences.getValue("info/send_slice_info"))
|
||||||
scaleToFitCheckbox.checked = boolCheck(UM.Preferences.getValue("mesh/scale_to_fit"))
|
scaleToFitCheckbox.checked = boolCheck(UM.Preferences.getValue("mesh/scale_to_fit"))
|
||||||
languageComboBox.currentIndex = 0
|
var defaultLanguage = UM.Preferences.getValue("general/language")
|
||||||
|
setDefaultLanguage(defaultLanguage)
|
||||||
}
|
}
|
||||||
|
|
||||||
GridLayout
|
GridLayout
|
||||||
|
|
|
@ -7,8 +7,6 @@ import QtQuick.Window 2.1
|
||||||
import QtQuick.Controls.Styles 1.1
|
import QtQuick.Controls.Styles 1.1
|
||||||
|
|
||||||
import UM 1.1 as UM
|
import UM 1.1 as UM
|
||||||
import Cura 1.0 as Cura
|
|
||||||
import ".."
|
|
||||||
|
|
||||||
Item
|
Item
|
||||||
{
|
{
|
||||||
|
@ -18,10 +16,60 @@ Item
|
||||||
|
|
||||||
property variant wizard: null;
|
property variant wizard: null;
|
||||||
|
|
||||||
|
property bool visibility: base.wizard.visible
|
||||||
|
onVisibilityChanged:
|
||||||
|
{
|
||||||
|
machineName.text = getMachineName()
|
||||||
|
errorMessage.show = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function editMachineName(word)
|
||||||
|
{
|
||||||
|
//Adds '#2' at the end or increases the number by 1 if the word ends with '#' and 1 or more digits
|
||||||
|
var regEx = /[#][\d]+$///ends with '#' and then 1 or more digit
|
||||||
|
var result = word.match(regEx)
|
||||||
|
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
result = result[0].split('')
|
||||||
|
|
||||||
|
var numberString = ''
|
||||||
|
for (var i = 1; i < result.length; i++){//starting at 1, makes it ignore the '#'
|
||||||
|
numberString += result[i]
|
||||||
|
}
|
||||||
|
var newNumber = Number(numberString) + 1
|
||||||
|
|
||||||
|
var newWord = word.replace(/[\d]+$/, newNumber)//replaces the last digits in the string by the same number + 1
|
||||||
|
return newWord
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return word + ' #2'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMachineName()
|
||||||
|
{
|
||||||
|
var name = machineList.model.getItem(machineList.currentIndex).name
|
||||||
|
|
||||||
|
//if the automatically assigned name is not unique, the editMachineName function keeps editing it untill it is.
|
||||||
|
while (UM.MachineManager.checkInstanceExists(name) != false)
|
||||||
|
{
|
||||||
|
name = editMachineName(name)
|
||||||
|
}
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
Connections
|
Connections
|
||||||
{
|
{
|
||||||
target: base.wizard
|
target: base.wizard
|
||||||
onNextClicked: //You can add functions here that get triggered when the final button is clicked in the wizard-element
|
onNextClicked: //You can add functions here that get triggered when the final button is clicked in the wizard-element
|
||||||
|
{
|
||||||
|
var name = machineName.text
|
||||||
|
if (UM.MachineManager.checkInstanceExists(name) != false)
|
||||||
|
{
|
||||||
|
errorMessage.show = true
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
var old_page_count = base.wizard.getPageCount()
|
var old_page_count = base.wizard.getPageCount()
|
||||||
// Delete old pages (if any)
|
// Delete old pages (if any)
|
||||||
|
@ -31,6 +79,7 @@ Item
|
||||||
}
|
}
|
||||||
saveMachine()
|
saveMachine()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
onBackClicked:
|
onBackClicked:
|
||||||
{
|
{
|
||||||
var old_page_count = base.wizard.getPageCount()
|
var old_page_count = base.wizard.getPageCount()
|
||||||
|
@ -63,7 +112,8 @@ Item
|
||||||
{
|
{
|
||||||
id: machinesHolder
|
id: machinesHolder
|
||||||
|
|
||||||
anchors{
|
anchors
|
||||||
|
{
|
||||||
left: parent.left;
|
left: parent.left;
|
||||||
top: subTitle.bottom;
|
top: subTitle.bottom;
|
||||||
right: parent.right;
|
right: parent.right;
|
||||||
|
@ -110,6 +160,7 @@ Item
|
||||||
onClicked: {
|
onClicked: {
|
||||||
base.activeManufacturer = section;
|
base.activeManufacturer = section;
|
||||||
machineList.currentIndex = machineList.model.find("manufacturer", section)
|
machineList.currentIndex = machineList.model.find("manufacturer", section)
|
||||||
|
machineName.text = getMachineName()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -128,7 +179,10 @@ Item
|
||||||
|
|
||||||
text: model.name
|
text: model.name
|
||||||
|
|
||||||
onClicked: ListView.view.currentIndex = index;
|
onClicked: {
|
||||||
|
ListView.view.currentIndex = index;
|
||||||
|
machineName.text = getMachineName()
|
||||||
|
}
|
||||||
|
|
||||||
Label
|
Label
|
||||||
{
|
{
|
||||||
|
@ -169,11 +223,33 @@ Item
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item
|
|
||||||
|
|
||||||
|
Column
|
||||||
{
|
{
|
||||||
id: machineNameHolder
|
id: machineNameHolder
|
||||||
height: childrenRect.height
|
|
||||||
anchors.bottom: parent.bottom;
|
anchors.bottom: parent.bottom;
|
||||||
|
//height: insertNameLabel.lineHeight * (2 + errorMessage.lineCount)
|
||||||
|
|
||||||
|
Item
|
||||||
|
{
|
||||||
|
height: errorMessage.lineHeight
|
||||||
|
anchors.bottom: insertNameLabel.top
|
||||||
|
anchors.bottomMargin: insertNameLabel.height * errorMessage.lineCount
|
||||||
|
Label
|
||||||
|
{
|
||||||
|
id: errorMessage
|
||||||
|
property bool show: false
|
||||||
|
width: base.width
|
||||||
|
height: errorMessage.show ? errorMessage.lineHeight : 0
|
||||||
|
visible: errorMessage.show
|
||||||
|
text: catalog.i18nc("@label", "This printer name has already been used. Please choose a different printer name.");
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
Behavior on height {NumberAnimation {duration: 75; }}
|
||||||
|
color: UM.Theme.colors.error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Label
|
Label
|
||||||
{
|
{
|
||||||
id: insertNameLabel
|
id: insertNameLabel
|
||||||
|
@ -182,8 +258,7 @@ Item
|
||||||
TextField
|
TextField
|
||||||
{
|
{
|
||||||
id: machineName;
|
id: machineName;
|
||||||
anchors.top: insertNameLabel.bottom
|
text: getMachineName()
|
||||||
text: machineList.model.getItem(machineList.currentIndex).name
|
|
||||||
implicitWidth: UM.Theme.sizes.standard_list_input.width
|
implicitWidth: UM.Theme.sizes.standard_list_input.width
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -218,6 +293,9 @@ Item
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(base.wizard.lastPage == true){
|
||||||
|
base.wizard.visible = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,8 @@ import QtQuick.Layouts 1.1
|
||||||
import QtQuick.Window 2.1
|
import QtQuick.Window 2.1
|
||||||
|
|
||||||
import UM 1.1 as UM
|
import UM 1.1 as UM
|
||||||
|
import Cura 1.0 as Cura
|
||||||
|
import ".."
|
||||||
|
|
||||||
Item
|
Item
|
||||||
{
|
{
|
||||||
|
@ -15,11 +17,22 @@ Item
|
||||||
property bool three_point_leveling: true
|
property bool three_point_leveling: true
|
||||||
property int platform_width: UM.MachineManager.getSettingValue("machine_width")
|
property int platform_width: UM.MachineManager.getSettingValue("machine_width")
|
||||||
property int platform_height: UM.MachineManager.getSettingValue("machine_depth")
|
property int platform_height: UM.MachineManager.getSettingValue("machine_depth")
|
||||||
property bool alreadyTested: base.addOriginalProgress.bedLeveling
|
|
||||||
anchors.fill: parent;
|
anchors.fill: parent;
|
||||||
property variant printer_connection: UM.USBPrinterManager.connectedPrinterList.getItem(0).printer
|
property variant printer_connection: UM.USBPrinterManager.connectedPrinterList.getItem(0).printer
|
||||||
Component.onCompleted: printer_connection.homeHead()
|
Component.onCompleted: printer_connection.homeHead()
|
||||||
UM.I18nCatalog { id: catalog; name:"cura"}
|
UM.I18nCatalog { id: catalog; name:"cura"}
|
||||||
|
property variant wizard: null;
|
||||||
|
|
||||||
|
Connections
|
||||||
|
{
|
||||||
|
target: wizardPage.wizard
|
||||||
|
onNextClicked: //You can add functions here that get triggered when the final button is clicked in the wizard-element
|
||||||
|
{
|
||||||
|
if(wizardPage.wizard.lastPage == true){
|
||||||
|
wizardPage.wizard.visible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Label
|
Label
|
||||||
{
|
{
|
||||||
|
@ -61,7 +74,6 @@ Item
|
||||||
id: bedlevelingButton
|
id: bedlevelingButton
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
enabled: !alreadyTested
|
|
||||||
text: catalog.i18nc("@action:button","Move to Next Position");
|
text: catalog.i18nc("@action:button","Move to Next Position");
|
||||||
onClicked:
|
onClicked:
|
||||||
{
|
{
|
||||||
|
@ -79,7 +91,6 @@ Item
|
||||||
}
|
}
|
||||||
wizardPage.leveling_state++
|
wizardPage.leveling_state++
|
||||||
if (wizardPage.leveling_state >= 3){
|
if (wizardPage.leveling_state >= 3){
|
||||||
base.addOriginalProgress.bedLeveling = true
|
|
||||||
resultText.visible = true
|
resultText.visible = true
|
||||||
skipBedlevelingButton.enabled = false
|
skipBedlevelingButton.enabled = false
|
||||||
bedlevelingButton.enabled = false
|
bedlevelingButton.enabled = false
|
||||||
|
@ -91,7 +102,6 @@ Item
|
||||||
Button
|
Button
|
||||||
{
|
{
|
||||||
id: skipBedlevelingButton
|
id: skipBedlevelingButton
|
||||||
enabled: !alreadyTested
|
|
||||||
anchors.top: parent.width < wizardPage.width ? parent.top : bedlevelingButton.bottom
|
anchors.top: parent.width < wizardPage.width ? parent.top : bedlevelingButton.bottom
|
||||||
anchors.topMargin: parent.width < wizardPage.width ? 0 : UM.Theme.sizes.default_margin.height/2
|
anchors.topMargin: parent.width < wizardPage.width ? 0 : UM.Theme.sizes.default_margin.height/2
|
||||||
anchors.left: parent.width < wizardPage.width ? bedlevelingButton.right : parent.left
|
anchors.left: parent.width < wizardPage.width ? bedlevelingButton.right : parent.left
|
||||||
|
@ -104,13 +114,13 @@ Item
|
||||||
Label
|
Label
|
||||||
{
|
{
|
||||||
id: resultText
|
id: resultText
|
||||||
visible: alreadyTested
|
visible: false
|
||||||
anchors.top: bedlevelingWrapper.bottom
|
anchors.top: bedlevelingWrapper.bottom
|
||||||
anchors.topMargin: UM.Theme.sizes.default_margin.height
|
anchors.topMargin: UM.Theme.sizes.default_margin.height
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
width: parent.width
|
width: parent.width
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
text: catalog.i18nc("@label", "Everythink is in order! You're done with bedeleveling.")
|
text: catalog.i18nc("@label", "Everything is in order! You're done with bedleveling.")
|
||||||
}
|
}
|
||||||
|
|
||||||
function threePointLeveling(width, height)
|
function threePointLeveling(width, height)
|
||||||
|
|
|
@ -17,11 +17,8 @@ Item
|
||||||
|
|
||||||
Component.onDestruction:
|
Component.onDestruction:
|
||||||
{
|
{
|
||||||
base.addOriginalProgress.upgrades[0] = extruderCheckBox.checked
|
|
||||||
base.addOriginalProgress.upgrades[1] = heatedBedCheckBox1.checked
|
|
||||||
base.addOriginalProgress.upgrades[2] = heatedBedCheckBox2.checked
|
|
||||||
if (extruderCheckBox.checked == true){
|
if (extruderCheckBox.checked == true){
|
||||||
UM.MachineManager.setMachineSettingValue("machine_extruder_drive_upgrade", true);
|
UM.MachineManager.setMachineSettingValue("machine_extruder_drive_upgrade", true)
|
||||||
}
|
}
|
||||||
if (heatedBedCheckBox1.checked == true || heatedBedCheckBox2.checked == true){
|
if (heatedBedCheckBox1.checked == true || heatedBedCheckBox2.checked == true){
|
||||||
UM.MachineManager.setMachineSettingValue("machine_heated_bed", true)
|
UM.MachineManager.setMachineSettingValue("machine_heated_bed", true)
|
||||||
|
@ -58,14 +55,14 @@ Item
|
||||||
{
|
{
|
||||||
id: extruderCheckBox
|
id: extruderCheckBox
|
||||||
text: catalog.i18nc("@option:check","Extruder driver ugrades")
|
text: catalog.i18nc("@option:check","Extruder driver ugrades")
|
||||||
checked: base.addOriginalProgress.upgrades[0]
|
checked: true
|
||||||
}
|
}
|
||||||
CheckBox
|
CheckBox
|
||||||
{
|
{
|
||||||
id: heatedBedCheckBox1
|
id: heatedBedCheckBox1
|
||||||
text: catalog.i18nc("@option:check","Heated printer bed (standard kit)")
|
text: catalog.i18nc("@option:check","Heated printer bed")
|
||||||
y: extruderCheckBox.height * 1
|
y: extruderCheckBox.height * 1
|
||||||
checked: base.addOriginalProgress.upgrades[1]
|
checked: false
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (heatedBedCheckBox2.checked == true)
|
if (heatedBedCheckBox2.checked == true)
|
||||||
heatedBedCheckBox2.checked = false
|
heatedBedCheckBox2.checked = false
|
||||||
|
@ -76,7 +73,7 @@ Item
|
||||||
id: heatedBedCheckBox2
|
id: heatedBedCheckBox2
|
||||||
text: catalog.i18nc("@option:check","Heated printer bed (self built)")
|
text: catalog.i18nc("@option:check","Heated printer bed (self built)")
|
||||||
y: extruderCheckBox.height * 2
|
y: extruderCheckBox.height * 2
|
||||||
checked: base.addOriginalProgress.upgrades[2]
|
checked: false
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (heatedBedCheckBox1.checked == true)
|
if (heatedBedCheckBox1.checked == true)
|
||||||
heatedBedCheckBox1.checked = false
|
heatedBedCheckBox1.checked = false
|
||||||
|
|
|
@ -14,35 +14,40 @@ Item
|
||||||
property int leftRow: wizardPage.width*0.40
|
property int leftRow: wizardPage.width*0.40
|
||||||
property int rightRow: wizardPage.width*0.60
|
property int rightRow: wizardPage.width*0.60
|
||||||
anchors.fill: parent;
|
anchors.fill: parent;
|
||||||
property bool alreadyTested: base.addOriginalProgress.checkUp[base.addOriginalProgress.checkUp.length-1]
|
|
||||||
property bool x_min_pressed: false
|
property bool x_min_pressed: false
|
||||||
property bool y_min_pressed: false
|
property bool y_min_pressed: false
|
||||||
property bool z_min_pressed: false
|
property bool z_min_pressed: false
|
||||||
property bool heater_works: false
|
property bool heater_works: false
|
||||||
property int extruder_target_temp: 0
|
property int extruder_target_temp: 0
|
||||||
property int bed_target_temp: 0
|
property int bed_target_temp: 0
|
||||||
|
UM.I18nCatalog { id: catalog; name:"cura"}
|
||||||
|
property var checkupProgress: {
|
||||||
|
"connection": false,
|
||||||
|
"endstopX": wizardPage.x_min_pressed,
|
||||||
|
"endstopY": wizardPage.y_min_pressed,
|
||||||
|
"endstopZ": wizardPage.z_min_pressed,
|
||||||
|
"nozzleTemp": false,
|
||||||
|
"bedTemp": false
|
||||||
|
}
|
||||||
|
|
||||||
property variant printer_connection: {
|
property variant printer_connection: {
|
||||||
if (UM.USBPrinterManager.connectedPrinterList.rowCount() != 0){
|
if (UM.USBPrinterManager.connectedPrinterList.rowCount() != 0){
|
||||||
base.addOriginalProgress.checkUp[0] = true
|
wizardPage.checkupProgress.connection = true
|
||||||
checkTotalCheckUp()
|
|
||||||
return UM.USBPrinterManager.connectedPrinterList.getItem(0).printer
|
return UM.USBPrinterManager.connectedPrinterList.getItem(0).printer
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//property variant printer_connection: UM.USBPrinterManager.connectedPrinterList.getItem(0).printer
|
|
||||||
UM.I18nCatalog { id: catalog; name:"cura"}
|
|
||||||
|
|
||||||
function checkTotalCheckUp(){
|
function checkTotalCheckUp(){
|
||||||
var allDone = true
|
var allDone = true
|
||||||
for (var i = 0; i < (base.addOriginalProgress.checkUp.length - 1); i++){
|
for(var property in checkupProgress){
|
||||||
if (base.addOriginalProgress.checkUp[i] == false){
|
if (checkupProgress[property] == false){
|
||||||
allDone = false
|
allDone = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (allDone == true){
|
if (allDone == true){
|
||||||
base.addOriginalProgress.checkUp[base.addOriginalProgress.checkUp.length] = true
|
|
||||||
skipCheckButton.enabled = false
|
skipCheckButton.enabled = false
|
||||||
resultText.visible = true
|
resultText.visible = true
|
||||||
}
|
}
|
||||||
|
@ -91,7 +96,7 @@ Item
|
||||||
id: startCheckButton
|
id: startCheckButton
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
enabled: !alreadyTested
|
//enabled: !alreadyTested
|
||||||
text: catalog.i18nc("@action:button","Start Printer Check");
|
text: catalog.i18nc("@action:button","Start Printer Check");
|
||||||
onClicked: {
|
onClicked: {
|
||||||
checkupContent.visible = true
|
checkupContent.visible = true
|
||||||
|
@ -107,7 +112,7 @@ Item
|
||||||
anchors.topMargin: parent.width < wizardPage.width ? 0 : UM.Theme.sizes.default_margin.height/2
|
anchors.topMargin: parent.width < wizardPage.width ? 0 : UM.Theme.sizes.default_margin.height/2
|
||||||
anchors.left: parent.width < wizardPage.width ? startCheckButton.right : parent.left
|
anchors.left: parent.width < wizardPage.width ? startCheckButton.right : parent.left
|
||||||
anchors.leftMargin: parent.width < wizardPage.width ? UM.Theme.sizes.default_margin.width : 0
|
anchors.leftMargin: parent.width < wizardPage.width ? UM.Theme.sizes.default_margin.width : 0
|
||||||
enabled: !alreadyTested
|
//enabled: !alreadyTested
|
||||||
text: catalog.i18nc("@action:button","Skip Printer Check");
|
text: catalog.i18nc("@action:button","Skip Printer Check");
|
||||||
onClicked: {
|
onClicked: {
|
||||||
base.currentPage += 1
|
base.currentPage += 1
|
||||||
|
@ -119,7 +124,7 @@ Item
|
||||||
id: checkupContent
|
id: checkupContent
|
||||||
anchors.top: startStopButtons.bottom
|
anchors.top: startStopButtons.bottom
|
||||||
anchors.topMargin: UM.Theme.sizes.default_margin.height
|
anchors.topMargin: UM.Theme.sizes.default_margin.height
|
||||||
visible: alreadyTested
|
visible: false
|
||||||
//////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////
|
||||||
Label
|
Label
|
||||||
{
|
{
|
||||||
|
@ -156,7 +161,7 @@ Item
|
||||||
anchors.left: endstopXLabel.right
|
anchors.left: endstopXLabel.right
|
||||||
anchors.top: connectionLabel.bottom
|
anchors.top: connectionLabel.bottom
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
text: x_min_pressed || base.addOriginalProgress.checkUp[1] ? catalog.i18nc("@info:status","Works") : catalog.i18nc("@info:status","Not checked")
|
text: x_min_pressed ? catalog.i18nc("@info:status","Works") : catalog.i18nc("@info:status","Not checked")
|
||||||
}
|
}
|
||||||
//////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////
|
||||||
Label
|
Label
|
||||||
|
@ -175,7 +180,7 @@ Item
|
||||||
anchors.left: endstopYLabel.right
|
anchors.left: endstopYLabel.right
|
||||||
anchors.top: endstopXLabel.bottom
|
anchors.top: endstopXLabel.bottom
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
text: y_min_pressed || base.addOriginalProgress.checkUp[2] ? catalog.i18nc("@info:status","Works") : catalog.i18nc("@info:status","Not checked")
|
text: y_min_pressed ? catalog.i18nc("@info:status","Works") : catalog.i18nc("@info:status","Not checked")
|
||||||
}
|
}
|
||||||
/////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////
|
||||||
Label
|
Label
|
||||||
|
@ -194,7 +199,7 @@ Item
|
||||||
anchors.left: endstopZLabel.right
|
anchors.left: endstopZLabel.right
|
||||||
anchors.top: endstopYLabel.bottom
|
anchors.top: endstopYLabel.bottom
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
text: z_min_pressed || base.addOriginalProgress.checkUp[3] ? catalog.i18nc("@info:status","Works") : catalog.i18nc("@info:status","Not checked")
|
text: z_min_pressed ? catalog.i18nc("@info:status","Works") : catalog.i18nc("@info:status","Not checked")
|
||||||
}
|
}
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
Label
|
Label
|
||||||
|
@ -233,10 +238,6 @@ Item
|
||||||
{
|
{
|
||||||
if(printer_connection != null)
|
if(printer_connection != null)
|
||||||
{
|
{
|
||||||
if (alreadyTested){
|
|
||||||
nozzleTempStatus.text = catalog.i18nc("@info:status","Works")
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
nozzleTempStatus.text = catalog.i18nc("@info:progress","Checking")
|
nozzleTempStatus.text = catalog.i18nc("@info:progress","Checking")
|
||||||
printer_connection.heatupNozzle(190)
|
printer_connection.heatupNozzle(190)
|
||||||
wizardPage.extruder_target_temp = 190
|
wizardPage.extruder_target_temp = 190
|
||||||
|
@ -244,7 +245,6 @@ Item
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Label
|
Label
|
||||||
{
|
{
|
||||||
id: nozzleTemp
|
id: nozzleTemp
|
||||||
|
@ -294,10 +294,6 @@ Item
|
||||||
{
|
{
|
||||||
if(printer_connection != null)
|
if(printer_connection != null)
|
||||||
{
|
{
|
||||||
if (alreadyTested){
|
|
||||||
bedTempStatus.text = catalog.i18nc("@info:status","Works")
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
bedTempStatus.text = catalog.i18nc("@info:progress","Checking")
|
bedTempStatus.text = catalog.i18nc("@info:progress","Checking")
|
||||||
printer_connection.heatupBed(60)
|
printer_connection.heatupBed(60)
|
||||||
wizardPage.bed_target_temp = 60
|
wizardPage.bed_target_temp = 60
|
||||||
|
@ -305,7 +301,6 @@ Item
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Label
|
Label
|
||||||
{
|
{
|
||||||
id: bedTemp
|
id: bedTemp
|
||||||
|
@ -320,7 +315,7 @@ Item
|
||||||
Label
|
Label
|
||||||
{
|
{
|
||||||
id: resultText
|
id: resultText
|
||||||
visible: base.addOriginalProgress.checkUp[base.addOriginalProgress.checkUp.length-1]
|
visible: false
|
||||||
anchors.top: bedTemp.bottom
|
anchors.top: bedTemp.bottom
|
||||||
anchors.topMargin: UM.Theme.sizes.default_margin.height
|
anchors.topMargin: UM.Theme.sizes.default_margin.height
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
|
@ -338,19 +333,16 @@ Item
|
||||||
{
|
{
|
||||||
if(key == "x_min")
|
if(key == "x_min")
|
||||||
{
|
{
|
||||||
base.addOriginalProgress.checkUp[1] = true
|
|
||||||
x_min_pressed = true
|
x_min_pressed = true
|
||||||
checkTotalCheckUp()
|
checkTotalCheckUp()
|
||||||
}
|
}
|
||||||
if(key == "y_min")
|
if(key == "y_min")
|
||||||
{
|
{
|
||||||
base.addOriginalProgress.checkUp[2] = true
|
|
||||||
y_min_pressed = true
|
y_min_pressed = true
|
||||||
checkTotalCheckUp()
|
checkTotalCheckUp()
|
||||||
}
|
}
|
||||||
if(key == "z_min")
|
if(key == "z_min")
|
||||||
{
|
{
|
||||||
base.addOriginalProgress.checkUp[3] = true
|
|
||||||
z_min_pressed = true
|
z_min_pressed = true
|
||||||
checkTotalCheckUp()
|
checkTotalCheckUp()
|
||||||
}
|
}
|
||||||
|
@ -363,7 +355,7 @@ Item
|
||||||
if(printer_connection != null)
|
if(printer_connection != null)
|
||||||
{
|
{
|
||||||
nozzleTempStatus.text = catalog.i18nc("@info:status","Works")
|
nozzleTempStatus.text = catalog.i18nc("@info:status","Works")
|
||||||
base.addOriginalProgress.checkUp[4] = true
|
wizardPage.checkupProgress.nozzleTemp = true
|
||||||
checkTotalCheckUp()
|
checkTotalCheckUp()
|
||||||
printer_connection.heatupNozzle(0)
|
printer_connection.heatupNozzle(0)
|
||||||
}
|
}
|
||||||
|
@ -374,7 +366,7 @@ Item
|
||||||
if(printer_connection.bedTemperature > wizardPage.bed_target_temp - 5 && printer_connection.bedTemperature < wizardPage.bed_target_temp + 5)
|
if(printer_connection.bedTemperature > wizardPage.bed_target_temp - 5 && printer_connection.bedTemperature < wizardPage.bed_target_temp + 5)
|
||||||
{
|
{
|
||||||
bedTempStatus.text = catalog.i18nc("@info:status","Works")
|
bedTempStatus.text = catalog.i18nc("@info:status","Works")
|
||||||
base.addOriginalProgress.checkUp[5] = true
|
wizardPage.checkupProgress.bedTemp = true
|
||||||
checkTotalCheckUp()
|
checkTotalCheckUp()
|
||||||
printer_connection.heatupBed(0)
|
printer_connection.heatupBed(0)
|
||||||
}
|
}
|
||||||
|
|
50
resources/themes/cura/icons/check.svg
Normal file
50
resources/themes/cura/icons/check.svg
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
version="1.1"
|
||||||
|
id="Capa_1"
|
||||||
|
x="0px"
|
||||||
|
y="0px"
|
||||||
|
width="415.582px"
|
||||||
|
height="415.582px"
|
||||||
|
viewBox="0 0 415.582 415.582"
|
||||||
|
style="enable-background:new 0 0 415.582 415.582;"
|
||||||
|
xml:space="preserve"
|
||||||
|
inkscape:version="0.91 r13725"
|
||||||
|
sodipodi:docname="check.svg"><metadata
|
||||||
|
id="metadata11"><rdf:RDF><cc:Work
|
||||||
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||||
|
id="defs9" /><sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
inkscape:window-height="1134"
|
||||||
|
id="namedview7"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="1.61"
|
||||||
|
inkscape:cx="211.31288"
|
||||||
|
inkscape:cy="137.35337"
|
||||||
|
inkscape:window-x="1440"
|
||||||
|
inkscape:window-y="27"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="Capa_1" /><g
|
||||||
|
id="g3"><path
|
||||||
|
d="m 411.47,96.426 -34.319,-34.32 c -5.48192,-5.482079 -14.34421,-5.455083 -19.853,0 L 152.348,265.058 56.282,174.994 c -5.48,-5.482 -14.37,-5.482 -19.851,0 l -32.319,32.32 c -5.482,5.481 -5.482,14.37 0,19.852 l 138.311,138.31 c 2.741,2.742 6.334,4.112 9.926,4.112 3.593,0 7.186,-1.37 9.926,-4.112 L 411.47,116.277 c 2.633,-2.632 4.111,-6.203 4.111,-9.925 10e-4,-3.724 -1.47804,-7.29296 -4.111,-9.926 z"
|
||||||
|
id="path5"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="sssccccscscccs" /></g></svg>
|
After Width: | Height: | Size: 2.1 KiB |
|
@ -66,6 +66,7 @@
|
||||||
"text_hover": [35, 35, 35, 255],
|
"text_hover": [35, 35, 35, 255],
|
||||||
"text_pressed": [12, 169, 227, 255],
|
"text_pressed": [12, 169, 227, 255],
|
||||||
|
|
||||||
|
"error": [255, 140, 0, 255],
|
||||||
"sidebar_header_bar": [12, 169, 227, 255],
|
"sidebar_header_bar": [12, 169, 227, 255],
|
||||||
|
|
||||||
"button": [139, 143, 153, 255],
|
"button": [139, 143, 153, 255],
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue