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;
				}
			}
		}
예제 #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);
                }
            }
        }
예제 #3
0
 void AddLine(PathF path, LineSegment lineSegment)
 {
     path.LineTo((float)lineSegment.Point.X, (float)lineSegment.Point.Y);
 }