Commit 725ff86f authored by Matthias Möller's avatar Matthias Möller

adds lasso and floodfill selectionmode for OVM

thanks to Vladimir Chalupecky

refs #1880

git-svn-id: http://www.openflipper.org/svnrepo/OpenFlipper/branches/Free@17848 383ad7c9-94d9-4d36-a494-682f7c89f535
parent 8f3dfcb1
This diff is collapsed.
......@@ -86,6 +86,8 @@ public:
/// Default destructor
~VolumeMeshSelectionPlugin();
friend class SelectVolumeAction;
signals:
// BaseInterface
......@@ -107,8 +109,11 @@ signals:
void registerType(QString _handleName, DataType _type);
void addPrimitiveType(QString _handleName, QString _name, QString _icon, SelectionInterface::PrimitiveType& _typeHandle);
void addSelectionOperations(QString _handleName, QStringList _operationsList, QString _category, SelectionInterface::PrimitiveType _type = 0u);
void showToggleSelectionMode(QString _handleName, bool _show, SelectionInterface::PrimitiveType _associatedTypes);
void showVolumeLassoSelectionMode(QString _handleName, bool _show, SelectionInterface::PrimitiveType _associatedTypes);
void showFloodFillSelectionMode(QString _handleName, bool _show, SelectionInterface::PrimitiveType _associatedTypes);
void addCustomSelectionMode(QString _handleName, QString _modeName, QString _description, QString _icon,
SelectionInterface::PrimitiveType _associatedTypes, QString& _customIdentifier);
......@@ -132,6 +137,9 @@ private slots:
// SelectionInterface
void slotSelectionOperation(QString _operation);
void slotToggleSelection(QMouseEvent* _event, SelectionInterface::PrimitiveType _currentType, bool _deselect);
void slotVolumeLassoSelection(QMouseEvent* _event, SelectionInterface::PrimitiveType _currentType, bool _deselect);
void slotFloodFillSelection(QMouseEvent* _event, double _maxAngle, SelectionInterface::PrimitiveType _currentType, bool _deselect);
void slotCustomSelection(QMouseEvent *_event, SelectionInterface::PrimitiveType _currentType, QString _customIdentifier, bool _deselect);
void slotLoadSelection(const INIFile& _file);
......@@ -311,6 +319,15 @@ public slots:
//===========================================================================
private:
/// Surface volume selection tool
template<class MeshT>
bool volumeSelection(MeshT* _mesh, ACG::GLState& _state, QRegion *_region,
PrimitiveType _primitiveTypes, bool _deselection);
/// Select all entities that are connected (and do not exceed the maximum dihedral angle)
template<class MeshT>
void floodFillSelection(MeshT* _mesh, uint _fh, double _maxAngle,
PrimitiveType _primitiveTypes, bool _deselection);
// Get orthogonal orientation of neighboring cell
unsigned char getOrthogonalOrientationOfNeighborCell(const OpenVolumeMesh::CellHandle& _ch1,
......@@ -334,6 +351,7 @@ private:
PrimitiveType cellType_;
PrimitiveType allSupportedTypes_;
PrimitiveType floodFillSupportedTypes_;
/// Keep volume lasso points
QVector<QPoint> volumeLassoPoints_;
......@@ -347,6 +365,38 @@ private:
};
/// Traverse the scenegraph and call the selection function for all mesh nodes
class SelectVolumeAction
{
public:
SelectVolumeAction(QRegion&_region, VolumeMeshSelectionPlugin* _plugin,
unsigned int _type, bool _deselection, ACG::GLState& _state)
: state_(_state)
, region_(_region)
, plugin_(_plugin)
, type_(_type)
, deselection_(_deselection)
{
}
void enter(BaseNode* /*_node*/) {}
void leave(BaseNode* /*_node*/) {}
bool operator()(BaseNode* _node);
private:
ACG::GLState& state_;
QRegion& region_;
VolumeMeshSelectionPlugin* plugin_;
unsigned int type_;
bool deselection_;
};
//=============================================================================
#if defined(INCLUDE_TEMPLATES) && !defined(VOLUMEMESHSELECTIONPLUGINT_CC)
#define VOLUMEMESHSELECTIONPLUGINT_TEMPLATES
#include "VolumeMeshSelectionPluginT.cc"
#endif
//=============================================================================
#endif // VOLUMEMESHSELECTIONPLUGIN_HH defined
//=============================================================================
#include "VolumeMeshSelectionPlugin.hh"
#include <stack>
#include <vector>
#include <cmath>
//***********************************************************************************
/** \brief Select all primitives that are entirely projected to the given region
*
* @param _mesh a mesh
* @param _state current gl state
* @param _region region
* @param _primitiveType primitive types to be selected
* @param _deselection true, if entities should be deselected
* @return true, if something was selected
*/
template<class MeshT>
bool VolumeMeshSelectionPlugin::volumeSelection(MeshT* _mesh, ACG::GLState& _state, QRegion *_region,
PrimitiveType _primitiveType, bool _deselection) {
using namespace OpenVolumeMesh;
ACG::Vec3d proj;
bool rv = false;
//reset tagged status
StatusAttrib status(*_mesh);
VertexIter v_it(_mesh->vertices_begin()), v_end(_mesh->vertices_end());
for (; v_it != v_end; ++v_it)
status[*v_it].set_tagged(false);
//tag all vertices that are projected into region
for (v_it = _mesh->vertices_begin(); v_it != v_end; ++v_it) {
proj = _state.project(_mesh->vertex(*v_it));
if (_region->contains(QPoint((int)proj[0], _state.context_height()- (int)proj[1]))) {
status[*v_it].set_tagged(true);
if (_primitiveType & vertexType_) {
rv = true;
status[*v_it].set_selected(!_deselection);
}
}
}
if (_primitiveType & edgeType_) {
EdgeIter e_it(_mesh->edges_begin()), e_end(_mesh->edges_end());
for (; e_it != e_end; ++e_it)
{
VertexHandle v1 = _mesh->halfedge(_mesh->halfedge_handle(*e_it, 0)).to_vertex();
VertexHandle v2 = _mesh->halfedge(_mesh->halfedge_handle(*e_it, 1)).to_vertex();
// select only edges whose both vertices are within the selection region
if (status[v1].tagged() && status[v2].tagged()) {
rv = true;
status[*e_it].set_selected(!_deselection);
}
}
}
if (_primitiveType & faceType_) {
FaceIter f_it(_mesh->faces_begin()), f_end(_mesh->faces_end());
for (; f_it != f_end; ++f_it) {
const std::vector<HalfEdgeHandle>& halfedges = _mesh->face(*f_it).halfedges();
bool all_fv_tagged = true;
for (std::size_t i = 0; i < halfedges.size(); ++i) {
VertexHandle v = _mesh->halfedge(halfedges[i]).to_vertex();
all_fv_tagged &= status[v].tagged();
}
// select only faces that are completely within the selection region
if (all_fv_tagged) {
rv = true;
status[*f_it].set_selected(!_deselection);
}
}
}
if (_primitiveType & cellType_) {
CellIter c_it(_mesh->cells_begin()), c_end(_mesh->cells_end());
for (; c_it != c_end; ++c_it) {
bool all_cv_tagged = true;
for (CellVertexIter cv_it(_mesh->cv_iter(*c_it)); cv_it.valid(); ++cv_it) {
all_cv_tagged &= status[*cv_it].tagged();
}
if (all_cv_tagged) {
rv = true;
status[*c_it].set_selected(!_deselection);
}
}
}
return rv;
}
//***********************************************************************************
/** \brief Select all primitves of a planar region surrounding the faceHandle
*
* @param _mesh a mesh
* @param _fh handle of the face that was picked
* @param _maxAngle the maximum dihedral angle over which the flood fill selection passes
* @param _primitiveTypes the currently active primitive types
* @param _deselection true if primitives should be deselected
*/
template<class MeshT>
void VolumeMeshSelectionPlugin::floodFillSelection(MeshT* _mesh, uint _fh, double _maxAngle,
PrimitiveType _primitiveTypes, bool _deselection)
{
using namespace OpenVolumeMesh;
FaceHandle hitFace(_fh);
if (!_mesh->is_boundary(hitFace))
return;
HalfFaceHandle hitHalfFace = _mesh->halfface_handle(hitFace, 0);
if (!_mesh->is_boundary(hitHalfFace))
hitHalfFace = _mesh->halfface_handle(hitFace, 1);
StatusAttrib status(*_mesh);
// reset tagged status
HalfFaceIter hf_it(_mesh->halffaces_begin()), hf_end(_mesh->halffaces_end());
for (; hf_it != hf_end; ++hf_it)
{
status[*hf_it].set_tagged(false);
}
status[hitHalfFace].set_tagged(true);
std::stack<HalfFaceHandle> hf_handles;
hf_handles.push(hitHalfFace);
NormalAttrib<MeshT> normals(*_mesh);
typename MeshT::PointT n1 = normals[hitHalfFace];
double maxAngle = _maxAngle / 180.0 * M_PI;
// tag all half-faces whose normal does not deviate too much from the
// initial face
while (!hf_handles.empty())
{
HalfFaceHandle hf = hf_handles.top();
hf_handles.pop();
for (BoundaryHalfFaceHalfFaceIter bhfhf_it(hf, _mesh) ; bhfhf_it.valid() ; ++bhfhf_it)
{
if (status[*bhfhf_it].tagged())
continue;
typename MeshT::PointT n2 = normals[*bhfhf_it];
double angle = std::acos(n1 | n2);
if (angle <= maxAngle) {
status[*bhfhf_it].set_tagged(true);
hf_handles.push(*bhfhf_it);
}
}
}
// now select all tagged primitives
for (hf_it = _mesh->halffaces_begin(); hf_it != hf_end; ++hf_it)
{
if (status[*hf_it].tagged())
{
FaceHandle fh = _mesh->face_handle(*hf_it);
if (_primitiveTypes & vertexType_)
for (HalfFaceVertexIter hfv_it(*hf_it, _mesh); hfv_it.valid(); ++hfv_it)
status[*hfv_it].set_selected(!_deselection);
if (_primitiveTypes & edgeType_)
{
std::vector<HalfEdgeHandle> const& halfedges = _mesh->face(fh).halfedges();
for (std::size_t i = 0; i < halfedges.size(); ++i)
status[_mesh->edge_handle(halfedges[i])].set_selected(!_deselection);
}
if (_primitiveTypes & faceType_)
status[fh].set_selected(!_deselection);
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment