...
 
Commits (3)
......@@ -151,6 +151,8 @@ add_library(
source/gui/input/editors/TreeEditor.cpp
source/gui/input/editors/TreeEditor.hpp
source/gui/input/editors/TreeItem.hpp
source/gui/input/views/AABB.cpp
source/gui/input/views/AABB.hpp
source/gui/input/views/LayerLegend.cpp
source/gui/input/views/LayerLegend.hpp
source/gui/input/views/LimbView.cpp
......
#pragma once
#include <QVector3D>
class AABB
{
public:
AABB(): AABB(max_inf(), min_inf())
{
}
AABB(const QVector3D& vec_min, const QVector3D& vec_max)
: vec_min(vec_min), vec_max(vec_max)
{
}
AABB extend(const AABB& other) const
{
return {
min(vec_min, other.vec_min),
max(vec_max, other.vec_max)
};
}
AABB extend(const QVector3D& point) const
{
return {
min(vec_min, point),
max(vec_max, point)
};
}
QVector3D center() const
{
return (vec_min + vec_max)/2.0f;
}
float diagonal() const
{
return (vec_max - vec_min).length();
}
private:
QVector3D vec_min;
QVector3D vec_max;
QVector3D min(const QVector3D& vec1, const QVector3D& vec2) const
{
return {
std::min(vec1.x(), vec2.x()),
std::min(vec1.y(), vec2.y()),
std::min(vec1.z(), vec2.z())
};
}
QVector3D max(const QVector3D& vec1, const QVector3D& vec2) const
{
return {
std::max(vec1.x(), vec2.x()),
std::max(vec1.y(), vec2.y()),
std::max(vec1.z(), vec2.z())
};
}
QVector3D min_inf() const
{
return {
-std::numeric_limits<float>::infinity(),
-std::numeric_limits<float>::infinity(),
-std::numeric_limits<float>::infinity()
};
}
QVector3D max_inf() const
{
return {
std::numeric_limits<float>::infinity(),
std::numeric_limits<float>::infinity(),
std::numeric_limits<float>::infinity()
};
}
};
......@@ -3,13 +3,18 @@
#include "bow/LimbProperties.hpp"
#include "numerics/ArcCurve.hpp"
#include "numerics/CubicSpline.hpp"
#include <qmath.h>
LimbMesh::LimbMesh(bool inverted)
: visible(true),
inverted(inverted)
{
}
void LimbMesh::setData(const InputData& data)
{
vertex_data.clear();
aabb_min = QVector3D();
aabb_max = QVector3D();
bounding_box = AABB();
// Todo: Abstract away the conversion data -> profile curve
std::vector<double> lengths = getEvalLengths(data, 100);
......@@ -76,8 +81,8 @@ void LimbMesh::setData(const InputData& data)
if(layer_indices.empty())
add_points(h_sum_prev, h_sum_next);
h_sum_prev += h_prev;
h_sum_next += h_next;
h_sum_prev -= h_prev;
h_sum_next -= h_next;
add_points(h_sum_prev, h_sum_next);
layer_indices.push_back(j);
......@@ -163,18 +168,32 @@ size_t LimbMesh::vertexCount() const
return vertex_data.size()/9;
}
QVector3D LimbMesh::aabbCenter() const
const AABB LimbMesh::aabb() const
{
return (aabb_min + aabb_max)/2.0f;
return bounding_box;
}
float LimbMesh::aabbDiagonal() const
bool LimbMesh::isVisible() const
{
return (aabb_max - aabb_min).length();
return visible;
}
void LimbMesh::addQuad(const QVector3D& p0, const QVector3D& p1, const QVector3D& p2, const QVector3D& p3, const QColor& color)
void LimbMesh::setVisible(bool value)
{
visible = value;
}
void LimbMesh::addQuad(QVector3D p0, QVector3D p1, QVector3D p2, QVector3D p3, const QColor& color)
{
if(inverted)
{
p0.setX(-p0.x());
p1.setX(-p1.x());
p2.setX(-p2.x());
p3.setX(-p3.x());
std::swap(p1, p3);
}
QVector3D n0 = QVector3D::normal(p1 - p0, p3 - p0);
QVector3D n1 = QVector3D::normal(p2 - p1, p0 - p1);
QVector3D n2 = QVector3D::normal(p3 - p2, p1 - p2);
......@@ -203,13 +222,5 @@ void LimbMesh::addVertex(const QVector3D& position, const QVector3D& normal, con
vertex_data.push_back(color.greenF());
vertex_data.push_back(color.blueF());
// Todo: Is there a vector operation for this in Eigen?
aabb_min.setX(std::min(aabb_min.x(), position.x()));
aabb_min.setY(std::min(aabb_min.y(), position.y()));
aabb_min.setZ(std::min(aabb_min.z(), position.z()));
// Todo: Is there a vector operation for this in Eigen?
aabb_max.setX(std::max(aabb_max.x(), position.x()));
aabb_max.setY(std::max(aabb_max.y(), position.y()));
aabb_max.setZ(std::max(aabb_max.z(), position.z()));
bounding_box = bounding_box.extend(position);
}
#pragma once
#include "bow/input/InputData.hpp"
#include "numerics/Eigen.hpp"
#include "AABB.hpp"
#include <qopengl.h>
#include <QVector3D>
#include <QColor>
......@@ -8,21 +9,23 @@
class LimbMesh
{
public:
LimbMesh() = default;
LimbMesh(bool inverted);
void setData(const InputData& data);
const std::vector<GLfloat>& vertexData() const;
size_t vertexCount() const;
const AABB aabb() const;
QVector3D aabbCenter() const;
float aabbDiagonal() const;
bool isVisible() const;
void setVisible(bool value);
private:
void addQuad(const QVector3D& p0, const QVector3D& p1, const QVector3D& p2, const QVector3D& p3, const QColor& color);
void addQuad(QVector3D p0, QVector3D p1, QVector3D p2, QVector3D p3, const QColor& color);
void addVertex(const QVector3D& position, const QVector3D& normal, const QColor& color);
std::vector<double> getEvalLengths(const InputData& data, unsigned n);
bool visible;
bool inverted;
std::vector<GLfloat> vertex_data;
QVector3D aabb_min;
QVector3D aabb_max;
AABB bounding_box;
};
......@@ -4,12 +4,17 @@
#include <QMouseEvent>
#include <QOpenGLShaderProgram>
#include <QCoreApplication>
#include <math.h>
LimbView::LimbView()
: legend(new LayerLegend()),
limb_mesh_left(true),
limb_mesh_right(false),
shader_program(nullptr)
{
QSurfaceFormat format = QSurfaceFormat::defaultFormat();
format.setSamples(32);
setFormat(format);
auto button0 = new QToolButton();
QObject::connect(button0, &QPushButton::clicked, this, &LimbView::viewProfile);
button0->setIcon(QIcon(":/icons/limb-view/view-profile"));
......@@ -58,6 +63,7 @@ LimbView::LimbView()
vbox->addStretch();
vbox->addLayout(hbox);
viewSymmetric(false);
view3D();
}
......@@ -69,11 +75,14 @@ LimbView::~LimbView()
void LimbView::setData(const InputData& data)
{
legend->setData(data.layers);
limb_mesh.setData(data);
limb_mesh_left.setData(data);
limb_mesh_right.setData(data);
limb_mesh_left_vbo.bind();
limb_mesh_left_vbo.allocate(limb_mesh_left.vertexData().data(), limb_mesh_left.vertexData().size()*sizeof(GLfloat));
limb_mesh_vbo.create();
limb_mesh_vbo.bind();
limb_mesh_vbo.allocate(limb_mesh.vertexData().data(), limb_mesh.vertexData().size()*sizeof(GLfloat));
limb_mesh_right_vbo.bind();
limb_mesh_right_vbo.allocate(limb_mesh_right.vertexData().data(), limb_mesh_right.vertexData().size()*sizeof(GLfloat));
update();
}
......@@ -87,7 +96,7 @@ void LimbView::viewProfile()
void LimbView::viewTop()
{
rot_x = 90.0f;
rot_x = -90.0f;
rot_y = 0.0f;
viewFit();
}
......@@ -101,7 +110,9 @@ void LimbView::view3D()
void LimbView::viewSymmetric(bool checked)
{
limb_mesh_left.setVisible(checked);
limb_mesh_right.setVisible(true);
update();
}
void LimbView::viewFit()
......@@ -118,7 +129,8 @@ void LimbView::cleanup()
return;
makeCurrent();
limb_mesh_vbo.destroy();
limb_mesh_left_vbo.destroy();
limb_mesh_right_vbo.destroy();
delete shader_program;
shader_program = nullptr;
doneCurrent();
......@@ -183,20 +195,41 @@ void LimbView::initializeGL()
loc_normalMatrix = shader_program->uniformLocation("normalMatrix");
loc_lightPosition = shader_program->uniformLocation("lightPosition");
// Setup vertex buffer object.
limb_mesh_vbo.create();
limb_mesh_vbo.bind();
limb_mesh_vbo.allocate(limb_mesh.vertexData().data(), limb_mesh.vertexData().size()*sizeof(GLfloat));
// Store the vertex attribute bindings for the program.
limb_mesh_vbo.bind();
// Create a vertex array object. In OpenGL ES 2.0 and OpenGL 2.x
// implementations this is optional and support may not be present
// at all. Nonetheless the below code works in all cases and makes
// sure there is a VAO when one is needed.
m_vao.create();
QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao);
// Setup vertex buffer object and vertex attributes for right limb
limb_mesh_left_vbo.create();
limb_mesh_left_vbo.bind();
limb_mesh_left_vbo.allocate(limb_mesh_left.vertexData().data(), limb_mesh_left.vertexData().size()*sizeof(GLfloat));
/*
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 9*sizeof(GLfloat), (void*)(0*sizeof(GLfloat)));
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 9*sizeof(GLfloat), (void*)(3*sizeof(GLfloat)));
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 9*sizeof(GLfloat), (void*)(6*sizeof(GLfloat)));
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
*/
limb_mesh_left_vbo.release();
// Setup vertex buffer object and vertex attributes for right limb
limb_mesh_right_vbo.create();
limb_mesh_right_vbo.bind();
limb_mesh_right_vbo.allocate(limb_mesh_right.vertexData().data(), limb_mesh_right.vertexData().size()*sizeof(GLfloat));
/*
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 9*sizeof(GLfloat), (void*)(0*sizeof(GLfloat)));
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 9*sizeof(GLfloat), (void*)(3*sizeof(GLfloat)));
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 9*sizeof(GLfloat), (void*)(6*sizeof(GLfloat)));
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
limb_mesh_vbo.release();
*/
limb_mesh_right_vbo.release();
// Set fixed light position
shader_program->setUniformValue(loc_lightPosition, QVector3D(0.0f, 0.0f, 50.0f));
......@@ -208,13 +241,19 @@ void LimbView::paintGL()
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glEnable(GL_MULTISAMPLE);
AABB content_bounds;
if(limb_mesh_left.isVisible())
content_bounds = content_bounds.extend(limb_mesh_left.aabb());
if(limb_mesh_right.isVisible())
content_bounds = content_bounds.extend(limb_mesh_right.aabb());
m_world.setToIdentity();
m_world.rotate(rot_x, 1.0f, 0.0f, 0.0f);
m_world.rotate(rot_y, 0.0f, 1.0f, 0.0f);
m_world.scale(1.0f/limb_mesh.aabbDiagonal());
m_world.translate(-limb_mesh.aabbCenter());
m_world.scale(1.0f/content_bounds.diagonal());
m_world.translate(-content_bounds.center());
m_camera.setToIdentity();
m_camera.translate(0.0f, 0.0f, -1.0f);
......@@ -226,12 +265,39 @@ void LimbView::paintGL()
( 0.5f*zoom + shift_y)*aspect_ratio,
0.001f, 100.0f);
QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao);
shader_program->bind();
shader_program->setUniformValue(loc_projectionMatrix, m_projection);
shader_program->setUniformValue(loc_modelViewMatrix, m_camera*m_world);
shader_program->setUniformValue(loc_normalMatrix, m_world.normalMatrix());
glDrawArrays(GL_TRIANGLES, 0, limb_mesh.vertexCount());
if(limb_mesh_left.isVisible())
{
limb_mesh_left_vbo.bind();
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 9*sizeof(GLfloat), (void*)(0*sizeof(GLfloat)));
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 9*sizeof(GLfloat), (void*)(3*sizeof(GLfloat)));
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 9*sizeof(GLfloat), (void*)(6*sizeof(GLfloat)));
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glDrawArrays(GL_TRIANGLES, 0, limb_mesh_left.vertexCount());
limb_mesh_left_vbo.release();
}
if(limb_mesh_right.isVisible())
{
limb_mesh_right_vbo.bind();
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 9*sizeof(GLfloat), (void*)(0*sizeof(GLfloat)));
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 9*sizeof(GLfloat), (void*)(3*sizeof(GLfloat)));
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 9*sizeof(GLfloat), (void*)(6*sizeof(GLfloat)));
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
glDrawArrays(GL_TRIANGLES, 0, limb_mesh_right.vertexCount());
limb_mesh_right_vbo.release();
}
shader_program->release();
}
......@@ -247,8 +313,8 @@ void LimbView::mouseMoveEvent(QMouseEvent *event)
if(event->buttons() & Qt::LeftButton)
{
rot_x -= ROT_SPEED*delta_y;
rot_y -= ROT_SPEED*delta_x;
rot_x += ROT_SPEED*delta_y;
rot_y += ROT_SPEED*delta_x;
update();
}
else if(event->buttons() & Qt::MiddleButton)
......
......@@ -16,8 +16,8 @@ QT_FORWARD_DECLARE_CLASS(QOpenGLShaderProgram)
class LimbView: public QOpenGLWidget, protected QOpenGLFunctions
{
private:
const float DEFAULT_ROT_X = -20.0f; // Magic number
const float DEFAULT_ROT_Y = 30.0f; // Magic number
const float DEFAULT_ROT_X = 20.0f; // Magic number
const float DEFAULT_ROT_Y = -30.0f; // Magic number
const float DEFAULT_ZOOM = 1.1f; // Magic number
const float ZOOM_SPEED = 0.2f; // Magic number
const float ROT_SPEED = 0.15f; // Magic number
......@@ -44,9 +44,11 @@ private:
void wheelEvent(QWheelEvent* event) override;
LayerLegend* legend;
LimbMesh limb_mesh;
QOpenGLBuffer limb_mesh_vbo;
LimbMesh limb_mesh_left;
LimbMesh limb_mesh_right;
QOpenGLVertexArrayObject m_vao;
QOpenGLBuffer limb_mesh_left_vbo;
QOpenGLBuffer limb_mesh_right_vbo;
QOpenGLShaderProgram* shader_program;
int loc_projectionMatrix;
......
#pragma once
#include "bow/input/InputData.hpp"
#include "LimbMesh.hpp"
#include "LayerLegend.hpp"
#include <QtWidgets>
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLVertexArrayObject>
#include <QOpenGLBuffer>
#include <QMatrix4x4>
QT_FORWARD_DECLARE_CLASS(QOpenGLShaderProgram)
// Based on Qt's "Hello GL2" example, http://doc.qt.io/qt-5/qtopengl-hellogl2-example.html
class LimbView: public QOpenGLWidget, protected QOpenGLFunctions
{
private:
const float DEFAULT_ROT_X = -20.0f; // Magic number
const float DEFAULT_ROT_Y = 30.0f; // Magic number
const float DEFAULT_ZOOM = 1.1f; // Magic number
const float ZOOM_SPEED = 0.2f; // Magic number
const float ROT_SPEED = 0.15f; // Magic number
public:
LimbView();
~LimbView() override;
void setData(const InputData& data);
void viewProfile();
void viewTop();
void view3D();
void viewSymmetric(bool checked);
void viewFit();
private:
void cleanup();
void initializeGL() override;
void paintGL() override;
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void wheelEvent(QWheelEvent* event) override;
LayerLegend* legend;
LimbMesh limb_mesh;
QOpenGLBuffer limb_mesh_vbo;
QOpenGLShaderProgram* shader_program;
int loc_projectionMatrix;
int loc_modelViewMatrix;
int loc_normalMatrix;
int loc_lightPosition;
QMatrix4x4 m_projection;
QMatrix4x4 m_camera;
QMatrix4x4 m_world;
QPoint mouse_pos;
float shift_x;
float shift_y;
float rot_x;
float rot_y;
float zoom;
};