#pragma once #include #include #include #include "RenderObject.h" #include "SurfaceMeshModel.h" using namespace SurfaceMesh; using namespace Eigen; #define glVertQt(v) glVertex3d(v.x(), v.y(), v.z()) #define glColorQt(c) glColor4d(c.redF(), c.greenF(), c.blueF(), c.alphaF()) #define glv(v) glVertex3dv(v.data()) #ifndef GL_MULTISAMPLE #define GL_MULTISAMPLE 0x809D #endif // Custom QVector3D class QVector3: public QVector3D{ public: QVector3(){ setX(0);setY(0);setZ(0); } QVector3(double x, double y, double z){ this->setX(x);this->setY(y);this->setZ(z); } QVector3 (const QVector3D& v){ this->setX(v.x());this->setY(v.y());this->setZ(v.z()); } QVector3 (const Vector3d& v){ this->setX(v.x());this->setY(v.y());this->setZ(v.z()); } operator const Vector3d() { return Vector3d(x(),y(),z()); } operator const QVector3D() { return *this; } }; class PolygonSoup : public RenderObject::Base{ QVector< QVector > polys; QVector< QVector3 > polys_normals; QVector< QColor > polys_colors; public: PolygonSoup():RenderObject::Base(1, Qt::black){} void clear(){ polys.clear(); polys_normals.clear(); polys_colors.clear(); } void draw(QGLWidget &widget){ this->draw(); Q_UNUSED(widget) } void draw(){ glEnable(GL_LIGHTING); glEnable(GL_BLEND); drawTris(); drawQuads(); glDisable(GL_LIGHTING); // Draw borders as lines and points to force drawing something glLineWidth(2.0f); glColor4d(0,0,0,1); glBegin(GL_LINES); foreach(QVector poly, polys){ for(int i = 0; i < (int) poly.size(); i++){ glVertQt(poly[i]); glVertQt(poly[(i+1) % poly.size()]); } } glEnd(); glPointSize(3.0f); glBegin(GL_POINTS); foreach(QVector poly, polys){ for(int i = 0; i < (int) poly.size(); i++) glVertQt(poly[i]); } glEnd(); glEnable(GL_LIGHTING); } void drawTris(bool isColored = true){ glBegin(GL_TRIANGLES); for(int i = 0; i < (int) polys.size(); i++) { if(polys[i].size() != 3) continue; else{ glNormal3d(polys_normals[i].x(),polys_normals[i].y(),polys_normals[i].z()); if(isColored) glColorQt(polys_colors[i]); for(int p = 0; p < 3; p++) glVertQt(polys[i][p]); } } glEnd(); } void drawQuads(bool isColored = true){ glBegin(GL_QUADS); for(int i = 0; i < (int) polys.size(); i++) { if(polys[i].size() != 4) continue; else{ glNormal3d(polys_normals[i].x(),polys_normals[i].y(),polys_normals[i].z()); if(isColored) glColorQt(polys_colors[i]); for(int p = 0; p < 4; p++) glVertQt(polys[i][p]); } } glEnd(); } void addPoly(const QVector& points, const QColor& c = Qt::red){ if(points.size() < 3) return; else polys.push_back(points); // Compute normal from 3 points polys_normals.push_back(QVector3D::crossProduct(points[1] - points[0], points[2] - points[0]).normalized()); polys_colors.push_back(c); } }; class LineSegments : public RenderObject::Base{ QVector< QPair > lines; QVector< QColor > lines_colors; public: LineSegments():RenderObject::Base(1, Qt::black){} void draw(QGLWidget &widget){ this->draw(); Q_UNUSED(widget) } void draw(){ glDisable(GL_LIGHTING); glLineWidth(_size); glBegin(GL_LINES); for(int i = 0; i < (int) lines.size(); i++){ glColorQt(lines_colors[i]); glVertQt(lines[i].first); glVertQt(lines[i].second); } glEnd(); glPointSize(_size+2); glBegin(GL_POINTS); for(int i = 0; i < (int) lines.size(); i++){ glColorQt(lines_colors[i]); glVertQt(lines[i].first); } glEnd(); glEnable(GL_LIGHTING); } void addLine(const QVector3& p1, const QVector3& p2, const QColor& c = Qt::blue){ lines.push_back( qMakePair(p1,p2) ); lines_colors.push_back(c); } void addLines() { } }; class PointSoup : public RenderObject::Base{ QVector< QVector3 > points; QVector< QVector3 > normals; QVector< QColor > points_colors; public: PointSoup(float size = 6.0f):RenderObject::Base(size, Qt::black){} void clear(){ points.clear(); points_colors.clear(); } void draw(QGLWidget &widget){ this->draw(); Q_UNUSED(widget) } void draw(){ glDisable(GL_LIGHTING); if(normals.size()) glEnable(GL_LIGHTING); glPointSize(_size); glBegin(GL_POINTS); for(int i = 0; i < (int) points.size(); i++){ if(normals.size()) glNormal3d(normals[i].x(),normals[i].y(),normals[i].z()); glColorQt(points_colors[i]); glVertQt(points[i]); } glEnd(); glEnable(GL_LIGHTING); } void addPointNormal(const QVector3& p, const QVector3& n, const QColor& c = Qt::blue){ addPoint(p,c); normals.push_back(n); } void addPoint(const QVector3& p, const QColor& c = Qt::blue){ points.push_back(p); points_colors.push_back(c); } size_t count(){ return points.size(); } }; class VectorSoup : public RenderObject::Base{ QVector< QPair > vectors; QVector< double > vectorLengths; double maxLen; public: VectorSoup(const QColor& c = Qt::green):RenderObject::Base(1, c){ maxLen = -DBL_MAX; } void clear(){ vectors.clear(); vectorLengths.clear(); maxLen = -DBL_MAX; } void addVector(const QVector3& start, const QVector3& direction){ vectors.push_back( qMakePair(start,direction) ); double l = direction.length(); vectorLengths.push_back(l); maxLen = qMax(l,maxLen); } void draw(QGLWidget &widget){ this->draw(); Q_UNUSED(widget) } void draw(float thickness = 1.0f){ glDisable(GL_LIGHTING); glLineWidth(thickness); glBegin(GL_LINES); for(int i = 0; i < (int) vectors.size(); i++){ // Color //double d = vectorLengths[i] / maxLen; //QColor c( _color.red() * d, _color.green() * d, _color.blue() * d ); glColorQt(this->_color.lighter()); // Line glVertQt(vectors[i].first); glVertQt((vectors[i].first + vectors[i].second)); } glEnd(); glPointSize(thickness * 2); glBegin(GL_POINTS); for(int i = 0; i < (int) vectors.size(); i++){ // Color //double d = vectorLengths[i] / maxLen; //QColor c( _color.red() * d, _color.green() * d, _color.blue() * d ); glColorQt(this->_color); // Point glVertQt((vectors[i].first + vectors[i].second)); } glEnd(); glEnable(GL_LIGHTING); } }; class PlaneSoup : public RenderObject::Base{ QVector< QPair > planes; double scale; public: PlaneSoup(double s = 1.0, const QColor& c = Qt::green):RenderObject::Base(1, c) { scale = s; } void addPlane(const QVector3& center, const QVector3& normal){ planes.push_back( qMakePair(center, normal) ); } void draw(QGLWidget &widget){this->draw();widget;} void draw(){ glDisable(GL_LIGHTING); // Rendering options glEnable (GL_POINT_SMOOTH); glEnable (GL_LINE_SMOOTH); glEnable (GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glHint (GL_LINE_SMOOTH_HINT, GL_NICEST); float color[4]; glGetFloatv(GL_CURRENT_COLOR, color); // Bake geometry int c = planes.size(); std::vector n(c),u(c),v(c),p1(c),p2(c),p3(c),p4(c); for(int i = 0; i < c; i++){ n[i] = planes[i].second; u[i] = scale * orthogonalVector(n[i]).normalized(); v[i] = scale * QVector3D::crossProduct(n[i], u[i]).normalized(); p1[i] = QVector3(planes[i].first + (u[i] + v[i])); p2[i] = QVector3(planes[i].first + (-u[i] + v[i])); p3[i] = QVector3(planes[i].first + (-v[i] + u[i])); p4[i] = QVector3(planes[i].first + (-v[i] + -u[i])); } // Draw Borders glColor4f(color[0]*0.8, color[1]*0.8, color[2]*0.8, 0.5); glLineWidth(2.0); glPolygonMode(GL_FRONT,GL_LINE); glBegin(GL_QUADS); for(int i = 0; i < c; i++) { glVertQt(p1[i]); glVertQt(p2[i]); glVertQt(p4[i]); glVertQt(p3[i]); } glEnd(); // Draw Center glColor3f(color[0], color[1], color[2]); glPointSize(4.0); glBegin(GL_POINTS); for(int i = 0; i < c; i++) glVertQt(planes[i].first); glEnd(); glPointSize(8.0); glColor4f(1, 1, 1, 0.5); glBegin(GL_POINTS); for(int i = 0; i < c; i++) glVertQt(planes[i].first); glEnd(); // Draw Normal glBegin(GL_LINES); for(int i = 0; i < c; i++) { Vector3d center = planes[i].first; glv(center); glv(Vector3(center + ((Vector3d)n[i] * 0.2 * scale))); } glEnd(); // Draw Transparent Fills glColor4f(color[0], color[1], color[2], 0.05f); glPolygonMode(GL_FRONT,GL_FILL); glBegin(GL_QUADS); for(int i = 0; i < c; i++) { glVertQt(p1[i]); glVertQt(p2[i]); glVertQt(p4[i]); glVertQt(p3[i]); } glEnd(); glDisable(GL_BLEND); glEnable(GL_LIGHTING); } static QVector3 orthogonalVector(const QVector3& n) { if ((abs(n.y()) >= 0.9 * abs(n.x())) && abs(n.z()) >= 0.9 * abs(n.x())) return QVector3(0.0, -n.z(), n.y()); else if ( abs(n.x()) >= 0.9 * abs(n.y()) && abs(n.z()) >= 0.9 * abs(n.y()) ) return QVector3(-n.z(), 0.0, n.x()); else return QVector3(-n.y(), n.x(), 0.0); } }; class FrameSoup : public RenderObject::Base{ QVector< QVector > frames; bool isFlip; public: FrameSoup(float scale, bool flip = false, const QColor& c = Qt::green):RenderObject::Base(scale, c) { this->isFlip = flip; } void addFrame(const QVector3& X, const QVector3& Y, const QVector3& Z, const QVector3& position){ QVector frame; if(isFlip) { frame.push_back(Z); frame.push_back(Y); frame.push_back(X); } else { frame.push_back(X); frame.push_back(Y); frame.push_back(Z); } frame.push_back(position); frames.push_back(frame); } void draw(QGLWidget &widget){ this->draw(); Q_UNUSED(widget) } void draw() { drawFrame(); } void drawFrame( int colorOffset = 0 ) { QColor frameColors[] = { QColor(255,0,0), QColor(0,255,0), QColor(0,0,255) }; int ci = colorOffset; glDisable(GL_LIGHTING); glLineWidth(1); glBegin(GL_LINES); for(int i = 0; i < (int) frames.size(); i++){ QVector3 X=frames[i][0],Y=frames[i][1],Z=frames[i][2]; QVector3 pos=frames[i][3]; glColorQt(frameColors[(ci+0)%3]); glVertQt(pos); glVertQt((pos + X * _size)); glColorQt(frameColors[(ci+1)%3]); glVertQt(pos); glVertQt((pos + Y * _size)); glColorQt(frameColors[(ci+2)%3]); glVertQt(pos); glVertQt((pos + Z * _size)); } glEnd(); glPointSize(3); glBegin(GL_POINTS); for(int i = 0; i < (int) frames.size(); i++){ QVector3 X=frames[i][0],Y=frames[i][1],Z=frames[i][2]; QVector3 pos=frames[i][3]; glColorQt(frameColors[(ci+0)%3]); glVertQt((pos + X * _size)); glColorQt(frameColors[(ci+1)%3]); glVertQt((pos + Y * _size)); glColorQt(frameColors[(ci+2)%3]); glVertQt((pos + Z * _size)); } glEnd(); glEnable(GL_LIGHTING); } }; static void renderSphere(float cx, float cy, float cz, float r) { #ifndef M_PI #define M_PI 3.14159265358979323846 #endif #ifndef M_PI_2 #define M_PI_2 1.57079632679489661923 #endif const int p = 24; float theta1 = 0.0, theta2 = 0.0, theta3 = 0.0; float ex = 0.0f, ey = 0.0f, ez = 0.0f; float px = 0.0f, py = 0.0f, pz = 0.0f; GLfloat vertices[p*6+6], normals[p*6+6], texCoords[p*4+4]; for(int i = 0; i < p/2; ++i){ theta1 = i * (M_PI*2) / p - M_PI_2; theta2 = (i + 1) * (M_PI*2) / p - M_PI_2; for(int j = 0; j <= p; ++j){ theta3 = j * (M_PI*2) / p; ex = cosf(theta2) * cosf(theta3); ey = sinf(theta2); ez = cosf(theta2) * sinf(theta3); px = cx + r * ex; py = cy + r * ey; pz = cz + r * ez; vertices[(6*j)+(0%6)] = px; vertices[(6*j)+(1%6)] = py; vertices[(6*j)+(2%6)] = pz; normals[(6*j)+(0%6)] = ex; normals[(6*j)+(1%6)] = ey; normals[(6*j)+(2%6)] = ez; texCoords[(4*j)+(0%4)] = -(j/(float)p); texCoords[(4*j)+(1%4)] = 2*(i+1)/(float)p; ex = cosf(theta1) * cosf(theta3); ey = sinf(theta1); ez = cosf(theta1) * sinf(theta3); px = cx + r * ex; py = cy + r * ey; pz = cz + r * ez; vertices[(6*j)+(3%6)] = px; vertices[(6*j)+(4%6)] = py; vertices[(6*j)+(5%6)] = pz; normals[(6*j)+(3%6)] = ex; normals[(6*j)+(4%6)] = ey; normals[(6*j)+(5%6)] = ez; texCoords[(4*j)+(2%4)] = -(j/(float)p); texCoords[(4*j)+(3%4)] = 2*i/(float)p; } glEnableClientState(GL_TEXTURE_COORD_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_VERTEX_ARRAY); glTexCoordPointer(2, GL_FLOAT, 0, texCoords); glNormalPointer(GL_FLOAT, 0, normals); glVertexPointer(3, GL_FLOAT, 0, vertices); glDrawArrays(GL_TRIANGLE_STRIP, 0, (p+1)*2); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); } } class SphereSoup : public RenderObject::Base{ QVector< QVector3 > centers; QVector< float > radii; QVector< QColor > colors; public: SphereSoup(const QColor& c = Qt::yellow):RenderObject::Base(1, c){} void clear(){ centers.clear(); radii.clear(); colors.clear(); } void draw(QGLWidget &widget){ this->draw(); Q_UNUSED(widget) } void draw(){ glEnable(GL_LIGHTING); for(int i = 0; i < (int) centers.size(); i++){ Vector3d c = centers[i]; glColorQt(colors[i]); renderSphere(c[0],c[1],c[2],radii[i]); } } void addSphere(const QVector3& center, float radius = 0.1f){ centers.push_back(center); radii.push_back(radius); colors.push_back(_color); } void addSphere(const QVector3& center, float radius, const QColor& c){ centers.push_back(center); radii.push_back(radius); colors.push_back(c); } }; class CubeSoup : public RenderObject::Base{ QVector< QVector3 > centers; QVector< float > lengths; QVector< QColor > colors; bool isWireframe; public: CubeSoup(float defaultSize = 1.0, bool is_wireframe = true):RenderObject::Base(defaultSize, Qt::black) { isWireframe = is_wireframe; } void clear(){ centers.clear(); lengths.clear(); colors.clear(); } void drawCube(QVector3 center, double length = 1.0) { static GLdouble n[6][3] = {{-1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {1.0, 0.0, 0.0}, {0.0, -1.0, 0.0}, {0.0, 0.0, 1.0}, {0.0, 0.0, -1.0}}; static GLint faces[6][4] = {{0, 1, 2, 3}, {3, 2, 6, 7}, {7, 6, 5, 4}, {4, 5, 1, 0}, {5, 6, 2, 1}, {7, 4, 0, 3}}; GLdouble v[8][3]; GLint i; v[0][0] = v[1][0] = v[2][0] = v[3][0] = -length / 2; v[4][0] = v[5][0] = v[6][0] = v[7][0] = length / 2; v[0][1] = v[1][1] = v[4][1] = v[5][1] = -length / 2; v[2][1] = v[3][1] = v[6][1] = v[7][1] = length / 2; v[0][2] = v[3][2] = v[4][2] = v[7][2] = -length / 2; v[1][2] = v[2][2] = v[5][2] = v[6][2] = length / 2; glPushMatrix(); glTranslatef(center.x(), center.y(), center.z()); for (i = 0; i < 6; i++) { glBegin(GL_QUADS); glNormal3dv(&n[i][0]); glVertex3dv(&v[faces[i][0]][0]); glVertex3dv(&v[faces[i][1]][0]); glVertex3dv(&v[faces[i][2]][0]); glVertex3dv(&v[faces[i][3]][0]); glEnd(); } glPopMatrix(); } void draw(QGLWidget &widget){ this->draw(); Q_UNUSED(widget) } void draw() { glEnable(GL_LIGHTING); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); if(isWireframe){ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glDisable(GL_LIGHTING); } for(int i = 0; i < (int) centers.size(); i++){ glColorQt(colors[i]); drawCube(centers[i],lengths[i]); } glEnable(GL_LIGHTING); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } void addCube(const QVector3& center, float length = 1, const QColor& c = Qt::yellow){ centers.push_back(center); lengths.push_back(length * _size); colors.push_back(c); } }; static QColor qtColdColor(double value, double min = 0.0, double max = 1.0){ unsigned char rgb[3]; value-=min; if(value==HUGE_VAL) {rgb[0]=rgb[1]=rgb[2]=255;} else if(value<0) {rgb[0]=rgb[1]=rgb[2]=0;} else if(value static std::vector randomColor() { std::vector color; float r = float( qMin(((rand() % 225) + 30), 255) ) / 255.0f; float g = float( qMin(((rand() % 230) + 25), 255) ) / 255.0f; float b = float( qMin(((rand() % 235) + 20), 255) ) / 255.0f; color.push_back(r); color.push_back(g); color.push_back(b); color.push_back(1.0); return color; } static std::vector< std::vector > randomColors( int count ) { srand(time(NULL)); std::vector< std::vector > colors(count); for (int i = 0; i < count; i++) colors[i] = randomColor(); return colors; } static QColor qRandomColor() { std::vector c = randomColor(); return QColor::fromRgbF( c[0], c[1], c[2], c[3] ); } static QColor qRandomColor2(double saturation = 0.5, double val = 0.95) { double golden_ratio_conjugate = 0.618033988749895; double h = ((double)rand() / RAND_MAX); h += golden_ratio_conjugate; h = fmod(h, 1.0); return QColor::fromHsvF(h, saturation, val); } // Helper functions double inline uniformRand(double a = 0.0, double b = 1.0){ double len = b - a; return ((double)rand()/RAND_MAX) * len + a; } // for mid = 0, colors are centered around Red static QColor qRandomColor3(double mid = 0, double range = 0.5, double saturation = 1.0, double val = 1.0) { // Bound checks mid = qMax(0.0, qMin(1.0, mid)); range = qMin(0.5, range); double h = uniformRand( -range + mid, range + mid ); h = fmod(1.0 + h, 1.0); return QColor::fromHsvF(h, saturation, val); }