How can i make a QList<QVector3D> unique
Asked Answered
R

3

5

I have a QList consist of QVector3D. A QVector3D represents a vertex or a point. This List holds also all vertices of a STL-File. The problem is that a vertex exist multiple times in the list. In need a list of the unique vertices of a STL-File. How can i implement it with Qt 5.0.2?

River answered 13/8, 2013 at 8:20 Comment(0)
M
6

QSet uses a hash-function for ensuring the uniqueness of the value (QMap uses operator <) There is no qHash implementation for QVector3D in Qt. You could implement your own one e.g. as in example:

//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();

Of cause it is not the fastest one, it relies on Qt's function qHash for QString. But I think it's good for demonstration.

Monogamous answered 13/8, 2013 at 9:46 Comment(2)
Thanks. It dose work fine. And it is fast enough for my first solution.River
I find, a selected answer with score 0 looks somehow incomplete. :-)Monogamous
B
1
QList<QVector3D> originalVector = ...;

then either:

QSet<QVector3D> noDublicatesSet = QSet<QVector3D>::fromList(originalVector);

or

QSet<QVector3D> noDublicatesSet = originalVector.toSet();

also you can add something like if you need QList back..

QList<QVector3D> destinationVector = QList<QVector3D>::fromSet(noDublicatesSet);

you also will need those things (sorry has them in my code for ages.. forgot that they are external).. you might want to change hash function:

#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()));
}

P.S. that's a code for Qt 5.0, actually to add missing qHash() for vectors, that's why they dont fit in QSet/QHash by default

Berners answered 13/8, 2013 at 8:29 Comment(7)
It does not work. I tried exactly this way before. But at this codeline QSet<QVector3D> noDublicatesSet = QSet::fromList(originalVector); i got the error that a overloaded argument list is required. I think an QSet can not handle QVector3D.River
+1: Interesting! Is it somewhere in Qt code? I suspect the macros would return 0 for many values.Monogamous
Thank you. Its sounds maybe stupid, but at wich place must i implement the snipped for changing the hashfunction?River
@Valentin Heinitz: honestly I dont remember where I took them ages ago.. I dont really in a subject of Qt 3D but that time they did a job and I keep this code in some 'convinience' libraryBerners
@Shulle: inline uint qHash(const QVector3D &v, uint seed)Berners
This doesn't always work. If you can use C++11 or later, there is hope. I can't use any of the syntax above to convert a member of QStringList to QSet. I ended up using auto uniqueMatches = this->m_allMatchesList.toSet();Overweary
what sort of errors you have as I can't think of anything which may prevent this code from working with QStringListBerners
T
0

Starting from Qt 5.14, you can use the new constructor:

template <typename InputIterator> QSet::QSet(InputIterator first, InputIterator last

Here is an example taken from the docs:

// 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());
Trilogy answered 27/3, 2022 at 10:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.