c# 实例——绘制波浪线(附源码)
作者:唐宋元明清2188 时间:2023-03-02 12:53:54
效果图
界面绘制操作
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
来源:https://www.cnblogs.com/kybs0/p/11141190.html
标签:c#,绘制,波浪线
![](/images/zang.png)
![](/images/jiucuo.png)
猜你喜欢
JAVA求两直线交点和三角形内外心的方法
2023-07-30 02:46:35
关于C# 5.0 CallerMemberName CallerFilePath CallerLineNumber 在.NET4中的使用介绍方法
2022-03-27 22:05:56
springboot FeignClient注解及参数
2021-07-09 21:59:07
SpringBoot动态修改日志级别的操作
2022-10-31 05:00:30
![](https://img.aspxhome.com/file/2023/6/67116_0s.png)
基于Spring@Autowired注解与自动装配详谈
2022-01-14 09:38:49
SpringBean依赖和三级缓存的案例讲解
2023-06-25 09:33:22
java实现图片滑动验证(包含前端代码)
2022-03-21 12:13:52
![](https://img.aspxhome.com/file/2023/8/60538_0s.jpg)
SpringBoot全局异常处理与定制404页面的方法
2021-08-07 18:54:56
![](https://img.aspxhome.com/file/2023/9/64759_0s.png)
C#简单读写txt文件的方法
2023-01-17 06:30:27
深入浅析Spring 的aop实现原理
2023-01-10 00:00:10
关于mybatis使用${}时sql注入的问题
2023-04-18 03:29:40
![](https://img.aspxhome.com/file/2023/3/66683_0s.png)
Java基于ArrayList实现群主发红包功能
2022-04-06 20:34:09
![](https://img.aspxhome.com/file/2023/4/74914_0s.png)
C#使用LINQ查询表达式的基本子句总结
2022-08-05 05:09:41
![](https://img.aspxhome.com/file/2023/3/77253_0s.png)
C++封装静态链接库和使用的详细步骤
2021-08-28 00:54:13
![](https://img.aspxhome.com/file/2023/0/112290_0s.jpg)
Android开发Retrofit源码分析
2022-06-11 18:19:07
![](https://img.aspxhome.com/file/2023/8/99768_0s.jpg)
jvm细节探索之synchronized及实现问题分析
2023-08-24 02:13:29
![](https://img.aspxhome.com/file/2023/6/57916_0s.png)
maven工程中jar包瘦身的五种方法
2023-11-04 05:01:54
java UDP实现一个聊天工具的示例代码
2021-09-19 18:41:47
![](https://img.aspxhome.com/file/2023/3/92723_0s.png)
JavaWeb Servlet实现文件上传与下载功能实例
2023-06-16 16:41:27
![](https://img.aspxhome.com/file/2023/2/62532_0s.png)
c#正反序列化XML文件示例(xml序列化)
2023-01-06 02:49:57