From 241ef42edcd21bb495c318c7f6eb4f7ed8b1bab4 Mon Sep 17 00:00:00 2001 From: HomineLudens Date: Wed, 6 Jan 2021 11:24:46 +0100 Subject: [PATCH 1/8] Refactoring Optimize - Refactor and remove unsused variables - Finally reverse best path to give better human interpretation - Considering all case of the curve AA-AB-BA-BB --- LaserGRBL/GrblFile.cs | 95 ++++++++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 47 deletions(-) diff --git a/LaserGRBL/GrblFile.cs b/LaserGRBL/GrblFile.cs index 73b9adb42..89b59ce76 100644 --- a/LaserGRBL/GrblFile.cs +++ b/LaserGRBL/GrblFile.cs @@ -777,44 +777,52 @@ private List> OptimizeFillingPaths(List> list) //Order all paths in list to reduce travel distance //Calculate and store all distances in a matrix - var distancesA = new double[list.Count, list.Count]; //array bidimensionale delle distanze tra ogni punto e gli altri punti - var distancesB = new double[list.Count, list.Count]; //array bidimensionale delle distanze tra ogni punto e gli altri punti + var distBA = new double[list.Count, list.Count]; //array bidimensionale delle distanze dal punto finale della curva 1 al punto iniziale della curva 2 + var distBB = new double[list.Count, list.Count]; //array bidimensionale delle distanze dal punto finale della curva 1 al punto finale della curva 2 + var distAA = new double[list.Count, list.Count]; //array bidimensionale delle distanze dal punto iniziale della curva 1 al punto iniziale della curva 2 + var distAB = new double[list.Count, list.Count]; //array bidimensionale delle distanze dal punto iniziale della curva 1 al punto finale della curva 2 - for (int p1 = 0; p1 < list.Count; p1++) //ciclo due volte su list + for (int c1 = 0; c1 < list.Count; c1++) //ciclo due volte sulla lista di curve { - for (int p2 = 0; p2 < list.Count; p2++) //con due indici diversi p1, p2 + for (int c2 = 0; c2 < list.Count; c2++) //con due indici diversi c1, c2 { - var dxA = list[p1][0].B.X - list[p2][0].A.X; //deltaX punto finale p1 con punto iniziale p2 - var dyA = list[p1][0].B.Y - list[p2][0].A.Y; //deltaY punto finale p1 con punto iniziale p2 + if (c1 != c2) + { + var dxBA = list[c1].First().B.X - list[c2].Last().A.X; //deltaX punto finale della c1 con punto iniziale c2 + var dyBA = list[c1].First().B.Y - list[c2].Last().A.Y; //deltaY punto finale della c1 con punto iniziale c2 + distBA[c1, c2] = ((dxBA * dxBA) + (dyBA * dyBA)); //distanza quadrata della c1 dal punto iniziale di c2 - var dxB = list[p1][0].B.X - list[p2][0].B.X; //deltaX punto finale p1 con punto finale p2 - var dyB = list[p1][0].B.Y - list[p2][0].B.Y; //deltaY punto finale p1 con punto finale p2 + var dxBB = list[c1].First().B.X - list[c2].Last().B.X; //deltaX punto finale della c1 con punto finale c2 + var dyBB = list[c1].First().B.Y - list[c2].Last().B.Y; //deltaY punto finale della c1 con punto finale c2 + distBB[c1, c2] = ((dxBB * dxBB) + (dyBB * dyBB)); //distanza quadrata della c1 dal punto finale di c2 - if (p1 != p2) - { - distancesA[p1, p2] = (dxA * dxA) + (dyA * dyA); //distanza di p1 dal punto iniziale di p2 - distancesB[p1, p2] = double.MaxValue; // (dxB * dxB) + (dyB * dyB); //distanza di p1 dal punto finale di p2 + var dxAA = list[c1].First().A.X - list[c2].Last().A.X; + var dyAA = list[c1].First().A.Y - list[c2].Last().A.Y; + distAA[c1, c2] = ((dxAA * dxAA) + (dyAA * dyAA)); + + var dxAB = list[c1].First().A.X - list[c2].Last().B.X; + var dyAB = list[c1].First().A.Y - list[c2].Last().B.Y; + distAB[c1, c2] = ((dxAB * dxAB) + (dyAB * dyAB)); } else //distanza del punto con se stesso (caso degenere) { - distancesA[p1, p2] = double.MaxValue; - distancesB[p1, p2] = double.MaxValue; + distBA[c1, c2] = double.MaxValue; + distBB[c1, c2] = double.MaxValue; + distAA[c1, c2] = double.MaxValue; + distAB[c1, c2] = double.MaxValue; } } } - List> best = new List>(); - var bestTotDistance = double.MaxValue; - //Create a list of unvisited places List unvisited = Enumerable.Range(0, list.Count).ToList(); //Pick nearest points - List> nearest = new List>(); + List> bestPath = new List>(); //Save starting point index var lastIndex = 0; - var totDistance = 0.0; + var lastReverse = false; while (unvisited.Count > 0) { var bestIndex = 0; @@ -822,28 +830,30 @@ private List> OptimizeFillingPaths(List> list) var reverseAB = false; foreach (var nextIndex in unvisited) //cicla tutti gli "unvisited" rimanenti { - var distA = distancesA[nextIndex, lastIndex]; //distanza A (al punto iniziale) tra corrente (nextIndex) e ultimo analizzato (lastIndex) - var distB = distancesB[nextIndex, lastIndex]; //distanza B (al punto finale) tra corrente (nextIndex) e ultimo analizzato (lastIndex) + var distToA = lastReverse ? distBA[lastIndex, nextIndex] : distAA[lastIndex, nextIndex]; //distanza dall'inizio partendo dalla fine o dall'inizio + var distToB = lastReverse ? distBB[lastIndex, nextIndex] : distAB[lastIndex, nextIndex]; //distanza dalla fine partendo dalla fine o dall'inizio - if (distA < bestDistance) //se il corrente fornisce un risultato migliore - { - bestIndex = nextIndex; //salva il bestIndex - bestDistance = distA; //salva come risultato migliore - reverseAB = false; - } - if (distB < bestDistance) //idem, ma su punto finale + if (distToA < bestDistance || distToB < bestDistance) { - bestIndex = nextIndex; - bestDistance = distB; - reverseAB = true; + if (distToA < distToB) //se il corrente fornisce un risultato migliore + { + bestIndex = nextIndex; //salva il bestIndex + bestDistance = distToA; //salva come risultato migliore + reverseAB = false; + } + else //idem, ma su punto finale + { + bestIndex = nextIndex; + bestDistance = distToB; + reverseAB = true; + } } - } + lastReverse = reverseAB; var curve = list[bestIndex]; - if (reverseAB) //fai l'inversione della curva se per caso era meglio la distanza con il punto finale + if (reverseAB) //fai l'inversione della curva se per caso era migliore la distanza con il punto finale { - for (int i = 0; i < curve.Count; i++) { var A = curve[i].A; @@ -853,24 +863,15 @@ private List> OptimizeFillingPaths(List> list) curve[i] = new Curve(curve[i].Kind, B, A, cpB, cpA); } } - nearest.Add(curve); - + bestPath.Add(curve); unvisited.Remove(bestIndex); - totDistance += bestDistance; //Save nearest point - lastIndex = bestIndex; //l'ultimo analizzato diventa quello che risulta come bestIndex - } + lastIndex = bestIndex; //l'ultimo miglior indice trovato diventa il prossimo punto da analizzare - //Count traveled distance - if (totDistance < bestTotDistance) //serve a qualcosa? sempre true (bestTotDistance = double.MaxValue) - { - bestTotDistance = totDistance; - //Save best list - best = nearest; } - - return best; + bestPath.Reverse(); + return bestPath; } private List> OptimizePaths(List> list) From e3c5b011c754c2810901e6eb0da4eb44a35ecc9a Mon Sep 17 00:00:00 2001 From: HomineLudens Date: Wed, 6 Jan 2021 12:54:42 +0100 Subject: [PATCH 2/8] Remove unecessary case As the curve is flipped it always the AB-AA case to be consider --- LaserGRBL/GrblFile.cs | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/LaserGRBL/GrblFile.cs b/LaserGRBL/GrblFile.cs index 89b59ce76..a24c0383a 100644 --- a/LaserGRBL/GrblFile.cs +++ b/LaserGRBL/GrblFile.cs @@ -777,8 +777,6 @@ private List> OptimizeFillingPaths(List> list) //Order all paths in list to reduce travel distance //Calculate and store all distances in a matrix - var distBA = new double[list.Count, list.Count]; //array bidimensionale delle distanze dal punto finale della curva 1 al punto iniziale della curva 2 - var distBB = new double[list.Count, list.Count]; //array bidimensionale delle distanze dal punto finale della curva 1 al punto finale della curva 2 var distAA = new double[list.Count, list.Count]; //array bidimensionale delle distanze dal punto iniziale della curva 1 al punto iniziale della curva 2 var distAB = new double[list.Count, list.Count]; //array bidimensionale delle distanze dal punto iniziale della curva 1 al punto finale della curva 2 @@ -788,14 +786,6 @@ private List> OptimizeFillingPaths(List> list) { if (c1 != c2) { - var dxBA = list[c1].First().B.X - list[c2].Last().A.X; //deltaX punto finale della c1 con punto iniziale c2 - var dyBA = list[c1].First().B.Y - list[c2].Last().A.Y; //deltaY punto finale della c1 con punto iniziale c2 - distBA[c1, c2] = ((dxBA * dxBA) + (dyBA * dyBA)); //distanza quadrata della c1 dal punto iniziale di c2 - - var dxBB = list[c1].First().B.X - list[c2].Last().B.X; //deltaX punto finale della c1 con punto finale c2 - var dyBB = list[c1].First().B.Y - list[c2].Last().B.Y; //deltaY punto finale della c1 con punto finale c2 - distBB[c1, c2] = ((dxBB * dxBB) + (dyBB * dyBB)); //distanza quadrata della c1 dal punto finale di c2 - var dxAA = list[c1].First().A.X - list[c2].Last().A.X; var dyAA = list[c1].First().A.Y - list[c2].Last().A.Y; distAA[c1, c2] = ((dxAA * dxAA) + (dyAA * dyAA)); @@ -806,8 +796,6 @@ private List> OptimizeFillingPaths(List> list) } else //distanza del punto con se stesso (caso degenere) { - distBA[c1, c2] = double.MaxValue; - distBB[c1, c2] = double.MaxValue; distAA[c1, c2] = double.MaxValue; distAB[c1, c2] = double.MaxValue; } @@ -822,7 +810,6 @@ private List> OptimizeFillingPaths(List> list) //Save starting point index var lastIndex = 0; - var lastReverse = false; while (unvisited.Count > 0) { var bestIndex = 0; @@ -830,8 +817,8 @@ private List> OptimizeFillingPaths(List> list) var reverseAB = false; foreach (var nextIndex in unvisited) //cicla tutti gli "unvisited" rimanenti { - var distToA = lastReverse ? distBA[lastIndex, nextIndex] : distAA[lastIndex, nextIndex]; //distanza dall'inizio partendo dalla fine o dall'inizio - var distToB = lastReverse ? distBB[lastIndex, nextIndex] : distAB[lastIndex, nextIndex]; //distanza dalla fine partendo dalla fine o dall'inizio + var distToA = distAA[lastIndex, nextIndex]; //distanza dall'inizio partendo dalla fine o dall'inizio + var distToB = distAB[lastIndex, nextIndex]; //distanza dalla fine partendo dalla fine o dall'inizio if (distToA < bestDistance || distToB < bestDistance) { @@ -849,7 +836,6 @@ private List> OptimizeFillingPaths(List> list) } } } - lastReverse = reverseAB; var curve = list[bestIndex]; if (reverseAB) //fai l'inversione della curva se per caso era migliore la distanza con il punto finale @@ -860,7 +846,7 @@ private List> OptimizeFillingPaths(List> list) var B = curve[i].B; var cpA = curve[i].ControlPointA; var cpB = curve[i].ControlPointB; - curve[i] = new Curve(curve[i].Kind, B, A, cpB, cpA); + curve[i] = new Curve(curve[i].Kind, B, A, cpB, cpA); //new curve reversed } } bestPath.Add(curve); From b0ad0e60b338a2b0078431357bd65ae42cb3bf04 Mon Sep 17 00:00:00 2001 From: HomineLudens Date: Wed, 6 Jan 2021 15:57:04 +0100 Subject: [PATCH 3/8] Simplification Taking a simply approach based on specific ouput of potrace --- LaserGRBL/GrblFile.cs | 119 +++++------------------------------------- 1 file changed, 13 insertions(+), 106 deletions(-) diff --git a/LaserGRBL/GrblFile.cs b/LaserGRBL/GrblFile.cs index a24c0383a..c0aad2346 100644 --- a/LaserGRBL/GrblFile.cs +++ b/LaserGRBL/GrblFile.cs @@ -376,7 +376,7 @@ public void LoadImagePotrace(Bitmap bmp, string filename, bool UseSpotRemoval, i { //Optimize fast movement if (useOptimizeFast) - plist = OptimizePaths(plist); + plist = OptimizeFillingPaths(plist); List gc = new List(); if (supportPWM) @@ -777,8 +777,7 @@ private List> OptimizeFillingPaths(List> list) //Order all paths in list to reduce travel distance //Calculate and store all distances in a matrix - var distAA = new double[list.Count, list.Count]; //array bidimensionale delle distanze dal punto iniziale della curva 1 al punto iniziale della curva 2 - var distAB = new double[list.Count, list.Count]; //array bidimensionale delle distanze dal punto iniziale della curva 1 al punto finale della curva 2 + var distBA = new double[list.Count, list.Count]; //array bidimensionale delle distanze dal punto finale della curva 1 al punto iniziale della curva 2 for (int c1 = 0; c1 < list.Count; c1++) //ciclo due volte sulla lista di curve { @@ -786,18 +785,13 @@ private List> OptimizeFillingPaths(List> list) { if (c1 != c2) { - var dxAA = list[c1].First().A.X - list[c2].Last().A.X; - var dyAA = list[c1].First().A.Y - list[c2].Last().A.Y; - distAA[c1, c2] = ((dxAA * dxAA) + (dyAA * dyAA)); - - var dxAB = list[c1].First().A.X - list[c2].Last().B.X; - var dyAB = list[c1].First().A.Y - list[c2].Last().B.Y; - distAB[c1, c2] = ((dxAB * dxAB) + (dyAB * dyAB)); + var dxAA = list[c1].Last().B.X - list[c2].First().A.X; + var dyAA = list[c1].Last().B.Y - list[c2].First().A.Y; + distBA[c1, c2] = ((dxAA * dxAA) + (dyAA * dyAA)); } else //distanza del punto con se stesso (caso degenere) { - distAA[c1, c2] = double.MaxValue; - distAB[c1, c2] = double.MaxValue; + distBA[c1, c2] = double.MaxValue; } } } @@ -810,46 +804,23 @@ private List> OptimizeFillingPaths(List> list) //Save starting point index var lastIndex = 0; + while (unvisited.Count > 0) { var bestIndex = 0; var bestDistance = double.MaxValue; - var reverseAB = false; + foreach (var nextIndex in unvisited) //cicla tutti gli "unvisited" rimanenti { - var distToA = distAA[lastIndex, nextIndex]; //distanza dall'inizio partendo dalla fine o dall'inizio - var distToB = distAB[lastIndex, nextIndex]; //distanza dalla fine partendo dalla fine o dall'inizio - - if (distToA < bestDistance || distToB < bestDistance) + var distToA = distBA[lastIndex, nextIndex]; + if (distToA < bestDistance) { - if (distToA < distToB) //se il corrente fornisce un risultato migliore - { - bestIndex = nextIndex; //salva il bestIndex - bestDistance = distToA; //salva come risultato migliore - reverseAB = false; - } - else //idem, ma su punto finale - { - bestIndex = nextIndex; - bestDistance = distToB; - reverseAB = true; - } + bestIndex = nextIndex; //salva il bestIndex + bestDistance = distToA; //salva come risultato migliore } } - var curve = list[bestIndex]; - if (reverseAB) //fai l'inversione della curva se per caso era migliore la distanza con il punto finale - { - for (int i = 0; i < curve.Count; i++) - { - var A = curve[i].A; - var B = curve[i].B; - var cpA = curve[i].ControlPointA; - var cpB = curve[i].ControlPointB; - curve[i] = new Curve(curve[i].Kind, B, A, cpB, cpA); //new curve reversed - } - } - bestPath.Add(curve); + bestPath.Add(list[bestIndex]); unvisited.Remove(bestIndex); //Save nearest point @@ -860,70 +831,6 @@ private List> OptimizeFillingPaths(List> list) return bestPath; } - private List> OptimizePaths(List> list) - { - if (list.Count == 1) - return list; - - //Order all paths in list to reduce travel distance - //Calculate and store all distances in a matrix - var distances = new double[list.Count, list.Count]; - for (int p1 = 0; p1 < list.Count; p1++) - { - for (int p2 = 0; p2 < list.Count; p2++) - { - var dx = list[p1][0].A.X - list[p2][0].A.X; - var dy = list[p1][0].A.Y - list[p2][0].A.Y; - if (p1 != p2) - distances[p1, p2] = Math.Sqrt((dx * dx) + (dy * dy)); - else - distances[p1, p2] = double.MaxValue; - } - } - - List> best = new List>(); - var bestTotDistance = double.MaxValue; - - //Create a list of unvisited places - List unvisited = Enumerable.Range(0, list.Count).ToList(); - - //Pick nearest points - List> nearest = new List>(); - - //Save starting point index - var lastIndex = 0; - var totDistance = 0.0; - while (unvisited.Count > 0) - { - var bestIndex = 0; - var bestDistance = double.MaxValue; - foreach (var nextIndex in unvisited) - { - var dist = distances[nextIndex, lastIndex]; - if (dist < bestDistance) - { - bestIndex = nextIndex; - bestDistance = dist; - } - } - - //Save nearest point - lastIndex = bestIndex; - nearest.Add(list[lastIndex]); - unvisited.Remove(lastIndex); - totDistance += bestDistance; - } - - //Count traveled distance - if (totDistance < bestTotDistance) - { - bestTotDistance = totDistance; - //Save best list - best = nearest; - } - - return best; - } private int GetColor(Bitmap I, int X, int Y, int min, int max, bool pwm) { From 51e7ee7647caaec07835aa6f70ee2dc0e42ba4dd Mon Sep 17 00:00:00 2001 From: arkypita Date: Wed, 6 Jan 2021 23:49:04 +0100 Subject: [PATCH 4/8] refactoring + add code for direction change optimization --- LaserGRBL/CsPotrace/CsPotraceExportGCODE.cs | 2 - LaserGRBL/CsPotrace/PotraceClipper.cs | 2 +- LaserGRBL/GrblFile.cs | 69 +++++++++++++-------- 3 files changed, 44 insertions(+), 29 deletions(-) diff --git a/LaserGRBL/CsPotrace/CsPotraceExportGCODE.cs b/LaserGRBL/CsPotrace/CsPotraceExportGCODE.cs index 85ff15f8f..81172b6b6 100644 --- a/LaserGRBL/CsPotrace/CsPotraceExportGCODE.cs +++ b/LaserGRBL/CsPotrace/CsPotraceExportGCODE.cs @@ -42,8 +42,6 @@ public static List Export2GCode(List> list, float } List rv = new List(); - - list.Reverse(); foreach (List Curves in list) rv.AddRange(GetPathGC(Curves, lOn, lOff, oX * scale, oY * scale, scale, g, skipcmd)); diff --git a/LaserGRBL/CsPotrace/PotraceClipper.cs b/LaserGRBL/CsPotrace/PotraceClipper.cs index cef76832d..bc3b122d6 100644 --- a/LaserGRBL/CsPotrace/PotraceClipper.cs +++ b/LaserGRBL/CsPotrace/PotraceClipper.cs @@ -48,7 +48,7 @@ internal static List> BuildFilling(List> plist, double s //result.AddLine(pts[0], pts[1]); } - + flist.Reverse(); return flist; } diff --git a/LaserGRBL/GrblFile.cs b/LaserGRBL/GrblFile.cs index c0aad2346..daef4d030 100644 --- a/LaserGRBL/GrblFile.cs +++ b/LaserGRBL/GrblFile.cs @@ -305,16 +305,8 @@ public void LoadImagePotrace(Bitmap bmp, string filename, bool UseSpotRemoval, i if (VectorFilling(c.dir)) { - long t1 = Tools.HiResTimer.TotalMilliseconds; flist = PotraceClipper.BuildFilling(plist, c.res / c.fres, bmp.Width, bmp.Height, c.dir); - long t2 = Tools.HiResTimer.TotalMilliseconds; - - System.Diagnostics.Debug.WriteLine($"BuildFilling = {t2 - t1}ms"); - - flist = ParallelOptimizeFillingPaths(flist); - long t3 = Tools.HiResTimer.TotalMilliseconds; - - System.Diagnostics.Debug.WriteLine($"OptimizeFilling = {t3 - t2}ms"); + flist = ParallelOptimizePaths(flist); } if (RasterFilling(c.dir)) { @@ -376,7 +368,9 @@ public void LoadImagePotrace(Bitmap bmp, string filename, bool UseSpotRemoval, i { //Optimize fast movement if (useOptimizeFast) - plist = OptimizeFillingPaths(plist); + plist = OptimizePaths(plist); + else + plist.Reverse(); //la lista viene fornita da potrace con prima esterni e poi interni, ma per il taglio è meglio il contrario List gc = new List(); if (supportPWM) @@ -735,19 +729,19 @@ private void ExtractSegment(Bitmap image, int x, int y, bool reverse, ref int le prevCol = col; } - private List> ParallelOptimizeFillingPaths(List> list) + private List> ParallelOptimizePaths(List> list) { int maxblocksize = 2048; //max number of List to process in a single OptimizePaths operation int blocknum = (int)Math.Ceiling(list.Count / (double)maxblocksize); if (blocknum <= 1) - return OptimizeFillingPaths(list); + return OptimizePaths(list); System.Diagnostics.Debug.WriteLine("Count: " + list.Count); Task>>[] taskArray = new Task>>[blocknum]; for (int i = 0; i < taskArray.Length; i++) - taskArray[i] = Task.Factory.StartNew((data) => OptimizeFillingPaths((List>)data), GetTaskJob(i, taskArray.Length, list)); + taskArray[i] = Task.Factory.StartNew((data) => OptimizePaths((List>)data), GetTaskJob(i, taskArray.Length, list)); Task.WaitAll(taskArray); List> rv = new List>(); @@ -770,9 +764,9 @@ private List> GetTaskJob(int threadIndex, int threadCount, List> OptimizeFillingPaths(List> list) + private List> OptimizePaths(List> list) { - if (list.Count == 1) + if (list.Count <= 1) return list; //Order all paths in list to reduce travel distance @@ -783,15 +777,27 @@ private List> OptimizeFillingPaths(List> list) { for (int c2 = 0; c2 < list.Count; c2++) //con due indici diversi c1, c2 { - if (c1 != c2) + if (c1 == 0 && c2 == 0) { - var dxAA = list[c1].Last().B.X - list[c2].First().A.X; - var dyAA = list[c1].Last().B.Y - list[c2].First().A.Y; - distBA[c1, c2] = ((dxAA * dxAA) + (dyAA * dyAA)); + distBA[c1, c2] = 0; //il primo dista zero, così siamo sicuri di partire da lui (sotto: if (dist < bestDistance)) } - else //distanza del punto con se stesso (caso degenere) + else if (c1 == c2) { - distBA[c1, c2] = double.MaxValue; + distBA[c1, c2] = double.MaxValue; //distanza del punto con se stesso (caso degenere) + } + else + { + dPoint a1 = list[c1].First().A; //primo segmento (percorso), inizio + dPoint a2 = list[c1].Last().B; //primo segmento (percorso), fine + dPoint b1 = list[c2].First().A; //secondo segmento (percorso), inizio + //dPoint b2 = list[c2].Last().B; //secondo segmento (percorso), fine + + var dX = b1.X - a2.X; + var dY = b1.Y - a2.Y; + + var af = 1; // DirectionChange(a1, a2, b1, 50); + + distBA[c1, c2] = ((dX * dX) + (dY * dY)) * (af * af); } } } @@ -812,11 +818,11 @@ private List> OptimizeFillingPaths(List> list) foreach (var nextIndex in unvisited) //cicla tutti gli "unvisited" rimanenti { - var distToA = distBA[lastIndex, nextIndex]; - if (distToA < bestDistance) + var dist = distBA[lastIndex, nextIndex]; + if (dist < bestDistance) { - bestIndex = nextIndex; //salva il bestIndex - bestDistance = distToA; //salva come risultato migliore + bestIndex = nextIndex; //salva il bestIndex + bestDistance = dist; //salva come risultato migliore } } @@ -827,10 +833,21 @@ private List> OptimizeFillingPaths(List> list) lastIndex = bestIndex; //l'ultimo miglior indice trovato diventa il prossimo punto da analizzare } - bestPath.Reverse(); + return bestPath; } + //questo metodo ritorna un fattore 1 se c'è continuità di direzione, weight se c'è inversione totale + private double DirectionChange(dPoint a1, dPoint a2, dPoint b1, double weight) + { + double angleA = Math.Atan2(a2.Y - a1.Y, a2.X - a1.X); //angolo del segmento corrente + double angleB = Math.Atan2(b1.Y - a2.Y, b1.X - a2.X); //angolo della retta congiungente + + double angleAB = Math.Abs(angleB - angleA); //0 se stessa direzione, pigreco se inverte direzione + double factor = 1 + (angleAB / Math.PI) * (weight - 1); //1 se stessa direzione, weight se inverte direzione + return factor; + } + private int GetColor(Bitmap I, int X, int Y, int min, int max, bool pwm) { From fea26da8dae0ef7653404e100f512dac476f1bf3 Mon Sep 17 00:00:00 2001 From: arkypita Date: Thu, 7 Jan 2021 01:10:12 +0100 Subject: [PATCH 5/8] Update GrblFile.cs --- LaserGRBL/GrblFile.cs | 69 +++++++++++++++++++++++++++---------------- 1 file changed, 43 insertions(+), 26 deletions(-) diff --git a/LaserGRBL/GrblFile.cs b/LaserGRBL/GrblFile.cs index daef4d030..760a5ffd7 100644 --- a/LaserGRBL/GrblFile.cs +++ b/LaserGRBL/GrblFile.cs @@ -769,37 +769,42 @@ private List> OptimizePaths(List> list) if (list.Count <= 1) return list; + dPoint Origin = new dPoint(0, 0); + int nearestToZero = 0; + double bestDistanceToZero = Double.MaxValue; + //Order all paths in list to reduce travel distance //Calculate and store all distances in a matrix - var distBA = new double[list.Count, list.Count]; //array bidimensionale delle distanze dal punto finale della curva 1 al punto iniziale della curva 2 - + double[,] distBA = new double[list.Count, list.Count]; //array bidimensionale delle distanze dal punto finale della curva 1 al punto iniziale della curva 2 for (int c1 = 0; c1 < list.Count; c1++) //ciclo due volte sulla lista di curve { + dPoint a1 = list[c1].First().A; //primo segmento (percorso), inizio + dPoint a2 = list[c1].Last().B; //primo segmento (percorso), fine + for (int c2 = 0; c2 < list.Count; c2++) //con due indici diversi c1, c2 { - if (c1 == 0 && c2 == 0) - { - distBA[c1, c2] = 0; //il primo dista zero, così siamo sicuri di partire da lui (sotto: if (dist < bestDistance)) - } - else if (c1 == c2) + dPoint b1 = list[c2].First().A; //secondo segmento (percorso), inizio + + if (c1 == c2) { distBA[c1, c2] = double.MaxValue; //distanza del punto con se stesso (caso degenere) } else - { - dPoint a1 = list[c1].First().A; //primo segmento (percorso), inizio - dPoint a2 = list[c1].Last().B; //primo segmento (percorso), fine - dPoint b1 = list[c2].First().A; //secondo segmento (percorso), inizio - //dPoint b2 = list[c2].Last().B; //secondo segmento (percorso), fine - - var dX = b1.X - a2.X; - var dY = b1.Y - a2.Y; - - var af = 1; // DirectionChange(a1, a2, b1, 50); + { + double sq =SquareDistance(a2, b1); + double af = 1;// DirectionChange(a1, a2, b1, 50); - distBA[c1, c2] = ((dX * dX) + (dY * dY)) * (af * af); + distBA[c1, c2] = sq * (af * af); } } + + //trova quello che parte più vicino allo zero + double distZero = SquareDistanceZero(a1); + if (distZero < bestDistanceToZero) + { + nearestToZero = c1; + bestDistanceToZero = distZero; + } } //Create a list of unvisited places @@ -808,17 +813,19 @@ private List> OptimizePaths(List> list) //Pick nearest points List> bestPath = new List>(); - //Save starting point index - var lastIndex = 0; - + //parti da quello individuato come "il più vicino allo zero" + bestPath.Add(list[nearestToZero]); + unvisited.Remove(nearestToZero); + int lastIndex = nearestToZero; + while (unvisited.Count > 0) { - var bestIndex = 0; - var bestDistance = double.MaxValue; + int bestIndex = 0; + double bestDistance = double.MaxValue; - foreach (var nextIndex in unvisited) //cicla tutti gli "unvisited" rimanenti + foreach (int nextIndex in unvisited) //cicla tutti gli "unvisited" rimanenti { - var dist = distBA[lastIndex, nextIndex]; + double dist = distBA[lastIndex, nextIndex]; if (dist < bestDistance) { bestIndex = nextIndex; //salva il bestIndex @@ -831,12 +838,22 @@ private List> OptimizePaths(List> list) //Save nearest point lastIndex = bestIndex; //l'ultimo miglior indice trovato diventa il prossimo punto da analizzare - } return bestPath; } + private static double SquareDistance(dPoint a, dPoint b) + { + double dX = b.X - a.X; + double dY = b.Y - a.Y; + return ((dX * dX) + (dY * dY)); + } + private static double SquareDistanceZero(dPoint a) + { + return ((a.X * a.X) + (a.Y * a.Y)); + } + //questo metodo ritorna un fattore 1 se c'è continuità di direzione, weight se c'è inversione totale private double DirectionChange(dPoint a1, dPoint a2, dPoint b1, double weight) { From d4cf4d93bd03a67637dfa97db6daf045e5d3f756 Mon Sep 17 00:00:00 2001 From: arkypita Date: Thu, 7 Jan 2021 09:36:18 +0100 Subject: [PATCH 6/8] Update GrblFile.cs --- LaserGRBL/GrblFile.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/LaserGRBL/GrblFile.cs b/LaserGRBL/GrblFile.cs index 760a5ffd7..c281f650c 100644 --- a/LaserGRBL/GrblFile.cs +++ b/LaserGRBL/GrblFile.cs @@ -791,10 +791,10 @@ private List> OptimizePaths(List> list) } else { - double sq =SquareDistance(a2, b1); - double af = 1;// DirectionChange(a1, a2, b1, 50); + double sq = SquareDistance(a2, b1); + //double af = DirectionChange(a1, a2, b1); - distBA[c1, c2] = sq * (af * af); + distBA[c1, c2] = sq; } } @@ -854,14 +854,14 @@ private static double SquareDistanceZero(dPoint a) return ((a.X * a.X) + (a.Y * a.Y)); } - //questo metodo ritorna un fattore 1 se c'è continuità di direzione, weight se c'è inversione totale - private double DirectionChange(dPoint a1, dPoint a2, dPoint b1, double weight) + //questo metodo ritorna un fattore 0 se c'è continuità di direzione, 0.5 su angolo 90°, 1 se c'è inversione totale (180°) + private double DirectionChange(dPoint a1, dPoint a2, dPoint b1) { double angleA = Math.Atan2(a2.Y - a1.Y, a2.X - a1.X); //angolo del segmento corrente double angleB = Math.Atan2(b1.Y - a2.Y, b1.X - a2.X); //angolo della retta congiungente double angleAB = Math.Abs(angleB - angleA); //0 se stessa direzione, pigreco se inverte direzione - double factor = 1 + (angleAB / Math.PI) * (weight - 1); //1 se stessa direzione, weight se inverte direzione + double factor = angleAB / Math.PI; return factor; } From 268ca5db77b15a6fd3e4cbaf6cdab9f0925e6f24 Mon Sep 17 00:00:00 2001 From: arkypita Date: Thu, 7 Jan 2021 09:59:39 +0100 Subject: [PATCH 7/8] refactoring variable names --- LaserGRBL/GrblFile.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/LaserGRBL/GrblFile.cs b/LaserGRBL/GrblFile.cs index c281f650c..0b0ecca37 100644 --- a/LaserGRBL/GrblFile.cs +++ b/LaserGRBL/GrblFile.cs @@ -778,12 +778,14 @@ private List> OptimizePaths(List> list) double[,] distBA = new double[list.Count, list.Count]; //array bidimensionale delle distanze dal punto finale della curva 1 al punto iniziale della curva 2 for (int c1 = 0; c1 < list.Count; c1++) //ciclo due volte sulla lista di curve { - dPoint a1 = list[c1].First().A; //primo segmento (percorso), inizio - dPoint a2 = list[c1].Last().B; //primo segmento (percorso), fine + dPoint c1fa = list[c1].First().A; //punto iniziale del primo segmento del percorso (per calcolo distanza dallo zero) + dPoint c1la = list[c1].Last().A; //punto iniziale dell'ulimo segmento del percorso (per calcolo direzione di uscita) + dPoint c1lb = list[c1].Last().B; //punto finale dell'ultimo segmento del percorso (per calcolo distanza tra percorsi e direzione di uscita e ingresso) + for (int c2 = 0; c2 < list.Count; c2++) //con due indici diversi c1, c2 { - dPoint b1 = list[c2].First().A; //secondo segmento (percorso), inizio + dPoint c2fa = list[c2].First().A; //punto iniziale del primo segmento del percorso (per calcolo distanza tra percorsi e direzione di ingresso) if (c1 == c2) { @@ -791,15 +793,15 @@ private List> OptimizePaths(List> list) } else { - double sq = SquareDistance(a2, b1); - //double af = DirectionChange(a1, a2, b1); + double sq = SquareDistance(c1lb, c2fa); + double af = DirectionChange(c1la, c1lb, c2fa); distBA[c1, c2] = sq; } } //trova quello che parte più vicino allo zero - double distZero = SquareDistanceZero(a1); + double distZero = SquareDistanceZero(c1fa); if (distZero < bestDistanceToZero) { nearestToZero = c1; From 33574abef3e0f8a90029ce09625d3a2895074cb8 Mon Sep 17 00:00:00 2001 From: arkypita Date: Thu, 7 Jan 2021 10:00:08 +0100 Subject: [PATCH 8/8] comment out test code --- LaserGRBL/GrblFile.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/LaserGRBL/GrblFile.cs b/LaserGRBL/GrblFile.cs index 0b0ecca37..62187af30 100644 --- a/LaserGRBL/GrblFile.cs +++ b/LaserGRBL/GrblFile.cs @@ -779,7 +779,7 @@ private List> OptimizePaths(List> list) for (int c1 = 0; c1 < list.Count; c1++) //ciclo due volte sulla lista di curve { dPoint c1fa = list[c1].First().A; //punto iniziale del primo segmento del percorso (per calcolo distanza dallo zero) - dPoint c1la = list[c1].Last().A; //punto iniziale dell'ulimo segmento del percorso (per calcolo direzione di uscita) + //dPoint c1la = list[c1].Last().A; //punto iniziale dell'ulimo segmento del percorso (per calcolo direzione di uscita) dPoint c1lb = list[c1].Last().B; //punto finale dell'ultimo segmento del percorso (per calcolo distanza tra percorsi e direzione di uscita e ingresso) @@ -794,7 +794,7 @@ private List> OptimizePaths(List> list) else { double sq = SquareDistance(c1lb, c2fa); - double af = DirectionChange(c1la, c1lb, c2fa); + //double af = DirectionChange(c1la, c1lb, c2fa); distBA[c1, c2] = sq; }