Exemple #1
0
    /// <summary>
    /// Parses a PathFigure element.
    /// </summary>
    PathFigure ParsePathFigure()
    {
      Debug.Assert(this.reader.Name == "PathFigure");
      bool isEmptyElement = this.reader.IsEmptyElement;
      PathFigure fig = new PathFigure();
      while (MoveToNextAttribute())
      {
        switch (this.reader.Name)
        {
          case "IsClosed":
            fig.IsClosed = ParseBool(this.reader.Value);
            break;

          case "StartPoint":
            fig.StartPoint = Point.Parse(this.reader.Value);
            break;

          case "IsFilled":
            fig.IsFilled = ParseBool(this.reader.Value);
            break;

          default:
            UnexpectedAttribute(this.reader.Name);
            break;
        }
      }
      if (!isEmptyElement)
      {
        MoveToNextElement();
        while (this.reader.IsStartElement())
        {
          switch (this.reader.Name)
          {
            case "PolyLineSegment":
              fig.Segments.Add(ParsePolyLineSegment());
              break;

            case "PolyBezierSegment":
              fig.Segments.Add(ParsePolyBezierSegment());
              break;

            case "ArcSegment":
              fig.Segments.Add(ParseArcSegment());
              break;

            case "PolyQuadraticBezierSegment":
              fig.Segments.Add(ParsePolyQuadraticBezierSegment());
              break;

            default:
              Debugger.Break();
              break;
          }
        }
      }
      MoveToNextElement();
      return fig;
    }
    void AddCapToPath(Path path, PathFigure figure, double length, double lineWidthHalf, LineCap lineCap, XMatrix matrix)
    {
      // sketch:
      // 1. create Transform that make a horizontal line with start in 0,0
      // 2. create a Polygon with the shape of the line including its caps
      // 3. render the shape with the brush of the pen
      //PolyLineSegment seg;
      switch (lineCap)
      {
        case LineCap.Flat:
          matrix.Transform(new XPoint(length + lineWidthHalf, -lineWidthHalf));
          break;

        case LineCap.Square:
          matrix.Transform(new XPoint(length + lineWidthHalf, -lineWidthHalf));
          break;

        case LineCap.Round:
          break;

        case LineCap.Triangle:
          break;
      }
    }
    /// <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;
    }