/// <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); }