#if _WIN32
#define NOMINMAX
#endif
#include <QtGui>
#include <QtOpenGL>
#include <cmath>
#include "ui/tvr/match_viewer.h"
using libmv::Matches;
using libmv::PointFeature;
static bool ImageContains(OnScreenImage &im, GLTexture &tex, float x, float y) {
return im.posx < x && x < im.posx + tex.width
&& im.posy < y && y < im.posy + tex.height;
}
MatchViewer::MatchViewer(QGLWidget *share, GLTexture *textures, QWidget *parent)
: QGLWidget(0, share), document_(NULL), textures_(textures) {
tx = 0;
ty = 0;
zoom = 1;
InitTextures();
connect(parent, SIGNAL(GLUpdateNeeded()), this, SLOT(GLUpdate()));
connect(parent, SIGNAL(TextureChanged()), this, SLOT(TextureChange()));
setWindowTitle("2D View");
}
MatchViewer::~MatchViewer() {
makeCurrent();
}
void MatchViewer::SetDocument(TvrDocument *doc) {
document_ = doc;
}
QSize MatchViewer::minimumSizeHint() const {
return QSize(50, 50);
}
QSize MatchViewer::sizeHint() const {
return QSize(800, 400);
}
void MatchViewer::SetTransformation(float tx_, float ty_, float zoom_) {
tx = tx_;
ty = ty_;
zoom = zoom_;
updateGL();
}
void MatchViewer::PlaneFromScreen(float xw, float yw, float *xi, float *yi) {
*xi = zoom * xw + tx;
*yi = zoom * yw + ty;
}
void MatchViewer::ScreenFromPlane(float xi, float yi, float *xw, float *yw) {
*xw = (xi - tx) / zoom;
*yw = (yi - ty) / zoom;
}
void MatchViewer::initializeGL() {
glClearColor(0, 0, 0, 1);
glShadeModel(GL_FLAT);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
}
void MatchViewer::SetUpGlCamera() {
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
float x0, y0, x1, y1;
PlaneFromScreen(0, 0, &x0, &y0);
PlaneFromScreen(width(), height(), &x1, &y1);
glOrtho(x0, x1, y1, y0, -1, 1);
glMatrixMode(GL_MODELVIEW);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
}
void MatchViewer::DrawImage(int i) {
assert(document_);
assert(!document_->images[i].isNull());
if (textures_[i].textureID) {
OnScreenImage &si = screen_images_[i];
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glTranslatef(si.posx, si.posy, 0);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textures_[i].textureID);
glBegin(GL_QUADS);
glTexCoord2d(0, 0); glVertex2d(0, 0);
glTexCoord2d(1, 0); glVertex2d(textures_[i].width, 0);
glTexCoord2d(1, 1); glVertex2d(textures_[i].width, textures_[i].height);
glTexCoord2d(0, 1); glVertex2d(0, textures_[i].height);
glEnd();
glDisable(GL_TEXTURE_2D);
DrawFeatures(i);
glPopMatrix();
}
}
void MatchViewer::DrawFeatures(int image_index) {
for (Matches::Points r =
document_->matches.InImage<PointFeature>(image_index); r; ++r) {
glPushMatrix();
glTranslatef(r.feature()->x(), r.feature()->y(), 0.0f);
float scale = r.feature()->scale;
glScalef(scale, scale, scale);
glRotatef(r.feature()->orientation*180.0f/3.14159f, 0.0f, 0.0f, 1.0f);
glBegin(GL_LINES);
glVertex2f(-1, -1); glVertex2f( 1, -1); glVertex2f( 1, -1); glVertex2f( 1, 1);
glVertex2f( 1, 1); glVertex2f(-1, 1);
glVertex2f(-1, 1); glVertex2f(-1, -1);
glVertex2f(0, 0); glVertex2f(0, -1); glEnd();
glPopMatrix();
}
}
void MatchViewer::DrawCandidateMatches() {
float xoff[2] = { screen_images_[0].posx, screen_images_[1].posx};
float yoff[2] = { screen_images_[0].posy, screen_images_[1].posy};
int nb = 0;
glBegin(GL_LINES); for (Matches::Points r =
document_->matches.AllReversed<PointFeature>(); r; ++r, ++nb) {
float colorFactor = sqrt( nb + abs(r.feature()->x()) + abs(r.feature()->y()) );
float red = 1000.f * colorFactor,
g = 10000.f * colorFactor,
b = 100000.f * colorFactor;
glColor3f( red -= (int)red, g -= (int)g, b -= (int)b);
glVertex2f(xoff[r.image()] + r.feature()->x(),
yoff[r.image()] + r.feature()->y());
}
glEnd();
glColor3f( 1.0f, 1.0f, 1.0f);
}
void MatchViewer::paintGL() {
if (TexturesInited()) {
SetUpGlCamera();
for (int i = 0; i < 2; ++i) {
DrawImage(i);
}
DrawCandidateMatches();
}
}
bool MatchViewer::TexturesInited() {
return textures_[0].textureID && textures_[1].textureID
&& glIsTexture(textures_[0].textureID) && glIsTexture(textures_[1].textureID);
}
void MatchViewer::InitTextures() {
for (int i=0; i<2; ++i) {
InitTexture(i);
}
}
void MatchViewer::InitTexture(int index) {
OnScreenImage &oi = screen_images_[index];
if (index == 0) {
oi.posx = 0;
oi.posy = 0;
} else {
OnScreenImage &prev = screen_images_[index - 1];
oi.posx = prev.posx + textures_[index-1].width + 10;
oi.posy = prev.posy;
}
}
void MatchViewer::resizeGL(int width, int height) {
glViewport(0, 0, width, height);
}
int MatchViewer::ImageUnderPointer(QMouseEvent *event) {
float x, y;
PlaneFromScreen(event->x(), event->y(), &x, &y);
for (int i = 0; i < 2; ++i) {
if (ImageContains(screen_images_[i], textures_[i], x, y)) {
return i;
}
}
return -1;
}
void MatchViewer::mousePressEvent(QMouseEvent *event) {
lastPos = event->pos();
mouse_drag_behavior_ = NONE;
if (event->modifiers() & Qt::ShiftModifier) {
int i = ImageUnderPointer(event);
if (i >= 0) {
dragging_image_ = i;
mouse_drag_behavior_ = MOVE_IMAGE;
}
} else {
mouse_drag_behavior_ = MOVE_VIEW;
}
}
void MatchViewer::mouseMoveEvent(QMouseEvent *event) {
float x0, y0, x1, y1;
PlaneFromScreen(lastPos.x(), lastPos.y(), &x0, &y0);
PlaneFromScreen(event->x(), event->y(), &x1, &y1);
if (event->buttons() & Qt::LeftButton) {
if (mouse_drag_behavior_ == MOVE_IMAGE) {
screen_images_[dragging_image_].posx += x1 - x0;
screen_images_[dragging_image_].posy += y1 - y0;
updateGL();
} else if (mouse_drag_behavior_ == MOVE_VIEW) {
SetTransformation(tx + x0 - x1, ty + y0 - y1, zoom);
}
}
lastPos = event->pos();
}
void MatchViewer::wheelEvent(QWheelEvent *event) {
const float newzoom = zoom * pow(1.001, event->delta());
const float newtx = (zoom - newzoom) * event->x() + tx;
const float newty = (zoom - newzoom) * event->y() + ty;
SetTransformation(newtx, newty, newzoom);
}