Exemple #1
0
        private static void DoLayerBooleans(SliceLayer layersA, SliceLayer layersB, BooleanType booleanType)
        {
            switch (booleanType)
            {
            case BooleanType.Union:
                if (layersB.AllOutlines.Count == 0)
                {
                    // do nothing we will keep the content of A
                }
                else if (layersA.AllOutlines.Count == 0)
                {
                    // there is nothing in A so set it to the content of B
                    layersA.AllOutlines = layersB.AllOutlines;
                }
                else
                {
                    layersA.AllOutlines = layersA.AllOutlines.CreateUnion(layersB.AllOutlines);
                }

                break;

            case BooleanType.Difference:
                layersA.AllOutlines = layersA.AllOutlines.CreateDifference(layersB.AllOutlines);
                break;

            case BooleanType.Intersection:
                layersA.AllOutlines = layersA.AllOutlines.CreateIntersection(layersB.AllOutlines);
                break;
            }
        }
        //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].TotalOutline.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].TotalOutline = fullLayer.CreateIntersection(layer1.parts[partIndex].TotalOutline.Offset(overlap / 2));
                    }
                }
            }
        }
Exemple #3
0
        private static void DoLayerBooleans(SliceLayer layersA, SliceLayer layersB, BooleanType booleanType)
        {
            switch (booleanType)
            {
            case BooleanType.Union:
                if (layersB.AllOutlines.Count == 0)
                {
                    // do nothing we will keep the content of A
                }
                else if (layersA.AllOutlines.Count == 0)
                {
                    // there is nothing in A so set it to the content of B
                    layersA.AllOutlines = layersB.AllOutlines;
                }
                else
                {
                    layersA.AllOutlines = layersA.AllOutlines.CreateUnion(layersB.AllOutlines);
                    // remove tiny gaps between parts
                    // first grow the outlines so they will combine if very close together
                    layersA.AllOutlines = layersA.AllOutlines.Offset(20);
                    // then shrink them back down so they are the same size as when we started
                    layersA.AllOutlines = layersA.AllOutlines.Offset(-20);
                }

                break;

            case BooleanType.Difference:
                layersA.AllOutlines = layersA.AllOutlines.CreateDifference(layersB.AllOutlines);
                break;

            case BooleanType.Intersection:
                layersA.AllOutlines = layersA.AllOutlines.CreateIntersection(layersB.AllOutlines);
                break;
            }
        }
Exemple #4
0
        public void GenerateInsets(ConfigSettings config, long extrusionWidth_um, long outerExtrusionWidth_um, int insetCount)
        {
            var expandThinWalls         = config.ExpandThinWalls && !config.ContinuousSpiralOuterPerimeter;
            var avoidCrossingPerimeters = config.AvoidCrossingPerimeters;

            SliceLayer layer = this;

            for (int islandIndex = 0; islandIndex < layer.Islands.Count; islandIndex++)
            {
                layer.Islands[islandIndex].GenerateInsets(config, extrusionWidth_um, outerExtrusionWidth_um, insetCount, avoidCrossingPerimeters);
            }

            if (!expandThinWalls)
            {
                // Remove the parts which did not generate an inset. As these parts are too small to print,
                // and later code can now assume that there is always minimum 1 inset line.
                for (int islandIndex = 0; islandIndex < layer.Islands.Count; islandIndex++)
                {
                    if (layer.Islands[islandIndex].InsetToolPaths.Count < 1)
                    {
                        layer.Islands.RemoveAt(islandIndex);
                        islandIndex -= 1;
                    }
                }
            }
        }
Exemple #5
0
        public static void GenerateRaftOutlines(SliceDataStorage storage, int extraDistanceAroundPart_um)
        {
            for (int volumeIdx = 0; volumeIdx < storage.volumes.Count; volumeIdx++)
            {
                if (storage.volumes[volumeIdx].layers.Count < 1)
                {
                    continue;
                }

                SliceLayer layer = storage.volumes[volumeIdx].layers[0];
                // let's find the first layer that has something in it for the raft rather than a zero layer
                if (layer.parts.Count == 0 && storage.volumes[volumeIdx].layers.Count > 2)
                {
                    layer = storage.volumes[volumeIdx].layers[1];
                }
                for (int i = 0; i < layer.parts.Count; i++)
                {
                    storage.raftOutline = storage.raftOutline.CreateUnion(layer.parts[i].outline.Offset(extraDistanceAroundPart_um));
                }
            }

            SupportPolyGenerator supportGenerator = new SupportPolyGenerator(storage.support, 0);

            storage.raftOutline = storage.raftOutline.CreateUnion(storage.wipeTower.Offset(extraDistanceAroundPart_um));
            storage.raftOutline = storage.raftOutline.CreateUnion(supportGenerator.supportPolygons.Offset(extraDistanceAroundPart_um));
        }
Exemple #6
0
        // 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));
                }
            }
        }
Exemple #7
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;
                    }
                }
            }
        }
Exemple #8
0
        public static void generateSkirt(SliceDataStorage storage, int distance, int extrusionWidth_um, int numberOfLoops, int minLength, int initialLayerHeight)
        {
            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 (storage.volumes[volumeIndex].layers.Count < 1)
                    {
                        continue;
                    }

                    SliceLayer layer = storage.volumes[volumeIndex].layers[0];
                    for (int i = 0; i < layer.parts.Count; i++)
                    {
                        if (externalOnly)
                        {
                            Polygons p = new Polygons();
                            p.Add(layer.parts[i].outline[0]);
                            skirtPolygons = skirtPolygons.CreateUnion(p.Offset(offsetDistance));
                        }
                        else
                        {
                            skirtPolygons = skirtPolygons.CreateUnion(layer.parts[i].outline.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++;
                }
            }
        }
Exemple #9
0
        private static Polygons RemoveAdditionalOutlinesForPart(SliceLayer layerToSubtract, SliceLayerPart partToUseAsBounds, Polygons polygonsToSubtractFrom)
        {
            for (int partIndex = 0; partIndex < layerToSubtract.parts.Count; partIndex++)
            {
                if (partToUseAsBounds.BoundingBox.Hit(layerToSubtract.parts[partIndex].BoundingBox))
                {
                    polygonsToSubtractFrom = polygonsToSubtractFrom.CreateDifference(layerToSubtract.parts[partIndex].Insets[layerToSubtract.parts[partIndex].Insets.Count - 1]);

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

            return(polygonsToSubtractFrom);
        }
 public static void RemoveExtruderIntersections(List <ExtruderLayers> extruders)
 {
     //Go trough all the extruders, and remove the previous extruders outlines from our own outline, so we never have overlapped areas.
     for (int extruderIndex = extruders.Count - 1; extruderIndex >= 0; extruderIndex--)
     {
         for (int otherExtuderIndex = extruderIndex - 1; otherExtuderIndex >= 0; otherExtuderIndex--)
         {
             for (int layerIndex = 0; layerIndex < extruders[extruderIndex].Layers.Count; layerIndex++)
             {
                 SliceLayer layerToRemoveFrom = extruders[extruderIndex].Layers[layerIndex];
                 SliceLayer layerToRemove     = extruders[otherExtuderIndex].Layers[layerIndex];
                 layerToRemoveFrom.AllOutlines = layerToRemoveFrom.AllOutlines.CreateDifference(layerToRemove.AllOutlines);
             }
         }
     }
 }
        public void GenerateRaftOutlines(long extraDistanceAroundPart_um, ConfigSettings config)
        {
            LayerDataStorage storage = this;

            for (int extruderIndex = 0; extruderIndex < storage.Extruders.Count; extruderIndex++)
            {
                if (config.ContinuousSpiralOuterPerimeter && extruderIndex > 0)
                {
                    continue;
                }

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

                SliceLayer layer = storage.Extruders[extruderIndex].Layers[0];
                // let's find the first layer that has something in it for the raft rather than a zero layer
                if (layer.Islands.Count == 0 && storage.Extruders[extruderIndex].Layers.Count > 2)
                {
                    layer = storage.Extruders[extruderIndex].Layers[1];
                }

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

                    storage.raftOutline = storage.raftOutline.CreateUnion(layer.Islands[partIndex].IslandOutline.Offset(extraDistanceAroundPart_um));
                }
            }

            storage.raftOutline = storage.raftOutline.CreateUnion(storage.WipeLayer(0).Offset(extraDistanceAroundPart_um));

            if (storage.WipeShield.Count > 0 &&
                storage.WipeShield[0].Count > 0)
            {
                storage.raftOutline = storage.raftOutline.CreateUnion(storage.WipeShield[0].Offset(extraDistanceAroundPart_um));
            }

            if (storage.Support != null)
            {
                storage.raftOutline = storage.raftOutline.CreateUnion(storage.Support.GetBedOutlines().Offset(extraDistanceAroundPart_um));
            }
        }
Exemple #12
0
        private static void WriteDebugData(Polygons areaAboveToFill, SliceLayer layerToRestOn, Polygons islandsToRestOn)
        {
            // string outlineString = areaAboveToFill.WriteToString();
            string islandOutlineString = "";

            foreach (LayerIsland prevLayerIsland in layerToRestOn.Islands)
            {
                foreach (Polygon islandOutline in prevLayerIsland.IslandOutline)
                {
                    islandOutlineString += islandOutline.WriteToString();
                }

                islandOutlineString += "|";
            }

            // string islandsString = islandsToRestOn.WriteToString();
        }
Exemple #13
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);
        }
        public void CalculateInfillData(ConfigSettings config,
                                        int extruderIndex,
                                        int layerIndex,
                                        LayerIsland part,
                                        Polygons bottomFillLines,
                                        Polygons sparseFillPolygons   = null,
                                        Polygons solidFillPolygons    = null,
                                        Polygons firstTopFillPolygons = null,
                                        Polygons topFillPolygons      = null,
                                        Polygons bridgePolygons       = null,
                                        Polygons bridgeAreas          = null)
        {
            double alternatingInfillAngle = config.InfillStartingAngle;

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

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

                        if (bridgePolygons != null &&
                            previousLayer.BridgeAngle(bottomFillIsland, config.GetNumberOfPerimeters() * config.ExtrusionWidth_um, out double bridgeAngle, bridgeAreas))
                        {
                            // TODO: Make this code handle very complex pathing between different sizes or layouts of support under the island to fill.
                            Infill.GenerateLinePaths(bottomFillIsland, bridgePolygons, config.ExtrusionWidth_um, config.InfillExtendIntoPerimeter_um, bridgeAngle);
                        }
                        else                         // we still need to extrude at bridging speed
                        {
                            Infill.GenerateLinePaths(bottomFillIsland, bottomFillLines, config.ExtrusionWidth_um, config.InfillExtendIntoPerimeter_um, alternatingInfillAngle, 0, config.BridgeSpeed);
                        }
                    }
                }
Exemple #15
0
        public static void generateInsets(SliceLayer layer, int offset, int insetCount)
        {
            for (int partIndex = 0; partIndex < layer.parts.Count; partIndex++)
            {
                GenerateInsets(layer.parts[partIndex], offset, insetCount);
            }

            //Remove the parts which did not generate an inset. As these parts are too small to print,
            // and later code can now assume that there is always minimum 1 inset line.
            for (int partIndex = 0; partIndex < layer.parts.Count; partIndex++)
            {
                if (layer.parts[partIndex].Insets.Count < 1)
                {
                    layer.parts.RemoveAt(partIndex);
                    partIndex -= 1;
                }
            }
        }
Exemple #16
0
        public static void generateInsets(SliceLayer layer, int offset, int insetCount)
        {
            for (int partIndex = 0; partIndex < layer.parts.Count; partIndex++)
            {
                GenerateInsets(layer.parts[partIndex], offset, insetCount);
            }

            //Remove the parts which did not generate an inset. As these parts are too small to print,
            // and later code can now assume that there is always minimum 1 inset line.
            for (int partIndex = 0; partIndex < layer.parts.Count; partIndex++)
            {
                if (layer.parts[partIndex].Insets.Count < 1)
                {
                    layer.parts.RemoveAt(partIndex);
                    partIndex -= 1;
                }
            }
        }
        public void DumpLayerparts(string filename)
        {
            var streamToWriteTo = new StreamWriter(filename);

            streamToWriteTo.Write("<!DOCTYPE html><html><body>");

            for (int extruderIndex = 0; extruderIndex < this.Extruders.Count; extruderIndex++)
            {
                for (int layerNr = 0; layerNr < this.Extruders[extruderIndex].Layers.Count; layerNr++)
                {
                    streamToWriteTo.Write("<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" style=\"width: 500px; height:500px\">\n");
                    SliceLayer layer = this.Extruders[extruderIndex].Layers[layerNr];
                    for (int i = 0; i < layer.Islands.Count; i++)
                    {
                        LayerIsland part = layer.Islands[i];
                        for (int j = 0; j < part.IslandOutline.Count; j++)
                        {
                            streamToWriteTo.Write("<polygon points=\"");

                            for (int k = 0; k < part.IslandOutline[j].Count; k++)
                            {
                                streamToWriteTo.Write("{0},{1} ".FormatWith((float)(part.IslandOutline[j][k].X - modelMin.X) / modelSize.X * 500, (float)(part.IslandOutline[j][k].Y - modelMin.Y) / modelSize.Y * 500));
                            }

                            if (j == 0)
                            {
                                streamToWriteTo.Write("\" style=\"fill:gray; stroke:black;stroke-width:1\" />\n");
                            }
                            else
                            {
                                streamToWriteTo.Write("\" style=\"fill:red; stroke:black;stroke-width:1\" />\n");
                            }
                        }
                    }

                    streamToWriteTo.Write("</svg>\n");
                }
            }

            streamToWriteTo.Write("</body></html>");
            streamToWriteTo.Close();
        }
Exemple #18
0
        public void GenerateInsets(int extrusionWidth_um, int outerExtrusionWidth_um, int insetCount)
        {
            SliceLayer layer = this;

            for (int islandIndex = 0; islandIndex < layer.Islands.Count; islandIndex++)
            {
                layer.Islands[islandIndex].GenerateInsets(extrusionWidth_um, outerExtrusionWidth_um, insetCount);
            }

            //Remove the parts which did not generate an inset. As these parts are too small to print,
            // and later code can now assume that there is always minimum 1 inset line.
            for (int islandIndex = 0; islandIndex < layer.Islands.Count; islandIndex++)
            {
                if (layer.Islands[islandIndex].InsetToolPaths.Count < 1)
                {
                    layer.Islands.RemoveAt(islandIndex);
                    islandIndex -= 1;
                }
            }
        }
Exemple #19
0
        public static void GenerateRaftOutlines(SliceDataStorage storage, int extraDistanceAroundPart_um)
        {
            for (int volumeIdx = 0; volumeIdx < storage.volumes.Count; volumeIdx++)
            {
                if (storage.volumes[volumeIdx].layers.Count < 1)
                {
                    continue;
                }

                SliceLayer layer = storage.volumes[volumeIdx].layers[0];
                for (int i = 0; i < layer.parts.Count; i++)
                {
                    storage.raftOutline = storage.raftOutline.CreateUnion(layer.parts[i].outline.Offset(extraDistanceAroundPart_um));
                }
            }

            SupportPolyGenerator supportGenerator = new SupportPolyGenerator(storage.support, 0);

            storage.raftOutline = storage.raftOutline.CreateUnion(storage.wipeTower.Offset(extraDistanceAroundPart_um));
            storage.raftOutline = storage.raftOutline.CreateUnion(supportGenerator.supportPolygons.Offset(extraDistanceAroundPart_um));
        }
Exemple #20
0
        public static void dumpLayerparts(SliceDataStorage storage, string filename)
        {
            StreamWriter streamToWriteTo = new StreamWriter(filename);

            streamToWriteTo.Write("<!DOCTYPE html><html><body>");
            Point3 modelSize = storage.modelSize;
            Point3 modelMin  = storage.modelMin;

            for (int volumeIdx = 0; volumeIdx < storage.volumes.Count; volumeIdx++)
            {
                for (int layerNr = 0; layerNr < storage.volumes[volumeIdx].layers.Count; layerNr++)
                {
                    streamToWriteTo.Write("<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" style=\"width: 500px; height:500px\">\n");
                    SliceLayer layer = storage.volumes[volumeIdx].layers[layerNr];
                    for (int i = 0; i < layer.parts.Count; i++)
                    {
                        SliceLayerPart part = layer.parts[i];
                        for (int j = 0; j < part.outline.Count; j++)
                        {
                            streamToWriteTo.Write("<polygon points=\"");
                            for (int k = 0; k < part.outline[j].Count; k++)
                            {
                                streamToWriteTo.Write("{0},{1} ".FormatWith((float)(part.outline[j][k].X - modelMin.x) / modelSize.x * 500, (float)(part.outline[j][k].Y - modelMin.y) / modelSize.y * 500));
                            }
                            if (j == 0)
                            {
                                streamToWriteTo.Write("\" style=\"fill:gray; stroke:black;stroke-width:1\" />\n");
                            }
                            else
                            {
                                streamToWriteTo.Write("\" style=\"fill:red; stroke:black;stroke-width:1\" />\n");
                            }
                        }
                    }
                    streamToWriteTo.Write("</svg>\n");
                }
            }
            streamToWriteTo.Write("</body></html>");
            streamToWriteTo.Close();
        }
Exemple #21
0
        /*
         * The layer-part creation step is the first step in creating actual useful data for 3D printing.
         * It takes the result of the Slice step, which is an unordered list of polygons, and makes groups of polygons,
         * each of these groups is called a "part", which sometimes are also known as "islands". These parts represent
         * isolated areas in the 2D layer with possible holes.
         *
         * Creating "parts" is an important step, as all elements in a single part should be printed before going to another part.
         * Every bit inside a single part can be printed without the nozzle leaving the boundery of this part.
         *
         * It's also the first step that stores the result in the "data storage" so all other steps can access it.
         */


        static void createLayerWithParts(SliceLayer storageLayer, SlicerLayer layer, ConfigConstants.REPAIR_OVERLAPS unionAllType)
        {
            if ((unionAllType & ConfigConstants.REPAIR_OVERLAPS.REVERSE_ORIENTATION) == ConfigConstants.REPAIR_OVERLAPS.REVERSE_ORIENTATION)
            {
                for (int i = 0; i < layer.polygonList.Count; i++)
                {
                    if (layer.polygonList[i].Orientation())
                    {
                        layer.polygonList[i].Reverse();
                    }
                }
            }

            List <Polygons> result;

            if ((unionAllType & ConfigConstants.REPAIR_OVERLAPS.UNION_ALL_TOGETHER) == ConfigConstants.REPAIR_OVERLAPS.UNION_ALL_TOGETHER)
            {
                result = layer.polygonList.Offset(1000).SplitIntoParts(unionAllType != 0);
            }
            else
            {
                result = layer.polygonList.SplitIntoParts(unionAllType != 0);
            }

            for (int i = 0; i < result.Count; i++)
            {
                storageLayer.parts.Add(new SliceLayerPart());
                if ((unionAllType & ConfigConstants.REPAIR_OVERLAPS.UNION_ALL_TOGETHER) == ConfigConstants.REPAIR_OVERLAPS.UNION_ALL_TOGETHER)
                {
                    storageLayer.parts[i].outline.Add(result[i][0]);
                    storageLayer.parts[i].outline = storageLayer.parts[i].outline.Offset(-1000);
                }
                else
                {
                    storageLayer.parts[i].outline = result[i];
                }

                storageLayer.parts[i].boundaryBox.calculate(storageLayer.parts[i].outline);
            }
        }
Exemple #22
0
        /*
         * The layer-part creation step is the first step in creating actual useful data for 3D printing.
         * It takes the result of the Slice step, which is an unordered list of polygons, and makes groups of polygons,
         * each of these groups is called a "part", which sometimes are also known as "islands". These parts represent
         * isolated areas in the 2D layer with possible holes.
         *
         * Creating "parts" is an important step, as all elements in a single part should be printed before going to another part.
         * Every bit inside a single part can be printed without the nozzle leaving the boundery of this part.
         *
         * It's also the first step that stores the result in the "data storage" so all other steps can access it.
         */

        private static void CreateLayerWithParts(SliceLayer storageLayer, SlicerLayer layer, ConfigConstants.REPAIR_OVERLAPS unionAllType)
        {
            if ((unionAllType & ConfigConstants.REPAIR_OVERLAPS.REVERSE_ORIENTATION) == ConfigConstants.REPAIR_OVERLAPS.REVERSE_ORIENTATION)
            {
                for (int i = 0; i < layer.PolygonList.Count; i++)
                {
                    if (layer.PolygonList[i].Orientation())
                    {
                        layer.PolygonList[i].Reverse();
                    }
                }
            }

            List <Polygons> result;

            if ((unionAllType & ConfigConstants.REPAIR_OVERLAPS.UNION_ALL_TOGETHER) == ConfigConstants.REPAIR_OVERLAPS.UNION_ALL_TOGETHER)
            {
                result = layer.PolygonList.Offset(1000).CreateLayerOutlines(PolygonsHelper.LayerOpperation.UnionAll);
            }
            else
            {
                result = layer.PolygonList.CreateLayerOutlines(PolygonsHelper.LayerOpperation.EvenOdd);
            }

            for (int i = 0; i < result.Count; i++)
            {
                storageLayer.parts.Add(new SliceLayerPart());
                if ((unionAllType & ConfigConstants.REPAIR_OVERLAPS.UNION_ALL_TOGETHER) == ConfigConstants.REPAIR_OVERLAPS.UNION_ALL_TOGETHER)
                {
                    storageLayer.parts[i].TotalOutline.Add(result[i][0]);
                    storageLayer.parts[i].TotalOutline = storageLayer.parts[i].TotalOutline.Offset(-1000);
                }
                else
                {
                    storageLayer.parts[i].TotalOutline = result[i];
                }

                storageLayer.parts[i].BoundingBox.Calculate(storageLayer.parts[i].TotalOutline);
            }
        }
 public static void RemoveVolumesIntersections(List <SliceVolumeStorage> volumes)
 {
     //Go trough all the volumes, and remove the previous volume outlines from our own outline, so we never have overlapped areas.
     for (int volumeToRemoveFromIndex = volumes.Count - 1; volumeToRemoveFromIndex >= 0; volumeToRemoveFromIndex--)
     {
         for (int volumeToRemoveIndex = volumeToRemoveFromIndex - 1; volumeToRemoveIndex >= 0; volumeToRemoveIndex--)
         {
             for (int layerIndex = 0; layerIndex < volumes[volumeToRemoveFromIndex].layers.Count; layerIndex++)
             {
                 SliceLayer layerToRemoveFrom = volumes[volumeToRemoveFromIndex].layers[layerIndex];
                 SliceLayer layerToRemove     = volumes[volumeToRemoveIndex].layers[layerIndex];
                 for (int partToRemoveFromIndex = 0; partToRemoveFromIndex < layerToRemoveFrom.parts.Count; partToRemoveFromIndex++)
                 {
                     for (int partToRemove = 0; partToRemove < layerToRemove.parts.Count; partToRemove++)
                     {
                         layerToRemoveFrom.parts[partToRemoveFromIndex].TotalOutline = layerToRemoveFrom.parts[partToRemoveFromIndex].TotalOutline.CreateDifference(layerToRemove.parts[partToRemove].TotalOutline);
                     }
                 }
             }
         }
     }
 }
 public static void carveMultipleVolumes(List <SliceVolumeStorage> volumes)
 {
     //Go trough all the volumes, and remove the previous volume outlines from our own outline, so we never have overlapped areas.
     for (int idx = 0; idx < volumes.Count; idx++)
     {
         for (int idx2 = 0; idx2 < idx; idx2++)
         {
             for (int layerNr = 0; layerNr < volumes[idx].layers.Count; layerNr++)
             {
                 SliceLayer layer1 = volumes[idx].layers[layerNr];
                 SliceLayer layer2 = volumes[idx2].layers[layerNr];
                 for (int p1 = 0; p1 < layer1.parts.Count; p1++)
                 {
                     for (int p2 = 0; p2 < layer2.parts.Count; p2++)
                     {
                         layer1.parts[p1].outline = layer1.parts[p1].outline.CreateDifference(layer2.parts[p2].outline);
                     }
                 }
             }
         }
     }
 }
Exemple #25
0
        public static void RemoveExtruderIntersections(List <ExtruderLayers> extruders, ConfigSettings config)
        {
            var start = extruders.Count - 1;

            if (config.BooleanOperations.Contains("F"))
            {
                start--;
            }

            // Go trough all the extruders, and remove the previous extruders outlines from our own outline, so we never have overlapped areas.
            for (int extruderIndex = start; extruderIndex >= 0; extruderIndex--)
            {
                for (int otherExtruderIndex = extruderIndex - 1; otherExtruderIndex >= 0; otherExtruderIndex--)
                {
                    for (int layerIndex = 0; layerIndex < extruders[extruderIndex].Layers.Count; layerIndex++)
                    {
                        SliceLayer layerToRemoveFrom = extruders[extruderIndex].Layers[layerIndex];
                        SliceLayer layerToRemove     = extruders[otherExtruderIndex].Layers[layerIndex];
                        layerToRemoveFrom.AllOutlines = layerToRemoveFrom.AllOutlines.CreateDifference(layerToRemove.AllOutlines);
                    }
                }
            }
        }
Exemple #26
0
        public void GenerateInsets(long extrusionWidth_um, long outerExtrusionWidth_um, int insetCount, bool expandThinWalls, bool avoidCrossingPerimeters)
        {
            SliceLayer layer = this;

            for (int islandIndex = 0; islandIndex < layer.Islands.Count; islandIndex++)
            {
                layer.Islands[islandIndex].GenerateInsets(extrusionWidth_um, outerExtrusionWidth_um, insetCount, avoidCrossingPerimeters);
            }

            if (!expandThinWalls)
            {
                //Remove the parts which did not generate an inset. As these parts are too small to print,
                // and later code can now assume that there is always minimum 1 inset line.
                for (int islandIndex = 0; islandIndex < layer.Islands.Count; islandIndex++)
                {
                    if (layer.Islands[islandIndex].InsetToolPaths.Count < 1)
                    {
                        layer.Islands.RemoveAt(islandIndex);
                        islandIndex -= 1;
                    }
                }
            }
        }
Exemple #27
0
        public static void GenerateRaftOutlines(SliceDataStorage storage, int extraDistanceAroundPart_um, ConfigSettings config)
        {
            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];
                // let's find the first layer that has something in it for the raft rather than a zero layer
                if (layer.parts.Count == 0 && storage.volumes[volumeIndex].layers.Count > 2)
                {
                    layer = storage.volumes[volumeIndex].layers[1];
                }
                for (int partIndex = 0; partIndex < layer.parts.Count; partIndex++)
                {
                    if (config.continuousSpiralOuterPerimeter && partIndex > 0)
                    {
                        continue;
                    }

                    storage.raftOutline = storage.raftOutline.CreateUnion(layer.parts[partIndex].TotalOutline.Offset(extraDistanceAroundPart_um));
                }
            }

            SupportPolyGenerator supportGenerator = new SupportPolyGenerator(storage.support, 0);

            storage.raftOutline = storage.raftOutline.CreateUnion(storage.wipeTower.Offset(extraDistanceAroundPart_um));
            storage.raftOutline = storage.raftOutline.CreateUnion(supportGenerator.supportPolygons.Offset(extraDistanceAroundPart_um));
        }
Exemple #28
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);
        }
Exemple #29
0
        public static bool BridgeAngle(Polygons outline, SliceLayer prevLayer, out double bridgeAngle, string debugName = "")
        {
            bridgeAngle = -1;
            Aabb boundaryBox = new Aabb(outline);
            //To detect if we have a bridge, first calculate the intersection of the current layer with the previous layer.
            // This gives us the islands that the layer rests on.
            Polygons islands = new Polygons();
            foreach (SliceLayerPart prevLayerPart in prevLayer.parts)
            {
                if (!boundaryBox.Hit(prevLayerPart.BoundingBox))
                {
                    continue;
                }

                islands.AddRange(outline.CreateIntersection(prevLayerPart.TotalOutline));
            }

            #if OUTPUT_DEBUG_DATA
            string outlineString = outline.WriteToString();
            string partOutlineString = "";
            foreach (SliceLayerPart prevLayerPart in prevLayer.parts)
            {
                foreach (Polygon prevPartOutline in prevLayerPart.outline)
                {
                    partOutlineString += prevPartOutline.WriteToString();
                }

                partOutlineString += "|";
            }

            string islandsString = islands.WriteToString();
            #endif

            if (islands.Count > 5 || islands.Count < 1)
            {
                return false;
            }

            if (islands.Count == 1)
            {
                return GetSingleIslandAngle(outline, islands[0], out bridgeAngle, debugName);
            }

            // Find the 2 largest islands that we rest on.
            double biggestArea = 0;
            double nextBiggestArea = 0;
            int indexOfBiggest = -1;
            int indexOfNextBigest = -1;
            for (int islandIndex = 0; islandIndex < islands.Count; islandIndex++)
            {
                //Skip internal holes
                if (!islands[islandIndex].Orientation())
                {
                    continue;
                }

                double area = Math.Abs(islands[islandIndex].Area());
                if (area > biggestArea)
                {
                    if (biggestArea > nextBiggestArea)
                    {
                        nextBiggestArea = biggestArea;
                        indexOfNextBigest = indexOfBiggest;
                    }
                    biggestArea = area;
                    indexOfBiggest = islandIndex;
                }
                else if (area > nextBiggestArea)
                {
                    nextBiggestArea = area;
                    indexOfNextBigest = islandIndex;
                }
            }

            if (indexOfBiggest < 0 || indexOfNextBigest < 0)
            {
                return false;
            }

            IntPoint center1 = islands[indexOfBiggest].CenterOfMass();
            IntPoint center2 = islands[indexOfNextBigest].CenterOfMass();

            bridgeAngle = Math.Atan2(center2.Y - center1.Y, center2.X - center1.X) / Math.PI * 180;
            Range0To360(ref bridgeAngle);
            #if OUTPUT_DEBUG_DATA
            islands.SaveToGCode("{0} - angle {1:0.}.gcode".FormatWith(debugName, bridgeAngle));
            #endif
            return true;
        }
        private static Polygons RemoveAdditionalOutlinesForPart(SliceLayer layerToSubtract, SliceLayerPart partToUseAsBounds, Polygons polygonsToSubtractFrom)
        {
            for (int partIndex = 0; partIndex < layerToSubtract.parts.Count; partIndex++)
            {
                if (partToUseAsBounds.BoundingBox.Hit(layerToSubtract.parts[partIndex].BoundingBox))
                {
                    polygonsToSubtractFrom = polygonsToSubtractFrom.CreateDifference(layerToSubtract.parts[partIndex].Insets[layerToSubtract.parts[partIndex].Insets.Count - 1]);

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

            return polygonsToSubtractFrom;
        }
        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;
        }
		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);
			}
		}
        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 void DoLayerBooleans(SliceLayer layersA, SliceLayer layersB, BooleanType booleanType)
 {
     switch (booleanType)
     {
         case BooleanType.Union:
             if (layersB.AllOutlines.Count == 0)
             {
                 // do nothing we will keep the content of A
             }
             else if (layersA.AllOutlines.Count == 0)
             {
                 // there is nothing in A so set it to the content of B
                 layersA.AllOutlines = layersB.AllOutlines;
             }
             else
             {
                 layersA.AllOutlines = layersA.AllOutlines.CreateUnion(layersB.AllOutlines);
             }
             break;
         case BooleanType.Difference:
             layersA.AllOutlines = layersA.AllOutlines.CreateDifference(layersB.AllOutlines);
             break;
         case BooleanType.Intersection:
             layersA.AllOutlines = layersA.AllOutlines.CreateIntersection(layersB.AllOutlines);
             break;
     }
 }
Exemple #35
0
        /*
        The layer-part creation step is the first step in creating actual useful data for 3D printing.
        It takes the result of the Slice step, which is an unordered list of polygons, and makes groups of polygons,
        each of these groups is called a "part", which sometimes are also known as "islands". These parts represent
        isolated areas in the 2D layer with possible holes.

        Creating "parts" is an important step, as all elements in a single part should be printed before going to another part.
        Every bit inside a single part can be printed without the nozzle leaving the boundery of this part.

        It's also the first step that stores the result in the "data storage" so all other steps can access it.
        */
        private static void CreateLayerWithParts(SliceLayer storageLayer, SlicerLayer layer, ConfigConstants.REPAIR_OVERLAPS unionAllType)
        {
            if ((unionAllType & ConfigConstants.REPAIR_OVERLAPS.REVERSE_ORIENTATION) == ConfigConstants.REPAIR_OVERLAPS.REVERSE_ORIENTATION)
            {
                for (int i = 0; i < layer.PolygonList.Count; i++)
                {
                    if (layer.PolygonList[i].Orientation())
                    {
                        layer.PolygonList[i].Reverse();
                    }
                }
            }

            List<Polygons> result;
            if ((unionAllType & ConfigConstants.REPAIR_OVERLAPS.UNION_ALL_TOGETHER) == ConfigConstants.REPAIR_OVERLAPS.UNION_ALL_TOGETHER)
            {
                result = layer.PolygonList.Offset(1000).CreateLayerOutlines(PolygonsHelper.LayerOpperation.UnionAll);
            }
            else
            {
                result = layer.PolygonList.CreateLayerOutlines(PolygonsHelper.LayerOpperation.EvenOdd);
            }

            for (int i = 0; i < result.Count; i++)
            {
                storageLayer.parts.Add(new SliceLayerPart());
                if ((unionAllType & ConfigConstants.REPAIR_OVERLAPS.UNION_ALL_TOGETHER) == ConfigConstants.REPAIR_OVERLAPS.UNION_ALL_TOGETHER)
                {
                    storageLayer.parts[i].TotalOutline.Add(result[i][0]);
                    storageLayer.parts[i].TotalOutline = storageLayer.parts[i].TotalOutline.Offset(-1000);
                }
                else
                {
                    storageLayer.parts[i].TotalOutline = result[i];
                }

                storageLayer.parts[i].BoundingBox.Calculate(storageLayer.parts[i].TotalOutline);
            }
        }
Exemple #36
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);
            }
        }
Exemple #37
0
        public void GenerateTopAndBottoms(ConfigSettings config, int layerIndex, long extrusionWidth_um, long outerPerimeterWidth_um, int downLayerCount, int upLayerCount, long infillExtendIntoPerimeter_um)
        {
            var clippingOffset = infillExtendIntoPerimeter_um * 2;

            ExtruderLayers extruder = this;
            SliceLayer     layer    = extruder.Layers[layerIndex];

            Agg.Parallel.For(0, layer.Islands.Count, (islandIndex) =>
                             // for (int islandIndex = 0; islandIndex < layer.Islands.Count; islandIndex++)
            {
                LayerIsland island = layer.Islands[islandIndex];
                if (island.InsetToolPaths.Count == 0)
                {
                    return;
                }

                // this is the entire extrusion width to make sure we are outside of the extrusion line
                Polygons lastInset         = island.InsetToolPaths[island.InsetToolPaths.Count - 1];
                Polygons infillRegionPath  = lastInset.Offset(-extrusionWidth_um);
                Polygons sparseInfillPaths = new Polygons(infillRegionPath);

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

                    if (layerIndex - 1 >= 0)
                    {
                        var previousLayer = extruder.Layers[layerIndex - 1];

                        bottomOutlines = RemoveIslandsFromPolygons(previousLayer.Islands, island.BoundingBox, bottomOutlines);
                        bottomOutlines.RemoveSmallAreas(extrusionWidth_um);
                    }

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

                    island.BottomPaths = bottomOutlines;
                }

                // calculate the top outlines
                if (upLayerCount > 0)
                {
                    Polygons topOutlines = new Polygons(infillRegionPath);
                    topOutlines          = topOutlines.CreateDifference(island.BottomPaths.Offset(clippingOffset));
                    topOutlines          = Clipper.CleanPolygons(topOutlines, cleanDistance_um);

                    if (layerIndex + 1 < extruder.Layers.Count)
                    {
                        // Remove the top layer that is above this one to get only the data that is a top layer on this layer.
                        topOutlines = RemoveIslandsFromPolygons(extruder.Layers[layerIndex + 1].Islands, island.BoundingBox, topOutlines);
                    }

                    topOutlines.RemoveSmallAreas(extrusionWidth_um);

                    sparseInfillPaths = sparseInfillPaths.CreateDifference(topOutlines.Offset(clippingOffset));
                    sparseInfillPaths = Clipper.CleanPolygons(sparseInfillPaths, cleanDistance_um);

                    island.TopPaths = topOutlines;
                }

                if (upLayerCount <= 0 && downLayerCount <= 0)
                {
                    // Assign infill directly if no top/bottom solid layers
                    island.SparseInfillPaths = sparseInfillPaths;
                }
                else
                {
                    // calculate the solid infill outlines
                    Polygons solidInfillPaths = new Polygons(infillRegionPath);

                    // remove all the top layers
                    solidInfillPaths = solidInfillPaths.CreateDifference(island.BottomPaths.Offset(clippingOffset));
                    solidInfillPaths = Clipper.CleanPolygons(solidInfillPaths, cleanDistance_um);

                    // remove all the bottom layers
                    solidInfillPaths = solidInfillPaths.CreateDifference(island.TopPaths.Offset(clippingOffset));
                    solidInfillPaths = Clipper.CleanPolygons(solidInfillPaths, cleanDistance_um);

                    int upEnd = layerIndex + upLayerCount + 1;
                    if (upEnd <= extruder.Layers.Count && layerIndex - downLayerCount >= 0)
                    {
                        // find all the regions that have more top and bottom layers than should be solid (will remain sparse)
                        Polygons regionsThatWillBeSparse = new Polygons(infillRegionPath);

                        int upStart = layerIndex + 2;

                        Agg.Parallel.For(upStart, upEnd, (layerToTest) =>
                                         // for (int layerToTest = upStart; layerToTest < upEnd; layerToTest++)
                        {
                            regionsThatWillBeSparse = IntersectWithPolygons(extruder.Layers[layerToTest].Islands, island.BoundingBox, regionsThatWillBeSparse);
                            regionsThatWillBeSparse = Clipper.CleanPolygons(regionsThatWillBeSparse, cleanDistance_um);
                        });

                        // find all the solid infill bottom layers
                        int downStart = Math.Max(0, layerIndex - 1);
                        int downEnd   = Math.Max(0, layerIndex - downLayerCount);

                        Agg.Parallel.For(downStart, downEnd, (layerToTest) =>
                                         // for (int layerToTest = downStart; layerToTest >= downEnd; layerToTest--)
                        {
                            regionsThatWillBeSparse = IntersectWithPolygons(extruder.Layers[layerToTest].Islands, island.BoundingBox, regionsThatWillBeSparse);
                            regionsThatWillBeSparse = Clipper.CleanPolygons(regionsThatWillBeSparse, cleanDistance_um);
                        });

                        solidInfillPaths = solidInfillPaths.CreateDifference(regionsThatWillBeSparse);
                        solidInfillPaths.RemoveSmallAreas(extrusionWidth_um);
                        solidInfillPaths = Clipper.CleanPolygons(solidInfillPaths, cleanDistance_um);
                    }

                    // remove the solid infill from the sparse infill
                    sparseInfillPaths = sparseInfillPaths.CreateDifference(solidInfillPaths.Offset(clippingOffset));
                    sparseInfillPaths.RemoveSmallAreas(extrusionWidth_um);
                    sparseInfillPaths        = Clipper.CleanPolygons(sparseInfillPaths, cleanDistance_um);
                    island.SparseInfillPaths = sparseInfillPaths;

                    if (config == null ||                   // this is to make our tests test the bridgeOverInfill
                        config.BridgeOverInfill)
                    {
                        // now figure out what part of the solid infill is actually first top layers and switch it to that
                        // we can only have a first top y layer at the bottom of the top layers
                        if (layerIndex == extruder.Layers.Count - upLayerCount)
                        {
                            // all of it is first top layers
                            island.FirstTopPaths = solidInfillPaths;
                            solidInfillPaths     = new Polygons();
                        }
                        else if (layerIndex > 0 &&
                                 layerIndex < extruder.Layers.Count - upLayerCount)
                        {
                            // Intersect the current solid layer with the previous spars layer
                            // that will be all of the new solid layers that are currently on sparse layer

                            var firstTopPaths = new Polygons(solidInfillPaths);
                            firstTopPaths     = IntersectWithSparsePolygons(extruder.Layers[layerIndex - 1].Islands, island.BoundingBox, firstTopPaths);
                            firstTopPaths.RemoveSmallAreas(extrusionWidth_um);
                            firstTopPaths = Clipper.CleanPolygons(firstTopPaths, cleanDistance_um);

                            if (firstTopPaths.Count > 0)
                            {
                                solidInfillPaths = solidInfillPaths.CreateDifference(firstTopPaths.Offset(clippingOffset));
                                solidInfillPaths.RemoveSmallAreas(extrusionWidth_um);
                                solidInfillPaths = Clipper.CleanPolygons(solidInfillPaths, cleanDistance_um);

                                island.FirstTopPaths = firstTopPaths;
                            }
                        }
                    }

                    island.SolidInfillPaths = solidInfillPaths;
                }
            });
        }
		private static ExtruderLayers CreateLayerData(List<Polygons> totalLayerOutlines)
		{
			int numLayers = totalLayerOutlines.Count;
			ExtruderLayers layerData = new ExtruderLayers();
			layerData.Layers = new List<SliceLayer>();
			for (int layerIndex = 0; layerIndex < numLayers; layerIndex++)
			{
				SliceLayer layer = new SliceLayer();
				layer.AllOutlines = totalLayerOutlines[layerIndex];
				layerData.Layers.Add(layer);
			}
			return layerData;
		}