public void SliceFileWithLeadingLowercaseN() { // Stl with leading n - tests past regression due to c:\path\name.stl where \n in path breaks during stuff/unstuff behavior string stlPath = TestUtilities.GetStlPath("name-with-leading-n"); string gcodePath = TestUtilities.GetTempGCodePath(nameof(SliceFileWithLeadingLowercaseN)); // Create config file var configFilePath = Path.ChangeExtension(gcodePath, "ini"); using (var stream = new StreamWriter(configFilePath)) { stream.WriteLine($"additionalArgsToProcess = -m \"1,0,0,0,0,1,0,0,0,0,1,0,5,0,0,1\" \"{stlPath}\""); } // Slice file MatterSlice.ProcessArgs($"-v -o \"{gcodePath}\" -c \"{configFilePath}\""); // Load and validate generated GCode string[] gcode = TestUtilities.LoadGCodeFile(gcodePath); var movement = new MovementInfo(); // check layer 1 var layer1Info = TestUtilities.GetGCodeForLayer(gcode, 1); var layer1Polygons = TestUtilities.GetExtrusionPolygons(layer1Info, ref movement); Assert.AreEqual(4, layer1Polygons.Count); // check layer 2 var layer2Info = TestUtilities.GetGCodeForLayer(gcode, 2); var layer2Polygons = TestUtilities.GetExtrusionPolygons(layer2Info, ref movement); Assert.AreEqual(4, layer2Polygons.Count); }
public void WindingDirectionDoesNotMatter() { string manifoldFile = TestUtilities.GetStlPath("20mm-box"); string manifoldGCode = TestUtilities.GetTempGCodePath("20mm-box"); string nonManifoldFile = TestUtilities.GetStlPath("20mm-box bad winding"); string nonManifoldGCode = TestUtilities.GetTempGCodePath("20mm-box bad winding"); { // load a model that is correctly manifold ConfigSettings config = new ConfigSettings(); FffProcessor processor = new FffProcessor(config); processor.SetTargetFile(manifoldGCode); processor.LoadStlFile(manifoldFile); // slice and save it processor.DoProcessing(); processor.Finalize(); } { // load a model that has some faces pointing the wrong way ConfigSettings config = new ConfigSettings(); FffProcessor processor = new FffProcessor(config); processor.SetTargetFile(nonManifoldGCode); processor.LoadStlFile(nonManifoldFile); // slice and save it processor.DoProcessing(); processor.Finalize(); } // load both gcode files and check that they are the same TestUtilities.CheckPolysAreSimilar(manifoldGCode, nonManifoldGCode); }
public void SliceFileWithSpaceInName() { // Stl with space in file name - tests past regression due to spaces in file name string stlPath = TestUtilities.GetStlPath("Box Left"); string gcodePath = TestUtilities.GetTempGCodePath(nameof(SliceFileWithSpaceInName)); // Create config file var configFilePath = Path.ChangeExtension(gcodePath, "ini"); using (var stream = new StreamWriter(configFilePath)) { stream.WriteLine($"additionalArgsToProcess = -m \"1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1\" \"{stlPath}\""); } // Slice file MatterSlice.ProcessArgs($"-v -o \"{gcodePath}\" -c \"{configFilePath}\""); // Load and validate generated GCode string[] gcode = TestUtilities.LoadGCodeFile(gcodePath); var movement = default(MovementInfo); // check layer 1 var layer1Info = TestUtilities.GetLayer(gcode, 1); var layer1Polygons = TestUtilities.GetExtrusionPolygonsForLayer(layer1Info, ref movement, false); Assert.AreEqual(2, layer1Polygons.Where(i => i.Count > 2).Count()); // check layer 2 var layer2Info = TestUtilities.GetLayer(gcode, 2); var layer2Polygons = TestUtilities.GetExtrusionPolygonsForLayer(layer2Info, ref movement, false); Assert.AreEqual(2, layer2Polygons.Where(i => i.Count > 2).Count()); }
public void WindingDirectionDoesNotMatter() { string manifoldFile = TestUtilities.GetStlPath("20mm-box"); string manifoldGCode = TestUtilities.GetTempGCodePath("20mm-box"); string nonManifoldFile = TestUtilities.GetStlPath("20mm-box bad winding"); string nonManifoldGCode = TestUtilities.GetTempGCodePath("20mm-box bad winding"); { // load a model that is correctly manifold ConfigSettings config = new ConfigSettings(); fffProcessor processor = new fffProcessor(config); processor.SetTargetFile(manifoldGCode); processor.LoadStlFile(manifoldFile); // slice and save it processor.DoProcessing(); processor.finalize(); } { // load a model that has some faces pointing the wrong way ConfigSettings config = new ConfigSettings(); fffProcessor processor = new fffProcessor(config); processor.SetTargetFile(nonManifoldGCode); processor.LoadStlFile(nonManifoldFile); // slice and save it processor.DoProcessing(); processor.finalize(); } // load both gcode files and check that they are the same string manifoldGCodeContent = File.ReadAllText(manifoldGCode); string nonManifoldGCodeContent = File.ReadAllText(nonManifoldGCode); Assert.AreEqual(manifoldGCodeContent, nonManifoldGCodeContent); }
public void CreatingInfill() { string infillSTL = TestUtilities.GetStlPath("has_infill"); string infillGCode = TestUtilities.GetTempGCodePath("has_infill.gcode"); { // load a model that is correctly manifold var config = new ConfigSettings(); config.ExpandThinWalls = true; config.NumberOfPerimeters = 1; config.AvoidCrossingPerimeters = false; var processor = new FffProcessor(config); processor.SetTargetFile(infillGCode); processor.LoadStlFile(infillSTL); // slice and save it processor.DoProcessing(); processor.Finalize(); string[] loadedGCode = TestUtilities.LoadGCodeFile(infillGCode); for (int i = 0; i < 100; i++) { var movements = loadedGCode.GetGCodeForLayer(i).Movements().ToList(); Assert.GreaterOrEqual(movements.Count, 100, $"Layer {i} should have more than 100 extrusions."); } } }
public void AllPerimetersGoInPolgonDirection() { string thinWallsSTL = TestUtilities.GetStlPath("ThinWallsRect"); string thinWallsGCode = TestUtilities.GetTempGCodePath("ThinWallsRect.gcode"); { // load a model that is correctly manifold var config = new ConfigSettings(); config.ExpandThinWalls = true; config.MergeOverlappingLines = false; var processor = new FffProcessor(config); processor.SetTargetFile(thinWallsGCode); processor.LoadStlFile(thinWallsSTL); // slice and save it processor.DoProcessing(); processor.Finalize(); string[] loadedGCode = TestUtilities.LoadGCodeFile(thinWallsGCode); int layerCount = TestUtilities.LayerCount(loadedGCode); var layerPolygons = loadedGCode.GetAllExtrusionPolygons(); for (int i = 2; i < layerCount - 2; i++) { Assert.LessOrEqual(layerPolygons[i].Count, 4, "We should not have add more than the 4 sides"); foreach (var polygon in layerPolygons[i]) { Assert.AreEqual(1, polygon.GetWindingDirection()); } } } }
public void NoLayerChangeRetractions() { string infillSTL = TestUtilities.GetStlPath("no_layer_change_retractions"); string infillGCode = TestUtilities.GetTempGCodePath("no_layer_change_retractions.gcode"); { // load a model that is correctly manifold var config = new ConfigSettings(); string settingsPath = TestContext.CurrentContext.ResolveProjectPath(4, "Tests", "TestData", "no_retractions_config.ini"); config.ReadSettings(settingsPath); var processor = new FffProcessor(config); processor.SetTargetFile(infillGCode); processor.LoadStlFile(infillSTL); // slice and save it processor.DoProcessing(); processor.Finalize(); string[] gcodeContents = TestUtilities.LoadGCodeFile(infillGCode); int numLayers = TestUtilities.LayerCount(gcodeContents); for (int i = 1; i < numLayers - 2; i++) { string[] layer = TestUtilities.GetGCodeForLayer(gcodeContents, i); int totalRetractions = TestUtilities.CountRetractions(layer); Assert.IsTrue(totalRetractions == 0); } } }
public void AllPerimetersGoInPolgonDirection() { string thinWallsSTL = TestUtilities.GetStlPath("ThinWallsRect.stl"); string thinWallsGCode = TestUtilities.GetTempGCodePath("ThinWallsRect.stl"); { // load a model that is correctly manifold ConfigSettings config = new ConfigSettings(); config.ExpandThinWalls = true; FffProcessor processor = new FffProcessor(config); processor.SetTargetFile(thinWallsGCode); processor.LoadStlFile(thinWallsSTL); // slice and save it processor.DoProcessing(); processor.Finalize(); string[] thinWallsGCodeContent = TestUtilities.LoadGCodeFile(thinWallsGCode); int layerCount = TestUtilities.CountLayers(thinWallsGCodeContent); for (int i = 2; i < layerCount - 2; i++) { var layerGCode = TestUtilities.GetGCodeForLayer(thinWallsGCodeContent, i); var polygons = TestUtilities.GetExtrusionPolygons(layerGCode, 1000); foreach (var polygon in polygons) { Assert.AreEqual(1, polygon.GetWindingDirection()); } } } }
public void AlwaysRetractOnIslandChange() { string meshWithIslands = TestUtilities.GetStlPath("comb"); string gCodeWithIslands = TestUtilities.GetTempGCodePath("comb-box"); { // load a model that has 3 islands ConfigSettings config = new ConfigSettings(); // make sure no retractions are going to occur that are island crossing config.MinimumTravelToCauseRetraction = 2000; FffProcessor processor = new FffProcessor(config); processor.SetTargetFile(gCodeWithIslands); processor.LoadStlFile(meshWithIslands); // slice and save it processor.DoProcessing(); processor.Finalize(); string[] gcodeContents = TestUtilities.LoadGCodeFile(gCodeWithIslands); int numLayers = TestUtilities.CountLayers(gcodeContents); for (int i = 1; i < numLayers - 1; i++) { string[] layer = TestUtilities.GetGCodeForLayer(gcodeContents, i); int totalRetractions = TestUtilities.CountRetractions(layer); Assert.IsTrue(totalRetractions == 6); } } }
public void SliceFileWithSpaceInGCodePath() { // GCode file with space in file name string gcodePath = TestUtilities.GetTempGCodePath("gcode file with space"); string stlPath = TestUtilities.GetStlPath("Box Left"); // Create config file var configFilePath = Path.ChangeExtension(gcodePath, "ini"); using (var stream = new StreamWriter(configFilePath)) { stream.WriteLine($"additionalArgsToProcess = -m \"1,0,0,0,0,1,0,0,0,0,1,0,5,0,0,1\" \"{stlPath}\""); } // Slice file MatterSlice.ProcessArgs($"-v -o \"{gcodePath}\" -c \"{configFilePath}\""); // Load and validate generated GCode string[] gcode = TestUtilities.LoadGCodeFile(gcodePath); var movement = new MovementInfo(); // check layer 1 var layer1Info = TestUtilities.GetGCodeForLayer(gcode, 1); var layer1Polygons = TestUtilities.GetExtrusionPolygons(layer1Info, ref movement); Assert.AreEqual(4, layer1Polygons.Count); // check layer 2 var layer2Info = TestUtilities.GetGCodeForLayer(gcode, 2); var layer2Polygons = TestUtilities.GetExtrusionPolygons(layer2Info, ref movement); Assert.AreEqual(4, layer2Polygons.Count); }
public void SingleLayerCreated() { string point3mmStlFile = TestUtilities.GetStlPath("Point3mm"); string point3mmGCodeFile = TestUtilities.GetTempGCodePath("Point3mm.gcode"); var config = new ConfigSettings(); config.FirstLayerThickness = .25; config.LayerThickness = .25; config.NumberOfSkirtLoops = 0; var processor = new FffProcessor(config); processor.SetTargetFile(point3mmGCodeFile); processor.LoadStlFile(point3mmStlFile); // slice and save it processor.DoProcessing(); processor.Finalize(); var loadedGCode = TestUtilities.LoadGCodeFile(point3mmGCodeFile); var layers = TestUtilities.CountLayers(loadedGCode); Assert.AreEqual(1, layers); var totalExtrusions = TestUtilities.GetExtrusionPolygons(loadedGCode); #if __ANDROID__ Assert.IsTrue(totalExtrusions.Count > 0); Assert.IsTrue(totalExtrusions[0].PolygonLength() > 100); #else Assert.Greater(totalExtrusions.Count, 0); Assert.Greater(totalExtrusions[0].PolygonLength(), 100); #endif }
public void CorrectIslandCount2() { void Test(bool mergeOverlaps, bool expandWalls) { string engineStlFile = TestUtilities.GetStlPath("all_layers"); string engineGCodeFile = TestUtilities.GetTempGCodePath($"all_layers - merge overlap {mergeOverlaps} - expand walls {expandWalls}.gcode"); var config = new ConfigSettings(); config.FirstLayerThickness = .2; config.LayerThickness = .2; config.NumberOfSkirtLoops = 0; config.InfillPercent = 0; config.NumberOfTopLayers = 0; config.NumberOfBottomLayers = 0; config.NumberOfPerimeters = 1; config.MergeOverlappingLines = mergeOverlaps; config.ExpandThinWalls = expandWalls; config.FillThinGaps = false; config.AvoidCrossingPerimeters = false; var processor = new FffProcessor(config); processor.SetTargetFile(engineGCodeFile); processor.LoadStlFile(engineStlFile); // slice and save it processor.DoProcessing(); processor.Dispose(); var loadedGCode = TestUtilities.LoadGCodeFile(engineGCodeFile); var layers = TestUtilities.LayerCount(loadedGCode); Assert.AreEqual(45, layers); var expectedIslands = new int[] { 7, 7, 7, 5, 5, // 0 - 4 5, 5, 5, 5, 5, // 5 - 9 5, 5, 5, 5, 5, // 10 - 14 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, }; var layerPolygons = TestUtilities.GetAllLayersExtrusionPolygons(loadedGCode); Assert.AreEqual(45, layerPolygons.Where(i => i.Count > 2).Count()); for (int i = 1; i < layers; i++) { Assert.AreEqual(expectedIslands[i], layerPolygons[i].Where(p => p.Count > 2).Count()); } } Test(false, false); Test(false, true); Test(true, false); Test(true, true); }
public void AllInsidesBeforeAnyOutsides() { string thinAttachStlFile = TestUtilities.GetStlPath("Thin Attach"); string thinAttachGCodeFile = TestUtilities.GetTempGCodePath("Thin Attach.gcode"); ConfigSettings config = new ConfigSettings(); config.NumberOfPerimeters = 2; config.InfillPercent = 0; config.NumberOfTopLayers = 0; config.FirstLayerExtrusionWidth = .4; config.NumberOfBottomLayers = 0; FffProcessor processor = new FffProcessor(config); processor.SetTargetFile(thinAttachGCodeFile); processor.LoadStlFile(thinAttachStlFile); // slice and save it processor.DoProcessing(); processor.Finalize(); string[] gcode = TestUtilities.LoadGCodeFile(thinAttachGCodeFile); // should look like this // ____________ ____________ // | _______ | | _______ | // | | | | | | | | // | | | |___| | | | // | | | ____ | | | // | |______| | | |______| | // |__________| |__________| MovementInfo movement = new MovementInfo(); { // check layer 1 string[] layer1Info = TestUtilities.GetGCodeForLayer(gcode, 1); Polygons layer1Polygons = TestUtilities.GetExtrusionPolygons(layer1Info, ref movement); // make sure there are 5 Assert.IsTrue(layer1Polygons.Count == 3); // make sure they are in the right order (two inner polygons print first) Assert.IsTrue(layer1Polygons[0].MinX() > layer1Polygons[1].MinX()); Assert.IsTrue(layer1Polygons[0].MinX() > layer1Polygons[2].MinX()); } { // check layer 2 string[] layer2Info = TestUtilities.GetGCodeForLayer(gcode, 2); Polygons layer2Polygons = TestUtilities.GetExtrusionPolygons(layer2Info, ref movement); // make sure there are 3 Assert.IsTrue(layer2Polygons.Count == 3); // make sure they are in the right order (two inner polygons print first) Assert.IsTrue(layer2Polygons[0].MinX() > layer2Polygons[1].MinX()); Assert.IsTrue(layer2Polygons[0].MinX() > layer2Polygons[2].MinX()); } }
public void ThinRingHasNoCrossingSegments() { string infillSTL = TestUtilities.GetStlPath("thin_ring"); string infillGCode = TestUtilities.GetTempGCodePath("thin_ring.gcode"); { // load a model that is correctly manifold var config = new ConfigSettings(); string settingsPath = TestContext.CurrentContext.ResolveProjectPath(4, "Tests", "TestData", "thin_ring_config.ini"); config.ReadSettings(settingsPath); config.SkirtDistanceFromObject = 7.5; var processor = new FffProcessor(config); processor.SetTargetFile(infillGCode); processor.LoadStlFile(infillSTL); // slice and save it processor.DoProcessing(); processor.Finalize(); string[] loadedGCode = TestUtilities.LoadGCodeFile(infillGCode); double LongestMove(Polygons polys) { double longest = 0; foreach (var poly in polys) { for (int j = 0; j < poly.Count - 1; j++) { var next = j + 1; var length = (poly[j] - poly[next]).Length(); longest = Math.Max(longest, length); } } return(longest); } var layers = loadedGCode.GetAllExtrusionPolygons(); for (int i = 0; i < 15; i++) { if (i == 0) { // on the first layer we are looking for a single move that is the right length from the skirt to the part var longest = LongestMove(layers[i]); Assert.AreEqual(config.SkirtDistance_um + config.ExtrusionWidth_um, longest, 50, "The skirt must be the correct distance from the outside of the part"); } else // check that there are no { var longest = LongestMove(layers[i]); Assert.Less(longest, 3000, $"Segment length was: {longest}, should be smaller."); } } } }
public void OuterPerimeterFirstCorrect() { string box20MmStlFile = TestUtilities.GetStlPath("20mm-box"); string boxGCodeFile = TestUtilities.GetTempGCodePath("20mm-box-perimeter.gcode"); var config = new ConfigSettings(); config.NumberOfPerimeters = 3; config.OutsidePerimetersFirst = true; config.InfillPercent = 0; config.NumberOfTopLayers = 0; config.NumberOfBottomLayers = 0; var processor = new FffProcessor(config); processor.SetTargetFile(boxGCodeFile); processor.LoadStlFile(box20MmStlFile); // slice and save it processor.DoProcessing(); processor.Dispose(); string[] gcode = TestUtilities.LoadGCodeFile(boxGCodeFile); var outerPerimeterIndex = 1; var secondPerimeterIndex = 2; var thirdPerimeterIndex = 0; var movement = default(MovementInfo); { // check layer 1 var layer1Info = TestUtilities.GetLayer(gcode, 1); var layerPolygons = TestUtilities.GetExtrusionPolygonsForLayer(layer1Info, ref movement); // make sure there are 3 Assert.IsTrue(layerPolygons.Count == 3); // perimeters should be in 3 1 2 order so that we have priming happening before the outer perimeter Assert.IsTrue(layerPolygons[outerPerimeterIndex].MinX() < layerPolygons[secondPerimeterIndex].MinX()); Assert.IsTrue(layerPolygons[outerPerimeterIndex].MinX() < layerPolygons[thirdPerimeterIndex].MinX()); Assert.IsTrue(layerPolygons[secondPerimeterIndex].MinX() < layerPolygons[thirdPerimeterIndex].MinX()); } { // check layer 2 var layer2Info = TestUtilities.GetLayer(gcode, 2); var layerPolygons = TestUtilities.GetExtrusionPolygonsForLayer(layer2Info, ref movement); // make sure there are 3 Assert.IsTrue(layerPolygons.Count == 3); // make sure they are in the right order (other layers are inside out) Assert.IsTrue(layerPolygons[outerPerimeterIndex].MinX() < layerPolygons[secondPerimeterIndex].MinX()); Assert.IsTrue(layerPolygons[outerPerimeterIndex].MinX() < layerPolygons[thirdPerimeterIndex].MinX()); Assert.IsTrue(layerPolygons[secondPerimeterIndex].MinX() < layerPolygons[thirdPerimeterIndex].MinX()); } }
public void ThinRingHasNoCrossingSegments2() { string infillSTL = TestUtilities.GetStlPath("thin_gap_fill_ring"); string infillGCode = TestUtilities.GetTempGCodePath("thin_gap_fill_ring.gcode"); { // load a model that is correctly manifold var config = new ConfigSettings(); string settingsPath = TestContext.CurrentContext.ResolveProjectPath(4, "Tests", "TestData", "thin_gap_fill.ini"); config.ReadSettings(settingsPath); config.SkirtDistanceFromObject = 7.5; var processor = new FffProcessor(config); processor.SetTargetFile(infillGCode); processor.LoadStlFile(infillSTL); // slice and save it processor.DoProcessing(); processor.Finalize(); string[] loadedGCode = TestUtilities.LoadGCodeFile(infillGCode); double LongestMove(Polygons polys) { double longest = 0; var last = polys[0][0]; foreach (var poly in polys) { for (int j = 0; j < poly.Count; j++) { var length = (poly[j] - last).Length(); if (length > 3000) { int a = 0; } longest = Math.Max(longest, length); last = poly[j]; } } return(longest); } var layers = loadedGCode.GetAllExtrusionPolygons(); // start at 6 to skip the bottom layers (only care about the ring) for (int i = 6; i < layers.Count - 1; i++) { var longest = LongestMove(layers[i]); Assert.Less(longest, 3000, $"Segment length was: {longest}, should be smaller."); } } }
private static void CheckLayersIncrement(string stlFile, string gcodeFile) { string risingLayersStlFile = TestUtilities.GetStlPath(stlFile); string risingLayersGCodeFileName = TestUtilities.GetTempGCodePath(gcodeFile); ConfigSettings config = new ConfigSettings(); config.FirstLayerThickness = .2; config.LayerThickness = .2; FffProcessor processor = new FffProcessor(config); processor.SetTargetFile(risingLayersGCodeFileName); processor.LoadStlFile(risingLayersStlFile); // slice and save it processor.DoProcessing(); processor.Finalize(); string[] risingLayersGCodeContent = TestUtilities.LoadGCodeFile(risingLayersGCodeFileName); // test .1 layer height int layerCount = TestUtilities.CountLayers(risingLayersGCodeContent); Assert.IsTrue(layerCount == 50); MovementInfo startingPosition = new MovementInfo(); for (int layerIndex = 0; layerIndex < layerCount; layerIndex++) { string[] layerInfo = TestUtilities.GetGCodeForLayer(risingLayersGCodeContent, layerIndex); int movementIndex = 0; // check that all layers move up foreach (MovementInfo movement in TestUtilities.Movements(layerInfo, startingPosition)) { if (movement.line.Contains("X") || movement.line.Contains("Y") || movement.line.Contains("Z")) { if (layerIndex > 0) { Assert.AreEqual(movement.position.z, .2 + layerIndex * .2, .001); Assert.IsTrue(movement.position.z >= startingPosition.position.z); } } // always go up startingPosition.position = new Vector3(0, 0, Math.Max(startingPosition.position.z, movement.position.z)); movementIndex++; } } }
private string CreateGcodeWithoutRaft(bool hasRaft) { string box20MmStlFile = TestUtilities.GetStlPath("20mm-box"); string boxGCodeFile = TestUtilities.GetTempGCodePath("20mm-box-f{0}.gcode".FormatWith(hasRaft)); ConfigSettings config = new ConfigSettings(); config.EnableRaft = hasRaft; FffProcessor processor = new FffProcessor(config); processor.SetTargetFile(boxGCodeFile); processor.LoadStlFile(box20MmStlFile); // slice and save it processor.DoProcessing(); processor.Finalize(); return(boxGCodeFile); }
public void InnerPerimeterFirstCorrect() { // By default we need to do the inner perimeters first string box20MmStlFile = TestUtilities.GetStlPath("20mm-box"); string boxGCodeFile = TestUtilities.GetTempGCodePath("20mm-box-perimeter.gcode"); ConfigSettings config = new ConfigSettings(); config.NumberOfPerimeters = 3; config.InfillPercent = 0; config.NumberOfTopLayers = 0; config.NumberOfBottomLayers = 0; FffProcessor processor = new FffProcessor(config); processor.SetTargetFile(boxGCodeFile); processor.LoadStlFile(box20MmStlFile); // slice and save it processor.DoProcessing(); processor.Finalize(); string[] gcode = TestUtilities.LoadGCodeFile(boxGCodeFile); MovementInfo movement = new MovementInfo(); { // check layer 1 string[] layer1Info = TestUtilities.GetGCodeForLayer(gcode, 1); Polygons layer1Polygons = TestUtilities.GetExtrusionPolygons(layer1Info, ref movement); // make sure there are 3 Assert.IsTrue(layer1Polygons.Count == 3); // make sure they are in the right order (first layer is outside in) Assert.IsTrue(layer1Polygons[0].MinX() > layer1Polygons[1].MinX()); } { // check layer 2 string[] layer2Info = TestUtilities.GetGCodeForLayer(gcode, 2); Polygons layer2Polygons = TestUtilities.GetExtrusionPolygons(layer2Info, ref movement); // make sure there are 3 Assert.IsTrue(layer2Polygons.Count == 3); // make sure they are in the right order (other layers are inside out) Assert.IsTrue(layer2Polygons[0].MinX() > layer2Polygons[1].MinX()); } }
private string CreateGCodeForLayerHeights(double firstLayerHeight, double otherLayerHeight) { string box20MmStlFile = TestUtilities.GetStlPath("20mm-box"); string boxGCodeFile = TestUtilities.GetTempGCodePath("20mm-box-f{0}_o{1}.gcode".FormatWith(firstLayerHeight, otherLayerHeight)); ConfigSettings config = new ConfigSettings(); config.FirstLayerThickness = firstLayerHeight; config.LayerThickness = otherLayerHeight; FffProcessor processor = new FffProcessor(config); processor.SetTargetFile(boxGCodeFile); processor.LoadStlFile(box20MmStlFile); // slice and save it processor.DoProcessing(); processor.Finalize(); return(boxGCodeFile); }
public static string[] SliceAndGetGCode(string stlName, Action <ConfigSettings> action = null) { string thinWallsSTL = TestUtilities.GetStlPath($"{stlName}.stl"); string thinWallsGCode = TestUtilities.GetTempGCodePath($"{stlName}.gcode"); var config = new ConfigSettings(); action?.Invoke(config); var processor = new FffProcessor(config); processor.SetTargetFile(thinWallsGCode); processor.LoadStlFile(thinWallsSTL); // slice and save it processor.DoProcessing(); processor.Dispose(); return(TestUtilities.LoadGCodeFile(thinWallsGCode)); }
public void DualMaterialNoRetraction(int material) { GCodeExport.CheckForZeroPositions = false; string shortCubeName = "CubePoint2High"; string shortCube = TestUtilities.GetStlPath(shortCubeName); string outputGCodeFileName = TestUtilities.GetTempGCodePath($"CubeNoRetractions{material}"); var config = new ConfigSettings(); config.ExtruderCount = 2; config.FirstLayerThickness = .2; config.LayerThickness = .2; var processor = new FffProcessor(config); processor.SetTargetFile(outputGCodeFileName); for (int i = 0; i < material; i++) { string skipExtruder = TestUtilities.GetStlPath("TooSmallToPrint"); processor.LoadStlFile(skipExtruder); } processor.LoadStlFile(shortCube); // slice and save it processor.DoProcessing(); processor.Dispose(); string[] gCodeContent = TestUtilities.LoadGCodeFile(outputGCodeFileName); // test layer count int layerCount = TestUtilities.LayerCount(gCodeContent); Assert.AreEqual(1, layerCount); int retractions = TestUtilities.CountRetractions(gCodeContent); Assert.AreEqual(1, retractions, $"Material {material} should have no retractions"); }
protected void RunGCodeTest(string testName, string testFileName, Action <ConfigSettings> action = null) { if (!buildControlFiles && testName == "baseline") { return; } if (!buildControlFiles && baseLineText == null) { baseLineText = File.ReadAllText(TestUtilities.GetControlGCodePath("baseline")); } string controlPath = TestUtilities.GetControlGCodePath(testName); string outputPath = (buildControlFiles) ? controlPath : TestUtilities.GetTempGCodePath(testName); var configSettings = new ConfigSettings(); action?.Invoke(configSettings); if (testFileName == null) { testFileName = "primitives.stl"; } ProcessGCode(configSettings, TestUtilities.GetStlPath(testFileName), outputPath); if (!buildControlFiles) { string testResults = File.ReadAllText(outputPath); Assert.AreNotEqual(controlPath, outputPath, "Control and test paths must differ"); Assert.AreNotEqual(testResults, baseLineText, "Test does not vary from baseline: " + testName); Assert.AreEqual( File.ReadAllText(controlPath), testResults, "Test varies from expected control output: " + testName); } }
public void SupportConnectedOptimaly() { string thinWallsSTL = TestUtilities.GetStlPath("two disks"); string thinWallsGCode = TestUtilities.GetTempGCodePath("two disks.gcode"); { // load a model that is correctly manifold var config = new ConfigSettings(); config.GenerateSupport = true; var processor = new FffProcessor(config); processor.SetTargetFile(thinWallsGCode); processor.LoadStlFile(thinWallsSTL); // slice and save it processor.DoProcessing(); processor.Finalize(); string[] loadedGCode = TestUtilities.LoadGCodeFile(thinWallsGCode); int layerCount = TestUtilities.LayerCount(loadedGCode); for (int i = 0; i < layerCount; i++) { var movements = loadedGCode.GetGCodeForLayer(i).Movements().ToList(); int longMoveCount = 0; for (var j = 1; j < movements.Count - 2; j++) { var start = movements[j - 1]; var end = movements[j]; if (end.extrusion - start.extrusion == 0 && (end.position - start.position).Length > 5) { longMoveCount++; } } Assert.LessOrEqual(longMoveCount, 6); } } }
public void SupportTowerHasCorrectRetractions() { string infillSTLA = TestUtilities.GetStlPath("dice_body"); string infillSTLB = TestUtilities.GetStlPath("dice_numbers"); string infillGCode = TestUtilities.GetTempGCodePath("dice_dual.gcode"); { // load a model that is correctly manifold var config = new ConfigSettings(); string settingsPath = TestContext.CurrentContext.ResolveProjectPath(4, "Tests", "TestData", "thin_ring_config.ini"); config.ReadSettings(settingsPath); var processor = new FffProcessor(config); processor.SetTargetFile(infillGCode); processor.LoadStlFile(infillSTLA); processor.LoadStlFile(infillSTLB); // slice and save it processor.DoProcessing(); processor.Finalize(); string[] loadedGCode = TestUtilities.LoadGCodeFile(infillGCode); Assert.IsTrue(loadedGCode.Contains("T1 ; switch extruder")); Assert.IsTrue(loadedGCode.Contains("T0 ; switch extruder")); var layers = loadedGCode.GetAllExtrusionPolygons(); for (int i = 0; i < layers.Count; i++) { var polys = layers[i]; foreach (var poly in polys) { for (int j = 0; j < poly.Count - 1; j++) { int a = 0; } } } } }
public void CorrectIslandCount() { string engineStlFile = TestUtilities.GetStlPath("Engine-Benchmark"); string engineGCodeFile = TestUtilities.GetTempGCodePath("Engine-Benchmark.gcode"); var config = new ConfigSettings(); config.FirstLayerThickness = .2; config.LayerThickness = .2; config.NumberOfSkirtLoops = 0; config.InfillPercent = 0; config.NumberOfTopLayers = 0; config.NumberOfBottomLayers = 0; config.NumberOfPerimeters = 1; config.MergeOverlappingLines = false; var processor = new FffProcessor(config); processor.SetTargetFile(engineGCodeFile); processor.LoadStlFile(engineStlFile); // slice and save it processor.DoProcessing(); processor.Dispose(); var loadedGCode = TestUtilities.LoadGCodeFile(engineGCodeFile); var layers = TestUtilities.LayerCount(loadedGCode); Assert.AreEqual(195, layers); var layerPolygons = TestUtilities.GetAllLayersExtrusionPolygons(loadedGCode); Assert.AreEqual(17, layerPolygons[32].Count); for (int i = 33; i < 44; i++) { Assert.AreEqual(13, layerPolygons[i].Where(p => p.Count > 2).Count()); } }
private static void CheckSpiralCylinder(string stlFile, string gcodeFile, int expectedLayers, bool enableThinWalls = false) { string cylinderStlFile = TestUtilities.GetStlPath(stlFile); string cylinderGCodeFileName = TestUtilities.GetTempGCodePath(gcodeFile); ConfigSettings config = new ConfigSettings(); config.FirstLayerThickness = .2; config.LayerThickness = .2; if (enableThinWalls) { config.ExpandThinWalls = true; config.FillThinGaps = true; } config.NumberOfBottomLayers = 0; config.ContinuousSpiralOuterPerimeter = true; FffProcessor processor = new FffProcessor(config); processor.SetTargetFile(cylinderGCodeFileName); processor.LoadStlFile(cylinderStlFile); // slice and save it processor.DoProcessing(); processor.Finalize(); string[] cylinderGCodeContent = TestUtilities.LoadGCodeFile(cylinderGCodeFileName); // test .1 layer height int layerCount = TestUtilities.CountLayers(cylinderGCodeContent); Assert.IsTrue(layerCount == expectedLayers); for (int i = 2; i < layerCount - 3; i++) { string[] layerInfo = TestUtilities.GetGCodeForLayer(cylinderGCodeContent, i); // check that all layers move up continuously MovementInfo lastMovement = new MovementInfo(); foreach (MovementInfo movement in TestUtilities.Movements(layerInfo)) { Assert.IsTrue(movement.position.z > lastMovement.position.z); lastMovement = movement; } bool first = true; lastMovement = new MovementInfo(); // check that all moves are on the outside of the cylinder (not crossing to a new point) foreach (MovementInfo movement in TestUtilities.Movements(layerInfo)) { if (!first) { Assert.IsTrue((movement.position - lastMovement.position).Length < 2); Vector3 xyOnly = new Vector3(movement.position.x, movement.position.y, 0); Assert.AreEqual(9.8, xyOnly.Length, .3); } lastMovement = movement; first = false; } } }
private static void CheckSpiralCone(string stlFile, string gcodeFile, bool enableThinWalls = false) { string cylinderStlFile = TestUtilities.GetStlPath(stlFile); string cylinderGCodeFileName = TestUtilities.GetTempGCodePath(gcodeFile); var config = new ConfigSettings { FirstLayerThickness = .2, LayerThickness = .2, NumberOfBottomLayers = 0, ContinuousSpiralOuterPerimeter = true }; if (enableThinWalls) { config.ExpandThinWalls = true; config.FillThinGaps = true; } var processor = new FffProcessor(config); processor.SetTargetFile(cylinderGCodeFileName); processor.LoadStlFile(cylinderStlFile); // slice and save it processor.DoProcessing(); processor.Finalize(); string[] cylinderGCodeContent = TestUtilities.LoadGCodeFile(cylinderGCodeFileName); // test .1 layer height int layerCount = TestUtilities.CountLayers(cylinderGCodeContent); Assert.AreEqual(50, layerCount, "SpiralCone should have 50 layers"); for (int i = 2; i < layerCount - 3; i++) { string[] layerInfo = TestUtilities.GetGCodeForLayer(cylinderGCodeContent, i); // check that all layers move up continuously MovementInfo lastMovement = new MovementInfo(); foreach (MovementInfo movement in TestUtilities.Movements(layerInfo)) { #if __ANDROID__ Assert.IsTrue(movement.position.z > lastMovement.position.z); #else Assert.Greater(movement.position.z, lastMovement.position.z, "Z position should increment per layer"); #endif lastMovement = movement; } double radiusForLayer = 5.0 + (20.0 - 5.0) / layerCount * i; bool first = true; lastMovement = new MovementInfo(); // check that all moves are on the outside of the cylinder (not crossing to a new point) foreach (MovementInfo movement in TestUtilities.Movements(layerInfo)) { if (!first) { Assert.IsTrue((movement.position - lastMovement.position).Length < 2); Vector3 xyOnly = new Vector3(movement.position.x, movement.position.y, 0); Assert.AreEqual(radiusForLayer, xyOnly.Length, .3); } lastMovement = movement; first = false; } } }
public void DualMaterialPrintMovesCorrectly(bool createWipeTower) { string leftPart = "Box Left"; string rightPart = "Box Right"; string leftStlFile = TestUtilities.GetStlPath(leftPart); string rightStlFile = TestUtilities.GetStlPath(rightPart); string outputGCodeFileName = TestUtilities.GetTempGCodePath("DualPartMoves"); ConfigSettings config = new ConfigSettings(); config.ExtruderCount = 2; config.FirstLayerThickness = .2; config.LayerThickness = .2; config.NumberOfBottomLayers = 0; if (createWipeTower) { config.WipeTowerSize = 10; } else { config.WipeTowerSize = 0; } var processor = new FffProcessor(config); processor.SetTargetFile(outputGCodeFileName); processor.LoadStlFile(leftStlFile); processor.LoadStlFile(rightStlFile); // slice and save it processor.DoProcessing(); processor.Finalize(); string[] gCodeContent = TestUtilities.LoadGCodeFile(outputGCodeFileName); // test .1 layer height int layerCount = TestUtilities.CountLayers(gCodeContent); Assert.IsTrue(layerCount == 50); bool hadMoveLessThan85 = false; MovementInfo lastMovement = new MovementInfo(); for (int i = 0; i < layerCount - 3; i++) { string[] layerInfo = TestUtilities.GetGCodeForLayer(gCodeContent, i); // check that all layers move up continuously foreach (MovementInfo movement in TestUtilities.Movements(layerInfo, lastMovement, onlyG1s: true)) { if (i > 2) { if (createWipeTower) { Assert.IsTrue(movement.position.x > 75 && movement.position.y > 10, "Moves don't go to 0"); if (movement.position.x < 85) { hadMoveLessThan85 = true; } } else { Assert.IsTrue(movement.position.x > 85 && movement.position.y > 10, "Moves don't go to 0"); } } lastMovement = movement; } } if (createWipeTower) { Assert.IsTrue(hadMoveLessThan85, "found a wipe tower"); } }
public void DoHas2WallRingsAllTheWayUp(string fileName, int expectedLayerCount, bool checkRadius = false) { string stlFile = TestUtilities.GetStlPath(fileName); string gCodeFile = TestUtilities.GetTempGCodePath(fileName + ".gcode"); ConfigSettings config = new ConfigSettings(); config.InfillPercent = 0; config.NumberOfPerimeters = 1; config.FirstLayerExtrusionWidth = .2; config.LayerThickness = .2; config.NumberOfBottomLayers = 0; config.NumberOfTopLayers = 0; FffProcessor processor = new FffProcessor(config); processor.SetTargetFile(gCodeFile); processor.LoadStlFile(stlFile); // slice and save it processor.DoProcessing(); processor.Finalize(); string[] gcodeLines = TestUtilities.LoadGCodeFile(gCodeFile); int layerCount = TestUtilities.CountLayers(gcodeLines); Assert.IsTrue(layerCount == expectedLayerCount); MovementInfo movement = new MovementInfo(); for (int i = 0; i < layerCount - 5; i++) { string[] layerInfo = TestUtilities.GetGCodeForLayer(gcodeLines, i); if (i > 0) { Polygons layerPolygons = TestUtilities.GetExtrusionPolygons(layerInfo, ref movement); Assert.IsTrue(layerPolygons.Count == 2); if (checkRadius) { Assert.IsTrue(layerPolygons[0].Count > 10); Assert.IsTrue(layerPolygons[1].Count > 10); if (false) { foreach (var polygon in layerPolygons) { double radiusForPolygon = polygon[0].LengthMm(); foreach (var point in polygon) { Assert.AreEqual(radiusForPolygon, point.LengthMm(), 15); } } } } } else { TestUtilities.GetExtrusionPolygons(layerInfo, ref movement); } } }