From 6930008dd8972dd5ec240821865882c75957bec3 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 28 Jan 2016 03:22:18 +0100 Subject: [PATCH 1/5] Pass the protocol file to Backend's createSocket --- plugins/CuraEngineBackend/CuraEngineBackend.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/plugins/CuraEngineBackend/CuraEngineBackend.py b/plugins/CuraEngineBackend/CuraEngineBackend.py index 955d508304..b0cd25a556 100644 --- a/plugins/CuraEngineBackend/CuraEngineBackend.py +++ b/plugins/CuraEngineBackend/CuraEngineBackend.py @@ -12,6 +12,7 @@ from UM.Logger import Logger from UM.Resources import Resources from UM.Settings.SettingOverrideDecorator import SettingOverrideDecorator from UM.Message import Message +from UM.PluginRegistry import PluginRegistry from cura.OneAtATimeIterator import OneAtATimeIterator from . import Cura_pb2 @@ -221,15 +222,7 @@ class CuraEngineBackend(Backend): pass def _createSocket(self): - super()._createSocket() - - self._socket.registerMessageType(1, Cura_pb2.Slice) - self._socket.registerMessageType(2, Cura_pb2.SlicedObjectList) - self._socket.registerMessageType(3, Cura_pb2.Progress) - self._socket.registerMessageType(4, Cura_pb2.GCodeLayer) - self._socket.registerMessageType(5, Cura_pb2.ObjectPrintTime) - self._socket.registerMessageType(6, Cura_pb2.SettingList) - self._socket.registerMessageType(7, Cura_pb2.GCodePrefix) + super()._createSocket(os.path.abspath(os.path.join(PluginRegistry.getInstance().getPluginPath(self.getPluginId()), "Cura.proto"))) ## Manually triggers a reslice def forceSlice(self): @@ -266,7 +259,6 @@ class CuraEngineBackend(Backend): else: self._layer_view_active = False - def _onInstanceChanged(self): self._terminate() self.slicingCancelled.emit() From 22fb26bae609a9f9bddb21844323bafc4d55ca2c Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 28 Jan 2016 03:23:10 +0100 Subject: [PATCH 2/5] Update StartSliceJob to reflect the new Arcus API --- plugins/CuraEngineBackend/StartSliceJob.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index 7fd703f8ca..4d94e5e8a9 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -81,14 +81,14 @@ class StartSliceJob(Job): self._sendSettings(self._profile) - slice_message = Cura_pb2.Slice() + slice_message = self._socket.createMessage("cura.proto.Slice"); for group in object_groups: - group_message = slice_message.object_lists.add() + group_message = slice_message.addRepeatedMessage("object_lists"); for object in group: mesh_data = object.getMeshData().getTransformed(object.getWorldTransformation()) - obj = group_message.objects.add() + obj = group_message.addRepeatedMessage("objects"); obj.id = id(object) verts = numpy.array(mesh_data.getVertices()) @@ -115,13 +115,13 @@ class StartSliceJob(Job): return str(value).encode("utf-8") def _sendSettings(self, profile): - msg = Cura_pb2.SettingList() + msg = self._socket.createMessage("cura.proto.SettingList"); settings = profile.getAllSettingValues(include_machine = True) start_gcode = settings["machine_start_gcode"] settings["material_bed_temp_prepend"] = "{material_bed_temperature}" not in start_gcode settings["material_print_temp_prepend"] = "{material_print_temperature}" not in start_gcode for key, value in settings.items(): - s = msg.settings.add() + s = msg.addRepeatedMessage("settings") s.name = key if key == "machine_start_gcode" or key == "machine_end_gcode": s.value = self._expandGcodeTokens(key, value, settings) @@ -134,7 +134,7 @@ class StartSliceJob(Job): profile = node.callDecoration("getProfile") if profile: for key, value in profile.getAllSettingValues().items(): - setting = message.settings.add() + setting = message.addRepeatedMessage("settings") setting.name = key setting.value = str(value).encode() @@ -145,7 +145,7 @@ class StartSliceJob(Job): return for key, value in object_settings.items(): - setting = message.settings.add() + setting = message.addRepeatedMessage("settings") setting.name = key setting.value = str(value).encode() From 21f70c412320fddd108dd70c371073ca696db771 Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 28 Jan 2016 03:23:47 +0100 Subject: [PATCH 3/5] Add Cura protobuf protocol file Should find some way of sharing the one in CuraEngine but this works for now --- plugins/CuraEngineBackend/Cura.proto | 100 +++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 plugins/CuraEngineBackend/Cura.proto diff --git a/plugins/CuraEngineBackend/Cura.proto b/plugins/CuraEngineBackend/Cura.proto new file mode 100644 index 0000000000..717a0a103d --- /dev/null +++ b/plugins/CuraEngineBackend/Cura.proto @@ -0,0 +1,100 @@ +syntax = "proto3"; + +package cura.proto; + + +message ObjectList +{ + repeated Object objects = 1; + repeated Setting settings = 2; +} + +// typeid 1 +message Slice +{ + repeated ObjectList object_lists = 1; +} + +message Object +{ + int64 id = 1; + bytes vertices = 2; //An array of 3 floats. + bytes normals = 3; //An array of 3 floats. + bytes indices = 4; //An array of ints. + repeated Setting settings = 5; // Setting override per object, overruling the global settings. +} + +// typeid 3 +message Progress +{ + float amount = 1; +} + +// typeid 2 +message SlicedObjectList +{ + repeated SlicedObject objects = 1; +} + +message SlicedObject +{ + int64 id = 1; + + repeated Layer layers = 2; +} + +message Layer { + int32 id = 1; + + float height = 2; + float thickness = 3; + + repeated Polygon polygons = 4; +} + +message Polygon { + enum Type { + NoneType = 0; + Inset0Type = 1; + InsetXType = 2; + SkinType = 3; + SupportType = 4; + SkirtType = 5; + InfillType = 6; + SupportInfillType = 7; + MoveCombingType = 8; + MoveRetractionType = 9; + } + Type type = 1; + bytes points = 2; + float line_width = 3; +} + +// typeid 4 +message GCodeLayer { + int64 id = 1; + bytes data = 2; +} + +// typeid 5 +message ObjectPrintTime { + int64 id = 1; + float time = 2; + float material_amount = 3; +} + +// typeid 6 +message SettingList { + repeated Setting settings = 1; +} + +message Setting { + string name = 1; + + bytes value = 2; +} + +// typeid 7 +message GCodePrefix { + bytes data = 2; +} From e74d300fb3db0f9e51fc71c821a566c0f573e21e Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Thu, 28 Jan 2016 18:07:42 +0100 Subject: [PATCH 4/5] Make things work properly using the new Arcus API --- plugins/CuraEngineBackend/CuraEngineBackend.py | 10 +++++----- .../ProcessSlicedObjectListJob.py | 16 +++++++++++----- plugins/CuraEngineBackend/StartSliceJob.py | 3 ++- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/plugins/CuraEngineBackend/CuraEngineBackend.py b/plugins/CuraEngineBackend/CuraEngineBackend.py index b0cd25a556..b431b5067c 100644 --- a/plugins/CuraEngineBackend/CuraEngineBackend.py +++ b/plugins/CuraEngineBackend/CuraEngineBackend.py @@ -62,11 +62,11 @@ class CuraEngineBackend(Backend): self._change_timer.setSingleShot(True) self._change_timer.timeout.connect(self.slice) - self._message_handlers[Cura_pb2.SlicedObjectList] = self._onSlicedObjectListMessage - self._message_handlers[Cura_pb2.Progress] = self._onProgressMessage - self._message_handlers[Cura_pb2.GCodeLayer] = self._onGCodeLayerMessage - self._message_handlers[Cura_pb2.GCodePrefix] = self._onGCodePrefixMessage - self._message_handlers[Cura_pb2.ObjectPrintTime] = self._onObjectPrintTimeMessage + self._message_handlers["cura.proto.SlicedObjectList"] = self._onSlicedObjectListMessage + self._message_handlers["cura.proto.Progress"] = self._onProgressMessage + self._message_handlers["cura.proto.GCodeLayer"] = self._onGCodeLayerMessage + self._message_handlers["cura.proto.GCodePrefix"] = self._onGCodePrefixMessage + self._message_handlers["cura.proto.ObjectPrintTime"] = self._onObjectPrintTimeMessage self._slicing = False self._restart = False diff --git a/plugins/CuraEngineBackend/ProcessSlicedObjectListJob.py b/plugins/CuraEngineBackend/ProcessSlicedObjectListJob.py index c802ca343b..09acab8a7e 100644 --- a/plugins/CuraEngineBackend/ProcessSlicedObjectListJob.py +++ b/plugins/CuraEngineBackend/ProcessSlicedObjectListJob.py @@ -55,21 +55,27 @@ class ProcessSlicedObjectListJob(Job): layer_data = LayerData.LayerData() layer_count = 0 - for object in self._message.objects: - layer_count += len(object.layers) + for i in range(self._message.repeatedMessageCount("objects")): + layer_count += self._message.getRepeatedMessage("objects", i).repeatedMessageCount("layers") current_layer = 0 - for object in self._message.objects: + 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 layer in object.layers: + for l in range(object.repeatedMessageCount("layers")): + layer = object.getRepeatedMessage("layers", i) + layer_data.addLayer(layer.id) layer_data.setLayerHeight(layer.id, layer.height) layer_data.setLayerThickness(layer.id, layer.thickness) - for polygon in layer.polygons: + + for p in range(layer.repeatedMessageCount("polygons")): + polygon = layer.getRepeatedMessage("polygons", i) + points = numpy.fromstring(polygon.points, dtype="i8") # Convert bytearray to numpy array 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.asarray(points, dtype=numpy.float32) diff --git a/plugins/CuraEngineBackend/StartSliceJob.py b/plugins/CuraEngineBackend/StartSliceJob.py index 4d94e5e8a9..156a859ade 100644 --- a/plugins/CuraEngineBackend/StartSliceJob.py +++ b/plugins/CuraEngineBackend/StartSliceJob.py @@ -94,7 +94,8 @@ class StartSliceJob(Job): verts = numpy.array(mesh_data.getVertices()) verts[:,[1,2]] = verts[:,[2,1]] verts[:,1] *= -1 - obj.vertices = verts.tostring() + + obj.vertices = verts self._handlePerObjectSettings(object, obj) From ffec2484b76980ef958778af0ed7f42baba2d3ed Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Mon, 1 Feb 2016 17:15:45 +0100 Subject: [PATCH 5/5] Fix Layer view --- cura/LayerData.py | 95 ++++++++++--------- .../ProcessSlicedObjectListJob.py | 6 +- 2 files changed, 51 insertions(+), 50 deletions(-) diff --git a/cura/LayerData.py b/cura/LayerData.py index 1cf13a1798..421b2589cb 100644 --- a/cura/LayerData.py +++ b/cura/LayerData.py @@ -131,7 +131,7 @@ class Layer(): continue if not make_mesh and not (polygon.type == Polygon.MoveCombingType or polygon.type == Polygon.MoveRetractionType): continue - + poly_color = polygon.getColor() points = numpy.copy(polygon.data) @@ -140,26 +140,7 @@ class Layer(): if polygon.type == Polygon.MoveCombingType or polygon.type == Polygon.MoveRetractionType: points[:,1] += 0.01 - # Calculate normals for the entire polygon using numpy. - normals = numpy.copy(points) - normals[:,1] = 0.0 # We are only interested in 2D normals - - # Calculate the edges between points. - # The call to numpy.roll shifts the entire array by one so that - # we end up subtracting each next point from the current, wrapping - # around. This gives us the edges from the next point to the current - # point. - normals[:] = normals[:] - numpy.roll(normals, -1, axis = 0) - # Calculate the length of each edge using standard Pythagoras - lengths = numpy.sqrt(normals[:,0] ** 2 + normals[:,2] ** 2) - # The normal of a 2D vector is equal to its x and y coordinates swapped - # and then x inverted. This code does that. - normals[:,[0, 2]] = normals[:,[2, 0]] - normals[:,0] *= -1 - - # Normalize the normals. - normals[:,0] /= lengths - normals[:,2] /= lengths + normals = polygon.getNormals() # Scale all by the line width of the polygon so we can easily offset. normals *= (polygon.lineWidth / 2) @@ -199,16 +180,33 @@ class Polygon(): self._data = data self._line_width = line_width / 1000 + if type == self.Inset0Type: + self._color = Color(1.0, 0.0, 0.0, 1.0) + elif self._type == self.InsetXType: + self._color = Color(0.0, 1.0, 0.0, 1.0) + elif self._type == self.SkinType: + self._color = Color(1.0, 1.0, 0.0, 1.0) + elif self._type == self.SupportType: + self._color = Color(0.0, 1.0, 1.0, 1.0) + elif self._type == self.SkirtType: + self._color = Color(0.0, 1.0, 1.0, 1.0) + elif self._type == self.InfillType: + self._color = Color(1.0, 0.74, 0.0, 1.0) + elif self._type == self.SupportInfillType: + self._color = Color(0.0, 1.0, 1.0, 1.0) + elif self._type == self.MoveCombingType: + self._color = Color(0.0, 0.0, 1.0, 1.0) + elif self._type == self.MoveRetractionType: + self._color = Color(0.5, 0.5, 1.0, 1.0) + else: + self._color = Color(1.0, 1.0, 1.0, 1.0) + def build(self, offset, vertices, colors, indices): self._begin = offset self._end = self._begin + len(self._data) - 1 - color = self.getColor() - 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) - vertices[self._begin:self._end + 1, :] = self._data[:, :] - colors[self._begin:self._end + 1, :] = color + colors[self._begin:self._end + 1, :] = numpy.array([self._color.r * 0.5, self._color.g * 0.5, self._color.b * 0.5, self._color.a], numpy.float32) for i in range(self._begin, self._end): indices[i, 0] = i @@ -218,26 +216,7 @@ class Polygon(): indices[self._end, 1] = self._begin def getColor(self): - if self._type == self.Inset0Type: - return Color(1.0, 0.0, 0.0, 1.0) - elif self._type == self.InsetXType: - return Color(0.0, 1.0, 0.0, 1.0) - elif self._type == self.SkinType: - return Color(1.0, 1.0, 0.0, 1.0) - elif self._type == self.SupportType: - return Color(0.0, 1.0, 1.0, 1.0) - elif self._type == self.SkirtType: - return Color(0.0, 1.0, 1.0, 1.0) - elif self._type == self.InfillType: - return Color(1.0, 0.74, 0.0, 1.0) - elif self._type == self.SupportInfillType: - return Color(0.0, 1.0, 1.0, 1.0) - elif self._type == self.MoveCombingType: - return Color(0.0, 0.0, 1.0, 1.0) - elif self._type == self.MoveRetractionType: - return Color(0.5, 0.5, 1.0, 1.0) - else: - return Color(1.0, 1.0, 1.0, 1.0) + return self._color def vertexCount(self): return len(self._data) @@ -257,3 +236,27 @@ class Polygon(): @property def lineWidth(self): return self._line_width + + # Calculate normals for the entire polygon using numpy. + def getNormals(self): + normals = numpy.copy(self._data) + normals[:,1] = 0.0 # We are only interested in 2D normals + + # Calculate the edges between points. + # The call to numpy.roll shifts the entire array by one so that + # we end up subtracting each next point from the current, wrapping + # around. This gives us the edges from the next point to the current + # point. + normals[:] = normals[:] - numpy.roll(normals, -1, axis = 0) + # Calculate the length of each edge using standard Pythagoras + lengths = numpy.sqrt(normals[:,0] ** 2 + normals[:,2] ** 2) + # The normal of a 2D vector is equal to its x and y coordinates swapped + # and then x inverted. This code does that. + normals[:,[0, 2]] = normals[:,[2, 0]] + normals[:,0] *= -1 + + # Normalize the normals. + normals[:,0] /= lengths + normals[:,2] /= lengths + + return normals diff --git a/plugins/CuraEngineBackend/ProcessSlicedObjectListJob.py b/plugins/CuraEngineBackend/ProcessSlicedObjectListJob.py index 09acab8a7e..5176f79eeb 100644 --- a/plugins/CuraEngineBackend/ProcessSlicedObjectListJob.py +++ b/plugins/CuraEngineBackend/ProcessSlicedObjectListJob.py @@ -67,14 +67,14 @@ class ProcessSlicedObjectListJob(Job): continue for l in range(object.repeatedMessageCount("layers")): - layer = object.getRepeatedMessage("layers", i) + layer = object.getRepeatedMessage("layers", l) layer_data.addLayer(layer.id) layer_data.setLayerHeight(layer.id, layer.height) layer_data.setLayerThickness(layer.id, layer.thickness) for p in range(layer.repeatedMessageCount("polygons")): - polygon = layer.getRepeatedMessage("polygons", i) + polygon = layer.getRepeatedMessage("polygons", p) points = numpy.fromstring(polygon.points, dtype="i8") # Convert bytearray to numpy array points = points.reshape((-1,2)) # We get a linear list of pairs that make up the points, so make numpy interpret them correctly. @@ -88,8 +88,6 @@ class ProcessSlicedObjectListJob(Job): 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.