QT之基于图形框架QGraphicsView实现链路图

2023-05-16

1 前言

最近因项目需求,需要制作一个可以绘制树结构的“事件链”插件,于是呼找到了QT自带的一个画流程图的例子“diagramscene”,还在网上找到了另外一个例子,然后我结合了两个demo实现了我的“事件编辑器”的前期实现工作,虽然有点小BUG但是基本上算是完成了。

1)qt 自带的绘制流程图示例,可以在QT Creator搜索“diagramscene”
D:\Qt\Qt5.9.3\Examples\Qt-5.9.3\widgets\graphicsview\diagramscene

https://download.csdn.net/download/octdream/11953929

2)  qt绘制流程图示例程序——Diagram

 https://download.csdn.net/download/octdream/11953930

2 效果预览

3 功能分析

由上图可以看到,本人实现了节点的添加,编辑,删除,移动以及节点与节点之间建立父子关系。

其实除了这些功能以外,还实现了链路图的保存,加载功能,可实现反复编辑操作,内部采用读写数据的方式完成。

4 实现

1)节点图元实现

相比原先的demo而言,我作了如下几个方面的修改:

i)添加了节点绑定自定义信息

这个信息由项目需要来定,为自定义结构体,可以实现一个节点能携带更多我们所需的信息。

public:
    //设置节点所表示事件的具体信息;
	void setEventInfo(const KDEventInfoCn &info);
	//获取节点所表示事件的具体信息;
	KDEventInfoCn eventInfo();
private:
	KDEventInfoCn mEventInfo;
void KDEventNode::setEventInfo(const KDEventInfoCn &info)
{
	prepareGeometryChange();
	this->mEventInfo = info;
	update();
}

KDEventInfoCn KDEventNode::eventInfo()
{
	return this->mEventInfo;
}

ii) 添加了节点支持多行文本显示

QT中QFontMetricsF 是不支持换行计算的,所以只能自己分割字符串来计算多行的文本外边框。

QRectF KDEventNode::getContentRect(QString content) const
{
	QFontMetricsF fm = qApp->fontMetrics();
	QRectF rect = fm.boundingRect(content);
	
	//单行字体大小
	float fontHeight = fm.height();
	//行距
	float lineHeight = 4;
	float maxWidth = 0;

	QStringList textList = content.split("\n");
	//最大的宽度
	for(int i = 0;i < textList.size(); i++)
	{
		float temp = fm.width(textList.at(i));

		if(temp > maxWidth)
		{
			maxWidth = temp;
		}
	}
	// 计算总高度
	float textHeightSum = fontHeight * textList.size();
	float lintHeightSum = lineHeight * (textList.size()-1);
	float heightSum = textHeightSum + lintHeightSum;
	float widthSum = maxWidth ;

	rect.setSize(QSizeF(widthSum,heightSum));
	return rect;
}

2)连线图元实现

i) 优化了连线与节点的交点计算,并且优化了箭头的样式

void KDEventLink::paint(QPainter *painter, const QStyleOptionGraphicsItem *,QWidget *)
{
	if (_mFromNode->collidesWithItem(_mToNode))
		return;

	QPen myPen = pen();
	myPen.setColor(_mColor);
	qreal arrowSize = 15;
	painter->setPen(myPen);
	painter->setBrush(_mColor);

	QLineF centerLine(_mFromNode->pos(), _mToNode->pos());
	QPolygonF endPolygon = _mToNode->shape().toFillPolygon();//_mToNode->polygon();
	QPointF intersectPointTo = getIntersectPoint(centerLine,endPolygon,_mToNode);
	QPolygonF startPolygon = _mFromNode->shape().toFillPolygon();
	QPointF intersectPointFrom = getIntersectPoint(centerLine,startPolygon,_mFromNode);
	setLine(QLineF(intersectPointTo,intersectPointFrom));

	double angle = ::acos(line().dx() / line().length());
	if (line().dy() >= 0)
		angle = (Pi * 2) - angle;

	QPointF arrowP1 = line().p1() + QPointF(sin(angle + Pi / 3) * arrowSize,
		cos(angle + Pi / 3) * arrowSize);
	QPointF arrowP2 = line().p1() + QPointF(sin(angle + Pi - Pi / 3) * arrowSize,
		cos(angle + Pi - Pi / 3) * arrowSize);
	qreal d = -(arrowSize-6);
	QPointF arrowP3 = line().p1() + QPointF((d *(line().p1().x() -line().p2().x()))/line().length() ,
		(d *(line().p1().y() -line().p2().y()))/line().length());

	_mLinkHead.clear();
	_mLinkHead << line().p1() << arrowP1 << arrowP3 << arrowP2;

	painter->drawLine(line());
	painter->drawPolygon(_mLinkHead);
	if (isSelected()) {
		painter->setPen(QPen(_mColor, 1, Qt::DashLine));
		QLineF myLine = line();
		myLine.translate(0, 4.0);
		painter->drawLine(myLine);
		myLine.translate(0,-8.0);
		painter->drawLine(myLine);
	}
}
QPointF KDEventLink::getIntersectPoint(QLineF centerLine,QPolygonF polygon,KDEventNode *node)
{
	QPointF p1 = polygon.first() + node->pos();
	QPointF p2;
	QPointF intersectPoint;
	QLineF polyLine;
	for (int i = 1; i < polygon.count(); ++i) {
		p2 = polygon.at(i) + node->pos(); //偏移坐标 + 原点 = 实际坐标
		polyLine = QLineF(p1, p2);
		QLineF::IntersectType intersectType =
			polyLine.intersect(centerLine, &intersectPoint);
		if (intersectType == QLineF::BoundedIntersection)
			break;
		p1 = p2;
	}

	return intersectPoint;
}

3)绘制场景

i) 添加了节点移动信号

节点移动信号,是为了支持节点发生移动后可以正常保存两数据库中,当重新绘制链路图时,可以正确显示节点的位置。

虽然系统提供了节点的x,y坐标移动信号,但是感觉触发太频繁;我这里是当 : 选中——>移动——>释放,完成这个过程才会触发一个移动信号。

ii)添加节点插入信号

当用户在场景中点击鼠标左键,会在点击位置产生一个节点,此时则与会产生一个节点插入信号

ii)添加连接线插入信号 

当用户在场景中在一节点上点击鼠标左键不松然后拖动至另一节点上释放左键,则会在开始节点与目标节点中间产生一个条带箭头的连接线,此时也会产生一个连接线插入信号。

signals:
    //节点插入
	void nodeInserted(KDEventNode *item);
    //连接线插入
	void linkInserted(KDEventLink *item);
    //节点移动
	void nodeMoved();

protected:
	void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent) override;
	void mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent) override;
	void mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent) override;

private:

	bool isChoosed;
	bool isMoved;
void KDEventScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
	if (mouseEvent->button() != Qt::LeftButton)
		return;

	if(this->mCurrWarInfo == NULL)
	{
		HRMessageBox::information(mParent, "没有选择一个交战项目", "请选择一个或创建一个交战项目");
		return ;
	}

	if(this->mCurrEventChainInfo == NULL)
	{
		HRMessageBox::information(mParent, "没有选择一个事件链", "请选择一个或创建一个事件链");
		return ;
	}

	KDEventNode *item;
	switch (mMode) {
	case InsertNode:{
		item = new KDEventNode(mItemMenu,mParent);
		addItem(item);
		seqNumber++;
		item->setPos(mouseEvent->scenePos());
		KDEventInfoCn info;
		info.eventChainId = this->mCurrEventChainInfo->id;
		info.warId = this->mCurrWarInfo->id;
		info.content = tr("事件 %1").arg(seqNumber);
		info.nodePos = item->pos();
		item->setEventInfo(info);
		emit nodeInserted(item);
		
		break;
	}
	case InsertLine:
		line = new QGraphicsLineItem(QLineF(mouseEvent->scenePos(),mouseEvent->scenePos()));
		line->setPen(QPen(myLineColor, 2));
		addItem(line);
		break;
	default:
		isChoosed = true;
		break;
	}
	QGraphicsScene::mousePressEvent(mouseEvent);
}

void KDEventScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
	if (mMode == InsertLine && line != 0) {
		QLineF newLine(line->line().p1(), mouseEvent->scenePos());
		line->setLine(newLine);
	} else if (mMode == MoveNode) {
		if(isChoosed)
			isMoved = true;
		QGraphicsScene::mouseMoveEvent(mouseEvent);
	}
}

void KDEventScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
	if (line != 0 && mMode == InsertLine) {
		QList<QGraphicsItem *> startItems = items(line->line().p1());
		if (startItems.count() && startItems.first() == line)
			startItems.removeFirst();
		QList<QGraphicsItem *> endItems = items(line->line().p2());
		if (endItems.count() && endItems.first() == line)
			endItems.removeFirst();

		removeItem(line);
		delete line;

		if (startItems.count() > 0 && endItems.count() > 0   && startItems.first() != endItems.first()) {
				KDEventNode *startItem = qgraphicsitem_cast<KDEventNode *>(startItems.first());
				KDEventNode *endItem = qgraphicsitem_cast<KDEventNode *>(endItems.first());
				KDEventLink *arrow = new KDEventLink(startItem, endItem);
				arrow->setColor(myLineColor);
				startItem->addLink(arrow);
				endItem->addLink(arrow);
				//arrow->setZValue(-1000.0);
				addItem(arrow);
				arrow->updatePosition();
				emit linkInserted(arrow);
		}
	}
	else if(mMode == MoveNode && isMoved)
	{
		emit nodeMoved();
	}
	isMoved = false;
	isChoosed = false;
	line = 0;
	QGraphicsScene::mouseReleaseEvent(mouseEvent);
}

4)链路图操作

i) 插入、更新

在主界面中需要关联三个信号:节点插入、连接线插入、节点移动

void KDEventEditorWidget::initGraphicsView()
{
	_p->_scene = new KDEventScene(_p->_nodeMenu,this);
	_p->_scene->setSceneRect(QRectF(0, 0, 5000, 5000));
	_p->_scene->setBackgroundBrush(Qt::white);
	connect(_p->_scene, SIGNAL(nodeInserted(KDEventNode*)),this, SLOT(nodeInserted(KDEventNode*)));
	connect(_p->_scene, SIGNAL(linkInserted(KDEventLink*)),this, SLOT(linkInserted(KDEventLink*)));
	connect(_p->_scene, SIGNAL(nodeMoved()),this, SLOT(nodeMoved()));
	ui->graphicsView->setScene(_p->_scene);
	ui->graphicsView->setDragMode(QGraphicsView::RubberBandDrag);
	ui->graphicsView->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
}

在各个槽函数中需要将所需要的数据保存下来,我在项目我采用的是Sqlite来保存数据的,当然你也可以采用文件或其它数据库来保存数据;主要是要将节点数据,节点在场景中的位置、节点的父节点信息保存下来,这样才能复现链路图。

节点插入是向数据库插入一条节点信息的过程。(INSERT)

连接线插入是节点之间创建父子关系的过程,需要在数据库中更新节点信息。(UPDATE)

节点移动是节点的位置改变的过程,也需要在数据库中更新节点位置信息。(UPDATE)

//得到节点信息,插入数据库
void KDEventEditorWidget::nodeInserted(KDEventNode *node)
{
	KDEventInfoCn infoCn = node->eventInfo();

	_p->_sqliteDB->insert(&infoCn);
}

void KDEventEditorWidget::linkInserted(KDEventLink *link)
{
	KDEventNode *node = link->toNode();
	KDEventInfoCn infoCn = node->eventInfo();
	infoCn.parentId = link->fromNode()->eventInfo().id;
	node->setEventInfo(infoCn);
	_p->_sqliteDB->update(&infoCn);
}

void KDEventEditorWidget::nodeMoved()
{
	QList<QGraphicsItem *> items = _p->_scene->selectedItems();
	foreach(QGraphicsItem * item,items)
	{
		if (item->type() == KDEventNode::Type)
		{
			KDEventNode *node = qgraphicsitem_cast<KDEventNode *>(item);
			KDEventInfoCn infoCn = node->eventInfo();
			infoCn.nodePos = node->pos();
			_p->_sqliteDB->update(&infoCn);
		}
	}	
		
	
}

在这里我在移动节点是,实现了兼容了可以框选多个节点进行移动,然后保存所有节点位置信息。

ii)节点删除

由于项目需要,我们的链路图中的节点之间是有因关系,当删除个节点时,需要删除这个节点即它的所有子节点,所以我使用了一个递归算法来删除。

void KDEventEditorWidget::deleteItem()
{
	QGraphicsItem *item = selectedItem();

	if (item)
	{
		int ret = HRMessageBox::information(this, "删除事件节点", "您确定要删除这个事件节点即所有子节点吗?",HRMessageBox::Yes | HRMessageBox::No,HRMessageBox::No);
		if(ret == HRMessageBox::Yes){
			delNodeBranch(item);
		}
	}

}

//递归删除
void KDEventEditorWidget::delNodeBranch(QGraphicsItem *item)
{
	if (item->type() == KDEventLink::Type)
	{
		KDEventLink *link = qgraphicsitem_cast<KDEventLink *>(item);
		delNodeBranch(link->toNode());
	}
	else if (item->type() == KDEventNode::Type)
	{
		KDEventNode *node = qgraphicsitem_cast<KDEventNode *>(item);
		//断开与父节点的连接
		foreach(KDEventLink *link,node->links)
		{
			if(link->toNode() == node)
			{
				node->removeLink(link);
				link->fromNode()->removeLink(link);
				_p->_scene->removeItem(link);
				delete link;
			}
		}

		foreach(KDEventLink *link,node->links)
		{
			if(link->toNode() != node)
			{
				delNodeBranch(link->toNode());
			}
		}
		_p->_scene->removeItem(node);
		_p->_sqliteDB->remove(&node->eventInfo());
		delete node;
	}
}

iii) 重新加载链路图

项目中需要对保存的链路图,重新加载后,再次编辑,这是一个数据读取及场景复现的问题,所以之间保存的节点位置,及父节点等信息起到了作用。

//点击事件链,加载该事件链的所有事件
void KDEventEditorWidget::on_eventChainTreeWidget_itemClicked(QTreeWidgetItem * dirItem, int column)
{
	if (dirItem)
	{
		currEventChainInfo = dirItem->data(0,Qt::UserRole+1).value<EventChainInfo>();
		_p->_scene->setCurrEventChain(&currEventChainInfo);
		ui->dockWidget_3->setWindowTitle(QString("%0 拓扑图").arg(dirItem->text(column)));
		//TD: 加载该事件链的所有节点
		clearGrapscsView();
		reDrawNodes(getEventChainNodeList(currEventChainInfo));
	}
}

QList<KDEventInfoCn> KDEventEditorWidget::getEventChainNodeList(EventChainInfo info)
{
	QList<KDEventInfoCn> result;
	QString sql = QString("select * from EventInfo where event_chain_id='%0'").arg(info.id);
	if(_p->_sqliteDB->select(sql))
	{
		QSqlQuery mQuery = _p->_sqliteDB->getSqlQuery();
		while(mQuery.next())
		{
			KDEventInfoCn nodeInfo(
				mQuery.value(0).toString(),
				mQuery.value(1).toString(),
				mQuery.value(2).toString(),
				mQuery.value(3).toString(),
				mQuery.value(4).toInt(),
				mQuery.value(5).toInt(),
				mQuery.value(6).toDouble(),
				mQuery.value(7).toInt(),
				mQuery.value(8).toInt(),
				mQuery.value(9).toDateTime(),
				mQuery.value(10).toDouble(),
				mQuery.value(11).toInt(),
				mQuery.value(12).toUInt(),
				mQuery.value(13).toUInt(),
				mQuery.value(14).toUInt(),
				mQuery.value(15).toUInt(),
				mQuery.value(16).toUInt(),
				mQuery.value(17).toDouble(),
				mQuery.value(18).toDouble(),
				mQuery.value(19).toString(),
				mQuery.value(20).toString());
			result.append(nodeInfo);
		}
	}
	return result;
}

void KDEventEditorWidget::reDrawNodes(QList<KDEventInfoCn> list)
{
	QMap<QString,KDEventNode *> nodeMap;
	QMap<QString,KDEventTypeInfo> eventTypesMap = getEventTypeList();
	KDEventNode * node = NULL;
	foreach(KDEventInfoCn info,list)
	{
		if(!info.eventType.id.isEmpty())
		{
			info.eventType = eventTypesMap[info.eventType.id];
		}
		node = _p->_scene->addNode(info);
		nodeMap[info.id] = node;
	}

	QMap<QString,KDEventNode *>::const_iterator it = nodeMap.constBegin();
	KDEventLink *link = NULL;
	while (it != nodeMap.constEnd()) {
		KDEventNode * toNode = it.value();
		KDEventNode * fromNode = NULL;
		QMap<QString,KDEventNode *>::const_iterator iter = nodeMap.find(toNode->eventInfo().parentId);
		if(iter != nodeMap.constEnd())
		{
			fromNode = iter.value();
			link = new KDEventLink(fromNode,toNode);
			_p->_scene->addLink(link);
		}
		++it;
	}
}

4 结束语

项目还属于初期阶段,后期还会继续优化功能,还有一些BUG要解决,写这篇文章纯属技术分享给需要的人;由于工程内有许多项目相关性的东西,不方便全部开源,如果有什么疑问欢迎交流。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

QT之基于图形框架QGraphicsView实现链路图 的相关文章

  • Meson安装

    Meson出现的原因 xff1a C 43 43 需要一个仓库管理系统 xff0c 用于管理依赖包 类似于Java里的Maven Maven可以做什么呢 xff1f Maven是Java的项目构建工具 43 仓库管理工具 由此需求下 xff
  • 微服务和云服务的关系

    今天 xff0c 突然想到微服务和云服务 xff08 分布式 xff0c 云计算 xff09 的关系 因为 xff0c 微服务的特点是松耦合 xff0c 而这不就是云计算的基础吗 xff1f 云计算的特点是分布式和集群 xff0c 而要实现
  • 一种简单的GIS云服务提供方案

    如果说云原生的GIS服务比较困难的话 要把GIS拆成一个个微服务 那么提出一种简单的云部署方案就是有必要的了 那就是 xff0c 采用容器化技术将GIS服务器部署到N个小型电脑上 然后采用一个类似于springcloud的中间件进行接受请求
  • Idea-android-osmdroid:the project uses gradle 2.14.1 which is incompatible with java 9 or newer

    方法一 xff1a 工具使用 IDEA 2019默认使用Java11导入gradle工程问题https blog csdn net jiajane article details 103014036 方法二 xff1a 点击open gra
  • Android 使用FFmpeg拉取RTSP流 用RTMP推流到RTMP服务器

    之前写了 如何在Android中使用ffmpeg 以及如何使用ffmpeg拉取RTSP流 业务场景大概是这样 拉取RTSP流之后 解码 送给AI分析 分析完之后 在进行绘制结果 然后编码 编码完之后 进行RTMP推流 AI 解码 是别的同时
  • GeoServer扩展之REST

    https docs geoserver org latest en developer programming guide rest services index html 这个服务扩展似乎过时了 不知道是不是这样 geoserver 2
  • python pyd文件是 - mapnik.pyd

  • leaflet加载postgis发布的矢量切片数据

    之前写过使用mapbox加载矢量切片 xff1a https www cnblogs com 2008nmj p 15069842 html 那么leaflet怎么加载python 43 postgis发布的矢量切片服务呢 xff1f 矢量
  • opencv安装make时报错: 没有指明目标并且找不到makefile

    在利用安装包进行opencv安装时 xff0c 当按照指令安装好依赖 xff0c 进行下载opencv文件夹下 xff0c 建立build文件夹并进入其文件夹后 xff0c 利用CMAKE进行编译 xff0c 但是编译成功之后 xff0c
  • 在Ubuntu中安装Chrome浏览器

    Chrome 简介 Google Chrome是由Google开发的一款设计简单 高效的Web浏览工具 Google Chrome的特点是简洁 快速 GoogleChrome支持多标签浏览 xff0c 每个标签页面都在独立的 沙箱 内运行
  • STM32H747 / STM32H745 简单测试

    目录 1 简介 2 datasheet关键点介绍 2 1 PWR 3 资料说明 4 例程运行 4 1 选择CM7作为项目工程对象 xff0c 并编译下载程序 4 2 同理编译CM4项目对象 4 3 编译结果说明 参考链接 1 简介 STM3
  • NUCLEO STM32H743购买和使用说明

    摘要 STM32H743的NUCLEO板子有两种 xff0c 对应不同的PCB电路 xff0c 使用方式也有所不同 本文将对这两款评估板进行比较 xff0c 并给出参考资料和选择建议 两款板子的资料可以在ST官网上下 xff0c 分别是MB
  • 关于硬盘数据恢复的一些思考

    我平时会将数据保存在两台电脑和两个移动硬盘上 xff0c 但由于假期回家 xff0c IDE软件用起来容易崩 xff0c 于是决定重装下系统 xff0c 但发现USB启动盘找不到了 xff0c 便将移动硬盘隔分了小的个新逻辑卷 xff0c
  • Simulink中的Simscape

    Simscape是在Simulink环境下创建物理系统模型的工具和语言 8 它可以通过基于Matlab语法的Simscape语法来制作自己的物理仿真系统 如果使用Simscape中现有的基础库 xff08 Foundation Librar
  • Matlab电路仿真

    电路仿真的工具有很多 xff0c 比如专业点的Pspice 本科时学习时经常使用 但问题是 xff0c 即使电信专业以后真的从事硬件设计的也寥寥无几 而为了进行简单的仿真还要多装个软件 xff0c 我能接收 xff0c 我的老电脑也接收不了
  • RK1126 平台环境搭建以及入坑指南(不不 应该是入门指南)

    手上有个RK1126的板子 如下图 采用的是底板 43 核心板 xff0c 摄像头是OS04a10 简单做个记录 相比与海思的sdk 和example RK1126 的sdk 和example 功能更丰富一些 基本的rtsp 什么的 都已经
  • 关于JSP开发中jsp页面调用DAO返回的ResultSet为空值完美解决方案

    不多说 问题蛮简单 直接上代码 关于ResultSet为空值的原因经我查阅资料 应该是因为在JSP页面的时候conn已经被释放掉了 因此对应的resultset也过期了 所以不能用 解决方案就是重新开辟一块内存存储它 用链表 关键代码 Li
  • 关系模式的基本概念

    为了更好地存储数据 xff0c 需要将现实世界的事物及其关系进行层层抽象 xff0c 从而得到数据模型 使用关系数据模型的数据库系统是现在的主流数据库系统 数据模型是数据库的框架 xff0c 该框架描述了数据及其联系的组织方式 表达方式和存
  • 惯性器件分析—— ICM-42688-P

    2019年年底新推出的一款很赞的IMU 陀螺特性 加计特性 相关链接 官网DataSheet xff1a https invensense tdk com download pdf icm 42688 p datasheet 两家IMU对比
  • vim学习导航

    vim学习曲线陡峭 xff0c 其实和开始学习键盘打字和双拼打字的过程差不多 以前练习打字是因为小学电脑课没游戏玩 xff0c 只能玩金山打字的 警察抓小偷 xff1b 学习双拼主要动力是为了打字手手不酸 xff0c 能尽量跟上思维速度 而

随机推荐

  • word论文格式调整

    目录 注意事项 论文框架搭建 论文分块 页边距 页眉 页脚 样式 默认样式 正文 标题 参考文献 致谢 目录 图表 参考文献 公式 最后 注意事项 1 使用同一个word版本编辑 xff0c 避免格式不兼容 本文可能不适用于WPS 本文用o
  • 符号编码与乱码问题

    目标 xff1a 解释符号与编码 xff0c 分析乱码问题 xff0c 于是就能明明白白地处理大多数符号乱码问题了 符号与编码 以C 43 43 为例 xff0c 符号A的 十进制 编码为65 即 39 A 39 为65 其中 xff0c
  • PWM变模拟信号(积分电路 )

    就是简单的积分电路 频率不变 xff0c 积分后的电平相当于把高电平的电压和对应的时间的面积 xff0c 平均到一个周期里 基本上占空比是50 xff0c 转换的电压 xff0c 就是最高电压的50 xff0c 占空比30 xff0c 模拟
  • 如何生成汇编代码文件

    61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
  • Ardupilot SITL——arducopter 操作步骤

    打开cygwin输入 cd ardupilot ArduCopter Tools autotest sim vehicle py map console xff08 默认master下版本arducopter xff0c 默认模拟 四轴 x
  • 3-catkin包介绍与构建

    本教程简单介绍ROS1的catkin包 至于为什么选择deepin而不是ROS通用的ubuntu 也仅仅是为了支持国产系统 鉴于本人水平有限 xff0c 如哪位攻城狮网友发现本文存在的问题 xff0c 烦请留言指正 xff0c 谢谢 cat
  • make与cmake入门

    文章目录 1 手动链接与编译2 make编译工具2 1 介绍makefile2 2 makefile三要素2 3 make工作原理2 4 实战案例1案例2案例3案例4 2 5 常见的自动化变量解析 3 使用cmake进行编译3 1 介绍cm
  • RK1126平台项目总结

    项目的大概流程是 从摄像头读数据然后经过ai分析 输出ai分析结果编码成2路venc的流 然后 起一个rtsp服务器 供后续模块 处理 但是从需求来看的话其实很简单 但是实际上做的时候还是会遇到一些坑的 程序起来之后会起一个http服务 等
  • Keil uVision5开发步骤备忘

    1 安装 2 授权 xff1a File gt License Management xff0c AddLIC 3 参照开发手册 xff0c 配置keil环境 xff1a 1 添加ET199模拟器 xff0c 复制SDK里的ET199Sim
  • 使用杉川3i-T1单线激光雷达和Cartographer库SLAM问题及解决

    用Cartographer做二维的激光SLAM xff0c 用杉川给的ROS例子发布LaserScan数据 xff0c 发现在Rviz中显示的数据 xff0c 本来应该是平直的墙变成弧形的 xff0c 建图也是混乱的 xff0c 如下图 x
  • TI毫米波雷达 MIMO (2TX4RX)设置

    我们知道xWR1243和xWR1443 EVM是3TX4RX雷达 xff0c xWR1642 EVM是2TX4RX雷达 xff0c 我们不仅要掌握1TX4RX模式的使用还要学会使用MIMO雷达模式 本文主要介绍如何在mmWave Studi
  • 以Apollo为例学习/分析自动驾驶运动规划算法

    这篇文章写得很粗糙 xff0c 作为我入门学习的笔记 xff0c 其中的思路 分析很可能不正确 xff0c 也希望有在工业界工作的朋友能给我提出一些意见建议 这将是一篇大杂烩 xff0c 也是我一直在学习的主线 想要一下子整理清楚还是很困难
  • 二次规划(QP)与OSQP求解器

    目录 二次规划 xff08 QP xff09 OSQP 求解器 OSQP eigen接口 二次规划 xff08 QP xff09 优化在很多领域都发挥着重要应用 xff0c 其中自动驾驶的运动规划可以看做一个优化问题 xff0c 根据实际情
  • Jetson TX2 入门 ——介绍

    暑假留校 xff0c 老师给我们拿了两块开发板 xff0c 一个是英伟达的Jetson TX2 xff0c 一个是up squared xff0c 让我们先熟悉开发板 xff0c 为明年的比赛做准备 这两个板子是前几届学长做比赛用过的 自己
  • 2.1.2 激光雷达

    更多内容 xff0c 请关注 xff1a github xff1a Autopilot Updating Notes gitee Autopilot Updating Notes 激光雷达是自动驾驶领域非常依赖的传感器 xff0c 越来越多
  • 2.1.5 GPS定位导航

    更多内容 xff0c 请关注 xff1a github xff1a Autopilot Updating Notes gitee Autopilot Updating Notes GPS是Global Positioning System
  • ROS2 + Qt5 cmake的CMakeLists.txt文件配置

    ROS2 QT实现学习笔记 1 1 功能包的创建和编译 ROS2 Foxy 43 Qt5 on Linux Platform 按上面两个文章配置后的目录结构 build CMakeLists txt include mainwindow h
  • 计算思维:二进制串的校验

    题目 xff1a 待传输的二进制串为 1001111 xff0c 若采用偶校验 xff0c 需增加几位校验位才能判断出哪一位传输错误 xff0c 若传输过去变为 1011111 xff0c 则如何判断出是哪一位出错 xff1f 请描述判断过
  • RK1126实现画中画功能 picture in picture for RK 1126

    项目中需要将两个摄像头的流 合并成一个流 主摄像头显示大画面 副摄像头 显示在右上角 实现类似画中画的功能 摸索了下 需要将 从摄像头中取到的 yuv数据进行处理即可 rga模块提供了关于图像处理的一些接口 使用improcess实现图像的
  • QT之基于图形框架QGraphicsView实现链路图

    1 前言 最近因项目需求 xff0c 需要制作一个可以绘制树结构的 事件链 插件 xff0c 于是呼找到了QT自带的一个画流程图的例子 diagramscene xff0c 还在网上找到了另外一个例子 然后我结合了两个demo实现了我的 事