public List <SvgPathSeg> Parse(char[] pathDataBuffer) { //parse pathdata to pathsegments List <SvgPathSeg> pathSegments = new List <SvgPathSeg>(); List <float> numbers = new List <float>(); int j = pathDataBuffer.Length; int currentState = 0; for (int i = 0; i < j;) { //lex and parse char c = pathDataBuffer[i]; switch (currentState) { case 0: { //init state switch (c) { case 'M': case 'm': { //move to ParseNumberList(pathDataBuffer, i + 1, out i, numbers); if (numbers.Count == 2) { var moveTo = new SvgPathSegMoveTo( numbers[0], numbers[1]); moveTo.IsRelative = c == 'm'; pathSegments.Add(moveTo); } else { //error throw new NotSupportedException(); } numbers.Clear(); //reset } break; case 'L': case 'l': { //line to ParseNumberList(pathDataBuffer, i + 1, out i, numbers); if (numbers.Count == 2) { var lineTo = new SvgPathSegLineTo( numbers[0], numbers[1]); lineTo.IsRelative = c == 'l'; pathSegments.Add(lineTo); } else { //error throw new NotSupportedException(); } numbers.Clear(); //reset } break; case 'H': case 'h': { ParseNumberList(pathDataBuffer, i + 1, out i, numbers); if (numbers.Count == 1) { var h = new SvgPathSegLineToHorizontal( numbers[0]); h.IsRelative = c == 'h'; pathSegments.Add(h); } else { //error throw new NotSupportedException(); } numbers.Clear(); //reset } break; case 'V': case 'v': { ParseNumberList(pathDataBuffer, i + 1, out i, numbers); if (numbers.Count == 1) { var v = new SvgPathSegLineToVertical( numbers[0]); v.IsRelative = c == 'v'; pathSegments.Add(v); } else { //error throw new NotSupportedException(); } numbers.Clear(); //reset } break; case 'Z': case 'z': { pathSegments.Add(new SvgPathSegClosePath()); i++; } break; case 'A': case 'a': { ParseNumberList(pathDataBuffer, i + 1, out i, numbers); if (numbers.Count == 7) { var arc = new SvgPathSegArc( numbers[0], numbers[1], numbers[2], (int)numbers[3], (int)numbers[4], numbers[5], numbers[6]); arc.IsRelative = c == 'a'; pathSegments.Add(arc); } else { throw new NotSupportedException(); } numbers.Clear(); } break; case 'C': case 'c': { ParseNumberList(pathDataBuffer, i + 1, out i, numbers); if (numbers.Count == 6) { var squadCurve = new SvgPathSegCurveToCubic( numbers[0], numbers[1], numbers[2], numbers[3], numbers[4], numbers[5]); squadCurve.IsRelative = c == 'c'; pathSegments.Add(squadCurve); } else { throw new NotSupportedException(); } numbers.Clear(); } break; case 'Q': case 'q': { ParseNumberList(pathDataBuffer, i + 1, out i, numbers); if (numbers.Count == 4) { var quadCurve = new SvgPathSegCurveToQuadratic( numbers[0], numbers[1], numbers[2], numbers[3]); quadCurve.IsRelative = c == 'q'; pathSegments.Add(quadCurve); } else { throw new NotSupportedException(); } numbers.Clear(); } break; case 'S': case 's': { ParseNumberList(pathDataBuffer, i + 1, out i, numbers); if (numbers.Count == 4) { var scubicCurve = new SvgPathSegCurveToCubicSmooth( numbers[0], numbers[1], numbers[2], numbers[3]); scubicCurve.IsRelative = c == 's'; pathSegments.Add(scubicCurve); } else { throw new NotSupportedException(); } numbers.Clear(); } break; case 'T': case 't': { ParseNumberList(pathDataBuffer, i + 1, out i, numbers); if (numbers.Count == 2) { var squadCurve = new SvgPathSegCurveToQuadraticSmooth( numbers[0], numbers[1]); squadCurve.IsRelative = c == 't'; pathSegments.Add(squadCurve); } else { throw new NotSupportedException(); } numbers.Clear(); } break; default: { } break; } } break; default: { } break; } } return(pathSegments); }
public static void MakeBezierCurveFromArc(ref PointF start, ref PointF end, float rx, float ry, float angle, SvgArcSize arcSize, SvgArcSweep arcSweep, out PointF[] bezier4Points) { double sinPhi = Math.Sin(angle * SvgPathSegArc.RAD_PER_DEG); double cosPhi = Math.Cos(angle * SvgPathSegArc.RAD_PER_DEG); double x1dash = cosPhi * (start.X - end.X) / 2.0 + sinPhi * (start.Y - end.Y) / 2.0; double y1dash = -sinPhi * (start.X - end.X) / 2.0 + cosPhi * (start.Y - end.Y) / 2.0; double root; double numerator = (rx * rx * ry * ry) - (rx * rx * y1dash * y1dash) - (ry * ry * x1dash * x1dash); if (numerator < 0.0) { float s = (float)Math.Sqrt(1.0 - numerator / (rx * rx * ry * ry)); rx *= s; ry *= s; root = 0.0; } else { root = ((arcSize == SvgArcSize.Large && arcSweep == SvgArcSweep.Positive) || (arcSize == SvgArcSize.Small && arcSweep == SvgArcSweep.Negative) ? -1.0 : 1.0) * Math.Sqrt(numerator / (rx * rx * y1dash * y1dash + ry * ry * x1dash * x1dash)); } double cxdash = root * rx * y1dash / ry; double cydash = -root * ry * x1dash / rx; double cx = cosPhi * cxdash - sinPhi * cydash + (start.X + end.X) / 2.0; double cy = sinPhi * cxdash + cosPhi * cydash + (start.Y + end.Y) / 2.0; double theta1 = SvgPathSegArc.CalculateVectorAngle(1.0, 0.0, (x1dash - cxdash) / rx, (y1dash - cydash) / ry); double dtheta = SvgPathSegArc.CalculateVectorAngle((x1dash - cxdash) / rx, (y1dash - cydash) / ry, (-x1dash - cxdash) / rx, (-y1dash - cydash) / ry); if (arcSweep == SvgArcSweep.Negative && dtheta > 0) { dtheta -= 2.0 * Math.PI; } else if (arcSweep == SvgArcSweep.Positive && dtheta < 0) { dtheta += 2.0 * Math.PI; } int nsegments = (int)Math.Ceiling((double)Math.Abs(dtheta / (Math.PI / 2.0))); double delta = dtheta / nsegments; double t = 8.0 / 3.0 * Math.Sin(delta / 4.0) * Math.Sin(delta / 4.0) / Math.Sin(delta / 2.0); double startX = start.X; double startY = start.Y; bezier4Points = new PointF[nsegments * 4]; int nn = 0; for (int n = 0; n < nsegments; ++n) { double cosTheta1 = Math.Cos(theta1); double sinTheta1 = Math.Sin(theta1); double theta2 = theta1 + delta; double cosTheta2 = Math.Cos(theta2); double sinTheta2 = Math.Sin(theta2); double endpointX = cosPhi * rx * cosTheta2 - sinPhi * ry * sinTheta2 + cx; double endpointY = sinPhi * rx * cosTheta2 + cosPhi * ry * sinTheta2 + cy; double dx1 = t * (-cosPhi * rx * sinTheta1 - sinPhi * ry * cosTheta1); double dy1 = t * (-sinPhi * rx * sinTheta1 + cosPhi * ry * cosTheta1); double dxe = t * (cosPhi * rx * sinTheta2 + sinPhi * ry * cosTheta2); double dye = t * (sinPhi * rx * sinTheta2 - cosPhi * ry * cosTheta2); bezier4Points[nn] = new PointF((float)startX, (float)startY); bezier4Points[nn + 1] = new PointF((float)(startX + dx1), (float)(startY + dy1)); bezier4Points[nn + 2] = new PointF((float)(endpointX + dxe), (float)(endpointY + dye)); bezier4Points[nn + 3] = new PointF((float)endpointX, (float)endpointY); nn += 4; theta1 = theta2; startX = (float)endpointX; startY = (float)endpointY; } }
public List<SvgPathSeg> Parse(char[] pathDataBuffer) { //parse pathdata to pathsegments List<SvgPathSeg> pathSegments = new List<SvgPathSeg>(); List<float> numbers = new List<float>(); int j = pathDataBuffer.Length; int currentState = 0; for (int i = 0; i < j;) { //lex and parse char c = pathDataBuffer[i]; switch (currentState) { case 0: { //init state switch (c) { case 'M': case 'm': { //move to ParseNumberList(pathDataBuffer, i + 1, out i, numbers); if (numbers.Count == 2) { var moveTo = new SvgPathSegMoveTo( numbers[0], numbers[1]); moveTo.IsRelative = c == 'm'; pathSegments.Add(moveTo); } else { //error throw new NotSupportedException(); } numbers.Clear();//reset } break; case 'L': case 'l': { //line to ParseNumberList(pathDataBuffer, i + 1, out i, numbers); if (numbers.Count == 2) { var lineTo = new SvgPathSegLineTo( numbers[0], numbers[1]); lineTo.IsRelative = c == 'l'; pathSegments.Add(lineTo); } else { //error throw new NotSupportedException(); } numbers.Clear();//reset } break; case 'H': case 'h': { ParseNumberList(pathDataBuffer, i + 1, out i, numbers); if (numbers.Count == 1) { var h = new SvgPathSegLineToHorizontal( numbers[0]); h.IsRelative = c == 'h'; pathSegments.Add(h); } else { //error throw new NotSupportedException(); } numbers.Clear();//reset } break; case 'V': case 'v': { ParseNumberList(pathDataBuffer, i + 1, out i, numbers); if (numbers.Count == 1) { var v = new SvgPathSegLineToVertical( numbers[0]); v.IsRelative = c == 'v'; pathSegments.Add(v); } else { //error throw new NotSupportedException(); } numbers.Clear();//reset } break; case 'Z': case 'z': { pathSegments.Add(new SvgPathSegClosePath()); i++; } break; case 'A': case 'a': { ParseNumberList(pathDataBuffer, i + 1, out i, numbers); if (numbers.Count == 7) { var arc = new SvgPathSegArc( numbers[0], numbers[1], numbers[2], (int)numbers[3], (int)numbers[4], numbers[5], numbers[6]); arc.IsRelative = c == 'a'; pathSegments.Add(arc); } else { throw new NotSupportedException(); } numbers.Clear(); } break; case 'C': case 'c': { ParseNumberList(pathDataBuffer, i + 1, out i, numbers); if (numbers.Count == 6) { var squadCurve = new SvgPathSegCurveToCubic( numbers[0], numbers[1], numbers[2], numbers[3], numbers[4], numbers[5]); squadCurve.IsRelative = c == 'c'; pathSegments.Add(squadCurve); } else { throw new NotSupportedException(); } numbers.Clear(); } break; case 'Q': case 'q': { ParseNumberList(pathDataBuffer, i + 1, out i, numbers); if (numbers.Count == 4) { var quadCurve = new SvgPathSegCurveToQuadratic( numbers[0], numbers[1], numbers[2], numbers[3]); quadCurve.IsRelative = c == 'q'; pathSegments.Add(quadCurve); } else { throw new NotSupportedException(); } numbers.Clear(); } break; case 'S': case 's': { ParseNumberList(pathDataBuffer, i + 1, out i, numbers); if (numbers.Count == 4) { var scubicCurve = new SvgPathSegCurveToCubicSmooth( numbers[0], numbers[1], numbers[2], numbers[3]); scubicCurve.IsRelative = c == 's'; pathSegments.Add(scubicCurve); } else { throw new NotSupportedException(); } numbers.Clear(); } break; case 'T': case 't': { ParseNumberList(pathDataBuffer, i + 1, out i, numbers); if (numbers.Count == 2) { var squadCurve = new SvgPathSegCurveToQuadraticSmooth( numbers[0], numbers[1]); squadCurve.IsRelative = c == 't'; pathSegments.Add(squadCurve); } else { throw new NotSupportedException(); } numbers.Clear(); } break; default: { } break; } } break; default: { } break; } } return pathSegments; }