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 = TestUtlities.GetStlPath("comb"); string gCodeWithIslands = TestUtlities.GetTempGCodePath("comb-box"); { // load a model that has 3 islands ConfigSettings config = new ConfigSettings(); // make sure no retractions are going to occure 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 = TestUtlities.LoadGCodeFile(gCodeWithIslands); int numLayers = TestUtlities.CountLayers(gcodeContents); for (int i = 1; i < numLayers - 1; i++) { string[] layer = TestUtlities.GetGCodeForLayer(gcodeContents, i); int totalRetractions = TestUtlities.CountRetractions(layer); Assert.IsTrue(totalRetractions == 6); } } }
private static void CheckSpiralCone(string stlFile, string gcodeFile) { string cylinderStlFile = TestUtlities.GetStlPath(stlFile); string cylinderGCodeFileName = TestUtlities.GetTempGCodePath(gcodeFile); ConfigSettings config = new ConfigSettings(); config.FirstLayerThickness = .2; config.CenterObjectInXy = false; config.LayerThickness = .2; 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 = TestUtlities.LoadGCodeFile(cylinderGCodeFileName); // test .1 layer height int layerCount = TestUtlities.CountLayers(cylinderGCodeContent); Assert.IsTrue(layerCount == 50); for (int i = 2; i < layerCount - 3; i++) { string[] layerInfo = TestUtlities.GetGCodeForLayer(cylinderGCodeContent, i); // check that all layers move up continuously MovementInfo lastMovement = new MovementInfo(); foreach (MovementInfo movement in TestUtlities.Movements(layerInfo)) { Assert.IsTrue(movement.position.z > lastMovement.position.z); 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 TestUtlities.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 WindingDirectionDoesNotMatter() { string manifoldFile = TestUtlities.GetStlPath("20mm-box"); string manifoldGCode = TestUtlities.GetTempGCodePath("20mm-box"); string nonManifoldFile = TestUtlities.GetStlPath("20mm-box bad winding"); string nonManifoldGCode = TestUtlities.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 wroing 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); }
private void ProcessGCode(ConfigSettings config, string stlPath, string outputPath) { var processor = new fffProcessor(config); processor.SetTargetFile(outputPath); processor.LoadStlFile(stlPath); processor.DoProcessing(); processor.finalize(); }
public void AllMovesRequiringRetractionDoRetraction() { string baseFileName = "ab retraction test"; string stlToLoad = TestUtlities.GetStlPath(baseFileName + ".stl"); // check that default is support printed with extruder 0 { string gcodeToCreate = TestUtlities.GetTempGCodePath(baseFileName + "_retract_" + ".gcode"); ConfigSettings config = new ConfigSettings(); config.RetractionZHop = 5; config.MinimumTravelToCauseRetraction = 2; config.MinimumExtrusionBeforeRetraction = 0; config.FirstLayerExtrusionWidth = .5; fffProcessor processor = new fffProcessor(config); processor.SetTargetFile(gcodeToCreate); processor.LoadStlFile(stlToLoad); // slice and save it processor.DoProcessing(); processor.finalize(); string[] gcodeContents = TestUtlities.LoadGCodeFile(gcodeToCreate); int layerCount = TestUtlities.CountLayers(gcodeContents); bool firstPosition = true; for(int i=0; i<layerCount; i++) { string[] layerGCode = TestUtlities.GetGCodeForLayer(gcodeContents, i); MovementInfo lastMovement = new MovementInfo(); foreach (MovementInfo movement in TestUtlities.Movements(layerGCode)) { if (!firstPosition) { bool isTravel = lastMovement.extrusion == movement.extrusion; if (isTravel) { Vector3 lastPosition = lastMovement.position; lastPosition.z = 0; Vector3 currenPosition = movement.position; currenPosition.z = 0; double xyLength = (lastPosition - currenPosition).Length; if (xyLength > config.MinimumTravelToCauseRetraction) { Assert.IsTrue(movement.position.z > lastMovement.position.z); } } } lastMovement = movement; firstPosition = false; } } Assert.IsFalse(TestUtlities.UsesExtruder(gcodeContents, 1)); Assert.IsFalse(TestUtlities.UsesExtruder(gcodeContents, 2)); } }
public void AllMovesRequiringRetractionDoRetraction() { string baseFileName = "ab retraction test"; string stlToLoad = TestUtlities.GetStlPath(baseFileName + ".stl"); // check that default is support printed with extruder 0 { string gcodeToCreate = TestUtlities.GetTempGCodePath(baseFileName + "_retract_" + ".gcode"); ConfigSettings config = new ConfigSettings(); config.RetractionZHop = 5; config.MinimumTravelToCauseRetraction = 2; config.MinimumExtrusionBeforeRetraction = 0; config.FirstLayerExtrusionWidth = .5; fffProcessor processor = new fffProcessor(config); processor.SetTargetFile(gcodeToCreate); processor.LoadStlFile(stlToLoad); // slice and save it processor.DoProcessing(); processor.finalize(); string[] gcodeContents = TestUtlities.LoadGCodeFile(gcodeToCreate); int layerCount = TestUtlities.CountLayers(gcodeContents); bool firstPosition = true; for (int i = 0; i < layerCount; i++) { string[] layerGCode = TestUtlities.GetGCodeForLayer(gcodeContents, i); MovementInfo lastMovement = new MovementInfo(); foreach (MovementInfo movement in TestUtlities.Movements(layerGCode)) { if (!firstPosition) { bool isTravel = lastMovement.extrusion == movement.extrusion; if (isTravel) { Vector3 lastPosition = lastMovement.position; lastPosition.z = 0; Vector3 currenPosition = movement.position; currenPosition.z = 0; double xyLength = (lastPosition - currenPosition).Length; if (xyLength > config.MinimumTravelToCauseRetraction) { Assert.IsTrue(movement.position.z > lastMovement.position.z); } } } lastMovement = movement; firstPosition = false; } } Assert.IsFalse(TestUtlities.UsesExtruder(gcodeContents, 1)); Assert.IsFalse(TestUtlities.UsesExtruder(gcodeContents, 2)); } }
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()); } }
private static void CheckLayersIncrement(string stlFile, string gcodeFile) { string risingLayersStlFile = TestUtlities.GetStlPath(stlFile); string risingLayersGCodeFileName = TestUtlities.GetTempGCodePath(gcodeFile); ConfigSettings config = new ConfigSettings(); config.FirstLayerThickness = .2; config.CenterObjectInXy = false; config.LayerThickness = .2; fffProcessor processor = new fffProcessor(config); processor.SetTargetFile(risingLayersGCodeFileName); processor.LoadStlFile(risingLayersStlFile); // slice and save it processor.DoProcessing(); processor.finalize(); string[] risingLayersGCodeContent = TestUtlities.LoadGCodeFile(risingLayersGCodeFileName); // test .1 layer height int layerCount = TestUtlities.CountLayers(risingLayersGCodeContent); Assert.IsTrue(layerCount == 50); MovementInfo startingPosition = new MovementInfo(); for (int layerIndex = 0; layerIndex < layerCount; layerIndex++) { string[] layerInfo = TestUtlities.GetGCodeForLayer(risingLayersGCodeContent, layerIndex); int movementIndex = 0; // check that all layers move up foreach (MovementInfo movement in TestUtlities.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 = TestUtlities.GetStlPath("20mm-box"); string boxGCodeFile = TestUtlities.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; }
private string CreateGCodeForLayerHeights(double firstLayerHeight, double otherLayerHeight, double bottomClip = 0) { string box20MmStlFile = TestUtlities.GetStlPath("20mm-box"); string boxGCodeFile = TestUtlities.GetTempGCodePath("20mm-box-f{0}_o{1}_c{2}.gcode".FormatWith(firstLayerHeight, otherLayerHeight, bottomClip)); ConfigSettings config = new ConfigSettings(); config.firstLayerThickness = firstLayerHeight; config.layerThickness = otherLayerHeight; config.bottomClipAmount = bottomClip; fffProcessor processor = new fffProcessor(config); processor.SetTargetFile(boxGCodeFile); processor.LoadStlFile(box20MmStlFile); // slice and save it processor.DoProcessing(); processor.finalize(); return boxGCodeFile; }
private string CreateGcodeWithoutRaft(bool hasRaft) { string box20MmStlFile = TestUtlities.GetStlPath("20mm-box"); string boxGCodeFile = TestUtlities.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); }
private void GenerateFile() { ConfigSettings config = new ConfigSettings(); fffProcessor processor = new fffProcessor(config); processor.SetTargetFile(@"I:\5mm.txt"); processor.LoadStlFile(@"I:\5mm.stl"); processor.DoProcessing(); processor.finalize(); processor.Cancel(); using (System.IO.StreamReader sr = new System.IO.StreamReader(@"I:\5mm.txt")) { string str; while ((str = sr.ReadLine()) != null) { //在线程中更新UI(通过UI线程同步上下文m_SyncContext) m_SyncContext.Post(SetTextSafePost, str); } } }
public void OuterPerimeterFirstCorrect() { string box20MmStlFile = TestUtlities.GetStlPath("20mm-box"); string boxGCodeFile = TestUtlities.GetTempGCodePath("20mm-box-perimeter.gcode"); ConfigSettings config = new ConfigSettings(); config.NumberOfPerimeters = 3; config.InfillPercent = 0; fffProcessor processor = new fffProcessor(config); processor.SetTargetFile(boxGCodeFile); processor.LoadStlFile(box20MmStlFile); // slice and save it processor.DoProcessing(); processor.finalize(); string[] gcode = TestUtlities.LoadGCodeFile(boxGCodeFile); { // check layer 0 string[] layer0Info = TestUtlities.GetGCodeForLayer(gcode, 0); List <Polygons> layer0Polygons = TestUtlities.GetExtrusionPolygons(layer0Info); // make sure there are 3 Assert.IsTrue(layer0Polygons.Count == 3); // make sure they are in the right order (first layer is outside in) } { // check layer 1 string[] layer1Info = TestUtlities.GetGCodeForLayer(gcode, 1); List <Polygons> layer1Polygons = TestUtlities.GetExtrusionPolygons(layer1Info); // make sure there are 3 Assert.IsTrue(layer1Polygons.Count == 3); // make sure they are in the right order (other layers are inside out) } }
public void CanSetExtruderForSupportMaterial() { string baseFileName = "Support Material 2 Bars"; string stlToLoad = TestUtilities.GetStlPath(baseFileName + ".stl"); string supportToLoad = TestUtilities.GetStlPath("2BarsSupport.stl"); // check that default is support printed with extruder 0 { string gcodeToCreate = TestUtilities.GetTempGCodePath(baseFileName + "_0_.gcode"); ConfigSettings config = new ConfigSettings(); fffProcessor processor = new fffProcessor(config); processor.SetTargetFile(gcodeToCreate); processor.LoadStlFile(stlToLoad); // slice and save it processor.DoProcessing(); processor.finalize(); string[] gcodeContents = TestUtilities.LoadGCodeFile(gcodeToCreate); Assert.IsFalse(TestUtilities.UsesExtruder(gcodeContents, 1)); Assert.IsFalse(TestUtilities.UsesExtruder(gcodeContents, 2)); } // check that support is printed with extruder 0 { string gcodeToCreate = TestUtilities.GetTempGCodePath(baseFileName + "_1b_.gcode"); ConfigSettings config = new ConfigSettings(); config.ExtruderCount = 1; config.SupportExtruder = 1; // from a 0 based index // this is a hack, but it is the signaling mechanism for support config.BooleanOperations = "S"; fffProcessor processor = new fffProcessor(config); processor.SetTargetFile(gcodeToCreate); processor.LoadStlFile(stlToLoad); processor.LoadStlFile(supportToLoad); // slice and save it processor.DoProcessing(); processor.finalize(); string[] gcodeContents = TestUtilities.LoadGCodeFile(gcodeToCreate); Assert.IsFalse(TestUtilities.UsesExtruder(gcodeContents, 1)); Assert.IsFalse(TestUtilities.UsesExtruder(gcodeContents, 2)); } // check that support is printed with extruder 1 { string gcodeToCreate = TestUtilities.GetTempGCodePath(baseFileName + "_1b_.gcode"); ConfigSettings config = new ConfigSettings(); config.SupportExtruder = 1; config.ExtruderCount = 2; // this is a hack, but it is the signaling mechanism for support config.BooleanOperations = "S"; fffProcessor processor = new fffProcessor(config); processor.SetTargetFile(gcodeToCreate); processor.LoadStlFile(stlToLoad); // we have to have a mesh for every extruder processor.LoadStlFile(stlToLoad); processor.LoadStlFile(supportToLoad); // slice and save it processor.DoProcessing(); processor.finalize(); string[] gcodeContents = TestUtilities.LoadGCodeFile(gcodeToCreate); Assert.IsTrue(TestUtilities.UsesExtruder(gcodeContents, 1)); Assert.IsFalse(TestUtilities.UsesExtruder(gcodeContents, 2)); } // check that support interface is printed with extruder 0 { string gcodeToCreate = TestUtilities.GetTempGCodePath(baseFileName + "_1i_.gcode"); ConfigSettings config = new ConfigSettings(); config.ExtruderCount = 1; config.SupportInterfaceExtruder = 1; // this is a hack, but it is the signaling mechanism for support config.BooleanOperations = "S"; fffProcessor processor = new fffProcessor(config); processor.SetTargetFile(gcodeToCreate); processor.LoadStlFile(stlToLoad); processor.LoadStlFile(supportToLoad); // slice and save it processor.DoProcessing(); processor.finalize(); string[] gcodeContents = TestUtilities.LoadGCodeFile(gcodeToCreate); Assert.IsFalse(TestUtilities.UsesExtruder(gcodeContents, 1)); Assert.IsFalse(TestUtilities.UsesExtruder(gcodeContents, 2)); } // check that support interface is printed with extruder 1 { string gcodeToCreate = TestUtilities.GetTempGCodePath(baseFileName + "_1i_.gcode"); ConfigSettings config = new ConfigSettings(); config.ExtruderCount = 2; config.SupportInterfaceExtruder = 1; // this is a hack, but it is the signaling mechanism for support config.BooleanOperations = "S"; fffProcessor processor = new fffProcessor(config); processor.SetTargetFile(gcodeToCreate); processor.LoadStlFile(stlToLoad); // we have to have a mesh for every extruder processor.LoadStlFile(stlToLoad); processor.LoadStlFile(supportToLoad); // slice and save it processor.DoProcessing(); processor.finalize(); string[] gcodeContents = TestUtilities.LoadGCodeFile(gcodeToCreate); Assert.IsTrue(TestUtilities.UsesExtruder(gcodeContents, 0)); Assert.IsTrue(TestUtilities.UsesExtruder(gcodeContents, 1)); Assert.IsFalse(TestUtilities.UsesExtruder(gcodeContents, 2)); } // check that support and interface can be set separately { string gcodeToCreate = TestUtilities.GetTempGCodePath(baseFileName + "_1b2i_.gcode"); ConfigSettings config = new ConfigSettings(); config.ExtruderCount = 1; config.SupportExtruder = 1; config.SupportInterfaceExtruder = 2; // this is a hack, but it is the signaling mechanism for support config.BooleanOperations = "S"; fffProcessor processor = new fffProcessor(config); processor.SetTargetFile(gcodeToCreate); processor.LoadStlFile(stlToLoad); processor.LoadStlFile(supportToLoad); // slice and save it processor.DoProcessing(); processor.finalize(); string[] gcodeContents = TestUtilities.LoadGCodeFile(gcodeToCreate); Assert.IsFalse(TestUtilities.UsesExtruder(gcodeContents, 1)); Assert.IsFalse(TestUtilities.UsesExtruder(gcodeContents, 2)); } // check that support and interface can be set separately { string gcodeToCreate = TestUtilities.GetTempGCodePath(baseFileName + "_1b2i_.gcode"); ConfigSettings config = new ConfigSettings(); config.ExtruderCount = 2; config.SupportExtruder = 1; config.SupportInterfaceExtruder = 2; // this is a hack, but it is the signaling mechanism for support config.BooleanOperations = "S"; fffProcessor processor = new fffProcessor(config); processor.SetTargetFile(gcodeToCreate); processor.LoadStlFile(stlToLoad); // we have to have a mesh for every extruder processor.LoadStlFile(stlToLoad); processor.LoadStlFile(supportToLoad); // slice and save it processor.DoProcessing(); processor.finalize(); string[] gcodeContents = TestUtilities.LoadGCodeFile(gcodeToCreate); Assert.IsTrue(TestUtilities.UsesExtruder(gcodeContents, 1)); Assert.IsFalse(TestUtilities.UsesExtruder(gcodeContents, 2)); } // check that support and interface can be set separately { string gcodeToCreate = TestUtilities.GetTempGCodePath(baseFileName + "_1b2i_.gcode"); ConfigSettings config = new ConfigSettings(); config.ExtruderCount = 3; config.SupportExtruder = 1; config.SupportInterfaceExtruder = 2; // this is a hack, but it is the signaling mechanism for support config.BooleanOperations = "S"; fffProcessor processor = new fffProcessor(config); processor.SetTargetFile(gcodeToCreate); processor.LoadStlFile(stlToLoad); // we have to have a mesh for every extruder processor.LoadStlFile(stlToLoad); processor.LoadStlFile(stlToLoad); processor.LoadStlFile(supportToLoad); // slice and save it processor.DoProcessing(); processor.finalize(); string[] gcodeContents = TestUtilities.LoadGCodeFile(gcodeToCreate); Assert.IsTrue(TestUtilities.UsesExtruder(gcodeContents, 1)); Assert.IsTrue(TestUtilities.UsesExtruder(gcodeContents, 2)); } }
public void CanSetExtruderForSupportMaterial() { string baseFileName = "Support Material 2 Bars"; string stlToLoad = TestUtlities.GetStlPath(baseFileName + ".stl"); // check that default is support printed with extruder 0 { string gcodeToCreate = TestUtlities.GetTempGCodePath(baseFileName + "_0_" + ".gcode"); ConfigSettings config = new ConfigSettings(); fffProcessor processor = new fffProcessor(config); processor.SetTargetFile(gcodeToCreate); processor.LoadStlFile(stlToLoad); // slice and save it processor.DoProcessing(); processor.finalize(); string[] gcodeContents = TestUtlities.LoadGCodeFile(gcodeToCreate); Assert.IsFalse(TestUtlities.UsesExtruder(gcodeContents, 1)); Assert.IsFalse(TestUtlities.UsesExtruder(gcodeContents, 2)); } // check that support is printed with extruder 1 { string gcodeToCreate = TestUtlities.GetTempGCodePath(baseFileName + "_1b_" + ".gcode"); ConfigSettings config = new ConfigSettings(); config.SupportExtruder = 1; config.GenerateSupport = true; fffProcessor processor = new fffProcessor(config); processor.SetTargetFile(gcodeToCreate); processor.LoadStlFile(stlToLoad); // slice and save it processor.DoProcessing(); processor.finalize(); string[] gcodeContents = TestUtlities.LoadGCodeFile(gcodeToCreate); Assert.IsTrue(TestUtlities.UsesExtruder(gcodeContents, 1)); Assert.IsFalse(TestUtlities.UsesExtruder(gcodeContents, 2)); } // check that support interface is printed with extruder 1 { string gcodeToCreate = TestUtlities.GetTempGCodePath(baseFileName + "_1i_" + ".gcode"); ConfigSettings config = new ConfigSettings(); config.SupportInterfaceExtruder = 1; config.GenerateSupport = true; fffProcessor processor = new fffProcessor(config); processor.SetTargetFile(gcodeToCreate); processor.LoadStlFile(stlToLoad); // slice and save it processor.DoProcessing(); processor.finalize(); string[] gcodeContents = TestUtlities.LoadGCodeFile(gcodeToCreate); Assert.IsTrue(TestUtlities.UsesExtruder(gcodeContents, 1)); Assert.IsFalse(TestUtlities.UsesExtruder(gcodeContents, 2)); } // check that support and interface can be set separately { string gcodeToCreate = TestUtlities.GetTempGCodePath(baseFileName + "_1b2i_" + ".gcode"); ConfigSettings config = new ConfigSettings(); config.SupportExtruder = 1; config.SupportInterfaceExtruder = 2; config.GenerateSupport = true; fffProcessor processor = new fffProcessor(config); processor.SetTargetFile(gcodeToCreate); processor.LoadStlFile(stlToLoad); // slice and save it processor.DoProcessing(); processor.finalize(); string[] gcodeContents = TestUtlities.LoadGCodeFile(gcodeToCreate); Assert.IsTrue(TestUtlities.UsesExtruder(gcodeContents, 1)); Assert.IsTrue(TestUtlities.UsesExtruder(gcodeContents, 2)); } }
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 wroing 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 OuterPerimeterFirstCorrect() { string box20MmStlFile = TestUtlities.GetStlPath("20mm-box"); string boxGCodeFile = TestUtlities.GetTempGCodePath("20mm-box-perimeter.gcode"); ConfigSettings config = new ConfigSettings(); config.NumberOfPerimeters = 3; config.InfillPercent = 0; fffProcessor processor = new fffProcessor(config); processor.SetTargetFile(boxGCodeFile); processor.LoadStlFile(box20MmStlFile); // slice and save it processor.DoProcessing(); processor.finalize(); string[] gcode = TestUtlities.LoadGCodeFile(boxGCodeFile); { // check layer 0 string[] layer0Info = TestUtlities.GetGCodeForLayer(gcode, 0); List<Polygons> layer0Polygons = TestUtlities.GetExtrusionPolygons(layer0Info); // make sure there are 3 Assert.IsTrue(layer0Polygons.Count == 3); // make sure they are in the right order (first layer is outside in) } { // check layer 1 string[] layer1Info = TestUtlities.GetGCodeForLayer(gcode, 1); List<Polygons> layer1Polygons = TestUtlities.GetExtrusionPolygons(layer1Info); // make sure there are 3 Assert.IsTrue(layer1Polygons.Count == 3); // make sure they are in the right order (other layers are inside out) } }
private static void CheckCylinder(string stlFile, string gcodeFile) { string cylinderStlFile = TestUtlities.GetStlPath(stlFile); string cylinderGCodeFileName = TestUtlities.GetTempGCodePath(gcodeFile); ConfigSettings config = new ConfigSettings(); config.firstLayerThickness = .2; config.centerObjectInXy = false; config.layerThickness = .2; 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 = TestUtlities.LoadGCodeFile(cylinderGCodeFileName); // test .1 layer height int layerCount = TestUtlities.CountLayers(cylinderGCodeContent); Assert.IsTrue(layerCount == 100); for (int i = 2; i < layerCount - 3; i++) { string[] layerInfo = TestUtlities.GetGCodeForLayer(cylinderGCodeContent, i); // check that all layers move up continuously MovementInfo lastMovement = new MovementInfo(); foreach (MovementInfo movement in TestUtlities.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 TestUtlities.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; } } }
public void AllMovesRequiringRetractionDoRetraction(string baseFileName, string settingsIniFile = "") { string stlToLoad = TestUtilities.GetStlPath(baseFileName + ".stl"); // check that default is support printed with extruder 0 string gcodeToCreate = TestUtilities.GetTempGCodePath(baseFileName + "_retract_.gcode"); ConfigSettings config = new ConfigSettings(); if (settingsIniFile == "") { config.MinimumTravelToCauseRetraction = 2; config.MinimumExtrusionBeforeRetraction = 0; config.MergeOverlappingLines = false; config.FirstLayerExtrusionWidth = .5; } else { config.ReadSettings(settingsIniFile); } // this is what we detect config.RetractionZHop = 5; fffProcessor processor = new fffProcessor(config); processor.SetTargetFile(gcodeToCreate); processor.LoadStlFile(stlToLoad); // slice and save it processor.DoProcessing(); processor.finalize(); string[] gcodeContents = TestUtilities.LoadGCodeFile(gcodeToCreate); int layerCount = TestUtilities.CountLayers(gcodeContents); bool firstPosition = true; MovementInfo lastMovement = new MovementInfo(); MovementInfo lastExtrusion = new MovementInfo(); bool lastMoveIsExtrusion = true; for (int layerIndex = 0; layerIndex < layerCount; layerIndex++) { string[] layerGCode = TestUtilities.GetGCodeForLayer(gcodeContents, layerIndex); int movementIndex = 0; foreach (MovementInfo movement in TestUtilities.Movements(layerGCode, lastMovement)) { if (!firstPosition) { bool isTravel = lastMovement.extrusion == movement.extrusion; if (isTravel) { Vector3 lastPosition = lastMovement.position; lastPosition.z = 0; Vector3 currenPosition = movement.position; currenPosition.z = 0; double xyLength = (lastPosition - currenPosition).Length; if (xyLength > config.MinimumTravelToCauseRetraction && lastMoveIsExtrusion) { Assert.GreaterOrEqual(movement.position.z, lastExtrusion.position.z); } lastMoveIsExtrusion = false; } else { lastMoveIsExtrusion = true; lastExtrusion = movement; } lastMoveIsExtrusion = !isTravel; } lastMovement = movement; firstPosition = false; movementIndex++; } } // make sure we don't switch extruders Assert.IsFalse(TestUtilities.UsesExtruder(gcodeContents, 1)); Assert.IsFalse(TestUtilities.UsesExtruder(gcodeContents, 2)); }
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; } fffProcessor 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); } } }