chiark / gitweb /
Add support angle setting.
[cura.git] / Cura / util / sliceEngine.py
index 4c834e6ac1cb2da62a712258f9abf0e4fd78a9a9..e968009cda6d170815e9a1ba3204d4fb4c2c093a 100644 (file)
@@ -46,7 +46,7 @@ class Slicer(object):
                self._objCount = 0
                self._sliceLog = []
                self._printTimeSeconds = None
-               self._filamentMM = None
+               self._filamentMM = [0.0, 0.0]
                self._modelHash = None
                self._id = 0
 
@@ -83,21 +83,21 @@ class Slicer(object):
        def getID(self):
                return self._id
 
-       def getFilamentWeight(self):
+       def getFilamentWeight(self, e=0):
                #Calculates the weight of the filament in kg
                radius = float(profile.getProfileSetting('filament_diameter')) / 2
-               volumeM3 = (self._filamentMM * (math.pi * radius * radius)) / (1000*1000*1000)
+               volumeM3 = (self._filamentMM[e] * (math.pi * radius * radius)) / (1000*1000*1000)
                return volumeM3 * profile.getPreferenceFloat('filament_physical_density')
 
-       def getFilamentCost(self):
+       def getFilamentCost(self, e=0):
                cost_kg = profile.getPreferenceFloat('filament_cost_kg')
                cost_meter = profile.getPreferenceFloat('filament_cost_meter')
                if cost_kg > 0.0 and cost_meter > 0.0:
-                       return "%.2f / %.2f" % (self.getFilamentWeight() * cost_kg, self._filamentMM / 1000.0 * cost_meter)
+                       return "%.2f / %.2f" % (self.getFilamentWeight(e) * cost_kg, self._filamentMM[e] / 1000.0 * cost_meter)
                elif cost_kg > 0.0:
-                       return "%.2f" % (self.getFilamentWeight() * cost_kg)
+                       return "%.2f" % (self.getFilamentWeight(e) * cost_kg)
                elif cost_meter > 0.0:
-                       return "%.2f" % (self._filamentMM / 1000.0 * cost_meter)
+                       return "%.2f" % (self._filamentMM[e] / 1000.0 * cost_meter)
                return None
 
        def getPrintTime(self):
@@ -107,15 +107,21 @@ class Slicer(object):
                        return '%d hour %d minutes' % (int(self._printTimeSeconds / 60 / 60), int(self._printTimeSeconds / 60) % 60)
                return '%d hours %d minutes' % (int(self._printTimeSeconds / 60 / 60), int(self._printTimeSeconds / 60) % 60)
 
-       def getFilamentAmount(self):
-               return '%0.2f meter %0.0f gram' % (float(self._filamentMM) / 1000.0, self.getFilamentWeight() * 1000.0)
+       def getFilamentAmount(self, e=0):
+               if self._filamentMM[e] == 0.0:
+                       return None
+               return '%0.2f meter %0.0f gram' % (float(self._filamentMM[e]) / 1000.0, self.getFilamentWeight(e) * 1000.0)
 
        def runSlicer(self, scene):
+               if len(scene.objects()) < 1:
+                       return
                extruderCount = 1
                for obj in scene.objects():
                        if scene.checkPlatform(obj):
                                extruderCount = max(extruderCount, len(obj._meshList))
 
+               extruderCount = max(extruderCount, profile.minimalExtruderCount())
+
                commandList = [getEngineFilename(), '-vv']
                for k, v in self._engineSettings(extruderCount).iteritems():
                        commandList += ['-s', '%s=%s' % (k, str(v))]
@@ -127,25 +133,43 @@ class Slicer(object):
                        order = scene.printOrder()
                        if order is None:
                                pos = numpy.array(profile.getMachineCenterCoords()) * 1000
-                               commandList += ['-s', 'posx=%d' % int(pos[0]), '-s', 'posy=%d' % int(pos[1])]
-
-                               vertexTotal = 0
+                               objMin = None
+                               objMax = None
                                for obj in scene.objects():
                                        if scene.checkPlatform(obj):
-                                               for mesh in obj._meshList:
-                                                       vertexTotal += mesh.vertexCount
+                                               oMin = obj.getMinimum()[0:2] + obj.getPosition()
+                                               oMax = obj.getMaximum()[0:2] + obj.getPosition()
+                                               if objMin is None:
+                                                       objMin = oMin
+                                                       objMax = oMax
+                                               else:
+                                                       objMin[0] = min(oMin[0], objMin[0])
+                                                       objMin[1] = min(oMin[1], objMin[1])
+                                                       objMax[0] = max(oMax[0], objMax[0])
+                                                       objMax[1] = max(oMax[1], objMax[1])
+                               pos += (objMin + objMax) / 2.0 * 1000
+                               commandList += ['-s', 'posx=%d' % int(pos[0]), '-s', 'posy=%d' % int(pos[1])]
 
-                               f.write(numpy.array([vertexTotal], numpy.int32).tostring())
+                               vertexTotal = [0] * 4
+                               meshMax = 1
                                for obj in scene.objects():
                                        if scene.checkPlatform(obj):
-                                               for mesh in obj._meshList:
-                                                       vertexes = (numpy.matrix(mesh.vertexes, copy = False) * numpy.matrix(obj._matrix, numpy.float32)).getA()
-                                                       vertexes -= obj._drawOffset
-                                                       vertexes += numpy.array([obj.getPosition()[0], obj.getPosition()[1], 0.0])
-                                                       f.write(vertexes.tostring())
-                                                       hash.update(mesh.vertexes.tostring())
+                                               meshMax = max(meshMax, len(obj._meshList))
+                                               for n in xrange(0, len(obj._meshList)):
+                                                       vertexTotal[n] += obj._meshList[n].vertexCount
 
-                               commandList += ['#']
+                               for n in xrange(0, meshMax):
+                                       f.write(numpy.array([vertexTotal[n]], numpy.int32).tostring())
+                                       for obj in scene.objects():
+                                               if scene.checkPlatform(obj):
+                                                       if n < len(obj._meshList):
+                                                               vertexes = (numpy.matrix(obj._meshList[n].vertexes, copy = False) * numpy.matrix(obj._matrix, numpy.float32)).getA()
+                                                               vertexes -= obj._drawOffset
+                                                               vertexes += numpy.array([obj.getPosition()[0], obj.getPosition()[1], 0.0])
+                                                               f.write(vertexes.tostring())
+                                                               hash.update(obj._meshList[n].vertexes.tostring())
+
+                               commandList += ['#' * meshMax]
                                self._objCount = 1
                        else:
                                for n in order:
@@ -184,7 +208,7 @@ class Slicer(object):
                self._callback(0.0, False)
                self._sliceLog = []
                self._printTimeSeconds = None
-               self._filamentMM = None
+               self._filamentMM = [0.0, 0.0]
 
                line = self._process.stdout.readline()
                objectNr = 0
@@ -208,10 +232,15 @@ class Slicer(object):
                        elif line.startswith('Print time:'):
                                self._printTimeSeconds = int(line.split(':')[1].strip())
                        elif line.startswith('Filament:'):
-                               self._filamentMM = int(line.split(':')[1].strip())
-                               if profile.getPreference('gcode_flavor') == 'UltiGCode':
+                               self._filamentMM[0] = int(line.split(':')[1].strip())
+                               if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
+                                       radius = profile.getProfileSettingFloat('filament_diameter') / 2.0
+                                       self._filamentMM[0] /= (math.pi * radius * radius)
+                       elif line.startswith('Filament2:'):
+                               self._filamentMM[1] = int(line.split(':')[1].strip())
+                               if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
                                        radius = profile.getProfileSettingFloat('filament_diameter') / 2.0
-                                       self._filamentMM /= (math.pi * radius * radius)
+                                       self._filamentMM[1] /= (math.pi * radius * radius)
                        else:
                                self._sliceLog.append(line.strip())
                        line = self._process.stdout.readline()
@@ -243,22 +272,20 @@ class Slicer(object):
                        'insetCount': int(profile.calculateLineCount()),
                        'downSkinCount': int(profile.calculateSolidLayerCount()) if profile.getProfileSetting('solid_bottom') == 'True' else 0,
                        'upSkinCount': int(profile.calculateSolidLayerCount()) if profile.getProfileSetting('solid_top') == 'True' else 0,
-                       'sparseInfillLineDistance': int(100 * profile.calculateEdgeWidth() * 1000 / profile.getProfileSettingFloat('fill_density')) if profile.getProfileSettingFloat('fill_density') > 0 else -1,
                        'infillOverlap': int(profile.getProfileSettingFloat('fill_overlap')),
                        'initialSpeedupLayers': int(4),
                        'initialLayerSpeed': int(profile.getProfileSettingFloat('bottom_layer_speed')),
                        'printSpeed': int(profile.getProfileSettingFloat('print_speed')),
                        'infillSpeed': int(profile.getProfileSettingFloat('infill_speed')) if int(profile.getProfileSettingFloat('infill_speed')) > 0 else int(profile.getProfileSettingFloat('print_speed')),
                        'moveSpeed': int(profile.getProfileSettingFloat('travel_speed')),
-                       'fanOnLayerNr': int(profile.getProfileSettingFloat('fan_layer')),
                        'fanSpeedMin': int(profile.getProfileSettingFloat('fan_speed')) if profile.getProfileSetting('fan_enabled') == 'True' else 0,
                        'fanSpeedMax': int(profile.getProfileSettingFloat('fan_speed_max')) if profile.getProfileSetting('fan_enabled') == 'True' else 0,
-                       'supportAngle': int(-1) if profile.getProfileSetting('support') == 'None' else int(60),
+                       'supportAngle': int(-1) if profile.getProfileSetting('support') == 'None' else int(profile.getProfileSettingFloat('support_angle')),
                        'supportEverywhere': int(1) if profile.getProfileSetting('support') == 'Everywhere' else int(0),
                        'supportLineDistance': int(100 * profile.calculateEdgeWidth() * 1000 / profile.getProfileSettingFloat('support_fill_rate')) if profile.getProfileSettingFloat('support_fill_rate') > 0 else -1,
                        'supportXYDistance': int(1000 * profile.getProfileSettingFloat('support_xy_distance')),
                        'supportZDistance': int(1000 * profile.getProfileSettingFloat('support_z_distance')),
-                       'supportExtruder': 0 if profile.getProfileSetting('support_dual_extrusion') == 'First extruder' else (1 if profile.getProfileSetting('support_dual_extrusion') == 'Second extruder' else -1),
+                       'supportExtruder': 0 if profile.getProfileSetting('support_dual_extrusion') == 'First extruder' else (1 if profile.getProfileSetting('support_dual_extrusion') == 'Second extruder' and profile.minimalExtruderCount() > 1 else -1),
                        'retractionAmount': int(profile.getProfileSettingFloat('retraction_amount') * 1000) if profile.getProfileSetting('retraction_enable') == 'True' else 0,
                        'retractionSpeed': int(profile.getProfileSettingFloat('retraction_speed')),
                        'retractionMinimalDistance': int(profile.getProfileSettingFloat('retraction_min_travel') * 1000),
@@ -273,14 +300,29 @@ class Slicer(object):
                        'startCode': profile.getAlterationFileContents('start.gcode', extruderCount),
                        'endCode': profile.getAlterationFileContents('end.gcode', extruderCount),
 
-                       'extruderOffset[1].X': int(profile.getPreferenceFloat('extruder_offset_x1') * 1000),
-                       'extruderOffset[1].Y': int(profile.getPreferenceFloat('extruder_offset_y1') * 1000),
-                       'extruderOffset[2].X': int(profile.getPreferenceFloat('extruder_offset_x2') * 1000),
-                       'extruderOffset[2].Y': int(profile.getPreferenceFloat('extruder_offset_y2') * 1000),
-                       'extruderOffset[3].X': int(profile.getPreferenceFloat('extruder_offset_x3') * 1000),
-                       'extruderOffset[3].Y': int(profile.getPreferenceFloat('extruder_offset_y3') * 1000),
+                       'extruderOffset[1].X': int(profile.getMachineSettingFloat('extruder_offset_x1') * 1000),
+                       'extruderOffset[1].Y': int(profile.getMachineSettingFloat('extruder_offset_y1') * 1000),
+                       'extruderOffset[2].X': int(profile.getMachineSettingFloat('extruder_offset_x2') * 1000),
+                       'extruderOffset[2].Y': int(profile.getMachineSettingFloat('extruder_offset_y2') * 1000),
+                       'extruderOffset[3].X': int(profile.getMachineSettingFloat('extruder_offset_x3') * 1000),
+                       'extruderOffset[3].Y': int(profile.getMachineSettingFloat('extruder_offset_y3') * 1000),
                        'fixHorrible': 0,
                }
+               fanFullHeight = int(profile.getProfileSettingFloat('fan_full_height') * 1000)
+               settings['fanFullOnLayerNr'] = (fanFullHeight - settings['initialLayerThickness'] - 1) / settings['layerThickness'] + 1
+               if settings['fanFullOnLayerNr'] < 0:
+                       settings['fanFullOnLayerNr'] = 0
+
+               if profile.getProfileSettingFloat('fill_density') == 0:
+                       settings['sparseInfillLineDistance'] = -1
+               elif profile.getProfileSettingFloat('fill_density') == 100:
+                       settings['sparseInfillLineDistance'] = settings['extrusionWidth']
+                       #Set the up/down skins height to 10000 if we want a 100% filled object.
+                       # This gives better results then normal 100% infill as the sparse and up/down skin have some overlap.
+                       settings['downSkinCount'] = 10000
+                       settings['upSkinCount'] = 10000
+               else:
+                       settings['sparseInfillLineDistance'] = int(100 * profile.calculateEdgeWidth() * 1000 / profile.getProfileSettingFloat('fill_density'))
                if profile.getProfileSetting('platform_adhesion') == 'Brim':
                        settings['skirtDistance'] = 0
                        settings['skirtLineCount'] = int(profile.getProfileSettingFloat('brim_line_count'))
@@ -288,6 +330,7 @@ class Slicer(object):
                        settings['skirtDistance'] = 0
                        settings['skirtLineCount'] = 0
                        settings['raftMargin'] = int(profile.getProfileSettingFloat('raft_margin') * 1000)
+                       settings['raftLineSpacing'] = int(profile.getProfileSettingFloat('raft_line_spacing') * 1000)
                        settings['raftBaseThickness'] = int(profile.getProfileSettingFloat('raft_base_thickness') * 1000)
                        settings['raftBaseLinewidth'] = int(profile.getProfileSettingFloat('raft_base_linewidth') * 1000)
                        settings['raftInterfaceThickness'] = int(profile.getProfileSettingFloat('raft_interface_thickness') * 1000)
@@ -295,7 +338,7 @@ class Slicer(object):
                else:
                        settings['skirtDistance'] = int(profile.getProfileSettingFloat('skirt_gap') * 1000)
                        settings['skirtLineCount'] = int(profile.getProfileSettingFloat('skirt_line_count'))
-                       settings['skirtMinLenght'] = int(profile.getProfileSettingFloat('skirt_minimal_length') * 1000)
+                       settings['skirtMinLength'] = int(profile.getProfileSettingFloat('skirt_minimal_length') * 1000)
 
                if profile.getProfileSetting('fix_horrible_union_all_type_a') == 'True':
                        settings['fixHorrible'] |= 0x01
@@ -308,8 +351,14 @@ class Slicer(object):
 
                if settings['layerThickness'] <= 0:
                        settings['layerThickness'] = 1000
-               if profile.getPreference('gcode_flavor') == 'UltiGCode':
+               if profile.getMachineSetting('gcode_flavor') == 'UltiGCode':
                        settings['gcodeFlavor'] = 1
+               if profile.getProfileSetting('spiralize') == 'True':
+                       settings['spiralizeMode'] = 1
+               if profile.getProfileSetting('wipe_tower') == 'True':
+                       settings['wipeTowerSize'] = int(math.sqrt(profile.getProfileSettingFloat('wipe_tower_volume') * 1000 * 1000 * 1000 / settings['layerThickness']))
+               if profile.getProfileSetting('ooze_shield') == 'True':
+                       settings['enableOozeShield'] = 1
                return settings
 
        def _runSliceProcess(self, cmdList):
@@ -331,8 +380,8 @@ class Slicer(object):
                        'processor': platform.processor(),
                        'machine': platform.machine(),
                        'platform': platform.platform(),
-                       'profile': profile.getGlobalProfileString(),
-                       'preferences': profile.getGlobalPreferencesString(),
+                       'profile': profile.getProfileString(),
+                       'preferences': profile.getPreferencesString(),
                        'modelhash': self._modelHash,
                        'version': version.getVersion(),
                }