]> git.sur5r.net Git - fstl/blob - src/mesh.cpp
Mostly complete from the Python original
[fstl] / src / mesh.cpp
1 #include <QFile>
2 #include <QDataStream>
3
4 #include <algorithm>
5
6 #include "mesh.h"
7
8 Mesh::Mesh(const Eigen::Matrix3Xf& v, const Eigen::Matrix3Xi& i)
9     : vertices(v), indices(i)
10 {
11     // Nothing to do here
12 }
13
14 Mesh* Mesh::load_stl(const QString& filename)
15 {
16     QFile file(filename);
17     file.open(QIODevice::ReadOnly);
18
19     QDataStream data(&file);
20     data.setByteOrder(QDataStream::LittleEndian);
21     data.setFloatingPointPrecision(QDataStream::SinglePrecision);
22
23     data.skipRawData(80);
24     uint32_t tri_count;
25     data >> tri_count;
26
27     // Extract vertices into a vector of Vector4d objects
28     std::vector<Eigen::Vector4d> verts(tri_count*3);
29     for (unsigned i=0; i < tri_count; ++i)
30     {
31         data.skipRawData(3*sizeof(float));
32         for (int j=0; j < 3; ++j)
33         {
34             float x, y, z;
35             data >> x >> y >> z;
36             verts[3*i + j] << x, y, z, 3*i + j;
37         }
38         data.skipRawData(sizeof(uint16_t));
39     }
40
41     // Sort the set of vertices (to deduplicate)
42     std::sort(verts.begin(), verts.end(),
43               [](const Eigen::Vector4d& lhs, const Eigen::Vector4d& rhs)
44         {
45             if      (lhs[0] != rhs[0])  return lhs[0] < rhs[0];
46             else if (lhs[1] != rhs[1])  return lhs[1] < rhs[1];
47             else if (lhs[2] != rhs[2])  return lhs[2] < rhs[2];
48             else                        return false;
49         }
50     );
51
52     // This list will store unique vertices
53     std::list<Eigen::Vector3f> unique;
54
55     // This vector will store triangles as rows of indices
56     Eigen::Matrix3Xi indices;
57     indices.resize(Eigen::NoChange, tri_count);
58
59     // Go through the sorted vertex list, deduplicating and creating
60     // an indexed geometry representation for the triangles.
61     for (auto v : verts)
62     {
63         if (!unique.size() || v[0] != unique.back()[0] ||
64                               v[1] != unique.back()[1] ||
65                               v[2] != unique.back()[2])
66         {
67             // Switch to a float vector and save in the list.
68             Eigen::Vector3f v_;
69             v_ << v[0], v[1], v[2];
70             unique.push_back(v_);
71         }
72         indices(int(v[3]) % 3, int(v[3]) / 3) = unique.size() - 1;
73     }
74
75     // Finally, pack unique vertices into a matrix.
76     Eigen::Matrix3Xf unique_verts;
77     unique_verts.resize(Eigen::NoChange, unique.size());
78     {
79         auto v = unique.begin();
80         for (unsigned i=0; i < unique.size(); ++i)
81         {
82             unique_verts.col(i) = *(v++);
83         }
84     }
85
86     return new Mesh(unique_verts, indices);
87 }