Reading floats from binary STL file with QDataStream
-
wrote on 21 Feb 2012, 17:00 last edited by
Hi all,
I'm trying to read floats from an STL binary file (http://en.wikipedia.org/wiki/STL_(file_format)#Binary_STL).
I'm having a strange problem taking the floats from the QDataStream. I've read that there is a known bug but I'm having a different problem. Once in a while it reads the wrong number (for example, if the 4-byte-float, as in IEEE 754 format, is supposed to be 35.56, it reads 1.231e+12). NOTE THAT MOST OF THE TIMES (99.5%) IT WORKS WELL.
Here is the code:
@ // Treat BINARY STL
file->seek(0);
QDataStream in(file);
//in.setVersion(1);
in.setByteOrder(QDataStream::LittleEndian);
in.setFloatingPointPrecision(QDataStream::SinglePrecision);
quint32 ntriangles;
quint16 control_bytes;
file->seek(80);
in >> ntriangles;
int triang_count = 0;
double LIMIT_OUT = 2000;
while (triang_count < ntriangles) {
float nx, ny, nz, x1, x2, x3, y1, y2, y3, z1, z2, z3;
file->seek(84+triang_count50+0+0);
in >> nx;
file->seek(84+triang_count50+0+4);
in >> ny;
file->seek(84+triang_count50+0+8);
in >> nz;
file->seek(84+triang_count50+12+0);
in >> x1;
file->seek(84+triang_count50+12+4);
in >> y1;
file->seek(84+triang_count50+12+8);
in >> z1;
file->seek(84+triang_count50+24+0);
in >> x2;
file->seek(84+triang_count50+24+4);
in >> y2;
file->seek(84+triang_count50+24+8);
in >> z2;
file->seek(84+triang_count50+36+0);
in >> x3;
file->seek(84+triang_count50+36+4);
in >> y3;
file->seek(84+triang_count50+36+8);
in >> z3;
file->seek(84+triang_count*50+48);
in >> control_bytes;
if (in.status() != QDataStream::Ok ){
qDebug()<< (int) in.status();
}
//qDebug() << triangle_i;
bool nook = false;
nook = nook || ((fabs((double)x1)) > LIMIT_OUT);
nook = nook || ((fabs((double)x2)) > LIMIT_OUT);
nook = nook || ((fabs((double)x3)) > LIMIT_OUT);
nook = nook || ((fabs((double)y1)) > LIMIT_OUT);
nook = nook || ((fabs((double)y2)) > LIMIT_OUT);
nook = nook || ((fabs((double)y3)) > LIMIT_OUT);
nook = nook || ((fabs((double)z1)) > LIMIT_OUT);
nook = nook || ((fabs((double)z2)) > LIMIT_OUT);
nook = nook || ((fabs((double)z3)) > LIMIT_OUT);
if (control_bytes == 0 && !nook){
//DO TREATMENT
}
}
@I've written the same code in Matlab, it works well and displays the STL geometry that it is supposed to display, I've also tried the versions of Qt 4.7.3, Qt 4.7.4 and Qt 4.8 beta in two different computers, the problem occurs in the same bytes in both computers for most versions (none works fine).
At the end of every iteration, I check the status and it is always OK.
Is there a better/different/more appropriate way to extract the floats according to IEEE 754?
Thank you so much :)
Albert
-
wrote on 21 Feb 2012, 18:19 last edited by
Wouldn't be easier if you would use QFile? or simply fstream from standard C++?
-
wrote on 21 Feb 2012, 22:09 last edited by
QDataStream is not sufficient to read data not written with a QDataStream.
Additionally, I wouldn't bet a penny that manipulating the file position on the QFile object plays nicely with the data stream. I would expect troubles here.
As TheDestroyer already mentioned, using QFile directly would be a more robust solution in your case.
-
wrote on 21 Feb 2012, 23:32 last edited by
Thanks a lot for your replies :)
I have also tried with QFile and memcpy. Like in this example :
(file is a pointer to QFile, as in the previous example)@ while (triang_count < ntriangles) {
file->seek(84+triang_count*50);
float nxyz[12];
QByteArray ba = file->read(50);
memcpy(&nxyz, ba.constData(), 48);
// code
// ...
// code
triang_count = triang_count + 1;
}@But I get the same wrong values at the same place.
In this case I get the 12 floats of every triangle at once in the array nxyz (normal vector, p1, p2, p3; each has the components x, y, z). I see that this is much easier to work with, but I still get the wrong values.
Thanks again for your help.
-
wrote on 21 Feb 2012, 23:59 last edited by
Ok I got it! :D
I was opening the file as text!! :$
@file->open(QIODevice::ReadOnly))@I'm so clumsy... I've spent more than 4 hours here.
Thanks for your help anyways.
-
wrote on 22 Feb 2012, 08:12 last edited by
[quote author="Volker" date="1329862180"]QDataStream is not sufficient to read data not written with a QDataStream.
[/quote]
Actually, it works quite nicely. QDataStream does not add or expect any special markers. Of course, its own internal types have (well defined) specific layouts in the stream, but that is not a concern for reading basic types like floats. The only thing you need to take into account is the endianness, but changing that is supported in the QDataStream API. -
wrote on 22 Feb 2012, 13:05 last edited by
Yes, that's true. Unfortunately I was convinced that QDataStream writes its version to the start of the stream. But that's not true.
1/7