/// <summary> /// Clips the given polylines to the given clipping region. Using the specified viewport extents, this /// routine also eliminates duplicate points that would otherwise occur after the viewport transformation. /// </summary> /// <typeparam name="P"> Output polyline type. </typeparam> /// <typeparam name="T"> Input point type. </typeparam> /// <param name="sz"> Viewport extents. </param> /// <param name="rc"> Logical clipping rectangle. </param> /// <param name="polylines"> Input polylines. </param> /// <param name="convPnt"> Function converting an input point of type T to System.Windows.Point. </param> /// <param name="addPnt"> Procedure adding a System.Windows.Point to the resulting polyline of type P. </param> /// <param name="reductionOnly">Specifies that only the reduction should be performed without clipping.</param> /// <returns> The reduced and optionally clipped polyline. </returns> public static ICollection <P> ClipPolylineReducePoints <P, T>(Size sz, Rect rc, ICollection <ICollection <T> > polylines, Func <T, Point> convPnt, Action <P, Point> addPnt, bool reductionOnly) where P : class, new() { // re-initialize rc, assuring left <= right and top <= bottom rc = new Rect(Math.Min(rc.Left, rc.Right), Math.Min(rc.Top, rc.Bottom), Math.Abs(rc.Width), Math.Abs(rc.Height)); // create result object storing the clipped lines var polylineBuilder = new PolylineBuilder <P>(addPnt, new Size(rc.Width / sz.Width, rc.Height / sz.Height)); if (polylines == null) { return(polylineBuilder.Polyline); } // loop through given polylines foreach (ICollection <T> polyline in polylines) { // enumerator for accessing points IEnumerator <T> e = polyline?.GetEnumerator(); // fetch first point if (e == null || !e.MoveNext()) { continue; } // initialize starting point var p0 = convPnt(e.Current); // number of points in current polyline int lastPointIndex = polyline.Count - 1; // loop through remaining points for (int pointIndex = 1; e.MoveNext(); ++pointIndex) { // fetch end point. p0 and p1 now mark the start and end point of the current line. var p1 = convPnt(e.Current); // clip the current line. CohenSutherland.clip returns true, if any section of the current line is visible. if (reductionOnly || CohenSutherlandClipping.Clip(rc, ref p0, ref p1)) { // Append current line. Append also does the magic of point reduction and line splitting polylines where necessary. polylineBuilder.Append(p0, pointIndex == 1, p1, pointIndex == lastPointIndex); } // current end point is the next starting point p0 = convPnt(e.Current); } } // return the polyline return(polylineBuilder.Polyline); }