diff --git a/src/fgt/edit_point/connectedComponent.h b/src/fgt/edit_point/connectedComponent.h index ff1c4ecb8..9776607b3 100644 --- a/src/fgt/edit_point/connectedComponent.h +++ b/src/fgt/edit_point/connectedComponent.h @@ -1,6 +1,8 @@ #ifndef CONNECTEDCOMPONENT_H #define CONNECTEDCOMPONENT_H +#include + #include "knnGraph.h" #include @@ -10,6 +12,8 @@ #include #include +#include + using namespace std; using namespace vcg; @@ -18,11 +22,13 @@ template class ComponentFinder { public: static std::vector<_MyVertexType*> &FindComponent(_MyMeshType& m, _MyVertexType& v, int numOfNeighbours, int numOfHop); - static std::vector<_MyVertexType*> &FindComponent(_MyMeshType& m, _MyVertexType& v, int numOfNeighbours, float dim, float maxHopDist, vector<_MyVertexType*> &borderVect, vector<_MyVertexType*> ¬ReachableVect); + static std::vector<_MyVertexType*> &FindComponent(_MyMeshType& m, _MyVertexType& v, int numOfNeighbours, float dim, float maxHopDist, vector<_MyVertexType*> &borderVect, vector<_MyVertexType*> ¬ReachableVect, bool fitting = false, float planeDim = 0.0, float distanceFromPlane = 0.0); static void DeletePerVertexAttribute(_MyMeshType& m); static void Dijkstra(_MyMeshType& m, _MyVertexType& v, int numOfNeighbours, float maxHopDist, vector<_MyVertexType*> ¬ReachableVect); +// static void DijkstraMod(_MyMeshType& m, _MyVertexType& v, int numOfNeighbours, float maxHopDist, vector<_MyVertexType*> ¬ReachableVect, bool fitting = false, float planeDim = 0.0, float distanceFromPlane = 0.0); + }; @@ -102,8 +108,9 @@ public: * maximum distance we want between two vertex (with the Shortest Path we also compute the geodesic distance) **/ template -std::vector<_MyVertexType*> &ComponentFinder<_MyMeshType, _MyVertexType>::FindComponent(_MyMeshType& m, _MyVertexType& v, int numOfNeighbours, float dim, float maxHopDist, vector<_MyVertexType*> &borderVect, vector<_MyVertexType*> ¬ReachableVect) { +std::vector<_MyVertexType*> &ComponentFinder<_MyMeshType, _MyVertexType>::FindComponent(_MyMeshType& m, _MyVertexType& v, int numOfNeighbours, float dim, float maxHopDist, vector<_MyVertexType*> &borderVect, vector<_MyVertexType*> ¬ReachableVect, bool fitting, float planeDim, float distanceFromPlane) { vector<_MyVertexType*> *resultVect = new vector<_MyVertexType*>(); + vector pointToFit = vector(); tri::UpdateFlags<_MyMeshType>::VertexClearV(m); @@ -115,12 +122,31 @@ std::vector<_MyVertexType*> &ComponentFinder<_MyMeshType, _MyVertexType>::FindCo else return *resultVect; for (typename _MyMeshType::VertexIterator vi = m.vert.begin(); vi != m.vert.end(); vi++) { - if (distFromCenter[vi] < dim) resultVect->push_back(&*vi); + if (fitting) { + if (distFromCenter[vi] < planeDim) { + pointToFit.push_back(vi->cP()); + } + } + else if (distFromCenter[vi] < dim) resultVect->push_back(&*vi); } typename vector<_MyVertexType*>::iterator it; - for (it = notReachableVect.begin(); it != notReachableVect.end(); it++) { - if (distFromCenter[*it] < dim) borderVect.push_back(*it); + if (fitting) { + Plane3 fittingPlane = Plane3(); + + vcg::PlaneFittingPoints(pointToFit, fittingPlane); + + for (typename _MyMeshType::VertexIterator vi = m.vert.begin(); vi != m.vert.end(); vi++) { + if (distFromCenter[vi] < dim && math::Abs(vcg::SignedDistancePlanePoint(fittingPlane, vi->cP())) < distanceFromPlane) resultVect->push_back(&*vi); + } + for (it = notReachableVect.begin(); it != notReachableVect.end(); it++) { + if (distFromCenter[*it] < dim && math::Abs(vcg::SignedDistancePlanePoint(fittingPlane, (*it)->cP())) < distanceFromPlane) borderVect.push_back(*it); + } + } + else { + for (it = notReachableVect.begin(); it != notReachableVect.end(); it++) { + if (distFromCenter[*it] < dim) borderVect.push_back(*it); + } } return *resultVect; @@ -140,13 +166,15 @@ void ComponentFinder<_MyMeshType, _MyVertexType>::Dijkstra(_MyMeshType& m, _MyVe } else distFromCenter = vcg::tri::Allocator<_MyMeshType>::template GetPerVertexAttribute(m, std::string("DistParam")); + //QTime t; + //t.start(); if (!hasKNNGraph) { KNNTree<_MyMeshType, _MyVertexType>::MakeKNNTree(m, numOfNeighbours); } + //printf("KNNGraph Creation: %d ms\n", t.elapsed()); typename _MyMeshType::template PerVertexAttributeHandle* > neighboursVect = vcg::tri::Allocator<_MyMeshType>::template GetPerVertexAttribute* >(m,"KNNGraph"); - typename vector<_MyVertexType*>::iterator it; typedef priority_queue<_MyVertexType*, vector<_MyVertexType*>, Compare<_MyMeshType, _MyVertexType> > VertPriorityQueue; @@ -174,12 +202,16 @@ void ComponentFinder<_MyMeshType, _MyVertexType>::Dijkstra(_MyMeshType& m, _MyVe for (it = neighboursVect[element]->begin(); it != neighboursVect[element]->end(); it++) { distance = vcg::Distance((*it)->P(), element->P()); - if (distFromCenter[*element] + distance < distFromCenter[*it]) distFromCenter[*it] = distFromCenter[*element] + distance; - if (!((*it)->IsV()) && distance <= maxHopDist) { - prQueue.push(*it); - (*it)->SetV(); + if (distance <= maxHopDist) { + if (distFromCenter[*element] + distance < distFromCenter[*it]) + distFromCenter[*it] = distFromCenter[*element] + distance; + + if (!(*it)->IsV()) { + prQueue.push(*it); + (*it)->SetV(); + } } - else if (distance > maxHopDist) notReachableVect.push_back(*it); + else if (distance > maxHopDist) notReachableVect.push_back(element); } } } diff --git a/src/fgt/edit_point/edit_point.cpp b/src/fgt/edit_point/edit_point.cpp index 5a84c468a..8211659a6 100644 --- a/src/fgt/edit_point/edit_point.cpp +++ b/src/fgt/edit_point/edit_point.cpp @@ -29,6 +29,7 @@ #include "edit_point.h" #include #include +#include #include "connectedComponent.h" @@ -36,10 +37,10 @@ using namespace std; using namespace vcg; -EditPointPlugin::EditPointPlugin() {} +EditPointPlugin::EditPointPlugin(int _editType) : editType(_editType){} const QString EditPointPlugin::Info() { - return tr("Select a region of the mesh"); + return tr("Select a region of the point cloud thought to be in the same connected component."); } void EditPointPlugin::Decorate(MeshModel &m, GLArea * gla, QPainter *p) @@ -53,7 +54,11 @@ void EditPointPlugin::Decorate(MeshModel &m, GLArea * gla, QPainter *p) if(NewSel.size() > 0) { startingVertex = NewSel.front(); + //timer.start(); ComponentFinder::Dijkstra(m.cm, *startingVertex, 6, this->maxHop, this->NotReachableVector); + + //printf("ComponentFinder in Decorate::Dijkstra: %d ms\n", timer.elapsed()); + ComponentVector.push_back(startingVertex); } @@ -74,13 +79,41 @@ void EditPointPlugin::Decorate(MeshModel &m, GLArea * gla, QPainter *p) glDepthFunc(GL_LEQUAL); glPointSize(6.f); + tri::UpdateSelection::VertexClear(m.cm); + + switch (composingSelMode) { + case SMSub: + for(vector::iterator vi = OldComponentVector.begin(); vi != OldComponentVector.end(); ++vi) { + (*vi)->SetS(); + } + for(vector::iterator vi = ComponentVector.begin(); vi != ComponentVector.end(); ++vi) { + (*vi)->ClearS(); + } + break; + + case SMAdd: + for(vector::iterator vi = OldComponentVector.begin(); vi != OldComponentVector.end(); ++vi) { + (*vi)->SetS(); + } + for(vector::iterator vi = ComponentVector.begin(); vi != ComponentVector.end(); ++vi) { + (*vi)->SetS(); + } + break; + + case SMClear: + for(vector::iterator vi = ComponentVector.begin(); vi != ComponentVector.end(); ++vi) { + (*vi)->SetS(); + } + break; + } + glBegin(GL_POINTS); glColor4f(1,0,0,.6f); - for(vector::iterator vi = ComponentVector.begin(); vi != ComponentVector.end(); ++vi) - { - glVertex((*vi)->cP()); + for (CMeshO::VertexIterator vi = m.cm.vert.begin(); vi != m.cm.vert.end(); vi++) { + if (vi->IsS()) glVertex(vi->cP()); } + glEnd(); glBegin(GL_POINTS); @@ -88,10 +121,11 @@ void EditPointPlugin::Decorate(MeshModel &m, GLArea * gla, QPainter *p) for(vector::iterator vi = BorderVector.begin(); vi != BorderVector.end(); ++vi) { - glVertex((*vi)->cP()); + if ((*vi)->IsS()) glVertex((*vi)->cP()); } glEnd(); + glPopAttrib(); glPopMatrix(); } @@ -100,7 +134,13 @@ void EditPointPlugin::Decorate(MeshModel &m, GLArea * gla, QPainter *p) bool EditPointPlugin::StartEdit(MeshModel &m, GLArea *gla ) { BorderVector = std::vector(); NotReachableVector = std::vector(); + OldComponentVector = std::vector(); + + composingSelMode = SMClear; + this->maxHop = m.cm.bbox.Diag() / 100.0; + this->planeDist = m.cm.bbox.Diag() / 100.0; + this->fittingRadiusPerc = 0.1; return true; } @@ -119,6 +159,21 @@ void EditPointPlugin::mousePressEvent(QMouseEvent *ev, MeshModel &m, GLArea *gla this->isMousePressed = true; this->dist = 0.0; this->startingClick = vcg::Point2f(ev->x(), ev->y()); + this->fittingRadius = 0.0; + + OldComponentVector.clear(); + + if (ev->modifiers() & Qt::ControlModifier || ev->modifiers() & Qt::ShiftModifier) + { + for (CMeshO::VertexIterator vi = m.cm.vert.begin(); vi != m.cm.vert.end(); ++vi) { + if (vi->IsS()) OldComponentVector.push_back(&*vi); + } + } + + + composingSelMode = SMClear; + if(ev->modifiers() & Qt::ControlModifier) composingSelMode = SMAdd; + if(ev->modifiers() & Qt::ShiftModifier) composingSelMode = SMSub; BorderVector.clear(); ComponentVector.clear(); @@ -135,45 +190,147 @@ void EditPointPlugin::mouseMoveEvent(QMouseEvent *ev, MeshModel &m, GLArea *gla this->dist = (perim * distFromCenter) / gla->width(); BorderVector.clear(); - ComponentVector = ComponentFinder::FindComponent(m.cm, *startingVertex, 6, this->dist, this->maxHop, BorderVector, NotReachableVector); - } + + if (editType == SELECT_DEFAULT_MODE) + ComponentVector = ComponentFinder::FindComponent(m.cm, *startingVertex, 6, this->dist, this->maxHop, BorderVector, NotReachableVector); + else if (editType == SELECT_FITTING_PLANE_MODE) { + this->fittingRadius = dist * fittingRadiusPerc; + ComponentVector = ComponentFinder::FindComponent(m.cm, *startingVertex, 6, this->dist, this->maxHop, BorderVector, NotReachableVector, true, fittingRadius, planeDist); + } + + gla->update(); + } } void EditPointPlugin::mouseReleaseEvent(QMouseEvent *ev, MeshModel &m, GLArea *gla) { + this->isMousePressed = false; + gla->update(); } void EditPointPlugin::keyPressEvent(QKeyEvent *ev, MeshModel &m, GLArea *gla) { bool hopDistModified = false; + bool parameterModified = false; + int keyPressed = ev->key(); - if (startingVertex != NULL) { - switch (keyPressed) { - case Qt::Key_A: - this->maxHop *= 1.2; + switch (keyPressed) { + case Qt::Key_A: + if (startingVertex != NULL) { + this->maxHop *= 1.2; - hopDistModified = true; - - break; - - case Qt::Key_Z: - this->maxHop /= 1.2; - - hopDistModified = true; - - break; - - default: break; + hopDistModified = true; + parameterModified = true; } + + break; + + case Qt::Key_Z: + if (startingVertex != NULL) { + this->maxHop /= 1.2; + + hopDistModified = true; + parameterModified = true; + } + + break; + + case Qt::Key_S: + if (startingVertex != NULL && editType == SELECT_FITTING_PLANE_MODE) { + this->fittingRadiusPerc *= 1.2; + this->fittingRadius = (dist * fittingRadiusPerc); + + parameterModified = true; + } + + break; + + case Qt::Key_X: + if (startingVertex != NULL && editType == SELECT_FITTING_PLANE_MODE) { + this->fittingRadiusPerc /= 1.2; + this->fittingRadius = (dist * fittingRadiusPerc); + + parameterModified = true; + } + + break; + + case Qt::Key_D: + if (startingVertex != NULL && editType == SELECT_FITTING_PLANE_MODE) { + this->planeDist *= 1.2; + + parameterModified = true; + } + + break; + + case Qt::Key_C: + if (startingVertex != NULL && editType == SELECT_FITTING_PLANE_MODE) { + this->planeDist /= 1.2; + + parameterModified = true; + } + + break; + + default: break; + } + if (hopDistModified) { + //timer.restart(); ComponentFinder::Dijkstra(m.cm, *startingVertex, 6, this->maxHop, this->NotReachableVector); + //printf("ComponentFinder in ChangeHop::Dijkstra: %d ms\n", timer.elapsed()); + } + if (parameterModified) { + //printf("fittingRadius: %f\n", fittingRadius); + //printf("planeDist: %f\n", planeDist); + BorderVector.clear(); - ComponentVector = ComponentFinder::FindComponent(m.cm, *startingVertex, 6, this->dist, this->maxHop, BorderVector, NotReachableVector); + if (editType == SELECT_DEFAULT_MODE) + ComponentVector = ComponentFinder::FindComponent(m.cm, *startingVertex, 6, this->dist, this->maxHop, BorderVector, NotReachableVector); + else if (editType == SELECT_FITTING_PLANE_MODE) + ComponentVector = ComponentFinder::FindComponent(m.cm, *startingVertex, 6, this->dist, this->maxHop, BorderVector, NotReachableVector, true, fittingRadius, planeDist); } gla->update(); return; } + +void EditPointPlugin::keyReleaseEvent(QKeyEvent *ev, MeshModel &m, GLArea *gla) {} + +void EditPointPlugin::wheelEvent(QWheelEvent* ev, MeshModel &m, GLArea *gla) { + bool hopDistModified = false; + int wheelDirection = ev->delta(); + + if (startingVertex != NULL) { + if (wheelDirection > 0) { + this->maxHop *= pow(1.2, wheelDirection / 120.f); + hopDistModified = true; + } + else if (wheelDirection < 0) { + this->maxHop /= pow(1.2, (-1*wheelDirection) / 120.f); + hopDistModified = true; + } + } + + if (hopDistModified) { + //timer.restart(); + ComponentFinder::Dijkstra(m.cm, *startingVertex, 6, this->maxHop, this->NotReachableVector); + + //printf("ComponentFinder in ChangeHop::Dijkstra: %d ms\n", timer.elapsed()); + + BorderVector.clear(); + + if (editType == SELECT_DEFAULT_MODE) + ComponentVector = ComponentFinder::FindComponent(m.cm, *startingVertex, 6, this->dist, this->maxHop, BorderVector, NotReachableVector); + else if (editType == SELECT_FITTING_PLANE_MODE) + ComponentVector = ComponentFinder::FindComponent(m.cm, *startingVertex, 6, this->dist, this->maxHop, BorderVector, NotReachableVector, true, fittingRadius, planeDist); + } + + gla->update(); + return; + +} diff --git a/src/fgt/edit_point/edit_point.h b/src/fgt/edit_point/edit_point.h index a7e969000..c59d965cb 100644 --- a/src/fgt/edit_point/edit_point.h +++ b/src/fgt/edit_point/edit_point.h @@ -33,7 +33,9 @@ class EditPointPlugin : public QObject, public MeshEditInterface Q_INTERFACES(MeshEditInterface) public: - EditPointPlugin(); + enum {SELECT_DEFAULT_MODE, SELECT_FITTING_PLANE_MODE}; + + EditPointPlugin(int _editType); virtual ~EditPointPlugin() {} static const QString Info(); @@ -45,9 +47,16 @@ public: void mouseMoveEvent(QMouseEvent *, MeshModel &, GLArea * ); void mouseReleaseEvent(QMouseEvent *, MeshModel &/*m*/, GLArea * ); void keyPressEvent(QKeyEvent *, MeshModel &/*m*/, GLArea *); + void keyReleaseEvent(QKeyEvent *, MeshModel &/*m*/, GLArea *); + void wheelEvent(QWheelEvent*, MeshModel &/*m*/, GLArea * ); -private: +private: + typedef enum {SMAdd, SMClear,SMSub} ComposingSelMode; // How the selection are composed + ComposingSelMode composingSelMode; + + int editType; + bool isMousePressed; bool haveToPick; @@ -56,12 +65,17 @@ private: float dist; float maxHop; + float fittingRadiusPerc; + float fittingRadius; + float planeDist; std::vector ComponentVector; std::vector BorderVector; std::vector NotReachableVector; + std::vector OldComponentVector; QPoint cur; + //QTime timer; }; #endif diff --git a/src/fgt/edit_point/edit_point_factory.cpp b/src/fgt/edit_point/edit_point_factory.cpp index 36f8c075a..4ad041e81 100644 --- a/src/fgt/edit_point/edit_point_factory.cpp +++ b/src/fgt/edit_point/edit_point_factory.cpp @@ -26,12 +26,14 @@ PointEditFactory::PointEditFactory() { - editPoint = new QAction(QIcon(":/images/icon_info.png"),"Point", this); + editPoint = new QAction(QIcon(":/images/select_vertex.png"),"Point", this); + editPointFittingPlane = new QAction(QIcon(":/images/select_vertex.png"),"PointFitting", this); actionList << editPoint; + actionList << editPointFittingPlane; foreach(QAction *editAction, actionList) - editAction->setCheckable(true); + editAction->setCheckable(true); } //gets a list of actions available from this plugin @@ -44,9 +46,11 @@ QList PointEditFactory::actions() const MeshEditInterface* PointEditFactory::getMeshEditInterface(QAction *action) { if(action == editPoint) - { - return new EditPointPlugin(); - } else assert(0); //should never be asked for an action that isn't here + return new EditPointPlugin(EditPointPlugin::SELECT_DEFAULT_MODE); + else if (action == editPointFittingPlane) + return new EditPointPlugin(EditPointPlugin::SELECT_FITTING_PLANE_MODE); + + assert(0); //should never be asked for an action that isn't here } QString PointEditFactory::getEditToolDescription(QAction *) diff --git a/src/fgt/edit_point/edit_point_factory.h b/src/fgt/edit_point/edit_point_factory.h index 7c7609711..5644c8c57 100644 --- a/src/fgt/edit_point/edit_point_factory.h +++ b/src/fgt/edit_point/edit_point_factory.h @@ -50,6 +50,7 @@ private: QList actionList; QAction *editPoint; + QAction *editPointFittingPlane; }; #endif diff --git a/src/fgt/edit_point/knnGraph.h b/src/fgt/edit_point/knnGraph.h index 8b4ce171b..cd9e277f2 100644 --- a/src/fgt/edit_point/knnGraph.h +++ b/src/fgt/edit_point/knnGraph.h @@ -1,6 +1,8 @@ #ifndef KNNGRAPH_H #define KNNGRAPH_H +#include + #include #include @@ -48,7 +50,10 @@ void KNNTree<_MyMeshType, _MyVertexType>::MakeKNNTree(_MyMeshType& m, int numOfN } ConstDataWrapper DW(&(input[0]), input.size()); + //QTime t2; + //t2.start(); KdTree tree(DW); + //printf("KdTree Creation: %d ms\n", t2.elapsed()); tree.setMaxNofNeighbors(neighboursVectSize); @@ -56,6 +61,8 @@ void KNNTree<_MyMeshType, _MyVertexType>::MakeKNNTree(_MyMeshType& m, int numOfN //If the number of the found vertices is less than the required we exclude the point with //the highest value (inserted by the doQueryK function of the vcg library). Moreover //we have to exclude the queryPoint! + + //t2.restart(); int neightId = -1; for (int j = 0; j < m.vn; j++) { tree.doQueryK(m.vert[j].cP()); @@ -67,6 +74,7 @@ void KNNTree<_MyMeshType, _MyVertexType>::MakeKNNTree(_MyMeshType& m, int numOfN kNeighboursVect[m.vert[j]]->push_back(&(m.vert[neightId])); } } + //printf("KdTree Creation (knn-query): %d ms\n", t2.elapsed()); return; }