51 #include "TopologyPlugin.hh"
53 #define EDGE_FLIP_POPUP "<B>Flip Edge</B><br>Rotate an edge"
54 #define EDGE_COLLAPSE_POPUP "<B>Collapse Edge</B><br>Collapse an edge into one of its vertices."
55 #define EDGE_SPLIT_POPUP "<B>Split Edge</B><br>Split an edge at the clicked point."
56 #define FACE_ADD_POPUP "<B>Add Face</B><br>Insert a face between clicked vertices."
57 #define FACE_SPLIT_POPUP "<B>Split Face</B><br>Split a face at a clicked point."
58 #define FACE_DELETE_POPUP "<B>Delete Face</B><br>Remove a clicked face."
61 #if QT_VERSION >= 0x050000
72 edgeCollapseAction_(0),
86 emit addHiddenPickMode(EDGE_FLIP_POPUP);
87 emit addHiddenPickMode(EDGE_SPLIT_POPUP);
88 emit addHiddenPickMode(EDGE_COLLAPSE_POPUP);
89 emit addHiddenPickMode(FACE_ADD_POPUP);
90 emit addHiddenPickMode(FACE_SPLIT_POPUP);
91 emit addHiddenPickMode(FACE_DELETE_POPUP);
94 toolbar_ =
new QToolBar(
"Topology");
96 QActionGroup* group =
new QActionGroup(0);
98 QString iconPath = OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator();
100 const QString baseHelpURL =
"<a href='qthelp://org.openflipper.plugin-topology/Plugin-Topology/index.html";
101 const QString clickText = tr(
"Click for more information</a>");
104 edgeFlipAction_ = toolbar_->addAction( QIcon(iconPath +
"topology-edgeFlip.png"), EDGE_FLIP_POPUP );
105 edgeFlipAction_->setCheckable(
true);
106 edgeFlipAction_->setActionGroup(group);
107 edgeFlipAction_->setWhatsThis(tr(
"Flip edge. ") + baseHelpURL+
"#flip_edge'>" + clickText);
109 edgeSplitAction_ = toolbar_->addAction( QIcon(iconPath +
"topology-edgeSplit.png"), EDGE_SPLIT_POPUP );
110 edgeSplitAction_->setCheckable(
true);
111 edgeSplitAction_->setActionGroup(group);
112 edgeSplitAction_->setWhatsThis(tr(
"Split edge. ") + baseHelpURL+
"#split_edge'>" + clickText);
115 edgeCollapseAction_ = toolbar_->addAction( QIcon(iconPath +
"topology-edgeCollapse.png"), EDGE_COLLAPSE_POPUP );
116 edgeCollapseAction_->setCheckable(
true);
117 edgeCollapseAction_->setActionGroup(group);
118 edgeCollapseAction_->setWhatsThis(tr(
"Collapse edge. ") + baseHelpURL+
"#collapse_edge'>" + clickText);
121 toolbar_->addSeparator();
122 faceAddAction_ = toolbar_->addAction( QIcon(iconPath +
"topology-addFace.png"), FACE_ADD_POPUP );
123 faceAddAction_->setCheckable(
true);
124 faceAddAction_->setActionGroup(group);
125 faceAddAction_->setWhatsThis(tr(
"Add face.") + baseHelpURL+
"#add_face'>" + clickText);
128 faceDeleteAction_ = toolbar_->addAction( QIcon(iconPath +
"topology-deleteFace.png"), FACE_DELETE_POPUP );
129 faceDeleteAction_->setCheckable(
true);
130 faceDeleteAction_->setActionGroup(group);
131 faceDeleteAction_->setWhatsThis(tr(
"Delete face. ") + baseHelpURL+
"#delete_face'>" + clickText);
134 faceSplitAction_ = toolbar_->addAction( QIcon(iconPath +
"topology-splitFace.png"), FACE_SPLIT_POPUP );
135 faceSplitAction_->setCheckable(
true);
136 faceSplitAction_->setActionGroup(group);
137 faceSplitAction_->setWhatsThis(tr(
"Split face. ") + baseHelpURL+
"#split_face'>" + clickText);
139 group->setExclusive(
true);
141 connect( toolbar_, SIGNAL( actionTriggered(QAction*) ),
this, SLOT(
toolBarTriggered(QAction*) ));
143 emit addToolbar( toolbar_ );
155 if ( _action->text() == EDGE_FLIP_POPUP)
157 else if ( _action->text() == EDGE_SPLIT_POPUP)
159 else if ( _action->text() == EDGE_COLLAPSE_POPUP)
161 else if ( _action->text() == FACE_ADD_POPUP)
163 else if ( _action->text() == FACE_SPLIT_POPUP)
165 else if ( _action->text() == FACE_DELETE_POPUP)
180 edgeFlipAction_->setChecked( _mode == EDGE_FLIP_POPUP );
181 edgeSplitAction_->setChecked( _mode == EDGE_SPLIT_POPUP );
182 edgeCollapseAction_->setChecked( _mode == EDGE_COLLAPSE_POPUP );
183 faceAddAction_->setChecked( _mode == FACE_ADD_POPUP );
184 faceDeleteAction_->setChecked( _mode == FACE_DELETE_POPUP );
185 faceSplitAction_->setChecked( _mode == FACE_SPLIT_POPUP );
195 if ( _event->buttons() == Qt::RightButton )
213 for ( uint i = 0 ; i < addFaceVertices_.size() ; ++i ) {
220 TriMesh::VertexHandle vh = m->vertex_handle( addFaceVertices_[i].second );
221 if ( vh.is_valid()) {
222 m->status(vh).set_selected(
false);
229 if ( vh.is_valid()) {
230 m->status(vh).set_selected(
false);
237 addFaceVertices_.clear();
249 if (( _event->type() != QEvent::MouseButtonPress) && (_event->type() != QEvent::MouseButtonDblClick))
252 unsigned int node_idx, target_idx;
263 TriMesh::FaceHandle fh = m.face_handle(target_idx);
265 TriMesh::FaceVertexIter fv_it(m,fh);
266 TriMesh::VertexHandle closest = *fv_it;
267 float shortest_distance = (m.point(closest) - hit_point).sqrnorm();
270 if ( (m.point(*fv_it) - hit_point).sqrnorm() < shortest_distance ) {
271 shortest_distance = (m.point(*fv_it) - hit_point).sqrnorm();
276 if ( (m.point(*fv_it) - hit_point).sqrnorm() < shortest_distance ) {
282 std::pair<int,int> newVertex(object->
id(), closest.idx() );
284 for ( uint i = 0 ; i < addFaceVertices_.size() ; ++i ) {
285 if ( ( addFaceVertices_[i].first == newVertex.first ) &&
286 ( addFaceVertices_[i].second == newVertex.second ) ) {
287 addFaceVertices_.erase(addFaceVertices_.begin()+i);
288 m.status(closest).set_selected(
false);
296 addFaceVertices_.push_back( std::pair<int,int>(object->
id(), closest.idx() ) );
297 m.status(closest).set_selected(
true);
300 if ( addFaceVertices_.size() < 3 ) {
308 for ( uint i = 0 ; i < addFaceVertices_.size() ; ++i ) {
311 emit log(
LOGERR,
"Unable to get object for adding face");
316 if ( tmpObject->
dataType() != dt ) {
317 emit log(
LOGERR,
"Adding faces between different type of meshes is not supported!");
325 int objectId = addFaceVertices_[0].first;
326 for ( uint i = 0 ; i < addFaceVertices_.size() ; ++i ) {
327 if ( addFaceVertices_[i].first != objectId ) {
328 emit log(
LOGERR,
"Adding faces between different objects!");
334 TriMesh::VertexHandle vh0 = m.vertex_handle( addFaceVertices_[0].second );
335 TriMesh::VertexHandle vh1 = m.vertex_handle( addFaceVertices_[1].second );
336 TriMesh::VertexHandle vh2 = m.vertex_handle( addFaceVertices_[2].second );
339 bool errlog = omerr().is_enabled();
342 fh = m.add_face(vh0,vh1,vh2);
343 if ( !fh.is_valid() ) {
344 fh = m.add_face(vh2,vh1,vh0);
359 emit log(
LOGERR,
"Unable to add face!");
367 PolyMesh::FaceHandle fh = m.face_handle(target_idx);
371 float shortest_distance = FLT_MAX;
374 float distance = (m.point( *fv_it ) - hit_point).sqrnorm();
376 if (distance < shortest_distance){
377 shortest_distance = distance;
382 if (!closest.is_valid())
385 if (_event->type() != QEvent::MouseButtonDblClick){
387 std::pair<int,int> newVertex(object->
id(), closest.idx() );
389 for ( uint i = 0 ; i < addFaceVertices_.size() ; ++i ) {
390 if ( ( addFaceVertices_[i].first == newVertex.first ) &&
391 ( addFaceVertices_[i].second == newVertex.second ) ) {
392 addFaceVertices_.erase(addFaceVertices_.begin()+i);
393 m.status(closest).set_selected(
false);
401 addFaceVertices_.push_back( std::pair<int,int>(object->
id(), closest.idx() ) );
402 m.status(closest).set_selected(
true);
406 if ( (addFaceVertices_.size() < 3) || (_event->type() != QEvent::MouseButtonDblClick) ) {
414 for ( uint i = 0 ; i < addFaceVertices_.size() ; ++i ) {
417 emit log(
LOGERR,
"Unable to get object for adding face");
422 if ( tmpObject->
dataType() != dt ) {
423 emit log(
LOGERR,
"Adding faces between different type of meshes is not supported!");
431 int objectId = addFaceVertices_[0].first;
432 for ( uint i = 0 ; i < addFaceVertices_.size() ; ++i ) {
433 if ( addFaceVertices_[i].first != objectId ) {
434 emit log(
LOGERR,
"Adding faces between different objects!");
440 std::vector< PolyMesh::VertexHandle > vhs;
441 for ( uint i = 0 ; i < addFaceVertices_.size() ; ++i )
442 vhs.push_back( m.vertex_handle( addFaceVertices_[i].second ) );
445 bool errlog = omerr().is_enabled();
448 fh = m.add_face(vhs);
451 std::vector< PolyMesh::VertexHandle > rvhs;
453 while (!vhs.empty()){
454 rvhs.push_back( vhs.back() );
458 fh = m.add_face(rvhs);
474 emit log(
LOGERR,
"Unable to add face!");
489 if ( _event->type() != QEvent::MouseButtonPress )
492 unsigned int target_idx;
501 TriMesh::FaceHandle fh = m.face_handle(target_idx);
503 emit log(
LOGOUT,
"Picked Face " + QString::number(fh.idx()) +
", normal (" +
504 QString::number(m.normal(fh)[0]) +
"," +
505 QString::number(m.normal(fh)[1]) +
"," +
506 QString::number(m.normal(fh)[2]) +
") ") ;
508 TriMesh::VertexHandle vh = m.add_vertex(hit_point);
510 m.garbage_collection();
520 PolyMesh::FaceHandle fh = m.face_handle(target_idx);
522 emit log(
LOGOUT,
"Picked Face " + QString::number(fh.idx()) +
", normal (" +
523 QString::number(m.normal(fh)[0]) +
"," +
524 QString::number(m.normal(fh)[1]) +
"," +
525 QString::number(m.normal(fh)[2]) +
") ") ;
529 m.garbage_collection();
548 if ( _event->type() != QEvent::MouseButtonPress )
551 unsigned int node_idx, target_idx;
560 TriMesh::FaceHandle fh = m.face_handle(target_idx);
561 emit log(
LOGOUT,
"Picked Face " + QString::number(fh.idx()) +
", normal (" +
562 QString::number(m.normal(fh)[0]) +
"," +
563 QString::number(m.normal(fh)[1]) +
"," +
564 QString::number(m.normal(fh)[2]) +
") ") ;
567 m.garbage_collection();
572 PolyMesh::FaceHandle fh = m.face_handle(target_idx);
573 emit log(
LOGOUT,
"Picked Face " + QString::number(fh.idx()) +
", normal (" +
574 QString::number(m.normal(fh)[0]) +
"," +
575 QString::number(m.normal(fh)[1]) +
"," +
576 QString::number(m.normal(fh)[2]) +
") ") ;
579 m.garbage_collection();
597 if ( _event->type() != QEvent::MouseButtonPress )
600 unsigned int node_idx, target_idx;
608 TriMesh::FaceHandle fh = m.face_handle(target_idx);
610 TriMesh::FaceEdgeIter fe_it(m,fh);
611 TriMesh::HalfedgeHandle e1 = m.halfedge_handle(*fe_it,0);
614 TriMesh::HalfedgeHandle e2 = m.halfedge_handle(*fe_it,0);
617 TriMesh::HalfedgeHandle e3 = m.halfedge_handle(*fe_it,0);
620 TriMesh::EdgeHandle closest_edge = m.edge_handle(e1);
623 if ( dist < min_dist ) {
625 closest_edge = m.edge_handle(e2);
629 if ( dist < min_dist) {
631 closest_edge = m.edge_handle(e3);
634 if ( m.is_flip_ok(closest_edge) )
635 m.flip(closest_edge);
637 emit log(
LOGERR,
"Flip is not allowed here!");
639 emit log(
LOGOUT,
"Picked Edge " + QString::number(closest_edge.idx()));
647 emit log(
LOGWARN,
"Edge Flips not supported for Poly Meshes");
662 if ( _event->type() != QEvent::MouseButtonPress )
665 unsigned int node_idx, target_idx;
673 TriMesh::FaceHandle fh = m.face_handle(target_idx);
675 TriMesh::FaceEdgeIter fe_it(m,fh);
676 TriMesh::HalfedgeHandle e1 = m.halfedge_handle(*fe_it,0);
679 TriMesh::HalfedgeHandle e2 = m.halfedge_handle(*fe_it,0);
682 TriMesh::HalfedgeHandle e3 = m.halfedge_handle(*fe_it,0);
685 TriMesh::HalfedgeHandle closest_halfedge = e1;
688 if ( dist < min_dist ) {
690 closest_halfedge = e2;
694 if ( dist < min_dist) {
696 closest_halfedge = e3;
700 TriMesh::Point to = m.point( m.to_vertex_handle(closest_halfedge) );
701 TriMesh::Point from = m.point( m.from_vertex_handle(closest_halfedge) );
703 if ( (hit_point - to).sqrnorm() > (hit_point - from).sqrnorm() )
704 closest_halfedge = m.opposite_halfedge_handle(closest_halfedge);
706 if ( m.is_collapse_ok(closest_halfedge) ){
708 m.collapse(closest_halfedge );
709 m.garbage_collection();
711 emit log(
LOGERR,
"Collapse is not allowed here!");
713 emit log(
LOGOUT,
"Picked Edge " + QString::number(closest_halfedge.idx()));
723 PolyMesh::FaceHandle fh = m.face_handle(target_idx);
726 PolyMesh::HalfedgeHandle closest_edge(-1);
727 double min_dist = FLT_MAX;
730 for(; fe_it.is_valid(); ++fe_it)
732 PolyMesh::HalfedgeHandle heh = m.halfedge_handle(*fe_it,0);
746 if ( (hit_point - to).sqrnorm() > (hit_point - from).sqrnorm() )
747 closest_edge = m.opposite_halfedge_handle(closest_edge);
751 m.collapse(closest_edge );
752 m.garbage_collection();
756 emit log(
LOGOUT,
"Picked Edge " + QString::number(closest_edge.idx()));
775 if ( _event->type() != QEvent::MouseButtonPress )
778 unsigned int node_idx, target_idx;
786 TriMesh::FaceHandle fh = m.face_handle(target_idx);
788 TriMesh::FaceEdgeIter fe_it(m,fh);
789 TriMesh::HalfedgeHandle e1 = m.halfedge_handle(*fe_it,0);
792 TriMesh::HalfedgeHandle e2 = m.halfedge_handle(*fe_it,0);
795 TriMesh::HalfedgeHandle e3 = m.halfedge_handle(*fe_it,0);
798 TriMesh::EdgeHandle closest_edge = m.edge_handle(e1);
802 m.point(m.to_vertex_handle(e2)),
803 m.point(m.from_vertex_handle(e2)));
805 if (dist < min_dist) {
807 closest_edge = m.edge_handle(e2);
811 m.point(m.to_vertex_handle(e3)),
812 m.point(m.from_vertex_handle(e3)));
814 if (dist < min_dist) {
816 closest_edge = m.edge_handle(e3);
819 m.split(closest_edge,hit_point);
821 emit log(
LOGOUT,
"Picked Edge " + QString::number(closest_edge.idx() ));
829 PolyMesh::FaceHandle fh = m.face_handle(target_idx);
833 std::vector<PolyMesh::HalfedgeHandle> halfEdgeHandles;
835 for (;fh_it.is_valid(); ++fh_it)
837 halfEdgeHandles.push_back(*fh_it);
841 PolyMesh::EdgeHandle closest_edge = m.edge_handle(*halfEdgeHandles.begin());
842 double min_dist =
ACG::Geometry::distPointLineSquared(hit_point, m.point(m.to_vertex_handle( *halfEdgeHandles.begin() )), m.point(m.from_vertex_handle( *halfEdgeHandles.begin() )));
844 for (std::vector<PolyMesh::HalfedgeHandle>::iterator iter = halfEdgeHandles.begin(); iter != halfEdgeHandles.end(); ++iter)
849 closest_edge = m.edge_handle(*iter);
854 m.
split(closest_edge,hit_point);
856 emit log(
LOGOUT,
"Picked Edge " + QString::number(closest_edge.idx()) );
867 #if QT_VERSION < 0x050000
void pluginsInitialized()
initialize the Plugin
void toolBarTriggered(QAction *_action)
called when an action on the toolbar was triggered
void flip_edge(QMouseEvent *_event)
Flip edge.
Kernel::FaceEdgeIter FaceEdgeIter
Circulator.
picks faces (should be implemented for all nodes)
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
bool getObject(int _identifier, BSplineCurveObject *&_object)
PolyMesh * polyMesh(BaseObjectData *_object)
Get a poly mesh from an object.
Kernel::Point Point
Coordinate type.
void slotPickModeChanged(const std::string &_mode)
Toggle actions when the PickMode changes.
VertexHandle add_vertex(const Point &_p)
Alias for new_vertex(const Point&).
bool dataType(DataType _type) const
const UpdateType UPDATE_SELECTION(UpdateTypeSet(1)<< 4)
Selection updated.
void split_edge(QMouseEvent *_event)
Split Edge.
TriMesh * triMesh(BaseObjectData *_object)
Get a triangle mesh from an object.
const std::string pickMode()
Get the current Picking mode.
void collapse_edge(QMouseEvent *_event)
Collapse edge.
const UpdateType UPDATE_TOPOLOGY(UpdateTypeSet(1)<< 3)
Topology updated.
TopologyPlugin()
Constructor.
void slotMouseEvent(QMouseEvent *_event)
this is called when a mouse event occurred
Kernel::VertexHandle VertexHandle
Handle for referencing the corresponding item.
void update_normals()
Compute normals for all primitives.
Kernel::FaceVertexIter FaceVertexIter
Circulator.
void delete_face(QMouseEvent *_event)
Delete a face at the current hit point.
bool scenegraphPick(ACG::SceneGraph::PickTarget _pickTarget, const QPoint &_mousePos, unsigned int &_nodeIdx, unsigned int &_targetIdx, ACG::Vec3d *_hitPointPtr=0)
Execute picking operation on scenegraph.
Viewer::ActionMode actionMode()
Get the current Action mode.
void clearAddFaceVertices()
clear the add face vector
Kernel::FaceHalfedgeIter FaceHalfedgeIter
Circulator.
void add_face(QMouseEvent *_event)
Add a face.
bool getPickedObject(const unsigned int _node_idx, BaseObjectData *&_object)
Get the picked mesh.
void split(FaceHandle _fh, const Point &_p)
Face split (= 1-to-n split)
#define DATA_TRIANGLE_MESH
Vec::value_type distPointLineSquared(const Vec &_p, const Vec &_v0, const Vec &_v1, Vec *_min_v)
squared distance from point _p to line segment (_v0,_v1)
virtual bool picked(uint _node_idx)
detect if the node has been picked
void split_face(QMouseEvent *_event)
Split a face at the current hit point.