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

}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

谷粒商城-高级篇-秒杀业务

1、后台添加秒杀商品 1、配置网关 - id: coupon_routeuri: lb://gulimall-couponpredicates:- Path/api/coupon/**filters:- RewritePath/api/(?<segment>.*),/$\{segment} 2、每日秒杀关联商品功能实现 点击关联商品后&#xff0c;应该查询当前场次的所有商品 点击关…

JuOne核心模块揭秘:从智能硬件到Web3生态的完美连接

JuOne核心模块揭秘&#xff1a;从智能硬件到Web3生态的完美连接在全球数字经济的浪潮中&#xff0c;Web3 正以前所未有的速度重塑我们的生活方式、商业模式和价值创造体系。它不仅仅是互联网的下一阶段&#xff0c;更是一场关于未来的革命。去中心化、用户主权、价值互联&#…

Kafka高性能设计

高性能设计概述 Kafka高性能是多方面协同的结果&#xff0c;包括集群架构、分布式存储、ISR数据同步及高效利用磁盘和操作系统特性等。主要体现在消息分区、顺序读写、页缓存、零拷贝、消息压缩和分批发送六个方面。 消息分区 存储不受单台服务器限制&#xff0c;能处理更多数据…

若依框架之简历pdf文档预览功能

一、前端 &#xff08;1&#xff09;安装插件vue-pdf&#xff1a;npm install vue-pdf &#xff08;2&#xff09;引入方式&#xff1a;import pdf from "vue-pdf"; &#xff08;3&#xff09;components注入方式&#xff1a;components:{pdf} &#xff08;4&…

【社区投稿】自动特征auto trait的扩散规则

自动特征auto trait的扩散规则 公式化地概括&#xff0c;auto trait marker trait derived trait。其中&#xff0c;等号右侧的marker与derived是在Rustonomicon书中的引入的概念&#xff0c;鲜见于Rust References。所以&#xff0c;若略感生僻&#xff0c;不奇怪。 marker …

Elasticsearch检索之三:官方推荐方案search_after检索实现(golang)

Elasticsearch8.17.0在mac上的安装 Kibana8.17.0在mac上的安装 Elasticsearch检索方案之一&#xff1a;使用fromsize实现分页 快速掌握Elasticsearch检索之二&#xff1a;滚动查询(scrool)获取全量数据(golang) 1、search_after检索 在前面的文章介绍了fromsize的普通分页…

精读DeepSeek v3技术文档的心得感悟

最近宋大宝同学读完了DeepSeekv3的文档&#xff0c;心中颇多感慨&#xff0c;忍不住想在这里记录一下对这款“业界有望启示未来低精度训练走向”的开源大模型的观察与思考。DeepSeek v3的亮点绝不仅仅是“Float8”或“超长上下文”这么简单&#xff0c;而是贯穿了从数值精度、注…

WAV文件双轨PCM格式详细说明及C语言解析示例

WAV文件双轨PCM格式详细说明及C语言解析示例 一、WAV文件双轨PCM格式详细说明1. WAV文件基本结构2. PCM编码方式3. 双轨PCM格式详细说明二、C语言解析WAV文件的代码示例代码说明一、WAV文件双轨PCM格式详细说明 WAV文件是一种用于存储未压缩音频数据的文件格式,广泛应用于音频…

Day1 微服务 单体架构、微服务架构、微服务拆分、服务远程调用、服务注册和发现Nacos、OpenFeign

目录 1.导入单体架构项目 1.1 安装mysql 1.2 后端 1.3 前端 2.微服务 2.1 单体架构 2.2 微服务 2.3 SpringCloud 3.微服务拆分 3.1 服务拆分原则 3.1.1 什么时候拆 3.1.2 怎么拆 3.2 拆分购物车、商品服务 3.2.1 商品服务 3.2.2 购物车服务 3.3 服务调用 3.3.1 RestTemplate 3.…

DeepSpeed 使用 LoRA 训练后文件结构详解

DeepSpeed 使用 LoRA 训练后文件结构详解 在大语言模型&#xff08;LLM&#xff09;的训练过程中&#xff0c;DeepSpeed 提供了强大的分布式训练能力&#xff0c;而 LoRA&#xff08;Low-Rank Adaptation&#xff09;通过参数高效微调技术显著减少了资源占用。完成训练后&…

Llama 3 预训练(二)

目录 3. 预训练 3.1 预训练数据 3.1.1 网络数据筛选 PII 和安全过滤 文本提取与清理 去重&#xff08;De-duplication&#xff09; 启发式过滤&#xff08;Heuristic Filtering&#xff09; 基于模型的质量过滤 代码和数学推理数据处理 多语言数据处理 3.1.2 确定数…

Autoware Universe 安装记录

前提&#xff1a; ubuntu20.04&#xff0c;英伟达显卡。 ROS2-Galactic安装 wget http://fishros.com/install -O fishros && . fishros 选择galactic(ROS2)版本&#xff0c;桌面版 ROS2-dev-tools安装 sudo apt install python3-testresources sudo apt update …

【小程序】自定义组件的data、methods、properties

目录 自定义组件 - 数据、方法和属性 1. data 数据 2. methods 方法 3. properties 属性 4. data 和 properties 的区别 5. 使用 setData 修改 properties 的值 自定义组件 - 数据、方法和属性 1. data 数据 在小程序组件中&#xff0c;用于组件模板渲染的私有数据&…

socket编程(C++/Windows)

相关文章推荐&#xff1a; Socket 编程基础 面试官&#xff0c;不要再问我三次握手和四次挥手 TCP的三次握手与四次挥手 参考视频&#xff1a; https://www.bilibili.com/video/BV1aW4y1w7Ui/?spm_id_from333.337.search-card.all.click TCP通信流程 服务端 #include<…

linux自动化一键批量检查主机端口

1、准备 我们可以使用下面命令关闭一个端口 sudo iptables -A INPUT -p tcp --dport 端口号 -j DROP我关闭的是22端口&#xff0c;各位可以关其它的或者打开其它端口测试&#xff0c;谨慎关闭22端口&#xff01;不然就会像我下面一样握手超时&#x1f62d;&#x1f62d;&…

实验五 时序逻辑电路部件实验

一、实验目的 熟悉常用的时序逻辑电路功能部件&#xff0c;掌握计数器、了解寄存器的功能。 二、实验所用器件和仪表 1、双 D触发器 74LS74 2片 2、74LS162 1片 3、74194 1片 4、LH-D4实验仪 1台 1.双…

开源轻量级文件分享服务Go File本地Docker部署与远程访问

???欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学习,不断总结,共同进步,活到老学到老…

flask基础

from flask import Flask, requestapp Flask(__name__)# app.route(/) # def hello_world(): # put applications code here # return Hello World!app.route(/) # 路由 当用户访问特定 URL 时&#xff0c;Flask 会调用对应的视图函数来处理请求 def index():return …

WPF使用OpenCvSharp4

WPF使用OpenCvSharp4 创建项目安装OpenCvSharp4 创建项目 安装OpenCvSharp4 在解决方案资源管理器中&#xff0c;右键单击项目名称&#xff0c;选择“管理 NuGet 包”。搜索并安装以下包&#xff1a; OpenCvSharp4OpenCvSharp4.ExtensionsOpenCvSharp4.runtime.winSystem.Man…

社媒运营专线 - SD-WAN 跨境网络专线 —— 外贸企业社媒平台的专属 “快车道”

在当今全球化的商业浪潮中&#xff0c;社交媒体平台已成为外贸企业拓展国际市场、提升品牌知名度和促进业务增长的关键阵地。然而&#xff0c;网络访问速度慢、IP 不纯净等问题却如影随形&#xff0c;严重制约了企业社媒运营的效率和效果。幸运的是&#xff0c;社媒运营专线 - …