<commit_before>from UM.Backend.Backend import Backend
from UM.Application import Application
from UM.Scene.SceneNode import SceneNode
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
from UM.Preferences import Preferences
from UM.Math.Vector import Vector

from . import Cura_pb2
from . import ProcessSlicedObjectListJob
from . import ProcessGCodeJob

import threading
import struct
import numpy

class CuraEngineBackend(Backend):
    def __init__(self):
        super().__init__()

        Preferences.getInstance().addPreference('backend/location', '../PinkUnicornEngine/CuraEngine')

        self._scene = Application.getInstance().getController().getScene()
        self._scene.sceneChanged.connect(self._onSceneChanged)

        self._settings = None
        Application.getInstance().activeMachineChanged.connect(self._onActiveMachineChanged)
        self._onActiveMachineChanged()

        self._changeTimer = None

        self._message_handlers[Cura_pb2.SlicedObjectList] = self._onSlicedObjectListMessage
        self._message_handlers[Cura_pb2.Progress] = self._onProgressMessage
        self._message_handlers[Cura_pb2.GCode] = self._onGCodeMessage
        self._message_handlers[Cura_pb2.ObjectPrintTime] = self._onObjectPrintTimeMessage

        self._center = None

    def getEngineCommand(self):
        return [Preferences.getInstance().getValue("backend/location"), '--connect', "127.0.0.1:{0}".format(self._port)]

    def _onSceneChanged(self, source):
        if (type(source) is not SceneNode) or (source is self._scene.getRoot()):
            return

        self._onChanged()

    def _onActiveMachineChanged(self):
        if self._settings:
            self._settings.settingChanged.disconnect(self._onSettingChanged)

        self._settings = Application.getInstance().getActiveMachine()
        if self._settings:
            self._settings.settingChanged.connect(self._onSettingChanged)
            self._onChanged()

    def _onSettingChanged(self, setting):
        self._onChanged()

    def _onSlicedObjectListMessage(self, message):
        job = ProcessSlicedObjectListJob.ProcessSlicedObjectListJob(message, self._center)
        job.start()

    def _onProgressMessage(self, message):
        self.processingProgress.emit(message.amount)

    def _onGCodeMessage(self, message):
        job = ProcessGCodeJob.ProcessGCodeJob(message)
        job.start()

    def _onObjectPrintTimeMessage(self, message):
        pass

    def _createSocket(self):
        super()._createSocket()
        
        self._socket.registerMessageType(1, Cura_pb2.ObjectList)
        self._socket.registerMessageType(2, Cura_pb2.SlicedObjectList)
        self._socket.registerMessageType(3, Cura_pb2.Progress)
        self._socket.registerMessageType(4, Cura_pb2.GCode)
        self._socket.registerMessageType(5, Cura_pb2.ObjectPrintTime)
        self._socket.registerMessageType(6, Cura_pb2.SettingList)

    def _onChanged(self):
        if not self._settings:
            return

        if self._changeTimer:
            return

        self._changeTimer = threading.Timer(1, self._onChangeTimerFinished)
        self._changeTimer.start()

    def _onChangeTimerFinished(self):
        objects = []
        for node in DepthFirstIterator(self._scene.getRoot()):
            if type(node) is SceneNode and node.getMeshData():
                objects.append(node)

        if not objects:
            self._changeTimer = None
            return #No point in slicing an empty build plate

        self._sendSettings()

        self._scene.acquireLock()

        msg = Cura_pb2.ObjectList()

        #TODO: All at once/one at a time mode
        center = Vector()
        for object in objects:
            center += object.getPosition()

            meshData = object.getMeshData()

            obj = msg.objects.add()
            obj.id = id(object)

            verts = numpy.array(meshData.getVertices(), copy=True)
            verts[:,[1,2]] = verts[:,[2,1]]
            obj.vertices = verts.tostring()

            #if meshData.hasNormals():
                #obj.normals = meshData.getNormalsAsByteArray()

            #if meshData.hasIndices():
                #obj.indices = meshData.getIndicesAsByteArray()

        self._scene.releaseLock()

        center /= float(len(objects))
        if not self._settings.getSettingValueByKey('machine_center_is_zero'):
            center.setX(center.x + self._settings.getSettingValueByKey('machine_width') / 2)
            center.setZ(center.z + self._settings.getSettingValueByKey('machine_depth') / 2)

        posmsg = Cura_pb2.SettingList()
        posX = posmsg.settings.add()
        posX.name = 'position.X'
        posX.value = str(int(center.x * 1000)).encode('utf-8')
        posY = posmsg.settings.add()
        posY.name = 'position.Y'
        posY.value = str(int(center.z * 1000)).encode('utf-8')
        posZ = posmsg.settings.add()
        posZ.name = 'position.Z'
        posZ.value = str(int(0)).encode('utf-8')
        self._socket.sendMessage(posmsg)

        self._center = center

        self._socket.sendMessage(msg)

        self._changeTimer = None

    def _sendSettings(self):
        extruder = 0

        settings = {
            'extruderNr': extruder,
            'layerThickness': int(self._settings.getSettingValueByKey('layer_height') * 1000),
            'initialLayerThickness': int(self._settings.getSettingValueByKey('layer_height_0') * 1000),
            'printTemperature': int(self._settings.getSettingValueByKey('material_print_temperature')),
            'filamentDiameter': int(self._settings.getSettingValueByKey('material_diameter') * 1000),
            'filamentFlow': int(self._settings.getSettingValueByKey('material_flow')),
            'layer0extrusionWidth': int(self._settings.getSettingValueByKey('wall_line_width_0') * 1000),
            'extrusionWidth': int(self._settings.getSettingValueByKey('wall_line_width_x') * 1000),
            'insetCount': int(self._settings.getSettingValueByKey('wall_line_count')),
            'downSkinCount': int(self._settings.getSettingValueByKey('bottom_layers')),
            'upSkinCount': int(self._settings.getSettingValueByKey('top_layers')),
            'skirtDistance': int(self._settings.getSettingValueByKey('skirt_gap') * 1000),
            'skirtLineCount': int(self._settings.getSettingValueByKey('skirt_line_count')),
            'skirtMinLength': int(self._settings.getSettingValueByKey('skirt_minimal_length') * 1000),

            'retractionAmount': int(self._settings.getSettingValueByKey('retraction_amount') * 1000),
            'retractionAmountPrime': int(0 * 1000),
            # 'retractionAmountExtruderSwitch': int(fbk('') * 1000),
            'retractionSpeed': int(self._settings.getSettingValueByKey('retraction_speed')),
            'retractionPrimeSpeed': int(self._settings.getSettingValueByKey('retraction_speed')),
            'retractionMinimalDistance': int(self._settings.getSettingValueByKey('retraction_min_travel') * 1000),
            'minimalExtrusionBeforeRetraction': int(self._settings.getSettingValueByKey('retraction_minimal_extrusion') * 1000),
            'retractionZHop': int(self._settings.getSettingValueByKey('retraction_hop') * 1000),

            'enableCombing': 1 if self._settings.getSettingValueByKey('retraction_combing') else 0,
            # 'enableOozeShield': int(fbk('') * 1000),
            # 'wipeTowerSize': int(fbk('') * 1000),
            # 'multiVolumeOverlap': int(fbk('') * 1000),

            'initialSpeedupLayers': int(self._settings.getSettingValueByKey('speed_slowdown_layers')),
            'initialLayerSpeed': int(self._settings.getSettingValueByKey('speed_layer_0')),
            'skirtSpeed': int(self._settings.getSettingValueByKey('skirt_speed')),
            'inset0Speed': int(self._settings.getSettingValueByKey('speed_wall_0')),
            'insetXSpeed': int(self._settings.getSettingValueByKey('speed_wall_x')),
            'supportSpeed': int(self._settings.getSettingValueByKey('speed_support')),
            'moveSpeed': int(self._settings.getSettingValueByKey('speed_travel')),
            #'fanFullOnLayerNr': int(fbk('cool_fan_full_layer')),

            'infillOverlap': int(self._settings.getSettingValueByKey('fill_overlap')),
            'infillSpeed': int(self._settings.getSettingValueByKey('speed_infill')),

            'minimalLayerTime': int(self._settings.getSettingValueByKey('cool_min_layer_time')),
            'minimalFeedrate': int(self._settings.getSettingValueByKey('cool_min_speed')),
            'coolHeadLift': 1 if self._settings.getSettingValueByKey('cool_lift_head') else 0,
            'fanSpeedMin': self._settings.getSettingValueByKey('cool_fan_speed_min'),
            'fanSpeedMax': self._settings.getSettingValueByKey('cool_fan_speed_max'),

            'spiralizeMode': 1 if self._settings.getSettingValueByKey('magic_spiralize') == 'True' else 0,

        }

        if self._settings.getSettingValueByKey('top_bottom_pattern') == 'lines':
            settings['skinPattern'] = 'SKIN_LINES'
        elif self._settings.getSettingValueByKey('top_bottom_pattern') == 'concentric':
            settings['skinPattern'] = 'SKIN_CONCENTRIC'

        if self._settings.getSettingValueByKey('fill_pattern') == 'Grid':
            settings['infillPattern'] = 'INFILL_GRID'
        elif self._settings.getSettingValueByKey('fill_pattern') == 'Lines':
            settings['infillPattern'] = 'INFILL_LINES'
        elif self._settings.getSettingValueByKey('fill_pattern') == 'concentric':
            settings['infillPattern'] = 'INFILL_CONCENTRIC'

        adhesion_type = self._settings.getSettingValueByKey('adhesion_type')
        if adhesion_type == 'Raft':
            settings['raftMargin'] = int(self._settings.getSettingValueByKey('raft_margin') * 1000)
            settings['raftLineSpacing'] = int(self._settings.getSettingValueByKey('raft_line_spacing') * 1000)
            settings['raftBaseThickness'] = int(self._settings.getSettingValueByKey('raft_base_thickness') * 1000)
            settings['raftBaseLinewidth'] = int(self._settings.getSettingValueByKey('raft_base_linewidth') * 1000)
            settings['raftBaseSpeed'] = int(self._settings.getSettingValueByKey('raft_base_speed') * 1000)
            settings['raftInterfaceThickness'] = int(self._settings.getSettingValueByKey('raft_interface_thickness') * 1000)
            settings['raftInterfaceLinewidth'] = int(self._settings.getSettingValueByKey('raft_interface_linewidth') * 1000)
            settings['raftInterfaceLineSpacing'] = int(self._settings.getSettingValueByKey('raft_line_spacing') * 1000)
            settings['raftFanSpeed'] = 0
            settings['raftSurfaceThickness'] = int(self._settings.getSettingValueByKey('layer_height_0') * 1000)
            settings['raftSurfaceLinewidth'] = int(self._settings.getSettingValueByKey('wall_line_width_x') * 1000)
            settings['raftSurfaceLineSpacing'] = int(self._settings.getSettingValueByKey('wall_line_width_x') * 1000)
            settings['raftSurfaceLayers'] = int(self._settings.getSettingValueByKey('raft_surface_layers'))
            settings['raftSurfaceSpeed'] = int(self._settings.getSettingValueByKey('speed_layer_0') * 1000)
            settings['raftAirGap'] = int(self._settings.getSettingValueByKey('raft_airgap') * 1000)
            settings['skirtLineCount'] = 0
            pass
        elif adhesion_type == 'Brim':
            settings['skirtDistance'] = 0
            settings['skirtLineCount'] = self._settings.getSettingValueByKey('brim_line_count')

        if self._settings.getSettingValueByKey('support_type') == 'None':
            settings['supportType'] = ''
            settings['supportAngle'] = -1
        else:
            settings['areaSupportPolyGenerator'] = 1
            settings['supportType'] = 'LINES'
            settings['supportAngle'] = self._settings.getSettingValueByKey('support_angle')
            settings['supportEverywhere'] = 1 if self._settings.getSettingValueByKey('support_type') == 'Everywhere' else 0
            settings['supportLineDistance'] = int(100 * self._settings.getSettingValueByKey('wall_line_width_x') * 1000 / self._settings.getSettingValueByKey('support_fill_rate'))
            settings['supportXYDistance'] = int(self._settings.getSettingValueByKey('support_xy_distance') * 1000)
            settings['supportZDistance'] = int(self._settings.getSettingValueByKey('support_z_distance') * 1000)
            settings['supportZDistanceBottom'] = int(self._settings.getSettingValueByKey('support_top_distance') * 1000)
            settings['supportZDistanceTop'] = int(self._settings.getSettingValueByKey('support_bottom_distance') * 1000)
            settings['supportJoinDistance'] = int(self._settings.getSettingValueByKey('support_join_distance') * 1000)
            settings['supportBridgeBack'] = int(self._settings.getSettingValueByKey('support_bridge_back'))
            settings['supportExtruder'] = -1
            if self._settings.getSettingValueByKey('support_pattern') == 'Grid':
                settings['supportType'] = 'GRID'
            elif self._settings.getSettingValueByKey('support_pattern') == 'Lines':
                settings['supportType'] = 'LINES'

        settings['sparseInfillLineDistance'] = -1
        if self._settings.getSettingValueByKey('fill_sparse_density') >= 100:
            settings['sparseInfillLineDistance'] = self._settings.getSettingValueByKey('wall_line_width_x')
            settings['downSkinCount'] = 10000
            settings['upSkinCount'] = 10000
        elif self._settings.getSettingValueByKey('fill_sparse_density') > 0:
            settings['sparseInfillLineDistance'] = int(100 * self._settings.getSettingValueByKey('wall_line_width_x') * 1000 / self._settings.getSettingValueByKey('fill_sparse_density'))
        settings['sparseInfillCombineCount'] = int(round(self._settings.getSettingValueByKey('fill_sparse_combine')))

        gcodeFlavor = self._settings.getSettingValueByKey('machine_gcode_flavor')
        if gcodeFlavor == 'UltiGCode':
            settings['gcodeFlavor'] = 1
        elif gcodeFlavor == 'Makerbot':
            settings['gcodeFlavor'] = 2
        elif gcodeFlavor == 'BFB':
            settings['gcodeFlavor'] = 3
        elif gcodeFlavor == 'Mach3':
            settings['gcodeFlavor'] = 4
        elif gcodeFlavor == 'Volumetric':
            settings['gcodeFlavor'] = 5
        else:
            settings['gcodeFlavor'] = 0

        settings['startCode'] = self._settings.getSettingValueByKey('machine_start_gcode')
        settings['endCode'] = self._settings.getSettingValueByKey('machine_end_gcode')

        #for n in range(1, self._machine.getMaxNozzles()):
        n = 1
        settings['extruderOffset1.X'] = int(self._settings.getSettingValueByKey('machine_nozzle_offset_x_1') * 1000)
        settings['extruderOffset1.Y'] = int(self._settings.getSettingValueByKey('machine_nozzle_offset_y_1') * 1000)

        msg = Cura_pb2.SettingList()
        for key, value in settings.items():
            s = msg.settings.add()
            s.name = key
            s.value = str(value).encode('utf-8')

        self._socket.sendMessage(msg)
<commit_msg>Cancel the running timer when receiving another change notification in CuraEngineBackend<commit_after>from UM.Backend.Backend import Backend
from UM.Application import Application
from UM.Scene.SceneNode import SceneNode
from UM.Scene.Iterator.DepthFirstIterator import DepthFirstIterator
from UM.Preferences import Preferences
from UM.Math.Vector import Vector

from . import Cura_pb2
from . import ProcessSlicedObjectListJob
from . import ProcessGCodeJob

import threading
import struct
import numpy

class CuraEngineBackend(Backend):
    def __init__(self):
        super().__init__()

        Preferences.getInstance().addPreference('backend/location', '../PinkUnicornEngine/CuraEngine')

        self._scene = Application.getInstance().getController().getScene()
        self._scene.sceneChanged.connect(self._onSceneChanged)

        self._settings = None
        Application.getInstance().activeMachineChanged.connect(self._onActiveMachineChanged)
        self._onActiveMachineChanged()

        self._changeTimer = None

        self._message_handlers[Cura_pb2.SlicedObjectList] = self._onSlicedObjectListMessage
        self._message_handlers[Cura_pb2.Progress] = self._onProgressMessage
        self._message_handlers[Cura_pb2.GCode] = self._onGCodeMessage
        self._message_handlers[Cura_pb2.ObjectPrintTime] = self._onObjectPrintTimeMessage

        self._center = None

        self._slice_interval = 0.5

    def getEngineCommand(self):
        return [Preferences.getInstance().getValue("backend/location"), '--connect', "127.0.0.1:{0}".format(self._port)]

    def _onSceneChanged(self, source):
        if (type(source) is not SceneNode) or (source is self._scene.getRoot()):
            return

        self._onChanged()

    def _onActiveMachineChanged(self):
        if self._settings:
            self._settings.settingChanged.disconnect(self._onSettingChanged)

        self._settings = Application.getInstance().getActiveMachine()
        if self._settings:
            self._settings.settingChanged.connect(self._onSettingChanged)
            self._onChanged()

    def _onSettingChanged(self, setting):
        self._onChanged()

    def _onSlicedObjectListMessage(self, message):
        job = ProcessSlicedObjectListJob.ProcessSlicedObjectListJob(message, self._center)
        job.start()

    def _onProgressMessage(self, message):
        self.processingProgress.emit(message.amount)

    def _onGCodeMessage(self, message):
        job = ProcessGCodeJob.ProcessGCodeJob(message)
        job.start()

    def _onObjectPrintTimeMessage(self, message):
        pass

    def _createSocket(self):
        super()._createSocket()
        
        self._socket.registerMessageType(1, Cura_pb2.ObjectList)
        self._socket.registerMessageType(2, Cura_pb2.SlicedObjectList)
        self._socket.registerMessageType(3, Cura_pb2.Progress)
        self._socket.registerMessageType(4, Cura_pb2.GCode)
        self._socket.registerMessageType(5, Cura_pb2.ObjectPrintTime)
        self._socket.registerMessageType(6, Cura_pb2.SettingList)

    def _onChanged(self):
        if not self._settings:
            return

        if self._changeTimer:
            self._changeTimer.cancel()

        self._changeTimer = threading.Timer(self._slice_interval, self._onChangeTimerFinished)
        self._changeTimer.start()

    def _onChangeTimerFinished(self):
        objects = []
        for node in DepthFirstIterator(self._scene.getRoot()):
            if type(node) is SceneNode and node.getMeshData():
                objects.append(node)

        if not objects:
            self._changeTimer = None
            return #No point in slicing an empty build plate

        self._sendSettings()

        self._scene.acquireLock()

        msg = Cura_pb2.ObjectList()

        #TODO: All at once/one at a time mode
        center = Vector()
        for object in objects:
            center += object.getPosition()

            meshData = object.getMeshData()

            obj = msg.objects.add()
            obj.id = id(object)

            verts = numpy.array(meshData.getVertices(), copy=True)
            verts[:,[1,2]] = verts[:,[2,1]]
            obj.vertices = verts.tostring()

            #if meshData.hasNormals():
                #obj.normals = meshData.getNormalsAsByteArray()

            #if meshData.hasIndices():
                #obj.indices = meshData.getIndicesAsByteArray()

        self._scene.releaseLock()

        center /= float(len(objects))
        if not self._settings.getSettingValueByKey('machine_center_is_zero'):
            center.setX(center.x + self._settings.getSettingValueByKey('machine_width') / 2)
            center.setZ(center.z + self._settings.getSettingValueByKey('machine_depth') / 2)

        posmsg = Cura_pb2.SettingList()
        posX = posmsg.settings.add()
        posX.name = 'position.X'
        posX.value = str(int(center.x * 1000)).encode('utf-8')
        posY = posmsg.settings.add()
        posY.name = 'position.Y'
        posY.value = str(int(center.z * 1000)).encode('utf-8')
        posZ = posmsg.settings.add()
        posZ.name = 'position.Z'
        posZ.value = str(int(0)).encode('utf-8')
        self._socket.sendMessage(posmsg)

        self._center = center

        self._socket.sendMessage(msg)

        self._changeTimer = None

    def _sendSettings(self):
        extruder = 0

        settings = {
            'extruderNr': extruder,
            'layerThickness': int(self._settings.getSettingValueByKey('layer_height') * 1000),
            'initialLayerThickness': int(self._settings.getSettingValueByKey('layer_height_0') * 1000),
            'printTemperature': int(self._settings.getSettingValueByKey('material_print_temperature')),
            'filamentDiameter': int(self._settings.getSettingValueByKey('material_diameter') * 1000),
            'filamentFlow': int(self._settings.getSettingValueByKey('material_flow')),
            'layer0extrusionWidth': int(self._settings.getSettingValueByKey('wall_line_width_0') * 1000),
            'extrusionWidth': int(self._settings.getSettingValueByKey('wall_line_width_x') * 1000),
            'insetCount': int(self._settings.getSettingValueByKey('wall_line_count')),
            'downSkinCount': int(self._settings.getSettingValueByKey('bottom_layers')),
            'upSkinCount': int(self._settings.getSettingValueByKey('top_layers')),
            'skirtDistance': int(self._settings.getSettingValueByKey('skirt_gap') * 1000),
            'skirtLineCount': int(self._settings.getSettingValueByKey('skirt_line_count')),
            'skirtMinLength': int(self._settings.getSettingValueByKey('skirt_minimal_length') * 1000),

            'retractionAmount': int(self._settings.getSettingValueByKey('retraction_amount') * 1000),
            'retractionAmountPrime': int(0 * 1000),
            # 'retractionAmountExtruderSwitch': int(fbk('') * 1000),
            'retractionSpeed': int(self._settings.getSettingValueByKey('retraction_speed')),
            'retractionPrimeSpeed': int(self._settings.getSettingValueByKey('retraction_speed')),
            'retractionMinimalDistance': int(self._settings.getSettingValueByKey('retraction_min_travel') * 1000),
            'minimalExtrusionBeforeRetraction': int(self._settings.getSettingValueByKey('retraction_minimal_extrusion') * 1000),
            'retractionZHop': int(self._settings.getSettingValueByKey('retraction_hop') * 1000),

            'enableCombing': 1 if self._settings.getSettingValueByKey('retraction_combing') else 0,
            # 'enableOozeShield': int(fbk('') * 1000),
            # 'wipeTowerSize': int(fbk('') * 1000),
            # 'multiVolumeOverlap': int(fbk('') * 1000),

            'initialSpeedupLayers': int(self._settings.getSettingValueByKey('speed_slowdown_layers')),
            'initialLayerSpeed': int(self._settings.getSettingValueByKey('speed_layer_0')),
            'skirtSpeed': int(self._settings.getSettingValueByKey('skirt_speed')),
            'inset0Speed': int(self._settings.getSettingValueByKey('speed_wall_0')),
            'insetXSpeed': int(self._settings.getSettingValueByKey('speed_wall_x')),
            'supportSpeed': int(self._settings.getSettingValueByKey('speed_support')),
            'moveSpeed': int(self._settings.getSettingValueByKey('speed_travel')),
            #'fanFullOnLayerNr': int(fbk('cool_fan_full_layer')),

            'infillOverlap': int(self._settings.getSettingValueByKey('fill_overlap')),
            'infillSpeed': int(self._settings.getSettingValueByKey('speed_infill')),

            'minimalLayerTime': int(self._settings.getSettingValueByKey('cool_min_layer_time')),
            'minimalFeedrate': int(self._settings.getSettingValueByKey('cool_min_speed')),
            'coolHeadLift': 1 if self._settings.getSettingValueByKey('cool_lift_head') else 0,
            'fanSpeedMin': self._settings.getSettingValueByKey('cool_fan_speed_min'),
            'fanSpeedMax': self._settings.getSettingValueByKey('cool_fan_speed_max'),

            'spiralizeMode': 1 if self._settings.getSettingValueByKey('magic_spiralize') == 'True' else 0,

        }

        if self._settings.getSettingValueByKey('top_bottom_pattern') == 'lines':
            settings['skinPattern'] = 'SKIN_LINES'
        elif self._settings.getSettingValueByKey('top_bottom_pattern') == 'concentric':
            settings['skinPattern'] = 'SKIN_CONCENTRIC'

        if self._settings.getSettingValueByKey('fill_pattern') == 'Grid':
            settings['infillPattern'] = 'INFILL_GRID'
        elif self._settings.getSettingValueByKey('fill_pattern') == 'Lines':
            settings['infillPattern'] = 'INFILL_LINES'
        elif self._settings.getSettingValueByKey('fill_pattern') == 'concentric':
            settings['infillPattern'] = 'INFILL_CONCENTRIC'

        adhesion_type = self._settings.getSettingValueByKey('adhesion_type')
        if adhesion_type == 'Raft':
            settings['raftMargin'] = int(self._settings.getSettingValueByKey('raft_margin') * 1000)
            settings['raftLineSpacing'] = int(self._settings.getSettingValueByKey('raft_line_spacing') * 1000)
            settings['raftBaseThickness'] = int(self._settings.getSettingValueByKey('raft_base_thickness') * 1000)
            settings['raftBaseLinewidth'] = int(self._settings.getSettingValueByKey('raft_base_linewidth') * 1000)
            settings['raftBaseSpeed'] = int(self._settings.getSettingValueByKey('raft_base_speed') * 1000)
            settings['raftInterfaceThickness'] = int(self._settings.getSettingValueByKey('raft_interface_thickness') * 1000)
            settings['raftInterfaceLinewidth'] = int(self._settings.getSettingValueByKey('raft_interface_linewidth') * 1000)
            settings['raftInterfaceLineSpacing'] = int(self._settings.getSettingValueByKey('raft_line_spacing') * 1000)
            settings['raftFanSpeed'] = 0
            settings['raftSurfaceThickness'] = int(self._settings.getSettingValueByKey('layer_height_0') * 1000)
            settings['raftSurfaceLinewidth'] = int(self._settings.getSettingValueByKey('wall_line_width_x') * 1000)
            settings['raftSurfaceLineSpacing'] = int(self._settings.getSettingValueByKey('wall_line_width_x') * 1000)
            settings['raftSurfaceLayers'] = int(self._settings.getSettingValueByKey('raft_surface_layers'))
            settings['raftSurfaceSpeed'] = int(self._settings.getSettingValueByKey('speed_layer_0') * 1000)
            settings['raftAirGap'] = int(self._settings.getSettingValueByKey('raft_airgap') * 1000)
            settings['skirtLineCount'] = 0
            pass
        elif adhesion_type == 'Brim':
            settings['skirtDistance'] = 0
            settings['skirtLineCount'] = self._settings.getSettingValueByKey('brim_line_count')

        if self._settings.getSettingValueByKey('support_type') == 'None':
            settings['supportType'] = ''
            settings['supportAngle'] = -1
        else:
            settings['areaSupportPolyGenerator'] = 1
            settings['supportType'] = 'LINES'
            settings['supportAngle'] = self._settings.getSettingValueByKey('support_angle')
            settings['supportEverywhere'] = 1 if self._settings.getSettingValueByKey('support_type') == 'Everywhere' else 0
            settings['supportLineDistance'] = int(100 * self._settings.getSettingValueByKey('wall_line_width_x') * 1000 / self._settings.getSettingValueByKey('support_fill_rate'))
            settings['supportXYDistance'] = int(self._settings.getSettingValueByKey('support_xy_distance') * 1000)
            settings['supportZDistance'] = int(self._settings.getSettingValueByKey('support_z_distance') * 1000)
            settings['supportZDistanceBottom'] = int(self._settings.getSettingValueByKey('support_top_distance') * 1000)
            settings['supportZDistanceTop'] = int(self._settings.getSettingValueByKey('support_bottom_distance') * 1000)
            settings['supportJoinDistance'] = int(self._settings.getSettingValueByKey('support_join_distance') * 1000)
            settings['supportBridgeBack'] = int(self._settings.getSettingValueByKey('support_bridge_back'))
            settings['supportExtruder'] = -1
            if self._settings.getSettingValueByKey('support_pattern') == 'Grid':
                settings['supportType'] = 'GRID'
            elif self._settings.getSettingValueByKey('support_pattern') == 'Lines':
                settings['supportType'] = 'LINES'

        settings['sparseInfillLineDistance'] = -1
        if self._settings.getSettingValueByKey('fill_sparse_density') >= 100:
            settings['sparseInfillLineDistance'] = self._settings.getSettingValueByKey('wall_line_width_x')
            settings['downSkinCount'] = 10000
            settings['upSkinCount'] = 10000
        elif self._settings.getSettingValueByKey('fill_sparse_density') > 0:
            settings['sparseInfillLineDistance'] = int(100 * self._settings.getSettingValueByKey('wall_line_width_x') * 1000 / self._settings.getSettingValueByKey('fill_sparse_density'))
        settings['sparseInfillCombineCount'] = int(round(self._settings.getSettingValueByKey('fill_sparse_combine')))

        gcodeFlavor = self._settings.getSettingValueByKey('machine_gcode_flavor')
        if gcodeFlavor == 'UltiGCode':
            settings['gcodeFlavor'] = 1
        elif gcodeFlavor == 'Makerbot':
            settings['gcodeFlavor'] = 2
        elif gcodeFlavor == 'BFB':
            settings['gcodeFlavor'] = 3
        elif gcodeFlavor == 'Mach3':
            settings['gcodeFlavor'] = 4
        elif gcodeFlavor == 'Volumetric':
            settings['gcodeFlavor'] = 5
        else:
            settings['gcodeFlavor'] = 0

        settings['startCode'] = self._settings.getSettingValueByKey('machine_start_gcode')
        settings['endCode'] = self._settings.getSettingValueByKey('machine_end_gcode')

        #for n in range(1, self._machine.getMaxNozzles()):
        n = 1
        settings['extruderOffset1.X'] = int(self._settings.getSettingValueByKey('machine_nozzle_offset_x_1') * 1000)
        settings['extruderOffset1.Y'] = int(self._settings.getSettingValueByKey('machine_nozzle_offset_y_1') * 1000)

        msg = Cura_pb2.SettingList()
        for key, value in settings.items():
            s = msg.settings.add()
            s.name = key
            s.value = str(value).encode('utf-8')

        self._socket.sendMessage(msg)

{'fraction_non_alphanumeric': 0.1179079170470849, 'fraction_numerical': 0.016792748141385157, 'mean_word_length': 3.3837907375643224, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7419689', 'n_tokens_mistral': 9331, 'n_tokens_neox': 8667, 'n_words': 1202}