/// <summary>Filter a PathRenderInfo object</summary> /// <param name="path">the PathRenderInfo object to be filtered</param> public virtual Path FilterStrokePath(PathRenderInfo path) { PdfArray dashPattern = path.GetLineDashPattern(); LineDashPattern lineDashPattern = new LineDashPattern(dashPattern.GetAsArray(0), dashPattern.GetAsNumber(1 ).FloatValue()); return(FilterStrokePath(path.GetPath(), path.GetCtm(), path.GetLineWidth(), path.GetLineCapStyle(), path.GetLineJoinStyle (), path.GetMiterLimit(), lineDashPattern)); }
/// <summary>Apply a LineDashPattern along a Path</summary> /// <param name="path">input path</param> /// <param name="lineDashPattern">input LineDashPattern</param> /// <returns>a dashed Path</returns> public static Path ApplyDashPattern(Path path, LineDashPattern lineDashPattern) { ICollection <int> modifiedSubpaths = new HashSet <int>(path.ReplaceCloseWithLine()); Path dashedPath = new Path(); int currentSubpath = 0; foreach (Subpath subpath in path.GetSubpaths()) { IList <Point> subpathApprox = subpath.GetPiecewiseLinearApproximation(); if (subpathApprox.Count > 1) { dashedPath.MoveTo((float)subpathApprox[0].GetX(), (float)subpathApprox[0].GetY()); float remainingDist = 0; bool remainingIsGap = false; for (int i = 1; i < subpathApprox.Count; ++i) { Point nextPoint = null; if (remainingDist != 0) { nextPoint = GetNextPoint(subpathApprox[i - 1], subpathApprox[i], remainingDist); remainingDist = ApplyDash(dashedPath, subpathApprox[i - 1], subpathApprox[i], nextPoint, remainingIsGap); } while (JavaUtil.FloatCompare(remainingDist, 0) == 0 && !dashedPath.GetCurrentPoint().Equals(subpathApprox[ i])) { LineDashPattern.DashArrayElem currentElem = lineDashPattern.Next(); nextPoint = GetNextPoint(nextPoint != null ? nextPoint : subpathApprox[i - 1], subpathApprox[i], currentElem .GetVal()); remainingDist = ApplyDash(dashedPath, subpathApprox[i - 1], subpathApprox[i], nextPoint, currentElem.IsGap ()); remainingIsGap = currentElem.IsGap(); } } // If true, then the line closing the subpath was explicitly added (see Path.ReplaceCloseWithLine). // This causes a loss of a visual effect of line join style parameter, so in this clause // we simply add overlapping dash (or gap, no matter), which continues the last dash and equals to // the first dash (or gap) of the path. if (modifiedSubpaths.Contains(currentSubpath)) { lineDashPattern.Reset(); LineDashPattern.DashArrayElem currentElem = lineDashPattern.Next(); Point nextPoint = GetNextPoint(subpathApprox[0], subpathApprox[1], currentElem.GetVal()); ApplyDash(dashedPath, subpathApprox[0], subpathApprox[1], nextPoint, currentElem.IsGap()); } } // According to PDF spec. line dash pattern should be restarted for each new subpath. lineDashPattern.Reset(); ++currentSubpath; } return(dashedPath); }
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>Construct a new DashArrayElem object</summary> /// <param name="val">the length of the dash array element</param> /// <param name="isGap">whether this element indicates a gap, or a stroke</param> internal DashArrayElem(LineDashPattern _enclosing, float val, bool isGap) { this._enclosing = _enclosing; this.val = val; this.isGap = isGap; }