Пример #1
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);
            }
        }
Пример #2
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);
        }
Пример #3
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);
            }
        }
Пример #4
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);
            }
        }
Пример #5
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);
			}
		}
Пример #6
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();
				}
			}
		}
Пример #7
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);
        }
Пример #8
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();
                }
            }
        }
Пример #9
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);
        }