예제 #1
0
        public void AllInsidesBeforeAnyOutsides()
        {
            string thinAttachStlFile   = TestUtilities.GetStlPath("Thin Attach");
            string thinAttachGCodeFile = TestUtilities.GetTempGCodePath("Thin Attach.gcode");

            var config = new ConfigSettings();

            config.NumberOfPerimeters       = 2;
            config.InfillPercent            = 0;
            config.NumberOfTopLayers        = 0;
            config.FirstLayerExtrusionWidth = .4;
            config.NumberOfBottomLayers     = 0;
            var 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
            // ____________   ____________
            // | _______  |	  | _______  |
            // | |      | |	  | |      | |
            // | |      | |___| |      | |
            // | |      | ____  |      | |
            // | |______| |   | |______| |
            // |__________|   |__________|
            var movement = default(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());
            }
        }
예제 #2
0
        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.");
                    }
                }
            }
        }
예제 #3
0
        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());
            }
        }
예제 #4
0
        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.");
                }
            }
        }
예제 #5
0
        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++;
                }
            }
        }
예제 #6
0
        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);
        }
예제 #7
0
        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());
            }
        }
예제 #8
0
        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);
        }
예제 #9
0
        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));
        }
예제 #10
0
        public static int ProcessArgs(string[] args)
        {
            if (args.Length == 0)
            {
                print_usage();
                return(0);
            }

            ConfigSettings config    = new ConfigSettings();
            FffProcessor   processor = new FffProcessor(config);

            LogOutput.Log("\nMatterSlice version {0}\n\n".FormatWith(ConfigConstants.VERSION));

            if (ProcessArgs(args, config, processor) == 0)
            {
                return(0);
            }

            if (!Canceled)
            {
                using (new QuickTimer2("DoProcessing"))
                {
                    processor.DoProcessing();
                }
            }

            if (!Canceled)
            {
                processor.Dispose();
            }

            if (Canceled)
            {
                processor.Cancel();
            }

            Canceled = true;

            return(0);
        }
예제 #11
0
        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");
        }
예제 #12
0
        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);
                }
            }
        }
예제 #13
0
        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;
                        }
                    }
                }
            }
        }
예제 #14
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());
            }
        }
예제 #15
0
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");


            ConfigSettings config    = new ConfigSettings();
            FffProcessor   processor = new FffProcessor(config);

            MemoryStream result = new MemoryStream();

            processor.SetTargetStream(result);

            var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().CodeBase).Replace("file:\\", "");

            path = $"{path}\\SampleSTLs\\AvoidCrossing9Holes.stl";
            var stream = new FileStream(path, FileMode.Open);

            using (new QuickTimer2("LoadStlFile"))
            {
                processor.LoadStlStream(stream);
            }

            using (new QuickTimer2("DoProcessing"))
            {
                processor.DoProcessing();
            }
            var data = processor.Finalize();


            //GenericGCodeParser parser = new GenericGCodeParser();


            //result.Position = 0;
            //TextReader tr = new StreamReader(result);
            //var gcode = parser.Parse(tr);
        }
예제 #16
0
        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;
                }
            }
        }
예제 #17
0
        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;
                }
            }
        }
예제 #18
0
        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");
            }
        }
예제 #19
0
        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);
                }
            }
        }
예제 #20
0
        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));
        }
예제 #21
0
        public void ExpandThinWallsFindsWalls()
        {
            string thinWallsSTL = TestUtilities.GetStlPath("ThinWalls");

            // without expand thin walls
            {
                string thinWallsGCode = TestUtilities.GetTempGCodePath("ThinWalls1.gcode");
                var    config         = new ConfigSettings
                {
                    FirstLayerThickness   = .2,
                    LayerThickness        = .2,
                    NumberOfSkirtLoops    = 0,
                    InfillPercent         = 0,
                    NumberOfTopLayers     = 0,
                    NumberOfBottomLayers  = 0,
                    NumberOfPerimeters    = 1,
                    ExpandThinWalls       = false,
                    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);
                Assert.AreEqual(50, layerCount);

                var layerPolygons = loadedGCode.GetAllExtrusionPolygons();

                Assert.AreEqual(6, layerPolygons[10].Where(i => i.Count > 2).Count());
            }

            // with expand thin walls
            {
                string thinWallsGCode = TestUtilities.GetTempGCodePath("ThinWalls2.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.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);
                Assert.AreEqual(50, layerCount);

                var layerPolygons = loadedGCode.GetAllExtrusionPolygons();

                Assert.AreEqual(10, layerPolygons[10].Count);
            }

            // with expand thin walls and with merge overlapping lines
            {
                string thinWallsGCode = TestUtilities.GetTempGCodePath("ThinWalls3.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.ExpandThinWalls       = true;
                config.MergeOverlappingLines = 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);
                Assert.AreEqual(50, layerCount);

                var layerPolygons = loadedGCode.GetAllExtrusionPolygons();

                Assert.AreEqual(10, layerPolygons[10].Count);
            }
        }
예제 #22
0
        public static int ProcessArgs(string[] args, ConfigSettings config, FffProcessor processor)
        {
            for (int argn = 0; argn < args.Length; argn++)
            {
                string str = args[argn];
                if (str[0] == '-')
                {
                    for (int stringIndex = 1; stringIndex < str.Length; stringIndex++)
                    {
                        switch (str[stringIndex])
                        {
                        case 'h':
                            print_usage();
                            return(0);

                        case 'v':
                            LogOutput.verbose_level++;
                            break;

                        case 'o':
                            argn++;
                            if (!processor.SetTargetFile(args[argn]))
                            {
                                LogOutput.LogError("Failed to open {0} for output.\n".FormatWith(args[argn]));
                                return(1);
                            }

                            break;

                        case 'c':
                        {
                            // Read a config file from the given path
                            argn++;
                            if (!config.ReadSettings(args[argn]))
                            {
                                LogOutput.LogError("Failed to read config '{0}'\n".FormatWith(args[argn]));
                            }

                            // process any matrix and mesh requested by config file
                            List <string> commands = new List <string>();
                            foreach (string command in SplitCommandLine.DoSplit(config.AdditionalArgsToProcess))
                            {
                                commands.Add(command);
                            }

                            string[] subArgs = commands.ToArray();
                            ProcessArgs(subArgs, config, processor);
                        }

                        break;

                        case 'd':
                            config.DumpSettings("settings.ini");
                            break;

                        case 's':
                        {
                            argn++;
                            int equalsPos = args[argn].IndexOf('=');
                            if (equalsPos != -1)
                            {
                                string key   = args[argn].Substring(0, equalsPos);
                                string value = args[argn].Substring(equalsPos + 1);
                                if (key.Length > 1)
                                {
                                    if (!config.SetSetting(key, value))
                                    {
                                        LogOutput.LogError("Setting not found: {0} {1}\n".FormatWith(key, value));
                                    }
                                }
                            }
                        }

                        break;

                        case 'm':
                            argn++;
                            string[] matrixValues = args[argn].Split(',');
                            var      loadedMatrix = Matrix4X4.Identity;
                            for (int i = 0; i < 4; i++)
                            {
                                for (int j = 0; j < 4; j++)
                                {
                                    string valueString = matrixValues[i * 4 + j];
                                    double value;
                                    if (double.TryParse(valueString, out value))
                                    {
                                        loadedMatrix[i, j] = value;
                                    }
                                }
                            }

                            config.ModelMatrix = loadedMatrix;
                            break;

                        default:
                            throw new NotImplementedException("Unknown option: {0}\n".FormatWith(str));
                            // LogOutput.logError("Unknown option: {0}\n".FormatWith(str));
                            // break;
                        }
                    }
                }
                else
                {
                    using (new QuickTimer2("LoadStlFile"))
                    {
                        processor.LoadStlFile(args[argn]);
                    }
                }
            }

            return(1);
        }
예제 #23
0
        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));
            }
        }