mirror of
https://git.mirrors.martin98.com/https://github.com/Ultimaker/Cura
synced 2025-08-15 11:06:01 +08:00
Merge branch '15.10' of https://github.com/Ultimaker/Cura into 15.10
This commit is contained in:
commit
dc2ca67727
@ -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
|
||||||
|
@ -134,6 +134,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({
|
||||||
|
@ -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
|
||||||
@ -67,12 +68,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
|
||||||
|
|
||||||
@ -97,24 +94,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:
|
||||||
@ -123,41 +108,15 @@ 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()
|
||||||
@ -165,62 +124,27 @@ 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()):
|
self.processingProgress.emit(0.0)
|
||||||
if type(node) is SceneNode and node.getMeshData():
|
if not self._message:
|
||||||
if node.callDecoration("getLayerData"):
|
self._message = Message(catalog.i18nc("@info:status", "Slicing..."), 0, False, -1)
|
||||||
Application.getInstance().getController().getScene().getRoot().removeChild(node)
|
self._message.show()
|
||||||
break
|
else:
|
||||||
Application.getInstance().getController().getScene().gcode_list = None
|
self._message.setProgress(-1)
|
||||||
|
|
||||||
|
self._scene.gcode_list = []
|
||||||
self._slicing = True
|
self._slicing = True
|
||||||
self.slicingStarted.emit()
|
|
||||||
|
|
||||||
self._report_progress = kwargs.get("report_progress", True)
|
job = StartSliceJob.StartSliceJob(self._profile, self._socket)
|
||||||
if self._report_progress:
|
job.start()
|
||||||
self.processingProgress.emit(0.0)
|
job.finished.connect(self._onStartSliceCompleted)
|
||||||
if not self._message:
|
|
||||||
self._message = Message(catalog.i18nc("@info:status", "Slicing..."), 0, False, -1)
|
|
||||||
self._message.show()
|
|
||||||
else:
|
|
||||||
self._message.setProgress(-1)
|
|
||||||
|
|
||||||
self._sendSettings(kwargs.get("profile", self._profile))
|
def _onStartSliceCompleted(self, job):
|
||||||
|
if job.getError() or job.getResult() != True:
|
||||||
self._scene.acquireLock()
|
if self._message:
|
||||||
|
self._message.hide()
|
||||||
# Set the gcode as an empty list. This will be filled with strings by GCodeLayer messages.
|
self._message = None
|
||||||
# This is done so the gcode can be fragmented in memory and does not need a continues memory space.
|
return
|
||||||
# (AKA. This prevents MemoryErrors)
|
|
||||||
self._save_gcode = kwargs.get("save_gcode", True)
|
|
||||||
if self._save_gcode:
|
|
||||||
setattr(self._scene, "gcode_list", [])
|
|
||||||
|
|
||||||
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:
|
||||||
@ -250,41 +174,42 @@ 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()
|
else :
|
||||||
else :
|
self._stored_layer_data = message
|
||||||
self._stored_layer_data = message
|
|
||||||
|
|
||||||
def _onProgressMessage(self, message):
|
def _onProgressMessage(self, message):
|
||||||
if message.amount >= 0.99:
|
|
||||||
self._slicing = False
|
|
||||||
|
|
||||||
if self._message:
|
|
||||||
self._message.setProgress(100)
|
|
||||||
self._message.hide()
|
|
||||||
self._message = None
|
|
||||||
|
|
||||||
if self._message:
|
if self._message:
|
||||||
self._message.setProgress(round(message.amount * 100))
|
self._message.setProgress(round(message.amount * 100))
|
||||||
|
|
||||||
if self._report_progress:
|
self.processingProgress.emit(message.amount)
|
||||||
self.processingProgress.emit(message.amount)
|
|
||||||
|
|
||||||
def _onGCodeLayerMessage(self, message):
|
def _onGCodeLayerMessage(self, message):
|
||||||
if self._save_gcode:
|
self._scene.gcode_list.append(message.data.decode("utf-8", "replace"))
|
||||||
job = ProcessGCodeJob.ProcessGCodeLayerJob(message)
|
|
||||||
job.start()
|
|
||||||
|
|
||||||
def _onGCodePrefixMessage(self, message):
|
def _onGCodePrefixMessage(self, message):
|
||||||
if self._save_gcode:
|
self._scene.gcode_list.insert(0, message.data.decode("utf-8", "replace"))
|
||||||
self._scene.gcode_list.insert(0, message.data.decode("utf-8", "replace"))
|
|
||||||
|
|
||||||
def _onObjectPrintTimeMessage(self, message):
|
def _onObjectPrintTimeMessage(self, message):
|
||||||
self.printDurationMessage.emit(message.time, message.material_amount)
|
self.printDurationMessage.emit(message.time, message.material_amount)
|
||||||
self.processingProgress.emit(1.0)
|
self.processingProgress.emit(1.0)
|
||||||
|
|
||||||
|
self._slicing = False
|
||||||
|
|
||||||
|
if self._message:
|
||||||
|
self._message.setProgress(100)
|
||||||
|
self._message.hide()
|
||||||
|
self._message = None
|
||||||
|
|
||||||
|
if self._always_restart:
|
||||||
|
try:
|
||||||
|
self._process.terminate()
|
||||||
|
self._createSocket()
|
||||||
|
except: # terminating a process that is already terminating causes an exception, silently ignore this.
|
||||||
|
pass
|
||||||
|
|
||||||
def _createSocket(self):
|
def _createSocket(self):
|
||||||
super()._createSocket()
|
super()._createSocket()
|
||||||
|
|
||||||
@ -306,15 +231,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()
|
||||||
@ -338,20 +254,3 @@ class CuraEngineBackend(Backend):
|
|||||||
self._stored_layer_data = None
|
self._stored_layer_data = None
|
||||||
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()
|
|
||||||
|
@ -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())
|
||||||
@ -198,18 +199,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
|
||||||
|
@ -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,20 @@ class ProcessSlicedObjectListJob(Job):
|
|||||||
|
|
||||||
mesh = MeshData()
|
mesh = MeshData()
|
||||||
layer_data = LayerData.LayerData()
|
layer_data = LayerData.LayerData()
|
||||||
|
|
||||||
|
#Add layerdata decorator to scene node to indicate that the node has layerdata
|
||||||
|
decorator = LayerDataDecorator.LayerDataDecorator()
|
||||||
|
decorator.setLayerData(layer_data)
|
||||||
|
new_node.addDecorator(decorator)
|
||||||
|
|
||||||
|
new_node.setMeshData(mesh)
|
||||||
|
new_node.setParent(self._scene.getRoot())
|
||||||
|
|
||||||
|
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,23 +87,26 @@ 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()
|
||||||
|
|
||||||
|
if self._progress:
|
||||||
#Add layerdata decorator to scene node to indicate that the node has layerdata
|
self._progress.setProgress(100)
|
||||||
decorator = LayerDataDecorator.LayerDataDecorator()
|
|
||||||
decorator.setLayerData(layer_data)
|
|
||||||
new_node.addDecorator(decorator)
|
|
||||||
|
|
||||||
new_node.setMeshData(mesh)
|
|
||||||
new_node.setParent(self._scene.getRoot())
|
|
||||||
|
|
||||||
view = Application.getInstance().getController().getActiveView()
|
view = Application.getInstance().getController().getActiveView()
|
||||||
if view.getPluginId() == "LayerView":
|
if view.getPluginId() == "LayerView":
|
||||||
view.resetLayerData()
|
view.resetLayerData()
|
||||||
|
126
plugins/CuraEngineBackend/StartSliceJob.py
Normal file
126
plugins/CuraEngineBackend/StartSliceJob.py
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
# Copyright (c) 2015 Ultimaker B.V.
|
||||||
|
# Cura is released under the terms of the AGPLv3 or higher.
|
||||||
|
|
||||||
|
import time
|
||||||
|
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()
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
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.getChangedSettingValues().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()
|
@ -1100,7 +1100,7 @@
|
|||||||
"unit": "mm",
|
"unit": "mm",
|
||||||
"min_value": "0",
|
"min_value": "0",
|
||||||
"max_value_warning": "10",
|
"max_value_warning": "10",
|
||||||
"default": 0.15,
|
"default": 0.1,
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"visible": false,
|
"visible": false,
|
||||||
"enabled": "support_enable"
|
"enabled": "support_enable"
|
||||||
@ -1141,7 +1141,7 @@
|
|||||||
"description": "The height of the steps of the stair-like bottom of support resting on the model. Small steps can cause the support to be hard to remove from the top of the model.",
|
"description": "The height of the steps of the stair-like bottom of support resting on the model. Small steps can cause the support to be hard to remove from the top of the model.",
|
||||||
"unit": "mm",
|
"unit": "mm",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"default": 2,
|
"default": 0.3,
|
||||||
"visible": false,
|
"visible": false,
|
||||||
"enabled": "support_enable"
|
"enabled": "support_enable"
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user