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));
            }
        }
        private static Polygons GetSkirtBounds(ConfigSettings config, LayerDataStorage storage, bool externalOnly, long distance_um, long extrusionWidth_um, int brimCount)
        {
            bool hasWipeTower = storage.WipeLayer(0).PolygonLength() > 0;

            var skirtPolygons = new Polygons();

            if (config.EnableRaft)
            {
                skirtPolygons = skirtPolygons.CreateUnion(storage.raftOutline);
            }
            else
            {
                var allOutlines = hasWipeTower ? new Polygons(storage.WipeLayer(0).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];
                        if (layer0.Islands.Count > 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());
                    }

                    Polygons brimLoops = new Polygons();
                    for (int brimIndex = 0; brimIndex < brimCount; brimIndex++)
                    {
                        // Extend the polygons to account for the brim (ensures convex hull takes this data into account)
                        brimLoops.AddAll(brimIslandOutlines.Offset(extrusionWidth_um * brimIndex + extrusionWidth_um / 2));
                    }

                    storage.Brims.AddAll(brimLoops);

                    // and extend the bounds of the skirt polygons
                    skirtPolygons = skirtPolygons.CreateUnion(brimIslandOutlines.Offset(extrusionWidth_um * brimCount));
                }

                skirtPolygons = skirtPolygons.CreateUnion(allOutlines);

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

            return(skirtPolygons);
        }