Commit 04f62a6c authored by Pierre Kraemer's avatar Pierre Kraemer

add normal angle selector to surface selection plugin

parent a517c887
......@@ -14,15 +14,8 @@
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Position :</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="combo_positionAttribute">
<item row="3" column="1">
<widget class="QComboBox" name="combo_selectionMethod">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
......@@ -31,27 +24,50 @@
</property>
<item>
<property name="text">
<string>- select attribute -</string>
<string>SingleCell</string>
</property>
</item>
<item>
<property name="text">
<string>WithinSphere</string>
</property>
</item>
<item>
<property name="text">
<string>NormalAngle</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0" colspan="2">
<widget class="Line" name="line">
<item row="4" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Vertical</enum>
</property>
</widget>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="0">
<item row="3" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Method :</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="combo_selectionMethod">
<item row="2" column="0" colspan="2">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="combo_positionAttribute">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
......@@ -60,29 +76,34 @@
</property>
<item>
<property name="text">
<string>SingleCell</string>
<string>- select attribute -</string>
</property>
</item>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Position :</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Normal :</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="combo_normalAttribute">
<item>
<property name="text">
<string>WithinSphere</string>
<string>- select attribute -</string>
</property>
</item>
</widget>
</item>
<item row="3" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>
......
......@@ -16,7 +16,8 @@ namespace SCHNApps
enum SelectionMethod
{
SingleCell = 0,
WithinSphere = 1
WithinSphere = 1,
NormalAngle = 2
};
struct MapParameters
......@@ -26,6 +27,7 @@ struct MapParameters
{}
VertexAttribute<PFP2::VEC3> positionAttribute;
VertexAttribute<PFP2::VEC3> normalAttribute;
SelectionMethod selectionMethod;
};
......@@ -70,8 +72,9 @@ private slots:
public slots:
// slots for Python calls
void changePositionAttribute(const QString& view, const QString& map, const QString& name);
void changeSelectionMethod(const QString& view, const QString& map, unsigned int method);
void changePositionAttribute(const QString& map, const QString& name);
void changeNormalAttribute(const QString& map, const QString& name);
void changeSelectionMethod(const QString& map, unsigned int method);
protected:
Surface_Selection_DockTab* m_dockTab;
......@@ -96,6 +99,9 @@ protected:
// WithinSphere parameters
Utils::VBO* m_selectionSphereVBO;
PFP2::REAL m_selectionRadius;
// NormalAngle parameters
PFP2::REAL m_normalAngleThreshold;
};
} // namespace SCHNApps
......
......@@ -29,6 +29,7 @@ private:
private slots:
void positionAttributeChanged(int index);
void normalAttributeChanged(int index);
void selectionMethodChanged(int index);
private:
......
......@@ -17,7 +17,8 @@ namespace SCHNApps
{
Surface_Selection_Plugin::Surface_Selection_Plugin() :
m_selecting(false)
m_selecting(false),
m_normalAngleThreshold(10)
{}
bool Surface_Selection_Plugin::enable()
......@@ -113,6 +114,7 @@ void Surface_Selection_Plugin::drawMap(View* view, MapHandlerGen* map)
switch(p.selectionMethod)
{
case NormalAngle :
case SingleCell : {
m_pointSprite->setSize(30 * map->getBBdiagSize() / nbCells);
break;
......@@ -139,6 +141,7 @@ void Surface_Selection_Plugin::drawMap(View* view, MapHandlerGen* map)
{
switch(p.selectionMethod)
{
case NormalAngle :
case SingleCell : {
PFP2::MAP* m = static_cast<MapHandler<PFP2>*>(map)->getMap();
m_selectingCellDrawer->newList(GL_COMPILE_AND_EXECUTE);
......@@ -180,6 +183,7 @@ void Surface_Selection_Plugin::drawMap(View* view, MapHandlerGen* map)
{
switch(p.selectionMethod)
{
case NormalAngle :
case SingleCell : {
PFP2::MAP* m = static_cast<MapHandler<PFP2>*>(map)->getMap();
m_selectingCellDrawer->newList(GL_COMPILE_AND_EXECUTE);
......@@ -277,6 +281,18 @@ void Surface_Selection_Plugin::mousePress(View* view, QMouseEvent* event)
selector->unselect(neigh.getInsideVertices());
break;
}
case NormalAngle : {
if(p.normalAttribute.isValid())
{
Algo::Surface::Selection::Collector_NormalAngle<PFP2> neigh(*map, p.normalAttribute, m_selectionRadius);
neigh.collectAll(m_selectingVertex);
if(event->button() == Qt::LeftButton)
selector->select(neigh.getInsideVertices());
else if(event->button() == Qt::RightButton)
selector->unselect(neigh.getInsideVertices());
}
break;
}
}
updateSelectedCellsRendering();
}
......@@ -303,6 +319,18 @@ void Surface_Selection_Plugin::mousePress(View* view, QMouseEvent* event)
selector->unselect(neigh.getInsideEdges());
break;
}
case NormalAngle : {
if(p.normalAttribute.isValid())
{
Algo::Surface::Selection::Collector_NormalAngle<PFP2> neigh(*map, p.normalAttribute, m_selectionRadius);
neigh.collectAll(m_selectingEdge);
if(event->button() == Qt::LeftButton)
selector->select(neigh.getInsideEdges());
else if(event->button() == Qt::RightButton)
selector->unselect(neigh.getInsideEdges());
}
break;
}
}
updateSelectedCellsRendering();
}
......@@ -329,6 +357,18 @@ void Surface_Selection_Plugin::mousePress(View* view, QMouseEvent* event)
selector->unselect(neigh.getInsideFaces());
break;
}
case NormalAngle : {
if(p.normalAttribute.isValid())
{
Algo::Surface::Selection::Collector_NormalAngle<PFP2> neigh(*map, p.normalAttribute, m_selectionRadius);
neigh.collectAll(m_selectingFace);
if(event->button() == Qt::LeftButton)
selector->select(neigh.getInsideFaces());
else if(event->button() == Qt::RightButton)
selector->unselect(neigh.getInsideFaces());
}
break;
}
}
updateSelectedCellsRendering();
}
......@@ -394,13 +434,26 @@ void Surface_Selection_Plugin::wheelEvent(View* view, QWheelEvent* event)
MapHandlerGen* mh = m_schnapps->getSelectedMap();
const MapParameters& p = h_parameterSet[mh];
if(p.selectionMethod == WithinSphere)
switch(p.selectionMethod)
{
if(event->delta() > 0)
m_selectionRadius *= 0.9f;
else
m_selectionRadius *= 1.1f;
view->updateGL();
case SingleCell : {
break;
}
case WithinSphere : {
if(event->delta() > 0)
m_selectionRadius *= 0.9f;
else
m_selectionRadius *= 1.1f;
view->updateGL();
break;
}
case NormalAngle : {
if(event->delta() > 0)
m_normalAngleThreshold *= 0.9f;
else
m_normalAngleThreshold *= 1.1f;
break;
}
}
}
}
......@@ -527,11 +580,10 @@ void Surface_Selection_Plugin::selectedMapConnectivityModified()
void Surface_Selection_Plugin::changePositionAttribute(const QString& view, const QString& map, const QString& name)
void Surface_Selection_Plugin::changePositionAttribute(const QString& map, const QString& name)
{
View* v = m_schnapps->getView(view);
MapHandlerGen* m = m_schnapps->getMap(map);
if(v && m)
if(m)
{
h_parameterSet[m].positionAttribute = m->getAttribute<PFP2::VEC3, VERTEX>(name);
if(m->isSelectedMap())
......@@ -539,11 +591,21 @@ void Surface_Selection_Plugin::changePositionAttribute(const QString& view, cons
}
}
void Surface_Selection_Plugin::changeSelectionMethod(const QString& view, const QString& map, unsigned int method)
void Surface_Selection_Plugin::changeNormalAttribute(const QString& map, const QString& name)
{
MapHandlerGen* m = m_schnapps->getMap(map);
if(m)
{
h_parameterSet[m].normalAttribute = m->getAttribute<PFP2::VEC3, VERTEX>(name);
if(m->isSelectedMap())
m_dockTab->updateMapParameters();
}
}
void Surface_Selection_Plugin::changeSelectionMethod(const QString& map, unsigned int method)
{
View* v = m_schnapps->getView(view);
MapHandlerGen* m = m_schnapps->getMap(map);
if(v && m)
if(m)
{
h_parameterSet[m].selectionMethod = SelectionMethod(method);
if(m->isSelectedMap())
......
......@@ -17,6 +17,7 @@ Surface_Selection_DockTab::Surface_Selection_DockTab(SCHNApps* s, Surface_Select
setupUi(this);
connect(combo_positionAttribute, SIGNAL(currentIndexChanged(int)), this, SLOT(positionAttributeChanged(int)));
connect(combo_normalAttribute, SIGNAL(currentIndexChanged(int)), this, SLOT(normalAttributeChanged(int)));
connect(combo_selectionMethod, SIGNAL(currentIndexChanged(int)), this, SLOT(selectionMethodChanged(int)));
}
......@@ -34,6 +35,16 @@ void Surface_Selection_DockTab::positionAttributeChanged(int index)
}
}
void Surface_Selection_DockTab::normalAttributeChanged(int index)
{
if(!b_updatingUI)
{
MapHandlerGen* map = m_schnapps->getSelectedMap();
if(map)
m_plugin->h_parameterSet[map].normalAttribute = map->getAttribute<PFP2::VEC3, VERTEX>(combo_normalAttribute->currentText());
}
}
void Surface_Selection_DockTab::selectionMethodChanged(int index)
{
if(!b_updatingUI)
......@@ -54,7 +65,10 @@ void Surface_Selection_DockTab::addVertexAttribute(const QString& nameAttr)
QString vec3TypeName = QString::fromStdString(nameOfType(PFP2::VEC3()));
const QString& typeAttr = m_schnapps->getSelectedMap()->getAttributeTypeName(VERTEX, nameAttr);
if(typeAttr == vec3TypeName)
{
combo_positionAttribute->addItem(nameAttr);
combo_normalAttribute->addItem(nameAttr);
}
b_updatingUI = false;
}
......@@ -64,6 +78,8 @@ void Surface_Selection_DockTab::updateMapParameters()
combo_positionAttribute->clear();
combo_positionAttribute->addItem("- select attribute -");
combo_normalAttribute->clear();
combo_normalAttribute->addItem("- select attribute -");
MapHandlerGen* map = m_schnapps->getSelectedMap();
......@@ -83,6 +99,10 @@ void Surface_Selection_DockTab::updateMapParameters()
if(p.positionAttribute.isValid() && it.key() == QString::fromStdString(p.positionAttribute.name()))
combo_positionAttribute->setCurrentIndex(i);
combo_normalAttribute->addItem(it.key());
if(p.normalAttribute.isValid() && it.key() == QString::fromStdString(p.normalAttribute.name()))
combo_normalAttribute->setCurrentIndex(i);
++i;
}
}
......
......@@ -46,4 +46,3 @@ ADD_SUBDIRECTORY(${SCHNApps_ROOT_DIR}/Plugins Plugins)
IF(IS_DIRECTORY ${SCHNApps_ROOT_DIR}/../../Plugins)
ADD_SUBDIRECTORY(${SCHNApps_ROOT_DIR}/../../Plugins ExtPlugins)
ENDIF(IS_DIRECTORY ${SCHNApps_ROOT_DIR}/../../Plugins)
......@@ -257,17 +257,52 @@ public:
void collectBorder(Dart d) ;
};
/*********************************************************
* Collector Normal Angle (Triangles)
*********************************************************/
/*
* collect all primitives of the connected component containing "centerDart"
* the angle between the included triangles normal vectors and the central normal vector
* stays under a given threshold
* NB : is equivalent to Collector_Triangles with CollectorCriterion_TriangleNormalAngle
*/
template <typename PFP>
class Collector_NormalAngle_Triangles : public Collector<PFP>
{
protected:
const FaceAttribute<typename PFP::VEC3>& normal ;
typename PFP::REAL angleThreshold ;
public:
Collector_NormalAngle_Triangles(
typename PFP::MAP& m,
const FaceAttribute<typename PFP::VEC3>& n,
typename PFP::REAL a,
unsigned int thread=0
) : Collector<PFP>(m,thread), normal(n), angleThreshold(a)
{}
inline void setAngleThreshold(typename PFP::REAL a) { angleThreshold = a; }
inline typename PFP::REAL getAngleThreshold() const { return angleThreshold; }
inline const VertexAttribute<typename PFP::VEC3>& getNormal() const { return normal ; }
void collectAll(Dart d) ;
void collectBorder(Dart d) ;
};
/*********************************************************
* Collector Criterions
*********************************************************/
class CollectorCriterion
{
public :
CollectorCriterion() {};
virtual ~CollectorCriterion() {} ;
CollectorCriterion() {}
virtual ~CollectorCriterion() {}
virtual void init(Dart center) = 0;
virtual bool isInside(Dart d) = 0;
};
template <typename PFP>
......@@ -277,15 +312,16 @@ private :
typedef typename PFP::VEC3 VEC3;
typedef typename PFP::REAL REAL;
const VertexAttribute<VEC3> & vertexNormals;
const VertexAttribute<VEC3>& vertexNormals;
REAL threshold;
VEC3 centerNormal;
public :
CollectorCriterion_VertexNormalAngle(const VertexAttribute<VEC3> & n, REAL th) :
CollectorCriterion_VertexNormalAngle(const VertexAttribute<VEC3>& n, REAL th) :
vertexNormals(n), threshold(th), centerNormal(0) {}
void init (Dart center) {centerNormal = vertexNormals[center];}
bool isInside (Dart d) {
bool isInside (Dart d)
{
return ( Geom::angle(centerNormal, vertexNormals[d]) < threshold);
}
};
......@@ -297,15 +333,16 @@ private :
typedef typename PFP::VEC3 VEC3;
typedef typename PFP::REAL REAL;
const FaceAttribute<VEC3> & faceNormals;
const FaceAttribute<VEC3>& faceNormals;
REAL threshold;
VEC3 centerNormal;
public :
CollectorCriterion_TriangleNormalAngle(const FaceAttribute<VEC3> & n, REAL th) :
CollectorCriterion_TriangleNormalAngle(const FaceAttribute<VEC3>& n, REAL th) :
faceNormals(n), threshold(th), centerNormal(0) {}
void init (Dart center) {centerNormal = faceNormals[center];}
bool isInside (Dart d) {
bool isInside (Dart d)
{
return ( Geom::angle(centerNormal, faceNormals[d]) < threshold);
}
};
......@@ -317,15 +354,16 @@ private :
typedef typename PFP::VEC3 VEC3;
typedef typename PFP::REAL REAL;
const VertexAttribute<VEC3> & vertexPositions;
const VertexAttribute<VEC3>& vertexPositions;
REAL threshold;
VEC3 centerPosition;
public :
CollectorCriterion_VertexWithinSphere(const VertexAttribute<VEC3> & p, REAL th) :
CollectorCriterion_VertexWithinSphere(const VertexAttribute<VEC3>& p, REAL th) :
vertexPositions(p), threshold(th), centerPosition(0) {}
void init (Dart center) {centerPosition = vertexPositions[center];}
bool isInside (Dart d) {
bool isInside (Dart d)
{
return (vertexPositions[d] - centerPosition).norm() < threshold ;
}
};
......@@ -337,7 +375,7 @@ public :
/*
* collect all vertices of the connected component containing "centerDart"
* within a distance to centerDart defined by the CollectorCriterion
* that satisfy the CollectorCriterion
* (hopefully) it defines a 2-manifold (if inserting border-vertices along the border-edges)
*/
template <typename PFP>
......@@ -357,39 +395,6 @@ public:
};
/*********************************************************
* Collector Normal Angle (Triangles)
*********************************************************/
/*
* collect all primitives of the connected component containing "centerDart"
* the angle between the included triangles normal vectors and the central normal vector
* stays under a given threshold
* NB : is equivalent to Collector_Triangles with CollectorCriterion_TriangleNormalAngle
*/
template <typename PFP>
class Collector_NormalAngle_Triangles : public Collector<PFP>
{
protected:
const FaceAttribute<typename PFP::VEC3>& normal ;
typename PFP::REAL angleThreshold ;
public:
Collector_NormalAngle_Triangles(
typename PFP::MAP& m,
const FaceAttribute<typename PFP::VEC3>& n,
typename PFP::REAL a,
unsigned int thread=0
) : Collector<PFP>(m,thread), normal(n), angleThreshold(a)
{}
inline void setAngleThreshold(typename PFP::REAL a) { angleThreshold = a; }
inline typename PFP::REAL getAngleThreshold() const { return angleThreshold; }
inline const VertexAttribute<typename PFP::VEC3>& getNormal() const { return normal ; }
void collectAll(Dart d) ;
void collectBorder(Dart d) ;
};
/*********************************************************
* Collector Triangles
*********************************************************/
......@@ -413,6 +418,7 @@ public:
void collectBorder(Dart d) ;
};
/*********************************************************
* Collector Dijkstra_Vertices
*********************************************************/
......@@ -450,7 +456,8 @@ public:
{
vertexInfo = m.template addAttribute<VertexInfo, VERTEX>("vertexInfo");
}
~Collector_Dijkstra_Vertices(){
~Collector_Dijkstra_Vertices()
{
this->map.removeAttribute(vertexInfo);
}
inline void init (Dart d) {Collector<PFP>::init(d); front.clear();}
......@@ -497,7 +504,8 @@ public:
{
vertexInfo = m.template addAttribute<VertexInfo, VERTEX>("vertexInfo");
}
~Collector_Dijkstra(){
~Collector_Dijkstra()
{
this->map.removeAttribute(vertexInfo);
}
inline void init (Dart d) {Collector<PFP>::init(d); front.clear();}
......@@ -507,6 +515,7 @@ public:
void collectAll(Dart d);
void collectBorder(Dart d);
private :
inline float edgeLength (Dart d);
// inline Dart oppositeVertex (Dart d);
......
......@@ -659,122 +659,6 @@ void Collector_NormalAngle<PFP>::collectBorder(Dart d)
this->insideVertices.clear();
}
/*********************************************************
* Collector Vertices
*********************************************************/
template <typename PFP>
void Collector_Vertices<PFP>::collectAll(Dart d)
{
typedef typename PFP::VEC3 VEC3;
typedef typename PFP::REAL REAL;
crit.init(d);
this->init(d);
this->isInsideCollected = true;
this->insideEdges.reserve(32);
this->insideFaces.reserve(32);
this->border.reserve(32);
CellMarkerStore<VERTEX> vm(this->map, this->m_thread); // mark the collected inside-vertices
CellMarkerStore<EDGE> em(this->map, this->m_thread); // mark the collected inside-edges + border-edges
CellMarkerStore<FACE> fm(this->map, this->m_thread); // mark the collected inside-faces + border-faces
this->insideVertices.push_back(this->centerDart);
vm.mark(this->centerDart);
unsigned int i = 0;
while (i < this->insideVertices.size())
{
Dart end = this->insideVertices[i];
Dart e = end;
do
{
if (! em.isMarked(e) || ! fm.isMarked(e)) // are both tests useful ?
{
const Dart f = this->map.phi1(e);
const Dart g = this->map.phi1(f);
if (! crit.isInside(f))
{
this->border.push_back(e); // add to border
em.mark(e);
fm.mark(e); // is it useful ?
}
else
{
if (! vm.isMarked(f))
{
this->insideVertices.push_back(f);
vm.mark(f);
}
if (! em.isMarked(e))
{
this->insideEdges.push_back(e);
em.mark(e);
}
if (! fm.isMarked(e) && crit.isInside(g))
{
this->insideFaces.push_back(e);
fm.mark(e);
}
}
}
e = this->map.phi2_1(e);
} while (e != end);
++i;
}
}
template <typename PFP>
void Collector_Vertices<PFP>::collectBorder(Dart d)
{
typedef typename PFP::VEC3 VEC3;
typedef typename PFP::REAL REAL;
crit.init(d);
this->init(d);
this->border.reserve(128);
this->insideVertices.reserve(128);
CellMarkerStore<VERTEX> vm(this->map, this->m_thread); // mark the collected inside-vertices
CellMarkerStore<EDGE> em(this->map, this->m_thread); // mark the collected inside-edges + border-edges
this->insideVertices.push_back(this->centerDart);
vm.mark(this->centerDart);
unsigned int i = 0;
while (i < this->insideVertices.size())
{
Dart end = this->insideVertices[i];
Dart e = end;
do
{
if ( ! em.isMarked(e) )
{
const Dart f = this->map.phi1(e);
if (! crit.isInside(f))
{
this->border.push_back(e); // add to border
}
else
{
if (! vm.isMarked(f))
{
this->insideVertices.push_back(f);
vm.mark(f);
}
}
em.mark(e);
}
e = this->map.phi2_1(e);
} while (e != end);
++i;
}
this->insideVertices.clear();
}
/*********************************************************