C# 波浪线绘制

波浪线效果如上

界面绘制操作

 1     private Point? _startPoint = null;
 2     private void ContainerCanvas_OnPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
 3     {
 4         var position = e.GetPosition(ContainerCanvas);
 5         if (_startPoint == null)
 6         {
 7             _startPoint = position;
 8         }
 9         else
10         {
11             //删除预览
12             if (_previewLineElement != null)
13             {
14                 ContainerCanvas.Children.Remove(_previewLineElement);
15                 _previewLineElement = null;
16                 _lastMovedPoint = null;
17             }
18             //确定结束点,绘制波浪线
19             var myLineElement = new MyLineElement();
20             myLineElement.DrawLine((Point)_startPoint, position);
21             ContainerCanvas.Children.Add(myLineElement);
22             _startPoint = null;
23         }
24     }
25 
26     private MyLineElement _previewLineElement = null;
27     private Point? _lastMovedPoint = null;
28 
29     /// <summary>
30     /// 波浪线绘制预览
31     /// </summary>
32     /// <param name="sender"></param>
33     /// <param name="e"></param>
34     private void ContainerCanvas_OnMouseMove(object sender, MouseEventArgs e)
35     {
36         var position = e.GetPosition(ContainerCanvas);
37         if (_startPoint != null && (_lastMovedPoint == null || _lastMovedPoint != null & (position - (Point)_lastMovedPoint).Length >= 2))
38         {
39             _lastMovedPoint = position;
40             if (_previewLineElement != null)
41             {
42                 ContainerCanvas.Children.Remove(_previewLineElement);
43             }
44             var myLineElement = new MyLineElement();
45             myLineElement.DrawLine((Point)_startPoint, position);
46             ContainerCanvas.Children.Add(myLineElement);
47             _previewLineElement = myLineElement;
48         }
49     }

波浪线控件及绘制

  1     class MyLineElement : FrameworkElement
  2     {
  3         public MyLineElement()
  4         {
  5             _visualShape = new VisualCollection(this);
  6         }
  7         internal void DrawLine(Point startPoint, Point endPoint)
  8         {
  9             List<Point> points = ForgePoints(startPoint, endPoint);
 10             DrawLine(points);
 11         }
 12         private const int SeparatorPiexl = 4;
 13         private const int AbundancePiexl = 3;
 14         private List<Point> ForgePoints(Point startPoint, Point endPoint)
 15         {
 16             var points = new List<Point>();
 17 
 18             var lineVector = endPoint - startPoint;
 19             var lineDistance = lineVector.Length;
 20             var lineAngle = Math.Atan2(-(endPoint.Y - startPoint.Y), endPoint.X - startPoint.X);
 21 
 22             points.Add(startPoint);
 23             int index = 0;
 24             bool isAbundanceUpward = true;
 25             while (index * SeparatorPiexl < lineDistance)
 26             {
 27                 index++;
 28                 //计算出间隔长度(模拟点到起始点)
 29                 var separatorDistance = index * SeparatorPiexl;
 30                 var abundancePiexl = AbundancePiexl;
 31                 var distanceToStartPoint = Math.Sqrt(Math.Pow(separatorDistance, 2) + Math.Pow(abundancePiexl, 2));
 32                 //计算出模拟点、起始点,与直线的角度
 33                 var separatorAngle = Math.Atan2(AbundancePiexl, separatorDistance);
 34                 separatorAngle = isAbundanceUpward ? separatorAngle : -separatorAngle;
 35                 isAbundanceUpward = !isAbundanceUpward;
 36                 //得到模拟点的水平角度
 37                 var mockPointAngle = lineAngle + separatorAngle;
 38                 //计算出模拟点坐标
 39                 var verticalDistance = distanceToStartPoint * Math.Sin(mockPointAngle);
 40                 var horizontalDistance = distanceToStartPoint * Math.Cos(mockPointAngle);
 41                 var mockPoint = new Point(startPoint.X + horizontalDistance, startPoint.Y - verticalDistance);
 42                 points.Add(mockPoint);
 43             }
 44             points.Add(endPoint);
 45             return points;
 46         }
 47 
 48         private void DrawLine(List<Point> points)
 49         {
 50             _visualShape.Clear();
 51 
 52             var geometryTest = new StreamGeometry();
 53             using (var ctx = geometryTest.Open())
 54             {
 55                 ctx.BeginFigure(points[0], true, false);
 56                 if (points.Count % 2 == 0)
 57                 {
 58                     //绘制二阶贝塞尔函数,需要保证为偶数点
 59                     ctx.PolyQuadraticBezierTo(points, true, true);
 60                 }
 61                 else
 62                 {
 63                     //绘制二阶贝塞尔函数,需要保证为偶数点
 64                     points.Insert(0, points[0]);
 65                     ctx.PolyQuadraticBezierTo(points, true, true);
 66                 }
 67 
 68                 ctx.Close();
 69             }
 70 
 71             var visual = new DrawingVisual();
 72             using (var context = visual.RenderOpen())
 73             {
 74                 context.DrawGeometry(FillBrush, StrokePen, geometryTest);
 75             }
 76             _visualShape.Add(visual);
 77         }
 78 
 79         #region 内部方法
 80 
 81         [Obsolete]
 82         protected override void OnRender(DrawingContext drawingContext)
 83         {
 84             //弃用,改为_visualShape填充实现
 85             //drawingContext.DrawGeometry(FillBrush, StrokePen, BaseGeometry);
 86         }
 87 
 88         protected override int VisualChildrenCount => _visualShape.Count;
 89 
 90         protected override Visual GetVisualChild(int index)
 91         {
 92             if (index < 0 || index >= _visualShape.Count)
 93             {
 94                 throw new ArgumentOutOfRangeException();
 95             }
 96 
 97             return _visualShape[index];
 98         }
 99 
100         #endregion
101 
102         #region 曲线属性
103 
104         private readonly VisualCollection _visualShape;
105         protected Brush FillBrush { get; set; } = Brushes.Transparent;
106         public Brush LineBrush { get; set; } = Brushes.DarkSeaGreen;
107         protected double BorderThickness { get; set; } = 1.0;
108         private Pen _defaultPen = null;
109         protected Pen StrokePen
110         {
111             get
112             {
113                 if (_defaultPen == null)
114                 {
115                     _defaultPen = new Pen(LineBrush, BorderThickness);
116                 }
117                 return _defaultPen;
118             }
119             set => _defaultPen = value;
120         }
121 
122         #endregion
123     }

Github地址:https://github.com/Kybs0/WaveLineTextDemo

猜你喜欢

转载自www.cnblogs.com/kybs0/p/11141190.html