Qt实现三次样条Cardinal曲线

linux下根据进程pid获取对应的window id的方法 有时候我们需要在一个图形化进程中抓取另外一个进程的窗口以嵌入到当前进程的界面里。比如,在QT开发中,在当前的进程界面里启动另外一个进程并将其窗口嵌入到当前进程的界面内。下面的代码示例了如何根据进程的id获取其对应的UI窗口ID(基于x11框架)。 阅读详情

目录

1. 前言

2. 预备知识

3. 代码实现

4. 附录


1. 前言

       在设计矢量图案的时候,我们常常需要用到曲线来表达物体造型,单纯用鼠标轨迹绘制显然是不足的。于是我们希望能够实现这样的方法:通过设计师手工选择控制点,再通过插值得到过控制点(或在附近)的一条平滑曲线。在这样的需求下,样条曲线诞生了。简而言之,样条曲线是由多个多项式按比例系数组成的多项式函数,而比例系数是由控制点决定的。Hermite曲线、Cardinal曲线在平时的开发中,经常用于模拟运动物体的轨迹,如下:

2. 预备知识

       关于Hermite曲线、Cardinal曲线的数学理论,参见如下博文:

3. 代码实现

如下为用Qt实现的Cardinal曲线

Cardinal.h

#pragma once

#include <QtWidgets/QWidget>
#include "ui_Cardinal.h"

QT_BEGIN_NAMESPACE
namespace Ui { class CardinalClass; };
QT_END_NAMESPACE

class Cardinal : public QWidget
{
    Q_OBJECT

public:
    Cardinal(QWidget *parent = nullptr);
    ~Cardinal();

private:
    Ui::CardinalClass *ui;
};

Cardinal.cpp 

#include "Cardinal.h"

Cardinal::Cardinal(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::CardinalClass())
{
    ui->setupUi(this);
    setWindowState(Qt::WindowMaximized);

    ui->doubleSpinBox->setMinimum(0);
    ui->doubleSpinBox->setMaximum(1);
    ui->doubleSpinBox->setValue(0.5);
    ui->doubleSpinBox->setSingleStep(0.1);

    connect(ui->doubleSpinBox, QOverload<double>::of(&QDoubleSpinBox::valueChanged), ui->myCardinalPanel, &CardinalPanel::valueChanged);
    connect(ui->startDrawBtn, &QAbstractButton::clicked, ui->myCardinalPanel, &CardinalPanel::startDraw);
    connect(ui->clearBtn, &QAbstractButton::clicked, ui->myCardinalPanel, &CardinalPanel::clear);
}


Cardinal::~Cardinal()
{
    delete ui;
}

CardinalPanel.h 

#pragma once

#include <QWidget>
#include "ui_CardinalPanel.h"
#include<vector>
using std::list;

class CardinalPanel : public QWidget
{
	Q_OBJECT


public:
	CardinalPanel(QWidget *parent = nullptr);
	~CardinalPanel();
public:

	void valueChanged(double value);

	void startDraw();

	void clear();
private:

	virtual void mousePressEvent(QMouseEvent* event) override;

	virtual void paintEvent(QPaintEvent* event)  override;

private:

	// 画鼠标左键按下选中的点
	void drawPoint();

	// 画Cardinal曲线
	void drawCardinal();

	// 计算MC矩阵
	void calMcMatrix(double s);

	// 压入头部和尾部两个点,用于计算
	void pushHeadAndTailPoint();
private:
	Ui::CardinalPanelClass ui;
	bool m_bStartDraw{false};
	double m_dfMcMatrix[4][4];
	list<QPoint> m_lstPoint;
	QPainterPath path;
};

CardinalPanel.cpp

#include "CardinalPanel.h"
#include<QMouseEvent>
#include<QPainter>
#include <QPainterPath>
#include<vector>
using std::vector;

CardinalPanel::CardinalPanel(QWidget* parent)
	: QWidget(parent)
{
	ui.setupUi(this);

	valueChanged(0.5);
}

CardinalPanel::~CardinalPanel()
{}

void CardinalPanel::valueChanged(double value)
{
	auto s = (1 - value) / 2.0;

	// 计算MC矩阵
	calMcMatrix(s);
	
	update();
}

// 计算MC矩阵
void CardinalPanel::calMcMatrix(double s)
{
	m_dfMcMatrix[0][0] = -s, m_dfMcMatrix[0][1] = 2 - s, m_dfMcMatrix[0][2] = s - 2, m_dfMcMatrix[0][3] = s;//Mc矩阵
	m_dfMcMatrix[1][0] = 2 * s, m_dfMcMatrix[1][1] = s - 3, m_dfMcMatrix[1][2] = 3 - 2 * s, m_dfMcMatrix[1][3] = -s;
	m_dfMcMatrix[2][0] = -s, m_dfMcMatrix[2][1] = 0, m_dfMcMatrix[2][2] = s, m_dfMcMatrix[2][3] = 0;
	m_dfMcMatrix[3][0] = 0, m_dfMcMatrix[3][1] = 1, m_dfMcMatrix[3][2] = 0, m_dfMcMatrix[3][3] = 0;
}

void CardinalPanel::clear()
{
	m_bStartDraw = false;

	m_lstPoint.clear();

	update();
}

// 压入头部和尾部两个点,用于计算
void CardinalPanel::pushHeadAndTailPoint()
{
	// 随便构造两个点
	auto ptBegin = m_lstPoint.begin();
	auto x = ptBegin->x() + 20;
	auto y = ptBegin->y() + 20;
	m_lstPoint.insert(m_lstPoint.begin(), QPoint(x, y));

	auto ptEnd = m_lstPoint.back();
	x = ptEnd.x() + 20;
	y = ptEnd.y() + 20;
	m_lstPoint.insert(m_lstPoint.end(), QPoint(x, y));
}
void CardinalPanel::startDraw()
{
	m_bStartDraw = true;

	pushHeadAndTailPoint();

	update();
}

void  CardinalPanel::mousePressEvent(QMouseEvent* event) 
{
	if ((Qt::LeftButton != event->button()))
	{
		return QWidget::mousePressEvent(event);
	}

	m_lstPoint.insert(m_lstPoint.end(), event->pos());

	update();

	QWidget::mousePressEvent(event);
}

// 画鼠标左键按下选中的点
void CardinalPanel::drawPoint()
{
	QPainter painter(this);
	painter.setBrush(QColor(Qt::red));

	const auto iPointSize = 8;

	// 先画鼠标左键按下选中的点
	auto nPointIndex = 0;
	for (auto iter = m_lstPoint.begin(); iter != m_lstPoint.end(); ++iter)
	{
		// 头部、尾部的两个控制点不绘制
		if (m_bStartDraw && ( (iter == m_lstPoint.begin()) || (*iter == m_lstPoint.back()) ))
		{
			continue;
		}
		
		painter.drawEllipse(*iter, iPointSize, iPointSize);
	}
}

// 画Cardinal曲线
void CardinalPanel::drawCardinal()
{
	if (m_lstPoint.size() < 4)
	{
		return;
	}

	QPainter painter(this);
	QPen pen(QColor(Qt::green), 6);
	painter.setPen(pen);
	
	path.clear();

	auto iter = m_lstPoint.begin();
	++iter; // 第1个点(基于0的索引)
	path.moveTo(*iter);
	--iter;

	auto endIter =  m_lstPoint.end();
	int nIndex = 0;
	while (true)
	{
		--endIter;
		++nIndex;
		if (3 == nIndex)
		{
			break;
		}
	}

	for (; iter != endIter; ++iter)
	{
		auto& p0 = *iter;
		auto& p1 = *(++iter);
		auto& p2 = *(++iter);
		auto& p3 = *(++iter);

		--iter;
		--iter;
		--iter;

		vector<QPoint>vtTempPoint;
		vtTempPoint.push_back(p0);
		vtTempPoint.push_back(p1);
		vtTempPoint.push_back(p2);
		vtTempPoint.push_back(p3);

		//double value[4][1];
		for (auto i = 0; i < 4; ++i)
		{
			vtTempPoint[i] = m_dfMcMatrix[i][0] * p0 + m_dfMcMatrix[i][1] * p1 + m_dfMcMatrix[i][2] * p2 + m_dfMcMatrix[i][3] * p3;
		}

		double t3, t2, t1, t0;
		for (double t = 0.0; t < 1; t += 0.01)
		{
			t3 = t * t * t; t2 = t * t; t1 = t; t0 = 1;
			auto newPoint = t3 * vtTempPoint[0] + t2 * vtTempPoint[1] + t1 * vtTempPoint[2] + t0 * vtTempPoint[3];
			path.lineTo(newPoint);
		}
		 
	}

	painter.drawPath(path);
}

void CardinalPanel::paintEvent(QPaintEvent* event)
{
	drawPoint();
	
	// 再画Cardinal曲线
	if (m_bStartDraw)
	{
		drawCardinal();
	}
}

运行效果如下:


 

可以看到当u值越大时,曲线越尖锐,当变为1时,就成了直线;越小越光滑。

4. 附录

 如果想实现3D版的Cardinal曲线,请参考:osg实现三次样条Cardinal曲线

QT绘制样条线图详解及示例代码 在本文中,我们将详细介绍如何使用C++和QT库来绘制样条线图。QT是一个功能强大的跨平台应用程序开发框架,它提供了丰富的绘图功能,使我们能够轻松创建各种图形。在示例代码中,我们添加了4个数据点,分别为(50, 50)、(100, 200)、(200, 80)和(300, 250)。通过上述步骤,我们已经完成了使用QT库绘制样条线图的过程。你可以将上述代码复制到一个QT项目中进行编译和运行,以查看样条线图的效果。这样,我们的样条线图将会在主窗口中显示。函数将数据点连接起来,形成样条线,并在窗口上进行绘制。 阅读详情

相关推荐

Qt实现cardinal样条曲线绘制并实现小车沿曲线运动

根据cardinal曲线原理完成鼠标取点绘制曲线,并使小车沿曲线运动,使用Qt完成界面设计。

B样条曲线绘制程序(基于Qt c++)

B样条曲线绘制程序(基于Qt c++)

fxm的博客 1245

b样条曲线QT实现

在qt 中写的样条曲线绘制程序,能够在界面上拖动控制点进行调整样条曲线。

Qt图表绘制(QtCharts)-绘制简单的样条曲线图(6)

Qt使用QtCharts模块绘制一个平滑曲线的简单示例,包含详细的注释说明。

mahuifa的博客 1万+

基于C++ Qt 5.15 的B样条曲线绘制程序

基于C++的B样条曲线绘制程序 本程序基于C++开发,其开发环境为: ·Windows 11操作系统 ·Qt 5.15.2 MSV2019 64bit Release构建套件 本程序具体可实现功能如下: 1) 输入控制点,显示控制点和控制线,如图1中白色点、线; 2) 可随时输入曲线的次数并实时重绘曲线,默认为2次曲线; 3) 可随时选择曲线的类型并实时重绘曲线,默认为均匀B样条,并可在错选分段Bezier类型时自动退出并弹窗提示; 4) 能够根据曲线类型自动确定节点矢量的计算策略,对于均匀、准均匀与分段Bezier三种类型自动确定,非均匀类型使用Hartley-Judd方法确定; 5) 根据输入计算并显示B样条基函数图; 6) 根据输入计算并显示B样条曲线; 7) 可对任意控制顶点的位置(需在控制点输入完成后)、曲线次数、曲线类型进行修改并实时动态显示。 具体操作方法为: 1) 通过鼠标左键输入控制顶点,并可在输入结束后进行拖动; 2) 通过鼠标右键结束控制顶点的输入; 3) 通过鼠标双击清空绘图区域并可重新绘制; 4) 通过窗口按钮可选择曲线类型、曲线次数、曲线抗锯齿开关

攻防世界:Crypto习题之easy_RSA

在非对称加密算法中,单向函数被广泛应用,用于确保从公钥加密后的密文无法轻易推导出私钥,从而保证数据的安全性。而其中最著名的算法便是 RSA 加密算法。首先设φm:=∣1≤k≤mgcdkm1∣为欧拉函数(Euler’sche Phi-function)。pqn:=pqpqφnnpqpqφnp−1q−1e∈12...φn−1gcdφne1ended≡1φn假设我们现在有明文x以及公钥en。

qq_52789488的博客 1572

osg实现三次样条Cardinal曲线

在设计矢量图案的时候,我们常常需要用到曲线来表达物体造型,单纯用鼠标轨迹绘制显然是不足的。于是我们希望能够实现这样的方法:通过设计师手工选择控制点,再通过插值得到过控制点(或在附近)的一条平滑曲线。在这样的需求下,样条曲线诞生了。简而言之,样条曲线是由多个多项式按比例系数组成的多项式函数,而比例系数是由控制点决定的。Hermite曲线、Cardinal曲线在平时的开发中,经常用于模拟运动物体的轨迹,如下:以上是二维下的Cardinal曲线效果,如何用osg实现 三维的Cardinal曲线呢?

danshiming的博客 676

机器人运动不流畅?手把手教你用ACCSET调整ABB/FANUC点位加速度

本文针对ABB和FANUC工业机器人运动不流畅、拐角抖动、到位震颤等常见问题,提供了详细的解决方案。核心在于使用ACCSET指令(ABB)或ACC选项(FANUC)调整机器人的点位加速度与减速度参数。文章通过实战案例与系统化调试流程,手把手指导工程师优化运动性能,实现平稳、精准的机器人运动控制。

gpu4optimizer的博客 284

三次参数样条曲线与Cardinal曲线

已知n个型值点Pi(xi, yi), i = 1, 2,…, n且相邻型值点不重合;型值点Pi在函数 p(t) 上。p(t) 在整个区间[P1, Pn]上二阶连续可导。在每个子区间[Pi, Pi+1], i = 1, 2,…, n-1上,分段函数 p(t) 都是参数t的三次多项式。则称函数是过型值点的三次参数样条函数,由三次参数样条函数构成的曲线称为三次参数样条曲线。其中,

danshiming的博客 1235

本届挑战赛亚军方案:基于大模型和多AGENT协同的运维

我们分别构建了异常检测基础模型,一旦系统接受到异常即会通知LLM主管Agent,主管Agent对异常问题进行决策与子领域Agent进行桥接,多个子领域Agent协同工作,实现运维故障自动诊断和多个任务模型的编排,提升运维效率。

weixin_52705010的博客 2292

Vitis 安装及环境配置

Vitis 官方手册 https://www.xilinx.com/html_docs/xilinx2020_1/vitis_doc/index.html Xilinx Downloads center https://www.xilinx.com/support/download/index.html/content/xilinx/en/downloadNav/vitis.html 系统要求如下图所示,Windows系统只能支持Vitis嵌入式系统开发流程,不能支持加速设计 1.安装ubuntu18.0

怠桑的博客 7051

osg实现物体沿着控制点生成的Cardinal样条轨迹曲线运动

在设计矢量图案的时候,我们常常需要用到曲线来表达物体造型,单纯用鼠标轨迹绘制显然是不足的。于是我们希望能够实现这样的方法:通过设计师手工选择控制点,再通过插值得到过控制点(或在附近)的一条平滑曲线。在这样的需求下,样条曲线诞生了。简而言之,样条曲线是由多个多项式按比例系数组成的多项式函数,而比例系数是由控制点决定的。Hermite曲线、Cardinal曲线在平时的开发中,经常用于模拟运动物体的轨迹,如下:以上是二维Cardinal曲线效果,如何用osg。

danshiming的博客 736

若依框架-实现管理端与用户端的不同页面布局

我们现在要做的是:管理员登录时展示后台管理端,普通用户登录时展示我们自己写的页面。所以我们可以用v-if来判断登录用户的角色,如果用户角色包含admin,说明是管理员,渲染管理端相关组件,否则渲染用户端组件。不过若依作者的本意还是想退出系统后清空角色信息,所以为了保险期间,我们可以在退出系统后,延迟2秒,再单独清空角色信息。当我们登录管理端后,再退出登录,会有那么一瞬间渲染用户页面,然后才是回到登录界面。这个时候,前端检测到角色信息为空,不包含admin,于是就会渲染用户页面。用来延迟 2 秒执行。

m0_74462339的博客 1566

Qt实现Cardinal样条曲线绘制与小车沿曲线运动

Qt实现Cardinal样条曲线绘制与小车沿曲线运动 去发现同类优质开源项目:https://gitcode.com/ 简介 本仓库提供了使用Qt框架实现的Cardinal样条曲线绘制功能,以及一个小车沿着该曲线运动的动画效果。Cardinal样条曲线是一种常用的插值曲线,通过鼠标取点,可以直观地绘制出平滑的曲线。在此基础上,通过Qt的动画框架,实现了小车沿着曲线运动的动态效果。 功能 曲线绘制...

gitblog_06731的博客 529

Multisim仿真入门:单相半波可控整流电路从搭建到波形分析(附避坑指南)

本文为电力电子技术初学者提供了一份详细的Multisim仿真指南,手把手教你从零搭建单相半波可控整流电路。通过对比纯电阻、阻感负载及加入续流二极管后的波形变化,直观理解晶闸管触发、电感续流等核心原理,并附有实用的参数设置与常见问题避坑指南,帮助你将抽象理论转化为可视化的工程实践。

weixin_29208077的博客 343

欧姆龙485通讯示例程序_【精品实验】PLC学习神器与温湿度变送器的通讯

BFH点击蓝字关注我们↑↑↑↑  PLC学习神器提供RS485接口,可支持无协议RS指令、无协议RS2指令、Modbus通讯功能,可通过设置通讯格式改变通讯协议,RS485对应的通讯格式地址是D8400;  本案例以RS485接口与温湿度变送器通讯,通讯格式如下一温湿度变送器的说明书介绍1.1主要技术参数1.2 通讯协议 1、所有通讯回路都应遵照主/从方式。依照主从方式,数据可以在一个主...

weixin_39860201的博客 1万+

【计算机动画】实验 路径曲线与运动物体控制 设计

要求 - 路径曲线与运动物体控制 掌握Cardinal样条曲线的表示和算法,了解控制参数对曲线形状的影响。 对照Cardinal样条曲线的数学表示和程序代码的对应关系。 在路径曲线上放置一小汽车,使其在路径上运动起来,汽车运动速度可调。 1.Cardinal spline P(u)=UTMB UT=[u3u2u1],B=⎡⎣⎢⎢...

bangce8949的博客 134

Vue - 解决报错 Error: Cannot find module ‘XXX\@vue\cli-service\bin\vue-cli-service.js‘(vue项目编译运行出错,启动失败)

vue报错,Error: Cannot find module ‘@vue\cli-service\bin\vue-cli-service.js‘,vue2项目启动报错,vue3项目运行出错,vue执行npm run serve报错,找不到@vue/cli-service模块,vue项目关于:Error: Cannot find module ‘D:\@vue\cli-service\bin\vue-cli-service.js‘的解决方案,vue项目跑不起来了,Vue项目报错,跑项目报错Cannot fi

🏆 前端领域优质创作者 3115

QT- QT-lximagerEidtor图片编辑器

功能如下:1、缩放、旋转、翻转和调整图像大小2、幻灯片3、缩略图栏(左、上或下);不同的缩略图大小4、Exif数据栏5、内联图像重命名6、自定义快捷方式7、图像注释(箭头、矩形、圆形、数字)8、最近的文件9、上传图片(Imgur)10、截屏。

u013083044的博客 1047

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

Linux下Qt应用嵌入外部进程窗口

Qt启动嵌入外部进程窗口 Linux x11环境下Qt应用实现多进程窗口嵌入 效果展示 如图: 实现说明 启动外部进程,通过进程id获取窗口winid,然后通过QWindow::fromWinId获取QWindow,使用QWidget::createWindowContainer创建包含进程界面QWidget。 embedexternalapp.cpp embedexternalapp::embedexternalapp(QWidget *parent) : QWidget(parent) {

sbkebcmj的博客 1万+

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

CardinalSpline样条曲线(沿着正方形路线走)

CardinalSpline样条曲线(沿着正方形路线走) 1 ////////////// CardinalSpline 样条曲线 /////////////// 2 3 Sprite* sprite = Sprite::create("button.png"); 4 //sprite->setPosition(Vec2(visib...

weixin_34088838的博客 397

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

Qt开发必备:5个高频使用却容易被忽略的QWidget类方法(附实战代码)

本文深入解析Qt开发中5个高频使用却容易被忽略的QWidget类方法,包括setWindowFlags()、setAttribute()、winId()、grab()和setGraphicsEffect(),通过实战代码演示它们在窗口样式控制、平台集成、界面截图和UI特效等场景的应用,帮助开发者提升Qt应用的功能和用户体验。

e3f4g5的博客 173

让相册应用丝滑流畅的秘诀:LavenderPhotos的Baseline Profiles与性能优化实践

LavenderPhotos 是一款主打美观与性能的 Android 相册应用(Kotlin + Jetpack Compose 开发)。本文带你拆解它如何用 **Baseline Profiles** 与 **Macrobenchmark 冷启动度量** 完成性能优化,让照片网格滚动更顺滑、冷启动更快,并提供一套可直接抄作业的 Android 应用性能优化清单。 ## Baseline Pro

gitblog_00486的博客 184

Cobalt 怎么保存 Vimeo 视频?4K 画质、密码视频都能一键搞定

想把 Vimeo 上的课程录像、独立短片存到本地,却找不到靠谱入口?不少在线下载器要么塞满广告,要么一碰到带密码的私有视频就罢工。Cobalt 是个开源的视频下载工具,这次把 Vimeo 视频下载做成了完整支持:贴个链接就能拿到 240p 到 4K 的多个清晰度,还能单独抽音频、抓取内嵌字幕。没有弹窗、没有追踪,体验就是"粘贴 → 下载"这么简单。对只想安静保存内容、不想被广告打扰的人来说,这个定

gitblog_00553的博客 608

AntiMicroX 手柄映射实战:一个手柄接管所有键鼠游戏

AntiMicroX 是一款图形化手柄映射工具,把游戏手柄的按键、摇杆翻译成键盘、鼠标、脚本与宏事件,设备轮询间隔可低至 1 ms。它同时支持 X11 与 Wayland,内置 xtest、uinput、SendInput、Vmulti 四套可插拔的事件注入后端,也是已停更的 AntiMicro 项目的直接继承者。 [![AntiMicroX 手柄映射主界面:列出已连接手柄并给每个按键槽位绑定键

gitblog_02391的博客 446
上一篇: 三次参数样条曲线与Cardinal曲线
下一篇: osg嵌入到Qt窗体,实现Qt和osg混合编程
荆楚闲人
博客等级 码龄20年 3万+粉丝 473原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值