Esempio n. 1
0
    protected virtual void ConvertToConvex(FSConcaveShapeComponent targetCSC)
    {
        FSShapeComponent[] childcomps = targetCSC.GetComponentsInChildren <FSShapeComponent>();
        if (childcomps != null)
        {
            if (childcomps.Length > 0)
            {
                for (int i = 0; i < childcomps.Length; i++)
                {
                    if (childcomps[i] == null)
                    {
                        continue;
                    }
                    if (childcomps[i].gameObject == null)
                    {
                        continue;
                    }
                    DestroyImmediate(childcomps[i].gameObject);
                }
            }
        }
        // convert vertices
        FarseerPhysics.Common.Vertices concaveVertices = new FarseerPhysics.Common.Vertices();

        if (targetCSC.PointInput == FSShapePointInput.Transform)
        {
            for (int i = 0; i < targetCSC.TransformPoints.Length; i++)
            {
                concaveVertices.Add(FSHelper.Vector3ToFVector2(targetCSC.TransformPoints[i].localPosition));
            }
        }
        List <FarseerPhysics.Common.Vertices> convexShapeVs = FarseerPhysics.Common.Decomposition.BayazitDecomposer.ConvexPartition(concaveVertices);

        for (int i = 0; i < convexShapeVs.Count; i++)
        {
            GameObject newConvShape = new GameObject("convexShape" + i.ToString());
            newConvShape.transform.parent        = targetCSC.transform;
            newConvShape.transform.localPosition = Vector3.zero;
            newConvShape.transform.localRotation = Quaternion.Euler(Vector3.zero);
            newConvShape.transform.localScale    = Vector3.one;
            FSShapeComponent shape0 = newConvShape.AddComponent <FSShapeComponent>();
            shape0.CollidesWith     = targetCSC.CollidesWith;
            shape0.CollisionFilter  = targetCSC.CollisionFilter;
            shape0.BelongsTo        = targetCSC.BelongsTo;
            shape0.CollisionGroup   = targetCSC.CollisionGroup;
            shape0.Friction         = targetCSC.Friction;
            shape0.Restitution      = targetCSC.Restitution;
            shape0.Density          = targetCSC.Density;
            shape0.UseUnityCollider = false;
            shape0.PolygonPoints    = new Transform[convexShapeVs[i].Count];
            for (int j = 0; j < convexShapeVs[i].Count; j++)
            {
                GameObject pnew = new GameObject("p" + j.ToString());
                pnew.transform.parent        = shape0.transform;
                pnew.transform.localPosition = FSHelper.FVector2ToVector3(convexShapeVs[i][j]);
                shape0.PolygonPoints[j]      = pnew.transform;
            }
        }
    }
    public void ConvertToConvex()
    {
        FSShapeComponent[] childFsShapes = GetComponentsInChildren <FSShapeComponent>();

        foreach (FSShapeComponent shapeComponent in childFsShapes)
        {
            if (shapeComponent.gameObject == null)
            {
                continue;
            }
            DestroyImmediate(shapeComponent.gameObject);
        }
        // convert vertices
        var concaveVertices = new FarseerPhysics.Common.Vertices();

        if (PointInput == FSShapePointInput.Transform)
        {
            for (int i = 0; i < PointsTransforms.Length; i++)
            {
                concaveVertices.Add(FSHelper.Vector3ToFVector2(PointsTransforms[i].localPosition));
            }
        }

        if (PointInput == FSShapePointInput.Vector2List)
        {
            foreach (var coordinate in PointsCoordinates)
            {
                concaveVertices.Add(FSHelper.Vector2ToFVector2(transform.TransformPoint(coordinate)));
            }
        }

        List <FarseerPhysics.Common.Vertices> convexShapeVs =
            FarseerPhysics.Common.Decomposition.BayazitDecomposer.ConvexPartition(concaveVertices);

        for (int i = 0; i < convexShapeVs.Count; i++)
        {
            var newConvShape = new GameObject("convexShape" + i.ToString());
            newConvShape.transform.parent        = transform;
            newConvShape.transform.localPosition = Vector3.zero;
            newConvShape.transform.localRotation = Quaternion.Euler(Vector3.zero);
            newConvShape.transform.localScale    = Vector3.one;

            var shapeComponent = newConvShape.AddComponent <FSShapeComponent>();
            shapeComponent.CollidesWith     = CollidesWith;
            shapeComponent.CollisionFilter  = CollisionFilter;
            shapeComponent.BelongsTo        = BelongsTo;
            shapeComponent.CollisionGroup   = CollisionGroup;
            shapeComponent.Friction         = Friction;
            shapeComponent.Restitution      = Restitution;
            shapeComponent.Density          = Density;
            shapeComponent.UseUnityCollider = false;
            shapeComponent.UseTransforms    = (PointInput == FSShapePointInput.Transform);

            if (PointInput == FSShapePointInput.Transform)
            {
                shapeComponent.PolygonTransforms = new Transform[convexShapeVs[i].Count];
                for (int j = 0; j < convexShapeVs[i].Count; j++)
                {
                    var pnew = new GameObject("p" + j.ToString(CultureInfo.InvariantCulture));
                    pnew.transform.parent               = shapeComponent.transform;
                    pnew.transform.localPosition        = FSHelper.FVector2ToVector3(convexShapeVs[i][j]);
                    shapeComponent.PolygonTransforms[j] = pnew.transform;
                }
            }
            else
            {
                shapeComponent.PolygonCoordinates = new Vector2[convexShapeVs[i].Count];
                for (int j = 0; j < convexShapeVs[i].Count; j++)
                {
                    shapeComponent.PolygonCoordinates[j] = newConvShape.transform.InverseTransformPoint(FSHelper.FVector2ToVector3(convexShapeVs[i][j]));
                }
            }
        }
    }
Esempio n. 3
0
        // From Eric Jordan's convex decomposition library

        /// <summary>
        /// Checks if polygon is valid for use in Box2d engine.
        /// Last ditch effort to ensure no invalid polygons are
        /// added to world geometry.
        ///
        /// Performs a full check, for simplicity, convexity,
        /// orientation, minimum angle, and volume.  This won't
        /// be very efficient, and a lot of it is redundant when
        /// other tools in this section are used.
        /// </summary>
        /// <returns></returns>
        public bool CheckPolygon()
        {
            int error = -1;

            if (Count < 3 || Count > Settings.MaxPolygonVertices)
            {
                error = 0;
            }
            if (!IsConvex())
            {
                error = 1;
            }
            if (!IsSimple())
            {
                error = 2;
            }
            if (GetArea() < Settings.Epsilon)
            {
                error = 3;
            }

            //Compute normals
            Vector2[] normals  = new Vector2[Count];
            Vertices  vertices = new Vertices(Count);
            var       elements = Elements;

            for (int i = 0; i < count; ++i)
            {
                vertices.Add(new Vector2(elements[i].X, elements[i].Y));
                int     i1   = i;
                int     i2   = i + 1 < Count ? i + 1 : 0;
                Vector2 edge = new Vector2(elements[i2].X - elements[i1].X, elements[i2].Y - elements[i1].Y);
                normals[i] = MathUtils.Cross(edge, 1.0f);
                normals[i].Normalize();
            }

            //Required side checks
            for (int i = 0; i < count; ++i)
            {
                int iminus = (i == 0) ? count - 1 : i - 1;

                //Parallel sides check
                float cross = MathUtils.Cross(normals[iminus], normals[i]);
                cross = MathHelper.Clamp(cross, -1.0f, 1.0f);
                float angle = (float)Math.Asin(cross);
                if (angle <= Settings.AngularSlop)
                {
                    error = 4;
                    break;
                }

                //Too skinny check
                for (int j = 0; j < count; ++j)
                {
                    if (j == i || j == (i + 1) % Count)
                    {
                        continue;
                    }
                    float s = Vector2.Dot(normals[i], vertices[j] - vertices[i]);
                    if (s >= -Settings.LinearSlop)
                    {
                        error = 5;
                    }
                }


                Vector2 centroid = vertices.GetCentroid();
                Vector2 n1       = normals[iminus];
                Vector2 n2       = normals[i];
                Vector2 v        = vertices[i] - centroid;

                Vector2 d = new Vector2();
                d.X = Vector2.Dot(n1, v); // - toiSlop;
                d.Y = Vector2.Dot(n2, v); // - toiSlop;

                // Shifting the edge inward by toiSlop should
                // not cause the plane to pass the centroid.
                if ((d.X < 0.0f) || (d.Y < 0.0f))
                {
                    error = 6;
                }
            }

            if (error != -1)
            {
                Debug.WriteLine("Found invalid polygon, ");
                switch (error)
                {
                case 0:
                    Debug.WriteLine(string.Format("must have between 3 and {0} vertices.\n",
                                                  Settings.MaxPolygonVertices));
                    break;

                case 1:
                    Debug.WriteLine("must be convex.\n");
                    break;

                case 2:
                    Debug.WriteLine("must be simple (cannot intersect itself).\n");
                    break;

                case 3:
                    Debug.WriteLine("area is too small.\n");
                    break;

                case 4:
                    Debug.WriteLine("sides are too close to parallel.\n");
                    break;

                case 5:
                    Debug.WriteLine("polygon is too thin.\n");
                    break;

                case 6:
                    Debug.WriteLine("core shape generation would move edge past centroid (too thin).\n");
                    break;

                default:
                    Debug.WriteLine("don't know why.\n");
                    break;
                }
            }
            return(error != -1);
        }
Esempio n. 4
0
        // From Eric Jordan's convex decomposition library

        /// <summary>
        /// Trace the edge of a non-simple polygon and return a simple polygon.
        ///
        /// Method:
        /// Start at vertex with minimum y (pick maximum x one if there are two).
        /// We aim our "lastDir" vector at (1.0, 0)
        /// We look at the two rays going off from our start vertex, and follow whichever
        /// has the smallest angle (in -Pi . Pi) wrt lastDir ("rightest" turn)
        /// Loop until we hit starting vertex:
        /// We add our current vertex to the list.
        /// We check the seg from current vertex to next vertex for intersections
        /// - if no intersections, follow to next vertex and continue
        /// - if intersections, pick one with minimum distance
        /// - if more than one, pick one with "rightest" next point (two possibilities for each)
        /// </summary>
        /// <param name="verts">The vertices.</param>
        /// <returns></returns>
        public Vertices TraceEdge(Vertices verts)
        {
            PolyNode[] nodes = new PolyNode[verts.Count * verts.Count];
            //overkill, but sufficient (order of mag. is right)
            int nNodes = 0;

            //Add base nodes (raw outline)
            for (int i = 0; i < verts.Count; ++i)
            {
                Vector2 pos = new Vector2(verts[i].x, verts[i].y);
                nodes[i].Position = pos;
                ++nNodes;
                int iplus  = (i == verts.Count - 1) ? 0 : i + 1;
                int iminus = (i == 0) ? verts.Count - 1 : i - 1;
                nodes[i].AddConnection(nodes[iplus]);
                nodes[i].AddConnection(nodes[iminus]);
            }

            //Process intersection nodes - horribly inefficient
            bool dirty   = true;
            int  counter = 0;

            while (dirty)
            {
                dirty = false;
                for (int i = 0; i < nNodes; ++i)
                {
                    for (int j = 0; j < nodes[i].NConnected; ++j)
                    {
                        for (int k = 0; k < nNodes; ++k)
                        {
                            if (k == i || nodes[k] == nodes[i].Connected[j])
                            {
                                continue;
                            }
                            for (int l = 0; l < nodes[k].NConnected; ++l)
                            {
                                if (nodes[k].Connected[l] == nodes[i].Connected[j] ||
                                    nodes[k].Connected[l] == nodes[i])
                                {
                                    continue;
                                }

                                //Check intersection
                                Vector2 intersectPt;

                                bool crosses = LineTools.LineIntersect(nodes[i].Position, nodes[i].Connected[j].Position,
                                                                       nodes[k].Position, nodes[k].Connected[l].Position,
                                                                       out intersectPt);
                                if (crosses)
                                {
                                    dirty = true;
                                    //Destroy and re-hook connections at crossing point
                                    PolyNode connj = nodes[i].Connected[j];
                                    PolyNode connl = nodes[k].Connected[l];
                                    nodes[i].Connected[j].RemoveConnection(nodes[i]);
                                    nodes[i].RemoveConnection(connj);
                                    nodes[k].Connected[l].RemoveConnection(nodes[k]);
                                    nodes[k].RemoveConnection(connl);
                                    nodes[nNodes] = new PolyNode(intersectPt);
                                    nodes[nNodes].AddConnection(nodes[i]);
                                    nodes[i].AddConnection(nodes[nNodes]);
                                    nodes[nNodes].AddConnection(nodes[k]);
                                    nodes[k].AddConnection(nodes[nNodes]);
                                    nodes[nNodes].AddConnection(connj);
                                    connj.AddConnection(nodes[nNodes]);
                                    nodes[nNodes].AddConnection(connl);
                                    connl.AddConnection(nodes[nNodes]);
                                    ++nNodes;
                                    goto SkipOut;
                                }
                            }
                        }
                    }
                }
SkipOut:
                ++counter;
            }

            //Collapse duplicate points
            bool foundDupe = true;
            int  nActive   = nNodes;

            while (foundDupe)
            {
                foundDupe = false;
                for (int i = 0; i < nNodes; ++i)
                {
                    if (nodes[i].NConnected == 0)
                    {
                        continue;
                    }
                    for (int j = i + 1; j < nNodes; ++j)
                    {
                        if (nodes[j].NConnected == 0)
                        {
                            continue;
                        }
                        Vector2 diff = nodes[i].Position - nodes[j].Position;
                        if (diff.sqrMagnitude <= Settings.Epsilon * Settings.Epsilon)
                        {
                            if (nActive <= 3)
                            {
                                return(new Vertices());
                            }

                            //printf("Found dupe, %d left\n",nActive);
                            --nActive;
                            foundDupe = true;
                            PolyNode inode = nodes[i];
                            PolyNode jnode = nodes[j];
                            //Move all of j's connections to i, and orphan j
                            int njConn = jnode.NConnected;
                            for (int k = 0; k < njConn; ++k)
                            {
                                PolyNode knode = jnode.Connected[k];
                                //Debug.Assert(knode != jnode);
                                if (knode != inode)
                                {
                                    inode.AddConnection(knode);
                                    knode.AddConnection(inode);
                                }
                                knode.RemoveConnection(jnode);
                            }
                            jnode.NConnected = 0;
                        }
                    }
                }
            }

            //Now walk the edge of the list

            //Find node with minimum y value (max x if equal)
            float minY      = float.MaxValue;
            float maxX      = -float.MaxValue;
            int   minYIndex = -1;

            for (int i = 0; i < nNodes; ++i)
            {
                if (nodes[i].Position.y < minY && nodes[i].NConnected > 1)
                {
                    minY      = nodes[i].Position.y;
                    minYIndex = i;
                    maxX      = nodes[i].Position.x;
                }
                else if (nodes[i].Position.y == minY && nodes[i].Position.x > maxX && nodes[i].NConnected > 1)
                {
                    minYIndex = i;
                    maxX      = nodes[i].Position.x;
                }
            }

            Vector2 origDir = new Vector2(1.0f, 0.0f);

            Vector2[] resultVecs = new Vector2[4 * nNodes];
            // nodes may be visited more than once, unfortunately - change to growable array!
            int      nResultVecs = 0;
            PolyNode currentNode = nodes[minYIndex];
            PolyNode startNode   = currentNode;
            //Debug.Assert(currentNode.NConnected > 0);
            PolyNode nextNode = currentNode.GetRightestConnection(origDir);

            if (nextNode == null)
            {
                Vertices vertices = new Vertices(nResultVecs);

                for (int i = 0; i < nResultVecs; ++i)
                {
                    vertices.Add(resultVecs[i]);
                }

                return(vertices);
            }

            // Borked, clean up our mess and return
            resultVecs[0] = startNode.Position;
            ++nResultVecs;
            while (nextNode != startNode)
            {
                if (nResultVecs > 4 * nNodes)
                {
                    //Debug.Assert(false);
                }
                resultVecs[nResultVecs++] = nextNode.Position;
                PolyNode oldNode = currentNode;
                currentNode = nextNode;
                nextNode    = currentNode.GetRightestConnection(oldNode);
                if (nextNode == null)
                {
                    Vertices vertices = new Vertices(nResultVecs);
                    for (int i = 0; i < nResultVecs; ++i)
                    {
                        vertices.Add(resultVecs[i]);
                    }
                    return(vertices);
                }
                // There was a problem, so jump out of the loop and use whatever garbage we've generated so far
            }

            return(new Vertices());
        }
Esempio n. 5
0
        // From Eric Jordan's convex decomposition library

        /// <summary>
        /// Checks if polygon is valid for use in Box2d engine.
        /// Last ditch effort to ensure no invalid polygons are
        /// added to world geometry.
        ///
        /// Performs a full check, for simplicity, convexity,
        /// orientation, minimum angle, and volume.  This won't
        /// be very efficient, and a lot of it is redundant when
        /// other tools in this section are used.
        /// </summary>
        /// <returns></returns>
        public bool CheckPolygon(out int error, out string errorMessage)
        {
            error        = -1;
            errorMessage = null;

            if (Count < 3 || Count > Settings.MaxPolygonVertices)
            {
                error = 0;
            }
            if (!IsConvex())
            {
                error = 1;
            }
            if (!IsSimple())
            {
                error = 2;
            }
            if (GetArea() < Settings.Epsilon)
            {
                error = 3;
            }

            //Compute normals
            Vector2[] normals  = new Vector2[Count];
            Vertices  vertices = new Vertices(Count);

            for (int i = 0; i < Count; ++i)
            {
                vertices.Add(new Vector2(this[i].x, this[i].y));
                int     i1   = i;
                int     i2   = i + 1 < Count ? i + 1 : 0;
                Vector2 edge = new Vector2(this[i2].x - this[i1].x, this[i2].y - this[i1].y);
                normals[i] = MathUtils.Cross(edge, 1.0f);
                normals[i].Normalize();
            }

            //Required side checks
            for (int i = 0; i < Count; ++i)
            {
                int iminus = (i == 0) ? Count - 1 : i - 1;

                //Parallel sides check
                float cross = MathUtils.Cross(normals[iminus], normals[i]);
                cross = MathUtils.Clamp(cross, -1.0f, 1.0f);
                float angle = Mathf.Asin(cross);
                if (angle <= Settings.AngularSlop)
                {
                    error = 4;
                    break;
                }

                //Too skinny check
                for (int j = 0; j < Count; ++j)
                {
                    if (j == i || j == (i + 1) % Count)
                    {
                        continue;
                    }
                    float s = Vector2.Dot(normals[i], vertices[j] - vertices[i]);
                    if (s >= -Settings.LinearSlop)
                    {
                        error = 5;
                    }
                }


                Vector2 centroid = vertices.GetCentroid();
                Vector2 n1       = normals[iminus];
                Vector2 n2       = normals[i];
                Vector2 v        = vertices[i] - centroid;

                Vector2 d = new Vector2();
                d.x = Vector2.Dot(n1, v); // - toiSlop;
                d.y = Vector2.Dot(n2, v); // - toiSlop;

                // Shifting the edge inward by toiSlop should
                // not cause the plane to pass the centroid.
                if ((d.x < 0.0f) || (d.y < 0.0f))
                {
                    error = 6;
                }
            }

            if (error != -1)
            {
                switch (error)
                {
                case 0:
                    errorMessage = string.Format("Polygon error: must have between 3 and {0} vertices.",
                                                 Settings.MaxPolygonVertices);
                    break;

                case 1:
                    errorMessage = "Polygon error: must be convex.";
                    break;

                case 2:
                    errorMessage = "Polygon error: must be simple (cannot intersect itself).";
                    break;

                case 3:
                    errorMessage = "Polygon error: area is too small.";
                    break;

                case 4:
                    errorMessage = "Polygon error: sides are too close to parallel.";
                    break;

                case 5:
                    errorMessage = "Polygon error: polygon is too thin.";
                    break;

                case 6:
                    errorMessage = "Polygon error: core shape generation would move edge past centroid (too thin).";
                    break;

                default:
                    errorMessage = "Polygon error: error " + error.ToString();
                    break;
                }
            }
            return(error != -1);
        }
        //Rounded rectangle contributed by Jonathan Smars - [email protected]

        /// <summary>
        /// Creates a rounded rectangle with the specified width and height.
        /// </summary>
        /// <param name="width">The width.</param>
        /// <param name="height">The height.</param>
        /// <param name="xRadius">The rounding X radius.</param>
        /// <param name="yRadius">The rounding Y radius.</param>
        /// <param name="segments">The number of segments to subdivide the edges.</param>
        /// <returns></returns>
        public static Vertices CreateRoundedRectangle(float width, float height, float xRadius, float yRadius,
                                                      int segments)
        {
            if (yRadius > height / 2 || xRadius > width / 2)
            {
                throw new Exception("Rounding amount can't be more than half the height and width respectively.");
            }
            if (segments < 0)
            {
                throw new Exception("Segments must be zero or more.");
            }

            //We need at least 8 vertices to create a rounded rectangle
            Debug.Assert(Settings.MaxPolygonVertices >= 8);

            Vertices vertices = new Vertices();

            if (segments == 0)
            {
                vertices.Add(new Vector2(width * .5f - xRadius, -height * .5f));
                vertices.Add(new Vector2(width * .5f, -height * .5f + yRadius));

                vertices.Add(new Vector2(width * .5f, height * .5f - yRadius));
                vertices.Add(new Vector2(width * .5f - xRadius, height * .5f));

                vertices.Add(new Vector2(-width * .5f + xRadius, height * .5f));
                vertices.Add(new Vector2(-width * .5f, height * .5f - yRadius));

                vertices.Add(new Vector2(-width * .5f, -height * .5f + yRadius));
                vertices.Add(new Vector2(-width * .5f + xRadius, -height * .5f));
            }
            else
            {
                int numberOfEdges = (segments * 4 + 8);

                float stepSize = MathHelper.TwoPi / (numberOfEdges - 4);
                int   perPhase = numberOfEdges / 4;

                Vector2 posOffset = new Vector2(width / 2 - xRadius, height / 2 - yRadius);
                vertices.Add(posOffset + new Vector2(xRadius, -yRadius + yRadius));
                short phase = 0;
                for (int i = 1; i < numberOfEdges; i++)
                {
                    if (i - perPhase == 0 || i - perPhase * 3 == 0)
                    {
                        posOffset.X *= -1;
                        phase--;
                    }
                    else if (i - perPhase * 2 == 0)
                    {
                        posOffset.Y *= -1;
                        phase--;
                    }

                    vertices.Add(posOffset + new Vector2(xRadius * (float)Math.Cos(stepSize * -(i + phase)),
                                                         -yRadius * (float)Math.Sin(stepSize * -(i + phase))));
                }
            }

            return(vertices);
        }
        /// <summary>
        /// Creates an capsule with the specified  height, radius and number of edges.
        /// A capsule has the same form as a pill capsule.
        /// </summary>
        /// <param name="height">Height (inner height + radii) of the capsule.</param>
        /// <param name="topRadius">Radius of the top.</param>
        /// <param name="topEdges">The number of edges of the top. The more edges, the more it resembles an capsule</param>
        /// <param name="bottomRadius">Radius of bottom.</param>
        /// <param name="bottomEdges">The number of edges of the bottom. The more edges, the more it resembles an capsule</param>
        /// <returns></returns>
        public static Vertices CreateCapsule(float height, float topRadius, int topEdges, float bottomRadius,
                                             int bottomEdges)
        {
            if (height <= 0)
            {
                throw new ArgumentException("Height must be longer than 0", "height");
            }

            if (topRadius <= 0)
            {
                throw new ArgumentException("The top radius must be more than 0", "topRadius");
            }

            if (topEdges <= 0)
            {
                throw new ArgumentException("Top edges must be more than 0", "topEdges");
            }

            if (bottomRadius <= 0)
            {
                throw new ArgumentException("The bottom radius must be more than 0", "bottomRadius");
            }

            if (bottomEdges <= 0)
            {
                throw new ArgumentException("Bottom edges must be more than 0", "bottomEdges");
            }

            if (topRadius >= height / 2)
            {
                throw new ArgumentException(
                          "The top radius must be lower than height / 2. Higher values of top radius would create a circle, and not a half circle.",
                          "topRadius");
            }

            if (bottomRadius >= height / 2)
            {
                throw new ArgumentException(
                          "The bottom radius must be lower than height / 2. Higher values of bottom radius would create a circle, and not a half circle.",
                          "bottomRadius");
            }

            Vertices vertices = new Vertices();

            float newHeight = (height - topRadius - bottomRadius) * 0.5f;

            // top
            vertices.Add(new Vector2(topRadius, newHeight));

            float stepSize = MathHelper.Pi / topEdges;

            for (int i = 1; i < topEdges; i++)
            {
                vertices.Add(new Vector2(topRadius * (float)Math.Cos(stepSize * i),
                                         topRadius * (float)Math.Sin(stepSize * i) + newHeight));
            }

            vertices.Add(new Vector2(-topRadius, newHeight));

            // bottom
            vertices.Add(new Vector2(-bottomRadius, -newHeight));

            stepSize = MathHelper.Pi / bottomEdges;
            for (int i = 1; i < bottomEdges; i++)
            {
                vertices.Add(new Vector2(-bottomRadius * (float)Math.Cos(stepSize * i),
                                         -bottomRadius * (float)Math.Sin(stepSize * i) - newHeight));
            }

            vertices.Add(new Vector2(bottomRadius, -newHeight));

            return(vertices);
        }
        private static Vertices CreateSimplePolygon(PolygonCreationAssistance pca, Vector2 entrance, Vector2 last)
        {
            bool entranceFound = false;
            bool endOfHull     = false;

            Vertices polygon       = new Vertices();
            Vertices hullArea      = new Vertices();
            Vertices endOfHullArea = new Vertices();

            Vector2 current = Vector2.Zero;

            #region Entrance check

            // Get the entrance point. //todo: alle möglichkeiten testen
            if (entrance == Vector2.Zero || !pca.InBounds(entrance))
            {
                entranceFound = GetHullEntrance(pca, out entrance);

                if (entranceFound)
                {
                    current = new Vector2(entrance.X - 1f, entrance.Y);
                }
            }
            else
            {
                if (pca.IsSolid(entrance))
                {
                    if (IsNearPixel(pca, entrance, last))
                    {
                        current       = last;
                        entranceFound = true;
                    }
                    else
                    {
                        Vector2 temp;
                        if (SearchNearPixels(pca, false, entrance, out temp))
                        {
                            current       = temp;
                            entranceFound = true;
                        }
                        else
                        {
                            entranceFound = false;
                        }
                    }
                }
            }

            #endregion

            if (entranceFound)
            {
                polygon.Add(entrance);
                hullArea.Add(entrance);

                Vector2 next = entrance;

                do
                {
                    // Search in the pre vision list for an outstanding point.
                    Vector2 outstanding;
                    if (SearchForOutstandingVertex(hullArea, pca.HullTolerance, out outstanding))
                    {
                        if (endOfHull)
                        {
                            // We have found the next pixel, but is it on the last bit of the hull?
                            if (endOfHullArea.Contains(outstanding))
                            {
                                // Indeed.
                                polygon.Add(outstanding);
                            }

                            // That's enough, quit.
                            break;
                        }

                        // Add it and remove all vertices that don't matter anymore
                        // (all the vertices before the outstanding).
                        polygon.Add(outstanding);
                        hullArea.RemoveRange(0, hullArea.IndexOf(outstanding));
                    }

                    // Last point gets current and current gets next. Our little spider is moving forward on the hull ;).
                    last    = current;
                    current = next;

                    // Get the next point on hull.
                    if (GetNextHullPoint(pca, ref last, ref current, out next))
                    {
                        // Add the vertex to a hull pre vision list.
                        hullArea.Add(next);
                    }
                    else
                    {
                        // Quit
                        break;
                    }

                    if (next == entrance && !endOfHull)
                    {
                        // It's the last bit of the hull, search on and exit at next found vertex.
                        endOfHull = true;
                        endOfHullArea.AddRange(hullArea);
                    }
                } while (true);
            }

            return(polygon);
        }