Exemplo n.º 1
0
        /// <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);
        }