2020-10-21 17:24:01 +02:00

2010 lines
74 KiB
C++

/****************************************************************************
* MeshLab o o *
* An extendible mesh processor o o *
* _ O _ *
* Copyright(C) 2005, 2009 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
#include "renderarea.h"
#include "textureeditor.h"
#include <wrap/qt/trackball.h>
#include <math.h>
#include <stdlib.h>
#define SELECTIONRECT 100
#define ORIGINRECT 200
#define MAX 100000
#define NOSEL -1
#define AREADIM 400
#define HRECT 6
RenderArea::RenderArea(QWidget *parent, QString textureName, MeshModel *m, unsigned tnum) : QGLWidget(parent)
{
// Parameters
antialiased = true;
setBackgroundRole(QPalette::Base);
setAutoFillBackground(true);
textNum = tnum;
model = m;
image = QImage();
fileName = textureName;
if(textureName != QString())
{
if (QFile(textureName).exists())
{
image = QImage(textureName);
int bestW = pow(2.0,floor(::log(double(image.width()))/::log(2.0)));
int bestH = pow(2.0,floor(::log(double(image.height()))/::log(2.0)));
QImage imgGL = image.scaled(bestW,bestH,Qt::IgnoreAspectRatio,Qt::SmoothTransformation);
QImage tmpGL = QGLWidget::convertToGLFormat(imgGL);
glGenTextures(1, &id);
image = QImage(tmpGL).mirrored(false, true);
}
else textureName = QString();
}
// Initialization
oldX = 0; oldY = 0;
viewport = vcg::Point2f(0,0);
tmpX = 0; tmpY = 0;
tb = new Trackball();
tb->center = Point3f(0, 0, 0);
tb->radius = 1;
panX = 0; panY = 0;
oldPX = 0; oldPY = 0;
posVX = 0; posVY = 0;
degenerate = false;
brush = QBrush(Qt::green);
mode = View;
oldMode = NoMode;
editMode = Scale;
origin = QPointF();
start = QPoint();
end = QPoint();
selectMode = Area;
selBit = CFaceO::NewBitFlag();
selVertBit = CVertexO::NewBitFlag();
selected = false;
selectedV = false;
vertRect = QRect(0,0,RADIUS,RADIUS);
selRect = vector<QRect>();
for (int i = 0; i < 4; i++) selRect.push_back(QRect(0,0,RECTDIM,RECTDIM));
selStart = QPoint(0,0); selEnd = QPoint(0,0);
degree = 0.0f;
highlighted = NOSEL;
pressed = NOSEL;
posX = 0; posY = 0;
oScale = QPointF(0,0);
scaleX = 1; scaleY = 1;
orX = 0; orY = 0;
initVX = 0; initVY = 0;
locked = false;
drawnPath = vector<Point2f>();
drawnPath1 = vector<Point2f>();
banList = vector<CFaceO*>();
drawP = false;
drawP1 = false;
path = vector<CVertexO*>();
path1 = vector<CVertexO*>();
zoom = 1;
rot = QImage(QString(":/images/rotate.png"));
scal = QImage(QString(":/images/scale.png"));
this->setMouseTracking(true);
this->setCursor(Qt::PointingHandCursor);
this->setAttribute(Qt::WA_NoSystemBackground);
this->setAttribute(Qt::WA_KeyCompression, true);
this->setFocusPolicy(Qt::ClickFocus);
}
RenderArea::~RenderArea()
{
//CFaceO::DeleteBitFlag(selBit);
//CVertexO::DeleteBitFlag(selVertBit);
}
// Change the Pen of the RenderArea
void RenderArea::setPen(const QPen &pen)
{
this->pen = pen;
update();
}
// Chanhe the Brush of the RenderArea
void RenderArea::setBrush(const QBrush &brush)
{
this->brush = brush;
update();
}
// Set the Antialiased property
void RenderArea::setAntialiased(bool antialiased)
{
this->antialiased = antialiased;
update();
}
// Change the background texture
void RenderArea::setTexture(QString path)
{
image = QImage(path);
fileName = path;
this->update();
}
// Returns the name of the background image
QString RenderArea::GetTextureName()
{
return fileName;
}
// Inform the render area that the model has degenerate coordinates
void RenderArea::SetDegenerate(bool deg)
{
degenerate = deg;
}
void RenderArea::paintEvent(QPaintEvent *)
{
// Init
QPainter painter(this);
painter.setPen(QPen(brush,2));
painter.setBrush(brush);
painter.setRenderHint(QPainter::Antialiasing, antialiased);
painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
tb->GetView();
tb->Apply();
maxX = 0; maxY = 0; minX = 0; minY = 0;
if (model != NULL && HasPerWedgeTexCoord(model->cm) && image != QImage())
{
glEnable(GL_COLOR_LOGIC_OP);
glEnable(GL_DEPTH_TEST);
glLineWidth(1);
for (unsigned i = 0; i < model->cm.face.size(); i++)
{
glLogicOp(GL_XOR);
glColor3f(1,1,1);
// First draw the model in u,v space
if (model->cm.face[i].WT(0).n() == textNum)
{
// While drawning, it counts the number of 'planes'
if (model->cm.face[i].WT(0).u() > maxX || model->cm.face[i].WT(1).u() > maxX || model->cm.face[i].WT(2).u() > maxX) maxX++;
if (model->cm.face[i].WT(0).v() > maxY || model->cm.face[i].WT(1).v() > maxY || model->cm.face[i].WT(2).v() > maxY) maxY++;
if (model->cm.face[i].WT(0).u() < minX || model->cm.face[i].WT(1).u() < minX || model->cm.face[i].WT(2).u() < minX) minX--;
if (model->cm.face[i].WT(0).v() < minY || model->cm.face[i].WT(1).v() < minY || model->cm.face[i].WT(2).v() < minY) minY--;
drawEdge(i); // Draw the edge of faces
glDisable(GL_COLOR_LOGIC_OP);
glColor3f(1.0f, 0.0f, 0.0f);
//if (selected && model->cm.face[i].IsUserBit(selBit)) drawSelectedFaces(i); // Draw the selected faces
if (selectedV && mode != UnifyVert) drawSelectedVertexes(i); // Draw the selected vertex
glEnable(GL_COLOR_LOGIC_OP);
}
}
if (mode == UnifyVert) drawUnifyVertexes();
glDisable(GL_LOGIC_OP);
glDisable(GL_COLOR_LOGIC_OP);
if (minX != 0 || minY != 0 || maxX != 0 || maxY != 0) drawBackground(); // Draw the background behind the model
// 2D
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0,this->width(),this->height(),0,-1,1);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glPushAttrib(GL_ENABLE_BIT);
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glDisable(GL_TEXTURE_2D);
drawAxis(&painter); // and the axis, always in first plane
drawSelectionRectangle(&painter); // Draw the rectangle of selection
if (mode != UnifyVert) drawEditRectangle(&painter);
else drawUnifyRectangles(&painter); // Draw the rectangles for unify
glDisable(GL_LOGIC_OP);
glPopAttrib();
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
// Draw blend object
glDepthMask(GL_FALSE);
glLogicOp(GL_AND);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(1.0f, 0.0f, 0.0f, 0.7f);
for (unsigned i = 0; i < model->cm.face.size(); i++)
if (selected && model->cm.face[i].IsUserBit(selBit)) drawSelectedFaces(i); // Draw the selected faces
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
}
else painter.drawText(this->visibleRegion().boundingRect().width()/2 - FMETRICX, this->visibleRegion().boundingRect().height()/2 - FMETRICY, tr("NO TEXTURE"));
painter.setPen(palette().dark().color());
painter.setBrush(Qt::NoBrush);
}
// Support methods for drawning
void RenderArea::drawSelectedVertexes(int i)
{
glDisable(GL_COLOR_LOGIC_OP);
glColor3f(1,0,0);
if (!isInside(&model->cm.face[i]))
{
for (int j = 0; j < 3; j++)
{
if(areaUV.contains(QPointF(model->cm.face[i].WT(j).u(), model->cm.face[i].WT(j).v())) && model->cm.face[i].V(j)->IsUserBit(selVertBit))
DrawCircle(QPoint((origin.x() + (cos(degree) * (model->cm.face[i].WT(j).u() - origin.x()) - sin(degree) * (model->cm.face[i].WT(j).v() - origin.y()))) * AREADIM - posVX/zoom,
(AREADIM - ((origin.y() + (sin(degree) * (model->cm.face[i].WT(j).u() - origin.x()) + cos(degree) * (model->cm.face[i].WT(j).v() - origin.y())))) * AREADIM) - posVY/zoom));
}
}
glColor3f(0,0,0);
glEnable(GL_COLOR_LOGIC_OP);
}
void RenderArea::drawSelectedFaces(int i)
{
glBegin(GL_TRIANGLES);
for (int j = 0; j < 3; j++)
{
if (editMode == Scale)
glVertex3f((oScale.x() + (model->cm.face[i].WT(j).u() - oScale.x()) * scaleX) * AREADIM - panX/zoom,
AREADIM - ((oScale.y() + (model->cm.face[i].WT(j).v() - oScale.y()) * scaleY) * AREADIM) - panY/zoom, 1);
else glVertex3f((origin.x() + (cos(degree) * (model->cm.face[i].WT(j).u() - origin.x()) - sin(degree) * (model->cm.face[i].WT(j).v() - origin.y()))) * AREADIM - panX/zoom,
AREADIM - ((origin.y() + (sin(degree) * (model->cm.face[i].WT(j).u() - origin.x()) + cos(degree) * (model->cm.face[i].WT(j).v() - origin.y()))) * AREADIM) - panY/zoom, 1);
}
glEnd();
}
void RenderArea::drawEdge(int i)
{
glBegin(GL_LINE_LOOP);
for (int j = 0; j < 3; j++)
{
if (mode != EditVert)
{
if (!model->cm.face[i].IsUserBit(selBit))
glVertex3f(model->cm.face[i].WT(j).u() * AREADIM , AREADIM - (model->cm.face[i].WT(j).v() * AREADIM), 1);
else if (editMode == Scale) glVertex3f((oScale.x() + (model->cm.face[i].WT(j).u() - oScale.x()) * scaleX) * AREADIM - panX/zoom,
AREADIM - ((oScale.y() + (model->cm.face[i].WT(j).v() - oScale.y()) * scaleY) * AREADIM) - panY/zoom, 1);
else glVertex3f((origin.x() + (cos(degree) * (model->cm.face[i].WT(j).u() - origin.x()) - sin(degree) * (model->cm.face[i].WT(j).v() - origin.y()))) * AREADIM - panX/zoom,
AREADIM - ((origin.y() + (sin(degree) * (model->cm.face[i].WT(j).u() - origin.x()) + cos(degree) * (model->cm.face[i].WT(j).v() - origin.y()))) * AREADIM) - panY/zoom, 1);
}
else
{
if (areaUV.contains(QPointF(model->cm.face[i].WT(j).u(), model->cm.face[i].WT(j).v())) && model->cm.face[i].V(j)->IsUserBit(selVertBit) && !isInside(&model->cm.face[i]))
glVertex3f((origin.x() + (cos(degree) * (model->cm.face[i].WT(j).u() - origin.x()) - sin(degree) * (model->cm.face[i].WT(j).v() - origin.y()))) * AREADIM - posVX/zoom,
AREADIM - ((origin.y() + (sin(degree) * (model->cm.face[i].WT(j).u() - origin.x()) + cos(degree) * (model->cm.face[i].WT(j).v() - origin.y()))) * AREADIM) - posVY/zoom, 1);
else glVertex3f(model->cm.face[i].WT(j).u() * AREADIM , AREADIM - (model->cm.face[i].WT(j).v() * AREADIM), 1);
}
}
glEnd();
}
void RenderArea::drawUnifyVertexes()
{
glDisable(GL_COLOR_LOGIC_OP);
glColor3f(1,0,0);
if (uvertA != QPoint()) DrawCircle(QPoint((origin.x() + (cos(degree) * (tua - origin.x()) - sin(degree) * (tva - origin.y()))) * AREADIM - posVX/zoom,
AREADIM - ((origin.y() + (sin(degree) * (tua - origin.x()) + cos(degree) * (tva - origin.y()))) * AREADIM) - posVY/zoom));
if (uvertB != QPoint()) DrawCircle(QPoint((origin.x() + (cos(degree) * (tub - origin.x()) - sin(degree) * (tvb - origin.y()))) * AREADIM - posVX/zoom,
AREADIM - ((origin.y() + (sin(degree) * (tub - origin.x()) + cos(degree) * (tvb - origin.y()))) * AREADIM) - posVY/zoom));
if (uvertA1 != QPoint()) DrawCircle(QPoint((origin.x() + (cos(degree) * (tua1 - origin.x()) - sin(degree) * (tva1 - origin.y()))) * AREADIM - posVX/zoom,
AREADIM - ((origin.y() + (sin(degree) * (tua1 - origin.x()) + cos(degree) * (tva1 - origin.y()))) * AREADIM) - posVY/zoom));
if (uvertB1 != QPoint()) DrawCircle(QPoint((origin.x() + (cos(degree) * (tub1 - origin.x()) - sin(degree) * (tvb1 - origin.y()))) * AREADIM - posVX/zoom,
AREADIM - ((origin.y() + (sin(degree) * (tub1 - origin.x()) + cos(degree) * (tvb1 - origin.y()))) * AREADIM) - posVY/zoom));
glColor3f(0,0,0);
glEnable(GL_COLOR_LOGIC_OP);
}
void RenderArea::drawBackground()
{
glColor3f(1,1,1);
glBindTexture(GL_TEXTURE_2D, id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, image.bits());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, image.width(), image.height(), GL_RGBA, GL_UNSIGNED_BYTE, image.bits());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glEnable(GL_TEXTURE_2D);
for (int x = minX; x < maxX; x++)
{
for (int y = minY; y < maxY; y++)
{
glBegin(GL_QUADS);
glTexCoord2f(0.0,0.0);
glVertex3f(0.0 + x*AREADIM,0.0 - y*AREADIM,0.0);
glTexCoord2f(1.0,0.0);
glVertex3f(1.0*AREADIM + x*AREADIM,0.0 - y*AREADIM,0.0);
glTexCoord2f(1.0,1.0);
glVertex3f(1.0*AREADIM + x*AREADIM,1.0*AREADIM - y*AREADIM,0.0);
glTexCoord2f(0.0,1.0);
glVertex3f(0.0 + x*AREADIM,1.0*AREADIM - y*AREADIM,0.0);
glEnd();
}
}
glDisable(GL_TEXTURE_2D);
}
void RenderArea::drawAxis(QPainter* painter)
{
// Line and text (native Qt)
int w = this->visibleRegion().boundingRect().width();
int h = this->visibleRegion().boundingRect().height();
painter->drawLine(0,h,w,h);
painter->drawLine(0,h,0,0);
// Calculate the coords and draw it
float ox = (float)-viewport.X()*zoom/(AREADIM*zoom), oy = (float)(AREADIM*zoom - h + viewport.Y()*zoom)/(AREADIM*zoom);
/*O:*/painter->drawText(TRANSLATE, h - TRANSLATE, QString("(%1,%2)").arg(ox).arg(oy));
/*Y:*/painter->drawText(TRANSLATE, TRANSLATE*3, QString("(%1,%2)").arg(ox).arg((float)(AREADIM*zoom + viewport.Y()*zoom)/(AREADIM*zoom)));
/*X:*/painter->drawText(w - TRANSLATE*18, h - TRANSLATE, QString("(%1,%2)").arg((float)(w-viewport.X()*zoom)/(AREADIM*zoom)).arg(oy));
painter->drawText(TRANSLATE, TRANSLATE*6, QString("V"));
painter->drawText(w - TRANSLATE*23, h - TRANSLATE, QString("U"));
}
void RenderArea::drawSelectionRectangle(QPainter *painter)
{
if (start != QPoint() && end != QPoint())
{
painter->setPen(QPen(QBrush(Qt::gray),1));
painter->setBrush(QBrush(Qt::NoBrush));
painter->drawRect(area);
}
}
void RenderArea::drawEditRectangle(QPainter *painter)
{
if (selection != QRect() && (mode == Edit || mode == EditVert))
{
// The rectangle of editing
painter->setPen(QPen(QBrush(Qt::yellow),2));
painter->setBrush(QBrush(Qt::NoBrush));
if (mode == Edit) painter->drawRect(QRect(selection.x() - posX, selection.y() - posY, selection.width(), selection.height()));
else painter->drawRect(QRect(selection.x() - posVX, selection.y() - posVY, selection.width(), selection.height()));
if (mode == Edit || (mode == EditVert && VCount > 1))
{
// Rectangle on the corner
painter->setPen(QPen(QBrush(Qt::black),1));
for (unsigned l = 0; l < selRect.size(); l++)
{
if (l == highlighted) painter->setBrush(QBrush(Qt::yellow));
else painter->setBrush(QBrush(Qt::NoBrush));
painter->drawRect(selRect[l]);
if (editMode == Scale && mode == Edit) painter->drawImage(selRect[l],scal,QRect(0,0,scal.width(),scal.height()));
else painter->drawImage(selRect[l],rot,QRect(0,0,rot.width(),rot.height()));
}
// and the origin of the rotation
if ((editMode == Rotate && mode == Edit) || mode == EditVert)
{
painter->setPen(QPen(QBrush(Qt::black),1));
if (highlighted == ORIGINRECT) painter->setBrush(QBrush(Qt::blue));
else painter->setBrush(QBrush(Qt::yellow));
if (mode == Edit) painter->drawEllipse(QRect(originR.x() - posX - orX, originR.y() - posY - orY, RADIUS, RADIUS));
else painter->drawEllipse(QRect(originR.x() - posVX - orX, originR.y() - posVY - orY, RADIUS, RADIUS));
}
}
}
}
void RenderArea::drawUnifyRectangles(QPainter *painter)
{
if (unifyRA != QRect())
{
painter->setPen(QPen(QBrush(Qt::blue),1));
painter->setBrush(QBrush(Qt::NoBrush));
painter->drawRect(unifyRA);
painter->drawText(unifyRA.center().x() - RADIUS*2, unifyRA.center().y(), tr("A"));
}
if (unifyRB != QRect())
{
painter->drawRect(unifyRB);
painter->drawText(unifyRB.center().x() - RADIUS*2, unifyRB.center().y(), tr("B"));
}
if (unifyRA != QRect() && unifyRB != QRect()) painter->drawLine(unifyRA.center(), unifyRB.center());
if (unifyRA1 != QRect())
{
painter->drawRect(unifyRA1);
painter->drawText(unifyRA1.center().x() - RADIUS*2, unifyRA1.center().y(), tr("A'"));
}
if (unifyRB1 != QRect())
{
painter->drawRect(unifyRB1);
painter->drawText(unifyRB1.center().x() - RADIUS*2, unifyRB1.center().y(), tr("B'"));
}
if (unifyRA1 != QRect() && unifyRB1 != QRect()) painter->drawLine(unifyRA1.center(), unifyRB1.center());
if (drawP)
{
painter->setPen(QPen(QBrush(Qt::red),2));
for (unsigned k = 0; k < drawnPath.size()-1; k++)
painter->drawLine(ToScreenSpace(drawnPath[k].X(), drawnPath[k].Y()), ToScreenSpace(drawnPath[k+1].X(),drawnPath[k+1].Y()));
}
if (drawP1)
{
for (unsigned k = 0; k < drawnPath1.size()-1; k++)
painter->drawLine(ToScreenSpace(drawnPath1[k].X(), drawnPath1[k].Y()), ToScreenSpace(drawnPath1[k+1].X(),drawnPath1[k+1].Y()));
}
}
// Mouse Event:
void RenderArea::mousePressEvent(QMouseEvent *e)
{
if((e->buttons() & Qt::LeftButton))
{
if ((mode == Edit || mode == EditVert) && highlighted == NOSEL)
{
this->ChangeMode(SPECIALMODE);
pressed = NOSEL;
selected = false;
selectedV = false;
selVertBit = CVertexO::NewBitFlag();
for (unsigned i = 0; i < model->cm.face.size(); i++) model->cm.face[i].ClearUserBit(selBit);
}
switch(mode)
{
case View:
handlePressView(e);
break;
case Edit:
handlePressEdit(e);
break;
case EditVert:
handlePressEdit(e);
break;
case Select:
handlePressSelect(e);
break;
case UnifyVert:
handlePressSelect(e);
break;
}
}
else if((e->buttons() & Qt::MidButton))
{
// Pan
oldMode = mode;
this->ChangeMode(VIEWMODE);
oldX = e->x(); oldY = e->y();
tmpX = viewport.X(); tmpY = viewport.Y();
tb->MouseDown(e->x(), AREADIM-e->y(), QT2VCG(e->button(), e->modifiers()));
this->update();
}
}
void RenderArea::handlePressView(QMouseEvent *e)
{
oldX = e->x(); oldY = e->y();
tmpX = viewport.X(); tmpY = viewport.Y();
tb->MouseDown(e->x(), AREADIM-e->y(), QT2VCG(e->button(), e->modifiers()));
this->update();
}
void RenderArea::handlePressSelect(QMouseEvent *e)
{
start = e->pos();
end = e->pos();
}
void RenderArea::handlePressEdit(QMouseEvent *e)
{
tpanX = e->x();
tpanY = e->y();
pressed = highlighted;
if (highlighted > NOSEL && highlighted < selRect.size())
{
rectX = selRect[highlighted].center().x();
rectY = selRect[highlighted].center().y();
if (mode == Edit)
{
oldSRX = selection.width();
oldSRY = selection.height();
scaleX = 1; scaleY = 1;
}
int perno;
if (highlighted == 0) perno = 3;
else if (highlighted == 1) perno = 2;
else if (highlighted == 2) perno = 1;
else perno = 0;
oScale = ToUVSpace(selRect[perno].center().x(), selRect[perno].center().y());
B2 = (float)(rectX - originR.center().x())*(rectX - originR.center().x()) + (rectY - originR.center().y())*(rectY - originR.center().y());
Rm = (float)(rectY - originR.center().y()) / (rectX - originR.center().x());
Rq = (float) rectY - Rm * rectX;
}
}
void RenderArea::mouseReleaseEvent(QMouseEvent *e)
{
switch(mode)
{
case View:
handleReleaseView(e);
break;
case Edit:
handleReleaseEdit(e);
break;
case EditVert:
handleReleaseEdit(e);
break;
case Select:
handleReleaseSelect(e);
break;
case UnifyVert:
area = QRect();
locked = false;
if (unifyRB1 != QRect()) UnifySet();
this->update();
break;
}
}
void RenderArea::handleReleaseView(QMouseEvent *e)
{
if (selection != QRect())
{
UpdateSelectionArea((viewport.X() - initVX)*zoom, (viewport.Y() - initVY)*zoom);
originR.moveCenter(QPoint(originR.x() + (viewport.X() - initVX)*zoom, originR.y() + (viewport.Y() - initVY)*zoom));
origin = ToUVSpace(originR.center().x(), originR.center().y());
}
initVX = viewport.X(); initVY = viewport.Y();
if (oldMode != NoMode)
{
this->ChangeMode(oldMode);
oldMode = NoMode;
}
}
void RenderArea::handleReleaseEdit(QMouseEvent *e)
{
oldPX = panX;
oldPY = panY;
if (pressed == ORIGINRECT) // Drag origin -> Update the position of the rectangle of rotation and the real point in UV
{
originR = QRect(originR.x() - posX - orX, originR.y() - posY - orY, RADIUS, RADIUS);
origin = ToUVSpace(originR.center().x(), originR.center().y());
orX = 0; orY = 0;
}
else if (pressed == SELECTIONRECT)
{
if (mode == Edit && posX != 0) // Drag selection -> Update the position of the selection area and the rotatation rect
{
selection = QRect(selection.x() - posX, selection.y() - posY, selection.width(), selection.height());
originR.moveCenter(QPoint(originR.center().x() - posX, originR.center().y() - posY));
origin = ToUVSpace(originR.center().x(), originR.center().y());
posX = 0; posY = 0;
if (selected) UpdateUV();
}
else if (mode == EditVert && posVX != 0)
{
selection = QRect(selection.x() - posVX, selection.y() - posVY, selection.width(), selection.height());
originR.moveCenter(QPoint(originR.center().x() - posVX, originR.center().y() - posVY));
origin = ToUVSpace(originR.center().x(), originR.center().y());
if (selectedV) UpdateVertex();
}
}
else if (pressed > NOSEL && pressed < selRect.size())
{
if (editMode == Rotate && mode == Edit)
{
RotateComponent(degree);
RecalculateSelectionArea();
degree = 0;
}
else if (scaleX != 1 && scaleY != 1 && mode == Edit)
{
ScaleComponent(scaleX, scaleY);
RecalculateSelectionArea();
scaleX = 1;
scaleY = 1;
oScale = QPointF(0,0);
}
else if (mode == EditVert)
{
selStart = QPoint(MAX,MAX);
selEnd = QPoint(-MAX,-MAX);
RotateComponent(degree);
selection = QRect(QPoint(selStart.x() - VRADIUS, selStart.y() - VRADIUS), QPoint(selEnd.x() + VRADIUS, selEnd.y() + VRADIUS));
QPointF a = ToUVSpace(selection.x(), selection.y());
QPointF b = ToUVSpace(selection.bottomRight().x(),selection.bottomRight().y());
areaUV = QRectF(a, QSizeF(b.x()-a.x(), b.y()-a.y()));
UpdateSelectionAreaV(0,0);
degree = 0;
}
}
}
void RenderArea::handleReleaseSelect(QMouseEvent *e)
{
start = QPoint();
end = QPoint();
area = QRect();
switch (selectMode)
{
case Area:
if (selected)
{
selection = QRect(selStart, selEnd);
UpdateSelectionArea(0,0);
origin = ToUVSpace(selection.center().x(), selection.center().y());
originR = QRect(selection.center().x()-RADIUS/2, selection.center().y()-RADIUS/2, RADIUS, RADIUS);
this->ChangeMode(EDITFACEMODE);
this->ShowFaces();
}
break;
case Connected:
SelectConnectedComponent(e->pos());
if (selected)
{
selection = QRect(selStart, selEnd);
UpdateSelectionArea(0,0);
RecalculateSelectionArea();
origin = ToUVSpace(selection.center().x(), selection.center().y());
originR = QRect(selection.center().x()-RADIUS/2, selection.center().y()-RADIUS/2, RADIUS, RADIUS);
this->ChangeMode(EDITFACEMODE);
this->ShowFaces();
}
break;
case Vertex:
if (selectedV)
{
CountVertexes();
selection = QRect(QPoint(selStart.x() - RADIUS/2, selStart.y() - RADIUS/2), QPoint(selEnd.x() + RADIUS/2, selEnd.y() + RADIUS/2));
if (VCount > 1)
{
UpdateSelectionAreaV(0,0);
origin = ToUVSpace(selection.center().x(), selection.center().y());
originR = QRect(selection.center().x()-RADIUS/2, selection.center().y()-RADIUS/2, RADIUS, RADIUS);
}
this->ChangeMode(EDITVERTEXMODE);
}
break;
}
this->update();
}
void RenderArea::mouseMoveEvent(QMouseEvent *e)
{
int sx = (e->x() - oldX)/zoom, sy = (e->y() - oldY)/zoom;
if((e->buttons() & Qt::LeftButton) && image != QImage())
{
if (mode == View)
{
tb->Translate(Point3f(- oldX + e->x(), - oldY + e->y(), zoom));
viewport = Point2f(tmpX + sx, tmpY + sy);
this->update();
}
else if (mode == Edit || mode == EditVert) handleMoveEdit(e);
else if (mode == Select || mode == UnifyVert) handleMoveSelect(e);
}
else if((e->buttons() & Qt::MidButton) && image != QImage()) // Pan
{
tb->Translate(Point3f(- oldX + e->x(), - oldY + e->y(), zoom));
viewport = Point2f(tmpX + sx, tmpY + sy);
this->update();
}
else if (image != QImage())// No click
{
if (mode == Edit || mode == EditVert)
{
for (unsigned y = 0; y < selRect.size(); y++)
{
if (selRect[y].contains(e->pos()) && (mode == Edit || (mode == EditVert && VCount > 1)))
{
if (highlighted != y) this->update(selRect[y]);
highlighted = y;
return;
}
}
if (originR.contains(e->pos()) && ((mode == Edit && editMode == Rotate) || mode == EditVert))
{
if (highlighted != ORIGINRECT) this->update(originR);
highlighted = ORIGINRECT;
return;
}
if (selection.contains(e->pos()))
{
if (highlighted == ORIGINRECT) this->update(originR);
else if (highlighted < selRect.size()) this->update(selRect[highlighted]);
highlighted = SELECTIONRECT;
return;
}
if (highlighted != NOSEL)
{
if (highlighted == ORIGINRECT) this->update(originR);
else if (highlighted < selRect.size()) this->update(selRect[highlighted]);
}
highlighted = NOSEL;
}
}
}
void RenderArea::handleMoveEdit(QMouseEvent *e)
{
int tX = tpanX - e->x();
int tY = tpanY - e->y();
if (pressed == SELECTIONRECT)
{
// Move the selection ara
if (mode == Edit)
{
panX = oldPX + tpanX - e->x();
panY = oldPY + tpanY - e->y();
}
if (tX != 0 || tY != 0)
{
QPoint ta = QPoint(selection.topLeft().x() - tX, selection.topLeft().y() - tY);
QPoint tb = QPoint(selection.topRight().x() - tX, selection.topRight().y() - tY);
QPoint tc = QPoint(selection.bottomLeft().x() - tX, selection.bottomLeft().y() - tY);
QPoint td = QPoint(selection.bottomRight().x() - tX, selection.bottomRight().y() - tY);
if (mode == Edit)
{
posX = tX; posY = tY;
selRect[0].moveCenter(ta); selRect[1].moveCenter(tb);
selRect[2].moveCenter(tc); selRect[3].moveCenter(td);
}
else
{
posVX = tX; posVY = tY;
selRect[0].moveBottomRight(ta); selRect[1].moveBottomLeft(tb);
selRect[2].moveTopRight(tc); selRect[3].moveTopLeft(td);
}
}
}
else if (pressed == ORIGINRECT)
{
orX = tX;
orY = tY;
this->update(originR);
}
else if (pressed > NOSEL && pressed < selRect.size())
{
if (editMode == Scale && mode == Edit) HandleScale(e->pos());
else HandleRotate(e->pos());
}
this->update();
}
void RenderArea::handleMoveSelect(QMouseEvent *e)
{
if ((mode == Select && selectMode != Connected) || mode == UnifyVert)
{
end = e->pos();
int x1, x2, y1, y2;
if (start.x() < end.x()) {x1 = start.x(); x2 = end.x();} else {x1 = end.x(); x2 = start.x();}
if (start.y() < end.y()) {y1 = start.y(); y2 = end.y();} else {y1 = end.y(); y2 = start.y();}
area = QRect(x1,y1,x2-x1,y2-y1);
if (mode == Select)
{
if (selectMode == Area) SelectFaces();
else SelectVertexes();
}
else if (!locked) SelectVertexes();
this->update();
}
}
void RenderArea::mouseDoubleClickEvent(QMouseEvent *e)
{
switch(mode)
{
case View: // Center the screen on the mouse click position
viewport = Point2f(viewport.X() - e->x()/zoom + (this->visibleRegion().boundingRect().width()/zoom)/2,
viewport.Y() - e->y()/zoom + (this->visibleRegion().boundingRect().height()/zoom)/2);
oldX = 0; oldY = 0;
tb->track.SetTranslate(Point3f(viewport.X(), viewport.Y(), 1));
tb->Scale(zoom);
this->update();
break;
case Edit: // Change edit mode
if (selection.contains(e->pos()))
{
if (editMode == Rotate) editMode = Scale;
else editMode = Rotate;
this->update();
}
break;
}
}
void RenderArea::wheelEvent(QWheelEvent*e)
{
if (image != QImage())
{
// Handle the zoom for any mode
int cwx = viewport.X() - (this->visibleRegion().boundingRect().width()/zoom)/2;
int cwy = viewport.Y() - (this->visibleRegion().boundingRect().height()/zoom)/2;
if (e->delta() > 0) zoom /= 0.75;
else zoom *= 0.75;
// Change the viewport, putting the center of the screen on the mouseposition
cwx += (this->visibleRegion().boundingRect().width()/zoom)/2;
cwy += (this->visibleRegion().boundingRect().height()/zoom)/2;
viewport = Point2f(cwx, cwy);
ResetTrack(false);
tb->Scale(zoom);
if (selectedV)
{
if (mode == UnifyVert) UpdateUnify();
else UpdateVertexSelection();
}
else if (selected) RecalculateSelectionArea();
originR.moveCenter(ToScreenSpace(origin.x(), origin.y()));
initVX = viewport.X(); initVY = viewport.Y();
this->update();
}
}
void RenderArea::keyPressEvent(QKeyEvent *e)
{
if (e->key() == Qt::Key_H) ResetPosition();
else e->ignore();
}
// Remap the uv coord out of border using clamp method
void RenderArea::RemapClamp()
{
for (unsigned i = 0; i < model->cm.face.size(); i++)
{
if (model->cm.face[i].WT(0).n() == textNum && !model->cm.face[i].IsD())
{
model->cm.face[i].ClearUserBit(selBit);
for (unsigned j = 0; j < 3; j++)
{
if (model->cm.face[i].WT(j).u() > 1) model->cm.face[i].WT(j).u() = 1;
else if (model->cm.face[i].WT(j).u() < 0) model->cm.face[i].WT(j).u() = 0;
if (model->cm.face[i].WT(j).v() > 1) model->cm.face[i].WT(j).v() = 1;
else if (model->cm.face[i].WT(j).v() < 0) model->cm.face[i].WT(j).v() = 0;
}
}
}
panX = 0; panY = 0; tpanX = 0; tpanY = 0; oldPX = 0; oldPY = 0;
ResetTrack(true);
vcg::tri::UpdateTopology<CMeshO>::FaceFaceFromTexCoord(model->cm);
selection = QRect();
this->update();
emit UpdateModel();
}
// Remap the uv coord out of border using mod function
void RenderArea::RemapMod()
{
for (unsigned i = 0; i < model->cm.face.size(); i++)
{
if (model->cm.face[i].WT(0).n() == textNum && !model->cm.face[i].IsD())
{
model->cm.face[i].ClearUserBit(selBit);
for (unsigned j = 0; j < 3; j++)
{
float u = model->cm.face[i].WT(j).u();
float v = model->cm.face[i].WT(j).v();
if (u < 0) u = u + (int)u + 1;
else if (u > 1) u = u - (int)u;
if (v < 0) v = v + (int)v + 1;
else if (v > 1) v = v - (int)v;
model->cm.face[i].WT(j).u() = u;
model->cm.face[i].WT(j).v() = v;
}
}
}
panX = 0; panY = 0; tpanX = 0; tpanY = 0; oldPX = 0; oldPY = 0;
ResetTrack(true);
vcg::tri::UpdateTopology<CMeshO>::FaceFaceFromTexCoord(model->cm);
selection = QRect();
this->update();
emit UpdateModel();
}
// Change the tool's action mode
void RenderArea::ChangeMode(int modenumber)
{
if (mode == UnifyVert && modenumber != UNIFYMODE)
{
resetUnifyData();
drawnPath.clear(); drawnPath1.clear();
drawP = false; drawP1 = false;
}
switch(modenumber)
{
case VIEWMODE:
if (mode != View)
{
mode = View;
this->setCursor(Qt::PointingHandCursor);
}
break;
case EDITFACEMODE:
if (mode != Edit)
{
mode = Edit;
highlighted = SELECTIONRECT;
this->setCursor(Qt::SizeAllCursor);
}
break;
case SELECTMODE:
if (mode != Select)
{
if (selection != QRect())
{
if (selectMode == Vertex)
{
mode = EditVert; selectedV = true;
UpdateSelectionAreaV(0,0);
for (unsigned i = 0; i < model->cm.face.size(); i++) model->cm.face[i].ClearUserBit(selBit);
}
else
{
mode = Edit; selected = true;
for (unsigned i = 0; i < model->cm.vert.size(); i++) model->cm.vert[i].ClearUserBit(selVertBit);
}
this->setCursor(Qt::SizeAllCursor);
}
else
{
mode = Select;
for (unsigned i = 0; i < model->cm.face.size(); i++)
{
model->cm.face[i].ClearUserBit(selBit); model->cm.face[i].ClearS();
}
for (unsigned i = 0; i < model->cm.vert.size(); i++) model->cm.vert[i].ClearUserBit(selVertBit);
emit UpdateModel();
this->setCursor(Qt::CrossCursor);
}
}
break;
case SPECIALMODE: // For internal use... reset the selection
mode = Select;
for (unsigned i = 0; i < model->cm.face.size(); i++)
{
model->cm.face[i].ClearUserBit(selBit); model->cm.face[i].ClearS();
}
selection = QRect();
this->setCursor(Qt::CrossCursor);
emit UpdateModel();
break;
case EDITVERTEXMODE:
if (mode != EditVert)
{
if (selection != QRect())
{
mode = EditVert; selectedV = true;
this->setCursor(Qt::SizeAllCursor);
}
else
{
mode = Select;
this->setCursor(Qt::CrossCursor);
}
}
break;
case UNIFYMODE:
if (mode != UnifyVert)
{
mode = UnifyVert;
resetUnifyData();
if (selected) {for (unsigned i = 0; i < model->cm.face.size(); i++) model->cm.face[i].ClearS();}
selection = QRect(); selected = false; selectedV = false;
for (unsigned i = 0; i < model->cm.face.size(); i++) model->cm.face[i].ClearUserBit(selBit);
selVertBit = CVertexO::NewBitFlag();
this->setCursor(Qt::CrossCursor);
model->updateDataMask(MeshModel::MM_VERTFACETOPO | MeshModel::MM_FACEFACETOPO);
//model->cm.face.EnableVFAdjacency();
//model->cm.vert.EnableVFAdjacency();
//model->cm.face.EnableFFAdjacency();
UpdateUnifyTopology();
}
break;
}
this->update();
}
void RenderArea::resetUnifyData()
{
unifyRA = QRect();
unifyRA1 = QRect();
unifyRB = QRect();
unifyRB1 = QRect();
uvertA = QPoint();
uvertA1 = QPoint();
uvertB = QPoint();
uvertB1 = QPoint();
}
// Change the selection function
void RenderArea::ChangeSelectMode(int selectindex)
{
switch(selectindex)
{
case SELECTAREA:
if (selectMode != Area && selectMode != Connected) selection = QRect();
selectMode = Area;
break;
case SELECTCONNECTED:
if (selectMode != Connected && selectMode != Area) selection = QRect();
selectMode = Connected;
break;
case SELECTVERTEX:
if (selectMode != Vertex) selection = QRect();
selectMode = Vertex;
break;
default:
selectMode = Area;
break;
}
if (selectedV && selectMode != Vertex)
{
areaUV = QRectF();
selVertBit = CVertexO::NewBitFlag();
selectedV = false;
}
if (selected && selectMode == Vertex)
{
selected = false;
//selBit = CFaceO::NewBitFlag();
for (unsigned i = 0; i < model->cm.face.size(); i++) model->cm.face[i].ClearUserBit(selBit);
for (unsigned i = 0; i < model->cm.face.size(); i++) model->cm.face[i].ClearS();
emit UpdateModel();
}
}
void RenderArea::RotateComponent(float theta)
{
// Calcolate the new position of the vertex of the selected component after a rotation.
// The rotation is done around the selected point
if (origin != QPoint())
{
float sinv = sin(theta);
float cosv = cos(theta);
if (selected)
{
for (unsigned i = 0; i < model->cm.face.size(); i++)
{
if (model->cm.face[i].WT(0).n() == textNum && !model->cm.face[i].IsD() && (!selected || (selected && model->cm.face[i].IsUserBit(selBit))))
for (unsigned j = 0; j < 3; j++)
{
float u = origin.x() + (cosv * (model->cm.face[i].WT(j).u() - origin.x()) - sinv * (model->cm.face[i].WT(j).v() - origin.y()));
float v = origin.y() + (sinv * (model->cm.face[i].WT(j).u() - origin.x()) + cosv * (model->cm.face[i].WT(j).v() - origin.y()));
model->cm.face[i].WT(j).u() = u;
model->cm.face[i].WT(j).v() = v;
}
}
}
else if (selectedV)
{
for (unsigned i = 0; i < model->cm.face.size(); i++)
{
for (unsigned j = 0; j < 3; j++)
{
if (areaUV.contains(QPointF(model->cm.face[i].WT(j).u(),model->cm.face[i].WT(j).v()))
&& model->cm.face[i].V(j)->IsUserBit(selVertBit) && !model->cm.face[i].V(j)->IsD())
{
float u = origin.x() + (cosv * (model->cm.face[i].WT(j).u() - origin.x()) - sinv * (model->cm.face[i].WT(j).v() - origin.y()));
float v = origin.y() + (sinv * (model->cm.face[i].WT(j).u() - origin.x()) + cosv * (model->cm.face[i].WT(j).v() - origin.y()));
model->cm.face[i].WT(j).u() = u;
model->cm.face[i].WT(j).v() = v;
QPoint tmp = ToScreenSpace(u, v);
UpdateBoundingArea(tmp,tmp);
}
}
}
}
this->update();
emit UpdateModel();
}
}
void RenderArea::ScaleComponent(float percX, float percY)
{
// Scale the selected component. The origin is set to the clicked point
for (unsigned i = 0; i < model->cm.face.size(); i++)
{
if (model->cm.face[i].WT(0).n() == textNum && selected && model->cm.face[i].IsUserBit(selBit) && !model->cm.face[i].IsD())
for (unsigned j = 0; j < 3; j++)
{
float x = oScale.x() + (model->cm.face[i].WT(j).u() - oScale.x()) * percX;
float y = oScale.y() + (model->cm.face[i].WT(j).v() - oScale.y()) * percY;
model->cm.face[i].WT(j).u() = x;
model->cm.face[i].WT(j).v() = y;
}
}
this->update();
emit UpdateModel();
}
void RenderArea::UpdateUV()
{
// After a move of component, re-calculate the new UV coordinates
for (unsigned i = 0; i < model->cm.face.size(); i++)
{
if (model->cm.face[i].WT(0).n() == textNum && model->cm.face[i].IsUserBit(selBit) && !model->cm.face[i].IsD())
{
for (unsigned j = 0; j < 3; j++)
{
model->cm.face[i].WT(j).u() = model->cm.face[i].WT(j).u() - (float)panX/(AREADIM*zoom);
model->cm.face[i].WT(j).v() = model->cm.face[i].WT(j).v() + (float)panY/(AREADIM*zoom);
}
}
}
panX = 0; panY = 0; tpanX = 0; tpanY = 0; oldPX = 0; oldPY = 0;
this->update();
emit UpdateModel();
}
void RenderArea::UpdateVertex()
{
// After a move of vertex, re-calculate the new UV coordinates
for (unsigned i = 0; i < model->cm.face.size(); i++)
{
if (!isInside(&model->cm.face[i]))
{
for (unsigned j = 0; j < 3; j++)
{
if (areaUV.contains(QPointF(model->cm.face[i].WT(j).u(),model->cm.face[i].WT(j).v()))
&& model->cm.face[i].V(j)->IsUserBit(selVertBit) && !model->cm.face[i].V(j)->IsD())
{
model->cm.face[i].WT(j).u() = model->cm.face[i].WT(j).u() - (float)posVX/(AREADIM*zoom);
model->cm.face[i].WT(j).v() = model->cm.face[i].WT(j).v() + (float)posVY/(AREADIM*zoom);
}
}
}
}
areaUV.moveCenter(QPointF(areaUV.center().x() - (float)posVX/(AREADIM*zoom), areaUV.center().y() + (float)posVY/(AREADIM*zoom)));
tpanX = 0; tpanY = 0; posVX = 0; posVY = 0;
this->update();
emit UpdateModel();
}
void RenderArea::ResetTrack(bool resetViewPort)
{
// Reset the viewport of the trackball
tb->center = Point3f(0, 0, 0);
tb->track.SetScale(1);
if (resetViewPort) viewport = Point2f(0,0);
oldX = 0; oldY = 0;
tb->track.SetTranslate(Point3f(viewport.X(), viewport.Y(), 1));
}
void RenderArea::SelectFaces()
{
// Check if a face is inside the rectangle of selection and mark it
selStart = QPoint(MAX,MAX);
selEnd = QPoint(-MAX,-MAX);
selected = false;
selection = QRect();
CMeshO::FaceIterator fi;
for(fi = model->cm.face.begin(); fi != model->cm.face.end(); ++fi)
{
if ((*fi).WT(0).n() == textNum && !(*fi).IsD())
{
(*fi).ClearUserBit(selBit);
QVector<QPoint> t = QVector<QPoint>();
t.push_back(ToScreenSpace((*fi).WT(0).u(), (*fi).WT(0).v()));
t.push_back(ToScreenSpace((*fi).WT(1).u(), (*fi).WT(1).v()));
t.push_back(ToScreenSpace((*fi).WT(2).u(), (*fi).WT(2).v()));
QRegion r = QRegion(QPolygon(t));
if (r.intersects(area))
{
(*fi).SetUserBit(selBit);
UpdateBoundingArea(r.boundingRect().topLeft(), r.boundingRect().bottomRight());
if (!selected) selected = true;
}
}
}
}
void RenderArea::SelectVertexes()
{
// Check if a vertex is inside the rectangle of selection
selStart = QPoint(MAX,MAX);
selEnd = QPoint(-MAX,-MAX);
selectedV = false;
selection = QRect();
QPointF a = ToUVSpace(area.x(), area.y());
QPointF b = ToUVSpace(area.bottomRight().x(),area.bottomRight().y());
areaUV = QRectF(a, QSizeF(b.x()-a.x(), b.y()-a.y()));
CMeshO::FaceIterator fi;
for(fi = model->cm.face.begin(); fi != model->cm.face.end(); ++fi)
{
if ((*fi).WT(0).n() == textNum && !(*fi).IsD())
{
for (int j = 0; j < 3; j++)
{
QPoint tmp = ToScreenSpace((*fi).WT(j).u(), (*fi).WT(j).v());
if (area.contains(tmp))
{
(*fi).V(j)->SetUserBit(selVertBit);
UpdateBoundingArea(tmp, tmp);
if (!selectedV) selectedV = true;
if (mode == UnifyVert && !locked)
{
locked = true;
handleUnifySelection(fi, j);
return;
}
}
}
}
}
if (mode != UnifyVert) CheckVertex();
}
void RenderArea::CheckVertex()
{
// Search for unselected vertices in UV Space
banList.clear();
CMeshO::FaceIterator fi;
for(fi = model->cm.face.begin(); fi != model->cm.face.end(); ++fi)
{
if ((*fi).WT(0).n() == textNum && !(*fi).IsD())
{
bool go = false;
for (int j = 0; j < 3; j++)
{
if ((*fi).V(j)->IsUserBit(selVertBit))
{
if (!areaUV.contains(QPointF((*fi).WT(j).u(), (*fi).WT(j).v()))) go = true;
else {go = false; break;}
}
}
if (go) banList.push_back(&(*fi));
}
}
}
void RenderArea::handleUnifySelection(CMeshO::FaceIterator fi, int j)
{
if (unifyRA == QRect())
{
unifyRA = QRect(QPoint(selStart.x() - VRADIUS, selStart.y() - VRADIUS), QPoint(selEnd.x() + VRADIUS, selEnd.y() + VRADIUS));
unifyA = (*fi).V(j);
firstface = &(*fi);
uvertA = ToScreenSpace((*fi).WT(j).u(), (*fi).WT(j).v());
tua = (*fi).WT(j).u(); tva = (*fi).WT(j).v();
drawnPath.clear();
drawnPath.push_back(Point2f(tua,tva));
}
else if (unifyRB == QRect())
{
unifyRB = QRect(QPoint(selStart.x() - VRADIUS, selStart.y() - VRADIUS), QPoint(selEnd.x() + VRADIUS, selEnd.y() + VRADIUS));
unifyB = (*fi).V(j);
uvertB = ToScreenSpace((*fi).WT(j).u(), (*fi).WT(j).v());
tub = (*fi).WT(j).u(); tvb = (*fi).WT(j).v();
path.clear();
if (unifyA->IsB() && unifyB->IsB())
{
path = FindPath(unifyA, unifyB, firstface, 0);
drawP = true;
}
this->update();
}
else if (unifyRA1 == QRect())
{
firstface1 = &(*fi);
unifyRA1 = QRect(QPoint(selStart.x() - VRADIUS, selStart.y() - VRADIUS), QPoint(selEnd.x() + VRADIUS, selEnd.y() + VRADIUS));
unifyA1 = (*fi).V(j);
uvertA1 = ToScreenSpace((*fi).WT(j).u(), (*fi).WT(j).v());
tua1 = (*fi).WT(j).u(); tva1 = (*fi).WT(j).v();
drawnPath1.clear();
drawnPath1.push_back(Point2f(tua1,tva1));
}
else if (unifyRB1 == QRect())
{
unifyRB1 = QRect(QPoint(selStart.x() - VRADIUS, selStart.y() - VRADIUS), QPoint(selEnd.x() + VRADIUS, selEnd.y() + VRADIUS));
unifyB1 = (*fi).V(j);
uvertB1 = ToScreenSpace((*fi).WT(j).u(), (*fi).WT(j).v());
tub1 = (*fi).WT(j).u(); tvb1 = (*fi).WT(j).v();
path1.clear();
if (unifyA1->IsB() && unifyB1->IsB())
{
path1 = FindPath(unifyA1, unifyB1, firstface1, 1);
drawP1 = true;
}
this->update();
}
}
void RenderArea::SelectConnectedComponent(QPoint e)
{
// Select a series of faces with the same UV coord on the edge
selStart = QPoint(MAX,MAX);
selEnd = QPoint(-MAX,-MAX);
selected = false;
//selBit = CFaceO::NewBitFlag();
for (unsigned i = 0; i < model->cm.face.size(); i++) model->cm.face[i].ClearUserBit(selBit);
unsigned index = 0;
vector<CFaceO*> Q = vector<CFaceO*>();
// Search the clicked face
for(unsigned i = 0; i < model->cm.face.size(); i++)
{
if (model->cm.face[i].WT(0).n() == textNum)
{
QVector<QPoint> t = QVector<QPoint>();
t.push_back(ToScreenSpace(model->cm.face[i].WT(0).u(), model->cm.face[i].WT(0).v()));
t.push_back(ToScreenSpace(model->cm.face[i].WT(1).u(), model->cm.face[i].WT(1).v()));
t.push_back(ToScreenSpace(model->cm.face[i].WT(2).u(), model->cm.face[i].WT(2).v()));
QRegion r = QRegion(QPolygon(t));
if (r.contains(e))
{
Q.push_back(&model->cm.face[i]);
model->cm.face[i].SetUserBit(selBit);
UpdateBoundingArea(r.boundingRect().topLeft(), r.boundingRect().bottomRight());
selected = true;
break;
}
}
}
// Select all the adjacentfaces
while (index < Q.size())
{
for (int j = 0; j < 3; j++)
{
CFaceO* p = Q[index]->FFp(j);
if (p != 0 && !p->IsUserBit(selBit))
{
p->SetUserBit(selBit);
Q.push_back(p);
QPoint tmp = ToScreenSpace(p->WT(j).u(), p->WT(j).v());
UpdateBoundingArea(tmp, tmp);
}
}
index++;
}
}
// Clear every selected faces or vertices
void RenderArea::ClearSelection()
{
//selBit = CFaceO::NewBitFlag();
for (unsigned i = 0; i < model->cm.face.size(); i++)
{
model->cm.face[i].ClearUserBit(selBit);
model->cm.face[i].ClearS();
}
selVertBit = CVertexO::NewBitFlag();
selection = QRect();
this->update();
emit UpdateModel();
}
// Invert selected faces
void RenderArea::InvertSelection()
{
if (selected)
{
for (unsigned i = 0; i < model->cm.face.size(); i++)
{
if (model->cm.face[i].WT(0).n() == textNum)
{
if (model->cm.face[i].IsUserBit(selBit)) model->cm.face[i].ClearUserBit(selBit);
else model->cm.face[i].SetUserBit(selBit);
}
}
RecalculateSelectionArea();
originR.moveCenter(selection.center());
origin = ToUVSpace(originR.center().x(), originR.center().y());
this->update();
ShowFaces();
}
else if (selectedV)
{
for (unsigned i = 0; i < model->cm.vert.size(); i++)
{
if (model->cm.vert[i].IsUserBit(selVertBit)) model->cm.vert[i].ClearUserBit(selVertBit);
else model->cm.vert[i].SetUserBit(selVertBit);
}
UpdateVertexSelection();
this->update();
}
}
// Flip the selected faces (mode = true -> horizontal, mode = false -> vertical)
void RenderArea::Flip(bool mode)
{
if (selected)
{
QPointF mid = ToUVSpace(selection.center().x(), selection.center().y());
for (unsigned i = 0; i < model->cm.face.size(); i++)
{
if (model->cm.face[i].WT(0).n() == textNum)
{
if (model->cm.face[i].IsUserBit(selBit))
{
for (int j = 0; j < 3; j++)
{
if (mode) model->cm.face[i].WT(j).u() = 2.0f * mid.x() - model->cm.face[i].WT(j).u();
else model->cm.face[i].WT(j).v() = 2.0f * mid.y() - model->cm.face[i].WT(j).v();
}
}
}
}
RecalculateSelectionArea();
this->update();
}
}
// Collapse a couple of vertices
void RenderArea::UnifyCouple()
{
// Calculate the average coordinates and unify a couple of vertices
if (VCount == 2)
{
float tu = (vc1.u() + vc2.u())/2.0;
float tv = (vc1.v() + vc2.v())/2.0;
for (unsigned i = 0; i < model->cm.face.size(); i++)
{
for (unsigned j = 0; j < 3; j++)
{
if (!isInside(&model->cm.face[i]) && (model->cm.face[i].V(j) == collapse1 || model->cm.face[i].V(j) == collapse2))
{
model->cm.face[i].WT(j).u() = tu;
model->cm.face[i].WT(j).v() = tv;
}
}
}
selectedV = false;
selVertBit = CVertexO::NewBitFlag();
areaUV = QRectF();
selection = QRect();
this->ChangeMode(SELECTMODE);
this->update();
emit UpdateModel();
}
}
// Unify a set of border vertices among the selected path
void RenderArea::UnifySet()
{
// Unify a set of vertices
if (path.size() == path1.size() && drawP && drawP1)
{
for (unsigned i = 0; i < path.size(); i++)
{
float mu = (drawnPath[i].X() + drawnPath1[i].X())/2.0;
float mv = (drawnPath[i].Y() + drawnPath1[i].Y())/2.0;
int n = path[i]->VFi();
CFaceO *next = path[i]->VFp();
while (n != -1)
{
if (drawnPath[i].X() == next->WT(n).u() && drawnPath[i].Y() == next->WT(n).v())
{
next->WT(n).u() = mu;
next->WT(n).v() = mv;
}
CFaceO* previous = next;
next = next->VFp(n);
n = previous->VFi(n);
if (next == 0) break;
}
int n1 = path1[i]->VFi();
CFaceO *next1 = path1[i]->VFp();
while (n1 != -1)
{
if (drawnPath1[i].X() == next1->WT(n1).u() && drawnPath1[i].Y() == next1->WT(n1).v())
{
next1->WT(n1).u() = mu;
next1->WT(n1).v() = mv;
}
CFaceO* previus1 = next1;
next1 = next1->VFp(n1);
n1 = previus1->VFi(n1);
if (next1 == 0) break;
}
}
UpdateUnifyTopology();
}
selectedV = false;
for (unsigned i = 0; i < model->cm.vert.size(); i++) model->cm.vert[i].ClearUserBit(selVertBit);
areaUV = QRectF();
selection = QRect();
unifyA = 0; unifyB = 0; unifyA1 = 0; unifyB1 = 0;
firstface = 0; firstface1 = 0;
drawP = false; drawP1 = false;
uvertA = QPoint(); uvertA1 = QPoint(); uvertB = QPoint(); uvertB1 = QPoint();
unifyRA = QRect(); unifyRA1 = QRect(); unifyRB = QRect(); unifyRB1 = QRect();
this->update();
emit UpdateModel();
}
vector<CVertexO*> RenderArea::FindPath(CVertexO* begin, CVertexO* end, CFaceO* first, int pathN)
{
// Find a path from the selected vertex, walking from LEFT TO RIGHT only on border edge...
vector<CVertexO*> path = vector<CVertexO*>();
unsigned index = 0;
vector<CFaceO*> Q = vector<CFaceO*>();
Q.push_back(first);
path.push_back(begin);
first->SetV();
bool finish = false;
int notcontrol = -1;
int lastadd = 0, lastex = -1;
/* Add all the adjacent faces to the vertex.
For each face in Stack Q
if the edge is a border one and contains the last added vertex and is on the right
enqueue all adjacent faces to the other vertex
add the other vertex to the path
*/
float tu, tv;
if (pathN == 0) {tu = tua; tv = tva;}
else {tu = tua1; tv = tva1;}
CFaceO* nextb, *previusb;
int nb = begin->VFi();
nextb = begin->VFp(), previusb = first;
while (nb != -1)
{
if (tu == nextb->WT(nb).u() && tv == nextb->WT(nb).v() && nextb != first) Q.push_back(nextb);
previusb = nextb;
nextb = nextb->VFp(nb);
nb = previusb->VFi(nb);
if (nextb == 0) break;
}
bool verso;
if (pathN == 0)
{
if (tua < tub) verso = true;
else verso = false;
}
else
{
if (tua1 < tub1) verso = true;
else verso = false;
}
if (begin->IsB() && end->IsB())
while (index < Q.size())
{
bool excluded = false;
int oldsize = Q.size();
CFaceO* p = Q[index];
float oldu;
if (pathN == 0) oldu = tua;
else oldu = tua1;
if (!p->IsV() || (p->IsV() && index == 0))
{
for (int j = 0; j < 3; j++)
{
if (p->IsB(j) && j != notcontrol)
{
notcontrol = j;
CVertexO *tmp1 = p->V(j);
CVertexO *tmp2 = p->V((j+1)%3);
bool added = false;
int n, oldn;
CFaceO *next, *previous;
float tu, tv;
if (tmp1 == path[path.size()-1] && ((verso && p->WT(j).u() >= oldu) || (!verso && p->WT(j).u() <= oldu)))
{
oldu = p->WT(j).u();
path.push_back(tmp2);
if (pathN == 0) drawnPath.push_back(Point2f(p->WT((j+1)%3).u(),p->WT((j+1)%3).v()));
else drawnPath1.push_back(Point2f(p->WT((j+1)%3).u(),p->WT((j+1)%3).v()));
if (tmp2 == end) {finish = true; break;}
n = tmp2->VFi(), oldn = (j+1)%3;
next = tmp2->VFp(), previous = p;
added = true;
lastadd = index; lastex = j;
}
else if (tmp2 == path[path.size()-1] && ((verso && p->WT(j).u() >= oldu) || (!verso && p->WT(j).u() <= oldu)))
{
oldu = p->WT(j).u();
path.push_back(tmp1);
if (pathN == 0) drawnPath.push_back(Point2f(p->WT(j).u(),p->WT(j).v()));
else drawnPath1.push_back(Point2f(p->WT(j).u(),p->WT(j).v()));
if (tmp1 == end) {finish = true; break;}
n = tmp1->VFi(), oldn = j;
next = tmp1->VFp(), previous = p;
added = true;
lastadd = index; lastex = j;
}
if (added)
{
index = Q.size()-1;
tu = p->WT(oldn).u(); tv = p->WT(oldn).v();
while (n != -1)
{
if (tu == next->WT(n).u() && tv == next->WT(n).v() && next != p && !next->IsV())
Q.push_back(next);
previous = next;
oldn = n;
next = next->VFp(n);
n = previous->VFi(n);
if (next == 0) break;
}
break;
}
else excluded = true;
}
}
p->SetV();
if (!p->IsB(0) && !p->IsB(1) && !p->IsB(2) && index != 0) excluded = true;
}
if (finish) break;
// casi degeneri...
if (oldsize == Q.size() && !excluded)
{
if (index == Q.size()-1) {index = lastadd; p->ClearV();} // Force to search again the same face...
}
else notcontrol = -1;
index++;
if (index == Q.size() && end != path[path.size()-1])
{
index = lastadd;
notcontrol = lastex;
Q[index]->ClearV();
}
}
for (unsigned i = 0; i < model->cm.face.size(); i++) model->cm.face[i].ClearV();
return path;
}
void RenderArea::HandleScale(QPoint e)
{
// Move the rectangle of scaling and resize the selection area
int tx = rectX - tpanX + e.x();
int ty = rectY - tpanY + e.y();
switch(highlighted)
{
case 0: // Top Left
if (tx > selection.x() + selection.width() - RECTDIM) tx = selection.x() + selection.width() - RECTDIM;
if (ty > selection.y() + selection.height() - RECTDIM) ty = selection.y() + selection.height() - RECTDIM;
selRect[0].moveCenter(QPoint(tx, ty));
selRect[2] = QRect(tx - RECTDIM/2, selRect[2].y(), RECTDIM, RECTDIM);
selRect[1] = QRect(selRect[1].x(), ty - RECTDIM/2, RECTDIM, RECTDIM);
selection.setTopLeft(selRect[0].center());
selection.setBottomLeft(selRect[2].center());
selection.setTopRight(selRect[1].center());
this->update(selRect[1]);
break;
case 1: // Top Right
if (tx < selection.x() + RECTDIM) tx = selection.x() + RECTDIM;
if (ty > selection.y() + selection.height() - RECTDIM) ty = selection.y() + selection.height() - RECTDIM;
selRect[1].moveCenter(QPoint(tx, ty));
selRect[3] = QRect(tx - RECTDIM/2, selRect[3].y(), RECTDIM, RECTDIM);
selRect[0] = QRect(selRect[0].x(), ty - RECTDIM/2, RECTDIM, RECTDIM);
selection.setTopRight(selRect[1].center());
selection.setTopLeft(selRect[0].center());
selection.setBottomRight(selRect[3].center());
this->update(selRect[0]);
break;
case 2: // Bottom Left
if (tx > selection.x() + selection.width() - RECTDIM) tx = selection.x() + selection.width() - RECTDIM;
if (ty < selection.y() + RECTDIM) ty = selection.y() + RECTDIM;
selRect[2].moveCenter(QPoint(tx, ty));
selRect[0] = QRect(tx - RECTDIM/2, selRect[0].y(), RECTDIM, RECTDIM);
selRect[3] = QRect(selRect[3].x(), ty - RECTDIM/2, RECTDIM, RECTDIM);
selection.setTopLeft(selRect[0].center());
selection.setBottomLeft(selRect[2].center());
selection.setBottomRight(selRect[3].center());
this->update(selRect[3]);
break;
case 3: // Bottom Right
if (tx < selection.x() + RECTDIM) tx = selection.x() + RECTDIM;
if (ty < selection.y() + RECTDIM) ty = selection.y() + RECTDIM;
selRect[3].moveCenter(QPoint(tx, ty));
selRect[1] = QRect(tx - RECTDIM/2, selRect[1].y(), RECTDIM, RECTDIM);
selRect[2] = QRect(selRect[2].x(), ty - RECTDIM/2, RECTDIM, RECTDIM);
selection.setTopRight(selRect[1].center());
selection.setBottomLeft(selRect[2].center());
selection.setBottomRight(selRect[3].center());
this->update(selRect[2]);
break;
}
this->update(selRect[highlighted]);
this->update(selRect[(highlighted+2)%selRect.size()]);
originR.moveCenter(selection.center());
origin = ToUVSpace(originR.center().x(), originR.center().y());
// calculate scaling
scaleX = (float)selection.width() / oldSRX;
scaleY = (float)selection.height() / oldSRY;
this->update(selection);
}
void RenderArea::HandleRotate(QPoint e)
{
// Calculate the angle of rotazion
float A2 = (e.x() - originR.center().x())*(e.x() - originR.center().x()) + (e.y() - originR.center().y())*(e.y() - originR.center().y());
float C2 = (rectX - e.x())*(rectX - e.x()) + (rectY - e.y()) * (rectY -e.y());
degree = acos((C2 - A2 - B2) / (-2*sqrt(A2)*sqrt(B2)));
float ny = (float) Rm * e.x() + Rq;
switch(highlighted)
{
case 0:
if (ny > e.y()) degree = -degree;
break;
case 1:
if (ny < e.y())
degree = -degree;
break;
case 2:
if (ny > e.y()) degree = -degree;
break;
case 3:
if (ny < e.y()) degree = -degree;
break;
}
this->update();
}
// Find the new size of the selection rectangle after an edit
void RenderArea::RecalculateSelectionArea()
{
selStart = QPoint(MAX,MAX);
selEnd = QPoint(-MAX,-MAX);
CMeshO::FaceIterator fi;
for(fi = model->cm.face.begin(); fi != model->cm.face.end(); ++fi)
{
if ((*fi).IsUserBit(selBit) && !(*fi).IsD())
{
QPoint a = ToScreenSpace((*fi).WT(0).u(), (*fi).WT(0).v());
QPoint b = ToScreenSpace((*fi).WT(1).u(), (*fi).WT(1).v());
QPoint c = ToScreenSpace((*fi).WT(2).u(), (*fi).WT(2).v());
// >> There's a BUG IN QREGION: I can't create a region if points are too near!!!! <<
SetUpRegion(a, b, c);
}
}
if (selected && selStart.x() < selEnd.x() && selStart.y() < selEnd.y())
{
selection = QRect(selStart, selEnd);
UpdateSelectionArea(0,0);
}
}
void RenderArea::SetUpRegion(QPoint a, QPoint b, QPoint c)
{
// Avoid a bug in Qt by calculating the region manually
if (a.x() < selStart.x()) selStart.setX(a.x());
if (b.x() < selStart.x()) selStart.setX(b.x());
if (c.x() < selStart.x()) selStart.setX(c.x());
if (a.y() < selStart.y()) selStart.setY(a.y());
if (b.y() < selStart.y()) selStart.setY(b.y());
if (c.y() < selStart.y()) selStart.setY(c.y());
if (a.x() > selEnd.x()) selEnd.setX(a.x());
if (b.x() > selEnd.x()) selEnd.setX(b.x());
if (c.x() > selEnd.x()) selEnd.setX(c.x());
if (a.y() > selEnd.y()) selEnd.setY(a.y());
if (b.y() > selEnd.y()) selEnd.setY(b.y());
if (c.y() > selEnd.y()) selEnd.setY(c.y());
}
void RenderArea::UpdateSelectionArea(int x, int y)
{
// Update the buttons of the selection area
selection.moveCenter(QPoint(selection.center().x() + x, selection.center().y() + y));
selRect[0].moveCenter(selection.topLeft());
selRect[1].moveCenter(selection.topRight());
selRect[2].moveCenter(selection.bottomLeft());
selRect[3].moveCenter(selection.bottomRight());
}
void RenderArea::UpdateSelectionAreaV(int x, int y)
{
// Update the buttons of the selection area for vertices
selection.moveCenter(QPoint(selection.center().x() + x, selection.center().y() + y));
selRect[0].moveBottomRight(selection.topLeft());
selRect[1].moveBottomLeft(selection.topRight());
selRect[2].moveTopRight(selection.bottomLeft());
selRect[3].moveTopLeft(selection.bottomRight());
}
void RenderArea::UpdateVertexSelection()
{
// Recalculate the rectangle for selection of vertices
selStart = QPoint(MAX,MAX);
selEnd = QPoint(-MAX,-MAX);
selectedV = false;
selection = QRect();
CMeshO::FaceIterator fi;
for(fi = model->cm.face.begin(); fi != model->cm.face.end(); ++fi)
{
if ((*fi).WT(0).n() == textNum && !(*fi).IsD())
{
for (int j = 0; j < 3; j++)
{
QPoint tmp = ToScreenSpace((*fi).WT(j).u(), (*fi).WT(j).v());
if ((*fi).V(j)->IsUserBit(selVertBit) && areaUV.contains(QPointF((*fi).WT(j).u(), (*fi).WT(j).v())))
{
UpdateBoundingArea(tmp,tmp);
if (!selectedV) selectedV = true;
}
}
}
}
selection = QRect(QPoint(selStart.x() - VRADIUS, selStart.y() - VRADIUS), QPoint(selEnd.x() + VRADIUS, selEnd.y() + VRADIUS));
QPointF a = ToUVSpace(selection.x(), selection.y());
QPointF b = ToUVSpace(selection.bottomRight().x(),selection.bottomRight().y());
areaUV = QRectF(a, QSizeF(b.x()-a.x(), b.y()-a.y()));
UpdateSelectionAreaV(0,0);
}
void RenderArea::UpdateUnify()
{
// Update the Unify infrastructure after a zoom
if (unifyRA != QRect())
{
unifyRA.moveCenter(ToScreenSpace(tua, tva));
uvertA = unifyRA.topLeft();
}
if (unifyRA1 != QRect())
{
unifyRA1.moveCenter(ToScreenSpace(tua1, tva1));
uvertA1 = unifyRA1.center();
}
if (unifyRB != QRect())
{
unifyRB.moveCenter(ToScreenSpace(tub, tvb));
uvertB = unifyRB.center();
}
if (unifyRB1 != QRect())
{
unifyRB1.moveCenter(ToScreenSpace(tub1, tvb1));
uvertB1 = unifyRB1.center();
}
}
QPointF RenderArea::ToUVSpace(int x, int y)
{
// Convert a point from screen-space to uv-space
return QPointF((float)(x - viewport.X()*zoom)/(AREADIM*zoom), (float)(AREADIM*zoom - y + viewport.Y()*zoom)/(AREADIM*zoom));
}
QPoint RenderArea::ToScreenSpace(float u, float v)
{
// Convert a point from uv-space to screen space
return QPoint(u * AREADIM*zoom + viewport.X()*zoom, AREADIM*zoom - (v * AREADIM*zoom) + viewport.Y()*zoom);
}
void RenderArea::DrawCircle(QPoint origin)
{
// Draw a circle in the RenderArea using openGL
float DEG2RAD = 3.14159f/180.0f;
float r = (float)VRADIUS/zoom;
glBegin(GL_TRIANGLE_FAN);
for (int i = 0; i < 360; i++)
{
float degInRad = i*DEG2RAD;
glVertex3f(origin.x() + cos(degInRad)*r,origin.y() + sin(degInRad)*r,2.0f);
}
glEnd();
}
void RenderArea::UpdateBoundingArea(QPoint topLeft, QPoint topRight)
{
// Update the bounding box (selection rectangle) of the selected faces/vertices
if (topLeft.x() < selStart.x()) selStart.setX(topLeft.x());
if (topLeft.y() < selStart.y()) selStart.setY(topLeft.y());
if (topRight.x() > selEnd.x()) selEnd.setX(topRight.x());
if (topRight.y() > selEnd.y()) selEnd.setY(topRight.y());
}
// Import the face selected from the meshlab GLArea in the pluging
void RenderArea::ImportSelection()
{
for (unsigned i = 0; i < model->cm.face.size(); i++) model->cm.face[i].ClearUserBit(selBit);
selStart = QPoint(MAX,MAX);
selEnd = QPoint(-MAX,-MAX);
CMeshO::FaceIterator fi;
for(fi = model->cm.face.begin(); fi != model->cm.face.end(); ++fi)
{
if ((*fi).IsS() && !(*fi).IsD())
{
if (!selected) selected = true;
(*fi).SetUserBit(selBit);
QPoint a = ToScreenSpace((*fi).WT(0).u(), (*fi).WT(0).v());
QPoint b = ToScreenSpace((*fi).WT(1).u(), (*fi).WT(1).v());
QPoint c = ToScreenSpace((*fi).WT(2).u(), (*fi).WT(2).v());
SetUpRegion(a, b, c);
}
}
if (selected)
{
selection = QRect(selStart, selEnd);
UpdateSelectionArea(0,0);
originR.moveCenter(ToScreenSpace(origin.x(), origin.y()));
origin = ToUVSpace(originR.center().x(), originR.center().y());
}
ChangeMode(EDITFACEMODE);
this->update();
}
void RenderArea::CountVertexes()
{
// Count the number of selected UV vertices (not so easy...)
VCount = 0;
collapse1 = 0;
collapse2 = 0;
CMeshO::FaceIterator fi;
vector< TexCoord2<float> > tmpCoord = vector< TexCoord2<float> >();
for(fi = model->cm.face.begin(); fi != model->cm.face.end(); ++fi)
{
if ((*fi).WT(0).n() == textNum)
{
for (int j = 0; j < 3; j++)
{
if ((*fi).V(j)->IsUserBit(selVertBit))
{
if (!isInside(tmpCoord, (*fi).WT(j)) && areaUV.contains(QPointF((*fi).WT(j).u(), (*fi).WT(j).v())))
{
VCount++;
if (collapse1 == 0) {collapse1 = (*fi).V(j); vc1 = (*fi).WT(j); }
else if (collapse2 == 0) {collapse2 = (*fi).V(j); vc2 = (*fi).WT(j); }
tmpCoord.push_back((*fi).WT(j));
}
}
}
}
}
}
void RenderArea::UpdateUnifyTopology()
{
// Update the topology needed for unify of edge
vcg::tri::UpdateTopology<CMeshO>::FaceFaceFromTexCoord(model->cm);
vcg::tri::UpdateTopology<CMeshO>::VertexFace(model->cm);
vcg::tri::UpdateFlags<CMeshO>::FaceBorderFromFF(model->cm);
vcg::tri::UpdateFlags<CMeshO>::VertexBorderFromFaceBorder(model->cm);
}
bool RenderArea::isInside(vector<TexCoord2<float> > tmpCoord, TexCoord2<float> act)
{
// Support function for search in a vector
for (unsigned i = 0; i < tmpCoord.size(); i++)
{
if (tmpCoord[i] == act) return true;
}
return false;
}
bool RenderArea::isInside(CFaceO* face)
{
for (int h = 0; h < banList.size(); h++)
{
if (face == banList[h]) return true;
}
return false;
}
void RenderArea::ShowFaces()
{
// Set up model for display the selected faces
for (unsigned i = 0; i < model->cm.face.size(); i++)
{
if (model->cm.face[i].IsUserBit(selBit)) model->cm.face[i].SetS();
else model->cm.face[i].ClearS();
}
emit UpdateModel();
}
// Reset the position of the viewport
void RenderArea::ResetPosition()
{
zoom = 1;
ResetTrack(true);
if (selected) RecalculateSelectionArea();
else if (selectedV) UpdateVertexSelection();
this->update();
}