WPF 绘制过顶点的圆滑曲线 (样条,贝塞尔)

在一个WPF项目中要用到样条曲线,必须过顶点,圆滑后还不能太走样,捣鼓一番,发现里面颇有玄机,于是把我多方抄来改造的方法发出来,方便新手:

如上图,看代码吧:

----------------------------------------

前台页面:

<Window x:Class="Wpf_north_demo.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:Wpf_north_demo"mc:Ignorable="d"Title="MainWindow" Height="450" Width="800"><Grid><Canvas x:Name="ca1" Background="White" MouseLeftButtonDown="ca1_MouseLeftButtonDown" MouseMove="ca1_MouseMove" MouseRightButtonDown="ca1_MouseRightButtonDown"><Polyline x:Name="path_lines" Stroke="Silver" StrokeThickness="1" StrokeDashArray="1 1 1" IsHitTestVisible="False"></Polyline><Path x:Name="path1" Stroke="Red" StrokeThickness="1" IsHitTestVisible="False"><Path.Data><PathGeometry x:Name="pathGeometry1"></PathGeometry></Path.Data></Path></Canvas><Canvas x:Name="ca_top" IsHitTestVisible="False"/><TextBlock  HorizontalAlignment="Left" VerticalAlignment="Top" Margin="5" Text="左键绘制,右键结束" IsHitTestVisible="False"/></Grid>
</Window>

后台代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;namespace Wpf_north_demo
{/// <summary>/// MainWindow.xaml 的交互逻辑/// </summary>public partial class MainWindow : Window{public MainWindow(){InitializeComponent();}int _num = 0;bool _started = false;List<Point> _seed = new List<Point>();private void ca1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e){if(!_started){_num = 0;_seed.Clear();_started = true;ca_top.Children.Clear();path_lines.Points.Clear();pathGeometry1.Figures.Clear();}while (path_lines.Points.Count > _num && _num > 0){path_lines.Points.RemoveAt(path_lines.Points.Count - 1);}_seed.Add(e.GetPosition(ca1));_num = _seed.Count;path_lines.Points.Add(_seed[_num - 1]);ca_top.Children.Add(new Ellipse{Width = 6,Height = 6,Stroke = Brushes.Blue,Fill = Brushes.Lime,Margin = new Thickness(_seed[_num - 1].X - 3, _seed[_num - 1].Y - 3, 0, 0)});}private void ca1_MouseMove(object sender, MouseEventArgs e){if (_started && e.LeftButton == MouseButtonState.Released && _num > 0){while (path_lines.Points.Count > _num){path_lines.Points.RemoveAt(path_lines.Points.Count - 1);}path_lines.Points.Add(e.GetPosition(ca1));}}private void ca1_MouseRightButtonDown(object sender, MouseButtonEventArgs e){if(_started){while (path_lines.Points.Count > _num && _num > 0){path_lines.Points.RemoveAt(path_lines.Points.Count - 1);}_seed.Add(e.GetPosition(ca1));_num = _seed.Count;path_lines.Points.Add(_seed[_num - 1]);ca_top.Children.Add(new Ellipse{Width = 6,Height = 6,Stroke = Brushes.Blue,Fill = Brushes.Lime,Margin = new Thickness(_seed[_num - 1].X - 3, _seed[_num - 1].Y - 3, 0, 0)});BezierHelper.DrawBezierPolyline(pathGeometry1, _seed, false);}else{_num = 0;_seed.Clear();ca_top.Children.Clear();path_lines.Points.Clear();pathGeometry1.Figures.Clear();}_started = false;}}public class BezierHelper{public static void DrawBezierPolyline(PathGeometry geo, List<Point> list, bool close){geo.Figures.Clear();if (list.Count > 0){PathFigure pf = new PathFigure() { IsClosed = close };pf.StartPoint = list[0];List<Point> controls = new List<Point>();for (int i = 0; i < list.Count; i++){Point control_01, control_02;GetControlPoint(list, i, out control_01, out control_02);controls.Add(control_01);controls.Add(control_02);}for (int i = 1; i < list.Count; i++){BezierSegment bs = new BezierSegment(controls[i * 2 - 1], controls[i * 2], list[i], true);bs.IsSmoothJoin = true;pf.Segments.Add(bs);}geo.Figures.Add(pf);}}static void GetControlPoint(List<Point> list, int idx, out Point control_01, out Point control_02){if (idx == 0){control_01 = list[0];}else{control_01 = GetAverage(list[idx - 1], list[idx]);}if (idx == list.Count - 1){control_02 = list[list.Count - 1];}else{control_02 = GetAverage(list[idx], list[idx + 1]);}Point ave = GetAverage(control_01, control_02);Point sh = Sub(list[idx], ave);control_01 = Mul(Add(control_01, sh), list[idx], 0.6);control_02 = Mul(Add(control_02, sh), list[idx], 0.6);}static Point GetAverage(Point x, Point y){return new Point((x.X + y.X) / 2, (x.Y + y.Y) / 2);}static Point Add(Point x, Point y){return new Point(x.X + y.X, x.Y + y.Y);}static Point Sub(Point x, Point y){return new Point(x.X - y.X, x.Y - y.Y);}static Point Mul(Point x, Point y, double d){Point temp = Sub(x, y);temp = new Point(temp.X * d, temp.Y * d);temp = Add(y, temp);return temp;}}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/891257.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

国产数据库TiDB从入门到放弃教程

国家层面战略&#xff0c;安全的角度&#xff0c;硬件、软件国产化是趋势&#xff0c;鸿蒙电脑操作系统、鸿蒙手机操作系统…数据库也会慢慢国产化&#xff0c;国产数据库TiDB用起来比OceanBase丝滑&#xff0c;本身没有那么重。 从入门到放弃 1. 介绍1.1 TiDB 的主要特点1.2 T…

基于STM32单片机矿井矿工作业安全监测设计

基于STM32单片机矿井矿工作业安全监测设计 目录 项目开发背景设计实现的功能项目硬件模块组成设计思路系统功能总结使用的模块技术详情介绍总结 1. 项目开发背景 随着矿井矿工作业环境的复杂性和危险性逐渐增加&#xff0c;矿井作业安全问题引起了社会各界的广泛关注。传统的…

单片机与MQTT协议

MQTT 协议简述 MQTT&#xff08;Message Queuing Telemetry Transport&#xff0c;消息队列遥测传输协议&#xff09;&#xff0c;是一种基于发布 / 订阅&#xff08;publish/subscribe&#xff09;模式的 “轻量级” 通讯协议&#xff0c;该协议构建于 TCP/IP 协议上&#xf…

基于 SensitiveWordBs 实现敏感词过滤功能

在现代的互联网应用中&#xff0c;敏感词过滤已成为一个必不可少的功能&#xff0c;尤其是在社交媒体、评论审核等需要保证内容健康的场景下。本文将基于开源库https://github.com/houbb/sensitive-word&#xff0c;详细讲解如何通过自定义敏感词库和工具类实现高效的敏感词过滤…

.Net Core配置系统

目录 Json文件配置 读取配置原始方法 绑定读取配置 用法 传统Web.config配置的缺点为了兼容&#xff0c;仍然可以使用Web.config和ConifgurationManager类&#xff0c;但不推荐.NET中的配置系统支持丰富的配置源&#xff0c;包括文件&#xff08;json、xml、ini等&#xff…

C#中相等比较 == 和 Equal函数 对比

1. 运算符 是一个运算符&#xff0c;用于比较两个值是否相等。对于值类型&#xff08;如 int、float、double 等&#xff09;&#xff0c; 直接比较两个值是否相同。对于引用类型&#xff08;如类和数组&#xff09;&#xff0c; 比较两个引用是否指向内存中的同一个对象。 2.…

Java 处理base64文件上传

场景&#xff1a; 在系统内有一个类似于公告的模块&#xff0c;如果里面添加的文章不是选择富文本上传图片的方式&#xff0c;而是选择复制别的文章直接粘贴到系统内的富文本&#xff0c;里面的图片就不会是url&#xff0c;而是图片的base64格式&#xff0c;这样会导致数据库存…

【行业发展报告】2024大数据与智能化行业发展浅析

回首 2024&#xff0c;大数据智能化浪潮汹涌。海量数据宛如繁星&#xff0c;在智能算法的苍穹下汇聚、碰撞&#xff0c;释放出洞察市场与用户的强大能量&#xff0c;精准勾勒出商业新航线。我们精心雕琢技术架构&#xff0c;从数据存储的坚固基石到处理分析的高效引擎&#xff…

C++ 设计模式:享元模式(Flyweight Pattern)

链接&#xff1a;C 设计模式 链接&#xff1a;C 设计模式 - 单例模式 享元模式&#xff08;Flyweight Pattern&#xff09;是一种结构型设计模式&#xff0c;它通过共享尽可能多的相同对象来减少内存使用和提高性能。享元模式适用于大量细粒度对象的场景&#xff0c;这些对象之…

项目基本配置

总说 本节主要记录修改配置文件、连接mysql数据库、git连接 一、配置文件的修改 1.1 配置pom.xml 由于我们要连接mysql数据库&#xff0c;需要在pom.xml中添加相关依赖 这里给出一个网站&#xff0c;可以找到各种依赖Maven Repository: Search/Browse/Explore 添加一个my…

【YOLOv3】源码(train.py)

概述 主要模块分析 参数解析与初始化 功能&#xff1a;解析命令行参数&#xff0c;设置训练配置项目经理制定详细的施工计划和资源分配日志记录与监控 功能&#xff1a;初始化日志记录器&#xff0c;配置监控系统项目经理使用监控和记录工具&#xff0c;实时跟踪施工进度和质量…

【Vim Masterclass 笔记02】第3章:Vim 核心知识 + L08:Vim 核心浏览命令 + L09:Vim 核心浏览命令同步练习

文章目录 Section 3&#xff1a;Vim Essentials&#xff08;Vim 核心知识&#xff09;S03L08 Essential Navigation Commands1 光标的上下左右移动2 上 / 下翻页3 基于单词前移4 基于单词后移5 重新定位视图中的文本&#xff08;页面重绘&#xff09;6 定位到所在行的行首7 光标…

音视频入门基础:MPEG2-PS专题(1)——MPEG2-PS官方文档下载

一、引言 MPEG2-PS&#xff08;又称PS&#xff0c;Program Stream&#xff0c;程序流&#xff0c;节目流&#xff09;是一种多路复用数字音频、视频等的封装容器。MPEG2-PS将一个或多个分组但有共同的时间基准的基本数据流 &#xff08;PES&#xff09;合并成一个整体流。它是…

【Rust自学】8.3. String类型 Pt.1:字符串的创建、更新与拼接

8.3.0. 本章内容 第八章主要讲的是Rust中常见的集合。Rust中提供了很多集合类型的数据结构&#xff0c;这些集合可以包含很多值。但是第八章所讲的集合与数组和元组有所不同。 第八章中的集合是存储在堆内存上而非栈内存上的&#xff0c;这也意味着这些集合的数据大小无需在编…

基础数据结构--二叉树

一、二叉树的定义 二叉树是 n( n > 0 ) 个结点组成的有限集合&#xff0c;这个集合要么是空集&#xff08;当 n 等于 0 时&#xff09;&#xff0c;要么是由一个根结点和两棵互不相交的二叉树组成。其中这两棵互不相交的二叉树被称为根结点的左子树和右子树。 如图所示&am…

力扣-数据结构-7【算法学习day.78】

前言 ###我做这类文章一个重要的目的还是给正在学习的大家提供方向&#xff08;例如想要掌握基础用法&#xff0c;该刷哪些题&#xff1f;建议灵神的题单和代码随想录&#xff09;和记录自己的学习过程&#xff0c;我的解析也不会做的非常详细&#xff0c;只会提供思路和一些关…

C++ —— 模板类扩展

C —— 模板类扩展 模板类的成员模板将模板类用作参数 模板类的成员模板 结构体中可以有结构体&#xff0c;类中可以有类和成员函数。那么&#xff0c;模板类中也应该可以有模板类和模板函数。 在类AA中再创建一个模板类和模板函数。 先创建模板类&#xff0c;代码如下&#x…

Flink中并行度和slot的关系——任务和任务槽

一、任务槽&#xff08;task slots) Flink的每一个TaskManager是一个JVM进程&#xff0c;在其上可以运行多个线程&#xff08;任务task&#xff09;&#xff0c;那么每个线程可以拥有多少进程资源呢&#xff1f;任务槽就是这样一个概念&#xff0c;对taskManager上每个任务运行…

Android着色器SweepGradient渐变圆环,Kotlin

Android着色器SweepGradient渐变圆环&#xff0c;Kotlin import android.content.Context import android.graphics.Canvas import android.graphics.Color import android.graphics.Paint import android.graphics.Path import android.graphics.SweepGradient import android…

QT---------GUI程序设计基础

代码UI化设计&#xff08;QT&#xff09; 实例功能概述 假设我们要创建一个简单的计算器应用程序。该应用程序具有以下功能&#xff1a; 包含数字按钮&#xff08;0-9&#xff09;、操作符按钮&#xff08;、-、*、/&#xff09;、等于按钮&#xff08;&#xff09;和清除按…