Пример #1
0
        public static void GenerateTriangleInfill(ConfigSettings config, Polygons partOutline, ref Polygons fillPolygons, double fillAngle)
        {
            if (config.infillPercent <= 0)
            {
                throw new Exception("infillPercent must be gerater than 0.");
            }

            int linespacing_um = (int)(config.extrusionWidth_um / (config.infillPercent / 100) * 3);

            long offset = linespacing_um / 2;

            Infill.GenerateLinePaths(partOutline, ref fillPolygons, linespacing_um, config.infillExtendIntoPerimeter_um, fillAngle, offset);

            fillAngle += 60;
            if (fillAngle > 360)
            {
                fillAngle -= 360;
            }

            Infill.GenerateLinePaths(partOutline, ref fillPolygons, linespacing_um, config.infillExtendIntoPerimeter_um, fillAngle, offset);

            fillAngle += 60;
            if (fillAngle > 360)
            {
                fillAngle -= 360;
            }

            Infill.GenerateLinePaths(partOutline, ref fillPolygons, linespacing_um, config.infillExtendIntoPerimeter_um, fillAngle, offset);
        }
Пример #2
0
        public void QueueAirGappedBottomLayer(ConfigSettings config, GCodePlanner gcodeLayer, int layerIndex, GCodePathConfig supportNormalConfig)
        {
            // normal support
            Polygons currentAirGappedBottoms = airGappedBottomOutlines[layerIndex];

            currentAirGappedBottoms = currentAirGappedBottoms.Offset(-config.ExtrusionWidth_um / 2);
            List <Polygons> supportIslands = currentAirGappedBottoms.ProcessIntoSeparatIslands();

            foreach (Polygons islandOutline in supportIslands)
            {
                Polygons islandInfillLines = new Polygons();
                // render a grid of support
                if (config.GenerateSupportPerimeter)
                {
                    Polygons outlines = Clipper.CleanPolygons(islandOutline, config.ExtrusionWidth_um / 4);
                    gcodeLayer.QueuePolygonsByOptimizer(outlines, supportNormalConfig);
                }
                Polygons infillOutline = islandOutline.Offset(-config.ExtrusionWidth_um / 2);
                switch (config.SupportType)
                {
                case ConfigConstants.SUPPORT_TYPE.GRID:
                    Infill.GenerateGridInfill(config, infillOutline, islandInfillLines, config.SupportInfillStartingAngle, config.SupportLineSpacing_um);
                    break;

                case ConfigConstants.SUPPORT_TYPE.LINES:
                    Infill.GenerateLineInfill(config, infillOutline, islandInfillLines, config.SupportInfillStartingAngle, config.SupportLineSpacing_um);
                    break;
                }
                gcodeLayer.QueuePolygonsByOptimizer(islandInfillLines, supportNormalConfig);
            }
        }
Пример #3
0
        public bool QueueNormalSupportLayer(ConfigSettings config, GCodePlanner gcodeLayer, int layerIndex, GCodePathConfig supportNormalConfig)
        {
            // normal support
            Polygons currentSupportOutlines = supportOutlines[layerIndex];

            currentSupportOutlines = currentSupportOutlines.Offset(-supportNormalConfig.lineWidth_um / 2);
            List <Polygons> supportIslands = currentSupportOutlines.ProcessIntoSeparatIslands();

            bool outputPaths = false;

            foreach (Polygons islandOutline in supportIslands)
            {
                // force a retract if changing islands
                if (config.RetractWhenChangingIslands)
                {
                    gcodeLayer.ForceRetract();
                }

                Polygons islandInfillLines = new Polygons();
                // render a grid of support
                if (config.GenerateSupportPerimeter || layerIndex == 0)
                {
                    Polygons outlines = Clipper.CleanPolygons(islandOutline, config.ExtrusionWidth_um / 4);
                    if (gcodeLayer.QueuePolygonsByOptimizer(outlines, supportNormalConfig))
                    {
                        outputPaths = true;
                    }
                }

                Polygons infillOutline = islandOutline.Offset(-supportNormalConfig.lineWidth_um / 2);

                if (layerIndex == 0)
                {
                    // on the first layer print this as solid
                    Infill.GenerateLineInfill(config, infillOutline, islandInfillLines, config.SupportInfillStartingAngle, config.ExtrusionWidth_um);
                }
                else
                {
                    switch (config.SupportType)
                    {
                    case ConfigConstants.SUPPORT_TYPE.GRID:
                        Infill.GenerateGridInfill(config, infillOutline, islandInfillLines, config.SupportInfillStartingAngle, config.SupportLineSpacing_um);
                        break;

                    case ConfigConstants.SUPPORT_TYPE.LINES:
                        Infill.GenerateLineInfill(config, infillOutline, islandInfillLines, config.SupportInfillStartingAngle, config.SupportLineSpacing_um);
                        break;
                    }
                }

                if (gcodeLayer.QueuePolygonsByOptimizer(islandInfillLines, supportNormalConfig))
                {
                    outputPaths |= true;
                }
            }

            return(outputPaths);
        }
Пример #4
0
        public static void GenerateHexagonInfill(ConfigSettings config, Polygons partOutline, ref Polygons fillPolygons, double fillAngle, int layerIndex)
        {
            if (config.infillPercent <= 0)
            {
                throw new Exception("infillPercent must be gerater than 0.");
            }

            int linespacing_um = (int)(config.extrusionWidth_um / (config.infillPercent / 100) * 3 * .66);

            Infill.GenerateHexLinePaths(partOutline, ref fillPolygons, linespacing_um, config.infillExtendIntoPerimeter_um, fillAngle, layerIndex);
        }
Пример #5
0
        public void QueueInterfaceSupportLayer(ConfigSettings config, GCodePlanner gcodeLayer, int layerIndex, GCodePathConfig supportInterfaceConfig)
        {
            // interface
            Polygons currentInterfaceOutlines = interfaceLayers[layerIndex].Offset(-config.ExtrusionWidth_um / 2);

            if (currentInterfaceOutlines.Count > 0)
            {
                Polygons supportLines = new Polygons();
                Infill.GenerateLineInfill(config, currentInterfaceOutlines, supportLines, config.InfillStartingAngle + 90, config.ExtrusionWidth_um);
                gcodeLayer.QueuePolygonsByOptimizer(supportLines, supportInterfaceConfig);
            }
        }
Пример #6
0
        public void GenerateFillConsideringBridging(Polygons bottomFillIsland, Polygons bottomFillLines, ConfigSettings config, Polygons bridgePolygons, string debugName = "")
        {
            double bridgeAngle = 0;

            if (this.BridgeAngle(bottomFillIsland, out bridgeAngle))
            {
                // TODO: Make this code handle very complex pathing between different sizes or layouts of support under the island to fill.
                Infill.GenerateLinePaths(bottomFillIsland, bridgePolygons, config.ExtrusionWidth_um, config.InfillExtendIntoPerimeter_um, bridgeAngle);
            }
            else
            {
                Infill.GenerateLinePaths(bottomFillIsland, bottomFillLines, config.ExtrusionWidth_um, config.InfillExtendIntoPerimeter_um, config.InfillStartingAngle);
            }
        }
Пример #7
0
        public bool QueueInterfaceSupportLayer(ConfigSettings config, LayerGCodePlanner gcodeLayer, int layerIndex, GCodePathConfig supportInterfaceConfig)
        {
            // interface
            bool     outputPaths       = false;
            Polygons interfaceOutlines = InterfaceLayers[layerIndex];

            if (interfaceOutlines.Count > 0)
            {
                List <Polygons> interfaceIslands = interfaceOutlines.ProcessIntoSeparateIslands();

                foreach (Polygons interfaceIsland in interfaceIslands)
                {
                    PathFinder pathFinder = null;
                    if (config.AvoidCrossingPerimeters)
                    {
                        pathFinder = new PathFinder(interfaceIsland, -config.ExtrusionWidth_um / 2, useInsideCache: config.AvoidCrossingPerimeters, name: "interface");
                    }

                    // force a retract if changing islands
                    if (config.RetractWhenChangingIslands)
                    {
                        gcodeLayer.ForceRetract();
                    }

                    var infillOffset = -config.ExtrusionWidth_um + config.InfillExtendIntoPerimeter_um;

                    // make a border if layer 0
                    if (config.GenerateSupportPerimeter || layerIndex == 0)
                    {
                        if (gcodeLayer.QueuePolygonsByOptimizer(interfaceIsland.Offset(-config.ExtrusionWidth_um / 2), pathFinder, supportInterfaceConfig, 0))
                        {
                            outputPaths = true;
                        }

                        infillOffset = config.ExtrusionWidth_um * -2 + config.InfillExtendIntoPerimeter_um;
                    }

                    Polygons supportLines = new Polygons();
                    Infill.GenerateLineInfill(config, interfaceIsland.Offset(infillOffset), supportLines, config.InfillStartingAngle + 90, config.ExtrusionWidth_um);
                    if (gcodeLayer.QueuePolygonsByOptimizer(supportLines, pathFinder, supportInterfaceConfig, 0))
                    {
                        outputPaths = true;
                    }
                }
            }

            return(outputPaths);
        }
Пример #8
0
        public bool QueueInterfaceSupportLayer(ConfigSettings config,
                                               LayerGCodePlanner gcodeLayer,
                                               int layerIndex,
                                               GCodePathConfig supportInterfaceConfig)
        {
            var foundSupport = false;

            // interface
            Polygons interfaceOutlines = InterfaceLayers[layerIndex];

            if (interfaceOutlines.Count > 0)
            {
                List <Polygons> interfaceIslands = interfaceOutlines.ProcessIntoSeparateIslands();

                foreach (Polygons interfaceIsland in interfaceIslands)
                {
                    var allSupport = new Polygons();

                    // force a retract if changing islands
                    if (config.RetractWhenChangingIslands)
                    {
                        gcodeLayer.ForceRetract();
                    }

                    var infillOffset = -config.ExtrusionWidth_um + config.InfillExtendIntoPerimeter_um;

                    // make a border if layer 0
                    // make a border if layer 0
                    if (config.GenerateSupportPerimeter || layerIndex == 0)
                    {
                        allSupport.AddRange(interfaceIsland.Offset(config.ExtrusionWidth_um / 2));
                    }

                    var supportLines = new Polygons();
                    Infill.GenerateLineInfill(config, interfaceIsland.Offset(infillOffset), supportLines, config.InfillStartingAngle + 90, config.ExtrusionWidth_um);
                    allSupport.AddRange(supportLines);

                    var pathFinder = new PathFinder(interfaceIsland, config.ExtrusionWidth_um * 3 / 2);

                    if (gcodeLayer.QueuePolygonsByOptimizer(allSupport, pathFinder, supportInterfaceConfig, 0))
                    {
                        foundSupport = true;
                    }
                }
            }

            return(foundSupport);
        }
Пример #9
0
        public void QueueAirGappedBottomLayer(ConfigSettings config, LayerGCodePlanner gcodeLayer, int layerIndex, GCodePathConfig supportNormalConfig)
        {
            // normal support
            Polygons        currentAirGappedBottoms = AirGappedBottomOutlines[layerIndex];
            List <Polygons> supportIslands          = currentAirGappedBottoms.ProcessIntoSeparateIslands();

            foreach (Polygons supportIsland in supportIslands)
            {
                PathFinder pathFinder = null;
                if (config.AvoidCrossingPerimeters)
                {
                    pathFinder = new PathFinder(supportIsland, -config.ExtrusionWidth_um / 2, useInsideCache: config.AvoidCrossingPerimeters, name: "air gap");
                }

                // force a retract if changing islands
                if (config.RetractWhenChangingIslands)
                {
                    gcodeLayer.ForceRetract();
                }

                var infillOffset = -config.ExtrusionWidth_um + config.InfillExtendIntoPerimeter_um;

                // make a border if layer 0
                if (config.GenerateSupportPerimeter || layerIndex == 0)
                {
                    var closedLoop = supportNormalConfig.ClosedLoop;
                    supportNormalConfig.ClosedLoop = true;
                    gcodeLayer.QueuePolygonsByOptimizer(supportIsland.Offset(-config.ExtrusionWidth_um / 2), pathFinder, supportNormalConfig, layerIndex);
                    infillOffset = config.ExtrusionWidth_um * -2 + config.InfillExtendIntoPerimeter_um;
                    supportNormalConfig.ClosedLoop = closedLoop;
                }

                Polygons infillOutline     = supportIsland.Offset(infillOffset);
                Polygons islandInfillLines = new Polygons();
                switch (config.SupportType)
                {
                case ConfigConstants.SUPPORT_TYPE.GRID:
                    Infill.GenerateGridInfill(config, infillOutline, islandInfillLines, config.SupportInfillStartingAngle, config.SupportLineSpacing_um);
                    break;

                case ConfigConstants.SUPPORT_TYPE.LINES:
                    Infill.GenerateLineInfill(config, infillOutline, islandInfillLines, config.SupportInfillStartingAngle, config.SupportLineSpacing_um);
                    break;
                }

                gcodeLayer.QueuePolygonsByOptimizer(islandInfillLines, pathFinder, supportNormalConfig, 0);
            }
        }
Пример #10
0
		private void addWipeTower(SliceDataStorage storage, GCodePlanner gcodeLayer, int layerNr, int prevExtruder, int extrusionWidth_um)
		{
			if (config.wipeTowerSize_um < 1)
			{
				return;
			}

			//If we changed extruder, print the wipe/prime tower for this nozzle;
			gcodeLayer.WritePolygonsByOptimizer(storage.wipeTower, supportInterfaceConfig);
			Polygons fillPolygons = new Polygons();
			Infill.GenerateLinePaths(storage.wipeTower, ref fillPolygons, extrusionWidth_um, config.infillExtendIntoPerimeter_um, 45 + 90 * (layerNr % 2));
			gcodeLayer.WritePolygonsByOptimizer(fillPolygons, supportInterfaceConfig);

			//Make sure we wipe the old extruder on the wipe tower.
			gcodeLayer.WriteTravel(storage.wipePoint - config.extruderOffsets[prevExtruder] + config.extruderOffsets[gcodeLayer.getExtruder()]);
		}
Пример #11
0
        public void CalculateInfillData(ConfigSettings config,
                                        int extruderIndex,
                                        int layerIndex,
                                        LayerIsland part,
                                        Polygons bottomFillLines,
                                        Polygons sparseFillPolygons   = null,
                                        Polygons solidFillPolygons    = null,
                                        Polygons firstTopFillPolygons = null,
                                        Polygons topFillPolygons      = null,
                                        Polygons bridgePolygons       = null,
                                        Polygons bridgeAreas          = null)
        {
            double alternatingInfillAngle = config.InfillStartingAngle;

            if ((layerIndex % 2) == 0)
            {
                alternatingInfillAngle += 90;
            }

            // generate infill for the bottom layer including bridging
            foreach (Polygons bottomFillIsland in part.BottomPaths.ProcessIntoSeparateIslands())
            {
                if (layerIndex > 0)
                {
                    if (this.Support != null)
                    {
                        double infillAngle = config.SupportInterfaceLayers > 0 ? config.InfillStartingAngle : config.InfillStartingAngle + 90;
                        Infill.GenerateLinePaths(bottomFillIsland, bottomFillLines, config.ExtrusionWidth_um, config.InfillExtendIntoPerimeter_um, infillAngle);
                    }
                    else
                    {
                        SliceLayer previousLayer = this.Extruders[extruderIndex].Layers[layerIndex - 1];

                        if (bridgePolygons != null &&
                            previousLayer.BridgeAngle(bottomFillIsland, config.GetNumberOfPerimeters() * config.ExtrusionWidth_um, out double bridgeAngle, bridgeAreas))
                        {
                            // TODO: Make this code handle very complex pathing between different sizes or layouts of support under the island to fill.
                            Infill.GenerateLinePaths(bottomFillIsland, bridgePolygons, config.ExtrusionWidth_um, config.InfillExtendIntoPerimeter_um, bridgeAngle);
                        }
                        else                         // we still need to extrude at bridging speed
                        {
                            Infill.GenerateLinePaths(bottomFillIsland, bottomFillLines, config.ExtrusionWidth_um, config.InfillExtendIntoPerimeter_um, alternatingInfillAngle, 0, config.BridgeSpeed);
                        }
                    }
                }
Пример #12
0
        public void QueueAirGappedBottomLayer(ConfigSettings config, LayerGCodePlanner gcodeLayer, int layerIndex, GCodePathConfig supportNormalConfig, PathFinder pathFinder)
        {
            // normal support
            Polygons        currentAirGappedBottoms = AirGappedBottomOutlines[layerIndex];
            List <Polygons> supportIslands          = currentAirGappedBottoms.ProcessIntoSeparateIslands();

            foreach (Polygons supportIsland in supportIslands)
            {
                var allSupport = new Polygons();

                // force a retract if changing islands
                if (config.RetractWhenChangingIslands)
                {
                    gcodeLayer.ForceRetract();
                }

                var infillOffset = -config.ExtrusionWidth_um + config.InfillExtendIntoPerimeter_um;

                // make a border if layer 0
                if (config.GenerateSupportPerimeter || layerIndex == 0)
                {
                    allSupport.AddRange(supportIsland.Offset(config.ExtrusionWidth_um / 2));
                    infillOffset = config.ExtrusionWidth_um * -2 + config.InfillExtendIntoPerimeter_um;
                }

                Polygons infillOutline     = supportIsland.Offset(infillOffset);
                var      islandInfillLines = new Polygons();
                switch (config.SupportType)
                {
                case SUPPORT_TYPE.GRID:
                    Infill.GenerateGridInfill(config, infillOutline, islandInfillLines, config.SupportInfillStartingAngle, config.SupportLineSpacing_um);
                    break;

                case SUPPORT_TYPE.LINES:
                    Infill.GenerateLineInfill(config, infillOutline, islandInfillLines, config.SupportInfillStartingAngle, config.SupportLineSpacing_um);
                    break;
                }

                allSupport.AddRange(islandInfillLines);

                gcodeLayer.QueuePolygonsByOptimizer(allSupport, pathFinder, supportNormalConfig, layerIndex);
            }
        }
Пример #13
0
        public static void GenerateGridInfill(ConfigSettings config, Polygons partOutline, Polygons fillPolygons, double fillAngle, int linespacing_um = 0)
        {
            if (linespacing_um == 0)
            {
                if (config.InfillPercent <= 0)
                {
                    throw new Exception("infillPercent must be greater than 0.");
                }
                linespacing_um = (int)(config.ExtrusionWidth_um / (config.InfillPercent / 100) * 2);
            }

            Infill.GenerateLinePaths(partOutline, fillPolygons, linespacing_um, config.InfillExtendIntoPerimeter_um, fillAngle);

            fillAngle += 90;
            if (fillAngle > 360)
            {
                fillAngle -= 360;
            }

            Infill.GenerateLinePaths(partOutline, fillPolygons, linespacing_um, config.InfillExtendIntoPerimeter_um, fillAngle);
        }
Пример #14
0
        public bool QueueInterfaceSupportLayer(ConfigSettings config, LayerGCodePlanner gcodeLayer, int layerIndex, GCodePathConfig supportInterfaceConfig)
        {
            // interface
            bool     outputPaths = false;
            Polygons currentInterfaceOutlines2 = InterfaceLayers[layerIndex].Offset(-config.ExtrusionWidth_um / 2);

            if (currentInterfaceOutlines2.Count > 0)
            {
                List <Polygons> interfaceIslands = currentInterfaceOutlines2.ProcessIntoSeparateIslands();

                foreach (Polygons interfaceOutline in interfaceIslands)
                {
                    // force a retract if changing islands
                    if (config.RetractWhenChangingIslands)
                    {
                        gcodeLayer.ForceRetract();
                    }

                    // make a border if layer 0
                    if (layerIndex == 0)
                    {
                        Polygons infillOutline = interfaceOutline.Offset(-supportInterfaceConfig.lineWidth_um / 2);
                        Polygons outlines      = Clipper.CleanPolygons(infillOutline, config.ExtrusionWidth_um / 4);
                        if (gcodeLayer.QueuePolygonsByOptimizer(outlines, null, supportInterfaceConfig, 0))
                        {
                            outputPaths = true;
                        }
                    }

                    Polygons supportLines = new Polygons();
                    Infill.GenerateLineInfill(config, interfaceOutline, supportLines, config.InfillStartingAngle + 90, config.ExtrusionWidth_um);
                    if (gcodeLayer.QueuePolygonsByOptimizer(supportLines, null, supportInterfaceConfig, 0))
                    {
                        outputPaths = true;
                    }
                }
            }

            return(outputPaths);
        }
Пример #15
0
        public void QueueInterfaceSupportLayer(ConfigSettings config, GCodePlanner gcodeLayer, int layerIndex, GCodePathConfig supportInterfaceConfig)
        {
            // interface
            Polygons currentInterfaceOutlines2 = interfaceLayers[layerIndex].Offset(-config.ExtrusionWidth_um / 2);

            if (currentInterfaceOutlines2.Count > 0)
            {
                List <Polygons> interfaceIslands = currentInterfaceOutlines2.ProcessIntoSeparatIslands();

                foreach (Polygons interfaceOutline in interfaceIslands)
                {
                    // force a retract if changing islands
                    if (config.RetractWhenChangingIslands)
                    {
                        gcodeLayer.ForceRetract();
                    }

                    Polygons supportLines = new Polygons();
                    Infill.GenerateLineInfill(config, interfaceOutline, supportLines, config.InfillStartingAngle + 90, config.ExtrusionWidth_um);
                    gcodeLayer.QueuePolygonsByOptimizer(supportLines, supportInterfaceConfig);
                }
            }
        }
Пример #16
0
        public void WriteRaftGCodeIfRequired(GCodeExport gcode, ConfigSettings config)
        {
            LayerDataStorage storage = this;

            if (config.ShouldGenerateRaft())
            {
                GCodePathConfig raftBaseConfig = new GCodePathConfig("raftBaseConfig");
                raftBaseConfig.SetData(config.FirstLayerSpeed, config.RaftBaseExtrusionWidth_um, "SUPPORT");

                GCodePathConfig raftMiddleConfig = new GCodePathConfig("raftMiddleConfig");
                raftMiddleConfig.SetData(config.RaftPrintSpeed, config.RaftInterfaceExtrusionWidth_um, "SUPPORT");

                GCodePathConfig raftSurfaceConfig = new GCodePathConfig("raftMiddleConfig");
                raftSurfaceConfig.SetData((config.RaftSurfacePrintSpeed > 0) ? config.RaftSurfacePrintSpeed : config.RaftPrintSpeed, config.RaftSurfaceExtrusionWidth_um, "SUPPORT");

                // create the raft base
                {
                    gcode.WriteComment("RAFT BASE");
                    LayerGCodePlanner layerPlanner = new LayerGCodePlanner(config, gcode, config.TravelSpeed, config.MinimumTravelToCauseRetraction_um, config.PerimeterStartEndOverlapRatio);
                    if (config.RaftExtruder >= 0)
                    {
                        // if we have a specified raft extruder use it
                        layerPlanner.SetExtruder(config.RaftExtruder);
                    }
                    else if (config.SupportExtruder >= 0)
                    {
                        // else preserve the old behavior of using the support extruder if set.
                        layerPlanner.SetExtruder(config.SupportExtruder);
                    }

                    gcode.CurrentZ = config.RaftBaseThickness_um;

                    gcode.LayerChanged(-3, config.RaftBaseThickness_um);

                    gcode.SetExtrusion(config.RaftBaseThickness_um, config.FilamentDiameter_um, config.ExtrusionMultiplier);

                    // write the skirt around the raft
                    layerPlanner.QueuePolygonsByOptimizer(storage.Skirt, null, raftBaseConfig, 0);

                    List <Polygons> raftIslands = storage.raftOutline.ProcessIntoSeparateIslands();
                    foreach (var raftIsland in raftIslands)
                    {
                        // write the outline of the raft
                        layerPlanner.QueuePolygonsByOptimizer(raftIsland, null, raftBaseConfig, 0);

                        Polygons raftLines = new Polygons();
                        Infill.GenerateLinePaths(raftIsland.Offset(-config.RaftBaseExtrusionWidth_um), raftLines, config.RaftBaseLineSpacing_um, config.InfillExtendIntoPerimeter_um, 0);

                        // write the inside of the raft base
                        layerPlanner.QueuePolygonsByOptimizer(raftLines, null, raftBaseConfig, 0);

                        if (config.RetractWhenChangingIslands)
                        {
                            layerPlanner.ForceRetract();
                        }
                    }

                    layerPlanner.WriteQueuedGCode(config.RaftBaseThickness_um);
                }

                // raft middle layers
                {
                    gcode.WriteComment("RAFT MIDDLE");
                    LayerGCodePlanner layerPlanner = new LayerGCodePlanner(config, gcode, config.TravelSpeed, config.MinimumTravelToCauseRetraction_um, config.PerimeterStartEndOverlapRatio);
                    gcode.CurrentZ = config.RaftBaseThickness_um + config.RaftInterfaceThicknes_um;
                    gcode.LayerChanged(-2, config.RaftInterfaceThicknes_um);
                    gcode.SetExtrusion(config.RaftInterfaceThicknes_um, config.FilamentDiameter_um, config.ExtrusionMultiplier);

                    Polygons raftLines = new Polygons();
                    Infill.GenerateLinePaths(storage.raftOutline, raftLines, config.RaftInterfaceLineSpacing_um, config.InfillExtendIntoPerimeter_um, 45);
                    layerPlanner.QueuePolygonsByOptimizer(raftLines, null, raftMiddleConfig, 0);

                    layerPlanner.WriteQueuedGCode(config.RaftInterfaceThicknes_um);
                }

                for (int raftSurfaceIndex = 1; raftSurfaceIndex <= config.RaftSurfaceLayers; raftSurfaceIndex++)
                {
                    gcode.WriteComment("RAFT SURFACE");
                    LayerGCodePlanner layerPlanner = new LayerGCodePlanner(config, gcode, config.TravelSpeed, config.MinimumTravelToCauseRetraction_um, config.PerimeterStartEndOverlapRatio);
                    gcode.CurrentZ = config.RaftBaseThickness_um + config.RaftInterfaceThicknes_um + config.RaftSurfaceThickness_um * raftSurfaceIndex;
                    gcode.LayerChanged(-1, config.RaftSurfaceThickness_um);
                    gcode.SetExtrusion(config.RaftSurfaceThickness_um, config.FilamentDiameter_um, config.ExtrusionMultiplier);

                    Polygons raftLines = new Polygons();
                    if (raftSurfaceIndex == config.RaftSurfaceLayers)
                    {
                        // make sure the top layer of the raft is 90 degrees offset to the first layer of the part so that it has minimum contact points.
                        Infill.GenerateLinePaths(storage.raftOutline, raftLines, config.RaftSurfaceLineSpacing_um, config.InfillExtendIntoPerimeter_um, config.InfillStartingAngle + 90);
                    }
                    else
                    {
                        Infill.GenerateLinePaths(storage.raftOutline, raftLines, config.RaftSurfaceLineSpacing_um, config.InfillExtendIntoPerimeter_um, 90 * raftSurfaceIndex);
                    }
                    layerPlanner.QueuePolygonsByOptimizer(raftLines, null, raftSurfaceConfig, 0);

                    layerPlanner.WriteQueuedGCode(config.RaftInterfaceThicknes_um);
                }
            }
        }
Пример #17
0
        public bool QueueNormalSupportLayer(ConfigSettings config, LayerGCodePlanner gcodeLayer, int layerIndex, GCodePathConfig supportNormalConfig)
        {
            // normal support
            Polygons        currentSupportOutlines = SparseSupportOutlines[layerIndex];
            List <Polygons> supportIslands         = currentSupportOutlines.ProcessIntoSeparateIslands();

            List <PathFinder> pathFinders    = new List <PathFinder>();
            List <Polygons>   infillOutlines = new List <Polygons>();

            for (int i = 0; i < supportIslands.Count; i++)
            {
                pathFinders.Add(null);
                infillOutlines.Add(null);
            }

            Agg.Parallel.For(0, supportIslands.Count, (index) =>
            {
                var infillOffset      = -config.ExtrusionWidth_um + config.InfillExtendIntoPerimeter_um;
                var supportIsland     = supportIslands[index];
                infillOutlines[index] = supportIsland.Offset(infillOffset);

                if (config.AvoidCrossingPerimeters)
                {
                    pathFinders[index] = new PathFinder(infillOutlines[index], -config.ExtrusionWidth_um / 2, useInsideCache: config.AvoidCrossingPerimeters, name: "normal support");
                }
            });

            bool outputPaths = false;

            for (int i = 0; i < supportIslands.Count; i++)
            {
                var supportIsland = supportIslands[i];

                // force a retract if changing islands
                if (config.RetractWhenChangingIslands)
                {
                    gcodeLayer.ForceRetract();
                }

                // make a border if layer 0
                if (config.GenerateSupportPerimeter || layerIndex == 0)
                {
                    if (gcodeLayer.QueuePolygonsByOptimizer(supportIsland.Offset(-config.ExtrusionWidth_um / 2), pathFinders[i], supportNormalConfig, 0))
                    {
                        outputPaths = true;
                    }
                }

                Polygons islandInfillLines = new Polygons();
                if (layerIndex == 0)
                {
                    // on the first layer print this as solid
                    Infill.GenerateLineInfill(config, infillOutlines[i], islandInfillLines, config.SupportInfillStartingAngle, config.ExtrusionWidth_um);
                }
                else
                {
                    switch (config.SupportType)
                    {
                    case ConfigConstants.SUPPORT_TYPE.GRID:
                        Infill.GenerateGridInfill(config, infillOutlines[i], islandInfillLines, config.SupportInfillStartingAngle, config.SupportLineSpacing_um);
                        break;

                    case ConfigConstants.SUPPORT_TYPE.LINES:
                        Infill.GenerateLineInfill(config, infillOutlines[i], islandInfillLines, config.SupportInfillStartingAngle, config.SupportLineSpacing_um);
                        break;
                    }
                }

                if (gcodeLayer.QueuePolygonsByOptimizer(islandInfillLines, pathFinders[i], supportNormalConfig, 0))
                {
                    outputPaths |= true;
                }
            }

            return(outputPaths);
        }
Пример #18
0
        private void CalculateInfillData(SliceDataStorage storage, int volumeIndex, int layerIndex, int extrusionWidth_um, SliceLayerPart part, ref Polygons fillPolygons, ref Polygons bridgePolygons)
        {
            // generate infill for outline including bridging
            foreach (Polygons outline in part.skinOutline.SplitIntoParts())
            {
                double partFillAngle = config.infillStartingAngle;
                if ((layerIndex & 1) == 1)
                {
                    partFillAngle += 90;
                }
                if (layerIndex > 0)
                {
                    double bridgeAngle;
                    if (Bridge.BridgeAngle(outline, storage.volumes[volumeIndex].layers[layerIndex - 1], out bridgeAngle))
                    {
                        Infill.GenerateLinePaths(outline, ref bridgePolygons, extrusionWidth_um, config.infillExtendIntoPerimeter_um, bridgeAngle);
                    }
                    else
                    {
                        Infill.GenerateLinePaths(outline, ref fillPolygons, extrusionWidth_um, config.infillExtendIntoPerimeter_um, partFillAngle);
                    }
                }
                else
                {
                    Infill.GenerateLinePaths(outline, ref fillPolygons, extrusionWidth_um, config.infillExtendIntoPerimeter_um, partFillAngle);
                }
            }

            double fillAngle = config.infillStartingAngle;

            // generate the infill for this part on this layer
            if (config.infillPercent > 0)
            {
                switch (config.infillType)
                {
                case ConfigConstants.INFILL_TYPE.LINES:
                    if ((layerIndex & 1) == 1)
                    {
                        fillAngle += 90;
                    }
                    Infill.GenerateLineInfill(config, part.sparseOutline, ref fillPolygons, extrusionWidth_um, fillAngle);
                    break;

                case ConfigConstants.INFILL_TYPE.GRID:
                    Infill.GenerateGridInfill(config, part.sparseOutline, ref fillPolygons, extrusionWidth_um, fillAngle);
                    break;

                case ConfigConstants.INFILL_TYPE.TRIANGLES:
                    Infill.GenerateTriangleInfill(config, part.sparseOutline, ref fillPolygons, extrusionWidth_um, fillAngle);
                    break;

                case ConfigConstants.INFILL_TYPE.HEXAGON:
                    Infill.GenerateHexagonInfill(config, part.sparseOutline, ref fillPolygons, extrusionWidth_um, fillAngle, layerIndex);
                    break;

                case ConfigConstants.INFILL_TYPE.CONCENTRIC:
                    Infill.generateConcentricInfill(config, part.sparseOutline, ref fillPolygons, extrusionWidth_um, fillAngle);
                    break;

                default:
                    throw new NotImplementedException();
                }
            }
        }
Пример #19
0
        public static void GenerateRaftGCodeIfRequired(SliceDataStorage storage, ConfigSettings config, GCodeExport gcode)
        {
            if (ShouldGenerateRaft(config))
            {
                GCodePathConfig raftBaseConfig    = new GCodePathConfig(config.firstLayerSpeed, config.raftBaseExtrusionWidth_um, "SUPPORT");
                GCodePathConfig raftMiddleConfig  = new GCodePathConfig(config.raftPrintSpeed, config.raftInterfaceExtrusionWidth_um, "SUPPORT");
                GCodePathConfig raftSurfaceConfig = new GCodePathConfig((config.raftSurfacePrintSpeed > 0) ? config.raftSurfacePrintSpeed : config.raftPrintSpeed, config.raftSurfaceExtrusionWidth_um, "SUPPORT");

                // create the raft base
                {
                    gcode.writeComment("LAYER:-3");
                    gcode.writeComment("RAFT BASE");
                    GCodePlanner gcodeLayer = new GCodePlanner(gcode, config.travelSpeed, config.minimumTravelToCauseRetraction_um);
                    if (config.raftExtruder > 0)
                    {
                        // if we have a specified raft extruder use it
                        gcodeLayer.setExtruder(config.raftExtruder);
                    }
                    else if (config.supportExtruder > 0)
                    {
                        // else preserve the old behavior of using the support extruder if set.
                        gcodeLayer.setExtruder(config.supportExtruder);
                    }

                    gcode.setZ(config.raftBaseThickness_um);
                    gcode.setExtrusion(config.raftBaseThickness_um, config.filamentDiameter_um, config.extrusionMultiplier);
                    gcodeLayer.writePolygonsByOptimizer(storage.raftOutline, raftBaseConfig);

                    Polygons raftLines = new Polygons();
                    Infill.GenerateLinePaths(storage.raftOutline, ref raftLines, config.raftBaseLineSpacing_um, config.infillExtendIntoPerimeter_um, 0);
                    gcodeLayer.writePolygonsByOptimizer(storage.skirt, raftBaseConfig);
                    gcodeLayer.writePolygonsByOptimizer(raftLines, raftBaseConfig);

                    gcodeLayer.writeGCode(false, config.raftBaseThickness_um);
                }

                if (config.raftFanSpeedPercent > 0)
                {
                    gcode.writeFanCommand(config.raftFanSpeedPercent);
                }

                // raft middle layers
                {
                    gcode.writeComment("LAYER:-2");
                    gcode.writeComment("RAFT MIDDLE");
                    GCodePlanner gcodeLayer = new GCodePlanner(gcode, config.travelSpeed, config.minimumTravelToCauseRetraction_um);
                    gcode.setZ(config.raftBaseThickness_um + config.raftInterfaceThicknes_um);
                    gcode.setExtrusion(config.raftInterfaceThicknes_um, config.filamentDiameter_um, config.extrusionMultiplier);

                    Polygons raftLines = new Polygons();
                    Infill.GenerateLinePaths(storage.raftOutline, ref raftLines, config.raftInterfaceLineSpacing_um, config.infillExtendIntoPerimeter_um, 45);
                    gcodeLayer.writePolygonsByOptimizer(raftLines, raftMiddleConfig);

                    gcodeLayer.writeGCode(false, config.raftInterfaceThicknes_um);
                }

                for (int raftSurfaceIndex = 1; raftSurfaceIndex <= config.raftSurfaceLayers; raftSurfaceIndex++)
                {
                    gcode.writeComment("LAYER:-1");
                    gcode.writeComment("RAFT SURFACE");
                    GCodePlanner gcodeLayer = new GCodePlanner(gcode, config.travelSpeed, config.minimumTravelToCauseRetraction_um);
                    gcode.setZ(config.raftBaseThickness_um + config.raftInterfaceThicknes_um + config.raftSurfaceThickness_um * raftSurfaceIndex);
                    gcode.setExtrusion(config.raftSurfaceThickness_um, config.filamentDiameter_um, config.extrusionMultiplier);

                    Polygons raftLines = new Polygons();
                    if (raftSurfaceIndex == config.raftSurfaceLayers)
                    {
                        // make sure the top layer of the raft is 90 degrees offset to the first layer of the part so that it has minimum contact points.
                        Infill.GenerateLinePaths(storage.raftOutline, ref raftLines, config.raftSurfaceLineSpacing_um, config.infillExtendIntoPerimeter_um, config.infillStartingAngle + 90);
                    }
                    else
                    {
                        Infill.GenerateLinePaths(storage.raftOutline, ref raftLines, config.raftSurfaceLineSpacing_um, config.infillExtendIntoPerimeter_um, 90 * raftSurfaceIndex);
                    }
                    gcodeLayer.writePolygonsByOptimizer(raftLines, raftSurfaceConfig);

                    gcodeLayer.writeGCode(false, config.raftInterfaceThicknes_um);
                }
            }
        }
Пример #20
0
        public static void GenerateRaftGCodeIfRequired(SliceDataStorage storage, ConfigSettings config, GCodeExport gcode)
        {
            if (ShouldGenerateRaft(config))
            {
                GCodePathConfig raftBaseConfig    = new GCodePathConfig(config.firstLayerSpeed, config.extrusionWidth_um * 3, "SUPPORT");
                GCodePathConfig raftMiddleConfig  = new GCodePathConfig(config.raftPrintSpeed, config.raftInterfaceLinewidth_um, "SUPPORT");
                GCodePathConfig raftSurfaceConfig = new GCodePathConfig((config.raftSurfacePrintSpeed > 0) ? config.raftSurfacePrintSpeed : config.raftPrintSpeed, config.raftSurfaceLinewidth_um, "SUPPORT");

                // create the raft base
                {
                    gcode.writeComment("LAYER:-3");
                    gcode.writeComment("RAFT BASE");
                    GCodePlanner gcodeLayer = new GCodePlanner(gcode, config.travelSpeed, config.minimumTravelToCauseRetraction_um);
                    if (config.supportExtruder > 0)
                    {
                        gcodeLayer.setExtruder(config.supportExtruder);
                    }

                    gcode.setZ(config.raftBaseThickness_um);
                    gcode.setExtrusion(config.raftBaseThickness_um, config.filamentDiameter_um, config.extrusionMultiplier);
                    gcodeLayer.writePolygonsByOptimizer(storage.raftOutline, raftBaseConfig);

                    Polygons raftLines = new Polygons();
                    Infill.GenerateLinePaths(storage.raftOutline, ref raftLines, config.raftBaseThickness_um, config.raftLineSpacing_um, config.infillExtendIntoPerimeter_um, 0);
                    gcodeLayer.writePolygonsByOptimizer(storage.skirt, raftBaseConfig);
                    gcodeLayer.writePolygonsByOptimizer(raftLines, raftBaseConfig);

                    gcodeLayer.writeGCode(false, config.raftBaseThickness_um);
                }

                if (config.raftFanSpeedPercent > 0)
                {
                    gcode.writeFanCommand(config.raftFanSpeedPercent);
                }

                // raft middle layers
                {
                    gcode.writeComment("LAYER:-2");
                    gcode.writeComment("RAFT MIDDLE");
                    GCodePlanner gcodeLayer = new GCodePlanner(gcode, config.travelSpeed, config.minimumTravelToCauseRetraction_um);
                    gcode.setZ(config.raftBaseThickness_um + config.raftInterfaceThicknes_um);
                    gcode.setExtrusion(config.raftInterfaceThicknes_um, config.filamentDiameter_um, config.extrusionMultiplier);

                    Polygons raftLines = new Polygons();
                    Infill.GenerateLinePaths(storage.raftOutline, ref raftLines, config.raftInterfaceLinewidth_um, config.raftInterfaceLineSpacing_um, config.infillExtendIntoPerimeter_um, 45);
                    gcodeLayer.writePolygonsByOptimizer(raftLines, raftMiddleConfig);

                    gcodeLayer.writeGCode(false, config.raftInterfaceThicknes_um);
                }

                for (int raftSurfaceLayer = 1; raftSurfaceLayer <= config.raftSurfaceLayers; raftSurfaceLayer++)
                {
                    gcode.writeComment("LAYER:-1");
                    gcode.writeComment("RAFT SURFACE");
                    GCodePlanner gcodeLayer = new GCodePlanner(gcode, config.travelSpeed, config.minimumTravelToCauseRetraction_um);
                    gcode.setZ(config.raftBaseThickness_um + config.raftInterfaceThicknes_um + config.raftSurfaceThickness_um * raftSurfaceLayer);
                    gcode.setExtrusion(config.raftSurfaceThickness_um, config.filamentDiameter_um, config.extrusionMultiplier);

                    Polygons raftLines = new Polygons();
                    Infill.GenerateLinePaths(storage.raftOutline, ref raftLines, config.raftSurfaceLinewidth_um, config.raftSurfaceLineSpacing_um, config.infillExtendIntoPerimeter_um, 90 * raftSurfaceLayer);
                    gcodeLayer.writePolygonsByOptimizer(raftLines, raftSurfaceConfig);

                    gcodeLayer.writeGCode(false, config.raftInterfaceThicknes_um);
                }
            }
        }
Пример #21
0
		private void WriteSupportPolygons(SliceDataStorage storage, GCodePlanner gcodeLayer, int layerIndex, ConfigSettings config, Polygons supportPolygons, SupportType interfaceLayer)
		{
			for (int volumeIndex = 0; volumeIndex < storage.volumes.Count; volumeIndex++)
			{
				SliceLayer layer = storage.volumes[volumeIndex].layers[layerIndex];
				for (int partIndex = 0; partIndex < layer.parts.Count; partIndex++)
				{
					supportPolygons = supportPolygons.CreateDifference(layer.parts[partIndex].TotalOutline.Offset(config.supportXYDistance_um));
				}
			}

			//Contract and expand the support polygons so small sections are removed and the final polygon is smoothed a bit.
			supportPolygons = supportPolygons.Offset(-config.extrusionWidth_um * 1);
			supportPolygons = supportPolygons.Offset(config.extrusionWidth_um * 1);

			List<Polygons> supportIslands = supportPolygons.CreateLayerOutlines(PolygonsHelper.LayerOpperation.EvenOdd);
			PathOrderOptimizer islandOrderOptimizer = new PathOrderOptimizer(gcode.GetPositionXY());

			for (int islandIndex = 0; islandIndex < supportIslands.Count; islandIndex++)
			{
				islandOrderOptimizer.AddPolygon(supportIslands[islandIndex][0]);
			}
			islandOrderOptimizer.Optimize();

			for (int islandIndex = 0; islandIndex < supportIslands.Count; islandIndex++)
			{
				Polygons island = supportIslands[islandOrderOptimizer.bestPolygonOrderIndex[islandIndex]];
				Polygons supportLines = new Polygons();
				if (config.supportLineSpacing_um > 0)
				{
					switch (interfaceLayer)
					{
						case SupportType.Interface:
							Infill.GenerateLineInfill(config, island, ref supportLines, config.supportInfillStartingAngle + 90, config.extrusionWidth_um);
							break;

						case SupportType.General:
							switch (config.supportType)
							{
								case ConfigConstants.SUPPORT_TYPE.GRID:
									Infill.GenerateGridInfill(config, island, ref supportLines, config.supportInfillStartingAngle, config.supportLineSpacing_um);
									break;

								case ConfigConstants.SUPPORT_TYPE.LINES:
									Infill.GenerateLineInfill(config, island, ref supportLines, config.supportInfillStartingAngle, config.supportLineSpacing_um);
									break;
							}
							break;

						default:
							throw new NotImplementedException();
					}
				}

				if (config.avoidCrossingPerimeters)
				{
					gcodeLayer.SetOuterPerimetersToAvoidCrossing(island);
				}

				switch (interfaceLayer)
				{
					case SupportType.Interface:
						gcodeLayer.WritePolygonsByOptimizer(supportLines, supportInterfaceConfig);
						break;

					case SupportType.General:
						if (config.supportType == ConfigConstants.SUPPORT_TYPE.GRID)
						{
							gcodeLayer.WritePolygonsByOptimizer(island, supportNormalConfig);
						}
						gcodeLayer.WritePolygonsByOptimizer(supportLines, supportNormalConfig);
						break;

					default:
						throw new NotImplementedException();
				}

				gcodeLayer.SetOuterPerimetersToAvoidCrossing(null);
			}
		}
Пример #22
0
		private void CalculateInfillData(SliceDataStorage storage, int volumeIndex, int layerIndex, SliceLayerPart part, ref Polygons fillPolygons, ref Polygons bridgePolygons)
		{
			// generate infill the bottom layers including bridging
			foreach (Polygons outline in part.SolidBottomOutlines.CreateLayerOutlines(PolygonsHelper.LayerOpperation.EvenOdd))
			{
				if (layerIndex > 0)
				{
					double bridgeAngle;
					if (Bridge.BridgeAngle(outline, storage.volumes[volumeIndex].layers[layerIndex - 1], out bridgeAngle))
					{
						Infill.GenerateLinePaths(outline, ref bridgePolygons, config.extrusionWidth_um, config.infillExtendIntoPerimeter_um, bridgeAngle);
					}
					else
					{
						Infill.GenerateLinePaths(outline, ref fillPolygons, config.extrusionWidth_um, config.infillExtendIntoPerimeter_um, config.infillStartingAngle);
					}
				}
				else
				{
					Infill.GenerateLinePaths(outline, ref fillPolygons, config.firstLayerExtrusionWidth_um, config.infillExtendIntoPerimeter_um, config.infillStartingAngle);
				}
			}

			// generate infill for the top layers
			foreach (Polygons outline in part.SolidTopOutlines.CreateLayerOutlines(PolygonsHelper.LayerOpperation.EvenOdd))
			{
				Infill.GenerateLinePaths(outline, ref fillPolygons, config.extrusionWidth_um, config.infillExtendIntoPerimeter_um, config.infillStartingAngle);
			}

			// generate infill intermediate layers
			foreach (Polygons outline in part.SolidInfillOutlines.CreateLayerOutlines(PolygonsHelper.LayerOpperation.EvenOdd))
			{
				if (true) // use the old infill method
				{
					Infill.GenerateLinePaths(outline, ref fillPolygons, config.extrusionWidth_um, config.infillExtendIntoPerimeter_um, config.infillStartingAngle + 90 * (layerIndex % 2));
				}
				else // use the new concentric infill (not tested enough yet) have to handle some bad casses better
				{
					double oldInfillPercent = config.infillPercent;
					config.infillPercent = 100;
					Infill.GenerateConcentricInfill(config, outline, ref fillPolygons);
					config.infillPercent = oldInfillPercent;
				}
			}

			double fillAngle = config.infillStartingAngle;

			// generate the infill for this part on this layer
			if (config.infillPercent > 0)
			{
				switch (config.infillType)
				{
					case ConfigConstants.INFILL_TYPE.LINES:
						if ((layerIndex & 1) == 1)
						{
							fillAngle += 90;
						}
						Infill.GenerateLineInfill(config, part.InfillOutlines, ref fillPolygons, fillAngle);
						break;

					case ConfigConstants.INFILL_TYPE.GRID:
						Infill.GenerateGridInfill(config, part.InfillOutlines, ref fillPolygons, fillAngle);
						break;

					case ConfigConstants.INFILL_TYPE.TRIANGLES:
						Infill.GenerateTriangleInfill(config, part.InfillOutlines, ref fillPolygons, fillAngle);
						break;

					case ConfigConstants.INFILL_TYPE.HEXAGON:
						Infill.GenerateHexagonInfill(config, part.InfillOutlines, ref fillPolygons, fillAngle, layerIndex);
						break;

					case ConfigConstants.INFILL_TYPE.CONCENTRIC:
						Infill.GenerateConcentricInfill(config, part.InfillOutlines, ref fillPolygons);
						break;

					default:
						throw new NotImplementedException();
				}
			}
		}
Пример #23
0
        public bool EnsureWipeTowerIsSolid(int layerIndex, PathFinder pathFinder, LayerGCodePlanner layerGcodePlanner, GCodePathConfig fillConfig, ConfigSettings config)
        {
            if (layerIndex >= LastLayerWithChange(config))
            {
                return(false);
            }

            // TODO: if layer index == 0 do all the loops from the outside-in, in order (no lines should be in the wipe tower)
            if (layerIndex == 0 && !config.EnableRaft)
            {
                CheckNoExtruderPrimed(config);

                long insetPerLoop    = fillConfig.LineWidth_um;
                int  maxPrimingLoops = MaxPrimingLoops(config);

                Polygons outlineForExtruder = this.WipeLayer(layerIndex);

                var fillPolygons = new Polygons();
                while (outlineForExtruder.Count > 0)
                {
                    for (int polygonIndex = 0; polygonIndex < outlineForExtruder.Count; polygonIndex++)
                    {
                        Polygon newInset = outlineForExtruder[polygonIndex];
                        newInset.Add(newInset[0]);                         // add in the last move so it is a solid polygon
                        fillPolygons.Add(newInset);
                    }

                    outlineForExtruder = outlineForExtruder.Offset(-insetPerLoop);
                }

                // set the path planner to avoid islands
                if (this.HaveWipeTower(config, layerIndex))
                {
                    layerGcodePlanner.QueueTravel(WipeCenter_um, pathFinder);
                }

                // turn off the planner for the wipe tower
                layerGcodePlanner.QueuePolygons(fillPolygons, null, fillConfig);
            }
            else
            {
                bool allowPartialInfill = false;
                // check if there was a change, if not partial fill the wipe tower
                if (primesThisLayer == 0 &&
                    allowPartialInfill)
                {
                    var outlinePolygons = new Polygons();

                    for (int i = 0; i < config.NumberOfPerimeters; i++)
                    {
                        var insets = this.WipeLayer(layerIndex).Offset(i * -fillConfig.LineWidth_um);
                        foreach (var inset in insets)
                        {
                            outlinePolygons.Add(inset);
                            // Add the first point back onto the polygon
                            outlinePolygons.Last().Add(outlinePolygons.Last()[0]);
                        }
                    }

                    layerGcodePlanner.QueuePolygons(outlinePolygons, null, fillConfig);

                    // print sparse infill on the wipe tower
                    var fillPolygons = new Polygons();

                    Infill.GenerateTriangleInfill(
                        config,
                        this.WipeLayer(layerIndex).Offset(config.NumberOfPerimeters * -fillConfig.LineWidth_um),
                        fillPolygons,
                        config.InfillStartingAngle);

                    layerGcodePlanner.QueuePolygonsByOptimizer(fillPolygons, null, fillConfig, layerIndex);
                }
                else
                {
                    // print all of the extruder loops that have not already been printed
                    int maxPrimingLoops = MaxPrimingLoops(config);

                    for (int primeLoop = primesThisLayer; primeLoop < maxPrimingLoops; primeLoop++)
                    {
                        // write the loops for this extruder, but don't change to it. We are just filling the prime tower.
                        PrimeOnWipeTower(layerIndex, layerGcodePlanner, pathFinder, fillConfig, config, false);
                    }
                }

                // clear the history of printer extruders for the next layer
                primesThisLayer = 0;
            }

            return(true);
        }
Пример #24
0
        public bool QueueNormalSupportLayer(ConfigSettings config, LayerGCodePlanner gcodeLayer, int layerIndex, GCodePathConfig supportNormalConfig, PathFinder pathFinder)
        {
            var foundSupport = false;

            // normal support
            Polygons        currentSupportOutlines = SparseSupportOutlines[layerIndex];
            List <Polygons> supportIslands         = currentSupportOutlines.ProcessIntoSeparateIslands();

            var infillOutlines = new List <Polygons>();

            for (int i = 0; i < supportIslands.Count; i++)
            {
                infillOutlines.Add(null);
            }

            Agg.Parallel.For(0, supportIslands.Count, (index) =>
            {
                var infillOffset      = -config.ExtrusionWidth_um + config.InfillExtendIntoPerimeter_um;
                var supportIsland     = supportIslands[index];
                infillOutlines[index] = supportIsland.Offset(infillOffset);
            });

            for (int i = 0; i < supportIslands.Count; i++)
            {
                var allSupport = new Polygons();

                var supportIsland = supportIslands[i];

                // force a retract if changing islands
                if (config.RetractWhenChangingIslands)
                {
                    gcodeLayer.ForceRetract();
                }

                // make a border if layer 0
                if (config.GenerateSupportPerimeter || layerIndex == 0)
                {
                    allSupport.AddRange(supportIsland.Offset(config.ExtrusionWidth_um / 2));
                }

                var islandInfillLines = new Polygons();
                if (layerIndex == 0)
                {
                    // on the first layer print this as solid
                    Infill.GenerateLineInfill(config, infillOutlines[i], islandInfillLines, config.SupportInfillStartingAngle, config.ExtrusionWidth_um);
                }
                else
                {
                    switch (config.SupportType)
                    {
                    case SUPPORT_TYPE.GRID:
                        Infill.GenerateGridInfill(config, infillOutlines[i], islandInfillLines, config.SupportInfillStartingAngle, config.SupportLineSpacing_um);
                        break;

                    case SUPPORT_TYPE.LINES:
                        Infill.GenerateLineInfill(config, infillOutlines[i], islandInfillLines, config.SupportInfillStartingAngle, config.SupportLineSpacing_um);
                        break;
                    }
                }

                allSupport.AddRange(islandInfillLines);

                if (gcodeLayer.QueuePolygonsByOptimizer(allSupport, pathFinder, supportNormalConfig, 0))
                {
                    foundSupport = true;
                }
            }

            return(foundSupport);
        }