Esempio n. 1
0
        /// <summary>
        /// Populates the edge list
        /// </summary>
        private void PopulateEdgeList()
        {
            var localedges = new List <LineSegment2D>(this.points.Count);

            for (var i = 0; i < this.points.Count - 1; i++)
            {
                var edge = new LineSegment2D(this.points[i], this.points[i + 1]);
                localedges.Add(edge);
            }

            localedges.Add(new LineSegment2D(this.points[this.points.Count - 1], this.points[0])); // complete loop
            this.edges = ImmutableList.Create(localedges);
        }
        /// <summary>
        /// Reduce the complexity of a manifold of points represented as an IEnumerable of Point2D objects.
        /// This algorithm goes through each point in the manifold and computes the error that would be introduced
        /// from the original if that point were removed.  Then it removes nonadjacent points to produce a
        /// reduced size manifold.
        /// </summary>
        /// <param name="points">A list of points</param>
        /// <param name="tolerance">Tolerance (Epsilon) to apply to determine if segments are to be merged.</param>
        /// <returns>A new list of points minus any segment which was merged.</returns>
        private static IEnumerable <Point2D> ReduceComplexitySingleStep(IEnumerable <Point2D> points, double tolerance)
        {
            var manifold     = points.ToList();
            var errorByIndex = new double[manifold.Count];

            // At this point we will loop through the list of points (excluding the first and the last) and
            // examine every adjacent triplet.  The middle point is tested against the segment created by
            // the two end points, and the error that would result in its deletion is computed as the length
            // of the point's projection onto the segment.
            for (var i = 1; i < manifold.Count - 1; i++)
            {
                // TODO: simplify this to remove all of the value copying
                var v0        = manifold[i - 1];
                var v1        = manifold[i];
                var v2        = manifold[i + 1];
                var projected = new LineSegment2D(v0, v2).ClosestPointTo(v1);

                var error = v1.VectorTo(projected).Length;
                errorByIndex[i] = error;
            }

            // Now go through the list of errors and remove nonadjacent points with less than the error tolerance
            var thinnedPoints = new List <Point2D>();
            var preserveMe    = 0;

            for (var i = 0; i < errorByIndex.Length - 1; i++)
            {
                if (i == preserveMe)
                {
                    thinnedPoints.Add(manifold[i]);
                }
                else
                {
                    if (errorByIndex[i] < tolerance)
                    {
                        preserveMe = i + 1;
                    }
                    else
                    {
                        thinnedPoints.Add(manifold[i]);
                    }
                }
            }

            thinnedPoints.Add(manifold.Last());

            return(thinnedPoints);
        }
        /// <summary>
        /// Returns the closest point on the polyline to the given point.
        /// </summary>
        /// <param name="p">a point</param>
        /// <returns>A point which is the closest to the given point but still on the line.</returns>
        public Point2D ClosestPointTo(Point2D p)
        {
            var minError = double.MaxValue;
            var closest  = default(Point2D);

            for (var i = 0; i < this.VertexCount - 1; i++)
            {
                var segment   = new LineSegment2D(this.points[i], this.points[i + 1]);
                var projected = segment.ClosestPointTo(p);
                var error     = p.DistanceTo(projected);
                if (error < minError)
                {
                    minError = error;
                    closest  = projected;
                }
            }

            return(closest);
        }