Beispiel #1
0
		//Add a single layer from a single extruder to the GCode
		private void QueueExtruderLayerToGCode(LayerDataStorage slicingData, GCodePlanner gcodeLayer, int extruderIndex, int layerIndex, int extrusionWidth_um, int fanSpeedPercent, long currentZ_um)
		{
			int prevExtruder = gcodeLayer.getExtruder();
			bool extruderChanged = gcodeLayer.SetExtruder(extruderIndex);

			SliceLayer layer = slicingData.Extruders[extruderIndex].Layers[layerIndex];
			if (extruderChanged)
			{
				addWipeTower(slicingData, gcodeLayer, layerIndex, prevExtruder, extrusionWidth_um);
			}

			if (slicingData.wipeShield.Count > 0 && slicingData.Extruders.Count > 1)
			{
				gcodeLayer.SetAlwaysRetract(true);
				gcodeLayer.QueuePolygonsByOptimizer(slicingData.wipeShield[layerIndex], skirtConfig);
				gcodeLayer.SetAlwaysRetract(!config.avoidCrossingPerimeters);
			}

			PathOrderOptimizer partOrderOptimizer = new PathOrderOptimizer(new IntPoint());
			for (int partIndex = 0; partIndex < layer.Islands.Count; partIndex++)
			{
				if (config.continuousSpiralOuterPerimeter && partIndex > 0)
				{
					continue;
				}

				partOrderOptimizer.AddPolygon(layer.Islands[partIndex].InsetToolPaths[0][0]);
			}
			partOrderOptimizer.Optimize();

			List<Polygons> bottomFillIslandPolygons = new List<Polygons>();

			for (int partIndex = 0; partIndex < partOrderOptimizer.bestPolygonOrderIndex.Count; partIndex++)
			{
				if (config.continuousSpiralOuterPerimeter && partIndex > 0)
				{
					continue;
				}

				LayerIsland island = layer.Islands[partOrderOptimizer.bestPolygonOrderIndex[partIndex]];

				if (config.avoidCrossingPerimeters)
				{
					gcodeLayer.SetOuterPerimetersToAvoidCrossing(island.AvoidCrossingBoundery);
				}
				else
				{
					gcodeLayer.SetAlwaysRetract(true);
				}

				Polygons fillPolygons = new Polygons();
				Polygons topFillPolygons = new Polygons();
				Polygons bridgePolygons = new Polygons();

				Polygons bottomFillPolygons = new Polygons();

				CalculateInfillData(slicingData, extruderIndex, layerIndex, island, ref bottomFillPolygons, ref fillPolygons, ref topFillPolygons, ref bridgePolygons);
				bottomFillIslandPolygons.Add(bottomFillPolygons);

				// Write the bridge polygons out first so the perimeter will have more to hold to while bridging the gaps.
				// It would be even better to slow down the perimeters that are part of bridges but that is a bit harder.
				if (bridgePolygons.Count > 0)
				{
					gcode.WriteFanCommand(config.bridgeFanSpeedPercent);
					gcodeLayer.QueuePolygonsByOptimizer(bridgePolygons, bridgConfig);
				}

				if (config.numberOfPerimeters > 0)
				{
					if (partIndex != lastPartIndex)
					{
						// force a retract if changing islands
						if (config.retractWhenChangingIslands)
						{
							gcodeLayer.ForceRetract();
						}
						lastPartIndex = partIndex;
					}

					if (config.continuousSpiralOuterPerimeter)
					{
						if (layerIndex >= config.numberOfBottomLayers)
						{
							inset0Config.spiralize = true;
						}
					}

					// If we are on the very first layer we start with the outside so that we can stick to the bed better.
					if (config.outsidePerimetersFirst || layerIndex == 0 || inset0Config.spiralize)
					{
						if (inset0Config.spiralize)
						{
							if (island.InsetToolPaths.Count > 0)
							{
								Polygon outsideSinglePolygon = island.InsetToolPaths[0][0];
								gcodeLayer.QueuePolygonsByOptimizer(new Polygons() { outsideSinglePolygon }, inset0Config);
							}
						}
						else
						{
							// First the outside (this helps with accuracy)
							if (island.InsetToolPaths.Count > 0)
							{
								QueuePolygonsConsideringSupport(layerIndex, gcodeLayer, island.InsetToolPaths[0], inset0Config, SupportWriteType.UnsupportedAreas);
							}

							for (int perimeterIndex = 1; perimeterIndex < island.InsetToolPaths.Count; perimeterIndex++)
							{
								QueuePolygonsConsideringSupport(layerIndex, gcodeLayer, island.InsetToolPaths[perimeterIndex], insetXConfig, SupportWriteType.UnsupportedAreas);
							}
						}
					}
					else // This is so we can do overhangs better (the outside can stick a bit to the inside).
					{
						// Figure out where the seam hiding start point is for inset 0 and move to that spot so
						// we have the minimum travel while starting inset 0 after printing the rest of the insets
						if (island?.InsetToolPaths?[0]?[0]?.Count > 0)
						{
							int bestPoint = PathOrderOptimizer.GetBestEdgeIndex(island.InsetToolPaths[0][0]);
							gcodeLayer.QueueTravel(island.InsetToolPaths[0][0][bestPoint]);
						}

						// Print everything but the first perimeter from the outside in so the little parts have more to stick to.
						for (int perimeterIndex = 1; perimeterIndex < island.InsetToolPaths.Count; perimeterIndex++)
						{
							QueuePolygonsConsideringSupport(layerIndex, gcodeLayer, island.InsetToolPaths[perimeterIndex], insetXConfig, SupportWriteType.UnsupportedAreas);
						}
						// then 0
						if (island.InsetToolPaths.Count > 0)
						{
							QueuePolygonsConsideringSupport(layerIndex, gcodeLayer, island.InsetToolPaths[0], inset0Config, SupportWriteType.UnsupportedAreas);
						}
					}
				}

				gcodeLayer.QueuePolygonsByOptimizer(fillPolygons, fillConfig);

				QueuePolygonsConsideringSupport(layerIndex, gcodeLayer, bottomFillPolygons, bottomFillConfig, SupportWriteType.UnsupportedAreas);

				gcodeLayer.QueuePolygonsByOptimizer(topFillPolygons, topFillConfig);

				//After a layer part, make sure the nozzle is inside the comb boundary, so we do not retract on the perimeter.
				if (!config.continuousSpiralOuterPerimeter || layerIndex < config.numberOfBottomLayers)
				{
					gcodeLayer.MoveInsideTheOuterPerimeter(extrusionWidth_um * 2);
				}
			}

			gcodeLayer.SetOuterPerimetersToAvoidCrossing(null);
		}
Beispiel #2
0
		private void QueueSkirtToGCode(LayerDataStorage slicingData, GCodePlanner gcodeLayer, int layerIndex)
		{
			if (slicingData.skirt.Count > 0
				&& slicingData.skirt[0].Count > 0)
			{
				IntPoint lowestPoint = slicingData.skirt[0][0];

				// lets make sure we start with the most outside loop
				foreach (Polygon polygon in slicingData.skirt)
				{
					foreach (IntPoint position in polygon)
					{
						if (position.Y < lowestPoint.Y)
						{
							lowestPoint = polygon[0];
						}
					}
				}

				gcodeLayer.QueueTravel(lowestPoint);
			}

			gcodeLayer.QueuePolygonsByOptimizer(slicingData.skirt, skirtConfig);
		}
        private void writeGCode(LayerDataStorage slicingData)
        {
            gcode.WriteComment("filamentDiameter = {0}".FormatWith(config.FilamentDiameter));
            gcode.WriteComment("extrusionWidth = {0}".FormatWith(config.ExtrusionWidth));
            gcode.WriteComment("firstLayerExtrusionWidth = {0}".FormatWith(config.FirstLayerExtrusionWidth));
            gcode.WriteComment("layerThickness = {0}".FormatWith(config.LayerThickness));
            gcode.WriteComment("firstLayerThickness = {0}".FormatWith(config.FirstLayerThickness));

            if (fileNumber == 1)
            {
                gcode.WriteCode(config.StartCode);
            }
            else
            {
                gcode.WriteFanCommand(0);
                gcode.ResetExtrusionValue();
                gcode.WriteRetraction();
                gcode.setZ(maxObjectHeight + 5000);
                gcode.WriteMove(gcode.GetPosition(), config.TravelSpeed, 0);
                gcode.WriteMove(new Point3(slicingData.modelMin.x, slicingData.modelMin.y, gcode.CurrentZ), config.TravelSpeed, 0);
            }
            fileNumber++;

            int totalLayers = slicingData.Extruders[0].Layers.Count;
            if (config.outputOnlyFirstLayer)
            {
                totalLayers = 1;
            }

            // let's remove any of the layers on top that are empty
            {
                for (int layerIndex = totalLayers - 1; layerIndex >= 0; layerIndex--)
                {
                    bool layerHasData = false;
                    foreach (ExtruderLayers currentExtruder in slicingData.Extruders)
                    {
                        SliceLayer currentLayer = currentExtruder.Layers[layerIndex];
                        for (int partIndex = 0; partIndex < currentExtruder.Layers[layerIndex].Islands.Count; partIndex++)
                        {
                            LayerIsland currentIsland = currentLayer.Islands[partIndex];
                            if (currentIsland.IslandOutline.Count > 0)
                            {
                                layerHasData = true;
                                break;
                            }
                        }
                    }

                    if (layerHasData)
                    {
                        break;
                    }
                    totalLayers--;
                }
            }
            gcode.WriteComment("Layer count: {0}".FormatWith(totalLayers));

            // keep the raft generation code inside of raft
            slicingData.WriteRaftGCodeIfRequired(gcode, config);

            for (int layerIndex = 0; layerIndex < totalLayers; layerIndex++)
            {
                if (MatterSlice.Canceled)
                {
                    return;
                }

                if(config.outputOnlyFirstLayer && layerIndex > 0)
                {
                    break;
                }

                LogOutput.Log("Writing Layers {0}/{1}\n".FormatWith(layerIndex + 1, totalLayers));

                LogOutput.logProgress("export", layerIndex + 1, totalLayers);

                if (layerIndex == 0)
                {
                    skirtConfig.SetData(config.FirstLayerSpeed, config.FirstLayerExtrusionWidth_um, "SKIRT");
                    inset0Config.SetData(config.FirstLayerSpeed, config.FirstLayerExtrusionWidth_um, "WALL-OUTER");
                    insetXConfig.SetData(config.FirstLayerSpeed, config.FirstLayerExtrusionWidth_um, "WALL-INNER");

                    fillConfig.SetData(config.FirstLayerSpeed, config.FirstLayerExtrusionWidth_um, "FILL", false);
                    topFillConfig.SetData(config.FirstLayerSpeed, config.FirstLayerExtrusionWidth_um, "TOP-FILL", false);
                    bottomFillConfig.SetData(config.FirstLayerSpeed, config.FirstLayerExtrusionWidth_um, "BOTTOM-FILL", false);
                    airGappedBottomConfig.SetData(config.FirstLayerSpeed, config.FirstLayerExtrusionWidth_um, "AIR-GAP", false);
                    bridgeConfig.SetData(config.FirstLayerSpeed, config.FirstLayerExtrusionWidth_um, "BRIDGE");

                    supportNormalConfig.SetData(config.FirstLayerSpeed, config.SupportExtrusionWidth_um, "SUPPORT");
                    supportInterfaceConfig.SetData(config.FirstLayerSpeed, config.ExtrusionWidth_um, "SUPPORT-INTERFACE");
                }
                else
                {
                    skirtConfig.SetData(config.InsidePerimetersSpeed, config.ExtrusionWidth_um, "SKIRT");
                    inset0Config.SetData(config.OutsidePerimeterSpeed, config.OutsideExtrusionWidth_um, "WALL-OUTER");
                    insetXConfig.SetData(config.InsidePerimetersSpeed, config.ExtrusionWidth_um, "WALL-INNER");

                    fillConfig.SetData(config.InfillSpeed, config.ExtrusionWidth_um, "FILL", false);
                    topFillConfig.SetData(config.TopInfillSpeed, config.ExtrusionWidth_um, "TOP-FILL", false);
                    bottomFillConfig.SetData(config.InfillSpeed, config.ExtrusionWidth_um, "BOTTOM-FILL", false);
                    airGappedBottomConfig.SetData(config.FirstLayerSpeed, config.ExtrusionWidth_um, "AIR-GAP", false);
                    bridgeConfig.SetData(config.BridgeSpeed, config.ExtrusionWidth_um, "BRIDGE");

                    supportNormalConfig.SetData(config.SupportMaterialSpeed, config.SupportExtrusionWidth_um, "SUPPORT");
                    supportInterfaceConfig.SetData(config.FirstLayerSpeed - 1, config.ExtrusionWidth_um, "SUPPORT-INTERFACE");
                }

                gcode.WriteComment("LAYER:{0}".FormatWith(layerIndex));
                if (layerIndex == 0)
                {
                    gcode.SetExtrusion(config.FirstLayerThickness_um, config.FilamentDiameter_um, config.ExtrusionMultiplier);
                }
                else
                {
                    gcode.SetExtrusion(config.LayerThickness_um, config.FilamentDiameter_um, config.ExtrusionMultiplier);
                }

                GCodePlanner gcodeLayer = new GCodePlanner(gcode, config.TravelSpeed, config.MinimumTravelToCauseRetraction_um, config.PerimeterStartEndOverlapRatio);
                if (layerIndex == 0
                    && config.RetractionZHop > 0)
                {
                    gcodeLayer.ForceRetract();
                }

                // get the correct height for this layer
                int z = config.FirstLayerThickness_um + layerIndex * config.LayerThickness_um;
                if (config.EnableRaft)
                {
                    z += config.RaftBaseThickness_um + config.RaftInterfaceThicknes_um + config.RaftSurfaceLayers * config.RaftSurfaceThickness_um;
                    if (layerIndex == 0)
                    {
                        // We only raise the first layer of the print up by the air gap.
                        // To give it:
                        //   Less press into the raft
                        //   More time to cool
                        //   more surface area to air while extruding
                        z += config.RaftAirGap_um;
                    }
                }

                gcode.setZ(z);

                // We only create the skirt if we are on layer 0.
                if (layerIndex == 0 && !config.ShouldGenerateRaft())
                {
                    QueueSkirtToGCode(slicingData, gcodeLayer, layerIndex);
                }

                int fanSpeedPercent = GetFanSpeed(layerIndex, gcodeLayer);

                for (int extruderIndex = 0; extruderIndex < config.MaxExtruderCount(); extruderIndex++)
                {
                    int prevExtruder = gcodeLayer.GetExtruder();
                    bool extruderChanged = gcodeLayer.SetExtruder(extruderIndex);

                    if (extruderChanged)
                    {
                        slicingData.PrimeOnWipeTower(extruderIndex, layerIndex, gcodeLayer, fillConfig, config);
                        //Make sure we wipe the old extruder on the wipe tower.
                        gcodeLayer.QueueTravel(slicingData.wipePoint - config.ExtruderOffsets[prevExtruder] + config.ExtruderOffsets[gcodeLayer.GetExtruder()]);
                    }

                    if (layerIndex == 0)
                    {
                        QueueExtruderLayerToGCode(slicingData, gcodeLayer, extruderIndex, layerIndex, config.FirstLayerExtrusionWidth_um, z);
                    }
                    else
                    {
                        QueueExtruderLayerToGCode(slicingData, gcodeLayer, extruderIndex, layerIndex, config.ExtrusionWidth_um, z);
                    }

                    if (slicingData.support != null)
                    {
                        if ((config.SupportExtruder <= 0 && extruderIndex == 0)
                            || config.SupportExtruder == extruderIndex)
                        {
                            slicingData.support.QueueNormalSupportLayer(config, gcodeLayer, layerIndex, supportNormalConfig);
                        }
                        if ((config.SupportInterfaceExtruder <= 0 && extruderIndex == 0)
                            || config.SupportInterfaceExtruder == extruderIndex)
                        {
                            slicingData.support.QueueInterfaceSupportLayer(config, gcodeLayer, layerIndex, supportInterfaceConfig);
                        }
                    }
                }

                slicingData.EnsureWipeTowerIsSolid(layerIndex, gcodeLayer, fillConfig, config);

                if (slicingData.support != null)
                {
                    z += config.SupportAirGap_um;
                    gcode.setZ(z);
                    gcodeLayer.QueueTravel(gcodeLayer.LastPosition);

                    for (int extruderIndex = 0; extruderIndex < slicingData.Extruders.Count; extruderIndex++)
                    {
                        QueueAirGappedExtruderLayerToGCode(slicingData, gcodeLayer, extruderIndex, layerIndex, config.ExtrusionWidth_um, z);
                    }

                    slicingData.support.QueueAirGappedBottomLayer(config, gcodeLayer, layerIndex, airGappedBottomConfig);
                }

                //Finish the layer by applying speed corrections for minimum layer times.
                gcodeLayer.ForceMinimumLayerTime(config.MinimumLayerTimeSeconds, config.MinimumPrintingSpeed);

                gcode.WriteFanCommand(fanSpeedPercent);

                int currentLayerThickness_um = config.LayerThickness_um;
                if (layerIndex <= 0)
                {
                    currentLayerThickness_um = config.FirstLayerThickness_um;
                }

                // Move to the best point for the next layer
                if (!config.ContinuousSpiralOuterPerimeter
                    && layerIndex > 0
                    && layerIndex < totalLayers - 2)
                {
                    // Figure out where the seam hiding start point is for inset 0 and move to that spot so
                    // we have the minimum travel while starting inset 0 after printing the rest of the insets
                    SliceLayer layer = slicingData?.Extruders?[0]?.Layers?[layerIndex + 1];
                    if (layer.Islands.Count == 1)
                    {
                        LayerIsland island = layer?.Islands?[0];
                        if (island?.InsetToolPaths?[0]?[0]?.Count > 0)
                        {
                            int bestPoint = PathOrderOptimizer.GetBestIndex(island.InsetToolPaths[0][0], config.ExtrusionWidth_um);
                            gcodeLayer.SetOuterPerimetersToAvoidCrossing(island.AvoidCrossingBoundary);
                            gcodeLayer.QueueTravel(island.InsetToolPaths[0][0][bestPoint]);
                            // Now move up to the next layer so we don't start the extrusion one layer too low.
                            gcode.setZ(z + config.LayerThickness_um);
                            gcodeLayer.QueueTravel(island.InsetToolPaths[0][0][bestPoint]);
                        }
                    }
                }

                gcodeLayer.WriteQueuedGCode(currentLayerThickness_um, fanSpeedPercent, config.BridgeFanSpeedPercent);
            }

            LogOutput.Log("Wrote layers in {0:0.00}s.\n".FormatWith(timeKeeper.Elapsed.TotalSeconds));
            timeKeeper.Restart();
            gcode.TellFileSize();
            gcode.WriteFanCommand(0);

            //Store the object height for when we are printing multiple objects, as we need to clear every one of them when moving to the next position.
            maxObjectHeight = Math.Max(maxObjectHeight, slicingData.modelSize.z);
        }
Beispiel #4
0
		private void addWipeTower(LayerDataStorage slicingData, 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.QueuePolygonsByOptimizer(slicingData.wipeTower, supportInterfaceConfig);
			Polygons fillPolygons = new Polygons();
			Infill.GenerateLinePaths(slicingData.wipeTower, ref fillPolygons, extrusionWidth_um, config.infillExtendIntoPerimeter_um, 45 + 90 * (layerNr % 2));
			gcodeLayer.QueuePolygonsByOptimizer(fillPolygons, supportInterfaceConfig);

			//Make sure we wipe the old extruder on the wipe tower.
			gcodeLayer.QueueTravel(slicingData.wipePoint - config.extruderOffsets[prevExtruder] + config.extruderOffsets[gcodeLayer.getExtruder()]);
		}
        //Add a single layer from a single extruder to the GCode
        private void QueueExtruderLayerToGCode(LayerDataStorage slicingData, GCodePlanner layerGcodePlanner, int extruderIndex, int layerIndex, int extrusionWidth_um, long currentZ_um)
        {
            if(extruderIndex > slicingData.Extruders.Count-1)
            {
                return;
            }

            SliceLayer layer = slicingData.Extruders[extruderIndex].Layers[layerIndex];

            if(layer.AllOutlines.Count == 0
                && config.WipeShieldDistanceFromObject == 0)
            {
                // don't do anything on this layer
                return;
            }

            if (slicingData.wipeShield.Count > 0 && slicingData.Extruders.Count > 1)
            {
                layerGcodePlanner.SetAlwaysRetract(true);
                layerGcodePlanner.QueuePolygonsByOptimizer(slicingData.wipeShield[layerIndex], skirtConfig);
                layerGcodePlanner.SetAlwaysRetract(!config.AvoidCrossingPerimeters);
            }

            PathOrderOptimizer islandOrderOptimizer = new PathOrderOptimizer(new IntPoint());
            for (int partIndex = 0; partIndex < layer.Islands.Count; partIndex++)
            {
                if (config.ContinuousSpiralOuterPerimeter && partIndex > 0)
                {
                    continue;
                }

                islandOrderOptimizer.AddPolygon(layer.Islands[partIndex].InsetToolPaths[0][0]);
            }
            islandOrderOptimizer.Optimize();

            List<Polygons> bottomFillIslandPolygons = new List<Polygons>();

            for (int islandOrderIndex = 0; islandOrderIndex < islandOrderOptimizer.bestIslandOrderIndex.Count; islandOrderIndex++)
            {
                if (config.ContinuousSpiralOuterPerimeter && islandOrderIndex > 0)
                {
                    continue;
                }

                LayerIsland island = layer.Islands[islandOrderOptimizer.bestIslandOrderIndex[islandOrderIndex]];

                if (config.AvoidCrossingPerimeters)
                {
                    layerGcodePlanner.SetOuterPerimetersToAvoidCrossing(island.AvoidCrossingBoundary);
                }
                else
                {
                    layerGcodePlanner.SetAlwaysRetract(true);
                }

                Polygons fillPolygons = new Polygons();
                Polygons topFillPolygons = new Polygons();
                Polygons bridgePolygons = new Polygons();

                Polygons bottomFillPolygons = new Polygons();

                CalculateInfillData(slicingData, extruderIndex, layerIndex, island, bottomFillPolygons, fillPolygons, topFillPolygons, bridgePolygons);
                bottomFillIslandPolygons.Add(bottomFillPolygons);

                // Write the bridge polygons out first so the perimeter will have more to hold to while bridging the gaps.
                // It would be even better to slow down the perimeters that are part of bridges but that is a bit harder.
                if (bridgePolygons.Count > 0)
                {
                    QueuePolygonsConsideringSupport(layerIndex, layerGcodePlanner, bridgePolygons, bridgeConfig, SupportWriteType.UnsupportedAreas);
                }

                if (config.NumberOfPerimeters > 0)
                {
                    if (islandOrderIndex != lastPartIndex)
                    {
                        // force a retract if changing islands
                        if (config.RetractWhenChangingIslands)
                        {
                            layerGcodePlanner.ForceRetract();
                        }
                        lastPartIndex = islandOrderIndex;
                    }

                    if (config.ContinuousSpiralOuterPerimeter)
                    {
                        if (layerIndex >= config.NumberOfBottomLayers)
                        {
                            inset0Config.spiralize = true;
                        }
                    }

                    // Figure out where the seam hiding start point is for inset 0 and move to that spot so
                    // we have the minimum travel while starting inset 0 after printing the rest of the insets
                    if (island?.InsetToolPaths?[0]?[0]?.Count > 0
                        && !config.ContinuousSpiralOuterPerimeter)
                    {
                        int bestPoint = PathOrderOptimizer.GetBestIndex(island.InsetToolPaths[0][0], config.ExtrusionWidth_um);
                        layerGcodePlanner.QueueTravel(island.InsetToolPaths[0][0][bestPoint]);
                    }

                    // Put all the insets into a new list so we can keep track of what has been printed.
                    List<Polygons> insetsToPrint = new List<Polygons>(island.InsetToolPaths.Count);
                    for (int insetIndex = 0; insetIndex < island.InsetToolPaths.Count; insetIndex++)
                    {
                        insetsToPrint.Add(new Polygons());
                        for (int polygonIndex = 0; polygonIndex < island.InsetToolPaths[insetIndex].Count; polygonIndex++)
                        {
                            if (island.InsetToolPaths[insetIndex][polygonIndex].Count > 0)
                            {
                                insetsToPrint[insetIndex].Add(island.InsetToolPaths[insetIndex][polygonIndex]);
                            }
                        }
                    }

                    // If we are on the very first layer we start with the outside so that we can stick to the bed better.
                    if (config.OutsidePerimetersFirst || layerIndex == 0 || inset0Config.spiralize)
                    {
                        if (inset0Config.spiralize)
                        {
                            if (island.InsetToolPaths.Count > 0)
                            {
                                Polygon outsideSinglePolygon = island.InsetToolPaths[0][0];
                                layerGcodePlanner.QueuePolygonsByOptimizer(new Polygons() { outsideSinglePolygon }, inset0Config);
                            }
                        }
                        else
                        {
                            int insetCount = CountInsetsToPrint(insetsToPrint);
                            while (insetCount > 0)
                            {
                                bool limitDistance = false;
                                if (island.InsetToolPaths.Count > 0)
                                {
                                    QueueClosetsInset(insetsToPrint[0], limitDistance, inset0Config, layerIndex, layerGcodePlanner);
                                }

                                if (island.InsetToolPaths.Count > 1)
                                {
                                    // Move to the closest inset 1 and print it
                                    limitDistance = QueueClosetsInset(insetsToPrint[1], limitDistance, insetXConfig, layerIndex, layerGcodePlanner);
                                    for (int insetIndex = 2; insetIndex < island.InsetToolPaths.Count; insetIndex++)
                                    {
                                        limitDistance = QueueClosetsInset(
                                            insetsToPrint[insetIndex],
                                            limitDistance,
                                            insetIndex == 0 ? inset0Config : insetXConfig,
                                            layerIndex,
                                            layerGcodePlanner);
                                    }
                                }

                                insetCount = CountInsetsToPrint(insetsToPrint);
                            }
                        }
                    }
                    else // This is so we can do overhangs better (the outside can stick a bit to the inside).
                    {
                        int insetCount = CountInsetsToPrint(insetsToPrint);
                        while (insetCount > 0)
                        {
                            bool limitDistance = false;
                            if (island.InsetToolPaths.Count > 0)
                            {
                                // Move to the closest inset 1 and print it
                                for (int insetIndex = island.InsetToolPaths.Count-1; insetIndex >= 0; insetIndex--)
                                {
                                    limitDistance = QueueClosetsInset(
                                        insetsToPrint[insetIndex],
                                        limitDistance,
                                        insetIndex == 0 ? inset0Config : insetXConfig,
                                        layerIndex,
                                        layerGcodePlanner);
                                }
                            }

                            insetCount = CountInsetsToPrint(insetsToPrint);
                        }
                    }
                }

                // TODO: Put all of these segments into a list that can be queued together and still preserver their individual config settings.
                // This will make the total amount of travel while printing infill much less.
                layerGcodePlanner.QueuePolygonsByOptimizer(fillPolygons, fillConfig);
                QueuePolygonsConsideringSupport(layerIndex, layerGcodePlanner, bottomFillPolygons, bottomFillConfig, SupportWriteType.UnsupportedAreas);
                layerGcodePlanner.QueuePolygonsByOptimizer(topFillPolygons, topFillConfig);

                //After a layer part, make sure the nozzle is inside the comb boundary, so we do not retract on the perimeter.
                if (!config.ContinuousSpiralOuterPerimeter || layerIndex < config.NumberOfBottomLayers)
                {
                    layerGcodePlanner.MoveInsideTheOuterPerimeter(extrusionWidth_um * 2);
                }
            }

            // Find the thin lines for this layer and add them to the queue
            if (false) // this code is just for test. LBB
            {
                Polygons fillPolygons = new Polygons();
                foreach (var island in layer.Islands)
                {
                    List<Point3> path = new List<Point3>();
                    List<PathAndWidth> thinLines;
                    foreach (var outline in island.IslandOutline.Offset(-extrusionWidth_um * 0))
                    {
                        foreach (var point in outline)
                        {
                            path.Add(new Point3(point, currentZ_um));
                        }
                    }

                    if (layerGcodePlanner.FindThinLines(path, extrusionWidth_um - 2, out thinLines))
                    {
                        foreach (var widthPath in thinLines)
                        {
                            Polygon thinPath = new Polygon();
                            foreach (var point in widthPath.Path)
                            {
                                thinPath.Add(new IntPoint(point.x, point.y));
                            }
                            fillPolygons.Add(thinPath);
                        }
                    }
                }
                layerGcodePlanner.QueuePolygonsByOptimizer(fillPolygons, fillConfig);
            }

            layerGcodePlanner.SetOuterPerimetersToAvoidCrossing(null);
        }