/// <summary>Approximates a given Path with a List of Point objects</summary>
        /// <param name="path">input path</param>
        private static IList <Point> GetPathApproximation(Path path)
        {
            IList <Point> approx = new ApproxPoints();

            foreach (Subpath subpath in path.GetSubpaths())
            {
                approx.AddAll(subpath.GetPiecewiseLinearApproximation());
            }
            return(approx);
        }
        private Path FilterStrokePath(Path sourcePath, Matrix ctm, float lineWidth, int lineCapStyle, int lineJoinStyle
                                      , float miterLimit, LineDashPattern lineDashPattern)
        {
            Path     path     = sourcePath;
            JoinType joinType = ClipperBridge.GetJoinType(lineJoinStyle);
            EndType  endType  = ClipperBridge.GetEndType(lineCapStyle);

            if (lineDashPattern != null)
            {
                if (!lineDashPattern.IsSolid())
                {
                    path = LineDashPattern.ApplyDashPattern(path, lineDashPattern);
                }
            }
            ClipperOffset offset = new ClipperOffset(miterLimit, PdfCleanUpTool.arcTolerance * PdfCleanUpTool.floatMultiplier
                                                     );
            IList <Subpath> degenerateSubpaths = ClipperBridge.AddPath(offset, path, joinType, endType);
            PolyTree        resultTree         = new PolyTree();

            offset.Execute(ref resultTree, lineWidth * PdfCleanUpTool.floatMultiplier / 2);
            Path offsetedPath = ClipperBridge.ConvertToPath(resultTree);

            if (degenerateSubpaths.Count > 0)
            {
                if (endType == EndType.OPEN_ROUND)
                {
                    IList <Subpath> circles = ConvertToCircles(degenerateSubpaths, lineWidth / 2);
                    offsetedPath.AddSubpaths(circles);
                }
                else
                {
                    if (endType == EndType.OPEN_SQUARE && lineDashPattern != null)
                    {
                        IList <Subpath> squares = ConvertToSquares(degenerateSubpaths, lineWidth, sourcePath);
                        offsetedPath.AddSubpaths(squares);
                    }
                }
            }
            return(FilterFillPath(offsetedPath, ctm, PdfCanvasConstants.FillingRule.NONZERO_WINDING));
        }
        /// <summary>Note: this method will close all unclosed subpaths of the passed path.</summary>
        /// <param name="fillingRule">If the subpath is contour, pass any value.</param>
        protected internal virtual Path FilterFillPath(Path path, Matrix ctm, int fillingRule)
        {
            path.CloseAllSubpaths();
            Clipper clipper = new Clipper();

            ClipperBridge.AddPath(clipper, path, PolyType.SUBJECT);
            foreach (Rectangle rectangle in regions)
            {
                Point[] transfRectVertices = TransformPoints(ctm, true, GetRectangleVertices(rectangle));
                ClipperBridge.AddRectToClipper(clipper, transfRectVertices, PolyType.CLIP);
            }
            PolyFillType fillType = PolyFillType.NON_ZERO;

            if (fillingRule == PdfCanvasConstants.FillingRule.EVEN_ODD)
            {
                fillType = PolyFillType.EVEN_ODD;
            }
            PolyTree resultTree = new PolyTree();

            clipper.Execute(ClipType.DIFFERENCE, resultTree, fillType, PolyFillType.NON_ZERO);
            return(ClipperBridge.ConvertToPath(resultTree));
        }
        /// <summary>Converts specified degenerate subpaths to squares.</summary>
        /// <remarks>
        /// Converts specified degenerate subpaths to squares.
        /// Note: the list of degenerate subpaths should contain at least 2 elements. Otherwise
        /// we can't determine the direction which the rotation of each square depends on.
        /// </remarks>
        /// <param name="squareWidth">Width of each constructed square.</param>
        /// <param name="sourcePath">The path which dash pattern applied to. Needed to calc rotation angle of each square.
        ///     </param>
        /// <returns>
        ///
        /// <see cref="System.Collections.IList{E}"/>
        /// consisting of squares constructed on given degenerated subpaths.
        /// </returns>
        private static IList <Subpath> ConvertToSquares(IList <Subpath> degenerateSubpaths, double squareWidth, Path
                                                        sourcePath)
        {
            IList <Point> pathApprox = GetPathApproximation(sourcePath);

            if (pathApprox.Count < 2)
            {
                return(JavaCollectionsUtil.EmptyList <Subpath>());
            }
            IEnumerator <Point> approxIter = pathApprox.GetEnumerator();

            approxIter.MoveNext();
            Point approxPt1 = approxIter.Current;

            approxIter.MoveNext();
            Point approxPt2 = approxIter.Current;

            PdfCleanUpFilter.StandardLine line = new PdfCleanUpFilter.StandardLine(approxPt1, approxPt2);
            IList <Subpath> squares            = new List <Subpath>(degenerateSubpaths.Count);
            float           widthHalf          = (float)squareWidth / 2;

            foreach (Subpath subpath in degenerateSubpaths)
            {
                Point point = subpath.GetStartPoint();
                while (!line.Contains(point))
                {
                    approxPt1 = approxPt2;
                    approxIter.MoveNext();
                    approxPt2 = approxIter.Current;
                    line      = new PdfCleanUpFilter.StandardLine(approxPt1, approxPt2);
                }
                double slope = line.GetSlope();
                double angle;
                if (!double.IsPositiveInfinity(slope))
                {
                    angle = Math.Atan(slope);
                }
                else
                {
                    angle = Math.PI / 2;
                }
                squares.Add(ConstructSquare(point, widthHalf, angle));
            }
            return(squares);
        }