예제 #1
0
        /// <summary>
        /// Parses a PathGeometry from a data string element.
        /// </summary>
        PathGeometry ParsePathGeometry(string data)
        {
#if DEBUG_
            // XPS = M 20,100 C 45,50 70,150 95,100 S 145,150 170,100 220,150 245,100 C 220,50 195,150 170,100 S 120,150 95,100 45,150 20,100
            // XXX = M20,100C45,50 70,150 95,100 120,50 145,150 170,100 195,50 220,150 245,100 220,50 195,150 170,100 145,50 120,150 95,100 70,50 45,150 20,100
            if (data.StartsWith("M 20,100 C 45,50 70,150 95,100 S 145,"))
            {
                Debugger.Break();
            }
#endif
            PathGeometry geo = TryParseStaticResource <PathGeometry>(data);
            if (geo != null)
            {
                return(geo);
            }

            data = FixHack(data);
            // From the algorithm on page 365 in XPS 1.0 specs
            // See Petzold page 813
            geo = new PathGeometry();
            Point           point  = new Point();
            PathFigure      figure = null;
            TokenizerHelper helper = new TokenizerHelper(data);
            helper.NextTokenRequired();
            do
            {
                string token = helper.GetCurrentToken();
                switch (token[0])
                {
                // FillRule
                case 'F':
                    geo.FillRule = helper.NextTokenRequired() == "1" ? FillRule.NonZero : FillRule.EvenOdd;
                    break;

                // Move
                case 'M':
                {
                    figure = new PathFigure();
                    geo.Figures.Add(figure);
                    point             = new Point(ParseDouble(helper.NextTokenRequired()), ParseDouble(helper.NextTokenRequired()));
                    figure.StartPoint = point;
                }
                break;

                // Move
                case 'm':
                {
                    figure = new PathFigure();
                    geo.Figures.Add(figure);
                    point             = new Point(point.X + ParseDouble(helper.NextTokenRequired()), point.Y + ParseDouble(helper.NextTokenRequired()));
                    figure.StartPoint = point;
                }
                break;

                // Line
                case 'L':
                {
                    PolyLineSegment seg;
                    int             segCount = figure.Segments.Count;
                    if (segCount > 0 && (seg = figure.Segments[segCount - 1] as PolyLineSegment) != null)
                    {
                    }
                    else
                    {
                        seg = new PolyLineSegment();
                        figure.Segments.Add(seg);
                    }
                    do
                    {
                        point = new Point(ParseDouble(helper.NextTokenRequired()), ParseDouble(helper.NextTokenRequired()));
                        seg.Points.Add(point);
                    } while (!Char.IsLetter(helper.PeekNextCharacter()));
                }
                break;

                // Line
                case 'l':
                {
                    PolyLineSegment seg;
                    int             segCount = figure.Segments.Count;
                    if (segCount > 0 && (seg = figure.Segments[segCount - 1] as PolyLineSegment) != null)
                    {
                    }
                    else
                    {
                        seg = new PolyLineSegment();
                        figure.Segments.Add(seg);
                    }
                    do
                    {
                        point = new Point(ParseDouble(helper.NextTokenRequired()), ParseDouble(helper.NextTokenRequired()));
                        seg.Points.Add(point);
                    } while (!Char.IsLetter(helper.PeekNextCharacter()));
                }
                break;

                // Horizontal Line
                case 'H':
                {
                    PolyLineSegment seg;
                    int             segCount = figure.Segments.Count;
                    if (segCount > 0 && (seg = figure.Segments[segCount - 1] as PolyLineSegment) != null)
                    {
                    }
                    else
                    {
                        seg = new PolyLineSegment();
                        figure.Segments.Add(seg);
                    }
                    do
                    {
                        point.X = ParseDouble(helper.NextTokenRequired());
                        seg.Points.Add(point);
                    } while (!Char.IsLetter(helper.PeekNextCharacter()));
                }
                break;

                // Horizontal Line
                case 'h':
                {
                    PolyLineSegment seg;
                    int             segCount = figure.Segments.Count;
                    if (segCount > 0 && (seg = figure.Segments[segCount - 1] as PolyLineSegment) != null)
                    {
                    }
                    else
                    {
                        seg = new PolyLineSegment();
                        figure.Segments.Add(seg);
                    }
                    do
                    {
                        point.X += ParseDouble(helper.NextTokenRequired());
                        seg.Points.Add(point);
                    } while (!Char.IsLetter(helper.PeekNextCharacter()));
                }
                break;

                // Vertical Line
                case 'V':
                {
                    PolyLineSegment seg;
                    int             segCount = figure.Segments.Count;
                    if (segCount > 0 && (seg = figure.Segments[segCount - 1] as PolyLineSegment) != null)
                    {
                    }
                    else
                    {
                        seg = new PolyLineSegment();
                        figure.Segments.Add(seg);
                    }
                    do
                    {
                        point.Y = ParseDouble(helper.NextTokenRequired());
                        seg.Points.Add(point);
                    } while (!Char.IsLetter(helper.PeekNextCharacter()));
                }
                break;

                // Vertical Line
                case 'v':
                {
                    PolyLineSegment seg;
                    int             segCount = figure.Segments.Count;
                    if (segCount > 0 && (seg = figure.Segments[segCount - 1] as PolyLineSegment) != null)
                    {
                    }
                    else
                    {
                        seg = new PolyLineSegment();
                        figure.Segments.Add(seg);
                    }
                    do
                    {
                        point.Y += ParseDouble(helper.NextTokenRequired());
                        seg.Points.Add(point);
                    } while (!Char.IsLetter(helper.PeekNextCharacter()));
                }
                break;

                // Elliptical Arc
                case 'A':
                    do
                    {
                        // I cannot believe it: "A70.1,50.1 1,34 0 0 170.1,30.1"
                        // The rotation angle "1,34" uses a ',' instead of a '.' in my German Windows Vista!
                        //A70.1,50.1    1,34   0   0   170.1,30.1
                        ArcSegment seg = new ArcSegment();
                        figure.Segments.Add(seg);
                        seg.Size           = new Size(ParseDouble(helper.NextTokenRequired()), ParseDouble(helper.NextTokenRequired()));
                        seg.RotationAngle  = ParseDouble(helper.NextTokenRequired());
                        seg.IsLargeArc     = helper.NextTokenRequired() == "1";
                        seg.SweepDirection = helper.NextTokenRequired() == "1" ? SweepDirection.Clockwise : SweepDirection.Counterclockwise;
                        point     = new Point(ParseDouble(helper.NextTokenRequired()), ParseDouble(helper.NextTokenRequired()));
                        seg.Point = point;
                    } while (!Char.IsLetter(helper.PeekNextCharacter()));
                    break;

                // Elliptical Arc
                case 'a':
                    do
                    {
                        ArcSegment seg = new ArcSegment();
                        figure.Segments.Add(seg);
                        seg.Size           = new Size(ParseDouble(helper.NextTokenRequired()), ParseDouble(helper.NextTokenRequired()));
                        seg.RotationAngle  = ParseDouble(helper.NextTokenRequired());
                        seg.IsLargeArc     = helper.NextTokenRequired() == "1";
                        seg.SweepDirection = helper.NextTokenRequired() == "1" ? SweepDirection.Clockwise : SweepDirection.Counterclockwise;
                        point     = new Point(point.X + ParseDouble(helper.NextTokenRequired()), point.Y + ParseDouble(helper.NextTokenRequired()));
                        seg.Point = point;
                    } while (!Char.IsLetter(helper.PeekNextCharacter()));
                    break;

                // Cubic Bézier Curve
                case 'C':
                {
                    PolyBezierSegment seg;
                    int segCount = figure.Segments.Count;
                    if (segCount > 0 && (seg = figure.Segments[segCount - 1] as PolyBezierSegment) != null)
                    {
                    }
                    else
                    {
                        seg = new PolyBezierSegment();
                        figure.Segments.Add(seg);
                    }
                    do
                    {
                        seg.Points.Add(new Point(ParseDouble(helper.NextTokenRequired()), ParseDouble(helper.NextTokenRequired())));
                        seg.Points.Add(new Point(ParseDouble(helper.NextTokenRequired()), ParseDouble(helper.NextTokenRequired())));
                        point = new Point(ParseDouble(helper.NextTokenRequired()), ParseDouble(helper.NextTokenRequired()));
                        seg.Points.Add(point);
                    } while (!Char.IsLetter(helper.PeekNextCharacter()));
                }
                break;

                // Cubic Bézier Curve
                case 'c':
                {
                    PolyBezierSegment seg;
                    int segCount = figure.Segments.Count;
                    if (segCount > 0 && (seg = figure.Segments[segCount - 1] as PolyBezierSegment) != null)
                    {
                    }
                    else
                    {
                        seg = new PolyBezierSegment();
                        figure.Segments.Add(seg);
                    }
                    do
                    {
                        seg.Points.Add(new Point(point.X + ParseDouble(helper.NextTokenRequired()), point.Y + ParseDouble(helper.NextTokenRequired())));
                        seg.Points.Add(new Point(point.X + ParseDouble(helper.NextTokenRequired()), point.Y + ParseDouble(helper.NextTokenRequired())));
                        point = new Point(point.X + ParseDouble(helper.NextTokenRequired()), point.Y + ParseDouble(helper.NextTokenRequired()));
                        seg.Points.Add(point);
                    } while (!Char.IsLetter(helper.PeekNextCharacter()));
                }
                break;

                // Smooth Cubic Bézier Curve
                case 'S':
                {
                    PolyBezierSegment seg;
                    int segCount = figure.Segments.Count;
                    if (segCount > 0 && (seg = figure.Segments[segCount - 1] as PolyBezierSegment) != null)
                    {
                    }
                    else
                    {
                        seg = new PolyBezierSegment();
                        figure.Segments.Add(seg);
                    }
                    do
                    {
                        Point pt    = new Point();
                        int   count = seg.Points.Count;
                        segCount = figure.Segments.Count;
                        if (count > 0)
                        {
                            Point lastCtrlPoint = seg.Points[count - 2];
                            pt.X = 2 * point.X - lastCtrlPoint.X;
                            pt.Y = 2 * point.Y - lastCtrlPoint.Y;
                        }
                        else if (segCount > 1 && figure.Segments[count - 2] is PolyBezierSegment)
                        {
                            PolyBezierSegment lastSeg = (PolyBezierSegment)figure.Segments[count - 2];
                            count = lastSeg.Points.Count;
                            Point lastCtrlPoint = lastSeg.Points[count - 2];
                            pt.X = 2 * point.X - lastCtrlPoint.X;
                            pt.Y = 2 * point.Y - lastCtrlPoint.Y;
                        }
                        else
                        {
                            pt = point;
                        }
                        seg.Points.Add(pt);
                        seg.Points.Add(new Point(ParseDouble(helper.NextTokenRequired()), ParseDouble(helper.NextTokenRequired())));
                        point = new Point(ParseDouble(helper.NextTokenRequired()), ParseDouble(helper.NextTokenRequired()));
                        seg.Points.Add(point);
                    } while (!Char.IsLetter(helper.PeekNextCharacter()));
                }
                break;

                // Smooth Cubic Bézier Curve
                case 's':
                {
                    PolyBezierSegment seg;
                    int segCount = figure.Segments.Count;
                    if (segCount > 0 && (seg = figure.Segments[segCount - 1] as PolyBezierSegment) != null)
                    {
                    }
                    else
                    {
                        seg = new PolyBezierSegment();
                        figure.Segments.Add(seg);
                    }
                    do
                    {
                        Point pt    = new Point();
                        int   count = seg.Points.Count;
                        segCount = figure.Segments.Count;
                        if (count > 0)
                        {
                            Point lastCtrlPoint = seg.Points[count - 2];
                            pt.X = 2 * point.X - lastCtrlPoint.X;
                            pt.Y = 2 * point.Y - lastCtrlPoint.Y;
                        }
                        else if (segCount > 1 && figure.Segments[count - 2] is PolyBezierSegment)
                        {
                            PolyBezierSegment lastSeg = (PolyBezierSegment)figure.Segments[count - 2];
                            count = lastSeg.Points.Count;
                            Point lastCtrlPoint = lastSeg.Points[count - 2];
                            pt.X = 2 * point.X - lastCtrlPoint.X;
                            pt.Y = 2 * point.Y - lastCtrlPoint.Y;
                        }
                        else
                        {
                            pt = point;
                        }
                        seg.Points.Add(pt);
                        seg.Points.Add(new Point(point.X + ParseDouble(helper.NextTokenRequired()), point.Y + ParseDouble(helper.NextTokenRequired())));
                        point = new Point(point.X + ParseDouble(helper.NextTokenRequired()), point.Y + ParseDouble(helper.NextTokenRequired()));
                        seg.Points.Add(point);
                    } while (!Char.IsLetter(helper.PeekNextCharacter()));
                }
                break;

                // Quadratic Bézier Curve
                case 'Q':
                {
                    PolyQuadraticBezierSegment seg = new PolyQuadraticBezierSegment();
                    figure.Segments.Add(seg);
                    do
                    {
                        seg.Points.Add(new Point(ParseDouble(helper.NextTokenRequired()), ParseDouble(helper.NextTokenRequired())));
                        point = new Point(ParseDouble(helper.NextTokenRequired()), ParseDouble(helper.NextTokenRequired()));
                        seg.Points.Add(point);
                    } while (!Char.IsLetter(helper.PeekNextCharacter()));
                }
                break;

                // Quadratic Bézier Curve
                case 'q':
                {
                    PolyQuadraticBezierSegment seg = new PolyQuadraticBezierSegment();
                    figure.Segments.Add(seg);
                    do
                    {
                        seg.Points.Add(new Point(point.X + ParseDouble(helper.NextTokenRequired()), point.Y + ParseDouble(helper.NextTokenRequired())));
                        point = new Point(point.X + ParseDouble(helper.NextTokenRequired()), point.Y + ParseDouble(helper.NextTokenRequired()));
                        seg.Points.Add(point);
                    } while (!Char.IsLetter(helper.PeekNextCharacter()));
                }
                break;

                // Close
                case 'Z':
                case 'z':
                {
                    figure.IsClosed = true;
                    if (figure.Segments.Count > 0)
                    {
                        PathSegment seg = figure.Segments[0];
                    }
                    point  = figure.StartPoint;
                    figure = null;
                }
                break;

                default:
                    Debug.Assert(false);
                    break;
                }
            } while (helper.NextToken());
            return(geo);
        }