static void ParseToPathFigureCollection(PathFigureCollection pathFigureCollection, string pathString, int startIndex)
        {
            PathFigure pathFigure = null;

            _pathString = pathString;
            _pathLength = pathString.Length;
            _curIndex   = startIndex;

            _secondLastPoint = new Point(0, 0);
            _lastPoint       = new Point(0, 0);
            _lastStart       = new Point(0, 0);

            _figureStarted = false;

            bool first = true;

            char last_cmd = ' ';

            while (ReadToken())             // Empty path is allowed in XAML
            {
                char cmd = _token;

                if (first)
                {
                    if ((cmd != 'M') && (cmd != 'm'))                      // Path starts with M|m
                    {
                        ThrowBadToken();
                    }

                    first = false;
                }

                switch (cmd)
                {
                case 'm':
                case 'M':
                    // XAML allows multiple points after M/m
                    _lastPoint = ReadPoint(cmd, !AllowComma);

                    pathFigure = new PathFigure
                    {
                        StartPoint = _lastPoint
                    };
                    pathFigureCollection.Add(pathFigure);

                    _figureStarted = true;
                    _lastStart     = _lastPoint;
                    last_cmd       = 'M';

                    while (IsNumber(AllowComma))
                    {
                        _lastPoint = ReadPoint(cmd, !AllowComma);

                        LineSegment lineSegment = new LineSegment
                        {
                            Point = _lastPoint
                        };
                        pathFigure.Segments.Add(lineSegment);

                        last_cmd = 'L';
                    }
                    break;

                case 'l':
                case 'L':
                case 'h':
                case 'H':
                case 'v':
                case 'V':
                    EnsureFigure();

                    do
                    {
                        switch (cmd)
                        {
                        case 'l':
                            _lastPoint = ReadPoint(cmd, !AllowComma);
                            break;

                        case 'L':
                            _lastPoint = ReadPoint(cmd, !AllowComma);
                            break;

                        case 'h':
                            _lastPoint.X += ReadNumber(!AllowComma);
                            break;

                        case 'H':
                            _lastPoint.X = ReadNumber(!AllowComma);
                            break;

                        case 'v':
                            _lastPoint.Y += ReadNumber(!AllowComma);
                            break;

                        case 'V':
                            _lastPoint.Y = ReadNumber(!AllowComma);
                            break;
                        }

                        pathFigure.Segments.Add(new LineSegment
                        {
                            Point = _lastPoint
                        });
                    }while (IsNumber(AllowComma));

                    last_cmd = 'L';
                    break;

                case 'c':
                case 'C':                         // Cubic Bezier
                case 's':
                case 'S':                         // Smooth cublic Bezier
                    EnsureFigure();

                    do
                    {
                        Point p;

                        if ((cmd == 's') || (cmd == 'S'))
                        {
                            if (last_cmd == 'C')
                            {
                                p = Reflect();
                            }
                            else
                            {
                                p = _lastPoint;
                            }

                            _secondLastPoint = ReadPoint(cmd, !AllowComma);
                        }
                        else
                        {
                            p = ReadPoint(cmd, !AllowComma);

                            _secondLastPoint = ReadPoint(cmd, AllowComma);
                        }

                        _lastPoint = ReadPoint(cmd, AllowComma);

                        BezierSegment bezierSegment = new BezierSegment
                        {
                            Point1 = p,
                            Point2 = _secondLastPoint,
                            Point3 = _lastPoint
                        };

                        pathFigure.Segments.Add(bezierSegment);

                        last_cmd = 'C';
                    }while (IsNumber(AllowComma));

                    break;

                case 'q':
                case 'Q':                         // Quadratic Bezier
                case 't':
                case 'T':                         // Smooth quadratic Bezier
                    EnsureFigure();

                    do
                    {
                        if ((cmd == 't') || (cmd == 'T'))
                        {
                            if (last_cmd == 'Q')
                            {
                                _secondLastPoint = Reflect();
                            }
                            else
                            {
                                _secondLastPoint = _lastPoint;
                            }

                            _lastPoint = ReadPoint(cmd, !AllowComma);
                        }
                        else
                        {
                            _secondLastPoint = ReadPoint(cmd, !AllowComma);
                            _lastPoint       = ReadPoint(cmd, AllowComma);
                        }

                        QuadraticBezierSegment quadraticBezierSegment = new QuadraticBezierSegment
                        {
                            Point1 = _secondLastPoint,
                            Point2 = _lastPoint
                        };

                        pathFigure.Segments.Add(quadraticBezierSegment);

                        last_cmd = 'Q';
                    }while (IsNumber(AllowComma));

                    break;

                case 'a':
                case 'A':
                    EnsureFigure();

                    do
                    {
                        // A 3,4 5, 0, 0, 6,7
                        double w        = ReadNumber(!AllowComma);
                        double h        = ReadNumber(AllowComma);
                        double rotation = ReadNumber(AllowComma);
                        bool   large    = ReadBool();
                        bool   sweep    = ReadBool();

                        _lastPoint = ReadPoint(cmd, AllowComma);

                        ArcSegment arcSegment = new ArcSegment
                        {
                            Size           = new Size(w, h),
                            RotationAngle  = rotation,
                            IsLargeArc     = large,
                            SweepDirection = sweep ? SweepDirection.Clockwise : SweepDirection.CounterClockwise,
                            Point          = _lastPoint
                        };

                        pathFigure.Segments.Add(arcSegment);
                    }while (IsNumber(AllowComma));

                    last_cmd = 'A';
                    break;

                case 'z':
                case 'Z':
                    EnsureFigure();
                    pathFigure.IsClosed = true;
                    _figureStarted      = false;
                    last_cmd            = 'Z';

                    _lastPoint = _lastStart;                             // Set reference point to be first point of current figure
                    break;

                default:
                    ThrowBadToken();
                    break;
                }
            }
        }
Exemplo n.º 2
0
		public static void FlattenGeometry(PathGeometry pathGeoDst, Geometry geoSrc, double tolerance, Matrix matxPrevious)
		{
			Matrix matx = matxPrevious;

			if (geoSrc is GeometryGroup)
			{
				foreach (Geometry geoChild in (geoSrc as GeometryGroup).Children)
				{
					FlattenGeometry(pathGeoDst, geoChild, tolerance, matx);
				}
			}
			else if (geoSrc is LineGeometry)
			{
				LineGeometry lineGeoSrc = geoSrc as LineGeometry;
				PathFigure figDst = new PathFigure();
				PolyLineSegment segDst = new PolyLineSegment();

				figDst.StartPoint = matx.Transform(lineGeoSrc.StartPoint);
				segDst.Points.Add(matx.Transform(lineGeoSrc.EndPoint));

				figDst.Segments.Add(segDst);
				pathGeoDst.Figures.Add(figDst);
			}
			else if (geoSrc is RectangleGeometry)
			{
				RectangleGeometry rectGeoSrc = geoSrc as RectangleGeometry;
				PathFigure figDst = new PathFigure();
				PolyLineSegment segDst = new PolyLineSegment();

				figDst.StartPoint = matx.Transform(new Point(rectGeoSrc.Rect.Left, rectGeoSrc.Rect.Top));
				segDst.Points.Add(matx.Transform(new Point(rectGeoSrc.Rect.Right, rectGeoSrc.Rect.Top)));
				segDst.Points.Add(matx.Transform(new Point(rectGeoSrc.Rect.Right, rectGeoSrc.Rect.Bottom)));
				segDst.Points.Add(matx.Transform(new Point(rectGeoSrc.Rect.Left, rectGeoSrc.Rect.Bottom)));
				segDst.Points.Add(matx.Transform(new Point(rectGeoSrc.Rect.Left, rectGeoSrc.Rect.Top)));

				figDst.IsClosed = true;
				figDst.Segments.Add(segDst);
				pathGeoDst.Figures.Add(figDst);
			}
			else if (geoSrc is EllipseGeometry)
			{
				EllipseGeometry elipGeoSrc = geoSrc as EllipseGeometry;
				PathFigure figDst = new PathFigure();
				PolyLineSegment segDst = new PolyLineSegment();

				int max = (int)(4 * (elipGeoSrc.RadiusX + elipGeoSrc.RadiusY) / tolerance);

				for (int i = 0; i < max; i++)
				{
					double x = elipGeoSrc.Center.X + elipGeoSrc.RadiusX * Math.Sin(i * 2 * Math.PI / max);
					double y = elipGeoSrc.Center.Y - elipGeoSrc.RadiusY * Math.Cos(i * 2 * Math.PI / max);
					Point pt = matx.Transform(new Point(x, y));

					if (i == 0)
						figDst.StartPoint = pt;
					else
						segDst.Points.Add(pt);
				}

				figDst.IsClosed = true;
				figDst.Segments.Add(segDst);
				pathGeoDst.Figures.Add(figDst);
			}
			else if (geoSrc is PathGeometry)
			{
				PathGeometry pathGeoSrc = geoSrc as PathGeometry;
				pathGeoDst.FillRule = pathGeoSrc.FillRule;

				foreach (PathFigure figSrc in pathGeoSrc.Figures)
				{
					PathFigure figDst = new PathFigure
					{
						IsFilled = figSrc.IsFilled,
						IsClosed = figSrc.IsClosed,
						StartPoint = matx.Transform(figSrc.StartPoint)
					};
					Point ptLast = figDst.StartPoint;

					foreach (PathSegment segSrc in figSrc.Segments)
					{
						PolyLineSegment segDst = new PolyLineSegment();

						if (segSrc is LineSegment)
						{
							LineSegment lineSegSrc = segSrc as LineSegment;
							ptLast = matx.Transform(lineSegSrc.Point);
							segDst.Points.Add(ptLast);
						}
						else if (segSrc is PolyLineSegment)
						{
							PolyLineSegment polySegSrc = segSrc as PolyLineSegment;

							foreach (Point pt in polySegSrc.Points)
							{
								ptLast = matx.Transform(pt);
								segDst.Points.Add(ptLast);
							}
						}
						else if (segSrc is BezierSegment)
						{
							BezierSegment bezSeg = segSrc as BezierSegment;
							Point pt0 = ptLast;
							Point pt1 = matx.Transform(bezSeg.Point1);
							Point pt2 = matx.Transform(bezSeg.Point2);
							Point pt3 = matx.Transform(bezSeg.Point3);

							Points.Clear();
							FlattenCubicBezier(Points, pt0, pt1, pt2, pt3, tolerance);

							for (int i = 1; i < Points.Count; i++)
								segDst.Points.Add(Points[i]);

							ptLast = Points[Points.Count - 1];
						}
						else if (segSrc is PolyBezierSegment)
						{
							PolyBezierSegment polyBezSeg = segSrc as PolyBezierSegment;

							for (int bez = 0; bez < polyBezSeg.Points.Count; bez += 3)
							{
								if (bez + 2 > polyBezSeg.Points.Count - 1)
									break;

								Point pt0 = ptLast;
								Point pt1 = matx.Transform(polyBezSeg.Points[bez]);
								Point pt2 = matx.Transform(polyBezSeg.Points[bez + 1]);
								Point pt3 = matx.Transform(polyBezSeg.Points[bez + 2]);

								Points.Clear();
								FlattenCubicBezier(Points, pt0, pt1, pt2, pt3, tolerance);

								for (int i = 1; i < Points.Count; i++)
									segDst.Points.Add(Points[i]);

								ptLast = Points[Points.Count - 1];
							}
						}
						else if (segSrc is QuadraticBezierSegment)
						{
							QuadraticBezierSegment quadBezSeg = segSrc as QuadraticBezierSegment;
							Point pt0 = ptLast;
							Point pt1 = matx.Transform(quadBezSeg.Point1);
							Point pt2 = matx.Transform(quadBezSeg.Point2);

							Points.Clear();
							FlattenQuadraticBezier(Points, pt0, pt1, pt2, tolerance);

							for (int i = 1; i < Points.Count; i++)
								segDst.Points.Add(Points[i]);

							ptLast = Points[Points.Count - 1];
						}
						else if (segSrc is PolyQuadraticBezierSegment)
						{
							PolyQuadraticBezierSegment polyQuadBezSeg = segSrc as PolyQuadraticBezierSegment;

							for (int bez = 0; bez < polyQuadBezSeg.Points.Count; bez += 2)
							{
								if (bez + 1 > polyQuadBezSeg.Points.Count - 1)
									break;

								Point pt0 = ptLast;
								Point pt1 = matx.Transform(polyQuadBezSeg.Points[bez]);
								Point pt2 = matx.Transform(polyQuadBezSeg.Points[bez + 1]);

								Points.Clear();
								FlattenQuadraticBezier(Points, pt0, pt1, pt2, tolerance);

								for (int i = 1; i < Points.Count; i++)
									segDst.Points.Add(Points[i]);

								ptLast = Points[Points.Count - 1];
							}
						}
						else if (segSrc is ArcSegment)
						{
							ArcSegment arcSeg = segSrc as ArcSegment;

							Points.Clear();

							FlattenArc(
								Points,
								ptLast,
								arcSeg.Point,
								arcSeg.Size.Width,
								arcSeg.Size.Height,
								arcSeg.RotationAngle,
								arcSeg.IsLargeArc,
								arcSeg.SweepDirection == SweepDirection.CounterClockwise,
								tolerance);

							// Set ptLast while transferring points
							for (int i = 1; i < Points.Count; i++)
								segDst.Points.Add(ptLast = Points[i]);
						}

						figDst.Segments.Add(segDst);
					}

					pathGeoDst.Figures.Add(figDst);
				}
			}
		}