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

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.kler.cn/a/456289.html

相关文章:

  • 创建用于预测序列的人工智能模型,用Keras Tuner探索模型的超参数。
  • PDF书籍《手写调用链监控APM系统-Java版》第8章 插件与链路的结合:Gson插件实现
  • Arcgis中python工具箱制造要点及统计要素图层字段信息工具分享
  • 【每日学点鸿蒙知识】组件封装通用方法、callback和await性能对比、Web组件下拉刷新、hsp包报错、WebView圆角
  • 使用 Three.js 创建一个 3D 人形机器人仿真系统
  • 基于MATLAB的冰箱水果保鲜识别系统
  • RustDesk内置ID服务器,Key教程
  • 洛谷 P2422:良好的感觉 ← 单调队列+前缀和
  • 【PPTist】表格功能
  • PyTorch框架——基于深度学习LYT-Net神经网络AI低光图像增强系统源码
  • 2.5.3 文件使用、共享、保护、安全与可靠性
  • 瑞芯微全新芯片平台RK3506优势详解,高集成低功耗,为工业而生 触觉智能测评
  • Proteus仿真——《51单片机AD和DA转换器的设计》
  • 【数据结构】单链表的使用
  • 【CSS in Depth 2 精译_096】16.4:CSS 中的三维变换 + 16.5:本章小结
  • 解决VSCODE输出python中文乱码问题
  • 【网络云计算】2024第52周-每日【2024/12/26】小测-理论实操-备份MySQL数据库并发送邮件-解析
  • 【从0带做】基于Springboot3+Vue3的高校食堂点餐系统
  • C# 编程系列:网络通信之TCP通信(第一篇:介绍TCP协议在C#中的基本概念和工作原理)
  • wordpres当前分类调用父分类的名称和链接