#ifndef CONNECTEDCOMPONENT_H #define CONNECTEDCOMPONENT_H #include #include "knnGraph.h" #include #include #include #include #include #include using namespace std; using namespace vcg; template class ComponentFinder { 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 * 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 * couldn't reach because of the hop distance. * * 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(); tri::UpdateFlags<_MyMeshType>::VertexClearV(m); bool hasDistParam = vcg::tri::HasPerVertexAttribute(m, "DistParam"); typename _MyMeshType::template PerVertexAttributeHandle distFromCenter; if (hasDistParam) distFromCenter = vcg::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++) { 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; if (fitting) { 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; } /* This class is used in the priority queue to order the nodes */ template class Compare { private: typename _MyMeshType::template PerVertexAttributeHandle *distFromCenter; public: Compare(typename _MyMeshType::template PerVertexAttributeHandle *distFromCenter) { this->distFromCenter = distFromCenter; } bool operator() (const _MyVertexType* lhs, const _MyVertexType* rhs) const { return (*distFromCenter)[*lhs] > (*distFromCenter)[*rhs]; } }; /** This function is used to calculate the minimum distances between one point (v) and all the others * in the mesh. We use the Dijkstra algorithm with one change: only arcs with a cost less or equal * of maxHopDist will be taken into account. * In the first call of this method, when neither DistParam or KNNGraph are present, we create these * 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"); notReachableVect.clear(); typename _MyMeshType::template PerVertexAttributeHandle distFromCenter; if (!hasDistParam) { distFromCenter = vcg::tri::Allocator<_MyMeshType>::template AddPerVertexAttribute(m, std::string("DistParam")); } else distFromCenter = vcg::tri::Allocator<_MyMeshType>::template GetPerVertexAttribute(m, std::string("DistParam")); if (!hasKNNGraph) { KNNTree<_MyMeshType, _MyVertexType>::MakeKNNTree(m, numOfNeighbours); } typename _MyMeshType::template PerVertexAttributeHandle* > neighboursVect = vcg::tri::Allocator<_MyMeshType>::template GetPerVertexAttribute* >(m,"KNNGraph"); typename vector<_MyVertexType*>::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); VertPriorityQueue prQueue (Comparator); for (typename _MyMeshType::VertexIterator vi = m.vert.begin(); vi != m.vert.end(); vi++) distFromCenter[vi] = numeric_limits::max(); distFromCenter[v] = 0.f; tri::UpdateFlags<_MyMeshType>::VertexClearV(m); prQueue.push(&v); v.SetV(); float distance; _MyVertexType* element; while (!prQueue.empty()) { element = prQueue.top(); prQueue.pop(); for (it = neighboursVect[element]->begin(); it != neighboursVect[element]->end(); it++) { //I have not to compute the arches connecting vertices already visited. if (!(*it)->IsV()) { 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(); } } // all the other are the notReachable arcs else if (distance > maxHopDist) notReachableVect.push_back(element); } } } } /** * Used to free memory **/ template void ComponentFinder<_MyMeshType, _MyVertexType>::DeletePerVertexAttribute(_MyMeshType& m) { KNNTree<_MyMeshType, _MyVertexType>::DeleteKNNTree(m); bool hasDistParam = vcg::tri::HasPerVertexAttribute(m, "DistParam"); if (hasDistParam) { vcg::tri::Allocator<_MyMeshType>::DeletePerVertexAttribute(m, "DistParam"); } return; } #endif // CONNECTEDCOMPONENT_H