public GCodePlanner(GCodeExport gcode, int travelSpeed, int retractionMinimumDistance) { this.gcode = gcode; travelConfig = new GCodePathConfig(travelSpeed, 0, "travel"); lastPosition = gcode.getPositionXY(); outerPerimetersToAvoidCrossing = null; extrudeSpeedFactor = 100; travelSpeedFactor = 100; extraTime = 0.0; totalPrintTime = 0.0; forceRetraction = false; alwaysRetract = false; currentExtruderIndex = gcode.getExtruderIndex(); this.retractionMinimumDistance = retractionMinimumDistance; }
public void forceMinimumLayerTime(double minTime, int minimumPrintingSpeed) { IntPoint lastPosition = gcode.getPositionXY(); double travelTime = 0.0; double extrudeTime = 0.0; for (int n = 0; n < paths.Count; n++) { GCodePath path = paths[n]; for (int pointIndex = 0; pointIndex < path.points.Count; pointIndex++) { IntPoint currentPosition = path.points[pointIndex]; double thisTime = (lastPosition - currentPosition).LengthMm() / (double)(path.config.speed); if (path.config.lineWidth != 0) { extrudeTime += thisTime; } else { travelTime += thisTime; } lastPosition = currentPosition; } } double totalTime = extrudeTime + travelTime; if (totalTime < minTime && extrudeTime > 0.0) { double minExtrudeTime = minTime - travelTime; if (minExtrudeTime < 1) { minExtrudeTime = 1; } double factor = extrudeTime / minExtrudeTime; for (int n = 0; n < paths.Count; n++) { GCodePath path = paths[n]; if (path.config.lineWidth == 0) { continue; } int speed = (int)(path.config.speed * factor); if (speed < minimumPrintingSpeed) { factor = (double)(minimumPrintingSpeed) / (double)(path.config.speed); } } //Only slow down with the minimum time if that will be slower then a factor already set. First layer slowdown also sets the speed factor. if (factor * 100 < getExtrudeSpeedFactor()) { setExtrudeSpeedFactor((int)(factor * 100)); } else { factor = getExtrudeSpeedFactor() / 100.0; } if (minTime - (extrudeTime / factor) - travelTime > 0.1) { //TODO: Use up this extra time (circle around the print?) this.extraTime = minTime - (extrudeTime / factor) - travelTime; } this.totalPrintTime = (extrudeTime / factor) + travelTime; } else { this.totalPrintTime = totalTime; } }
void writeGCode(SliceDataStorage storage) { gcode.writeComment("filamentDiameter = {0}".FormatWith(config.filamentDiameter)); gcode.writeComment("extrusionWidth = {0}".FormatWith(config.extrusionWidth)); gcode.writeComment("firstLayerExtrusionWidth = {0}".FormatWith(config.firstLayerExtrusionWidth)); gcode.writeComment("layerThickness = {0}".FormatWith(config.layerThickness)); gcode.writeComment("firstLayerThickness = {0}".FormatWith(config.firstLayerThickness)); if (fileNr == 1) { if (gcode.GetOutputType() == ConfigConstants.OUTPUT_TYPE.ULTIGCODE) { gcode.writeComment("TYPE:UltiGCode"); gcode.writeComment("TIME:<__TIME__>"); gcode.writeComment("MATERIAL:<FILAMENT>"); gcode.writeComment("MATERIAL2:<FILAMEN2>"); } gcode.writeCode(config.startCode); if (gcode.GetOutputType() == ConfigConstants.OUTPUT_TYPE.BFB) { gcode.writeComment("enable auto-retraction"); gcode.writeLine("M227 S{0} P{1}".FormatWith(config.retractionOnTravel * 2560, config.retractionOnTravel * 2560)); } } else { gcode.writeFanCommand(0); gcode.resetExtrusionValue(); gcode.writeRetraction(); gcode.setZ(maxObjectHeight + 5000); gcode.writeMove(gcode.getPositionXY(), config.travelSpeed, 0); gcode.writeMove(new IntPoint(storage.modelMin.x, storage.modelMin.y), config.travelSpeed, 0); } fileNr++; int totalLayers = storage.volumes[0].layers.Count; // let's remove any of the layers on top that are empty { for (int layerIndex = totalLayers - 1; layerIndex >= 0; layerIndex--) { bool layerHasData = false; foreach (SliceVolumeStorage currentVolume in storage.volumes) { SliceLayer currentLayer = currentVolume.layers[layerIndex]; for (int partIndex = 0; partIndex < currentVolume.layers[layerIndex].parts.Count; partIndex++) { SliceLayerPart currentPart = currentLayer.parts[partIndex]; if (currentPart.outline.Count > 0) { layerHasData = true; break; } } } if (layerHasData) { break; } totalLayers--; } } gcode.writeComment("Layer count: {0}".FormatWith(totalLayers)); // keep the raft generation code inside of raft Raft.GenerateRaftGCodeIfRequired(storage, config, gcode); int volumeIdx = 0; for (int layerIndex = 0; layerIndex < totalLayers; layerIndex++) { if (MatterSlice.Canceled) { return; } LogOutput.log("Writing Layers {0}/{1}\n".FormatWith(layerIndex + 1, totalLayers)); LogOutput.logProgress("export", layerIndex + 1, totalLayers); int extrusionWidth_um = config.extrusionWidth_um; if (layerIndex == 0) { extrusionWidth_um = config.firstLayerExtrusionWidth_um; } if (layerIndex == 0) { skirtConfig.setData(config.firstLayerSpeed, extrusionWidth_um, "SKIRT"); inset0Config.setData(config.firstLayerSpeed, extrusionWidth_um, "WALL-OUTER"); insetXConfig.setData(config.firstLayerSpeed, extrusionWidth_um, "WALL-INNER"); fillConfig.setData(config.firstLayerSpeed, extrusionWidth_um, "FILL", false); bridgConfig.setData(config.firstLayerSpeed, extrusionWidth_um, "BRIDGE"); supportNormalConfig.setData(config.firstLayerSpeed, config.supportExtrusionWidth_um, "SUPPORT"); supportInterfaceConfig.setData(config.firstLayerSpeed, config.extrusionWidth_um, "SUPPORT-INTERFACE"); } else { skirtConfig.setData(config.insidePerimetersSpeed, extrusionWidth_um, "SKIRT"); inset0Config.setData(config.outsidePerimeterSpeed, extrusionWidth_um, "WALL-OUTER"); insetXConfig.setData(config.insidePerimetersSpeed, extrusionWidth_um, "WALL-INNER"); fillConfig.setData(config.infillSpeed, extrusionWidth_um, "FILL", false); bridgConfig.setData(config.bridgeSpeed, extrusionWidth_um, "BRIDGE"); supportNormalConfig.setData(config.supportMaterialSpeed, config.supportExtrusionWidth_um, "SUPPORT"); supportInterfaceConfig.setData(config.supportMaterialSpeed, config.extrusionWidth_um, "SUPPORT-INTERFACE"); } gcode.writeComment("LAYER:{0}".FormatWith(layerIndex)); if (layerIndex == 0) { gcode.setExtrusion(config.firstLayerThickness_um, config.filamentDiameter_um, config.extrusionMultiplier); } else { gcode.setExtrusion(config.layerThickness_um, config.filamentDiameter_um, config.extrusionMultiplier); } GCodePlanner gcodeLayer = new GCodePlanner(gcode, config.travelSpeed, config.minimumTravelToCauseRetraction_um); // get the correct height for this layer int z = config.firstLayerThickness_um + layerIndex * config.layerThickness_um; if (config.enableRaft) { z += config.raftBaseThickness_um + config.raftInterfaceThicknes_um + config.raftSurfaceLayers * config.raftSurfaceThickness_um; if (layerIndex == 0) { // We only raise the first layer of the print up by the air gap. // To give it: // Less press into the raft // More time to cool // more surface area to air while extruding z += config.raftAirGap_um; } } gcode.setZ(z); bool printSupportFirst = (storage.support.generated && config.supportExtruder > 0 && config.supportExtruder == gcodeLayer.getExtruder()); if (printSupportFirst) { AddSupportToGCode(storage, gcodeLayer, layerIndex, config); } int fanSpeedPercent = GetFanSpeed(layerIndex, gcodeLayer); for (int volumeCnt = 0; volumeCnt < storage.volumes.Count; volumeCnt++) { if (volumeCnt > 0) { volumeIdx = (volumeIdx + 1) % storage.volumes.Count; } AddVolumeLayerToGCode(storage, gcodeLayer, volumeIdx, layerIndex, extrusionWidth_um, fanSpeedPercent); } if (!printSupportFirst) { AddSupportToGCode(storage, gcodeLayer, layerIndex, config); } //Finish the layer by applying speed corrections for minimum layer times. gcodeLayer.forceMinimumLayerTime(config.minimumLayerTimeSeconds, config.minimumPrintingSpeed); gcode.writeFanCommand(fanSpeedPercent); int currentLayerThickness_um = config.layerThickness_um; if (layerIndex <= 0) { currentLayerThickness_um = config.firstLayerThickness_um; } gcodeLayer.writeGCode(config.doCoolHeadLift, currentLayerThickness_um); } LogOutput.log("Wrote layers in {0:0.00}s.\n".FormatWith(timeKeeper.Elapsed.Seconds)); timeKeeper.Restart(); gcode.tellFileSize(); gcode.writeFanCommand(0); //Store the object height for when we are printing multiple objects, as we need to clear every one of them when moving to the next position. maxObjectHeight = Math.Max(maxObjectHeight, storage.modelSize.z); }