public bool SetTargetFile(string filename) { gcode.SetFilename(filename); { gcode.WriteComment("Generated with TeethControl {0}".FormatWith(ConfigConstants.VERSION)); } return(gcode.IsOpened()); }
public void WriteQueuedGCode(int layerThickness, int fanSpeedPercent = -1, int bridgeFanSpeedPercent = -1) { GCodePathConfig lastConfig = null; int extruderIndex = gcodeExport.GetExtruderIndex(); for (int pathIndex = 0; pathIndex < paths.Count; pathIndex++) { GCodePath path = paths[pathIndex]; if (extruderIndex != path.extruderIndex) { extruderIndex = path.extruderIndex; gcodeExport.SwitchExtruder(extruderIndex); } else if (path.Retract) { gcodeExport.WriteRetraction(); } if (path.config != travelConfig && lastConfig != path.config) { if (path.config.gcodeComment == "BRIDGE" && bridgeFanSpeedPercent != -1) { gcodeExport.WriteFanCommand(bridgeFanSpeedPercent); } else if (lastConfig?.gcodeComment == "BRIDGE" && bridgeFanSpeedPercent != -1) { gcodeExport.WriteFanCommand(fanSpeedPercent); } gcodeExport.WriteComment("TYPE:{0}".FormatWith(path.config.gcodeComment)); lastConfig = path.config; } double speed = path.config.speed; if (path.config.lineWidth_um != 0) { // Prevent cooling overrides from affecting bridge moves if (path.config.gcodeComment != "BRIDGE") { speed = speed * extrudeSpeedFactor / 100; } } else { speed = speed * travelSpeedFactor / 100; } if (path.points.Count == 1 && path.config != travelConfig && (gcodeExport.GetPositionXY() - path.points[0].XYPoint).ShorterThen(path.config.lineWidth_um * 2)) { //Check for lots of small moves and combine them into one large line Point3 nextPosition = path.points[0]; int i = pathIndex + 1; while (i < paths.Count && paths[i].points.Count == 1 && (nextPosition - paths[i].points[0]).ShorterThen(path.config.lineWidth_um * 2)) { nextPosition = paths[i].points[0]; i++; } if (paths[i - 1].config == travelConfig) { i--; } if (i > pathIndex + 2) { nextPosition = gcodeExport.GetPosition(); for (int x = pathIndex; x < i - 1; x += 2) { long oldLen = (nextPosition - paths[x].points[0]).Length(); Point3 newPoint = (paths[x].points[0] + paths[x + 1].points[0]) / 2; long newLen = (gcodeExport.GetPosition() - newPoint).Length(); if (newLen > 0) { gcodeExport.WriteMove(newPoint, speed, (int)(path.config.lineWidth_um * oldLen / newLen)); } nextPosition = paths[x + 1].points[0]; } gcodeExport.WriteMove(paths[i - 1].points[0], speed, path.config.lineWidth_um); pathIndex = i - 1; continue; } } bool spiralize = path.config.spiralize; if (spiralize) { //Check if we are the last spiralize path in the list, if not, do not spiralize. for (int m = pathIndex + 1; m < paths.Count; m++) { if (paths[m].config.spiralize) { spiralize = false; } } } if (spiralize) // if we are still in spiralize mode { //If we need to spiralize then raise the head slowly by 1 layer as this path progresses. double totalLength = 0; long z = gcodeExport.GetPositionZ(); IntPoint currentPosition = gcodeExport.GetPositionXY(); for (int pointIndex = 0; pointIndex < path.points.Count; pointIndex++) { IntPoint nextPosition = path.points[pointIndex].XYPoint; totalLength += (currentPosition - nextPosition).LengthMm(); currentPosition = nextPosition; } double length = 0.0; currentPosition = gcodeExport.GetPositionXY(); for (int i = 0; i < path.points.Count; i++) { IntPoint nextPosition = path.points[i].XYPoint; length += (currentPosition - nextPosition).LengthMm(); currentPosition = nextPosition; Point3 nextExtrusion = path.points[i]; nextExtrusion.z = (int)(z + layerThickness * length / totalLength + .5); gcodeExport.WriteMove(nextExtrusion, speed, path.config.lineWidth_um); } } else { bool pathIsClosed = true; if (perimeterStartEndOverlapRatio < 1) { pathIsClosed = !TrimPerimeterIfNeeded(path, perimeterStartEndOverlapRatio); } // This is test code to remove double drawn small perimeter lines. List <PathAndWidth> pathsWithOverlapsRemoved; if (RemovePerimetersThatOverlap(path, speed, out pathsWithOverlapsRemoved, pathIsClosed)) { for (int polygonIndex = 0; polygonIndex < pathsWithOverlapsRemoved.Count; polygonIndex++) { PathAndWidth polygon = pathsWithOverlapsRemoved[polygonIndex]; if (polygon.Path.Count == 2) { // make sure the path is ordered with the first point the closest to where we are now Point3 currentPosition = gcodeExport.GetPosition(); // if the second point is closer swap them if ((polygon.Path[1] - currentPosition).LengthSquared() < (polygon.Path[0] - currentPosition).LengthSquared()) { // swap them Point3 temp = polygon.Path[0]; polygon.Path[0] = polygon.Path[1]; polygon.Path[1] = temp; } } // move to the start of this polygon gcodeExport.WriteMove(polygon.Path[0], travelConfig.speed, 0); // write all the data for the polygon for (int pointIndex = 1; pointIndex < polygon.Path.Count; pointIndex++) { gcodeExport.WriteMove(polygon.Path[pointIndex], speed, polygon.ExtrusionWidthUm); } } } else { for (int i = 0; i < path.points.Count; i++) { gcodeExport.WriteMove(path.points[i], speed, path.config.lineWidth_um); } } } } gcodeExport.UpdateTotalPrintTime(); }
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); } } }
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"); LayerGCodePlanner layerPlanner = new LayerGCodePlanner(config, gcode, config.TravelSpeed, config.MinimumTravelToCauseRetraction_um, config.PerimeterStartEndOverlapRatio); if (config.RaftExtruder >= 0) { // if we have a specified raft extruder use it layerPlanner.SetExtruder(config.RaftExtruder); } else if (config.SupportExtruder >= 0) { // else preserve the old behavior of using the support extruder if set. layerPlanner.SetExtruder(config.SupportExtruder); } gcode.CurrentZ = config.RaftBaseThickness_um; gcode.LayerChanged(-3, config.RaftBaseThickness_um); gcode.SetExtrusion(config.RaftBaseThickness_um, config.FilamentDiameter_um, config.ExtrusionMultiplier); // write the skirt around the raft layerPlanner.QueuePolygonsByOptimizer(storage.Skirt, null, raftBaseConfig, 0); List <Polygons> raftIslands = storage.raftOutline.ProcessIntoSeparateIslands(); foreach (var raftIsland in raftIslands) { // write the outline of the raft layerPlanner.QueuePolygonsByOptimizer(raftIsland, null, raftBaseConfig, 0); 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 layerPlanner.QueuePolygonsByOptimizer(raftLines, null, raftBaseConfig, 0); if (config.RetractWhenChangingIslands) { layerPlanner.ForceRetract(); } } layerPlanner.WriteQueuedGCode(config.RaftBaseThickness_um); } // raft middle layers { gcode.WriteComment("RAFT MIDDLE"); LayerGCodePlanner layerPlanner = new LayerGCodePlanner(config, gcode, config.TravelSpeed, config.MinimumTravelToCauseRetraction_um, config.PerimeterStartEndOverlapRatio); gcode.CurrentZ = config.RaftBaseThickness_um + config.RaftInterfaceThicknes_um; gcode.LayerChanged(-2, config.RaftInterfaceThicknes_um); 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); layerPlanner.QueuePolygonsByOptimizer(raftLines, null, raftMiddleConfig, 0); layerPlanner.WriteQueuedGCode(config.RaftInterfaceThicknes_um); } for (int raftSurfaceIndex = 1; raftSurfaceIndex <= config.RaftSurfaceLayers; raftSurfaceIndex++) { gcode.WriteComment("RAFT SURFACE"); LayerGCodePlanner layerPlanner = new LayerGCodePlanner(config, gcode, config.TravelSpeed, config.MinimumTravelToCauseRetraction_um, config.PerimeterStartEndOverlapRatio); gcode.CurrentZ = config.RaftBaseThickness_um + config.RaftInterfaceThicknes_um + config.RaftSurfaceThickness_um * raftSurfaceIndex; gcode.LayerChanged(-1, config.RaftSurfaceThickness_um); 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); } layerPlanner.QueuePolygonsByOptimizer(raftLines, null, raftSurfaceConfig, 0); layerPlanner.WriteQueuedGCode(config.RaftInterfaceThicknes_um); } } }
public void WriteQueuedGCode(long layerThickness_um) { GCodePathConfig lastConfig = null; int extruderIndex = gcodeExport.GetExtruderIndex(); for (int pathIndex = 0; pathIndex < paths.Count; pathIndex++) { var path = paths[pathIndex]; if (extruderIndex != path.ExtruderIndex) { extruderIndex = path.ExtruderIndex; gcodeExport.SwitchExtruder(extruderIndex); } else if (path.Retract != RetractType.None) { double timeOfMove = 0; if (path.Config.LineWidthUM == 0) { var lengthToStart = (gcodeExport.GetPosition() - path.Polygon[0]).Length(); var lengthOfMove = lengthToStart + path.Polygon.PolygonLength(); timeOfMove = lengthOfMove / 1000.0 / path.Speed; } gcodeExport.WriteRetraction(timeOfMove, path.Retract == RetractType.Force); } if (lastConfig != path.Config && path.Config != travelConfig) { gcodeExport.WriteComment("TYPE:{0}".FormatWith(path.Config.GCodeComment)); lastConfig = path.Config; } if (path.FanPercent != -1) { gcodeExport.WriteFanCommand(path.FanPercent); } if (path.Polygon.Count == 1 && path.Config != travelConfig && (gcodeExport.GetPositionXY() - path.Polygon[0]).ShorterThen(path.Config.LineWidthUM * 2)) { //Check for lots of small moves and combine them into one large line IntPoint nextPosition = path.Polygon[0]; int i = pathIndex + 1; while (i < paths.Count && paths[i].Polygon.Count == 1 && (nextPosition - paths[i].Polygon[0]).ShorterThen(path.Config.LineWidthUM * 2)) { nextPosition = paths[i].Polygon[0]; i++; } if (paths[i - 1].Config == travelConfig) { i--; } if (i > pathIndex + 2) { nextPosition = gcodeExport.GetPosition(); for (int x = pathIndex; x < i - 1; x += 2) { long oldLen = (nextPosition - paths[x].Polygon[0]).Length(); IntPoint newPoint = (paths[x].Polygon[0] + paths[x + 1].Polygon[0]) / 2; long newLen = (gcodeExport.GetPosition() - newPoint).Length(); if (newLen > 0) { gcodeExport.WriteMove(newPoint, path.Speed, (int)(path.Config.LineWidthUM * oldLen / newLen)); } nextPosition = paths[x + 1].Polygon[0]; } long lineWidth_um = path.Config.LineWidthUM; if (paths[i - 1].Polygon[0].Width != 0) { lineWidth_um = paths[i - 1].Polygon[0].Width; } gcodeExport.WriteMove(paths[i - 1].Polygon[0], path.Speed, lineWidth_um); pathIndex = i - 1; continue; } } bool spiralize = path.Config.Spiralize; if (spiralize) { //Check if we are the last spiralize path in the list, if not, do not spiralize. for (int m = pathIndex + 1; m < paths.Count; m++) { if (paths[m].Config.Spiralize) { spiralize = false; } } } if (spiralize) // if we are still in spiralize mode { //If we need to spiralize then raise the head slowly by 1 layer as this path progresses. double totalLength = 0; long z = gcodeExport.GetPositionZ(); IntPoint currentPosition = gcodeExport.GetPositionXY(); for (int pointIndex = 0; pointIndex < path.Polygon.Count; pointIndex++) { IntPoint nextPosition = path.Polygon[pointIndex]; totalLength += (currentPosition - nextPosition).LengthMm(); currentPosition = nextPosition; } double length = 0.0; currentPosition = gcodeExport.GetPositionXY(); for (int i = 0; i < path.Polygon.Count; i++) { IntPoint nextPosition = path.Polygon[i]; length += (currentPosition - nextPosition).LengthMm(); currentPosition = nextPosition; IntPoint nextExtrusion = path.Polygon[i]; nextExtrusion.Z = (int)(z + layerThickness_um * length / totalLength + .5); gcodeExport.WriteMove(nextExtrusion, path.Speed, path.Config.LineWidthUM); } } else { var loopStart = gcodeExport.GetPosition(); int pointCount = path.Polygon.Count; bool outerPerimeter = path.Config.GCodeComment == "WALL-OUTER"; bool innerPerimeter = path.Config.GCodeComment == "WALL-INNER"; bool perimeter = outerPerimeter || innerPerimeter; bool completeLoop = (pointCount > 0 && path.Polygon[pointCount - 1] == loopStart); bool trimmed = perimeter && completeLoop && perimeterStartEndOverlapRatio < 1; // This is test code to remove double drawn small perimeter lines. if (trimmed) { long targetDistance = (long)(path.Config.LineWidthUM * (1 - perimeterStartEndOverlapRatio)); path = TrimGCodePathEnd(path, targetDistance); // update the point count after trimming pointCount = path.Polygon.Count; } for (int i = 0; i < pointCount; i++) { long lineWidth_um = path.Config.LineWidthUM; if (path.Polygon[i].Width != 0) { lineWidth_um = path.Polygon[i].Width; } gcodeExport.WriteMove(path.Polygon[i], path.Speed, lineWidth_um); } if (trimmed) { // go back to the start of the loop gcodeExport.WriteMove(loopStart, path.Speed, 0); var length = path.Polygon.PolygonLength(false); if (outerPerimeter && config.CoastAtEndDistance_um > 0 && length > config.CoastAtEndDistance_um) { //gcodeExport.WriteRetraction var wipePoly = new Polygon(new IntPoint[] { loopStart }); wipePoly.AddRange(path.Polygon); // then drive down it just a bit more to make sure we have a clean overlap var extraMove = wipePoly.CutToLength(config.CoastAtEndDistance_um); for (int i = 0; i < extraMove.Count; i++) { gcodeExport.WriteMove(extraMove[i], path.Speed, 0); } } } } } gcodeExport.UpdateLayerPrintTime(); }
public void WriteQueuedGCode(int layerThickness, int fanSpeedPercent = -1, int bridgeFanSpeedPercent = -1) { GCodePathConfig lastConfig = null; int extruderIndex = gcodeExport.GetExtruderIndex(); for (int pathIndex = 0; pathIndex < paths.Count; pathIndex++) { GCodePath path = paths[pathIndex]; if (extruderIndex != path.extruderIndex) { extruderIndex = path.extruderIndex; gcodeExport.SwitchExtruder(extruderIndex); } else if (path.Retract) { gcodeExport.WriteRetraction(); } if (path.config != travelConfig && lastConfig != path.config) { if (path.config.gcodeComment == "BRIDGE" && bridgeFanSpeedPercent != -1) { gcodeExport.WriteFanCommand(bridgeFanSpeedPercent); } else if (lastConfig?.gcodeComment == "BRIDGE" && bridgeFanSpeedPercent != -1) { gcodeExport.WriteFanCommand(fanSpeedPercent); } gcodeExport.WriteComment("TYPE:{0}".FormatWith(path.config.gcodeComment)); lastConfig = path.config; } double speed = path.config.speed; if (path.config.lineWidth_um != 0) { // Prevent cooling overrides from affecting bridge moves if (path.config.gcodeComment != "BRIDGE") { speed = speed * extrudeSpeedFactor / 100; } } else { speed = speed * travelSpeedFactor / 100; } if (path.points.Count == 1 && path.config != travelConfig && (gcodeExport.GetPositionXY() - path.points[0]).ShorterThen(path.config.lineWidth_um * 2)) { //Check for lots of small moves and combine them into one large line IntPoint nextPosition = path.points[0]; int i = pathIndex + 1; while (i < paths.Count && paths[i].points.Count == 1 && (nextPosition - paths[i].points[0]).ShorterThen(path.config.lineWidth_um * 2)) { nextPosition = paths[i].points[0]; i++; } if (paths[i - 1].config == travelConfig) { i--; } if (i > pathIndex + 2) { nextPosition = gcodeExport.GetPosition(); for (int x = pathIndex; x < i - 1; x += 2) { long oldLen = (nextPosition - paths[x].points[0]).Length(); IntPoint newPoint = (paths[x].points[0] + paths[x + 1].points[0]) / 2; long newLen = (gcodeExport.GetPosition() - newPoint).Length(); if (newLen > 0) { gcodeExport.WriteMove(newPoint, speed, (int)(path.config.lineWidth_um * oldLen / newLen)); } nextPosition = paths[x + 1].points[0]; } long lineWidth_um = path.config.lineWidth_um; if (paths[i - 1].points[0].Width != 0) { lineWidth_um = paths[i - 1].points[0].Width; } gcodeExport.WriteMove(paths[i - 1].points[0], speed, lineWidth_um); pathIndex = i - 1; continue; } } bool spiralize = path.config.spiralize; if (spiralize) { //Check if we are the last spiralize path in the list, if not, do not spiralize. for (int m = pathIndex + 1; m < paths.Count; m++) { if (paths[m].config.spiralize) { spiralize = false; } } } if (spiralize) // if we are still in spiralize mode { //If we need to spiralize then raise the head slowly by 1 layer as this path progresses. double totalLength = 0; long z = gcodeExport.GetPositionZ(); IntPoint currentPosition = gcodeExport.GetPositionXY(); for (int pointIndex = 0; pointIndex < path.points.Count; pointIndex++) { IntPoint nextPosition = path.points[pointIndex]; totalLength += (currentPosition - nextPosition).LengthMm(); currentPosition = nextPosition; } double length = 0.0; currentPosition = gcodeExport.GetPositionXY(); for (int i = 0; i < path.points.Count; i++) { IntPoint nextPosition = path.points[i]; length += (currentPosition - nextPosition).LengthMm(); currentPosition = nextPosition; IntPoint nextExtrusion = path.points[i]; nextExtrusion.Z = (int)(z + layerThickness * length / totalLength + .5); gcodeExport.WriteMove(nextExtrusion, speed, path.config.lineWidth_um); } } else { // This is test code to remove double drawn small perimeter lines. Polygons pathsWithOverlapsRemoved = null; bool pathHadOverlaps = false; bool pathIsClosed = true; if (mergeOverlappingLines && (path.config.gcodeComment == "WALL-OUTER" || path.config.gcodeComment == "WALL-INNER")) { //string perimeterString = Newtonsoft.Json.JsonConvert.SerializeObject(path); if (perimeterStartEndOverlapRatio < 1) { path = TrimPerimeter(path, perimeterStartEndOverlapRatio); //string trimmedString = Newtonsoft.Json.JsonConvert.SerializeObject(path); // it was closed but now it isn't pathIsClosed = false; } if (path.config.lineWidth_um > 0 && path.points.Count > 2) { // have to add in the position we are currently at path.points.Insert(0, gcodeExport.GetPosition()); //string openPerimeterString = Newtonsoft.Json.JsonConvert.SerializeObject(path); pathHadOverlaps = MergePerimeterOverlaps(path.points, path.config.lineWidth_um, out pathsWithOverlapsRemoved, pathIsClosed) && pathsWithOverlapsRemoved.Count > 0; //string trimmedString = Newtonsoft.Json.JsonConvert.SerializeObject(pathsWithOverlapsRemoved); } } if (pathHadOverlaps) { for (int polygonIndex = 0; polygonIndex < pathsWithOverlapsRemoved.Count; polygonIndex++) { Polygon polygon = pathsWithOverlapsRemoved[polygonIndex]; if (polygon.Count == 2) { // make sure the path is ordered with the first point the closest to where we are now IntPoint currentPosition = gcodeExport.GetPosition(); // if the second point is closer swap them if ((polygon[1] - currentPosition).LengthSquared() < (polygon[0] - currentPosition).LengthSquared()) { // swap them IntPoint temp = polygon[0]; polygon[0] = polygon[1]; polygon[1] = temp; } } // move to the start of this polygon gcodeExport.WriteMove(polygon[0], travelConfig.speed, 0); // write all the data for the polygon for (int pointIndex = 1; pointIndex < polygon.Count; pointIndex++) { gcodeExport.WriteMove(polygon[pointIndex], speed, polygon[pointIndex - 1].Width); } } } else { int outputCount = path.points.Count; for (int i = 0; i < outputCount; i++) { long lineWidth_um = path.config.lineWidth_um; if (path.points[i].Width != 0) { lineWidth_um = path.points[i].Width; } gcodeExport.WriteMove(path.points[i], speed, lineWidth_um); } } } } gcodeExport.UpdateTotalPrintTime(); }
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, 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, 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, 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); } } }
public void WriteQueuedGCode(int layerThickness) { GCodePathConfig lastConfig = null; int extruderIndex = gcodeExport.GetExtruderIndex(); for (int pathIndex = 0; pathIndex < paths.Count; pathIndex++) { GCodePath path = paths[pathIndex]; if (extruderIndex != path.extruderIndex) { extruderIndex = path.extruderIndex; gcodeExport.SwitchExtruder(extruderIndex); } else if (path.Retract) { gcodeExport.WriteRetraction(); } if (path.config != travelConfig && lastConfig != path.config) { gcodeExport.WriteComment("TYPE:{0}".FormatWith(path.config.gcodeComment)); lastConfig = path.config; } double speed = path.config.speed; if (path.config.lineWidth_um != 0) { // Only apply the extrudeSpeedFactor to extrusion moves speed = speed * extrudeSpeedFactor / 100; } else { speed = speed * travelSpeedFactor / 100; } if (path.points.Count == 1 && path.config != travelConfig && (gcodeExport.GetPositionXY() - path.points[0].XYPoint).ShorterThen(path.config.lineWidth_um * 2)) { //Check for lots of small moves and combine them into one large line Point3 nextPosition = path.points[0]; int i = pathIndex + 1; while (i < paths.Count && paths[i].points.Count == 1 && (nextPosition - paths[i].points[0]).ShorterThen(path.config.lineWidth_um * 2)) { nextPosition = paths[i].points[0]; i++; } if (paths[i - 1].config == travelConfig) { i--; } if (i > pathIndex + 2) { nextPosition = gcodeExport.GetPosition(); for (int x = pathIndex; x < i - 1; x += 2) { long oldLen = (nextPosition - paths[x].points[0]).Length(); Point3 newPoint = (paths[x].points[0] + paths[x + 1].points[0]) / 2; long newLen = (gcodeExport.GetPosition() - newPoint).Length(); if (newLen > 0) { gcodeExport.WriteMove(newPoint, speed, (int)(path.config.lineWidth_um * oldLen / newLen)); } nextPosition = paths[x + 1].points[0]; } gcodeExport.WriteMove(paths[i - 1].points[0], speed, path.config.lineWidth_um); pathIndex = i - 1; continue; } } bool spiralize = path.config.spiralize; if (spiralize) { //Check if we are the last spiralize path in the list, if not, do not spiralize. for (int m = pathIndex + 1; m < paths.Count; m++) { if (paths[m].config.spiralize) { spiralize = false; } } } if (spiralize) // if we are still in spiralize mode { //If we need to spiralize then raise the head slowly by 1 layer as this path progresses. double totalLength = 0; long z = gcodeExport.GetPositionZ(); IntPoint currentPosition = gcodeExport.GetPositionXY(); for (int pointIndex = 0; pointIndex < path.points.Count; pointIndex++) { IntPoint nextPosition = path.points[pointIndex].XYPoint; totalLength += (currentPosition - nextPosition).LengthMm(); currentPosition = nextPosition; } double length = 0.0; currentPosition = gcodeExport.GetPositionXY(); for (int i = 0; i < path.points.Count; i++) { IntPoint nextPosition = path.points[i].XYPoint; length += (currentPosition - nextPosition).LengthMm(); currentPosition = nextPosition; Point3 nextExtrusion = path.points[i]; nextExtrusion.z = (int)(z + layerThickness * length / totalLength + .5); gcodeExport.WriteMove(nextExtrusion, speed, path.config.lineWidth_um); } } else { // This is test code to remove double drawn small perimeter lines. if (RemoveDoubleDrawPerimeterLines(path, speed)) { return; } else { //TrimPerimeterIfNeeded(path); for (int i = 0; i < path.points.Count; i++) { gcodeExport.WriteMove(path.points[i], speed, path.config.lineWidth_um); } } } } gcodeExport.UpdateTotalPrintTime(); }
public void WriteGCode(bool liftHeadIfNeeded, int layerThickness) { GCodePathConfig lastConfig = null; int extruderIndex = gcode.GetExtruderIndex(); for (int pathIndex = 0; pathIndex < paths.Count; pathIndex++) { GCodePath path = paths[pathIndex]; if (extruderIndex != path.extruderIndex) { extruderIndex = path.extruderIndex; gcode.SwitchExtruder(extruderIndex); } else if (path.Retract) { gcode.WriteRetraction(); } if (path.config != travelConfig && lastConfig != path.config) { //gcode.WriteComment("TYPE:{0}".FormatWith(path.config.gcodeComment)); lastConfig = path.config; ////后加的//只是边框,不填充。 if ((path.config.gcodeComment == "SKIRT") || (path.config.gcodeComment == "FILL") || (path.config.gcodeComment == "TOP-FILL")) { return; } } double speed = path.config.speed; if (path.config.lineWidth != 0) { // Only apply the extrudeSpeedFactor to extrusion moves speed = speed * extrudeSpeedFactor / 100; } else { speed = speed * travelSpeedFactor / 100; } if (path.points.Count == 1 && path.config != travelConfig && (gcode.GetPositionXY() - path.points[0]).ShorterThen(path.config.lineWidth * 2)) { //Check for lots of small moves and combine them into one large line IntPoint nextPosition = path.points[0]; int i = pathIndex + 1; while (i < paths.Count && paths[i].points.Count == 1 && (nextPosition - paths[i].points[0]).ShorterThen(path.config.lineWidth * 2)) { nextPosition = paths[i].points[0]; i++; } if (paths[i - 1].config == travelConfig) { i--; } if (i > pathIndex + 2) { nextPosition = gcode.GetPositionXY(); for (int x = pathIndex; x < i - 1; x += 2) { long oldLen = (nextPosition - paths[x].points[0]).Length(); IntPoint newPoint = (paths[x].points[0] + paths[x + 1].points[0]) / 2; long newLen = (gcode.GetPositionXY() - newPoint).Length(); if (newLen > 0) { gcode.WriteMove(newPoint, speed, (int)(path.config.lineWidth * oldLen / newLen)); } nextPosition = paths[x + 1].points[0]; } gcode.WriteMove(paths[i - 1].points[0], speed, path.config.lineWidth); pathIndex = i - 1; continue; } } bool spiralize = path.config.spiralize; if (spiralize) { //Check if we are the last spiralize path in the list, if not, do not spiralize. for (int m = pathIndex + 1; m < paths.Count; m++) { if (paths[m].config.spiralize) { spiralize = false; } } } if (spiralize) { //If we need to spiralize then raise the head slowly by 1 layer as this path progresses. double totalLength = 0; int z = gcode.GetPositionZ(); IntPoint currentPosition = gcode.GetPositionXY(); for (int pointIndex = 0; pointIndex < path.points.Count; pointIndex++) { IntPoint nextPosition = path.points[pointIndex]; totalLength += (currentPosition - nextPosition).LengthMm(); currentPosition = nextPosition; } double length = 0.0; currentPosition = gcode.GetPositionXY(); for (int i = 0; i < path.points.Count; i++) { IntPoint nextPosition = path.points[i]; length += (currentPosition - nextPosition).LengthMm(); currentPosition = nextPosition; gcode.setZ((int)(z + layerThickness * length / totalLength + .5)); gcode.WriteMove(path.points[i], speed, path.config.lineWidth); } } else { #if false // This is test code to remove double drawn small perimeter lines. if (path.config.lineWidth > 0 && path.points.Count > 2 && // If the count is not greater than 2 there is no way it can ovelap itself. gcode.GetPositionXY() == path.points[path.points.Count - 1]) { Polygons pathsWithOverlapsRemoved = GetPathsWithOverlapsRemoved(path.points, path.config.lineWidth / 2); if (pathsWithOverlapsRemoved.Count > 0) { for (int polygonIndex = 0; polygonIndex < pathsWithOverlapsRemoved.Count; polygonIndex++) { int startIndex = 0; Polygon polygon = pathsWithOverlapsRemoved[polygonIndex]; if (polygonIndex > 0) { gcode.WriteMove(polygon[0], travelConfig.speed, 0); startIndex = 1; // We skip the first point in the next extrusion, because we just moved to it. } for (int pointIndex = startIndex; pointIndex < polygon.Count; pointIndex++) { gcode.WriteMove(polygon[pointIndex], speed, path.config.lineWidth); } } } } else #endif { //TrimPerimeterIfNeeded(path); for (int i = 0; i < path.points.Count; i++) { gcode.WriteMove(path.points[i], speed, path.config.lineWidth); } } } } gcode.UpdateTotalPrintTime(); if (liftHeadIfNeeded && extraTime > 0.0) { gcode.WriteComment("Small layer, adding delay of {0}".FormatWith(extraTime)); gcode.WriteRetraction(); gcode.setZ(gcode.GetPositionZ() + 3000); gcode.WriteMove(gcode.GetPositionXY(), travelConfig.speed, 0); gcode.WriteMove(gcode.GetPositionXY() - new IntPoint(-20000, 0), travelConfig.speed, 0); gcode.WriteDelay(extraTime); } }
public void WriteQueuedGCode(int layerThickness, int fanSpeedPercent = -1, int bridgeFanSpeedPercent = -1) { GCodePathConfig lastConfig = null; int extruderIndex = gcodeExport.GetExtruderIndex(); for (int pathIndex = 0; pathIndex < paths.Count; pathIndex++) { GCodePath path = paths[pathIndex]; if (extruderIndex != path.extruderIndex) { extruderIndex = path.extruderIndex; gcodeExport.SwitchExtruder(extruderIndex); } else if (path.Retract) { gcodeExport.WriteRetraction(); } if (path.config != travelConfig && lastConfig != path.config) { if (path.config.gcodeComment == "BRIDGE" && bridgeFanSpeedPercent != -1) { gcodeExport.WriteFanCommand(bridgeFanSpeedPercent); } else if (lastConfig?.gcodeComment == "BRIDGE" && bridgeFanSpeedPercent != -1) { gcodeExport.WriteFanCommand(fanSpeedPercent); } gcodeExport.WriteComment("TYPE:{0}".FormatWith(path.config.gcodeComment)); lastConfig = path.config; } double speed = path.config.speed; if (path.config.lineWidth_um != 0) { // Prevent cooling overrides from affecting bridge moves if (path.config.gcodeComment != "BRIDGE") { speed = speed * extrudeSpeedFactor / 100; } } else { speed = speed * travelSpeedFactor / 100; } if (path.polygon.Count == 1 && path.config != travelConfig && (gcodeExport.GetPositionXY() - path.polygon[0]).ShorterThen(path.config.lineWidth_um * 2)) { //Check for lots of small moves and combine them into one large line IntPoint nextPosition = path.polygon[0]; int i = pathIndex + 1; while (i < paths.Count && paths[i].polygon.Count == 1 && (nextPosition - paths[i].polygon[0]).ShorterThen(path.config.lineWidth_um * 2)) { nextPosition = paths[i].polygon[0]; i++; } if (paths[i - 1].config == travelConfig) { i--; } if (i > pathIndex + 2) { nextPosition = gcodeExport.GetPosition(); for (int x = pathIndex; x < i - 1; x += 2) { long oldLen = (nextPosition - paths[x].polygon[0]).Length(); IntPoint newPoint = (paths[x].polygon[0] + paths[x + 1].polygon[0]) / 2; long newLen = (gcodeExport.GetPosition() - newPoint).Length(); if (newLen > 0) { gcodeExport.WriteMove(newPoint, speed, (int)(path.config.lineWidth_um * oldLen / newLen)); } nextPosition = paths[x + 1].polygon[0]; } long lineWidth_um = path.config.lineWidth_um; if (paths[i - 1].polygon[0].Width != 0) { lineWidth_um = paths[i - 1].polygon[0].Width; } gcodeExport.WriteMove(paths[i - 1].polygon[0], speed, lineWidth_um); pathIndex = i - 1; continue; } } bool spiralize = path.config.spiralize; if (spiralize) { //Check if we are the last spiralize path in the list, if not, do not spiralize. for (int m = pathIndex + 1; m < paths.Count; m++) { if (paths[m].config.spiralize) { spiralize = false; } } } if (spiralize) // if we are still in spiralize mode { //If we need to spiralize then raise the head slowly by 1 layer as this path progresses. double totalLength = 0; long z = gcodeExport.GetPositionZ(); IntPoint currentPosition = gcodeExport.GetPositionXY(); for (int pointIndex = 0; pointIndex < path.polygon.Count; pointIndex++) { IntPoint nextPosition = path.polygon[pointIndex]; totalLength += (currentPosition - nextPosition).LengthMm(); currentPosition = nextPosition; } double length = 0.0; currentPosition = gcodeExport.GetPositionXY(); for (int i = 0; i < path.polygon.Count; i++) { IntPoint nextPosition = path.polygon[i]; length += (currentPosition - nextPosition).LengthMm(); currentPosition = nextPosition; IntPoint nextExtrusion = path.polygon[i]; nextExtrusion.Z = (int)(z + layerThickness * length / totalLength + .5); gcodeExport.WriteMove(nextExtrusion, speed, path.config.lineWidth_um); } } else { // This is test code to remove double drawn small perimeter lines. if (path.config.gcodeComment == "WALL-OUTER" || path.config.gcodeComment == "WALL-INNER") { //string perimeterString = Newtonsoft.Json.JsonConvert.SerializeObject(path); if (perimeterStartEndOverlapRatio < 1) { path = TrimPerimeter(path, perimeterStartEndOverlapRatio); } } int outputCount = path.polygon.Count; for (int i = 0; i < outputCount; i++) { long lineWidth_um = path.config.lineWidth_um; if (path.polygon[i].Width != 0) { lineWidth_um = path.polygon[i].Width; } gcodeExport.WriteMove(path.polygon[i], speed, lineWidth_um); } } } gcodeExport.UpdateTotalPrintTime(); }