meshlab/src/meshlabplugins/edit_hole/holeListModel.cpp
2011-04-05 22:18:17 +00:00

440 lines
12 KiB
C++

/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004 \/)\/ *
* 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 "holeListModel.h"
using namespace vcg;
HoleListModel::HoleListModel(MeshModel *m, QObject *parent)
: QAbstractItemModel(parent)
{
state = HoleListModel::Selection;
mesh = m;
pickedAbutment.SetNull();
mesh->clearDataMask(MeshModel::MM_FACEFLAGBORDER | MeshModel::MM_FACEFACETOPO);
mesh->updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER);
holesManager.Init(&m->cm);
emit dataChanged( index(0, 0), index(holesManager.HolesCount(), 2) );
emit SGN_needUpdateGLA();
}
void HoleListModel::drawHoles() const
{
glLineWidth(2.0f);
glDepthMask(GL_TRUE);
glDepthFunc(GL_GREATER);
glEnable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
HoleVector::const_iterator it = holesManager.holes.begin();
for( ; it != holesManager.holes.end(); ++it)
{
if( it->IsSelected())
{
if(it->IsAccepted())
glColor(Color4b::DarkGreen);
else
glColor(Color4b::DarkRed);
}
else
glColor(Color4b::DarkBlue);
it->Draw();
}
// draw the edge selected as a bridge abutment in manual-bridging
if(!pickedAbutment.IsNull())
{
glDepthFunc(GL_ALWAYS);
glLineWidth(2.0f);
glColor(Color4b::Yellow);
glBegin(GL_LINES);
glVertex( pickedAbutment.f->V0(pickedAbutment.z)->P() );
glVertex( pickedAbutment.f->V1(pickedAbutment.z)->P() );
glEnd();
}
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glLineWidth(2.0f);
for(it = holesManager.holes.begin(); it != holesManager.holes.end(); ++it)
{
if(it->IsSelected())
{
if(it->IsAccepted())
glColor(Color4b::Green);
else
glColor(Color4b::Red);
}
else
glColor(Color4b::Blue);
it->Draw();
}
}
void HoleListModel::drawCompenetratingFaces() const
{
glDisable(GL_DEPTH_TEST);
glDepthFunc(GL_ALWAYS);
glDisable(GL_LIGHTING);
glColor3f(0.8f, 0.8f, 0.f);
// draw face border also behind other face
HoleVector::const_iterator it;
for(it = holesManager.holes.begin(); it != holesManager.holes.end(); ++it)
if(it->IsCompenetrating())
it->DrawCompenetratingFace(GL_LINE_LOOP);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
// draw compenetrating face, only the visible part
for(it = holesManager.holes.begin(); it != holesManager.holes.end(); ++it)
if(it->IsCompenetrating())
it->DrawCompenetratingFace(GL_TRIANGLES);
// draw face border only visible part
glLineWidth(4.0f);
glColor3f(1.0f, 1.0f, 0.f);
for(it = holesManager.holes.begin(); it != holesManager.holes.end(); ++it)
if(it->IsCompenetrating())
it->DrawCompenetratingFace(GL_LINE_LOOP);
}
void HoleListModel::toggleSelectionHoleFromFace(CFaceO *bface)
{
assert(holesManager.IsHoleBorderFace(bface));
HoleVector::iterator h;
int ind = holesManager.FindHoleFromFace(bface, h);
if( ind == -1)
return;
h->SetSelect( !h->IsSelected() );
emit dataChanged( index(ind, 4), index(ind, 4) );
emit SGN_needUpdateGLA();
}
void HoleListModel::toggleAcceptanceHole(CFaceO *bface)
{
assert(state == HoleListModel::Filled);
HoleVector::iterator h;
int ind = holesManager.FindHoleFromFace(bface, h);
if(ind == -1)
return;
h->SetAccepted( !h->IsAccepted() );
emit dataChanged( index(ind, 6), index(ind, 6) );
emit SGN_needUpdateGLA();
}
void HoleListModel::addBridgeFace(CFaceO *pickedFace, int pickedX, int pickedY)
{
BridgeAbutment<CMeshO> picked;
if (!holesManager.FindBridgeAbutmentFromPick(pickedFace, pickedX, pickedY, picked))
return;
// reselect an already selected edge... deselect
if(pickedAbutment.f == picked.f && pickedAbutment.z == picked.z )
{
pickedAbutment.SetNull();
return;
}
if(pickedAbutment.IsNull() || pickedAbutment.f == picked.f)
pickedAbutment = picked;
else
{
// 2 edge selected... bridge building
std::vector<CMeshO::FacePointer *> local_facePointer;
local_facePointer.push_back(&pickedAbutment.f);
local_facePointer.push_back(&picked.f);
QString errLog;
if(FgtBridge<CMeshO>::CreateBridge(pickedAbutment, picked, &holesManager, errLog))
{
emit SGN_ExistBridge(true);
emit layoutChanged();
}
else
QMessageBox::warning(0, tr("Bridge error"), errLog);
pickedAbutment.SetNull();
}
}
void HoleListModel::fill(FgtHole<CMeshO>::FillerMode mode)
{
mesh->clearDataMask(MeshModel::MM_FACEFLAGBORDER | MeshModel::MM_FACEFACETOPO );
mesh->updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER );
if(holesManager.Fill(mode))
{
state = HoleListModel::Filled;
emit layoutChanged();
}
}
void HoleListModel::acceptFilling(bool accept)
{
/* if(!accept)
{
mesh->clearDataMask(MeshModel::MM_FACEFLAGBORDER | MeshModel::MM_FACEFACETOPO );
mesh->updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER );
}
*/
holesManager.ConfirmFilling(accept);
state = HoleListModel::Selection;
emit dataChanged( index(0, 0), index(holesManager.HolesCount(), 2) );
if(holesManager.holes.size()==0)
{
QMessageBox::information(0, tr("No holes"), QString("Mesh have no hole to edit."));
emit SGN_Closing();
}
else
{
emit SGN_ExistBridge( holesManager.bridges.size() > 0 );
emit SGN_needUpdateGLA();
emit layoutChanged();
}
}
void HoleListModel::autoBridge(bool singleHole, double distCoeff)
{
holesManager.DiscardBridges();
mesh->clearDataMask(MeshModel::MM_FACEFLAGBORDER | MeshModel::MM_FACEFACETOPO );
mesh->updateDataMask(MeshModel::MM_FACEFACETOPO | MeshModel::MM_FACEFLAGBORDER );
if(singleHole)
holesManager.AutoSelfBridging(distCoeff, 0);
else
holesManager.AutoMultiBridging(0);
emit SGN_ExistBridge( holesManager.bridges.size() > 0 );
emit layoutChanged();
}
void HoleListModel::removeBridges()
{
holesManager.DiscardBridges();
emit SGN_ExistBridge(false);
emit layoutChanged();
}
void HoleListModel::acceptBridges()
{
holesManager.ConfirmBridges();
emit SGN_ExistBridge(false);
}
void HoleListModel::closeNonManifolds()
{
holesManager.CloseNonManifoldHoles();
emit SGN_ExistBridge( holesManager.bridges.size()>0 );
emit layoutChanged();
}
/************* Implementazione QAbstractItemModel class *****************/
QVariant HoleListModel::data(const QModelIndex &index, int role) const
{
if(!index.isValid() )
return QVariant();
if(role == Qt::DisplayRole)
{
switch(index.column())
{
case 0:
return holesManager.holes[index.row()].name;
case 1:
return holesManager.holes.at(index.row()).Size();
case 2:
return QString("%1").arg(holesManager.holes.at(index.row()).Perimeter(), 0, 'f', 5);
}
}
else if (role == Qt::TextAlignmentRole)
{
if(index.column() == 0) return Qt::AlignLeft;
if(index.column() == 1 ||
index.column() == 2) return Qt::AlignRight;
return Qt::AlignCenter;
}
else if (role == Qt::CheckStateRole)
{
bool checked;
if(index.column() == 3)
checked = holesManager.holes[index.row()].IsNonManifold();
else if(index.column() == 4)
checked = holesManager.holes[index.row()].IsSelected();
else if(state == HoleListModel::Filled && holesManager.holes[index.row()].IsSelected())
{
if(index.column() == 5)
checked = holesManager.holes[index.row()].IsCompenetrating();
else if(index.column() == 6)
checked = holesManager.holes[index.row()].IsAccepted();
else
return QVariant();
}
else
return QVariant();
if(checked)
return Qt::Checked;
else
return Qt::Unchecked;
}
return QVariant();
}
QVariant HoleListModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
{
switch(section)
{
case 0:
return tr("Hole");
case 1:
return tr("Edges");
case 2:
return tr("Perimeter");
case 3:
return tr("Non Manif.");
case 4:
if(state == HoleListModel::Filled)
return tr("Fill");
else
return tr("Select");
case 5:
if(state == HoleListModel::Filled)
return tr("Comp.");
case 6:
if(state == HoleListModel::Filled)
return tr("Accept");
}
}
else if (orientation == Qt::Horizontal && role == Qt::SizeHintRole)
{
switch(section)
{
case 0:
return QSize(63, 20);
case 1:
return QSize(38, 20);
case 2:
return QSize(55, 20);
case 3:
return QSize(60, 20);
case 4:
if(state == HoleListModel::Filled)
return QSize(20, 20);
else
return QSize(50, 20);
case 5:
return QSize(38, 20);
case 6:
return QSize(42, 20);
}
}
else if (orientation == Qt::Horizontal && role == Qt::ToolTip && state==HoleListModel::Filled && section == 4)
return tr("Compenetration");
return QVariant();
}
QModelIndex HoleListModel::index(int row, int column, const QModelIndex &/*parent*/) const
{
if(row >= (int)holesManager.holes.size())
return QModelIndex();
return createIndex(row,column, 0);
}
Qt::ItemFlags HoleListModel::flags(const QModelIndex &index) const
{
Qt::ItemFlags ret = QAbstractItemModel::flags(index);
if (!index.isValid())
return Qt::ItemIsEnabled;
if(index.column() == 0)
ret = ret | Qt::ItemIsEditable;
else if( (index.column() == 4 && state == HoleListModel::Selection) ||
(index.column() == 6 && state == HoleListModel::Filled) )
return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled;
//return ret = ret | Qt::ItemIsUserCheckable ;
return ret;
}
bool HoleListModel::setData( const QModelIndex & index, const QVariant & value, int role )
{
if(!index.isValid())
return false;
bool ret = false;
if(role == Qt::EditRole && index.column() == 0)
{
QString newName = value.toString().trimmed();
if(newName != "")
{
holesManager.holes[index.row()].name = newName;
ret = true;
}
}
else if(role == Qt::CheckStateRole)
{
if(state == HoleListModel::Selection)
{
if(index.column() == 4 && state == HoleListModel::Selection)
{
holesManager.holes[index.row()].SetSelect( !holesManager.holes[index.row()].IsSelected() );
ret = true;
}
}
else if(index.column() == 6)
{ // check accept
holesManager.holes[index.row()].SetAccepted( !holesManager.holes[index.row()].IsAccepted() );
ret = true;
}
}
if(ret)
{
emit dataChanged(index, index);
emit SGN_needUpdateGLA();
}
return ret;
}