QT实现单个控制点在曲线上的贝塞尔曲线

news2025/3/4 15:39:09

最终效果:
在这里插入图片描述
一共三个文件
main.cpp

#include <QApplication>
#include "SplineBoard.h"
int main(int argc,char** argv) {
    QApplication a(argc, argv);
    SplineBoard b;
    b.setWindowTitle("标准的贝塞尔曲线");
    b.show();

    SplineBoard b2(0.0001);
    b2.show();
    b2.setWindowTitle("控制点在曲线上的贝塞尔曲线");

    b.move(0,0);
    b2.move(800,0);
    return a.exec();
}

SplineBoard.h

#ifndef SPLINEBOARD_H
#define SPLINEBOARD_H
#include <QPainter>
#include <QWidget>
class SplineBoard:public QWidget
{
    Q_OBJECT
public:
    SplineBoard(double terminalRatio = 0.25);

protected:
    void mouseMoveEvent(QMouseEvent* e);
    void mousePressEvent(QMouseEvent* e);
    void mouseReleaseEvent(QMouseEvent* e);
    void paintEvent(QPaintEvent* e);
    int mPressedPos;
    QPointF mStart;
    QPointF mEnd;
    QPointF mCont;
    const double termRatio;
};

#endif // SPLINEBOARD_H

SplineBoard.cpp

#include "SplineBoard.h"
#include <QDebug>
#include <QMouseEvent>
#include <QPainterPath>

static int radius = 8;
static const int PosEmpty = 0;
static const int PosStart = 1;
static const int PosCont = 2;
static const int PosEnd = 4;

static void buildQuadBezier(QPainterPath& pp, const QPointF& p0,const QPointF& p1,
                     const QPointF& p2, qreal term){
    pp.moveTo(p0);
    const qreal a = (term-0.5)*-4;
    const qreal d = (1-2*term)*-4;
    for (qreal t = 0; t < 1.01; t += 0.01) {
        qreal A = a*t*t+(-1-a)*t+1;
        qreal B = d*t*t - d*t;
        qreal C = a*t*t + (1-a)*t;
        qreal x = A * p0.x() + B * p1.x() + C * p2.x();
        qreal y = A * p0.y() + B * p1.y() + C * p2.y();
        pp.lineTo(x, y);
    }
}
SplineBoard::SplineBoard(double terminalRatio):mPressedPos(PosEmpty),termRatio(terminalRatio)
{
    resize(800,600);
    setWindowTitle("spline board");

    mStart = QPointF(50,300);
    mEnd = QPointF(750,300);
    mCont = QPointF(400,300);
}

void SplineBoard::mouseMoveEvent(QMouseEvent* e){
    auto cur = e->pos();
    if(mPressedPos == PosStart){
        mStart = cur;
    }
    else if(mPressedPos == PosCont){
        mCont = cur;
    }
    else if(PosEnd == mPressedPos){
        mEnd = cur;
    }
    else{
        return;
    }
    update();
}
void SplineBoard::mousePressEvent(QMouseEvent* e){
    auto pos = e->pos();
    auto startRect = QRectF(mStart,QSize(radius*2,radius*2));
    startRect.translate(-radius,-radius);
    auto contRect = QRectF(mCont,QSize(radius*2, radius*2));
    contRect.translate(-radius,-radius);
    auto endRect = QRectF(mEnd , QSize(radius*2, radius*2));
    endRect.translate(-radius,-radius);

    if(startRect.contains(pos)){
        mPressedPos = PosStart;
    }
    else if(contRect.contains(pos)) {
        mPressedPos = PosCont;
    }
    else if(endRect.contains(pos)){
        mPressedPos = PosEnd;
    }
    else{
        mPressedPos = PosEmpty;
    }

}
void SplineBoard::mouseReleaseEvent(QMouseEvent* e){
    mPressedPos = PosEmpty;
}

void SplineBoard::paintEvent(QPaintEvent* e){
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);

    QPen pen(Qt::blue);
    pen.setWidth(2);
    painter.setPen(pen);

    QPainterPath path;

    buildQuadBezier(path,mStart,mCont,mEnd,termRatio);
    painter.drawPath(path);

    painter.setPen(Qt::NoPen);
    painter.setBrush(Qt::magenta);
    painter.drawEllipse(mStart,radius,radius);  // Draw start point
    painter.drawEllipse(mCont, radius,radius);  // Draw control point
    painter.drawEllipse(mEnd, radius,radius);  // Draw end point

    QWidget::paintEvent(e);

}

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

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

相关文章

Linux基础开发工具(vim编译器,yum与apt软件安装)

Linux 下载安装软件的方案 源代码安装-》》》非常麻烦与复杂一步错步步错 rmp包安装 -》》》只是安装没有对应的库与依赖相当于只是一个外壳 包管理器进行安装-》》 yum / apt(本篇重点讲解) 1.什么是软件包和软件包管理器 就好⽐ "App" 和 "应⽤商店"…

神经网络 - 激活函数(Maxout 单元)

一、Maxout 单元 Maxout 单元是一种特殊的激活函数&#xff0c;用于神经网络中&#xff0c;其主要思想是通过多个线性变换的最大值来作为神经元的输出&#xff0c;从而提高模型的表达能力和鲁棒性。 1. 数学定义 假设输入为 x&#xff0c;Maxout 单元会计算 k 个线性变换&am…

nginx+keepalived负载均衡及高可用

1 项目背景 keepalived除了能够管理LVS软件外&#xff0c;还可以作为其他服务的高可用解决方案软件。采用nginxkeepalived&#xff0c;它是一个高性能的服务器高可用或者热备解决方案&#xff0c;Keepalived主要来防止服务器单点故障的发生问题&#xff0c;可以通过其与Nginx的…

VirtualBox虚拟机转VM虚拟机

前言&#xff1a;部分靶机只适用于VirtualBox&#xff0c;VM打不开VirtualBox的文件&#xff0c;所以需要进行转换 前置条件&#xff1a;本机已经下载VM和VirtualBox 第一步&#xff1a;文件转换 找到VirtualBox.exe所在位置&#xff0c;启动cmd窗口 文件转换的命令&#xf…

使用DeepSeek+KIMI生成高质量PPT

一、使用DeepSeek DeepSeek官网&#xff1a;DeepSeek 点击“开始对话”&#xff0c;进入交互页面。 在上图中&#xff0c;输入问题&#xff0c;即可获取AI生成的结果。 基础模型&#xff08;V3&#xff09;&#xff1a;通用模型&#xff08;2024.12&#xff09;&#xff0c;高…

基于SpringBoot的失物招领平台的设计与实现

基于SpringBoot的失物招领平台的设计与实现 基于微信小程序的失物招领系统 失物招领小程序 校园失物招领小程序 基于微信小程序SSMMySQL开发&#xff0c;高分JAVA成品毕业设计&#xff0c;附带往届论文、启动教程、讲解视频、二次开发教程和配套安装包文件&#xff0c;论文中…

鸿蒙NEXT开发-元服务和服务卡片的开发

注意&#xff1a;博主有个鸿蒙专栏&#xff0c;里面从上到下有关于鸿蒙next的教学文档&#xff0c;大家感兴趣可以学习下 如果大家觉得博主文章写的好的话&#xff0c;可以点下关注&#xff0c;博主会一直更新鸿蒙next相关知识 目录 1. 元服务基本概念 1.1 基本介绍 1.2 元…

【Spark+Hive】基于Spark大数据技术小红书舆情分析可视化预测系统(完整系统源码+数据库+开发笔记+详细部署教程+虚拟机分布式启动教程)✅

目录 一、项目背景 二、项目目标 三、算法介绍 四、开发技术介绍 五、项目创新点 六、项目展示 七、权威教学视频 源码获取方式在文章末尾 一、项目背景 在数字经济蓬勃发展的当下&#xff0c;社交电商平台小红书凭借其"内容电商"的独特模式&#xff0c;已…

IO基础知识和练习

一、思维导图 二、练习 1.使用标准IO函数&#xff0c;实现文件的拷贝 #include <head.h> int main(int argc, const char *argv[]) {FILE *pfopen("./one.txt","r");FILE *fpfopen("./two.txt","r");if(pNULL)PRINT_ERROR(&qu…

gradle libs.versions.toml文件

1.libs.versions.toml介绍2.创建libs.versions.toml文件3.libraries5.versions6.plugins7.bundles 1.libs.versions.toml介绍 下图是官网介绍 意思就是说项目所有插件和库的依赖版本都统一在这个文件配置。 文件中有以下四个部分 versions, 申明要使用的插件和库的版本号的…

2025 Lakehouse 趋势全景展望:从技术演进到商业重构

1. 为什么湖仓正在成为企业数据架构的必选项&#xff1f; 越来越多的企业正在通过实时数据处理能力构建核心竞争力——用户期待 APP 精准捕捉需求并实时响应&#xff0c;企业员工追求业务系统的秒级反馈&#xff0c;这些场景背后是千亿级数据资产的敏捷调度。 据 IDC 预测&am…

一、NRF2401无线通信模块使用记录

一、电路引脚图 1、引脚说明&#xff1a; 2、引脚标号&#xff1a; 找到1号引脚&#xff0c;与原理图对号入座。 3、cubemx初始化配置&#xff1a; 5、驱动文件 配置spi&#xff0c;并构建发送与接收函数接口 .h #define TX_ADR_WIDTH 5 //发射地址宽度 #define TX_PLO…

NVIDIA GPU 架构详解:Pascal、Volta、Turing、Ampere、Ada、Hopper、Blackwell

目录 1. Pascal&#xff08;帕斯卡&#xff09;架构&#xff08;2016&#xff09;关键技术性能特性代表产品应用场景 2. Volta&#xff08;伏特&#xff09;架构&#xff08;2017&#xff09;关键技术性能特性代表产品应用场景 3.Turing&#xff08;图灵&#xff09;架构&#…

初阶数据结构(C语言实现)——3顺序表和链表(2)

2.3 数组相关面试题 原地移除数组中所有的元素val&#xff0c;要求时间复杂度为O(N)&#xff0c;空间复杂度为O(1)。OJ链接 力扣OJ链接-移除元素删除排序数组中的重复项。力扣OJ链接-删除有序数组中的重复项合并两个有序数组。力扣OJ链接-合并两个有序数组 2.3.1 移除元素 1…

IP-----BGP协议

7.BGP协议 1.BGP的所属分类 2.BGP的特性 3.BGP的数据包 4.BGP的6种状态机 5.BGP的工作过程 6.BGP的路由黑洞 1.BGP路由黑洞 2.解决方法 7.BGP的防环 1.EBGP水平分割 2.IBGP水平分割 1.解决IBGP环路的规则 2.解决IBGP水平分割问题 3.作用 8.BGP的基础配置 1.查看…

【String】917. 仅仅反转字母

917. 仅仅反转字母 - 力扣&#xff08;LeetCode&#xff09; 使用双指针&#xff0c;一个指针指向s的开始&#xff0c;一个指向s的末尾&#xff0c;同时遍历即可。

python3使用selenium打开火狐并全屏

序言 本来桌面端全屏这种东西现在用electron或者tauri来做软件的全屏&#xff0c;但是奈何今天拿到了一块早些年的nx板子&#xff0c;arm架构的&#xff0c;系统有点老&#xff0c;装node只能到16版本&#xff0c;装了半天终于搞好了&#xff0c;发现这个系统没法隐藏系统的顶…

探秘基带算法:从原理到5G时代的通信变革【二】Viterbi解码

文章目录 二、关键算法原理剖析2.1 Viterbi 解码2.1.1 卷积码与网格图基础**卷积码****网格图****生成多项式****理想情况下解码过程** 2.1.2 Viterbi 算法核心思想2.1.3 路径度量与状态转移机制2.1.4 算法流程与关键步骤详解2.1.5 译码算法举例与复杂度分析2.1.6 算法代码示例…

金融项目实战

测试流程 测试流程 功能测试流程 功能测试流程 需求评审制定测试计划编写测试用例和评审用例执行缺陷管理测试报告 接口测试流程 接口测试流程 需求评审制定测试计划分析api文档编写测试用例搭建测试环境编写脚本执行脚本缺陷管理测试报告 测试步骤 测试步骤 需求评审 需求评…

命令行参数和环境变量 ─── linux第13课

目录 命令行参数 命令行参数列表: 如何实现命令行参数传递到此进程 环境变量 基本概念 常见环境变量 查看环境变量方法 ​编辑 环境变量如何写入 总结: 测试PATH 命令行参数 同一个程序,可以根据命令行参数的不同,表现不同功能 比如:指令中的选项的实现. ls -al…