示例#1
0
        public static Polygons ConvertToLines(Polygons polygons, bool closedLoop)
        {
            Polygons linePolygons = new Polygons();

            foreach (Polygon polygon in polygons)
            {
                if (polygon.Count > 2)
                {
                    int endIndex = closedLoop ? polygon.Count : polygon.Count - 1;
                    for (int vertexIndex = 0; vertexIndex < endIndex; vertexIndex++)
                    {
                        linePolygons.Add(new Polygon()
                        {
                            polygon[vertexIndex], polygon[(vertexIndex + 1) % polygon.Count]
                        });
                    }
                }
                else
                {
                    linePolygons.Add(polygon);
                }
            }

            return(linePolygons);
        }
示例#2
0
        public void GenerateBase(Polygons polygonShape, double bottomWithoutBase)
        {
            if (polygonShape != null &&
                polygonShape.Select(p => p.Count).Sum() > 3)
            {
                Polygons polysToOffset = new Polygons();

                switch (BaseType)
                {
                case BaseTypes.Rectangle:
                    polysToOffset.Add(GetBoundingPolygon(polygonShape));
                    break;

                case BaseTypes.Circle:
                    polysToOffset.Add(GetBoundingCircle(polygonShape));
                    break;

                case BaseTypes.Outline:
                    PolyTree polyTreeForBase = GetPolyTree(polygonShape);
                    foreach (PolyNode polyToOffset in polyTreeForBase.Childs)
                    {
                        polysToOffset.Add(polyToOffset.Contour);
                    }
                    break;
                }

                if (polysToOffset.Count > 0)
                {
                    Polygons basePolygons;

                    if (BaseType == BaseTypes.Outline &&
                        InfillAmount > 0)
                    {
                        basePolygons = Offset(polysToOffset, (BaseSize + InfillAmount) * scalingForClipper);
                        basePolygons = Offset(basePolygons, -InfillAmount * scalingForClipper);
                    }
                    else
                    {
                        basePolygons = Offset(polysToOffset, BaseSize * scalingForClipper);
                    }

                    basePolygons = ClipperLib.Clipper.CleanPolygons(basePolygons, 10);

                    VertexStorage rawVectorShape = basePolygons.PolygonToPathStorage();
                    var           vectorShape    = new VertexSourceApplyTransform(rawVectorShape, Affine.NewScaling(1.0 / scalingForClipper));

                    var baseObject = new Object3D()
                    {
                        Mesh = VertexSourceToMesh.Extrude(vectorShape, zHeight: ExtrusionHeight)
                    };
                    Children.Add(baseObject);
                    baseObject.Mesh.Translate(new Vector3(0, 0, -ExtrusionHeight + bottomWithoutBase));
                }
                else
                {
                    // clear the mesh
                    Mesh = null;
                }
            }
        }
示例#3
0
        void GenerateAustPlusRandomEllipses(int count)
        {
            subjects.Clear();
            //load map of Australia from resource ...
            System.IO.Stream polyStream = Alt.IO.VirtualFile.OpenRead("AltData/Clipper/aust.bin");
            int len = (int)polyStream.Length;

            byte[] b = new byte[len];
            polyStream.Read(b, 0, len);
            int polyCnt = BitConverter.ToInt32(b, 0);
            int k       = 4;

            for (int i = 0; i < polyCnt; ++i)
            {
                int vertCnt = BitConverter.ToInt32(b, k);
                k += 4;
                Polygon pg = new Polygon(vertCnt);
                for (int j = 0; j < vertCnt; ++j)
                {
                    float x = BitConverter.ToSingle(b, k) * scale;
                    float y = BitConverter.ToSingle(b, k + 4) * scale;
                    k += 8;
                    pg.Add(new IntPoint((int)x, (int)y));
                }
                subjects.Add(pg);
            }

            clips.Clear();
            Random       rand = new Random();
            GraphicsPath path = new GraphicsPath();
            PointI       pt   = new PointI();

            const int ellipse_size = 100, margin = 10;

            for (int i = 0; i < count; ++i)
            {
                int w = WorkArea.Width - ellipse_size - margin * 2;
                int h = WorkArea.Height - ellipse_size - margin * 2;

                pt.X = rand.Next(w) + margin;
                pt.Y = rand.Next(h) + margin;
                int size = rand.Next(ellipse_size - 20) + 20;
                path.Reset();
                path.AddEllipse(pt.X, pt.Y, size, size);
                path.Flatten();
                Polygon clip = new Polygon(path.PathPoints.Length);//Count());
                foreach (Point p in path.PathPoints)
                {
                    clip.Add(new IntPoint((int)(p.X * scale), (int)(p.Y * scale)));
                }

                clips.Add(clip);
            }
        }
示例#4
0
        public Form1(IOperation IOperation)  //Dependency Injection
        {
            _IOperation = IOperation;

            InitializeComponent();
            polygons = new Polygons();

            //Create initial instances of two polygons
            polygons.Add(Factory.Factory.Instance());
            polygons.Add(Factory.Factory.Instance());
        }
示例#5
0
        //---------------------------------------------------------------------

        private void GenerateAustPlusRandomEllipses(int count)
        {
            subjects.Clear();
            //load map of Australia from resource ...
            _assembly  = Assembly.GetExecutingAssembly();
            polyStream = _assembly.GetManifestResourceStream("GuiDemo.aust.bin");
            int len = (int)polyStream.Length;

            byte[] b = new byte[len];
            polyStream.Read(b, 0, len);
            int polyCnt = BitConverter.ToInt32(b, 0);
            int k       = 4;

            for (int i = 0; i < polyCnt; ++i)
            {
                int vertCnt = BitConverter.ToInt32(b, k);
                k += 4;
                Polygon pg = new Polygon(vertCnt);
                for (int j = 0; j < vertCnt; ++j)
                {
                    float x = BitConverter.ToSingle(b, k) * scale;
                    float y = BitConverter.ToSingle(b, k + 4) * scale;
                    k += 8;
                    pg.Add(new IntPoint((int)x, (int)y));
                }
                subjects.Add(pg);
            }

            clips.Clear();
            Random       rand = new Random();
            GraphicsPath path = new GraphicsPath();
            Point        pt   = new Point();

            const int ellipse_size = 100, margin = 10;

            for (int i = 0; i < count; ++i)
            {
                int w = pictureBox1.ClientRectangle.Width - ellipse_size - margin * 2;
                int h = pictureBox1.ClientRectangle.Height - ellipse_size - margin * 2 - statusStrip1.Height;

                pt.X = rand.Next(w) + margin;
                pt.Y = rand.Next(h) + margin;
                int size = rand.Next(ellipse_size - 20) + 20;
                path.Reset();
                path.AddEllipse(pt.X, pt.Y, size, size);
                path.Flatten();
                Polygon clip = new Polygon(path.PathPoints.Count());
                foreach (PointF p in path.PathPoints)
                {
                    clip.Add(new IntPoint((int)(p.X * scale), (int)(p.Y * scale)));
                }
                clips.Add(clip);
            }
        }
示例#6
0
        ////////////////////////////////////////////////

        static Polygons ExPolygons2Polygons(ExPolygons epgs)
        {
            Polygons result = new Polygons();

            foreach (ExPolygon epg in epgs)
            {
                result.Add(epg.outer);
                foreach (Polygon hole in epg.holes)
                {
                    result.Add(hole);
                }
            }
            return(result);
        }
示例#7
0
 private static void ProcessPolyTreeNodeIntoSeparateIslands(this Polygons polygonsIn, PolyNode node, List <Polygons> ret)
 {
     for (int n = 0; n < node.ChildCount; n++)
     {
         PolyNode child    = node.Childs[n];
         Polygons polygons = new Polygons();
         polygons.Add(child.Contour);
         for (int i = 0; i < child.ChildCount; i++)
         {
             polygons.Add(child.Childs[i].Contour);
             polygonsIn.ProcessPolyTreeNodeIntoSeparateIslands(child.Childs[i], ret);
         }
         ret.Add(polygons);
     }
 }
示例#8
0
        //---------------------------------------------------------------------

        private void GenerateAustPlusRandomEllipses(int count)
        {
            subjects.Clear();
            //load map of Australia from resource ...
            Assembly _assembly = Assembly.GetExecutingAssembly();

            using (BinaryReader polyStream = new BinaryReader(_assembly.GetManifestResourceStream("GuiDemo.aust.bin")))
            {
                int polyCnt = polyStream.ReadInt32();
                for (int i = 0; i < polyCnt; ++i)
                {
                    int     vertCnt = polyStream.ReadInt32();
                    Polygon pg      = new Polygon(vertCnt);
                    for (int j = 0; j < vertCnt; ++j)
                    {
                        float x = polyStream.ReadSingle() * scale;
                        float y = polyStream.ReadSingle() * scale;
                        pg.Add(new IntPoint((int)x, (int)y));
                    }
                    subjects.Add(pg);
                }
            }
            clips.Clear();
            Random rand = new Random();

            using (GraphicsPath path = new GraphicsPath())
            {
                const int ellipse_size = 100, margin = 10;
                for (int i = 0; i < count; ++i)
                {
                    int w = pictureBox1.ClientRectangle.Width - ellipse_size - margin * 2;
                    int h = pictureBox1.ClientRectangle.Height - ellipse_size - margin * 2 - statusStrip1.Height;

                    int x    = rand.Next(w) + margin;
                    int y    = rand.Next(h) + margin;
                    int size = rand.Next(ellipse_size - 20) + 20;
                    path.Reset();
                    path.AddEllipse(x, y, size, size);
                    path.Flatten();
                    Polygon clip = new Polygon(path.PathPoints.Count());
                    foreach (PointF p in path.PathPoints)
                    {
                        clip.Add(new IntPoint((int)(p.X * scale), (int)(p.Y * scale)));
                    }
                    clips.Add(clip);
                }
            }
        }
示例#9
0
        public static Polygons CreateFromString(string polygonsPackedString, double scale = 1)
        {
            Polygon SinglePolygon(string polygonString)
            {
                var poly = new Polygon();

                string[] intPointData = polygonString.Split(',');
                int      increment    = 2;

                for (int i = 0; i < intPointData.Length - 1; i += increment)
                {
                    string elementX     = intPointData[i];
                    string elementY     = intPointData[i + 1];
                    var    nextIntPoint = new IntPoint(double.Parse(elementX) * scale,
                                                       double.Parse(elementY) * scale);
                    poly.Add(nextIntPoint);
                }

                return(poly);
            }

            Polygons output = new Polygons();

            string[] polygons = polygonsPackedString.Split('|');
            foreach (string polygonString in polygons)
            {
                Polygon nextPoly = SinglePolygon(polygonString);
                if (nextPoly.Count > 0)
                {
                    output.Add(nextPoly);
                }
            }

            return(output);
        }
示例#10
0
        private void SetPolygons()
        {
            var zc = ZoneContract;

            Polygons.Clear();

            if (zc == null)
            {
                return;
            }

            Polygon poly = new Polygon()
            {
                //FillColor = Color.FromHex(zc.ARGBFill),
                //StrokeColor = Color.FromHex(zc.ARGBFill),
                FillColor   = Color.FromHex(Constants.CardinalRed50ARGB),
                StrokeColor = Color.FromHex(Constants.CardinalRed50ARGB),
                StrokeWidth = 1.0f,
                Tag         = new PolygonTag()
                {
                    PolygonTagType = PolygonTagType.Zone,
                    Tag            = zc.Description
                }
            };

            foreach (var shape in zc.ZoneShapes.Where(z => z.Order > 0).OrderBy(z => z.Order))
            {
                poly.Positions.Add(new Position(shape.Latitude, shape.Longitude));
                //TODO: add code to display negative space
            }
            Polygons.Add(poly);
        }
示例#11
0
        public void AddPolygon()
        {
            Polygon p = new Polygon();

            Polygons.Add(p);
            Polygon = p;
        }
示例#12
0
        /// \brief Constructs a new Polygon.
        /// \return Newly created Polygon without any connections.
        public Polygon MakePolygon()
        {
            Polygon polygon = new Polygon();

            Polygons.Add(polygon);
            return(polygon);
        }
示例#13
0
        /// <summary>
        /// Load existing collision
        /// </summary>
        /// <param name="buffer"></param>
        public void Load(byte[] buffer)
        {
            try
            {
                using (BinaryReader b = new BinaryReader(new MemoryStream(buffer)))
                {
                    var polygonCount = b.ReadInt32();

                    for (int i = 0; i < polygonCount; i++)
                    {
                        var polygon  = new Polygon2();
                        var pointNum = b.ReadInt32();

                        for (int p = 0; p < pointNum; p++)
                        {
                            var point = new K2DPosition();
                            point.X = b.ReadInt32();
                            point.Y = b.ReadInt32();
                            polygon.Points.Add(point);
                        }

                        Polygons.Add(polygon);
                    }
                }

                XLog.WriteLine(Levels.Good, "Ok");
            }
            catch (Exception exception)
            {
                Blank();
                XLog.WriteLine(Levels.Error, "Failed");
                XLog.WriteLine(Levels.Fatal, "NfaManager::Load<Exception> -> {0}", exception);
            }
        }
示例#14
0
        private void StartAnimation(object sender, EventArgs e)
        {
            _continueAnimation = true;
            LockButtons(Grafika002.Form1.ActionType.animation);

            animationPolygon = Polygon.RandomPolygon(_drawing);

            animationPolygon.FinnishDrawing();
            animationPolygon.FillEnabled = true;
            Polygons.Add(animationPolygon);

            int maxRight = 0;

            while (_continueAnimation && maxRight < mainPictureBox.Width)
            {
                lock (this.mainPictureBox.Image)
                {
                    _drawing.ClearBitmap();
                    Polygons.ForEach(x => x.DrawPolygon());
                    maxRight = animationPolygon.MoveRigth();
                    IntersectAllPolygonsWithAnimationPolygon();
                    this.mainPictureBox.Image = directBitmap.Bitmap;
                    mainPictureBox.Update();
                    mainPictureBox.Refresh();
                    Application.DoEvents();
                }
            }
            Polygons.Remove(animationPolygon);
            _drawing.ClearBitmap();
            Polygons.ForEach(x => x.DrawPolygon());
            this.mainPictureBox.Image = directBitmap.Bitmap;
            LockButtons(Grafika002.Form1.ActionType.animation, true);
        }
示例#15
0
 public void AddPolygon(Polygon p2)
 {
     if (!Polygons.Contains(p2))
     {
         Polygons.Add(p2);
     }
 }
示例#16
0
 public static void AddAll(this Polygons polygons, Polygons other)
 {
     for (int n = 0; n < other.Count; n++)
     {
         polygons.Add(other[n]);
     }
 }
示例#17
0
 private void StopDrawingClick(object sender, EventArgs e)
 {
     polygon?.FinnishDrawing();
     polygon = new Polygon(_drawing);
     Polygons.Add(polygon);
     RedrawPolygons();
 }
示例#18
0
        private void ClipPolygons()
        {
            if (Polygons.Count != 2)
            {
                throw new InvalidOperationException("Clipping is only possible for two and exactly two polygons");
            }

            if (Clipper == null)
            {
                throw new InvalidOperationException("No polygon clipper set");
            }

            var resultPolygon = Clipper.GetIntersectedPolygon(Polygons[0].Points, Polygons[1].Points);

            if (resultPolygon.IsEmpty)
            {
                DialogHandler?.ShowMessageBox("No overlap");
            }
            else
            {
                Polygons.Clear();
                var color = GenerateRandomColor();
                Polygons.Add(new Polygon
                {
                    Description = "Clipped Polygon",
                    Points      = resultPolygon,
                    StrokeColor = color,
                    FillColor   = Color.FromArgb(128, color)
                });
            }
        }
示例#19
0
        //Calculate Poly's from Points
        private Polygons GenerateRandomCubes(int countObs)
        {
            int      scale  = trackBar1.Value;
            Polygons obs    = new Polygons();
            int      height = rand.Next(0, pictureBox1.Width * scale / 10);
            int      width  = rand.Next(0, pictureBox1.Width * scale / 10);
            int      x;
            int      y;

            for (int i = 0; i < countObs; i++)
            {
                Polygon cube = new Polygon();
                x = rand.Next(0, pictureBox1.Width * scale);
                y = rand.Next(0, pictureBox1.Height * scale);
                cube.Add(GeneratePoint(x, y));
                x = x + rand.Next(0, pictureBox1.Width * scale / 10);
                cube.Add(GeneratePoint(x, y));
                y = y + rand.Next(0, pictureBox1.Width * scale / 10);
                cube.Add(GeneratePoint(x, y));
                x = x - rand.Next(0, pictureBox1.Width * scale / 10);
                cube.Add(GeneratePoint(x, y));
                obs.Add(cube);
            }
            return(obs);
        }
示例#20
0
        private void GenerateRandomPolygon(int count)
        {
            int    Q    = 10;
            Random rand = new Random();
            int    l    = 10;
            int    t    = 10;
            int    r    = (pictureBox1.ClientRectangle.Width - 20) / Q * Q;
            int    b    = (pictureBox1.ClientRectangle.Height - 20) / Q * Q;

            subjects.Clear();
            clips.Clear();

            Polygon subj = new Polygon(count);

            for (int i = 0; i < count; ++i)
            {
                subj.Add(GenerateRandomPoint(l, t, r, b, rand));
            }
            subjects.Add(subj);

            Polygon clip = new Polygon(count);

            for (int i = 0; i < count; ++i)
            {
                clip.Add(GenerateRandomPoint(l, t, r, b, rand));
            }
            clips.Add(clip);
        }
示例#21
0
        /// <summary>
        /// Add the 2D projection of the given arc
        /// to the current element outline union
        /// </summary>
        static public bool AddToUnion(
            Polygons union,
            VertexLookup vl,
            Clipper c,
            Arc arc)
        {
            IList <XYZ> pts = arc.Tessellate();
            int         n   = pts.Count;

            Polygons faces  = new Polygons(1);
            Polygon  face2d = new Polygon(n);

            IntPoint a = vl.GetOrAdd(pts[0]);

            face2d.Add(a);

            for (int i = 1; i < n; ++i)
            {
                IntPoint b = vl.GetOrAdd(pts[i]);

                if (b != a)
                {
                    face2d.Add(b);
                    a = b;
                }
            }
            faces.Add(face2d);

            return(c.AddPaths(faces, PolyType.ptSubject, true));
        }
示例#22
0
        public static void GenerateConcentricInfill(ConfigSettings config, Polygons partOutline, ref Polygons fillPolygons, long extrusionWidthOverride_um = 0)
        {
            if (extrusionWidthOverride_um == 0)
            {
                extrusionWidthOverride_um = config.extrusionWidth_um;
            }

            Polygons outlineCopy = new Polygons(partOutline);

            foreach (Polygon outline in outlineCopy)
            {
                if (outline.Count > 0)
                {
                    outline.Add(outline[0]);
                }
            }
            int linespacing_um = (int)(extrusionWidthOverride_um / (config.infillPercent / 100));

            while (outlineCopy.Count > 0)
            {
                for (int outlineIndex = 0; outlineIndex < outlineCopy.Count; outlineIndex++)
                {
                    Polygon r = outlineCopy[outlineIndex];
                    fillPolygons.Add(r);
                }
                outlineCopy = outlineCopy.Offset(-linespacing_um);
                foreach (Polygon outline in outlineCopy)
                {
                    if (outline.Count > 0)
                    {
                        outline.Add(outline[0]);
                    }
                }
            }
        }
示例#23
0
        public static Polygons CreatePolygons(this IVertexSource sourcePath, double scaling = 1000)
        {
            var     allPolys    = new Polygons();
            Polygon currentPoly = null;

            foreach (VertexData vertexData in sourcePath.Vertices())
            {
                if (vertexData.command == ShapePath.FlagsAndCommand.MoveTo ||
                    vertexData.IsLineTo)
                {
                    // MoveTo always creates a new polygon
                    if (vertexData.command == ShapePath.FlagsAndCommand.MoveTo)
                    {
                        currentPoly = null;
                    }

                    // Construct current polygon if unset
                    if (currentPoly == null)
                    {
                        currentPoly = new Polygon();
                        allPolys.Add(currentPoly);
                    }

                    // Add polygon point for LineTo or MoveTo command
                    currentPoly.Add(new IntPoint(vertexData.position.X * scaling, vertexData.position.Y * scaling));
                }
                else if (vertexData.command != ShapePath.FlagsAndCommand.FlagNone)
                {
                    // Clear active, reconstructed on first valid point
                    currentPoly = null;
                }
            }

            return(allPolys);
        }
示例#24
0
        private void AddPaddingTraectory()
        {
            //long scale = 1000;

            List <IntPoint> lpoint = new Polygon();

            //lpoint.Add(new IntPoint(10 * scale, 10 * scale));
            //lpoint.Add(new IntPoint(10 * scale, 20 * scale));
            //lpoint.Add(new IntPoint(20 * scale, 20 * scale));
            //lpoint.Add(new IntPoint(20 * scale, 10 * scale));
            //lpoint.Add(new IntPoint(16 * scale, 10 * scale));
            //lpoint.Add(new IntPoint(16 * scale, 15 * scale));
            //lpoint.Add(new IntPoint(14 * scale, 15 * scale));
            //lpoint.Add(new IntPoint(14 * scale, 10 * scale));



            Polygons pSource = new Polygons();
            Polygons pDestin = new Polygons();

            pSource.Add(lpoint);

            pDestin = GetOffsetPolugon(pSource, (double)numericDiff.Value * 10000);

            ////отобразим результат
            //Bitmap mybitmap = new Bitmap(pictureBox1.ClientRectangle.Width, pictureBox1.ClientRectangle.Height, PixelFormat.Format32bppArgb);


            //using (Graphics newgraphic = Graphics.FromImage(mybitmap))
            //{
            //    newgraphic.SmoothingMode = SmoothingMode.AntiAlias;
            //    newgraphic.Clear(Color.White);

            //    GraphicsPath path1 = new GraphicsPath();
            //    path1.FillMode = FillMode.Winding;

            //    GraphicsPath path2 = new GraphicsPath();
            //    path2.FillMode = FillMode.Winding;

            //    foreach (Polygon pg in pSource)
            //    {
            //        PointF[] pts = PolygonToPointFArray(pg, scale / 10);
            //        path1.AddPolygon(pts);
            //        pts = null;
            //    }

            //    foreach (Polygon pg in pDestin)
            //    {
            //        PointF[] pts = PolygonToPointFArray(pg, scale / 10);
            //        path2.AddPolygon(pts);
            //        pts = null;
            //    }

            //    newgraphic.DrawPath(new Pen(Color.Blue, 1.0f), path1);
            //    newgraphic.DrawPath(new Pen(Color.Red, 1.0f), path2);
            //}

            //pictureBox1.Image = mybitmap;
        }
示例#25
0
        private static InfillGrid generateRaftGrid(Polygons raftOutline, float density)
        {
            //Start by calculating the endpoints of the raft

            long raftMinX = Global.Values.modelMinX - Global.Values.raftDistance * 2;
            long raftMaxX = Global.Values.modelMaxX + Global.Values.raftDistance * 2;
            long raftMinY = Global.Values.modelMinY - Global.Values.raftDistance * 2;
            long raftMaxY = Global.Values.modelMaxY + Global.Values.raftDistance * 2;

            Polygons rightList = new Polygons();
            Polygons leftList  = new Polygons();

            uint spacing = caluclateNeededSpacing(density, Global.Values.nozzleWidth);
            uint divider = (uint)(Global.Values.nozzleWidth + spacing);

            uint amountOfLines = 0;

            //2 points of line segments
            IntPoint p1 = new IntPoint();
            IntPoint p2 = new IntPoint();

            //We need to start creating diagonal lines before the min x sothat there are lines over every part of the model
            long xOffset = (long)((raftMaxY - raftMinY) / Math.Tan(MathUtils.MathHelper.ToRadians(45)));

            raftMinX -= xOffset;

            amountOfLines = (uint)((raftMaxX - raftMinX) / divider);

            //Calculate the right and left line simeltaniously
            for (uint i = 0; i < amountOfLines; i++)
            {
                //First the right angled line
                p1.X = raftMinX + i * divider + (Global.Values.nozzleWidth / 2);
                p1.Y = raftMinY;
                p2.X = p1.X;// +xOffset;
                p2.Y = raftMaxY;

                Polygon line = new Polygon();
                line.Add(p1); line.Add(p2);
                rightList.Add(line);
            }

            amountOfLines = (uint)((raftMaxY - raftMinY) / divider);

            //Calculate the right and left line simeltaniously
            for (uint i = 0; i < amountOfLines; i++)
            {
                p1.Y = raftMinY + i * divider + (Global.Values.nozzleWidth / 2);
                p1.X = raftMinX;
                p2.Y = p1.Y;// +xOffset;
                p2.X = raftMaxX;

                Polygon line = new Polygon();
                line.Add(p1); line.Add(p2);
                leftList.Add(line);
            }

            return(new InfillGrid(rightList, leftList));
        }
示例#26
0
        public static Polygons GetExtrusionPolygons(string[] gcode, ref MovementInfo movementInfo)
        {
            Polygons foundPolygons = new Polygons();

            bool extruding = false;
            // check that all moves are on the outside of the cylinder (not crossing to a new point)
            int movementCount = 0;

            foreach (MovementInfo movement in TestUtlities.Movements(gcode, movementInfo))
            {
                bool isExtrude = movement.extrusion != movementInfo.extrusion;

                if (extruding)
                {
                    if (isExtrude)
                    {
                        // add to the extrusion
                        foundPolygons[foundPolygons.Count - 1].Add(new IntPoint(
                                                                       (long)(movement.position.x * 1000),
                                                                       (long)(movement.position.y * 1000),
                                                                       (long)(movement.position.z * 1000)));
                    }
                    else
                    {
                        extruding = false;
                    }
                }
                else                 // not extruding
                {
                    if (isExtrude)
                    {
                        // starting a new extrusion
                        foundPolygons.Add(new Polygon());
                        foundPolygons[foundPolygons.Count - 1].Add(new IntPoint(
                                                                       (long)(movement.position.x * 1000),
                                                                       (long)(movement.position.y * 1000),
                                                                       (long)(movement.position.z * 1000)));
                        extruding = true;
                    }
                    else                     // do nothing waiting for extrude
                    {
                        int stop = 0;
                    }
                }

                movementInfo = movement;
                movementCount++;
            }

            for (int i = foundPolygons.Count - 1; i >= 0; i--)
            {
                if (foundPolygons[i].Count == 1)
                {
                    foundPolygons.RemoveAt(i);
                }
            }

            return(foundPolygons);
        }
示例#27
0
        /// <summary>
        /// Add new collision
        /// </summary>
        /// <param name="location"></param>
        public void Add(PointF[] points)
        {
            var polygon = _2DUtils.PointToPolygon(points);

            Polygons.Add(polygon);

            Added?.Invoke(this, polygon);
        }
示例#28
0
 public void AddPoly(Polygon p)
 {
     if (p.Name == string.Empty)
     {
         p.Name = nextPathName;
     }
     Polygons.Add(p);
     UpdateExtent(p);
 }
 private void MovePolygonToTop(Polygon p)
 {
     if (p == null)
     {
         return;
     }
     Polygons.Remove(p);
     Polygons.Add(p);
 }
示例#30
0
        private void testpoly()
        {
            Polygons subj = new Polygons(2);

            subj.Add(new Polygon(4));
            subj[0].Add(new IntPoint(180, 200));
            subj[0].Add(new IntPoint(260, 200));
            subj[0].Add(new IntPoint(260, 150));
            subj[0].Add(new IntPoint(180, 150));
        }
示例#31
0
		public static void GenerateLinePaths(Polygons polygonToInfill, ref Polygons infillLinesToPrint, int lineSpacing, int infillExtendIntoPerimeter_um, double rotation, long rotationOffset = 0)
		{
			if (polygonToInfill.Count > 0)
			{
				Polygons outlines = polygonToInfill.Offset(infillExtendIntoPerimeter_um);
				if (outlines.Count > 0)
				{
					PointMatrix matrix = new PointMatrix(-(rotation + 90)); // we are rotating the part so we rotate by the negative so the lines go the way we expect

					outlines.ApplyMatrix(matrix);

					Aabb boundary = new Aabb(outlines);

					boundary.min.X = ((boundary.min.X / lineSpacing) - 1) * lineSpacing - rotationOffset;
					int xLineCount = (int)((boundary.max.X - boundary.min.X + (lineSpacing - 1)) / lineSpacing);
					Polygons unclipedPatern = new Polygons();

					long firstX = boundary.min.X / lineSpacing * lineSpacing;
					for (int lineIndex = 0; lineIndex < xLineCount; lineIndex++)
					{
						Polygon line = new Polygon();
						line.Add(new IntPoint(firstX + lineIndex * lineSpacing, boundary.min.Y));
						line.Add(new IntPoint(firstX + lineIndex * lineSpacing, boundary.max.Y));
						unclipedPatern.Add(line);
					}

					PolyTree ret = new PolyTree();
					Clipper clipper = new Clipper();
					clipper.AddPaths(unclipedPatern, PolyType.ptSubject, false);
					clipper.AddPaths(outlines, PolyType.ptClip, true);
					clipper.Execute(ClipType.ctIntersection, ret, PolyFillType.pftPositive, PolyFillType.pftEvenOdd);

					Polygons newSegments = Clipper.OpenPathsFromPolyTree(ret);
					PointMatrix inversematrix = new PointMatrix((rotation + 90));
					newSegments.ApplyMatrix(inversematrix);

					infillLinesToPrint.AddRange(newSegments);
				}
			}
		}
示例#32
0
        //------------------------------------------------------------------------------

        public static void AddPolyNodeToPolygons(PolyNode polynode, Polygons polygons)
        {
            if (polynode.Contour.Count > 0) 
                polygons.Add(polynode.Contour);
            foreach (PolyNode pn in polynode.Childs)
                AddPolyNodeToPolygons(pn, polygons);
        }
示例#33
0
        //------------------------------------------------------------------------------

        private void BuildResult(Polygons polyg)
        {
            polyg.Clear();
            polyg.Capacity = m_PolyOuts.Count;
            for (int i = 0; i < m_PolyOuts.Count; i++)
            {
                OutRec outRec = m_PolyOuts[i];
                if (outRec.pts == null) continue;
                OutPt p = outRec.pts;
                int cnt = PointCount(p);
                if (cnt < 3) continue;
                Polygon pg = new Polygon(cnt);
                for (int j = 0; j < cnt; j++)
                {
                    pg.Add(p.pt);
                    p = p.prev;
                }
                polyg.Add(pg);
            }
        }
示例#34
0
		public Polygons CreateLineLoops(int pixelsToIntPointsScale, int maxLineLoopsToAdd = int.MaxValue)
		{
			Polygons LineLoops = new Polygons();

			bool[] hasBeenAddedList = new bool[LineSegments.Count];

			for (int segmentToAddIndex = 0; segmentToAddIndex < LineSegments.Count; segmentToAddIndex++)
			{
				if (!hasBeenAddedList[segmentToAddIndex])
				{
					// now find all the connected segments until we get back to this one
					Polygon loopToAdd = new Polygon();

					// walk the loop
					int currentSegmentIndex = segmentToAddIndex;
					LineSegment currentSegment = LineSegments[currentSegmentIndex];
					Vector2 connectionVertex = currentSegment.end;
					loopToAdd.Add(new IntPoint((long)(connectionVertex.x * pixelsToIntPointsScale), (long)(connectionVertex.y * pixelsToIntPointsScale)));
					hasBeenAddedList[currentSegmentIndex] = true;
					bool addedToLoop = false;
					do
					{
						bool foundNextSegment = false;
						addedToLoop = false;
						for (int segmentToCheckIndex = 0; segmentToCheckIndex < LineSegments.Count; segmentToCheckIndex++)
						{
							LineSegment segmentToCheck = LineSegments[segmentToCheckIndex];
							if (!hasBeenAddedList[segmentToCheckIndex])
							{
								if (connectionVertex == segmentToCheck.start)
								{
									connectionVertex = segmentToCheck.end;
									foundNextSegment = true;
								}
								else if (connectionVertex == segmentToCheck.end)
								{
									connectionVertex = segmentToCheck.start;
									foundNextSegment = true;
								}
								else
								{
									int i = 0;
								}

								if (foundNextSegment)
								{
									hasBeenAddedList[segmentToCheckIndex] = true;
									currentSegmentIndex = segmentToCheckIndex;
									currentSegment = segmentToCheck;
									loopToAdd.Add(new IntPoint((long)(connectionVertex.x * pixelsToIntPointsScale), (long)(connectionVertex.y * pixelsToIntPointsScale)));
									addedToLoop = true;
									break;
								}
							}
						}
					} while (addedToLoop);

					LineLoops.Add(loopToAdd);
					if (LineLoops.Count > maxLineLoopsToAdd)
					{
						break;
					}
				}
			}

			return LineLoops;
		}
示例#35
0
		public static void GenerateConcentricInfill(ConfigSettings config, Polygons partOutline, ref Polygons fillPolygons, long extrusionWidthOverride_um = 0)
		{
			if (extrusionWidthOverride_um == 0)
			{
				extrusionWidthOverride_um = config.extrusionWidth_um;
			}

			Polygons outlineCopy = new Polygons(partOutline);
			foreach (Polygon outline in outlineCopy)
			{
				if (outline.Count > 0)
				{
					outline.Add(outline[0]);
				}
			}
			int linespacing_um = (int)(extrusionWidthOverride_um / (config.infillPercent / 100));
			while (outlineCopy.Count > 0)
			{
				for (int outlineIndex = 0; outlineIndex < outlineCopy.Count; outlineIndex++)
				{
					Polygon r = outlineCopy[outlineIndex];
					fillPolygons.Add(r);
				}
				outlineCopy = outlineCopy.Offset(-linespacing_um);
				foreach (Polygon outline in outlineCopy)
				{
					if (outline.Count > 0)
					{
						outline.Add(outline[0]);
					}
				}
			}
		}
示例#36
0
		public static void GenerateHexLinePaths(Polygons in_outline, ref Polygons result, int lineSpacing, int infillExtendIntoPerimeter_um, double rotationDegrees, int layerIndex)
		{
			int extraRotationAngle = 0;
			if (in_outline.Count > 0)
			{
				Polygons outlines = in_outline.Offset(infillExtendIntoPerimeter_um);
				if (outlines.Count > 0)
				{
					int perIncrementOffset = (int)(lineSpacing * Math.Sqrt(3) / 2 + .5);
					PointMatrix matrix = new PointMatrix(-(rotationDegrees + extraRotationAngle)); // we are rotating the part so we rotate by the negative so the lines go the way we expect

					outlines.ApplyMatrix(matrix);

					Aabb boundary = new Aabb(outlines);

					boundary.min.X = ((boundary.min.X / lineSpacing) - 1) * lineSpacing;
					boundary.min.Y = ((boundary.min.Y / perIncrementOffset) - 2) * perIncrementOffset;
					boundary.max.X += lineSpacing;
					boundary.max.Y += perIncrementOffset;
					Polygons unclipedPatern = new Polygons();

					foreach (IntPoint startPoint in StartPositionIterator(boundary, lineSpacing, layerIndex))
					{
						Polygon attachedLine = new Polygon();
						foreach (IntPoint center in IncrementPositionIterator(startPoint, boundary, lineSpacing, layerIndex))
						{
							// what we are adding are the little plusses that define the points
							//        | top
							//        |
							//        /\ center
							//   left/  \ right
							//
							IntPoint left = center + new IntPoint(-lineSpacing / 2, -perIncrementOffset / 3);
							IntPoint right = center + new IntPoint(lineSpacing / 2, -perIncrementOffset / 3);
							IntPoint top = center + new IntPoint(0, perIncrementOffset * 2 / 3);

							switch (layerIndex % 3)
							{
								case 0: // left to right
									attachedLine.Add(left); attachedLine.Add(center);
									attachedLine.Add(center); attachedLine.Add(right);
									unclipedPatern.Add(new Polygon() { top, center });
									break;

								case 1: // left to top
									attachedLine.Add(left); attachedLine.Add(center);
									attachedLine.Add(center); attachedLine.Add(top);
									unclipedPatern.Add(new Polygon() { center, right });
									break;

								case 2: // top to right
									attachedLine.Add(top); attachedLine.Add(center);
									attachedLine.Add(center); attachedLine.Add(right);
									unclipedPatern.Add(new Polygon() { left, center });
									break;
							}
						}
						if (attachedLine.Count > 0)
						{
							unclipedPatern.Add(attachedLine);
						}
					}

					PolyTree ret = new PolyTree();
					Clipper clipper = new Clipper();
					clipper.AddPaths(unclipedPatern, PolyType.ptSubject, false);
					clipper.AddPaths(outlines, PolyType.ptClip, true);
					clipper.Execute(ClipType.ctIntersection, ret, PolyFillType.pftPositive, PolyFillType.pftEvenOdd);

					Polygons newSegments = Clipper.OpenPathsFromPolyTree(ret);
					PointMatrix inversematrix = new PointMatrix((rotationDegrees + extraRotationAngle));
					newSegments.ApplyMatrix(inversematrix);

					result.AddRange(newSegments);
				}
			}
		}
示例#37
0
		public Polygons GetPathsWithOverlapsRemoved(Polygon perimeter, int overlapMergeAmount_um)
		{
			// make a copy that has every point duplicatiod (so that we have them as segments).
			Polygon polySegments = new Polygon(perimeter.Count * 2);
			for (int i = 0; i < perimeter.Count - 1; i++)
			{
				IntPoint point = perimeter[i];
				IntPoint nextPoint = perimeter[i + 1];

				polySegments.Add(point);
				polySegments.Add(nextPoint);
			}

			Altered[] markedAltered = new Altered[polySegments.Count/2];

			int segmentCount = polySegments.Count / 2;
			// now walk every segment and check if there is another segment that is similar enough to merge them together
			for (int firstSegmentIndex = 0; firstSegmentIndex < segmentCount; firstSegmentIndex++)
			{
				int firstPointIndex = firstSegmentIndex * 2;
				for (int checkSegmentIndex = firstSegmentIndex + 1; checkSegmentIndex < segmentCount; checkSegmentIndex++)
				{
					int checkPointIndex = checkSegmentIndex * 2;
					// The first point of start and the last point of check (the path will be coming back on itself).
					long startDelta = (polySegments[firstPointIndex] - polySegments[checkPointIndex + 1]).Length();
					// if the segmets are similar enough
					if (startDelta < overlapMergeAmount_um)
					{
						// The last point of start and the first point of check (the path will be coming back on itself).
						long endDelta = (polySegments[firstPointIndex + 1] - polySegments[checkPointIndex]).Length();
						if (endDelta < overlapMergeAmount_um)
						{
							// move the first segments points to the average of the merge positions
							polySegments[firstPointIndex] = (polySegments[firstPointIndex] + polySegments[checkPointIndex + 1]) / 2; // the start
							polySegments[firstPointIndex + 1] = (polySegments[firstPointIndex + 1] + polySegments[checkPointIndex]) / 2; // the end

							markedAltered[firstSegmentIndex] = Altered.merged;
							// mark this segment for removal
							markedAltered[checkSegmentIndex] = Altered.remove;
							// We only expect to find one match for each segment, so move on to the next segment
							break;
						}
					}
				}
			}

			// Check for perimeter edeges that need to be removed that are the u turns of sectons that go back on themselves.
			//  __________
			// |__________|	->  |--------|  the 2 vertical sections should be removed
			for (int segmentIndex = 0; segmentIndex < segmentCount; segmentIndex++)
			{
				int prevSegmentIndex = (int)((uint)(segmentIndex - 1) % (uint)segmentCount);
				int nextSegmentIndex = (segmentIndex + 1) % segmentCount;
				if ((markedAltered[nextSegmentIndex] == Altered.merged && markedAltered[prevSegmentIndex] == Altered.remove)
					|| (markedAltered[nextSegmentIndex] == Altered.remove && markedAltered[prevSegmentIndex] == Altered.merged))
				{
					markedAltered[segmentIndex] = Altered.remove;
				}
			}

			// remove the marked segments
			for (int segmentIndex = segmentCount - 1; segmentIndex >= 0; segmentIndex--)
			{
				int pointIndex = segmentIndex * 2;
				if (markedAltered[segmentIndex] == Altered.remove)
				{
					polySegments.RemoveRange(pointIndex, 2);
				}
			}

			// go through the polySegmets and create a new polygon for every connected set of segmets
			Polygons separatedPolygons = new Polygons();
			Polygon currentPolygon = new Polygon();
			separatedPolygons.Add(currentPolygon);
			// put in the first point
			for (int segmentIndex = 0; segmentIndex < polySegments.Count; segmentIndex += 2)
			{
				// add the start point
				currentPolygon.Add(polySegments[segmentIndex]);

				// if the next segment is not connected to this one
				if (segmentIndex < polySegments.Count - 2
					&& polySegments[segmentIndex + 1] != polySegments[segmentIndex + 2])
				{
					// add the end point
					currentPolygon.Add(polySegments[segmentIndex + 1]);

					// create a new polygon
					currentPolygon = new Polygon();
					separatedPolygons.Add(currentPolygon);
				}
			}

			// add the end point
			currentPolygon.Add(polySegments[polySegments.Count - 1]);

			return separatedPolygons;
		}
示例#38
0
		public static Polygons CreateFromString(string polygonsPackedString)
		{
			Polygons output = new Polygons();
			string[] polygons = polygonsPackedString.Split('|');
			foreach (string polygonString in polygons)
			{
				Polygon nextPoly = PolygonHelper.CreateFromString(polygonString);
				if (nextPoly.Count > 0)
				{
					output.Add(nextPoly);
				}
			}
			return output;
		}
示例#39
0
		private static void ProcessPolyTreeNodeIntoSeparatIslands(this Polygons polygonsIn, PolyNode node, List<Polygons> ret)
		{
			for (int n = 0; n < node.ChildCount; n++)
			{
				PolyNode child = node.Childs[n];
				Polygons polygons = new Polygons();
				polygons.Add(child.Contour);
				for (int i = 0; i < child.ChildCount; i++)
				{
					polygons.Add(child.Childs[i].Contour);
					polygonsIn.ProcessPolyTreeNodeIntoSeparatIslands(child.Childs[i], ret);
				}
				ret.Add(polygons);
			}
		}
示例#40
0
		public static Polygons DeepCopy(this Polygons polygons)
		{
			Polygons deepCopy = new Polygons();
			foreach (Polygon poly in polygons)
			{
				deepCopy.Add(new Polygon(poly));
			}

			return deepCopy;
		}
示例#41
0
		public bool BridgeAngle(Polygons areaAboveToFill, out double bridgeAngle, string debugName = "")
		{
			SliceLayer layerToRestOn = this;
            bridgeAngle = -1;
			Aabb boundaryBox = new Aabb(areaAboveToFill);
			//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 islandsToRestOn = new Polygons();
			foreach (LayerIsland islandToRestOn in layerToRestOn.Islands)
			{
				if (!boundaryBox.Hit(islandToRestOn.BoundingBox))
				{
					continue;
				}

				islandsToRestOn.AddRange(areaAboveToFill.CreateIntersection(islandToRestOn.IslandOutline));
			}

			if (OUTPUT_DEBUG_DATA)
			{
				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();
			}

			Polygons islandConvexHuls = new Polygons();
			foreach(Polygon poly in islandsToRestOn)
			{
				islandConvexHuls.Add(poly.CreateConvexHull());
			}

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

			if (islandsToRestOn.Count == 1)
			{
				return GetSingleIslandAngle(areaAboveToFill, islandsToRestOn[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 < islandsToRestOn.Count; islandIndex++)
			{
				//Skip internal holes
				if (!islandsToRestOn[islandIndex].Orientation())
				{
					continue;
				}

				double area = Math.Abs(islandConvexHuls[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;
			}

			Polygons big1 = new Polygons() { islandConvexHuls[indexOfBiggest] };
			Polygons big2 = new Polygons() { islandConvexHuls[indexOfNextBigest] };

			Polygons intersection = big1.CreateIntersection(big2);
			if(intersection.Count > 0)
			{
				return GetSingleIslandAngle(areaAboveToFill, islandsToRestOn[indexOfBiggest], out bridgeAngle, debugName);
			}

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

			bridgeAngle = Math.Atan2(center2.Y - center1.Y, center2.X - center1.X) / Math.PI * 180;
			Range0To360(ref bridgeAngle);
			if (OUTPUT_DEBUG_DATA)
			{
				islandsToRestOn.SaveToGCode("{0} - angle {1:0.}.gcode".FormatWith(debugName, bridgeAngle));
			}
			return true;
		}
示例#42
0
		public static Polygons ConvertToLines(Polygons polygons)
		{
			Polygons linePolygons = new Polygons();
			foreach(Polygon polygon in polygons)
			{
				if (polygon.Count > 2)
				{
					for (int vertexIndex = 0; vertexIndex < polygon.Count; vertexIndex++)
					{
						linePolygons.Add(new Polygon() { polygon[vertexIndex], polygon[(vertexIndex + 1) % polygon.Count] });
					}
				}
				else
				{
					linePolygons.Add(polygon);
				}
			}

			return linePolygons;
		}
示例#43
0
        //---------------------------------------------------------------------

        bool LoadFromFile(string filename, Polygons ppg, double scale = 0,
          int xOffset = 0, int yOffset = 0)
        {
            double scaling = Math.Pow(10, scale);
            ppg.Clear();
            if (!File.Exists(filename)) return false;
            StreamReader sr = new StreamReader(filename);
            if (sr == null) return false;
            string line;
            if ((line = sr.ReadLine()) == null) return false;
            int polyCnt, vertCnt;
            if (!Int32.TryParse(line, out polyCnt) || polyCnt < 0) return false;
            ppg.Capacity = polyCnt;
            for (int i = 0; i < polyCnt; i++)
            {
                if ((line = sr.ReadLine()) == null) return false;
                if (!Int32.TryParse(line, out vertCnt) || vertCnt < 0) return false;
                Polygon pg = new Polygon(vertCnt);
                ppg.Add(pg);
                for (int j = 0; j < vertCnt; j++)
                {
                    double x, y;
                    if ((line = sr.ReadLine()) == null) return false;
                    char[] delimiters = new char[] { ',', ' ' };
                    string [] vals = line.Split(delimiters);
                    if (vals.Length < 2) return false;
                    if (!double.TryParse(vals[0], out x)) return false;
                    if (!double.TryParse(vals[1], out y))
                        if (vals.Length < 2 || !double.TryParse(vals[2], out y)) return false;
                    x = x * scaling + xOffset;
                    y = y * scaling + yOffset;
                    pg.Add(new IntPoint((int)Math.Round(x), (int)Math.Round(y)));
                }
            }
            return true;
        }
		static private void GetAreasRecursive(PolyNode polyTreeForPlate, Polygons discreteAreas)
		{
			if (!polyTreeForPlate.IsHole)
			{
				discreteAreas.Add(polyTreeForPlate.Contour);
			}

			foreach (PolyNode child in polyTreeForPlate.Childs)
			{
				GetAreasRecursive(child, discreteAreas);
			}
		}
示例#45
0
		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++;
				}
			}
		}