c# 实例——绘制波浪线(附源码)

所属分类: 软件编程 / C#教程 阅读数: 115
收藏 0 赞 0 分享

效果图

界面绘制操作

private Point? _startPoint = null;
  private void ContainerCanvas_OnPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
  {
    var position = e.GetPosition(ContainerCanvas);
    if (_startPoint == null)
    {
      _startPoint = position;
    }
    else
    {
      //删除预览
      if (_previewLineElement != null)
      {
        ContainerCanvas.Children.Remove(_previewLineElement);
        _previewLineElement = null;
        _lastMovedPoint = null;
      }
      //确定结束点,绘制波浪线
      var myLineElement = new MyLineElement();
      myLineElement.DrawLine((Point)_startPoint, position);
      ContainerCanvas.Children.Add(myLineElement);
      _startPoint = null;
    }
  }

  private MyLineElement _previewLineElement = null;
  private Point? _lastMovedPoint = null;

  /// <summary>
  /// 波浪线绘制预览
  /// </summary>
  /// <param name="sender"></param>
  /// <param name="e"></param>
  private void ContainerCanvas_OnMouseMove(object sender, MouseEventArgs e)
  {
    var position = e.GetPosition(ContainerCanvas);
    if (_startPoint != null && (_lastMovedPoint == null || _lastMovedPoint != null & (position - (Point)_lastMovedPoint).Length >= 2))
    {
      _lastMovedPoint = position;
      if (_previewLineElement != null)
      {
        ContainerCanvas.Children.Remove(_previewLineElement);
      }
      var myLineElement = new MyLineElement();
      myLineElement.DrawLine((Point)_startPoint, position);
      ContainerCanvas.Children.Add(myLineElement);
      _previewLineElement = myLineElement;
    }
  }

波浪线控件及绘制

class MyLineElement : FrameworkElement
  {
    public MyLineElement()
    {
      _visualShape = new VisualCollection(this);
    }
    internal void DrawLine(Point startPoint, Point endPoint)
    {
      List<Point> points = ForgePoints(startPoint, endPoint);
      DrawLine(points);
    }
    private const int SeparatorPiexl = 4;
    private const int AbundancePiexl = 3;
    private List<Point> ForgePoints(Point startPoint, Point endPoint)
    {
      var points = new List<Point>();

      var lineVector = endPoint - startPoint;
      var lineDistance = lineVector.Length;
      var lineAngle = Math.Atan2(-(endPoint.Y - startPoint.Y), endPoint.X - startPoint.X);

      points.Add(startPoint);
      int index = 0;
      bool isAbundanceUpward = true;
      while (index * SeparatorPiexl < lineDistance)
      {
        index++;
        //计算出间隔长度(模拟点到起始点)
        var separatorDistance = index * SeparatorPiexl;
        var abundancePiexl = AbundancePiexl;
        var distanceToStartPoint = Math.Sqrt(Math.Pow(separatorDistance, 2) + Math.Pow(abundancePiexl, 2));
        //计算出模拟点、起始点,与直线的角度
        var separatorAngle = Math.Atan2(AbundancePiexl, separatorDistance);
        separatorAngle = isAbundanceUpward ? separatorAngle : -separatorAngle;
        isAbundanceUpward = !isAbundanceUpward;
        //得到模拟点的水平角度
        var mockPointAngle = lineAngle + separatorAngle;
        //计算出模拟点坐标
        var verticalDistance = distanceToStartPoint * Math.Sin(mockPointAngle);
        var horizontalDistance = distanceToStartPoint * Math.Cos(mockPointAngle);
        var mockPoint = new Point(startPoint.X + horizontalDistance, startPoint.Y - verticalDistance);
        points.Add(mockPoint);
      }
      points.Add(endPoint);
      return points;
    }

    private void DrawLine(List<Point> points)
    {
      _visualShape.Clear();

      var geometryTest = new StreamGeometry();
      using (var ctx = geometryTest.Open())
      {
        ctx.BeginFigure(points[0], true, false);
        if (points.Count % 2 == 0)
        {
          //绘制二阶贝塞尔函数,需要保证为偶数点
          ctx.PolyQuadraticBezierTo(points, true, true);
        }
        else
        {
          //绘制二阶贝塞尔函数,需要保证为偶数点
          points.Insert(0, points[0]);
          ctx.PolyQuadraticBezierTo(points, true, true);
        }

        ctx.Close();
      }

      var visual = new DrawingVisual();
      using (var context = visual.RenderOpen())
      {
        context.DrawGeometry(FillBrush, StrokePen, geometryTest);
      }
      _visualShape.Add(visual);
    }

    #region 内部方法

    [Obsolete]
    protected override void OnRender(DrawingContext drawingContext)
    {
      //弃用,改为_visualShape填充实现
      //drawingContext.DrawGeometry(FillBrush, StrokePen, BaseGeometry);
    }

    protected override int VisualChildrenCount => _visualShape.Count;

    protected override Visual GetVisualChild(int index)
    {
      if (index < 0 || index >= _visualShape.Count)
      {
        throw new ArgumentOutOfRangeException();
      }

      return _visualShape[index];
    }

    #endregion

    #region 曲线属性

    private readonly VisualCollection _visualShape;
    protected Brush FillBrush { get; set; } = Brushes.Transparent;
    public Brush LineBrush { get; set; } = Brushes.DarkSeaGreen;
    protected double BorderThickness { get; set; } = 1.0;
    private Pen _defaultPen = null;
    protected Pen StrokePen
    {
      get
      {
        if (_defaultPen == null)
        {
          _defaultPen = new Pen(LineBrush, BorderThickness);
        }
        return _defaultPen;
      }
      set => _defaultPen = value;
    }

    #endregion
  }

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

以上就是c# 实例——绘制波浪线(附源码)的详细内容,更多关于c# 绘制波浪线的资料请关注脚本之家其它相关文章!

更多精彩内容其他人还在看

C#获取并修改文件扩展名的方法

这篇文章主要介绍了C#获取并修改文件扩展名的方法,实例分析了C#编程方式修改文件扩展名的技巧,涉及Path类的使用方法,需要的朋友可以参考下
收藏 0 赞 0 分享

C#遍历操作系统下所有驱动器的方法

这篇文章主要介绍了C#遍历操作系统下所有驱动器的方法,涉及C#中DriveInfo类GetDrivers方法的使用技巧,具有一定参考借鉴价值,需要的朋友可以参考下
收藏 0 赞 0 分享

C#遍历指定目录下所有文件的方法

这篇文章主要介绍了C#遍历指定目录下所有文件的方法,实例分析了C#中GetFiles()方法遍历文件的使用技巧,非常具有实用价值,需要的朋友可以参考下
收藏 0 赞 0 分享

C#拷贝文件简单实现方法

这篇文章主要介绍了C#拷贝文件简单实现方法,主要分析了FileInfo类中CopyTo方法针对文件复制的操作技巧,非常简单实用,需要的朋友可以参考下
收藏 0 赞 0 分享

C#获取文件相关信息的方法

这篇文章主要介绍了C#获取文件相关信息的方法,涉及C#中FileInfo类的相关使用技巧,具有一定参考借鉴价值,需要的朋友可以参考下
收藏 0 赞 0 分享

C#交错数组用法实例

这篇文章主要介绍了C#交错数组用法,较为详细的分析了交错数组的概念、用法并实例分析了交错数组的使用技巧,需要的朋友可以参考下
收藏 0 赞 0 分享

C#实现在前端网页弹出警告对话框(alert)的方法

这篇文章主要介绍了C#实现在前端网页弹出警告对话框(alert)的方法,涉及C#通过自定义函数调用window.alert方法弹出对话框的技巧,具有一定参考借鉴价值,需要的朋友可以参考下
收藏 0 赞 0 分享

C#实现控制Windows系统关机、重启和注销的方法

这篇文章主要介绍了C#实现控制Windows系统关机、重启和注销的方法,涉及C#调用windows系统命令实现控制开机、关机等操作的技巧,非常简单实用,需要的朋友可以参考下
收藏 0 赞 0 分享

C#读取Excel并转化成XML的方法

这篇文章主要介绍了C#读取Excel并转化成XML的方法,实例分析了C#操作Excel及XML文件的技巧,具有一定参考借鉴价值,需要的朋友可以参考下
收藏 0 赞 0 分享

C#创建一个Word并打开的方法

这篇文章主要介绍了C#创建一个Word并打开的方法,实例分析了C#操作word的常用技巧,非常具有实用价值,需要的朋友可以参考下
收藏 0 赞 0 分享
查看更多