【Robotics Library】rlPlanDemo

官方网站:https://www.roboticslibrary.org/
参考指南:https://www.roboticslibrary.org/tutorials/

rlPlanDemo文件夹

1、ConfigurationDelegate.cpp

//
// Copyright (c) 2009, Markus Rickert
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
//   this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//

#include <QDoubleSpinBox>
#include <QModelIndex>

#include "ConfigurationDelegate.h"
#include "MainWindow.h"

ConfigurationDelegate::ConfigurationDelegate(QObject* parent) :
	QItemDelegate(parent)
{
}

ConfigurationDelegate::~ConfigurationDelegate()
{
}

QWidget*
ConfigurationDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
	QDoubleSpinBox* editor = new QDoubleSpinBox(parent);
	
	rl::math::Vector maximum = MainWindow::instance()->model->getMaximum();
	rl::math::Vector minimum = MainWindow::instance()->model->getMinimum();
	Eigen::Matrix<rl::math::Unit, Eigen::Dynamic, 1> qUnits = MainWindow::instance()->model->getPositionUnits();
	
	if (rl::math::UNIT_RADIAN == qUnits(index.row()))
	{
		editor->setDecimals(2);
		editor->setMinimum(minimum(index.row()) * rl::math::RAD2DEG);
		editor->setMaximum(maximum(index.row()) * rl::math::RAD2DEG);
		editor->setSingleStep(1.0f);
	}
	else
	{
		editor->setDecimals(4);
		editor->setMinimum(minimum(index.row()));
		editor->setMaximum(maximum(index.row()));
		editor->setSingleStep(0.01f);
	}
	
	QObject::connect(editor, SIGNAL(valueChanged(double)), this, SLOT(valueChanged(double)));
	
	return editor;
}

void
ConfigurationDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
{
	QDoubleSpinBox* doubleSpinBox = static_cast<QDoubleSpinBox*>(editor);
	doubleSpinBox->setValue(index.model()->data(index, Qt::EditRole).toDouble());
}

void
ConfigurationDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const
{
	QDoubleSpinBox* doubleSpinBox = static_cast<QDoubleSpinBox*>(editor);
	doubleSpinBox->interpretText();
	model->setData(index, doubleSpinBox->value(), Qt::EditRole);
}

void
ConfigurationDelegate::updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
	editor->setGeometry(option.rect);
}	

void
ConfigurationDelegate::valueChanged(double d)
{
	emit commitData(static_cast<QWidget*>(QObject::sender()));
}

头文件

系统头文件

include<> : 编译器直接从系统类库目录里查找头文件

  1. QDoubleSpinBox 浮点计数器控件
  2. QModelIndex 模型索引
    建立起Data中数据的索引与View中数据的索引的映射关系。QModelIndex详解参考
自定义头文件

include “” : 默认从项目当前目录查找头文件,所谓项目当前目录,就是项目工程文件(*.vcxproj) 所在的目录

  1. ConfigurationDelegate.h
    委托是Qt中的一种机制,委托提供了一种方便的方法来定制特定类型的数据的显示和编辑。委托可以用来定制Qt中各种视图组件中特定类型的数据的显示和编辑,使得开发人员能够更好地控制数据的外观和行为。使用委托可以使代码更具可重用性和灵活性。
    Qt中的委托资料参考
  2. MainWindow.h

C++

C++中双冒号::
  • 类作用域
  • 命名空间作用域
  • 全局作用域
C++中函数前~

取反的意思——析构函数
析构函数与构造函数相反
当对象脱离其作用域时(例如对象所在的函数已调用完毕),系统自动执行析构函数。
C++语言:析构函数名也应与类名相同,只是在函数名前面加一个位取反符~,以区别于构造函数。它不能带任何参数,也没有返回值(包括void类型)。只能有一个析构函数,不能重载。如果用户没有编写析构函数,编译系统会自动生成一个缺省的析构函数,它也不进行任何操作。所以许多简单的类中没有用显示的析构函数。

类和对象

QObject *parent、QWidget *parent

QObject *parent/QWidget *parent,当指定了parent后,Qt就会介入,在合适的时候调用对应的delete操作
Qt析构机制参考

QItemDelegate

Qt使用model/view 模式,一般来讲, model是数据,view把数据展示给用户,数据与界面的交互则通过delegagte来执行。
QItemDelegate类为模型中的数据项提供了显示和编辑的工具,从中派生创建自定义委托代理类。

函数

自定义委托函数
  • createEditor函数:创建委托控件。可编辑输入
  • setEditorData 函数:设置控件数据
    QDoubleSpinBox:浮点计数器控件,接收输入的浮点数值
    QDoubleSpinBox常用方法
  • setModelData 函数:用户完成输入后,将数据储存到模型中
    获取编辑的内容-设置到模型数据
  • updateEditorGeometry函数:调整编辑器的位置和大小
    更新控件位置大小
  • valueChanged函数:当前值发生了改变,发射该信号
保存到
设置到
setModelData
setEditorData
setModuleData
Index
value
编辑器
模型
rl API(应用程序接口)

机器人库:

主要机器人领域的所有重要算法,包括运动学、动力学、轨迹生成和路径规划,都是可用的,并使用相同的符号和接口。

rl::math::Vector 正向运动学

2、ConfigurationModel.cpp

//
// Copyright (c) 2009, Markus Rickert
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
//   this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//

#include "ConfigurationModel.h"
#include "MainWindow.h"
#include "Thread.h"
#include "Viewer.h"

ConfigurationModel::ConfigurationModel(QObject* parent) :
	QAbstractTableModel(parent)
{
}

ConfigurationModel::~ConfigurationModel()
{
}

int
ConfigurationModel::columnCount(const QModelIndex& parent) const
{
	return 1;
}

QVariant
ConfigurationModel::data(const QModelIndex& index, int role) const
{
	if (nullptr == MainWindow::instance()->model)
	{
		return QVariant();
	}
	
	if (!index.isValid())
	{
		return QVariant();
	}
	
	switch (role)
	{
	case Qt::DisplayRole:
	case Qt::EditRole:
		{
			Eigen::Matrix<rl::math::Unit, Eigen::Dynamic, 1> qUnits = MainWindow::instance()->model->getPositionUnits();
			
			if (rl::math::UNIT_RADIAN == qUnits(index.row()))
			{
				return (*MainWindow::instance()->q)(index.row()) * rl::math::RAD2DEG;
			}
			else
			{
				return (*MainWindow::instance()->q)(index.row());
			}
		}
	case Qt::TextAlignmentRole:
		return QVariant(Qt::AlignRight | Qt::AlignVCenter);
		break;
	default:
		break;
	}
	
	return QVariant();
}

Qt::ItemFlags
ConfigurationModel::flags(const QModelIndex &index) const
{
	if (!index.isValid())
	{
		return Qt::NoItemFlags;
	}
	
	return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
}

QVariant
ConfigurationModel::headerData(int section, Qt::Orientation orientation, int role) const
{
	if (Qt::DisplayRole == role && Qt::Vertical == orientation)
	{
		return QString::number(section);
	}
	
	return QVariant();
}

void
ConfigurationModel::invalidate()
{
	this->beginResetModel();
	this->endResetModel();
}

int
ConfigurationModel::rowCount(const QModelIndex& parent) const
{
	if (nullptr == MainWindow::instance()->model)
	{
		return 0;
	}
	
	return MainWindow::instance()->model->getDofPosition();
}

bool
ConfigurationModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
	if (nullptr == MainWindow::instance()->model)
	{
		return false;
	}
	
	if (MainWindow::instance()->thread->isRunning())
	{
		return false;
	}
	
	if (index.isValid() && Qt::EditRole == role)
	{
		Eigen::Matrix<rl::math::Unit, Eigen::Dynamic, 1> qUnits = MainWindow::instance()->model->getPositionUnits();
		
		if (rl::math::UNIT_RADIAN == qUnits(index.row()))
		{
			(*MainWindow::instance()->q)(index.row()) = value.value<rl::math::Real>() * rl::math::DEG2RAD;
		}
		else
		{
			(*MainWindow::instance()->q)(index.row()) = value.value<rl::math::Real>();
		}
		
		MainWindow::instance()->viewer->drawConfiguration(*MainWindow::instance()->q);
		
		emit dataChanged(index, index);
		
		return true;
	}
	
	return false;
}

Model/View结构原理

Model/View结构原理参考1
Model/View结构原理参考2
Model/View基本原理
实际数据Data与界面组件View之间通过Model通信,Model为视图组件提供数据接口——从原始数据Data中提取需要的部分在视图组件中显示和编辑。
Delegate委托代理功能使得用户可以编辑内容和定制界面。

Model/View框架

Model类:定义了模型访问接口。负责访问数据集中的数据项;

Delegate类:负责视图中每个数据项的绘制与编辑;

View类:负责绘制总体外观并处理用户的交互命令。
QAbstractTableModel

三种模型QAbstractTableModel接口需要被继承后实现相关的函数后使用,将数据用二维表格显示:

提供数据模型接口
QAbstractTableModel
QTaleView

C++

nullptr

指针空值

函数

三大接口
  • int columnCount 表格列数
  • int rowCount 表格行数
  • QVariant data 根据模型索引当前数据 【最主要的】
columnCount()

获取列数:直接返回1。

注:固定的数据列表,而非动态加载的,需要调用 insertRows()、removeRows()、insertColumns() 和 removeColumns() 实现视图大小的调整。

data()

获取单元格数据。
两个参数:
1.QModelIndex 模型索引 :模型检索或修改数据,唯一确定一个数据项
2. role 角色
主要角色此处包含

  • DisplayRole 显示
  • EditRole 编辑
  • TextAlignmentRole 对齐方式(右对齐/中心对齐)

用switch变换角色,然后返回任意类型的数据。

flag()

此处flag()函数只需要表达可编辑:单元格支持编辑操作,返回编辑后的数据。

headerData()

获取表头信息:

  • Section 位置(行/列数)
  • Orientation 方向(水平/垂直)
  • Role

此处返回列表头信息。

invalidate()

刷新view:修改view的显示后调用invalidate()函数才能重新看到绘制的界面。
必须在UI线程中工作。

rowCount()

此处返回实际的行数。

setData()

可编辑的模型必须重写setData()函数。
dataChanged()信号

3、ConfigurationSpaceModel.cpp

向量空间模型

//
// Copyright (c) 2009, Markus Rickert
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
//   this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
//   this list of conditions and the following disclaimer in the documentation
//   and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//

#include "ConfigurationSpaceModel.h"
#include "ConfigurationSpaceScene.h"
#include "MainWindow.h"
#include "Thread.h"
#include "Viewer.h"

ConfigurationSpaceModel::ConfigurationSpaceModel(QObject* parent) :
	QAbstractTableModel(parent),
	configurationSpaceScene(nullptr)
{
}

ConfigurationSpaceModel::~ConfigurationSpaceModel()
{
}

int
ConfigurationSpaceModel::columnCount(const QModelIndex& parent) const
{
	return 1;
}

QVariant
ConfigurationSpaceModel::data(const QModelIndex& index, int role) const
{
	if (nullptr == this->configurationSpaceScene)
	{
		return QVariant();
	}
	
	if (nullptr == this->configurationSpaceScene->model)
	{
		return QVariant();
	}
	
	if (!index.isValid())
	{
		return QVariant();
	}
	
	switch (role)
	{
	case Qt::DisplayRole:
	case Qt::EditRole:
		switch (index.row())
		{
		case 0:
			return static_cast<unsigned int>(this->configurationSpaceScene->axis0);
			break;
		case 1:
			return static_cast<unsigned int>(this->configurationSpaceScene->axis1);
			break;
		case 2:
			return this->configurationSpaceScene->delta0;
			break;
		case 3:
			return this->configurationSpaceScene->delta1;
			break;
		default:
			break;
		}
		
		break;
	case Qt::TextAlignmentRole:
		return QVariant(Qt::AlignRight | Qt::AlignVCenter);
		break;
	default:
		break;
	}
	
	return QVariant();
}

Qt::ItemFlags
ConfigurationSpaceModel::flags(const QModelIndex &index) const
{
	if (!index.isValid())
	{
		return Qt::NoItemFlags;
	}
	
	return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
}

QVariant
ConfigurationSpaceModel::headerData(int section, Qt::Orientation orientation, int role) const
{
	if (nullptr == this->configurationSpaceScene)
	{
		return QVariant();
	}
	
	if (nullptr == this->configurationSpaceScene->model)
	{
		return QVariant();
	}
	
	if (Qt::DisplayRole == role && Qt::Vertical == orientation)
	{
		switch (section)
		{
		case 0:
			return "axis0";
			break;
		case 1:
			return "axis1";
			break;
		case 2:
			return "delta0";
			break;
		case 3:
			return "delta1";
			break;
		default:
			break;
		}
	}
	
	return QVariant();
}

void
ConfigurationSpaceModel::invalidate()
{
	this->beginResetModel();
	this->endResetModel();
}

int
ConfigurationSpaceModel::rowCount(const QModelIndex& parent) const
{
	if (nullptr == this->configurationSpaceScene)
	{
		return 0;
	}
	
	
	if (nullptr == this->configurationSpaceScene->model)
	{
		return 0;
	}
	return 4;
}

bool
ConfigurationSpaceModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
	if (nullptr == this->configurationSpaceScene)
	{
		return false;
	}
	
	if (nullptr == this->configurationSpaceScene->model)
	{
		return false;
	}
	
	if (MainWindow::instance()->thread->isRunning())
	{
		return false;
	}
	
	if (index.isValid() && Qt::EditRole == role)
	{
		switch (index.row())
		{
		case 0:
			if (value.value<std::size_t>() < this->configurationSpaceScene->model->getDofPosition())
			{
				this->configurationSpaceScene->axis0 = value.value<std::size_t>();
			}
			else
			{
				return false;
			}
			break;
		case 1:
			if (value.value<std::size_t>() < this->configurationSpaceScene->model->getDofPosition())
			{
				this->configurationSpaceScene->axis1 = value.value<std::size_t>();
			}
			else
			{
				return false;
			}
			break;
		case 2:
			if (value.value<rl::math::Real>() > 0)
			{
				this->configurationSpaceScene->delta0 = value.value<rl::math::Real>();
			}
			else
			{
				return false;
			}
			break;
		case 3:
			if (value.value<rl::math::Real>() > 0)
			{
				this->configurationSpaceScene->delta1 = value.value<rl::math::Real>();
			}
			else
			{
				return false;
			}
			break;
		default:
			break;
		}
		
		this->configurationSpaceScene->init();
		
		emit dataChanged(index, index);
		
		return true;
	}
	
	return false;
}

C++

static_cast

static_cast为强制类型转换,具体形式为:

staic_cast<new_type>(expresstion)

注:static_cast不能将const类型进行转化(const_cast可以)

axis

方向:
axis=0时,表示纵轴,方向从上到下;
axis=1时,表示横轴,方向从左到右。

delta

δ函数也可以理解为(任意阶可微)函数序列的极限。

函数

columnCount()

返回1列

data()

可编辑数据时,根据这4行表头信息进行检索

flags()

单元格可编辑

headerData()

section标识第几行或者第几列,此处自定义表头:
在四行的表头分别返回"axis0"、“axis1”、“delta0”、“delta1”

invalidate()

刷新view,线程中进行

rowCount()

4行

setData()

根据实际的真实输入数据确定

4、ConfigurationDelegate.h

#ifndef CONFIGURATIONDELEGATE_H
#define CONFIGURATIONDELEGATE_H

#include <QItemDelegate>

class ConfigurationDelegate : public QItemDelegate
{
	Q_OBJECT
	
public:
	ConfigurationDelegate(QObject* parent = nullptr);
	
	virtual ~ConfigurationDelegate();
	
	QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const;
	
	void setEditorData(QWidget* editor, const QModelIndex& index) const;
	
	void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const;
	
	void updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const;	
	
public slots:
	void valueChanged(double d);
	
protected:
	
private:
	
};

#endif // CONFIGURATIONDELEGATE_H

宏定义

#ifndef XX_H
#define XX_H

#endif

宏定义的作用
多个文件都包含同一个头文件时,容易造成编译混乱,加上ifndef/define/endif,就可以防止这种重定义错误。

虚析构函数 virtual ~

虚析构函数有无的输出区别
类的析构函数:释放内存资源
virtual的析构函数:实现多态,释放子类空间
当一个类被用作基类,把析构函数写成虚函数。

自定义委托函数

自定义委托函数同上。

5、 ConfigurationModel.h

#ifndef CONFIGURATIONMODEL_H
#define CONFIGURATIONMODEL_H

#include <QAbstractTableModel>

class ConfigurationModel : public QAbstractTableModel
{
public:
	ConfigurationModel(QObject* parent = nullptr);
	
	virtual ~ConfigurationModel();
	
	int columnCount(const QModelIndex& parent = QModelIndex()) const;
	
	QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
	
	Qt::ItemFlags flags(const QModelIndex &index) const;
	
	QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
	
	void invalidate();
	
	int rowCount(const QModelIndex& parent = QModelIndex()) const;
	
	bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole); 
	
protected:
	
private:
	
};

#endif // CONFIGURATIONMODEL_H

定义函数类型,函数含义见上一篇,ConfigurationSpaceModel.h同

从此处开始,先阅读.h文件,再贯穿.cpp文件,顺序改变

6、 ConfigurationSpaceScene.h

#ifndef CONFIGURATIONSPACESCENE_H
#define CONFIGURATIONSPACESCENE_H

#include <QGraphicsLineItem>
#include <QGraphicsScene>
#include <QLinkedList>
#include <rl/plan/Model.h>
#include <rl/plan/Viewer.h>

class ConfigurationSpaceThread;

class ConfigurationSpaceScene : public QGraphicsScene, public rl::plan::Viewer
{
	Q_OBJECT
	
public:
	ConfigurationSpaceScene(QObject* parent = nullptr);
	
	virtual ~ConfigurationSpaceScene();
	
	std::size_t axis0;
	
	std::size_t axis1;
	
	rl::math::Real delta0;
	
	rl::math::Real delta1;
	
	rl::plan::Model* model;
	
public slots:
	void addCollision(const qreal& x, const qreal& y, const qreal& w, const qreal& h, const int& rgb);
	
	void clear();
	
	void drawConfiguration(const rl::math::Vector& q);
	
	void drawConfigurationEdge(const rl::math::Vector& u, const rl::math::Vector& v, const bool& free = true);
	
	void drawConfigurationPath(const rl::plan::VectorList& path);
	
	void drawConfigurationVertex(const rl::math::Vector& q, const bool& free = true);
	
	void drawLine(const rl::math::Vector& xyz0, const rl::math::Vector& xyz1);
	
	void drawPoint(const rl::math::Vector& xyz);
	
	void drawSphere(const rl::math::Vector& center, const rl::math::Real& radius);
	
	void drawSweptVolume(const rl::plan::VectorList& path);
	
	void drawWork(const rl::math::Transform& t);
	
	void drawWorkEdge(const rl::math::Vector& u, const rl::math::Vector& v);
	
	void drawWorkPath(const rl::plan::VectorList& path);
	
	void drawWorkVertex(const rl::math::Vector& q);
	
	void eval();
	
	void init();
	
	void reset();
	
	void resetEdges();
	
	void resetLines();
	
	void resetPath();
	
	void resetPoints();
	
	void resetSpheres();
	
	void resetVertices();
	
	void showMessage(const std::string& message);
	
protected:
	void mouseMoveEvent(QGraphicsSceneMouseEvent* mouseEvent);
	
	void mousePressEvent(QGraphicsSceneMouseEvent* mouseEvent);
	
private:
	QLinkedList<QGraphicsLineItem*> edges;
	
	QLinkedList<QGraphicsLineItem*> path;

	QGraphicsRectItem* scene;
	
	ConfigurationSpaceThread* thread;
	
signals:
	void evalFinished();
};

#endif // CONFIGURATIONSPACESCENE_H

Include

QGraphicsLineItem

QGranphicsItem

QGraphicsScene

管理QGraphicsItem的容器

QGraphicsScene继承自QObject,而不是QWidget,因此本身不可见

QLinkedList

基于迭代器访问的数据链表

QVector、Qlist、QlinkedList 类:用法比较
QlinkedList使用迭代器访问,而不是索引:
如果需要一个真实的链表,保证在列表中间插入常量时间,并将迭代器设置为项而不是索引,请使用QLinkedList.

C++

size_t

size_t 基本的与机器相关的无符号整数的C/C + +类型

7、 ConfigurationSpaceScene.cpp

Include

QGraphicsRectItem

QGraphicsRectItem

QGraphicsSceneMouseEvent

QGraphicsSceneMouseEvent 鼠标移动

函数

addCollision()

单独地向刚体添加碰撞对象,可以使用addCollision函数。

8、 ConfigurationSpaceThread.h

#ifndef CONFIGURATIONSPACETHREAD_H
#define CONFIGURATIONSPACETHREAD_H

#include <QThread>
#include <rl/plan/Model.h>

class ConfigurationSpaceThread : public QThread
{
	Q_OBJECT
	
public:
	ConfigurationSpaceThread(QObject* parent = nullptr);
	
	virtual ~ConfigurationSpaceThread();
	
	void run();
	
	void stop();
	
	std::size_t axis0;
	
	std::size_t axis1;
	
	rl::math::Real delta0;
	
	rl::math::Real delta1;
	
	rl::plan::Model* model;
	
protected:
	
private:
	bool running;
	
signals:
	void addCollision(const qreal& x, const qreal& y, const qreal& w, const qreal& h, const int& rgb);
};

#endif // CONFIGURATIONSPACETHREAD_H

Include

QThread

QThread 线程

9、 ConfigurationSpaceThread.cpp

#include <QMutexLocker>
#include <rl/plan/SimpleModel.h>

#include "ConfigurationSpaceThread.h"
#include "MainWindow.h"

ConfigurationSpaceThread::ConfigurationSpaceThread(QObject* parent) :
	QThread(parent),
	axis0(0),
	axis1(1),
	delta0(1.0f),
	delta1(1.0f),
	model(nullptr),
	running(false)
{
}

ConfigurationSpaceThread::~ConfigurationSpaceThread()
{
}

void
ConfigurationSpaceThread::run()
{
	QMutexLocker lock(&MainWindow::instance()->mutex);
	
	this->running = true;
	
	if (rl::plan::SimpleModel* model = dynamic_cast<rl::plan::SimpleModel*>(this->model))
	{
		rl::math::Vector maximum = model->getMaximum();
		rl::math::Vector minimum = model->getMinimum();
		
		rl::math::Real range0 = std::abs(maximum(this->axis0) - minimum(this->axis0));
		rl::math::Real range1 = std::abs(maximum(this->axis1) - minimum(this->axis1));
		
		rl::math::Real delta0 = range0 / std::ceil(range0 / this->delta0);
		rl::math::Real delta1 = range1 / std::ceil(range1 / this->delta1);
		
		std::size_t steps0 = static_cast<std::size_t>(std::ceil(range0 / delta0));
		std::size_t steps1 = static_cast<std::size_t>(std::ceil(range1 / delta1));
		
		rl::math::Vector q(*MainWindow::instance()->q);
		
		for (std::size_t i = 0; i < steps1 + 1 && this->running; ++i)
		{
			q(this->axis1) = maximum(this->axis1) - i * delta1;
			
			for (std::size_t j = 0; j < steps0 + 1 && this->running; ++j)
			{
				q(this->axis0) = minimum(this->axis0) + j * delta0;
				
				model->setPosition(q);
				model->updateFrames();
				
				if (model->isColliding())
				{
					emit addCollision(
						q(this->axis0),
						q(this->axis1),
						delta0,
						delta1,
						0
					);
				}
			}
		}
	}
	
	this->running = false;
}

void
ConfigurationSpaceThread::stop()
{
	if (this->running)
	{
		this->running = false;
		
		while (!this->isFinished())
		{
			QThread::usleep(0);
		}
	}
}

Include

QMuteLocker

QMutexLocker 互斥锁解锁

QMutexLocker创建时将传入的QMutex锁定,释放时将传入的QMutex解锁。

函数

run()

run()函数中实现线程任务.

10、 GraphicsView.h

#ifndef GRAPHICSVIEW_H
#define GRAPHICSVIEW_H

#include <QGraphicsView>
#include <QModelIndex>

class GraphicsView : public QGraphicsView
{
	Q_OBJECT
	
public:
	GraphicsView(QWidget* parent = nullptr);
	
	virtual ~GraphicsView();
	
public slots:
	void adjust();
	
	void adjust(const QModelIndex&, const QModelIndex&);
	
protected:
	virtual void resizeEvent(QResizeEvent* event);
	
private:
	
};

#endif // GRAPHICSVIEW_H

Include

QGraphicsView

QGraphicsView 视图窗口部件

将鼠标和按键事件场景化-使场景内容可视化

函数

槽函数

slots 槽函数

C++成员函数,很多的信号与之相关联,关联信号被发射时,槽就会被调用。

信号和槽是Qt特有的信息传输机制,让互不干扰的对象形成联系。

resizeEvent()

resizeEvent() 窗口大小、位置及其大小改变

adjust()

adjust() 自动识别调整

直接使用adjust()函数,进行界面的实时调整。

11、 GraphicsView.cpp

#include "GraphicsView.h"

GraphicsView::GraphicsView(QWidget* parent) :
	QGraphicsView(parent)
{
}

GraphicsView::~GraphicsView()
{
}

void
GraphicsView::adjust()
{
	this->fitInView(this->scene()->sceneRect(), Qt::KeepAspectRatio);
}

void
GraphicsView::adjust(const QModelIndex&, const QModelIndex&)
{
	this->adjust();
}

void
GraphicsView::resizeEvent(QResizeEvent* event)
{
	this->adjust();
}

函数

fitInView()

fitInView 适中view显示

视图中显示的内容较多时,出现横或竖的滚动条时,需要将视图中的元素适中显示时(即让滚动条因内容自动消失),通过计算出一个rect,调用fitInView函数即可。

12、 SoGradientBackground.h

#ifndef SOGRADIENTBACKGROUND_H
#define SOGRADIENTBACKGROUND_H

#include <Inventor/fields/SoSFColor.h>
#include <Inventor/nodes/SoNode.h>

class SoGradientBackground : public SoNode
{
	SO_NODE_HEADER(SoGradientBackground);
	
public:
	SoGradientBackground();
	
	virtual SbBool affectsState() const;
	
	static void exitClass();
	
	virtual void GLRender(SoGLRenderAction* action);
	
	static void initClass();
	
	SoSFColor color0;
	
	SoSFColor color1;
	
protected:
	virtual ~SoGradientBackground();
	
private:
	
};

#endif // SOGRADIENTBACKGROUND_H

13、 SoGradientBackground.h

#ifdef WIN32
#include <windows.h>
#endif // WIN32

#ifdef __APPLE__
#include <OpenGL/gl.h>
#else // __APPLE__
#include <GL/gl.h>
#endif // __APPLE__

#include <Inventor/nodes/SoSubNode.h>

#include "SoGradientBackground.h"

SO_NODE_SOURCE(SoGradientBackground);

SoGradientBackground::SoGradientBackground() :
	SoNode(),
	color0(),
	color1()
{
	SO_NODE_CONSTRUCTOR(SoGradientBackground);
	
	SO_NODE_ADD_FIELD(color0, (1.0f, 1.0f, 1.0f));
	SO_NODE_ADD_FIELD(color1, (0.0f, 0.0f, 0.0f));
}

SoGradientBackground::~SoGradientBackground()
{
}

SbBool
SoGradientBackground::affectsState() const
{
	return false;
}

void
SoGradientBackground::exitClass()
{
}

void
SoGradientBackground::GLRender(SoGLRenderAction* action)
{
	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();
	glOrtho(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);
	glMatrixMode(GL_MODELVIEW);
	glPushMatrix();
	glLoadIdentity();
	
	glPushAttrib(GL_ENABLE_BIT);
	glDisable(GL_DEPTH_TEST);
	glDisable(GL_LIGHTING);
	glDisable(GL_TEXTURE_2D);
	
	glBegin(GL_QUADS);
	
	glColor3f(this->color0.getValue()[0], this->color0.getValue()[1], this->color0.getValue()[2]);
	glVertex2f(1.0, 1.0);
	glVertex2f(-1.0, 1.0);
	
	glColor3f(this->color1.getValue()[0], this->color1.getValue()[1], this->color1.getValue()[2]);
	glVertex2f(-1.0, -1.0);
	glVertex2f(1.0, -1.0);
	
	glEnd();
	
	glPopAttrib();
	
	glPopMatrix();
	glMatrixMode(GL_PROJECTION);
	glPopMatrix();
	glMatrixMode(GL_MODELVIEW);
}

void
SoGradientBackground::initClass()
{
	SO_NODE_INIT_CLASS(SoGradientBackground, SoNode, "Node");
}

SoQt

引用使用了SoQt

API

参考http://doc.roboticslibrary.org/0.7.0/index.html

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值