43 #include "TopologyPlugin.hh" 45 #define EDGE_FLIP_POPUP "<B>Flip Edge</B><br>Rotate an edge" 46 #define EDGE_COLLAPSE_POPUP "<B>Collapse Edge</B><br>Collapse an edge into one of its vertices." 47 #define EDGE_SPLIT_POPUP "<B>Split Edge</B><br>Split an edge at the clicked point." 48 #define FACE_ADD_POPUP "<B>Add Face</B><br>Insert a face between clicked vertices." 49 #define FACE_SPLIT_POPUP "<B>Split Face</B><br>Split a face at a clicked point." 50 #define FACE_DELETE_POPUP "<B>Delete Face</B><br>Remove a clicked face." 60 edgeCollapseAction_(0),
74 emit addHiddenPickMode(EDGE_FLIP_POPUP);
75 emit addHiddenPickMode(EDGE_SPLIT_POPUP);
76 emit addHiddenPickMode(EDGE_COLLAPSE_POPUP);
77 emit addHiddenPickMode(FACE_ADD_POPUP);
78 emit addHiddenPickMode(FACE_SPLIT_POPUP);
79 emit addHiddenPickMode(FACE_DELETE_POPUP);
82 toolbar_ =
new QToolBar(
"Topology");
84 QActionGroup* group =
new QActionGroup(0);
86 QString iconPath = OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator();
88 const QString baseHelpURL =
"<a href='qthelp://org.openflipper.plugin-topology/Plugin-Topology/index.html";
89 const QString clickText = tr(
"Click for more information</a>");
92 edgeFlipAction_ = toolbar_->addAction( QIcon(iconPath +
"topology-edgeFlip.png"), EDGE_FLIP_POPUP );
93 edgeFlipAction_->setCheckable(
true);
94 edgeFlipAction_->setActionGroup(group);
95 edgeFlipAction_->setWhatsThis(tr(
"Flip edge. ") + baseHelpURL+
"#flip_edge'>" + clickText);
97 edgeSplitAction_ = toolbar_->addAction( QIcon(iconPath +
"topology-edgeSplit.png"), EDGE_SPLIT_POPUP );
98 edgeSplitAction_->setCheckable(
true);
99 edgeSplitAction_->setActionGroup(group);
100 edgeSplitAction_->setWhatsThis(tr(
"Split edge. ") + baseHelpURL+
"#split_edge'>" + clickText);
103 edgeCollapseAction_ = toolbar_->addAction( QIcon(iconPath +
"topology-edgeCollapse.png"), EDGE_COLLAPSE_POPUP );
104 edgeCollapseAction_->setCheckable(
true);
105 edgeCollapseAction_->setActionGroup(group);
106 edgeCollapseAction_->setWhatsThis(tr(
"Collapse edge. ") + baseHelpURL+
"#collapse_edge'>" + clickText);
109 toolbar_->addSeparator();
110 faceAddAction_ = toolbar_->addAction( QIcon(iconPath +
"topology-addFace.png"), FACE_ADD_POPUP );
111 faceAddAction_->setCheckable(
true);
112 faceAddAction_->setActionGroup(group);
113 faceAddAction_->setWhatsThis(tr(
"Add face.") + baseHelpURL+
"#add_face'>" + clickText);
116 faceDeleteAction_ = toolbar_->addAction( QIcon(iconPath +
"topology-deleteFace.png"), FACE_DELETE_POPUP );
117 faceDeleteAction_->setCheckable(
true);
118 faceDeleteAction_->setActionGroup(group);
119 faceDeleteAction_->setWhatsThis(tr(
"Delete face. ") + baseHelpURL+
"#delete_face'>" + clickText);
122 faceSplitAction_ = toolbar_->addAction( QIcon(iconPath +
"topology-splitFace.png"), FACE_SPLIT_POPUP );
123 faceSplitAction_->setCheckable(
true);
124 faceSplitAction_->setActionGroup(group);
125 faceSplitAction_->setWhatsThis(tr(
"Split face. ") + baseHelpURL+
"#split_face'>" + clickText);
127 group->setExclusive(
true);
129 connect( toolbar_, SIGNAL( actionTriggered(QAction*) ),
this, SLOT(
toolBarTriggered(QAction*) ));
131 emit addToolbar( toolbar_ );
143 if ( _action->text() == EDGE_FLIP_POPUP)
145 else if ( _action->text() == EDGE_SPLIT_POPUP)
147 else if ( _action->text() == EDGE_COLLAPSE_POPUP)
149 else if ( _action->text() == FACE_ADD_POPUP)
151 else if ( _action->text() == FACE_SPLIT_POPUP)
153 else if ( _action->text() == FACE_DELETE_POPUP)
168 edgeFlipAction_->setChecked( _mode == EDGE_FLIP_POPUP );
169 edgeSplitAction_->setChecked( _mode == EDGE_SPLIT_POPUP );
170 edgeCollapseAction_->setChecked( _mode == EDGE_COLLAPSE_POPUP );
171 faceAddAction_->setChecked( _mode == FACE_ADD_POPUP );
172 faceDeleteAction_->setChecked( _mode == FACE_DELETE_POPUP );
173 faceSplitAction_->setChecked( _mode == FACE_SPLIT_POPUP );
183 if ( _event->buttons() == Qt::RightButton )
201 for ( uint i = 0 ; i < addFaceVertices_.size() ; ++i ) {
209 if ( vh.is_valid()) {
210 m->status(vh).set_selected(
false);
217 if ( vh.is_valid()) {
218 m->status(vh).set_selected(
false);
225 addFaceVertices_.clear();
237 if (( _event->type() != QEvent::MouseButtonPress) && (_event->type() != QEvent::MouseButtonDblClick))
240 size_t node_idx, target_idx;
251 TriMesh::FaceHandle fh = m.face_handle(target_idx);
255 float shortest_distance = (m.point(closest) - hit_point).sqrnorm();
258 if ( (m.point(*fv_it) - hit_point).sqrnorm() < shortest_distance ) {
259 shortest_distance = (m.point(*fv_it) - hit_point).sqrnorm();
264 if ( (m.point(*fv_it) - hit_point).sqrnorm() < shortest_distance ) {
270 std::pair<int,int> newVertex(object->
id(), closest.idx() );
272 for ( uint i = 0 ; i < addFaceVertices_.size() ; ++i ) {
273 if ( ( addFaceVertices_[i].first == newVertex.first ) &&
274 ( addFaceVertices_[i].second == newVertex.second ) ) {
275 addFaceVertices_.erase(addFaceVertices_.begin()+i);
276 m.status(closest).set_selected(
false);
284 addFaceVertices_.push_back( std::pair<int,int>(object->
id(), closest.idx() ) );
285 m.status(closest).set_selected(
true);
288 if ( addFaceVertices_.size() < 3 ) {
296 for ( uint i = 0 ; i < addFaceVertices_.size() ; ++i ) {
299 emit log(
LOGERR,
"Unable to get object for adding face");
304 if ( tmpObject->
dataType() != dt ) {
305 emit log(
LOGERR,
"Adding faces between different type of meshes is not supported!");
313 int objectId = addFaceVertices_[0].first;
314 for ( uint i = 0 ; i < addFaceVertices_.size() ; ++i ) {
315 if ( addFaceVertices_[i].first != objectId ) {
316 emit log(
LOGERR,
"Adding faces between different objects!");
327 bool errlog = omerr().is_enabled();
330 fh = m.add_face(vh0,vh1,vh2);
331 if ( !fh.is_valid() ) {
332 fh = m.add_face(vh2,vh1,vh0);
347 emit log(
LOGERR,
"Unable to add face!");
355 PolyMesh::FaceHandle fh = m.face_handle(target_idx);
359 float shortest_distance = FLT_MAX;
362 float distance = (m.point( *fv_it ) - hit_point).sqrnorm();
364 if (distance < shortest_distance){
365 shortest_distance = distance;
370 if (!closest.is_valid())
373 if (_event->type() != QEvent::MouseButtonDblClick){
375 std::pair<int,int> newVertex(object->
id(), closest.idx() );
377 for ( uint i = 0 ; i < addFaceVertices_.size() ; ++i ) {
378 if ( ( addFaceVertices_[i].first == newVertex.first ) &&
379 ( addFaceVertices_[i].second == newVertex.second ) ) {
380 addFaceVertices_.erase(addFaceVertices_.begin()+i);
381 m.status(closest).set_selected(
false);
389 addFaceVertices_.push_back( std::pair<int,int>(object->
id(), closest.idx() ) );
390 m.status(closest).set_selected(
true);
394 if ( (addFaceVertices_.size() < 3) || (_event->type() != QEvent::MouseButtonDblClick) ) {
402 for ( uint i = 0 ; i < addFaceVertices_.size() ; ++i ) {
405 emit log(
LOGERR,
"Unable to get object for adding face");
410 if ( tmpObject->
dataType() != dt ) {
411 emit log(
LOGERR,
"Adding faces between different type of meshes is not supported!");
419 int objectId = addFaceVertices_[0].first;
420 for ( uint i = 0 ; i < addFaceVertices_.size() ; ++i ) {
421 if ( addFaceVertices_[i].first != objectId ) {
422 emit log(
LOGERR,
"Adding faces between different objects!");
428 std::vector< PolyMesh::VertexHandle > vhs;
429 for ( uint i = 0 ; i < addFaceVertices_.size() ; ++i )
430 vhs.push_back( m.vertex_handle( addFaceVertices_[i].second ) );
433 bool errlog = omerr().is_enabled();
436 fh = m.add_face(vhs);
439 std::vector< PolyMesh::VertexHandle > rvhs;
441 while (!vhs.empty()){
442 rvhs.push_back( vhs.back() );
446 fh = m.add_face(rvhs);
462 emit log(
LOGERR,
"Unable to add face!");
477 if ( _event->type() != QEvent::MouseButtonPress )
489 TriMesh::FaceHandle fh = m.face_handle(target_idx);
491 emit log(
LOGOUT,
"Picked Face " + QString::number(fh.idx()) +
", normal (" +
492 QString::number(m.normal(fh)[0]) +
"," +
493 QString::number(m.normal(fh)[1]) +
"," +
494 QString::number(m.normal(fh)[2]) +
") ") ;
498 m.garbage_collection();
508 PolyMesh::FaceHandle fh = m.face_handle(target_idx);
510 emit log(
LOGOUT,
"Picked Face " + QString::number(fh.idx()) +
", normal (" +
511 QString::number(m.normal(fh)[0]) +
"," +
512 QString::number(m.normal(fh)[1]) +
"," +
513 QString::number(m.normal(fh)[2]) +
") ") ;
517 m.garbage_collection();
536 if ( _event->type() != QEvent::MouseButtonPress )
539 size_t node_idx, target_idx;
548 TriMesh::FaceHandle fh = m.face_handle(target_idx);
549 emit log(
LOGOUT,
"Picked Face " + QString::number(fh.idx()) +
", normal (" +
550 QString::number(m.normal(fh)[0]) +
"," +
551 QString::number(m.normal(fh)[1]) +
"," +
552 QString::number(m.normal(fh)[2]) +
") ") ;
555 m.garbage_collection();
560 PolyMesh::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();
585 if ( _event->type() != QEvent::MouseButtonPress )
588 size_t node_idx, target_idx;
596 TriMesh::FaceHandle fh = m.face_handle(target_idx);
599 TriMesh::HalfedgeHandle e1 = m.halfedge_handle(*fe_it,0);
602 TriMesh::HalfedgeHandle e2 = m.halfedge_handle(*fe_it,0);
605 TriMesh::HalfedgeHandle e3 = m.halfedge_handle(*fe_it,0);
608 TriMesh::EdgeHandle closest_edge = m.edge_handle(e1);
611 if ( dist < min_dist ) {
613 closest_edge = m.edge_handle(e2);
617 if ( dist < min_dist) {
619 closest_edge = m.edge_handle(e3);
622 if ( m.is_flip_ok(closest_edge) )
623 m.flip(closest_edge);
625 emit log(
LOGERR,
"Flip is not allowed here!");
627 emit log(
LOGOUT,
"Picked Edge " + QString::number(closest_edge.idx()));
635 emit log(
LOGWARN,
"Edge Flips not supported for Poly Meshes");
650 if ( _event->type() != QEvent::MouseButtonPress )
653 size_t node_idx, target_idx;
661 TriMesh::FaceHandle fh = m.face_handle(target_idx);
664 TriMesh::HalfedgeHandle e1 = m.halfedge_handle(*fe_it,0);
667 TriMesh::HalfedgeHandle e2 = m.halfedge_handle(*fe_it,0);
670 TriMesh::HalfedgeHandle e3 = m.halfedge_handle(*fe_it,0);
673 TriMesh::HalfedgeHandle closest_halfedge = e1;
676 if ( dist < min_dist ) {
678 closest_halfedge = e2;
682 if ( dist < min_dist) {
684 closest_halfedge = e3;
688 TriMesh::Point to = m.point( m.to_vertex_handle(closest_halfedge) );
689 TriMesh::Point from = m.point( m.from_vertex_handle(closest_halfedge) );
691 if ( (hit_point - to).sqrnorm() > (hit_point - from).sqrnorm() )
692 closest_halfedge = m.opposite_halfedge_handle(closest_halfedge);
694 if ( m.is_collapse_ok(closest_halfedge) ){
696 m.collapse(closest_halfedge );
697 m.garbage_collection();
699 emit log(
LOGERR,
"Collapse is not allowed here!");
701 emit log(
LOGOUT,
"Picked Edge " + QString::number(closest_halfedge.idx()));
711 PolyMesh::FaceHandle fh = m.face_handle(target_idx);
714 PolyMesh::HalfedgeHandle closest_edge(-1);
715 double min_dist = FLT_MAX;
718 for(; fe_it.is_valid(); ++fe_it)
720 PolyMesh::HalfedgeHandle heh = m.halfedge_handle(*fe_it,0);
734 if ( (hit_point - to).sqrnorm() > (hit_point - from).sqrnorm() )
735 closest_edge = m.opposite_halfedge_handle(closest_edge);
739 m.collapse(closest_edge );
740 m.garbage_collection();
744 emit log(
LOGOUT,
"Picked Edge " + QString::number(closest_edge.idx()));
763 if ( _event->type() != QEvent::MouseButtonPress )
766 size_t node_idx, target_idx;
774 TriMesh::FaceHandle fh = m.face_handle(target_idx);
777 TriMesh::HalfedgeHandle e1 = m.halfedge_handle(*fe_it,0);
780 TriMesh::HalfedgeHandle e2 = m.halfedge_handle(*fe_it,0);
783 TriMesh::HalfedgeHandle e3 = m.halfedge_handle(*fe_it,0);
786 TriMesh::EdgeHandle closest_edge = m.edge_handle(e1);
790 m.point(m.to_vertex_handle(e2)),
791 m.point(m.from_vertex_handle(e2)));
793 if (dist < min_dist) {
795 closest_edge = m.edge_handle(e2);
799 m.point(m.to_vertex_handle(e3)),
800 m.point(m.from_vertex_handle(e3)));
802 if (dist < min_dist) {
804 closest_edge = m.edge_handle(e3);
807 m.
split(closest_edge,hit_point);
809 emit log(
LOGOUT,
"Picked Edge " + QString::number(closest_edge.idx() ));
817 PolyMesh::FaceHandle fh = m.face_handle(target_idx);
821 std::vector<PolyMesh::HalfedgeHandle> halfEdgeHandles;
823 for (;fh_it.is_valid(); ++fh_it)
825 halfEdgeHandles.push_back(*fh_it);
829 PolyMesh::EdgeHandle closest_edge = m.edge_handle(*halfEdgeHandles.begin());
830 double min_dist =
ACG::Geometry::distPointLineSquared(hit_point, m.point(m.to_vertex_handle( *halfEdgeHandles.begin() )), m.point(m.from_vertex_handle( *halfEdgeHandles.begin() )));
832 for (std::vector<PolyMesh::HalfedgeHandle>::iterator iter = halfEdgeHandles.begin(); iter != halfEdgeHandles.end(); ++iter)
837 closest_edge = m.edge_handle(*iter);
842 m.
split(closest_edge,hit_point);
844 emit log(
LOGOUT,
"Picked Edge " + QString::number(closest_edge.idx()) );
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
void split_edge(QMouseEvent *_event)
Split Edge.
void collapse_edge(QMouseEvent *_event)
Collapse edge.
bool scenegraphPick(ACG::SceneGraph::PickTarget _pickTarget, const QPoint &_mousePos, size_t &_nodeIdx, size_t &_targetIdx, ACG::Vec3d *_hitPointPtr=0)
Execute picking operation on scenegraph.
Kernel::Point Point
Coordinate type.
VertexHandle add_vertex(const Point &_p)
Alias for new_vertex(const Point&).
bool getPickedObject(const size_t _node_idx, BaseObjectData *&_object)
Get the picked mesh.
void toolBarTriggered(QAction *_action)
called when an action on the toolbar was triggered
const UpdateType UPDATE_SELECTION(UpdateTypeSet(1)<< 4)
Selection updated.
void slotPickModeChanged(const std::string &_mode)
Toggle actions when the PickMode changes.
Kernel::FaceVertexIter FaceVertexIter
Circulator.
bool dataType(DataType _type) const
Kernel::VertexHandle VertexHandle
Handle for referencing the corresponding item.
TriMesh * triMesh(BaseObjectData *_object)
Get a triangle mesh from an object.
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)
Kernel::FaceEdgeIter FaceEdgeIter
Circulator.
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.
void pluginsInitialized()
initialize the Plugin
void add_face(QMouseEvent *_event)
Add a face.
TopologyPlugin()
Constructor.
void delete_face(QMouseEvent *_event)
Delete a face at the current hit point.
Kernel::FaceHalfedgeIter FaceHalfedgeIter
Circulator.
PolyMesh * polyMesh(BaseObjectData *_object)
Get a poly mesh from an object.
picks faces (should be implemented for all nodes)
const UpdateType UPDATE_TOPOLOGY(UpdateTypeSet(1)<< 3)
Topology updated.
void split_face(QMouseEvent *_event)
Split a face at the current hit point.
Viewer::ActionMode actionMode()
Get the current Action mode.
void flip_edge(QMouseEvent *_event)
Flip edge.
virtual bool picked(uint _node_idx)
detect if the node has been picked
#define DATA_TRIANGLE_MESH
void clearAddFaceVertices()
clear the add face vector
void split(FaceHandle _fh, const Point &_p)
Face split (= 1-to-n split)
void update_normals()
Compute normals for all primitives.
void slotMouseEvent(QMouseEvent *_event)
this is called when a mouse event occurred
const std::string pickMode()
Get the current Picking mode.
VertexHandle split(EdgeHandle _eh, const Point &_p)
Edge split (= 2-to-4 split)