/// <summary> /// Create a new point based on a existing line (x,y are based on the line vector) /// </summary> private HpglCommand GetNewCommand(HpglCommand pt, double x, double y) { double diffAlpha = Math.Atan2(y, x); double lineAlpha = diffAlpha + (pt.LineAngle ?? 0); double dx = x * Math.Cos(lineAlpha); double dy = x * Math.Sin(lineAlpha); return(new HpglCommand { CommandType = pt.CommandType, PointTo = new Point3D { X = pt.PointFrom.X + dx, Y = pt.PointFrom.Y + dy } }); }
public static void CalculateAngles(IEnumerable <HpglCommand> list, Point3D firstFrom) { HpglCommand last = null; if (firstFrom != null) { last = new HpglCommand { PointTo = firstFrom, CommandType = HpglCommand.HpglCommandType.PenDown }; } foreach (var cmd in list) { cmd.ResetCalculated(); if (cmd.IsPointToValid) { if (last != null) { cmd.PointFrom = last.PointTo; cmd.LineAngle = Math.Atan2((cmd.PointTo.Y0) - (cmd.PointFrom.Y0), (cmd.PointTo.X0) - (cmd.PointFrom.X0)); cmd.DiffLineAngleWithNext = null; if (last.LineAngle.HasValue && cmd.IsPenDownCommand) { last.DiffLineAngleWithNext = last.LineAngle - cmd.LineAngle; if (last.DiffLineAngleWithNext > Math.PI) { last.DiffLineAngleWithNext -= Math.PI * 2.0; } if (last.DiffLineAngleWithNext < -Math.PI) { last.DiffLineAngleWithNext += (Math.PI * 2.0); } } } last = cmd; } } }
private IEnumerable <HpglLine> OffsetLine(double offset, HpglLine line) { var newlines = new List <HpglLine> { line }; var co = new ClipperOffset(); var solution = new List <List <IntPoint> >(); var solution2 = new List <List <IntPoint> >(); solution.Add(line.Commands.Select(x => new IntPoint(_scale * x.PointFrom.X0, _scale * x.PointFrom.Y0)).ToList()); co.AddPaths(solution, JoinType.jtRound, EndType.etClosedPolygon); co.Execute(ref solution2, offset); var existingLine = line; foreach (var polygon in solution2) { var newCmds = new List <HpglCommand>(); HpglCommand last = null; foreach (var pt in polygon) { var from = new Point3D { X = pt.X / _scale, Y = pt.Y / _scale }; var hpgl = new HpglCommand { PointFrom = from, CommandType = HpglCommand.HpglCommandType.PenDown }; newCmds.Add(hpgl); if (last != null) { last.PointTo = @from; } last = hpgl; } last.PointTo = newCmds.First().PointFrom; if (existingLine == null) { // add new line existingLine = new HpglLine { PreCommands = new List <HpglCommand> { new HpglCommand { CommandType = HpglCommand.HpglCommandType.PenUp } }, PostCommands = new List <HpglCommand>(), ParentLine = line.ParentLine }; newlines.Add(existingLine); } existingLine.Commands = newCmds; existingLine.PreCommands.Last(l => l.IsPenCommand).PointTo = newCmds.First().PointFrom; existingLine = null; } return(newlines); }
static void Main(string[] args) { string InFileName = null; string OutFileName = null; string InLine; string[] HpglCommands; string HpglCode; StreamReader InFile; StreamWriter OutFile; Settings settings = new Settings(); ArgProc arguments = new ArgProc(args, settings); // test /* * Console.WriteLine("Arguments:"); * for (int i = 0; i < arguments.ArgCount; i++) * { * Console.WriteLine("[" + i.ToString() + "] " + arguments[i]); * } * Console.WriteLine("Switches:"); * foreach (string switchKey in arguments.SwitchKeys) * { * Console.WriteLine("[" + switchKey + "] " + arguments[switchKey]); * } */ // end test double HpglPpmm = arguments["HpglPpmm"].ToDouble(); // Hpgl Points per mm //double Speed = arguments["Speed"].ToDouble(); Cordinate CurrentXY; Cordinate CenterXY = new Cordinate(0, 0);; double Angle; double Alpha; Cordinate XY = new Cordinate(0, 0); double R; Cordinate IJ; string[] HpglParams; bool IsDrawing = false; Console.WriteLine("HPGL to GCODE Converter v0.1 alpha - Copyright (C) 2017 by SUF"); Console.WriteLine("This program is free software: you can redistribute it and / or modify"); Console.WriteLine("it under the terms of the GNU General Public License as published by"); Console.WriteLine("the Free Software Foundation, either version 3 of the License, or"); Console.WriteLine("any later version."); if (arguments.ArgCount == 2) { InFileName = arguments[0]; OutFileName = arguments[1]; } else { InFileName = arguments["Source"]; OutFileName = arguments["Destination"]; } if (InFileName != null && OutFileName != null) { InFile = new StreamReader(InFileName); OutFile = new StreamWriter(OutFileName); // Write header OutFile.WriteLine("G21"); OutFile.WriteLine(arguments["PenUp"]); IsDrawing = false; if (!ArgProc.GetBool(arguments["IgnoreSpeed"])) { OutFile.WriteLine("G1 F" + arguments["Speed"]); } OutFile.WriteLine("G28 " + arguments["HomeAxes"]); CurrentXY = new Cordinate(0, 0); while (!InFile.EndOfStream) { InLine = InFile.ReadLine(); HpglCommands = InLine.Split(';'); foreach (string HpglCommand in HpglCommands) { if (HpglCommand.Trim().Length > 1) { HpglCode = HpglCommand.Trim().Substring(0, 2); switch (HpglCode) { case "PU": // Pen Up OutFile.WriteLine(arguments["PenUp"]); IsDrawing = false; CurrentXY = DrawPoly(OutFile, HpglPpmm, HpglCommand.Substring(2).Trim(), false); break; case "PD": // Pen Down OutFile.WriteLine(arguments["PenDown"]); IsDrawing = true; CurrentXY = DrawPoly(OutFile, HpglPpmm, HpglCommand.Substring(2).Trim(), true); break; case "VS": // Velocity Set if (!ArgProc.GetBool(arguments["IgnoreVelocity"])) { OutFile.WriteLine("G1 F" + (HpglCommand.Substring(2).ToDouble() * arguments["VelocityScale"].ToDouble()).ToIString()); } break; case "IN": // Start break; case "SP": break; case "PA": // Position Absolute XY = CurrentXY; CurrentXY = DrawPoly(OutFile, HpglPpmm, HpglCommand.Substring(2).Trim(), IsDrawing); CurrentXY = XY; break; case "CI": // Circle // Parse radius R = HpglCommand.Substring(2).Trim().ToDouble() / HpglPpmm; // Move negative X by Radius to arrive to the arc OutFile.WriteLine("G0 X" + (CurrentXY.X - R).ToIString()); // Pen down - there is no PD command before CI, it assume that you draw the circle OutFile.WriteLine(arguments["PenDown"]); IsDrawing = true; // Draw the circle OutFile.WriteLine("G2 I" + R.ToIString()); CurrentXY.X -= R; break; case "AA": // Arc Absolute // gather the parameters HpglParams = HpglCommand.Substring(2).Trim().Split(','); CenterXY.X = HpglParams[0].ToDouble() / HpglPpmm; CenterXY.Y = HpglParams[1].ToDouble() / HpglPpmm; Angle = HpglParams[2].ToDouble(); // calculate the relative center point (I,J) IJ = CenterXY - CurrentXY; // calculate the radius (pythagorean theorem) R = Math.Sqrt(Math.Pow(IJ.X, 2) + Math.Pow(IJ.Y, 2)); // calculate the angle between start point and the X axis Alpha = DegMath.Asin((CurrentXY.Y - CenterXY.Y) / R); // extend the -90 to 90 degree angle to -270 to 90 if (CurrentXY.X < CenterXY.X) { Alpha = -180 - Alpha; } // calculate the arc end absolute cordinates XY.X = CenterXY.X + R * DegMath.Cos(Angle + Alpha); XY.Y = CenterXY.Y + R * DegMath.Sin(Angle + Alpha); // generate the gcode // the positive angles moves CCV, the negative angles move CV OutFile.WriteLine((Angle > 0 ? "G3 X" : "G2 X") + XY.XString + " Y" + XY.YString + " I" + IJ.XString + " J" + IJ.YString); // Save the cordinates CurrentXY = XY; break; default: // Unknown or unimplemented command arrived Console.WriteLine("Warrning: Unknown Command: " + HpglCommand); break; } } } } OutFile.Flush(); OutFile.Close(); InFile.Close(); } else { if (InFileName == null) { Console.WriteLine("Command line error: Source file missing"); } if (OutFileName == null) { Console.WriteLine("Command line error: Destination file missing"); } } }
private bool Command(HpglCommand cmd) { bool isPenUp = true; if (cmd.IsPenCommand) { switch (cmd.CommandType) { case HpglCommand.HpglCommandType.PenDown: isPenUp = false; break; case HpglCommand.HpglCommandType.PenUp: isPenUp = true; break; } Point3D pt = Adjust(cmd.PointTo); if (isPenUp != _lastIsPenUp) { if (isPenUp) { LoadPenUp(); } else { LoadPenDown(Adjust(cmd.PointFrom)); } _lastIsPenUp = isPenUp; } string hpglCmd; Command r; if (isPenUp) { r = new G00Command(); hpglCmd = "PU"; } else { r = new G01Command(); AddCamBamPoint(pt); hpglCmd = "PD"; } r.AddVariable('X', pt.X0, false); r.AddVariable('Y', pt.Y0, false); if (_needSpeed) { _needSpeed = false; r.AddVariable('F', LoadOptions.MoveSpeed ?? 0); } Commands.AddCommand(r); r.ImportInfo = $"{hpglCmd}{(int)(pt.X0 * 40.0)},{(int)(pt.Y0 * 40.0)}"; } else { var r = new GxxCommand(); r.SetCode($";Hpgl={cmd.CommandString}"); r.ImportInfo = cmd.CommandString; Commands.AddCommand(r); } return(true); }
private IEnumerable <HpglCommand> SplitLineImpl(IEnumerable <HpglCommand> line) { if (line.Count() < 3) { return(line); } var newline = new List <HpglCommand>(); HpglCommand prev = null; double minLineLength = LoadOptions.SmoothMinLineLength.HasValue ? (double)LoadOptions.SmoothMinLineLength.Value : double.MaxValue; double maxError = LoadOptions.SmoothMaxError.HasValue ? (double)LoadOptions.SmoothMaxError.Value : 1.0 / 40.0; minLineLength /= (double)LoadOptions.ScaleX; maxError /= (double)LoadOptions.ScaleX; foreach (var pt in line) { double x = (pt.PointTo.X0) - (pt.PointFrom.X0); double y = (pt.PointTo.Y0) - (pt.PointFrom.Y0); double c = Math.Sqrt(x * x + y * y); if (minLineLength <= c) { double alpha = pt.DiffLineAngleWithNext ?? (prev?.DiffLineAngleWithNext ?? 0.0); double beta = prev != null ? (prev.DiffLineAngleWithNext ?? 0.0) : alpha; double swapScale = 1.0; if ((alpha >= 0.0 && beta >= 0.0) || (alpha <= 0.0 && beta <= 0.0)) { } else { beta = -beta; swapScale = 0.5; } if ((alpha >= 0.0 && beta >= 0.0) || (alpha <= 0.0 && beta <= 0.0)) { double gamma = Math.PI - alpha - beta; double b = Math.Sin(beta) / Math.Sin(gamma) * c; //double a = Math.Sin(alpha) / Math.Sin(gamma) * c; double hc = b * Math.Sin(alpha) * swapScale; double dc = Math.Sqrt(b * b - hc * hc); double hc4 = hc / 4.0; if (Math.Abs(hc4) > maxError && Math.Abs(hc4) < c && Math.Abs(dc) < c) { newline.Add(GetNewCommand(pt, dc, hc4)); } } } prev = pt; newline.Add(pt); } return(newline); }