当前位置: 首页 > news >正文

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;}}}

相关文章:

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

在一个WPF项目中要用到样条曲线&#xff0c;必须过顶点&#xff0c;圆滑后还不能太走样&#xff0c;捣鼓一番&#xff0c;发现里面颇有玄机&#xff0c;于是把我多方抄来改造的方法发出来&#xff0c;方便新手&#xff1a; 如上图&#xff0c;看代码吧&#xff1a; ----------…...

Kafka 幂等性与事务

文章目录 幂等性实现机制配置使用局限性 事务使用场景配置使用实现机制事务过程事务初始化事务开始事务提交事务取消事务消费 幂等性 Producer 无论向 Broker 发送多少次重复的数据&#xff0c;Broker 端只会持久化一条&#xff0c;保证数据不丢失且不重复。 实现机制 通过引…...

day2 Linux操作系统指令

思维导图 在家目录下创建目录文件&#xff0c;dir 1、dir下创建dir1和dir2 2、把当前目录下的所有文件拷贝到dir1中&#xff0c; 3、把当前目录下的所有脚本文件拷贝到dir2中 4、把dir2打包并压缩为dir2.tar.xz 5、再把dir2.tar.xz移动到dir1中 6、解压dir1中的压缩包 7、使用…...

AI一周重要会议和活动概览

一、小模型的曙光和机会之思辨高峰论坛 会议介绍&#xff1a;小模型的曙光和机会之思辨”高峰论坛暨第32期CSIG图像图形学科前沿讲习班于2025年1月3—4日在杭州举办&#xff0c;会议由中国图象图形学学会主办&#xff0c;中国图象图形学学会前沿科技论坛委员会承办。本次论坛设…...

重启ubuntu服务器,如何让springboot服务自动运行

文章目录 1. 使用 systemd 服务步骤&#xff1a; 2. 使用 cron 的 reboot 任务步骤&#xff1a; 3. 使用 init.d 脚本&#xff08;适用于较旧版本&#xff09;步骤&#xff1a; 推荐方案 为了确保在重启Ubuntu服务器后&#xff0c;让springboot的服务test.jar象 nohup java -ja…...

python系列教程237——启动扩展功能

朋友们&#xff0c;如需转载请标明出处&#xff1a;https://blog.csdn.net/jiangjunshow 声明&#xff1a;在人工智能技术教学期间&#xff0c;不少学生向我提一些python相关的问题&#xff0c;所以为了让同学们掌握更多扩展知识更好地理解AI技术&#xff0c;我让助理负责分享…...

U盘格式化工具合集:6个免费的U盘格式化工具

在日常使用中&#xff0c;U盘可能会因为文件系统不兼容、数据损坏或使用需求发生改变而需要进行格式化。一个合适的格式化工具不仅可以清理存储空间&#xff0c;还能解决部分存储问题。本文为大家精选了6款免费的U盘格式化工具&#xff0c;并详细介绍它们的功能、使用方法、优缺…...

循环神经网络(RNN)入门指南:从原理到实践

目录 1. 循环神经网络的基本概念 2. 简单循环网络及其应用 3. 参数学习与优化 4. 基于门控的循环神经网络 4.1 长短期记忆网络&#xff08;LSTM&#xff09; 4.1.1 LSTM的核心组件&#xff1a; 4.2 门控循环单元&#xff08;GRU&#xff09; 5 实际应用中的优化技巧 5…...

马原复习笔记

文章目录 前言导论物质实践人类社会资本主义社会主义共产主义后记 前言 一月二号下午四点多考试&#xff0c;很友好&#xff0c;不是早八&#xff0c;哈哈哈。之前豪言壮语和朋友说这次马原要全对&#xff0c;多做了几次测试之后&#xff0c;发现总有一些知识点是自己不知道的…...

Android Room 框架的初步使用

一、简介 Room 是一个强大的对象关系映射库&#xff0c;它允许你将 SQLite 数据库中的表映射到 Java 或 Kotlin 的对象&#xff08;称为实体&#xff09;上。你可以使用简单的注解&#xff08;如 Entity、Dao 和 Database&#xff09;来定义数据库表、数据访问对象&#xff08…...

什么是过度拟合和欠拟合?

在机器学习中&#xff0c;当一个算法的预测非常接近或者直接等于它的训练数据&#xff0c;导致不能够准确预测除了训练数据以外的数据&#xff0c;我们把这种情况称为过度拟合。算法能够非常接近甚至就是训练的数据&#xff0c;是个非常好的事&#xff0c;但是它不能准确预测除…...

DotnetSpider实现网络爬虫

1. 使用DotnetSpider框架 DotnetSpider是一个开源的、轻量、灵活、高性能、跨平台的分布式网络爬虫框架,适用于.NET平台。它可以帮助开发者快速实现网页数据的抓取功能。 1.1 安装DotnetSpider NuGet包 首先,你需要在你的.NET项目中安装DotnetSpider NuGet包。你可以通过…...

锐捷WLAN产品出货量排名第一!

摘要:2024年Q3锐捷WLAN产品出货量排名第一!锐捷多形态Wi-Fi 7产品重磅出击! 近日, IT市场研究和咨询公司IDC发布《IDC中国企业级WLAN市场跟踪报告,2024年Q3》。报告显示,锐捷WLAN产品在2024年Q3出货量位居行业首位。至此,锐捷WLAN产品在2024年的Q1、Q2、Q3均实现了市场出货量的…...

win32汇编环境下,对话框程序中生成listview列表控件,点击标题栏自动排序的示例

;把代码抄进radasm里面&#xff0c;可以直接编译运行。重要的地方加了备注。 ;这个有点复杂&#xff0c;重要的地方加了备注 ;以下是ASM文件 ;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>…...

自动化文档处理:Azure AI Document Intelligence

Azure AI Document Intelligence支持多种文件格式&#xff0c;包括PDF、JPEG、PNG等。其核心功能是将这些文档按页进行内容提取&#xff0c;并转化为LangChain文档。其默认输出格式是Markdown&#xff0c;这使得文档可以通过MarkdownHeaderTextSplitter进行语义分片。您也可以使…...

【Maven】Maven打包机制详解

Maven打包的类型&#xff1f; 以下是几种常见的打包形式&#xff1a; 1、jar (Java Archive) 用途&#xff1a;用于包含 Java 类文件和其他资源&#xff08;如属性文件、配置文件等&#xff09;的库项目。特点&#xff1a; 可以被其他项目作为依赖引用。适合创建独立的应用程…...

Python 向量检索库Faiss使用

Faiss&#xff08;Facebook AI Similarity Search&#xff09;是一个由 Facebook AI Research 开发的库&#xff0c;它专门用于高效地搜索和聚类大量向量。Faiss 能够在几毫秒内搜索数亿个向量&#xff0c;这使得它非常适合于实现近似最近邻&#xff08;ANN&#xff09;搜索&am…...

pd.Timestamp接收的参数类型

pd.Timestamp() 是 Pandas 中用于表示单个日期时间的函数&#xff0c;它可以接受多种类型的参数。以下是 pd.Timestamp() 可以接受的主要参数类型&#xff0c;并举例说明&#xff1a; 1. 日期时间字符串&#xff08;Date/Time String&#xff09; pd.Timestamp() 可以接收标准…...

FOC控制原理-ADC采样时机

0、文章推荐 SimpleFOC移植STM32&#xff08;五&#xff09;—— 电流采样及其变换_极对数对电流采样的影响-CSDN博客 FOC 电流采样方案对比&#xff08;单电阻/双电阻/三电阻&#xff09; - 知乎 (zhihu.com) FOC中的三种电流采样方式&#xff0c;你真的会选择吗&#xff1f;…...

运行python程序报错 undefined symbol: ffi_type_uint32 的参考解决方法

文章目录 写在前面一、问题描述二、解决方法参考链接 写在前面 自己的测试环境&#xff1a; Ubuntu20.04 ROS-Noetic 一、问题描述 运行 python 程序出现如下问题&#xff1a; Traceback (most recent call last):File "<string>", line 1, in <module&…...

挑战杯推荐项目

“人工智能”创意赛 - 智能艺术创作助手&#xff1a;借助大模型技术&#xff0c;开发能根据用户输入的主题、风格等要求&#xff0c;生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用&#xff0c;帮助艺术家和创意爱好者激发创意、提高创作效率。 ​ - 个性化梦境…...

在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:

在 HarmonyOS 应用开发中&#xff0c;手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力&#xff0c;既支持点击、长按、拖拽等基础单一手势的精细控制&#xff0c;也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档&#xff0c…...

Docker 运行 Kafka 带 SASL 认证教程

Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明&#xff1a;server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验

一、多模态商品数据接口的技术架构 &#xff08;一&#xff09;多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如&#xff0c;当用户上传一张“蓝色连衣裙”的图片时&#xff0c;接口可自动提取图像中的颜色&#xff08;RGB值&…...

Module Federation 和 Native Federation 的比较

前言 Module Federation 是 Webpack 5 引入的微前端架构方案&#xff0c;允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...

leetcodeSQL解题:3564. 季节性销售分析

leetcodeSQL解题&#xff1a;3564. 季节性销售分析 题目&#xff1a; 表&#xff1a;sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...

Mac下Android Studio扫描根目录卡死问题记录

环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中&#xff0c;提示一个依赖外部头文件的cpp源文件需要同步&#xff0c;点…...

Pinocchio 库详解及其在足式机器人上的应用

Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库&#xff0c;专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性&#xff0c;并提供了一个通用的框架&…...

C++使用 new 来创建动态数组

问题&#xff1a; 不能使用变量定义数组大小 原因&#xff1a; 这是因为数组在内存中是连续存储的&#xff0c;编译器需要在编译阶段就确定数组的大小&#xff0c;以便正确地分配内存空间。如果允许使用变量来定义数组的大小&#xff0c;那么编译器就无法在编译时确定数组的大…...

Java + Spring Boot + Mybatis 实现批量插入

在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法&#xff1a;使用 MyBatis 的 <foreach> 标签和批处理模式&#xff08;ExecutorType.BATCH&#xff09;。 方法一&#xff1a;使用 XML 的 <foreach> 标签&#xff…...