/// <summary> /// Traverse the instructions backwards until a movement is found, /// return as Point3D /// </summary> /// <param name="instructions">a list of gcode instructions</param> /// <returns>previous point as a Point3D or Empty</returns> private static Point3D GetPreviousPoint(IList <GCodeInstruction> instructions) { var prevPoint = Point3D.Empty; if (instructions.Count == 0) { return(prevPoint); } GCodeInstruction prevInstruction = null; bool foundLastMovement = false; int index = 1; while (!foundLastMovement) { prevInstruction = instructions[instructions.Count - index]; if (prevInstruction.CommandType == CommandType.CWArc || prevInstruction.CommandType == CommandType.CCWArc || prevInstruction.CommandType == CommandType.NormalMove || prevInstruction.CommandType == CommandType.RapidMove) { foundLastMovement = true; } if (index == instructions.Count) { // warning, no previous movements found break; } index++; } // merge previous coordinates with newer ones to maintain correct point coordinates if (prevInstruction.X.HasValue || prevInstruction.Y.HasValue || prevInstruction.Z.HasValue) { if (prevInstruction.X.HasValue) { prevPoint.X = prevInstruction.X.Value; } if (prevInstruction.Y.HasValue) { prevPoint.Y = prevInstruction.Y.Value; } if (prevInstruction.Z.HasValue) { prevPoint.Z = prevInstruction.Z.Value; } } return(prevPoint); }
public bool EqualsXYZ(GCodeInstruction other) { if (other == null) { return(false); } if (X.HasValue && other.X.HasValue && X.Value == other.X.Value && Y.HasValue && other.Y.HasValue && Y.Value == other.Y.Value && Z.HasValue && other.Z.HasValue && Z.Value == other.Z.Value) { return(true); } return(false); }
/// <summary> /// Split a gcode file into tiles /// </summary> /// <param name="instructions">list of gcode instructions</param> /// <param name="splitPoint">Point3D describing the split coordinates</param> /// <param name="angle">Whether the split should happen in an angle</param> /// <param name="zClearance">z-height (clearance) to use in added rapid moves</param> /// <returns>List of tiles</returns> /// <remarks> /// Porteed from the G-Code_Ripper-0.14 Python App /// Method: def split_code(self,code2split,shift=[0,0,0],angle=0.0) /// </remarks> public static List <List <GCodeInstruction> > Split(List <GCodeInstruction> instructions, Point3D splitPoint, float angle, float zClearance) { // G0 (Rapid), G1 (linear), G2 (clockwise arc) or G3 (counterclockwise arc). CommandType command = CommandType.Other; const float xsplit = 0.0f; // xsplit is always zero, because the whole coordinate system is shifted to origin var app = new List <List <GCodeInstruction> >(); app.Add(new List <GCodeInstruction>()); app.Add(new List <GCodeInstruction>()); var flag_side = Position.None; int thisSide = -1; int otherSide = -1; float currentFeedrate = 0.0f; var currentPos = Point3D.Empty; // current position as read var previousPos = Point3D.Empty; // current position as read var centerPos = Point3D.Empty; // center position as read var currentPosAtOrigin = Point3D.Empty; // current position, shifted var previousPosAtOrigin = Point3D.Empty; // last position, shifted var centerPosAtOrigin = Point3D.Empty; // center position, shifted var A = Point3D.Empty; var B = Point3D.Empty; var C = Point3D.Empty; var D = Point3D.Empty; var E = Point3D.Empty; var cross = new List <Point3D>(); // number of intersections found #if DEBUG Debug.WriteLine("Split point: {0}, angle: {1} z-clearance: {2}", splitPoint, angle, zClearance); #endif int numInstructions = 1; foreach (var instruction in instructions) { // store move type command = instruction.CommandType; // merge previous coordinates with newer ones to maintain correct point coordinates if ((instruction.X.HasValue || instruction.Y.HasValue || instruction.Z.HasValue || instruction.F.HasValue)) { if (instruction.X.HasValue && instruction.X.Value != currentPos.X) { currentPos.X = instruction.X.Value; } if (instruction.Y.HasValue && instruction.Y.Value != currentPos.Y) { currentPos.Y = instruction.Y.Value; } if (instruction.Z.HasValue && instruction.Z.Value != currentPos.Z) { currentPos.Z = instruction.Z.Value; } if (instruction.F.HasValue && instruction.F.Value != currentFeedrate) { currentFeedrate = instruction.F.Value; } } if (command == CommandType.NormalMove || command == CommandType.CWArc || command == CommandType.CCWArc) { // shift and rotate so that we can work with the coordinate system at origin (0, 0) currentPosAtOrigin = SetOffsetAndRotation(currentPos, splitPoint, angle); previousPosAtOrigin = SetOffsetAndRotation(previousPos, splitPoint, angle); // store center point if (instruction.I.HasValue && instruction.J.HasValue) { centerPos = new Point3D(previousPos.X + instruction.I.Value, previousPos.Y + instruction.J.Value, currentPos.Z); centerPosAtOrigin = SetOffsetAndRotation(centerPos, splitPoint, angle); } // determine what side the move belongs to if (previousPosAtOrigin.X > xsplit + SELF_ZERO) { flag_side = Position.R; } else if (previousPosAtOrigin.X < xsplit - SELF_ZERO) { flag_side = Position.L; } else { if (command == CommandType.NormalMove) { if (currentPosAtOrigin.X >= xsplit) { flag_side = Position.R; } else { flag_side = Position.L; } } else if (command == CommandType.CWArc) { if (Math.Abs(previousPosAtOrigin.Y - centerPosAtOrigin.Y) < SELF_ZERO) { if (centerPosAtOrigin.X > xsplit) { flag_side = Position.R; } else { flag_side = Position.L; } } else { if (previousPosAtOrigin.Y >= centerPosAtOrigin.Y) { flag_side = Position.R; } else { flag_side = Position.L; } } } else //(mvtype == 3) { { if (Math.Abs(previousPosAtOrigin.Y - centerPosAtOrigin.Y) < SELF_ZERO) { if (centerPosAtOrigin.X > xsplit) { flag_side = Position.R; } else { flag_side = Position.L; } } else { if (previousPosAtOrigin.Y >= centerPosAtOrigin.Y) { flag_side = Position.L; } else { flag_side = Position.R; } } } } if (flag_side == Position.R) { thisSide = 1; otherSide = 0; } else { thisSide = 0; otherSide = 1; } // Handle normal moves if (command == CommandType.NormalMove) { A = UnsetOffsetAndRotation(previousPosAtOrigin, splitPoint, angle); C = UnsetOffsetAndRotation(currentPosAtOrigin, splitPoint, angle); cross = GetLineIntersect(previousPosAtOrigin, currentPosAtOrigin, xsplit); if (cross.Count > 0) { // Line crosses boundary B = UnsetOffsetAndRotation(cross[0], splitPoint, angle); app[thisSide].AddRange(GCodeInstruction.GetInstructions(command, A, B, currentFeedrate, splitPoint, thisSide, GetPreviousPoint(app[thisSide]), zClearance)); app[otherSide].AddRange(GCodeInstruction.GetInstructions(command, B, C, currentFeedrate, splitPoint, otherSide, GetPreviousPoint(app[otherSide]), zClearance)); } else { // Lines doesn't intersect // check if this point is the same as centerpoint // if so add it to both sides // TODO: check if this works in all cases? if (currentPos.X == splitPoint.X) { app[thisSide].AddRange(GCodeInstruction.GetInstructions(command, A, C, currentFeedrate, splitPoint, thisSide, GetPreviousPoint(app[thisSide]), zClearance)); app[otherSide].AddRange(GCodeInstruction.GetInstructions(command, A, C, currentFeedrate, splitPoint, otherSide, GetPreviousPoint(app[otherSide]), zClearance)); } else { app[thisSide].AddRange(GCodeInstruction.GetInstructions(command, A, C, currentFeedrate, splitPoint, thisSide, GetPreviousPoint(app[thisSide]), zClearance)); } } } // Handle Arc moves if (command == CommandType.CWArc || command == CommandType.CCWArc) { A = UnsetOffsetAndRotation(previousPosAtOrigin, splitPoint, angle); C = UnsetOffsetAndRotation(currentPosAtOrigin, splitPoint, angle); D = UnsetOffsetAndRotation(centerPosAtOrigin, splitPoint, angle); cross = GetArcIntersects(previousPosAtOrigin, currentPosAtOrigin, centerPosAtOrigin, xsplit, command); if (cross.Count > 0) { // Arc crosses boundary at least once B = UnsetOffsetAndRotation(cross[0], splitPoint, angle); // Check length of arc before writing if (Transformation.Distance(B, A) > SELF_ACCURACY) { app[thisSide].AddRange(GCodeInstruction.GetInstructions(command, A, B, D, currentFeedrate, splitPoint, thisSide, GetPreviousPoint(app[thisSide]), zClearance)); } if (cross.Count == 1) // Arc crosses boundary only once // Check length of arc before writing { if (Transformation.Distance(C, B) > SELF_ACCURACY) { app[otherSide].AddRange(GCodeInstruction.GetInstructions(command, B, C, D, currentFeedrate, splitPoint, otherSide, GetPreviousPoint(app[otherSide]), zClearance)); } } if (cross.Count == 2) // Arc crosses boundary twice { E = UnsetOffsetAndRotation(cross[1], splitPoint, angle); // Check length of arc before writing if (Transformation.Distance(E, B) > SELF_ACCURACY) { app[otherSide].AddRange(GCodeInstruction.GetInstructions(command, B, E, D, currentFeedrate, splitPoint, otherSide, GetPreviousPoint(app[otherSide]), zClearance)); } // Check length of arc before writing if (Transformation.Distance(C, E) > SELF_ACCURACY) { app[thisSide].AddRange(GCodeInstruction.GetInstructions(command, E, C, D, currentFeedrate, splitPoint, thisSide, GetPreviousPoint(app[thisSide]), zClearance)); } } } else { // Arc does not cross boundary app[thisSide].AddRange(GCodeInstruction.GetInstructions(command, A, C, D, currentFeedrate, splitPoint, thisSide, GetPreviousPoint(app[thisSide]), zClearance)); } } } else { // if not any normal or arc moves, store the instruction in both lists // rapid moves are also handled here if (instruction.CommandType != CommandType.RapidMove) { app[0].Add(instruction); app[1].Add(instruction); } } #if DEBUG if (command == CommandType.RapidMove) { Debug.WriteLine("{0} [{1}={2}], [{3}={4}]", command, previousPos, previousPosAtOrigin, currentPos, currentPosAtOrigin); } if (command == CommandType.NormalMove) { Debug.WriteLine("{0} [{1}={2}], [{3}={4}] {5}", command, previousPos, previousPosAtOrigin, currentPos, currentPosAtOrigin, currentFeedrate); } if (command == CommandType.CWArc || command == CommandType.CCWArc) { Debug.WriteLine("{0} [{1}={2}], [{3}={4}] [{5}={6}] {7}", command, previousPos, previousPosAtOrigin, currentPos, currentPosAtOrigin, centerPos, centerPosAtOrigin, currentFeedrate); } #endif // store current position previousPos = currentPos; // count number of instructions processed numInstructions++; } // add a last raise Z // raise Z to Z clearance (= G0 Za) var lastRaiseBitInstruction = new GCodeInstruction(CommandType.RapidMove, null, null, zClearance, null); app[0].Add(lastRaiseBitInstruction); app[1].Add(lastRaiseBitInstruction); return(app); }
/// <summary> /// Minimize gcode by removing coordinates that is a repeat of the previous coordinate /// </summary> /// <param name="instructions">instructions</param> /// <returns>minimized gcode</returns> public static List <GCodeInstruction> GetMinimizeGCode(List <GCodeInstruction> instructions) { var cleanedList = new List <GCodeInstruction>(); var prevInstruction = new GCodeInstruction(CommandType.RapidMove, new Point3D(), 0); CommandType mvtype = CommandType.Other; float lastX = 0.0f; float lastY = 0.0f; float lastZ = 0.0f; float lastF = 0.0f; foreach (GCodeInstruction currentInstruction in instructions) { if (currentInstruction.Equals(prevInstruction)) { continue; } // store move type mvtype = currentInstruction.CommandType; if (mvtype == CommandType.RapidMove || mvtype == CommandType.NormalMove || mvtype == CommandType.CWArc || mvtype == CommandType.CCWArc) { // merge previous coordinates with newer ones to maintain correct point coordinates if ((currentInstruction.X.HasValue || currentInstruction.Y.HasValue || currentInstruction.Z.HasValue || currentInstruction.F.HasValue)) { if ((currentInstruction.X.HasValue && prevInstruction.X.HasValue && currentInstruction.X.Value == prevInstruction.X.Value) || currentInstruction.X.HasValue && currentInstruction.X.Value == lastX) { // X is similar currentInstruction.X = (float?)null; } if ((currentInstruction.Y.HasValue && prevInstruction.Y.HasValue && currentInstruction.Y.Value == prevInstruction.Y.Value) || currentInstruction.Y.HasValue && currentInstruction.Y.Value == lastY) { // Y is similar currentInstruction.Y = (float?)null; } if ((currentInstruction.Z.HasValue && prevInstruction.Z.HasValue && currentInstruction.Z.Value == prevInstruction.Z.Value) || currentInstruction.Z.HasValue && currentInstruction.Z.Value == lastZ) { // Z is similar currentInstruction.Z = (float?)null; } if ((currentInstruction.F.HasValue && prevInstruction.F.HasValue && currentInstruction.F.Value == prevInstruction.F.Value) || currentInstruction.F.HasValue && currentInstruction.F.Value == lastF) { // F is similar currentInstruction.F = (float?)null; } } // store latest movement instructions as previous instrucion prevInstruction = currentInstruction; // at all times store the latest X, Y, Z and feedrate if (currentInstruction.X.HasValue) { lastX = currentInstruction.X.Value; } if (currentInstruction.Y.HasValue) { lastY = currentInstruction.Y.Value; } if (currentInstruction.Z.HasValue) { lastZ = currentInstruction.Z.Value; } if (currentInstruction.F.HasValue) { lastF = currentInstruction.F.Value; } } cleanedList.Add(currentInstruction); } return(cleanedList); }