Как я могу сделать QList<QVector3D> уникальным
У меня есть QList
состоит из QVector3D
, QVector3D
представляет вершину или точку. Этот список содержит также все вершины STL-File
, Проблема в том, что вершины существуют несколько раз в списке. Нужен список уникальных вершин STL-файла. Как я могу реализовать это с Qt 5.0.2
?
3 ответа
QSet использует хеш-функцию для обеспечения уникальности значения (QMap использует operator<). В Qt нет реализации qHash для QVector3D. Вы можете реализовать свой собственный, например, как в примере:
//place anywhere in Qt-code
#include <QSet>
#include <QVector3D>
#include <QList>
uint qHash(const QVector3D &v)
{
return qHash( QString( "%1x%2x%3" ).arg(v.x()).arg(v.y()).arg(v.z()) ) ;
}
int foo()
{
QList<QVector3D> uvector3D_1;
QSet<QVector3D> uvector3D_2;
uvector3D_2 = QSet<QVector3D>::fromList(uvector3D_1);
return 0;
}
static int testFoo = foo();
Конечно, он не самый быстрый, он полагается на функцию QHash для QString. Но я думаю, что это хорошо для демонстрации.
QList<QVector3D> originalVector = ...;
тогда либо:
QSet<QVector3D> noDublicatesSet = QSet<QVector3D>::fromList(originalVector);
или же
QSet<QVector3D> noDublicatesSet = originalVector.toSet();
также вы можете добавить что-то вроде, если вам нужен QList обратно..
QList<QVector3D> destinationVector = QList<QVector3D>::fromSet(noDublicatesSet);
вам также понадобятся эти вещи (извините, они есть в моем коде целую вечность.. забыл, что они внешние).. вы можете изменить хеш-функцию:
#define ROTL10(x) (((x) << 10) | (((x) >> 22) & 0x000000ff))
#define ROTL20(x) (((x) << 20) | (((x) >> 12) & 0x0000ffff))
uint qHash(double data)
{
union U {
quint64 n;
double f;
};
U u;
u.f = data;
return u.f;
}
inline uint qHash(const QVector3D &v, uint seed)
{
return qHash(v.x()) ^ ROTL10(qHash(v.y())) ^ ROTL20(qHash(v.z()));
}
PS это код для Qt 5.0, фактически для добавления отсутствующих qHash() для векторов, поэтому по умолчанию они не помещаются в QSet/QHash
Начиная с Qt
5.14
, вы можете использовать новый конструктор :
template <typename InputIterator> QSet::QSet(InputIterator first, InputIterator last
Вот пример, взятый из документации :
// For example, if you have code like
QStringList list;
QSet<QString> set = QSet<QString>::fromList(list);
// you can rewrite it as
QStringList list;
QSet<QString> set(list.begin(), list.end());