Point GetNextPointFromCurveData(CurveStream curveStream) { return new Point(GetNextDoubleFromCurveData(curveStream), GetNextDoubleFromCurveData(curveStream)); }
double GetNextDoubleFromCurveData(CurveStream curveStream) { var a = curveStream.GetNextCurveStreamElement(); if (a == null) Error("cannot parse curveData"); var d = a as DoubleStreamElement; if (d == null) Error("cannot parse curveData"); // ReSharper disable PossibleNullReferenceException return d.Double; // ReSharper restore PossibleNullReferenceException }
void ProceedWithLines(Curve curve, CurveStream curveStream, ref Point currentPoint) { do { curve.AddSegment(new LineSegment(currentPoint, currentPoint = GetNextPointFromCurveData(curveStream))); } while (curveStream.PickNextCurveStreamElement() is DoubleStreamElement); }
ICurve ReadEllepticalArc(CurveStream curveStream, ref Point currentPoint) { /* var rx = "A"+DoubleToString(ellipse.AxisA.Length); var ry = DoubleToString(ellipse.AxisB.Length); var xAxisRotation = DoubleToString(180*Point.Angle(new Point(1, 0), ellipse.AxisA)/Math.PI); var largeArcFlag = Math.Abs(ellipse.ParEnd - ellipse.ParStart) >= Math.PI ? "1" : "0"; var sweepFlag = ellipse.ParEnd > ellipse.ParStart ? "1" : "0"; //it happens because of the y-axis orientation down in SVG var endPoint=PointToString(ellipse.End); return string.Join(" ", new[] {rx, ry, xAxisRotation, largeArcFlag, sweepFlag, endPoint}); var endPoint = GetCurveDataPoint(curveStream); */ var rx = GetNextDoubleFromCurveData(curveStream); var ry = GetNextDoubleFromCurveData(curveStream); var xAxisRotation = GetNextDoubleFromCurveData(curveStream)/180*Math.PI; var largeArcFlag = (int) GetNextDoubleFromCurveData(curveStream); var sweepFlag = (int) GetNextDoubleFromCurveData(curveStream); var endPoint = GetNextPointFromCurveData(curveStream); //figure out the transform to the circle //then solve this problem on the circle if (ApproximateComparer.Close(rx, 0) || ApproximateComparer.Close(ry, 0)) Error("ellipseArc radius is too small"); var yScale = rx/ry; var rotationMatrix = PlaneTransformation.Rotation(-xAxisRotation); var scaleMatrix = new PlaneTransformation(1, 0, 0, 0, yScale, 0); var transform = scaleMatrix*rotationMatrix; var start = transform*currentPoint; currentPoint = endPoint; var end = transform*endPoint; Point center; double startAngle; double endAngle; Point axisY; GetArcCenterAndAngles(rx, largeArcFlag, sweepFlag, start, end, out center, out startAngle, out endAngle, out axisY); var inverted = transform.Inverse; center = inverted*center; var rotation = PlaneTransformation.Rotation(xAxisRotation); var axisX = rotation*new Point(rx, 0); axisY = rotation*(axisY/yScale); var ret = new Ellipse(startAngle, endAngle, axisX, axisY, center); Debug.Assert(ApproximateComparer.Close(ret.End, endPoint)); return ret; }
void ReadEllepticalArc(Curve curve, CurveStream curveStream, ref Point currentPoint) { curve.AddSegment(ReadEllepticalArc(curveStream, ref currentPoint)); }
void AddCurveSegment(CurveStream curveStream, char c, Curve curve, ref Point currentPoint) { switch (c) { case 'M': //moveto currentPoint = GetNextPointFromCurveData(curveStream); break; case 'm': //relative moveto throw new NotImplementedException(); case 'Z': case 'z': //closepath if (curve.Segments.Count == 0) Error("the curve is too short"); curve.AddSegment(new LineSegment(currentPoint, currentPoint = curve.Start)); break; case 'L': //lineto ProceedWithLines(curve, curveStream, ref currentPoint); break; case 'l': //lineto relative throw new NotImplementedException(); case 'H': //lineto horizontal throw new NotImplementedException(); case 'h': //lineto horizontal relative throw new NotImplementedException(); case 'V': //lineto vertical throw new NotImplementedException(); case 'v': //lineto vertical relative throw new NotImplementedException(); case 'C': //cubic Bezier ProceedWithCubicBeziers(curve, curveStream, ref currentPoint); break; case 'c': //cubic Bezier relative throw new NotImplementedException(); case 'S': //cubic Bezier shorthand throw new NotImplementedException(); case 's': //cubic Bezier relative shorthand throw new NotImplementedException(); case 'Q': //quadratic Bezier throw new NotImplementedException(); case 'q': //quadratic Bezier relative throw new NotImplementedException(); case 'T': //quadratic Bezier shorthand throw new NotImplementedException(); case 't': //quadratic Bezier relative shorthand throw new NotImplementedException(); case 'A': //elleptical arc ReadEllepticalArc(curve, curveStream, ref currentPoint); break; case 'a': //eleptical arc relative throw new NotImplementedException(); default: Error("unknown character " + c); break; } }
ICurve ParseCurve(string curveData) { var curve = new Curve(); var curveStream = new CurveStream(curveData); var currentPoint = new Point(); do { var curveStreamElement = curveStream.GetNextCurveStreamElement(); if (curveStreamElement == null) return curve; var charStreamElement = curveStreamElement as CharStreamElement; if (charStreamElement == null) { Error("wrong formatted curve string " + curveStreamElement); return null; } AddCurveSegment(curveStream, charStreamElement.Char, curve, ref currentPoint); } while (true); }