From 5762e22a0ce784a8c314531d5895aa904faeceac Mon Sep 17 00:00:00 2001 From: Sven Date: Sun, 18 Aug 2024 20:31:47 +0200 Subject: [PATCH] Version 1.7.4.0 --- GRBL-Plotter/GCodeCreation/Graphic2GCode.cs | 52 ++-- .../GCodeCreation/Graphic2GCodeRelated.cs | 48 +-- GRBL-Plotter/GCodeCreation/GraphicClasses.cs | 22 +- .../GCodeCreation/GraphicCollectData.cs | 76 ++++- .../GCodeCreation/GraphicGenerateHatchFill.cs | 18 +- .../GCodeCreation/GraphicGenerateMisc.cs | 288 ++++++++++-------- .../GCodeCreation/GraphicGenerateSpecial.cs | 42 +-- .../GraphicGenerateTangential.cs | 127 +++++--- GRBL-Plotter/GCodeCreation/ImportMath.cs | 15 +- 9 files changed, 437 insertions(+), 251 deletions(-) diff --git a/GRBL-Plotter/GCodeCreation/Graphic2GCode.cs b/GRBL-Plotter/GCodeCreation/Graphic2GCode.cs index d294bf16..5969e459 100644 --- a/GRBL-Plotter/GCodeCreation/Graphic2GCode.cs +++ b/GRBL-Plotter/GCodeCreation/Graphic2GCode.cs @@ -48,6 +48,7 @@ You should have received a copy of the GNU General Public License * 2024-01-07 l:393 f:CreateGCode if (useToolTable) also adapt width/diameter issue #370 * 2024-03-19 l:970 f:MoveToDashed avoid intermediate G0 coordinates * 2024-04-13 l:438 f:ProcessPathLength new function + * 2024-06-22 l:1116 f:arc tangential */ using System; @@ -94,7 +95,9 @@ public static class Graphic2GCode private static double PathDashArrayDistance = 0; private static bool PathDashArrayPenIsUp = false; - private static double GlobalPathLength = 0; + private static double GlobalPathLengthPD = 0; + private static double GlobalPathLengthPU = 0; + private static Point GlobalPathStart = new Point(); private static double setAux1FinalDistance = 0; // sum-up path distances 396 private static double setAux2FinalDistance = 0; @@ -112,10 +115,8 @@ public static class Graphic2GCode public static void CleanUp() { - // Logger.Trace("CleanUp()"); - gcodeString.Clear(); - gcodeString.Length = 0; - finalGcodeString.Clear(); + gcodeString?.Clear(); + finalGcodeString?.Clear(); } public static void Init() @@ -138,7 +139,10 @@ public static void Init() finalGcodeString.Clear(); PathCount = 0; - GlobalPathLength = 0; + GlobalPathLengthPD = 0; + GlobalPathLengthPU = 0; + GlobalPathStart = Graphic.GetStartPos(); + FigureEndTagWasSet = true; Gcode.Setup(true); // convertGraphics=true (repeat, inser sub) // initialize GCode creation (get stored settings for export) @@ -211,7 +215,7 @@ internal static bool CreateGCode(List tiledGraphic, List", XmlMarker.CollectionEnd)); } Gcode.JobEnd(finalGcodeString, "EndJob"); // Spindle / laser off - ProcessPathLength(GlobalPathLength); + ProcessPathLength(GlobalPathLengthPD, GlobalPathLengthPU); return FinalGCode(graphicInfo.Title, graphicInfo.FilePath); } @@ -320,7 +324,7 @@ internal static bool CreateGCode(List completeGraphic, List if (!useTiles) { Gcode.JobEnd(finalGcodeString, "EndJob"); // Spindle / laser off - ProcessPathLength(GlobalPathLength); + ProcessPathLength(GlobalPathLengthPD, GlobalPathLengthPU); return FinalGCode(graphicInfo.Title, graphicInfo.FilePath); } else @@ -424,7 +428,7 @@ internal static bool CreateGCode(List completeGraphic, List< finalGcodeString.Append(gcodeString); if (multiImport) { Gcode.Comment(finalGcodeString, string.Format("{0}>", XmlMarker.CollectionEnd)); } Gcode.JobEnd(finalGcodeString, "EndJob"); // Spindle / laser off - ProcessPathLength(GlobalPathLength); + ProcessPathLength(GlobalPathLengthPD, GlobalPathLengthPU); return FinalGCode(graphicInfo.Title, graphicInfo.FilePath); } else @@ -435,11 +439,12 @@ internal static bool CreateGCode(List completeGraphic, List< } } - private static void ProcessPathLength(double val) + private static void ProcessPathLength(double valPD, double valPU) { //SetComment(string.Format("Path length: {0:0.00}", val)); - Gcode.gcodeDistance=val; - Logger.Info("Path length: {0:0.00}",val); + Gcode.gcodeDistancePD=valPD; + Gcode.gcodeDistancePU = valPU; + Logger.Info("Path length PD:{0:0.00} PU:{0:0.00}", valPD, valPU); } //convert graphic to gcode ################################################################## @@ -453,7 +458,7 @@ private static void ProcessPathObject(PathObject pathObject, Graphic.GraphicInfo useAlternitveZ = Properties.Settings.Default.importDepthFromWidthRamp || graphicInfo.DxfImportZ; - GlobalPathLength += pathObject.PathLength; + GlobalPathLengthPD += pathObject.PathLength; /* Create Dot */ @@ -495,6 +500,7 @@ private static void ProcessPathObject(PathObject pathObject, Graphic.GraphicInfo pathObject.FigureId = StartPath(DotData, toolNr, toolCmt, "PD"); PenDown("PD"); StopPath("PU DOT"); + GlobalPathStart = DotData.Start; if (Properties.Settings.Default.importSVGCircleToDot && (Properties.Settings.Default.importCircleToDotScriptCount > 0) && (dotCounter >= Properties.Settings.Default.importCircleToDotScriptCount)) { @@ -583,15 +589,18 @@ private static void ProcessPathObject(PathObject pathObject, Graphic.GraphicInfo /* Create Line */ if (entity is GCodeLine) { + // Logger.Trace("# MoveTo {0:0.0} Angle:{1:0.0}", entity.MoveTo, (entity.Angle * 180 / Math.PI)); MoveTo(entity.MoveTo, newZ, newS, entity.Angle, ""); } else if (entity is GCodeArc ArcData) { /* Create Arc */ + // Logger.Trace("# ArcTo {0:0.0} AngleStart:{1:0.0} Angle:{2:0.0}", ArcData.MoveTo, ArcData.AngleStart * 180 / Math.PI, ArcData.Angle * 180 / Math.PI); Arc(ArcData.IsCW, ArcData.MoveTo, ArcData.CenterIJ, ArcData.AngleStart, ArcData.Angle);//, "");// entity.comment); } } StopPath("PU"); + GlobalPathStart = PathData.End; if (graphicInfo.OptionSpecialWireBend) { InsertCode(Properties.Settings.Default.importGraphicWireBenderCodeCut); @@ -787,6 +796,10 @@ private static StringBuilder GetFigureAttributes(PathObject pathObject) private static bool overWriteId = false; private static int StartPath(PathObject pathObject, int toolNr, string toolCmt, string penCmt = "")//string cmt) { + double lengthPU = GcodeMath.DistancePointToPoint(GlobalPathStart, pathObject.Start); + // Logger.Trace("StartPath Length:{0:0.0} from:{1:0.0} to:{2:0.0}", lengthPU, GlobalPathStart, pathObject.Start); + GlobalPathLengthPU += lengthPU; + Point startRamp = pathObject.Start; Point startPenDown = new Point(startRamp.X, startRamp.Y); double angle = pathObject.StartAngle; @@ -906,7 +919,7 @@ private static int StartPath(PathObject pathObject, int toolNr, string toolCmt, Gcode.MoveToRapid(gcodeString, startRamp, ""); PenDown(penCmt); } - if (logCoordinates) Logger.Trace(" StartPath at x{0:0.000} y{1:0.000} a={2:0.00}", startRamp.X, startRamp.Y, setangle); + if (logCoordinates) Logger.Trace(" StartPath G0 at x{0:0.000} y{1:0.000} a={2:0.00}", startRamp.X, startRamp.Y, setangle); if (Properties.Settings.Default.importGraphicLeadInEnable) // importGraphicLeadOutEnable) { @@ -965,7 +978,7 @@ private static void MoveTo(Point coordxy, double newZ, double? newS, double tang PenDown(cmt); // + " moveto" // also process tangetial axis double setangle = 180 * tangAngle / Math.PI; - if (logCoordinates) Logger.Trace(" MoveTo X{0:0.000} Y{1:0.000} A{2:0.00} useAlternitveZ:{3} applyDashPattern:{4}", coordxy.X, coordxy.Y, setangle, useAlternitveZ, applyDashPattern); + if (logCoordinates) Logger.Trace(" MoveTo G1 X{0:0.000} Y{1:0.000} A{2:0.00} useAlternitveZ:{3} applyDashPattern:{4}", coordxy.X, coordxy.Y, setangle, useAlternitveZ, applyDashPattern); Gcode.SetTangential(gcodeString, setangle, true); Gcode.SetAux1DistanceCommand(setAux1FinalDistance); // Create command-snipped, to be added in G1 command (Graphic2GCodeMove.cs - Move) Gcode.SetAux2DistanceCommand(setAux2FinalDistance); @@ -1085,24 +1098,25 @@ private static void Arc(int gnr, double x, double y, double i, double j, double Point coordxy = new Point(x, y); Point center = new Point(lastGC.X + i, lastGC.Y + j); double offset = +Math.PI / 2; - if (logCoordinates) Logger.Trace(" Start Arc G{0} X{1:0.000} Y{2:0.000} angle:{3:0.000} cx{4:0.000} cy{5:0.000} angle:{6:0.000}", gnr, x, y, (180 * tangStartRad / Math.PI), center.X, center.Y, (180 * tangEndRad / Math.PI)); + if (logCoordinates) Logger.Trace(" ArcTo G{0} X{1:0.000} Y{2:0.000} aStart:{3:0.000} cx{4:0.000} cy{5:0.000} aEnd:{6:0.000}", gnr, x, y, (180 * tangStartRad / Math.PI), center.X, center.Y, (180 * tangEndRad / Math.PI)); if (gnr > 2) { offset = -offset; } Gcode.SetTangential(gcodeString, 180 * tangStartRad / Math.PI, true); Gcode.SetAux1DistanceCommand(setAux1FinalDistance); Gcode.SetAux2DistanceCommand(setAux2FinalDistance); - if (logCoordinates) Logger.Trace(" Start Arc alpha{0:0.000} offset{1:0.000} ", 180 * tangStartRad / Math.PI, 180 * offset / Math.PI); + if (logCoordinates) Logger.Trace(" Start Arc alpha{0:0.000} offset{1:0.000} ", 180 * tangStartRad / Math.PI, 180 * offset / Math.PI); PenDown(cmt + " from Arc"); if (GcodeMath.IsEqual(coordxy, lastGC)) // end = start position? Full circle! { if (gnr > 2) - tangEndRad += 2 * Math.PI + tangStartRad; // CW 360° + tangEndRad += 2 * Math.PI;// + tangStartRad; // CW 360° else - tangEndRad -= 2 * Math.PI + tangStartRad; // CCW 360° + tangEndRad -= 2 * Math.PI;// + tangStartRad; // CCW 360° } + if (logCoordinates) Logger.Trace(" End Arc alpha{0:0.000} offset{1:0.000} ", 180 * tangEndRad / Math.PI, 180 * offset / Math.PI); Gcode.SetTangential(gcodeString, 180 * tangEndRad / Math.PI, false); Gcode.Arc(gcodeString, gnr, x, y, i, j, cmt); diff --git a/GRBL-Plotter/GCodeCreation/Graphic2GCodeRelated.cs b/GRBL-Plotter/GCodeCreation/Graphic2GCodeRelated.cs index ce91708f..0c4634d7 100644 --- a/GRBL-Plotter/GCodeCreation/Graphic2GCodeRelated.cs +++ b/GRBL-Plotter/GCodeCreation/Graphic2GCodeRelated.cs @@ -59,6 +59,8 @@ You should have received a copy of the GNU General Public License * 2024-04-13 l:1815 f:SetHeaderInfo add output of path length and new format for process time * 2024-05-06 l:1817 f:GetHeader avoid timespan overflow * 2024-05-07 l:643 f:Setup check GcodeSummary.MetadataUse instead of Properties.Settings.Default.importSVGMetaData) + * 2024-05-28 l:699 f:Setup gcodeAngleStep set min to 0.01 + * 2024-07-08 l:2004 f:IntermediateZ - Z-Up at least on final pass */ using System; @@ -506,7 +508,8 @@ public static partial class Gcode private static int gcodeLines = 0; // counter for GCode lines private static int gcodeFigureLines = 0; // counter for GCode lines - internal static double gcodeDistance = 0; // counter for GCode move distance + internal static double gcodeDistancePD = 0; // counter for GCode move distance + internal static double gcodeDistancePU = 0; // counter for GCode move distance private static float gcodeFigureDistance = 0; // counter for GCode move distance private static int gcodeSubroutineEnable = 0; // state subroutine @@ -561,7 +564,7 @@ public static partial class Gcode private static bool gcodeCompress = false; // reduce code by avoiding sending again same G-Nr and unchanged coordinates public static bool GcodeRelative { get; set; } //= false; // calculate relative coordinates for G91 private static bool gcodeNoArcs = false; // replace arcs by line segments - private static float gcodeAngleStep = 0.1f; + private static double gcodeAngleStep = 0.1; private static bool gcodeInsertSubroutineEnable = false; private static bool gcodeInsertSubroutinePenUpDown = false; private static int gcodeSubroutineCount = 0; @@ -695,7 +698,7 @@ public static string GetSettings() GcodeRelative = (convertGraphics && Properties.Settings.Default.importGCRelative || auxIsRelative); gcodeNoArcs = convertGraphics && Properties.Settings.Default.importGCNoArcs; - gcodeAngleStep = (float)Properties.Settings.Default.importGCSegment; + gcodeAngleStep = Math.Max((double)Properties.Settings.Default.importGCSegment, 0.01); gcodeInsertSubroutineEnable = convertGraphics && Properties.Settings.Default.importGCSubEnable; gcodeInsertSubroutinePenUpDown = convertGraphics && Properties.Settings.Default.importGCSubPenUpDown; @@ -704,7 +707,8 @@ public static string GetSettings() LastMovewasG0 = true; gcodeLines = 1; // counter for GCode lines - gcodeDistance = 0; // counter for GCode move distance + gcodeDistancePD = 0; // counter for GCode move distance + gcodeDistancePU = 0; // counter for GCode move distance remainingC = (float)Properties.Settings.Default.importGCLineSegmentLength; gcodeLineSegmentationEnable = false; @@ -973,6 +977,7 @@ public static void SetPwm(StringBuilder gcodeValue, float pwm, float delay) public static void JobStart(StringBuilder gcodeValue, string cmto) { + bool penup = false; if (gcodeValue != null) { string cmt = cmto; @@ -1001,6 +1006,7 @@ public static void JobStart(StringBuilder gcodeValue, string cmto) else { PenUp(gcodeValue, "PU"); + penup = true; } if (GcodeZApply || gcodeSpindleToggle) @@ -1008,8 +1014,9 @@ public static void JobStart(StringBuilder gcodeValue, string cmto) if (gcodeUseLasermode) // in jobStart { if (gcodeComments) cmt = " (" + cmto + " lasermode )"; - else cmt = ""; - gcodeValue.AppendFormat("M{0} S{1}{2}\r\n", GcodeSpindleCmd, 0, cmt); // switch on laser with power=0 + else cmt = "(JobStart)"; + if (!penup) + gcodeValue.AppendFormat("M{0} S{1}{2}\r\n", GcodeSpindleCmd, 0, cmt); // switch on laser with power=0 } else { @@ -1555,7 +1562,9 @@ internal static void SplitArc(StringBuilder gcodeValue, int gnr, XyzabcuvwPoint XyPoint p2 = new XyPoint(pos2.X, pos2.Y); p1.Round(); p2.Round(); arcMove = GcodeMath.GetArcMoveProperties(p1, p2, i1, j2, (gnr == 2)); // 2020-04-14 add round() - double step = Math.Asin(gcodeAngleStep / arcMove.radius); // in RAD + double step = Math.Abs(Math.Asin(gcodeAngleStep / arcMove.radius)); // in RAD + if (step <= 0) + step = 0.1; if (step > Math.Abs(arcMove.angleDiff)) step = Math.Abs(arcMove.angleDiff / 2); @@ -1735,7 +1744,7 @@ public static void SetHeaderInfo(string title, float distance, float feed, int l { Logger.Trace("SetHeaderInfo title:{0} distance:{1} feed:{2} lines:{3} downUp:{4}", title, distance, feed, lines, downUp); docTitle = title; - gcodeDistance = distance; + gcodeDistancePD = distance; GcodeXYFeed = feed; gcodeLines = lines; gcodeDownUp = downUp; @@ -1743,7 +1752,7 @@ public static void SetHeaderInfo(string title, float distance, float feed, int l } public static string GetHeader(string cmt, string source) { - gcodeTime += gcodeDistance / GcodeXYFeed; + gcodeTime += gcodeDistancePD / GcodeXYFeed; string header = string.Format("( {0} by GRBL-Plotter {1} )\r\n", cmt, MyApplication.GetVersion()); string header_end = headerData.ToString(); header_end += string.Format("({0} >)\r\n", XmlMarker.HeaderEnd); @@ -1812,30 +1821,31 @@ public static string GetHeader(string cmt, string source) Logger.Info("◆◆ Header: G-Code repetitions:{0}", Properties.Settings.Default.importRepeatCnt); } - header += string.Format("( G-Code lines: {0} )\r\n", gcodeLines); + header += string.Format("( G-Code lines : {0} )\r\n", gcodeLines); Logger.Info("◆◆ Header: G-Code lines:{0}", gcodeLines); - header += string.Format("( Pen Down/Up : {0} times )\r\n", gcodeDownUp); - header += string.Format("( Path length : {0:0.0} mm )\r\n", gcodeDistance); + header += string.Format("( Pen Down/Up PD/PU : {0} times )\r\n", gcodeDownUp); + header += string.Format("( Path length (PD) : {0:0.0} mm )\r\n", gcodeDistancePD); + header += string.Format("( Path length (PU) : {0:0.0} mm )\r\n", gcodeDistancePU); try { TimeSpan t = TimeSpan.FromSeconds(gcodeTime * 60); - header += string.Format("( Duration ca.: {0:D2}:{1:D2}:{2:D2} h:m:s )\r\n", t.Hours, t.Minutes, t.Seconds); + header += string.Format("( Duration ca. : {0:D2}:{1:D2}:{2:D2} h:m:s )\r\n", t.Hours, t.Minutes, t.Seconds); } catch (Exception err) { - header += string.Format("( Duration ca.: {0:0.0} min. )\r\n", gcodeTime); + header += string.Format("( Duration ca. : {0:0.0} min. )\r\n", gcodeTime); } if (gcodeSubroutineCount > 0) { - header += string.Format("( Call to subs.: {0} )\r\n", gcodeSubroutineCount); + header += string.Format("( Call to subs. : {0} )\r\n", gcodeSubroutineCount); Logger.Info("◆◆ Header: Subroutine calls:{0}", gcodeSubroutineCount); } stopwatch.Stop(); - header += string.Format("( Conv. time : {0} )\r\n", stopwatch.Elapsed); + header += string.Format("( Conv. time : {0} )\r\n", stopwatch.Elapsed); if (Properties.Settings.Default.importGCToolTableUse) { @@ -1923,7 +1933,7 @@ private static void Drill(StringBuilder gcodeString) gcodeTime += gcodeFigureTime; gcodeLines += gcodeFigureLines + 3; - gcodeDistance += gcodeFigureDistance; + gcodeDistancePD += gcodeFigureDistance; } figureString.Clear(); } @@ -1994,7 +2004,7 @@ private static void IntermediateZ(StringBuilder gcodeString) gcodeLines++; } - if (!gcodeZNoUp) + if (!gcodeZNoUp || (zStep <= finalZ)) // Z-Up at least on final pass { if (gcodeUseLasermode) SpindleOff(gcodeString, "lasermode"); // send S0 gcodeString.AppendFormat("G{0} Z{1} {2}\r\n", FrmtCode(0), FrmtNum(GcodeZUp), ""); // Router up @@ -2006,7 +2016,7 @@ private static void IntermediateZ(StringBuilder gcodeString) gcodeTime += gcodeFigureTime; gcodeLines += gcodeFigureLines + 3; - gcodeDistance += gcodeFigureDistance; + gcodeDistancePD += gcodeFigureDistance; } figureString.Clear(); } diff --git a/GRBL-Plotter/GCodeCreation/GraphicClasses.cs b/GRBL-Plotter/GCodeCreation/GraphicClasses.cs index bf9ae0b7..727f9398 100644 --- a/GRBL-Plotter/GCodeCreation/GraphicClasses.cs +++ b/GRBL-Plotter/GCodeCreation/GraphicClasses.cs @@ -56,7 +56,7 @@ public static partial class Graphic /// /// General information about imported graphic /// - public enum SourceType { none, DXF, SVG, HPGL, CSV, Drill, Gerber, Text, Barcode }; + public enum SourceType { none, DXF, SVG, HPGL, CSV, Drill, Gerber, Text, Barcode, Wire, PDNJson }; public enum GroupOption { none = 0, ByColor = 1, ByWidth = 2, ByLayer = 3, ByType = 4, ByTile = 5, ByFill = 6, Label = 7 }; public enum SortOption { none = 0, ByProperty = 1, ByToolNr = 2, ByCodeSize = 3, ByGraphicDimension = 4 }; public enum CreationOption { none = 0, AddPause = 1, AddPauseBeforePath = 2 }; @@ -80,6 +80,7 @@ internal class GraphicInformationClass public bool ApplyHatchFill { get; set; } // Format related SVG public bool OptionCodeOffset { get; set; } // General options, Graphics import general + public bool OptionCodeOffsetRemoveLargest { get; set; } // General options, Graphics import general public bool OptionCodeSortDistance { get; set; } public bool OptionCodeSortDimension { get; set; } public bool ConvertArcToLine { get; set; } @@ -152,6 +153,7 @@ public GraphicInformationClass() } PauseBeforePath = Properties.Settings.Default.importPauseElement; OptionCodeOffset = Properties.Settings.Default.importGraphicOffsetOrigin; + OptionCodeOffsetRemoveLargest = Properties.Settings.Default.importGraphicOffsetLargestRemove; OptionCodeSortDistance = Properties.Settings.Default.importGraphicSortDistance; OptionCodeSortDimension = Properties.Settings.Default.importGraphicSortDimension; OptionFeedFromToolTable = Properties.Settings.Default.importGCToolTableUse; @@ -172,6 +174,7 @@ public void ResetOptions(bool enableFigures) OptionCodeSortDistance = false; OptionCodeSortDimension = false; OptionCodeOffset = false; + OptionCodeOffsetRemoveLargest = false; ApplyHatchFill = false; OptionHatchFill = false; OptionNoise = false; @@ -221,6 +224,7 @@ public string ListOptions() if (OptionZFromRadius) importOptions += " "; if (Properties.Settings.Default.importGraphicAddFrameEnable) importOptions += " "; if (OptionCodeOffset) importOptions += " "; + if (OptionCodeOffset && OptionCodeOffsetRemoveLargest) importOptions += " "; if (Properties.Settings.Default.importGraphicMultiplyGraphicsEnable) importOptions += " "; if (OptionCodeSortDistance) importOptions += " "; if (ApplyHatchFill) importOptions += " "; @@ -652,6 +656,22 @@ public void AddMotion(GCodeMotion old) AddArc(((GCodeArc)old).MoveTo, ((GCodeArc)old).CenterIJ, ((GCodeArc)old).IsCW, 0, ((GCodeArc)old).AngleStart, ((GCodeArc)old).Angle); } } + public void AddMotion(GCodeMotion old, double offsetX, double offsetY) + { + if (old != null) + { + if (old is GCodeLine) + { + Point newStart = new Point(old.MoveTo.X + offsetX, old.MoveTo.Y + offsetY); + Add(newStart, old.Depth, old.Angle); + } + else + { + Point newStart = new Point(((GCodeArc)old).MoveTo.X + offsetX, ((GCodeArc)old).MoveTo.Y + offsetY); + AddArc(newStart, ((GCodeArc)old).CenterIJ, ((GCodeArc)old).IsCW, old.Depth, ((GCodeArc)old).AngleStart, ((GCodeArc)old).Angle); + } + } + } public void Add(Point tmp, double dz, double ang) { diff --git a/GRBL-Plotter/GCodeCreation/GraphicCollectData.cs b/GRBL-Plotter/GCodeCreation/GraphicCollectData.cs index 8721e9fc..015c45bb 100644 --- a/GRBL-Plotter/GCodeCreation/GraphicCollectData.cs +++ b/GRBL-Plotter/GCodeCreation/GraphicCollectData.cs @@ -63,6 +63,7 @@ You should have received a copy of the GNU General Public License using System; using System.Collections.Generic; using System.ComponentModel; +using System.Data; using System.Diagnostics; using System.Drawing.Drawing2D; using System.Globalization; @@ -153,11 +154,9 @@ public static void CleanUp() ClearList(finalPathList); // = null; ClearList(tileGraphicAll); // = null; ClearList(groupedGraphic); // = null; - headerInfo.Clear(); // = null; - headerMessage.Clear(); // = null; - //backgroundWorker = null; // will be set by GCodeFromxxx - //backgroundEvent = null; - GCode.Clear(); // = null; + headerInfo?.Clear(); // = null; + headerMessage?.Clear(); // = null; + GCode?.Clear(); // = null; GC.Collect(); Logger.Trace("---- CleanUp() after WorkingSet: {0} kb Total Memory: {1:N0} kb", System.Environment.WorkingSet / 1024, GC.GetTotalMemory(true) / 1024); } @@ -295,7 +294,7 @@ public static void Init(SourceType type, string filePath, BackgroundWorker worke countWarnDimNotSet = 0; } - public static bool StartPath(float x, float y) + public static bool StartPath(double x, double y) { return StartPath(new Point(x, y)); } public static bool StartPath(Point xy, double? useZ = null)//, CreationOptions addFunction = CreationOptions.none) @@ -380,7 +379,7 @@ public static void StopPath(string cmt) { if (actualPath.Dimension.IsXYSet()) { - if (graphicInformation.OptionNoise) + if (graphicInformation.OptionNoise) actualPath.Add(lastPoint, GetActualZ(), 0); completeGraphic.Add(actualPath); @@ -468,7 +467,7 @@ private static Point AddNoiseToPath(Point end, double z, int index, double ampli fx *= (amplitude / 2); ; fy *= (-amplitude / 2); ; - float scale, n, nx = 0, ny = 0; + double scale, n, nx = 0, ny = 0; scale = 1;// (float)stepWidth / 2000; //Logger.Trace("AddNoiseToPath step:{0}",step); @@ -476,8 +475,8 @@ private static Point AddNoiseToPath(Point end, double z, int index, double ampli if (step <= 1) { n = Noise.CalcPixel2D(index, 1, scale); - nx = (float)fx * n; - ny = (float)fy * n; + nx = fx * n; + ny = fy * n; actualPath.Add(new Point(x + nx, y + ny), z, 0); //actualPath.Add(end, z, 0); } @@ -486,8 +485,8 @@ private static Point AddNoiseToPath(Point end, double z, int index, double ampli for (int i = 1; i < step; i++) { n = Noise.CalcPixel2D(index, i, scale); - nx = (float)fx * n; - ny = (float)fy * n; + nx = fx * n; + ny = fy * n; x += dix; y += diy; actualPath.Add(new Point(x + nx, y + ny), z, 0); @@ -583,6 +582,40 @@ public static double GetActualZ() return z; } + internal static PathObject GetLastGraphicsItemPath() + { + if ((completeGraphic.Count > 0) && (completeGraphic[completeGraphic.Count - 1] is ItemPath PathData)) + { + return (ItemPath)PathData.Copy(); + } + else return null; + } + + internal static Point AddGraphicsItemPath(PathObject pathToAdd, Point start, int indexStart, int indexEnd) + { + double ox = start.X - pathToAdd.Start.X; + double oy = start.Y - pathToAdd.Start.Y; + + if (pathToAdd is ItemPath PathData && (indexStart < PathData.Path.Count)) + { + // foreach (GCodeMotion entity in PathData.Path) + for (int i = indexStart; i < PathData.Path.Count - indexEnd; i++) + { + actualPath.AddMotion(PathData.Path[i], ox, oy); + } + + Point tmp = PathData.Path[PathData.Path.Count - 1].MoveTo; + return new Point(tmp.X + ox, tmp.Y + oy); + } + return new Point(ox, oy); + } + + internal static void RemoveLastPath() + { + if (completeGraphic.Count > 0) + completeGraphic.RemoveAt(completeGraphic.Count - 1); + } + // set marker, to take-over the flag on next "StartPath" public static void OptionInsertPause() { lastOption |= CreationOption.AddPause; } @@ -618,7 +651,7 @@ public static void SetLabel(string txt) // from inkscape:label, will be added to public static bool SetPenWidth(string txt) // DXF: 0 - 2.11mm = 0 - 211 SVG: 0.000 - ? Convert with to mm, then to string in importClass { - if (logProperties) + if (logProperties) Logger.Trace("SetPenWidth '{0}' called by:{1}", txt, (new System.Diagnostics.StackTrace()).GetFrame(1).GetMethod().Name); if (txt.Contains("NaN")) { @@ -1077,13 +1110,13 @@ public static bool CreateGCode()//Final(BackgroundWorker backgroundWorker, DoWor { backgroundWorker?.ReportProgress(0, new MyUserState { Value = (actOpt++ * 100 / maxOpt), Content = "Sort elements 2) sort by distance (" + countGeometry.ToString() + " elements)" }); Logger.Info("{0} Sort by distance", loggerTag); - SortByDistance(completeGraphic, new Point(0, actualDimension.maxy), false); // CreateGCode + SortByDistance(completeGraphic, GetStartPos(), false); // CreateGCode } } if (!cancelByWorker && graphicInformation.OptionCodeSortDimension) { - Logger.Info("{0} Sort by dimension", loggerTag); + Logger.Info("{0} Sort by dimension - Count:{1}", loggerTag, completeGraphic.Count); SortByDimension(completeGraphic); } @@ -1238,6 +1271,19 @@ public static bool CreateGCode()//Final(BackgroundWorker backgroundWorker, DoWor } // ####################################################################### + internal static Point GetStartPos() + { + int sort = Properties.Settings.Default.importGraphicSortDistanceStart; + Point start; + if (sort == 1) { start = new Point(actualDimension.maxx, actualDimension.maxy); } + else if (sort == 2) { start = new Point(actualDimension.maxx, actualDimension.miny); } + else if (sort == 3) { start = new Point(actualDimension.minx, actualDimension.miny); } + else if (sort == 4) { start = new Point((actualDimension.minx + actualDimension.maxx) / 2, (actualDimension.miny + actualDimension.maxy) / 2); } + else if (sort == 5) { start = new Point(0, 0); } + else if (sort == 6) { start = new Point(Grbl.posWork.X, Grbl.posWork.Y); } + else { start = new Point(actualDimension.minx, actualDimension.maxy); } + return start; + } private static int GetOptionsAmount() { int amount = 1; // backgroud diff --git a/GRBL-Plotter/GCodeCreation/GraphicGenerateHatchFill.cs b/GRBL-Plotter/GCodeCreation/GraphicGenerateHatchFill.cs index 32add2ea..e2e6cb4d 100644 --- a/GRBL-Plotter/GCodeCreation/GraphicGenerateHatchFill.cs +++ b/GRBL-Plotter/GCodeCreation/GraphicGenerateHatchFill.cs @@ -41,10 +41,13 @@ internal static void HatchFill(List graphicToFill) if (graphicToFill == null) return; double distance = (double)Properties.Settings.Default.importGraphicHatchFillDistance; + double distOffset = 0; + double offset = (double)Properties.Settings.Default.importGraphicHatchFillOffset; double angle = (double)Properties.Settings.Default.importGraphicHatchFillAngle; double angle2 = (double)Properties.Settings.Default.importGraphicHatchFillAngle2; bool cross = Properties.Settings.Default.importGraphicHatchFillCross; bool incrementAngle = Properties.Settings.Default.importGraphicHatchFillAngleInc; + bool incrementOffset = Properties.Settings.Default.importGraphicHatchFillOffsetInc; bool deletePath = Properties.Settings.Default.importGraphicHatchFillDeletePath; bool inset2 = Properties.Settings.Default.importGraphicHatchFillInsetEnable && Properties.Settings.Default.importGraphicHatchFillInsetEnable2; @@ -120,10 +123,11 @@ internal static void HatchFill(List graphicToFill) // create hatch pattern hatchPattern.Clear(); - hatchPattern.AddRange(CreateLinePattern(pathDimension, angle, distance)); + hatchPattern.AddRange(CreateLinePattern(pathDimension, angle, distance, distOffset)); if (cross) - hatchPattern.AddRange(CreateLinePattern(pathDimension, angle + 90, distance)); + hatchPattern.AddRange(CreateLinePattern(pathDimension, angle + 90, distance, distOffset)); + if (incrementOffset) distOffset += offset; if (incrementAngle) angle += angle2; // process single hatch lines - shorten to match inside polygone @@ -167,9 +171,9 @@ internal static void HatchFill(List graphicToFill) } - private static List CreateLinePattern(Dimensions dim, double angle, double distance) - { return CreateLinePattern(dim.minx, dim.miny, dim.maxx, dim.maxy, angle, distance); } - private static List CreateLinePattern(double minx, double miny, double maxx, double maxy, double angle, double distance) + private static List CreateLinePattern(Dimensions dim, double angle, double distance, double offset) + { return CreateLinePattern(dim.minx, dim.miny, dim.maxx, dim.maxy, angle, distance, offset); } + private static List CreateLinePattern(double minx, double miny, double maxx, double maxy, double angle, double distance, double offset) { double width = maxx - minx; double height = maxy - miny; @@ -187,7 +191,7 @@ private static List CreateLinePattern(double minx, double miny, double List lines = new List(); // int count = 0; - for (double i = -r; i < r; i += distance) + for (double i = - (r+offset); i < r; i += distance) { x1 = cx + (i * ca) + (r * sa);// # i * ca - (-r) * sa y1 = cy + (i * sa) - (r * ca); //# i * sa + (-r) * ca @@ -267,7 +271,7 @@ private static void AddNoiseToLine(Point start, Point end, int index, double amp fx *= (amplitude / 2); ; fy *= (-amplitude / 2); ; - float scale, n, nx = 0, ny = 0; + double scale, n, nx = 0, ny = 0; scale = 1;// (float)stepWidth / 2000; //Logger.Trace("AddNoiseToPath step:{0}", step); diff --git a/GRBL-Plotter/GCodeCreation/GraphicGenerateMisc.cs b/GRBL-Plotter/GCodeCreation/GraphicGenerateMisc.cs index 377ce73c..b80aae70 100644 --- a/GRBL-Plotter/GCodeCreation/GraphicGenerateMisc.cs +++ b/GRBL-Plotter/GCodeCreation/GraphicGenerateMisc.cs @@ -35,6 +35,8 @@ You should have received a copy of the GNU General Public License * 2023-11-09 l:1067 f:AddFrame -> SetPenFill("none") to avoid hatch-fill * 2023-11-11 l_1030 f:Scale scale also ((GCodeArc)entity).CenterIJ * 2024-04-17 l:1144 f:ExtendClosedPaths also allow path-shortening (negative value) + * 2024-07-25 l:896/1568 f:RemoveOffset/SortByDistance move all largset (same size) objects to the end -> List iLargest = new List(); + * 2024-08-11 l:1684 f:HasSameProperties at least compare color */ using System; @@ -76,14 +78,6 @@ private static void CalculateDistances() ArcProperties tmp = GcodeMath.GetArcMoveProperties((XyPoint)pStart, (XyPoint)pEnd, aPathArc.CenterIJ.X, aPathArc.CenterIJ.Y, aPathArc.IsCW); aPathArc.Depth = Math.Abs(tmp.angleDiff * r); } - /* else if (apath.Path[i] is GCodeArc) - { // is arc - Point center = new Point(pStart.X + ((GCodeArc)apath.Path[i]).CenterIJ.X, pStart.Y + ((GCodeArc)apath.Path[i]).CenterIJ.Y); - double r = PointDistance(center, pEnd); - ArcProperties tmp = GcodeMath.GetArcMoveProperties((XyPoint)pStart, (XyPoint)pEnd, ((GCodeArc)apath.Path[i]).CenterIJ.X, ((GCodeArc)apath.Path[i]).CenterIJ.Y, ((GCodeArc)apath.Path[i]).IsCW); - apath.Path[i].Depth = Math.Abs(tmp.angleDiff * r); - // Logger.Info("CalculateDistances arc a0:{0:0.00} a1:{1:0.00} diff:{2:0.00} r:{3:0.00}", tmp.angleStart,tmp.angleEnd,tmp.angleDiff,r); - }*/ } } } @@ -173,11 +167,8 @@ private static void CreateGraphicsPath(List graphicToDraw, GraphicsP } } - private static bool GroupAllGraphics(List completeGraphic, List groupedGraphicLocal, GraphicInformationClass graphicInformation, bool preventReversal = false) { - // groupedGraphicLocal = new List(); // local 2020-12-14 - // groupedGraphicLocal = groupedGraphic; bool log = logEnable && ((logFlags & (uint)LogEnables.GroupAllGraphics) > 0); keyToIndex = new Dictionary(); string tmpKey = ""; @@ -309,13 +300,15 @@ private static bool GroupAllGraphics(List completeGraphic, List graphicToShow, bool showCoord = false) { - if (logEnable) Logger.Trace(" ListGraphicObjects Count:{0} ##########################################", graphicToShow.Count); + if (!logEnable) + return; + + Logger.Trace(" ListGraphicObjects Count:{0} ##########################################", graphicToShow.Count); int cnt; string coordByLine; string info; @@ -344,7 +337,13 @@ private static void ListGraphicObjects(List graphicToShow, bool show if (showCoord && (graphicItem is ItemPath bpath)) { foreach (GCodeMotion ent in bpath.Path) - { Logger.Trace(" X:{0:0.00} Y:{1:0.00} Z:{2:0.00} Line:{3} ", ent.MoveTo.X, ent.MoveTo.Y, ent.Depth, (ent is GCodeLine).ToString()); } + { + if (ent is GCodeArc) + Logger.Trace(" X:{0:0.00} Y:{1:0.00} Z:{2:0.00} Arc aStart:{4:0.00} aEnd:{5:0.00}", ent.MoveTo.X, ent.MoveTo.Y, ent.Depth, ent.ToString(), ((GCodeArc)ent).AngleStart * 180 / Math.PI, ent.Angle * 180 / Math.PI); + else + Logger.Trace(" X:{0:0.00} Y:{1:0.00} Z:{2:0.00} Line angle:{4:0.00}", ent.MoveTo.X, ent.MoveTo.Y, ent.Depth, ent.ToString(), ent.Angle * 180 / Math.PI); + + } } } } @@ -375,7 +374,7 @@ private static void ClipCode(double tileSizeX, double tileSizeY, double addOnX)/ /* rotate before clipping */ if (Properties.Settings.Default.importGraphicClipAngleEnable) - Rotate(completeGraphic, (double)Properties.Settings.Default.importGraphicClipAngle, tileSizeX / 2, tileSizeY / 2); + Rotate(completeGraphic, (double)Properties.Settings.Default.importGraphicClipAngle * Math.PI / 180, tileSizeX / 2, tileSizeY / 2); if (graphicInformation.OptionCodeOffset) { @@ -754,7 +753,6 @@ private static void RemoveIntermediateSteps(List graphicToImprove) { if (item is ItemPath PathData) { - //ItemPath PathData = (ItemPath)item; Point lastPoint = PathData.End; double angleNow = 0; // when adjacent line segments have the same angle - end point of first can be removed double angleLast = 0; @@ -762,7 +760,7 @@ private static void RemoveIntermediateSteps(List graphicToImprove) double zLast = 0; bool isLineNow = false; bool isLineLast = false; - // bool removeMinDistance; + if (PathData.Path.Count > 2) { zLast = PathData.Path[PathData.Path.Count - 1].Depth; @@ -883,12 +881,23 @@ private static void RemoveShortMoves(List graphicToImprove, double m #endregion #region remove offset + internal static void RemoveOffset() + { + RemoveOffset(completeGraphic, actualDimension.minx, actualDimension.miny); + } + internal static void RemoveOffset(ItemPath tmp, double ox, double oy) + { + foreach (GCodeMotion entity in tmp.Path) + { entity.MoveTo = new Point(entity.MoveTo.X - ox, entity.MoveTo.Y - oy); } + } + private static void RemoveOffset(List graphicToOffset, double offsetX, double offsetY, int start = 0) { System.Diagnostics.StackTrace s = new System.Diagnostics.StackTrace(System.Threading.Thread.CurrentThread, true); - int iLargest = 0; + List iLargest = new List(); double tlarge, largest = 0; + // logEnable = true; if (logEnable) Logger.Trace("...RemoveOffset before min X:{0:0.00} Y:{1:0.00} caller:{2} --------------------------------------", actualDimension.minx, actualDimension.miny, s.GetFrame(1).GetMethod().Name); PathObject item; @@ -898,34 +907,52 @@ private static void RemoveOffset(List graphicToOffset, double offset item.Start = new Point(item.Start.X - offsetX, item.Start.Y - offsetY); item.End = new Point(item.End.X - offsetX, item.End.Y - offsetY); item.Dimension.OffsetXY(-offsetX, -offsetY); - + // Logger.Trace("RemoveOffset {0} {1}", item.FigureId, item.Info.PenColorId); if (item is ItemPath PathData) { foreach (GCodeMotion entity in PathData.Path) { entity.MoveTo = new Point(entity.MoveTo.X - offsetX, entity.MoveTo.Y - offsetY); } - // PathData.Dimension.OffsetXY(-offsetX, -offsetY); - tlarge = PathData.Dimension.dimx + PathData.Dimension.dimy; + tlarge = Math.Round(PathData.Dimension.dimx + PathData.Dimension.dimy); if (tlarge > largest) { + iLargest.Clear(); largest = tlarge; - iLargest = i; - // if (logEnable) Logger.Trace(" Larger: id:{0}", i); + iLargest.Add(i); + // Logger.Trace("RemoveOffset clear/add {0} ", i); + } + else if (tlarge == largest) + { + iLargest.Add(i); + // Logger.Trace("RemoveOffset add {0} ", i); } } } actualDimension.OffsetXY(-offsetX, -offsetY); + //ListGraphicObjects(graphicToOffset); - if (Properties.Settings.Default.importGraphicLargestLast) // move largest object to the end + if (Properties.Settings.Default.importGraphicOffsetLargestLast || Properties.Settings.Default.importGraphicOffsetLargestRemove) // move largest object to the end { - if (logEnable) Logger.Trace("...RemoveOffset move largest object to the end id:{0}", iLargest); - if (graphicToOffset.Count > iLargest) + if (!Properties.Settings.Default.importGraphicOffsetLargestRemove) { - graphicToOffset.Add(graphicToOffset[iLargest]); - graphicToOffset.RemoveAt(iLargest); + if (logEnable) Logger.Trace("...RemoveOffset move largest objects to the end ({0}), ids:{1}", iLargest.Count, String.Join("; ", iLargest)); + for (int li = 0; li < iLargest.Count; li++) + { + if (graphicToOffset.Count > iLargest[li]) + graphicToOffset.Add(graphicToOffset[iLargest[li]]); // 1st add largest at the end + } } else - { Logger.Warn("...RemoveOffset index nok: iLargest:{0} Count:{1}", iLargest, graphicToOffset.Count); } + if (logEnable) Logger.Trace("...RemoveOffset remove largest objects ({0}), ids:{1}", iLargest.Count, String.Join("; ", iLargest)); + + for (int li = iLargest.Count - 1; li >= 0; li--) + { + if (graphicToOffset.Count > iLargest[li]) + { + graphicToOffset.RemoveAt(iLargest[li]); // 2nd remove largest from origin index + } + } } + //ListGraphicObjects(graphicToOffset); } #endregion @@ -980,43 +1007,95 @@ private static void FilterProperties(List graphicToFilter) } } - private static void Rotate(List graphicToRotate, double angle, double offsetX, double offsetY) + public static void Rotate(double angleRad, double offsetX, double offsetY) // scaleX != scaleY will not work for arc! + { Rotate(completeGraphic, angleRad, offsetX, offsetY); } + private static void Rotate(List graphicToRotate, double angleRad, double offsetX, double offsetY) { System.Diagnostics.StackTrace s = new System.Diagnostics.StackTrace(System.Threading.Thread.CurrentThread, true); - - // MessageBox.Show("Methode B wurde von Methode " + s.GetFrame(1).GetMethod().Name + " aufgerufen"); - if (logEnable) Logger.Trace("...Rotate a:{0:0.00} X:{1:0.00} Y:{2:0.00} caller:{3} --------------------------------------", angle, offsetX, offsetY, s.GetFrame(1).GetMethod().Name); + if (logEnable) Logger.Trace("...Rotate a:{0:0.00} X:{1:0.00} Y:{2:0.00} caller:{3} --------------------------------------", angleRad * 180 / Math.PI, offsetX, offsetY, s.GetFrame(1).GetMethod().Name); foreach (PathObject item in graphicToRotate) // dot or path { - item.Start = RotatePoint(item.Start, angle, offsetX, offsetY); - item.End = RotatePoint(item.End, angle, offsetX, offsetY); + item.Start = RotatePoint(item.Start, angleRad, offsetX, offsetY); + item.End = RotatePoint(item.End, angleRad, offsetX, offsetY); if (item is ItemPath PathData) { - //ItemPath PathData = (ItemPath)item; foreach (GCodeMotion entity in PathData.Path) - { entity.MoveTo = RotatePoint(entity.MoveTo, angle, offsetX, offsetY); ; } - //PathData.Dimension.OffsetXY(-offsetX, -offsetY); + { + entity.MoveTo = RotatePoint(entity.MoveTo, angleRad, offsetX, offsetY); + if (entity is GCodeArc arcEntity) + { + Point tmp = RotatePoint(arcEntity.CenterIJ, angleRad, 0, 0); + arcEntity.CenterIJ = new Point(tmp.X, tmp.Y); + } + } } } - actualDimension.OffsetXY(-offsetX, -offsetY); + ReCalcDimension(graphicToRotate); + } + public static void MirrorX() // scaleX != scaleY will not work for arc! + { + List graphicToMirror = completeGraphic; + if (logEnable) Logger.Trace("...MirrorX --------------------------------------"); + foreach (PathObject item in graphicToMirror) // dot or path + { + item.Start = new Point(-item.Start.X, item.Start.Y); + item.End = new Point(-item.End.X, item.End.Y); + if (item is ItemPath PathData) + { + foreach (GCodeMotion entity in PathData.Path) + { + entity.MoveTo = new Point(-entity.MoveTo.X, entity.MoveTo.Y); + if (entity is GCodeArc arcEntity) + { + arcEntity.CenterIJ = new Point(-arcEntity.CenterIJ.X, arcEntity.CenterIJ.Y); + arcEntity.IsCW = !arcEntity.IsCW; + } + } + } + } + ReCalcDimension(graphicToMirror); } - private static Point RotatePoint(Point p, double angle, double offX, double offY) + private static void ReCalcDimension(List graphicToReCalc) + { + if (logEnable) Logger.Trace("ReCalcDimension before dimx:{0:0.00} dimy:{1:0.00}", actualDimension.dimx, actualDimension.dimy); + actualDimension.ResetDimension(); + Point start; + foreach (PathObject item in graphicToReCalc) // dot or path + { + if (item is ItemPath PathData) + { + item.Dimension.ResetDimension(); + start = PathData.Start; + foreach (GCodeMotion entity in PathData.Path) + { + item.Dimension.SetDimensionXY(entity.MoveTo.X, entity.MoveTo.Y); + if (entity is GCodeArc arcEntity) + { + item.Dimension.SetDimensionArc(new XyPoint(start), new XyPoint(entity.MoveTo), arcEntity.CenterIJ.X, arcEntity.CenterIJ.Y, arcEntity.IsCW); + } + start = entity.MoveTo; + } + } + actualDimension.AddDimensionXY(item.Dimension); + } + if (logEnable) Logger.Trace("ReCalcDimension after dimx:{0:0.00} dimy:{1:0.00}", actualDimension.dimx, actualDimension.dimy); + } + private static Point RotatePoint(Point p, double angleRad, double offX, double offY) { - double newvalx = (p.X - offX) * Math.Cos(angle * Math.PI / 180) - (p.Y - offY) * Math.Sin(angle * Math.PI / 180); - double newvaly = (p.X - offX) * Math.Sin(angle * Math.PI / 180) + (p.Y - offY) * Math.Cos(angle * Math.PI / 180); + double newvalx = (p.X - offX) * Math.Cos(angleRad) - (p.Y - offY) * Math.Sin(angleRad); + double newvaly = (p.X - offX) * Math.Sin(angleRad) + (p.Y - offY) * Math.Cos(angleRad); Point pn = new Point(newvalx + offX, newvaly + offY); return pn; } - public static void ScaleXY(double scaleX, double scaleY) // scaleX != scaleY will not work for arc! + public static void ScaleXY(double scaleX, double scaleY) // scaleX != scaleY will not work for arc! { Scale(completeGraphic, scaleX, scaleY); } private static void Scale(List graphicToOffset, double scaleX, double scaleY, int start = 0) { if (logEnable) Logger.Trace("...Scale scaleX:{0:0.00} scaleY:{1:0.00} ", scaleX, scaleY); for (int i = start; i < graphicToOffset.Count; i++) - //foreach (PathObject item in graphicToOffset) // dot or path { var item = graphicToOffset[i]; item.Start = new Point(item.Start.X * scaleX, item.Start.Y * scaleY); @@ -1096,8 +1175,6 @@ private static void MultiplyGraphics(List graphicToRepeat, Dimension List repeatedGraphic = new List(); - // double startx = dim.minx; - // double starty = dim.miny; double dx = dim.dimx + distance; double dy = dim.dimy + distance; double offsetX, offsetY; @@ -1243,10 +1320,9 @@ private static void ExtendClosedPaths(List graphicToExtend, double e break; */ } - } } - else + else //if (shorten && (PathData.Path.Count > 1)) { if (IsEqual(PathData.Start, PathData.End)) //(PathData.Start.X == PathData.End.X) && (PathData.Start.Y == PathData.End.Y)) { @@ -1310,7 +1386,7 @@ private static void ExtendClosedPaths(List graphicToExtend, double e } } } - } // shorten + } // shorten } } } @@ -1321,6 +1397,12 @@ private static void SortByDimension(List graphicToSort) // 2. sort by location // 3. reverse order - smallest = innerst first if (logEnable) Logger.Trace("...SortByDimension() count:{0}", graphicToSort.Count); + if (graphicToSort.Count <= 1) + { + Logger.Info("...SortByDimension() nothing to sort - count:{0}", graphicToSort.Count); + return; + } + stopwatch = new Stopwatch(); stopwatch.Start(); @@ -1334,7 +1416,6 @@ private static void SortByDimension(List graphicToSort) } graphicToSort.Sort((x, y) => y.Distance.CompareTo(x.Distance)); // sort by size, large first - List sortedGraphic = new List(); List lastDim = new List(); double minX, minY, maxX, maxY; @@ -1430,17 +1511,6 @@ private static void SortByDistance(List graphicToSort, Point actualP tmp = graphicToSort[i]; tmp.Distance = PointDistanceSquared(actualPos, tmp.Start); - /*if (backgroundWorker != null) // 2023-08-16 pull request Speed up merge and sort #348 Reduce CPU used updating progress bars - { - if (UpdateGUI()) backgroundWorker.ReportProgress(((maxElements - graphicToSort.Count) * 100) / maxElements); - if (backgroundWorker.CancellationPending) - { - cancelByWorker = true; - backgroundWorker.ReportProgress(100, new MyUserState { Value = 100, Content = "Stop processing, clean up data. Please wait!" }); - break; - } - }*/ - if (tmp is ItemPath tmpItemPath) { /* if closed path, find closest point */ @@ -1448,7 +1518,6 @@ private static void SortByDistance(List graphicToSort, Point actualP { if (closedPathRotate && !preventReversal) { - //ItemPath tmpItemPath = (ItemPath)tmp; if (tmpItemPath.Path.Count > 2) { PathDistanceSquared(actualPos, tmpItemPath); @@ -1491,14 +1560,7 @@ private static void SortByDistance(List graphicToSort, Point actualP minDistIndex = i; } } - /* 2023-08-16 pull request Speed up merge and sort #348 Remove unnecessary sort - graphicToSort.Sort((x, y) => x.Distance.CompareTo(y.Distance)); // sort by distance - - sortedGraphic.Add(graphicToSort[0]); // get closest item = first in list - actualPos = graphicToSort[0].End; // set new start pos - if (logSortMerge) Logger.Trace(" remove id:{0} ", graphicToSort[0].Info.Id); - graphicToSort.RemoveAt(0); // remove item from remaining list - */ + if (minDistIndex != -1) // 2023-08-16 pull request Speed up merge and sort #348 Remove unnecessary sort { sortedGraphic.Add(graphicToSort[minDistIndex]); // get closest item = first in list @@ -1514,7 +1576,7 @@ private static void SortByDistance(List graphicToSort, Point actualP sortedGraphic.Add(tmpgrp); } - int iLargest = 0; + List iLargest = new List(); double tlarge, largest = 0; PathObject sortedItem; for (int i = 0; i < sortedGraphic.Count; i++) // loop through all items @@ -1531,12 +1593,22 @@ private static void SortByDistance(List graphicToSort, Point actualP if (sortedItem is ItemPath tmpItemPath) { - tlarge = tmpItemPath.Dimension.dimx + tmpItemPath.Dimension.dimy; + tlarge = Math.Round(tmpItemPath.Dimension.dimx + tmpItemPath.Dimension.dimy); if (tlarge > largest) { + iLargest.Clear(); largest = tlarge; - iLargest = i; - if (logEnable) Logger.Trace(" Larger: id:{0}", i); + iLargest.Add(i); + if (logEnable) Logger.Trace(" Larger new: id:{0} size:{1:0.00}", i, largest); + } + else if (tlarge == largest) + { + if (logEnable) Logger.Trace(" Larger same:id:{0} size:{1:0.00}", i, largest); + iLargest.Add(i); + } + else + { + if (logEnable) Logger.Trace(" Larger not :id:{0} size:{1:0.00}", i, largest); } } } @@ -1549,21 +1621,21 @@ private static void SortByDistance(List graphicToSort, Point actualP if (Properties.Settings.Default.importGraphicLargestLast) // move largest object to the end { - if (logEnable) Logger.Trace("...SortByDistance move largest object to the end id:{0}", iLargest); - graphicToSort.Add(graphicToSort[iLargest]); - graphicToSort.RemoveAt(iLargest); - // PathObject tmpp = graphicToSort[graphicToSort.Count - 1]; - // graphicToSort[graphicToSort.Count - 1] = graphicToSort[iLargest]; - // graphicToSort[iLargest] = tmpp; + if (logEnable) Logger.Trace("...SortByDistance move largest objects to the end id:{0}", String.Join("; ", iLargest)); + for (int i = 0; i < iLargest.Count; i++) + graphicToSort.Add(graphicToSort[iLargest[i]]); + + for (int i = iLargest.Count - 1; i >= 0; i--) + graphicToSort.RemoveAt(iLargest[i]); } if (logEnable) Logger.Trace("...SortByDistance() finish"); } - private static double PointDistanceSquared(Point a, Point b) // avoid square-root, to save time + private static double PointDistanceSquared(Point a, Point b) // avoid square-root, to save time { double dx = a.X - b.X; double dy = a.Y - b.Y; - return (dx * dx + dy * dy); // speed up + return (dx * dx + dy * dy); // speed up } private static void CircleDistanceSquared(Point a, ItemPath tmp) { @@ -1576,12 +1648,11 @@ private static void CircleDistanceSquared(Point a, ItemPath tmp) }; double distance = PointDistanceSquared(a, ptmp); - // Logger.Trace(" circle angle:{0:0.00} radius:{1:0.00} x:{2:0.00} y:{3:0.00} distance:{4:0.00} ", (aLine*180/Math.PI), arcMove.radius, ptmp.X, ptmp.Y, distance); tmp.Distance = distance; tmp.StartAngle = aLine; } - private static void PathDistanceSquared(Point a, ItemPath tmp) // go through coordinates of path + private static void PathDistanceSquared(Point a, ItemPath tmp) // go through coordinates of path { if (tmp.Path.Count < 2) return; @@ -1596,21 +1667,18 @@ private static void PathDistanceSquared(Point a, ItemPath tmp) // go through coo distance = distTemp; index = i; } - // Logger.Trace(" path a.x:{0:0.00} a.y:{1:0.00} distance:{2:0.00} i:{3} index:{4}", a.X, a.Y, distTemp, i, index); } tmp.Distance = distance; - tmp.TmpIndex = index; //tmp.StartAngle = index; + tmp.TmpIndex = index; if (logSortMerge) Logger.Trace(" path a.x:{0:0.00} a.y:{1:0.00} distance:{2:0.00} i:{3}", a.X, a.Y, distance, index); } private static Point ToPointF(XyPoint tmp) { return new Point((float)tmp.X, (float)tmp.Y); } - //private static bool HasSameProperties(ItemPath a, ItemPath b) private static bool HasSameProperties(ItemPath a, ItemPath b, bool importLineDashPattern) // 2023-08-16 pull request Speed up merge and sort #348 Improve comparing GroupAttributes { if (graphicInformation.GroupEnable) { - //for (int i = 1; i <= 6; i++) // GroupOptions { none = 0, ByColor = 1, ByWidth = 2, ByLayer = 3, ByType = 4, ByTile = 5, ByFill = 6, Label = 7}; for (int i = 1; i < a.Info.GroupAttributes.Count; i++) // GroupOptions { none = 0, ByColor = 1, ByWidth = 2, ByLayer = 3, ByType = 4, ByTile = 5}; { if (logDetailed) Logger.Trace(" hasSameProperties - GroupEnable-Option:{0} a:'{1}' b:'{2}'", i, a.Info.GroupAttributes[i], b.Info.GroupAttributes[i]); @@ -1618,15 +1686,14 @@ private static bool HasSameProperties(ItemPath a, ItemPath b, bool importLineDas return false; } } + else + { + if (a.Info.GroupAttributes[1] != b.Info.GroupAttributes[1]) // 2024-08-11 at least check color + return false; + } - //bool sameDash = true; if (importLineDashPattern) { - //sameDash = false; - //if ((a.DashArray.Length == 0) && (b.DashArray.Length == 0)) - /// sameDash = true; - //else if (a.DashArray == b.DashArray) - // sameDash = true; if ((a.DashArray.Length == 0) && (b.DashArray.Length == 0)) { return true; @@ -1642,15 +1709,9 @@ private static bool HasSameProperties(ItemPath a, ItemPath b, bool importLineDas } } } - //return (sameProperties && sameDash); return true; } - /* private static string ShowArray(double[] tmp) - { string tmps = ""; - foreach (double nr in tmp) - tmps += string.Format( "{0:0.00} ", nr); - return tmps; - }*/ + private static void MergeFigures(List graphicToMerge) { if (logEnable) Logger.Trace("...MergeFigures before:{0} ------------------------------------", graphicToMerge.Count); @@ -1764,15 +1825,6 @@ private static void MergePaths(ItemPath addAtEnd, ItemPath toMerge) // addAtEnd.Info.pathGeometry += ".";// " Merged " + toMerge.Info.id.ToString(); } - /* - private static void SetDotOnly() - { foreach (PathObject item in completeGraphic) // replace original list - { foreach (grblMotion path in item.path) - { path.lineType = MotionType.dot; } - } - }*/ - - private static void RotatePath(ItemPath item) { List rotatedPath = new List(); @@ -1822,11 +1874,10 @@ private static void RotatePath(ItemPath item) } else { - // if ((item.StartAngle == 0) || (iStart >= item.path.Count)) // nothing to rotate if ((item.TmpIndex == 0) || (iStart >= item.Path.Count)) // nothing to rotate return; - tmpMove = new GCodeLine(item.Start); // + tmpMove = new GCodeLine(item.Start); // rotatedPath.Add(tmpMove); for (i = iStart + 1; i < item.Path.Count; i++) @@ -1835,7 +1886,6 @@ private static void RotatePath(ItemPath item) { rotatedPath.Add(item.Path[i]); } } - //item.StartAngle = 0; item.TmpIndex = 0; /* replace original path */ @@ -1884,7 +1934,6 @@ private static void ReversePath(ItemPath item) { double cx = item.Path[i].MoveTo.X + ((GCodeArc)item.Path[i + 1]).CenterIJ.X; // arc is a bit more work double cy = item.Path[i].MoveTo.Y + ((GCodeArc)item.Path[i + 1]).CenterIJ.Y; - // Point center = new Point(cx, cy); double newi = cx - item.Path[i + 1].MoveTo.X; double newj = cy - item.Path[i + 1].MoveTo.Y; tmpMove = new GCodeArc(item.Path[i].MoveTo, new Point(newi, newj), !((GCodeArc)item.Path[i + 1]).IsCW, item.Path[i + 1].Depth); @@ -1895,18 +1944,17 @@ private static void ReversePath(ItemPath item) foreach (GCodeMotion ent in reversedPath) item.Path.Add(ent); - if (!item.IsReversed) // indicatior if Start/End was already switched (in SortCode() + if (!item.IsReversed) // indicatior if Start/End was already switched (in SortCode() { Point tmp = item.End; // if not, do now item.End = item.Start; item.Start = tmp; } - item.IsReversed = false; // reset indicator + item.IsReversed = false; // reset indicator } - public static void AlignLines(int align) // apply offset to figures with same AuxInfo + public static void AlignLines(int align) // apply offset to figures with same AuxInfo { - // Logger.Info("AlignLines gcnt:{0}", completeGraphic.Count); if (completeGraphic.Count > 0) { Dictionary lineDim = new Dictionary(); @@ -1919,12 +1967,10 @@ public static void AlignLines(int align) // apply offset to figures with same Au if (lineDim.ContainsKey(item.Info.AuxInfo)) { lineDim[item.Info.AuxInfo].AddDimensionXY(item.Dimension); - // Logger.Info("AlignLines line:{0} x:{1}", item.Info.AuxInfo, lineDim[item.Info.AuxInfo].dimx); } else { lineDim.Add(item.Info.AuxInfo, new Dimensions(item.Dimension)); - // Logger.Info("AlignLines new line:{0} cnt:{1} x:{2}", item.Info.AuxInfo, cnt, item.Dimension.dimx); } cnt++; } @@ -1935,7 +1981,6 @@ public static void AlignLines(int align) // apply offset to figures with same Au else offsetX = (actualDimension.dimx - pair.Value.dimx); // right lineOffset.Add(pair.Key, offsetX); - // Logger.Info("AlignLines line:{0} offset:{1:0.000}", pair.Key, offsetX); } foreach (PathObject item in completeGraphic) // apply offsets @@ -1945,7 +1990,6 @@ public static void AlignLines(int align) // apply offset to figures with same Au item.End = new Point(item.End.X + offsetX, item.End.Y + offsetY); if (item is ItemPath PathData) { - //ItemPath PathData = (ItemPath)item; foreach (GCodeMotion entity in PathData.Path) { entity.MoveTo = new Point(entity.MoveTo.X + offsetX, entity.MoveTo.Y + offsetY); } PathData.Dimension.OffsetXY(offsetX, offsetY); diff --git a/GRBL-Plotter/GCodeCreation/GraphicGenerateSpecial.cs b/GRBL-Plotter/GCodeCreation/GraphicGenerateSpecial.cs index d5b6e62b..01ba89f2 100644 --- a/GRBL-Plotter/GCodeCreation/GraphicGenerateSpecial.cs +++ b/GRBL-Plotter/GCodeCreation/GraphicGenerateSpecial.cs @@ -650,9 +650,9 @@ public static class Noise /// The number of points to generate /// The scale of the noise. The greater the scale, the denser the noise gets /// An array containing 1D Simplex noise - public static float[] Calc1D(int width, float scale) + public static double[] Calc1D(int width, double scale) { - var values = new float[width]; + var values = new double[width]; for (var i = 0; i < width; i++) values[i] = Generate(i * scale) * 128 + 128; return values; @@ -665,9 +665,9 @@ public static float[] Calc1D(int width, float scale) /// The number of points to generate in the 2nd dimension /// The scale of the noise. The greater the scale, the denser the noise gets /// An array containing 2D Simplex noise - public static float[,] Calc2D(int width, int height, float scale) + public static double[,] Calc2D(int width, int height, double scale) { - var values = new float[width, height]; + var values = new double[width, height]; for (var i = 0; i < width; i++) for (var j = 0; j < height; j++) values[i, j] = Generate(i * scale, j * scale) * 128 + 128; @@ -682,9 +682,9 @@ public static float[] Calc1D(int width, float scale) /// The number of points to generate in the 3nd dimension /// The scale of the noise. The greater the scale, the denser the noise gets /// An array containing 3D Simplex noise - public static float[,,] Calc3D(int width, int height, int length, float scale) + public static double[,,] Calc3D(int width, int height, int length, double scale) { - var values = new float[width, height, length]; + var values = new double[width, height, length]; for (var i = 0; i < width; i++) for (var j = 0; j < height; j++) for (var k = 0; k < length; k++) @@ -698,7 +698,7 @@ public static float[] Calc1D(int width, float scale) /// Index /// The scale of the noise. The greater the scale, the denser the noise gets /// The value of an index of 1D simplex noise - public static float CalcPixel1D(int x, float scale) + public static double CalcPixel1D(int x, float scale) { return Generate(x * scale);// * 128 + 128; } @@ -710,7 +710,7 @@ public static float CalcPixel1D(int x, float scale) /// 2st dimension index /// The scale of the noise. The greater the scale, the denser the noise gets /// The value of an index of 2D simplex noise - public static float CalcPixel2D(int x, int y, float scale) + public static double CalcPixel2D(int x, int y, double scale) { return Generate(x * scale, y * scale);// * 128 + 128; } @@ -724,7 +724,7 @@ public static float CalcPixel2D(int x, int y, float scale) /// 3rd dimension index /// The scale of the noise. The greater the scale, the denser the noise gets /// The value of an index of 3D simplex noise - public static float CalcPixel3D(int x, int y, int z, float scale) + public static double CalcPixel3D(int x, int y, int z, double scale) { return Generate(x * scale, y * scale, z * scale) * 128 + 128; } @@ -766,7 +766,7 @@ public static int Seed /// /// /// - private static float Generate(float x) + private static double Generate(double x) { var i0 = FastFloor(x); var i1 = i0 + 1; @@ -791,12 +791,12 @@ private static float Generate(float x) /// /// /// - private static float Generate(float x, float y) + private static double Generate(double x, double y) { - const float F2 = 0.366025403f; // F2 = 0.5*(sqrt(3.0)-1.0) - const float G2 = 0.211324865f; // G2 = (3.0-Math.sqrt(3.0))/6.0 + const double F2 = 0.366025403f; // F2 = 0.5*(sqrt(3.0)-1.0) + const double G2 = 0.211324865f; // G2 = (3.0-Math.sqrt(3.0))/6.0 - float n0, n1, n2; // Noise contributions from the three corners + double n0, n1, n2; // Noise contributions from the three corners // Skew the input space to determine which simplex cell we're in var s = (x + y) * F2; // Hairy factor for 2D @@ -861,13 +861,13 @@ private static float Generate(float x, float y) } - private static float Generate(float x, float y, float z) + private static double Generate(double x, double y, double z) { // Simple skewing factors for the 3D case const float F3 = 0.333333333f; const float G3 = 0.166666667f; - float n0, n1, n2, n3; // Noise contributions from the four corners + double n0, n1, n2, n3; // Noise contributions from the four corners // Skew the input space to determine which simplex cell we're in var s = (x + y + z) * F3; // Very nice and simple skew factor for 3D @@ -995,7 +995,7 @@ private static float Generate(float x, float y, float z) 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180 }; - private static int FastFloor(float x) + private static int FastFloor(double x) { return (x > 0) ? ((int)x) : (((int)x) - 1); } @@ -1006,7 +1006,7 @@ private static int Mod(int x, int m) return a < 0 ? a + m : a; } - private static float Grad(int hash, float x) + private static double Grad(int hash, double x) { var h = hash & 15; var grad = 1.0f + (h & 7); // Gradient value 1.0, 2.0, ..., 8.0 @@ -1014,7 +1014,7 @@ private static float Grad(int hash, float x) return (grad * x); // Multiply the gradient with the distance } - private static float Grad(int hash, float x, float y) + private static double Grad(int hash, double x, double y) { var h = hash & 7; // Convert low 3 bits of hash code var u = h < 4 ? x : y; // into 8 simple gradient directions, @@ -1022,7 +1022,7 @@ private static float Grad(int hash, float x, float y) return ((h & 1) != 0 ? -u : u) + ((h & 2) != 0 ? -2.0f * v : 2.0f * v); } - private static float Grad(int hash, float x, float y, float z) + private static double Grad(int hash, double x, double y, double z) { var h = hash & 15; // Convert low 4 bits of hash code into 12 simple var u = h < 8 ? x : y; // gradient directions, and compute dot product. @@ -1030,7 +1030,7 @@ private static float Grad(int hash, float x, float y, float z) return ((h & 1) != 0 ? -u : u) + ((h & 2) != 0 ? -v : v); } - private static float Grad(int hash, float x, float y, float z, float t) + private static double Grad(int hash, double x, double y, double z, double t) { var h = hash & 31; // Convert low 5 bits of hash code into 32 simple var u = h < 24 ? x : y; // gradient directions, and compute dot product. diff --git a/GRBL-Plotter/GCodeCreation/GraphicGenerateTangential.cs b/GRBL-Plotter/GCodeCreation/GraphicGenerateTangential.cs index c7e46be6..4a5a86e8 100644 --- a/GRBL-Plotter/GCodeCreation/GraphicGenerateTangential.cs +++ b/GRBL-Plotter/GCodeCreation/GraphicGenerateTangential.cs @@ -69,12 +69,16 @@ public static void CalculateTangentialAxis() double pathShortening = (double)Properties.Settings.Default.importGCTangentialShortening; double maxAngleRad = maxAngleChangeDeg * Math.PI / 180; // in RAD - double angleNow, angleLast, angleOffset, angleApply, angleLastApply; + double angleNow = 0, angleLast, angleOffset, angleApply, angleLastApply; finalPathList = new List(); // figures of one tile ItemPath tempPath; Point pStart, pEnd; Logger.Trace("...CalculateTangentialAxis maxAngle:{0}", maxAngleChangeDeg); - GcodeMath.ResetAngles(); + // GcodeMath.ResetAngles(); + + bool showLog = ((logFlags & loggerSelect) > 0); + + // ListGraphicObjects(completeGraphic, true); foreach (PathObject graphicItem in completeGraphic) { @@ -114,8 +118,10 @@ public static void CalculateTangentialAxis() if (item.Path[i] is GCodeLine) { angleNow = GcodeMath.GetAlpha(pStart, pEnd); // angle-i = p[i-1] to p[i] in radiant - - // if ((loggerTrace & loggerSelect) > 0) Logger.Trace(" TangentialAxis diff:{0:0.00} now:{1:0.00} last:{2:0.00} offfset:{3:0.00} ", diff, angleNow,angleLast, angleOffset); + if ((angleNow - angleLast) < -Math.PI) + angleNow += 2 * Math.PI; + else if ((angleNow - angleLast) > Math.PI) + angleNow -= 2 * Math.PI; if (i == 1) { @@ -124,24 +130,29 @@ public static void CalculateTangentialAxis() angleLastApply = angleApply = angleNow; } - if ((logFlags & loggerSelect) > 0) Logger.Trace(" before angleNow:{0:0.00} angleLast:{1:0.00} angleApply:{2:0.00} offset:{3:0.00}", (angleNow * 180 / Math.PI), (angleLast * 180 / Math.PI), (angleApply * 180 / Math.PI), (angleOffset * 180 / Math.PI)); + if (showLog) Logger.Trace("{0} Line before angleNow:{1:0.00} angleLast:{2:0.00} angleApply:{3:0.00} offset:{4:0.00}", i, (angleNow * 180 / Math.PI), (angleLast * 180 / Math.PI), (angleApply * 180 / Math.PI), (angleOffset * 180 / Math.PI)); double diff = angleNow - angleLast; // + angleOffset; if (diff > Math.PI) { angleOffset -= 2 * Math.PI; } else if (diff < -Math.PI) { angleOffset += 2 * Math.PI; } angleApply = angleNow + angleOffset; - if ((logFlags & loggerSelect) > 0) Logger.Trace(" after angleNow:{0:0.00} angleLast:{1:0.00} angleApply:{2:0.00} offset:{3:0.00}", (angleNow * 180 / Math.PI), (angleLast * 180 / Math.PI), (angleApply * 180 / Math.PI), (angleOffset * 180 / Math.PI)); + if (showLog) Logger.Trace(" Line after angleNow:{0:0.00} angleLast:{1:0.00} angleApply:{2:0.00} offset:{3:0.00}", (angleNow * 180 / Math.PI), (angleLast * 180 / Math.PI), (angleApply * 180 / Math.PI), (angleOffset * 180 / Math.PI)); item.Path[i].Angle = angleApply; - // if ((loggerTrace & loggerSelect) > 0) Logger.Trace(" TangentialAxis Line X:{0:0.00} Y:{1:0.00} end X:{2:0.00} Y:{3:0.00} angleNow:{4:0.00} angleApply:{5:0.00} offset:{6:0.00}", pStart.X, pStart.Y, pEnd.X, pEnd.Y, (angleNow * 180 / Math.PI), (angleApply * 180 / Math.PI), (angleOffset* 180 / Math.PI)); + + if (showLog) Logger.Trace(" GCodeLine angleLastApply:{0:0.00} angleApply:{1:0.00} maxAngleRad:{2:0.00}", (angleLastApply * 180 / Math.PI), (angleApply * 180 / Math.PI), (maxAngleRad * 180 / Math.PI)); + if (showLog) Logger.Trace(" GCodeLine (Math.Abs(angleLastApply - angleApply) > maxAngleRad):{0} FixAngleExceed(ref angleApply, ref angleOffset):{1} ", (Math.Abs(angleLastApply - angleApply) > maxAngleRad), FixAngleExceed(ref angleApply, ref angleOffset)); /* split path if swivel angle is reached*/ if ((Math.Abs(angleLastApply - angleApply) > maxAngleRad) || FixAngleExceed(ref angleApply, ref angleOffset)) // change in angle is too large -> insert pen up/turn/down -> seperate path { - if (tempPath.Path.Count > 1) - finalPathList.Add(tempPath); // save prev path, start new path to force pen up/turn/down - if ((logFlags & loggerSelect) > 0) Logger.Trace(" Exceed angle max:{0:0.00} actual:{1:0.00}", (maxAngleRad * 180 / Math.PI), (Math.Abs(angleLast - angleNow) * 180 / Math.PI)); + if (tempPath.Path.Count > 0) + { + finalPathList.Add(tempPath.Copy()); // save prev path, start new path to force pen up/turn/down + if (showLog) Logger.Trace(" GCodeLine finalPathList.Add(tempPath)"); + } + if (showLog) Logger.Trace(" Exceed angle max:{0:0.00} actual:{1:0.00}", (maxAngleRad * 180 / Math.PI), (Math.Abs(angleLast - angleNow) * 180 / Math.PI)); tempPath = new ItemPath(new Point(pStart.X, pStart.Y)); // start new path with clipped start position tempPath.Info.CopyData(graphicItem.Info); // preset global info for GROUP @@ -163,40 +174,61 @@ public static void CalculateTangentialAxis() /* Process Arc implement fixAngleExceed(ref angleApply, ref angleNow, ref angleOffset)?*/ { double offset = +Math.PI / 2; // angle-i = center to p[i] + 90° it is the tangente - double aStart = 0; - if (!((GCodeArc)item.Path[i]).IsCW) { offset = -offset; } // angleStart-i = center to p[i-1] + 90° + bool isCW = ((GCodeArc)item.Path[i]).IsCW; + if (!isCW) { offset = -offset; } // angleStart-i = center to p[i-1] + 90° Point center = new Point(pStart.X + ((GCodeArc)item.Path[i]).CenterIJ.X, pStart.Y + ((GCodeArc)item.Path[i]).CenterIJ.Y); - aStart = GcodeMath.GetAngle(pStart, center, offset, 0); // angle of tangente + /* Start angle */ + double angleArcStart = GcodeMath.GetAlpha(pStart, center) + offset; // angle of tangente (isCW?2:3) + if ((angleArcStart - angleLast) < -Math.PI) + angleArcStart += 2 * Math.PI; + else if ((angleArcStart - angleLast) > Math.PI) + angleArcStart -= 2 * Math.PI; + if (i == 1) { - angleLast = item.Path[0].Angle = aStart; - tempPath.StartAngle = aStart; + angleLast = item.Path[0].Angle = angleArcStart; + tempPath.StartAngle = angleArcStart; } - double diff = aStart - angleLast; // + angleOffset; + double diff = angleArcStart - angleLast; // + angleOffset; if (diff > Math.PI) { angleOffset -= 2 * Math.PI; } else if (diff < -Math.PI) { angleOffset += 2 * Math.PI; } - angleApply = aStart + angleOffset; + angleArcStart = angleArcStart + angleOffset; - // if (loggerTrace) Logger.Trace(" Tang Circle a-start:{0:0.00} a-end:{1:0.00} ", (angle * 180 / Math.PI)); ((GCodeArc)item.Path[i]).AngleStart = angleApply; - - angleNow = GcodeMath.GetAngle(pEnd, center, offset, 0); - diff = angleNow - angleLast; //+ angleOffset; - if (diff > Math.PI) { angleOffset -= 2 * Math.PI; } - else if (diff < -Math.PI) { angleOffset += 2 * Math.PI; } - angleApply = angleNow + angleOffset; + // Logger.Trace("=== AngleStart {0:0.0} angleArcStart:{1:0.00} angleLast:{2:0.00} angleOffset:{3:0.00} isCW:{4}", angleApply * 180 / Math.PI, angleArcStart * 180 / Math.PI, angleLast * 180 / Math.PI, angleOffset * 180 / Math.PI, isCW); + + /* End angle */ + double angleArcEnd = GcodeMath.GetAlpha(pEnd, center) + offset; + if (isCW && (angleArcEnd > angleArcStart)) // CW aEnd must be < aStart + while (isCW && (angleArcEnd > angleArcStart)) + angleArcEnd -= 2 * Math.PI; + else if (!isCW && (angleArcEnd < angleArcStart)) // CCW aEnd must be > aStart + while (!isCW && (angleArcEnd < angleArcStart)) + angleArcEnd += 2 * Math.PI; + + diff = angleArcEnd - angleArcStart;//angleLast; //+ angleOffset; + if (diff > 2*Math.PI) { angleOffset -= 2 * Math.PI; } + else if (diff < -2*Math.PI) { angleOffset += 2 * Math.PI; } + angleApply = angleArcEnd;// + angleOffset; ((GCodeArc)item.Path[i]).Angle = angleApply; - if ((logFlags & loggerSelect) > 0) Logger.Trace(" Tangential Circle X:{0:0.00} Y:{1:0.00} end X:{2:0.00} Y:{3:0.00} angleStart:{4:0.00} angleEnd:{5:0.00}", pStart.X, pStart.Y, pEnd.X, pEnd.Y, (aStart * 180 / Math.PI), (angleNow * 180 / Math.PI)); - - if (Math.Abs(angleLast - angleNow) > maxAngleRad) // change in angle is too large -> insert pen up/turn/down -> seperate path + // Logger.Trace("=== Angle {0:0.0} angleArcEnd:{1:0.00} angleLast:{2:0.00} angleOffset:{3:0.00} diff:{4:0.00}", angleApply * 180 / Math.PI, angleArcEnd * 180 / Math.PI, angleLast * 180 / Math.PI, angleOffset * 180 / Math.PI, diff); + + if (showLog) Logger.Trace("{0} Tangential Circle X:{1:0.00} Y:{2:0.00} end X:{3:0.00} Y:{4:0.00} angleStart:{5:0.00} angleEnd:{6:0.00} angleLast:{7:0.00}", i, pStart.X, pStart.Y, pEnd.X, pEnd.Y, (angleArcStart * 180 / Math.PI), (angleArcEnd * 180 / Math.PI), (angleLast * 180 / Math.PI)); + //////////////////// + // if (Math.Abs(angleLast - angleArcEnd) > maxAngleRad) // change in angle is too large -> insert pen up/turn/down -> seperate path + + + if (Math.Abs(angleLastApply - angleArcStart) > maxAngleRad) // change in angle is too large -> insert pen up/turn/down -> seperate path { - if (tempPath.Path.Count > 1) + if (tempPath.Path.Count > 0) + { finalPathList.Add(tempPath); // save prev path, start new path to force pen up/turn/down - + if (showLog) Logger.Trace(" Tangential finalPathList.Add"); + } tempPath = new ItemPath(new Point(pStart.X, pStart.Y)); // start new path with clipped start position tempPath.Info.CopyData(graphicItem.Info); // preset global info for GROUP if (actualDashArray.Length > 0) @@ -204,31 +236,42 @@ public static void CalculateTangentialAxis() tempPath.DashArray = new double[actualDashArray.Length]; actualDashArray.CopyTo(tempPath.DashArray, 0); } - } + tempPath.StartAngle = angleArcStart; + tempPath.AddArc((GCodeArc)item.Path[i], item.Path[i].Depth, angleArcStart, angleApply); + if (showLog) Logger.Trace("a Tangential tempPath.AddArc aStart:{0:0.0} aEnd:{1:0.0}", angleArcStart * 180 / Math.PI, angleApply * 180 / Math.PI); + }//////////////////////////// else - { tempPath.AddArc((GCodeArc)item.Path[i], aStart, angleApply, item.Path[i].Depth); } // add point and angle + { + tempPath.AddArc((GCodeArc)item.Path[i], item.Path[i].Depth, angleArcStart, angleApply); + if (showLog) Logger.Trace("b Tangential tempPath.AddArc aStart:{0:0.0} aEnd:{1:0.0}", angleArcStart * 180 / Math.PI, angleApply * 180 / Math.PI); + } // add point and angle + angleLastApply = angleNow = angleApply; } angleLast = angleNow; } - if (tempPath.Path.Count > 1) - finalPathList.Add(tempPath); // save prev path + if (tempPath.Path.Count > 0) + { + finalPathList.Add(tempPath.Copy()); // save prev path + if (showLog) Logger.Trace(" Tangential finalPathList.Add(tempPath)"); + } } else /* Process Dot */ { ItemDot dot = new ItemDot(graphicItem.Start.X, graphicItem.Start.Y); dot.Info.CopyData(graphicItem.Info); // preset global info for GROUP - finalPathList.Add(dot); + finalPathList.Add(dot.Copy()); if ((logFlags & loggerSelect) > 0) Logger.Trace(" Clip Dot copied"); } } completeGraphic.Clear(); - if (pathShorteningEnable) - { - ExtendClosedPaths(finalPathList, pathShortening, true); - } - foreach (PathObject item in finalPathList) // add tile to full graphic - completeGraphic.Add(item); + if (pathShorteningEnable) + { + ExtendClosedPaths(finalPathList, pathShortening, true); + } + foreach (PathObject item in finalPathList) + completeGraphic.Add(item); + // ListGraphicObjects(completeGraphic, true); } private static bool FixAngleExceed(ref double angleApply, ref double angleOffset) @@ -491,8 +534,8 @@ private static void InsertArcMove(ItemPath item, int pos, Point oldPoint, Point int insertCounter = 1; - // if (stepwidth > arcMove.radius / 2) - // { stepwidth = arcMove.radius / 5; } + // if (stepwidth > arcMove.radius / 2) + // { stepwidth = arcMove.radius / 5; } double step = Math.Asin(stepwidth / arcMove.radius); // in RAD // double step = Math.Asin((double)Properties.Settings.Default.importGCSegment / arcMove.radius); // in RAD if (step > Math.Abs(arcMove.angleDiff)) diff --git a/GRBL-Plotter/GCodeCreation/ImportMath.cs b/GRBL-Plotter/GCodeCreation/ImportMath.cs index 4a06699f..96061448 100644 --- a/GRBL-Plotter/GCodeCreation/ImportMath.cs +++ b/GRBL-Plotter/GCodeCreation/ImportMath.cs @@ -31,13 +31,14 @@ namespace GrblPlotter { public static class ImportMath { - // private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger(); + // Trace, Debug, Info, Warn, Error, Fatal + // private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger(); /// /// Calculate Path-Arc-Command - Code from https://github.com/vvvv/SVG/blob/master/Source/Paths/SvgArcSegment.cs /// public static void CalcArc(double astartX, double astartY, double radiusX, double radiusY, - double angle, double size, double sweep, double endX, double endY, Action moveTo) + double angleRad, double size, double sweep, double endX, double endY, Action moveTo) { // Logger.Trace(" calcArc Start: {0};{1} rx: {2} ry: {3} a: {4} size: {5} sweep: {6} End: {7};{8}", StartX, StartY, RadiusX, RadiusY, // Angle, Size, Sweep, EndX, EndY); @@ -46,17 +47,19 @@ public static void CalcArc(double astartX, double astartY, double radiusX, doubl // graphicsPath.AddLine(this.Start, this.End); return; } - double sinPhi = Math.Sin(angle * Math.PI / 180.0); - double cosPhi = Math.Cos(angle * Math.PI / 180.0); + double sinPhi = Math.Sin(angleRad); + double cosPhi = Math.Cos(angleRad); double x1dash = cosPhi * (astartX - endX) / 2.0 + sinPhi * (astartY - endY) / 2.0; double y1dash = -sinPhi * (astartX - endX) / 2.0 + cosPhi * (astartY - endY) / 2.0; double root; double numerator = radiusX * radiusX * radiusY * radiusY - radiusX * radiusX * y1dash * y1dash - radiusY * radiusY * x1dash * x1dash; double rx = radiusX; double ry = radiusY; + + double s = Math.Sqrt(1.0 - numerator / (radiusX * radiusX * radiusY * radiusY)); if (numerator < 0.0) { - double s = Math.Sqrt(1.0 - numerator / (radiusX * radiusX * radiusY * radiusY)); + // double s = Math.Sqrt(1.0 - numerator / (radiusX * radiusX * radiusY * radiusY)); rx *= s; ry *= s; @@ -66,6 +69,8 @@ public static void CalcArc(double astartX, double astartY, double radiusX, doubl { root = ((size == 1 && sweep == 1) || (size == 0 && sweep == 0) ? -1.0 : 1.0) * Math.Sqrt(numerator / (radiusX * radiusX * y1dash * y1dash + radiusY * radiusY * x1dash * x1dash)); } + // Logger.Trace("CalcArc numerator:{0} s:{1} root:{2}", numerator,s,root); + double cxdash = root * rx * y1dash / ry; double cydash = -root * ry * x1dash / rx; double cx = cosPhi * cxdash - sinPhi * cydash + (astartX + endX) / 2.0;