mirror of
https://github.com/lucaspalomodevelop/meshlab.git
synced 2026-03-16 09:34:36 +00:00
450 lines
14 KiB
C++
450 lines
14 KiB
C++
/****************************************************************************
|
|
* MeshLab o o *
|
|
* A versatile mesh processing toolbox o o *
|
|
* _ O _ *
|
|
* Copyright(C) 2005 \/)\/ *
|
|
* 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. *
|
|
* *
|
|
****************************************************************************/
|
|
/****************************************************************************
|
|
History
|
|
$Log: meshedit.cpp,v $
|
|
****************************************************************************/
|
|
#include <QtGui>
|
|
|
|
#include <math.h>
|
|
#include <stdlib.h>
|
|
#include <meshlab/glarea.h>
|
|
#include <vcg/math/point_matching.h>
|
|
#include "edit_align.h"
|
|
#include <wrap/gl/pick.h>
|
|
#include <wrap/qt/trackball.h>
|
|
#include "AlignPairWidget.h"
|
|
#include "AlignPairDialog.h"
|
|
#include "align/align_parameter.h"
|
|
#include <meshlab/stdpardialog.h>
|
|
using namespace vcg;
|
|
|
|
EditAlignPlugin::EditAlignPlugin() {
|
|
alignDialog=0;
|
|
qFont.setFamily("Helvetica");
|
|
qFont.setPixelSize(10);
|
|
|
|
trackball.center=Point3f(0, 0, 0);
|
|
trackball.radius= 1;
|
|
}
|
|
|
|
const QString EditAlignPlugin::Info()
|
|
{
|
|
return tr("Allow to align different layers toghether.");
|
|
}
|
|
|
|
void EditAlignPlugin::Decorate(MeshModel &m, GLArea * gla)
|
|
{
|
|
switch(mode)
|
|
{
|
|
case ALIGN_MOVE:
|
|
// Draw the editing mesh
|
|
gla->rm.colorMode=GLW::CMPerMesh;
|
|
m.visible=false;
|
|
glPushMatrix();
|
|
trackball.GetView();
|
|
trackball.Apply(true);
|
|
m.render(GLW::DMFlat,GLW::CMPerMesh,gla->rm.textureMode);
|
|
glPopMatrix();
|
|
break;
|
|
|
|
case ALIGN_IDLE:
|
|
{
|
|
if(alignDialog->ui.falseColorCB->isChecked())
|
|
gla->rm.colorMode=GLW::CMPerMesh;
|
|
else
|
|
gla->rm.colorMode=GLW::CMPerVert;
|
|
|
|
m.render(GLW::DMBox,GLW::CMNone,GLW::TMNone);
|
|
if(alignDialog->currentArc!=0)
|
|
DrawArc(alignDialog->currentArc);
|
|
}
|
|
case ALIGN_INSPECT_ARC:
|
|
{
|
|
break;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
bool EditAlignPlugin::StartEdit(MeshDocument &_md, GLArea *_gla )
|
|
{
|
|
if (_md.mm() == NULL)
|
|
return false;
|
|
this->md=&_md;
|
|
gla=_gla;
|
|
|
|
int id=0;
|
|
int numOfMeshes = md->meshList.size();
|
|
meshTree.clear();
|
|
foreach(MeshModel *mm, md->meshList)
|
|
{
|
|
// assigns random color: if less than 50 meshes, color is truly unique, and the less meshes, the more different they will be
|
|
// if above 50, truly unique color would geenrate too similar colors, so total number of unique color
|
|
// is capped to 50 and the color reused, id that are close will have different color anyway
|
|
if(numOfMeshes < 50)
|
|
mm->cm.C()=Color4b::Scatter(numOfMeshes+1, id, .2f, .7f);
|
|
else
|
|
mm->cm.C()=Color4b::Scatter(51, id%50, .2f, .7f);
|
|
meshTree.nodeList.push_back(new MeshNode(mm,id));
|
|
++id;
|
|
}
|
|
gla->rm.colorMode=GLW::CMPerMesh;
|
|
|
|
//MainWindow *mainW=qobject_cast<MainWindow *> (gla->parentWidget()->parentWidget());
|
|
//assert(mainW);
|
|
gla->setCursor(QCursor(QPixmap(":/images/cur_align.png"),1,1));
|
|
if(alignDialog==0)
|
|
{
|
|
//alignDialog=new AlignDialog(gla->parentWidget()->parentWidget());
|
|
alignDialog=new AlignDialog(gla->window(),this);
|
|
connect(alignDialog->ui.icpParamButton,SIGNAL(clicked()),this,SLOT(alignParam()));
|
|
connect(alignDialog->ui.icpParamCurrentButton,SIGNAL(clicked()),this,SLOT(alignParamCurrent()));
|
|
connect(alignDialog->ui.icpButton,SIGNAL(clicked()),this,SLOT(process()));
|
|
connect(alignDialog->ui.manualAlignButton,SIGNAL(clicked()),this,SLOT(glueManual()));
|
|
connect(alignDialog->ui.pointBasedAlignButton,SIGNAL(clicked()),this,SLOT(glueByPicking()));
|
|
connect(alignDialog->ui.glueHereButton,SIGNAL(clicked()),this,SLOT(glueHere()));
|
|
connect(alignDialog->ui.glueHereAllButton,SIGNAL(clicked()),this,SLOT(glueHereAll()));
|
|
connect(alignDialog->ui.falseColorCB, SIGNAL(valueChanged(bool)) , _gla->window(), SLOT(updateGL() ) );
|
|
connect(alignDialog->ui.recalcButton, SIGNAL(clicked()) , this, SLOT(recalcCurrentArc() ) );
|
|
connect(alignDialog->ui.hideRevealButton, SIGNAL(clicked()) , this, SLOT(hideRevealGluedMesh() ) );
|
|
connect(alignDialog, SIGNAL(updateMeshSetVisibilities() ), this->gla,SLOT(updateMeshSetVisibilities()));
|
|
connect(alignDialog->ui.baseMeshButton, SIGNAL(clicked()) , this, SLOT(setBaseMesh() ) );
|
|
}
|
|
|
|
//alignDialog->setCurrentNode(meshTree.find(gla->mm()) );
|
|
alignDialog->setTree(& meshTree);
|
|
alignDialog->show();
|
|
//alignDialog->adjustSize();
|
|
|
|
//mainW->addDockWidget(Qt::LeftDockWidgetArea,alignDialog);
|
|
mode=ALIGN_IDLE;
|
|
connect(this, SIGNAL(suspendEditToggle()),gla,SLOT(suspendEditToggle()) );
|
|
connect(alignDialog, SIGNAL(closing()),gla,SLOT(endEdit()) );
|
|
suspendEditToggle();
|
|
return true;
|
|
}
|
|
|
|
void EditAlignPlugin::EndEdit(MeshModel &/*m*/, GLArea * /*parent*/)
|
|
{
|
|
// some cleaning at the end.
|
|
qDebug("EndEdit: cleaning everything");
|
|
meshTree.clear();
|
|
assert(alignDialog);
|
|
delete alignDialog;
|
|
alignDialog=0;
|
|
}
|
|
|
|
void EditAlignPlugin::hideRevealGluedMesh()
|
|
{
|
|
foreach(MeshNode *mn, meshTree.nodeList)
|
|
if(!mn->glued) mn->m->visible=!(mn->m->visible);
|
|
|
|
alignDialog->rebuildTree();
|
|
gla->update();
|
|
}
|
|
|
|
void EditAlignPlugin::setBaseMesh()
|
|
{
|
|
Matrix44d oldTr = Matrix44d::Construct(md->mm()->cm.Tr);
|
|
Matrix44d inv = Inverse(oldTr);
|
|
md->mm()->cm.Tr.SetIdentity();
|
|
|
|
foreach(MeshNode *mn, meshTree.nodeList)
|
|
if(mn->glued && (mn->m != md->mm()) )
|
|
mn->m->cm.Tr.Import(inv*Matrix44d::Construct(mn->m->cm.Tr));
|
|
|
|
alignDialog->rebuildTree();
|
|
gla->update();
|
|
}
|
|
|
|
|
|
void EditAlignPlugin::glueByPicking()
|
|
{
|
|
if(meshTree.gluedNum()<1)
|
|
{
|
|
QMessageBox::warning(0,"Align tool", "Point based aligning requires at least one glued mesh");
|
|
return;
|
|
}
|
|
|
|
Matrix44f oldTr = md->mm()->cm.Tr;
|
|
md->mm()->cm.Tr.SetIdentity();
|
|
AlignPairDialog *dd=new AlignPairDialog();
|
|
dd->aa->initMesh(currentNode(), &meshTree);
|
|
dd->aa->isUsingVertexColor = !alignDialog->ui.falseColorCB->isChecked();
|
|
dd->exec();
|
|
|
|
if(dd->result()==QDialog::Rejected) return;
|
|
|
|
// i picked points sono in due sistemi di riferimento.
|
|
|
|
std::vector<vcg::Point3f>freePnt = dd->aa->freePickedPointVec;
|
|
std::vector<vcg::Point3f>gluedPnt= dd->aa->gluedPickedPointVec;
|
|
|
|
if( (freePnt.size() != gluedPnt.size()) || (freePnt.size()==0) ) {
|
|
QMessageBox::warning(0,"Align tool", "require the same number of chosen points");
|
|
return;
|
|
}
|
|
|
|
Matrix44f res;
|
|
if(dd->allowScalingCB->isChecked())
|
|
PointMatching<float>::ComputeSimilarityMatchMatrix(res,gluedPnt,freePnt);
|
|
else
|
|
PointMatching<float>::ComputeRigidMatchMatrix(res,gluedPnt,freePnt);
|
|
|
|
//md->mm()->cm.Tr=res;
|
|
currentNode()->tr()=res;
|
|
QString buf;
|
|
// for(size_t i=0;i<freePnt.size();++i)
|
|
// meshTree.cb(0,qPrintable(buf.sprintf("%f %f %f -- %f %f %f \n",freePnt[i][0],freePnt[i][1],freePnt[i][2],gluedPnt[i][0],gluedPnt[i][1],gluedPnt[i][2])));
|
|
|
|
assert(currentNode()->glued==false);
|
|
|
|
currentNode()->glued=true;
|
|
alignDialog->rebuildTree();
|
|
}
|
|
|
|
|
|
void EditAlignPlugin::glueManual()
|
|
{
|
|
assert(currentNode()->glued==false);
|
|
MeshModel *mm=md->mm();
|
|
static QString oldLabelButton;
|
|
Matrix44f tran,mtran;
|
|
|
|
switch(mode)
|
|
{
|
|
case ALIGN_IDLE:
|
|
suspendEditToggle();
|
|
mode = ALIGN_MOVE;
|
|
md->mm()->visible=false;
|
|
trackball.Reset();
|
|
trackball.center= mm->cm.trBB().Center();
|
|
trackball.radius= mm->cm.trBB().Diag()/2.0;
|
|
toggleButtons();
|
|
oldLabelButton= alignDialog->ui.manualAlignButton->text();
|
|
alignDialog->ui.manualAlignButton->setText("Store transformation");
|
|
break;
|
|
|
|
case ALIGN_MOVE: // stop manual alignment and freeze the mesh
|
|
mode = ALIGN_IDLE;
|
|
toggleButtons();
|
|
tran.SetTranslate(trackball.center);
|
|
mtran.SetTranslate(-trackball.center);
|
|
mm->cm.Tr= (tran) * trackball.track.Matrix()*(mtran) * mm->cm.Tr;
|
|
mm->visible=true;
|
|
currentNode()->glued=true;
|
|
alignDialog->ui.manualAlignButton->setText(oldLabelButton);
|
|
break;
|
|
|
|
default : assert("entered in the GlueManual slot in the wrong state"==0);
|
|
}
|
|
gla->update();
|
|
}
|
|
|
|
void EditAlignPlugin:: alignParamCurrent()
|
|
{
|
|
assert(currentArc());
|
|
|
|
RichParameterSet alignParamSet;
|
|
QString titleString=QString("Current Arc (%1 -> %2) Alignment Parameters").arg(currentArc()->MovName).arg(currentArc()->FixName);
|
|
AlignParameter::buildRichParameterSet(currentArc()->ap, alignParamSet);
|
|
|
|
GenericParamDialog ad(alignDialog,&alignParamSet,titleString);
|
|
int result=ad.exec();
|
|
if(result != QDialog::Accepted) return;
|
|
|
|
// Dialog accepted. get back the values
|
|
AlignParameter::buildAlignParameters(alignParamSet, currentArc()->ap);
|
|
}
|
|
|
|
void EditAlignPlugin:: alignParam()
|
|
{
|
|
RichParameterSet alignParamSet;
|
|
AlignParameter::buildRichParameterSet(defaultAP, alignParamSet);
|
|
|
|
GenericParamDialog ad(alignDialog,&alignParamSet,"Default Alignment Parameters");
|
|
int result=ad.exec();
|
|
if(result != QDialog::Accepted) return;
|
|
|
|
// Dialog accepted. get back the values
|
|
AlignParameter::buildAlignParameters(alignParamSet, defaultAP);
|
|
}
|
|
|
|
void EditAlignPlugin::glueHere()
|
|
{
|
|
MeshNode *mn=currentNode();
|
|
mn->glued = !mn->glued;
|
|
alignDialog->rebuildTree();
|
|
}
|
|
|
|
void EditAlignPlugin::glueHereAll()
|
|
{
|
|
foreach(MeshNode *mn, meshTree.nodeList)
|
|
mn->glued=true;
|
|
|
|
alignDialog->rebuildTree();
|
|
}
|
|
|
|
void EditAlignPlugin::process()
|
|
{
|
|
if(meshTree.gluedNum()<2)
|
|
{
|
|
QMessageBox::warning(0,"Align tool", "Process can work only when more than two meshes have been glued");
|
|
return;
|
|
}
|
|
meshTree.Process(defaultAP);
|
|
alignDialog->rebuildTree();
|
|
gla->update();
|
|
}
|
|
|
|
void EditAlignPlugin::recalcCurrentArc()
|
|
{
|
|
assert(currentArc());
|
|
|
|
meshTree.ProcessArc(currentArc()->FixName,currentArc()->MovName,*currentArc(),currentArc()->ap);
|
|
meshTree.ProcessGlobal(currentArc()->ap);
|
|
|
|
alignDialog->rebuildTree();
|
|
gla->update();
|
|
}
|
|
|
|
|
|
void EditAlignPlugin::mousePressEvent(QMouseEvent *e, MeshModel &, GLArea * )
|
|
{
|
|
if(mode==ALIGN_MOVE)
|
|
{
|
|
trackball.MouseDown(e->x(),gla->height()-e->y(), QT2VCG(e->button(), e->modifiers() ) );
|
|
gla->update();
|
|
}
|
|
}
|
|
|
|
void EditAlignPlugin::mouseMoveEvent(QMouseEvent *e, MeshModel &, GLArea * )
|
|
{
|
|
if(mode==ALIGN_MOVE)
|
|
{
|
|
trackball.MouseMove(e->x(),gla->height()-e->y() );
|
|
gla->update();
|
|
}
|
|
|
|
}
|
|
|
|
void EditAlignPlugin::mouseReleaseEvent(QMouseEvent * e, MeshModel &/*m*/, GLArea * gla)
|
|
{
|
|
if(mode==ALIGN_MOVE)
|
|
{
|
|
trackball.MouseUp(e->x(),gla->height()-e->y(), QT2VCG(e->button(), e->modifiers() ) );
|
|
gla->update();
|
|
}
|
|
}
|
|
|
|
|
|
// this function toggles on and off all the buttons (according to the "modal" states of the interface),
|
|
// do not confuse it with the updatebuttons function of the alignDialog class.
|
|
void EditAlignPlugin::toggleButtons()
|
|
{
|
|
switch(mode)
|
|
{
|
|
case ALIGN_MOVE:
|
|
alignDialog->ui.manualAlignButton->setEnabled(true);
|
|
alignDialog->ui.recalcButton->setEnabled(false);
|
|
alignDialog->ui.icpButton->setEnabled(false);
|
|
alignDialog->ui.icpParamButton->setEnabled(false);
|
|
alignDialog->ui.alignTreeWidget->setEnabled(false);
|
|
alignDialog->ui.baseMeshButton->setEnabled(false);
|
|
|
|
|
|
break;
|
|
case ALIGN_IDLE:
|
|
alignDialog->ui.manualAlignButton->setEnabled(true);
|
|
alignDialog->ui.recalcButton->setEnabled(true);
|
|
alignDialog->ui.icpButton->setEnabled(true);
|
|
alignDialog->ui.icpParamButton->setEnabled(true);
|
|
alignDialog->ui.alignTreeWidget->setEnabled(true);
|
|
alignDialog->ui.baseMeshButton->setEnabled(true);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void EditAlignPlugin::DrawArc(vcg::AlignPair::Result *A )
|
|
{
|
|
unsigned int i;
|
|
AlignPair::Result &r=*A;
|
|
MeshNode *fix=meshTree.find(r.FixName);
|
|
MeshNode *mov=meshTree.find(r.MovName);
|
|
//int mov=FindMesh(r.MovName);
|
|
double nl=2.0*(*fix).bbox().Diag()/100.0;
|
|
glPushAttrib(GL_ENABLE_BIT );
|
|
|
|
glDisable(GL_LIGHTING);
|
|
|
|
glPushMatrix();
|
|
glMultMatrix(fix->tr());
|
|
glPointSize(5.0f);
|
|
glColor3f(1,0,0);
|
|
glBegin(GL_POINTS);
|
|
for(i=0;i<r.Pfix.size();i++) glVertex(r.Pfix[i]);
|
|
glEnd();
|
|
glPointSize(1.0f);
|
|
//glColor((*fix).mi.c);
|
|
if(r.Nfix.size()==r.Pfix.size())
|
|
{
|
|
glBegin(GL_LINES);
|
|
for(i=0;i<r.Pfix.size();i++) {
|
|
glVertex(r.Pfix[i]);
|
|
glVertex(r.Pfix[i]+r.Nfix[i]*nl);
|
|
}
|
|
glEnd();
|
|
}
|
|
|
|
glPopMatrix();
|
|
glPushMatrix();
|
|
glMultMatrix(mov->tr());
|
|
|
|
glPointSize(5.0f);
|
|
glColor3f(0,0,1);
|
|
glBegin(GL_POINTS);
|
|
for(i=0;i<r.Pmov.size();i++) glVertex(r.Pmov[i]);
|
|
glEnd();
|
|
glPointSize(1.0f);
|
|
//glColor((*mov).mi.c);
|
|
if(r.Nmov.size()==r.Pmov.size())
|
|
{
|
|
glBegin(GL_LINES);
|
|
for(i=0;i<r.Pmov.size();i++) {
|
|
glVertex(r.Pmov[i]);
|
|
glVertex(r.Pmov[i]+r.Nmov[i]*nl);
|
|
}
|
|
glEnd();
|
|
}
|
|
glPopMatrix();
|
|
/*
|
|
// Now Draw the histogram
|
|
|
|
int HSize = ViewPort[2]-100;
|
|
r.H.glDraw(Point4i(20,80,HSize,100),dlFont,r.as.I[0].MinDistAbs,1);
|
|
*/
|
|
glPopAttrib();
|
|
|
|
}
|