波浪线效果如上

界面绘制操作

     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 >= ))
{
_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 = ;
private const int AbundancePiexl = ;
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 = ;
bool isAbundanceUpward = true;
while (index * SeparatorPiexl < lineDistance)
{
index++;
//计算出间隔长度(模拟点到起始点)
var separatorDistance = index * SeparatorPiexl;
var abundancePiexl = AbundancePiexl;
var distanceToStartPoint = Math.Sqrt(Math.Pow(separatorDistance, ) + Math.Pow(abundancePiexl, ));
//计算出模拟点、起始点,与直线的角度
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[], true, false);
if (points.Count % == )
{
//绘制二阶贝塞尔函数,需要保证为偶数点
ctx.PolyQuadraticBezierTo(points, true, true);
}
else
{
//绘制二阶贝塞尔函数,需要保证为偶数点
points.Insert(, points[]);
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 < || 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# 波浪线绘制的更多相关文章

  1. 2019-6-27-WPF-如何给定两个点画出一条波浪线

    title author date CreateTime categories WPF 如何给定两个点画出一条波浪线 lindexi 2019-6-27 10:17:6 +0800 2019-6-26 ...

  2. Coreldraw绘制标准波浪线

    Coreldraw中如何绘制标准波浪线? 先画一根直线,单击工具栏中的“互动式工具组”,选择“互动式变形工具”, 再在弹出的属性栏中选择“拉链变形”,在幅度和频率中分别输入波形的波峰 到波底的值.波浪 ...

  3. VC++ GetModuleFileName()获取路径字符串中带波浪线~

    GetModuleFileName()获取的字符串中带波浪线,不是完整的路径显示. 原因:获取的是短路径,进行了缩写 解决:还原长路径 TCHAR }; GetLongPathName( strTem ...

  4. Mac 不能输入波浪线?

    当你发现你的Mac或者mbp不能输入波浪线 , 输出的都是的时候,检查一下这个选项(如下图所示)有没有选中. 如果没有,就勾上它!

  5. 消除PyCharm中满屏的波浪线

    PyCharm使用了较为严格的PEP8的检查规则,如果代码命名不规范,甚至多出的空格都会被波浪线标识出来,导致整个编辑器里铺满了波浪线,右边的滚动条也全是黄色或灰色的标记线,很是影响编辑. 在网上看了 ...

  6. VS中的波浪线

    绿色波浪线: 如果你的代码中出现了绿色的波浪线,说明你的代码语法并没有错误, 只不过提示你有可能会出现错误,但是不一定会出现错误.警告线 红色波浪线: 如果你的代码中出现了红色的波浪线,意味着你的代码 ...

  7. sql server 2008 查询语句的红色波浪线

    在 Microsoft sql server management studio 里点击“编辑”——“IntelliSense”——“刷新本地缓存” 就会发现红色波浪线没了(前提是你的代码没错)

  8. 去掉Visual Studio 编辑器里中文注释的红色波浪线 转载

    我们通常用visual studio进行开发的时候,我们通常会用到一款比较流行比较方便的插件,那就是Visual Assist X,它可以增强Microsoft开发环境下的编辑能力,支持C/C++,C ...

  9. 002-python书写规范--消去提示波浪线

    强迫症患者面对PyCharm的波浪线是很难受的,针对如下代码去除PyCharm中的波浪线: # _*_coding:utf-8_*_ # /usr/bin/env python3 A_user = & ...

随机推荐

  1. hdu 1667 The Rotation Game ( IDA* )

    题目大意: 给你一个“井”子状的board,对称的由24个方块组成,每个方块上有123三个数字中的一个.给你初始状态,共有八种变换方式,求字典序最小的最短的的变换路径使得,board中间的八个方块上数 ...

  2. eclipse 导入别人拷贝过来的工作空间项目

    切换自己的工作空间 File --> Import --> Existing Project into Workspace --> 选择项目根目录 --> 确定 如果你的ecl ...

  3. Python 分析电影《南方车站的聚会》

    <南方车站的聚会>由刁亦男执导,主要演员包括:胡歌.桂纶镁.廖凡.万茜等,该片于 2019 年 5 月 18 在戛纳电影节首映,2019 年 12 月 6 日在中国正式上映.故事灵感来自真 ...

  4. 2016/09/21 context.getConfiguration().get()

    查看api:http://hadoop.apache.org/docs/stable/api/ public String get(String name) Get the value of the ...

  5. ps命令输出进程状态S后面加号的含义

    最近发现一个问题,ps命令输出里面进程状态为S+的含义,网上好多文章都说是表明进程“位于在后台进程组”. 例如下面这个ps命令输出说明: D 不可中断 Uninterruptible sleep (u ...

  6. NLP(十六)轻松上手文本分类

    背景介绍   文本分类是NLP中的常见的重要任务之一,它的主要功能就是将输入的文本以及文本的类别训练出一个模型,使之具有一定的泛化能力,能够对新文本进行较好地预测.它的应用很广泛,在很多领域发挥着重要 ...

  7. unittest---unittest封装方法

    前面我们写了一个关于查询歌曲的接口测试,但是代码重复性比较大,进行一次简单的优化 封装方法 在编写自动化脚本的时候,都要求代码简介,上一篇unittest---unittest断言中代码重复性比较多, ...

  8. vue项目 npm run dev在Linux 持久运行

    touch run.dev.logchmod u+w run.dev.log 记录日志文件 nohup npm run dev > run.dev.log 2>run.dev.log &a ...

  9. JavaWeb入门——在Windows环境下安装Tomcat服务器

    JavaWeb入门——在Windows环境下安装Tomcat服务器 摘要:本文主要学习如何在Windows环境中下载并安装Tomcat服务器. 下载 获取安装包 推荐去官网上下载Tomcat: htt ...

  10. 剑指offer笔记面试题7----重建二叉树

    题目:输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如,输入前序遍历序列{1, 2, 4, 7, 3, 5, 6, 8}和中序遍历序列 ...