diff --git a/src/meshlabplugins/edit_point/connectedComponent.h b/src/meshlabplugins/edit_point/connectedComponent.h index 10f2d9f43..bccbe59ca 100644 --- a/src/meshlabplugins/edit_point/connectedComponent.h +++ b/src/meshlabplugins/edit_point/connectedComponent.h @@ -14,22 +14,17 @@ #include +namespace vcg { +namespace tri { -using namespace std; -using namespace vcg; - -template +template class ComponentFinder { + typedef typename _MyMeshType::VertexType VertexType; + typedef typename _MyMeshType::VertexIterator VertexIterator; + typedef typename _MyMeshType::CoordType CoordType; public: - static std::vector<_MyVertexType*> &FindComponent(_MyMeshType& m, float dim, vector<_MyVertexType*> &borderVect, vector<_MyVertexType*> ¬ReachableVect, bool fitting = false, float planeDim = 0.0, float distanceFromPlane = 0.0, Plane3 *fittingPlane = NULL); - static void DeletePerVertexAttribute(_MyMeshType& m); - - static void Dijkstra(_MyMeshType& m, _MyVertexType& v, int numOfNeighbours, float maxHopDist, vector<_MyVertexType*> ¬ReachableVect); -}; - - -/** This function returns a vector which stores pointers to the vertices of the connected component with + /** This function returns a vector which stores pointers to the vertices of the connected component with * max distance 'dim' from the center. It assumes that the vertices have the DistParam attribute, so * we don't have to know where is the center. * The border is also computed, using the notReachableVect parameter, which stores the vertices we @@ -38,21 +33,25 @@ public: * We can specify to fit some points: in this case first we compute the fitting plane (vcg library method), * then we calculate the connected component and the border. **/ -template -std::vector<_MyVertexType*> &ComponentFinder<_MyMeshType, _MyVertexType>::FindComponent(_MyMeshType& m, float dim, vector<_MyVertexType*> &borderVect, vector<_MyVertexType*> ¬ReachableVect, bool fitting, float planeDim, float distanceFromPlane, Plane3 *fittingPlane) { - vector<_MyVertexType*> *resultVect = new vector<_MyVertexType*>(); - vector pointToFit = vector(); +static std::vector &FindComponent(_MyMeshType& m, float dim, + std::vector &borderVect, + std::vector ¬ReachableVect, + bool fitting=false, float planeDim=0, float distanceFromPlane=0, + Plane3 *fittingPlane=NULL) +{ + std::vector *resultVect = new std::vector(); + std::vector pointToFit = std::vector(); tri::UpdateFlags<_MyMeshType>::VertexClearV(m); - bool hasDistParam = vcg::tri::HasPerVertexAttribute(m, "DistParam"); + bool hasDistParam = tri::HasPerVertexAttribute(m, "DistParam"); typename _MyMeshType::template PerVertexAttributeHandle distFromCenter; - if (hasDistParam) distFromCenter = vcg::tri::Allocator<_MyMeshType>::template GetPerVertexAttribute(m, std::string("DistParam")); + if (hasDistParam) distFromCenter = tri::Allocator<_MyMeshType>::template GetPerVertexAttribute(m, std::string("DistParam")); else return *resultVect; - for (typename _MyMeshType::VertexIterator vi = m.vert.begin(); vi != m.vert.end(); vi++) { + for (VertexIterator vi = m.vert.begin(); vi != m.vert.end(); vi++) { if (fitting) { if (distFromCenter[vi] < planeDim) { pointToFit.push_back(vi->cP()); @@ -61,11 +60,11 @@ std::vector<_MyVertexType*> &ComponentFinder<_MyMeshType, _MyVertexType>::FindCo else if (distFromCenter[vi] < dim) resultVect->push_back(&*vi); } - typename vector<_MyVertexType*>::iterator it; + typename std::vector::iterator it; if (fitting) { vcg::PlaneFittingPoints(pointToFit, *fittingPlane); - for (typename _MyMeshType::VertexIterator vi = m.vert.begin(); vi != m.vert.end(); vi++) { + for (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++) { @@ -85,7 +84,6 @@ std::vector<_MyVertexType*> &ComponentFinder<_MyMeshType, _MyVertexType>::FindCo /* This class is used in the priority queue to order the nodes */ -template class Compare { private: typename _MyMeshType::template PerVertexAttributeHandle *distFromCenter; @@ -95,7 +93,7 @@ public: this->distFromCenter = distFromCenter; } - bool operator() (const _MyVertexType* lhs, const _MyVertexType* rhs) const + bool operator() (const VertexType* lhs, const VertexType* rhs) const { return (*distFromCenter)[*lhs] > (*distFromCenter)[*rhs]; } @@ -109,34 +107,35 @@ public: * attributes and we construct the KNNGraph. * The notReachableVect is returned in order to calculate the border in other methods. **/ -template -void ComponentFinder<_MyMeshType, _MyVertexType>::Dijkstra(_MyMeshType& m, _MyVertexType& v, int numOfNeighbours, float maxHopDist, vector<_MyVertexType*> ¬ReachableVect) { - bool hasKNNGraph = vcg::tri::HasPerVertexAttribute(m, "KNNGraph"); - bool hasDistParam = vcg::tri::HasPerVertexAttribute(m, "DistParam"); + +static void Dijkstra(_MyMeshType& m, VertexType& v, int numOfNeighbours, float maxHopDist, std::vector ¬ReachableVect) +{ + bool hasKNNGraph = tri::HasPerVertexAttribute(m, "KNNGraph"); + bool hasDistParam = tri::HasPerVertexAttribute(m, "DistParam"); notReachableVect.clear(); typename _MyMeshType::template PerVertexAttributeHandle distFromCenter; if (!hasDistParam) { - distFromCenter = vcg::tri::Allocator<_MyMeshType>::template AddPerVertexAttribute(m, std::string("DistParam")); + distFromCenter = tri::Allocator<_MyMeshType>::template AddPerVertexAttribute(m, std::string("DistParam")); } - else distFromCenter = vcg::tri::Allocator<_MyMeshType>::template GetPerVertexAttribute(m, std::string("DistParam")); + else distFromCenter = tri::Allocator<_MyMeshType>::template GetPerVertexAttribute(m, std::string("DistParam")); if (!hasKNNGraph) { - KNNTree<_MyMeshType, _MyVertexType>::MakeKNNTree(m, numOfNeighbours); + KNNGraph<_MyMeshType>::MakeKNNTree(m, numOfNeighbours); } - typename _MyMeshType::template PerVertexAttributeHandle* > neighboursVect = vcg::tri::Allocator<_MyMeshType>::template GetPerVertexAttribute* >(m,"KNNGraph"); + typename _MyMeshType::template PerVertexAttributeHandle* > neighboursVect = tri::Allocator<_MyMeshType>::template GetPerVertexAttribute* >(m,"KNNGraph"); - typename vector<_MyVertexType*>::iterator it; + typename std::vector::iterator it; // For Dijkstra algorithm we use a Priority Queue - typedef priority_queue<_MyVertexType*, vector<_MyVertexType*>, Compare<_MyMeshType, _MyVertexType> > VertPriorityQueue; - Compare<_MyMeshType, _MyVertexType> Comparator(&distFromCenter); + typedef std::priority_queue, Compare > VertPriorityQueue; + Compare Comparator(&distFromCenter); VertPriorityQueue prQueue (Comparator); for (typename _MyMeshType::VertexIterator vi = m.vert.begin(); vi != m.vert.end(); vi++) - distFromCenter[vi] = numeric_limits::max(); + distFromCenter[vi] = std::numeric_limits::max(); distFromCenter[v] = 0.f; @@ -145,11 +144,8 @@ void ComponentFinder<_MyMeshType, _MyVertexType>::Dijkstra(_MyMeshType& m, _MyVe prQueue.push(&v); v.SetV(); - float distance; - _MyVertexType* element; - while (!prQueue.empty()) { - element = prQueue.top(); + VertexType* element = prQueue.top(); prQueue.pop(); for (it = neighboursVect[element]->begin(); it != neighboursVect[element]->end(); it++) @@ -157,15 +153,14 @@ void ComponentFinder<_MyMeshType, _MyVertexType>::Dijkstra(_MyMeshType& m, _MyVe //I have not to compute the arches connecting vertices already visited. if (!(*it)->IsV()) { - distance = vcg::Distance((*it)->P(), element->P()); + float distance = vcg::Distance((*it)->P(), element->P()); // we take into account only the arcs with a distance less or equal to maxHopDist if (distance <= maxHopDist) { if ((distFromCenter[*element] + distance) < distFromCenter[*it]) + { distFromCenter[*it] = distFromCenter[*element] + distance; - - if (!(*it)->IsV()) { prQueue.push(*it); (*it)->SetV(); } @@ -181,18 +176,20 @@ void ComponentFinder<_MyMeshType, _MyVertexType>::Dijkstra(_MyMeshType& m, _MyVe /** * Used to free memory **/ -template -void ComponentFinder<_MyMeshType, _MyVertexType>::DeletePerVertexAttribute(_MyMeshType& m) { - KNNTree<_MyMeshType, _MyVertexType>::DeleteKNNTree(m); - bool hasDistParam = vcg::tri::HasPerVertexAttribute(m, "DistParam"); +static void DeletePerVertexAttribute(_MyMeshType& m) +{ + KNNGraph<_MyMeshType>::DeleteKNNTree(m); + + bool hasDistParam = tri::HasPerVertexAttribute(m, "DistParam"); if (hasDistParam) { - vcg::tri::Allocator<_MyMeshType>::DeletePerVertexAttribute(m, "DistParam"); + Allocator<_MyMeshType>::DeletePerVertexAttribute(m, "DistParam"); } - return; } - +}; // end ComponentFinder Class +} //end namespace tri +} // end namespace vcg; #endif // CONNECTEDCOMPONENT_H diff --git a/src/meshlabplugins/edit_point/edit_point.cpp b/src/meshlabplugins/edit_point/edit_point.cpp index e8842bb42..bc2d1cb30 100644 --- a/src/meshlabplugins/edit_point/edit_point.cpp +++ b/src/meshlabplugins/edit_point/edit_point.cpp @@ -50,6 +50,9 @@ const QString EditPointPlugin::Info() { void EditPointPlugin::Decorate(MeshModel &m, GLArea * gla, QPainter *p) { + this->RealTimeLog("EditPointHop","Hop Thr: %8.3f (Wheel to change it)",this->maxHop); + this->RealTimeLog("EditPointRad"," Radius: %8.3f (Drag or Alt+Wheel to change it)",this->dist); + /* When the user first click we have to find the point under the mouse pointer. At the same time we need to compute the Dijkstra algorithm over the knn-graph in order to find the distance between the selected point and the others. */ @@ -62,7 +65,7 @@ void EditPointPlugin::Decorate(MeshModel &m, GLArea * gla, QPainter *p) if(NewSel.size() > 0) { startingVertex = NewSel.front(); - ComponentFinder::Dijkstra(m.cm, *startingVertex, K, this->maxHop, this->NotReachableVector); + tri::ComponentFinder::Dijkstra(m.cm, *startingVertex, K, this->maxHop, this->NotReachableVector); ComponentVector.push_back(startingVertex); } @@ -181,6 +184,7 @@ bool EditPointPlugin::StartEdit(MeshModel &m, GLArea *gla) { this->maxHop = m.cm.bbox.Diag() / 100.0; this->planeDist = m.cm.bbox.Diag() / 100.0; this->fittingRadiusPerc = 0.1; + this->dist = 0; composingSelMode = SMClear; @@ -190,19 +194,22 @@ bool EditPointPlugin::StartEdit(MeshModel &m, GLArea *gla) { void EditPointPlugin::EndEdit(MeshModel &m, GLArea *gla) { //delete the circle if present. fittingCircle.Clear(); - ComponentFinder::DeletePerVertexAttribute(m.cm); + tri::ComponentFinder::DeletePerVertexAttribute(m.cm); } void EditPointPlugin::mousePressEvent(QMouseEvent *ev, MeshModel &m, GLArea *gla) { - startingVertex = NULL; cur = ev->pos(); - haveToPick = true; this->isMousePressed = true; - this->dist = 0.0; - this->startingClick = vcg::Point2f(ev->x(), ev->y()); + if(!(ev->modifiers() & Qt::AltModifier) || startingVertex == NULL) + { + this->startingClick = vcg::Point2f(ev->x(), ev->y()); + startingVertex = NULL; + this->dist = 0.0; + haveToPick = true; + } this->fittingRadius = 0.0; OldComponentVector.clear(); @@ -236,10 +243,10 @@ void EditPointPlugin::mouseMoveEvent(QMouseEvent *ev, MeshModel &m, GLArea *gla BorderVector.clear(); if (editType == SELECT_DEFAULT_MODE) - ComponentVector = ComponentFinder::FindComponent(m.cm, this->dist, BorderVector, NotReachableVector); + ComponentVector = tri::ComponentFinder::FindComponent(m.cm, this->dist, BorderVector, NotReachableVector); else if (editType == SELECT_FITTING_PLANE_MODE) { this->fittingRadius = dist * fittingRadiusPerc; - ComponentVector = ComponentFinder::FindComponent(m.cm, this->dist, BorderVector, NotReachableVector, true, fittingRadius, planeDist, &fittingPlane); + ComponentVector = tri::ComponentFinder::FindComponent(m.cm, this->dist, BorderVector, NotReachableVector, true, fittingRadius, planeDist, &fittingPlane); } gla->update(); @@ -326,47 +333,53 @@ void EditPointPlugin::keyPressEvent(QKeyEvent *ev, MeshModel &m, GLArea *gla) { new arcs to consider in the Dijkstra algorithm. If we modified other parameters we need only to find the new selected component. */ if (hopDistModified) { - ComponentFinder::Dijkstra(m.cm, *startingVertex, 6, this->maxHop, this->NotReachableVector); + tri::ComponentFinder::Dijkstra(m.cm, *startingVertex, 6, this->maxHop, this->NotReachableVector); } if (parameterModified) { BorderVector.clear(); if (editType == SELECT_DEFAULT_MODE) - ComponentVector = ComponentFinder::FindComponent(m.cm, this->dist, BorderVector, NotReachableVector); + ComponentVector = tri::ComponentFinder::FindComponent(m.cm, this->dist, BorderVector, NotReachableVector); else if (editType == SELECT_FITTING_PLANE_MODE) - ComponentVector = ComponentFinder::FindComponent(m.cm, this->dist, BorderVector, NotReachableVector, true, fittingRadius, planeDist, &fittingPlane); + ComponentVector = tri::ComponentFinder::FindComponent(m.cm, this->dist, BorderVector, NotReachableVector, true, fittingRadius, planeDist, &fittingPlane); } gla->update(); return; } -void EditPointPlugin::wheelEvent(QWheelEvent* ev, MeshModel &m, GLArea *gla) { - bool hopDistModified = false; - int wheelDirection = ev->delta(); +void EditPointPlugin::wheelEvent(QWheelEvent* ev, MeshModel &m, GLArea *gla) +{ + bool hopDistModified = false; + bool distModified = false; - if (startingVertex != NULL) { - if (wheelDirection > 0) { - this->maxHop *= pow(1.2f, wheelDirection / 120.f); - hopDistModified = true; - } - else if (wheelDirection < 0) { - this->maxHop /= pow(1.2f, (-1*wheelDirection) / 120.f); - hopDistModified = true; - } - } + int wheelDirection = ev->delta(); + if (startingVertex != NULL && (ev->modifiers() & Qt::AltModifier)) + { + this->dist *= pow(1.1f, wheelDirection / 120.f); + distModified = true; + } - if (hopDistModified) { - ComponentFinder::Dijkstra(m.cm, *startingVertex, K, this->maxHop, this->NotReachableVector); + if (!(ev->modifiers() & Qt::AltModifier)) + { + this->maxHop *= pow(1.1f, wheelDirection / 120.f); + hopDistModified = true; + } - BorderVector.clear(); + if (hopDistModified && (startingVertex != NULL)) { + tri::ComponentFinder::Dijkstra(m.cm, *startingVertex, K, this->maxHop, this->NotReachableVector); + } - if (editType == SELECT_DEFAULT_MODE) - ComponentVector = ComponentFinder::FindComponent(m.cm, this->dist, BorderVector, NotReachableVector); - else if (editType == SELECT_FITTING_PLANE_MODE) - ComponentVector = ComponentFinder::FindComponent(m.cm, this->dist, BorderVector, NotReachableVector, true, fittingRadius, planeDist, &fittingPlane); - } + if(startingVertex != NULL) + { + BorderVector.clear(); - gla->update(); - return; + if (editType == SELECT_DEFAULT_MODE) + ComponentVector = tri::ComponentFinder::FindComponent(m.cm, this->dist, BorderVector, NotReachableVector); + else if (editType == SELECT_FITTING_PLANE_MODE) + ComponentVector = tri::ComponentFinder::FindComponent(m.cm, this->dist, BorderVector, NotReachableVector, true, fittingRadius, planeDist, &fittingPlane); + } + + gla->update(); + return; } diff --git a/src/meshlabplugins/edit_point/knnGraph.h b/src/meshlabplugins/edit_point/knnGraph.h index 2138fab4d..1afdf9aad 100644 --- a/src/meshlabplugins/edit_point/knnGraph.h +++ b/src/meshlabplugins/edit_point/knnGraph.h @@ -10,22 +10,21 @@ #include -using namespace std; -using namespace vcg; +namespace vcg { +namespace tri { -template -class KNNTree { +template +class KNNGraph { public: - static void MakeKNNTree(_MyMeshType& m, int numOfNeighbours); - static void DeleteKNNTree(_MyMeshType& m); -}; -/** +typedef typename _MyMeshType::VertexType _MyVertexType; + + /** * Static function to create and fill the PerVertexAttribute KNNGraph, which stores the k-nearest * neighbours via vertex pointers */ -template -void KNNTree<_MyMeshType, _MyVertexType>::MakeKNNTree(_MyMeshType& m, int numOfNeighbours) { +static void MakeKNNTree(_MyMeshType& m, int numOfNeighbours) +{ //we search k+1 neighbours in order to exclude the queryPoint from the returned heap int neighboursVectSize = numOfNeighbours + 1; @@ -35,15 +34,15 @@ void KNNTree<_MyMeshType, _MyVertexType>::MakeKNNTree(_MyMeshType& m, int numOfN tri::Allocator<_MyMeshType>::CompactVertexVector(m); //the PerVertexAttribute handles is create and each of the vector capacity set to the maximum possible - typename _MyMeshType::template PerVertexAttributeHandle* > kNeighboursVect; - kNeighboursVect = vcg::tri::Allocator<_MyMeshType>::template AddPerVertexAttribute* >(m, std::string("KNNGraph")); + typename _MyMeshType::template PerVertexAttributeHandle* > kNeighboursVect; + kNeighboursVect = tri::Allocator<_MyMeshType>::template AddPerVertexAttribute* >(m, std::string("KNNGraph")); for (typename _MyMeshType::VertexIterator vi = m.vert.begin(); vi != m.vert.end(); vi++) { - kNeighboursVect[vi] = new vector<_MyVertexType*>(); + kNeighboursVect[vi] = new std::vector<_MyVertexType*>(); kNeighboursVect[vi]->reserve(neighboursVectSize); } //we create and fill the DataWrapper we need to pass the points to the KdTree - vector input(m.vn); + std::vector input(m.vn); int i = 0; for (typename _MyMeshType::VertexIterator vi = m.vert.begin(); vi != m.vert.end(); vi++, ++i) { input[i] = vi->cP(); @@ -77,15 +76,19 @@ void KNNTree<_MyMeshType, _MyVertexType>::MakeKNNTree(_MyMeshType& m, int numOfN /** * Static function which removes the KNNGraph PerVertex attribute */ -template -void KNNTree<_MyMeshType, _MyVertexType>::DeleteKNNTree(_MyMeshType& m) { +static void DeleteKNNTree(_MyMeshType& m) +{ bool hasKNNGraph = tri::HasPerVertexAttribute(m, "KNNGraph"); if (hasKNNGraph) { - vcg::tri::Allocator<_MyMeshType>::DeletePerVertexAttribute(m, "KNNGraph"); + tri::Allocator<_MyMeshType>::DeletePerVertexAttribute(m, "KNNGraph"); } return; } +}; // end knnGraph Class +} //end namespace tri +} // end namespace vcg; + #endif // KNNGRAPH_H