diff --git a/src/canvas.cpp b/src/canvas.cpp index 290885b..39081b0 100644 --- a/src/canvas.cpp +++ b/src/canvas.cpp @@ -1,6 +1,8 @@ #include #include +#include + #include "canvas.h" #include "backdrop.h" #include "glmesh.h" @@ -28,7 +30,6 @@ void Canvas::load_mesh(Mesh* m) pow(m->xmax() - m->xmin(), 2) + pow(m->ymax() - m->ymin(), 2) + pow(m->zmax() - m->zmin(), 2)); - update(); delete m; diff --git a/src/fstl.pro b/src/fstl.pro index a5a0f0f..2033575 100644 --- a/src/fstl.pro +++ b/src/fstl.pro @@ -22,7 +22,5 @@ HEADERS += \ CONFIG += c++11 -INCLUDEPATH += /usr/local/include/eigen3 - RESOURCES += \ resources.qrc diff --git a/src/mesh.cpp b/src/mesh.cpp index d7266e7..36ad10e 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -1,16 +1,61 @@ #include #include +#include #include +#include #include "mesh.h" -Mesh::Mesh(const Eigen::Matrix3Xf& v, const Eigen::Matrix3Xi& i) +//////////////////////////////////////////////////////////////////////////////// + +Mesh::Mesh(std::vector v, std::vector i) : vertices(v), indices(i) { // Nothing to do here } +float Mesh::min(size_t start) const +{ + float v = vertices[start]; + for (size_t i=start; i < vertices.size(); i += 3) + { + v = fmin(v, vertices[i]); + } + return v; +} + +float Mesh::max(size_t start) const +{ + float v = vertices[start]; + for (size_t i=start; i < vertices.size(); i += 3) + { + v = fmax(v, vertices[i]); + } + return v; +} +//////////////////////////////////////////////////////////////////////////////// + +struct Vec3 +{ + GLfloat x, y, z; + bool operator!=(const Vec3& rhs) const + { + return x != rhs.x || y != rhs.y || z != rhs.z; + } + bool operator<(const Vec3& rhs) const + { + if (x != rhs.x) return x < rhs.x; + else if (y != rhs.y) return y < rhs.y; + else if (z != rhs.z) return z < rhs.z; + else return false; + } +}; + +typedef std::pair Vec3i; + +//////////////////////////////////////////////////////////////////////////////// + Mesh* Mesh::load_stl(const QString& filename) { QFile file(filename); @@ -20,68 +65,67 @@ Mesh* Mesh::load_stl(const QString& filename) data.setByteOrder(QDataStream::LittleEndian); data.setFloatingPointPrecision(QDataStream::SinglePrecision); + // Skip .stl file header data.skipRawData(80); + + // Load the triangle count from the .stl file uint32_t tri_count; data >> tri_count; - // Extract vertices into a vector of Vector4d objects - std::vector verts(tri_count*3); - for (unsigned i=0; i < tri_count; ++i) + // Extract vertices into an array of xyz, unsigned pairs + QVector verts(tri_count*3); + + // Store vertices in the array, processing one triangle at a time. + for (auto v=verts.begin(); v != verts.end(); v += 3) { + // Skip face's normal vector data.skipRawData(3*sizeof(float)); - for (int j=0; j < 3; ++j) - { - float x, y, z; - data >> x >> y >> z; - verts[3*i + j] << x, y, z, 3*i + j; - } + + // Load vertex data from .stl file into vertices + data >> v[0].first.x >> v[0].first.y >> v[0].first.z; + data >> v[1].first.x >> v[1].first.y >> v[1].first.z; + data >> v[2].first.x >> v[2].first.y >> v[2].first.z; + + // Skip face attribute data.skipRawData(sizeof(uint16_t)); } + // Save indicies as the second element in the array + // (so that we can reconstruct triangle order after sorting) + for (size_t i=0; i < tri_count*3; ++i) + { + verts[i].second = i; + } + // Sort the set of vertices (to deduplicate) - std::sort(verts.begin(), verts.end(), - [](const Eigen::Vector4d& lhs, const Eigen::Vector4d& rhs) - { - if (lhs[0] != rhs[0]) return lhs[0] < rhs[0]; - else if (lhs[1] != rhs[1]) return lhs[1] < rhs[1]; - else if (lhs[2] != rhs[2]) return lhs[2] < rhs[2]; - else return false; - } - ); + std::sort(verts.begin(), verts.end()); - // This list will store unique vertices - std::list unique; - - // This vector will store triangles as rows of indices - Eigen::Matrix3Xi indices; - indices.resize(Eigen::NoChange, tri_count); + // This vector will store triangles as sets of 3 indices + std::vector indices(tri_count*3); // Go through the sorted vertex list, deduplicating and creating // an indexed geometry representation for the triangles. + // Unique vertices are moved so that they occupy the first vertex_count + // positions in the verts array. + size_t vertex_count = 0; for (auto v : verts) { - if (!unique.size() || v[0] != unique.back()[0] || - v[1] != unique.back()[1] || - v[2] != unique.back()[2]) + if (!vertex_count || v.first != verts[vertex_count-1].first) { - // Switch to a float vector and save in the list. - Eigen::Vector3f v_; - v_ << v[0], v[1], v[2]; - unique.push_back(v_); + verts[vertex_count++] = v; } - indices(int(v[3]) % 3, int(v[3]) / 3) = unique.size() - 1; + indices[v.second] = vertex_count - 1; } + verts.resize(vertex_count); - // Finally, pack unique vertices into a matrix. - Eigen::Matrix3Xf unique_verts; - unique_verts.resize(Eigen::NoChange, unique.size()); + std::vector flat_verts; + flat_verts.reserve(vertex_count*3); + for (auto v : verts) { - auto v = unique.begin(); - for (unsigned i=0; i < unique.size(); ++i) - { - unique_verts.col(i) = *(v++); - } + flat_verts.push_back(v.first.x); + flat_verts.push_back(v.first.y); + flat_verts.push_back(v.first.z); } - return new Mesh(unique_verts, indices); + return new Mesh(flat_verts, indices); } diff --git a/src/mesh.h b/src/mesh.h index 064d276..f83a477 100644 --- a/src/mesh.h +++ b/src/mesh.h @@ -2,25 +2,29 @@ #define MESH_H #include +#include -#include +#include class Mesh { public: - Mesh(const Eigen::Matrix3Xf &vertices, const Eigen::Matrix3Xi &indices); + Mesh(std::vector vertices, std::vector indices); static Mesh* load_stl(const QString& filename); - float xmin() const { return vertices.row(0).minCoeff(); } - float xmax() const { return vertices.row(0).maxCoeff(); } - float ymin() const { return vertices.row(1).minCoeff(); } - float ymax() const { return vertices.row(1).maxCoeff(); } - float zmin() const { return vertices.row(2).minCoeff(); } - float zmax() const { return vertices.row(2).maxCoeff(); } + float min(size_t start) const; + float max(size_t start) const; + + float xmin() const { return min(0); } + float ymin() const { return min(1); } + float zmin() const { return min(2); } + float xmax() const { return max(0); } + float ymax() const { return max(1); } + float zmax() const { return max(2); } private: - const Eigen::Matrix3Xf vertices; - const Eigen::Matrix3Xi indices; + std::vector vertices; + std::vector indices; friend class GLMesh; };