private ConvexHull2Test()
        {
            _pointCloud1 = new Vertices(PointCount);

            for (int i = 0; i < PointCount; i++)
            {
                float x = Rand.RandomFloat(-10, 10);
                float y = Rand.RandomFloat(-10, 10);

                _pointCloud1.Add(new Vector2(x, y));
            }

            _pointCloud2 = new Vertices(_pointCloud1);
            _pointCloud3 = new Vertices(_pointCloud1);

            //Melkman DOES NOT work on point clouds. It only works on simple polygons.
            _pointCloud1.Translate(new Vector2(-20, 30));
            _melkman = Melkman.GetConvexHull(_pointCloud1);

            //Giftwrap works on point clouds
            _pointCloud2.Translate(new Vector2(20, 30));
            _giftWrap = GiftWrap.GetConvexHull(_pointCloud2);

            //Chain hull also works on point clouds
            _pointCloud3.Translate(new Vector2(20, 10));
            _chainHull = ChainHull.GetConvexHull(_pointCloud3);
        }
Esempio n. 2
0
        /// <summary>
        ///     Describes whether validate polygon
        /// </summary>
        /// <param name="polygon">The polygon</param>
        /// <returns>The bool</returns>
        private static bool ValidatePolygon(Vertices polygon)
        {
            PolygonError errorCode = polygon.CheckPolygon();

            if (errorCode == PolygonError.InvalidAmountOfVertices || errorCode == PolygonError.AreaTooSmall ||
                errorCode == PolygonError.SideTooSmall || errorCode == PolygonError.NotSimple)
            {
                return(false);
            }

            if (
                errorCode ==
                PolygonError
                .NotCounterClockWise)     //NotCounterCloseWise is the last check in CheckPolygon(), thus we don't need to call ValidatePolygon again.
            {
                polygon.Reverse();
            }

            if (errorCode == PolygonError.NotConvex)
            {
                polygon = GiftWrap.GetConvexHull(polygon);
                return(ValidatePolygon(polygon));
            }

            return(true);
        }
        /// <summary>
        /// Updates data for the convex hull of the polygon.
        /// </summary>
        private void UpdateConvexHull()
        {
            // compute convex hull
            Vertices hull = GiftWrap.GetConvexHull(Polygon.Vertices);

            // update polygon lines
            convexHullLines = new PointF[hull.Count];
            for (int i = 0; i < hull.Count; ++i)
            {
                convexHullLines[i] = new PointF(hull[i].X, hull[i].Y);
            }

            // update valid/invalid vertices
            for (int i = 0; i < vertices.Count; ++i)
            {
                int index = hull.IndexOf(Polygon.Vertices[i]);
                if (index == -1)
                {
                    vertices[i] = new KeyValuePair <PointF, bool>(vertices[i].Key, false);
                }
                else
                {
                    vertices[i] = new KeyValuePair <PointF, bool>(vertices[i].Key, true);
                }
            }
        }
Esempio n. 4
0
        /// <summary>
        /// sets the vertices without copying over the data from verts to the local List.
        /// </summary>
        /// <param name="verts">Verts.</param>
        public void SetVerticesNoCopy(Vertices verts)
        {
            Debug.Assert(verts.Count >= 3 && verts.Count <= Settings.MaxPolygonVertices);
            _vertices = verts;

            if (Settings.UseConvexHullPolygons)
            {
                // FPE note: This check is required as the GiftWrap algorithm early exits on triangles
                // So instead of giftwrapping a triangle, we just force it to be clock wise.
                if (_vertices.Count <= 3)
                {
                    _vertices.ForceCounterClockWise();
                }
                else
                {
                    _vertices = GiftWrap.GetConvexHull(_vertices);
                }
            }

            if (_normals == null)
            {
                _normals = new Vertices(_vertices.Count);
            }
            else
            {
                _normals.Clear();
            }

            // Compute normals. Ensure the edges have non-zero length.
            for (var i = 0; i < _vertices.Count; ++i)
            {
                var next = i + 1 < _vertices.Count ? i + 1 : 0;
                var edge = _vertices[next] - _vertices[i];
                Debug.Assert(edge.LengthSquared() > Settings.Epsilon * Settings.Epsilon);

                // FPE optimization: Normals.Add(MathHelper.Cross(edge, 1.0f));
                var temp = new Vector2(edge.Y, -edge.X);
                Nez.Vector2Ext.Normalize(ref temp);
                _normals.Add(temp);
            }

            // Compute the polygon mass data
            ComputeProperties();
        }
        /// <summary>
        /// Makes convex hull from the polygon.
        /// </summary>
        public void MakeConvexHull()
        {
            // compute convex hull
            Vertices hull = GiftWrap.GetConvexHull(Polygon.Vertices);

            // remove all unused vertices from convex hull
            for (int i = 0; i < Polygon.Vertices.Count; ++i)
            {
                int index = hull.IndexOf(Polygon.Vertices[i]);
                if (index == -1)
                {
                    Polygon.Vertices.RemoveAt(i);
                    --i;
                }
            }

            // update data
            UpdateVertices();
        }
        public static List <Vertices> ConvexPartition(Vertices vertices, TriangulationAlgorithm algorithm, bool discardAndFixInvalid = true, float tolerance = 0.001f)
        {
            if (vertices.Count <= 3)
            {
                return new List <Vertices> {
                           vertices
                }
            }
            ;

            List <Vertices> results;

            switch (algorithm)
            {
            case TriangulationAlgorithm.Earclip:
                if (Settings.SkipSanityChecks)
                {
                    Debug.Assert(!vertices.IsCounterClockWise(), "The Earclip algorithm expects the polygon to be clockwise.");
                }
                else
                {
                    if (vertices.IsCounterClockWise())
                    {
                        Vertices temp = new Vertices(vertices);
                        temp.Reverse();
                        results = EarclipDecomposer.ConvexPartition(temp, tolerance);
                    }
                    else
                    {
                        results = EarclipDecomposer.ConvexPartition(vertices, tolerance);
                    }
                }
                break;

            case TriangulationAlgorithm.Bayazit:
                if (Settings.SkipSanityChecks)
                {
                    Debug.Assert(vertices.IsCounterClockWise(), "The polygon is not counter clockwise. This is needed for Bayazit to work correctly.");
                }
                else
                {
                    if (!vertices.IsCounterClockWise())
                    {
                        Vertices temp = new Vertices(vertices);
                        temp.Reverse();
                        results = BayazitDecomposer.ConvexPartition(temp);
                    }
                    else
                    {
                        results = BayazitDecomposer.ConvexPartition(vertices);
                    }
                }
                break;

            case TriangulationAlgorithm.Flipcode:
                if (Settings.SkipSanityChecks)
                {
                    Debug.Assert(vertices.IsCounterClockWise(), "The polygon is not counter clockwise. This is needed for Bayazit to work correctly.");
                }
                else
                {
                    if (!vertices.IsCounterClockWise())
                    {
                        Vertices temp = new Vertices(vertices);
                        temp.Reverse();
                        results = FlipcodeDecomposer.ConvexPartition(temp);
                    }
                    else
                    {
                        results = FlipcodeDecomposer.ConvexPartition(vertices);
                    }
                }
                break;

            case TriangulationAlgorithm.Seidel:
                results = SeidelDecomposer.ConvexPartition(vertices, tolerance);
                break;

            case TriangulationAlgorithm.SeidelTrapezoids:
                results = SeidelDecomposer.ConvexPartitionTrapezoid(vertices, tolerance);
                break;

            case TriangulationAlgorithm.Delauny:
                results = CDTDecomposer.ConvexPartition(vertices);
                break;

            default:
                throw new ArgumentOutOfRangeException("algorithm");
            }

            if (discardAndFixInvalid)
            {
                for (int i = results.Count - 1; i >= 0; i--)
                {
                    Vertices polygon = results[i];

                    PolygonError errorCode = polygon.CheckPolygon();

                    if (errorCode == PolygonError.InvalidAmountOfVertices || errorCode == PolygonError.AreaTooSmall || errorCode == PolygonError.SideTooSmall || errorCode == PolygonError.NotSimple)
                    {
                        results.RemoveAt(i);
                    }
                    else if (errorCode == PolygonError.NotCounterClockWise)
                    {
                        polygon.Reverse();
                    }
                    else if (errorCode == PolygonError.NotConvex)
                    {
                        results[i] = GiftWrap.GetConvexHull(polygon);
                    }
                }
            }

            return(results);
        }
    }