none
如何在Inkcanvas中实现类似纹理笔的轨迹? RRS feed

  • 问题

  • 请问如何在inkcanvas中绘制类似纹理笔的轨迹?

    我以某图案作为brush,重载DrawCore方法,如何使用这个brush填充绘制的区域?

    2011年8月27日 3:25

答案

  • 不错的想法,不过我还是得闲看看你的代码逻辑是怎么实现的。我实现出来的和你的效果一样,在过快时候是间隔过大。 Stroke采样是有他自己的频率的,如果我们的手势运动过快的话,势必会造成某些采样点的间隔过大。

    不过我通过判断填充间隙过大空间完成了你要的效果,你看下代码:

     public partial class MainWindow : Window
     {
      public MainWindow()
      {
       InitializeComponent();
      }
    
      Point previousPoint, currentPoint;
      bool IsDrawing = false;
      private void inkcanvas_MouseDown(object sender, MouseButtonEventArgs e)
      {
       if (inkcanvas.EditingMode == InkCanvasEditingMode.None)
       {
        IsDrawing = true;
        previousPoint = e.GetPosition((IInputElement)sender);
       }
      }
    
      Stroke st = null;
      double imageWidth = 30;
      double distance = 0.0;
      private void inkcanvas_MouseMove(object sender, MouseEventArgs e)
      {
       if (IsDrawing)
       {
        currentPoint = e.GetPosition((IInputElement)sender);
    
        distance = Math.Sqrt(Math.Pow(currentPoint.X - previousPoint.X, 2) + Math.Pow(currentPoint.Y - previousPoint.Y, 2));
    
        while (distance >= imageWidth)
        {
         double x = imageWidth * (Math.Sin(Math.Atan(Math.Abs(currentPoint.X - previousPoint.X) / Math.Abs(currentPoint.Y - previousPoint.Y)))) * (currentPoint.X > previousPoint.X ? 1.0 : -1.0) + previousPoint.X;
         double y = imageWidth * (Math.Cos(Math.Atan(Math.Abs(currentPoint.X - previousPoint.X) / Math.Abs(currentPoint.Y - previousPoint.Y)))) * (currentPoint.Y > previousPoint.Y ? 1.0 : -1.0) + previousPoint.Y;
         distance -= imageWidth;
         previousPoint = new Point(x, y);
    
         StylusPointCollection pts = new StylusPointCollection();
         pts.Add(new StylusPoint(x, y));
         st = new customStroke(pts);
         inkcanvas.Strokes.Add(st);
        }
    
       }
      }
    
      private void inkcanvas_MouseUp(object sender, MouseButtonEventArgs e)
      {
       if (inkcanvas.EditingMode == InkCanvasEditingMode.None)
       {
        if (st != null)
        {
         inkcanvas.Strokes.Remove(st);
         inkcanvas.Strokes.Add(st.Clone());
        }
        IsDrawing = false;
       }
      }
     }
    
     public class customStroke : Stroke
     {
      public customStroke(StylusPointCollection pts)
       : base(pts)
      {
       this.StylusPoints = pts;
      }
    
      protected override void DrawCore(DrawingContext drawingContext, DrawingAttributes drawingAttributes)
      {
       if (drawingContext == null)
       {
        throw new ArgumentNullException("drawingContext");
       }
       if (null == drawingAttributes)
       {
        throw new ArgumentNullException("drawingAttributes");
       }
    
       DrawingAttributes originalDa = drawingAttributes.Clone();
       originalDa.Width = 30;
       originalDa.Height = 30;
       ImageBrush brush = new ImageBrush(new BitmapImage(new Uri(@"XD.jpg", UriKind.Relative)));
       brush.Freeze();
       drawingContext.DrawGeometry(brush, null, this.GetGeometry(originalDa));
    
      }
     }
    

    例子下载:https://skydrive.live.com/?cid=51b2fdd068799d15#!/?cid=51b2fdd068799d15&sc=documents&uc=1&id=51B2FDD068799D15%21811

     

    Sincerely,

     

     

     


    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • 已标记为答案 张柱敏 2011年8月31日 5:42
    2011年8月30日 6:51
    版主

全部回复

  • 在 DrawCore 中通过 drawingContext.DrawXXX 绘制图形的时候,你可以把你的Brush作为背景色填充。比如,我们需要画一个圆形,在 DrawCore 里面可以这么写:

            protected override void DrawCore(DrawingContext drawingContext, DrawingAttributes drawingAttributes)
            {
                if (drawingContext == null)
                {
                    throw new ArgumentNullException("drawingContext");
                }
                if (null == drawingAttributes)
                {
                    throw new ArgumentNullException("drawingAttributes");
                }
                Pen pen = new Pen
                {
                    StartLineCap = PenLineCap.Round,
                    EndLineCap = PenLineCap.Round,
                    Brush = new SolidColorBrush(drawingAttributes.Color),
                    Thickness = LineWidth
                };
                Rect r = new Rect(
                    new Point(StylusPoints[0].X, StylusPoints[0].Y),
                    new Point(StylusPoints[1].X, StylusPoints[1].Y));
     
                Point center = new Point(
                     (r.Left + r.Right) / 2.0,
                     (r.Top + r.Bottom) / 2.0);
     
                double radiusX = (r.Right - r.Left) / 2.0;
                double radiusY = (r.Bottom - r.Top) / 2.0;
     
     
                drawingContext.DrawEllipse(
                    new ImageBrush(new BitmapImage(new Uri(@"C:\Users\v-bobbao\Desktop\XD.jpg"UriKind.Absolute))),
                    pen,
                    center,
                    radiusX,
                    radiusY);
            }

    出来效果就是:

     

    注:以上代码参考了 HeroHua0509 同学的最近几个帖子。

     

    Sincerely,


    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2011年8月29日 5:48
    版主
  • .....

    我说窗口下面那一堆按钮怎么看着眼熟...

    哈哈


    Hero
    2011年8月29日 6:05
  • .....

    我说窗口下面那一堆按钮怎么看着眼熟...

    哈哈


    Hero

    你的代码我还没关掉, 就这个差不多的帖子,所以就用现成的了,哈哈
    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    2011年8月29日 6:16
    版主
  • 那个图我喜欢....XD

    银鳞胸甲...奥杜之杖...


    Hero
    2011年8月29日 6:20
  • 非常感谢回答!

    我想实现的效果是

    首先在外面设置了笔画的大小(width和height一样),在添加采样点的时候,我舍弃了之间距离过小的采样点(和笔画大小进行比较),然后在每一个采样点绘制椭圆。

    问题是 如果速度很快,两个采样点之间距离过大的话,就会出现断裂的情况。

    2011年8月29日 7:04
  • 不错的想法,不过我还是得闲看看你的代码逻辑是怎么实现的。我实现出来的和你的效果一样,在过快时候是间隔过大。 Stroke采样是有他自己的频率的,如果我们的手势运动过快的话,势必会造成某些采样点的间隔过大。

    不过我通过判断填充间隙过大空间完成了你要的效果,你看下代码:

     public partial class MainWindow : Window
     {
      public MainWindow()
      {
       InitializeComponent();
      }
    
      Point previousPoint, currentPoint;
      bool IsDrawing = false;
      private void inkcanvas_MouseDown(object sender, MouseButtonEventArgs e)
      {
       if (inkcanvas.EditingMode == InkCanvasEditingMode.None)
       {
        IsDrawing = true;
        previousPoint = e.GetPosition((IInputElement)sender);
       }
      }
    
      Stroke st = null;
      double imageWidth = 30;
      double distance = 0.0;
      private void inkcanvas_MouseMove(object sender, MouseEventArgs e)
      {
       if (IsDrawing)
       {
        currentPoint = e.GetPosition((IInputElement)sender);
    
        distance = Math.Sqrt(Math.Pow(currentPoint.X - previousPoint.X, 2) + Math.Pow(currentPoint.Y - previousPoint.Y, 2));
    
        while (distance >= imageWidth)
        {
         double x = imageWidth * (Math.Sin(Math.Atan(Math.Abs(currentPoint.X - previousPoint.X) / Math.Abs(currentPoint.Y - previousPoint.Y)))) * (currentPoint.X > previousPoint.X ? 1.0 : -1.0) + previousPoint.X;
         double y = imageWidth * (Math.Cos(Math.Atan(Math.Abs(currentPoint.X - previousPoint.X) / Math.Abs(currentPoint.Y - previousPoint.Y)))) * (currentPoint.Y > previousPoint.Y ? 1.0 : -1.0) + previousPoint.Y;
         distance -= imageWidth;
         previousPoint = new Point(x, y);
    
         StylusPointCollection pts = new StylusPointCollection();
         pts.Add(new StylusPoint(x, y));
         st = new customStroke(pts);
         inkcanvas.Strokes.Add(st);
        }
    
       }
      }
    
      private void inkcanvas_MouseUp(object sender, MouseButtonEventArgs e)
      {
       if (inkcanvas.EditingMode == InkCanvasEditingMode.None)
       {
        if (st != null)
        {
         inkcanvas.Strokes.Remove(st);
         inkcanvas.Strokes.Add(st.Clone());
        }
        IsDrawing = false;
       }
      }
     }
    
     public class customStroke : Stroke
     {
      public customStroke(StylusPointCollection pts)
       : base(pts)
      {
       this.StylusPoints = pts;
      }
    
      protected override void DrawCore(DrawingContext drawingContext, DrawingAttributes drawingAttributes)
      {
       if (drawingContext == null)
       {
        throw new ArgumentNullException("drawingContext");
       }
       if (null == drawingAttributes)
       {
        throw new ArgumentNullException("drawingAttributes");
       }
    
       DrawingAttributes originalDa = drawingAttributes.Clone();
       originalDa.Width = 30;
       originalDa.Height = 30;
       ImageBrush brush = new ImageBrush(new BitmapImage(new Uri(@"XD.jpg", UriKind.Relative)));
       brush.Freeze();
       drawingContext.DrawGeometry(brush, null, this.GetGeometry(originalDa));
    
      }
     }
    

    例子下载:https://skydrive.live.com/?cid=51b2fdd068799d15#!/?cid=51b2fdd068799d15&sc=documents&uc=1&id=51B2FDD068799D15%21811

     

    Sincerely,

     

     

     


    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • 已标记为答案 张柱敏 2011年8月31日 5:42
    2011年8月30日 6:51
    版主
  • 非常感谢!您这个方法比使用一个笔画来表现效果效率高很多,使用一笔来绘制 开始的时候速度还可以,但是越到后面延迟越明显。
    2011年8月31日 5:44