Как я могу сделать 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());
Другие вопросы по тегам