Reading floats from binary STL file with QDataStream



  • 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_count
    50+0+4);
    in >> ny;
    file->seek(84+triang_count50+0+8);
    in >> nz;
    file->seek(84+triang_count
    50+12+0);
    in >> x1;
    file->seek(84+triang_count50+12+4);
    in >> y1;
    file->seek(84+triang_count
    50+12+8);
    in >> z1;
    file->seek(84+triang_count50+24+0);
    in >> x2;
    file->seek(84+triang_count
    50+24+4);
    in >> y2;
    file->seek(84+triang_count50+24+8);
    in >> z2;
    file->seek(84+triang_count
    50+36+0);
    in >> x3;
    file->seek(84+triang_count50+36+4);
    in >> y3;
    file->seek(84+triang_count
    50+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



  • Wouldn't be easier if you would use QFile? or simply fstream from standard C++?



  • 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.



  • 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.



  • 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.



  • [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.



  • Yes, that's true. Unfortunately I was convinced that QDataStream writes its version to the start of the stream. But that's not true.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.