QuickMesh.h
#pragma once
#include <QString>
#include <QFile>
#include <QTextStream>
#include <qgl.h>
#include <float.h>
#include <QVector3D>
class QuickMesh : public QObject{
Q_OBJECT
public:
QuickMesh()
{
verts.clear();
tris.clear();
isLoading = true;
fileName = "";
}
bool isLoading;
QString fileName;
void draw()
{
if(isLoading) return;
glEnable(GL_LIGHTING);
glColor3d(1,1,1);
if(tris.size())
{
glBegin(GL_TRIANGLES);
foreach(const QVector<int> tri, tris){
if(tri[0] < 0 || tri[1] < 0 || tri[2] < 0) continue;
QVector3D v1 = verts[tri[0]], v2 = verts[tri[1]], v3 = verts[tri[2]];
QVector3D n = QVector3D::crossProduct((v2-v1).normalized(), (v3-v1).normalized()).normalized();
glNormal3d(n.x(), n.y(), n.z());
glVertex3d(v1.x(), v1.y(), v1.z());
glVertex3d(v2.x(), v2.y(), v2.z());
glVertex3d(v3.x(), v3.y(), v3.z());
}
glEnd();
}
else{
// Point cloud
glPointSize(2.0f);
glDisable(GL_LIGHTING);
glBegin(GL_POINTS);
foreach(const QVector3D v, verts) glVertex3d(v.x(), v.y(), v.z());
glEnd();
}
glDisable(GL_LIGHTING);
}
QVector3D center;
QVector3D bbmin;
QVector3D bbmax;
public slots:
void load(QString fileame, bool isNormalize = true, bool isMoveCenter = true)
{
isLoading = true;
fileName = fileame;
clear();
QString ext = fileName.right(3).toLower();
if(ext == "obj") loadOBJ(fileName);
if(ext == "off") loadOFF(fileName);
postProcess(isNormalize, isMoveCenter);
isLoading = false;
}
void clear()
{
verts.clear();
tris.clear();
isLoading = true;
}
private:
void loadOBJ(QString fileName)
{
QFile file(fileName); file.open(QIODevice::ReadOnly | QIODevice::Text);
QTextStream in(&file);
while (!in.atEnd()){
QStringList v = in.readLine().split(" ", QString::SkipEmptyParts);
if(v.size() < 4) continue;
if(v[0] == "v")
{
verts.push_back(QVector3D(v[1].toDouble(),v[2].toDouble(),v[3].toDouble()));
}
if(v[0] == "f")
{
tris.push_back(QVector<int>(3));
tris.back()[0] = ( v[1].replace("/", " ").split(" ", QString::SkipEmptyParts)[0].toInt() - 1 );
tris.back()[1] = ( v[2].replace("/", " ").split(" ", QString::SkipEmptyParts)[0].toInt() - 1 );
tris.back()[2] = ( v[3].replace("/", " ").split(" ", QString::SkipEmptyParts)[0].toInt() - 1 );
}
}
}
void loadOFF(QString fileName)
{
QFile file(fileName); file.open(QIODevice::ReadOnly | QIODevice::Text);
QTextStream in(&file);
// skip first line
in.readLine();
// Read number of verts and tris
QStringList lineOne = in.readLine().split(" ", QString::SkipEmptyParts);
if(lineOne.size() != 3) return;
int num_v = lineOne[0].toInt();
int num_f = lineOne[1].toInt();
// Read vertices
for(int vi = 0; vi < num_v; vi++){
QStringList v = in.readLine().split(" ", QString::SkipEmptyParts);
if(v.size() == 3) verts.push_back(QVector3D(v[0].toDouble(),v[1].toDouble(),v[2].toDouble()));
else break;
}
if(verts.size() != num_v) return;
// Read faces
for(int fi = 0; fi < num_f; fi++){
if(in.atEnd()) return;
QStringList f = in.readLine().split(" ", QString::SkipEmptyParts);
if(f.size() < 4) continue;
tris.push_back(QVector<int>());
for(int i = 1; i < f.size(); i++) tris.back().push_back(f[i].toInt());
}
}
void postProcess(bool isNormalize, bool isMoveCenter)
{
// compute bounding box
QVector3D bmin (FLT_MAX, FLT_MAX, FLT_MAX);
QVector3D bmax = -bmin;
foreach(const QVector3D v, verts)
{
if(v.x() < bmin.x()) bmin.setX(v.x());
if(v.y() < bmin.y()) bmin.setY(v.y());
if(v.z() < bmin.z()) bmin.setZ(v.z());
if(v.x() > bmax.x()) bmax.setX(v.x());
if(v.y() > bmax.y()) bmax.setY(v.y());
if(v.z() > bmax.z()) bmax.setZ(v.z());
}
bbmin = bmin;
bbmax = bmax;
center = (bbmin + bbmax) * 0.5;
// Normalize and move to center
QVector3D d = bbmax - bbmin;
double s = (d.x() > d.y())? d.x():d.y();
s = (s>d.z())? s: d.z();
for(int vi = 0; vi < verts.size(); vi++)
{
verts[vi] = (verts[vi] - (isMoveCenter ? center : QVector3D(0,0,0))) / (isNormalize ? s : 1.0);
}
}
QVector< QVector3D > verts;
QVector< QVector<int> > tris;
};