public void ClipSegmentTests() { { GCodePath inPath = Newtonsoft.Json.JsonConvert.DeserializeObject <GCodePath>("{\"config\":{\"closedLoop\":true,\"lineWidth_um\":500,\"gcodeComment\":\"WALL-OUTER\",\"speed\":18.9,\"spiralize\":false,\"doSeamHiding\":true,\"Name\":\"inset0Config\"},\"points\":[{\"x\":105366,\"y\":108976,\"z\":300},{\"x\":105743,\"y\":109188,\"z\":300},{\"x\":106352,\"y\":109582,\"z\":300},{\"x\":106606,\"y\":109674,\"z\":300},{\"x\":107513,\"y\":110120,\"z\":300},{\"x\":107766,\"y\":110836,\"z\":300},{\"x\":107804,\"y\":110986,\"z\":300},{\"x\":107806,\"y\":111124,\"z\":300},{\"x\":106720,\"y\":116034,\"z\":300},{\"x\":106669,\"y\":116205,\"z\":300},{\"x\":106345,\"y\":116505,\"z\":300},{\"x\":103152,\"y\":117619,\"z\":300},{\"x\":102975,\"y\":117661,\"z\":300},{\"x\":102749,\"y\":117546,\"z\":300},{\"x\":101132,\"y\":116186,\"z\":300},{\"x\":100997,\"y\":115990,\"z\":300},{\"x\":100845,\"y\":115704,\"z\":300},{\"x\":100673,\"y\":114777,\"z\":300},{\"x\":100959,\"y\":109833,\"z\":300},{\"x\":101785,\"y\":109149,\"z\":300},{\"x\":101836,\"y\":109129,\"z\":300},{\"x\":101976,\"y\":109137,\"z\":300},{\"x\":102415,\"y\":109277,\"z\":300},{\"x\":102712,\"y\":108910,\"z\":300},{\"x\":103239,\"y\":108477,\"z\":300},{\"x\":103355,\"y\":108453,\"z\":300},{\"x\":103710,\"y\":108924,\"z\":300},{\"x\":104116,\"y\":108883,\"z\":300},{\"x\":104330,\"y\":108371,\"z\":300},{\"x\":104867,\"y\":108245,\"z\":300},{\"x\":104888,\"y\":108273,\"z\":300},{\"x\":104980,\"y\":109145,\"z\":300}]}"); GCodePath controlPath = Newtonsoft.Json.JsonConvert.DeserializeObject <GCodePath>("{\"config\":{\"closedLoop\":true,\"lineWidth_um\":500,\"gcodeComment\":\"WALL-OUTER\",\"speed\":18.9,\"spiralize\":false,\"doSeamHiding\":true,\"Name\":\"inset0Config\"},\"points\":[{\"x\":105366,\"y\":108976,\"z\":300},{\"x\":105743,\"y\":109188,\"z\":300},{\"x\":106352,\"y\":109582,\"z\":300},{\"x\":106606,\"y\":109674,\"z\":300},{\"x\":107513,\"y\":110120,\"z\":300},{\"x\":107766,\"y\":110836,\"z\":300},{\"x\":107804,\"y\":110986,\"z\":300},{\"x\":107806,\"y\":111124,\"z\":300},{\"x\":106720,\"y\":116034,\"z\":300},{\"x\":106669,\"y\":116205,\"z\":300},{\"x\":106345,\"y\":116505,\"z\":300},{\"x\":103152,\"y\":117619,\"z\":300},{\"x\":102975,\"y\":117661,\"z\":300},{\"x\":102749,\"y\":117546,\"z\":300},{\"x\":101132,\"y\":116186,\"z\":300},{\"x\":100997,\"y\":115990,\"z\":300},{\"x\":100845,\"y\":115704,\"z\":300},{\"x\":100673,\"y\":114777,\"z\":300},{\"x\":100959,\"y\":109833,\"z\":300},{\"x\":101785,\"y\":109149,\"z\":300},{\"x\":101836,\"y\":109129,\"z\":300},{\"x\":101976,\"y\":109137,\"z\":300},{\"x\":102415,\"y\":109277,\"z\":300},{\"x\":102712,\"y\":108910,\"z\":300},{\"x\":103239,\"y\":108477,\"z\":300},{\"x\":103355,\"y\":108453,\"z\":300},{\"x\":103710,\"y\":108924,\"z\":300},{\"x\":104116,\"y\":108883,\"z\":300},{\"x\":104330,\"y\":108371,\"z\":300},{\"x\":104867,\"y\":108245,\"z\":300},{\"x\":104888,\"y\":108273,\"z\":300},{\"x\":104927,\"y\":108647,\"z\":300}]}"); long targetDistance = (long)(inPath.Config.LineWidthUM); GCodePath testPath = LayerGCodePlanner.TrimGCodePathEnd(inPath, targetDistance); Assert.IsTrue(controlPath.Polygon.Count == testPath.Polygon.Count); for (int i = 0; i < controlPath.Polygon.Count; i++) { Assert.IsTrue(controlPath.Polygon[i] == testPath.Polygon[i]); } } { var path = new Polygon(new IntPoint[] { new IntPoint(0, 0), new IntPoint(0, 10000) }); var trimPath = path.CutToLength(7000); Assert.AreEqual(2, trimPath.Count); Assert.IsTrue(trimPath[1] == new IntPoint(0, 7000)); } { var path = new Polygon(new IntPoint[] { new IntPoint(0, 0), new IntPoint(0, 10000) }); var trimPath = path.TrimEnd(3000); Assert.AreEqual(2, trimPath.Count); Assert.IsTrue(trimPath[1] == new IntPoint(0, 7000)); } { var path = new Polygon(new IntPoint[] { new IntPoint(0, 0), new IntPoint(0, 5000), new IntPoint(0, 10000) }); var trimPath = path.TrimEnd(3000); Assert.AreEqual(3, trimPath.Count); Assert.IsTrue(trimPath[1] == new IntPoint(0, 5000)); Assert.IsTrue(trimPath[2] == new IntPoint(0, 7000)); } { var path = new Polygon(new IntPoint[] { new IntPoint(0, 0), new IntPoint(0, 5000), new IntPoint(0, 10000) }); var trimPath = path.TrimEnd(7000); Assert.AreEqual(2, trimPath.Count); Assert.IsTrue(trimPath[1] == new IntPoint(0, 3000)); } { var path = new Polygon(new IntPoint[] { new IntPoint(0, 0), new IntPoint(0, 10000) }); var trimPath = path.CutToLength(0); Assert.AreEqual(1, trimPath.Count); } { var path = new Polygon(new IntPoint[] { new IntPoint(0, 0), new IntPoint(0, 10000) }); var trimPath = path.CutToLength(20000); Assert.AreEqual(2, trimPath.Count); Assert.IsTrue(trimPath[1] == new IntPoint(0, 10000)); } }
public void MergePathsIgnoringCollinearLines() { //GCodePath path = Newtonsoft.Json.JsonConvert.DeserializeObject<GCodePath>("{\"config\":{\"closedLoop\":true,\"lineWidth_um\":500,\"gcodeComment\":\"WALL-OUTER\",\"speed\":15.0,\"spiralize\":false,\"doSeamHiding\":true,\"Name\":\"inset0Config\"},\"points\":[{\"X\":0,\"Y\":6290,\"Width\":0,\"Z\":200},{\"X\":0,\"Y\":6290,\"Width\":0,\"Z\":200},{\"X\":0,\"Y\":6290,\"Width\":0,\"Z\":200},{\"X\":401,\"Y\":6277,\"Width\":0,\"Z\":200},{\"X\":787,\"Y\":6240,\"Width\":0,\"Z\":200},{\"X\":1185,\"Y\":6177,\"Width\":0,\"Z\":200},{\"X\":1564,\"Y\":6092,\"Width\":0,\"Z\":200},{\"X\":1944,\"Y\":5982,\"Width\":0,\"Z\":200},{\"X\":2315,\"Y\":5848,\"Width\":0,\"Z\":200},{\"X\":2671,\"Y\":5693,\"Width\":0,\"Z\":200},{\"X\":3036,\"Y\":5508,\"Width\":0,\"Z\":200},{\"X\":3369,\"Y\":5310,\"Width\":0,\"Z\":200},{\"X\":3691,\"Y\":5093,\"Width\":0,\"Z\":200}]}"); GCodePath path = Newtonsoft.Json.JsonConvert.DeserializeObject <GCodePath>("{\"config\":{\"closedLoop\":true,\"lineWidth_um\":500,\"gcodeComment\":\"WALL-OUTER\",\"speed\":15.0,\"spiralize\":false,\"doSeamHiding\":true,\"Name\":\"inset0Config\"},\"points\":[{\"X\":0,\"Y\":6290,\"Width\":0,\"Z\":200},{\"X\":0,\"Y\":6290,\"Width\":0,\"Z\":200},{\"X\":0,\"Y\":6290,\"Width\":0,\"Z\":200}]}"); bool pathIsClosed = false; var pathsWithOverlapsRemoved = path.Polygon.MergePerimeterOverlaps(path.Config.LineWidth_um, pathIsClosed); Assert.IsFalse(pathsWithOverlapsRemoved == null); }
public void ClipSegmentTests() { GCodePath inPath = Newtonsoft.Json.JsonConvert.DeserializeObject <GCodePath>("{\"config\":{\"closedLoop\":true,\"lineWidth_um\":500,\"gcodeComment\":\"WALL-OUTER\",\"speed\":18.9,\"spiralize\":false,\"doSeamHiding\":true,\"Name\":\"inset0Config\"},\"points\":[{\"x\":105366,\"y\":108976,\"z\":300},{\"x\":105743,\"y\":109188,\"z\":300},{\"x\":106352,\"y\":109582,\"z\":300},{\"x\":106606,\"y\":109674,\"z\":300},{\"x\":107513,\"y\":110120,\"z\":300},{\"x\":107766,\"y\":110836,\"z\":300},{\"x\":107804,\"y\":110986,\"z\":300},{\"x\":107806,\"y\":111124,\"z\":300},{\"x\":106720,\"y\":116034,\"z\":300},{\"x\":106669,\"y\":116205,\"z\":300},{\"x\":106345,\"y\":116505,\"z\":300},{\"x\":103152,\"y\":117619,\"z\":300},{\"x\":102975,\"y\":117661,\"z\":300},{\"x\":102749,\"y\":117546,\"z\":300},{\"x\":101132,\"y\":116186,\"z\":300},{\"x\":100997,\"y\":115990,\"z\":300},{\"x\":100845,\"y\":115704,\"z\":300},{\"x\":100673,\"y\":114777,\"z\":300},{\"x\":100959,\"y\":109833,\"z\":300},{\"x\":101785,\"y\":109149,\"z\":300},{\"x\":101836,\"y\":109129,\"z\":300},{\"x\":101976,\"y\":109137,\"z\":300},{\"x\":102415,\"y\":109277,\"z\":300},{\"x\":102712,\"y\":108910,\"z\":300},{\"x\":103239,\"y\":108477,\"z\":300},{\"x\":103355,\"y\":108453,\"z\":300},{\"x\":103710,\"y\":108924,\"z\":300},{\"x\":104116,\"y\":108883,\"z\":300},{\"x\":104330,\"y\":108371,\"z\":300},{\"x\":104867,\"y\":108245,\"z\":300},{\"x\":104888,\"y\":108273,\"z\":300},{\"x\":104980,\"y\":109145,\"z\":300}]}"); GCodePath controlPath = Newtonsoft.Json.JsonConvert.DeserializeObject <GCodePath>("{\"config\":{\"closedLoop\":true,\"lineWidth_um\":500,\"gcodeComment\":\"WALL-OUTER\",\"speed\":18.9,\"spiralize\":false,\"doSeamHiding\":true,\"Name\":\"inset0Config\"},\"points\":[{\"x\":105366,\"y\":108976,\"z\":300},{\"x\":105743,\"y\":109188,\"z\":300},{\"x\":106352,\"y\":109582,\"z\":300},{\"x\":106606,\"y\":109674,\"z\":300},{\"x\":107513,\"y\":110120,\"z\":300},{\"x\":107766,\"y\":110836,\"z\":300},{\"x\":107804,\"y\":110986,\"z\":300},{\"x\":107806,\"y\":111124,\"z\":300},{\"x\":106720,\"y\":116034,\"z\":300},{\"x\":106669,\"y\":116205,\"z\":300},{\"x\":106345,\"y\":116505,\"z\":300},{\"x\":103152,\"y\":117619,\"z\":300},{\"x\":102975,\"y\":117661,\"z\":300},{\"x\":102749,\"y\":117546,\"z\":300},{\"x\":101132,\"y\":116186,\"z\":300},{\"x\":100997,\"y\":115990,\"z\":300},{\"x\":100845,\"y\":115704,\"z\":300},{\"x\":100673,\"y\":114777,\"z\":300},{\"x\":100959,\"y\":109833,\"z\":300},{\"x\":101785,\"y\":109149,\"z\":300},{\"x\":101836,\"y\":109129,\"z\":300},{\"x\":101976,\"y\":109137,\"z\":300},{\"x\":102415,\"y\":109277,\"z\":300},{\"x\":102712,\"y\":108910,\"z\":300},{\"x\":103239,\"y\":108477,\"z\":300},{\"x\":103355,\"y\":108453,\"z\":300},{\"x\":103710,\"y\":108924,\"z\":300},{\"x\":104116,\"y\":108883,\"z\":300},{\"x\":104330,\"y\":108371,\"z\":300},{\"x\":104867,\"y\":108245,\"z\":300},{\"x\":104888,\"y\":108273,\"z\":300},{\"x\":104927,\"y\":108647,\"z\":300}]}"); GCodePath testPath = GCodePlanner.TrimPerimeter(inPath, 0); Assert.IsTrue(controlPath.points.Count == testPath.points.Count); for (int i = 0; i < controlPath.points.Count; i++) { Assert.IsTrue(controlPath.points[i] == testPath.points[i]); } }
private bool RemovePerimetersThatOverlap(GCodePath path, double speed, out List<PathAndWidth> pathsWithOverlapsRemoved, bool pathIsClosed) { pathsWithOverlapsRemoved = null; if (path.config.lineWidth_um > 0 && path.points.Count > 2 // If the count is not greater than 2 there is no way it can overlap itself. && gcodeExport.GetPosition() == path.points[path.points.Count - 1]) { if (RemovePerimeterOverlaps(path.points, path.config.lineWidth_um, out pathsWithOverlapsRemoved, pathIsClosed) && pathsWithOverlapsRemoved.Count > 0) { return true; } } return false; }
private static bool TrimPerimeterIfNeeded(GCodePath path, double perimeterStartEndOverlapRatio) { if (path.config.gcodeComment == "WALL-OUTER" || path.config.gcodeComment == "WALL-INNER") { long currentDistance = 0; long targetDistance = (long)(path.config.lineWidth_um * (1-perimeterStartEndOverlapRatio)); if (path.points.Count > 1) { for (int pointIndex = path.points.Count - 1; pointIndex > 0; pointIndex--) { // Calculate distance between 2 points currentDistance = (path.points[pointIndex] - path.points[pointIndex - 1]).Length(); // If distance exceeds clip distance: // - Sets the new last path point if (currentDistance > targetDistance) { long newDistance = currentDistance - targetDistance; if (newDistance > 50) // Don't clip segments less than 50 um. We get too much truncation error. { Point3 dir = (path.points[pointIndex] - path.points[pointIndex - 1]) * newDistance / currentDistance; Point3 clippedEndpoint = path.points[pointIndex - 1] + dir; path.points[pointIndex] = clippedEndpoint; } break; } else if (currentDistance == targetDistance) { // Pops off last point because it is at the limit distance path.points.RemoveAt(path.points.Count - 1); break; } else { // Pops last point and reduces distance remaining to target targetDistance -= currentDistance; path.points.RemoveAt(path.points.Count - 1); } } } // the path was trimmed return true; } return false; }
private static void TrimPerimeterIfNeeded(GCodePath path) { if (path.config.name == "WALL-OUTER" || path.config.name == "WALL-INNER") { double currentDistance = 0; double targetDistance = (long)(path.config.lineWidth * .90); if (path.points.Count > 1) { for (int pointIndex = path.points.Count - 1; pointIndex > 0; pointIndex--) { // Calculate distance between 2 points currentDistance = (path.points[pointIndex] - path.points[pointIndex - 1]).Length(); // If distance exceeds clip distance: // - Sets the new last path point if (currentDistance > targetDistance) { DoublePoint dir = new DoublePoint((path.points[pointIndex].X - path.points[pointIndex - 1].X) / currentDistance, (path.points[pointIndex].Y - path.points[pointIndex - 1].Y) / currentDistance); double newDistance = currentDistance - targetDistance; dir.X *= newDistance; dir.Y *= newDistance; IntPoint clippedEndpoint = path.points[pointIndex - 1] + new IntPoint(dir.X, dir.Y); path.points[pointIndex] = clippedEndpoint; break; } else if (currentDistance == targetDistance) { // Pops off last point because it is at the limit distance path.points.RemoveAt(path.points.Count - 1); break; } else { // Pops last point and reduces distance remaining to target targetDistance = targetDistance - currentDistance; path.points.RemoveAt(path.points.Count - 1); } } } } }
private static void TrimPerimeterIfNeeded(GCodePath path) { if (path.config.gcodeComment == "WALL-OUTER" || path.config.gcodeComment == "WALL-INNER") { long currentDistance = 0; long targetDistance = (long)(path.config.lineWidth_um * .90); if (path.points.Count > 1) { for (int pointIndex = path.points.Count - 1; pointIndex > 0; pointIndex--) { // Calculate distance between 2 points currentDistance = (path.points[pointIndex] - path.points[pointIndex - 1]).Length(); // If distance exceeds clip distance: // - Sets the new last path point if (currentDistance > targetDistance) { long newDistance = currentDistance - targetDistance; Point3 dir = path.points[pointIndex] - path.points[pointIndex - 1] * newDistance / currentDistance; Point3 clippedEndpoint = path.points[pointIndex - 1] + dir; path.points[pointIndex] = clippedEndpoint; break; } else if (currentDistance == targetDistance) { // Pops off last point because it is at the limit distance path.points.RemoveAt(path.points.Count - 1); break; } else { // Pops last point and reduces distance remaining to target targetDistance = targetDistance - currentDistance; path.points.RemoveAt(path.points.Count - 1); } } } } }
private bool RemoveDoubleDrawPerimeterLines(GCodePath path, double speed) { return false; if (path.config.lineWidth_um > 0 && path.points.Count > 2 // If the count is not greater than 2 there is no way it can ovelap itself. && gcodeExport.GetPosition() == path.points[path.points.Count - 1]) { List<List<Point3>> pathsWithOverlapsRemoved = GetPathsWithOverlapsRemoved(path.points, path.config.lineWidth_um / 2); if (pathsWithOverlapsRemoved.Count > 0) { for (int polygonIndex = 0; polygonIndex < pathsWithOverlapsRemoved.Count; polygonIndex++) { int startIndex = 0; List<Point3> polygon = pathsWithOverlapsRemoved[polygonIndex]; if (polygonIndex > 0) { gcodeExport.WriteMove(polygon[0], travelConfig.speed, 0); startIndex = 1; // We skip the first point in the next extrusion, because we just moved to it. } for (int pointIndex = startIndex; pointIndex < polygon.Count; pointIndex++) { gcodeExport.WriteMove(polygon[pointIndex], speed, path.config.lineWidth_um); } } } } }