From fd90fd27db2e8185c75d224b96336efafca27b5f Mon Sep 17 00:00:00 2001 From: Manuele Sabbadin msabbadin Date: Tue, 24 Jan 2012 17:01:38 +0000 Subject: [PATCH] An edit plugin to select parts of a point cloud in a reasonable way. It is based on a knn-graph, built on the mesh, where we search for near points. It takes two parameters, a maximum distance of hop (between two adjacent points in the graph) and a maximum distance from the selected point. Both of them are chosen via mouse (actually via keyboard). --- src/fgt/edit_point/connectedComponent.h | 202 ++++++++++++++++++++++ src/fgt/edit_point/edit_point.cpp | 179 +++++++++++++++++++ src/fgt/edit_point/edit_point.h | 67 +++++++ src/fgt/edit_point/edit_point.pro | 23 +++ src/fgt/edit_point/edit_point_factory.cpp | 57 ++++++ src/fgt/edit_point/edit_point_factory.h | 55 ++++++ src/fgt/edit_point/knnGraph.h | 88 ++++++++++ 7 files changed, 671 insertions(+) create mode 100644 src/fgt/edit_point/connectedComponent.h create mode 100644 src/fgt/edit_point/edit_point.cpp create mode 100644 src/fgt/edit_point/edit_point.h create mode 100644 src/fgt/edit_point/edit_point.pro create mode 100644 src/fgt/edit_point/edit_point_factory.cpp create mode 100644 src/fgt/edit_point/edit_point_factory.h create mode 100644 src/fgt/edit_point/knnGraph.h diff --git a/src/fgt/edit_point/connectedComponent.h b/src/fgt/edit_point/connectedComponent.h new file mode 100644 index 000000000..ff1c4ecb8 --- /dev/null +++ b/src/fgt/edit_point/connectedComponent.h @@ -0,0 +1,202 @@ +#ifndef CONNECTEDCOMPONENT_H +#define CONNECTEDCOMPONENT_H + +#include "knnGraph.h" + +#include +#include + +#include +#include +#include + + +using namespace std; +using namespace vcg; + +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 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 vertex of the connected component with + * center v and max distance (in number of edges) 'numOfHop' from v. + * It uses the knnGraph with k = numOfNeighbours to find the component. + * In order to compute the connected component it is used a Depth-Limited search + **/ +template +std::vector<_MyVertexType*> &ComponentFinder<_MyMeshType, _MyVertexType>::FindComponent(_MyMeshType& m, _MyVertexType& v, int numOfNeighbours, int numOfHop) { + vector<_MyVertexType*> *resultVect = new vector<_MyVertexType*>(); + stack<_MyVertexType*> DFSStack; + stack levelStack; + + tri::UpdateFlags<_MyMeshType>::VertexClearV(m); + + KNNTree<_MyMeshType, _MyVertexType>::MakeKNNTree(m, numOfNeighbours); + + typename _MyMeshType::template PerVertexAttributeHandle* > neighboursVect = vcg::tri::Allocator<_MyMeshType>::template GetPerVertexAttribute* >(m,"KNNGraph"); + typename vector<_MyVertexType*>::iterator it; + int actualLevel; + + DFSStack.push(&v); + levelStack.push(0); + v.SetV(); + resultVect->push_back(&v); + + + // The Depth-Limited Search + _MyVertexType* element; + while (!DFSStack.empty()) { + element = DFSStack.top(); + actualLevel = levelStack.top(); + DFSStack.pop(); + levelStack.pop(); + + if (actualLevel < numOfHop) { + for (it = neighboursVect[element]->begin(); it != neighboursVect[element]->end(); it++) { + if (!((*it)->IsV())) { + DFSStack.push(*it); + levelStack.push(actualLevel + 1); + (*it)->SetV(); + resultVect->push_back(*it); + } + } + } + } + + KNNTree<_MyMeshType, _MyVertexType>::DeleteKNNTree(m); + + return *resultVect; +} + + + + + +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 returns a vector which stores pointers to the vertex of the connected component with + * center v and max distance 'dim' from v. + * It uses the knnGraph with k = numOfNeighbours to find the component. + * In order to compute the connected component it is used a Shortest Path algorithm where maxHopDist is the + * 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) { + vector<_MyVertexType*> *resultVect = new vector<_MyVertexType*>(); + + 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 (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); + } + + return *resultVect; +} + + +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; + + 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++) { + 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(); + } + else if (distance > maxHopDist) notReachableVect.push_back(*it); + } + } +} + + +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 diff --git a/src/fgt/edit_point/edit_point.cpp b/src/fgt/edit_point/edit_point.cpp new file mode 100644 index 000000000..5a84c468a --- /dev/null +++ b/src/fgt/edit_point/edit_point.cpp @@ -0,0 +1,179 @@ +/**************************************************************************** + * 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. * + * * + ****************************************************************************/ + +#include + +#include +#include +#include +#include "edit_point.h" +#include +#include + +#include "connectedComponent.h" + + +using namespace std; +using namespace vcg; + +EditPointPlugin::EditPointPlugin() {} + +const QString EditPointPlugin::Info() { + return tr("Select a region of the mesh"); +} + +void EditPointPlugin::Decorate(MeshModel &m, GLArea * gla, QPainter *p) +{ + if(haveToPick) + { + glPushMatrix(); + glMultMatrix(m.cm.Tr); + vector NewSel; + GLPickTri::PickVert(cur.x(), gla->height() - cur.y(), m.cm, NewSel); + if(NewSel.size() > 0) { + startingVertex = NewSel.front(); + + ComponentFinder::Dijkstra(m.cm, *startingVertex, 6, this->maxHop, this->NotReachableVector); + ComponentVector.push_back(startingVertex); + } + + haveToPick = false; + glPopMatrix(); + } + + if (startingVertex != NULL) { + glPushMatrix(); + glMultMatrix(m.cm.Tr); + + glPushAttrib(GL_ENABLE_BIT ); + glDisable(GL_LIGHTING); + glDisable(GL_TEXTURE_2D); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); + glDepthRange (0.0, 0.9999); + glDepthFunc(GL_LEQUAL); + glPointSize(6.f); + + glBegin(GL_POINTS); + glColor4f(1,0,0,.6f); + + for(vector::iterator vi = ComponentVector.begin(); vi != ComponentVector.end(); ++vi) + { + glVertex((*vi)->cP()); + } + glEnd(); + + glBegin(GL_POINTS); + glColor4f(1,1,0,.6f); + + for(vector::iterator vi = BorderVector.begin(); vi != BorderVector.end(); ++vi) + { + glVertex((*vi)->cP()); + } + + glEnd(); + glPopAttrib(); + glPopMatrix(); + } +} + +bool EditPointPlugin::StartEdit(MeshModel &m, GLArea *gla ) { + BorderVector = std::vector(); + NotReachableVector = std::vector(); + this->maxHop = m.cm.bbox.Diag() / 100.0; + + return true; +} + +void EditPointPlugin::EndEdit(MeshModel &m, GLArea *gla) { + 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()); + + BorderVector.clear(); + ComponentVector.clear(); +} + +void EditPointPlugin::mouseMoveEvent(QMouseEvent *ev, MeshModel &m, GLArea *gla ) { + if (this->isMousePressed && startingVertex != NULL) { + float distFromCenter = math::Sqrt((startingClick.X() - ev->x())*(startingClick.X() - ev->x()) + (startingClick.Y() - ev->y()) * (startingClick.Y() - ev->y())); + + float perim = 2 * m.cm.bbox.DimX() + 2 * m.cm.bbox.DimY(); + perim = (perim < 2 * m.cm.bbox.DimY() + 2 * m.cm.bbox.DimZ()) ? 2 * m.cm.bbox.DimY() + 2 * m.cm.bbox.DimZ() : perim; + perim = (perim < 2 * m.cm.bbox.DimX() + 2 * m.cm.bbox.DimZ()) ? 2 * m.cm.bbox.DimX() + 2 * m.cm.bbox.DimZ() : perim; + + this->dist = (perim * distFromCenter) / gla->width(); + + BorderVector.clear(); + ComponentVector = ComponentFinder::FindComponent(m.cm, *startingVertex, 6, this->dist, this->maxHop, BorderVector, NotReachableVector); + } +} + +void EditPointPlugin::mouseReleaseEvent(QMouseEvent *ev, MeshModel &m, GLArea *gla) { + gla->update(); +} + +void EditPointPlugin::keyPressEvent(QKeyEvent *ev, MeshModel &m, GLArea *gla) { + bool hopDistModified = false; + int keyPressed = ev->key(); + + if (startingVertex != NULL) { + switch (keyPressed) { + case Qt::Key_A: + this->maxHop *= 1.2; + + hopDistModified = true; + + break; + + case Qt::Key_Z: + this->maxHop /= 1.2; + + hopDistModified = true; + + break; + + default: break; + } + } + + if (hopDistModified) { + ComponentFinder::Dijkstra(m.cm, *startingVertex, 6, this->maxHop, this->NotReachableVector); + + BorderVector.clear(); + ComponentVector = ComponentFinder::FindComponent(m.cm, *startingVertex, 6, this->dist, this->maxHop, BorderVector, NotReachableVector); + } + + gla->update(); + return; +} diff --git a/src/fgt/edit_point/edit_point.h b/src/fgt/edit_point/edit_point.h new file mode 100644 index 000000000..a7e969000 --- /dev/null +++ b/src/fgt/edit_point/edit_point.h @@ -0,0 +1,67 @@ +/**************************************************************************** +* 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. * +* * +****************************************************************************/ + +#ifndef EDITPOINTPLUGIN_H +#define EDITPOINTPLUGIN_H + +#include +#include + +class EditPointPlugin : public QObject, public MeshEditInterface +{ + Q_OBJECT + Q_INTERFACES(MeshEditInterface) + +public: + EditPointPlugin(); + virtual ~EditPointPlugin() {} + + static const QString Info(); + + bool StartEdit(MeshModel &/*m*/, GLArea * /*parent*/); + void EndEdit(MeshModel &/*m*/, GLArea * /*parent*/); + void Decorate(MeshModel &/*m*/, GLArea * /*parent*/, QPainter *p); + void mousePressEvent(QMouseEvent *, MeshModel &, GLArea * ); + void mouseMoveEvent(QMouseEvent *, MeshModel &, GLArea * ); + void mouseReleaseEvent(QMouseEvent *, MeshModel &/*m*/, GLArea * ); + void keyPressEvent(QKeyEvent *, MeshModel &/*m*/, GLArea *); + + +private: + bool isMousePressed; + bool haveToPick; + + CMeshO::VertexPointer startingVertex; + vcg::Point2f startingClick; + + float dist; + float maxHop; + + std::vector ComponentVector; + std::vector BorderVector; + std::vector NotReachableVector; + + QPoint cur; +}; + +#endif diff --git a/src/fgt/edit_point/edit_point.pro b/src/fgt/edit_point/edit_point.pro new file mode 100644 index 000000000..2b6594db4 --- /dev/null +++ b/src/fgt/edit_point/edit_point.pro @@ -0,0 +1,23 @@ +include (../../shared.pri) + + +HEADERS = \ + edit_point.h \ + edit_point_factory.h \ + connectedComponent.h \ + knnGraph.h + +SOURCES = \ + edit_point.cpp \ + edit_point_factory.cpp \ + + +TARGET = edit_point + +QT += opengl + +#RESOURCES = sampleedit.qrc + + + + diff --git a/src/fgt/edit_point/edit_point_factory.cpp b/src/fgt/edit_point/edit_point_factory.cpp new file mode 100644 index 000000000..36f8c075a --- /dev/null +++ b/src/fgt/edit_point/edit_point_factory.cpp @@ -0,0 +1,57 @@ +/**************************************************************************** +* MeshLab o o * +* A versatile mesh processing toolbox o o * +* _ O _ * +* Copyright(C) 2005-2008 \/)\/ * +* 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 "edit_point_factory.h" +#include "edit_point.h" + +PointEditFactory::PointEditFactory() +{ + editPoint = new QAction(QIcon(":/images/icon_info.png"),"Point", this); + + actionList << editPoint; + + foreach(QAction *editAction, actionList) + editAction->setCheckable(true); +} + +//gets a list of actions available from this plugin +QList PointEditFactory::actions() const +{ + return actionList; +} + +//get the edit tool for the given action +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 +} + +QString PointEditFactory::getEditToolDescription(QAction *) +{ + return EditPointPlugin::Info(); +} + +Q_EXPORT_PLUGIN(PointEditFactory) diff --git a/src/fgt/edit_point/edit_point_factory.h b/src/fgt/edit_point/edit_point_factory.h new file mode 100644 index 000000000..7c7609711 --- /dev/null +++ b/src/fgt/edit_point/edit_point_factory.h @@ -0,0 +1,55 @@ +/**************************************************************************** +* MeshLab o o * +* A versatile mesh processing toolbox o o * +* _ O _ * +* Copyright(C) 2005-2008 \/)\/ * +* 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. * +* * +****************************************************************************/ + + +#ifndef EditPointFactoryPLUGIN_H +#define EditPointFactoryPLUGIN_H + +#include +#include + +class PointEditFactory : public QObject, public MeshEditInterfaceFactory +{ + Q_OBJECT + Q_INTERFACES(MeshEditInterfaceFactory) + +public: + PointEditFactory(); + virtual ~PointEditFactory() { delete editPoint; } + + //gets a list of actions available from this plugin + virtual QList actions() const; + + //get the edit tool for the given action + virtual MeshEditInterface* getMeshEditInterface(QAction *); + + //get the description for the given action + virtual QString getEditToolDescription(QAction *); + +private: + QList actionList; + + QAction *editPoint; +}; + +#endif diff --git a/src/fgt/edit_point/knnGraph.h b/src/fgt/edit_point/knnGraph.h new file mode 100644 index 000000000..8b4ce171b --- /dev/null +++ b/src/fgt/edit_point/knnGraph.h @@ -0,0 +1,88 @@ +#ifndef KNNGRAPH_H +#define KNNGRAPH_H + +#include + +#include +#include + +#include + +using namespace std; +using namespace vcg; + +template +class KNNTree { +public: + static void MakeKNNTree(_MyMeshType& m, int numOfNeighbours); + static void DeleteKNNTree(_MyMeshType& m); +}; + +/** + * 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) { + //we search k+1 neighbours in order to exclude the queryPoint from the returned heap + int neighboursVectSize = numOfNeighbours + 1; + + int neighbours; //number of neighbours found (no more than neighboursVectSize) + + //we have to use the indices of the vertices, and they MUST be continuous + 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")); + for (typename _MyMeshType::VertexIterator vi = m.vert.begin(); vi != m.vert.end(); vi++) { + kNeighboursVect[vi] = new 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); + int i = 0; + for (typename _MyMeshType::VertexIterator vi = m.vert.begin(); vi != m.vert.end(); vi++, ++i) { + input[i] = vi->cP(); + } + ConstDataWrapper DW(&(input[0]), input.size()); + + KdTree tree(DW); + + tree.setMaxNofNeighbors(neighboursVectSize); + + //For each vertex we insert the k-nearest neighbours in the associated vector. + //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! + int neightId = -1; + for (int j = 0; j < m.vn; j++) { + tree.doQueryK(m.vert[j].cP()); + + neighbours = tree.getNofFoundNeighbors(); + for (int i = 0; i < neighbours; i++) { + neightId = tree.getNeighborId(i); + if (neightId < m.vn && (neightId != j)) + kNeighboursVect[m.vert[j]]->push_back(&(m.vert[neightId])); + } + } + + return; +} + +/** + * Static function which removes the KNNGraph PerVertex attribute + */ +template +void KNNTree<_MyMeshType, _MyVertexType>::DeleteKNNTree(_MyMeshType& m) { + bool hasKNNGraph = tri::HasPerVertexAttribute(m, "KNNGraph"); + + if (hasKNNGraph) { + vcg::tri::Allocator<_MyMeshType>::DeletePerVertexAttribute(m, "KNNGraph"); + } + + return; +} + +#endif // KNNGRAPH_H