private static SvgPath ConvertArc(Arc arc) { SvgPath svgPath = new SvgPath(); SvgPathSegmentList svgPathSegmentList = new SvgPathSegmentList(); svgPathSegmentList.Add(new SvgMoveToSegment(arc.GetEndPoint(0).ConvertToPointF())); XYZ a = arc.GetEndPoint(0) - arc.Center; XYZ b = arc.GetEndPoint(1) - arc.Center; double angleAboutAxis = a.AngleOnPlaneTo(b, arc.Normal); SvgArcSweep svgArcSweep = SvgArcSweep.Positive; if (angleAboutAxis >= 180) { svgArcSweep = SvgArcSweep.Negative; } SvgArcSize svgArcSize = SvgArcSize.Small; SvgArcSegment svgArcSegment = new SvgArcSegment(svgPathSegmentList.Last.End, (float)arc.Radius, (float)arc.Radius, (float)angleAboutAxis, svgArcSize, svgArcSweep, arc.GetEndPoint(1).ConvertToPointF()); svgPathSegmentList.Add(svgArcSegment); svgPath.PathData = svgPathSegmentList; return(svgPath); }
public void DrawPath(IEnumerable <IEnumerable <Point> > points, bool winding, GraphicsContext context, DeviceDescription description) { var svgContext = _mapper.MapGraphicsContextToSvg(context); foreach (var point in points) { var vertices = point.ToList(); var list = new SvgPathSegmentList(); var first = vertices.First(); list.Add(new SvgMoveToSegment(new PointF((float)first.X, (float)first.Y))); foreach (var vertex in vertices.Skip(1)) { list.Add(new SvgLineSegment(new PointF((float)first.X, (float)first.Y), new PointF((float)vertex.X, (float)vertex.Y))); first = vertex; } list.Add(new SvgClosePathSegment()); AddChild(new SvgPath { Fill = svgContext.Fill, FillOpacity = svgContext.Opacity, PathData = list, Stroke = svgContext.Pen.Stroke, StrokeDashArray = svgContext.Pen.StrokeDashArray, StrokeLineCap = svgContext.Pen.StrokeLineCap, StrokeLineJoin = svgContext.Pen.StrokeLineJoin, StrokeWidth = svgContext.Pen.StrokeWidth }); } }
private static SvgPath ConvertLine(Line line) { SvgPath svgPath = new SvgPath(); SvgPathSegmentList svgPathSegmentList = new SvgPathSegmentList(); svgPathSegmentList.Add(new SvgMoveToSegment(line.GetEndPoint(0).ConvertToPointF())); SvgLineSegment svgLineSegment = new SvgLineSegment(svgPathSegmentList.Last.End, line.GetEndPoint(1).ConvertToPointF()); svgPathSegmentList.Add(svgLineSegment); svgPath.PathData = svgPathSegmentList; return(svgPath); }
private static SvgPath ConverPolyCurve(List <Curve> curves) { SvgPath svgPath = new SvgPath(); SvgPathSegmentList svgPathSegmentList = new SvgPathSegmentList(); svgPathSegmentList.Add(new SvgMoveToSegment(curves[0].GetEndPoint(0).ConvertToPointF())); foreach (Curve curve in curves) { if (curve is Arc) { Arc arc = (Arc)curve; XYZ a = arc.GetEndPoint(0) - arc.Center; XYZ b = arc.GetEndPoint(1) - arc.Center; double angleAboutAxis = a.AngleOnPlaneTo(b, arc.Normal); SvgArcSweep svgArcSweep = SvgArcSweep.Positive; if (angleAboutAxis >= 180) { svgArcSweep = SvgArcSweep.Negative; } SvgArcSize svgArcSize = SvgArcSize.Small; SvgArcSegment svgArcSegment = new SvgArcSegment(svgPathSegmentList.Last.End, (float)arc.Radius, (float)arc.Radius, (float)angleAboutAxis, svgArcSize, svgArcSweep, arc.GetEndPoint(1).ConvertToPointF()); svgPathSegmentList.Add(svgArcSegment); } else if (curve is Line) { SvgLineSegment svgLineSegment = new SvgLineSegment(svgPathSegmentList.Last.End, ((Line)curve).GetEndPoint(1).ConvertToPointF()); svgPathSegmentList.Add(svgLineSegment); } } svgPath.PathData = svgPathSegmentList; return(svgPath); }
public override SvgElement DeepCopy <T>() { var newObj = base.DeepCopy <T>() as SvgGlyph; if (PathData != null) { var pathData = new SvgPathSegmentList(); foreach (var segment in PathData) { pathData.Add(segment.Clone()); } newObj.PathData = pathData; } return(newObj); }
public override SvgElement DeepCopy <T>() { var newObj = base.DeepCopy <T>() as SvgPath; if (PathData != null) { var pathData = new SvgPathSegmentList(); foreach (var segment in PathData) { pathData.Add(segment.Clone()); } newObj.PathData = pathData; } newObj.PathLength = this.PathLength; newObj.MarkerStart = this.MarkerStart; newObj.MarkerEnd = this.MarkerEnd; return(newObj); }
/// <summary> /// Parses the specified string into a collection of path segments. /// </summary> /// <param name="path">A <see cref="string"/> containing path data.</param> public static SvgPathSegmentList Parse(string path) { if (string.IsNullOrEmpty(path)) { throw new ArgumentNullException("path"); } var segments = new SvgPathSegmentList(); try { List <float> coords; char command; bool isRelative; foreach (var commandSet in SplitCommands(path.TrimEnd(null))) { coords = new List <float>(ParseCoordinates(commandSet.Trim())); command = commandSet[0]; isRelative = char.IsLower(command); // http://www.w3.org/TR/SVG11/paths.html#PathDataGeneralInformation switch (command) { case 'm': // relative moveto case 'M': // moveto segments.Add( new SvgMoveToSegment(ToAbsolute(coords[0], coords[1], segments, isRelative))); for (var i = 2; i < coords.Count; i += 2) { segments.Add(new SvgLineSegment(segments.Last.End, ToAbsolute(coords[i], coords[i + 1], segments, isRelative))); } break; case 'a': case 'A': SvgArcSize size; SvgArcSweep sweep; for (var i = 0; i < coords.Count; i += 7) { size = (coords[i + 3] != 0.0f) ? SvgArcSize.Large : SvgArcSize.Small; sweep = (coords[i + 4] != 0.0f) ? SvgArcSweep.Positive : SvgArcSweep.Negative; // A|a rx ry x-axis-rotation large-arc-flag sweep-flag x y segments.Add(new SvgArcSegment(segments.Last.End, coords[i], coords[i + 1], coords[i + 2], size, sweep, ToAbsolute(coords[i + 5], coords[i + 6], segments, isRelative))); } break; case 'l': // relative lineto case 'L': // lineto for (var i = 0; i < coords.Count; i += 2) { segments.Add(new SvgLineSegment(segments.Last.End, ToAbsolute(coords[i], coords[i + 1], segments, isRelative))); } break; case 'H': // horizontal lineto case 'h': // relative horizontal lineto foreach (var value in coords) { segments.Add(new SvgLineSegment(segments.Last.End, ToAbsolute(value, segments.Last.End.Y, segments, isRelative, false))); } break; case 'V': // vertical lineto case 'v': // relative vertical lineto foreach (var value in coords) { segments.Add(new SvgLineSegment(segments.Last.End, ToAbsolute(segments.Last.End.X, value, segments, false, isRelative))); } break; case 'Q': // curveto case 'q': // relative curveto for (var i = 0; i < coords.Count; i += 4) { segments.Add(new SvgQuadraticCurveSegment(segments.Last.End, ToAbsolute(coords[i], coords[i + 1], segments, isRelative), ToAbsolute(coords[i + 2], coords[i + 3], segments, isRelative))); } break; case 'T': // shorthand/smooth curveto case 't': // relative shorthand/smooth curveto for (var i = 0; i < coords.Count; i += 2) { var lastQuadCurve = segments.Last as SvgQuadraticCurveSegment; var controlPoint = lastQuadCurve != null ? Reflect(lastQuadCurve.ControlPoint, segments.Last.End) : segments.Last.End; segments.Add(new SvgQuadraticCurveSegment(segments.Last.End, controlPoint, ToAbsolute(coords[i], coords[i + 1], segments, isRelative))); } break; case 'C': // curveto case 'c': // relative curveto for (var i = 0; i < coords.Count; i += 6) { segments.Add(new SvgCubicCurveSegment(segments.Last.End, ToAbsolute(coords[i], coords[i + 1], segments, isRelative), ToAbsolute(coords[i + 2], coords[i + 3], segments, isRelative), ToAbsolute(coords[i + 4], coords[i + 5], segments, isRelative))); } break; case 'S': // shorthand/smooth curveto case 's': // relative shorthand/smooth curveto for (var i = 0; i < coords.Count; i += 4) { var lastCubicCurve = segments.Last as SvgCubicCurveSegment; var controlPoint = lastCubicCurve != null ? Reflect(lastCubicCurve.SecondControlPoint, segments.Last.End) : segments.Last.End; segments.Add(new SvgCubicCurveSegment(segments.Last.End, controlPoint, ToAbsolute(coords[i], coords[i + 1], segments, isRelative), ToAbsolute(coords[i + 2], coords[i + 3], segments, isRelative))); } break; case 'Z': // closepath case 'z': // relative closepath segments.Add(new SvgClosePathSegment()); break; } } } catch (Exception exc) { Trace.TraceError("Error parsing path \"{0}\": {1}", path, exc.Message); } return(segments); }
private static void CreatePathSegment(char command, SvgPathSegmentList segments, CoordinateParser parser, bool isRelative) { var coords = new float[6]; switch (command) { case 'm': // relative moveto case 'M': // moveto if (parser.TryGetFloat(out coords[0]) && parser.TryGetFloat(out coords[1])) { segments.Add(new SvgMoveToSegment(ToAbsolute(coords[0], coords[1], segments, isRelative))); } while (parser.TryGetFloat(out coords[0]) && parser.TryGetFloat(out coords[1])) { segments.Add(new SvgLineSegment(segments.Last.End, ToAbsolute(coords[0], coords[1], segments, isRelative))); } break; case 'a': case 'A': bool size; bool sweep; while (parser.TryGetFloat(out coords[0]) && parser.TryGetFloat(out coords[1]) && parser.TryGetFloat(out coords[2]) && parser.TryGetBool(out size) && parser.TryGetBool(out sweep) && parser.TryGetFloat(out coords[3]) && parser.TryGetFloat(out coords[4])) { // A|a rx ry x-axis-rotation large-arc-flag sweep-flag x y segments.Add(new SvgArcSegment(segments.Last.End, coords[0], coords[1], coords[2], size ? SvgArcSize.Large : SvgArcSize.Small, sweep ? SvgArcSweep.Positive : SvgArcSweep.Negative, ToAbsolute(coords[3], coords[4], segments, isRelative))); } break; case 'l': // relative lineto case 'L': // lineto while (parser.TryGetFloat(out coords[0]) && parser.TryGetFloat(out coords[1])) { segments.Add(new SvgLineSegment(segments.Last.End, ToAbsolute(coords[0], coords[1], segments, isRelative))); } break; case 'H': // horizontal lineto case 'h': // relative horizontal lineto while (parser.TryGetFloat(out coords[0])) { segments.Add(new SvgLineSegment(segments.Last.End, ToAbsolute(coords[0], segments.Last.End.Y, segments, isRelative, false))); } break; case 'V': // vertical lineto case 'v': // relative vertical lineto while (parser.TryGetFloat(out coords[0])) { segments.Add(new SvgLineSegment(segments.Last.End, ToAbsolute(segments.Last.End.X, coords[0], segments, false, isRelative))); } break; case 'Q': // curveto case 'q': // relative curveto while (parser.TryGetFloat(out coords[0]) && parser.TryGetFloat(out coords[1]) && parser.TryGetFloat(out coords[2]) && parser.TryGetFloat(out coords[3])) { segments.Add(new SvgQuadraticCurveSegment(segments.Last.End, ToAbsolute(coords[0], coords[1], segments, isRelative), ToAbsolute(coords[2], coords[3], segments, isRelative))); } break; case 'T': // shorthand/smooth curveto case 't': // relative shorthand/smooth curveto while (parser.TryGetFloat(out coords[0]) && parser.TryGetFloat(out coords[1])) { var lastQuadCurve = segments.Last as SvgQuadraticCurveSegment; var controlPoint = lastQuadCurve != null ? Reflect(lastQuadCurve.ControlPoint, segments.Last.End) : segments.Last.End; segments.Add(new SvgQuadraticCurveSegment(segments.Last.End, controlPoint, ToAbsolute(coords[0], coords[1], segments, isRelative))); } break; case 'C': // curveto case 'c': // relative curveto while (parser.TryGetFloat(out coords[0]) && parser.TryGetFloat(out coords[1]) && parser.TryGetFloat(out coords[2]) && parser.TryGetFloat(out coords[3]) && parser.TryGetFloat(out coords[4]) && parser.TryGetFloat(out coords[5])) { segments.Add(new SvgCubicCurveSegment(segments.Last.End, ToAbsolute(coords[0], coords[1], segments, isRelative), ToAbsolute(coords[2], coords[3], segments, isRelative), ToAbsolute(coords[4], coords[5], segments, isRelative))); } break; case 'S': // shorthand/smooth curveto case 's': // relative shorthand/smooth curveto while (parser.TryGetFloat(out coords[0]) && parser.TryGetFloat(out coords[1]) && parser.TryGetFloat(out coords[2]) && parser.TryGetFloat(out coords[3])) { var lastCubicCurve = segments.Last as SvgCubicCurveSegment; var controlPoint = lastCubicCurve != null ? Reflect(lastCubicCurve.SecondControlPoint, segments.Last.End) : segments.Last.End; segments.Add(new SvgCubicCurveSegment(segments.Last.End, controlPoint, ToAbsolute(coords[0], coords[1], segments, isRelative), ToAbsolute(coords[2], coords[3], segments, isRelative))); } break; case 'Z': // closepath case 'z': // relative closepath segments.Add(new SvgClosePathSegment()); break; } }
public static void CreatePathSegment(char command, SvgPathSegmentList segments, List<float> coords, bool isRelative) { switch (command) { case 'm': // relative moveto case 'M': // moveto segments.Add( new SvgMoveToSegment(ToAbsolute(coords[0], coords[1], segments, isRelative))); for (var i = 2; i < coords.Count; i += 2) { segments.Add(new SvgLineSegment(segments.Last.End, ToAbsolute(coords[i], coords[i + 1], segments, isRelative))); } break; case 'a': case 'A': SvgArcSize size; SvgArcSweep sweep; for (var i = 0; i < coords.Count; i += 7) { size = (coords[i + 3] != 0.0f) ? SvgArcSize.Large : SvgArcSize.Small; sweep = (coords[i + 4] != 0.0f) ? SvgArcSweep.Positive : SvgArcSweep.Negative; // A|a rx ry x-axis-rotation large-arc-flag sweep-flag x y segments.Add(new SvgArcSegment(segments.Last.End, coords[i], coords[i + 1], coords[i + 2], size, sweep, ToAbsolute(coords[i + 5], coords[i + 6], segments, isRelative))); } break; case 'l': // relative lineto case 'L': // lineto for (var i = 0; i < coords.Count; i += 2) { segments.Add(new SvgLineSegment(segments.Last.End, ToAbsolute(coords[i], coords[i + 1], segments, isRelative))); } break; case 'H': // horizontal lineto case 'h': // relative horizontal lineto foreach (var value in coords) segments.Add(new SvgLineSegment(segments.Last.End, ToAbsolute(value, segments.Last.End.Y, segments, isRelative, false))); break; case 'V': // vertical lineto case 'v': // relative vertical lineto foreach (var value in coords) segments.Add(new SvgLineSegment(segments.Last.End, ToAbsolute(segments.Last.End.X, value, segments, false, isRelative))); break; case 'Q': // curveto case 'q': // relative curveto for (var i = 0; i < coords.Count; i += 4) { segments.Add(new SvgQuadraticCurveSegment(segments.Last.End, ToAbsolute(coords[i], coords[i + 1], segments, isRelative), ToAbsolute(coords[i + 2], coords[i + 3], segments, isRelative))); } break; case 'T': // shorthand/smooth curveto case 't': // relative shorthand/smooth curveto for (var i = 0; i < coords.Count; i += 2) { var lastQuadCurve = segments.Last as SvgQuadraticCurveSegment; var controlPoint = lastQuadCurve != null ? Reflect(lastQuadCurve.ControlPoint, segments.Last.End) : segments.Last.End; segments.Add(new SvgQuadraticCurveSegment(segments.Last.End, controlPoint, ToAbsolute(coords[i], coords[i + 1], segments, isRelative))); } break; case 'C': // curveto case 'c': // relative curveto for (var i = 0; i < coords.Count; i += 6) { segments.Add(new SvgCubicCurveSegment(segments.Last.End, ToAbsolute(coords[i], coords[i + 1], segments, isRelative), ToAbsolute(coords[i + 2], coords[i + 3], segments, isRelative), ToAbsolute(coords[i + 4], coords[i + 5], segments, isRelative))); } break; case 'S': // shorthand/smooth curveto case 's': // relative shorthand/smooth curveto for (var i = 0; i < coords.Count; i += 4) { var lastCubicCurve = segments.Last as SvgCubicCurveSegment; var controlPoint = lastCubicCurve != null ? Reflect(lastCubicCurve.SecondControlPoint, segments.Last.End) : segments.Last.End; segments.Add(new SvgCubicCurveSegment(segments.Last.End, controlPoint, ToAbsolute(coords[i], coords[i + 1], segments, isRelative), ToAbsolute(coords[i + 2], coords[i + 3], segments, isRelative))); } break; case 'Z': // closepath case 'z': // relative closepath segments.Add(new SvgClosePathSegment()); break; } }
public void DrawPath(IEnumerable<IEnumerable<Point>> points, bool winding, GraphicsContext context, DeviceDescription description) { var svgContext = _mapper.MapGraphicsContextToSvg(context); foreach (var point in points) { var vertices = point.ToList(); var list = new SvgPathSegmentList(); var first = vertices.First(); list.Add(new SvgMoveToSegment(new PointF((float)first.X, (float)first.Y))); foreach (var vertex in vertices.Skip(1)) { list.Add(new SvgLineSegment(new PointF((float)first.X, (float)first.Y), new PointF((float)vertex.X, (float)vertex.Y))); first = vertex; } list.Add(new SvgClosePathSegment()); AddChild(new SvgPath { Fill = svgContext.Fill, FillOpacity = svgContext.Opacity, PathData = list, Stroke = svgContext.Pen.Stroke, StrokeDashArray = svgContext.Pen.StrokeDashArray, StrokeLineCap = svgContext.Pen.StrokeLineCap, StrokeLineJoin = svgContext.Pen.StrokeLineJoin, StrokeWidth = svgContext.Pen.StrokeWidth }); } }
/// <summary> /// Parses the specified string into a collection of path segments. /// </summary> /// <param name="path">A <see cref="string"/> containing path data.</param> public static SvgPathSegmentList Parse(string path) { if (string.IsNullOrEmpty(path)) { throw new ArgumentNullException("path"); } var segments = new SvgPathSegmentList(); try { List<float> coords; char command; bool isRelative; foreach (var commandSet in SplitCommands(path.TrimEnd(null))) { coords = new List<float>(ParseCoordinates(commandSet.Trim())); command = commandSet[0]; isRelative = char.IsLower(command); // http://www.w3.org/TR/SVG11/paths.html#PathDataGeneralInformation switch (command) { case 'm': // relative moveto case 'M': // moveto segments.Add( new SvgMoveToSegment(ToAbsolute(coords[0], coords[1], segments, isRelative))); for (var i = 2; i < coords.Count; i += 2) { segments.Add(new SvgLineSegment(segments.Last.End, ToAbsolute(coords[i], coords[i + 1], segments, isRelative))); } break; case 'a': case 'A': SvgArcSize size; SvgArcSweep sweep; for (var i = 0; i < coords.Count; i += 7) { size = (coords[i + 3] != 0.0f) ? SvgArcSize.Large : SvgArcSize.Small; sweep = (coords[i + 4] != 0.0f) ? SvgArcSweep.Positive : SvgArcSweep.Negative; // A|a rx ry x-axis-rotation large-arc-flag sweep-flag x y segments.Add(new SvgArcSegment(segments.Last.End, coords[i], coords[i + 1], coords[i + 2], size, sweep, ToAbsolute(coords[i + 5], coords[i + 6], segments, isRelative))); } break; case 'l': // relative lineto case 'L': // lineto for (var i = 0; i < coords.Count; i += 2) { segments.Add(new SvgLineSegment(segments.Last.End, ToAbsolute(coords[i], coords[i + 1], segments, isRelative))); } break; case 'H': // horizontal lineto case 'h': // relative horizontal lineto foreach (var value in coords) segments.Add(new SvgLineSegment(segments.Last.End, ToAbsolute(value, segments.Last.End.Y, segments, isRelative, false))); break; case 'V': // vertical lineto case 'v': // relative vertical lineto foreach (var value in coords) segments.Add(new SvgLineSegment(segments.Last.End, ToAbsolute(segments.Last.End.X, value, segments, false, isRelative))); break; case 'Q': // curveto case 'q': // relative curveto for (var i = 0; i < coords.Count; i += 4) { segments.Add(new SvgQuadraticCurveSegment(segments.Last.End, ToAbsolute(coords[i], coords[i + 1], segments, isRelative), ToAbsolute(coords[i + 2], coords[i + 3], segments, isRelative))); } break; case 'T': // shorthand/smooth curveto case 't': // relative shorthand/smooth curveto for (var i = 0; i < coords.Count; i += 2) { var lastQuadCurve = segments.Last as SvgQuadraticCurveSegment; var controlPoint = lastQuadCurve != null ? Reflect(lastQuadCurve.ControlPoint, segments.Last.End) : segments.Last.End; segments.Add(new SvgQuadraticCurveSegment(segments.Last.End, controlPoint, ToAbsolute(coords[i], coords[i + 1], segments, isRelative))); } break; case 'C': // curveto case 'c': // relative curveto for (var i = 0; i < coords.Count; i += 6) { segments.Add(new SvgCubicCurveSegment(segments.Last.End, ToAbsolute(coords[i], coords[i + 1], segments, isRelative), ToAbsolute(coords[i + 2], coords[i + 3], segments, isRelative), ToAbsolute(coords[i + 4], coords[i + 5], segments, isRelative))); } break; case 'S': // shorthand/smooth curveto case 's': // relative shorthand/smooth curveto for (var i = 0; i < coords.Count; i += 4) { var lastCubicCurve = segments.Last as SvgCubicCurveSegment; var controlPoint = lastCubicCurve != null ? Reflect(lastCubicCurve.SecondControlPoint, segments.Last.End) : segments.Last.End; segments.Add(new SvgCubicCurveSegment(segments.Last.End, controlPoint, ToAbsolute(coords[i], coords[i + 1], segments, isRelative), ToAbsolute(coords[i + 2], coords[i + 3], segments, isRelative))); } break; case 'Z': // closepath case 'z': // relative closepath segments.Add(new SvgClosePathSegment()); break; } } } catch (Exception exc) { // Trace.TraceError("Error parsing path \"{0}\": {1}", path, exc.Message); } return segments; }
private static void CreatePathSegment(char command, SvgPathSegmentList segments, CoordinateParser parser, bool isRelative) { var coords = new float[6]; switch (command) { case 'm': // relative moveto case 'M': // moveto if (parser.TryGetFloat(out coords[0]) && parser.TryGetFloat(out coords[1])) { segments.Add(new SvgMoveToSegment(ToAbsolute(coords[0], coords[1], segments, isRelative))); } while (parser.TryGetFloat(out coords[0]) && parser.TryGetFloat(out coords[1])) { segments.Add(new SvgLineSegment(segments.Last.End, ToAbsolute(coords[0], coords[1], segments, isRelative))); } break; case 'a': case 'A': bool size; bool sweep; while (parser.TryGetFloat(out coords[0]) && parser.TryGetFloat(out coords[1]) && parser.TryGetFloat(out coords[2]) && parser.TryGetBool(out size) && parser.TryGetBool(out sweep) && parser.TryGetFloat(out coords[3]) && parser.TryGetFloat(out coords[4])) { // A|a rx ry x-axis-rotation large-arc-flag sweep-flag x y segments.Add(new SvgArcSegment(segments.Last.End, coords[0], coords[1], coords[2], (size ? SvgArcSize.Large : SvgArcSize.Small), (sweep ? SvgArcSweep.Positive : SvgArcSweep.Negative), ToAbsolute(coords[3], coords[4], segments, isRelative))); } break; case 'l': // relative lineto case 'L': // lineto while (parser.TryGetFloat(out coords[0]) && parser.TryGetFloat(out coords[1])) { segments.Add(new SvgLineSegment(segments.Last.End, ToAbsolute(coords[0], coords[1], segments, isRelative))); } break; case 'H': // horizontal lineto case 'h': // relative horizontal lineto while (parser.TryGetFloat(out coords[0])) { segments.Add(new SvgLineSegment(segments.Last.End, ToAbsolute(coords[0], segments.Last.End.Y, segments, isRelative, false))); } break; case 'V': // vertical lineto case 'v': // relative vertical lineto while (parser.TryGetFloat(out coords[0])) { segments.Add(new SvgLineSegment(segments.Last.End, ToAbsolute(segments.Last.End.X, coords[0], segments, false, isRelative))); } break; case 'Q': // curveto case 'q': // relative curveto while (parser.TryGetFloat(out coords[0]) && parser.TryGetFloat(out coords[1]) && parser.TryGetFloat(out coords[2]) && parser.TryGetFloat(out coords[3])) { segments.Add(new SvgQuadraticCurveSegment(segments.Last.End, ToAbsolute(coords[0], coords[1], segments, isRelative), ToAbsolute(coords[2], coords[3], segments, isRelative))); } break; case 'T': // shorthand/smooth curveto case 't': // relative shorthand/smooth curveto while (parser.TryGetFloat(out coords[0]) && parser.TryGetFloat(out coords[1])) { var lastQuadCurve = segments.Last as SvgQuadraticCurveSegment; var controlPoint = lastQuadCurve != null ? Reflect(lastQuadCurve.ControlPoint, segments.Last.End) : segments.Last.End; segments.Add(new SvgQuadraticCurveSegment(segments.Last.End, controlPoint, ToAbsolute(coords[0], coords[1], segments, isRelative))); } break; case 'C': // curveto case 'c': // relative curveto while (parser.TryGetFloat(out coords[0]) && parser.TryGetFloat(out coords[1]) && parser.TryGetFloat(out coords[2]) && parser.TryGetFloat(out coords[3]) && parser.TryGetFloat(out coords[4]) && parser.TryGetFloat(out coords[5])) { segments.Add(new SvgCubicCurveSegment(segments.Last.End, ToAbsolute(coords[0], coords[1], segments, isRelative), ToAbsolute(coords[2], coords[3], segments, isRelative), ToAbsolute(coords[4], coords[5], segments, isRelative))); } break; case 'S': // shorthand/smooth curveto case 's': // relative shorthand/smooth curveto while (parser.TryGetFloat(out coords[0]) && parser.TryGetFloat(out coords[1]) && parser.TryGetFloat(out coords[2]) && parser.TryGetFloat(out coords[3])) { var lastCubicCurve = segments.Last as SvgCubicCurveSegment; var controlPoint = lastCubicCurve != null ? Reflect(lastCubicCurve.SecondControlPoint, segments.Last.End) : segments.Last.End; segments.Add(new SvgCubicCurveSegment(segments.Last.End, controlPoint, ToAbsolute(coords[0], coords[1], segments, isRelative), ToAbsolute(coords[2], coords[3], segments, isRelative))); } break; case 'Z': // closepath case 'z': // relative closepath segments.Add(new SvgClosePathSegment()); break; } }
private static void CreatePathSegment(char command, SvgPathSegmentList segments, ref CoordinateParserState state, ref ReadOnlySpan <char> chars) { var isRelative = char.IsLower(command); // http://www.w3.org/TR/SVG11/paths.html#PathDataGeneralInformation switch (command) { case 'M': // moveto case 'm': // relative moveto { if (CoordinateParser.TryGetFloat(out var coords0, ref chars, ref state) && CoordinateParser.TryGetFloat(out var coords1, ref chars, ref state)) { segments.Add( new SvgMoveToSegment( isRelative, new PointF(coords0, coords1))); } while (CoordinateParser.TryGetFloat(out coords0, ref chars, ref state) && CoordinateParser.TryGetFloat(out coords1, ref chars, ref state)) { segments.Add( new SvgLineSegment( isRelative, new PointF(coords0, coords1))); } } break; case 'A': // elliptical arc case 'a': // relative elliptical arc { while (CoordinateParser.TryGetFloat(out var coords0, ref chars, ref state) && CoordinateParser.TryGetFloat(out var coords1, ref chars, ref state) && CoordinateParser.TryGetFloat(out var coords2, ref chars, ref state) && CoordinateParser.TryGetBool(out var size, ref chars, ref state) && CoordinateParser.TryGetBool(out var sweep, ref chars, ref state) && CoordinateParser.TryGetFloat(out var coords3, ref chars, ref state) && CoordinateParser.TryGetFloat(out var coords4, ref chars, ref state)) { // A|a rx ry x-axis-rotation large-arc-flag sweep-flag x y segments.Add( new SvgArcSegment( coords0, coords1, coords2, size ? SvgArcSize.Large : SvgArcSize.Small, sweep ? SvgArcSweep.Positive : SvgArcSweep.Negative, isRelative, new PointF(coords3, coords4))); } } break; case 'L': // lineto case 'l': // relative lineto { while (CoordinateParser.TryGetFloat(out var coords0, ref chars, ref state) && CoordinateParser.TryGetFloat(out var coords1, ref chars, ref state)) { segments.Add( new SvgLineSegment( isRelative, new PointF(coords0, coords1))); } } break; case 'H': // horizontal lineto case 'h': // relative horizontal lineto { while (CoordinateParser.TryGetFloat(out var coords0, ref chars, ref state)) { segments.Add( new SvgLineSegment( isRelative, new PointF(coords0, float.NaN))); } } break; case 'V': // vertical lineto case 'v': // relative vertical lineto { while (CoordinateParser.TryGetFloat(out var coords0, ref chars, ref state)) { segments.Add( new SvgLineSegment( isRelative, new PointF(float.NaN, coords0))); } } break; case 'Q': // quadratic bézier curveto case 'q': // relative quadratic bézier curveto { while (CoordinateParser.TryGetFloat(out var coords0, ref chars, ref state) && CoordinateParser.TryGetFloat(out var coords1, ref chars, ref state) && CoordinateParser.TryGetFloat(out var coords2, ref chars, ref state) && CoordinateParser.TryGetFloat(out var coords3, ref chars, ref state)) { segments.Add( new SvgQuadraticCurveSegment( isRelative, new PointF(coords0, coords1), new PointF(coords2, coords3))); } } break; case 'T': // shorthand/smooth quadratic bézier curveto case 't': // relative shorthand/smooth quadratic bézier curveto { while (CoordinateParser.TryGetFloat(out var coords0, ref chars, ref state) && CoordinateParser.TryGetFloat(out var coords1, ref chars, ref state)) { segments.Add( new SvgQuadraticCurveSegment( isRelative, new PointF(coords0, coords1))); } } break; case 'C': // curveto case 'c': // relative curveto { while (CoordinateParser.TryGetFloat(out var coords0, ref chars, ref state) && CoordinateParser.TryGetFloat(out var coords1, ref chars, ref state) && CoordinateParser.TryGetFloat(out var coords2, ref chars, ref state) && CoordinateParser.TryGetFloat(out var coords3, ref chars, ref state) && CoordinateParser.TryGetFloat(out var coords4, ref chars, ref state) && CoordinateParser.TryGetFloat(out var coords5, ref chars, ref state)) { segments.Add( new SvgCubicCurveSegment( isRelative, new PointF(coords0, coords1), new PointF(coords2, coords3), new PointF(coords4, coords5))); } } break; case 'S': // shorthand/smooth curveto case 's': // relative shorthand/smooth curveto { while (CoordinateParser.TryGetFloat(out var coords0, ref chars, ref state) && CoordinateParser.TryGetFloat(out var coords1, ref chars, ref state) && CoordinateParser.TryGetFloat(out var coords2, ref chars, ref state) && CoordinateParser.TryGetFloat(out var coords3, ref chars, ref state)) { segments.Add( new SvgCubicCurveSegment( isRelative, new PointF(coords0, coords1), new PointF(coords2, coords3))); } } break; case 'Z': // closepath case 'z': // relative closepath { segments.Add(new SvgClosePathSegment(isRelative)); } break; } }
public static void CreatePathSegment(char command, SvgPathSegmentList segments, List <float> coords, bool isRelative) { switch (command) { case 'm': // relative moveto case 'M': // moveto segments.Add( new SvgMoveToSegment(ToAbsolute(coords[0], coords[1], segments, isRelative))); for (var i = 2; i < coords.Count; i += 2) { segments.Add(new SvgLineSegment(segments.Last.End, ToAbsolute(coords[i], coords[i + 1], segments, isRelative))); } break; case 'a': case 'A': SvgArcSize size; SvgArcSweep sweep; for (var i = 0; i < coords.Count; i += 7) { size = (coords[i + 3] != 0.0f) ? SvgArcSize.Large : SvgArcSize.Small; sweep = (coords[i + 4] != 0.0f) ? SvgArcSweep.Positive : SvgArcSweep.Negative; // A|a rx ry x-axis-rotation large-arc-flag sweep-flag x y segments.Add(new SvgArcSegment(segments.Last.End, coords[i], coords[i + 1], coords[i + 2], size, sweep, ToAbsolute(coords[i + 5], coords[i + 6], segments, isRelative))); } break; case 'l': // relative lineto case 'L': // lineto for (var i = 0; i < coords.Count; i += 2) { segments.Add(new SvgLineSegment(segments.Last.End, ToAbsolute(coords[i], coords[i + 1], segments, isRelative))); } break; case 'H': // horizontal lineto case 'h': // relative horizontal lineto foreach (var value in coords) { segments.Add(new SvgLineSegment(segments.Last.End, ToAbsolute(value, segments.Last.End.Y, segments, isRelative, false))); } break; case 'V': // vertical lineto case 'v': // relative vertical lineto foreach (var value in coords) { segments.Add(new SvgLineSegment(segments.Last.End, ToAbsolute(segments.Last.End.X, value, segments, false, isRelative))); } break; case 'Q': // curveto case 'q': // relative curveto for (var i = 0; i < coords.Count; i += 4) { segments.Add(new SvgQuadraticCurveSegment(segments.Last.End, ToAbsolute(coords[i], coords[i + 1], segments, isRelative), ToAbsolute(coords[i + 2], coords[i + 3], segments, isRelative))); } break; case 'T': // shorthand/smooth curveto case 't': // relative shorthand/smooth curveto for (var i = 0; i < coords.Count; i += 2) { var lastQuadCurve = segments.Last as SvgQuadraticCurveSegment; var controlPoint = lastQuadCurve != null ? Reflect(lastQuadCurve.ControlPoint, segments.Last.End) : segments.Last.End; segments.Add(new SvgQuadraticCurveSegment(segments.Last.End, controlPoint, ToAbsolute(coords[i], coords[i + 1], segments, isRelative))); } break; case 'C': // curveto case 'c': // relative curveto for (var i = 0; i < coords.Count; i += 6) { segments.Add(new SvgCubicCurveSegment(segments.Last.End, ToAbsolute(coords[i], coords[i + 1], segments, isRelative), ToAbsolute(coords[i + 2], coords[i + 3], segments, isRelative), ToAbsolute(coords[i + 4], coords[i + 5], segments, isRelative))); } break; case 'S': // shorthand/smooth curveto case 's': // relative shorthand/smooth curveto for (var i = 0; i < coords.Count; i += 4) { var lastCubicCurve = segments.Last as SvgCubicCurveSegment; var controlPoint = lastCubicCurve != null ? Reflect(lastCubicCurve.SecondControlPoint, segments.Last.End) : segments.Last.End; segments.Add(new SvgCubicCurveSegment(segments.Last.End, controlPoint, ToAbsolute(coords[i], coords[i + 1], segments, isRelative), ToAbsolute(coords[i + 2], coords[i + 3], segments, isRelative))); } break; case 'Z': // closepath case 'z': // relative closepath segments.Add(new SvgClosePathSegment()); break; } }
public static SvgPathSegmentList NormalizeAndTruncate(this SvgPathSegmentList path, out DoubleMatrix transform, double halfSize = 2048) { // Calculate the bounding box of the path var points = path.Curves().SelectMany(c => c.EnclosingPolygon).ToArray(); // Don't normalize an empty path if (points.Length == 0) { transform = DoubleMatrix.Identity; return(path); } var minx = double.PositiveInfinity; var maxx = double.NegativeInfinity; var miny = double.PositiveInfinity; var maxy = double.NegativeInfinity; // Find the bounding box foreach (var pt in points) { minx = Math.Min(minx, pt.X); maxx = Math.Max(maxx, pt.X); miny = Math.Min(miny, pt.Y); maxy = Math.Max(maxy, pt.Y); } // Calculate the points var center = new Double2(minx + maxx, miny + maxy) / 2; // And the half-sizes var hx = (maxx - minx) / 2; var hy = (maxy - miny) / 2; // Chose the maximum value of it var d = halfSize / Math.Max(hx, hy); var dm = Double2.Zero; // And transform the path var newPath = new SvgPathSegmentList(); foreach (var segment in path) { if (segment is SvgMoveToSegment move) { newPath.Add(new SvgMoveToSegment(Transform(move.Start))); } else if (segment is SvgLineSegment line) { newPath.Add(new SvgLineSegment(Transform(line.Start), Transform(line.End))); } else if (segment is SvgQuadraticCurveSegment quad) { newPath.Add(new SvgQuadraticCurveSegment(Transform(quad.Start), Transform(quad.ControlPoint), Transform(quad.End))); } else if (segment is SvgCubicCurveSegment cubic) { newPath.Add(new SvgCubicCurveSegment(Transform(cubic.Start), Transform(cubic.FirstControlPoint), Transform(cubic.SecondControlPoint), Transform(cubic.End))); } else if (segment is SvgArcSegment arc) { newPath.Add(new SvgArcSegment(Transform(arc.Start), (float)(arc.RadiusX * d).Truncate(), (float)(arc.RadiusY * d).Truncate(), arc.Angle, arc.Size, arc.Sweep, Transform(arc.End))); } else if (segment is SvgClosePathSegment) { newPath.Add(new SvgClosePathSegment()); } } // Mount the inverse matrix transform = new DoubleMatrix(1 / d, 0, 0, 1 / d, center.X, center.Y); return(newPath); System.Drawing.PointF Transform(System.Drawing.PointF point) { var pt = (point.ToDouble2() * d - center * d).Truncate() + dm; return(new System.Drawing.PointF((float)pt.X, (float)pt.Y)); } }