mirror of
https://github.com/Ultimaker/Cura.git
synced 2025-07-14 10:17:52 -06:00
Layer data is now processed layer by layer.
This is done to prevent the very large messages that would be sent otherwise. Protobuf can't do anything with messages above 512MB. As we no longer send a "collection" message, this should no longer occur. CURA-1210
This commit is contained in:
parent
834e2148d2
commit
7045d67bde
3 changed files with 51 additions and 82 deletions
|
@ -2,14 +2,12 @@ syntax = "proto3";
|
||||||
|
|
||||||
package cura.proto;
|
package cura.proto;
|
||||||
|
|
||||||
|
|
||||||
message ObjectList
|
message ObjectList
|
||||||
{
|
{
|
||||||
repeated Object objects = 1;
|
repeated Object objects = 1;
|
||||||
repeated Setting settings = 2;
|
repeated Setting settings = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// typeid 1
|
|
||||||
message Slice
|
message Slice
|
||||||
{
|
{
|
||||||
repeated ObjectList object_lists = 1;
|
repeated ObjectList object_lists = 1;
|
||||||
|
@ -24,28 +22,13 @@ message Object
|
||||||
repeated Setting settings = 5; // Setting override per object, overruling the global settings.
|
repeated Setting settings = 5; // Setting override per object, overruling the global settings.
|
||||||
}
|
}
|
||||||
|
|
||||||
// typeid 3
|
|
||||||
message Progress
|
message Progress
|
||||||
{
|
{
|
||||||
float amount = 1;
|
float amount = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// typeid 2
|
|
||||||
message SlicedObjectList
|
|
||||||
{
|
|
||||||
repeated SlicedObject objects = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message SlicedObject
|
|
||||||
{
|
|
||||||
int64 id = 1;
|
|
||||||
|
|
||||||
repeated Layer layers = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
message Layer {
|
message Layer {
|
||||||
int32 id = 1;
|
int32 id = 1;
|
||||||
|
|
||||||
float height = 2;
|
float height = 2;
|
||||||
float thickness = 3;
|
float thickness = 3;
|
||||||
|
|
||||||
|
@ -70,20 +53,16 @@ message Polygon {
|
||||||
float line_width = 3;
|
float line_width = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// typeid 4
|
|
||||||
message GCodeLayer {
|
message GCodeLayer {
|
||||||
int64 id = 1;
|
|
||||||
bytes data = 2;
|
bytes data = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// typeid 5
|
|
||||||
message ObjectPrintTime {
|
message ObjectPrintTime {
|
||||||
int64 id = 1;
|
int64 id = 1;
|
||||||
float time = 2;
|
float time = 2;
|
||||||
float material_amount = 3;
|
float material_amount = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// typeid 6
|
|
||||||
message SettingList {
|
message SettingList {
|
||||||
repeated Setting settings = 1;
|
repeated Setting settings = 1;
|
||||||
}
|
}
|
||||||
|
@ -94,11 +73,9 @@ message Setting {
|
||||||
bytes value = 2;
|
bytes value = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// typeid 7
|
|
||||||
message GCodePrefix {
|
message GCodePrefix {
|
||||||
bytes data = 2;
|
bytes data = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// typeid 8
|
|
||||||
message SlicingFinished {
|
message SlicingFinished {
|
||||||
}
|
}
|
|
@ -16,7 +16,7 @@ from UM.Message import Message
|
||||||
from UM.PluginRegistry import PluginRegistry
|
from UM.PluginRegistry import PluginRegistry
|
||||||
|
|
||||||
from cura.OneAtATimeIterator import OneAtATimeIterator
|
from cura.OneAtATimeIterator import OneAtATimeIterator
|
||||||
from . import ProcessSlicedObjectListJob
|
from . import ProcessSlicedLayersJob
|
||||||
from . import ProcessGCodeJob
|
from . import ProcessGCodeJob
|
||||||
from . import StartSliceJob
|
from . import StartSliceJob
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ class CuraEngineBackend(Backend):
|
||||||
self._layer_view_active = False
|
self._layer_view_active = False
|
||||||
Application.getInstance().getController().activeViewChanged.connect(self._onActiveViewChanged)
|
Application.getInstance().getController().activeViewChanged.connect(self._onActiveViewChanged)
|
||||||
self._onActiveViewChanged()
|
self._onActiveViewChanged()
|
||||||
self._stored_layer_data = None
|
self._stored_layer_data = []
|
||||||
|
|
||||||
Application.getInstance().getMachineManager().activeMachineInstanceChanged.connect(self._onChanged)
|
Application.getInstance().getMachineManager().activeMachineInstanceChanged.connect(self._onChanged)
|
||||||
|
|
||||||
|
@ -64,7 +64,8 @@ class CuraEngineBackend(Backend):
|
||||||
self._change_timer.setSingleShot(True)
|
self._change_timer.setSingleShot(True)
|
||||||
self._change_timer.timeout.connect(self.slice)
|
self._change_timer.timeout.connect(self.slice)
|
||||||
|
|
||||||
self._message_handlers["cura.proto.SlicedObjectList"] = self._onSlicedObjectListMessage
|
#self._message_handlers["cura.proto.SlicedObjectList"] = self._onSlicedObjectListMessage
|
||||||
|
self._message_handlers["cura.proto.Layer"] = self._onLayerMessage
|
||||||
self._message_handlers["cura.proto.Progress"] = self._onProgressMessage
|
self._message_handlers["cura.proto.Progress"] = self._onProgressMessage
|
||||||
self._message_handlers["cura.proto.GCodeLayer"] = self._onGCodeLayerMessage
|
self._message_handlers["cura.proto.GCodeLayer"] = self._onGCodeLayerMessage
|
||||||
self._message_handlers["cura.proto.GCodePrefix"] = self._onGCodePrefixMessage
|
self._message_handlers["cura.proto.GCodePrefix"] = self._onGCodePrefixMessage
|
||||||
|
@ -155,6 +156,7 @@ class CuraEngineBackend(Backend):
|
||||||
def _terminate(self):
|
def _terminate(self):
|
||||||
self._slicing = False
|
self._slicing = False
|
||||||
self._restart = True
|
self._restart = True
|
||||||
|
self._stored_layer_data = []
|
||||||
self.slicingCancelled.emit()
|
self.slicingCancelled.emit()
|
||||||
Logger.log("d", "Attempting to kill the engine process")
|
Logger.log("d", "Attempting to kill the engine process")
|
||||||
if self._process is not None:
|
if self._process is not None:
|
||||||
|
@ -209,12 +211,9 @@ class CuraEngineBackend(Backend):
|
||||||
def _onSettingChanged(self, setting):
|
def _onSettingChanged(self, setting):
|
||||||
self._onChanged()
|
self._onChanged()
|
||||||
|
|
||||||
def _onSlicedObjectListMessage(self, message):
|
def _onLayerMessage(self, message):
|
||||||
if self._layer_view_active:
|
self._stored_layer_data.append(message)
|
||||||
self._process_layers_job = ProcessSlicedObjectListJob.ProcessSlicedObjectListJob(message)
|
|
||||||
self._process_layers_job.start()
|
|
||||||
else :
|
|
||||||
self._stored_layer_data = message
|
|
||||||
|
|
||||||
def _onProgressMessage(self, message):
|
def _onProgressMessage(self, message):
|
||||||
if self._message:
|
if self._message:
|
||||||
|
@ -234,6 +233,11 @@ class CuraEngineBackend(Backend):
|
||||||
self._message.hide()
|
self._message.hide()
|
||||||
self._message = None
|
self._message = None
|
||||||
|
|
||||||
|
if self._layer_view_active and (self._process_layers_job is None or not self._process_layers_job.isRunning()):
|
||||||
|
self._process_layers_job = ProcessSlicedLayersJob.ProcessSlicedLayersJob(self._stored_layer_data)
|
||||||
|
self._process_layers_job.start()
|
||||||
|
self._stored_layer_data = []
|
||||||
|
|
||||||
def _onGCodeLayerMessage(self, message):
|
def _onGCodeLayerMessage(self, message):
|
||||||
self._scene.gcode_list.append(message.data.decode("utf-8", "replace"))
|
self._scene.gcode_list.append(message.data.decode("utf-8", "replace"))
|
||||||
|
|
||||||
|
@ -275,10 +279,10 @@ class CuraEngineBackend(Backend):
|
||||||
self._layer_view_active = True
|
self._layer_view_active = True
|
||||||
# There is data and we're not slicing at the moment
|
# There is data and we're not slicing at the moment
|
||||||
# if we are slicing, there is no need to re-calculate the data as it will be invalid in a moment.
|
# if we are slicing, there is no need to re-calculate the data as it will be invalid in a moment.
|
||||||
if self._stored_layer_data and not self._slicing:
|
if len(self._stored_layer_data) and not self._slicing:
|
||||||
self._process_layers_job = ProcessSlicedObjectListJob.ProcessSlicedObjectListJob(self._stored_layer_data)
|
self._process_layers_job = ProcessSlicedLayersJob.ProcessSlicedLayersJob(self._stored_layer_data)
|
||||||
self._process_layers_job.start()
|
self._process_layers_job.start()
|
||||||
self._stored_layer_data = None
|
self._stored_layer_data = []
|
||||||
else:
|
else:
|
||||||
self._layer_view_active = False
|
self._layer_view_active = False
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Copyright (c) 2015 Ultimaker B.V.
|
# Copyright (c) 2016 Ultimaker B.V.
|
||||||
# Cura is released under the terms of the AGPLv3 or higher.
|
# Cura is released under the terms of the AGPLv3 or higher.
|
||||||
|
|
||||||
from UM.Job import Job
|
from UM.Job import Job
|
||||||
|
@ -20,10 +20,10 @@ import struct
|
||||||
|
|
||||||
catalog = i18nCatalog("cura")
|
catalog = i18nCatalog("cura")
|
||||||
|
|
||||||
class ProcessSlicedObjectListJob(Job):
|
class ProcessSlicedLayersJob(Job):
|
||||||
def __init__(self, message):
|
def __init__(self, layers):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self._message = message
|
self._layers = layers
|
||||||
self._scene = Application.getInstance().getController().getScene()
|
self._scene = Application.getInstance().getController().getScene()
|
||||||
self._progress = None
|
self._progress = None
|
||||||
self._abort_requested = False
|
self._abort_requested = False
|
||||||
|
@ -51,13 +51,12 @@ class ProcessSlicedObjectListJob(Job):
|
||||||
|
|
||||||
object_id_map = {}
|
object_id_map = {}
|
||||||
new_node = SceneNode()
|
new_node = SceneNode()
|
||||||
## Put all nodes in a dict identified by ID
|
|
||||||
|
## Remove old layer data (if any)
|
||||||
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"):
|
||||||
self._scene.getRoot().removeChild(node)
|
self._scene.getRoot().removeChild(node)
|
||||||
else:
|
|
||||||
object_id_map[id(node)] = node
|
|
||||||
Job.yieldThread()
|
Job.yieldThread()
|
||||||
if self._abort_requested:
|
if self._abort_requested:
|
||||||
if self._progress:
|
if self._progress:
|
||||||
|
@ -68,56 +67,45 @@ class ProcessSlicedObjectListJob(Job):
|
||||||
|
|
||||||
mesh = MeshData()
|
mesh = MeshData()
|
||||||
layer_data = LayerData.LayerData()
|
layer_data = LayerData.LayerData()
|
||||||
|
layer_count = len(self._layers)
|
||||||
layer_count = 0
|
|
||||||
for i in range(self._message.repeatedMessageCount("objects")):
|
|
||||||
layer_count += self._message.getRepeatedMessage("objects", i).repeatedMessageCount("layers")
|
|
||||||
|
|
||||||
current_layer = 0
|
current_layer = 0
|
||||||
for i in range(self._message.repeatedMessageCount("objects")):
|
|
||||||
object = self._message.getRepeatedMessage("objects", i)
|
|
||||||
try:
|
|
||||||
node = object_id_map[object.id]
|
|
||||||
except KeyError:
|
|
||||||
continue
|
|
||||||
|
|
||||||
for l in range(object.repeatedMessageCount("layers")):
|
for layer in self._layers:
|
||||||
layer = object.getRepeatedMessage("layers", l)
|
layer_data.addLayer(layer.id)
|
||||||
|
layer_data.setLayerHeight(layer.id, layer.height)
|
||||||
|
layer_data.setLayerThickness(layer.id, layer.thickness)
|
||||||
|
|
||||||
layer_data.addLayer(layer.id)
|
for p in range(layer.repeatedMessageCount("polygons")):
|
||||||
layer_data.setLayerHeight(layer.id, layer.height)
|
polygon = layer.getRepeatedMessage("polygons", p)
|
||||||
layer_data.setLayerThickness(layer.id, layer.thickness)
|
|
||||||
|
|
||||||
for p in range(layer.repeatedMessageCount("polygons")):
|
points = numpy.fromstring(polygon.points, dtype="i8") # Convert bytearray to numpy array
|
||||||
polygon = layer.getRepeatedMessage("polygons", p)
|
points = points.reshape((-1,2)) # We get a linear list of pairs that make up the points, so make numpy interpret them correctly.
|
||||||
|
|
||||||
points = numpy.fromstring(polygon.points, dtype="i8") # Convert bytearray to numpy array
|
# Create a new 3D-array, copy the 2D points over and insert the right height.
|
||||||
points = points.reshape((-1,2)) # We get a linear list of pairs that make up the points, so make numpy interpret them correctly.
|
# This uses manual array creation + copy rather than numpy.insert since this is
|
||||||
|
# faster.
|
||||||
|
new_points = numpy.empty((len(points), 3), numpy.float32)
|
||||||
|
new_points[:,0] = points[:,0]
|
||||||
|
new_points[:,1] = layer.height
|
||||||
|
new_points[:,2] = -points[:,1]
|
||||||
|
|
||||||
# Create a new 3D-array, copy the 2D points over and insert the right height.
|
new_points /= 1000
|
||||||
# This uses manual array creation + copy rather than numpy.insert since this is
|
|
||||||
# faster.
|
|
||||||
new_points = numpy.empty((len(points), 3), numpy.float32)
|
|
||||||
new_points[:,0] = points[:,0]
|
|
||||||
new_points[:,1] = layer.height
|
|
||||||
new_points[:,2] = -points[:,1]
|
|
||||||
|
|
||||||
new_points /= 1000
|
layer_data.addPolygon(layer.id, polygon.type, new_points, polygon.line_width)
|
||||||
|
|
||||||
layer_data.addPolygon(layer.id, polygon.type, new_points, polygon.line_width)
|
|
||||||
Job.yieldThread()
|
|
||||||
Job.yieldThread()
|
Job.yieldThread()
|
||||||
current_layer += 1
|
Job.yieldThread()
|
||||||
progress = (current_layer / layer_count) * 100
|
current_layer += 1
|
||||||
# TODO: Rebuild the layer data mesh once the layer has been processed.
|
progress = (current_layer / layer_count) * 100
|
||||||
# This needs some work in LayerData so we can add the new layers instead of recreating the entire mesh.
|
# 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._abort_requested:
|
if self._abort_requested:
|
||||||
if self._progress:
|
|
||||||
self._progress.hide()
|
|
||||||
return
|
|
||||||
if self._progress:
|
if self._progress:
|
||||||
self._progress.setProgress(progress)
|
self._progress.hide()
|
||||||
|
return
|
||||||
|
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()
|
Loading…
Add table
Add a link
Reference in a new issue