Beispiel #1
0
        private void CreateWipeShields(SliceDataStorage storage, int totalLayers)
        {
            for (int layerNr = 0; layerNr < totalLayers; layerNr++)
            {
                Polygons wipeShield = new Polygons();
                for (int volumeIdx = 0; volumeIdx < storage.volumes.Count; volumeIdx++)
                {
                    for (int partNr = 0; partNr < storage.volumes[volumeIdx].layers[layerNr].parts.Count; partNr++)
                    {
                        wipeShield = wipeShield.CreateUnion(storage.volumes[volumeIdx].layers[layerNr].parts[partNr].outline.Offset(config.wipeShieldDistanceFromShapes_um));
                    }
                }
                storage.wipeShield.Add(wipeShield);
            }

            for (int layerIndex = 0; layerIndex < totalLayers; layerIndex++)
            {
                storage.wipeShield[layerIndex] = storage.wipeShield[layerIndex].Offset(-1000).Offset(1000);
            }

            int offsetAngle = (int)Math.Tan(60.0 * Math.PI / 180) * config.layerThickness_um;//Allow for a 60deg angle in the wipeShield.

            for (int layerNr = 1; layerNr < totalLayers; layerNr++)
            {
                storage.wipeShield[layerNr] = storage.wipeShield[layerNr].CreateUnion(storage.wipeShield[layerNr - 1].Offset(-offsetAngle));
            }

            for (int layerNr = totalLayers - 1; layerNr > 0; layerNr--)
            {
                storage.wipeShield[layerNr - 1] = storage.wipeShield[layerNr - 1].CreateUnion(storage.wipeShield[layerNr].Offset(-offsetAngle));
            }
        }
Beispiel #2
0
        private static List <Polygons> AccumulateDownPolygons(ConfigSettings config, List <Polygons> inputPolys, List <Polygons> allPartOutlines)
        {
            int numLayers = inputPolys.Count;

            long nozzleSize = config.ExtrusionWidth_um;

            List <Polygons> allDownOutlines = CreateEmptyPolygons(numLayers);

            for (int layerIndex = numLayers - 2; layerIndex >= 0; layerIndex--)
            {
                Polygons aboveRequiredSupport = inputPolys[layerIndex + 1];

                // get all the polygons above us
                Polygons accumulatedAbove = allDownOutlines[layerIndex + 1].CreateUnion(aboveRequiredSupport);

                // add in the support on this level
                Polygons curRequiredSupport = inputPolys[layerIndex];

                Polygons totalSupportThisLayer = accumulatedAbove.CreateUnion(curRequiredSupport);

                // remove the solid polygons on this level
                Polygons remainingAbove = totalSupportThisLayer.CreateDifference(allPartOutlines[layerIndex]);

                allDownOutlines[layerIndex] = Clipper.CleanPolygons(remainingAbove, cleanDistance_um);
            }

            return(allDownOutlines);
        }
Beispiel #3
0
        //Expand each layer a bit and then keep the extra overlapping parts that overlap with other volumes.
        //This generates some overlap in dual extrusion, for better bonding in touching parts.
        public static void OverlapMultipleVolumesSlightly(List <SliceVolumeStorage> volumes, int overlap)
        {
            if (volumes.Count < 2 || overlap <= 0)
            {
                return;
            }

            for (int layerIndex = 0; layerIndex < volumes[0].layers.Count; layerIndex++)
            {
                Polygons fullLayer = new Polygons();
                for (int volIdx = 0; volIdx < volumes.Count; volIdx++)
                {
                    SliceLayer layer1 = volumes[volIdx].layers[layerIndex];
                    for (int p1 = 0; p1 < layer1.parts.Count; p1++)
                    {
                        fullLayer = fullLayer.CreateUnion(layer1.parts[p1].outline.Offset(20));
                    }
                }
                fullLayer = fullLayer.Offset(-20);

                for (int volumeIndex = 0; volumeIndex < volumes.Count; volumeIndex++)
                {
                    SliceLayer layer1 = volumes[volumeIndex].layers[layerIndex];
                    for (int partIndex = 0; partIndex < layer1.parts.Count; partIndex++)
                    {
                        layer1.parts[partIndex].outline = fullLayer.CreateIntersection(layer1.parts[partIndex].outline.Offset(overlap / 2));
                    }
                }
            }
        }
Beispiel #4
0
        public static void generateTopAndBottomLayers(int layerIndex, SliceVolumeStorage storage, int extrusionWidth, int downSkinCount, int upSkinCount)
        {
            SliceLayer layer = storage.layers[layerIndex];

            for (int partNr = 0; partNr < layer.parts.Count; partNr++)
            {
                SliceLayerPart part = layer.parts[partNr];

                Polygons upskin   = part.insets[part.insets.Count - 1].Offset(-extrusionWidth / 2);
                Polygons downskin = upskin;

                if (part.insets.Count > 1)
                {
                    // Add thin wall filling by taking the area between the insets.
                    Polygons thinWalls = part.insets[0].Offset(-extrusionWidth / 2).CreateDifference(part.insets[1].Offset(extrusionWidth / 2));
                    upskin.AddAll(thinWalls);
                    downskin.AddAll(thinWalls);
                }

                if (layerIndex - downSkinCount >= 0)
                {
                    SliceLayer layer2 = storage.layers[layerIndex - downSkinCount];
                    for (int partIndex = 0; partIndex < layer2.parts.Count; partIndex++)
                    {
                        if (part.boundaryBox.hit(layer2.parts[partIndex].boundaryBox))
                        {
                            downskin = downskin.CreateDifference(layer2.parts[partIndex].insets[layer2.parts[partIndex].insets.Count - 1]);
                        }
                    }
                }

                if (layerIndex + upSkinCount < storage.layers.Count)
                {
                    SliceLayer layer2 = storage.layers[layerIndex + upSkinCount];
                    for (int partIndex = 0; partIndex < layer2.parts.Count; partIndex++)
                    {
                        if (part.boundaryBox.hit(layer2.parts[partIndex].boundaryBox))
                        {
                            upskin = upskin.CreateDifference(layer2.parts[partIndex].insets[layer2.parts[partIndex].insets.Count - 1]);
                        }
                    }
                }

                part.skinOutline = upskin.CreateUnion(downskin);

                double minAreaSize = (2 * Math.PI * (extrusionWidth / 1000.0) * (extrusionWidth / 1000.0)) * 0.3;
                for (int outlineIndex = 0; outlineIndex < part.skinOutline.Count; outlineIndex++)
                {
                    double area = Math.Abs(part.skinOutline[outlineIndex].Area()) / 1000.0 / 1000.0;
                    if (area < minAreaSize) // Only create an up/down skin if the area is large enough. So you do not create tiny blobs of "trying to fill"
                    {
                        part.skinOutline.RemoveAt(outlineIndex);
                        outlineIndex -= 1;
                    }
                }
            }
        }
Beispiel #5
0
        private static Polygons AddAllOutlines(SliceLayer layerToAdd, SliceLayerPart partToUseAsBounds, Polygons polysToAddTo)
        {
            Polygons polysToIntersect = new Polygons();

            for (int partIndex = 0; partIndex < layerToAdd.parts.Count; partIndex++)
            {
                if (partToUseAsBounds.BoundingBox.Hit(layerToAdd.parts[partIndex].BoundingBox))
                {
                    polysToIntersect = polysToIntersect.CreateUnion(layerToAdd.parts[partIndex].Insets[layerToAdd.parts[partIndex].Insets.Count - 1]);
                    polysToIntersect = Clipper.CleanPolygons(polysToIntersect, cleanDistance_um);
                }
            }

            polysToAddTo = polysToAddTo.CreateIntersection(polysToIntersect);

            return(polysToAddTo);
        }
        private static Polygons AddIslandsToPolygons(List <LayerIsland> islands, Aabb boundsToConsider, Polygons polysToAddTo)
        {
            Polygons polysToIntersect = new Polygons();

            for (int islandIndex = 0; islandIndex < islands.Count; islandIndex++)
            {
                if (boundsToConsider.Hit(islands[islandIndex].BoundingBox))
                {
                    polysToIntersect = polysToIntersect.CreateUnion(islands[islandIndex].InsetToolPaths[islands[islandIndex].InsetToolPaths.Count - 1]);
                    polysToIntersect = Clipper.CleanPolygons(polysToIntersect, cleanDistance_um);
                }
            }

            polysToAddTo = polysToAddTo.CreateIntersection(polysToIntersect);

            return(polysToAddTo);
        }
Beispiel #7
0
        private static List <Polygons> RemoveSupportFromInternalSpaces(List <Polygons> inputPolys, List <Polygons> allPartOutlines)
        {
            int numLayers = inputPolys.Count;

            Polygons accumulatedLayers = new Polygons();

            for (int layerIndex = 0; layerIndex < numLayers; layerIndex++)
            {
                accumulatedLayers = accumulatedLayers.CreateUnion(allPartOutlines[layerIndex]);
                accumulatedLayers = Clipper.CleanPolygons(accumulatedLayers, cleanDistance_um);

                inputPolys[layerIndex] = inputPolys[layerIndex].CreateDifference(accumulatedLayers);
                inputPolys[layerIndex] = Clipper.CleanPolygons(inputPolys[layerIndex], cleanDistance_um);
            }

            return(inputPolys);
        }
Beispiel #8
0
        private static Polygons IntersectWithSparsePolygons(List <LayerIsland> islands, Aabb boundsToConsider, Polygons polysToIntersect)
        {
            Polygons polysFromIslands = new Polygons();

            for (int islandIndex = 0; islandIndex < islands.Count; islandIndex++)
            {
                if (boundsToConsider.Hit(islands[islandIndex].BoundingBox))
                {
                    if (islands[islandIndex].InsetToolPaths.Count > 0)
                    {
                        polysFromIslands = polysFromIslands.CreateUnion(islands[islandIndex].SparseInfillPaths);
                        polysFromIslands = Clipper.CleanPolygons(polysFromIslands, cleanDistance_um);
                    }
                }
            }

            polysToIntersect = polysToIntersect.CreateIntersection(polysFromIslands);

            return(polysToIntersect);
        }
Beispiel #9
0
        public void CreateWipeShield(int totalLayers, ConfigSettings config)
        {
            if (config.WipeShieldDistanceFromShapes_um <= 0)
            {
                return;
            }

            for (int layerIndex = 0; layerIndex < totalLayers; layerIndex++)
            {
                Polygons wipeShield = new Polygons();
                for (int extruderIndex = 0; extruderIndex < this.Extruders.Count; extruderIndex++)
                {
                    for (int islandIndex = 0; islandIndex < this.Extruders[extruderIndex].Layers[layerIndex].Islands.Count; islandIndex++)
                    {
                        wipeShield = wipeShield.CreateUnion(this.Extruders[extruderIndex].Layers[layerIndex].Islands[islandIndex].IslandOutline.Offset(config.WipeShieldDistanceFromShapes_um));
                    }
                }
                this.wipeShield.Add(wipeShield);
            }

            for (int layerIndex = 0; layerIndex < totalLayers; layerIndex++)
            {
                this.wipeShield[layerIndex] = this.wipeShield[layerIndex].Offset(-1000).Offset(1000);
            }

            int offsetAngle = (int)Math.Tan(60.0 * Math.PI / 180) * config.LayerThickness_um;            //Allow for a 60deg angle in the wipeShield.

            for (int layerIndex = 1; layerIndex < totalLayers; layerIndex++)
            {
                this.wipeShield[layerIndex] = this.wipeShield[layerIndex].CreateUnion(this.wipeShield[layerIndex - 1].Offset(-offsetAngle));
            }

            for (int layerIndex = totalLayers - 1; layerIndex > 0; layerIndex--)
            {
                this.wipeShield[layerIndex - 1] = this.wipeShield[layerIndex - 1].CreateUnion(this.wipeShield[layerIndex].Offset(-offsetAngle));
            }
        }
        //Expand each layer a bit and then keep the extra overlapping parts that overlap with other extruders.
        //This generates some overlap in dual extrusion, for better bonding in touching parts.
        public static void OverlapMultipleExtrudersSlightly(List <ExtruderLayers> extruders, int overlapUm)
        {
            if (extruders.Count < 2 || overlapUm <= 0)
            {
                return;
            }

            for (int layerIndex = 0; layerIndex < extruders[0].Layers.Count; layerIndex++)
            {
                Polygons fullLayer = new Polygons();
                for (int extruderIndex = 0; extruderIndex < extruders.Count; extruderIndex++)
                {
                    SliceLayer layer1 = extruders[extruderIndex].Layers[layerIndex];
                    fullLayer = fullLayer.CreateUnion(layer1.AllOutlines.Offset(20));
                }
                fullLayer = fullLayer.Offset(-20);

                for (int extruderIndex = 0; extruderIndex < extruders.Count; extruderIndex++)
                {
                    SliceLayer layer1 = extruders[extruderIndex].Layers[layerIndex];
                    layer1.AllOutlines = fullLayer.CreateIntersection(layer1.AllOutlines.Offset(overlapUm / 2));
                }
            }
        }
Beispiel #11
0
        private static Polygons AddAllOutlines(SliceLayer layerToAdd, SliceLayerPart partToUseAsBounds, Polygons polysToAddTo, ref bool makeInfillSolid, ConfigSettings config)
        {
            Polygons polysToIntersect = new Polygons();

            for (int partIndex = 0; partIndex < layerToAdd.parts.Count; partIndex++)
            {
                var partToConsider = layerToAdd.parts[partIndex];

                if (config.smallProtrusionProportion > 0)
                {
                    // If the part under consideration intersects the part from the current layer and
                    // the area of that intersection is less than smallProtrusionProportion % of the part under consideration solidify the infill
                    var intersection = partToUseAsBounds.TotalOutline.CreateIntersection(partToConsider.TotalOutline);
                    if (intersection.Count > 0) // They do intersect
                    {
                        if (intersection.TotalArea() < partToConsider.TotalOutline.TotalArea() * config.smallProtrusionProportion)
                        {
                            makeInfillSolid = true;
                            return(polysToAddTo);
                        }
                    }
                }

                if (partToUseAsBounds.BoundingBox.Hit(partToConsider.BoundingBox))
                {
                    polysToIntersect =
                        polysToIntersect.CreateUnion(
                            layerToAdd.parts[partIndex].Insets[partToConsider.Insets.Count - 1]);
                    polysToIntersect = Clipper.CleanPolygons(polysToIntersect, cleanDistance_um);
                }
            }

            polysToAddTo = polysToAddTo.CreateIntersection(polysToIntersect);

            return(polysToAddTo);
        }
Beispiel #12
0
        private static List <Polygons> CreateInterfaceLayers(List <Polygons> inputPolys, int numInterfaceLayers)
        {
            int numLayers = inputPolys.Count;

            List <Polygons> allInterfaceLayers = CreateEmptyPolygons(numLayers);

            if (numInterfaceLayers > 0)
            {
                for (int layerIndex = 0; layerIndex < numLayers; layerIndex++)
                {
                    Polygons accumulatedAbove = inputPolys[layerIndex].DeepCopy();

                    for (int addIndex = layerIndex + 1; addIndex < Math.Min(layerIndex + numInterfaceLayers, numLayers - 2); addIndex++)
                    {
                        accumulatedAbove = accumulatedAbove.CreateUnion(inputPolys[addIndex]);
                        accumulatedAbove = Clipper.CleanPolygons(accumulatedAbove, cleanDistance_um);
                    }

                    allInterfaceLayers[layerIndex] = accumulatedAbove;
                }
            }

            return(allInterfaceLayers);
        }
Beispiel #13
0
        private static List <Polygons> AccumulateDownPolygons(ConfigSettings config, List <Polygons> inputPolys, List <Polygons> allPartOutlines)
        {
            int numLayers = inputPolys.Count;

            long nozzleSize     = config.ExtrusionWidth_um;
            long areaToTryAndBe = 20 * 20 * nozzleSize * nozzleSize;             // 10 x 10 mm approximately (assuming .5 nozzle)

            List <Polygons> allDownOutlines = CreateEmptyPolygons(numLayers);

            for (int layerIndex = numLayers - 2; layerIndex >= 0; layerIndex--)
            {
                Polygons aboveRequiredSupport = inputPolys[layerIndex + 1];

                // get all the polygons above us
                Polygons accumulatedAbove = allDownOutlines[layerIndex + 1].CreateUnion(aboveRequiredSupport);

                // experimental and not working well enough yet
                if (config.MinimizeSupportColumns)
                {
                    // reduce the amount of support material used
                    for (int i = accumulatedAbove.Count - 1; i >= 0; i--)
                    {
                        Polygon polygon  = accumulatedAbove[i];
                        double  polyArea = polygon.Area();
                        if (polyArea > areaToTryAndBe)
                        {
                            Polygons offsetPolygons = new Polygons()
                            {
                                polygon
                            }.Offset(-config.ExtrusionWidth_um / 2);
                            accumulatedAbove.RemoveAt(i);
                            foreach (Polygon polyToAdd in offsetPolygons)
                            {
                                accumulatedAbove.Insert(i, polyToAdd);
                            }
                        }
                        else if (polyArea < areaToTryAndBe * .9)
                        {
                            Polygons offsetPolygons = new Polygons()
                            {
                                polygon
                            }.Offset(config.ExtrusionWidth_um / 2);
                            accumulatedAbove.RemoveAt(i);
                            foreach (Polygon polyToAdd in offsetPolygons)
                            {
                                accumulatedAbove.Insert(i, polyToAdd);
                            }
                        }
                    }
                }

                // add in the support on this level
                Polygons curRequiredSupport = inputPolys[layerIndex];

                Polygons totalSupportThisLayer = accumulatedAbove.CreateUnion(curRequiredSupport);

                // remove the solid polygons on this level
                Polygons remainingAbove = totalSupportThisLayer.CreateDifference(allPartOutlines[layerIndex]);

                allDownOutlines[layerIndex] = Clipper.CleanPolygons(remainingAbove, cleanDistance_um);
            }

            return(allDownOutlines);
        }
Beispiel #14
0
        public static void generateSkirt(SliceDataStorage storage, int distance, int extrusionWidth_um, int numberOfLoops, int minLength, int initialLayerHeight, ConfigSettings config)
        {
            bool externalOnly = (distance > 0);

            for (int skirtLoop = 0; skirtLoop < numberOfLoops; skirtLoop++)
            {
                int offsetDistance = distance + extrusionWidth_um * skirtLoop + extrusionWidth_um / 2;

                Polygons skirtPolygons = new Polygons(storage.wipeTower.Offset(offsetDistance));
                for (int volumeIndex = 0; volumeIndex < storage.volumes.Count; volumeIndex++)
                {
                    if (config.continuousSpiralOuterPerimeter && volumeIndex > 0)
                    {
                        continue;
                    }

                    if (storage.volumes[volumeIndex].layers.Count < 1)
                    {
                        continue;
                    }

                    SliceLayer layer = storage.volumes[volumeIndex].layers[0];
                    for (int partIndex = 0; partIndex < layer.parts.Count; partIndex++)
                    {
                        if (config.continuousSpiralOuterPerimeter && partIndex > 0)
                        {
                            continue;
                        }

                        if (externalOnly)
                        {
                            Polygons p = new Polygons();
                            p.Add(layer.parts[partIndex].TotalOutline[0]);
                            //p.Add(IntPointHelper.CreateConvexHull(layer.parts[partIndex].outline[0]));
                            skirtPolygons = skirtPolygons.CreateUnion(p.Offset(offsetDistance));
                        }
                        else
                        {
                            skirtPolygons = skirtPolygons.CreateUnion(layer.parts[partIndex].TotalOutline.Offset(offsetDistance));
                        }
                    }
                }

                SupportPolyGenerator supportGenerator = new SupportPolyGenerator(storage.support, initialLayerHeight);
                skirtPolygons = skirtPolygons.CreateUnion(supportGenerator.supportPolygons.Offset(offsetDistance));

                //Remove small inner skirt holes. Holes have a negative area, remove anything smaller then 100x extrusion "area"
                for (int n = 0; n < skirtPolygons.Count; n++)
                {
                    double area = skirtPolygons[n].Area();
                    if (area < 0 && area > -extrusionWidth_um * extrusionWidth_um * 100)
                    {
                        skirtPolygons.RemoveAt(n--);
                    }
                }

                storage.skirt.AddAll(skirtPolygons);

                int lenght = (int)storage.skirt.PolygonLength();
                if (skirtLoop + 1 >= numberOfLoops && lenght > 0 && lenght < minLength)
                {
                    // add more loops for as long as we have not extruded enough length
                    numberOfLoops++;
                }
            }
        }
Beispiel #15
0
        public static void generateSparse(int layerIndex, SliceVolumeStorage storage, int extrusionWidth, int downSkinCount, int upSkinCount)
        {
            SliceLayer layer = storage.layers[layerIndex];

            for (int partNr = 0; partNr < layer.parts.Count; partNr++)
            {
                SliceLayerPart part = layer.parts[partNr];

                Polygons sparse   = part.insets[part.insets.Count - 1].Offset(-extrusionWidth / 2);
                Polygons downskin = sparse;
                Polygons upskin   = sparse;

                if ((int)(layerIndex - downSkinCount) >= 0)
                {
                    SliceLayer layer2 = storage.layers[layerIndex - downSkinCount];
                    for (int partNr2 = 0; partNr2 < layer2.parts.Count; partNr2++)
                    {
                        if (part.boundaryBox.hit(layer2.parts[partNr2].boundaryBox))
                        {
                            if (layer2.parts[partNr2].insets.Count > 1)
                            {
                                downskin = downskin.CreateDifference(layer2.parts[partNr2].insets[layer2.parts[partNr2].insets.Count - 2]);
                            }
                            else
                            {
                                downskin = downskin.CreateDifference(layer2.parts[partNr2].insets[layer2.parts[partNr2].insets.Count - 1]);
                            }
                        }
                    }
                }
                if ((int)(layerIndex + upSkinCount) < (int)storage.layers.Count)
                {
                    SliceLayer layer2 = storage.layers[layerIndex + upSkinCount];
                    for (int partNr2 = 0; partNr2 < layer2.parts.Count; partNr2++)
                    {
                        if (part.boundaryBox.hit(layer2.parts[partNr2].boundaryBox))
                        {
                            if (layer2.parts[partNr2].insets.Count > 1)
                            {
                                upskin = upskin.CreateDifference(layer2.parts[partNr2].insets[layer2.parts[partNr2].insets.Count - 2]);
                            }
                            else
                            {
                                upskin = upskin.CreateDifference(layer2.parts[partNr2].insets[layer2.parts[partNr2].insets.Count - 1]);
                            }
                        }
                    }
                }

                Polygons result = upskin.CreateUnion(downskin);

                double minAreaSize = 3.0;//(2 * M_PI * ((double)(config.extrusionWidth) / 1000.0) * ((double)(config.extrusionWidth) / 1000.0)) * 3;
                for (int i = 0; i < result.Count; i++)
                {
                    double area = Math.Abs(result[i].Area()) / 1000.0 / 1000.0;
                    if (area < minAreaSize) /* Only create an up/down skin if the area is large enough. So you do not create tiny blobs of "trying to fill" */
                    {
                        result.RemoveAt(i);
                        i -= 1;
                    }
                }

                part.sparseOutline = sparse.CreateDifference(result);
            }
        }
		//Expand each layer a bit and then keep the extra overlapping parts that overlap with other extruders.
		//This generates some overlap in dual extrusion, for better bonding in touching parts.
		public static void OverlapMultipleExtrudersSlightly(List<ExtruderLayers> extruders, int overlapUm)
		{
			if (extruders.Count < 2 || overlapUm <= 0)
			{
				return;
			}

			for (int layerIndex = 0; layerIndex < extruders[0].Layers.Count; layerIndex++)
			{
				Polygons fullLayer = new Polygons();
				for (int extruderIndex = 0; extruderIndex < extruders.Count; extruderIndex++)
				{
					SliceLayer layer1 = extruders[extruderIndex].Layers[layerIndex];
                    fullLayer = fullLayer.CreateUnion(layer1.AllOutlines.Offset(20));
				}
				fullLayer = fullLayer.Offset(-20);

				for (int extruderIndex = 0; extruderIndex < extruders.Count; extruderIndex++)
				{
					SliceLayer layer1 = extruders[extruderIndex].Layers[layerIndex];
                    layer1.AllOutlines = fullLayer.CreateIntersection(layer1.AllOutlines.Offset(overlapUm / 2));
				}
			}
		}
		public void GenerateSkirt(int distance, int extrusionWidth_um, int numberOfLoops, int minLength, int initialLayerHeight, ConfigSettings config)
		{
			LayerDataStorage storage = this;
			bool externalOnly = (distance > 0);
			for (int skirtLoop = 0; skirtLoop < numberOfLoops; skirtLoop++)
			{
				int offsetDistance = distance + extrusionWidth_um * skirtLoop + extrusionWidth_um / 2;

				Polygons skirtPolygons = new Polygons(storage.wipeTower.Offset(offsetDistance));
				for (int extrudeIndex = 0; extrudeIndex < storage.Extruders.Count; extrudeIndex++)
				{
					if (config.continuousSpiralOuterPerimeter && extrudeIndex > 0)
					{
						continue;
					}

					if (storage.Extruders[extrudeIndex].Layers.Count < 1)
					{
						continue;
					}

					SliceLayer layer = storage.Extruders[extrudeIndex].Layers[0];
					for (int partIndex = 0; partIndex < layer.Islands.Count; partIndex++)
					{
						if (config.continuousSpiralOuterPerimeter && partIndex > 0)
						{
							continue;
						}

						if (externalOnly)
						{
							Polygons p = new Polygons();
							p.Add(layer.Islands[partIndex].IslandOutline[0]);
							//p.Add(IntPointHelper.CreateConvexHull(layer.parts[partIndex].outline[0]));
							skirtPolygons = skirtPolygons.CreateUnion(p.Offset(offsetDistance));
						}
						else
						{
							skirtPolygons = skirtPolygons.CreateUnion(layer.Islands[partIndex].IslandOutline.Offset(offsetDistance));
						}
					}
				}

				if (storage.support != null)
				{
					skirtPolygons = skirtPolygons.CreateUnion(storage.support.GetBedOutlines().Offset(offsetDistance));
				}

				//Remove small inner skirt holes. Holes have a negative area, remove anything smaller then 100x extrusion "area"
				for (int n = 0; n < skirtPolygons.Count; n++)
				{
					double area = skirtPolygons[n].Area();
					if (area < 0 && area > -extrusionWidth_um * extrusionWidth_um * 100)
					{
						skirtPolygons.RemoveAt(n--);
					}
				}

				storage.skirt.AddAll(skirtPolygons);

				int lenght = (int)storage.skirt.PolygonLength();
				if (skirtLoop + 1 >= numberOfLoops && lenght > 0 && lenght < minLength)
				{
					// add more loops for as long as we have not extruded enough length
					numberOfLoops++;
				}
			}
		}
Beispiel #18
0
        public static void GenerateTopAndBottom(int layerIndex, SliceVolumeStorage storage, int extrusionWidth, ConfigSettings config)
        {
            var downLayerCount = config.numberOfBottomLayers;
            var upLayerCount   = config.numberOfTopLayers;

            SliceLayer layer = storage.layers[layerIndex];

            for (int partIndex = 0; partIndex < layer.parts.Count; partIndex++)
            {
                SliceLayerPart part            = layer.parts[partIndex];
                Polygons       insetWithOffset = part.Insets[part.Insets.Count - 1].Offset(-extrusionWidth / 2);
                Polygons       infillOutlines  = new Polygons(insetWithOffset);

                // calculate the bottom outlines
                if (downLayerCount > 0)
                {
                    Polygons bottomOutlines = new Polygons(insetWithOffset);

                    if (layerIndex - 1 >= 0)
                    {
                        bottomOutlines = RemoveAdditionalOutlinesForPart(storage.layers[layerIndex - 1], part, bottomOutlines);
                        RemoveSmallAreas(extrusionWidth, bottomOutlines);
                    }

                    infillOutlines = infillOutlines.CreateDifference(bottomOutlines);
                    infillOutlines = Clipper.CleanPolygons(infillOutlines, cleanDistance_um);

                    part.SolidBottomOutlines = bottomOutlines;
                }

                // calculate the top outlines
                if (upLayerCount > 0)
                {
                    Polygons topOutlines = new Polygons(insetWithOffset);
                    topOutlines = topOutlines.CreateDifference(part.SolidBottomOutlines);
                    topOutlines = Clipper.CleanPolygons(topOutlines, cleanDistance_um);

                    if (part.Insets.Count > 1)
                    {
                        // Add thin wall filling by taking the area between the insets.
                        Polygons thinWalls = part.Insets[0].Offset(-extrusionWidth / 2).CreateDifference(part.Insets[1].Offset(extrusionWidth / 2));
                        topOutlines.AddAll(thinWalls);
                    }

                    if (layerIndex + 1 < storage.layers.Count)
                    {
                        topOutlines = RemoveAdditionalOutlinesForPart(storage.layers[layerIndex + 1], part, topOutlines);
                        RemoveSmallAreas(extrusionWidth, topOutlines);
                    }

                    infillOutlines = infillOutlines.CreateDifference(topOutlines);
                    infillOutlines = Clipper.CleanPolygons(infillOutlines, cleanDistance_um);

                    part.SolidTopOutlines = topOutlines;
                }

                // calculate the solid infill outlines
                if (upLayerCount > 1 || downLayerCount > 1)
                {
                    var solidInfillOutlines = new Polygons(insetWithOffset);
                    solidInfillOutlines = solidInfillOutlines.CreateDifference(part.SolidBottomOutlines);
                    solidInfillOutlines = Clipper.CleanPolygons(solidInfillOutlines, cleanDistance_um);
                    solidInfillOutlines = solidInfillOutlines.CreateDifference(part.SolidTopOutlines);
                    solidInfillOutlines = Clipper.CleanPolygons(solidInfillOutlines, cleanDistance_um);

                    var upStart   = layerIndex + 2;
                    var upEnd     = layerIndex + upLayerCount + 1;
                    var downStart = layerIndex - 1;
                    var downEnd   = layerIndex - downLayerCount;

                    if (upEnd <= storage.layers.Count && downEnd >= 0)
                    {
                        var makeInfillSolid    = false;
                        var totalPartsToRemove = new Polygons(insetWithOffset);

                        for (var layerToTest = upStart; layerToTest < upEnd; layerToTest++)
                        {
                            totalPartsToRemove = AddAllOutlines(storage.layers[layerToTest], part, totalPartsToRemove, ref makeInfillSolid, config);
                            totalPartsToRemove = Clipper.CleanPolygons(totalPartsToRemove, cleanDistance_um);
                            if (makeInfillSolid)
                            {
                                break;
                            }
                        }

                        for (var layerToTest = downStart; layerToTest >= downEnd; layerToTest--)
                        {
                            totalPartsToRemove = AddAllOutlines(storage.layers[layerToTest], part, totalPartsToRemove, ref makeInfillSolid, config);
                            totalPartsToRemove = Clipper.CleanPolygons(totalPartsToRemove, cleanDistance_um);
                            if (makeInfillSolid)
                            {
                                break;
                            }
                        }

                        if (!makeInfillSolid)
                        {
                            solidInfillOutlines = solidInfillOutlines.CreateDifference(totalPartsToRemove);
                            RemoveSmallAreas(extrusionWidth, solidInfillOutlines);
                        }

                        solidInfillOutlines = Clipper.CleanPolygons(solidInfillOutlines, cleanDistance_um);
                    }

                    part.SolidInfillOutlines = solidInfillOutlines;
                    infillOutlines           = infillOutlines.CreateDifference(solidInfillOutlines);

                    Polygons totalInfillOutlines = null;
                    double   totalInfillArea     = 0.0;

                    if (config.infillSolidProportion > 0)
                    {
                        totalInfillOutlines = infillOutlines.CreateUnion(solidInfillOutlines);
                        totalInfillArea     = totalInfillOutlines.TotalArea();
                    }

                    if (config.infillSolidProportion > 0)
                    {
                        var solidInfillArea = solidInfillOutlines.TotalArea();
                        if (solidInfillArea > totalInfillArea * config.infillSolidProportion)
                        {
                            solidInfillOutlines      = solidInfillOutlines.CreateUnion(infillOutlines);
                            infillOutlines           = new Polygons();
                            part.SolidInfillOutlines = solidInfillOutlines;
                        }
                        var solidTopOutlinesArea = part.SolidTopOutlines.TotalArea();
                        if (totalInfillArea < solidTopOutlinesArea * config.infillSolidProportion / 2)
                        {
                            var totalSolidTop = totalInfillOutlines.CreateUnion(part.SolidTopOutlines);
                            part.SolidTopOutlines    = totalSolidTop;
                            part.SolidInfillOutlines = new Polygons();
                            infillOutlines           = part.InfillOutlines = new Polygons();
                        }
                        var solidBottomOutlinesArea = part.SolidBottomOutlines.TotalArea();
                        if (totalInfillArea < solidBottomOutlinesArea * config.infillSolidProportion / 2)
                        {
                            var totalSolidBottom = totalInfillOutlines.CreateUnion(part.SolidBottomOutlines);
                            part.SolidBottomOutlines = totalSolidBottom;
                            part.SolidInfillOutlines = new Polygons();
                            infillOutlines           = part.InfillOutlines = new Polygons();
                        }
                    }
                    if (config.minInfillArea_mm2 > 0)
                    {
                        var infillArea = infillOutlines.TotalArea() / 1e6; // convert from um2 to mm2
                        if (infillArea < config.minInfillArea_mm2)
                        {
                            solidInfillOutlines      = solidInfillOutlines.CreateUnion(infillOutlines);
                            infillOutlines           = new Polygons();
                            part.SolidInfillOutlines = solidInfillOutlines;
                        }
                    }
                }

                RemoveSmallAreas(extrusionWidth, infillOutlines);
                infillOutlines      = Clipper.CleanPolygons(infillOutlines, cleanDistance_um);
                part.InfillOutlines = infillOutlines;
            }
        }
Beispiel #19
0
		private static List<Polygons> RemoveSupportFromInternalSpaces(List<Polygons> inputPolys, List<Polygons> allPartOutlines)
		{
			int numLayers = inputPolys.Count;

			Polygons accumulatedLayers = new Polygons();
			for (int layerIndex = 0; layerIndex < numLayers; layerIndex++)
			{
				accumulatedLayers = accumulatedLayers.CreateUnion(allPartOutlines[layerIndex]);
				accumulatedLayers = Clipper.CleanPolygons(accumulatedLayers, cleanDistance_um);

				inputPolys[layerIndex] = inputPolys[layerIndex].CreateDifference(accumulatedLayers);
				inputPolys[layerIndex] = Clipper.CleanPolygons(inputPolys[layerIndex], cleanDistance_um);
			}

			return inputPolys;
		}
		private static Polygons AddIslandsToPolygons(List<LayerIsland> islands, Aabb boundsToConsider, Polygons polysToAddTo)
		{
			Polygons polysToIntersect = new Polygons();
			for (int islandIndex = 0; islandIndex < islands.Count; islandIndex++)
			{
				if (boundsToConsider.Hit(islands[islandIndex].BoundingBox))
				{
					polysToIntersect = polysToIntersect.CreateUnion(islands[islandIndex].InsetToolPaths[islands[islandIndex].InsetToolPaths.Count - 1]);
					polysToIntersect = Clipper.CleanPolygons(polysToIntersect, cleanDistance_um);
				}
			}

			polysToAddTo = polysToAddTo.CreateIntersection(polysToIntersect);

			return polysToAddTo;
		}
Beispiel #21
0
        private static Polygons GetSkirtBounds(ConfigSettings config, LayerDataStorage storage, bool externalOnly, int distance, int extrusionWidth_um, int brimCount)
        {
            bool hasWipeTower = storage.wipeTower.PolygonLength() > 0;

            Polygons skirtPolygons = new Polygons();

            if (config.EnableRaft)
            {
                skirtPolygons = skirtPolygons.CreateUnion(storage.raftOutline);
            }
            else
            {
                Polygons allOutlines = hasWipeTower ? new Polygons(storage.wipeTower.Offset(-extrusionWidth_um / 2)) : new Polygons();

                if (storage.wipeShield.Count > 0 &&
                    storage.wipeShield[0].Count > 0)
                {
                    allOutlines = allOutlines.CreateUnion(storage.wipeShield[0].Offset(-extrusionWidth_um / 2));
                }

                // Loop over every extruder
                for (int extrudeIndex = 0; extrudeIndex < storage.Extruders.Count; extrudeIndex++)
                {
                    // Only process the first extruder on spiral vase or
                    // skip extruders that have empty layers
                    if (config.ContinuousSpiralOuterPerimeter)
                    {
                        SliceLayer layer0 = storage.Extruders[extrudeIndex].Layers[0];
                        allOutlines.AddAll(layer0.Islands[0]?.IslandOutline);
                    }
                    else
                    {
                        // Add the layers outline to allOutlines
                        SliceLayer layer = storage.Extruders[extrudeIndex].Layers[0];
                        foreach (var island in layer.Islands)
                        {
                            if (island.IslandOutline?.Count > 0)
                            {
                                allOutlines.Add(island.IslandOutline[0]);
                            }
                        }
                    }
                }

                if (brimCount > 0)
                {
                    Polygons brimIslandOutlines = new Polygons();

                    // Grow each island by the current brim distance
                    // Union the island brims
                    brimIslandOutlines = brimIslandOutlines.CreateUnion(allOutlines);

                    if (storage.support != null)
                    {
                        brimIslandOutlines = brimIslandOutlines.CreateUnion(storage.support.GetBedOutlines());
                    }

                    brimIslandOutlines = brimIslandOutlines.Offset(extrusionWidth_um * (brimCount - 1));

                    // Loop over the requested brimCount creating and unioning a new perimeter for each island
                    List <Polygons> brimIslands = brimIslandOutlines.ProcessIntoSeparateIslands();

                    foreach (var brimIsland in brimIslands)
                    {
                        Polygons brimLoops = new Polygons();
                        for (int brimIndex = brimCount - 1; brimIndex >= 0; brimIndex--)
                        {
                            int offsetDistance = extrusionWidth_um * brimIndex;

                            // Extend the polygons to account for the brim (ensures convex hull takes this data into account)
                            brimLoops.AddAll(brimIsland.Offset(-offsetDistance + extrusionWidth_um / 2));
                        }

                        storage.Brims.Add(brimLoops);
                    }

                    // and extend the bonuds of the skirt polygons
                    skirtPolygons = skirtPolygons.CreateUnion(brimIslandOutlines);
                }

                skirtPolygons = skirtPolygons.CreateUnion(allOutlines);

                if (storage.support != null)
                {
                    skirtPolygons = skirtPolygons.CreateUnion(storage.support.GetBedOutlines());
                }
            }

            return(skirtPolygons);
        }
        private static Polygons GetSkirtBounds(ConfigSettings config, LayerDataStorage storage, bool externalOnly, int distance, int extrusionWidth_um, int brimCount)
        {
            bool hasWipeTower = storage.wipeTower.PolygonLength() > 0;

            Polygons skirtPolygons = new Polygons();

            if (config.EnableRaft)
            {
                skirtPolygons = skirtPolygons.CreateUnion(storage.raftOutline);
            }
            else
            {
                Polygons allOutlines = hasWipeTower ? new Polygons(storage.wipeTower) : new Polygons();

                // Loop over every extruder
                for (int extrudeIndex = 0; extrudeIndex < storage.Extruders.Count; extrudeIndex++)
                {
                    // Only process the first extruder on spiral vase or
                    // skip extruders that have empty layers
                    if (config.ContinuousSpiralOuterPerimeter)
                    {
                        SliceLayer layer0 = storage.Extruders[extrudeIndex].Layers[0];
                        allOutlines.AddAll(layer0.Islands[0]?.IslandOutline);
                    }
                    else
                    {
                        // Add the layers outline to allOutlines
                        SliceLayer layer = storage.Extruders[extrudeIndex].Layers[0];
                        foreach (var island in layer.Islands)
                        {
                            if (island.IslandOutline?.Count > 0)
                            {
                                allOutlines.Add(island.IslandOutline[0]);
                            }
                        }
                    }
                }

                if (brimCount > 0)
                {
                    Polygons unionedIslandOutlines = new Polygons();

                    // Grow each island by the current brim distance
                    // Union the island brims
                    unionedIslandOutlines = unionedIslandOutlines.CreateUnion(allOutlines);

                    if (storage.support != null)
                    {
                        unionedIslandOutlines = unionedIslandOutlines.CreateUnion(storage.support.GetBedOutlines());
                    }

                    Polygons brimLoops = new Polygons();

                    // Loop over the requested brimCount creating and unioning a new perimeter for each island
                    for (int brimIndex = 0; brimIndex < brimCount; brimIndex++)
                    {
                        int offsetDistance = extrusionWidth_um * brimIndex + extrusionWidth_um / 2;

                        // Extend the polygons to account for the brim (ensures convex hull takes this data into account)
                        brimLoops.AddAll(unionedIslandOutlines.Offset(offsetDistance));
                    }

                    // TODO: This is a quick hack, reuse the skirt data to stuff in the brim. Good enough from proof of concept
                    storage.skirt.AddAll(brimLoops);

                    skirtPolygons = skirtPolygons.CreateUnion(brimLoops);
                }
                else
                {
                    skirtPolygons = skirtPolygons.CreateUnion(allOutlines);
                }

                if (storage.support != null)
                {
                    skirtPolygons = skirtPolygons.CreateUnion(storage.support.GetBedOutlines());
                }
            }

            return(skirtPolygons);
        }
Beispiel #23
0
		private void CreateWipeShields(LayerDataStorage slicingData, int totalLayers)
		{
			for (int layerNr = 0; layerNr < totalLayers; layerNr++)
			{
				Polygons wipeShield = new Polygons();
				for (int extruderIndex = 0; extruderIndex < slicingData.Extruders.Count; extruderIndex++)
				{
					for (int partNr = 0; partNr < slicingData.Extruders[extruderIndex].Layers[layerNr].Islands.Count; partNr++)
					{
						wipeShield = wipeShield.CreateUnion(slicingData.Extruders[extruderIndex].Layers[layerNr].Islands[partNr].IslandOutline.Offset(config.wipeShieldDistanceFromShapes_um));
					}
				}
				slicingData.wipeShield.Add(wipeShield);
			}

			for (int layerIndex = 0; layerIndex < totalLayers; layerIndex++)
			{
				slicingData.wipeShield[layerIndex] = slicingData.wipeShield[layerIndex].Offset(-1000).Offset(1000);
			}

			int offsetAngle = (int)Math.Tan(60.0 * Math.PI / 180) * config.layerThickness_um;//Allow for a 60deg angle in the wipeShield.
			for (int layerNr = 1; layerNr < totalLayers; layerNr++)
			{
				slicingData.wipeShield[layerNr] = slicingData.wipeShield[layerNr].CreateUnion(slicingData.wipeShield[layerNr - 1].Offset(-offsetAngle));
			}

			for (int layerNr = totalLayers - 1; layerNr > 0; layerNr--)
			{
				slicingData.wipeShield[layerNr - 1] = slicingData.wipeShield[layerNr - 1].CreateUnion(slicingData.wipeShield[layerNr].Offset(-offsetAngle));
			}
		}