public void WriteRaftGCodeIfRequired(ConfigSettings config, GCodeExport gcode) { LayerDataStorage storage = this; if (config.ShouldGenerateRaft()) { GCodePathConfig raftBaseConfig = new GCodePathConfig(config.firstLayerSpeed, config.raftBaseExtrusionWidth_um, "SUPPORT"); GCodePathConfig raftMiddleConfig = new GCodePathConfig(config.raftPrintSpeed, config.raftInterfaceExtrusionWidth_um, "SUPPORT"); GCodePathConfig raftSurfaceConfig = new GCodePathConfig((config.raftSurfacePrintSpeed > 0) ? config.raftSurfacePrintSpeed : config.raftPrintSpeed, config.raftSurfaceExtrusionWidth_um, "SUPPORT"); // create the raft base { gcode.WriteComment("LAYER:-3"); gcode.WriteComment("RAFT BASE"); GCodePlanner gcodeLayer = new GCodePlanner(gcode, config.travelSpeed, config.minimumTravelToCauseRetraction_um); if (config.raftExtruder >= 0) { // if we have a specified raft extruder use it gcodeLayer.SetExtruder(config.raftExtruder); } else if (config.supportExtruder >= 0) { // else preserve the old behavior of using the support extruder if set. gcodeLayer.SetExtruder(config.supportExtruder); } gcode.setZ(config.raftBaseThickness_um); gcode.SetExtrusion(config.raftBaseThickness_um, config.filamentDiameter_um, config.extrusionMultiplier); Polygons raftLines = new Polygons(); Infill.GenerateLinePaths(storage.raftOutline, ref raftLines, config.raftBaseLineSpacing_um, config.infillExtendIntoPerimeter_um, 0); // write the skirt around the raft gcodeLayer.QueuePolygonsByOptimizer(storage.skirt, raftBaseConfig); // write the outline of the raft gcodeLayer.QueuePolygonsByOptimizer(storage.raftOutline, raftBaseConfig); // write the inside of the raft base gcodeLayer.QueuePolygonsByOptimizer(raftLines, raftBaseConfig); gcodeLayer.WriteQueuedGCode(config.raftBaseThickness_um); } if (config.raftFanSpeedPercent > 0) { gcode.WriteFanCommand(config.raftFanSpeedPercent); } // raft middle layers { gcode.WriteComment("LAYER:-2"); gcode.WriteComment("RAFT MIDDLE"); GCodePlanner gcodeLayer = new GCodePlanner(gcode, config.travelSpeed, config.minimumTravelToCauseRetraction_um); gcode.setZ(config.raftBaseThickness_um + config.raftInterfaceThicknes_um); gcode.SetExtrusion(config.raftInterfaceThicknes_um, config.filamentDiameter_um, config.extrusionMultiplier); Polygons raftLines = new Polygons(); Infill.GenerateLinePaths(storage.raftOutline, ref raftLines, config.raftInterfaceLineSpacing_um, config.infillExtendIntoPerimeter_um, 45); gcodeLayer.QueuePolygonsByOptimizer(raftLines, raftMiddleConfig); gcodeLayer.WriteQueuedGCode(config.raftInterfaceThicknes_um); } for (int raftSurfaceIndex = 1; raftSurfaceIndex <= config.raftSurfaceLayers; raftSurfaceIndex++) { gcode.WriteComment("LAYER:-1"); gcode.WriteComment("RAFT SURFACE"); GCodePlanner gcodeLayer = new GCodePlanner(gcode, config.travelSpeed, config.minimumTravelToCauseRetraction_um); gcode.setZ(config.raftBaseThickness_um + config.raftInterfaceThicknes_um + config.raftSurfaceThickness_um * raftSurfaceIndex); gcode.SetExtrusion(config.raftSurfaceThickness_um, config.filamentDiameter_um, config.extrusionMultiplier); Polygons raftLines = new Polygons(); if (raftSurfaceIndex == config.raftSurfaceLayers) { // make sure the top layer of the raft is 90 degrees offset to the first layer of the part so that it has minimum contact points. Infill.GenerateLinePaths(storage.raftOutline, ref raftLines, config.raftSurfaceLineSpacing_um, config.infillExtendIntoPerimeter_um, config.infillStartingAngle + 90); } else { Infill.GenerateLinePaths(storage.raftOutline, ref raftLines, config.raftSurfaceLineSpacing_um, config.infillExtendIntoPerimeter_um, 90 * raftSurfaceIndex); } gcodeLayer.QueuePolygonsByOptimizer(raftLines, raftSurfaceConfig); gcodeLayer.WriteQueuedGCode(config.raftInterfaceThicknes_um); } } }
private void writeGCode(LayerDataStorage slicingData) { 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 (fileNumber == 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); } else { gcode.WriteFanCommand(0); gcode.ResetExtrusionValue(); gcode.WriteRetraction(); gcode.setZ(maxObjectHeight + 5000); gcode.WriteMove(gcode.GetPosition(), config.travelSpeed, 0); gcode.WriteMove(new Point3(slicingData.modelMin.x, slicingData.modelMin.y, gcode.CurrentZ), config.travelSpeed, 0); } fileNumber++; int totalLayers = slicingData.Extruders[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 (ExtruderLayers currentExtruder in slicingData.Extruders) { SliceLayer currentLayer = currentExtruder.Layers[layerIndex]; for (int partIndex = 0; partIndex < currentExtruder.Layers[layerIndex].Islands.Count; partIndex++) { LayerIsland currentIsland = currentLayer.Islands[partIndex]; if (currentIsland.IslandOutline.Count > 0) { layerHasData = true; break; } } } if (layerHasData) { break; } totalLayers--; } } gcode.WriteComment("Layer count: {0}".FormatWith(totalLayers)); // keep the raft generation code inside of raft slicingData.WriteRaftGCodeIfRequired(config, gcode); 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); if (layerIndex == 0) { skirtConfig.SetData(config.firstLayerSpeed, config.firstLayerExtrusionWidth_um, "SKIRT"); inset0Config.SetData(config.firstLayerSpeed, config.firstLayerExtrusionWidth_um, "WALL-OUTER"); insetXConfig.SetData(config.firstLayerSpeed, config.firstLayerExtrusionWidth_um, "WALL-INNER"); fillConfig.SetData(config.firstLayerSpeed, config.firstLayerExtrusionWidth_um, "FILL", false); topFillConfig.SetData(config.firstLayerSpeed, config.firstLayerExtrusionWidth_um, "TOP-FILL", false); bottomFillConfig.SetData(config.firstLayerSpeed, config.firstLayerExtrusionWidth_um, "BOTTOM-FILL", false); bridgConfig.SetData(config.firstLayerSpeed, config.firstLayerExtrusionWidth_um, "BRIDGE"); supportNormalConfig.SetData(config.firstLayerSpeed, config.supportExtrusionWidth_um, "SUPPORT"); supportInterfaceConfig.SetData(config.firstLayerSpeed, config.extrusionWidth_um, "SUPPORT-INTERFACE"); } else { skirtConfig.SetData(config.insidePerimetersSpeed, config.extrusionWidth_um, "SKIRT"); inset0Config.SetData(config.outsidePerimeterSpeed, config.outsideExtrusionWidth_um, "WALL-OUTER"); insetXConfig.SetData(config.insidePerimetersSpeed, config.extrusionWidth_um, "WALL-INNER"); fillConfig.SetData(config.infillSpeed, config.extrusionWidth_um, "FILL", false); topFillConfig.SetData(config.topInfillSpeed, config.firstLayerExtrusionWidth_um, "TOP-FILL", false); bottomFillConfig.SetData(config.infillSpeed, config.firstLayerExtrusionWidth_um, "BOTTOM-FILL", false); bridgConfig.SetData(config.bridgeSpeed, config.extrusionWidth_um, "BRIDGE"); supportNormalConfig.SetData(config.supportMaterialSpeed, config.supportExtrusionWidth_um, "SUPPORT"); supportInterfaceConfig.SetData(config.supportMaterialSpeed - 5, 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); // We only create the skirt if we are on layer 0. if (layerIndex == 0 && !config.ShouldGenerateRaft()) { QueueSkirtToGCode(slicingData, gcodeLayer, layerIndex); } if (slicingData.support != null) { slicingData.support.QueueNormalSupportLayer(config, gcodeLayer, layerIndex, supportNormalConfig, supportInterfaceConfig); } int fanSpeedPercent = GetFanSpeed(layerIndex, gcodeLayer); for (int extruderIndex = 0; extruderIndex < slicingData.Extruders.Count; extruderIndex++) { if (layerIndex == 0) { QueueExtruderLayerToGCode(slicingData, gcodeLayer, extruderIndex, layerIndex, config.firstLayerExtrusionWidth_um, fanSpeedPercent, z); } else { QueueExtruderLayerToGCode(slicingData, gcodeLayer, extruderIndex, layerIndex, config.extrusionWidth_um, fanSpeedPercent, z); } } if (slicingData.support != null) { z += config.supportAirGap_um; gcode.setZ(z); for (int extruderIndex = 0; extruderIndex < slicingData.Extruders.Count; extruderIndex++) { QueueAirGappedExtruderLayerToGCode(slicingData, gcodeLayer, extruderIndex, layerIndex, config.extrusionWidth_um, fanSpeedPercent, z); } slicingData.support.QueueAirGappedBottomLayer(config, gcodeLayer, layerIndex, supportNormalConfig); } //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.WriteQueuedGCode(currentLayerThickness_um); } LogOutput.Log("Wrote layers in {0:0.00}s.\n".FormatWith(timeKeeper.Elapsed.TotalSeconds)); 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, slicingData.modelSize.z); }
public void WriteRaftGCodeIfRequired(GCodeExport gcode, ConfigSettings config) { LayerDataStorage storage = this; if (config.ShouldGenerateRaft()) { GCodePathConfig raftBaseConfig = new GCodePathConfig("raftBaseConfig"); raftBaseConfig.SetData(config.FirstLayerSpeed, config.RaftBaseExtrusionWidth_um, "SUPPORT"); GCodePathConfig raftMiddleConfig = new GCodePathConfig("raftMiddleConfig"); raftMiddleConfig.SetData(config.RaftPrintSpeed, config.RaftInterfaceExtrusionWidth_um, "SUPPORT"); GCodePathConfig raftSurfaceConfig = new GCodePathConfig("raftMiddleConfig"); raftSurfaceConfig.SetData((config.RaftSurfacePrintSpeed > 0) ? config.RaftSurfacePrintSpeed : config.RaftPrintSpeed, config.RaftSurfaceExtrusionWidth_um, "SUPPORT"); // create the raft base { gcode.WriteComment("RAFT BASE"); GCodePlanner gcodeLayer = new GCodePlanner(gcode, config.TravelSpeed, config.MinimumTravelToCauseRetraction_um, config.PerimeterStartEndOverlapRatio); if (config.RaftExtruder >= 0) { // if we have a specified raft extruder use it gcodeLayer.SetExtruder(config.RaftExtruder); } else if (config.SupportExtruder >= 0) { // else preserve the old behavior of using the support extruder if set. gcodeLayer.SetExtruder(config.SupportExtruder); } gcode.SetZ(config.RaftBaseThickness_um); gcode.LayerChanged(-3); gcode.SetExtrusion(config.RaftBaseThickness_um, config.FilamentDiameter_um, config.ExtrusionMultiplier); // write the skirt around the raft gcodeLayer.QueuePolygonsByOptimizer(storage.skirt, raftBaseConfig); List <Polygons> raftIslands = storage.raftOutline.ProcessIntoSeparatIslands(); foreach (var raftIsland in raftIslands) { // write the outline of the raft gcodeLayer.QueuePolygonsByOptimizer(raftIsland, raftBaseConfig); Polygons raftLines = new Polygons(); Infill.GenerateLinePaths(raftIsland.Offset(-config.RaftBaseExtrusionWidth_um), raftLines, config.RaftBaseLineSpacing_um, config.InfillExtendIntoPerimeter_um, 0); // write the inside of the raft base gcodeLayer.QueuePolygonsByOptimizer(raftLines, raftBaseConfig); if (config.RetractWhenChangingIslands) { gcodeLayer.ForceRetract(); } } gcodeLayer.WriteQueuedGCode(config.RaftBaseThickness_um); } if (config.RaftFanSpeedPercent > 0) { gcode.WriteFanCommand(config.RaftFanSpeedPercent); } // raft middle layers { gcode.WriteComment("RAFT MIDDLE"); GCodePlanner gcodeLayer = new GCodePlanner(gcode, config.TravelSpeed, config.MinimumTravelToCauseRetraction_um, config.PerimeterStartEndOverlapRatio); gcode.SetZ(config.RaftBaseThickness_um + config.RaftInterfaceThicknes_um); gcode.LayerChanged(-2); gcode.SetExtrusion(config.RaftInterfaceThicknes_um, config.FilamentDiameter_um, config.ExtrusionMultiplier); Polygons raftLines = new Polygons(); Infill.GenerateLinePaths(storage.raftOutline, raftLines, config.RaftInterfaceLineSpacing_um, config.InfillExtendIntoPerimeter_um, 45); gcodeLayer.QueuePolygonsByOptimizer(raftLines, raftMiddleConfig); gcodeLayer.WriteQueuedGCode(config.RaftInterfaceThicknes_um); } for (int raftSurfaceIndex = 1; raftSurfaceIndex <= config.RaftSurfaceLayers; raftSurfaceIndex++) { gcode.WriteComment("RAFT SURFACE"); GCodePlanner gcodeLayer = new GCodePlanner(gcode, config.TravelSpeed, config.MinimumTravelToCauseRetraction_um, config.PerimeterStartEndOverlapRatio); gcode.SetZ(config.RaftBaseThickness_um + config.RaftInterfaceThicknes_um + config.RaftSurfaceThickness_um * raftSurfaceIndex); gcode.LayerChanged(-1); gcode.SetExtrusion(config.RaftSurfaceThickness_um, config.FilamentDiameter_um, config.ExtrusionMultiplier); Polygons raftLines = new Polygons(); if (raftSurfaceIndex == config.RaftSurfaceLayers) { // make sure the top layer of the raft is 90 degrees offset to the first layer of the part so that it has minimum contact points. Infill.GenerateLinePaths(storage.raftOutline, raftLines, config.RaftSurfaceLineSpacing_um, config.InfillExtendIntoPerimeter_um, config.InfillStartingAngle + 90); } else { Infill.GenerateLinePaths(storage.raftOutline, raftLines, config.RaftSurfaceLineSpacing_um, config.InfillExtendIntoPerimeter_um, 90 * raftSurfaceIndex); } gcodeLayer.QueuePolygonsByOptimizer(raftLines, raftSurfaceConfig); gcodeLayer.WriteQueuedGCode(config.RaftInterfaceThicknes_um); } } }
private void writeGCode(LayerDataStorage slicingData) { 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 (fileNumber == 1) { gcode.WriteCode(config.StartCode); } else { gcode.WriteFanCommand(0); gcode.ResetExtrusionValue(); gcode.WriteRetraction(); gcode.setZ(maxObjectHeight + 5000); gcode.WriteMove(gcode.GetPosition(), config.TravelSpeed, 0); gcode.WriteMove(new Point3(slicingData.modelMin.x, slicingData.modelMin.y, gcode.CurrentZ), config.TravelSpeed, 0); } fileNumber++; int totalLayers = slicingData.Extruders[0].Layers.Count; if (config.outputOnlyFirstLayer) { totalLayers = 1; } // let's remove any of the layers on top that are empty { for (int layerIndex = totalLayers - 1; layerIndex >= 0; layerIndex--) { bool layerHasData = false; foreach (ExtruderLayers currentExtruder in slicingData.Extruders) { SliceLayer currentLayer = currentExtruder.Layers[layerIndex]; for (int partIndex = 0; partIndex < currentExtruder.Layers[layerIndex].Islands.Count; partIndex++) { LayerIsland currentIsland = currentLayer.Islands[partIndex]; if (currentIsland.IslandOutline.Count > 0) { layerHasData = true; break; } } } if (layerHasData) { break; } totalLayers--; } } gcode.WriteComment("Layer count: {0}".FormatWith(totalLayers)); // keep the raft generation code inside of raft slicingData.WriteRaftGCodeIfRequired(gcode, config); for (int layerIndex = 0; layerIndex < totalLayers; layerIndex++) { if (MatterSlice.Canceled) { return; } if(config.outputOnlyFirstLayer && layerIndex > 0) { break; } LogOutput.Log("Writing Layers {0}/{1}\n".FormatWith(layerIndex + 1, totalLayers)); LogOutput.logProgress("export", layerIndex + 1, totalLayers); if (layerIndex == 0) { skirtConfig.SetData(config.FirstLayerSpeed, config.FirstLayerExtrusionWidth_um, "SKIRT"); inset0Config.SetData(config.FirstLayerSpeed, config.FirstLayerExtrusionWidth_um, "WALL-OUTER"); insetXConfig.SetData(config.FirstLayerSpeed, config.FirstLayerExtrusionWidth_um, "WALL-INNER"); fillConfig.SetData(config.FirstLayerSpeed, config.FirstLayerExtrusionWidth_um, "FILL", false); topFillConfig.SetData(config.FirstLayerSpeed, config.FirstLayerExtrusionWidth_um, "TOP-FILL", false); bottomFillConfig.SetData(config.FirstLayerSpeed, config.FirstLayerExtrusionWidth_um, "BOTTOM-FILL", false); airGappedBottomConfig.SetData(config.FirstLayerSpeed, config.FirstLayerExtrusionWidth_um, "AIR-GAP", false); bridgeConfig.SetData(config.FirstLayerSpeed, config.FirstLayerExtrusionWidth_um, "BRIDGE"); supportNormalConfig.SetData(config.FirstLayerSpeed, config.SupportExtrusionWidth_um, "SUPPORT"); supportInterfaceConfig.SetData(config.FirstLayerSpeed, config.ExtrusionWidth_um, "SUPPORT-INTERFACE"); } else { skirtConfig.SetData(config.InsidePerimetersSpeed, config.ExtrusionWidth_um, "SKIRT"); inset0Config.SetData(config.OutsidePerimeterSpeed, config.OutsideExtrusionWidth_um, "WALL-OUTER"); insetXConfig.SetData(config.InsidePerimetersSpeed, config.ExtrusionWidth_um, "WALL-INNER"); fillConfig.SetData(config.InfillSpeed, config.ExtrusionWidth_um, "FILL", false); topFillConfig.SetData(config.TopInfillSpeed, config.ExtrusionWidth_um, "TOP-FILL", false); bottomFillConfig.SetData(config.InfillSpeed, config.ExtrusionWidth_um, "BOTTOM-FILL", false); airGappedBottomConfig.SetData(config.FirstLayerSpeed, config.ExtrusionWidth_um, "AIR-GAP", false); bridgeConfig.SetData(config.BridgeSpeed, config.ExtrusionWidth_um, "BRIDGE"); supportNormalConfig.SetData(config.SupportMaterialSpeed, config.SupportExtrusionWidth_um, "SUPPORT"); supportInterfaceConfig.SetData(config.FirstLayerSpeed - 1, 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, config.PerimeterStartEndOverlapRatio); if (layerIndex == 0 && config.RetractionZHop > 0) { gcodeLayer.ForceRetract(); } // 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); // We only create the skirt if we are on layer 0. if (layerIndex == 0 && !config.ShouldGenerateRaft()) { QueueSkirtToGCode(slicingData, gcodeLayer, layerIndex); } int fanSpeedPercent = GetFanSpeed(layerIndex, gcodeLayer); for (int extruderIndex = 0; extruderIndex < config.MaxExtruderCount(); extruderIndex++) { int prevExtruder = gcodeLayer.GetExtruder(); bool extruderChanged = gcodeLayer.SetExtruder(extruderIndex); if (extruderChanged) { slicingData.PrimeOnWipeTower(extruderIndex, layerIndex, gcodeLayer, fillConfig, config); //Make sure we wipe the old extruder on the wipe tower. gcodeLayer.QueueTravel(slicingData.wipePoint - config.ExtruderOffsets[prevExtruder] + config.ExtruderOffsets[gcodeLayer.GetExtruder()]); } if (layerIndex == 0) { QueueExtruderLayerToGCode(slicingData, gcodeLayer, extruderIndex, layerIndex, config.FirstLayerExtrusionWidth_um, z); } else { QueueExtruderLayerToGCode(slicingData, gcodeLayer, extruderIndex, layerIndex, config.ExtrusionWidth_um, z); } if (slicingData.support != null) { if ((config.SupportExtruder <= 0 && extruderIndex == 0) || config.SupportExtruder == extruderIndex) { slicingData.support.QueueNormalSupportLayer(config, gcodeLayer, layerIndex, supportNormalConfig); } if ((config.SupportInterfaceExtruder <= 0 && extruderIndex == 0) || config.SupportInterfaceExtruder == extruderIndex) { slicingData.support.QueueInterfaceSupportLayer(config, gcodeLayer, layerIndex, supportInterfaceConfig); } } } slicingData.EnsureWipeTowerIsSolid(layerIndex, gcodeLayer, fillConfig, config); if (slicingData.support != null) { z += config.SupportAirGap_um; gcode.setZ(z); gcodeLayer.QueueTravel(gcodeLayer.LastPosition); for (int extruderIndex = 0; extruderIndex < slicingData.Extruders.Count; extruderIndex++) { QueueAirGappedExtruderLayerToGCode(slicingData, gcodeLayer, extruderIndex, layerIndex, config.ExtrusionWidth_um, z); } slicingData.support.QueueAirGappedBottomLayer(config, gcodeLayer, layerIndex, airGappedBottomConfig); } //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; } // Move to the best point for the next layer if (!config.ContinuousSpiralOuterPerimeter && layerIndex > 0 && layerIndex < totalLayers - 2) { // Figure out where the seam hiding start point is for inset 0 and move to that spot so // we have the minimum travel while starting inset 0 after printing the rest of the insets SliceLayer layer = slicingData?.Extruders?[0]?.Layers?[layerIndex + 1]; if (layer.Islands.Count == 1) { LayerIsland island = layer?.Islands?[0]; if (island?.InsetToolPaths?[0]?[0]?.Count > 0) { int bestPoint = PathOrderOptimizer.GetBestIndex(island.InsetToolPaths[0][0], config.ExtrusionWidth_um); gcodeLayer.SetOuterPerimetersToAvoidCrossing(island.AvoidCrossingBoundary); gcodeLayer.QueueTravel(island.InsetToolPaths[0][0][bestPoint]); // Now move up to the next layer so we don't start the extrusion one layer too low. gcode.setZ(z + config.LayerThickness_um); gcodeLayer.QueueTravel(island.InsetToolPaths[0][0][bestPoint]); } } } gcodeLayer.WriteQueuedGCode(currentLayerThickness_um, fanSpeedPercent, config.BridgeFanSpeedPercent); } LogOutput.Log("Wrote layers in {0:0.00}s.\n".FormatWith(timeKeeper.Elapsed.TotalSeconds)); 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, slicingData.modelSize.z); }